@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,905 @@
|
|
|
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 { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
18
|
+
import { canvas, FEATURE_FLAG, REUSABLE_INSTANCE_PROP_VALUES_KEY, RICH_TEXT_COMMANDS } from "@aglyn/aglyn";
|
|
19
|
+
import { mdiCodeBraces } from "@aglyn/shared-data-mdi";
|
|
20
|
+
import { MdiIcon } from "@aglyn/shared-ui-jsx";
|
|
21
|
+
// Subpath, not the library index — see the note there.
|
|
22
|
+
import { escapeHtml } from "@aglyn/shared-util-tools/escape-html";
|
|
23
|
+
import { Box, Button, IconButton, Paper } from "@mui/material";
|
|
24
|
+
import isEqual from "lodash-es/isEqual.js";
|
|
25
|
+
import { toJS } from "mobx";
|
|
26
|
+
import { observer } from "mobx-react-lite";
|
|
27
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
28
|
+
import { clampToViewport, useAnchoredRect } from "../hooks/use-anchored-rect.js";
|
|
29
|
+
import useInsertTokenOptions from "../hooks/use-insert-token-options.js";
|
|
30
|
+
import { beginInPlaceEdit, selectionOf } from "../utils/in-place-edit-surface.js";
|
|
31
|
+
import { inlineTextEdit } from "../utils/inline-text-edit.store.js";
|
|
32
|
+
import { richTextCommandGroups } from "../utils/rich-text-commands.js";
|
|
33
|
+
import { richTextToPlain, sanitizeRichText } from "../utils/sanitize-rich-text.js";
|
|
34
|
+
import { createTokenPillElement, materializeTokenPillsInElement, readTokenSegmentsFromDom, replacePillsWithTokenText, TOKEN_PILL_ATTR } from "../utils/token-editable-dom.js";
|
|
35
|
+
import { parseTokenSegments, resolveTokenLabel, serializeTokenSegments } from "../utils/token-segments.js";
|
|
36
|
+
import { InsertTokenMenu } from "./insert-token-menu.component.js";
|
|
37
|
+
import { TokenPillPopover, tokenPillContainerSx } from "./token-pill.component.js";
|
|
38
|
+
/**
|
|
39
|
+
* The formatting tools, each tagged with the group that has to be allowed
|
|
40
|
+
* for it to appear (AGL-2557).
|
|
41
|
+
*
|
|
42
|
+
* The toolbar used to render this list whole, which is why rich text could
|
|
43
|
+
* only ever be offered by a component that could hold all of it — a
|
|
44
|
+
* `<button>` cannot hold a list, so Accordion Summary and Button were left
|
|
45
|
+
* with no formatting at all rather than with the half that is safe in them.
|
|
46
|
+
*/ const RICH_COMMANDS = [
|
|
47
|
+
{
|
|
48
|
+
command: 'bold',
|
|
49
|
+
label: 'B',
|
|
50
|
+
title: 'Bold',
|
|
51
|
+
group: RICH_TEXT_COMMANDS.EMPHASIS
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
command: 'italic',
|
|
55
|
+
label: 'I',
|
|
56
|
+
title: 'Italic',
|
|
57
|
+
group: RICH_TEXT_COMMANDS.EMPHASIS
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
command: 'underline',
|
|
61
|
+
label: 'U',
|
|
62
|
+
title: 'Underline',
|
|
63
|
+
group: RICH_TEXT_COMMANDS.EMPHASIS
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
command: 'insertUnorderedList',
|
|
67
|
+
label: '•',
|
|
68
|
+
title: 'Bulleted list',
|
|
69
|
+
group: RICH_TEXT_COMMANDS.LIST
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
command: 'insertOrderedList',
|
|
73
|
+
label: '1.',
|
|
74
|
+
title: 'Numbered list',
|
|
75
|
+
group: RICH_TEXT_COMMANDS.LIST
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
/** Stands in while no edit is open, so the anchor hook can run every render. */ const EMPTY_RECT = {
|
|
79
|
+
left: 0,
|
|
80
|
+
top: 0,
|
|
81
|
+
width: 0,
|
|
82
|
+
height: 0
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* The fallback editor, for an edit with no element to type into — opened
|
|
86
|
+
* with no anchor, or on an anchor already detached from the document.
|
|
87
|
+
*
|
|
88
|
+
* Deliberately OPAQUE. It floats over content that cannot re-flow with it,
|
|
89
|
+
* and a see-through surface in that position is what drew two texts over
|
|
90
|
+
* each other; covering what it stands on is honest, blending with it is not.
|
|
91
|
+
* Everything else edits the canvas leaf itself and needs no surface here.
|
|
92
|
+
*/ const BOXED_SURFACE_SX = {
|
|
93
|
+
p: 0.5,
|
|
94
|
+
bgcolor: 'background.paper',
|
|
95
|
+
color: 'text.primary',
|
|
96
|
+
border: '2px solid',
|
|
97
|
+
borderColor: 'tertiary.main',
|
|
98
|
+
borderRadius: 0.5,
|
|
99
|
+
outline: 'none',
|
|
100
|
+
boxShadow: 4
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Plain text as the markup that renders it, newlines included.
|
|
104
|
+
*
|
|
105
|
+
* Named for what it does rather than `escapeHtml`, which it is not: the
|
|
106
|
+
* `<br>` is a CONVERSION, and a reader who takes this for the escaper will
|
|
107
|
+
* eventually reach for it somewhere a line break must stay literal. The
|
|
108
|
+
* escaping half is the shared one.
|
|
109
|
+
*/ function textToHtml(text) {
|
|
110
|
+
return escapeHtml(text).replace(/\n/g, '<br>');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Fixed-position overlay that edits a node's text in place, opened by
|
|
114
|
+
* double-clicking a `textEditable` element in the canvas (see
|
|
115
|
+
* DraggableDroppable). Plain components edit through a pill-capable
|
|
116
|
+
* contentEditable line (Enter or blur commits, Shift+Enter breaks a line,
|
|
117
|
+
* Escape cancels). Components flagged `richTextEditable` (AGL-54) get a
|
|
118
|
+
* contentEditable surface with a basic formatting toolbar; the commit
|
|
119
|
+
* sanitizes the markup through an allowlist and stores it in the `html`
|
|
120
|
+
* prop with `children` kept as the plain-text fallback. Either mode
|
|
121
|
+
* commits ONCE through `Aglyn.canvas.updateNodeProps` (a single undo entry).
|
|
122
|
+
*
|
|
123
|
+
* Binding pills (AGL-586): stored `{{...}}` tokens render as named,
|
|
124
|
+
* colored, atomic pills in BOTH modes when the editor opens; the toolbar's
|
|
125
|
+
* {x} button opens the same grouped insert picker as the attributes panel
|
|
126
|
+
* (assembled from this node's ancestor context) and drops a pill at the
|
|
127
|
+
* caret; clicking a pill offers Replace/Remove. Commits serialize pills
|
|
128
|
+
* back to raw token syntax — names shown, ids stored.
|
|
129
|
+
*
|
|
130
|
+
* Instance prop overrides (AGL-1304): opened with a `propTarget`, the same
|
|
131
|
+
* surface edits a component instance's `propValues[propName]` instead of a
|
|
132
|
+
* node's `children` — the double-clicked leaf is a GRAFTED preview node,
|
|
133
|
+
* not a canvas node, so the commit rides the instance. Always the plain
|
|
134
|
+
* surface (prop values substitute as strings), the same single
|
|
135
|
+
* `updateNodeProps` commit (one undo entry, and the same node-changed
|
|
136
|
+
* signal co-editing's shadow diff already mirrors), and an emptied commit
|
|
137
|
+
* REMOVES the override so the component's own copy returns — exactly what
|
|
138
|
+
* clearing the Attributes field does.
|
|
139
|
+
*/ export const InlineTextEditorComponent = observer(function InlineTextEditorComponent() {
|
|
140
|
+
var _ref, _ref1, _ref2;
|
|
141
|
+
var _node_componentSchema_flags, _node_componentSchema;
|
|
142
|
+
const node = inlineTextEdit.node;
|
|
143
|
+
const rect = inlineTextEdit.rect;
|
|
144
|
+
const propTarget = inlineTextEdit.propTarget;
|
|
145
|
+
// Follows the element as the canvas scrolls or resizes (AGL-1644). Called
|
|
146
|
+
// unconditionally, above the `!node || !rect` bail-out further down, so the
|
|
147
|
+
// hook order is stable whether or not an edit is open.
|
|
148
|
+
const anchor = inlineTextEdit.anchor;
|
|
149
|
+
const live = useAnchoredRect(anchor, rect != null ? rect : EMPTY_RECT);
|
|
150
|
+
/**
|
|
151
|
+
* Whether the canvas leaf ITSELF is the editing surface (AGL-2486).
|
|
152
|
+
*
|
|
153
|
+
* When it is, this component renders only the toolbar: there is no
|
|
154
|
+
* second rectangle to keep in sync with the text, so the text cannot
|
|
155
|
+
* move or restyle when editing begins and the layout re-flows because
|
|
156
|
+
* the element really did grow. That is the
|
|
157
|
+
* transparent-if-and-only-if-reserved invariant satisfied by
|
|
158
|
+
* construction rather than by a check.
|
|
159
|
+
*
|
|
160
|
+
* When it is not — no element to type into — the opaque fallback
|
|
161
|
+
* overlay is used instead.
|
|
162
|
+
*/ const [inPlaceActive, setInPlaceActive] = useState(false);
|
|
163
|
+
const overlayRef = useRef(null);
|
|
164
|
+
const plainRef = useRef(null);
|
|
165
|
+
const richRef = useRef(null);
|
|
166
|
+
// Distinguish commit-blur (Enter already committed) from cancel paths.
|
|
167
|
+
const committedRef = useRef(false);
|
|
168
|
+
/**
|
|
169
|
+
* Whether the surface has been BUILT from the node yet (AGL-2486).
|
|
170
|
+
*
|
|
171
|
+
* The editable is populated and focused on a `requestAnimationFrame`, so
|
|
172
|
+
* between opening and that frame it is an empty box holding no caret.
|
|
173
|
+
* Committing then reads emptiness as an author's deletion and writes
|
|
174
|
+
* `children: ''` — the element's text is gone from the canvas, the
|
|
175
|
+
* co-editing mirror publishes it, and every joiner gets the blank.
|
|
176
|
+
* Measured exactly that way against screen `yFjgqiG2wm`: node
|
|
177
|
+
* `XlqFJTz4ej` ("Be first through the door") went to `children: ''` from
|
|
178
|
+
* a double-click and a click-away, with nothing typed. A background tab
|
|
179
|
+
* makes it certain rather than rare — `requestAnimationFrame` does not
|
|
180
|
+
* run in one at all, so the surface NEVER seeds and every click-away is
|
|
181
|
+
* a wipe.
|
|
182
|
+
*
|
|
183
|
+
* Nothing can be lost by refusing: a surface that was never built holds
|
|
184
|
+
* no caret and no typing.
|
|
185
|
+
*/ const seededRef = useRef(false);
|
|
186
|
+
/** The canvas leaf while it IS the editing surface — see beginInPlaceEdit. */ const inPlaceRef = useRef(undefined);
|
|
187
|
+
/**
|
|
188
|
+
* Latest handlers for the listeners bound onto the leaf. They are bound
|
|
189
|
+
* once per edit, so they must not close over a stale render.
|
|
190
|
+
*/ const handlersRef = useRef({
|
|
191
|
+
keyDown: (_e)=>undefined,
|
|
192
|
+
richKeyDown: (_e)=>undefined,
|
|
193
|
+
blur: ()=>undefined,
|
|
194
|
+
click: (_e)=>undefined,
|
|
195
|
+
mouseDown: (_e)=>undefined
|
|
196
|
+
});
|
|
197
|
+
// The insert picker / pill popover take focus (portal + autofocus
|
|
198
|
+
// search) — commit-on-blur must stand down while one is open, or the
|
|
199
|
+
// editor would commit and close under the open menu (AGL-586).
|
|
200
|
+
const menuOpenRef = useRef(false);
|
|
201
|
+
const savedRangeRef = useRef(null);
|
|
202
|
+
const [insertMenu, setInsertMenu] = useState(null);
|
|
203
|
+
const [pillMenu, setPillMenu] = useState(null);
|
|
204
|
+
// Same context walk as the attributes panel (AGL-583) — the edited
|
|
205
|
+
// node is known, so dataset-item / entry groups resolve identically.
|
|
206
|
+
const { options: insertOptions, labelContext } = useInsertTokenOptions(node);
|
|
207
|
+
const labelContextRef = useRef(labelContext);
|
|
208
|
+
labelContextRef.current = labelContext;
|
|
209
|
+
// A prop edit is always the plain surface: prop values substitute into
|
|
210
|
+
// the definition as strings (see buildPropTokens), so there is no
|
|
211
|
+
// per-instance html channel for the rich toolbar to write.
|
|
212
|
+
const rich = !propTarget && (((_ref = node == null ? void 0 : (_node_componentSchema = node.componentSchema) == null ? void 0 : (_node_componentSchema_flags = _node_componentSchema.flags) == null ? void 0 : _node_componentSchema_flags.richTextEditable) != null ? _ref : FEATURE_FLAG.DISABLED) & FEATURE_FLAG.ENABLED) !== 0;
|
|
213
|
+
// What THIS component's schema allows (AGL-2557); a schema that names
|
|
214
|
+
// nothing allows everything, which is what leaves Typography alone.
|
|
215
|
+
const commandGroups = richTextCommandGroups(node == null ? void 0 : node.componentSchema);
|
|
216
|
+
/**
|
|
217
|
+
* The surface may hold phrasing content only.
|
|
218
|
+
*
|
|
219
|
+
* Derived from the allowance rather than declared beside it: a component
|
|
220
|
+
* that can take neither a list nor a link is one whose element admits no
|
|
221
|
+
* block and no nested control, and that single fact is what the commit
|
|
222
|
+
* sanitizer, the Enter key and the toolbar all need. Two ways to say it
|
|
223
|
+
* would eventually say two different things.
|
|
224
|
+
*/ const phrasingOnly = rich && !commandGroups.has(RICH_TEXT_COMMANDS.LIST) && !commandGroups.has(RICH_TEXT_COMMANDS.LINK);
|
|
225
|
+
const activeEditable = useCallback(()=>{
|
|
226
|
+
var _ref;
|
|
227
|
+
var _inPlaceRef_current;
|
|
228
|
+
return (_ref = (_inPlaceRef_current = inPlaceRef.current) == null ? void 0 : _inPlaceRef_current.element) != null ? _ref : rich ? richRef.current : plainRef.current;
|
|
229
|
+
}, [
|
|
230
|
+
rich
|
|
231
|
+
]);
|
|
232
|
+
/**
|
|
233
|
+
* Opens the edit: builds the content once, and puts it in the canvas
|
|
234
|
+
* leaf itself wherever that is possible (AGL-2486).
|
|
235
|
+
*
|
|
236
|
+
* The builder is shared deliberately. In-place and the fallback overlay
|
|
237
|
+
* must show the SAME thing — the same pills, the same markup, the same
|
|
238
|
+
* plain-text seed — or the two paths would drift into two editors.
|
|
239
|
+
*/ useEffect(()=>{
|
|
240
|
+
if (!node) return;
|
|
241
|
+
committedRef.current = false;
|
|
242
|
+
menuOpenRef.current = false;
|
|
243
|
+
savedRangeRef.current = null;
|
|
244
|
+
seededRef.current = false;
|
|
245
|
+
const props = _extends({}, node.props, node.resolvedProps);
|
|
246
|
+
const text = propTarget ? propTarget.initialText : typeof (props == null ? void 0 : props.children) === 'string' ? props.children : '';
|
|
247
|
+
const resolve = (token)=>resolveTokenLabel(token, labelContextRef.current);
|
|
248
|
+
const build = (target)=>{
|
|
249
|
+
if (rich) {
|
|
250
|
+
const initial = typeof (props == null ? void 0 : props.html) === 'string' && props.html ? props.html : textToHtml(text);
|
|
251
|
+
target.innerHTML = initial;
|
|
252
|
+
// Raw {{tokens}} in the stored markup become pills (AGL-586).
|
|
253
|
+
materializeTokenPillsInElement(target, resolve);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
// Plain mode: text nodes + pills, then the browser owns the DOM.
|
|
257
|
+
target.textContent = '';
|
|
258
|
+
for (const segment of parseTokenSegments(text)){
|
|
259
|
+
if (segment.type === 'token') {
|
|
260
|
+
var _segment_token, _segment_token1;
|
|
261
|
+
target.appendChild(createTokenPillElement(target.ownerDocument, (_segment_token = segment.token) != null ? _segment_token : segment.value, resolve((_segment_token1 = segment.token) != null ? _segment_token1 : segment.value)));
|
|
262
|
+
} else {
|
|
263
|
+
target.appendChild(target.ownerDocument.createTextNode(segment.value));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
// The element itself, whenever there is one to edit.
|
|
268
|
+
const surface = beginInPlaceEdit(anchor, build);
|
|
269
|
+
if (surface) {
|
|
270
|
+
inPlaceRef.current = surface;
|
|
271
|
+
seededRef.current = true;
|
|
272
|
+
setInPlaceActive(true);
|
|
273
|
+
surface.element.focus();
|
|
274
|
+
const selection = surface.selection();
|
|
275
|
+
if (selection) {
|
|
276
|
+
const range = surface.element.ownerDocument.createRange();
|
|
277
|
+
range.selectNodeContents(surface.element);
|
|
278
|
+
// Caret at the end, never select-all: the author double-clicked a
|
|
279
|
+
// word to edit it, and replacing the lot on the next keystroke is
|
|
280
|
+
// how a heading gets destroyed by a typo.
|
|
281
|
+
range.collapse(false);
|
|
282
|
+
selection.removeAllRanges();
|
|
283
|
+
selection.addRange(range);
|
|
284
|
+
}
|
|
285
|
+
return ()=>{
|
|
286
|
+
surface.dispose();
|
|
287
|
+
inPlaceRef.current = undefined;
|
|
288
|
+
setInPlaceActive(false);
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
// No element to edit — the OPAQUE overlay. Built on a frame because
|
|
292
|
+
// the surface it writes into has not rendered yet, which is the race
|
|
293
|
+
// `seededRef` exists for.
|
|
294
|
+
setInPlaceActive(false);
|
|
295
|
+
const raf = requestAnimationFrame(()=>{
|
|
296
|
+
const editable = rich ? richRef.current : plainRef.current;
|
|
297
|
+
if (!editable) return;
|
|
298
|
+
build(editable);
|
|
299
|
+
editable.focus();
|
|
300
|
+
const selection = window.getSelection();
|
|
301
|
+
if (selection) {
|
|
302
|
+
const range = document.createRange();
|
|
303
|
+
range.selectNodeContents(editable);
|
|
304
|
+
if (rich) range.collapse(false);
|
|
305
|
+
selection.removeAllRanges();
|
|
306
|
+
selection.addRange(range);
|
|
307
|
+
}
|
|
308
|
+
seededRef.current = true;
|
|
309
|
+
});
|
|
310
|
+
return ()=>cancelAnimationFrame(raf);
|
|
311
|
+
}, [
|
|
312
|
+
node,
|
|
313
|
+
rich,
|
|
314
|
+
propTarget,
|
|
315
|
+
anchor
|
|
316
|
+
]);
|
|
317
|
+
/**
|
|
318
|
+
* Writes `next` only when it is a different document (AGL-2486).
|
|
319
|
+
*
|
|
320
|
+
* Closing this editor is not by itself an edit. Every branch below
|
|
321
|
+
* rebuilds the WHOLE props object from the surface's DOM, so a commit
|
|
322
|
+
* that changed nothing still produced a fresh object — an undo entry, a
|
|
323
|
+
* node-changed signal, and a co-editing mirror publish, all for an edit
|
|
324
|
+
* the author never made. The mirror is the expensive one: it is cleared
|
|
325
|
+
* only by a successful save, so an unsaved no-op is replayed into every
|
|
326
|
+
* joiner's canvas for `COEDIT_MIRROR_MAX_AGE_MS` (seven days) and each
|
|
327
|
+
* of them opens a document that reads dirty with nothing to see.
|
|
328
|
+
*/ const commitProps = useCallback((node, next)=>{
|
|
329
|
+
if (isEqual(toJS(node.props), next)) return;
|
|
330
|
+
canvas.updateNodeProps(node, next);
|
|
331
|
+
}, []);
|
|
332
|
+
const commit = useCallback(()=>{
|
|
333
|
+
var // Give the element back to React BEFORE the write — see `nextWrite`.
|
|
334
|
+
_inPlaceRef_current;
|
|
335
|
+
if (committedRef.current) return;
|
|
336
|
+
committedRef.current = true;
|
|
337
|
+
const current = inlineTextEdit.node;
|
|
338
|
+
// An unbuilt surface is not an emptied one (AGL-2486) — close, do not
|
|
339
|
+
// write. See `seededRef`.
|
|
340
|
+
/**
|
|
341
|
+
* Collected first, WRITTEN LAST (AGL-2486).
|
|
342
|
+
*
|
|
343
|
+
* The markup this computes is correct; the hazard is that it can be
|
|
344
|
+
* undone a moment later. Ending the edit restores the element's
|
|
345
|
+
* original child nodes — deliberately, by reference, so React's fibers
|
|
346
|
+
* keep pointing at live nodes — and that restore must not run in the
|
|
347
|
+
* effect cleanup, i.e. AFTER `updateNodeProps` has already told React
|
|
348
|
+
* to re-render the leaf. In that order React paints the new text and
|
|
349
|
+
* the parked ORIGINAL nodes then go back over the top of it, so an
|
|
350
|
+
* edit reads as never having taken.
|
|
351
|
+
*
|
|
352
|
+
* Worst for formatted text, which is how it was found: a node with
|
|
353
|
+
* `html` renders through `dangerouslySetInnerHTML`, so React does not
|
|
354
|
+
* track those children at all and never corrects them afterwards. The
|
|
355
|
+
* canvas kept the pre-edit markup, the store held the new value, and
|
|
356
|
+
* the break came back every time — until "Remove formatting" dropped
|
|
357
|
+
* `html` and the plain `children` finally showed.
|
|
358
|
+
*
|
|
359
|
+
* So the element is given back BEFORE the store is written, and the
|
|
360
|
+
* write is the last thing that happens. React then re-renders onto a
|
|
361
|
+
* subtree that is exactly where it left it.
|
|
362
|
+
*/ let nextWrite;
|
|
363
|
+
if (current && seededRef.current) {
|
|
364
|
+
// UpdateNodeProps REPLACES the props object — spread the existing
|
|
365
|
+
// props so variant/component/etc. survive the text edit.
|
|
366
|
+
const surface = activeEditable();
|
|
367
|
+
if (rich && surface) {
|
|
368
|
+
// Pills serialize back to raw tokens BEFORE sanitizing (the
|
|
369
|
+
// sanitizer strips attributes, and pill labels must never
|
|
370
|
+
// reach storage) — on a clone, the live DOM stays intact.
|
|
371
|
+
const clone = surface.cloneNode(true);
|
|
372
|
+
replacePillsWithTokenText(clone);
|
|
373
|
+
// The toolbar offers no block command on a phrasing-only surface,
|
|
374
|
+
// but a PASTE can still carry one in, and the renderer would strip
|
|
375
|
+
// it — so the commit strips it first and what is stored is what
|
|
376
|
+
// the page will draw.
|
|
377
|
+
const sanitized = sanitizeRichText(clone.innerHTML, {
|
|
378
|
+
phrasingOnly
|
|
379
|
+
});
|
|
380
|
+
const plain = richTextToPlain(sanitized);
|
|
381
|
+
const hasMarkup = /<[a-z]/i.test(sanitized);
|
|
382
|
+
const nextProps = _extends({}, toJS(current.props), {
|
|
383
|
+
children: plain
|
|
384
|
+
});
|
|
385
|
+
// ABSENT, not `''`, when there is no markup (AGL-2486). The
|
|
386
|
+
// renderer gates on `typeof html === 'string' && Boolean(html)`,
|
|
387
|
+
// so the two are the same document to everything that draws it —
|
|
388
|
+
// but `isInitialSame` compares serialized node maps with
|
|
389
|
+
// `isEqual`, and there the empty key is a difference. Writing it
|
|
390
|
+
// onto a node that never had one is what put SAVE on the header
|
|
391
|
+
// of a screen nobody had touched.
|
|
392
|
+
if (hasMarkup) nextProps['html'] = sanitized;
|
|
393
|
+
else delete nextProps['html'];
|
|
394
|
+
nextWrite = nextProps;
|
|
395
|
+
} else if (surface) {
|
|
396
|
+
let value = serializeTokenSegments(readTokenSegmentsFromDom(surface));
|
|
397
|
+
// An emptied contentEditable leaves a stray <br> behind.
|
|
398
|
+
if (value === '\n') value = '';
|
|
399
|
+
const target = inlineTextEdit.propTarget;
|
|
400
|
+
if (target) {
|
|
401
|
+
var _current_props;
|
|
402
|
+
// Instance prop override (AGL-1304): the edit rides the
|
|
403
|
+
// INSTANCE's nested propValues, never the grafted leaf (which
|
|
404
|
+
// is not a canvas node). An emptied value REMOVES the key —
|
|
405
|
+
// the graft treats '' as unset anyway, and a cleared override
|
|
406
|
+
// must read as clean, exactly like the style-override layer.
|
|
407
|
+
const values = _extends({}, (_current_props = current.props) == null ? void 0 : _current_props[REUSABLE_INSTANCE_PROP_VALUES_KEY]);
|
|
408
|
+
if (value === '') delete values[target.propName];
|
|
409
|
+
else values[target.propName] = value;
|
|
410
|
+
const nextProps = _extends({}, current.props, {
|
|
411
|
+
[REUSABLE_INSTANCE_PROP_VALUES_KEY]: values
|
|
412
|
+
});
|
|
413
|
+
// The LAST override cleared: drop the container too, so the
|
|
414
|
+
// stored instance is byte-identical to one never overridden.
|
|
415
|
+
if (!Object.keys(values).length) {
|
|
416
|
+
delete nextProps[REUSABLE_INSTANCE_PROP_VALUES_KEY];
|
|
417
|
+
}
|
|
418
|
+
nextWrite = toJS(nextProps);
|
|
419
|
+
} else {
|
|
420
|
+
nextWrite = _extends({}, toJS(current.props), {
|
|
421
|
+
children: value
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
(_inPlaceRef_current = inPlaceRef.current) == null ? void 0 : _inPlaceRef_current.dispose();
|
|
427
|
+
inPlaceRef.current = undefined;
|
|
428
|
+
if (current && nextWrite) commitProps(current, nextWrite);
|
|
429
|
+
inlineTextEdit.close();
|
|
430
|
+
}, [
|
|
431
|
+
rich,
|
|
432
|
+
phrasingOnly,
|
|
433
|
+
commitProps,
|
|
434
|
+
activeEditable
|
|
435
|
+
]);
|
|
436
|
+
const cancel = useCallback(()=>{
|
|
437
|
+
committedRef.current = true;
|
|
438
|
+
inlineTextEdit.close();
|
|
439
|
+
}, []);
|
|
440
|
+
const handleEditableBlur = useCallback(()=>{
|
|
441
|
+
if (menuOpenRef.current) return;
|
|
442
|
+
commit();
|
|
443
|
+
}, [
|
|
444
|
+
commit
|
|
445
|
+
]);
|
|
446
|
+
// Latest `commit` for the document listener below, which must not
|
|
447
|
+
// re-register on every render just to stay current.
|
|
448
|
+
const commitRef = useRef(commit);
|
|
449
|
+
commitRef.current = commit;
|
|
450
|
+
/**
|
|
451
|
+
* Wires the editing handlers onto the LEAF while it is the surface.
|
|
452
|
+
*
|
|
453
|
+
* Imperatively, because the element belongs to the canvas renderer and
|
|
454
|
+
* not to this component's JSX — the same reason `contentEditable` is set
|
|
455
|
+
* as a DOM property. Registered once per edit and torn down with it.
|
|
456
|
+
*
|
|
457
|
+
* No `input` handler is needed any more, and that absence is the point:
|
|
458
|
+
* the element being typed into IS the element being laid out, so the
|
|
459
|
+
* card, the row and the siblings re-flow on their own. The stand-in that
|
|
460
|
+
* used to reproduce that effect for an overlay is gone with the overlay.
|
|
461
|
+
*/ useEffect(()=>{
|
|
462
|
+
const surface = inPlaceActive ? inPlaceRef.current : undefined;
|
|
463
|
+
const element = surface == null ? void 0 : surface.element;
|
|
464
|
+
if (!element) return;
|
|
465
|
+
const onKeyDown = (event)=>(rich ? handlersRef.current.richKeyDown : handlersRef.current.keyDown)(event);
|
|
466
|
+
const onBlur = ()=>handlersRef.current.blur();
|
|
467
|
+
const onClick = (event)=>handlersRef.current.click(event);
|
|
468
|
+
const onMouseDown = (event)=>handlersRef.current.mouseDown(event);
|
|
469
|
+
element.addEventListener('keydown', onKeyDown);
|
|
470
|
+
element.addEventListener('blur', onBlur);
|
|
471
|
+
element.addEventListener('click', onClick);
|
|
472
|
+
element.addEventListener('mousedown', onMouseDown);
|
|
473
|
+
return ()=>{
|
|
474
|
+
element.removeEventListener('keydown', onKeyDown);
|
|
475
|
+
element.removeEventListener('blur', onBlur);
|
|
476
|
+
element.removeEventListener('click', onClick);
|
|
477
|
+
element.removeEventListener('mousedown', onMouseDown);
|
|
478
|
+
};
|
|
479
|
+
}, [
|
|
480
|
+
inPlaceActive,
|
|
481
|
+
rich
|
|
482
|
+
]);
|
|
483
|
+
/**
|
|
484
|
+
* Click-away commits, because on this canvas blur never arrives
|
|
485
|
+
* (AGL-2486).
|
|
486
|
+
*
|
|
487
|
+
* `commit()` used to be reachable from a click only through `onBlur`,
|
|
488
|
+
* and a click on another element cannot produce one: `DraggableDroppable`
|
|
489
|
+
* registers `mousedown` AND `pointerdown` on every leaf and both begin
|
|
490
|
+
* `e.preventDefault(); e.stopPropagation()`. Preventing a mousedown's
|
|
491
|
+
* default suppresses the focus change it would have caused, so the
|
|
492
|
+
* editable keeps focus and stays open — while the same handler runs
|
|
493
|
+
* `Besigner.focus.handleNodeSelection(node, …)` and moves the selection
|
|
494
|
+
* out from under it. Clicking out "just selects other elements rather
|
|
495
|
+
* than applying", and the edit sits in a surface the author has already
|
|
496
|
+
* mentally left. This repo has recorded that exact shape once before:
|
|
497
|
+
* an attribute that commits on blur, discarded by selecting the next
|
|
498
|
+
* node, with the canvas still looking right.
|
|
499
|
+
*
|
|
500
|
+
* A CAPTURE-phase listener on the document is what reaches the commit
|
|
501
|
+
* first: capture runs from the document down, so it is ahead of the
|
|
502
|
+
* leaf's own bubble-phase listener and ahead of the `preventDefault`
|
|
503
|
+
* that would have swallowed the blur. It calls the SAME `commit()` the
|
|
504
|
+
* Done button does — one commit path, one undo entry, and the same
|
|
505
|
+
* no-op guard, rather than a second route into the document.
|
|
506
|
+
*
|
|
507
|
+
* The click is deliberately NOT consumed: committing and then letting
|
|
508
|
+
* the canvas select what was clicked is what every other design tool
|
|
509
|
+
* does, and it is what the author asked for by clicking there.
|
|
510
|
+
*
|
|
511
|
+
* `pointerdown`, not `mousedown`: it is the first of the pair, and
|
|
512
|
+
* `preventDefault` on it suppresses the mouse events that follow, so a
|
|
513
|
+
* `mousedown` listener would never run for a touch or pen edit.
|
|
514
|
+
*
|
|
515
|
+
* Targets inside the canvas retarget to its CLOSED shadow host, which is
|
|
516
|
+
* not inside this overlay, so `contains` reads them as outside — which
|
|
517
|
+
* they are. The portalled insert picker and pill popover ARE outside the
|
|
518
|
+
* overlay in the DOM, and are covered by the same `menuOpenRef` stand-down
|
|
519
|
+
* that already guards commit-on-blur (AGL-586).
|
|
520
|
+
*/ useEffect(()=>{
|
|
521
|
+
var _inPlaceRef_current;
|
|
522
|
+
if (!node) return;
|
|
523
|
+
const editing = (_inPlaceRef_current = inPlaceRef.current) == null ? void 0 : _inPlaceRef_current.element;
|
|
524
|
+
const root = editing == null ? void 0 : editing.getRootNode();
|
|
525
|
+
const host = root && 'host' in root ? root.host : undefined;
|
|
526
|
+
const isInsideTheEditor = (target)=>{
|
|
527
|
+
var _inPlaceRef_current;
|
|
528
|
+
if (!target) return false;
|
|
529
|
+
// Read LIVE, never the value captured when this effect ran: a click
|
|
530
|
+
// inside the text is the author placing a caret, and getting that
|
|
531
|
+
// wrong tears the surface down and rebuilds it on every click, which
|
|
532
|
+
// looks exactly like a caret that will not move.
|
|
533
|
+
const live = (_inPlaceRef_current = inPlaceRef.current) == null ? void 0 : _inPlaceRef_current.element;
|
|
534
|
+
if (live == null ? void 0 : live.contains(target)) return true;
|
|
535
|
+
const overlay = overlayRef.current;
|
|
536
|
+
return Boolean(overlay == null ? void 0 : overlay.contains(target));
|
|
537
|
+
};
|
|
538
|
+
const handlePointerDownAway = (event)=>{
|
|
539
|
+
if (menuOpenRef.current) return;
|
|
540
|
+
const target = event.target;
|
|
541
|
+
// Inside the CLOSED canvas root, an event seen from the document has
|
|
542
|
+
// already been retargeted to the host, so it cannot say whether the
|
|
543
|
+
// click landed on the text being edited or beside it. The listener on
|
|
544
|
+
// the root itself sees the real target and has already decided; this
|
|
545
|
+
// one must not overrule it with a guess.
|
|
546
|
+
if (host && target === host) return;
|
|
547
|
+
if (isInsideTheEditor(target)) return;
|
|
548
|
+
commitRef.current();
|
|
549
|
+
};
|
|
550
|
+
document.addEventListener('pointerdown', handlePointerDownAway, true);
|
|
551
|
+
// Second listener, INSIDE the shadow root, for the clicks the first one
|
|
552
|
+
// is blind to — including a click on the very element being edited,
|
|
553
|
+
// which must move the caret rather than end the edit.
|
|
554
|
+
if (root && root !== document) {
|
|
555
|
+
root.addEventListener('pointerdown', handlePointerDownAway, true);
|
|
556
|
+
}
|
|
557
|
+
return ()=>{
|
|
558
|
+
document.removeEventListener('pointerdown', handlePointerDownAway, true);
|
|
559
|
+
if (root && root !== document) {
|
|
560
|
+
root.removeEventListener('pointerdown', handlePointerDownAway, true);
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
}, [
|
|
564
|
+
node,
|
|
565
|
+
inPlaceActive
|
|
566
|
+
]);
|
|
567
|
+
const insertPlainNewline = useCallback(()=>{
|
|
568
|
+
const editable = activeEditable();
|
|
569
|
+
const selection = editable ? selectionOf(editable) : null;
|
|
570
|
+
if (!selection || selection.rangeCount === 0) return;
|
|
571
|
+
const range = selection.getRangeAt(0);
|
|
572
|
+
range.deleteContents();
|
|
573
|
+
const newline = document.createTextNode('\n');
|
|
574
|
+
range.insertNode(newline);
|
|
575
|
+
range.setStartAfter(newline);
|
|
576
|
+
range.collapse(true);
|
|
577
|
+
selection.removeAllRanges();
|
|
578
|
+
selection.addRange(range);
|
|
579
|
+
}, [
|
|
580
|
+
activeEditable
|
|
581
|
+
]);
|
|
582
|
+
const handleKeyDown = useCallback((event)=>{
|
|
583
|
+
if (event.key === 'Escape') {
|
|
584
|
+
event.preventDefault();
|
|
585
|
+
cancel();
|
|
586
|
+
} else if (event.key === 'Enter' && !event.shiftKey) {
|
|
587
|
+
event.preventDefault();
|
|
588
|
+
commit();
|
|
589
|
+
} else if (event.key === 'Enter') {
|
|
590
|
+
// Browsers fork contentEditable into <div>s on Enter — insert
|
|
591
|
+
// the newline ourselves so reads stay text + pills only.
|
|
592
|
+
event.preventDefault();
|
|
593
|
+
insertPlainNewline();
|
|
594
|
+
}
|
|
595
|
+
}, [
|
|
596
|
+
cancel,
|
|
597
|
+
commit,
|
|
598
|
+
insertPlainNewline
|
|
599
|
+
]);
|
|
600
|
+
const handleRichKeyDown = useCallback((event)=>{
|
|
601
|
+
if (event.key === 'Escape') {
|
|
602
|
+
event.preventDefault();
|
|
603
|
+
cancel();
|
|
604
|
+
} else if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {
|
|
605
|
+
event.preventDefault();
|
|
606
|
+
commit();
|
|
607
|
+
} else if (event.key === 'Enter' && phrasingOnly && !event.shiftKey) {
|
|
608
|
+
// A phrasing-only surface is a control's LABEL — a button, a link,
|
|
609
|
+
// an accordion header. Enter there means "done", the same as it
|
|
610
|
+
// does on the plain surface; a browser would otherwise fork the
|
|
611
|
+
// contentEditable into `<div>`s, which is exactly the markup this
|
|
612
|
+
// surface may not hold. Shift+Enter still breaks the line, and a
|
|
613
|
+
// `<br>` is phrasing content.
|
|
614
|
+
event.preventDefault();
|
|
615
|
+
commit();
|
|
616
|
+
}
|
|
617
|
+
}, [
|
|
618
|
+
cancel,
|
|
619
|
+
commit,
|
|
620
|
+
phrasingOnly
|
|
621
|
+
]);
|
|
622
|
+
// Keep the selection inside the editable surface while clicking tools.
|
|
623
|
+
const keepFocus = useCallback((event)=>{
|
|
624
|
+
event.preventDefault();
|
|
625
|
+
}, []);
|
|
626
|
+
const exec = useCallback((command)=>()=>{
|
|
627
|
+
var _activeEditable;
|
|
628
|
+
// ExecCommand is deprecated but universally supported and keeps this
|
|
629
|
+
// dependency-free; the output is normalized by the sanitizer anyway.
|
|
630
|
+
document.execCommand(command);
|
|
631
|
+
(_activeEditable = activeEditable()) == null ? void 0 : _activeEditable.focus();
|
|
632
|
+
}, [
|
|
633
|
+
activeEditable
|
|
634
|
+
]);
|
|
635
|
+
const handleLink = useCallback(()=>{
|
|
636
|
+
var _activeEditable;
|
|
637
|
+
const url = window.prompt('Link URL (https://…)');
|
|
638
|
+
if (url) document.execCommand('createLink', false, url);
|
|
639
|
+
(_activeEditable = activeEditable()) == null ? void 0 : _activeEditable.focus();
|
|
640
|
+
}, [
|
|
641
|
+
activeEditable
|
|
642
|
+
]);
|
|
643
|
+
/** Pill clicks (delegated): offer Replace/Remove (AGL-586). */ const handleEditableClick = useCallback((event)=>{
|
|
644
|
+
const pill = event.target.closest == null ? void 0 : event.target.closest.call(event.target, `[${TOKEN_PILL_ATTR}]`);
|
|
645
|
+
if (!pill || !event.currentTarget.contains(pill)) return;
|
|
646
|
+
menuOpenRef.current = true;
|
|
647
|
+
setPillMenu(pill);
|
|
648
|
+
}, []);
|
|
649
|
+
// Pills are non-editable islands — a mousedown on one would move
|
|
650
|
+
// focus out of the editable and trigger commit-on-blur.
|
|
651
|
+
const handleEditableMouseDown = useCallback((event)=>{
|
|
652
|
+
const pill = event.target.closest == null ? void 0 : event.target.closest.call(event.target, `[${TOKEN_PILL_ATTR}]`);
|
|
653
|
+
if (pill) event.preventDefault();
|
|
654
|
+
}, []);
|
|
655
|
+
handlersRef.current = {
|
|
656
|
+
keyDown: handleKeyDown,
|
|
657
|
+
richKeyDown: handleRichKeyDown,
|
|
658
|
+
blur: handleEditableBlur,
|
|
659
|
+
click: handleEditableClick,
|
|
660
|
+
mouseDown: handleEditableMouseDown
|
|
661
|
+
};
|
|
662
|
+
/** The toolbar {x}: captures the live selection, opens the picker. */ const handleInsertOpen = useCallback((event)=>{
|
|
663
|
+
const editable = activeEditable();
|
|
664
|
+
const selection = editable ? selectionOf(editable) : null;
|
|
665
|
+
const range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
|
|
666
|
+
savedRangeRef.current = range && editable && editable.contains(range.startContainer) && editable.contains(range.endContainer) ? range.cloneRange() : null;
|
|
667
|
+
menuOpenRef.current = true;
|
|
668
|
+
setInsertMenu({
|
|
669
|
+
anchorEl: event.currentTarget,
|
|
670
|
+
replacePill: null
|
|
671
|
+
});
|
|
672
|
+
}, [
|
|
673
|
+
activeEditable
|
|
674
|
+
]);
|
|
675
|
+
const closeMenus = useCallback(()=>{
|
|
676
|
+
var _activeEditable;
|
|
677
|
+
setInsertMenu(null);
|
|
678
|
+
setPillMenu(null);
|
|
679
|
+
menuOpenRef.current = false;
|
|
680
|
+
(_activeEditable = activeEditable()) == null ? void 0 : _activeEditable.focus();
|
|
681
|
+
}, [
|
|
682
|
+
activeEditable
|
|
683
|
+
]);
|
|
684
|
+
const handleInsertPick = useCallback((token)=>{
|
|
685
|
+
var _ref;
|
|
686
|
+
const editable = activeEditable();
|
|
687
|
+
const replacePill = (_ref = insertMenu == null ? void 0 : insertMenu.replacePill) != null ? _ref : null;
|
|
688
|
+
setInsertMenu(null);
|
|
689
|
+
menuOpenRef.current = false;
|
|
690
|
+
if (!editable) return;
|
|
691
|
+
const pill = createTokenPillElement(document, token, resolveTokenLabel(token, labelContextRef.current));
|
|
692
|
+
if (replacePill && editable.contains(replacePill)) {
|
|
693
|
+
replacePill.replaceWith(pill);
|
|
694
|
+
} else {
|
|
695
|
+
const range = savedRangeRef.current;
|
|
696
|
+
if (range && editable.contains(range.startContainer) && editable.contains(range.endContainer)) {
|
|
697
|
+
range.deleteContents();
|
|
698
|
+
range.insertNode(pill);
|
|
699
|
+
} else {
|
|
700
|
+
editable.appendChild(pill);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
savedRangeRef.current = null;
|
|
704
|
+
editable.focus();
|
|
705
|
+
// Caret lands just after the pill, ready to keep typing.
|
|
706
|
+
const selection = selectionOf(editable);
|
|
707
|
+
if (selection) {
|
|
708
|
+
const after = document.createRange();
|
|
709
|
+
after.setStartAfter(pill);
|
|
710
|
+
after.collapse(true);
|
|
711
|
+
selection.removeAllRanges();
|
|
712
|
+
selection.addRange(after);
|
|
713
|
+
}
|
|
714
|
+
}, [
|
|
715
|
+
activeEditable,
|
|
716
|
+
insertMenu
|
|
717
|
+
]);
|
|
718
|
+
const handlePillReplace = useCallback(()=>{
|
|
719
|
+
const pill = pillMenu;
|
|
720
|
+
setPillMenu(null);
|
|
721
|
+
if (!pill) {
|
|
722
|
+
menuOpenRef.current = false;
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
// Keep menuOpenRef up — the insert picker opens next.
|
|
726
|
+
setInsertMenu({
|
|
727
|
+
anchorEl: pill,
|
|
728
|
+
replacePill: pill
|
|
729
|
+
});
|
|
730
|
+
}, [
|
|
731
|
+
pillMenu
|
|
732
|
+
]);
|
|
733
|
+
const handlePillRemove = useCallback(()=>{
|
|
734
|
+
pillMenu == null ? void 0 : pillMenu.remove();
|
|
735
|
+
closeMenus();
|
|
736
|
+
}, [
|
|
737
|
+
pillMenu,
|
|
738
|
+
closeMenus
|
|
739
|
+
]);
|
|
740
|
+
const insertButton = /*#__PURE__*/ _jsx(IconButton, {
|
|
741
|
+
size: "small",
|
|
742
|
+
title: "Insert data",
|
|
743
|
+
"aria-label": "Insert data token",
|
|
744
|
+
onMouseDown: keepFocus,
|
|
745
|
+
onClick: handleInsertOpen,
|
|
746
|
+
sx: {
|
|
747
|
+
width: 28,
|
|
748
|
+
height: 28,
|
|
749
|
+
borderRadius: 0.5
|
|
750
|
+
},
|
|
751
|
+
children: /*#__PURE__*/ _jsx(MdiIcon, {
|
|
752
|
+
path: mdiCodeBraces.path,
|
|
753
|
+
fontSize: "small"
|
|
754
|
+
})
|
|
755
|
+
});
|
|
756
|
+
if (!node || !rect) return null;
|
|
757
|
+
// Read at render, which `useAnchoredRect` makes safe: it re-renders on
|
|
758
|
+
// every scroll and resize, so these are never a stale snapshot. The toolbar
|
|
759
|
+
// sits 40px ABOVE the surface, so the top margin has to clear it or the
|
|
760
|
+
// controls go off-screen while the editable stays on it.
|
|
761
|
+
const viewportWidth = typeof window === 'undefined' ? Infinity : window.innerWidth;
|
|
762
|
+
const viewportHeight = typeof window === 'undefined' ? Infinity : window.innerHeight;
|
|
763
|
+
// The fallback overlay is ALWAYS the opaque box (AGL-2486). It exists
|
|
764
|
+
// only for an edit with no element to type into, and an element that is
|
|
765
|
+
// not there cannot re-flow — so a see-through surface over it would be
|
|
766
|
+
// exactly what the invariant forbids. In-place editing needs no surface
|
|
767
|
+
// here at all: the leaf is the surface, and this component renders only
|
|
768
|
+
// the toolbar.
|
|
769
|
+
//
|
|
770
|
+
// Built as plain records and cast ONCE, the way `tokenPillContainerSx`
|
|
771
|
+
// is: MUI's `sx` union cannot absorb a computed spread and reports every
|
|
772
|
+
// neighbouring key as the error instead.
|
|
773
|
+
const surfaceSx = BOXED_SURFACE_SX;
|
|
774
|
+
const richSurfaceSx = _extends({
|
|
775
|
+
width: '100%',
|
|
776
|
+
minHeight: live.height,
|
|
777
|
+
boxSizing: 'border-box',
|
|
778
|
+
font: 'inherit'
|
|
779
|
+
}, surfaceSx, {
|
|
780
|
+
'& a': {
|
|
781
|
+
pointerEvents: 'none'
|
|
782
|
+
}
|
|
783
|
+
}, tokenPillContainerSx);
|
|
784
|
+
const plainSurfaceSx = _extends({
|
|
785
|
+
width: '100%',
|
|
786
|
+
minHeight: live.height,
|
|
787
|
+
boxSizing: 'border-box',
|
|
788
|
+
font: 'inherit'
|
|
789
|
+
}, surfaceSx, {
|
|
790
|
+
// After the anchor's type, never from it: `pre-wrap` is what makes a
|
|
791
|
+
// Shift+Enter newline visible while typing.
|
|
792
|
+
whiteSpace: 'pre-wrap',
|
|
793
|
+
wordBreak: 'break-word'
|
|
794
|
+
}, tokenPillContainerSx);
|
|
795
|
+
const minWidth = Math.max(live.width, 120);
|
|
796
|
+
const TOOLBAR_CLEARANCE = 48;
|
|
797
|
+
const KEEP_VISIBLE = 80;
|
|
798
|
+
return /*#__PURE__*/ _jsxs(Box, {
|
|
799
|
+
ref: overlayRef,
|
|
800
|
+
"data-aglyn": "overlay:inline-text-editor",
|
|
801
|
+
sx: {
|
|
802
|
+
position: 'fixed',
|
|
803
|
+
left: clampToViewport(live.left, minWidth, viewportWidth),
|
|
804
|
+
top: clampToViewport(live.top, KEEP_VISIBLE, viewportHeight, TOOLBAR_CLEARANCE),
|
|
805
|
+
minWidth,
|
|
806
|
+
maxWidth: '90vw',
|
|
807
|
+
zIndex: (theme)=>theme.zIndex.modal
|
|
808
|
+
},
|
|
809
|
+
children: [
|
|
810
|
+
/*#__PURE__*/ _jsxs(Paper, {
|
|
811
|
+
elevation: 4,
|
|
812
|
+
sx: {
|
|
813
|
+
position: 'absolute',
|
|
814
|
+
top: -40,
|
|
815
|
+
left: 0,
|
|
816
|
+
px: 0.5,
|
|
817
|
+
py: 0.25,
|
|
818
|
+
display: 'flex',
|
|
819
|
+
gap: 0.25,
|
|
820
|
+
alignItems: 'center'
|
|
821
|
+
},
|
|
822
|
+
children: [
|
|
823
|
+
rich ? RICH_COMMANDS.filter(({ group })=>commandGroups.has(group)).map(({ command, label, title })=>/*#__PURE__*/ _jsx(IconButton, {
|
|
824
|
+
size: "small",
|
|
825
|
+
title: title,
|
|
826
|
+
onMouseDown: keepFocus,
|
|
827
|
+
onClick: exec(command),
|
|
828
|
+
sx: {
|
|
829
|
+
width: 28,
|
|
830
|
+
height: 28,
|
|
831
|
+
fontSize: 13,
|
|
832
|
+
fontWeight: 700,
|
|
833
|
+
fontStyle: command === 'italic' ? 'italic' : undefined,
|
|
834
|
+
textDecoration: command === 'underline' ? 'underline' : undefined,
|
|
835
|
+
borderRadius: 0.5
|
|
836
|
+
},
|
|
837
|
+
children: label
|
|
838
|
+
}, command)) : null,
|
|
839
|
+
rich && commandGroups.has(RICH_TEXT_COMMANDS.LINK) ? /*#__PURE__*/ _jsx(IconButton, {
|
|
840
|
+
size: "small",
|
|
841
|
+
title: "Insert link",
|
|
842
|
+
onMouseDown: keepFocus,
|
|
843
|
+
onClick: handleLink,
|
|
844
|
+
sx: {
|
|
845
|
+
width: 28,
|
|
846
|
+
height: 28,
|
|
847
|
+
fontSize: 13,
|
|
848
|
+
borderRadius: 0.5
|
|
849
|
+
},
|
|
850
|
+
children: '\u{1F517}'
|
|
851
|
+
}) : null,
|
|
852
|
+
insertButton,
|
|
853
|
+
/*#__PURE__*/ _jsx(Button, {
|
|
854
|
+
size: "small",
|
|
855
|
+
color: "primary",
|
|
856
|
+
onMouseDown: keepFocus,
|
|
857
|
+
onClick: commit,
|
|
858
|
+
children: 'Done'
|
|
859
|
+
})
|
|
860
|
+
]
|
|
861
|
+
}),
|
|
862
|
+
inPlaceActive ? null : rich ? /*#__PURE__*/ _jsx(Box, {
|
|
863
|
+
ref: richRef,
|
|
864
|
+
contentEditable: true,
|
|
865
|
+
suppressContentEditableWarning: true,
|
|
866
|
+
role: "textbox",
|
|
867
|
+
"aria-label": "Edit rich text",
|
|
868
|
+
onKeyDown: handleRichKeyDown,
|
|
869
|
+
onBlur: handleEditableBlur,
|
|
870
|
+
onClick: handleEditableClick,
|
|
871
|
+
onMouseDown: handleEditableMouseDown,
|
|
872
|
+
sx: richSurfaceSx
|
|
873
|
+
}) : /*#__PURE__*/ _jsx(Box, {
|
|
874
|
+
ref: plainRef,
|
|
875
|
+
contentEditable: true,
|
|
876
|
+
suppressContentEditableWarning: true,
|
|
877
|
+
role: "textbox",
|
|
878
|
+
"aria-label": "Edit text",
|
|
879
|
+
onKeyDown: handleKeyDown,
|
|
880
|
+
onBlur: handleEditableBlur,
|
|
881
|
+
onClick: handleEditableClick,
|
|
882
|
+
onMouseDown: handleEditableMouseDown,
|
|
883
|
+
sx: plainSurfaceSx
|
|
884
|
+
}),
|
|
885
|
+
/*#__PURE__*/ _jsx(InsertTokenMenu, {
|
|
886
|
+
anchorEl: (_ref1 = insertMenu == null ? void 0 : insertMenu.anchorEl) != null ? _ref1 : null,
|
|
887
|
+
open: Boolean(insertMenu),
|
|
888
|
+
onClose: closeMenus,
|
|
889
|
+
options: insertOptions,
|
|
890
|
+
onInsert: handleInsertPick
|
|
891
|
+
}),
|
|
892
|
+
/*#__PURE__*/ _jsx(TokenPillPopover, {
|
|
893
|
+
anchorEl: pillMenu,
|
|
894
|
+
token: (_ref2 = pillMenu == null ? void 0 : pillMenu.getAttribute(TOKEN_PILL_ATTR)) != null ? _ref2 : '',
|
|
895
|
+
onClose: closeMenus,
|
|
896
|
+
onReplace: handlePillReplace,
|
|
897
|
+
onRemove: handlePillRemove
|
|
898
|
+
})
|
|
899
|
+
]
|
|
900
|
+
});
|
|
901
|
+
});
|
|
902
|
+
InlineTextEditorComponent.displayName = 'InlineTextEditorComponent';
|
|
903
|
+
export default InlineTextEditorComponent;
|
|
904
|
+
|
|
905
|
+
//# sourceMappingURL=inline-text-editor.component.js.map
|