@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.
Files changed (483) hide show
  1. package/README.md +1 -1
  2. package/dist/auth/cookies.d.ts +39 -0
  3. package/dist/auth/cookies.d.ts.map +1 -1
  4. package/dist/auth/index.js +3 -3
  5. package/dist/{chunk-GPPVYLEI.js → chunk-45FA7Z55.js} +1 -1
  6. package/dist/{chunk-REDDTTGJ.js → chunk-4Y2JQQZL.js} +19 -1
  7. package/dist/chunk-5GFACGSN.js +6 -0
  8. package/dist/chunk-5KSAS4VY.js +275 -0
  9. package/dist/{chunk-Z7W3DQTR.js → chunk-7SAAJVDE.js} +408 -28
  10. package/dist/{chunk-S2L3BPLS.js → chunk-7SX42OP4.js} +1 -1
  11. package/dist/{chunk-GGXZZ77Z.js → chunk-AASEGXNT.js} +18 -1
  12. package/dist/{chunk-WKZ7OENC.js → chunk-BQ5TZZUE.js} +5 -1
  13. package/dist/chunk-DIMDRBFK.js +11 -0
  14. package/dist/{chunk-WUJ3XNFI.js → chunk-GGYY3JQJ.js} +19 -24
  15. package/dist/{chunk-NHN2LSIU.js → chunk-IP2SEBAJ.js} +5 -1
  16. package/dist/{chunk-IINIZBQB.js → chunk-JCDZAFX2.js} +30 -10
  17. package/dist/chunk-JR24U7FJ.js +120 -0
  18. package/dist/{chunk-SW6PCQQD.js → chunk-KQA772WQ.js} +2 -1
  19. package/dist/{chunk-KR2MHTNJ.js → chunk-N3G7DOU3.js} +609 -61
  20. package/dist/chunk-OAGJBCSH.js +67 -0
  21. package/dist/{chunk-6BZ2KNTP.js → chunk-PLANHXS7.js} +191 -61
  22. package/dist/{chunk-VWWY5TL5.js → chunk-PNSCDBU7.js} +38 -56
  23. package/dist/{chunk-AHALSCQH.js → chunk-PTY2RG2K.js} +1 -1
  24. package/dist/{chunk-BDFTMGCL.js → chunk-PZPGJZRG.js} +9 -8
  25. package/dist/{chunk-FRE2CCLV.js → chunk-QHMKIODQ.js} +17 -4
  26. package/dist/{chunk-HBULBDGP.js → chunk-S37DZPHW.js} +1 -1
  27. package/dist/{chunk-4I5OO5UB.js → chunk-TEOAKGZA.js} +0 -1
  28. package/dist/chunk-VUYCRBJK.js +174 -0
  29. package/dist/{chunk-4RNF2DRG.js → chunk-XDEPXTBY.js} +0 -2
  30. package/dist/{chunk-DS4GCYV2.js → chunk-Y5QECJX7.js} +223 -16
  31. package/dist/collab/rebase.d.ts +2 -1
  32. package/dist/collab/rebase.d.ts.map +1 -1
  33. package/dist/collab/rebase.js +20 -5
  34. package/dist/components/brandguide/ColorsEditable.d.ts.map +1 -1
  35. package/dist/components/chat/ChatPanel.d.ts.map +1 -1
  36. package/dist/components/chat/ChatWidget.d.ts.map +1 -1
  37. package/dist/components/docfile/DocFilePane.d.ts.map +1 -1
  38. package/dist/components/editor/ChildBlockWrapper.d.ts.map +1 -1
  39. package/dist/components/editor/ConflictDialog.d.ts.map +1 -1
  40. package/dist/components/editor/DragHandle.d.ts +12 -2
  41. package/dist/components/editor/DragHandle.d.ts.map +1 -1
  42. package/dist/components/editor/DropEdgeIndicator.d.ts +15 -6
  43. package/dist/components/editor/DropEdgeIndicator.d.ts.map +1 -1
  44. package/dist/components/editor/NavGroupRow.d.ts +4 -1
  45. package/dist/components/editor/NavGroupRow.d.ts.map +1 -1
  46. package/dist/components/editor/PagesModal.d.ts.map +1 -1
  47. package/dist/components/editor/SectionWrapper.d.ts +1 -1
  48. package/dist/components/editor/SectionWrapper.d.ts.map +1 -1
  49. package/dist/components/editor/SettingsForm.d.ts.map +1 -1
  50. package/dist/components/editor/TagIndicator.d.ts +15 -0
  51. package/dist/components/editor/TagIndicator.d.ts.map +1 -0
  52. package/dist/components/editor/index.js +148 -77
  53. package/dist/components/primitives/DocumentDropZone.d.ts +1 -1
  54. package/dist/components/primitives/EditableGrid.d.ts.map +1 -1
  55. package/dist/components/primitives/EditableList.d.ts.map +1 -1
  56. package/dist/components/primitives/HeadingSection.d.ts +4 -1
  57. package/dist/components/primitives/HeadingSection.d.ts.map +1 -1
  58. package/dist/components/primitives/ResolvedMedia.d.ts +5 -1
  59. package/dist/components/primitives/ResolvedMedia.d.ts.map +1 -1
  60. package/dist/components/primitives/{defineHeadingSection.d.ts → define-heading-section.d.ts} +1 -1
  61. package/dist/components/primitives/define-heading-section.d.ts.map +1 -0
  62. package/dist/components/primitives/{gridDrop.d.ts → grid-drop.d.ts} +1 -1
  63. package/dist/components/primitives/grid-drop.d.ts.map +1 -0
  64. package/dist/components/primitives/index.d.ts +1 -1
  65. package/dist/components/primitives/index.d.ts.map +1 -1
  66. package/dist/components/primitives/index.js +17 -154
  67. package/dist/components/sections/Button/CTAButton.d.ts.map +1 -1
  68. package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts +2 -6
  69. package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts.map +1 -1
  70. package/dist/components/sections/DoDontMedia/index.d.ts +8 -0
  71. package/dist/components/sections/DoDontMedia/index.d.ts.map +1 -1
  72. package/dist/components/sections/IconList/IconList.d.ts +2 -1
  73. package/dist/components/sections/IconList/IconList.d.ts.map +1 -1
  74. package/dist/components/sections/IconList/IconListSettings.d.ts +2 -1
  75. package/dist/components/sections/IconList/IconListSettings.d.ts.map +1 -1
  76. package/dist/components/sections/IconList/index.d.ts +1 -0
  77. package/dist/components/sections/IconList/index.d.ts.map +1 -1
  78. package/dist/components/sections/Media/MediaBlock.d.ts +2 -1
  79. package/dist/components/sections/Media/MediaBlock.d.ts.map +1 -1
  80. package/dist/components/sections/Media/index.d.ts +8 -0
  81. package/dist/components/sections/Media/index.d.ts.map +1 -1
  82. package/dist/components/sections/Reference/ReferenceList.d.ts +35 -0
  83. package/dist/components/sections/Reference/ReferenceList.d.ts.map +1 -0
  84. package/dist/components/sections/Reference/ReferenceSettings.d.ts +12 -0
  85. package/dist/components/sections/Reference/ReferenceSettings.d.ts.map +1 -0
  86. package/dist/components/sections/Reference/index.d.ts +9 -0
  87. package/dist/components/sections/Reference/index.d.ts.map +1 -0
  88. package/dist/components/sections/SectionSummary/SectionSummaryBlock.d.ts +38 -0
  89. package/dist/components/sections/SectionSummary/SectionSummaryBlock.d.ts.map +1 -0
  90. package/dist/components/sections/SectionSummary/SectionSummarySettings.d.ts +20 -0
  91. package/dist/components/sections/SectionSummary/SectionSummarySettings.d.ts.map +1 -0
  92. package/dist/components/sections/SectionSummary/index.d.ts +33 -0
  93. package/dist/components/sections/SectionSummary/index.d.ts.map +1 -0
  94. package/dist/components/sections/all-sections.d.ts +53 -0
  95. package/dist/components/sections/all-sections.d.ts.map +1 -1
  96. package/dist/components/sections/brand-guide.d.ts +41 -2
  97. package/dist/components/sections/brand-guide.d.ts.map +1 -1
  98. package/dist/components/sections/brand-guide.js +12 -10
  99. package/dist/components/sections/core-sections.d.ts +14 -0
  100. package/dist/components/sections/core-sections.d.ts.map +1 -1
  101. package/dist/components/sections/register-schemas.js +19 -17
  102. package/dist/components/sections/register.js +19 -17
  103. package/dist/components/shared/BrandSwatchesContext.d.ts +9 -0
  104. package/dist/components/shared/BrandSwatchesContext.d.ts.map +1 -0
  105. package/dist/components/shared/Button.d.ts +11 -3
  106. package/dist/components/shared/Button.d.ts.map +1 -1
  107. package/dist/components/shared/Checkbox.d.ts +6 -0
  108. package/dist/components/shared/Checkbox.d.ts.map +1 -1
  109. package/dist/components/shared/ConfirmDialog.d.ts +25 -0
  110. package/dist/components/shared/ConfirmDialog.d.ts.map +1 -0
  111. package/dist/components/shared/ConfirmInline.d.ts +25 -0
  112. package/dist/components/shared/ConfirmInline.d.ts.map +1 -0
  113. package/dist/components/shared/ErrorBoundary.d.ts.map +1 -1
  114. package/dist/components/shared/Fab.d.ts +11 -2
  115. package/dist/components/shared/Fab.d.ts.map +1 -1
  116. package/dist/components/shared/FabStack.d.ts +22 -0
  117. package/dist/components/shared/FabStack.d.ts.map +1 -0
  118. package/dist/components/shared/HistoryChangesModal.d.ts.map +1 -1
  119. package/dist/components/shared/HistoryPopover.d.ts.map +1 -1
  120. package/dist/components/shared/ImageBackgroundField.d.ts +9 -0
  121. package/dist/components/shared/ImageBackgroundField.d.ts.map +1 -0
  122. package/dist/components/shared/{UploadRejectionAlert.d.ts → InlineAlert.d.ts} +4 -2
  123. package/dist/components/shared/InlineAlert.d.ts.map +1 -0
  124. package/dist/components/shared/Input.d.ts +10 -0
  125. package/dist/components/shared/Input.d.ts.map +1 -1
  126. package/dist/components/shared/Navigation.d.ts.map +1 -1
  127. package/dist/components/shared/Notice.d.ts +10 -0
  128. package/dist/components/shared/Notice.d.ts.map +1 -0
  129. package/dist/components/shared/Popover.d.ts.map +1 -1
  130. package/dist/components/shared/ReferenceSourcesContext.d.ts +25 -0
  131. package/dist/components/shared/ReferenceSourcesContext.d.ts.map +1 -0
  132. package/dist/components/shared/Select.d.ts +3 -2
  133. package/dist/components/shared/Select.d.ts.map +1 -1
  134. package/dist/components/shared/SplitButton.d.ts.map +1 -1
  135. package/dist/components/shared/SummaryAnchorsContext.d.ts +10 -0
  136. package/dist/components/shared/SummaryAnchorsContext.d.ts.map +1 -0
  137. package/dist/components/shared/Textarea.d.ts +7 -0
  138. package/dist/components/shared/Textarea.d.ts.map +1 -1
  139. package/dist/components/shared/ToolbarFrame.d.ts +17 -0
  140. package/dist/components/shared/ToolbarFrame.d.ts.map +1 -0
  141. package/dist/components/shared/copy.d.ts +13 -0
  142. package/dist/components/shared/copy.d.ts.map +1 -0
  143. package/dist/components/shared/icons.d.ts +0 -12
  144. package/dist/components/shared/icons.d.ts.map +1 -1
  145. package/dist/components/shell/AudienceDetailsPanel.d.ts +7 -1
  146. package/dist/components/shell/AudienceDetailsPanel.d.ts.map +1 -1
  147. package/dist/components/shell/AudienceRow.d.ts.map +1 -1
  148. package/dist/components/shell/BugReportFAB.d.ts +7 -1
  149. package/dist/components/shell/BugReportFAB.d.ts.map +1 -1
  150. package/dist/components/shell/CredentialList.d.ts.map +1 -1
  151. package/dist/components/shell/DocInspector.d.ts.map +1 -1
  152. package/dist/components/shell/DocumentEditorOverlay.d.ts.map +1 -1
  153. package/dist/components/shell/EditorContext.d.ts +4 -0
  154. package/dist/components/shell/EditorContext.d.ts.map +1 -1
  155. package/dist/components/shell/EditorLoginForm.d.ts.map +1 -1
  156. package/dist/components/shell/EditorModal.d.ts.map +1 -1
  157. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  158. package/dist/components/shell/HistoryToolbar.d.ts.map +1 -1
  159. package/dist/components/shell/MediaFolderTile.d.ts +4 -1
  160. package/dist/components/shell/MediaFolderTile.d.ts.map +1 -1
  161. package/dist/components/shell/MediaLibraryModal.d.ts.map +1 -1
  162. package/dist/components/shell/RestoreModal.d.ts.map +1 -1
  163. package/dist/components/shell/SiteSettingsChatbot.d.ts.map +1 -1
  164. package/dist/components/shell/SiteSettingsDisplay.d.ts.map +1 -1
  165. package/dist/components/shell/SiteSettingsModal.d.ts +3 -1
  166. package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
  167. package/dist/components/shell/SiteSettingsTags.d.ts +13 -0
  168. package/dist/components/shell/SiteSettingsTags.d.ts.map +1 -0
  169. package/dist/components/shell/SiteSettingsUsers.d.ts.map +1 -1
  170. package/dist/components/shell/ViewerLoginForm.d.ts.map +1 -1
  171. package/dist/components/shell/{blockMoveDispatch.d.ts → block-move-dispatch.d.ts} +1 -1
  172. package/dist/components/shell/block-move-dispatch.d.ts.map +1 -0
  173. package/dist/components/shell/reference-sources.d.ts +22 -0
  174. package/dist/components/shell/reference-sources.d.ts.map +1 -0
  175. package/dist/deck/index.d.ts +2 -2
  176. package/dist/deck/index.d.ts.map +1 -1
  177. package/dist/deck/index.js +1 -3
  178. package/dist/deck-builder/index.js +11 -18
  179. package/dist/document/index.d.ts +2 -2
  180. package/dist/document/index.d.ts.map +1 -1
  181. package/dist/hooks/useBlockDnd.d.ts +11 -0
  182. package/dist/hooks/useBlockDnd.d.ts.map +1 -1
  183. package/dist/hooks/useBuildStatus.d.ts +1 -1
  184. package/dist/hooks/useBuildStatus.d.ts.map +1 -1
  185. package/dist/hooks/useDocumentUploads.d.ts +1 -1
  186. package/dist/hooks/useDocumentUploads.d.ts.map +1 -1
  187. package/dist/hooks/useEditorPersistence.d.ts +5 -1
  188. package/dist/hooks/useEditorPersistence.d.ts.map +1 -1
  189. package/dist/hooks/useEditorPublish.d.ts +2 -2
  190. package/dist/hooks/useEditorPublish.d.ts.map +1 -1
  191. package/dist/hooks/useNotice.d.ts +19 -0
  192. package/dist/hooks/useNotice.d.ts.map +1 -0
  193. package/dist/hooks/useSortableNavRow.d.ts +11 -0
  194. package/dist/hooks/useSortableNavRow.d.ts.map +1 -1
  195. package/dist/hooks/useSortableRow.d.ts +11 -0
  196. package/dist/hooks/useSortableRow.d.ts.map +1 -1
  197. package/dist/hooks/useStackedEscape.d.ts +32 -0
  198. package/dist/hooks/useStackedEscape.d.ts.map +1 -0
  199. package/dist/index.js +67 -49
  200. package/dist/lib/audience-secret.js +2 -2
  201. package/dist/lib/block-dnd.d.ts +5 -0
  202. package/dist/lib/block-dnd.d.ts.map +1 -1
  203. package/dist/lib/block-move.d.ts.map +1 -1
  204. package/dist/lib/brand-swatches.d.ts +12 -0
  205. package/dist/lib/brand-swatches.d.ts.map +1 -0
  206. package/dist/lib/container-ops.d.ts +3 -2
  207. package/dist/lib/container-ops.d.ts.map +1 -1
  208. package/dist/lib/dexie.d.ts.map +1 -1
  209. package/dist/lib/dexie.js +9 -1
  210. package/dist/lib/env.d.ts +4 -0
  211. package/dist/lib/env.d.ts.map +1 -1
  212. package/dist/lib/env.js +5 -3
  213. package/dist/lib/events.d.ts +1 -2
  214. package/dist/lib/events.d.ts.map +1 -1
  215. package/dist/lib/image-background.d.ts +8 -0
  216. package/dist/lib/image-background.d.ts.map +1 -0
  217. package/dist/lib/index-ops.js +3 -3
  218. package/dist/lib/index.d.ts +6 -4
  219. package/dist/lib/index.d.ts.map +1 -1
  220. package/dist/lib/index.js +29 -21
  221. package/dist/lib/loader.d.ts +21 -7
  222. package/dist/lib/loader.d.ts.map +1 -1
  223. package/dist/lib/nav-tree.d.ts +1 -0
  224. package/dist/lib/nav-tree.d.ts.map +1 -1
  225. package/dist/lib/nav.d.ts +38 -0
  226. package/dist/lib/nav.d.ts.map +1 -1
  227. package/dist/lib/platform-broker.d.ts +4 -2
  228. package/dist/lib/platform-broker.d.ts.map +1 -1
  229. package/dist/lib/platform-broker.js +21 -13
  230. package/dist/lib/reference-type.d.ts +2 -0
  231. package/dist/lib/reference-type.d.ts.map +1 -0
  232. package/dist/lib/reference-validation.d.ts +31 -0
  233. package/dist/lib/reference-validation.d.ts.map +1 -0
  234. package/dist/lib/reference-validation.js +39 -0
  235. package/dist/lib/references.d.ts +74 -0
  236. package/dist/lib/references.d.ts.map +1 -0
  237. package/dist/lib/registry.d.ts +35 -0
  238. package/dist/lib/registry.d.ts.map +1 -1
  239. package/dist/lib/{safeRedirect.d.ts → safe-redirect.d.ts} +1 -1
  240. package/dist/lib/safe-redirect.d.ts.map +1 -0
  241. package/dist/lib/tags.d.ts +58 -0
  242. package/dist/lib/tags.d.ts.map +1 -0
  243. package/dist/lib/theme-vars.d.ts +9 -0
  244. package/dist/lib/theme-vars.d.ts.map +1 -1
  245. package/dist/media/index.d.ts +1 -1
  246. package/dist/media/index.d.ts.map +1 -1
  247. package/dist/media/index.js +8 -4
  248. package/dist/media/utils.d.ts +2 -0
  249. package/dist/media/utils.d.ts.map +1 -1
  250. package/dist/media/{videoPoster.d.ts → video-poster.d.ts} +1 -1
  251. package/dist/media/video-poster.d.ts.map +1 -0
  252. package/dist/schemas/audience.js +2 -2
  253. package/dist/schemas/index.d.ts +1 -0
  254. package/dist/schemas/index.d.ts.map +1 -1
  255. package/dist/schemas/index.js +14 -8
  256. package/dist/schemas/shared.d.ts +26 -0
  257. package/dist/schemas/shared.d.ts.map +1 -1
  258. package/dist/schemas/site-config.d.ts +6 -0
  259. package/dist/schemas/site-config.d.ts.map +1 -1
  260. package/dist/schemas/tags.d.ts +27 -0
  261. package/dist/schemas/tags.d.ts.map +1 -0
  262. package/dist/storage/index.js +1 -1
  263. package/dist/types/database.d.ts.map +1 -1
  264. package/package.json +6 -1
  265. package/src/auth/cookies.ts +111 -0
  266. package/src/collab/rebase.ts +26 -2
  267. package/src/components/brandguide/ColorSwatchSettings.tsx +1 -1
  268. package/src/components/brandguide/ColorsEditable.tsx +1 -0
  269. package/src/components/chat/ChatPanel.tsx +2 -3
  270. package/src/components/chat/ChatWidget.tsx +2 -3
  271. package/src/components/docfile/DocFilePane.tsx +4 -12
  272. package/src/components/editor/ChildBlockWrapper.tsx +13 -19
  273. package/src/components/editor/ConflictDialog.tsx +27 -35
  274. package/src/components/editor/DeleteButton.tsx +2 -2
  275. package/src/components/editor/DragHandle.tsx +16 -3
  276. package/src/components/editor/DropEdgeIndicator.tsx +36 -10
  277. package/src/components/editor/InsertButton.tsx +2 -2
  278. package/src/components/editor/NavGroupRow.tsx +43 -14
  279. package/src/components/editor/PagesModal.tsx +99 -26
  280. package/src/components/editor/SectionWrapper.tsx +64 -23
  281. package/src/components/editor/SettingsButton.tsx +2 -2
  282. package/src/components/editor/SettingsForm.tsx +19 -2
  283. package/src/components/editor/StatusIndicator.tsx +4 -4
  284. package/src/components/editor/TagIndicator.tsx +80 -0
  285. package/src/components/primitives/DocumentDropZone.tsx +1 -1
  286. package/src/components/primitives/EditableGrid.tsx +15 -14
  287. package/src/components/primitives/EditableList.tsx +27 -74
  288. package/src/components/primitives/HeadingSection.tsx +5 -2
  289. package/src/components/primitives/ResolvedMedia.tsx +13 -0
  290. package/src/components/primitives/{defineHeadingSection.tsx → define-heading-section.tsx} +1 -0
  291. package/src/components/primitives/index.ts +1 -1
  292. package/src/components/primitives/useEditablePlainText.ts +5 -5
  293. package/src/components/sections/Button/CTAButton.tsx +3 -1
  294. package/src/components/sections/DoDontMedia/DoDontMediaBlock.tsx +4 -4
  295. package/src/components/sections/DoDontMedia/index.tsx +12 -3
  296. package/src/components/sections/IconList/DoDontToggle.tsx +2 -2
  297. package/src/components/sections/IconList/IconList.tsx +70 -37
  298. package/src/components/sections/IconList/IconListSettings.tsx +55 -17
  299. package/src/components/sections/IconList/index.tsx +10 -3
  300. package/src/components/sections/LinkHeading/index.tsx +1 -1
  301. package/src/components/sections/Media/MediaBlock.tsx +13 -2
  302. package/src/components/sections/Media/index.tsx +12 -4
  303. package/src/components/sections/Reference/ReferenceList.tsx +214 -0
  304. package/src/components/sections/Reference/ReferenceSettings.tsx +159 -0
  305. package/src/components/sections/Reference/index.tsx +47 -0
  306. package/src/components/sections/SectionSummary/SectionSummaryBlock.tsx +476 -0
  307. package/src/components/sections/SectionSummary/SectionSummarySettings.tsx +126 -0
  308. package/src/components/sections/SectionSummary/index.tsx +149 -0
  309. package/src/components/sections/SubHeading/index.tsx +1 -1
  310. package/src/components/sections/SubSubHeading/index.tsx +1 -1
  311. package/src/components/sections/brand-guide.ts +4 -3
  312. package/src/components/sections/core-sections.ts +2 -0
  313. package/src/components/shared/BrandSwatchesContext.ts +13 -0
  314. package/src/components/shared/Button.tsx +47 -34
  315. package/src/components/shared/Checkbox.tsx +21 -12
  316. package/src/components/shared/ConfirmDialog.tsx +87 -0
  317. package/src/components/shared/ConfirmInline.tsx +90 -0
  318. package/src/components/shared/ErrorBoundary.tsx +6 -18
  319. package/src/components/shared/Fab.tsx +15 -5
  320. package/src/components/shared/FabStack.tsx +28 -0
  321. package/src/components/shared/HistoryChangesModal.tsx +43 -41
  322. package/src/components/shared/HistoryPopover.tsx +7 -20
  323. package/src/components/shared/ImageBackgroundField.tsx +92 -0
  324. package/src/components/shared/{UploadRejectionAlert.tsx → InlineAlert.tsx} +21 -5
  325. package/src/components/shared/Input.tsx +23 -7
  326. package/src/components/shared/Navigation.tsx +22 -17
  327. package/src/components/shared/Notice.tsx +59 -0
  328. package/src/components/shared/Popover.tsx +7 -11
  329. package/src/components/shared/ReferenceSourcesContext.ts +27 -0
  330. package/src/components/shared/Select.tsx +5 -2
  331. package/src/components/shared/SplitButton.tsx +11 -17
  332. package/src/components/shared/SummaryAnchorsContext.ts +11 -0
  333. package/src/components/shared/Textarea.tsx +17 -2
  334. package/src/components/shared/ToolbarFrame.tsx +28 -0
  335. package/src/components/shared/VideoSourceField.tsx +1 -1
  336. package/src/components/shared/copy.ts +18 -0
  337. package/src/components/shared/icons.tsx +1 -17
  338. package/src/components/shell/AudienceAddForm.tsx +2 -2
  339. package/src/components/shell/AudienceDetailsPanel.tsx +23 -5
  340. package/src/components/shell/AudienceRow.tsx +22 -15
  341. package/src/components/shell/BugReportFAB.tsx +50 -40
  342. package/src/components/shell/CredentialList.tsx +33 -13
  343. package/src/components/shell/DocInspector.tsx +3 -12
  344. package/src/components/shell/DocumentEditorOverlay.tsx +33 -23
  345. package/src/components/shell/EditorContext.tsx +7 -0
  346. package/src/components/shell/EditorLoginForm.tsx +26 -36
  347. package/src/components/shell/EditorModal.tsx +8 -10
  348. package/src/components/shell/EditorShell.tsx +499 -339
  349. package/src/components/shell/HistoryToolbar.tsx +24 -26
  350. package/src/components/shell/MediaFolderTile.tsx +8 -3
  351. package/src/components/shell/MediaLibraryModal.tsx +59 -60
  352. package/src/components/shell/ProcessingIndicator.tsx +2 -2
  353. package/src/components/shell/RestoreModal.tsx +17 -16
  354. package/src/components/shell/SetPasswordForm.tsx +3 -3
  355. package/src/components/shell/SiteSettingsChatbot.tsx +61 -42
  356. package/src/components/shell/SiteSettingsDisplay.tsx +10 -20
  357. package/src/components/shell/SiteSettingsModal.tsx +24 -2
  358. package/src/components/shell/SiteSettingsTags.tsx +143 -0
  359. package/src/components/shell/SiteSettingsUsers.tsx +36 -26
  360. package/src/components/shell/SiteSettingsViewerAccess.tsx +2 -2
  361. package/src/components/shell/ViewerLoginForm.tsx +5 -4
  362. package/src/components/shell/reference-sources.ts +36 -0
  363. package/src/deck/index.ts +2 -2
  364. package/src/document/index.ts +2 -2
  365. package/src/hooks/useBlockDnd.ts +11 -0
  366. package/src/hooks/useBuildStatus.ts +53 -6
  367. package/src/hooks/useDocumentUploads.ts +1 -1
  368. package/src/hooks/useEditorPersistence.ts +141 -35
  369. package/src/hooks/useEditorPublish.ts +18 -27
  370. package/src/hooks/useMediaPipeline.ts +1 -1
  371. package/src/hooks/useNotice.ts +45 -0
  372. package/src/hooks/useSortableNavRow.ts +11 -0
  373. package/src/hooks/useSortableRow.ts +22 -2
  374. package/src/hooks/useStackedEscape.ts +62 -0
  375. package/src/lib/block-dnd.ts +6 -1
  376. package/src/lib/block-move.ts +3 -0
  377. package/src/lib/brand-swatches.ts +32 -0
  378. package/src/lib/container-ops.ts +5 -3
  379. package/src/lib/dexie.ts +15 -1
  380. package/src/lib/env.ts +9 -0
  381. package/src/lib/events.ts +1 -2
  382. package/src/lib/image-background.ts +31 -0
  383. package/src/lib/index.ts +5 -4
  384. package/src/lib/loader.ts +54 -55
  385. package/src/lib/nav-tree.ts +71 -0
  386. package/src/lib/nav.ts +196 -36
  387. package/src/lib/platform-broker.ts +32 -14
  388. package/src/lib/reference-type.ts +3 -0
  389. package/src/lib/reference-validation.ts +69 -0
  390. package/src/lib/references.ts +130 -0
  391. package/src/lib/registry.ts +37 -0
  392. package/src/lib/tags.ts +148 -0
  393. package/src/lib/theme-vars.ts +23 -0
  394. package/src/media/index.ts +1 -1
  395. package/src/media/utils.ts +18 -0
  396. package/src/media/{videoPoster.ts → video-poster.ts} +2 -2
  397. package/src/schemas/index.ts +1 -0
  398. package/src/schemas/shared.ts +24 -1
  399. package/src/schemas/site-config.ts +6 -1
  400. package/src/schemas/tags.ts +33 -0
  401. package/src/storage/types.ts +1 -1
  402. package/src/types/database.ts +2 -0
  403. package/dist/chunk-DNY72JZN.js +0 -86
  404. package/dist/chunk-F2LYQPXV.js +0 -77
  405. package/dist/chunk-JH762VUH.js +0 -128
  406. package/dist/chunk-K7DYZXVU.js +0 -138
  407. package/dist/components/primitives/defineHeadingSection.d.ts.map +0 -1
  408. package/dist/components/primitives/gridDrop.d.ts.map +0 -1
  409. package/dist/components/shared/UploadRejectionAlert.d.ts.map +0 -1
  410. package/dist/components/shell/BuildStatusIndicator.d.ts +0 -7
  411. package/dist/components/shell/BuildStatusIndicator.d.ts.map +0 -1
  412. package/dist/components/shell/blockMoveDispatch.d.ts.map +0 -1
  413. package/dist/hooks/index.d.ts +0 -9
  414. package/dist/hooks/index.d.ts.map +0 -1
  415. package/dist/lib/grid.d.ts +0 -2
  416. package/dist/lib/grid.d.ts.map +0 -1
  417. package/dist/lib/safeRedirect.d.ts.map +0 -1
  418. package/dist/media/videoPoster.d.ts.map +0 -1
  419. package/src/components/brandguide/ColorSwatchSettings.d.ts.map +0 -1
  420. package/src/components/brandguide/Colors.d.ts.map +0 -1
  421. package/src/components/primitives/CustomParagraph.d.ts.map +0 -1
  422. package/src/components/primitives/EditableGrid.d.ts.map +0 -1
  423. package/src/components/primitives/EditablePlainText.d.ts.map +0 -1
  424. package/src/components/primitives/EditableRichText.d.ts.map +0 -1
  425. package/src/components/primitives/HeadingSection.d.ts.map +0 -1
  426. package/src/components/primitives/IconPicker.d.ts.map +0 -1
  427. package/src/components/primitives/LinkPopover.d.ts.map +0 -1
  428. package/src/components/primitives/MediaSettingsForms.d.ts.map +0 -1
  429. package/src/components/primitives/ResolvedMedia.d.ts.map +0 -1
  430. package/src/components/primitives/RichTextToolbar.d.ts.map +0 -1
  431. package/src/components/primitives/tiptap-presets.d.ts.map +0 -1
  432. package/src/components/primitives/useEditableCollection.d.ts.map +0 -1
  433. package/src/components/primitives/useEditablePlainText.d.ts.map +0 -1
  434. package/src/components/primitives/useEditableRichText.d.ts.map +0 -1
  435. package/src/components/sections/Button/CTAButton.d.ts.map +0 -1
  436. package/src/components/sections/Button/index.d.ts.map +0 -1
  437. package/src/components/sections/Colors/index.d.ts.map +0 -1
  438. package/src/components/sections/IconList/IconList.d.ts.map +0 -1
  439. package/src/components/sections/IconList/IconListSettings.d.ts.map +0 -1
  440. package/src/components/sections/IconList/index.d.ts.map +0 -1
  441. package/src/components/sections/LinkHeading/index.d.ts.map +0 -1
  442. package/src/components/sections/Prose/Prose.d.ts.map +0 -1
  443. package/src/components/sections/Prose/index.d.ts.map +0 -1
  444. package/src/components/sections/SubHeading/index.d.ts.map +0 -1
  445. package/src/components/sections/SubSubHeading/index.d.ts.map +0 -1
  446. package/src/components/sections/register-schemas.d.ts.map +0 -1
  447. package/src/components/shared/Button.d.ts.map +0 -1
  448. package/src/components/shared/Checkbox.d.ts.map +0 -1
  449. package/src/components/shared/FormLabel.d.ts.map +0 -1
  450. package/src/components/shared/IconButton.d.ts.map +0 -1
  451. package/src/components/shared/Input.d.ts.map +0 -1
  452. package/src/components/shared/Select.d.ts.map +0 -1
  453. package/src/components/shared/icons.d.ts.map +0 -1
  454. package/src/components/shell/BuildStatusIndicator.tsx +0 -59
  455. package/src/components/shell/MediaLibraryContext.d.ts.map +0 -1
  456. package/src/hooks/index.ts +0 -8
  457. package/src/hooks/useResolvedMedia.d.ts.map +0 -1
  458. package/src/lib/cn.d.ts.map +0 -1
  459. package/src/lib/grid.d.ts.map +0 -1
  460. package/src/lib/grid.ts +0 -7
  461. package/src/lib/icons.d.ts.map +0 -1
  462. package/src/lib/loader.d.ts.map +0 -1
  463. package/src/lib/nav.d.ts.map +0 -1
  464. package/src/lib/registry.d.ts.map +0 -1
  465. package/src/lib/sanitize.d.ts.map +0 -1
  466. package/src/media/github.d.ts.map +0 -1
  467. package/src/media/index.d.ts.map +0 -1
  468. package/src/media/queue.d.ts.map +0 -1
  469. package/src/media/resolve.d.ts.map +0 -1
  470. package/src/media/types.d.ts.map +0 -1
  471. package/src/media/utils.d.ts.map +0 -1
  472. package/src/media/videoPoster.d.ts.map +0 -1
  473. package/src/schemas/auth.d.ts.map +0 -1
  474. package/src/schemas/media-grid-options.d.ts.map +0 -1
  475. package/src/schemas/media.d.ts.map +0 -1
  476. package/src/schemas/sections.d.ts.map +0 -1
  477. package/src/schemas/shared.d.ts.map +0 -1
  478. package/src/schemas/site-config.d.ts.map +0 -1
  479. /package/dist/{chunk-B7VBSE5X.js → chunk-3JDTXOIG.js} +0 -0
  480. /package/dist/{chunk-CXZ5YJG4.js → chunk-L45X7DKX.js} +0 -0
  481. /package/src/components/primitives/{gridDrop.ts → grid-drop.ts} +0 -0
  482. /package/src/components/shell/{blockMoveDispatch.ts → block-move-dispatch.ts} +0 -0
  483. /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
+ }