@kortix/ui 0.0.0-bootstrap.0 → 0.14.3
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 +153 -2
- package/dist/_vendor/kortix-shared.js +341 -0
- package/dist/chat/agent-picker.d.ts +8 -0
- package/dist/chat/agent-picker.js +18 -0
- package/dist/chat/composer.d.ts +31 -0
- package/dist/chat/composer.js +114 -0
- package/dist/chat/index.d.ts +22 -0
- package/dist/chat/index.js +22 -0
- package/dist/chat/markdown.d.ts +10 -0
- package/dist/chat/markdown.js +36 -0
- package/dist/chat/message-list.d.ts +25 -0
- package/dist/chat/message-list.js +73 -0
- package/dist/chat/message-view.d.ts +17 -0
- package/dist/chat/message-view.js +86 -0
- package/dist/chat/model-picker.d.ts +10 -0
- package/dist/chat/model-picker.js +68 -0
- package/dist/chat/permission-prompt.d.ts +10 -0
- package/dist/chat/permission-prompt.js +40 -0
- package/dist/chat/question-prompt.d.ts +8 -0
- package/dist/chat/question-prompt.js +60 -0
- package/dist/chat/send-failure.d.ts +9 -0
- package/dist/chat/send-failure.js +21 -0
- package/dist/chat/session-thread.d.ts +28 -0
- package/dist/chat/session-thread.js +47 -0
- package/dist/chat/streaming-markdown.d.ts +21 -0
- package/dist/chat/streaming-markdown.js +59 -0
- package/dist/chat/tool-call.d.ts +4 -0
- package/dist/chat/tool-call.js +150 -0
- package/dist/chat/user-message-parts.d.ts +6 -0
- package/dist/chat/user-message-parts.js +11 -0
- package/dist/components/ui/accordion.d.ts +7 -0
- package/dist/components/ui/accordion.js +18 -0
- package/dist/components/ui/alert-dialog.d.ts +19 -0
- package/dist/components/ui/alert-dialog.js +48 -0
- package/dist/components/ui/alert.d.ts +13 -0
- package/dist/components/ui/alert.js +67 -0
- package/dist/components/ui/avatar.d.ts +11 -0
- package/dist/components/ui/avatar.js +23 -0
- package/dist/components/ui/back-pill.d.ts +13 -0
- package/dist/components/ui/back-pill.js +18 -0
- package/dist/components/ui/badge.d.ts +10 -0
- package/dist/components/ui/badge.js +42 -0
- package/dist/components/ui/breadcrumb.d.ts +11 -0
- package/dist/components/ui/breadcrumb.js +28 -0
- package/dist/components/ui/bubble.d.ts +20 -0
- package/dist/components/ui/bubble.js +38 -0
- package/dist/components/ui/button-group.d.ts +9 -0
- package/dist/components/ui/button-group.js +32 -0
- package/dist/components/ui/button.d.ts +13 -0
- package/dist/components/ui/button.js +67 -0
- package/dist/components/ui/calendar.d.ts +4 -0
- package/dist/components/ui/calendar.js +39 -0
- package/dist/components/ui/card.d.ts +96 -0
- package/dist/components/ui/card.js +291 -0
- package/dist/components/ui/chain-of-thought.d.ts +75 -0
- package/dist/components/ui/chain-of-thought.js +66 -0
- package/dist/components/ui/chart.d.ts +65 -0
- package/dist/components/ui/chart.js +118 -0
- package/dist/components/ui/checkbox-group.d.ts +19 -0
- package/dist/components/ui/checkbox-group.js +41 -0
- package/dist/components/ui/checkbox.d.ts +14 -0
- package/dist/components/ui/checkbox.js +27 -0
- package/dist/components/ui/collapsible.d.ts +5 -0
- package/dist/components/ui/collapsible.js +14 -0
- package/dist/components/ui/command.d.ts +58 -0
- package/dist/components/ui/command.js +135 -0
- package/dist/components/ui/confirm-dialog.d.ts +19 -0
- package/dist/components/ui/confirm-dialog.js +30 -0
- package/dist/components/ui/context-menu.d.ts +45 -0
- package/dist/components/ui/context-menu.js +93 -0
- package/dist/components/ui/count-badge.d.ts +26 -0
- package/dist/components/ui/count-badge.js +26 -0
- package/dist/components/ui/data-grid.d.ts +24 -0
- package/dist/components/ui/data-grid.js +107 -0
- package/dist/components/ui/date-range-picker.d.ts +119 -0
- package/dist/components/ui/date-range-picker.js +190 -0
- package/dist/components/ui/definition-list.d.ts +15 -0
- package/dist/components/ui/definition-list.js +26 -0
- package/dist/components/ui/dialog.d.ts +29 -0
- package/dist/components/ui/dialog.js +52 -0
- package/dist/components/ui/disclosure.d.ts +121 -0
- package/dist/components/ui/disclosure.js +138 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-10.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-10.js +29 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-12.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-12.js +19 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-13.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-13.js +19 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-15.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-15.js +22 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-16.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-16.js +5 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-18.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-18.js +5 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-19.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-19.js +5 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-2.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-2.js +3 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-20.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-20.js +5 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-21.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-21.js +5 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-3.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-3.js +3 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-4.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-4.js +3 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-5.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-5.js +3 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-6.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-6.js +19 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-7.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-7.js +19 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-8.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-8.js +19 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-9.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-3x3-9.js +23 -0
- package/dist/components/ui/dot-matrix/dotm-circular-1.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-1.js +28 -0
- package/dist/components/ui/dot-matrix/dotm-circular-10.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-10.js +40 -0
- package/dist/components/ui/dot-matrix/dotm-circular-11.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-11.js +37 -0
- package/dist/components/ui/dot-matrix/dotm-circular-12.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-12.js +42 -0
- package/dist/components/ui/dot-matrix/dotm-circular-14.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-14.js +37 -0
- package/dist/components/ui/dot-matrix/dotm-circular-15.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-15.js +49 -0
- package/dist/components/ui/dot-matrix/dotm-circular-17.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-17.js +31 -0
- package/dist/components/ui/dot-matrix/dotm-circular-2.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-2.js +37 -0
- package/dist/components/ui/dot-matrix/dotm-circular-3.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-3.js +54 -0
- package/dist/components/ui/dot-matrix/dotm-circular-4.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-4.js +35 -0
- package/dist/components/ui/dot-matrix/dotm-circular-5.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-5.js +30 -0
- package/dist/components/ui/dot-matrix/dotm-circular-6.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-6.js +37 -0
- package/dist/components/ui/dot-matrix/dotm-circular-7.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-7.js +25 -0
- package/dist/components/ui/dot-matrix/dotm-circular-8.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-8.js +26 -0
- package/dist/components/ui/dot-matrix/dotm-circular-9.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-circular-9.js +41 -0
- package/dist/components/ui/dot-matrix/dotm-square-1.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-1.js +27 -0
- package/dist/components/ui/dot-matrix/dotm-square-10.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-10.js +27 -0
- package/dist/components/ui/dot-matrix/dotm-square-11.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-11.js +25 -0
- package/dist/components/ui/dot-matrix/dotm-square-12.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-12.js +28 -0
- package/dist/components/ui/dot-matrix/dotm-square-13.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-13.js +45 -0
- package/dist/components/ui/dot-matrix/dotm-square-14.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-14.js +38 -0
- package/dist/components/ui/dot-matrix/dotm-square-15.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-15.js +31 -0
- package/dist/components/ui/dot-matrix/dotm-square-16.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-16.js +33 -0
- package/dist/components/ui/dot-matrix/dotm-square-17.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-17.js +27 -0
- package/dist/components/ui/dot-matrix/dotm-square-18.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-18.js +29 -0
- package/dist/components/ui/dot-matrix/dotm-square-19.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-19.js +74 -0
- package/dist/components/ui/dot-matrix/dotm-square-2.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-2.js +72 -0
- package/dist/components/ui/dot-matrix/dotm-square-20.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-20.js +79 -0
- package/dist/components/ui/dot-matrix/dotm-square-3.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-3.js +23 -0
- package/dist/components/ui/dot-matrix/dotm-square-4.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-4.js +41 -0
- package/dist/components/ui/dot-matrix/dotm-square-5.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-5.js +23 -0
- package/dist/components/ui/dot-matrix/dotm-square-6.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-6.js +20 -0
- package/dist/components/ui/dot-matrix/dotm-square-7.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-7.js +43 -0
- package/dist/components/ui/dot-matrix/dotm-square-8.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-8.js +57 -0
- package/dist/components/ui/dot-matrix/dotm-square-9.d.ts +4 -0
- package/dist/components/ui/dot-matrix/dotm-square-9.js +89 -0
- package/dist/components/ui/dot-matrix/session-dot-matrix.d.ts +46 -0
- package/dist/components/ui/dot-matrix/session-dot-matrix.js +153 -0
- package/dist/components/ui/drawer.d.ts +15 -0
- package/dist/components/ui/drawer.js +35 -0
- package/dist/components/ui/dropdown-menu.d.ts +49 -0
- package/dist/components/ui/dropdown-menu.js +113 -0
- package/dist/components/ui/emoji-picker.d.ts +15 -0
- package/dist/components/ui/emoji-picker.js +137 -0
- package/dist/components/ui/emoji-tint.d.ts +41 -0
- package/dist/components/ui/emoji-tint.js +131 -0
- package/dist/components/ui/empty.d.ts +11 -0
- package/dist/components/ui/empty.js +33 -0
- package/dist/components/ui/entity-avatar.d.ts +84 -0
- package/dist/components/ui/entity-avatar.js +106 -0
- package/dist/components/ui/faded-scroll-area.d.ts +8 -0
- package/dist/components/ui/faded-scroll-area.js +80 -0
- package/dist/components/ui/favicon-avatar.d.ts +32 -0
- package/dist/components/ui/favicon-avatar.js +18 -0
- package/dist/components/ui/field.d.ts +15 -0
- package/dist/components/ui/field.js +48 -0
- package/dist/components/ui/file-tree.d.ts +32 -0
- package/dist/components/ui/file-tree.js +30 -0
- package/dist/components/ui/glyph-face.d.ts +18 -0
- package/dist/components/ui/glyph-face.js +37 -0
- package/dist/components/ui/glyph-paths-source.d.ts +2 -0
- package/dist/components/ui/glyph-paths-source.js +40 -0
- package/dist/components/ui/glyph-paths.generated.d.ts +2 -0
- package/dist/components/ui/glyph-paths.generated.js +207 -0
- package/dist/components/ui/glyph-picker.d.ts +22 -0
- package/dist/components/ui/glyph-picker.js +118 -0
- package/dist/components/ui/glyph-registry.d.ts +36 -0
- package/dist/components/ui/glyph-registry.js +479 -0
- package/dist/components/ui/glyph-tint.d.ts +6 -0
- package/dist/components/ui/glyph-tint.js +93 -0
- package/dist/components/ui/hint.d.ts +14 -0
- package/dist/components/ui/hint.js +12 -0
- package/dist/components/ui/histogram-bars.d.ts +38 -0
- package/dist/components/ui/histogram-bars.js +93 -0
- package/dist/components/ui/hover-card.d.ts +28 -0
- package/dist/components/ui/hover-card.js +35 -0
- package/dist/components/ui/icon-provider.d.ts +23 -0
- package/dist/components/ui/icon-provider.js +30 -0
- package/dist/components/ui/info-banner.d.ts +14 -0
- package/dist/components/ui/info-banner.js +72 -0
- package/dist/components/ui/inline-meta.d.ts +6 -0
- package/dist/components/ui/inline-meta.js +8 -0
- package/dist/components/ui/input-group.d.ts +19 -0
- package/dist/components/ui/input-group.js +73 -0
- package/dist/components/ui/input.d.ts +26 -0
- package/dist/components/ui/input.js +23 -0
- package/dist/components/ui/item.d.ts +23 -0
- package/dist/components/ui/item.js +67 -0
- package/dist/components/ui/kbd.d.ts +3 -0
- package/dist/components/ui/kbd.js +20 -0
- package/dist/components/ui/kortix-asterisk.d.ts +6 -0
- package/dist/components/ui/kortix-asterisk.js +17 -0
- package/dist/components/ui/kortix-icons.d.ts +2 -0
- package/dist/components/ui/kortix-icons.js +17 -0
- package/dist/components/ui/kortix-loader.d.ts +76 -0
- package/dist/components/ui/kortix-loader.js +74 -0
- package/dist/components/ui/kortix-logo.d.ts +30 -0
- package/dist/components/ui/kortix-logo.js +47 -0
- package/dist/components/ui/label.d.ts +4 -0
- package/dist/components/ui/label.js +9 -0
- package/dist/components/ui/list.d.ts +15 -0
- package/dist/components/ui/list.js +25 -0
- package/dist/components/ui/loading.d.ts +19 -0
- package/dist/components/ui/loading.js +31 -0
- package/dist/components/ui/local-time.d.ts +34 -0
- package/dist/components/ui/local-time.js +60 -0
- package/dist/components/ui/map.d.ts +101 -0
- package/dist/components/ui/map.js +257 -0
- package/dist/components/ui/marker.d.ts +14 -0
- package/dist/components/ui/marker.js +28 -0
- package/dist/components/ui/menu-recipe.d.ts +102 -0
- package/dist/components/ui/menu-recipe.js +129 -0
- package/dist/components/ui/mermaid-render.d.ts +51 -0
- package/dist/components/ui/mermaid-render.js +65 -0
- package/dist/components/ui/mermaid-renderer.d.ts +13 -0
- package/dist/components/ui/mermaid-renderer.js +340 -0
- package/dist/components/ui/message.d.ts +15 -0
- package/dist/components/ui/message.js +26 -0
- package/dist/components/ui/modal.d.ts +104 -0
- package/dist/components/ui/modal.js +180 -0
- package/dist/components/ui/navigation-menu.d.ts +16 -0
- package/dist/components/ui/navigation-menu.js +35 -0
- package/dist/components/ui/page-search-bar.d.ts +11 -0
- package/dist/components/ui/page-search-bar.js +13 -0
- package/dist/components/ui/phone-input.d.ts +7 -0
- package/dist/components/ui/phone-input.js +59 -0
- package/dist/components/ui/pixel-kortix-mark.d.ts +13 -0
- package/dist/components/ui/pixel-kortix-mark.js +40 -0
- package/dist/components/ui/popover.d.ts +10 -0
- package/dist/components/ui/popover.js +38 -0
- package/dist/components/ui/portal.d.ts +5 -0
- package/dist/components/ui/portal.js +15 -0
- package/dist/components/ui/preview-image.d.ts +14 -0
- package/dist/components/ui/preview-image.js +58 -0
- package/dist/components/ui/progress-ring.d.ts +6 -0
- package/dist/components/ui/progress-ring.js +9 -0
- package/dist/components/ui/progress.d.ts +6 -0
- package/dist/components/ui/progress.js +8 -0
- package/dist/components/ui/radio-group.d.ts +12 -0
- package/dist/components/ui/radio-group.js +20 -0
- package/dist/components/ui/resizable.d.ts +24 -0
- package/dist/components/ui/resizable.js +16 -0
- package/dist/components/ui/scroll-area.d.ts +5 -0
- package/dist/components/ui/scroll-area.js +11 -0
- package/dist/components/ui/section-card.d.ts +37 -0
- package/dist/components/ui/section-card.js +14 -0
- package/dist/components/ui/section.d.ts +10 -0
- package/dist/components/ui/section.js +22 -0
- package/dist/components/ui/select.d.ts +25 -0
- package/dist/components/ui/select.js +59 -0
- package/dist/components/ui/separator.d.ts +4 -0
- package/dist/components/ui/separator.js +8 -0
- package/dist/components/ui/shader-safe.d.ts +48 -0
- package/dist/components/ui/shader-safe.js +74 -0
- package/dist/components/ui/sheet.d.ts +32 -0
- package/dist/components/ui/sheet.js +55 -0
- package/dist/components/ui/sidebar-context.d.ts +72 -0
- package/dist/components/ui/sidebar-context.js +36 -0
- package/dist/components/ui/sidebar-menu-primitives.d.ts +38 -0
- package/dist/components/ui/sidebar-menu-primitives.js +97 -0
- package/dist/components/ui/sidebar-panel.d.ts +36 -0
- package/dist/components/ui/sidebar-panel.js +265 -0
- package/dist/components/ui/sidebar-peek.d.ts +27 -0
- package/dist/components/ui/sidebar-peek.js +70 -0
- package/dist/components/ui/sidebar-width.d.ts +48 -0
- package/dist/components/ui/sidebar-width.js +62 -0
- package/dist/components/ui/sidebar.d.ts +18 -0
- package/dist/components/ui/sidebar.js +194 -0
- package/dist/components/ui/skeleton.d.ts +3 -0
- package/dist/components/ui/skeleton.js +6 -0
- package/dist/components/ui/slider-native.d.ts +7 -0
- package/dist/components/ui/slider-native.js +16 -0
- package/dist/components/ui/slider.d.ts +14 -0
- package/dist/components/ui/slider.js +48 -0
- package/dist/components/ui/sliding-tab-indicator.d.ts +61 -0
- package/dist/components/ui/sliding-tab-indicator.js +128 -0
- package/dist/components/ui/split-sheet.d.ts +61 -0
- package/dist/components/ui/split-sheet.js +239 -0
- package/dist/components/ui/spotlight-card.d.ts +8 -0
- package/dist/components/ui/spotlight-card.js +43 -0
- package/dist/components/ui/status-ring.d.ts +38 -0
- package/dist/components/ui/status-ring.js +38 -0
- package/dist/components/ui/status.d.ts +58 -0
- package/dist/components/ui/status.js +76 -0
- package/dist/components/ui/stepper.d.ts +28 -0
- package/dist/components/ui/stepper.js +73 -0
- package/dist/components/ui/switch.d.ts +8 -0
- package/dist/components/ui/switch.js +131 -0
- package/dist/components/ui/system-message.d.ts +23 -0
- package/dist/components/ui/system-message.js +51 -0
- package/dist/components/ui/table.d.ts +10 -0
- package/dist/components/ui/table.js +28 -0
- package/dist/components/ui/tabs.d.ts +73 -0
- package/dist/components/ui/tabs.js +207 -0
- package/dist/components/ui/tag.d.ts +7 -0
- package/dist/components/ui/tag.js +22 -0
- package/dist/components/ui/text-shimmer.d.ts +13 -0
- package/dist/components/ui/text-shimmer.js +91 -0
- package/dist/components/ui/textarea.d.ts +33 -0
- package/dist/components/ui/textarea.js +87 -0
- package/dist/components/ui/toast.d.ts +105 -0
- package/dist/components/ui/toast.js +233 -0
- package/dist/components/ui/toggle.d.ts +12 -0
- package/dist/components/ui/toggle.js +26 -0
- package/dist/components/ui/tooltip.d.ts +9 -0
- package/dist/components/ui/tooltip.js +16 -0
- package/dist/components/ui/trigger-variants.d.ts +14 -0
- package/dist/components/ui/trigger-variants.js +67 -0
- package/dist/components/ui/type-to-confirm-dialog.d.ts +88 -0
- package/dist/components/ui/type-to-confirm-dialog.js +101 -0
- package/dist/components/ui/typed-title-logic.d.ts +22 -0
- package/dist/components/ui/typed-title-logic.js +33 -0
- package/dist/components/ui/typed-title.d.ts +38 -0
- package/dist/components/ui/typed-title.js +66 -0
- package/dist/components/ui/typing-animation.d.ts +36 -0
- package/dist/components/ui/typing-animation.js +141 -0
- package/dist/components/ui/user-avatar.d.ts +47 -0
- package/dist/components/ui/user-avatar.js +46 -0
- package/dist/hooks/use-debounce.d.ts +4 -0
- package/dist/hooks/use-debounce.js +17 -0
- package/dist/hooks/use-is-dark.d.ts +2 -0
- package/dist/hooks/use-is-dark.js +27 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.js +15 -0
- package/dist/hooks/use-proximity-hover.d.ts +52 -0
- package/dist/hooks/use-proximity-hover.js +232 -0
- package/dist/icons/close.d.ts +2 -0
- package/dist/icons/close.js +7 -0
- package/dist/icons/copy.d.ts +3 -0
- package/dist/icons/copy.js +6 -0
- package/dist/icons/sidebar-toggle.d.ts +13 -0
- package/dist/icons/sidebar-toggle.js +13 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +33 -0
- package/dist/lib/dotmatrix-core.d.ts +113 -0
- package/dist/lib/dotmatrix-core.js +920 -0
- package/dist/lib/dotmatrix-hooks.d.ts +28 -0
- package/dist/lib/dotmatrix-hooks.js +151 -0
- package/dist/lib/favicon.d.ts +4 -0
- package/dist/lib/favicon.js +21 -0
- package/dist/lib/font-weight.d.ts +6 -0
- package/dist/lib/font-weight.js +6 -0
- package/dist/lib/icon-config.d.ts +33 -0
- package/dist/lib/icon-config.js +22 -0
- package/dist/lib/icon-context.d.ts +34 -0
- package/dist/lib/icon-context.js +81 -0
- package/dist/lib/portal-root.d.ts +8 -0
- package/dist/lib/portal-root.js +26 -0
- package/dist/lib/settle.d.ts +16 -0
- package/dist/lib/settle.js +29 -0
- package/dist/lib/springs.d.ts +31 -0
- package/dist/lib/springs.js +29 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/lib/z-stack.d.ts +55 -0
- package/dist/lib/z-stack.js +130 -0
- package/dist/providers/ui-provider.d.ts +141 -0
- package/dist/providers/ui-provider.js +93 -0
- package/dist/styles/dotmatrix-loader.css +1239 -0
- package/dist/styles/fonts.css +46 -0
- package/dist/styles/tailwind.css +10 -0
- package/dist/styles/theme.css +1019 -0
- package/dist/styles/tokens.css +146 -0
- package/dist/styles.css +2 -0
- package/package.json +874 -4
- package/skills/kortix-ui/SKILL.md +150 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tint a project's emoji wears.
|
|
3
|
+
*
|
|
4
|
+
* In the picker (emoji-picker.tsx) a cell takes a pale fill and a stronger 1px
|
|
5
|
+
* inset ring while it is hovered or keyboard-active. That treatment is what a
|
|
6
|
+
* project's icon now wears AT REST everywhere it appears: the card tile in
|
|
7
|
+
* /projects, the switcher row in the sidebar, and the picker's own trigger
|
|
8
|
+
* button in the create/edit modals.
|
|
9
|
+
*
|
|
10
|
+
* WHERE THE HUE COMES FROM. The picker rotates its six hues by GRID POSITION —
|
|
11
|
+
* a cell's tint is a function of (column mod 6, row parity). A card tile and a
|
|
12
|
+
* trigger button have no position, so that source does not exist here. The hue
|
|
13
|
+
* is derived from the EMOJI instead, which also buys the property the feature
|
|
14
|
+
* needs: the same project shows the same colour on every surface, with no state
|
|
15
|
+
* to thread and nothing to store. 🌿 is green wherever it renders.
|
|
16
|
+
*
|
|
17
|
+
* TWO TIERS, deliberately lopsided:
|
|
18
|
+
*
|
|
19
|
+
* 1. An anchor table of ~106 emoji, below. It is not an attempt at coverage —
|
|
20
|
+
* it is the set where a MISMATCH would read as a mistake, i.e. glyphs
|
|
21
|
+
* dominated by one hue in every major vendor font (Apple, Noto, Segoe,
|
|
22
|
+
* Twemoji). A blue ring on 🔥 looks broken; a blue ring on 📝 is just a
|
|
23
|
+
* colour. Most emoji are the second kind, which is why the table stays this
|
|
24
|
+
* small and why growing it is rarely the right fix.
|
|
25
|
+
*
|
|
26
|
+
* 2. A hash for everything else. Deterministic, so a project's colour survives
|
|
27
|
+
* a reload and matches across surfaces, and spread across all six hues so
|
|
28
|
+
* the grid does not settle on one.
|
|
29
|
+
*
|
|
30
|
+
* teal is thin on purpose. Almost no emoji is unambiguously teal across
|
|
31
|
+
* vendors, so rather than force marginal glyphs into it the table leaves teal
|
|
32
|
+
* almost entirely to the hash, which keeps it in rotation.
|
|
33
|
+
*/
|
|
34
|
+
export const EMOJI_HUES = ['red', 'amber', 'green', 'teal', 'blue', 'violet'];
|
|
35
|
+
/**
|
|
36
|
+
* Variation selectors (U+FE0E text, U+FE0F emoji) and the five Fitzpatrick skin
|
|
37
|
+
* tone modifiers.
|
|
38
|
+
*
|
|
39
|
+
* Both have to go before anything is looked up or hashed. The same icon reaches
|
|
40
|
+
* this module in more than one encoding — frimousse's `onEmojiSelect`, a row
|
|
41
|
+
* loaded from the API, a value written by an older client — and '❤️' and '❤'
|
|
42
|
+
* must not be two different colours. Skin tone is the same argument five times
|
|
43
|
+
* over: without the strip, one gesture picks five unrelated hashes.
|
|
44
|
+
*/
|
|
45
|
+
const MODIFIERS = /[\u{FE0E}\u{FE0F}\u{1F3FB}-\u{1F3FF}]/gu;
|
|
46
|
+
function baseOf(emoji) {
|
|
47
|
+
return emoji.replace(MODIFIERS, '');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Emoji whose glyph is one hue in every major vendor font.
|
|
51
|
+
*
|
|
52
|
+
* Read with `[...string]`, which iterates CODE POINTS — so every entry here has
|
|
53
|
+
* to be a single code point plus an optional variation selector. No ZWJ
|
|
54
|
+
* sequences, no flags, no keycaps: those would register their halves as
|
|
55
|
+
* separate anchors. emoji-tint.test.ts enforces that, and that no glyph appears
|
|
56
|
+
* under two hues.
|
|
57
|
+
*
|
|
58
|
+
* Brown has no token of its own, so 🟤 🟫 🤎 📦 🪵 sit under amber — the
|
|
59
|
+
* nearest of the six, and much nearer than a hash would land them.
|
|
60
|
+
*/
|
|
61
|
+
const DOMINANT = {
|
|
62
|
+
red: '🔴🟥❤️🩷💔🍎🍓🍒🍅🌹🌶️🩸💋🔻🚨🚒🧨🎈🐞🦞',
|
|
63
|
+
amber: '🟠🟧🟡🟨🧡💛🟤🟫🤎🔥⚡⭐🌟✨☀️💡🍊🍋🍌🌽🧀🍯🏆🥇🌻🎃🦁🐯🐝🔶📦🪵',
|
|
64
|
+
green: '🟢🟩💚🌿🍀🌱🌳🌲🍃🥬🥦🥑🥒🍐🍏🫑🐸🐢🐍🦖♻️✅',
|
|
65
|
+
teal: '🩵🧊🫧🦚',
|
|
66
|
+
blue: '🔵🟦💙🔷🔹💧🌊🌐🌍🌎🌏🐳🐋🫐🥶🌀❄️💎🦋🩻',
|
|
67
|
+
violet: '🟣🟪💜🔮🍇🍆👾🪻',
|
|
68
|
+
};
|
|
69
|
+
const HUE_BY_EMOJI = new Map(EMOJI_HUES.flatMap((hue) => [...baseOf(DOMINANT[hue])].map((glyph) => [glyph, hue])));
|
|
70
|
+
/**
|
|
71
|
+
* FNV-1a-ish, over CODE POINTS rather than UTF-16 units — the same shape
|
|
72
|
+
* `chalkColors` in @kortix/shared uses for entity tiles, kept local because
|
|
73
|
+
* that package exports the colours and not the hash.
|
|
74
|
+
*/
|
|
75
|
+
function hash(seed) {
|
|
76
|
+
let value = 0;
|
|
77
|
+
for (const char of seed)
|
|
78
|
+
value = (value * 31 + (char.codePointAt(0) ?? 0)) | 0;
|
|
79
|
+
return Math.abs(value);
|
|
80
|
+
}
|
|
81
|
+
/** The hue an emoji wears — anchored if it is loud, hashed if it is not. */
|
|
82
|
+
export function emojiHue(emoji) {
|
|
83
|
+
const base = baseOf(emoji);
|
|
84
|
+
return HUE_BY_EMOJI.get(base) ?? EMOJI_HUES[hash(base) % EMOJI_HUES.length];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Every class below is a LITERAL string. Do not build one with a template
|
|
88
|
+
* literal or a .map(): Tailwind v4 extracts class names by scanning source
|
|
89
|
+
* TEXT, so an interpolated name emits no CSS at all and the tints silently
|
|
90
|
+
* never paint. That has already happened once on this feature.
|
|
91
|
+
*
|
|
92
|
+
* There is no `dark:` set — each token is a light-dark() pair and :root / .dark
|
|
93
|
+
* set color-scheme, so one class covers both themes.
|
|
94
|
+
*
|
|
95
|
+
* `border-0` is part of the tint, not the host's business: both hosts bring a
|
|
96
|
+
* 1px border of their own (EntityAvatar's base class list, Button's `outline`
|
|
97
|
+
* variant) and it would sit outside the inset ring as a grey second edge. The
|
|
98
|
+
* picker cell has no border at all, and matching it is the point.
|
|
99
|
+
*/
|
|
100
|
+
const TINT = {
|
|
101
|
+
red: 'border-0 bg-emoji-fill-red inset-ring-1 inset-ring-emoji-ring-red',
|
|
102
|
+
amber: 'border-0 bg-emoji-fill-amber inset-ring-1 inset-ring-emoji-ring-amber',
|
|
103
|
+
green: 'border-0 bg-emoji-fill-green inset-ring-1 inset-ring-emoji-ring-green',
|
|
104
|
+
teal: 'border-0 bg-emoji-fill-teal inset-ring-1 inset-ring-emoji-ring-teal',
|
|
105
|
+
blue: 'border-0 bg-emoji-fill-blue inset-ring-1 inset-ring-emoji-ring-blue',
|
|
106
|
+
violet: 'border-0 bg-emoji-fill-violet inset-ring-1 inset-ring-emoji-ring-violet',
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* The resting fill again, under `hover:`.
|
|
110
|
+
*
|
|
111
|
+
* Only an INTERACTIVE host needs it. Button's `outline` variant carries
|
|
112
|
+
* `hover:bg-foreground/5`, and a `:hover` rule outranks the resting
|
|
113
|
+
* `bg-emoji-fill-*` on specificity, so hovering the trigger would wipe the tint
|
|
114
|
+
* to a neutral wash. Restating the fill at the same modifier is what holds it.
|
|
115
|
+
*/
|
|
116
|
+
const TINT_HOVER = {
|
|
117
|
+
red: 'hover:bg-emoji-fill-red',
|
|
118
|
+
amber: 'hover:bg-emoji-fill-amber',
|
|
119
|
+
green: 'hover:bg-emoji-fill-green',
|
|
120
|
+
teal: 'hover:bg-emoji-fill-teal',
|
|
121
|
+
blue: 'hover:bg-emoji-fill-blue',
|
|
122
|
+
violet: 'hover:bg-emoji-fill-violet',
|
|
123
|
+
};
|
|
124
|
+
/** The picker's active-cell treatment, at rest: fill + 1px inset ring. */
|
|
125
|
+
export function emojiTint(emoji) {
|
|
126
|
+
return TINT[emojiHue(emoji)];
|
|
127
|
+
}
|
|
128
|
+
/** Holds `emojiTint`'s fill through a host variant's own hover background. */
|
|
129
|
+
export function emojiTintHover(emoji) {
|
|
130
|
+
return TINT_HOVER[emojiHue(emoji)];
|
|
131
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type VariantProps } from 'class-variance-authority';
|
|
2
|
+
declare function Empty({ className, ...props }: React.ComponentProps<'div'>): import("react").JSX.Element;
|
|
3
|
+
declare function EmptyHeader({ className, ...props }: React.ComponentProps<'div'>): import("react").JSX.Element;
|
|
4
|
+
declare const emptyMediaVariants: (props?: ({
|
|
5
|
+
variant?: "default" | "icon" | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
declare function EmptyMedia({ className, variant, ...props }: React.ComponentProps<'div'> & VariantProps<typeof emptyMediaVariants>): import("react").JSX.Element;
|
|
8
|
+
declare function EmptyTitle({ className, ...props }: React.ComponentProps<'div'>): import("react").JSX.Element;
|
|
9
|
+
declare function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>): import("react").JSX.Element;
|
|
10
|
+
declare function EmptyContent({ className, ...props }: React.ComponentProps<'div'>): import("react").JSX.Element;
|
|
11
|
+
export { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cva } from 'class-variance-authority';
|
|
3
|
+
import { cn } from '../../lib/utils.js';
|
|
4
|
+
function Empty({ className, ...props }) {
|
|
5
|
+
return (_jsx("div", { "data-slot": "empty", className: cn('flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12', className), ...props }));
|
|
6
|
+
}
|
|
7
|
+
function EmptyHeader({ className, ...props }) {
|
|
8
|
+
return (_jsx("div", { "data-slot": "empty-header", className: cn('flex max-w-sm flex-col items-center gap-2 text-center', className), ...props }));
|
|
9
|
+
}
|
|
10
|
+
const emptyMediaVariants = cva('mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0', {
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
default: 'bg-transparent',
|
|
14
|
+
icon: "flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground [&_svg:not([class*='size-'])]:size-6",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
variant: 'default',
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
function EmptyMedia({ className, variant = 'default', ...props }) {
|
|
22
|
+
return (_jsx("div", { "data-slot": "empty-icon", "data-variant": variant, className: cn(emptyMediaVariants({ variant, className })), ...props }));
|
|
23
|
+
}
|
|
24
|
+
function EmptyTitle({ className, ...props }) {
|
|
25
|
+
return (_jsx("div", { "data-slot": "empty-title", className: cn('text-lg font-medium tracking-tight', className), ...props }));
|
|
26
|
+
}
|
|
27
|
+
function EmptyDescription({ className, ...props }) {
|
|
28
|
+
return (_jsx("div", { "data-slot": "empty-description", className: cn('text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4', className), ...props }));
|
|
29
|
+
}
|
|
30
|
+
function EmptyContent({ className, ...props }) {
|
|
31
|
+
return (_jsx("div", { "data-slot": "empty-content", className: cn('flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance', className), ...props }));
|
|
32
|
+
}
|
|
33
|
+
export { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Icon } from './kortix-icons.js';
|
|
2
|
+
import { type Icon as IconType } from '@phosphor-icons/react';
|
|
3
|
+
/**
|
|
4
|
+
* `emoji` is its own step, not the initial's `text-*`: an emoji is the tile's
|
|
5
|
+
* content, not a letter set in the tile's type scale. Inheriting `box`'s size
|
|
6
|
+
* puts a 14px emoji in the 36.8px `lg` card tile — legible, but visibly a
|
|
7
|
+
* letter-sized thing in an icon-sized hole.
|
|
8
|
+
*
|
|
9
|
+
* The values are measured, not derived. A colour-emoji face is a bitmap strike,
|
|
10
|
+
* so `measureText` over-reports it and the glyph paints WIDER than its
|
|
11
|
+
* font-size. Rasterised through Chromium on this font stack, painted extent vs.
|
|
12
|
+
* the tile it sits in:
|
|
13
|
+
*
|
|
14
|
+
* xs 13px → 16×14 in 18.40 (0.87) md 16px → 20×17 in 29.44 (0.68)
|
|
15
|
+
* sm 14px → 18×16 in 22.08 (0.82) lg 20px → 22×17 in 36.80 (0.60)
|
|
16
|
+
* xl 30px → 30×25 in 51.52 (0.58)
|
|
17
|
+
*
|
|
18
|
+
* Nothing overflows its tile. The two small tiles run proportionally fuller
|
|
19
|
+
* because `text-xs` (13px) is the floor of this app's type scale — and below
|
|
20
|
+
* that an emoji stops being readable in an 18px square anyway.
|
|
21
|
+
*/
|
|
22
|
+
declare const SIZE_MAP: {
|
|
23
|
+
readonly xs: {
|
|
24
|
+
readonly box: "size-5 rounded-sm text-xs";
|
|
25
|
+
readonly icon: "size-3";
|
|
26
|
+
readonly emoji: "text-xs";
|
|
27
|
+
};
|
|
28
|
+
readonly sm: {
|
|
29
|
+
readonly box: "size-6 rounded-sm text-xs";
|
|
30
|
+
readonly icon: "size-3.5";
|
|
31
|
+
readonly emoji: "text-sm";
|
|
32
|
+
};
|
|
33
|
+
readonly md: {
|
|
34
|
+
readonly box: "size-8 rounded-md text-xs";
|
|
35
|
+
readonly icon: "size-4";
|
|
36
|
+
readonly emoji: "text-base";
|
|
37
|
+
};
|
|
38
|
+
readonly lg: {
|
|
39
|
+
readonly box: "size-10 rounded-md text-sm";
|
|
40
|
+
readonly icon: "size-5";
|
|
41
|
+
readonly emoji: "text-xl";
|
|
42
|
+
};
|
|
43
|
+
readonly xl: {
|
|
44
|
+
readonly box: "size-14 rounded-md text-base";
|
|
45
|
+
readonly icon: "size-7";
|
|
46
|
+
readonly emoji: "text-3xl";
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
export type EntityAvatarSize = keyof typeof SIZE_MAP;
|
|
50
|
+
export interface EntityAvatarProps {
|
|
51
|
+
label?: string;
|
|
52
|
+
/**
|
|
53
|
+
* A named glyph + colour — a project's alternative to `emoji`. Takes
|
|
54
|
+
* precedence over `emoji`, `icon`, and the label's initial: the field that
|
|
55
|
+
* produces this value is a union (a project has an emoji XOR a glyph,
|
|
56
|
+
* never both), so whichever was chosen last is what should paint.
|
|
57
|
+
*
|
|
58
|
+
* An unknown `name` resolves through `glyphFace()` to `null` and
|
|
59
|
+
* falls through to the rest of the precedence chain rather than painting
|
|
60
|
+
* an empty tile — the server rejects unknown names, but a client
|
|
61
|
+
* rendering STALE cached data (an old snapshot in the query cache, a
|
|
62
|
+
* catalogue that shrank) must not break.
|
|
63
|
+
*/
|
|
64
|
+
glyph?: {
|
|
65
|
+
name: string;
|
|
66
|
+
color: string;
|
|
67
|
+
} | null;
|
|
68
|
+
/**
|
|
69
|
+
* A single emoji grapheme standing in for the entity — today, a project's
|
|
70
|
+
* own icon. Beaten by `glyph`; takes precedence over `icon` and over the
|
|
71
|
+
* label's initial.
|
|
72
|
+
*
|
|
73
|
+
* Typed `| null` so it takes `KortixProject.icon` (server-validated to one
|
|
74
|
+
* emoji, or null) with no coercion at the call site. Anything falsy — null,
|
|
75
|
+
* undefined, '' — is "no emoji" and falls through to the existing behaviour,
|
|
76
|
+
* which is what keeps all ~30 emoji-less call sites byte-identical.
|
|
77
|
+
*/
|
|
78
|
+
emoji?: string | null;
|
|
79
|
+
icon?: Icon | IconType;
|
|
80
|
+
size?: EntityAvatarSize;
|
|
81
|
+
className?: string;
|
|
82
|
+
}
|
|
83
|
+
export declare function EntityAvatar({ label, glyph, emoji, icon: IconComponent, size, className, }: EntityAvatarProps): import("react").JSX.Element;
|
|
84
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { emojiTint } from './emoji-tint.js';
|
|
4
|
+
import { glyphFace } from './glyph-face.js';
|
|
5
|
+
import { glyphForeground, glyphTint } from './glyph-tint.js';
|
|
6
|
+
import { cn } from '../../lib/utils.js';
|
|
7
|
+
import { chalkColors } from '../../_vendor/kortix-shared.js';
|
|
8
|
+
/**
|
|
9
|
+
* `emoji` is its own step, not the initial's `text-*`: an emoji is the tile's
|
|
10
|
+
* content, not a letter set in the tile's type scale. Inheriting `box`'s size
|
|
11
|
+
* puts a 14px emoji in the 36.8px `lg` card tile — legible, but visibly a
|
|
12
|
+
* letter-sized thing in an icon-sized hole.
|
|
13
|
+
*
|
|
14
|
+
* The values are measured, not derived. A colour-emoji face is a bitmap strike,
|
|
15
|
+
* so `measureText` over-reports it and the glyph paints WIDER than its
|
|
16
|
+
* font-size. Rasterised through Chromium on this font stack, painted extent vs.
|
|
17
|
+
* the tile it sits in:
|
|
18
|
+
*
|
|
19
|
+
* xs 13px → 16×14 in 18.40 (0.87) md 16px → 20×17 in 29.44 (0.68)
|
|
20
|
+
* sm 14px → 18×16 in 22.08 (0.82) lg 20px → 22×17 in 36.80 (0.60)
|
|
21
|
+
* xl 30px → 30×25 in 51.52 (0.58)
|
|
22
|
+
*
|
|
23
|
+
* Nothing overflows its tile. The two small tiles run proportionally fuller
|
|
24
|
+
* because `text-xs` (13px) is the floor of this app's type scale — and below
|
|
25
|
+
* that an emoji stops being readable in an 18px square anyway.
|
|
26
|
+
*/
|
|
27
|
+
const SIZE_MAP = {
|
|
28
|
+
xs: { box: 'size-5 rounded-sm text-xs', icon: 'size-3', emoji: 'text-xs' },
|
|
29
|
+
sm: { box: 'size-6 rounded-sm text-xs', icon: 'size-3.5', emoji: 'text-sm' },
|
|
30
|
+
md: { box: 'size-8 rounded-md text-xs', icon: 'size-4', emoji: 'text-base' },
|
|
31
|
+
lg: { box: 'size-10 rounded-md text-sm', icon: 'size-5', emoji: 'text-xl' },
|
|
32
|
+
xl: { box: 'size-14 rounded-md text-base', icon: 'size-7', emoji: 'text-3xl' },
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Resolves a `glyph` prop to the component that actually draws it, or `null`
|
|
36
|
+
* if the name isn't in the registry.
|
|
37
|
+
*
|
|
38
|
+
* Its own function rather than an inline `glyph ? glyphFace(…) : null`
|
|
39
|
+
* at each use site, because EVERY use site (the inline style, the tile's
|
|
40
|
+
* class list, the rendered face) has to agree on whether there IS a
|
|
41
|
+
* renderable glyph, and a name that fails to resolve has to fall through to
|
|
42
|
+
* the rest of the precedence chain identically everywhere. Two independent
|
|
43
|
+
* `glyphFace()` calls computing the same answer is how they drift.
|
|
44
|
+
*/
|
|
45
|
+
function resolveGlyph(glyph) {
|
|
46
|
+
if (!glyph)
|
|
47
|
+
return null;
|
|
48
|
+
const GlyphComponent = glyphFace(glyph.name);
|
|
49
|
+
return GlyphComponent ? { GlyphComponent, color: glyph.color } : null;
|
|
50
|
+
}
|
|
51
|
+
export function EntityAvatar({ label, glyph, emoji, icon: IconComponent, size = 'md', className, }) {
|
|
52
|
+
const sizes = SIZE_MAP[size];
|
|
53
|
+
const initial = (label?.trim()?.charAt(0) || '?').toUpperCase();
|
|
54
|
+
const chalk = chalkColors(`${label?.trim()}` || initial);
|
|
55
|
+
const resolvedGlyph = resolveGlyph(glyph);
|
|
56
|
+
return (_jsx("span", { "data-slot": "entity-avatar",
|
|
57
|
+
// chalkColors() is an inline style, so it beats any class a caller
|
|
58
|
+
// passes. A glyph or an emoji is already the colour — sitting either on
|
|
59
|
+
// a saturated hash-derived pastel reads as noise, and in dark mode that
|
|
60
|
+
// pastel is a bright square in an otherwise dark grid. So a glyph or
|
|
61
|
+
// emoji tile drops the style entirely and rebuilds itself from its own
|
|
62
|
+
// tint tokens. See the class list.
|
|
63
|
+
style: resolvedGlyph || emoji
|
|
64
|
+
? undefined
|
|
65
|
+
: {
|
|
66
|
+
backgroundColor: chalk.background,
|
|
67
|
+
color: chalk.foreground,
|
|
68
|
+
borderColor: chalk.border,
|
|
69
|
+
}, className: cn('inline-flex shrink-0 items-center justify-center border font-semibold', sizes.box,
|
|
70
|
+
// After `sizes.box`, so tailwind-merge resolves `sizes.emoji` over the
|
|
71
|
+
// initial's text size — and so `border-0` resolves over the base
|
|
72
|
+
// `border`, which is what stops a neutral hairline being drawn OUTSIDE
|
|
73
|
+
// the coloured inset ring.
|
|
74
|
+
//
|
|
75
|
+
// `emojiTint()` is the picker's hovered-cell treatment (a pale
|
|
76
|
+
// `--color-emoji-fill-*` under a 1px `--color-emoji-ring-*` inset ring)
|
|
77
|
+
// made this tile's RESTING look, with the hue derived from the emoji
|
|
78
|
+
// rather than from a grid position the tile does not have. See
|
|
79
|
+
// emoji-tint.ts for the mapping. Both the ring and the fill are
|
|
80
|
+
// light-dark() pairs, so there is no `dark:` variant here.
|
|
81
|
+
//
|
|
82
|
+
// It replaces `bg-muted border-foreground/25 shadow-2xs`, which existed
|
|
83
|
+
// to fix a different tile: a NEUTRAL fill measured 1.07:1 against the
|
|
84
|
+
// card in dark, so it had to borrow an edge from `--foreground` and a
|
|
85
|
+
// lift from a shadow to read as a tile at all. The tinted fill and its
|
|
86
|
+
// ring carry that on their own — measured against all three surfaces in
|
|
87
|
+
// both themes, the ring runs 2.30–3.55:1 and the fill 1.19–1.55:1
|
|
88
|
+
// (.superpowers/sdd/2026-07-31-project-emoji-icons/tint-report.md).
|
|
89
|
+
//
|
|
90
|
+
// STILL LAST-WINS: a caller className that sets a background silently
|
|
91
|
+
// beats `bg-emoji-fill-*` / `bg-glyph-fill-*` and leaves the tile
|
|
92
|
+
// ringed but untinted. That is why the project card no longer passes
|
|
93
|
+
// `bg-background`.
|
|
94
|
+
resolvedGlyph ? glyphTint(resolvedGlyph.color) : emoji && [emojiTint(emoji), sizes.emoji], className), children: resolvedGlyph ? (
|
|
95
|
+
// Same reasoning as the emoji span below: the tile always sits
|
|
96
|
+
// beside the name it belongs to, so the glyph itself is decorative.
|
|
97
|
+
// `sizes.icon`, not `sizes.emoji` — a glyph is a drawn Phosphor icon,
|
|
98
|
+
// sized like the plain `icon` prop below, not like a text-rendered
|
|
99
|
+
// emoji grapheme.
|
|
100
|
+
_jsx(resolvedGlyph.GlyphComponent, { className: cn(sizes.icon, glyphForeground(resolvedGlyph.color)) })) : emoji ? (
|
|
101
|
+
// The tile always sits beside the name it belongs to, so the glyph is
|
|
102
|
+
// decorative: announced, it reads the emoji's CLDR name immediately
|
|
103
|
+
// before the label that says the same thing. Same treatment as the
|
|
104
|
+
// picker trigger in features/projects/modal/project-icon-field.tsx.
|
|
105
|
+
_jsx("span", { "aria-hidden": true, className: "leading-none", children: emoji })) : IconComponent ? (_jsx(IconComponent, { className: sizes.icon })) : (initial) }));
|
|
106
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export declare const FadedScrollArea: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
|
|
3
|
+
fadeColor?: string;
|
|
4
|
+
orientation?: "vertical" | "horizontal";
|
|
5
|
+
rootClassName?: string;
|
|
6
|
+
/** Tailwind spacing unit (`10` → `h-10`) or a CSS length (`1.5rem`). */
|
|
7
|
+
fadeSize?: string;
|
|
8
|
+
}, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from '../../lib/utils.js';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
|
6
|
+
export const FadedScrollArea = React.forwardRef(function FadedScrollArea({ children, className, fadeColor = 'from-sidebar', orientation = 'vertical', rootClassName, fadeSize = '10', style, ...props }, ref) {
|
|
7
|
+
const scrollRef = useRef(null);
|
|
8
|
+
const [showStartFade, setShowStartFade] = useState(false);
|
|
9
|
+
const [showEndFade, setShowEndFade] = useState(false);
|
|
10
|
+
const isHorizontal = orientation === 'horizontal';
|
|
11
|
+
const fadeSizeValue = /^\d+(\.\d+)?$/.test(fadeSize.trim())
|
|
12
|
+
? `calc(var(--spacing) * ${fadeSize.trim()})`
|
|
13
|
+
: fadeSize.trim();
|
|
14
|
+
const setScrollRef = useCallback((node) => {
|
|
15
|
+
scrollRef.current = node;
|
|
16
|
+
if (typeof ref === 'function') {
|
|
17
|
+
ref(node);
|
|
18
|
+
}
|
|
19
|
+
else if (ref) {
|
|
20
|
+
ref.current = node;
|
|
21
|
+
}
|
|
22
|
+
}, [ref]);
|
|
23
|
+
const updateScrollFades = useCallback(() => {
|
|
24
|
+
const el = scrollRef.current;
|
|
25
|
+
if (!el)
|
|
26
|
+
return;
|
|
27
|
+
if (isHorizontal) {
|
|
28
|
+
const { scrollLeft, scrollWidth, clientWidth } = el;
|
|
29
|
+
const maxScroll = scrollWidth - clientWidth;
|
|
30
|
+
const canScroll = maxScroll > 1;
|
|
31
|
+
if (!canScroll) {
|
|
32
|
+
setShowStartFade(false);
|
|
33
|
+
setShowEndFade(false);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
setShowStartFade(scrollLeft > 1);
|
|
37
|
+
setShowEndFade(scrollLeft < maxScroll - 1);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const { scrollTop, scrollHeight, clientHeight } = el;
|
|
41
|
+
const maxScroll = scrollHeight - clientHeight;
|
|
42
|
+
const canScroll = maxScroll > 1;
|
|
43
|
+
if (!canScroll) {
|
|
44
|
+
setShowStartFade(false);
|
|
45
|
+
setShowEndFade(false);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
setShowStartFade(scrollTop > 1);
|
|
49
|
+
setShowEndFade(scrollTop < maxScroll - 1);
|
|
50
|
+
}, [isHorizontal]);
|
|
51
|
+
useLayoutEffect(() => {
|
|
52
|
+
updateScrollFades();
|
|
53
|
+
}, [updateScrollFades]);
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
const el = scrollRef.current;
|
|
56
|
+
if (!el)
|
|
57
|
+
return;
|
|
58
|
+
const ro = new ResizeObserver(updateScrollFades);
|
|
59
|
+
ro.observe(el);
|
|
60
|
+
el.addEventListener('scroll', updateScrollFades, { passive: true });
|
|
61
|
+
window.addEventListener('resize', updateScrollFades);
|
|
62
|
+
// Keep wheel/touch scroll working inside Radix scroll-lock layers (Dialog/Modal).
|
|
63
|
+
const stopScrollLockCapture = (e) => e.stopPropagation();
|
|
64
|
+
el.addEventListener('wheel', stopScrollLockCapture, { passive: false });
|
|
65
|
+
el.addEventListener('touchmove', stopScrollLockCapture, { passive: false });
|
|
66
|
+
return () => {
|
|
67
|
+
ro.disconnect();
|
|
68
|
+
el.removeEventListener('scroll', updateScrollFades);
|
|
69
|
+
window.removeEventListener('resize', updateScrollFades);
|
|
70
|
+
el.removeEventListener('wheel', stopScrollLockCapture);
|
|
71
|
+
el.removeEventListener('touchmove', stopScrollLockCapture);
|
|
72
|
+
};
|
|
73
|
+
}, [updateScrollFades]);
|
|
74
|
+
return (_jsxs("div", { className: cn('relative flex min-h-0 min-w-0', isHorizontal ? 'w-full min-w-0 flex-1 self-center' : 'h-full flex-col', rootClassName), style: { '--fade-size': fadeSizeValue, ...style }, children: [_jsx("div", { className: cn('pointer-events-none absolute z-10 transition-opacity', fadeColor, isHorizontal
|
|
75
|
+
? 'inset-y-0 left-0 w-(--fade-size) bg-gradient-to-r to-transparent'
|
|
76
|
+
: 'inset-x-0 top-0 h-(--fade-size) bg-gradient-to-b to-transparent', showStartFade ? 'opacity-100' : 'opacity-0'), "aria-hidden": true }), _jsx("div", { className: cn('pointer-events-none absolute z-10 transition-opacity', fadeColor, isHorizontal
|
|
77
|
+
? 'inset-y-0 right-0 w-(--fade-size) bg-gradient-to-l to-transparent'
|
|
78
|
+
: 'inset-x-0 bottom-0 h-(--fade-size) bg-gradient-to-t to-transparent', showEndFade ? 'opacity-100' : 'opacity-0'), "aria-hidden": true }), _jsx("div", { ref: setScrollRef, className: cn('scrollbar-hide min-h-0 min-w-0 flex-1 pb-0', isHorizontal ? 'touch-pan-x overflow-x-auto overflow-y-hidden' : 'overflow-y-auto', className), ...props, children: children })] }));
|
|
79
|
+
});
|
|
80
|
+
FadedScrollArea.displayName = 'FadedScrollArea';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
declare const SIZE_MAP: {
|
|
2
|
+
readonly '2xs': {
|
|
3
|
+
readonly avatar: "size-4";
|
|
4
|
+
readonly icon: "size-2.5";
|
|
5
|
+
};
|
|
6
|
+
readonly xs: {
|
|
7
|
+
readonly avatar: "size-5";
|
|
8
|
+
readonly icon: "size-3";
|
|
9
|
+
};
|
|
10
|
+
readonly sm: {
|
|
11
|
+
readonly avatar: "size-6";
|
|
12
|
+
readonly icon: "size-3.5";
|
|
13
|
+
};
|
|
14
|
+
readonly md: {
|
|
15
|
+
readonly avatar: "size-8";
|
|
16
|
+
readonly icon: "size-4";
|
|
17
|
+
};
|
|
18
|
+
readonly lg: {
|
|
19
|
+
readonly avatar: "size-10";
|
|
20
|
+
readonly icon: "size-5";
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
export type FaviconAvatarSize = keyof typeof SIZE_MAP;
|
|
24
|
+
export interface FaviconAvatarProps {
|
|
25
|
+
/** Full http(s) URL or bare domain (e.g. google.com). */
|
|
26
|
+
value: string;
|
|
27
|
+
size?: FaviconAvatarSize;
|
|
28
|
+
className?: string;
|
|
29
|
+
alt?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function FaviconAvatar({ value, size, className, alt }: FaviconAvatarProps): import("react").JSX.Element;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Avatar, AvatarFallback, AvatarImage } from './avatar.js';
|
|
4
|
+
import { faviconUrlForValue } from '../../lib/favicon.js';
|
|
5
|
+
import { cn } from '../../lib/utils.js';
|
|
6
|
+
import { GlobeIcon as Globe } from '@phosphor-icons/react';
|
|
7
|
+
const SIZE_MAP = {
|
|
8
|
+
'2xs': { avatar: 'size-4', icon: 'size-2.5' },
|
|
9
|
+
xs: { avatar: 'size-5', icon: 'size-3' },
|
|
10
|
+
sm: { avatar: 'size-6', icon: 'size-3.5' },
|
|
11
|
+
md: { avatar: 'size-8', icon: 'size-4' },
|
|
12
|
+
lg: { avatar: 'size-10', icon: 'size-5' },
|
|
13
|
+
};
|
|
14
|
+
export function FaviconAvatar({ value, size = 'xs', className, alt = '' }) {
|
|
15
|
+
const sizes = SIZE_MAP[size];
|
|
16
|
+
const src = faviconUrlForValue(value);
|
|
17
|
+
return (_jsxs(Avatar, { "data-slot": "favicon-avatar", className: cn('bg-muted/60 rounded', sizes.avatar, className), children: [src ? (_jsx(AvatarImage, { src: src, alt: alt, className: "outline outline-black/10 dark:outline-white/10" })) : null, _jsx(AvatarFallback, { delayMs: 0, className: "bg-muted/60", children: _jsx(Globe, { className: cn('text-muted-foreground/50', sizes.icon) }) })] }));
|
|
18
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type VariantProps } from 'class-variance-authority';
|
|
2
|
+
import { Label } from './label.js';
|
|
3
|
+
declare function FieldGroup({ className, ...props }: React.ComponentProps<'div'>): import("react").JSX.Element;
|
|
4
|
+
declare const fieldVariants: (props?: ({
|
|
5
|
+
orientation?: "horizontal" | "vertical" | "responsive" | null | undefined;
|
|
6
|
+
variant?: "default" | "outline" | null | undefined;
|
|
7
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
8
|
+
declare function Field({ className, orientation, variant, ...props }: React.ComponentProps<'div'> & VariantProps<typeof fieldVariants> & {
|
|
9
|
+
variant?: 'default' | 'outline';
|
|
10
|
+
}): import("react").JSX.Element;
|
|
11
|
+
declare function FieldContent({ className, ...props }: React.ComponentProps<'div'>): import("react").JSX.Element;
|
|
12
|
+
declare function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>): import("react").JSX.Element;
|
|
13
|
+
declare function FieldTitle({ className, ...props }: React.ComponentProps<'div'>): import("react").JSX.Element;
|
|
14
|
+
declare function FieldDescription({ className, ...props }: React.ComponentProps<'p'>): import("react").JSX.Element;
|
|
15
|
+
export { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, FieldTitle, };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cva } from 'class-variance-authority';
|
|
4
|
+
import { Label } from './label.js';
|
|
5
|
+
import { cn } from '../../lib/utils.js';
|
|
6
|
+
function FieldGroup({ className, ...props }) {
|
|
7
|
+
return (_jsx("div", { "data-slot": "field-group", className: cn('group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4', className), ...props }));
|
|
8
|
+
}
|
|
9
|
+
const fieldVariants = cva('group/field flex w-full gap-3 data-[invalid=true]:text-destructive', {
|
|
10
|
+
variants: {
|
|
11
|
+
orientation: {
|
|
12
|
+
vertical: ['flex-col [&>*]:w-full [&>.sr-only]:w-auto'],
|
|
13
|
+
horizontal: [
|
|
14
|
+
'flex-row items-center',
|
|
15
|
+
'[&>[data-slot=field-label]]:flex-auto',
|
|
16
|
+
'has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px',
|
|
17
|
+
],
|
|
18
|
+
responsive: [
|
|
19
|
+
'flex-col @md/field-group:flex-row @md/field-group:items-center [&>*]:w-full @md/field-group:[&>*]:w-auto [&>.sr-only]:w-auto',
|
|
20
|
+
'@md/field-group:[&>[data-slot=field-label]]:flex-auto',
|
|
21
|
+
'@md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px',
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
variant: {
|
|
25
|
+
default: 'bg-transparent',
|
|
26
|
+
outline: ' border-border rounded-md border px-3 py-2.5',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
defaultVariants: {
|
|
30
|
+
orientation: 'vertical',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
function Field({ className, orientation = 'vertical', variant = 'default', ...props }) {
|
|
34
|
+
return (_jsx("div", { role: "group", "data-slot": "field", "data-orientation": orientation, className: cn(fieldVariants({ orientation, variant }), className), ...props }));
|
|
35
|
+
}
|
|
36
|
+
function FieldContent({ className, ...props }) {
|
|
37
|
+
return (_jsx("div", { "data-slot": "field-content", className: cn('group/field-content flex flex-1 flex-col gap-1.5 leading-snug', className), ...props }));
|
|
38
|
+
}
|
|
39
|
+
function FieldLabel({ className, ...props }) {
|
|
40
|
+
return (_jsx(Label, { "data-slot": "field-label", className: cn('group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50', 'has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border [&>*]:data-[slot=field]:p-4', 'has-data-[state=checked]:border-primary has-data-[state=checked]:bg-primary/5 dark:has-data-[state=checked]:bg-primary/10', className), ...props }));
|
|
41
|
+
}
|
|
42
|
+
function FieldTitle({ className, ...props }) {
|
|
43
|
+
return (_jsx("div", { "data-slot": "field-label", className: cn('flex w-fit items-center gap-2 text-sm leading-snug font-medium group-data-[disabled=true]/field:opacity-50', className), ...props }));
|
|
44
|
+
}
|
|
45
|
+
function FieldDescription({ className, ...props }) {
|
|
46
|
+
return (_jsx("p", { "data-slot": "field-description", className: cn('text-muted-foreground text-sm leading-normal font-normal group-has-[[data-orientation=horizontal]]/field:text-balance', 'last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5', '[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4', className), ...props }));
|
|
47
|
+
}
|
|
48
|
+
export { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, FieldTitle, };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface FileTreeProps {
|
|
3
|
+
title: ReactNode;
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Collapsible file-tree shell: ghost trigger with caret, rows inside the
|
|
9
|
+
* disclosure content. Uncontrolled and open by default — clicking the title
|
|
10
|
+
* collapses it (a bare `open` would freeze it; see `DisclosureProps.open`).
|
|
11
|
+
* Callers own the tree rows (or any children) — this only owns the disclosure chrome.
|
|
12
|
+
*/
|
|
13
|
+
export declare function FileTree({ title, children, className }: FileTreeProps): import("react").JSX.Element;
|
|
14
|
+
export interface FileTreeNode {
|
|
15
|
+
name: string;
|
|
16
|
+
path: string;
|
|
17
|
+
/** Nesting below the tree's root directory. 0 = sits directly in it. */
|
|
18
|
+
depth: number;
|
|
19
|
+
}
|
|
20
|
+
export interface FileTreeNavProps {
|
|
21
|
+
nodes: readonly FileTreeNode[];
|
|
22
|
+
selectedPath: string | undefined;
|
|
23
|
+
onSelect: (path: string) => void;
|
|
24
|
+
/** Accessible name for the list, e.g. "account-research files". */
|
|
25
|
+
label: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The file rows inside a `FileTree`: one indented button per file, the
|
|
29
|
+
* selected one on a quiet fill. Shared by the capability entity modal and the
|
|
30
|
+
* marketplace item rail so both trees are the same component.
|
|
31
|
+
*/
|
|
32
|
+
export declare function FileTreeNav({ nodes, selectedPath, onSelect, label }: FileTreeNavProps): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Button } from './button.js';
|
|
4
|
+
import { Disclosure, DisclosureContent, DisclosureTrigger } from './disclosure.js';
|
|
5
|
+
import { cn } from '../../lib/utils.js';
|
|
6
|
+
import { CaretRightIcon } from '@phosphor-icons/react';
|
|
7
|
+
/**
|
|
8
|
+
* Collapsible file-tree shell: ghost trigger with caret, rows inside the
|
|
9
|
+
* disclosure content. Uncontrolled and open by default — clicking the title
|
|
10
|
+
* collapses it (a bare `open` would freeze it; see `DisclosureProps.open`).
|
|
11
|
+
* Callers own the tree rows (or any children) — this only owns the disclosure chrome.
|
|
12
|
+
*/
|
|
13
|
+
export function FileTree({ title, children, className }) {
|
|
14
|
+
return (_jsxs(Disclosure, { defaultOpen: true, className: cn('group', className), children: [_jsx(DisclosureTrigger, { children: _jsxs(Button, { variant: "ghost", size: "sm", className: "flex w-full items-center justify-between gap-1.5", children: [title, _jsx(CaretRightIcon, { className: "text-muted-foreground size-3.5 transition-transform duration-(--duration-moderate) group-data-[state=open]:rotate-90" })] }) }), _jsx(DisclosureContent, { children: _jsx("div", { className: "mt-1", children: children }) })] }));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The file rows inside a `FileTree`: one indented button per file, the
|
|
18
|
+
* selected one on a quiet fill. Shared by the capability entity modal and the
|
|
19
|
+
* marketplace item rail so both trees are the same component.
|
|
20
|
+
*/
|
|
21
|
+
export function FileTreeNav({ nodes, selectedPath, onSelect, label }) {
|
|
22
|
+
if (nodes.length === 0)
|
|
23
|
+
return null;
|
|
24
|
+
return (_jsx("nav", { "aria-label": label, className: "space-y-0.5", children: nodes.map((node) => (_jsx("button", { type: "button", onClick: () => onSelect(node.path), "aria-current": node.path === selectedPath,
|
|
25
|
+
// Root rows start on the trigger's text lane (`px-2.5`, the ghost
|
|
26
|
+
// `sm` button's inset with an icon), so file names sit under the title.
|
|
27
|
+
style: { paddingLeft: `calc(var(--spacing) * 2.5 + ${node.depth * 12}px)` }, className: cn('block w-full truncate rounded-md py-1.5 pr-2 text-left text-xs transition-colors', 'focus-visible:ring-ring/50 focus-visible:ring-2 focus-visible:outline-none', node.path === selectedPath
|
|
28
|
+
? 'bg-primary/[0.06] text-foreground'
|
|
29
|
+
: 'text-muted-foreground hover:text-foreground'), children: node.name }, node.path))) }));
|
|
30
|
+
}
|