@drawnagency/primitives 0.1.118 → 0.1.120

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 (279) hide show
  1. package/dist/{chunk-O37AV27P.js → chunk-5JYHTHVR.js} +28 -0
  2. package/dist/{chunk-W72BPGR3.js → chunk-BZKHHUIN.js} +44 -8
  3. package/dist/{chunk-4NSOKEA7.js → chunk-HFHM4MNK.js} +12 -7
  4. package/dist/{chunk-CEFFP3CH.js → chunk-HZTPF6OK.js} +304 -83
  5. package/dist/{chunk-RIITGTV3.js → chunk-LQHBC7C6.js} +37 -2
  6. package/dist/{chunk-VY3IFGE3.js → chunk-QAMAIDXZ.js} +1 -1
  7. package/dist/{chunk-HRX3XJBU.js → chunk-RIN2QCYJ.js} +9 -11
  8. package/dist/{chunk-ZOTRHHUB.js → chunk-UNFPATDE.js} +8 -10
  9. package/dist/{chunk-ERLIL4RU.js → chunk-UZBFVVTC.js} +35 -37
  10. package/dist/{chunk-67P34WNW.js → chunk-ZKVQMIMJ.js} +3 -20
  11. package/dist/collab/rebase.js +4 -5
  12. package/dist/components/chat/ChatComposer.d.ts +0 -4
  13. package/dist/components/chat/ChatComposer.d.ts.map +1 -1
  14. package/dist/components/chat/ChatPanel.d.ts +2 -3
  15. package/dist/components/chat/ChatPanel.d.ts.map +1 -1
  16. package/dist/components/chat/markdown.d.ts +2 -3
  17. package/dist/components/chat/markdown.d.ts.map +1 -1
  18. package/dist/components/editor/AudienceIndicator.d.ts +3 -1
  19. package/dist/components/editor/AudienceIndicator.d.ts.map +1 -1
  20. package/dist/components/editor/IndicatorPill.d.ts +3 -1
  21. package/dist/components/editor/IndicatorPill.d.ts.map +1 -1
  22. package/dist/components/editor/PagesModal.d.ts +0 -2
  23. package/dist/components/editor/PagesModal.d.ts.map +1 -1
  24. package/dist/components/editor/SectionBulkEditModal.d.ts +25 -0
  25. package/dist/components/editor/SectionBulkEditModal.d.ts.map +1 -0
  26. package/dist/components/editor/StatusIndicator.d.ts +3 -1
  27. package/dist/components/editor/StatusIndicator.d.ts.map +1 -1
  28. package/dist/components/editor/index.js +28 -26
  29. package/dist/components/primitives/index.js +11 -15
  30. package/dist/components/sections/brand-guide.js +10 -13
  31. package/dist/components/sections/register-schemas.js +16 -21
  32. package/dist/components/sections/register.js +16 -21
  33. package/dist/components/shared/Popover.d.ts +1 -1
  34. package/dist/components/shared/Popover.d.ts.map +1 -1
  35. package/dist/components/shared/SectionSummaryRow.d.ts +1 -1
  36. package/dist/components/shell/AudienceChips.d.ts +1 -3
  37. package/dist/components/shell/AudienceChips.d.ts.map +1 -1
  38. package/dist/components/shell/EditorModal.d.ts.map +1 -1
  39. package/dist/components/shell/EditorShell.d.ts +0 -34
  40. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  41. package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
  42. package/dist/hooks/useSortableNavRow.d.ts +1 -1
  43. package/dist/hooks/useSortableRow.d.ts +1 -1
  44. package/dist/index.js +83 -90
  45. package/dist/lib/index-ops.js +5 -6
  46. package/dist/lib/index.js +27 -32
  47. package/dist/lib/pages.d.ts +0 -2
  48. package/dist/lib/pages.d.ts.map +1 -1
  49. package/dist/lib/sidecars.js +2 -2
  50. package/dist/lib/site-validation.js +13 -14
  51. package/dist/lib/storage-tier.js +4 -4
  52. package/dist/schemas/index.js +42 -45
  53. package/dist/schemas/site-config.d.ts +1 -277
  54. package/dist/schemas/site-config.d.ts.map +1 -1
  55. package/package.json +2 -42
  56. package/src/components/chat/ChatComposer.tsx +0 -4
  57. package/src/components/chat/ChatPanel.tsx +2 -3
  58. package/src/components/chat/markdown.ts +2 -3
  59. package/src/components/editor/AudienceIndicator.tsx +8 -4
  60. package/src/components/editor/IndicatorPill.tsx +4 -0
  61. package/src/components/editor/PagesModal.tsx +1 -15
  62. package/src/components/editor/SectionBulkEditModal.tsx +328 -0
  63. package/src/components/editor/StatusIndicator.tsx +7 -6
  64. package/src/components/shared/Popover.tsx +17 -4
  65. package/src/components/shared/SectionSummaryRow.tsx +1 -1
  66. package/src/components/shell/AudienceChips.tsx +1 -3
  67. package/src/components/shell/EditorModal.tsx +5 -2
  68. package/src/components/shell/EditorShell.tsx +15 -119
  69. package/src/components/shell/SiteSettingsModal.tsx +0 -11
  70. package/src/lib/pages.ts +0 -22
  71. package/src/schemas/index.ts +0 -4
  72. package/src/schemas/site-config.ts +4 -32
  73. package/dist/chunk-4TZJZU2T.js +0 -92
  74. package/dist/chunk-DIMDRBFK.js +0 -11
  75. package/dist/chunk-FV7JQRCN.js +0 -94
  76. package/dist/chunk-IIDKW7AV.js +0 -41
  77. package/dist/chunk-JCDZAFX2.js +0 -224
  78. package/dist/chunk-MM7KZS5C.js +0 -30
  79. package/dist/chunk-QQ3S3P5P.js +0 -38
  80. package/dist/chunk-TEOAKGZA.js +0 -784
  81. package/dist/chunk-VAYZJKVR.js +0 -209
  82. package/dist/components/editor/SectionOrderingModal.d.ts +0 -10
  83. package/dist/components/editor/SectionOrderingModal.d.ts.map +0 -1
  84. package/dist/components/shell/DocInspector.d.ts +0 -18
  85. package/dist/components/shell/DocInspector.d.ts.map +0 -1
  86. package/dist/components/shell/DocumentEditorOverlay.d.ts +0 -29
  87. package/dist/components/shell/DocumentEditorOverlay.d.ts.map +0 -1
  88. package/dist/components/shell/DocumentPresentOverlay.d.ts +0 -30
  89. package/dist/components/shell/DocumentPresentOverlay.d.ts.map +0 -1
  90. package/dist/components/shell/SiteSettingsDecks.d.ts +0 -13
  91. package/dist/components/shell/SiteSettingsDecks.d.ts.map +0 -1
  92. package/dist/deck/DeckComponentView.d.ts +0 -13
  93. package/dist/deck/DeckComponentView.d.ts.map +0 -1
  94. package/dist/deck/DeckPlayer.d.ts +0 -26
  95. package/dist/deck/DeckPlayer.d.ts.map +0 -1
  96. package/dist/deck/DeckSlideView.d.ts +0 -17
  97. package/dist/deck/DeckSlideView.d.ts.map +0 -1
  98. package/dist/deck/DeckStage.d.ts +0 -16
  99. package/dist/deck/DeckStage.d.ts.map +0 -1
  100. package/dist/deck/components/DeckImage.d.ts +0 -14
  101. package/dist/deck/components/DeckImage.d.ts.map +0 -1
  102. package/dist/deck/components/DeckImageGrid.d.ts +0 -27
  103. package/dist/deck/components/DeckImageGrid.d.ts.map +0 -1
  104. package/dist/deck/components/DeckRichText.d.ts +0 -22
  105. package/dist/deck/components/DeckRichText.d.ts.map +0 -1
  106. package/dist/deck/components/DeckVideo.d.ts +0 -15
  107. package/dist/deck/components/DeckVideo.d.ts.map +0 -1
  108. package/dist/deck/editing.d.ts +0 -50
  109. package/dist/deck/editing.d.ts.map +0 -1
  110. package/dist/deck/flip.d.ts +0 -11
  111. package/dist/deck/flip.d.ts.map +0 -1
  112. package/dist/deck/index.d.ts +0 -24
  113. package/dist/deck/index.d.ts.map +0 -1
  114. package/dist/deck/index.js +0 -51
  115. package/dist/deck/layouts/CenteredTextLayout.d.ts +0 -12
  116. package/dist/deck/layouts/CenteredTextLayout.d.ts.map +0 -1
  117. package/dist/deck/layouts/ColumnSplitLayout.d.ts +0 -14
  118. package/dist/deck/layouts/ColumnSplitLayout.d.ts.map +0 -1
  119. package/dist/deck/layouts/FullBleedImageLayout.d.ts +0 -14
  120. package/dist/deck/layouts/FullBleedImageLayout.d.ts.map +0 -1
  121. package/dist/deck/media.d.ts +0 -33
  122. package/dist/deck/media.d.ts.map +0 -1
  123. package/dist/deck/tokens.d.ts +0 -22
  124. package/dist/deck/tokens.d.ts.map +0 -1
  125. package/dist/deck/useStageScale.d.ts +0 -10
  126. package/dist/deck/useStageScale.d.ts.map +0 -1
  127. package/dist/deck-builder/DeckBuilderApp.d.ts +0 -30
  128. package/dist/deck-builder/DeckBuilderApp.d.ts.map +0 -1
  129. package/dist/deck-builder/DeckBuilderTopBar.d.ts +0 -24
  130. package/dist/deck-builder/DeckBuilderTopBar.d.ts.map +0 -1
  131. package/dist/deck-builder/DeckChatPanel.d.ts +0 -45
  132. package/dist/deck-builder/DeckChatPanel.d.ts.map +0 -1
  133. package/dist/deck-builder/DeckEditor.d.ts +0 -37
  134. package/dist/deck-builder/DeckEditor.d.ts.map +0 -1
  135. package/dist/deck-builder/DeckLibrary.d.ts +0 -22
  136. package/dist/deck-builder/DeckLibrary.d.ts.map +0 -1
  137. package/dist/deck-builder/DeckSlideSurface.d.ts +0 -31
  138. package/dist/deck-builder/DeckSlideSurface.d.ts.map +0 -1
  139. package/dist/deck-builder/deck-api.d.ts +0 -76
  140. package/dist/deck-builder/deck-api.d.ts.map +0 -1
  141. package/dist/deck-builder/deck-chat-client.d.ts +0 -44
  142. package/dist/deck-builder/deck-chat-client.d.ts.map +0 -1
  143. package/dist/deck-builder/deck-chat-history.d.ts +0 -10
  144. package/dist/deck-builder/deck-chat-history.d.ts.map +0 -1
  145. package/dist/deck-builder/index.d.ts +0 -13
  146. package/dist/deck-builder/index.d.ts.map +0 -1
  147. package/dist/deck-builder/index.js +0 -1498
  148. package/dist/deck-builder/starter-deck.d.ts +0 -23
  149. package/dist/deck-builder/starter-deck.d.ts.map +0 -1
  150. package/dist/deck-builder/types.d.ts +0 -29
  151. package/dist/deck-builder/types.d.ts.map +0 -1
  152. package/dist/deck-builder/useSortableSlide.d.ts +0 -29
  153. package/dist/deck-builder/useSortableSlide.d.ts.map +0 -1
  154. package/dist/document/assets/fonts/albra-grotesk-bold.woff +0 -0
  155. package/dist/document/assets/fonts/albra-grotesk-regular.woff +0 -0
  156. package/dist/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
  157. package/dist/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
  158. package/dist/document/components/DocCoverPage.d.ts +0 -11
  159. package/dist/document/components/DocCoverPage.d.ts.map +0 -1
  160. package/dist/document/components/DocPage.d.ts +0 -10
  161. package/dist/document/components/DocPage.d.ts.map +0 -1
  162. package/dist/document/components/DocRail.d.ts +0 -28
  163. package/dist/document/components/DocRail.d.ts.map +0 -1
  164. package/dist/document/components/DocSectionPage.d.ts +0 -12
  165. package/dist/document/components/DocSectionPage.d.ts.map +0 -1
  166. package/dist/document/components/DocViewer.d.ts +0 -21
  167. package/dist/document/components/DocViewer.d.ts.map +0 -1
  168. package/dist/document/components/Wordmark.d.ts +0 -4
  169. package/dist/document/components/Wordmark.d.ts.map +0 -1
  170. package/dist/document/components/measure.d.ts +0 -7
  171. package/dist/document/components/measure.d.ts.map +0 -1
  172. package/dist/document/components/useDocPages.d.ts +0 -12
  173. package/dist/document/components/useDocPages.d.ts.map +0 -1
  174. package/dist/document/engine/blocks.d.ts +0 -2
  175. package/dist/document/engine/blocks.d.ts.map +0 -1
  176. package/dist/document/engine/harvest.d.ts +0 -3
  177. package/dist/document/engine/harvest.d.ts.map +0 -1
  178. package/dist/document/engine/masonry.d.ts +0 -26
  179. package/dist/document/engine/masonry.d.ts.map +0 -1
  180. package/dist/document/engine/paginate.d.ts +0 -43
  181. package/dist/document/engine/paginate.d.ts.map +0 -1
  182. package/dist/document/engine/settings.d.ts +0 -91
  183. package/dist/document/engine/settings.d.ts.map +0 -1
  184. package/dist/document/engine/types.d.ts +0 -44
  185. package/dist/document/engine/types.d.ts.map +0 -1
  186. package/dist/document/index.d.ts +0 -13
  187. package/dist/document/index.d.ts.map +0 -1
  188. package/dist/document/index.js +0 -1030
  189. package/dist/document/styles/document.css +0 -217
  190. package/dist/lib/deck-access.d.ts +0 -86
  191. package/dist/lib/deck-access.d.ts.map +0 -1
  192. package/dist/lib/deck-access.js +0 -58
  193. package/dist/lib/deck-dexie.d.ts +0 -88
  194. package/dist/lib/deck-dexie.d.ts.map +0 -1
  195. package/dist/lib/deck-dexie.js +0 -22
  196. package/dist/lib/deck-edit.d.ts +0 -67
  197. package/dist/lib/deck-edit.d.ts.map +0 -1
  198. package/dist/lib/deck-media-assets.d.ts +0 -27
  199. package/dist/lib/deck-media-assets.d.ts.map +0 -1
  200. package/dist/lib/deck-media-assets.js +0 -25
  201. package/dist/lib/deck-media-refs.d.ts +0 -35
  202. package/dist/lib/deck-media-refs.d.ts.map +0 -1
  203. package/dist/lib/deck-media-refs.js +0 -36
  204. package/dist/lib/deck-tool.d.ts +0 -25
  205. package/dist/lib/deck-tool.d.ts.map +0 -1
  206. package/dist/lib/deck-tool.js +0 -58
  207. package/dist/lib/document-input.d.ts +0 -25
  208. package/dist/lib/document-input.d.ts.map +0 -1
  209. package/dist/schemas/deck-meta.d.ts +0 -85
  210. package/dist/schemas/deck-meta.d.ts.map +0 -1
  211. package/dist/schemas/deck-meta.js +0 -64
  212. package/dist/schemas/deck.d.ts +0 -954
  213. package/dist/schemas/deck.d.ts.map +0 -1
  214. package/dist/schemas/deck.js +0 -65
  215. package/src/components/editor/SectionOrderingModal.tsx +0 -80
  216. package/src/components/shell/DocInspector.tsx +0 -314
  217. package/src/components/shell/DocumentEditorOverlay.tsx +0 -179
  218. package/src/components/shell/DocumentPresentOverlay.tsx +0 -87
  219. package/src/components/shell/SiteSettingsDecks.tsx +0 -41
  220. package/src/deck/DeckComponentView.tsx +0 -28
  221. package/src/deck/DeckPlayer.tsx +0 -166
  222. package/src/deck/DeckSlideView.tsx +0 -38
  223. package/src/deck/DeckStage.tsx +0 -39
  224. package/src/deck/components/DeckImage.tsx +0 -38
  225. package/src/deck/components/DeckImageGrid.tsx +0 -254
  226. package/src/deck/components/DeckRichText.tsx +0 -111
  227. package/src/deck/components/DeckVideo.tsx +0 -81
  228. package/src/deck/editing.tsx +0 -201
  229. package/src/deck/flip.ts +0 -70
  230. package/src/deck/index.ts +0 -30
  231. package/src/deck/layouts/CenteredTextLayout.tsx +0 -29
  232. package/src/deck/layouts/ColumnSplitLayout.tsx +0 -69
  233. package/src/deck/layouts/FullBleedImageLayout.tsx +0 -58
  234. package/src/deck/media.tsx +0 -46
  235. package/src/deck/tokens.ts +0 -57
  236. package/src/deck/useStageScale.ts +0 -44
  237. package/src/deck-builder/DeckBuilderApp.tsx +0 -572
  238. package/src/deck-builder/DeckBuilderTopBar.tsx +0 -62
  239. package/src/deck-builder/DeckChatPanel.tsx +0 -334
  240. package/src/deck-builder/DeckEditor.tsx +0 -258
  241. package/src/deck-builder/DeckLibrary.tsx +0 -195
  242. package/src/deck-builder/DeckSlideSurface.tsx +0 -55
  243. package/src/deck-builder/deck-api.ts +0 -177
  244. package/src/deck-builder/deck-chat-client.ts +0 -129
  245. package/src/deck-builder/deck-chat-history.ts +0 -62
  246. package/src/deck-builder/index.ts +0 -12
  247. package/src/deck-builder/starter-deck.ts +0 -86
  248. package/src/deck-builder/types.ts +0 -24
  249. package/src/deck-builder/useSortableSlide.ts +0 -102
  250. package/src/document/assets/fonts/albra-grotesk-bold.woff +0 -0
  251. package/src/document/assets/fonts/albra-grotesk-regular.woff +0 -0
  252. package/src/document/assets/fonts/kapra-neue-expanded-medium.woff +0 -0
  253. package/src/document/assets/fonts/kapra-neue-expanded-regular.woff +0 -0
  254. package/src/document/components/DocCoverPage.tsx +0 -45
  255. package/src/document/components/DocPage.tsx +0 -40
  256. package/src/document/components/DocRail.tsx +0 -189
  257. package/src/document/components/DocSectionPage.tsx +0 -48
  258. package/src/document/components/DocViewer.tsx +0 -313
  259. package/src/document/components/Wordmark.tsx +0 -18
  260. package/src/document/components/measure.tsx +0 -133
  261. package/src/document/components/useDocPages.ts +0 -95
  262. package/src/document/engine/blocks.ts +0 -116
  263. package/src/document/engine/harvest.ts +0 -95
  264. package/src/document/engine/masonry.ts +0 -158
  265. package/src/document/engine/paginate.ts +0 -232
  266. package/src/document/engine/settings.ts +0 -125
  267. package/src/document/engine/types.ts +0 -64
  268. package/src/document/index.ts +0 -18
  269. package/src/document/styles/document.css +0 -217
  270. package/src/lib/deck-access.ts +0 -132
  271. package/src/lib/deck-dexie.ts +0 -190
  272. package/src/lib/deck-edit.ts +0 -196
  273. package/src/lib/deck-media-assets.ts +0 -57
  274. package/src/lib/deck-media-refs.ts +0 -67
  275. package/src/lib/deck-tool.ts +0 -95
  276. package/src/lib/document-input.ts +0 -57
  277. package/src/schemas/deck-meta.ts +0 -88
  278. package/src/schemas/deck.ts +0 -478
  279. package/dist/{chunk-DJABADOO.js → chunk-AJ2QOAZI.js} +3 -3
@@ -1 +0,0 @@
1
- {"version":3,"file":"deck.d.ts","sourceRoot":"","sources":["../../src/schemas/deck.ts"],"names":[],"mappings":"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"}
@@ -1,65 +0,0 @@
1
- import {
2
- CenteredTextLayoutSchema,
3
- ColumnSplitLayoutSchema,
4
- DECK_COMPONENT_TYPES,
5
- DECK_LAYOUT_TYPES,
6
- DECK_MAX_SLIDES,
7
- DECK_MEDIA_KINDS,
8
- DECK_OVERLAY_PLACEMENTS,
9
- DECK_SCHEMA_VERSION,
10
- DECK_SPLIT_RATIOS,
11
- DECK_STAGE_HEIGHT,
12
- DECK_STAGE_WIDTH,
13
- DECK_SURFACES,
14
- DeckComponentSchema,
15
- DeckIdSchema,
16
- DeckImageGridItemSchema,
17
- DeckImageGridSchema,
18
- DeckImageSchema,
19
- DeckLayoutSchema,
20
- DeckMediaRefSchema,
21
- DeckOverlayPanelSchema,
22
- DeckRichTextSchema,
23
- DeckSchema,
24
- DeckSlideSchema,
25
- DeckTextSpanSchema,
26
- DeckVideoSchema,
27
- FullBleedImageLayoutSchema,
28
- PortalMediaRefSchema,
29
- formatDeckIssues,
30
- parseDeck,
31
- serializeDeck
32
- } from "../chunk-VAYZJKVR.js";
33
- import "../chunk-JSBRDJBE.js";
34
- export {
35
- CenteredTextLayoutSchema,
36
- ColumnSplitLayoutSchema,
37
- DECK_COMPONENT_TYPES,
38
- DECK_LAYOUT_TYPES,
39
- DECK_MAX_SLIDES,
40
- DECK_MEDIA_KINDS,
41
- DECK_OVERLAY_PLACEMENTS,
42
- DECK_SCHEMA_VERSION,
43
- DECK_SPLIT_RATIOS,
44
- DECK_STAGE_HEIGHT,
45
- DECK_STAGE_WIDTH,
46
- DECK_SURFACES,
47
- DeckComponentSchema,
48
- DeckIdSchema,
49
- DeckImageGridItemSchema,
50
- DeckImageGridSchema,
51
- DeckImageSchema,
52
- DeckLayoutSchema,
53
- DeckMediaRefSchema,
54
- DeckOverlayPanelSchema,
55
- DeckRichTextSchema,
56
- DeckSchema,
57
- DeckSlideSchema,
58
- DeckTextSpanSchema,
59
- DeckVideoSchema,
60
- FullBleedImageLayoutSchema,
61
- PortalMediaRefSchema,
62
- formatDeckIssues,
63
- parseDeck,
64
- serializeDeck
65
- };
@@ -1,80 +0,0 @@
1
- import type { LoadedSection } from "../../lib/loader";
2
- import { getSection } from "../../lib/registry";
3
- import type { MediaManifest } from "../../media/types";
4
- import { DragHandle } from "./DragHandle";
5
- import { useSortableRow } from "../../hooks/useSortableRow";
6
- import { DropEdgeIndicator } from "./DropEdgeIndicator";
7
- import { SectionSummaryRow } from "../shared/SectionSummaryRow";
8
- import { toThumbViews } from "../../lib/thumb-views";
9
- import { cn } from "../../lib/cn";
10
-
11
- interface SectionOrderingModalProps {
12
- sections: LoadedSection[];
13
- mediaManifest: MediaManifest;
14
- onReorder: (fromIndex: number, toIndex: number) => void;
15
- }
16
-
17
- function SectionRow({
18
- section,
19
- index,
20
- mediaManifest,
21
- onReorder,
22
- }: {
23
- section: LoadedSection;
24
- index: number;
25
- mediaManifest: MediaManifest;
26
- onReorder: (fromIndex: number, toIndex: number) => void;
27
- }) {
28
- const { rowRef, handleRef, isDragging, closestEdge } = useSortableRow<HTMLDivElement, HTMLButtonElement>({
29
- index,
30
- dragType: "ordering-row",
31
- onReorder,
32
- });
33
-
34
- const definition = getSection(section.section.type);
35
- const label = definition?.getLabel?.(section.section) ?? definition?.label ?? section.section.type;
36
- const typeLabel = definition?.label ?? section.section.type;
37
-
38
- return (
39
- <div
40
- ref={rowRef}
41
- className={cn(
42
- "relative flex items-center gap-1",
43
- isDragging && "opacity-50",
44
- )}
45
- >
46
- <DropEdgeIndicator edge={closestEdge} />
47
-
48
- <div className="shrink-0 [&_[role=tooltip]]:hidden">
49
- <DragHandle ref={handleRef} />
50
- </div>
51
-
52
- <SectionSummaryRow
53
- label={label}
54
- typeLabel={typeLabel}
55
- thumbnails={toThumbViews(definition?.getThumbnails?.(section.section) ?? [], mediaManifest)}
56
- className={cn(isDragging && "outline outline-2 outline-primary/50")}
57
- />
58
- </div>
59
- );
60
- }
61
-
62
- export function SectionOrderingModal({
63
- sections,
64
- mediaManifest,
65
- onReorder,
66
- }: SectionOrderingModalProps) {
67
- return (
68
- <div className="flex flex-col gap-2 overflow-y-auto">
69
- {sections.map((loadedSection, index) => (
70
- <SectionRow
71
- key={loadedSection.section.id}
72
- section={loadedSection}
73
- index={index}
74
- mediaManifest={mediaManifest}
75
- onReorder={onReorder}
76
- />
77
- ))}
78
- </div>
79
- );
80
- }
@@ -1,314 +0,0 @@
1
- import { settingsFor, type DocumentOptions } from "../../document";
2
- import { Input } from "../shared/Input";
3
- import { Select } from "../shared/Select";
4
- import { Checkbox } from "../shared/Checkbox";
5
- import { RadioGroup } from "../shared/RadioGroup";
6
- import { ColorPicker } from "../shared/ColorPicker";
7
- import { FormLabel } from "../shared/FormLabel";
8
- import { useMediaLibrary } from "./MediaLibraryContext";
9
- import { Button } from "../shared/Button";
10
- import { imageThumbnailUrl } from "../../media/utils";
11
-
12
-
13
- export interface DocInspectorProps {
14
- document: DocumentOptions;
15
- selection: { kind: "cover" } | { kind: "chunk"; chunkId: string; title: string; depth?: number };
16
- warnings: string[]; // warningsByChunk for the selected chunk
17
- onUpdateCover: (patch: Partial<DocumentOptions["cover"]>) => void;
18
- onUpdateMeta: (patch: Partial<DocumentOptions["meta"]>) => void;
19
- // Caller merges the patch via sectionSettingsSchema.parse.
20
- onUpdateSection: (chunkId: string, patch: Record<string, unknown>) => void;
21
- }
22
-
23
- // Drawn palette — mirrors the swatch row in the harness inspector.
24
- const SWATCHES = [
25
- "#FFFFFF", "#EBEBEB", "#999999", "#333333", "#1F1F1F", // neutrals: white → near-black
26
- "#009FAD", // teal (brand primary)
27
- "#3D7F7F", // forest
28
- "#099A6F", // green
29
- "#5F81AB", // blue
30
- "#7C97BB", // sky
31
- "#6864A0", // violet
32
- "#D3A978", // beige
33
- "#EB9500", // gold
34
- "#F07C00", // orange
35
- "#A24E16", // brown / rust
36
- "#A65982", // indigo
37
- "#E64165", // pink
38
- ];
39
-
40
- function ColorControl({ label, value, onPick }: { label: string; value: string; onPick: (v: string) => void }) {
41
- return (
42
- <div className="mb-4">
43
- <FormLabel>{label}</FormLabel>
44
- <div className="flex flex-wrap items-center gap-1">
45
- {SWATCHES.map((s) => (
46
- <button
47
- key={s}
48
- type="button"
49
- aria-label={s}
50
- onClick={() => onPick(s)}
51
- style={{ background: s }}
52
- className={`h-6 w-6 rounded border ${s === value ? "border-primary ring-1 ring-primary" : "border-base-200"}`}
53
- />
54
- ))}
55
- <ColorPicker value={value} onChange={onPick} label="Custom color" className="h-6 w-6" />
56
- </div>
57
- </div>
58
- );
59
- }
60
-
61
- export function DocInspector({
62
- document: doc,
63
- selection,
64
- warnings,
65
- onUpdateCover,
66
- onUpdateMeta,
67
- onUpdateSection,
68
- }: DocInspectorProps) {
69
- return (
70
- <aside data-testid="doc-inspector" className="w-64 shrink-0 overflow-y-auto border-l border-base-200 bg-base p-4">
71
- {selection.kind === "cover" ? (
72
- <CoverPanel doc={doc} onUpdateCover={onUpdateCover} onUpdateMeta={onUpdateMeta} />
73
- ) : (
74
- <ChunkPanel
75
- key={selection.chunkId}
76
- chunkId={selection.chunkId}
77
- title={selection.title}
78
- depth={selection.depth}
79
- doc={doc}
80
- warnings={warnings}
81
- onUpdateSection={onUpdateSection}
82
- />
83
- )}
84
- </aside>
85
- );
86
- }
87
-
88
- function CoverPanel({
89
- doc,
90
- onUpdateCover,
91
- onUpdateMeta,
92
- }: {
93
- doc: DocumentOptions;
94
- onUpdateCover: (patch: Partial<DocumentOptions["cover"]>) => void;
95
- onUpdateMeta: (patch: Partial<DocumentOptions["meta"]>) => void;
96
- }) {
97
- const { cover, meta } = doc;
98
- const media = useMediaLibrary();
99
- return (
100
- <>
101
- <h2 className="mb-2 text-xs font-semibold uppercase tracking-wide text-base-contrast-light">Cover</h2>
102
- <Input label="Title" value={cover.title} onChange={(title) => onUpdateCover({ title })} className="mb-2" />
103
- <Input label="Label" value={cover.label} onChange={(label) => onUpdateCover({ label })} className="mb-2" />
104
- <Input label="Date" value={cover.date} onChange={(date) => onUpdateCover({ date })} className="mb-2" />
105
-
106
- {media ? (
107
- <div className="mb-4">
108
- <FormLabel>Cover image</FormLabel>
109
- {cover.imageId ? (
110
- (() => {
111
- const src = imageThumbnailUrl(media.manifest.images[cover.imageId]);
112
- return src ? (
113
- <img src={src} alt="Cover image preview" className="mb-2 max-h-24 rounded border border-base-200" />
114
- ) : null;
115
- })()
116
- ) : null}
117
- <div className="flex gap-2">
118
- <Button
119
- variant="secondary"
120
- size="sm"
121
- onClick={() => media.openSelectModal((imageId) => onUpdateCover({ imageId }))}
122
- >
123
- {cover.imageId ? "Replace image" : "Choose image"}
124
- </Button>
125
- {cover.imageId ? (
126
- <Button variant="ghost" size="sm" onClick={() => onUpdateCover({ imageId: null })}>
127
- Remove image
128
- </Button>
129
- ) : null}
130
- </div>
131
- </div>
132
- ) : null}
133
-
134
- <ColorControl label="Background" value={cover.bgColor} onPick={(bgColor) => onUpdateCover({ bgColor })} />
135
- <ColorControl label="Accent" value={cover.accentColor} onPick={(accentColor) => onUpdateCover({ accentColor })} />
136
-
137
- <h2 className="mb-2 mt-6 text-xs font-semibold uppercase tracking-wide text-base-contrast-light">Document</h2>
138
- <Input label="Client" value={meta.client} onChange={(client) => onUpdateMeta({ client })} className="mb-2" />
139
- <Input label="Project" value={meta.project} onChange={(project) => onUpdateMeta({ project })} className="mb-2" />
140
- <Input label="Date label" value={meta.dateLabel} onChange={(dateLabel) => onUpdateMeta({ dateLabel })} className="mb-2" />
141
- </>
142
- );
143
- }
144
-
145
- function ChunkPanel({
146
- chunkId,
147
- title,
148
- depth,
149
- doc,
150
- warnings,
151
- onUpdateSection,
152
- }: {
153
- chunkId: string;
154
- title: string;
155
- depth?: number;
156
- doc: DocumentOptions;
157
- warnings: string[];
158
- onUpdateSection: (chunkId: string, patch: Record<string, unknown>) => void;
159
- }) {
160
- const settings = settingsFor(doc.sections, chunkId);
161
- const layout = settings.imageLayout;
162
-
163
- return (
164
- <>
165
- <h2 className="mb-3 text-xs font-semibold uppercase tracking-wide text-base-contrast-light">{title}</h2>
166
-
167
- <Checkbox
168
- className="mb-4"
169
- checked={!settings.excluded}
170
- onChange={(checked) => onUpdateSection(chunkId, { excluded: !checked })}
171
- label="Include in document"
172
- />
173
-
174
- {/* Only parent sections own the boundary setting — a sub-page can't
175
- split further, and its entry would be inert anyway (harvest reads
176
- splitAt from parent ids only). */}
177
- {(depth ?? 0) === 0 ? (
178
- <Select
179
- className="mb-4"
180
- label="Split pages at"
181
- value={settings.splitAt}
182
- options={[
183
- { value: "none", label: "Off" },
184
- { value: "sub_heading", label: "Sub-headings" },
185
- ]}
186
- onChange={(splitAt) => onUpdateSection(chunkId, { splitAt })}
187
- />
188
- ) : null}
189
-
190
- {/* Image placement is linked, not independent (Drew, 2026-07-19): text
191
- left → images right of the column, text top → images below full
192
- width. One control drives both fields. */}
193
- <RadioGroup
194
- className="mb-4"
195
- label="Text placement"
196
- value={settings.textPlacement}
197
- options={[
198
- { label: "Top", value: "top" },
199
- { label: "Left column", value: "leftColumn" },
200
- ]}
201
- onChange={(textPlacement) =>
202
- onUpdateSection(chunkId, {
203
- textPlacement,
204
- imagePlacement: textPlacement === "leftColumn" ? "right" : "fullWidth",
205
- })
206
- }
207
- />
208
-
209
- <Checkbox
210
- className="mb-4"
211
- checked={settings.dropTextOverflow}
212
- onChange={(dropTextOverflow) => onUpdateSection(chunkId, { dropTextOverflow })}
213
- label="Drop text overflow"
214
- />
215
-
216
- <Select
217
- className="mb-4"
218
- label="Image layout"
219
- value={layout.mode}
220
- options={[
221
- { value: "grid", label: "Grid" },
222
- { value: "masonry", label: "Masonry" },
223
- ]}
224
- onChange={(v) =>
225
- onUpdateSection(
226
- chunkId,
227
- v === "grid"
228
- ? { imageLayout: { mode: "grid", rows: 2, columns: 4 } }
229
- : { imageLayout: { mode: "masonry", flow: "rows", columns: 3 } },
230
- )
231
- }
232
- />
233
-
234
- {layout.mode === "grid" ? (
235
- <>
236
- <Select
237
- className="mb-4"
238
- label="Rows"
239
- value={String(layout.rows)}
240
- options={[1, 2, 3].map((n) => ({ value: String(n), label: String(n) }))}
241
- onChange={(v) => onUpdateSection(chunkId, { imageLayout: { ...layout, rows: Number(v) } })}
242
- />
243
- <Select
244
- className="mb-4"
245
- label="Columns"
246
- value={String(layout.columns)}
247
- options={[2, 3, 4].map((n) => ({ value: String(n), label: String(n) }))}
248
- onChange={(v) => onUpdateSection(chunkId, { imageLayout: { ...layout, columns: Number(v) } })}
249
- />
250
- <Select
251
- className="mb-4"
252
- label="Image fit"
253
- value={layout.fit}
254
- options={[
255
- { value: "cover", label: "Crop" },
256
- { value: "contain", label: "Contain" },
257
- ]}
258
- onChange={(v) => onUpdateSection(chunkId, { imageLayout: { ...layout, fit: v } })}
259
- />
260
- </>
261
- ) : (
262
- <>
263
- <Select
264
- className="mb-4"
265
- label="Flow"
266
- value={layout.flow}
267
- options={[
268
- { value: "rows", label: "Rows" },
269
- { value: "columns", label: "Columns" },
270
- ]}
271
- onChange={(v) => onUpdateSection(chunkId, { imageLayout: { ...layout, flow: v } })}
272
- />
273
- {/* Rows count only drives the rows flow; "auto" keeps the greedy
274
- target-height fill. Mirrors Columns, which only drives columns. */}
275
- {layout.flow === "rows" ? (
276
- <Select
277
- className="mb-4"
278
- label="Rows"
279
- value={String(layout.rows)}
280
- options={[
281
- { value: "auto", label: "Auto" },
282
- ...[1, 2, 3, 4].map((n) => ({ value: String(n), label: String(n) })),
283
- ]}
284
- onChange={(v) =>
285
- onUpdateSection(chunkId, { imageLayout: { ...layout, rows: v === "auto" ? "auto" : Number(v) } })
286
- }
287
- />
288
- ) : null}
289
- {/* Column count only drives the columns flow (layoutRows never reads
290
- it) — hide it when irrelevant. */}
291
- {layout.flow === "columns" ? (
292
- <Select
293
- className="mb-4"
294
- label="Columns"
295
- value={String(layout.columns)}
296
- options={[2, 3, 4, 5, 6].map((n) => ({ value: String(n), label: String(n) }))}
297
- onChange={(v) => onUpdateSection(chunkId, { imageLayout: { ...layout, columns: Number(v) } })}
298
- />
299
- ) : null}
300
- </>
301
- )}
302
-
303
- {warnings.length > 0 ? (
304
- <div className="mt-2">
305
- {warnings.map((w, i) => (
306
- <p key={i} className="mb-1 rounded border border-warning bg-warning-bg px-2 py-1 text-xs text-warning">
307
- {w}
308
- </p>
309
- ))}
310
- </div>
311
- ) : null}
312
- </>
313
- );
314
- }
@@ -1,179 +0,0 @@
1
- import { useCallback, useMemo, useRef, useState } from "react";
2
- import type { Page } from "../../schemas/site-config";
3
- import type { MediaManifest } from "../../media/types";
4
- import type { LoadedSection } from "../../lib/loader";
5
- import {
6
- DocViewer,
7
- documentOptionsSchema,
8
- sectionSettingsSchema,
9
- settingsFor,
10
- type Chunk,
11
- type DocHost,
12
- type DocumentOptions,
13
- } from "../../document";
14
- import { DocInspector, type DocInspectorProps } from "./DocInspector";
15
- import { buildDraftDocumentInput } from "../../lib/document-input";
16
- import { Button } from "../shared/Button";
17
- import { useFocusTrap } from "../../hooks/useFocusTrap";
18
- import { useStackedEscape } from "../../hooks/useStackedEscape";
19
- // The sealed document stylesheet ships with its editor consumer (Task 6 decided
20
- // the present route imports it from its island; this is the editor's island).
21
- // Vitest stubs CSS imports, so it stays out of the jsdom test graph regardless.
22
- import "../../document/styles/document.css";
23
-
24
- export interface DocumentEditorOverlayProps {
25
- /** The active page — its `document` block must be enabled for the FAB to mount. */
26
- page: Page;
27
- /**
28
- * The page's draft sections, in `page.order` order. The overlay drops
29
- * archived ones itself — /present renders only live sections, so a chunk the
30
- * published document will never show must not influence the proofed layout.
31
- */
32
- sections: LoadedSection[];
33
- manifest: MediaManifest;
34
- /** Wired by the shell to `setPageDocument` + the local-changes dirty flag. */
35
- onUpdateDocument: (patch: Partial<DocumentOptions>) => void;
36
- onClose: () => void;
37
- }
38
-
39
- /**
40
- * Full-viewport editing surface: DocViewer (edit mode, ghosts + selection) on
41
- * the left, DocInspector (settings for the current selection) on the right.
42
- *
43
- * The engine input is rebuilt from the live draft (page + in-memory sections +
44
- * manifest) on every prop change, so unsaved edits repaginate immediately —
45
- * the pagination hook's stale-heights guard absorbs the shape changes.
46
- */
47
- export function DocumentEditorOverlay({
48
- page,
49
- sections,
50
- manifest,
51
- onUpdateDocument,
52
- onClose,
53
- }: DocumentEditorOverlayProps) {
54
- // page.document is optional on the type; the caller only mounts this when it
55
- // is enabled, but parse-with-defaults keeps us total either way.
56
- const doc = useMemo(() => documentOptionsSchema.parse(page.document ?? {}), [page.document]);
57
-
58
- const source = useMemo(
59
- () =>
60
- buildDraftDocumentInput({
61
- page,
62
- sections: sections.filter((s) => s.meta.status !== "archived"),
63
- manifest,
64
- }),
65
- [page, sections, manifest],
66
- );
67
-
68
- // Titles (for the inspector header) + per-chunk warnings come straight from
69
- // DocViewer's single pagination pass via onDocState — no second useDocPages.
70
- const [docState, setDocState] = useState<{ chunks: Chunk[]; warningsByChunk: Record<string, string[]> }>({
71
- chunks: [],
72
- warningsByChunk: {},
73
- });
74
- const { chunks, warningsByChunk } = docState;
75
-
76
- // null = cover selected.
77
- const [selectedChunkId, setSelectedChunkId] = useState<string | null>(null);
78
-
79
- // All media bytes come from /api/media (draft branch bytes are served to
80
- // editor sessions) — the same host shape the present route uses.
81
- const host: DocHost = useMemo(
82
- () => ({
83
- variant: "preview",
84
- imageSrc: (image, variant) =>
85
- `/api/media/${image.imageId}/${variant === "print" ? image.printFile : image.previewFile}`,
86
- }),
87
- [],
88
- );
89
-
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
- });
119
-
120
- const selection: DocInspectorProps["selection"] = useMemo(() => {
121
- if (selectedChunkId === null) return { kind: "cover" };
122
- const chunk = chunks.find((c) => c.id === selectedChunkId);
123
- return { kind: "chunk", chunkId: selectedChunkId, title: chunk?.title ?? selectedChunkId, depth: chunk?.depth };
124
- }, [selectedChunkId, chunks]);
125
-
126
- const warnings = selectedChunkId ? warningsByChunk[selectedChunkId] ?? [] : [];
127
-
128
- // Merge the inspector's partial patch onto the chunk's CURRENT settings and
129
- // ship the whole validated block — setPageDocument merges sections shallowly
130
- // by key, so we must hand it a complete SectionSettings, not a fragment.
131
- const handleUpdateSection = useCallback(
132
- (chunkId: string, patch: Record<string, unknown>) => {
133
- const merged = sectionSettingsSchema.parse({ ...settingsFor(doc.sections, chunkId), ...patch });
134
- onUpdateDocument({ sections: { [chunkId]: merged } });
135
- },
136
- [doc.sections, onUpdateDocument],
137
- );
138
-
139
- // Cover/meta are single objects on the document; merge onto the current value
140
- // so a one-field edit doesn't blank the siblings before setPageDocument runs.
141
- const handleUpdateCover = useCallback(
142
- (patch: Partial<DocumentOptions["cover"]>) => onUpdateDocument({ cover: { ...doc.cover, ...patch } }),
143
- [doc.cover, onUpdateDocument],
144
- );
145
- const handleUpdateMeta = useCallback(
146
- (patch: Partial<DocumentOptions["meta"]>) => onUpdateDocument({ meta: { ...doc.meta, ...patch } }),
147
- [doc.meta, onUpdateDocument],
148
- );
149
-
150
- return (
151
- <div ref={panelRef} className="fixed inset-0 z-50 flex flex-col bg-base" role="dialog" aria-modal="true" aria-label="Document editor">
152
- <div className="flex items-center justify-between border-b border-base-200 bg-base px-4 py-2">
153
- <span className="text-sm font-medium text-base-contrast">Document · {page.title}</span>
154
- <Button variant="secondary" size="sm" aria-label="Close document editor" onClick={onClose}>
155
- Close
156
- </Button>
157
- </div>
158
- <div className="flex min-h-0 flex-1">
159
- <DocViewer
160
- source={source}
161
- document={doc}
162
- host={host}
163
- mode="edit"
164
- selectedChunkId={selectedChunkId}
165
- onSelectChunk={setSelectedChunkId}
166
- onDocState={setDocState}
167
- />
168
- <DocInspector
169
- document={doc}
170
- selection={selection}
171
- warnings={warnings}
172
- onUpdateCover={handleUpdateCover}
173
- onUpdateMeta={handleUpdateMeta}
174
- onUpdateSection={handleUpdateSection}
175
- />
176
- </div>
177
- </div>
178
- );
179
- }