@elytracms/studio 0.0.93 → 0.0.95
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/convex/analytics-cost.test.ts +817 -0
- package/convex/asset-alt-migration.test.ts +2 -2
- package/convex/asset-meta-patch.test.ts +218 -0
- package/convex/asset-replace-delete-race.test.ts +127 -0
- package/convex/assets.ts +27 -2
- package/convex/auth.ts +5 -2
- package/convex/authority.ts +35 -11
- package/convex/contract-parity.test.ts +7 -0
- package/convex/delivery-redirects.test.ts +167 -0
- package/convex/delivery.ts +23 -10
- package/convex/guard.ts +9 -7
- package/convex/http-routes.test.ts +18 -8
- package/convex/http.ts +23 -17
- package/convex/ingest.test.ts +326 -0
- package/convex/ingest.ts +281 -0
- package/convex/invites.ts +13 -5
- package/convex/members.ts +10 -4
- package/convex/rail-write-parity.test.ts +6 -6
- package/convex/record-functions.ts +325 -0
- package/convex/records.test.ts +156 -0
- package/convex/redirect-migration.test.ts +205 -0
- package/convex/redirect-revalidate.test.ts +5 -1
- package/convex/redirects.ts +120 -79
- package/convex/role-policy.test.ts +315 -0
- package/convex/roles.ts +83 -0
- package/convex/schema.ts +36 -0
- package/convex/triggers.ts +21 -1
- package/dist/addon.d.ts +71 -0
- package/dist/addon.js +67 -0
- package/dist/addon.js.map +1 -0
- package/dist/components/account/account-settings.js +2 -2
- package/dist/components/account/account-settings.js.map +1 -1
- package/dist/components/account/credential-panel.js +2 -2
- package/dist/components/account/credential-panel.js.map +1 -1
- package/dist/components/account/self-account-schema.d.ts +6 -15
- package/dist/components/account/self-account-schema.js +52 -34
- package/dist/components/account/self-account-schema.js.map +1 -1
- package/dist/components/account/self-account-view-source.d.ts +1 -1
- package/dist/components/account/self-account-view-source.js +6 -4
- package/dist/components/account/self-account-view-source.js.map +1 -1
- package/dist/components/ai/ai-chat-panel-lazy.js +1 -1
- package/dist/components/ai/ai-chat-panel-lazy.js.map +1 -1
- package/dist/components/ai/ai-chat-panel.js +6 -6
- package/dist/components/ai/ai-chat-panel.js.map +1 -1
- package/dist/components/ai/ai-cms-panel.js +2 -2
- package/dist/components/ai/ai-cms-panel.js.map +1 -1
- package/dist/components/ai/ai-panel-toggle.js +4 -4
- package/dist/components/ai/ai-panel-toggle.js.map +1 -1
- package/dist/components/ai/chat-ui.js +2 -2
- package/dist/components/ai/chat-ui.js.map +1 -1
- package/dist/components/ai/proposal-card.d.ts +2 -2
- package/dist/components/ai/proposal-card.js +2 -2
- package/dist/components/ai/proposal-card.js.map +1 -1
- package/dist/components/ai/proposal-issues.js +2 -2
- package/dist/components/ai/proposal-issues.js.map +1 -1
- package/dist/components/ai/translate-document-action.js +2 -2
- package/dist/components/ai/translate-document-action.js.map +1 -1
- package/dist/components/ai/translate-document-dialog.js +6 -6
- package/dist/components/ai/translate-document-dialog.js.map +1 -1
- package/dist/components/ai/translate-skipped.d.ts +1 -1
- package/dist/components/ai/translate-skipped.js +2 -2
- package/dist/components/ai/translate-skipped.js.map +1 -1
- package/dist/components/app-views/default-modules.d.ts +50 -2
- package/dist/components/app-views/default-modules.js +65 -20
- package/dist/components/app-views/default-modules.js.map +1 -1
- package/dist/components/app-views/module.d.ts +53 -3
- package/dist/components/app-views/module.js +14 -7
- package/dist/components/app-views/module.js.map +1 -1
- package/dist/components/app-views/sidebar.js +1 -1
- package/dist/components/app-views/sidebar.js.map +1 -1
- package/dist/components/app-views/studio-config.d.ts +11 -2
- package/dist/components/app-views/studio-config.js.map +1 -1
- package/dist/components/assets/asset-detail.js +28 -13
- package/dist/components/assets/asset-detail.js.map +1 -1
- package/dist/components/assets/asset-grid.js +2 -2
- package/dist/components/assets/asset-grid.js.map +1 -1
- package/dist/components/assets/asset-locale.d.ts +9 -0
- package/dist/components/assets/asset-locale.js +16 -0
- package/dist/components/assets/asset-locale.js.map +1 -0
- package/dist/components/assets/asset-meta-label.d.ts +12 -0
- package/dist/components/assets/asset-meta-label.js +15 -0
- package/dist/components/assets/asset-meta-label.js.map +1 -0
- package/dist/components/assets/asset-metadata.d.ts +69 -15
- package/dist/components/assets/asset-metadata.js +99 -11
- package/dist/components/assets/asset-metadata.js.map +1 -1
- package/dist/components/assets/asset-search.js +8 -2
- package/dist/components/assets/asset-search.js.map +1 -1
- package/dist/components/assets/asset-thumb.js +9 -5
- package/dist/components/assets/asset-thumb.js.map +1 -1
- package/dist/components/assets/assets-collection-view-source.d.ts +25 -11
- package/dist/components/assets/assets-collection-view-source.js +78 -26
- package/dist/components/assets/assets-collection-view-source.js.map +1 -1
- package/dist/components/assets/assets-module.js +1 -1
- package/dist/components/assets/assets-module.js.map +1 -1
- package/dist/components/assets/assets-store.d.ts +2 -2
- package/dist/components/assets/assets-store.js +22 -9
- package/dist/components/assets/assets-store.js.map +1 -1
- package/dist/components/assets/assets-view-preference.js +1 -1
- package/dist/components/assets/assets-view-preference.js.map +1 -1
- package/dist/components/assets/replace-file.js +1 -1
- package/dist/components/assets/replace-file.js.map +1 -1
- package/dist/components/auth-context.d.ts +1 -1
- package/dist/components/auth-context.js +6 -6
- package/dist/components/auth-context.js.map +1 -1
- package/dist/components/builder/blocks-model.d.ts +1 -1
- package/dist/components/builder/blocks-model.js +3 -3
- package/dist/components/builder/blocks-model.js.map +1 -1
- package/dist/components/builder/blocks-panel.d.ts +1 -1
- package/dist/components/builder/blocks-panel.js +4 -4
- package/dist/components/builder/blocks-panel.js.map +1 -1
- package/dist/components/builder/builder-store.d.ts +21 -0
- package/dist/components/builder/builder-store.js +24 -2
- package/dist/components/builder/builder-store.js.map +1 -1
- package/dist/components/builder/canvas-breakpoints.js +1 -1
- package/dist/components/builder/canvas-breakpoints.js.map +1 -1
- package/dist/components/builder/canvas-commit-boundary.d.ts +22 -0
- package/dist/components/builder/canvas-commit-boundary.js +27 -0
- package/dist/components/builder/canvas-commit-boundary.js.map +1 -0
- package/dist/components/builder/canvas-dnd.d.ts +2 -2
- package/dist/components/builder/canvas-dnd.js +1 -1
- package/dist/components/builder/canvas-dnd.js.map +1 -1
- package/dist/components/builder/canvas-inline-editing.d.ts +1 -1
- package/dist/components/builder/canvas-inline-editing.js.map +1 -1
- package/dist/components/builder/canvas-overlay-geometry.d.ts +1 -1
- package/dist/components/builder/canvas-overlay-geometry.js.map +1 -1
- package/dist/components/builder/canvas-rebase.d.ts +77 -0
- package/dist/components/builder/canvas-rebase.js +169 -0
- package/dist/components/builder/canvas-rebase.js.map +1 -0
- package/dist/components/builder/canvas-render-context.d.ts +7 -4
- package/dist/components/builder/canvas-render-context.js +21 -13
- package/dist/components/builder/canvas-render-context.js.map +1 -1
- package/dist/components/builder/canvas-theme-notice.js +2 -2
- package/dist/components/builder/canvas-theme-notice.js.map +1 -1
- package/dist/components/builder/canvas.js +3 -3
- package/dist/components/builder/canvas.js.map +1 -1
- package/dist/components/builder/clipboard-actions.d.ts +2 -2
- package/dist/components/builder/clipboard-actions.js +4 -4
- package/dist/components/builder/clipboard-actions.js.map +1 -1
- package/dist/components/builder/composition-field-editor-lazy.js +1 -1
- package/dist/components/builder/composition-field-editor-lazy.js.map +1 -1
- package/dist/components/builder/composition-field-editor.d.ts +21 -3
- package/dist/components/builder/composition-field-editor.js +48 -30
- package/dist/components/builder/composition-field-editor.js.map +1 -1
- package/dist/components/builder/drag-session.d.ts +1 -1
- package/dist/components/builder/drag-session.js.map +1 -1
- package/dist/components/builder/fixture-thumbnail.js +1 -1
- package/dist/components/builder/fixture-thumbnail.js.map +1 -1
- package/dist/components/builder/insert-context.d.ts +1 -1
- package/dist/components/builder/insert-context.js +3 -3
- package/dist/components/builder/insert-context.js.map +1 -1
- package/dist/components/builder/layout-inspector.js +1 -1
- package/dist/components/builder/layout-inspector.js.map +1 -1
- package/dist/components/builder/node-factory.js +15 -3
- package/dist/components/builder/node-factory.js.map +1 -1
- package/dist/components/builder/node-title.js +1 -1
- package/dist/components/builder/node-title.js.map +1 -1
- package/dist/components/builder/page-tree.d.ts +1 -1
- package/dist/components/builder/page-tree.js +5 -5
- package/dist/components/builder/page-tree.js.map +1 -1
- package/dist/components/builder/placement-refusal.js +3 -3
- package/dist/components/builder/placement-refusal.js.map +1 -1
- package/dist/components/builder/property-inspector.js +7 -5
- package/dist/components/builder/property-inspector.js.map +1 -1
- package/dist/components/builder/reuse-context.js +4 -4
- package/dist/components/builder/reuse-context.js.map +1 -1
- package/dist/components/builder/reuse.js +1 -1
- package/dist/components/builder/reuse.js.map +1 -1
- package/dist/components/builder/rich-text-toolbar.js +1 -1
- package/dist/components/builder/rich-text-toolbar.js.map +1 -1
- package/dist/components/builder/run-inspector.js +11 -7
- package/dist/components/builder/run-inspector.js.map +1 -1
- package/dist/components/builder/selection-overlay.js +3 -3
- package/dist/components/builder/selection-overlay.js.map +1 -1
- package/dist/components/builder/spacing-handles.d.ts +2 -2
- package/dist/components/builder/spacing-handles.js +3 -3
- package/dist/components/builder/spacing-handles.js.map +1 -1
- package/dist/components/cms/asset-field.d.ts +5 -2
- package/dist/components/cms/asset-field.js +36 -19
- package/dist/components/cms/asset-field.js.map +1 -1
- package/dist/components/cms/asset-picker.js +5 -3
- package/dist/components/cms/asset-picker.js.map +1 -1
- package/dist/components/cms/bulk-actions.d.ts +1 -1
- package/dist/components/cms/bulk-actions.js +2 -2
- package/dist/components/cms/bulk-actions.js.map +1 -1
- package/dist/components/cms/bulk-bar.d.ts +2 -2
- package/dist/components/cms/bulk-bar.js +2 -2
- package/dist/components/cms/bulk-bar.js.map +1 -1
- package/dist/components/cms/canvas-commit.d.ts +56 -0
- package/dist/components/cms/canvas-commit.js +35 -0
- package/dist/components/cms/canvas-commit.js.map +1 -0
- package/dist/components/cms/cell-edit.d.ts +1 -1
- package/dist/components/cms/cell-edit.js +1 -1
- package/dist/components/cms/cell-edit.js.map +1 -1
- package/dist/components/cms/cell.d.ts +1 -1
- package/dist/components/cms/cell.js +3 -3
- package/dist/components/cms/cell.js.map +1 -1
- package/dist/components/cms/cms-index.js +2 -2
- package/dist/components/cms/cms-index.js.map +1 -1
- package/dist/components/cms/cms-labels.js +2 -2
- package/dist/components/cms/cms-labels.js.map +1 -1
- package/dist/components/cms/cms-store.d.ts +2 -2
- package/dist/components/cms/cms-store.js +10 -10
- package/dist/components/cms/cms-store.js.map +1 -1
- package/dist/components/cms/collection-table.js +30 -14
- package/dist/components/cms/collection-table.js.map +1 -1
- package/dist/components/cms/commit-policy.d.ts +6 -2
- package/dist/components/cms/commit-policy.js +1 -1
- package/dist/components/cms/commit-policy.js.map +1 -1
- package/dist/components/cms/detail-editor.d.ts +5 -2
- package/dist/components/cms/detail-editor.js +31 -15
- package/dist/components/cms/detail-editor.js.map +1 -1
- package/dist/components/cms/details-pane.js +1 -1
- package/dist/components/cms/details-pane.js.map +1 -1
- package/dist/components/cms/doc-state.js +1 -1
- package/dist/components/cms/doc-state.js.map +1 -1
- package/dist/components/cms/document-diff-view.js +5 -5
- package/dist/components/cms/document-diff-view.js.map +1 -1
- package/dist/components/cms/document-editor-context.js +1 -1
- package/dist/components/cms/document-editor-context.js.map +1 -1
- package/dist/components/cms/document-staging.js +1 -1
- package/dist/components/cms/document-staging.js.map +1 -1
- package/dist/components/cms/document-url-path.js +2 -2
- package/dist/components/cms/document-url-path.js.map +1 -1
- package/dist/components/cms/duplicate-document.d.ts +1 -1
- package/dist/components/cms/duplicate-document.js.map +1 -1
- package/dist/components/cms/editable-cell.js +3 -3
- package/dist/components/cms/editable-cell.js.map +1 -1
- package/dist/components/cms/field-collaboration.d.ts +1 -1
- package/dist/components/cms/field-collaboration.js +1 -1
- package/dist/components/cms/field-collaboration.js.map +1 -1
- package/dist/components/cms/field-connection.d.ts +1 -1
- package/dist/components/cms/field-connection.js +2 -2
- package/dist/components/cms/field-connection.js.map +1 -1
- package/dist/components/cms/field-control-lib.js +1 -1
- package/dist/components/cms/field-control-lib.js.map +1 -1
- package/dist/components/cms/field-control.js +4 -4
- package/dist/components/cms/field-control.js.map +1 -1
- package/dist/components/cms/field-renderer.d.ts +1 -1
- package/dist/components/cms/field-renderer.js +2 -2
- package/dist/components/cms/field-renderer.js.map +1 -1
- package/dist/components/cms/filter-builder.d.ts +1 -1
- package/dist/components/cms/filter-builder.js +3 -3
- package/dist/components/cms/filter-builder.js.map +1 -1
- package/dist/components/cms/gate-validation.js +1 -1
- package/dist/components/cms/gate-validation.js.map +1 -1
- package/dist/components/cms/import-export.js +2 -2
- package/dist/components/cms/import-export.js.map +1 -1
- package/dist/components/cms/issue-copy.js +1 -1
- package/dist/components/cms/issue-copy.js.map +1 -1
- package/dist/components/cms/issues-pane.js +3 -3
- package/dist/components/cms/issues-pane.js.map +1 -1
- package/dist/components/cms/object-array-field.js +2 -2
- package/dist/components/cms/object-array-field.js.map +1 -1
- package/dist/components/cms/prop-fields.js +2 -2
- package/dist/components/cms/prop-fields.js.map +1 -1
- package/dist/components/cms/reference-confirm.d.ts +1 -1
- package/dist/components/cms/reference-confirm.js +2 -2
- package/dist/components/cms/reference-confirm.js.map +1 -1
- package/dist/components/cms/relation-picker.js +2 -2
- package/dist/components/cms/relation-picker.js.map +1 -1
- package/dist/components/cms/rich-text/block-style.js +1 -1
- package/dist/components/cms/rich-text/block-style.js.map +1 -1
- package/dist/components/cms/rich-text/component-embed.js +4 -4
- package/dist/components/cms/rich-text/component-embed.js.map +1 -1
- package/dist/components/cms/rich-text/editor.js +3 -3
- package/dist/components/cms/rich-text/editor.js.map +1 -1
- package/dist/components/cms/rich-text/embed-picker.js +3 -3
- package/dist/components/cms/rich-text/embed-picker.js.map +1 -1
- package/dist/components/cms/rich-text/embed-props.js +3 -3
- package/dist/components/cms/rich-text/embed-props.js.map +1 -1
- package/dist/components/cms/rich-text/extensions.js +1 -1
- package/dist/components/cms/rich-text/extensions.js.map +1 -1
- package/dist/components/cms/rich-text/font-size-control.d.ts +1 -1
- package/dist/components/cms/rich-text/font-size-control.js +2 -2
- package/dist/components/cms/rich-text/font-size-control.js.map +1 -1
- package/dist/components/cms/rich-text/lazy.js +1 -1
- package/dist/components/cms/rich-text/lazy.js.map +1 -1
- package/dist/components/cms/rich-text/link-control.js +2 -2
- package/dist/components/cms/rich-text/link-control.js.map +1 -1
- package/dist/components/cms/rich-text/slash-command.js +3 -3
- package/dist/components/cms/rich-text/slash-command.js.map +1 -1
- package/dist/components/cms/rich-text/toolbar.js +1 -1
- package/dist/components/cms/rich-text/toolbar.js.map +1 -1
- package/dist/components/cms/rich-text/unknown-node.js +2 -2
- package/dist/components/cms/rich-text/unknown-node.js.map +1 -1
- package/dist/components/cms/rich-text-preview.js +2 -2
- package/dist/components/cms/rich-text-preview.js.map +1 -1
- package/dist/components/cms/row-actions.d.ts +1 -1
- package/dist/components/cms/row-actions.js.map +1 -1
- package/dist/components/cms/scalar-value-editor.d.ts +1 -1
- package/dist/components/cms/scalar-value-editor.js +2 -2
- package/dist/components/cms/scalar-value-editor.js.map +1 -1
- package/dist/components/cms/use-discard-controller.d.ts +1 -1
- package/dist/components/cms/use-discard-controller.js +1 -1
- package/dist/components/cms/use-discard-controller.js.map +1 -1
- package/dist/components/cms/use-document-draft.d.ts +69 -5
- package/dist/components/cms/use-document-draft.js +118 -34
- package/dist/components/cms/use-document-draft.js.map +1 -1
- package/dist/components/cms/use-document-versions.js +1 -1
- package/dist/components/cms/use-document-versions.js.map +1 -1
- package/dist/components/cms/use-field-focus.d.ts +1 -1
- package/dist/components/cms/use-field-focus.js +2 -2
- package/dist/components/cms/use-field-focus.js.map +1 -1
- package/dist/components/cms/use-live-url.d.ts +7 -2
- package/dist/components/cms/use-live-url.js +15 -12
- package/dist/components/cms/use-live-url.js.map +1 -1
- package/dist/components/cms/use-publish-controller.d.ts +1 -1
- package/dist/components/cms/use-publish-controller.js +1 -1
- package/dist/components/cms/use-publish-controller.js.map +1 -1
- package/dist/components/cms/use-published-perspective.d.ts +1 -1
- package/dist/components/cms/use-published-perspective.js.map +1 -1
- package/dist/components/cms/use-restore-version.d.ts +1 -1
- package/dist/components/cms/use-restore-version.js +1 -1
- package/dist/components/cms/use-restore-version.js.map +1 -1
- package/dist/components/cms/version-compare-lazy.js +1 -1
- package/dist/components/cms/version-compare-lazy.js.map +1 -1
- package/dist/components/cms/version-compare.js +1 -1
- package/dist/components/cms/version-compare.js.map +1 -1
- package/dist/components/cms/versions-pane.js +3 -3
- package/dist/components/cms/versions-pane.js.map +1 -1
- package/dist/components/cms/view-bar.js +3 -3
- package/dist/components/cms/view-bar.js.map +1 -1
- package/dist/components/collection-view/cms-collection-view-source.d.ts +1 -1
- package/dist/components/collection-view/cms-collection-view-source.js +11 -7
- package/dist/components/collection-view/cms-collection-view-source.js.map +1 -1
- package/dist/components/collection-view/collection-view-context.d.ts +1 -1
- package/dist/components/collection-view/collection-view-context.js +1 -1
- package/dist/components/collection-view/collection-view-context.js.map +1 -1
- package/dist/components/collection-view/collection-view-surface.d.ts +13 -0
- package/dist/components/collection-view/collection-view-surface.js +18 -0
- package/dist/components/collection-view/collection-view-surface.js.map +1 -0
- package/dist/components/components/component-detail.js +10 -10
- package/dist/components/components/component-detail.js.map +1 -1
- package/dist/components/components/component-preview.d.ts +2 -2
- package/dist/components/components/component-preview.js +5 -5
- package/dist/components/components/component-preview.js.map +1 -1
- package/dist/components/components/component-status.d.ts +1 -1
- package/dist/components/components/component-status.js +1 -1
- package/dist/components/components/component-status.js.map +1 -1
- package/dist/components/components/components-index.js +2 -2
- package/dist/components/components/components-index.js.map +1 -1
- package/dist/components/components/field-inspector.js +1 -1
- package/dist/components/components/field-inspector.js.map +1 -1
- package/dist/components/components/registry-browser.js +3 -3
- package/dist/components/components/registry-browser.js.map +1 -1
- package/dist/components/components/taxonomy.d.ts +1 -1
- package/dist/components/components/taxonomy.js.map +1 -1
- package/dist/components/components/transfer-dialog.js +3 -3
- package/dist/components/components/transfer-dialog.js.map +1 -1
- package/dist/components/current-user-menu.js +1 -1
- package/dist/components/current-user-menu.js.map +1 -1
- package/dist/components/delivery-health-banner.js +2 -2
- package/dist/components/delivery-health-banner.js.map +1 -1
- package/dist/components/deployment-setup-gate.js +13 -4
- package/dist/components/deployment-setup-gate.js.map +1 -1
- package/dist/components/dev-login-badge.js +2 -2
- package/dist/components/dev-login-badge.js.map +1 -1
- package/dist/components/guards.js +1 -1
- package/dist/components/guards.js.map +1 -1
- package/dist/components/inspector/document-panes.d.ts +54 -0
- package/dist/components/inspector/document-panes.js +41 -0
- package/dist/components/inspector/document-panes.js.map +1 -0
- package/dist/components/inspector/inspector-sidebar.js +1 -1
- package/dist/components/inspector/inspector-sidebar.js.map +1 -1
- package/dist/components/nav-issues-registry.d.ts +53 -0
- package/dist/components/nav-issues-registry.js +69 -0
- package/dist/components/nav-issues-registry.js.map +1 -0
- package/dist/components/nav-issues.js +4 -4
- package/dist/components/nav-issues.js.map +1 -1
- package/dist/components/operation-error.d.ts +1 -1
- package/dist/components/operation-error.js +4 -4
- package/dist/components/operation-error.js.map +1 -1
- package/dist/components/playground-badge.js +2 -2
- package/dist/components/playground-badge.js.map +1 -1
- package/dist/components/project-list.js +3 -3
- package/dist/components/project-list.js.map +1 -1
- package/dist/components/project-session.d.ts +2 -2
- package/dist/components/project-session.js +5 -5
- package/dist/components/project-session.js.map +1 -1
- package/dist/components/project-switcher.js +2 -2
- package/dist/components/project-switcher.js.map +1 -1
- package/dist/components/rail-store-status.js +1 -1
- package/dist/components/rail-store-status.js.map +1 -1
- package/dist/components/rail-view-source.d.ts +6 -5
- package/dist/components/rail-view-source.js +4 -3
- package/dist/components/rail-view-source.js.map +1 -1
- package/dist/components/records/record-lens.d.ts +51 -0
- package/dist/components/records/record-lens.js +151 -0
- package/dist/components/records/record-lens.js.map +1 -0
- package/dist/components/records/record-rail.d.ts +86 -0
- package/dist/components/records/record-rail.js +241 -0
- package/dist/components/records/record-rail.js.map +1 -0
- package/dist/components/redirects/redirects-schema.js +1 -1
- package/dist/components/redirects/redirects-schema.js.map +1 -1
- package/dist/components/references/references-panel.js +2 -2
- package/dist/components/references/references-panel.js.map +1 -1
- package/dist/components/section-nav.js +27 -11
- package/dist/components/section-nav.js.map +1 -1
- package/dist/components/section-state.js +2 -2
- package/dist/components/section-state.js.map +1 -1
- package/dist/components/section-surface.js +2 -2
- package/dist/components/section-surface.js.map +1 -1
- package/dist/components/session-expired-overlay.js +3 -3
- package/dist/components/session-expired-overlay.js.map +1 -1
- package/dist/components/settings-form.js +1 -1
- package/dist/components/settings-form.js.map +1 -1
- package/dist/components/sign-in-needed-badge.js +1 -1
- package/dist/components/sign-in-needed-badge.js.map +1 -1
- package/dist/components/sign-in-view.d.ts +2 -2
- package/dist/components/sign-in-view.js +5 -5
- package/dist/components/sign-in-view.js.map +1 -1
- package/dist/components/studio-context.js +3 -3
- package/dist/components/studio-context.js.map +1 -1
- package/dist/components/studio-project-screen.js +30 -3
- package/dist/components/studio-project-screen.js.map +1 -1
- package/dist/components/studio-shell.js +6 -5
- package/dist/components/studio-shell.js.map +1 -1
- package/dist/components/theme-context.d.ts +1 -1
- package/dist/components/theme-context.js +2 -2
- package/dist/components/theme-context.js.map +1 -1
- package/dist/components/use-hydration-phase.d.ts +1 -1
- package/dist/components/use-hydration-phase.js +1 -1
- package/dist/components/use-hydration-phase.js.map +1 -1
- package/dist/components/users/invite-user-bar.d.ts +27 -0
- package/dist/components/users/invite-user-bar.js +25 -9
- package/dist/components/users/invite-user-bar.js.map +1 -1
- package/dist/components/users/role-policy-drift-issues.d.ts +38 -0
- package/dist/components/users/role-policy-drift-issues.js +71 -0
- package/dist/components/users/role-policy-drift-issues.js.map +1 -0
- package/dist/components/users/users-collection-view-source.d.ts +1 -1
- package/dist/components/users/users-collection-view-source.js +4 -2
- package/dist/components/users/users-collection-view-source.js.map +1 -1
- package/dist/components/users/users-module.js +1 -1
- package/dist/components/users/users-module.js.map +1 -1
- package/dist/components/users/users-schema.d.ts +10 -1
- package/dist/components/users/users-schema.js +45 -25
- package/dist/components/users/users-schema.js.map +1 -1
- package/dist/components/users/users-store.js +3 -3
- package/dist/components/users/users-store.js.map +1 -1
- package/dist/components/workspace-projects.d.ts +1 -1
- package/dist/components/workspace-projects.js +1 -1
- package/dist/components/workspace-projects.js.map +1 -1
- package/dist/lib/ai/index.d.ts +1 -1
- package/dist/lib/ai/index.js +1 -1
- package/dist/lib/ai/index.js.map +1 -1
- package/dist/lib/ai/node-handler.d.ts +1 -1
- package/dist/lib/ai/node-handler.js.map +1 -1
- package/dist/lib/ai/translate-document.js +1 -1
- package/dist/lib/ai/translate-document.js.map +1 -1
- package/dist/lib/assets/upload.d.ts +25 -7
- package/dist/lib/assets/upload.js +30 -21
- package/dist/lib/assets/upload.js.map +1 -1
- package/dist/lib/clipboard/paste-issues.js +1 -1
- package/dist/lib/clipboard/paste-issues.js.map +1 -1
- package/dist/lib/clipboard/paste-target.js +2 -2
- package/dist/lib/clipboard/paste-target.js.map +1 -1
- package/dist/lib/cms/published-documents.d.ts +24 -6
- package/dist/lib/cms/published-documents.js +39 -6
- package/dist/lib/cms/published-documents.js.map +1 -1
- package/dist/lib/cms-views/view-model.d.ts +12 -99
- package/dist/lib/cms-views/view-model.js +22 -103
- package/dist/lib/cms-views/view-model.js.map +1 -1
- package/dist/lib/collection-view/collection-view-source.d.ts +13 -3
- package/dist/lib/collection-view/collection-view-source.js.map +1 -1
- package/dist/lib/data/content-session-refresh.d.ts +1 -1
- package/dist/lib/data/content-session-refresh.js.map +1 -1
- package/dist/lib/data/playground-unload-guard.d.ts +1 -1
- package/dist/lib/data/playground-unload-guard.js +1 -1
- package/dist/lib/data/playground-unload-guard.js.map +1 -1
- package/dist/lib/engine-version.d.ts +1 -1
- package/dist/lib/engine-version.js +1 -1
- package/dist/lib/engine-version.js.map +1 -1
- package/dist/lib/i18n/i18n.js +1 -1
- package/dist/lib/i18n/i18n.js.map +1 -1
- package/dist/lib/i18n/messages.de.js +11 -3
- package/dist/lib/i18n/messages.de.js.map +1 -1
- package/dist/lib/i18n/messages.en.d.ts +9 -1
- package/dist/lib/i18n/messages.en.js +16 -4
- package/dist/lib/i18n/messages.en.js.map +1 -1
- package/dist/lib/operations/config-manifest-lookup.d.ts +1 -1
- package/dist/lib/operations/config-manifest-lookup.js +3 -3
- package/dist/lib/operations/config-manifest-lookup.js.map +1 -1
- package/dist/lib/operations/project-runtime-config.d.ts +9 -0
- package/dist/lib/operations/project-runtime-config.js +13 -0
- package/dist/lib/operations/project-runtime-config.js.map +1 -1
- package/dist/lib/operations/studio-operations.d.ts +9 -1
- package/dist/lib/operations/studio-operations.js +6 -1
- package/dist/lib/operations/studio-operations.js.map +1 -1
- package/dist/lib/persistence/convex-adapter.d.ts +16 -3
- package/dist/lib/persistence/convex-adapter.js +78 -47
- package/dist/lib/persistence/convex-adapter.js.map +1 -1
- package/dist/lib/persistence/deployment-readiness.js +14 -11
- package/dist/lib/persistence/deployment-readiness.js.map +1 -1
- package/dist/lib/persistence/index.js +14 -1
- package/dist/lib/persistence/index.js.map +1 -1
- package/dist/lib/persona/labels.js +2 -1
- package/dist/lib/persona/labels.js.map +1 -1
- package/dist/lib/query/index.d.ts +2 -2
- package/dist/lib/query/index.js +1 -1
- package/dist/lib/query/index.js.map +1 -1
- package/dist/lib/query/operations-query.d.ts +27 -1
- package/dist/lib/query/operations-query.js +13 -1
- package/dist/lib/query/operations-query.js.map +1 -1
- package/dist/lib/references/reference-model.js +1 -1
- package/dist/lib/references/reference-model.js.map +1 -1
- package/dist/lib/references/references-store.js +1 -1
- package/dist/lib/references/references-store.js.map +1 -1
- package/dist/lib/registry/index.js +2 -2
- package/dist/lib/registry/index.js.map +1 -1
- package/dist/lib/registry/preview.d.ts +10 -0
- package/dist/lib/registry/preview.js +13 -4
- package/dist/lib/registry/preview.js.map +1 -1
- package/dist/lib/routes/route-issues.js +6 -3
- package/dist/lib/routes/route-issues.js.map +1 -1
- package/dist/lib/workspace/index.d.ts +6 -0
- package/dist/lib/workspace/index.js +8 -0
- package/dist/lib/workspace/index.js.map +1 -1
- package/dist/lib/workspace/workspace-source.js +6 -7
- package/dist/lib/workspace/workspace-source.js.map +1 -1
- package/dist/mount.d.ts +28 -0
- package/dist/mount.js +27 -0
- package/dist/mount.js.map +1 -0
- package/dist/previews/entry-node.d.ts +14 -0
- package/dist/previews/entry-node.js +22 -0
- package/dist/previews/entry-node.js.map +1 -0
- package/dist/previews/harness.js +2 -16
- package/dist/previews/harness.js.map +1 -1
- package/dist/router/root.js +10 -10
- package/dist/router/root.js.map +1 -1
- package/dist/ui/badge.d.ts +1 -1
- package/dist/ui/button.d.ts +2 -2
- package/package.json +15 -11
- package/dist/components/redirects/redirects-collection-view-source.d.ts +0 -53
- package/dist/components/redirects/redirects-collection-view-source.js +0 -146
- package/dist/components/redirects/redirects-collection-view-source.js.map +0 -1
- package/dist/components/redirects/redirects-module.d.ts +0 -21
- package/dist/components/redirects/redirects-module.js +0 -40
- package/dist/components/redirects/redirects-module.js.map +0 -1
- package/dist/components/redirects/redirects-store.d.ts +0 -68
- package/dist/components/redirects/redirects-store.js +0 -132
- package/dist/components/redirects/redirects-store.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"row-actions.js","sourceRoot":"","sources":["../../../src/components/cms/row-actions.ts"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,aAAa,CAAC,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAmB;IACvF,MAAM,OAAO,GAAgB,EAAE,CAAA;IAC/B,IAAI,aAAa;QAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACvC,IAAI,YAAY,CAAC,SAAS,IAAI,aAAa;QAAE,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IACtE,IAAI,YAAY,CAAC,OAAO;QAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IAC3E,IAAI,YAAY,CAAC,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC/C,OAAO,OAAO,CAAA;AAChB,CAAC","sourcesContent":["import type { CollectionViewCapabilities } from '
|
|
1
|
+
{"version":3,"file":"row-actions.js","sourceRoot":"","sources":["../../../src/components/cms/row-actions.ts"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,aAAa,CAAC,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAmB;IACvF,MAAM,OAAO,GAAgB,EAAE,CAAA;IAC/B,IAAI,aAAa;QAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IACvC,IAAI,YAAY,CAAC,SAAS,IAAI,aAAa;QAAE,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IACtE,IAAI,YAAY,CAAC,OAAO;QAAE,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IAC3E,IAAI,YAAY,CAAC,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC/C,OAAO,OAAO,CAAA;AAChB,CAAC","sourcesContent":["import type { CollectionViewCapabilities } from '../../lib/collection-view/collection-view-source'\n\n/**\n * EC-316 — the right-edge row `⋮` menu's action vocabulary: the SAME bulk-action\n * set the toolbar's selection actions offer (`bulk-actions.ts`'s `BulkAction`),\n * minus `set-field` (a bulk-only composer over a multi-row selection — a single\n * row edits its fields directly in the table), plus `open` (jump to the detail\n * editor — the row's own affordance the primary-column link already offers, but\n * explicit in the menu for a keyboard/menu-driven workflow), plus `duplicate`\n * (EC-442 — copy the draft into a fresh draft document).\n */\nexport type RowAction = 'open' | 'duplicate' | 'publish' | 'unpublish' | 'delete'\n\nexport interface RowActionsInput {\n /** The rail's capability matrix (AD-19) — the SAME gate the list/edit shells use. */\n capabilities: Pick<CollectionViewCapabilities, 'publish' | 'remove' | 'duplicate'>\n /** Whether this row has a navigable detail route (a rail with no detail surface omits it). */\n hasDetailPath: boolean\n /** Whether this document IS published — decides `publish` vs `unpublish`. */\n published: boolean\n}\n\n/**\n * The gated action list for one row (EC-316). Every entry mirrors a capability\n * the rail actually declares — a source without `publish` never offers\n * publish/unpublish, one without `remove` never offers delete, and a rail with\n * no detail surface never offers `open` — so the SAME menu serves the users\n * rail (EC-240), redirects, and any future `CollectionViewSource` without a\n * bespoke per-rail menu. An empty result means the row menu itself renders\n * nothing (never an empty, useless trigger).\n *\n * `duplicate` (EC-442, amended same day) is gated on its OWN capability flag\n * plus a detail surface to land on — never derived from `create`. The owner\n * call (2026-07-17): CMS collections ONLY; every primitive rail declares\n * `duplicate: false` (identities and uploads aren't copyable content;\n * redirects deferred until requested as a product feature).\n */\nexport function rowActionsFor({ capabilities, hasDetailPath, published }: RowActionsInput): RowAction[] {\n const actions: RowAction[] = []\n if (hasDetailPath) actions.push('open')\n if (capabilities.duplicate && hasDetailPath) actions.push('duplicate')\n if (capabilities.publish) actions.push(published ? 'unpublish' : 'publish')\n if (capabilities.remove) actions.push('delete')\n return actions\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { FilterScalar } from '@elytracms/core/content';
|
|
2
|
-
import type { FilterableFieldOption } from '
|
|
2
|
+
import type { FilterableFieldOption } from '../../lib/cms-views/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* The closed single-scalar value control (EC-247), shared by the filter
|
|
5
5
|
* builder's `eq`/comparison clauses and the bulk set-field action so both
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Input, Select } from '@elytracms/studio/ui';
|
|
4
|
-
import { localizedLabel, translate } from '
|
|
5
|
-
import { scalarFromText } from '
|
|
4
|
+
import { localizedLabel, translate } from '../../lib/i18n/index.js';
|
|
5
|
+
import { scalarFromText } from '../../lib/cms-views/index.js';
|
|
6
6
|
import { DateInput } from './date-input.js';
|
|
7
7
|
import { datePickerBounds } from './date-input-core.js';
|
|
8
8
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scalar-value-editor.js","sourceRoot":"","sources":["../../../src/components/cms/scalar-value-editor.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"scalar-value-editor.js","sourceRoot":"","sources":["../../../src/components/cms/scalar-value-editor.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEpD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,sBAAsB,CAAC,EACrC,MAAM,EACN,KAAK,EACL,MAAM,EACN,SAAS,GAAG,SAAS,CAAC,iBAAiB,CAAC,EACxC,QAAQ,GAQT;IACC,QAAQ,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QAC1B,KAAK,SAAS;YACZ,OAAO,CACL,MAAC,MAAM,kBACO,SAAS,EACrB,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EACxC,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,EAC5D,SAAS,EAAC,yBAAyB,iBACtB,MAAM,aAEnB,iBAAQ,KAAK,EAAC,MAAM,YAAE,SAAS,CAAC,aAAa,CAAC,GAAU,EACxD,iBAAQ,KAAK,EAAC,OAAO,YAAE,SAAS,CAAC,cAAc,CAAC,GAAU,IACnD,CACV,CAAA;QACH,KAAK,QAAQ;YACX,OAAO,CACL,MAAC,MAAM,kBACO,SAAS,EACrB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EACjD,SAAS,EAAC,yBAAyB,iBACtB,MAAM,aAEnB,iBAAQ,KAAK,EAAC,EAAE,uBAAW,EAC1B,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAC/B,iBAAwB,KAAK,EAAE,GAAG,CAAC,KAAK,YACrC,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,IAD1B,GAAG,CAAC,KAAK,CAEb,CACV,CAAC,IACK,CACV,CAAA;QACH,KAAK,MAAM;YACT,wEAAwE;YACxE,uDAAuD;YACvD,OAAO,CACL,KAAC,SAAS,IACR,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,EAC5C,SAAS,EAAC,kBAAkB,EAC5B,MAAM,EAAE,MAAM,KACV,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,GAC3C,CACH,CAAA;QACH,KAAK,QAAQ;YACX,OAAO,CACL,KAAC,eAAe,IACd,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAC1C,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GACtD,CACH,CAAA;QACH;YACE,OAAO,CACL,KAAC,eAAe,IACd,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EACtB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GACtD,CACH,CAAA;IACL,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,OAAO,EACP,IAAI,GAAG,MAAM,EACb,WAAW,EACX,SAAS,GAAG,SAAS,CAAC,iBAAiB,CAAC,EACxC,MAAM,EACN,MAAM,GAQP;IACC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAA;IAC3C,OAAO,CACL,KAAC,KAAK,kBACQ,SAAS,EACrB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,WAAW,IAAI,SAAS,CAAC,4BAA4B,CAAC,EACnE,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;YAClB,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YAC5B,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC5B,CAAC,EACD,SAAS,EAAC,kBAAkB,iBACf,MAAM,GACnB,CACH,CAAA;AACH,CAAC","sourcesContent":["import { useState } from 'react'\nimport type { FilterScalar } from '@elytracms/core/content'\nimport { Input, Select } from '@elytracms/studio/ui'\nimport { localizedLabel, translate } from '../../lib/i18n'\nimport { scalarFromText } from '../../lib/cms-views'\nimport type { FilterableFieldOption } from '../../lib/cms-views'\nimport { DateInput } from './date-input'\nimport { datePickerBounds } from './date-input-core'\n\n/**\n * The closed single-scalar value control (EC-247), shared by the filter\n * builder's `eq`/comparison clauses and the bulk set-field action so both\n * surfaces enter a value the SAME way. It renders exactly the input the field's\n * schema type warrants — a select for boolean/select, a date input, a\n * number/text input otherwise. The `in` multi-value list and the\n * publication-state pseudo field stay in the filter builder: they are\n * filter-only and never a set-field target.\n *\n * It is deliberately *closed* — no field type invents a new control — keeping\n * value entry consistent and agent-inspectable across the two surfaces.\n */\nexport function ScalarFieldValueEditor({\n option,\n value,\n testId,\n ariaLabel = translate('cms.field.value'),\n onChange,\n}: {\n /** The field whose value is being entered (its `def` drives the control). */\n option: FilterableFieldOption | undefined\n value: FilterScalar\n testId: string\n ariaLabel?: string\n onChange: (value: FilterScalar) => void\n}) {\n switch (option?.def?.type) {\n case 'boolean':\n return (\n <Select\n aria-label={ariaLabel}\n value={value === true ? 'true' : 'false'}\n onChange={(event) => onChange(event.target.value === 'true')}\n className=\"h-7 w-auto py-0 text-xs\"\n data-testid={testId}\n >\n <option value=\"true\">{translate('common.true')}</option>\n <option value=\"false\">{translate('common.false')}</option>\n </Select>\n )\n case 'select':\n return (\n <Select\n aria-label={ariaLabel}\n value={String(value)}\n onChange={(event) => onChange(event.target.value)}\n className=\"h-7 w-auto py-0 text-xs\"\n data-testid={testId}\n >\n <option value=\"\">—</option>\n {option.def.options.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {localizedLabel(opt.label, opt.value)}\n </option>\n ))}\n </Select>\n )\n case 'date':\n // EC-463: the shared date control — a segment keystroke never commits a\n // partial year, and pasting/filling an ISO date works.\n return (\n <DateInput\n ariaLabel={ariaLabel}\n value={value}\n onChange={(stored) => onChange(stored ?? '')}\n className=\"h-7 w-36 text-xs\"\n testId={testId}\n {...datePickerBounds(option.def.validation)}\n />\n )\n case 'number':\n return (\n <DraftValueInput\n type=\"number\"\n initial={value === '' ? '' : String(value)}\n ariaLabel={ariaLabel}\n testId={testId}\n onText={(raw) => onChange(scalarFromText(option, raw))}\n />\n )\n default:\n return (\n <DraftValueInput\n initial={String(value)}\n ariaLabel={ariaLabel}\n testId={testId}\n onText={(raw) => onChange(scalarFromText(option, raw))}\n />\n )\n }\n}\n\n/**\n * Text input with a local draft so typing is never re-normalized mid-keystroke\n * (e.g. a trailing comma in a filter `in` list). Remount (key it) when the\n * field/operator changes so the draft resets to the new initial.\n */\nexport function DraftValueInput({\n initial,\n type = 'text',\n placeholder,\n ariaLabel = translate('cms.field.value'),\n testId,\n onText,\n}: {\n initial: string\n type?: 'text' | 'number'\n placeholder?: string\n ariaLabel?: string\n testId: string\n onText: (raw: string) => void\n}) {\n const [draft, setDraft] = useState(initial)\n return (\n <Input\n aria-label={ariaLabel}\n type={type}\n value={draft}\n placeholder={placeholder ?? translate('cms.field.valuePlaceholder')}\n onChange={(event) => {\n setDraft(event.target.value)\n onText(event.target.value)\n }}\n className=\"h-7 w-36 text-xs\"\n data-testid={testId}\n />\n )\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { QueryKey } from '@tanstack/react-query';
|
|
2
2
|
import type { CmsDocument, DocumentRef } from '@elytracms/core/cms-core';
|
|
3
|
-
import type { CollectionViewSource } from '
|
|
3
|
+
import type { CollectionViewSource } from '../../lib/collection-view/collection-view-source.js';
|
|
4
4
|
import type { DiscardDraftStatus } from './discard-draft.js';
|
|
5
5
|
export interface DiscardController {
|
|
6
6
|
status: DiscardDraftStatus;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useState } from 'react';
|
|
2
|
-
import { translate } from '
|
|
2
|
+
import { translate } from '../../lib/i18n/index.js';
|
|
3
3
|
import { discardDraftStatus } from './discard-draft.js';
|
|
4
4
|
import { useRestoreVersion } from './use-restore-version.js';
|
|
5
5
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-discard-controller.js","sourceRoot":"","sources":["../../../src/components/cms/use-discard-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAI7C,OAAO,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"use-discard-controller.js","sourceRoot":"","sources":["../../../src/components/cms/use-discard-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAI7C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAezD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAapC;IACC,MAAM,EACJ,UAAU,EACV,SAAS,EACT,YAAY,EACZ,oBAAoB,EACpB,sBAAsB,EACtB,UAAU,EACV,KAAK,EACL,MAAM,EACN,MAAM,EACN,YAAY,EACZ,KAAK,EACL,IAAI,GACL,GAAG,KAAK,CAAA;IAET,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACrD,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,iBAAiB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAA;IAEtG,MAAM,MAAM,GAAG,kBAAkB,CAAC;QAChC,UAAU;QACV,SAAS;QACT,YAAY;QACZ,iBAAiB,EAAE,oBAAoB;QACvC,KAAK;KACN,CAAC,CAAA;IACF,MAAM,cAAc,GAClB,MAAM,KAAK,gBAAgB;QACzB,CAAC,CAAC,SAAS,CAAC,mCAAmC,CAAC;QAChD,CAAC,CAAC,MAAM,KAAK,YAAY;YACvB,CAAC,CAAC,SAAS,CAAC,qCAAqC,CAAC;YAClD,CAAC,CAAC,MAAM,KAAK,SAAS;gBACpB,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC;gBAC7B,CAAC,CAAC,SAAS,CAAA;IAEnB,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACrC,IAAI,sBAAsB,KAAK,SAAS;YAAE,OAAM;QAChD,IAAI,CAAC;YACH,4EAA4E;YAC5E,+EAA+E;YAC/E,MAAM,OAAO,CAAC,sBAAsB,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QACxD,CAAC;gBAAS,CAAC;YACT,cAAc,CAAC,KAAK,CAAC,CAAA;QACvB,CAAC;IACH,CAAC,EAAE,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC,CAAA;IAErC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,CAAA;AAC/E,CAAC","sourcesContent":["import { useCallback, useState } from 'react'\nimport type { QueryKey } from '@tanstack/react-query'\nimport type { CmsDocument, DocumentRef } from '@elytracms/core/cms-core'\nimport type { CollectionViewSource } from '../../lib/collection-view/collection-view-source'\nimport { translate } from '../../lib/i18n'\nimport { discardDraftStatus } from './discard-draft'\nimport type { DiscardDraftStatus } from './discard-draft'\nimport { useRestoreVersion } from './use-restore-version'\n\nexport interface DiscardController {\n status: DiscardDraftStatus\n /** The hint shown when the item is disabled (view-read-only / up-to-date / loading). */\n disabledReason: string | undefined\n /** Is the confirmation dialog open? */\n confirmOpen: boolean\n setConfirmOpen: (open: boolean) => void\n /** Is a discard restore round-tripping (gates the dialog buttons)? */\n busy: boolean\n /** Confirm the discard: flush → restore the pinned published version whole. */\n discard: () => Promise<void>\n}\n\n/**\n * EC-316 / EC-325 — the \"Discard changes\" controller. Reverting the draft to the\n * published content IS a whole-document restore of the pinned published version,\n * so it routes through the SAME shared restore sequence\n * ({@link useRestoreVersion}) the Compare view's and Versions pane's restores use\n * — never a parallel write path. That sequence flushes a dirty in-memory buffer\n * FIRST (`documents.restore` snapshots whatever is currently PERSISTED), closing\n * the undo-guarantee gap the header's discard used to have.\n *\n * The enablement is the pure `discardDraftStatus` decision (tested in\n * `discard-draft.test.ts`); its semantic-equality edge is the SAME comparator the\n * Versions pane's publish gate uses, so the two never contradict (EC-298).\n */\nexport function useDiscardController(input: {\n canDiscard: boolean\n published: boolean\n viewReadOnly: boolean\n publishedSnapshotDoc: CmsDocument | undefined\n publishedVersionNumber: number | undefined\n versionKey: QueryKey\n draft: CmsDocument\n source: CollectionViewSource\n docRef: DocumentRef\n replaceDraft: (doc: CmsDocument) => void\n dirty: boolean\n save: () => void\n}): DiscardController {\n const {\n canDiscard,\n published,\n viewReadOnly,\n publishedSnapshotDoc,\n publishedVersionNumber,\n versionKey,\n draft,\n source,\n docRef,\n replaceDraft,\n dirty,\n save,\n } = input\n\n const [confirmOpen, setConfirmOpen] = useState(false)\n const { restore, busy } = useRestoreVersion({ source, docRef, versionKey, dirty, save, replaceDraft })\n\n const status = discardDraftStatus({\n canDiscard,\n published,\n viewReadOnly,\n publishedSnapshot: publishedSnapshotDoc,\n draft,\n })\n const disabledReason =\n status === 'view-read-only'\n ? translate('cms.editor.switchToDraftToDiscard')\n : status === 'up-to-date'\n ? translate('cms.editor.discardDraftUpToDateHint')\n : status === 'loading'\n ? translate('common.loading')\n : undefined\n\n const discard = useCallback(async () => {\n if (publishedVersionNumber === undefined) return\n try {\n // Whole-document restore of the pinned published version (the shared helper\n // flushes any dirty buffer first, mirroring the Versions pane / Compare view).\n await restore(publishedVersionNumber, { kind: 'all' })\n } finally {\n setConfirmOpen(false)\n }\n }, [publishedVersionNumber, restore])\n\n return { status, disabledReason, confirmOpen, setConfirmOpen, busy, discard }\n}\n"]}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { PresenceEntry } from '@elytracms/core/persistence';
|
|
2
2
|
import type { CmsDocument, CollectionDef, DocumentPatch, FieldDef, Locale, PropFieldLookup, ValuePath } from '@elytracms/core/cms-core';
|
|
3
|
-
import type { CollectionViewSource } from '
|
|
3
|
+
import type { CollectionViewSource } from '../../lib/collection-view/collection-view-source.js';
|
|
4
|
+
import type { CanvasFieldChange } from '../builder/canvas-rebase.js';
|
|
5
|
+
import type { CommitPolicy } from './commit-policy.js';
|
|
6
|
+
import type { CanvasControlPosition } from './canvas-commit.js';
|
|
4
7
|
import type { Scheduler, UncommittedPosition } from './draft-commit.js';
|
|
5
8
|
/**
|
|
6
9
|
* EC-595 A2 — the detail editor's draft over the revisioned document (and, for the
|
|
@@ -10,7 +13,9 @@ import type { Scheduler, UncommittedPosition } from './draft-commit.js';
|
|
|
10
13
|
* reads it); a field's edit is COMMITTED per its control kind's policy
|
|
11
14
|
* ({@link commitPolicyOf} / {@link createDraftCommitter}) as the patch of the position it
|
|
12
15
|
* wrote — never a document. The canvas commits each action's node patches at once
|
|
13
|
-
* (`compositionPatches`)
|
|
16
|
+
* (`compositionPatches`); a burst of typing in one of its inspector controls is that
|
|
17
|
+
* control's uncommitted position, committed on its kind's policy like a form field
|
|
18
|
+
* (EC-630, `canvas-commit.ts`). The draft REBASES whenever the session's document changes
|
|
14
19
|
* (a write result, a colleague's change by subscription, a resolved conflict): it is the
|
|
15
20
|
* session's document with this editor's uncommitted positions laid over it — local wins
|
|
16
21
|
* until committed, then the per-path check decides (EC-595 point 7).
|
|
@@ -42,6 +47,35 @@ export declare function positionPatch(doc: CmsDocument, path: ValuePath): Docume
|
|
|
42
47
|
* over it, values from the editor's current draft.
|
|
43
48
|
*/
|
|
44
49
|
export declare function rebaseDraft(sessionDoc: CmsDocument, draft: CmsDocument, uncommitted: readonly UncommittedPosition[]): CmsDocument;
|
|
50
|
+
/**
|
|
51
|
+
* EC-630 — the canvas's write into the draft (pure). The canvas writer's node patches,
|
|
52
|
+
* keyed by node id, are the canvas's OWN delta: from `base`, the value it last agreed on
|
|
53
|
+
* with the draft, to `value` — never a document diff, and never measured against the
|
|
54
|
+
* draft's CURRENT value (a colleague's change that reached the draft a moment before the
|
|
55
|
+
* edit lifted would read as part of the edit, and its patches would revert it). The draft
|
|
56
|
+
* takes the delta over whatever it holds now (normally `base` itself) and canonicalises the
|
|
57
|
+
* field through the write lens. `undefined` when the canvas changed nothing.
|
|
58
|
+
*/
|
|
59
|
+
export declare function canvasWrite(input: {
|
|
60
|
+
collection: CollectionDef;
|
|
61
|
+
draft: CmsDocument;
|
|
62
|
+
field: string;
|
|
63
|
+
locale: Locale;
|
|
64
|
+
value: unknown;
|
|
65
|
+
base: unknown;
|
|
66
|
+
lookupManifest: PropFieldLookup;
|
|
67
|
+
}): {
|
|
68
|
+
next: CmsDocument;
|
|
69
|
+
patches: DocumentPatch[];
|
|
70
|
+
} | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* EC-630 — the change of the canvas field made UNDERNEATH the canvas when the draft
|
|
73
|
+
* rebased from `previous` to `next` (pure), numbered after `last`; `undefined` when the
|
|
74
|
+
* field did not move. The canvas's own edits are in both values (the session's view holds
|
|
75
|
+
* every patch it committed, the draft overlays every position it has not), so the change
|
|
76
|
+
* is someone else's: a colleague's patch, a write's canonical row, a resolved conflict.
|
|
77
|
+
*/
|
|
78
|
+
export declare function canvasFieldChange(previous: CmsDocument, next: CmsDocument, path: ValuePath, last: CanvasFieldChange | undefined): CanvasFieldChange | undefined;
|
|
45
79
|
/**
|
|
46
80
|
* The reader's "now" for presence liveness: THIS session's own latest heartbeat `at`
|
|
47
81
|
* (written by the same store clock as everyone else's — the playground store runs a
|
|
@@ -61,22 +95,46 @@ export interface DocumentDraft {
|
|
|
61
95
|
setFieldValue(field: FieldDef, value: unknown): void;
|
|
62
96
|
/** A writer that transforms ONE field position (fill / reset from base). */
|
|
63
97
|
editField(field: FieldDef, update: (draft: CmsDocument) => CmsDocument): void;
|
|
64
|
-
/**
|
|
65
|
-
|
|
98
|
+
/**
|
|
99
|
+
* The canvas emitted a new value for its field (node patches, committed at once). `base`
|
|
100
|
+
* is the value the canvas last agreed on with the draft: the canvas writer's delta is
|
|
101
|
+
* `base` → `value`, applied over whatever the draft holds now (EC-630 — a change that
|
|
102
|
+
* landed underneath meanwhile is never reverted by the canvas's own write).
|
|
103
|
+
*/
|
|
104
|
+
setCanvasValue(field: FieldDef, value: unknown, base: unknown): void;
|
|
66
105
|
/** The slot alias (a document-level key: a whole-document write at the held revision). */
|
|
67
106
|
setAlias(alias: string | undefined): void;
|
|
68
107
|
/** Field boundary events (focus / blur / Enter) — the commit policy's triggers. */
|
|
69
108
|
focused(field: FieldDef): void;
|
|
70
109
|
blurred(field: FieldDef): void;
|
|
71
110
|
entered(field: FieldDef): void;
|
|
111
|
+
/**
|
|
112
|
+
* EC-630 — the canvas inspector's boundary events: a control writing `position` of the
|
|
113
|
+
* canvas field `field`, committing on `policy` (THE declaration for its kind). A burst of
|
|
114
|
+
* typing in it is its uncommitted position until blur / Enter / the idle pause.
|
|
115
|
+
*/
|
|
116
|
+
canvasFocused(field: FieldDef, position: CanvasControlPosition, policy: CommitPolicy): void;
|
|
117
|
+
canvasBlurred(field: FieldDef, position: CanvasControlPosition): void;
|
|
118
|
+
canvasEntered(field: FieldDef, position: CanvasControlPosition): void;
|
|
72
119
|
/** The forced commit (sync; the persister serialises what follows) / the record model's Save. */
|
|
73
120
|
save(): void;
|
|
74
121
|
/** The FORCED FLUSH: commit everything uncommitted and await persistence. */
|
|
75
122
|
flush(): Promise<void>;
|
|
76
123
|
/** Adopt a draft from outside (a restored version). */
|
|
77
124
|
replaceDraft(next: CmsDocument): void;
|
|
78
|
-
/**
|
|
125
|
+
/**
|
|
126
|
+
* Bumped when the canvas must remount from the draft: a restored version replaced the
|
|
127
|
+
* document, or a locale switch pointed the canvas at another bucket. (A change made
|
|
128
|
+
* underneath the canvas is NOT a remount — {@link canvasChange}.)
|
|
129
|
+
*/
|
|
79
130
|
canvasNonce: number;
|
|
131
|
+
/**
|
|
132
|
+
* EC-630 — the latest change of the canvas field's value made UNDERNEATH the canvas (a
|
|
133
|
+
* colleague's patch by subscription, a write's canonical row, a resolved conflict): the
|
|
134
|
+
* draft's value before and after it. The canvas REBASES onto it — the change lands, its
|
|
135
|
+
* undo history and selection survive — where it used to remount and lose both.
|
|
136
|
+
*/
|
|
137
|
+
canvasChange: CanvasFieldChange | undefined;
|
|
80
138
|
/** The OTHER sessions present on this document, live by the reader's clock. */
|
|
81
139
|
presence: readonly PresenceEntry[];
|
|
82
140
|
}
|
|
@@ -93,4 +151,10 @@ export interface UseDocumentDraftInput {
|
|
|
93
151
|
/** The reader's clock for presence liveness (ISO); `new Date().toISOString()` by default. */
|
|
94
152
|
now?: () => string;
|
|
95
153
|
}
|
|
154
|
+
/**
|
|
155
|
+
* EC-616 — the base a record save is diffed against: the source's value whenever the draft
|
|
156
|
+
* equals it (the record as opened, or as a save came back), else the previous base (the
|
|
157
|
+
* editor has unsaved changes; a change from another writer meanwhile is not theirs). Pure.
|
|
158
|
+
*/
|
|
159
|
+
export declare function recordSaveBase(previous: CmsDocument, draft: CmsDocument, doc: CmsDocument): CmsDocument;
|
|
96
160
|
export declare function useDocumentDraft(input: UseDocumentDraftInput): DocumentDraft;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { PRESENCE_TTL_MS, livePresence, } from '@elytracms/core/persistence';
|
|
3
3
|
import { applyDocumentPatches, formatValuePath, readValueAt, semanticValueEqual, writeField, } from '@elytracms/core/cms-core';
|
|
4
|
-
import { fieldPositionPath } from '
|
|
4
|
+
import { fieldPositionPath } from '../../lib/cms/field-patch.js';
|
|
5
5
|
import { compositionPatches } from '../builder/composition-patches.js';
|
|
6
6
|
import { commitPolicyOf } from './commit-policy.js';
|
|
7
|
+
import { canvasControl, routeCanvasWrite } from './canvas-commit.js';
|
|
7
8
|
import { browserScheduler, createDraftCommitter } from './draft-commit.js';
|
|
8
9
|
/**
|
|
9
10
|
* EC-595 A2 — the detail editor's draft over the revisioned document (and, for the
|
|
@@ -13,7 +14,9 @@ import { browserScheduler, createDraftCommitter } from './draft-commit.js';
|
|
|
13
14
|
* reads it); a field's edit is COMMITTED per its control kind's policy
|
|
14
15
|
* ({@link commitPolicyOf} / {@link createDraftCommitter}) as the patch of the position it
|
|
15
16
|
* wrote — never a document. The canvas commits each action's node patches at once
|
|
16
|
-
* (`compositionPatches`)
|
|
17
|
+
* (`compositionPatches`); a burst of typing in one of its inspector controls is that
|
|
18
|
+
* control's uncommitted position, committed on its kind's policy like a form field
|
|
19
|
+
* (EC-630, `canvas-commit.ts`). The draft REBASES whenever the session's document changes
|
|
17
20
|
* (a write result, a colleague's change by subscription, a resolved conflict): it is the
|
|
18
21
|
* session's document with this editor's uncommitted positions laid over it — local wins
|
|
19
22
|
* until committed, then the per-path check decides (EC-595 point 7).
|
|
@@ -59,6 +62,37 @@ export function rebaseDraft(sessionDoc, draft, uncommitted) {
|
|
|
59
62
|
const patches = uncommitted.map((position) => positionPatch(draft, position.path));
|
|
60
63
|
return applyDocumentPatches({ document: sessionDoc, patches, since: [] }).document;
|
|
61
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* EC-630 — the canvas's write into the draft (pure). The canvas writer's node patches,
|
|
67
|
+
* keyed by node id, are the canvas's OWN delta: from `base`, the value it last agreed on
|
|
68
|
+
* with the draft, to `value` — never a document diff, and never measured against the
|
|
69
|
+
* draft's CURRENT value (a colleague's change that reached the draft a moment before the
|
|
70
|
+
* edit lifted would read as part of the edit, and its patches would revert it). The draft
|
|
71
|
+
* takes the delta over whatever it holds now (normally `base` itself) and canonicalises the
|
|
72
|
+
* field through the write lens. `undefined` when the canvas changed nothing.
|
|
73
|
+
*/
|
|
74
|
+
export function canvasWrite(input) {
|
|
75
|
+
const { collection, draft, field, locale, lookupManifest } = input;
|
|
76
|
+
const path = fieldPositionPath(collection, field, locale);
|
|
77
|
+
const localized = path.length > 1 ? locale : undefined;
|
|
78
|
+
const patches = compositionPatches(input.base, input.value, field, localized);
|
|
79
|
+
if (patches.length === 0)
|
|
80
|
+
return undefined;
|
|
81
|
+
const applied = applyDocumentPatches({ document: draft, patches, since: [] }).document;
|
|
82
|
+
return { next: writeField(collection, draft, field, locale, readValueAt(applied, path), { lookupManifest }), patches };
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* EC-630 — the change of the canvas field made UNDERNEATH the canvas when the draft
|
|
86
|
+
* rebased from `previous` to `next` (pure), numbered after `last`; `undefined` when the
|
|
87
|
+
* field did not move. The canvas's own edits are in both values (the session's view holds
|
|
88
|
+
* every patch it committed, the draft overlays every position it has not), so the change
|
|
89
|
+
* is someone else's: a colleague's patch, a write's canonical row, a resolved conflict.
|
|
90
|
+
*/
|
|
91
|
+
export function canvasFieldChange(previous, next, path, last) {
|
|
92
|
+
const from = readValueAt(previous, path);
|
|
93
|
+
const to = readValueAt(next, path);
|
|
94
|
+
return semanticValueEqual(from, to) ? undefined : { from, to, seq: (last?.seq ?? 0) + 1 };
|
|
95
|
+
}
|
|
62
96
|
/**
|
|
63
97
|
* The reader's "now" for presence liveness: THIS session's own latest heartbeat `at`
|
|
64
98
|
* (written by the same store clock as everyone else's — the playground store runs a
|
|
@@ -71,6 +105,14 @@ export function presenceReaderNow(entries, sessionId, fallback) {
|
|
|
71
105
|
const own = entries.filter((entry) => entry.sessionId === sessionId).map((entry) => entry.at);
|
|
72
106
|
return own.length > 0 ? own.sort().at(-1) : fallback;
|
|
73
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* EC-616 — the base a record save is diffed against: the source's value whenever the draft
|
|
110
|
+
* equals it (the record as opened, or as a save came back), else the previous base (the
|
|
111
|
+
* editor has unsaved changes; a change from another writer meanwhile is not theirs). Pure.
|
|
112
|
+
*/
|
|
113
|
+
export function recordSaveBase(previous, draft, doc) {
|
|
114
|
+
return semanticValueEqual(draft, doc) ? doc : previous;
|
|
115
|
+
}
|
|
74
116
|
export function useDocumentDraft(input) {
|
|
75
117
|
const { source, collection, doc, locale, lookupManifest, canvasField } = input;
|
|
76
118
|
const writes = source.writes;
|
|
@@ -78,6 +120,12 @@ export function useDocumentDraft(input) {
|
|
|
78
120
|
const ref = useMemo(() => ({ collection: doc.collection, id: doc.id }), [doc.collection, doc.id]);
|
|
79
121
|
const [draft, setDraftState] = useState(doc);
|
|
80
122
|
const draftRef = useRef(draft);
|
|
123
|
+
// EC-616: the record as the editor opened it (or as of their last successful save) — the
|
|
124
|
+
// BASE a record rail diffs a save against, so it writes only the editor's changes. It moves
|
|
125
|
+
// only while the draft equals the source's value (at open, and once a save is reflected
|
|
126
|
+
// back): another writer's change arriving mid-edit never becomes the editor's base.
|
|
127
|
+
const baseRef = useRef(doc);
|
|
128
|
+
baseRef.current = recordSaveBase(baseRef.current, draftRef.current, doc);
|
|
81
129
|
const setDraft = useCallback((next) => {
|
|
82
130
|
draftRef.current = next;
|
|
83
131
|
setDraftState(next);
|
|
@@ -88,10 +136,14 @@ export function useDocumentDraft(input) {
|
|
|
88
136
|
// --- Committing --------------------------------------------------------------------
|
|
89
137
|
const writesRef = useRef(documentModel);
|
|
90
138
|
writesRef.current = documentModel;
|
|
139
|
+
/** EC-630 — the canvas inspector controls that took focus, by committer key (their position + policy). */
|
|
140
|
+
const canvasControls = useRef(new Map());
|
|
91
141
|
const committer = useMemo(() => createDraftCommitter({
|
|
92
142
|
policyOf: (name) => {
|
|
93
143
|
const field = fieldsByName.get(name);
|
|
94
|
-
|
|
144
|
+
if (field)
|
|
145
|
+
return commitPolicyOf(field);
|
|
146
|
+
return canvasControls.current.get(name)?.policy ?? 'blur-or-idle';
|
|
95
147
|
},
|
|
96
148
|
commit: (positions) => {
|
|
97
149
|
const target = writesRef.current;
|
|
@@ -104,29 +156,17 @@ export function useDocumentDraft(input) {
|
|
|
104
156
|
}),
|
|
105
157
|
// One committer per open document (the editor is keyed by it).
|
|
106
158
|
[ref]);
|
|
107
|
-
// --- The canvas's value and its
|
|
159
|
+
// --- The canvas's value: its remount and its rebase ------------------------------------
|
|
108
160
|
const canvasPath = canvasField ? fieldPositionPath(collection, canvasField.name, locale) : undefined;
|
|
109
161
|
const canvasPathKey = canvasPath ? formatValuePath(canvasPath) : '';
|
|
110
|
-
const canvasValueRef = useRef(canvasPath ? readValueAt(draft, canvasPath) : undefined);
|
|
111
162
|
const [canvasNonce, setCanvasNonce] = useState(0);
|
|
112
|
-
const
|
|
113
|
-
if (!canvasPath)
|
|
114
|
-
return;
|
|
115
|
-
const value = readValueAt(next, canvasPath);
|
|
116
|
-
if (semanticValueEqual(value, canvasValueRef.current))
|
|
117
|
-
return;
|
|
118
|
-
canvasValueRef.current = value;
|
|
119
|
-
setCanvasNonce((n) => n + 1);
|
|
120
|
-
},
|
|
121
|
-
// The path is keyed by its string form.
|
|
122
|
-
[canvasPathKey]);
|
|
163
|
+
const [canvasChange, setCanvasChange] = useState(undefined);
|
|
123
164
|
// A locale switch points the canvas at another bucket: remount from it.
|
|
124
165
|
const lastCanvasPathKey = useRef(canvasPathKey);
|
|
125
166
|
useEffect(() => {
|
|
126
167
|
if (lastCanvasPathKey.current === canvasPathKey)
|
|
127
168
|
return;
|
|
128
169
|
lastCanvasPathKey.current = canvasPathKey;
|
|
129
|
-
canvasValueRef.current = canvasPath ? readValueAt(draftRef.current, canvasPath) : undefined;
|
|
130
170
|
setCanvasNonce((n) => n + 1);
|
|
131
171
|
}, [canvasPathKey]);
|
|
132
172
|
// --- The rebase (document model) -------------------------------------------------------
|
|
@@ -138,9 +178,15 @@ export function useDocumentDraft(input) {
|
|
|
138
178
|
}
|
|
139
179
|
if (!documentModel)
|
|
140
180
|
return;
|
|
141
|
-
const
|
|
181
|
+
const previous = draftRef.current;
|
|
182
|
+
const next = rebaseDraft(doc, previous, committer.uncommitted());
|
|
142
183
|
setDraft(next);
|
|
143
|
-
|
|
184
|
+
// EC-630: the canvas field moved underneath the canvas — the canvas rebases onto the
|
|
185
|
+
// change (its own edits are in both values: the session's view holds every patch it
|
|
186
|
+
// committed, and the draft overlays every position it has not).
|
|
187
|
+
if (!canvasPath)
|
|
188
|
+
return;
|
|
189
|
+
setCanvasChange((last) => canvasFieldChange(previous, next, canvasPath, last) ?? last);
|
|
144
190
|
}, [doc]);
|
|
145
191
|
// --- Writers ----------------------------------------------------------------------------
|
|
146
192
|
const setFieldValue = useCallback((field, value) => {
|
|
@@ -154,20 +200,23 @@ export function useDocumentDraft(input) {
|
|
|
154
200
|
if (documentModel)
|
|
155
201
|
committer.edited(field.name, fieldPositionPath(collection, field.name, locale));
|
|
156
202
|
}, [collection, locale, setDraft, documentModel, committer]);
|
|
157
|
-
const setCanvasValue = useCallback((field, value) => {
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
setDraft(next);
|
|
163
|
-
canvasValueRef.current = after;
|
|
203
|
+
const setCanvasValue = useCallback((field, value, base) => {
|
|
204
|
+
const write = canvasWrite({ collection, draft: draftRef.current, field: field.name, locale, value, base, lookupManifest });
|
|
205
|
+
if (!write)
|
|
206
|
+
return;
|
|
207
|
+
setDraft(write.next);
|
|
164
208
|
if (!documentModel)
|
|
165
209
|
return;
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
210
|
+
// EC-630: a burst of typing in a focused inspector control is that control's
|
|
211
|
+
// uncommitted position (its policy commits it); a canvas action commits now.
|
|
212
|
+
const focus = committer.focusedField();
|
|
213
|
+
routeCanvasWrite({
|
|
214
|
+
patches: write.patches,
|
|
215
|
+
focused: focus === undefined ? undefined : canvasControls.current.get(focus),
|
|
216
|
+
committer,
|
|
217
|
+
commitNow: (patches) => void documentModel.commit(ref, patches),
|
|
218
|
+
});
|
|
219
|
+
}, [collection, locale, lookupManifest, setDraft, documentModel, ref, committer]);
|
|
171
220
|
const setAlias = useCallback((alias) => {
|
|
172
221
|
const next = { ...draftRef.current };
|
|
173
222
|
if (alias === undefined)
|
|
@@ -185,7 +234,7 @@ export function useDocumentDraft(input) {
|
|
|
185
234
|
if (documentModel)
|
|
186
235
|
committer.commitAll();
|
|
187
236
|
else if (writes.kind === 'record')
|
|
188
|
-
writes.save(draftRef.current);
|
|
237
|
+
writes.save(draftRef.current, baseRef.current);
|
|
189
238
|
}, [documentModel, committer, writes]);
|
|
190
239
|
const flush = useCallback(async () => {
|
|
191
240
|
save();
|
|
@@ -257,10 +306,41 @@ export function useDocumentDraft(input) {
|
|
|
257
306
|
if (documentModel)
|
|
258
307
|
committer.entered(field.name);
|
|
259
308
|
}, [documentModel, committer]);
|
|
309
|
+
// EC-630 — the canvas inspector's commit boundary: a control at a position of the canvas
|
|
310
|
+
// field gained focus, lost it, or saw Enter. Its policy is THE declaration's for its kind.
|
|
311
|
+
const canvasControlOf = useCallback((field, position, policy) => canvasControl(fieldPositionPath(collection, field.name, locale), position, policy), [collection, locale]);
|
|
312
|
+
const canvasFocused = useCallback((field, position, policy) => {
|
|
313
|
+
if (!documentModel)
|
|
314
|
+
return;
|
|
315
|
+
const control = canvasControlOf(field, position, policy);
|
|
316
|
+
canvasControls.current.set(control.key, control);
|
|
317
|
+
committer.focused(control.key);
|
|
318
|
+
focusedPathRef.current = control.path;
|
|
319
|
+
heartbeat();
|
|
320
|
+
}, [documentModel, committer, canvasControlOf, heartbeat]);
|
|
321
|
+
const canvasBlurred = useCallback((field, position) => {
|
|
322
|
+
if (!documentModel)
|
|
323
|
+
return;
|
|
324
|
+
const key = canvasControlOf(field, position, 'change').key;
|
|
325
|
+
committer.blurred(key);
|
|
326
|
+
canvasControls.current.delete(key);
|
|
327
|
+
focusedPathRef.current = undefined;
|
|
328
|
+
heartbeat();
|
|
329
|
+
}, [documentModel, committer, canvasControlOf, heartbeat]);
|
|
330
|
+
const canvasEntered = useCallback((field, position) => {
|
|
331
|
+
if (documentModel)
|
|
332
|
+
committer.entered(canvasControlOf(field, position, 'change').key);
|
|
333
|
+
}, [documentModel, committer, canvasControlOf]);
|
|
260
334
|
const replaceDraft = useCallback((next) => {
|
|
335
|
+
// A restored version replaces the document: when it moved the canvas field, the
|
|
336
|
+
// canvas remounts from it (its history belonged to the replaced value).
|
|
337
|
+
const moved = canvasPath && !semanticValueEqual(readValueAt(draftRef.current, canvasPath), readValueAt(next, canvasPath));
|
|
261
338
|
setDraft(next);
|
|
262
|
-
|
|
263
|
-
|
|
339
|
+
if (moved)
|
|
340
|
+
setCanvasNonce((n) => n + 1);
|
|
341
|
+
},
|
|
342
|
+
// The path is keyed by its string form.
|
|
343
|
+
[setDraft, canvasPathKey]);
|
|
264
344
|
const dirty = useMemo(() => !semanticValueEqual(draft, doc), [draft, doc]);
|
|
265
345
|
return {
|
|
266
346
|
draft,
|
|
@@ -273,10 +353,14 @@ export function useDocumentDraft(input) {
|
|
|
273
353
|
focused,
|
|
274
354
|
blurred,
|
|
275
355
|
entered,
|
|
356
|
+
canvasFocused,
|
|
357
|
+
canvasBlurred,
|
|
358
|
+
canvasEntered,
|
|
276
359
|
save,
|
|
277
360
|
flush,
|
|
278
361
|
replaceDraft,
|
|
279
362
|
canvasNonce,
|
|
363
|
+
canvasChange,
|
|
280
364
|
presence,
|
|
281
365
|
};
|
|
282
366
|
}
|