@aglyn/besigner-ui 1.0.0-beta.143
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/LICENSE +201 -0
- package/README.md +7 -0
- package/package.json +73 -0
- package/src/besigner.d.ts +88 -0
- package/src/besigner.js +89 -0
- package/src/besigner.js.map +1 -0
- package/src/index.d.ts +17 -0
- package/src/index.js +18 -0
- package/src/index.js.map +1 -0
- package/src/lib/box-styler/box-styler.d.ts +57 -0
- package/src/lib/box-styler/box-styler.js +240 -0
- package/src/lib/box-styler/box-styler.js.map +1 -0
- package/src/lib/box-styler/components/box-diagram.d.ts +89 -0
- package/src/lib/box-styler/components/box-diagram.js +661 -0
- package/src/lib/box-styler/components/box-diagram.js.map +1 -0
- package/src/lib/box-styler/components/legend.d.ts +56 -0
- package/src/lib/box-styler/components/legend.js +130 -0
- package/src/lib/box-styler/components/legend.js.map +1 -0
- package/src/lib/box-styler/components/spacing-editor.d.ts +55 -0
- package/src/lib/box-styler/components/spacing-editor.js +347 -0
- package/src/lib/box-styler/components/spacing-editor.js.map +1 -0
- package/src/lib/box-styler/constants.d.ts +17 -0
- package/src/lib/box-styler/constants.js +30 -0
- package/src/lib/box-styler/constants.js.map +1 -0
- package/src/lib/box-styler/index.d.ts +2 -0
- package/src/lib/box-styler/index.js +4 -0
- package/src/lib/box-styler/index.js.map +1 -0
- package/src/lib/box-styler/region-fills.d.ts +107 -0
- package/src/lib/box-styler/region-fills.js +139 -0
- package/src/lib/box-styler/region-fills.js.map +1 -0
- package/src/lib/box-styler/spacing-value.d.ts +104 -0
- package/src/lib/box-styler/spacing-value.js +223 -0
- package/src/lib/box-styler/spacing-value.js.map +1 -0
- package/src/lib/box-styler/types.d.ts +29 -0
- package/src/lib/box-styler/types.js +18 -0
- package/src/lib/box-styler/types.js.map +1 -0
- package/src/lib/components/accordion-list.component.d.ts +50 -0
- package/src/lib/components/accordion-list.component.js +228 -0
- package/src/lib/components/accordion-list.component.js.map +1 -0
- package/src/lib/components/add-controls.component.d.ts +22 -0
- package/src/lib/components/add-controls.component.js +50 -0
- package/src/lib/components/add-controls.component.js.map +1 -0
- package/src/lib/components/app-bar-breadcrumbs.component.d.ts +29 -0
- package/src/lib/components/app-bar-breadcrumbs.component.js +279 -0
- package/src/lib/components/app-bar-breadcrumbs.component.js.map +1 -0
- package/src/lib/components/app-bar-primary.component.d.ts +21 -0
- package/src/lib/components/app-bar-primary.component.js +108 -0
- package/src/lib/components/app-bar-primary.component.js.map +1 -0
- package/src/lib/components/app-bar-secondary.component.d.ts +21 -0
- package/src/lib/components/app-bar-secondary.component.js +94 -0
- package/src/lib/components/app-bar-secondary.component.js.map +1 -0
- package/src/lib/components/aside-panel.component.d.ts +23 -0
- package/src/lib/components/aside-panel.component.js +505 -0
- package/src/lib/components/aside-panel.component.js.map +1 -0
- package/src/lib/components/besigner-conflict-alert.component.d.ts +36 -0
- package/src/lib/components/besigner-conflict-alert.component.js +51 -0
- package/src/lib/components/besigner-conflict-alert.component.js.map +1 -0
- package/src/lib/components/besigner-dnd-context.component.d.ts +32 -0
- package/src/lib/components/besigner-dnd-context.component.js +75 -0
- package/src/lib/components/besigner-dnd-context.component.js.map +1 -0
- package/src/lib/components/besigner-draft-alert.component.d.ts +70 -0
- package/src/lib/components/besigner-draft-alert.component.js +155 -0
- package/src/lib/components/besigner-draft-alert.component.js.map +1 -0
- package/src/lib/components/besigner-root-provider.component.d.ts +33 -0
- package/src/lib/components/besigner-root-provider.component.js +68 -0
- package/src/lib/components/besigner-root-provider.component.js.map +1 -0
- package/src/lib/components/binding-preview-controls.component.d.ts +28 -0
- package/src/lib/components/binding-preview-controls.component.js +63 -0
- package/src/lib/components/binding-preview-controls.component.js.map +1 -0
- package/src/lib/components/closeable-drawer.component.d.ts +32 -0
- package/src/lib/components/closeable-drawer.component.js +134 -0
- package/src/lib/components/closeable-drawer.component.js.map +1 -0
- package/src/lib/components/component-accordion-list.d.ts +28 -0
- package/src/lib/components/component-accordion-list.js +205 -0
- package/src/lib/components/component-accordion-list.js.map +1 -0
- package/src/lib/components/component-icon.component.d.ts +32 -0
- package/src/lib/components/component-icon.component.js +51 -0
- package/src/lib/components/component-icon.component.js.map +1 -0
- package/src/lib/components/component-picker.d.ts +27 -0
- package/src/lib/components/component-picker.js +368 -0
- package/src/lib/components/component-picker.js.map +1 -0
- package/src/lib/components/components-grid-list.component.d.ts +31 -0
- package/src/lib/components/components-grid-list.component.js +162 -0
- package/src/lib/components/components-grid-list.component.js.map +1 -0
- package/src/lib/components/custom-css-form.component.d.ts +115 -0
- package/src/lib/components/custom-css-form.component.js +699 -0
- package/src/lib/components/custom-css-form.component.js.map +1 -0
- package/src/lib/components/device-preview-controls.component.d.ts +22 -0
- package/src/lib/components/device-preview-controls.component.js +150 -0
- package/src/lib/components/device-preview-controls.component.js.map +1 -0
- package/src/lib/components/dnd/canvas-drop-indicator.d.ts +20 -0
- package/src/lib/components/dnd/canvas-drop-indicator.js +61 -0
- package/src/lib/components/dnd/canvas-drop-indicator.js.map +1 -0
- package/src/lib/components/dnd/draggable-droppable.d.ts +31 -0
- package/src/lib/components/dnd/draggable-droppable.js +383 -0
- package/src/lib/components/dnd/draggable-droppable.js.map +1 -0
- package/src/lib/components/dnd/draggable.d.ts +42 -0
- package/src/lib/components/dnd/draggable.js +66 -0
- package/src/lib/components/dnd/draggable.js.map +1 -0
- package/src/lib/components/dnd/drop-indicator.d.ts +31 -0
- package/src/lib/components/dnd/drop-indicator.js +139 -0
- package/src/lib/components/dnd/drop-indicator.js.map +1 -0
- package/src/lib/components/dnd/droppable.d.ts +43 -0
- package/src/lib/components/dnd/droppable.js +63 -0
- package/src/lib/components/dnd/droppable.js.map +1 -0
- package/src/lib/components/element-card.component.d.ts +23 -0
- package/src/lib/components/element-card.component.js +49 -0
- package/src/lib/components/element-card.component.js.map +1 -0
- package/src/lib/components/element-classes-field.component.d.ts +41 -0
- package/src/lib/components/element-classes-field.component.js +140 -0
- package/src/lib/components/element-classes-field.component.js.map +1 -0
- package/src/lib/components/element-detail-overlay.component.d.ts +55 -0
- package/src/lib/components/element-detail-overlay.component.js +157 -0
- package/src/lib/components/element-detail-overlay.component.js.map +1 -0
- package/src/lib/components/element-detail.component.d.ts +56 -0
- package/src/lib/components/element-detail.component.js +171 -0
- package/src/lib/components/element-detail.component.js.map +1 -0
- package/src/lib/components/element-info-details.component.d.ts +18 -0
- package/src/lib/components/element-info-details.component.js +169 -0
- package/src/lib/components/element-info-details.component.js.map +1 -0
- package/src/lib/components/element-interactions-form.component.d.ts +21 -0
- package/src/lib/components/element-interactions-form.component.js +199 -0
- package/src/lib/components/element-interactions-form.component.js.map +1 -0
- package/src/lib/components/element-preview.component.d.ts +75 -0
- package/src/lib/components/element-preview.component.js +346 -0
- package/src/lib/components/element-preview.component.js.map +1 -0
- package/src/lib/components/element-props-form.component.d.ts +565 -0
- package/src/lib/components/element-props-form.component.js +2392 -0
- package/src/lib/components/element-props-form.component.js.map +1 -0
- package/src/lib/components/element-styles-form-template.component.d.ts +27 -0
- package/src/lib/components/element-styles-form-template.component.js +89 -0
- package/src/lib/components/element-styles-form-template.component.js.map +1 -0
- package/src/lib/components/element-styles-form.component.d.ts +52 -0
- package/src/lib/components/element-styles-form.component.js +1350 -0
- package/src/lib/components/element-styles-form.component.js.map +1 -0
- package/src/lib/components/empty-document-slot.d.ts +39 -0
- package/src/lib/components/empty-document-slot.js +121 -0
- package/src/lib/components/empty-document-slot.js.map +1 -0
- package/src/lib/components/empty-results.d.ts +22 -0
- package/src/lib/components/empty-results.js +131 -0
- package/src/lib/components/empty-results.js.map +1 -0
- package/src/lib/components/history-controls.component.d.ts +21 -0
- package/src/lib/components/history-controls.component.js +67 -0
- package/src/lib/components/history-controls.component.js.map +1 -0
- package/src/lib/components/inline-markdown-editor.component.d.ts +17 -0
- package/src/lib/components/inline-markdown-editor.component.js +220 -0
- package/src/lib/components/inline-markdown-editor.component.js.map +1 -0
- package/src/lib/components/inline-text-editor.component.d.ts +48 -0
- package/src/lib/components/inline-text-editor.component.js +905 -0
- package/src/lib/components/inline-text-editor.component.js.map +1 -0
- package/src/lib/components/insert-token-menu.component.d.ts +86 -0
- package/src/lib/components/insert-token-menu.component.js +232 -0
- package/src/lib/components/insert-token-menu.component.js.map +1 -0
- package/src/lib/components/instance-attr-overrides.component.d.ts +50 -0
- package/src/lib/components/instance-attr-overrides.component.js +298 -0
- package/src/lib/components/instance-attr-overrides.component.js.map +1 -0
- package/src/lib/components/interact-controls.component.d.ts +22 -0
- package/src/lib/components/interact-controls.component.js +74 -0
- package/src/lib/components/interact-controls.component.js.map +1 -0
- package/src/lib/components/markdown-attribute-field.component.d.ts +40 -0
- package/src/lib/components/markdown-attribute-field.component.js +103 -0
- package/src/lib/components/markdown-attribute-field.component.js.map +1 -0
- package/src/lib/components/node-card.d.ts +24 -0
- package/src/lib/components/node-card.js +86 -0
- package/src/lib/components/node-card.js.map +1 -0
- package/src/lib/components/node-context-menu.d.ts +25 -0
- package/src/lib/components/node-context-menu.js +558 -0
- package/src/lib/components/node-context-menu.js.map +1 -0
- package/src/lib/components/node-leaf.d.ts +39 -0
- package/src/lib/components/node-leaf.js +628 -0
- package/src/lib/components/node-leaf.js.map +1 -0
- package/src/lib/components/node-outline.d.ts +24 -0
- package/src/lib/components/node-outline.js +156 -0
- package/src/lib/components/node-outline.js.map +1 -0
- package/src/lib/components/node-overlay.d.ts +23 -0
- package/src/lib/components/node-overlay.js +299 -0
- package/src/lib/components/node-overlay.js.map +1 -0
- package/src/lib/components/node-quick-actions.d.ts +24 -0
- package/src/lib/components/node-quick-actions.js +284 -0
- package/src/lib/components/node-quick-actions.js.map +1 -0
- package/src/lib/components/node-tree-view.d.ts +106 -0
- package/src/lib/components/node-tree-view.js +820 -0
- package/src/lib/components/node-tree-view.js.map +1 -0
- package/src/lib/components/panel-controls.component.d.ts +22 -0
- package/src/lib/components/panel-controls.component.js +76 -0
- package/src/lib/components/panel-controls.component.js.map +1 -0
- package/src/lib/components/picker-search-field.d.ts +38 -0
- package/src/lib/components/picker-search-field.js +79 -0
- package/src/lib/components/picker-search-field.js.map +1 -0
- package/src/lib/components/plugin-settings-field.component.d.ts +38 -0
- package/src/lib/components/plugin-settings-field.component.js +264 -0
- package/src/lib/components/plugin-settings-field.component.js.map +1 -0
- package/src/lib/components/properties-dialog.component.d.ts +22 -0
- package/src/lib/components/properties-dialog.component.js +40 -0
- package/src/lib/components/properties-dialog.component.js.map +1 -0
- package/src/lib/components/property-binding-field.component.d.ts +142 -0
- package/src/lib/components/property-binding-field.component.js +325 -0
- package/src/lib/components/property-binding-field.component.js.map +1 -0
- package/src/lib/components/property-values-form.component.d.ts +43 -0
- package/src/lib/components/property-values-form.component.js +223 -0
- package/src/lib/components/property-values-form.component.js.map +1 -0
- package/src/lib/components/scheme-preview-controls.component.d.ts +26 -0
- package/src/lib/components/scheme-preview-controls.component.js +56 -0
- package/src/lib/components/scheme-preview-controls.component.js.map +1 -0
- package/src/lib/components/screen-link-field.component.d.ts +118 -0
- package/src/lib/components/screen-link-field.component.js +282 -0
- package/src/lib/components/screen-link-field.component.js.map +1 -0
- package/src/lib/components/site-theme-color-tokens-provider.component.d.ts +33 -0
- package/src/lib/components/site-theme-color-tokens-provider.component.js +53 -0
- package/src/lib/components/site-theme-color-tokens-provider.component.js.map +1 -0
- package/src/lib/components/subtree-json-dialog.component.d.ts +46 -0
- package/src/lib/components/subtree-json-dialog.component.js +125 -0
- package/src/lib/components/subtree-json-dialog.component.js.map +1 -0
- package/src/lib/components/token-pill.component.d.ts +51 -0
- package/src/lib/components/token-pill.component.js +164 -0
- package/src/lib/components/token-pill.component.js.map +1 -0
- package/src/lib/components/token-text-field.component.d.ts +146 -0
- package/src/lib/components/token-text-field.component.js +603 -0
- package/src/lib/components/token-text-field.component.js.map +1 -0
- package/src/lib/components/tree/tree-list.d.ts +6 -0
- package/src/lib/components/tree/tree-list.js +108 -0
- package/src/lib/components/tree/tree-list.js.map +1 -0
- package/src/lib/components/viewport-canvas.component.d.ts +23 -0
- package/src/lib/components/viewport-canvas.component.js +128 -0
- package/src/lib/components/viewport-canvas.component.js.map +1 -0
- package/src/lib/components/viewport-frame.component.d.ts +47 -0
- package/src/lib/components/viewport-frame.component.js +332 -0
- package/src/lib/components/viewport-frame.component.js.map +1 -0
- package/src/lib/components/viewport-root.component.d.ts +22 -0
- package/src/lib/components/viewport-root.component.js +112 -0
- package/src/lib/components/viewport-root.component.js.map +1 -0
- package/src/lib/components/viewport-zoom-controls.d.ts +29 -0
- package/src/lib/components/viewport-zoom-controls.js +147 -0
- package/src/lib/components/viewport-zoom-controls.js.map +1 -0
- package/src/lib/components/workspace-editor.component.d.ts +23 -0
- package/src/lib/components/workspace-editor.component.js +191 -0
- package/src/lib/components/workspace-editor.component.js.map +1 -0
- package/src/lib/components/workspace-panel.component.d.ts +28 -0
- package/src/lib/components/workspace-panel.component.js +147 -0
- package/src/lib/components/workspace-panel.component.js.map +1 -0
- package/src/lib/constants/sample-data.d.ts +18 -0
- package/src/lib/constants/sample-data.js +106 -0
- package/src/lib/constants/sample-data.js.map +1 -0
- package/src/lib/constants/shared.d.ts +17 -0
- package/src/lib/constants/shared.js +18 -0
- package/src/lib/constants/shared.js.map +1 -0
- package/src/lib/contexts/besigner-app-context.d.ts +30 -0
- package/src/lib/contexts/besigner-app-context.js +41 -0
- package/src/lib/contexts/besigner-app-context.js.map +1 -0
- package/src/lib/contexts/binding-picker-context.d.ts +78 -0
- package/src/lib/contexts/binding-picker-context.js +21 -0
- package/src/lib/contexts/binding-picker-context.js.map +1 -0
- package/src/lib/contexts/canvas-host-tokens-context.d.ts +49 -0
- package/src/lib/contexts/canvas-host-tokens-context.js +63 -0
- package/src/lib/contexts/canvas-host-tokens-context.js.map +1 -0
- package/src/lib/contexts/canvas-reveal-context.d.ts +32 -0
- package/src/lib/contexts/canvas-reveal-context.js +34 -0
- package/src/lib/contexts/canvas-reveal-context.js.map +1 -0
- package/src/lib/contexts/component-promotion-context.d.ts +89 -0
- package/src/lib/contexts/component-promotion-context.js +21 -0
- package/src/lib/contexts/component-promotion-context.js.map +1 -0
- package/src/lib/contexts/components-drawer-context.provider.d.ts +32 -0
- package/src/lib/contexts/components-drawer-context.provider.js +80 -0
- package/src/lib/contexts/components-drawer-context.provider.js.map +1 -0
- package/src/lib/contexts/element-drawer-context.d.ts +1005 -0
- package/src/lib/contexts/element-drawer-context.js +45 -0
- package/src/lib/contexts/element-drawer-context.js.map +1 -0
- package/src/lib/contexts/inspected-selection.d.ts +32 -0
- package/src/lib/contexts/inspected-selection.js +38 -0
- package/src/lib/contexts/inspected-selection.js.map +1 -0
- package/src/lib/contexts/inspector-extras-context.d.ts +56 -0
- package/src/lib/contexts/inspector-extras-context.js +35 -0
- package/src/lib/contexts/inspector-extras-context.js.map +1 -0
- package/src/lib/contexts/interactions-context.d.ts +99 -0
- package/src/lib/contexts/interactions-context.js +22 -0
- package/src/lib/contexts/interactions-context.js.map +1 -0
- package/src/lib/contexts/layout-chrome-context.d.ts +37 -0
- package/src/lib/contexts/layout-chrome-context.js +75 -0
- package/src/lib/contexts/layout-chrome-context.js.map +1 -0
- package/src/lib/contexts/media-asset-facts-context.d.ts +74 -0
- package/src/lib/contexts/media-asset-facts-context.js +27 -0
- package/src/lib/contexts/media-asset-facts-context.js.map +1 -0
- package/src/lib/contexts/media-picker-context.d.ts +88 -0
- package/src/lib/contexts/media-picker-context.js +21 -0
- package/src/lib/contexts/media-picker-context.js.map +1 -0
- package/src/lib/contexts/rendered-canvas-elements.d.ts +42 -0
- package/src/lib/contexts/rendered-canvas-elements.js +79 -0
- package/src/lib/contexts/rendered-canvas-elements.js.map +1 -0
- package/src/lib/contexts/repeat-record-context.d.ts +38 -0
- package/src/lib/contexts/repeat-record-context.js +21 -0
- package/src/lib/contexts/repeat-record-context.js.map +1 -0
- package/src/lib/contexts/repeat-rows-context.d.ts +53 -0
- package/src/lib/contexts/repeat-rows-context.js +38 -0
- package/src/lib/contexts/repeat-rows-context.js.map +1 -0
- package/src/lib/contexts/toolbar-extras-context.d.ts +31 -0
- package/src/lib/contexts/toolbar-extras-context.js +33 -0
- package/src/lib/contexts/toolbar-extras-context.js.map +1 -0
- package/src/lib/drafts/besigner-draft-store.d.ts +110 -0
- package/src/lib/drafts/besigner-draft-store.js +125 -0
- package/src/lib/drafts/besigner-draft-store.js.map +1 -0
- package/src/lib/drafts/besigner-server-draft.d.ts +130 -0
- package/src/lib/drafts/besigner-server-draft.js +211 -0
- package/src/lib/drafts/besigner-server-draft.js.map +1 -0
- package/src/lib/form-fields/components/shared/inline-form-control.d.ts +32 -0
- package/src/lib/form-fields/components/shared/inline-form-control.js +85 -0
- package/src/lib/form-fields/components/shared/inline-form-control.js.map +1 -0
- package/src/lib/form-fields/components/shared/toggle-button-form-control.d.ts +33 -0
- package/src/lib/form-fields/components/shared/toggle-button-form-control.js +83 -0
- package/src/lib/form-fields/components/shared/toggle-button-form-control.js.map +1 -0
- package/src/lib/form-fields/form-fields.d.ts +20 -0
- package/src/lib/form-fields/form-fields.js +21 -0
- package/src/lib/form-fields/form-fields.js.map +1 -0
- package/src/lib/form-fields/index.d.ts +1 -0
- package/src/lib/form-fields/index.js +3 -0
- package/src/lib/form-fields/index.js.map +1 -0
- package/src/lib/hooks/use-add-element-drawer-callback.d.ts +28 -0
- package/src/lib/hooks/use-add-element-drawer-callback.js +112 -0
- package/src/lib/hooks/use-add-element-drawer-callback.js.map +1 -0
- package/src/lib/hooks/use-aglyn-besigner-flag.d.ts +23 -0
- package/src/lib/hooks/use-aglyn-besigner-flag.js +47 -0
- package/src/lib/hooks/use-aglyn-besigner-flag.js.map +1 -0
- package/src/lib/hooks/use-aglyn-besigner-panel-value.d.ts +23 -0
- package/src/lib/hooks/use-aglyn-besigner-panel-value.js +54 -0
- package/src/lib/hooks/use-aglyn-besigner-panel-value.js.map +1 -0
- package/src/lib/hooks/use-aglyn-besigner-panel.d.ts +23 -0
- package/src/lib/hooks/use-aglyn-besigner-panel.js +47 -0
- package/src/lib/hooks/use-aglyn-besigner-panel.js.map +1 -0
- package/src/lib/hooks/use-anchored-rect.d.ts +68 -0
- package/src/lib/hooks/use-anchored-rect.js +131 -0
- package/src/lib/hooks/use-anchored-rect.js.map +1 -0
- package/src/lib/hooks/use-besigner-app-context.d.ts +18 -0
- package/src/lib/hooks/use-besigner-app-context.js +19 -0
- package/src/lib/hooks/use-besigner-app-context.js.map +1 -0
- package/src/lib/hooks/use-besigner-document.d.ts +309 -0
- package/src/lib/hooks/use-besigner-document.js +500 -0
- package/src/lib/hooks/use-besigner-document.js.map +1 -0
- package/src/lib/hooks/use-besigner-draft.d.ts +209 -0
- package/src/lib/hooks/use-besigner-draft.js +429 -0
- package/src/lib/hooks/use-besigner-draft.js.map +1 -0
- package/src/lib/hooks/use-clipboard-callbacks.d.ts +29 -0
- package/src/lib/hooks/use-clipboard-callbacks.js +82 -0
- package/src/lib/hooks/use-clipboard-callbacks.js.map +1 -0
- package/src/lib/hooks/use-clipboard-shortcuts.d.ts +52 -0
- package/src/lib/hooks/use-clipboard-shortcuts.js +102 -0
- package/src/lib/hooks/use-clipboard-shortcuts.js.map +1 -0
- package/src/lib/hooks/use-component-propagation-notice.d.ts +96 -0
- package/src/lib/hooks/use-component-propagation-notice.js +177 -0
- package/src/lib/hooks/use-component-propagation-notice.js.map +1 -0
- package/src/lib/hooks/use-debounced-commit.d.ts +43 -0
- package/src/lib/hooks/use-debounced-commit.js +88 -0
- package/src/lib/hooks/use-debounced-commit.js.map +1 -0
- package/src/lib/hooks/use-delete-element-callback.d.ts +24 -0
- package/src/lib/hooks/use-delete-element-callback.js +82 -0
- package/src/lib/hooks/use-delete-element-callback.js.map +1 -0
- package/src/lib/hooks/use-detail-hover-intent.d.ts +76 -0
- package/src/lib/hooks/use-detail-hover-intent.js +123 -0
- package/src/lib/hooks/use-detail-hover-intent.js.map +1 -0
- package/src/lib/hooks/use-document-repair-callbacks.d.ts +50 -0
- package/src/lib/hooks/use-document-repair-callbacks.js +237 -0
- package/src/lib/hooks/use-document-repair-callbacks.js.map +1 -0
- package/src/lib/hooks/use-insert-token-options.d.ts +52 -0
- package/src/lib/hooks/use-insert-token-options.js +230 -0
- package/src/lib/hooks/use-insert-token-options.js.map +1 -0
- package/src/lib/hooks/use-leaf-drag.d.ts +24 -0
- package/src/lib/hooks/use-leaf-drag.js +28 -0
- package/src/lib/hooks/use-leaf-drag.js.map +1 -0
- package/src/lib/hooks/use-leaf-drop.d.ts +31 -0
- package/src/lib/hooks/use-leaf-drop.js +43 -0
- package/src/lib/hooks/use-leaf-drop.js.map +1 -0
- package/src/lib/hooks/use-markdown-media-picker.d.ts +63 -0
- package/src/lib/hooks/use-markdown-media-picker.js +110 -0
- package/src/lib/hooks/use-markdown-media-picker.js.map +1 -0
- package/src/lib/hooks/use-media-asset-facts-overlay.d.ts +43 -0
- package/src/lib/hooks/use-media-asset-facts-overlay.js +133 -0
- package/src/lib/hooks/use-media-asset-facts-overlay.js.map +1 -0
- package/src/lib/hooks/use-move-node-callbacks.d.ts +22 -0
- package/src/lib/hooks/use-move-node-callbacks.js +57 -0
- package/src/lib/hooks/use-move-node-callbacks.js.map +1 -0
- package/src/lib/hooks/use-node-with-host-tokens.d.ts +42 -0
- package/src/lib/hooks/use-node-with-host-tokens.js +59 -0
- package/src/lib/hooks/use-node-with-host-tokens.js.map +1 -0
- package/src/lib/hooks/use-picker-filter.d.ts +61 -0
- package/src/lib/hooks/use-picker-filter.js +122 -0
- package/src/lib/hooks/use-picker-filter.js.map +1 -0
- package/src/lib/hooks/use-repeat-preview.d.ts +64 -0
- package/src/lib/hooks/use-repeat-preview.js +214 -0
- package/src/lib/hooks/use-repeat-preview.js.map +1 -0
- package/src/lib/hooks/use-repeat-sources.d.ts +17 -0
- package/src/lib/hooks/use-repeat-sources.js +41 -0
- package/src/lib/hooks/use-repeat-sources.js.map +1 -0
- package/src/lib/hooks/use-visible-component-categories.d.ts +37 -0
- package/src/lib/hooks/use-visible-component-categories.js +79 -0
- package/src/lib/hooks/use-visible-component-categories.js.map +1 -0
- package/src/lib/utils/active-host-theme.d.ts +28 -0
- package/src/lib/utils/active-host-theme.js +77 -0
- package/src/lib/utils/active-host-theme.js.map +1 -0
- package/src/lib/utils/attr-target.d.ts +170 -0
- package/src/lib/utils/attr-target.js +229 -0
- package/src/lib/utils/attr-target.js.map +1 -0
- package/src/lib/utils/attribute-field-value.d.ts +21 -0
- package/src/lib/utils/attribute-field-value.js +28 -0
- package/src/lib/utils/attribute-field-value.js.map +1 -0
- package/src/lib/utils/canvas-context-menu.d.ts +28 -0
- package/src/lib/utils/canvas-context-menu.js +56 -0
- package/src/lib/utils/canvas-context-menu.js.map +1 -0
- package/src/lib/utils/canvas-reveal.d.ts +115 -0
- package/src/lib/utils/canvas-reveal.js +165 -0
- package/src/lib/utils/canvas-reveal.js.map +1 -0
- package/src/lib/utils/describe-element.d.ts +72 -0
- package/src/lib/utils/describe-element.js +159 -0
- package/src/lib/utils/describe-element.js.map +1 -0
- package/src/lib/utils/device-preview-styles.d.ts +89 -0
- package/src/lib/utils/device-preview-styles.js +228 -0
- package/src/lib/utils/device-preview-styles.js.map +1 -0
- package/src/lib/utils/docs-help.d.ts +22 -0
- package/src/lib/utils/docs-help.generated.d.ts +47 -0
- package/src/lib/utils/docs-help.generated.js +229 -0
- package/src/lib/utils/docs-help.generated.js.map +1 -0
- package/src/lib/utils/docs-help.js +37 -0
- package/src/lib/utils/docs-help.js.map +1 -0
- package/src/lib/utils/held-answers-store.d.ts +59 -0
- package/src/lib/utils/held-answers-store.js +94 -0
- package/src/lib/utils/held-answers-store.js.map +1 -0
- package/src/lib/utils/in-place-edit-surface.d.ts +118 -0
- package/src/lib/utils/in-place-edit-surface.js +164 -0
- package/src/lib/utils/in-place-edit-surface.js.map +1 -0
- package/src/lib/utils/inline-markdown-edit.store.d.ts +71 -0
- package/src/lib/utils/inline-markdown-edit.store.js +90 -0
- package/src/lib/utils/inline-markdown-edit.store.js.map +1 -0
- package/src/lib/utils/inline-text-edit.store.d.ts +85 -0
- package/src/lib/utils/inline-text-edit.store.js +78 -0
- package/src/lib/utils/inline-text-edit.store.js.map +1 -0
- package/src/lib/utils/instance-leaf-hit.d.ts +39 -0
- package/src/lib/utils/instance-leaf-hit.js +56 -0
- package/src/lib/utils/instance-leaf-hit.js.map +1 -0
- package/src/lib/utils/muted-classes.d.ts +76 -0
- package/src/lib/utils/muted-classes.js +108 -0
- package/src/lib/utils/muted-classes.js.map +1 -0
- package/src/lib/utils/muted-styles.d.ts +125 -0
- package/src/lib/utils/muted-styles.js +193 -0
- package/src/lib/utils/muted-styles.js.map +1 -0
- package/src/lib/utils/numeric-text-value.d.ts +42 -0
- package/src/lib/utils/numeric-text-value.js +47 -0
- package/src/lib/utils/numeric-text-value.js.map +1 -0
- package/src/lib/utils/preset-interactions.d.ts +37 -0
- package/src/lib/utils/preset-interactions.js +87 -0
- package/src/lib/utils/preset-interactions.js.map +1 -0
- package/src/lib/utils/publish-failure-message.d.ts +35 -0
- package/src/lib/utils/publish-failure-message.js +51 -0
- package/src/lib/utils/publish-failure-message.js.map +1 -0
- package/src/lib/utils/rank-picker-results.d.ts +45 -0
- package/src/lib/utils/rank-picker-results.js +136 -0
- package/src/lib/utils/rank-picker-results.js.map +1 -0
- package/src/lib/utils/responsive-sx.d.ts +65 -0
- package/src/lib/utils/responsive-sx.js +129 -0
- package/src/lib/utils/responsive-sx.js.map +1 -0
- package/src/lib/utils/rich-text-commands.d.ts +28 -0
- package/src/lib/utils/rich-text-commands.js +43 -0
- package/src/lib/utils/rich-text-commands.js.map +1 -0
- package/src/lib/utils/sanitize-rich-text.d.ts +52 -0
- package/src/lib/utils/sanitize-rich-text.js +173 -0
- package/src/lib/utils/sanitize-rich-text.js.map +1 -0
- package/src/lib/utils/state-sx.d.ts +255 -0
- package/src/lib/utils/state-sx.js +338 -0
- package/src/lib/utils/state-sx.js.map +1 -0
- package/src/lib/utils/style-field-groups.d.ts +136 -0
- package/src/lib/utils/style-field-groups.js +874 -0
- package/src/lib/utils/style-field-groups.js.map +1 -0
- package/src/lib/utils/style-field-search.d.ts +84 -0
- package/src/lib/utils/style-field-search.js +505 -0
- package/src/lib/utils/style-field-search.js.map +1 -0
- package/src/lib/utils/style-target.d.ts +69 -0
- package/src/lib/utils/style-target.js +203 -0
- package/src/lib/utils/style-target.js.map +1 -0
- package/src/lib/utils/theme-scale-options.d.ts +169 -0
- package/src/lib/utils/theme-scale-options.js +702 -0
- package/src/lib/utils/theme-scale-options.js.map +1 -0
- package/src/lib/utils/token-editable-dom.d.ts +82 -0
- package/src/lib/utils/token-editable-dom.js +280 -0
- package/src/lib/utils/token-editable-dom.js.map +1 -0
- package/src/lib/utils/token-segments.d.ts +111 -0
- package/src/lib/utils/token-segments.js +246 -0
- package/src/lib/utils/token-segments.js.map +1 -0
- package/src/lib/utils/visibility-styles.d.ts +38 -0
- package/src/lib/utils/visibility-styles.js +54 -0
- package/src/lib/utils/visibility-styles.js.map +1 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import type { Firestore } from 'firebase/firestore';
|
|
18
|
+
import { type BesignerDraftIds } from '../drafts/besigner-draft-store';
|
|
19
|
+
/**
|
|
20
|
+
* Trailing debounce on the snapshot. Longer than the AGL-567 attribute
|
|
21
|
+
* debounce because this is disk work, not model work, and nobody is waiting
|
|
22
|
+
* on it: a snapshot one second behind the canvas is still a snapshot.
|
|
23
|
+
*/
|
|
24
|
+
export declare const DRAFT_WRITE_DEBOUNCE_MS = 1000;
|
|
25
|
+
/**
|
|
26
|
+
* …and an upper bound, because a trailing debounce alone never fires during
|
|
27
|
+
* sustained activity. Dragging a section around for two minutes without a
|
|
28
|
+
* one-second pause must not mean two minutes of unprotected work.
|
|
29
|
+
*/
|
|
30
|
+
export declare const DRAFT_WRITE_MAX_WAIT_MS = 15000;
|
|
31
|
+
/**
|
|
32
|
+
* Why a recovered draft may not be put back on the canvas (AGL-2486). Null
|
|
33
|
+
* when restoring is a private act and safe to offer.
|
|
34
|
+
*/
|
|
35
|
+
export type BesignerDraftRestoreBlock =
|
|
36
|
+
/**
|
|
37
|
+
* Someone else SAVED this document after the draft was taken, so the draft
|
|
38
|
+
* predates work that is now in the stored document.
|
|
39
|
+
*
|
|
40
|
+
* The only remaining verdict, and it applies only when this editor is
|
|
41
|
+
* ALONE in the room: every shared case now withholds the whole prompt
|
|
42
|
+
* rather than a button (see `roomIsShared`). A `'live-session'` member
|
|
43
|
+
* used to sit beside this one and became unreachable the moment the
|
|
44
|
+
* signal that produced it also suppressed the offer — so it is gone
|
|
45
|
+
* rather than left as a branch nothing can enter.
|
|
46
|
+
*/
|
|
47
|
+
'saved-since';
|
|
48
|
+
/** Which store an offered draft came from. See `BesignerDraftState.origin`. */
|
|
49
|
+
export type BesignerDraftOrigin = 'browser' | 'shared';
|
|
50
|
+
export interface BesignerDraftState {
|
|
51
|
+
/**
|
|
52
|
+
* Unsaved work from a previous session is on hand and the author has not
|
|
53
|
+
* decided about it yet. Undefined ids (no draft support wired) or no draft
|
|
54
|
+
* both read as false.
|
|
55
|
+
*/
|
|
56
|
+
available: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* When the offered draft was written, per its own store; null when there is
|
|
59
|
+
* no offer, or when the store recorded no time.
|
|
60
|
+
*/
|
|
61
|
+
takenAt: number | null;
|
|
62
|
+
/**
|
|
63
|
+
* The stored document has moved on since the draft was taken — someone
|
|
64
|
+
* else saved while it was stranded (AGL-674).
|
|
65
|
+
*/
|
|
66
|
+
staleAgainstDocument: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* WHERE the offered draft came from, which is the difference between two
|
|
69
|
+
* things the banner used to describe in one voice (AGL-2508).
|
|
70
|
+
*
|
|
71
|
+
* * `browser` — the local crash net. Work that was never saved, held in
|
|
72
|
+
* this browser only, offered back after a reload or a crash.
|
|
73
|
+
* * `shared` — the WORKING DRAFT on the server. The author pressed Save
|
|
74
|
+
* draft, was told it saved, and it did: this is that document coming
|
|
75
|
+
* back, from any browser, for anyone with access.
|
|
76
|
+
*
|
|
77
|
+
* Telling an author their deliberately saved draft was "recovered from
|
|
78
|
+
* this browser" reads as a save that failed and a browser that rescued
|
|
79
|
+
* them. It is the opposite on both counts.
|
|
80
|
+
*/
|
|
81
|
+
origin: BesignerDraftOrigin;
|
|
82
|
+
/**
|
|
83
|
+
* Why {@link restore} is withheld, or null when it is safe to offer
|
|
84
|
+
* (AGL-2486). A blocked restore is a no-op, not merely an unrendered
|
|
85
|
+
* button: the offer and the action have to agree.
|
|
86
|
+
*/
|
|
87
|
+
restoreBlockedBy: BesignerDraftRestoreBlock | null;
|
|
88
|
+
/**
|
|
89
|
+
* A SAVED draft exists that this session has neither opened nor discarded
|
|
90
|
+
* (AGL-2874).
|
|
91
|
+
*
|
|
92
|
+
* True even while the offer is withheld from a shared room, which is why it
|
|
93
|
+
* is not folded into {@link available}: what it protects is the draft, not
|
|
94
|
+
* the prompt. A save or publish from a canvas that never took the draft in
|
|
95
|
+
* must not delete it on the way past.
|
|
96
|
+
*/
|
|
97
|
+
sharedDraftUnopened: boolean;
|
|
98
|
+
/** Puts the draft into the canvas as an undoable, unsaved change. */
|
|
99
|
+
restore: () => void;
|
|
100
|
+
/** Drops the offer and the stored draft. */
|
|
101
|
+
discard: () => void;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* How many OTHER editing sessions are in this room, from the point of view
|
|
105
|
+
* of the recovery prompt — or null while that is not yet known (AGL-2486).
|
|
106
|
+
*
|
|
107
|
+
* Presence is the input, but its statuses do not map onto "am I alone" one
|
|
108
|
+
* for one, and the difference decides whether a person who crashed gets
|
|
109
|
+
* their work back:
|
|
110
|
+
*
|
|
111
|
+
* * `live` — the room is known. However many sessions it holds is the
|
|
112
|
+
* answer, zero included.
|
|
113
|
+
* * `idle` / `connecting` — NOT known yet. Null, so the prompt waits rather
|
|
114
|
+
* than offering a Discard for the second before presence lands.
|
|
115
|
+
* * `unauthorized` / `error` / `unconfigured` — presence cannot answer and
|
|
116
|
+
* never will on this load. Zero, deliberately: a deployment with no
|
|
117
|
+
* Realtime Database has no co-edit mirror either, so there is nothing to
|
|
118
|
+
* have already restored the work, and withholding recovery there would
|
|
119
|
+
* break the crash net for every self-host that never configured presence
|
|
120
|
+
* (`project_self_host_docker_byo_firebase`).
|
|
121
|
+
*/
|
|
122
|
+
export declare function recoverableRoomSessions(status: string, otherSessions: number): number | null;
|
|
123
|
+
export interface UseBesignerDraftOptions {
|
|
124
|
+
/** Omit to disable drafts for this document. */
|
|
125
|
+
ids?: BesignerDraftIds;
|
|
126
|
+
/**
|
|
127
|
+
* Omit to use the local crash net alone (AGL-1152).
|
|
128
|
+
*
|
|
129
|
+
* Given one, the SHARED working draft is consulted too and PREFERRED when
|
|
130
|
+
* both exist. That ordering is the point rather than a tie-break: a local
|
|
131
|
+
* draft is residue from a browser that stopped, while a server draft is work
|
|
132
|
+
* somebody deliberately saved — possibly a colleague, possibly this person
|
|
133
|
+
* on another machine. Offering the crash residue over it would hand back the
|
|
134
|
+
* older of the two and look like data loss.
|
|
135
|
+
*/
|
|
136
|
+
firestore?: Firestore;
|
|
137
|
+
/**
|
|
138
|
+
* True once the stored document has been pushed into the canvas. Nothing
|
|
139
|
+
* is read or written before this: writing earlier would snapshot an empty
|
|
140
|
+
* canvas over a real draft, and reading earlier could not tell "no draft"
|
|
141
|
+
* from "not loaded yet".
|
|
142
|
+
*/
|
|
143
|
+
loaded: boolean;
|
|
144
|
+
/** The canvas differs from the last agreed state. */
|
|
145
|
+
dirty: boolean;
|
|
146
|
+
/** Current stored-document stamp, in `Aglyn.versionStamp` form. */
|
|
147
|
+
storedStamp: string | null;
|
|
148
|
+
/**
|
|
149
|
+
* The stored document's node map, in stored shape (AGL-2874).
|
|
150
|
+
*
|
|
151
|
+
* Lets a draft tell a write that moved the TREE from one that only moved
|
|
152
|
+
* the stamp — a component's declared properties, a version's layout
|
|
153
|
+
* binding. Only the first makes restoring a draft a rollback. Omitted, every
|
|
154
|
+
* stamp change counts, which is the conservative answer.
|
|
155
|
+
*/
|
|
156
|
+
storedNodes?: unknown;
|
|
157
|
+
/**
|
|
158
|
+
* Other live editing sessions in this room, or null while unknown — see
|
|
159
|
+
* {@link recoverableRoomSessions}, which is how a caller with a presence
|
|
160
|
+
* state derives it (AGL-2486).
|
|
161
|
+
*
|
|
162
|
+
* Omitted means ZERO, not unknown: an editor with no presence at all (the
|
|
163
|
+
* system-email besigner has no honest orgId for a room) is a single-player
|
|
164
|
+
* session by construction, and must keep its crash net.
|
|
165
|
+
*/
|
|
166
|
+
roomSessions?: number | null;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Keeps a single local snapshot of unsaved canvas work per document, and
|
|
170
|
+
* offers it back after a crash (AGL-1256).
|
|
171
|
+
*
|
|
172
|
+
* See `besigner-draft-store` for why this is a crash net and not version
|
|
173
|
+
* history — in particular why the draft is destroyed the instant a save
|
|
174
|
+
* succeeds, which is the property that keeps it from being a free stand-in
|
|
175
|
+
* for the paid versioning feature.
|
|
176
|
+
*
|
|
177
|
+
* **Two tabs on one document write one draft key, last writer wins.** That
|
|
178
|
+
* is deliberate: both tabs are editing the same version and the newest
|
|
179
|
+
* unsaved state is the one worth recovering. Nothing here tries to merge
|
|
180
|
+
* them; merging whole node maps is AGL-677's problem, not a crash net's.
|
|
181
|
+
*
|
|
182
|
+
* ## Where this sits next to live co-editing (AGL-2486)
|
|
183
|
+
*
|
|
184
|
+
* There are two "unsaved" states in a besigner editor and they have
|
|
185
|
+
* different scopes, which is why the prompt says "from this browser" out
|
|
186
|
+
* loud:
|
|
187
|
+
*
|
|
188
|
+
* * The **co-edit mirror** (AGL-677) is the SHARED one. It carries unsaved
|
|
189
|
+
* work per node between sessions and replays it to whoever joins, so
|
|
190
|
+
* opening a document someone else is editing already shows their
|
|
191
|
+
* in-progress state — and shows you your own again after a crash, before
|
|
192
|
+
* this prompt is read.
|
|
193
|
+
* * This draft is the PRIVATE one: one snapshot, in one browser, for the
|
|
194
|
+
* case where nothing else survived.
|
|
195
|
+
*
|
|
196
|
+
* They are not merged and this one is not made shareable — the mirror
|
|
197
|
+
* already is that, per node, without a merge of two whole maps.
|
|
198
|
+
*
|
|
199
|
+
* The private snapshot is not OFFERED at all while the room is shared
|
|
200
|
+
* (AGL-2486). Withholding only Restore is not enough: that leaves a prompt
|
|
201
|
+
* whose one remaining button is Discard, standing over work several people
|
|
202
|
+
* are still doing. Recovery is a crash story, a crash means nothing else
|
|
203
|
+
* survived, and a live room is proof that something did. See
|
|
204
|
+
* `roomIsShared` in the body for the two signals that decide it, and
|
|
205
|
+
* {@link BesignerDraftState.restoreBlockedBy} for the narrower verdicts that
|
|
206
|
+
* still apply when this editor is alone.
|
|
207
|
+
*/
|
|
208
|
+
export declare function useBesignerDraft(options: UseBesignerDraftOptions): BesignerDraftState;
|
|
209
|
+
export default useBesignerDraft;
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
17
|
+
import { canvas, hasConcurrentWrite } from "@aglyn/aglyn";
|
|
18
|
+
import isEqual from "lodash-es/isEqual.js";
|
|
19
|
+
import { autorun } from "mobx";
|
|
20
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
21
|
+
import { besignerDraftKey, clearBesignerDraft, pruneBesignerDrafts, readBesignerDraft, writeBesignerDraft } from "../drafts/besigner-draft-store.js";
|
|
22
|
+
import { clearServerDraft, readServerDraft } from "../drafts/besigner-server-draft.js";
|
|
23
|
+
import { useDebouncedCommit } from "./use-debounced-commit.js";
|
|
24
|
+
/**
|
|
25
|
+
* Trailing debounce on the snapshot. Longer than the AGL-567 attribute
|
|
26
|
+
* debounce because this is disk work, not model work, and nobody is waiting
|
|
27
|
+
* on it: a snapshot one second behind the canvas is still a snapshot.
|
|
28
|
+
*/ export const DRAFT_WRITE_DEBOUNCE_MS = 1000;
|
|
29
|
+
/**
|
|
30
|
+
* …and an upper bound, because a trailing debounce alone never fires during
|
|
31
|
+
* sustained activity. Dragging a section around for two minutes without a
|
|
32
|
+
* one-second pause must not mean two minutes of unprotected work.
|
|
33
|
+
*/ export const DRAFT_WRITE_MAX_WAIT_MS = 15000;
|
|
34
|
+
const EMPTY_STATE = {
|
|
35
|
+
available: false,
|
|
36
|
+
takenAt: null,
|
|
37
|
+
staleAgainstDocument: false,
|
|
38
|
+
origin: 'browser',
|
|
39
|
+
restoreBlockedBy: null,
|
|
40
|
+
sharedDraftUnopened: false,
|
|
41
|
+
restore: ()=>undefined,
|
|
42
|
+
discard: ()=>undefined
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* How many OTHER editing sessions are in this room, from the point of view
|
|
46
|
+
* of the recovery prompt — or null while that is not yet known (AGL-2486).
|
|
47
|
+
*
|
|
48
|
+
* Presence is the input, but its statuses do not map onto "am I alone" one
|
|
49
|
+
* for one, and the difference decides whether a person who crashed gets
|
|
50
|
+
* their work back:
|
|
51
|
+
*
|
|
52
|
+
* * `live` — the room is known. However many sessions it holds is the
|
|
53
|
+
* answer, zero included.
|
|
54
|
+
* * `idle` / `connecting` — NOT known yet. Null, so the prompt waits rather
|
|
55
|
+
* than offering a Discard for the second before presence lands.
|
|
56
|
+
* * `unauthorized` / `error` / `unconfigured` — presence cannot answer and
|
|
57
|
+
* never will on this load. Zero, deliberately: a deployment with no
|
|
58
|
+
* Realtime Database has no co-edit mirror either, so there is nothing to
|
|
59
|
+
* have already restored the work, and withholding recovery there would
|
|
60
|
+
* break the crash net for every self-host that never configured presence
|
|
61
|
+
* (`project_self_host_docker_byo_firebase`).
|
|
62
|
+
*/ export function recoverableRoomSessions(status, otherSessions) {
|
|
63
|
+
if (status === 'live') return otherSessions;
|
|
64
|
+
if (status === 'idle' || status === 'connecting') return null;
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Keeps a single local snapshot of unsaved canvas work per document, and
|
|
69
|
+
* offers it back after a crash (AGL-1256).
|
|
70
|
+
*
|
|
71
|
+
* See `besigner-draft-store` for why this is a crash net and not version
|
|
72
|
+
* history — in particular why the draft is destroyed the instant a save
|
|
73
|
+
* succeeds, which is the property that keeps it from being a free stand-in
|
|
74
|
+
* for the paid versioning feature.
|
|
75
|
+
*
|
|
76
|
+
* **Two tabs on one document write one draft key, last writer wins.** That
|
|
77
|
+
* is deliberate: both tabs are editing the same version and the newest
|
|
78
|
+
* unsaved state is the one worth recovering. Nothing here tries to merge
|
|
79
|
+
* them; merging whole node maps is AGL-677's problem, not a crash net's.
|
|
80
|
+
*
|
|
81
|
+
* ## Where this sits next to live co-editing (AGL-2486)
|
|
82
|
+
*
|
|
83
|
+
* There are two "unsaved" states in a besigner editor and they have
|
|
84
|
+
* different scopes, which is why the prompt says "from this browser" out
|
|
85
|
+
* loud:
|
|
86
|
+
*
|
|
87
|
+
* * The **co-edit mirror** (AGL-677) is the SHARED one. It carries unsaved
|
|
88
|
+
* work per node between sessions and replays it to whoever joins, so
|
|
89
|
+
* opening a document someone else is editing already shows their
|
|
90
|
+
* in-progress state — and shows you your own again after a crash, before
|
|
91
|
+
* this prompt is read.
|
|
92
|
+
* * This draft is the PRIVATE one: one snapshot, in one browser, for the
|
|
93
|
+
* case where nothing else survived.
|
|
94
|
+
*
|
|
95
|
+
* They are not merged and this one is not made shareable — the mirror
|
|
96
|
+
* already is that, per node, without a merge of two whole maps.
|
|
97
|
+
*
|
|
98
|
+
* The private snapshot is not OFFERED at all while the room is shared
|
|
99
|
+
* (AGL-2486). Withholding only Restore is not enough: that leaves a prompt
|
|
100
|
+
* whose one remaining button is Discard, standing over work several people
|
|
101
|
+
* are still doing. Recovery is a crash story, a crash means nothing else
|
|
102
|
+
* survived, and a live room is proof that something did. See
|
|
103
|
+
* `roomIsShared` in the body for the two signals that decide it, and
|
|
104
|
+
* {@link BesignerDraftState.restoreBlockedBy} for the narrower verdicts that
|
|
105
|
+
* still apply when this editor is alone.
|
|
106
|
+
*/ export function useBesignerDraft(options) {
|
|
107
|
+
var _sameTreeStampsRef_current;
|
|
108
|
+
const { ids, loaded, dirty, storedStamp, storedNodes, firestore } = options;
|
|
109
|
+
// `??` would fold null into 0 and lose the distinction the whole rule
|
|
110
|
+
// rests on: null is "presence has not answered yet", 0 is "it answered,
|
|
111
|
+
// and you are alone".
|
|
112
|
+
const roomSessions = options.roomSessions === undefined ? 0 : options.roomSessions;
|
|
113
|
+
const key = ids ? besignerDraftKey(ids) : null;
|
|
114
|
+
/** The draft being offered, held in memory for the life of the offer. */ const [offer, setOffer] = useState(null);
|
|
115
|
+
/**
|
|
116
|
+
* Which store {@link offer} came from (AGL-2508). Tracked beside the offer
|
|
117
|
+
* rather than folded into `BesignerDraft`, because the stored shape is what
|
|
118
|
+
* both stores persist and neither one records where it ended up being read
|
|
119
|
+
* from — that is a fact about this load, not about the document.
|
|
120
|
+
*/ const [offerOrigin, setOfferOrigin] = useState('browser');
|
|
121
|
+
/** Guards the read so it happens exactly once per document, before writes. */ const readKeyRef = useRef(null);
|
|
122
|
+
/**
|
|
123
|
+
* The same guard for the SHARED draft, kept apart from the local one
|
|
124
|
+
* because the two become readable at different moments (AGL-2874).
|
|
125
|
+
*
|
|
126
|
+
* An editor passes `firestore` only once its PARENT document has said that
|
|
127
|
+
* this is the live version, and the version document can reach the canvas
|
|
128
|
+
* before that. With one latch for both, the local read takes it and the
|
|
129
|
+
* shared draft is never read that session — no offer, and nothing standing
|
|
130
|
+
* between the draft and a save that overwrites it.
|
|
131
|
+
*/ const serverReadKeyRef = useRef(null);
|
|
132
|
+
const idsRef = useRef(ids);
|
|
133
|
+
idsRef.current = ids;
|
|
134
|
+
const storedStampRef = useRef(storedStamp);
|
|
135
|
+
storedStampRef.current = storedStamp;
|
|
136
|
+
/**
|
|
137
|
+
* Whether this session has ever written the draft slot. Without it the
|
|
138
|
+
* clean-canvas cleanup below would delete the draft it was just offered:
|
|
139
|
+
* a freshly loaded document is clean by definition, so "clean" only means
|
|
140
|
+
* "nothing left to protect" once we have actually put something there.
|
|
141
|
+
*/ const wroteRef = useRef(false);
|
|
142
|
+
const writeDraft = useCallback(()=>{
|
|
143
|
+
const currentIds = idsRef.current;
|
|
144
|
+
if (!currentIds) return;
|
|
145
|
+
wroteRef.current = true;
|
|
146
|
+
// Serialising here rather than in the autorun is the whole point of the
|
|
147
|
+
// debounce: the tracking read is cheap to repeat, `JSON.stringify` of a
|
|
148
|
+
// 200-node map plus a synchronous `setItem` is not (AGL-567).
|
|
149
|
+
const nodes = canvas.toJSON().nodes;
|
|
150
|
+
writeBesignerDraft(currentIds, {
|
|
151
|
+
nodes,
|
|
152
|
+
baseStamp: storedStampRef.current
|
|
153
|
+
});
|
|
154
|
+
}, []);
|
|
155
|
+
const { schedule, flush } = useDebouncedCommit(writeDraft, DRAFT_WRITE_DEBOUNCE_MS, {
|
|
156
|
+
maxWait: DRAFT_WRITE_MAX_WAIT_MS
|
|
157
|
+
});
|
|
158
|
+
// Read the existing draft once the document is in the canvas, and before
|
|
159
|
+
// anything can overwrite it.
|
|
160
|
+
// Keyed on the storage key rather than the ids object: callers build that
|
|
161
|
+
// object inline, so a dependency on it would re-run this on every render.
|
|
162
|
+
useEffect(()=>{
|
|
163
|
+
const currentIds = idsRef.current;
|
|
164
|
+
if (!key || !currentIds || !loaded) return undefined;
|
|
165
|
+
if (readKeyRef.current !== key) {
|
|
166
|
+
var _local_updatedAt;
|
|
167
|
+
readKeyRef.current = key;
|
|
168
|
+
pruneBesignerDrafts();
|
|
169
|
+
const local = readBesignerDraft(currentIds);
|
|
170
|
+
setOffer(local ? {
|
|
171
|
+
nodes: local.nodes,
|
|
172
|
+
baseStamp: local.baseStamp,
|
|
173
|
+
takenAt: (_local_updatedAt = local.updatedAt) != null ? _local_updatedAt : null
|
|
174
|
+
} : null);
|
|
175
|
+
setOfferOrigin('browser');
|
|
176
|
+
}
|
|
177
|
+
// The shared draft answers late, and wins when it answers. It is read at
|
|
178
|
+
// most once per document too, so a slow reply cannot re-offer a draft
|
|
179
|
+
// the author has meanwhile restored or discarded.
|
|
180
|
+
if (!firestore || serverReadKeyRef.current === key) return undefined;
|
|
181
|
+
serverReadKeyRef.current = key;
|
|
182
|
+
let live = true;
|
|
183
|
+
let answered = false;
|
|
184
|
+
void readServerDraft(firestore, currentIds).then((server)=>{
|
|
185
|
+
answered = true;
|
|
186
|
+
if (!live || !server) return;
|
|
187
|
+
setOfferOrigin('shared');
|
|
188
|
+
setOffer({
|
|
189
|
+
nodes: server.nodes,
|
|
190
|
+
baseStamp: server.baseStamp,
|
|
191
|
+
// The server's stamp, so the banner tells the draft's real age.
|
|
192
|
+
// Expiry never reads it: `DRAFT_MAX_AGE_MS` belongs to the crash
|
|
193
|
+
// net, and a saved draft lives until it is published or discarded.
|
|
194
|
+
takenAt: server.updatedAt
|
|
195
|
+
});
|
|
196
|
+
}).catch(()=>{
|
|
197
|
+
answered = true;
|
|
198
|
+
});
|
|
199
|
+
return ()=>{
|
|
200
|
+
live = false;
|
|
201
|
+
// A read torn down before it answered never happened, so the next run
|
|
202
|
+
// asks again rather than finding the latch already taken.
|
|
203
|
+
if (!answered) serverReadKeyRef.current = null;
|
|
204
|
+
};
|
|
205
|
+
}, [
|
|
206
|
+
key,
|
|
207
|
+
loaded,
|
|
208
|
+
firestore
|
|
209
|
+
]);
|
|
210
|
+
// Snapshot on canvas change. `autorun` re-runs whenever anything the
|
|
211
|
+
// tracked read touched changes, and `toJSON()` touches every node — which
|
|
212
|
+
// is the same depth of read the existing `isInitialSame` computed already
|
|
213
|
+
// performs on every change, so this adds a constant factor to a path that
|
|
214
|
+
// is already O(nodes), not a new order of cost.
|
|
215
|
+
useEffect(()=>{
|
|
216
|
+
if (!key || !loaded) return undefined;
|
|
217
|
+
return autorun(()=>{
|
|
218
|
+
canvas.toJSON();
|
|
219
|
+
if (canvas.isInitialSame) return;
|
|
220
|
+
schedule();
|
|
221
|
+
});
|
|
222
|
+
}, [
|
|
223
|
+
key,
|
|
224
|
+
loaded,
|
|
225
|
+
schedule
|
|
226
|
+
]);
|
|
227
|
+
// Returning to the saved state (an undo back to it, or a save landing)
|
|
228
|
+
// means there is no unsaved work left IN THIS BROWSER to protect. Dropping
|
|
229
|
+
// the crash net here is what stops it lingering as a restore point for a
|
|
230
|
+
// document that has moved past it.
|
|
231
|
+
//
|
|
232
|
+
// The SHARED draft is not this effect's to drop (AGL-2874). It is work
|
|
233
|
+
// somebody deliberately saved, and a canvas back at the stored document says
|
|
234
|
+
// nothing about it: edit anything and undo it, and this runs with the shared
|
|
235
|
+
// draft still unopened. Deciding about it belongs to Discard, and to a save
|
|
236
|
+
// or publish of a canvas that took the draft in.
|
|
237
|
+
useEffect(()=>{
|
|
238
|
+
const currentIds = idsRef.current;
|
|
239
|
+
if (!key || !currentIds || !loaded || dirty) return;
|
|
240
|
+
if (!wroteRef.current) return;
|
|
241
|
+
// Flush before clearing, not after: a timer left pending would land
|
|
242
|
+
// *after* the delete and re-create a draft whose content is identical to
|
|
243
|
+
// the saved document — offered on the next load as unsaved work that
|
|
244
|
+
// never existed.
|
|
245
|
+
flush();
|
|
246
|
+
clearBesignerDraft(currentIds);
|
|
247
|
+
wroteRef.current = false;
|
|
248
|
+
}, [
|
|
249
|
+
key,
|
|
250
|
+
loaded,
|
|
251
|
+
dirty,
|
|
252
|
+
flush
|
|
253
|
+
]);
|
|
254
|
+
// A crash is not the only way a tab dies; closing it is the common one,
|
|
255
|
+
// and `pagehide` is the last reliable moment to get the pending snapshot
|
|
256
|
+
// onto disk. `visibilitychange` covers the mobile/background case where
|
|
257
|
+
// `pagehide` may never fire.
|
|
258
|
+
useEffect(()=>{
|
|
259
|
+
if (!key || !loaded) return undefined;
|
|
260
|
+
const flushNow = ()=>{
|
|
261
|
+
if (!canvas.isInitialSame) flush();
|
|
262
|
+
};
|
|
263
|
+
const onVisibility = ()=>{
|
|
264
|
+
if (document.visibilityState === 'hidden') flushNow();
|
|
265
|
+
};
|
|
266
|
+
window.addEventListener('pagehide', flushNow);
|
|
267
|
+
document.addEventListener('visibilitychange', onVisibility);
|
|
268
|
+
return ()=>{
|
|
269
|
+
window.removeEventListener('pagehide', flushNow);
|
|
270
|
+
document.removeEventListener('visibilitychange', onVisibility);
|
|
271
|
+
};
|
|
272
|
+
}, [
|
|
273
|
+
key,
|
|
274
|
+
loaded,
|
|
275
|
+
flush
|
|
276
|
+
]);
|
|
277
|
+
/**
|
|
278
|
+
* A peer's live change is on this canvas. Read OUTSIDE the memo below so
|
|
279
|
+
* the observer that renders the prompt re-runs it when the first remote
|
|
280
|
+
* change lands — a mobx read inside a `useMemo` whose deps never mention
|
|
281
|
+
* it would keep serving the verdict from mount.
|
|
282
|
+
*/ const canvasHasRemoteEdits = canvas.hasRemoteEdits;
|
|
283
|
+
/**
|
|
284
|
+
* Every stamp the stored document has carried this session while its tree
|
|
285
|
+
* stayed exactly as it is now (AGL-2874).
|
|
286
|
+
*
|
|
287
|
+
* A write that leaves `nodes` alone still moves `updatedAt` — declaring a
|
|
288
|
+
* component's properties is one — and a draft judged on the stamp alone
|
|
289
|
+
* becomes unrestorable the moment an author does that, though putting it
|
|
290
|
+
* back could roll nothing back. A draft taken against any stamp in this set
|
|
291
|
+
* is a draft of this very tree. Reset whenever the tree itself changes, so
|
|
292
|
+
* someone else's saved nodes still block it.
|
|
293
|
+
*
|
|
294
|
+
* Kept in a ref and brought up to date during render: the answer has to be
|
|
295
|
+
* right in the same render the new stamp arrives in, or the banner shows a
|
|
296
|
+
* blocked draft for a frame. Adding a stamp twice changes nothing, so a
|
|
297
|
+
* repeated render lands in the same place.
|
|
298
|
+
*/ const sameTreeStampsRef = useRef(undefined);
|
|
299
|
+
if (storedNodes !== undefined && storedStamp) {
|
|
300
|
+
const current = sameTreeStampsRef.current;
|
|
301
|
+
if (!current || current.nodes !== storedNodes && !isEqual(current.nodes, storedNodes)) {
|
|
302
|
+
sameTreeStampsRef.current = {
|
|
303
|
+
nodes: storedNodes,
|
|
304
|
+
stamps: new Set([
|
|
305
|
+
storedStamp
|
|
306
|
+
])
|
|
307
|
+
};
|
|
308
|
+
} else {
|
|
309
|
+
current.nodes = storedNodes;
|
|
310
|
+
current.stamps.add(storedStamp);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const draftOfThisTree = Boolean((offer == null ? void 0 : offer.baseStamp) && ((_sameTreeStampsRef_current = sameTreeStampsRef.current) == null ? void 0 : _sameTreeStampsRef_current.stamps.has(offer.baseStamp)));
|
|
314
|
+
const staleAgainstDocument = Boolean(offer && hasConcurrentWrite(offer.baseStamp, storedStamp) && !draftOfThisTree);
|
|
315
|
+
/**
|
|
316
|
+
* Restoring is a WHOLE-MAP replace, and in a shared session that is not a
|
|
317
|
+
* private act (AGL-2486). Measured on the running editor: a peer created a
|
|
318
|
+
* node, the other session pressed Restore, and the node was deleted on the
|
|
319
|
+
* peer's own screen; with a stale draft the same click reverted a
|
|
320
|
+
* colleague's SAVED work and survived the reload the conflict banner asks
|
|
321
|
+
* for, with Save re-enabled and no warning left on screen.
|
|
322
|
+
*
|
|
323
|
+
* So the offer is withheld rather than merely re-worded. What the author
|
|
324
|
+
* loses by that is small and the mirror mostly covers it: unsaved work in a
|
|
325
|
+
* co-edited room is republished to whoever rejoins, which is how their own
|
|
326
|
+
* changes are already back on the canvas before this prompt is even read.
|
|
327
|
+
* What they would lose by the other choice is someone else's work.
|
|
328
|
+
*/ const restoreBlockedBy = staleAgainstDocument ? 'saved-since' : null;
|
|
329
|
+
/**
|
|
330
|
+
* Whether this room is somebody else's too, i.e. whether the mirror
|
|
331
|
+
* already has the work this prompt is about (AGL-2486).
|
|
332
|
+
*
|
|
333
|
+
* The recovery prompt exists for a CRASH, and a crash is the case where
|
|
334
|
+
* nothing else survived. When something else demonstrably did — a third tab
|
|
335
|
+
* opening onto a document two other tabs are editing unsaved — there is no
|
|
336
|
+
* recovery to offer, and both buttons can only do harm to work that is
|
|
337
|
+
* still in progress.
|
|
338
|
+
*
|
|
339
|
+
* TWO signals, OR'd, because they cover different halves of "the mirror
|
|
340
|
+
* already has this" and neither implies the other:
|
|
341
|
+
*
|
|
342
|
+
* * **Presence membership.** Another session is in the room right now. It
|
|
343
|
+
* may not have published anything since this tab joined — a colleague
|
|
344
|
+
* who is reading rather than typing publishes nothing — but the mirror
|
|
345
|
+
* is live and their unsaved work is in it, so a whole-map replace from
|
|
346
|
+
* an older private snapshot would still be a replace of shared state.
|
|
347
|
+
* * **Mirror-entry presence** (`canvas.hasRemoteEdits`). The mirror has
|
|
348
|
+
* already replayed another session's unsaved work ONTO this canvas.
|
|
349
|
+
* This is the half that catches the room whose other sessions have since
|
|
350
|
+
* closed: their work came back on join, and it is on screen now.
|
|
351
|
+
*
|
|
352
|
+
* Presence alone misses the second; `hasRemoteEdits` alone misses the
|
|
353
|
+
* first, which is any tab that joins a live room before anyone in it types
|
|
354
|
+
* again. Unknown (null) counts as shared until presence says otherwise —
|
|
355
|
+
* the cost of waiting a second is a delayed offer, the cost of guessing
|
|
356
|
+
* wrong is a Discard button over other people's work.
|
|
357
|
+
*
|
|
358
|
+
* What is NOT withheld: a person alone in the room after a browser quit
|
|
359
|
+
* gets the full offer, Restore included. That case is the entire reason
|
|
360
|
+
* the feature exists, and nothing here narrows it.
|
|
361
|
+
*/ const roomIsShared = roomSessions === null || roomSessions > 0 || canvasHasRemoteEdits;
|
|
362
|
+
const restore = useCallback(()=>{
|
|
363
|
+
const draft = offer;
|
|
364
|
+
if (!draft) return;
|
|
365
|
+
// The action agrees with the offer. A component that renders Restore
|
|
366
|
+
// without consulting `restoreBlockedBy` still cannot roll a colleague
|
|
367
|
+
// back through this path.
|
|
368
|
+
if (restoreBlockedBy || roomIsShared) return;
|
|
369
|
+
// `applyNodes` snapshots history first, so restoring is undoable and
|
|
370
|
+
// leaves the canvas dirty. Dirty matters beyond the save button: it is
|
|
371
|
+
// what keeps "Save the canvas before creating a version" firing, so a
|
|
372
|
+
// restored draft can never be swept into a version snapshot.
|
|
373
|
+
canvas.applyNodes(draft.nodes);
|
|
374
|
+
setOffer(null);
|
|
375
|
+
}, [
|
|
376
|
+
offer,
|
|
377
|
+
restoreBlockedBy,
|
|
378
|
+
roomIsShared
|
|
379
|
+
]);
|
|
380
|
+
const discard = useCallback(()=>{
|
|
381
|
+
const currentIds = idsRef.current;
|
|
382
|
+
setOffer(null);
|
|
383
|
+
if (!currentIds) return;
|
|
384
|
+
clearBesignerDraft(currentIds);
|
|
385
|
+
// Whichever store the offer came from. The shared draft is PREFERRED over
|
|
386
|
+
// the local one when both exist, so declining an offer that clearing only
|
|
387
|
+
// localStorage cannot reach leaves the author declining the same thing on
|
|
388
|
+
// every reload, with no way to stop being asked.
|
|
389
|
+
if (firestore) void clearServerDraft(firestore, currentIds);
|
|
390
|
+
}, [
|
|
391
|
+
firestore
|
|
392
|
+
]);
|
|
393
|
+
const sharedDraftUnopened = Boolean(offer && offerOrigin === 'shared');
|
|
394
|
+
return useMemo(()=>{
|
|
395
|
+
if (!key || !offer) return EMPTY_STATE;
|
|
396
|
+
// No prompt at all in a shared room — not a re-worded one. The draft is
|
|
397
|
+
// deliberately LEFT ON DISK: nothing about the room makes this browser's
|
|
398
|
+
// snapshot wrong, only unofferable, and reaping it here would take away
|
|
399
|
+
// the crash net of the very tab that is still holding the work.
|
|
400
|
+
if (roomIsShared) {
|
|
401
|
+
return sharedDraftUnopened ? _extends({}, EMPTY_STATE, {
|
|
402
|
+
sharedDraftUnopened
|
|
403
|
+
}) : EMPTY_STATE;
|
|
404
|
+
}
|
|
405
|
+
return {
|
|
406
|
+
available: true,
|
|
407
|
+
takenAt: offer.takenAt,
|
|
408
|
+
staleAgainstDocument,
|
|
409
|
+
origin: offerOrigin,
|
|
410
|
+
restoreBlockedBy,
|
|
411
|
+
sharedDraftUnopened,
|
|
412
|
+
restore,
|
|
413
|
+
discard
|
|
414
|
+
};
|
|
415
|
+
}, [
|
|
416
|
+
key,
|
|
417
|
+
offer,
|
|
418
|
+
offerOrigin,
|
|
419
|
+
roomIsShared,
|
|
420
|
+
staleAgainstDocument,
|
|
421
|
+
restoreBlockedBy,
|
|
422
|
+
sharedDraftUnopened,
|
|
423
|
+
restore,
|
|
424
|
+
discard
|
|
425
|
+
]);
|
|
426
|
+
}
|
|
427
|
+
export default useBesignerDraft;
|
|
428
|
+
|
|
429
|
+
//# sourceMappingURL=use-besigner-draft.js.map
|