@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
- import { useCallback, useState, useEffect } from "react";
2
- import { Check, ChevronDown, Home } from "lucide-react";
1
+ import { useCallback, useState, useEffect, useId } from "react";
2
+ import { Check, ChevronDown, ChevronUp, Home } from "lucide-react";
3
3
  import type { SiteIndex, Page } from "../../schemas/site-config";
4
4
  import type { Audience } from "../../auth/types";
5
5
  // Sanctioned outside->inside import: document/ is a sealed subtree, but the
@@ -7,6 +7,8 @@ import type { Audience } from "../../auth/types";
7
7
  // sanctioned import in schemas/site-config.ts and lib/pages.ts).
8
8
  import type { DocumentOptions } from "../../document/engine/settings";
9
9
  import { Button } from "../shared/Button";
10
+ import { ConfirmDialog } from "../shared/ConfirmDialog";
11
+ import { IconButton } from "../shared/IconButton";
10
12
  import { Input } from "../shared/Input";
11
13
  import { Toggle } from "../shared/Toggle";
12
14
  import { AudienceIndicator } from "./AudienceIndicator";
@@ -80,7 +82,17 @@ export function PagesModal(props: PagesModalProps) {
80
82
 
81
83
  // `location` is optional: the archived flat block renders inert rows with no
82
84
  // nav position, exactly as it did when draggability keyed off `dragIndex`.
83
- const renderPage = (page: Page, location?: NavLocation, entryIndex?: number) => (
85
+ // `liveSiblingRawIndexes` is the ordered list of RAW positions (within the
86
+ // group's `pageIds`, or within the top-level `entries`) that Move up/down
87
+ // may cross into — i.e. every LIVE sibling's raw slot, archived ones
88
+ // excluded. `location.index` is itself a raw position (drag needs it to
89
+ // splice correctly — see the ORIGINAL pageIds index comment below), so
90
+ // comparing it against a raw-space list (not a live COUNT) is what keeps an
91
+ // archived page sitting between two live ones from producing a wrongly
92
+ // disabled button or a click that silently swaps past the archived page
93
+ // with no visible reorder (drag can cross a group boundary; the keyboard
94
+ // pair deliberately cannot).
95
+ const renderPage = (page: Page, location?: NavLocation, entryIndex?: number, liveSiblingRawIndexes?: number[]) => (
84
96
  <PageRow
85
97
  key={page.id}
86
98
  page={page}
@@ -90,6 +102,7 @@ export function PagesModal(props: PagesModalProps) {
90
102
  otherSlugs={index.pages.filter((p) => p.id !== page.id).map((p) => p.slug)}
91
103
  location={location}
92
104
  entryIndex={entryIndex}
105
+ liveSiblingRawIndexes={liveSiblingRawIndexes}
93
106
  onMove={props.onMoveNavEntry}
94
107
  onToggleExpand={() => toggleExpand(page.id)}
95
108
  onSetHome={() => props.onSetHome(page.id)}
@@ -108,14 +121,28 @@ export function PagesModal(props: PagesModalProps) {
108
121
  />
109
122
  );
110
123
 
124
+ const entries = navEntries(index);
125
+ const entryCount = entries.length;
126
+ // Raw top-level positions that are "live" for Move up/down purposes: every
127
+ // group (always visible) plus every non-archived page — mirrors
128
+ // isLiveTopEntry in lib/nav-tree.ts, which describeNavMove's "N of M" uses.
129
+ const liveTopIndexes = entries
130
+ .map((entry, i) => ({ entry, i }))
131
+ .filter(({ entry }) => {
132
+ if (entry.kind === "group") return true;
133
+ const page = index.pages.find((p) => p.id === entry.pageId);
134
+ return page?.status === "live";
135
+ })
136
+ .map(({ i }) => i);
137
+
111
138
  return (
112
139
  <div className="flex flex-col gap-2 overflow-y-auto">
113
140
  <div className="flex flex-col gap-2">
114
- {navEntries(index).map((entry, entryIndex) => {
141
+ {entries.map((entry, entryIndex) => {
115
142
  if (entry.kind === "page") {
116
143
  const page = index.pages.find((p) => p.id === entry.pageId);
117
144
  if (!page || page.status !== "live") return null;
118
- return renderPage(page, { groupId: null, index: entryIndex }, entryIndex);
145
+ return renderPage(page, { groupId: null, index: entryIndex }, entryIndex, liveTopIndexes);
119
146
  }
120
147
 
121
148
  // CRITICAL: carry the ORIGINAL pageIds index (`pi`) through the filter.
@@ -134,6 +161,7 @@ export function PagesModal(props: PagesModalProps) {
134
161
  <NavGroupRow
135
162
  group={entry}
136
163
  entryIndex={entryIndex}
164
+ entryCount={entryCount}
137
165
  memberCount={members.length}
138
166
  autoOpenSettings={newGroupId === entry.id}
139
167
  onRename={(label) => props.onRenameGroup(entry.id, label)}
@@ -146,7 +174,7 @@ export function PagesModal(props: PagesModalProps) {
146
174
  <div data-testid={`nav-group-members-${entry.id}`} className="ml-6 flex flex-col gap-2">
147
175
  {members.length === 0
148
176
  ? <EmptyGroupDropzone groupId={entry.id} onMove={props.onMoveNavEntry} />
149
- : members.map(({ page, pi }) => renderPage(page, { groupId: entry.id, index: pi }, entryIndex))}
177
+ : members.map(({ page, pi }) => renderPage(page, { groupId: entry.id, index: pi }, entryIndex, members.map((m) => m.pi)))}
150
178
  </div>
151
179
  )}
152
180
  </div>
@@ -156,7 +184,7 @@ export function PagesModal(props: PagesModalProps) {
156
184
 
157
185
  {/* The only target for "after the last entry" when that entry is a group:
158
186
  every edge of a trailing group resolves to a position inside it. */}
159
- <TailDropzone entryCount={navEntries(index).length} onMove={props.onMoveNavEntry} />
187
+ <TailDropzone entryCount={entryCount} onMove={props.onMoveNavEntry} />
160
188
 
161
189
  <div className="mt-2 flex gap-2">
162
190
  <Button
@@ -194,11 +222,16 @@ export function PagesModal(props: PagesModalProps) {
194
222
  }
195
223
 
196
224
  function PageRow({
197
- page, audiences, expanded, isNew, otherSlugs, location, entryIndex, onMove, onToggleExpand, onSetHome, onSetArchived, onSetFields, onSetAudience, onSetDocument, onRequestDelete,
225
+ page, audiences, expanded, isNew, otherSlugs, location, entryIndex, liveSiblingRawIndexes, onMove, onToggleExpand, onSetHome, onSetArchived, onSetFields, onSetAudience, onSetDocument, onRequestDelete,
198
226
  }: {
199
227
  page: Page; audiences: Audience[]; expanded: boolean;
200
228
  isNew: boolean; otherSlugs: string[];
201
229
  location?: NavLocation; entryIndex?: number;
230
+ /** Ordered RAW positions of every LIVE sibling (the enclosing group's
231
+ * `pageIds`, or the top-level `entries`, whichever `location.groupId`
232
+ * selects) — see the comment on `renderPage` in PagesModal. Drag can cross
233
+ * a group boundary; the keyboard pair deliberately cannot. */
234
+ liveSiblingRawIndexes?: number[];
202
235
  onMove: (from: NavLocation, to: NavLocation) => void;
203
236
  onToggleExpand: () => void; onSetHome: () => void; onSetArchived: (v: boolean) => void;
204
237
  onSetFields: (patch: Partial<Pick<Page, "title" | "slug" | "showInNav">>) => void;
@@ -211,6 +244,19 @@ function PageRow({
211
244
  row: { kind: "page", pageId: page.id, groupId: location?.groupId ?? null, index: location?.index ?? 0 },
212
245
  entryIndex: entryIndex ?? 0, kind: "page", onMove, enabled: draggable,
213
246
  });
247
+ const dragHintId = useId();
248
+ // Neighbours are resolved among LIVE siblings only, then translated back to
249
+ // the neighbour's own raw index — never `location.index + delta`, which
250
+ // would step into an archived page's raw slot instead of the next visible
251
+ // row (see the `liveSiblingRawIndexes` comment on PagesModal's renderPage).
252
+ const liveIndex = liveSiblingRawIndexes?.indexOf(location?.index ?? -1) ?? -1;
253
+ const canMoveUp = draggable && liveIndex > 0;
254
+ const canMoveDown = draggable && liveSiblingRawIndexes !== undefined && liveIndex !== -1 && liveIndex < liveSiblingRawIndexes.length - 1;
255
+ const moveTo = (delta: 1 | -1) => {
256
+ const neighbourRawIndex = liveSiblingRawIndexes?.[liveIndex + delta];
257
+ if (neighbourRawIndex === undefined) return;
258
+ onMove(location!, { groupId: location!.groupId, index: neighbourRawIndex });
259
+ };
214
260
 
215
261
  // The slug input edits a local draft; only valid values commit to the index,
216
262
  // which must always hold a non-empty, unique, non-reserved slug.
@@ -297,8 +343,27 @@ function PageRow({
297
343
  >
298
344
  <DropEdgeIndicator edge={closestEdge} inset={location?.groupId != null} />
299
345
  {draggable && (
300
- <div className="flex shrink-0 items-center py-2 [&_[role=tooltip]]:hidden">
301
- <DragHandle ref={handleRef} />
346
+ <div className="flex shrink-0 items-center gap-1 py-2 [&_[role=tooltip]]:hidden">
347
+ <DragHandle ref={handleRef} tabIndex={0} aria-describedby={dragHintId} />
348
+ <div className="flex flex-col">
349
+ <IconButton
350
+ icon={<ChevronUp size={12} />}
351
+ label="Move up"
352
+ size="sm"
353
+ disabled={!canMoveUp}
354
+ onClick={() => moveTo(-1)}
355
+ />
356
+ <IconButton
357
+ icon={<ChevronDown size={12} />}
358
+ label="Move down"
359
+ size="sm"
360
+ disabled={!canMoveDown}
361
+ onClick={() => moveTo(1)}
362
+ />
363
+ </div>
364
+ <span id={dragHintId} className="sr-only">
365
+ Use Move up / Move down to reorder with the keyboard.
366
+ </span>
302
367
  </div>
303
368
  )}
304
369
  <div className={cn("min-w-0 flex-1 rounded-md border border-base-200 bg-base", isDragging && "outline outline-2 outline-primary/50")}>
@@ -455,21 +520,29 @@ function DeleteConfirm({ page, onCancel, onConfirm }: { page: Page; onCancel: ()
455
520
  // type-the-name guard pre-satisfied ("" === "").
456
521
  const confirmName = pageDisplayTitle(page.title);
457
522
  return (
458
- <div className="flex flex-col gap-3">
459
- <p className="text-sm text-base-contrast">
460
- Deleting <strong>{confirmName}</strong> permanently removes the page and its{" "}
461
- <strong>{pluralize(n, "section")}</strong>. This is recoverable only via GitHub version history.
462
- </p>
463
- <Input
464
- label={`Type the page name "${confirmName}" to confirm`}
465
- value={typed}
466
- onChange={setTyped}
467
- placeholder={confirmName}
468
- />
469
- <div className="flex justify-end gap-3">
470
- <Button variant="secondary" size="md" onClick={onCancel}>Cancel</Button>
471
- <Button variant="destructive" size="md" disabled={typed !== confirmName} onClick={onConfirm}>Delete</Button>
472
- </div>
473
- </div>
523
+ <ConfirmDialog
524
+ isOpen
525
+ embedded
526
+ title="Delete this page?"
527
+ body={
528
+ <div className="flex flex-col gap-3">
529
+ <p className="text-sm text-base-contrast">
530
+ Deleting <strong>{confirmName}</strong> permanently removes the page and its{" "}
531
+ <strong>{pluralize(n, "section")}</strong>. This is recoverable only via GitHub version history.
532
+ </p>
533
+ <Input
534
+ label={`Type the page name "${confirmName}" to confirm`}
535
+ value={typed}
536
+ onChange={setTyped}
537
+ placeholder={confirmName}
538
+ />
539
+ </div>
540
+ }
541
+ confirmLabel="Delete"
542
+ tone="destructive"
543
+ confirmDisabled={typed !== confirmName}
544
+ onConfirm={onConfirm}
545
+ onCancel={onCancel}
546
+ />
474
547
  );
475
548
  }
@@ -1,14 +1,16 @@
1
- import { useState, useRef, useEffect } from "react";
2
- import { ArrowRightLeft, Plus } from "lucide-react";
1
+ import { useState, useRef, useEffect, useId } from "react";
2
+ import { ArrowRightLeft, Plus, ChevronUp, ChevronDown } from "lucide-react";
3
3
  import type { Edge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
4
4
  import { DragHandle } from "./DragHandle";
5
+ import { DropEdgeIndicator } from "./DropEdgeIndicator";
5
6
  import { InsertButton } from "./InsertButton";
6
7
  import { DeleteButton } from "./DeleteButton";
7
8
  import { SettingsButton } from "./SettingsButton";
8
9
  import { IconButton } from "../shared/IconButton";
9
- import { Tooltip, Kbd } from "../shared/Tooltip";
10
+ import { Tooltip } from "../shared/Tooltip";
10
11
  import { StatusIndicator } from "./StatusIndicator";
11
12
  import { AudienceIndicator } from "./AudienceIndicator";
13
+ import { TagIndicator } from "./TagIndicator";
12
14
  import { LockBadge } from "./LockBadge";
13
15
  import { SettingsForm } from "./SettingsForm";
14
16
  import { useEditorContext } from "../shell/EditorContext";
@@ -16,6 +18,7 @@ import { useEditorModal } from "../shell/EditorModalContext";
16
18
  import type { WrapperProps } from "../../lib/registry";
17
19
  import { buildBlockDragData, buildBlockDropData, isBlockDragData, canDropBlock } from "../../lib/block-dnd";
18
20
  import { cn } from "../../lib/cn";
21
+ import { REFERENCE_TYPE } from "../../lib/reference-type";
19
22
 
20
23
  export function SectionWrapper({
21
24
  sectionId,
@@ -24,6 +27,7 @@ export function SectionWrapper({
24
27
  dirty,
25
28
  index,
26
29
  isLast,
30
+ sectionCount,
27
31
  containerId,
28
32
  isContainerBlock,
29
33
  definition,
@@ -31,6 +35,7 @@ export function SectionWrapper({
31
35
  audiences,
32
36
  access,
33
37
  onAccessChange,
38
+ tagging,
34
39
  onStatusChange,
35
40
  onSectionChange,
36
41
  onReorder,
@@ -64,6 +69,7 @@ export function SectionWrapper({
64
69
  const handleRef = useRef<HTMLButtonElement>(null);
65
70
  const [isDragging, setIsDragging] = useState(false);
66
71
  const [closestEdge, setClosestEdge] = useState<Edge | null>(null);
72
+ const dragHintId = useId();
67
73
 
68
74
  const hasSettings = !!(
69
75
  (definition.settings || definition.settingsForm) &&
@@ -120,6 +126,7 @@ export function SectionWrapper({
120
126
  containerId,
121
127
  index,
122
128
  isContainer: isContainerBlock,
129
+ isReference: sectionType === REFERENCE_TYPE,
123
130
  }),
124
131
  onGenerateDragPreview: () => {
125
132
  dropElement.style.opacity = "0.4";
@@ -182,7 +189,7 @@ export function SectionWrapper({
182
189
  // be torn down on lock-acquire (cleanup above) and re-run against the fresh
183
190
  // handle node on lock-release — without it, a locked-then-released section's
184
191
  // registration stays bound to the old unmounted handle and reorder breaks.
185
- }, [sectionId, index, containerId, isContainerBlock, isEditMode, isLocked]);
192
+ }, [sectionId, sectionType, index, containerId, isContainerBlock, isEditMode, isLocked]);
186
193
 
187
194
  function handleSettingsClick() {
188
195
  if (!onSectionChange) return;
@@ -278,11 +285,14 @@ export function SectionWrapper({
278
285
  <div
279
286
  className={cn(
280
287
  "absolute left-0 bottom-full z-30 hover:z-[60] mb-1 flex items-center gap-1.5 transition-opacity",
281
- alwaysShow ? "opacity-100" : "opacity-0 group-hover:opacity-100",
288
+ // group-focus-within: this cluster's own tab stops (DragHandle,
289
+ // Move up/down) would otherwise be focusable but invisible —
290
+ // hover alone doesn't cover keyboard navigation.
291
+ alwaysShow ? "opacity-100" : "opacity-0 group-hover:opacity-100 group-focus-within:opacity-100",
282
292
  )}
283
293
  >
284
294
  <div className="relative -ml-[34px] flex flex-col items-center">
285
- <DragHandle ref={handleRef} />
295
+ <DragHandle ref={handleRef} tabIndex={0} aria-describedby={dragHintId} />
286
296
  {onRequestInsert && !isDragging && chromeReady && (
287
297
  // Below xl the gutter can't fit the plus beside the handle, so it
288
298
  // hangs below it (absolute → no row-height contribution: the handle
@@ -295,6 +305,27 @@ export function SectionWrapper({
295
305
  <span className="pointer-events-none select-none whitespace-nowrap text-sm capitalize text-base-contrast-light/80">
296
306
  {definition.label}
297
307
  </span>
308
+ {onReorder && (
309
+ <div className="pointer-events-auto flex items-center">
310
+ <IconButton
311
+ icon={<ChevronUp size={14} />}
312
+ label={sectionCount ? `Move up (position ${index + 1} of ${sectionCount})` : "Move up"}
313
+ size="sm"
314
+ disabled={index === 0}
315
+ onClick={() => onReorder(index, index - 1)}
316
+ />
317
+ <IconButton
318
+ icon={<ChevronDown size={14} />}
319
+ label={sectionCount ? `Move down (position ${index + 1} of ${sectionCount})` : "Move down"}
320
+ size="sm"
321
+ disabled={isLast}
322
+ onClick={() => onReorder(index, index + 1)}
323
+ />
324
+ </div>
325
+ )}
326
+ <span id={dragHintId} className="sr-only">
327
+ Use Move up / Move down to reorder with the keyboard.
328
+ </span>
298
329
  </div>
299
330
  )}
300
331
 
@@ -331,9 +362,18 @@ export function SectionWrapper({
331
362
  onChange={(newAccess) => onAccessChange?.(newAccess)}
332
363
  />
333
364
  </div>
365
+ <div className="pointer-events-auto">
366
+ <TagIndicator
367
+ tags={tagging.tags}
368
+ assignedIds={tagging.assignedIds}
369
+ disabled={isLocked || !tagging.onToggle || !tagging.onCreate}
370
+ onToggle={(tagId, tagged) => tagging.onToggle?.(tagId, tagged)}
371
+ onCreate={(label) => tagging.onCreate?.(label)}
372
+ />
373
+ </div>
334
374
 
335
375
  {!isLocked && onAddChild && (
336
- <Tooltip className="pointer-events-auto" content={<><Kbd>Add</Kbd> a block</>}>
376
+ <Tooltip className="pointer-events-auto" content="Add a block">
337
377
  <IconButton
338
378
  icon={<Plus size={16} />}
339
379
  label="Add block"
@@ -344,7 +384,7 @@ export function SectionWrapper({
344
384
  )}
345
385
 
346
386
  {!isLocked && onMoveSection && (
347
- <Tooltip className="pointer-events-auto" content={<><Kbd>Move</Kbd> to page</>}>
387
+ <Tooltip className="pointer-events-auto" content="Move to page">
348
388
  <IconButton
349
389
  icon={<ArrowRightLeft size={16} />}
350
390
  label="Move to page"
@@ -355,31 +395,32 @@ export function SectionWrapper({
355
395
  )}
356
396
 
357
397
  {!isLocked && hasSettings && (
358
- <Tooltip className="pointer-events-auto" content={<><Kbd>Edit</Kbd> settings</>}>
398
+ <Tooltip className="pointer-events-auto" content="Edit settings">
359
399
  <SettingsButton onClick={handleSettingsClick} />
360
400
  </Tooltip>
361
401
  )}
362
402
 
363
403
  {!isLocked && onDelete && (
364
- <Tooltip className="pointer-events-auto" content={<><Kbd>Delete</Kbd> section</>}>
404
+ <Tooltip className="pointer-events-auto" content="Delete section">
365
405
  <DeleteButton onDelete={onDelete} />
366
406
  </Tooltip>
367
407
  )}
368
408
  </div>
369
409
 
370
- {/* Drop indicator — centered in the section's own padding-top */}
371
- {closestEdge === "top" && (
372
- <div
373
- className="absolute right-0 left-0 z-10 h-0.5 bg-primary"
374
- style={{
375
- top: "calc(var(--section-gap) / 2 * -1)",
376
- transform: "translateY(-50%)",
377
- }}
378
- />
379
- )}
380
- {closestEdge === "bottom" && isLast && (
381
- <div className="absolute right-0 bottom-0 left-0 z-10 h-0.5 bg-primary" />
382
- )}
410
+ {/* Drop indicator — centered in the section's own padding-top. Bottom
411
+ only ever shows on the last section: every other slot's "insert
412
+ after me" is the next section's own "top" line, so showing both
413
+ would double the line. */}
414
+ <DropEdgeIndicator
415
+ edge={closestEdge === "bottom" && !isLast ? null : closestEdge}
416
+ style={
417
+ closestEdge === "top"
418
+ ? { top: "calc(var(--section-gap) / 2 * -1)" }
419
+ : closestEdge === "bottom"
420
+ ? { transform: "none" }
421
+ : undefined
422
+ }
423
+ />
383
424
 
384
425
  {isLocked ? (
385
426
  // React 19 supports the boolean `inert` prop — blocks focus, pointer,
@@ -1,4 +1,4 @@
1
- import { SettingsIcon } from "../shared/icons";
1
+ import { Settings } from "lucide-react";
2
2
  import { IconButton } from "../shared/IconButton";
3
3
 
4
4
  interface SettingsButtonProps {
@@ -8,7 +8,7 @@ interface SettingsButtonProps {
8
8
  export function SettingsButton({ onClick }: SettingsButtonProps) {
9
9
  return (
10
10
  <IconButton
11
- icon={<SettingsIcon size={16} />}
11
+ icon={<Settings size={16} />}
12
12
  label="Section settings"
13
13
  onClick={onClick}
14
14
  className="pointer-events-auto"
@@ -7,8 +7,10 @@ import { FormLabel } from "../shared/FormLabel";
7
7
  import { LinkField } from "../shared/LinkField";
8
8
  import { VideoSourceField } from "../shared/VideoSourceField";
9
9
  import { DocumentSourceField, type DocumentRef } from "../shared/DocumentSourceField";
10
+ import { ImageBackgroundField } from "../shared/ImageBackgroundField";
10
11
  import { Tabs } from "../shared/Tabs";
11
12
  import type { LinkValue } from "../../schemas/link";
13
+ import type { ImageBackground } from "../../schemas/shared";
12
14
  import type { VideoSource } from "../sections/Video/VideoBlock";
13
15
  import { cn } from "../../lib/cn";
14
16
 
@@ -101,6 +103,7 @@ function renderField(
101
103
  field: SettingsFieldDef,
102
104
  value: unknown,
103
105
  handleFieldChange: (key: string, newValue: unknown) => void,
106
+ values: Record<string, unknown>,
104
107
  ) {
105
108
  switch (field.type) {
106
109
  case "text":
@@ -184,6 +187,17 @@ function renderField(
184
187
  />
185
188
  );
186
189
 
190
+ case "image-background":
191
+ if (field.hidden?.(values)) return null;
192
+ return (
193
+ <ImageBackgroundField
194
+ key={key}
195
+ label={field.label}
196
+ value={value as ImageBackground | undefined}
197
+ onChange={(v) => handleFieldChange(key, v)}
198
+ />
199
+ );
200
+
187
201
  default:
188
202
  return null;
189
203
  }
@@ -192,6 +206,9 @@ function renderField(
192
206
  export function SettingsForm({ schema, values, onChange, tabs }: SettingsFormProps) {
193
207
  const [local, setLocal] = useState(() => resolveValues(schema, values));
194
208
 
209
+ // `local` holds only schema keys; `hidden` predicates may read others (e.g. `ref`).
210
+ const allValues = { ...values, ...local };
211
+
195
212
  function handleFieldChange(key: string, newValue: unknown) {
196
213
  const next = { ...local, [key]: newValue };
197
214
  setLocal(next);
@@ -200,7 +217,7 @@ export function SettingsForm({ schema, values, onChange, tabs }: SettingsFormPro
200
217
 
201
218
  if (tabs) {
202
219
  const fields = (keys: string[]) =>
203
- keys.filter((key) => key in schema).map((key) => renderField(key, schema[key], local[key], handleFieldChange));
220
+ keys.filter((key) => key in schema).map((key) => renderField(key, schema[key], local[key], handleFieldChange, allValues));
204
221
 
205
222
  const listed = new Set(tabs.flatMap((t) => t.fields));
206
223
  const otherKeys = Object.keys(schema).filter((key) => !listed.has(key));
@@ -216,7 +233,7 @@ export function SettingsForm({ schema, values, onChange, tabs }: SettingsFormPro
216
233
 
217
234
  return (
218
235
  <div className="flex flex-col gap-4">
219
- {Object.entries(schema).map(([key, field]) => renderField(key, field, local[key], handleFieldChange))}
236
+ {Object.entries(schema).map(([key, field]) => renderField(key, field, local[key], handleFieldChange, allValues))}
220
237
  </div>
221
238
  );
222
239
  }
@@ -74,10 +74,10 @@ export function deriveStatusDisplay({ mainStatus, savedStatus, contentDiffers, i
74
74
  }
75
75
 
76
76
  const dotColorClasses: Record<StatusColor, string> = {
77
- live: "bg-green-500",
78
- draft: "bg-gray-400",
79
- archived: "bg-white border-gray-300",
80
- modified: "bg-orange-400",
77
+ live: "bg-status-live-text",
78
+ draft: "bg-status-draft-text",
79
+ archived: "bg-white border-status-draft-text",
80
+ modified: "bg-status-modified-text",
81
81
  };
82
82
 
83
83
 
@@ -0,0 +1,80 @@
1
+ import { useState, type FormEvent } from "react";
2
+ import { Plus } from "lucide-react";
3
+ import { cn } from "../../lib/cn";
4
+ import { tagDisplayLabel } from "../../lib/tags";
5
+ import type { TagEntry } from "../../schemas/tags";
6
+ import { IndicatorPill } from "./IndicatorPill";
7
+ import { PopoverItem } from "../shared/PopoverItem";
8
+ import { IconButton } from "../shared/IconButton";
9
+ import { CheckboxBox } from "../shared/Checkbox";
10
+
11
+ interface TagIndicatorProps {
12
+ /** The site's tag registry, already reconciled (siteTags). */
13
+ tags: TagEntry[];
14
+ /** The ids of the tags on this section. */
15
+ assignedIds: string[];
16
+ onToggle: (tagId: string, tagged: boolean) => void;
17
+ /** Create a tag from a typed name and put it on this section. */
18
+ onCreate: (label: string) => void;
19
+ /** Display-only mode — the pill still summarizes, but the picker never opens. */
20
+ disabled?: boolean;
21
+ }
22
+
23
+ export function TagIndicator({ tags, assignedIds, onToggle, onCreate, disabled }: TagIndicatorProps) {
24
+ const [draft, setDraft] = useState("");
25
+ const assigned = tags.filter((t) => assignedIds.includes(t.id));
26
+
27
+ const labelText = assigned.length === 0
28
+ ? "No tags"
29
+ : assigned.length === 1 ? tagDisplayLabel(assigned[0].label) : `${assigned.length} tags`;
30
+ const ariaSummary = assigned.length === 0 ? "none" : assigned.map((t) => tagDisplayLabel(t.label)).join(", ");
31
+
32
+ function submit(e: FormEvent) {
33
+ e.preventDefault();
34
+ const label = draft.trim();
35
+ if (!label) return;
36
+ onCreate(label);
37
+ setDraft("");
38
+ }
39
+
40
+ return (
41
+ <IndicatorPill
42
+ dots={[]}
43
+ label={labelText}
44
+ ariaLabel={`Tags: ${ariaSummary}`}
45
+ buttonClassName={assigned.length === 0 ? "text-base-contrast-light" : undefined}
46
+ disabled={disabled}
47
+ clickContent={
48
+ <div className="w-56 py-1">
49
+ {tags.length > 0 && (
50
+ <ul role="list" className="max-h-64 overflow-y-auto">
51
+ {tags.map((t) => {
52
+ const checked = assignedIds.includes(t.id);
53
+ return (
54
+ <li key={t.id}>
55
+ <PopoverItem role="checkbox" aria-checked={checked} onClick={() => onToggle(t.id, !checked)}>
56
+ <CheckboxBox checked={checked} />
57
+ <span className={cn("truncate font-medium text-base-contrast", !t.label && "italic text-base-contrast/60")}>
58
+ {tagDisplayLabel(t.label)}
59
+ </span>
60
+ </PopoverItem>
61
+ </li>
62
+ );
63
+ })}
64
+ </ul>
65
+ )}
66
+ <form onSubmit={submit} className={cn("flex items-center gap-1 px-3 py-1.5", tags.length > 0 && "border-t border-base-200")}>
67
+ <input
68
+ aria-label="New tag"
69
+ value={draft}
70
+ placeholder={tags.length > 0 ? "New tag" : "Create the first tag"}
71
+ onChange={(e) => setDraft(e.target.value)}
72
+ className="min-w-0 flex-1 rounded border border-base-200 bg-base px-2 py-1 text-xs text-base-contrast focus:border-base-contrast focus:outline-none"
73
+ />
74
+ <IconButton icon={<Plus size={14} />} label="Create tag" size="sm" type="submit" />
75
+ </form>
76
+ </div>
77
+ }
78
+ />
79
+ );
80
+ }
@@ -19,7 +19,7 @@ const isDocumentFile = (file: File) => file.type in DOCUMENT_MIME_TO_EXT;
19
19
  *
20
20
  * Deliberately thin on validation: every rejection (wrong type, too large, no
21
21
  * documents store) belongs to `uploadDocument`, which already routes typed copy
22
- * through the pipeline's `onUploadError` → `UploadRejectionAlert` channel. The
22
+ * through the pipeline's `onUploadError` → `InlineAlert` channel. The
23
23
  * one judgement made here is WHICH file of a multi-file drop to hand over.
24
24
  */
25
25
  export function DocumentDropZone({ onDocumentSelected, className }: DocumentDropZoneProps) {
@@ -1,11 +1,12 @@
1
1
  import { useRef, useEffect, useState, useId, type ReactNode } from "react";
2
- import { ImageIcon } from "lucide-react";
3
- import { AddIcon, DragHandle, DeleteIcon, SettingsIcon } from "../shared/icons";
2
+ import { ImageIcon, Plus, Trash2, Settings } from "lucide-react";
3
+ import { DragHandle } from "../shared/icons";
4
4
  import { IconButton } from "../shared/IconButton";
5
+ import { DropEdgeIndicator } from "../editor/DropEdgeIndicator";
5
6
  import { cn } from "../../lib/cn";
6
7
  import { containerGridClass } from "../../lib/container-grid";
7
8
  import { useEditableCollection } from "./useEditableCollection";
8
- import { resolveDropIndex } from "./gridDrop";
9
+ import { resolveDropIndex } from "./grid-drop";
9
10
 
10
11
  interface EditableGridProps<T> {
11
12
  items: T[];
@@ -166,7 +167,7 @@ export function EditableGrid<T>({
166
167
 
167
168
  {/* Add button — absolute, centered below the grid */}
168
169
  <IconButton
169
- icon={<AddIcon size={16} />}
170
+ icon={<Plus size={16} />}
170
171
  label="Add item"
171
172
  size="lg"
172
173
  intent="primary"
@@ -287,18 +288,18 @@ function GridCell<T>({
287
288
  isCellDragging && "opacity-50",
288
289
  )}
289
290
  >
290
- {/* Drop indicator — centered in the gap between cells */}
291
- {showLeftEdge && (
292
- <div className="absolute top-0 bottom-0 left-0 z-10 w-0.5 -translate-x-2 bg-primary" />
293
- )}
294
- {showRightEdge && (
295
- <div className="absolute top-0 right-0 bottom-0 z-10 w-0.5 translate-x-2 bg-primary" />
296
- )}
291
+ {/* Drop indicator — centered in the gap between cells. The gap is wider
292
+ here than DropEdgeIndicator's default gutter, so the offset goes
293
+ through `style`. */}
294
+ <DropEdgeIndicator
295
+ edge={showLeftEdge ? "left" : showRightEdge ? "right" : null}
296
+ style={{ transform: showLeftEdge ? "translateX(-0.5rem)" : "translateX(0.5rem)" }}
297
+ />
297
298
 
298
299
  {/* Insert button — centered in the gap between cells */}
299
300
  {!isDragging && !isLast && (
300
301
  <IconButton
301
- icon={<AddIcon size={12} />}
302
+ icon={<Plus size={12} />}
302
303
  label="Insert item"
303
304
  size="sm"
304
305
  intent="primary"
@@ -328,14 +329,14 @@ function GridCell<T>({
328
329
  )}
329
330
  {onSettings && (
330
331
  <IconButton
331
- icon={<SettingsIcon size={16} />}
332
+ icon={<Settings size={16} />}
332
333
  label="Item settings"
333
334
  onClick={onSettings}
334
335
  className="bg-base/80 shadow-sm"
335
336
  />
336
337
  )}
337
338
  <IconButton
338
- icon={<DeleteIcon size={16} />}
339
+ icon={<Trash2 size={16} />}
339
340
  label="Delete item"
340
341
  intent="destructive"
341
342
  onClick={() => onRemove(id)}