@nikala-ui/docs 0.12.0
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/README.md +22 -0
- package/dist/cli/commands/build.d.ts +5 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +27 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +7 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +32 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +308 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/preview.d.ts +7 -0
- package/dist/cli/commands/preview.d.ts.map +1 -0
- package/dist/cli/commands/preview.js +24 -0
- package/dist/cli/commands/preview.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +7 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +33 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +53 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/client/App.d.ts +5 -0
- package/dist/client/App.d.ts.map +1 -0
- package/dist/client/App.jsx +31 -0
- package/dist/client/App.jsx.map +1 -0
- package/dist/client/app-types.d.ts +14 -0
- package/dist/client/app-types.d.ts.map +1 -0
- package/dist/client/app-types.js +2 -0
- package/dist/client/app-types.js.map +1 -0
- package/dist/client/components/DocsLayoutShell.d.ts +21 -0
- package/dist/client/components/DocsLayoutShell.d.ts.map +1 -0
- package/dist/client/components/DocsLayoutShell.jsx +14 -0
- package/dist/client/components/DocsLayoutShell.jsx.map +1 -0
- package/dist/client/components/DocsPageContent.d.ts +9 -0
- package/dist/client/components/DocsPageContent.d.ts.map +1 -0
- package/dist/client/components/DocsPageContent.jsx +10 -0
- package/dist/client/components/DocsPageContent.jsx.map +1 -0
- package/dist/client/entry.d.ts +2 -0
- package/dist/client/entry.d.ts.map +1 -0
- package/dist/client/entry.jsx +28 -0
- package/dist/client/entry.jsx.map +1 -0
- package/dist/client/index.html +21 -0
- package/dist/client/navigation/page-navigation.d.ts +9 -0
- package/dist/client/navigation/page-navigation.d.ts.map +1 -0
- package/dist/client/navigation/page-navigation.js +51 -0
- package/dist/client/navigation/page-navigation.js.map +1 -0
- package/dist/client/routing/use-docs-router.d.ts +17 -0
- package/dist/client/routing/use-docs-router.d.ts.map +1 -0
- package/dist/client/routing/use-docs-router.js +71 -0
- package/dist/client/routing/use-docs-router.js.map +1 -0
- package/dist/client/ssr-entry.d.ts +3 -0
- package/dist/client/ssr-entry.d.ts.map +1 -0
- package/dist/client/ssr-entry.jsx +13 -0
- package/dist/client/ssr-entry.jsx.map +1 -0
- package/dist/client/style.css +183 -0
- package/dist/client/utils/sidebar.d.ts +2 -0
- package/dist/client/utils/sidebar.d.ts.map +1 -0
- package/dist/client/utils/sidebar.js +2 -0
- package/dist/client/utils/sidebar.js.map +1 -0
- package/dist/components/mdx-components.d.ts +34 -0
- package/dist/components/mdx-components.d.ts.map +1 -0
- package/dist/components/mdx-components.jsx +131 -0
- package/dist/components/mdx-components.jsx.map +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +105 -0
- package/dist/config.js.map +1 -0
- package/dist/core/content-scanner.d.ts +10 -0
- package/dist/core/content-scanner.d.ts.map +1 -0
- package/dist/core/content-scanner.js +153 -0
- package/dist/core/content-scanner.js.map +1 -0
- package/dist/core/route-tree.d.ts +19 -0
- package/dist/core/route-tree.d.ts.map +1 -0
- package/dist/core/route-tree.js +176 -0
- package/dist/core/route-tree.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cn.d.ts +6 -0
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/lib/cn.js +9 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/mdx/compiler.d.ts +13 -0
- package/dist/mdx/compiler.d.ts.map +1 -0
- package/dist/mdx/compiler.js +38 -0
- package/dist/mdx/compiler.js.map +1 -0
- package/dist/mdx/highlighter.d.ts +22 -0
- package/dist/mdx/highlighter.d.ts.map +1 -0
- package/dist/mdx/highlighter.js +139 -0
- package/dist/mdx/highlighter.js.map +1 -0
- package/dist/mdx/rehype-shiki.d.ts +3 -0
- package/dist/mdx/rehype-shiki.d.ts.map +1 -0
- package/dist/mdx/rehype-shiki.js +83 -0
- package/dist/mdx/rehype-shiki.js.map +1 -0
- package/dist/navigation/index.d.ts +2 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +2 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/navigation/sidebar-state.d.ts +6 -0
- package/dist/navigation/sidebar-state.d.ts.map +1 -0
- package/dist/navigation/sidebar-state.js +20 -0
- package/dist/navigation/sidebar-state.js.map +1 -0
- package/dist/navigation/sidebar-tree.d.ts +7 -0
- package/dist/navigation/sidebar-tree.d.ts.map +1 -0
- package/dist/navigation/sidebar-tree.js +11 -0
- package/dist/navigation/sidebar-tree.js.map +1 -0
- package/dist/registry/accordion.json +18 -0
- package/dist/registry/alert.json +18 -0
- package/dist/registry/api-table.json +21 -0
- package/dist/registry/aspect-ratio.json +17 -0
- package/dist/registry/avatar.json +17 -0
- package/dist/registry/badge.json +18 -0
- package/dist/registry/banner.json +19 -0
- package/dist/registry/breadcrumb.json +17 -0
- package/dist/registry/bubble.json +18 -0
- package/dist/registry/button-group.json +20 -0
- package/dist/registry/button.json +21 -0
- package/dist/registry/callout.json +19 -0
- package/dist/registry/card.json +17 -0
- package/dist/registry/checkbox.json +20 -0
- package/dist/registry/code-block.json +26 -0
- package/dist/registry/code-group.json +20 -0
- package/dist/registry/collapsible.json +18 -0
- package/dist/registry/combobox.json +21 -0
- package/dist/registry/command.json +27 -0
- package/dist/registry/component-viewer.json +25 -0
- package/dist/registry/container.json +18 -0
- package/dist/registry/context-menu.json +24 -0
- package/dist/registry/create-active-element.json +13 -0
- package/dist/registry/create-app-updater.json +13 -0
- package/dist/registry/create-audio.json +7 -0
- package/dist/registry/create-battery.json +13 -0
- package/dist/registry/create-chat-scroll.json +13 -0
- package/dist/registry/create-click-outside.json +13 -0
- package/dist/registry/create-clipboard.json +13 -0
- package/dist/registry/create-color-mode.json +13 -0
- package/dist/registry/create-controllable-signal.json +13 -0
- package/dist/registry/create-debounce.json +13 -0
- package/dist/registry/create-disclosure.json +13 -0
- package/dist/registry/create-document-tabs.json +13 -0
- package/dist/registry/create-document-title.json +13 -0
- package/dist/registry/create-drop-zone.json +13 -0
- package/dist/registry/create-event-source.json +13 -0
- package/dist/registry/create-favicon.json +13 -0
- package/dist/registry/create-fetch.json +13 -0
- package/dist/registry/create-focus-trap.json +13 -0
- package/dist/registry/create-form.json +13 -0
- package/dist/registry/create-fullscreen.json +13 -0
- package/dist/registry/create-geolocation.json +13 -0
- package/dist/registry/create-global-shortcut.json +13 -0
- package/dist/registry/create-hover.json +13 -0
- package/dist/registry/create-idle.json +13 -0
- package/dist/registry/create-infinite-scroll.json +13 -0
- package/dist/registry/create-input-mask.json +13 -0
- package/dist/registry/create-intersection-observer.json +13 -0
- package/dist/registry/create-keybindings.json +13 -0
- package/dist/registry/create-lock-scroll.json +13 -0
- package/dist/registry/create-long-press.json +13 -0
- package/dist/registry/create-media-query.json +13 -0
- package/dist/registry/create-mouse-position.json +13 -0
- package/dist/registry/create-network-status.json +13 -0
- package/dist/registry/create-orientation.json +13 -0
- package/dist/registry/create-pagination.json +13 -0
- package/dist/registry/create-permission.json +13 -0
- package/dist/registry/create-previous.json +13 -0
- package/dist/registry/create-resize-observer.json +13 -0
- package/dist/registry/create-scroll-into-view.json +13 -0
- package/dist/registry/create-scroll-position.json +13 -0
- package/dist/registry/create-storage.json +13 -0
- package/dist/registry/create-tauri-window.json +13 -0
- package/dist/registry/create-timer.json +13 -0
- package/dist/registry/create-tiptap-editor.json +34 -0
- package/dist/registry/create-undo-redo.json +13 -0
- package/dist/registry/create-web-notification.json +13 -0
- package/dist/registry/create-websocket.json +13 -0
- package/dist/registry/create-window-size.json +13 -0
- package/dist/registry/dialog.json +21 -0
- package/dist/registry/dropdown-menu.json +22 -0
- package/dist/registry/dropzone.json +21 -0
- package/dist/registry/empty.json +17 -0
- package/dist/registry/field.json +20 -0
- package/dist/registry/file-tree.json +21 -0
- package/dist/registry/footer.json +18 -0
- package/dist/registry/forgot-password-01.json +28 -0
- package/dist/registry/form-message.json +17 -0
- package/dist/registry/form.json +17 -0
- package/dist/registry/hero-01.json +22 -0
- package/dist/registry/hover-card.json +18 -0
- package/dist/registry/icon-button.json +20 -0
- package/dist/registry/index.json +1489 -0
- package/dist/registry/input-group.json +21 -0
- package/dist/registry/input.json +17 -0
- package/dist/registry/kbd.json +18 -0
- package/dist/registry/label.json +18 -0
- package/dist/registry/list.json +20 -0
- package/dist/registry/login-01.json +28 -0
- package/dist/registry/logo.json +17 -0
- package/dist/registry/marker.json +17 -0
- package/dist/registry/marquee.json +17 -0
- package/dist/registry/message.json +17 -0
- package/dist/registry/navbar.json +19 -0
- package/dist/registry/navigation-menu.json +22 -0
- package/dist/registry/number-input.json +24 -0
- package/dist/registry/otp-verification-01.json +26 -0
- package/dist/registry/package-manager-tabs.json +24 -0
- package/dist/registry/pager.json +21 -0
- package/dist/registry/pagination.json +22 -0
- package/dist/registry/pin-input.json +17 -0
- package/dist/registry/popover.json +22 -0
- package/dist/registry/progress.json +18 -0
- package/dist/registry/radio-group.json +18 -0
- package/dist/registry/rating.json +19 -0
- package/dist/registry/register-01.json +31 -0
- package/dist/registry/resizable.json +21 -0
- package/dist/registry/review-card.json +23 -0
- package/dist/registry/rich-text-editor.json +95 -0
- package/dist/registry/scroll-area.json +21 -0
- package/dist/registry/section-heading.json +21 -0
- package/dist/registry/select.json +22 -0
- package/dist/registry/separator.json +17 -0
- package/dist/registry/sheet.json +22 -0
- package/dist/registry/sidebar.json +24 -0
- package/dist/registry/skeleton.json +17 -0
- package/dist/registry/slider.json +18 -0
- package/dist/registry/spinner.json +18 -0
- package/dist/registry/stat.json +19 -0
- package/dist/registry/status.json +18 -0
- package/dist/registry/steps.json +20 -0
- package/dist/registry/switch.json +20 -0
- package/dist/registry/table-of-contents.json +23 -0
- package/dist/registry/table.json +17 -0
- package/dist/registry/tabs.json +20 -0
- package/dist/registry/textarea.json +17 -0
- package/dist/registry/theme-manager.json +39 -0
- package/dist/registry/timeline.json +18 -0
- package/dist/registry/titlebar-tabs.json +24 -0
- package/dist/registry/titlebar.json +26 -0
- package/dist/registry/toast.json +20 -0
- package/dist/registry/toggle-group.json +21 -0
- package/dist/registry/toggle.json +18 -0
- package/dist/registry/tooltip.json +18 -0
- package/dist/registry/updater-modal.json +26 -0
- package/dist/server/index.d.ts +18 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +526 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/plugin.d.ts +10 -0
- package/dist/server/plugin.d.ts.map +1 -0
- package/dist/server/plugin.js +271 -0
- package/dist/server/plugin.js.map +1 -0
- package/dist/themes/default/content/breadcrumbs.d.ts +4 -0
- package/dist/themes/default/content/breadcrumbs.d.ts.map +1 -0
- package/dist/themes/default/content/breadcrumbs.jsx +31 -0
- package/dist/themes/default/content/breadcrumbs.jsx.map +1 -0
- package/dist/themes/default/content/pager.d.ts +5 -0
- package/dist/themes/default/content/pager.d.ts.map +1 -0
- package/dist/themes/default/content/pager.jsx +9 -0
- package/dist/themes/default/content/pager.jsx.map +1 -0
- package/dist/themes/default/content/table-of-contents.d.ts +4 -0
- package/dist/themes/default/content/table-of-contents.d.ts.map +1 -0
- package/dist/themes/default/content/table-of-contents.jsx +19 -0
- package/dist/themes/default/content/table-of-contents.jsx.map +1 -0
- package/dist/themes/default/index.d.ts +11 -0
- package/dist/themes/default/index.d.ts.map +1 -0
- package/dist/themes/default/index.js +30 -0
- package/dist/themes/default/index.js.map +1 -0
- package/dist/themes/default/layout.d.ts +4 -0
- package/dist/themes/default/layout.d.ts.map +1 -0
- package/dist/themes/default/layout.jsx +75 -0
- package/dist/themes/default/layout.jsx.map +1 -0
- package/dist/themes/default/navbar.d.ts +4 -0
- package/dist/themes/default/navbar.d.ts.map +1 -0
- package/dist/themes/default/navbar.jsx +74 -0
- package/dist/themes/default/navbar.jsx.map +1 -0
- package/dist/themes/default/navigation/mobile-table-of-contents.d.ts +4 -0
- package/dist/themes/default/navigation/mobile-table-of-contents.d.ts.map +1 -0
- package/dist/themes/default/navigation/mobile-table-of-contents.jsx +22 -0
- package/dist/themes/default/navigation/mobile-table-of-contents.jsx.map +1 -0
- package/dist/themes/default/navigation/sidebar-tree.d.ts +8 -0
- package/dist/themes/default/navigation/sidebar-tree.d.ts.map +1 -0
- package/dist/themes/default/navigation/sidebar-tree.jsx +100 -0
- package/dist/themes/default/navigation/sidebar-tree.jsx.map +1 -0
- package/dist/themes/default/overlays/search-dialog.d.ts +4 -0
- package/dist/themes/default/overlays/search-dialog.d.ts.map +1 -0
- package/dist/themes/default/overlays/search-dialog.jsx +34 -0
- package/dist/themes/default/overlays/search-dialog.jsx.map +1 -0
- package/dist/themes/default/sidebar.d.ts +4 -0
- package/dist/themes/default/sidebar.d.ts.map +1 -0
- package/dist/themes/default/sidebar.jsx +60 -0
- package/dist/themes/default/sidebar.jsx.map +1 -0
- package/dist/themes/index.d.ts +4 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +5 -0
- package/dist/themes/index.js.map +1 -0
- package/dist/themes/types.d.ts +83 -0
- package/dist/themes/types.d.ts.map +1 -0
- package/dist/themes/types.js +2 -0
- package/dist/themes/types.js.map +1 -0
- package/dist/types.d.ts +97 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/vendor/core-src/index.css +11 -0
- package/dist/vendor/core-src/index.ts +48 -0
- package/dist/vendor/core-src/lib/cn.ts +9 -0
- package/dist/vendor/core-src/registry/blocks/forgot-password-01.tsx +141 -0
- package/dist/vendor/core-src/registry/blocks/hero-01.tsx +28 -0
- package/dist/vendor/core-src/registry/blocks/login-01.tsx +231 -0
- package/dist/vendor/core-src/registry/blocks/otp-verification-01.tsx +170 -0
- package/dist/vendor/core-src/registry/blocks/register-01.tsx +318 -0
- package/dist/vendor/core-src/registry/components/ui/accordion.tsx +128 -0
- package/dist/vendor/core-src/registry/components/ui/alert.tsx +155 -0
- package/dist/vendor/core-src/registry/components/ui/api-table.tsx +117 -0
- package/dist/vendor/core-src/registry/components/ui/aspect-ratio.tsx +31 -0
- package/dist/vendor/core-src/registry/components/ui/avatar.tsx +114 -0
- package/dist/vendor/core-src/registry/components/ui/badge.tsx +56 -0
- package/dist/vendor/core-src/registry/components/ui/banner.tsx +187 -0
- package/dist/vendor/core-src/registry/components/ui/breadcrumb.tsx +136 -0
- package/dist/vendor/core-src/registry/components/ui/bubble.tsx +142 -0
- package/dist/vendor/core-src/registry/components/ui/button-group.tsx +42 -0
- package/dist/vendor/core-src/registry/components/ui/button.tsx +82 -0
- package/dist/vendor/core-src/registry/components/ui/callout.tsx +137 -0
- package/dist/vendor/core-src/registry/components/ui/card.tsx +113 -0
- package/dist/vendor/core-src/registry/components/ui/checkbox.tsx +74 -0
- package/dist/vendor/core-src/registry/components/ui/code-block.tsx +326 -0
- package/dist/vendor/core-src/registry/components/ui/code-group.tsx +105 -0
- package/dist/vendor/core-src/registry/components/ui/collapsible.tsx +73 -0
- package/dist/vendor/core-src/registry/components/ui/combobox.tsx +299 -0
- package/dist/vendor/core-src/registry/components/ui/command.tsx +378 -0
- package/dist/vendor/core-src/registry/components/ui/component-viewer.tsx +363 -0
- package/dist/vendor/core-src/registry/components/ui/container.tsx +45 -0
- package/dist/vendor/core-src/registry/components/ui/context-menu.tsx +237 -0
- package/dist/vendor/core-src/registry/components/ui/dialog.tsx +200 -0
- package/dist/vendor/core-src/registry/components/ui/dropdown-menu.tsx +298 -0
- package/dist/vendor/core-src/registry/components/ui/dropzone.tsx +189 -0
- package/dist/vendor/core-src/registry/components/ui/empty.tsx +83 -0
- package/dist/vendor/core-src/registry/components/ui/field.tsx +71 -0
- package/dist/vendor/core-src/registry/components/ui/file-tree.tsx +181 -0
- package/dist/vendor/core-src/registry/components/ui/footer.tsx +247 -0
- package/dist/vendor/core-src/registry/components/ui/form-message.tsx +36 -0
- package/dist/vendor/core-src/registry/components/ui/form.tsx +21 -0
- package/dist/vendor/core-src/registry/components/ui/hover-card.tsx +105 -0
- package/dist/vendor/core-src/registry/components/ui/icon-button.tsx +34 -0
- package/dist/vendor/core-src/registry/components/ui/input-group.tsx +80 -0
- package/dist/vendor/core-src/registry/components/ui/input.tsx +28 -0
- package/dist/vendor/core-src/registry/components/ui/kbd.tsx +73 -0
- package/dist/vendor/core-src/registry/components/ui/label.tsx +30 -0
- package/dist/vendor/core-src/registry/components/ui/list.tsx +222 -0
- package/dist/vendor/core-src/registry/components/ui/logo.tsx +68 -0
- package/dist/vendor/core-src/registry/components/ui/marker.tsx +102 -0
- package/dist/vendor/core-src/registry/components/ui/marquee.tsx +118 -0
- package/dist/vendor/core-src/registry/components/ui/message.tsx +168 -0
- package/dist/vendor/core-src/registry/components/ui/navbar.tsx +375 -0
- package/dist/vendor/core-src/registry/components/ui/navigation-menu.tsx +358 -0
- package/dist/vendor/core-src/registry/components/ui/number-input.tsx +150 -0
- package/dist/vendor/core-src/registry/components/ui/package-manager-tabs.tsx +226 -0
- package/dist/vendor/core-src/registry/components/ui/pager.tsx +102 -0
- package/dist/vendor/core-src/registry/components/ui/pagination.tsx +258 -0
- package/dist/vendor/core-src/registry/components/ui/pin-input.tsx +198 -0
- package/dist/vendor/core-src/registry/components/ui/popover.tsx +90 -0
- package/dist/vendor/core-src/registry/components/ui/progress.tsx +66 -0
- package/dist/vendor/core-src/registry/components/ui/radio-group.tsx +95 -0
- package/dist/vendor/core-src/registry/components/ui/rating.tsx +185 -0
- package/dist/vendor/core-src/registry/components/ui/resizable.tsx +195 -0
- package/dist/vendor/core-src/registry/components/ui/review-card.tsx +195 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/bubble-menu.tsx +236 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/editor.tsx +308 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/extensions.ts +116 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/footer.tsx +36 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/image-dialog.tsx +75 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/index.ts +11 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/link-dialog.tsx +48 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/markdown.ts +170 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/slash-command.tsx +301 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/table-controls.tsx +68 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/toolbar.tsx +465 -0
- package/dist/vendor/core-src/registry/components/ui/rich-text-editor/use-editor.ts +231 -0
- package/dist/vendor/core-src/registry/components/ui/scroll-area.tsx +228 -0
- package/dist/vendor/core-src/registry/components/ui/section-heading.tsx +108 -0
- package/dist/vendor/core-src/registry/components/ui/select.tsx +156 -0
- package/dist/vendor/core-src/registry/components/ui/separator.tsx +37 -0
- package/dist/vendor/core-src/registry/components/ui/sheet.tsx +220 -0
- package/dist/vendor/core-src/registry/components/ui/sidebar.tsx +692 -0
- package/dist/vendor/core-src/registry/components/ui/skeleton.tsx +24 -0
- package/dist/vendor/core-src/registry/components/ui/slider.tsx +153 -0
- package/dist/vendor/core-src/registry/components/ui/spinner.tsx +41 -0
- package/dist/vendor/core-src/registry/components/ui/stat.tsx +245 -0
- package/dist/vendor/core-src/registry/components/ui/status.tsx +121 -0
- package/dist/vendor/core-src/registry/components/ui/steps.tsx +198 -0
- package/dist/vendor/core-src/registry/components/ui/switch.tsx +68 -0
- package/dist/vendor/core-src/registry/components/ui/table-of-contents.tsx +131 -0
- package/dist/vendor/core-src/registry/components/ui/table.tsx +160 -0
- package/dist/vendor/core-src/registry/components/ui/tabs.tsx +204 -0
- package/dist/vendor/core-src/registry/components/ui/textarea.tsx +82 -0
- package/dist/vendor/core-src/registry/components/ui/theme-toggle.tsx +238 -0
- package/dist/vendor/core-src/registry/components/ui/timeline.tsx +350 -0
- package/dist/vendor/core-src/registry/components/ui/titlebar-tabs.tsx +773 -0
- package/dist/vendor/core-src/registry/components/ui/titlebar.tsx +468 -0
- package/dist/vendor/core-src/registry/components/ui/toast.tsx +124 -0
- package/dist/vendor/core-src/registry/components/ui/toggle-group.tsx +203 -0
- package/dist/vendor/core-src/registry/components/ui/toggle.tsx +101 -0
- package/dist/vendor/core-src/registry/components/ui/tooltip.tsx +41 -0
- package/dist/vendor/core-src/registry/components/ui/updater-modal.tsx +254 -0
- package/dist/vendor/core-src/registry/index.ts +50 -0
- package/dist/vendor/core-src/registry/metadata.ts +742 -0
- package/dist/vendor/core-src/registry/providers/theme-provider.tsx +216 -0
- package/dist/vendor/core-src/registry/providers/theme-script.tsx +78 -0
- package/dist/vendor/core-src/registry/providers/theme-transitions.ts +139 -0
- package/dist/vendor/hooks-src/create-active-element.ts +51 -0
- package/dist/vendor/hooks-src/create-app-updater.ts +272 -0
- package/dist/vendor/hooks-src/create-audio-video.ts +444 -0
- package/dist/vendor/hooks-src/create-battery.ts +78 -0
- package/dist/vendor/hooks-src/create-chat-scroll.ts +113 -0
- package/dist/vendor/hooks-src/create-click-outside.ts +82 -0
- package/dist/vendor/hooks-src/create-clipboard.ts +69 -0
- package/dist/vendor/hooks-src/create-color-mode.ts +115 -0
- package/dist/vendor/hooks-src/create-controllable-signal.ts +56 -0
- package/dist/vendor/hooks-src/create-debounce.ts +90 -0
- package/dist/vendor/hooks-src/create-disclosure.ts +82 -0
- package/dist/vendor/hooks-src/create-document-tabs.ts +267 -0
- package/dist/vendor/hooks-src/create-document-title.ts +33 -0
- package/dist/vendor/hooks-src/create-drop-zone.ts +317 -0
- package/dist/vendor/hooks-src/create-event-source.ts +126 -0
- package/dist/vendor/hooks-src/create-favicon.ts +52 -0
- package/dist/vendor/hooks-src/create-fetch.ts +93 -0
- package/dist/vendor/hooks-src/create-focus-trap.ts +94 -0
- package/dist/vendor/hooks-src/create-form.ts +200 -0
- package/dist/vendor/hooks-src/create-fullscreen.ts +105 -0
- package/dist/vendor/hooks-src/create-geolocation.ts +140 -0
- package/dist/vendor/hooks-src/create-global-shortcut.ts +140 -0
- package/dist/vendor/hooks-src/create-hover.ts +88 -0
- package/dist/vendor/hooks-src/create-idle.ts +109 -0
- package/dist/vendor/hooks-src/create-infinite-scroll.ts +90 -0
- package/dist/vendor/hooks-src/create-input-mask.ts +109 -0
- package/dist/vendor/hooks-src/create-intersection-observer.ts +82 -0
- package/dist/vendor/hooks-src/create-keybindings.ts +148 -0
- package/dist/vendor/hooks-src/create-lock-scroll.ts +97 -0
- package/dist/vendor/hooks-src/create-long-press.ts +85 -0
- package/dist/vendor/hooks-src/create-media-query.ts +94 -0
- package/dist/vendor/hooks-src/create-mouse-position.ts +87 -0
- package/dist/vendor/hooks-src/create-network-status.ts +100 -0
- package/dist/vendor/hooks-src/create-orientation.ts +129 -0
- package/dist/vendor/hooks-src/create-pagination.ts +208 -0
- package/dist/vendor/hooks-src/create-permission.ts +91 -0
- package/dist/vendor/hooks-src/create-previous.ts +21 -0
- package/dist/vendor/hooks-src/create-resize-observer.ts +89 -0
- package/dist/vendor/hooks-src/create-scroll-into-view.ts +57 -0
- package/dist/vendor/hooks-src/create-scroll-position.ts +129 -0
- package/dist/vendor/hooks-src/create-storage.ts +106 -0
- package/dist/vendor/hooks-src/create-tauri-window.ts +628 -0
- package/dist/vendor/hooks-src/create-timer.ts +150 -0
- package/dist/vendor/hooks-src/create-tiptap-editor.ts +326 -0
- package/dist/vendor/hooks-src/create-undo-redo.ts +100 -0
- package/dist/vendor/hooks-src/create-web-notification.ts +111 -0
- package/dist/vendor/hooks-src/create-websocket.ts +179 -0
- package/dist/vendor/hooks-src/create-window-size.ts +41 -0
- package/dist/vendor/hooks-src/index.ts +48 -0
- package/package.json +87 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-tiptap-editor",
|
|
3
|
+
"title": "createTiptapEditor",
|
|
4
|
+
"description": "Fine-grained reactive SolidJS primitive for managing Tiptap rich text editor instances, signals, and formatting commands.",
|
|
5
|
+
"type": "registry:hook",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"@tiptap/core",
|
|
8
|
+
"@tiptap/starter-kit",
|
|
9
|
+
"@tiptap/extension-link",
|
|
10
|
+
"@tiptap/extension-image",
|
|
11
|
+
"@tiptap/extension-placeholder",
|
|
12
|
+
"@tiptap/extension-task-list",
|
|
13
|
+
"@tiptap/extension-task-item",
|
|
14
|
+
"@tiptap/extension-table",
|
|
15
|
+
"@tiptap/extension-table-row",
|
|
16
|
+
"@tiptap/extension-table-cell",
|
|
17
|
+
"@tiptap/extension-table-header",
|
|
18
|
+
"@tiptap/extension-underline",
|
|
19
|
+
"@tiptap/extension-text-align",
|
|
20
|
+
"@tiptap/extension-highlight",
|
|
21
|
+
"@tiptap/extension-character-count",
|
|
22
|
+
"@tiptap/extension-subscript",
|
|
23
|
+
"@tiptap/extension-superscript",
|
|
24
|
+
"@tiptap/extension-typography",
|
|
25
|
+
"tiptap-markdown"
|
|
26
|
+
],
|
|
27
|
+
"files": [
|
|
28
|
+
{
|
|
29
|
+
"path": "hooks/create-tiptap-editor.ts",
|
|
30
|
+
"content": "import {\n createSignal,\n onMount,\n onCleanup,\n type Accessor,\n} from \"solid-js\";\nimport { Editor, type EditorOptions, type Extension } from \"@tiptap/core\";\nimport StarterKit from \"@tiptap/starter-kit\";\nimport Placeholder from \"@tiptap/extension-placeholder\";\nimport Link from \"@tiptap/extension-link\";\nimport Image from \"@tiptap/extension-image\";\nimport TaskList from \"@tiptap/extension-task-list\";\nimport TaskItem from \"@tiptap/extension-task-item\";\nimport { Table, TableRow, TableCell, TableHeader } from \"@tiptap/extension-table\";\nimport Underline from \"@tiptap/extension-underline\";\nimport TextAlign from \"@tiptap/extension-text-align\";\nimport Highlight from \"@tiptap/extension-highlight\";\nimport CharacterCount from \"@tiptap/extension-character-count\";\nimport Subscript from \"@tiptap/extension-subscript\";\nimport Superscript from \"@tiptap/extension-superscript\";\nimport Typography from \"@tiptap/extension-typography\";\nimport { Markdown } from \"tiptap-markdown\";\n\nexport interface CreateTiptapEditorOptions\n extends Partial<Omit<EditorOptions, \"element\">> {\n placeholder?: string;\n characterLimit?: number;\n}\n\nexport interface CreateTiptapEditorReturn {\n editor: Accessor<Editor | null>;\n html: Accessor<string>;\n text: Accessor<string>;\n markdown: Accessor<string>;\n isEmpty: Accessor<boolean>;\n characterCount: Accessor<number>;\n wordCount: Accessor<number>;\n canUndo: Accessor<boolean>;\n canRedo: Accessor<boolean>;\n mount: (element: HTMLElement) => void;\n destroy: () => void;\n isActive: (name: string | Record<string, any>, attributes?: Record<string, any>) => boolean;\n toggleBold: () => void;\n toggleItalic: () => void;\n toggleUnderline: () => void;\n toggleStrike: () => void;\n toggleCode: () => void;\n toggleHighlight: (color?: string) => void;\n setHeading: (level: 1 | 2 | 3 | 4 | 5 | 6) => void;\n setParagraph: () => void;\n toggleBulletList: () => void;\n toggleOrderedList: () => void;\n toggleTaskList: () => void;\n toggleBlockquote: () => void;\n toggleCodeBlock: () => void;\n setTextAlign: (alignment: \"left\" | \"center\" | \"right\" | \"justify\") => void;\n setLink: (options: string | { href: string; target?: string }) => void;\n unsetLink: () => void;\n setImage: (options: string | { src: string; alt?: string; title?: string }) => void;\n insertTable: (options?: { rows?: number; cols?: number; withHeaderRow?: boolean }) => void;\n insertHorizontalRule: () => void;\n clearContent: () => void;\n setContent: (content: string) => void;\n setEditable: (editable: boolean) => void;\n undo: () => void;\n redo: () => void;\n}\n\nexport function createTiptapEditor(\n options: CreateTiptapEditorOptions = {}\n): CreateTiptapEditorReturn {\n const [editorInstance, setEditorInstance] = createSignal<Editor | null>(null);\n const [html, setHtml] = createSignal<string>(\"\");\n const [text, setText] = createSignal<string>(\"\");\n const [markdown, setMarkdown] = createSignal<string>(\"\");\n const [isEmpty, setIsEmpty] = createSignal<boolean>(true);\n const [characterCount, setCharacterCount] = createSignal<number>(0);\n const [wordCount, setWordCount] = createSignal<number>(0);\n const [canUndo, setCanUndo] = createSignal<boolean>(false);\n const [canRedo, setCanRedo] = createSignal<boolean>(false);\n const [transactionVersion, setTransactionVersion] = createSignal<number>(0);\n\n let targetElement: HTMLElement | null = null;\n\n const updateStats = (ed: Editor) => {\n const currentHtml = ed.getHTML();\n const currentText = ed.getText();\n const currentMd = (ed.storage as any).markdown?.getMarkdown?.() || \"\";\n setHtml(currentHtml);\n setText(currentText);\n setMarkdown(currentMd);\n setIsEmpty(ed.isEmpty);\n setCharacterCount(ed.storage.characterCount?.characters?.() ?? currentText.length);\n setWordCount(ed.storage.characterCount?.words?.() ?? currentText.split(/\\s+/).filter(Boolean).length);\n setCanUndo(ed.can().undo());\n setCanRedo(ed.can().redo());\n setTransactionVersion((v) => v + 1);\n };\n\n const defaultExtensions: Extension[] = [\n StarterKit.configure({\n heading: {\n levels: [1, 2, 3, 4, 5, 6],\n HTMLAttributes: { class: \"font-heading tracking-tight\" },\n },\n bulletList: {\n HTMLAttributes: { class: \"list-disc pl-6 my-3 space-y-1\" },\n },\n orderedList: {\n HTMLAttributes: { class: \"list-decimal pl-6 my-3 space-y-1\" },\n },\n codeBlock: {\n HTMLAttributes: {\n class: \"rounded-lg bg-muted p-4 font-mono text-xs border border-border my-3 overflow-x-auto text-foreground\",\n },\n },\n code: {\n HTMLAttributes: {\n class: \"rounded bg-muted px-1.5 py-0.5 font-mono text-xs text-foreground font-semibold border border-border/50\",\n },\n },\n blockquote: {\n HTMLAttributes: {\n class: \"border-l-4 border-primary pl-4 italic text-muted-foreground my-3\",\n },\n },\n }) as Extension,\n Placeholder.configure({\n placeholder: options.placeholder || \"Write something rich or type '/' for commands...\",\n emptyEditorClass: \"is-editor-empty\",\n }) as Extension,\n Underline as Extension,\n Subscript as Extension,\n Superscript as Extension,\n Typography as Extension,\n Highlight.configure({\n multicolor: true,\n HTMLAttributes: { class: \"rounded px-1 py-0.5\" },\n }) as Extension,\n TextAlign.configure({ types: [\"heading\", \"paragraph\"] }) as Extension,\n Link.configure({\n openOnClick: false,\n HTMLAttributes: {\n class: \"text-primary font-medium underline underline-offset-4 hover:opacity-80 transition-opacity cursor-pointer\",\n },\n }) as Extension,\n Image.configure({\n HTMLAttributes: {\n class: \"rounded-lg max-w-full h-auto my-4 border border-border shadow-xs\",\n },\n }) as Extension,\n TaskList.configure({\n HTMLAttributes: { class: \"list-none pl-0 my-3 space-y-2\" },\n }) as Extension,\n TaskItem.configure({\n nested: true,\n HTMLAttributes: { class: \"flex items-start gap-2.5 my-1\" },\n }) as Extension,\n Table.configure({\n resizable: true,\n HTMLAttributes: {\n class: \"border-collapse table-auto w-full my-4 border border-border rounded-lg overflow-hidden text-sm\",\n },\n }) as Extension,\n TableRow as Extension,\n TableHeader.configure({\n HTMLAttributes: { class: \"border border-border bg-muted/70 px-3 py-2 font-semibold text-left text-xs\" },\n }) as Extension,\n TableCell.configure({\n HTMLAttributes: { class: \"border border-border px-3 py-2 text-xs\" },\n }) as Extension,\n CharacterCount.configure({ limit: options.characterLimit }) as Extension,\n Markdown.configure({\n html: true,\n tightLists: true,\n bulletListMarker: \"-\",\n linkify: true,\n breaks: false,\n transformPastedText: true,\n transformCopiedText: true,\n }) as Extension,\n ];\n\n const initEditor = (el: HTMLElement) => {\n if (typeof window === \"undefined\") return;\n\n const extensions = [...defaultExtensions, ...(options.extensions || [])];\n\n const editor = new Editor({\n element: el,\n content: options.content,\n editable: options.editable ?? true,\n autofocus: options.autofocus ?? false,\n extensions,\n editorProps: {\n attributes: {\n class:\n \"focus:outline-hidden min-h-[220px] w-full max-w-none text-foreground leading-relaxed text-sm \" +\n \"[&_h1]:text-3xl [&_h1]:font-bold [&_h1]:tracking-tight [&_h1]:mt-6 [&_h1]:mb-3 \" +\n \"[&_h2]:text-2xl [&_h2]:font-semibold [&_h2]:tracking-tight [&_h2]:mt-5 [&_h2]:mb-2.5 \" +\n \"[&_h3]:text-xl [&_h3]:font-semibold [&_h3]:mt-4 [&_h3]:mb-2 \" +\n \"[&_h4]:text-lg [&_h4]:font-semibold [&_h4]:mt-3 [&_h4]:mb-1.5 \" +\n \"[&_p]:my-2 [&_p]:leading-7 \" +\n \"[&_ul]:list-disc [&_ul]:pl-6 [&_ul]:my-3 [&_ul]:space-y-1 \" +\n \"[&_ol]:list-decimal [&_ol]:pl-6 [&_ol]:my-3 [&_ol]:space-y-1 \" +\n \"[&_li]:my-0.5 \" +\n \"[&_ul[data-type=taskList]]:list-none [&_ul[data-type=taskList]]:pl-0 [&_ul[data-type=taskList]]:my-3 [&_ul[data-type=taskList]]:space-y-2 \" +\n \"[&_ul[data-type=taskList]_li]:flex [&_ul[data-type=taskList]_li]:items-start [&_ul[data-type=taskList]_li]:gap-2.5 \" +\n \"[&_ul[data-type=taskList]_input[type=checkbox]]:mt-1 [&_ul[data-type=taskList]_input[type=checkbox]]:h-4 [&_ul[data-type=taskList]_input[type=checkbox]]:w-4 [&_ul[data-type=taskList]_input[type=checkbox]]:rounded [&_ul[data-type=taskList]_input[type=checkbox]]:border-border [&_ul[data-type=taskList]_input[type=checkbox]]:accent-primary [&_ul[data-type=taskList]_input[type=checkbox]]:cursor-pointer \" +\n \"[&_mark]:text-foreground [&_mark]:dark:text-background [&_mark]:font-medium [&_mark]:rounded-xs [&_mark]:px-1 [&_mark]:py-0.5 \" +\n \"[&_.is-editor-empty:first-child::before]:content-[attr(data-placeholder)] [&_.is-editor-empty:first-child::before]:text-muted-foreground [&_.is-editor-empty:first-child::before]:float-left [&_.is-editor-empty:first-child::before]:pointer-events-none [&_.is-editor-empty:first-child::before]:h-0\",\n },\n ...options.editorProps,\n },\n onUpdate: (props) => {\n updateStats(props.editor);\n options.onUpdate?.(props);\n },\n onSelectionUpdate: (props) => {\n updateStats(props.editor);\n options.onSelectionUpdate?.(props);\n },\n onTransaction: (props) => {\n updateStats(props.editor);\n options.onTransaction?.(props);\n },\n onFocus: (args) => options.onFocus?.(args),\n onBlur: (args) => options.onBlur?.(args),\n });\n\n setEditorInstance(editor);\n updateStats(editor);\n };\n\n const mount = (element: HTMLElement) => {\n targetElement = element;\n initEditor(element);\n };\n\n const destroy = () => {\n editorInstance()?.destroy();\n setEditorInstance(null);\n };\n\n onCleanup(() => {\n destroy();\n });\n\n const isActive = (name: string | Record<string, any>, attributes?: Record<string, any>) => {\n transactionVersion();\n const ed = editorInstance();\n if (!ed) return false;\n if (typeof name === \"string\") {\n return ed.isActive(name, attributes);\n }\n return ed.isActive(name);\n };\n\n return {\n editor: editorInstance,\n html,\n text,\n markdown,\n isEmpty,\n characterCount,\n wordCount,\n canUndo,\n canRedo,\n mount,\n destroy,\n isActive,\n toggleBold: () => editorInstance()?.chain().focus().toggleBold().run(),\n toggleItalic: () => editorInstance()?.chain().focus().toggleItalic().run(),\n toggleUnderline: () => editorInstance()?.chain().focus().toggleUnderline().run(),\n toggleStrike: () => editorInstance()?.chain().focus().toggleStrike().run(),\n toggleCode: () => editorInstance()?.chain().focus().toggleCode().run(),\n toggleHighlight: (color) => {\n const ed = editorInstance();\n if (!ed) return;\n if (color) {\n ed.chain().focus().toggleHighlight({ color }).run();\n } else {\n ed.chain().focus().toggleHighlight().run();\n }\n },\n setHeading: (level) => editorInstance()?.chain().focus().toggleHeading({ level }).run(),\n setParagraph: () => editorInstance()?.chain().focus().setParagraph().run(),\n toggleBulletList: () => editorInstance()?.chain().focus().toggleBulletList().run(),\n toggleOrderedList: () => editorInstance()?.chain().focus().toggleOrderedList().run(),\n toggleTaskList: () => editorInstance()?.chain().focus().toggleTaskList().run(),\n toggleBlockquote: () => editorInstance()?.chain().focus().toggleBlockquote().run(),\n toggleCodeBlock: () => editorInstance()?.chain().focus().toggleCodeBlock().run(),\n setTextAlign: (alignment) => editorInstance()?.chain().focus().setTextAlign(alignment).run(),\n setLink: (opts) => {\n const ed = editorInstance();\n if (!ed) return;\n if (typeof opts === \"string\") {\n ed.chain().focus().setLink({ href: opts, target: \"_blank\" }).run();\n } else {\n ed.chain().focus().setLink({ href: opts.href, target: opts.target ?? \"_blank\" }).run();\n }\n },\n unsetLink: () => editorInstance()?.chain().focus().unsetLink().run(),\n setImage: (opts) => {\n const ed = editorInstance();\n if (!ed) return;\n if (typeof opts === \"string\") {\n ed.chain().focus().setImage({ src: opts }).run();\n } else {\n ed.chain().focus().setImage(opts).run();\n }\n },\n insertTable: (opts) =>\n editorInstance()?.chain().focus().insertTable({\n rows: opts?.rows ?? 3,\n cols: opts?.cols ?? 3,\n withHeaderRow: opts?.withHeaderRow ?? true,\n }).run(),\n insertHorizontalRule: () => editorInstance()?.chain().focus().setHorizontalRule().run(),\n clearContent: () => editorInstance()?.chain().focus().clearContent().run(),\n setContent: (c) => editorInstance()?.commands.setContent(c),\n setEditable: (editable: boolean) => editorInstance()?.setEditable(editable),\n undo: () => editorInstance()?.chain().focus().undo().run(),\n redo: () => editorInstance()?.chain().focus().redo().run(),\n };\n}\n",
|
|
31
|
+
"type": "registry:hook"
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-undo-redo",
|
|
3
|
+
"title": "createUndoRedo",
|
|
4
|
+
"description": "SolidJS reactive primitive for undo/redo state history management, history stack tracking, and reverting actions",
|
|
5
|
+
"type": "registry:hook",
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-undo-redo.ts",
|
|
9
|
+
"content": "import { createSignal, type Accessor } from \"solid-js\";\n\nexport interface CreateUndoRedoOptions<T> {\n /** Maximum number of history states to retain. Defaults to 50. */\n maxHistory?: number;\n}\n\nexport interface CreateUndoRedoReturn<T> {\n /** Signal containing the current state value. */\n state: Accessor<T>;\n /** Update state value and append to history. */\n set: (nextState: T | ((prev: T) => T)) => void;\n /** Revert to previous state history entry. */\n undo: () => void;\n /** Advance to next state history entry. */\n redo: () => void;\n /** Signal indicating whether undo is available. */\n canUndo: Accessor<boolean>;\n /** Signal indicating whether redo is available. */\n canRedo: Accessor<boolean>;\n /** History stack of past states. */\n history: Accessor<T[]>;\n /** Reset history to initial state value. */\n reset: (initialState?: T) => void;\n}\n\n/**\n * SolidJS reactive primitive for undo/redo state history management.\n */\nexport function createUndoRedo<T>(\n initialValue: T | Accessor<T>,\n options: CreateUndoRedoOptions<T> = {}\n): CreateUndoRedoReturn<T> {\n const getInitial = (): T => {\n return typeof initialValue === \"function\"\n ? (initialValue as Accessor<T>)()\n : initialValue;\n };\n\n const maxHistory = options.maxHistory ?? 50;\n\n const [history, setHistory] = createSignal<T[]>([getInitial()]);\n const [pointer, setPointer] = createSignal<number>(0);\n\n const state = (): T => history()[pointer()] ?? getInitial();\n\n const canUndo = (): boolean => pointer() > 0;\n const canRedo = (): boolean => pointer() < history().length - 1;\n\n const set = (nextState: T | ((prev: T) => T)): void => {\n const current = state();\n const resolved =\n typeof nextState === \"function\"\n ? (nextState as (prev: T) => T)(current)\n : nextState;\n\n if (Object.is(resolved, current)) return;\n\n /* Slice history up to current pointer and push new state */\n const sliced = history().slice(0, pointer() + 1);\n const updated = [...sliced, resolved];\n\n /* Trim to maxHistory limit */\n if (updated.length > maxHistory) {\n updated.shift();\n }\n\n setHistory(updated);\n setPointer(updated.length - 1);\n };\n\n const undo = (): void => {\n if (canUndo()) {\n setPointer((p) => p - 1);\n }\n };\n\n const redo = (): void => {\n if (canRedo()) {\n setPointer((p) => p + 1);\n }\n };\n\n const reset = (newInitial?: T): void => {\n const init = newInitial !== undefined ? newInitial : getInitial();\n setHistory([init]);\n setPointer(0);\n };\n\n return {\n state,\n set,\n undo,\n redo,\n canUndo,\n canRedo,\n history,\n reset,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-web-notification",
|
|
3
|
+
"title": "createWebNotification",
|
|
4
|
+
"description": "SolidJS reactive primitive for sending browser desktop notifications and managing notification permissions",
|
|
5
|
+
"type": "registry:hook",
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-web-notification.ts",
|
|
9
|
+
"content": "import { createSignal, createEffect, type Accessor } from \"solid-js\";\n\nexport interface CreateWebNotificationOptions extends NotificationOptions {\n /** Title of the notification. */\n title?: string;\n /** Callback fired when notification is clicked. */\n onClick?: (event: Event) => void;\n /** Callback fired when notification is closed. */\n onClose?: (event: Event) => void;\n /** Callback fired when notification error occurs. */\n onError?: (event: Event) => void;\n /** Callback fired when notification is shown. */\n onShow?: (event: Event) => void;\n}\n\nexport interface CreateWebNotificationReturn {\n /** Signal accessor containing current Notification permission state. */\n permission: Accessor<NotificationPermission>;\n /** Signal accessor indicating whether Web Notifications API is supported in browser environment. */\n isSupported: Accessor<boolean>;\n /** Function to show a web notification. */\n show: (overrideTitle?: string, overrideOptions?: NotificationOptions) => Notification | null;\n /** Request notification permission from browser. */\n requestPermission: () => Promise<NotificationPermission>;\n /** Close active notification. */\n close: () => void;\n}\n\n/**\n * SolidJS reactive primitive for sending browser desktop notifications and managing notification permissions.\n */\nexport function createWebNotification(\n defaultOptions: CreateWebNotificationOptions = {}\n): CreateWebNotificationReturn {\n const [permission, setPermission] = createSignal<NotificationPermission>(\"default\");\n\n const isSupported = (): boolean =>\n typeof window !== \"undefined\" &&\n \"Notification\" in window;\n\n let activeNotification: Notification | null = null;\n\n const updatePermission = (): void => {\n if (isSupported()) {\n setPermission(Notification.permission);\n } else {\n setPermission(\"denied\");\n }\n };\n\n const requestPermission = async (): Promise<NotificationPermission> => {\n if (!isSupported()) return \"denied\";\n\n try {\n const result = await Notification.requestPermission();\n setPermission(result);\n return result;\n } catch {\n updatePermission();\n return permission();\n }\n };\n\n const close = (): void => {\n if (activeNotification) {\n activeNotification.close();\n activeNotification = null;\n }\n };\n\n const show = (\n overrideTitle?: string,\n overrideOptions?: NotificationOptions\n ): Notification | null => {\n if (!isSupported() || permission() !== \"granted\") return null;\n\n const title = overrideTitle ?? defaultOptions.title ?? \"Notification\";\n const options: NotificationOptions = {\n ...defaultOptions,\n ...overrideOptions,\n };\n\n close();\n\n try {\n const notification = new Notification(title, options);\n activeNotification = notification;\n\n if (defaultOptions.onClick) notification.onclick = (e) => defaultOptions.onClick?.(e);\n if (defaultOptions.onClose) notification.onclose = (e) => defaultOptions.onClose?.(e);\n if (defaultOptions.onError) notification.onerror = (e) => defaultOptions.onError?.(e);\n if (defaultOptions.onShow) notification.onshow = (e) => defaultOptions.onShow?.(e);\n\n return notification;\n } catch {\n return null;\n }\n };\n\n createEffect(() => {\n updatePermission();\n });\n\n return {\n permission,\n isSupported,\n show,\n requestPermission,\n close,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-websocket",
|
|
3
|
+
"title": "createWebSocket",
|
|
4
|
+
"description": "SolidJS reactive primitive for WebSocket client connections, auto-reconnection, and message passing",
|
|
5
|
+
"type": "registry:hook",
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-websocket.ts",
|
|
9
|
+
"content": "import { createSignal, createEffect, onCleanup, type Accessor } from \"solid-js\";\n\nexport type WebSocketReadyState = \"CONNECTING\" | \"OPEN\" | \"CLOSING\" | \"CLOSED\";\n\nexport interface CreateWebSocketOptions {\n /** Subprotocol or list of subprotocols. */\n protocols?: string | string[];\n /** Whether to automatically reconnect upon disconnect. Defaults to true. */\n autoReconnect?: boolean;\n /** Reconnection delay in milliseconds. Defaults to 3000ms. */\n reconnectInterval?: number;\n /** Maximum reconnection attempts. Defaults to 5. */\n maxReconnectAttempts?: number;\n /** Whether to open connection immediately upon initialization. Defaults to true. */\n immediate?: boolean;\n /** Callback fired when WebSocket connection opens. */\n onConnected?: (ws: WebSocket) => void;\n /** Callback fired when WebSocket connection closes. */\n onDisconnected?: (event: CloseEvent) => void;\n /** Callback fired when WebSocket receives a message. */\n onMessage?: (event: MessageEvent) => void;\n /** Callback fired when WebSocket encounters an error. */\n onError?: (event: Event) => void;\n}\n\nexport interface CreateWebSocketReturn<T = unknown> {\n /** Signal accessor containing latest received message data (parsed if JSON). */\n data: Accessor<T | null>;\n /** Signal accessor containing current WebSocket ready state. */\n readyState: Accessor<WebSocketReadyState>;\n /** Signal accessor containing last raw MessageEvent. */\n lastMessage: Accessor<MessageEvent | null>;\n /** Send string data or object payload (auto JSON stringified). */\n send: (data: string | object | ArrayBufferLike | Blob) => boolean;\n /** Open or reconnect WebSocket connection. */\n open: () => void;\n /** Close active WebSocket connection. */\n close: (code?: number, reason?: string) => void;\n /** Signal accessor indicating whether WebSocket is supported in browser environment. */\n isSupported: Accessor<boolean>;\n}\n\n/**\n * SolidJS reactive primitive for WebSocket client connections, auto-reconnection, and message passing.\n */\nexport function createWebSocket<T = unknown>(\n url: string | Accessor<string>,\n options: CreateWebSocketOptions = {}\n): CreateWebSocketReturn<T> {\n const [data, setData] = createSignal<T | null>(null);\n const [lastMessage, setLastMessage] = createSignal<MessageEvent | null>(null);\n const [readyState, setReadyState] = createSignal<WebSocketReadyState>(\"CLOSED\");\n\n const getUrl = (): string => (typeof url === \"function\" ? url() : url);\n\n const isSupported = (): boolean =>\n typeof window !== \"undefined\" && \"WebSocket\" in window;\n\n let ws: WebSocket | null = null;\n let reconnectCount = 0;\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\n const mapReadyState = (state: number): WebSocketReadyState => {\n switch (state) {\n case WebSocket.CONNECTING:\n return \"CONNECTING\";\n case WebSocket.OPEN:\n return \"OPEN\";\n case WebSocket.CLOSING:\n return \"CLOSING\";\n case WebSocket.CLOSED:\n default:\n return \"CLOSED\";\n }\n };\n\n const close = (code?: number, reason?: string): void => {\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n if (ws) {\n const socket = ws;\n ws = null;\n socket.close(code, reason);\n setReadyState(\"CLOSED\");\n }\n };\n\n const send = (payload: string | object | ArrayBufferLike | Blob): boolean => {\n if (!ws || ws.readyState !== WebSocket.OPEN) return false;\n\n try {\n if (typeof payload === \"object\" && !(payload instanceof ArrayBuffer) && !(payload instanceof Blob)) {\n ws.send(JSON.stringify(payload));\n } else {\n ws.send(payload as any);\n }\n return true;\n } catch {\n return false;\n }\n };\n\n const open = (): void => {\n if (!isSupported()) return;\n\n if (ws) {\n ws.close();\n ws = null;\n }\n\n setReadyState(\"CONNECTING\");\n\n try {\n const targetUrl = getUrl();\n const socket = new WebSocket(targetUrl, options.protocols);\n ws = socket;\n\n socket.onopen = () => {\n reconnectCount = 0;\n setReadyState(\"OPEN\");\n options.onConnected?.(socket);\n };\n\n socket.onmessage = (event: MessageEvent) => {\n setLastMessage(() => event);\n try {\n const parsed = JSON.parse(event.data);\n setData(() => parsed);\n } catch {\n setData(() => event.data as unknown as T);\n }\n options.onMessage?.(event);\n };\n\n socket.onerror = (event: Event) => {\n options.onError?.(event);\n };\n\n socket.onclose = (event: CloseEvent) => {\n setReadyState(\"CLOSED\");\n ws = null;\n options.onDisconnected?.(event);\n\n if (\n (options.autoReconnect ?? false) &&\n reconnectCount < (options.maxReconnectAttempts ?? 5)\n ) {\n reconnectCount++;\n reconnectTimer = setTimeout(open, options.reconnectInterval ?? 3000);\n }\n };\n } catch {\n setReadyState(\"CLOSED\");\n ws = null;\n }\n };\n\n createEffect(() => {\n if (options.immediate ?? true) {\n open();\n }\n\n onCleanup(() => {\n close();\n });\n });\n\n return {\n data,\n readyState,\n lastMessage,\n send,\n open,\n close,\n isSupported,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-window-size",
|
|
3
|
+
"title": "createWindowSize",
|
|
4
|
+
"description": "SolidJS reactive primitive for tracking window viewport inner width and height",
|
|
5
|
+
"type": "registry:hook",
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": "hooks/create-window-size.ts",
|
|
9
|
+
"content": "import { createSignal, onMount, onCleanup, type Accessor } from \"solid-js\";\n\nexport interface CreateWindowSizeReturn {\n /** Accessor for current window inner width in pixels */\n width: Accessor<number>;\n /** Accessor for current window inner height in pixels */\n height: Accessor<number>;\n}\n\n/**\n * SolidJS reactive primitive for tracking window viewport dimensions (width and height).\n */\nexport function createWindowSize(): CreateWindowSizeReturn {\n const [width, setWidth] = createSignal<number>(\n typeof window !== \"undefined\" ? window.innerWidth : 0\n );\n const [height, setHeight] = createSignal<number>(\n typeof window !== \"undefined\" ? window.innerHeight : 0\n );\n\n onMount(() => {\n if (typeof window === \"undefined\") return;\n\n const handleResize = () => {\n setWidth(window.innerWidth);\n setHeight(window.innerHeight);\n };\n\n handleResize();\n\n window.addEventListener(\"resize\", handleResize);\n onCleanup(() => {\n window.removeEventListener(\"resize\", handleResize);\n });\n });\n\n return {\n width,\n height,\n };\n}\n",
|
|
10
|
+
"type": "registry:hook"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dialog",
|
|
3
|
+
"title": "Dialog",
|
|
4
|
+
"description": "A modal window overlaying the main content, built on Kobalte primitives with blur and outside-click options.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"@kobalte/core"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"scroll-area"
|
|
13
|
+
],
|
|
14
|
+
"files": [
|
|
15
|
+
{
|
|
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 \"@/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
|
+
"type": "registry:ui"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dropdown-menu",
|
|
3
|
+
"title": "Dropdown Menu",
|
|
4
|
+
"description": "Displays a menu to the user—such as a set of actions or functions—triggered by a button or avatar.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"@kobalte/core"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"scroll-area",
|
|
13
|
+
"create-click-outside"
|
|
14
|
+
],
|
|
15
|
+
"files": [
|
|
16
|
+
{
|
|
17
|
+
"path": "ui/dropdown-menu.tsx",
|
|
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};",
|
|
19
|
+
"type": "registry:ui"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "empty",
|
|
3
|
+
"title": "Empty",
|
|
4
|
+
"description": "A compound empty-state layout for collections, search results, and initial application states.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "ui/empty.tsx",
|
|
13
|
+
"content": "import { splitProps, type Component, type JSX } from \"solid-js\";\nimport { cn } from \"@/lib/cn\";\n\nexport interface EmptyProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\n/** A centered layout for empty collections, search results, and initial states. */\nexport const Empty: Component<EmptyProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <div\n class={cn(\n \"flex min-h-64 w-full flex-col items-center justify-center rounded-lg border border-dashed border-border bg-card/30 p-6 text-center\",\n local.class\n )}\n {...rest}\n />\n );\n};\n\nexport interface EmptyIconProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const EmptyIcon: Component<EmptyIconProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <div\n aria-hidden=\"true\"\n class={cn(\n \"mb-4 flex size-12 items-center justify-center rounded-lg bg-muted text-muted-foreground [&_svg]:size-6\",\n local.class\n )}\n {...rest}\n />\n );\n};\n\nexport interface EmptyTitleProps extends JSX.HTMLAttributes<HTMLHeadingElement> {\n class?: string;\n}\n\nexport const EmptyTitle: Component<EmptyTitleProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <h3\n class={cn(\"text-lg font-semibold tracking-tight text-foreground\", local.class)}\n {...rest}\n />\n );\n};\n\nexport interface EmptyDescriptionProps\n extends JSX.HTMLAttributes<HTMLParagraphElement> {\n class?: string;\n}\n\nexport const EmptyDescription: Component<EmptyDescriptionProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <p\n class={cn(\"mt-1 max-w-sm text-sm text-muted-foreground\", local.class)}\n {...rest}\n />\n );\n};\n\nexport interface EmptyActionProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const EmptyAction: Component<EmptyActionProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <div class={cn(\"mt-5 flex items-center gap-2\", local.class)} {...rest} />\n );\n};\n",
|
|
14
|
+
"type": "registry:ui"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "field",
|
|
3
|
+
"title": "Field",
|
|
4
|
+
"description": "A consistent form field layout for labels, descriptions, and validation errors.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge"
|
|
9
|
+
],
|
|
10
|
+
"registryDependencies": [
|
|
11
|
+
"label"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
{
|
|
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 \"@/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
|
+
"type": "registry:ui"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "file-tree",
|
|
3
|
+
"title": "File Tree",
|
|
4
|
+
"description": "An interactive hierarchical directory file tree component built on Collapsible.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"lucide-solid"
|
|
10
|
+
],
|
|
11
|
+
"registryDependencies": [
|
|
12
|
+
"collapsible"
|
|
13
|
+
],
|
|
14
|
+
"files": [
|
|
15
|
+
{
|
|
16
|
+
"path": "ui/file-tree.tsx",
|
|
17
|
+
"content": "import {\n createSignal,\n splitProps,\n Show,\n type JSX,\n type ParentComponent,\n} from \"solid-js\";\nimport {\n Folder,\n FolderOpen,\n File,\n FileCode,\n FileJson,\n FileText,\n ChevronRight,\n} from \"lucide-solid\";\nimport {\n Collapsible,\n CollapsibleTrigger,\n CollapsibleContent,\n} from \"@/components/ui/collapsible\";\nimport { cn } from \"@/lib/cn\";\n\nexport interface FileTreeProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\n/**\n * Root FileTree container for displaying project directory hierarchies.\n */\nexport const FileTree: ParentComponent<FileTreeProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n return (\n <div\n class={cn(\n \"my-4 w-full rounded-lg border border-border bg-card/60 p-3 font-mono text-sm shadow-2xs select-none\",\n local.class\n )}\n {...rest}\n >\n <div class=\"space-y-0.5\">{local.children}</div>\n </div>\n );\n};\n\nexport interface FileTreeFolderProps {\n /** Folder name */\n name: string;\n /** Initial open state of the folder (default: true) */\n defaultOpen?: boolean;\n /** Controlled open state */\n open?: boolean;\n /** Callback fired when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Custom folder icon override */\n icon?: JSX.Element;\n class?: string;\n children?: JSX.Element;\n}\n\n/**\n * Collapsible folder node in the FileTree.\n */\nexport const FileTreeFolder: ParentComponent<FileTreeFolderProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"name\",\n \"defaultOpen\",\n \"open\",\n \"onOpenChange\",\n \"icon\",\n \"class\",\n \"children\",\n ]);\n\n const [isOpen, setIsOpen] = createSignal(local.defaultOpen ?? true);\n\n const openState = () => (local.open !== undefined ? local.open : isOpen());\n\n const handleToggle = (next: boolean) => {\n if (local.open === undefined) {\n setIsOpen(next);\n }\n local.onOpenChange?.(next);\n };\n\n return (\n <Collapsible\n open={openState()}\n onOpenChange={handleToggle}\n class={cn(\"w-full\", local.class)}\n {...rest}\n >\n <CollapsibleTrigger class=\"group flex w-full items-center justify-start gap-1.5 rounded-md px-1.5 py-1 text-xs text-foreground transition-colors hover:bg-muted/70 cursor-pointer\">\n <ChevronRight\n class={cn(\n \"size-3.5 shrink-0 text-muted-foreground transition-transform duration-200\",\n openState() && \"rotate-90 text-foreground\"\n )}\n />\n <Show\n when={local.icon}\n fallback={\n <Show\n when={openState()}\n fallback={<Folder class=\"size-3.5 shrink-0 text-amber-500/90 dark:text-amber-400\" />}\n >\n <FolderOpen class=\"size-3.5 shrink-0 text-amber-500 dark:text-amber-400\" />\n </Show>\n }\n >\n {local.icon}\n </Show>\n <span class=\"font-medium text-foreground tracking-tight\">{local.name}</span>\n </CollapsibleTrigger>\n\n <CollapsibleContent class=\"border-l border-border/60 ml-3.5 pl-3 pt-0.5 space-y-0.5\">\n {local.children}\n </CollapsibleContent>\n </Collapsible>\n );\n};\n\nexport interface FileTreeFileProps extends JSX.HTMLAttributes<HTMLDivElement> {\n /** File name */\n name: string;\n /** Custom file icon override */\n icon?: JSX.Element;\n class?: string;\n}\n\n/**\n * Returns a smart default Lucide icon based on file extension.\n */\nfunction getFileIcon(filename: string): JSX.Element {\n const ext = filename.split(\".\").pop()?.toLowerCase();\n switch (ext) {\n case \"tsx\":\n case \"jsx\":\n case \"ts\":\n case \"js\":\n case \"mjs\":\n case \"rs\":\n case \"py\":\n case \"go\":\n return <FileCode class=\"size-3.5 shrink-0 text-sky-500 dark:text-sky-400\" />;\n case \"json\":\n return <FileJson class=\"size-3.5 shrink-0 text-amber-500 dark:text-amber-400\" />;\n case \"md\":\n case \"mdx\":\n case \"txt\":\n return <FileText class=\"size-3.5 shrink-0 text-emerald-500 dark:text-emerald-400\" />;\n default:\n return <File class=\"size-3.5 shrink-0 text-muted-foreground\" />;\n }\n}\n\n/**\n * Leaf file item inside a FileTree.\n */\nexport const FileTreeFile: ParentComponent<FileTreeFileProps> = (props) => {\n const [local, rest] = splitProps(props, [\"name\", \"icon\", \"class\", \"children\"]);\n\n return (\n <div\n class={cn(\n \"flex w-full items-center justify-start gap-1.5 rounded-md px-1.5 py-1 text-xs text-muted-foreground transition-colors hover:bg-muted/50 hover:text-foreground cursor-default\",\n local.class\n )}\n {...rest}\n >\n <span class=\"size-3.5 shrink-0\" />\n <Show when={local.icon} fallback={getFileIcon(local.name)}>\n {local.icon}\n </Show>\n <span class=\"tracking-tight\">{local.name}</span>\n <Show when={local.children}>\n <div class=\"ml-auto\">{local.children}</div>\n </Show>\n </div>\n );\n};\n",
|
|
18
|
+
"type": "registry:ui"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "form-message",
|
|
3
|
+
"title": "Form Message",
|
|
4
|
+
"description": "Validation message helper connected to createForm errors and touched state.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"registryDependencies": [
|
|
7
|
+
"field",
|
|
8
|
+
"create-form"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "ui/form-message.tsx",
|
|
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",
|
|
14
|
+
"type": "registry:ui"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "form",
|
|
3
|
+
"title": "Form",
|
|
4
|
+
"description": "A semantic form layout wrapper designed to work with the createForm hook.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge"
|
|
9
|
+
],
|
|
10
|
+
"files": [
|
|
11
|
+
{
|
|
12
|
+
"path": "ui/form.tsx",
|
|
13
|
+
"content": "import { splitProps, type Component, type JSX } from \"solid-js\";\nimport { cn } from \"@/lib/cn\";\n\nexport interface FormProps extends JSX.FormHTMLAttributes<HTMLFormElement> {\n /** Indicates that the form is currently processing a submission. */\n loading?: boolean;\n class?: string;\n}\n\n/** A semantic form layout wrapper designed to work with the createForm hook. */\nexport const Form: Component<FormProps> = (props) => {\n const [local, rest] = splitProps(props, [\"loading\", \"class\"]);\n\n return (\n <form\n aria-busy={local.loading ? \"true\" : undefined}\n class={cn(\"w-full space-y-5\", local.class)}\n {...rest}\n />\n );\n};\n",
|
|
14
|
+
"type": "registry:ui"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hover-card",
|
|
3
|
+
"title": "Hover Card",
|
|
4
|
+
"description": "Profile and link preview popover triggered on hover, built on Kobalte primitives.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge",
|
|
9
|
+
"@kobalte/core"
|
|
10
|
+
],
|
|
11
|
+
"files": [
|
|
12
|
+
{
|
|
13
|
+
"path": "ui/hover-card.tsx",
|
|
14
|
+
"content": "import { splitProps, type JSX, type ValidComponent } from \"solid-js\";\nimport * as HoverCardPrimitive from \"@kobalte/core/hover-card\";\nimport { cn } from \"@/lib/cn\";\n\nexport type HoverCardProps = HoverCardPrimitive.HoverCardRootProps;\n\n/**\n * Root HoverCard component built on Kobalte primitives.\n * Controls hover open/close delays (default: 200ms / 150ms).\n */\nexport const HoverCard = (props: HoverCardProps) => {\n return (\n <HoverCardPrimitive.Root\n openDelay={200}\n closeDelay={150}\n {...props}\n />\n );\n};\n\nexport type HoverCardTriggerProps<T extends ValidComponent = \"a\"> =\n HoverCardPrimitive.HoverCardTriggerProps<T> &\n JSX.AnchorHTMLAttributes<HTMLAnchorElement> & {\n class?: string;\n children?: JSX.Element;\n };\n\n/**\n * HoverCard trigger handle (link, avatar, or text).\n */\nexport const HoverCardTrigger = <T extends ValidComponent = \"a\">(\n props: HoverCardTriggerProps<T>\n) => {\n const [local, rest] = splitProps(props as HoverCardTriggerProps, [\n \"class\",\n \"children\",\n ]);\n\n return (\n <HoverCardPrimitive.Trigger\n class={cn(\n \"inline-flex items-center text-sm font-medium text-foreground underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2\",\n local.class\n )}\n {...(rest as any)}\n >\n {local.children}\n </HoverCardPrimitive.Trigger>\n );\n};\n\nexport type HoverCardContentProps<T extends ValidComponent = \"div\"> =\n HoverCardPrimitive.HoverCardContentProps<T> & {\n class?: string;\n children?: JSX.Element;\n };\n\n/**\n * Floating card preview container rendered in a portal layer.\n * Includes offset spacing from trigger and support for optional HoverCardArrow.\n */\nexport const HoverCardContent = <T extends ValidComponent = \"div\">(\n props: HoverCardContentProps<T>\n) => {\n const [local, rest] = splitProps(props as HoverCardContentProps, [\n \"class\",\n \"children\",\n ]);\n\n return (\n <HoverCardPrimitive.Portal>\n <HoverCardPrimitive.Content\n sideOffset={8}\n class={cn(\n \"z-50 w-80 rounded-lg border border-border bg-popover p-4 text-popover-foreground shadow-xl outline-none transition-all 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-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n local.class\n )}\n {...(rest as any)}\n >\n {local.children}\n </HoverCardPrimitive.Content>\n </HoverCardPrimitive.Portal>\n );\n};\n\nexport type HoverCardArrowProps<T extends ValidComponent = \"div\"> =\n HoverCardPrimitive.HoverCardArrowProps<T> & {\n class?: string;\n };\n\n/**\n * Optional arrow pointer pointing to the trigger.\n */\nexport const HoverCardArrow = <T extends ValidComponent = \"div\">(\n props: HoverCardArrowProps<T>\n) => {\n const [local, rest] = splitProps(props as HoverCardArrowProps, [\"class\"]);\n\n return (\n <HoverCardPrimitive.Arrow\n class={cn(\"fill-popover stroke-border stroke-1\", local.class)}\n {...(rest as any)}\n />\n );\n};\n",
|
|
15
|
+
"type": "registry:ui"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "icon-button",
|
|
3
|
+
"title": "Icon Button",
|
|
4
|
+
"description": "An accessible square button intended for a single icon action.",
|
|
5
|
+
"type": "registry:ui",
|
|
6
|
+
"dependencies": [
|
|
7
|
+
"clsx",
|
|
8
|
+
"tailwind-merge"
|
|
9
|
+
],
|
|
10
|
+
"registryDependencies": [
|
|
11
|
+
"button"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
{
|
|
15
|
+
"path": "ui/icon-button.tsx",
|
|
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
|
+
"type": "registry:ui"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|