@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
package/src/lib/loader.ts CHANGED
@@ -3,52 +3,38 @@ import { IndexSchema, type SiteIndex, type SectionMeta } from "../schemas/site-c
3
3
  import { getAllSchemas } from "./registry";
4
4
  import { blockDepth, MAX_BLOCK_DEPTH } from "../schemas/block";
5
5
  import { upgradeLegacySection } from "./migrate-sections-transform";
6
- import { NavEntrySchema, type NavEntry } from "../schemas/nav";
6
+ import type { NavEntry } from "../schemas/nav";
7
+ import type { TagEntry } from "../schemas/tags";
8
+ import type { SidecarRead } from "./sidecars";
7
9
 
8
10
  export interface LoadedSection {
9
11
  section: Section;
10
12
  meta: SectionMeta;
13
+ /** Set only on render-time copies a Reference pulled in (resolveReference):
14
+ * the id of that Reference. Never loaded or persisted. */
15
+ referencedBy?: string;
11
16
  }
12
17
 
13
18
  export interface SiteContent {
14
19
  sections: LoadedSection[];
15
20
  index: SiteIndex;
16
- /** True when nav.json was present but held entries this package version could
17
- * not represent (unknown kinds, invalid shapes) — the returned nav is missing
18
- * them. Writers must treat a degraded nav as read-only: wholesale-replacing
19
- * nav.json from a degraded read permanently destroys the entries this
20
- * version dropped. */
21
+ /** A Degraded read of nav.json (see SidecarRead): the returned nav is missing
22
+ * entries, so writers treat it as read-only — wholesale-replacing nav.json
23
+ * from it permanently destroys the entries this version dropped. */
21
24
  navDegraded: boolean;
25
+ /** Same contract as navDegraded, for tags.json: a degraded read is
26
+ * read-only for tags. */
27
+ tagsDegraded: boolean;
22
28
  }
23
29
 
24
30
  /**
25
- * Parse the nav.json sidecar defensively, entry by entry. A malformed sidecar
26
- * must degrade, never brick the site — nav.json is optional content, and the
27
- * whole point of the sidecar is that it tolerates writers that don't understand
28
- * it. Tolerance is PER ENTRY: one unknown entry kind (a newer package version's
29
- * addition, or an authoring typo) drops that entry alone, not every group on
30
- * the site. Any drop is reported as `degraded` so write paths can refuse to
31
- * persist the lossy tree back over the original.
31
+ * The Sidecars a load read, from the Sidecar module's readers. A Sidecar the
32
+ * load did not look for is omitted. Tags then stay unattached ("not loaded":
33
+ * writers leave tags.json alone, where an attached `[]` saved back would delete
34
+ * every tag). Nav is attached as `[]` either way — the editor has no nav gate
35
+ * yet to make "not loaded" safe for nav (exploration B).
32
36
  */
33
- function parseNavFile(navFile: unknown): { entries: NavEntry[]; degraded: boolean } {
34
- if (!navFile) return { entries: [], degraded: false };
35
- const rawEntries = (navFile as { entries?: unknown }).entries;
36
- if (!Array.isArray(rawEntries)) {
37
- console.warn("Invalid nav.json, falling back to a flat navigation");
38
- return { entries: [], degraded: true };
39
- }
40
- const entries: NavEntry[] = [];
41
- let dropped = 0;
42
- for (const raw of rawEntries) {
43
- const result = NavEntrySchema.safeParse(raw);
44
- if (result.success) entries.push(result.data);
45
- else dropped++;
46
- }
47
- if (dropped > 0) {
48
- console.warn(`nav.json: dropped ${dropped} entr${dropped === 1 ? "y" : "ies"} this package version cannot represent; navigation is degraded`);
49
- }
50
- return { entries, degraded: dropped > 0 };
51
- }
37
+ export type SidecarReads = { nav?: SidecarRead<NavEntry>; tags?: SidecarRead<TagEntry> };
52
38
 
53
39
  /**
54
40
  * Merge a validated index with raw section file contents.
@@ -58,7 +44,7 @@ function parseNavFile(navFile: unknown): { entries: NavEntry[]; degraded: boolea
58
44
  export function mergeSiteContent(
59
45
  index: SiteIndex,
60
46
  sectionFiles: Record<string, unknown>,
61
- navFile?: unknown,
47
+ sidecars: SidecarReads = {},
62
48
  ): SiteContent {
63
49
  const sections: LoadedSection[] = [];
64
50
 
@@ -111,8 +97,13 @@ export function mergeSiteContent(
111
97
  }
112
98
  }
113
99
 
114
- const nav = parseNavFile(navFile);
115
- return { sections, index: { ...index, nav: nav.entries }, navDegraded: nav.degraded };
100
+ const { nav, tags } = sidecars;
101
+ return {
102
+ sections,
103
+ index: { ...index, nav: nav?.entries ?? [], ...(tags ? { tags: tags.entries } : {}) },
104
+ navDegraded: nav?.degraded ?? false,
105
+ tagsDegraded: tags?.degraded ?? false,
106
+ };
116
107
  }
117
108
 
118
109
  /**
@@ -123,7 +114,7 @@ export function mergeSiteContent(
123
114
  export function loadStaticSiteContent(
124
115
  index: SiteIndex,
125
116
  sectionGlob: Record<string, unknown>,
126
- navFile?: unknown,
117
+ sidecars: SidecarReads = {},
127
118
  ): SiteContent {
128
119
  const sectionFiles: Record<string, unknown> = {};
129
120
  for (const [path, data] of Object.entries(sectionGlob)) {
@@ -131,56 +122,5 @@ export function loadStaticSiteContent(
131
122
  const id = filename.replace(".json", "");
132
123
  sectionFiles[id] = data;
133
124
  }
134
- return mergeSiteContent(index, sectionFiles, navFile);
135
- }
136
-
137
- /**
138
- * Load site content from the filesystem.
139
- * For use in scripts and tests — Astro pages should use import.meta.glob instead.
140
- */
141
- export async function loadSiteContent(contentDir: string): Promise<SiteContent> {
142
- const fs = await import("node:fs/promises");
143
- const path = await import("node:path");
144
-
145
- const indexPath = path.join(contentDir, "index.json");
146
- const indexRaw = JSON.parse(await fs.readFile(indexPath, "utf-8"));
147
- const index = IndexSchema.parse(indexRaw);
148
-
149
- const sectionFiles: Record<string, unknown> = {};
150
- for (const id of index.pages.flatMap((p: SiteIndex["pages"][number]) => p.order)) {
151
- const sectionPath = path.join(contentDir, "sections", `${id}.json`);
152
- sectionFiles[id] = JSON.parse(await fs.readFile(sectionPath, "utf-8"));
153
- }
154
-
155
- // nav.json is an optional sidecar — absent (every portal predating page
156
- // groups) or unreadable must degrade to a flat nav, never fail the load.
157
- //
158
- // ABSENT and UNREADABLE are not the same answer, though: absent is the normal
159
- // case and safe to overwrite, while a present-but-unparseable sidecar holds
160
- // groups this load cannot see. Collapsing both to `undefined` reported
161
- // navDegraded: false, so the next nav-touching save wholesale-wrote a flat
162
- // nav.json over a file that was still hand-recoverable. Mirrors the
163
- // GitHub-backed loader's navRaw/navFile split in @drawnagency/core.
164
- let navRaw: string | undefined;
165
- let readFailed = false;
166
- try {
167
- navRaw = await fs.readFile(path.join(contentDir, "nav.json"), "utf-8");
168
- } catch (err) {
169
- // Only a genuinely missing file is "absent". A permissions/IO error leaves
170
- // the sidecar's contents unknown, which must not license overwriting it.
171
- readFailed = (err as { code?: string })?.code !== "ENOENT";
172
- }
173
-
174
- let navFile: unknown;
175
- let parseFailed = false;
176
- if (navRaw !== undefined) {
177
- try {
178
- navFile = JSON.parse(navRaw);
179
- } catch {
180
- parseFailed = true;
181
- }
182
- }
183
-
184
- const content = mergeSiteContent(index, sectionFiles, navFile);
185
- return readFailed || parseFailed ? { ...content, navDegraded: true } : content;
125
+ return mergeSiteContent(index, sectionFiles, sidecars);
186
126
  }
@@ -0,0 +1,112 @@
1
+ import type { MediaItem, MediaManifest } from "../schemas/media";
2
+ import type { DocumentManifest, DocumentManifestEntry } from "../schemas/documents";
3
+
4
+ // Media intents (CONTEXT.md: Index op / Media intent): a change to the media
5
+ // library stated as what to do, applied by the write path to its own fresh read
6
+ // of the manifests. A writer that sent a whole manifest instead could only
7
+ // send back what it had read — dropping another writer's images, or `folders`,
8
+ // the moment its copy was stale. Intents leave everything they do not name as
9
+ // the branch has it. Pure: the write path does the reads and the commit.
10
+
11
+ export type MediaBlob = { path: string; base64: string };
12
+
13
+ export type MediaOp =
14
+ /**
15
+ * A new image and its variant files, keyed by its id (the content hash).
16
+ * `alt` is the caller's alt text, if it sent one — the only alt applied when
17
+ * the image turns out to be in the library already (`entry.alt` is just the
18
+ * new entry's default).
19
+ */
20
+ | { op: "addImage"; entry: MediaItem; blobs: MediaBlob[]; alt?: string }
21
+ | { op: "setImageAlt"; imageId: string; alt: string }
22
+ | { op: "deleteImage"; imageId: string }
23
+ /**
24
+ * A document's manifest entry, with its bytes when they ride in the commit
25
+ * (git tier; bucket-tier bytes are uploaded beforehand). For an id already in
26
+ * the library — git-tier ids are the content hash, so the same bytes — only
27
+ * the filename is applied: its stored bytes and path stay. That is how a
28
+ * rename lands.
29
+ */
30
+ | { op: "putDocument"; documentId: string; entry: DocumentManifestEntry; blob?: MediaBlob };
31
+
32
+ /**
33
+ * Per op, in order. `existed` means `addImage` found the image already in the
34
+ * library: its bytes are not committed again, and only a differing alt text is
35
+ * applied.
36
+ */
37
+ export type MediaOpOutcome = "added" | "existed" | "updated" | "deleted";
38
+
39
+ export type AppliedMediaOps = {
40
+ ok: true;
41
+ images: MediaManifest;
42
+ /** Null when no op touched documents, so the write leaves that file alone. */
43
+ documents: DocumentManifest | null;
44
+ uploads: { item: { id: string; folder: string }; blobs: MediaBlob[] }[];
45
+ /** Images whose variant folders the write deletes. */
46
+ deletions: { id: string; folder: string }[];
47
+ outcomes: MediaOpOutcome[];
48
+ };
49
+
50
+ export function applyMediaOps(
51
+ manifests: { images: MediaManifest; documents: DocumentManifest },
52
+ ops: MediaOp[],
53
+ ): AppliedMediaOps | { ok: false; code: "not_found"; error: string } {
54
+ const images: MediaManifest = { ...manifests.images, images: { ...manifests.images.images } };
55
+ let documents: DocumentManifest | null = null;
56
+ const uploads: AppliedMediaOps["uploads"] = [];
57
+ const deletions: AppliedMediaOps["deletions"] = [];
58
+ const outcomes: MediaOpOutcome[] = [];
59
+
60
+ // Keys are content hashes and normally equal the entry's id; find by id so a
61
+ // caller naming the id it was given always reaches the right entry.
62
+ const keyOf = (imageId: string) =>
63
+ imageId in images.images ? imageId : Object.keys(images.images).find((key) => images.images[key].id === imageId);
64
+ const notFound = (imageId: string) =>
65
+ ({ ok: false, code: "not_found", error: `No media with imageId "${imageId}" in the site's media library.` }) as const;
66
+
67
+ for (const op of ops) {
68
+ switch (op.op) {
69
+ case "addImage": {
70
+ const key = keyOf(op.entry.id);
71
+ if (key === undefined) {
72
+ images.images[op.entry.id] = op.entry;
73
+ uploads.push({ item: { id: op.entry.id, folder: op.entry.folder }, blobs: op.blobs });
74
+ outcomes.push("added");
75
+ } else {
76
+ if (op.alt !== undefined) images.images[key] = { ...images.images[key], alt: op.alt };
77
+ outcomes.push("existed");
78
+ }
79
+ break;
80
+ }
81
+ case "setImageAlt": {
82
+ const key = keyOf(op.imageId);
83
+ if (key === undefined) return notFound(op.imageId);
84
+ images.images[key] = { ...images.images[key], alt: op.alt };
85
+ outcomes.push("updated");
86
+ break;
87
+ }
88
+ case "deleteImage": {
89
+ const key = keyOf(op.imageId);
90
+ if (key === undefined) return notFound(op.imageId);
91
+ deletions.push({ id: key, folder: images.images[key].folder });
92
+ delete images.images[key];
93
+ outcomes.push("deleted");
94
+ break;
95
+ }
96
+ case "putDocument": {
97
+ documents ??= { ...manifests.documents };
98
+ const existing = documents[op.documentId];
99
+ if (existing) {
100
+ documents[op.documentId] = { ...existing, filename: op.entry.filename };
101
+ outcomes.push(existing.filename === op.entry.filename ? "existed" : "updated");
102
+ } else {
103
+ documents[op.documentId] = op.entry;
104
+ if (op.blob) uploads.push({ item: { id: op.documentId, folder: op.blob.path.split("/")[2] ?? "" }, blobs: [op.blob] });
105
+ outcomes.push("added");
106
+ }
107
+ break;
108
+ }
109
+ }
110
+ }
111
+ return { ok: true, images, documents, uploads, deletions, outcomes };
112
+ }
@@ -1,5 +1,6 @@
1
1
  import type { NavEntry, NavGroupEntry } from "../schemas/nav";
2
2
  import type { Page, SiteIndex } from "../schemas/site-config";
3
+ import { diagnosticsCollector, type SidecarDiagnostic } from "./sidecar-diagnostics";
3
4
 
4
5
  /**
5
6
  * Repair an authored nav against the current page set.
@@ -19,6 +20,15 @@ import type { Page, SiteIndex } from "../schemas/site-config";
19
20
  * prior state and defeat identity-based re-render checks.
20
21
  */
21
22
  export function reconcileNav(entries: NavEntry[], pages: Page[]): NavEntry[] {
23
+ return reconcileNavReport(entries, pages).entries;
24
+ }
25
+
26
+ /** reconcileNav plus what the repair changed — what a validator reports. */
27
+ export function reconcileNavReport(
28
+ entries: NavEntry[],
29
+ pages: Page[],
30
+ ): { entries: NavEntry[]; diagnostics: SidecarDiagnostic[] } {
31
+ const report = diagnosticsCollector();
22
32
  const entryList = Array.isArray(entries) ? entries : [];
23
33
  const pageList = Array.isArray(pages) ? pages : [];
24
34
 
@@ -33,7 +43,14 @@ export function reconcileNav(entries: NavEntry[], pages: Page[]): NavEntry[] {
33
43
 
34
44
  for (const entry of entryList) {
35
45
  if (entry?.kind === "page") {
36
- if (!validIds.has(entry.pageId) || placed.has(entry.pageId)) continue;
46
+ if (!validIds.has(entry.pageId)) {
47
+ report.add("dangling", entry.pageId);
48
+ continue;
49
+ }
50
+ if (placed.has(entry.pageId)) {
51
+ report.add("duplicate-member", entry.pageId);
52
+ continue;
53
+ }
37
54
  placed.add(entry.pageId);
38
55
  result.push({ ...entry });
39
56
  continue;
@@ -46,12 +63,23 @@ export function reconcileNav(entries: NavEntry[], pages: Page[]): NavEntry[] {
46
63
  // and "total" would be a lie. Dropping it spills its members to the tail
47
64
  // append below: a group lost, never a page.
48
65
  if (typeof entry.id !== "string" || entry.id === "") continue;
49
- if (seenGroupIds.has(entry.id)) continue;
66
+ if (seenGroupIds.has(entry.id)) {
67
+ report.add("duplicate-id", entry.id);
68
+ continue;
69
+ }
50
70
  seenGroupIds.add(entry.id);
51
71
 
52
72
  const claimed = Array.isArray(entry.pageIds) ? entry.pageIds : [];
53
73
  const pageIds = claimed.filter((id) => {
54
- if (typeof id !== "string" || !validIds.has(id) || placed.has(id)) return false;
74
+ if (typeof id !== "string") return false;
75
+ if (!validIds.has(id)) {
76
+ report.add("dangling", id);
77
+ return false;
78
+ }
79
+ if (placed.has(id)) {
80
+ report.add("duplicate-member", id);
81
+ return false;
82
+ }
55
83
  placed.add(id);
56
84
  return true;
57
85
  });
@@ -70,10 +98,11 @@ export function reconcileNav(entries: NavEntry[], pages: Page[]): NavEntry[] {
70
98
  for (const p of pageList) {
71
99
  if (!p?.id || placed.has(p.id)) continue;
72
100
  placed.add(p.id);
101
+ report.add("unlisted", p.id);
73
102
  result.push({ kind: "page", pageId: p.id });
74
103
  }
75
104
 
76
- return result;
105
+ return { entries: result, diagnostics: report.list() };
77
106
  }
78
107
 
79
108
  /**
@@ -204,3 +233,74 @@ export function moveNavEntry(index: SiteIndex, from: NavLocation, to: NavLocatio
204
233
 
205
234
  return withNav(index, entries);
206
235
  }
236
+
237
+ /**
238
+ * "Moved <label> to position N of M" for the aria-live reorder announcement,
239
+ * covering both `moveNavEntry` callers: drag (PagesModal/NavGroupRow) and the
240
+ * Move up/down buttons. `prevIndex` resolves WHO moved and its label (read
241
+ * before the move, since `from` is a position, not an id); `nextIndex` (the
242
+ * result of `moveNavEntry(prevIndex, from, to)`) is searched by id for where
243
+ * it actually landed — robust to `moveNavEntry`'s own clamping, so the caller
244
+ * never has to replicate that math. Returns null if `from` didn't resolve to
245
+ * a real row (defensive; ordinary callers always pass a live location).
246
+ */
247
+ /** A top-level entry counts toward "N of M" iff it's a group (always visible)
248
+ * or a page that isn't archived — mirrors the PagesModal Move up/down rows,
249
+ * which skip archived pages entirely rather than render an inert slot. */
250
+ function isLiveTopEntry(index: SiteIndex, entry: NavEntry): boolean {
251
+ if (entry.kind === "group") return true;
252
+ const page = index.pages.find((p) => p.id === entry.pageId);
253
+ return page?.status === "live";
254
+ }
255
+
256
+ export function describeNavMove(prevIndex: SiteIndex, nextIndex: SiteIndex, from: NavLocation): string | null {
257
+ const prevEntries = navEntries(prevIndex);
258
+ let label: string;
259
+ let pageId: string | null = null;
260
+ let groupId: string | null = null;
261
+
262
+ if (from.groupId === null) {
263
+ const entry = prevEntries[from.index];
264
+ if (!entry) return null;
265
+ if (entry.kind === "group") {
266
+ label = groupDisplayLabel(entry.label);
267
+ groupId = entry.id;
268
+ } else {
269
+ const page = prevIndex.pages.find((p) => p.id === entry.pageId);
270
+ if (!page) return null;
271
+ label = page.title || "Untitled";
272
+ pageId = page.id;
273
+ }
274
+ } else {
275
+ const group = prevEntries.find((e) => e.kind === "group" && e.id === from.groupId);
276
+ if (!group || group.kind !== "group") return null;
277
+ const id = group.pageIds[from.index];
278
+ if (!id) return null;
279
+ const page = prevIndex.pages.find((p) => p.id === id);
280
+ if (!page) return null;
281
+ label = page.title || "Untitled";
282
+ pageId = page.id;
283
+ }
284
+
285
+ const nextEntries = navEntries(nextIndex);
286
+ const liveTopEntries = nextEntries.filter((e) => isLiveTopEntry(nextIndex, e));
287
+
288
+ if (groupId !== null) {
289
+ const i = liveTopEntries.findIndex((e) => e.kind === "group" && e.id === groupId);
290
+ if (i === -1) return null;
291
+ return `Moved ${label} to position ${i + 1} of ${liveTopEntries.length}`;
292
+ }
293
+
294
+ if (pageId === null) return null;
295
+
296
+ const topIndex = liveTopEntries.findIndex((e) => e.kind === "page" && e.pageId === pageId);
297
+ if (topIndex !== -1) return `Moved ${label} to position ${topIndex + 1} of ${liveTopEntries.length}`;
298
+ for (const e of nextEntries) {
299
+ if (e.kind === "group") {
300
+ const liveMemberIds = e.pageIds.filter((id) => nextIndex.pages.find((p) => p.id === id)?.status === "live");
301
+ const gi = liveMemberIds.indexOf(pageId);
302
+ if (gi !== -1) return `Moved ${label} to position ${gi + 1} of ${liveMemberIds.length}`;
303
+ }
304
+ }
305
+ return null;
306
+ }