@drawnagency/primitives 0.1.113 → 0.1.114

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (483) hide show
  1. package/README.md +1 -1
  2. package/dist/auth/cookies.d.ts +39 -0
  3. package/dist/auth/cookies.d.ts.map +1 -1
  4. package/dist/auth/index.js +3 -3
  5. package/dist/{chunk-GPPVYLEI.js → chunk-45FA7Z55.js} +1 -1
  6. package/dist/{chunk-REDDTTGJ.js → chunk-4Y2JQQZL.js} +19 -1
  7. package/dist/chunk-5GFACGSN.js +6 -0
  8. package/dist/chunk-5KSAS4VY.js +275 -0
  9. package/dist/{chunk-Z7W3DQTR.js → chunk-7SAAJVDE.js} +408 -28
  10. package/dist/{chunk-S2L3BPLS.js → chunk-7SX42OP4.js} +1 -1
  11. package/dist/{chunk-GGXZZ77Z.js → chunk-AASEGXNT.js} +18 -1
  12. package/dist/{chunk-WKZ7OENC.js → chunk-BQ5TZZUE.js} +5 -1
  13. package/dist/chunk-DIMDRBFK.js +11 -0
  14. package/dist/{chunk-WUJ3XNFI.js → chunk-GGYY3JQJ.js} +19 -24
  15. package/dist/{chunk-NHN2LSIU.js → chunk-IP2SEBAJ.js} +5 -1
  16. package/dist/{chunk-IINIZBQB.js → chunk-JCDZAFX2.js} +30 -10
  17. package/dist/chunk-JR24U7FJ.js +120 -0
  18. package/dist/{chunk-SW6PCQQD.js → chunk-KQA772WQ.js} +2 -1
  19. package/dist/{chunk-KR2MHTNJ.js → chunk-N3G7DOU3.js} +609 -61
  20. package/dist/chunk-OAGJBCSH.js +67 -0
  21. package/dist/{chunk-6BZ2KNTP.js → chunk-PLANHXS7.js} +191 -61
  22. package/dist/{chunk-VWWY5TL5.js → chunk-PNSCDBU7.js} +38 -56
  23. package/dist/{chunk-AHALSCQH.js → chunk-PTY2RG2K.js} +1 -1
  24. package/dist/{chunk-BDFTMGCL.js → chunk-PZPGJZRG.js} +9 -8
  25. package/dist/{chunk-FRE2CCLV.js → chunk-QHMKIODQ.js} +17 -4
  26. package/dist/{chunk-HBULBDGP.js → chunk-S37DZPHW.js} +1 -1
  27. package/dist/{chunk-4I5OO5UB.js → chunk-TEOAKGZA.js} +0 -1
  28. package/dist/chunk-VUYCRBJK.js +174 -0
  29. package/dist/{chunk-4RNF2DRG.js → chunk-XDEPXTBY.js} +0 -2
  30. package/dist/{chunk-DS4GCYV2.js → chunk-Y5QECJX7.js} +223 -16
  31. package/dist/collab/rebase.d.ts +2 -1
  32. package/dist/collab/rebase.d.ts.map +1 -1
  33. package/dist/collab/rebase.js +20 -5
  34. package/dist/components/brandguide/ColorsEditable.d.ts.map +1 -1
  35. package/dist/components/chat/ChatPanel.d.ts.map +1 -1
  36. package/dist/components/chat/ChatWidget.d.ts.map +1 -1
  37. package/dist/components/docfile/DocFilePane.d.ts.map +1 -1
  38. package/dist/components/editor/ChildBlockWrapper.d.ts.map +1 -1
  39. package/dist/components/editor/ConflictDialog.d.ts.map +1 -1
  40. package/dist/components/editor/DragHandle.d.ts +12 -2
  41. package/dist/components/editor/DragHandle.d.ts.map +1 -1
  42. package/dist/components/editor/DropEdgeIndicator.d.ts +15 -6
  43. package/dist/components/editor/DropEdgeIndicator.d.ts.map +1 -1
  44. package/dist/components/editor/NavGroupRow.d.ts +4 -1
  45. package/dist/components/editor/NavGroupRow.d.ts.map +1 -1
  46. package/dist/components/editor/PagesModal.d.ts.map +1 -1
  47. package/dist/components/editor/SectionWrapper.d.ts +1 -1
  48. package/dist/components/editor/SectionWrapper.d.ts.map +1 -1
  49. package/dist/components/editor/SettingsForm.d.ts.map +1 -1
  50. package/dist/components/editor/TagIndicator.d.ts +15 -0
  51. package/dist/components/editor/TagIndicator.d.ts.map +1 -0
  52. package/dist/components/editor/index.js +148 -77
  53. package/dist/components/primitives/DocumentDropZone.d.ts +1 -1
  54. package/dist/components/primitives/EditableGrid.d.ts.map +1 -1
  55. package/dist/components/primitives/EditableList.d.ts.map +1 -1
  56. package/dist/components/primitives/HeadingSection.d.ts +4 -1
  57. package/dist/components/primitives/HeadingSection.d.ts.map +1 -1
  58. package/dist/components/primitives/ResolvedMedia.d.ts +5 -1
  59. package/dist/components/primitives/ResolvedMedia.d.ts.map +1 -1
  60. package/dist/components/primitives/{defineHeadingSection.d.ts → define-heading-section.d.ts} +1 -1
  61. package/dist/components/primitives/define-heading-section.d.ts.map +1 -0
  62. package/dist/components/primitives/{gridDrop.d.ts → grid-drop.d.ts} +1 -1
  63. package/dist/components/primitives/grid-drop.d.ts.map +1 -0
  64. package/dist/components/primitives/index.d.ts +1 -1
  65. package/dist/components/primitives/index.d.ts.map +1 -1
  66. package/dist/components/primitives/index.js +17 -154
  67. package/dist/components/sections/Button/CTAButton.d.ts.map +1 -1
  68. package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts +2 -6
  69. package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts.map +1 -1
  70. package/dist/components/sections/DoDontMedia/index.d.ts +8 -0
  71. package/dist/components/sections/DoDontMedia/index.d.ts.map +1 -1
  72. package/dist/components/sections/IconList/IconList.d.ts +2 -1
  73. package/dist/components/sections/IconList/IconList.d.ts.map +1 -1
  74. package/dist/components/sections/IconList/IconListSettings.d.ts +2 -1
  75. package/dist/components/sections/IconList/IconListSettings.d.ts.map +1 -1
  76. package/dist/components/sections/IconList/index.d.ts +1 -0
  77. package/dist/components/sections/IconList/index.d.ts.map +1 -1
  78. package/dist/components/sections/Media/MediaBlock.d.ts +2 -1
  79. package/dist/components/sections/Media/MediaBlock.d.ts.map +1 -1
  80. package/dist/components/sections/Media/index.d.ts +8 -0
  81. package/dist/components/sections/Media/index.d.ts.map +1 -1
  82. package/dist/components/sections/Reference/ReferenceList.d.ts +35 -0
  83. package/dist/components/sections/Reference/ReferenceList.d.ts.map +1 -0
  84. package/dist/components/sections/Reference/ReferenceSettings.d.ts +12 -0
  85. package/dist/components/sections/Reference/ReferenceSettings.d.ts.map +1 -0
  86. package/dist/components/sections/Reference/index.d.ts +9 -0
  87. package/dist/components/sections/Reference/index.d.ts.map +1 -0
  88. package/dist/components/sections/SectionSummary/SectionSummaryBlock.d.ts +38 -0
  89. package/dist/components/sections/SectionSummary/SectionSummaryBlock.d.ts.map +1 -0
  90. package/dist/components/sections/SectionSummary/SectionSummarySettings.d.ts +20 -0
  91. package/dist/components/sections/SectionSummary/SectionSummarySettings.d.ts.map +1 -0
  92. package/dist/components/sections/SectionSummary/index.d.ts +33 -0
  93. package/dist/components/sections/SectionSummary/index.d.ts.map +1 -0
  94. package/dist/components/sections/all-sections.d.ts +53 -0
  95. package/dist/components/sections/all-sections.d.ts.map +1 -1
  96. package/dist/components/sections/brand-guide.d.ts +41 -2
  97. package/dist/components/sections/brand-guide.d.ts.map +1 -1
  98. package/dist/components/sections/brand-guide.js +12 -10
  99. package/dist/components/sections/core-sections.d.ts +14 -0
  100. package/dist/components/sections/core-sections.d.ts.map +1 -1
  101. package/dist/components/sections/register-schemas.js +19 -17
  102. package/dist/components/sections/register.js +19 -17
  103. package/dist/components/shared/BrandSwatchesContext.d.ts +9 -0
  104. package/dist/components/shared/BrandSwatchesContext.d.ts.map +1 -0
  105. package/dist/components/shared/Button.d.ts +11 -3
  106. package/dist/components/shared/Button.d.ts.map +1 -1
  107. package/dist/components/shared/Checkbox.d.ts +6 -0
  108. package/dist/components/shared/Checkbox.d.ts.map +1 -1
  109. package/dist/components/shared/ConfirmDialog.d.ts +25 -0
  110. package/dist/components/shared/ConfirmDialog.d.ts.map +1 -0
  111. package/dist/components/shared/ConfirmInline.d.ts +25 -0
  112. package/dist/components/shared/ConfirmInline.d.ts.map +1 -0
  113. package/dist/components/shared/ErrorBoundary.d.ts.map +1 -1
  114. package/dist/components/shared/Fab.d.ts +11 -2
  115. package/dist/components/shared/Fab.d.ts.map +1 -1
  116. package/dist/components/shared/FabStack.d.ts +22 -0
  117. package/dist/components/shared/FabStack.d.ts.map +1 -0
  118. package/dist/components/shared/HistoryChangesModal.d.ts.map +1 -1
  119. package/dist/components/shared/HistoryPopover.d.ts.map +1 -1
  120. package/dist/components/shared/ImageBackgroundField.d.ts +9 -0
  121. package/dist/components/shared/ImageBackgroundField.d.ts.map +1 -0
  122. package/dist/components/shared/{UploadRejectionAlert.d.ts → InlineAlert.d.ts} +4 -2
  123. package/dist/components/shared/InlineAlert.d.ts.map +1 -0
  124. package/dist/components/shared/Input.d.ts +10 -0
  125. package/dist/components/shared/Input.d.ts.map +1 -1
  126. package/dist/components/shared/Navigation.d.ts.map +1 -1
  127. package/dist/components/shared/Notice.d.ts +10 -0
  128. package/dist/components/shared/Notice.d.ts.map +1 -0
  129. package/dist/components/shared/Popover.d.ts.map +1 -1
  130. package/dist/components/shared/ReferenceSourcesContext.d.ts +25 -0
  131. package/dist/components/shared/ReferenceSourcesContext.d.ts.map +1 -0
  132. package/dist/components/shared/Select.d.ts +3 -2
  133. package/dist/components/shared/Select.d.ts.map +1 -1
  134. package/dist/components/shared/SplitButton.d.ts.map +1 -1
  135. package/dist/components/shared/SummaryAnchorsContext.d.ts +10 -0
  136. package/dist/components/shared/SummaryAnchorsContext.d.ts.map +1 -0
  137. package/dist/components/shared/Textarea.d.ts +7 -0
  138. package/dist/components/shared/Textarea.d.ts.map +1 -1
  139. package/dist/components/shared/ToolbarFrame.d.ts +17 -0
  140. package/dist/components/shared/ToolbarFrame.d.ts.map +1 -0
  141. package/dist/components/shared/copy.d.ts +13 -0
  142. package/dist/components/shared/copy.d.ts.map +1 -0
  143. package/dist/components/shared/icons.d.ts +0 -12
  144. package/dist/components/shared/icons.d.ts.map +1 -1
  145. package/dist/components/shell/AudienceDetailsPanel.d.ts +7 -1
  146. package/dist/components/shell/AudienceDetailsPanel.d.ts.map +1 -1
  147. package/dist/components/shell/AudienceRow.d.ts.map +1 -1
  148. package/dist/components/shell/BugReportFAB.d.ts +7 -1
  149. package/dist/components/shell/BugReportFAB.d.ts.map +1 -1
  150. package/dist/components/shell/CredentialList.d.ts.map +1 -1
  151. package/dist/components/shell/DocInspector.d.ts.map +1 -1
  152. package/dist/components/shell/DocumentEditorOverlay.d.ts.map +1 -1
  153. package/dist/components/shell/EditorContext.d.ts +4 -0
  154. package/dist/components/shell/EditorContext.d.ts.map +1 -1
  155. package/dist/components/shell/EditorLoginForm.d.ts.map +1 -1
  156. package/dist/components/shell/EditorModal.d.ts.map +1 -1
  157. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  158. package/dist/components/shell/HistoryToolbar.d.ts.map +1 -1
  159. package/dist/components/shell/MediaFolderTile.d.ts +4 -1
  160. package/dist/components/shell/MediaFolderTile.d.ts.map +1 -1
  161. package/dist/components/shell/MediaLibraryModal.d.ts.map +1 -1
  162. package/dist/components/shell/RestoreModal.d.ts.map +1 -1
  163. package/dist/components/shell/SiteSettingsChatbot.d.ts.map +1 -1
  164. package/dist/components/shell/SiteSettingsDisplay.d.ts.map +1 -1
  165. package/dist/components/shell/SiteSettingsModal.d.ts +3 -1
  166. package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
  167. package/dist/components/shell/SiteSettingsTags.d.ts +13 -0
  168. package/dist/components/shell/SiteSettingsTags.d.ts.map +1 -0
  169. package/dist/components/shell/SiteSettingsUsers.d.ts.map +1 -1
  170. package/dist/components/shell/ViewerLoginForm.d.ts.map +1 -1
  171. package/dist/components/shell/{blockMoveDispatch.d.ts → block-move-dispatch.d.ts} +1 -1
  172. package/dist/components/shell/block-move-dispatch.d.ts.map +1 -0
  173. package/dist/components/shell/reference-sources.d.ts +22 -0
  174. package/dist/components/shell/reference-sources.d.ts.map +1 -0
  175. package/dist/deck/index.d.ts +2 -2
  176. package/dist/deck/index.d.ts.map +1 -1
  177. package/dist/deck/index.js +1 -3
  178. package/dist/deck-builder/index.js +11 -18
  179. package/dist/document/index.d.ts +2 -2
  180. package/dist/document/index.d.ts.map +1 -1
  181. package/dist/hooks/useBlockDnd.d.ts +11 -0
  182. package/dist/hooks/useBlockDnd.d.ts.map +1 -1
  183. package/dist/hooks/useBuildStatus.d.ts +1 -1
  184. package/dist/hooks/useBuildStatus.d.ts.map +1 -1
  185. package/dist/hooks/useDocumentUploads.d.ts +1 -1
  186. package/dist/hooks/useDocumentUploads.d.ts.map +1 -1
  187. package/dist/hooks/useEditorPersistence.d.ts +5 -1
  188. package/dist/hooks/useEditorPersistence.d.ts.map +1 -1
  189. package/dist/hooks/useEditorPublish.d.ts +2 -2
  190. package/dist/hooks/useEditorPublish.d.ts.map +1 -1
  191. package/dist/hooks/useNotice.d.ts +19 -0
  192. package/dist/hooks/useNotice.d.ts.map +1 -0
  193. package/dist/hooks/useSortableNavRow.d.ts +11 -0
  194. package/dist/hooks/useSortableNavRow.d.ts.map +1 -1
  195. package/dist/hooks/useSortableRow.d.ts +11 -0
  196. package/dist/hooks/useSortableRow.d.ts.map +1 -1
  197. package/dist/hooks/useStackedEscape.d.ts +32 -0
  198. package/dist/hooks/useStackedEscape.d.ts.map +1 -0
  199. package/dist/index.js +67 -49
  200. package/dist/lib/audience-secret.js +2 -2
  201. package/dist/lib/block-dnd.d.ts +5 -0
  202. package/dist/lib/block-dnd.d.ts.map +1 -1
  203. package/dist/lib/block-move.d.ts.map +1 -1
  204. package/dist/lib/brand-swatches.d.ts +12 -0
  205. package/dist/lib/brand-swatches.d.ts.map +1 -0
  206. package/dist/lib/container-ops.d.ts +3 -2
  207. package/dist/lib/container-ops.d.ts.map +1 -1
  208. package/dist/lib/dexie.d.ts.map +1 -1
  209. package/dist/lib/dexie.js +9 -1
  210. package/dist/lib/env.d.ts +4 -0
  211. package/dist/lib/env.d.ts.map +1 -1
  212. package/dist/lib/env.js +5 -3
  213. package/dist/lib/events.d.ts +1 -2
  214. package/dist/lib/events.d.ts.map +1 -1
  215. package/dist/lib/image-background.d.ts +8 -0
  216. package/dist/lib/image-background.d.ts.map +1 -0
  217. package/dist/lib/index-ops.js +3 -3
  218. package/dist/lib/index.d.ts +6 -4
  219. package/dist/lib/index.d.ts.map +1 -1
  220. package/dist/lib/index.js +29 -21
  221. package/dist/lib/loader.d.ts +21 -7
  222. package/dist/lib/loader.d.ts.map +1 -1
  223. package/dist/lib/nav-tree.d.ts +1 -0
  224. package/dist/lib/nav-tree.d.ts.map +1 -1
  225. package/dist/lib/nav.d.ts +38 -0
  226. package/dist/lib/nav.d.ts.map +1 -1
  227. package/dist/lib/platform-broker.d.ts +4 -2
  228. package/dist/lib/platform-broker.d.ts.map +1 -1
  229. package/dist/lib/platform-broker.js +21 -13
  230. package/dist/lib/reference-type.d.ts +2 -0
  231. package/dist/lib/reference-type.d.ts.map +1 -0
  232. package/dist/lib/reference-validation.d.ts +31 -0
  233. package/dist/lib/reference-validation.d.ts.map +1 -0
  234. package/dist/lib/reference-validation.js +39 -0
  235. package/dist/lib/references.d.ts +74 -0
  236. package/dist/lib/references.d.ts.map +1 -0
  237. package/dist/lib/registry.d.ts +35 -0
  238. package/dist/lib/registry.d.ts.map +1 -1
  239. package/dist/lib/{safeRedirect.d.ts → safe-redirect.d.ts} +1 -1
  240. package/dist/lib/safe-redirect.d.ts.map +1 -0
  241. package/dist/lib/tags.d.ts +58 -0
  242. package/dist/lib/tags.d.ts.map +1 -0
  243. package/dist/lib/theme-vars.d.ts +9 -0
  244. package/dist/lib/theme-vars.d.ts.map +1 -1
  245. package/dist/media/index.d.ts +1 -1
  246. package/dist/media/index.d.ts.map +1 -1
  247. package/dist/media/index.js +8 -4
  248. package/dist/media/utils.d.ts +2 -0
  249. package/dist/media/utils.d.ts.map +1 -1
  250. package/dist/media/{videoPoster.d.ts → video-poster.d.ts} +1 -1
  251. package/dist/media/video-poster.d.ts.map +1 -0
  252. package/dist/schemas/audience.js +2 -2
  253. package/dist/schemas/index.d.ts +1 -0
  254. package/dist/schemas/index.d.ts.map +1 -1
  255. package/dist/schemas/index.js +14 -8
  256. package/dist/schemas/shared.d.ts +26 -0
  257. package/dist/schemas/shared.d.ts.map +1 -1
  258. package/dist/schemas/site-config.d.ts +6 -0
  259. package/dist/schemas/site-config.d.ts.map +1 -1
  260. package/dist/schemas/tags.d.ts +27 -0
  261. package/dist/schemas/tags.d.ts.map +1 -0
  262. package/dist/storage/index.js +1 -1
  263. package/dist/types/database.d.ts.map +1 -1
  264. package/package.json +6 -1
  265. package/src/auth/cookies.ts +111 -0
  266. package/src/collab/rebase.ts +26 -2
  267. package/src/components/brandguide/ColorSwatchSettings.tsx +1 -1
  268. package/src/components/brandguide/ColorsEditable.tsx +1 -0
  269. package/src/components/chat/ChatPanel.tsx +2 -3
  270. package/src/components/chat/ChatWidget.tsx +2 -3
  271. package/src/components/docfile/DocFilePane.tsx +4 -12
  272. package/src/components/editor/ChildBlockWrapper.tsx +13 -19
  273. package/src/components/editor/ConflictDialog.tsx +27 -35
  274. package/src/components/editor/DeleteButton.tsx +2 -2
  275. package/src/components/editor/DragHandle.tsx +16 -3
  276. package/src/components/editor/DropEdgeIndicator.tsx +36 -10
  277. package/src/components/editor/InsertButton.tsx +2 -2
  278. package/src/components/editor/NavGroupRow.tsx +43 -14
  279. package/src/components/editor/PagesModal.tsx +99 -26
  280. package/src/components/editor/SectionWrapper.tsx +64 -23
  281. package/src/components/editor/SettingsButton.tsx +2 -2
  282. package/src/components/editor/SettingsForm.tsx +19 -2
  283. package/src/components/editor/StatusIndicator.tsx +4 -4
  284. package/src/components/editor/TagIndicator.tsx +80 -0
  285. package/src/components/primitives/DocumentDropZone.tsx +1 -1
  286. package/src/components/primitives/EditableGrid.tsx +15 -14
  287. package/src/components/primitives/EditableList.tsx +27 -74
  288. package/src/components/primitives/HeadingSection.tsx +5 -2
  289. package/src/components/primitives/ResolvedMedia.tsx +13 -0
  290. package/src/components/primitives/{defineHeadingSection.tsx → define-heading-section.tsx} +1 -0
  291. package/src/components/primitives/index.ts +1 -1
  292. package/src/components/primitives/useEditablePlainText.ts +5 -5
  293. package/src/components/sections/Button/CTAButton.tsx +3 -1
  294. package/src/components/sections/DoDontMedia/DoDontMediaBlock.tsx +4 -4
  295. package/src/components/sections/DoDontMedia/index.tsx +12 -3
  296. package/src/components/sections/IconList/DoDontToggle.tsx +2 -2
  297. package/src/components/sections/IconList/IconList.tsx +70 -37
  298. package/src/components/sections/IconList/IconListSettings.tsx +55 -17
  299. package/src/components/sections/IconList/index.tsx +10 -3
  300. package/src/components/sections/LinkHeading/index.tsx +1 -1
  301. package/src/components/sections/Media/MediaBlock.tsx +13 -2
  302. package/src/components/sections/Media/index.tsx +12 -4
  303. package/src/components/sections/Reference/ReferenceList.tsx +214 -0
  304. package/src/components/sections/Reference/ReferenceSettings.tsx +159 -0
  305. package/src/components/sections/Reference/index.tsx +47 -0
  306. package/src/components/sections/SectionSummary/SectionSummaryBlock.tsx +476 -0
  307. package/src/components/sections/SectionSummary/SectionSummarySettings.tsx +126 -0
  308. package/src/components/sections/SectionSummary/index.tsx +149 -0
  309. package/src/components/sections/SubHeading/index.tsx +1 -1
  310. package/src/components/sections/SubSubHeading/index.tsx +1 -1
  311. package/src/components/sections/brand-guide.ts +4 -3
  312. package/src/components/sections/core-sections.ts +2 -0
  313. package/src/components/shared/BrandSwatchesContext.ts +13 -0
  314. package/src/components/shared/Button.tsx +47 -34
  315. package/src/components/shared/Checkbox.tsx +21 -12
  316. package/src/components/shared/ConfirmDialog.tsx +87 -0
  317. package/src/components/shared/ConfirmInline.tsx +90 -0
  318. package/src/components/shared/ErrorBoundary.tsx +6 -18
  319. package/src/components/shared/Fab.tsx +15 -5
  320. package/src/components/shared/FabStack.tsx +28 -0
  321. package/src/components/shared/HistoryChangesModal.tsx +43 -41
  322. package/src/components/shared/HistoryPopover.tsx +7 -20
  323. package/src/components/shared/ImageBackgroundField.tsx +92 -0
  324. package/src/components/shared/{UploadRejectionAlert.tsx → InlineAlert.tsx} +21 -5
  325. package/src/components/shared/Input.tsx +23 -7
  326. package/src/components/shared/Navigation.tsx +22 -17
  327. package/src/components/shared/Notice.tsx +59 -0
  328. package/src/components/shared/Popover.tsx +7 -11
  329. package/src/components/shared/ReferenceSourcesContext.ts +27 -0
  330. package/src/components/shared/Select.tsx +5 -2
  331. package/src/components/shared/SplitButton.tsx +11 -17
  332. package/src/components/shared/SummaryAnchorsContext.ts +11 -0
  333. package/src/components/shared/Textarea.tsx +17 -2
  334. package/src/components/shared/ToolbarFrame.tsx +28 -0
  335. package/src/components/shared/VideoSourceField.tsx +1 -1
  336. package/src/components/shared/copy.ts +18 -0
  337. package/src/components/shared/icons.tsx +1 -17
  338. package/src/components/shell/AudienceAddForm.tsx +2 -2
  339. package/src/components/shell/AudienceDetailsPanel.tsx +23 -5
  340. package/src/components/shell/AudienceRow.tsx +22 -15
  341. package/src/components/shell/BugReportFAB.tsx +50 -40
  342. package/src/components/shell/CredentialList.tsx +33 -13
  343. package/src/components/shell/DocInspector.tsx +3 -12
  344. package/src/components/shell/DocumentEditorOverlay.tsx +33 -23
  345. package/src/components/shell/EditorContext.tsx +7 -0
  346. package/src/components/shell/EditorLoginForm.tsx +26 -36
  347. package/src/components/shell/EditorModal.tsx +8 -10
  348. package/src/components/shell/EditorShell.tsx +499 -339
  349. package/src/components/shell/HistoryToolbar.tsx +24 -26
  350. package/src/components/shell/MediaFolderTile.tsx +8 -3
  351. package/src/components/shell/MediaLibraryModal.tsx +59 -60
  352. package/src/components/shell/ProcessingIndicator.tsx +2 -2
  353. package/src/components/shell/RestoreModal.tsx +17 -16
  354. package/src/components/shell/SetPasswordForm.tsx +3 -3
  355. package/src/components/shell/SiteSettingsChatbot.tsx +61 -42
  356. package/src/components/shell/SiteSettingsDisplay.tsx +10 -20
  357. package/src/components/shell/SiteSettingsModal.tsx +24 -2
  358. package/src/components/shell/SiteSettingsTags.tsx +143 -0
  359. package/src/components/shell/SiteSettingsUsers.tsx +36 -26
  360. package/src/components/shell/SiteSettingsViewerAccess.tsx +2 -2
  361. package/src/components/shell/ViewerLoginForm.tsx +5 -4
  362. package/src/components/shell/reference-sources.ts +36 -0
  363. package/src/deck/index.ts +2 -2
  364. package/src/document/index.ts +2 -2
  365. package/src/hooks/useBlockDnd.ts +11 -0
  366. package/src/hooks/useBuildStatus.ts +53 -6
  367. package/src/hooks/useDocumentUploads.ts +1 -1
  368. package/src/hooks/useEditorPersistence.ts +141 -35
  369. package/src/hooks/useEditorPublish.ts +18 -27
  370. package/src/hooks/useMediaPipeline.ts +1 -1
  371. package/src/hooks/useNotice.ts +45 -0
  372. package/src/hooks/useSortableNavRow.ts +11 -0
  373. package/src/hooks/useSortableRow.ts +22 -2
  374. package/src/hooks/useStackedEscape.ts +62 -0
  375. package/src/lib/block-dnd.ts +6 -1
  376. package/src/lib/block-move.ts +3 -0
  377. package/src/lib/brand-swatches.ts +32 -0
  378. package/src/lib/container-ops.ts +5 -3
  379. package/src/lib/dexie.ts +15 -1
  380. package/src/lib/env.ts +9 -0
  381. package/src/lib/events.ts +1 -2
  382. package/src/lib/image-background.ts +31 -0
  383. package/src/lib/index.ts +5 -4
  384. package/src/lib/loader.ts +54 -55
  385. package/src/lib/nav-tree.ts +71 -0
  386. package/src/lib/nav.ts +196 -36
  387. package/src/lib/platform-broker.ts +32 -14
  388. package/src/lib/reference-type.ts +3 -0
  389. package/src/lib/reference-validation.ts +69 -0
  390. package/src/lib/references.ts +130 -0
  391. package/src/lib/registry.ts +37 -0
  392. package/src/lib/tags.ts +148 -0
  393. package/src/lib/theme-vars.ts +23 -0
  394. package/src/media/index.ts +1 -1
  395. package/src/media/utils.ts +18 -0
  396. package/src/media/{videoPoster.ts → video-poster.ts} +2 -2
  397. package/src/schemas/index.ts +1 -0
  398. package/src/schemas/shared.ts +24 -1
  399. package/src/schemas/site-config.ts +6 -1
  400. package/src/schemas/tags.ts +33 -0
  401. package/src/storage/types.ts +1 -1
  402. package/src/types/database.ts +2 -0
  403. package/dist/chunk-DNY72JZN.js +0 -86
  404. package/dist/chunk-F2LYQPXV.js +0 -77
  405. package/dist/chunk-JH762VUH.js +0 -128
  406. package/dist/chunk-K7DYZXVU.js +0 -138
  407. package/dist/components/primitives/defineHeadingSection.d.ts.map +0 -1
  408. package/dist/components/primitives/gridDrop.d.ts.map +0 -1
  409. package/dist/components/shared/UploadRejectionAlert.d.ts.map +0 -1
  410. package/dist/components/shell/BuildStatusIndicator.d.ts +0 -7
  411. package/dist/components/shell/BuildStatusIndicator.d.ts.map +0 -1
  412. package/dist/components/shell/blockMoveDispatch.d.ts.map +0 -1
  413. package/dist/hooks/index.d.ts +0 -9
  414. package/dist/hooks/index.d.ts.map +0 -1
  415. package/dist/lib/grid.d.ts +0 -2
  416. package/dist/lib/grid.d.ts.map +0 -1
  417. package/dist/lib/safeRedirect.d.ts.map +0 -1
  418. package/dist/media/videoPoster.d.ts.map +0 -1
  419. package/src/components/brandguide/ColorSwatchSettings.d.ts.map +0 -1
  420. package/src/components/brandguide/Colors.d.ts.map +0 -1
  421. package/src/components/primitives/CustomParagraph.d.ts.map +0 -1
  422. package/src/components/primitives/EditableGrid.d.ts.map +0 -1
  423. package/src/components/primitives/EditablePlainText.d.ts.map +0 -1
  424. package/src/components/primitives/EditableRichText.d.ts.map +0 -1
  425. package/src/components/primitives/HeadingSection.d.ts.map +0 -1
  426. package/src/components/primitives/IconPicker.d.ts.map +0 -1
  427. package/src/components/primitives/LinkPopover.d.ts.map +0 -1
  428. package/src/components/primitives/MediaSettingsForms.d.ts.map +0 -1
  429. package/src/components/primitives/ResolvedMedia.d.ts.map +0 -1
  430. package/src/components/primitives/RichTextToolbar.d.ts.map +0 -1
  431. package/src/components/primitives/tiptap-presets.d.ts.map +0 -1
  432. package/src/components/primitives/useEditableCollection.d.ts.map +0 -1
  433. package/src/components/primitives/useEditablePlainText.d.ts.map +0 -1
  434. package/src/components/primitives/useEditableRichText.d.ts.map +0 -1
  435. package/src/components/sections/Button/CTAButton.d.ts.map +0 -1
  436. package/src/components/sections/Button/index.d.ts.map +0 -1
  437. package/src/components/sections/Colors/index.d.ts.map +0 -1
  438. package/src/components/sections/IconList/IconList.d.ts.map +0 -1
  439. package/src/components/sections/IconList/IconListSettings.d.ts.map +0 -1
  440. package/src/components/sections/IconList/index.d.ts.map +0 -1
  441. package/src/components/sections/LinkHeading/index.d.ts.map +0 -1
  442. package/src/components/sections/Prose/Prose.d.ts.map +0 -1
  443. package/src/components/sections/Prose/index.d.ts.map +0 -1
  444. package/src/components/sections/SubHeading/index.d.ts.map +0 -1
  445. package/src/components/sections/SubSubHeading/index.d.ts.map +0 -1
  446. package/src/components/sections/register-schemas.d.ts.map +0 -1
  447. package/src/components/shared/Button.d.ts.map +0 -1
  448. package/src/components/shared/Checkbox.d.ts.map +0 -1
  449. package/src/components/shared/FormLabel.d.ts.map +0 -1
  450. package/src/components/shared/IconButton.d.ts.map +0 -1
  451. package/src/components/shared/Input.d.ts.map +0 -1
  452. package/src/components/shared/Select.d.ts.map +0 -1
  453. package/src/components/shared/icons.d.ts.map +0 -1
  454. package/src/components/shell/BuildStatusIndicator.tsx +0 -59
  455. package/src/components/shell/MediaLibraryContext.d.ts.map +0 -1
  456. package/src/hooks/index.ts +0 -8
  457. package/src/hooks/useResolvedMedia.d.ts.map +0 -1
  458. package/src/lib/cn.d.ts.map +0 -1
  459. package/src/lib/grid.d.ts.map +0 -1
  460. package/src/lib/grid.ts +0 -7
  461. package/src/lib/icons.d.ts.map +0 -1
  462. package/src/lib/loader.d.ts.map +0 -1
  463. package/src/lib/nav.d.ts.map +0 -1
  464. package/src/lib/registry.d.ts.map +0 -1
  465. package/src/lib/sanitize.d.ts.map +0 -1
  466. package/src/media/github.d.ts.map +0 -1
  467. package/src/media/index.d.ts.map +0 -1
  468. package/src/media/queue.d.ts.map +0 -1
  469. package/src/media/resolve.d.ts.map +0 -1
  470. package/src/media/types.d.ts.map +0 -1
  471. package/src/media/utils.d.ts.map +0 -1
  472. package/src/media/videoPoster.d.ts.map +0 -1
  473. package/src/schemas/auth.d.ts.map +0 -1
  474. package/src/schemas/media-grid-options.d.ts.map +0 -1
  475. package/src/schemas/media.d.ts.map +0 -1
  476. package/src/schemas/sections.d.ts.map +0 -1
  477. package/src/schemas/shared.d.ts.map +0 -1
  478. package/src/schemas/site-config.d.ts.map +0 -1
  479. /package/dist/{chunk-B7VBSE5X.js → chunk-3JDTXOIG.js} +0 -0
  480. /package/dist/{chunk-CXZ5YJG4.js → chunk-L45X7DKX.js} +0 -0
  481. /package/src/components/primitives/{gridDrop.ts → grid-drop.ts} +0 -0
  482. /package/src/components/shell/{blockMoveDispatch.ts → block-move-dispatch.ts} +0 -0
  483. /package/src/lib/{safeRedirect.ts → safe-redirect.ts} +0 -0
@@ -1,8 +1,9 @@
1
- import { useState } from "react";
1
+ import { useRef, useState } from "react";
2
2
  import { Eye, Copy, Check } from "lucide-react";
3
3
  import { Input } from "../shared/Input";
4
4
  import { PasswordInput } from "../shared/PasswordInput";
5
5
  import { Button } from "../shared/Button";
6
+ import { ConfirmInline } from "../shared/ConfirmInline";
6
7
  import {
7
8
  ViewerUsernameSchema,
8
9
  VIEWER_PASSWORD_MIN_LENGTH,
@@ -60,6 +61,9 @@ function CredentialRow({
60
61
  const [revealed, setRevealed] = useState<string | null>(null);
61
62
  const [busy, setBusy] = useState(false);
62
63
  const [error, setError] = useState<string | null>(null);
64
+ const [confirmingRemove, setConfirmingRemove] = useState(false);
65
+ const [removing, setRemoving] = useState(false);
66
+ const removeButtonRef = useRef<HTMLButtonElement>(null);
63
67
 
64
68
  async function reveal() {
65
69
  setError(null);
@@ -107,16 +111,15 @@ function CredentialRow({
107
111
  }
108
112
 
109
113
  async function remove() {
110
- if (!confirm(
111
- `Remove the sign-in "${credential.username}"?\n\n` +
112
- "Anyone using it will be locked out — though a browser already signed in " +
113
- "may keep access for up to 24 hours, until its session expires.",
114
- )) return;
115
114
  setError(null);
115
+ setRemoving(true);
116
116
  try {
117
117
  await onDelete(credential.username);
118
+ setConfirmingRemove(false);
118
119
  } catch (e) {
119
120
  setError(e instanceof Error ? e.message : "Remove failed");
121
+ } finally {
122
+ setRemoving(false);
120
123
  }
121
124
  }
122
125
 
@@ -133,7 +136,7 @@ function CredentialRow({
133
136
  {revealed ? (
134
137
  <CopyableSecret value={revealed} />
135
138
  ) : (
136
- <Button variant="ghost" onClick={reveal} isLoading={busy && !editing} loadingLabel="...">
139
+ <Button variant="ghost" onClick={reveal} isLoading={busy && !editing} loadingLabel="…">
137
140
  <span className="inline-flex items-center gap-1.5">
138
141
  <Eye className="h-3.5 w-3.5" aria-hidden />
139
142
  Show
@@ -143,11 +146,28 @@ function CredentialRow({
143
146
  {revealed && <Button variant="ghost" onClick={() => setRevealed(null)}>Hide</Button>}
144
147
 
145
148
  {canMutate && !editing && <Button variant="ghost" onClick={() => setEditing(true)}>Edit</Button>}
146
- {canMutate && !editing && (
147
- <Button variant="ghost" tone="destructive" onClick={remove}>Remove</Button>
149
+ {canMutate && !editing && !confirmingRemove && (
150
+ <Button ref={removeButtonRef} variant="ghost" tone="destructive" onClick={() => setConfirmingRemove(true)}>Remove</Button>
148
151
  )}
149
152
  </div>
150
153
 
154
+ {confirmingRemove && (
155
+ <div className="mt-2">
156
+ <ConfirmInline
157
+ message={
158
+ `Remove the sign-in "${credential.username}"? Anyone using it will be locked out — ` +
159
+ "though a browser already signed in may keep access for up to 24 hours, until its session expires."
160
+ }
161
+ confirmLabel="Remove"
162
+ tone="destructive"
163
+ busy={removing}
164
+ onConfirm={remove}
165
+ onCancel={() => setConfirmingRemove(false)}
166
+ returnFocusTo={removeButtonRef}
167
+ />
168
+ </div>
169
+ )}
170
+
151
171
  {editing && (
152
172
  <div className="mt-2 space-y-2">
153
173
  <Input label="Label" value={label} onChange={setLabel} placeholder="Login Name" />
@@ -163,12 +183,12 @@ function CredentialRow({
163
183
  <Button variant="secondary" onClick={() => { setEditing(false); setPassword(""); setLabel(credential.label ?? ""); setError(null); }} disabled={busy}>
164
184
  Cancel
165
185
  </Button>
166
- <Button variant="primary" onClick={save} isLoading={busy} loadingLabel="Saving...">Save</Button>
186
+ <Button variant="primary" onClick={save} isLoading={busy} loadingLabel="Saving…">Save</Button>
167
187
  </div>
168
188
  </div>
169
189
  )}
170
190
 
171
- {error && <p className="mt-1 text-xs text-red-600">{error}</p>}
191
+ {error && <p className="mt-1 text-xs text-danger">{error}</p>}
172
192
  </li>
173
193
  );
174
194
  }
@@ -241,10 +261,10 @@ function AddForm({ audienceName, onCreate, onCancel }: {
241
261
  Signs in to <span className="font-medium">{audienceName}</span> and sees exactly what that audience sees.
242
262
  You can look this password up again later.
243
263
  </p>
244
- {error && <p className="text-xs text-red-600">{error}</p>}
264
+ {error && <p className="text-xs text-danger">{error}</p>}
245
265
  <div className="flex justify-end gap-2">
246
266
  <Button variant="secondary" onClick={onCancel} disabled={busy}>Cancel</Button>
247
- <Button variant="primary" onClick={submit} isLoading={busy} loadingLabel="Adding...">Add</Button>
267
+ <Button variant="primary" onClick={submit} isLoading={busy} loadingLabel="Adding…">Add</Button>
248
268
  </div>
249
269
  </li>
250
270
  );
@@ -7,17 +7,8 @@ import { ColorPicker } from "../shared/ColorPicker";
7
7
  import { FormLabel } from "../shared/FormLabel";
8
8
  import { useMediaLibrary } from "./MediaLibraryContext";
9
9
  import { Button } from "../shared/Button";
10
- import type { MediaItem } from "../../media/types";
10
+ import { imageThumbnailUrl } from "../../media/utils";
11
11
 
12
- // Smallest generated variant for the inspector thumbnail (same file naming as
13
- // docImagesFrom in lib/document-input.ts); null when the item can't render.
14
- function thumbSrc(imageId: string, item: MediaItem | undefined): string | null {
15
- if (!item || item.kind !== "image") return null;
16
- if (item.mimeType === "image/svg+xml") return `/api/media/${imageId}/original.svg`;
17
- const widths = item.variants.map((v) => v.width).sort((a, b) => a - b);
18
- if (widths.length === 0) return null;
19
- return `/api/media/${imageId}/${widths[0]}.webp`;
20
- }
21
12
 
22
13
  export interface DocInspectorProps {
23
14
  document: DocumentOptions;
@@ -117,7 +108,7 @@ function CoverPanel({
117
108
  <FormLabel>Cover image</FormLabel>
118
109
  {cover.imageId ? (
119
110
  (() => {
120
- const src = thumbSrc(cover.imageId, media.manifest.images[cover.imageId]);
111
+ const src = imageThumbnailUrl(media.manifest.images[cover.imageId]);
121
112
  return src ? (
122
113
  <img src={src} alt="Cover image preview" className="mb-2 max-h-24 rounded border border-base-200" />
123
114
  ) : null;
@@ -312,7 +303,7 @@ function ChunkPanel({
312
303
  {warnings.length > 0 ? (
313
304
  <div className="mt-2">
314
305
  {warnings.map((w, i) => (
315
- <p key={i} className="mb-1 rounded border border-amber-300 bg-amber-50 px-2 py-1 text-xs text-amber-800">
306
+ <p key={i} className="mb-1 rounded border border-warning bg-warning-bg px-2 py-1 text-xs text-warning">
316
307
  {w}
317
308
  </p>
318
309
  ))}
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect, useMemo, useState } from "react";
1
+ import { useCallback, useMemo, useRef, useState } from "react";
2
2
  import type { Page } from "../../schemas/site-config";
3
3
  import type { MediaManifest } from "../../media/types";
4
4
  import type { LoadedSection } from "../../lib/loader";
@@ -14,6 +14,8 @@ import {
14
14
  import { DocInspector, type DocInspectorProps } from "./DocInspector";
15
15
  import { buildDraftDocumentInput } from "../../lib/document-input";
16
16
  import { Button } from "../shared/Button";
17
+ import { useFocusTrap } from "../../hooks/useFocusTrap";
18
+ import { useStackedEscape } from "../../hooks/useStackedEscape";
17
19
  // The sealed document stylesheet ships with its editor consumer (Task 6 decided
18
20
  // the present route imports it from its island; this is the editor's island).
19
21
  // Vitest stubs CSS imports, so it stays out of the jsdom test graph regardless.
@@ -85,27 +87,35 @@ export function DocumentEditorOverlay({
85
87
  [],
86
88
  );
87
89
 
88
- // Escape closes (the close button is the other exit). DocViewer owns arrow
89
- // paging on its own window listener; Escape doesn't collide with it. An
90
- // Escape aimed at an inspector control is the cancel-the-field gesture, not
91
- // "leave the editor": text fields blur (so the next Escape closes), and a
92
- // select is left alone entirely — the browser uses Escape to dismiss its
93
- // popup and there's no way to tell whether one is open.
94
- useEffect(() => {
95
- const onKey = (e: KeyboardEvent) => {
96
- if (e.key !== "Escape") return;
97
- const t = e.target as HTMLElement | null;
98
- if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) {
99
- t.blur();
100
- return;
101
- }
102
- if (t && t.tagName === "SELECT") return;
103
- e.preventDefault();
104
- onClose();
105
- };
106
- window.addEventListener("keydown", onKey);
107
- return () => window.removeEventListener("keydown", onKey);
108
- }, [onClose]);
90
+ const panelRef = useRef<HTMLDivElement>(null);
91
+ useFocusTrap(panelRef, true);
92
+
93
+ // Escape closes (the close button is the other exit), but a modal opened on
94
+ // top — the Media Library, from the cover-image picker — owns Escape first
95
+ // (useStackedEscape's layer check). DocViewer owns arrow paging on its own
96
+ // window listener; Escape doesn't collide with it. An Escape aimed at an
97
+ // inspector control is the cancel-the-field gesture, not "leave the
98
+ // editor": text fields blur (so the next Escape closes), and a select is
99
+ // left alone entirely (swallowed, not blurred) — the browser uses Escape to
100
+ // dismiss its popup and there's no way to tell whether one is open.
101
+ // Stable identity: useStackedEscape's effect deps include `before`, so a
102
+ // fresh arrow every render (this closes over nothing render-specific) would
103
+ // tear down and re-add the document listener on every render instead of
104
+ // just mount/unmount.
105
+ const blurFieldFirst = useCallback((e: KeyboardEvent) => {
106
+ const t = e.target as HTMLElement | null;
107
+ if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) {
108
+ t.blur();
109
+ return true;
110
+ }
111
+ if (t && t.tagName === "SELECT") return true;
112
+ return false;
113
+ }, []);
114
+
115
+ useStackedEscape(onClose, {
116
+ enabled: true,
117
+ before: blurFieldFirst,
118
+ });
109
119
 
110
120
  const selection: DocInspectorProps["selection"] = useMemo(() => {
111
121
  if (selectedChunkId === null) return { kind: "cover" };
@@ -138,7 +148,7 @@ export function DocumentEditorOverlay({
138
148
  );
139
149
 
140
150
  return (
141
- <div className="fixed inset-0 z-50 flex flex-col bg-base" role="dialog" aria-modal="true" aria-label="Document editor">
151
+ <div ref={panelRef} className="fixed inset-0 z-50 flex flex-col bg-base" role="dialog" aria-modal="true" aria-label="Document editor">
142
152
  <div className="flex items-center justify-between border-b border-base-200 bg-base px-4 py-2">
143
153
  <span className="text-sm font-medium text-base-contrast">Document · {page.title}</span>
144
154
  <Button variant="secondary" size="sm" aria-label="Close document editor" onClick={onClose}>
@@ -71,3 +71,10 @@ export function useEditorContext(): EditorContextValue {
71
71
  }
72
72
  return context;
73
73
  }
74
+
75
+ /** For editor components rendered outside an EditorProvider (tests, isolated
76
+ * rendering): null instead of throwing. Not a licence for viewer reuse —
77
+ * editor code must never reach a viewer path. */
78
+ export function useOptionalEditorContext(): EditorContextValue | null {
79
+ return useContext(EditorContext);
80
+ }
@@ -1,7 +1,9 @@
1
1
  import { useState, useEffect, type FormEvent } from "react";
2
2
  import { PasswordInput } from "../shared/PasswordInput";
3
+ import { Input } from "../shared/Input";
3
4
  import { Button } from "../shared/Button";
4
- import { safeRedirect } from "../../lib/safeRedirect";
5
+ import { COPY } from "../shared/copy";
6
+ import { safeRedirect } from "../../lib/safe-redirect";
5
7
 
6
8
  const HASH_ERROR_MESSAGES: Record<string, string> = {
7
9
  otp_expired: "This link has expired. Please request a new one.",
@@ -126,7 +128,7 @@ export function EditorLoginForm({ capabilities, oauthProviders = [], next, serve
126
128
 
127
129
  if (!response.ok) {
128
130
  const data = await response.json().catch(() => ({}));
129
- setError(data.error || "Sign-in failed");
131
+ setError(data.error || COPY.auth.signInFallback);
130
132
  return;
131
133
  }
132
134
 
@@ -154,7 +156,7 @@ export function EditorLoginForm({ capabilities, oauthProviders = [], next, serve
154
156
 
155
157
  if (!response.ok) {
156
158
  const data = await response.json().catch(() => ({}));
157
- setError(data.error || "Failed to send reset link");
159
+ setError(data.error || "Couldn't send reset link");
158
160
  return;
159
161
  }
160
162
 
@@ -186,7 +188,7 @@ export function EditorLoginForm({ capabilities, oauthProviders = [], next, serve
186
188
  if (exchangingTokens) {
187
189
  return (
188
190
  <div className="mx-auto max-w-sm py-8 text-center">
189
- <p className="text-sm text-base-contrast-light">Signing in...</p>
191
+ <p className="text-sm text-base-contrast-light">Signing in…</p>
190
192
  </div>
191
193
  );
192
194
  }
@@ -219,29 +221,23 @@ export function EditorLoginForm({ capabilities, oauthProviders = [], next, serve
219
221
  </div>
220
222
  ) : (
221
223
  <form onSubmit={handleResetSubmit} className="space-y-4">
222
- <div>
223
- <label htmlFor="reset-email" className="mb-1.5 block text-sm font-medium text-base-contrast">
224
- Email
225
- </label>
226
- <input
227
- id="reset-email"
228
- type="email"
229
- value={email}
230
- onChange={(e) => setEmail(e.target.value)}
231
- required
232
- autoComplete="email"
233
- className="w-full rounded border border-base-200 bg-base px-3 py-2 text-sm text-base-contrast focus:border-base-contrast focus:outline-none focus:ring-1 focus:ring-base-contrast"
234
- />
235
- </div>
224
+ <Input
225
+ label="Email"
226
+ type="email"
227
+ value={email}
228
+ onChange={setEmail}
229
+ required
230
+ autoComplete="email"
231
+ />
236
232
 
237
- {error && <p className="text-sm text-red-600">{error}</p>}
233
+ {error && <p className="text-sm text-danger">{error}</p>}
238
234
 
239
235
  <Button
240
236
  type="submit"
241
237
  variant="primary"
242
238
  size="md"
243
239
  isLoading={loading}
244
- loadingLabel="Sending..."
240
+ loadingLabel="Sending…"
245
241
  className="w-full"
246
242
  >
247
243
  Send reset link
@@ -289,20 +285,14 @@ export function EditorLoginForm({ capabilities, oauthProviders = [], next, serve
289
285
 
290
286
  <form onSubmit={handlePasswordSubmit} className="space-y-4">
291
287
  {capabilities.emailPassword && (
292
- <div>
293
- <label htmlFor="email" className="mb-1.5 block text-sm font-medium text-base-contrast">
294
- Email
295
- </label>
296
- <input
297
- id="email"
298
- type="email"
299
- value={email}
300
- onChange={(e) => setEmail(e.target.value)}
301
- required
302
- autoComplete="email"
303
- className="w-full rounded border border-base-200 bg-base px-3 py-2 text-sm text-base-contrast focus:border-base-contrast focus:outline-none focus:ring-1 focus:ring-base-contrast"
304
- />
305
- </div>
288
+ <Input
289
+ label="Email"
290
+ type="email"
291
+ value={email}
292
+ onChange={setEmail}
293
+ required
294
+ autoComplete="email"
295
+ />
306
296
  )}
307
297
 
308
298
  <PasswordInput
@@ -325,7 +315,7 @@ export function EditorLoginForm({ capabilities, oauthProviders = [], next, serve
325
315
  )}
326
316
 
327
317
  {error && (
328
- <p className="text-sm text-red-600">{error}</p>
318
+ <p className="text-sm text-danger">{error}</p>
329
319
  )}
330
320
 
331
321
  <Button
@@ -333,7 +323,7 @@ export function EditorLoginForm({ capabilities, oauthProviders = [], next, serve
333
323
  variant="primary"
334
324
  size="md"
335
325
  isLoading={loading}
336
- loadingLabel="Signing in..."
326
+ loadingLabel="Signing in…"
337
327
  className="w-full"
338
328
  >
339
329
  Sign In
@@ -1,8 +1,9 @@
1
1
  import { useEffect, useId, useRef, type ReactNode } from "react";
2
2
  import { createPortal } from "react-dom";
3
- import { RemoveIcon } from "../shared/icons";
3
+ import { X } from "lucide-react";
4
4
  import { IconButton } from "../shared/IconButton";
5
5
  import { useFocusTrap } from "../../hooks/useFocusTrap";
6
+ import { useStackedEscape } from "../../hooks/useStackedEscape";
6
7
  import { cn } from "../../lib/cn";
7
8
  import { lockBodyScroll } from "../../lib/scroll-lock";
8
9
 
@@ -27,14 +28,10 @@ export function EditorModal({ isOpen, onClose, title, blocking = false, size = "
27
28
 
28
29
  useFocusTrap(panelRef, isOpen);
29
30
 
30
- useEffect(() => {
31
- if (!isOpen || blocking) return;
32
- const handleKeyDown = (e: KeyboardEvent) => {
33
- if (e.key === "Escape") onClose();
34
- };
35
- document.addEventListener("keydown", handleKeyDown);
36
- return () => document.removeEventListener("keydown", handleKeyDown);
37
- }, [isOpen, blocking, onClose]);
31
+ // Another EditorModal opened on top of this one (a ConfirmDialog, say) owns
32
+ // Escape — attaching layerRef to our own data-modal-layer element below is
33
+ // what lets the hook tell "another layer" from "just me".
34
+ const layerRef = useStackedEscape<HTMLDivElement>(onClose, { enabled: isOpen && !blocking });
38
35
 
39
36
  useEffect(() => {
40
37
  if (!isOpen) return;
@@ -45,6 +42,7 @@ export function EditorModal({ isOpen, onClose, title, blocking = false, size = "
45
42
 
46
43
  return createPortal(
47
44
  <div
45
+ ref={layerRef}
48
46
  data-testid="modal-backdrop"
49
47
  // Marks the whole modal layer (backdrop + panel) so surfaces underneath —
50
48
  // notably Popover's outside-click handler — can tell "a dialog above me is
@@ -87,7 +85,7 @@ export function EditorModal({ isOpen, onClose, title, blocking = false, size = "
87
85
  <h3 id={titleId} className="text-lg font-semibold text-base-contrast">{title}</h3>
88
86
  {!blocking && (
89
87
  <IconButton
90
- icon={<RemoveIcon size={18} />}
88
+ icon={<X size={18} />}
91
89
  label="Close modal"
92
90
  size="lg"
93
91
  onClick={onClose}