@atmos.build/ui 0.1.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 +45 -0
- package/dist/components/alert-dialog.d.ts +14 -0
- package/dist/components/alert-dialog.js +40 -0
- package/dist/components/at-search.d.ts +35 -0
- package/dist/components/at-search.js +57 -0
- package/dist/components/attachment-thumbnail-stack.d.ts +13 -0
- package/dist/components/attachment-thumbnail-stack.js +23 -0
- package/dist/components/audio-preview.d.ts +33 -0
- package/dist/components/audio-preview.js +176 -0
- package/dist/components/avatar-uploader.d.ts +29 -0
- package/dist/components/avatar-uploader.js +67 -0
- package/dist/components/avatar.d.ts +12 -0
- package/dist/components/avatar.js +38 -0
- package/dist/components/badge.d.ts +9 -0
- package/dist/components/badge.js +25 -0
- package/dist/components/button-group.d.ts +12 -0
- package/dist/components/button-group.js +29 -0
- package/dist/components/button.d.ts +10 -0
- package/dist/components/button.js +42 -0
- package/dist/components/calendar.d.ts +26 -0
- package/dist/components/calendar.js +154 -0
- package/dist/components/channel-list.d.ts +33 -0
- package/dist/components/channel-list.js +40 -0
- package/dist/components/charts/area-chart.d.ts +2 -0
- package/dist/components/charts/area-chart.js +5 -0
- package/dist/components/charts/bar-chart.d.ts +2 -0
- package/dist/components/charts/bar-chart.js +58 -0
- package/dist/components/charts/colors.d.ts +2 -0
- package/dist/components/charts/colors.js +42 -0
- package/dist/components/charts/hover.d.ts +20 -0
- package/dist/components/charts/hover.js +31 -0
- package/dist/components/charts/index.d.ts +10 -0
- package/dist/components/charts/index.js +9 -0
- package/dist/components/charts/layout.d.ts +35 -0
- package/dist/components/charts/layout.js +101 -0
- package/dist/components/charts/legend.d.ts +6 -0
- package/dist/components/charts/legend.js +7 -0
- package/dist/components/charts/line-area-chart.d.ts +4 -0
- package/dist/components/charts/line-area-chart.js +86 -0
- package/dist/components/charts/line-chart.d.ts +2 -0
- package/dist/components/charts/line-chart.js +5 -0
- package/dist/components/charts/pie-chart.d.ts +2 -0
- package/dist/components/charts/pie-chart.js +22 -0
- package/dist/components/charts/radar-chart.d.ts +2 -0
- package/dist/components/charts/radar-chart.js +29 -0
- package/dist/components/charts/radial-chart.d.ts +2 -0
- package/dist/components/charts/radial-chart.js +19 -0
- package/dist/components/charts/scatter-chart.d.ts +2 -0
- package/dist/components/charts/scatter-chart.js +16 -0
- package/dist/components/charts/story-data.d.ts +24 -0
- package/dist/components/charts/story-data.js +48 -0
- package/dist/components/charts/types.d.ts +43 -0
- package/dist/components/charts/types.js +1 -0
- package/dist/components/checkbox.d.ts +4 -0
- package/dist/components/checkbox.js +10 -0
- package/dist/components/chip.d.ts +25 -0
- package/dist/components/chip.js +36 -0
- package/dist/components/code-editor-theme.d.ts +19 -0
- package/dist/components/code-editor-theme.js +100 -0
- package/dist/components/collapsible-section-header.d.ts +82 -0
- package/dist/components/collapsible-section-header.js +82 -0
- package/dist/components/collection-view/collection-view-group-settings.d.ts +73 -0
- package/dist/components/collection-view/collection-view-group-settings.js +55 -0
- package/dist/components/collection-view/collection-view-settings.d.ts +115 -0
- package/dist/components/collection-view/collection-view-settings.js +146 -0
- package/dist/components/collection-view/collection-view.d.ts +87 -0
- package/dist/components/collection-view/collection-view.js +95 -0
- package/dist/components/collection-view/index.d.ts +6 -0
- package/dist/components/collection-view/index.js +6 -0
- package/dist/components/collection-view/use-collection-detail-navigation.d.ts +11 -0
- package/dist/components/collection-view/use-collection-detail-navigation.js +12 -0
- package/dist/components/collection-view/use-collection-escape.d.ts +9 -0
- package/dist/components/collection-view/use-collection-escape.js +20 -0
- package/dist/components/collection-view/use-collection-selection.d.ts +42 -0
- package/dist/components/collection-view/use-collection-selection.js +203 -0
- package/dist/components/color-picker.d.ts +18 -0
- package/dist/components/color-picker.js +77 -0
- package/dist/components/color-swatch-list.d.ts +16 -0
- package/dist/components/color-swatch-list.js +60 -0
- package/dist/components/combobox/combobox.d.ts +4 -0
- package/dist/components/combobox/combobox.js +70 -0
- package/dist/components/combobox/compound.d.ts +68 -0
- package/dist/components/combobox/compound.js +151 -0
- package/dist/components/combobox/context.d.ts +34 -0
- package/dist/components/combobox/context.js +123 -0
- package/dist/components/combobox/create-step.d.ts +12 -0
- package/dist/components/combobox/create-step.js +8 -0
- package/dist/components/combobox/index.d.ts +10 -0
- package/dist/components/combobox/index.js +5 -0
- package/dist/components/combobox/inline-create-form.d.ts +24 -0
- package/dist/components/combobox/inline-create-form.js +43 -0
- package/dist/components/combobox/types.d.ts +57 -0
- package/dist/components/combobox/types.js +10 -0
- package/dist/components/command.d.ts +35 -0
- package/dist/components/command.js +76 -0
- package/dist/components/comment-pin.d.ts +13 -0
- package/dist/components/comment-pin.js +33 -0
- package/dist/components/confidence-meter.d.ts +11 -0
- package/dist/components/confidence-meter.js +24 -0
- package/dist/components/context-menu.d.ts +31 -0
- package/dist/components/context-menu.js +54 -0
- package/dist/components/copy-button.d.ts +12 -0
- package/dist/components/copy-button.js +32 -0
- package/dist/components/date-picker.d.ts +29 -0
- package/dist/components/date-picker.js +86 -0
- package/dist/components/date-tile.d.ts +11 -0
- package/dist/components/date-tile.js +16 -0
- package/dist/components/date-time-picker.d.ts +25 -0
- package/dist/components/date-time-picker.js +153 -0
- package/dist/components/detail-breadcrumb-utils.d.ts +2 -0
- package/dist/components/detail-breadcrumb-utils.js +18 -0
- package/dist/components/detail-nav-bar.d.ts +28 -0
- package/dist/components/detail-nav-bar.js +28 -0
- package/dist/components/detail-top-bar.d.ts +49 -0
- package/dist/components/detail-top-bar.js +41 -0
- package/dist/components/dialog.d.ts +22 -0
- package/dist/components/dialog.js +51 -0
- package/dist/components/dropdown-menu.d.ts +29 -0
- package/dist/components/dropdown-menu.js +52 -0
- package/dist/components/editable-doc-title.d.ts +17 -0
- package/dist/components/editable-doc-title.js +147 -0
- package/dist/components/empty-state.d.ts +12 -0
- package/dist/components/empty-state.js +6 -0
- package/dist/components/filter-condition-editor.d.ts +18 -0
- package/dist/components/filter-condition-editor.js +102 -0
- package/dist/components/form-dialog.d.ts +30 -0
- package/dist/components/form-dialog.js +52 -0
- package/dist/components/formula-editor.d.ts +18 -0
- package/dist/components/formula-editor.js +154 -0
- package/dist/components/hover-card.d.ts +52 -0
- package/dist/components/hover-card.js +51 -0
- package/dist/components/icon-button.d.ts +15 -0
- package/dist/components/icon-button.js +18 -0
- package/dist/components/inline-alert.d.ts +11 -0
- package/dist/components/inline-alert.js +17 -0
- package/dist/components/input.d.ts +3 -0
- package/dist/components/input.js +7 -0
- package/dist/components/kanban-board.d.ts +27 -0
- package/dist/components/kanban-board.js +145 -0
- package/dist/components/kbd.d.ts +3 -0
- package/dist/components/kbd.js +8 -0
- package/dist/components/label.d.ts +4 -0
- package/dist/components/label.js +9 -0
- package/dist/components/markdown-editor/index.d.ts +4 -0
- package/dist/components/markdown-editor/index.js +2 -0
- package/dist/components/markdown-editor/markdown-editor.d.ts +16 -0
- package/dist/components/markdown-editor/markdown-editor.js +53 -0
- package/dist/components/markdown-editor/serialize.d.ts +12 -0
- package/dist/components/markdown-editor/serialize.js +122 -0
- package/dist/components/markdown-editor/vim.d.ts +8 -0
- package/dist/components/markdown-editor/vim.js +394 -0
- package/dist/components/metric-grid.d.ts +41 -0
- package/dist/components/metric-grid.js +39 -0
- package/dist/components/microphone-priority.d.ts +29 -0
- package/dist/components/microphone-priority.js +15 -0
- package/dist/components/middle-truncate.d.ts +6 -0
- package/dist/components/middle-truncate.js +15 -0
- package/dist/components/multi-combobox.d.ts +48 -0
- package/dist/components/multi-combobox.js +221 -0
- package/dist/components/naut-avatar-engine.d.ts +83 -0
- package/dist/components/naut-avatar-engine.js +803 -0
- package/dist/components/naut-avatar.d.ts +31 -0
- package/dist/components/naut-avatar.js +108 -0
- package/dist/components/navigable-list.d.ts +4 -0
- package/dist/components/navigable-list.js +20 -0
- package/dist/components/note-icon-picker.d.ts +20 -0
- package/dist/components/note-icon-picker.js +84 -0
- package/dist/components/note-icon.d.ts +690 -0
- package/dist/components/note-icon.js +353 -0
- package/dist/components/note-row.d.ts +33 -0
- package/dist/components/note-row.js +29 -0
- package/dist/components/overlapping-dots.d.ts +10 -0
- package/dist/components/overlapping-dots.js +13 -0
- package/dist/components/overview-card.d.ts +12 -0
- package/dist/components/overview-card.js +9 -0
- package/dist/components/panel-header.d.ts +8 -0
- package/dist/components/panel-header.js +6 -0
- package/dist/components/panel-section-states.d.ts +9 -0
- package/dist/components/panel-section-states.js +10 -0
- package/dist/components/person-avatar.d.ts +10 -0
- package/dist/components/person-avatar.js +23 -0
- package/dist/components/photo-avatar.d.ts +11 -0
- package/dist/components/photo-avatar.js +24 -0
- package/dist/components/picker-field.d.ts +23 -0
- package/dist/components/picker-field.js +24 -0
- package/dist/components/popover-stack.d.ts +26 -0
- package/dist/components/popover-stack.js +89 -0
- package/dist/components/popover.d.ts +12 -0
- package/dist/components/popover.js +31 -0
- package/dist/components/portal-login-barrier.d.ts +12 -0
- package/dist/components/portal-login-barrier.js +41 -0
- package/dist/components/presence-dot.d.ts +8 -0
- package/dist/components/presence-dot.js +15 -0
- package/dist/components/presence-overlay.d.ts +27 -0
- package/dist/components/presence-overlay.js +34 -0
- package/dist/components/property-list.d.ts +64 -0
- package/dist/components/property-list.js +313 -0
- package/dist/components/property-panel.d.ts +54 -0
- package/dist/components/property-panel.js +87 -0
- package/dist/components/property-selector.d.ts +36 -0
- package/dist/components/property-selector.js +141 -0
- package/dist/components/provenance-chip.d.ts +12 -0
- package/dist/components/provenance-chip.js +17 -0
- package/dist/components/qr-code.d.ts +13 -0
- package/dist/components/qr-code.js +42 -0
- package/dist/components/qr-encode.d.ts +2 -0
- package/dist/components/qr-encode.js +469 -0
- package/dist/components/quantity-stepper.d.ts +25 -0
- package/dist/components/quantity-stepper.js +43 -0
- package/dist/components/radio-group.d.ts +5 -0
- package/dist/components/radio-group.js +13 -0
- package/dist/components/rename-dialog.d.ts +19 -0
- package/dist/components/rename-dialog.js +35 -0
- package/dist/components/row-surface.d.ts +1 -0
- package/dist/components/row-surface.js +5 -0
- package/dist/components/row-trailing.d.ts +30 -0
- package/dist/components/row-trailing.js +59 -0
- package/dist/components/run-status-badge.d.ts +16 -0
- package/dist/components/run-status-badge.js +43 -0
- package/dist/components/scroll-area.d.ts +5 -0
- package/dist/components/scroll-area.js +12 -0
- package/dist/components/select.d.ts +15 -0
- package/dist/components/select.js +39 -0
- package/dist/components/selectable-card.d.ts +33 -0
- package/dist/components/selectable-card.js +66 -0
- package/dist/components/separator.d.ts +3 -0
- package/dist/components/separator.js +8 -0
- package/dist/components/settings-dialog-shell.d.ts +46 -0
- package/dist/components/settings-dialog-shell.js +48 -0
- package/dist/components/shimmer-text.d.ts +8 -0
- package/dist/components/shimmer-text.js +26 -0
- package/dist/components/side-panel-tokens.d.ts +27 -0
- package/dist/components/side-panel-tokens.js +26 -0
- package/dist/components/side-panel.d.ts +94 -0
- package/dist/components/side-panel.js +106 -0
- package/dist/components/skeleton.d.ts +2 -0
- package/dist/components/skeleton.js +6 -0
- package/dist/components/sortable.d.ts +65 -0
- package/dist/components/sortable.js +110 -0
- package/dist/components/spec-strip.d.ts +18 -0
- package/dist/components/spec-strip.js +15 -0
- package/dist/components/speech-playback.d.ts +25 -0
- package/dist/components/speech-playback.js +35 -0
- package/dist/components/sql-editor.d.ts +13 -0
- package/dist/components/sql-editor.js +228 -0
- package/dist/components/stat-tile.d.ts +7 -0
- package/dist/components/stat-tile.js +6 -0
- package/dist/components/status-badge.d.ts +17 -0
- package/dist/components/status-badge.js +8 -0
- package/dist/components/status-tone.d.ts +9 -0
- package/dist/components/status-tone.js +10 -0
- package/dist/components/sticky-header-fade.d.ts +8 -0
- package/dist/components/sticky-header-fade.js +11 -0
- package/dist/components/swatch-button.d.ts +14 -0
- package/dist/components/swatch-button.js +25 -0
- package/dist/components/switch.d.ts +6 -0
- package/dist/components/switch.js +9 -0
- package/dist/components/system-load/index.d.ts +6 -0
- package/dist/components/system-load/index.js +6 -0
- package/dist/components/system-load/load-block.d.ts +20 -0
- package/dist/components/system-load/load-block.js +23 -0
- package/dist/components/system-load/load-grid.d.ts +16 -0
- package/dist/components/system-load/load-grid.js +23 -0
- package/dist/components/system-load/load-meter.d.ts +25 -0
- package/dist/components/system-load/load-meter.js +29 -0
- package/dist/components/system-load/load-tone.d.ts +21 -0
- package/dist/components/system-load/load-tone.js +29 -0
- package/dist/components/system-load/meter-row.d.ts +31 -0
- package/dist/components/system-load/meter-row.js +29 -0
- package/dist/components/system-load/resource-meter.d.ts +19 -0
- package/dist/components/system-load/resource-meter.js +15 -0
- package/dist/components/tab-title-bar.d.ts +12 -0
- package/dist/components/tab-title-bar.js +9 -0
- package/dist/components/table.d.ts +10 -0
- package/dist/components/table.js +29 -0
- package/dist/components/tabs.d.ts +11 -0
- package/dist/components/tabs.js +97 -0
- package/dist/components/template-chip-input.d.ts +36 -0
- package/dist/components/template-chip-input.js +271 -0
- package/dist/components/template-input.d.ts +24 -0
- package/dist/components/template-input.js +57 -0
- package/dist/components/terminal-spinner.d.ts +11 -0
- package/dist/components/terminal-spinner.js +48 -0
- package/dist/components/textarea.d.ts +3 -0
- package/dist/components/textarea.js +7 -0
- package/dist/components/time-column.d.ts +24 -0
- package/dist/components/time-column.js +60 -0
- package/dist/components/timestamped-transcript.d.ts +38 -0
- package/dist/components/timestamped-transcript.js +29 -0
- package/dist/components/timezone-picker.d.ts +22 -0
- package/dist/components/timezone-picker.js +60 -0
- package/dist/components/tooltip.d.ts +11 -0
- package/dist/components/tooltip.js +29 -0
- package/dist/components/transcription-overlay.d.ts +47 -0
- package/dist/components/transcription-overlay.js +30 -0
- package/dist/components/usage-bar.d.ts +17 -0
- package/dist/components/usage-bar.js +26 -0
- package/dist/components/view-query-bar.d.ts +13 -0
- package/dist/components/view-query-bar.js +13 -0
- package/dist/components/view-query-controls.d.ts +159 -0
- package/dist/components/view-query-controls.js +109 -0
- package/dist/components/view-save-menu.d.ts +20 -0
- package/dist/components/view-save-menu.js +13 -0
- package/dist/components/view-sort-editor.d.ts +40 -0
- package/dist/components/view-sort-editor.js +47 -0
- package/dist/components/voice-line.d.ts +37 -0
- package/dist/components/voice-line.js +293 -0
- package/dist/components/weekly-schedule-editor.d.ts +15 -0
- package/dist/components/weekly-schedule-editor.js +28 -0
- package/dist/flow/canvas/canvas-frame.d.ts +160 -0
- package/dist/flow/canvas/canvas-frame.js +521 -0
- package/dist/flow/canvas/collaborator-layer.d.ts +12 -0
- package/dist/flow/canvas/collaborator-layer.js +43 -0
- package/dist/flow/canvas/connector-edge.d.ts +22 -0
- package/dist/flow/canvas/connector-edge.js +61 -0
- package/dist/flow/canvas/editor-context.d.ts +23 -0
- package/dist/flow/canvas/editor-context.js +6 -0
- package/dist/flow/canvas/graph-core.d.ts +60 -0
- package/dist/flow/canvas/graph-core.js +296 -0
- package/dist/flow/canvas/minimap-sticky-overlay.d.ts +4 -0
- package/dist/flow/canvas/minimap-sticky-overlay.js +45 -0
- package/dist/flow/canvas/node-card.d.ts +46 -0
- package/dist/flow/canvas/node-card.js +56 -0
- package/dist/flow/canvas/node-library.d.ts +40 -0
- package/dist/flow/canvas/node-library.js +54 -0
- package/dist/flow/canvas/sticky-notes.d.ts +25 -0
- package/dist/flow/canvas/sticky-notes.js +101 -0
- package/dist/flow/collaborative-graph-presence.d.ts +28 -0
- package/dist/flow/collaborative-graph-presence.js +55 -0
- package/dist/flow/collaborative-graph-sync.d.ts +40 -0
- package/dist/flow/collaborative-graph-sync.js +127 -0
- package/dist/flow/editor/adapter.d.ts +64 -0
- package/dist/flow/editor/adapter.js +1 -0
- package/dist/flow/editor/command-registry.d.ts +10 -0
- package/dist/flow/editor/command-registry.js +35 -0
- package/dist/flow/editor/dag-canvas.d.ts +18 -0
- package/dist/flow/editor/dag-canvas.js +33 -0
- package/dist/flow/editor/flow-editor.d.ts +54 -0
- package/dist/flow/editor/flow-editor.js +199 -0
- package/dist/flow/editor/issues-popover.d.ts +11 -0
- package/dist/flow/editor/issues-popover.js +70 -0
- package/dist/flow/editor/library-rail.d.ts +19 -0
- package/dist/flow/editor/library-rail.js +25 -0
- package/dist/flow/editor/make-controller.d.ts +18 -0
- package/dist/flow/editor/make-controller.js +44 -0
- package/dist/flow/editor/node-chip.d.ts +2 -0
- package/dist/flow/editor/node-chip.js +16 -0
- package/dist/flow/editor/save-publish-bar.d.ts +27 -0
- package/dist/flow/editor/save-publish-bar.js +14 -0
- package/dist/flow/editor/settings-dialog.d.ts +11 -0
- package/dist/flow/editor/settings-dialog.js +11 -0
- package/dist/flow/editor/settings-shell.d.ts +21 -0
- package/dist/flow/editor/settings-shell.js +20 -0
- package/dist/flow/editor/side-rail.d.ts +22 -0
- package/dist/flow/editor/side-rail.js +15 -0
- package/dist/flow/editor/use-dag-editor.d.ts +94 -0
- package/dist/flow/editor/use-dag-editor.js +502 -0
- package/dist/flow/index.d.ts +25 -0
- package/dist/flow/index.js +25 -0
- package/dist/flow/presence-motion.d.ts +10 -0
- package/dist/flow/presence-motion.js +88 -0
- package/dist/flow/styles.css +1 -0
- package/dist/flow/use-collaborative-graph.d.ts +61 -0
- package/dist/flow/use-collaborative-graph.js +396 -0
- package/dist/flow/use-debounced-value.d.ts +1 -0
- package/dist/flow/use-debounced-value.js +10 -0
- package/dist/hooks/use-detail-nav.d.ts +11 -0
- package/dist/hooks/use-detail-nav.js +49 -0
- package/dist/hooks/use-flush-on-hide.d.ts +1 -0
- package/dist/hooks/use-flush-on-hide.js +21 -0
- package/dist/hooks/use-media-query.d.ts +1 -0
- package/dist/hooks/use-media-query.js +20 -0
- package/dist/hooks/use-virtualizer.d.ts +1 -0
- package/dist/hooks/use-virtualizer.js +1 -0
- package/dist/index.d.ts +139 -0
- package/dist/index.js +139 -0
- package/dist/lib/brand-style.d.ts +6 -0
- package/dist/lib/brand-style.js +16 -0
- package/dist/lib/cn.d.ts +2 -0
- package/dist/lib/cn.js +5 -0
- package/dist/lib/composited-glint.d.ts +7 -0
- package/dist/lib/composited-glint.js +98 -0
- package/dist/lib/date-time-format.d.ts +2 -0
- package/dist/lib/date-time-format.js +21 -0
- package/dist/lib/disclosure-state.d.ts +11 -0
- package/dist/lib/disclosure-state.js +22 -0
- package/dist/lib/label-swatches.d.ts +10 -0
- package/dist/lib/label-swatches.js +24 -0
- package/dist/lib/local-ui-state.d.ts +10 -0
- package/dist/lib/local-ui-state.js +95 -0
- package/dist/lib/parse-loose-datetime.d.ts +1 -0
- package/dist/lib/parse-loose-datetime.js +180 -0
- package/dist/lib/parse-loose-time.d.ts +6 -0
- package/dist/lib/parse-loose-time.js +53 -0
- package/dist/lib/parse-loose.d.ts +1 -0
- package/dist/lib/parse-loose.js +170 -0
- package/dist/lib/react-19-jsx.d.ts +8 -0
- package/dist/lib/react-19-jsx.js +1 -0
- package/dist/lib/view-chrome.d.ts +5 -0
- package/dist/lib/view-chrome.js +5 -0
- package/dist/lib/view-query/config.d.ts +26 -0
- package/dist/lib/view-query/config.js +162 -0
- package/dist/lib/view-query/evaluate.d.ts +11 -0
- package/dist/lib/view-query/evaluate.js +196 -0
- package/dist/lib/view-query/group-order.d.ts +25 -0
- package/dist/lib/view-query/group-order.js +49 -0
- package/dist/lib/view-query/index.d.ts +6 -0
- package/dist/lib/view-query/index.js +6 -0
- package/dist/lib/view-query/model.d.ts +34 -0
- package/dist/lib/view-query/model.js +88 -0
- package/dist/lib/view-query/sort.d.ts +7 -0
- package/dist/lib/view-query/sort.js +30 -0
- package/dist/lib/view-query/types.d.ts +70 -0
- package/dist/lib/view-query/types.js +12 -0
- package/dist/lib/weekly-schedule.d.ts +8 -0
- package/dist/lib/weekly-schedule.js +10 -0
- package/dist/mcp-app/index.d.ts +4 -0
- package/dist/mcp-app/index.js +3 -0
- package/dist/mcp-app/shadcn.css +629 -0
- package/dist/mcp-app/styles.css +72 -0
- package/dist/mcp-app/theme.d.ts +2 -0
- package/dist/mcp-app/theme.js +62 -0
- package/dist/mcp-app/use-atmos-mcp-app.d.ts +109 -0
- package/dist/mcp-app/use-atmos-mcp-app.js +30 -0
- package/dist/mcp-app/vite.d.ts +7 -0
- package/dist/mcp-app/vite.js +30 -0
- package/dist/tokens/index.d.ts +7 -0
- package/dist/tokens/index.js +7 -0
- package/dist/tokens/semantic.css +110 -0
- package/dist/tokens/tokens.css +195 -0
- package/package.json +98 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../../lib/cn.js';
|
|
5
|
+
import { LoadMeter } from './load-meter.js';
|
|
6
|
+
import { LOAD_TEXT, resolveLoadReading } from './load-tone.js';
|
|
7
|
+
/**
|
|
8
|
+
* Short enough that the reading sits inside a line of text rather than spanning the surface,
|
|
9
|
+
* long enough to tell a quarter from a half. A popover has no room for an instrument.
|
|
10
|
+
*/
|
|
11
|
+
const DEFAULT_ROW_BLOCKS = 5;
|
|
12
|
+
/**
|
|
13
|
+
* The grid the rows inside it borrow. Each row is its own subgrid, so a stack of readings
|
|
14
|
+
* puts its blocks and its figures on the same two edges however wide the labels run — which
|
|
15
|
+
* a row that sized itself could not do, and which is the whole reason a column of readings
|
|
16
|
+
* scans as one instrument.
|
|
17
|
+
*/
|
|
18
|
+
export function MeterRowGroup({ className, ...props }) {
|
|
19
|
+
return (_jsx("div", { "data-slot": "meter-row-group", className: cn('grid grid-cols-[minmax(0,1fr)_auto_auto] items-center gap-x-2.5 gap-y-1.5', className), ...props }));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A reading on one line: what it measures, a short run of blocks filled to it, the figure.
|
|
23
|
+
* ResourceMeter is the same reading given a panel to live in; this is the form that belongs
|
|
24
|
+
* beside rows of text, where a full-width track would claim the surface for a single number.
|
|
25
|
+
*/
|
|
26
|
+
export function MeterRow({ label, percent, detail, caption, alertAt, labelHidden, className, ...props }) {
|
|
27
|
+
const { value, reading, tone } = resolveLoadReading(percent, detail, alertAt);
|
|
28
|
+
return (_jsxs("div", { "data-slot": "meter-row", "data-tone": tone, className: cn('col-span-3 grid grid-cols-subgrid items-center', className), ...props, children: [_jsx("span", { className: cn('text-muted-foreground truncate text-[11.5px]', labelHidden && 'sr-only'), children: label }), _jsx(LoadMeter, { label: label, percent: value, detail: reading, blocks: DEFAULT_ROW_BLOCKS, alertAt: alertAt, size: "sm" }), _jsx("span", { className: cn('shrink-0 font-mono text-[11.5px] tabular-nums', LOAD_TEXT[tone]), children: reading }), caption ? (_jsx("p", { className: "text-muted-foreground/75 col-span-3 mt-0.5 font-mono text-[10.5px]", children: caption })) : null] }));
|
|
29
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export interface ResourceMeterProps extends Omit<React.ComponentProps<'div'>, 'children'> {
|
|
3
|
+
/** What is being measured — "Memory", "Storage". */
|
|
4
|
+
label: string;
|
|
5
|
+
/** Utilisation, 0–100. */
|
|
6
|
+
percent: number;
|
|
7
|
+
/** The reading in the reader's units, already formatted: "27.9 GB of 64 GB". */
|
|
8
|
+
detail?: string;
|
|
9
|
+
/** How many blocks the line is long; each one is a slice of the whole. */
|
|
10
|
+
blocks?: number;
|
|
11
|
+
/** Past this reading the meter turns red. Left out, it never does. */
|
|
12
|
+
alertAt?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A label, a line of blocks filled to the reading, and the reading itself. The line is
|
|
16
|
+
* drawn in the same units as the core grid above it, so a panel of them reads as one
|
|
17
|
+
* instrument rather than as a stack of unrelated bars.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ResourceMeter({ label, percent, detail, blocks, alertAt, className, ...props }: ResourceMeterProps): React.JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../../lib/cn.js';
|
|
5
|
+
import { LoadMeter } from './load-meter.js';
|
|
6
|
+
import { LOAD_TEXT, resolveLoadReading } from './load-tone.js';
|
|
7
|
+
/**
|
|
8
|
+
* A label, a line of blocks filled to the reading, and the reading itself. The line is
|
|
9
|
+
* drawn in the same units as the core grid above it, so a panel of them reads as one
|
|
10
|
+
* instrument rather than as a stack of unrelated bars.
|
|
11
|
+
*/
|
|
12
|
+
export function ResourceMeter({ label, percent, detail, blocks, alertAt, className, ...props }) {
|
|
13
|
+
const { value, reading, tone } = resolveLoadReading(percent, detail, alertAt);
|
|
14
|
+
return (_jsxs("div", { "data-slot": "resource-meter", "data-tone": tone, className: cn('grid grid-cols-[minmax(0,5rem)_auto_1fr] items-center gap-3', className), ...props, children: [_jsx("span", { className: "truncate text-[12.5px]", children: label }), _jsx(LoadMeter, { label: label, percent: value, detail: detail, blocks: blocks, alertAt: alertAt }), _jsx("span", { className: cn('truncate font-mono text-[11.5px] tabular-nums', LOAD_TEXT[tone]), children: reading })] }));
|
|
15
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export interface TabTitleBarProps {
|
|
3
|
+
left: ReactNode;
|
|
4
|
+
actions?: ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
chromeFont?: string;
|
|
7
|
+
dataTestId?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function TabTitleBar({ left, actions, className, chromeFont, dataTestId, }: TabTitleBarProps): import("react").JSX.Element;
|
|
10
|
+
export declare function tabTitleBarButtonClass(className?: string, opts?: {
|
|
11
|
+
iconOnly?: boolean;
|
|
12
|
+
}): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { DetailTopBar, detailTopBarButtonClass } from './detail-top-bar.js';
|
|
4
|
+
export function TabTitleBar({ left, actions, className, chromeFont, dataTestId, }) {
|
|
5
|
+
return (_jsx(DetailTopBar, { trail: left, actions: actions, chromeFont: chromeFont, className: className, dataTestId: dataTestId }));
|
|
6
|
+
}
|
|
7
|
+
export function tabTitleBarButtonClass(className, opts = {}) {
|
|
8
|
+
return detailTopBarButtonClass(className, opts);
|
|
9
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
declare function Table({ className, ...props }: React.ComponentProps<'table'>): React.JSX.Element;
|
|
3
|
+
declare function TableHeader({ className, ...props }: React.ComponentProps<'thead'>): React.JSX.Element;
|
|
4
|
+
declare function TableBody({ className, ...props }: React.ComponentProps<'tbody'>): React.JSX.Element;
|
|
5
|
+
declare function TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>): React.JSX.Element;
|
|
6
|
+
declare function TableRow({ className, ...props }: React.ComponentProps<'tr'>): React.JSX.Element;
|
|
7
|
+
declare function TableHead({ className, ...props }: React.ComponentProps<'th'>): React.JSX.Element;
|
|
8
|
+
declare function TableCell({ className, ...props }: React.ComponentProps<'td'>): React.JSX.Element;
|
|
9
|
+
declare function TableCaption({ className, ...props }: React.ComponentProps<'caption'>): React.JSX.Element;
|
|
10
|
+
export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../lib/cn.js';
|
|
5
|
+
function Table({ className, ...props }) {
|
|
6
|
+
return (_jsx("div", { "data-slot": "table-container", className: "relative w-full overflow-x-auto", children: _jsx("table", { "data-slot": "table", className: cn('w-full caption-bottom text-sm', className), ...props }) }));
|
|
7
|
+
}
|
|
8
|
+
function TableHeader({ className, ...props }) {
|
|
9
|
+
return _jsx("thead", { "data-slot": "table-header", className: cn('[&_tr]:border-b', className), ...props });
|
|
10
|
+
}
|
|
11
|
+
function TableBody({ className, ...props }) {
|
|
12
|
+
return (_jsx("tbody", { "data-slot": "table-body", className: cn('[&_tr:last-child]:border-0', className), ...props }));
|
|
13
|
+
}
|
|
14
|
+
function TableFooter({ className, ...props }) {
|
|
15
|
+
return (_jsx("tfoot", { "data-slot": "table-footer", className: cn('bg-muted/50 border-t font-medium [&>tr]:last:border-b-0', className), ...props }));
|
|
16
|
+
}
|
|
17
|
+
function TableRow({ className, ...props }) {
|
|
18
|
+
return (_jsx("tr", { "data-slot": "table-row", className: cn('hover:bg-muted/40 data-[state=selected]:bg-muted border-b transition-colors', className), ...props }));
|
|
19
|
+
}
|
|
20
|
+
function TableHead({ className, ...props }) {
|
|
21
|
+
return (_jsx("th", { "data-slot": "table-head", className: cn('text-muted-foreground h-9 px-3 text-left align-middle font-mono text-[11px] font-medium whitespace-nowrap', '[&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]', className), ...props }));
|
|
22
|
+
}
|
|
23
|
+
function TableCell({ className, ...props }) {
|
|
24
|
+
return (_jsx("td", { "data-slot": "table-cell", className: cn('px-3 py-2.5 align-middle text-[13px] whitespace-nowrap', '[&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]', className), ...props }));
|
|
25
|
+
}
|
|
26
|
+
function TableCaption({ className, ...props }) {
|
|
27
|
+
return (_jsx("caption", { "data-slot": "table-caption", className: cn('text-muted-foreground mt-4 text-sm', className), ...props }));
|
|
28
|
+
}
|
|
29
|
+
export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type VariantProps } from "class-variance-authority";
|
|
3
|
+
import { Tabs as TabsPrimitive } from "radix-ui";
|
|
4
|
+
declare function Tabs({ className, orientation, ...props }: React.ComponentProps<typeof TabsPrimitive.Root>): React.JSX.Element;
|
|
5
|
+
declare const tabsListVariants: (props?: ({
|
|
6
|
+
variant?: "line" | "default" | null | undefined;
|
|
7
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
8
|
+
declare function TabsList({ className, variant, children, ...props }: React.ComponentProps<typeof TabsPrimitive.List> & VariantProps<typeof tabsListVariants>): React.JSX.Element;
|
|
9
|
+
declare function TabsTrigger({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Trigger>): React.JSX.Element;
|
|
10
|
+
declare function TabsContent({ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Content>): React.JSX.Element;
|
|
11
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
import { Tabs as TabsPrimitive } from "radix-ui";
|
|
6
|
+
import { cn } from '../lib/cn.js';
|
|
7
|
+
function Tabs({ className, orientation = "horizontal", ...props }) {
|
|
8
|
+
return (_jsx(TabsPrimitive.Root, { "data-slot": "tabs", "data-orientation": orientation, className: cn("group/tabs flex gap-2 data-[orientation=horizontal]:flex-col", className), ...props }));
|
|
9
|
+
}
|
|
10
|
+
const tabsListVariants = cva("group/tabs-list relative inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col data-[variant=line]:rounded-none", {
|
|
11
|
+
variants: {
|
|
12
|
+
variant: {
|
|
13
|
+
default: "bg-muted group-data-horizontal/tabs:h-8",
|
|
14
|
+
line: "gap-1 bg-transparent group-data-horizontal/tabs:min-h-8",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
defaultVariants: {
|
|
18
|
+
variant: "line",
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
function TabsList({ className, variant = "line", children, ...props }) {
|
|
22
|
+
const listRef = React.useRef(null);
|
|
23
|
+
const [orientation, setOrientation] = React.useState("horizontal");
|
|
24
|
+
const [indicator, setIndicator] = React.useState({
|
|
25
|
+
left: 0,
|
|
26
|
+
top: 0,
|
|
27
|
+
width: 0,
|
|
28
|
+
height: 0,
|
|
29
|
+
visible: false,
|
|
30
|
+
});
|
|
31
|
+
const [animate, setAnimate] = React.useState(false);
|
|
32
|
+
React.useEffect(() => {
|
|
33
|
+
if (variant !== "line")
|
|
34
|
+
return;
|
|
35
|
+
const list = listRef.current;
|
|
36
|
+
if (!list)
|
|
37
|
+
return;
|
|
38
|
+
const update = () => {
|
|
39
|
+
setOrientation(list
|
|
40
|
+
.closest('[data-slot="tabs"]')
|
|
41
|
+
?.getAttribute("data-orientation") === "vertical"
|
|
42
|
+
? "vertical"
|
|
43
|
+
: "horizontal");
|
|
44
|
+
const active = list.querySelector('[data-slot="tabs-trigger"][data-state="active"]');
|
|
45
|
+
if (!active) {
|
|
46
|
+
setIndicator((prev) => ({ ...prev, visible: false }));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
setIndicator({
|
|
50
|
+
left: active.offsetLeft,
|
|
51
|
+
top: active.offsetTop,
|
|
52
|
+
width: active.offsetWidth,
|
|
53
|
+
height: active.offsetHeight,
|
|
54
|
+
visible: true,
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
update();
|
|
58
|
+
const frame = requestAnimationFrame(() => setAnimate(true));
|
|
59
|
+
const mutation = new MutationObserver(update);
|
|
60
|
+
mutation.observe(list, {
|
|
61
|
+
subtree: true,
|
|
62
|
+
attributes: true,
|
|
63
|
+
attributeFilter: ["data-state"],
|
|
64
|
+
});
|
|
65
|
+
const resize = new ResizeObserver(update);
|
|
66
|
+
resize.observe(list);
|
|
67
|
+
list
|
|
68
|
+
.querySelectorAll('[data-slot="tabs-trigger"]')
|
|
69
|
+
.forEach((el) => resize.observe(el));
|
|
70
|
+
return () => {
|
|
71
|
+
cancelAnimationFrame(frame);
|
|
72
|
+
mutation.disconnect();
|
|
73
|
+
resize.disconnect();
|
|
74
|
+
};
|
|
75
|
+
}, [variant, children]);
|
|
76
|
+
return (_jsxs(TabsPrimitive.List, { ref: listRef, "data-slot": "tabs-list", "data-variant": variant, className: cn(tabsListVariants({ variant }), className), ...props, children: [variant === "line" ? (_jsx("span", { "aria-hidden": true, "data-slot": "tabs-indicator", className: cn("pointer-events-none absolute z-0 bg-foreground", animate &&
|
|
77
|
+
"transition-[left,top,width,height,opacity] duration-150 ease-[cubic-bezier(0.4,0,0.2,1)]", indicator.visible ? "opacity-100" : "opacity-0"), style: orientation === "vertical"
|
|
78
|
+
? {
|
|
79
|
+
top: indicator.top,
|
|
80
|
+
height: indicator.height,
|
|
81
|
+
right: 0,
|
|
82
|
+
width: 2,
|
|
83
|
+
}
|
|
84
|
+
: {
|
|
85
|
+
left: indicator.left,
|
|
86
|
+
width: indicator.width,
|
|
87
|
+
bottom: 0,
|
|
88
|
+
height: 2,
|
|
89
|
+
} })) : null, children] }));
|
|
90
|
+
}
|
|
91
|
+
function TabsTrigger({ className, ...props }) {
|
|
92
|
+
return (_jsx(TabsPrimitive.Trigger, { "data-slot": "tabs-trigger", className: cn("relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-1.5 py-0.5 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50 has-data-[icon=inline-end]:pr-1 has-data-[icon=inline-start]:pl-1 dark:text-muted-foreground dark:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent", "data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground", className), ...props }));
|
|
93
|
+
}
|
|
94
|
+
function TabsContent({ className, ...props }) {
|
|
95
|
+
return (_jsx(TabsPrimitive.Content, { "data-slot": "tabs-content", className: cn("flex-1 text-sm outline-none", className), ...props }));
|
|
96
|
+
}
|
|
97
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type KeyboardEvent, type MutableRefObject } from 'react';
|
|
2
|
+
import type { TemplateToken } from './template-input.js';
|
|
3
|
+
export type TemplateChipInputHandle = {
|
|
4
|
+
focus: () => void;
|
|
5
|
+
getSelection: () => {
|
|
6
|
+
start: number;
|
|
7
|
+
end: number;
|
|
8
|
+
};
|
|
9
|
+
setSelection: (offset: number) => void;
|
|
10
|
+
getBoundingClientRect: () => DOMRect | null;
|
|
11
|
+
};
|
|
12
|
+
export type TemplateChipInputProps = {
|
|
13
|
+
value: string;
|
|
14
|
+
onChange: (value: string) => void;
|
|
15
|
+
/** Token ranges within `value`; each renders as an atomic chip. */
|
|
16
|
+
tokens?: ReadonlyArray<TemplateToken>;
|
|
17
|
+
multiline?: boolean;
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
invalid?: boolean;
|
|
20
|
+
className?: string;
|
|
21
|
+
onFocus?: () => void;
|
|
22
|
+
onBlur?: () => void;
|
|
23
|
+
/** Fires whenever the caret moves (offsets are in `value` space). */
|
|
24
|
+
onSelect?: () => void;
|
|
25
|
+
onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void;
|
|
26
|
+
handleRef?: MutableRefObject<TemplateChipInputHandle | null>;
|
|
27
|
+
removeTokenLabel?: string;
|
|
28
|
+
'aria-label'?: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* A template-string editor that renders each `{{ … }}` token as an atomic
|
|
32
|
+
* inline chip with a friendly label. The value stays the raw template string;
|
|
33
|
+
* chips are presentation only. Deleting a chip (× or backspace) removes the
|
|
34
|
+
* whole token from the value.
|
|
35
|
+
*/
|
|
36
|
+
export declare function TemplateChipInput({ value, onChange, tokens, multiline, placeholder, invalid, className, onFocus, onBlur, onSelect, onKeyDown, handleRef, removeTokenLabel, 'aria-label': ariaLabel, }: TemplateChipInputProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useLayoutEffect, useRef, } from 'react';
|
|
4
|
+
import { cn } from '../lib/cn.js';
|
|
5
|
+
const CHIP_BRACES_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="width:11px;height:11px;flex:none"><path d="M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1"/><path d="M16 21h1a2 2 0 0 0 2-2v-5c0-1.1.9-2 2-2a2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1"/></svg>';
|
|
6
|
+
const CHIP_X_SVG = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="width:10px;height:10px;flex:none"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>';
|
|
7
|
+
function serialize(root) {
|
|
8
|
+
let out = '';
|
|
9
|
+
root.childNodes.forEach((node) => {
|
|
10
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
11
|
+
out += node.textContent ?? '';
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (node instanceof HTMLElement) {
|
|
15
|
+
const raw = node.dataset.raw;
|
|
16
|
+
if (raw !== undefined) {
|
|
17
|
+
out += raw;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (node.tagName === 'BR') {
|
|
21
|
+
out += '\n';
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
out += node.textContent ?? '';
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
/** Serialized length a node contributes (chips count as their raw template text). */
|
|
30
|
+
function nodeLength(node) {
|
|
31
|
+
if (node.nodeType === Node.TEXT_NODE)
|
|
32
|
+
return (node.textContent ?? '').length;
|
|
33
|
+
if (node instanceof HTMLElement) {
|
|
34
|
+
if (node.dataset.raw !== undefined)
|
|
35
|
+
return node.dataset.raw.length;
|
|
36
|
+
if (node.tagName === 'BR')
|
|
37
|
+
return 1;
|
|
38
|
+
return (node.textContent ?? '').length;
|
|
39
|
+
}
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
function selectionOffsets(root) {
|
|
43
|
+
const selection = window.getSelection();
|
|
44
|
+
if (!selection || selection.rangeCount === 0)
|
|
45
|
+
return { start: 0, end: 0 };
|
|
46
|
+
const range = selection.getRangeAt(0);
|
|
47
|
+
return {
|
|
48
|
+
start: pointOffset(root, range.startContainer, range.startOffset),
|
|
49
|
+
end: pointOffset(root, range.endContainer, range.endOffset),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function pointOffset(root, container, offset) {
|
|
53
|
+
if (container === root) {
|
|
54
|
+
let acc = 0;
|
|
55
|
+
for (let index = 0; index < offset; index += 1) {
|
|
56
|
+
const child = root.childNodes.item(index);
|
|
57
|
+
if (child)
|
|
58
|
+
acc += nodeLength(child);
|
|
59
|
+
}
|
|
60
|
+
return acc;
|
|
61
|
+
}
|
|
62
|
+
let acc = 0;
|
|
63
|
+
for (const child of Array.from(root.childNodes)) {
|
|
64
|
+
if (child === container || child.contains(container)) {
|
|
65
|
+
if (child.nodeType === Node.TEXT_NODE)
|
|
66
|
+
return acc + offset;
|
|
67
|
+
if (child instanceof HTMLElement && child.dataset.raw !== undefined) {
|
|
68
|
+
// Inside a chip: snap to its end.
|
|
69
|
+
return acc + child.dataset.raw.length;
|
|
70
|
+
}
|
|
71
|
+
return acc + offset;
|
|
72
|
+
}
|
|
73
|
+
acc += nodeLength(child);
|
|
74
|
+
}
|
|
75
|
+
return acc;
|
|
76
|
+
}
|
|
77
|
+
function placeCaret(root, target) {
|
|
78
|
+
const selection = window.getSelection();
|
|
79
|
+
if (!selection)
|
|
80
|
+
return;
|
|
81
|
+
let acc = 0;
|
|
82
|
+
for (const child of Array.from(root.childNodes)) {
|
|
83
|
+
const length = nodeLength(child);
|
|
84
|
+
if (target <= acc + length) {
|
|
85
|
+
const range = document.createRange();
|
|
86
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
87
|
+
range.setStart(child, Math.max(0, Math.min(target - acc, length)));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// A chip (or other element): put the caret before or after it whole.
|
|
91
|
+
if (target - acc <= length / 2)
|
|
92
|
+
range.setStartBefore(child);
|
|
93
|
+
else
|
|
94
|
+
range.setStartAfter(child);
|
|
95
|
+
}
|
|
96
|
+
range.collapse(true);
|
|
97
|
+
selection.removeAllRanges();
|
|
98
|
+
selection.addRange(range);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
acc += length;
|
|
102
|
+
}
|
|
103
|
+
const range = document.createRange();
|
|
104
|
+
range.selectNodeContents(root);
|
|
105
|
+
range.collapse(false);
|
|
106
|
+
selection.removeAllRanges();
|
|
107
|
+
selection.addRange(range);
|
|
108
|
+
}
|
|
109
|
+
function chipElement(raw, token, removeLabel) {
|
|
110
|
+
const chip = document.createElement('span');
|
|
111
|
+
chip.contentEditable = 'false';
|
|
112
|
+
chip.dataset.raw = raw;
|
|
113
|
+
chip.title = token.title ?? raw;
|
|
114
|
+
chip.className = cn('mx-px inline-flex h-[18px] max-w-full min-w-0 items-center gap-1 rounded-full py-0 pr-0.5 pl-1.5 align-[-3px] text-[11px] leading-none', token.valid ? 'bg-primary/10 text-primary' : 'bg-destructive/10 text-destructive');
|
|
115
|
+
const glyph = document.createElement('span');
|
|
116
|
+
glyph.innerHTML = CHIP_BRACES_SVG;
|
|
117
|
+
glyph.style.display = 'inline-flex';
|
|
118
|
+
chip.appendChild(glyph);
|
|
119
|
+
const label = document.createElement('span');
|
|
120
|
+
label.textContent = token.label ?? token.title ?? raw.replace(/^\{\{\s*|\s*\}\}$/g, '');
|
|
121
|
+
label.className = 'min-w-0 truncate';
|
|
122
|
+
chip.appendChild(label);
|
|
123
|
+
const remove = document.createElement('button');
|
|
124
|
+
remove.type = 'button';
|
|
125
|
+
remove.dataset.chipRemove = 'true';
|
|
126
|
+
remove.setAttribute('aria-label', removeLabel);
|
|
127
|
+
remove.className =
|
|
128
|
+
'flex size-3.5 shrink-0 items-center justify-center rounded-full hover:bg-current/15';
|
|
129
|
+
remove.innerHTML = CHIP_X_SVG;
|
|
130
|
+
chip.appendChild(remove);
|
|
131
|
+
return chip;
|
|
132
|
+
}
|
|
133
|
+
function rebuild(root, value, tokens, removeLabel) {
|
|
134
|
+
root.textContent = '';
|
|
135
|
+
let cursor = 0;
|
|
136
|
+
for (const token of tokens) {
|
|
137
|
+
if (token.start > cursor) {
|
|
138
|
+
root.appendChild(document.createTextNode(value.slice(cursor, token.start)));
|
|
139
|
+
}
|
|
140
|
+
root.appendChild(chipElement(value.slice(token.start, token.end), token, removeLabel));
|
|
141
|
+
cursor = token.end;
|
|
142
|
+
}
|
|
143
|
+
if (cursor < value.length)
|
|
144
|
+
root.appendChild(document.createTextNode(value.slice(cursor)));
|
|
145
|
+
}
|
|
146
|
+
function tokensKey(tokens) {
|
|
147
|
+
return tokens
|
|
148
|
+
.map((token) => `${token.start}:${token.end}:${token.valid ? 1 : 0}:${token.label ?? ''}`)
|
|
149
|
+
.join('|');
|
|
150
|
+
}
|
|
151
|
+
function insertPlainText(root, text) {
|
|
152
|
+
const selection = window.getSelection();
|
|
153
|
+
if (!selection || selection.rangeCount === 0)
|
|
154
|
+
return;
|
|
155
|
+
const range = selection.getRangeAt(0);
|
|
156
|
+
if (!root.contains(range.startContainer))
|
|
157
|
+
return;
|
|
158
|
+
range.deleteContents();
|
|
159
|
+
const node = document.createTextNode(text);
|
|
160
|
+
range.insertNode(node);
|
|
161
|
+
range.setStartAfter(node);
|
|
162
|
+
range.collapse(true);
|
|
163
|
+
selection.removeAllRanges();
|
|
164
|
+
selection.addRange(range);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* A template-string editor that renders each `{{ … }}` token as an atomic
|
|
168
|
+
* inline chip with a friendly label. The value stays the raw template string;
|
|
169
|
+
* chips are presentation only. Deleting a chip (× or backspace) removes the
|
|
170
|
+
* whole token from the value.
|
|
171
|
+
*/
|
|
172
|
+
export function TemplateChipInput({ value, onChange, tokens = [], multiline, placeholder, invalid, className, onFocus, onBlur, onSelect, onKeyDown, handleRef, removeTokenLabel = 'Remove', 'aria-label': ariaLabel, }) {
|
|
173
|
+
const rootRef = useRef(null);
|
|
174
|
+
const renderedRef = useRef(null);
|
|
175
|
+
const focusedRef = useRef(false);
|
|
176
|
+
useLayoutEffect(() => {
|
|
177
|
+
const root = rootRef.current;
|
|
178
|
+
if (!root)
|
|
179
|
+
return;
|
|
180
|
+
const key = tokensKey(tokens);
|
|
181
|
+
const rendered = renderedRef.current;
|
|
182
|
+
if (rendered && rendered.value === value && rendered.key === key)
|
|
183
|
+
return;
|
|
184
|
+
const caret = focusedRef.current ? selectionOffsets(root).start : null;
|
|
185
|
+
rebuild(root, value, tokens, removeTokenLabel);
|
|
186
|
+
renderedRef.current = { value, key };
|
|
187
|
+
if (caret !== null)
|
|
188
|
+
placeCaret(root, Math.min(caret, value.length));
|
|
189
|
+
});
|
|
190
|
+
useLayoutEffect(() => {
|
|
191
|
+
if (!handleRef)
|
|
192
|
+
return;
|
|
193
|
+
handleRef.current = {
|
|
194
|
+
focus: () => rootRef.current?.focus(),
|
|
195
|
+
getSelection: () => {
|
|
196
|
+
const root = rootRef.current;
|
|
197
|
+
return root ? selectionOffsets(root) : { start: 0, end: 0 };
|
|
198
|
+
},
|
|
199
|
+
setSelection: (offset) => {
|
|
200
|
+
const root = rootRef.current;
|
|
201
|
+
if (!root)
|
|
202
|
+
return;
|
|
203
|
+
root.focus();
|
|
204
|
+
placeCaret(root, offset);
|
|
205
|
+
},
|
|
206
|
+
getBoundingClientRect: () => rootRef.current?.getBoundingClientRect() ?? null,
|
|
207
|
+
};
|
|
208
|
+
return () => {
|
|
209
|
+
handleRef.current = null;
|
|
210
|
+
};
|
|
211
|
+
}, [handleRef]);
|
|
212
|
+
const emit = () => {
|
|
213
|
+
const root = rootRef.current;
|
|
214
|
+
if (!root)
|
|
215
|
+
return;
|
|
216
|
+
const next = serialize(root);
|
|
217
|
+
renderedRef.current = { value: next, key: renderedRef.current?.key ?? '' };
|
|
218
|
+
onChange(next);
|
|
219
|
+
};
|
|
220
|
+
return (_jsxs("div", { className: "relative min-w-0 flex-1", children: [_jsx("div", { ref: rootRef, role: "textbox", "aria-multiline": multiline || undefined, "aria-label": ariaLabel, "aria-invalid": invalid || undefined, contentEditable: true, suppressContentEditableWarning: true, spellCheck: false, tabIndex: 0, className: cn('bg-background w-full rounded-md border px-2 text-[12px] outline-none', multiline
|
|
221
|
+
? 'min-h-[72px] py-1.5 leading-6 break-words whitespace-pre-wrap'
|
|
222
|
+
: 'h-8 overflow-x-auto leading-[30px] whitespace-nowrap [scrollbar-width:none]', invalid ? 'border-destructive/70' : 'border-border/60', className), onInput: emit, onFocus: () => {
|
|
223
|
+
focusedRef.current = true;
|
|
224
|
+
onFocus?.();
|
|
225
|
+
}, onBlur: () => {
|
|
226
|
+
focusedRef.current = false;
|
|
227
|
+
onBlur?.();
|
|
228
|
+
}, onKeyUp: () => onSelect?.(), onClick: (event) => {
|
|
229
|
+
// A contenteditable host is not labelable, so inside a <label> the
|
|
230
|
+
// label's implicit control is some other element (e.g. a trailing
|
|
231
|
+
// insert button) and the click's default activation would move focus
|
|
232
|
+
// there. Cancel it; the caret was already placed on mousedown.
|
|
233
|
+
event.preventDefault();
|
|
234
|
+
const target = event.target;
|
|
235
|
+
const removeButton = target.closest('[data-chip-remove]');
|
|
236
|
+
if (removeButton) {
|
|
237
|
+
const chip = removeButton.closest('[data-raw]');
|
|
238
|
+
const root = rootRef.current;
|
|
239
|
+
if (chip && root) {
|
|
240
|
+
chip.remove();
|
|
241
|
+
const next = serialize(root);
|
|
242
|
+
renderedRef.current = { value: next, key: renderedRef.current?.key ?? '' };
|
|
243
|
+
onChange(next);
|
|
244
|
+
}
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
onSelect?.();
|
|
248
|
+
}, onPaste: (event) => {
|
|
249
|
+
event.preventDefault();
|
|
250
|
+
const text = event.clipboardData.getData('text/plain');
|
|
251
|
+
const root = rootRef.current;
|
|
252
|
+
if (!root || !text)
|
|
253
|
+
return;
|
|
254
|
+
insertPlainText(root, multiline ? text : text.replace(/\n+/g, ' '));
|
|
255
|
+
emit();
|
|
256
|
+
}, onKeyDown: (event) => {
|
|
257
|
+
if (event.key === 'Enter') {
|
|
258
|
+
event.preventDefault();
|
|
259
|
+
if (multiline) {
|
|
260
|
+
const root = rootRef.current;
|
|
261
|
+
if (root) {
|
|
262
|
+
insertPlainText(root, '\n');
|
|
263
|
+
emit();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
onKeyDown?.(event);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
onKeyDown?.(event);
|
|
270
|
+
} }), value === '' && placeholder ? (_jsx("span", { "aria-hidden": true, className: cn('text-muted-foreground/70 pointer-events-none absolute inset-x-0 top-0 truncate px-2 text-[12px]', multiline ? 'py-1.5 leading-6' : 'leading-[30px]'), children: placeholder })) : null] }));
|
|
271
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type KeyboardEvent, type MutableRefObject } from 'react';
|
|
2
|
+
export type TemplateToken = {
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
valid: boolean;
|
|
6
|
+
label?: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
};
|
|
9
|
+
export type TemplateInputProps = {
|
|
10
|
+
value: string;
|
|
11
|
+
onChange: (value: string) => void;
|
|
12
|
+
tokens?: ReadonlyArray<TemplateToken>;
|
|
13
|
+
multiline?: boolean;
|
|
14
|
+
placeholder?: string;
|
|
15
|
+
invalid?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
onFocus?: () => void;
|
|
18
|
+
onBlur?: () => void;
|
|
19
|
+
onSelect?: () => void;
|
|
20
|
+
onKeyDown?: (event: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
21
|
+
controlRef?: MutableRefObject<HTMLInputElement | HTMLTextAreaElement | null>;
|
|
22
|
+
'aria-label'?: string;
|
|
23
|
+
};
|
|
24
|
+
export declare function TemplateInput({ value, onChange, tokens, multiline, placeholder, invalid, className, onFocus, onBlur, onSelect, onKeyDown, controlRef, 'aria-label': ariaLabel, }: TemplateInputProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, } from 'react';
|
|
4
|
+
import { cn } from '../lib/cn.js';
|
|
5
|
+
function segments(value, tokens) {
|
|
6
|
+
const out = [];
|
|
7
|
+
let cursor = 0;
|
|
8
|
+
tokens.forEach((token, i) => {
|
|
9
|
+
if (token.start > cursor)
|
|
10
|
+
out.push(value.slice(cursor, token.start));
|
|
11
|
+
out.push(_jsx("mark", { title: token.title, className: cn('rounded-[3px] box-decoration-clone', token.valid
|
|
12
|
+
? 'bg-primary/12 text-primary'
|
|
13
|
+
: 'bg-destructive/10 text-destructive decoration-destructive/50 underline decoration-wavy underline-offset-2'), children: value.slice(token.start, token.end) }, i));
|
|
14
|
+
cursor = token.end;
|
|
15
|
+
});
|
|
16
|
+
if (cursor < value.length)
|
|
17
|
+
out.push(value.slice(cursor));
|
|
18
|
+
if (value.endsWith('\n'))
|
|
19
|
+
out.push(' ');
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
22
|
+
export function TemplateInput({ value, onChange, tokens = [], multiline, placeholder, invalid, className, onFocus, onBlur, onSelect, onKeyDown, controlRef, 'aria-label': ariaLabel, }) {
|
|
23
|
+
const backdropRef = useRef(null);
|
|
24
|
+
const syncScroll = (el) => {
|
|
25
|
+
const backdrop = backdropRef.current;
|
|
26
|
+
if (!backdrop)
|
|
27
|
+
return;
|
|
28
|
+
backdrop.scrollLeft = el.scrollLeft;
|
|
29
|
+
backdrop.scrollTop = el.scrollTop;
|
|
30
|
+
};
|
|
31
|
+
const metrics = cn('w-full rounded-md border px-2 text-[12px]', multiline
|
|
32
|
+
? 'min-h-[72px] resize-none py-1.5 font-mono text-[11px] leading-4'
|
|
33
|
+
: 'h-8 leading-[30px]');
|
|
34
|
+
const controlStyle = { color: 'transparent', caretColor: 'var(--foreground)' };
|
|
35
|
+
const setControl = (el) => {
|
|
36
|
+
if (controlRef)
|
|
37
|
+
controlRef.current = el;
|
|
38
|
+
};
|
|
39
|
+
const shared = {
|
|
40
|
+
value,
|
|
41
|
+
placeholder,
|
|
42
|
+
'aria-label': ariaLabel,
|
|
43
|
+
onFocus,
|
|
44
|
+
onBlur,
|
|
45
|
+
onSelect,
|
|
46
|
+
onKeyDown,
|
|
47
|
+
style: controlStyle,
|
|
48
|
+
className: cn(metrics, 'bg-background placeholder:text-muted-foreground/70 relative', invalid ? 'border-destructive/70' : 'border-border/60', className),
|
|
49
|
+
};
|
|
50
|
+
return (_jsxs("div", { className: "relative", children: [multiline ? (_jsx("textarea", { ...shared, ref: setControl, onChange: (e) => {
|
|
51
|
+
onChange(e.currentTarget.value);
|
|
52
|
+
syncScroll(e.currentTarget);
|
|
53
|
+
}, onScroll: (e) => syncScroll(e.currentTarget) })) : (_jsx("input", { ...shared, ref: setControl, onChange: (e) => {
|
|
54
|
+
onChange(e.currentTarget.value);
|
|
55
|
+
syncScroll(e.currentTarget);
|
|
56
|
+
}, onScroll: (e) => syncScroll(e.currentTarget) })), _jsx("div", { ref: backdropRef, "aria-hidden": true, className: cn(metrics, 'text-foreground pointer-events-none absolute inset-0 overflow-hidden border-transparent', multiline ? 'break-words whitespace-pre-wrap' : 'whitespace-pre', className), children: segments(value, tokens) })] }));
|
|
57
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type JSX } from 'react';
|
|
2
|
+
export type TerminalSpinnerTone = 'neutral' | 'accent' | 'muted';
|
|
3
|
+
export interface TerminalSpinnerProps {
|
|
4
|
+
fps?: number;
|
|
5
|
+
tone?: TerminalSpinnerTone;
|
|
6
|
+
ariaLabel?: string;
|
|
7
|
+
status?: string;
|
|
8
|
+
rotateMs?: number;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function TerminalSpinner({ fps, tone, ariaLabel, className, }: TerminalSpinnerProps): JSX.Element;
|