canopycms 0.0.68-int.98 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2131 -0
- package/README.md +47 -63
- package/dist/ai/generate.d.ts +5 -0
- package/dist/ai/generate.js +244 -115
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/json-to-markdown.d.ts +21 -1
- package/dist/ai/json-to-markdown.js +120 -57
- package/dist/ai/references.d.ts +72 -0
- package/dist/ai/references.js +223 -0
- package/dist/ai/resolve-branch.js +9 -2
- package/dist/ai/to-plain-text.d.ts +17 -8
- package/dist/ai/to-plain-text.js +18 -15
- package/dist/ai/types.d.ts +84 -3
- package/dist/api/admin-branch-health.d.ts +24 -1
- package/dist/api/admin-branch-health.js +52 -20
- package/dist/api/admin.d.ts +23 -5
- package/dist/api/admin.js +36 -1
- package/dist/api/assets.js +88 -78
- package/dist/api/branch-create-window.d.ts +12 -0
- package/dist/api/branch-create-window.js +13 -0
- package/dist/api/branch-merge.d.ts +1 -1
- package/dist/api/branch-merge.js +1 -1
- package/dist/api/branch-review.d.ts +3 -3
- package/dist/api/branch-review.js +16 -7
- package/dist/api/branch-status.d.ts +16 -6
- package/dist/api/branch-status.js +57 -12
- package/dist/api/branch-withdraw.d.ts +2 -2
- package/dist/api/branch-withdraw.js +8 -3
- package/dist/api/branch.d.ts +25 -12
- package/dist/api/branch.js +164 -103
- package/dist/api/client.d.ts +78 -58
- package/dist/api/client.js +150 -117
- package/dist/api/comments.d.ts +12 -3
- package/dist/api/comments.js +118 -9
- package/dist/api/content.d.ts +9 -9
- package/dist/api/content.js +131 -22
- package/dist/api/entries-constants.d.ts +14 -3
- package/dist/api/entries-constants.js +14 -3
- package/dist/api/entries.d.ts +40 -2
- package/dist/api/entries.js +102 -6
- package/dist/api/github-sync.d.ts +19 -0
- package/dist/api/github-sync.js +50 -3
- package/dist/api/groups.d.ts +4 -4
- package/dist/api/groups.js +2 -1
- package/dist/api/guards.js +23 -3
- package/dist/api/index.d.ts +3 -1
- package/dist/api/index.js +1 -0
- package/dist/api/permissions.d.ts +21 -2
- package/dist/api/permissions.js +50 -3
- package/dist/api/request-deadline.d.ts +59 -0
- package/dist/api/request-deadline.js +73 -0
- package/dist/api/resolve-references.js +8 -7
- package/dist/api/route-builder.d.ts +14 -0
- package/dist/api/route-builder.js +14 -1
- package/dist/api/schema.d.ts +11 -9
- package/dist/api/schema.js +2 -0
- package/dist/api/settings-helpers.d.ts +5 -1
- package/dist/api/settings-helpers.js +10 -2
- package/dist/api/types.d.ts +18 -0
- package/dist/api/users-constants.d.ts +6 -0
- package/dist/api/users-constants.js +6 -0
- package/dist/assets/asset-url.d.ts +28 -16
- package/dist/assets/asset-url.js +51 -25
- package/dist/assets/finalize.js +3 -0
- package/dist/assets/index.d.ts +1 -1
- package/dist/assets/materialize.d.ts +153 -0
- package/dist/assets/materialize.js +402 -0
- package/dist/assets/store-local.d.ts +19 -5
- package/dist/assets/store-local.js +69 -10
- package/dist/assets/store-s3.d.ts +38 -7
- package/dist/assets/store-s3.js +128 -22
- package/dist/assets/transform-directives.d.ts +52 -13
- package/dist/assets/transform-directives.js +87 -27
- package/dist/assets/transform.d.ts +3 -3
- package/dist/assets/transform.js +13 -8
- package/dist/assets/types.d.ts +31 -4
- package/dist/auth/cache.d.ts +1 -1
- package/dist/auth/cache.js +1 -1
- package/dist/auth/caching-auth-plugin.d.ts +2 -0
- package/dist/auth/caching-auth-plugin.js +12 -2
- package/dist/auth/file-based-auth-cache.d.ts +8 -0
- package/dist/auth/file-based-auth-cache.js +18 -8
- package/dist/auth/person-name.d.ts +5 -0
- package/dist/auth/person-name.js +8 -0
- package/dist/auth/plugin.d.ts +10 -1
- package/dist/auth/types.d.ts +2 -0
- package/dist/auth/user-metadata-lookup.d.ts +21 -0
- package/dist/auth/user-metadata-lookup.js +116 -0
- package/dist/authorization/branch.d.ts +1 -1
- package/dist/authorization/branch.js +12 -13
- package/dist/authorization/groups/schema.d.ts +4 -4
- package/dist/authorization/helpers.d.ts +8 -0
- package/dist/authorization/helpers.js +8 -0
- package/dist/authorization/index.d.ts +1 -1
- package/dist/authorization/index.js +1 -1
- package/dist/authorization/protected-branch.d.ts +5 -4
- package/dist/authorization/protected-branch.js +7 -5
- package/dist/branch-health.d.ts +35 -8
- package/dist/branch-health.js +54 -18
- package/dist/branch-metadata-error.d.ts +27 -0
- package/dist/branch-metadata-error.js +23 -0
- package/dist/branch-metadata-file.d.ts +205 -24
- package/dist/branch-metadata-file.js +126 -25
- package/dist/branch-metadata.d.ts +45 -6
- package/dist/branch-metadata.js +142 -50
- package/dist/branch-provisioning.d.ts +167 -0
- package/dist/branch-provisioning.js +501 -0
- package/dist/branch-registry.d.ts +8 -0
- package/dist/branch-registry.js +61 -9
- package/dist/branch-schema-cache.d.ts +29 -12
- package/dist/branch-schema-cache.js +64 -21
- package/dist/branch-sparse.d.ts +23 -0
- package/dist/branch-sparse.js +118 -0
- package/dist/branch-workspace.d.ts +42 -3
- package/dist/branch-workspace.js +239 -100
- package/dist/build/asset-refs.d.ts +94 -0
- package/dist/build/asset-refs.js +267 -0
- package/dist/build/generate-ai-content.js +5 -0
- package/dist/build/inline-flight.d.ts +37 -0
- package/dist/build/inline-flight.js +142 -0
- package/dist/cli/asset-refs.d.ts +52 -0
- package/dist/cli/asset-refs.js +194 -0
- package/dist/cli/cli.d.ts +15 -1
- package/dist/cli/cli.js +8543 -3193
- package/dist/cli/configured-asset-store.d.ts +12 -0
- package/dist/cli/configured-asset-store.js +46 -0
- package/dist/cli/generate-ai-content.js +4244 -1072
- package/dist/cli/init.js +217 -126
- package/dist/cli/project-detect.d.ts +2 -0
- package/dist/cli/project-detect.js +2 -0
- package/dist/cli/template-files/Dockerfile.cms.template +13 -5
- package/dist/cli/template-files/cms-stack.ts.template +16 -13
- package/dist/client.d.ts +1 -2
- package/dist/client.js +1 -2
- package/dist/comment-store.d.ts +25 -0
- package/dist/comment-store.js +43 -8
- package/dist/config/flatten.js +2 -0
- package/dist/config/helpers.js +2 -2
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schemas/config.d.ts +12 -29
- package/dist/config/schemas/config.js +9 -12
- package/dist/config/schemas/field.d.ts +3 -0
- package/dist/config/schemas/field.js +58 -4
- package/dist/config/schemas/media.d.ts +4 -13
- package/dist/config/schemas/media.js +5 -8
- package/dist/config/schemas/url.d.ts +2 -20
- package/dist/config/schemas/url.js +2 -25
- package/dist/config/types.d.ts +116 -22
- package/dist/config/types.js +3 -9
- package/dist/config/validation.d.ts +25 -4
- package/dist/config/validation.js +116 -3
- package/dist/content-id-index.js +2 -2
- package/dist/content-index-generation.d.ts +1 -1
- package/dist/content-index-generation.js +1 -1
- package/dist/content-listing.d.ts +10 -1
- package/dist/content-listing.js +22 -5
- package/dist/content-reader.d.ts +9 -0
- package/dist/content-reader.js +16 -11
- package/dist/content-store.d.ts +75 -12
- package/dist/content-store.js +249 -86
- package/dist/content-tree.js +2 -2
- package/dist/context.js +5 -2
- package/dist/dangling-reference-log.d.ts +17 -0
- package/dist/dangling-reference-log.js +29 -0
- package/dist/dev-content-watcher.d.ts +1 -1
- package/dist/dev-content-watcher.js +1 -1
- package/dist/editor/BranchManager.d.ts +23 -7
- package/dist/editor/BranchManager.js +119 -54
- package/dist/editor/CanopyEditor.d.ts +1 -1
- package/dist/editor/CanopyEditor.js +1 -2
- package/dist/editor/CommentsPanel.d.ts +14 -0
- package/dist/editor/CommentsPanel.js +68 -43
- package/dist/editor/Editor.d.ts +11 -5
- package/dist/editor/Editor.js +891 -218
- package/dist/editor/EditorAuthGate.d.ts +7 -1
- package/dist/editor/EditorAuthGate.js +41 -9
- package/dist/editor/EntryNavigator.d.ts +22 -0
- package/dist/editor/EntryNavigator.js +353 -105
- package/dist/editor/FormHeader.d.ts +25 -0
- package/dist/editor/FormHeader.js +82 -0
- package/dist/editor/FormRenderer.d.ts +27 -3
- package/dist/editor/FormRenderer.js +171 -76
- package/dist/editor/PreviewFrame.d.ts +40 -0
- package/dist/editor/PreviewFrame.js +215 -0
- package/dist/editor/PreviewPane.d.ts +47 -0
- package/dist/editor/PreviewPane.js +147 -0
- package/dist/editor/PreviewToolbarTools.d.ts +22 -0
- package/dist/editor/PreviewToolbarTools.js +73 -0
- package/dist/editor/admin/SystemHealthPanel.d.ts +2 -1
- package/dist/editor/admin/SystemHealthPanel.js +163 -33
- package/dist/editor/admin/useSystemHealth.d.ts +18 -0
- package/dist/editor/admin/useSystemHealth.js +70 -1
- package/dist/editor/branch-status.d.ts +17 -0
- package/dist/editor/branch-status.js +29 -0
- package/dist/editor/canopy-path.d.ts +9 -6
- package/dist/editor/canopy-path.js +8 -11
- package/dist/editor/client-reference-resolver.d.ts +43 -16
- package/dist/editor/client-reference-resolver.js +155 -64
- package/dist/editor/comments/BranchComments.d.ts +1 -1
- package/dist/editor/comments/BranchComments.js +2 -2
- package/dist/editor/comments/CloseRefusedNotice.d.ts +4 -0
- package/dist/editor/comments/CloseRefusedNotice.js +7 -0
- package/dist/editor/comments/CommentThreadsPopover.d.ts +47 -0
- package/dist/editor/comments/CommentThreadsPopover.js +274 -0
- package/dist/editor/comments/CommentWriteAlert.d.ts +11 -0
- package/dist/editor/comments/CommentWriteAlert.js +13 -0
- package/dist/editor/comments/EntryComments.d.ts +10 -4
- package/dist/editor/comments/EntryComments.js +14 -17
- package/dist/editor/comments/FieldWrapper.d.ts +18 -4
- package/dist/editor/comments/FieldWrapper.js +62 -28
- package/dist/editor/comments/InlineCommentThread.d.ts +9 -2
- package/dist/editor/comments/InlineCommentThread.js +11 -47
- package/dist/editor/comments/ThreadCarousel.d.ts +1 -1
- package/dist/editor/comments/ThreadCarousel.js +18 -21
- package/dist/editor/comments/ThreadReplyControls.d.ts +28 -0
- package/dist/editor/comments/ThreadReplyControls.js +92 -0
- package/dist/editor/comments/field-comment-context.d.ts +14 -0
- package/dist/editor/comments/field-comment-context.js +14 -0
- package/dist/editor/comments/form-comments.d.ts +48 -0
- package/dist/editor/comments/form-comments.js +178 -0
- package/dist/editor/comments/item-anchor-copy.d.ts +6 -0
- package/dist/editor/comments/item-anchor-copy.js +6 -0
- package/dist/editor/comments/move-focus-if-unmoved.d.ts +6 -0
- package/dist/editor/comments/move-focus-if-unmoved.js +11 -0
- package/dist/editor/comments/popover-placement.d.ts +18 -0
- package/dist/editor/comments/popover-placement.js +58 -0
- package/dist/editor/comments/use-tracked-writes.d.ts +16 -0
- package/dist/editor/comments/use-tracked-writes.js +53 -0
- package/dist/editor/components/BranchAccessList.d.ts +15 -0
- package/dist/editor/components/BranchAccessList.js +52 -0
- package/dist/editor/components/BranchLockBanner.d.ts +22 -0
- package/dist/editor/components/BranchLockBanner.js +39 -0
- package/dist/editor/components/BranchPill.d.ts +32 -0
- package/dist/editor/components/BranchPill.js +33 -0
- package/dist/editor/components/BranchesDrawer.d.ts +11 -0
- package/dist/editor/components/BranchesDrawer.js +5 -0
- package/dist/editor/components/ConfirmDeleteModal.d.ts +6 -1
- package/dist/editor/components/ConfirmDeleteModal.js +3 -2
- package/dist/editor/components/DestructiveMenuItem.d.ts +7 -0
- package/dist/editor/components/DestructiveMenuItem.js +8 -0
- package/dist/editor/components/EditorCrashScreen.d.ts +17 -0
- package/dist/editor/components/EditorCrashScreen.js +22 -0
- package/dist/editor/components/EditorErrorBoundary.d.ts +38 -0
- package/dist/editor/components/EditorErrorBoundary.js +40 -0
- package/dist/editor/components/EditorHeader.d.ts +56 -106
- package/dist/editor/components/EditorHeader.js +130 -131
- package/dist/editor/components/EditorRail.d.ts +49 -0
- package/dist/editor/components/EditorRail.js +65 -0
- package/dist/editor/components/EntryBreadcrumb.d.ts +33 -0
- package/dist/editor/components/EntryBreadcrumb.js +56 -0
- package/dist/editor/components/EntryCreateModal.d.ts +12 -7
- package/dist/editor/components/EntryCreateModal.js +51 -57
- package/dist/editor/components/NoEditPermissionNotice.d.ts +6 -5
- package/dist/editor/components/NoEditPermissionNotice.js +5 -4
- package/dist/editor/components/QuickOpenPalette.d.ts +22 -0
- package/dist/editor/components/QuickOpenPalette.js +66 -0
- package/dist/editor/components/ReadOnlyDraftNotice.d.ts +11 -0
- package/dist/editor/components/ReadOnlyDraftNotice.js +12 -0
- package/dist/editor/components/ReasonedMenuItem.d.ts +15 -0
- package/dist/editor/components/ReasonedMenuItem.js +15 -0
- package/dist/editor/components/ReferencedByList.d.ts +11 -0
- package/dist/editor/components/ReferencedByList.js +28 -0
- package/dist/editor/components/RelativeTime.d.ts +10 -0
- package/dist/editor/components/RelativeTime.js +10 -0
- package/dist/editor/components/RenameEntryModal.d.ts +9 -1
- package/dist/editor/components/RenameEntryModal.js +19 -31
- package/dist/editor/components/RetryToastMessage.d.ts +9 -0
- package/dist/editor/components/RetryToastMessage.js +6 -0
- package/dist/editor/components/SaveAllResult.d.ts +25 -0
- package/dist/editor/components/SaveAllResult.js +86 -0
- package/dist/editor/components/SaveSplitButton.d.ts +30 -0
- package/dist/editor/components/SaveSplitButton.js +108 -0
- package/dist/editor/components/StagedChangesDrawer.d.ts +39 -0
- package/dist/editor/components/StagedChangesDrawer.js +92 -0
- package/dist/editor/components/UnavailableEntryNotice.d.ts +6 -0
- package/dist/editor/components/UnavailableEntryNotice.js +9 -0
- package/dist/editor/components/UnavailableTypeMessage.d.ts +6 -0
- package/dist/editor/components/UnavailableTypeMessage.js +9 -0
- package/dist/editor/components/UndoToastMessage.d.ts +18 -0
- package/dist/editor/components/UndoToastMessage.js +10 -0
- package/dist/editor/components/UserBadge.d.ts +2 -5
- package/dist/editor/components/UserBadge.js +62 -33
- package/dist/editor/components/ValidationSummary.d.ts +14 -0
- package/dist/editor/components/ValidationSummary.js +24 -0
- package/dist/editor/components/index.d.ts +2 -2
- package/dist/editor/components/index.js +2 -2
- package/dist/editor/context/ApiClientContext.d.ts +8 -2
- package/dist/editor/context/ApiClientContext.js +19 -8
- package/dist/editor/context/AssetContext.d.ts +13 -35
- package/dist/editor/context/AssetContext.js +12 -31
- package/dist/editor/context/EditorStateContext.d.ts +4 -4
- package/dist/editor/context/EditorStateContext.js +4 -4
- package/dist/editor/context/SWRProvider.d.ts +3 -3
- package/dist/editor/context/SiteMdxAllowContext.d.ts +4 -0
- package/dist/editor/context/SiteMdxAllowContext.js +7 -0
- package/dist/editor/context/index.d.ts +2 -1
- package/dist/editor/context/index.js +2 -1
- package/dist/editor/contrast.d.ts +19 -0
- package/dist/editor/contrast.js +41 -0
- package/dist/editor/copy.d.ts +18 -0
- package/dist/editor/copy.js +18 -0
- package/dist/editor/editor-config.js +16 -0
- package/dist/editor/editor-utils.d.ts +34 -8
- package/dist/editor/editor-utils.js +42 -20
- package/dist/editor/entry-search.d.ts +20 -0
- package/dist/editor/entry-search.js +34 -0
- package/dist/editor/field-breadcrumb.d.ts +12 -0
- package/dist/editor/field-breadcrumb.js +85 -0
- package/dist/editor/field-props.d.ts +86 -0
- package/dist/editor/field-props.js +27 -0
- package/dist/editor/field-target.d.ts +30 -0
- package/dist/editor/field-target.js +77 -0
- package/dist/editor/fields/BlockField.d.ts +12 -0
- package/dist/editor/fields/BlockField.js +89 -73
- package/dist/editor/fields/CodeField.d.ts +2 -0
- package/dist/editor/fields/CodeField.js +6 -2
- package/dist/editor/fields/DateTimeField.d.ts +4 -29
- package/dist/editor/fields/DateTimeField.js +79 -41
- package/dist/editor/fields/ExpandAllButton.d.ts +6 -0
- package/dist/editor/fields/ExpandAllButton.js +4 -0
- package/dist/editor/fields/FieldCrashFallback.d.ts +17 -0
- package/dist/editor/fields/FieldCrashFallback.js +30 -0
- package/dist/editor/fields/FieldLabel.d.ts +37 -0
- package/dist/editor/fields/FieldLabel.js +19 -0
- package/dist/editor/fields/ImageField.d.ts +4 -0
- package/dist/editor/fields/ImageField.js +29 -14
- package/dist/editor/fields/InlineGroupField.js +4 -3
- package/dist/editor/fields/ItemList.d.ts +42 -0
- package/dist/editor/fields/ItemList.js +130 -0
- package/dist/editor/fields/MarkdownField.d.ts +32 -0
- package/dist/editor/fields/MarkdownField.js +223 -46
- package/dist/editor/fields/MdxImageDialog.js +1 -1
- package/dist/editor/fields/NumberField.d.ts +2 -0
- package/dist/editor/fields/NumberField.js +8 -5
- package/dist/editor/fields/NumberListField.d.ts +2 -0
- package/dist/editor/fields/NumberListField.js +19 -16
- package/dist/editor/fields/ObjectField.d.ts +2 -7
- package/dist/editor/fields/ObjectField.js +15 -5
- package/dist/editor/fields/ObjectListField.d.ts +29 -0
- package/dist/editor/fields/ObjectListField.js +57 -0
- package/dist/editor/fields/ReferenceField.d.ts +2 -0
- package/dist/editor/fields/ReferenceField.js +34 -9
- package/dist/editor/fields/SelectField.d.ts +2 -0
- package/dist/editor/fields/SelectField.js +11 -2
- package/dist/editor/fields/StringListField.d.ts +4 -1
- package/dist/editor/fields/StringListField.js +22 -8
- package/dist/editor/fields/TextField.d.ts +2 -0
- package/dist/editor/fields/TextField.js +6 -2
- package/dist/editor/fields/ToggleField.d.ts +2 -0
- package/dist/editor/fields/ToggleField.js +8 -3
- package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +1 -1
- package/dist/editor/fields/entry-link/InsertEntryLink.js +1 -1
- package/dist/editor/fields/form-expansion.d.ts +9 -0
- package/dist/editor/fields/form-expansion.js +2 -0
- package/dist/editor/fields/item-expansion.d.ts +15 -0
- package/dist/editor/fields/item-expansion.js +60 -0
- package/dist/editor/fields/list-item-keys.d.ts +8 -0
- package/dist/editor/fields/list-item-keys.js +50 -0
- package/dist/editor/fields/list-item-title.d.ts +20 -0
- package/dist/editor/fields/list-item-title.js +85 -0
- package/dist/editor/fields/markdown-export-options.d.ts +2 -0
- package/dist/editor/fields/markdown-export-options.js +8 -0
- package/dist/editor/fields/markdown-fidelity-visitors.d.ts +11 -0
- package/dist/editor/fields/markdown-fidelity-visitors.js +160 -0
- package/dist/editor/fields/mdx-jsx-support.d.ts +5 -1
- package/dist/editor/fields/mdx-jsx-support.js +157 -69
- package/dist/editor/fields/rich-text-failures.d.ts +5 -0
- package/dist/editor/fields/rich-text-failures.js +26 -0
- package/dist/editor/fields/toolbar-wrap.d.ts +7 -0
- package/dist/editor/fields/toolbar-wrap.js +35 -0
- package/dist/editor/form-outline.d.ts +13 -0
- package/dist/editor/form-outline.js +70 -0
- package/dist/editor/group-manager/GroupCard.d.ts +4 -1
- package/dist/editor/group-manager/GroupCard.js +12 -3
- package/dist/editor/group-manager/GroupForm.js +1 -1
- package/dist/editor/group-manager/InternalGroupsTab.d.ts +2 -1
- package/dist/editor/group-manager/InternalGroupsTab.js +4 -4
- package/dist/editor/group-manager/MemberList.d.ts +2 -1
- package/dist/editor/group-manager/MemberList.js +15 -4
- package/dist/editor/group-manager/hooks/useGroupState.d.ts +5 -0
- package/dist/editor/group-manager/hooks/useGroupState.js +30 -7
- package/dist/editor/group-manager/index.js +34 -5
- package/dist/editor/group-manager/types.d.ts +5 -2
- package/dist/editor/hooks/create-branch-request.d.ts +20 -0
- package/dist/editor/hooks/create-branch-request.js +54 -0
- package/dist/editor/hooks/save-all.d.ts +68 -0
- package/dist/editor/hooks/save-all.js +61 -0
- package/dist/editor/hooks/useBranchActions.d.ts +11 -1
- package/dist/editor/hooks/useBranchActions.js +42 -19
- package/dist/editor/hooks/useBranchManager.d.ts +21 -0
- package/dist/editor/hooks/useBranchManager.js +321 -125
- package/dist/editor/hooks/useBranchesData.d.ts +8 -4
- package/dist/editor/hooks/useBranchesData.js +9 -5
- package/dist/editor/hooks/useCommentSystem.d.ts +14 -2
- package/dist/editor/hooks/useCommentSystem.js +79 -55
- package/dist/editor/hooks/useCommentsData.d.ts +11 -7
- package/dist/editor/hooks/useCommentsData.js +20 -19
- package/dist/editor/hooks/useDraftManager.d.ts +77 -3
- package/dist/editor/hooks/useDraftManager.js +887 -94
- package/dist/editor/hooks/useEditorLayout.d.ts +53 -7
- package/dist/editor/hooks/useEditorLayout.js +98 -20
- package/dist/editor/hooks/useEntriesData.d.ts +2 -1
- package/dist/editor/hooks/useEntriesData.js +18 -4
- package/dist/editor/hooks/useEntryManager.d.ts +41 -2
- package/dist/editor/hooks/useEntryManager.js +227 -41
- package/dist/editor/hooks/useGroupManager.js +13 -16
- package/dist/editor/hooks/usePermissionManager.js +14 -6
- package/dist/editor/hooks/usePreviewMarks.d.ts +21 -0
- package/dist/editor/hooks/usePreviewMarks.js +33 -0
- package/dist/editor/hooks/useReferenceResolution.d.ts +10 -3
- package/dist/editor/hooks/useReferenceResolution.js +34 -177
- package/dist/editor/hooks/useSchemaManager.d.ts +25 -6
- package/dist/editor/hooks/useSchemaManager.js +97 -39
- package/dist/editor/hooks/useUserMetadata.d.ts +14 -4
- package/dist/editor/hooks/useUserMetadata.js +76 -47
- package/dist/editor/hooks/user-metadata-batcher.d.ts +8 -0
- package/dist/editor/hooks/user-metadata-batcher.js +33 -0
- package/dist/editor/media/AssetCard.d.ts +6 -7
- package/dist/editor/media/AssetCard.js +24 -31
- package/dist/editor/media/AssetListRow.d.ts +16 -0
- package/dist/editor/media/AssetListRow.js +41 -0
- package/dist/editor/media/CropStep.js +6 -1
- package/dist/editor/media/MediaLibrary.d.ts +4 -3
- package/dist/editor/media/MediaLibrary.js +11 -4
- package/dist/editor/media/MediaLibraryBody.d.ts +3 -3
- package/dist/editor/media/MediaLibraryBody.js +195 -80
- package/dist/editor/media/MediaLibrarySkeleton.d.ts +6 -0
- package/dist/editor/media/MediaLibrarySkeleton.js +14 -0
- package/dist/editor/media/crop-math.d.ts +3 -4
- package/dist/editor/media/crop-math.js +11 -22
- package/dist/editor/media/editor-image-src.d.ts +8 -0
- package/dist/editor/media/editor-image-src.js +10 -0
- package/dist/editor/media/format-bytes.d.ts +2 -0
- package/dist/editor/media/format-bytes.js +23 -0
- package/dist/editor/media/media-library-prefs.d.ts +23 -0
- package/dist/editor/media/media-library-prefs.js +49 -0
- package/dist/editor/media/media-library-view.d.ts +34 -0
- package/dist/editor/media/media-library-view.js +40 -0
- package/dist/editor/media/useAssetLibrary.d.ts +30 -0
- package/dist/editor/media/useAssetLibrary.js +126 -0
- package/dist/editor/media/useStableAssetOrder.d.ts +11 -0
- package/dist/editor/media/useStableAssetOrder.js +37 -0
- package/dist/editor/media/useThumbnailFailure.d.ts +6 -0
- package/dist/editor/media/useThumbnailFailure.js +16 -0
- package/dist/editor/permission-manager/GroupSelector.js +2 -2
- package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -1
- package/dist/editor/permission-manager/PermissionEditor.js +15 -4
- package/dist/editor/permission-manager/PermissionLevelBadge.js +1 -1
- package/dist/editor/permission-manager/PermissionTree.d.ts +1 -1
- package/dist/editor/permission-manager/UserSelector.d.ts +1 -1
- package/dist/editor/permission-manager/UserSelector.js +3 -3
- package/dist/editor/permission-manager/index.js +12 -3
- package/dist/editor/permission-manager/types.d.ts +5 -2
- package/dist/editor/platform.d.ts +3 -0
- package/dist/editor/platform.js +9 -0
- package/dist/editor/preview-asset-base.d.ts +9 -0
- package/dist/editor/preview-asset-base.js +17 -0
- package/dist/editor/preview-bridge.d.ts +51 -27
- package/dist/editor/preview-bridge.js +103 -144
- package/dist/editor/preview-marks.d.ts +15 -0
- package/dist/editor/preview-marks.js +74 -0
- package/dist/editor/preview-path.d.ts +12 -0
- package/dist/editor/preview-path.js +45 -1
- package/dist/editor/preview-scale.d.ts +27 -0
- package/dist/editor/preview-scale.js +34 -0
- package/dist/editor/raw-asset-base.d.ts +5 -0
- package/dist/editor/raw-asset-base.js +14 -0
- package/dist/editor/relative-time.d.ts +4 -4
- package/dist/editor/relative-time.js +16 -8
- package/dist/editor/schema-editor/CollectionEditor.d.ts +20 -3
- package/dist/editor/schema-editor/CollectionEditor.js +361 -62
- package/dist/editor/schema-editor/EntryTypeEditor.d.ts +5 -1
- package/dist/editor/schema-editor/EntryTypeEditor.js +11 -6
- package/dist/editor/schema-editor/collection-draft.d.ts +22 -0
- package/dist/editor/schema-editor/collection-draft.js +40 -0
- package/dist/editor/schema-editor/index.d.ts +1 -1
- package/dist/editor/schema-label.d.ts +10 -0
- package/dist/editor/schema-label.js +17 -0
- package/dist/editor/settings-conflict.d.ts +5 -0
- package/dist/editor/settings-conflict.js +8 -0
- package/dist/editor/shell/ActivityRail.d.ts +37 -0
- package/dist/editor/shell/ActivityRail.js +91 -0
- package/dist/editor/shell/EditorShell.d.ts +17 -0
- package/dist/editor/shell/EditorShell.js +31 -0
- package/dist/editor/shell/PaneLayout.d.ts +28 -0
- package/dist/editor/shell/PaneLayout.js +116 -0
- package/dist/editor/shell/SidePanelHost.d.ts +35 -0
- package/dist/editor/shell/SidePanelHost.js +184 -0
- package/dist/editor/shell/TopBar.d.ts +12 -0
- package/dist/editor/shell/TopBar.js +14 -0
- package/dist/editor/shell/host-chrome.d.ts +16 -0
- package/dist/editor/shell/host-chrome.js +69 -0
- package/dist/editor/slug.d.ts +16 -0
- package/dist/editor/slug.js +43 -0
- package/dist/editor/theme.d.ts +2 -1
- package/dist/editor/theme.js +314 -13
- package/dist/editor/unanswered.d.ts +17 -0
- package/dist/editor/unanswered.js +26 -0
- package/dist/editor/unavailable-entry-type.d.ts +20 -0
- package/dist/editor/unavailable-entry-type.js +28 -0
- package/dist/editor/undo-removal.d.ts +57 -0
- package/dist/editor/undo-removal.js +163 -0
- package/dist/editor/user-display.d.ts +4 -0
- package/dist/editor/user-display.js +5 -0
- package/dist/editor/utils/confirm-modal.d.ts +8 -0
- package/dist/editor/utils/confirm-modal.js +12 -0
- package/dist/editor/utils/editor-errors.d.ts +19 -0
- package/dist/editor/utils/editor-errors.js +32 -0
- package/dist/editor/utils/focus-return.d.ts +56 -0
- package/dist/editor/utils/focus-return.js +106 -0
- package/dist/entry-link-resolver.d.ts +11 -1
- package/dist/entry-link-resolver.js +65 -5
- package/dist/entry-schema-registry.d.ts +3 -3
- package/dist/entry-schema-registry.js +7 -4
- package/dist/entry-schema.d.ts +49 -3
- package/dist/entry-schema.js +18 -0
- package/dist/git-manager.d.ts +172 -10
- package/dist/git-manager.js +449 -107
- package/dist/github-service.d.ts +39 -2
- package/dist/github-service.js +101 -7
- package/dist/http/handler.js +74 -9
- package/dist/http/types.d.ts +2 -0
- package/dist/http/worker-not-ready.d.ts +9 -4
- package/dist/http/worker-not-ready.js +59 -6
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/item-keys.d.ts +46 -0
- package/dist/item-keys.js +235 -0
- package/dist/operating-mode/editor-mode-check.d.ts +15 -0
- package/dist/operating-mode/editor-mode-check.js +24 -0
- package/dist/operating-mode/mode-env.d.ts +13 -14
- package/dist/operating-mode/mode-env.js +13 -14
- package/dist/operating-mode/types.d.ts +2 -2
- package/dist/paths/branch.d.ts +0 -1
- package/dist/paths/branch.js +1 -8
- package/dist/paths/index.d.ts +1 -1
- package/dist/paths/index.js +1 -1
- package/dist/paths/validation.js +0 -2
- package/dist/preview.d.ts +8 -0
- package/dist/preview.js +7 -0
- package/dist/reference-resolver.js +1 -0
- package/dist/resolve-canopy-user.d.ts +1 -1
- package/dist/resolve-canopy-user.js +1 -1
- package/dist/schema/meta-loader.d.ts +18 -8
- package/dist/schema/meta-loader.js +42 -9
- package/dist/schema/registry-fingerprint.d.ts +14 -0
- package/dist/schema/registry-fingerprint.js +63 -0
- package/dist/schema/resolver.d.ts +7 -4
- package/dist/schema/resolver.js +7 -6
- package/dist/schema/schema-store.d.ts +7 -10
- package/dist/schema/schema-store.js +13 -11
- package/dist/schema/schema-unavailable-error.d.ts +11 -0
- package/dist/schema/schema-unavailable-error.js +15 -0
- package/dist/schema/types.d.ts +22 -0
- package/dist/schema-registry-record.d.ts +35 -0
- package/dist/schema-registry-record.js +134 -0
- package/dist/server.d.ts +79 -9
- package/dist/server.js +62 -8
- package/dist/services.d.ts +33 -5
- package/dist/services.js +155 -37
- package/dist/settings-workspace.d.ts +23 -3
- package/dist/settings-workspace.js +159 -45
- package/dist/stamp-on-publish.d.ts +36 -0
- package/dist/stamp-on-publish.js +71 -0
- package/dist/static/index.d.ts +58 -5
- package/dist/static/index.js +133 -3
- package/dist/static/seo.d.ts +5 -5
- package/dist/static/seo.js +5 -5
- package/dist/submission-attribution.d.ts +8 -0
- package/dist/submission-attribution.js +22 -0
- package/dist/system-users.d.ts +12 -0
- package/dist/system-users.js +12 -0
- package/dist/task-queue/cms-task-queue.d.ts +1 -1
- package/dist/task-queue/cms-task-queue.js +1 -1
- package/dist/task-queue/index.d.ts +1 -1
- package/dist/task-queue/index.js +1 -1
- package/dist/task-queue/task-queue.d.ts +6 -0
- package/dist/task-queue/task-queue.js +29 -0
- package/dist/task-queue/worker-status.d.ts +35 -9
- package/dist/task-queue/worker-status.js +84 -17
- package/dist/types.d.ts +90 -9
- package/dist/url-collision.js +3 -3
- package/dist/url-exclusivity-fixtures.d.ts +8 -1
- package/dist/url-exclusivity-fixtures.js +11 -1
- package/dist/user.js +2 -1
- package/dist/utils/atomic-write.js +2 -1
- package/dist/utils/base-branch.d.ts +13 -0
- package/dist/utils/base-branch.js +23 -0
- package/dist/utils/content-serialize.d.ts +15 -7
- package/dist/utils/content-serialize.js +353 -51
- package/dist/utils/content-write-lock.d.ts +6 -1
- package/dist/utils/content-write-lock.js +21 -6
- package/dist/utils/debug.d.ts +1 -1
- package/dist/utils/debug.js +5 -3
- package/dist/utils/error.js +13 -2
- package/dist/utils/escape-text.d.ts +7 -0
- package/dist/utils/escape-text.js +27 -0
- package/dist/utils/fs.d.ts +12 -4
- package/dist/utils/fs.js +18 -5
- package/dist/utils/git.d.ts +21 -1
- package/dist/utils/git.js +63 -8
- package/dist/utils/json-source-splice.d.ts +14 -0
- package/dist/utils/json-source-splice.js +120 -0
- package/dist/utils/markdown-body-splice.d.ts +39 -0
- package/dist/utils/markdown-body-splice.js +421 -0
- package/dist/utils/occ-json-write.js +18 -12
- package/dist/utils/provision-log.d.ts +25 -0
- package/dist/utils/provision-log.js +49 -0
- package/dist/utils/provisioning-lock.d.ts +32 -1
- package/dist/utils/provisioning-lock.js +78 -32
- package/dist/utils/sanitize-href.d.ts +9 -23
- package/dist/utils/sanitize-href.js +14 -28
- package/dist/utils/title-field.d.ts +10 -0
- package/dist/utils/title-field.js +47 -0
- package/dist/utils/yaml-source-splice.d.ts +58 -0
- package/dist/utils/yaml-source-splice.js +515 -0
- package/dist/validation/block-structural-keys.d.ts +1 -1
- package/dist/validation/block-structural-keys.js +1 -1
- package/dist/validation/deletion-checker.d.ts +21 -29
- package/dist/validation/deletion-checker.js +41 -117
- package/dist/validation/entry-validator.d.ts +6 -10
- package/dist/validation/entry-validator.js +19 -26
- package/dist/validation/field-traversal.d.ts +22 -0
- package/dist/validation/field-traversal.js +39 -8
- package/dist/validation/markdown-safety.d.ts +68 -0
- package/dist/validation/markdown-safety.js +596 -0
- package/dist/validation/mdx-allowlist.d.ts +55 -0
- package/dist/validation/mdx-allowlist.js +183 -0
- package/dist/validation/reference-validator.d.ts +2 -0
- package/dist/validation/reference-validator.js +3 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker/branch-policy.d.ts +124 -0
- package/dist/worker/branch-policy.js +243 -0
- package/dist/worker/bundle-header.d.ts +117 -0
- package/dist/worker/bundle-header.js +253 -0
- package/dist/worker/cms-worker.d.ts +236 -142
- package/dist/worker/cms-worker.js +772 -285
- package/dist/worker/gateway-egress.d.ts +43 -0
- package/dist/worker/gateway-egress.js +209 -0
- package/dist/worker/gateway-instance.d.ts +42 -0
- package/dist/worker/gateway-instance.js +129 -0
- package/dist/worker/git-process.d.ts +81 -0
- package/dist/worker/git-process.js +234 -0
- package/dist/worker/git-sync.d.ts +34 -17
- package/dist/worker/git-sync.js +394 -131
- package/dist/worker/github-auth.d.ts +9 -9
- package/dist/worker/github-auth.js +13 -15
- package/dist/worker/github-gateway-http.d.ts +62 -0
- package/dist/worker/github-gateway-http.js +977 -0
- package/dist/worker/github-gateway-wire.d.ts +590 -0
- package/dist/worker/github-gateway-wire.js +488 -0
- package/dist/worker/github-gateway.d.ts +238 -0
- package/dist/worker/github-gateway.js +726 -0
- package/dist/worker/github-mirror-upkeep.d.ts +75 -0
- package/dist/worker/github-mirror-upkeep.js +266 -0
- package/dist/worker/github-mirror.d.ts +364 -0
- package/dist/worker/github-mirror.js +1030 -0
- package/dist/worker/github-transfer.d.ts +56 -0
- package/dist/worker/github-transfer.js +444 -0
- package/dist/worker/history-rewrite.d.ts +4 -5
- package/dist/worker/history-rewrite.js +12 -17
- package/dist/worker/provisioned-workspace.d.ts +5 -5
- package/dist/worker/provisioned-workspace.js +5 -5
- package/dist/worker/rebase.d.ts +1 -1
- package/dist/worker/rebase.js +58 -54
- package/dist/worker/remote-git-maintenance.d.ts +3 -0
- package/dist/worker/remote-git-maintenance.js +12 -0
- package/dist/worker/schema-gate.d.ts +49 -0
- package/dist/worker/schema-gate.js +226 -0
- package/dist/worker/self-checks.d.ts +107 -0
- package/dist/worker/self-checks.js +358 -0
- package/dist/worker/shared-repo-git.d.ts +96 -0
- package/dist/worker/shared-repo-git.js +459 -0
- package/dist/worker/sparse-cone.d.ts +20 -0
- package/dist/worker/sparse-cone.js +136 -0
- package/dist/worker/stale-mirror.d.ts +82 -0
- package/dist/worker/stale-mirror.js +130 -0
- package/dist/worker/task-runner.d.ts +5 -3
- package/dist/worker/task-runner.js +287 -186
- package/dist/worker/worker-context.d.ts +36 -37
- package/package.json +35 -7
- package/dist/editor/EditorPanes.d.ts +0 -10
- package/dist/editor/EditorPanes.js +0 -98
- package/dist/editor/components/EditorFooter.d.ts +0 -11
- package/dist/editor/components/EditorFooter.js +0 -9
- package/dist/editor/components/EditorSidebar.d.ts +0 -67
- package/dist/editor/components/EditorSidebar.js +0 -22
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, useState } from 'react';
|
|
4
|
+
import { ActionIcon, Badge, Box, Button, Group, Popover, ScrollArea, Text, Tooltip, UnstyledButton, VisuallyHidden, } from '@mantine/core';
|
|
5
|
+
import { useIsomorphicEffect } from '@mantine/hooks';
|
|
6
|
+
import { IconChevronsDown, IconChevronsUp, IconListTree } from '@tabler/icons-react';
|
|
7
|
+
/** The padding of the scroller the form sits in, which `shell/PaneLayout.tsx` sets; 0 where unset. */
|
|
8
|
+
const PANE_PADDING = 'var(--canopy-form-pane-padding, 0px)';
|
|
9
|
+
/** Below this header width "Outline" shows its icon alone, so the controls never clip. */
|
|
10
|
+
const COMPACT_WIDTH = 280;
|
|
11
|
+
/** Space kept between the header and a field scrolled up to it. */
|
|
12
|
+
const SCROLL_GAP = 8;
|
|
13
|
+
/** The nearest ancestor that scrolls vertically, which the header sticks within. */
|
|
14
|
+
const scrollerOf = (element) => {
|
|
15
|
+
for (let node = element.parentElement; node; node = node.parentElement) {
|
|
16
|
+
const { overflowY } = getComputedStyle(node);
|
|
17
|
+
if (overflowY === 'auto' || overflowY === 'scroll')
|
|
18
|
+
return node;
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* One level of the outline as a list. A row's name leads with its field's label ("Page sections ›
|
|
24
|
+
* Hero, Welcome"), so rows of two lists are told apart by ear.
|
|
25
|
+
*/
|
|
26
|
+
const OutlineList = ({ nodes, field, nested = false, onChoose }) => (_jsx("ul", { style: { listStyle: 'none', margin: 0, paddingLeft: nested ? 16 : 0 }, children: nodes.map((node, idx) => {
|
|
27
|
+
const name = node.secondary ? `${node.label}, ${node.secondary}` : node.label;
|
|
28
|
+
return (_jsxs("li", { children: [node.path === undefined ? (_jsx(Text, { size: "xs", fw: 600, c: "dimmed", px: "xs", pt: 6, pb: 2, children: node.label })) : (_jsx(UnstyledButton, { onClick: () => onChoose(node.path), "aria-label": field ? `${field} › ${name}` : undefined, display: "block", w: "100%", py: 4, px: "xs", style: { borderRadius: 'var(--mantine-radius-sm)' }, className: "canopy-outline-item", "data-testid": "form-outline-item", children: _jsxs(Text, { size: "sm", truncate: "end", fw: field ? undefined : 500, children: [node.label, node.secondary && (_jsxs(Text, { span: true, c: "dimmed", size: "sm", children: [' ', node.secondary] }))] }) })), node.children && node.children.length > 0 && (_jsx(OutlineList, { nodes: node.children, field: node.path === undefined ? undefined : node.label, nested: true, onChoose: onChoose }))] }, node.path ?? `group-${idx}`));
|
|
29
|
+
}) }));
|
|
30
|
+
/**
|
|
31
|
+
* The form's sticky header: which entry this is, an outline of its fields to jump to, and
|
|
32
|
+
* Expand all / Collapse all for every list and block field in it.
|
|
33
|
+
*/
|
|
34
|
+
export const FormHeader = ({ title, typeLabel, outline, onSelect, onExpandAll, }) => {
|
|
35
|
+
const [outlineOpen, setOutlineOpen] = useState(false);
|
|
36
|
+
const [compact, setCompact] = useState(false);
|
|
37
|
+
const headerRef = useRef(null);
|
|
38
|
+
// Its scroller pads its scroll edge by the header's height and a gap, so a field scrolled to the
|
|
39
|
+
// top, as `scrollIntoView` does, lands below the header rather than under it.
|
|
40
|
+
useIsomorphicEffect(() => {
|
|
41
|
+
const header = headerRef.current;
|
|
42
|
+
if (!header)
|
|
43
|
+
return;
|
|
44
|
+
const scroller = scrollerOf(header);
|
|
45
|
+
const previous = scroller?.style.scrollPaddingTop ?? '';
|
|
46
|
+
const measure = () => {
|
|
47
|
+
if (scroller)
|
|
48
|
+
scroller.style.scrollPaddingTop = `${header.offsetHeight + SCROLL_GAP}px`;
|
|
49
|
+
setCompact(header.clientWidth > 0 && header.clientWidth < COMPACT_WIDTH);
|
|
50
|
+
};
|
|
51
|
+
measure();
|
|
52
|
+
const observer = typeof ResizeObserver === 'function' ? new ResizeObserver(measure) : undefined;
|
|
53
|
+
observer?.observe(header);
|
|
54
|
+
return () => {
|
|
55
|
+
observer?.disconnect();
|
|
56
|
+
if (scroller)
|
|
57
|
+
scroller.style.scrollPaddingTop = previous;
|
|
58
|
+
};
|
|
59
|
+
}, []);
|
|
60
|
+
return (_jsxs(Box, { ref: headerRef, "data-testid": "form-header", style: {
|
|
61
|
+
// Bleeds over the form pane's padding, so it spans the pane and sticks to its very top.
|
|
62
|
+
position: 'sticky',
|
|
63
|
+
top: `calc(-1 * ${PANE_PADDING})`,
|
|
64
|
+
zIndex: 3,
|
|
65
|
+
margin: `calc(-1 * ${PANE_PADDING}) calc(-1 * ${PANE_PADDING}) 0`,
|
|
66
|
+
padding: `8px ${PANE_PADDING}`,
|
|
67
|
+
backgroundColor: 'var(--canopy-surface-muted)',
|
|
68
|
+
borderBottom: '1px solid var(--mantine-color-default-border)',
|
|
69
|
+
}, children: [_jsxs(Group, { gap: "xs", wrap: "nowrap", children: [_jsx(Text, { fw: 600, size: "sm", truncate: "end", style: { minWidth: 0 }, children: title }), typeLabel && (_jsx(Badge, { variant: "light", color: "gray", size: "sm", tt: "none",
|
|
70
|
+
// Gives way before the title in a narrow pane.
|
|
71
|
+
style: { flexShrink: 2, minWidth: 0 }, children: typeLabel })), _jsxs(Group, { gap: 4, wrap: "nowrap", ml: "auto", style: { flexShrink: 0 }, children: [_jsxs(Popover, { opened: outlineOpen, onChange: setOutlineOpen, position: "bottom-end", width: 300, shadow: "md", withinPortal: true,
|
|
72
|
+
// Focus enters the list; Escape hands it back to "Outline" (`closeOnEscape`). A chosen
|
|
73
|
+
// field takes it instead, so closing returns it nowhere.
|
|
74
|
+
trapFocus: true, returnFocus: false, children: [_jsx(Tooltip, { label: "Outline", disabled: !compact, opened: compact ? undefined : false, children: _jsx(Popover.Target, { children: _jsx(Button, { variant: "subtle", color: "gray", c: "dimmed", size: "compact-sm", px: compact ? 6 : undefined, leftSection: _jsx(IconListTree, { size: 14, "aria-hidden": true }), styles: compact ? { section: { marginInlineEnd: 0 } } : undefined, onClick: () => setOutlineOpen((open) => !open), "data-testid": "form-outline-button", children: compact ? _jsx(VisuallyHidden, { children: "Outline" }) : 'Outline' }) }) }), _jsx(Popover.Dropdown, { p: 4, children: _jsx(ScrollArea.Autosize, { mah: 400, type: "auto", children: _jsx("nav", { "aria-label": "Outline", "data-testid": "form-outline", children: _jsx(OutlineList, { nodes: outline, onChoose: (path) => {
|
|
75
|
+
setOutlineOpen(false);
|
|
76
|
+
onSelect(path);
|
|
77
|
+
} }) }) }) })] }), onExpandAll && (_jsxs(_Fragment, { children: [_jsx(Tooltip, { label: "Expand all lists", children: _jsx(ActionIcon, { variant: "subtle", color: "gray", "aria-label": "Expand all lists", onClick: () => onExpandAll(true), "data-testid": "form-expand-all", children: _jsx(IconChevronsDown, { size: 16, "aria-hidden": true }) }) }), _jsx(Tooltip, { label: "Collapse all lists", children: _jsx(ActionIcon, { variant: "subtle", color: "gray", "aria-label": "Collapse all lists", onClick: () => onExpandAll(false), "data-testid": "form-collapse-all", children: _jsx(IconChevronsUp, { size: 16, "aria-hidden": true }) }) })] }))] })] }), _jsx("style", { children: `
|
|
78
|
+
.canopy-outline-item:hover, .canopy-outline-item:focus-visible {
|
|
79
|
+
background-color: var(--canopy-surface-muted);
|
|
80
|
+
}
|
|
81
|
+
` })] }));
|
|
82
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { EntrySchema, FieldConfig } from '../config/index.js';
|
|
2
|
+
import type { ContentFormat, EntrySchema, FieldConfig } from '../config/index.js';
|
|
3
3
|
import type { CommentThread } from '../comment-store.js';
|
|
4
|
+
import type { UserSearchResult } from '../auth/types.js';
|
|
5
|
+
import type { FieldRemoval } from './undo-removal.js';
|
|
4
6
|
export type FormValue = Record<string, unknown>;
|
|
5
7
|
export interface CustomFieldRenderProps {
|
|
6
8
|
field: FieldConfig;
|
|
@@ -8,6 +10,8 @@ export interface CustomFieldRenderProps {
|
|
|
8
10
|
onChange: (v: unknown) => void;
|
|
9
11
|
path: Array<string | number>;
|
|
10
12
|
id: string;
|
|
13
|
+
/** The branch is locked (protected, or in review): show the value; `onChange` is ignored. */
|
|
14
|
+
readOnly: boolean;
|
|
11
15
|
}
|
|
12
16
|
export type CustomFieldRenderers = Record<string, (props: CustomFieldRenderProps) => React.ReactNode>;
|
|
13
17
|
export interface FormRendererProps {
|
|
@@ -24,8 +28,6 @@ export interface FormRendererProps {
|
|
|
24
28
|
highlightThreadId?: string;
|
|
25
29
|
onAddComment?: (text: string, type: 'field' | 'entry' | 'branch', entryPath?: string, canopyPath?: string, threadId?: string) => Promise<void>;
|
|
26
30
|
onResolveThread?: (threadId: string) => Promise<void>;
|
|
27
|
-
onResolvedValueChange?: (resolved: FormValue) => void;
|
|
28
|
-
onLoadingStateChange?: (loadingState: FormValue) => void;
|
|
29
31
|
/** True when this entry's content conflicts with a recent change on the base branch */
|
|
30
32
|
conflictNotice?: boolean;
|
|
31
33
|
/**
|
|
@@ -35,5 +37,27 @@ export interface FormRendererProps {
|
|
|
35
37
|
* in useDraftManager and by server 422 rejections.
|
|
36
38
|
*/
|
|
37
39
|
fieldErrors?: Record<string, string>;
|
|
40
|
+
/** The entry's format, which decides how its body field is checked. */
|
|
41
|
+
format?: ContentFormat;
|
|
42
|
+
/** Shows the value without accepting edits. Comments stay open. */
|
|
43
|
+
readOnly?: boolean;
|
|
44
|
+
/** Told of each list item, block or image Remove takes out, or object Clear resets, for Undo. */
|
|
45
|
+
onRemoved?: (removal: FieldRemoval) => void;
|
|
46
|
+
/** Resolves comment authors to names in field and entry threads; without it they show as ids. */
|
|
47
|
+
onGetUserMetadata?: (userId: string) => Promise<UserSearchResult | null>;
|
|
48
|
+
/**
|
|
49
|
+
* Shows a sticky header naming the entry, with an outline of its fields and, when it has list
|
|
50
|
+
* or block fields, Expand all and Collapse all.
|
|
51
|
+
*/
|
|
52
|
+
header?: {
|
|
53
|
+
title: string;
|
|
54
|
+
typeLabel?: string;
|
|
55
|
+
};
|
|
56
|
+
/** An entry-wide notice, shown first under the header. */
|
|
57
|
+
notice?: React.ReactNode;
|
|
58
|
+
/** Why a field can't take a new comment thread yet, such as one inside an unsaved item. */
|
|
59
|
+
commentBlockedReason?: (canopyPath: string) => string | undefined;
|
|
60
|
+
/** Names a removed item's thread's field; else the schema alone does, without the items. */
|
|
61
|
+
removedItemFieldLabel?: (thread: CommentThread) => string | undefined;
|
|
38
62
|
}
|
|
39
63
|
export declare const FormRenderer: React.FC<FormRendererProps>;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { Alert, Stack, Text } from '@mantine/core';
|
|
5
|
+
import { IconInfoCircle } from '@tabler/icons-react';
|
|
5
6
|
import { MarkdownField } from './fields/MarkdownField.js';
|
|
7
|
+
import { useSiteMdxAllow } from './context/index.js';
|
|
8
|
+
import { markdownPolicyOf } from '../validation/mdx-allowlist.js';
|
|
9
|
+
import { findBodyFieldName } from '../utils/body-field.js';
|
|
6
10
|
import { StringListField } from './fields/StringListField.js';
|
|
7
11
|
import { TextField } from './fields/TextField.js';
|
|
8
12
|
import { ToggleField } from './fields/ToggleField.js';
|
|
@@ -15,23 +19,31 @@ import { ReferenceField } from './fields/ReferenceField.js';
|
|
|
15
19
|
import { CodeField } from './fields/CodeField.js';
|
|
16
20
|
import { ImageField } from './fields/ImageField.js';
|
|
17
21
|
import { ObjectField } from './fields/ObjectField.js';
|
|
18
|
-
import {
|
|
22
|
+
import { ObjectListField } from './fields/ObjectListField.js';
|
|
23
|
+
import { listItemTitle } from './fields/list-item-title.js';
|
|
19
24
|
import { InlineGroupField } from './fields/InlineGroupField.js';
|
|
20
25
|
import { formatCanopyPath, normalizeCanopyPath } from './canopy-path.js';
|
|
21
26
|
import { FieldWrapper } from './comments/FieldWrapper.js';
|
|
27
|
+
import { FormCommentsContext, createFormComments } from './comments/form-comments.js';
|
|
22
28
|
import { EntryComments } from './comments/EntryComments.js';
|
|
23
|
-
import {
|
|
29
|
+
import { EditorErrorBoundary } from './components/EditorErrorBoundary.js';
|
|
30
|
+
import { ValidationSummary } from './components/ValidationSummary.js';
|
|
31
|
+
import { fieldBreadcrumb } from './field-breadcrumb.js';
|
|
32
|
+
import { FieldCrashFallback } from './fields/FieldCrashFallback.js';
|
|
33
|
+
import { useListItemKeys } from './fields/list-item-keys.js';
|
|
34
|
+
import { FormExpansionContext } from './fields/form-expansion.js';
|
|
35
|
+
import { FormHeader } from './FormHeader.js';
|
|
36
|
+
import { buildFormOutline, hasCollapsibleList } from './form-outline.js';
|
|
37
|
+
import { findFieldTarget, focusFieldTarget } from './field-target.js';
|
|
38
|
+
import { schemaLabel } from './schema-label.js';
|
|
24
39
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
40
|
+
* How an Undo toast names a removed object-list item: by its title field or first non-empty
|
|
41
|
+
* text field, since a positional "#2" title passes to the next item once this one is gone.
|
|
27
42
|
*/
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (typeof raw === 'string' && raw.trim() !== '')
|
|
33
|
-
return raw.trim();
|
|
34
|
-
return fallback;
|
|
43
|
+
const removedItemLabel = (item, objectField, listLabel, index) => {
|
|
44
|
+
const text = listItemTitle(item, objectField);
|
|
45
|
+
const byPosition = `${objectField.itemLabel ?? 'item'} ${index + 1}`;
|
|
46
|
+
return text ? `"${text}" from ${listLabel}` : `${byPosition} from ${listLabel}`;
|
|
35
47
|
};
|
|
36
48
|
const normalizeOptions = (options) => {
|
|
37
49
|
if (!options)
|
|
@@ -39,22 +51,74 @@ const normalizeOptions = (options) => {
|
|
|
39
51
|
return options.map((opt) => (typeof opt === 'string' ? { label: opt, value: opt } : opt));
|
|
40
52
|
};
|
|
41
53
|
const fieldKey = (path) => formatCanopyPath(path);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
const noop = () => { };
|
|
55
|
+
const FENCE_STYLE = { border: 0, padding: 0, margin: 0, minWidth: 0 };
|
|
56
|
+
const READ_ONLY_FORM_CLASS = 'canopy-read-only-form';
|
|
57
|
+
/**
|
|
58
|
+
* Read-only inputs look disabled but stay focusable, so a reviewer can select and copy them. A
|
|
59
|
+
* picker's trigger is a button, which Mantine marks `data-read-only` instead.
|
|
60
|
+
*/
|
|
61
|
+
const ReadOnlyFormStyles = () => (_jsx("style", { children: `
|
|
62
|
+
.${READ_ONLY_FORM_CLASS} .mantine-Input-input:is([readonly], [data-read-only], :has(input[readonly])) {
|
|
63
|
+
background-color: var(--input-disabled-bg);
|
|
64
|
+
}
|
|
65
|
+
.${READ_ONLY_FORM_CLASS} .canopy-mdx-content {
|
|
66
|
+
background-color: var(--canopy-surface-muted);
|
|
67
|
+
}
|
|
68
|
+
.${READ_ONLY_FORM_CLASS} .mantine-Switch-label {
|
|
69
|
+
color: var(--mantine-color-text);
|
|
70
|
+
}
|
|
71
|
+
` }));
|
|
72
|
+
/**
|
|
73
|
+
* Disables a custom renderer's native controls on a read-only form, whether or not it honours
|
|
74
|
+
* `readOnly`. It wraps the control, never its `FieldWrapper`, so review comments stay open.
|
|
75
|
+
*/
|
|
76
|
+
const ReadOnlyFence = ({ readOnly, children, }) => (_jsx("fieldset", { disabled: readOnly, role: "presentation", style: FENCE_STYLE, children: children }));
|
|
77
|
+
/** Builds the control inside the field's boundary: a custom renderer is called, not mounted. */
|
|
78
|
+
const FieldControl = ({ build }) => _jsx(_Fragment, { children: build() });
|
|
79
|
+
/**
|
|
80
|
+
* One field's error boundary. Every edit callback a field was rendered with before it crashed
|
|
81
|
+
* is dead for good, so nothing it scheduled can land later, even on another entry's draft.
|
|
82
|
+
* Callbacks from renders after the crash, which happen once the boundary resets on an entry or
|
|
83
|
+
* branch change, work.
|
|
84
|
+
*/
|
|
85
|
+
const FieldBoundary = ({ canopyPath, resetKey, update, build, fallback }) => {
|
|
86
|
+
const [generation, setGeneration] = useState(0);
|
|
87
|
+
const liveGeneration = useRef(0);
|
|
88
|
+
const guardedUpdate = (next) => {
|
|
89
|
+
if (liveGeneration.current === generation)
|
|
90
|
+
update(next);
|
|
91
|
+
};
|
|
92
|
+
return (_jsx(EditorErrorBoundary, { context: { boundary: 'field', fieldPath: canopyPath }, resetKey: resetKey, onCaught: () => {
|
|
93
|
+
liveGeneration.current += 1;
|
|
94
|
+
setGeneration(liveGeneration.current);
|
|
95
|
+
}, fallback: fallback, children: _jsx(FieldControl, { build: () => build(guardedUpdate) }) }));
|
|
96
|
+
};
|
|
97
|
+
export const FormRenderer = ({ fields, value, onChange, customRenderers, branch = 'main', comments = [], currentEntryPath, currentUserId, canResolve = false, focusedFieldPath, highlightThreadId, onAddComment, onResolveThread, conflictNotice = false, fieldErrors, format, readOnly = false, onRemoved, onGetUserMetadata, header, notice, commentBlockedReason, removedItemFieldLabel, }) => {
|
|
98
|
+
const emit = readOnly ? noop : onChange;
|
|
99
|
+
const formRef = useRef(null);
|
|
100
|
+
const customTypes = new Set(Object.keys(customRenderers ?? {}));
|
|
101
|
+
const [expansionCommand, setExpansionCommand] = useState();
|
|
102
|
+
const boundaryResetKey = `${branch}\n${currentEntryPath ?? ''}`;
|
|
103
|
+
const siteMdxAllow = useSiteMdxAllow();
|
|
104
|
+
const bodyName = format === 'md' || format === 'mdx' ? findBodyFieldName(fields) : undefined;
|
|
105
|
+
const keysForList = useListItemKeys();
|
|
106
|
+
// Whether a list row holds an error, so a collapsed row can say so.
|
|
107
|
+
const rowHasErrors = (listPath) => (index) => {
|
|
108
|
+
const row = normalizeCanopyPath([...listPath, index]);
|
|
109
|
+
return Object.keys(fieldErrors ?? {}).some((key) => key === row || key.startsWith(`${row}.`) || key.startsWith(`${row}[`));
|
|
110
|
+
};
|
|
111
|
+
const [formComments] = useState(createFormComments);
|
|
112
|
+
// The field last focused on one entry is never offered on the next.
|
|
113
|
+
useEffect(() => formComments.noteFocus(undefined), [formComments, boundaryResetKey]);
|
|
114
|
+
// Wraps the rendered control in an error boundary, and with an inline validation message
|
|
115
|
+
// when this field has an active error (keyed by canonical canopy path, so errors land on
|
|
116
|
+
// nested object/block fields too). Passed down to BlockField/ObjectField so nested fields
|
|
117
|
+
// get the same decoration.
|
|
54
118
|
const renderField = (field, currentValue, update, path) => {
|
|
55
|
-
const
|
|
56
|
-
const error = fieldErrors?.[
|
|
57
|
-
return (_jsxs(Stack, { gap: 4, children: [
|
|
119
|
+
const canopyPath = normalizeCanopyPath(path);
|
|
120
|
+
const error = fieldErrors?.[canopyPath];
|
|
121
|
+
return (_jsxs(Stack, { gap: 4, children: [_jsx(FieldBoundary, { canopyPath: canopyPath, resetKey: boundaryResetKey, update: update, build: (guardedUpdate) => renderFieldControl(field, currentValue, guardedUpdate, path), fallback: (caught) => (_jsx(FieldCrashFallback, { label: schemaLabel(field), fieldType: field.type, value: currentValue, onChange: readOnly ? undefined : update, caught: caught, dataCanopyField: canopyPath })) }), error && (_jsx(Text, { size: "xs", c: "var(--canopy-danger-text)", "data-testid": `field-error-${fieldKey(path)}`, children: error }))] }, fieldKey(path)));
|
|
58
122
|
};
|
|
59
123
|
const renderFieldControl = (field, currentValue, update, path) => {
|
|
60
124
|
const fieldId = `field-${fieldKey(path).replace(/[^a-zA-Z0-9_-]/g, '-')}`;
|
|
@@ -62,49 +126,56 @@ export const FormRenderer = ({ fields, value, onChange, customRenderers, branch
|
|
|
62
126
|
const fieldThreads = currentEntryPath && onAddComment
|
|
63
127
|
? comments.filter((thread) => thread.type === 'field' &&
|
|
64
128
|
thread.entryPath === currentEntryPath &&
|
|
65
|
-
thread.canopyPath === canopyPath
|
|
129
|
+
thread.canopyPath === canopyPath &&
|
|
130
|
+
!thread.onRemovedItem)
|
|
66
131
|
: [];
|
|
132
|
+
// The full breadcrumb, so a list item's or block's fields are told apart by name.
|
|
133
|
+
const commentSubject = fieldBreadcrumb(fields, value, canopyPath).join(' › ');
|
|
67
134
|
const custom = customRenderers?.[field.type];
|
|
68
135
|
if (custom) {
|
|
69
|
-
const renderedField = (_jsx(
|
|
136
|
+
const renderedField = (_jsx(ReadOnlyFence, { readOnly: readOnly, children: custom({
|
|
70
137
|
field,
|
|
71
138
|
value: currentValue,
|
|
72
|
-
onChange: update,
|
|
139
|
+
onChange: readOnly ? noop : update,
|
|
73
140
|
path,
|
|
74
141
|
id: fieldId,
|
|
142
|
+
readOnly,
|
|
75
143
|
}) }, fieldKey(path)));
|
|
76
144
|
if (currentEntryPath && currentUserId && onAddComment && onResolveThread) {
|
|
77
|
-
return (_jsx(FieldWrapper, { canopyPath: canopyPath, entryPath: currentEntryPath, threads: fieldThreads, autoFocus: focusedFieldPath === canopyPath, currentUserId: currentUserId, canResolve: canResolve, onAddComment: onAddComment, onResolveThread: onResolveThread, highlightThreadId: highlightThreadId, children: renderedField }, fieldKey(path)));
|
|
145
|
+
return (_jsx(FieldWrapper, { canopyPath: canopyPath, entryPath: currentEntryPath, threads: fieldThreads, commentBlockedReason: commentBlockedReason?.(canopyPath), autoFocus: focusedFieldPath === canopyPath, currentUserId: currentUserId, canResolve: canResolve, onAddComment: onAddComment, onResolveThread: onResolveThread, highlightThreadId: highlightThreadId, onGetUserMetadata: onGetUserMetadata, fieldLabel: commentSubject, resetKey: boundaryResetKey, controlPlacement: "corner", children: renderedField }, fieldKey(path)));
|
|
78
146
|
}
|
|
79
147
|
return renderedField;
|
|
80
148
|
}
|
|
81
|
-
const label = field
|
|
149
|
+
const label = schemaLabel(field);
|
|
82
150
|
const wrapWithComments = (renderedField) => {
|
|
83
151
|
if (currentEntryPath && currentUserId && onAddComment && onResolveThread) {
|
|
84
|
-
return (_jsx(FieldWrapper, { canopyPath: canopyPath, entryPath: currentEntryPath, threads: fieldThreads, autoFocus: focusedFieldPath === canopyPath, currentUserId: currentUserId, canResolve: canResolve, onAddComment: onAddComment, onResolveThread: onResolveThread, highlightThreadId: highlightThreadId, children: renderedField }));
|
|
152
|
+
return (_jsx(FieldWrapper, { canopyPath: canopyPath, entryPath: currentEntryPath, threads: fieldThreads, commentBlockedReason: commentBlockedReason?.(canopyPath), autoFocus: focusedFieldPath === canopyPath, currentUserId: currentUserId, canResolve: canResolve, onAddComment: onAddComment, onResolveThread: onResolveThread, highlightThreadId: highlightThreadId, onGetUserMetadata: onGetUserMetadata, fieldLabel: commentSubject, resetKey: boundaryResetKey, children: renderedField }));
|
|
85
153
|
}
|
|
86
154
|
return renderedField;
|
|
87
155
|
};
|
|
88
156
|
switch (field.type) {
|
|
89
157
|
case 'string':
|
|
90
158
|
if (field.list) {
|
|
91
|
-
return wrapWithComments(_jsx(StringListField, { id: fieldId, label: label, description: field.description, value: Array.isArray(currentValue) ? currentValue : [], onChange: (v) => update(v), dataCanopyField: normalizeCanopyPath(path) }, fieldKey(path)));
|
|
159
|
+
return wrapWithComments(_jsx(StringListField, { id: fieldId, label: label, description: field.description, value: Array.isArray(currentValue) ? currentValue : [], onChange: (v) => update(v), dataCanopyField: normalizeCanopyPath(path), readOnly: readOnly }, fieldKey(path)));
|
|
92
160
|
}
|
|
93
|
-
return wrapWithComments(_jsx(TextField, { id: fieldId, label: label, description: field.description, value: currentValue ?? '', onChange: update, dataCanopyField: normalizeCanopyPath(path) }, fieldKey(path)));
|
|
161
|
+
return wrapWithComments(_jsx(TextField, { id: fieldId, label: label, description: field.description, value: currentValue ?? '', onChange: update, dataCanopyField: normalizeCanopyPath(path), readOnly: readOnly }, fieldKey(path)));
|
|
94
162
|
case 'boolean':
|
|
95
|
-
return wrapWithComments(_jsx(ToggleField, { id: fieldId, label: label, description: field.description, value: Boolean(currentValue), onChange: (v) => update(Boolean(v)), dataCanopyField: normalizeCanopyPath(path), testId: `field-toggle-${field.name}
|
|
163
|
+
return wrapWithComments(_jsx(ToggleField, { id: fieldId, label: label, description: field.description, value: Boolean(currentValue), onChange: (v) => update(Boolean(v)), dataCanopyField: normalizeCanopyPath(path), testId: `field-toggle-${field.name}`, readOnly: readOnly }, fieldKey(path)));
|
|
96
164
|
case 'number':
|
|
97
165
|
if (field.list) {
|
|
98
166
|
return wrapWithComments(_jsx(NumberListField, { id: fieldId, label: label, description: field.description, value: Array.isArray(currentValue)
|
|
99
167
|
? currentValue.filter((v) => typeof v === 'number')
|
|
100
|
-
: [], onChange: (v) => update(v), dataCanopyField: normalizeCanopyPath(path) }, fieldKey(path)));
|
|
168
|
+
: [], onChange: (v) => update(v), dataCanopyField: normalizeCanopyPath(path), readOnly: readOnly }, fieldKey(path)));
|
|
101
169
|
}
|
|
102
|
-
return wrapWithComments(_jsx(NumberField, { id: fieldId, label: label, description: field.description, value: typeof currentValue === 'number' ? currentValue : undefined, onChange: (v) => update(v), dataCanopyField: normalizeCanopyPath(path) }, fieldKey(path)));
|
|
170
|
+
return wrapWithComments(_jsx(NumberField, { id: fieldId, label: label, description: field.description, value: typeof currentValue === 'number' ? currentValue : undefined, onChange: (v) => update(v), dataCanopyField: normalizeCanopyPath(path), readOnly: readOnly }, fieldKey(path)));
|
|
103
171
|
case 'datetime':
|
|
104
|
-
return wrapWithComments(_jsx(DateTimeField, { id: fieldId, label: label, description: field.description, value: typeof currentValue === 'string' ? currentValue : '', onChange: (v) => update(v), dataCanopyField: normalizeCanopyPath(path) }, fieldKey(path)));
|
|
172
|
+
return wrapWithComments(_jsx(DateTimeField, { id: fieldId, label: label, description: field.description, value: typeof currentValue === 'string' ? currentValue : '', onChange: (v) => update(v), dataCanopyField: normalizeCanopyPath(path), readOnly: readOnly, stampOnPublish: 'stampOnPublish' in field && field.stampOnPublish === true }, fieldKey(path)));
|
|
105
173
|
case 'markdown':
|
|
106
|
-
case 'mdx':
|
|
107
|
-
|
|
174
|
+
case 'mdx': {
|
|
175
|
+
const isBody = path.length === 1 && path[0] === bodyName;
|
|
176
|
+
const policy = markdownPolicyOf(field, siteMdxAllow, isBody ? format : undefined);
|
|
177
|
+
return wrapWithComments(_jsx(MarkdownField, { id: fieldId, label: label, description: field.description, value: currentValue ?? '', onChange: (v) => update(v), dataCanopyField: normalizeCanopyPath(path), htmlTags: policy?.dialect === 'mdx' ? policy.allow.htmlTags : undefined, readOnly: readOnly }, fieldKey(path)));
|
|
178
|
+
}
|
|
108
179
|
case 'select': {
|
|
109
180
|
const selectField = field;
|
|
110
181
|
const options = normalizeOptions(selectField.options);
|
|
@@ -113,7 +184,7 @@ export const FormRenderer = ({ fields, value, onChange, customRenderers, branch
|
|
|
113
184
|
? Array.isArray(currentValue)
|
|
114
185
|
? currentValue
|
|
115
186
|
: []
|
|
116
|
-
: (currentValue ?? ''), multiple: isMulti, onChange: (next) => update(next), dataCanopyField: normalizeCanopyPath(path) }, fieldKey(path)));
|
|
187
|
+
: (currentValue ?? ''), multiple: isMulti, onChange: (next) => update(next), dataCanopyField: normalizeCanopyPath(path), readOnly: readOnly }, fieldKey(path)));
|
|
117
188
|
}
|
|
118
189
|
case 'reference': {
|
|
119
190
|
const referenceField = field;
|
|
@@ -128,7 +199,7 @@ export const FormRenderer = ({ fields, value, onChange, customRenderers, branch
|
|
|
128
199
|
? Array.isArray(currentValue)
|
|
129
200
|
? currentValue
|
|
130
201
|
: []
|
|
131
|
-
: (currentValue ?? ''), multiple: isMulti, onChange: (next) => update(next), dataCanopyField: normalizeCanopyPath(path) }, fieldKey(path)));
|
|
202
|
+
: (currentValue ?? ''), multiple: isMulti, onChange: (next) => update(next), dataCanopyField: normalizeCanopyPath(path), readOnly: readOnly }, fieldKey(path)));
|
|
132
203
|
}
|
|
133
204
|
case 'image': {
|
|
134
205
|
const imageField = field;
|
|
@@ -136,11 +207,20 @@ export const FormRenderer = ({ fields, value, onChange, customRenderers, branch
|
|
|
136
207
|
src: fieldErrors?.[`${canopyPath}.src`],
|
|
137
208
|
alt: fieldErrors?.[`${canopyPath}.alt`],
|
|
138
209
|
crop: fieldErrors?.[`${canopyPath}.crop`],
|
|
139
|
-
} }, fieldKey(path)));
|
|
210
|
+
}, readOnly: readOnly, onRemoved: (removed) => onRemoved?.({ kind: 'value', path, value: removed, label: `the image from ${label}` }) }, fieldKey(path)));
|
|
140
211
|
}
|
|
141
212
|
case 'block': {
|
|
142
213
|
const blockField = field;
|
|
143
|
-
return wrapWithComments(_jsx(BlockField, { label: label, description: field.description, templates: blockField.templates, value: (Array.isArray(currentValue) ? currentValue : []), onChange: (next) => update(next), renderField: renderField, path: path, dataCanopyField: normalizeCanopyPath(path)
|
|
214
|
+
return wrapWithComments(_jsx(BlockField, { label: label, required: field.required, description: field.description, templates: blockField.templates, value: (Array.isArray(currentValue) ? currentValue : []), onChange: (next) => update(next), renderField: renderField, path: path, dataCanopyField: normalizeCanopyPath(path), readOnly: readOnly, resetKey: boundaryResetKey, hasErrors: rowHasErrors(path), onRemoved: (index, block) => {
|
|
215
|
+
const template = blockField.templates.find((t) => t.name === block.template);
|
|
216
|
+
onRemoved?.({
|
|
217
|
+
kind: 'list-item',
|
|
218
|
+
listPath: path,
|
|
219
|
+
index,
|
|
220
|
+
item: block,
|
|
221
|
+
label: `"${template ? schemaLabel(template) : block.template}" from ${label}`,
|
|
222
|
+
});
|
|
223
|
+
} }, fieldKey(path)));
|
|
144
224
|
}
|
|
145
225
|
case 'object': {
|
|
146
226
|
const objectField = field;
|
|
@@ -148,41 +228,56 @@ export const FormRenderer = ({ fields, value, onChange, customRenderers, branch
|
|
|
148
228
|
const items = Array.isArray(currentValue)
|
|
149
229
|
? currentValue
|
|
150
230
|
: [];
|
|
151
|
-
return wrapWithComments(_jsx(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}), items.length === 0 && (_jsx(Text, { size: "xs", c: "dimmed", children: "No items yet. Add one to get started." }))] })] }) }, fieldKey(path)));
|
|
231
|
+
return wrapWithComments(_jsx(ObjectListField, { id: fieldId, label: label, field: objectField, items: items, itemKeys: keysForList(items, fieldKey(path)), onChange: (next) => update(next), renderField: renderField, path: path, canopyPath: canopyPath, readOnly: readOnly, resetKey: boundaryResetKey, hasErrors: rowHasErrors(path), onRemoved: (index, item) => onRemoved?.({
|
|
232
|
+
kind: 'list-item',
|
|
233
|
+
listPath: path,
|
|
234
|
+
index,
|
|
235
|
+
item,
|
|
236
|
+
label: removedItemLabel(item, objectField, label, index),
|
|
237
|
+
}) }, fieldKey(path)));
|
|
159
238
|
}
|
|
160
|
-
//
|
|
161
|
-
//
|
|
162
|
-
//
|
|
163
|
-
// (
|
|
164
|
-
// `undefined`/`null`. The Clear button (ObjectField's `onRemove`) resets to
|
|
165
|
-
// `undefined`, never `{}` -- shown only when the field is optional and
|
|
166
|
-
// already has a value, and labeled "Clear" rather than "Remove" so it
|
|
167
|
-
// doesn't read as deleting the field from the schema.
|
|
239
|
+
// A non-list object has no list item to remove, so its only way back to `undefined` is
|
|
240
|
+
// the Clear button (`onRemove`): shown only for an optional field that has a value.
|
|
241
|
+
// Reset to `undefined`, never `{}`, which `isEmptyForRequired` (entry-validator.ts) reads
|
|
242
|
+
// as present. The label is "Clear" (docs/ux-guidelines.md, Vocabulary), and it offers Undo.
|
|
168
243
|
const hasValue = currentValue !== undefined && currentValue !== null;
|
|
169
|
-
const canClear = objectField.required !== true && hasValue;
|
|
170
|
-
return wrapWithComments(_jsx(ObjectField, { label: label, description: field.description, fields: objectField.fields, value: currentValue, onChange: (next) => update(next), onRemove: canClear
|
|
244
|
+
const canClear = !readOnly && objectField.required !== true && hasValue;
|
|
245
|
+
return wrapWithComments(_jsx(ObjectField, { label: label, required: objectField.required, description: field.description, fields: objectField.fields, value: currentValue, onChange: (next) => update(next), onRemove: canClear
|
|
246
|
+
? () => {
|
|
247
|
+
update(undefined);
|
|
248
|
+
onRemoved?.({
|
|
249
|
+
kind: 'value',
|
|
250
|
+
path,
|
|
251
|
+
value: currentValue,
|
|
252
|
+
label: `"${label}"`,
|
|
253
|
+
action: 'clear',
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
: undefined, renderField: renderField, path: path, dataCanopyField: normalizeCanopyPath(path) }, fieldKey(path)));
|
|
171
257
|
}
|
|
172
258
|
case 'code':
|
|
173
|
-
return wrapWithComments(_jsx(CodeField, { id: fieldId, label: label, description: field.description, value: typeof currentValue === 'string' ? currentValue : '', onChange: (v) => update(v), dataCanopyField: normalizeCanopyPath(path) }, fieldKey(path)));
|
|
259
|
+
return wrapWithComments(_jsx(CodeField, { id: fieldId, label: label, description: field.description, value: typeof currentValue === 'string' ? currentValue : '', onChange: (v) => update(v), dataCanopyField: normalizeCanopyPath(path), readOnly: readOnly }, fieldKey(path)));
|
|
174
260
|
default:
|
|
175
261
|
return (_jsxs(Text, { size: "xs", c: "dimmed", children: ["Unsupported field: ", field.type] }, fieldKey(path)));
|
|
176
262
|
}
|
|
177
263
|
};
|
|
178
|
-
return (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
264
|
+
return (_jsx(FormCommentsContext.Provider, { value: formComments, children: _jsx(FormExpansionContext.Provider, { value: expansionCommand, children: _jsxs(Stack, { ref: formRef, gap: "md", "data-form-renderer": true, className: readOnly ? READ_ONLY_FORM_CLASS : undefined, children: [header && (_jsx(FormHeader, { title: header.title, typeLabel: header.typeLabel, outline: buildFormOutline(fields, value, customTypes), onSelect: (path) => {
|
|
265
|
+
const target = formRef.current ? findFieldTarget(path, formRef.current) : undefined;
|
|
266
|
+
if (target)
|
|
267
|
+
focusFieldTarget(target.element);
|
|
268
|
+
}, onExpandAll: hasCollapsibleList(fields, customTypes)
|
|
269
|
+
? (expanded) => setExpansionCommand((prev) => ({ seq: (prev?.seq ?? 0) + 1, expanded }))
|
|
270
|
+
: undefined })), notice, readOnly && _jsx(ReadOnlyFormStyles, {}), currentEntryPath && currentUserId && onAddComment && onResolveThread && (_jsx(EntryComments, { comments: comments, entryPath: currentEntryPath, currentUserId: currentUserId, canResolve: canResolve, onAddComment: onAddComment, onResolveThread: onResolveThread, highlightThreadId: highlightThreadId, onGetUserMetadata: onGetUserMetadata, resetKey: boundaryResetKey, removedItemFieldLabel: (thread) => removedItemFieldLabel?.(thread) ??
|
|
271
|
+
fieldBreadcrumb(fields, undefined, thread.canopyPath ?? '', { items: false }).join(' › ') })), conflictNotice && (_jsx(Alert, { icon: _jsx(IconInfoCircle, { size: 16 }), color: "orange", variant: "light", title: "Page updated since your draft started", "data-testid": "conflict-alert", children: readOnly
|
|
272
|
+
? 'Someone else has recently changed this page.'
|
|
273
|
+
: 'Someone else has recently changed this page. You can keep editing — a reviewer will reconcile your changes when you submit.' })), fieldErrors && _jsx(ValidationSummary, { fields: fields, value: value, errors: fieldErrors }), fields.map((field) => {
|
|
274
|
+
// Inline groups are transparent to the value — render them directly with parent value/onChange
|
|
275
|
+
if (field.type === 'group') {
|
|
276
|
+
const groupField = field;
|
|
277
|
+
return (_jsx("div", { children: _jsx(InlineGroupField, { label: groupField.label, description: groupField.description, fields: groupField.fields, value: value, onChange: emit, renderField: renderField, path: [] }) }, `group-${groupField.name}`));
|
|
278
|
+
}
|
|
279
|
+
const val = value[field.name];
|
|
280
|
+
const path = [field.name];
|
|
281
|
+
return (_jsx("div", { children: renderField(field, val, (next) => emit({ ...value, [field.name]: next }), path) }, fieldKey(path)));
|
|
282
|
+
})] }) }) }));
|
|
188
283
|
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react';
|
|
2
|
+
/** What the preview reports of its marks; see `PreviewMarksMessage`. */
|
|
3
|
+
export interface PreviewMarks {
|
|
4
|
+
count: number;
|
|
5
|
+
paths?: string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Lightweight iframe wrapper to keep the preview in sync with form state.
|
|
9
|
+
* It posts the latest draft data to the iframe after load and when data changes. A progress bar
|
|
10
|
+
* runs until the preview's ready message arrives; when none does, a "Live updates off" chip offers
|
|
11
|
+
* to reload the preview.
|
|
12
|
+
*/
|
|
13
|
+
export declare const PreviewFrame: ({ src, path, data, isLoading, className, style, highlightEnabled, onPreviewError, onMarks, assetBase, iframeStyle, onReload, }: {
|
|
14
|
+
src: string;
|
|
15
|
+
path: string;
|
|
16
|
+
data?: unknown;
|
|
17
|
+
isLoading?: unknown;
|
|
18
|
+
className?: string;
|
|
19
|
+
style?: CSSProperties;
|
|
20
|
+
highlightEnabled?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* The editor's authenticated asset route, a same-origin path, so it is sent with drafts only to
|
|
23
|
+
* a same-origin preview: another origin would resolve it against itself.
|
|
24
|
+
*/
|
|
25
|
+
assetBase?: string;
|
|
26
|
+
/** Called when the preview reports a draft compile/render error; null clears it. */
|
|
27
|
+
onPreviewError?: (error: {
|
|
28
|
+
message: string;
|
|
29
|
+
fieldPath?: string;
|
|
30
|
+
} | null) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Called with how many elements the preview marks, while highlighting is on, and their
|
|
33
|
+
* distinct paths when the preview sends them within `MARK_REPORT_LIMITS`.
|
|
34
|
+
*/
|
|
35
|
+
onMarks?: (marks: PreviewMarks) => void;
|
|
36
|
+
/** Overrides the iframe's own layout, such as a fixed width and scale; the bar and chip stay unscaled. */
|
|
37
|
+
iframeStyle?: CSSProperties;
|
|
38
|
+
/** Replaces the chip's Retry, for a host whose own reload control remounts the frame. */
|
|
39
|
+
onReload?: () => void;
|
|
40
|
+
}) => import("react/jsx-runtime").JSX.Element;
|