diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..327d4c3 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,54 @@ +on: + push: + branches: + - main + +permissions: + contents: write + +jobs: + + release: + name: Release + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v4 + + - name: Extract package version + run: echo "PACKAGE_VERSION=$(npm pkg get version | sed 's/"//g')" >> "$GITHUB_ENV" + + - name: Get release (if exists) + id: getRelease + uses: cardinalby/git-get-release-action@v1 + env: + GITHUB_TOKEN: ${{ github.token }} + with: + doNotFailIfNotFound: true + releaseName: "v${{ env.PACKAGE_VERSION }}" + + - name: Fail on duplicate release + run: | + if [ -n "${{ steps.getRelease.RELEASE_ID}}" ]; then + echo "Release already exists" + exit 1 + fi + + - name: Create schema.json + run: node scripts/create-schema.js + + - name: Upload schema.json + uses: actions/upload-artifact@v4 + with: + name: schema.json + path: schema.json + + - name: Create release + uses: softprops/action-gh-release@v2 + with: + name: "v${{ env.PACKAGE_VERSION }}" + tag_name: "v${{ env.PACKAGE_VERSION }}" + files: schema.json + fail_on_unmatched_files: true + make_latest: true diff --git a/package.json b/package.json index 2711df6..2c00fb2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "shadncn-tree-view", - "version": "0.0.1", + "version": "1.0.1", "description": "", "main": "index.js", "scripts": { diff --git a/schema.json b/schema.json deleted file mode 100644 index 54c191d..0000000 --- a/schema.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "tree-view", - "type": "registry:block", - "dependencies": [ - "@radix-ui/react-accordion", - "class-variance-authority" - ], - "devDependencies": [], - "registryDependencies": [], - "files": [ - { - "path": "components/tree-view.tsx", - "type": "registry:block", - "content": "'use client'\n\nimport React from 'react'\nimport * as AccordionPrimitive from '@radix-ui/react-accordion'\nimport { ChevronRight } from 'lucide-react'\nimport { cva } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\n\nconst treeVariants = cva(\n 'group hover:before:opacity-100 before:absolute before:rounded-lg before:left-0 px-2 before:w-full before:opacity-0 before:bg-accent/70 before:h-[2rem] before:-z-10'\n)\n\nconst selectedTreeVariants = cva(\n 'before:opacity-100 before:bg-accent/70 text-accent-foreground'\n)\n\ninterface TreeDataItem {\n id: string\n name: string\n icon?: any\n selectedIcon?: any\n openIcon?: any\n children?: TreeDataItem[]\n actions?: React.ReactNode\n onClick?: () => void\n}\n\ntype TreeProps = React.HTMLAttributes & {\n data: TreeDataItem[] | TreeDataItem\n initialSelectedItemId?: string\n onSelectChange?: (item: TreeDataItem | undefined) => void\n expandAll?: boolean\n defaultNodeIcon?: any\n defaultLeafIcon?: any\n}\n\nconst TreeView = React.forwardRef(\n (\n {\n data,\n initialSelectedItemId,\n onSelectChange,\n expandAll,\n defaultLeafIcon,\n defaultNodeIcon,\n className,\n ...props\n },\n ref\n ) => {\n const [selectedItemId, setSelectedItemId] = React.useState<\n string | undefined\n >(initialSelectedItemId)\n\n const handleSelectChange = React.useCallback(\n (item: TreeDataItem | undefined) => {\n setSelectedItemId(item?.id)\n if (onSelectChange) {\n onSelectChange(item)\n }\n },\n [onSelectChange]\n )\n\n const expandedItemIds = React.useMemo(() => {\n if (!initialSelectedItemId) {\n return [] as string[]\n }\n\n const ids: string[] = []\n\n function walkTreeItems(\n items: TreeDataItem[] | TreeDataItem,\n targetId: string\n ) {\n if (items instanceof Array) {\n for (let i = 0; i < items.length; i++) {\n ids.push(items[i]!.id)\n if (walkTreeItems(items[i]!, targetId) && !expandAll) {\n return true\n }\n if (!expandAll) ids.pop()\n }\n } else if (!expandAll && items.id === targetId) {\n return true\n } else if (items.children) {\n return walkTreeItems(items.children, targetId)\n }\n }\n\n walkTreeItems(data, initialSelectedItemId)\n return ids\n }, [data, expandAll, initialSelectedItemId])\n\n return (\n
\n \n
\n )\n }\n)\n\ntype TreeItemProps = TreeProps & {\n selectedItemId?: string\n handleSelectChange: (item: TreeDataItem | undefined) => void\n expandedItemIds: string[]\n defaultNodeIcon?: any\n defaultLeafIcon?: any\n}\n\nconst TreeItem = React.forwardRef(\n (\n {\n className,\n data,\n selectedItemId,\n handleSelectChange,\n expandedItemIds,\n defaultNodeIcon,\n defaultLeafIcon,\n ...props\n },\n ref\n ) => {\n if (!(data instanceof Array)) {\n data = [data]\n }\n return (\n
\n
    \n {data.map((item) => (\n
  • \n {item.children ? (\n \n ) : (\n \n )}\n
  • \n ))}\n
\n
\n )\n }\n)\n\nconst TreeNode = ({\n item,\n handleSelectChange,\n expandedItemIds,\n selectedItemId,\n defaultNodeIcon,\n defaultLeafIcon\n}: {\n item: TreeDataItem\n handleSelectChange: (item: TreeDataItem | undefined) => void\n expandedItemIds: string[]\n selectedItemId?: string\n defaultNodeIcon?: any\n defaultLeafIcon?: any\n}) => {\n const [value, setValue] = React.useState(\n expandedItemIds.includes(item.id) ? [item.id] : []\n )\n return (\n setValue(s)}\n >\n \n {\n handleSelectChange(item)\n item.onClick?.()\n }}\n >\n \n {item.name}\n \n {item.actions}\n \n \n \n \n \n \n \n )\n}\n\nconst TreeLeaf = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes & {\n item: TreeDataItem\n selectedItemId?: string\n handleSelectChange: (item: TreeDataItem | undefined) => void\n defaultLeafIcon?: any\n }\n>(\n (\n {\n className,\n item,\n selectedItemId,\n handleSelectChange,\n defaultLeafIcon,\n ...props\n },\n ref\n ) => {\n return (\n {\n handleSelectChange(item)\n item.onClick?.()\n }}\n {...props}\n >\n \n {item.name}\n \n {item.actions}\n \n \n )\n }\n)\n\nconst AccordionTrigger = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, ...props }, ref) => (\n \n svg]:rotate-90',\n className\n )}\n {...props}\n >\n \n {children}\n \n \n))\nAccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName\n\nconst AccordionContent = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, ...props }, ref) => (\n \n
{children}
\n \n))\nAccordionContent.displayName = AccordionPrimitive.Content.displayName\n\nconst TreeIcon = ({\n item,\n isOpen,\n isSelected,\n default: defaultIcon\n}: {\n item: TreeDataItem\n isOpen?: boolean\n isSelected?: boolean\n default?: any\n}) => {\n let Icon = defaultIcon\n if (isSelected && item.selectedIcon) {\n Icon = item.selectedIcon\n } else if (isOpen && item.openIcon) {\n Icon = item.openIcon\n } else if (item.icon) {\n Icon = item.icon\n }\n return Icon ? (\n \n ) : (\n <>\n )\n}\n\nconst TreeActions = ({\n children,\n isSelected\n}: {\n children: React.ReactNode\n isSelected: boolean\n}) => {\n return (\n \n {children}\n \n )\n}\n\nexport { TreeView, type TreeDataItem }\n" - } - ], - "tailwind": {}, - "cssVars": {}, - "meta": { - "importSpecifier": "TreeView", - "moduleSpecifier": "@/components/tree-view" - } -} \ No newline at end of file