Compare commits

..

15 Commits

Author SHA1 Message Date
github-actions[bot]
ed9d5939e6 chore(release): version packages (#8479)
* chore(release): version packages

* fix

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: shadcn <m@shadcn.com>
2025-10-15 22:55:13 +04:00
shadcn
b52ec12f1e fix(shadcn): universal items handling (#8478)
* fix(shadcn): universal items handling

* chore: add changeset
2025-10-15 22:27:12 +04:00
Igor S. Zizinio
2ab9bff4bb Fix formatting of Badge variant prop in documentation (#8477) 2025-10-15 22:09:06 +04:00
Shaban Haider
2f6b51fa0a feat: add @efferd-ui in trusted registries (#8474) 2025-10-15 22:03:39 +04:00
shadcn
8a4764ed91 chore: registry build 2025-10-15 12:05:03 +04:00
Chisom Uma
e934d4645b feat(registry): Add Austin UI Components to the registry index (#8456)
* feat(registry): Add Austin UI Components to the registry index

* Fix JSON syntax for @austin-ui registry URL

---------

Co-authored-by: shadcn <m@shadcn.com>
2025-10-15 12:02:40 +04:00
shadcn
08b8e499d8 chore: update registries.json (#8470) 2025-10-15 11:52:43 +04:00
shadcn
69402b3579 ci: update deprecated to ignore www/package.json 2025-10-15 11:39:53 +04:00
shadcn
679c852254 Merge branch 'main' of github.com:shadcn-ui/ui 2025-10-15 11:37:26 +04:00
github-actions[bot]
d478412e44 chore(release): version packages (#8453)
* chore(release): version packages

* chore(release): version packages

* chore: deps

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: shadcn <m@shadcn.com>
2025-10-15 11:37:01 +04:00
shadcn
d5c8a25150 Merge branch 'main' of github.com:shadcn-ui/ui 2025-10-15 11:30:53 +04:00
Benjamin
26433a651c Added react-market registry (#8346)
Co-authored-by: shadcn <m@shadcn.com>
2025-10-15 11:30:43 +04:00
shadcn
c3da716e94 debug: ci 2025-10-15 11:30:24 +04:00
dependabot[bot]
b2572d0287 chore(deps): bump tj-actions/changed-files in /.github/workflows (#8466)
Bumps [tj-actions/changed-files](https://github.com/tj-actions/changed-files) from 44 to 46.
- [Release notes](https://github.com/tj-actions/changed-files/releases)
- [Changelog](https://github.com/tj-actions/changed-files/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/changed-files/compare/v44...v46)

---
updated-dependencies:
- dependency-name: tj-actions/changed-files
  dependency-version: '46'
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-15 11:30:03 +04:00
shadcn
b83f042416 fix: actions 2025-10-15 11:26:28 +04:00
28 changed files with 717 additions and 2169 deletions

View File

@@ -1,5 +0,0 @@
---
"shadcn": patch
---
Fix support for universal registry items that only have dependencies without files

View File

@@ -1,5 +0,0 @@
---
"shadcn": patch
---
add support for color as var

View File

@@ -1,5 +0,0 @@
---
"shadcn": patch
---
fix adding registry item with CSS at-property

View File

@@ -1,13 +1,14 @@
name: Deprecated
on:
pull_request:
pull_request_target:
types: [opened, synchronize]
permissions:
issues: write
contents: read
pull-requests: write
jobs:
deprecated:
runs-on: ubuntu-latest
@@ -15,11 +16,12 @@ jobs:
- name: Checkout PR
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v44
uses: tj-actions/changed-files@v46
with:
files: |
apps/www/**
@@ -37,7 +39,8 @@ jobs:
const changedFiles = `${{ steps.changed-files.outputs.all_changed_files }}`.split(' ');
const wwwFiles = changedFiles.filter(file =>
file.startsWith('apps/www/') &&
!file.startsWith('apps/www/public/r/')
!file.startsWith('apps/www/public/r/') &&
file !== 'apps/www/package.json'
);
if (wwwFiles.length > 0) {

View File

@@ -49,7 +49,7 @@ import { Badge } from "@/components/ui/badge"
```
```tsx
<Badge variant="default |outline | secondary | destructive">Badge</Badge>
<Badge variant="default | outline | secondary | destructive">Badge</Badge>
```
### Link

View File

@@ -89,7 +89,7 @@
"recharts": "2.15.1",
"rehype-pretty-code": "^0.14.1",
"rimraf": "^6.0.1",
"shadcn": "3.4.0",
"shadcn": "3.4.2",
"shiki": "^1.10.1",
"sonner": "^2.0.0",
"tailwind-merge": "^3.0.1",

View File

@@ -1,51 +1,53 @@
{
"@8bitcn": "https://8bitcn.com/r/{name}.json",
"@97cn": "https://97cn.itzik.co/r/{name}.json",
"@aceternity": "https://ui.aceternity.com/registry/{name}.json",
"@ai-elements": "https://registry.ai-sdk.dev/{name}.json",
"@alexcarpenter": "https://ui.alexcarpenter.me/r/{name}.json",
"@alpine": "https://alpine-registry.vercel.app/r/{name}.json",
"@animate-ui": "https://animate-ui.com/r/{name}.json",
"@assistant-ui": "https://r.assistant-ui.com/{name}.json",
"@austin-ui": "https://austin-ui.netlify.app/r/{name}.json",
"@basecn": "https://basecn.dev/r/{name}.json",
"@better-upload": "https://better-upload.com/r/{name}.json",
"@billingsdk": "https://billingsdk.com/r/{name}.json",
"@blocks": "https://blocks.so/r/{name}.json",
"@bucharitesh": "https://bucharitesh.in/r/{name}.json",
"@clerk": "https://clerk.com/r/{name}.json",
"@cult-ui": "https://cult-ui.com/r/{name}.json",
"@efferd-ui": "https://ui.efferd.com/r/{name}.json",
"@eldoraui": "https://eldoraui.site/r/{name}.json",
"@elements": "https://tryelements.dev/r/{name}.json",
"@elevenlabs-ui": "https://ui.elevenlabs.io/r/{name}.json",
"@fancy": "https://fancycomponents.dev/r/{name}.json",
"@formcn": "https://formcn.dev/r/{name}.json",
"@heseui": "https://www.heseui.com/r/{name}.json",
"@intentui": "https://intentui.com/r/{name}",
"@kibo-ui": "https://www.kibo-ui.com/r/{name}.json",
"@kokonutui": "https://kokonutui.com/r/{name}.json",
"@limeplay": "https://limeplay.winoffrg.dev/r/{name}.json",
"@magicui": "https://magicui.design/r/{name}.json",
"@motion-primitives": "https://motion-primitives.com/c/{name}.json",
"@originui": "https://originui.com/r/{name}.json",
"@prompt-kit": "https://prompt-kit.com/c/{name}.json",
"@tailark": "https://tailark.com/r/{name}.json",
"@tweakcn": "https://tweakcn.com/r/themes/{name}.json",
"@react-bits": "https://reactbits.dev/r/{name}.json",
"@reui": "https://reui.io/r/{name}.json",
"@heseui": "https://www.heseui.com/r/{name}.json",
"@paceui-ui": "https://ui.paceui.com/r/{name}.json",
"@basecn": "https://basecn.dev/r/{name}.json",
"@ncdai": "https://chanhdai.com/r/{name}.json",
"@8bitcn": "https://8bitcn.com/r/{name}.json",
"@billingsdk": "https://billingsdk.com/r/{name}.json",
"@elements": "https://tryelements.dev/r/{name}.json",
"@nativeui": "https://nativeui.io/registry/{name}.json",
"@ncdai": "https://chanhdai.com/r/{name}.json",
"@paceui-ui": "https://ui.paceui.com/r/{name}.json",
"@prompt-kit": "https://prompt-kit.com/c/{name}.json",
"@react-bits": "https://reactbits.dev/r/{name}.json",
"@react-market": "https://www.react-market.com/get/{name}.json",
"@retroui": "https://retroui.dev/r/{name}.json",
"@reui": "https://reui.io/r/{name}.json",
"@rigidui": "https://rigidui.com/r/{name}.json",
"@scrollxui": "https://www.scrollxui.dev/registry/{name}.json",
"@shadcn-editor": "https://shadcn-editor.vercel.app/r/{name}.json",
"@shadcn-map": "http://shadcn-map.vercel.app/r/{name}.json",
"@shadcn-studio": "https://shadcnstudio.com/r/{name}.json",
"@shadcnblocks": "https://shadcnblocks.com/r/{name}.json",
"@skiper-ui": "https://skiper-ui.com/registry/{name}.json",
"@skyr": "https://ui-play.skyroc.me/r/{name}.json",
"@smoothui": "https://smoothui.dev/r/{name}.json",
"@svgl": "https://svgl.app/r/{name}.json",
"@formcn": "https://formcn.dev/r/{name}.json",
"@limeplay": "https://limeplay.winoffrg.dev/r/{name}.json",
"@skiper-ui": "https://skiper-ui.com/registry/{name}.json",
"@shadcnblocks": "https://shadcnblocks.com/r/{name}.json",
"@shadcn-editor": "https://shadcn-editor.vercel.app/r/{name}.json",
"@shadcn-studio": "https://shadcnstudio.com/r/{name}.json",
"@rigidui": "https://rigidui.com/r/{name}.json",
"@skyr": "https://ui-play.skyroc.me/r/{name}.json",
"@retroui": "https://retroui.dev/r/{name}.json",
"@tailark": "https://tailark.com/r/{name}.json",
"@tweakcn": "https://tweakcn.com/r/themes/{name}.json",
"@wds": "https://wds-shadcn-registry.netlify.app/r/{name}.json",
"@97cn": "https://97cn.itzik.co/r/{name}.json",
"@better-upload": "https://better-upload.com/r/{name}.json",
"@zippystarter": "https://zippystarter.com/r/{name}.json",
"@elevenlabs-ui": "https://ui.elevenlabs.io/r/{name}.json",
"@eldoraui": "https://eldoraui.site/r/{name}.json",
"@intentui": "https://intentui.com/r/{name}",
"@shadcn-map": "http://shadcn-map.vercel.app/r/{name}.json",
"@fancy": "https://fancycomponents.dev/r/{name}.json"
"@zippystarter": "https://zippystarter.com/r/{name}.json"
}

View File

@@ -17,7 +17,7 @@
"files": [
{
"path": "ui/form.tsx",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport {\n Controller,\n FormProvider,\n useFormContext,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Label } from \"@/registry/default/ui/label\"\n\nconst Form = FormProvider\n\ntype FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = {\n name: TName\n}\n\nconst FormFieldContext = React.createContext<FormFieldContextValue>(\n {} as FormFieldContextValue\n)\n\nconst FormField = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n ...props\n}: ControllerProps<TFieldValues, TName>) => {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n )\n}\n\nconst useFormField = () => {\n const fieldContext = React.useContext(FormFieldContext)\n const itemContext = React.useContext(FormItemContext)\n const { getFieldState, formState } = useFormContext()\n\n const fieldState = getFieldState(fieldContext.name, formState)\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\")\n }\n\n const { id } = itemContext\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n }\n}\n\ntype FormItemContextValue = {\n id: string\n}\n\nconst FormItemContext = React.createContext<FormItemContextValue>(\n {} as FormItemContextValue\n)\n\nconst FormItem = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const id = React.useId()\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <div ref={ref} className={cn(\"space-y-2\", className)} {...props} />\n </FormItemContext.Provider>\n )\n})\nFormItem.displayName = \"FormItem\"\n\nconst FormLabel = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const { error, formItemId } = useFormField()\n\n return (\n <Label\n ref={ref}\n className={cn(error && \"text-destructive\", className)}\n htmlFor={formItemId}\n {...props}\n />\n )\n})\nFormLabel.displayName = \"FormLabel\"\n\nconst FormControl = React.forwardRef<\n React.ElementRef<typeof Slot>,\n React.ComponentPropsWithoutRef<typeof Slot>\n>(({ ...props }, ref) => {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n return (\n <Slot\n ref={ref}\n id={formItemId}\n aria-describedby={\n !error\n ? `${formDescriptionId}`\n : `${formDescriptionId} ${formMessageId}`\n }\n aria-invalid={!!error}\n {...props}\n />\n )\n})\nFormControl.displayName = \"FormControl\"\n\nconst FormDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n const { formDescriptionId } = useFormField()\n\n return (\n <p\n ref={ref}\n id={formDescriptionId}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n})\nFormDescription.displayName = \"FormDescription\"\n\nconst FormMessage = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => {\n const { error, formMessageId } = useFormField()\n const body = error ? String(error?.message ?? \"\") : children\n\n if (!body) {\n return null\n }\n\n return (\n <p\n ref={ref}\n id={formMessageId}\n className={cn(\"text-sm font-medium text-destructive\", className)}\n {...props}\n >\n {body}\n </p>\n )\n})\nFormMessage.displayName = \"FormMessage\"\n\nexport {\n useFormField,\n Form,\n FormItem,\n FormLabel,\n FormControl,\n FormDescription,\n FormMessage,\n FormField,\n}\n",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport {\n Controller,\n FormProvider,\n useFormContext,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Label } from \"@/registry/default/ui/label\"\n\nconst Form = FormProvider\n\ntype FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = {\n name: TName\n}\n\nconst FormFieldContext = React.createContext<FormFieldContextValue | null>(null)\n\nconst FormField = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n ...props\n}: ControllerProps<TFieldValues, TName>) => {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n )\n}\n\nconst useFormField = () => {\n const fieldContext = React.useContext(FormFieldContext)\n const itemContext = React.useContext(FormItemContext)\n const { getFieldState, formState } = useFormContext()\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\")\n }\n\n if (!itemContext) {\n throw new Error(\"useFormField should be used within <FormItem>\")\n }\n\n const fieldState = getFieldState(fieldContext.name, formState)\n\n const { id } = itemContext\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n }\n}\n\ntype FormItemContextValue = {\n id: string\n}\n\nconst FormItemContext = React.createContext<FormItemContextValue | null>(null)\n\nconst FormItem = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const id = React.useId()\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <div ref={ref} className={cn(\"space-y-2\", className)} {...props} />\n </FormItemContext.Provider>\n )\n})\nFormItem.displayName = \"FormItem\"\n\nconst FormLabel = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const { error, formItemId } = useFormField()\n\n return (\n <Label\n ref={ref}\n className={cn(error && \"text-destructive\", className)}\n htmlFor={formItemId}\n {...props}\n />\n )\n})\nFormLabel.displayName = \"FormLabel\"\n\nconst FormControl = React.forwardRef<\n React.ElementRef<typeof Slot>,\n React.ComponentPropsWithoutRef<typeof Slot>\n>(({ ...props }, ref) => {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n return (\n <Slot\n ref={ref}\n id={formItemId}\n aria-describedby={\n !error\n ? `${formDescriptionId}`\n : `${formDescriptionId} ${formMessageId}`\n }\n aria-invalid={!!error}\n {...props}\n />\n )\n})\nFormControl.displayName = \"FormControl\"\n\nconst FormDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n const { formDescriptionId } = useFormField()\n\n return (\n <p\n ref={ref}\n id={formDescriptionId}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n})\nFormDescription.displayName = \"FormDescription\"\n\nconst FormMessage = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => {\n const { error, formMessageId } = useFormField()\n const body = error ? String(error?.message ?? \"\") : children\n\n if (!body) {\n return null\n }\n\n return (\n <p\n ref={ref}\n id={formMessageId}\n className={cn(\"text-sm font-medium text-destructive\", className)}\n {...props}\n >\n {body}\n </p>\n )\n})\nFormMessage.displayName = \"FormMessage\"\n\nexport {\n useFormField,\n Form,\n FormItem,\n FormLabel,\n FormControl,\n FormDescription,\n FormMessage,\n FormField,\n}\n",
"type": "registry:ui",
"target": ""
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -8,7 +8,7 @@
"files": [
{
"path": "registry/new-york-v4/examples/sonner-types.tsx",
"content": "\"use client\"\n\nimport { toast } from \"sonner\"\n\nimport { Button } from \"@/registry/new-york-v4/ui/button\"\n\nexport default function SonnerTypes() {\n return (\n <div className=\"flex flex-wrap gap-2\">\n <Button variant=\"outline\" onClick={() => toast(\"Event has been created\")}>\n Default\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => toast.success(\"Event has been created\")}\n >\n Success\n </Button>\n <Button\n variant=\"outline\"\n onClick={() =>\n toast.info(\"Be at the area 10 minutes before the event time\")\n }\n >\n Info\n </Button>\n <Button\n variant=\"outline\"\n onClick={() =>\n toast.warning(\"Event start time cannot be earlier than 8am\")\n }\n >\n Warning\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => toast.error(\"Event has not been created\")}\n >\n Error\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => {\n const promise = () =>\n new Promise((resolve) =>\n setTimeout(() => resolve({ name: \"Event\" }), 2000)\n )\n\n toast.promise(promise(), {\n loading: \"Loading...\",\n success: (data) => `${data.name} has been created`,\n error: \"Error\",\n })\n }}\n >\n Promise\n </Button>\n </div>\n )\n}\n",
"content": "\"use client\"\n\nimport { toast } from \"sonner\"\n\nimport { Button } from \"@/registry/new-york-v4/ui/button\"\n\nexport default function SonnerTypes() {\n return (\n <div className=\"flex flex-wrap gap-2\">\n <Button variant=\"outline\" onClick={() => toast(\"Event has been created\")}>\n Default\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => toast.success(\"Event has been created\")}\n >\n Success\n </Button>\n <Button\n variant=\"outline\"\n onClick={() =>\n toast.info(\"Be at the area 10 minutes before the event time\")\n }\n >\n Info\n </Button>\n <Button\n variant=\"outline\"\n onClick={() =>\n toast.warning(\"Event start time cannot be earlier than 8am\")\n }\n >\n Warning\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => toast.error(\"Event has not been created\")}\n >\n Error\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => {\n toast.promise<{ name: string }>(\n () =>\n new Promise((resolve) =>\n setTimeout(() => resolve({ name: \"Event\" }), 2000)\n ),\n {\n loading: \"Loading...\",\n success: (data) => `${data.name} has been created`,\n error: \"Error\",\n }\n )\n }}\n >\n Promise\n </Button>\n </div>\n )\n}\n",
"type": "registry:example"
}
]

View File

@@ -17,7 +17,7 @@
"files": [
{
"path": "ui/form.tsx",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport {\n Controller,\n FormProvider,\n useFormContext,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Label } from \"@/registry/new-york/ui/label\"\n\nconst Form = FormProvider\n\ntype FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = {\n name: TName\n}\n\nconst FormFieldContext = React.createContext<FormFieldContextValue>(\n {} as FormFieldContextValue\n)\n\nconst FormField = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n ...props\n}: ControllerProps<TFieldValues, TName>) => {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n )\n}\n\nconst useFormField = () => {\n const fieldContext = React.useContext(FormFieldContext)\n const itemContext = React.useContext(FormItemContext)\n const { getFieldState, formState } = useFormContext()\n\n const fieldState = getFieldState(fieldContext.name, formState)\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\")\n }\n\n const { id } = itemContext\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n }\n}\n\ntype FormItemContextValue = {\n id: string\n}\n\nconst FormItemContext = React.createContext<FormItemContextValue>(\n {} as FormItemContextValue\n)\n\nconst FormItem = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const id = React.useId()\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <div ref={ref} className={cn(\"space-y-2\", className)} {...props} />\n </FormItemContext.Provider>\n )\n})\nFormItem.displayName = \"FormItem\"\n\nconst FormLabel = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const { error, formItemId } = useFormField()\n\n return (\n <Label\n ref={ref}\n className={cn(error && \"text-destructive\", className)}\n htmlFor={formItemId}\n {...props}\n />\n )\n})\nFormLabel.displayName = \"FormLabel\"\n\nconst FormControl = React.forwardRef<\n React.ElementRef<typeof Slot>,\n React.ComponentPropsWithoutRef<typeof Slot>\n>(({ ...props }, ref) => {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n return (\n <Slot\n ref={ref}\n id={formItemId}\n aria-describedby={\n !error\n ? `${formDescriptionId}`\n : `${formDescriptionId} ${formMessageId}`\n }\n aria-invalid={!!error}\n {...props}\n />\n )\n})\nFormControl.displayName = \"FormControl\"\n\nconst FormDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n const { formDescriptionId } = useFormField()\n\n return (\n <p\n ref={ref}\n id={formDescriptionId}\n className={cn(\"text-[0.8rem] text-muted-foreground\", className)}\n {...props}\n />\n )\n})\nFormDescription.displayName = \"FormDescription\"\n\nconst FormMessage = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => {\n const { error, formMessageId } = useFormField()\n const body = error ? String(error?.message ?? \"\") : children\n\n if (!body) {\n return null\n }\n\n return (\n <p\n ref={ref}\n id={formMessageId}\n className={cn(\"text-[0.8rem] font-medium text-destructive\", className)}\n {...props}\n >\n {body}\n </p>\n )\n})\nFormMessage.displayName = \"FormMessage\"\n\nexport {\n useFormField,\n Form,\n FormItem,\n FormLabel,\n FormControl,\n FormDescription,\n FormMessage,\n FormField,\n}\n",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport {\n Controller,\n FormProvider,\n useFormContext,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Label } from \"@/registry/new-york/ui/label\"\n\nconst Form = FormProvider\n\ntype FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = {\n name: TName\n}\n\nconst FormFieldContext = React.createContext<FormFieldContextValue | null>(null)\n\nconst FormField = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n ...props\n}: ControllerProps<TFieldValues, TName>) => {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n )\n}\n\nconst useFormField = () => {\n const fieldContext = React.useContext(FormFieldContext)\n const itemContext = React.useContext(FormItemContext)\n const { getFieldState, formState } = useFormContext()\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\")\n }\n\n if (!itemContext) {\n throw new Error(\"useFormField should be used within <FormItem>\")\n }\n\n const fieldState = getFieldState(fieldContext.name, formState)\n\n const { id } = itemContext\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n }\n}\n\ntype FormItemContextValue = {\n id: string\n}\n\nconst FormItemContext = React.createContext<FormItemContextValue | null>(null)\n\nconst FormItem = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const id = React.useId()\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <div ref={ref} className={cn(\"space-y-2\", className)} {...props} />\n </FormItemContext.Provider>\n )\n})\nFormItem.displayName = \"FormItem\"\n\nconst FormLabel = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const { error, formItemId } = useFormField()\n\n return (\n <Label\n ref={ref}\n className={cn(error && \"text-destructive\", className)}\n htmlFor={formItemId}\n {...props}\n />\n )\n})\nFormLabel.displayName = \"FormLabel\"\n\nconst FormControl = React.forwardRef<\n React.ElementRef<typeof Slot>,\n React.ComponentPropsWithoutRef<typeof Slot>\n>(({ ...props }, ref) => {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n return (\n <Slot\n ref={ref}\n id={formItemId}\n aria-describedby={\n !error\n ? `${formDescriptionId}`\n : `${formDescriptionId} ${formMessageId}`\n }\n aria-invalid={!!error}\n {...props}\n />\n )\n})\nFormControl.displayName = \"FormControl\"\n\nconst FormDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n const { formDescriptionId } = useFormField()\n\n return (\n <p\n ref={ref}\n id={formDescriptionId}\n className={cn(\"text-[0.8rem] text-muted-foreground\", className)}\n {...props}\n />\n )\n})\nFormDescription.displayName = \"FormDescription\"\n\nconst FormMessage = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => {\n const { error, formMessageId } = useFormField()\n const body = error ? String(error?.message ?? \"\") : children\n\n if (!body) {\n return null\n }\n\n return (\n <p\n ref={ref}\n id={formMessageId}\n className={cn(\"text-[0.8rem] font-medium text-destructive\", className)}\n {...props}\n >\n {body}\n </p>\n )\n})\nFormMessage.displayName = \"FormMessage\"\n\nexport {\n useFormField,\n Form,\n FormItem,\n FormLabel,\n FormControl,\n FormDescription,\n FormMessage,\n FormField,\n}\n",
"type": "registry:ui",
"target": ""
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -4,5 +4,3 @@
> The site at ui.shadcn.com now points to `apps/v4`. All changes should be made in the `apps/v4` directory.
Licensed under the [MIT license](https://github.com/shadcn/ui/blob/main/LICENSE.md).
# This is a test.

View File

@@ -88,7 +88,7 @@
"react-resizable-panels": "^2.0.22",
"react-wrap-balancer": "^0.4.1",
"recharts": "2.12.7",
"shadcn": "3.4.0",
"shadcn": "3.4.2",
"sharp": "^0.32.6",
"sonner": "^1.2.3",
"swr": "2.2.6-beta.3",

View File

@@ -1,52 +1,52 @@
{
"@8bitcn": "https://8bitcn.com/r/{name}.json",
"@97cn": "https://97cn.itzik.co/r/{name}.json",
"@aceternity": "https://ui.aceternity.com/registry/{name}.json",
"@ai-elements": "https://registry.ai-sdk.dev/{name}.json",
"@alexcarpenter": "https://ui.alexcarpenter.me/r/{name}.json",
"@alpine": "https://alpine-registry.vercel.app/r/{name}.json",
"@animate-ui": "https://animate-ui.com/r/{name}.json",
"@assistant-ui": "https://r.assistant-ui.com/{name}.json",
"@austin-ui": "https://austin-ui.netlify.app/r/{name}.json",
"@basecn": "https://basecn.dev/r/{name}.json",
"@better-upload": "https://better-upload.com/r/{name}.json",
"@billingsdk": "https://billingsdk.com/r/{name}.json",
"@blocks": "https://blocks.so/r/{name}.json",
"@bucharitesh": "https://bucharitesh.in/r/{name}.json",
"@clerk": "https://clerk.com/r/{name}.json",
"@cult-ui": "https://cult-ui.com/r/{name}.json",
"@eldoraui": "https://eldoraui.site/r/{name}.json",
"@elements": "https://tryelements.dev/r/{name}.json",
"@elevenlabs-ui": "https://ui.elevenlabs.io/r/{name}.json",
"@fancy": "https://fancycomponents.dev/r/{name}.json",
"@formcn": "https://formcn.dev/r/{name}.json",
"@heseui": "https://www.heseui.com/r/{name}.json",
"@intentui": "https://intentui.com/r/{name}",
"@kibo-ui": "https://www.kibo-ui.com/r/{name}.json",
"@kokonutui": "https://kokonutui.com/r/{name}.json",
"@limeplay": "https://limeplay.winoffrg.dev/r/{name}.json",
"@magicui": "https://magicui.design/r/{name}.json",
"@motion-primitives": "https://motion-primitives.com/c/{name}.json",
"@originui": "https://originui.com/r/{name}.json",
"@prompt-kit": "https://prompt-kit.com/c/{name}.json",
"@tailark": "https://tailark.com/r/{name}.json",
"@tweakcn": "https://tweakcn.com/r/themes/{name}.json",
"@react-bits": "https://reactbits.dev/r/{name}.json",
"@reui": "https://reui.io/r/{name}.json",
"@heseui": "https://www.heseui.com/r/{name}.json",
"@paceui-ui": "https://ui.paceui.com/r/{name}.json",
"@basecn": "https://basecn.dev/r/{name}.json",
"@ncdai": "https://chanhdai.com/r/{name}.json",
"@8bitcn": "https://8bitcn.com/r/{name}.json",
"@billingsdk": "https://billingsdk.com/r/{name}.json",
"@elements": "https://tryelements.dev/r/{name}.json",
"@nativeui": "https://nativeui.io/registry/{name}.json",
"@ncdai": "https://chanhdai.com/r/{name}.json",
"@paceui-ui": "https://ui.paceui.com/r/{name}.json",
"@prompt-kit": "https://prompt-kit.com/c/{name}.json",
"@react-bits": "https://reactbits.dev/r/{name}.json",
"@react-market": "https://www.react-market.com/get/{name}.json",
"@retroui": "https://retroui.dev/r/{name}.json",
"@reui": "https://reui.io/r/{name}.json",
"@rigidui": "https://rigidui.com/r/{name}.json",
"@scrollxui": "https://www.scrollxui.dev/registry/{name}.json",
"@shadcn-editor": "https://shadcn-editor.vercel.app/r/{name}.json",
"@shadcn-map": "http://shadcn-map.vercel.app/r/{name}.json",
"@shadcn-studio": "https://shadcnstudio.com/r/{name}.json",
"@shadcnblocks": "https://shadcnblocks.com/r/{name}.json",
"@skiper-ui": "https://skiper-ui.com/registry/{name}.json",
"@skyr": "https://ui-play.skyroc.me/r/{name}.json",
"@smoothui": "https://smoothui.dev/r/{name}.json",
"@svgl": "https://svgl.app/r/{name}.json",
"@formcn": "https://formcn.dev/r/{name}.json",
"@limeplay": "https://limeplay.winoffrg.dev/r/{name}.json",
"@skiper-ui": "https://skiper-ui.com/registry/{name}.json",
"@shadcnblocks": "https://shadcnblocks.com/r/{name}.json",
"@shadcn-editor": "https://shadcn-editor.vercel.app/r/{name}.json",
"@shadcn-studio": "https://shadcnstudio.com/r/{name}.json",
"@rigidui": "https://rigidui.com/r/{name}.json",
"@skyr": "https://ui-play.skyroc.me/r/{name}.json",
"@retroui": "https://retroui.dev/r/{name}.json",
"@tailark": "https://tailark.com/r/{name}.json",
"@tweakcn": "https://tweakcn.com/r/themes/{name}.json",
"@wds": "https://wds-shadcn-registry.netlify.app/r/{name}.json",
"@97cn": "https://97cn.itzik.co/r/{name}.json",
"@better-upload": "https://better-upload.com/r/{name}.json",
"@zippystarter": "https://zippystarter.com/r/{name}.json",
"@elevenlabs-ui": "https://ui.elevenlabs.io/r/{name}.json",
"@eldoraui": "https://eldoraui.site/r/{name}.json",
"@intentui": "https://intentui.com/r/{name}",
"@shadcn-map": "http://shadcn-map.vercel.app/r/{name}.json",
"@fancy": "https://fancycomponents.dev/r/{name}.json",
"@marmelab": "https://marmelab.com/shadcn-admin-kit/r/{name}.json"
"@zippystarter": "https://zippystarter.com/r/{name}.json"
}

View File

@@ -17,7 +17,7 @@
"files": [
{
"path": "ui/form.tsx",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport {\n Controller,\n FormProvider,\n useFormContext,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Label } from \"@/registry/default/ui/label\"\n\nconst Form = FormProvider\n\ntype FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = {\n name: TName\n}\n\nconst FormFieldContext = React.createContext<FormFieldContextValue>(\n {} as FormFieldContextValue\n)\n\nconst FormField = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n ...props\n}: ControllerProps<TFieldValues, TName>) => {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n )\n}\n\nconst useFormField = () => {\n const fieldContext = React.useContext(FormFieldContext)\n const itemContext = React.useContext(FormItemContext)\n const { getFieldState, formState } = useFormContext()\n\n const fieldState = getFieldState(fieldContext.name, formState)\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\")\n }\n\n const { id } = itemContext\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n }\n}\n\ntype FormItemContextValue = {\n id: string\n}\n\nconst FormItemContext = React.createContext<FormItemContextValue>(\n {} as FormItemContextValue\n)\n\nconst FormItem = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const id = React.useId()\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <div ref={ref} className={cn(\"space-y-2\", className)} {...props} />\n </FormItemContext.Provider>\n )\n})\nFormItem.displayName = \"FormItem\"\n\nconst FormLabel = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const { error, formItemId } = useFormField()\n\n return (\n <Label\n ref={ref}\n className={cn(error && \"text-destructive\", className)}\n htmlFor={formItemId}\n {...props}\n />\n )\n})\nFormLabel.displayName = \"FormLabel\"\n\nconst FormControl = React.forwardRef<\n React.ElementRef<typeof Slot>,\n React.ComponentPropsWithoutRef<typeof Slot>\n>(({ ...props }, ref) => {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n return (\n <Slot\n ref={ref}\n id={formItemId}\n aria-describedby={\n !error\n ? `${formDescriptionId}`\n : `${formDescriptionId} ${formMessageId}`\n }\n aria-invalid={!!error}\n {...props}\n />\n )\n})\nFormControl.displayName = \"FormControl\"\n\nconst FormDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n const { formDescriptionId } = useFormField()\n\n return (\n <p\n ref={ref}\n id={formDescriptionId}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n})\nFormDescription.displayName = \"FormDescription\"\n\nconst FormMessage = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => {\n const { error, formMessageId } = useFormField()\n const body = error ? String(error?.message ?? \"\") : children\n\n if (!body) {\n return null\n }\n\n return (\n <p\n ref={ref}\n id={formMessageId}\n className={cn(\"text-sm font-medium text-destructive\", className)}\n {...props}\n >\n {body}\n </p>\n )\n})\nFormMessage.displayName = \"FormMessage\"\n\nexport {\n useFormField,\n Form,\n FormItem,\n FormLabel,\n FormControl,\n FormDescription,\n FormMessage,\n FormField,\n}\n",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport {\n Controller,\n FormProvider,\n useFormContext,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Label } from \"@/registry/default/ui/label\"\n\nconst Form = FormProvider\n\ntype FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = {\n name: TName\n}\n\nconst FormFieldContext = React.createContext<FormFieldContextValue | null>(null)\n\nconst FormField = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n ...props\n}: ControllerProps<TFieldValues, TName>) => {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n )\n}\n\nconst useFormField = () => {\n const fieldContext = React.useContext(FormFieldContext)\n const itemContext = React.useContext(FormItemContext)\n const { getFieldState, formState } = useFormContext()\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\")\n }\n\n if (!itemContext) {\n throw new Error(\"useFormField should be used within <FormItem>\")\n }\n\n const fieldState = getFieldState(fieldContext.name, formState)\n\n const { id } = itemContext\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n }\n}\n\ntype FormItemContextValue = {\n id: string\n}\n\nconst FormItemContext = React.createContext<FormItemContextValue | null>(null)\n\nconst FormItem = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const id = React.useId()\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <div ref={ref} className={cn(\"space-y-2\", className)} {...props} />\n </FormItemContext.Provider>\n )\n})\nFormItem.displayName = \"FormItem\"\n\nconst FormLabel = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const { error, formItemId } = useFormField()\n\n return (\n <Label\n ref={ref}\n className={cn(error && \"text-destructive\", className)}\n htmlFor={formItemId}\n {...props}\n />\n )\n})\nFormLabel.displayName = \"FormLabel\"\n\nconst FormControl = React.forwardRef<\n React.ElementRef<typeof Slot>,\n React.ComponentPropsWithoutRef<typeof Slot>\n>(({ ...props }, ref) => {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n return (\n <Slot\n ref={ref}\n id={formItemId}\n aria-describedby={\n !error\n ? `${formDescriptionId}`\n : `${formDescriptionId} ${formMessageId}`\n }\n aria-invalid={!!error}\n {...props}\n />\n )\n})\nFormControl.displayName = \"FormControl\"\n\nconst FormDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n const { formDescriptionId } = useFormField()\n\n return (\n <p\n ref={ref}\n id={formDescriptionId}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n )\n})\nFormDescription.displayName = \"FormDescription\"\n\nconst FormMessage = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => {\n const { error, formMessageId } = useFormField()\n const body = error ? String(error?.message ?? \"\") : children\n\n if (!body) {\n return null\n }\n\n return (\n <p\n ref={ref}\n id={formMessageId}\n className={cn(\"text-sm font-medium text-destructive\", className)}\n {...props}\n >\n {body}\n </p>\n )\n})\nFormMessage.displayName = \"FormMessage\"\n\nexport {\n useFormField,\n Form,\n FormItem,\n FormLabel,\n FormControl,\n FormDescription,\n FormMessage,\n FormField,\n}\n",
"type": "registry:ui",
"target": ""
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -8,7 +8,7 @@
"files": [
{
"path": "registry/new-york-v4/examples/sonner-types.tsx",
"content": "\"use client\"\n\nimport { toast } from \"sonner\"\n\nimport { Button } from \"@/registry/new-york-v4/ui/button\"\n\nexport default function SonnerTypes() {\n return (\n <div className=\"flex flex-wrap gap-2\">\n <Button variant=\"outline\" onClick={() => toast(\"Event has been created\")}>\n Default\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => toast.success(\"Event has been created\")}\n >\n Success\n </Button>\n <Button\n variant=\"outline\"\n onClick={() =>\n toast.info(\"Be at the area 10 minutes before the event time\")\n }\n >\n Info\n </Button>\n <Button\n variant=\"outline\"\n onClick={() =>\n toast.warning(\"Event start time cannot be earlier than 8am\")\n }\n >\n Warning\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => toast.error(\"Event has not been created\")}\n >\n Error\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => {\n const promise = () =>\n new Promise((resolve) =>\n setTimeout(() => resolve({ name: \"Event\" }), 2000)\n )\n\n toast.promise(promise(), {\n loading: \"Loading...\",\n success: (data) => `${data.name} has been created`,\n error: \"Error\",\n })\n }}\n >\n Promise\n </Button>\n </div>\n )\n}\n",
"content": "\"use client\"\n\nimport { toast } from \"sonner\"\n\nimport { Button } from \"@/registry/new-york-v4/ui/button\"\n\nexport default function SonnerTypes() {\n return (\n <div className=\"flex flex-wrap gap-2\">\n <Button variant=\"outline\" onClick={() => toast(\"Event has been created\")}>\n Default\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => toast.success(\"Event has been created\")}\n >\n Success\n </Button>\n <Button\n variant=\"outline\"\n onClick={() =>\n toast.info(\"Be at the area 10 minutes before the event time\")\n }\n >\n Info\n </Button>\n <Button\n variant=\"outline\"\n onClick={() =>\n toast.warning(\"Event start time cannot be earlier than 8am\")\n }\n >\n Warning\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => toast.error(\"Event has not been created\")}\n >\n Error\n </Button>\n <Button\n variant=\"outline\"\n onClick={() => {\n toast.promise<{ name: string }>(\n () =>\n new Promise((resolve) =>\n setTimeout(() => resolve({ name: \"Event\" }), 2000)\n ),\n {\n loading: \"Loading...\",\n success: (data) => `${data.name} has been created`,\n error: \"Error\",\n }\n )\n }}\n >\n Promise\n </Button>\n </div>\n )\n}\n",
"type": "registry:example"
}
]

View File

@@ -17,7 +17,7 @@
"files": [
{
"path": "ui/form.tsx",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport {\n Controller,\n FormProvider,\n useFormContext,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Label } from \"@/registry/new-york/ui/label\"\n\nconst Form = FormProvider\n\ntype FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = {\n name: TName\n}\n\nconst FormFieldContext = React.createContext<FormFieldContextValue>(\n {} as FormFieldContextValue\n)\n\nconst FormField = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n ...props\n}: ControllerProps<TFieldValues, TName>) => {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n )\n}\n\nconst useFormField = () => {\n const fieldContext = React.useContext(FormFieldContext)\n const itemContext = React.useContext(FormItemContext)\n const { getFieldState, formState } = useFormContext()\n\n const fieldState = getFieldState(fieldContext.name, formState)\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\")\n }\n\n const { id } = itemContext\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n }\n}\n\ntype FormItemContextValue = {\n id: string\n}\n\nconst FormItemContext = React.createContext<FormItemContextValue>(\n {} as FormItemContextValue\n)\n\nconst FormItem = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const id = React.useId()\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <div ref={ref} className={cn(\"space-y-2\", className)} {...props} />\n </FormItemContext.Provider>\n )\n})\nFormItem.displayName = \"FormItem\"\n\nconst FormLabel = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const { error, formItemId } = useFormField()\n\n return (\n <Label\n ref={ref}\n className={cn(error && \"text-destructive\", className)}\n htmlFor={formItemId}\n {...props}\n />\n )\n})\nFormLabel.displayName = \"FormLabel\"\n\nconst FormControl = React.forwardRef<\n React.ElementRef<typeof Slot>,\n React.ComponentPropsWithoutRef<typeof Slot>\n>(({ ...props }, ref) => {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n return (\n <Slot\n ref={ref}\n id={formItemId}\n aria-describedby={\n !error\n ? `${formDescriptionId}`\n : `${formDescriptionId} ${formMessageId}`\n }\n aria-invalid={!!error}\n {...props}\n />\n )\n})\nFormControl.displayName = \"FormControl\"\n\nconst FormDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n const { formDescriptionId } = useFormField()\n\n return (\n <p\n ref={ref}\n id={formDescriptionId}\n className={cn(\"text-[0.8rem] text-muted-foreground\", className)}\n {...props}\n />\n )\n})\nFormDescription.displayName = \"FormDescription\"\n\nconst FormMessage = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => {\n const { error, formMessageId } = useFormField()\n const body = error ? String(error?.message ?? \"\") : children\n\n if (!body) {\n return null\n }\n\n return (\n <p\n ref={ref}\n id={formMessageId}\n className={cn(\"text-[0.8rem] font-medium text-destructive\", className)}\n {...props}\n >\n {body}\n </p>\n )\n})\nFormMessage.displayName = \"FormMessage\"\n\nexport {\n useFormField,\n Form,\n FormItem,\n FormLabel,\n FormControl,\n FormDescription,\n FormMessage,\n FormField,\n}\n",
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as LabelPrimitive from \"@radix-ui/react-label\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport {\n Controller,\n FormProvider,\n useFormContext,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Label } from \"@/registry/new-york/ui/label\"\n\nconst Form = FormProvider\n\ntype FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = {\n name: TName\n}\n\nconst FormFieldContext = React.createContext<FormFieldContextValue | null>(null)\n\nconst FormField = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n ...props\n}: ControllerProps<TFieldValues, TName>) => {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n )\n}\n\nconst useFormField = () => {\n const fieldContext = React.useContext(FormFieldContext)\n const itemContext = React.useContext(FormItemContext)\n const { getFieldState, formState } = useFormContext()\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\")\n }\n\n if (!itemContext) {\n throw new Error(\"useFormField should be used within <FormItem>\")\n }\n\n const fieldState = getFieldState(fieldContext.name, formState)\n\n const { id } = itemContext\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n }\n}\n\ntype FormItemContextValue = {\n id: string\n}\n\nconst FormItemContext = React.createContext<FormItemContextValue | null>(null)\n\nconst FormItem = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement>\n>(({ className, ...props }, ref) => {\n const id = React.useId()\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <div ref={ref} className={cn(\"space-y-2\", className)} {...props} />\n </FormItemContext.Provider>\n )\n})\nFormItem.displayName = \"FormItem\"\n\nconst FormLabel = React.forwardRef<\n React.ElementRef<typeof LabelPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const { error, formItemId } = useFormField()\n\n return (\n <Label\n ref={ref}\n className={cn(error && \"text-destructive\", className)}\n htmlFor={formItemId}\n {...props}\n />\n )\n})\nFormLabel.displayName = \"FormLabel\"\n\nconst FormControl = React.forwardRef<\n React.ElementRef<typeof Slot>,\n React.ComponentPropsWithoutRef<typeof Slot>\n>(({ ...props }, ref) => {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n return (\n <Slot\n ref={ref}\n id={formItemId}\n aria-describedby={\n !error\n ? `${formDescriptionId}`\n : `${formDescriptionId} ${formMessageId}`\n }\n aria-invalid={!!error}\n {...props}\n />\n )\n})\nFormControl.displayName = \"FormControl\"\n\nconst FormDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n const { formDescriptionId } = useFormField()\n\n return (\n <p\n ref={ref}\n id={formDescriptionId}\n className={cn(\"text-[0.8rem] text-muted-foreground\", className)}\n {...props}\n />\n )\n})\nFormDescription.displayName = \"FormDescription\"\n\nconst FormMessage = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => {\n const { error, formMessageId } = useFormField()\n const body = error ? String(error?.message ?? \"\") : children\n\n if (!body) {\n return null\n }\n\n return (\n <p\n ref={ref}\n id={formMessageId}\n className={cn(\"text-[0.8rem] font-medium text-destructive\", className)}\n {...props}\n >\n {body}\n </p>\n )\n})\nFormMessage.displayName = \"FormMessage\"\n\nexport {\n useFormField,\n Form,\n FormItem,\n FormLabel,\n FormControl,\n FormDescription,\n FormMessage,\n FormField,\n}\n",
"type": "registry:ui",
"target": ""
}

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,21 @@
# @shadcn/ui
## 3.4.2
### Patch Changes
- [#8478](https://github.com/shadcn-ui/ui/pull/8478) [`b52ec12f1e22cf89270bf3d931f5b7544e4b80b4`](https://github.com/shadcn-ui/ui/commit/b52ec12f1e22cf89270bf3d931f5b7544e4b80b4) Thanks [@shadcn](https://github.com/shadcn)! - fix regression with universal item detection
## 3.4.1
### Patch Changes
- [#8420](https://github.com/shadcn-ui/ui/pull/8420) [`40c3ff513a88ca8e6f02bf798a7cf73b88401024`](https://github.com/shadcn-ui/ui/commit/40c3ff513a88ca8e6f02bf798a7cf73b88401024) Thanks [@zbeyens](https://github.com/zbeyens)! - Fix support for universal registry items that only have dependencies without files
- [#8459](https://github.com/shadcn-ui/ui/pull/8459) [`7cd019ad3652a0e98770b89032b7a161edfda805`](https://github.com/shadcn-ui/ui/commit/7cd019ad3652a0e98770b89032b7a161edfda805) Thanks [@shadcn](https://github.com/shadcn)! - add support for color as var
- [#8451](https://github.com/shadcn-ui/ui/pull/8451) [`b83023034a301b41fa18045af0d9bd787e415aa5`](https://github.com/shadcn-ui/ui/commit/b83023034a301b41fa18045af0d9bd787e415aa5) Thanks [@diegohaz](https://github.com/diegohaz)! - fix adding registry item with CSS at-property
## 3.4.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "shadcn",
"version": "3.4.0",
"version": "3.4.2",
"description": "Add components to your apps.",
"publishConfig": {
"access": "public"

View File

@@ -144,6 +144,7 @@ describe("isLocalFile", () => {
describe("isUniversalRegistryItem", () => {
it("should return true when all files have targets with registry:file type", () => {
const registryItem = {
type: "registry:item" as const,
files: [
{
path: "file1.ts",
@@ -160,7 +161,26 @@ describe("isUniversalRegistryItem", () => {
expect(isUniversalRegistryItem(registryItem)).toBe(true)
})
it("should return true for any registry item type if all files are registry:file with targets", () => {
it("should return true when registry item type is registry:file and all files have targets", () => {
const registryItem = {
type: "registry:file" as const,
files: [
{
path: "file1.ts",
target: "src/file1.ts",
type: "registry:file" as const,
},
{
path: "file2.ts",
target: "src/utils/file2.ts",
type: "registry:item" as const,
},
],
}
expect(isUniversalRegistryItem(registryItem)).toBe(true)
})
it("should return false for any registry item type other than registry:item or registry:file", () => {
const registryItem = {
type: "registry:ui" as const,
files: [
@@ -171,11 +191,12 @@ describe("isUniversalRegistryItem", () => {
},
],
}
expect(isUniversalRegistryItem(registryItem)).toBe(true)
expect(isUniversalRegistryItem(registryItem)).toBe(false)
})
it("should return false when some files lack targets", () => {
const registryItem = {
type: "registry:item" as const,
files: [
{
path: "file1.ts",
@@ -190,6 +211,7 @@ describe("isUniversalRegistryItem", () => {
it("should return false when files have non-registry:file type", () => {
const registryItem = {
type: "registry:item" as const,
files: [
{
path: "file1.ts",
@@ -208,6 +230,7 @@ describe("isUniversalRegistryItem", () => {
it("should return false when no files have targets", () => {
const registryItem = {
type: "registry:item" as const,
files: [
{ path: "file1.ts", target: "", type: "registry:file" as const },
{ path: "file2.ts", target: "", type: "registry:file" as const },
@@ -216,18 +239,44 @@ describe("isUniversalRegistryItem", () => {
expect(isUniversalRegistryItem(registryItem)).toBe(false)
})
it("should return true when files array is empty", () => {
it("should return true when files array is empty and type is registry:item", () => {
const registryItem = {
type: "registry:item" as const,
files: [],
}
expect(isUniversalRegistryItem(registryItem)).toBe(true)
})
it("should return true when files is undefined", () => {
const registryItem = {}
it("should return true when files is undefined and type is registry:item", () => {
const registryItem = {
type: "registry:item" as const,
}
expect(isUniversalRegistryItem(registryItem)).toBe(true)
})
it("should return false when type is registry:style", () => {
const registryItem = {
type: "registry:style" as const,
files: [],
}
expect(isUniversalRegistryItem(registryItem)).toBe(false)
})
it("should return false when type is registry:ui", () => {
const registryItem = {
type: "registry:ui" as const,
files: [],
}
expect(isUniversalRegistryItem(registryItem)).toBe(false)
})
it("should return false when files is undefined and type is not registry:item or registry:file", () => {
const registryItem = {
type: "registry:component" as const,
}
expect(isUniversalRegistryItem(registryItem)).toBe(false)
})
it("should return false when registryItem is null", () => {
expect(isUniversalRegistryItem(null)).toBe(false)
})
@@ -238,6 +287,7 @@ describe("isUniversalRegistryItem", () => {
it("should return false when target is null", () => {
const registryItem = {
type: "registry:item" as const,
files: [
{
path: "file1.ts",
@@ -251,6 +301,7 @@ describe("isUniversalRegistryItem", () => {
it("should return false when target is undefined", () => {
const registryItem = {
type: "registry:item" as const,
files: [
{
path: "file1.ts",
@@ -264,6 +315,7 @@ describe("isUniversalRegistryItem", () => {
it("should return false when files have registry:component type even with targets", () => {
const registryItem = {
type: "registry:item" as const,
files: [
{
path: "component.tsx",
@@ -277,6 +329,7 @@ describe("isUniversalRegistryItem", () => {
it("should return false when files have registry:hook type even with targets", () => {
const registryItem = {
type: "registry:item" as const,
files: [
{
path: "use-hook.ts",
@@ -290,6 +343,7 @@ describe("isUniversalRegistryItem", () => {
it("should return false when files have registry:lib type even with targets", () => {
const registryItem = {
type: "registry:item" as const,
files: [
{
path: "utils.ts",
@@ -303,6 +357,7 @@ describe("isUniversalRegistryItem", () => {
it("should return true when all targets are non-empty strings for registry:file", () => {
const registryItem = {
type: "registry:item" as const,
files: [
{ path: "file1.ts", target: " ", type: "registry:file" as const }, // whitespace is truthy
{ path: "file2.ts", target: "0", type: "registry:file" as const }, // "0" is truthy
@@ -313,6 +368,7 @@ describe("isUniversalRegistryItem", () => {
it("should handle real-world example with path traversal attempts for registry:file", () => {
const registryItem = {
type: "registry:item" as const,
files: [
{
path: "malicious.ts",
@@ -326,18 +382,18 @@ describe("isUniversalRegistryItem", () => {
},
],
}
// The function should still return true - path validation is handled elsewhere
// The function should still return true - path validation is handled elsewhere.
expect(isUniversalRegistryItem(registryItem)).toBe(true)
})
it("should return false when files have non-registry:file type in a UI registry item", () => {
it("should return false when registry item type is registry:ui", () => {
const registryItem = {
type: "registry:ui" as const,
files: [
{
path: "button.tsx",
target: "src/components/ui/button.tsx",
type: "registry:ui" as const, // Not registry:file
type: "registry:file" as const,
},
],
}

View File

@@ -267,14 +267,14 @@ export function isLocalFile(path: string) {
/**
* Check if a registry item is universal (framework-agnostic).
* A universal registry item must have all files with:
* 1. Explicit targets
* 2. Type "registry:file"
* A universal registry item must:
* 1. Have type "registry:item" or "registry:file"
* 2. If it has files, all files must have explicit targets and be type "registry:file" or "registry:item"
* It can be installed without framework detection or components.json.
*/
export function isUniversalRegistryItem(
registryItem:
| Pick<z.infer<typeof registryItemSchema>, "files">
| Pick<z.infer<typeof registryItemSchema>, "files" | "type">
| null
| undefined
): boolean {
@@ -282,8 +282,16 @@ export function isUniversalRegistryItem(
return false
}
if (
registryItem.type !== "registry:item" &&
registryItem.type !== "registry:file"
) {
return false
}
const files = registryItem.files ?? []
// If there are files, all must have targets and be of type registry:file or registry:item.
return files.every(
(file) =>
!!file.target &&

4
pnpm-lock.yaml generated
View File

@@ -331,7 +331,7 @@ importers:
specifier: ^6.0.1
version: 6.0.1
shadcn:
specifier: 3.4.0
specifier: 3.4.2
version: link:../../packages/shadcn
shiki:
specifier: ^1.10.1
@@ -611,7 +611,7 @@ importers:
specifier: 2.12.7
version: 2.12.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
shadcn:
specifier: 3.4.0
specifier: 3.4.2
version: link:../../packages/shadcn
sharp:
specifier: ^0.32.6