efficient-easel 0.104.0 → 0.105.0

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 (106) hide show
  1. package/README.md +59 -1
  2. package/dist/CanvasDragLayer-zgYT1xwY.d.ts +168 -0
  3. package/dist/chrome/index.js +1 -1
  4. package/dist/{chunk-KVNRNDUC.js → chunk-3P6AMTOS.js} +1 -1
  5. package/dist/chunk-4XQUWGIV.js +65 -0
  6. package/dist/{chunk-QCBWT2XE.js → chunk-53G47SWO.js} +1 -1
  7. package/dist/{chunk-IWAPPEL4.js → chunk-5ZBBXZPV.js} +1 -1
  8. package/dist/chunk-7FBDZTUD.js +2 -0
  9. package/dist/chunk-7V5WZ46F.js +2 -0
  10. package/dist/{chunk-4EUWOGZF.js → chunk-CLOS6SSX.js} +1 -1
  11. package/dist/{chunk-ZOJEFIP4.js → chunk-GMCZXMOV.js} +1 -1
  12. package/dist/{chunk-OYX47SL7.js → chunk-HNKB2ZYR.js} +1 -1
  13. package/dist/{chunk-R2MUSGPS.js → chunk-IE4GFYKO.js} +1 -1
  14. package/dist/{chunk-UB7JVPK4.js → chunk-KG7RJWOK.js} +1 -1
  15. package/dist/chunk-N7VRF7PR.js +5 -0
  16. package/dist/{chunk-PYNQRX56.js → chunk-NYKIQJT2.js} +1 -1
  17. package/dist/chunk-PA3PNTVV.js +1 -0
  18. package/dist/chunk-PLVEGYK6.js +1 -0
  19. package/dist/chunk-PQXIFBDY.js +1 -0
  20. package/dist/{chunk-NEQIEYYO.js → chunk-QH6LCNOX.js} +1 -1
  21. package/dist/{chunk-Z6BAZFSW.js → chunk-R6WTQWAC.js} +2 -2
  22. package/dist/{chunk-BBRY7KI4.js → chunk-RQHC4TD6.js} +3 -3
  23. package/dist/{chunk-QDEZQ5A6.js → chunk-S4AWJX4Q.js} +1 -1
  24. package/dist/{chunk-YODRYAZX.js → chunk-SARZN4M7.js} +1 -1
  25. package/dist/chunk-SQTY6CJD.js +1 -0
  26. package/dist/{chunk-QOPY2LQM.js → chunk-TBF5CVPA.js} +1 -1
  27. package/dist/chunk-THWO5YVZ.js +1 -0
  28. package/dist/chunk-TLZG2FCF.js +1 -0
  29. package/dist/chunk-U3JP4VGF.js +2 -0
  30. package/dist/{chunk-LXEOVUAV.js → chunk-V4LF7D4F.js} +1 -1
  31. package/dist/chunk-VSHV6KJQ.js +5 -0
  32. package/dist/{chunk-OM67AJQC.js → chunk-VSOP4GUM.js} +1 -1
  33. package/dist/{chunk-6DJHRLCU.js → chunk-YC4TB3CJ.js} +9 -9
  34. package/dist/{chunk-TTENU2HX.js → chunk-YN4KND5F.js} +1 -1
  35. package/dist/chunk-ZTTWFAAC.js +1 -0
  36. package/dist/drag/index.d.ts +4 -164
  37. package/dist/edit-lock/index.d.ts +55 -1
  38. package/dist/edit-lock/index.js +1 -1
  39. package/dist/{host-DJ8Gzsx7.d.ts → host-BQ_b9Qzk.d.ts} +27 -1
  40. package/dist/screen/components/AddBlockRow.js +1 -1
  41. package/dist/screen/components/AddSidePanel.js +1 -1
  42. package/dist/screen/components/MediaSidePanel.d.ts +1 -1
  43. package/dist/screen/components/MediaSidePanel.js +1 -1
  44. package/dist/screen/components/NodeContextMenu.d.ts +167 -9
  45. package/dist/screen/components/NodeContextMenu.js +1 -1
  46. package/dist/screen/components/PageEditGuardNotices.js +1 -1
  47. package/dist/screen/components/ScreenChrome.js +1 -1
  48. package/dist/screen/components/ScreenDocumentContext.d.ts +1 -1
  49. package/dist/screen/components/ScreenDocumentContext.js +1 -1
  50. package/dist/screen/components/ScreenMount.d.ts +10 -2
  51. package/dist/screen/components/ScreenMount.js +1 -1
  52. package/dist/screen/components/ScreenStoreProvider.d.ts +18 -6
  53. package/dist/screen/components/ScreenStoreProvider.js +1 -1
  54. package/dist/screen/components/SectionScreenShell.js +16 -16
  55. package/dist/screen/components/SidePanelHead.js +1 -1
  56. package/dist/screen/components/panel-widths.js +1 -1
  57. package/dist/screen/components/usePartBridge.d.ts +18 -6
  58. package/dist/screen/components/usePartBridge.js +1 -1
  59. package/dist/screen/index.d.ts +13 -5
  60. package/dist/screen/index.js +1 -1
  61. package/dist/screen/lib/admin-bridge.js +1 -1
  62. package/dist/screen/lib/document-addressing.d.ts +1 -1
  63. package/dist/screen/lib/document-switch.js +1 -1
  64. package/dist/screen/lib/failure.js +1 -1
  65. package/dist/screen/lib/host-inbound.js +1 -1
  66. package/dist/screen/lib/host.d.ts +1 -1
  67. package/dist/screen/lib/host.js +1 -1
  68. package/dist/screen/lib/key-scope.js +1 -1
  69. package/dist/screen/lib/media-panel.d.ts +1 -1
  70. package/dist/screen/lib/media-panel.js +1 -1
  71. package/dist/screen/lib/media-picker.d.ts +1 -1
  72. package/dist/screen/lib/media-picker.js +1 -1
  73. package/dist/screen/lib/page-lock.js +1 -1
  74. package/dist/screen/lib/puck/content-tree.d.ts +8 -1
  75. package/dist/screen/lib/puck/content-tree.js +1 -1
  76. package/dist/screen/lib/puck/palette-sections.d.ts +7 -0
  77. package/dist/screen/lib/puck/palette-sections.js +1 -1
  78. package/dist/screen/lib/puck/section-doc.js +1 -1
  79. package/dist/screen/lib/puck/slot-child-name.d.ts +25 -1
  80. package/dist/screen/lib/puck/slot-child-name.js +1 -1
  81. package/dist/screen/lib/puck/style-clipboard.d.ts +53 -1
  82. package/dist/screen/lib/puck/style-clipboard.js +1 -1
  83. package/dist/screen/lib/puck/use-section-ops.js +1 -1
  84. package/dist/screen/lib/screen-parts.d.ts +471 -8
  85. package/dist/screen/lib/screen-parts.js +1 -1
  86. package/dist/screen/screen.css +18 -0
  87. package/dist/screen/words.d.ts +73 -2
  88. package/dist/screen/words.js +1 -1
  89. package/dist/strings/catalogue.d.ts +4 -2
  90. package/dist/strings/catalogue.js +1 -1
  91. package/dist/strings/index.d.ts +1 -1
  92. package/dist/strings/index.js +1 -1
  93. package/package.json +1 -1
  94. package/dist/chunk-5D2XAZKH.js +0 -62
  95. package/dist/chunk-7755VWRT.js +0 -4
  96. package/dist/chunk-7GVLSNFW.js +0 -1
  97. package/dist/chunk-A2LFBOUF.js +0 -1
  98. package/dist/chunk-D6324C3E.js +0 -5
  99. package/dist/chunk-GENAF3P6.js +0 -1
  100. package/dist/chunk-HMWJB3HF.js +0 -1
  101. package/dist/chunk-JUQ6YJCG.js +0 -1
  102. package/dist/chunk-LEGAPYPC.js +0 -1
  103. package/dist/chunk-LRTIMWZG.js +0 -2
  104. package/dist/chunk-Q2HPBMG5.js +0 -1
  105. package/dist/chunk-R5ZVNJLJ.js +0 -2
  106. package/dist/chunk-SERF2FAU.js +0 -1
@@ -1,29 +1,41 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, MouseEvent, ComponentType } from 'react';
3
3
  import { Data } from '../../blocks/index.js';
4
+ import { C as CanvasTarget } from '../../watch-BTYOJpQU.js';
4
5
  import { D as DeviceOption } from '../../types-CqY85foL.js';
6
+ import { P as Place } from '../../types-41704JE4.js';
7
+ import { M as MeasuredCanvas, C as CanvasDragModel } from '../../CanvasDragLayer-zgYT1xwY.js';
8
+ import { E as EaselContextMenuItem } from '../../types-Djdq6Xkd.js';
5
9
  import { a as EaselRailItem } from '../../types-DWS-s9z-.js';
10
+ import { StyleRow } from '../../style-clipboard/index.js';
6
11
  import { T as TreeRowMark } from '../../types-DJDBtdB2.js';
12
+ import { AddKey } from '../components/AddSidePanel.js';
13
+ import { k as AnyScreenTarget } from '../../host-BQ_b9Qzk.js';
7
14
  import { HostProduct } from './host-chrome.js';
8
15
  import { EaselSession } from './session.js';
9
16
  import { AddTarget } from './puck/add-target-types.js';
17
+ import { SlotConfigView } from './puck/content-tree.js';
10
18
  import '../../types-E3HrTPg2.js';
11
19
  import '../../data/index.js';
12
- import '../../types-41704JE4.js';
13
20
  import '../../resolve-D68pb3Bx.js';
14
21
  import '../../plan-DChbUXdS.js';
15
22
  import '../../edit-lock/index.js';
16
23
  import '../../panelWidths-D9hTLR25.js';
24
+ import '../../session-DSQFmIvx.js';
25
+ import '../../words-BDignMl_.js';
17
26
  import '../../wordFit-D4S36PvB.js';
27
+ import '../../words-CnnHb9jo.js';
18
28
  import '../../words-DgHcY5qB.js';
29
+ import './section-template-types.js';
30
+ import './puck/block-choice.js';
31
+ import './document-contract.js';
32
+ import './document-switch.js';
33
+ import '../../engine-DBxp_v6B.js';
34
+ import './admin-bridge.js';
35
+ import './backend-error.js';
19
36
  import './links/link-filters.js';
20
37
  import '../../LinkPicker-W2Rtxetz.js';
21
- import './backend-error.js';
22
- import './document-contract.js';
23
38
  import './document-hooks.js';
24
- import './section-template-types.js';
25
- import './puck/content-tree.js';
26
- import './puck/block-choice.js';
27
39
  import './puck/slot-section-spec.js';
28
40
 
29
41
  /**
@@ -95,6 +107,28 @@ type ScreenPartMode = {
95
107
  * member by member, so the screen can answer without knowing what a layer
96
108
  * keeps beside the kind. */
97
109
  declare function sameInspectorMode(a: ScreenInspectorMode, b: ScreenInspectorMode): boolean;
110
+ /**
111
+ * A SLOT's own panel (0.105.0): the mode the screen opens when the row of a
112
+ * slot it draws as a rung is pressed (`ScreenSlot.panel`) — the campaign
113
+ * designer's Column inspector. `kind` is the layer's (`panel`), and beside it
114
+ * the node the slot is a slot of and the slot's own name. The screen makes it
115
+ * and hands it back to the layer's inspector; a layer may name one itself to
116
+ * `ScreenInspector.select`.
117
+ */
118
+ interface ScreenSlotMode extends ScreenInspectorMode {
119
+ nodeId: string;
120
+ slot: string;
121
+ }
122
+ /** Is a panel a slot's own ({@link ScreenSlotMode}) — about a node's slot, not
123
+ * the node? */
124
+ declare function isSlotMode(mode: ScreenInspectorMode): mode is ScreenSlotMode;
125
+ /** An address of a node the screen selects, as its own ops spell one: its
126
+ * index, in the list `zone` names (left out for the top-level list); or null,
127
+ * for nothing selected. */
128
+ type ScreenSelector = {
129
+ index: number;
130
+ zone?: string;
131
+ } | null;
98
132
  /** The inspector, as far as a layer needs it: which panel it shows, and how to
99
133
  * show one of the layer's own. */
100
134
  interface ScreenInspector {
@@ -116,6 +150,18 @@ interface ScreenInspector {
116
150
  show: (mode: ScreenInspectorMode) => void;
117
151
  /** Bring the inspector into view if it is hidden. What it shows stays. */
118
152
  reveal: () => void;
153
+ /**
154
+ * Move the selection AND put a panel of the layer's own in the inspector, in
155
+ * one step (0.105.0): what the campaign designer's Column needs, which is a
156
+ * slot and not a node — nothing is selected (`null`) and the Column
157
+ * inspector shows. `show` then a selection would not hold: the screen puts
158
+ * the inspector back to the selection's own panel whenever the selection
159
+ * changes, so the mode is kept pending and that reset honours it for this
160
+ * one change. The inspector is left as it stands, in view or hidden, as
161
+ * `show` leaves it. A slot's own panel ({@link ScreenSlotMode}) for a slot
162
+ * the tree draws as a rung also unfolds the tree to that rung's row.
163
+ */
164
+ select: (selector: ScreenSelector, mode: ScreenInspectorMode) => void;
119
165
  }
120
166
  /**
121
167
  * What the screen hands THE INSPECTOR it mounts in its right panel
@@ -394,10 +440,26 @@ interface ScreenBridges {
394
440
  * scroll; absent, the screen scrolls.
395
441
  */
396
442
  holdCanvasOn?: (id: string) => void;
443
+ /**
444
+ * THE LAYER'S OWN ROWS IN A NODE'S RIGHT-CLICK MENU (0.105.0), by the group
445
+ * each joins (`ScreenMenuRows`): the campaign designer's "Check this image
446
+ * loads" and its phone rows. Asked of the node the menu was opened on, and
447
+ * where it sits, every time the menu is drawn; what comes back is placed at
448
+ * the end of its group, after the screen's own rows, as it is handed — a row
449
+ * that writes runs a component or an op of the layer's that reaches the
450
+ * document itself. Nothing handed back adds nothing. Absent: the screen's
451
+ * rows alone, as the menu has always drawn them.
452
+ */
453
+ menuRows?: (node: ScreenNode, zone: string, index: number) => ScreenMenuRows | null | undefined;
397
454
  /** The layer's own context, stood round the whole screen. What it is handed
398
455
  * is the screen; what it returns is rendered in the screen's place. */
399
456
  wrap?: (screen: ReactNode) => ReactNode;
400
457
  }
458
+ /** A layer's own rows in a node's menu, by the group of the menu each goes at
459
+ * the end of (efficient-easel/node-ops `nodeMenuItems`' `extras`): `pick`
460
+ * (Select layer), `make` (Duplicate … Paste), `change` (Rename, Hide …) and
461
+ * `remove` (Delete). */
462
+ type ScreenMenuRows = Partial<Record<"pick" | "make" | "change" | "remove", EaselContextMenuItem[]>>;
401
463
  /** A block type's own default props, read off the config the screen holds.
402
464
  * The screen's to look up and a layer's to be lent: a layer that reached into
403
465
  * the config for itself would be holding a second copy of it. */
@@ -462,8 +524,50 @@ interface ScreenBlockRules {
462
524
  * tree, the panel, the menu, the Add panel), so no two of them can come to
463
525
  * offer one node different lists; what each of the layer's blocks takes is
464
526
  * the layer's catalogue, and the screen is not told it.
527
+ *
528
+ * `slot` (0.105.0) is asked where the screen means ONE slot of a node that
529
+ * has several: a gap or an empty slot in the tree, a slot place Add was
530
+ * opened at, a drop into a slot. The answer is that slot's (the campaign
531
+ * designer's Column 2 answers `col2`); a layer that keeps one slot per node
532
+ * may ignore it, and the screen then offers that slot alone, as before.
465
533
  */
466
- canAddTo: (nodeType: string, nestDepth?: number) => AddTarget | null;
534
+ canAddTo: (nodeType: string, nestDepth?: number, slot?: string) => AddTarget | null;
535
+ /**
536
+ * THE SLOTS OF A NODE, IN ORDER, AS THE SCREEN DRAWS THEM (0.105.0). A slot
537
+ * that is a `rung` is a row of its own in the Layers tree, with its children
538
+ * under it, a level of the Select layer flyout and a place of its own in a
539
+ * drag: the campaign designer's section draws Column 1 and Column 2 so from
540
+ * two columns up, and its lone column not at all. Every other slot's children
541
+ * hang straight off the node's row, as they do today. A slot left out of the
542
+ * answer is not drawn (a column the section's layout hides). The tree, the
543
+ * Add panel's "Adding to …", the drag and the flyout read it; where a node's
544
+ * children are FOUND (the menu, a write, a drop's checks) is still every
545
+ * slot field.
546
+ *
547
+ * Answered for every node the tree draws; null or undefined for one is the
548
+ * screen's own reading of it, so a layer may answer for its sections alone.
549
+ * Absent: every slot field the config declares, in its order, none of them a
550
+ * rung — the tree the website has.
551
+ */
552
+ slotsOf?: (node: ScreenNode) => ReadonlyArray<ScreenSlot> | null | undefined;
553
+ /**
554
+ * A RUNG MOVED (0.105.0): the rung at `from` in the node's run of rungs (its
555
+ * place among `slotsOf`'s rungs) dropped so it rests at `to` — a drag in the
556
+ * tree, or ⌥↑ / ⌥↓ on its row. The layer writes the move (the campaign
557
+ * designer swaps two columns' blocks, or reorders the phone stack) and may
558
+ * answer the slot to select after it, which the screen selects as a press
559
+ * on that rung's row does. Absent: no rung is picked up.
560
+ */
561
+ moveSlot?: (nodeId: string, from: number, to: number) => string | null | void;
562
+ /**
563
+ * What a rung's row offers besides its fold (0.105.0): the campaign
564
+ * designer's Duplicate and Delete of a column, drawn in the order handed,
565
+ * among the row's actions. The screen confirms nothing: what a press asks
566
+ * first (Delete a column that still holds blocks) is the layer's `run`.
567
+ * Withheld while the document is read-only. Absent, or nothing handed: the
568
+ * row has none.
569
+ */
570
+ slotActions?: (node: ScreenNode, slot: string) => ReadonlyArray<ScreenSlotAction> | null | undefined;
467
571
  /**
468
572
  * Does the host of this editor offer the type? Asked of the editor's own
469
573
  * session where the screen holds it, else of the editor on the page. Where
@@ -482,6 +586,64 @@ interface ScreenBlockRules {
482
586
  */
483
587
  resolveOnInsert?: boolean;
484
588
  }
589
+ /**
590
+ * ONE SLOT OF A NODE, as the screen draws it (`ScreenBlockRules.slotsOf`,
591
+ * 0.105.0). Only `slot` and `rung` are read of a slot that is not a rung.
592
+ */
593
+ interface ScreenSlot {
594
+ /** The slot field's name (`col2`): its children are `props[slot]`, its list
595
+ * is `${nodeId}:${slot}`. */
596
+ slot: string;
597
+ /** What the rung's row says ("Column 2"), and the flyout, and Add's
598
+ * "Adding to …". */
599
+ label: string;
600
+ /** The rung's glyph, drawn as handed. Absent: none. */
601
+ glyph?: ReactNode;
602
+ /** Drawn as a row of its own, its children under it. False: its children
603
+ * hang straight off the node's row. */
604
+ rung: boolean;
605
+ /**
606
+ * The kind of the layer's panel this rung is edited in (the Column
607
+ * inspector): a press on its row selects nothing and shows that panel, as a
608
+ * {@link ScreenSlotMode} naming the node and the slot, and the row is lit
609
+ * while it shows; the flyout lists it as a level. Absent: the rung only
610
+ * folds, its press selects the node it is a slot of, and the flyout leaves
611
+ * it out.
612
+ */
613
+ panel?: string;
614
+ /** A pill after the name ("2 of 3", the phone stack's place). */
615
+ badge?: ReactNode;
616
+ /** The hint the row shows when it may be dragged. Absent: the tree's own. */
617
+ dragHint?: string;
618
+ /** Drawn above the rung's row, as handed: the campaign designer's "Phone
619
+ * order" label over its first column. */
620
+ heading?: ReactNode;
621
+ /** False: the rung keeps its place, and is not picked up (a pinned
622
+ * section's columns). Absent: it moves where `moveSlot` is handed. */
623
+ movable?: boolean;
624
+ }
625
+ /** What a rung's row offers (`ScreenBlockRules.slotActions`, 0.105.0). */
626
+ interface ScreenSlotAction {
627
+ /** Which action: the screen draws its glyph, and the delete in its red. */
628
+ kind: "duplicate" | "delete";
629
+ /** Its tooltip and accessible name: "Duplicate Column 2", or why not. */
630
+ label: string;
631
+ /** Drawn, and not pressed: the label says why. */
632
+ disabled?: boolean;
633
+ /**
634
+ * The action, the layer's whole: it asks what it must ask first and writes.
635
+ * It may answer the slot to select after it (the copy, the column that took
636
+ * a deleted one's place), which the screen selects as a press on that rung's
637
+ * row does; nothing, and the selection stays.
638
+ */
639
+ run: () => string | null | void | Promise<string | null | void>;
640
+ }
641
+ /**
642
+ * The slots of `node` as the screen draws them: the layer's answer
643
+ * (`slotsOf`), else — with no `slotsOf`, or none for this node — every slot
644
+ * field the config declares, in its order, none of them a rung.
645
+ */
646
+ declare function screenSlotsOf(rules: ScreenBlockRules, config: SlotConfigView, node: ScreenNode): ReadonlyArray<ScreenSlot>;
485
647
  /** The tier a node is NAMED at: a node at the top of the document is a section,
486
648
  * a node inside another is a block. */
487
649
  type ScreenNodeLevel = "section" | "block";
@@ -559,6 +721,21 @@ interface ScreenBlockLook {
559
721
  * screen's rule, as it named every row.
560
722
  */
561
723
  rowName?: (node: ScreenNode, level: ScreenNodeLevel, fallback: string) => string;
724
+ /**
725
+ * THE PROP A RENAME WRITES, by the layer (0.105.0; owner ruling R11, Victor
726
+ * Mau, 2026-10-09: Rename works on top-level sections in both editors). The
727
+ * write side of `rowName`: handed a node, the level it is named at and
728
+ * `base` — what the screen's own rule answered (lib/puck/slot-child-name
729
+ * `slotChildRenameProp` for a block, `sectionRenameProp` for a section) — it
730
+ * answers the prop the Layers row's rename box writes, or null for a node
731
+ * that has no name of its own, which takes Rename out of its menu. Answer the
732
+ * prop `rowName` reads, so a renamed row says its new name: the campaign
733
+ * designer's sections are named by their `label` ("Section name"). Asked of
734
+ * every node the menu opens on, a pinned node and a section group's too.
735
+ * Absent: the screen's rule — a block's declared name, and a section's
736
+ * `name`, which its row reads.
737
+ */
738
+ renamePropOf?: (node: ScreenNode, level: ScreenNodeLevel, base: string | null) => string | null;
562
739
  /**
563
740
  * The quieter words a node row draws after its name (`TreeRow`'s
564
741
  * `preview`): a node's own first words, so a tree of rows all called
@@ -609,6 +786,116 @@ interface ScreenDevices {
609
786
  /** The width each device is drawn at, in CSS px, by id. For `fluid` it is
610
787
  * only the width of the frame before the pane has been measured. */
611
788
  widths: Readonly<Record<string, number>>;
789
+ /**
790
+ * How a fixed device is fitted to the pane (0.105.0). `"fill"`: scaled to
791
+ * the pane's width, up to twice its size, so a phone reads big and clear in
792
+ * a wide pane — the website's view tiers. `"shrink"`: scaled DOWN when the
793
+ * pane is narrower than the device and never up, so a device is drawn at its
794
+ * real size or smaller — the campaign designer's phone, a mail preview of
795
+ * the width the recipient's phone has. The fluid device is drawn at the
796
+ * pane's width either way. Absent: `"fill"`.
797
+ */
798
+ fit?: "fill" | "shrink";
799
+ }
800
+ /**
801
+ * WHAT A DRAG ON THE PAGE SCREEN CARRIES (0.105.0): a node of the document —
802
+ * its id, the list it sits in (a zone key, `<parentId>:<slot>`), its index
803
+ * there and its type — or, with `add`, a NEW one from the Add panel, which
804
+ * has no place yet. One kind of thing for the ONE drag the Layers tree, the
805
+ * canvas and the Add panel share, so a block picked up on one lands on
806
+ * another. A layer's own canvas sources (`ScreenCanvasDrag.model`) carry it
807
+ * too; a thing of the layer's that is not a node (the campaign designer's
808
+ * column) is told apart by a `zone` and a `type` of the layer's own — a list
809
+ * the document has none of, so the screen's writes find no node there and
810
+ * do nothing, and the Layers tree, which draws no gap in it, takes none. A
811
+ * layer that offers one answers for it on the canvas (`canDrop`, `drop`,
812
+ * `pick`).
813
+ */
814
+ interface ScreenDragItem {
815
+ id: string;
816
+ zone: string;
817
+ index: number;
818
+ type: string;
819
+ add?: AddKey;
820
+ /** A slot the Layers tree draws as a row of its own (`slotsOf`, a rung),
821
+ * picked up by its row: `index` is its place in its node's run of rungs. */
822
+ rung?: {
823
+ nodeId: string;
824
+ slot: string;
825
+ };
826
+ }
827
+ /**
828
+ * What the screen tells a layer's canvas drag each time it asks
829
+ * (`ScreenCanvasDrag`, 0.105.0). Its rules are plain functions, the same for
830
+ * the life of the mount like the block rules, so what they reason about is
831
+ * handed to them: the document as it stands, the device the canvas is drawn
832
+ * as, and — for a drop or a pick that does what the screen's own would not —
833
+ * the screen's writes and its inspector.
834
+ */
835
+ interface ScreenCanvasDragContext {
836
+ /** The working document (`{ root, content, zones }`), as the store holds it
837
+ * now: what the measure and the model are of. */
838
+ data: unknown;
839
+ /** The device the canvas is drawn as, one of the layer's own
840
+ * (`ScreenDevices.options`): a phone may stack what a desktop lays across. */
841
+ device: string;
842
+ /** The screen's writes (`ScreenDocumentOps`, refused while somebody else
843
+ * holds the document), for a drop of the layer's own. */
844
+ ops: ScreenDocumentOps;
845
+ /** The inspector, for a drop or a pick that opens a panel of the layer's
846
+ * own on what it moved or named (a column's). */
847
+ inspector: ScreenInspector;
848
+ }
849
+ /**
850
+ * THE CANVAS DRAG, AS A LAYER HAS IT (`ScreenParts.canvasDrag`, 0.105.0).
851
+ * That there is a drag on the canvas — the handle on the smallest box under
852
+ * the pointer, the one drop line, the catch surface, the session it shares
853
+ * with the Layers tree and the Add panel — is the screen's
854
+ * (efficient-easel/drag `CanvasDragLayer`). How the canvas is MEASURED, what
855
+ * may be picked up on it and what may land where on it may be the layer's: an
856
+ * email lays its sections out in columns, measured from cells of its own, and
857
+ * a column is grabbed by a strip down its edge that is the column's and not its
858
+ * blocks'.
859
+ *
860
+ * Each member is optional and falls back on the screen's own; each is handed
861
+ * the screen's own answer (`base`) as well, so a layer may add to it, narrow it
862
+ * or answer only for what is its own and leave the rest to the screen. They
863
+ * answer for the canvas only: a drop on the Layers tree is the tree's rules',
864
+ * whatever surface the thing was picked up on.
865
+ *
866
+ * Plain functions, the same object for the life of the mount, like the block
867
+ * rules; what they reason about is handed to them (`ScreenCanvasDragContext`).
868
+ */
869
+ interface ScreenCanvasDrag {
870
+ /** How the canvas is measured into boxes, in the coordinates of `layer`
871
+ * (the element the drag layer draws in). Absent: Puck's markers, the slots
872
+ * and the blocks directly in them (efficient-easel/drag `measureCanvas`). */
873
+ measure?: (canvas: CanvasTarget, layer: Element, context: ScreenCanvasDragContext) => MeasuredCanvas;
874
+ /**
875
+ * What may be picked up on what was measured, and which lists take drops,
876
+ * handed the screen's own model of it (`base`: every node but the pinned
877
+ * ones — asked through `isPinnedFirst` / `isPinnedLast` — a locked block, a
878
+ * group of sections, and a section with nothing to trade places with). It
879
+ * is asked of an EMPTY measure too, before the frame is first measured.
880
+ * Absent: `base`.
881
+ */
882
+ model?: (measured: MeasuredCanvas, base: CanvasDragModel<ScreenDragItem>, context: ScreenCanvasDragContext) => CanvasDragModel<ScreenDragItem>;
883
+ /** May the thing in hand land at `to` on the canvas? Handed the screen's
884
+ * own rule (`base`, the Layers tree's). Absent: `base`. */
885
+ canDrop?: (item: ScreenDragItem, to: Place, base: (item: ScreenDragItem, to: Place) => boolean, context: ScreenCanvasDragContext) => boolean;
886
+ /** Land it, at a place `canDrop` said yes to. Handed the screen's own write
887
+ * (`base`, the tree's: a section moved, a block moved, a new one added).
888
+ * Absent: `base`. */
889
+ drop?: (item: ScreenDragItem, to: Place, base: (item: ScreenDragItem, to: Place) => void, context: ScreenCanvasDragContext) => void;
890
+ /** A handle CLICKED, not dragged: select what it names. Handed the screen's
891
+ * own (`base`: the node, as a press on its row selects it). Absent: `base`. */
892
+ pick?: (item: ScreenDragItem, base: (item: ScreenDragItem) => void, context: ScreenCanvasDragContext) => void;
893
+ }
894
+ /** What a layer's head over the canvas is handed (`ScreenParts.CanvasHead`,
895
+ * 0.105.0): the device the canvas is drawn as, so it can say what is the
896
+ * device's (the campaign designer's mail-app switch is desktop's only). */
897
+ interface ScreenCanvasHeadProps {
898
+ device: string;
612
899
  }
613
900
  /**
614
901
  * WHAT IS PINNED in the document's top-level list. That the list has a BAND
@@ -738,6 +1025,100 @@ interface ScreenLeftViewRules {
738
1025
  * view to be on. */
739
1026
  forSelection: (selectedId: string | null | undefined, current: string) => string;
740
1027
  }
1028
+ /**
1029
+ * THE SELECTION, as the screen hands it to a rule that asks where it is
1030
+ * (`ScreenAdd.railTarget`, 0.105.0): the node selected, and the panel the
1031
+ * inspector is showing — the selection's own (`SELECTION_MODE`), or one of the
1032
+ * layer's, such as the campaign designer's column, which is a slot and no
1033
+ * node.
1034
+ */
1035
+ interface ScreenSelection {
1036
+ node: ScreenNode | null;
1037
+ mode: ScreenInspectorMode;
1038
+ }
1039
+ /**
1040
+ * WHERE ADD PUTS WHAT IT ADDS, where that is the layer's to say (0.105.0, seam
1041
+ * E9). That there is an Add panel, what it lists and where a tile dragged out
1042
+ * of it may land are the screen's. Plain data and a plain function, the same
1043
+ * for the life of a mount, for the reason the block rules are.
1044
+ */
1045
+ interface ScreenAdd {
1046
+ /**
1047
+ * Where the rail's "+" aims Add: handed the working document and the
1048
+ * selection, the place a BLOCK the panel adds goes — the campaign designer's
1049
+ * last body section's first column, at its end, where its own drawer put a
1050
+ * block — or null for the screen's own. Asked as the panel draws while it is
1051
+ * open at no place of its own (from the rail, or after its place was
1052
+ * cleared), so a place at the end of a list stays at its end as blocks go in.
1053
+ * A place in a slot heads the panel with what that slot takes ("Inside
1054
+ * Section 3"), and a block tile pressed lands there; the sections still
1055
+ * follow, and land where they always did. A place in the top-level list is
1056
+ * where a section or a saved one lands. No "Adding to …" line is drawn for it:
1057
+ * that line is for a place a "+" named. Absent, or null: the rail's "+" opens
1058
+ * Add at no place — the selected container's blocks, then the blank section,
1059
+ * the saved sections and the sections — as it always has.
1060
+ */
1061
+ railTarget?: (data: unknown, selection: ScreenSelection) => Place | null;
1062
+ /**
1063
+ * Is Add a picker of BLOCKS first, as the campaign designer's drawer is? With
1064
+ * true, where Add offers the blocks of a container — the rail's target, or
1065
+ * the container selected — those blocks are the whole panel, with no
1066
+ * section catalogue after them; and a gap between two sections, where what
1067
+ * goes in is a new section, offers the catalogue alone, with no container's
1068
+ * blocks before it. So one panel never lists the same blocks twice, under the
1069
+ * same headings, for two different places (a container's runs and the
1070
+ * catalogue's groups). A place a "+" names in a slot offers that slot's
1071
+ * blocks alone either way. Absent, false: a container's blocks, then the
1072
+ * catalogue, wherever there is a container to offer — as it always has.
1073
+ */
1074
+ blocksFirst?: boolean;
1075
+ }
1076
+ /** What a style clipboard's scope is read off (`ScreenStyleClipboard.scope`):
1077
+ * the document the screen has open. */
1078
+ interface ScreenStyleDocument {
1079
+ /** What the screen is pointed at: a website's page, or a host's own
1080
+ * document (`{ kind: "document", record }`). */
1081
+ target: AnyScreenTarget;
1082
+ /** The website the page belongs to, or null. */
1083
+ siteId: string | null;
1084
+ /** The backend's id of the loaded document, or null while it loads. */
1085
+ docId: string | null;
1086
+ }
1087
+ /** What a Paste style onto one node would do: its new props, whether they
1088
+ * changed, how many rows were pasted, and the words the merchant reads. */
1089
+ interface ScreenStylePastePlan {
1090
+ props: Record<string, unknown>;
1091
+ changed: boolean;
1092
+ pasted: number;
1093
+ message: string;
1094
+ }
1095
+ /**
1096
+ * COPY STYLE / PASTE STYLE, where it is the layer's (0.105.0, seam E10). The
1097
+ * clipboard, the matching rule, the menu rows, their words and the ⌥⌘C / ⌥⌘V
1098
+ * keys are efficient-easel/style-clipboard's and the screen's; WHICH rows of a
1099
+ * node are its look, and how far a copied look travels (its scope), are the
1100
+ * layer's — the website's look is its Style and Layout tabs and travels across
1101
+ * one site's pages, the campaign designer's is its own panels' and stays in
1102
+ * one campaign. Each member is optional, and one left out is the website's
1103
+ * (lib/puck/style-clipboard): a layer may hand only its scope. Plain functions,
1104
+ * the same object for the life of the mount.
1105
+ */
1106
+ interface ScreenStyleClipboard {
1107
+ /** The clipboard's scope for the open document: in another scope nothing is
1108
+ * held. Absent: `siteStyleScope(siteId)`, one site across its pages. */
1109
+ scope?: (doc: ScreenStyleDocument) => string;
1110
+ /** A node's look, as rows the clipboard holds and matches. Absent: the
1111
+ * website's (`nodeStyleRows`), the Style and Layout tabs. */
1112
+ rows?: (config: unknown, node: ScreenNode) => StyleRow[];
1113
+ /** Copy a node's look into `scope`, named `label` (the menu's word for it).
1114
+ * Absent: its `rows`, copied as they are stored. */
1115
+ copy?: (scope: string, node: ScreenNode, label: string, config: unknown) => void;
1116
+ /** What a paste onto a node would do, or null when nothing is held in
1117
+ * `scope`. The screen writes `props` through its one replace op when
1118
+ * `changed`, and always shows `message`. Absent: the held look laid over the
1119
+ * node's `rows` (efficient-easel/style-clipboard `planPaste`). */
1120
+ plan?: (scope: string, node: ScreenNode, label: string, config: unknown) => ScreenStylePastePlan | null;
1121
+ }
741
1122
  interface ScreenParts {
742
1123
  /**
743
1124
  * The name a panel's head gives what is being edited — the website's name,
@@ -819,6 +1200,38 @@ interface ScreenParts {
819
1200
  * false: a pick outlives a change of selection, as the website's does.
820
1201
  */
821
1202
  pickFollowsSelection?: boolean;
1203
+ /** Where Add puts what it adds, and whether it is a picker of blocks first
1204
+ * (0.105.0; `ScreenAdd`). Absent: the screen's Add, as it always was. */
1205
+ add?: ScreenAdd;
1206
+ /** Copy style / Paste style's scope and a node's look, where they are the
1207
+ * layer's (0.105.0; `ScreenStyleClipboard`). Absent: the website's. */
1208
+ styleClipboard?: ScreenStyleClipboard;
1209
+ /**
1210
+ * Do ⌘C / ⌘X / ⌘V (Ctrl on Windows) copy, cut and paste the SELECTED block
1211
+ * (0.105.0)? The keyboard door to the menu's Copy, Cut and Paste rows, which
1212
+ * print these keys beside them: the menu's rules, the menu's place for a
1213
+ * paste, and a paste with nowhere to go there refused aloud
1214
+ * (`screen.pasteRefused`). Heard on the editor and in the canvas frame, never
1215
+ * where a person types or has words selected, nor with ⌥ (Copy style) or ⇧
1216
+ * held. Nothing is cut or pasted on a document this editor cannot write; a
1217
+ * copy is allowed there.
1218
+ *
1219
+ * Owner ruling R12/R13 (Victor Mau, 2026-10-09): Copy and Paste work the same
1220
+ * way in both editors. So the keys are on unless the layer says false.
1221
+ */
1222
+ nodeKeys?: boolean;
1223
+ /**
1224
+ * THE HOST'S OWN TOASTS (0.105.0; owner ruling R17, Victor Mau, 2026-10-09).
1225
+ * Every line the screen would say in its toast — "Copied Text", "Added
1226
+ * “Hero” section", a refused paste, a pasted style, what a panel of the
1227
+ * layer's or the inspector says through the screen's toast — goes to the host
1228
+ * instead, with its tone: `"error"` for what went wrong, `"info"` for the
1229
+ * rest; and the screen draws no toast of its own. The campaign designer
1230
+ * hands the admin portal's toast, so the designer's lines stand where every
1231
+ * other window's do. Called as each line is said, so it may change between
1232
+ * renders. Absent: the screen's own toast (`.sf-toast`), as before.
1233
+ */
1234
+ notify?: (message: string, tone: "info" | "error") => void;
822
1235
  /**
823
1236
  * THE CANVAS the screen frames: the engine's, as the layer dresses it — the
824
1237
  * layer's own sheet and theme in the frame, its own say over the outline
@@ -828,8 +1241,31 @@ interface ScreenParts {
828
1241
  *
829
1242
  * ONE function for the life of a mount: the screen renders it as an element
830
1243
  * type, and a type that changed identity would remount the whole canvas.
1244
+ *
1245
+ * The frame it draws is published to it, and to the head over it
1246
+ * (`CanvasHead`), as the screen found it: `useScreenCanvasTarget()`.
831
1247
  */
832
1248
  Canvas?: ComponentType;
1249
+ /**
1250
+ * A HEAD OVER THE CANVAS (0.105.0): the layer's own row above the frame, in
1251
+ * the canvas's well and at its own size — never scaled with a device — such
1252
+ * as the campaign designer's Subject line, its mail-app switch and its dark
1253
+ * mail app's bar, which sit above the email the way an inbox shows them. The
1254
+ * frame fills what is left of the well under it, and is fitted to that. It is
1255
+ * handed the device the canvas is drawn as. Absent: nothing is drawn above
1256
+ * the frame, and the frame fills the well.
1257
+ *
1258
+ * ONE function for the life of a mount, for the reason `Canvas` is.
1259
+ */
1260
+ CanvasHead?: ComponentType<ScreenCanvasHeadProps>;
1261
+ /**
1262
+ * The canvas drag's measure, model and rules, where they are the layer's
1263
+ * (0.105.0; `ScreenCanvasDrag`). Each member absent, and the whole object
1264
+ * absent, is the screen's own: Puck's markers, every node but the pinned
1265
+ * ones, the Layers tree's rules. Plain functions, and handed here for the
1266
+ * reason the rules are.
1267
+ */
1268
+ canvasDrag?: ScreenCanvasDrag;
833
1269
  /**
834
1270
  * THE INSPECTOR the screen mounts in its right panel: the panel of whatever
835
1271
  * is selected and, in its place, each panel of the layer's own — frame, head
@@ -884,11 +1320,38 @@ declare function useScreenSaveSwitch(): boolean;
884
1320
  * follows the selection (`pickFollowsSelection`). With no layer, a pick
885
1321
  * outlives a change of selection, as it always has. */
886
1322
  declare function useScreenPickFollowsSelection(selection: unknown): void;
1323
+ /** Where Add puts what it adds (`add`). With no layer's, nothing: the
1324
+ * screen's own Add. */
1325
+ declare function useScreenAdd(): ScreenAdd;
1326
+ /** The layer's style clipboard (`styleClipboard`), or null: the website's. */
1327
+ declare function useScreenStyleClipboard(): ScreenStyleClipboard | null;
1328
+ /** Whether ⌘C / ⌘X / ⌘V reach the selected block (`nodeKeys`). They do
1329
+ * unless the layer says not (owner ruling R12/R13). */
1330
+ declare function useScreenNodeKeys(): boolean;
1331
+ /** The host's toast (`notify`), or null: with none, the screen says its lines
1332
+ * in its own (R17). */
1333
+ declare function useScreenNotify(): ((message: string, tone: "info" | "error") => void) | null;
887
1334
  /** The canvas the layer dresses for the screen to frame. With no layer, the
888
1335
  * engine's plain one. */
889
1336
  declare function useScreenCanvasFrame(): ComponentType;
1337
+ /** The layer's head over the canvas (`CanvasHead`), or null: with no layer's,
1338
+ * nothing is drawn above the frame. */
1339
+ declare function useScreenCanvasHead(): ComponentType<ScreenCanvasHeadProps> | null;
1340
+ /** The layer's canvas drag (`canvasDrag`), or null: with no layer's, every
1341
+ * answer is the screen's own. */
1342
+ declare function useScreenCanvasDrag(): ScreenCanvasDrag | null;
1343
+ /** Publishes the frame the page screen found. The screen's own: it stands round
1344
+ * the chrome, and adds nothing to the page. */
1345
+ declare function ScreenCanvasTargetProvider({ target, children }: {
1346
+ target: CanvasTarget | null;
1347
+ children?: ReactNode;
1348
+ }): react.JSX.Element;
1349
+ /** The canvas frame the page screen found: its frame, document and window, or
1350
+ * null while there is none — and always null outside the page screen (the
1351
+ * section screen watches for no frame). */
1352
+ declare function useScreenCanvasTarget(): CanvasTarget | null;
890
1353
  /** The inspector the layer draws for the screen to mount. With no layer, the
891
1354
  * engine's plain rows for the selection. */
892
1355
  declare function useScreenInspectorPanel(): ComponentType<ScreenInspectorPanelProps>;
893
1356
 
894
- export { type NodeDefaults, SELECTION_MODE, type ScreenBlockLook, type ScreenBlockRules, type ScreenBridges, type ScreenCanvas, type ScreenDevices, type ScreenDocumentOps, type ScreenInspector, type ScreenInspectorMode, type ScreenInspectorPanelProps, type ScreenLeftPanel, type ScreenLeftView, type ScreenLeftViewFrame, type ScreenLeftViewRules, type ScreenNewNode, type ScreenNode, type ScreenNodeActions, type ScreenNodeLevel, type ScreenNodeMaker, type ScreenPartMode, type ScreenParts, ScreenPartsProvider, type ScreenPinnedBand, type ScreenPinnedNodes, type ScreenRailItem, type ScreenTree, type ScreenTreeFolds, type ScreenTreeRows, isPinnedFirst, isPinnedLast, sameInspectorMode, useScreenBlockLook, useScreenBlockRules, useScreenBridges, useScreenCanvasFrame, useScreenDevices, useScreenDocumentLabel, useScreenDocumentPass, useScreenInspectorPanel, useScreenLeftView, useScreenOwnerName, useScreenParts, useScreenPickFollowsSelection, useScreenPinned, useScreenSaveSwitch, useStandaloneScreenBridges };
1357
+ export { type NodeDefaults, SELECTION_MODE, type ScreenAdd, type ScreenBlockLook, type ScreenBlockRules, type ScreenBridges, type ScreenCanvas, type ScreenCanvasDrag, type ScreenCanvasDragContext, type ScreenCanvasHeadProps, ScreenCanvasTargetProvider, type ScreenDevices, type ScreenDocumentOps, type ScreenDragItem, type ScreenInspector, type ScreenInspectorMode, type ScreenInspectorPanelProps, type ScreenLeftPanel, type ScreenLeftView, type ScreenLeftViewFrame, type ScreenLeftViewRules, type ScreenMenuRows, type ScreenNewNode, type ScreenNode, type ScreenNodeActions, type ScreenNodeLevel, type ScreenNodeMaker, type ScreenPartMode, type ScreenParts, ScreenPartsProvider, type ScreenPinnedBand, type ScreenPinnedNodes, type ScreenRailItem, type ScreenSelection, type ScreenSelector, type ScreenSlot, type ScreenSlotAction, type ScreenSlotMode, type ScreenStyleClipboard, type ScreenStyleDocument, type ScreenStylePastePlan, type ScreenTree, type ScreenTreeFolds, type ScreenTreeRows, isPinnedFirst, isPinnedLast, isSlotMode, sameInspectorMode, screenSlotsOf, useScreenAdd, useScreenBlockLook, useScreenBlockRules, useScreenBridges, useScreenCanvasDrag, useScreenCanvasFrame, useScreenCanvasHead, useScreenCanvasTarget, useScreenDevices, useScreenDocumentLabel, useScreenDocumentPass, useScreenInspectorPanel, useScreenLeftView, useScreenNodeKeys, useScreenNotify, useScreenOwnerName, useScreenParts, useScreenPickFollowsSelection, useScreenPinned, useScreenSaveSwitch, useScreenStyleClipboard, useStandaloneScreenBridges };
@@ -1 +1 @@
1
- export{SELECTION_MODE,ScreenPartsProvider,isPinnedFirst,isPinnedLast,sameInspectorMode,useScreenBlockLook,useScreenBlockRules,useScreenBridges,useScreenCanvasFrame,useScreenDevices,useScreenDocumentLabel,useScreenDocumentPass,useScreenInspectorPanel,useScreenLeftView,useScreenOwnerName,useScreenParts,useScreenPickFollowsSelection,useScreenPinned,useScreenSaveSwitch,useStandaloneScreenBridges}from"../../chunk-7755VWRT.js";import"../../chunk-Z6BAZFSW.js";import"../../chunk-R5ZVNJLJ.js";import"../../chunk-P67FP7PG.js";import"../../chunk-AELNNAFM.js";import"../../chunk-BXZ6WLHC.js";import"../../chunk-EOJNJCMJ.js";import"../../chunk-ZFDCDJNZ.js";import"../../chunk-ZNS7727Y.js";import"../../chunk-3EDSDPIP.js";import"../../chunk-QTLAVDJE.js";import"../../chunk-YRLPFZW3.js";import"../../chunk-KTVH2ZRL.js";import"../../chunk-D2BCHTQR.js";import"../../chunk-EWVJSRRY.js";import"../../chunk-P6O363EE.js";import"../../chunk-FPOKPNO4.js";import"../../chunk-MFIRYGHW.js";import"../../chunk-BZ5ASXOL.js";import"../../chunk-67GNT6PF.js";import"../../chunk-ZNCEOSXO.js";import"../../chunk-L5KW4HG5.js";import"../../chunk-KRXQM65X.js";import"../../chunk-NKB3KVAB.js";
1
+ export{SELECTION_MODE,ScreenCanvasTargetProvider,ScreenPartsProvider,isPinnedFirst,isPinnedLast,isSlotMode,sameInspectorMode,screenSlotsOf,useScreenAdd,useScreenBlockLook,useScreenBlockRules,useScreenBridges,useScreenCanvasDrag,useScreenCanvasFrame,useScreenCanvasHead,useScreenCanvasTarget,useScreenDevices,useScreenDocumentLabel,useScreenDocumentPass,useScreenInspectorPanel,useScreenLeftView,useScreenNodeKeys,useScreenNotify,useScreenOwnerName,useScreenParts,useScreenPickFollowsSelection,useScreenPinned,useScreenSaveSwitch,useScreenStyleClipboard,useStandaloneScreenBridges}from"../../chunk-VSHV6KJQ.js";import"../../chunk-PLVEGYK6.js";import"../../chunk-R6WTQWAC.js";import"../../chunk-U3JP4VGF.js";import"../../chunk-P67FP7PG.js";import"../../chunk-AELNNAFM.js";import"../../chunk-BXZ6WLHC.js";import"../../chunk-EOJNJCMJ.js";import"../../chunk-ZFDCDJNZ.js";import"../../chunk-ZNS7727Y.js";import"../../chunk-3EDSDPIP.js";import"../../chunk-QTLAVDJE.js";import"../../chunk-YRLPFZW3.js";import"../../chunk-KTVH2ZRL.js";import"../../chunk-D2BCHTQR.js";import"../../chunk-EWVJSRRY.js";import"../../chunk-P6O363EE.js";import"../../chunk-FPOKPNO4.js";import"../../chunk-MFIRYGHW.js";import"../../chunk-BZ5ASXOL.js";import"../../chunk-67GNT6PF.js";import"../../chunk-ZNCEOSXO.js";import"../../chunk-L5KW4HG5.js";import"../../chunk-KRXQM65X.js";import"../../chunk-NKB3KVAB.js";
@@ -634,6 +634,24 @@
634
634
  padding: 0;
635
635
  }
636
636
 
637
+ /* A layer's HEAD OVER THE CANVAS (ScreenParts.CanvasHead, 0.105.0): the
638
+ campaign designer's Subject line and its dark mail app's bar, above the
639
+ email the way an inbox shows them. The well stacks the head over the device
640
+ sizer — the sizer still centred across it, as in a row — and the chrome
641
+ fits the frame to the height the head leaves (ScreenChrome `paneHeight`).
642
+ The head spans the well and is never scaled; what it draws in it is the
643
+ layer's. Only a well with a head wears the marker, so the website's well
644
+ keeps its row. */
645
+ .sf-center[data-sf-canvas-head] {
646
+ flex-direction: column;
647
+ justify-content: flex-start;
648
+ }
649
+ .sf-canvas-head {
650
+ flex: none;
651
+ align-self: stretch;
652
+ min-width: 0;
653
+ }
654
+
637
655
  /* ── Center: device-framed preview (wraps Puck.Preview) ──────────────── */
638
656
  .sf-frame {
639
657
  width: 100%;