efficient-easel 0.96.0 → 0.98.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 (66) hide show
  1. package/README.md +98 -3
  2. package/dist/autosave/index.d.ts +4 -4
  3. package/dist/blocks/index.d.ts +15 -4
  4. package/dist/{buckets-1vRlQceY.d.ts → buckets-CuLM47h9.d.ts} +1 -1
  5. package/dist/chrome/chrome.css +25 -16
  6. package/dist/chrome/index.d.ts +6 -6
  7. package/dist/chrome/index.js +6 -6
  8. package/dist/chunk-2UX75JDP.js +1 -0
  9. package/dist/{chunk-STFMZJKU.js → chunk-66CKSTXP.js} +6 -6
  10. package/dist/{chunk-6JDII7N3.js → chunk-6PS6STGA.js} +1 -1
  11. package/dist/{chunk-EFTTSIMK.js → chunk-D2BCHTQR.js} +1 -1
  12. package/dist/{chunk-YIMRTIBN.js → chunk-IBOFSS56.js} +1 -1
  13. package/dist/chunk-KRXQM65X.js +1 -0
  14. package/dist/chunk-PI26YXYD.js +462 -0
  15. package/dist/{chunk-FJE4IDBQ.js → chunk-YRLPFZW3.js} +1 -1
  16. package/dist/copy/copy.css +5 -5
  17. package/dist/copy/index.d.ts +5 -5
  18. package/dist/copy/index.js +10 -10
  19. package/dist/data/index.d.ts +171 -4
  20. package/dist/data/index.js +1 -1
  21. package/dist/drag/drag.css +15 -15
  22. package/dist/drag/index.d.ts +1 -1
  23. package/dist/drag/index.js +15 -15
  24. package/dist/edit-lock/index.d.ts +1 -1
  25. package/dist/editor/index.d.ts +9 -9
  26. package/dist/editor/index.js +6 -6
  27. package/dist/fields/fields.css +126 -12
  28. package/dist/fields/index.d.ts +61 -13
  29. package/dist/fields/index.js +41 -34
  30. package/dist/gold/index.d.ts +1 -1
  31. package/dist/icons/index.d.ts +26 -5
  32. package/dist/icons/index.js +1 -1
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.js +1 -1
  35. package/dist/menu/menu.css +4 -4
  36. package/dist/node-ops/index.d.ts +3 -3
  37. package/dist/node-ops/index.js +1 -1
  38. package/dist/panel/index.d.ts +10 -10
  39. package/dist/panel/panel.css +34 -25
  40. package/dist/pick/pick.css +8 -8
  41. package/dist/{plan-DtNw2VuI.d.ts → plan-DChbUXdS.d.ts} +1 -1
  42. package/dist/rail/index.d.ts +2 -2
  43. package/dist/rail/index.js +1 -1
  44. package/dist/rail/rail.css +1 -1
  45. package/dist/render/index.d.ts +2 -2
  46. package/dist/{resolve-DpH8YQOA.d.ts → resolve-D68pb3Bx.d.ts} +1 -1
  47. package/dist/shell/index.d.ts +24 -4
  48. package/dist/shell/index.js +1 -1
  49. package/dist/shell/shell.css +12 -2
  50. package/dist/strings/catalogue.d.ts +4 -4
  51. package/dist/strings/index.d.ts +4 -4
  52. package/dist/style-clipboard/index.js +1 -1
  53. package/dist/tree/index.d.ts +1 -1
  54. package/dist/tree/index.js +1 -1
  55. package/dist/tree/tree.css +11 -11
  56. package/dist/{types-DziKCwsN.d.ts → types-41704JE4.d.ts} +8 -1
  57. package/dist/{types-CEqUFH2j.d.ts → types-C7HFvdtk.d.ts} +26 -4
  58. package/dist/{types-CuNiSnX6.d.ts → types-CnRzp9oc.d.ts} +1 -1
  59. package/dist/{types-_Vayx8ov.d.ts → types-Dy6oR6Z2.d.ts} +2 -2
  60. package/dist/{useNodeOps-6IAej9jy.d.ts → useNodeOps-BF0fQsif.d.ts} +2 -2
  61. package/dist/{words-CsRWXkY4.d.ts → words-Cqmyey0s.d.ts} +2 -2
  62. package/dist/{words-DfxEp_RH.d.ts → words-bOMsUJk9.d.ts} +1 -1
  63. package/package.json +1 -1
  64. package/dist/chunk-FI23ALVJ.js +0 -1
  65. package/dist/chunk-LPRQDDQO.js +0 -1
  66. package/dist/chunk-YNZZYHA4.js +0 -450
@@ -5,7 +5,7 @@
5
5
  * editor chrome theme: accent, surfaces, fields, text, lines, chips, named
6
6
  * chrome literals, danger/warning/success, radii, gap, shadows and font. Every
7
7
  * value bar one is taken verbatim from the storefront editor's `--sf-*` block
8
- * (`efficient-shop/components/storefront-editor.css`), the visual reference the
8
+ * (`efficient-storefront/components/storefront-editor.css`), the visual reference the
9
9
  * campaign designer (`--cd-*`) and the storefront's own TS mirror (`tk`) had
10
10
  * each re-copied. After card 66024 they all resolve to these values instead.
11
11
  * The one exception is `success`, which that block has no counterpart for; see
@@ -131,8 +131,22 @@ declare const shellTokens: {
131
131
  readonly rowRadius: 8;
132
132
  /** `--es-field-radius`. */
133
133
  readonly fieldRadius: 6;
134
- /** `--es-panel-gap` — inter-pane gutter + outer frame padding, ONE token. */
135
- readonly panelGap: 10;
134
+ /** `--es-panel-gap` — inter-pane gutter + outer frame padding, ONE token.
135
+ * 12 since the one spacing scale (was 10, which is not a step). */
136
+ readonly panelGap: 12;
137
+ /** `--es-space-2` — between the buttons of one group (B · I · U · S). */
138
+ readonly space2: 2;
139
+ /** `--es-space-4` — a sub-name to its control; between the cells of one group. */
140
+ readonly space4: 4;
141
+ /** `--es-space-8` — between the layers of ONE setting (bar → box → Show marks). */
142
+ readonly space8: 8;
143
+ /** `--es-space-12` — between rows under one heading; inside one setting;
144
+ * the panel's padding when it is narrower than 260px. */
145
+ readonly space12: 12;
146
+ /** `--es-space-16` — the panel's own padding. */
147
+ readonly space16: 16;
148
+ /** `--es-space-32` — between two settings. */
149
+ readonly space32: 32;
136
150
  /** `--es-panel-shadow`. */
137
151
  readonly panelShadow: "0 1px 2px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.06)";
138
152
  /** `--es-topbar-shadow`. */
@@ -148,6 +162,12 @@ declare const shellTokens: {
148
162
  readonly font: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif";
149
163
  };
150
164
  type ShellTokens = typeof shellTokens;
165
+ /**
166
+ * The one spacing scale, smallest first (owner ruling, 2026-10-02): the six
167
+ * `space*` tokens above as a list, for code that must snap a number to it.
168
+ * A seventh step is a new ruling, not a new entry.
169
+ */
170
+ declare const SPACING_SCALE: readonly [2, 4, 8, 12, 16, 32];
151
171
  /**
152
172
  * The CSS custom-property name behind each `shellTokens` key. `shell.css` sets
153
173
  * these on `.es-editor`; override any of them on (or above) the editor root to
@@ -156,4 +176,4 @@ type ShellTokens = typeof shellTokens;
156
176
  */
157
177
  declare const shellCssVars: Record<keyof ShellTokens, string>;
158
178
 
159
- export { type ShellTokens, shellCssVars, shellTokens };
179
+ export { SPACING_SCALE, type ShellTokens, shellCssVars, shellTokens };
@@ -1 +1 @@
1
- export{shellCssVars,shellTokens}from"../chunk-FI23ALVJ.js";
1
+ export{SPACING_SCALE,shellCssVars,shellTokens}from"../chunk-2UX75JDP.js";
@@ -34,7 +34,7 @@
34
34
  * Audited 2026-09-02 across every sheet here that opens an `.es-editor` block,
35
35
  * and the honest number is zero:
36
36
  *
37
- * shell.css 67 declarations, 67 custom, 0 paint
37
+ * shell.css 73 declarations, 73 custom, 0 paint (6 spacing steps added 2026-10-06)
38
38
  * panel.css 11 declarations, 11 custom, 0 paint
39
39
  * menu.css 7 declarations, 7 custom, 0 paint
40
40
  *
@@ -110,7 +110,17 @@
110
110
  --es-panel-radius: 12px;
111
111
  --es-row-radius: 8px;
112
112
  --es-field-radius: 6px;
113
- --es-panel-gap: 10px;
113
+ --es-panel-gap: 12px;
114
+
115
+ /* — spacing: ONE scale for every panel (owner ruling, 2026-10-02) —
116
+ Six steps and no seventh. Every margin, padding and gap in this package
117
+ is one of them; `tests/spacing-scale.test.ts` holds every sheet to it. */
118
+ --es-space-2: 2px;
119
+ --es-space-4: 4px;
120
+ --es-space-8: 8px;
121
+ --es-space-12: 12px;
122
+ --es-space-16: 16px;
123
+ --es-space-32: 32px;
114
124
 
115
125
  /* — shadows — */
116
126
  --es-panel-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.06);
@@ -1,15 +1,15 @@
1
- import { S as SaveWords } from '../words-CsRWXkY4.js';
1
+ import { S as SaveWords } from '../words-Cqmyey0s.js';
2
2
  import { N as NoticeWords, C as ChromeWords } from '../words-DagJdwIA.js';
3
- import { C as CopyWords } from '../words-DfxEp_RH.js';
3
+ import { C as CopyWords } from '../words-bOMsUJk9.js';
4
4
  import { D as DragWords } from '../words-D9ChvbNC.js';
5
5
  import { LockWords } from '../edit-lock/index.js';
6
6
  import { F as FieldsWords } from '../words-CD3WADyb.js';
7
7
  import { N as NodeMenuWords } from '../words-DOhF-4D4.js';
8
- import { S as SettingsBucket } from '../buckets-1vRlQceY.js';
8
+ import { S as SettingsBucket } from '../buckets-CuLM47h9.js';
9
9
  import { P as PickWords } from '../words-B87GIFWH.js';
10
10
  import { S as StyleClipboardWords } from '../words-B2YLaKEr.js';
11
11
  import { T as TreeWords } from '../words-BK-npta-.js';
12
- import '../types-CuNiSnX6.js';
12
+ import '../types-CnRzp9oc.js';
13
13
  import '../types-DNrn_w4V.js';
14
14
  import '../wordFit-9B9nqyf3.js';
15
15
  import 'react';
@@ -3,18 +3,18 @@ export { CanvasWords, DEFAULT_EDITOR_STRINGS, PanelWords, RailWords, mergeEditor
3
3
  import * as react from 'react';
4
4
  import { ReactNode } from 'react';
5
5
  export { C as ChromeWords, N as NoticeWords } from '../words-DagJdwIA.js';
6
- export { C as CopyWords } from '../words-DfxEp_RH.js';
6
+ export { C as CopyWords } from '../words-bOMsUJk9.js';
7
7
  export { D as DragWords } from '../words-D9ChvbNC.js';
8
8
  export { F as FieldsWords } from '../words-CD3WADyb.js';
9
9
  export { LockWords } from '../edit-lock/index.js';
10
10
  export { N as NodeMenuWords } from '../words-DOhF-4D4.js';
11
11
  export { P as PickWords } from '../words-B87GIFWH.js';
12
- export { S as SaveWords } from '../words-CsRWXkY4.js';
12
+ export { S as SaveWords } from '../words-Cqmyey0s.js';
13
13
  export { S as StyleClipboardWords } from '../words-B2YLaKEr.js';
14
14
  export { T as TreeWords } from '../words-BK-npta-.js';
15
- import '../buckets-1vRlQceY.js';
15
+ import '../buckets-CuLM47h9.js';
16
16
  import '../markup/index.js';
17
- import '../types-CuNiSnX6.js';
17
+ import '../types-CnRzp9oc.js';
18
18
  import '../types-DNrn_w4V.js';
19
19
  import '../wordFit-9B9nqyf3.js';
20
20
 
@@ -1 +1 @@
1
- import{DEFAULT_STYLE_CLIPBOARD_WORDS as t}from"../chunk-6WY6ZXJG.js";import{CopyStyleIcon as e,PasteStyleIcon as n}from"../chunk-YNZZYHA4.js";import{jsx as o}from"react/jsx-runtime";var r="__styleKind";function u(t,e){return t[r]=e,t}function c(t,e){return`${t}:${e.map(t=>String(t)).sort().join("|")}`}function i(t){if(!t)return null;const e=t.indexOf(":");if(e<0)return null;const n=t.slice(0,e);return s.has(n)?{control:n,values:t.slice(e+1).split("|")}:null}var s=/* @__PURE__ */new Set(["choice","select","radio"]);function l(t){if(!t||"object"!=typeof t)return null;const e=t;return"string"==typeof e[r]?e[r]:"text"===e.type||"textarea"===e.type||"number"===e.type?e.type:"select"!==e.type&&"radio"!==e.type||!Array.isArray(e.options)?null:c(e.type,e.options.map(t=>t?.value))}function a(t){return null!=t&&""!==t}function p(t,e){let n=t;for(const t of e){if(!n||"object"!=typeof n)return;n=n[t]}return n}function f(t){return void 0===t?t:JSON.parse(JSON.stringify(t))}function d(t,e,n){const[o,...r]=e,u={...t};if(0===r.length)return void 0===n?delete u[o]:u[o]=n,u;const c=u[o],i=d(c&&"object"==typeof c?c:{},r,n);return 0===Object.keys(i).length?delete u[o]:u[o]=i,u}var y=t=>t.join("."),h="editor-shell:style-clipboard",g=null,m=!1,v=/* @__PURE__ */new Set;function S(){try{return"undefined"==typeof sessionStorage?null:sessionStorage}catch{return null}}function b(){if(!m){m=!0;try{const t=S()?.getItem(h);t&&(g=JSON.parse(t))}catch{g=null}}}function k(t){b(),g={scope:t.scope,sourceType:t.type,sourceLabel:t.label,rows:t.rows.map(e=>{const n=p(t.props,e.path);return{path:[...e.path],kind:e.kind,counted:!1!==e.counted,value:a(n)?f(n):void 0}})};try{S()?.setItem(h,JSON.stringify(g))}catch{}return v.forEach(t=>t()),g}function N(t){return b(),g&&g.scope===t?g:null}function j(t){return v.add(t),()=>{v.delete(t)}}function C(){g=null,m=!0;try{S()?.removeItem(h)}catch{}v.forEach(t=>t())}function w(t,e,n){if(t.kind===e.kind)return null!==e.kind||n;const o=i(t.kind),r=i(e.kind);return!(!o||!r||o.control!==r.control)&&(!a(t.value)||r.values.includes(String(t.value)))}function O(t,e){const n=t.sourceType===e.type,o=new Map(t.rows.map(t=>[y(t.path),t]));let r=e.props,u=0,c=!1;for(const t of e.rows){const e=o.get(y(t.path));if(!e)continue;if(!w(e,t,n))continue;const i=p(r,t.path),s=void 0===e.value?void 0:f(e.value);JSON.stringify(a(i)?i:void 0)!==JSON.stringify(s)&&(r=d(r,t.path,s),c=!0),!1!==t.counted&&(u+=1)}return{props:r,pasted:u,changed:c}}function E(e,n,o,r=t){return 0===e.pasted?r.nothing({source:n,target:o}):r.pasted({count:e.pasted,source:n})}var J="⌥⌘C",K="⌥⌘V";function T(r){const u=r.words??t,c=[];return r.canCopy&&c.push({label:u.copy,icon:/* @__PURE__ */o(e,{}),shortcut:"⌥⌘C",onClick:r.onCopy}),r.held&&c.push({label:u.paste({source:r.held.sourceLabel}),icon:/* @__PURE__ */o(n,{}),shortcut:"⌥⌘V",onClick:r.onPaste}),c}function x(t){if(!t.altKey||t.shiftKey||!t.metaKey&&!t.ctrlKey)return null;const e=t.target;return e&&(e.isContentEditable||"INPUT"===e.tagName||"TEXTAREA"===e.tagName||"SELECT"===e.tagName)?null:"KeyC"===t.code?"copy":"KeyV"===t.code?"paste":null}export{J as COPY_STYLE_SHORTCUT,K as PASTE_STYLE_SHORTCUT,r as STYLE_KIND,c as choiceKind,C as clearStyle,k as copyStyle,l as fieldKind,N as heldStyle,E as pasteMessage,O as planPaste,T as styleMenuItems,x as styleShortcut,j as subscribeStyle,u as withStyleKind};
1
+ import{DEFAULT_STYLE_CLIPBOARD_WORDS as t}from"../chunk-6WY6ZXJG.js";import{CopyStyleIcon as e,PasteStyleIcon as n}from"../chunk-PI26YXYD.js";import{jsx as o}from"react/jsx-runtime";var r="__styleKind";function u(t,e){return t[r]=e,t}function c(t,e){return`${t}:${e.map(t=>String(t)).sort().join("|")}`}function i(t){if(!t)return null;const e=t.indexOf(":");if(e<0)return null;const n=t.slice(0,e);return s.has(n)?{control:n,values:t.slice(e+1).split("|")}:null}var s=/* @__PURE__ */new Set(["choice","select","radio"]);function l(t){if(!t||"object"!=typeof t)return null;const e=t;return"string"==typeof e[r]?e[r]:"text"===e.type||"textarea"===e.type||"number"===e.type?e.type:"select"!==e.type&&"radio"!==e.type||!Array.isArray(e.options)?null:c(e.type,e.options.map(t=>t?.value))}function a(t){return null!=t&&""!==t}function p(t,e){let n=t;for(const t of e){if(!n||"object"!=typeof n)return;n=n[t]}return n}function f(t){return void 0===t?t:JSON.parse(JSON.stringify(t))}function d(t,e,n){const[o,...r]=e,u={...t};if(0===r.length)return void 0===n?delete u[o]:u[o]=n,u;const c=u[o],i=d(c&&"object"==typeof c?c:{},r,n);return 0===Object.keys(i).length?delete u[o]:u[o]=i,u}var y=t=>t.join("."),h="editor-shell:style-clipboard",g=null,m=!1,v=/* @__PURE__ */new Set;function S(){try{return"undefined"==typeof sessionStorage?null:sessionStorage}catch{return null}}function b(){if(!m){m=!0;try{const t=S()?.getItem(h);t&&(g=JSON.parse(t))}catch{g=null}}}function k(t){b(),g={scope:t.scope,sourceType:t.type,sourceLabel:t.label,rows:t.rows.map(e=>{const n=p(t.props,e.path);return{path:[...e.path],kind:e.kind,counted:!1!==e.counted,value:a(n)?f(n):void 0}})};try{S()?.setItem(h,JSON.stringify(g))}catch{}return v.forEach(t=>t()),g}function N(t){return b(),g&&g.scope===t?g:null}function j(t){return v.add(t),()=>{v.delete(t)}}function C(){g=null,m=!0;try{S()?.removeItem(h)}catch{}v.forEach(t=>t())}function w(t,e,n){if(t.kind===e.kind)return null!==e.kind||n;const o=i(t.kind),r=i(e.kind);return!(!o||!r||o.control!==r.control)&&(!a(t.value)||r.values.includes(String(t.value)))}function O(t,e){const n=t.sourceType===e.type,o=new Map(t.rows.map(t=>[y(t.path),t]));let r=e.props,u=0,c=!1;for(const t of e.rows){const e=o.get(y(t.path));if(!e)continue;if(!w(e,t,n))continue;const i=p(r,t.path),s=void 0===e.value?void 0:f(e.value);JSON.stringify(a(i)?i:void 0)!==JSON.stringify(s)&&(r=d(r,t.path,s),c=!0),!1!==t.counted&&(u+=1)}return{props:r,pasted:u,changed:c}}function E(e,n,o,r=t){return 0===e.pasted?r.nothing({source:n,target:o}):r.pasted({count:e.pasted,source:n})}var J="⌥⌘C",K="⌥⌘V";function T(r){const u=r.words??t,c=[];return r.canCopy&&c.push({label:u.copy,icon:/* @__PURE__ */o(e,{}),shortcut:"⌥⌘C",onClick:r.onCopy}),r.held&&c.push({label:u.paste({source:r.held.sourceLabel}),icon:/* @__PURE__ */o(n,{}),shortcut:"⌥⌘V",onClick:r.onPaste}),c}function x(t){if(!t.altKey||t.shiftKey||!t.metaKey&&!t.ctrlKey)return null;const e=t.target;return e&&(e.isContentEditable||"INPUT"===e.tagName||"TEXTAREA"===e.tagName||"SELECT"===e.tagName)?null:"KeyC"===t.code?"copy":"KeyV"===t.code?"paste":null}export{J as COPY_STYLE_SHORTCUT,K as PASTE_STYLE_SHORTCUT,r as STYLE_KIND,c as choiceKind,C as clearStyle,k as copyStyle,l as fieldKind,N as heldStyle,E as pasteMessage,O as planPaste,T as styleMenuItems,x as styleShortcut,j as subscribeStyle,u as withStyleKind};
@@ -143,7 +143,7 @@ declare const TREE_DRAG_HINT: string;
143
143
  /**
144
144
  * ONE row, at every depth (the owner's "One Ladder", 2026-09-04).
145
145
  *
146
- * Lifted from the website editor's `.sf-row` (efficient-shop). Left to right:
146
+ * Lifted from the website editor's `.sf-row` (efficient-storefront). Left to right:
147
147
  * the drag handle (out of flow, in the row's left padding), the caret — or a
148
148
  * spacer holding its column open, so every glyph below lines up whether its row
149
149
  * folds or not — the type glyph, then the name box. The actions are laid over
@@ -1 +1 @@
1
- export{LayersTree,Subtree,TREE_DRAG_HINT,TreeGroupLabel,TreeRow,TreeRowAction,TreeSeam}from"../chunk-STFMZJKU.js";import"../chunk-H4B72XCJ.js";import"../chunk-YNZZYHA4.js";
1
+ export{LayersTree,Subtree,TREE_DRAG_HINT,TreeGroupLabel,TreeRow,TreeRowAction,TreeSeam}from"../chunk-66CKSTXP.js";import"../chunk-H4B72XCJ.js";import"../chunk-PI26YXYD.js";
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * efficient-easel/tree.css — the Layers tree: one row shape at every depth.
3
3
  *
4
- * EVERY VALUE HERE WAS READ OFF `efficient-shop/components/storefront-editor.css`
4
+ * EVERY VALUE HERE WAS READ OFF `efficient-storefront/components/storefront-editor.css`
5
5
  * on origin/main (release 14.24.0, 2026-09-17), where the website editor drew
6
6
  * the tree as `.sf-tree` / `.sf-row` / `.sf-subtree` / `.sf-group-label` (the
7
7
  * owner's "One Ladder", 2026-09-04). Its `--sf-*` tokens alias the `--es-*`
@@ -17,13 +17,13 @@
17
17
  /* LEFT 8 — the inset a rounded row needs. RIGHT 11 — the room a real,
18
18
  space-taking 11px scrollbar takes, so nothing at a row's end sits under
19
19
  the thumb. Words inside start on one 11px column down the panel. */
20
- padding: 0 11px 10px 8px;
20
+ padding: 0 12px 12px 8px;
21
21
  /* THE TREE'S RHYTHM, under the shell's names, at the tree's own density: the
22
22
  owner picked 10 between groups and 6 between rows by eye (2026-08-31). They
23
23
  are declared HERE, not on the editor root, so the settings panel beside the
24
24
  tree keeps its own values for the same names. */
25
- --es-rhythm-group: 10px;
26
- --es-rhythm-between: 6px;
25
+ --es-rhythm-group: 12px;
26
+ --es-rhythm-between: 8px;
27
27
  }
28
28
  /* Every seam the tree stacks, spelled out: labels and subtrees interleave with
29
29
  rows, and a rule that knew only rows would leave those seams to chance. */
@@ -38,7 +38,7 @@
38
38
  letter-spacing: 0.07em;
39
39
  text-transform: uppercase;
40
40
  color: var(--es-muted);
41
- padding: var(--es-rhythm-group) 11px var(--es-rhythm-between);
41
+ padding: var(--es-rhythm-group) 12px var(--es-rhythm-between);
42
42
  }
43
43
 
44
44
  /* THE ONLY THING IN THE TREE THAT SAYS DEPTH: 16px of indent and a hairline
@@ -46,7 +46,7 @@
46
46
  rows outside, so the ladder reads as one list at several depths. */
47
47
  .es-subtree {
48
48
  margin: var(--es-rhythm-between) 0 var(--es-rhythm-between) 16px;
49
- padding-left: 9px;
49
+ padding-left: 8px;
50
50
  border-left: 1px solid var(--es-line);
51
51
  display: flex;
52
52
  flex-direction: column;
@@ -57,7 +57,7 @@
57
57
  display: flex;
58
58
  align-items: center;
59
59
  gap: 8px;
60
- padding: 7px 11px;
60
+ padding: 8px 12px;
61
61
  border-radius: var(--es-row-radius);
62
62
  cursor: pointer;
63
63
  transition: background 0.12s;
@@ -158,7 +158,7 @@
158
158
  STOCK NOW" — quieter than the name, and the first thing to be cut when the
159
159
  panel is narrow (it sits inside the name's own ellipsis). */
160
160
  .es-tree-preview {
161
- margin-left: 6px;
161
+ margin-left: 8px;
162
162
  font-weight: 400;
163
163
  color: var(--es-muted);
164
164
  }
@@ -337,7 +337,7 @@
337
337
  min-width: 0;
338
338
  display: flex;
339
339
  align-items: center;
340
- gap: 6px;
340
+ gap: 8px;
341
341
  cursor: pointer;
342
342
  border-radius: 4px;
343
343
  }
@@ -371,7 +371,7 @@
371
371
  color: var(--es-muted);
372
372
  background: var(--es-chip-bg);
373
373
  border-radius: 4px;
374
- padding: 1px 4px;
374
+ padding: 2px 4px;
375
375
  }
376
376
  .es-tree-trailing {
377
377
  flex: none;
@@ -490,7 +490,7 @@
490
490
  left: 24px;
491
491
  top: calc(100% + 4px);
492
492
  z-index: 5;
493
- padding: 3px 7px;
493
+ padding: 4px 8px;
494
494
  border-radius: 6px;
495
495
  background: var(--es-toast-bg);
496
496
  color: var(--es-on-accent);
@@ -51,13 +51,20 @@ interface Place extends SlotAddress {
51
51
  index: number;
52
52
  }
53
53
  /**
54
- * The part of a field definition the data layer needs: which props are slots.
54
+ * The part of a field definition the data layer needs: which props are slots,
55
+ * and (./translate) which hold words that are written again per language.
55
56
  * A Puck `Field` satisfies it, so an app hands in the config it already has.
56
57
  */
57
58
  interface FieldShape {
58
59
  type: string;
59
60
  objectFields?: Record<string, FieldShape>;
60
61
  arrayFields?: Record<string, FieldShape>;
62
+ /**
63
+ * Whether the value is translated. Left out, `text` and `textarea` are and
64
+ * nothing else is; on an `object` or `array` field it is the default for the
65
+ * fields inside it. A `slot` never is: its children have ids of their own.
66
+ */
67
+ translatable?: boolean;
61
68
  }
62
69
  type FieldsShape = Record<string, FieldShape>;
63
70
  /**
@@ -1,5 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
- import { S as SettingsBucket } from './buckets-1vRlQceY.js';
2
+ import { S as SettingsBucket } from './buckets-CuLM47h9.js';
3
3
 
4
4
  /** What every control shares: an id for its label, a name for screen readers, and a read-only switch. */
5
5
  interface ControlBase {
@@ -22,13 +22,35 @@ interface FieldNumberProps extends ControlBase {
22
22
  onChange: (value: number | undefined) => void;
23
23
  min?: number;
24
24
  max?: number;
25
+ /** What an arrow or ↑↓ moves by. Default 1. */
25
26
  step?: number;
26
- /** Shown after the box, e.g. `px`. */
27
+ /** What Shift + an arrow or ↑↓ moves by. Default ten steps. */
28
+ shiftStep?: number;
29
+ /**
30
+ * The style's number. While the value is `undefined` it shows in the box,
31
+ * grey, and a step starts from it; a typed value beats it until cleared.
32
+ */
33
+ styleValue?: number;
34
+ /** Drawn first in the cell, e.g. the font-size glyph. */
35
+ icon?: ReactNode;
36
+ /** Shown after the number, inside the cell, e.g. `px`. */
27
37
  unit?: string;
28
- /** − and + beside the box. */
38
+ /** Two small stacked arrows at the cell's end. */
29
39
  steppers?: boolean;
30
40
  placeholder?: string;
31
41
  }
42
+ /**
43
+ * A slider row (Site styles, Email styles): the name left and the typed value
44
+ * right on one line, the slider under them. `sliderMin` / `sliderMax` are the
45
+ * slider's travel only; a typed value may go past them, held only by `min` /
46
+ * `max`.
47
+ */
48
+ interface FieldSliderProps extends Omit<FieldNumberProps, 'icon' | 'steppers' | 'placeholder' | 'ariaLabel' | 'ariaLabelledBy'> {
49
+ /** The row's name; it labels both the value and the slider. */
50
+ label: string;
51
+ sliderMin: number;
52
+ sliderMax: number;
53
+ }
32
54
  interface FieldOption<V = unknown> {
33
55
  label: string;
34
56
  value: V;
@@ -126,4 +148,4 @@ type FieldRenderer = (props: {
126
148
  readOnly?: boolean;
127
149
  }) => ReactNode;
128
150
 
129
- 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, FieldSelectProps as d, FieldOption as e, CustomFieldRenderProps as f, SlotFieldDef as g, TextareaFieldDef as h };
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 };
@@ -5,7 +5,7 @@ import { EditAccess, SaveConflict } from './edit-lock/index.js';
5
5
  /**
6
6
  * The side-panel widths every editor opens on and drags between (px).
7
7
  *
8
- * Lifted from `efficient-shop/components/panel-widths.ts`, where the website
8
+ * Lifted from `efficient-storefront/components/panel-widths.ts`, where the website
9
9
  * editor measured them:
10
10
  *
11
11
  * RIGHT is 320, not 308 (card 8810). At 308 the settings tab strip was left
@@ -1,6 +1,6 @@
1
1
  import { DataInput } from './data/index.js';
2
- import { I as ItemSelector, N as NodeSelection } from './plan-DtNw2VuI.js';
3
- import { D as Data, S as SlotAddress, a as DataConfig, N as Node } from './types-DziKCwsN.js';
2
+ import { I as ItemSelector, N as NodeSelection } from './plan-DChbUXdS.js';
3
+ import { D as Data, S as SlotAddress, a as DataConfig, N as Node } from './types-41704JE4.js';
4
4
 
5
5
  /**
6
6
  * The editor's UI state, in Puck's shape so the apps' `appState.ui` reads move
@@ -1,5 +1,5 @@
1
- import { N as Node, S as SlotAddress, D as Data, a as DataConfig, P as Place } from './types-DziKCwsN.js';
2
- import { N as NodeSelection, A as AfterRemove, S as StepBounds } from './plan-DtNw2VuI.js';
1
+ import { N as Node, S as SlotAddress, D as Data, a as DataConfig, P as Place } from './types-41704JE4.js';
2
+ import { N as NodeSelection, A as AfterRemove, S as StepBounds } from './plan-DChbUXdS.js';
3
3
 
4
4
  /**
5
5
  * The node clipboard — what Copy and Cut hold, and Paste reads.
@@ -1,4 +1,4 @@
1
- import { S as SaveTone } from './types-CuNiSnX6.js';
1
+ import { S as SaveTone } from './types-CnRzp9oc.js';
2
2
 
3
3
  /** Time and timers, passed in so a test can run minutes in a millisecond. */
4
4
  type AutosaveClock = {
@@ -76,7 +76,7 @@ declare function createAutosave<T>(options?: AutosaveOptions<T>): Autosave<T>;
76
76
  *
77
77
  * There were three: the campaign designer's `saveStatusLabel`
78
78
  * (efficient-admin-portal `src/components/email/autosaveStatus.ts`), the
79
- * website editor's `autosaveStatusLabel` (efficient-shop
79
+ * website editor's `autosaveStatusLabel` (efficient-storefront
80
80
  * `lib/editor/autosave-status.ts`, which said of the first "a MIRRORED copy …
81
81
  * whether that pair should collapse into `efficient-easel` is called out
82
82
  * rather than decided here") and the website chrome's own words for its
@@ -61,7 +61,7 @@ declare const COPY_ALIGN_GLYPHS: Record<CopyAlign, ReactNode>;
61
61
  * An over-estimate is safe (the words drop a little early); an under-estimate
62
62
  * draws a button past the strip's edge.
63
63
  *
64
- * THREE is measured, not guessed — `efficient-shop/components/PartSettingsPanel`
64
+ * THREE is measured, not guessed — `efficient-storefront/components/PartSettingsPanel`
65
65
  * had this exact pair as its own `ALIGN_FIT`, produced by
66
66
  * `tests/fixtures/segmented-fit.html`. It moves here so the one alignment strip
67
67
  * carries its own measurement, and that constant is deleted when the panel
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "efficient-easel",
3
- "version": "0.96.0",
3
+ "version": "0.98.0",
4
4
  "description": "Efficient Easel: the EFFICIENT editors' shared engine and chrome: the saved document as pure functions, the published renderer, and the editor frame, panels, Layers tree, text grammar and type-in-place box. Published as editor-shell up to 0.66.0 and as efficient-editor up to 0.95.0.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "Efficient Pty Ltd",
@@ -1 +0,0 @@
1
- var e={accent:"#2563eb",accentTint:"#eff6ff",accentTintStrong:"#dbeafe",accentLine:"#bfdbfe",accentText:"#1d4ed8",accentRing:"rgba(37, 99, 235, 0.25)",accentShadow:"rgba(37, 99, 235, 0.35)",onAccent:"#ffffff",appBg:"#f9fafb",previewBg:"#f3f4f6",panel:"#ffffff",raised:"#ffffff",topbarBg:"#ffffff",frameBg:"#ffffff",hover:"#f3f4f6",hatch:"rgba(0, 0, 0, 0.018)",addcardVeil:"rgba(248, 249, 250, 0.66)",fieldBg:"#ffffff",trackBg:"#f3f4f6",inputBorder:"#d1d5db",fieldText:"#1f2937",fieldPlaceholder:"#9ca3af",knob:"#ffffff",text:"#111827",textStrong:"#030712",textSecondary:"#374151",muted:"#6b7280",icon:"#6b7280",disabled:"#9ca3af",divider:"#e5e7eb",line:"#e5e7eb",btnBorder:"#d1d5db",btnText:"#374151",chipBg:"#f3f4f6",chipFg:"#6b7280",brandSquare:"#111827",deviceBorder:"#e5e7eb",toastBg:"#111827",toggleOff:"#d1d5db",scrollbar:"#d1d5db",scrollbarHover:"#9ca3af",danger:"#dc2626",dangerStrong:"#b91c1c",dangerTint:"#fef2f2",warning:"#b45309",previewTint:"#fef3c7",success:"#15803d",panelRadius:12,rowRadius:8,fieldRadius:6,panelGap:10,panelShadow:"0 1px 2px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.06)",topbarShadow:"0 1px 3px rgba(0, 0, 0, 0.06)",raisedShadow:"0 1px 2px rgba(16, 24, 40, 0.1)",font:'-apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif'},a={accent:"--es-accent",accentTint:"--es-accent-tint",accentTintStrong:"--es-accent-tint-strong",accentLine:"--es-accent-line",accentText:"--es-accent-text",accentRing:"--es-accent-ring",accentShadow:"--es-accent-shadow",onAccent:"--es-on-accent",appBg:"--es-app-bg",previewBg:"--es-preview-bg",panel:"--es-panel",raised:"--es-raised",topbarBg:"--es-topbar-bg",frameBg:"--es-frame-bg",hover:"--es-hover",hatch:"--es-hatch",addcardVeil:"--es-addcard-veil",fieldBg:"--es-field-bg",trackBg:"--es-track-bg",inputBorder:"--es-input-border",fieldText:"--es-field-text",fieldPlaceholder:"--es-field-placeholder",knob:"--es-knob",text:"--es-text",textStrong:"--es-text-strong",textSecondary:"--es-text-secondary",muted:"--es-muted",icon:"--es-icon",disabled:"--es-disabled",divider:"--es-divider",line:"--es-line",btnBorder:"--es-btn-border",btnText:"--es-btn-text",chipBg:"--es-chip-bg",chipFg:"--es-chip-fg",brandSquare:"--es-brand-square",deviceBorder:"--es-device-border",toastBg:"--es-toast-bg",toggleOff:"--es-toggle-off",scrollbar:"--es-scrollbar",scrollbarHover:"--es-scrollbar-hover",danger:"--es-danger",dangerStrong:"--es-danger-strong",dangerTint:"--es-danger-tint",warning:"--es-warning",previewTint:"--es-preview-tint",success:"--es-success",panelRadius:"--es-panel-radius",rowRadius:"--es-row-radius",fieldRadius:"--es-field-radius",panelGap:"--es-panel-gap",panelShadow:"--es-panel-shadow",topbarShadow:"--es-topbar-shadow",raisedShadow:"--es-raised-shadow",font:"--es-font"};export{a as shellCssVars,e as shellTokens};
@@ -1 +0,0 @@
1
- import{isRecord as n,fieldsFrom as t,blockOf as o,topLevelSlotKeys as e,slotLocations as r,setIn as s,fieldsOf as c,defaultsFrom as i,isNode as p}from"./chunk-NKB3KVAB.js";var f=()=>({lastChange:{}});function l(n,t){if(n===t)return!0;if(!n||!t||"object"!=typeof n||"object"!=typeof t)return n!=n&&t!=t;if(Array.isArray(n)!==Array.isArray(t))return!1;if(Array.isArray(n)){const o=t;if(n.length!==o.length)return!1;for(let t=0;t<n.length;t++)if(!l(n[t],o[t]))return!1;return!0}const o=Object.keys(n),e=Object.keys(t);if(o.length!==e.length)return!1;for(const e of o){if(!Object.prototype.hasOwnProperty.call(t,e))return!1;if(!l(n[e],t[e]))return!1}return!0}function a(n,t){if(!n)return{};const o=n.props??{},e=t?.props??{},r={};for(const n of Object.keys(o))r[n]=!l(e[n],o[n]);return r}async function d(c,i,p={}){const{metadata:u={},trigger:y="replace",cache:h=f(),onResolveStart:g,onResolveEnd:w}=p,m=function(n,t){return n.type&&"root"!==n.type?t.components[n.type]:t.root}(c,i);let $={...c};const x=Boolean(m?.resolveData&&c.props),I=n(c.props)&&"id"in c.props?String(c.props.id):"root";if(x){const n=h.lastChange[I];if("force"!==y&&n&&l(c,n.item))return{node:n.resolved,didChange:!1};const t=a(c,n?.item??null);g?.(c);const o=await m.resolveData(c,{changed:t,lastData:n?.item??null,metadata:{...u,...m.metadata??{}},trigger:y})??{};$.props={...c.props,...o.props??{}},o.readOnly&&Object.keys(o.readOnly).length&&($.readOnly=o.readOnly)}const b=t(c.type&&"root"!==c.type?o(i,c.type):i.root);if(m)for(const n of e(b))void 0===$.props[n]&&($={...$,props:{...$.props,[n]:[]}});for(const n of r($.props,b)){if(!n.present)continue;const t=await Promise.all(n.content.map(async n=>(await d(n,i,{metadata:u,trigger:y,cache:h,onResolveStart:g,onResolveEnd:w})).node));$={...$,props:s($.props,n.segments,t)}}return x&&w?.($),h.lastChange[I]={item:c,resolved:$},{node:$,didChange:!l(c,$)}}var u="root",y="default-zone",h={parentId:u,slot:y},g=({parentId:n,slot:t})=>`${n}:${t}`;function w(n){const t=n.indexOf(":");if(-1===t)throw new $("no-slot",`"${n}" is not a zone key`);return{parentId:n.slice(0,t),slot:n.slice(t+1)}}var m=n=>n.parentId===u&&n.slot===y,$=class extends Error{code;constructor(n,t){super(t),this.name="DataError",this.code=n}};function x(n){try{const t=globalThis.crypto;if(t&&"function"==typeof t.randomUUID)return`${n}-${t.randomUUID()}`}catch{}return`${n}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function I(n,t){return r(n.props,c(t,n.type)).map(({slot:n,content:t})=>({slot:n,content:t}))}function b(n,o){return r(z(n),t(o.root))}function z(t){return n(t.root?.props)?t.root.props:{}}function O(n,t,o){const e=(n,t,e,r,s)=>{if(!Array.isArray(n))return n;const c=[...e,t];let f=null;return n.forEach((e,l)=>{if(!p(e))return;const a={place:{...t,index:l},path:c,parent:r,depth:s};let d=o(e,a)??e;if(d!==e&&d.props.id!==e.props.id)throw new $("id-change",`walk: ${e.props.id} came back as ${d.props.id}`);d=i(d,c,s+1),d!==e&&(f??=[...n],f[l]=d)}),f??n},i=(n,o,i)=>{let p=n.props;for(const f of r(n.props,c(t,n.type))){if(!f.present)continue;const t=e(f.content,{parentId:n.props.id,slot:f.slot},o,n,i);t!==f.content&&(p=s(p,f.segments,t))}return p===n.props?n:{...n,props:p}};let f=n;const l=e(n.content,h,[],null,0);l!==n.content&&(f={...f,content:l});let a=z(f);for(const n of b(f,t)){if(!n.present)continue;const t=e(n.content,{parentId:u,slot:n.slot},[],null,0);t!==n.content&&(a=s(a,n.segments,t))}a!==z(f)&&(f={...f,root:{...f.root,props:a}});const d=f.zones;if(d){let n=d;for(const t of Object.keys(d)){const o=k(t);if(!o)continue;const r=e(d[t],o,[],null,0);r!==d[t]&&(n={...n,[t]:r})}n!==d&&(f={...f,zones:n})}return f}function k(n){const t=n.indexOf(":");return-1===t?null:{parentId:n.slice(0,t),slot:n.slice(t+1)}}function A(n,t,o){let e=null;const r={};try{O(n,t,(n,t)=>{if(n.props.id===o)throw e={node:n,place:t.place,path:t.path},r})}catch(n){if(n!==r)throw n}return e}function j(n,t,o){if(m(o))return Array.isArray(n.content)?n.content:[];const e=n.zones?.[g(o)];if(o.parentId===u){const r=b(n,t).find(n=>n.slot===o.slot);return r?r.content:e??null}const s=A(n,t,o.parentId);if(s){const n=r(s.node.props,c(t,s.node.type)).find(n=>n.slot===o.slot);if(n)return n.content}return e??null}function v(n,t){const o=/* @__PURE__ */new Set;return O(n,t,n=>{o.add(n.props.id)}),o}function S(n,t){const o=/* @__PURE__ */new Set([n.props.id]),e=n=>{for(const{content:r}of I(n,t))for(const n of r)p(n)&&(o.add(n.props.id),e(n))};return e(n),o}function D(n,t,o,e){if(m(o)){const t=Array.isArray(n.content)?n.content:[];return{...n,content:e(t)}}const i=g(o),p=!!n.zones&&Array.isArray(n.zones[i]);if(o.parentId===u){const r=b(n,t).find(n=>n.slot===o.slot);if(r){const t=s(z(n),r.segments,e(r.content));return{...n,root:{...n.root,props:t}}}}else{const i=A(n,t,o.parentId);if(i){const p=r(i.node.props,c(t,i.node.type)).find(n=>n.slot===o.slot);if(p)return N(n,t,i,n=>({...n,props:s(n.props,p.segments,e(p.content))}))}else if(!p)throw new $("not-found",`no node ${o.parentId}`)}if(p)return{...n,zones:{...n.zones,[i]:e(n.zones[i])}};throw new $("no-slot",`no slot "${o.slot}" on ${o.parentId}`)}function N(n,t,o,e){return D(n,t,o.place,n=>{const t=[...n];return t[o.place.index]=e(n[o.place.index]),t})}function E(n,t,o){const e=A(n,t,o);if(!e)throw new $("not-found",`no node ${o}`);return e}function C(n,t,o){const e=j(n,t,o);if(e)return e;if(o.parentId!==u&&!A(n,t,o.parentId))throw new $("not-found",`no node ${o.parentId}`);throw new $("no-slot",`no slot "${o.slot}" on ${o.parentId}`)}function R(n,t,o){if(!Number.isInteger(n)||n<0||n>t)throw new $("bad-index",`${o}: index ${n} is outside 0…${t}`)}function U(n,c){const i=o(c,n.type);if(!i)return n;const p=t(i);let f=n.props;for(const n of e(p))null==f[n]&&(f={...f,[n]:[]});for(const n of r(f,p)){if(!n.present)continue;const t=B(n.content,c);t!==n.content&&(f=s(f,n.segments,t))}return f===n.props?n:{...n,props:f}}function B(t,o){let e=null;return t.forEach((r,s)=>{if(!n(r)||"string"!=typeof r.type)return;let c=r;if(n(c.props)){if("string"!=typeof c.props.id||""===c.props.id){const{id:n,...t}=c.props;c={...c,props:{id:x(c.type),...t}}}}else c={...c,props:{id:x(c.type)}};const i=U(c,o);i!==r&&(e??=[...t],e[s]=i)}),e??t}function P(n,o){const c=t(o.root);let i=n.props;for(const n of e(c))null==i[n]&&(i={...i,[n]:[]});for(const n of r(i,c)){if(!n.present)continue;const t=B(n.content,o);t!==n.content&&(i=s(i,n.segments,t))}return i===n.props?n:{...n,props:i}}function J(t,o){let e=n(t)?t:{};const r=e.root;if(n(r)){if(!n(r.props)){const n=Object.keys(r).filter(n=>"props"!==n);e={...e,root:n.length?{props:{...M(r,n)}}:{props:{}}}}}else e={...e,root:{props:{}}};const s=i(o.root);if(s){const n=Object.keys(s).filter(n=>!(n in e.root.props));if(n.length){const t=T(M(s,n));e={...e,root:{...e.root,props:{...e.root.props,...t}}}}}const c=P(e.root,o);c!==e.root&&(e={...e,root:c}),Array.isArray(e.content)||(e={...e,content:[]});const p=B(e.content,o);return p!==e.content&&(e={...e,content:p}),e=n(e.zones)?function(n,t){let o=n;for(const e of Object.keys(n.zones??{})){const n=o.zones[e];if(!Array.isArray(n)||0===n.length)continue;const r=k(e);if(!r||m(r))continue;const s=K(o,t,r);if(!s||s.content.length>0)continue;const{[e]:c,...i}=o.zones;o=D({...o,zones:i},t,r,()=>B(n,t))}const e=o.zones;let r=e;for(const n of Object.keys(e)){if(!Array.isArray(e[n]))continue;const o=B(e[n],t);o!==e[n]&&(r={...r,[n]:o})}return r===e?o:{...o,zones:r}}(e,o):{...e,zones:{}},e}function K(n,t,o){if(o.parentId===u)return b(n,t).find(n=>n.slot===o.slot);const e=A(n,t,o.parentId);return e?r(e.node.props,c(t,e.node.type)).find(n=>n.slot===o.slot):void 0}function M(n,t){const o={};for(const e of t)o[e]=n[e];return o}function T(n){return void 0===n?n:JSON.parse(JSON.stringify(n))}function V(n,t,o={},e={}){const r=n.components[t];if(!r)throw new $("unknown-type",`no block type "${t}" in the config`);return U({type:t,props:{...T(i(r)??{}),...T(o),id:e.id??x(t)}},n)}function q(t,o,e,r){if(!p(r))throw new $("unknown-type","insert: not a node");const s=C(t,o,e);R(e.index,s.length,"insert");const c=U(n(r.props)&&"string"==typeof r.props.id&&r.props.id?r:{...r,props:{...r.props,id:x(r.type)}},o),i=v(t,o);for(const n of S(c,o))if(i.has(n))throw new $("duplicate-id",`insert: ${n} is already in the document`);return D(t,o,e,n=>[...n.slice(0,e.index),c,...n.slice(e.index)])}function F(n,t,o){const e=E(n,t,o);let r=D(n,t,e.place,n=>[...n.slice(0,e.place.index),...n.slice(e.place.index+1)]);if(r.zones&&Object.keys(r.zones).length){const n=S(e.node,t),o=Object.keys(r.zones).filter(t=>!n.has(t.split(":")[0]));o.length!==Object.keys(r.zones).length&&(r={...r,zones:M(r.zones,o)})}return r}function G(n,t,o,e){const r=E(n,t,o);if(S(r.node,t).has(e.parentId))throw new $("cycle",`move: ${o} cannot go inside itself`);if(r.place.parentId===e.parentId&&r.place.slot===e.slot){const o=C(n,t,e);return R(e.index,o.length-1,"move"),e.index===r.place.index?n:D(n,t,e,n=>{const t=[...n],[o]=t.splice(r.place.index,1);return t.splice(e.index,0,o),t})}R(e.index,C(n,t,e).length,"move");const s=D(n,t,r.place,n=>[...n.slice(0,r.place.index),...n.slice(r.place.index+1)]);return D(s,t,e,n=>[...n.slice(0,e.index),r.node,...n.slice(e.index)])}function H(n,t,o,e={}){const r=E(n,t,o),s=Q(T(r.node),t,e.strip,e.id);return D(n,t,r.place,n=>[...n.slice(0,r.place.index+1),s,...n.slice(r.place.index+1)])}function L(n,t,o={}){return Q(T(n),t,o.strip,o.id)}function Q(n,t,o,e){let i={...n,props:{...n.props,id:e??x(n.type)}};if(o){const n=o(i);if(n.props.id!==i.props.id)throw new $("id-change","duplicate: strip must not change the id");i=n}let f=i.props;for(const n of r(f,c(t,i.type))){if(!n.present)continue;const e=n.content.map(n=>p(n)?Q(n,t,o):n);f=s(f,n.segments,e)}return U({...i,props:f},t)}function W(n,t,o,e){if("id"in e&&e.id!==o)throw new $("id-change",`setProps: ${o} cannot become ${String(e.id)}`);const r=E(n,t,o);return Z(r.node.props,e)?N(n,t,r,n=>U({...n,props:{...n.props,...e,id:o}},t)):n}function X(n,t,o,e){if(!p(e))throw new $("unknown-type","replaceNode: not a node");if(e.props.id!==o)throw new $("id-change",`replaceNode: ${o} cannot become ${String(e.props.id)}`);const r=E(n,t,o),s=U(e,t),c=v(n,t);for(const n of S(r.node,t))c.delete(n);for(const n of S(s,t))if(c.has(n))throw new $("duplicate-id",`replaceNode: ${n} is already in the document`);return N(n,t,r,()=>s)}function Y(n,t,o){const e=z(n);if(!Z(e,o))return n;const r=P({...n.root,props:{...e,...o}},t);return{...n,root:r}}function Z(n,t){return Object.keys(t).some(o=>!(o in n)||!Object.is(n[o],t[o]))}export{$ as DataError,u as ROOT_ID,h as ROOT_LIST,y as ROOT_SLOT,a as changedProps,L as copyNode,V as createNode,f as createResolveCache,l as deepEqual,H as duplicate,A as find,j as getList,q as insert,G as move,x as newId,J as normalizeData,w as parseZoneKey,F as remove,X as replaceNode,d as resolveNodeData,W as setProps,Y as setRoot,I as slotsOf,O as walk,g as zoneKey};