@drawnagency/primitives 0.1.113 → 0.1.115

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 (534) 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-4WQ36ZP7.js +83 -0
  6. package/dist/{chunk-REDDTTGJ.js → chunk-4Y2JQQZL.js} +19 -1
  7. package/dist/chunk-5GFACGSN.js +6 -0
  8. package/dist/{chunk-AHALSCQH.js → chunk-67P34WNW.js} +76 -131
  9. package/dist/{chunk-S2L3BPLS.js → chunk-7SX42OP4.js} +1 -1
  10. package/dist/{chunk-GGXZZ77Z.js → chunk-AASEGXNT.js} +18 -1
  11. package/dist/chunk-APIJPTFG.js +64 -0
  12. package/dist/{chunk-WKZ7OENC.js → chunk-BQ5TZZUE.js} +5 -1
  13. package/dist/chunk-CDBURDPX.js +90 -0
  14. package/dist/chunk-DFKTF3CH.js +0 -0
  15. package/dist/chunk-DIMDRBFK.js +11 -0
  16. package/dist/chunk-DJABADOO.js +131 -0
  17. package/dist/{chunk-NHN2LSIU.js → chunk-DJOGPSRU.js} +31 -68
  18. package/dist/{chunk-KR2MHTNJ.js → chunk-FHTKSELX.js} +610 -62
  19. package/dist/{chunk-WUJ3XNFI.js → chunk-GGYY3JQJ.js} +19 -24
  20. package/dist/chunk-GNF6KFQ7.js +18 -0
  21. package/dist/{chunk-FRE2CCLV.js → chunk-HHNPSKPT.js} +5 -79
  22. package/dist/{chunk-IINIZBQB.js → chunk-JCDZAFX2.js} +30 -10
  23. package/dist/chunk-JR24U7FJ.js +120 -0
  24. package/dist/{chunk-BDFTMGCL.js → chunk-JXATNKLV.js} +11 -10
  25. package/dist/{chunk-SW6PCQQD.js → chunk-KQA772WQ.js} +2 -1
  26. package/dist/{chunk-6BZ2KNTP.js → chunk-NX7TFHA4.js} +195 -65
  27. package/dist/{chunk-VWWY5TL5.js → chunk-O37AV27P.js} +14 -75
  28. package/dist/chunk-RIITGTV3.js +275 -0
  29. package/dist/{chunk-HBULBDGP.js → chunk-S37DZPHW.js} +1 -1
  30. package/dist/chunk-S7QRHUWO.js +8 -0
  31. package/dist/{chunk-Z7W3DQTR.js → chunk-T26HAKW3.js} +424 -42
  32. package/dist/{chunk-4I5OO5UB.js → chunk-TEOAKGZA.js} +0 -1
  33. package/dist/{chunk-GPPVYLEI.js → chunk-UUUSJDIG.js} +1 -1
  34. package/dist/chunk-VY3IFGE3.js +70 -0
  35. package/dist/chunk-WYOFQHKI.js +176 -0
  36. package/dist/{chunk-4RNF2DRG.js → chunk-XDEPXTBY.js} +0 -2
  37. package/dist/{chunk-DS4GCYV2.js → chunk-YV3YSZEB.js} +223 -16
  38. package/dist/collab/rebase.d.ts +2 -1
  39. package/dist/collab/rebase.d.ts.map +1 -1
  40. package/dist/collab/rebase.js +24 -9
  41. package/dist/components/brandguide/ColorsEditable.d.ts.map +1 -1
  42. package/dist/components/chat/ChatPanel.d.ts.map +1 -1
  43. package/dist/components/chat/ChatWidget.d.ts.map +1 -1
  44. package/dist/components/docfile/DocFilePane.d.ts.map +1 -1
  45. package/dist/components/editor/ChildBlockWrapper.d.ts.map +1 -1
  46. package/dist/components/editor/ConflictDialog.d.ts.map +1 -1
  47. package/dist/components/editor/DragHandle.d.ts +12 -2
  48. package/dist/components/editor/DragHandle.d.ts.map +1 -1
  49. package/dist/components/editor/DropEdgeIndicator.d.ts +15 -6
  50. package/dist/components/editor/DropEdgeIndicator.d.ts.map +1 -1
  51. package/dist/components/editor/NavGroupRow.d.ts +4 -1
  52. package/dist/components/editor/NavGroupRow.d.ts.map +1 -1
  53. package/dist/components/editor/PagesModal.d.ts.map +1 -1
  54. package/dist/components/editor/SectionWrapper.d.ts +1 -1
  55. package/dist/components/editor/SectionWrapper.d.ts.map +1 -1
  56. package/dist/components/editor/SettingsForm.d.ts.map +1 -1
  57. package/dist/components/editor/TagIndicator.d.ts +15 -0
  58. package/dist/components/editor/TagIndicator.d.ts.map +1 -0
  59. package/dist/components/editor/index.js +150 -79
  60. package/dist/components/primitives/DocumentDropZone.d.ts +1 -1
  61. package/dist/components/primitives/EditableGrid.d.ts.map +1 -1
  62. package/dist/components/primitives/EditableList.d.ts.map +1 -1
  63. package/dist/components/primitives/HeadingSection.d.ts +4 -1
  64. package/dist/components/primitives/HeadingSection.d.ts.map +1 -1
  65. package/dist/components/primitives/ResolvedMedia.d.ts +5 -1
  66. package/dist/components/primitives/ResolvedMedia.d.ts.map +1 -1
  67. package/dist/components/primitives/{defineHeadingSection.d.ts → define-heading-section.d.ts} +1 -1
  68. package/dist/components/primitives/define-heading-section.d.ts.map +1 -0
  69. package/dist/components/primitives/{gridDrop.d.ts → grid-drop.d.ts} +1 -1
  70. package/dist/components/primitives/grid-drop.d.ts.map +1 -0
  71. package/dist/components/primitives/index.d.ts +1 -1
  72. package/dist/components/primitives/index.d.ts.map +1 -1
  73. package/dist/components/primitives/index.js +22 -154
  74. package/dist/components/sections/Button/CTAButton.d.ts.map +1 -1
  75. package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts +2 -6
  76. package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts.map +1 -1
  77. package/dist/components/sections/DoDontMedia/index.d.ts +8 -0
  78. package/dist/components/sections/DoDontMedia/index.d.ts.map +1 -1
  79. package/dist/components/sections/IconList/IconList.d.ts +2 -1
  80. package/dist/components/sections/IconList/IconList.d.ts.map +1 -1
  81. package/dist/components/sections/IconList/IconListSettings.d.ts +2 -1
  82. package/dist/components/sections/IconList/IconListSettings.d.ts.map +1 -1
  83. package/dist/components/sections/IconList/index.d.ts +1 -0
  84. package/dist/components/sections/IconList/index.d.ts.map +1 -1
  85. package/dist/components/sections/Media/MediaBlock.d.ts +2 -1
  86. package/dist/components/sections/Media/MediaBlock.d.ts.map +1 -1
  87. package/dist/components/sections/Media/index.d.ts +8 -0
  88. package/dist/components/sections/Media/index.d.ts.map +1 -1
  89. package/dist/components/sections/Reference/ReferenceList.d.ts +35 -0
  90. package/dist/components/sections/Reference/ReferenceList.d.ts.map +1 -0
  91. package/dist/components/sections/Reference/ReferenceSettings.d.ts +12 -0
  92. package/dist/components/sections/Reference/ReferenceSettings.d.ts.map +1 -0
  93. package/dist/components/sections/Reference/index.d.ts +9 -0
  94. package/dist/components/sections/Reference/index.d.ts.map +1 -0
  95. package/dist/components/sections/SectionSummary/SectionSummaryBlock.d.ts +38 -0
  96. package/dist/components/sections/SectionSummary/SectionSummaryBlock.d.ts.map +1 -0
  97. package/dist/components/sections/SectionSummary/SectionSummarySettings.d.ts +20 -0
  98. package/dist/components/sections/SectionSummary/SectionSummarySettings.d.ts.map +1 -0
  99. package/dist/components/sections/SectionSummary/index.d.ts +33 -0
  100. package/dist/components/sections/SectionSummary/index.d.ts.map +1 -0
  101. package/dist/components/sections/all-sections.d.ts +53 -0
  102. package/dist/components/sections/all-sections.d.ts.map +1 -1
  103. package/dist/components/sections/brand-guide.d.ts +41 -2
  104. package/dist/components/sections/brand-guide.d.ts.map +1 -1
  105. package/dist/components/sections/brand-guide.js +17 -10
  106. package/dist/components/sections/core-sections.d.ts +14 -0
  107. package/dist/components/sections/core-sections.d.ts.map +1 -1
  108. package/dist/components/sections/register-schemas.js +25 -18
  109. package/dist/components/sections/register.js +25 -18
  110. package/dist/components/shared/BrandSwatchesContext.d.ts +9 -0
  111. package/dist/components/shared/BrandSwatchesContext.d.ts.map +1 -0
  112. package/dist/components/shared/Button.d.ts +11 -3
  113. package/dist/components/shared/Button.d.ts.map +1 -1
  114. package/dist/components/shared/Checkbox.d.ts +6 -0
  115. package/dist/components/shared/Checkbox.d.ts.map +1 -1
  116. package/dist/components/shared/ConfirmDialog.d.ts +25 -0
  117. package/dist/components/shared/ConfirmDialog.d.ts.map +1 -0
  118. package/dist/components/shared/ConfirmInline.d.ts +25 -0
  119. package/dist/components/shared/ConfirmInline.d.ts.map +1 -0
  120. package/dist/components/shared/ErrorBoundary.d.ts.map +1 -1
  121. package/dist/components/shared/Fab.d.ts +11 -2
  122. package/dist/components/shared/Fab.d.ts.map +1 -1
  123. package/dist/components/shared/FabStack.d.ts +22 -0
  124. package/dist/components/shared/FabStack.d.ts.map +1 -0
  125. package/dist/components/shared/HistoryChangesModal.d.ts.map +1 -1
  126. package/dist/components/shared/HistoryPopover.d.ts.map +1 -1
  127. package/dist/components/shared/ImageBackgroundField.d.ts +9 -0
  128. package/dist/components/shared/ImageBackgroundField.d.ts.map +1 -0
  129. package/dist/components/shared/{UploadRejectionAlert.d.ts → InlineAlert.d.ts} +4 -2
  130. package/dist/components/shared/InlineAlert.d.ts.map +1 -0
  131. package/dist/components/shared/Input.d.ts +10 -0
  132. package/dist/components/shared/Input.d.ts.map +1 -1
  133. package/dist/components/shared/Navigation.d.ts.map +1 -1
  134. package/dist/components/shared/Notice.d.ts +10 -0
  135. package/dist/components/shared/Notice.d.ts.map +1 -0
  136. package/dist/components/shared/Popover.d.ts.map +1 -1
  137. package/dist/components/shared/ReferenceSourcesContext.d.ts +25 -0
  138. package/dist/components/shared/ReferenceSourcesContext.d.ts.map +1 -0
  139. package/dist/components/shared/Select.d.ts +3 -2
  140. package/dist/components/shared/Select.d.ts.map +1 -1
  141. package/dist/components/shared/SplitButton.d.ts.map +1 -1
  142. package/dist/components/shared/SummaryAnchorsContext.d.ts +10 -0
  143. package/dist/components/shared/SummaryAnchorsContext.d.ts.map +1 -0
  144. package/dist/components/shared/Textarea.d.ts +7 -0
  145. package/dist/components/shared/Textarea.d.ts.map +1 -1
  146. package/dist/components/shared/ToolbarFrame.d.ts +17 -0
  147. package/dist/components/shared/ToolbarFrame.d.ts.map +1 -0
  148. package/dist/components/shared/copy.d.ts +13 -0
  149. package/dist/components/shared/copy.d.ts.map +1 -0
  150. package/dist/components/shared/icons.d.ts +0 -12
  151. package/dist/components/shared/icons.d.ts.map +1 -1
  152. package/dist/components/shell/AudienceDetailsPanel.d.ts +7 -1
  153. package/dist/components/shell/AudienceDetailsPanel.d.ts.map +1 -1
  154. package/dist/components/shell/AudienceRow.d.ts.map +1 -1
  155. package/dist/components/shell/BugReportFAB.d.ts +7 -1
  156. package/dist/components/shell/BugReportFAB.d.ts.map +1 -1
  157. package/dist/components/shell/CredentialList.d.ts.map +1 -1
  158. package/dist/components/shell/DocInspector.d.ts.map +1 -1
  159. package/dist/components/shell/DocumentEditorOverlay.d.ts.map +1 -1
  160. package/dist/components/shell/EditorContext.d.ts +4 -0
  161. package/dist/components/shell/EditorContext.d.ts.map +1 -1
  162. package/dist/components/shell/EditorLoginForm.d.ts.map +1 -1
  163. package/dist/components/shell/EditorModal.d.ts.map +1 -1
  164. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  165. package/dist/components/shell/HistoryToolbar.d.ts.map +1 -1
  166. package/dist/components/shell/MediaFolderTile.d.ts +4 -1
  167. package/dist/components/shell/MediaFolderTile.d.ts.map +1 -1
  168. package/dist/components/shell/MediaLibraryModal.d.ts.map +1 -1
  169. package/dist/components/shell/RestoreModal.d.ts.map +1 -1
  170. package/dist/components/shell/SiteSettingsChatbot.d.ts.map +1 -1
  171. package/dist/components/shell/SiteSettingsDisplay.d.ts.map +1 -1
  172. package/dist/components/shell/SiteSettingsModal.d.ts +3 -1
  173. package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
  174. package/dist/components/shell/SiteSettingsTags.d.ts +13 -0
  175. package/dist/components/shell/SiteSettingsTags.d.ts.map +1 -0
  176. package/dist/components/shell/SiteSettingsUsers.d.ts.map +1 -1
  177. package/dist/components/shell/ViewerLoginForm.d.ts.map +1 -1
  178. package/dist/components/shell/{blockMoveDispatch.d.ts → block-move-dispatch.d.ts} +1 -1
  179. package/dist/components/shell/block-move-dispatch.d.ts.map +1 -0
  180. package/dist/components/shell/reference-sources.d.ts +22 -0
  181. package/dist/components/shell/reference-sources.d.ts.map +1 -0
  182. package/dist/deck/index.d.ts +2 -2
  183. package/dist/deck/index.d.ts.map +1 -1
  184. package/dist/deck/index.js +1 -3
  185. package/dist/deck-builder/index.js +10 -17
  186. package/dist/document/index.d.ts +2 -2
  187. package/dist/document/index.d.ts.map +1 -1
  188. package/dist/hooks/useBlockDnd.d.ts +11 -0
  189. package/dist/hooks/useBlockDnd.d.ts.map +1 -1
  190. package/dist/hooks/useBuildStatus.d.ts +1 -1
  191. package/dist/hooks/useBuildStatus.d.ts.map +1 -1
  192. package/dist/hooks/useDocumentUploads.d.ts +1 -1
  193. package/dist/hooks/useDocumentUploads.d.ts.map +1 -1
  194. package/dist/hooks/useEditorPersistence.d.ts +5 -1
  195. package/dist/hooks/useEditorPersistence.d.ts.map +1 -1
  196. package/dist/hooks/useEditorPublish.d.ts +6 -3
  197. package/dist/hooks/useEditorPublish.d.ts.map +1 -1
  198. package/dist/hooks/useMediaPipeline.d.ts.map +1 -1
  199. package/dist/hooks/useNotice.d.ts +19 -0
  200. package/dist/hooks/useNotice.d.ts.map +1 -0
  201. package/dist/hooks/useSortableNavRow.d.ts +11 -0
  202. package/dist/hooks/useSortableNavRow.d.ts.map +1 -1
  203. package/dist/hooks/useSortableRow.d.ts +11 -0
  204. package/dist/hooks/useSortableRow.d.ts.map +1 -1
  205. package/dist/hooks/useStackedEscape.d.ts +32 -0
  206. package/dist/hooks/useStackedEscape.d.ts.map +1 -0
  207. package/dist/index.js +95 -48
  208. package/dist/lib/audience-secret.js +2 -2
  209. package/dist/lib/block-dnd.d.ts +5 -0
  210. package/dist/lib/block-dnd.d.ts.map +1 -1
  211. package/dist/lib/block-move.d.ts.map +1 -1
  212. package/dist/lib/brand-swatches.d.ts +12 -0
  213. package/dist/lib/brand-swatches.d.ts.map +1 -0
  214. package/dist/lib/container-ops.d.ts +3 -2
  215. package/dist/lib/container-ops.d.ts.map +1 -1
  216. package/dist/lib/dexie.d.ts +7 -1
  217. package/dist/lib/dexie.d.ts.map +1 -1
  218. package/dist/lib/dexie.js +12 -3
  219. package/dist/lib/env.d.ts +4 -0
  220. package/dist/lib/env.d.ts.map +1 -1
  221. package/dist/lib/env.js +5 -3
  222. package/dist/lib/events.d.ts +1 -2
  223. package/dist/lib/events.d.ts.map +1 -1
  224. package/dist/lib/image-background.d.ts +8 -0
  225. package/dist/lib/image-background.d.ts.map +1 -0
  226. package/dist/lib/image-variant-plan.d.ts +42 -0
  227. package/dist/lib/image-variant-plan.d.ts.map +1 -0
  228. package/dist/lib/image-variant-plan.js +53 -0
  229. package/dist/lib/index-ops.d.ts.map +1 -1
  230. package/dist/lib/index-ops.js +21 -17
  231. package/dist/lib/index.d.ts +7 -4
  232. package/dist/lib/index.d.ts.map +1 -1
  233. package/dist/lib/index.js +55 -26
  234. package/dist/lib/loader.d.ts +25 -12
  235. package/dist/lib/loader.d.ts.map +1 -1
  236. package/dist/lib/media-ops.d.ts +73 -0
  237. package/dist/lib/media-ops.d.ts.map +1 -0
  238. package/dist/lib/media-ops.js +60 -0
  239. package/dist/lib/nav-tree.d.ts +7 -0
  240. package/dist/lib/nav-tree.d.ts.map +1 -1
  241. package/dist/lib/nav.d.ts +38 -0
  242. package/dist/lib/nav.d.ts.map +1 -1
  243. package/dist/lib/pages.d.ts +2 -1
  244. package/dist/lib/pages.d.ts.map +1 -1
  245. package/dist/lib/platform-broker.d.ts +4 -2
  246. package/dist/lib/platform-broker.d.ts.map +1 -1
  247. package/dist/lib/platform-broker.js +21 -13
  248. package/dist/lib/reference-type.d.ts +2 -0
  249. package/dist/lib/reference-type.d.ts.map +1 -0
  250. package/dist/lib/reference-validation.d.ts +31 -0
  251. package/dist/lib/reference-validation.d.ts.map +1 -0
  252. package/dist/lib/reference-validation.js +39 -0
  253. package/dist/lib/references.d.ts +74 -0
  254. package/dist/lib/references.d.ts.map +1 -0
  255. package/dist/lib/registry.d.ts +35 -0
  256. package/dist/lib/registry.d.ts.map +1 -1
  257. package/dist/lib/{safeRedirect.d.ts → safe-redirect.d.ts} +1 -1
  258. package/dist/lib/safe-redirect.d.ts.map +1 -0
  259. package/dist/lib/sidecar-diagnostics.d.ts +20 -0
  260. package/dist/lib/sidecar-diagnostics.d.ts.map +1 -0
  261. package/dist/lib/sidecars.d.ts +118 -0
  262. package/dist/lib/sidecars.d.ts.map +1 -0
  263. package/dist/lib/sidecars.js +23 -0
  264. package/dist/lib/slug.d.ts +2 -0
  265. package/dist/lib/slug.d.ts.map +1 -0
  266. package/dist/lib/storage-tier.d.ts +17 -0
  267. package/dist/lib/storage-tier.d.ts.map +1 -0
  268. package/dist/lib/storage-tier.js +29 -0
  269. package/dist/lib/tags.d.ts +64 -0
  270. package/dist/lib/tags.d.ts.map +1 -0
  271. package/dist/lib/theme-vars.d.ts +9 -0
  272. package/dist/lib/theme-vars.d.ts.map +1 -1
  273. package/dist/media/index.d.ts +1 -1
  274. package/dist/media/index.d.ts.map +1 -1
  275. package/dist/media/index.js +18 -14
  276. package/dist/media/queue.d.ts +2 -0
  277. package/dist/media/queue.d.ts.map +1 -1
  278. package/dist/media/utils.d.ts +2 -0
  279. package/dist/media/utils.d.ts.map +1 -1
  280. package/dist/media/{videoPoster.d.ts → video-poster.d.ts} +1 -1
  281. package/dist/media/video-poster.d.ts.map +1 -0
  282. package/dist/media/worker.d.ts +1 -35
  283. package/dist/media/worker.d.ts.map +1 -1
  284. package/dist/schemas/audience.js +2 -2
  285. package/dist/schemas/index.d.ts +1 -0
  286. package/dist/schemas/index.d.ts.map +1 -1
  287. package/dist/schemas/index.js +25 -13
  288. package/dist/schemas/media.d.ts +4 -0
  289. package/dist/schemas/media.d.ts.map +1 -1
  290. package/dist/schemas/shared.d.ts +26 -0
  291. package/dist/schemas/shared.d.ts.map +1 -1
  292. package/dist/schemas/site-config.d.ts +6 -0
  293. package/dist/schemas/site-config.d.ts.map +1 -1
  294. package/dist/schemas/tags.d.ts +27 -0
  295. package/dist/schemas/tags.d.ts.map +1 -0
  296. package/dist/storage/index.js +2 -1
  297. package/dist/storage/memory.d.ts +21 -0
  298. package/dist/storage/memory.d.ts.map +1 -0
  299. package/dist/storage/memory.js +129 -0
  300. package/dist/storage/types.d.ts +9 -0
  301. package/dist/storage/types.d.ts.map +1 -1
  302. package/dist/types/database.d.ts.map +1 -1
  303. package/package.json +26 -1
  304. package/src/auth/cookies.ts +111 -0
  305. package/src/collab/rebase.ts +29 -9
  306. package/src/components/brandguide/ColorSwatchSettings.tsx +1 -1
  307. package/src/components/brandguide/ColorsEditable.tsx +1 -0
  308. package/src/components/chat/ChatPanel.tsx +2 -3
  309. package/src/components/chat/ChatWidget.tsx +2 -3
  310. package/src/components/docfile/DocFilePane.tsx +4 -12
  311. package/src/components/editor/ChildBlockWrapper.tsx +13 -19
  312. package/src/components/editor/ConflictDialog.tsx +27 -35
  313. package/src/components/editor/DeleteButton.tsx +2 -2
  314. package/src/components/editor/DragHandle.tsx +16 -3
  315. package/src/components/editor/DropEdgeIndicator.tsx +36 -10
  316. package/src/components/editor/InsertButton.tsx +2 -2
  317. package/src/components/editor/NavGroupRow.tsx +43 -14
  318. package/src/components/editor/PagesModal.tsx +99 -26
  319. package/src/components/editor/SectionWrapper.tsx +64 -23
  320. package/src/components/editor/SettingsButton.tsx +2 -2
  321. package/src/components/editor/SettingsForm.tsx +19 -2
  322. package/src/components/editor/StatusIndicator.tsx +4 -4
  323. package/src/components/editor/TagIndicator.tsx +80 -0
  324. package/src/components/primitives/DocumentDropZone.tsx +1 -1
  325. package/src/components/primitives/EditableGrid.tsx +15 -14
  326. package/src/components/primitives/EditableList.tsx +27 -74
  327. package/src/components/primitives/HeadingSection.tsx +5 -2
  328. package/src/components/primitives/ResolvedMedia.tsx +13 -0
  329. package/src/components/primitives/{defineHeadingSection.tsx → define-heading-section.tsx} +1 -0
  330. package/src/components/primitives/index.ts +1 -1
  331. package/src/components/primitives/useEditablePlainText.ts +5 -5
  332. package/src/components/sections/Button/CTAButton.tsx +3 -1
  333. package/src/components/sections/DoDontMedia/DoDontMediaBlock.tsx +4 -4
  334. package/src/components/sections/DoDontMedia/index.tsx +12 -3
  335. package/src/components/sections/IconList/DoDontToggle.tsx +2 -2
  336. package/src/components/sections/IconList/IconList.tsx +70 -37
  337. package/src/components/sections/IconList/IconListSettings.tsx +55 -17
  338. package/src/components/sections/IconList/index.tsx +10 -3
  339. package/src/components/sections/LinkHeading/index.tsx +1 -1
  340. package/src/components/sections/Media/MediaBlock.tsx +13 -2
  341. package/src/components/sections/Media/index.tsx +12 -4
  342. package/src/components/sections/Reference/ReferenceList.tsx +214 -0
  343. package/src/components/sections/Reference/ReferenceSettings.tsx +159 -0
  344. package/src/components/sections/Reference/index.tsx +47 -0
  345. package/src/components/sections/SectionSummary/SectionSummaryBlock.tsx +476 -0
  346. package/src/components/sections/SectionSummary/SectionSummarySettings.tsx +126 -0
  347. package/src/components/sections/SectionSummary/index.tsx +149 -0
  348. package/src/components/sections/SubHeading/index.tsx +1 -1
  349. package/src/components/sections/SubSubHeading/index.tsx +1 -1
  350. package/src/components/sections/brand-guide.ts +4 -3
  351. package/src/components/sections/core-sections.ts +2 -0
  352. package/src/components/shared/BrandSwatchesContext.ts +13 -0
  353. package/src/components/shared/Button.tsx +47 -34
  354. package/src/components/shared/Checkbox.tsx +21 -12
  355. package/src/components/shared/ConfirmDialog.tsx +87 -0
  356. package/src/components/shared/ConfirmInline.tsx +90 -0
  357. package/src/components/shared/ErrorBoundary.tsx +6 -18
  358. package/src/components/shared/Fab.tsx +15 -5
  359. package/src/components/shared/FabStack.tsx +28 -0
  360. package/src/components/shared/HistoryChangesModal.tsx +43 -41
  361. package/src/components/shared/HistoryPopover.tsx +7 -20
  362. package/src/components/shared/ImageBackgroundField.tsx +92 -0
  363. package/src/components/shared/{UploadRejectionAlert.tsx → InlineAlert.tsx} +21 -5
  364. package/src/components/shared/Input.tsx +23 -7
  365. package/src/components/shared/Navigation.tsx +22 -17
  366. package/src/components/shared/Notice.tsx +59 -0
  367. package/src/components/shared/Popover.tsx +7 -11
  368. package/src/components/shared/ReferenceSourcesContext.ts +27 -0
  369. package/src/components/shared/Select.tsx +5 -2
  370. package/src/components/shared/SplitButton.tsx +11 -17
  371. package/src/components/shared/SummaryAnchorsContext.ts +11 -0
  372. package/src/components/shared/Textarea.tsx +17 -2
  373. package/src/components/shared/ToolbarFrame.tsx +28 -0
  374. package/src/components/shared/VideoSourceField.tsx +1 -1
  375. package/src/components/shared/copy.ts +18 -0
  376. package/src/components/shared/icons.tsx +1 -17
  377. package/src/components/shell/AudienceAddForm.tsx +2 -2
  378. package/src/components/shell/AudienceDetailsPanel.tsx +23 -5
  379. package/src/components/shell/AudienceRow.tsx +22 -15
  380. package/src/components/shell/BugReportFAB.tsx +50 -40
  381. package/src/components/shell/CredentialList.tsx +33 -13
  382. package/src/components/shell/DocInspector.tsx +3 -12
  383. package/src/components/shell/DocumentEditorOverlay.tsx +33 -23
  384. package/src/components/shell/EditorContext.tsx +7 -0
  385. package/src/components/shell/EditorLoginForm.tsx +26 -36
  386. package/src/components/shell/EditorModal.tsx +8 -10
  387. package/src/components/shell/EditorShell.tsx +501 -338
  388. package/src/components/shell/HistoryToolbar.tsx +24 -26
  389. package/src/components/shell/MediaFolderTile.tsx +8 -3
  390. package/src/components/shell/MediaLibraryModal.tsx +59 -60
  391. package/src/components/shell/ProcessingIndicator.tsx +2 -2
  392. package/src/components/shell/RestoreModal.tsx +17 -16
  393. package/src/components/shell/SetPasswordForm.tsx +3 -3
  394. package/src/components/shell/SiteSettingsChatbot.tsx +61 -42
  395. package/src/components/shell/SiteSettingsDisplay.tsx +10 -20
  396. package/src/components/shell/SiteSettingsModal.tsx +24 -2
  397. package/src/components/shell/SiteSettingsTags.tsx +143 -0
  398. package/src/components/shell/SiteSettingsUsers.tsx +36 -26
  399. package/src/components/shell/SiteSettingsViewerAccess.tsx +2 -2
  400. package/src/components/shell/ViewerLoginForm.tsx +5 -4
  401. package/src/components/shell/reference-sources.ts +36 -0
  402. package/src/deck/index.ts +2 -2
  403. package/src/document/index.ts +2 -2
  404. package/src/hooks/useBlockDnd.ts +11 -0
  405. package/src/hooks/useBuildStatus.ts +53 -6
  406. package/src/hooks/useDocumentUploads.ts +1 -1
  407. package/src/hooks/useEditorPersistence.ts +141 -35
  408. package/src/hooks/useEditorPublish.ts +27 -31
  409. package/src/hooks/useMediaPipeline.ts +30 -24
  410. package/src/hooks/useNotice.ts +45 -0
  411. package/src/hooks/useSortableNavRow.ts +11 -0
  412. package/src/hooks/useSortableRow.ts +22 -2
  413. package/src/hooks/useStackedEscape.ts +62 -0
  414. package/src/lib/block-dnd.ts +6 -1
  415. package/src/lib/block-move.ts +3 -0
  416. package/src/lib/brand-swatches.ts +32 -0
  417. package/src/lib/container-ops.ts +5 -3
  418. package/src/lib/dexie.ts +24 -2
  419. package/src/lib/env.ts +9 -0
  420. package/src/lib/events.ts +1 -2
  421. package/src/lib/image-background.ts +31 -0
  422. package/src/lib/image-variant-plan.ts +92 -0
  423. package/src/lib/index-ops.ts +9 -18
  424. package/src/lib/index.ts +20 -4
  425. package/src/lib/loader.ts +28 -88
  426. package/src/lib/media-ops.ts +112 -0
  427. package/src/lib/nav-tree.ts +104 -4
  428. package/src/lib/nav.ts +196 -36
  429. package/src/lib/pages.ts +2 -3
  430. package/src/lib/platform-broker.ts +32 -14
  431. package/src/lib/reference-type.ts +3 -0
  432. package/src/lib/reference-validation.ts +69 -0
  433. package/src/lib/references.ts +130 -0
  434. package/src/lib/registry.ts +37 -0
  435. package/src/lib/sidecar-diagnostics.ts +29 -0
  436. package/src/lib/sidecars.ts +221 -0
  437. package/src/lib/slug.ts +6 -0
  438. package/src/lib/storage-tier.ts +38 -0
  439. package/src/lib/tags.ts +165 -0
  440. package/src/lib/theme-vars.ts +23 -0
  441. package/src/media/index.ts +1 -1
  442. package/src/media/queue.ts +3 -0
  443. package/src/media/utils.ts +19 -1
  444. package/src/media/{videoPoster.ts → video-poster.ts} +2 -2
  445. package/src/media/worker.ts +17 -8
  446. package/src/schemas/index.ts +1 -0
  447. package/src/schemas/media.ts +7 -2
  448. package/src/schemas/shared.ts +24 -1
  449. package/src/schemas/site-config.ts +6 -1
  450. package/src/schemas/tags.ts +33 -0
  451. package/src/storage/memory.ts +178 -0
  452. package/src/storage/types.ts +16 -3
  453. package/src/types/database.ts +2 -0
  454. package/dist/chunk-DNY72JZN.js +0 -86
  455. package/dist/chunk-F2LYQPXV.js +0 -77
  456. package/dist/chunk-JH762VUH.js +0 -128
  457. package/dist/chunk-K7DYZXVU.js +0 -138
  458. package/dist/components/primitives/defineHeadingSection.d.ts.map +0 -1
  459. package/dist/components/primitives/gridDrop.d.ts.map +0 -1
  460. package/dist/components/shared/UploadRejectionAlert.d.ts.map +0 -1
  461. package/dist/components/shell/BuildStatusIndicator.d.ts +0 -7
  462. package/dist/components/shell/BuildStatusIndicator.d.ts.map +0 -1
  463. package/dist/components/shell/blockMoveDispatch.d.ts.map +0 -1
  464. package/dist/hooks/index.d.ts +0 -9
  465. package/dist/hooks/index.d.ts.map +0 -1
  466. package/dist/lib/grid.d.ts +0 -2
  467. package/dist/lib/grid.d.ts.map +0 -1
  468. package/dist/lib/safeRedirect.d.ts.map +0 -1
  469. package/dist/media/videoPoster.d.ts.map +0 -1
  470. package/src/components/brandguide/ColorSwatchSettings.d.ts.map +0 -1
  471. package/src/components/brandguide/Colors.d.ts.map +0 -1
  472. package/src/components/primitives/CustomParagraph.d.ts.map +0 -1
  473. package/src/components/primitives/EditableGrid.d.ts.map +0 -1
  474. package/src/components/primitives/EditablePlainText.d.ts.map +0 -1
  475. package/src/components/primitives/EditableRichText.d.ts.map +0 -1
  476. package/src/components/primitives/HeadingSection.d.ts.map +0 -1
  477. package/src/components/primitives/IconPicker.d.ts.map +0 -1
  478. package/src/components/primitives/LinkPopover.d.ts.map +0 -1
  479. package/src/components/primitives/MediaSettingsForms.d.ts.map +0 -1
  480. package/src/components/primitives/ResolvedMedia.d.ts.map +0 -1
  481. package/src/components/primitives/RichTextToolbar.d.ts.map +0 -1
  482. package/src/components/primitives/tiptap-presets.d.ts.map +0 -1
  483. package/src/components/primitives/useEditableCollection.d.ts.map +0 -1
  484. package/src/components/primitives/useEditablePlainText.d.ts.map +0 -1
  485. package/src/components/primitives/useEditableRichText.d.ts.map +0 -1
  486. package/src/components/sections/Button/CTAButton.d.ts.map +0 -1
  487. package/src/components/sections/Button/index.d.ts.map +0 -1
  488. package/src/components/sections/Colors/index.d.ts.map +0 -1
  489. package/src/components/sections/IconList/IconList.d.ts.map +0 -1
  490. package/src/components/sections/IconList/IconListSettings.d.ts.map +0 -1
  491. package/src/components/sections/IconList/index.d.ts.map +0 -1
  492. package/src/components/sections/LinkHeading/index.d.ts.map +0 -1
  493. package/src/components/sections/Prose/Prose.d.ts.map +0 -1
  494. package/src/components/sections/Prose/index.d.ts.map +0 -1
  495. package/src/components/sections/SubHeading/index.d.ts.map +0 -1
  496. package/src/components/sections/SubSubHeading/index.d.ts.map +0 -1
  497. package/src/components/sections/register-schemas.d.ts.map +0 -1
  498. package/src/components/shared/Button.d.ts.map +0 -1
  499. package/src/components/shared/Checkbox.d.ts.map +0 -1
  500. package/src/components/shared/FormLabel.d.ts.map +0 -1
  501. package/src/components/shared/IconButton.d.ts.map +0 -1
  502. package/src/components/shared/Input.d.ts.map +0 -1
  503. package/src/components/shared/Select.d.ts.map +0 -1
  504. package/src/components/shared/icons.d.ts.map +0 -1
  505. package/src/components/shell/BuildStatusIndicator.tsx +0 -59
  506. package/src/components/shell/MediaLibraryContext.d.ts.map +0 -1
  507. package/src/hooks/index.ts +0 -8
  508. package/src/hooks/useResolvedMedia.d.ts.map +0 -1
  509. package/src/lib/cn.d.ts.map +0 -1
  510. package/src/lib/grid.d.ts.map +0 -1
  511. package/src/lib/grid.ts +0 -7
  512. package/src/lib/icons.d.ts.map +0 -1
  513. package/src/lib/loader.d.ts.map +0 -1
  514. package/src/lib/nav.d.ts.map +0 -1
  515. package/src/lib/registry.d.ts.map +0 -1
  516. package/src/lib/sanitize.d.ts.map +0 -1
  517. package/src/media/github.d.ts.map +0 -1
  518. package/src/media/index.d.ts.map +0 -1
  519. package/src/media/queue.d.ts.map +0 -1
  520. package/src/media/resolve.d.ts.map +0 -1
  521. package/src/media/types.d.ts.map +0 -1
  522. package/src/media/utils.d.ts.map +0 -1
  523. package/src/media/videoPoster.d.ts.map +0 -1
  524. package/src/schemas/auth.d.ts.map +0 -1
  525. package/src/schemas/media-grid-options.d.ts.map +0 -1
  526. package/src/schemas/media.d.ts.map +0 -1
  527. package/src/schemas/sections.d.ts.map +0 -1
  528. package/src/schemas/shared.d.ts.map +0 -1
  529. package/src/schemas/site-config.d.ts.map +0 -1
  530. /package/dist/{chunk-B7VBSE5X.js → chunk-3JDTXOIG.js} +0 -0
  531. /package/dist/{chunk-CXZ5YJG4.js → chunk-L45X7DKX.js} +0 -0
  532. /package/src/components/primitives/{gridDrop.ts → grid-drop.ts} +0 -0
  533. /package/src/components/shell/{blockMoveDispatch.ts → block-move-dispatch.ts} +0 -0
  534. /package/src/lib/{safeRedirect.ts → safe-redirect.ts} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { useState } from "react";
2
- import { Check, X } from "lucide-react";
2
+ import { Check, Hash, Shapes, X } from "lucide-react";
3
3
  import { Checkbox } from "../../shared/Checkbox";
4
4
  import { FormLabel } from "../../shared/FormLabel";
5
5
  import { IconPicker } from "../../primitives/IconPicker";
@@ -11,79 +11,117 @@ export function IconListSettings({
11
11
  showLabel: initialShowLabel,
12
12
  stackText: initialStackText,
13
13
  dodont: initialDodont,
14
+ marker: initialMarker,
14
15
  onChange,
15
16
  }: {
16
17
  icon: string | null;
17
18
  showLabel: boolean;
18
19
  stackText: boolean;
19
20
  dodont?: "do" | "dont";
21
+ marker?: "icon" | "number";
20
22
  onChange: (result: { content: Record<string, unknown>; options: Record<string, unknown> }) => void;
21
23
  }) {
22
24
  const [icon, setIcon] = useState(initialIcon);
23
25
  const [showLabel, setShowLabel] = useState(initialShowLabel);
24
26
  const [stackText, setStackText] = useState(initialStackText);
25
27
  const [dodont, setDodont] = useState<"do" | "dont" | undefined>(initialDodont);
28
+ // The Icon marker choice is stored as an absent key, matching every list saved
29
+ // before the option existed (an explicit "icon" normalises to absent on save).
30
+ const [marker, setMarker] = useState<"number" | undefined>(initialMarker === "number" ? "number" : undefined);
26
31
  const [pickerOpen, setPickerOpen] = useState(false);
27
32
 
28
33
  const emit = (
29
- overrides: Partial<{ icon: string | null; showLabel: boolean; stackText: boolean; dodont: "do" | "dont" | undefined }>,
30
- ) => onChange({ content: {}, options: { icon, showLabel, stackText, dodont, ...overrides } });
34
+ overrides: Partial<{
35
+ icon: string | null;
36
+ showLabel: boolean;
37
+ stackText: boolean;
38
+ dodont: "do" | "dont" | undefined;
39
+ marker: "number" | undefined;
40
+ }>,
41
+ ) => onChange({ content: {}, options: { icon, showLabel, stackText, dodont, marker, ...overrides } });
31
42
 
32
43
  const iconEntry = icon ? getIcon(icon) : null;
33
44
  const dodontActive = dodont === "do" || dodont === "dont";
45
+ const numbered = marker === "number" && !dodontActive;
46
+ const iconDisabled = dodontActive || numbered;
34
47
 
35
- const tile = (value: "do" | "dont" | undefined, label: string, aria: string, glyph: React.ReactNode, tint: string) => (
48
+ // Numbering is for standard icon lists only, so turning on Do/Don't drops it.
49
+ const pickDodont = (value: "do" | "dont" | undefined) => {
50
+ setDodont(value);
51
+ if (value) {
52
+ setMarker(undefined);
53
+ emit({ dodont: value, marker: undefined });
54
+ } else {
55
+ emit({ dodont: value });
56
+ }
57
+ };
58
+
59
+ const tile = (pressed: boolean, onPick: () => void, label: string, aria: string, glyph: React.ReactNode, tint: string) => (
36
60
  <button
37
61
  type="button"
38
62
  aria-label={aria}
39
- aria-pressed={dodont === value}
63
+ aria-pressed={pressed}
40
64
  className={cn(
41
65
  "cursor-pointer flex flex-col items-center gap-1 rounded border py-2 transition-colors",
42
66
  tint,
43
- dodont === value ? "border-primary bg-base-accent" : "border-base-200",
67
+ pressed ? "border-primary bg-base-accent" : "border-base-200",
44
68
  )}
45
- onClick={() => { setDodont(value); emit({ dodont: value }); }}
69
+ onClick={onPick}
46
70
  >
47
71
  {glyph}
48
72
  <span className="text-xs font-medium">{label}</span>
49
73
  </button>
50
74
  );
75
+ const dodontTile = (value: "do" | "dont" | undefined, label: string, aria: string, glyph: React.ReactNode, tint: string) =>
76
+ tile(dodont === value, () => pickDodont(value), label, aria, glyph, tint);
77
+ const markerTile = (value: "number" | undefined, label: string, aria: string, glyph: React.ReactNode) =>
78
+ tile(marker === value, () => { setMarker(value); emit({ marker: value }); }, label, aria, glyph, "text-base-contrast-light");
51
79
 
52
80
  return (
53
81
  <div className="space-y-4">
54
82
  <div>
55
83
  <FormLabel>Do / Don't list</FormLabel>
56
84
  <div className="grid grid-cols-3 gap-2">
57
- {tile(
85
+ {dodontTile(
58
86
  undefined,
59
87
  "None",
60
88
  "No do/don't",
61
89
  <span className="flex h-5 w-5 items-center justify-center rounded-sm border border-dashed border-base-contrast-light/40" />,
62
90
  "text-base-contrast-light",
63
91
  )}
64
- {tile("do", "Do", "Do list", <Check size={20} />, "text-green-600")}
65
- {tile("dont", "Don't", "Don't list", <X size={20} />, "text-red-600")}
92
+ {dodontTile("do", "Do", "Do list", <Check size={20} />, "text-success")}
93
+ {dodontTile("dont", "Don't", "Don't list", <X size={20} />, "text-danger")}
66
94
  </div>
67
95
  </div>
68
96
 
97
+ {!dodontActive && (
98
+ <div>
99
+ <FormLabel>Marker</FormLabel>
100
+ <div className="grid grid-cols-2 gap-2">
101
+ {markerTile(undefined, "Icon", "Icon markers", <Shapes size={20} />)}
102
+ {markerTile("number", "Number", "Number markers", <Hash size={20} />)}
103
+ </div>
104
+ </div>
105
+ )}
106
+
69
107
  <div className="relative">
70
108
  <FormLabel htmlFor="icon-picker-btn">Default Icon</FormLabel>
71
109
  <div className="flex items-center gap-2">
72
110
  <button
73
111
  id="icon-picker-btn"
74
- disabled={dodontActive}
112
+ disabled={iconDisabled}
75
113
  className={cn(
76
114
  "flex items-center gap-2 rounded border border-base-200 px-3 py-1.5 text-sm text-base-contrast-light",
77
- dodontActive
115
+ iconDisabled
78
116
  ? "cursor-not-allowed opacity-50"
79
117
  : "cursor-pointer hover:border-primary hover:text-primary",
80
118
  )}
81
- onClick={() => { if (!dodontActive) setPickerOpen((prev) => !prev); }}
119
+ onClick={() => { if (!iconDisabled) setPickerOpen((prev) => !prev); }}
82
120
  >
83
121
  {iconEntry && <iconEntry.icon size={16} />}
84
122
  <span>{iconEntry?.label ?? "None"}</span>
85
123
  </button>
86
- {icon && !dodontActive && (
124
+ {icon && !iconDisabled && (
87
125
  <button
88
126
  className="cursor-pointer text-xs text-base-contrast-light hover:text-base-contrast"
89
127
  onClick={() => { setIcon(null); emit({ icon: null }); }}
@@ -92,12 +130,12 @@ export function IconListSettings({
92
130
  </button>
93
131
  )}
94
132
  </div>
95
- {dodontActive && (
133
+ {iconDisabled && (
96
134
  <p className="mt-1 text-xs text-base-contrast-light/70">
97
- Whole-list Do/Don't overrides the default icon.
135
+ {numbered ? "Numbered lists don't show icons." : "Whole-list Do/Don't overrides the default icon."}
98
136
  </p>
99
137
  )}
100
- {pickerOpen && !dodontActive && (
138
+ {pickerOpen && !iconDisabled && (
101
139
  <div className="absolute top-full left-0 z-50 mt-1">
102
140
  <IconPicker
103
141
  selected={icon}
@@ -40,6 +40,12 @@ const schema = z.object({
40
40
  .enum(["do", "dont"])
41
41
  .describe("Whole-list do/don't mode: render every item with a green check (do) or red x (don't).")
42
42
  .optional(),
43
+ marker: z
44
+ .enum(["icon", "number"])
45
+ .describe(
46
+ "What marks each item: \"icon\" (default when absent) or \"number\" — bold numerals 1, 2, 3… in place of icons, ignoring item and default icons. Standard lists only: ignored when options.dodont is set.",
47
+ )
48
+ .optional(),
43
49
  })
44
50
  .optional(),
45
51
  });
@@ -72,7 +78,7 @@ export default defineSection({
72
78
  icon: <List size={18} />,
73
79
  schema,
74
80
  authoringNote:
75
- "A list of labeled items, optionally with per-item icons and do/don't markers. Use for feature lists, guidelines, or do/don't guidance.",
81
+ "A list of labeled items, optionally with per-item icons and do/don't markers, or numbered instead (options.marker: \"number\"). Use for feature lists, guidelines, steps, or do/don't guidance.",
76
82
  component: ({ content, options, onChange }) => (
77
83
  <IconList
78
84
  items={content.content.items}
@@ -80,11 +86,12 @@ export default defineSection({
80
86
  showLabel={options?.showLabel as boolean}
81
87
  stackText={options?.stackText as boolean}
82
88
  dodont={options?.dodont as "do" | "dont" | undefined}
83
- // IconList rebuilds its options from the four props above, which inside a
89
+ marker={options?.marker as "icon" | "number" | undefined}
90
+ // IconList rebuilds its options from the five props above, which inside a
84
91
  // container are childDefaults merged with the child's own options — writing
85
92
  // that back would materialise the container's defaults onto the child (it
86
93
  // then stops following later default changes) and drop any option key
87
- // outside those four. Only items change here, so keep the stored options.
94
+ // outside those five. Only items change here, so keep the stored options.
88
95
  onChange={
89
96
  onChange ? (c) => onChange({ ...(c as typeof content), options: content.options }) : undefined
90
97
  }
@@ -1,5 +1,5 @@
1
1
  import { Heading1 } from "lucide-react";
2
- import { defineHeadingSection } from "../../primitives/defineHeadingSection";
2
+ import { defineHeadingSection } from "../../primitives/define-heading-section";
3
3
 
4
4
  export default defineHeadingSection({
5
5
  type: "link_heading",
@@ -1,4 +1,4 @@
1
- import type { SingleMediaReference } from "../../../schemas/shared";
1
+ import type { ImageBackground, SingleMediaReference } from "../../../schemas/shared";
2
2
  import type { LinkValue } from "../../../schemas/link";
3
3
  import { cn } from "../../../lib/cn";
4
4
  import { ResolvedMedia } from "../../primitives/ResolvedMedia";
@@ -6,10 +6,17 @@ import { ImageDropZone } from "../../primitives/ImageDropZone";
6
6
  import { EditablePlainText } from "../../primitives/EditablePlainText";
7
7
  import { useMediaLibrary } from "../../shell/MediaLibraryContext";
8
8
  import { rebindImageRef } from "../../../media/resolve";
9
+ import { imageBackdrop } from "../../../lib/image-background";
9
10
 
10
11
  export interface MediaBlockProps {
11
12
  refValue: SingleMediaReference;
12
- options: { square?: boolean; showCaption?: boolean; border?: boolean; objectFit?: "cover" | "contain" };
13
+ options: {
14
+ square?: boolean;
15
+ showCaption?: boolean;
16
+ border?: boolean;
17
+ objectFit?: "cover" | "contain";
18
+ background?: ImageBackground;
19
+ };
13
20
  /** Per-item link (viewer: already resolved to kind:"external" upstream). */
14
21
  link?: LinkValue;
15
22
  isEditMode: boolean;
@@ -22,6 +29,9 @@ export function MediaBlock({ refValue, options, link, isEditMode, onRefChange }:
22
29
  const fit = refValue.objectFit ?? options.objectFit;
23
30
  const fitClass = fit === "cover" ? "object-cover" : "object-contain";
24
31
  const showBorder = refValue.border ?? options.border;
32
+ // Image-only: a backdrop behind a video would just frame its letterboxing.
33
+ // Per placement by design (#60): not inheritable, and no per-ref override.
34
+ const backdrop = refValue.type === "video" ? undefined : imageBackdrop(options.background);
25
35
  const captionStr = refValue.caption
26
36
  ? Array.isArray(refValue.caption) ? refValue.caption.join("\n") : refValue.caption
27
37
  : "";
@@ -49,6 +59,7 @@ export function MediaBlock({ refValue, options, link, isEditMode, onRefChange }:
49
59
  className="h-full w-full"
50
60
  imgClassName={fitClass}
51
61
  invertFrom={refValue.invertFrom}
62
+ backdrop={backdrop}
52
63
  />
53
64
  );
54
65
 
@@ -1,9 +1,9 @@
1
1
  import { defineSection } from "../../../lib/registry";
2
2
  import { z } from "zod";
3
3
  import { Image as ImageIcon } from "lucide-react";
4
- import { SingleMediaReferenceSchema } from "../../../schemas/shared";
4
+ import { SingleMediaReferenceSchema, ImageBackgroundSchema } from "../../../schemas/shared";
5
5
  import { LinkValueSchema, DEFAULT_LINK } from "../../../schemas/link";
6
- import { MediaBlock } from "./MediaBlock";
6
+ import { MediaBlock, type MediaBlockProps } from "./MediaBlock";
7
7
 
8
8
  const schema = z.object({
9
9
  type: z.literal("media"),
@@ -24,6 +24,9 @@ const schema = z.object({
24
24
  .enum(["cover", "contain"])
25
25
  .describe("How the image fills its box: 'contain' (fit whole image) or 'cover' (fill and crop).")
26
26
  .optional(),
27
+ background: ImageBackgroundSchema.describe(
28
+ "Optional backdrop filling the image box, for images that need contrast (e.g. a white transparent logo). 'theme' picks the site's light or dark surface separately for light and dark mode; 'custom' uses one hex for both. Images only — ignored for video. Omit for none.",
29
+ ).optional(),
27
30
  })
28
31
  .default({}),
29
32
  });
@@ -38,7 +41,7 @@ export default defineSection({
38
41
  component: ({ content, options, onChange }) => (
39
42
  <MediaBlock
40
43
  refValue={content.content.ref}
41
- options={(options ?? {}) as { square?: boolean; showCaption?: boolean; border?: boolean; objectFit?: "cover" | "contain" }}
44
+ options={(options ?? {}) as MediaBlockProps["options"]}
42
45
  link={content.content.link}
43
46
  isEditMode={!!onChange}
44
47
  onRefChange={
@@ -69,11 +72,16 @@ export default defineSection({
69
72
  { label: "Cover", value: "cover" },
70
73
  ],
71
74
  },
75
+ background: {
76
+ type: "image-background",
77
+ label: "Image background",
78
+ hidden: (values) => (values.ref as { type?: string } | undefined)?.type === "video",
79
+ },
72
80
  link: { type: "link", label: "Link", default: DEFAULT_LINK, target: "content" },
73
81
  },
74
82
  inheritableSettings: ["square", "showCaption", "border", "objectFit"],
75
83
  settingsTabs: [
76
- { label: "Display", fields: ["square", "showCaption", "border", "objectFit"] },
84
+ { label: "Display", fields: ["square", "showCaption", "border", "objectFit", "background"] },
77
85
  { label: "Link", fields: ["link"] },
78
86
  ],
79
87
  });
@@ -0,0 +1,214 @@
1
+ import { useContext, useMemo } from "react";
2
+ import { ArrowUpRight } from "lucide-react";
3
+ import { cn } from "../../../lib/cn";
4
+ import { getSection } from "../../../lib/registry";
5
+ import { audiencePasses, pageDisplayTitle } from "../../../lib/pages";
6
+ import {
7
+ referenceItems, type ReferenceContent, type ReferenceExclusion, type ReferenceItem,
8
+ } from "../../../lib/references";
9
+ import { ReferenceSourcesContext, type ReferenceSources } from "../../shared/ReferenceSourcesContext";
10
+ import { SummaryAnchorsContext } from "../../shared/SummaryAnchorsContext";
11
+ import { useOptionalEditorContext } from "../../shell/EditorContext";
12
+ import { Button } from "../../shared/Button";
13
+
14
+ type ViewBranch = "saved" | "live";
15
+
16
+ /** Everything the canvas does with an item the published site drops, by why
17
+ * it drops it. `renders`: whether there is a copy to draw at all (a dangling
18
+ * pick has no source; a nested Reference is never expanded). `inPreview`:
19
+ * whether the preview still shows it, mirroring how it treats native sections. */
20
+ const EXCLUSIONS: Record<ReferenceExclusion, {
21
+ reason: (item: ReferenceItem) => string;
22
+ renders: boolean;
23
+ inPreview: (item: ReferenceItem, viewBranch: ViewBranch) => boolean;
24
+ }> = {
25
+ missing: {
26
+ reason: (i) => `Not found — deleted, unreadable, or not a top-level section (${i.sectionId})`,
27
+ renders: false,
28
+ inPreview: () => false,
29
+ },
30
+ reference: { reason: () => "Another Reference — never shown", renders: false, inPreview: () => false },
31
+ "archived-page": { reason: () => "On an archived page", renders: true, inPreview: () => false },
32
+ "not-live": {
33
+ reason: (i) => (i.source?.meta.status === "archived" ? "Archived section" : "Draft — publish it to show it here"),
34
+ renders: true,
35
+ // The Unpublished preview dims drafts and hides archived sections.
36
+ inPreview: (i, viewBranch) => viewBranch === "saved" && i.source?.meta.status === "draft",
37
+ },
38
+ };
39
+
40
+ const shownInPreview = (item: ReferenceItem, viewBranch: ViewBranch) =>
41
+ item.excluded === null || EXCLUSIONS[item.excluded].inPreview(item, viewBranch);
42
+
43
+ /**
44
+ * Whether a Reference draws anything in preview. The viewer renders no wrapper
45
+ * for an empty Reference, so EditorContent skips its wrapper in preview too.
46
+ * Audience-independent: an audience preview dims copies, it never removes them.
47
+ */
48
+ export function referenceShowsInPreview(
49
+ sources: ReferenceSources, referenceId: string, content: ReferenceContent, viewBranch: ViewBranch,
50
+ ): boolean {
51
+ return referenceItems({ referenceId, content, index: sources.index, allSections: sources.sections, audiences: [] })
52
+ .some((item) => shownInPreview(item, viewBranch));
53
+ }
54
+
55
+ const NO_SUMMARY_ANCHORS = {};
56
+
57
+ /**
58
+ * A Reference on the editor canvas, laid out exactly as the viewer lays out
59
+ * the sections it expands to — copy after copy, each 2.25rem below the last
60
+ * (a `.section-wrapper`'s top padding; the Reference's own wrapper supplies the
61
+ * first copy's) — so toggling between editing and preview never moves
62
+ * anything. Everything editor-only (where a copy comes from, why the site
63
+ * drops it, which of the page's audiences can't see it, Edit source) is an
64
+ * overlay that takes no space.
65
+ *
66
+ * Which copies show follows how the canvas treats native sections: edit mode
67
+ * lists every item, greyed with the reason when the published site drops it
68
+ * (a dangling pick or a nested Reference as an empty greyed row);
69
+ * the Unpublished preview hides archived ones and dims drafts; the Published
70
+ * preview shows exactly what the viewer resolves (EditorShell hands it the
71
+ * `main` branch's content then). An audience preview dims what that audience
72
+ * can't see. The audience warnings are relative to who can see this Reference
73
+ * — the page's audiences narrowed by the Reference's own access; when that
74
+ * leaves no one, the whole Reference says so.
75
+ */
76
+ export function ReferenceList({ referenceId, content, isEditMode }: {
77
+ referenceId: string;
78
+ content: ReferenceContent;
79
+ isEditMode: boolean;
80
+ }) {
81
+ const sources = useContext(ReferenceSourcesContext);
82
+ const editor = useOptionalEditorContext();
83
+ const viewBranch = editor?.viewBranch ?? "saved";
84
+ const previewAudience = editor?.previewAudience ?? null;
85
+
86
+ const model = useMemo(() => {
87
+ if (!sources) return null;
88
+ const { index, sections, audiences } = sources;
89
+ const page = index.pages.find((p) => p.order.includes(referenceId));
90
+ const access = index.sections[referenceId]?.access ?? [];
91
+ const viewers = audiences.filter((a) => audiencePasses(page?.access ?? [], a.name) && audiencePasses(access, a.name));
92
+ const items = referenceItems({
93
+ referenceId, content, index, allSections: sections, audiences: viewers.map((a) => a.name),
94
+ });
95
+ return {
96
+ items,
97
+ // Copies carry the page-wide anchors the editor nav links to, so no
98
+ // heading here duplicates its source's DOM id or another Reference's.
99
+ copyById: sources.copies[referenceId] ?? {},
100
+ displayName: new Map(viewers.map((a) => [a.name, a.displayName])),
101
+ viewerCount: viewers.length,
102
+ // The site has audiences, yet none passes both the page's access and the
103
+ // Reference's own: no one can ever see a copy here. (Empty access is
104
+ // "everyone", so an unrestricted page or Reference never lands here.)
105
+ noViewers: audiences.length > 0 && viewers.length === 0,
106
+ // Absent `tags` is "not loaded": tagged sections can't be listed yet.
107
+ tagsUnloaded: index.tags === undefined && content.tagIds.length > 0,
108
+ };
109
+ }, [sources, referenceId, content]);
110
+
111
+ if (!sources || !model) {
112
+ return isEditMode ? <Placeholder>Reference: shown as live copies on the published site.</Placeholder> : null;
113
+ }
114
+
115
+ // Edit mode lists every item, greyed with its reason when the site drops it;
116
+ // preview shows what the canvas shows for native sections.
117
+ const shown = isEditMode ? model.items : model.items.filter((item) => shownInPreview(item, viewBranch));
118
+
119
+ const notes = [
120
+ model.tagsUnloaded && "Tags haven't loaded, so tagged sections aren't listed yet.",
121
+ model.noViewers && "No audience can see this Reference on this page",
122
+ ].filter((n): n is string => !!n);
123
+
124
+ if (shown.length === 0) {
125
+ // EditorContent skips an empty Reference's wrapper in preview
126
+ // (referenceShowsInPreview); this covers rendering without it.
127
+ if (!isEditMode) return null;
128
+ if (notes.length === 0) return <Placeholder>Reference: no tags or sections chosen yet.</Placeholder>;
129
+ return <Placeholder>{["Reference: nothing to show.", ...notes].join(" ")}</Placeholder>;
130
+ }
131
+
132
+ return (
133
+ // The page's summary anchors are keyed by section id, so a copy of a
134
+ // summary also on this page would take its native anchor; emptying the
135
+ // context leaves every copy on the anchor stamped for it.
136
+ <SummaryAnchorsContext.Provider value={NO_SUMMARY_ANCHORS}>
137
+ {shown.map((item, n) => {
138
+ const { source } = item;
139
+ const exclusion = item.excluded ? EXCLUSIONS[item.excluded] : null;
140
+ const drawn = source && (!exclusion || exclusion.renders) ? source : null;
141
+ const definition = source ? getSection(source.section.type) : undefined;
142
+ const copy = drawn ? model.copyById[item.sectionId] ?? drawn.section : null;
143
+ const Component = definition?.component;
144
+ const reason = exclusion?.reason(item) ?? null;
145
+ const hiddenForAll = model.noViewers || (model.viewerCount > 0 && item.hiddenFrom.length === model.viewerCount);
146
+ const previewHidden = previewAudience !== null && !!source &&
147
+ (!audiencePasses(item.page?.access ?? [], previewAudience) || !audiencePasses(source.meta.access, previewAudience));
148
+ const typeLabel = definition?.label ?? source?.section.type ?? "Section";
149
+ const label = (source && definition?.getLabel?.(source.section)) || typeLabel;
150
+
151
+ return (
152
+ <div key={item.sectionId} className={cn(n > 0 && "pt-9")}>
153
+ <div
154
+ data-reference-item={item.sectionId}
155
+ className={cn(
156
+ // `group` mirrors the viewer's per-section wrapper for the copy's
157
+ // own hover styles; `group/copy` scopes Edit source to this copy,
158
+ // since the Reference's wrapper is a `group` too.
159
+ "group group/copy relative",
160
+ isEditMode && "rounded-outer hover:outline hover:outline-1 hover:outline-dashed hover:outline-primary/40",
161
+ previewHidden ? "opacity-15 transition-opacity duration-200 hover:opacity-100"
162
+ : (isEditMode ? reason || hiddenForAll : item.excluded) && "opacity-50",
163
+ )}
164
+ >
165
+ {/* inert while editing: a copy is read-only — edits happen on its source. */}
166
+ <div inert={isEditMode}>
167
+ {!copy && <div className="min-h-20 rounded-md border-2 border-dashed" />}
168
+ {copy && Component && (
169
+ <Component
170
+ content={copy}
171
+ options={"options" in copy ? (copy.options as Record<string, unknown>) : undefined}
172
+ isEditMode={false}
173
+ />
174
+ )}
175
+ </div>
176
+ {isEditMode && (
177
+ <div className="absolute right-2 top-2 z-20 flex max-w-[calc(100%-1rem)] flex-wrap items-center justify-end gap-1">
178
+ {n === 0 && notes.map((note) => <Badge key={note}>{note}</Badge>)}
179
+ {reason && <Badge>{reason}</Badge>}
180
+ {!reason && hiddenForAll && !model.noViewers && <Badge>Hidden for all of this page's audiences</Badge>}
181
+ {!reason && !hiddenForAll && item.hiddenFrom.length > 0 && (
182
+ <Badge>{`Hidden from ${item.hiddenFrom.map((a) => model.displayName.get(a) ?? a).join(", ")}`}</Badge>
183
+ )}
184
+ {source && <span className="flex items-center gap-2 rounded-full border border-base-200 bg-base px-2 py-0.5 text-xs opacity-0 shadow-sm transition-opacity focus-within:opacity-100 group-hover/copy:opacity-100">
185
+ <span className="max-w-56 truncate text-base-contrast-light">
186
+ {item.page ? `${pageDisplayTitle(item.page.title)} · ` : ""}{label}
187
+ </span>
188
+ <Button variant="ghost" className="inline-flex items-center gap-0.5" onClick={() => sources.jumpToSection(item.sectionId)}>
189
+ Edit source <ArrowUpRight size={12} aria-hidden="true" />
190
+ </Button>
191
+ </span>}
192
+ </div>
193
+ )}
194
+ </div>
195
+ </div>
196
+ );
197
+ })}
198
+ </SummaryAnchorsContext.Provider>
199
+ );
200
+ }
201
+
202
+ function Badge({ children }: { children: string }) {
203
+ return (
204
+ <span className="rounded-full border border-warning bg-warning-bg px-2 py-0.5 text-xs text-warning shadow-sm">{children}</span>
205
+ );
206
+ }
207
+
208
+ function Placeholder({ children }: { children: string }) {
209
+ return (
210
+ <div className="flex min-h-20 items-center justify-center rounded-md border-2 border-dashed px-4 text-center text-xs text-base-contrast-light/50">
211
+ {children}
212
+ </div>
213
+ );
214
+ }
@@ -0,0 +1,159 @@
1
+ import { useContext, useState } from "react";
2
+ import { cn } from "../../../lib/cn";
3
+ import { getSection } from "../../../lib/registry";
4
+ import { pageDisplayTitle } from "../../../lib/pages";
5
+ import { pagesInNavOrder } from "../../../lib/nav-tree";
6
+ import { siteTags, tagDisplayLabel } from "../../../lib/tags";
7
+ import { pluralize } from "../../../lib/text";
8
+ import { toThumbViews, type ThumbView } from "../../../lib/thumb-views";
9
+ import { REFERENCE_TYPE } from "../../../lib/reference-type";
10
+ import type { ReferenceContent } from "../../../lib/references";
11
+ import { ReferenceSourcesContext } from "../../shared/ReferenceSourcesContext";
12
+ import { SectionSummaryRow } from "../../shared/SectionSummaryRow";
13
+ import { Checkbox, CheckboxBox } from "../../shared/Checkbox";
14
+ import { Tabs } from "../../shared/Tabs";
15
+
16
+ const panel = "flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto px-px";
17
+
18
+ /**
19
+ * Tags and Sections, combined as a union. Ids the registry or index no longer
20
+ * knows are listed too, so an editor can see them and clear them — the viewer
21
+ * drops them silently.
22
+ */
23
+ export function ReferenceSettings({
24
+ tagIds = [],
25
+ sectionIds = [],
26
+ onChange,
27
+ }: Partial<ReferenceContent> & { onChange: (result: { content: ReferenceContent }) => void }) {
28
+ const sources = useContext(ReferenceSourcesContext);
29
+ const [v, setV] = useState<ReferenceContent>({ tagIds, sectionIds });
30
+
31
+ const update = (next: ReferenceContent) => {
32
+ setV(next);
33
+ onChange({ content: next });
34
+ };
35
+ const toggle = (list: string[], id: string, on: boolean) => (on ? [...list, id] : list.filter((x) => x !== id));
36
+
37
+ if (!sources) return null;
38
+ const { index, sections, mediaManifest } = sources;
39
+
40
+ // Absent `tags` is "not loaded", not "none": every stored tag would read as
41
+ // deleted, and clearing one would drop a real tag. Hold the tab read-only.
42
+ const tagsLoaded = index.tags !== undefined;
43
+ const tags = siteTags(index);
44
+ const deletedTagIds = tagsLoaded ? v.tagIds.filter((id) => !tags.some((t) => t.id === id)) : [];
45
+
46
+ const byId = new Map(sections.map((s) => [s.section.id, s]));
47
+ const pageGroups = pagesInNavOrder(index)
48
+ .map((page) => ({
49
+ page,
50
+ rows: page.order.flatMap((id) => {
51
+ const s = byId.get(id);
52
+ // References can't be picked; one already picked (by an agent) is
53
+ // listed so it can be cleared.
54
+ return s && (s.section.type !== REFERENCE_TYPE || v.sectionIds.includes(id)) ? [s] : [];
55
+ }),
56
+ }))
57
+ .filter((g) => g.rows.length > 0);
58
+ const onAPage = new Set(pageGroups.flatMap((g) => g.rows.map((s) => s.section.id)));
59
+ const deletedSectionIds = v.sectionIds.filter((id) => !onAPage.has(id));
60
+
61
+ const tagsTab = (
62
+ <div className={panel}>
63
+ {!tagsLoaded && (
64
+ <p className="text-sm text-base-contrast-light">Tags haven't loaded, so they can't be changed right now.</p>
65
+ )}
66
+ {tagsLoaded && tags.length === 0 && deletedTagIds.length === 0 && (
67
+ <p className="text-sm text-base-contrast-light">
68
+ No tags yet. Add them from a section's Tags pill or under Site settings → Tags.
69
+ </p>
70
+ )}
71
+ {tags.map((t) => (
72
+ <Checkbox
73
+ key={t.id}
74
+ label={tagDisplayLabel(t.label)}
75
+ description={pluralize(t.sectionIds.length, "section")}
76
+ checked={v.tagIds.includes(t.id)}
77
+ onChange={(on) => update({ ...v, tagIds: toggle(v.tagIds, t.id, on) })}
78
+ />
79
+ ))}
80
+ {deletedTagIds.map((id) => (
81
+ <Checkbox
82
+ key={id}
83
+ label="Deleted tag"
84
+ description="Shows nothing. Untick to remove it."
85
+ checked
86
+ onChange={() => update({ ...v, tagIds: toggle(v.tagIds, id, false) })}
87
+ />
88
+ ))}
89
+ </div>
90
+ );
91
+
92
+ const sectionRow = (id: string, label: string, typeLabel: string, thumbs: ThumbView[], status?: string) => {
93
+ const checked = v.sectionIds.includes(id);
94
+ return (
95
+ <button
96
+ key={id}
97
+ type="button"
98
+ role="checkbox"
99
+ aria-checked={checked}
100
+ aria-label={`${typeLabel}: ${label}`}
101
+ onClick={() => update({ ...v, sectionIds: toggle(v.sectionIds, id, !checked) })}
102
+ className="flex w-full cursor-pointer text-left"
103
+ >
104
+ <SectionSummaryRow
105
+ label={label}
106
+ typeLabel={typeLabel}
107
+ thumbnails={thumbs}
108
+ className={cn(checked && "border-primary")}
109
+ trailing={
110
+ <>
111
+ {status && status !== "live" && <span className="text-xs capitalize text-base-contrast-light">{status}</span>}
112
+ <CheckboxBox checked={checked} />
113
+ </>
114
+ }
115
+ />
116
+ </button>
117
+ );
118
+ };
119
+
120
+ const sectionsTab = (
121
+ <div className={panel}>
122
+ {pageGroups.map(({ page, rows }) => (
123
+ <section key={page.id} className="flex flex-col gap-2">
124
+ <h3 className="text-xs font-medium uppercase tracking-wide text-base-contrast-light">
125
+ {pageDisplayTitle(page.title)}
126
+ {page.status === "archived" && " (archived)"}
127
+ </h3>
128
+ {rows.map((s) => {
129
+ const def = getSection(s.section.type);
130
+ const typeLabel = def?.label ?? s.section.type;
131
+ return sectionRow(
132
+ s.section.id,
133
+ def?.getLabel?.(s.section) ?? typeLabel,
134
+ typeLabel,
135
+ toThumbViews(def?.getThumbnails?.(s.section) ?? [], mediaManifest),
136
+ s.meta.status,
137
+ );
138
+ })}
139
+ </section>
140
+ ))}
141
+ {deletedSectionIds.length > 0 && (
142
+ <section className="flex flex-col gap-2">
143
+ <h3 className="text-xs font-medium uppercase tracking-wide text-base-contrast-light">Not found</h3>
144
+ {deletedSectionIds.map((id) => sectionRow(id, "Section not found", "Deleted or can't be read", []))}
145
+ </section>
146
+ )}
147
+ </div>
148
+ );
149
+
150
+ return (
151
+ <Tabs
152
+ fullBleedTabBar
153
+ tabs={[
154
+ { id: "tags", label: `Tags${v.tagIds.length ? ` (${v.tagIds.length})` : ""}`, content: tagsTab },
155
+ { id: "sections", label: `Sections${v.sectionIds.length ? ` (${v.sectionIds.length})` : ""}`, content: sectionsTab },
156
+ ]}
157
+ />
158
+ );
159
+ }