@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,25 @@
|
|
|
1
|
+
export type StickyNoteColor = 'yellow' | 'blue' | 'green' | 'rose';
|
|
2
|
+
export type StickyNote = {
|
|
3
|
+
id: string;
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
text: string;
|
|
7
|
+
color?: StickyNoteColor;
|
|
8
|
+
};
|
|
9
|
+
export declare const STICKY_NOTE_COLORS: StickyNoteColor[];
|
|
10
|
+
export type StickyNoteLabels = {
|
|
11
|
+
body: string;
|
|
12
|
+
placeholder: string;
|
|
13
|
+
delete: string;
|
|
14
|
+
color: (color: StickyNoteColor) => string;
|
|
15
|
+
};
|
|
16
|
+
export type StickyNotesController = {
|
|
17
|
+
annotations: StickyNote[];
|
|
18
|
+
updateAnnotation: (id: string, patch: Partial<StickyNote>) => void;
|
|
19
|
+
commitAnnotation: (id: string, patch: Partial<StickyNote>) => void;
|
|
20
|
+
removeAnnotation: (id: string) => void;
|
|
21
|
+
};
|
|
22
|
+
export declare function StickyNotesLayer({ controller, labels, }: {
|
|
23
|
+
controller: StickyNotesController;
|
|
24
|
+
labels: StickyNoteLabels;
|
|
25
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { useViewport } from 'reactflow';
|
|
5
|
+
import { Trash2 } from 'lucide-react';
|
|
6
|
+
import { cn } from '../../lib/cn.js';
|
|
7
|
+
export const STICKY_NOTE_COLORS = ['yellow', 'blue', 'green', 'rose'];
|
|
8
|
+
const NOTE_COLOR_CLASS = {
|
|
9
|
+
yellow: 'border-amber-300/70 bg-amber-100 text-amber-950 dark:border-amber-400/30 dark:bg-amber-400/15 dark:text-amber-50',
|
|
10
|
+
blue: 'border-sky-300/70 bg-sky-100 text-sky-950 dark:border-sky-400/30 dark:bg-sky-400/15 dark:text-sky-50',
|
|
11
|
+
green: 'border-emerald-300/70 bg-emerald-100 text-emerald-950 dark:border-emerald-400/30 dark:bg-emerald-400/15 dark:text-emerald-50',
|
|
12
|
+
rose: 'border-rose-300/70 bg-rose-100 text-rose-950 dark:border-rose-400/30 dark:bg-rose-400/15 dark:text-rose-50',
|
|
13
|
+
};
|
|
14
|
+
const NOTE_TEXT_COMMIT_MS = 400;
|
|
15
|
+
export function StickyNotesLayer({ controller, labels, }) {
|
|
16
|
+
const viewport = useViewport();
|
|
17
|
+
return (_jsx("div", { className: "pointer-events-none absolute inset-0 z-10", children: controller.annotations.map((annotation) => (_jsx(StickyNoteCard, { annotation: annotation, viewport: viewport, labels: labels, onUpdate: controller.updateAnnotation, onCommit: controller.commitAnnotation, onRemove: controller.removeAnnotation }, annotation.id))) }));
|
|
18
|
+
}
|
|
19
|
+
function StickyNoteCard({ annotation, viewport, labels, onUpdate, onCommit, onRemove, }) {
|
|
20
|
+
const [dragPos, setDragPos] = useState(null);
|
|
21
|
+
const textAreaRef = useRef(null);
|
|
22
|
+
const textTimerRef = useRef(null);
|
|
23
|
+
const pendingTextRef = useRef(null);
|
|
24
|
+
const dirtyTextRef = useRef(false);
|
|
25
|
+
const flushText = useCallback(() => {
|
|
26
|
+
if (textTimerRef.current) {
|
|
27
|
+
clearTimeout(textTimerRef.current);
|
|
28
|
+
textTimerRef.current = null;
|
|
29
|
+
}
|
|
30
|
+
if (pendingTextRef.current !== null) {
|
|
31
|
+
onUpdate(annotation.id, { text: pendingTextRef.current });
|
|
32
|
+
pendingTextRef.current = null;
|
|
33
|
+
dirtyTextRef.current = false;
|
|
34
|
+
}
|
|
35
|
+
}, [annotation.id, onUpdate]);
|
|
36
|
+
useEffect(() => () => flushText(), [flushText]);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const textArea = textAreaRef.current;
|
|
39
|
+
if (!textArea || dirtyTextRef.current || textArea.value === annotation.text)
|
|
40
|
+
return;
|
|
41
|
+
textArea.value = annotation.text;
|
|
42
|
+
}, [annotation.text]);
|
|
43
|
+
const handleTextChange = (value) => {
|
|
44
|
+
dirtyTextRef.current = true;
|
|
45
|
+
pendingTextRef.current = value;
|
|
46
|
+
if (textTimerRef.current)
|
|
47
|
+
clearTimeout(textTimerRef.current);
|
|
48
|
+
textTimerRef.current = setTimeout(flushText, NOTE_TEXT_COMMIT_MS);
|
|
49
|
+
};
|
|
50
|
+
const handleTextBlur = () => {
|
|
51
|
+
flushText();
|
|
52
|
+
};
|
|
53
|
+
const startDrag = useCallback((event) => {
|
|
54
|
+
const target = event.target;
|
|
55
|
+
if (target?.closest('textarea, button'))
|
|
56
|
+
return;
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
const start = { x: event.clientX, y: event.clientY };
|
|
59
|
+
const origin = { x: annotation.x, y: annotation.y };
|
|
60
|
+
let last = null;
|
|
61
|
+
let frame = null;
|
|
62
|
+
const onMove = (move) => {
|
|
63
|
+
last = {
|
|
64
|
+
x: origin.x + (move.clientX - start.x) / viewport.zoom,
|
|
65
|
+
y: origin.y + (move.clientY - start.y) / viewport.zoom,
|
|
66
|
+
};
|
|
67
|
+
if (frame == null) {
|
|
68
|
+
frame = requestAnimationFrame(() => {
|
|
69
|
+
frame = null;
|
|
70
|
+
setDragPos(last);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const onUp = () => {
|
|
75
|
+
document.removeEventListener('mousemove', onMove);
|
|
76
|
+
document.removeEventListener('mouseup', onUp);
|
|
77
|
+
if (frame != null) {
|
|
78
|
+
cancelAnimationFrame(frame);
|
|
79
|
+
frame = null;
|
|
80
|
+
}
|
|
81
|
+
if (last && (last.x !== origin.x || last.y !== origin.y)) {
|
|
82
|
+
onCommit(annotation.id, { x: last.x, y: last.y });
|
|
83
|
+
}
|
|
84
|
+
setDragPos(null);
|
|
85
|
+
};
|
|
86
|
+
document.addEventListener('mousemove', onMove);
|
|
87
|
+
document.addEventListener('mouseup', onUp);
|
|
88
|
+
}, [annotation.id, annotation.x, annotation.y, onCommit, viewport.zoom]);
|
|
89
|
+
const color = annotation.color ?? 'yellow';
|
|
90
|
+
const pos = dragPos ?? { x: annotation.x, y: annotation.y };
|
|
91
|
+
return (
|
|
92
|
+
// Drag container is a plain div, not a button: a button would make the drag
|
|
93
|
+
// guard's `closest('button')` match the card itself and abort every drag,
|
|
94
|
+
// and nesting a textarea/buttons inside a button is invalid HTML.
|
|
95
|
+
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
|
|
96
|
+
_jsxs("div", { "aria-label": labels.body, className: cn('pointer-events-auto absolute w-52 cursor-grab rounded-md border text-left shadow-sm select-none', NOTE_COLOR_CLASS[color]), style: {
|
|
97
|
+
transform: `translate(${pos.x * viewport.zoom + viewport.x}px, ${pos.y * viewport.zoom + viewport.y}px) scale(${viewport.zoom})`,
|
|
98
|
+
transformOrigin: 'top left',
|
|
99
|
+
}, onMouseDown: startDrag, children: [_jsxs("div", { className: "flex items-center justify-between gap-2 border-b border-current/10 px-2 py-1", children: [_jsx("div", { className: "flex items-center gap-1", children: STICKY_NOTE_COLORS.map((candidate) => (_jsx("button", { type: "button", "aria-label": labels.color(candidate), title: labels.color(candidate), onClick: () => onUpdate(annotation.id, { color: candidate }), className: cn('size-3 rounded-full border border-current/25', candidate === 'yellow' && 'bg-amber-300', candidate === 'blue' && 'bg-sky-300', candidate === 'green' && 'bg-emerald-300', candidate === 'rose' && 'bg-rose-300', color === candidate &&
|
|
100
|
+
'ring-offset-background ring-2 ring-current/35 ring-offset-1') }, candidate))) }), _jsx("button", { type: "button", "aria-label": labels.delete, title: labels.delete, onClick: () => onRemove(annotation.id), className: "inline-flex size-5 items-center justify-center rounded text-current/60 hover:bg-current/10 hover:text-current", children: _jsx(Trash2, { className: "size-3", strokeWidth: 1.8 }) })] }), _jsx("textarea", { ref: textAreaRef, defaultValue: annotation.text, "aria-label": labels.body, placeholder: labels.placeholder, onChange: (event) => handleTextChange(event.currentTarget.value), onBlur: handleTextBlur, className: "block min-h-24 w-full resize-none bg-transparent px-2 py-2 text-[12px] leading-relaxed outline-none placeholder:text-current/45" })] }));
|
|
101
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type CollaborativeConnectionStatus = 'connecting' | 'connected' | 'disconnected';
|
|
2
|
+
export declare function collaborativePresenceColor(id: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* A node a peer is dragging right now, expressed in flow/world coordinates so
|
|
5
|
+
* every viewer projects it through its own viewport. `width`/`height` are the
|
|
6
|
+
* node's measured size (also world units) used to draw the live ghost.
|
|
7
|
+
*/
|
|
8
|
+
export type CollaborativeGraphDrag = {
|
|
9
|
+
nodeId: string;
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
width: number;
|
|
13
|
+
height: number;
|
|
14
|
+
};
|
|
15
|
+
export type CollaborativeGraphPeer = {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
color: string;
|
|
19
|
+
/** Pointer in flow/world coordinates (not container pixels), or null. */
|
|
20
|
+
pointer: {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
} | null;
|
|
24
|
+
selectedNodeIds: string[];
|
|
25
|
+
/** The node this peer is dragging live, or null when idle. */
|
|
26
|
+
drag: CollaborativeGraphDrag | null;
|
|
27
|
+
};
|
|
28
|
+
export declare function parseCollaborativeGraphPeer(fallbackID: string, state: unknown): CollaborativeGraphPeer | null;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const presenceColors = [
|
|
2
|
+
'#2563eb',
|
|
3
|
+
'#7c3aed',
|
|
4
|
+
'#db2777',
|
|
5
|
+
'#dc2626',
|
|
6
|
+
'#ea580c',
|
|
7
|
+
'#16a34a',
|
|
8
|
+
'#0891b2',
|
|
9
|
+
];
|
|
10
|
+
export function collaborativePresenceColor(id) {
|
|
11
|
+
let hash = 0;
|
|
12
|
+
for (let index = 0; index < id.length; index++)
|
|
13
|
+
hash = (hash * 31 + id.charCodeAt(index)) | 0;
|
|
14
|
+
return presenceColors[Math.abs(hash) % presenceColors.length] ?? presenceColors[0];
|
|
15
|
+
}
|
|
16
|
+
export function parseCollaborativeGraphPeer(fallbackID, state) {
|
|
17
|
+
if (!state || typeof state !== 'object' || Array.isArray(state))
|
|
18
|
+
return null;
|
|
19
|
+
const record = state;
|
|
20
|
+
return {
|
|
21
|
+
id: fallbackID,
|
|
22
|
+
name: typeof record.name === 'string' && record.name.trim() ? record.name : fallbackID,
|
|
23
|
+
color: collaborativePresenceColor(fallbackID),
|
|
24
|
+
pointer: parseCollaborativePointer(record.pointer),
|
|
25
|
+
selectedNodeIds: Array.isArray(record.selectedNodeIds)
|
|
26
|
+
? record.selectedNodeIds.filter((value) => typeof value === 'string')
|
|
27
|
+
: [],
|
|
28
|
+
drag: parseCollaborativeDrag(record.drag),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function parseCollaborativeDrag(value) {
|
|
32
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
33
|
+
return null;
|
|
34
|
+
const record = value;
|
|
35
|
+
if (typeof record.nodeId !== 'string' ||
|
|
36
|
+
typeof record.x !== 'number' ||
|
|
37
|
+
typeof record.y !== 'number') {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
nodeId: record.nodeId,
|
|
42
|
+
x: record.x,
|
|
43
|
+
y: record.y,
|
|
44
|
+
width: typeof record.width === 'number' && record.width > 0 ? record.width : 160,
|
|
45
|
+
height: typeof record.height === 'number' && record.height > 0 ? record.height : 44,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function parseCollaborativePointer(value) {
|
|
49
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
50
|
+
return null;
|
|
51
|
+
const record = value;
|
|
52
|
+
return typeof record.x === 'number' && typeof record.y === 'number'
|
|
53
|
+
? { x: record.x, y: record.y }
|
|
54
|
+
: null;
|
|
55
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Edge, Node } from 'reactflow';
|
|
2
|
+
import type * as Y from 'yjs';
|
|
3
|
+
export type CollaborativeYDoc = Y.Doc;
|
|
4
|
+
export type CollaborativeYMap<T = unknown> = Y.Map<T>;
|
|
5
|
+
export type CollaborativeYMapEvent<T = unknown> = Y.YMapEvent<T>;
|
|
6
|
+
export type CollaborativeGraphSnapshot<TNodeData, TEdgeData> = {
|
|
7
|
+
nodes: Node<TNodeData>[];
|
|
8
|
+
edges: Edge<TEdgeData>[];
|
|
9
|
+
};
|
|
10
|
+
export type CollaborativeGraphPatch<TNodeData, TEdgeData> = {
|
|
11
|
+
nodes?: {
|
|
12
|
+
upsert?: Node<TNodeData>[];
|
|
13
|
+
deleteIds?: string[];
|
|
14
|
+
};
|
|
15
|
+
edges?: {
|
|
16
|
+
upsert?: Edge<TEdgeData>[];
|
|
17
|
+
deleteIds?: string[];
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export type CollaborativeCollectionHashes = {
|
|
21
|
+
nodes: Map<string, string>;
|
|
22
|
+
edges: Map<string, string>;
|
|
23
|
+
};
|
|
24
|
+
export type CollaborativeGraphMapNames = {
|
|
25
|
+
nodes: string;
|
|
26
|
+
edges: string;
|
|
27
|
+
};
|
|
28
|
+
export declare function createCollaborativeCollectionHashes(): CollaborativeCollectionHashes;
|
|
29
|
+
export declare function collaborativeEdgeKey<TEdgeData>(edge: Edge<TEdgeData>): string;
|
|
30
|
+
export declare function serializeCollaborativeNode<TNodeData>(node: Node<TNodeData>): Node<TNodeData>;
|
|
31
|
+
export declare function serializeCollaborativeEdge<TEdgeData>(edge: Edge<TEdgeData>): Edge<TEdgeData>;
|
|
32
|
+
export declare function coerceCollaborativeNode<TNodeData>(value: unknown): Node<TNodeData> | null;
|
|
33
|
+
export declare function coerceCollaborativeEdge<TEdgeData>(value: unknown): Edge<TEdgeData> | null;
|
|
34
|
+
export declare function syncCollaborativeCollection<TItem>(map: Y.Map<unknown>, items: readonly TItem[], hashes: Map<string, string>, keyForItem: (item: TItem, index: number) => string): boolean;
|
|
35
|
+
export declare function collaborativePatchFromMapEvent<TItem>(event: Y.YMapEvent<unknown>, map: Y.Map<unknown>, hashes: Map<string, string>, coerce: (value: unknown) => TItem | null, keyForItem: (item: TItem, index: number) => string): {
|
|
36
|
+
upsert?: TItem[];
|
|
37
|
+
deleteIds?: string[];
|
|
38
|
+
};
|
|
39
|
+
export declare function writeCollaborativeGraph<TNodeData, TEdgeData>(doc: Y.Doc, graph: CollaborativeGraphSnapshot<TNodeData, TEdgeData>, mapNames: CollaborativeGraphMapNames, hashes: CollaborativeCollectionHashes): boolean;
|
|
40
|
+
export declare function resetCollaborativeGraphHashes<TNodeData, TEdgeData>(graph: CollaborativeGraphSnapshot<TNodeData, TEdgeData>, hashes: CollaborativeCollectionHashes): void;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
export function createCollaborativeCollectionHashes() {
|
|
2
|
+
return { nodes: new Map(), edges: new Map() };
|
|
3
|
+
}
|
|
4
|
+
export function collaborativeEdgeKey(edge) {
|
|
5
|
+
return (edge.id ||
|
|
6
|
+
`${edge.source}:${edge.sourceHandle ?? ''}->${edge.target}:${edge.targetHandle ?? ''}`);
|
|
7
|
+
}
|
|
8
|
+
export function serializeCollaborativeNode(node) {
|
|
9
|
+
return {
|
|
10
|
+
id: node.id,
|
|
11
|
+
type: node.type ?? 'atmos',
|
|
12
|
+
position: { x: Math.round(node.position.x), y: Math.round(node.position.y) },
|
|
13
|
+
data: structuredClone(node.data),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function serializeCollaborativeEdge(edge) {
|
|
17
|
+
return {
|
|
18
|
+
id: collaborativeEdgeKey(edge),
|
|
19
|
+
source: edge.source,
|
|
20
|
+
target: edge.target,
|
|
21
|
+
type: edge.type ?? 'atmos',
|
|
22
|
+
...(edge.sourceHandle ? { sourceHandle: edge.sourceHandle } : {}),
|
|
23
|
+
...(edge.targetHandle ? { targetHandle: edge.targetHandle } : {}),
|
|
24
|
+
...(edge.data ? { data: structuredClone(edge.data) } : {}),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function coerceCollaborativeNode(value) {
|
|
28
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
29
|
+
return null;
|
|
30
|
+
const record = value;
|
|
31
|
+
if (typeof record.id !== 'string')
|
|
32
|
+
return null;
|
|
33
|
+
if (!record.position || typeof record.position !== 'object' || Array.isArray(record.position)) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const position = record.position;
|
|
37
|
+
if (typeof position.x !== 'number' || typeof position.y !== 'number')
|
|
38
|
+
return null;
|
|
39
|
+
if (!record.data || typeof record.data !== 'object' || Array.isArray(record.data))
|
|
40
|
+
return null;
|
|
41
|
+
return {
|
|
42
|
+
id: record.id,
|
|
43
|
+
type: typeof record.type === 'string' ? record.type : 'atmos',
|
|
44
|
+
position: { x: position.x, y: position.y },
|
|
45
|
+
data: structuredClone(record.data),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function coerceCollaborativeEdge(value) {
|
|
49
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
50
|
+
return null;
|
|
51
|
+
const record = value;
|
|
52
|
+
if (typeof record.source !== 'string' || typeof record.target !== 'string')
|
|
53
|
+
return null;
|
|
54
|
+
const sourceHandle = typeof record.sourceHandle === 'string' ? record.sourceHandle : undefined;
|
|
55
|
+
const targetHandle = typeof record.targetHandle === 'string' ? record.targetHandle : undefined;
|
|
56
|
+
const edge = {
|
|
57
|
+
id: typeof record.id === 'string' && record.id.trim()
|
|
58
|
+
? record.id
|
|
59
|
+
: `${record.source}:${sourceHandle ?? ''}->${record.target}:${targetHandle ?? ''}`,
|
|
60
|
+
source: record.source,
|
|
61
|
+
target: record.target,
|
|
62
|
+
type: typeof record.type === 'string' ? record.type : 'atmos',
|
|
63
|
+
...(sourceHandle ? { sourceHandle } : {}),
|
|
64
|
+
...(targetHandle ? { targetHandle } : {}),
|
|
65
|
+
};
|
|
66
|
+
if (record.data && typeof record.data === 'object' && !Array.isArray(record.data)) {
|
|
67
|
+
edge.data = structuredClone(record.data);
|
|
68
|
+
}
|
|
69
|
+
return edge;
|
|
70
|
+
}
|
|
71
|
+
export function syncCollaborativeCollection(map, items, hashes, keyForItem) {
|
|
72
|
+
let changed = false;
|
|
73
|
+
const nextKeys = new Set();
|
|
74
|
+
items.forEach((item, index) => {
|
|
75
|
+
const key = keyForItem(item, index);
|
|
76
|
+
nextKeys.add(key);
|
|
77
|
+
const serialized = JSON.stringify(item);
|
|
78
|
+
if (hashes.get(key) !== serialized) {
|
|
79
|
+
map.set(key, item);
|
|
80
|
+
hashes.set(key, serialized);
|
|
81
|
+
changed = true;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
for (const key of Array.from(map.keys())) {
|
|
85
|
+
if (nextKeys.has(key))
|
|
86
|
+
continue;
|
|
87
|
+
map.delete(key);
|
|
88
|
+
hashes.delete(key);
|
|
89
|
+
changed = true;
|
|
90
|
+
}
|
|
91
|
+
return changed;
|
|
92
|
+
}
|
|
93
|
+
export function collaborativePatchFromMapEvent(event, map, hashes, coerce, keyForItem) {
|
|
94
|
+
const upsert = [];
|
|
95
|
+
const deleteIds = [];
|
|
96
|
+
for (const [key, change] of event.changes.keys) {
|
|
97
|
+
if (change.action === 'delete') {
|
|
98
|
+
hashes.delete(key);
|
|
99
|
+
deleteIds.push(key);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const item = coerce(map.get(key));
|
|
103
|
+
if (!item)
|
|
104
|
+
continue;
|
|
105
|
+
hashes.set(keyForItem(item, 0), JSON.stringify(item));
|
|
106
|
+
upsert.push(item);
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
...(upsert.length ? { upsert } : {}),
|
|
110
|
+
...(deleteIds.length ? { deleteIds } : {}),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export function writeCollaborativeGraph(doc, graph, mapNames, hashes) {
|
|
114
|
+
const nodes = graph.nodes.map(serializeCollaborativeNode);
|
|
115
|
+
const edges = graph.edges.map(serializeCollaborativeEdge);
|
|
116
|
+
const nodesChanged = syncCollaborativeCollection(doc.getMap(mapNames.nodes), nodes, hashes.nodes, (node) => node.id);
|
|
117
|
+
const edgesChanged = syncCollaborativeCollection(doc.getMap(mapNames.edges), edges, hashes.edges, collaborativeEdgeKey);
|
|
118
|
+
return nodesChanged || edgesChanged;
|
|
119
|
+
}
|
|
120
|
+
export function resetCollaborativeGraphHashes(graph, hashes) {
|
|
121
|
+
resetHashes(hashes.nodes, graph.nodes, (node) => node.id);
|
|
122
|
+
resetHashes(hashes.edges, graph.edges, collaborativeEdgeKey);
|
|
123
|
+
}
|
|
124
|
+
function resetHashes(hashes, items, keyForItem) {
|
|
125
|
+
hashes.clear();
|
|
126
|
+
items.forEach((item, index) => hashes.set(keyForItem(item, index), JSON.stringify(item)));
|
|
127
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from 'react';
|
|
2
|
+
import type { Connection, EdgeProps, Edge as RfEdge, Node as RfNode } from 'reactflow';
|
|
3
|
+
import type { FlowCanvasController } from '../canvas/canvas-frame.js';
|
|
4
|
+
import type { NodeLibraryGroup } from '../canvas/node-library.js';
|
|
5
|
+
import type { MakeNodeDataContext } from './use-dag-editor.js';
|
|
6
|
+
export type FlowEditorIssueSeverity = 'error' | 'warning' | 'info';
|
|
7
|
+
export interface FlowEditorIssue {
|
|
8
|
+
readonly nodeId: string;
|
|
9
|
+
readonly message: string;
|
|
10
|
+
readonly severity?: FlowEditorIssueSeverity;
|
|
11
|
+
}
|
|
12
|
+
export interface FlowAdapterContext {
|
|
13
|
+
readonly workspaceId: string | null | undefined;
|
|
14
|
+
}
|
|
15
|
+
export interface NodeConfigPanelProps<TData> {
|
|
16
|
+
readonly node: RfNode<TData>;
|
|
17
|
+
readonly onChange: (patch: Partial<TData>) => void;
|
|
18
|
+
readonly onClose: () => void;
|
|
19
|
+
}
|
|
20
|
+
export interface SettingsDialogContentProps {
|
|
21
|
+
readonly onClose: () => void;
|
|
22
|
+
}
|
|
23
|
+
export interface FlowMutation<TInput, TResult> {
|
|
24
|
+
readonly mutateAsync: (input: TInput) => Promise<TResult>;
|
|
25
|
+
readonly isPending: boolean;
|
|
26
|
+
}
|
|
27
|
+
export type FlowStickyNotes = Pick<FlowCanvasController, 'annotations' | 'addAnnotation' | 'updateAnnotation' | 'commitAnnotation' | 'removeAnnotation'>;
|
|
28
|
+
export interface FlowDomainAdapter<TData, TEdge, TDef, TSaveInput = unknown, TSaveResult = unknown, TPublishInput = unknown, TPublishResult = unknown> {
|
|
29
|
+
readonly nodeGroups: (ctx: FlowAdapterContext) => NodeLibraryGroup[];
|
|
30
|
+
readonly makeNodeData: (kind: string, title: string, ctx?: MakeNodeDataContext<TData>) => TData;
|
|
31
|
+
readonly cloneNodeData?: (data: TData) => TData;
|
|
32
|
+
readonly stampIdentity?: (nodes: RfNode<TData>[]) => RfNode<TData>[] | null;
|
|
33
|
+
readonly isEntryNode: (node: RfNode<TData>) => boolean;
|
|
34
|
+
readonly isProtected: (node: RfNode<TData>) => boolean;
|
|
35
|
+
readonly isValidConnection?: (connection: Connection, nodes: RfNode<TData>[], edges: RfEdge<TEdge>[]) => boolean;
|
|
36
|
+
readonly NodeComponent: ComponentType<Record<string, unknown>>;
|
|
37
|
+
readonly EdgeComponent: ComponentType<EdgeProps<TEdge>>;
|
|
38
|
+
readonly titleForKind: (kind: string) => string;
|
|
39
|
+
readonly nodeLabel?: (node: RfNode<TData>) => string;
|
|
40
|
+
readonly NodeConfigPanel: ComponentType<NodeConfigPanelProps<TData>>;
|
|
41
|
+
readonly SettingsDialogContent: ComponentType<SettingsDialogContentProps>;
|
|
42
|
+
readonly compile: (nodes: RfNode<TData>[], edges: RfEdge<TEdge>[]) => TDef;
|
|
43
|
+
readonly decode: (def: TDef | null | undefined, layout?: FlowLayoutMap) => {
|
|
44
|
+
nodes: RfNode<TData>[];
|
|
45
|
+
edges: RfEdge<TEdge>[];
|
|
46
|
+
};
|
|
47
|
+
readonly encodeLayout: (nodes: RfNode<TData>[]) => FlowLayoutMap;
|
|
48
|
+
readonly useSave: () => FlowMutation<TSaveInput, TSaveResult>;
|
|
49
|
+
readonly usePublish: () => FlowMutation<TPublishInput, TPublishResult>;
|
|
50
|
+
readonly buildSaveInput: (args: {
|
|
51
|
+
nodes: RfNode<TData>[];
|
|
52
|
+
edges: RfEdge<TEdge>[];
|
|
53
|
+
positionsOnly: boolean;
|
|
54
|
+
}) => TSaveInput;
|
|
55
|
+
readonly buildPublishInput: (saveResult: TSaveResult) => TPublishInput;
|
|
56
|
+
readonly validate: (nodes: RfNode<TData>[], edges: RfEdge<TEdge>[]) => FlowEditorIssue[];
|
|
57
|
+
readonly supportsStickyNotes?: boolean;
|
|
58
|
+
readonly useStickyNotes?: () => FlowStickyNotes;
|
|
59
|
+
readonly toolbarExtras?: (ctx: FlowAdapterContext) => ReactNode;
|
|
60
|
+
}
|
|
61
|
+
export type FlowLayoutMap = Record<string, {
|
|
62
|
+
x: number;
|
|
63
|
+
y: number;
|
|
64
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type FlowEditorCommands = {
|
|
2
|
+
readonly run?: () => void;
|
|
3
|
+
readonly tidy?: () => void;
|
|
4
|
+
readonly addNode?: () => void;
|
|
5
|
+
};
|
|
6
|
+
export type FlowEditorCommandId = keyof FlowEditorCommands;
|
|
7
|
+
export declare function registerFlowEditorCommands(scope: string, commands: FlowEditorCommands): () => void;
|
|
8
|
+
export declare function getFlowEditorCommands(scope: string): FlowEditorCommands;
|
|
9
|
+
export declare function runFlowEditorCommand(scope: string, id: FlowEditorCommandId): void;
|
|
10
|
+
export declare function useFlowEditorCommands(scope: string): FlowEditorCommands;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useSyncExternalStore } from 'react';
|
|
3
|
+
const commandsByScope = new Map();
|
|
4
|
+
const listeners = new Set();
|
|
5
|
+
const emptyCommands = {};
|
|
6
|
+
function notifyListeners() {
|
|
7
|
+
for (const listener of listeners)
|
|
8
|
+
listener();
|
|
9
|
+
}
|
|
10
|
+
export function registerFlowEditorCommands(scope, commands) {
|
|
11
|
+
commandsByScope.set(scope, { ...commandsByScope.get(scope), ...commands });
|
|
12
|
+
notifyListeners();
|
|
13
|
+
return () => {
|
|
14
|
+
const current = commandsByScope.get(scope) ?? emptyCommands;
|
|
15
|
+
const removed = new Set(Object.keys(commands).filter((key) => current[key] === commands[key]));
|
|
16
|
+
const remaining = Object.fromEntries(Object.entries(current).filter(([key]) => !removed.has(key)));
|
|
17
|
+
if (Object.keys(remaining).length === 0)
|
|
18
|
+
commandsByScope.delete(scope);
|
|
19
|
+
else
|
|
20
|
+
commandsByScope.set(scope, remaining);
|
|
21
|
+
notifyListeners();
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function getFlowEditorCommands(scope) {
|
|
25
|
+
return commandsByScope.get(scope) ?? emptyCommands;
|
|
26
|
+
}
|
|
27
|
+
export function runFlowEditorCommand(scope, id) {
|
|
28
|
+
getFlowEditorCommands(scope)[id]?.();
|
|
29
|
+
}
|
|
30
|
+
export function useFlowEditorCommands(scope) {
|
|
31
|
+
return useSyncExternalStore((listener) => {
|
|
32
|
+
listeners.add(listener);
|
|
33
|
+
return () => listeners.delete(listener);
|
|
34
|
+
}, () => getFlowEditorCommands(scope), () => emptyCommands);
|
|
35
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ComponentType } from 'react';
|
|
2
|
+
import type { EdgeProps, NodeTypes } from 'reactflow';
|
|
3
|
+
import type { FlowStickyNotes } from './adapter.js';
|
|
4
|
+
import type { FlowEditorCanvasPresentation } from './flow-editor.js';
|
|
5
|
+
import type { DagEditor } from './use-dag-editor.js';
|
|
6
|
+
export interface FlowDagCanvasProps<TData, TEdge> {
|
|
7
|
+
readonly dag: DagEditor<TData, TEdge>;
|
|
8
|
+
readonly NodeComponent: NodeTypes[string] | ComponentType<Record<string, unknown>>;
|
|
9
|
+
readonly EdgeComponent: ComponentType<EdgeProps<TEdge>>;
|
|
10
|
+
readonly titleForKind: (kind: string) => string;
|
|
11
|
+
readonly renderInsertPicker: FlowEditorCanvasPresentation<TData, TEdge>['renderInsertPicker'];
|
|
12
|
+
readonly renderDropPicker: FlowEditorCanvasPresentation<TData, TEdge>['renderDropPicker'];
|
|
13
|
+
readonly presentation?: FlowEditorCanvasPresentation<TData, TEdge>;
|
|
14
|
+
readonly invalidNodeIds?: ReadonlySet<string>;
|
|
15
|
+
readonly stickyNotes?: FlowStickyNotes | null;
|
|
16
|
+
readonly showStickyNotes?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare function FlowDagCanvas<TData, TEdge>({ dag, NodeComponent, EdgeComponent, titleForKind, renderInsertPicker, renderDropPicker, presentation, invalidNodeIds, stickyNotes, showStickyNotes, }: FlowDagCanvasProps<TData, TEdge>): import("react").JSX.Element;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import { useTranslations } from 'use-intl';
|
|
5
|
+
import { FlowCanvasFrame } from '../canvas/canvas-frame.js';
|
|
6
|
+
import { makeFlowCanvasController } from './make-controller.js';
|
|
7
|
+
export function FlowDagCanvas({ dag, NodeComponent, EdgeComponent, titleForKind, renderInsertPicker, renderDropPicker, presentation = {}, invalidNodeIds, stickyNotes, showStickyNotes = false, }) {
|
|
8
|
+
const tc = useTranslations('flowEditor.canvas');
|
|
9
|
+
const controller = useMemo(() => makeFlowCanvasController(dag, { stickyNotes }), [dag, stickyNotes]);
|
|
10
|
+
const labels = useMemo(() => ({
|
|
11
|
+
modeMove: tc('modeMove'),
|
|
12
|
+
modeSelect: tc('modeSelect'),
|
|
13
|
+
copy: tc('copy'),
|
|
14
|
+
paste: tc('paste'),
|
|
15
|
+
undo: tc('undo'),
|
|
16
|
+
redo: tc('redo'),
|
|
17
|
+
tidy: tc('tidy'),
|
|
18
|
+
addNote: tc('addNote'),
|
|
19
|
+
minimapShow: tc('minimapShow'),
|
|
20
|
+
minimapHide: tc('minimapHide'),
|
|
21
|
+
closePicker: tc('closePicker'),
|
|
22
|
+
stickyNotes: {
|
|
23
|
+
body: tc('stickyNotes.body'),
|
|
24
|
+
placeholder: tc('stickyNotes.placeholder'),
|
|
25
|
+
delete: tc('stickyNotes.delete'),
|
|
26
|
+
color: () => '',
|
|
27
|
+
},
|
|
28
|
+
}), [tc]);
|
|
29
|
+
const nodeTypes = useMemo(() => ({ atmos: NodeComponent }), [NodeComponent]);
|
|
30
|
+
const edgeTypes = useMemo(() => ({ atmos: EdgeComponent }), [EdgeComponent]);
|
|
31
|
+
const { afterCanvas: _afterCanvas, alternateContent: _alternateContent, renderInsertPicker: contributedInsertPicker, renderDropPicker: contributedDropPicker, ...canvasProps } = presentation;
|
|
32
|
+
return (_jsx(FlowCanvasFrame, { ...canvasProps, controller: controller, nodeTypes: nodeTypes, edgeTypes: edgeTypes, labels: labels, titleForKind: titleForKind, invalidNodeIds: invalidNodeIds, showStickyNotes: showStickyNotes, onCopySelection: dag.copy, onPasteSelection: dag.paste, onPaneDrop: (kind, position) => dag.addNodeAt(kind, position), renderInsertPicker: contributedInsertPicker ?? renderInsertPicker ?? (() => null), renderDropPicker: contributedDropPicker ?? renderDropPicker ?? (() => null) }));
|
|
33
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { Edge as RfEdge, Node as RfNode } from 'reactflow';
|
|
3
|
+
import type { DropAddContext, FlowCanvasFrameProps } from '../canvas/canvas-frame.js';
|
|
4
|
+
import type { FlowDomainAdapter } from './adapter.js';
|
|
5
|
+
import { type DagEditor, type EdgeBridgeSpec } from './use-dag-editor.js';
|
|
6
|
+
import type { NodeLibraryGroup } from '../canvas/node-library.js';
|
|
7
|
+
type PickerActions = {
|
|
8
|
+
onPick: (kind: string) => void;
|
|
9
|
+
onClose: () => void;
|
|
10
|
+
};
|
|
11
|
+
type CoreCanvasProps = 'controller' | 'nodeTypes' | 'edgeTypes' | 'labels' | 'titleForKind' | 'renderDropPicker' | 'renderInsertPicker' | 'invalidNodeIds' | 'showStickyNotes' | 'onCopySelection' | 'onPasteSelection' | 'onPaneDrop';
|
|
12
|
+
export type FlowEditorCanvasPresentation<TData, TEdge> = Omit<FlowCanvasFrameProps<TData, TEdge>, CoreCanvasProps> & {
|
|
13
|
+
readonly afterCanvas?: ReactNode;
|
|
14
|
+
readonly alternateContent?: ReactNode;
|
|
15
|
+
readonly renderInsertPicker?: FlowCanvasFrameProps<TData, TEdge>['renderInsertPicker'];
|
|
16
|
+
readonly renderDropPicker?: FlowCanvasFrameProps<TData, TEdge>['renderDropPicker'];
|
|
17
|
+
};
|
|
18
|
+
export interface FlowEditorCanvasContext<TData, TEdge> {
|
|
19
|
+
readonly dag: DagEditor<TData, TEdge>;
|
|
20
|
+
readonly groups: readonly NodeLibraryGroup[];
|
|
21
|
+
readonly invalidNodeIds: ReadonlySet<string>;
|
|
22
|
+
}
|
|
23
|
+
export type UseFlowEditorCanvasPresentation<TData, TEdge> = (context: FlowEditorCanvasContext<TData, TEdge>) => FlowEditorCanvasPresentation<TData, TEdge>;
|
|
24
|
+
export interface FlowEditorProps<TData, TEdge, TDef, TSaveInput, TSaveResult, TPublishInput, TPublishResult> {
|
|
25
|
+
readonly adapter: FlowDomainAdapter<TData, TEdge, TDef, TSaveInput, TSaveResult, TPublishInput, TPublishResult>;
|
|
26
|
+
readonly workspaceId: string | null | undefined;
|
|
27
|
+
readonly initialNodes: RfNode<TData>[];
|
|
28
|
+
readonly initialEdges: RfEdge<TEdge>[];
|
|
29
|
+
readonly settingsTitle: string;
|
|
30
|
+
readonly isNew?: boolean;
|
|
31
|
+
readonly externalDirty?: boolean;
|
|
32
|
+
readonly initiallyUnpublished?: boolean;
|
|
33
|
+
readonly onSaved?: (result: TSaveResult) => void;
|
|
34
|
+
readonly onPublished?: (result: TSaveResult) => void;
|
|
35
|
+
readonly onFirstSave?: (result: TSaveResult) => void;
|
|
36
|
+
readonly onError?: (error: unknown, phase: 'save' | 'publish') => void;
|
|
37
|
+
readonly renderInsertPicker: (edgeId: string, actions: PickerActions) => ReactNode;
|
|
38
|
+
readonly renderDropPicker: (ctx: DropAddContext, actions: PickerActions) => ReactNode;
|
|
39
|
+
readonly dropPickerWidth?: number;
|
|
40
|
+
readonly buildEdge?: (spec: EdgeBridgeSpec<TEdge>) => RfEdge<TEdge>;
|
|
41
|
+
readonly isSingleHandle?: (sourceId: string, handle: string | null, nodes: RfNode<TData>[]) => boolean;
|
|
42
|
+
readonly handleOrderOf?: (sourceId: string, sourceHandle: string | null | undefined, nodes: RfNode<TData>[]) => number | null;
|
|
43
|
+
readonly clipboardKind?: string;
|
|
44
|
+
readonly headingFont?: string;
|
|
45
|
+
readonly testId?: string;
|
|
46
|
+
readonly renderHeaderStart?: () => ReactNode;
|
|
47
|
+
readonly useCanvasPresentation?: UseFlowEditorCanvasPresentation<TData, TEdge>;
|
|
48
|
+
readonly renderSettings?: (args: {
|
|
49
|
+
open: boolean;
|
|
50
|
+
onOpenChange: (open: boolean) => void;
|
|
51
|
+
}) => ReactNode;
|
|
52
|
+
}
|
|
53
|
+
export declare function FlowEditor<TData, TEdge = unknown, TDef = unknown, TSaveInput = unknown, TSaveResult = unknown, TPublishInput = unknown, TPublishResult = unknown>({ adapter, workspaceId, initialNodes, initialEdges, settingsTitle, isNew, externalDirty, initiallyUnpublished, onSaved, onPublished, onFirstSave, onError, renderInsertPicker, renderDropPicker, dropPickerWidth, buildEdge, isSingleHandle, handleOrderOf, clipboardKind, headingFont, testId, renderHeaderStart, useCanvasPresentation, renderSettings, }: FlowEditorProps<TData, TEdge, TDef, TSaveInput, TSaveResult, TPublishInput, TPublishResult>): import("react").JSX.Element;
|
|
54
|
+
export {};
|