@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,6 +1,7 @@
1
1
  import { useRef, useState } from "react";
2
2
  import { ChevronDown } from "lucide-react";
3
3
  import { cn } from "../../lib/cn";
4
+ import { Button } from "./Button";
4
5
  import { Popover } from "./Popover";
5
6
  import { PopoverItem } from "./PopoverItem";
6
7
 
@@ -37,38 +38,31 @@ export function SplitButton({
37
38
 
38
39
  return (
39
40
  <div className={cn("relative inline-flex", className)}>
40
- <button
41
- type="button"
41
+ <Button
42
+ variant="primary"
43
+ size="sm"
42
44
  onClick={onClick}
43
45
  disabled={resolvedDisabled}
44
- className={cn(
45
- "inline-flex items-center px-4 py-1.5 text-xs font-medium transition-colors",
46
- "bg-base-contrast text-base-accent",
47
- hasOptions ? "rounded-l" : "rounded",
48
- resolvedDisabled ? "cursor-not-allowed opacity-50" : "cursor-pointer hover:bg-base-contrast/90",
49
- )}
46
+ className={hasOptions ? "rounded-l rounded-r-none" : undefined}
50
47
  aria-label={displayLabel}
51
48
  >
52
49
  {displayLabel}
53
- </button>
50
+ </Button>
54
51
  {hasOptions && (
55
52
  <>
56
- <button
53
+ <Button
57
54
  ref={chevronRef}
58
- type="button"
55
+ variant="primary"
56
+ size="sm"
59
57
  onClick={() => setOpen((v) => !v)}
60
58
  disabled={resolvedDisabled}
61
- className={cn(
62
- "inline-flex items-center border-l border-base-accent/20 px-2 py-1.5 transition-colors",
63
- "bg-base-contrast text-base-accent rounded-r",
64
- resolvedDisabled ? "cursor-not-allowed opacity-50" : "cursor-pointer hover:bg-base-contrast/90",
65
- )}
59
+ className="rounded-l-none border-l border-base-accent/20 px-2"
66
60
  aria-label="More actions"
67
61
  aria-haspopup="true"
68
62
  aria-expanded={open}
69
63
  >
70
64
  <ChevronDown size={14} />
71
- </button>
65
+ </Button>
72
66
  <Popover isOpen={open} onClose={() => setOpen(false)} anchorRef={chevronRef} className="w-full">
73
67
  <ul role="menu" className="py-1">
74
68
  {options.map((option) => (
@@ -0,0 +1,11 @@
1
+ import { createContext } from "react";
2
+ import type { SummaryNavAnchor } from "../../lib/nav";
3
+
4
+ /**
5
+ * TL;DR / Summary nav anchors for the page being edited, keyed by section id.
6
+ * EditorShell provides it from summaryNavAnchors over the whole page, so a plate
7
+ * nested in a container gets the same anchor its nav entry links to. The SSR
8
+ * viewer can't share context across sections and reads `navAnchor` stamped on
9
+ * the section instead (withNavAnchors).
10
+ */
11
+ export const SummaryAnchorsContext = createContext<Record<string, SummaryNavAnchor>>({});
@@ -5,16 +5,24 @@ import { FormLabel } from "./FormLabel";
5
5
  interface TextareaProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "onChange"> {
6
6
  label: string;
7
7
  onChange: (value: string) => void;
8
+ /** Helper text below the field, e.g. a format hint or character count. */
9
+ hint?: string;
10
+ /** See `Input`'s `hideLabel` — keeps a real associated `<label>` for a11y
11
+ * without a visible caption, for compact fields that never showed one. */
12
+ hideLabel?: boolean;
13
+ /** Escape hatch for one-off sizing, matching `Select`'s `selectClassName`. */
14
+ textareaClassName?: string;
8
15
  }
9
16
 
10
17
  export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(function Textarea(
11
- { label, value, onChange, rows = 3, className, disabled, ...rest },
18
+ { label, value, onChange, rows = 3, className, disabled, hint, hideLabel, textareaClassName, ...rest },
12
19
  ref,
13
20
  ) {
14
21
  const id = useId();
22
+ const hintId = `${id}-hint`;
15
23
  return (
16
24
  <div className={className}>
17
- <FormLabel htmlFor={id}>{label}</FormLabel>
25
+ <FormLabel htmlFor={id} className={hideLabel ? "sr-only" : undefined}>{label}</FormLabel>
18
26
  <textarea
19
27
  ref={ref}
20
28
  id={id}
@@ -22,13 +30,20 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(function
22
30
  onChange={(e) => onChange(e.target.value)}
23
31
  rows={rows}
24
32
  disabled={disabled}
33
+ aria-describedby={hint ? hintId : undefined}
25
34
  className={cn(
26
35
  "w-full resize-none rounded border border-base-200 bg-base px-3 py-2 text-sm text-base-contrast",
27
36
  "focus:border-base-contrast focus:outline-none focus:ring-1 focus:ring-base-contrast",
28
37
  disabled && "cursor-not-allowed opacity-50",
38
+ textareaClassName,
29
39
  )}
30
40
  {...rest}
31
41
  />
42
+ {hint && (
43
+ <p id={hintId} className="mt-1 text-xs text-base-contrast-light">
44
+ {hint}
45
+ </p>
46
+ )}
32
47
  </div>
33
48
  );
34
49
  });
@@ -0,0 +1,28 @@
1
+ import type { ReactNode } from "react";
2
+ import { cn } from "../../lib/cn";
3
+
4
+ interface ToolbarFrameProps {
5
+ left?: ReactNode;
6
+ center?: ReactNode;
7
+ right?: ReactNode;
8
+ /** Pins the bar to the viewport's top edge (`fixed top-0 inset-x-0`) — the
9
+ * default, and what every toolbar in the shell (the two EditorShell bars,
10
+ * HistoryToolbar) uses. `false` renders in-flow. */
11
+ fixed?: boolean;
12
+ }
13
+
14
+ /** The one h-16, 3-column toolbar shell shared by EditorShell's edit-mode
15
+ * and view-mode bars and HistoryToolbar. Standardizing on h-16 here is what
16
+ * fixed HistoryToolbar's `py-2` bar being shorter than the body's `pt-16` —
17
+ * a gap under the bar, not an overlap. */
18
+ export function ToolbarFrame({ left, center, right, fixed = true }: ToolbarFrameProps) {
19
+ return (
20
+ <div className={cn(fixed && "fixed top-0 right-0 left-0 z-50", "border-b border-base-200 bg-base")}>
21
+ <div className="mx-auto grid h-16 max-w-screen-xl grid-cols-3 items-center px-4">
22
+ <div className="flex items-center gap-2">{left}</div>
23
+ <div className="flex items-center justify-center gap-2">{center}</div>
24
+ <div className="flex items-center justify-end gap-2">{right}</div>
25
+ </div>
26
+ </div>
27
+ );
28
+ }
@@ -140,7 +140,7 @@ export function VideoSourceField({ value, onChange }: Props) {
140
140
  {loading ? "Loading…" : "Use link"}
141
141
  </Button>
142
142
  </div>
143
- {error ? <p className="text-xs text-red-600">{error}</p> : null}
143
+ {error ? <p className="text-xs text-danger">{error}</p> : null}
144
144
  {!error && fallback ? (
145
145
  <p className="text-xs text-base-contrast-light/70">
146
146
  Added — couldn't fetch exact dimensions, using 16:9.
@@ -0,0 +1,18 @@
1
+ // Single source for editor-facing copy touched by the D1/D2/D5 UI
2
+ // consolidation pass (docs/superpowers/specs/2026-09-04-editor-ui-primitives-consolidation.md).
3
+ // Only strings this pass touched move here — no repo-wide sweep.
4
+ export const COPY = {
5
+ auth: {
6
+ // Both EditorLoginForm and ViewerLoginForm show the server's message when
7
+ // present ("Incorrect email or password." / "Incorrect username or
8
+ // password.") and fall back to this generic message otherwise.
9
+ signInFallback: "Couldn't sign in. Try again.",
10
+ },
11
+ bugReport: {
12
+ submitted: "Bug report submitted",
13
+ },
14
+ publish: {
15
+ saved: "Saved",
16
+ publishFailed: "Publish failed",
17
+ },
18
+ };
@@ -3,26 +3,10 @@
3
3
  * Each returns a styled element ready to drop into any context.
4
4
  * Sizing and visibility are left to the consumer via className.
5
5
  */
6
- import { GripVertical, Plus, Trash2, X, Settings } from "lucide-react";
6
+ import { GripVertical } from "lucide-react";
7
7
 
8
8
  export function DragHandle({ size = 16 }: { size?: number }) {
9
9
  return <GripVertical size={size} />;
10
10
  }
11
11
 
12
- export function AddIcon({ size = 14 }: { size?: number }) {
13
- return <Plus size={size} />;
14
- }
15
-
16
- export function RemoveIcon({ size = 14 }: { size?: number }) {
17
- return <X size={size} />;
18
- }
19
-
20
- export function DeleteIcon({ size = 14 }: { size?: number }) {
21
- return <Trash2 size={size} />;
22
- }
23
-
24
- export function SettingsIcon({ size = 14 }: { size?: number }) {
25
- return <Settings size={size} />;
26
- }
27
-
28
12
  export { GripVertical, Plus, Trash2, X, Settings } from "lucide-react";
@@ -59,7 +59,7 @@ export function AudienceAddForm({ onSubmit, onCancel }: Props) {
59
59
  </p>
60
60
  </div>
61
61
  </div>
62
- {error && <p className="text-xs text-red-600">{error}</p>}
62
+ {error && <p className="text-xs text-danger">{error}</p>}
63
63
  <div className="flex justify-end gap-2">
64
64
  <Button
65
65
  type="button"
@@ -73,7 +73,7 @@ export function AudienceAddForm({ onSubmit, onCancel }: Props) {
73
73
  type="submit"
74
74
  variant="primary"
75
75
  isLoading={submitting}
76
- loadingLabel="Adding..."
76
+ loadingLabel="Adding…"
77
77
  >
78
78
  Add
79
79
  </Button>
@@ -1,5 +1,5 @@
1
1
  import { useState } from "react";
2
- import { ChevronRight, Copy, Check, Eye } from "lucide-react";
2
+ import { ChevronRight, Copy, Check, Eye, ScanEye } from "lucide-react";
3
3
  import { cn } from "../../lib/cn";
4
4
  import { Button } from "../shared/Button";
5
5
  import { SectionSummaryRow } from "../shared/SectionSummaryRow";
@@ -21,6 +21,12 @@ interface Props {
21
21
  audiences: AudienceDetail[];
22
22
  /** False when the auth provider cannot store a reversible password at all. */
23
23
  revealSupported: boolean;
24
+ /**
25
+ * Show "View as" on each audience (#61): to editors and the default audience,
26
+ * and only while password protection is on, since without it no visitor sees
27
+ * an audience-filtered site.
28
+ */
29
+ canImpersonate?: boolean;
24
30
  }
25
31
 
26
32
  const PLACEHOLDER_COLOR = "#94a3b8";
@@ -103,7 +109,7 @@ function PasswordCell({ username, revealSupported }: { username: string; revealS
103
109
  }
104
110
 
105
111
  return (
106
- <Button variant="ghost" onClick={reveal} isLoading={state.kind === "loading"} loadingLabel="Loading...">
112
+ <Button variant="ghost" onClick={reveal} isLoading={state.kind === "loading"} loadingLabel="Loading…">
107
113
  <span className="inline-flex items-center gap-1.5">
108
114
  <Eye className="h-3.5 w-3.5" aria-hidden />
109
115
  Show password
@@ -168,7 +174,7 @@ function PageRow({ page }: { page: OverviewPage }) {
168
174
  );
169
175
  }
170
176
 
171
- function AudienceBlock({ audience, revealSupported }: { audience: AudienceDetail; revealSupported: boolean }) {
177
+ function AudienceBlock({ audience, revealSupported, canImpersonate }: { audience: AudienceDetail; revealSupported: boolean; canImpersonate: boolean }) {
172
178
  const [open, setOpen] = useState(false);
173
179
  const { overview } = audience;
174
180
 
@@ -200,6 +206,18 @@ function AudienceBlock({ audience, revealSupported }: { audience: AudienceDetail
200
206
  </span>
201
207
  </span>
202
208
  </button>
209
+ {canImpersonate && (
210
+ // A plain form POST: the route sets the cookie and 303s to the viewer site.
211
+ <form method="post" action="/api/auth/impersonate" className="shrink-0">
212
+ <input type="hidden" name="audience" value={audience.name} />
213
+ <Button type="submit" variant="secondary" size="sm" aria-label={`View the site as ${audience.displayName}`}>
214
+ <span className="inline-flex items-center gap-1.5">
215
+ <ScanEye className="h-3.5 w-3.5" aria-hidden />
216
+ View as
217
+ </span>
218
+ </Button>
219
+ </form>
220
+ )}
203
221
  </div>
204
222
 
205
223
  <div className="border-t border-base-200 px-4 py-3">
@@ -242,7 +260,7 @@ function AudienceBlock({ audience, revealSupported }: { audience: AudienceDetail
242
260
  * Reachable by editors and the site's default audience (the client), so the
243
261
  * client can hand a new partner access without going through us.
244
262
  */
245
- export function AudienceDetailsPanel({ audiences, revealSupported }: Props) {
263
+ export function AudienceDetailsPanel({ audiences, revealSupported, canImpersonate = false }: Props) {
246
264
  if (audiences.length === 0) {
247
265
  return (
248
266
  <p className="text-sm text-base-contrast-light">
@@ -254,7 +272,7 @@ export function AudienceDetailsPanel({ audiences, revealSupported }: Props) {
254
272
  return (
255
273
  <div className="flex flex-col gap-3">
256
274
  {audiences.map((a) => (
257
- <AudienceBlock key={a.name} audience={a} revealSupported={revealSupported} />
275
+ <AudienceBlock key={a.name} audience={a} revealSupported={revealSupported} canImpersonate={canImpersonate} />
258
276
  ))}
259
277
  </div>
260
278
  );
@@ -1,8 +1,9 @@
1
- import { useState } from "react";
1
+ import { useRef, useState } from "react";
2
2
  import type { Audience } from "../../auth/types";
3
3
  import { Input } from "../shared/Input";
4
4
  import { Button } from "../shared/Button";
5
5
  import { ColorPicker } from "../shared/ColorPicker";
6
+ import { ConfirmInline } from "../shared/ConfirmInline";
6
7
  import { CredentialList } from "./CredentialList";
7
8
  import type { ViewerCredential } from "../../schemas/audience";
8
9
 
@@ -41,6 +42,7 @@ export function AudienceRow({
41
42
  const [error, setError] = useState<string | null>(null);
42
43
  const [confirmingRemove, setConfirmingRemove] = useState(false);
43
44
  const [saving, setSaving] = useState(false);
45
+ const removeButtonRef = useRef<HTMLButtonElement>(null);
44
46
 
45
47
  function startEdit() {
46
48
  setIsEditing(true);
@@ -109,7 +111,7 @@ export function AudienceRow({
109
111
  />
110
112
  </div>
111
113
  </div>
112
- {error && <p className="text-xs text-red-600">{error}</p>}
114
+ {error && <p className="text-xs text-danger">{error}</p>}
113
115
  <div className="flex justify-end gap-2">
114
116
  <Button
115
117
  type="button"
@@ -124,7 +126,7 @@ export function AudienceRow({
124
126
  variant="primary"
125
127
  onClick={save}
126
128
  isLoading={saving}
127
- loadingLabel="Saving..."
129
+ loadingLabel="Saving…"
128
130
  >
129
131
  Save
130
132
  </Button>
@@ -168,22 +170,27 @@ export function AudienceRow({
168
170
  <Button variant="ghost" onClick={startEdit}>Edit</Button>
169
171
  )}
170
172
  {canMutate && !isDefault && !confirmingRemove && (
171
- <Button variant="ghost" tone="destructive" onClick={() => setConfirmingRemove(true)}>Remove</Button>
173
+ <Button ref={removeButtonRef} variant="ghost" tone="destructive" onClick={() => setConfirmingRemove(true)}>Remove</Button>
172
174
  )}
173
175
  </div>
174
176
 
175
177
  {confirmingRemove && (
176
- <div role="alertdialog" aria-label={`Remove ${audience.displayName}`} className="mt-2 rounded border border-red-200 bg-red-50 px-3 py-2 dark:border-red-900/50 dark:bg-red-950/30">
177
- <p className="text-sm text-red-800 dark:text-red-200">
178
- Remove &ldquo;{audience.displayName}&rdquo;?
179
- {audience.credentialCount > 0 && (
180
- <> Its {audience.credentialCount === 1 ? "sign-in" : `${audience.credentialCount} sign-ins`} go with it, locking out anyone using them.</>
181
- )}
182
- </p>
183
- <div className="mt-2 flex justify-end gap-2">
184
- <Button variant="secondary" onClick={() => setConfirmingRemove(false)}>Cancel</Button>
185
- <Button variant="destructive" onClick={remove}>Remove</Button>
186
- </div>
178
+ <div className="mt-2">
179
+ <ConfirmInline
180
+ message={
181
+ <>
182
+ Remove &ldquo;{audience.displayName}&rdquo;?
183
+ {audience.credentialCount > 0 && (
184
+ <> Its {audience.credentialCount === 1 ? "sign-in" : `${audience.credentialCount} sign-ins`} go with it, locking out anyone using them.</>
185
+ )}
186
+ </>
187
+ }
188
+ confirmLabel="Remove"
189
+ tone="destructive"
190
+ onConfirm={remove}
191
+ onCancel={() => setConfirmingRemove(false)}
192
+ returnFocusTo={removeButtonRef}
193
+ />
187
194
  </div>
188
195
  )}
189
196
 
@@ -1,8 +1,15 @@
1
1
  import { useState, useCallback, useRef, useEffect } from "react";
2
+ import { AlertTriangle, X } from "lucide-react";
2
3
  import { EditorModal } from "./EditorModal";
3
4
  import { useEditorContext } from "./EditorContext";
4
5
  import { cn } from "../../lib/cn";
5
6
  import Fab from "../shared/Fab";
7
+ import { Notice } from "../shared/Notice";
8
+ import { useNotice } from "../../hooks/useNotice";
9
+ import { COPY } from "../shared/copy";
10
+ import { Button } from "../shared/Button";
11
+ import { IconButton } from "../shared/IconButton";
12
+ import { Textarea } from "../shared/Textarea";
6
13
 
7
14
  type Category = "Visual" | "Unexpected Behavior" | "Media / Media Library" | "Save / Publish" | "Feature Request" | "Other";
8
15
 
@@ -30,7 +37,13 @@ interface ImagePreview {
30
37
  name: string;
31
38
  }
32
39
 
33
- export function BugReportFAB() {
40
+ interface BugReportFABProps {
41
+ /** Renders as a `FabStack` member (relative, no bottom-* of its own)
42
+ * instead of an independently fixed FAB — see FabStack. */
43
+ stacked?: boolean;
44
+ }
45
+
46
+ export function BugReportFAB({ stacked }: BugReportFABProps) {
34
47
  const { isEditMode, historyState } = useEditorContext();
35
48
  const [isOpen, setIsOpen] = useState(false);
36
49
  const [category, setCategory] = useState<Category>("Visual");
@@ -42,9 +55,7 @@ export function BugReportFAB() {
42
55
  const [submitError, setSubmitError] = useState<string | null>(null);
43
56
  const [imageNotice, setImageNotice] = useState<string | null>(null);
44
57
  const [descriptionError, setDescriptionError] = useState<string | null>(null);
45
- const [toast, setToast] = useState<string | null>(null);
46
- const toastTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
47
- useEffect(() => () => { if (toastTimerRef.current) clearTimeout(toastTimerRef.current); }, []);
58
+ const { notice: toast, show: showToast } = useNotice();
48
59
  const capturedContextRef = useRef<CapturedContext | null>(null);
49
60
  const dropZoneRef = useRef<HTMLDivElement>(null);
50
61
 
@@ -186,9 +197,7 @@ export function BugReportFAB() {
186
197
  }
187
198
 
188
199
  handleClose();
189
- setToast("Bug report submitted");
190
- if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
191
- toastTimerRef.current = setTimeout(() => setToast(null), 3000);
200
+ showToast("success", COPY.bugReport.submitted, { ttlMs: 3000 });
192
201
  } catch (err) {
193
202
  setSubmitError(err instanceof Error ? err.message : "Submission failed");
194
203
  } finally {
@@ -204,11 +213,14 @@ export function BugReportFAB() {
204
213
  <>
205
214
  {/* FAB button */}
206
215
  {visible && (
207
- <Fab label="Report a bug" column="editor" className="bottom-28" onClick={handleOpen}>
208
- {/* Bug / beetle SVG icon */}
209
- <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
210
- <path d="M19 8h-1.26A6.003 6.003 0 0012 4a6.003 6.003 0 00-5.74 4H5a1 1 0 000 2h1.05A6.04 6.04 0 006 12H5a1 1 0 000 2h1c0 .34.03.67.08 1H5a1 1 0 000 2h1.26a6 6 0 0011.48 0H19a1 1 0 000-2h-1.08c.05-.33.08-.66.08-1h1a1 1 0 000-2h-1a6.04 6.04 0 00-.05-2H19a1 1 0 000-2zM12 6c1.7 0 3.16.88 4 2.19V8a1 1 0 10-2 0v.04A3.97 3.97 0 0012 8a3.97 3.97 0 00-2 .04V8a1 1 0 10-2 0v.19A4.69 4.69 0 018 6a4 4 0 014 0zm0 14a4 4 0 01-4-4v-4a4 4 0 018 0v4a4 4 0 01-4 4z"/>
211
- </svg>
216
+ <Fab
217
+ label="Report a bug"
218
+ column="editor"
219
+ stacked={stacked}
220
+ className={stacked ? undefined : "bottom-28"}
221
+ onClick={handleOpen}
222
+ >
223
+ <AlertTriangle className="h-5 w-5" aria-hidden="true" />
212
224
  </Fab>
213
225
  )}
214
226
 
@@ -246,7 +258,7 @@ export function BugReportFAB() {
246
258
  className={cn(
247
259
  "relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
248
260
  isCritical
249
- ? "bg-red-600 focus-visible:ring-red-600"
261
+ ? "bg-danger focus-visible:ring-danger"
250
262
  : "bg-base-200 focus-visible:ring-base-200",
251
263
  )}
252
264
  >
@@ -262,24 +274,20 @@ export function BugReportFAB() {
262
274
 
263
275
  {/* Description */}
264
276
  <div>
265
- <label className="mb-1 block text-sm font-medium text-base-contrast" htmlFor="bug-description">
266
- Description
267
- </label>
268
- <textarea
269
- id="bug-description"
277
+ <Textarea
278
+ label="Description"
270
279
  rows={4}
271
280
  value={description}
272
- onChange={(e) => {
273
- setDescription(e.target.value);
274
- if (descriptionError && e.target.value.trim()) {
281
+ onChange={(value) => {
282
+ setDescription(value);
283
+ if (descriptionError && value.trim()) {
275
284
  setDescriptionError(null);
276
285
  }
277
286
  }}
278
287
  placeholder="Describe the issue..."
279
- className="w-full rounded-md border border-base-200 bg-base px-3 py-2 text-sm text-base-contrast placeholder:text-base-contrast/50 resize-none"
280
288
  />
281
289
  {descriptionError && (
282
- <p className="mt-1 text-xs text-red-600">{descriptionError}</p>
290
+ <p className="mt-1 text-xs text-danger">{descriptionError}</p>
283
291
  )}
284
292
  </div>
285
293
 
@@ -304,7 +312,7 @@ export function BugReportFAB() {
304
312
  Drop images here or paste from clipboard
305
313
  </p>
306
314
  </div>
307
- {imageNotice && <p className="mt-1 text-xs text-red-600">{imageNotice}</p>}
315
+ {imageNotice && <p className="mt-1 text-xs text-danger">{imageNotice}</p>}
308
316
 
309
317
  {/* Thumbnail previews */}
310
318
  {images.length > 0 && (
@@ -316,14 +324,13 @@ export function BugReportFAB() {
316
324
  alt={img.name}
317
325
  className="h-16 w-16 rounded object-cover border border-base-200"
318
326
  />
319
- <button
320
- type="button"
327
+ <IconButton
328
+ icon={<X size={12} />}
321
329
  onClick={() => handleRemoveImage(index)}
322
- aria-label={`Remove screenshot ${img.name}`}
323
- className="absolute -top-1.5 -right-1.5 hidden h-5 w-5 items-center justify-center rounded-full bg-red-600 text-white text-xs group-hover:flex"
324
- >
325
- ×
326
- </button>
330
+ label={`Remove screenshot ${img.name}`}
331
+ size="sm"
332
+ className="absolute -top-1.5 -right-1.5 hidden rounded-full bg-danger text-white group-hover:flex"
333
+ />
327
334
  </div>
328
335
  ))}
329
336
  </div>
@@ -332,26 +339,29 @@ export function BugReportFAB() {
332
339
 
333
340
  {/* Submit error */}
334
341
  {submitError && (
335
- <p className="text-sm text-red-600">{submitError}</p>
342
+ <p className="text-sm text-danger">{submitError}</p>
336
343
  )}
337
344
 
338
345
  {/* Submit button */}
339
- <button
346
+ <Button
340
347
  type="button"
348
+ variant="brand"
349
+ size="md"
350
+ fullWidth
341
351
  onClick={handleSubmit}
342
- disabled={isSubmitting}
343
- className="w-full rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-contrast hover:opacity-90 transition-opacity disabled:opacity-60"
352
+ isLoading={isSubmitting}
353
+ loadingLabel="Submitting…"
344
354
  >
345
- {isSubmitting ? "Submitting..." : "Submit"}
346
- </button>
355
+ Submit
356
+ </Button>
347
357
  </div>
348
358
  </EditorModal>
349
359
 
350
360
  {/* Toast */}
351
361
  {toast && (
352
- <div className="fixed bottom-4 left-1/2 z-[60] -translate-x-1/2 rounded-md bg-green-600 px-4 py-2 text-sm font-medium text-white shadow-lg">
353
- {toast}
354
- </div>
362
+ <Notice tone="success" placement="toast">
363
+ {toast.message}
364
+ </Notice>
355
365
  )}
356
366
  </>
357
367
  );