efficient-web-builder 12.0.0 → 13.0.1

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # Changelog
2
2
 
3
+ ## 13.0.1 - 2026-10-15
4
+
5
+ - **A settings band with no row in it is not drawn** (JJ's panel pin,
6
+ approved by GG 2026-10-14). Process Steps drew an empty "Header" band:
7
+ its three text rows (step number, title, description) are in the Text
8
+ band, and its `boxes` slot draws nothing, so the band had a title and
9
+ nothing under it. `bandIsDropped` (`lib/puck/panel-bands`) now drops a
10
+ band with 0 shown rows, as well as §2b.1's band of one labelled row; its
11
+ rows stand alone at that place, as they do for §2b.1. A band with one
12
+ unlabelled row still keeps its band. No data change. Across the 53
13
+ tabbed section panels (default props), 1 band was empty before and 0
14
+ are now.
15
+ - Dev range: `efficient-easel ^7.2.0`, so the guards run on 7.2.0. The
16
+ peer range (`^7.0.4`) is unchanged.
17
+ - Guard: `scripts/test-panel-one-level-bands.tsx` §4 holds the 0-row
18
+ branches; new §6 draws every tabbed section panel as the section screen
19
+ draws it and fails on any band over 0 shown rows.
20
+
21
+ ## 13.0.0 - 2026-10-14
22
+
23
+ **Double-click the words on the canvas to type them where they are** (Lewis 2026-10-14, for Victor; card [DESIGN] Typing On The Canvas). A major only because the `efficient-easel` and `efficient-shell` peer ranges are narrowed (harness CI-3). Also: **the Pages panel's delete-with-Undo now uses the shell's one copy, `toast.undoable`**.
24
+
25
+ ### Changed for merchants
26
+
27
+ - **A double-click on a part's words types them on the page**, in place, with ONE text toolbar floating above them. One click still selects the part and opens its panel. **Enter** on a selected part types it from the keyboard. **Enter** finishes (Shift+Enter makes a new line where the field has lines), and so does **Escape** or a click elsewhere. Nothing typed is thrown away.
28
+ - **The words being typed get one plain box**, like an input: one rectangle round all their lines. The part's thin outline steps away while they are typed, so a heading on three lines no longer shows a stepped outline.
29
+ - **The panel follows the words being typed.** Its text box shows the same words as they change, and puts its own toolbar away until it is clicked, so the toolbar shows ONCE.
30
+ - **One Undo takes back a whole typing session.**
31
+ - **A click on a part's words leaves the keys on the canvas.** The panel's text box no longer takes the caret when the click came from the canvas, so Enter types in place. Opened from anywhere else, it still takes the caret, as before.
32
+ - The canvas toolbar offers the marks the panel's box offers for the same field (bold, italic, underline, strike, superscript, subscript, and the two lists where the field has lines). Link, Colour, Alignment and Letter case stay in the panel for now. Words that only show a grey placeholder are typed in the panel.
33
+
34
+ ### Changed for hosts
35
+
36
+ - **Peer and dev range: `efficient-shell ^7.29.0`.** The Pages panel's delete with Undo now uses the shell's `toast.undoable` (7.29.0): the toast, the 8 seconds, the held server delete and the flush with `keepalive` when the tab closes. It is the one copy every editor uses (the admin's page list too).
37
+ - **Removed `lib/held-page-delete`** (new in 12.0.0, never imported outside this package): it moved to the shell, made generic. `PagesPanel` no longer takes `notify`; the Pages panel draws its own toast, as the shell's toasts do everywhere else. Hosts pass nothing new.
38
+ - **Peer and dev range: `efficient-easel ^7.0.4`.** easel 6.3 to 6.5 type the words in place (`EaselCanvas` `typing`). 7.0.3 keeps a part's panel open while its words are typed. 7.0.4 draws the one plain box on the canvas. On an older easel a host would get typing with the panel jumping away and no box, which is why the range is narrowed rather than left open.
39
+ - **`SiteCanvas` passes `typing`** to `EaselCanvas`. Nothing new to hand over: the words are read off `data-sf-part` and written through the panel's own writer.
40
+ - **New `lib/puck/canvas-typing`**: `partTypingTarget` (a part id to the words, their grammar and lines, the panel's tools and the panel's writer, `commitPartText`, reading the node again on every write), `partTextTools` (the one list of marks, read by the panel's box and the canvas), `partElement`, `keysOnCanvas`, and the part the canvas is typing (`setCanvasTypingPart`, `useCanvasTypingPart`).
41
+ - **`PartTextBox` takes `typedOnCanvas`**: its toolbar shows on focus only while the same words are typed on the canvas.
42
+ - `PART_PICK_CSS` stands the part hairline down on words carrying `data-es-typing`.
43
+
44
+ ### Guards
45
+
46
+ - `test-page-delete-undo` now guards the wiring: `PagesPanel` deletes through `toast.undoable`, the held row stays out of the list until the commit ends, Undo puts it back, and no local copy of the timer or the leave flush is left.
47
+ - New `test-canvas-typing-target`: the field, tools, grammar and writer are the panel's; a write is one replace into the node as it is NOW; a row of a list; nothing to type (a whole section, hidden words, off the page, no one string, a gone node or row) is null; the typed part is held once; the panel's box spells no tool list of its own; the panel takes the caret only when the keys are not on the canvas; the words are followed by their part id after a redraw; the hairline steps away on typed words.
48
+ - Real Chrome, on the packaged website editor (not run in CI): 23 checks, from one click selecting to one Undo taking the session back.
49
+
3
50
  ## 12.0.0 - 2026-10-14
4
51
 
5
52
  **A page deleted in the editor goes at once, and Undo can bring it back** (Lewis 2026-10-14, via GG: "delete without asking, undo instead"; card [BUILD] The Two Ways To Add). A major: the `efficient-easel` and `efficient-shell` peer ranges are narrowed.
@@ -1,10 +1,8 @@
1
- import type { ScreenToastExtra } from "efficient-easel/screen";
2
1
  interface Props {
3
2
  onNavigate: (slug: string) => void;
4
3
  onClose: () => void;
5
4
  activeSurface?: string | null;
6
5
  onPreviewSurface: (surface: string) => void;
7
- notify?: (msg: string, tone?: "success" | "error", extra?: ScreenToastExtra) => void;
8
6
  }
9
- export default function PagesPanel({ onNavigate, onClose, activeSurface, onPreviewSurface, notify }: Props): import("react").JSX.Element;
7
+ export default function PagesPanel({ onNavigate, onClose, activeSurface, onPreviewSurface }: Props): import("react").JSX.Element;
10
8
  export {};
@@ -1 +1 @@
1
- "use client";import{jsx as n,Fragment as _,jsxs as u}from"react/jsx-runtime";import{Fragment as fe,useEffect as be,useId as we,useMemo as V,useState as m}from"react";import{useStorefrontDocument as ye}from"./StorefrontDocumentContext.js";import I from"./UiIcon.js";import ke from"./SidePanelHead.js";import{useWebsiteName as Ce}from"./WebsiteSettingsPanel.js";import{InspectorIconButton as Pe}from"efficient-easel/chrome";import{Button as X,Dialog as Se,FormField as ve,Input as Z,toast as Ie}from"efficient-shell/ui";import{LayersTree as Ne,TreeGroupLabel as xe,TreeRow as ee,TreeRowAction as F}from"efficient-easel/tree";import{AddIcon as Ae}from"efficient-easel/icons";import{PagesIcon as Re}from"efficient-easel/rail";import{useEditorHost as De}from"../lib/editor-host.js";import{bucketEditorPageRows as Le,DYNAMIC_PAGES_GROUP_KEY as Ee,isDynamicPageRow as Oe,MAIN_PAGES_GROUP as _e}from"../lib/editor-page-rows.js";import{useEditorSession as Fe}from"../lib/editor-session-context.js";import{usePageRows as ze}from"../lib/page-rows.js";import{HOLD_MS as Ge,holdDelete as Me}from"../lib/held-page-delete.js";import{say as t}from"../lib/editor-words.js";const ne="sf-editor-pages-collapsed-groups",Be=i=>i.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,""),te=(i,w)=>{const d=Be(i)||"page";if(!w.has(d))return d;let p=2;for(;w.has(`${d}-${p}`);)p+=1;return`${d}-${p}`};function He({onNavigate:i,onClose:w,activeSurface:d,onPreviewSurface:p,notify:z}){const y=Fe().chrome?.pageRows,G=De(),{adapter:N,capabilities:h,ready:M,currentSlug:B}=ye(),se=Ce(),{rows:c,reload:oe,setRows:H,getRows:ae}=ze(),[x,le]=m(""),[g,W]=m(!1),[k,f]=m(null),[j,C]=m(!1),[b,A]=m(""),T=we(),[R,re]=m(()=>{if(typeof window>"u")return new Set;try{const e=window.localStorage.getItem(ne);return new Set(e?JSON.parse(e):[])}catch{return new Set}});be(()=>{try{window.localStorage.setItem(ne,JSON.stringify([...R]))}catch{}},[R]);const ie=e=>re(o=>{const s=new Set(o);return s.has(e)?s.delete(e):s.add(e),s}),de=V(()=>Le(c??[]),[c]),D=x.trim().toLowerCase(),U=e=>!D||e.toLowerCase().includes(D),ce=e=>D?!0:!R.has(e),$=V(()=>new Set((c??[]).map(e=>e.slug)),[c]),ue=()=>{if(h.pageCreationInAdminForm){G.send("storefront-editor:new-page");return}A(""),f(null),C(!0)},q=async()=>{const e=b.trim();if(!(!e||!M||g||!N.createPage)){W(!0),f(null);try{const o=await N.createPage({slug:te(e,$),title:e,layout:{}});await oe(),C(!1),A(""),i(o.slug)}catch{f(t("Couldn’t add the page — please retry."))}finally{W(!1)}}},me=e=>{const o=c??[],s=N.deletePage;if(!M||g||!s||o.length<=1)return;const a=o.findIndex(l=>l.id===e.id),r=o.filter(l=>l.id!==e.id),P=e.slug===B;H(r),f(null),P&&r[0]&&i(r[0].slug);const S=()=>{const l=ae()??[];if(l.some(ge=>ge.id===e.id))return;const O=[...l];O.splice(Math.max(0,Math.min(a,O.length)),0,e),H(O)},J=Me({id:e.id,send:l=>s(e.id,l),onFail:()=>{S(),f(t("Couldn’t delete the page — please retry."))}}),v={duration:Ge,action:{label:t("Undo"),onClick:()=>{J.undo()&&(S(),P&&i(e.slug))}},onClose:l=>{l!=="action"&&J.release()}},Q=t("Deleted “{name}”",{name:e.label});z?z(Q,"success",v):Ie.success(Q,{sound:!1,duration:v.duration,action:v.action,onClose:v.onClose})},pe=e=>G.send("storefront-editor:open-page",{slug:e}),he=e=>{if(!U(e.label))return null;const o=!d&&e.slug===B,s=h.canDeletePagesInline&&(c??[]).length>1,a=Oe(e),r=e.kind==="lightbox",P=a||r||e.draft?u(_,{children:[a&&n("span",{className:"sf-badge-dynamic",children:t("Dynamic")}),r&&n("span",{className:"sf-badge-lightbox",children:t("Lightbox")}),e.draft&&n("span",{className:"sf-page-draft",children:t("draft")})]}):void 0,S=h.pageCreationInAdminForm||s?u(_,{children:[h.pageCreationInAdminForm&&n(F,{kind:"plain",label:t("Edit “{name}” in {place}",{name:e.label,place:t("the admin")}),onClick:()=>pe(e.slug),children:n(I,{name:"pencil",size:13,strokeWidth:1.7,rounded:!0})}),s&&n(F,{kind:"delete",label:t("Delete “{name}”",{name:e.label}),disabled:g,onClick:()=>me(e),children:n(I,{name:"trash",size:13,strokeWidth:1.7,rounded:!0})})]}):void 0;return n(ee,{icon:n(We,{}),name:e.label,selected:o,onSelect:()=>i(e.slug),preview:P,actions:S,rowProps:{"data-page-slug":e.slug}},e.id)},L=(e,o,s)=>{const a=s.filter(Boolean);if(a.length===0)return null;const r=ce(e);return u(fe,{children:[n(xe,{count:a.length,expanded:r,onToggle:()=>ie(e),children:o}),r&&a]},e)},K=(y?.rows??[]).filter(e=>U(e.label)).map(e=>{const o=d===e.key;return n(ee,{icon:e.icon,name:e.label,selected:o,onSelect:()=>p(e.key),preview:n("span",{className:"sf-badge-preview",children:t("Preview")}),actions:n(F,{kind:"plain",label:t("Open the {name} in a new tab",{name:e.label}),onClick:()=>window.open(e.href,"_blank","noopener,noreferrer"),children:n(I,{name:"external-link",size:13,strokeWidth:1.7,rounded:!0})}),rowProps:{"data-shop-surface":e.key}},e.key)}),Y=h.hasSiteSettings&&!!y,E=(()=>{if(c===null)return null;const e=[];let o=!1;for(const s of de){Y&&!o&&s.key.startsWith("system:")&&(e.push(L("shop",y.title,K)),o=!0);const a=s.key===Ee||s.label===_e?t(s.label):s.label;e.push(L(s.key,a,s.rows.map(he)))}return Y&&!o&&e.push(L("shop",y.title,K)),e})();return u("div",{className:"sf-pages",children:[n(ke,{icon:n(Re,{}),title:t("Pages"),context:se,actions:n(Pe,{label:t("New page"),onClick:ue,children:n(Ae,{size:15})}),onHide:w}),n("div",{className:"sf-pages-find",children:n(Z,{type:"search",leftIcon:n(I,{name:"search",size:14,rounded:!0}),placeholder:t("Search all pages…"),value:x,onChange:e=>le(e.target.value),"aria-label":t("Search all pages")})}),k&&!j&&n("div",{className:"sf-note sf-note--error",role:"alert",children:k}),E===null?n("div",{className:"sf-note",children:t("Loading…")}):E.some(Boolean)?n(Ne,{ariaLabel:t("Pages"),className:"sf-scroll",children:E}):n("div",{className:"sf-note",children:x.trim()?t("No pages match your search"):t("No pages yet. Add one with + above.")}),n(Se,{open:j,onClose:()=>C(!1),size:"sm",title:t("Add a page"),description:t("Give the new template page a name. It starts blank — add sections once it opens."),footer:u(_,{children:[n(X,{variant:"secondary",onClick:()=>C(!1),children:t("Cancel")}),n(X,{onClick:()=>{q()},disabled:g||!b.trim(),loading:g,children:t("Add page")})]}),children:n(ve,{label:t("Page name"),htmlFor:T,hint:b.trim()?t("URL: /{slug}",{slug:te(b,$)}):void 0,error:k??void 0,children:n(Z,{id:T,value:b,invalid:!!k,onChange:e=>A(e.target.value),onKeyDown:e=>{e.key==="Enter"&&q()},placeholder:t("e.g. About")})})})]})}function We(){return u("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.7,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[n("path",{d:"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"}),n("path",{d:"M14 3v5h5"})]})}export{He as default};
1
+ "use client";import{jsx as t,Fragment as F,jsxs as u}from"react/jsx-runtime";import{Fragment as ge,useEffect as he,useId as fe,useMemo as Y,useState as m}from"react";import{useStorefrontDocument as be}from"./StorefrontDocumentContext.js";import v from"./UiIcon.js";import we from"./SidePanelHead.js";import{useWebsiteName as ye}from"./WebsiteSettingsPanel.js";import{InspectorIconButton as ke}from"efficient-easel/chrome";import{Button as J,Dialog as Pe,FormField as Se,Input as Q,toast as V}from"efficient-shell/ui";import{LayersTree as Ce,TreeGroupLabel as ve,TreeRow as X,TreeRowAction as O}from"efficient-easel/tree";import{AddIcon as Ie}from"efficient-easel/icons";import{PagesIcon as Ne}from"efficient-easel/rail";import{useEditorHost as Ae}from"../lib/editor-host.js";import{bucketEditorPageRows as xe,DYNAMIC_PAGES_GROUP_KEY as Re,isDynamicPageRow as Le,MAIN_PAGES_GROUP as De}from"../lib/editor-page-rows.js";import{useEditorSession as Ee}from"../lib/editor-session-context.js";import{holdPageRow as _,usePageRows as Fe}from"../lib/page-rows.js";import{say as n}from"../lib/editor-words.js";const Z="sf-editor-pages-collapsed-groups",Oe=r=>r.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,""),ee=(r,b)=>{const d=Oe(r)||"page";if(!b.has(d))return d;let p=2;for(;b.has(`${d}-${p}`);)p+=1;return`${d}-${p}`};function _e({onNavigate:r,onClose:b,activeSurface:d,onPreviewSurface:p}){const w=Ee().chrome?.pageRows,z=Ae(),{adapter:I,capabilities:g,ready:G,currentSlug:B}=be(),te=ye(),{rows:c,reload:ne,setRows:M,getRows:ae}=Fe(),[N,se]=m(""),[h,W]=m(!1),[y,k]=m(null),[j,P]=m(!1),[f,A]=m(""),H=fe(),[x,oe]=m(()=>{if(typeof window>"u")return new Set;try{const e=window.localStorage.getItem(Z);return new Set(e?JSON.parse(e):[])}catch{return new Set}});he(()=>{try{window.localStorage.setItem(Z,JSON.stringify([...x]))}catch{}},[x]);const le=e=>oe(s=>{const a=new Set(s);return a.has(e)?a.delete(e):a.add(e),a}),re=Y(()=>xe(c??[]),[c]),R=N.trim().toLowerCase(),T=e=>!R||e.toLowerCase().includes(R),ie=e=>R?!0:!x.has(e),U=Y(()=>new Set((c??[]).map(e=>e.slug)),[c]),de=()=>{if(g.pageCreationInAdminForm){z.send("storefront-editor:new-page");return}A(""),k(null),P(!0)},$=async()=>{const e=f.trim();if(!(!e||!G||h||!I.createPage)){W(!0),k(null);try{const s=await I.createPage({slug:ee(e,U),title:e,layout:{}});await ne(),P(!1),A(""),r(s.slug)}catch{k(n("Couldn’t add the page — please retry."))}finally{W(!1)}}},ce=e=>{const s=c??[],a=I.deletePage;if(!G||h||!a||s.length<=1)return;const o=s.findIndex(i=>i.id===e.id),l=s.filter(i=>i.id!==e.id),S=e.slug===B;_(e.id,!0),M(l),k(null),S&&l[0]&&r(l[0].slug);const C=()=>{_(e.id,!1);const i=ae()??[];if(i.some(pe=>pe.id===e.id))return;const E=[...i];E.splice(Math.max(0,Math.min(o,E.length)),0,e),M(E)};V.undoable(n("Deleted “{name}”",{name:e.label}),{actionLabel:n("Undo"),commit:async i=>{await a(e.id,i),_(e.id,!1)},undo:()=>{C(),S&&r(e.slug)},onFail:()=>{C(),V.error(n("Couldn’t delete the page — please retry."))}})},ue=e=>z.send("storefront-editor:open-page",{slug:e}),me=e=>{if(!T(e.label))return null;const s=!d&&e.slug===B,a=g.canDeletePagesInline&&(c??[]).length>1,o=Le(e),l=e.kind==="lightbox",S=o||l||e.draft?u(F,{children:[o&&t("span",{className:"sf-badge-dynamic",children:n("Dynamic")}),l&&t("span",{className:"sf-badge-lightbox",children:n("Lightbox")}),e.draft&&t("span",{className:"sf-page-draft",children:n("draft")})]}):void 0,C=g.pageCreationInAdminForm||a?u(F,{children:[g.pageCreationInAdminForm&&t(O,{kind:"plain",label:n("Edit “{name}” in {place}",{name:e.label,place:n("the admin")}),onClick:()=>ue(e.slug),children:t(v,{name:"pencil",size:13,strokeWidth:1.7,rounded:!0})}),a&&t(O,{kind:"delete",label:n("Delete “{name}”",{name:e.label}),disabled:h,onClick:()=>ce(e),children:t(v,{name:"trash",size:13,strokeWidth:1.7,rounded:!0})})]}):void 0;return t(X,{icon:t(ze,{}),name:e.label,selected:s,onSelect:()=>r(e.slug),preview:S,actions:C,rowProps:{"data-page-slug":e.slug}},e.id)},L=(e,s,a)=>{const o=a.filter(Boolean);if(o.length===0)return null;const l=ie(e);return u(ge,{children:[t(ve,{count:o.length,expanded:l,onToggle:()=>le(e),children:s}),l&&o]},e)},q=(w?.rows??[]).filter(e=>T(e.label)).map(e=>{const s=d===e.key;return t(X,{icon:e.icon,name:e.label,selected:s,onSelect:()=>p(e.key),preview:t("span",{className:"sf-badge-preview",children:n("Preview")}),actions:t(O,{kind:"plain",label:n("Open the {name} in a new tab",{name:e.label}),onClick:()=>window.open(e.href,"_blank","noopener,noreferrer"),children:t(v,{name:"external-link",size:13,strokeWidth:1.7,rounded:!0})}),rowProps:{"data-shop-surface":e.key}},e.key)}),K=g.hasSiteSettings&&!!w,D=(()=>{if(c===null)return null;const e=[];let s=!1;for(const a of re){K&&!s&&a.key.startsWith("system:")&&(e.push(L("shop",w.title,q)),s=!0);const o=a.key===Re||a.label===De?n(a.label):a.label;e.push(L(a.key,o,a.rows.map(me)))}return K&&!s&&e.push(L("shop",w.title,q)),e})();return u("div",{className:"sf-pages",children:[t(we,{icon:t(Ne,{}),title:n("Pages"),context:te,actions:t(ke,{label:n("New page"),onClick:de,children:t(Ie,{size:15})}),onHide:b}),t("div",{className:"sf-pages-find",children:t(Q,{type:"search",leftIcon:t(v,{name:"search",size:14,rounded:!0}),placeholder:n("Search all pages…"),value:N,onChange:e=>se(e.target.value),"aria-label":n("Search all pages")})}),y&&!j&&t("div",{className:"sf-note sf-note--error",role:"alert",children:y}),D===null?t("div",{className:"sf-note",children:n("Loading…")}):D.some(Boolean)?t(Ce,{ariaLabel:n("Pages"),className:"sf-scroll",children:D}):t("div",{className:"sf-note",children:N.trim()?n("No pages match your search"):n("No pages yet. Add one with + above.")}),t(Pe,{open:j,onClose:()=>P(!1),size:"sm",title:n("Add a page"),description:n("Give the new template page a name. It starts blank — add sections once it opens."),footer:u(F,{children:[t(J,{variant:"secondary",onClick:()=>P(!1),children:n("Cancel")}),t(J,{onClick:()=>{$()},disabled:h||!f.trim(),loading:h,children:n("Add page")})]}),children:t(Se,{label:n("Page name"),htmlFor:H,hint:f.trim()?n("URL: /{slug}",{slug:ee(f,U)}):void 0,error:y??void 0,children:t(Q,{id:H,value:f,invalid:!!y,onChange:e=>A(e.target.value),onKeyDown:e=>{e.key==="Enter"&&$()},placeholder:n("e.g. About")})})})]})}function ze(){return u("svg",{width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.7,strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[t("path",{d:"M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"}),t("path",{d:"M14 3v5h5"})]})}export{_e as default};
@@ -1 +1 @@
1
- "use client";import{jsx as t,jsxs as f,Fragment as _}from"react/jsx-runtime";import{useEffect as G,useId as ze,useRef as Z,useState as ee}from"react";import{PartResetDot as he}from"./PartResetDot.js";import{FieldSelect as ye,InspectorField as $e}from"efficient-easel/fields";import{SettingsField as ge,SettingsGroup as De}from"efficient-easel/panel";import{InspectorUpLevel as j}from"efficient-easel/chrome";import{StylesIcon as Ve,TextColorIcon as Be,TypeIcon as be}from"efficient-easel/icons";import{useEasel as Me}from"efficient-easel/easel";import{Tooltip as We}from"efficient-shell/ui";import{PartInkControl as Ge}from"./PartInkControl.js";import{PartTextBox as je}from"./PartTextBox.js";import Se from"./UiIcon.js";import{usePreviewHeader as Ue}from"./PreviewHeaderContext.js";import{usePartStyle as He}from"./PreviewPartStyleContext.js";import{say as o}from"../lib/editor-words.js";import{readHidable as U,textFieldOffPage as Ke}from"../lib/puck/controls.js";import{TEXT_FIELD_MARKER as Xe}from"../lib/puck/field-markers.js";import{useSectionOps as Ye}from"../lib/puck/use-section-ops.js";import{FONT_OPTIONS as qe,FONT_ROLES as te,FONT_ROLE_LABELS as ne,fontOption as L}from"../lib/fonts.js";import{isMultilineKind as Je,partPlaceholder as Qe,typeInPlaceKind as Ze}from"../lib/puck/part-text.js";import{partRowField as et}from"../lib/puck/part-row-field.js";import{decodePartKey as tt,partPropsWithRowValue as nt,partRowValue as ot}from"../lib/puck/part-rows.js";import{PART_WIDTH_MAX as st,propsWithPartStyleValue as oe,propsWithoutPartStyle as lt,readPartStyle as xe}from"../lib/puck/part-styles.js";import{partInks as rt}from"../lib/puck/part-inks.js";import{styleKeyForPart as at,TEXT_KIND_LABELS as it}from"../lib/sections/section-text-kinds.js";import{commitPartText as ct}from"../lib/puck/part-typing.js";import{useEditorHost as dt}from"../lib/editor-host.js";import{SOURCE_LINES as ut,SOURCE_ACTIONS as ft,SOURCE_ACTION_LABEL as pt,partSourceOf as mt,sourceSlugOf as ve}from"../lib/puck/source-bound-parts.js";import{encodePartId as ht,holdsAuthoredText as yt}from"../lib/puck/text-parts.js";import{regionsForSection as gt}from"../lib/sections/section-text-regions.js";import{textRegionOfPartKey as bt}from"../lib/sections/text-regions.js";const St={400:"Regular",500:"Medium",600:"Semibold",700:"Bold"},Ne=[{key:"font",label:"Font",group:"Style"},{key:"color",label:"Color",group:"Style"}],xt=[...new Set(Ne.map(e=>e.group))],vt={font:t(be,{}),color:t(Be,{})};function A(e){return e?o(e):null}function F(e){return e.kind==="role"?ne[e.role]:e.kind==="custom"?"Custom":null}const Nt=e=>e.kind==="role"?`role:${e.role}`:e.kind;function kt(e){const n=e.role;return n&&te.includes(n)?{kind:"role",role:n}:null}function wt(e,n){if(!e)return{kind:"unread"};const{faceRole:l,base:r}=e;if(n[l]===r.fontKey)return{kind:"role",role:l};const c=Object.keys(n).filter(a=>n[a]===r.fontKey);return c.length===1?{kind:"role",role:c[0]}:{kind:"custom"}}function se(e,n,l,r){return kt(xe(e,n))??wt(l,r)}function hn(e,n,l,r){return F(se(e,n,l,r))}function le(e,n){if(!e.length)return null;const l=n(e[0]);return e.every(r=>n(r)===l)?l:null}function Pt(e){return Object.values(e).filter(n=>n!==void 0).length}function Tt(e,n){const l=e.style[n];return n==="color"?l??"":l!==void 0?String(l):e.base.fontKey}function Et({face:e,base:n,onPick:l}){const[r,c]=ee(!1),a=Z(null),y=Z(null),g=ze();G(()=>{if(!r)return;const i=E=>{a.current&&!a.current.contains(E.target)&&c(!1)};return document.addEventListener("mousedown",i),()=>document.removeEventListener("mousedown",i)},[r]);const d=e.kind==="role"?e.role:null,k=i=>{l(i),c(!1),y.current?.focus()};return f("div",{className:"sf-part-style-pick",ref:a,children:[f("button",{ref:y,type:"button",className:"sf-part-style-trigger","aria-expanded":r,"aria-controls":g,"aria-label":F(e)?o("Follows {name} — change",{name:A(F(e))}):o("Follows no style — change"),onClick:()=>c(i=>!i),onKeyDown:i=>{i.key==="Escape"&&r&&(i.preventDefault(),c(!1))},children:[t("span",{className:"sf-part-style-name",style:{fontFamily:n?.fontKey?`var(${L(n.fontKey)?.cssVar})`:void 0,fontWeight:n?.weight},children:A(F(e))}),t("span",{className:"sf-part-style-sign","aria-hidden":"true"})]}),r&&f("div",{className:"sf-multi-menu sf-part-style-menu",id:g,role:"listbox",onKeyDown:i=>{i.key==="Escape"&&(i.preventDefault(),c(!1),y.current?.focus())},children:[f("button",{type:"button",role:"option","aria-selected":d===null,className:`sf-part-style-option${d===null?" is-on":""}`,onClick:()=>k(null),children:[t("span",{className:"sf-part-style-option-name",children:o("No style")}),t("span",{className:"sf-note",children:o("Section’s own")})]}),te.map(i=>t("button",{type:"button",role:"option","aria-selected":d===i,className:`sf-part-style-option${d===i?" is-on":""}`,onClick:()=>k(i),children:t("span",{className:"sf-part-style-option-name",style:{fontFamily:`var(--font-role-${i})`},children:o(ne[i])})},i))]})]})}const H="";function Rt({face:e,base:n,onPick:l}){const r=e.kind==="role"?e.role:H,c=[{label:o("No style"),value:H},...te.map(a=>({label:o(ne[a]),value:a}))];return t(ye,{ariaLabel:o("Style"),value:r,options:c,inline:!0,onChange:a=>l(a===H?null:a),renderOption:a=>a.value===H?f(_,{children:[t("span",{className:"es-fsel-label sf-part-style-keep",children:a.label}),t("span",{className:"sf-part-style-aside","aria-hidden":"true",children:o("Section’s own")})]}):t("span",{className:"es-fsel-label",style:{fontFamily:`var(--font-role-${a.value})`},children:a.label}),renderValue:()=>t("span",{style:{fontFamily:n?.fontKey?`var(${L(n.fontKey)?.cssVar})`:void 0,fontWeight:n?.weight},children:A(F(e))}),valueText:a=>A(F(e))??a?.label??""})}function Ft({parts:e,onEditStyle:n,onClearAll:l,onFollowStyle:r,kindLabel:c}){const y=le(e,E=>Nt(E.face))?e[0].face:null,g=y?F(y):null,d=y&&y.kind!=="unread"?e[0].base:null,k=e.reduce((E,z)=>E+Pt(z.style),0),i=d?L(d.fontKey)?.label:void 0;return f("div",{className:`sf-part-style${k?" has-overrides":""}`,children:[t("div",{className:"sf-part-style-caption",children:o("Style")}),e.length>1&&t("div",{className:"sf-part-style-count",children:o("{n} selected",{n:e.length})}),e.length===1&&c&&t("div",{className:"sf-part-style-count",children:o("{kind} · every row",{kind:o(c)})}),g&&d?f(_,{children:[r&&y?t(Et,{face:y,base:d,onPick:r}):t("div",{className:"sf-part-style-name",style:{fontFamily:i?`var(${L(d.fontKey)?.cssVar})`:void 0,fontWeight:d.weight},children:o(g)}),t("div",{className:"sf-part-style-meta",children:[i,`${Math.round(d.sizePx)} px`,o(St[d.weight])].filter(Boolean).join(" · ")})]}):t("div",{className:"sf-part-style-name",children:o("Mixed styles")}),f("div",{className:"sf-part-style-top",children:[g?k?f(_,{children:[t("span",{className:"sf-part-chip",children:o("{n} changed",{n:k})}),t("button",{type:"button",className:"sf-part-link",onClick:l,children:o("Clear")})]}):t("span",{className:"sf-part-style-state",children:o("This text follows the site style.")}):t("span",{className:"sf-part-style-state",children:o("Changes apply to all selected.")}),t("span",{className:"sf-part-style-gap"}),g&&n&&t("button",{type:"button",className:"sf-part-link",onClick:n,children:o("Edit")})]})]})}function Ct({sectionName:e,onBack:n,textEditor:l,styleRow:r,children:c}){return f("div",{className:"sf-part-panel",children:[t(j,{inline:!0,name:o(e),onSelect:n}),l,r,c]})}function ke({source:e,slug:n}){const l=dt(),r=ft[e],c=!r.needsSlug||!!n;return t("div",{className:"sf-note sf-note--source",children:f("p",{className:"es-field-hint sf-hint-keep",children:[o(ut[e]),c?f(_,{children:[" ",t("button",{type:"button",className:"sf-source-open",onClick:()=>{r.type==="storefront-editor:open-menus"?l.send(r.type):n&&l.send(r.type,{slug:n})},children:o(pt)})]}):null]})})}const we=4,Ot=120;function It({region:e,sizePx:n,face:l,base:r,onFollowStyle:c,source:a,slug:y,onBack:g}){const d=e.follows;return f("div",{className:"sf-note",children:[t("p",{children:t("strong",{children:o(e.label)})}),t("p",{children:n?o("Its size follows Site styles ▸ {follows} — {px}px right now.",{follows:o(d),px:Math.round(n)}):o("Its size follows Site styles ▸ {follows}.",{follows:o(d)})}),c?t(_,{children:t(ge,{label:o("Style"),icon:t(Ve,{}),hint:o("Every {part} in this section follows it. The face and the size change; the letter case is the section’s own and stays as it is.",{part:o(e.label).toLowerCase()}),children:t(Rt,{face:l,base:r,onPick:c})})}):t("p",{className:"es-field-hint sf-hint-keep",children:o("Only the size follows a site style. This section sets its own font, weight and letter case.")}),a?t(ke,{source:a,slug:y}):null,t(j,{inline:!0,name:o("Page"),onSelect:g})]})}function _t({onBack:e}){return f("div",{className:"sf-note",children:[t("p",{children:t("strong",{children:o("This part is no longer here.")})}),t("p",{children:o("The section it belonged to has been changed or removed.")}),t(j,{inline:!0,name:o("Page"),onSelect:e})]})}function Lt({onBack:e,partId:n,why:l}){return f("div",{className:"sf-note",children:[t("p",{children:t("strong",{children:o("This part's settings did not open.")})}),t("p",{children:o("The words are still on your page and nothing has been lost. The editor could not work out which control belongs to them, which is a fault on our side. Go back and click the section to open its settings instead.")}),t("p",{className:"sf-note-detail",children:f("code",{children:[n," — ",l]})}),t(j,{inline:!0,name:o("Page"),onSelect:e})]})}function At({nodeId:e,propKey:n,onBack:l,onEditStyle:r}){const{getItemById:c,getSelectorForId:a,config:y}=Me(s=>s),g=Ye(),{partStyle:d}=He(),{fonts:k}=Ue(),[i,E]=ee({}),z=Z(null),b=c(e),x=a(e),re=b?y.components[b.type]:void 0,{key:R,row:w}=tt(n),ae=re?.fields?.[R],P=w?et(ae,w):ae,O=ht(e,n),m=b?.props??{},T=Ze(P),Pe=Ke(P),Te=yt(P),K=b?mt(b.type):null,X=w?ot(m[R],w):m[R],ie=!!w&&!(Array.isArray(m[R])&&w.index<m[R].length);G(()=>{z.current?.querySelector(".es-copy [contenteditable='true'], .es-copy textarea, .sf-copybox textarea, .sf-copybox input")?.focus()},[O]);const[Y,ce]=ee(0);G(()=>ce(0),[O]);const q=!!b&&!ie&&(!x||!P);G(()=>{if(!q||Y>=we)return;const s=setTimeout(()=>ce(u=>u+1),Ot);return()=>clearTimeout(s)},[q,Y]);const Ee=q&&Y<we;if(!b||ie)return t(_t,{onBack:l});const $=gt(b.type),de=$?bt($,n):null;if($&&de){const s=d?.partId===O?d:null,u=$[de],h=u.writable===!0&&!!x,S=p=>{x&&g.replaceComponent(x.zone,x.index,{...b,props:oe(m,n,"role",p)})};return t(It,{region:u,sizePx:s?.base.sizePx??null,face:se(m,n,s,k),base:s?.base??null,onFollowStyle:h?S:void 0,source:K,slug:ve(m),onBack:l})}if(!x||!P)return Ee?t("div",{className:"sf-note","aria-busy":"true"}):t(Lt,{onBack:l,partId:O,why:x?"no field":"no selector"});const D=s=>{g.replaceComponent(x.zone,x.index,{...b,props:s})},J=s=>{if(U(s).hidden!==U(X).hidden||!T){const h=w?nt(m,R,w,s):{...m,[R]:s};h&&D(h);return}ct({node:b,propKey:n,kind:T,zone:x.zone,index:x.index},U(s).text,g.replaceComponent)},Re=X,V=at(b?.type,n),Fe=xe(m,V),B=d?.partId===O?d:null,v=[{partKey:V,face:se(m,V,B,k),sizeGroup:B?.sizeGroup??null,base:B?.base??zt,style:Fe}],Ce=le(v,s=>s.sizeGroup),ue=rt(B?.inks),M=(s,u)=>{let h=m;for(const S of v)h=oe(h,S.partKey,s,u);D(h)},Oe=s=>M("role",s),Ie=()=>{let s=m;for(const u of v)s=lt(s,u.partKey);D(s)},_e=s=>{let u=m;for(const h of v)for(const[S,p]of Object.entries(s))u=oe(u,h.partKey,S,p??null);D(u)},Le=(s,u)=>{const h=v.some(N=>N.style[s]!==void 0),S=le(v,N=>Tt(N,s)),p=S===null,C=`sf-part-${e}-${n}-${s}`;return s==="color"?t(Ge,{value:p?null:String(S),label:u,colors:ue,onChange:N=>M("color",N)},s):t(ge,{label:o(u),icon:vt[s],className:"sf-part-field",changed:h,htmlFor:C,action:h?t(he,{label:u,onClear:()=>M(s,null)}):void 0,children:s==="font"?t(ye,{id:C,ariaLabel:o(u),value:!p&&L(String(S))?String(S):void 0,placeholder:p?o("Mixed"):o("Site style"),options:qe.map(N=>({label:N.label,value:N.key})),onChange:N=>M("font",N||null)}):null},s)},fe=T==="text"||T==="textarea",{text:pe,hidden:I}=U(X),W=P?.[Xe]?.label??n,me=I?o("Show {label} on the slide",{label:o(W)}):o("Hide {label} on the slide",{label:o(W)}),Ae=f("div",{className:"sf-field-head",children:[t(be,{}),t("span",{className:"sf-field-label sf-field-label--inline",children:o(W)}),fe&&t(We,{content:me,children:t("button",{type:"button",className:"sf-field-eye","aria-pressed":I,"aria-label":me,onClick:()=>J({text:pe,hidden:!I}),children:I?t(Se,{name:"eye-off",size:14}):t(Se,{name:"eye",size:14})})})]}),Q=!Pe&&Te;return f(Ct,{sectionName:re?.label??b.type,onBack:l,textEditor:f("div",{ref:z,className:"sf-part-text",children:[T?t(je,{text:pe,onTextChange:s=>J(fe?{text:s,hidden:I}:s),multiline:Je(T),markup:T!=="plainText",styled:Q,style:v[0].style,base:v[0].base,setValue:_e,colors:ue.map(s=>({name:s.key,label:o(s.name),value:s.value})),placeholder:A(Qe(P))??void 0,ariaLabel:o(W),head:Ae}):t($e,{field:P,name:n,value:Re,onChange:J,id:`sf-part-${e}-${n}`}),Q&&T&&Ce===null&&t("p",{className:"es-field-hint sf-hint-keep",children:o("Fixed size — the site’s Text setting doesn’t resize this.")})]}),children:[K&&t(ke,{source:K,slug:ve(m)}),Q&&xt.map(s=>{const u=Ne.filter(p=>p.group===s),h=u.filter(p=>v.some(C=>C.style[p.key]!==void 0)).length,S=`sf-part-g-${e}-${n}-${s.replace(/\W+/g,"-")}`;return f(De,{id:S,title:o(s),open:i[s]!==!0,onToggle:p=>E(C=>({...C,[s]:!p})),count:h,children:[t(Ft,{parts:v,onEditStyle:r,onClearAll:Ie,onFollowStyle:Oe,kindLabel:it[V]}),u.map(p=>Le(p.key,p.label))]},s)})]})}const zt={fontKey:"",sizePx:16,weight:400,lineRatio:1.4,letterEm:0,align:"left",case:"none",paddingPx:0,widthPx:st};export{Ne as PART_FIELDS,Ct as PartPanelBody,he as PartResetDot,ke as PartSourceNote,Ft as PartStyleCard,Rt as PartStyleSelect,At as default,se as partFace,hn as partStyleName};
1
+ "use client";import{jsx as t,jsxs as u,Fragment as _}from"react/jsx-runtime";import{useEffect as W,useId as $e,useRef as Z,useState as ee}from"react";import{PartResetDot as ye}from"./PartResetDot.js";import{FieldSelect as ge,InspectorField as De}from"efficient-easel/fields";import{SettingsField as be,SettingsGroup as Ve}from"efficient-easel/panel";import{InspectorUpLevel as G}from"efficient-easel/chrome";import{StylesIcon as Be,TextColorIcon as Me,TypeIcon as Se}from"efficient-easel/icons";import{useEasel as We}from"efficient-easel/easel";import{Tooltip as Ge}from"efficient-shell/ui";import{PartInkControl as je}from"./PartInkControl.js";import{PartTextBox as Ue}from"./PartTextBox.js";import xe from"./UiIcon.js";import{usePreviewHeader as He}from"./PreviewHeaderContext.js";import{usePartStyle as Ke}from"./PreviewPartStyleContext.js";import{say as o}from"../lib/editor-words.js";import{readHidable as j,textFieldOffPage as Xe}from"../lib/puck/controls.js";import{TEXT_FIELD_MARKER as Ye}from"../lib/puck/field-markers.js";import{useSectionOps as qe}from"../lib/puck/use-section-ops.js";import{FONT_OPTIONS as Je,FONT_ROLES as te,FONT_ROLE_LABELS as ne,fontOption as L}from"../lib/fonts.js";import{isMultilineKind as Qe,partPlaceholder as Ze,typeInPlaceKind as et}from"../lib/puck/part-text.js";import{partRowField as tt}from"../lib/puck/part-row-field.js";import{decodePartKey as nt,partPropsWithRowValue as ot,partRowValue as st}from"../lib/puck/part-rows.js";import{PART_WIDTH_MAX as lt,propsWithPartStyleValue as oe,propsWithoutPartStyle as rt,readPartStyle as ve}from"../lib/puck/part-styles.js";import{partInks as at}from"../lib/puck/part-inks.js";import{styleKeyForPart as it,TEXT_KIND_LABELS as ct}from"../lib/sections/section-text-kinds.js";import{commitPartText as dt}from"../lib/puck/part-typing.js";import{keysOnCanvas as ut,useCanvasTypingPart as ft}from"../lib/puck/canvas-typing.js";import{useEditorHost as pt}from"../lib/editor-host.js";import{SOURCE_LINES as mt,SOURCE_ACTIONS as ht,SOURCE_ACTION_LABEL as yt,partSourceOf as gt,sourceSlugOf as Ne}from"../lib/puck/source-bound-parts.js";import{encodePartId as bt,holdsAuthoredText as St}from"../lib/puck/text-parts.js";import{regionsForSection as xt}from"../lib/sections/section-text-regions.js";import{textRegionOfPartKey as vt}from"../lib/sections/text-regions.js";const Nt={400:"Regular",500:"Medium",600:"Semibold",700:"Bold"},ke=[{key:"font",label:"Font",group:"Style"},{key:"color",label:"Color",group:"Style"}],kt=[...new Set(ke.map(e=>e.group))],Pt={font:t(Se,{}),color:t(Me,{})};function A(e){return e?o(e):null}function R(e){return e.kind==="role"?ne[e.role]:e.kind==="custom"?"Custom":null}const wt=e=>e.kind==="role"?`role:${e.role}`:e.kind;function Tt(e){const n=e.role;return n&&te.includes(n)?{kind:"role",role:n}:null}function Et(e,n){if(!e)return{kind:"unread"};const{faceRole:l,base:r}=e;if(n[l]===r.fontKey)return{kind:"role",role:l};const c=Object.keys(n).filter(i=>n[i]===r.fontKey);return c.length===1?{kind:"role",role:c[0]}:{kind:"custom"}}function se(e,n,l,r){return Tt(ve(e,n))??Et(l,r)}function Sn(e,n,l,r){return R(se(e,n,l,r))}function le(e,n){if(!e.length)return null;const l=n(e[0]);return e.every(r=>n(r)===l)?l:null}function Ct(e){return Object.values(e).filter(n=>n!==void 0).length}function Rt(e,n){const l=e.style[n];return n==="color"?l??"":l!==void 0?String(l):e.base.fontKey}function Ft({face:e,base:n,onPick:l}){const[r,c]=ee(!1),i=Z(null),y=Z(null),g=$e();W(()=>{if(!r)return;const a=E=>{i.current&&!i.current.contains(E.target)&&c(!1)};return document.addEventListener("mousedown",a),()=>document.removeEventListener("mousedown",a)},[r]);const f=e.kind==="role"?e.role:null,x=a=>{l(a),c(!1),y.current?.focus()};return u("div",{className:"sf-part-style-pick",ref:i,children:[u("button",{ref:y,type:"button",className:"sf-part-style-trigger","aria-expanded":r,"aria-controls":g,"aria-label":R(e)?o("Follows {name} — change",{name:A(R(e))}):o("Follows no style — change"),onClick:()=>c(a=>!a),onKeyDown:a=>{a.key==="Escape"&&r&&(a.preventDefault(),c(!1))},children:[t("span",{className:"sf-part-style-name",style:{fontFamily:n?.fontKey?`var(${L(n.fontKey)?.cssVar})`:void 0,fontWeight:n?.weight},children:A(R(e))}),t("span",{className:"sf-part-style-sign","aria-hidden":"true"})]}),r&&u("div",{className:"sf-multi-menu sf-part-style-menu",id:g,role:"listbox",onKeyDown:a=>{a.key==="Escape"&&(a.preventDefault(),c(!1),y.current?.focus())},children:[u("button",{type:"button",role:"option","aria-selected":f===null,className:`sf-part-style-option${f===null?" is-on":""}`,onClick:()=>x(null),children:[t("span",{className:"sf-part-style-option-name",children:o("No style")}),t("span",{className:"sf-note",children:o("Section’s own")})]}),te.map(a=>t("button",{type:"button",role:"option","aria-selected":f===a,className:`sf-part-style-option${f===a?" is-on":""}`,onClick:()=>x(a),children:t("span",{className:"sf-part-style-option-name",style:{fontFamily:`var(--font-role-${a})`},children:o(ne[a])})},a))]})]})}const U="";function Ot({face:e,base:n,onPick:l}){const r=e.kind==="role"?e.role:U,c=[{label:o("No style"),value:U},...te.map(i=>({label:o(ne[i]),value:i}))];return t(ge,{ariaLabel:o("Style"),value:r,options:c,inline:!0,onChange:i=>l(i===U?null:i),renderOption:i=>i.value===U?u(_,{children:[t("span",{className:"es-fsel-label sf-part-style-keep",children:i.label}),t("span",{className:"sf-part-style-aside","aria-hidden":"true",children:o("Section’s own")})]}):t("span",{className:"es-fsel-label",style:{fontFamily:`var(--font-role-${i.value})`},children:i.label}),renderValue:()=>t("span",{style:{fontFamily:n?.fontKey?`var(${L(n.fontKey)?.cssVar})`:void 0,fontWeight:n?.weight},children:A(R(e))}),valueText:i=>A(R(e))??i?.label??""})}function It({parts:e,onEditStyle:n,onClearAll:l,onFollowStyle:r,kindLabel:c}){const y=le(e,E=>wt(E.face))?e[0].face:null,g=y?R(y):null,f=y&&y.kind!=="unread"?e[0].base:null,x=e.reduce((E,H)=>E+Ct(H.style),0),a=f?L(f.fontKey)?.label:void 0;return u("div",{className:`sf-part-style${x?" has-overrides":""}`,children:[t("div",{className:"sf-part-style-caption",children:o("Style")}),e.length>1&&t("div",{className:"sf-part-style-count",children:o("{n} selected",{n:e.length})}),e.length===1&&c&&t("div",{className:"sf-part-style-count",children:o("{kind} · every row",{kind:o(c)})}),g&&f?u(_,{children:[r&&y?t(Ft,{face:y,base:f,onPick:r}):t("div",{className:"sf-part-style-name",style:{fontFamily:a?`var(${L(f.fontKey)?.cssVar})`:void 0,fontWeight:f.weight},children:o(g)}),t("div",{className:"sf-part-style-meta",children:[a,`${Math.round(f.sizePx)} px`,o(Nt[f.weight])].filter(Boolean).join(" · ")})]}):t("div",{className:"sf-part-style-name",children:o("Mixed styles")}),u("div",{className:"sf-part-style-top",children:[g?x?u(_,{children:[t("span",{className:"sf-part-chip",children:o("{n} changed",{n:x})}),t("button",{type:"button",className:"sf-part-link",onClick:l,children:o("Clear")})]}):t("span",{className:"sf-part-style-state",children:o("This text follows the site style.")}):t("span",{className:"sf-part-style-state",children:o("Changes apply to all selected.")}),t("span",{className:"sf-part-style-gap"}),g&&n&&t("button",{type:"button",className:"sf-part-link",onClick:n,children:o("Edit")})]})]})}function _t({sectionName:e,onBack:n,textEditor:l,styleRow:r,children:c}){return u("div",{className:"sf-part-panel",children:[t(G,{inline:!0,name:o(e),onSelect:n}),l,r,c]})}function Pe({source:e,slug:n}){const l=pt(),r=ht[e],c=!r.needsSlug||!!n;return t("div",{className:"sf-note sf-note--source",children:u("p",{className:"es-field-hint sf-hint-keep",children:[o(mt[e]),c?u(_,{children:[" ",t("button",{type:"button",className:"sf-source-open",onClick:()=>{r.type==="storefront-editor:open-menus"?l.send(r.type):n&&l.send(r.type,{slug:n})},children:o(yt)})]}):null]})})}const we=4,Lt=120;function At({region:e,sizePx:n,face:l,base:r,onFollowStyle:c,source:i,slug:y,onBack:g}){const f=e.follows;return u("div",{className:"sf-note",children:[t("p",{children:t("strong",{children:o(e.label)})}),t("p",{children:n?o("Its size follows Site styles ▸ {follows} — {px}px right now.",{follows:o(f),px:Math.round(n)}):o("Its size follows Site styles ▸ {follows}.",{follows:o(f)})}),c?t(_,{children:t(be,{label:o("Style"),icon:t(Be,{}),hint:o("Every {part} in this section follows it. The face and the size change; the letter case is the section’s own and stays as it is.",{part:o(e.label).toLowerCase()}),children:t(Ot,{face:l,base:r,onPick:c})})}):t("p",{className:"es-field-hint sf-hint-keep",children:o("Only the size follows a site style. This section sets its own font, weight and letter case.")}),i?t(Pe,{source:i,slug:y}):null,t(G,{inline:!0,name:o("Page"),onSelect:g})]})}function zt({onBack:e}){return u("div",{className:"sf-note",children:[t("p",{children:t("strong",{children:o("This part is no longer here.")})}),t("p",{children:o("The section it belonged to has been changed or removed.")}),t(G,{inline:!0,name:o("Page"),onSelect:e})]})}function $t({onBack:e,partId:n,why:l}){return u("div",{className:"sf-note",children:[t("p",{children:t("strong",{children:o("This part's settings did not open.")})}),t("p",{children:o("The words are still on your page and nothing has been lost. The editor could not work out which control belongs to them, which is a fault on our side. Go back and click the section to open its settings instead.")}),t("p",{className:"sf-note-detail",children:u("code",{children:[n," — ",l]})}),t(G,{inline:!0,name:o("Page"),onSelect:e})]})}function Dt({nodeId:e,propKey:n,onBack:l,onEditStyle:r}){const{getItemById:c,getSelectorForId:i,config:y}=We(s=>s),g=qe(),f=ft(),{partStyle:x}=Ke(),{fonts:a}=He(),[E,H]=ee({}),re=Z(null),b=c(e),v=i(e),ae=b?y.components[b.type]:void 0,{key:C,row:P}=nt(n),ie=ae?.fields?.[C],w=P?tt(ie,P):ie,F=bt(e,n),m=b?.props??{},T=et(w),Te=Xe(w),Ee=St(w),K=b?gt(b.type):null,X=P?st(m[C],P):m[C],ce=!!P&&!(Array.isArray(m[C])&&P.index<m[C].length);W(()=>{if(ut(document))return;re.current?.querySelector(".es-copy [contenteditable='true'], .es-copy textarea, .sf-copybox textarea, .sf-copybox input")?.focus()},[F]);const[Y,de]=ee(0);W(()=>de(0),[F]);const q=!!b&&!ce&&(!v||!w);W(()=>{if(!q||Y>=we)return;const s=setTimeout(()=>de(d=>d+1),Lt);return()=>clearTimeout(s)},[q,Y]);const Ce=q&&Y<we;if(!b||ce)return t(zt,{onBack:l});const z=xt(b.type),ue=z?vt(z,n):null;if(z&&ue){const s=x?.partId===F?x:null,d=z[ue],h=d.writable===!0&&!!v,S=p=>{v&&g.replaceComponent(v.zone,v.index,{...b,props:oe(m,n,"role",p)})};return t(At,{region:d,sizePx:s?.base.sizePx??null,face:se(m,n,s,a),base:s?.base??null,onFollowStyle:h?S:void 0,source:K,slug:Ne(m),onBack:l})}if(!v||!w)return Ce?t("div",{className:"sf-note","aria-busy":"true"}):t($t,{onBack:l,partId:F,why:v?"no field":"no selector"});const $=s=>{g.replaceComponent(v.zone,v.index,{...b,props:s})},J=s=>{if(j(s).hidden!==j(X).hidden||!T){const h=P?ot(m,C,P,s):{...m,[C]:s};h&&$(h);return}dt({node:b,propKey:n,kind:T,zone:v.zone,index:v.index},j(s).text,g.replaceComponent)},Re=X,D=it(b?.type,n),Fe=ve(m,D),V=x?.partId===F?x:null,N=[{partKey:D,face:se(m,D,V,a),sizeGroup:V?.sizeGroup??null,base:V?.base??Vt,style:Fe}],Oe=le(N,s=>s.sizeGroup),fe=at(V?.inks),B=(s,d)=>{let h=m;for(const S of N)h=oe(h,S.partKey,s,d);$(h)},Ie=s=>B("role",s),_e=()=>{let s=m;for(const d of N)s=rt(s,d.partKey);$(s)},Le=s=>{let d=m;for(const h of N)for(const[S,p]of Object.entries(s))d=oe(d,h.partKey,S,p??null);$(d)},Ae=(s,d)=>{const h=N.some(k=>k.style[s]!==void 0),S=le(N,k=>Rt(k,s)),p=S===null,O=`sf-part-${e}-${n}-${s}`;return s==="color"?t(je,{value:p?null:String(S),label:d,colors:fe,onChange:k=>B("color",k)},s):t(be,{label:o(d),icon:Pt[s],className:"sf-part-field",changed:h,htmlFor:O,action:h?t(ye,{label:d,onClear:()=>B(s,null)}):void 0,children:s==="font"?t(ge,{id:O,ariaLabel:o(d),value:!p&&L(String(S))?String(S):void 0,placeholder:p?o("Mixed"):o("Site style"),options:Je.map(k=>({label:k.label,value:k.key})),onChange:k=>B("font",k||null)}):null},s)},pe=T==="text"||T==="textarea",{text:me,hidden:I}=j(X),M=w?.[Ye]?.label??n,he=I?o("Show {label} on the slide",{label:o(M)}):o("Hide {label} on the slide",{label:o(M)}),ze=u("div",{className:"sf-field-head",children:[t(Se,{}),t("span",{className:"sf-field-label sf-field-label--inline",children:o(M)}),pe&&t(Ge,{content:he,children:t("button",{type:"button",className:"sf-field-eye","aria-pressed":I,"aria-label":he,onClick:()=>J({text:me,hidden:!I}),children:I?t(xe,{name:"eye-off",size:14}):t(xe,{name:"eye",size:14})})})]}),Q=!Te&&Ee;return u(_t,{sectionName:ae?.label??b.type,onBack:l,textEditor:u("div",{ref:re,className:"sf-part-text",children:[T?t(Ue,{text:me,onTextChange:s=>J(pe?{text:s,hidden:I}:s),multiline:Qe(T),markup:T!=="plainText",styled:Q,style:N[0].style,base:N[0].base,setValue:Le,colors:fe.map(s=>({name:s.key,label:o(s.name),value:s.value})),placeholder:A(Ze(w))??void 0,ariaLabel:o(M),head:ze,typedOnCanvas:f===F}):t(De,{field:w,name:n,value:Re,onChange:J,id:`sf-part-${e}-${n}`}),Q&&T&&Oe===null&&t("p",{className:"es-field-hint sf-hint-keep",children:o("Fixed size — the site’s Text setting doesn’t resize this.")})]}),children:[K&&t(Pe,{source:K,slug:Ne(m)}),Q&&kt.map(s=>{const d=ke.filter(p=>p.group===s),h=d.filter(p=>N.some(O=>O.style[p.key]!==void 0)).length,S=`sf-part-g-${e}-${n}-${s.replace(/\W+/g,"-")}`;return u(Ve,{id:S,title:o(s),open:E[s]!==!0,onToggle:p=>H(O=>({...O,[s]:!p})),count:h,children:[t(It,{parts:N,onEditStyle:r,onClearAll:_e,onFollowStyle:Ie,kindLabel:ct[D]}),d.map(p=>Ae(p.key,p.label))]},s)})]})}const Vt={fontKey:"",sizePx:16,weight:400,lineRatio:1.4,letterEm:0,align:"left",case:"none",paddingPx:0,widthPx:lt};export{ke as PART_FIELDS,_t as PartPanelBody,ye as PartResetDot,Pe as PartSourceNote,It as PartStyleCard,Ot as PartStyleSelect,Dt as default,se as partFace,Sn as partStyleName};
@@ -4,7 +4,7 @@ import { type PartStyle, type PartStyleBase } from "../lib/puck/part-styles.js";
4
4
  export type PartStylePatch = {
5
5
  [K in keyof PartStyle]?: PartStyle[K] | null;
6
6
  };
7
- export declare function PartTextBox({ text, onTextChange, multiline, markup, styled, style, base, setValue, colors, placeholder, ariaLabel, head, }: {
7
+ export declare function PartTextBox({ text, onTextChange, multiline, markup, styled, style, base, setValue, colors, placeholder, ariaLabel, head, typedOnCanvas, }: {
8
8
  text: string;
9
9
  onTextChange: (next: string) => void;
10
10
  multiline: boolean;
@@ -17,4 +17,5 @@ export declare function PartTextBox({ text, onTextChange, multiline, markup, sty
17
17
  placeholder?: string;
18
18
  ariaLabel?: string;
19
19
  head?: ReactNode;
20
+ typedOnCanvas?: boolean;
20
21
  }): import("react").JSX.Element;
@@ -1 +1 @@
1
- "use client";import{jsx as o,jsxs as S}from"react/jsx-runtime";import{COPY_CELLS as a,CopyBox as T}from"efficient-easel/copy";import{PaddingYIcon as A,WidthIcon as C}from"efficient-easel/icons";import{say as u}from"../lib/editor-words.js";import{SHOP_MARKUP as I}from"../lib/markup.js";import{PART_PADDING_MAX as R,PART_PADDING_MIN as D,PART_PADDING_STEP as O,PART_WIDTH_MAX as v,PART_WIDTH_MIN as H,PART_WIDTH_STEP as L,partSpacingOf as z}from"../lib/puck/part-styles.js";const N=["left","center","right","justify"],M=["bold","italic","underline","strike","link","sup","sub"],W=["bullet","number"];function y({text:c,onTextChange:d,multiline:r,markup:g=!0,styled:t=!0,style:e,base:l,setValue:i,colors:s,placeholder:h,ariaLabel:P,head:m}){const p=z(e),_=e.size??l.sizePx,f=[{...a.fontSize,value:e.size,styleValue:Math.round(l.sizePx),onChange:n=>i({size:n??null})},{...a.lineHeight,value:p.lineHeight,styleValue:l.lineRatio,onChange:n=>i(n===void 0?{lineHeight:null,line:null}:{lineHeight:n})},{...a.letterSpacing,scale:_,value:p.letterSpacingEm,styleValue:l.letterEm,onChange:n=>i(n===void 0?{letterSpacing:null,letter:null}:{letterSpacing:n})},{...a.paragraphSpacing,value:e.paragraphSpacing,styleValue:0,onChange:n=>i({paragraphSpacing:n??null})},{key:"padding",name:u("Padding"),icon:o(A,{}),unit:"px",step:O,shiftStep:10,min:D,max:R,value:e.padding,styleValue:l.paddingPx,onChange:n=>i({padding:n??null})},{key:"width",name:u("Width"),icon:o(C,{}),unit:"px",step:L,shiftStep:100,min:H,max:v,value:e.width,styleValue:l.widthPx,onChange:n=>i({width:n??null})}],x=g?[...M,...r?W:[]]:[];return S("div",{className:"sf-part-textbox",children:[m,o(T,{value:c,onChange:d,multiline:r,placeholder:h,ariaLabel:P,rules:I,tools:x,colors:g?s:[],align:t?{value:e.align??l.align,allow:N,onChange:n=>i({align:n})}:void 0,letterCase:t?{value:e.case??"",onChange:n=>i({case:n||null})}:void 0,cells:t?f:void 0})]})}export{y as PartTextBox};
1
+ "use client";import{jsx as o,jsxs as T}from"react/jsx-runtime";import{COPY_CELLS as l,CopyBox as A}from"efficient-easel/copy";import{PaddingYIcon as C,WidthIcon as I}from"efficient-easel/icons";import{say as u}from"../lib/editor-words.js";import{SHOP_MARKUP as R}from"../lib/markup.js";import{partTextTools as D}from"../lib/puck/canvas-typing.js";import{PART_PADDING_MAX as v,PART_PADDING_MIN as H,PART_PADDING_STEP as w,PART_WIDTH_MAX as z,PART_WIDTH_MIN as N,PART_WIDTH_STEP as M,partSpacingOf as j}from"../lib/puck/part-styles.js";const E=["left","center","right","justify"];function Y({text:c,onTextChange:d,multiline:r,markup:p=!0,styled:t=!0,style:e,base:a,setValue:i,colors:h,placeholder:s,ariaLabel:P,head:f,typedOnCanvas:m=!1}){const g=j(e),x=e.size??a.sizePx,_=[{...l.fontSize,value:e.size,styleValue:Math.round(a.sizePx),onChange:n=>i({size:n??null})},{...l.lineHeight,value:g.lineHeight,styleValue:a.lineRatio,onChange:n=>i(n===void 0?{lineHeight:null,line:null}:{lineHeight:n})},{...l.letterSpacing,scale:x,value:g.letterSpacingEm,styleValue:a.letterEm,onChange:n=>i(n===void 0?{letterSpacing:null,letter:null}:{letterSpacing:n})},{...l.paragraphSpacing,value:e.paragraphSpacing,styleValue:0,onChange:n=>i({paragraphSpacing:n??null})},{key:"padding",name:u("Padding"),icon:o(C,{}),unit:"px",step:w,shiftStep:10,min:H,max:v,value:e.padding,styleValue:a.paddingPx,onChange:n=>i({padding:n??null})},{key:"width",name:u("Width"),icon:o(I,{}),unit:"px",step:M,shiftStep:100,min:N,max:z,value:e.width,styleValue:a.widthPx,onChange:n=>i({width:n??null})}],S=D(p,r);return T("div",{className:"sf-part-textbox",children:[f,o(A,{value:c,onChange:d,multiline:r,placeholder:s,ariaLabel:P,rules:R,tools:S,barShows:m?"focus":"always",colors:p?h:[],align:t?{value:e.align??a.align,allow:E,onChange:n=>i({align:n})}:void 0,letterCase:t?{value:e.case??"",onChange:n=>i({case:n||null})}:void 0,cells:t?_:void 0})]})}export{Y as PartTextBox};
@@ -1,4 +1,4 @@
1
- "use client";import{jsx as n,Fragment as h,jsxs as l}from"react/jsx-runtime";import{useEffect as a,useLayoutEffect as u}from"react";import{usePreviewHeader as c}from"./PreviewHeaderContext.js";import{tk as d}from"./floating-editor/tokens.js";import{PART_ATTR as m,PART_SELECTED_ATTR as t}from"../lib/puck/text-parts.js";import{syncPreviewSurfaces as T,syncPreviewTheme as $}from"../lib/theme-dom.js";import{normalizeTheme as p}from"../lib/theme.js";import{CanvasOwnStyles as x}from"../lib/editor-canvas-styles.js";import{runFitWordsIn as P}from"../lib/fit-words.js";const S=`
1
+ "use client";import{jsx as n,Fragment as h,jsxs as l}from"react/jsx-runtime";import{useEffect as a,useLayoutEffect as u}from"react";import{usePreviewHeader as $}from"./PreviewHeaderContext.js";import{tk as d}from"./floating-editor/tokens.js";import{PART_ATTR as m,PART_SELECTED_ATTR as t}from"../lib/puck/text-parts.js";import{syncPreviewSurfaces as c,syncPreviewTheme as T}from"../lib/theme-dom.js";import{normalizeTheme as p}from"../lib/theme.js";import{CanvasOwnStyles as x}from"../lib/editor-canvas-styles.js";import{runFitWordsIn as y}from"../lib/fit-words.js";const P=`
2
2
  [${m}][${m}] { cursor: text; }
3
3
  [${t}][${t}][${t}] {
4
4
  outline: 1px solid ${d.accent};
@@ -8,4 +8,8 @@
8
8
  [data-puck-overlay-portal][data-puck-overlay-portal]:has([${t}]) {
9
9
  outline: none;
10
10
  }
11
- `;function _({children:f,document:r}){const{theme:i,themeMode:e,themeSwitchShown:o}=c(),s=p(i);return a(()=>{if(r)return $(r,{mode:e,switchShown:o})},[r,e,o]),a(()=>{if(r)return T(r,s)},[r,s]),u(()=>{if(r)return P(r)},[r]),l(h,{children:[n(x,{}),n("style",{children:S}),f]})}export{S as PART_PICK_CSS,_ as default};
11
+ [${t}][${t}][${t}][data-es-typing],
12
+ [data-es-typing] [${t}][${t}][${t}] {
13
+ outline: none;
14
+ }
15
+ `;function S({children:i,document:r}){const{theme:f,themeMode:e,themeSwitchShown:o}=$(),s=p(f);return a(()=>{if(r)return T(r,{mode:e,switchShown:o})},[r,e,o]),a(()=>{if(r)return c(r,s)},[r,s]),u(()=>{if(r)return y(r)},[r]),l(h,{children:[n(x,{}),n("style",{children:P}),i]})}export{P as PART_PICK_CSS,S as default};
@@ -1 +1 @@
1
- "use client";import{jsx as S}from"react/jsx-runtime";import{useLayoutEffect as O,useMemo as B,useRef as k,useState as T}from"react";import{useSelectedFields as D}from"efficient-easel/easel";import{Inspector as K,planFields as x}from"efficient-easel/fields";import{BUCKET_ICONS as j,entriesHiddenForTab as v}from"../lib/puck/controls.js";import{BUCKETS as L}from"../lib/puck/field-groups.js";import{say as q}from"../lib/editor-words.js";import{bandIsDropped as R,droppedBands as U,sameKeys as X,TEXT_BAND_KEY as F,TEXT_BAND_TITLE as G,withoutBands as H}from"../lib/puck/panel-bands.js";const E=new Map,f=new Set;function P(n,r){const s=new Map;for(const l of n.querySelectorAll(".es-insp-row[data-field]"))s.set(l.getAttribute("data-field")??"",l);const o=[];for(const[l,m]of r)o.push({key:l,rows:m.map(p=>{const d=s.get(p),c=!!d&&[...d.children].some(w=>!w.hidden),i=d?.querySelector(".es-field-label, .es-list-label")?.textContent?.trim();return{shown:c,labelled:c&&!!i}})});return o}const Y=Object.fromEntries(L.map(n=>{const r=j[n];return[n,S(r,{},n)]}));function te({entries:n,entryCount:r=0}){const{id:s,fields:o,values:l,readOnly:m,onChange:p}=D(),[d,c]=T(()=>new Set(f)),[i,w]=T(()=>new Set),g=k(null),C=B(()=>{const e=new Map;for(const t of x(o).rows){if(!t.fold)continue;const a=e.get(t.fold.key)??[];a.push(t.name),e.set(t.fold.key,a)}return e},[o]);O(()=>{const e=g.current?.parentElement;if(!e)return;const t=new Set(U(P(e,C)));w(a=>X(a,t)?a:t)});const _=B(()=>H(o,i),[o,i]),A={key:F,rows:Array.from({length:r},()=>({shown:!0,labelled:!0}))},I=r>0&&!R(A)?{key:F,title:G}:void 0,[b,M]=T(()=>E.get(s)),h=E.get(s),u=x(o).buckets,y=h&&u.includes(h)?h:b&&u.includes(b)?b:u[0],N=y===void 0||v(u,y)!==!0;return S(K,{fields:_,values:l,onChange:p,readOnly:m,tab:y,onTab:e=>{E.set(s,e),M(e)},tabIcons:Y,idPrefix:s,ariaLabel:q("Section settings"),lead:N?n:null,leadFold:I,closedFolds:d,onFold:(e,t)=>{t?f.delete(e):f.add(e),c(new Set(f))},children:S("span",{ref:g,hidden:!0})})}export{te as SiteFields,Y as TAB_ICONS};
1
+ "use client";import{jsx as S}from"react/jsx-runtime";import{useLayoutEffect as O,useMemo as B,useRef as k,useState as T}from"react";import{useSelectedFields as D}from"efficient-easel/easel";import{Inspector as K,planFields as x}from"efficient-easel/fields";import{BUCKET_ICONS as j,entriesHiddenForTab as v}from"../lib/puck/controls.js";import{BUCKETS as L}from"../lib/puck/field-groups.js";import{say as q}from"../lib/editor-words.js";import{bandIsDropped as R,droppedBands as U,sameKeys as X,TEXT_BAND_KEY as C,TEXT_BAND_TITLE as G,withoutBands as H}from"../lib/puck/panel-bands.js";const E=new Map,f=new Set;function P(n,l){const s=new Map;for(const r of n.querySelectorAll(".es-insp-row[data-field]"))s.set(r.getAttribute("data-field")??"",r);const o=[];for(const[r,m]of l)o.push({key:r,rows:m.map(p=>{const d=s.get(p),c=!!d&&[...d.children].some(w=>!w.hidden),i=d?.querySelector(".es-field-label, .es-list-label")?.textContent?.trim();return{shown:c,labelled:c&&!!i}})});return o}const Y=Object.fromEntries(L.map(n=>{const l=j[n];return[n,S(l,{},n)]}));function te({entries:n,entryCount:l=0}){const{id:s,fields:o,values:r,readOnly:m,onChange:p}=D(),[d,c]=T(()=>new Set(f)),[i,w]=T(()=>new Set),g=k(null),F=B(()=>{const e=new Map;for(const t of x(o).rows){if(!t.fold)continue;const a=e.get(t.fold.key)??[];a.push(t.name),e.set(t.fold.key,a)}return e},[o]);O(()=>{const e=g.current?.parentElement;if(!e)return;const t=new Set(U(P(e,F)));w(a=>X(a,t)?a:t)});const _=B(()=>H(o,i),[o,i]),A={key:C,rows:Array.from({length:l},()=>({shown:!0,labelled:!0}))},I=R(A)?void 0:{key:C,title:G},[b,M]=T(()=>E.get(s)),y=E.get(s),u=x(o).buckets,h=y&&u.includes(y)?y:b&&u.includes(b)?b:u[0],N=h===void 0||v(u,h)!==!0;return S(K,{fields:_,values:r,onChange:p,readOnly:m,tab:h,onTab:e=>{E.set(s,e),M(e)},tabIcons:Y,idPrefix:s,ariaLabel:q("Section settings"),lead:N?n:null,leadFold:I,closedFolds:d,onFold:(e,t)=>{t?f.delete(e):f.add(e),c(new Set(f))},children:S("span",{ref:g,hidden:!0})})}export{te as SiteFields,Y as TAB_ICONS};
@@ -1 +1 @@
1
- "use client";import{jsx as r,jsxs as I}from"react/jsx-runtime";import{useCallback as C,useEffect as S,useState as j}from"react";import{ExternalIcon as z}from"efficient-easel/icons";import{Button as K,Tooltip as A,buttonClasses as U}from"efficient-shell/ui";import{SettingsSwitch as Z}from"efficient-easel/panel";import{PagesIcon as q,StylesIcon as X}from"efficient-easel/rail";import{TreeRow as J}from"efficient-easel/tree";import{useEaselStrings as Q}from"efficient-easel/strings";import{LocationsTreeContext as $}from"./LocationsTreeContext.js";import ee from"./PagesPanel.js";import{usePreviewChat as te}from"./PreviewChatContext.js";import{PREVIEW_DEVICES as oe}from"./preview-devices.js";import{PreviewDeviceContext as re}from"./PreviewDeviceContext.js";import{usePreviewHeader as ie}from"./PreviewHeaderContext.js";import{usePreviewSocial as se}from"./PreviewSocialContext.js";import{usePreviewSurface as ne}from"./PreviewSurfaceContext.js";import{TICKER_PART_LABEL as ae,usePreviewTicker as ce}from"./PreviewTickerContext.js";import le,{CHAT_MODE as de,HEADER_MODE as B,SOCIAL_MODE as pe,WEBSITE_MODE as N}from"./SectionEditor.js";import g from"./SectionIcon.js";import me from"./SectionThumbnail.js";import{useStorefrontDocument as _}from"./StorefrontDocumentContext.js";import fe from"./StylesPanel.js";import ue from"./TemplateGlyph.js";import{useFooterFocus as Se}from"./useFooterFocus.js";import{LOCATIONS_TYPE as Te,useLocationsTree as Ee}from"./useLocationsTree.js";import{usePinnedChromeSeed as he}from"./usePinnedChromeSeed.js";import{usePreviewHref as we}from"./usePreviewHref.js";import{SITE_STYLES_TABS as be,SITE_STYLES_TEXT_TAB as Pe,useWebsiteName as ve}from"./WebsiteSettingsPanel.js";import{useOpenPageName as ke}from"../lib/page-rows.js";import{HERO_GROUP_TYPE as Ie,duplicateBlocked as Ce,heroGroupNestDepth as ge}from"../lib/hero-group-placement.js";import{stripMarkup as _e}from"../lib/markup.js";import{categoryShortLabel as Le,PINNED_SECTION_TYPE as ye}from"../lib/puck/add-palette.js";import{canAddTo as Oe}from"../lib/puck/add-target.js";import{blockIsOffered as Ae}from"../lib/puck/block-offer.js";import{sectionIdOfBoxZone as Be,setBookingPreview as Ne}from"../lib/puck/booking-preview.js";import{footerBlockRowName as Re}from"../lib/puck/footer-block-row-name.js";import{FOOTER_TYPE as De,HEADER_TYPE as R}from"../lib/puck/footer-blocks.js";import{leftViewForSelection as He,readLeftView as We,resolveLeftView as xe,writeLeftView as Ve}from"../lib/puck/left-view.js";import{isLockedBlock as Me}from"../lib/puck/locked-blocks.js";import{scrollPreviewToSection as Ye,scrollPreviewToTop as D}from"../lib/puck/preview-dom.js";import{SiteCanvas as Fe}from"../lib/puck/overrides.js";import{labelAtLevel as Ge}from"../lib/puck/section-catalog.js";import{editorWords as je,say as i}from"../lib/editor-words.js";import{SECTION_DESCRIPTIONS as ze}from"../lib/puck/section-descriptions.js";import{isSectionGroupType as Ke,sectionGroupZone as Ue,SITE_FOOTER_TYPE as Ze,SITE_HEADER_TYPE as qe}from"../lib/puck/section-groups.js";import{resolveSaveAsTemplateAction as Xe,SAVE_AS_TEMPLATE_EVENT as Je}from"../lib/save-as-template-action.js";import{newSectionNode as Qe}from"../lib/sections/new-section-node.js";import{useHostProducts as $e}from"../lib/use-host-products.js";function H({mode:e,open:t}){const{setSelectedHeroId:o,setSelectHandler:s}=ce(),m=Q().tree,c=e,l=c.kind==="ticker"?c.heroId:null,n=C(d=>{if(!d)return;t({kind:"ticker",heroId:d}),Ye(d)},[t]);return S(()=>{o(l)},[l,o]),S(()=>{s(n)},[s,n]),{partRows:(d,{rowClick:a})=>{const f=String(d.props.id);return d.type==="Hero"&&r(J,{icon:r(g,{type:"ticker",size:13}),name:i(ae),onSelect:()=>n(f),selected:l===f,rowProps:{onClick:a(()=>n(f))},words:m})}}}function et(){const{adapter:e,capabilities:t,currentSlug:o,siteId:s,hasUnsavedEdits:m,bridgeCapabilities:c,notifyParent:l,token:n}=_(),{hasPreviewLink:d}=t,a=Xe({hasTrustedConsole:!!n,canCreatePlatformTemplate:c.canCreatePlatformTemplate,capabilities:t,siteId:s,hasUnsavedEdits:m}),f=C(()=>{!s||!o||l(Je,{siteId:s,slug:o})},[l,s,o]),T=we({pageSlug:o,siteId:s,token:n}),E=e.previewHref?.(o)??T;return{barLead:()=>a.visible&&r(A,{side:"bottom",content:a.enabled?i("Save this website as a platform template"):i(a.disabledReason),children:r("span",{className:"sf-tip-disabled",tabIndex:a.enabled?void 0:0,children:r(K,{variant:"secondary",disabled:!a.enabled,onClick:f,rightIcon:r(ue,{}),children:i("Save as Template")})})}),barTrail:()=>d&&o&&r(A,{content:i("Preview the live site (opens in a new tab)"),children:I("a",{className:U({variant:"secondary"}),href:E,target:"_blank",rel:"noopener noreferrer","aria-label":i("Preview the live site in a new tab"),children:[i("Preview"),r(z,{size:15})]})})}}function tt(){return I("svg",{width:"17",height:"17",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.7,strokeLinecap:"round",strokeLinejoin:"round",children:[r("path",{d:"M12 3a9 9 0 0 0 0 18 2.3 2.3 0 0 0 2.3-2.3c0-.55-.22-1.05-.57-1.42-.34-.37-.56-.87-.56-1.43A2.35 2.35 0 0 1 15.6 13.5H18a3 3 0 0 0 3-3c0-4.14-4-7.5-9-7.5z"}),r("circle",{cx:"7.7",cy:"11.3",r:"1.05",fill:"currentColor",stroke:"none"}),r("circle",{cx:"12",cy:"8",r:"1.05",fill:"currentColor",stroke:"none"}),r("circle",{cx:"16",cy:"11",r:"1.05",fill:"currentColor",stroke:"none"})]})}function ot(e,t){const{capabilities:o,templateId:s,siteId:m,tokenRef:c,navigate:l}=_(),{hasSiteTheme:n,explainsSiteSettings:d}=o,a=p=>t.setView(p),[f,T]=j(be[0].id),{surface:E,setSurface:P}=ne(),v=()=>{if(n){a("styles"),t.reveal(),D();return}e.show(N),e.reveal(),D()},k={id:"pages",label:i("Pages"),icon:r(q,{}),panel:({onHide:p,notify:u})=>r(ee,{notify:u,activeSurface:E,onPreviewSurface:P,onNavigate:w=>{P(null),l(s?{kind:"template",id:s,pageSlug:w}:{kind:"page",slug:w,siteId:m??void 0})},onClose:p})},h=[];return!n&&d&&h.push({id:"appearance",label:i("Appearance"),icon:r(tt,{}),active:e.kind==="website",onSelect:v}),n&&h.push({id:"styles",label:i("Site styles"),icon:r(X,{}),panel:({onHide:p,notify:u})=>r(fe,{tokenRef:c,siteId:m??void 0,onClose:p,onNotify:u,tab:f,onTabChange:T})}),{railLead:[k],railTrail:h,resolveLeftView:(p,u)=>xe(p,n,u),openSettings:v,openStyles:()=>{T(Pe),a("styles")}}}function rt(e,t,o,s){const{kind:m,open:c}=e,{selected:l,zoneOf:n}=t,d=Se(t,o);S(()=>{Ne(l?.type==="BookingBox"&&l.props.region==="confirm"?Be(n(String(l.props.id))):null)},[l?.props.id]);const a=Ee(e,t),{capabilities:{hasSiteSettings:f}}=_(),{setSelected:T,setSelectHandler:E}=ie(),{chat:P,setChat:v,setSelected:k,setSelectHandler:h}=te(),p=m==="header";S(()=>{T(p)},[p,T]),S(()=>{E(()=>c(B))},[E,c]);const u=C(()=>c(de),[c]),w=m==="chat";S(()=>{k(w)},[w,k]),S(()=>{h(u)},[h,u]);const{setOpenHandler:y}=se(),O=C(()=>c(pe),[c]);S(()=>{y(O)},[y,O]);const V=H(e),M=et(),Y=ot(e,s),F=o.device;return{...d,...V,...M,...Y,hasOwnRows:b=>b.type===Te,ownRows:a.renderLocationTree,sectionPressed:a.sectionPressed,wrap:b=>r($.Provider,{value:!0,children:r(re.Provider,{value:F,children:b})}),addPanelRow:b=>f?I("div",{className:"sf-addside-sitewide",children:[r("span",{className:"sf-addside-sitewide-glyph","aria-hidden":"true",children:r(g,{type:"chat",size:16})}),I("button",{type:"button",className:"sf-addside-sitewide-name",onClick:()=>{b(),u()},children:[i("Live chat"),r("span",{className:"sf-addside-sitewide-desc",children:i("A chat bubble on every page")})]}),r(Z,{checked:P.enabled,onChange:G=>v({enabled:G}),ariaLabel:i("Show the chat bubble on the whole site")})]}):void 0}}let W=null,L=new WeakMap;function it(e){const t=je();if(!e||!t)return e;W!==t&&(W=t,L=new WeakMap);let o=L.get(e);return o||(o={...e,choices:e.choices?e.choices.map(s=>({...s,label:i(s.label)})):null,spec:e.spec?{...e.spec,addLabel:i(e.spec.addLabel)}:null},L.set(e,o)),o}const st={isLockedBlock:Me,duplicateBlocked:Ce,nestDepth:(e,t,o)=>t===Ie?ge(e,o):0,newSectionNode:Qe,canAddTo:(e,t)=>it(Oe(e,t)),blockIsOffered:Ae},nt=new Proxy(ze,{get:(e,t)=>{const o=Reflect.get(e,t);return typeof o=="string"?i(o):o}}),at={labelAtLevel:(e,t,o)=>i(Ge(e,t,o)),descriptions:nt,categoryLabel:e=>{const t=Le(e);return t===void 0?void 0:i(t)},firstSection:ye,blockRowName:Re,plainText:_e,Icon:g,Thumbnail:me,useProducts:$e},ct={desktop:2e3,tablet:800,mobile:390},x="desktop",lt={options:oe,initial:x,fluid:x,widths:ct},dt={read:We,write:e=>Ve(e),forSelection:(e,t)=>He(e,t)},pt={first:R,last:De,firstGroup:qe,lastGroup:Ze,isSectionGroup:Ke,sectionGroupZone:Ue,panelOf:e=>e===R?B:null};function mt(e){return{...H(e),openSettings:()=>e.show(N)}}const ao={useOwnerName:ve,useDocumentLabel:ke,useBridges:rt,useStandaloneBridges:mt,useDocumentPass:he,blockRules:st,blockLook:at,devices:lt,leftView:dt,pinned:pt,Canvas:Fe,Inspector:le};export{ao as WEBSITE_SCREEN};
1
+ "use client";import{jsx as r,jsxs as k}from"react/jsx-runtime";import{useCallback as I,useEffect as S,useState as j}from"react";import{ExternalIcon as z}from"efficient-easel/icons";import{Button as K,Tooltip as A,buttonClasses as U}from"efficient-shell/ui";import{SettingsSwitch as Z}from"efficient-easel/panel";import{PagesIcon as q,StylesIcon as X}from"efficient-easel/rail";import{TreeRow as J}from"efficient-easel/tree";import{useEaselStrings as Q}from"efficient-easel/strings";import{LocationsTreeContext as $}from"./LocationsTreeContext.js";import ee from"./PagesPanel.js";import{usePreviewChat as te}from"./PreviewChatContext.js";import{PREVIEW_DEVICES as oe}from"./preview-devices.js";import{PreviewDeviceContext as re}from"./PreviewDeviceContext.js";import{usePreviewHeader as ie}from"./PreviewHeaderContext.js";import{usePreviewSocial as se}from"./PreviewSocialContext.js";import{usePreviewSurface as ne}from"./PreviewSurfaceContext.js";import{TICKER_PART_LABEL as ae,usePreviewTicker as ce}from"./PreviewTickerContext.js";import le,{CHAT_MODE as de,HEADER_MODE as B,SOCIAL_MODE as pe,WEBSITE_MODE as N}from"./SectionEditor.js";import C from"./SectionIcon.js";import me from"./SectionThumbnail.js";import{useStorefrontDocument as g}from"./StorefrontDocumentContext.js";import fe from"./StylesPanel.js";import ue from"./TemplateGlyph.js";import{useFooterFocus as Se}from"./useFooterFocus.js";import{LOCATIONS_TYPE as Te,useLocationsTree as Ee}from"./useLocationsTree.js";import{usePinnedChromeSeed as he}from"./usePinnedChromeSeed.js";import{usePreviewHref as we}from"./usePreviewHref.js";import{SITE_STYLES_TABS as be,SITE_STYLES_TEXT_TAB as Pe,useWebsiteName as ve}from"./WebsiteSettingsPanel.js";import{useOpenPageName as ke}from"../lib/page-rows.js";import{HERO_GROUP_TYPE as Ie,duplicateBlocked as Ce,heroGroupNestDepth as ge}from"../lib/hero-group-placement.js";import{stripMarkup as _e}from"../lib/markup.js";import{categoryShortLabel as Le,PINNED_SECTION_TYPE as Oe}from"../lib/puck/add-palette.js";import{canAddTo as ye}from"../lib/puck/add-target.js";import{blockIsOffered as Ae}from"../lib/puck/block-offer.js";import{sectionIdOfBoxZone as Be,setBookingPreview as Ne}from"../lib/puck/booking-preview.js";import{footerBlockRowName as Re}from"../lib/puck/footer-block-row-name.js";import{FOOTER_TYPE as De,HEADER_TYPE as R}from"../lib/puck/footer-blocks.js";import{leftViewForSelection as He,readLeftView as We,resolveLeftView as xe,writeLeftView as Ve}from"../lib/puck/left-view.js";import{isLockedBlock as Me}from"../lib/puck/locked-blocks.js";import{scrollPreviewToSection as Ye,scrollPreviewToTop as D}from"../lib/puck/preview-dom.js";import{SiteCanvas as Fe}from"../lib/puck/overrides.js";import{labelAtLevel as Ge}from"../lib/puck/section-catalog.js";import{editorWords as je,say as i}from"../lib/editor-words.js";import{SECTION_DESCRIPTIONS as ze}from"../lib/puck/section-descriptions.js";import{isSectionGroupType as Ke,sectionGroupZone as Ue,SITE_FOOTER_TYPE as Ze,SITE_HEADER_TYPE as qe}from"../lib/puck/section-groups.js";import{resolveSaveAsTemplateAction as Xe,SAVE_AS_TEMPLATE_EVENT as Je}from"../lib/save-as-template-action.js";import{newSectionNode as Qe}from"../lib/sections/new-section-node.js";import{useHostProducts as $e}from"../lib/use-host-products.js";function H({mode:e,open:t}){const{setSelectedHeroId:o,setSelectHandler:s}=ce(),f=Q().tree,c=e,l=c.kind==="ticker"?c.heroId:null,n=I(d=>{if(!d)return;t({kind:"ticker",heroId:d}),Ye(d)},[t]);return S(()=>{o(l)},[l,o]),S(()=>{s(n)},[s,n]),{partRows:(d,{rowClick:a})=>{const u=String(d.props.id);return d.type==="Hero"&&r(J,{icon:r(C,{type:"ticker",size:13}),name:i(ae),onSelect:()=>n(u),selected:l===u,rowProps:{onClick:a(()=>n(u))},words:f})}}}function et(){const{adapter:e,capabilities:t,currentSlug:o,siteId:s,hasUnsavedEdits:f,bridgeCapabilities:c,notifyParent:l,token:n}=g(),{hasPreviewLink:d}=t,a=Xe({hasTrustedConsole:!!n,canCreatePlatformTemplate:c.canCreatePlatformTemplate,capabilities:t,siteId:s,hasUnsavedEdits:f}),u=I(()=>{!s||!o||l(Je,{siteId:s,slug:o})},[l,s,o]),T=we({pageSlug:o,siteId:s,token:n}),E=e.previewHref?.(o)??T;return{barLead:()=>a.visible&&r(A,{side:"bottom",content:a.enabled?i("Save this website as a platform template"):i(a.disabledReason),children:r("span",{className:"sf-tip-disabled",tabIndex:a.enabled?void 0:0,children:r(K,{variant:"secondary",disabled:!a.enabled,onClick:u,rightIcon:r(ue,{}),children:i("Save as Template")})})}),barTrail:()=>d&&o&&r(A,{content:i("Preview the live site (opens in a new tab)"),children:k("a",{className:U({variant:"secondary"}),href:E,target:"_blank",rel:"noopener noreferrer","aria-label":i("Preview the live site in a new tab"),children:[i("Preview"),r(z,{size:15})]})})}}function tt(){return k("svg",{width:"17",height:"17",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.7,strokeLinecap:"round",strokeLinejoin:"round",children:[r("path",{d:"M12 3a9 9 0 0 0 0 18 2.3 2.3 0 0 0 2.3-2.3c0-.55-.22-1.05-.57-1.42-.34-.37-.56-.87-.56-1.43A2.35 2.35 0 0 1 15.6 13.5H18a3 3 0 0 0 3-3c0-4.14-4-7.5-9-7.5z"}),r("circle",{cx:"7.7",cy:"11.3",r:"1.05",fill:"currentColor",stroke:"none"}),r("circle",{cx:"12",cy:"8",r:"1.05",fill:"currentColor",stroke:"none"}),r("circle",{cx:"16",cy:"11",r:"1.05",fill:"currentColor",stroke:"none"})]})}function ot(e,t){const{capabilities:o,templateId:s,siteId:f,tokenRef:c,navigate:l}=g(),{hasSiteTheme:n,explainsSiteSettings:d}=o,a=p=>t.setView(p),[u,T]=j(be[0].id),{surface:E,setSurface:b}=ne(),P=()=>{if(n){a("styles"),t.reveal(),D();return}e.show(N),e.reveal(),D()},v={id:"pages",label:i("Pages"),icon:r(q,{}),panel:({onHide:p})=>r(ee,{activeSurface:E,onPreviewSurface:b,onNavigate:m=>{b(null),l(s?{kind:"template",id:s,pageSlug:m}:{kind:"page",slug:m,siteId:f??void 0})},onClose:p})},h=[];return!n&&d&&h.push({id:"appearance",label:i("Appearance"),icon:r(tt,{}),active:e.kind==="website",onSelect:P}),n&&h.push({id:"styles",label:i("Site styles"),icon:r(X,{}),panel:({onHide:p,notify:m})=>r(fe,{tokenRef:c,siteId:f??void 0,onClose:p,onNotify:m,tab:u,onTabChange:T})}),{railLead:[v],railTrail:h,resolveLeftView:(p,m)=>xe(p,n,m),openSettings:P,openStyles:()=>{T(Pe),a("styles")}}}function rt(e,t,o,s){const{kind:f,open:c}=e,{selected:l,zoneOf:n}=t,d=Se(t,o);S(()=>{Ne(l?.type==="BookingBox"&&l.props.region==="confirm"?Be(n(String(l.props.id))):null)},[l?.props.id]);const a=Ee(e,t),{capabilities:{hasSiteSettings:u}}=g(),{setSelected:T,setSelectHandler:E}=ie(),{chat:b,setChat:P,setSelected:v,setSelectHandler:h}=te(),p=f==="header";S(()=>{T(p)},[p,T]),S(()=>{E(()=>c(B))},[E,c]);const m=I(()=>c(de),[c]),L=f==="chat";S(()=>{v(L)},[L,v]),S(()=>{h(m)},[h,m]);const{setOpenHandler:O}=se(),y=I(()=>c(pe),[c]);S(()=>{O(y)},[O,y]);const V=H(e),M=et(),Y=ot(e,s),F=o.device;return{...d,...V,...M,...Y,hasOwnRows:w=>w.type===Te,ownRows:a.renderLocationTree,sectionPressed:a.sectionPressed,wrap:w=>r($.Provider,{value:!0,children:r(re.Provider,{value:F,children:w})}),addPanelRow:w=>u?k("div",{className:"sf-addside-sitewide",children:[r("span",{className:"sf-addside-sitewide-glyph","aria-hidden":"true",children:r(C,{type:"chat",size:16})}),k("button",{type:"button",className:"sf-addside-sitewide-name",onClick:()=>{w(),m()},children:[i("Live chat"),r("span",{className:"sf-addside-sitewide-desc",children:i("A chat bubble on every page")})]}),r(Z,{checked:b.enabled,onChange:G=>P({enabled:G}),ariaLabel:i("Show the chat bubble on the whole site")})]}):void 0}}let W=null,_=new WeakMap;function it(e){const t=je();if(!e||!t)return e;W!==t&&(W=t,_=new WeakMap);let o=_.get(e);return o||(o={...e,choices:e.choices?e.choices.map(s=>({...s,label:i(s.label)})):null,spec:e.spec?{...e.spec,addLabel:i(e.spec.addLabel)}:null},_.set(e,o)),o}const st={isLockedBlock:Me,duplicateBlocked:Ce,nestDepth:(e,t,o)=>t===Ie?ge(e,o):0,newSectionNode:Qe,canAddTo:(e,t)=>it(ye(e,t)),blockIsOffered:Ae},nt=new Proxy(ze,{get:(e,t)=>{const o=Reflect.get(e,t);return typeof o=="string"?i(o):o}}),at={labelAtLevel:(e,t,o)=>i(Ge(e,t,o)),descriptions:nt,categoryLabel:e=>{const t=Le(e);return t===void 0?void 0:i(t)},firstSection:Oe,blockRowName:Re,plainText:_e,Icon:C,Thumbnail:me,useProducts:$e},ct={desktop:2e3,tablet:800,mobile:390},x="desktop",lt={options:oe,initial:x,fluid:x,widths:ct},dt={read:We,write:e=>Ve(e),forSelection:(e,t)=>He(e,t)},pt={first:R,last:De,firstGroup:qe,lastGroup:Ze,isSectionGroup:Ke,sectionGroupZone:Ue,panelOf:e=>e===R?B:null};function mt(e){return{...H(e),openSettings:()=>e.show(N)}}const ao={useOwnerName:ve,useDocumentLabel:ke,useBridges:rt,useStandaloneBridges:mt,useDocumentPass:he,blockRules:st,blockLook:at,devices:lt,leftView:dt,pinned:pt,Canvas:Fe,Inspector:le};export{ao as WEBSITE_SCREEN};
@@ -1,4 +1,5 @@
1
1
  import type { EditorPageRow } from "./editor-document-adapter.js";
2
+ export declare function holdPageRow(id: string, on: boolean): void;
2
3
  export declare function usePageRows(): {
3
4
  rows: EditorPageRow[] | null;
4
5
  reload: () => Promise<void>;
@@ -1 +1 @@
1
- "use client";import{useCallback as i,useEffect as p,useSyncExternalStore as S}from"react";import{useStorefrontDocument as f}from"../components/StorefrontDocumentContext.js";import{heldDeleteIds as b}from"./held-page-delete.js";const d=new WeakMap;function r(e){let n=d.get(e);return n||(n={rows:null,loading:null,listeners:new Set},d.set(e,n)),n}function u(e,n){e.rows=n;for(const t of e.listeners)t()}function g(e){const n=r(e),t=e.listPages().then(o=>{const l=new Set(b());u(n,l.size?o.filter(c=>!l.has(c.id)):o)},()=>u(n,[])).finally(()=>{n.loading===t&&(n.loading=null)});return n.loading=t,t}const m=()=>null,O=()=>()=>{};function y(){const{adapter:e,ready:n}=f(),t=i(s=>{const{listeners:a}=r(e);return a.add(s),()=>a.delete(s)},[e]),o=i(()=>r(e).rows,[e]),l=S(n?t:O,n?o:m,m);p(()=>{if(!n)return;const s=r(e);s.rows===null&&!s.loading&&g(e)},[e,n]);const c=i(()=>n?g(e):Promise.resolve(),[e,n]),w=i(s=>u(r(e),s),[e]);return{rows:l,reload:c,setRows:w,getRows:o}}function h(e,n){return e?.find(o=>o.slug===n)?.label?.trim()||`/${n}`}function x(){const{currentSlug:e}=f(),{rows:n}=y();return h(n,e)}export{h as pageNameOf,x as useOpenPageName,y as usePageRows};
1
+ "use client";import{useCallback as l,useEffect as S,useSyncExternalStore as b}from"react";import{useStorefrontDocument as f}from"../components/StorefrontDocumentContext.js";const d=new WeakMap;function r(e){let n=d.get(e);return n||(n={rows:null,loading:null,listeners:new Set},d.set(e,n)),n}function u(e,n){e.rows=n;for(const t of e.listeners)t()}const i=new Set;function x(e,n){n?i.add(e):i.delete(e)}function g(e){const n=r(e),t=e.listPages().then(o=>u(n,i.size?o.filter(c=>!i.has(c.id)):o),()=>u(n,[])).finally(()=>{n.loading===t&&(n.loading=null)});return n.loading=t,t}const w=()=>null,O=()=>()=>{};function P(){const{adapter:e,ready:n}=f(),t=l(s=>{const{listeners:a}=r(e);return a.add(s),()=>a.delete(s)},[e]),o=l(()=>r(e).rows,[e]),c=b(n?t:O,n?o:w,w);S(()=>{if(!n)return;const s=r(e);s.rows===null&&!s.loading&&g(e)},[e,n]);const m=l(()=>n?g(e):Promise.resolve(),[e,n]),p=l(s=>u(r(e),s),[e]);return{rows:c,reload:m,setRows:p,getRows:o}}function R(e,n){return e?.find(o=>o.slug===n)?.label?.trim()||`/${n}`}function N(){const{currentSlug:e}=f(),{rows:n}=P();return R(n,e)}export{x as holdPageRow,R as pageNameOf,N as useOpenPageName,P as usePageRows};
@@ -0,0 +1,31 @@
1
+ import type { MarkStyle } from "efficient-easel/markup";
2
+ import { SHOP_MARKUP } from "../markup.js";
3
+ import type { TreeItem } from "./content-tree.js";
4
+ import { type ReplacePart } from "./part-typing.js";
5
+ export declare function partTextTools(markup: boolean, multiline: boolean): MarkStyle[];
6
+ export type PartTypingDeps = {
7
+ getItemById: (id: string) => TreeItem | undefined;
8
+ getSelectorForId: (id: string) => {
9
+ zone: string;
10
+ index: number;
11
+ } | undefined;
12
+ components: Record<string, {
13
+ fields?: Record<string, unknown>;
14
+ } | undefined>;
15
+ replace: ReplacePart;
16
+ };
17
+ export type PartTyping = {
18
+ partId: string;
19
+ value: string;
20
+ rules: typeof SHOP_MARKUP;
21
+ multiline: boolean;
22
+ offered: MarkStyle[];
23
+ write: (next: string) => void;
24
+ };
25
+ export declare function partTypingTarget(partId: string, deps: PartTypingDeps): PartTyping | null;
26
+ export declare function partElement(last: Pick<HTMLElement, "isConnected" | "getAttribute"> | null, doc: Pick<Document, "querySelector"> | null, partId: string): HTMLElement | null;
27
+ export declare function keysOnCanvas(doc: Pick<Document, "activeElement">): boolean;
28
+ export declare function canvasTypingPart(): string | null;
29
+ export declare function setCanvasTypingPart(partId: string | null): void;
30
+ export declare function subscribeCanvasTypingPart(listener: () => void): () => void;
31
+ export declare function useCanvasTypingPart(): string | null;
@@ -0,0 +1 @@
1
+ import{useSyncExternalStore as T}from"react";import{SHOP_MARKUP as P}from"../markup.js";import{readHidable as S,textFieldOffPage as k}from"./controls.js";import{decodePartId as v}from"./part-id.js";import{PART_ATTR as y}from"./text-parts.js";import{partRowField as b}from"./part-row-field.js";import{decodePartKey as K,partRowValue as O}from"./part-rows.js";import{isMultilineKind as A,typeInPlaceKind as R}from"./part-text.js";import{commitPartText as w}from"./part-typing.js";const C=["bold","italic","underline","strike","link","sup","sub"],F=["bullet","number"];function E(e,t){return e?[...C,...t?F:[]]:[]}function g(e,t){const r=v(e);if(!r?.propKey)return null;const{nodeId:l,propKey:u}=r,o=t.getItemById(l),s=t.getSelectorForId(l);if(!o||!s)return null;const{key:n,row:i}=K(u),p=t.components[o.type]?.fields?.[n],d=i?b(p,i):p,m=R(d);if(!m)return null;const c=o.props??{};if(i&&!(Array.isArray(c[n])&&i.index<c[n].length))return null;const x=i?O(c[n],i):c[n];return{node:o,selector:s,propKey:u,kind:m,stored:x,offPage:k(d)}}function U(e,t){const r=g(e,t);if(!r||r.offPage)return null;const{text:l,hidden:u}=S(r.stored);if(u)return null;const o=A(r.kind);return{partId:e,value:l,rules:P,multiline:o,offered:E(r.kind!=="plainText",o),write:s=>{const n=g(e,t);n&&w({node:n.node,propKey:n.propKey,kind:n.kind,zone:n.selector.zone,index:n.selector.index},s,t.replace)}}}function V(e,t,r){return e?.isConnected&&e.getAttribute(y)===r?e:t?.querySelector(`[${y}="${I(r)}"]`)??null}function I(e){return e.replace(/["\\]/g,"\\$&")}function W(e){const t=e.activeElement;return t?t.tagName==="IFRAME"||!!t.closest(".es-canvas"):!1}let a=null;const f=new Set;function _(){return a}function j(e){if(e!==a){a=e;for(const t of f)t()}}function L(e){return f.add(e),()=>{f.delete(e)}}function G(){return T(L,_,()=>null)}export{_ as canvasTypingPart,W as keysOnCanvas,V as partElement,E as partTextTools,U as partTypingTarget,j as setCanvasTypingPart,L as subscribeCanvasTypingPart,G as useCanvasTypingPart};
@@ -1 +1 @@
1
- "use client";import{Fragment as o,jsx as a}from"react/jsx-runtime";import{EaselCanvas as m}from"efficient-easel/easel";import n from"../../components/PreviewThemeFrame.js";import{usePreviewParts as s}from"../../components/PreviewPartsContext.js";import{partOpenOn as i}from"./text-parts.js";import{useBlockMetadata as f}from"../editor-block-metadata.js";import{useEditorCanvasStyles as l}from"../editor-canvas-styles.js";function p({children:r,componentId:t}){const{selectedPartId:e}=s();return i(e,t)?a(o,{}):a(o,{children:r})}function C(r){const{mirrorHostStyles:t}=l(),e=f();return a(m,{...r,metadata:r.metadata??e,height:"fill",mirrorStyles:t,frameWrapper:n,overlay:p})}export{C as SiteCanvas};
1
+ "use client";import{Fragment as g,jsx as p}from"react/jsx-runtime";import{useMemo as S,useRef as d}from"react";import{EaselCanvas as I,useEaselApi as P}from"efficient-easel/easel";import C from"../../components/PreviewThemeFrame.js";import{usePreviewParts as y}from"../../components/PreviewPartsContext.js";import{partElement as T,partTypingTarget as w,setCanvasTypingPart as v}from"./canvas-typing.js";import{partOpenOn as F,PART_ATTR as c}from"./text-parts.js";import{useSectionOps as h}from"./use-section-ops.js";import{useBlockMetadata as A}from"../editor-block-metadata.js";import{useEditorCanvasStyles as D}from"../editor-canvas-styles.js";function E({children:n,componentId:o}){const{selectedPartId:s}=y();return F(s,o)?p(g,{}):p(g,{children:n})}function W(n){const{mirrorHostStyles:o}=D(),s=A(),l=d(null),a=O(l),{onDocument:i}=n;return p(I,{...n,onDocument:t=>{l.current=t,i?.(t)},typing:a,metadata:n.metadata??s,height:"fill",mirrorStyles:o,frameWrapper:C,overlay:E})}function O(n){const o=P(),s=h(),l=y(),a=d({ops:s,parts:l});return a.current={ops:s,parts:l},S(()=>{const i={getItemById:t=>o.getState().getItemById(t),getSelectorForId:t=>o.getState().getSelectorForId(t),get components(){return o.getState().config.components},replace:(t,e,r)=>a.current.ops.replaceComponent(t,e,r)},m=(t,e)=>{const r=w(t,i);if(!r)return null;let u=e;const f=()=>(u=T(u,u?.ownerDocument??n.current,t),u);return f()?{element:f,value:r.value,rules:r.rules,multiline:r.multiline,write:r.write,toolbar:{offered:r.offered}}:null};return{at:t=>{const e=t.closest(`[${c}]`),r=e?.getAttribute(c);return e&&r?m(r,e):null},atSelection:()=>{const t=a.current.parts.selectedPartId;return t?m(t,null):null},onChange:t=>{if(!t.typing){v(null);return}const e=t.element.closest(`[${c}]`)?.getAttribute(c)??null;v(e),e&&a.current.parts.selectedPartId!==e&&a.current.parts.select(e)}}},[o,n])}export{W as SiteCanvas};
@@ -1 +1 @@
1
- const f=" text",u="Text";function s(t){const e=t.rows.filter(o=>o.shown);return e.length===1&&e[0].labelled}function i(t){return t.filter(s).map(e=>e.key)}function l(t,e){let o=null;for(const r of e){const n=t[r];!n||n.marker!==!0||typeof n.fold!="string"||(o??={...t},o[r]={...n,fold:!1})}return o??t}function p(t,e){if(t.size!==e.size)return!1;for(const o of t)if(!e.has(o))return!1;return!0}export{f as TEXT_BAND_KEY,u as TEXT_BAND_TITLE,s as bandIsDropped,i as droppedBands,p as sameKeys,l as withoutBands};
1
+ const f=" text",u="Text";function s(t){const e=t.rows.filter(n=>n.shown);return e.length===0||e.length===1&&e[0].labelled}function l(t){return t.filter(s).map(e=>e.key)}function i(t,e){let n=null;for(const r of e){const o=t[r];!o||o.marker!==!0||typeof o.fold!="string"||(n??={...t},n[r]={...o,fold:!1})}return n??t}function p(t,e){if(t.size!==e.size)return!1;for(const n of t)if(!e.has(n))return!1;return!0}export{f as TEXT_BAND_KEY,u as TEXT_BAND_TITLE,s as bandIsDropped,l as droppedBands,p as sameKeys,i as withoutBands};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "efficient-web-builder",
3
- "version": "12.0.0",
3
+ "version": "13.0.1",
4
4
  "description": "The EFFICIENT website builder: the website editor, the general sections and the renderer that draws them, compiled. Hostable by any EFFICIENT product; nothing here imports a host.",
5
5
  "license": "UNLICENSED",
6
6
  "author": "Efficient Pty Ltd",
@@ -40,8 +40,8 @@
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@tabler/icons-react": "^3.46.0",
43
- "efficient-easel": "^7.0.2",
44
- "efficient-shell": "^7.24.0",
43
+ "efficient-easel": "^7.0.4",
44
+ "efficient-shell": "^7.29.0",
45
45
  "isomorphic-dompurify": "^3.18.0",
46
46
  "next": ">=16",
47
47
  "react": ">=19",
@@ -59,8 +59,8 @@
59
59
  "@types/node": "^20",
60
60
  "@types/react": "^19",
61
61
  "@types/react-dom": "^19",
62
- "efficient-easel": "^7.0.2",
63
- "efficient-shell": "^7.24.0",
62
+ "efficient-easel": "^7.2.0",
63
+ "efficient-shell": "^7.29.0",
64
64
  "esbuild": "^0.28.0",
65
65
  "happy-dom": "^20.14.5",
66
66
  "isomorphic-dompurify": "^3.18.0",
@@ -1,14 +0,0 @@
1
- export declare const HOLD_MS = 8000;
2
- export interface HeldDelete {
3
- id: string;
4
- send: (options?: {
5
- keepalive?: boolean;
6
- }) => Promise<unknown>;
7
- onFail?: (error: unknown) => void;
8
- }
9
- export declare function flushHeldDeletes(): void;
10
- export declare function heldDeleteIds(): string[];
11
- export declare function holdDelete(entry: HeldDelete): {
12
- undo: () => boolean;
13
- release: () => Promise<void>;
14
- };
@@ -1 +0,0 @@
1
- const s=8e3,d=new Map;async function i(e,t){try{await(t?e.send(t):e.send())}catch(o){e.onFail?.(o)}}function l(){const e=[...d.values()];d.clear();for(const t of e)i(t,{keepalive:!0})}function r(){return[...d.keys()]}let n=!1;function a(){n||typeof window>"u"||(n=!0,window.addEventListener("pagehide",l))}function u(e){return a(),d.set(e.id,e),{undo:()=>d.get(e.id)===e&&d.delete(e.id),release:async()=>{d.get(e.id)===e&&(d.delete(e.id),await i(e))}}}export{s as HOLD_MS,l as flushHeldDeletes,r as heldDeleteIds,u as holdDelete};