@drawnagency/primitives 0.1.113 → 0.1.114
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/auth/cookies.d.ts +39 -0
- package/dist/auth/cookies.d.ts.map +1 -1
- package/dist/auth/index.js +3 -3
- package/dist/{chunk-GPPVYLEI.js → chunk-45FA7Z55.js} +1 -1
- package/dist/{chunk-REDDTTGJ.js → chunk-4Y2JQQZL.js} +19 -1
- package/dist/chunk-5GFACGSN.js +6 -0
- package/dist/chunk-5KSAS4VY.js +275 -0
- package/dist/{chunk-Z7W3DQTR.js → chunk-7SAAJVDE.js} +408 -28
- package/dist/{chunk-S2L3BPLS.js → chunk-7SX42OP4.js} +1 -1
- package/dist/{chunk-GGXZZ77Z.js → chunk-AASEGXNT.js} +18 -1
- package/dist/{chunk-WKZ7OENC.js → chunk-BQ5TZZUE.js} +5 -1
- package/dist/chunk-DIMDRBFK.js +11 -0
- package/dist/{chunk-WUJ3XNFI.js → chunk-GGYY3JQJ.js} +19 -24
- package/dist/{chunk-NHN2LSIU.js → chunk-IP2SEBAJ.js} +5 -1
- package/dist/{chunk-IINIZBQB.js → chunk-JCDZAFX2.js} +30 -10
- package/dist/chunk-JR24U7FJ.js +120 -0
- package/dist/{chunk-SW6PCQQD.js → chunk-KQA772WQ.js} +2 -1
- package/dist/{chunk-KR2MHTNJ.js → chunk-N3G7DOU3.js} +609 -61
- package/dist/chunk-OAGJBCSH.js +67 -0
- package/dist/{chunk-6BZ2KNTP.js → chunk-PLANHXS7.js} +191 -61
- package/dist/{chunk-VWWY5TL5.js → chunk-PNSCDBU7.js} +38 -56
- package/dist/{chunk-AHALSCQH.js → chunk-PTY2RG2K.js} +1 -1
- package/dist/{chunk-BDFTMGCL.js → chunk-PZPGJZRG.js} +9 -8
- package/dist/{chunk-FRE2CCLV.js → chunk-QHMKIODQ.js} +17 -4
- package/dist/{chunk-HBULBDGP.js → chunk-S37DZPHW.js} +1 -1
- package/dist/{chunk-4I5OO5UB.js → chunk-TEOAKGZA.js} +0 -1
- package/dist/chunk-VUYCRBJK.js +174 -0
- package/dist/{chunk-4RNF2DRG.js → chunk-XDEPXTBY.js} +0 -2
- package/dist/{chunk-DS4GCYV2.js → chunk-Y5QECJX7.js} +223 -16
- package/dist/collab/rebase.d.ts +2 -1
- package/dist/collab/rebase.d.ts.map +1 -1
- package/dist/collab/rebase.js +20 -5
- package/dist/components/brandguide/ColorsEditable.d.ts.map +1 -1
- package/dist/components/chat/ChatPanel.d.ts.map +1 -1
- package/dist/components/chat/ChatWidget.d.ts.map +1 -1
- package/dist/components/docfile/DocFilePane.d.ts.map +1 -1
- package/dist/components/editor/ChildBlockWrapper.d.ts.map +1 -1
- package/dist/components/editor/ConflictDialog.d.ts.map +1 -1
- package/dist/components/editor/DragHandle.d.ts +12 -2
- package/dist/components/editor/DragHandle.d.ts.map +1 -1
- package/dist/components/editor/DropEdgeIndicator.d.ts +15 -6
- package/dist/components/editor/DropEdgeIndicator.d.ts.map +1 -1
- package/dist/components/editor/NavGroupRow.d.ts +4 -1
- package/dist/components/editor/NavGroupRow.d.ts.map +1 -1
- package/dist/components/editor/PagesModal.d.ts.map +1 -1
- package/dist/components/editor/SectionWrapper.d.ts +1 -1
- package/dist/components/editor/SectionWrapper.d.ts.map +1 -1
- package/dist/components/editor/SettingsForm.d.ts.map +1 -1
- package/dist/components/editor/TagIndicator.d.ts +15 -0
- package/dist/components/editor/TagIndicator.d.ts.map +1 -0
- package/dist/components/editor/index.js +148 -77
- package/dist/components/primitives/DocumentDropZone.d.ts +1 -1
- package/dist/components/primitives/EditableGrid.d.ts.map +1 -1
- package/dist/components/primitives/EditableList.d.ts.map +1 -1
- package/dist/components/primitives/HeadingSection.d.ts +4 -1
- package/dist/components/primitives/HeadingSection.d.ts.map +1 -1
- package/dist/components/primitives/ResolvedMedia.d.ts +5 -1
- package/dist/components/primitives/ResolvedMedia.d.ts.map +1 -1
- package/dist/components/primitives/{defineHeadingSection.d.ts → define-heading-section.d.ts} +1 -1
- package/dist/components/primitives/define-heading-section.d.ts.map +1 -0
- package/dist/components/primitives/{gridDrop.d.ts → grid-drop.d.ts} +1 -1
- package/dist/components/primitives/grid-drop.d.ts.map +1 -0
- package/dist/components/primitives/index.d.ts +1 -1
- package/dist/components/primitives/index.d.ts.map +1 -1
- package/dist/components/primitives/index.js +17 -154
- package/dist/components/sections/Button/CTAButton.d.ts.map +1 -1
- package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts +2 -6
- package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts.map +1 -1
- package/dist/components/sections/DoDontMedia/index.d.ts +8 -0
- package/dist/components/sections/DoDontMedia/index.d.ts.map +1 -1
- package/dist/components/sections/IconList/IconList.d.ts +2 -1
- package/dist/components/sections/IconList/IconList.d.ts.map +1 -1
- package/dist/components/sections/IconList/IconListSettings.d.ts +2 -1
- package/dist/components/sections/IconList/IconListSettings.d.ts.map +1 -1
- package/dist/components/sections/IconList/index.d.ts +1 -0
- package/dist/components/sections/IconList/index.d.ts.map +1 -1
- package/dist/components/sections/Media/MediaBlock.d.ts +2 -1
- package/dist/components/sections/Media/MediaBlock.d.ts.map +1 -1
- package/dist/components/sections/Media/index.d.ts +8 -0
- package/dist/components/sections/Media/index.d.ts.map +1 -1
- package/dist/components/sections/Reference/ReferenceList.d.ts +35 -0
- package/dist/components/sections/Reference/ReferenceList.d.ts.map +1 -0
- package/dist/components/sections/Reference/ReferenceSettings.d.ts +12 -0
- package/dist/components/sections/Reference/ReferenceSettings.d.ts.map +1 -0
- package/dist/components/sections/Reference/index.d.ts +9 -0
- package/dist/components/sections/Reference/index.d.ts.map +1 -0
- package/dist/components/sections/SectionSummary/SectionSummaryBlock.d.ts +38 -0
- package/dist/components/sections/SectionSummary/SectionSummaryBlock.d.ts.map +1 -0
- package/dist/components/sections/SectionSummary/SectionSummarySettings.d.ts +20 -0
- package/dist/components/sections/SectionSummary/SectionSummarySettings.d.ts.map +1 -0
- package/dist/components/sections/SectionSummary/index.d.ts +33 -0
- package/dist/components/sections/SectionSummary/index.d.ts.map +1 -0
- package/dist/components/sections/all-sections.d.ts +53 -0
- package/dist/components/sections/all-sections.d.ts.map +1 -1
- package/dist/components/sections/brand-guide.d.ts +41 -2
- package/dist/components/sections/brand-guide.d.ts.map +1 -1
- package/dist/components/sections/brand-guide.js +12 -10
- package/dist/components/sections/core-sections.d.ts +14 -0
- package/dist/components/sections/core-sections.d.ts.map +1 -1
- package/dist/components/sections/register-schemas.js +19 -17
- package/dist/components/sections/register.js +19 -17
- package/dist/components/shared/BrandSwatchesContext.d.ts +9 -0
- package/dist/components/shared/BrandSwatchesContext.d.ts.map +1 -0
- package/dist/components/shared/Button.d.ts +11 -3
- package/dist/components/shared/Button.d.ts.map +1 -1
- package/dist/components/shared/Checkbox.d.ts +6 -0
- package/dist/components/shared/Checkbox.d.ts.map +1 -1
- package/dist/components/shared/ConfirmDialog.d.ts +25 -0
- package/dist/components/shared/ConfirmDialog.d.ts.map +1 -0
- package/dist/components/shared/ConfirmInline.d.ts +25 -0
- package/dist/components/shared/ConfirmInline.d.ts.map +1 -0
- package/dist/components/shared/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/shared/Fab.d.ts +11 -2
- package/dist/components/shared/Fab.d.ts.map +1 -1
- package/dist/components/shared/FabStack.d.ts +22 -0
- package/dist/components/shared/FabStack.d.ts.map +1 -0
- package/dist/components/shared/HistoryChangesModal.d.ts.map +1 -1
- package/dist/components/shared/HistoryPopover.d.ts.map +1 -1
- package/dist/components/shared/ImageBackgroundField.d.ts +9 -0
- package/dist/components/shared/ImageBackgroundField.d.ts.map +1 -0
- package/dist/components/shared/{UploadRejectionAlert.d.ts → InlineAlert.d.ts} +4 -2
- package/dist/components/shared/InlineAlert.d.ts.map +1 -0
- package/dist/components/shared/Input.d.ts +10 -0
- package/dist/components/shared/Input.d.ts.map +1 -1
- package/dist/components/shared/Navigation.d.ts.map +1 -1
- package/dist/components/shared/Notice.d.ts +10 -0
- package/dist/components/shared/Notice.d.ts.map +1 -0
- package/dist/components/shared/Popover.d.ts.map +1 -1
- package/dist/components/shared/ReferenceSourcesContext.d.ts +25 -0
- package/dist/components/shared/ReferenceSourcesContext.d.ts.map +1 -0
- package/dist/components/shared/Select.d.ts +3 -2
- package/dist/components/shared/Select.d.ts.map +1 -1
- package/dist/components/shared/SplitButton.d.ts.map +1 -1
- package/dist/components/shared/SummaryAnchorsContext.d.ts +10 -0
- package/dist/components/shared/SummaryAnchorsContext.d.ts.map +1 -0
- package/dist/components/shared/Textarea.d.ts +7 -0
- package/dist/components/shared/Textarea.d.ts.map +1 -1
- package/dist/components/shared/ToolbarFrame.d.ts +17 -0
- package/dist/components/shared/ToolbarFrame.d.ts.map +1 -0
- package/dist/components/shared/copy.d.ts +13 -0
- package/dist/components/shared/copy.d.ts.map +1 -0
- package/dist/components/shared/icons.d.ts +0 -12
- package/dist/components/shared/icons.d.ts.map +1 -1
- package/dist/components/shell/AudienceDetailsPanel.d.ts +7 -1
- package/dist/components/shell/AudienceDetailsPanel.d.ts.map +1 -1
- package/dist/components/shell/AudienceRow.d.ts.map +1 -1
- package/dist/components/shell/BugReportFAB.d.ts +7 -1
- package/dist/components/shell/BugReportFAB.d.ts.map +1 -1
- package/dist/components/shell/CredentialList.d.ts.map +1 -1
- package/dist/components/shell/DocInspector.d.ts.map +1 -1
- package/dist/components/shell/DocumentEditorOverlay.d.ts.map +1 -1
- package/dist/components/shell/EditorContext.d.ts +4 -0
- package/dist/components/shell/EditorContext.d.ts.map +1 -1
- package/dist/components/shell/EditorLoginForm.d.ts.map +1 -1
- package/dist/components/shell/EditorModal.d.ts.map +1 -1
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/components/shell/HistoryToolbar.d.ts.map +1 -1
- package/dist/components/shell/MediaFolderTile.d.ts +4 -1
- package/dist/components/shell/MediaFolderTile.d.ts.map +1 -1
- package/dist/components/shell/MediaLibraryModal.d.ts.map +1 -1
- package/dist/components/shell/RestoreModal.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsChatbot.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsDisplay.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsModal.d.ts +3 -1
- package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsTags.d.ts +13 -0
- package/dist/components/shell/SiteSettingsTags.d.ts.map +1 -0
- package/dist/components/shell/SiteSettingsUsers.d.ts.map +1 -1
- package/dist/components/shell/ViewerLoginForm.d.ts.map +1 -1
- package/dist/components/shell/{blockMoveDispatch.d.ts → block-move-dispatch.d.ts} +1 -1
- package/dist/components/shell/block-move-dispatch.d.ts.map +1 -0
- package/dist/components/shell/reference-sources.d.ts +22 -0
- package/dist/components/shell/reference-sources.d.ts.map +1 -0
- package/dist/deck/index.d.ts +2 -2
- package/dist/deck/index.d.ts.map +1 -1
- package/dist/deck/index.js +1 -3
- package/dist/deck-builder/index.js +11 -18
- package/dist/document/index.d.ts +2 -2
- package/dist/document/index.d.ts.map +1 -1
- package/dist/hooks/useBlockDnd.d.ts +11 -0
- package/dist/hooks/useBlockDnd.d.ts.map +1 -1
- package/dist/hooks/useBuildStatus.d.ts +1 -1
- package/dist/hooks/useBuildStatus.d.ts.map +1 -1
- package/dist/hooks/useDocumentUploads.d.ts +1 -1
- package/dist/hooks/useDocumentUploads.d.ts.map +1 -1
- package/dist/hooks/useEditorPersistence.d.ts +5 -1
- package/dist/hooks/useEditorPersistence.d.ts.map +1 -1
- package/dist/hooks/useEditorPublish.d.ts +2 -2
- package/dist/hooks/useEditorPublish.d.ts.map +1 -1
- package/dist/hooks/useNotice.d.ts +19 -0
- package/dist/hooks/useNotice.d.ts.map +1 -0
- package/dist/hooks/useSortableNavRow.d.ts +11 -0
- package/dist/hooks/useSortableNavRow.d.ts.map +1 -1
- package/dist/hooks/useSortableRow.d.ts +11 -0
- package/dist/hooks/useSortableRow.d.ts.map +1 -1
- package/dist/hooks/useStackedEscape.d.ts +32 -0
- package/dist/hooks/useStackedEscape.d.ts.map +1 -0
- package/dist/index.js +67 -49
- package/dist/lib/audience-secret.js +2 -2
- package/dist/lib/block-dnd.d.ts +5 -0
- package/dist/lib/block-dnd.d.ts.map +1 -1
- package/dist/lib/block-move.d.ts.map +1 -1
- package/dist/lib/brand-swatches.d.ts +12 -0
- package/dist/lib/brand-swatches.d.ts.map +1 -0
- package/dist/lib/container-ops.d.ts +3 -2
- package/dist/lib/container-ops.d.ts.map +1 -1
- package/dist/lib/dexie.d.ts.map +1 -1
- package/dist/lib/dexie.js +9 -1
- package/dist/lib/env.d.ts +4 -0
- package/dist/lib/env.d.ts.map +1 -1
- package/dist/lib/env.js +5 -3
- package/dist/lib/events.d.ts +1 -2
- package/dist/lib/events.d.ts.map +1 -1
- package/dist/lib/image-background.d.ts +8 -0
- package/dist/lib/image-background.d.ts.map +1 -0
- package/dist/lib/index-ops.js +3 -3
- package/dist/lib/index.d.ts +6 -4
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +29 -21
- package/dist/lib/loader.d.ts +21 -7
- package/dist/lib/loader.d.ts.map +1 -1
- package/dist/lib/nav-tree.d.ts +1 -0
- package/dist/lib/nav-tree.d.ts.map +1 -1
- package/dist/lib/nav.d.ts +38 -0
- package/dist/lib/nav.d.ts.map +1 -1
- package/dist/lib/platform-broker.d.ts +4 -2
- package/dist/lib/platform-broker.d.ts.map +1 -1
- package/dist/lib/platform-broker.js +21 -13
- package/dist/lib/reference-type.d.ts +2 -0
- package/dist/lib/reference-type.d.ts.map +1 -0
- package/dist/lib/reference-validation.d.ts +31 -0
- package/dist/lib/reference-validation.d.ts.map +1 -0
- package/dist/lib/reference-validation.js +39 -0
- package/dist/lib/references.d.ts +74 -0
- package/dist/lib/references.d.ts.map +1 -0
- package/dist/lib/registry.d.ts +35 -0
- package/dist/lib/registry.d.ts.map +1 -1
- package/dist/lib/{safeRedirect.d.ts → safe-redirect.d.ts} +1 -1
- package/dist/lib/safe-redirect.d.ts.map +1 -0
- package/dist/lib/tags.d.ts +58 -0
- package/dist/lib/tags.d.ts.map +1 -0
- package/dist/lib/theme-vars.d.ts +9 -0
- package/dist/lib/theme-vars.d.ts.map +1 -1
- package/dist/media/index.d.ts +1 -1
- package/dist/media/index.d.ts.map +1 -1
- package/dist/media/index.js +8 -4
- package/dist/media/utils.d.ts +2 -0
- package/dist/media/utils.d.ts.map +1 -1
- package/dist/media/{videoPoster.d.ts → video-poster.d.ts} +1 -1
- package/dist/media/video-poster.d.ts.map +1 -0
- package/dist/schemas/audience.js +2 -2
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +14 -8
- package/dist/schemas/shared.d.ts +26 -0
- package/dist/schemas/shared.d.ts.map +1 -1
- package/dist/schemas/site-config.d.ts +6 -0
- package/dist/schemas/site-config.d.ts.map +1 -1
- package/dist/schemas/tags.d.ts +27 -0
- package/dist/schemas/tags.d.ts.map +1 -0
- package/dist/storage/index.js +1 -1
- package/dist/types/database.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/auth/cookies.ts +111 -0
- package/src/collab/rebase.ts +26 -2
- package/src/components/brandguide/ColorSwatchSettings.tsx +1 -1
- package/src/components/brandguide/ColorsEditable.tsx +1 -0
- package/src/components/chat/ChatPanel.tsx +2 -3
- package/src/components/chat/ChatWidget.tsx +2 -3
- package/src/components/docfile/DocFilePane.tsx +4 -12
- package/src/components/editor/ChildBlockWrapper.tsx +13 -19
- package/src/components/editor/ConflictDialog.tsx +27 -35
- package/src/components/editor/DeleteButton.tsx +2 -2
- package/src/components/editor/DragHandle.tsx +16 -3
- package/src/components/editor/DropEdgeIndicator.tsx +36 -10
- package/src/components/editor/InsertButton.tsx +2 -2
- package/src/components/editor/NavGroupRow.tsx +43 -14
- package/src/components/editor/PagesModal.tsx +99 -26
- package/src/components/editor/SectionWrapper.tsx +64 -23
- package/src/components/editor/SettingsButton.tsx +2 -2
- package/src/components/editor/SettingsForm.tsx +19 -2
- package/src/components/editor/StatusIndicator.tsx +4 -4
- package/src/components/editor/TagIndicator.tsx +80 -0
- package/src/components/primitives/DocumentDropZone.tsx +1 -1
- package/src/components/primitives/EditableGrid.tsx +15 -14
- package/src/components/primitives/EditableList.tsx +27 -74
- package/src/components/primitives/HeadingSection.tsx +5 -2
- package/src/components/primitives/ResolvedMedia.tsx +13 -0
- package/src/components/primitives/{defineHeadingSection.tsx → define-heading-section.tsx} +1 -0
- package/src/components/primitives/index.ts +1 -1
- package/src/components/primitives/useEditablePlainText.ts +5 -5
- package/src/components/sections/Button/CTAButton.tsx +3 -1
- package/src/components/sections/DoDontMedia/DoDontMediaBlock.tsx +4 -4
- package/src/components/sections/DoDontMedia/index.tsx +12 -3
- package/src/components/sections/IconList/DoDontToggle.tsx +2 -2
- package/src/components/sections/IconList/IconList.tsx +70 -37
- package/src/components/sections/IconList/IconListSettings.tsx +55 -17
- package/src/components/sections/IconList/index.tsx +10 -3
- package/src/components/sections/LinkHeading/index.tsx +1 -1
- package/src/components/sections/Media/MediaBlock.tsx +13 -2
- package/src/components/sections/Media/index.tsx +12 -4
- package/src/components/sections/Reference/ReferenceList.tsx +214 -0
- package/src/components/sections/Reference/ReferenceSettings.tsx +159 -0
- package/src/components/sections/Reference/index.tsx +47 -0
- package/src/components/sections/SectionSummary/SectionSummaryBlock.tsx +476 -0
- package/src/components/sections/SectionSummary/SectionSummarySettings.tsx +126 -0
- package/src/components/sections/SectionSummary/index.tsx +149 -0
- package/src/components/sections/SubHeading/index.tsx +1 -1
- package/src/components/sections/SubSubHeading/index.tsx +1 -1
- package/src/components/sections/brand-guide.ts +4 -3
- package/src/components/sections/core-sections.ts +2 -0
- package/src/components/shared/BrandSwatchesContext.ts +13 -0
- package/src/components/shared/Button.tsx +47 -34
- package/src/components/shared/Checkbox.tsx +21 -12
- package/src/components/shared/ConfirmDialog.tsx +87 -0
- package/src/components/shared/ConfirmInline.tsx +90 -0
- package/src/components/shared/ErrorBoundary.tsx +6 -18
- package/src/components/shared/Fab.tsx +15 -5
- package/src/components/shared/FabStack.tsx +28 -0
- package/src/components/shared/HistoryChangesModal.tsx +43 -41
- package/src/components/shared/HistoryPopover.tsx +7 -20
- package/src/components/shared/ImageBackgroundField.tsx +92 -0
- package/src/components/shared/{UploadRejectionAlert.tsx → InlineAlert.tsx} +21 -5
- package/src/components/shared/Input.tsx +23 -7
- package/src/components/shared/Navigation.tsx +22 -17
- package/src/components/shared/Notice.tsx +59 -0
- package/src/components/shared/Popover.tsx +7 -11
- package/src/components/shared/ReferenceSourcesContext.ts +27 -0
- package/src/components/shared/Select.tsx +5 -2
- package/src/components/shared/SplitButton.tsx +11 -17
- package/src/components/shared/SummaryAnchorsContext.ts +11 -0
- package/src/components/shared/Textarea.tsx +17 -2
- package/src/components/shared/ToolbarFrame.tsx +28 -0
- package/src/components/shared/VideoSourceField.tsx +1 -1
- package/src/components/shared/copy.ts +18 -0
- package/src/components/shared/icons.tsx +1 -17
- package/src/components/shell/AudienceAddForm.tsx +2 -2
- package/src/components/shell/AudienceDetailsPanel.tsx +23 -5
- package/src/components/shell/AudienceRow.tsx +22 -15
- package/src/components/shell/BugReportFAB.tsx +50 -40
- package/src/components/shell/CredentialList.tsx +33 -13
- package/src/components/shell/DocInspector.tsx +3 -12
- package/src/components/shell/DocumentEditorOverlay.tsx +33 -23
- package/src/components/shell/EditorContext.tsx +7 -0
- package/src/components/shell/EditorLoginForm.tsx +26 -36
- package/src/components/shell/EditorModal.tsx +8 -10
- package/src/components/shell/EditorShell.tsx +499 -339
- package/src/components/shell/HistoryToolbar.tsx +24 -26
- package/src/components/shell/MediaFolderTile.tsx +8 -3
- package/src/components/shell/MediaLibraryModal.tsx +59 -60
- package/src/components/shell/ProcessingIndicator.tsx +2 -2
- package/src/components/shell/RestoreModal.tsx +17 -16
- package/src/components/shell/SetPasswordForm.tsx +3 -3
- package/src/components/shell/SiteSettingsChatbot.tsx +61 -42
- package/src/components/shell/SiteSettingsDisplay.tsx +10 -20
- package/src/components/shell/SiteSettingsModal.tsx +24 -2
- package/src/components/shell/SiteSettingsTags.tsx +143 -0
- package/src/components/shell/SiteSettingsUsers.tsx +36 -26
- package/src/components/shell/SiteSettingsViewerAccess.tsx +2 -2
- package/src/components/shell/ViewerLoginForm.tsx +5 -4
- package/src/components/shell/reference-sources.ts +36 -0
- package/src/deck/index.ts +2 -2
- package/src/document/index.ts +2 -2
- package/src/hooks/useBlockDnd.ts +11 -0
- package/src/hooks/useBuildStatus.ts +53 -6
- package/src/hooks/useDocumentUploads.ts +1 -1
- package/src/hooks/useEditorPersistence.ts +141 -35
- package/src/hooks/useEditorPublish.ts +18 -27
- package/src/hooks/useMediaPipeline.ts +1 -1
- package/src/hooks/useNotice.ts +45 -0
- package/src/hooks/useSortableNavRow.ts +11 -0
- package/src/hooks/useSortableRow.ts +22 -2
- package/src/hooks/useStackedEscape.ts +62 -0
- package/src/lib/block-dnd.ts +6 -1
- package/src/lib/block-move.ts +3 -0
- package/src/lib/brand-swatches.ts +32 -0
- package/src/lib/container-ops.ts +5 -3
- package/src/lib/dexie.ts +15 -1
- package/src/lib/env.ts +9 -0
- package/src/lib/events.ts +1 -2
- package/src/lib/image-background.ts +31 -0
- package/src/lib/index.ts +5 -4
- package/src/lib/loader.ts +54 -55
- package/src/lib/nav-tree.ts +71 -0
- package/src/lib/nav.ts +196 -36
- package/src/lib/platform-broker.ts +32 -14
- package/src/lib/reference-type.ts +3 -0
- package/src/lib/reference-validation.ts +69 -0
- package/src/lib/references.ts +130 -0
- package/src/lib/registry.ts +37 -0
- package/src/lib/tags.ts +148 -0
- package/src/lib/theme-vars.ts +23 -0
- package/src/media/index.ts +1 -1
- package/src/media/utils.ts +18 -0
- package/src/media/{videoPoster.ts → video-poster.ts} +2 -2
- package/src/schemas/index.ts +1 -0
- package/src/schemas/shared.ts +24 -1
- package/src/schemas/site-config.ts +6 -1
- package/src/schemas/tags.ts +33 -0
- package/src/storage/types.ts +1 -1
- package/src/types/database.ts +2 -0
- package/dist/chunk-DNY72JZN.js +0 -86
- package/dist/chunk-F2LYQPXV.js +0 -77
- package/dist/chunk-JH762VUH.js +0 -128
- package/dist/chunk-K7DYZXVU.js +0 -138
- package/dist/components/primitives/defineHeadingSection.d.ts.map +0 -1
- package/dist/components/primitives/gridDrop.d.ts.map +0 -1
- package/dist/components/shared/UploadRejectionAlert.d.ts.map +0 -1
- package/dist/components/shell/BuildStatusIndicator.d.ts +0 -7
- package/dist/components/shell/BuildStatusIndicator.d.ts.map +0 -1
- package/dist/components/shell/blockMoveDispatch.d.ts.map +0 -1
- package/dist/hooks/index.d.ts +0 -9
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/lib/grid.d.ts +0 -2
- package/dist/lib/grid.d.ts.map +0 -1
- package/dist/lib/safeRedirect.d.ts.map +0 -1
- package/dist/media/videoPoster.d.ts.map +0 -1
- package/src/components/brandguide/ColorSwatchSettings.d.ts.map +0 -1
- package/src/components/brandguide/Colors.d.ts.map +0 -1
- package/src/components/primitives/CustomParagraph.d.ts.map +0 -1
- package/src/components/primitives/EditableGrid.d.ts.map +0 -1
- package/src/components/primitives/EditablePlainText.d.ts.map +0 -1
- package/src/components/primitives/EditableRichText.d.ts.map +0 -1
- package/src/components/primitives/HeadingSection.d.ts.map +0 -1
- package/src/components/primitives/IconPicker.d.ts.map +0 -1
- package/src/components/primitives/LinkPopover.d.ts.map +0 -1
- package/src/components/primitives/MediaSettingsForms.d.ts.map +0 -1
- package/src/components/primitives/ResolvedMedia.d.ts.map +0 -1
- package/src/components/primitives/RichTextToolbar.d.ts.map +0 -1
- package/src/components/primitives/tiptap-presets.d.ts.map +0 -1
- package/src/components/primitives/useEditableCollection.d.ts.map +0 -1
- package/src/components/primitives/useEditablePlainText.d.ts.map +0 -1
- package/src/components/primitives/useEditableRichText.d.ts.map +0 -1
- package/src/components/sections/Button/CTAButton.d.ts.map +0 -1
- package/src/components/sections/Button/index.d.ts.map +0 -1
- package/src/components/sections/Colors/index.d.ts.map +0 -1
- package/src/components/sections/IconList/IconList.d.ts.map +0 -1
- package/src/components/sections/IconList/IconListSettings.d.ts.map +0 -1
- package/src/components/sections/IconList/index.d.ts.map +0 -1
- package/src/components/sections/LinkHeading/index.d.ts.map +0 -1
- package/src/components/sections/Prose/Prose.d.ts.map +0 -1
- package/src/components/sections/Prose/index.d.ts.map +0 -1
- package/src/components/sections/SubHeading/index.d.ts.map +0 -1
- package/src/components/sections/SubSubHeading/index.d.ts.map +0 -1
- package/src/components/sections/register-schemas.d.ts.map +0 -1
- package/src/components/shared/Button.d.ts.map +0 -1
- package/src/components/shared/Checkbox.d.ts.map +0 -1
- package/src/components/shared/FormLabel.d.ts.map +0 -1
- package/src/components/shared/IconButton.d.ts.map +0 -1
- package/src/components/shared/Input.d.ts.map +0 -1
- package/src/components/shared/Select.d.ts.map +0 -1
- package/src/components/shared/icons.d.ts.map +0 -1
- package/src/components/shell/BuildStatusIndicator.tsx +0 -59
- package/src/components/shell/MediaLibraryContext.d.ts.map +0 -1
- package/src/hooks/index.ts +0 -8
- package/src/hooks/useResolvedMedia.d.ts.map +0 -1
- package/src/lib/cn.d.ts.map +0 -1
- package/src/lib/grid.d.ts.map +0 -1
- package/src/lib/grid.ts +0 -7
- package/src/lib/icons.d.ts.map +0 -1
- package/src/lib/loader.d.ts.map +0 -1
- package/src/lib/nav.d.ts.map +0 -1
- package/src/lib/registry.d.ts.map +0 -1
- package/src/lib/sanitize.d.ts.map +0 -1
- package/src/media/github.d.ts.map +0 -1
- package/src/media/index.d.ts.map +0 -1
- package/src/media/queue.d.ts.map +0 -1
- package/src/media/resolve.d.ts.map +0 -1
- package/src/media/types.d.ts.map +0 -1
- package/src/media/utils.d.ts.map +0 -1
- package/src/media/videoPoster.d.ts.map +0 -1
- package/src/schemas/auth.d.ts.map +0 -1
- package/src/schemas/media-grid-options.d.ts.map +0 -1
- package/src/schemas/media.d.ts.map +0 -1
- package/src/schemas/sections.d.ts.map +0 -1
- package/src/schemas/shared.d.ts.map +0 -1
- package/src/schemas/site-config.d.ts.map +0 -1
- /package/dist/{chunk-B7VBSE5X.js → chunk-3JDTXOIG.js} +0 -0
- /package/dist/{chunk-CXZ5YJG4.js → chunk-L45X7DKX.js} +0 -0
- /package/src/components/primitives/{gridDrop.ts → grid-drop.ts} +0 -0
- /package/src/components/shell/{blockMoveDispatch.ts → block-move-dispatch.ts} +0 -0
- /package/src/lib/{safeRedirect.ts → safe-redirect.ts} +0 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import { useId, useState } from "react";
|
|
2
|
+
import { EditablePlainText } from "../../primitives/EditablePlainText";
|
|
3
|
+
import { EditableList } from "../../primitives/EditableList";
|
|
4
|
+
import { LinkField } from "../../shared/LinkField";
|
|
5
|
+
import { usePages } from "../../shared/PagesContext";
|
|
6
|
+
import { DEFAULT_LINK, type LinkValue } from "../../../schemas/link";
|
|
7
|
+
import type { OpenModal } from "../../../lib/registry";
|
|
8
|
+
import type { SummaryNavLevel } from "../../../lib/nav";
|
|
9
|
+
|
|
10
|
+
// End-of-section TL;DR plate, promoted from Siete's site-local section (#59)
|
|
11
|
+
// with its look kept: every color and font is a theme token. A branded plate
|
|
12
|
+
// (background = --color-primary) with a kicker top-left, a script accent ("tl;dr") top-right, numbered principle
|
|
13
|
+
// items (bold headline + soft one-sentence explainer, hanging numeral so both
|
|
14
|
+
// share a left edge), an inline jump-link trailing each explainer, and a
|
|
15
|
+
// footer with a contextual note (left) and a "copy summary" action (right).
|
|
16
|
+
//
|
|
17
|
+
// The PUBLIC VIEWER never hydrates React — this renders as SSR HTML — so:
|
|
18
|
+
// - layout/hover states are pure CSS in a per-instance <style> scoped #<id>;
|
|
19
|
+
// - the copy button is wired by a tiny inline <script> (delegated click
|
|
20
|
+
// listener on the plate root),
|
|
21
|
+
// which has to read the copy text back out of the DOM. In the hydrated
|
|
22
|
+
// editor the button is an ordinary React onClick that builds the same text
|
|
23
|
+
// from props, and the inline <script> is not rendered at all.
|
|
24
|
+
//
|
|
25
|
+
// Escaping story: the only string interpolated into the <style>/<script> text
|
|
26
|
+
// is the id prefix, sanitized to [a-z0-9-]. Free-form user text renders through
|
|
27
|
+
// React children / EditablePlainText only. Jump-links come from the shared
|
|
28
|
+
// LinkField picker: internal links are collapsed to a resolved, safe href by the
|
|
29
|
+
// SSR resolveInternalLinks pass, and external hrefs pass the link schema's
|
|
30
|
+
// isSafeHref guard — so no user href is ever interpolated into the markup here.
|
|
31
|
+
|
|
32
|
+
export interface SummaryItem {
|
|
33
|
+
headline: string;
|
|
34
|
+
explainer: string;
|
|
35
|
+
link: LinkValue;
|
|
36
|
+
linkLabel: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface SectionSummaryOptions {
|
|
40
|
+
showAccent?: boolean;
|
|
41
|
+
showFooter?: boolean;
|
|
42
|
+
showCopy?: boolean;
|
|
43
|
+
numbered?: boolean;
|
|
44
|
+
nav?: SummaryNavLevel;
|
|
45
|
+
navLabel?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface SectionSummaryBlockProps {
|
|
49
|
+
sectionId?: string;
|
|
50
|
+
kicker: string;
|
|
51
|
+
accent: string;
|
|
52
|
+
footNote: string;
|
|
53
|
+
items: SummaryItem[];
|
|
54
|
+
options: SectionSummaryOptions;
|
|
55
|
+
isEditMode?: boolean;
|
|
56
|
+
openModal?: OpenModal;
|
|
57
|
+
onKickerChange?: (value: string) => void;
|
|
58
|
+
onAccentChange?: (value: string) => void;
|
|
59
|
+
onFootNoteChange?: (value: string) => void;
|
|
60
|
+
onItemsChange?: (items: SummaryItem[]) => void;
|
|
61
|
+
/** Page-unique nav anchor (see summaryNavAnchors), when nav is on. */
|
|
62
|
+
navAnchor?: string;
|
|
63
|
+
/** Editor-only note on why a nav-enabled plate is missing from the nav. */
|
|
64
|
+
navHint?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// --font-label / --font-accent are optional site-defined hooks (Siete sets both);
|
|
68
|
+
// without them the label and the script accent fall back to the heading font.
|
|
69
|
+
const LABEL_FONT = "var(--font-label, var(--font-heading, system-ui))";
|
|
70
|
+
const ACCENT_FONT = "var(--font-accent, var(--font-heading, cursive))";
|
|
71
|
+
// Text on the primary-filled plate reads from --color-on-primary, the framework's
|
|
72
|
+
// per-brand derived on-primary ink (black or white, whichever wins WCAG on
|
|
73
|
+
// primaryColor). The #fff fallback covers package versions predating the token.
|
|
74
|
+
// Deliberately NOT --color-primary-contrast: that is the decorative accent
|
|
75
|
+
// (Siete's gold), used below for the kicker, numerals and hover states.
|
|
76
|
+
const INK_SOFT = "color-mix(in srgb, var(--color-on-primary, #fff) 70%, var(--color-primary))";
|
|
77
|
+
const PLATE_LINE = "color-mix(in srgb, var(--color-on-primary, #fff) 25%, var(--color-primary))";
|
|
78
|
+
|
|
79
|
+
const sanitizeIdPart = (s: string) => s.toLowerCase().replace(/[^a-z0-9-]/g, "");
|
|
80
|
+
|
|
81
|
+
// A link counts as "set" when it names a target. In the editor an internal link
|
|
82
|
+
// carries a pageId but no resolved href yet (resolveInternalLinks runs SSR-side);
|
|
83
|
+
// in the viewer it has already been collapsed to { kind: "external", href }.
|
|
84
|
+
function linkIsSet(link: LinkValue): boolean {
|
|
85
|
+
return link.kind === "external" ? link.href.trim() !== "" : link.pageId !== "";
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// The navigable href, only ever present for the viewer's resolved external form
|
|
89
|
+
// (or an editor-side external link). Internal links have no href until the SSR
|
|
90
|
+
// pass resolves them, so the editor renders a non-navigating label preview.
|
|
91
|
+
function linkHref(link: LinkValue): { href: string; target?: string } {
|
|
92
|
+
if (link.kind === "external") return { href: link.href.trim(), target: link.target };
|
|
93
|
+
return { href: "" };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Stored label wins; external links with no label fall back to the raw URL.
|
|
97
|
+
function displayLabel(item: SummaryItem): string {
|
|
98
|
+
if (item.linkLabel.trim() !== "") return item.linkLabel.trim();
|
|
99
|
+
if (item.link.kind === "external") return item.link.href.trim();
|
|
100
|
+
return "";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Modal body for setting an item's jump-link — the shared LinkField (external
|
|
104
|
+
// URL / internal page + section), same picker the Button/Media settings use.
|
|
105
|
+
// Opened via the section's openModal; changes apply live to the item (the modal
|
|
106
|
+
// chrome owns closing) and the label is derived here, where the pages context
|
|
107
|
+
// (only present inside the editor) is available.
|
|
108
|
+
function JumpLinkModalBody({
|
|
109
|
+
initialLink,
|
|
110
|
+
onApply,
|
|
111
|
+
onRemove,
|
|
112
|
+
}: {
|
|
113
|
+
initialLink: LinkValue;
|
|
114
|
+
onApply: (link: LinkValue, label: string) => void;
|
|
115
|
+
onRemove: () => void;
|
|
116
|
+
}) {
|
|
117
|
+
const { pages, getPageHeadings } = usePages();
|
|
118
|
+
const [link, setLink] = useState<LinkValue>(initialLink);
|
|
119
|
+
const deriveLabel = (l: LinkValue): string => {
|
|
120
|
+
if (l.kind !== "internal" || !l.pageId) return "";
|
|
121
|
+
if (l.anchorSectionId) {
|
|
122
|
+
const h = getPageHeadings(l.pageId).find((x) => x.id === l.anchorSectionId);
|
|
123
|
+
if (h) return h.label;
|
|
124
|
+
}
|
|
125
|
+
return pages.find((pg) => pg.id === l.pageId)?.title ?? "";
|
|
126
|
+
};
|
|
127
|
+
const handle = (l: LinkValue) => {
|
|
128
|
+
setLink(l);
|
|
129
|
+
onApply(l, l.kind === "internal" ? deriveLabel(l) : "");
|
|
130
|
+
};
|
|
131
|
+
return (
|
|
132
|
+
<div className="flex flex-col gap-4">
|
|
133
|
+
<LinkField label="Jump-link target" value={link} onChange={handle} />
|
|
134
|
+
{linkIsSet(link) && (
|
|
135
|
+
<button
|
|
136
|
+
type="button"
|
|
137
|
+
className="cursor-pointer self-start text-sm text-base-contrast-light underline hover:text-base-contrast"
|
|
138
|
+
onClick={() => {
|
|
139
|
+
setLink(DEFAULT_LINK);
|
|
140
|
+
onRemove();
|
|
141
|
+
}}
|
|
142
|
+
>
|
|
143
|
+
Remove jump link
|
|
144
|
+
</button>
|
|
145
|
+
)}
|
|
146
|
+
</div>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Radii follow the portal's corner-radius tokens (--radius-outer / --radius-inner).
|
|
151
|
+
function buildCss(p: string, numbered: boolean): string {
|
|
152
|
+
return [
|
|
153
|
+
`#${p}{background:var(--color-primary);border-radius:var(--radius-outer, 18px);padding:1.4rem 1.4rem 1.1rem;color:var(--color-on-primary, #fff);}`,
|
|
154
|
+
`#${p} .ss-head{display:flex;justify-content:space-between;align-items:baseline;gap:1rem;flex-wrap:wrap;}`,
|
|
155
|
+
`#${p} .ss-kicker{font-family:${LABEL_FONT};font-weight:700;letter-spacing:.18em;font-size:.78rem;color:var(--color-primary-contrast);text-transform:uppercase;}`,
|
|
156
|
+
`#${p} .ss-accent{font-family:${ACCENT_FONT};font-size:1.45rem;color:var(--color-on-primary, #fff);opacity:.92;text-align:right;}`,
|
|
157
|
+
// The list: neutralize EditableList's utility gap so rhythm comes from item
|
|
158
|
+
// padding + rules (id-scoped, so it wins in both view and edit mode).
|
|
159
|
+
`#${p} .ss-list{margin-top:.5rem;gap:0;}`,
|
|
160
|
+
`#${p} .ss-item{display:grid;grid-template-columns:${numbered ? "max-content 1fr" : "1fr"};column-gap:.9rem;align-items:baseline;padding:.95rem 0;border-top:1px solid ${PLATE_LINE};}`,
|
|
161
|
+
`#${p} .ss-list > div:first-child .ss-item{border-top:0;padding-top:.6rem;}`,
|
|
162
|
+
`#${p} .ss-num{font-family:${LABEL_FONT};font-weight:700;font-size:.78rem;letter-spacing:.1em;color:var(--color-primary-contrast);}`,
|
|
163
|
+
`#${p} .ss-h{font-weight:700;font-size:1.22rem;line-height:1.3;}`,
|
|
164
|
+
`#${p} .ss-x{color:${INK_SOFT};font-size:.98rem;line-height:1.45;margin-top:.25rem;}`,
|
|
165
|
+
// Jump-link trails each item on its own line. When no link is set the element
|
|
166
|
+
// is kept (visibility:hidden) so toggling a link never shifts the layout.
|
|
167
|
+
`#${p} .ss-jumprow{margin-top:.4rem;}`,
|
|
168
|
+
`#${p} .ss-arrow{margin-right:.4em;}`,
|
|
169
|
+
`#${p} .ss-jump{display:inline-block;font-family:${LABEL_FONT};font-size:.7rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:${INK_SOFT};text-decoration:none;white-space:nowrap;border-bottom:1px solid ${PLATE_LINE};transition:color .15s,border-color .15s;}`,
|
|
170
|
+
`#${p} a.ss-jump:hover{color:var(--color-primary-contrast);border-color:var(--color-primary-contrast);}`,
|
|
171
|
+
`#${p} .ss-foot{margin-top:.4rem;padding-top:.9rem;border-top:1px solid ${PLATE_LINE};display:flex;justify-content:space-between;align-items:baseline;gap:1rem;font-family:${LABEL_FONT};font-size:.72rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:${INK_SOFT};}`,
|
|
172
|
+
`#${p} .ss-copy{background:none;border:0;padding:0;cursor:pointer;font:inherit;letter-spacing:inherit;text-transform:inherit;color:${INK_SOFT};border-bottom:1px solid ${PLATE_LINE};transition:color .15s,border-color .15s;}`,
|
|
173
|
+
`#${p} .ss-copy:hover,#${p} .ss-copy.ss-copied{color:var(--color-primary-contrast);border-color:var(--color-primary-contrast);}`,
|
|
174
|
+
// Editor-only: the jump-link trigger (opens the picker modal) and the
|
|
175
|
+
// EditableList "Add row" button, both branded with --color-primary-contrast.
|
|
176
|
+
`#${p} .ss-jumpedit{display:inline-flex;align-items:center;background:none;border:0;padding:0;cursor:pointer;font-family:${LABEL_FONT};font-size:.7rem;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:${INK_SOFT};transition:color .15s;}`,
|
|
177
|
+
`#${p} .ss-jumpedit:hover{color:var(--color-primary-contrast);}`,
|
|
178
|
+
`#${p} .ss-jumpedit.is-set{border-bottom:1px solid ${PLATE_LINE};}`,
|
|
179
|
+
`#${p} .ss-jumpedit-ic{margin-left:.4em;opacity:.7;}`,
|
|
180
|
+
`#${p} .ss-list > button{border-color:var(--color-primary-contrast);color:var(--color-primary-contrast);}`,
|
|
181
|
+
`#${p} .ss-list > button:hover{background:color-mix(in srgb, var(--color-primary-contrast) 12%, transparent);}`,
|
|
182
|
+
// EditableList's drag/drop chrome renders inside the primary-filled plate, so
|
|
183
|
+
// tint the drag handle and the drop-target indicator (a border-primary top
|
|
184
|
+
// rule that would otherwise vanish into the plate) to the same soft on-primary
|
|
185
|
+
// ink as the jump-link trigger.
|
|
186
|
+
`#${p} .ss-list button.cursor-grab{color:${INK_SOFT};}`,
|
|
187
|
+
`#${p} .ss-list .border-primary{border-color:${INK_SOFT};}`,
|
|
188
|
+
`#${p} [contenteditable]{outline:none;caret-color:var(--color-primary-contrast);}`,
|
|
189
|
+
`#${p} [contenteditable]:focus{box-shadow:0 0 0 2px color-mix(in srgb, var(--color-primary-contrast) 55%, transparent);border-radius:var(--radius-inner, 6px);}`,
|
|
190
|
+
].join("\n");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Copy wiring for the SSR viewer (no React hydration there). One delegated
|
|
194
|
+
// `click` listener on the plate root; builds plain text from the rendered DOM
|
|
195
|
+
// (kicker + "• headline — explainer" lines, jump-link text stripped). `P` is
|
|
196
|
+
// the sanitized [a-z0-9-] prefix — the only value interpolated in.
|
|
197
|
+
function copyScript(p: string): string {
|
|
198
|
+
return (
|
|
199
|
+
`(function(){var bind=function(){var c=document.getElementById("${p}");` +
|
|
200
|
+
`if(!c||c.dataset.ssBound)return;c.dataset.ssBound="1";` +
|
|
201
|
+
`c.addEventListener("click",function(e){var t=e.target&&e.target.closest?e.target.closest(".ss-copy"):null;` +
|
|
202
|
+
`if(!t||!c.contains(t)||t.classList.contains("ss-copied")||!(navigator.clipboard&&navigator.clipboard.writeText))return;` +
|
|
203
|
+
`var lines=[];var k=c.querySelector(".ss-kicker");` +
|
|
204
|
+
`if(k&&k.textContent&&k.textContent.trim())lines.push(k.textContent.trim().toUpperCase());` +
|
|
205
|
+
`var items=c.querySelectorAll(".ss-item");` +
|
|
206
|
+
`for(var i=0;i<items.length;i++){var h=items[i].querySelector(".ss-h");var x=items[i].querySelector(".ss-x");var xt="";` +
|
|
207
|
+
`if(x){var cl=x.cloneNode(true);var j=cl.querySelector(".ss-jump");if(j)j.remove();xt=(cl.textContent||"").trim();}` +
|
|
208
|
+
`var ht=((h&&h.textContent)||"").trim();if(ht||xt)lines.push("\\u2022 "+ht+(xt?" \\u2014 "+xt:""));}` +
|
|
209
|
+
`navigator.clipboard.writeText(lines.join("\\n")).then(function(){` +
|
|
210
|
+
`var o=t.textContent;t.classList.add("ss-copied");t.textContent="\\u2713 Copied";` +
|
|
211
|
+
`setTimeout(function(){t.classList.remove("ss-copied");t.textContent=o;},1400);},function(){});});};` +
|
|
212
|
+
`bind();if(document.readyState==="loading"){document.addEventListener("DOMContentLoaded",bind);}})();`
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const pad2 = (n: number) => String(n).padStart(2, "0");
|
|
217
|
+
|
|
218
|
+
export function SectionSummaryBlock({
|
|
219
|
+
sectionId,
|
|
220
|
+
kicker,
|
|
221
|
+
accent,
|
|
222
|
+
footNote,
|
|
223
|
+
items,
|
|
224
|
+
options,
|
|
225
|
+
isEditMode,
|
|
226
|
+
openModal,
|
|
227
|
+
onKickerChange,
|
|
228
|
+
onAccentChange,
|
|
229
|
+
onFootNoteChange,
|
|
230
|
+
onItemsChange,
|
|
231
|
+
navAnchor,
|
|
232
|
+
navHint,
|
|
233
|
+
}: SectionSummaryBlockProps) {
|
|
234
|
+
// Stable, sanitized per-instance prefix (id from the content envelope; useId
|
|
235
|
+
// is only a fallback).
|
|
236
|
+
const reactId = useId();
|
|
237
|
+
const p = `ss-${sanitizeIdPart(sectionId ?? "") || sanitizeIdPart(reactId) || "x"}`;
|
|
238
|
+
|
|
239
|
+
const edit = !!isEditMode;
|
|
240
|
+
const numbered = options.numbered ?? true;
|
|
241
|
+
|
|
242
|
+
// View mode skips rows with no content at all (e.g. a forgotten starter
|
|
243
|
+
// row), so they don't render as blank ruled rows; the editor still shows
|
|
244
|
+
// them for filling in.
|
|
245
|
+
const visibleItems = items.filter(
|
|
246
|
+
(item) => item.headline.trim() !== "" || item.explainer.trim() !== "" || linkIsSet(item.link),
|
|
247
|
+
);
|
|
248
|
+
// Count what this mode actually renders, so an all-empty list doesn't leave
|
|
249
|
+
// the viewer with a footer rule and a copy button over no content.
|
|
250
|
+
const rowCount = edit ? items.length : visibleItems.length;
|
|
251
|
+
|
|
252
|
+
const showFooter = (options.showFooter ?? true) && (edit || footNote.trim() !== "" || rowCount > 0);
|
|
253
|
+
// Button and inline script share one gate so the viewer never ships a
|
|
254
|
+
// listener for a control that isn't rendered.
|
|
255
|
+
const showCopyButton = showFooter && (options.showCopy ?? true) && rowCount > 0;
|
|
256
|
+
const showAccent = (options.showAccent ?? true) && (edit ? !!onAccentChange : accent.trim() !== "");
|
|
257
|
+
const showKicker = edit ? !!onKickerChange : kicker.trim() !== "";
|
|
258
|
+
|
|
259
|
+
const css = buildCss(p, numbered);
|
|
260
|
+
|
|
261
|
+
// Editor-only copy handling: here the button is an ordinary React control, so
|
|
262
|
+
// the text comes straight from props. The SSR viewer has no React and gets the
|
|
263
|
+
// inline <script> instead (which reads the same text back out of the DOM).
|
|
264
|
+
const [copied, setCopied] = useState(false);
|
|
265
|
+
const onCopyClick = () => {
|
|
266
|
+
if (copied || !navigator.clipboard?.writeText) return;
|
|
267
|
+
const lines: string[] = [];
|
|
268
|
+
if (kicker.trim()) lines.push(kicker.trim().toUpperCase());
|
|
269
|
+
for (const item of items) {
|
|
270
|
+
const h = item.headline.trim();
|
|
271
|
+
const x = item.explainer.trim();
|
|
272
|
+
if (h || x) lines.push(`• ${h}${x ? ` — ${x}` : ""}`);
|
|
273
|
+
}
|
|
274
|
+
navigator.clipboard.writeText(lines.join("\n")).then(
|
|
275
|
+
() => {
|
|
276
|
+
setCopied(true);
|
|
277
|
+
setTimeout(() => setCopied(false), 1400);
|
|
278
|
+
},
|
|
279
|
+
() => {
|
|
280
|
+
// Clipboard denied/unavailable: leave the label untouched rather than
|
|
281
|
+
// surface an unhandled rejection.
|
|
282
|
+
},
|
|
283
|
+
);
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const renderViewItem = (item: SummaryItem, index: number) => {
|
|
287
|
+
const { href, target } = linkHref(item.link);
|
|
288
|
+
const hasLink = href !== "";
|
|
289
|
+
const label = displayLabel(item);
|
|
290
|
+
return (
|
|
291
|
+
<div className="ss-item">
|
|
292
|
+
{numbered && (
|
|
293
|
+
<span className="ss-num" aria-hidden="true">
|
|
294
|
+
{pad2(index + 1)}
|
|
295
|
+
</span>
|
|
296
|
+
)}
|
|
297
|
+
<div className="ss-body">
|
|
298
|
+
<div className="ss-h">{item.headline}</div>
|
|
299
|
+
{item.explainer.trim() !== "" && <div className="ss-x">{item.explainer}</div>}
|
|
300
|
+
<div className="ss-jumprow">
|
|
301
|
+
{hasLink ? (
|
|
302
|
+
<a className="ss-jump" href={href} target={target}>
|
|
303
|
+
<span className="ss-arrow" aria-hidden="true">{"↩"}</span>
|
|
304
|
+
{label}
|
|
305
|
+
</a>
|
|
306
|
+
) : (
|
|
307
|
+
// Reserve the line so a row with/without a link keeps the same height.
|
|
308
|
+
<span className="ss-jump" style={{ visibility: "hidden" }} aria-hidden="true">
|
|
309
|
+
{"↩ Link"}
|
|
310
|
+
</span>
|
|
311
|
+
)}
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
315
|
+
);
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const renderEditItem = (item: SummaryItem, index: number) => {
|
|
319
|
+
const set = (patch: Partial<SummaryItem>) => {
|
|
320
|
+
const next = items.slice();
|
|
321
|
+
next[index] = { ...next[index], ...patch };
|
|
322
|
+
onItemsChange?.(next);
|
|
323
|
+
};
|
|
324
|
+
const label = displayLabel(item);
|
|
325
|
+
const isSet = linkIsSet(item.link);
|
|
326
|
+
// The picker opens in a modal (the shared link pattern); changes apply live.
|
|
327
|
+
const openLinkModal = () =>
|
|
328
|
+
openModal?.(
|
|
329
|
+
"Jump link",
|
|
330
|
+
<JumpLinkModalBody
|
|
331
|
+
initialLink={item.link}
|
|
332
|
+
onApply={(link, linkLabel) => set({ link, linkLabel })}
|
|
333
|
+
onRemove={() => set({ link: DEFAULT_LINK, linkLabel: "" })}
|
|
334
|
+
/>,
|
|
335
|
+
);
|
|
336
|
+
return (
|
|
337
|
+
<div className="ss-item">
|
|
338
|
+
{numbered && <span className="ss-num">{pad2(index + 1)}</span>}
|
|
339
|
+
<div className="ss-body">
|
|
340
|
+
<EditablePlainText
|
|
341
|
+
tag="div"
|
|
342
|
+
className="ss-h"
|
|
343
|
+
value={item.headline}
|
|
344
|
+
onChange={(headline) => set({ headline })}
|
|
345
|
+
isEditMode={true}
|
|
346
|
+
placeholder="Headline"
|
|
347
|
+
/>
|
|
348
|
+
<EditablePlainText
|
|
349
|
+
tag="div"
|
|
350
|
+
className="ss-x"
|
|
351
|
+
value={item.explainer}
|
|
352
|
+
onChange={(explainer) => set({ explainer })}
|
|
353
|
+
isEditMode={true}
|
|
354
|
+
placeholder="One-sentence explainer (optional)"
|
|
355
|
+
/>
|
|
356
|
+
<div className="ss-jumprow">
|
|
357
|
+
<button
|
|
358
|
+
type="button"
|
|
359
|
+
className={isSet ? "ss-jumpedit is-set" : "ss-jumpedit"}
|
|
360
|
+
onClick={openLinkModal}
|
|
361
|
+
>
|
|
362
|
+
{isSet ? (
|
|
363
|
+
<>
|
|
364
|
+
<span className="ss-arrow" aria-hidden="true">{"↩"}</span>
|
|
365
|
+
{label || "Edit jump link"}
|
|
366
|
+
<span className="ss-jumpedit-ic" aria-hidden="true">{" ✎"}</span>
|
|
367
|
+
</>
|
|
368
|
+
) : (
|
|
369
|
+
"+ Add jump link"
|
|
370
|
+
)}
|
|
371
|
+
</button>
|
|
372
|
+
</div>
|
|
373
|
+
</div>
|
|
374
|
+
</div>
|
|
375
|
+
);
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
const autoNote = rowCount > 0 ? `${pad2(rowCount)} ${rowCount === 1 ? "principle" : "principles"}` : "";
|
|
379
|
+
|
|
380
|
+
const plate = (
|
|
381
|
+
<div id={p}>
|
|
382
|
+
<style dangerouslySetInnerHTML={{ __html: css }} />
|
|
383
|
+
|
|
384
|
+
{(showKicker || showAccent) && (
|
|
385
|
+
<div className="ss-head">
|
|
386
|
+
{showKicker &&
|
|
387
|
+
(edit && onKickerChange ? (
|
|
388
|
+
<EditablePlainText
|
|
389
|
+
tag="span"
|
|
390
|
+
className="ss-kicker"
|
|
391
|
+
value={kicker}
|
|
392
|
+
onChange={onKickerChange}
|
|
393
|
+
isEditMode={true}
|
|
394
|
+
placeholder="Section — Summary"
|
|
395
|
+
/>
|
|
396
|
+
) : (
|
|
397
|
+
<span className="ss-kicker">{kicker}</span>
|
|
398
|
+
))}
|
|
399
|
+
{showAccent &&
|
|
400
|
+
(edit && onAccentChange ? (
|
|
401
|
+
<EditablePlainText
|
|
402
|
+
tag="span"
|
|
403
|
+
className="ss-accent"
|
|
404
|
+
value={accent}
|
|
405
|
+
onChange={onAccentChange}
|
|
406
|
+
isEditMode={true}
|
|
407
|
+
placeholder="tl;dr"
|
|
408
|
+
style={{ marginLeft: "auto" }}
|
|
409
|
+
/>
|
|
410
|
+
) : (
|
|
411
|
+
<span className="ss-accent" style={{ marginLeft: "auto" }}>
|
|
412
|
+
{accent}
|
|
413
|
+
</span>
|
|
414
|
+
))}
|
|
415
|
+
</div>
|
|
416
|
+
)}
|
|
417
|
+
|
|
418
|
+
{edit && onItemsChange ? (
|
|
419
|
+
<EditableList<SummaryItem>
|
|
420
|
+
className="ss-list"
|
|
421
|
+
items={items}
|
|
422
|
+
onChange={onItemsChange}
|
|
423
|
+
createItem={() => ({ headline: "", explainer: "", link: DEFAULT_LINK, linkLabel: "" })}
|
|
424
|
+
isEditMode={true}
|
|
425
|
+
renderItem={(item, { index }) => renderEditItem(item, index)}
|
|
426
|
+
/>
|
|
427
|
+
) : (
|
|
428
|
+
visibleItems.length > 0 && (
|
|
429
|
+
<div className="ss-list" style={{ display: "flex", flexDirection: "column" }}>
|
|
430
|
+
{visibleItems.map((item, index) => (
|
|
431
|
+
<div key={index}>{renderViewItem(item, index)}</div>
|
|
432
|
+
))}
|
|
433
|
+
</div>
|
|
434
|
+
)
|
|
435
|
+
)}
|
|
436
|
+
|
|
437
|
+
{showFooter && (
|
|
438
|
+
<div className="ss-foot">
|
|
439
|
+
{edit && onFootNoteChange ? (
|
|
440
|
+
<EditablePlainText
|
|
441
|
+
tag="span"
|
|
442
|
+
value={footNote}
|
|
443
|
+
onChange={onFootNoteChange}
|
|
444
|
+
isEditMode={true}
|
|
445
|
+
placeholder={autoNote || "Footer note"}
|
|
446
|
+
/>
|
|
447
|
+
) : (
|
|
448
|
+
<span>{footNote.trim() || autoNote}</span>
|
|
449
|
+
)}
|
|
450
|
+
{showCopyButton && (
|
|
451
|
+
<button
|
|
452
|
+
type="button"
|
|
453
|
+
className={copied ? "ss-copy ss-copied" : "ss-copy"}
|
|
454
|
+
aria-live="polite"
|
|
455
|
+
onClick={edit ? onCopyClick : undefined}
|
|
456
|
+
>
|
|
457
|
+
{copied ? "✓ Copied" : "⧉ Copy summary"}
|
|
458
|
+
</button>
|
|
459
|
+
)}
|
|
460
|
+
</div>
|
|
461
|
+
)}
|
|
462
|
+
|
|
463
|
+
{!edit && showCopyButton && <script dangerouslySetInnerHTML={{ __html: copyScript(p) }} />}
|
|
464
|
+
</div>
|
|
465
|
+
);
|
|
466
|
+
const hint = edit && navHint ? <p className="mt-2 text-xs text-warning">{navHint}</p> : null;
|
|
467
|
+
if (!navAnchor && !hint) return plate;
|
|
468
|
+
|
|
469
|
+
return (
|
|
470
|
+
// The nav anchor sits on a wrapper: the plate's own id is the CSS/script scope.
|
|
471
|
+
<div id={navAnchor} className={navAnchor ? "scroll-mt-20" : undefined}>
|
|
472
|
+
{plate}
|
|
473
|
+
{hint}
|
|
474
|
+
</div>
|
|
475
|
+
);
|
|
476
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { Input } from "../../shared/Input";
|
|
3
|
+
import { Select } from "../../shared/Select";
|
|
4
|
+
import { Checkbox } from "../../shared/Checkbox";
|
|
5
|
+
import { Tabs } from "../../shared/Tabs";
|
|
6
|
+
import type { SummaryNavLevel as NavLevel } from "../../../lib/nav";
|
|
7
|
+
|
|
8
|
+
interface Values {
|
|
9
|
+
kicker: string;
|
|
10
|
+
accent: string;
|
|
11
|
+
footNote: string;
|
|
12
|
+
showAccent: boolean;
|
|
13
|
+
showFooter: boolean;
|
|
14
|
+
showCopy: boolean;
|
|
15
|
+
numbered: boolean;
|
|
16
|
+
nav: NavLevel;
|
|
17
|
+
navLabel: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const navOptions = [
|
|
21
|
+
{ label: "Off", value: "off" },
|
|
22
|
+
{ label: "Heading", value: "heading" },
|
|
23
|
+
{ label: "Subheading", value: "subheading" },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
// A custom form rather than declarative `settings`: turning nav on prefills the
|
|
27
|
+
// label from the kicker, and the label is required while nav is on.
|
|
28
|
+
export function SectionSummarySettings({
|
|
29
|
+
kicker = "",
|
|
30
|
+
accent = "",
|
|
31
|
+
footNote = "",
|
|
32
|
+
showAccent = true,
|
|
33
|
+
showFooter = true,
|
|
34
|
+
showCopy = true,
|
|
35
|
+
numbered = true,
|
|
36
|
+
nav = "off",
|
|
37
|
+
navLabel = "",
|
|
38
|
+
onChange,
|
|
39
|
+
}: Partial<Values> & {
|
|
40
|
+
onChange: (result: { content: Record<string, unknown>; options: Record<string, unknown> }) => void;
|
|
41
|
+
}) {
|
|
42
|
+
const [v, setV] = useState<Values>({ kicker, accent, footNote, showAccent, showFooter, showCopy, numbered, nav, navLabel });
|
|
43
|
+
|
|
44
|
+
const update = (patch: Partial<Values>) => {
|
|
45
|
+
const next = { ...v, ...patch };
|
|
46
|
+
setV(next);
|
|
47
|
+
onChange({
|
|
48
|
+
content: { kicker: next.kicker, accent: next.accent, footNote: next.footNote },
|
|
49
|
+
options: {
|
|
50
|
+
showAccent: next.showAccent,
|
|
51
|
+
showFooter: next.showFooter,
|
|
52
|
+
showCopy: next.showCopy,
|
|
53
|
+
numbered: next.numbered,
|
|
54
|
+
// Off is stored as an absent key; the label is kept so turning nav back
|
|
55
|
+
// on restores it.
|
|
56
|
+
nav: next.nav === "off" ? undefined : next.nav,
|
|
57
|
+
navLabel: next.navLabel,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const navOn = v.nav !== "off";
|
|
63
|
+
const panel = "flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-px";
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<Tabs
|
|
67
|
+
fullBleedTabBar
|
|
68
|
+
tabs={[
|
|
69
|
+
{
|
|
70
|
+
id: "text",
|
|
71
|
+
label: "Text",
|
|
72
|
+
content: (
|
|
73
|
+
<div className={panel}>
|
|
74
|
+
<Input label="Kicker" value={v.kicker} placeholder="Brand Color — Summary" onChange={(kicker) => update({ kicker })} />
|
|
75
|
+
<Input label="Accent flourish" value={v.accent} placeholder="tl;dr" onChange={(accent) => update({ accent })} />
|
|
76
|
+
<Input label="Footer note" value={v.footNote} placeholder="Brand Color · 06 principles" onChange={(footNote) => update({ footNote })} />
|
|
77
|
+
</div>
|
|
78
|
+
),
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: "display",
|
|
82
|
+
label: "Display",
|
|
83
|
+
content: (
|
|
84
|
+
<div className={panel}>
|
|
85
|
+
<Checkbox label="Show accent" checked={v.showAccent} onChange={(showAccent) => update({ showAccent })} />
|
|
86
|
+
<Checkbox label="Show footer" checked={v.showFooter} onChange={(showFooter) => update({ showFooter })} />
|
|
87
|
+
<Checkbox label="Show copy action" checked={v.showCopy} onChange={(showCopy) => update({ showCopy })} />
|
|
88
|
+
<Checkbox label="Number the items" checked={v.numbered} onChange={(numbered) => update({ numbered })} />
|
|
89
|
+
</div>
|
|
90
|
+
),
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: "nav",
|
|
94
|
+
label: "Navigation",
|
|
95
|
+
content: (
|
|
96
|
+
<div className={panel}>
|
|
97
|
+
<Select
|
|
98
|
+
label="Nav"
|
|
99
|
+
value={v.nav}
|
|
100
|
+
options={navOptions}
|
|
101
|
+
onChange={(value) => {
|
|
102
|
+
const level = value as NavLevel;
|
|
103
|
+
const prefill = level !== "off" && !v.navLabel.trim();
|
|
104
|
+
update(prefill ? { nav: level, navLabel: v.kicker } : { nav: level });
|
|
105
|
+
}}
|
|
106
|
+
/>
|
|
107
|
+
{v.nav === "subheading" && (
|
|
108
|
+
<p className="-mt-2 text-xs text-base-contrast-light">
|
|
109
|
+
Nests under the nearest Link Heading above this plate; with none above it, it is left out of the nav.
|
|
110
|
+
</p>
|
|
111
|
+
)}
|
|
112
|
+
{navOn && (
|
|
113
|
+
<Input
|
|
114
|
+
label="Nav label"
|
|
115
|
+
value={v.navLabel}
|
|
116
|
+
onChange={(label) => update({ navLabel: label })}
|
|
117
|
+
error={v.navLabel.trim() ? undefined : "Required while this plate is in the nav."}
|
|
118
|
+
/>
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
),
|
|
122
|
+
},
|
|
123
|
+
]}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
}
|