efficient-easel 0.99.2 → 0.101.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 (108) hide show
  1. package/README.md +233 -17
  2. package/dist/autosave/index.d.ts +11 -5
  3. package/dist/blocks/index.d.ts +1 -1
  4. package/dist/canvas/index.d.ts +2 -2
  5. package/dist/canvas/index.js +1 -1
  6. package/dist/chrome/chrome.css +96 -29
  7. package/dist/chrome/index.d.ts +67 -18
  8. package/dist/chrome/index.js +25 -21
  9. package/dist/{chunk-JYPOOHII.js → chunk-2FZJWH24.js} +3 -3
  10. package/dist/chunk-3EDSDPIP.js +1 -0
  11. package/dist/chunk-546BBOPE.js +1 -0
  12. package/dist/chunk-67GNT6PF.js +1 -0
  13. package/dist/chunk-EOJNJCMJ.js +16 -0
  14. package/dist/chunk-EWVJSRRY.js +6 -0
  15. package/dist/chunk-FPOKPNO4.js +1 -0
  16. package/dist/chunk-H24N5TMZ.js +11 -0
  17. package/dist/chunk-IG3U5NWJ.js +1 -0
  18. package/dist/chunk-JUQ6YJCG.js +1 -0
  19. package/dist/chunk-KTVH2ZRL.js +15 -0
  20. package/dist/{chunk-PI26YXYD.js → chunk-L5KW4HG5.js} +16 -8
  21. package/dist/chunk-M6F6LS3H.js +1 -0
  22. package/dist/chunk-P6O363EE.js +6 -0
  23. package/dist/chunk-PAELDYYS.js +1 -0
  24. package/dist/chunk-QTLAVDJE.js +1 -0
  25. package/dist/chunk-UH7IGZKF.js +1 -0
  26. package/dist/chunk-WZ7TGAAT.js +3 -0
  27. package/dist/chunk-ZFDCDJNZ.js +16 -0
  28. package/dist/chunk-ZJEBF4NB.js +1 -0
  29. package/dist/chunk-ZNS7727Y.js +12 -0
  30. package/dist/copy/copy.css +442 -5
  31. package/dist/copy/index.d.ts +302 -5
  32. package/dist/copy/index.js +32 -10
  33. package/dist/drag/drag.css +10 -1
  34. package/dist/drag/index.d.ts +99 -8
  35. package/dist/drag/index.js +18 -17
  36. package/dist/easel/easel.css +15 -0
  37. package/dist/easel/index.d.ts +104 -33
  38. package/dist/easel/index.js +9 -1
  39. package/dist/edit-lock/index.d.ts +1 -3
  40. package/dist/edit-lock/index.js +1 -1
  41. package/dist/fields/fields.css +270 -38
  42. package/dist/fields/index.d.ts +209 -26
  43. package/dist/fields/index.js +22 -53
  44. package/dist/gold/index.js +1 -1
  45. package/dist/icons/index.d.ts +13 -1
  46. package/dist/icons/index.js +1 -1
  47. package/dist/index.d.ts +2 -2
  48. package/dist/index.js +1 -1
  49. package/dist/markup/index.d.ts +111 -10
  50. package/dist/markup/index.js +1 -1
  51. package/dist/menu/index.d.ts +58 -5
  52. package/dist/menu/index.js +1 -15
  53. package/dist/menu/menu.css +17 -6
  54. package/dist/node-ops/index.d.ts +1 -1
  55. package/dist/node-ops/index.js +1 -1
  56. package/dist/panel/index.d.ts +83 -4
  57. package/dist/panel/index.js +18 -16
  58. package/dist/panel/panel.css +135 -62
  59. package/dist/pick/index.d.ts +78 -2
  60. package/dist/pick/index.js +7 -14
  61. package/dist/pick/pick.css +197 -10
  62. package/dist/rail/index.d.ts +3 -7
  63. package/dist/rail/index.js +1 -1
  64. package/dist/strings/catalogue.d.ts +13 -35
  65. package/dist/strings/catalogue.js +1 -1
  66. package/dist/strings/index.d.ts +12 -18
  67. package/dist/strings/index.js +2 -2
  68. package/dist/style-clipboard/index.d.ts +1 -1
  69. package/dist/style-clipboard/index.js +1 -1
  70. package/dist/text-styles/index.d.ts +328 -0
  71. package/dist/text-styles/index.js +38 -0
  72. package/dist/text-styles/text-styles.css +309 -0
  73. package/dist/tree/index.d.ts +43 -2
  74. package/dist/tree/index.js +1 -1
  75. package/dist/tree/tree.css +71 -0
  76. package/dist/{types-p9j2Fac7.d.ts → types-DGcCsxs8.d.ts} +72 -7
  77. package/dist/{types-Bs_gVkVI.d.ts → types-DWS-s9z-.d.ts} +1 -9
  78. package/dist/{types-DO-b0LNj.d.ts → types-Djdq6Xkd.d.ts} +9 -8
  79. package/dist/{types-BOSGNvil.d.ts → types-E3HrTPg2.d.ts} +7 -13
  80. package/dist/{types-C7HFvdtk.d.ts → types-VqL6t5HH.d.ts} +82 -5
  81. package/dist/{watch-B5RTR-WX.d.ts → watch-BTYOJpQU.d.ts} +18 -1
  82. package/dist/{words-DagJdwIA.d.ts → words-AHHfiaRY.d.ts} +31 -2
  83. package/dist/words-BGrHZAJJ.d.ts +46 -0
  84. package/dist/{words-c-3h9xQQ.d.ts → words-BMzV04b1.d.ts} +1 -1
  85. package/dist/words-CRYvAiHX.d.ts +105 -0
  86. package/dist/words-D8kf071T.d.ts +93 -0
  87. package/dist/{words-N4ebT88_.d.ts → words-DgHcY5qB.d.ts} +9 -3
  88. package/dist/{words-C74EUpFr.d.ts → words-XH0TvZPg.d.ts} +60 -4
  89. package/package.json +8 -8
  90. package/dist/chunk-66CKSTXP.js +0 -14
  91. package/dist/chunk-672FAEKU.js +0 -1
  92. package/dist/chunk-67VZRQLG.js +0 -13
  93. package/dist/chunk-6PS6STGA.js +0 -1
  94. package/dist/chunk-7A7O2JWQ.js +0 -1
  95. package/dist/chunk-7JTL3P6P.js +0 -1
  96. package/dist/chunk-F2PIG3AA.js +0 -10
  97. package/dist/chunk-H4B72XCJ.js +0 -1
  98. package/dist/chunk-KDIVA6WD.js +0 -1
  99. package/dist/chunk-MCLBHENY.js +0 -1
  100. package/dist/chunk-QB3BZIRA.js +0 -5
  101. package/dist/chunk-SJQG5ENJ.js +0 -1
  102. package/dist/chunk-SUO5627P.js +0 -1
  103. package/dist/chunk-XUE5O62R.js +0 -3
  104. package/dist/chunk-ZT7M24XD.js +0 -1
  105. package/dist/editor/index.d.ts +0 -10
  106. package/dist/editor/index.js +0 -1
  107. package/dist/words-CD3WADyb.d.ts +0 -51
  108. /package/dist/{chunk-2PHD4L6A.js → chunk-OWBO4WKA.js} +0 -0
@@ -1 +1 @@
1
- import{DEFAULT_NODE_MENU_WORDS as e}from"../chunk-WK3AFPXY.js";export{canStep,fromItemSelector,parentStep,planDuplicate,planMove,planPaste,planRemove,planSetProps,planStep,toItemSelector,useNodeOps}from"../chunk-D2BCHTQR.js";import{TrashIcon as n,EyeIcon as t,EyeOffIcon as o,RenameIcon as p,PasteIcon as l,CopyIcon as c,MoveDownIcon as s,MoveUpIcon as a,DuplicateIcon as i,AddIcon as r,LayersIcon as u}from"../chunk-PI26YXYD.js";import"../chunk-KRXQM65X.js";import"../chunk-NKB3KVAB.js";import{jsx as h}from"react/jsx-runtime";function d(){let e=null;const n=/* @__PURE__ */new Set;return{get:()=>e,set(t){e=t;for(const e of[...n])e()},subscribe:e=>(n.add(e),()=>n.delete(e))}}var m={layer:{icon:/* @__PURE__ */h(u,{})},addInside:{icon:/* @__PURE__ */h(r,{})},duplicate:{icon:/* @__PURE__ */h(i,{})},moveUp:{icon:/* @__PURE__ */h(a,{})},moveDown:{icon:/* @__PURE__ */h(s,{})},copy:{icon:/* @__PURE__ */h(c,{}),shortcut:"⌘C"},cut:{icon:/* @__PURE__ */h(c,{}),shortcut:"⌘X"},paste:{icon:/* @__PURE__ */h(l,{}),shortcut:"⌘V"},rename:{icon:/* @__PURE__ */h(p,{})},hide:{icon:/* @__PURE__ */h(o,{})},show:{icon:/* @__PURE__ */h(t,{})},upLevel:{},delete:{icon:/* @__PURE__ */h(n,{}),danger:!0}};function v(n){const{actions:t,rows:o={},extras:p={},words:l=e}=n,c=e=>({...m[e],label:l[e],...o[e]}),s=(e,n,t)=>{const o=c(e),p={label:t??o.label??e,onClick:n};return o.icon&&(p.icon=o.icon),o.shortcut&&(p.shortcut=o.shortcut),o.danger&&(p.danger=!0),p},a=()=>{const e=c("layer"),t={label:e.label??l.layer,onClick:()=>{},children:n.layer.items};return e.icon&&(t.icon=e.icon),t},i=[],r=[],u=[],h=[],d=!!n.layer&&n.layer.items.length>1;if(d&&"pick"===(n.layer.group??"pick")&&i.push(a()),t.addInside&&r.push(s("addInside",t.addInside)),t.duplicate&&r.push(s("duplicate",t.duplicate)),t.moveUp&&r.push(s("moveUp",t.moveUp)),t.moveDown&&r.push(s("moveDown",t.moveDown)),t.copy&&r.push(s("copy",t.copy)),t.cut&&r.push(s("cut",t.cut)),t.paste){const e=c("paste").label??l.paste;r.push(s("paste",t.paste.run,l.pasteNamed({paste:e,label:t.paste.label})))}t.rename&&u.push(s("rename",t.rename)),t.hide&&u.push(t.hide.hidden?s("show",t.hide.run):s("hide",t.hide.run)),d&&"change"===n.layer.group&&u.push(a()),t.upLevel&&u.push(s("upLevel",t.upLevel)),t.delete&&h.push(s("delete",t.delete)),i.push(...p.pick??[]),r.push(...p.make??[]),u.push(...p.change??[]),h.push(...p.remove??[]);const v=[i,r,n.style??[],u,h].filter(e=>e.length>0),g=i.length+r.length+u.length+h.length===0,k=[{label:n.title,header:!0,onClick:()=>{}}];return g&&n.pinnedLine&&k.push({label:n.pinnedLine,header:!0,onClick:()=>{}}),v.forEach((e,t)=>{(t>0||g&&n.pinnedLine)&&k.push({label:"—",onClick:()=>{}}),k.push(...e)}),k}export{d as createNodeClipboard,v as nodeMenuItems};
1
+ import{DEFAULT_NODE_MENU_WORDS as e}from"../chunk-WK3AFPXY.js";export{canStep,fromItemSelector,parentStep,planDuplicate,planMove,planPaste,planRemove,planSetProps,planStep,toItemSelector,useNodeOps}from"../chunk-D2BCHTQR.js";import{TrashIcon as n,EyeIcon as t,EyeOffIcon as o,RenameIcon as p,PasteIcon as l,CopyIcon as c,MoveDownIcon as s,MoveUpIcon as a,DuplicateIcon as i,AddIcon as r,LayersIcon as u}from"../chunk-L5KW4HG5.js";import"../chunk-KRXQM65X.js";import"../chunk-NKB3KVAB.js";import{jsx as h}from"react/jsx-runtime";function d(){let e=null;const n=/* @__PURE__ */new Set;return{get:()=>e,set(t){e=t;for(const e of[...n])e()},subscribe:e=>(n.add(e),()=>n.delete(e))}}var m={layer:{icon:/* @__PURE__ */h(u,{})},addInside:{icon:/* @__PURE__ */h(r,{})},duplicate:{icon:/* @__PURE__ */h(i,{})},moveUp:{icon:/* @__PURE__ */h(a,{})},moveDown:{icon:/* @__PURE__ */h(s,{})},copy:{icon:/* @__PURE__ */h(c,{}),shortcut:"⌘C"},cut:{icon:/* @__PURE__ */h(c,{}),shortcut:"⌘X"},paste:{icon:/* @__PURE__ */h(l,{}),shortcut:"⌘V"},rename:{icon:/* @__PURE__ */h(p,{})},hide:{icon:/* @__PURE__ */h(o,{})},show:{icon:/* @__PURE__ */h(t,{})},upLevel:{},delete:{icon:/* @__PURE__ */h(n,{}),danger:!0}};function v(n){const{actions:t,rows:o={},extras:p={},words:l=e}=n,c=e=>({...m[e],label:l[e],...o[e]}),s=(e,n,t)=>{const o=c(e),p={label:t??o.label??e,onClick:n};return o.icon&&(p.icon=o.icon),o.shortcut&&(p.shortcut=o.shortcut),o.danger&&(p.danger=!0),p},a=()=>{const e=c("layer"),t={label:e.label??l.layer,onClick:()=>{},children:n.layer.items};return e.icon&&(t.icon=e.icon),t},i=[],r=[],u=[],h=[],d=!!n.layer&&n.layer.items.length>1;if(d&&"pick"===(n.layer.group??"pick")&&i.push(a()),t.addInside&&r.push(s("addInside",t.addInside)),t.duplicate&&r.push(s("duplicate",t.duplicate)),t.moveUp&&r.push(s("moveUp",t.moveUp)),t.moveDown&&r.push(s("moveDown",t.moveDown)),t.copy&&r.push(s("copy",t.copy)),t.cut&&r.push(s("cut",t.cut)),t.paste){const e=c("paste").label??l.paste;r.push(s("paste",t.paste.run,l.pasteNamed({paste:e,label:t.paste.label})))}t.rename&&u.push(s("rename",t.rename)),t.hide&&u.push(t.hide.hidden?s("show",t.hide.run):s("hide",t.hide.run)),d&&"change"===n.layer.group&&u.push(a()),t.upLevel&&u.push(s("upLevel",t.upLevel)),t.delete&&h.push(s("delete",t.delete)),i.push(...p.pick??[]),r.push(...p.make??[]),u.push(...p.change??[]),h.push(...p.remove??[]);const v=[i,r,n.style??[],u,h].filter(e=>e.length>0),g=i.length+r.length+u.length+h.length===0,k=[{label:n.title,header:!0,onClick:()=>{}}];return g&&n.pinnedLine&&k.push({label:n.pinnedLine,header:!0,onClick:()=>{}}),v.forEach((e,t)=>{(t>0||g&&n.pinnedLine)&&k.push({label:"—",onClick:()=>{}}),k.push(...e)}),k}export{d as createNodeClipboard,v as nodeMenuItems};
@@ -1,6 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import { W as WordFit } from '../wordFit-D4S36PvB.js';
4
+ import { P as PanelWords } from '../words-BGrHZAJJ.js';
4
5
  export { a as SETTINGS_BUCKETS, S as SettingsBucket } from '../buckets-CuLM47h9.js';
5
6
 
6
7
  /**
@@ -367,9 +368,10 @@ interface SettingsFieldProps {
367
368
  /** Set when the control is a single form element, so the label points at it. */
368
369
  htmlFor?: string;
369
370
  /**
370
- * A trailing control on the label row — a reset dot, a badge, or the SWITCH
371
- * of a boolean row (card 8801, Option A: a yes-or-no setting is one line, not
372
- * two, so the switch takes the spot a value like "34 px" normally sits in).
371
+ * A trailing control on the label row — `SettingsDefaultReset` (Default /
372
+ * Reset), or the SWITCH of a boolean row (card 8801, Option A: a yes-or-no
373
+ * setting is one line, not two, so the switch takes the spot a value like
374
+ * "34 px" normally sits in).
373
375
  */
374
376
  action?: ReactNode;
375
377
  /**
@@ -384,6 +386,45 @@ interface SettingsFieldProps {
384
386
  children?: ReactNode;
385
387
  className?: string;
386
388
  }
389
+ /**
390
+ * `SettingsDefaultReset` — the end of a label line: a ↺ button while the value
391
+ * is changed, an empty 22px slot while it follows its default (owner
392
+ * 2026-10-06; option E, final 2026-10-07).
393
+ */
394
+ interface SettingsDefaultResetProps {
395
+ /** The field's visible label. The ↺ button is named after it ("Reset Gap"). */
396
+ label: string;
397
+ /** Is the value changed from its default? The host's to say. */
398
+ changed: boolean;
399
+ /** Clear the value back to its default. The part writes nothing itself. */
400
+ onReset: () => void;
401
+ /**
402
+ * What the default IS, in the host's words — "24px from Site styles". The ↺
403
+ * says it: in its tooltip ("Reset Gap (back to 24px from Site styles)") and
404
+ * as its accessible description, while its NAME stays "Reset Gap" (GG
405
+ * 2026-10-07, E2). Read it live; a baked value goes stale. Nothing shows it
406
+ * while the setting is unchanged: the slot is empty then.
407
+ */
408
+ detail?: string;
409
+ /** Read-only (a sent campaign): ↺ is drawn, and cannot be pressed. */
410
+ disabled?: boolean;
411
+ /**
412
+ * Rare: something to press while the setting is UNCHANGED, for a row a
413
+ * merchant cannot leave by hand. The website's type sizes are the case (GG
414
+ * 2026-10-06, Q3): their default can be a responsive `clamp()` no slider
415
+ * position stores, so one press keeps the section's own built-in size.
416
+ * `icon` is drawn in the 22px slot; `title` is its name and its tooltip.
417
+ * Left out, an unchanged row draws nothing — the usual case.
418
+ */
419
+ defaultAction?: {
420
+ onPress: () => void;
421
+ title: string;
422
+ icon: ReactNode;
423
+ };
424
+ /** The host's words, from `useWords('panel', …)`. English when left out. */
425
+ words?: Partial<Pick<PanelWords, 'followsDefault' | 'reset' | 'resetName' | 'backToDefault' | 'resetTitle'>>;
426
+ className?: string;
427
+ }
387
428
  /**
388
429
  * A switch has no text of its own, so without one of these it announces
389
430
  * "switch, on" and nothing else. The union makes an unnamed switch a COMPILE
@@ -901,6 +942,44 @@ declare function SettingsField({ label, labelId, icon, value, hint, changed, htm
901
942
  */
902
943
  declare function SettingsSwitch({ checked, onChange, disabled, id, ariaLabel, ariaLabelledBy, className, }: SettingsSwitchProps): react.JSX.Element;
903
944
 
945
+ /**
946
+ * The end of a setting's label line: a ↺ button once the setting is changed,
947
+ * NOTHING while it is not. ONE part, both editors.
948
+ *
949
+ * Owner, 2026-10-06: the two editors said "follows its default / put it back"
950
+ * five ways (the website's "Inherits · Site" chip and blue reset dot, the
951
+ * email's "Default" mark, "Reset" link and "Reset to default" text), and it
952
+ * became one part. Option E, final 2026-10-07 (mockup
953
+ * https://claude.ai/artifact/KATfHhLK7wogfTD84Manox), gave it its look:
954
+ *
955
+ * changed the set's `revert` icon (↺, "Revert to inherited") in a 22px
956
+ * button, accent; its name "Reset <setting>", its tooltip that
957
+ * plus what it goes back to when the host says ("(back to 24px
958
+ * from Site styles)", also its description);
959
+ * unchanged nothing at all: the row's grey value already says it is the
960
+ * default. The 22px slot stays, empty and out of the tab order,
961
+ * so every row's end lines up.
962
+ *
963
+ * It rides `SettingsField`'s `action` slot; `SettingsField` leaves its name
964
+ * alone (only a switch is named after the field).
965
+ *
966
+ * FOCUS AFTER A PRESS. Reset turns the button into the empty slot, which cannot
967
+ * hold focus, so a keyboard user would fall back to the top of the page. The
968
+ * press hands focus to the row's own control (its slider, box or swatch) first.
969
+ * That is read off the event's own element, never a global, so the module stays
970
+ * a leaf.
971
+ *
972
+ * `defaultAction` is the one row with something to press while unchanged: the
973
+ * website's type sizes, whose default can be a responsive `clamp()` no slider
974
+ * stores, keep ONE press to the section's own built-in size (a feature is
975
+ * never cut to fit a look). It draws the host's icon in the same 22px slot.
976
+ *
977
+ * CONTROLLED and hook-free like the rest of the panel: `changed` is the host's,
978
+ * and a press only asks the host to clear. The words are handed in (`words`),
979
+ * because a leaf never reads the strings provider.
980
+ */
981
+ declare function SettingsDefaultReset({ label, changed, onReset, detail, disabled, defaultAction, words, className, }: SettingsDefaultResetProps): react.JSX.Element;
982
+
904
983
  /**
905
984
  * A DRILL-IN ROW — a name, a one-line preview, and a chevron (card 8819).
906
985
  *
@@ -1085,4 +1164,4 @@ declare function SettingsCorners({ label, value, corners, onChange, id, classNam
1085
1164
  */
1086
1165
  declare function SettingsAction({ label, onPress, disabled, note, done, doneLabel, icon, id, className, }: SettingsActionProps): react.JSX.Element;
1087
1166
 
1088
- export { SettingsAction, type SettingsActionBaseProps, type SettingsActionNote, type SettingsActionProps, type SettingsCornerPoint, SettingsCorners, type SettingsCornersProps, SettingsDrill, type SettingsDrillProps, SettingsField, type SettingsFieldProps, SettingsGroup, SettingsGroupHead, type SettingsGroupHeadProps, type SettingsGroupProps, SettingsGroupSub, type SettingsGroupSubProps, SettingsPlacement, type SettingsPlacementPoint, type SettingsPlacementProps, SettingsSegmented, type SettingsSegmentedFit, type SettingsSegmentedOption, type SettingsSegmentedProps, SettingsSwitch, type SettingsSwitchBaseProps, type SettingsSwitchLabel, type SettingsSwitchProps, type SettingsTabItem, SettingsTabs, type SettingsTabsProps };
1167
+ export { SettingsAction, type SettingsActionBaseProps, type SettingsActionNote, type SettingsActionProps, type SettingsCornerPoint, SettingsCorners, type SettingsCornersProps, SettingsDefaultReset, type SettingsDefaultResetProps, SettingsDrill, type SettingsDrillProps, SettingsField, type SettingsFieldProps, SettingsGroup, SettingsGroupHead, type SettingsGroupHeadProps, type SettingsGroupProps, SettingsGroupSub, type SettingsGroupSubProps, SettingsPlacement, type SettingsPlacementPoint, type SettingsPlacementProps, SettingsSegmented, type SettingsSegmentedFit, type SettingsSegmentedOption, type SettingsSegmentedProps, SettingsSwitch, type SettingsSwitchBaseProps, type SettingsSwitchLabel, type SettingsSwitchProps, type SettingsTabItem, SettingsTabs, type SettingsTabsProps };
@@ -1,16 +1,18 @@
1
- export{SETTINGS_BUCKETS,SettingsField,SettingsGroup,SettingsSwitch,SettingsTabs}from"../chunk-67VZRQLG.js";import"../chunk-7A7O2JWQ.js";export{SettingsSegmented}from"../chunk-QB3BZIRA.js";import"../chunk-BZ5ASXOL.js";import{jsx as e,jsxs as a}from"react/jsx-runtime";function l({title:a,level:l=3,id:s,className:i}){/* @__PURE__ */
2
- return e(`h${l}`,{id:s,className:i?`es-group-head ${i}`:"es-group-head",children:a})}function s({title:a,level:l=4,id:s,className:i}){/* @__PURE__ */
3
- return e(`h${l}`,{id:s,className:i?`es-group-sub ${i}`:"es-group-sub",children:a})}function i({name:l,preview:s,offPage:i,status:n,onOpen:r,id:t,className:c}){const d=null!=s;/* @__PURE__ */
4
- return a("button",{type:"button",id:t,className:c?`es-drill ${c}`:"es-drill",onClick:r,children:[
5
- /* @__PURE__ */a("span",{className:"es-drill-text",children:[
6
- /* @__PURE__ */e("span",{className:"es-drill-name",children:l}),d?/* @__PURE__ */e("span",{className:i?"es-drill-preview is-offpage":"es-drill-preview",children:s}):null]}),n?/* @__PURE__ */e("span",{className:"es-drill-status",children:n}):null,
7
- /* @__PURE__ */e("span",{className:"es-drill-chev","aria-hidden":"true"})]})}function n({label:a,value:l,points:s,onChange:i,id:n,className:r}){/* @__PURE__ */
8
- return e("div",{id:n,className:"es-placement"+(r?` ${r}`:""),role:"radiogroup","aria-label":a,children:s.map(a=>{const s=l===a.value,n=!0===a.disabled;/* @__PURE__ */
9
- return e("button",{type:"button",role:"radio","aria-checked":s,"aria-label":a.label,"aria-disabled":n||void 0,disabled:n,title:a.title??a.label,className:`es-placement-cell${s?" is-active":""}${n?" is-off":""}`,onClick:()=>i(a.value),children:a.icon?/* @__PURE__ */e("span",{className:"es-placement-icon","aria-hidden":"true",children:a.icon}):/* @__PURE__ */e("span",{className:"es-placement-dot"})},a.value)})})}function r({label:l,value:s,corners:i,onChange:n,id:r,className:t}){/* @__PURE__ */
10
- return a("div",{id:r,className:"es-corners"+(t?` ${t}`:""),role:"group","aria-label":l,children:[
11
- /* @__PURE__ */e("span",{className:"es-corners-frame","aria-hidden":"true"}),i.map(a=>{const l=s.includes(a.value),i=!0===a.disabled;/* @__PURE__ */
12
- return e("button",{type:"button","aria-pressed":l,"aria-label":a.label,"aria-disabled":i||void 0,disabled:i,title:a.title??a.label,className:`es-corners-cell es-corners-${a.value}${l?" is-on":""}${i?" is-off":""}`,onClick:()=>n(l?s.filter(e=>e!==a.value):[...s,a.value]),children:/* @__PURE__ */e("span",{className:"es-corners-mark","aria-hidden":"true"})},a.value)})]})}function t({label:l,onPress:s,disabled:i,note:n,done:r,doneLabel:t,icon:c,id:d,className:o}){const u=void 0===t?l:t,m=r?u:l,p=null!=n,h=p&&d?`${d}-note`:void 0;/* @__PURE__ */
13
- return a("div",{className:o?`es-action-wrap ${o}`:"es-action-wrap",children:[
14
- /* @__PURE__ */a("button",{type:"button",id:d,className:r?"es-action is-done":"es-action",disabled:i,"aria-describedby":h,onClick:s,children:[c?/* @__PURE__ */e("span",{className:"es-action-icon","aria-hidden":"true",children:c}):null,
15
- /* @__PURE__ */e("span",{className:"es-action-label",children:m})]}),p?/* @__PURE__ */e("p",{id:h,className:"es-action-note",children:n}):null,
16
- /* @__PURE__ */e("span",{className:"es-action-live",role:"status","aria-live":"polite",children:r?u:null})]})}export{t as SettingsAction,r as SettingsCorners,i as SettingsDrill,l as SettingsGroupHead,s as SettingsGroupSub,n as SettingsPlacement};
1
+ export{SETTINGS_BUCKETS,SettingsField,SettingsGroup,SettingsTabs}from"../chunk-ZNS7727Y.js";import{DEFAULT_PANEL_WORDS as e}from"../chunk-QTLAVDJE.js";export{SettingsSegmented,SettingsSwitch}from"../chunk-P6O363EE.js";import"../chunk-BZ5ASXOL.js";import{RevertIcon as a}from"../chunk-L5KW4HG5.js";import{jsx as l,jsxs as s}from"react/jsx-runtime";function i({title:e,level:a=3,id:s,className:i}){/* @__PURE__ */
2
+ return l(`h${a}`,{id:s,className:i?`es-group-head ${i}`:"es-group-head",children:e})}function n({title:e,level:a=4,id:s,className:i}){/* @__PURE__ */
3
+ return l(`h${a}`,{id:s,className:i?`es-group-sub ${i}`:"es-group-sub",children:e})}function t({label:s,changed:i,onReset:n,detail:t,disabled:r,defaultAction:d,words:o,className:u}){const p={...e,...o},m=["es-default-reset"];if(i&&m.push("is-changed"),u&&m.push(u),!i&&d)return m.push("is-pressable"),/* @__PURE__ */l("button",{type:"button",className:m.join(" "),"aria-label":d.title,title:d.title,disabled:r,onClick:d.onPress,children:d.icon});if(!i)/* @__PURE__ */
4
+ return l("span",{className:m.join(" "),"aria-hidden":"true"});const b=p.resetName({label:s});/* @__PURE__ */
5
+ return l("button",{type:"button",className:m.join(" "),"aria-label":b,"aria-description":t||void 0,title:t?p.resetTitle({label:s,detail:t}):b,disabled:r,onClick:e=>{n(),function(e){const a=e.currentTarget.closest(".es-field"),l=a?.querySelector(c(".es-field-ctl"))??a?.querySelector(c(".es-field-head"));l?.focus()}(e)},children:/* @__PURE__ */l(a,{size:15})})}var r=['input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])","button:not([disabled]):not(.es-default-reset)",'[tabindex]:not([tabindex="-1"])'].join(", "),c=e=>r.split(", ").map(a=>`${e} ${a}`).join(", ");function d({name:e,preview:a,offPage:i,status:n,onOpen:t,id:r,className:c}){const d=null!=a;/* @__PURE__ */
6
+ return s("button",{type:"button",id:r,className:c?`es-drill ${c}`:"es-drill",onClick:t,children:[
7
+ /* @__PURE__ */s("span",{className:"es-drill-text",children:[
8
+ /* @__PURE__ */l("span",{className:"es-drill-name",children:e}),d?/* @__PURE__ */l("span",{className:i?"es-drill-preview is-offpage":"es-drill-preview",children:a}):null]}),n?/* @__PURE__ */l("span",{className:"es-drill-status",children:n}):null,
9
+ /* @__PURE__ */l("span",{className:"es-drill-chev","aria-hidden":"true"})]})}function o({label:e,value:a,points:s,onChange:i,id:n,className:t}){/* @__PURE__ */
10
+ return l("div",{id:n,className:"es-placement"+(t?` ${t}`:""),role:"radiogroup","aria-label":e,children:s.map(e=>{const s=a===e.value,n=!0===e.disabled;/* @__PURE__ */
11
+ return l("button",{type:"button",role:"radio","aria-checked":s,"aria-label":e.label,"aria-disabled":n||void 0,disabled:n,title:e.title??e.label,className:`es-placement-cell${s?" is-active":""}${n?" is-off":""}`,onClick:()=>i(e.value),children:e.icon?/* @__PURE__ */l("span",{className:"es-placement-icon","aria-hidden":"true",children:e.icon}):/* @__PURE__ */l("span",{className:"es-placement-dot"})},e.value)})})}function u({label:e,value:a,corners:i,onChange:n,id:t,className:r}){/* @__PURE__ */
12
+ return s("div",{id:t,className:"es-corners"+(r?` ${r}`:""),role:"group","aria-label":e,children:[
13
+ /* @__PURE__ */l("span",{className:"es-corners-frame","aria-hidden":"true"}),i.map(e=>{const s=a.includes(e.value),i=!0===e.disabled;/* @__PURE__ */
14
+ return l("button",{type:"button","aria-pressed":s,"aria-label":e.label,"aria-disabled":i||void 0,disabled:i,title:e.title??e.label,className:`es-corners-cell es-corners-${e.value}${s?" is-on":""}${i?" is-off":""}`,onClick:()=>n(s?a.filter(a=>a!==e.value):[...a,e.value]),children:/* @__PURE__ */l("span",{className:"es-corners-mark","aria-hidden":"true"})},e.value)})]})}function p({label:e,onPress:a,disabled:i,note:n,done:t,doneLabel:r,icon:c,id:d,className:o}){const u=void 0===r?e:r,p=t?u:e,m=null!=n,b=m&&d?`${d}-note`:void 0;/* @__PURE__ */
15
+ return s("div",{className:o?`es-action-wrap ${o}`:"es-action-wrap",children:[
16
+ /* @__PURE__ */s("button",{type:"button",id:d,className:t?"es-action is-done":"es-action",disabled:i,"aria-describedby":b,onClick:a,children:[c?/* @__PURE__ */l("span",{className:"es-action-icon","aria-hidden":"true",children:c}):null,
17
+ /* @__PURE__ */l("span",{className:"es-action-label",children:p})]}),m?/* @__PURE__ */l("p",{id:b,className:"es-action-note",children:n}):null,
18
+ /* @__PURE__ */l("span",{className:"es-action-live",role:"status","aria-live":"polite",children:t?u:null})]})}export{p as SettingsAction,u as SettingsCorners,t as SettingsDefaultReset,d as SettingsDrill,i as SettingsGroupHead,n as SettingsGroupSub,o as SettingsPlacement};
@@ -330,61 +330,38 @@
330
330
  box-shadow: 0 0 0 3px var(--es-accent-ring);
331
331
  }
332
332
 
333
- /* THE CHOSEN CHIP IS THE DARKEST THING IN THE ROW (card 66302).
334
-
335
- IT WAS A RAISED WHITE CHIP, AND THAT WAS NOT A MISTAKE. Card 66138 put white
336
- on the grey track with a soft lift, and Lewis picked that look himself from
337
- six treatments. He picked it BY EYE, AT A WIDTH WHERE THE WORDS WERE STILL
338
- THERE — which is the whole reason this is a revision and not a correction.
339
-
340
- WHAT CHANGED IS THE CONDITION, TWICE.
341
-
342
- First the words went. A four-tab strip is already wordless below 200px, and
343
- the panel's drag band bottoms out at 181px, so that state is live in the
344
- editor today; card 66246 then made the shop's Weight row show one word of
345
- four at the DEFAULT panel and none at the narrow end. A chip that used to sit
346
- beside a word became the only thing saying which option is set.
347
-
348
- Then the second mark went, and nobody noticed. Card 66248 moved the strip
349
- into this package and the quiet label darkened from the muted grey to
350
- `--es-text-secondary`. That darkening is right on its own terms — it is card
351
- 66138's AA fix, 4.39:1 to 9.37:1 on the track — but it also cut the
352
- chosen-vs-quiet GLYPH contrast from 3.67:1 to 1.72:1. The strip lost the one
353
- state cue that was already above 3:1, and the change was described as
354
- cosmetic when it merged.
355
-
356
- So the raised white chip was left carrying the whole message alone, at
357
- 1.10:1 against its own track, where WCAG 1.4.11 asks 3:1 of anything
358
- identifying a control's STATE.
359
-
360
- WHY DARK AND NOT A RING. Four treatments were drawn and measured for Lewis;
361
- two of the routes were closed by arithmetic before he saw them (darkening the
362
- track drops the quiet label to 3.40:1 and fails AA; pushing the glyph delta
363
- only reaches 3:1 by putting that label back where 66138 moved it FROM). Of
364
- what was left, this is the one that survives the DISABLED state:
365
- `.es-segs[data-disabled]` fades the strip to 0.5 over the panel, and a ring
366
- at 4.39:1 composites down to 1.89:1 while this holds 3.24:1. A cue that only
367
- works while the control is live is a cue with a hole in it.
368
-
369
- ⚠️ THE LIFT STAYS, AND IT IS NO LONGER THE MESSAGE. `--es-raised-shadow`
370
- still seats the chip on the track. What it must not go back to being is the
371
- thing telling the two states apart — a shadow is not a colour, so no
372
- contrast ratio can score it, and that is exactly how this got to 1.10:1
373
- without any guard noticing. `tests/panel-chip-contrast.test.ts` pins the
374
- RATIO and not this colour, so a better answer is free to replace it. */
333
+ /* THE CHOSEN CHIP IS BLUE (Lewis, 2026-10-06): 「用蓝色的背景, 不要黑色的了」.
334
+
335
+ Said while the shop's hand-built "pick one of 2-3" rungs were merged into
336
+ this control. It was `--es-text`, near-black, since card 66302; before that a
337
+ raised white chip (card 66138). Both editors draw every segmented control and
338
+ the settings tab strip from this one rule, so this is the whole change.
339
+
340
+ THE NUMBERS STILL HOLD, which is why the colour could move at all. Card 66302
341
+ made the chip the ONLY state cue once the words drop at the narrow end, and
342
+ WCAG 1.4.11 asks 3:1 of it: `--es-accent` on `--es-track-bg` is
343
+ 4.70:1, and the white word on it is 5.17:1 (1.4.3 asks 4.5:1 at 12px).
344
+
345
+ ⚠️ THE LIFT STAYS, AND IT IS NOT THE MESSAGE. `--es-raised-shadow` seats the
346
+ chip on the track; the colour is what tells the states apart, because a
347
+ shadow cannot be scored and that is how this once sat at 1.10:1 unnoticed.
348
+ `tests/panel-chip-contrast.test.ts` pins the ratios AND, since the ruling,
349
+ the colour itself. */
375
350
  .es-tab.is-active,
376
351
  .es-seg.is-active {
377
- background: var(--es-text);
352
+ background: var(--es-accent);
378
353
  color: var(--es-on-accent);
379
354
  box-shadow: var(--es-raised-shadow);
380
355
  border-radius: 6px;
381
356
  }
382
357
 
383
- /* Focused AND chosen: keep the lift, or the chip drops flat the moment a
384
- keyboard reaches it. */
358
+ /* Focused AND chosen. The quiet chip's ring is a translucent accent wash, and
359
+ laid against a chip that is itself the accent it reads as the chip growing,
360
+ not as focus. So this ring stands OFF the chip: a 2px gap in the panel
361
+ colour, then a solid accent ring — the blue chip, a white gap, a blue line. */
385
362
  .es-tab.is-active:focus-visible,
386
363
  .es-seg.is-active:focus-visible {
387
- box-shadow: var(--es-raised-shadow), 0 0 0 3px var(--es-accent-ring);
364
+ box-shadow: 0 0 0 2px var(--es-panel), 0 0 0 4px var(--es-accent);
388
365
  }
389
366
 
390
367
  .es-tab-badge {
@@ -689,26 +666,36 @@
689
666
  merchant's answer — a pressed chip faded to the same grey as the ones beside
690
667
  it stops saying which answer that was.
691
668
 
692
- ⚠️ THIS COLOUR BELONGS TO THE CHIP'S GROUND, NOT TO THE TRACK (card 66302).
693
- It was `--es-text-secondary`, which was right while the chip was white:
694
- 10.31:1 on it. The moment the chip went dark that same rule drew
695
- `--es-text-secondary` on `--es-text` — 1.72:1, an unreadable label on a
696
- control that had just been made MORE visible. Nothing about the rule changed; what it sat on moved underneath
697
- it. So it reads `--es-on-accent` for the same reason the enabled chip does,
698
- and the strip says which option is out of force through the track's fade and
699
- its quiet siblings rather than by dimming the one word still worth reading. */
700
- .es-seg:disabled.is-active { color: var(--es-on-accent); }
669
+ GREY, NOT BLUE, AND NOT FADED (2026-10-06). The live chip is the accent now,
670
+ and blue is the colour that says "this is in force" — so an answer out of
671
+ force drops to `--es-muted`. The arithmetic decided the rest: the blue chip
672
+ faded to half over the panel is 2.04:1 against its faded track, under the
673
+ 3:1 a state cue needs. `--es-muted` with no fade is 4.39:1 on the track and
674
+ its white word 4.83:1. That is why the whole strip no longer fades (below):
675
+ any fade took this chip under 3:1 again.
676
+
677
+ ⚠️ THE WORD COLOUR BELONGS TO THE CHIP'S GROUND, NOT TO THE TRACK (card
678
+ 66302): a label written for one ground went unreadable when the ground moved
679
+ under it. So the ground and the word are declared together, here. */
680
+ .es-seg:disabled.is-active {
681
+ background: var(--es-muted);
682
+ color: var(--es-on-accent);
683
+ }
701
684
 
702
685
  /* And none of them answers the pointer any more: the hover rule above would
703
686
  otherwise keep lighting a segment that cannot be chosen. */
704
687
  .es-seg:disabled:hover:not(.is-active) { color: var(--es-disabled); }
705
688
 
706
- /* THE WHOLE CONTROL, when every option went at once — one statement instead of
707
- three identically faded chips. The track is the part that says "these buttons
708
- are one control", so it is the right place to say the control is not in force.
709
- A single option out of force leaves the track alone, because the strip still
710
- is. */
711
- .es-segs[data-disabled] { opacity: 0.5; cursor: not-allowed; }
689
+ /* THE WHOLE CONTROL, when every option went at once. Every button is then
690
+ `:disabled`, so the quiet words are already `--es-disabled` and the chosen
691
+ chip is already grey — the strip says "out of force" through them.
692
+
693
+ IT USED TO FADE TO 0.5, and that fade is gone on purpose (2026-10-06). An
694
+ opacity on the track composites the chosen chip with it, and no chip colour
695
+ the ruling allows survives that above 3:1: blue faded is 2.04:1, the grey
696
+ above faded is about 2:1. The chip is the one thing a disabled strip must
697
+ still say clearly, so the fade went rather than the chip. */
698
+ .es-segs[data-disabled] { cursor: not-allowed; }
712
699
 
713
700
  /* ── a group: the soft pill row that folds ─────────────────────────────────── */
714
701
 
@@ -897,9 +884,23 @@ button.es-group-head:hover { background: var(--es-chip-bg); }
897
884
 
898
885
  .es-field.is-changed .es-field-label { color: var(--es-accent-text); }
899
886
 
887
+ /* The same cue, read off the row itself: a row whose Default / Reset part says
888
+ Reset is changed, whether or not its host passed `changed`. A host that draws
889
+ the part inside a component of its own (it reads a live value through a
890
+ hook) is invisible to SettingsField, and without this its label stayed grey
891
+ beside a Reset — measured on the website's section Width row. */
892
+ .es-field:has(> .es-field-head > .es-default-reset.is-changed) > .es-field-head .es-field-label {
893
+ color: var(--es-accent-text);
894
+ }
895
+
900
896
  .es-field-value {
901
897
  margin-left: auto;
902
898
  font-size: 12px;
899
+ /* The part's own 16px, and the head's min-height: so a row is one height
900
+ whether its value is drawn or not. Left to the host's line-height (18px in
901
+ the website editor) a press on Reset, which empties the value, moved every
902
+ row below it by 1.5px. */
903
+ line-height: 16px;
903
904
  color: var(--es-text);
904
905
  font-variant-numeric: tabular-nums;
905
906
  }
@@ -911,14 +912,86 @@ button.es-group-head:hover { background: var(--es-chip-bg); }
911
912
  min-width: 0;
912
913
  }
913
914
 
915
+ /* The hint sits FLUSH LEFT, on the same edge as the row's icon and control —
916
+ not indented under the label's words (owner ruling, 2026-10-06; it was
917
+ 24px, glyph + gap, until then). `tests/panel-hint-flush-left` holds it. */
914
918
  .es-field-hint {
915
919
  margin: 8px 0 0;
916
- padding-left: 24px;
917
920
  font-size: 11px;
918
921
  line-height: 1.45;
919
922
  color: var(--es-muted);
920
923
  }
921
924
 
925
+ /* ── Default / Reset: the end of a label line ─────────────────────────────────
926
+ Owner 2026-10-06: ONE part puts a changed setting back. Option E, final
927
+ 2026-10-07: a ↺ icon button while the setting is changed, NOTHING while it is
928
+ not (the row's grey value already says it is the default).
929
+
930
+ ONE FIXED 22px SLOT IN BOTH STATES. The unchanged state is an empty span of
931
+ the same box, so every row's end lines up whether it can be reset or not.
932
+ It replaced PR 154's two hidden words, which sized the box to the wider of
933
+ "Default" and "Reset": there is no word to size for now.
934
+
935
+ Straight after the label the slot pushes itself to the row's end. After a
936
+ value it sits 4px from it (the head's 8px gap less 4, option E). After
937
+ anything else on the line — a colour row's readout — that thing has already
938
+ been pushed right; pick.css sets the gap there. A second `auto` would split
939
+ the free space and strand the slot mid-row (PR 163: 295px apart). */
940
+ .es-default-reset {
941
+ appearance: none;
942
+ -webkit-appearance: none;
943
+ box-sizing: border-box;
944
+ flex: none;
945
+ display: inline-flex;
946
+ align-items: center;
947
+ justify-content: center;
948
+ width: 22px;
949
+ height: 22px;
950
+ margin: 0;
951
+ padding: 0;
952
+ border: 0;
953
+ border-radius: 6px;
954
+ background: transparent;
955
+ color: var(--es-muted);
956
+ }
957
+
958
+ .es-default-reset svg {
959
+ display: block;
960
+ width: 15px;
961
+ height: 15px;
962
+ }
963
+
964
+ .es-default-reset.is-changed {
965
+ color: var(--es-accent-text);
966
+ cursor: pointer;
967
+ }
968
+
969
+ .es-default-reset.is-changed:hover { background: var(--es-hover); }
970
+
971
+ .es-default-reset.is-changed:disabled {
972
+ color: var(--es-disabled);
973
+ background: transparent;
974
+ cursor: default;
975
+ }
976
+
977
+ .es-default-reset.is-pressable { cursor: pointer; }
978
+ .es-default-reset.is-pressable:hover { background: var(--es-hover); color: var(--es-text-secondary); }
979
+ .es-default-reset.is-pressable:disabled { color: var(--es-disabled); background: transparent; cursor: default; }
980
+
981
+ .es-default-reset:focus-visible {
982
+ outline: 2px solid var(--es-accent-ring);
983
+ outline-offset: 1px;
984
+ }
985
+
986
+ .es-field-name + .es-default-reset { margin-left: auto; }
987
+
988
+ /* THE GREY VALUE IS THE "DEFAULT" WORD NOW (option E): a row whose slot is
989
+ empty draws its value grey, and the value takes the text colour once the
990
+ setting is changed. Scoped to rows that carry the part, so a value on a row
991
+ with nothing to reset keeps its colour. */
992
+ .es-field:has(> .es-field-head > span.es-default-reset) .es-field-value { color: var(--es-muted); }
993
+ .es-field-value + .es-default-reset { margin-left: -4px; }
994
+
922
995
  /* A boolean row is ONE line (card 8801, Option A). The switch rides the label
923
996
  line in the `action` slot, so there is no control row under it — and with no
924
997
  control row, the label line's 7px bottom margin would be a gap to nothing.
@@ -1,4 +1,5 @@
1
1
  import * as react from 'react';
2
+ import { ReactNode } from 'react';
2
3
  import { P as PickWords } from '../words-is_Vy6hn.js';
3
4
 
4
5
  /** One colour the site's theme names — offered first, by name. */
@@ -24,6 +25,28 @@ type ColourPickerProps = {
24
25
  * caption that IS the value's hex is no word, and the row's hex box stays.
25
26
  */
26
27
  caption?: string;
28
+ /**
29
+ * The colour IN FORCE while `value` is `''`: the setting has none of its own
30
+ * and follows a style (the email's body text, `#333333`). The swatch paints
31
+ * it (`is-inherited`, not the not-set look), the row prints `caption` or
32
+ * else that colour's hex in grey (no word: the row's Default part already
33
+ * says the state, one idea one word, GG 2026-10-07) — in the hex BOX, so a
34
+ * press selects it all for copying (GG for Lewis, 2026-10-07: the colour a
35
+ * row follows is the one most often copied); and the window starts
36
+ * from it with its hex as a placeholder. ⚠️ Nothing is written until the merchant moves something:
37
+ * showing the colour a setting follows must not pin it. Left out, or `''`,
38
+ * an empty value is "Not set", exactly as before.
39
+ */
40
+ inherited?: string;
41
+ /**
42
+ * A control drawn at the END of the row, after the hex: the panel's Default /
43
+ * Reset part (`SettingsDefaultReset`, Lewis 2026-10-06). ⚠️ INSIDE the row,
44
+ * not after the picker: a line that holds the picker wraps item by item, and
45
+ * a part beside the picker could drop onto a line of its own at a narrow
46
+ * panel (measured at 220px on a short label) while the swatch stayed above.
47
+ * In the row, the swatch, the hex and the part wrap as one.
48
+ */
49
+ after?: ReactNode;
27
50
  /** The swatch's DOM id, for a row whose own `<label for>` points at it. */
28
51
  id?: string;
29
52
  readOnly?: boolean;
@@ -52,8 +75,61 @@ type ColourPickerProps = {
52
75
  * The hex box is always a box you can type into — pasting a brand colour
53
76
  * costs no clicks — live on the keystroke that makes it a colour, and put back
54
77
  * to what is stored on Enter, Escape or leaving it.
78
+ *
79
+ * ONE LINE (Lewis, 2026-10-07, option E, final v9). In a line that holds it
80
+ * (`.es-field-head`, `.es-pick-line`) the label, the swatch, the hex and the
81
+ * host's `after` never wrap: short of room the label fades at its end (it
82
+ * keeps 56px), then the hex (it keeps 36px) — pick.css. What is cut is
83
+ * MEASURED here (`data-clipped` turns the fade on; text that fits is never
84
+ * faded), and over a cut label or hex a small dark tag shows the whole text.
85
+ * A press on the hex edits it IN PLACE: pick.css widens it to seven
86
+ * characters from its own left edge, never past the row's end
87
+ * (`--es-pick-edit-room`, measured here), and the `after` part steps aside
88
+ * only when that box reaches it (`data-editing="over"`). The swatch and the
89
+ * label never move. The accessible names are whole throughout: the fade and
90
+ * the tag are for the eye.
91
+ */
92
+ declare function ColourPicker({ value, onChange, label, theme, caption, inherited, after, id: swatchId, readOnly, words, }: ColourPickerProps): react.JSX.Element;
93
+ type ColourWindowProps = {
94
+ /** The colour, `#rrggbb`, or `''` while there is none. */
95
+ value: string;
96
+ /** Live, as the colour moves: one `#rrggbb` from every way in. */
97
+ onChange: (next: string) => void;
98
+ /** The colour's name: the window is "<label> colour", its hex box "<label> hex code". */
99
+ label: string;
100
+ /** The theme's colours, offered first. */
101
+ theme?: readonly ThemeColour[];
102
+ /** Escape in the window. The opener closes it and takes the focus back. */
103
+ onClose?: () => void;
104
+ /** The window's DOM id, for the opener's `aria-controls`. */
105
+ id?: string;
106
+ /** The colour in force while `value` is `''` (see `ColourPicker`): the window starts from it, its hex a placeholder. */
107
+ inherited?: string;
108
+ readOnly?: boolean;
109
+ words?: PickWords['colour'];
110
+ /**
111
+ * Start the hex row with a swatch of the colour, as the text box's colour
112
+ * window draws it (E5b). Off by default: `ColourPicker`'s row already has its
113
+ * swatch beside the hex.
114
+ */
115
+ swatch?: boolean;
116
+ /**
117
+ * When a drag on the square or the hue bar writes. `'live'` (the default,
118
+ * as `ColourPicker` always has): every move. `'end'`: once, where the
119
+ * pointer comes up — one undo step for a host whose every write is one,
120
+ * like the text box (E5b). The thumbs, the hex and the swatch follow the
121
+ * drag live either way. An arrow key writes each press in both.
122
+ */
123
+ dragWrites?: 'live' | 'end';
124
+ };
125
+ /**
126
+ * THE COLOUR WINDOW on its own: the theme's colours, the saturation and
127
+ * brightness square, the hue strip and the hex. `ColourPicker` opens it under
128
+ * its swatch; a row that draws its own swatches (the text-styles list's Any
129
+ * color, plan step E6) opens the same one, so there is one window, not two.
130
+ * The opener owns when it is open and puts it in the panel's own flow.
55
131
  */
56
- declare function ColourPicker({ value, onChange, label, theme, caption, id: swatchId, readOnly, words, }: ColourPickerProps): react.JSX.Element;
132
+ declare function ColourWindow({ value, onChange, label, theme, onClose, id, inherited, readOnly, words, swatch, dragWrites, }: ColourWindowProps): react.JSX.Element;
57
133
 
58
134
  type ImageBoxProps = {
59
135
  /** The file's URL, or `''` while the setting has none. */
@@ -150,4 +226,4 @@ declare function hueFromPoint(x: number, box: {
150
226
  * name, so it reads as none rather than as its own bytes. */
151
227
  declare function mediaName(url: string): string;
152
228
 
153
- export { ColourPicker, type ColourPickerProps, HEX_MAX_LENGTH, type Hsv, ImageBox, type ImageBoxProps, PickWords, type ThemeColour, hexReadout, hexToHsv, hsvToHex, hueFromPoint, mediaName, svFromPoint, typedHex };
229
+ export { ColourPicker, type ColourPickerProps, ColourWindow, type ColourWindowProps, HEX_MAX_LENGTH, type Hsv, ImageBox, type ImageBoxProps, PickWords, type ThemeColour, hexReadout, hexToHsv, hsvToHex, hueFromPoint, mediaName, svFromPoint, typedHex };
@@ -1,14 +1,7 @@
1
- import{DEFAULT_PICK_WORDS as e}from"../chunk-ZAOM6PFH.js";import{useId as a,useState as t,useRef as n,useEffect as l}from"react";import{jsxs as r,jsx as i}from"react/jsx-runtime";var s=/^(?:[0-9a-f]{3}|[0-9a-f]{6})$/i,o=7;function c(e){const a=e.trim().replace(/^#/,"");if(!s.test(a))return null;return`#${(3===a.length?[...a].map(e=>e+e).join(""):a).toLowerCase()}`}var u=e=>e.toUpperCase(),h=(e,a,t)=>Math.min(t,Math.max(a,e));function m(e){const a=c(e)??"#000000",t=parseInt(a.slice(1,3),16)/255,n=parseInt(a.slice(3,5),16)/255,l=parseInt(a.slice(5,7),16)/255,r=Math.max(t,n,l),i=r-Math.min(t,n,l);let s=0;return 0!==i&&(s=r===t?(n-l)/i%6*60:r===n?60*((l-t)/i+2):60*((t-n)/i+4)),{h:(s+360)%360,s:0===r?0:i/r,v:r}}function d({h:e,s:a,v:t}){const n=(e%360+360)%360,l=h(a,0,1),r=h(t,0,1),i=r*l,s=i*(1-Math.abs(n/60%2-1)),o=r-i,[c,u,m]=n<60?[i,s,0]:n<120?[s,i,0]:n<180?[0,i,s]:n<240?[0,s,i]:n<300?[s,0,i]:[i,0,s],d=e=>Math.round(255*(e+o)).toString(16).padStart(2,"0");return`#${d(c)}${d(u)}${d(m)}`}function p(e,a,t){return{s:t.width>0?h((e-t.left)/t.width,0,1):0,v:t.height>0?1-h((a-t.top)/t.height,0,1):0}}function v(e,a){return a.width>0?360*h((e-a.left)/a.width,0,1):0}function g(e){if(/^(data|blob):/i.test(e))return"";const a=(e.split(/[?#]/)[0]??"").split("/").filter(Boolean).pop()??"";try{return decodeURIComponent(a)}catch{return a}}function b({value:s,onChange:o,label:h,theme:g,caption:b,id:f,readOnly:y,words:w=e.colour}){const N=a(),[x,C]=t(!1),M=n(null),D=n(null),[A,I]=t(()=>m(s||"#000000")),$=n(s);l(()=>{s!==$.current&&($.current=s,s&&I(m(s)))},[s]);const L=e=>{y||e===s||($.current=e,o(e))},O=e=>{I(m(e)),L(e)},E=e=>{I(e),L(d(e))};l(()=>{if(!x)return;const e=M.current?.ownerDocument;if(!e)return;const a=e=>{M.current&&!M.current.contains(e.target)&&C(!1)};return e.addEventListener("click",a,!0),()=>e.removeEventListener("click",a,!0)},[x]);const K=e=>({onPointerDown:a=>{y||(a.currentTarget.setPointerCapture?.(a.pointerId),e(a))},onPointerMove:a=>{1&a.buttons&&e(a)}}),P=K(e=>E({...A,...p(e.clientX,e.clientY,e.currentTarget.getBoundingClientRect())})),T=K(e=>E({...A,h:v(e.clientX,e.currentTarget.getBoundingClientRect())})),B=e=>`${Math.round(100*e)}%`,R=void 0===b||s&&c(b)===c(s)?null:b,S=R??(s?u(s):w.notSet);/* @__PURE__ */
2
- return r("div",{ref:M,className:"es-pick-colour",children:[
3
- /* @__PURE__ */r("div",{className:"es-pick-colour-row",children:[
4
- /* @__PURE__ */i("button",{ref:D,id:f,type:"button",className:s?"es-pick-swatch":"es-pick-swatch is-unset",style:s?{background:s}:void 0,"aria-label":w.swatch({label:h,shown:S}),"aria-expanded":x,"aria-controls":x?N:void 0,disabled:y,onClick:()=>C(e=>!e)}),null===R?/* @__PURE__ */i(k,{value:s,onChange:O,name:w.hex({label:h}),readOnly:y}):/* @__PURE__ */i("span",{className:"es-pick-caption",children:R})]}),x?/* @__PURE__ */r("div",{id:N,role:"dialog","aria-label":w.dialog({label:h}),className:"es-pick-window",onKeyDown:e=>{"Escape"===e.key&&(e.preventDefault(),e.stopPropagation(),C(!1),D.current?.focus())},children:[g&&g.length>0?/* @__PURE__ */i("div",{role:"group","aria-label":w.theme,className:"es-pick-theme",children:g.map(e=>/* @__PURE__ */i("button",{type:"button",className:"es-pick-theme-swatch",style:{background:e.value},title:w.themeSwatchTitle({name:e.name,hex:u(e.value)}),"aria-label":w.themeSwatch({name:e.name,hex:u(e.value)}),"aria-pressed":c(e.value)===s,onClick:()=>O(c(e.value)??e.value)},`${e.name}:${e.value}`))}):null,
5
- /* @__PURE__ */i("div",{className:"es-pick-sv",role:"slider",tabIndex:0,"aria-label":w.square,"aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":Math.round(100*A.v),"aria-valuetext":w.squareValue({saturation:B(A.s),brightness:B(A.v)}),style:{backgroundColor:d({h:A.h,s:1,v:1})},onKeyDown:e=>{const a=e.shiftKey?.1:.01,t={ArrowLeft:[-a,0],ArrowRight:[a,0],ArrowDown:[0,-a],ArrowUp:[0,a]}[e.key];t&&(e.preventDefault(),E({...A,s:Math.min(1,Math.max(0,A.s+t[0])),v:Math.min(1,Math.max(0,A.v+t[1]))}))},...P,children:/* @__PURE__ */i("span",{className:"es-pick-sv-thumb",style:{left:B(A.s),top:B(1-A.v)}})}),
6
- /* @__PURE__ */i("div",{className:"es-pick-hue",role:"slider",tabIndex:0,"aria-label":w.hue,"aria-valuemin":0,"aria-valuemax":359,"aria-valuenow":Math.round(A.h),onKeyDown:e=>{const a=e.shiftKey?10:1,t="ArrowLeft"===e.key||"ArrowDown"===e.key?-a:"ArrowRight"===e.key||"ArrowUp"===e.key?a:null,n="Home"===e.key?0:"End"===e.key?359:null===t?null:Math.min(359,Math.max(0,A.h+t));null!==n&&(e.preventDefault(),E({...A,h:n}))},...T,children:/* @__PURE__ */i("span",{className:"es-pick-hue-thumb",style:{left:A.h/360*100+"%"}})}),
7
- /* @__PURE__ */i(k,{value:s,onChange:O,name:w.hex({label:h}),readOnly:y})]}):null]})}function k({value:e,onChange:a,name:n,readOnly:l}){const[r,s]=t(null);/* @__PURE__ */
8
- return i("input",{type:"text",className:"es-pick-hex",value:r??(e?u(e):""),"aria-label":n,maxLength:7,spellCheck:!1,autoComplete:"off",readOnly:l,onChange:t=>{s(t.target.value);const n=c(t.target.value);null!==n&&n!==e&&a(n)},onFocus:e=>e.currentTarget.select(),onKeyDown:e=>{"Enter"!==e.key&&"Escape"!==e.key||(e.preventDefault(),e.stopPropagation(),s(null),e.currentTarget.blur())},onBlur:()=>s(null)})}function f({value:a,onChange:n,label:l,openLibrary:s,kind:o="image",placeholder:c,readOnly:u,words:h=e.image}){const[m,d]=t(!1),[p,v]=t(!1),b=Boolean(s)&&!u,k=async()=>{if(s&&!m&&!u){d(!0),v(!1);try{const e=await s();e&&n(e)}catch{v(!0)}finally{d(!1)}}},f=m?/* @__PURE__ */i("p",{className:"es-pick-image-status",role:"status",children:h.choosing}):p?/* @__PURE__ */i("p",{className:"es-pick-image-status is-error",role:"alert",children:h.failed}):null;if(!a)/* @__PURE__ */
9
- return r("div",{className:"es-pick-image",children:[
10
- /* @__PURE__ */r("button",{type:"button",className:"es-pick-image-slot",onClick:k,disabled:!b||m,"aria-label":h.empty({label:l,kind:o,placeholder:c}),children:[
11
- /* @__PURE__ */i("span",{className:"es-pick-image-slot-name",children:c??("video"===o?h.chooseVideo:h.chooseImage)}),b?/* @__PURE__ */i("span",{className:"es-pick-image-slot-hint",children:h.hint}):null]}),f]});const y=g(a),w=y?h.named({label:l,name:y}):l;/* @__PURE__ */
12
- return r("div",{className:"es-pick-image",children:[
13
- /* @__PURE__ */r("figure",{className:"es-pick-image-figure",children:[
14
- /* @__PURE__ */i("div",{className:"es-pick-image-frame",children:"video"===o?/* @__PURE__ */i("video",{src:a,muted:!0,playsInline:!0,preload:"metadata","aria-label":w}):/* @__PURE__ */i("img",{src:a,alt:w})}),y?/* @__PURE__ */i("figcaption",{className:"es-pick-image-name",title:y,children:y}):null]}),b||!u?/* @__PURE__ */r("div",{className:"es-pick-image-actions",children:[b?/* @__PURE__ */i("button",{type:"button",className:"es-pick-image-btn",onClick:k,disabled:m,"aria-label":h.replaceNamed({label:l}),children:h.replace}):null,u?null:/* @__PURE__ */i("button",{type:"button",className:"es-pick-image-btn is-bare",onClick:()=>n(""),disabled:m,"aria-label":h.removeNamed({label:l}),children:h.remove})]}):null,f]})}export{b as ColourPicker,o as HEX_MAX_LENGTH,f as ImageBox,u as hexReadout,m as hexToHsv,d as hsvToHex,v as hueFromPoint,g as mediaName,p as svFromPoint,c as typedHex};
1
+ import{mediaName as e}from"../chunk-H24N5TMZ.js";export{ColourPicker,ColourWindow,HEX_MAX_LENGTH,hexReadout,hexToHsv,hsvToHex,hueFromPoint,mediaName,svFromPoint,typedHex}from"../chunk-H24N5TMZ.js";import{DEFAULT_PICK_WORDS as a}from"../chunk-ZAOM6PFH.js";import{useState as i}from"react";import{jsx as l,jsxs as s}from"react/jsx-runtime";function c({value:c,onChange:n,label:o,openLibrary:r,kind:t="image",placeholder:m,readOnly:d,words:p=a.image}){const[u,h]=i(!1),[b,g]=i(!1),k=Boolean(r)&&!d,N=async()=>{if(r&&!u&&!d){h(!0),g(!1);try{const e=await r();e&&n(e)}catch{g(!0)}finally{h(!1)}}},f=u?/* @__PURE__ */l("p",{className:"es-pick-image-status",role:"status",children:p.choosing}):b?/* @__PURE__ */l("p",{className:"es-pick-image-status is-error",role:"alert",children:p.failed}):null;if(!c)/* @__PURE__ */
2
+ return s("div",{className:"es-pick-image",children:[
3
+ /* @__PURE__ */s("button",{type:"button",className:"es-pick-image-slot",onClick:N,disabled:!k||u,"aria-label":p.empty({label:o,kind:t,placeholder:m}),children:[
4
+ /* @__PURE__ */l("span",{className:"es-pick-image-slot-name",children:m??("video"===t?p.chooseVideo:p.chooseImage)}),k?/* @__PURE__ */l("span",{className:"es-pick-image-slot-hint",children:p.hint}):null]}),f]});const v=e(c),y=v?p.named({label:o,name:v}):o;/* @__PURE__ */
5
+ return s("div",{className:"es-pick-image",children:[
6
+ /* @__PURE__ */s("figure",{className:"es-pick-image-figure",children:[
7
+ /* @__PURE__ */l("div",{className:"es-pick-image-frame",children:"video"===t?/* @__PURE__ */l("video",{src:c,muted:!0,playsInline:!0,preload:"metadata","aria-label":y}):/* @__PURE__ */l("img",{src:c,alt:y})}),v?/* @__PURE__ */l("figcaption",{className:"es-pick-image-name",title:v,children:v}):null]}),k||!d?/* @__PURE__ */s("div",{className:"es-pick-image-actions",children:[k?/* @__PURE__ */l("button",{type:"button",className:"es-pick-image-btn",onClick:N,disabled:u,"aria-label":p.replaceNamed({label:o}),children:p.replace}):null,d?null:/* @__PURE__ */l("button",{type:"button",className:"es-pick-image-btn is-bare",onClick:()=>n(""),disabled:u,"aria-label":p.removeNamed({label:o}),children:p.remove})]}):null,f]})}export{c as ImageBox};