efficient-easel 10.0.0 → 10.2.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 (44) hide show
  1. package/README.md +6 -0
  2. package/dist/canvas-typing-CJodefPO.d.ts +478 -0
  3. package/dist/{chunk-OWW44DVK.js → chunk-74ZFATLG.js} +1 -1
  4. package/dist/{chunk-LGDQLTJW.js → chunk-7O6MDCDU.js} +3 -3
  5. package/dist/{chunk-U5RF4USK.js → chunk-A5OEGP7B.js} +4 -4
  6. package/dist/{chunk-K2YSFVOJ.js → chunk-ERA3XM2U.js} +1 -1
  7. package/dist/{chunk-BPLCMQ6S.js → chunk-FJ3ZJJ5Z.js} +45 -45
  8. package/dist/chunk-ICN6COBK.js +5 -0
  9. package/dist/{chunk-WQASXLXS.js → chunk-IL6QCPO6.js} +1 -1
  10. package/dist/{chunk-GKGBKSZ7.js → chunk-IZ2QRXSE.js} +1 -1
  11. package/dist/{chunk-XF2AIO46.js → chunk-JSPZU7X2.js} +1 -1
  12. package/dist/{chunk-K5744MTM.js → chunk-M32O2WRM.js} +10 -10
  13. package/dist/{chunk-M6F6LS3H.js → chunk-OGH6CC3E.js} +1 -1
  14. package/dist/{chunk-XO7OUCZV.js → chunk-OWK7DGWG.js} +1 -1
  15. package/dist/{chunk-4CE7XFCE.js → chunk-TROOTMAD.js} +1 -1
  16. package/dist/{chunk-2AKW6UXX.js → chunk-YMEN4KVE.js} +1 -1
  17. package/dist/copy/index.d.ts +20 -399
  18. package/dist/copy/index.js +17 -15
  19. package/dist/easel/index.d.ts +19 -2
  20. package/dist/easel/index.js +1 -1
  21. package/dist/fields/index.d.ts +2 -2
  22. package/dist/screen/components/AddBlockRow.js +1 -1
  23. package/dist/screen/components/AddSidePanel.js +1 -1
  24. package/dist/screen/components/MediaSidePanel.js +1 -1
  25. package/dist/screen/components/ScreenChrome.js +1 -1
  26. package/dist/screen/components/ScreenMount.js +1 -1
  27. package/dist/screen/components/ScreenStoreProvider.js +1 -1
  28. package/dist/screen/components/SectionScreenShell.js +15 -15
  29. package/dist/screen/components/usePartBridge.js +1 -1
  30. package/dist/screen/index.js +1 -1
  31. package/dist/screen/lib/key-scope.js +1 -1
  32. package/dist/screen/lib/puck/use-section-ops.js +1 -1
  33. package/dist/screen/lib/screen-parts.js +1 -1
  34. package/dist/strings/catalogue.d.ts +1 -1
  35. package/dist/strings/catalogue.js +1 -1
  36. package/dist/strings/index.d.ts +1 -1
  37. package/dist/strings/index.js +1 -1
  38. package/dist/text-styles/index.d.ts +3 -3
  39. package/dist/text-styles/index.js +33 -33
  40. package/dist/{types-C97TAUKi.d.ts → types-Dkx1VAIQ.d.ts} +1 -1
  41. package/dist/{words-CRYvAiHX.d.ts → words-gIDCeRv3.d.ts} +1 -0
  42. package/package.json +1 -1
  43. package/dist/canvas-typing-Cnvlsh_V.d.ts +0 -69
  44. package/dist/chunk-XTDBTCVO.js +0 -5
@@ -1,11 +1,11 @@
1
- import{DEFAULT_CANVAS_WORDS as e}from"./chunk-TBY3DFKS.js";import{useResolvedFields as t}from"./chunk-YRLPFZW3.js";import{toItemSelector as n,fromItemSelector as o,useNodeOps as r,parentStep as i,clickPick as a}from"./chunk-ECM5F6JJ.js";import{startCanvasTyping as s,textMap as l}from"./chunk-WQASXLXS.js";import{useWords as c}from"./chunk-MFIRYGHW.js";import{setCanvasNonce as d,isTypingTarget as u,frameRectToHost as p,CANVAS_TYPING_EVENT as f,drawnBox as h}from"./chunk-ILXP5VX5.js";import{find as m,ROOT_ID as g,getList as v,remove as y,parseZoneKey as w,move as k,duplicate as b,replaceNode as S,createNode as I,insert as C,normalizeData as E,createResolveCache as x,resolveNodeData as D,ROOT_SLOT as O}from"./chunk-KRXQM65X.js";import{topLevelSlotKeys as A,fieldsFrom as P,defaultsFrom as M}from"./chunk-NKB3KVAB.js";import{createContext as z,useEffect as K,useContext as $,useRef as j,useSyncExternalStore as B,useState as L,useMemo as N,useCallback as R,useLayoutEffect as Z}from"react";import{jsx as V,jsxs as F}from"react/jsx-runtime";import{createPortal as T}from"react-dom";import{FloatingBar as H,TextToolbar as X}from"efficient-shell/ui";function W(e){return!["setData","setUi","set"].includes(e.type)}var Y=(e,t,n,o)=>{const r=v(e,t,w(n));return r?.[o]??null},q=(e,t,n,o,r)=>{const i=Y(e,t,n,o);if(!i)throw new Error(`${r}: nothing at ${n}[${o}]`);return i};function U(e,t){const{selection:o}=e;return{...e.ui,itemSelector:n(e.data,t,o),selectedSlot:o&&"slot"===o.kind?{parentId:o.parentId,slot:o.slot}:null}}function J(e,t,n){return n?"node"===n.kind?m(e,t,n.id)?n:null:n.parentId===g?v(e,t,n)?n:null:m(e,t,n.parentId)&&v(e,t,n)?n:null:null}function Q(e,t,n,r=!1){const{itemSelector:i,selectedSlot:a,...s}=n;let l=e.selection;var c;return"itemSelector"in n&&(l=o(e.data,t,i??null)),"selectedSlot"in n&&(a?l=(c=a)?{kind:"slot",parentId:c.parentId,slot:c.slot}:null:"slot"===l?.kind&&(l=null)),{...e,selection:l,ui:r?s:{...e.ui,...s}}}function G(e,t,n){const o=_(e,t,n);if(o===e)return e;const r=J(o.data,n,o.selection);return r===o.selection?o:{...o,selection:r}}function _(e,t,n){const{data:o}=e;switch(t.type){case"setData":{const n="function"==typeof t.data?t.data(o):t.data;return{...e,data:{...o,...n}}}case"setUi":return Q(e,n,"function"==typeof t.ui?t.ui(U(e,n)):t.ui);case"set":{const r={data:o,ui:U(e,n)},i="function"==typeof t.state?t.state(r):t.state;let a=i.data?{...e,data:i.data}:e;return i.ui&&(a=Q(a,n,i.ui,!0)),a}case"insert":{const r={...w(t.destinationZone),index:t.destinationIndex},i=I(n,t.componentType,{},t.id?{id:t.id}:{});return{...e,data:C(o,n,r,i)}}case"replace":{const r=q(o,n,t.destinationZone,t.destinationIndex,"replace");if(r.props.id!==t.data.props.id)throw new Error("Can't change the id during a replace action. Use remove and insert for a new node.");return{...e,data:S(o,n,r.props.id,t.data)}}case"replaceRoot":{const n={...o.root,props:{...o.root.props,...t.root.props},readOnly:t.root.readOnly};return{...e,data:{...o,root:n}}}case"duplicate":{const r=q(o,n,t.sourceZone,t.sourceIndex,"duplicate"),i=b(o,n,r.props.id),a=Y(i,n,t.sourceZone,t.sourceIndex+1);return{...e,data:i,selection:a?{kind:"node",id:a.props.id}:e.selection}}case"reorder":return _(e,{...t,type:"move",sourceZone:t.destinationZone},n);case"move":{if(t.sourceZone===t.destinationZone&&t.sourceIndex===t.destinationIndex)return e;const r=Y(o,n,t.sourceZone,t.sourceIndex);if(!r)return e;const i={...w(t.destinationZone),index:t.destinationIndex};return{...e,data:k(o,n,r.props.id,i)}}case"remove":{const r=q(o,n,t.zone,t.index,"remove");return{...e,data:y(o,n,r.props.id)}}default:return e}}var ee={drag:!0,duplicate:!0,delete:!0,edit:!0,insert:!0},te={leftSideBarVisible:!0,rightSideBarVisible:!0,arrayState:{},componentList:{},isDragging:!1,previewMode:"edit",viewports:{current:{width:360,height:"auto"},options:[],controlsVisible:!0},field:{focus:null}},ne=0,oe=()=>`history-${ne+=1}`;function re(e){let t=e.config;const r=e.now??(()=>Date.now()),i=e.historyCoalesceMs??250;let a=e.permissions??{};const s=E(e.data,t);let l={data:s,selection:null,ui:{...te}};if(e.ui){const{itemSelector:n,selectedSlot:r,...i}=e.ui;l={data:s,selection:r?{kind:"slot",...r}:o(s,t,n??null),ui:{...te,...i}}}let c=[{core:l,at:-1/0,sealed:!0,id:oe()}],d=0;const u=e=>{const t=c[d],n=r();!e&&d===c.length-1&&d>0&&!t.sealed&&n-t.at<i?c=[...c.slice(0,d),{...t,core:l,at:n}]:(c=[...c.slice(0,d+1),{core:l,at:n,sealed:e,id:oe()}],d=c.length-1)},p=/* @__PURE__ */new Set;let f=null,h=null,g=0,y=null,w=!1;const k=()=>{for(const e of[...p])e()},b=()=>{c=[...c.slice(0,d),{...c[d],core:l},...c.slice(d+1)]},I=(t,n)=>{g>0?w=w||n:(n?u(!1):l!==t&&b(),l.data!==t.data&&e.onChange?.(l.data),l!==t&&k())},C=e=>{const n=l;if(l=G(l,e,t),l===n)return;const o=e.recordHistory??W(e);I(n,o&&l.data!==n.data)},O=t=>{0===g&&(y=l,w=!1),g+=1;try{t()}catch(e){throw g-=1,0===g&&y&&(l=y,y=null),e}if(g-=1,g>0||!y)return;const n=y;y=null,w&&l.data!==n.data?u(!0):l!==n&&b(),l.data!==n.data&&e.onChange?.(l.data),l!==n&&k()},A=e=>{const n=l,o=J(l.data,t,e);var r,i;(r=o,i=l.selection,r===i||r&&i&&r.kind===i.kind&&("node"===r.kind&&"node"===i.kind?r.id===i.id:"slot"===r.kind&&"slot"===i.kind&&r.parentId===i.parentId&&r.slot===i.slot))||(l={...l,selection:o},I(n,!1))},P=t=>{const n=l;d=t,l=c[d].core,l.data!==n.data&&e.onChange?.(l.data),l!==n&&k()},M=()=>(e={})=>{const n=e.root?t.root?.permissions:t.components[e.item?.type??e.type??""]?.permissions;return{...ee,...a,...n}};let z=M();const K=x(),$={resolveCache:K,async resolveAll({trigger:e="load",metadata:n}={}){const o=l.data,r={type:"root",props:{...o.root.props??{}}},i=[...o.content,...Object.values(o.zones??{}).flat()],[a,...s]=await Promise.all([D(r,t,{cache:K,trigger:e,metadata:n}),...i.map(o=>D(o,t,{cache:K,trigger:e,metadata:n}))]);O(()=>{const e=l;let n=l.data;s.forEach((e,r)=>{if(!e.didChange)return;const a=i[r].props.id,s=m(n,t,a)?.node;s&&s===m(o,t,a)?.node&&(n=S(n,t,a,e.node))}),a.didChange&&n.root===o.root&&(n={...n,root:{...n.root,props:a.node.props,readOnly:a.node.readOnly??n.root.readOnly}}),n!==l.data&&(l={...l,data:n,selection:J(n,t,l.selection)},I(e,!1))})},async resolveNode(e,{trigger:n="replace",metadata:o}={}){const r=m(l.data,t,e)?.node;if(!r)return!1;const i=await D(r,t,{cache:K,trigger:n,metadata:o});if(!i.didChange)return!1;let a=!1;return O(()=>{const n=l;if(m(l.data,t,e)?.node!==r)return;const o=S(l.data,t,e,i.node);o!==l.data&&(l={...l,data:o,selection:J(o,t,l.selection)},I(n,!1),a=!0)}),a},get config(){return t},getState(){if(f&&h===l)return f;const e=l,o={data:e.data,ui:U(e,t)},r="node"===e.selection?.kind?m(e.data,t,e.selection.id)?.node??null:null;return f={appState:o,selection:e.selection,selectedItem:r,config:t,dispatch:C,history:{back:()=>$.undo(),forward:()=>$.redo(),hasPast:d>0,hasFuture:d<c.length-1,histories:c.map(e=>({id:e.id,state:{data:e.core.data,ui:U(e.core,t)}})),index:d,setHistoryIndex:e=>{e>=0&&e<c.length&&e!==d&&P(e)}},getPermissions:z,getItemById:n=>m(e.data,t,n)?.node,getItemBySelector:n=>function(e,t,n){const[o,r]=(n.zone??"root:default-zone").split(/:(.*)/s);return v(e,t,{parentId:o,slot:r})?.[n.index]}(e.data,t,n),getSelectorForId:o=>{const r=n(e.data,t,{kind:"node",id:o});return r?{index:r.index,zone:r.zone??"root:default-zone"}:void 0}},h=e,f},subscribe:e=>(p.add(e),()=>{p.delete(e)}),dispatch:C,batch:O,group:()=>{const e=d,t=c[e].id;let n=!0;return{close:()=>{if(!n)return;if(n=!1,c[e]?.id!==t)return;if(d<=e+1)return void(d===e+1&&(c=[...c.slice(0,d),{...c[d],sealed:!0},...c.slice(d+1)]));const o=c[d];c=[...c.slice(0,e+1),{...o,sealed:!0},...c.slice(d+1)],d=e+1}}},select:e=>A(e?{kind:"node",id:e}:null),selectSlot:e=>A(e?{kind:"slot",parentId:e.parentId,slot:e.slot}:null),run(e){O(()=>{const n=l,o=void 0===e.select?l.selection:e.select;l={...l,data:e.data,selection:J(e.data,t,o)},I(n,e.data!==n.data)})},load(e,n={}){const o=l,r=E(e,t);l={...l,data:r,selection:J(r,t,n.selection??l.selection)},n.keepHistory||(c=[{core:l,at:-1/0,sealed:!0,id:oe()}],d=0),l!==o&&k()},undo(){d>0&&P(d-1)},redo(){d<c.length-1&&P(d+1)},setPermissions(e){(function(e,t){if(e===t)return!0;const n=Object.keys(e);return n.length===Object.keys(t).length&&n.every(n=>e[n]===t[n])})(e,a)||(a=e,z=M(),f=null,k())},setConfig(e){e!==t&&(t=e,z=M(),f=null,k())}};return $}function ie(e,t,n={}){const o=e=>{if(e.altKey)return;if(!(e.metaKey!==e.ctrlKey))return;const o="KeyZ"===e.code,r="KeyY"===e.code&&!e.shiftKey;(o||r)&&(n.leaveTyping&&u(e.target)||!1!==t.getState?.().getPermissions().edit&&(e.preventDefault(),r||e.shiftKey?t.redo():t.undo()))};return e.addEventListener("keydown",o),()=>e.removeEventListener("keydown",o)}var ae=z(null),se=z(!0);function le({easel:e,hotkeys:t=!0,resolveOnMount:n=!0,children:o}){return K(()=>{n&&e.resolveAll()},[e,n]),K(()=>{if(t&&"undefined"!=typeof document)return ie(document,e)},[e,t]),/* @__PURE__ */V(ae.Provider,{value:e,children:/* @__PURE__ */V(se.Provider,{value:t,children:o})})}function ce(){const e=$(ae);if(!e)throw new Error("useEasel: no <EaselProvider> above this component");return e}function de(e){const t=ce(),n=j({view:null,selector:null,value:void 0,has:!1}),o=()=>{const o=t.getState(),r=n.current;if(r.has&&r.view===o&&r.selector===e)return r.value;const i=e(o);return r.has&&Object.is(r.value,i)?(n.current={view:o,selector:e,value:r.value,has:!0},r.value):(n.current={view:o,selector:e,value:i,has:!0},i)};return B(t.subscribe,o,o)}function ue(){return function(e){return de(e)}}var pe="data-puck-component",fe="data-puck-dropzone",he={},me="data-es-mirror",ge="undefined"==typeof window?K:Z;function ve(e,t,n){for(const e of Array.from(t.head.querySelectorAll(`[${me}]`)))e.remove();for(const o of Array.from(e.head.querySelectorAll('style, link[rel="stylesheet"]'))){const e=o.cloneNode(!0);e.setAttribute(me,""),n&&e.setAttribute("nonce",n),t.head.appendChild(e)}}function ye({children:t,id:n="preview-frame",title:o,className:r,style:i,mirrorStyles:a=!0,onDocument:s,height:l="auto",nonce:u}){const p=c("canvas",e),f=j(null),[h,m]=L(null);return ge(()=>{const e=f.current,t=h?.ownerDocument.defaultView;if("auto"!==l||!e||!h||!t)return;const n=()=>{e.style.height=`${Math.ceil(h.getBoundingClientRect().height)}px`};n();const o=t.ResizeObserver,r=o?new o(n):null;return r?.observe(h),()=>r?.disconnect()},[h,l]),ge(()=>{let e=f.current?.contentDocument;if(!e)return;"CSS1Compat"!==e.compatMode&&(e.open(),e.write("<!DOCTYPE html><html><head></head><body></body></html>"),e.close(),e=f.current?.contentDocument??e),e.body||e.documentElement.appendChild(e.createElement("body")),e.body.style.margin="0";const t=e.createElement("div");t.setAttribute("data-puck-entry",""),t.id="frame-root","fill"===l&&t.classList.add("es-frame-fill"),e.body.appendChild(t),d(e,u),m(t),s?.(e);let n=null;const o=f.current?.ownerDocument;if(a&&o){ve(o,e,u);const t=o.defaultView;t&&"MutationObserver"in t&&(n=new t.MutationObserver(()=>ve(o,e,u)),n.observe(o.head,{childList:!0,subtree:!0,characterData:!0}))}return()=>{n?.disconnect(),t.remove(),m(null),s?.(null)}},[]),/* @__PURE__ */V("iframe",{ref:f,id:n,title:o??p.frame,className:["es-canvas-frame","fill"===l?"is-fill":"",r??""].filter(Boolean).join(" "),style:i,children:h?T(t,h):null})}var we=z(null),ke=z(he),be=[];function Se({parentId:e,slot:t,className:n,style:o,minEmptyHeight:r=128,minEmptyWidth:i=120}){const a=ce(),s=de(n=>v(n.appState.data,a.config,{parentId:e,slot:t})??be),l=de(t=>"node"===t.selection?.kind&&t.selection.id===e&&e!==g),c=de(n=>"slot"===n.selection?.kind&&n.selection.parentId===e&&n.selection.slot===t),d=$(we),u=["es-zone"];return s.length&&u.push("has-children"),e===g&&u.push("is-root"),(l||c)&&u.push("is-area-selected"),null!==d&&d===e&&e!==g&&u.push("is-hovering-area"),n&&u.push(n),/* @__PURE__ */V("div",{className:u.join(" "),[fe]:`${e}:${t}`,style:{...o,"--min-empty-height":`${r}px`,"--min-empty-width":`${i}px`},children:s.map(e=>/* @__PURE__ */V(Ee,{node:e},e.props.id))})}function Ie(e,t){return N(()=>{const n={};for(const o of A(P(e)))n[o]=function(e={}){/* @__PURE__ */
2
- return V(Se,{parentId:t,slot:o,...e})};return n},[e,t])}function Ce(e){return N(()=>function({zone:t,...n}){/* @__PURE__ */
3
- return V(Se,{parentId:e,slot:t,...n})},[e])}function Ee({node:e}){const t=ce().config.components[e.type],n=e.props.id,o=function(e){const t=j(null);return N(()=>n=>{const o=t.current;o&&o!==n&&(o.removeAttribute(pe),o.removeAttribute("data-puck-dnd")),t.current=n,n&&(n.setAttribute(pe,e),n.setAttribute("data-puck-dnd",e),n.style.position="relative")},[e])}(n),r=$(ke),i=Ie(t,n),a=Ce(n);if(!t?.render)return null;const s=t.render,l={...M(t),...e.props,...i},c={renderDropZone:a,isEditing:!0,dragRef:t.inline?o:null,metadata:{...r,...t.metadata}};return t.inline?/* @__PURE__ */V(s,{...l,puck:c,editMode:!0}):/* @__PURE__ */V("div",{[pe]:n,"data-puck-dnd":n,style:{position:"relative"},children:/* @__PURE__ */V(s,{...l,puck:c,editMode:!0})})}function xe({metadata:e}){const t=de(e=>e.config),n=de(e=>e.appState.data.root).props??{},o=t.root?.render,r=Ie(t.root,g),i=Ce(g),a=/* @__PURE__ */V(Se,{parentId:g,slot:O}),s=o?/* @__PURE__ */V(o,{id:"puck-root",...n,...r,puck:{renderDropZone:i,isEditing:!0,dragRef:null,metadata:e??{}},editMode:!0,children:a}):a;/* @__PURE__ */
4
- return V(ke.Provider,{value:e??he,children:s})}var De=z(void 0);function Oe(e,t,n){const[o,r]=L(null),i=j(t);return i.current=t,ge(()=>{const t=e.current?.ownerDocument,n=t?.defaultView;if(!t||!n||!i.current)return void r(null);let o=0;const a=()=>{o=0;const n=function(e,t){if(!e||!t)return null;const n=h(e),o=t.getBoundingClientRect();return{top:n.top-o.top,left:n.left-o.left,width:n.width,height:n.height}}(i.current?i.current(t):null,e.current?.parentElement??null);r(e=>{return(t=e)===(o=n)||t&&o&&t.top===o.top&&t.left===o.left&&t.width===o.width&&t.height===o.height?e:n;var t,o})},s=()=>{o||(o=(n.requestAnimationFrame??(e=>n.setTimeout(e,16)))(a))};a();const l="MutationObserver"in n?new n.MutationObserver(s):null;l?.observe(t.body,{childList:!0,subtree:!0,attributes:!0,characterData:!0});const c="ResizeObserver"in n?new n.ResizeObserver(s):null;return c?.observe(t.documentElement),n.addEventListener("resize",s),()=>{l?.disconnect(),c?.disconnect(),n.removeEventListener("resize",s),o&&(n.cancelAnimationFrame??n.clearTimeout)(o)}},[n]),o}function Ae({id:e,kind:t,overlay:n}){const o=j(null),r=Oe(o,e?t=>t.querySelector(`[${pe}="${t.defaultView?.CSS?.escape?t.defaultView.CSS.escape(e):e}"]`):null,e),i=/* @__PURE__ */V("div",{ref:o,"aria-hidden":"true",className:`es-canvas-outline is-${t}`,style:r?{position:"absolute",top:r.top,left:r.left,width:r.width,height:r.height}:{display:"none"}});return n&&e?/* @__PURE__ */V(n,{componentId:e,kind:t,children:i}):i}function Pe(e,t,n){const o=l(e,n),r=o.text.length,i=e.ownerDocument;if(!t)return[r,r];let a=null;const s=i.caretPositionFromPoint?.(t.x,t.y);if(s&&e.contains(s.offsetNode))a=o.at(s.offsetNode,s.offset);else{const n=i.caretRangeFromPoint?.(t.x,t.y);n&&e.contains(n.startContainer)&&(a=o.at(n.startContainer,n.startOffset))}if(null===a)return[r,r];const c=o.text;let d=a,u=a;for(;d>0&&!/\s/.test(c[d-1]);)d-=1;for(;u<c.length&&!/\s/.test(c[u]);)u+=1;return[d,u]}function Me({s:e,element:t,toolbar:n,label:o}){const r=e.pressed(),i=new Set(n.offered.filter(e=>"link"!==e));/* @__PURE__ */
5
- return V(H,{anchor:()=>{const e=t();if(!e)return null;const n=e.getBoundingClientRect(),o=e.ownerDocument.defaultView?.frameElement,r=o?p(o,{left:n.left,top:n.top,width:n.width,height:n.height}):{left:n.left,top:n.top,width:n.width,height:n.height};return{left:r.left-6,top:r.top-6,right:r.left+r.width+6,bottom:r.top+r.height+6}},bounds:()=>{const e=t(),n=e?.ownerDocument.defaultView?.frameElement,o=(n??e?.closest(".es-canvas")??e)?.getBoundingClientRect();return o?{left:o.left,top:o.top,right:o.right,bottom:o.bottom}:{left:0,top:0,right:window.innerWidth,bottom:window.innerHeight}},"aria-label":o,children:/* @__PURE__ */V("div",{style:{width:"18rem"},children:/* @__PURE__ */V(X,{offered:i,pressed:r.marks,onMark:t=>{"link"!==t&&e.press(t)},list:{pressed:r.list,onList:t=>e.list(t)},alignment:n.alignment,letterCase:n.letterCase})})})}function ze({element:e}){const t=j(null),n=Oe(t,()=>e(),e);/* @__PURE__ */
6
- return V("div",{ref:t,"aria-hidden":"true",className:"es-canvas-outline is-typing",style:n?{position:"absolute",top:n.top,left:n.left,width:n.width,height:n.height}:{display:"none"}})}function Ke({frame:t=!0,className:n,style:o,metadata:r,mirrorStyles:l,onDocument:d,height:u,title:p,nonce:h,hotkeys:m,frameWrapper:g,overlay:v,children:y,typing:w,passThrough:k}){const b=ce(),S=$(De),I=k??S,C=$(se),E=c("canvas",e),x=m??C,[D,O]=L(void 0),A=de(e=>"node"===e.selection?.kind?e.selection.id:null),[P,M]=L(null),[z,B]=L(null),N=j(null),[,R]=L(0),Z=j(w);Z.current=w;const T=j(null),H=e=>{const t=T.current?.ownerDocument,n=t?.defaultView?.CustomEvent;t&&n&&t.dispatchEvent(new n(f,{detail:{typing:e}}))},X=(e,t)=>{N.current?.s.stop("stop");const n=e.element();if(!n)return!1;const o=b.group(),r=e.element,i=s({element:r,value:e.value,rules:e.rules,multiline:e.multiline,skip:e.skip,caret:Pe(n,t,e.skip),write:e.write,remount:e.remount,onSelect:()=>R(e=>e+1),end:e=>{o.close(),N.current?.element===r&&(N.current=null),B(null),H(!1),Z.current?.onChange?.({typing:!1,why:e})}});if(!i)return o.close(),!1;const a=n.closest?.(`[${pe}]`)?.getAttribute(pe);return a&&b.select(a),N.current={s:i,element:r,target:e},B(()=>r),M(null),H(!0),Z.current?.onChange?.({typing:!0,element:n}),!0};K(()=>()=>N.current?.s.stop("stop"),[]);const W=e=>{const t=N.current?.element();return Boolean(t&&t.contains(e))},Y=e=>{const t=e.closest?.(`[${pe}]`)?.getAttribute(pe);if(!t)return;const n=b.getState(),o="node"===n.selection?.kind?n.selection.id:null;return a(n.appState.data,b.config,t,o,I)??t},q=e=>{if("Enter"!==e.key||e.defaultPrevented||e.shiftKey||e.metaKey||e.ctrlKey||e.altKey)return;if(N.current)return;const t=e.target;if(t?.isContentEditable||t?.closest?.("input, textarea, select, button"))return;const n=Z.current?.atSelection?.();n&&X(n,null)&&e.preventDefault()},U=/* @__PURE__ */F("div",{ref:T,className:"es-canvas-content",style:{position:"relative"},onClick:e=>{const t=e.target;if(t.closest?.("a[href]")&&e.preventDefault(),N.current){if(W(t))return;N.current.s.stop("outside")}const n=Y(t);void 0===n?t.hasAttribute?.(fe)||b.select(null):b.select(n)},onDoubleClick:e=>{const t=Z.current;if(!t||W(e.target))return;const n=t.at(e.target);n&&X(n,{x:e.clientX,y:e.clientY})&&e.preventDefault()},onKeyDown:e=>q(e),onMouseOver:e=>{if(N.current)return;const t=Y(e.target)??null;t!==P&&M(t)},onMouseLeave:()=>M(null),children:[
7
- /* @__PURE__ */V(we.Provider,{value:P,children:/* @__PURE__ */V(xe,{metadata:r})}),
1
+ import{DEFAULT_CANVAS_WORDS as e}from"./chunk-TBY3DFKS.js";import{useResolvedFields as t}from"./chunk-YRLPFZW3.js";import{toItemSelector as n,fromItemSelector as o,useNodeOps as r,parentStep as i,clickPick as a}from"./chunk-ECM5F6JJ.js";import{startCanvasTyping as s,textMap as l}from"./chunk-IL6QCPO6.js";import{useWords as c}from"./chunk-MFIRYGHW.js";import{setCanvasNonce as d,isTypingTarget as u,frameRectToHost as p,CANVAS_TYPING_EVENT as f,drawnBox as h}from"./chunk-ILXP5VX5.js";import{find as m,ROOT_ID as g,getList as v,remove as y,parseZoneKey as w,move as k,duplicate as b,replaceNode as S,createNode as I,insert as C,normalizeData as E,createResolveCache as x,resolveNodeData as D,ROOT_SLOT as O}from"./chunk-KRXQM65X.js";import{topLevelSlotKeys as P,fieldsFrom as A,defaultsFrom as M}from"./chunk-NKB3KVAB.js";import{createContext as z,useEffect as K,useContext as N,useRef as $,useSyncExternalStore as j,useState as B,useMemo as L,useCallback as R,useLayoutEffect as Z}from"react";import{jsx as V,jsxs as F}from"react/jsx-runtime";import{createPortal as T}from"react-dom";import{FloatingBar as H,TextToolbar as Y}from"efficient-shell/ui";function W(e){return!["setData","setUi","set"].includes(e.type)}var X=(e,t,n,o)=>{const r=v(e,t,w(n));return r?.[o]??null},q=(e,t,n,o,r)=>{const i=X(e,t,n,o);if(!i)throw new Error(`${r}: nothing at ${n}[${o}]`);return i};function U(e,t){const{selection:o}=e;return{...e.ui,itemSelector:n(e.data,t,o),selectedSlot:o&&"slot"===o.kind?{parentId:o.parentId,slot:o.slot}:null}}function J(e,t,n){return n?"node"===n.kind?m(e,t,n.id)?n:null:n.parentId===g?v(e,t,n)?n:null:m(e,t,n.parentId)&&v(e,t,n)?n:null:null}function Q(e,t,n,r=!1){const{itemSelector:i,selectedSlot:a,...s}=n;let l=e.selection;var c;return"itemSelector"in n&&(l=o(e.data,t,i??null)),"selectedSlot"in n&&(a?l=(c=a)?{kind:"slot",parentId:c.parentId,slot:c.slot}:null:"slot"===l?.kind&&(l=null)),{...e,selection:l,ui:r?s:{...e.ui,...s}}}function G(e,t,n){const o=_(e,t,n);if(o===e)return e;const r=J(o.data,n,o.selection);return r===o.selection?o:{...o,selection:r}}function _(e,t,n){const{data:o}=e;switch(t.type){case"setData":{const n="function"==typeof t.data?t.data(o):t.data;return{...e,data:{...o,...n}}}case"setUi":return Q(e,n,"function"==typeof t.ui?t.ui(U(e,n)):t.ui);case"set":{const r={data:o,ui:U(e,n)},i="function"==typeof t.state?t.state(r):t.state;let a=i.data?{...e,data:i.data}:e;return i.ui&&(a=Q(a,n,i.ui,!0)),a}case"insert":{const r={...w(t.destinationZone),index:t.destinationIndex},i=I(n,t.componentType,{},t.id?{id:t.id}:{});return{...e,data:C(o,n,r,i)}}case"replace":{const r=q(o,n,t.destinationZone,t.destinationIndex,"replace");if(r.props.id!==t.data.props.id)throw new Error("Can't change the id during a replace action. Use remove and insert for a new node.");return{...e,data:S(o,n,r.props.id,t.data)}}case"replaceRoot":{const n={...o.root,props:{...o.root.props,...t.root.props},readOnly:t.root.readOnly};return{...e,data:{...o,root:n}}}case"duplicate":{const r=q(o,n,t.sourceZone,t.sourceIndex,"duplicate"),i=b(o,n,r.props.id),a=X(i,n,t.sourceZone,t.sourceIndex+1);return{...e,data:i,selection:a?{kind:"node",id:a.props.id}:e.selection}}case"reorder":return _(e,{...t,type:"move",sourceZone:t.destinationZone},n);case"move":{if(t.sourceZone===t.destinationZone&&t.sourceIndex===t.destinationIndex)return e;const r=X(o,n,t.sourceZone,t.sourceIndex);if(!r)return e;const i={...w(t.destinationZone),index:t.destinationIndex};return{...e,data:k(o,n,r.props.id,i)}}case"remove":{const r=q(o,n,t.zone,t.index,"remove");return{...e,data:y(o,n,r.props.id)}}default:return e}}var ee={drag:!0,duplicate:!0,delete:!0,edit:!0,insert:!0},te={leftSideBarVisible:!0,rightSideBarVisible:!0,arrayState:{},componentList:{},isDragging:!1,previewMode:"edit",viewports:{current:{width:360,height:"auto"},options:[],controlsVisible:!0},field:{focus:null}},ne=0,oe=()=>`history-${ne+=1}`;function re(e){let t=e.config;const r=e.now??(()=>Date.now()),i=e.historyCoalesceMs??250;let a=e.permissions??{};const s=E(e.data,t);let l={data:s,selection:null,ui:{...te}};if(e.ui){const{itemSelector:n,selectedSlot:r,...i}=e.ui;l={data:s,selection:r?{kind:"slot",...r}:o(s,t,n??null),ui:{...te,...i}}}let c=[{core:l,at:-1/0,sealed:!0,id:oe()}],d=0;const u=e=>{const t=c[d],n=r();!e&&d===c.length-1&&d>0&&!t.sealed&&n-t.at<i?c=[...c.slice(0,d),{...t,core:l,at:n}]:(c=[...c.slice(0,d+1),{core:l,at:n,sealed:e,id:oe()}],d=c.length-1)},p=/* @__PURE__ */new Set;let f=null,h=null,g=0,y=null,w=!1;const k=()=>{for(const e of[...p])e()},b=()=>{c=[...c.slice(0,d),{...c[d],core:l},...c.slice(d+1)]},I=(t,n)=>{g>0?w=w||n:(n?u(!1):l!==t&&b(),l.data!==t.data&&e.onChange?.(l.data),l!==t&&k())},C=e=>{const n=l;if(l=G(l,e,t),l===n)return;const o=e.recordHistory??W(e);I(n,o&&l.data!==n.data)},O=t=>{0===g&&(y=l,w=!1),g+=1;try{t()}catch(e){throw g-=1,0===g&&y&&(l=y,y=null),e}if(g-=1,g>0||!y)return;const n=y;y=null,w&&l.data!==n.data?u(!0):l!==n&&b(),l.data!==n.data&&e.onChange?.(l.data),l!==n&&k()},P=e=>{const n=l,o=J(l.data,t,e);var r,i;(r=o,i=l.selection,r===i||r&&i&&r.kind===i.kind&&("node"===r.kind&&"node"===i.kind?r.id===i.id:"slot"===r.kind&&"slot"===i.kind&&r.parentId===i.parentId&&r.slot===i.slot))||(l={...l,selection:o},I(n,!1))},A=t=>{const n=l;d=t,l=c[d].core,l.data!==n.data&&e.onChange?.(l.data),l!==n&&k()},M=()=>(e={})=>{const n=e.root?t.root?.permissions:t.components[e.item?.type??e.type??""]?.permissions;return{...ee,...a,...n}};let z=M();const K=x(),N={resolveCache:K,async resolveAll({trigger:e="load",metadata:n}={}){const o=l.data,r={type:"root",props:{...o.root.props??{}}},i=[...o.content,...Object.values(o.zones??{}).flat()],[a,...s]=await Promise.all([D(r,t,{cache:K,trigger:e,metadata:n}),...i.map(o=>D(o,t,{cache:K,trigger:e,metadata:n}))]);O(()=>{const e=l;let n=l.data;s.forEach((e,r)=>{if(!e.didChange)return;const a=i[r].props.id,s=m(n,t,a)?.node;s&&s===m(o,t,a)?.node&&(n=S(n,t,a,e.node))}),a.didChange&&n.root===o.root&&(n={...n,root:{...n.root,props:a.node.props,readOnly:a.node.readOnly??n.root.readOnly}}),n!==l.data&&(l={...l,data:n,selection:J(n,t,l.selection)},I(e,!1))})},async resolveNode(e,{trigger:n="replace",metadata:o}={}){const r=m(l.data,t,e)?.node;if(!r)return!1;const i=await D(r,t,{cache:K,trigger:n,metadata:o});if(!i.didChange)return!1;let a=!1;return O(()=>{const n=l;if(m(l.data,t,e)?.node!==r)return;const o=S(l.data,t,e,i.node);o!==l.data&&(l={...l,data:o,selection:J(o,t,l.selection)},I(n,!1),a=!0)}),a},get config(){return t},getState(){if(f&&h===l)return f;const e=l,o={data:e.data,ui:U(e,t)},r="node"===e.selection?.kind?m(e.data,t,e.selection.id)?.node??null:null;return f={appState:o,selection:e.selection,selectedItem:r,config:t,dispatch:C,history:{back:()=>N.undo(),forward:()=>N.redo(),hasPast:d>0,hasFuture:d<c.length-1,histories:c.map(e=>({id:e.id,state:{data:e.core.data,ui:U(e.core,t)}})),index:d,setHistoryIndex:e=>{e>=0&&e<c.length&&e!==d&&A(e)}},getPermissions:z,getItemById:n=>m(e.data,t,n)?.node,getItemBySelector:n=>function(e,t,n){const[o,r]=(n.zone??"root:default-zone").split(/:(.*)/s);return v(e,t,{parentId:o,slot:r})?.[n.index]}(e.data,t,n),getSelectorForId:o=>{const r=n(e.data,t,{kind:"node",id:o});return r?{index:r.index,zone:r.zone??"root:default-zone"}:void 0}},h=e,f},subscribe:e=>(p.add(e),()=>{p.delete(e)}),dispatch:C,batch:O,group:()=>{const e=d,t=c[e].id;let n=!0;return{close:()=>{if(!n)return;if(n=!1,c[e]?.id!==t)return;if(d<=e+1)return void(d===e+1&&(c=[...c.slice(0,d),{...c[d],sealed:!0},...c.slice(d+1)]));const o=c[d];c=[...c.slice(0,e+1),{...o,sealed:!0},...c.slice(d+1)],d=e+1}}},select:e=>P(e?{kind:"node",id:e}:null),selectSlot:e=>P(e?{kind:"slot",parentId:e.parentId,slot:e.slot}:null),run(e){O(()=>{const n=l,o=void 0===e.select?l.selection:e.select;l={...l,data:e.data,selection:J(e.data,t,o)},I(n,e.data!==n.data)})},load(e,n={}){const o=l,r=E(e,t);l={...l,data:r,selection:J(r,t,n.selection??l.selection)},n.keepHistory||(c=[{core:l,at:-1/0,sealed:!0,id:oe()}],d=0),l!==o&&k()},undo(){d>0&&A(d-1)},redo(){d<c.length-1&&A(d+1)},setPermissions(e){(function(e,t){if(e===t)return!0;const n=Object.keys(e);return n.length===Object.keys(t).length&&n.every(n=>e[n]===t[n])})(e,a)||(a=e,z=M(),f=null,k())},setConfig(e){e!==t&&(t=e,z=M(),f=null,k())}};return N}function ie(e,t,n={}){const o=e=>{if(e.altKey)return;if(!(e.metaKey!==e.ctrlKey))return;const o="KeyZ"===e.code,r="KeyY"===e.code&&!e.shiftKey;(o||r)&&(n.leaveTyping&&u(e.target)||!1!==t.getState?.().getPermissions().edit&&(e.preventDefault(),r||e.shiftKey?t.redo():t.undo()))};return e.addEventListener("keydown",o),()=>e.removeEventListener("keydown",o)}var ae=z(null),se=z(!0);function le({easel:e,hotkeys:t=!0,resolveOnMount:n=!0,children:o}){return K(()=>{n&&e.resolveAll()},[e,n]),K(()=>{if(t&&"undefined"!=typeof document)return ie(document,e)},[e,t]),/* @__PURE__ */V(ae.Provider,{value:e,children:/* @__PURE__ */V(se.Provider,{value:t,children:o})})}function ce(){const e=N(ae);if(!e)throw new Error("useEasel: no <EaselProvider> above this component");return e}function de(e){const t=ce(),n=$({view:null,selector:null,value:void 0,has:!1}),o=()=>{const o=t.getState(),r=n.current;if(r.has&&r.view===o&&r.selector===e)return r.value;const i=e(o);return r.has&&Object.is(r.value,i)?(n.current={view:o,selector:e,value:r.value,has:!0},r.value):(n.current={view:o,selector:e,value:i,has:!0},i)};return j(t.subscribe,o,o)}function ue(){return function(e){return de(e)}}var pe="data-puck-component",fe="data-puck-dropzone",he={},me="data-es-mirror",ge="undefined"==typeof window?K:Z;function ve(e,t,n){for(const e of Array.from(t.head.querySelectorAll(`[${me}]`)))e.remove();for(const o of Array.from(e.head.querySelectorAll('style, link[rel="stylesheet"]'))){const e=o.cloneNode(!0);e.setAttribute(me,""),n&&e.setAttribute("nonce",n),t.head.appendChild(e)}}function ye({children:t,id:n="preview-frame",title:o,className:r,style:i,mirrorStyles:a=!0,onDocument:s,height:l="auto",nonce:u}){const p=c("canvas",e),f=$(null),[h,m]=B(null);return ge(()=>{const e=f.current,t=h?.ownerDocument.defaultView;if("auto"!==l||!e||!h||!t)return;const n=()=>{e.style.height=`${Math.ceil(h.getBoundingClientRect().height)}px`};n();const o=t.ResizeObserver,r=o?new o(n):null;return r?.observe(h),()=>r?.disconnect()},[h,l]),ge(()=>{let e=f.current?.contentDocument;if(!e)return;"CSS1Compat"!==e.compatMode&&(e.open(),e.write("<!DOCTYPE html><html><head></head><body></body></html>"),e.close(),e=f.current?.contentDocument??e),e.body||e.documentElement.appendChild(e.createElement("body")),e.body.style.margin="0";const t=e.createElement("div");t.setAttribute("data-puck-entry",""),t.id="frame-root","fill"===l&&t.classList.add("es-frame-fill"),e.body.appendChild(t),d(e,u),m(t),s?.(e);let n=null;const o=f.current?.ownerDocument;if(a&&o){ve(o,e,u);const t=o.defaultView;t&&"MutationObserver"in t&&(n=new t.MutationObserver(()=>ve(o,e,u)),n.observe(o.head,{childList:!0,subtree:!0,characterData:!0}))}return()=>{n?.disconnect(),t.remove(),m(null),s?.(null)}},[]),/* @__PURE__ */V("iframe",{ref:f,id:n,title:o??p.frame,className:["es-canvas-frame","fill"===l?"is-fill":"",r??""].filter(Boolean).join(" "),style:i,children:h?T(t,h):null})}var we=z(null),ke=z(he),be=[];function Se({parentId:e,slot:t,className:n,style:o,minEmptyHeight:r=128,minEmptyWidth:i=120}){const a=ce(),s=de(n=>v(n.appState.data,a.config,{parentId:e,slot:t})??be),l=de(t=>"node"===t.selection?.kind&&t.selection.id===e&&e!==g),c=de(n=>"slot"===n.selection?.kind&&n.selection.parentId===e&&n.selection.slot===t),d=N(we),u=["es-zone"];return s.length&&u.push("has-children"),e===g&&u.push("is-root"),(l||c)&&u.push("is-area-selected"),null!==d&&d===e&&e!==g&&u.push("is-hovering-area"),n&&u.push(n),/* @__PURE__ */V("div",{className:u.join(" "),[fe]:`${e}:${t}`,style:{...o,"--min-empty-height":`${r}px`,"--min-empty-width":`${i}px`},children:s.map(e=>/* @__PURE__ */V(Ee,{node:e},e.props.id))})}function Ie(e,t){return L(()=>{const n={};for(const o of P(A(e)))n[o]=function(e={}){/* @__PURE__ */
2
+ return V(Se,{parentId:t,slot:o,...e})};return n},[e,t])}function Ce(e){return L(()=>function({zone:t,...n}){/* @__PURE__ */
3
+ return V(Se,{parentId:e,slot:t,...n})},[e])}function Ee({node:e}){const t=ce().config.components[e.type],n=e.props.id,o=function(e){const t=$(null);return L(()=>n=>{const o=t.current;o&&o!==n&&(o.removeAttribute(pe),o.removeAttribute("data-puck-dnd")),t.current=n,n&&(n.setAttribute(pe,e),n.setAttribute("data-puck-dnd",e),n.style.position="relative")},[e])}(n),r=N(ke),i=Ie(t,n),a=Ce(n);if(!t?.render)return null;const s=t.render,l={...M(t),...e.props,...i},c={renderDropZone:a,isEditing:!0,dragRef:t.inline?o:null,metadata:{...r,...t.metadata}};return t.inline?/* @__PURE__ */V(s,{...l,puck:c,editMode:!0}):/* @__PURE__ */V("div",{[pe]:n,"data-puck-dnd":n,style:{position:"relative"},children:/* @__PURE__ */V(s,{...l,puck:c,editMode:!0})})}function xe({metadata:e}){const t=de(e=>e.config),n=de(e=>e.appState.data.root).props??{},o=t.root?.render,r=Ie(t.root,g),i=Ce(g),a=/* @__PURE__ */V(Se,{parentId:g,slot:O}),s=o?/* @__PURE__ */V(o,{id:"puck-root",...n,...r,puck:{renderDropZone:i,isEditing:!0,dragRef:null,metadata:e??{}},editMode:!0,children:a}):a;/* @__PURE__ */
4
+ return V(ke.Provider,{value:e??he,children:s})}var De=z(void 0);function Oe(e,t,n){const[o,r]=B(null),i=$(t);return i.current=t,ge(()=>{const t=e.current?.ownerDocument,n=t?.defaultView;if(!t||!n||!i.current)return void r(null);let o=0;const a=()=>{o=0;const n=function(e,t){if(!e||!t)return null;const n=h(e),o=t.getBoundingClientRect();return{top:n.top-o.top,left:n.left-o.left,width:n.width,height:n.height}}(i.current?i.current(t):null,e.current?.parentElement??null);r(e=>{return(t=e)===(o=n)||t&&o&&t.top===o.top&&t.left===o.left&&t.width===o.width&&t.height===o.height?e:n;var t,o})},s=()=>{o||(o=(n.requestAnimationFrame??(e=>n.setTimeout(e,16)))(a))};a();const l="MutationObserver"in n?new n.MutationObserver(s):null;l?.observe(t.body,{childList:!0,subtree:!0,attributes:!0,characterData:!0});const c="ResizeObserver"in n?new n.ResizeObserver(s):null;return c?.observe(t.documentElement),n.addEventListener("resize",s),()=>{l?.disconnect(),c?.disconnect(),n.removeEventListener("resize",s),o&&(n.cancelAnimationFrame??n.clearTimeout)(o)}},[n]),o}function Pe({id:e,kind:t,overlay:n}){const o=$(null),r=Oe(o,e?t=>t.querySelector(`[${pe}="${t.defaultView?.CSS?.escape?t.defaultView.CSS.escape(e):e}"]`):null,e),i=/* @__PURE__ */V("div",{ref:o,"aria-hidden":"true",className:`es-canvas-outline is-${t}`,style:r?{position:"absolute",top:r.top,left:r.left,width:r.width,height:r.height}:{display:"none"}});return n&&e?/* @__PURE__ */V(n,{componentId:e,kind:t,children:i}):i}function Ae(e,t,n){const o=l(e,n),r=o.text.length,i=e.ownerDocument;if(!t)return[r,r];let a=null;const s=i.caretPositionFromPoint?.(t.x,t.y);if(s&&e.contains(s.offsetNode))a=o.at(s.offsetNode,s.offset);else{const n=i.caretRangeFromPoint?.(t.x,t.y);n&&e.contains(n.startContainer)&&(a=o.at(n.startContainer,n.startOffset))}if(null===a)return[r,r];const c=o.text;let d=a,u=a;for(;d>0&&!/\s/.test(c[d-1]);)d-=1;for(;u<c.length&&!/\s/.test(c[u]);)u+=1;return[d,u]}function Me({s:e,element:t,toolbar:n,label:o}){const r=e.pressed(),i=new Set(n.offered.filter(e=>"link"!==e));/* @__PURE__ */
5
+ return V(H,{anchor:()=>{const e=t();if(!e)return null;const n=e.getBoundingClientRect(),o=e.ownerDocument.defaultView?.frameElement,r=o?p(o,{left:n.left,top:n.top,width:n.width,height:n.height}):{left:n.left,top:n.top,width:n.width,height:n.height};return{left:r.left-6,top:r.top-6,right:r.left+r.width+6,bottom:r.top+r.height+6}},bounds:()=>{const e=t(),n=e?.ownerDocument.defaultView?.frameElement,o=(n??e?.closest(".es-canvas")??e)?.getBoundingClientRect();return o?{left:o.left,top:o.top,right:o.right,bottom:o.bottom}:{left:0,top:0,right:window.innerWidth,bottom:window.innerHeight}},"aria-label":o,children:/* @__PURE__ */V("div",{style:{width:"18rem"},children:/* @__PURE__ */V(Y,{offered:i,pressed:r.marks,onMark:t=>{"link"!==t&&e.press(t)},list:{pressed:r.list,onList:t=>e.list(t)},alignment:n.alignment,letterCase:n.letterCase,last:n.lastTool?.({className:"rosh-tb-btn",disabled:!1,selected:r.selected,keepCaret:t=>{t.preventDefault(),e.hold()},insert:t=>e.insert(t)})})})})}function ze({element:e}){const t=$(null),n=Oe(t,()=>e(),e);/* @__PURE__ */
6
+ return V("div",{ref:t,"aria-hidden":"true",className:"es-canvas-outline is-typing",style:n?{position:"absolute",top:n.top,left:n.left,width:n.width,height:n.height}:{display:"none"}})}function Ke({frame:t=!0,className:n,style:o,metadata:r,mirrorStyles:l,onDocument:d,height:u,title:p,nonce:h,hotkeys:m,frameWrapper:g,overlay:v,children:y,typing:w,passThrough:k}){const b=ce(),S=N(De),I=k??S,C=N(se),E=c("canvas",e),x=m??C,[D,O]=B(void 0),P=de(e=>"node"===e.selection?.kind?e.selection.id:null),[A,M]=B(null),[z,j]=B(null),L=$(null),[,R]=B(0),Z=$(w);Z.current=w;const T=$(null),H=e=>{const t=T.current?.ownerDocument,n=t?.defaultView?.CustomEvent;t&&n&&t.dispatchEvent(new n(f,{detail:{typing:e}}))},Y=(e,t)=>{L.current?.s.stop("stop");const n=e.element();if(!n)return!1;const o=b.group(),r=e.element,i=s({element:r,value:e.value,rules:e.rules,multiline:e.multiline,skip:e.skip,caret:Ae(n,t,e.skip),write:e.write,remount:e.remount,onSelect:()=>R(e=>e+1),end:e=>{o.close(),L.current?.element===r&&(L.current=null),j(null),H(!1),Z.current?.onChange?.({typing:!1,why:e})}});if(!i)return o.close(),!1;const a=n.closest?.(`[${pe}]`)?.getAttribute(pe);return a&&b.select(a),L.current={s:i,element:r,target:e},j(()=>r),M(null),H(!0),Z.current?.onChange?.({typing:!0,element:n}),!0};K(()=>()=>L.current?.s.stop("stop"),[]);const W=e=>{const t=L.current?.element();return Boolean(t&&t.contains(e))},X=e=>{const t=e.closest?.(`[${pe}]`)?.getAttribute(pe);if(!t)return;const n=b.getState(),o="node"===n.selection?.kind?n.selection.id:null;return a(n.appState.data,b.config,t,o,I)??t},q=e=>{if("Enter"!==e.key||e.defaultPrevented||e.shiftKey||e.metaKey||e.ctrlKey||e.altKey)return;if(L.current)return;const t=e.target;if(t?.isContentEditable||t?.closest?.("input, textarea, select, button"))return;const n=Z.current?.atSelection?.();n&&Y(n,null)&&e.preventDefault()},U=/* @__PURE__ */F("div",{ref:T,className:"es-canvas-content",style:{position:"relative"},onClick:e=>{const t=e.target;if(t.closest?.("a[href]")&&e.preventDefault(),L.current){if(W(t))return;L.current.s.stop("outside")}const n=X(t);void 0===n?t.hasAttribute?.(fe)||b.select(null):b.select(n)},onDoubleClick:e=>{const t=Z.current;if(!t||W(e.target))return;const n=t.at(e.target);n&&Y(n,{x:e.clientX,y:e.clientY})&&e.preventDefault()},onKeyDown:e=>q(e),onMouseOver:e=>{if(L.current)return;const t=X(e.target)??null;t!==A&&M(t)},onMouseLeave:()=>M(null),children:[
7
+ /* @__PURE__ */V(we.Provider,{value:A,children:/* @__PURE__ */V(xe,{metadata:r})}),
8
8
  /* @__PURE__ */F("div",{className:"es-canvas-outlines",style:{position:"absolute",top:0,left:0,pointerEvents:"none"},children:[
9
- /* @__PURE__ */V(Ae,{id:!z&&P&&P!==A?P:null,kind:"hover",overlay:v}),
10
- /* @__PURE__ */V(Ae,{id:z?null:A,kind:"selected",overlay:v}),z?/* @__PURE__ */V(ze,{element:z}):null]}),y]}),J=g?/* @__PURE__ */V(g,{document:D,children:U}):U;K(()=>{if(D&&x)return ie(D,b)},[D,x,b]),K(()=>{if(!D)return;const e=e=>{if("Enter"===e.key)return void q(e);if("Escape"!==e.key||e.defaultPrevented)return;const t=e.target;if(t?.isContentEditable||t?.closest?.("input, textarea, select"))return;const n=b.getState();if("node"!==n.selection?.kind)return;const o=i(n.appState.data,b.config,n.selection);"node"===o?.kind&&b.select(o.id)};return D.addEventListener("keydown",e),()=>D.removeEventListener("keydown",e)},[D,b]);/* @__PURE__ */
11
- return F("div",{className:"es-canvas"+(n?` ${n}`:""),style:o,"data-puck-preview":"","data-es-typing":z?"":void 0,children:[z&&N.current?.target.toolbar?/* @__PURE__ */V(Me,{s:N.current.s,element:N.current.element,toolbar:N.current.target.toolbar,label:E.textTools}):null,t?/* @__PURE__ */V(ye,{mirrorStyles:l,onDocument:e=>{O(e??void 0),d?.(e)},height:u,title:p,nonce:h,children:J}):/* @__PURE__ */V("div",{id:"preview-frame","data-puck-entry":"",children:J})]})}function $e(e={}){const t=ce(),n=de(e=>e.appState.data);return r({...e,data:n,config:t.config,commit:(e,{select:n})=>t.run({data:e,select:n})})}function je(){const e=ce(),n=de(e=>e.config),o=e.resolveCache,r=de(e=>e.selectedItem),i=de(e=>e.appState.data.root),a=r?r.props.id:"root",s=i.props??{},l=N(()=>r||{type:"root",props:s},[r,s]),c=r?n.components[r.type]:n.root,d=e.getState(),u=r?m(d.appState.data,n,a):null,p=u&&"root"!==u.place.parentId?u.place.parentId:null,f=p?d.getItemById(p)??null:null,{fields:h}=t({id:a,node:l,block:c,parent:f,appState:d.appState}),g=de(e=>!1===e.getPermissions(r?{item:r}:{root:!0}).edit),v=R((t,r)=>{(async()=>{const i=e.getState();if("root"!==a){const s=i.getItemById(a),l=i.getSelectorForId(a);if(!s||!l)return;const c={...s,props:{...s.props,[t]:r}},{node:d}=await D(c,n,{cache:o,trigger:"replace"}),u=e.getState().getSelectorForId(a);if(!u)return;return void e.dispatch({type:"replace",destinationZone:u.zone??"root:default-zone",destinationIndex:u.index,data:d})}const s=i.appState.data.root.props??{},{node:l}=await D({type:"root",props:{...s,[t]:r}},n,{cache:o,trigger:"replace"});e.dispatch({type:"replaceRoot",root:{props:l.props,readOnly:l.readOnly},recordHistory:!0})})()},[e,n,o,a]);return{id:a,node:l,fields:h,values:l.props,readOnly:g,onChange:v}}export{ye as CanvasFrame,De as CanvasPassThroughContext,te as DEFAULT_UI,Ke as EaselCanvas,le as EaselProvider,xe as EditDocument,ie as bindUndoKeys,re as createEasel,ue as createUseEasel,W as recordsByDefault,G as reduce,U as uiView,de as useEasel,ce as useEaselApi,$e as useEaselNodeOps,je as useSelectedFields,J as validSelection};
9
+ /* @__PURE__ */V(Pe,{id:!z&&A&&A!==P?A:null,kind:"hover",overlay:v}),
10
+ /* @__PURE__ */V(Pe,{id:z?null:P,kind:"selected",overlay:v}),z?/* @__PURE__ */V(ze,{element:z}):null]}),y]}),J=g?/* @__PURE__ */V(g,{document:D,children:U}):U;K(()=>{if(D&&x)return ie(D,b)},[D,x,b]),K(()=>{if(!D)return;const e=e=>{if("Enter"===e.key)return void q(e);if("Escape"!==e.key||e.defaultPrevented)return;const t=e.target;if(t?.isContentEditable||t?.closest?.("input, textarea, select"))return;const n=b.getState();if("node"!==n.selection?.kind)return;const o=i(n.appState.data,b.config,n.selection);"node"===o?.kind&&b.select(o.id)};return D.addEventListener("keydown",e),()=>D.removeEventListener("keydown",e)},[D,b]);/* @__PURE__ */
11
+ return F("div",{className:"es-canvas"+(n?` ${n}`:""),style:o,"data-puck-preview":"","data-es-typing":z?"":void 0,children:[z&&L.current?.target.toolbar?/* @__PURE__ */V(Me,{s:L.current.s,element:L.current.element,toolbar:L.current.target.toolbar,label:E.textTools}):null,t?/* @__PURE__ */V(ye,{mirrorStyles:l,onDocument:e=>{O(e??void 0),d?.(e)},height:u,title:p,nonce:h,children:J}):/* @__PURE__ */V("div",{id:"preview-frame","data-puck-entry":"",children:J})]})}function Ne(e={}){const t=ce(),n=de(e=>e.appState.data);return r({...e,data:n,config:t.config,commit:(e,{select:n})=>t.run({data:e,select:n})})}function $e(){const e=ce(),n=de(e=>e.config),o=e.resolveCache,r=de(e=>e.selectedItem),i=de(e=>e.appState.data.root),a=r?r.props.id:"root",s=i.props??{},l=L(()=>r||{type:"root",props:s},[r,s]),c=r?n.components[r.type]:n.root,d=e.getState(),u=r?m(d.appState.data,n,a):null,p=u&&"root"!==u.place.parentId?u.place.parentId:null,f=p?d.getItemById(p)??null:null,{fields:h}=t({id:a,node:l,block:c,parent:f,appState:d.appState}),g=de(e=>!1===e.getPermissions(r?{item:r}:{root:!0}).edit),v=R(t=>{(async()=>{const r=e.getState();if("root"!==a){const i=r.getItemById(a),s=r.getSelectorForId(a);if(!i||!s)return;const l={...i,props:{...i.props,...t}},{node:c}=await D(l,n,{cache:o,trigger:"replace"}),d=e.getState().getSelectorForId(a);if(!d)return;return void e.dispatch({type:"replace",destinationZone:d.zone??"root:default-zone",destinationIndex:d.index,data:c})}const i=r.appState.data.root.props??{},{node:s}=await D({type:"root",props:{...i,...t}},n,{cache:o,trigger:"replace"});e.dispatch({type:"replaceRoot",root:{props:s.props,readOnly:s.readOnly},recordHistory:!0})})()},[e,n,o,a]),y=R((e,t)=>v({[e]:t}),[v]);return{id:a,node:l,fields:h,values:l.props,readOnly:g,onChange:y,onChangeMany:v}}export{ye as CanvasFrame,De as CanvasPassThroughContext,te as DEFAULT_UI,Ke as EaselCanvas,le as EaselProvider,xe as EditDocument,ie as bindUndoKeys,re as createEasel,ue as createUseEasel,W as recordsByDefault,G as reduce,U as uiView,de as useEasel,ce as useEaselApi,Ne as useEaselNodeOps,$e as useSelectedFields,J as validSelection};
@@ -1 +1 @@
1
- var e={groups:{heading:"Headings",body:"Body"},add:{heading:"+ Add heading",body:"+ Add body"},count:({n:e,max:a})=>`${e} / ${a}`,full:({kind:e,max:a})=>`Up to ${a} ${e} styles`,styleName:({kind:e,n:a})=>`${"heading"===e?"Heading":"Body"} ${a}`,remove:"Delete",removeNamed:({name:e})=>`Delete ${e}`,sample:"The quick brown fox jumps over the lazy dog",preview:"Preview",summary:({font:e,size:a,weight:t})=>`${e} · ${a} · ${t}`,px:({n:e})=>`${e} px`,auto:"Auto",weights:{thin:"Thin",extraLight:"Extra light",light:"Light",regular:"Regular",medium:"Medium",semibold:"Semibold",bold:"Bold",extraBold:"Extra bold",black:"Black"},settings:{font:"Font",color:"Color",size:"Font size",weight:"Weight",emphasis:"Style",lineSpacing:"Line spacing",letterSpacing:"Letter spacing",paragraphSpacing:"Paragraph spacing",letterCase:"Letter case",largestSize:"Largest size"},bold:"Bold",italic:"Italic",italicMissing:"Italic: this font has no italic loaded",case:{auto:"Auto",autoTitle:"Auto: as each section draws it",none:"As typed",upper:"Uppercase",lower:"Lowercase"},colour:{any:"Any color",follows:"Follows the style"}};export{e as DEFAULT_TEXT_STYLES_WORDS};
1
+ var e={groups:{heading:"Headings",body:"Body"},add:{heading:"+ Add heading",body:"+ Add body"},count:({n:e,max:a})=>`${e} / ${a}`,full:({kind:e,max:a})=>`Up to ${a} ${e} styles`,styleName:({kind:e,n:a})=>`${"heading"===e?"Heading":"Body"} ${a}`,remove:"Delete",removeNamed:({name:e})=>`Delete ${e}`,sample:"The quick brown fox jumps over the lazy dog",preview:"Preview",summary:({font:e,size:a,weight:t})=>`${e} · ${a} · ${t}`,px:({n:e})=>`${e} px`,auto:"Auto",weights:{thin:"Thin",extraLight:"Extra light",light:"Light",regular:"Regular",medium:"Medium",semibold:"Semibold",bold:"Bold",extraBold:"Extra bold",black:"Black"},settings:{font:"Font",color:"Color",size:"Font size",weight:"Weight",emphasis:"Style",lineSpacing:"Line spacing",letterSpacing:"Letter spacing",paragraphSpacing:"Paragraph spacing",letterCase:"Letter case",largestSize:"Largest size"},bold:"Bold",italic:"Italic",italicMissing:"Italic: this font has no italic loaded",case:{auto:"Auto",autoTitle:"Auto: as each section draws it",none:"As typed",upper:"Uppercase",capitalize:"Capitalized",lower:"Lowercase"},colour:{any:"Any color",follows:"Follows the style"}};export{e as DEFAULT_TEXT_STYLES_WORDS};
@@ -1 +1 @@
1
- import{useSectionOps as o}from"./chunk-K2YSFVOJ.js";import{decodePartId as e,encodePartId as r}from"./chunk-IYT6NN2J.js";import{usePreviewParts as t}from"./chunk-I54UCYOU.js";import{SELECTION_MODE as n}from"./chunk-LGDQLTJW.js";import{useEasel as p}from"./chunk-K5744MTM.js";import{useCallback as d,useEffect as c}from"react";var s=o=>"part"===o.kind;function m({mode:m,setMode:i,onOpenPart:a}){const{getSelectorForId:u}=p(o=>o),I=o(),{setSelectedPartId:f,setSelectHandler:k}=t(),l=d(o=>{const r=e(o);if(!r)return;const{nodeId:t,propKey:p}=r;p?(i(o=>s(o)&&o.nodeId===t&&o.propKey===p?o:{kind:"part",nodeId:t,propKey:p}),a?.(t)):i(o=>"part"===o.kind?n:o)},[i,a]);c(()=>{k(l)},[k,l]);const K=s(m)?r(m.nodeId,m.propKey):null;c(()=>{f(K)},[K,f]);return{selectNode:d(o=>{i(()=>n);const e=u(o);e&&I.select(e)},[i,u,I]),openPartId:K}}export{m as usePartBridge};
1
+ import{useSectionOps as o}from"./chunk-ERA3XM2U.js";import{decodePartId as e,encodePartId as r}from"./chunk-IYT6NN2J.js";import{usePreviewParts as t}from"./chunk-I54UCYOU.js";import{SELECTION_MODE as n}from"./chunk-7O6MDCDU.js";import{useEasel as p}from"./chunk-M32O2WRM.js";import{useCallback as d,useEffect as c}from"react";var s=o=>"part"===o.kind;function m({mode:m,setMode:i,onOpenPart:a}){const{getSelectorForId:u}=p(o=>o),I=o(),{setSelectedPartId:f,setSelectHandler:k}=t(),l=d(o=>{const r=e(o);if(!r)return;const{nodeId:t,propKey:p}=r;p?(i(o=>s(o)&&o.nodeId===t&&o.propKey===p?o:{kind:"part",nodeId:t,propKey:p}),a?.(t)):i(o=>"part"===o.kind?n:o)},[i,a]);c(()=>{k(l)},[k,l]);const h=s(m)?r(m.nodeId,m.propKey):null;c(()=>{f(h)},[h,f]);return{selectNode:d(o=>{i(()=>n);const e=u(o);e&&I.select(e)},[i,u,I]),openPartId:h}}export{m as usePartBridge};
@@ -1,4 +1,4 @@
1
- import{blockRuns as e}from"./chunk-HQ4VVRIC.js";import{useScreenBlockLook as r}from"./chunk-LGDQLTJW.js";import{DEFAULT_SCREEN_WORDS as s}from"./chunk-JTUUIVBZ.js";import{useWords as t}from"./chunk-MFIRYGHW.js";import{DropdownMenu as n}from"efficient-shell/ui";import{jsxs as c,Fragment as i,jsx as o}from"react/jsx-runtime";function l({choices:l,onPick:p}){const{Icon:a}=r(),m=t("screen",s),u=e(l).flatMap(e=>[...e.group?[{type:"label",key:`group:${e.group}`,label:/* @__PURE__ */c(i,{children:[e.group," ",
1
+ import{blockRuns as e}from"./chunk-HQ4VVRIC.js";import{useScreenBlockLook as r}from"./chunk-7O6MDCDU.js";import{DEFAULT_SCREEN_WORDS as s}from"./chunk-JTUUIVBZ.js";import{useWords as t}from"./chunk-MFIRYGHW.js";import{DropdownMenu as n}from"efficient-shell/ui";import{jsxs as c,Fragment as i,jsx as o}from"react/jsx-runtime";function l({choices:l,onPick:p}){const{Icon:a}=r(),m=t("screen",s),u=e(l).flatMap(e=>[...e.group?[{type:"label",key:`group:${e.group}`,label:/* @__PURE__ */c(i,{children:[e.group," ",
2
2
  /* @__PURE__ */o("span",{className:"sf-menugroup-count",children:e.items.length})]})}]:[],...e.items.map(e=>({key:e.type,label:e.label,icon:/* @__PURE__ */o("span",{className:"sf-chip",children:/* @__PURE__ */o(a,{type:e.type,size:13})}),onSelect:()=>p(e.type)}))]);/* @__PURE__ */
3
3
  return o(n,{align:"start",triggerClassName:"sf-add-card",items:u,trigger:/* @__PURE__ */c(i,{children:[
4
4
  /* @__PURE__ */o("span",{className:"sf-plus sf-plus--sm",children:"+"}),m.addBlockMenu]})})}export{l as AddBlockRow};
@@ -1,4 +1,4 @@
1
- import{useScreenOwnerName as e}from"./chunk-LGDQLTJW.js";import{settlePanelPick as n}from"./chunk-R6WTQWAC.js";import{MediaPanelHead as i,mediaPickKind as c}from"./chunk-IE55HNMA.js";import{jsxs as o,Fragment as r,jsx as t}from"react/jsx-runtime";function l({panel:l,pick:d,onHide:m}){const p=e();/* @__PURE__ */
1
+ import{useScreenOwnerName as e}from"./chunk-7O6MDCDU.js";import{settlePanelPick as n}from"./chunk-R6WTQWAC.js";import{MediaPanelHead as i,mediaPickKind as c}from"./chunk-IE55HNMA.js";import{jsxs as o,Fragment as r,jsx as t}from"react/jsx-runtime";function l({panel:l,pick:d,onHide:m}){const p=e();/* @__PURE__ */
2
2
  return o(r,{children:[
3
3
  /* @__PURE__ */t(i,{context:p,pick:d?{kind:c(d.accept),field:d.title||void 0}:null,onCancel:()=>d&&n(d.requestId,null),onHide:m}),
4
4
  /* @__PURE__ */t("div",{className:"sf-media-panel",children:/* @__PURE__ */t(l,{pick:d,onPick:e=>d&&n(d.requestId,e)})})]})}export{l as MediaSidePanel};
@@ -1,403 +1,13 @@
1
1
  import * as react from 'react';
2
- import { ReactNode } from 'react';
3
- import { MarkStyle, MarkupTool, WrapResult, InlineRule, MarkedLine } from '../markup/index.js';
4
- import { C as CopyWords, a as CopyAlign } from '../words-dsex49Jh.js';
5
- export { b as COPY_ALIGNS, c as COPY_ALIGN_FIT, d as COPY_ALIGN_GLYPHS, e as COPY_ALIGN_LABELS, f as copyAlignOptions } from '../words-dsex49Jh.js';
6
- import { TextToolbarCase, TextToolbarMark } from 'efficient-shell/ui';
2
+ import { b as CopyBoxProps, c as CopyCell, T as TextBoxHandle } from '../canvas-typing-CJodefPO.js';
3
+ export { d as COPY_CELLS, a as CanvasTypingEnd, e as CanvasTypingOptions, f as CanvasTypingSession, g as ColorWindow, h as CopyBoxAlign, i as CopyBoxFooter, C as CopyBoxLastTool, j as CopyCase, k as CopyCellPreset, l as CopyCells, m as CopyThemeColor, M as MarkBar, n as MarkBarProps, o as MarkWriter, S as SelectionSource, p as TextAreaHandle, q as TextMap, r as ToolbarMark, s as ariaShortcut, t as insertSelection, u as markSelection, v as startCanvasTyping, w as textMap } from '../canvas-typing-CJodefPO.js';
7
4
  export { TextToolbar, TextToolbarProps } from 'efficient-shell/ui';
8
- import { g as FieldOption } from '../types-C97TAUKi.js';
9
- export { C as CanvasTypingEnd, a as CanvasTypingOptions, b as CanvasTypingSession, T as TextMap, s as startCanvasTyping, t as textMap } from '../canvas-typing-Cnvlsh_V.js';
5
+ import { F as FieldOption } from '../types-Dkx1VAIQ.js';
6
+ import { a as CopyAlign } from '../words-dsex49Jh.js';
7
+ export { b as COPY_ALIGNS, c as COPY_ALIGN_FIT, d as COPY_ALIGN_GLYPHS, e as COPY_ALIGN_LABELS, C as CopyWords, f as copyAlignOptions } from '../words-dsex49Jh.js';
8
+ import { InlineRule, MarkStyle, MarkedLine, WrapResult } from '../markup/index.js';
10
9
  import '../buckets-Tj-nkBpg.js';
11
10
 
12
- type CellWords = NonNullable<CopyWords['cells']>;
13
- interface CopyCell {
14
- /** Which cell this is — a stable key for the grid. */
15
- key: string;
16
- /** The cell's name, from the copy words (the four the design draws)… */
17
- nameKey?: Exclude<keyof CellWords, 'tip'>;
18
- /** …or the host's own (a cell the package does not know). */
19
- name?: string;
20
- icon?: ReactNode;
21
- unit?: string;
22
- /** What an arrow or ↑↓ moves by, in SHOWN units. */
23
- step?: number;
24
- /** What Shift moves by. Default ten steps. */
25
- shiftStep?: number;
26
- /** Bounds, in SHOWN units. */
27
- min?: number;
28
- max?: number;
29
- /** Shown = stored × scale (100 for a multiple shown in %). Default 1. */
30
- scale?: number;
31
- /** The STORED value, or `undefined` while the cell follows the style. */
32
- value: number | undefined;
33
- /** The style's STORED value, shown grey while the cell is empty. */
34
- styleValue?: number;
35
- /** A STORED value, or `undefined` when the cell is emptied. */
36
- onChange: (value: number | undefined) => void;
37
- }
38
- /** A cell's preset: everything but its value and its write. */
39
- type CopyCellPreset = Omit<CopyCell, 'value' | 'styleValue' | 'onChange'>;
40
- /** The four cells the final design draws, with its steps and ranges
41
- * (the campaign page's "三个框的规则" table, read 2026-10-06). */
42
- declare const COPY_CELLS: {
43
- fontSize: CopyCellPreset;
44
- lineHeight: CopyCellPreset;
45
- letterSpacing: CopyCellPreset;
46
- paragraphSpacing: CopyCellPreset;
47
- };
48
- declare function CopyCells({ cells, words, readOnly }: {
49
- cells: readonly CopyCell[];
50
- words?: CellWords;
51
- readOnly?: boolean;
52
- }): react.JSX.Element;
53
-
54
- interface CopyThemeColor {
55
- name: string;
56
- label: string;
57
- value: string;
58
- }
59
- declare function ColorWindow({ colors, current, words, onPick, }: {
60
- colors: readonly CopyThemeColor[];
61
- /** The colour the selection wears — a theme name or a hex — or null. */
62
- current: string | null;
63
- words: NonNullable<CopyWords['colors']>;
64
- /** A theme name, a lowercase `#rrggbb`, or null to take the colour off. */
65
- onPick: (color: string | null) => void;
66
- }): react.JSX.Element;
67
-
68
- /** `'b'` → `Meta+B`, `'shift+x'` → `Meta+Shift+X` — the ARIA spelling of a
69
- * shortcut. Meta is what the tooltips promise (⌘); Ctrl works too. */
70
- declare function ariaShortcut(shortcut: string | undefined): string | undefined;
71
- interface MarkBarProps {
72
- /**
73
- * Which buttons to show.
74
- *
75
- * TWO FORMS, and the second is not a convenience — it is the only way a
76
- * product with marks of its OWN can use this bar at all.
77
- *
78
- * `MarkStyle[]` resolved against the shared grammar's `MARKUP_TOOLS`, in
79
- * that order. What the campaign designer passes.
80
- * `MarkupTool[]` used verbatim. What `efficient-storefront` passes.
81
- *
82
- * ⚠️ WHY VERBATIM DESCRIPTORS HAD TO EXIST. The storefront offered SEVEN
83
- * marks: the grammar's four, plus its three word styles (`@@`, `++`, `^^`),
84
- * which then lived only in the shop because the grammar was
85
- * `efficient-shell/markup`. Resolving through `markupTools` can only ever
86
- * return marks the grammar knows, so it silently DROPPED all three — the bar
87
- * rendered four buttons where the panel had seven, and nothing failed to
88
- * compile. Since 2026-09-28 the grammar is ours and holds Quiet (`^^`) and
89
- * reads `@@` / `++` as Emphasis and Strong, but a host may still hand in
90
- * marks of its own.
91
- *
92
- * So a host that has its own marks builds its own descriptors (the shop
93
- * already did: `shopMarkupTools()`) and hands them over whole. The bar's job
94
- * is the ROW — the buttons, the focus guard, the naming, the group — and that
95
- * job does not depend on who defined the mark.
96
- */
97
- tools: readonly MarkStyle[] | readonly MarkupTool[];
98
- onApply: (style: MarkStyle) => void;
99
- disabled?: boolean;
100
- /** Buttons that write no mark, after a divider — see `CopyBoxProps.actions`. */
101
- actions?: ReactNode;
102
- /** The alignment strip, already built by the control. */
103
- align?: ReactNode;
104
- /**
105
- * WHAT A BUTTON IS DRAWN AS, per style. Default: the grammar's own letter —
106
- * `B`, `I`, `S`, `◆` — which is what the campaign designer has always shown.
107
- *
108
- * ⚠️ THIS IS NOT A THEME KNOB, AND IT IS NOT OPTIONAL POLISH. This package
109
- * already says that WHICH buttons and WHAT they write are the grammar's, while
110
- * how they LOOK is the host's, "because this bar has to belong to the
111
- * storefront inspector's chrome and the campaign designer's bar has to belong
112
- * to the portal's". Colour was delegated by tokens on day one; the DRAWING was
113
- * not, and a letter is a drawing. `efficient-storefront` renders each mark as a 14px
114
- * stroked SVG at the weight of its other inspector glyphs, on the stated
115
- * ground that the row should read "as part of the field rather than as
116
- * pasted-in icons" — so without this it could not adopt the bar without losing
117
- * that, which is a regression dressed as a refactor.
118
- *
119
- * The set now HAS a glyph for every mark (0.94.0: bold, italic, strike,
120
- * emphasis, quiet, clear-marks — the owner's call, made 2026-10-02), and they
121
- * are the default. This map stays so a host can still draw its own.
122
- *
123
- * A style the map does not name falls back to the icon set's glyph for it
124
- * (`SET_GLYPH`, 0.94.0, when the owner added the mark glyphs to the set) and
125
- * then to the letter, so a host may override one button and leave the rest.
126
- */
127
- glyphs?: Partial<Record<MarkStyle, ReactNode>>;
128
- /**
129
- * What the group is CALLED. Defaults to "Formatting" (`EaselStrings.copy.formatting`).
130
- *
131
- * A bar bound to one box needs nothing more. A bar SHARED by several rows has
132
- * to say which row it is aimed at, because the visible cue — the marked row —
133
- * is not readable. `efficient-storefront` has that case today.
134
- */
135
- ariaLabel?: string;
136
- /**
137
- * The marks the selection already wears — a button drawn pressed is one
138
- * whose press takes the mark OFF (`markedAt`, the same test `applyMark`
139
- * unwraps by), so the two cannot disagree. A style not named is not pressed;
140
- * with no map at all no button says either way (`aria-pressed` is left off),
141
- * which is what every host that does not track the selection still gets.
142
- */
143
- pressed?: Partial<Record<MarkStyle, boolean>>;
144
- /** The style whose own window is open — the link button while its "Link
145
- * to" window is showing. Drawn pressed, and named as expanded. */
146
- open?: MarkStyle | null;
147
- }
148
- declare function MarkBar({ tools, onApply, disabled, actions, align, glyphs, ariaLabel, pressed, open, }: MarkBarProps): react.JSX.Element | null;
149
-
150
- /**
151
- * Just enough of a text control to read a selection off it. Narrowed to these
152
- * two fields so a caller may hand in a plain object in a test.
153
- *
154
- * A `<textarea>` OR an `<input>` (blueprint 4.9). An input's selection is
155
- * `number | null` where a textarea's is `number`, so the type had to be the
156
- * wider of the two: typed to the textarea, every one-line row in the website
157
- * editor needed a cast or a copy of this file, and the shop kept a copy.
158
- */
159
- type SelectionSource = {
160
- readonly selectionStart: number | null;
161
- readonly selectionEnd: number | null;
162
- } | null;
163
- /**
164
- * How a mark is written. Defaults to the shared grammar's own `applyMark`.
165
- *
166
- * INJECTED RATHER THAN ASSUMED, because the storefront legitimately writes marks
167
- * the shell's grammar does not know: its three word styles (`@@`, `++`, `^^`)
168
- * go through `applyShopMark`, which delegates here for everything else. Making
169
- * the writer a parameter is what lets one control serve both products without
170
- * this package learning a vocabulary that belongs to one of them.
171
- */
172
- type MarkWriter = (text: string, start: number, end: number, style: MarkStyle) => WrapResult;
173
- /** Apply a style to whatever the field has selected. */
174
- declare function markSelection(value: string, style: MarkStyle, el: SelectionSource, write?: MarkWriter): WrapResult;
175
- /**
176
- * Put a literal string where the caret is.
177
- *
178
- * The caret lands AFTER the inserted text and selects nothing, because the thing
179
- * inserted is finished — a merge tag is not a placeholder to type over, and
180
- * leaving it selected invites the next keystroke to delete it.
181
- */
182
- declare function insertSelection(value: string, text: string, el: SelectionSource): WrapResult;
183
-
184
- /** A letter case the toolbar sets on the host's field: the shell toolbar's. */
185
- type CopyCase = TextToolbarCase;
186
- /** The marks row 1 of the toolbar carries: the shell toolbar's. */
187
- type ToolbarMark = TextToolbarMark;
188
- /**
189
- * A handle on the box's textarea.
190
- *
191
- * DECLARED STRUCTURALLY rather than as React's `RefObject`, and the reason is
192
- * the package's `react >=18` peer range. React 18 types read `RefObject<T>` as
193
- * `{ readonly current: T | null }`, React 19's `useRef<T>(null)` produces
194
- * `RefObject<T | null>`, and the interface is covariant in `T` — so the two
195
- * spellings of the same object do not assign to each other, and a package that
196
- * has to compile against both cannot name either one. The shape is the whole
197
- * contract; naming it here costs one line and no version branch.
198
- */
199
- type TextAreaHandle = {
200
- current: HTMLTextAreaElement | null;
201
- };
202
- /**
203
- * A handle on ANY text control the caret machinery can drive — a `<textarea>`
204
- * or a one-line `<input>` (blueprint 4.9). `useCaretEdit` takes this, so a host
205
- * with its own input rows (the website editor's list lines) uses the same
206
- * twelve lines instead of a copy of them. A {@link TextAreaHandle} is one.
207
- */
208
- type TextBoxHandle = {
209
- current: HTMLInputElement | HTMLTextAreaElement | null;
210
- };
211
- /**
212
- * What a host may put UNDER the box, and what it needs to draw it.
213
- *
214
- * A render prop rather than a plain node, for one reason that is not style: the
215
- * campaign's merge-tag chips have to insert at the caret, and only this control
216
- * knows where the caret is. Handing the host `insert` is what lets the chips
217
- * live in the app — where the tag list, the audience call and the product's
218
- * vocabulary belong — while the caret machinery stays here, written once.
219
- *
220
- * `focused` is passed for the same reason the portal tracked it locally: the row
221
- * appears while the merchant is typing in THIS box and not in its neighbour.
222
- */
223
- interface CopyBoxFooter {
224
- focused: boolean;
225
- /** Put a literal string where the caret is, replacing any selection. */
226
- insert: (text: string) => void;
227
- }
228
- /**
229
- * What a host needs to draw its OWN control in row 1's 9th cell of the final
230
- * toolbar ({@link CopyBoxProps.lastTool}) — the campaign designer's Insert
231
- * (merge tags), owner ruling 2026-10-07. The website editor passes nothing.
232
- *
233
- * `className` makes it a cell that looks like its neighbours; `keepCaret` on
234
- * its mousedown keeps the caret and the selection in the box; `insert` writes
235
- * at the caret, as {@link CopyBoxFooter.insert} does.
236
- */
237
- interface CopyBoxLastTool {
238
- className: string;
239
- /** The box is read-only. */
240
- disabled: boolean;
241
- /** Words are selected (not just a caret). */
242
- selected: boolean;
243
- keepCaret: (e: {
244
- preventDefault(): void;
245
- }) => void;
246
- /** Put a literal string where the caret is, replacing any selection. */
247
- insert: (text: string) => void;
248
- }
249
- /**
250
- * The alignment strip, when the host has an alignment to offer.
251
- *
252
- * GENERIC IN THE DIRECTIONS IT ALLOWS, so `onChange` RECEIVES only what the
253
- * host said it could honour. Before this it received the whole union, and a
254
- * host allowing three directions had to narrow a `justify` it had just
255
- * declared impossible before storing. Raised by the strip's first consumer,
256
- * which did write that narrowing; the next one might not.
257
- *
258
- * `A` is inferred from `allow`, so nothing has to be spelled at the call site.
259
- *
260
- * ⚠️ IT DOES NOT FORBID A WIDER HANDLER, and cannot: a function taking the
261
- * whole `CopyAlign` is assignable where one taking three is wanted, because
262
- * parameters are contravariant — and that direction is SAFE, since only the
263
- * three can ever arrive. What this buys is that the narrow handler now
264
- * type-checks without a cast, which is what makes writing the safe one the
265
- * path of least resistance.
266
- */
267
- interface CopyBoxAlign<A extends CopyAlign = CopyAlign> {
268
- value: A | '';
269
- onChange: (next: A) => void;
270
- /**
271
- * Which directions this host can honour. Required and with no default: a
272
- * renderer that cannot justify must not be given a Justify button because a
273
- * default handed it one, which is the shape of mistake this whole card exists
274
- * to stop. It is also what `A` above is inferred from.
275
- */
276
- allow: readonly A[];
277
- /** The strip exists but cannot apply right now. Distinct from the whole
278
- * control being read-only. */
279
- disabled?: boolean;
280
- }
281
- interface CopyBoxProps {
282
- /** The authored string, delimiters and all. The single source of truth. */
283
- value: string;
284
- /** Every keystroke, and every button press. */
285
- onChange: (value: string) => void;
286
- /** The edit is finished and may be written: on blur, and on Enter when
287
- * {@link multiline} is false. */
288
- onCommit?: (value: string) => void;
289
- /** Escape. The argument is the value the box was given when it gained focus;
290
- * the HOST puts it back, because the host owns the string. */
291
- onCancel?: (restored: string) => void;
292
- /** What Enter means — NOT how the text wraps. Both modes soft-wrap. */
293
- multiline?: boolean;
294
- placeholder?: string;
295
- /** Accessible name for the box. */
296
- ariaLabel?: string;
297
- className?: string;
298
- /** Nothing may be typed or pressed. */
299
- readOnly?: boolean;
300
- /**
301
- * The grammar's rule set — `CAMPAIGN_MARKUP` in the designer,
302
- * `STOREFRONT_MARKUP` in the shop, both from `efficient-easel/markup`. It
303
- * decides what the LAYER paints; {@link tools} decides what the BAR offers,
304
- * and a host that lets those two disagree gets a button whose mark draws as
305
- * plain text.
306
- */
307
- rules?: readonly InlineRule[];
308
- /**
309
- * Which mark buttons to show — styles resolved against the shared grammar, or
310
- * the host's own descriptors used verbatim. See `MarkBarProps.tools`. Empty
311
- * draws no bar.
312
- */
313
- tools?: MarkBarProps['tools'];
314
- /**
315
- * How a mark is written. Defaults to the shared grammar's `applyMark`; the
316
- * storefront passes its own so its three word styles reach the same bar.
317
- */
318
- writeMark?: MarkWriter;
319
- /**
320
- * Buttons that are NOT marks, drawn after a divider at the end of the bar.
321
- *
322
- * The storefront's "Clear formatting" is the one that exists: it writes no
323
- * mark at all, so it is not in the grammar's tool list and must not be added
324
- * to it. Drawing it here keeps `MARKUP_TOOLS` meaning "what a mark MEANS".
325
- */
326
- actions?: ReactNode;
327
- /** The alignment strip. Omitted = no strip. */
328
- align?: CopyBoxAlign<CopyAlign>;
329
- /** What each mark button is DRAWN as — see `MarkBarProps.glyphs`. Default is
330
- * the grammar's own letter. */
331
- glyphs?: MarkBarProps['glyphs'];
332
- /** What the formatting group is CALLED — see `MarkBarProps.ariaLabel`. */
333
- barLabel?: string;
334
- /** What goes under the box — see {@link CopyBoxFooter}. */
335
- renderFooter?: (ctx: CopyBoxFooter) => ReactNode;
336
- /**
337
- * When the bar is drawn. `'always'` (the default) keeps it over the box at
338
- * rest. `'focus'` draws it only while this box is being typed in — the text
339
- * box design for 4.9: a column of text settings at rest is a column of
340
- * words, not a column of toolbars.
341
- */
342
- barShows?: 'always' | 'focus';
343
- /**
344
- * Show the EFFECT, not the marks (0.95.0, rulings B + C — the default). A
345
- * many-line box gets a "Show marks" switch under it that flips to the raw
346
- * text with its marks and back; a one-line box is always the effect.
347
- * `false` keeps the 0.94 box (the raw text, painted) with no switch.
348
- *
349
- * ⚠️ In the rich view there is no textarea, so {@link inputRef} holds null.
350
- * Insert at the caret through `renderFooter`'s `insert`, which works in both.
351
- */
352
- richText?: boolean;
353
- /** A many-line box opens with its marks shown. Default false. */
354
- defaultShowMarks?: boolean;
355
- /**
356
- * Which toolbar (E5b). `'final'` — the default — is the design made final
357
- * on 2026-10-06: two rows on one 9-column grid, B · I · U · S · Color ·
358
- * Link · Superscript · Subscript · the host's {@link lastTool} (Undo until
359
- * 2026-10-07) over Left · Center · Right · Justify
360
- * · Bulleted · Numbered · Aa · AA · aa, with the number {@link cells}
361
- * between it and the box. `'classic'` is the bar before it (`MarkBar` and
362
- * the alignment strip), for a host not moved over yet.
363
- */
364
- toolbar?: 'final' | 'classic';
365
- /**
366
- * The theme colours the colour window offers (final toolbar): the NAME
367
- * saved in `[words]{color=name}`, what it is called, and its value. The box
368
- * paints a coloured word with the value (`--es-color-<name>`). The window
369
- * also offers Any color, saved as a hex (`[words]{color=#rrggbb}`). No colours:
370
- * no colour button, and no blank where it was (Lewis 2026-10-13).
371
- */
372
- colors?: readonly CopyThemeColor[];
373
- /** The number cells between the toolbar and the box (final toolbar), each
374
- * the host's value — see `COPY_CELLS`. None: no cells. */
375
- cells?: readonly CopyCell[];
376
- /**
377
- * The host's letter-case field, set by Aa · AA · aa (final toolbar). The
378
- * lit one pressed again writes `''`: no case of its own, the style decides.
379
- * Left out: no case buttons, and no blanks where they were (Lewis
380
- * 2026-10-13). A row with no tool at all is not drawn.
381
- */
382
- letterCase?: {
383
- value: CopyCase | '';
384
- onChange: (next: CopyCase | '') => void;
385
- disabled?: boolean;
386
- };
387
- /**
388
- * Row 1's 9th cell of the final toolbar, drawn by the host (owner ruling
389
- * 2026-10-07: Undo left that cell). Return one control; it is placed in the
390
- * cell as given; one that draws nothing (`null`) leaves no blank. Left
391
- * out, row 1 is eight buttons spread over the row. See
392
- * {@link CopyBoxLastTool}.
393
- */
394
- lastTool?: (slot: CopyBoxLastTool) => ReactNode;
395
- /** A handle on the textarea, for a host that needs one — and the SAME object
396
- * the control uses, so there is never a second ref to reconcile. A plain prop
397
- * rather than `ref`, for the reason `GoldLayer.layerRef` gives. */
398
- inputRef?: TextAreaHandle;
399
- }
400
-
401
11
  declare function CopyBox({ value, onChange, onCommit, onCancel, multiline, placeholder, ariaLabel, className, readOnly, rules, tools, writeMark, actions, align, glyphs, barLabel, renderFooter, inputRef, barShows, richText, defaultShowMarks, toolbar, colors, cells, letterCase, lastTool, }: CopyBoxProps): react.JSX.Element;
402
12
 
403
13
  /** Whether the lines are a list, and which kind. */
@@ -413,6 +23,15 @@ interface TextPartStrip<V extends string> {
413
23
  interface TextPartPanelProps {
414
24
  /** The kept box, on top: a `CopyBox` for words the canvas cannot take. */
415
25
  kept?: CopyBoxProps;
26
+ /** One line under the kept box (what its host tool does, say). A name is
27
+ * never a manual: the hint is where a clause goes (`SettingsField`'s). */
28
+ keptHint?: string;
29
+ /**
30
+ * Nothing can be changed (a sent campaign, a page held by somebody else):
31
+ * every control is shown and disabled, and nothing writes. The kept box is
32
+ * read-only too.
33
+ */
34
+ readOnly?: boolean;
416
35
  style?: {
417
36
  value: string;
418
37
  /** The site's (or the email's) text styles. `description` is the second
@@ -435,7 +54,9 @@ interface TextPartPanelProps {
435
54
  /** A long list (the website's fonts): the field is a search. */
436
55
  searchable?: boolean;
437
56
  };
438
- /** The Italic button at the end of the Font row. `undefined` follows the style. */
57
+ /** The Italic button at the end of the Font row — or, where the host hands
58
+ * no `font` (a phone has no font of its own), on a row of its own named
59
+ * Italic, where the Font row stands. `undefined` follows the style. */
439
60
  italic?: {
440
61
  value: boolean | undefined;
441
62
  styleValue?: boolean;
@@ -448,7 +69,7 @@ interface TextPartPanelProps {
448
69
  list?: TextPartStrip<TextList>;
449
70
  letterCase?: TextPartStrip<TextCase>;
450
71
  }
451
- declare function TextPartPanel({ kept, style, font, italic, cells, align, list, letterCase }: TextPartPanelProps): react.JSX.Element;
72
+ declare function TextPartPanel({ kept, keptHint, readOnly, style, font, italic, cells, align, list, letterCase, }: TextPartPanelProps): react.JSX.Element;
452
73
 
453
74
  interface PasteData {
454
75
  /** The clipboard's `text/html`, when there is one. */
@@ -700,4 +321,4 @@ interface CaretEdit {
700
321
  */
701
322
  declare function useCaretEdit({ target, onChange }: CaretEdit): (edit: (el: HTMLInputElement | HTMLTextAreaElement | null) => WrapResult) => void;
702
323
 
703
- export { COPY_CELLS, type CaretEdit, ColorWindow, CopyAlign, CopyBox, type CopyBoxAlign, type CopyBoxFooter, type CopyBoxLastTool, type CopyBoxProps, type CopyCase, type CopyCell, type CopyCellPreset, CopyCells, type CopyThemeColor, CopyWords, type History, MARKUP_CLIPBOARD_TYPE, MarkBar, type MarkBarProps, type MarkWriter, type PasteData, type PasteOptions, RichBox, type RichBoxProps, type RichEdit, type RichHandle, type RichInputEvent, type RichInputResult, type RichInsert, type RichLayout, type RichLine, type RichPending, type SelectionSource, type Snapshot, TYPING_BURST_MS, type TextAreaHandle, type TextBoxHandle, type TextCase, type TextList, TextPartPanel, type TextPartPanelProps, type TextPartStrip, type ToolbarMark, ariaShortcut, createHistory, editVisible, insertSelection, markSelection, markupOfRange, newLine, pasteToMarkup, richInput, richLayout, selectionToSource, selectionToVisible, setBullet, toSource, toSourceStart, toVisible, useCaretEdit };
324
+ export { type CaretEdit, CopyAlign, CopyBox, CopyBoxProps, CopyCell, type History, MARKUP_CLIPBOARD_TYPE, type PasteData, type PasteOptions, RichBox, type RichBoxProps, type RichEdit, type RichHandle, type RichInputEvent, type RichInputResult, type RichInsert, type RichLayout, type RichLine, type RichPending, type Snapshot, TYPING_BURST_MS, TextBoxHandle, type TextCase, type TextList, TextPartPanel, type TextPartPanelProps, type TextPartStrip, createHistory, editVisible, markupOfRange, newLine, pasteToMarkup, richInput, richLayout, selectionToSource, selectionToVisible, setBullet, toSource, toSourceStart, toVisible, useCaretEdit };