efficient-easel 0.99.1 → 0.100.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 (110) hide show
  1. package/README.md +281 -36
  2. package/dist/autosave/index.d.ts +12 -6
  3. package/dist/blocks/index.d.ts +2 -2
  4. package/dist/canvas/index.d.ts +3 -3
  5. package/dist/canvas/index.js +1 -1
  6. package/dist/chrome/chrome.css +96 -29
  7. package/dist/chrome/index.d.ts +72 -19
  8. package/dist/chrome/index.js +17 -21
  9. package/dist/chunk-3EDSDPIP.js +1 -0
  10. package/dist/chunk-67GNT6PF.js +1 -0
  11. package/dist/{chunk-PI26YXYD.js → chunk-6EIVTKZZ.js} +21 -14
  12. package/dist/chunk-A5UK76FC.js +6 -0
  13. package/dist/chunk-AZT7V4UM.js +10 -0
  14. package/dist/chunk-DICUMYMG.js +12 -0
  15. package/dist/chunk-HDVD27VB.js +1 -0
  16. package/dist/chunk-JQM3V7XQ.js +1 -0
  17. package/dist/{chunk-TDA4HH54.js → chunk-JUQ6YJCG.js} +1 -1
  18. package/dist/chunk-LA54QLP5.js +1 -0
  19. package/dist/chunk-LGKQXSKO.js +16 -0
  20. package/dist/chunk-M6F6LS3H.js +1 -0
  21. package/dist/chunk-MH5GUZFQ.js +9 -0
  22. package/dist/chunk-P6O363EE.js +6 -0
  23. package/dist/chunk-PAELDYYS.js +1 -0
  24. package/dist/{chunk-JYPOOHII.js → chunk-QKVR3K73.js} +3 -3
  25. package/dist/chunk-SAJUCHOX.js +1 -0
  26. package/dist/chunk-TRVZ7C23.js +1 -0
  27. package/dist/chunk-V7GIIXFB.js +16 -0
  28. package/dist/{chunk-IBOFSS56.js → chunk-WZ7TGAAT.js} +1 -1
  29. package/dist/chunk-ZJEBF4NB.js +1 -0
  30. package/dist/copy/copy.css +388 -5
  31. package/dist/copy/index.d.ts +271 -8
  32. package/dist/copy/index.js +31 -10
  33. package/dist/data/index.d.ts +4 -4
  34. package/dist/drag/drag.css +10 -1
  35. package/dist/drag/index.d.ts +102 -11
  36. package/dist/drag/index.js +18 -17
  37. package/dist/{editor/editor.css → easel/easel.css} +16 -1
  38. package/dist/{editor → easel}/index.d.ts +146 -51
  39. package/dist/easel/index.js +9 -0
  40. package/dist/edit-lock/index.d.ts +3 -3
  41. package/dist/edit-lock/index.js +1 -1
  42. package/dist/fields/fields.css +103 -26
  43. package/dist/fields/index.d.ts +51 -13
  44. package/dist/fields/index.js +30 -46
  45. package/dist/gold/index.js +1 -1
  46. package/dist/icons/index.d.ts +10 -1
  47. package/dist/icons/index.js +1 -1
  48. package/dist/index.d.ts +3 -3
  49. package/dist/index.js +1 -1
  50. package/dist/markup/index.d.ts +94 -10
  51. package/dist/markup/index.js +1 -1
  52. package/dist/menu/index.d.ts +61 -6
  53. package/dist/menu/index.js +15 -15
  54. package/dist/menu/menu.css +17 -6
  55. package/dist/node-ops/index.d.ts +9 -9
  56. package/dist/node-ops/index.js +1 -1
  57. package/dist/panel/index.d.ts +73 -5
  58. package/dist/panel/index.js +18 -16
  59. package/dist/panel/panel.css +56 -1
  60. package/dist/pick/index.d.ts +42 -4
  61. package/dist/pick/index.js +7 -14
  62. package/dist/pick/pick.css +14 -0
  63. package/dist/rail/index.d.ts +6 -6
  64. package/dist/rail/index.js +1 -1
  65. package/dist/rail/rail.css +1 -1
  66. package/dist/strings/catalogue.d.ts +24 -40
  67. package/dist/strings/catalogue.js +1 -1
  68. package/dist/strings/index.d.ts +25 -23
  69. package/dist/strings/index.js +2 -2
  70. package/dist/style-clipboard/index.d.ts +5 -5
  71. package/dist/style-clipboard/index.js +1 -1
  72. package/dist/text-styles/index.d.ts +328 -0
  73. package/dist/text-styles/index.js +38 -0
  74. package/dist/text-styles/text-styles.css +309 -0
  75. package/dist/tree/index.d.ts +44 -3
  76. package/dist/tree/index.js +1 -1
  77. package/dist/tree/tree.css +71 -0
  78. package/dist/{types-CnRzp9oc.d.ts → types-DGcCsxs8.d.ts} +79 -12
  79. package/dist/{types-DNrn_w4V.d.ts → types-DWS-s9z-.d.ts} +10 -10
  80. package/dist/{types-pGBXevBU.d.ts → types-Djdq6Xkd.d.ts} +15 -8
  81. package/dist/{types-Dy6oR6Z2.d.ts → types-E3HrTPg2.d.ts} +20 -14
  82. package/dist/{types-C7HFvdtk.d.ts → types-VqL6t5HH.d.ts} +82 -5
  83. package/dist/{watch-DmasQA61.d.ts → watch-BTYOJpQU.d.ts} +19 -2
  84. package/dist/{wordFit-9B9nqyf3.d.ts → wordFit-D4S36PvB.d.ts} +1 -1
  85. package/dist/{words-DagJdwIA.d.ts → words-AHHfiaRY.d.ts} +31 -2
  86. package/dist/{words-D9ChvbNC.d.ts → words-BDignMl_.d.ts} +1 -1
  87. package/dist/{words-Cqmyey0s.d.ts → words-BMzV04b1.d.ts} +2 -2
  88. package/dist/words-CJjUKcV5.d.ts +37 -0
  89. package/dist/words-CRYvAiHX.d.ts +105 -0
  90. package/dist/{words-B2YLaKEr.d.ts → words-CnnHb9jo.d.ts} +1 -1
  91. package/dist/{words-CD3WADyb.d.ts → words-CzoyDNHm.d.ts} +4 -0
  92. package/dist/{words-bOMsUJk9.d.ts → words-DBq7vfHy.d.ts} +59 -6
  93. package/dist/{words-DOhF-4D4.d.ts → words-DMG4dYq2.d.ts} +1 -1
  94. package/dist/{words-BK-npta-.d.ts → words-DgHcY5qB.d.ts} +10 -4
  95. package/dist/{words-B87GIFWH.d.ts → words-is_Vy6hn.d.ts} +1 -1
  96. package/package.json +14 -8
  97. package/dist/chunk-66CKSTXP.js +0 -14
  98. package/dist/chunk-67VZRQLG.js +0 -13
  99. package/dist/chunk-6PS6STGA.js +0 -1
  100. package/dist/chunk-7A7O2JWQ.js +0 -1
  101. package/dist/chunk-H4B72XCJ.js +0 -1
  102. package/dist/chunk-JE63JHKO.js +0 -1
  103. package/dist/chunk-KDIVA6WD.js +0 -1
  104. package/dist/chunk-MCLBHENY.js +0 -1
  105. package/dist/chunk-QB3BZIRA.js +0 -5
  106. package/dist/chunk-SJQG5ENJ.js +0 -1
  107. package/dist/chunk-SUO5627P.js +0 -1
  108. package/dist/chunk-ZT7M24XD.js +0 -1
  109. package/dist/editor/index.js +0 -9
  110. /package/dist/{chunk-GGTPNGFJ.js → chunk-AELNNAFM.js} +0 -0
@@ -7,7 +7,7 @@ import { CSSProperties, ReactNode } from 'react';
7
7
  * what the menus OFFER is not this card's to move. A `label` of `'—'` renders a
8
8
  * separator; `header: true` renders a caption, and the FIRST such caption names
9
9
  * the menu for assistive tech. */
10
- interface EditorContextMenuItem {
10
+ interface EaselContextMenuItem {
11
11
  label: string;
12
12
  onClick: () => void;
13
13
  danger?: boolean;
@@ -16,7 +16,7 @@ interface EditorContextMenuItem {
16
16
  * One level only — a child carrying its own `children` is drawn as a plain
17
17
  * item, which is all any caller has needed and keeps the flyout from becoming
18
18
  * a tree nobody can navigate with a mouse. */
19
- children?: EditorContextMenuItem[];
19
+ children?: EaselContextMenuItem[];
20
20
  /** Draw a tick beside this item — for a submenu whose entries are STATES
21
21
  * rather than actions, so it can say which one you are already on. */
22
22
  checked?: boolean;
@@ -65,7 +65,7 @@ interface EditorContextMenuItem {
65
65
  *
66
66
  * A slot left empty is left empty. The default fills all of them.
67
67
  */
68
- interface EditorContextMenuSkin {
68
+ interface EaselContextMenuSkin {
69
69
  /** The box. */
70
70
  menu?: string;
71
71
  /** The FLYOUT box. Falls back to {@link menu} when a skin gives only one —
@@ -106,26 +106,33 @@ interface EditorContextMenuSkin {
106
106
  /** Merged into each row's inline style. */
107
107
  itemStyle?: CSSProperties;
108
108
  }
109
- interface EditorContextMenuProps {
109
+ interface EaselContextMenuProps {
110
110
  /** Where the pointer was. The box is placed from here and then kept on
111
111
  * screen — see the note on the component. */
112
112
  x: number;
113
113
  y: number;
114
- items: EditorContextMenuItem[];
114
+ items: EaselContextMenuItem[];
115
115
  onClose: () => void;
116
116
  /** Cap the box's height; it scrolls past that. */
117
117
  maxHeight?: number;
118
118
  /** Defaults to {@link ES_MENU_SKIN}, the storefront editor's approved look. */
119
- skin?: EditorContextMenuSkin;
119
+ skin?: EaselContextMenuSkin;
120
120
  /**
121
- * Where to portal to. Defaults to `document.body`.
121
+ * Where to portal to. Defaults to `document.body` (`null` means the default).
122
122
  *
123
123
  * A host that OVERRIDES `--es-*` on its own editor root should pass that root
124
124
  * instead: the default skin re-declares the token defaults on the box (see the
125
125
  * component's note), which is right for a box hanging off `<body>` and wrong
126
126
  * for one that should inherit a re-themed editor's values.
127
+ *
128
+ * So should a host that wants the box INSIDE ITS LANDMARKS (on the body it
129
+ * is page content outside every landmark: axe-core's `region`) — through
130
+ * `menuPortalTarget(root)`, never the bare root: the box is `position:
131
+ * fixed`, and a transformed, filtered or contained ancestor places and clips
132
+ * it. `menuPortalTarget` answers the root only when none does. The decision
133
+ * is recorded in `./portal`.
127
134
  */
128
135
  portalTo?: HTMLElement | null;
129
136
  }
130
137
 
131
- export type { EditorContextMenuItem as E, EditorContextMenuProps as a, EditorContextMenuSkin as b };
138
+ export type { EaselContextMenuItem as E, EaselContextMenuProps as a, EaselContextMenuSkin as b };
@@ -3,12 +3,12 @@ import { I as ItemSelector, N as NodeSelection } from './plan-DChbUXdS.js';
3
3
  import { D as Data, S as SlotAddress, a as DataConfig, N as Node } from './types-41704JE4.js';
4
4
 
5
5
  /**
6
- * The editor's UI state, in Puck's shape so the apps' `appState.ui` reads move
6
+ * The easel's UI state, in Puck's shape so the apps' `appState.ui` reads move
7
7
  * over unchanged. `itemSelector` and `selectedSlot` are DERIVED from the
8
8
  * selection the store holds by id; every other key is the host's own and is
9
9
  * kept as written.
10
10
  */
11
- type EditorUi = Record<string, unknown> & {
11
+ type EaselUi = Record<string, unknown> & {
12
12
  itemSelector: ItemSelector | null;
13
13
  /** The selected slot (a column), when a slot rather than a node is selected. */
14
14
  selectedSlot: SlotAddress | null;
@@ -22,7 +22,7 @@ type EditorUi = Record<string, unknown> & {
22
22
  /** Puck's public `appState`. */
23
23
  interface AppState {
24
24
  data: Data;
25
- ui: EditorUi;
25
+ ui: EaselUi;
26
26
  }
27
27
  type Recordable = {
28
28
  recordHistory?: boolean;
@@ -34,13 +34,19 @@ type SetDataPatch = Partial<Data> | DataInput;
34
34
  /**
35
35
  * The actions the apps dispatch today — Puck 0.20's, with Puck's meaning. Zone
36
36
  * keys are `"<parentId>:<slot>"`; `root:default-zone` is the page's own list.
37
+ *
38
+ * `insert` puts the block in with its `defaultProps` and runs NO resolver, as
39
+ * Puck's reducer did not. What ran a new block's `resolveData` in Puck was its
40
+ * own drop from the component list; here that is `easel.resolveNode(id, {
41
+ * trigger: 'insert' })`, called by the host after the insert (pass the action
42
+ * an `id` so there is one to name).
37
43
  */
38
- type EditorAction = ({
44
+ type EaselAction = ({
39
45
  type: 'setData';
40
46
  data: SetDataPatch | ((prev: Data) => SetDataPatch);
41
47
  } & Recordable) | ({
42
48
  type: 'setUi';
43
- ui: Partial<EditorUi> | ((prev: EditorUi) => Partial<EditorUi>);
49
+ ui: Partial<EaselUi> | ((prev: EaselUi) => Partial<EaselUi>);
44
50
  } & Recordable) | ({
45
51
  type: 'set';
46
52
  state: Partial<AppState> | ((prev: AppState) => Partial<AppState>);
@@ -81,7 +87,7 @@ type EditorAction = ({
81
87
  index: number;
82
88
  zone: string;
83
89
  } & Recordable);
84
- /** What a block, the root or the whole editor allows. Puck's five. */
90
+ /** What a block, the root or the whole easel allows. Puck's five. */
85
91
  interface Permissions {
86
92
  drag: boolean;
87
93
  duplicate: boolean;
@@ -93,7 +99,7 @@ interface Permissions {
93
99
  /** The config the store needs: the data layer's shape, plus each block's own
94
100
  * `permissions` (Puck's per-component permissions). Rendering keys are the
95
101
  * renderer's business and pass through untouched. */
96
- interface EditorConfig extends DataConfig {
102
+ interface EaselConfig extends DataConfig {
97
103
  root?: DataConfig['root'] & {
98
104
  permissions?: Partial<Permissions>;
99
105
  };
@@ -102,7 +108,7 @@ interface EditorConfig extends DataConfig {
102
108
  }) | undefined>;
103
109
  }
104
110
  /** The state the store holds. The selection is BY ID. */
105
- interface EditorCore {
111
+ interface EaselCore {
106
112
  data: Data;
107
113
  selection: NodeSelection;
108
114
  /** The host's own UI keys — everything but `itemSelector` / `selectedSlot`. */
@@ -115,7 +121,7 @@ interface HistoryEntry {
115
121
  }
116
122
  /** Puck's PUBLIC `history` (what `usePuck` hands out): `hasPast` and
117
123
  * `hasFuture` are booleans there, read at the state they came with. */
118
- interface EditorHistory {
124
+ interface EaselHistory {
119
125
  back: () => void;
120
126
  forward: () => void;
121
127
  hasPast: boolean;
@@ -126,18 +132,18 @@ interface EditorHistory {
126
132
  setHistoryIndex: (index: number) => void;
127
133
  }
128
134
  /**
129
- * What `useEditor` reads — Puck's `usePuck` state, so the apps' selectors move
135
+ * What `useEasel` reads — Puck's `usePuck` state, so the apps' selectors move
130
136
  * over by renaming the hook: `appState`, `selectedItem`, `dispatch`, `config`,
131
137
  * `history`, `getPermissions`, `getItemById`, `getSelectorForId`. Plus the
132
138
  * selection by id (`selection`), which Puck never had.
133
139
  */
134
- interface EditorView<C extends EditorConfig = EditorConfig> {
140
+ interface EaselView<C extends EaselConfig = EaselConfig> {
135
141
  appState: AppState;
136
142
  selection: NodeSelection;
137
143
  selectedItem: Node | null;
138
144
  config: C;
139
- dispatch: (action: EditorAction) => void;
140
- history: EditorHistory;
145
+ dispatch: (action: EaselAction) => void;
146
+ history: EaselHistory;
141
147
  getPermissions: (params?: {
142
148
  item?: Node | null;
143
149
  type?: string;
@@ -150,4 +156,4 @@ interface EditorView<C extends EditorConfig = EditorConfig> {
150
156
  getSelectorForId: (id: string) => Required<ItemSelector> | undefined;
151
157
  }
152
158
 
153
- export type { AppState as A, EditorConfig as E, HistoryEntry as H, Permissions as P, SetDataPatch as S, EditorView as a, EditorAction as b, EditorCore as c, EditorUi as d, EditorHistory as e };
159
+ export type { AppState as A, EaselConfig as E, HistoryEntry as H, Permissions as P, SetDataPatch as S, EaselView as a, EaselAction as b, EaselCore as c, EaselUi as d, EaselHistory as e };
@@ -38,6 +38,9 @@ interface FieldNumberProps extends ControlBase {
38
38
  /** Two small stacked arrows at the cell's end. */
39
39
  steppers?: boolean;
40
40
  placeholder?: string;
41
+ /** The cell's tooltip — the text box's cells say their name and step here
42
+ * (E5b), since the cell draws no name. */
43
+ title?: string;
41
44
  }
42
45
  /**
43
46
  * A slider row (Site styles, Email styles): the name left and the typed value
@@ -50,20 +53,94 @@ interface FieldSliderProps extends Omit<FieldNumberProps, 'icon' | 'steppers' |
50
53
  label: string;
51
54
  sliderMin: number;
52
55
  sliderMax: number;
56
+ /**
57
+ * The word for "no number of its own: each section draws its own" (plan
58
+ * step E6). Given, the slider gains one spot left of `sliderMin` that means
59
+ * it, and the value reads the word while there is no number.
60
+ */
61
+ auto?: string;
53
62
  }
54
63
  interface FieldOption<V = unknown> {
55
64
  label: string;
56
65
  value: V;
57
66
  disabled?: boolean;
58
67
  icon?: ReactNode;
68
+ /**
69
+ * The heading this option sits under in the open list — what `<optgroup>`
70
+ * did. Each RUN of options with the same group gets one heading, in the
71
+ * order the options come; an option with none sits under no heading. A
72
+ * heading is not an option: it cannot be chosen and the keys never land on it.
73
+ */
74
+ group?: string;
75
+ /**
76
+ * A small picture at the head of the row (a product's cover). One option
77
+ * with a `thumb` key gives EVERY row the picture column, so a mixed list
78
+ * keeps its columns; `null` draws the empty well. No option with the key, no
79
+ * column.
80
+ */
81
+ thumb?: string | null;
82
+ /**
83
+ * One quiet fact at the end of the row (a price, a count). It is not part
84
+ * of the option's name: a screen reader does not hear it, and the closed
85
+ * control never shows it.
86
+ */
87
+ meta?: string;
59
88
  }
60
- interface FieldSelectProps<V = unknown> extends ControlBase {
61
- value: V | undefined;
89
+ /**
90
+ * `ariaLabelledBy` / `ariaLabel` name the button AND its open list. Left out,
91
+ * the button is named by its `<label for>` (or by what it shows) and the list
92
+ * by the button, so the list is never without a name.
93
+ */
94
+ interface FieldSelectBase<V> extends ControlBase {
62
95
  options: readonly FieldOption<V>[];
63
- onChange: (value: V) => void;
64
- /** Shown when the value names no option. */
96
+ /** Shown when the value names no option (when nothing is on, for `multiple`). */
65
97
  placeholder?: string;
98
+ /**
99
+ * A search box at the top of the open list. Typing narrows the options by
100
+ * label and the keys walk what is left; a letter goes into the box, so
101
+ * there is no letter jump. A long list (every product in a catalogue).
102
+ */
103
+ searchable?: boolean;
104
+ /**
105
+ * The search box's hint and name, in the host's own words ("Search your
106
+ * catalog…"). Left out, the catalogue's `fields.search`.
107
+ */
108
+ searchPlaceholder?: string;
109
+ /** Each group heading says how many of its options are showing. Derived, never passed. */
110
+ groupCount?: boolean;
111
+ /**
112
+ * The list opens IN FLOW, pushing the rows below it down, instead of
113
+ * floating. For a list inside a panel that scrolls, where a floating list is
114
+ * clipped by the panel's edge.
115
+ */
116
+ inline?: boolean;
117
+ /** Draws an option's row in place of its label (each style in its own face). It is still an option. */
118
+ renderOption?: (option: FieldOption<V>, state: {
119
+ active: boolean;
120
+ chosen: boolean;
121
+ }) => ReactNode;
122
+ }
123
+ /** One of a set. */
124
+ interface FieldSelectOneProps<V = unknown> extends FieldSelectBase<V> {
125
+ multiple?: false;
126
+ value: V | undefined;
127
+ onChange: (value: V) => void;
128
+ /** Draws the closed control's value in place of the chosen label. */
129
+ renderValue?: (chosen: FieldOption<V> | undefined) => ReactNode;
66
130
  }
131
+ /**
132
+ * Several of a set (`multiple`). The value is a list, saved in the order the
133
+ * OPTIONS come, never in the order they were ticked: two lists that look the
134
+ * same hold the same data. An empty list is an answer, not a missing one.
135
+ */
136
+ interface FieldSelectManyProps<V = unknown> extends FieldSelectBase<V> {
137
+ multiple: true;
138
+ value: readonly V[] | undefined;
139
+ onChange: (value: V[]) => void;
140
+ /** Draws the closed control's value in place of the labels of what is on. */
141
+ renderValue?: (on: FieldOption<V>[]) => ReactNode;
142
+ }
143
+ type FieldSelectProps<V = unknown> = FieldSelectOneProps<V> | FieldSelectManyProps<V>;
67
144
  interface FieldMeta {
68
145
  label?: string;
69
146
  /** The tab this field opens; inherited by the fields after it (see above). */
@@ -148,4 +225,4 @@ type FieldRenderer = (props: {
148
225
  readOnly?: boolean;
149
226
  }) => ReactNode;
150
227
 
151
- export type { ArrayFieldDef as A, CustomFieldDef as C, FieldRenderer as F, InspectorFields as I, NumberFieldDef as N, ObjectFieldDef as O, RadioFieldDef as R, SelectFieldDef as S, TextFieldDef as T, InspectorFieldDef as a, FieldTextProps as b, FieldNumberProps as c, FieldSliderProps as d, FieldSelectProps as e, FieldOption as f, CustomFieldRenderProps as g, SlotFieldDef as h, TextareaFieldDef as i };
228
+ export type { ArrayFieldDef as A, CustomFieldDef as C, FieldRenderer as F, InspectorFields as I, NumberFieldDef as N, ObjectFieldDef as O, RadioFieldDef as R, SelectFieldDef as S, TextFieldDef as T, InspectorFieldDef as a, FieldTextProps as b, FieldNumberProps as c, FieldSliderProps as d, FieldSelectManyProps as e, FieldSelectOneProps as f, FieldOption as g, CustomFieldRenderProps as h, FieldSelectProps as i, SlotFieldDef as j, TextareaFieldDef as k };
@@ -32,15 +32,32 @@ interface WatchOptions {
32
32
  * `load` — and a measurement taken then measures nothing. For the editor's
33
33
  * canvas pass `BLOCK_SELECTOR`. Watched with a MutationObserver on the frame's
34
34
  * document, never polled.
35
+ *
36
+ * ⚠️ "Ready" then means "holds a block", so a page with NO blocks is never
37
+ * ready: the frame is not published, and nothing that needs the canvas (the
38
+ * drag layer, a canvas stylesheet, a context menu) works on an empty page —
39
+ * the one page a first block has to be dropped on. An editor whose page can
40
+ * be empty names something the canvas ALWAYS draws instead — a list,
41
+ * `LIST_SELECTOR`: the page's own is there with nothing in it — or leaves
42
+ * this out.
35
43
  */
36
44
  readySelector?: string;
37
45
  }
38
46
  /**
39
47
  * Every block the canvas draws carries this attribute. The markup is the one
40
- * Puck 0.20 drew, kept by the engine's own canvas (`efficient-easel/editor`)
48
+ * Puck 0.20 drew, kept by the engine's own canvas (`efficient-easel/easel`)
41
49
  * because both apps' canvas CSS and checks read it.
42
50
  */
43
51
  declare const BLOCK_SELECTOR = "[data-puck-component]";
52
+ /**
53
+ * Every LIST the canvas draws carries this attribute — the page's own
54
+ * (`root:default-zone`) and each slot's — whether or not there is a block in
55
+ * it. So it is the `readySelector` for an editor whose page may be EMPTY: the
56
+ * canvas of a page with no blocks holds no `BLOCK_SELECTOR` and would never be
57
+ * published, on the one page a first block has to be dropped on (second host,
58
+ * 2026-10-07: it had typed the attribute out by hand to get this).
59
+ */
60
+ declare const LIST_SELECTOR = "[data-puck-dropzone]";
44
61
  /** The canvas frame: Puck 0.20's, and the engine's own `CanvasFrame` since 0.89.0. */
45
62
  declare const CANVAS_SELECTOR = "iframe#preview-frame";
46
63
  /**
@@ -57,4 +74,4 @@ declare function isFrameReady(frame: HTMLIFrameElement): boolean;
57
74
  */
58
75
  declare function watchCanvasFrame(root: Node, onChange: (target: CanvasTarget | null) => void, { selector, readySelector }?: WatchOptions): () => void;
59
76
 
60
- export { BLOCK_SELECTOR as B, type CanvasTarget as C, type WatchOptions as W, CANVAS_SELECTOR as a, isFrameReady as i, watchCanvasFrame as w };
77
+ export { BLOCK_SELECTOR as B, type CanvasTarget as C, LIST_SELECTOR as L, type WatchOptions as W, CANVAS_SELECTOR as a, isFrameReady as i, watchCanvasFrame as w };
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * `SettingsSegmented` the host passes its measured `fit`;
9
9
  * the top-bar rail `TopBarRail` measures the words in the browser and
10
- * hands `EditorRail` the result.
10
+ * hands `EaselRail` the result.
11
11
  *
12
12
  * Both numbers are the width of TEXT ONLY, in the strip's own type, and neither
13
13
  * includes any padding, glyph or gap: those are the strip's, and the sheet adds
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * The editor frame's own words (`efficient-easel/strings`, 0.95.0), in two
3
- * groups: what `EditNotice` says (`NoticeWords`) and the few words the rest of
4
- * the chrome carries when the host gives none (`ChromeWords`).
3
+ * groups: what `EditNotice` says (`NoticeWords`) and the words the rest of the
4
+ * chrome carries when the host gives none (`ChromeWords`), the media panel's
5
+ * head among them.
5
6
  *
6
7
  * A plain module with no import. Anything with a value in it is a function, so
7
8
  * a host puts the name, the noun and the time where its language wants them.
@@ -73,6 +74,34 @@ type ChromeWords = {
73
74
  }) => string;
74
75
  /** `PanelResizeHandle`: the tooltip. */
75
76
  resize: string;
77
+ /** `MediaPanelHead`, browsing: the panel's name. */
78
+ mediaLibrary: string;
79
+ /** `MediaPanelHead`, choosing: the panel's name. `kind` is a `mediaKinds` word. */
80
+ mediaChoose: (v: {
81
+ kind: string;
82
+ }) => string;
83
+ /** `MediaPanelHead`, choosing: the line under the name. `field` is the host's label for the field. */
84
+ mediaFor: (v: {
85
+ field: string;
86
+ }) => string;
87
+ /** What a field can hold, as the head says it, by `MediaPickKind`. */
88
+ mediaKinds: {
89
+ image: string;
90
+ video: string;
91
+ svg: string;
92
+ };
93
+ /** `MediaPanelHead`: the word that leaves choosing. */
94
+ mediaCancel: string;
95
+ /** `MediaPanelHead`: Cancel's tooltip. `kind` is a `mediaKinds` word. */
96
+ mediaKeep: (v: {
97
+ kind: string;
98
+ }) => string;
99
+ /** The Hide panel button at the end of a side panel's head: the tooltip. */
100
+ hidePanel: string;
101
+ /** The same button: its accessible name. */
102
+ hidePanelLabel: (v: {
103
+ side: 'left' | 'right';
104
+ }) => string;
76
105
  };
77
106
 
78
107
  export type { ChromeWords as C, NoticeWords as N };
@@ -6,7 +6,7 @@
6
6
  * A plain module with no import, in drag's own folder: drag may reach only its
7
7
  * lane (`tests/drag-leaf-safety.test.ts`), so `AddPanel` and `CanvasDragLayer`
8
8
  * do NOT read the strings provider. They take their group as `words`, and a
9
- * host passes `useEditorStrings().drag.add` / `.drag.canvas`.
9
+ * host passes `useEaselStrings().drag.add` / `.drag.canvas`.
10
10
  */
11
11
  type DragWords = {
12
12
  add: {
@@ -1,4 +1,4 @@
1
- import { S as SaveTone } from './types-CnRzp9oc.js';
1
+ import { S as SaveTone } from './types-DGcCsxs8.js';
2
2
 
3
3
  /** Time and timers, passed in so a test can run minutes in a millisecond. */
4
4
  type AutosaveClock = {
@@ -121,7 +121,7 @@ type SaveWords = {
121
121
  unsaved: string;
122
122
  };
123
123
  /**
124
- * `words` is the host's language (`useEditorStrings().save`); left out, the
124
+ * `words` is the host's language (`useEaselStrings().save`); left out, the
125
125
  * pill speaks English as it always has.
126
126
  */
127
127
  declare function saveIndicator(state: AutosaveSnapshot, words?: SaveWords): SaveIndicator;
@@ -0,0 +1,37 @@
1
+ import { S as SettingsBucket } from './buckets-CuLM47h9.js';
2
+
3
+ /**
4
+ * The settings panel's own words (`efficient-easel/strings`, 0.95.0): what
5
+ * the tab strip is called, what each tab SAYS, and the Default / Reset part.
6
+ *
7
+ * A bucket's key (`'Content'`, `'Style'`, …) is an identifier — fields name
8
+ * their tab with it and `SETTINGS_BUCKETS` orders them — so it never changes
9
+ * with the language. `buckets` is the word drawn for each key.
10
+ *
11
+ * The panel is hook-free, so nothing here is read from the strings provider:
12
+ * `SettingsTabs` takes its name as `ariaLabel` and each tab's word as the
13
+ * item's `label`, and `Inspector` (which has hooks) passes both.
14
+ * `SettingsDefaultReset` takes `words`, and a host passes the four from
15
+ * `useWords('panel', …)`.
16
+ */
17
+
18
+ type PanelWords = {
19
+ /** The tab strip's accessible name. */
20
+ settings: string;
21
+ /** The word each tab shows, by its key. */
22
+ buckets: Record<SettingsBucket, string>;
23
+ /** `SettingsDefaultReset`, resting: the value follows its default. */
24
+ followsDefault: string;
25
+ /** `SettingsDefaultReset`, changed: the button that clears the value. */
26
+ reset: string;
27
+ /** The Reset button's accessible name — which setting it resets. */
28
+ resetName: (p: {
29
+ label: string;
30
+ }) => string;
31
+ /** The Reset button's tooltip, when the host says what the default is. */
32
+ backToDefault: (p: {
33
+ detail: string;
34
+ }) => string;
35
+ };
36
+
37
+ export type { PanelWords as P };
@@ -0,0 +1,105 @@
1
+ /**
2
+ * The text-styles list's own words (`efficient-easel/strings`, plan step E6).
3
+ * A style's NAME is the host's data ("Heading 1" is stored); `styleName` is
4
+ * only how a NEW one is named. The fonts' and theme colours' names are the
5
+ * host's too.
6
+ *
7
+ * A plain module with no import. The English is the design's own (both pages,
8
+ * final 2026-10-06): "Body", never "Paragraph" (N10.1); US spelling, "Color".
9
+ */
10
+ type TextStylesWords = {
11
+ /** The two group headings, in the order they are drawn. */
12
+ groups: {
13
+ heading: string;
14
+ body: string;
15
+ };
16
+ /** The button under each group. */
17
+ add: {
18
+ heading: string;
19
+ body: string;
20
+ };
21
+ /** Beside the button: how many there are of the most allowed. */
22
+ count: (v: {
23
+ n: number;
24
+ max: number;
25
+ }) => string;
26
+ /** The button's tooltip once the group is full. */
27
+ full: (v: {
28
+ kind: 'heading' | 'body';
29
+ max: number;
30
+ }) => string;
31
+ /** A new style's name. `n` counts from 1 within its kind. */
32
+ styleName: (v: {
33
+ kind: 'heading' | 'body';
34
+ n: number;
35
+ }) => string;
36
+ /** Delete's tooltip: the same word as the Layers delete and the node menu. */
37
+ remove: string;
38
+ /** Delete's accessible name. `name` is the style's: "Heading 4". */
39
+ removeNamed: (v: {
40
+ name: string;
41
+ }) => string;
42
+ /** The line an open style's preview is drawn in, unless the host gives its own. */
43
+ sample: string;
44
+ /** The preview's accessible name. */
45
+ preview: string;
46
+ /** A row's grey line. Each part is already words: "16 px", "Auto", "Regular". */
47
+ summary: (v: {
48
+ font: string;
49
+ size: string;
50
+ weight: string;
51
+ }) => string;
52
+ /** A size in the grey line. */
53
+ px: (v: {
54
+ n: number;
55
+ }) => string;
56
+ /** No number of its own: each section draws its own. */
57
+ auto: string;
58
+ /** A weight's name, by the hundred it is nearest. */
59
+ weights: {
60
+ thin: string;
61
+ extraLight: string;
62
+ light: string;
63
+ regular: string;
64
+ medium: string;
65
+ semibold: string;
66
+ bold: string;
67
+ extraBold: string;
68
+ black: string;
69
+ };
70
+ /** Each setting's name in an open style. */
71
+ settings: {
72
+ font: string;
73
+ color: string;
74
+ size: string;
75
+ weight: string;
76
+ /** The B · I row (Site styles). */
77
+ emphasis: string;
78
+ lineSpacing: string;
79
+ letterSpacing: string;
80
+ paragraphSpacing: string;
81
+ letterCase: string;
82
+ largestSize: string;
83
+ };
84
+ bold: string;
85
+ italic: string;
86
+ /** The Italic button's tooltip when the font has no italic. */
87
+ italicMissing: string;
88
+ /** Letter case's buttons. */
89
+ case: {
90
+ auto: string;
91
+ autoTitle: string;
92
+ none: string;
93
+ upper: string;
94
+ lower: string;
95
+ };
96
+ colour: {
97
+ /** The rainbow swatch at the end of the theme's colours. */
98
+ any: string;
99
+ /** What the Color row reads while the style has no colour of its own. */
100
+ follows: string;
101
+ };
102
+ };
103
+ declare const DEFAULT_TEXT_STYLES_WORDS: TextStylesWords;
104
+
105
+ export { DEFAULT_TEXT_STYLES_WORDS as D, type TextStylesWords as T };
@@ -6,7 +6,7 @@
6
6
  * A plain module with no import. The style clipboard imports React's JSX
7
7
  * runtime and nothing else (`tests/style-clipboard-leaf-safety.test.ts`), so it
8
8
  * reads no provider: `styleMenuItems` and `pasteMessage` take these as an
9
- * argument, and a host passes `useEditorStrings().styleClipboard`.
9
+ * argument, and a host passes `useEaselStrings().styleClipboard`.
10
10
  */
11
11
  type StyleClipboardWords = {
12
12
  /** The Copy style row. */
@@ -13,6 +13,10 @@ type FieldsWords = {
13
13
  more: string;
14
14
  /** `FieldSelect`: what the box says while nothing is chosen. */
15
15
  choose: string;
16
+ /** `FieldSelect` with `searchable`: the search box's hint and name. Optional: a host's older catalogue falls back to the English. */
17
+ search?: string;
18
+ /** `FieldSelect` with `searchable`: what the list says when nothing matches. */
19
+ noMatches?: string;
16
20
  /** `ListField` — an array field drawn as rows. */
17
21
  list: {
18
22
  /** One item's word when the field names none. */