@elytracms/studio 0.0.92 → 0.0.93

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 (241) hide show
  1. package/convex/asset-alt-migration.test.ts +127 -0
  2. package/convex/asset-replace.test.ts +168 -0
  3. package/convex/asset-revalidate.test.ts +6 -6
  4. package/convex/assets.ts +41 -5
  5. package/convex/cms.ts +25 -11
  6. package/convex/contract-parity.test.ts +18 -3
  7. package/convex/document-revalidate.test.ts +10 -12
  8. package/convex/orphan-hydration.test.ts +116 -0
  9. package/convex/rail-write-parity.test.ts +11 -8
  10. package/convex/schema.ts +6 -0
  11. package/dist/components/ai/proposal-card.js +2 -1
  12. package/dist/components/ai/proposal-card.js.map +1 -1
  13. package/dist/components/ai/translate-document-dialog.js +4 -2
  14. package/dist/components/ai/translate-document-dialog.js.map +1 -1
  15. package/dist/components/ai/translate-skipped.d.ts +19 -0
  16. package/dist/components/ai/translate-skipped.js +46 -0
  17. package/dist/components/ai/translate-skipped.js.map +1 -0
  18. package/dist/components/assets/asset-detail.js +18 -8
  19. package/dist/components/assets/asset-detail.js.map +1 -1
  20. package/dist/components/assets/asset-metadata.d.ts +15 -4
  21. package/dist/components/assets/asset-metadata.js +15 -2
  22. package/dist/components/assets/asset-metadata.js.map +1 -1
  23. package/dist/components/assets/asset-search.js +4 -1
  24. package/dist/components/assets/asset-search.js.map +1 -1
  25. package/dist/components/assets/asset-selection.d.ts +0 -8
  26. package/dist/components/assets/asset-selection.js +4 -23
  27. package/dist/components/assets/asset-selection.js.map +1 -1
  28. package/dist/components/assets/asset-thumb.js +3 -2
  29. package/dist/components/assets/asset-thumb.js.map +1 -1
  30. package/dist/components/assets/assets-collection-view-source.d.ts +3 -3
  31. package/dist/components/assets/assets-collection-view-source.js +9 -5
  32. package/dist/components/assets/assets-collection-view-source.js.map +1 -1
  33. package/dist/components/assets/assets-store.d.ts +14 -0
  34. package/dist/components/assets/assets-store.js +23 -1
  35. package/dist/components/assets/assets-store.js.map +1 -1
  36. package/dist/components/assets/replace-file.d.ts +22 -0
  37. package/dist/components/assets/replace-file.js +59 -0
  38. package/dist/components/assets/replace-file.js.map +1 -0
  39. package/dist/components/builder/blocks-model.d.ts +14 -26
  40. package/dist/components/builder/blocks-model.js +35 -41
  41. package/dist/components/builder/blocks-model.js.map +1 -1
  42. package/dist/components/builder/blocks-panel.d.ts +7 -3
  43. package/dist/components/builder/blocks-panel.js +6 -5
  44. package/dist/components/builder/blocks-panel.js.map +1 -1
  45. package/dist/components/builder/builder-store.d.ts +104 -15
  46. package/dist/components/builder/builder-store.js +156 -31
  47. package/dist/components/builder/builder-store.js.map +1 -1
  48. package/dist/components/builder/canvas-body.d.ts +30 -0
  49. package/dist/components/builder/canvas-body.js +38 -0
  50. package/dist/components/builder/canvas-body.js.map +1 -0
  51. package/dist/components/builder/canvas-chrome-css.js +7 -0
  52. package/dist/components/builder/canvas-chrome-css.js.map +1 -1
  53. package/dist/components/builder/canvas-dnd.d.ts +7 -7
  54. package/dist/components/builder/canvas-dnd.js +5 -5
  55. package/dist/components/builder/canvas-dnd.js.map +1 -1
  56. package/dist/components/builder/canvas-render-context.d.ts +27 -19
  57. package/dist/components/builder/canvas-render-context.js +42 -43
  58. package/dist/components/builder/canvas-render-context.js.map +1 -1
  59. package/dist/components/builder/canvas-runs.d.ts +45 -0
  60. package/dist/components/builder/canvas-runs.js +51 -0
  61. package/dist/components/builder/canvas-runs.js.map +1 -0
  62. package/dist/components/builder/canvas.js +32 -5
  63. package/dist/components/builder/canvas.js.map +1 -1
  64. package/dist/components/builder/clipboard-actions.d.ts +15 -0
  65. package/dist/components/builder/clipboard-actions.js +44 -7
  66. package/dist/components/builder/clipboard-actions.js.map +1 -1
  67. package/dist/components/builder/composition-field-editor.d.ts +3 -15
  68. package/dist/components/builder/composition-field-editor.js +29 -40
  69. package/dist/components/builder/composition-field-editor.js.map +1 -1
  70. package/dist/components/builder/delete-key.d.ts +5 -0
  71. package/dist/components/builder/delete-key.js +4 -0
  72. package/dist/components/builder/delete-key.js.map +1 -1
  73. package/dist/components/builder/insert-context.d.ts +17 -25
  74. package/dist/components/builder/insert-context.js +45 -92
  75. package/dist/components/builder/insert-context.js.map +1 -1
  76. package/dist/components/builder/page-tree.d.ts +3 -3
  77. package/dist/components/builder/page-tree.js +3 -3
  78. package/dist/components/builder/page-tree.js.map +1 -1
  79. package/dist/components/builder/placement-refusal.d.ts +18 -0
  80. package/dist/components/builder/placement-refusal.js +46 -0
  81. package/dist/components/builder/placement-refusal.js.map +1 -0
  82. package/dist/components/builder/property-inspector.js +4 -0
  83. package/dist/components/builder/property-inspector.js.map +1 -1
  84. package/dist/components/builder/reuse-context.js +65 -27
  85. package/dist/components/builder/reuse-context.js.map +1 -1
  86. package/dist/components/builder/reuse.d.ts +79 -1
  87. package/dist/components/builder/reuse.js +69 -2
  88. package/dist/components/builder/reuse.js.map +1 -1
  89. package/dist/components/builder/run-inspector.d.ts +11 -0
  90. package/dist/components/builder/run-inspector.js +33 -0
  91. package/dist/components/builder/run-inspector.js.map +1 -0
  92. package/dist/components/cms/asset-field.d.ts +38 -1
  93. package/dist/components/cms/asset-field.js +182 -58
  94. package/dist/components/cms/asset-field.js.map +1 -1
  95. package/dist/components/cms/asset-picker-core.d.ts +16 -0
  96. package/dist/components/cms/asset-picker-core.js +20 -0
  97. package/dist/components/cms/asset-picker-core.js.map +1 -1
  98. package/dist/components/cms/asset-picker.js +12 -18
  99. package/dist/components/cms/asset-picker.js.map +1 -1
  100. package/dist/components/cms/bulk-actions.d.ts +3 -19
  101. package/dist/components/cms/bulk-actions.js +3 -24
  102. package/dist/components/cms/bulk-actions.js.map +1 -1
  103. package/dist/components/cms/cell.js.map +1 -1
  104. package/dist/components/cms/cms-store.d.ts +5 -4
  105. package/dist/components/cms/cms-store.js +16 -36
  106. package/dist/components/cms/cms-store.js.map +1 -1
  107. package/dist/components/cms/detail-editor.js +0 -1
  108. package/dist/components/cms/detail-editor.js.map +1 -1
  109. package/dist/components/cms/document-diff-view.d.ts +3 -1
  110. package/dist/components/cms/document-diff-view.js +12 -7
  111. package/dist/components/cms/document-diff-view.js.map +1 -1
  112. package/dist/components/cms/field-anchors.d.ts +7 -4
  113. package/dist/components/cms/field-anchors.js +9 -7
  114. package/dist/components/cms/field-anchors.js.map +1 -1
  115. package/dist/components/cms/field-control-lib.d.ts +15 -1
  116. package/dist/components/cms/field-control-lib.js +22 -3
  117. package/dist/components/cms/field-control-lib.js.map +1 -1
  118. package/dist/components/cms/gate-validation.d.ts +21 -30
  119. package/dist/components/cms/gate-validation.js +11 -32
  120. package/dist/components/cms/gate-validation.js.map +1 -1
  121. package/dist/components/cms/object-array-field.js +4 -4
  122. package/dist/components/cms/object-array-field.js.map +1 -1
  123. package/dist/components/cms/prop-fields.d.ts +7 -2
  124. package/dist/components/cms/prop-fields.js +13 -6
  125. package/dist/components/cms/prop-fields.js.map +1 -1
  126. package/dist/components/cms/rich-text/embed-picker.d.ts +1 -1
  127. package/dist/components/cms/rich-text/embed-picker.js.map +1 -1
  128. package/dist/components/cms/rich-text/insert.d.ts +20 -9
  129. package/dist/components/cms/rich-text/insert.js +25 -17
  130. package/dist/components/cms/rich-text/insert.js.map +1 -1
  131. package/dist/components/cms/use-publish-controller.d.ts +1 -2
  132. package/dist/components/cms/use-publish-controller.js +7 -19
  133. package/dist/components/cms/use-publish-controller.js.map +1 -1
  134. package/dist/components/cms/versions-pane.js +8 -1
  135. package/dist/components/cms/versions-pane.js.map +1 -1
  136. package/dist/components/collection-view/cms-collection-view-source.js +3 -1
  137. package/dist/components/collection-view/cms-collection-view-source.js.map +1 -1
  138. package/dist/components/components/transfer-dialog.js +2 -1
  139. package/dist/components/components/transfer-dialog.js.map +1 -1
  140. package/dist/components/components/transfer.d.ts +10 -10
  141. package/dist/components/components/transfer.js +13 -12
  142. package/dist/components/components/transfer.js.map +1 -1
  143. package/dist/lib/ai/apply-content.js +56 -116
  144. package/dist/lib/ai/apply-content.js.map +1 -1
  145. package/dist/lib/ai/chat-context.d.ts +8 -0
  146. package/dist/lib/ai/chat-context.js +37 -6
  147. package/dist/lib/ai/chat-context.js.map +1 -1
  148. package/dist/lib/ai/chat-state.d.ts +6 -0
  149. package/dist/lib/ai/chat-state.js.map +1 -1
  150. package/dist/lib/ai/constraints.d.ts +20 -5
  151. package/dist/lib/ai/constraints.js +125 -33
  152. package/dist/lib/ai/constraints.js.map +1 -1
  153. package/dist/lib/ai/fake-provider.d.ts +16 -3
  154. package/dist/lib/ai/fake-provider.js +22 -6
  155. package/dist/lib/ai/fake-provider.js.map +1 -1
  156. package/dist/lib/ai/index.d.ts +2 -0
  157. package/dist/lib/ai/index.js +2 -0
  158. package/dist/lib/ai/index.js.map +1 -1
  159. package/dist/lib/ai/leash.d.ts +34 -0
  160. package/dist/lib/ai/leash.js +28 -0
  161. package/dist/lib/ai/leash.js.map +1 -0
  162. package/dist/lib/ai/rich-text-input.d.ts +8 -8
  163. package/dist/lib/ai/rich-text-input.js +2 -1
  164. package/dist/lib/ai/rich-text-input.js.map +1 -1
  165. package/dist/lib/ai/rich-text-translate.d.ts +27 -4
  166. package/dist/lib/ai/rich-text-translate.js +28 -10
  167. package/dist/lib/ai/rich-text-translate.js.map +1 -1
  168. package/dist/lib/ai/shape.d.ts +13 -13
  169. package/dist/lib/ai/shape.js +69 -93
  170. package/dist/lib/ai/shape.js.map +1 -1
  171. package/dist/lib/ai/tools.d.ts +36 -41
  172. package/dist/lib/ai/tools.js +83 -87
  173. package/dist/lib/ai/tools.js.map +1 -1
  174. package/dist/lib/ai/translate-document.d.ts +32 -4
  175. package/dist/lib/ai/translate-document.js +144 -46
  176. package/dist/lib/ai/translate-document.js.map +1 -1
  177. package/dist/lib/ai/types.d.ts +34 -23
  178. package/dist/lib/ai/types.js.map +1 -1
  179. package/dist/lib/ai/update-fields.d.ts +15 -12
  180. package/dist/lib/ai/update-fields.js +112 -188
  181. package/dist/lib/ai/update-fields.js.map +1 -1
  182. package/dist/lib/ai/writer-form.d.ts +116 -0
  183. package/dist/lib/ai/writer-form.js +429 -0
  184. package/dist/lib/ai/writer-form.js.map +1 -0
  185. package/dist/lib/assets/upload.d.ts +31 -2
  186. package/dist/lib/assets/upload.js +61 -6
  187. package/dist/lib/assets/upload.js.map +1 -1
  188. package/dist/lib/clipboard/os-clipboard.d.ts +10 -2
  189. package/dist/lib/clipboard/os-clipboard.js +8 -4
  190. package/dist/lib/clipboard/os-clipboard.js.map +1 -1
  191. package/dist/lib/clipboard/paste-target.d.ts +18 -9
  192. package/dist/lib/clipboard/paste-target.js +8 -7
  193. package/dist/lib/clipboard/paste-target.js.map +1 -1
  194. package/dist/lib/cms/field-patch.d.ts +0 -10
  195. package/dist/lib/cms/field-patch.js +4 -30
  196. package/dist/lib/cms/field-patch.js.map +1 -1
  197. package/dist/lib/cms-views/view-model.d.ts +3 -3
  198. package/dist/lib/collection-view/collection-view-source.d.ts +7 -3
  199. package/dist/lib/collection-view/collection-view-source.js.map +1 -1
  200. package/dist/lib/data/collection-content.js +3 -2
  201. package/dist/lib/data/collection-content.js.map +1 -1
  202. package/dist/lib/dnd/drop-rules.d.ts +25 -31
  203. package/dist/lib/dnd/drop-rules.js +53 -59
  204. package/dist/lib/dnd/drop-rules.js.map +1 -1
  205. package/dist/lib/engine-version.d.ts +1 -1
  206. package/dist/lib/engine-version.js +1 -1
  207. package/dist/lib/engine-version.js.map +1 -1
  208. package/dist/lib/i18n/messages.de.js +40 -3
  209. package/dist/lib/i18n/messages.de.js.map +1 -1
  210. package/dist/lib/i18n/messages.en.d.ts +34 -2
  211. package/dist/lib/i18n/messages.en.js +43 -3
  212. package/dist/lib/i18n/messages.en.js.map +1 -1
  213. package/dist/lib/operations/project-runtime-config.d.ts +25 -6
  214. package/dist/lib/operations/project-runtime-config.js +37 -10
  215. package/dist/lib/operations/project-runtime-config.js.map +1 -1
  216. package/dist/lib/operations/publish-with-revision.d.ts +33 -1
  217. package/dist/lib/operations/publish-with-revision.js +32 -0
  218. package/dist/lib/operations/publish-with-revision.js.map +1 -1
  219. package/dist/lib/operations/runtime-validator.d.ts +19 -68
  220. package/dist/lib/operations/runtime-validator.js +12 -138
  221. package/dist/lib/operations/runtime-validator.js.map +1 -1
  222. package/dist/lib/operations/studio-operations.d.ts +9 -2
  223. package/dist/lib/operations/studio-operations.js +13 -11
  224. package/dist/lib/operations/studio-operations.js.map +1 -1
  225. package/dist/lib/persistence/convex-adapter.js +6 -1
  226. package/dist/lib/persistence/convex-adapter.js.map +1 -1
  227. package/dist/lib/persona/labels.js +3 -1
  228. package/dist/lib/persona/labels.js.map +1 -1
  229. package/dist/lib/workspace/index.d.ts +8 -11
  230. package/dist/lib/workspace/index.js +12 -24
  231. package/dist/lib/workspace/index.js.map +1 -1
  232. package/package.json +3 -3
  233. package/dist/components/cms/cms-composition-validators.d.ts +0 -16
  234. package/dist/components/cms/cms-composition-validators.js +0 -133
  235. package/dist/components/cms/cms-composition-validators.js.map +0 -1
  236. package/dist/components/cms/publish-clean.d.ts +0 -28
  237. package/dist/components/cms/publish-clean.js +0 -38
  238. package/dist/components/cms/publish-clean.js.map +0 -1
  239. package/dist/lib/assets/asset-placements.d.ts +0 -28
  240. package/dist/lib/assets/asset-placements.js +0 -83
  241. package/dist/lib/assets/asset-placements.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import type { ComponentNode } from '@elytracms/core/project-graph';
1
+ import type { ComponentNode, PlacementScope } from '@elytracms/core/project-graph';
2
2
  import type { StudioRegistry } from '@elytracms/studio/lib/registry';
3
3
  import type { InsertContext } from './insert-menu.js';
4
4
  /**
@@ -9,22 +9,18 @@ import type { InsertContext } from './insert-menu.js';
9
9
  * Canvas editor (`composition-field-editor.tsx`, EC-188/AD-12) can own it without
10
10
  * importing the dead shell. No UI here — pure graph/registry resolution.
11
11
  */
12
+ /** What the resolution reads from the builder store: the tree and its placement scope (EC-584). */
13
+ export interface InsertScope {
14
+ present: ComponentNode;
15
+ placement: PlacementScope;
16
+ }
12
17
  /**
13
- * Resolve where an insert lands: into the node's child slot, else as a sibling.
14
- *
15
- * `fieldAllow` (EC-188) is the composition field's TOP-LEVEL vocabulary
16
- * (`field.allow`). It constrains ONLY inserts that land as a direct child of the
17
- * active page root — the top level of a composition field value — where it is
18
- * intersected into `slotAllow` so forbidden components are never even offered,
19
- * mirroring the top-level leash in `validateCompositionValue`. Deeper inserts keep
20
- * following each component's own slot `allow`. Callers that omit `fieldAllow` get
21
- * an unconstrained top level. EC-554: which placements the field governs is read
22
- * through `fieldAllowAt` — the SAME reader drag-and-drop and paste judge with, so
23
- * the offer and the placement can never disagree.
18
+ * Resolve where an insert lands: into the node's child slot, else as a sibling. The
19
+ * offered vocabulary is the landing position's (see {@link contextAt}) — the SAME
20
+ * reader the reducer, drag-and-drop and paste judge with, so the offer and the
21
+ * placement can never disagree.
24
22
  */
25
- export declare function resolveInsertContext(builder: {
26
- present: ComponentNode;
27
- }, nodeId: string, fieldAllow?: readonly string[], studio?: StudioRegistry): InsertContext | null;
23
+ export declare function resolveInsertContext(builder: InsertScope, nodeId: string, studio?: StudioRegistry): InsertContext | null;
28
24
  /**
29
25
  * An in-canvas insertion position relative to a reference node (EC-405) — the
30
26
  * DnD position vocabulary (`lib/dnd/drop-rules`), narrowed to the three the
@@ -42,17 +38,15 @@ export type InsertPosition = 'before' | 'after' | 'into';
42
38
  * {@link primaryInsertSlot} (the same slot a drop `into` picks; `null` when the
43
39
  * node accepts no children), `before`/`after` use the reference's parent slot at
44
40
  * `index`/`index + 1` — so this surface and drag-insert can never disagree about
45
- * where a position lands or what it allows. `fieldAllow` (EC-188) still constrains
46
- * ONLY a direct child of the composition root, mirroring `resolveInsertContext`.
41
+ * where a position lands or what it allows (EC-584: the vocabulary is `allowAt`'s,
42
+ * exactly as in `resolveInsertContext`).
47
43
  */
48
- export declare function resolveInsertContextAt(builder: {
49
- present: ComponentNode;
50
- }, nodeId: string, position: InsertPosition, fieldAllow?: readonly string[], studio?: StudioRegistry): InsertContext | null;
44
+ export declare function resolveInsertContextAt(builder: InsertScope, nodeId: string, position: InsertPosition, studio?: StudioRegistry): InsertContext | null;
51
45
  /**
52
46
  * Which affordance positions are actually insertable at `nodeId` (EC-405 scope 3):
53
47
  * a position is offered only when it structurally exists AND at least one registry
54
- * component may land there (the SAME slot-rule filter the tree/DnD and the blocks
55
- * panel apply — {@link hasInsertableComponent} over the resolved `slotAllow`), so a
48
+ * component may land there (the SAME judge the tree/DnD, the blocks panel and the
49
+ * reducer apply — {@link hasInsertableComponent} over the resolved `allow`), so a
56
50
  * blocked spot shows no dead button.
57
51
  *
58
52
  * An EMPTY, insertable container surfaces ONLY `into` — the meaningful action there
@@ -62,6 +56,4 @@ export declare function resolveInsertContextAt(builder: {
62
56
  * child already carries its own edge affordances, so a filled container needs no
63
57
  * center "+").
64
58
  */
65
- export declare function insertablePositions(builder: {
66
- present: ComponentNode;
67
- }, nodeId: string, fieldAllow?: readonly string[], studio?: StudioRegistry): InsertPosition[];
59
+ export declare function insertablePositions(builder: InsertScope, nodeId: string, studio?: StudioRegistry): InsertPosition[];
@@ -1,30 +1,29 @@
1
- import { getNode, getParentInfo } from '@elytracms/core/project-graph';
1
+ import { allowAt, getNode, getParentInfo } from '@elytracms/core/project-graph';
2
2
  import { getStudioRegistry } from '@elytracms/studio/lib/registry';
3
3
  import { componentDisplayName } from '@elytracms/studio/lib/persona/labels';
4
- import { fieldAllowAt, manifestRules, primaryInsertSlot } from '@elytracms/studio/lib/dnd/drop-rules';
5
- import { hasInsertableComponent, intersectAllow } from './blocks-model.js';
4
+ import { manifestRules, primaryInsertSlot } from '@elytracms/studio/lib/dnd/drop-rules';
5
+ import { hasInsertableComponent } from './blocks-model.js';
6
6
  /**
7
- * Where an insert lands: the canvas insert-context resolution, shared by every
8
- * surface that mounts the canvas engine.
9
- *
10
- * Extracted from the retired standalone `BuilderShell` (EC-210) so the in-CMS
11
- * Canvas editor (`composition-field-editor.tsx`, EC-188/AD-12) can own it without
12
- * importing the dead shell. No UI here — pure graph/registry resolution.
7
+ * The offer at a target: its EFFECTIVE vocabulary, read through the core judge's own
8
+ * reader (`allowAt` — the composition field's at the composition root, keyed on node
9
+ * identity, mirroring the top-level leash in `validateCompositionValue`; each slot's
10
+ * own `allow` below), so the offer is exactly what the reducer admits (EC-584).
11
+ * EC-544: a closed set that admits nothing is the "No allowed components match" state.
13
12
  */
13
+ function contextAt(builder, target, destinationLabel) {
14
+ return {
15
+ target,
16
+ allow: allowAt(builder.present, target.parentId, target.slot, builder.placement),
17
+ destinationLabel,
18
+ };
19
+ }
14
20
  /**
15
- * Resolve where an insert lands: into the node's child slot, else as a sibling.
16
- *
17
- * `fieldAllow` (EC-188) is the composition field's TOP-LEVEL vocabulary
18
- * (`field.allow`). It constrains ONLY inserts that land as a direct child of the
19
- * active page root — the top level of a composition field value — where it is
20
- * intersected into `slotAllow` so forbidden components are never even offered,
21
- * mirroring the top-level leash in `validateCompositionValue`. Deeper inserts keep
22
- * following each component's own slot `allow`. Callers that omit `fieldAllow` get
23
- * an unconstrained top level. EC-554: which placements the field governs is read
24
- * through `fieldAllowAt` — the SAME reader drag-and-drop and paste judge with, so
25
- * the offer and the placement can never disagree.
21
+ * Resolve where an insert lands: into the node's child slot, else as a sibling. The
22
+ * offered vocabulary is the landing position's (see {@link contextAt}) — the SAME
23
+ * reader the reducer, drag-and-drop and paste judge with, so the offer and the
24
+ * placement can never disagree.
26
25
  */
27
- export function resolveInsertContext(builder, nodeId, fieldAllow, studio = getStudioRegistry()) {
26
+ export function resolveInsertContext(builder, nodeId, studio = getStudioRegistry()) {
28
27
  const root = builder.present;
29
28
  const node = getNode(root, nodeId);
30
29
  if (!node)
@@ -35,47 +34,24 @@ export function resolveInsertContext(builder, nodeId, fieldAllow, studio = getSt
35
34
  // instead of silently degrading to a sibling insert.
36
35
  const manifest = studio.registry.getManifest(node.componentId);
37
36
  const childSlot = primaryInsertSlot(manifestRules(manifest));
38
- const ctx = childSlot
39
- ? {
40
- target: { parentId: nodeId, slot: childSlot.name },
41
- slotAllow: childSlot.allow,
42
- destinationLabel: `${componentDisplayName(node.componentId, manifest)} · ${childSlot.name}`,
43
- }
44
- : resolveSiblingContext(studio, root, nodeId);
45
- // The field vocabulary governs only the top level (a direct child of the page
46
- // root). EC-544: an `allow` list is a closed set — absent = any, a list (even
47
- // an empty one) = exactly those ids — the same reading the validator applies,
48
- // so an empty intersection here is the "No allowed components match" state.
49
- return withFieldLeash(root, ctx, fieldAllow);
50
- }
51
- /**
52
- * Layer the composition field's top-level vocabulary over the resolved slot
53
- * `allow` (EC-188) — for a direct child of the root only, as decided by
54
- * {@link fieldAllowAt} (EC-554: the one reader every placement path shares).
55
- */
56
- function withFieldLeash(root, ctx, fieldAllow) {
57
- const leash = fieldAllowAt(root, ctx.target.parentId, fieldAllow);
58
- return leash ? { ...ctx, slotAllow: intersectAllow(ctx.slotAllow, leash) } : ctx;
37
+ if (childSlot) {
38
+ return contextAt(builder, { parentId: nodeId, slot: childSlot.name }, `${componentDisplayName(node.componentId, manifest)} · ${childSlot.name}`);
39
+ }
40
+ return resolveSiblingContext(studio, builder, nodeId);
59
41
  }
60
42
  /** A destination's component label — its manifest title (EC-591: never a stripped id prefix). */
61
43
  function parentLabel(studio, componentId) {
62
44
  return componentDisplayName(componentId, studio.registry.getManifest(componentId));
63
45
  }
64
46
  /** Sibling-or-root insert context for a node with no insertable child slot. */
65
- function resolveSiblingContext(studio, root, nodeId) {
66
- const info = getParentInfo(root, nodeId);
47
+ function resolveSiblingContext(studio, builder, nodeId) {
48
+ const info = getParentInfo(builder.present, nodeId);
67
49
  if (info) {
68
- // EC-386: the parent slot may be a blocks-prop region — look it up on the
69
- // merged vocabulary so its `allow` leash still filters sibling inserts.
70
- const pManifest = manifestRules(studio.registry.getManifest(info.parent.componentId));
71
- const allow = pManifest?.slots.find((s) => s.name === info.slot)?.allow;
72
- return {
73
- target: { parentId: info.parent.id, slot: info.slot, index: info.index + 1 },
74
- slotAllow: allow,
75
- destinationLabel: `${parentLabel(studio, info.parent.componentId)} · ${info.slot}`,
76
- };
50
+ // EC-386: the parent slot may be a blocks-prop region — its `allow` leash still
51
+ // filters sibling inserts (the core lookup merges blocks props into the slots).
52
+ return contextAt(builder, { parentId: info.parent.id, slot: info.slot, index: info.index + 1 }, `${parentLabel(studio, info.parent.componentId)} · ${info.slot}`);
77
53
  }
78
- return { target: { parentId: nodeId, slot: 'children' }, destinationLabel: 'root' };
54
+ return contextAt(builder, { parentId: nodeId, slot: 'children' }, 'root');
79
55
  }
80
56
  /**
81
57
  * Resolve an `InsertContext` for an EXPLICIT position relative to `nodeId`
@@ -87,15 +63,14 @@ function resolveSiblingContext(studio, root, nodeId) {
87
63
  * {@link primaryInsertSlot} (the same slot a drop `into` picks; `null` when the
88
64
  * node accepts no children), `before`/`after` use the reference's parent slot at
89
65
  * `index`/`index + 1` — so this surface and drag-insert can never disagree about
90
- * where a position lands or what it allows. `fieldAllow` (EC-188) still constrains
91
- * ONLY a direct child of the composition root, mirroring `resolveInsertContext`.
66
+ * where a position lands or what it allows (EC-584: the vocabulary is `allowAt`'s,
67
+ * exactly as in `resolveInsertContext`).
92
68
  */
93
- export function resolveInsertContextAt(builder, nodeId, position, fieldAllow, studio = getStudioRegistry()) {
69
+ export function resolveInsertContextAt(builder, nodeId, position, studio = getStudioRegistry()) {
94
70
  const root = builder.present;
95
71
  const node = getNode(root, nodeId);
96
72
  if (!node)
97
73
  return null;
98
- let ctx;
99
74
  if (position === 'into') {
100
75
  // EC-386: `manifestRules` folds blocks-prop regions into the slot set, so
101
76
  // an affordance/drop `into` a Section-style body lands in that region.
@@ -103,40 +78,18 @@ export function resolveInsertContextAt(builder, nodeId, position, fieldAllow, st
103
78
  const slot = primaryInsertSlot(manifestRules(manifest));
104
79
  if (!slot)
105
80
  return null; // the node accepts no children — no `into` position
106
- ctx = {
107
- target: {
108
- parentId: nodeId,
109
- slot: slot.name,
110
- index: (node.slots?.[slot.name] ?? []).length,
111
- },
112
- slotAllow: slot.allow,
113
- destinationLabel: `${componentDisplayName(node.componentId, manifest)} · ${slot.name}`,
114
- };
81
+ return contextAt(builder, { parentId: nodeId, slot: slot.name, index: (node.slots?.[slot.name] ?? []).length }, `${componentDisplayName(node.componentId, manifest)} · ${slot.name}`);
115
82
  }
116
- else {
117
- const info = getParentInfo(root, nodeId);
118
- if (!info)
119
- return null; // the root has no siblings — no before/after position
120
- // EC-386: merged vocabulary — a blocks-prop parent region keeps its leash.
121
- const pManifest = manifestRules(studio.registry.getManifest(info.parent.componentId));
122
- ctx = {
123
- target: {
124
- parentId: info.parent.id,
125
- slot: info.slot,
126
- index: info.index + (position === 'after' ? 1 : 0),
127
- },
128
- slotAllow: pManifest?.slots.find((s) => s.name === info.slot)?.allow,
129
- destinationLabel: `${parentLabel(studio, info.parent.componentId)} · ${info.slot}`,
130
- };
131
- }
132
- // EC-544: closed-set reading, same as `resolveInsertContext` above.
133
- return withFieldLeash(root, ctx, fieldAllow);
83
+ const info = getParentInfo(root, nodeId);
84
+ if (!info)
85
+ return null; // the root has no siblings — no before/after position
86
+ return contextAt(builder, { parentId: info.parent.id, slot: info.slot, index: info.index + (position === 'after' ? 1 : 0) }, `${parentLabel(studio, info.parent.componentId)} · ${info.slot}`);
134
87
  }
135
88
  /**
136
89
  * Which affordance positions are actually insertable at `nodeId` (EC-405 scope 3):
137
90
  * a position is offered only when it structurally exists AND at least one registry
138
- * component may land there (the SAME slot-rule filter the tree/DnD and the blocks
139
- * panel apply — {@link hasInsertableComponent} over the resolved `slotAllow`), so a
91
+ * component may land there (the SAME judge the tree/DnD, the blocks panel and the
92
+ * reducer apply — {@link hasInsertableComponent} over the resolved `allow`), so a
140
93
  * blocked spot shows no dead button.
141
94
  *
142
95
  * An EMPTY, insertable container surfaces ONLY `into` — the meaningful action there
@@ -146,17 +99,17 @@ export function resolveInsertContextAt(builder, nodeId, position, fieldAllow, st
146
99
  * child already carries its own edge affordances, so a filled container needs no
147
100
  * center "+").
148
101
  */
149
- export function insertablePositions(builder, nodeId, fieldAllow, studio = getStudioRegistry()) {
102
+ export function insertablePositions(builder, nodeId, studio = getStudioRegistry()) {
150
103
  // Empty insertable container → into only.
151
- const into = resolveInsertContextAt(builder, nodeId, 'into', fieldAllow, studio);
152
- if (into && (into.target.index ?? 0) === 0 && hasInsertableComponent(studio, into.slotAllow)) {
104
+ const into = resolveInsertContextAt(builder, nodeId, 'into', studio);
105
+ if (into && (into.target.index ?? 0) === 0 && hasInsertableComponent(studio, into.allow)) {
153
106
  return ['into'];
154
107
  }
155
108
  // Otherwise the sibling edges that accept something.
156
109
  const out = [];
157
110
  for (const position of ['before', 'after']) {
158
- const ctx = resolveInsertContextAt(builder, nodeId, position, fieldAllow, studio);
159
- if (ctx && hasInsertableComponent(studio, ctx.slotAllow))
111
+ const ctx = resolveInsertContextAt(builder, nodeId, position, studio);
112
+ if (ctx && hasInsertableComponent(studio, ctx.allow))
160
113
  out.push(position);
161
114
  }
162
115
  return out;
@@ -1 +1 @@
1
- {"version":3,"file":"insert-context.js","sourceRoot":"","sources":["../../../src/components/builder/insert-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAElE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAA;AAC3E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAA;AACrG,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAGvE;;;;;;;GAOG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAmC,EACnC,MAAc,EACd,UAA8B,EAC9B,SAAyB,iBAAiB,EAAE;IAE5C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAA;IAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAClC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IACtB,4EAA4E;IAC5E,2EAA2E;IAC3E,6EAA6E;IAC7E,qDAAqD;IACrD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IAC9D,MAAM,SAAS,GAAG,iBAAiB,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC5D,MAAM,GAAG,GAAkB,SAAS;QAClC,CAAC,CAAC;YACE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE;YAClD,SAAS,EAAE,SAAS,CAAC,KAAK;YAC1B,gBAAgB,EAAE,GAAG,oBAAoB,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,SAAS,CAAC,IAAI,EAAE;SAC5F;QACH,CAAC,CAAC,qBAAqB,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAA;IAE/C,8EAA8E;IAC9E,8EAA8E;IAC9E,8EAA8E;IAC9E,4EAA4E;IAC5E,OAAO,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,UAAU,CAAC,CAAA;AAC9C,CAAC;AAED;;;;GAIG;AACH,SAAS,cAAc,CACrB,IAAmB,EACnB,GAAkB,EAClB,UAAyC;IAEzC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;IACjE,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,cAAc,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA;AAClF,CAAC;AAED,iGAAiG;AACjG,SAAS,WAAW,CAAC,MAAsB,EAAE,WAAmB;IAC9D,OAAO,oBAAoB,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAA;AACpF,CAAC;AAED,+EAA+E;AAC/E,SAAS,qBAAqB,CAAC,MAAsB,EAAE,IAAmB,EAAE,MAAc;IACxF,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACxC,IAAI,IAAI,EAAE,CAAC;QACT,0EAA0E;QAC1E,wEAAwE;QACxE,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAA;QACrF,MAAM,KAAK,GAAG,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,CAAA;QACvE,OAAO;YACL,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE;YAC5E,SAAS,EAAE,KAAK;YAChB,gBAAgB,EAAE,GAAG,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE;SACnF,CAAA;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,gBAAgB,EAAE,MAAM,EAAE,CAAA;AACrF,CAAC;AAUD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAmC,EACnC,MAAc,EACd,QAAwB,EACxB,UAA8B,EAC9B,SAAyB,iBAAiB,EAAE;IAE5C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAA;IAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAClC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IAEtB,IAAI,GAAkB,CAAA;IACtB,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,0EAA0E;QAC1E,uEAAuE;QACvE,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QAC9D,MAAM,IAAI,GAAG,iBAAiB,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAA;QACvD,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA,CAAC,oDAAoD;QAC3E,GAAG,GAAG;YACJ,MAAM,EAAE;gBACN,QAAQ,EAAE,MAAM;gBAChB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM;aAC9C;YACD,SAAS,EAAE,IAAI,CAAC,KAAK;YACrB,gBAAgB,EAAE,GAAG,oBAAoB,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE;SACvF,CAAA;IACH,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QACxC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA,CAAC,sDAAsD;QAC7E,2EAA2E;QAC3E,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAA;QACrF,GAAG,GAAG;YACJ,MAAM,EAAE;gBACN,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE;gBACxB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aACnD;YACD,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK;YACpE,gBAAgB,EAAE,GAAG,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE;SACnF,CAAA;IACH,CAAC;IAED,oEAAoE;IACpE,OAAO,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,UAAU,CAAC,CAAA;AAC9C,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAmC,EACnC,MAAc,EACd,UAA8B,EAC9B,SAAyB,iBAAiB,EAAE;IAE5C,0CAA0C;IAC1C,MAAM,IAAI,GAAG,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,CAAA;IAChF,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,sBAAsB,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7F,OAAO,CAAC,MAAM,CAAC,CAAA;IACjB,CAAC;IACD,qDAAqD;IACrD,MAAM,GAAG,GAAqB,EAAE,CAAA;IAChC,KAAK,MAAM,QAAQ,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAU,EAAE,CAAC;QACpD,MAAM,GAAG,GAAG,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,CAAA;QACjF,IAAI,GAAG,IAAI,sBAAsB,CAAC,MAAM,EAAE,GAAG,CAAC,SAAS,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAC9E,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["import { getNode, getParentInfo } from '@elytracms/core/project-graph'\nimport type { ComponentNode } from '@elytracms/core/project-graph'\nimport { getStudioRegistry } from '@elytracms/studio/lib/registry'\nimport type { StudioRegistry } from '@elytracms/studio/lib/registry'\nimport { componentDisplayName } from '@elytracms/studio/lib/persona/labels'\nimport { fieldAllowAt, manifestRules, primaryInsertSlot } from '@elytracms/studio/lib/dnd/drop-rules'\nimport { hasInsertableComponent, intersectAllow } from './blocks-model'\nimport type { InsertContext } from './insert-menu'\n\n/**\n * Where an insert lands: the canvas insert-context resolution, shared by every\n * surface that mounts the canvas engine.\n *\n * Extracted from the retired standalone `BuilderShell` (EC-210) so the in-CMS\n * Canvas editor (`composition-field-editor.tsx`, EC-188/AD-12) can own it without\n * importing the dead shell. No UI here — pure graph/registry resolution.\n */\n\n/**\n * Resolve where an insert lands: into the node's child slot, else as a sibling.\n *\n * `fieldAllow` (EC-188) is the composition field's TOP-LEVEL vocabulary\n * (`field.allow`). It constrains ONLY inserts that land as a direct child of the\n * active page root — the top level of a composition field value — where it is\n * intersected into `slotAllow` so forbidden components are never even offered,\n * mirroring the top-level leash in `validateCompositionValue`. Deeper inserts keep\n * following each component's own slot `allow`. Callers that omit `fieldAllow` get\n * an unconstrained top level. EC-554: which placements the field governs is read\n * through `fieldAllowAt` — the SAME reader drag-and-drop and paste judge with, so\n * the offer and the placement can never disagree.\n */\nexport function resolveInsertContext(\n builder: { present: ComponentNode },\n nodeId: string,\n fieldAllow?: readonly string[],\n studio: StudioRegistry = getStudioRegistry(),\n): InsertContext | null {\n const root = builder.present\n const node = getNode(root, nodeId)\n if (!node) return null\n // EC-386: resolve against the merged slot vocabulary (`manifestRules` folds\n // blocks-prop regions in), through the SAME `primaryInsertSlot` rule a DnD\n // `into` uses — so a `project.Section.body`-style region receives the insert\n // instead of silently degrading to a sibling insert.\n const manifest = studio.registry.getManifest(node.componentId)\n const childSlot = primaryInsertSlot(manifestRules(manifest))\n const ctx: InsertContext = childSlot\n ? {\n target: { parentId: nodeId, slot: childSlot.name },\n slotAllow: childSlot.allow,\n destinationLabel: `${componentDisplayName(node.componentId, manifest)} · ${childSlot.name}`,\n }\n : resolveSiblingContext(studio, root, nodeId)\n\n // The field vocabulary governs only the top level (a direct child of the page\n // root). EC-544: an `allow` list is a closed set — absent = any, a list (even\n // an empty one) = exactly those ids — the same reading the validator applies,\n // so an empty intersection here is the \"No allowed components match\" state.\n return withFieldLeash(root, ctx, fieldAllow)\n}\n\n/**\n * Layer the composition field's top-level vocabulary over the resolved slot\n * `allow` (EC-188) — for a direct child of the root only, as decided by\n * {@link fieldAllowAt} (EC-554: the one reader every placement path shares).\n */\nfunction withFieldLeash(\n root: ComponentNode,\n ctx: InsertContext,\n fieldAllow: readonly string[] | undefined,\n): InsertContext {\n const leash = fieldAllowAt(root, ctx.target.parentId, fieldAllow)\n return leash ? { ...ctx, slotAllow: intersectAllow(ctx.slotAllow, leash) } : ctx\n}\n\n/** A destination's component label — its manifest title (EC-591: never a stripped id prefix). */\nfunction parentLabel(studio: StudioRegistry, componentId: string): string {\n return componentDisplayName(componentId, studio.registry.getManifest(componentId))\n}\n\n/** Sibling-or-root insert context for a node with no insertable child slot. */\nfunction resolveSiblingContext(studio: StudioRegistry, root: ComponentNode, nodeId: string): InsertContext {\n const info = getParentInfo(root, nodeId)\n if (info) {\n // EC-386: the parent slot may be a blocks-prop region — look it up on the\n // merged vocabulary so its `allow` leash still filters sibling inserts.\n const pManifest = manifestRules(studio.registry.getManifest(info.parent.componentId))\n const allow = pManifest?.slots.find((s) => s.name === info.slot)?.allow\n return {\n target: { parentId: info.parent.id, slot: info.slot, index: info.index + 1 },\n slotAllow: allow,\n destinationLabel: `${parentLabel(studio, info.parent.componentId)} · ${info.slot}`,\n }\n }\n return { target: { parentId: nodeId, slot: 'children' }, destinationLabel: 'root' }\n}\n\n/**\n * An in-canvas insertion position relative to a reference node (EC-405) — the\n * DnD position vocabulary (`lib/dnd/drop-rules`), narrowed to the three the\n * insertion affordances offer: `before`/`after` a sibling, or `into` an (empty)\n * container. `left`/`right` (the wrap-into-columns gesture) are DnD-only.\n */\nexport type InsertPosition = 'before' | 'after' | 'into'\n\n/**\n * Resolve an `InsertContext` for an EXPLICIT position relative to `nodeId`\n * (EC-405) — the position-carrying twin of {@link resolveInsertContext}, so an\n * affordance click at a chosen edge lands the insert at exactly that spot rather\n * than the panel re-deriving it from the selection.\n *\n * The slot resolution reuses the shared DnD rules — `into` uses\n * {@link primaryInsertSlot} (the same slot a drop `into` picks; `null` when the\n * node accepts no children), `before`/`after` use the reference's parent slot at\n * `index`/`index + 1` — so this surface and drag-insert can never disagree about\n * where a position lands or what it allows. `fieldAllow` (EC-188) still constrains\n * ONLY a direct child of the composition root, mirroring `resolveInsertContext`.\n */\nexport function resolveInsertContextAt(\n builder: { present: ComponentNode },\n nodeId: string,\n position: InsertPosition,\n fieldAllow?: readonly string[],\n studio: StudioRegistry = getStudioRegistry(),\n): InsertContext | null {\n const root = builder.present\n const node = getNode(root, nodeId)\n if (!node) return null\n\n let ctx: InsertContext\n if (position === 'into') {\n // EC-386: `manifestRules` folds blocks-prop regions into the slot set, so\n // an affordance/drop `into` a Section-style body lands in that region.\n const manifest = studio.registry.getManifest(node.componentId)\n const slot = primaryInsertSlot(manifestRules(manifest))\n if (!slot) return null // the node accepts no children — no `into` position\n ctx = {\n target: {\n parentId: nodeId,\n slot: slot.name,\n index: (node.slots?.[slot.name] ?? []).length,\n },\n slotAllow: slot.allow,\n destinationLabel: `${componentDisplayName(node.componentId, manifest)} · ${slot.name}`,\n }\n } else {\n const info = getParentInfo(root, nodeId)\n if (!info) return null // the root has no siblings — no before/after position\n // EC-386: merged vocabulary — a blocks-prop parent region keeps its leash.\n const pManifest = manifestRules(studio.registry.getManifest(info.parent.componentId))\n ctx = {\n target: {\n parentId: info.parent.id,\n slot: info.slot,\n index: info.index + (position === 'after' ? 1 : 0),\n },\n slotAllow: pManifest?.slots.find((s) => s.name === info.slot)?.allow,\n destinationLabel: `${parentLabel(studio, info.parent.componentId)} · ${info.slot}`,\n }\n }\n\n // EC-544: closed-set reading, same as `resolveInsertContext` above.\n return withFieldLeash(root, ctx, fieldAllow)\n}\n\n/**\n * Which affordance positions are actually insertable at `nodeId` (EC-405 scope 3):\n * a position is offered only when it structurally exists AND at least one registry\n * component may land there (the SAME slot-rule filter the tree/DnD and the blocks\n * panel apply — {@link hasInsertableComponent} over the resolved `slotAllow`), so a\n * blocked spot shows no dead button.\n *\n * An EMPTY, insertable container surfaces ONLY `into` — the meaningful action there\n * is \"add the first child\", and an empty container often renders zero-height, so\n * its own before/after edges are degenerate and would pile the three \"+\" buttons\n * onto one point. A filled container and every leaf get before/after instead (each\n * child already carries its own edge affordances, so a filled container needs no\n * center \"+\").\n */\nexport function insertablePositions(\n builder: { present: ComponentNode },\n nodeId: string,\n fieldAllow?: readonly string[],\n studio: StudioRegistry = getStudioRegistry(),\n): InsertPosition[] {\n // Empty insertable container → into only.\n const into = resolveInsertContextAt(builder, nodeId, 'into', fieldAllow, studio)\n if (into && (into.target.index ?? 0) === 0 && hasInsertableComponent(studio, into.slotAllow)) {\n return ['into']\n }\n // Otherwise the sibling edges that accept something.\n const out: InsertPosition[] = []\n for (const position of ['before', 'after'] as const) {\n const ctx = resolveInsertContextAt(builder, nodeId, position, fieldAllow, studio)\n if (ctx && hasInsertableComponent(studio, ctx.slotAllow)) out.push(position)\n }\n return out\n}\n"]}
1
+ {"version":3,"file":"insert-context.js","sourceRoot":"","sources":["../../../src/components/builder/insert-context.ts"],"names":[],"mappings":"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","sourcesContent":["import { allowAt, getNode, getParentInfo } from '@elytracms/core/project-graph'\nimport type { ComponentNode, InsertTarget, PlacementScope } from '@elytracms/core/project-graph'\nimport { getStudioRegistry } from '@elytracms/studio/lib/registry'\nimport type { StudioRegistry } from '@elytracms/studio/lib/registry'\nimport { componentDisplayName } from '@elytracms/studio/lib/persona/labels'\nimport { manifestRules, primaryInsertSlot } from '@elytracms/studio/lib/dnd/drop-rules'\nimport { hasInsertableComponent } from './blocks-model'\nimport type { InsertContext } from './insert-menu'\n\n/**\n * Where an insert lands: the canvas insert-context resolution, shared by every\n * surface that mounts the canvas engine.\n *\n * Extracted from the retired standalone `BuilderShell` (EC-210) so the in-CMS\n * Canvas editor (`composition-field-editor.tsx`, EC-188/AD-12) can own it without\n * importing the dead shell. No UI here — pure graph/registry resolution.\n */\n\n/** What the resolution reads from the builder store: the tree and its placement scope (EC-584). */\nexport interface InsertScope {\n present: ComponentNode\n placement: PlacementScope\n}\n\n/**\n * The offer at a target: its EFFECTIVE vocabulary, read through the core judge's own\n * reader (`allowAt` — the composition field's at the composition root, keyed on node\n * identity, mirroring the top-level leash in `validateCompositionValue`; each slot's\n * own `allow` below), so the offer is exactly what the reducer admits (EC-584).\n * EC-544: a closed set that admits nothing is the \"No allowed components match\" state.\n */\nfunction contextAt(builder: InsertScope, target: InsertTarget, destinationLabel: string): InsertContext {\n return {\n target,\n allow: allowAt(builder.present, target.parentId, target.slot, builder.placement),\n destinationLabel,\n }\n}\n\n/**\n * Resolve where an insert lands: into the node's child slot, else as a sibling. The\n * offered vocabulary is the landing position's (see {@link contextAt}) — the SAME\n * reader the reducer, drag-and-drop and paste judge with, so the offer and the\n * placement can never disagree.\n */\nexport function resolveInsertContext(\n builder: InsertScope,\n nodeId: string,\n studio: StudioRegistry = getStudioRegistry(),\n): InsertContext | null {\n const root = builder.present\n const node = getNode(root, nodeId)\n if (!node) return null\n // EC-386: resolve against the merged slot vocabulary (`manifestRules` folds\n // blocks-prop regions in), through the SAME `primaryInsertSlot` rule a DnD\n // `into` uses — so a `project.Section.body`-style region receives the insert\n // instead of silently degrading to a sibling insert.\n const manifest = studio.registry.getManifest(node.componentId)\n const childSlot = primaryInsertSlot(manifestRules(manifest))\n if (childSlot) {\n return contextAt(\n builder,\n { parentId: nodeId, slot: childSlot.name },\n `${componentDisplayName(node.componentId, manifest)} · ${childSlot.name}`,\n )\n }\n return resolveSiblingContext(studio, builder, nodeId)\n}\n\n/** A destination's component label — its manifest title (EC-591: never a stripped id prefix). */\nfunction parentLabel(studio: StudioRegistry, componentId: string): string {\n return componentDisplayName(componentId, studio.registry.getManifest(componentId))\n}\n\n/** Sibling-or-root insert context for a node with no insertable child slot. */\nfunction resolveSiblingContext(studio: StudioRegistry, builder: InsertScope, nodeId: string): InsertContext {\n const info = getParentInfo(builder.present, nodeId)\n if (info) {\n // EC-386: the parent slot may be a blocks-prop region — its `allow` leash still\n // filters sibling inserts (the core lookup merges blocks props into the slots).\n return contextAt(\n builder,\n { parentId: info.parent.id, slot: info.slot, index: info.index + 1 },\n `${parentLabel(studio, info.parent.componentId)} · ${info.slot}`,\n )\n }\n return contextAt(builder, { parentId: nodeId, slot: 'children' }, 'root')\n}\n\n/**\n * An in-canvas insertion position relative to a reference node (EC-405) — the\n * DnD position vocabulary (`lib/dnd/drop-rules`), narrowed to the three the\n * insertion affordances offer: `before`/`after` a sibling, or `into` an (empty)\n * container. `left`/`right` (the wrap-into-columns gesture) are DnD-only.\n */\nexport type InsertPosition = 'before' | 'after' | 'into'\n\n/**\n * Resolve an `InsertContext` for an EXPLICIT position relative to `nodeId`\n * (EC-405) — the position-carrying twin of {@link resolveInsertContext}, so an\n * affordance click at a chosen edge lands the insert at exactly that spot rather\n * than the panel re-deriving it from the selection.\n *\n * The slot resolution reuses the shared DnD rules — `into` uses\n * {@link primaryInsertSlot} (the same slot a drop `into` picks; `null` when the\n * node accepts no children), `before`/`after` use the reference's parent slot at\n * `index`/`index + 1` — so this surface and drag-insert can never disagree about\n * where a position lands or what it allows (EC-584: the vocabulary is `allowAt`'s,\n * exactly as in `resolveInsertContext`).\n */\nexport function resolveInsertContextAt(\n builder: InsertScope,\n nodeId: string,\n position: InsertPosition,\n studio: StudioRegistry = getStudioRegistry(),\n): InsertContext | null {\n const root = builder.present\n const node = getNode(root, nodeId)\n if (!node) return null\n\n if (position === 'into') {\n // EC-386: `manifestRules` folds blocks-prop regions into the slot set, so\n // an affordance/drop `into` a Section-style body lands in that region.\n const manifest = studio.registry.getManifest(node.componentId)\n const slot = primaryInsertSlot(manifestRules(manifest))\n if (!slot) return null // the node accepts no children — no `into` position\n return contextAt(\n builder,\n { parentId: nodeId, slot: slot.name, index: (node.slots?.[slot.name] ?? []).length },\n `${componentDisplayName(node.componentId, manifest)} · ${slot.name}`,\n )\n }\n const info = getParentInfo(root, nodeId)\n if (!info) return null // the root has no siblings — no before/after position\n return contextAt(\n builder,\n { parentId: info.parent.id, slot: info.slot, index: info.index + (position === 'after' ? 1 : 0) },\n `${parentLabel(studio, info.parent.componentId)} · ${info.slot}`,\n )\n}\n\n/**\n * Which affordance positions are actually insertable at `nodeId` (EC-405 scope 3):\n * a position is offered only when it structurally exists AND at least one registry\n * component may land there (the SAME judge the tree/DnD, the blocks panel and the\n * reducer apply — {@link hasInsertableComponent} over the resolved `allow`), so a\n * blocked spot shows no dead button.\n *\n * An EMPTY, insertable container surfaces ONLY `into` — the meaningful action there\n * is \"add the first child\", and an empty container often renders zero-height, so\n * its own before/after edges are degenerate and would pile the three \"+\" buttons\n * onto one point. A filled container and every leaf get before/after instead (each\n * child already carries its own edge affordances, so a filled container needs no\n * center \"+\").\n */\nexport function insertablePositions(\n builder: InsertScope,\n nodeId: string,\n studio: StudioRegistry = getStudioRegistry(),\n): InsertPosition[] {\n // Empty insertable container → into only.\n const into = resolveInsertContextAt(builder, nodeId, 'into', studio)\n if (into && (into.target.index ?? 0) === 0 && hasInsertableComponent(studio, into.allow)) {\n return ['into']\n }\n // Otherwise the sibling edges that accept something.\n const out: InsertPosition[] = []\n for (const position of ['before', 'after'] as const) {\n const ctx = resolveInsertContextAt(builder, nodeId, position, studio)\n if (ctx && hasInsertableComponent(studio, ctx.allow)) out.push(position)\n }\n return out\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { ComponentNode, LayoutContainerIds } from '@elytracms/core/project-graph';
1
+ import type { ComponentNode, LayoutContainerIds, PlacementScope } from '@elytracms/core/project-graph';
2
2
  import type { DragSubject, DropIndicator, DropResolution, ManifestLookup } from '@elytracms/studio/lib/dnd/drop-rules';
3
3
  /**
4
4
  * The tree's dragover resolution (EC-160/EC-162), pure: the row under the pointer
@@ -12,8 +12,8 @@ export declare function resolveTreeRowDrop(args: {
12
12
  getManifest: ManifestLookup;
13
13
  /** The layout-role component ids (EC-591) — `builder.layout`. */
14
14
  layout: LayoutContainerIds;
15
- /** The composition field's top-level `allow` (EC-554) — `builder.field.allow`. */
16
- fieldAllow: readonly string[] | undefined;
15
+ /** EC-584: the store's placement scope (`builder.placement`) — the reducer judges the same. */
16
+ placement: PlacementScope;
17
17
  subject: DragSubject;
18
18
  row: {
19
19
  id: string;
@@ -32,7 +32,7 @@ function flatten(node, depth, rows, meta) {
32
32
  * are pinned without a DOM — the handler only measures the pointer and renders.
33
33
  */
34
34
  export function resolveTreeRowDrop(args) {
35
- const { root, getManifest, layout, fieldAllow, subject, row, pointer } = args;
35
+ const { root, getManifest, layout, placement, subject, row, pointer } = args;
36
36
  let position = 'into';
37
37
  if (!row.isRoot) {
38
38
  // The hit-band axis follows the parent container's flow (EC-162):
@@ -48,7 +48,7 @@ export function resolveTreeRowDrop(args) {
48
48
  root,
49
49
  getManifest,
50
50
  layout,
51
- fieldAllow,
51
+ placement,
52
52
  subject,
53
53
  location: { nodeId: row.id, position },
54
54
  });
@@ -130,7 +130,7 @@ export function PageTree({ onAddChild }) {
130
130
  root: builder.present,
131
131
  getManifest,
132
132
  layout: builder.layout,
133
- fieldAllow: builder.field.allow,
133
+ placement: builder.placement,
134
134
  subject: drag.subject,
135
135
  row,
136
136
  pointer: {
@@ -1 +1 @@
1
- {"version":3,"file":"page-tree.js","sourceRoot":"","sources":["../../../src/components/builder/page-tree.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Boxes,\n ChevronUp,\n ChevronDown,\n ClipboardCopy,\n ClipboardPaste,\n ClipboardX,\n Copy,\n MoreHorizontal,\n Plus,\n Trash2,\n Unlink,\n} from 'lucide-react'\nimport { useEffect, useRef, useState } from 'react'\nimport type { ComponentNode, LayoutContainerIds } from '@elytracms/core/project-graph'\nimport { getParentInfo } from '@elytracms/core/project-graph'\nimport {\n canNestInto,\n containerFlowAxis,\n dropIndicatorFor,\n dropPositionForPointer,\n manifestRules,\n resolveDrop,\n} from '@elytracms/studio/lib/dnd/drop-rules'\nimport type {\n DragSubject,\n DropIndicator,\n DropPlan,\n DropPosition,\n DropResolution,\n ManifestLookup,\n} from '@elytracms/studio/lib/dnd/drop-rules'\nimport { getStudioRegistry } from '@elytracms/studio/lib/registry'\nimport { componentDisplayName } from '@elytracms/studio/lib/persona/labels'\nimport { translate, useUiLocale } from '@elytracms/studio/lib/i18n'\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Row,\n Spacer,\n Text,\n} from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { useBuilder } from './builder-store'\nimport { attachClipboardListeners, useStudioClipboard } from './clipboard-actions'\nimport { attachDeleteKeyListener } from './delete-key'\nimport { nodeDisplayTitle } from './node-title'\nimport { useReuse } from './reuse-context'\nimport { activeDrag, beginDrag, endDrag, onDragSessionEnd } from './drag-session'\n\ninterface TreeRow {\n id: string\n componentId: string\n /** The node itself — EC-407 derives the instance title from its prop values. */\n node: ComponentNode\n depth: number\n isRoot: boolean\n isFirst: boolean\n isLast: boolean\n}\n\nfunction flatten(\n node: ComponentNode,\n depth: number,\n rows: TreeRow[],\n meta: { isFirst: boolean; isLast: boolean; isRoot: boolean },\n): void {\n rows.push({ id: node.id, componentId: node.componentId, node, depth, ...meta })\n for (const children of Object.values(node.slots ?? {})) {\n children.forEach((child, i) =>\n flatten(child, depth + 1, rows, {\n isFirst: i === 0,\n isLast: i === children.length - 1,\n isRoot: false,\n }),\n )\n }\n}\n\n/**\n * The tree's dragover resolution (EC-160/EC-162), pure: the row under the pointer\n * → a drop position (the hit band along the parent's flow axis; the root row is\n * always `into`) → the shared {@link resolveDrop} verdict → the row indicator.\n * Extracted from the React handler (EC-554) so the tree surface's placement rules\n * are pinned without a DOM — the handler only measures the pointer and renders.\n */\nexport function resolveTreeRowDrop(args: {\n root: ComponentNode\n getManifest: ManifestLookup\n /** The layout-role component ids (EC-591) — `builder.layout`. */\n layout: LayoutContainerIds\n /** The composition field's top-level `allow` (EC-554) — `builder.field.allow`. */\n fieldAllow: readonly string[] | undefined\n subject: DragSubject\n row: { id: string; componentId: string; isRoot: boolean }\n /** Pointer offset within the row box, 0..1 per axis (unused for the root row). */\n pointer: { x: number; y: number }\n}): { resolution: DropResolution; indicator: DropIndicator } {\n const { root, getManifest, layout, fieldAllow, subject, row, pointer } = args\n let position: DropPosition = 'into'\n if (!row.isRoot) {\n // The hit-band axis follows the parent container's flow (EC-162):\n // children of horizontal Stacks/Grids reorder along the row's x axis.\n const flow = containerFlowAxis(getParentInfo(root, row.id)?.parent, layout)\n position = dropPositionForPointer({\n ratio: flow === 'horizontal' ? pointer.x : pointer.y,\n nestable: canNestInto(getManifest, row.componentId),\n edges: true,\n })\n }\n const resolution = resolveDrop({\n root,\n getManifest,\n layout,\n fieldAllow,\n subject,\n location: { nodeId: row.id, position },\n })\n return { resolution, indicator: dropIndicatorFor(resolution, position) }\n}\n\n/** Tailwind classes per drop indicator state (EC-160/EC-162) — rejection is visible. */\nconst ROW_DROP_CLASSES: Record<Exclude<DropIndicator, null>, string> = {\n into: 'ring-1 ring-inset ring-emerald-400 bg-emerald-400/10',\n before: 'shadow-[inset_0_2px_0_0_#38bdf8]',\n after: 'shadow-[inset_0_-2px_0_0_#38bdf8]',\n // Wrap-into-columns gesture (EC-162): the tree can execute wrap plans, the\n // bands themselves are a canvas gesture (rows have no spatial \"beside\").\n left: 'shadow-[inset_2px_0_0_0_#a78bfa] bg-violet-400/10',\n right: 'shadow-[inset_-2px_0_0_0_#a78bfa] bg-violet-400/10',\n blocked: 'ring-1 ring-inset ring-red-500/80 bg-red-500/10 cursor-not-allowed',\n}\n\nexport function PageTree({ onAddChild }: { onAddChild: (parentId: string) => void }) {\n const builder = useBuilder()\n const studio = getStudioRegistry()\n const uiLocale = useUiLocale()\n const rows: TreeRow[] = []\n flatten(builder.present, 0, rows, { isFirst: true, isLast: true, isRoot: true })\n\n // Copy/cut/paste (EC-175): keyboard shortcuts for the whole studio window\n // (the canvas iframe wires its own document) plus per-row affordances. The\n // shared listener keeps shortcuts inert in form fields/inline editors. (A\n // \"published preview is read-only\" guard used to sit here, keyed on the\n // collaboration store's `previewMode`; that mode was a constant `'draft'` with\n // no setter caller, so the guard never fired — EC-574 deleted both.)\n const clipboard = useStudioClipboard()\n const selectedIdRef = useRef(builder.selectedId)\n selectedIdRef.current = builder.selectedId\n useEffect(\n () =>\n attachClipboardListeners(window, {\n clipboard,\n getSelectedId: () => selectedIdRef.current,\n getSelection: () => window.getSelection(),\n }),\n [clipboard],\n )\n\n // Delete/Backspace removes the selected node from the tree side too (EC-404),\n // beside the clipboard shortcuts. Inert while focus is in a form field /\n // inline editor (isEditingContext).\n const { dispatch } = builder\n const rootId = builder.present.id\n useEffect(\n () =>\n attachDeleteKeyListener(window, {\n getSelectedId: () => selectedIdRef.current,\n remove: (id) => dispatch({ type: 'remove', id }),\n getRootId: () => rootId,\n }),\n [rootId, dispatch],\n )\n\n // Drag & drop (EC-160): eligibility comes from the same pure rule set the\n // canvas uses (`lib/dnd/drop-rules`); the tree only renders the resolution.\n // One eligible drop dispatches exactly one move/insert action.\n // The current plan lives in a ref: `drop` fires synchronously after the\n // last `dragover`, before React flushes indicator state.\n const dropPlanRef = useRef<DropPlan | null>(null)\n const [drop, setDrop] = useState<{ rowId: string; indicator: DropIndicator } | null>(null)\n const clearDrop = () => {\n dropPlanRef.current = null\n setDrop(null)\n }\n useEffect(() => onDragSessionEnd(() => clearDrop()), [])\n // EC-386: adapt through `manifestRules` so blocks-prop regions (e.g. a\n // Section's `body`) are drop targets with their `allow` leash, like raw slots.\n const getManifest = (id: string) => manifestRules(studio.registry.getManifest(id))\n\n function handleRowDragStart(row: TreeRow, e: React.DragEvent) {\n if (row.isRoot) {\n e.preventDefault()\n return\n }\n beginDrag(\n {\n subject: { kind: 'node', nodeId: row.id, componentId: row.componentId },\n source: 'tree',\n label: componentDisplayName(row.componentId, studio.registry.getManifest(row.componentId)),\n },\n e.dataTransfer,\n )\n }\n\n function handleRowDragOver(row: TreeRow, e: React.DragEvent) {\n const drag = activeDrag()\n if (!drag) return\n const rect = e.currentTarget.getBoundingClientRect()\n const { resolution, indicator } = resolveTreeRowDrop({\n root: builder.present,\n getManifest,\n layout: builder.layout,\n fieldAllow: builder.field.allow,\n subject: drag.subject,\n row,\n pointer: {\n x: rect.width > 0 ? (e.clientX - rect.left) / rect.width : 0.5,\n y: rect.height > 0 ? (e.clientY - rect.top) / rect.height : 0.5,\n },\n })\n dropPlanRef.current = resolution.eligible ? resolution : null\n setDrop({ rowId: row.id, indicator })\n if (resolution.eligible) {\n e.preventDefault()\n e.dataTransfer.dropEffect = drag.subject.kind === 'node' ? 'move' : 'copy'\n }\n }\n\n function handleRowDrop(e: React.DragEvent) {\n const drag = activeDrag()\n if (!drag) return\n const plan = dropPlanRef.current\n clearDrop()\n if (!plan) return\n e.preventDefault()\n // Exactly one dispatch per completed drop (one undo step, one command).\n if (plan.kind === 'move') {\n builder.dispatch({ type: 'move', id: plan.nodeId, target: plan.target })\n } else if (plan.kind === 'wrap') {\n // EC-162: shared plan vocabulary — the tree executes wrap plans too.\n const subject =\n plan.nodeId !== undefined\n ? { kind: 'node' as const, nodeId: plan.nodeId }\n : drag.buildNode\n ? { kind: 'component' as const, node: drag.buildNode() }\n : null\n if (!subject) {\n endDrag('cancelled')\n return\n }\n builder.dispatch({ type: 'wrap', referenceId: plan.referenceId, side: plan.side, subject })\n } else if (drag.buildNode) {\n builder.dispatch({ type: 'insert', target: plan.target, node: drag.buildNode() })\n } else {\n endDrag('cancelled')\n return\n }\n endDrag('dropped')\n }\n\n function handleRowDragEnd() {\n clearDrop()\n endDrag('cancelled')\n }\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n <Row gap=\"2\" className=\"h-10 shrink-0 border-b border-border px-3\">\n <Text size=\"sm\" weight=\"semibold\">\n {translate('builder.pageTree.title')}\n </Text>\n <Spacer />\n <Text size=\"xs\" tone=\"subtle\" mono>\n {rows.length}\n </Text>\n </Row>\n <div\n className=\"min-h-0 flex-1 overflow-auto p-1.5\"\n onMouseLeave={() => builder.dispatch({ type: 'hover', id: null })}\n onDragLeave={(e) => {\n // Clear the indicator when the drag exits the tree panel.\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) clearDrop()\n }}\n >\n {rows.map((row) => {\n const manifest = studio.registry.getManifest(row.componentId)\n const title = nodeDisplayTitle(manifest, row.node, uiLocale)\n const selected = row.id === builder.selectedId\n const hovered = row.id === builder.hoveredId\n return (\n <div\n key={row.id}\n onMouseEnter={() => builder.dispatch({ type: 'hover', id: row.id })}\n draggable={!row.isRoot}\n onDragStart={(e) => handleRowDragStart(row, e)}\n onDragOver={(e) => handleRowDragOver(row, e)}\n onDrop={handleRowDrop}\n onDragEnd={handleRowDragEnd}\n data-tree-row={row.id}\n data-tree-drop={drop?.rowId === row.id ? (drop.indicator ?? undefined) : undefined}\n className={cn(\n 'group flex items-center rounded-md pr-1 text-left text-xs transition-colors',\n selected\n ? 'bg-accent text-accent-foreground'\n : hovered\n ? 'bg-muted text-foreground'\n : 'text-muted-foreground',\n drop?.rowId === row.id && drop.indicator\n ? ROW_DROP_CLASSES[drop.indicator]\n : undefined,\n )}\n >\n <button\n type=\"button\"\n onClick={() => builder.dispatch({ type: 'select', id: row.id })}\n title={row.componentId}\n className=\"flex min-w-0 flex-1 items-center gap-1.5 py-1\"\n style={{ paddingLeft: `${6 + row.depth * 14}px` }}\n >\n {/* EC-407: instance title (its own text content) is primary; the\n localized component name is secondary context. The raw mono id\n left the row — it stays in the `title=` above + inspector header. */}\n <span className=\"truncate\">{title.primary}</span>\n {title.secondary ? (\n <span className=\"truncate text-muted-foreground/70\">{title.secondary}</span>\n ) : null}\n </button>\n\n <div\n className={cn(\n 'flex shrink-0 items-center gap-0.5',\n selected\n ? 'opacity-100'\n : 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100',\n )}\n >\n {/* Add child stays inline — the one constructive, high-frequency\n action. Everything else collapses into the ••• menu so labels\n stop cropping on the 200–240px panel (EC-211). */}\n <IconAction label={translate('builder.pageTree.addChild')} onClick={() => onAddChild(row.id)}>\n <Plus />\n </IconAction>\n <RowActionsMenu row={row} builder={builder} clipboard={clipboard} />\n </div>\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n\n/** Right-aligned keyboard-shortcut hint in a menu item — informational only; the\n * shortcut fires globally via the clipboard listeners regardless of the menu. */\nfunction MenuShortcut({ children }: { children: React.ReactNode }) {\n return <span className=\"ml-auto pl-6 text-xs tracking-widest text-muted-foreground\">{children}</span>\n}\n\n/**\n * The per-row \"•••\" action menu (EC-211). Copy/Paste on every row; Cut, Move,\n * Duplicate, Delete for non-root rows. Collapsing the old inline icon cluster\n * (up to 8 buttons, cropping on the 200–240px panel) into a menu changes no\n * behavior — same clipboard fragment + dispatch paths, same Cmd/Ctrl shortcuts.\n * Delete stays a one-click (undoable) destructive item, consistent with the rest\n * of the studio.\n */\nfunction RowActionsMenu({\n row,\n builder,\n clipboard,\n}: {\n row: { id: string; isRoot: boolean; isFirst: boolean; isLast: boolean }\n builder: ReturnType<typeof useBuilder>\n clipboard: ReturnType<typeof useStudioClipboard>\n}) {\n // EC-282 in-canvas reuse gestures, present only where a reuse capability is\n // configured (and the row is eligible). Null outside the composition editor.\n const reuse = useReuse()\n const canMakeReusable = !row.isRoot && (reuse?.canMakeReusable(row.id) ?? false)\n const canDetach = reuse?.canDetach(row.id) ?? false\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n size=\"icon-sm\"\n variant=\"ghost\"\n aria-label={translate('builder.pageTree.moreActions')}\n title={translate('builder.pageTree.moreActions')}\n className=\"size-6\"\n >\n <MoreHorizontal />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={() => clipboard.copyNode(row.id)}>\n <ClipboardCopy /> {translate('common.copy')} <MenuShortcut>⌘C</MenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => void clipboard.pasteFromClipboard(row.id)}>\n <ClipboardPaste /> {translate('builder.clipboard.paste')} <MenuShortcut>⌘V</MenuShortcut>\n </DropdownMenuItem>\n {!row.isRoot ? (\n <>\n <DropdownMenuItem onClick={() => clipboard.cutNode(row.id)}>\n <ClipboardX /> {translate('builder.clipboard.cut')} <MenuShortcut>⌘X</MenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n disabled={row.isFirst}\n onClick={() => builder.dispatch({ type: 'reorder', id: row.id, delta: -1 })}\n >\n <ChevronUp /> {translate('builder.pageTree.moveUp')}\n </DropdownMenuItem>\n <DropdownMenuItem\n disabled={row.isLast}\n onClick={() => builder.dispatch({ type: 'reorder', id: row.id, delta: 1 })}\n >\n <ChevronDown /> {translate('builder.pageTree.moveDown')}\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => builder.dispatch({ type: 'duplicate', id: row.id })}>\n <Copy /> {translate('common.duplicate')}\n </DropdownMenuItem>\n {canMakeReusable || canDetach ? <DropdownMenuSeparator /> : null}\n {canMakeReusable ? (\n <DropdownMenuItem onClick={() => reuse?.startMakeReusable(row.id)}>\n <Boxes /> {translate('builder.reuse.makeReusable')}\n </DropdownMenuItem>\n ) : null}\n {canDetach ? (\n <DropdownMenuItem onClick={() => reuse?.detach(row.id)}>\n <Unlink /> {translate('builder.reuse.detachToCopy')}\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuSeparator />\n <DropdownMenuItem\n variant=\"destructive\"\n onClick={() => builder.dispatch({ type: 'remove', id: row.id })}\n >\n <Trash2 /> {translate('common.delete')}\n </DropdownMenuItem>\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\nfunction IconAction({\n label,\n onClick,\n disabled,\n destructive,\n children,\n}: {\n label: string\n onClick: () => void\n disabled?: boolean\n destructive?: boolean\n children: React.ReactNode\n}) {\n return (\n <Button\n size=\"icon-sm\"\n variant=\"ghost\"\n aria-label={label}\n title={label}\n disabled={disabled}\n onClick={onClick}\n className={cn('size-6', destructive && 'hover:text-destructive')}\n >\n {children}\n </Button>\n )\n}\n"]}
1
+ {"version":3,"file":"page-tree.js","sourceRoot":"","sources":["../../../src/components/builder/page-tree.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n Boxes,\n ChevronUp,\n ChevronDown,\n ClipboardCopy,\n ClipboardPaste,\n ClipboardX,\n Copy,\n MoreHorizontal,\n Plus,\n Trash2,\n Unlink,\n} from 'lucide-react'\nimport { useEffect, useRef, useState } from 'react'\nimport type { ComponentNode, LayoutContainerIds, PlacementScope } from '@elytracms/core/project-graph'\nimport { getParentInfo } from '@elytracms/core/project-graph'\nimport {\n canNestInto,\n containerFlowAxis,\n dropIndicatorFor,\n dropPositionForPointer,\n manifestRules,\n resolveDrop,\n} from '@elytracms/studio/lib/dnd/drop-rules'\nimport type {\n DragSubject,\n DropIndicator,\n DropPlan,\n DropPosition,\n DropResolution,\n ManifestLookup,\n} from '@elytracms/studio/lib/dnd/drop-rules'\nimport { getStudioRegistry } from '@elytracms/studio/lib/registry'\nimport { componentDisplayName } from '@elytracms/studio/lib/persona/labels'\nimport { translate, useUiLocale } from '@elytracms/studio/lib/i18n'\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n Row,\n Spacer,\n Text,\n} from '@elytracms/studio/ui'\nimport { cn } from '@elytracms/studio/lib/utils'\nimport { useBuilder } from './builder-store'\nimport { attachClipboardListeners, useStudioClipboard } from './clipboard-actions'\nimport { attachDeleteKeyListener } from './delete-key'\nimport { nodeDisplayTitle } from './node-title'\nimport { useReuse } from './reuse-context'\nimport { activeDrag, beginDrag, endDrag, onDragSessionEnd } from './drag-session'\n\ninterface TreeRow {\n id: string\n componentId: string\n /** The node itself — EC-407 derives the instance title from its prop values. */\n node: ComponentNode\n depth: number\n isRoot: boolean\n isFirst: boolean\n isLast: boolean\n}\n\nfunction flatten(\n node: ComponentNode,\n depth: number,\n rows: TreeRow[],\n meta: { isFirst: boolean; isLast: boolean; isRoot: boolean },\n): void {\n rows.push({ id: node.id, componentId: node.componentId, node, depth, ...meta })\n for (const children of Object.values(node.slots ?? {})) {\n children.forEach((child, i) =>\n flatten(child, depth + 1, rows, {\n isFirst: i === 0,\n isLast: i === children.length - 1,\n isRoot: false,\n }),\n )\n }\n}\n\n/**\n * The tree's dragover resolution (EC-160/EC-162), pure: the row under the pointer\n * → a drop position (the hit band along the parent's flow axis; the root row is\n * always `into`) → the shared {@link resolveDrop} verdict → the row indicator.\n * Extracted from the React handler (EC-554) so the tree surface's placement rules\n * are pinned without a DOM — the handler only measures the pointer and renders.\n */\nexport function resolveTreeRowDrop(args: {\n root: ComponentNode\n getManifest: ManifestLookup\n /** The layout-role component ids (EC-591) — `builder.layout`. */\n layout: LayoutContainerIds\n /** EC-584: the store's placement scope (`builder.placement`) — the reducer judges the same. */\n placement: PlacementScope\n subject: DragSubject\n row: { id: string; componentId: string; isRoot: boolean }\n /** Pointer offset within the row box, 0..1 per axis (unused for the root row). */\n pointer: { x: number; y: number }\n}): { resolution: DropResolution; indicator: DropIndicator } {\n const { root, getManifest, layout, placement, subject, row, pointer } = args\n let position: DropPosition = 'into'\n if (!row.isRoot) {\n // The hit-band axis follows the parent container's flow (EC-162):\n // children of horizontal Stacks/Grids reorder along the row's x axis.\n const flow = containerFlowAxis(getParentInfo(root, row.id)?.parent, layout)\n position = dropPositionForPointer({\n ratio: flow === 'horizontal' ? pointer.x : pointer.y,\n nestable: canNestInto(getManifest, row.componentId),\n edges: true,\n })\n }\n const resolution = resolveDrop({\n root,\n getManifest,\n layout,\n placement,\n subject,\n location: { nodeId: row.id, position },\n })\n return { resolution, indicator: dropIndicatorFor(resolution, position) }\n}\n\n/** Tailwind classes per drop indicator state (EC-160/EC-162) — rejection is visible. */\nconst ROW_DROP_CLASSES: Record<Exclude<DropIndicator, null>, string> = {\n into: 'ring-1 ring-inset ring-emerald-400 bg-emerald-400/10',\n before: 'shadow-[inset_0_2px_0_0_#38bdf8]',\n after: 'shadow-[inset_0_-2px_0_0_#38bdf8]',\n // Wrap-into-columns gesture (EC-162): the tree can execute wrap plans, the\n // bands themselves are a canvas gesture (rows have no spatial \"beside\").\n left: 'shadow-[inset_2px_0_0_0_#a78bfa] bg-violet-400/10',\n right: 'shadow-[inset_-2px_0_0_0_#a78bfa] bg-violet-400/10',\n blocked: 'ring-1 ring-inset ring-red-500/80 bg-red-500/10 cursor-not-allowed',\n}\n\nexport function PageTree({ onAddChild }: { onAddChild: (parentId: string) => void }) {\n const builder = useBuilder()\n const studio = getStudioRegistry()\n const uiLocale = useUiLocale()\n const rows: TreeRow[] = []\n flatten(builder.present, 0, rows, { isFirst: true, isLast: true, isRoot: true })\n\n // Copy/cut/paste (EC-175): keyboard shortcuts for the whole studio window\n // (the canvas iframe wires its own document) plus per-row affordances. The\n // shared listener keeps shortcuts inert in form fields/inline editors. (A\n // \"published preview is read-only\" guard used to sit here, keyed on the\n // collaboration store's `previewMode`; that mode was a constant `'draft'` with\n // no setter caller, so the guard never fired — EC-574 deleted both.)\n const clipboard = useStudioClipboard()\n const selectedIdRef = useRef(builder.selectedId)\n selectedIdRef.current = builder.selectedId\n useEffect(\n () =>\n attachClipboardListeners(window, {\n clipboard,\n getSelectedId: () => selectedIdRef.current,\n getSelection: () => window.getSelection(),\n }),\n [clipboard],\n )\n\n // Delete/Backspace removes the selected node from the tree side too (EC-404),\n // beside the clipboard shortcuts. Inert while focus is in a form field /\n // inline editor (isEditingContext).\n const { dispatch } = builder\n const rootId = builder.present.id\n useEffect(\n () =>\n attachDeleteKeyListener(window, {\n getSelectedId: () => selectedIdRef.current,\n remove: (id) => dispatch({ type: 'remove', id }),\n getRootId: () => rootId,\n }),\n [rootId, dispatch],\n )\n\n // Drag & drop (EC-160): eligibility comes from the same pure rule set the\n // canvas uses (`lib/dnd/drop-rules`); the tree only renders the resolution.\n // One eligible drop dispatches exactly one move/insert action.\n // The current plan lives in a ref: `drop` fires synchronously after the\n // last `dragover`, before React flushes indicator state.\n const dropPlanRef = useRef<DropPlan | null>(null)\n const [drop, setDrop] = useState<{ rowId: string; indicator: DropIndicator } | null>(null)\n const clearDrop = () => {\n dropPlanRef.current = null\n setDrop(null)\n }\n useEffect(() => onDragSessionEnd(() => clearDrop()), [])\n // EC-386: adapt through `manifestRules` so blocks-prop regions (e.g. a\n // Section's `body`) are drop targets with their `allow` leash, like raw slots.\n const getManifest = (id: string) => manifestRules(studio.registry.getManifest(id))\n\n function handleRowDragStart(row: TreeRow, e: React.DragEvent) {\n if (row.isRoot) {\n e.preventDefault()\n return\n }\n beginDrag(\n {\n subject: { kind: 'node', nodeId: row.id, componentId: row.componentId },\n source: 'tree',\n label: componentDisplayName(row.componentId, studio.registry.getManifest(row.componentId)),\n },\n e.dataTransfer,\n )\n }\n\n function handleRowDragOver(row: TreeRow, e: React.DragEvent) {\n const drag = activeDrag()\n if (!drag) return\n const rect = e.currentTarget.getBoundingClientRect()\n const { resolution, indicator } = resolveTreeRowDrop({\n root: builder.present,\n getManifest,\n layout: builder.layout,\n placement: builder.placement,\n subject: drag.subject,\n row,\n pointer: {\n x: rect.width > 0 ? (e.clientX - rect.left) / rect.width : 0.5,\n y: rect.height > 0 ? (e.clientY - rect.top) / rect.height : 0.5,\n },\n })\n dropPlanRef.current = resolution.eligible ? resolution : null\n setDrop({ rowId: row.id, indicator })\n if (resolution.eligible) {\n e.preventDefault()\n e.dataTransfer.dropEffect = drag.subject.kind === 'node' ? 'move' : 'copy'\n }\n }\n\n function handleRowDrop(e: React.DragEvent) {\n const drag = activeDrag()\n if (!drag) return\n const plan = dropPlanRef.current\n clearDrop()\n if (!plan) return\n e.preventDefault()\n // Exactly one dispatch per completed drop (one undo step, one command).\n if (plan.kind === 'move') {\n builder.dispatch({ type: 'move', id: plan.nodeId, target: plan.target })\n } else if (plan.kind === 'wrap') {\n // EC-162: shared plan vocabulary — the tree executes wrap plans too.\n const subject =\n plan.nodeId !== undefined\n ? { kind: 'node' as const, nodeId: plan.nodeId }\n : drag.buildNode\n ? { kind: 'component' as const, node: drag.buildNode() }\n : null\n if (!subject) {\n endDrag('cancelled')\n return\n }\n builder.dispatch({ type: 'wrap', referenceId: plan.referenceId, side: plan.side, subject })\n } else if (drag.buildNode) {\n builder.dispatch({ type: 'insert', target: plan.target, node: drag.buildNode() })\n } else {\n endDrag('cancelled')\n return\n }\n endDrag('dropped')\n }\n\n function handleRowDragEnd() {\n clearDrop()\n endDrag('cancelled')\n }\n\n return (\n <div className=\"flex h-full min-h-0 flex-col\">\n <Row gap=\"2\" className=\"h-10 shrink-0 border-b border-border px-3\">\n <Text size=\"sm\" weight=\"semibold\">\n {translate('builder.pageTree.title')}\n </Text>\n <Spacer />\n <Text size=\"xs\" tone=\"subtle\" mono>\n {rows.length}\n </Text>\n </Row>\n <div\n className=\"min-h-0 flex-1 overflow-auto p-1.5\"\n onMouseLeave={() => builder.dispatch({ type: 'hover', id: null })}\n onDragLeave={(e) => {\n // Clear the indicator when the drag exits the tree panel.\n if (!e.currentTarget.contains(e.relatedTarget as Node | null)) clearDrop()\n }}\n >\n {rows.map((row) => {\n const manifest = studio.registry.getManifest(row.componentId)\n const title = nodeDisplayTitle(manifest, row.node, uiLocale)\n const selected = row.id === builder.selectedId\n const hovered = row.id === builder.hoveredId\n return (\n <div\n key={row.id}\n onMouseEnter={() => builder.dispatch({ type: 'hover', id: row.id })}\n draggable={!row.isRoot}\n onDragStart={(e) => handleRowDragStart(row, e)}\n onDragOver={(e) => handleRowDragOver(row, e)}\n onDrop={handleRowDrop}\n onDragEnd={handleRowDragEnd}\n data-tree-row={row.id}\n data-tree-drop={drop?.rowId === row.id ? (drop.indicator ?? undefined) : undefined}\n className={cn(\n 'group flex items-center rounded-md pr-1 text-left text-xs transition-colors',\n selected\n ? 'bg-accent text-accent-foreground'\n : hovered\n ? 'bg-muted text-foreground'\n : 'text-muted-foreground',\n drop?.rowId === row.id && drop.indicator\n ? ROW_DROP_CLASSES[drop.indicator]\n : undefined,\n )}\n >\n <button\n type=\"button\"\n onClick={() => builder.dispatch({ type: 'select', id: row.id })}\n title={row.componentId}\n className=\"flex min-w-0 flex-1 items-center gap-1.5 py-1\"\n style={{ paddingLeft: `${6 + row.depth * 14}px` }}\n >\n {/* EC-407: instance title (its own text content) is primary; the\n localized component name is secondary context. The raw mono id\n left the row — it stays in the `title=` above + inspector header. */}\n <span className=\"truncate\">{title.primary}</span>\n {title.secondary ? (\n <span className=\"truncate text-muted-foreground/70\">{title.secondary}</span>\n ) : null}\n </button>\n\n <div\n className={cn(\n 'flex shrink-0 items-center gap-0.5',\n selected\n ? 'opacity-100'\n : 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100',\n )}\n >\n {/* Add child stays inline — the one constructive, high-frequency\n action. Everything else collapses into the ••• menu so labels\n stop cropping on the 200–240px panel (EC-211). */}\n <IconAction label={translate('builder.pageTree.addChild')} onClick={() => onAddChild(row.id)}>\n <Plus />\n </IconAction>\n <RowActionsMenu row={row} builder={builder} clipboard={clipboard} />\n </div>\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n\n/** Right-aligned keyboard-shortcut hint in a menu item — informational only; the\n * shortcut fires globally via the clipboard listeners regardless of the menu. */\nfunction MenuShortcut({ children }: { children: React.ReactNode }) {\n return <span className=\"ml-auto pl-6 text-xs tracking-widest text-muted-foreground\">{children}</span>\n}\n\n/**\n * The per-row \"•••\" action menu (EC-211). Copy/Paste on every row; Cut, Move,\n * Duplicate, Delete for non-root rows. Collapsing the old inline icon cluster\n * (up to 8 buttons, cropping on the 200–240px panel) into a menu changes no\n * behavior — same clipboard fragment + dispatch paths, same Cmd/Ctrl shortcuts.\n * Delete stays a one-click (undoable) destructive item, consistent with the rest\n * of the studio.\n */\nfunction RowActionsMenu({\n row,\n builder,\n clipboard,\n}: {\n row: { id: string; isRoot: boolean; isFirst: boolean; isLast: boolean }\n builder: ReturnType<typeof useBuilder>\n clipboard: ReturnType<typeof useStudioClipboard>\n}) {\n // EC-282 in-canvas reuse gestures, present only where a reuse capability is\n // configured (and the row is eligible). Null outside the composition editor.\n const reuse = useReuse()\n const canMakeReusable = !row.isRoot && (reuse?.canMakeReusable(row.id) ?? false)\n const canDetach = reuse?.canDetach(row.id) ?? false\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n size=\"icon-sm\"\n variant=\"ghost\"\n aria-label={translate('builder.pageTree.moreActions')}\n title={translate('builder.pageTree.moreActions')}\n className=\"size-6\"\n >\n <MoreHorizontal />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\">\n <DropdownMenuItem onClick={() => clipboard.copyNode(row.id)}>\n <ClipboardCopy /> {translate('common.copy')} <MenuShortcut>⌘C</MenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => void clipboard.pasteFromClipboard(row.id)}>\n <ClipboardPaste /> {translate('builder.clipboard.paste')} <MenuShortcut>⌘V</MenuShortcut>\n </DropdownMenuItem>\n {!row.isRoot ? (\n <>\n <DropdownMenuItem onClick={() => clipboard.cutNode(row.id)}>\n <ClipboardX /> {translate('builder.clipboard.cut')} <MenuShortcut>⌘X</MenuShortcut>\n </DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n disabled={row.isFirst}\n onClick={() => builder.dispatch({ type: 'reorder', id: row.id, delta: -1 })}\n >\n <ChevronUp /> {translate('builder.pageTree.moveUp')}\n </DropdownMenuItem>\n <DropdownMenuItem\n disabled={row.isLast}\n onClick={() => builder.dispatch({ type: 'reorder', id: row.id, delta: 1 })}\n >\n <ChevronDown /> {translate('builder.pageTree.moveDown')}\n </DropdownMenuItem>\n <DropdownMenuItem onClick={() => builder.dispatch({ type: 'duplicate', id: row.id })}>\n <Copy /> {translate('common.duplicate')}\n </DropdownMenuItem>\n {canMakeReusable || canDetach ? <DropdownMenuSeparator /> : null}\n {canMakeReusable ? (\n <DropdownMenuItem onClick={() => reuse?.startMakeReusable(row.id)}>\n <Boxes /> {translate('builder.reuse.makeReusable')}\n </DropdownMenuItem>\n ) : null}\n {canDetach ? (\n <DropdownMenuItem onClick={() => reuse?.detach(row.id)}>\n <Unlink /> {translate('builder.reuse.detachToCopy')}\n </DropdownMenuItem>\n ) : null}\n <DropdownMenuSeparator />\n <DropdownMenuItem\n variant=\"destructive\"\n onClick={() => builder.dispatch({ type: 'remove', id: row.id })}\n >\n <Trash2 /> {translate('common.delete')}\n </DropdownMenuItem>\n </>\n ) : null}\n </DropdownMenuContent>\n </DropdownMenu>\n )\n}\n\nfunction IconAction({\n label,\n onClick,\n disabled,\n destructive,\n children,\n}: {\n label: string\n onClick: () => void\n disabled?: boolean\n destructive?: boolean\n children: React.ReactNode\n}) {\n return (\n <Button\n size=\"icon-sm\"\n variant=\"ghost\"\n aria-label={label}\n title={label}\n disabled={disabled}\n onClick={onClick}\n className={cn('size-6', destructive && 'hover:text-destructive')}\n >\n {children}\n </Button>\n )\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import type { PlacementVerdict } from '@elytracms/core/project-graph';
2
+ import type { PlacementRefusal } from './builder-store.js';
3
+ /**
4
+ * The sentence for a refused placement — pure (beyond the catalog and the registry's
5
+ * titles), so each wording is pinned without mounting. A field refusal names the
6
+ * FIELD (`fieldLabel`), never the invisible synthetic root's slot.
7
+ */
8
+ export declare function placementRefusalMessage(verdict: PlacementVerdict, fieldLabel: string, label?: (componentId: string) => string): string;
9
+ /**
10
+ * The refusal above the canvas while it stands (the next edit, selection, undo or redo
11
+ * clears it; the editor may dismiss it). `role="alert"` so assistive tech announces it
12
+ * the moment a drop, paste, duplicate or reuse gesture is refused.
13
+ */
14
+ export declare function PlacementRefusalNotice({ refusal, fieldLabel, onDismiss, }: {
15
+ refusal: PlacementRefusal | null;
16
+ fieldLabel: string;
17
+ onDismiss: () => void;
18
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Ban, X } from 'lucide-react';
3
+ import { Button, Row, Text } from '@elytracms/studio/ui';
4
+ import { getStudioRegistry } from '@elytracms/studio/lib/registry';
5
+ import { componentDisplayName } from '@elytracms/studio/lib/persona/labels';
6
+ import { translate } from '@elytracms/studio/lib/i18n';
7
+ /**
8
+ * EC-584 — the visible reason a placement was refused. The builder reducer runs the
9
+ * one core judge over every node an `insert`/`replace`/`move`/`wrap`/`duplicate`
10
+ * places and, on a refusal, leaves the composition unchanged and records the verdict
11
+ * (`BuilderState.refusal`); this is how that verdict reaches the editor. Never a
12
+ * silent no-op.
13
+ */
14
+ /** A component's label in a notice — its manifest title (EC-591: never a stripped id prefix). */
15
+ function componentLabel(componentId) {
16
+ return componentDisplayName(componentId, getStudioRegistry().registry.getManifest(componentId));
17
+ }
18
+ /**
19
+ * The sentence for a refused placement — pure (beyond the catalog and the registry's
20
+ * titles), so each wording is pinned without mounting. A field refusal names the
21
+ * FIELD (`fieldLabel`), never the invisible synthetic root's slot.
22
+ */
23
+ export function placementRefusalMessage(verdict, fieldLabel, label = componentLabel) {
24
+ const component = label(verdict.componentId);
25
+ if (verdict.code === 'server-only-component') {
26
+ return translate('builder.placement.serverOnly', { component });
27
+ }
28
+ if (verdict.site.kind === 'field') {
29
+ return translate('builder.placement.notAllowedByField', { component, field: fieldLabel });
30
+ }
31
+ return translate('builder.placement.notAllowedInSlot', {
32
+ component,
33
+ destination: `${label(verdict.site.parentComponentId)} · ${verdict.site.slot}`,
34
+ });
35
+ }
36
+ /**
37
+ * The refusal above the canvas while it stands (the next edit, selection, undo or redo
38
+ * clears it; the editor may dismiss it). `role="alert"` so assistive tech announces it
39
+ * the moment a drop, paste, duplicate or reuse gesture is refused.
40
+ */
41
+ export function PlacementRefusalNotice({ refusal, fieldLabel, onDismiss, }) {
42
+ if (!refusal)
43
+ return null;
44
+ return (_jsxs(Row, { gap: "2", align: "center", role: "alert", "data-testid": "placement-refusal", "data-refusal-code": refusal.verdict.code, className: "shrink-0 border-b border-border bg-destructive/10 px-3 py-1.5", children: [_jsx(Ban, { "aria-hidden": true, className: "size-3.5 shrink-0 text-destructive" }), _jsx(Text, { size: "xs", className: "min-w-0 flex-1", children: placementRefusalMessage(refusal.verdict, fieldLabel) }), _jsx(Button, { size: "icon-sm", variant: "ghost", "aria-label": translate('builder.placement.dismiss'), title: translate('builder.placement.dismiss'), onClick: onDismiss, children: _jsx(X, {}) })] }));
45
+ }
46
+ //# sourceMappingURL=placement-refusal.js.map