@nikala-ui/core 0.10.1 → 0.11.0-nightly.b01fa01
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/registry/banner.json +1 -1
- package/registry/bubble.json +18 -0
- package/registry/button-group.json +20 -0
- package/registry/button.json +1 -1
- package/registry/checkbox.json +4 -1
- package/registry/combobox.json +1 -1
- package/registry/command.json +3 -2
- package/registry/context-menu.json +1 -1
- package/registry/create-app-updater.json +13 -0
- package/registry/create-chat-scroll.json +13 -0
- package/registry/create-document-tabs.json +13 -0
- package/registry/create-drop-zone.json +13 -0
- package/registry/create-global-shortcut.json +13 -0
- package/registry/create-pagination.json +13 -0
- package/registry/create-tauri-window.json +13 -0
- package/registry/dialog.json +1 -1
- package/registry/dropdown-menu.json +3 -2
- package/registry/dropzone.json +21 -0
- package/registry/field.json +1 -1
- package/registry/footer.json +18 -0
- package/registry/forgot-password-01.json +28 -0
- package/registry/form-message.json +3 -2
- package/registry/hero-01.json +22 -0
- package/registry/icon-button.json +1 -1
- package/registry/index.json +432 -5
- package/registry/login-01.json +28 -0
- package/registry/marker.json +17 -0
- package/registry/marquee.json +17 -0
- package/registry/message.json +17 -0
- package/registry/navbar.json +19 -0
- package/registry/navigation-menu.json +22 -0
- package/registry/number-input.json +1 -1
- package/registry/otp-verification-01.json +26 -0
- package/registry/pagination.json +22 -0
- package/registry/popover.json +4 -1
- package/registry/rating.json +19 -0
- package/registry/register-01.json +31 -0
- package/registry/resizable.json +1 -1
- package/registry/review-card.json +23 -0
- package/registry/scroll-area.json +1 -1
- package/registry/select.json +3 -2
- package/registry/sheet.json +1 -1
- package/registry/sidebar.json +24 -0
- package/registry/spinner.json +1 -1
- package/registry/stat.json +19 -0
- package/registry/status.json +1 -1
- package/registry/switch.json +4 -1
- package/registry/table.json +17 -0
- package/registry/tabs.json +4 -1
- package/registry/theme-manager.json +4 -3
- package/registry/timeline.json +18 -0
- package/registry/titlebar-tabs.json +24 -0
- package/registry/titlebar.json +26 -0
- package/registry/toggle-group.json +21 -0
- package/registry/updater-modal.json +26 -0
- package/src/registry/blocks/forgot-password-01.tsx +141 -0
- package/src/registry/blocks/hero-01.tsx +28 -0
- package/src/registry/blocks/login-01.tsx +231 -0
- package/src/registry/blocks/otp-verification-01.tsx +170 -0
- package/src/registry/blocks/register-01.tsx +318 -0
- package/src/registry/components/ui/banner.tsx +0 -2
- package/src/registry/components/ui/bubble.tsx +142 -0
- package/src/registry/components/ui/button-group.tsx +42 -0
- package/src/registry/components/ui/button.tsx +1 -1
- package/src/registry/components/ui/checkbox.tsx +1 -1
- package/src/registry/components/ui/combobox.tsx +83 -18
- package/src/registry/components/ui/command.tsx +101 -105
- package/src/registry/components/ui/context-menu.tsx +67 -22
- package/src/registry/components/ui/dialog.tsx +42 -32
- package/src/registry/components/ui/dropdown-menu.tsx +69 -31
- package/src/registry/components/ui/dropzone.tsx +189 -0
- package/src/registry/components/ui/field.tsx +7 -3
- package/src/registry/components/ui/footer.tsx +247 -0
- package/src/registry/components/ui/form-message.tsx +2 -2
- package/src/registry/components/ui/icon-button.tsx +1 -1
- package/src/registry/components/ui/marker.tsx +102 -0
- package/src/registry/components/ui/marquee.tsx +118 -0
- package/src/registry/components/ui/message.tsx +168 -0
- package/src/registry/components/ui/navbar.tsx +375 -0
- package/src/registry/components/ui/navigation-menu.tsx +358 -0
- package/src/registry/components/ui/number-input.tsx +3 -3
- package/src/registry/components/ui/pagination.tsx +258 -0
- package/src/registry/components/ui/popover.tsx +1 -1
- package/src/registry/components/ui/rating.tsx +185 -0
- package/src/registry/components/ui/resizable.tsx +3 -1
- package/src/registry/components/ui/review-card.tsx +195 -0
- package/src/registry/components/ui/scroll-area.tsx +13 -3
- package/src/registry/components/ui/select.tsx +16 -19
- package/src/registry/components/ui/sheet.tsx +58 -53
- package/src/registry/components/ui/sidebar.tsx +692 -0
- package/src/registry/components/ui/spinner.tsx +1 -1
- package/src/registry/components/ui/stat.tsx +245 -0
- package/src/registry/components/ui/status.tsx +7 -5
- package/src/registry/components/ui/switch.tsx +1 -1
- package/src/registry/components/ui/table.tsx +160 -0
- package/src/registry/components/ui/tabs.tsx +1 -1
- package/src/registry/components/ui/theme-toggle.tsx +80 -79
- package/src/registry/components/ui/timeline.tsx +350 -0
- package/src/registry/components/ui/titlebar-tabs.tsx +412 -0
- package/src/registry/components/ui/titlebar.tsx +399 -0
- package/src/registry/components/ui/toggle-group.tsx +203 -0
- package/src/registry/components/ui/updater-modal.tsx +254 -0
- package/src/registry/index.ts +3 -3
- package/src/registry/metadata.ts +184 -5
- package/src/registry/providers/theme-transitions.ts +81 -50
package/registry/dialog.json
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"files": [
|
|
15
15
|
{
|
|
16
16
|
"path": "ui/dialog.tsx",
|
|
17
|
-
"content": "import { splitProps, type Component, type JSX, type ValidComponent, Show } from \"solid-js\";\nimport * as DialogPrimitive from \"@kobalte/core/dialog\";\nimport type { PolymorphicProps } from \"@kobalte/core/polymorphic\";\nimport { ScrollArea } from \"
|
|
17
|
+
"content": "import { splitProps, type Component, type JSX, type ValidComponent, Show } from \"solid-js\";\nimport * as DialogPrimitive from \"@kobalte/core/dialog\";\nimport type { PolymorphicProps } from \"@kobalte/core/polymorphic\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { cn } from \"@/lib/cn\";\n\nexport type DialogRootProps = DialogPrimitive.DialogRootProps;\n\n/**\n * Root Dialog component managing modal open state.\n */\nexport const Dialog: Component<DialogRootProps> = (props) => {\n return <DialogPrimitive.Root {...props} />;\n};\n\nexport const DialogTrigger = DialogPrimitive.Trigger;\n\nexport type DialogOverlayProps<T extends ValidComponent = \"div\"> =\n DialogPrimitive.DialogOverlayProps<T> & {\n /** Whether to apply background blur effect (default: true) */\n blur?: boolean;\n class?: string;\n };\n\n/**\n * Backdrop overlay wrapper with optional backdrop blur styling.\n */\nexport const DialogOverlay = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DialogOverlayProps<T>>\n) => {\n const [local, rest] = splitProps(props as DialogOverlayProps, [\"class\", \"blur\"]);\n\n return (\n <DialogPrimitive.Overlay\n class={cn(\n \"fixed inset-0 z-50 bg-black/80 data-expanded:animate-in data-closed:animate-out data-[closed]:fade-out-0 data-[expanded]:fade-in-0\",\n local.blur !== false && \"backdrop-blur-sm\",\n local.class\n )}\n {...(rest as any)}\n />\n );\n};\n\nexport type DialogContentProps<T extends ValidComponent = \"div\"> =\n DialogPrimitive.DialogContentProps<T> & {\n /** Whether to show the top-right close (X) button (default: true) */\n showCloseButton?: boolean;\n /** Whether clicking outside closes the dialog (default: true) */\n closeOnOutsideClick?: boolean;\n /** Whether to apply background backdrop blur (default: true) */\n blur?: boolean;\n class?: string;\n children?: JSX.Element;\n };\n\n/**\n * Main dialog popup window housing header, content, and footer.\n */\nexport const DialogContent = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DialogContentProps<T>>\n) => {\n const [local, rest] = splitProps(props as DialogContentProps, [\n \"class\",\n \"children\",\n \"showCloseButton\",\n \"closeOnOutsideClick\",\n \"blur\",\n \"onPointerDownOutside\",\n \"onInteractOutside\",\n ]);\n\n const handlePointerDownOutside = (e: Event) => {\n if (local.closeOnOutsideClick === false) {\n e.preventDefault();\n }\n if (typeof local.onPointerDownOutside === \"function\") {\n local.onPointerDownOutside(e as any);\n }\n };\n\n const handleInteractOutside = (e: Event) => {\n if (local.closeOnOutsideClick === false) {\n e.preventDefault();\n }\n if (typeof local.onInteractOutside === \"function\") {\n local.onInteractOutside(e as any);\n }\n };\n\n return (\n <DialogPrimitive.Portal>\n {/* Forward blur prop to DialogOverlay */}\n <DialogOverlay blur={local.blur} />\n <DialogPrimitive.Content\n onPointerDownOutside={handlePointerDownOutside}\n onInteractOutside={handleInteractOutside}\n class={cn(\n \"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] border border-border bg-popover shadow-lg duration-200 data-expanded:animate-in data-closed:animate-out data-[closed]:fade-out-0 data-[expanded]:fade-in-0 data-closed:zoom-out-95 data-expanded:zoom-in-95 data-[closed]:slide-out-to-left-1/2 data-[closed]:slide-out-to-top-[48%] data-[expanded]:slide-in-from-left-1/2 data-[expanded]:slide-in-from-top-[48%] sm:rounded-lg text-card-foreground overflow-hidden max-h-[80vh]\",\n local.class\n )}\n {...(rest as any)}\n >\n <ScrollArea class=\"max-h-[80vh] w-full\">\n <div class=\"p-6 space-y-4\">\n {local.children}\n </div>\n </ScrollArea>\n <Show when={local.showCloseButton !== false}>\n <DialogPrimitive.CloseButton class=\"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-expanded:bg-accent data-expanded:text-muted-foreground cursor-pointer z-50\">\n <svg class=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n <span class=\"sr-only\">Close</span>\n </DialogPrimitive.CloseButton>\n </Show>\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n );\n};\n\nexport interface DialogHeaderProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\n/**\n * Dialog top header container.\n */\nexport const DialogHeader: Component<DialogHeaderProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <div\n class={cn(\"flex flex-col space-y-1.5 text-center sm:text-left\", local.class)}\n {...rest}\n />\n );\n};\n\nexport interface DialogFooterProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\n/**\n * Dialog bottom action buttons area.\n */\nexport const DialogFooter: Component<DialogFooterProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <div\n class={cn(\"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2\", local.class)}\n {...rest}\n />\n );\n};\n\nexport type DialogTitleProps<T extends ValidComponent = \"h2\"> =\n DialogPrimitive.DialogTitleProps<T> & {\n class?: string;\n };\n\n/**\n * Dialog title heading.\n */\nexport const DialogTitle = <T extends ValidComponent = \"h2\">(\n props: PolymorphicProps<T, DialogTitleProps<T>>\n) => {\n const [local, rest] = splitProps(props as DialogTitleProps, [\"class\"]);\n\n return (\n <DialogPrimitive.Title\n class={cn(\"text-lg font-semibold leading-none tracking-tight text-foreground\", local.class)}\n {...(rest as any)}\n />\n );\n};\n\nexport type DialogDescriptionProps<T extends ValidComponent = \"p\"> =\n DialogPrimitive.DialogDescriptionProps<T> & {\n class?: string;\n };\n\n/**\n * Dialog subtitle or description text.\n */\nexport const DialogDescription = <T extends ValidComponent = \"p\">(\n props: PolymorphicProps<T, DialogDescriptionProps<T>>\n) => {\n const [local, rest] = splitProps(props as DialogDescriptionProps, [\"class\"]);\n\n return (\n <DialogPrimitive.Description\n class={cn(\"text-sm text-muted-foreground\", local.class)}\n {...(rest as any)}\n />\n );\n};\n\nexport const DialogClose = DialogPrimitive.CloseButton;",
|
|
18
18
|
"type": "registry:ui"
|
|
19
19
|
}
|
|
20
20
|
]
|
|
@@ -9,12 +9,13 @@
|
|
|
9
9
|
"@kobalte/core"
|
|
10
10
|
],
|
|
11
11
|
"registryDependencies": [
|
|
12
|
-
"scroll-area"
|
|
12
|
+
"scroll-area",
|
|
13
|
+
"create-click-outside"
|
|
13
14
|
],
|
|
14
15
|
"files": [
|
|
15
16
|
{
|
|
16
17
|
"path": "ui/dropdown-menu.tsx",
|
|
17
|
-
"content": "import { splitProps, type Component, type JSX, type ValidComponent } from \"solid-js\";\nimport * as DropdownMenuPrimitive from \"@kobalte/core/dropdown-menu\";\nimport type { PolymorphicProps } from \"@kobalte/core/polymorphic\";\nimport { createClickOutside } from \"@nikala-ui/hooks\";\nimport { ScrollArea } from \"./scroll-area\";\nimport { cn } from \"@/lib/cn\";\n\nexport type DropdownMenuRootProps = Omit<\n DropdownMenuPrimitive.DropdownMenuRootProps,\n \"placement\"\n> & {\n placement?:\n | \"top\"\n | \"top-start\"\n | \"top-end\"\n | \"right\"\n | \"right-start\"\n | \"right-end\"\n | \"bottom\"\n | \"bottom-start\"\n | \"bottom-end\"\n | \"left\"\n | \"left-start\"\n | \"left-end\";\n};\n\nexport const DropdownMenu: Component<DropdownMenuRootProps> = (props) => {\n return <DropdownMenuPrimitive.Root {...props} />;\n};\n\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\nexport const DropdownMenuSub = DropdownMenuPrimitive.Sub;\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nexport type DropdownMenuSubTriggerProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuSubTriggerProps<T> & {\n class?: string;\n children?: JSX.Element;\n inset?: boolean;\n };\n\nexport const DropdownMenuSubTrigger = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuSubTriggerProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuSubTriggerProps, [\"class\", \"children\", \"inset\"]);\n\n return (\n <DropdownMenuPrimitive.SubTrigger\n class={cn(\n \"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent text-foreground\",\n local.inset && \"pl-8\",\n local.class\n )}\n {...(rest as any)}\n >\n {local.children}\n <svg class=\"ml-auto h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </DropdownMenuPrimitive.SubTrigger>\n );\n};\n\nexport type DropdownMenuSubContentProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuSubContentProps<T> & {\n class?: string;\n };\n\nexport const DropdownMenuSubContent = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuSubContentProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuSubContentProps, [\"class\"]);\n\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.SubContent\n class={cn(\n \"z-50 min-w-32 overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg data-expanded:animate-in data-closed:animate-out data-[closed]:fade-out-0 data-[expanded]:fade-in-0\",\n local.class\n )}\n {...(rest as any)}\n />\n </DropdownMenuPrimitive.Portal>\n );\n};\n\nexport type DropdownMenuContentProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuContentProps<T> & {\n class?: string;\n children?: JSX.Element;\n };\n\nexport const DropdownMenuContent = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuContentProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuContentProps, [\"class\", \"children\"]);\n let contentRef: HTMLElement | undefined;\n\n createClickOutside({\n target: () => contentRef,\n onInteractOutside: (e) => {\n if (typeof (props as any).onInteractOutside === \"function\") {\n (props as any).onInteractOutside(e);\n }\n },\n });\n\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={(el) => {\n contentRef = el;\n if (typeof (props as any).ref === \"function\") (props as any).ref(el);\n }}\n {...(rest as any)}\n sideOffset={(rest as any).sideOffset ?? 8}\n class={cn(\n \"z-50 min-w-32 overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md animate-in fade-in-80 max-h-72 flex flex-col mt-1\",\n local.class\n )}\n >\n <ScrollArea class=\"max-h-72 w-full rounded-[inherit]\">\n <div class=\"p-1\">\n {local.children}\n </div>\n </ScrollArea>\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n );\n};\n\nexport type DropdownMenuItemProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuItemProps<T> & {\n class?: string;\n inset?: boolean;\n };\n\nexport const DropdownMenuItem = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuItemProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuItemProps, [\"class\", \"inset\"]);\n\n return (\n <DropdownMenuPrimitive.Item\n class={cn(\n \"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 text-foreground\",\n local.inset && \"pl-8\",\n local.class\n )}\n {...(rest as any)}\n />\n );\n};\n\nexport type DropdownMenuCheckboxItemProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuCheckboxItemProps<T> & {\n class?: string;\n children?: JSX.Element;\n checked?: boolean;\n };\n\nexport const DropdownMenuCheckboxItem = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuCheckboxItemProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuCheckboxItemProps, [\"class\", \"children\", \"checked\"]);\n\n return (\n <DropdownMenuPrimitive.CheckboxItem\n checked={local.checked}\n class={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 text-foreground\",\n local.class\n )}\n {...(rest as any)}\n >\n <span class=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <svg class=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {local.children}\n </DropdownMenuPrimitive.CheckboxItem>\n );\n};\n\nexport type DropdownMenuRadioItemProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuRadioItemProps<T> & {\n class?: string;\n children?: JSX.Element;\n };\n\nexport const DropdownMenuRadioItem = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuRadioItemProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuRadioItemProps, [\"class\", \"children\"]);\n\n return (\n <DropdownMenuPrimitive.RadioItem\n class={cn(\n \"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 text-foreground\",\n local.class\n )}\n {...(rest as any)}\n >\n <span class=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <svg class=\"h-2 w-2 fill-current\" viewBox=\"0 0 8 8\">\n <circle cx=\"4\" cy=\"4\" r=\"3\" />\n </svg>\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {local.children}\n </DropdownMenuPrimitive.RadioItem>\n );\n};\n\nexport interface DropdownMenuLabelProps {\n class?: string;\n inset?: boolean;\n children?: JSX.Element;\n}\n\nexport const DropdownMenuLabel: Component<DropdownMenuLabelProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"inset\", \"children\"]);\n\n return (\n <DropdownMenuPrimitive.GroupLabel\n class={cn(\"px-2 py-1.5 text-sm font-semibold text-foreground\", local.inset && \"pl-8\", local.class)}\n {...rest}\n >\n {local.children}\n </DropdownMenuPrimitive.GroupLabel>\n );\n};\n\nexport const DropdownMenuSeparator: Component<{ class?: string }> = (props) => {\n return (\n <DropdownMenuPrimitive.Separator\n class={cn(\"-mx-1 my-1 h-px bg-border\", props.class)}\n />\n );\n};\n\nexport interface DropdownMenuShortcutProps {\n class?: string;\n children?: JSX.Element;\n}\n\nexport const DropdownMenuShortcut: Component<DropdownMenuShortcutProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <span class={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", local.class)} {...rest}>\n {local.children}\n </span>\n );\n};",
|
|
18
|
+
"content": "import { splitProps, type Component, type JSX, type ValidComponent, createContext, useContext } from \"solid-js\";\nimport * as DropdownMenuPrimitive from \"@kobalte/core/dropdown-menu\";\nimport type { PolymorphicProps } from \"@kobalte/core/polymorphic\";\nimport { createClickOutside } from \"@/hooks/create-click-outside\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { cn } from \"@/lib/cn\";\n\nconst DropdownGroupContext = createContext<boolean>(false);\n\nexport type DropdownMenuRootProps = Omit<\n DropdownMenuPrimitive.DropdownMenuRootProps,\n \"placement\"\n> & {\n placement?:\n | \"top\"\n | \"top-start\"\n | \"top-end\"\n | \"right\"\n | \"right-start\"\n | \"right-end\"\n | \"bottom\"\n | \"bottom-start\"\n | \"bottom-end\"\n | \"left\"\n | \"left-start\"\n | \"left-end\";\n};\n\nexport const DropdownMenu: Component<DropdownMenuRootProps> = (props) => {\n return <DropdownMenuPrimitive.Root {...props} />;\n};\n\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\n\nexport const DropdownMenuGroup: Component<DropdownMenuPrimitive.DropdownMenuGroupProps> = (props) => {\n return (\n <DropdownGroupContext.Provider value={true}>\n <DropdownMenuPrimitive.Group {...props} />\n </DropdownGroupContext.Provider>\n );\n};\n\nexport const DropdownMenuSub = DropdownMenuPrimitive.Sub;\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nexport type DropdownMenuSubTriggerProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuSubTriggerProps<T> & {\n class?: string;\n children?: JSX.Element;\n inset?: boolean;\n };\n\nexport const DropdownMenuSubTrigger = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuSubTriggerProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuSubTriggerProps, [\"class\", \"children\", \"inset\"]);\n\n return (\n <DropdownMenuPrimitive.SubTrigger\n class={cn(\n \"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent text-foreground\",\n local.inset && \"pl-8\",\n local.class\n )}\n {...(rest as any)}\n >\n {local.children}\n <svg class=\"ml-auto h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5l7 7-7 7\" />\n </svg>\n </DropdownMenuPrimitive.SubTrigger>\n );\n};\n\nexport type DropdownMenuSubContentProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuSubContentProps<T> & {\n class?: string;\n };\n\nexport const DropdownMenuSubContent = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuSubContentProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuSubContentProps, [\"class\"]);\n\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.SubContent\n class={cn(\n \"z-50 min-w-32 overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg data-expanded:animate-in data-closed:animate-out data-[closed]:fade-out-0 data-[expanded]:fade-in-0\",\n local.class\n )}\n {...(rest as any)}\n />\n </DropdownMenuPrimitive.Portal>\n );\n};\n\nexport type DropdownMenuContentProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuContentProps<T> & {\n class?: string;\n children?: JSX.Element;\n };\n\nexport const DropdownMenuContent = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuContentProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuContentProps, [\"class\", \"children\"]);\n let contentRef: HTMLElement | undefined;\n\n createClickOutside({\n target: () => contentRef,\n onInteractOutside: (e) => {\n if (typeof (props as any).onInteractOutside === \"function\") {\n (props as any).onInteractOutside(e);\n }\n },\n });\n\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={(el) => {\n contentRef = el;\n if (typeof (props as any).ref === \"function\") (props as any).ref(el);\n }}\n {...(rest as any)}\n sideOffset={(rest as any).sideOffset ?? 8}\n class={cn(\n \"z-50 min-w-32 overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md animate-in fade-in-80 max-h-72 flex flex-col mt-1\",\n local.class\n )}\n >\n <ScrollArea class=\"max-h-72 w-full\">\n <div class=\"p-1\">\n {local.children}\n </div>\n </ScrollArea>\n </DropdownMenuPrimitive.Content>\n </DropdownMenuPrimitive.Portal>\n );\n};\n\nexport type DropdownMenuItemProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuItemProps<T> & {\n class?: string;\n inset?: boolean;\n variant?: \"default\" | \"destructive\";\n };\n\nexport const DropdownMenuItem = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuItemProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuItemProps, [\n \"class\",\n \"inset\",\n \"variant\",\n ]);\n\n return (\n <DropdownMenuPrimitive.Item\n class={cn(\n \"relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50\",\n local.inset && \"pl-8\",\n local.variant === \"destructive\" &&\n \"text-destructive focus:bg-destructive/15 focus:text-destructive\",\n local.class\n )}\n {...(rest as any)}\n />\n );\n};\n\nexport type DropdownMenuCheckboxItemProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuCheckboxItemProps<T> & {\n class?: string;\n children?: JSX.Element;\n };\n\nexport const DropdownMenuCheckboxItem = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuCheckboxItemProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuCheckboxItemProps, [\"class\", \"children\"]);\n\n return (\n <DropdownMenuPrimitive.CheckboxItem\n class={cn(\n \"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50\",\n local.class\n )}\n {...(rest as any)}\n >\n <span class=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <svg class=\"h-4 w-4 fill-none stroke-current stroke-2\" viewBox=\"0 0 24 24\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {local.children}\n </DropdownMenuPrimitive.CheckboxItem>\n );\n};\n\nexport type DropdownMenuRadioItemProps<T extends ValidComponent = \"div\"> =\n DropdownMenuPrimitive.DropdownMenuRadioItemProps<T> & {\n class?: string;\n children?: JSX.Element;\n };\n\nexport const DropdownMenuRadioItem = <T extends ValidComponent = \"div\">(\n props: PolymorphicProps<T, DropdownMenuRadioItemProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuRadioItemProps, [\"class\", \"children\"]);\n\n return (\n <DropdownMenuPrimitive.RadioItem\n class={cn(\n \"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50\",\n local.class\n )}\n {...(rest as any)}\n >\n <span class=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <span class=\"h-2 w-2 rounded-lg bg-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {local.children}\n </DropdownMenuPrimitive.RadioItem>\n );\n};\n\nexport const DropdownMenuGroupLabel = DropdownMenuPrimitive.GroupLabel;\n\nexport interface DropdownMenuLabelProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n inset?: boolean;\n children?: JSX.Element;\n}\n\nexport const DropdownMenuLabel: Component<DropdownMenuLabelProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"inset\", \"children\"]);\n const isInsideGroup = useContext(DropdownGroupContext);\n\n const classes = () =>\n cn(\n \"px-2 py-1.5 text-sm font-semibold text-foreground\",\n local.inset && \"pl-8\",\n local.class\n );\n\n return (\n <>\n {isInsideGroup ? (\n <DropdownMenuPrimitive.GroupLabel class={classes()} {...(rest as any)}>\n {local.children}\n </DropdownMenuPrimitive.GroupLabel>\n ) : (\n <div class={classes()} {...rest}>\n {local.children}\n </div>\n )}\n </>\n );\n};\n\nexport type DropdownMenuSeparatorProps<T extends ValidComponent = \"hr\"> =\n DropdownMenuPrimitive.DropdownMenuSeparatorProps<T> & {\n class?: string;\n };\n\nexport const DropdownMenuSeparator = <T extends ValidComponent = \"hr\">(\n props: PolymorphicProps<T, DropdownMenuSeparatorProps<T>>\n) => {\n const [local, rest] = splitProps(props as DropdownMenuSeparatorProps, [\"class\"]);\n\n return (\n <DropdownMenuPrimitive.Separator\n class={cn(\"-mx-1 my-1 h-px bg-border\", local.class)}\n {...(rest as any)}\n />\n );\n};\n\nexport interface DropdownMenuShortcutProps extends JSX.HTMLAttributes<HTMLSpanElement> {\n class?: string;\n}\n\nexport const DropdownMenuShortcut: Component<DropdownMenuShortcutProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <span\n class={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", local.class)}\n {...rest}\n />\n );\n};",
|
|
18
19
|
"type": "registry:ui"
|
|
19
20
|
}
|
|
20
21
|
]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dropzone",
|
|
3
|
+
"title": "Dropzone",
|
|
4
|
+
"description": "A compound drag-and-drop file upload container with file list previews and validation feedback.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"lucide-solid"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"create-drop-zone"
|
|
13
|
+
],
|
|
14
|
+
"files": [
|
|
15
|
+
{
|
|
16
|
+
"path": "ui/dropzone.tsx",
|
|
17
|
+
"content": "import { splitProps, type Component, type JSX } from \"solid-js\";\nimport { cn } from \"@/lib/cn\";\nimport { CloudUpload, FileText, X, AlertCircle } from \"lucide-solid\";\n\nexport interface DropzoneProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n isOver?: boolean;\n disabled?: boolean;\n}\n\n/**\n * Root container for the Dropzone file upload component.\n */\nexport const Dropzone: Component<DropzoneProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"isOver\", \"disabled\"]);\n\n return (\n <div\n class={cn(\n \"group relative flex w-full flex-col items-center justify-center rounded-lg border-2 border-dashed border-border bg-card/50 p-8 text-center transition-all\",\n \"hover:border-primary/50 hover:bg-card/80\",\n local.isOver && \"border-primary bg-primary/5 ring-2 ring-primary/20\",\n local.disabled && \"pointer-events-none opacity-50\",\n local.class\n )}\n {...rest}\n />\n );\n};\n\nexport interface DropzoneIconProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\n/**\n * Centered icon placeholder for Dropzone.\n */\nexport const DropzoneIcon: Component<DropzoneIconProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n class={cn(\n \"mb-3 flex size-12 items-center justify-center rounded-lg bg-primary/10 text-primary transition-transform group-hover:scale-105\",\n local.class\n )}\n {...rest}\n >\n {local.children || <CloudUpload class=\"size-6\" />}\n </div>\n );\n};\n\nexport interface DropzoneTitleProps extends JSX.HTMLAttributes<HTMLHeadingElement> {\n class?: string;\n}\n\n/**\n * Primary title text for the dropzone prompt.\n */\nexport const DropzoneTitle: Component<DropzoneTitleProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <h4\n class={cn(\"text-sm font-semibold tracking-tight text-foreground\", local.class)}\n {...rest}\n />\n );\n};\n\nexport interface DropzoneDescriptionProps extends JSX.HTMLAttributes<HTMLParagraphElement> {\n class?: string;\n}\n\n/**\n * Subtitle description text for dropzone file specifications.\n */\nexport const DropzoneDescription: Component<DropzoneDescriptionProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <p\n class={cn(\"mt-1 text-xs text-muted-foreground\", local.class)}\n {...rest}\n />\n );\n};\n\nexport interface DropzoneFileListProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\n/**\n * Container list for uploaded files.\n */\nexport const DropzoneFileList: Component<DropzoneFileListProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <div\n class={cn(\"mt-4 flex w-full flex-col gap-2\", local.class)}\n {...rest}\n />\n );\n};\n\nexport interface DropzoneFileItemProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n name: string;\n size?: string;\n onRemove?: () => void;\n}\n\n/**\n * Individual uploaded file card with name, formatted size, and remove button.\n */\nexport const DropzoneFileItem: Component<DropzoneFileItemProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"name\", \"size\", \"onRemove\", \"children\"]);\n\n return (\n <div\n class={cn(\n \"flex items-center justify-between gap-3 rounded-md border border-border bg-card p-2.5 text-xs transition-colors\",\n local.class\n )}\n {...rest}\n >\n <div class=\"flex min-w-0 items-center gap-2.5\">\n <div class=\"flex size-8 shrink-0 items-center justify-center rounded-md bg-muted text-muted-foreground\">\n {local.children || <FileText class=\"size-4\" />}\n </div>\n <div class=\"flex min-w-0 flex-col text-left\">\n <span class=\"truncate font-medium text-foreground\">{local.name}</span>\n {local.size && (\n <span class=\"font-mono text-[11px] text-muted-foreground\">{local.size}</span>\n )}\n </div>\n </div>\n\n {local.onRemove && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n local.onRemove?.();\n }}\n class=\"flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-destructive/10 hover:text-destructive\"\n aria-label=\"Remove file\"\n >\n <X class=\"size-3.5\" />\n </button>\n )}\n </div>\n );\n};\n\nexport interface DropzoneRejectedItemProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n name: string;\n error?: string;\n size?: string;\n}\n\n/**\n * Card for displaying rejected files and validation errors.\n */\nexport const DropzoneRejectedItem: Component<DropzoneRejectedItemProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"name\", \"error\", \"size\"]);\n\n return (\n <div\n class={cn(\n \"flex items-center justify-between gap-3 rounded-md border border-destructive/30 bg-destructive/10 p-2.5 text-xs text-destructive\",\n local.class\n )}\n {...rest}\n >\n <div class=\"flex min-w-0 items-center gap-2\">\n <AlertCircle class=\"size-4 shrink-0\" />\n <span class=\"truncate font-medium\">{local.name}</span>\n {local.size && <span class=\"font-mono text-[11px] opacity-80\">({local.size})</span>}\n </div>\n {local.error && (\n <span class=\"shrink-0 text-[11px] font-medium\">{local.error}</span>\n )}\n </div>\n );\n};\n",
|
|
18
|
+
"type": "registry:ui"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
package/registry/field.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"files": [
|
|
14
14
|
{
|
|
15
15
|
"path": "ui/field.tsx",
|
|
16
|
-
"content": "import { splitProps, type Component, type JSX } from \"solid-js\";\nimport { cn } from \"@/lib/cn\";\nimport { Label, type LabelProps } from \"
|
|
16
|
+
"content": "import { splitProps, type Component, type JSX } from \"solid-js\";\nimport { cn } from \"@/lib/cn\";\nimport { Label, type LabelProps } from \"@/components/ui/label\";\n\nexport interface FieldProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\n/** A consistent layout wrapper for labels, controls, descriptions, and errors. */\nexport const Field: Component<FieldProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div class={cn(\"grid w-full gap-1.5\", local.class)} {...rest}>\n {local.children}\n </div>\n );\n};\n\nexport interface FieldLabelProps extends JSX.LabelHTMLAttributes<HTMLLabelElement>, LabelProps {\n class?: string;\n for?: string;\n children?: JSX.Element;\n}\n\nexport const FieldLabel: Component<FieldLabelProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <Label class={cn(\"text-sm font-medium\", local.class)} {...rest}>\n {local.children}\n </Label>\n );\n};\n\nexport interface FieldDescriptionProps\n extends JSX.HTMLAttributes<HTMLParagraphElement> {\n class?: string;\n}\n\nexport const FieldDescription: Component<FieldDescriptionProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <p\n class={cn(\"text-sm text-muted-foreground\", local.class)}\n {...rest}\n >\n {local.children}\n </p>\n );\n};\n\nexport interface FieldErrorProps\n extends JSX.HTMLAttributes<HTMLParagraphElement> {\n class?: string;\n}\n\nexport const FieldError: Component<FieldErrorProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <p\n role=\"alert\"\n class={cn(\"text-sm font-medium text-destructive\", local.class)}\n {...rest}\n >\n {local.children}\n </p>\n );\n};\n",
|
|
17
17
|
"type": "registry:ui"
|
|
18
18
|
}
|
|
19
19
|
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "footer",
|
|
3
|
+
"title": "Footer",
|
|
4
|
+
"description": "A responsive, accessible, and structured bottom navigation layout suite supporting multi-column link directories, brand sections, and newsletter inputs.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"class-variance-authority"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
{
|
|
13
|
+
"path": "ui/footer.tsx",
|
|
14
|
+
"content": "import { splitProps, type JSX, type ParentComponent, type Component } from \"solid-js\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/cn\";\n\n/* --- Root Footer --- */\nexport const footerVariants = cva(\"w-full transition-colors\", {\n variants: {\n variant: {\n default: \"bg-background border-t border-border/60 text-foreground\",\n muted: \"bg-muted/40 border-t border-border text-foreground\",\n bordered: \"bg-background border-t-2 border-border text-foreground\",\n floating: \"my-8 rounded-lg border border-border/80 bg-card text-card-foreground shadow-xs\",\n transparent: \"bg-transparent border-transparent text-foreground\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n});\n\nexport interface FooterProps\n extends JSX.HTMLAttributes<HTMLElement>,\n VariantProps<typeof footerVariants> {\n maxWidth?: \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | \"full\";\n}\n\nexport const Footer: ParentComponent<FooterProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"variant\", \"maxWidth\", \"children\"]);\n\n const maxWidthClass = () => {\n switch (local.maxWidth) {\n case \"sm\":\n return \"max-w-screen-sm\";\n case \"md\":\n return \"max-w-screen-md\";\n case \"lg\":\n return \"max-w-screen-lg\";\n case \"xl\":\n return \"max-w-screen-xl\";\n case \"full\":\n return \"max-w-full\";\n case \"2xl\":\n default:\n return \"max-w-screen-2xl\";\n }\n };\n\n return (\n <footer\n class={cn(\n footerVariants({ variant: local.variant }),\n local.variant === \"floating\" && cn(\"mx-auto\", maxWidthClass()),\n local.class\n )}\n {...rest}\n >\n <div class={cn(\"w-full\", local.variant !== \"floating\" && cn(\"mx-auto\", maxWidthClass()))}>\n {local.children}\n </div>\n </footer>\n );\n};\n\n/* --- Footer Container --- */\nexport interface FooterContainerProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const FooterContainer: ParentComponent<FooterContainerProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n class={cn(\"px-4 sm:px-6 lg:px-8 py-10 sm:py-12 md:py-16 w-full\", local.class)}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- Footer Content (Columns Grid / Layout) --- */\nexport interface FooterContentProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const FooterContent: ParentComponent<FooterContentProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n class={cn(\n \"grid grid-cols-2 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-8 lg:gap-12\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- Footer Column --- */\nexport interface FooterColumnProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const FooterColumn: ParentComponent<FooterColumnProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div class={cn(\"flex flex-col space-y-3\", local.class)} {...rest}>\n {local.children}\n </div>\n );\n};\n\n/* --- Footer Column Title --- */\nexport interface FooterColumnTitleProps extends JSX.HTMLAttributes<HTMLHeadingElement> {\n class?: string;\n}\n\nexport const FooterColumnTitle: ParentComponent<FooterColumnTitleProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <h4\n class={cn(\n \"text-xs font-semibold uppercase tracking-wider text-foreground\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </h4>\n );\n};\n\n/* --- Footer Column List --- */\nexport interface FooterColumnListProps extends JSX.HTMLAttributes<HTMLUListElement> {\n class?: string;\n}\n\nexport const FooterColumnList: ParentComponent<FooterColumnListProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <ul class={cn(\"space-y-2 list-none p-0 m-0\", local.class)} {...rest}>\n {local.children}\n </ul>\n );\n};\n\n/* --- Footer Link --- */\nexport interface FooterLinkProps extends JSX.AnchorHTMLAttributes<HTMLAnchorElement> {\n class?: string;\n}\n\nexport const FooterLink: ParentComponent<FooterLinkProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <li>\n <a\n class={cn(\n \"inline-flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground transition-colors cursor-pointer\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </a>\n </li>\n );\n};\n\n/* --- Footer Brand / Info Section --- */\nexport interface FooterBrandProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const FooterBrand: ParentComponent<FooterBrandProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n class={cn(\n \"col-span-2 sm:col-span-2 md:col-span-4 lg:col-span-2 flex flex-col space-y-3 mb-4 lg:mb-0\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- Footer Bottom (Copyright and Secondary Links Bar) --- */\nexport interface FooterBottomProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const FooterBottom: ParentComponent<FooterBottomProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div\n class={cn(\n \"mt-12 sm:mt-16 pt-8 border-t border-border/50 flex flex-col sm:flex-row items-center justify-between gap-4 text-xs text-muted-foreground\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- Footer Copyright Text --- */\nexport interface FooterCopyrightProps extends JSX.HTMLAttributes<HTMLParagraphElement> {\n class?: string;\n}\n\nexport const FooterCopyright: ParentComponent<FooterCopyrightProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <p class={cn(\"text-xs text-muted-foreground leading-relaxed\", local.class)} {...rest}>\n {local.children}\n </p>\n );\n};\n\n/* --- Footer Social Links Container --- */\nexport interface FooterSocialsProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const FooterSocials: ParentComponent<FooterSocialsProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <div class={cn(\"flex items-center gap-3 text-muted-foreground\", local.class)} {...rest}>\n {local.children}\n </div>\n );\n};\n",
|
|
15
|
+
"type": "registry:ui"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "forgot-password-01",
|
|
3
|
+
"title": "Forgot Password 01 — Account Recovery Flow",
|
|
4
|
+
"description": "A sleek password recovery block with email instructions submission and success confirmation states.",
|
|
5
|
+
"type": "registry:block",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"lucide-solid"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"card",
|
|
13
|
+
"input",
|
|
14
|
+
"label",
|
|
15
|
+
"button",
|
|
16
|
+
"alert",
|
|
17
|
+
"form",
|
|
18
|
+
"field",
|
|
19
|
+
"form-message"
|
|
20
|
+
],
|
|
21
|
+
"files": [
|
|
22
|
+
{
|
|
23
|
+
"path": "blocks/forgot-password-01.tsx",
|
|
24
|
+
"content": "import { createSignal, Show, type Component } from \"solid-js\";\nimport { createForm } from \"@nikala-ui/hooks\";\nimport {\n Card,\n CardHeader,\n CardTitle,\n CardDescription,\n CardContent,\n CardFooter,\n} from \"../components/ui/card\";\nimport { Form } from \"../components/ui/form\";\nimport { Field, FieldLabel } from \"../components/ui/field\";\nimport { FormMessage } from \"../components/ui/form-message\";\nimport { Button } from \"../components/ui/button\";\nimport { Input } from \"../components/ui/input\";\nimport { Alert, AlertTitle, AlertDescription } from \"../components/ui/alert\";\nimport { Lock, Mail, ArrowLeft, ArrowRight, CheckCircle2, RotateCcw } from \"lucide-solid\";\n\nexport const ForgotPassword01: Component = () => {\n const [sent, setSent] = createSignal(false);\n const [submittedEmail, setSubmittedEmail] = createSignal(\"\");\n\n const form = createForm({\n initialValues: {\n email: \"\",\n },\n validate: (values) => {\n const errors: Record<string, string> = {};\n if (!values.email.trim()) {\n errors.email = \"Email is required\";\n } else if (!values.email.includes(\"@\")) {\n errors.email = \"Please enter a valid email address\";\n }\n return errors;\n },\n onSubmit: async (values) => {\n await new Promise((resolve) => setTimeout(resolve, 1000));\n setSubmittedEmail(values.email);\n setSent(true);\n },\n });\n\n const isFormValid = () =>\n form.values().email.trim() !== \"\" && form.values().email.includes(\"@\");\n\n const handleReset = () => {\n setSent(false);\n form.resetForm();\n };\n\n return (\n <div class=\"@container w-full min-h-[520px] flex items-center justify-center p-4 sm:p-6 md:p-10\">\n <Card class=\"w-full max-w-md border-border shadow-md bg-card\">\n {/* Card Header */}\n <CardHeader class=\"space-y-2 text-center pb-4\">\n <div class=\"mx-auto size-12 rounded-lg bg-primary/10 text-primary flex items-center justify-center mb-1 shadow-2xs\">\n <Show when={sent()} fallback={<Lock class=\"size-6\" />}>\n <Mail class=\"size-6\" />\n </Show>\n </div>\n <CardTitle class=\"text-2xl font-bold tracking-tight\">\n {sent() ? \"Check your email\" : \"Reset your password\"}\n </CardTitle>\n <CardDescription class=\"text-xs sm:text-sm\">\n {sent()\n ? `We have sent a secure password reset link to ${submittedEmail()}`\n : \"Enter the email associated with your account and we will send you a reset link\"}\n </CardDescription>\n </CardHeader>\n\n <CardContent class=\"space-y-4\">\n <Show\n when={sent()}\n fallback={\n <Form onSubmit={form.handleSubmit} loading={form.isSubmitting()} class=\"space-y-4\">\n <Field>\n <FieldLabel for=\"fp-email\" class=\"text-xs sm:text-sm\">Email address</FieldLabel>\n <Input\n id=\"fp-email\"\n type=\"email\"\n placeholder=\"name@company.com\"\n value={form.values().email}\n onInput={form.handleChange(\"email\")}\n onBlur={form.handleBlur(\"email\")}\n autocomplete=\"email\"\n />\n <FormMessage form={form} name=\"email\" />\n </Field>\n\n <Button\n type=\"submit\"\n class=\"w-full font-medium\"\n disabled={form.isSubmitting() || !isFormValid()}\n >\n <Show when={form.isSubmitting()} fallback={<>Send Reset Link <ArrowRight class=\"ml-2 size-4\" /></>}>\n Sending instructions...\n </Show>\n </Button>\n </Form>\n }\n >\n <div class=\"space-y-4\">\n <Alert class=\"bg-emerald-500/10 border-emerald-500/30 text-emerald-500 py-3\">\n <CheckCircle2 class=\"size-4 text-emerald-500 shrink-0\" />\n <AlertTitle class=\"text-xs font-semibold text-foreground\">Instructions Sent</AlertTitle>\n <AlertDescription class=\"text-[11px] text-muted-foreground\">\n If an account exists for <span class=\"font-medium text-foreground font-mono\">{submittedEmail()}</span>, you will receive an email shortly.\n </AlertDescription>\n </Alert>\n\n <div class=\"flex items-center justify-between text-xs text-muted-foreground pt-1\">\n <span>Didn't get the email?</span>\n <Button\n variant=\"link\"\n size=\"sm\"\n type=\"button\"\n onClick={handleReset}\n class=\"h-auto p-0 text-xs text-primary font-semibold gap-1 cursor-pointer\"\n >\n <RotateCcw class=\"size-3\" /> Try another email\n </Button>\n </div>\n </div>\n </Show>\n </CardContent>\n\n {/* Card Footer */}\n <CardFooter class=\"justify-center border-t border-border/50 py-4 text-xs text-muted-foreground\">\n <a\n href=\"/blocks/login-01\"\n class=\"inline-flex items-center gap-1.5 text-foreground hover:text-primary transition-colors font-medium\"\n >\n <ArrowLeft class=\"size-3.5\" /> Back to sign in\n </a>\n </CardFooter>\n </Card>\n </div>\n );\n};\n\nexport default ForgotPassword01;\n",
|
|
25
|
+
"type": "registry:block"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -4,12 +4,13 @@
|
|
|
4
4
|
"description": "Validation message helper connected to createForm errors and touched state.",
|
|
5
5
|
"type": "registry:ui",
|
|
6
6
|
"registryDependencies": [
|
|
7
|
-
"field"
|
|
7
|
+
"field",
|
|
8
|
+
"create-form"
|
|
8
9
|
],
|
|
9
10
|
"files": [
|
|
10
11
|
{
|
|
11
12
|
"path": "ui/form-message.tsx",
|
|
12
|
-
"content": "import { Show, splitProps, type JSX } from \"solid-js\";\nimport type { CreateFormReturn } from \"
|
|
13
|
+
"content": "import { Show, splitProps, type JSX } from \"solid-js\";\nimport type { CreateFormReturn } from \"@/hooks/create-form\";\nimport { FieldError, type FieldErrorProps } from \"@/components/ui/field\";\n\ntype FormState<T extends Record<string, any>> = Pick<\n CreateFormReturn<T>,\n \"errors\" | \"touched\"\n>;\n\nexport interface FormMessageProps<\n T extends Record<string, any>,\n K extends keyof T,\n> extends Omit<FieldErrorProps, \"children\"> {\n form: FormState<T>;\n name: K;\n /** Show the message even before the field has been touched. */\n showUntouched?: boolean;\n}\n\n/** Displays a field's validation error from createForm when it should be visible. */\nexport function FormMessage<\n T extends Record<string, any>,\n K extends keyof T,\n>(props: FormMessageProps<T, K>): JSX.Element {\n const [local, rest] = splitProps(props, [\"form\", \"name\", \"showUntouched\", \"class\"]);\n const error = () => local.form.errors()[local.name] as string | undefined;\n const touched = () => local.form.touched()[local.name] === true;\n\n return (\n <Show when={error() && (local.showUntouched || touched())}>\n <FieldError class={local.class} {...rest}>\n {error()}\n </FieldError>\n </Show>\n );\n}\n",
|
|
13
14
|
"type": "registry:ui"
|
|
14
15
|
}
|
|
15
16
|
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hero-01",
|
|
3
|
+
"title": "Hero 01 — Simple Centered with Actions",
|
|
4
|
+
"description": "A clean centered hero section with badge pill, high-contrast headline, and dual CTA buttons.",
|
|
5
|
+
"type": "registry:block",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"lucide-solid"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"button",
|
|
13
|
+
"badge"
|
|
14
|
+
],
|
|
15
|
+
"files": [
|
|
16
|
+
{
|
|
17
|
+
"path": "blocks/hero-01.tsx",
|
|
18
|
+
"content": "import { Component } from \"solid-js\";\nimport { Button } from \"../components/ui/button\";\nimport { Badge } from \"../components/ui/badge\";\nimport { ArrowRight } from \"lucide-solid\";\n\nexport default function Hero01() {\n return (\n <section class=\"w-full py-12 md:py-24 lg:py-32 flex flex-col items-center justify-center text-center\">\n <Badge variant=\"secondary\" class=\"mb-4\">\n Nikala UI Blocks\n </Badge>\n <h1 class=\"text-4xl font-bold tracking-tight sm:text-6xl text-foreground max-w-3xl\">\n Build faster with copy-paste SolidJS blocks\n </h1>\n <p class=\"mt-6 text-lg text-muted-foreground max-w-2xl\">\n Pre-designed, fully responsive marketing and application blocks built natively for Tailwind CSS v4.\n </p>\n <div class=\"mt-8 flex items-center gap-4\">\n <Button size=\"lg\">\n Get Started <ArrowRight class=\"ml-2 size-4\" />\n </Button>\n <Button variant=\"outline\" size=\"lg\">\n Documentation\n </Button>\n </div>\n </section>\n );\n}\n",
|
|
19
|
+
"type": "registry:block"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"files": [
|
|
14
14
|
{
|
|
15
15
|
"path": "ui/icon-button.tsx",
|
|
16
|
-
"content": "import { splitProps, type Component, type JSX } from \"solid-js\";\nimport { Button, type ButtonProps } from \"
|
|
16
|
+
"content": "import { splitProps, type Component, type JSX } from \"solid-js\";\nimport { Button, type ButtonProps } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/cn\";\n\nexport interface IconButtonProps\n extends Omit<ButtonProps, \"size\" | \"children\"> {\n /** Accessible label for the icon-only button. */\n label: string;\n size?: \"sm\" | \"default\" | \"lg\";\n children?: JSX.Element;\n}\n\n/** An accessible square button intended for a single icon action. */\nexport const IconButton: Component<IconButtonProps> = (props) => {\n const [local, rest] = splitProps(props, [\"label\", \"size\", \"class\", \"children\"]);\n\n return (\n <Button\n size=\"icon\"\n aria-label={local.label}\n class={cn(\n {\n \"size-8\": local.size === \"sm\",\n \"size-9\": !local.size || local.size === \"default\",\n \"size-10\": local.size === \"lg\",\n },\n local.class\n )}\n {...rest}\n >\n {local.children}\n </Button>\n );\n};\n",
|
|
17
17
|
"type": "registry:ui"
|
|
18
18
|
}
|
|
19
19
|
]
|