efficient-web-builder 5.4.0 → 6.0.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 (37) hide show
  1. package/CHANGELOG.md +103 -0
  2. package/README.md +2 -0
  3. package/dist/components/ImageFocusRow.js +1 -1
  4. package/dist/components/SocialLinksPanel.js +1 -1
  5. package/dist/components/StorefrontLinkField.js +1 -1
  6. package/dist/components/socialIcons.js +1 -1
  7. package/dist/components/storefront-editor.css +18 -120
  8. package/dist/components/useSocialSettings.d.ts +2 -2
  9. package/dist/lib/content/block-sources.d.ts +20 -0
  10. package/dist/lib/content/block-sources.js +1 -0
  11. package/dist/lib/content/product-page.js +1 -1
  12. package/dist/lib/content/record-types.d.ts +21 -0
  13. package/dist/lib/content/record-types.js +1 -0
  14. package/dist/lib/content/social-links.d.ts +1 -1
  15. package/dist/lib/content/social-links.js +1 -1
  16. package/dist/lib/links/link-picker-setup.d.ts +1 -1
  17. package/dist/lib/links/link-picker-setup.js +1 -1
  18. package/dist/lib/links/page-link-rules.d.ts +0 -1
  19. package/dist/lib/links/page-link-rules.js +1 -1
  20. package/dist/lib/puck/block-source-fields.d.ts +5 -0
  21. package/dist/lib/puck/block-source-fields.js +1 -0
  22. package/dist/lib/puck/blocks/general/HeroSingle/render.js +1 -1
  23. package/dist/lib/puck/blocks/general/HeroSlide/render.js +1 -1
  24. package/dist/lib/puck/blocks/general/OrderSummary/fields.js +1 -1
  25. package/dist/lib/puck/blocks/general/OrderSummary/render.js +1 -1
  26. package/dist/lib/puck/controls.d.ts +1 -1
  27. package/dist/lib/puck/controls.js +1 -1
  28. package/dist/lib/puck/editor-page-context.d.ts +1 -0
  29. package/dist/lib/puck/editor-page-context.js +1 -1
  30. package/dist/lib/puck/page-root-fields.d.ts +4 -1
  31. package/dist/lib/puck/page-root-fields.js +1 -1
  32. package/dist/lib/puck/registry.js +1 -1
  33. package/dist/lib/source-rules/editor-chrome-note.js +1 -1
  34. package/dist/lib/source-rules/social-icons-import.js +4 -4
  35. package/package.json +4 -4
  36. package/dist/lib/image-focus.d.ts +0 -16
  37. package/dist/lib/image-focus.js +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,108 @@
1
1
  # Changelog
2
2
 
3
+ ## 6.0.0 - 2026-10-13
4
+
5
+ - **Breaking: efficient-shell ^5.6.0** (peer; was `^4.171.0 || ^5.0.0`). The
6
+ image focus dot and the link picker are efficient-shell parts now
7
+ (Efficient-Pty-Ltd/efficient-shell#375 and #376, harness UI-24: one UI
8
+ kit), and the block renders read the focus default from the server-safe
9
+ `efficient-shell/format` entry (#394). 5.6.0 is the first published shell
10
+ with all three. A host moves to this release and a shell at or above 5.6.0
11
+ together. efficient-easel 2.2.0 already admits
12
+ shell 5, so its peer here is unchanged (`^2.0.0`).
13
+ - **Breaking: `lib/image-focus` is removed.** `parseFocal`, `formatFocal`,
14
+ `nudgeFocal`, `focalFromRect`, `FOCAL_DEFAULT`, `FOCAL_NUDGE_STEP`,
15
+ `FOCAL_NUDGE_COARSE` and the `FocalPoint` type come from
16
+ `efficient-shell/ui` (editor code) or `efficient-shell/format` (the
17
+ HeroSlide and HeroSingle render modules, which can run on a server, where
18
+ the `ui` entry is a client boundary), unchanged. `lib/puck/controls` still
19
+ re-exports `FOCAL_DEFAULT`.
20
+ - **Breaking: `isSafeLink` is removed from `lib/links/page-link-rules`.** The
21
+ Link field hands the picker no address rule, so the shell's
22
+ `isSafeLinkHref` decides (on the trimmed text). It is the same rule plus
23
+ one thing: an address with a control character in it is refused too.
24
+ - **The Image focus row draws the shell's `ImageFocusPoint`.** The row
25
+ (`components/ImageFocusRow`, the shared expandable row) and its own open
26
+ state stay; "Done" (now the kit's `Button`) and "Choose a background image
27
+ first" are passed in as the part's `actions` and `emptyText`. Same value
28
+ (`"38% 64%"`), same keys (arrows 1%, Shift 10%, Enter and Space inert).
29
+ The stylesheet's rule that hides the 96px crop while the row is open reads
30
+ the part's `[data-image-focus]` (was `[data-sf-focusing]`); the
31
+ `.sf-focus*` rules and `.sf-image-btn`, which only that row used, are gone.
32
+ Small visible changes come from the part: the dot is 16px (was 18px), the
33
+ picture at most 144px tall (was 150px), the hint 12px (was 11px).
34
+ - **The Link field draws the shell's `LinkPicker`** (was efficient-easel's
35
+ `fields/LinkPicker`), with the same kinds, rules and filters.
36
+ `lib/links/link-picker-setup` takes its types from `efficient-shell/ui`.
37
+ - Host follow-ups when taking this release: the storefront's
38
+ `scripts/test-image-focus-point.tsx` loads `@/lib/image-focus` and walks
39
+ the old row's own elements, and `packages/storefront-blocks`
40
+ `lib/links/link-rules.ts` re-exports `isSafeLink`; both change in the
41
+ storefront pull request that moves to 6.0.0.
42
+
43
+ ## 5.6.0 - 2026-10-13
44
+
45
+ - **A block reads its rows from a source, as the page is served.** Some blocks
46
+ draw a list, and until now a page held the list itself. A block may now
47
+ name a source in `props.dataSource` (`lib/content/block-sources`), and its
48
+ host's backend puts the rows beside its settings as the page is served, in
49
+ `props.dataRows`. Nothing of a source's rows is ever written into a page:
50
+ the editor never writes `dataRows`. A block that names no source, and every
51
+ page there is, draws and edits exactly as before. EFFICIENT backend
52
+ `docs/adr/0049`, "Amended 2026-10-12" (pull request 3).
53
+ - **A host declares its sources.** `registerBlockSources([{ key, label,
54
+ blocks, sample? }])`, before it mounts an editor; `blockSources(block)`
55
+ lists the ones that fill a block. The list is kept on `globalThis`, so two
56
+ copies of the module share it. `declaredBlockSource`, `servedRows` and
57
+ `sourcedRows` read a block's props: on a published page a sourced block
58
+ draws the rows it was served, and none where it was served none; in the
59
+ editor, where no page is served, it draws the host's `sample` or its own.
60
+ - **The Order Table takes a source for its items.** A new "Items from" row
61
+ (`dataSource`) above the typed Items, shown only where the host declared a
62
+ source for `OrderSummary`. A source picked hides the typed Items, and the
63
+ table draws the served rows (`label`, `meta`, `amount`) and never the typed
64
+ ones. A published table that was served nothing draws nothing at all. The
65
+ sub-total lines, the total and the note stay typed.
66
+ - **`blockSourceField` and `blockSourceFields`** (`lib/puck/block-source-fields`):
67
+ the row and the resolver step a block of a host's own uses to take a source
68
+ the same way.
69
+ - **Social links gain Telegram, LINE and WeChat.** `SOCIAL_PLATFORMS` holds
70
+ eleven, in the backend's order. Tabler ships the three outline marks and no
71
+ filled ones, so `components/socialIcons` draws their Solid marks from the
72
+ same geometry with Tabler's own component factory. Each is a link like the
73
+ rest: WeChat's is the link inside the business's own WeChat QR code, and a
74
+ bare WeChat ID draws nothing. A host whose backend does not send the three
75
+ keys draws eight marks, as before.
76
+
77
+ ## 5.5.0 - 2026-10-13
78
+
79
+ - **A dynamic page says which type of record it draws.** A dynamic page is
80
+ one layout drawn for many records, and until now its record was a product
81
+ and nothing else. A page now names a record type in `root.props.recordType`
82
+ (`lib/content/record-types`): `product`, the builder's own, or one its host
83
+ declared. A page that says nothing draws a product, so every page and every
84
+ host there is renders and edits exactly as before. EFFICIENT backend
85
+ `docs/adr/0049`, "Amended 2026-10-12".
86
+ - **A host declares its record types.** `registerRecordTypes([{ key, label,
87
+ fields }])`, once, before it mounts an editor or draws a page;
88
+ `recordTypes()` lists them, `product` first. A field is `{ key, label,
89
+ kind }`, with `kind` `"text"` or `"date"`, and is what a block bound to the
90
+ page's record may read (`recordFields(key, kinds)`). A key or a field the
91
+ registry cannot use throws.
92
+ - **Page settings gains a "Record type" row** on a dynamic page of a host
93
+ that declared a type beside `product`, added by `finishRegistry` to every
94
+ host's root, above the host's own rows. A host that declared nothing has
95
+ one type and gets no row: its Page settings is the same list it was.
96
+ - **A page of another record type is no product template.**
97
+ `templateProductKind`, `declaredTemplateProductKind`,
98
+ `layoutDeclaredProductKind` and `isProductTemplatePage` answer "none" for
99
+ it, on a reserved slug and with a product type left in its document.
100
+ - New readers: `declaredRecordType`, `layoutRecordType`, `drawsProduct`,
101
+ `recordTypeSpec`, and `editorRecordType` in `lib/puck/editor-page-context`.
102
+ Nothing of a record is ever written into a page: the document holds the
103
+ type's key, and the host hands the record to the blocks as the page is
104
+ served.
105
+
3
106
  ## 5.4.0 - 2026-10-12
4
107
 
5
108
  - **A new general section: Countdown.** Hours : minutes : seconds to ONE fixed
package/README.md CHANGED
@@ -27,6 +27,8 @@ What a host adds, it hands over on the editor's session
27
27
  | chrome | `src/lib/editor-chrome.tsx` | The host's furniture round the editor, as components: a wrapper, panels, Pages-panel rows, its products and its row under a Link field. |
28
28
  | document hooks | `src/lib/editor-document-hooks.ts` | What the host does to a document as it opens and as an edit is stored. |
29
29
  | failure reader | `src/lib/web-backend.ts` (`provideHostFailures`) | How to read the host client's own errors. |
30
+ | record types | `src/lib/content/record-types.ts` (`registerRecordTypes`) | What a dynamic page of this host may draw besides a product: a key, a label and the fields a block may read. Declared once, for the app and not for one mount. |
31
+ | block sources | `src/lib/content/block-sources.ts` (`registerBlockSources`) | Where a block of this host may read its rows from instead of holding them: a key, a label, the blocks it fills and sample rows for the editor. The host's backend puts the rows in as a page is served. Declared once, for the app and not for one mount. |
30
32
 
31
33
  The storefront's are assembled in its `lib/storefront-editor.ts`.
32
34
 
@@ -1 +1 @@
1
- "use client";import{jsx as s,jsxs as a,Fragment as P}from"react/jsx-runtime";import{useRef as N,useState as F}from"react";import k from"./TextStyleRow.js";import{focalFromRect as D,formatFocal as $,nudgeFocal as C,parseFocal as R}from"../lib/image-focus.js";function j({label:c,value:t,onChange:l,image:i}){const[f,u]=F(!1),m=N(null),n=N(!1),{x:p,y:d}=R(t),g=(e,o)=>{const h=m.current?.getBoundingClientRect();if(!h)return;const y=D(h,e,o);l($(y.x,y.y))},b=e=>{const o=C(t,e.key,e.shiftKey);o!==null&&(e.preventDefault(),l(o))},x=e=>{e.currentTarget.setPointerCapture?.(e.pointerId),n.current=!0,g(e.clientX,e.clientY)},w=e=>{n.current&&g(e.clientX,e.clientY)},r=()=>{n.current=!1};return s(k,{styleKey:"imageFocal",label:c,value:t,sampleStyle:{fontSize:11,fontVariantNumeric:"tabular-nums"},open:f,onToggle:()=>u(e=>!e),children:f?s("div",{className:"sf-focus","data-sf-focusing":"",children:i?a(P,{children:[s("button",{type:"button",className:"sf-focus-canvas","aria-label":`${c}: ${t}. Use the arrow keys to move the point.`,onKeyDown:b,onPointerDown:x,onPointerMove:w,onPointerUp:r,onPointerCancel:r,onLostPointerCapture:r,children:a("span",{className:"sf-focus-pane",ref:m,children:[s("img",{className:"sf-focus-img",src:i,alt:"",draggable:!1}),s("span",{className:"sf-focus-cross sf-focus-cross--h",style:{top:`${d}%`}}),s("span",{className:"sf-focus-cross sf-focus-cross--v",style:{left:`${p}%`}}),s("span",{className:"sf-focus-marker",style:{left:`${p}%`,top:`${d}%`}})]})}),a("div",{className:"sf-focus-bar",children:[s("span",{className:"sf-focus-hint",children:"Press the picture, or nudge the point with the arrow keys."}),s("button",{type:"button",className:"sf-image-btn",onClick:()=>u(!1),children:"Done"})]})]}):s("p",{className:"es-field-hint sf-hint-keep",children:"Choose a background image first — there’s nothing to focus yet."})}):null})}export{j as default};
1
+ "use client";import{jsx as e}from"react/jsx-runtime";import{useState as l}from"react";import{Button as m,ImageFocusPoint as u}from"efficient-shell/ui";import c from"./TextStyleRow.js";function f({label:o,value:t,onChange:s,image:i}){const[n,a]=l(!1);return e(c,{styleKey:"imageFocal",label:o,value:t,sampleStyle:{fontSize:11,fontVariantNumeric:"tabular-nums"},open:n,onToggle:()=>a(r=>!r),children:n?e(u,{label:o,value:t,onChange:s,image:i,emptyText:"Choose a background image first — there’s nothing to focus yet.",actions:e(m,{variant:"secondary",size:"sm",onClick:()=>a(!1),children:"Done"})}):null})}export{f as default};
@@ -1 +1 @@
1
- "use client";import{jsx as t,Fragment as l,jsxs as p}from"react/jsx-runtime";import{useEffect as b,useId as d,useState as h}from"react";import{SettingsField as L}from"efficient-easel/panel";import{usePreviewSocial as y}from"./PreviewSocialContext.js";import{SocialMark as v}from"./socialIcons.js";import{SOCIAL_PLATFORMS as w,SOCIAL_PLATFORM_LABELS as x}from"../lib/content/social-links.js";const A={instagram:"instagram.com/yourshop",facebook:"facebook.com/yourshop",tiktok:"tiktok.com/@yourshop",youtube:"youtube.com/@yourshop",x:"x.com/yourshop",linkedin:"linkedin.com/company/yourshop",pinterest:"pinterest.com/yourshop",whatsapp:"wa.me/61400000000"};function E({platform:e}){const{rows:c,saveLink:n}=y(),{value:o,error:i}=c[e],[s,a]=h(o),[k,u]=h(!1),f=d(),m=d();b(()=>a(o),[o]);const S=async()=>{if(s.trim()===o){s!==o&&a(o);return}u(!0),await n(e,s),u(!1)},g=x[e];return p(l,{children:[t(L,{label:g,htmlFor:f,icon:t(v,{platform:e,iconStyle:"outline",size:18}),children:t("input",{id:f,type:"text",inputMode:"url",value:s,placeholder:A[e],onChange:r=>a(r.target.value),onBlur:()=>{S()},onKeyDown:r=>{r.key==="Enter"&&r.currentTarget.blur(),r.key==="Escape"&&(a(o),r.currentTarget.blur())},"aria-invalid":i?!0:void 0,"aria-describedby":i?m:void 0,"aria-busy":k||void 0,autoComplete:"off",spellCheck:!1})}),i&&t("p",{id:m,className:"sf-note sf-note--error",role:"alert",children:i})]})}function F({unavailable:e}){const{canSave:c}=y();return!c&&e?t(l,{children:e}):p(l,{children:[t("p",{className:"es-field-hint sf-hint-keep",children:"Paste a link to each profile. A platform left empty shows nothing on the site."}),w.map(n=>t(E,{platform:n},n))]})}export{F as default};
1
+ "use client";import{jsx as t,Fragment as l,jsxs as f}from"react/jsx-runtime";import{useEffect as b,useId as d,useState as h}from"react";import{SettingsField as w}from"efficient-easel/panel";import{usePreviewSocial as y}from"./PreviewSocialContext.js";import{SocialMark as L}from"./socialIcons.js";import{SOCIAL_PLATFORMS as v,SOCIAL_PLATFORM_LABELS as x}from"../lib/content/social-links.js";const A={instagram:"instagram.com/yourshop",facebook:"facebook.com/yourshop",tiktok:"tiktok.com/@yourshop",youtube:"youtube.com/@yourshop",x:"x.com/yourshop",linkedin:"linkedin.com/company/yourshop",pinterest:"pinterest.com/yourshop",whatsapp:"wa.me/61400000000",telegram:"t.me/yourshop",line:"line.me/ti/p/~yourshop",wechat:"u.wechat.com/your-qr-code-link"};function E({platform:e}){const{rows:c,saveLink:n}=y(),{value:o,error:i}=c[e],[s,a]=h(o),[k,u]=h(!1),m=d(),p=d();b(()=>a(o),[o]);const g=async()=>{if(s.trim()===o){s!==o&&a(o);return}u(!0),await n(e,s),u(!1)},S=x[e];return f(l,{children:[t(w,{label:S,htmlFor:m,icon:t(L,{platform:e,iconStyle:"outline",size:18}),children:t("input",{id:m,type:"text",inputMode:"url",value:s,placeholder:A[e],onChange:r=>a(r.target.value),onBlur:()=>{g()},onKeyDown:r=>{r.key==="Enter"&&r.currentTarget.blur(),r.key==="Escape"&&(a(o),r.currentTarget.blur())},"aria-invalid":i?!0:void 0,"aria-describedby":i?p:void 0,"aria-busy":k||void 0,autoComplete:"off",spellCheck:!1})}),i&&t("p",{id:p,className:"sf-note sf-note--error",role:"alert",children:i})]})}function F({unavailable:e}){const{canSave:c}=y();return!c&&e?t(l,{children:e}):f(l,{children:[t("p",{className:"es-field-hint sf-hint-keep",children:"Paste a link to each profile. A platform left empty shows nothing on the site."}),v.map(n=>t(E,{platform:n},n))]})}export{F as default};
@@ -1 +1 @@
1
- "use client";import{jsx as f,jsxs as C}from"react/jsx-runtime";import{LinkPicker as M}from"efficient-easel/fields";import{SettingsField as D}from"efficient-easel/panel";import{LinkIcon as H}from"efficient-easel/icons";import{useEffect as R,useMemo as P,useRef as O,useState as p}from"react";import{getEditorToken as q}from"../lib/editor-auth.js";import{currentEditorSession as z}from"../lib/editor-session.js";import{backendOf as T}from"../lib/website-session.js";import{useStorefrontDocument as A}from"./StorefrontDocumentContext.js";import{pagePath as G}from"../lib/links/page-link-rules.js";import{linkPickerSetup as I}from"../lib/links/link-picker-setup.js";import{useEditorSession as J}from"../lib/editor-session-context.js";import{isSystemPageSlug as K}from"../lib/content/subscribe.js";function j(i){const o=new Map;return(n="")=>{const t=q(),s=o.get(n);if(!s||s.token===null&&t!==null){const l=t||!z().usesBridgedToken?i(t??"",n).catch(()=>[]):Promise.resolve([]);return o.set(n,{promise:l,token:t}),l}return s.promise}}const N=j(async(i,o)=>{const n=o?{siteId:o}:void 0,{pages:t}=T();return t.linkTargets?t.linkTargets(n):(await t.list(n)).map(s=>({id:s.id,slug:s.slug,label:s.label,layout:null}))}),Q=j(async(i,o)=>await T().blog?.posts(o?{siteId:o}:void 0)??[]);function U({value:i,onChange:o,label:n="Link",data:t,filters:s}){const l=P(()=>I(t,s),[t,s]);return f(D,{label:n,icon:f(H,{}),children:f(M,{value:i,onChange:r=>o(r),kinds:l.kinds,rules:l.rules,filtersFor:l.filtersFor,label:n})})}function V({value:i,onChange:o,label:n="Link"}){const t=typeof i=="string"?i:"",{siteId:s,capabilities:l}=A(),{offersCommerce:r,hasBlog:a}=l,[g,y]=p([]),[S,E]=p([]),[L,_]=p([]),[k,b]=p(null),h=J().chrome,v=h?.products?.list,m=h?.linkFilters,x=m?void 0:h?.linkRow,c=O(!0);R(()=>(c.current=!0,()=>{c.current=!1}),[]),R(()=>{let e=!0;return N(s??void 0).then(u=>e&&c.current&&y(u)),a&&Q(s??void 0).then(u=>e&&c.current&&E(u)),r&&v?.().then(u=>e&&c.current&&_(u)),r&&m?m.load(s).catch(()=>null).then(u=>e&&c.current&&b(()=>u)):b(null),()=>{e=!1}},[s,r,a,v,m]);const d=P(()=>({pages:g.filter(e=>!K(e.slug)).map(e=>({slug:e.slug,title:e.label,docs:[e.layout]})),posts:a?S.map(e=>({slug:e.slug,title:e.title})):[],products:r?L.map(e=>({href:e.href,name:e.name})):[],offers:{offersCommerce:r,offersService:a}}),[g,S,L,r,a]),w=P(()=>k?k(d.pages):null,[k,d]),B=d.pages.map(e=>G(e.slug)),F=r&&x&&(t==="/"||B.includes(t))?x:void 0;return C("div",{children:[f(U,{value:t,onChange:o,label:n,data:d,filters:w}),F&&f(F,{value:t,onChange:o,pages:g})]})}export{U as StorefrontLinkPicker,V as default,N as loadPages,Q as loadPosts};
1
+ "use client";import{jsx as f,jsxs as C}from"react/jsx-runtime";import{SettingsField as M}from"efficient-easel/panel";import{LinkIcon as D}from"efficient-easel/icons";import{LinkPicker as H}from"efficient-shell/ui";import{useEffect as R,useMemo as P,useRef as O,useState as p}from"react";import{getEditorToken as q}from"../lib/editor-auth.js";import{currentEditorSession as z}from"../lib/editor-session.js";import{backendOf as T}from"../lib/website-session.js";import{useStorefrontDocument as A}from"./StorefrontDocumentContext.js";import{pagePath as G}from"../lib/links/page-link-rules.js";import{linkPickerSetup as I}from"../lib/links/link-picker-setup.js";import{useEditorSession as J}from"../lib/editor-session-context.js";import{isSystemPageSlug as K}from"../lib/content/subscribe.js";function j(i){const o=new Map;return(n="")=>{const t=q(),s=o.get(n);if(!s||s.token===null&&t!==null){const l=t||!z().usesBridgedToken?i(t??"",n).catch(()=>[]):Promise.resolve([]);return o.set(n,{promise:l,token:t}),l}return s.promise}}const N=j(async(i,o)=>{const n=o?{siteId:o}:void 0,{pages:t}=T();return t.linkTargets?t.linkTargets(n):(await t.list(n)).map(s=>({id:s.id,slug:s.slug,label:s.label,layout:null}))}),Q=j(async(i,o)=>await T().blog?.posts(o?{siteId:o}:void 0)??[]);function U({value:i,onChange:o,label:n="Link",data:t,filters:s}){const l=P(()=>I(t,s),[t,s]);return f(M,{label:n,icon:f(D,{}),children:f(H,{value:i,onChange:r=>o(r),kinds:l.kinds,rules:l.rules,filtersFor:l.filtersFor,label:n})})}function V({value:i,onChange:o,label:n="Link"}){const t=typeof i=="string"?i:"",{siteId:s,capabilities:l}=A(),{offersCommerce:r,hasBlog:a}=l,[g,y]=p([]),[S,E]=p([]),[L,_]=p([]),[k,b]=p(null),h=J().chrome,v=h?.products?.list,m=h?.linkFilters,x=m?void 0:h?.linkRow,c=O(!0);R(()=>(c.current=!0,()=>{c.current=!1}),[]),R(()=>{let e=!0;return N(s??void 0).then(u=>e&&c.current&&y(u)),a&&Q(s??void 0).then(u=>e&&c.current&&E(u)),r&&v?.().then(u=>e&&c.current&&_(u)),r&&m?m.load(s).catch(()=>null).then(u=>e&&c.current&&b(()=>u)):b(null),()=>{e=!1}},[s,r,a,v,m]);const d=P(()=>({pages:g.filter(e=>!K(e.slug)).map(e=>({slug:e.slug,title:e.label,docs:[e.layout]})),posts:a?S.map(e=>({slug:e.slug,title:e.title})):[],products:r?L.map(e=>({href:e.href,name:e.name})):[],offers:{offersCommerce:r,offersService:a}}),[g,S,L,r,a]),w=P(()=>k?k(d.pages):null,[k,d]),B=d.pages.map(e=>G(e.slug)),F=r&&x&&(t==="/"||B.includes(t))?x:void 0;return C("div",{children:[f(U,{value:t,onChange:o,label:n,data:d,filters:w}),F&&f(F,{value:t,onChange:o,pages:g})]})}export{U as StorefrontLinkPicker,V as default,N as loadPages,Q as loadPosts};
@@ -1 +1 @@
1
- import{jsx as a}from"react/jsx-runtime";import{IconBrandFacebook as t,IconBrandFacebookFilled as d,IconBrandInstagram as l,IconBrandInstagramFilled as r,IconBrandLinkedin as s,IconBrandLinkedinFilled as c,IconBrandPinterest as I,IconBrandPinterestFilled as u,IconBrandTiktok as B,IconBrandTiktokFilled as k,IconBrandWhatsapp as p,IconBrandWhatsappFilled as F,IconBrandX as b,IconBrandXFilled as m,IconBrandYoutube as f,IconBrandYoutubeFilled as x}from"@tabler/icons-react";const T="outline",L={instagram:{outline:l,solid:r},facebook:{outline:t,solid:d},tiktok:{outline:B,solid:k},youtube:{outline:f,solid:x},x:{outline:b,solid:m},linkedin:{outline:s,solid:c},pinterest:{outline:I,solid:u},whatsapp:{outline:p,solid:F}};function _({platform:n,iconStyle:o,size:i}){const e=L[n][o];return a(e,{size:i,stroke:1.75,"aria-hidden":"true",focusable:"false"})}export{T as DEFAULT_SOCIAL_ICON_STYLE,_ as SocialMark};
1
+ import{jsx as d}from"react/jsx-runtime";import{IconBrandFacebook as t,IconBrandFacebookFilled as c,IconBrandInstagram as r,IconBrandInstagramFilled as s,IconBrandLine as I,IconBrandLinkedin as u,IconBrandLinkedinFilled as B,IconBrandPinterest as p,IconBrandPinterestFilled as k,IconBrandTelegram as h,IconBrandTiktok as M,IconBrandTiktokFilled as F,IconBrandWechat as f,IconBrandWhatsapp as z,IconBrandWhatsappFilled as m,IconBrandX as S,IconBrandXFilled as b,IconBrandYoutube as j,IconBrandYoutubeFilled as E,createReactComponent as n}from"@tabler/icons-react";const v="outline",L={fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"},T={},o={fillRule:"evenodd"},g=[["path",{...L,d:"M21 4L3 11L7 13L9 19L12 15L17 20z"}],["path",{...o,d:"M21 4L3 11L7 13L9 19L12 15L17 20zM15.212 8.939 10.576 13.576 11.424 14.424 16.061 9.788z"}]],A=[["path",{...L,d:["M21 10.663c0 -4.224 -4.041 -7.663 -9 -7.663s-9 3.439 -9 7.663","c0 3.783 3.201 6.958 7.527 7.56c1.053 .239 .932 .644 .696 2.133","c-.039 .238 -.184 .932 .777 .512c.96 -.42 5.18 -3.201 7.073 -5.48","c1.304 -1.504 1.927 -3.029 1.927 -4.715v-.01z"].join("")}],["path",{...T,d:["M21 10.663c0 -4.224 -4.041 -7.663 -9 -7.663s-9 3.439 -9 7.663","c0 3.783 3.201 6.958 7.527 7.56c1.053 .239 .932 .644 .696 2.133","c-.039 .238 -.184 .932 .777 .512c.96 -.42 5.18 -3.201 7.073 -5.48","c1.304 -1.504 1.927 -3.029 1.927 -4.715v-.01z"].join("")}]],W=[["path",{...L,d:["M16.5 10c3.038 0 5.5 2.015 5.5 4.5c0 1.397 -.778 2.645 -2 3.47l0 2.03l-1.964 -1.178","a6.649 6.649 0 0 1 -1.536 .178c-3.038 0 -5.5 -2.015 -5.5 -4.5s2.462 -4.5 5.5 -4.5z"].join("")}],["path",{...L,d:["M8.319 15.972L7.84 15.918L7.349 15.832L6.865 15.715L6.388 15.568L4 17L4 14.199","L3.559 13.775L3.197 13.356L2.877 12.91L2.603 12.439L2.376 11.946L2.201 11.433","L2.079 10.902L2.016 10.405L2.001 9.897L2.036 9.386L2.12 8.889L2.25 8.405L2.425 7.937","L2.642 7.486L2.9 7.055L3.195 6.645L3.459 6.333L3.744 6.037L4.05 5.757L4.377 5.495","L4.723 5.25L5.086 5.025L5.467 4.819L5.864 4.634L6.275 4.471L6.701 4.331L7.139 4.214","L7.589 4.122L8.05 4.055L8.521 4.014L9.352 4.007L9.815 4.04L10.269 4.098L10.713 4.181","L11.146 4.287L11.567 4.416L11.975 4.567L12.369 4.739L12.748 4.932L13.112 5.143","L13.459 5.374L13.788 5.622L14.172 5.956L14.458 6.241L14.722 6.542L14.965 6.856","L15.217 7.237A8.35 7.35 0 0 0 8.319 15.972z"].join("")}],["path",{...o,d:["M8.319 15.972L7.84 15.918L7.349 15.832L6.865 15.715L6.388 15.568L4 17L4 14.199","L3.559 13.775L3.197 13.356L2.877 12.91L2.603 12.439L2.376 11.946L2.201 11.433","L2.079 10.902L2.016 10.405L2.001 9.897L2.036 9.386L2.12 8.889L2.25 8.405L2.425 7.937","L2.642 7.486L2.9 7.055L3.195 6.645L3.459 6.333L3.744 6.037L4.05 5.757L4.377 5.495","L4.723 5.25L5.086 5.025L5.467 4.819L5.864 4.634L6.275 4.471L6.701 4.331L7.139 4.214","L7.589 4.122L8.05 4.055L8.521 4.014L9.352 4.007L9.815 4.04L10.269 4.098L10.713 4.181","L11.146 4.287L11.567 4.416L11.975 4.567L12.369 4.739L12.748 4.932L13.112 5.143","L13.459 5.374L13.788 5.622L14.172 5.956L14.458 6.241L14.722 6.542L14.965 6.856","L15.217 7.237A8.35 7.35 0 0 0 8.319 15.972zM5.25 7.9a0.85 0.85 0 1 0 1.7 0","a0.85 0.85 0 1 0 -1.7 0zM8.25 7.9a0.85 0.85 0 1 0 1.7 0a0.85 0.85 0 1 0 -1.7 0z"].join("")}],["path",{...o,d:["M16.5 10c3.038 0 5.5 2.015 5.5 4.5c0 1.397 -.778 2.645 -2 3.47l0 2.03l-1.964 -1.178","a6.649 6.649 0 0 1 -1.536 .178c-3.038 0 -5.5 -2.015 -5.5 -4.5s2.462 -4.5 5.5 -4.5z","M14.15 14a0.85 0.85 0 1 0 1.7 0a0.85 0.85 0 1 0 -1.7 0zM17.15 14","a0.85 0.85 0 1 0 1.7 0a0.85 0.85 0 1 0 -1.7 0z"].join("")}]],_=n("filled","brand-telegram-filled","BrandTelegramFilled",g),O=n("filled","brand-line-filled","BrandLineFilled",A),x=n("filled","brand-wechat-filled","BrandWechatFilled",W),C={instagram:{outline:r,solid:s},facebook:{outline:t,solid:c},tiktok:{outline:M,solid:F},youtube:{outline:j,solid:E},x:{outline:S,solid:b},linkedin:{outline:u,solid:B},pinterest:{outline:p,solid:k},whatsapp:{outline:z,solid:m},telegram:{outline:h,solid:_},line:{outline:I,solid:O},wechat:{outline:f,solid:x}};function w({platform:e,iconStyle:a,size:l}){const i=C[e][a];return d(i,{size:l,stroke:1.75,"aria-hidden":"true",focusable:"false"})}export{v as DEFAULT_SOCIAL_ICON_STYLE,w as SocialMark};
@@ -3670,26 +3670,7 @@ input.sf-list-marking {
3670
3670
  /* THE MEDIA ROW IS efficient-easel's `ImageBox` since blueprint step 4.8
3671
3671
  (`es-pick-image-*`, efficient-easel/pick.css): the picture, its name under
3672
3672
  it, Replace and Remove. What stays here is the shop's own around it — the
3673
- button the focus row borrows, the drop's live regions, and the template's
3674
- inert slot. */
3675
- .sf-image-btn {
3676
- border: 1px solid var(--sf-btn-border);
3677
- background: var(--sf-panel);
3678
- color: var(--sf-btn-text);
3679
- border-radius: var(--radius-md);
3680
- padding: 4px 10px;
3681
- font-size: 12px;
3682
- font-weight: 500;
3683
- cursor: pointer;
3684
- transition: background 0.12s;
3685
- }
3686
- .sf-image-btn:hover:not(:disabled) {
3687
- background: var(--sf-hover);
3688
- }
3689
- .sf-image-btn:disabled {
3690
- cursor: default;
3691
- opacity: 0.55;
3692
- }
3673
+ drop's live regions and the template's inert slot. */
3693
3674
  /* Loading / error line under the slot, so a slow or failed picker round-trip is
3694
3675
  visible instead of nothing happening. */
3695
3676
  .sf-image-status {
@@ -3729,109 +3710,26 @@ ul.sf-image-status {
3729
3710
  /* ── The image FOCUS point (card 66226) ──────────────────────────────────────
3730
3711
  WHICH PART OF A BACKGROUND IMAGE SURVIVES ITS CROP, as any point on the
3731
3712
  picture rather than as one of nine. The `Image focus` row opens (the shared
3732
- .sf-style-head grammar, see components/ImageFocusRow.tsx), shows the whole
3733
- photograph, and a press or an arrow key puts the point where the merchant
3734
- wants it. The stored value is the same CSS `object-position` string it has
3735
- always been.
3713
+ .sf-style-head grammar, see components/ImageFocusRow.tsx) onto
3714
+ efficient-shell's `ImageFocusPoint`, which draws the whole photograph, the
3715
+ dot and its crosshair with the kit's own classes (efficient-shell#375); no
3716
+ rule here styles it.
3736
3717
 
3737
3718
  ⚠️ THE MEDIA ROW'S OWN FRAME IS NOT RESTYLED, EVER. `.es-pick-image-frame`
3738
3719
  stays `cover` because that is what the PAGE will look like, and that
3739
- is its job. This block is a second frame, on screen only while a merchant is
3740
- actually setting the point, because a `cover` view cannot express a point it
3741
- has already cropped away. */
3742
- .sf-focus {
3743
- display: flex;
3744
- flex-direction: column;
3745
- gap: 6px;
3746
- }
3747
- /* THE PHOTOGRAPH IS A REAL <button>, not a div wearing a tabIndex. What this
3748
- card replaced is a `role="radiogroup"` a keyboard could already drive, so the
3749
- successor has to earn its place in the tab order the same way. `touch-action`
3750
- is off so a drag on a phone moves the point instead of scrolling the panel. */
3751
- .sf-focus-canvas {
3752
- display: flex;
3753
- align-items: center;
3754
- justify-content: center;
3755
- min-height: 150px;
3756
- padding: 0;
3757
- border: 1px solid var(--sf-line);
3758
- border-radius: var(--radius-md);
3759
- background: var(--sf-preview-bg);
3760
- cursor: crosshair;
3761
- touch-action: none;
3762
- }
3763
- .sf-focus-canvas:focus-visible {
3764
- outline: 2px solid var(--sf-accent);
3765
- outline-offset: 1px;
3766
- }
3767
- /* Shrink-wraps the picture. The marker and crosshairs are positioned against
3768
- THIS and not against the canvas, because a whole photograph in a fixed-height
3769
- box is letterboxed — measuring against the box would land the marker on a
3770
- different pixel for every aspect ratio, and the merchant would watch the dot
3771
- drift away from where they pressed. */
3772
- .sf-focus-pane {
3773
- position: relative;
3774
- display: inline-block;
3775
- max-width: 100%;
3776
- line-height: 0;
3777
- }
3778
- .sf-focus-img {
3779
- display: block;
3780
- width: auto;
3781
- height: auto;
3782
- max-width: 100%;
3783
- max-height: 150px;
3784
- object-fit: contain;
3785
- }
3786
- .sf-focus-cross {
3787
- position: absolute;
3788
- background: color-mix(in srgb, var(--status-on-solid) 45%, transparent);
3789
- pointer-events: none;
3790
- }
3791
- .sf-focus-cross--h {
3792
- right: 0;
3793
- left: 0;
3794
- height: 1px;
3795
- }
3796
- .sf-focus-cross--v {
3797
- top: 0;
3798
- bottom: 0;
3799
- width: 1px;
3800
- }
3801
- /* Drawn in white with a dark ring rather than in a panel token: it sits on a
3802
- merchant's own photograph, which can be any colour, and a token that read
3803
- correctly against the panel would vanish against half of them. White and the
3804
- ring are the shell's own on-media pair (`--status-on-solid`, the media
3805
- scrim), which do not change with the theme for the same reason. */
3806
- .sf-focus-marker {
3807
- position: absolute;
3808
- width: 18px;
3809
- height: 18px;
3810
- border: 2px solid var(--status-on-solid);
3811
- border-radius: 50%;
3812
- box-shadow: 0 0 0 1.5px var(--rosh-media-scrim-button), 0 1px 5px var(--rosh-media-scrim-button);
3813
- transform: translate(-50%, -50%);
3814
- pointer-events: none;
3815
- }
3816
- .sf-focus-bar {
3817
- display: flex;
3818
- align-items: center;
3819
- gap: 8px;
3820
- }
3821
- .sf-focus-hint {
3822
- min-width: 0;
3823
- flex: 1;
3824
- font-size: 11px;
3825
- color: var(--sf-muted);
3826
- }
3827
- /* THE PHOTOGRAPH IS NEVER ON SCREEN TWICE. The 96px crop belongs to the
3828
- Background image field and this row belongs to `imageFocal` — two sibling
3829
- Puck fields, which cannot reach each other from React — so the crop stands
3830
- down for as long as a focus session is open, and comes back the moment it
3831
- closes. The `:has()` on Puck's own field wrapper is this stylesheet's
3832
- established idiom for exactly that problem (see the `[data-sf-bucket]` and
3833
- `[data-sf-no-control]` rules above). */
3834
- .es-insp-rows:has([data-sf-focusing]) .es-pick-image-frame {
3720
+ is its job. The focus part is a second frame, on screen only while a
3721
+ merchant is actually setting the point, because a `cover` view cannot
3722
+ express a point it has already cropped away.
3723
+
3724
+ THE PHOTOGRAPH IS NEVER ON SCREEN TWICE. The 96px crop belongs to the
3725
+ Background image field and the focus row belongs to `imageFocal` — two
3726
+ sibling Puck fields, which cannot reach each other from React — so the crop
3727
+ stands down for as long as the part is open (its root carries
3728
+ `data-image-focus`), and comes back the moment it closes. The `:has()` on
3729
+ Puck's own field wrapper is this stylesheet's established idiom for exactly
3730
+ that problem (see the `[data-sf-bucket]` and `[data-sf-no-control]` rules
3731
+ above). */
3732
+ .es-insp-rows:has([data-image-focus]) .es-pick-image-frame {
3835
3733
  display: none;
3836
3734
  }
3837
3735
 
@@ -7,8 +7,8 @@ export declare function useSocialSettings({ token, siteId, enabled, }: {
7
7
  siteId: string | null;
8
8
  enabled: boolean;
9
9
  }): {
10
- links: Partial<Record<"facebook" | "instagram" | "pinterest" | "tiktok" | "whatsapp" | "youtube" | "x" | "linkedin", string>>;
11
- rows: Record<"facebook" | "instagram" | "pinterest" | "tiktok" | "whatsapp" | "youtube" | "x" | "linkedin", SocialRowState>;
10
+ links: Partial<Record<"facebook" | "instagram" | "pinterest" | "telegram" | "tiktok" | "whatsapp" | "youtube" | "x" | "linkedin" | "line" | "wechat", string>>;
11
+ rows: Record<"facebook" | "instagram" | "pinterest" | "telegram" | "tiktok" | "whatsapp" | "youtube" | "x" | "linkedin" | "line" | "wechat", SocialRowState>;
12
12
  canSave: boolean;
13
13
  saveLink: (platform: SocialPlatform, value: string) => Promise<SocialSaveOutcome>;
14
14
  };
@@ -0,0 +1,20 @@
1
+ export declare const BLOCK_SOURCE_PROP = "dataSource";
2
+ export declare const BLOCK_SOURCE_OPTIONS_PROP = "dataSourceOptions";
3
+ export declare const BLOCK_SOURCE_ROWS_PROP = "dataRows";
4
+ export type SourceRow = Readonly<Record<string, string>>;
5
+ export interface BlockSourceSpec {
6
+ key: string;
7
+ label: string;
8
+ blocks: readonly string[];
9
+ sample?: readonly SourceRow[];
10
+ }
11
+ export declare function registerBlockSources(sources: readonly BlockSourceSpec[]): void;
12
+ export declare function blockSources(block?: string): readonly BlockSourceSpec[];
13
+ export declare function blockSourceSpec(key: string): BlockSourceSpec | null;
14
+ export declare function blockSourcesRevision(): number;
15
+ export declare function declaredBlockSource(props?: Record<string, unknown> | null): string;
16
+ export declare function servedRows(props?: Record<string, unknown> | null): readonly SourceRow[] | null;
17
+ export declare function sourcedRows(props: Record<string, unknown> | null | undefined, editing: boolean, fallback?: readonly SourceRow[]): {
18
+ rows: readonly SourceRow[];
19
+ sample: boolean;
20
+ };
@@ -0,0 +1 @@
1
+ const c="dataSource",b="dataSourceOptions",i="dataRows",a=/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,f=Symbol.for("efficient.block-sources");function n(){const e=globalThis;return e[f]??={sources:new Map,revision:0}}function u(e){if(typeof e.key!="string"||!a.test(e.key))throw new Error(`A block source key is lower-case words joined by hyphens, not ${JSON.stringify(e.key)}.`);if(typeof e.label!="string"||!e.label.trim())throw new Error(`The block source ${e.key} has no label.`);if(!Array.isArray(e.blocks)||!e.blocks.length||e.blocks.some(t=>typeof t!="string"||!t))throw new Error(`The block source ${e.key} names no block it can fill.`);return{key:e.key,label:e.label.trim(),blocks:[...e.blocks],...e.sample?{sample:e.sample.map(t=>l(t)).filter(t=>t!==null)}:{}}}function O(e){const t=e.map(u),o=n();for(const r of t)o.sources.set(r.key,r);t.length&&(o.revision+=1)}function d(e){const t=[...n().sources.values()];return e===void 0?t:t.filter(o=>o.blocks.includes(e))}function p(e){return n().sources.get(e)??null}function m(){return n().revision}function k(e){const t=e?.[c];return typeof t=="string"?t.trim():""}function l(e){if(!e||typeof e!="object"||Array.isArray(e))return null;const t={};for(const[o,r]of Object.entries(e))typeof r=="string"&&r&&(t[o]=r);return Object.keys(t).length?t:null}function y(e){const t=e?.[i];return Array.isArray(t)?t.map(l).filter(o=>o!==null):null}function S(e,t,o=[]){const r=y(e);if(r!==null&&(r.length||!t))return{rows:r,sample:!1};if(!t)return{rows:[],sample:!1};const s=p(k(e))?.sample;return{rows:s?.length?s:o,sample:!0}}export{b as BLOCK_SOURCE_OPTIONS_PROP,c as BLOCK_SOURCE_PROP,i as BLOCK_SOURCE_ROWS_PROP,p as blockSourceSpec,d as blockSources,m as blockSourcesRevision,k as declaredBlockSource,O as registerBlockSources,y as servedRows,S as sourcedRows};
@@ -1 +1 @@
1
- const o="product",r="tyre",c=[o,r];function d(t){return c.includes(t)}const u="productType",l={[o]:"alloy-wheel",[r]:"tyre"},p=["alloy-wheel","tyre"];function P(t,e){return n(e)??l[t]??null}function n(t){const e=t?.[u];return typeof e=="string"&&p.includes(e)?e:null}function i(t){const e=t?.root;return n(e?.props)}function s(t,e){return P(t,e)!==null}const T="dynamic";export{T as DYNAMIC_PRODUCT_PROP,c as DYNAMIC_TEMPLATE_SLUGS,o as PRODUCT_PAGE_SLUG,u as TEMPLATE_PRODUCT_TYPE_PROP,r as TYRE_PAGE_SLUG,n as declaredTemplateProductKind,d as isDynamicTemplateSlug,s as isProductTemplatePage,i as layoutDeclaredProductKind,P as templateProductKind};
1
+ import{drawsProduct as r}from"./record-types.js";const n="product",o="tyre",c=[n,o];function a(t){return c.includes(t)}const l="productType",d={[n]:"alloy-wheel",[o]:"tyre"},i=["alloy-wheel","tyre"];function p(t,e){return r(e)?u(e)??d[t]??null:null}function u(t){if(!r(t))return null;const e=t?.[l];return typeof e=="string"&&i.includes(e)?e:null}function s(t){const e=t?.root;return u(e?.props)}function T(t,e){return p(t,e)!==null}const _="dynamic";export{_ as DYNAMIC_PRODUCT_PROP,c as DYNAMIC_TEMPLATE_SLUGS,n as PRODUCT_PAGE_SLUG,l as TEMPLATE_PRODUCT_TYPE_PROP,o as TYRE_PAGE_SLUG,u as declaredTemplateProductKind,a as isDynamicTemplateSlug,T as isProductTemplatePage,s as layoutDeclaredProductKind,p as templateProductKind};
@@ -0,0 +1,21 @@
1
+ export declare const PRODUCT_RECORD_TYPE = "product";
2
+ export declare const TEMPLATE_RECORD_TYPE_PROP = "recordType";
3
+ export type RecordFieldKind = "text" | "date";
4
+ export interface RecordFieldSpec {
5
+ key: string;
6
+ label: string;
7
+ kind: RecordFieldKind;
8
+ }
9
+ export interface RecordTypeSpec {
10
+ key: string;
11
+ label: string;
12
+ fields: readonly RecordFieldSpec[];
13
+ }
14
+ export declare function registerRecordTypes(types: readonly RecordTypeSpec[]): void;
15
+ export declare function recordTypes(): readonly RecordTypeSpec[];
16
+ export declare function recordTypeSpec(key: string): RecordTypeSpec | null;
17
+ export declare function recordTypesRevision(): number;
18
+ export declare function declaredRecordType(rootProps?: Record<string, unknown> | null): string;
19
+ export declare function layoutRecordType(layout: unknown): string;
20
+ export declare function drawsProduct(rootProps?: Record<string, unknown> | null): boolean;
21
+ export declare function recordFields(key: string, kinds?: readonly RecordFieldKind[]): readonly RecordFieldSpec[];
@@ -0,0 +1 @@
1
+ const t="product",f="recordType",i={key:t,label:"Product",fields:[]},l=/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,a=/^[a-z][A-Za-z0-9]*$/,u=["text","date"],n=new Map;let s=0;function y(e){if(typeof e.key!="string"||!l.test(e.key))throw new Error(`A record type key is lower-case words joined by hyphens, not ${JSON.stringify(e.key)}.`);if(e.key===t)throw new Error("The product record type is the builder's own and is not declared by a host.");if(typeof e.label!="string"||!e.label.trim())throw new Error(`The record type ${e.key} has no label.`);const o=new Set;for(const r of e.fields){if(typeof r.key!="string"||!a.test(r.key)||o.has(r.key))throw new Error(`The record type ${e.key} has a field key it cannot use: ${JSON.stringify(r.key)}.`);if(!u.includes(r.kind))throw new Error(`The field ${r.key} of ${e.key} has no kind ${JSON.stringify(r.kind)}.`);o.add(r.key)}return{key:e.key,label:e.label.trim(),fields:e.fields.map(r=>({...r}))}}function k(e){const o=e.map(y);for(const r of o)n.set(r.key,r);o.length&&(s+=1)}function h(){return[i,...n.values()]}function p(e){return e===t?i:n.get(e)??null}function T(){return s}function c(e){const o=e?.[f];return typeof o!="string"?t:o.trim()||t}function w(e){const o=e?.root;return c(o&&typeof o=="object"?o.props:null)}function E(e){return c(e)===t}function x(e,o){const r=p(e)?.fields??[];return o?r.filter(d=>o.includes(d.kind)):r}export{t as PRODUCT_RECORD_TYPE,f as TEMPLATE_RECORD_TYPE_PROP,c as declaredRecordType,E as drawsProduct,w as layoutRecordType,x as recordFields,p as recordTypeSpec,h as recordTypes,T as recordTypesRevision,k as registerRecordTypes};
@@ -1,4 +1,4 @@
1
- export declare const SOCIAL_PLATFORMS: readonly ["instagram", "facebook", "tiktok", "youtube", "x", "linkedin", "pinterest", "whatsapp"];
1
+ export declare const SOCIAL_PLATFORMS: readonly ["instagram", "facebook", "tiktok", "youtube", "x", "linkedin", "pinterest", "whatsapp", "telegram", "line", "wechat"];
2
2
  export type SocialPlatform = (typeof SOCIAL_PLATFORMS)[number];
3
3
  export declare const SOCIAL_PLATFORM_LABELS: Record<SocialPlatform, string>;
4
4
  export type SocialLinks = Partial<Record<SocialPlatform, string>>;
@@ -1 +1 @@
1
- const r=["instagram","facebook","tiktok","youtube","x","linkedin","pinterest","whatsapp"],s={instagram:"Instagram",facebook:"Facebook",tiktok:"TikTok",youtube:"YouTube",x:"X",linkedin:"LinkedIn",pinterest:"Pinterest",whatsapp:"WhatsApp"},a={};function c(t){if(!t||typeof t!="object")return a;const o={};for(const e of r){const i=t[e];if(typeof i!="string")continue;const n=i.trim();!n||!/^https?:\/\//i.test(n)||(o[e]=n)}return o}function p(t){return r.flatMap(o=>{const e=t[o];return e?[{platform:o,href:e,label:s[o]}]:[]})}const u=t=>`${t}_url`;export{a as EMPTY_SOCIAL_LINKS,r as SOCIAL_PLATFORMS,s as SOCIAL_PLATFORM_LABELS,c as normalizeSocialLinks,p as socialLinksToDraw,u as socialUrlField};
1
+ const r=["instagram","facebook","tiktok","youtube","x","linkedin","pinterest","whatsapp","telegram","line","wechat"],a={instagram:"Instagram",facebook:"Facebook",tiktok:"TikTok",youtube:"YouTube",x:"X",linkedin:"LinkedIn",pinterest:"Pinterest",whatsapp:"WhatsApp",telegram:"Telegram",line:"LINE",wechat:"WeChat"},s={};function c(t){if(!t||typeof t!="object")return s;const e={};for(const o of r){const i=t[o];if(typeof i!="string")continue;const n=i.trim();!n||!/^https?:\/\//i.test(n)||(e[o]=n)}return e}function l(t){return r.flatMap(e=>{const o=t[e];return o?[{platform:e,href:o,label:a[e]}]:[]})}const p=t=>`${t}_url`;export{s as EMPTY_SOCIAL_LINKS,r as SOCIAL_PLATFORMS,a as SOCIAL_PLATFORM_LABELS,c as normalizeSocialLinks,l as socialLinksToDraw,p as socialUrlField};
@@ -1,4 +1,4 @@
1
- import type { LinkFilterField, LinkKindChoice, LinkRules } from "efficient-easel/fields";
1
+ import type { LinkFilterField, LinkKindChoice, LinkRules } from "efficient-shell/ui";
2
2
  import type { LinkFilters, LinkPickerPage } from "./link-filters.js";
3
3
  import { type LinkKind } from "./page-link-rules.js";
4
4
  export type { LinkFilters, LinkPickerPage };
@@ -1 +1 @@
1
- import{anchorPath as d,isSafeLink as u,linkKindsFor as f,pageAnchors as P,pagePath as m,postPath as v}from"./page-link-rules.js";const r={choosePage:"Choose a page",chooseSection:"Choose a section",noSections:"No section anchors yet",sectionHint:"Jumps to a section on that page.",choosePost:"Choose a post",chooseProduct:"Choose a product"};function p(t,o,a){if(!t)return"page";if(t.startsWith("/journal/"))return"blog";if(t.startsWith("/wheels/"))return"product";if(t.includes("#")){const n=t.slice(0,t.indexOf("#"));if(n===""||n==="/"||o.includes(n))return"anchor"}return t==="/"||o.includes(t)||a&&a.listingPaths.includes(a.targetOf(t))?"page":"custom"}function O(t,o){const a=t.pages.map(e=>({value:m(e.slug),label:e.title})),n=o?.pageOptions?o.pageOptions(a):a,i=n.map(e=>e.value),c=t.pages.map(e=>({label:e.title,options:P(...e.docs).map(s=>({value:d(e.slug,s.slug),label:s.name}))})).filter(e=>e.options.length>0),g=e=>{switch(e){case"page":return{type:"select",options:n,placeholder:r.choosePage};case"anchor":return{type:"groups",groups:c,placeholder:c.length?r.chooseSection:r.noSections};case"blog":return{type:"select",options:t.posts.map(s=>({value:v(s.slug),label:s.title||s.slug})),placeholder:r.choosePost};case"product":return{type:"select",options:t.products.map(s=>({value:s.href,label:s.name||s.href})),placeholder:r.chooseProduct};case"custom":return{type:"text"}}},l=f(t.offers).map(e=>({value:e.value,label:e.label,target:g(e.value),...e.value==="anchor"?{hint:r.sectionHint}:{},...e.value==="blog"||e.value==="product"?{hideWhenEmpty:!0}:{}}));if(!o)return{kinds:l,rules:{kindOf:e=>p(e,i),targetOf:e=>e,readFilter:()=>null,withFilter:e=>e,isSafe:u}};const h=e=>{const s=o.withFilter(e,null);return o.listingPaths.includes(s)?s:e};return{kinds:l,rules:{kindOf:e=>p(e,i,{listingPaths:o.listingPaths,targetOf:h}),targetOf:h,readFilter:o.readFilter,withFilter:o.withFilter,isSafe:u},filtersFor:e=>o.listingPaths.includes(e)?o.filtersFor(e):null}}export{p as inferLinkKind,O as linkPickerSetup};
1
+ import{anchorPath as g,linkKindsFor as d,pageAnchors as P,pagePath as f,postPath as m}from"./page-link-rules.js";const r={choosePage:"Choose a page",chooseSection:"Choose a section",noSections:"No section anchors yet",sectionHint:"Jumps to a section on that page.",choosePost:"Choose a post",chooseProduct:"Choose a product"};function u(t,o,a){if(!t)return"page";if(t.startsWith("/journal/"))return"blog";if(t.startsWith("/wheels/"))return"product";if(t.includes("#")){const n=t.slice(0,t.indexOf("#"));if(n===""||n==="/"||o.includes(n))return"anchor"}return t==="/"||o.includes(t)||a&&a.listingPaths.includes(a.targetOf(t))?"page":"custom"}function F(t,o){const a=t.pages.map(e=>({value:f(e.slug),label:e.title})),n=o?.pageOptions?o.pageOptions(a):a,c=n.map(e=>e.value),i=t.pages.map(e=>({label:e.title,options:P(...e.docs).map(s=>({value:g(e.slug,s.slug),label:s.name}))})).filter(e=>e.options.length>0),p=e=>{switch(e){case"page":return{type:"select",options:n,placeholder:r.choosePage};case"anchor":return{type:"groups",groups:i,placeholder:i.length?r.chooseSection:r.noSections};case"blog":return{type:"select",options:t.posts.map(s=>({value:m(s.slug),label:s.title||s.slug})),placeholder:r.choosePost};case"product":return{type:"select",options:t.products.map(s=>({value:s.href,label:s.name||s.href})),placeholder:r.chooseProduct};case"custom":return{type:"text"}}},l=d(t.offers).map(e=>({value:e.value,label:e.label,target:p(e.value),...e.value==="anchor"?{hint:r.sectionHint}:{},...e.value==="blog"||e.value==="product"?{hideWhenEmpty:!0}:{}}));if(!o)return{kinds:l,rules:{kindOf:e=>u(e,c),targetOf:e=>e,readFilter:()=>null,withFilter:e=>e}};const h=e=>{const s=o.withFilter(e,null);return o.listingPaths.includes(s)?s:e};return{kinds:l,rules:{kindOf:e=>u(e,c,{listingPaths:o.listingPaths,targetOf:h}),targetOf:h,readFilter:o.readFilter,withFilter:o.withFilter},filtersFor:e=>o.listingPaths.includes(e)?o.filtersFor(e):null}}export{u as inferLinkKind,F as linkPickerSetup};
@@ -17,6 +17,5 @@ export declare function pageAnchors(...docs: unknown[]): {
17
17
  slug: string;
18
18
  name: string;
19
19
  }[];
20
- export declare function isSafeLink(url: string): boolean;
21
20
  export declare function linkPagePath(url: string): string;
22
21
  export declare function inferKind(url: string, pagePaths: string[]): LinkKind;
@@ -1 +1 @@
1
- import{HOME_PAGE_SLUG as u}from"../puck/home-page.js";import{slugify as f}from"../slugify.js";const i=[{value:"page",label:"Page"},{value:"anchor",label:"Anchor"},{value:"blog",label:"Blog post",needs:"service"},{value:"product",label:"Product",needs:"commerce"},{value:"custom",label:"Custom URL"}];function x(e){return e.offersCommerce&&e.offersService?i:i.filter(t=>!t.needs||(t.needs==="commerce"?e.offersCommerce:e.offersService))}function a(e){return e===u?"/":`/${e}`}function g(e){return`/journal/${e}`}function b(e){return`/wheels/${e}`}function S(e,t){return`${a(e)}#${t}`}function l(e){return f(e)}function p(e){return typeof e=="string"?e.trim():e&&typeof e=="object"&&typeof e.text=="string"?e.text.trim():""}function A(...e){const t=new Set,n=[];for(const r of e)for(const s of r?.content??[]){const c=p(s?.props?.anchor);if(!c)continue;const o=l(c);!o||t.has(o)||(t.add(o),n.push({slug:o,name:c}))}return n}const h=["http","https","mailto","tel"];function P(e){const t=e.trim();if(!t||/\s/.test(t))return!1;const n=/^([a-z][a-z0-9+.-]*):/i.exec(t);return!n||h.includes(n[1].toLowerCase())}function w(e){const t=e.indexOf("#"),n=t===-1?e:e.slice(0,t),r=n.indexOf("?");return r===-1?n:n.slice(0,r)}function y(e,t){if(!e)return"page";if(e.startsWith("/journal/"))return"blog";if(e.startsWith("/wheels/"))return"product";if(e.includes("#")){const n=e.slice(0,e.indexOf("#"));if(n===""||n==="/"||t.includes(n))return"anchor"}return e==="/"||t.includes(e)?"page":"custom"}export{i as LINK_KINDS,S as anchorPath,y as inferKind,P as isSafeLink,x as linkKindsFor,w as linkPagePath,A as pageAnchors,a as pagePath,g as postPath,l as slugifyAnchor,b as wheelPath};
1
+ import{HOME_PAGE_SLUG as u}from"../puck/home-page.js";import{slugify as f}from"../slugify.js";const i=[{value:"page",label:"Page"},{value:"anchor",label:"Anchor"},{value:"blog",label:"Blog post",needs:"service"},{value:"product",label:"Product",needs:"commerce"},{value:"custom",label:"Custom URL"}];function d(e){return e.offersCommerce&&e.offersService?i:i.filter(t=>!t.needs||(t.needs==="commerce"?e.offersCommerce:e.offersService))}function a(e){return e===u?"/":`/${e}`}function x(e){return`/journal/${e}`}function g(e){return`/wheels/${e}`}function b(e,t){return`${a(e)}#${t}`}function p(e){return f(e)}function l(e){return typeof e=="string"?e.trim():e&&typeof e=="object"&&typeof e.text=="string"?e.text.trim():""}function P(...e){const t=new Set,n=[];for(const r of e)for(const s of r?.content??[]){const c=l(s?.props?.anchor);if(!c)continue;const o=p(c);!o||t.has(o)||(t.add(o),n.push({slug:o,name:c}))}return n}function A(e){const t=e.indexOf("#"),n=t===-1?e:e.slice(0,t),r=n.indexOf("?");return r===-1?n:n.slice(0,r)}function y(e,t){if(!e)return"page";if(e.startsWith("/journal/"))return"blog";if(e.startsWith("/wheels/"))return"product";if(e.includes("#")){const n=e.slice(0,e.indexOf("#"));if(n===""||n==="/"||t.includes(n))return"anchor"}return e==="/"||t.includes(e)?"page":"custom"}export{i as LINK_KINDS,b as anchorPath,y as inferKind,d as linkKindsFor,A as linkPagePath,P as pageAnchors,a as pagePath,x as postPath,p as slugifyAnchor,g as wheelPath};
@@ -0,0 +1,5 @@
1
+ import { type SelectField } from "./controls.js";
2
+ export declare function blockSourceField(label: string, own: string): SelectField;
3
+ export declare function blockSourceFields<Fields extends Record<string, unknown>>(block: string, fields: Fields, props: Record<string, unknown> | null | undefined, options?: {
4
+ hides?: readonly string[];
5
+ }): Fields;
@@ -0,0 +1 @@
1
+ import{jsx as y}from"react/jsx-runtime";import{ListIcon as M}from"efficient-easel/icons";import{BLOCK_SOURCE_PROP as m,blockSources as v,blockSourcesRevision as f,declaredBlockSource as $}from"../content/block-sources.js";import{select as O}from"./controls.js";function C(s,e){return O(s,y(M,{}),[{label:e,value:""}],"")}const b=new WeakMap;let S=-1,p={};const g=new WeakMap;function j(s,e,c){S!==f()&&(S=f(),p={});let t=b.get(e);(!t||g.get(t)!==p)&&(t=new Map,g.set(t,p),b.set(e,t));const i=v(s),o=c&&!i.some(n=>n.key===c)?c:"",l=`${s}\0${o}`;let r=t.get(l);return r||(r={...e,options:[...e.options,...i.map(n=>({label:n.label,value:n.key})),...o?[{label:o,value:o}]:[]]},t.set(l,r)),r}const R=new WeakMap;function F(s,e,c,t={}){const i=e[m];if(!i)return e;const o=$(c),l=v(s).length>0||o!=="",r=l?j(s,i,o):null;let n=R.get(e);n||R.set(e,n=new Map);const w=`${f()}\0${l?"1":"0"}\0${o}`,k=n.get(w);if(k)return k;const h=new Set(o?t.hides??[]:[]),a={};for(const[u,x]of Object.entries(e))u===m?r&&(a[u]=r):h.has(u)||(a[u]=x);return n.set(w,a),a}export{C as blockSourceField,F as blockSourceFields};
@@ -1 +1 @@
1
- import{jsx as O}from"react/jsx-runtime";import y from"../../../../../components/HeroSingle.js";import{FOCAL_DEFAULT as c}from"../../../../image-focus.js";import{DEFAULT_OVERLAY_COLOR as L,DEFAULT_OVERLAY_POSITION as u}from"../../../../sections/hero-overlay.js";const v={boxes:{type:"slot",allow:["HeroGroup"]}},S={label:"Hero",fields:v,defaultProps:{mediaType:"image",imageFocal:c,tintColor:"#000000",tintOpacity:0,overlay:100,overlayColor:L,overlayPosition:u},render:({mediaType:o,mediaImage:e,mediaVideo:i,poster:r,imageFocal:t,tintColor:n,tintOpacity:l,overlay:a,overlayColor:s,overlayPosition:d,heightDesktop:m,heightMobile:g,boxes:p,puck:f})=>O(y,{mediaType:o,mediaSrc:(o==="image"?e:i)||void 0,poster:r||void 0,objectPosition:o==="image"&&t||void 0,tintColor:n,tintOpacity:o==="image"?l:0,overlay:a,overlayColor:s,overlayPosition:d,heightDesktop:m,heightMobile:g,boxes:p,editing:f?.isEditing})};export{S as HeroSingleRender,v as HeroSingleSlots};
1
+ import{jsx as O}from"react/jsx-runtime";import y from"../../../../../components/HeroSingle.js";import{FOCAL_DEFAULT as c}from"efficient-shell/format";import{DEFAULT_OVERLAY_COLOR as L,DEFAULT_OVERLAY_POSITION as u}from"../../../../sections/hero-overlay.js";const v={boxes:{type:"slot",allow:["HeroGroup"]}},S={label:"Hero",fields:v,defaultProps:{mediaType:"image",imageFocal:c,tintColor:"#000000",tintOpacity:0,overlay:100,overlayColor:L,overlayPosition:u},render:({mediaType:o,mediaImage:e,mediaVideo:i,poster:r,imageFocal:t,tintColor:n,tintOpacity:l,overlay:a,overlayColor:s,overlayPosition:d,heightDesktop:m,heightMobile:g,boxes:p,puck:f})=>O(y,{mediaType:o,mediaSrc:(o==="image"?e:i)||void 0,poster:r||void 0,objectPosition:o==="image"&&t||void 0,tintColor:n,tintOpacity:o==="image"?l:0,overlay:a,overlayColor:s,overlayPosition:d,heightDesktop:m,heightMobile:g,boxes:p,editing:f?.isEditing})};export{S as HeroSingleRender,v as HeroSingleSlots};
@@ -1 +1 @@
1
- import{jsx as g}from"react/jsx-runtime";import S from"../../../../../components/HeroSlide.js";import{FOCAL_DEFAULT as H}from"../../../../image-focus.js";import{nestedAccentValue as h,sectionThemeWrap as y}from"../../../../content/section-surface.js";import{phHide as A}from"../../scaffold.js";const b={groups:{type:"slot",allow:["HeroGroup"]}},L={label:"Hero Slide",fields:b,defaultProps:{mediaType:"video",videoSpeed:100,imageFocal:H,tintColor:"#000000",overlay:0},render:({name:r,process:d,mediaType:e,mediaVideo:s,mediaImage:l,poster:m,mediaSrc:a,videoSpeed:o,imageFocal:c,tintColor:p,overlay:f,groups:u,puck:t,...i})=>{const n=y({...i,sectionAccent:h(i.sectionAccent)});return g(S,{themeClassName:n?.className,themeStyle:n?.style,name:r||void 0,process:A(d,"Label",t),mediaType:e,mediaSrc:(e==="image"?l:s||a)||void 0,videoSpeed:typeof o=="number"?o:void 0,poster:m||void 0,objectPosition:e==="image"&&c||void 0,tintColor:p,tintOpacity:e==="image"?f:0,groups:u,editing:t?.isEditing})}};export{L as HeroSlideRender,b as HeroSlideSlots};
1
+ import{jsx as g}from"react/jsx-runtime";import S from"../../../../../components/HeroSlide.js";import{FOCAL_DEFAULT as H}from"efficient-shell/format";import{nestedAccentValue as h,sectionThemeWrap as y}from"../../../../content/section-surface.js";import{phHide as A}from"../../scaffold.js";const b={groups:{type:"slot",allow:["HeroGroup"]}},L={label:"Hero Slide",fields:b,defaultProps:{mediaType:"video",videoSpeed:100,imageFocal:H,tintColor:"#000000",overlay:0},render:({name:r,process:d,mediaType:e,mediaVideo:s,mediaImage:l,poster:m,mediaSrc:a,videoSpeed:o,imageFocal:c,tintColor:p,overlay:f,groups:u,puck:t,...i})=>{const n=y({...i,sectionAccent:h(i.sectionAccent)});return g(S,{themeClassName:n?.className,themeStyle:n?.style,name:r||void 0,process:A(d,"Label",t),mediaType:e,mediaSrc:(e==="image"?l:s||a)||void 0,videoSpeed:typeof o=="number"?o:void 0,poster:m||void 0,objectPosition:e==="image"&&c||void 0,tintColor:p,tintOpacity:e==="image"?f:0,groups:u,editing:t?.isEditing})}};export{L as HeroSlideRender,b as HeroSlideSlots};
@@ -1 +1 @@
1
- import{copyText as t,group as e,text as o,textarea as l}from"../../../controls.js";import{PH as r}from"../../placeholders.js";import{ORDER_SUMMARY_PH as m}from"./render.js";const u={fields:{_gContent:e("Content"),eyebrow:o("Eyebrow",r.eyebrow),title:l("Heading",m.title),_gItems:e("Items"),rows:{type:"array",label:"Items",arrayFields:{label:t("Item"),meta:t("Meta line"),amount:t("Amount")},getItemSummary:a=>a.label||"Item"},subRows:{type:"array",label:"Sub-total lines",arrayFields:{label:t("Label"),amount:t("Amount")},getItemSummary:a=>a.label||"Line"},_gTotal:e("Total"),totalLabel:o("Total label","Total"),totalAmount:o("Total amount","$0,000"),note:l("Note",m.note),_gLayout:e("Layout")}};export{u as OrderSummaryFields};
1
+ import{blockSourceField as s,blockSourceFields as i}from"../../../block-source-fields.js";import{copyText as t,group as o,text as a,textarea as r}from"../../../controls.js";import{PH as u}from"../../placeholders.js";import{ORDER_SUMMARY_PH as l}from"./render.js";const p={fields:{_gContent:o("Content"),eyebrow:a("Eyebrow",u.eyebrow),title:r("Heading",l.title),_gItems:o("Items"),dataSource:s("Items from","Typed here"),rows:{type:"array",label:"Items",arrayFields:{label:t("Item"),meta:t("Meta line"),amount:t("Amount")},getItemSummary:e=>e.label||"Item"},subRows:{type:"array",label:"Sub-total lines",arrayFields:{label:t("Label"),amount:t("Amount")},getItemSummary:e=>e.label||"Line"},_gTotal:o("Total"),totalLabel:a("Total label","Total"),totalAmount:a("Total amount","$0,000"),note:r("Note",l.note),_gLayout:o("Layout")},resolveFields:(e,{fields:m})=>i("OrderSummary",m,e.props,{hides:["rows"]})};export{p as OrderSummaryFields};
@@ -1 +1 @@
1
- import{jsx as d}from"react/jsx-runtime";import S from"../../../../../components/OrderSummary.js";import{PH as u}from"../../placeholders.js";import{phRows as o,phHide as e}from"../../scaffold.js";const r={title:"Order summary",note:"A short reassurance note under the total."},O=[{label:"Product name",meta:"Finish · Size · ×1",amount:"$0,000"},{label:"Second item",meta:"Detail line",amount:"$000"}],_=[{label:"Subtotal",amount:"$0,000"},{label:"Delivery",amount:"$00"}],M={label:"Order Table",defaultProps:{eyebrow:"",title:"",rows:[],subRows:[],totalLabel:"",totalAmount:"",note:"",contained:!0},render:({eyebrow:a,title:l,rows:n,subRows:m,totalLabel:s,totalAmount:i,note:R,contained:b,puck:t})=>d(S,{eyebrow:e(a,u.eyebrow,t),title:e(l,r.title,t),rows:o(n,O,t),subRows:o(m,_,t),totalLabel:e(s,"Total",t),totalAmount:e(i,"$0,000",t),note:e(R,r.note,t),contained:b})};export{r as ORDER_SUMMARY_PH,M as OrderSummaryRender};
1
+ import{Fragment as w,jsx as r}from"react/jsx-runtime";import c from"../../../../../components/OrderSummary.js";import{declaredBlockSource as O,sourcedRows as _}from"../../../../content/block-sources.js";import{PH as R}from"../../placeholders.js";import{phRows as S,phHide as e}from"../../scaffold.js";const l={title:"Order summary",note:"A short reassurance note under the total."},y=[{label:"Product name",meta:"Finish · Size · ×1",amount:"$0,000"},{label:"Second item",meta:"Detail line",amount:"$000"}],M=[{label:"Subtotal",amount:"$0,000"},{label:"Delivery",amount:"$00"}],f=[{label:"First item",meta:"A detail line",amount:"$000"},{label:"Second item",meta:"A detail line",amount:"$000"},{label:"Third item",meta:"A detail line",amount:"$000"}],p=o=>({label:o.label,meta:o.meta,amount:o.amount}),U={label:"Order Table",defaultProps:{eyebrow:"",title:"",rows:[],subRows:[],totalLabel:"",totalAmount:"",note:"",contained:!0},render:o=>{const{eyebrow:n,title:m,rows:A,subRows:a,totalLabel:i,totalAmount:s,note:u,contained:b,puck:t}=o;if(O(o)!==""){const d=_(o,!!t?.isEditing,f);return d.rows.length?r(c,{eyebrow:e(n,R.eyebrow,t),title:e(m,l.title,t),rows:d.rows.map(p),subRows:Array.isArray(a)?a:[],totalLabel:e(i,"",t),totalAmount:e(s,"",t),note:e(u,"",t),contained:b}):r(w,{})}return r(c,{eyebrow:e(n,R.eyebrow,t),title:e(m,l.title,t),rows:S(A,y,t),subRows:S(a,M,t),totalLabel:e(i,"Total",t),totalAmount:e(s,"$0,000",t),note:e(u,l.note,t),contained:b})}};export{l as ORDER_SUMMARY_PH,U as OrderSummaryRender};
@@ -1,8 +1,8 @@
1
1
  import { type ReactElement, type ReactNode } from "react";
2
2
  import { readHidable, hidableText, type HidableValue } from "./hidable.js";
3
- import { FOCAL_DEFAULT } from "../image-focus.js";
4
3
  import { FOLD_FIELD_MARKER, LINK_FIELD_MARKER, MEDIA_FIELD_MARKER, SCAFFOLD_FIELD_MARKER, TEXT_FIELD_MARKER, foldMetaOf, textFieldIdentifier, type EdgeCell, type FoldFieldMeta, type TextFieldMeta, type TextListRendering } from "./field-markers.js";
5
4
  import { type HeroGroupPlacement } from "../hero-group-placement.js";
5
+ import { FOCAL_DEFAULT } from "efficient-shell/ui";
6
6
  import type { GeocodeState } from "../content/contact.js";
7
7
  import { type DirectionContainer } from "../content/container-direction.js";
8
8
  import { GAP_FIELD_CONTAINER, type GapContainer } from "../content/container-gap.js";
@@ -1 +1 @@
1
- "use client";import{jsx as r,jsxs as y,Fragment as E}from"react/jsx-runtime";import{cloneElement as qe,useId as Je,useRef as q,useState as ue}from"react";import{useEasel as N}from"efficient-easel/easel";import{readHidable as de,hidableText as pe}from"./hidable.js";import{FOCAL_DEFAULT as me}from"../image-focus.js";import{FOLD_FIELD_MARKER as J,LINK_FIELD_MARKER as fe,MEDIA_FIELD_MARKER as he,SCAFFOLD_FIELD_MARKER as ge,TEXT_FIELD_MARKER as T,foldMetaOf as Z,textFieldIdentifier as Ze}from"./field-markers.js";import Qe from"../../components/ApplyCornersToSiblings.js";import{CARD_IMAGE_RADIUS_STEP as et,CORNER_RADIUS_MAX as W,CORNER_RADIUS_MIN as B}from"../content/card-image-shape.js";import{IMAGE_CORNER_STEP as tt,IMAGE_CORNERS_LABEL as nt}from"../content/image-corners.js";import{GRID_MAX_COLUMNS as ot}from"../content/grid-span.js";import{GALLERY_ACROSS_BUCKETS as rt,GALLERY_LAYOUTS as A,GALLERY_LAYOUT_KEYS as be}from"../content/gallery-layout.js";import{anchorSiblingsOf as it,HERO_GROUP_PLACEMENTS as lt,HERO_GROUP_PLACEMENT_DEFAULT as at,normalisePlacement as st,placementPoints as xe}from"../hero-group-placement.js";import ct from"../../components/KeepHint.js";import{AlignLeftIcon as ut,AlignSeparateIcon as dt,AnimationIcon as Ce,BackgroundIcon as pt,BlockSectionIcon as mt,CartIcon as ft,ColumnWidthsIcon as Se,ColumnsIcon as ht,CornerIcon as Ie,DirectionDownIcon as gt,DirectionLeftIcon as bt,DirectionRightIcon as xt,DirectionUpIcon as Ct,DollarIcon as St,FinishIcon as It,GapIcon as _e,GridIcon as _t,GroundIcon as yt,HashIcon as ye,ImageIcon as Et,LayoutIcon as Tt,ListIcon as Rt,LocationIcon as Q,PaddingBottomIcon as Lt,PaddingLeftIcon as vt,PaddingRightIcon as Ot,PaddingTopIcon as Nt,PageIcon as Ee,PhoneIcon as At,PlacementIcon as Ft,ProductSizeIcon as Pt,RotateIcon as wt,SquareIcon as kt,StylesIcon as Dt,TextLinesIcon as Ht,TypeIcon as Bt,WidthIcon as Gt,WrapIcon as Mt}from"efficient-easel/icons";import{FieldGlyph as Te}from"../../components/FieldGlyph.js";import{resolvePageBackground as $t}from"../content/page-background.js";import{CORNER_SIDES as F,CORNER_SIDE_POINTS as ee,CORNER_SIDES_LABEL as P,cornerSidesSummary as Re,hasOwnSectionCorners as Wt,normalizeCornerSides as U}from"../content/section-corners.js";import{hasOwnCardCorners as Ut}from"../content/card-corners.js";import{SECTION_MOTION_NONE as Kt,SECTION_MOTION_OPTIONS as Xt}from"../content/section-animation.js";import{enclosingSectionProps as Le}from"./enclosing-section.js";import{SettingsCorners as ve,SettingsDefaultReset as g,SettingsField as f,SettingsGroupHead as zt,SettingsGroupSub as Vt,SettingsPlacement as Yt,SettingsSegmented as jt,SettingsSwitch as qt}from"efficient-easel/panel";import{FieldSelect as Jt,ListField as Zt}from"efficient-easel/fields";import{Checkbox as Qt,DateTimePicker as en,Slider as tn,Tooltip as K}from"efficient-shell/ui";import{ColourControl as Oe}from"./ColourControl.js";import Ne from"./MarkupToolbar.js";import{deviceField as R}from"./device-fields.js";import{noControlField as nn}from"./panel-no-control-mark.js";import{phoneKey as X,resolvePhoneValue as te}from"./phone-override.js";import{SuppressibleText as on}from"./section-text-suppress.js";import{CARD_INDEX_OPTIONS as rn,CARD_OUTLINE_OPTIONS as ln,DEFAULT_CARD_INDEX_FORMAT as an,DEFAULT_CARD_OUTLINE as sn}from"../sections/product-card-style.js";import{COVER_INDEX_OPTIONS as cn,DEFAULT_COVER_INDEX as un}from"../sections/card-cover-index.js";import{SCALAR_TEXT_CONTROLS as dn}from"./text-control-kinds.js";import pn from"../../components/ImageFocusRow.js";import mn from"../../components/MediaUploadField.js";import fn from"../../components/MultiSelectField.js";import hn from"../../components/SectionThemePicker.js";import gn from"../../components/SearchSelectField.js";import bn from"../../components/StorefrontLinkField.js";import Ae from"../../components/UiIcon.js";import{SECTION_PADDING as S}from"../content/section-padding.js";import{hasPhoneHeight as xn,resolveSectionMinHeight as Cn}from"../content/section-min-height.js";import{VIEW_TIER_LABEL as ne}from"../content/view-tiers.js";import{SECTION_MIN_HEIGHT as Sn,SECTION_MIN_HEIGHT_GROUP_LABEL as G,SECTION_SCREEN_PCT as In}from"../content/section-min-height.js";import{CONTAINER_DIRECTION_LABEL as _n,containerDirectionPoints as yn,resolveContainerDirection as Fe}from"../content/container-direction.js";import{BOX_ALIGN_POINTS as En,BOX_BLOCK_SPACING_LABEL as Tn,BOX_BLOCK_SPACING_POINTS as Pe,BOX_JUSTIFY_POINTS as we,BOX_PHONE_ROW_LABEL as Rn,BOX_PHONE_ROW_MAX as Ln,BOX_PHONE_ROW_MIN as ke,BOX_SHARE_LABEL as De,BOX_SHARE_POINTS as oe,BOX_WRAP_LABEL as vn,BOX_WRAP_POINTS as He}from"../content/box-layout.js";import{usePreviewHeader as z}from"../../components/PreviewHeaderContext.js";import{CONTAINER_GAP as re,CONTAINER_GAP_BUILT_IN as On,GAP_FIELD_CONTAINER as Nn,hasOwnContainerGap as An,resolveContainerGap as Fn}from"../content/container-gap.js";import{CARD_IMAGE_BG_INHERIT as Pn,CARD_IMAGE_BG_OFF as wn,CARD_IMAGE_BG_SWATCH_NAMES as kn,CARD_IMAGE_BG_SWATCHES as Dn,isCardImageBackgroundInheriting as Hn,cardImageBackgroundChoice as Bn,THEME_CARD_IMAGE_BG as Gn}from"../content/card-image-background.js";import{SECTION_BG_INHERIT as Mn,SECTION_BG_SWATCHES as $n,SECTION_BG_SWATCH_NAMES as Wn,THEME_SECTION_BG as Un,isSectionBackgroundInheriting as Kn}from"../content/section-background.js";import{SECTION_THEME_GROUP_LABEL as Xn}from"../content/section-surface.js";import{TYPE_SIZE_FIXED as zn,TYPE_SIZE_INHERIT as Vn,isTypeSizeInheriting as Yn}from"../content/section-type-size.js";import{SECTION_WIDTH_CHOICES as jn,WIDTH_CHOICE_LABEL as qn,WIDTH_INHERIT as Jn,resolveWidth as Zn,sectionRunsFullWidth as Be}from"../content/section-width.js";import{useFoldHeadingLevel as Ge}from"./panel-heading-scope.js";import{withStyleKind as Qn}from"efficient-easel/style-clipboard";function M(e){for(const[t,n]of Object.entries(e))n&&typeof n=="object"&&!Z(n)&&Qn(n,`section:${t}`);return e}function jr({children:e}){return r("div",{className:"sf-field-label",children:e})}function Me(){return null}function eo(e){if(!e.trim())throw new Error("noGlyph() needs a reason naming the ruling that decided it.");return r(Me,{},e)}function to(e){return e.type===Me}function V(e){return to(e)?void 0:e}function w(e,t){return`${e} from ${t}`}function no(){const{appState:e}=N(i=>i),t=e.data.root?.props??{},{mode:n,pageWidth:o}=Zn(t,"full");return w(n==="page"?`${o}px`:n==="contained"?"Contained":"Full","the page")}function oo(){const{blockGap:e}=z();return e===null?"this container's own spacing":w(`${e}px`,"Site styles")}function ro({inherited:e,onReset:t,label:n}){return r(g,{label:n,changed:!e,detail:oo(),onReset:t})}function io({inherited:e,onReset:t,label:n}){return r(g,{label:n,changed:!e,detail:no(),onReset:t})}function k({value:e,onChange:t,label:n,placeholder:o,hint:i,multiline:l,hideable:a=!0,markup:s=!0}){const{text:c,hidden:d}=de(e),m=q(null),u=q(null),p=_=>t(a?{text:_,hidden:d}:_),h=()=>t({text:c,hidden:!d}),b=a&&d,I=Je(),x=i?uo(i)?r("span",{className:"sf-hint-keep sf-hint-while-typing",children:i}):r(ct,{children:i}):void 0;return r(f,{label:n,icon:r(Bt,{}),htmlFor:I,className:b?"is-hidden":void 0,hint:x,action:a?r(K,{content:d?`Show ${n} on the slide`:`Hide ${n} on the slide`,children:r("button",{type:"button",className:"sf-field-eye","aria-pressed":d,"aria-label":d?`Show ${n} on the slide`:`Hide ${n} on the slide`,onClick:h,children:d?r(Ae,{name:"eye-off",size:14}):r(Ae,{name:"eye",size:14})})}):void 0,children:y("div",{className:"sf-copybox",children:[s&&r(Ne,{target:l?u:m,value:c,onChange:p}),l?r("textarea",{id:I,ref:u,value:c,placeholder:o,onChange:_=>p(_.target.value)}):r("input",{id:I,ref:m,type:"text",value:c,placeholder:o,onChange:_=>p(_.target.value)})]})})}function qr(e,t){return{...e,[ge]:t}}function Jr(e){const t=e[T];if(!t)throw new Error("withOffPage: the field holds no authored text");return{...e,[T]:{...t,offPage:!0}}}function Zr(e){return!e||typeof e!="object"?!1:e[T]?.offPage===!0}function Qr(e){const t=e[T];if(!t)throw new Error("withIdentifier: the field holds no authored text");return{...e,[T]:{...t,identifier:!0}}}import{TEXT_CONTROL_KINDS as ol,SCALAR_TEXT_CONTROLS as rl}from"./text-control-kinds.js";const lo=new Set(dn),D=(e,t)=>{const n={...t,[T]:e};if(!lo.has(e.control))return n;const o=t.render;return{...nn(n,"authored-copy"),render:i=>r(on,{name:i.name,children:o(i)})}},ei="Everything else on this block comes from the linked post. Unlink it to edit by hand.",ao="Select a word, then press the highlighter.",so="A short name so a link can jump straight to this section, like yoursite.com/page#about.",co=new Set([ao]),uo=e=>co.has(e);function ti(e,t,n){return D({control:"text",label:e,placeholder:t,hint:n},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:e,placeholder:t,hint:n})})}function ni(e,t,n){return D({control:"textarea",label:e,placeholder:t,hint:n},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:e,placeholder:t,hint:n,multiline:!0})})}function po(e,t,n){return D({control:"plainText",label:e,placeholder:t,hint:n},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:e,placeholder:t,hint:n,hideable:!1,markup:!1})})}function oi(e,t,n){return D({control:"copyText",label:e,placeholder:t,hint:n},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:e,placeholder:t,hint:n,hideable:!1})})}function ri(e){return{type:"custom",[fe]:{label:e},render:({value:t,onChange:n})=>r(bn,{value:pe(t),onChange:n,label:e})}}function ii(e,t,n){return D({control:"plainTextarea",label:e,placeholder:t,hint:n},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:e,placeholder:t,hint:n,multiline:!0,hideable:!1})})}const li={Content:Ht,Style:Dt,Layout:Tt,Animation:Ce};function ai(e,t){return e.includes("Content")?t!=="Content":null}function mo({label:e}){return r(zt,{title:e,level:Ge(1)})}function fo({level:e,label:t}){return e===1?r(mo,{label:t}):r(go,{label:t})}function $e(e,t){return{type:"custom",[J]:{label:e,level:t},render:()=>r(fo,{level:t,label:e})}}function C(e){return $e(e,2)}function si(e){return{type:"custom",render:()=>r(ho,{text:e})}}function ho({text:e}){return r("p",{className:"sf-note",children:e})}function ci(e){return $e(e,1)}function ui(e){return Z(e)!==null&&e?.tabs!==void 0}const We=new Map;function di(e,t){const n=`${e}\0${t?t.join(""):""}`,o=We.get(n)??{type:"custom",tabs:t,[J]:{label:e,level:1},bucket:e,marker:!0,render:()=>r(E,{})};return We.set(n,o),o}function go({label:e}){return r(Vt,{title:e,level:Ge(2)})}function Ue({swatches:e,current:t,onPick:n,names:o}){const i=e.find(a=>a.toLowerCase()===t.toLowerCase()),l=(i?o?.[i]:void 0)??t;return y("div",{className:"sf-swatches",children:[e.map(a=>{const s=o?.[a]??a;return r(K,{content:s,children:r("button",{type:"button","aria-pressed":t.toLowerCase()===a.toLowerCase(),className:`sf-swatch ${t.toLowerCase()===a.toLowerCase()?"is-active":""}`,style:{background:a},onClick:()=>n(a),"aria-label":s})},a)}),r("span",{className:"sf-swatch-hex",children:l})]})}function pi(e,t){return{type:"custom",render:({value:n,onChange:o})=>{const i=Kn(n,t);return r(f,{label:e,icon:r(pt,{}),changed:!i,action:r(g,{label:e,changed:!i,detail:"the theme's section background",onReset:()=>o(Mn)}),children:Ue({swatches:$n,current:i?Un:n??t??"",onPick:o,names:Wn})})}}}function bo(e,t){return{type:"custom",render:({value:n,onChange:o})=>{const i=n,l=Hn(i,t);return r(f,{label:e,icon:r(yt,{}),changed:!l,action:r(g,{label:e,changed:!l,detail:"the theme's image stage",onReset:()=>o(Pn)}),children:Ue({swatches:Dn,current:l?Gn:Bn(i,t),onPick:o,names:kn})})}}}function mi(e=n=>n,t){return M({_gSectionTheme:C(Xn),sectionAccent:{type:"custom",render:({value:n,onChange:o})=>r(hn,{value:e(n),onChange:o,followLabel:t})}})}function v({min:e,max:t,step:n,value:o,onChange:i,suffix:l="",readout:a=!0,notch:s,ariaLabel:c,disabled:d=!1}){const m=s!==void 0&&Number.isFinite(s)&&s>=e&&s<=t;return r("div",{className:m?"sf-slider has-notch":"sf-slider",style:m?{"--sf-notch":(s-e)/(t-e)}:void 0,children:r(tn,{min:e,max:t,step:n,value:o,suffix:l||void 0,showInput:a,label:c,disabled:d,size:"sm",className:"sf-slider-track",onChange:u=>{u!==null&&u!==o&&i(u)}})})}function H(e,t,n,o,i,l,a="",s){return{type:"custom",render:c=>r(f,{label:e,icon:V(t),action:s?s("storedValue"in c?c.storedValue:c.value,c.onChange):void 0,children:v({min:n,max:o,step:i,value:typeof c.value=="number"?c.value:l,suffix:a,ariaLabel:e,onChange:c.onChange})})}}function Ke({min:e,max:t,step:n,px:o,label:i,onChange:l,disabled:a=!1}){const{cornerRadiusPx:s}=z();return r(E,{children:v({min:e,max:t,step:n,value:o??(typeof s=="number"?s:e),readout:!1,ariaLabel:i,disabled:a,onChange:l})})}function $(e,t){const{min:n,max:o,step:i=1,unsetLabel:l,hint:a,restAtSite:s=!1,restTrack:c,unsetMark:d}=t;return{type:"custom",render:({value:m,onChange:u})=>{const p=typeof m=="number"?m:null,h=p===null;return r(f,{label:e,value:h?d?void 0:l:`${p}px`,changed:!h,action:d?qe(d,{changed:!h,onReset:()=>u(null)}):r(g,{label:e,changed:!h,onReset:()=>u(null)}),hint:a,children:c?c({min:n,max:o,step:i,px:p,label:e,onChange:u}):s?r(Ke,{min:n,max:o,step:i,px:p,label:e,onChange:u}):v({min:n,max:o,step:i,value:p??n,readout:!1,ariaLabel:e,onChange:u})})}}}function fi(e){const t=H("Gap",r(_e,{}),re.min,re.max,re.step,On[e],"px",(n,o)=>r(ro,{inherited:!An(e,n),onReset:()=>o(void 0),label:"Gap"}));return{type:"custom",[Nn]:e,render:n=>t.render({...n,value:Fn(e,n.value,n.field?.siteGap),storedValue:n.value,onChange:o=>n.onChange(o)})}}function xo(){return{type:"custom",render:({value:e,onChange:t})=>{const o=U(e)??[...F],i=o.length===F.length;return r(f,{label:P,icon:r(Ie,{}),value:Re(o),changed:!i,action:r(g,{label:P,changed:!i,onReset:()=>t(null)}),hint:"Corners left off stay square. The row above sets how round the others are.",children:r(yo,{value:o,onChange:l=>{const a=U(l)??[];t(a.length===F.length?null:a)}})})}}}function Co({label:e,changed:t=!1,onReset:n=()=>{}}){const{cornerRadiusPx:o}=z(),i=typeof o=="number"?`${o}px`:"not set";return r(g,{label:e,changed:t,detail:o==null?"the built-in corners":w(i,"Site styles"),onReset:n})}function So(){return $("Corners",{min:B,max:W,unsetLabel:"Follows the site",unsetMark:r(Co,{label:"Corners"}),restTrack:e=>r(Io,{...e}),hint:r(_o,{})})}const Xe="This section runs edge to edge, so its corners sit off the page. Set Width to Content width to use them.";function ie(){return Be(Y())}function Io(e){return r(Ke,{...e,disabled:ie()})}function _o(){return r(E,{children:ie()?Xe:"Follows Site styles ▸ Basics ▸ Corners until you set a number here."})}function yo({value:e,onChange:t}){const n=ie();return r(ve,{label:P,value:e,corners:n?ee.map(o=>({...o,disabled:!0,title:Xe})):ee,onChange:t})}function hi(){return M({_gShape:C("Shape"),sectionCorners:So(),sectionCornerSides:xo()})}function gi(){return{_gMotion:C("Motion"),sectionAnimation:ce("Entrance",r(Ce,{}),[...Xt],Kt)}}function le(){let e=null;try{const{appState:t,selectedItem:n}=N(i=>i),o=n?.props?.id?String(n.props.id):void 0;e=o?Le(t?.data,o):null}catch{e=null}return e!==null&&Be(e)}function ze(e){const{cornerRadiusPx:t}=z(),n=le(),o=typeof t=="number"?t:e;let i=null;try{const{appState:a,selectedItem:s}=N(d=>d),c=s?.props?.id?String(s.props.id):void 0;i=c?Le(a?.data,c):null}catch{i=null}if(n||!i)return o;const l=i.sectionCorners;return Wt(l)?l:o}function Eo({min:e,max:t,step:n,px:o,label:i,onChange:l}){const a=ze(e);return r(E,{children:v({min:e,max:t,step:n,value:o??a,readout:!1,ariaLabel:i,onChange:l})})}function To({label:e,changed:t=!1,onReset:n=()=>{}}){const o=le(),i=ze(B),l=o?"Site":"Section";return r(g,{label:e,changed:t,detail:w(`${i}px`,o?"Site styles":"the section"),onReset:n})}function Ro(){return r(E,{children:le()?"The section is full width, so this card follows Site styles ▸ Basics ▸ Corners.":"Follows the section's Corners until you set a number here."})}function Lo(){return $("Corners",{min:B,max:W,unsetLabel:"Follows the section",unsetMark:r(To,{label:"Corners"}),restTrack:e=>r(Eo,{...e}),hint:r(Ro,{})})}function vo({value:e,onChange:t}){return r(ve,{label:P,value:e,corners:ee,onChange:t})}function Oo({unset:e}){return r(E,{children:e?"Set a number above first — there is nothing to shape yet.":"Corners left off stay square. The row above sets how round the others are."})}function No(){return{type:"custom",render:({value:e,onChange:t})=>{const o=U(e)??[...F],i=o.length===F.length;return r(f,{label:P,icon:r(Ie,{}),value:Re(o),changed:!i,action:r(g,{label:P,changed:!i,onReset:()=>t(null)}),hint:r(Oo,{unset:!Ut(e)}),children:r(vo,{value:o,onChange:l=>{const a=U(l)??[];t(a.length===F.length?null:a)}})})}}}function Ao(){return{type:"custom",render:()=>r(Qe,{})}}function bi(){return{_gShape:C("Shape"),cardCorners:Lo(),cardCornerSides:No(),cardCornersApplyAll:Ao()}}function xi(){return L("Justify",r(dt,{}),we,we[0].value)}function Ci(){return L("Item alignment",r(ut,{}),En,"stretch")}function Si(){return L(vn,r(Mt,{}),He,He[0].value)}function Ii(){return{type:"custom",render:({value:e,onChange:t})=>{const n=oe.find(o=>o.value===e)??oe[0];return r(f,{label:De,icon:r(Se,{}),value:n.label,children:r("div",{className:"sf-gallery-layouts",role:"group","aria-label":De,children:oe.map(o=>r(K,{content:o.label,className:"sf-tile-tip",children:r("button",{type:"button","aria-pressed":n.value===o.value,"aria-label":o.label,onClick:()=>t(o.value),children:r("span",{className:"sf-gallery-pic",children:Fo(o.weights).map((i,l)=>r("i",{style:{gridColumn:`span ${i}`}},l))})})},o.value))})})}}}function Fo(e){if(!e)return[3,4];const t=e.reduce((n,o)=>n+o,0);return e.map(n=>Math.round(n/t*12))}function _i(){return L(Tn,r(_e,{}),Pe,Pe[0].value)}function yi(){return H(Rn,r(At,{}),ke,Ln,1,ke)}function Ei(e){const t=ce(_n,eo("`Direction` names how a container's children run — a MODIFIER, not a thing. doc/naming.md N10.1 gives the idea a dash in its Glyph column; editor-shell's own `direction` meaning says the bare row is CORRECT and not an omission (SS seat, 2026-09-11)."),yn(e),Fe(e,void 0));return{type:"custom",render:n=>t.render({...n,value:Fe(e,n.value),onChange:o=>n.onChange(o)})}}function Ti(e,t,n,o,i,l){return{type:"custom",render:({value:a,onChange:s})=>r(f,{label:e,icon:r(Te,{noun:l}),action:r(g,{label:e,changed:!Yn(a),detail:"the Text style in Site styles",onReset:()=>s(Vn),defaultAction:{onPress:()=>s(zn),title:"Keep this section's own built-in size",icon:r(mt,{})}}),children:v({min:t,max:n,step:o,value:typeof a=="number"?a:i,suffix:"px",ariaLabel:e,onChange:s})})}}function Ri(){return{_gCellWidth:C("Cell width"),gridSpan:L("Positions",r(Se,{}),[{label:"Auto",value:""},...Array.from({length:ot},(e,t)=>({label:t===0?"1 position":`${t+1} positions`,value:String(t+1)}))],"")}}function Y(){let e=null;try{e=N(t=>t).selectedItem}catch{e=null}return e?.props??{}}function Po({min:e,max:t,step:n,px:o,label:i,onChange:l,desktopKey:a,fallback:s}){const c=Y()[a],d=te(void 0,c,s);return r(E,{children:v({min:e,max:t,step:n,value:te(o,c,s),readout:!1,ariaLabel:i,notch:d,onChange:l})})}function wo({label:e,desktopKey:t,fallback:n,changed:o=!1,onReset:i=()=>{}}){const l=Y()[t],a=te(void 0,l,n);return r(g,{label:e,changed:o,detail:`${a}px on ${ne.desktop.toLowerCase()}`,onReset:i})}function ko(e){return $(e.label,{min:e.min,max:e.max,step:e.step,unsetLabel:`Follows ${ne.desktop}`,unsetMark:r(wo,{label:e.label,desktopKey:e.desktopKey,fallback:e.fallback}),restTrack:t=>r(Po,{...t,desktopKey:e.desktopKey,fallback:e.fallback})})}function Li(e={}){const t=e.keys?.top??"sectionPaddingTop",n=e.keys?.bottom??"sectionPaddingBottom",o=e.group!==!1,i=x=>o?x:`Padding ${x.toLowerCase()}`,l=x=>H(i("Top"),r(Nt,{}),S.min,S.max,S.step,x,"px"),a=(x,_,je,j=S)=>R("mobile",ko({label:i(x),desktopKey:_,min:j.min,max:j.max,step:j.step,fallback:je})),s=e.top??S.min,c=e.bottom??S.min,d="sectionPaddingLeft",m="sectionPaddingRight",u=e.sideBounds??S,p=e.side??u.min,h=e.sidePhone??p,b=e.phone===!0,I=x=>b?R("desktop",x):x;return M({...o?{_gSpacing:C("Padding")}:{},[t]:I(l(s)),...b?{[X(t)]:a("Top",t,s)}:{},...e.only==="top"?{}:{[n]:I(H(i("Bottom"),r(Lt,{}),S.min,S.max,S.step,c,"px")),...b?{[X(n)]:a("Bottom",n,c)}:{}},...e.sides?{[d]:I(H(i("Left"),r(vt,{}),u.min,u.max,u.step,p,"px")),...b?{[X(d)]:a("Left",d,h,u)}:{},[m]:I(H(i("Right"),r(Ot,{}),u.min,u.max,u.step,p,"px")),...b?{[X(m)]:a("Right",m,h,u)}:{}}:{}})}const Do={contained:"Contained",page:"Page",full:"Full"},ae="Width";function vi(e,t=jn,n=!0){const o=t.map(i=>({label:qn[i]??Do[i],value:i}));return M({...n?{_gWidth:C(ae)}:{},widthMode:{type:"custom",render:({onChange:i,field:l})=>r(f,{label:"Width",icon:r(Gt,{}),action:n?r(io,{inherited:l?.inherited??!1,onReset:()=>i(Jn),label:ae}):void 0,children:se({options:o,value:l?.currentValue||e,onChange:i,ariaLabel:ae})})}})}function Oi(){const e=o=>({type:"custom",render:({value:i,onChange:l})=>y("div",{className:"sf-field",children:[o?y("div",{className:"sf-field-head",children:[r("span",{className:"sf-field-label sf-field-label--inline",children:G}),o(l)]}):null,r("div",{children:se({options:[{label:"Auto",value:"auto"},{label:"Fixed",value:"fixed"},{label:"Screen",value:"screen"}],value:["auto","fixed","screen"].includes(i)?i:"auto",onChange:l,ariaLabel:G})})]})}),t=()=>({type:"custom",render:({value:o,onChange:i,field:l})=>{const a=l?.unit==="%"?"%":"px",s=a==="%"?In:Sn;return r("div",{className:"sf-field",children:v({min:s.min,max:s.max,step:s.step,value:typeof o=="number"?o:s.fallback,suffix:a,ariaLabel:G,onChange:i})})}}),n=()=>ce("Unit",r(ye,{}),[{label:"px",value:"px"},{label:"%",value:"%"}],"px");return M({_gHeight:C(G),sectionHeightMode:R("desktop",e()),sectionHeightValue:R("desktop",t()),sectionHeightUnit:R("desktop",n()),sectionHeightModePhone:R("mobile",e(o=>r(Ho,{onClear:()=>o(void 0)}))),sectionHeightValuePhone:R("mobile",t()),sectionHeightUnitPhone:R("mobile",n())})}function Ho({onClear:e}){const t=Y(),n=xn(t),o=Cn(t),i=`${o.mode==="auto"?"Auto":`${o.value}${o.unit}`} on ${ne.desktop.toLowerCase()}`;return r(g,{label:G,changed:n,detail:i,onReset:e})}function Ni(){return{_gAnchor:C("Anchor"),anchor:po("Anchor name","e.g. about",so)}}function Ai(e,t,n){return{type:"custom",render:({value:o,onChange:i,id:l,name:a})=>{const s=`${l??a??e}-datetime`,c=Date.parse(typeof o=="string"?o:"");return r(f,{label:e,icon:t,htmlFor:s,hint:n,children:r(en,{id:s,value:Number.isFinite(c)?new Date(c):null,onChange:d=>i(d?d.toISOString():"")})})}}}function O(e,t,n){return{type:"custom",render:({value:o,onChange:i,id:l,name:a})=>{const s=typeof o=="boolean"?o:t,c=`${l??a??e}-label`;return r(f,{label:e,labelId:c,icon:n,action:r(qt,{checked:s,onChange:i,ariaLabelledBy:c})})}}}function Fi(){return{type:"custom",render:({value:e,onChange:t,id:n,name:o})=>{const i=`${String(n??o??"pageBackground")}-colour`;return r(f,{label:"Background",icon:r(Ee,{}),htmlFor:i,action:r(Oe,{id:i,label:"Background",value:$t(e),onChange:t})})}}}function Pi(e,t){return{type:"custom",render:({value:n,onChange:o,id:i})=>{const l=typeof n=="boolean"?n:t,a=`${i??e}-checkbox`;return r(f,{label:e,htmlFor:a,className:"sf-checkbox",action:r(Qt,{id:a,checked:l,onChange:o})})}}}function wi(e,t){return{type:"custom",render:({value:n,onChange:o})=>r(f,{label:e,action:Oe({value:n||t,onChange:o,label:e})})}}const Bo=[{value:"0% 0%",label:"Top left"},{value:"50% 0%",label:"Top"},{value:"100% 0%",label:"Top right"},{value:"0% 50%",label:"Left"},{value:"50% 50%",label:"Center"},{value:"100% 50%",label:"Right"},{value:"0% 100%",label:"Bottom left"},{value:"50% 100%",label:"Bottom"},{value:"100% 100%",label:"Bottom right"}];function Ve({label:e,value:t,onChange:n,points:o=Bo}){return r(Yt,{label:e,value:t,points:o,onChange:n})}function ki(e,t=me,n="mediaImage"){return{type:"custom",render:({value:o,onChange:i})=>r("div",{className:"sf-focal-row",children:r(Go,{label:e,value:o||t,onChange:i,imageProp:n})})}}function Go({label:e,value:t,onChange:n,imageProp:o}){const{selectedItem:i}=N(a=>a),l=i?.props?.[o];return r(pn,{label:e,value:t,onChange:n,image:typeof l=="string"?l:void 0})}const Mo=xe([]);function Di(e,{stacking:t,fallback:n=at}){return{type:"custom",render:({value:o,onChange:i})=>{const l=lt.includes(o)?o:n;return t?r($o,{label:e,value:l,onChange:i}):Ye({label:e,value:l,onChange:i,points:Mo})}}}function $o({label:e,value:t,onChange:n}){const{appState:o,selectedItem:i}=N(s=>s),l=i?.props?.id?String(i.props.id):void 0,a=l?it(o?.data,l):[];return Ye({label:e,value:t,onChange:n,points:xe(a,l)})}function Ye({label:e,value:t,onChange:n,points:o}){const i=o.find(l=>l.disabled);return r(f,{label:e,icon:r(Ft,{}),hint:i?i.title:void 0,children:Ve({label:e,value:st(t),onChange:n,points:o})})}const Hi={top:r(Ct,{}),right:r(xt,{}),bottom:r(gt,{}),left:r(bt,{})};function Bi(e,t,n,o,i,l){const a=m=>t.find(u=>u.value===m),s=m=>({value:m,label:"",disabled:!0,title:o}),c=m=>{const u=t.find(h=>h.cell===m);if(!u)return s(`missing-${m}`);const p=l?.[m];return p?{value:u.value,label:u.label,icon:p}:{value:u.value,label:u.label}},d=[s("corner-top-left"),c("top"),s("corner-top-right"),c("left"),s("centre"),c("right"),s("corner-bottom-left"),c("bottom"),s("corner-bottom-right")];return{type:"custom",render:({value:m,onChange:u})=>{const p=t.some(h=>h.value===m)?m:n;return r(f,{label:e,icon:i,value:a(p)?.label??"",children:Ve({label:e,value:p,onChange:u,points:d})})}}}const Wo="\0note";function L(e,t,n,o,i){return{type:"custom",options:n,fallback:o,...i?{note:i}:{},render:({value:l,onChange:a,field:s})=>{const c=s.options??n,d=s.fallback??o,m=c.some(u=>u.value===l)?l:d;return r(f,{label:e,icon:V(t),children:r(Jt,{value:m,ariaLabel:e,onChange:a,options:[...i?[{label:i,value:Wo,disabled:!0}]:[],...c.map(u=>({label:u.label,value:u.value}))]})})}}}function Gi(e,t,n){return{type:"custom",options:t,render:({value:o,onChange:i,field:l})=>r(fn,{label:e,options:l.options??t,value:Array.isArray(o)?o:[],onChange:i,...n?{emptyLabel:n}:{}})}}function Mi(e,t,n,o){return{type:"custom",options:t,fallback:n,render:({value:i,onChange:l,field:a})=>r(gn,{label:e,options:a.options??t,fallback:a.fallback??n,value:i,onChange:l,placeholder:o})}}function $i(e,t={}){return{type:"custom",render:({value:n,onChange:o})=>{const i={value:n,onChange:o,...t};return r(e,{...i})}}}function se({options:e,value:t,onChange:n,ariaLabel:o,disabled:i=!1}){return r(jt,{options:e.map(l=>({id:l.value,label:l.label,title:l.title})),value:t,onChange:n,ariaLabel:o,disabled:i})}const Wi=[{label:"Image",value:"image"},{label:"Video",value:"video"}];function ce(e,t,n,o){const i=n.map(l=>typeof l=="string"?{label:l,value:l}:l);return{type:"custom",render:({value:l,onChange:a,field:s})=>r(f,{label:e,icon:V(t),children:se({options:i,value:i.some(c=>c.value===l)?l:l||s?.currentValue||o,onChange:a,ariaLabel:e})})}}function Ui(e,t,n){return{type:"custom",[he]:!0,render:({value:o,onChange:i})=>r(mn,{value:o||"",onChange:i,label:e,accept:t,placeholder:n})}}const Ki={HeroSingle:["imageFocal"],ContactLocations:["locations[].photo"],ProcessSteps:["steps[].image"]};function Xi({value:e,onChange:t,label:n}){const o=e||{},i=!!o.pending,l=i?"var(--fg-dim, #888)":o.ok?"#1d9e75":"#d85a30",a=(s,c)=>t({...o,[s]:c===""?void 0:Number(c)});return y(f,{label:n,icon:r(Q,{}),children:[r("button",{type:"button",disabled:i,onClick:()=>t({...o,pending:!0,ok:!1,status:"Finding…"}),style:{width:"100%",display:"flex",alignItems:"center",justifyContent:"center",gap:6,padding:"8px 10px",fontSize:13,cursor:i?"default":"pointer",opacity:i?.6:1,border:"1px solid var(--border-strong, #ccc)",borderRadius:6,background:"transparent",color:"inherit"},children:i?"Finding…":"Find coordinates"}),o.status&&r("div",{style:{marginTop:6,fontSize:12,lineHeight:1.4,color:l},children:o.status}),r("div",{style:{marginTop:6,fontSize:11,color:"var(--fg-dim, #999)"},children:"Coordinates from OpenStreetMap"}),r("button",{type:"button",onClick:()=>t({...o,manual:!o.manual}),style:{marginTop:8,padding:0,border:"none",background:"none",font:"inherit",fontSize:12,color:"var(--sf-accent, #2563eb)",cursor:"pointer",textDecoration:"underline"},children:o.manual?"Hide manual coordinates":"Enter coordinates manually"}),o.manual&&y("div",{style:{marginTop:8,display:"grid",gap:8},children:[r(f,{label:"Latitude",icon:r(Q,{}),children:r("input",{type:"number",step:"any",placeholder:"e.g. 34.0990198",value:typeof o.lat=="number"?o.lat:"",onChange:s=>a("lat",s.target.value)})}),r(f,{label:"Longitude",icon:r(Q,{}),children:r("input",{type:"number",step:"any",placeholder:"e.g. -117.9842833",value:typeof o.lng=="number"?o.lng:"",onChange:s=>a("lng",s.target.value)})})]})]})}function Uo(e,t){return t===null||t<0||t>=e.length?"":e[t]?.text??""}function Ko(e,t,n){const o=e.map(i=>({text:i?.text??""}));return t===null||t<0||t>=e.length?o:o.map((i,l)=>l===t?{text:n}:i)}function zi(e,t){return e===null?null:t>e?e:null}function Xo(e,t,n){if(n===null||n>=t.length)return null;for(let o=0;o<n;o+=1)if(e[o]!==t[o])return null;return e[n]!==t[n]&&t.includes(e[n])||e[n]!==t[n]&&t.length!==e.length?null:n}const Vi={label:"Ticker items",icon:r(Rt,{})};function Yi(e,t,n,o){return{type:"custom",[T]:{control:"textList",label:e,placeholder:n,itemKey:"text",rendering:o},render:({value:i,onChange:l})=>r(zo,{label:e,icon:V(t),items:Array.isArray(i)?i:[],placeholder:n,onChange:l,markup:o==="markup"})}}function zo({label:e,icon:t,items:n,placeholder:o,onChange:i,markup:l=!1}){const a=q(null),[s,c]=ue(null),d=u=>u.map(p=>({text:p?.text??""}));return r(Zt,{label:e,icon:t,noun:"item",items:n,onChange:u=>{const p=Xo(n,u,s);p===null&&(a.current=null),c(p),i(d(u))},newItem:()=>({text:""}),open:null,onOpen:()=>{},renderItem:()=>null,above:l?r(Ne,{target:a,value:Uo(n,s),onChange:u=>i(Ko(n,s??-1,u)),disabled:s===null,label:s===null?"Formatting — click a row first":`Formatting — row ${s+1}`}):void 0,renderRow:(u,p,h)=>r("input",{type:"text",className:l&&s===p?"sf-list-marking":void 0,value:u?.text??"",placeholder:o,"aria-label":`${e} ${p+1}`,onChange:b=>h({text:b.target.value}),onFocus:b=>{a.current=b.currentTarget,c(p)}})})}function ji(e,t){const n=`${e.label} — row ${t+1}`;return D({control:"plainText",label:n,placeholder:e.placeholder,offPage:e.offPage},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:n,placeholder:e.placeholder,hideable:!1,markup:e.rendering==="markup"})})}function qi(e){return{_gCards:C("Cards"),coverIndex:L("Cover image",r(Et,{}),cn,String(un),e?.coverHint??"A card's opening picture — a card pinned to a finish keeps its own."),imageBackground:bo("Image background",wn),cardImage:Vo(),spinOnHover:O("Rotate on hover",e?.spinDefault??!0,r(wt,{}))}}function Ji(){return{outline:L("Card outline",r(kt,{}),ln,sn),indexBadge:L("Card number",r(ye,{}),rn,an),showBadge:O("Product badge",!0,r(Te,{noun:"tag"}))}}function Zi(e){const t=e?.bottomDefault??!0;return{_gShowOnCard:C("Show on a card"),showCardPrice:O("Price",!0,r(St,{})),showCardFinishes:O("Finish swatches",!0,r(It,{})),showCardSizes:O("Sizes",t,r(Pt,{})),showCardBuy:O("Buy button",t,r(ft,{})),showCardPage:O("Page button",t,r(Ee,{}))}}function Vo(){return $("Card image",{min:B,max:W,step:et,hint:"Rounds the picture. The card's own corner is in Site styles."})}function Qi(){return $(nt,{min:B,max:W,step:tt,unsetLabel:"Square",hint:"Rounds the picture. Left alone it stays square."})}function el(){return{type:"custom",render:({value:e,onChange:t})=>r(Yo,{value:typeof e=="string"?e:"",onChange:t})}}function Yo({value:e,onChange:t}){const[n,o]=ue(null),i=be.filter(a=>n===null||A[a].across===n),l=e&&e in A?A[e]:null;return y(E,{children:[r(f,{label:"Photos in a row",icon:r(ht,{}),children:y("div",{className:"sf-gallery-filter",children:[r("button",{type:"button","aria-pressed":n===null,onClick:()=>o(null),children:"All"}),rt.map(a=>r("button",{type:"button","aria-pressed":n===a,onClick:()=>o(a),children:a},a))]})}),r(f,{label:"Layout",icon:r(_t,{}),value:l?l.label:"Not chosen",hint:`${i.length} of ${be.length} layouts`,children:r("div",{className:"sf-gallery-layouts",children:i.map(a=>r(K,{content:A[a].label,className:"sf-tile-tip",children:r("button",{type:"button","aria-pressed":e===a,"aria-label":A[a].label,onClick:()=>t(e===a?"":a),children:r("span",{className:"sf-gallery-pic",children:A[a].desktop.map(([s,c],d)=>r("i",{style:{gridColumn:`span ${s}`,gridRow:`span ${c}`}},d))})})},a))})})]})}export{so as ANCHOR_HINT,ei as BOUND_TO_POST_NOTE,li as BUCKET_ICONS,Ki as CUSTOM_FIELD_MEDIA,Xi as CoordsField,Hi as EDGE_ARROWS,me as FOCAL_DEFAULT,Bo as FOCAL_POINTS,J as FOLD_FIELD_MARKER,Ve as FocalPicker,go as GroupLabel,ao as HIGHLIGHT_HINT,k as HidableTextField,fe as LINK_FIELD_MARKER,jr as Label,he as MEDIA_FIELD_MARKER,Wi as MEDIA_TYPE_OPTIONS,ho as PanelNoteLine,Ye as PlacementGridView,ge as SCAFFOLD_FIELD_MARKER,rl as SCALAR_TEXT_CONTROLS,Xe as SECTION_BLEEDS_HINT,mo as SectionHeading,se as Segmented,ro as SiteGapDefaultReset,v as Slider,Ue as Swatches,ol as TEXT_CONTROL_KINDS,T as TEXT_FIELD_MARKER,Vi as TICKER_ITEMS_ROW,zo as TextListField,io as WidthDefaultReset,Xo as aimAfterListChange,Ni as anchorFields,w as backTo,pi as backgroundField,Ci as boxAlignField,_i as boxBlockSpacingField,xi as boxJustifyField,yi as boxPhoneRowField,Ii as boxShareField,Si as boxWrapField,di as bucketHeader,No as cardCornerSidesField,Lo as cardCornersField,bo as cardImageBackgroundField,Vo as cardImageField,qi as cardMediaFields,bi as cardShapeFields,Zi as cardShowFields,Ji as cardStyleFields,Ri as cellWidthFields,Pi as checkbox,wi as colorInput,oi as copyText,Ai as dateTime,Ei as directionField,Bi as edgePad,ai as entriesHiddenForTab,ki as focalPicker,zi as focusAfterRemove,Z as foldMetaOf,el as galleryLayoutField,fi as gapField,C as group,Oi as heightFields,pe as hidableText,uo as hintIsWhileTyping,V as iconOf,Qi as imageCornersField,ui as isBucketHeader,to as isNoGlyph,ri as linkField,Gi as multiSelect,eo as noGlyph,Fi as pageBackgroundField,si as panelNote,ko as phoneOverrideField,Di as placementField,po as plainText,ii as plainTextarea,$ as pxField,de as readHidable,Uo as rowText,Mi as searchSelect,ci as section,gi as sectionAnimationFields,xo as sectionCornerSidesField,So as sectionCornersField,hi as sectionShapeFields,mi as sectionThemeFields,ce as segmented,L as select,Ko as setRowText,Ti as sizeField,H as slider,$i as sourceField,Li as spacingFields,ti as text,Ze as textFieldIdentifier,Zr as textFieldOffPage,Yi as textList,ji as textListRowField,ni as textarea,O as toggle,Ui as upload,no as usePageWidthDetail,oo as useSiteGapDetail,vi as widthField,Qr as withIdentifier,Jr as withOffPage,qr as withScaffold};
1
+ "use client";import{jsx as r,jsxs as y,Fragment as E}from"react/jsx-runtime";import{cloneElement as qe,useId as Je,useRef as q,useState as ue}from"react";import{useEasel as N}from"efficient-easel/easel";import{readHidable as de,hidableText as pe}from"./hidable.js";import{FOLD_FIELD_MARKER as J,LINK_FIELD_MARKER as me,MEDIA_FIELD_MARKER as fe,SCAFFOLD_FIELD_MARKER as he,TEXT_FIELD_MARKER as T,foldMetaOf as Z,textFieldIdentifier as Ze}from"./field-markers.js";import Qe from"../../components/ApplyCornersToSiblings.js";import{CARD_IMAGE_RADIUS_STEP as et,CORNER_RADIUS_MAX as W,CORNER_RADIUS_MIN as B}from"../content/card-image-shape.js";import{IMAGE_CORNER_STEP as tt,IMAGE_CORNERS_LABEL as nt}from"../content/image-corners.js";import{GRID_MAX_COLUMNS as ot}from"../content/grid-span.js";import{GALLERY_ACROSS_BUCKETS as rt,GALLERY_LAYOUTS as A,GALLERY_LAYOUT_KEYS as ge}from"../content/gallery-layout.js";import{anchorSiblingsOf as it,HERO_GROUP_PLACEMENTS as lt,HERO_GROUP_PLACEMENT_DEFAULT as at,normalisePlacement as st,placementPoints as be}from"../hero-group-placement.js";import ct from"../../components/KeepHint.js";import{AlignLeftIcon as ut,AlignSeparateIcon as dt,AnimationIcon as xe,BackgroundIcon as pt,BlockSectionIcon as mt,CartIcon as ft,ColumnWidthsIcon as Ce,ColumnsIcon as ht,CornerIcon as Se,DirectionDownIcon as gt,DirectionLeftIcon as bt,DirectionRightIcon as xt,DirectionUpIcon as Ct,DollarIcon as St,FinishIcon as It,GapIcon as Ie,GridIcon as _t,GroundIcon as yt,HashIcon as _e,ImageIcon as Et,LayoutIcon as Tt,ListIcon as Rt,LocationIcon as Q,PaddingBottomIcon as Lt,PaddingLeftIcon as vt,PaddingRightIcon as Ot,PaddingTopIcon as Nt,PageIcon as ye,PhoneIcon as At,PlacementIcon as Ft,ProductSizeIcon as Pt,RotateIcon as wt,SquareIcon as kt,StylesIcon as Dt,TextLinesIcon as Ht,TypeIcon as Bt,WidthIcon as Gt,WrapIcon as Mt}from"efficient-easel/icons";import{FieldGlyph as Ee}from"../../components/FieldGlyph.js";import{resolvePageBackground as $t}from"../content/page-background.js";import{CORNER_SIDES as F,CORNER_SIDE_POINTS as ee,CORNER_SIDES_LABEL as P,cornerSidesSummary as Te,hasOwnSectionCorners as Wt,normalizeCornerSides as U}from"../content/section-corners.js";import{hasOwnCardCorners as Ut}from"../content/card-corners.js";import{SECTION_MOTION_NONE as Kt,SECTION_MOTION_OPTIONS as Xt}from"../content/section-animation.js";import{enclosingSectionProps as Re}from"./enclosing-section.js";import{SettingsCorners as Le,SettingsDefaultReset as g,SettingsField as f,SettingsGroupHead as zt,SettingsGroupSub as Vt,SettingsPlacement as Yt,SettingsSegmented as jt,SettingsSwitch as qt}from"efficient-easel/panel";import{FieldSelect as Jt,ListField as Zt}from"efficient-easel/fields";import{Checkbox as Qt,DateTimePicker as en,FOCAL_DEFAULT as ve,Slider as tn,Tooltip as K}from"efficient-shell/ui";import{ColourControl as Oe}from"./ColourControl.js";import Ne from"./MarkupToolbar.js";import{deviceField as R}from"./device-fields.js";import{noControlField as nn}from"./panel-no-control-mark.js";import{phoneKey as X,resolvePhoneValue as te}from"./phone-override.js";import{SuppressibleText as on}from"./section-text-suppress.js";import{CARD_INDEX_OPTIONS as rn,CARD_OUTLINE_OPTIONS as ln,DEFAULT_CARD_INDEX_FORMAT as an,DEFAULT_CARD_OUTLINE as sn}from"../sections/product-card-style.js";import{COVER_INDEX_OPTIONS as cn,DEFAULT_COVER_INDEX as un}from"../sections/card-cover-index.js";import{SCALAR_TEXT_CONTROLS as dn}from"./text-control-kinds.js";import pn from"../../components/ImageFocusRow.js";import mn from"../../components/MediaUploadField.js";import fn from"../../components/MultiSelectField.js";import hn from"../../components/SectionThemePicker.js";import gn from"../../components/SearchSelectField.js";import bn from"../../components/StorefrontLinkField.js";import Ae from"../../components/UiIcon.js";import{SECTION_PADDING as S}from"../content/section-padding.js";import{hasPhoneHeight as xn,resolveSectionMinHeight as Cn}from"../content/section-min-height.js";import{VIEW_TIER_LABEL as ne}from"../content/view-tiers.js";import{SECTION_MIN_HEIGHT as Sn,SECTION_MIN_HEIGHT_GROUP_LABEL as G,SECTION_SCREEN_PCT as In}from"../content/section-min-height.js";import{CONTAINER_DIRECTION_LABEL as _n,containerDirectionPoints as yn,resolveContainerDirection as Fe}from"../content/container-direction.js";import{BOX_ALIGN_POINTS as En,BOX_BLOCK_SPACING_LABEL as Tn,BOX_BLOCK_SPACING_POINTS as Pe,BOX_JUSTIFY_POINTS as we,BOX_PHONE_ROW_LABEL as Rn,BOX_PHONE_ROW_MAX as Ln,BOX_PHONE_ROW_MIN as ke,BOX_SHARE_LABEL as De,BOX_SHARE_POINTS as oe,BOX_WRAP_LABEL as vn,BOX_WRAP_POINTS as He}from"../content/box-layout.js";import{usePreviewHeader as z}from"../../components/PreviewHeaderContext.js";import{CONTAINER_GAP as re,CONTAINER_GAP_BUILT_IN as On,GAP_FIELD_CONTAINER as Nn,hasOwnContainerGap as An,resolveContainerGap as Fn}from"../content/container-gap.js";import{CARD_IMAGE_BG_INHERIT as Pn,CARD_IMAGE_BG_OFF as wn,CARD_IMAGE_BG_SWATCH_NAMES as kn,CARD_IMAGE_BG_SWATCHES as Dn,isCardImageBackgroundInheriting as Hn,cardImageBackgroundChoice as Bn,THEME_CARD_IMAGE_BG as Gn}from"../content/card-image-background.js";import{SECTION_BG_INHERIT as Mn,SECTION_BG_SWATCHES as $n,SECTION_BG_SWATCH_NAMES as Wn,THEME_SECTION_BG as Un,isSectionBackgroundInheriting as Kn}from"../content/section-background.js";import{SECTION_THEME_GROUP_LABEL as Xn}from"../content/section-surface.js";import{TYPE_SIZE_FIXED as zn,TYPE_SIZE_INHERIT as Vn,isTypeSizeInheriting as Yn}from"../content/section-type-size.js";import{SECTION_WIDTH_CHOICES as jn,WIDTH_CHOICE_LABEL as qn,WIDTH_INHERIT as Jn,resolveWidth as Zn,sectionRunsFullWidth as Be}from"../content/section-width.js";import{useFoldHeadingLevel as Ge}from"./panel-heading-scope.js";import{withStyleKind as Qn}from"efficient-easel/style-clipboard";function M(e){for(const[t,n]of Object.entries(e))n&&typeof n=="object"&&!Z(n)&&Qn(n,`section:${t}`);return e}function Yr({children:e}){return r("div",{className:"sf-field-label",children:e})}function Me(){return null}function eo(e){if(!e.trim())throw new Error("noGlyph() needs a reason naming the ruling that decided it.");return r(Me,{},e)}function to(e){return e.type===Me}function V(e){return to(e)?void 0:e}function w(e,t){return`${e} from ${t}`}function no(){const{appState:e}=N(i=>i),t=e.data.root?.props??{},{mode:n,pageWidth:o}=Zn(t,"full");return w(n==="page"?`${o}px`:n==="contained"?"Contained":"Full","the page")}function oo(){const{blockGap:e}=z();return e===null?"this container's own spacing":w(`${e}px`,"Site styles")}function ro({inherited:e,onReset:t,label:n}){return r(g,{label:n,changed:!e,detail:oo(),onReset:t})}function io({inherited:e,onReset:t,label:n}){return r(g,{label:n,changed:!e,detail:no(),onReset:t})}function k({value:e,onChange:t,label:n,placeholder:o,hint:i,multiline:l,hideable:a=!0,markup:s=!0}){const{text:c,hidden:d}=de(e),m=q(null),u=q(null),p=_=>t(a?{text:_,hidden:d}:_),h=()=>t({text:c,hidden:!d}),b=a&&d,I=Je(),x=i?uo(i)?r("span",{className:"sf-hint-keep sf-hint-while-typing",children:i}):r(ct,{children:i}):void 0;return r(f,{label:n,icon:r(Bt,{}),htmlFor:I,className:b?"is-hidden":void 0,hint:x,action:a?r(K,{content:d?`Show ${n} on the slide`:`Hide ${n} on the slide`,children:r("button",{type:"button",className:"sf-field-eye","aria-pressed":d,"aria-label":d?`Show ${n} on the slide`:`Hide ${n} on the slide`,onClick:h,children:d?r(Ae,{name:"eye-off",size:14}):r(Ae,{name:"eye",size:14})})}):void 0,children:y("div",{className:"sf-copybox",children:[s&&r(Ne,{target:l?u:m,value:c,onChange:p}),l?r("textarea",{id:I,ref:u,value:c,placeholder:o,onChange:_=>p(_.target.value)}):r("input",{id:I,ref:m,type:"text",value:c,placeholder:o,onChange:_=>p(_.target.value)})]})})}function jr(e,t){return{...e,[he]:t}}function qr(e){const t=e[T];if(!t)throw new Error("withOffPage: the field holds no authored text");return{...e,[T]:{...t,offPage:!0}}}function Jr(e){return!e||typeof e!="object"?!1:e[T]?.offPage===!0}function Zr(e){const t=e[T];if(!t)throw new Error("withIdentifier: the field holds no authored text");return{...e,[T]:{...t,identifier:!0}}}import{TEXT_CONTROL_KINDS as nl,SCALAR_TEXT_CONTROLS as ol}from"./text-control-kinds.js";const lo=new Set(dn),D=(e,t)=>{const n={...t,[T]:e};if(!lo.has(e.control))return n;const o=t.render;return{...nn(n,"authored-copy"),render:i=>r(on,{name:i.name,children:o(i)})}},Qr="Everything else on this block comes from the linked post. Unlink it to edit by hand.",ao="Select a word, then press the highlighter.",so="A short name so a link can jump straight to this section, like yoursite.com/page#about.",co=new Set([ao]),uo=e=>co.has(e);function ei(e,t,n){return D({control:"text",label:e,placeholder:t,hint:n},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:e,placeholder:t,hint:n})})}function ti(e,t,n){return D({control:"textarea",label:e,placeholder:t,hint:n},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:e,placeholder:t,hint:n,multiline:!0})})}function po(e,t,n){return D({control:"plainText",label:e,placeholder:t,hint:n},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:e,placeholder:t,hint:n,hideable:!1,markup:!1})})}function ni(e,t,n){return D({control:"copyText",label:e,placeholder:t,hint:n},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:e,placeholder:t,hint:n,hideable:!1})})}function oi(e){return{type:"custom",[me]:{label:e},render:({value:t,onChange:n})=>r(bn,{value:pe(t),onChange:n,label:e})}}function ri(e,t,n){return D({control:"plainTextarea",label:e,placeholder:t,hint:n},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:e,placeholder:t,hint:n,multiline:!0,hideable:!1})})}const ii={Content:Ht,Style:Dt,Layout:Tt,Animation:xe};function li(e,t){return e.includes("Content")?t!=="Content":null}function mo({label:e}){return r(zt,{title:e,level:Ge(1)})}function fo({level:e,label:t}){return e===1?r(mo,{label:t}):r(go,{label:t})}function $e(e,t){return{type:"custom",[J]:{label:e,level:t},render:()=>r(fo,{level:t,label:e})}}function C(e){return $e(e,2)}function ai(e){return{type:"custom",render:()=>r(ho,{text:e})}}function ho({text:e}){return r("p",{className:"sf-note",children:e})}function si(e){return $e(e,1)}function ci(e){return Z(e)!==null&&e?.tabs!==void 0}const We=new Map;function ui(e,t){const n=`${e}\0${t?t.join(""):""}`,o=We.get(n)??{type:"custom",tabs:t,[J]:{label:e,level:1},bucket:e,marker:!0,render:()=>r(E,{})};return We.set(n,o),o}function go({label:e}){return r(Vt,{title:e,level:Ge(2)})}function Ue({swatches:e,current:t,onPick:n,names:o}){const i=e.find(a=>a.toLowerCase()===t.toLowerCase()),l=(i?o?.[i]:void 0)??t;return y("div",{className:"sf-swatches",children:[e.map(a=>{const s=o?.[a]??a;return r(K,{content:s,children:r("button",{type:"button","aria-pressed":t.toLowerCase()===a.toLowerCase(),className:`sf-swatch ${t.toLowerCase()===a.toLowerCase()?"is-active":""}`,style:{background:a},onClick:()=>n(a),"aria-label":s})},a)}),r("span",{className:"sf-swatch-hex",children:l})]})}function di(e,t){return{type:"custom",render:({value:n,onChange:o})=>{const i=Kn(n,t);return r(f,{label:e,icon:r(pt,{}),changed:!i,action:r(g,{label:e,changed:!i,detail:"the theme's section background",onReset:()=>o(Mn)}),children:Ue({swatches:$n,current:i?Un:n??t??"",onPick:o,names:Wn})})}}}function bo(e,t){return{type:"custom",render:({value:n,onChange:o})=>{const i=n,l=Hn(i,t);return r(f,{label:e,icon:r(yt,{}),changed:!l,action:r(g,{label:e,changed:!l,detail:"the theme's image stage",onReset:()=>o(Pn)}),children:Ue({swatches:Dn,current:l?Gn:Bn(i,t),onPick:o,names:kn})})}}}function pi(e=n=>n,t){return M({_gSectionTheme:C(Xn),sectionAccent:{type:"custom",render:({value:n,onChange:o})=>r(hn,{value:e(n),onChange:o,followLabel:t})}})}function v({min:e,max:t,step:n,value:o,onChange:i,suffix:l="",readout:a=!0,notch:s,ariaLabel:c,disabled:d=!1}){const m=s!==void 0&&Number.isFinite(s)&&s>=e&&s<=t;return r("div",{className:m?"sf-slider has-notch":"sf-slider",style:m?{"--sf-notch":(s-e)/(t-e)}:void 0,children:r(tn,{min:e,max:t,step:n,value:o,suffix:l||void 0,showInput:a,label:c,disabled:d,size:"sm",className:"sf-slider-track",onChange:u=>{u!==null&&u!==o&&i(u)}})})}function H(e,t,n,o,i,l,a="",s){return{type:"custom",render:c=>r(f,{label:e,icon:V(t),action:s?s("storedValue"in c?c.storedValue:c.value,c.onChange):void 0,children:v({min:n,max:o,step:i,value:typeof c.value=="number"?c.value:l,suffix:a,ariaLabel:e,onChange:c.onChange})})}}function Ke({min:e,max:t,step:n,px:o,label:i,onChange:l,disabled:a=!1}){const{cornerRadiusPx:s}=z();return r(E,{children:v({min:e,max:t,step:n,value:o??(typeof s=="number"?s:e),readout:!1,ariaLabel:i,disabled:a,onChange:l})})}function $(e,t){const{min:n,max:o,step:i=1,unsetLabel:l,hint:a,restAtSite:s=!1,restTrack:c,unsetMark:d}=t;return{type:"custom",render:({value:m,onChange:u})=>{const p=typeof m=="number"?m:null,h=p===null;return r(f,{label:e,value:h?d?void 0:l:`${p}px`,changed:!h,action:d?qe(d,{changed:!h,onReset:()=>u(null)}):r(g,{label:e,changed:!h,onReset:()=>u(null)}),hint:a,children:c?c({min:n,max:o,step:i,px:p,label:e,onChange:u}):s?r(Ke,{min:n,max:o,step:i,px:p,label:e,onChange:u}):v({min:n,max:o,step:i,value:p??n,readout:!1,ariaLabel:e,onChange:u})})}}}function mi(e){const t=H("Gap",r(Ie,{}),re.min,re.max,re.step,On[e],"px",(n,o)=>r(ro,{inherited:!An(e,n),onReset:()=>o(void 0),label:"Gap"}));return{type:"custom",[Nn]:e,render:n=>t.render({...n,value:Fn(e,n.value,n.field?.siteGap),storedValue:n.value,onChange:o=>n.onChange(o)})}}function xo(){return{type:"custom",render:({value:e,onChange:t})=>{const o=U(e)??[...F],i=o.length===F.length;return r(f,{label:P,icon:r(Se,{}),value:Te(o),changed:!i,action:r(g,{label:P,changed:!i,onReset:()=>t(null)}),hint:"Corners left off stay square. The row above sets how round the others are.",children:r(yo,{value:o,onChange:l=>{const a=U(l)??[];t(a.length===F.length?null:a)}})})}}}function Co({label:e,changed:t=!1,onReset:n=()=>{}}){const{cornerRadiusPx:o}=z(),i=typeof o=="number"?`${o}px`:"not set";return r(g,{label:e,changed:t,detail:o==null?"the built-in corners":w(i,"Site styles"),onReset:n})}function So(){return $("Corners",{min:B,max:W,unsetLabel:"Follows the site",unsetMark:r(Co,{label:"Corners"}),restTrack:e=>r(Io,{...e}),hint:r(_o,{})})}const Xe="This section runs edge to edge, so its corners sit off the page. Set Width to Content width to use them.";function ie(){return Be(Y())}function Io(e){return r(Ke,{...e,disabled:ie()})}function _o(){return r(E,{children:ie()?Xe:"Follows Site styles ▸ Basics ▸ Corners until you set a number here."})}function yo({value:e,onChange:t}){const n=ie();return r(Le,{label:P,value:e,corners:n?ee.map(o=>({...o,disabled:!0,title:Xe})):ee,onChange:t})}function fi(){return M({_gShape:C("Shape"),sectionCorners:So(),sectionCornerSides:xo()})}function hi(){return{_gMotion:C("Motion"),sectionAnimation:ce("Entrance",r(xe,{}),[...Xt],Kt)}}function le(){let e=null;try{const{appState:t,selectedItem:n}=N(i=>i),o=n?.props?.id?String(n.props.id):void 0;e=o?Re(t?.data,o):null}catch{e=null}return e!==null&&Be(e)}function ze(e){const{cornerRadiusPx:t}=z(),n=le(),o=typeof t=="number"?t:e;let i=null;try{const{appState:a,selectedItem:s}=N(d=>d),c=s?.props?.id?String(s.props.id):void 0;i=c?Re(a?.data,c):null}catch{i=null}if(n||!i)return o;const l=i.sectionCorners;return Wt(l)?l:o}function Eo({min:e,max:t,step:n,px:o,label:i,onChange:l}){const a=ze(e);return r(E,{children:v({min:e,max:t,step:n,value:o??a,readout:!1,ariaLabel:i,onChange:l})})}function To({label:e,changed:t=!1,onReset:n=()=>{}}){const o=le(),i=ze(B),l=o?"Site":"Section";return r(g,{label:e,changed:t,detail:w(`${i}px`,o?"Site styles":"the section"),onReset:n})}function Ro(){return r(E,{children:le()?"The section is full width, so this card follows Site styles ▸ Basics ▸ Corners.":"Follows the section's Corners until you set a number here."})}function Lo(){return $("Corners",{min:B,max:W,unsetLabel:"Follows the section",unsetMark:r(To,{label:"Corners"}),restTrack:e=>r(Eo,{...e}),hint:r(Ro,{})})}function vo({value:e,onChange:t}){return r(Le,{label:P,value:e,corners:ee,onChange:t})}function Oo({unset:e}){return r(E,{children:e?"Set a number above first — there is nothing to shape yet.":"Corners left off stay square. The row above sets how round the others are."})}function No(){return{type:"custom",render:({value:e,onChange:t})=>{const o=U(e)??[...F],i=o.length===F.length;return r(f,{label:P,icon:r(Se,{}),value:Te(o),changed:!i,action:r(g,{label:P,changed:!i,onReset:()=>t(null)}),hint:r(Oo,{unset:!Ut(e)}),children:r(vo,{value:o,onChange:l=>{const a=U(l)??[];t(a.length===F.length?null:a)}})})}}}function Ao(){return{type:"custom",render:()=>r(Qe,{})}}function gi(){return{_gShape:C("Shape"),cardCorners:Lo(),cardCornerSides:No(),cardCornersApplyAll:Ao()}}function bi(){return L("Justify",r(dt,{}),we,we[0].value)}function xi(){return L("Item alignment",r(ut,{}),En,"stretch")}function Ci(){return L(vn,r(Mt,{}),He,He[0].value)}function Si(){return{type:"custom",render:({value:e,onChange:t})=>{const n=oe.find(o=>o.value===e)??oe[0];return r(f,{label:De,icon:r(Ce,{}),value:n.label,children:r("div",{className:"sf-gallery-layouts",role:"group","aria-label":De,children:oe.map(o=>r(K,{content:o.label,className:"sf-tile-tip",children:r("button",{type:"button","aria-pressed":n.value===o.value,"aria-label":o.label,onClick:()=>t(o.value),children:r("span",{className:"sf-gallery-pic",children:Fo(o.weights).map((i,l)=>r("i",{style:{gridColumn:`span ${i}`}},l))})})},o.value))})})}}}function Fo(e){if(!e)return[3,4];const t=e.reduce((n,o)=>n+o,0);return e.map(n=>Math.round(n/t*12))}function Ii(){return L(Tn,r(Ie,{}),Pe,Pe[0].value)}function _i(){return H(Rn,r(At,{}),ke,Ln,1,ke)}function yi(e){const t=ce(_n,eo("`Direction` names how a container's children run — a MODIFIER, not a thing. doc/naming.md N10.1 gives the idea a dash in its Glyph column; editor-shell's own `direction` meaning says the bare row is CORRECT and not an omission (SS seat, 2026-09-11)."),yn(e),Fe(e,void 0));return{type:"custom",render:n=>t.render({...n,value:Fe(e,n.value),onChange:o=>n.onChange(o)})}}function Ei(e,t,n,o,i,l){return{type:"custom",render:({value:a,onChange:s})=>r(f,{label:e,icon:r(Ee,{noun:l}),action:r(g,{label:e,changed:!Yn(a),detail:"the Text style in Site styles",onReset:()=>s(Vn),defaultAction:{onPress:()=>s(zn),title:"Keep this section's own built-in size",icon:r(mt,{})}}),children:v({min:t,max:n,step:o,value:typeof a=="number"?a:i,suffix:"px",ariaLabel:e,onChange:s})})}}function Ti(){return{_gCellWidth:C("Cell width"),gridSpan:L("Positions",r(Ce,{}),[{label:"Auto",value:""},...Array.from({length:ot},(e,t)=>({label:t===0?"1 position":`${t+1} positions`,value:String(t+1)}))],"")}}function Y(){let e=null;try{e=N(t=>t).selectedItem}catch{e=null}return e?.props??{}}function Po({min:e,max:t,step:n,px:o,label:i,onChange:l,desktopKey:a,fallback:s}){const c=Y()[a],d=te(void 0,c,s);return r(E,{children:v({min:e,max:t,step:n,value:te(o,c,s),readout:!1,ariaLabel:i,notch:d,onChange:l})})}function wo({label:e,desktopKey:t,fallback:n,changed:o=!1,onReset:i=()=>{}}){const l=Y()[t],a=te(void 0,l,n);return r(g,{label:e,changed:o,detail:`${a}px on ${ne.desktop.toLowerCase()}`,onReset:i})}function ko(e){return $(e.label,{min:e.min,max:e.max,step:e.step,unsetLabel:`Follows ${ne.desktop}`,unsetMark:r(wo,{label:e.label,desktopKey:e.desktopKey,fallback:e.fallback}),restTrack:t=>r(Po,{...t,desktopKey:e.desktopKey,fallback:e.fallback})})}function Ri(e={}){const t=e.keys?.top??"sectionPaddingTop",n=e.keys?.bottom??"sectionPaddingBottom",o=e.group!==!1,i=x=>o?x:`Padding ${x.toLowerCase()}`,l=x=>H(i("Top"),r(Nt,{}),S.min,S.max,S.step,x,"px"),a=(x,_,je,j=S)=>R("mobile",ko({label:i(x),desktopKey:_,min:j.min,max:j.max,step:j.step,fallback:je})),s=e.top??S.min,c=e.bottom??S.min,d="sectionPaddingLeft",m="sectionPaddingRight",u=e.sideBounds??S,p=e.side??u.min,h=e.sidePhone??p,b=e.phone===!0,I=x=>b?R("desktop",x):x;return M({...o?{_gSpacing:C("Padding")}:{},[t]:I(l(s)),...b?{[X(t)]:a("Top",t,s)}:{},...e.only==="top"?{}:{[n]:I(H(i("Bottom"),r(Lt,{}),S.min,S.max,S.step,c,"px")),...b?{[X(n)]:a("Bottom",n,c)}:{}},...e.sides?{[d]:I(H(i("Left"),r(vt,{}),u.min,u.max,u.step,p,"px")),...b?{[X(d)]:a("Left",d,h,u)}:{},[m]:I(H(i("Right"),r(Ot,{}),u.min,u.max,u.step,p,"px")),...b?{[X(m)]:a("Right",m,h,u)}:{}}:{}})}const Do={contained:"Contained",page:"Page",full:"Full"},ae="Width";function Li(e,t=jn,n=!0){const o=t.map(i=>({label:qn[i]??Do[i],value:i}));return M({...n?{_gWidth:C(ae)}:{},widthMode:{type:"custom",render:({onChange:i,field:l})=>r(f,{label:"Width",icon:r(Gt,{}),action:n?r(io,{inherited:l?.inherited??!1,onReset:()=>i(Jn),label:ae}):void 0,children:se({options:o,value:l?.currentValue||e,onChange:i,ariaLabel:ae})})}})}function vi(){const e=o=>({type:"custom",render:({value:i,onChange:l})=>y("div",{className:"sf-field",children:[o?y("div",{className:"sf-field-head",children:[r("span",{className:"sf-field-label sf-field-label--inline",children:G}),o(l)]}):null,r("div",{children:se({options:[{label:"Auto",value:"auto"},{label:"Fixed",value:"fixed"},{label:"Screen",value:"screen"}],value:["auto","fixed","screen"].includes(i)?i:"auto",onChange:l,ariaLabel:G})})]})}),t=()=>({type:"custom",render:({value:o,onChange:i,field:l})=>{const a=l?.unit==="%"?"%":"px",s=a==="%"?In:Sn;return r("div",{className:"sf-field",children:v({min:s.min,max:s.max,step:s.step,value:typeof o=="number"?o:s.fallback,suffix:a,ariaLabel:G,onChange:i})})}}),n=()=>ce("Unit",r(_e,{}),[{label:"px",value:"px"},{label:"%",value:"%"}],"px");return M({_gHeight:C(G),sectionHeightMode:R("desktop",e()),sectionHeightValue:R("desktop",t()),sectionHeightUnit:R("desktop",n()),sectionHeightModePhone:R("mobile",e(o=>r(Ho,{onClear:()=>o(void 0)}))),sectionHeightValuePhone:R("mobile",t()),sectionHeightUnitPhone:R("mobile",n())})}function Ho({onClear:e}){const t=Y(),n=xn(t),o=Cn(t),i=`${o.mode==="auto"?"Auto":`${o.value}${o.unit}`} on ${ne.desktop.toLowerCase()}`;return r(g,{label:G,changed:n,detail:i,onReset:e})}function Oi(){return{_gAnchor:C("Anchor"),anchor:po("Anchor name","e.g. about",so)}}function Ni(e,t,n){return{type:"custom",render:({value:o,onChange:i,id:l,name:a})=>{const s=`${l??a??e}-datetime`,c=Date.parse(typeof o=="string"?o:"");return r(f,{label:e,icon:t,htmlFor:s,hint:n,children:r(en,{id:s,value:Number.isFinite(c)?new Date(c):null,onChange:d=>i(d?d.toISOString():"")})})}}}function O(e,t,n){return{type:"custom",render:({value:o,onChange:i,id:l,name:a})=>{const s=typeof o=="boolean"?o:t,c=`${l??a??e}-label`;return r(f,{label:e,labelId:c,icon:n,action:r(qt,{checked:s,onChange:i,ariaLabelledBy:c})})}}}function Ai(){return{type:"custom",render:({value:e,onChange:t,id:n,name:o})=>{const i=`${String(n??o??"pageBackground")}-colour`;return r(f,{label:"Background",icon:r(ye,{}),htmlFor:i,action:r(Oe,{id:i,label:"Background",value:$t(e),onChange:t})})}}}function Fi(e,t){return{type:"custom",render:({value:n,onChange:o,id:i})=>{const l=typeof n=="boolean"?n:t,a=`${i??e}-checkbox`;return r(f,{label:e,htmlFor:a,className:"sf-checkbox",action:r(Qt,{id:a,checked:l,onChange:o})})}}}function Pi(e,t){return{type:"custom",render:({value:n,onChange:o})=>r(f,{label:e,action:Oe({value:n||t,onChange:o,label:e})})}}const Bo=[{value:"0% 0%",label:"Top left"},{value:"50% 0%",label:"Top"},{value:"100% 0%",label:"Top right"},{value:"0% 50%",label:"Left"},{value:"50% 50%",label:"Center"},{value:"100% 50%",label:"Right"},{value:"0% 100%",label:"Bottom left"},{value:"50% 100%",label:"Bottom"},{value:"100% 100%",label:"Bottom right"}];function Ve({label:e,value:t,onChange:n,points:o=Bo}){return r(Yt,{label:e,value:t,points:o,onChange:n})}function wi(e,t=ve,n="mediaImage"){return{type:"custom",render:({value:o,onChange:i})=>r("div",{className:"sf-focal-row",children:r(Go,{label:e,value:o||t,onChange:i,imageProp:n})})}}function Go({label:e,value:t,onChange:n,imageProp:o}){const{selectedItem:i}=N(a=>a),l=i?.props?.[o];return r(pn,{label:e,value:t,onChange:n,image:typeof l=="string"?l:void 0})}const Mo=be([]);function ki(e,{stacking:t,fallback:n=at}){return{type:"custom",render:({value:o,onChange:i})=>{const l=lt.includes(o)?o:n;return t?r($o,{label:e,value:l,onChange:i}):Ye({label:e,value:l,onChange:i,points:Mo})}}}function $o({label:e,value:t,onChange:n}){const{appState:o,selectedItem:i}=N(s=>s),l=i?.props?.id?String(i.props.id):void 0,a=l?it(o?.data,l):[];return Ye({label:e,value:t,onChange:n,points:be(a,l)})}function Ye({label:e,value:t,onChange:n,points:o}){const i=o.find(l=>l.disabled);return r(f,{label:e,icon:r(Ft,{}),hint:i?i.title:void 0,children:Ve({label:e,value:st(t),onChange:n,points:o})})}const Di={top:r(Ct,{}),right:r(xt,{}),bottom:r(gt,{}),left:r(bt,{})};function Hi(e,t,n,o,i,l){const a=m=>t.find(u=>u.value===m),s=m=>({value:m,label:"",disabled:!0,title:o}),c=m=>{const u=t.find(h=>h.cell===m);if(!u)return s(`missing-${m}`);const p=l?.[m];return p?{value:u.value,label:u.label,icon:p}:{value:u.value,label:u.label}},d=[s("corner-top-left"),c("top"),s("corner-top-right"),c("left"),s("centre"),c("right"),s("corner-bottom-left"),c("bottom"),s("corner-bottom-right")];return{type:"custom",render:({value:m,onChange:u})=>{const p=t.some(h=>h.value===m)?m:n;return r(f,{label:e,icon:i,value:a(p)?.label??"",children:Ve({label:e,value:p,onChange:u,points:d})})}}}const Wo="\0note";function L(e,t,n,o,i){return{type:"custom",options:n,fallback:o,...i?{note:i}:{},render:({value:l,onChange:a,field:s})=>{const c=s.options??n,d=s.fallback??o,m=c.some(u=>u.value===l)?l:d;return r(f,{label:e,icon:V(t),children:r(Jt,{value:m,ariaLabel:e,onChange:a,options:[...i?[{label:i,value:Wo,disabled:!0}]:[],...c.map(u=>({label:u.label,value:u.value}))]})})}}}function Bi(e,t,n){return{type:"custom",options:t,render:({value:o,onChange:i,field:l})=>r(fn,{label:e,options:l.options??t,value:Array.isArray(o)?o:[],onChange:i,...n?{emptyLabel:n}:{}})}}function Gi(e,t,n,o){return{type:"custom",options:t,fallback:n,render:({value:i,onChange:l,field:a})=>r(gn,{label:e,options:a.options??t,fallback:a.fallback??n,value:i,onChange:l,placeholder:o})}}function Mi(e,t={}){return{type:"custom",render:({value:n,onChange:o})=>{const i={value:n,onChange:o,...t};return r(e,{...i})}}}function se({options:e,value:t,onChange:n,ariaLabel:o,disabled:i=!1}){return r(jt,{options:e.map(l=>({id:l.value,label:l.label,title:l.title})),value:t,onChange:n,ariaLabel:o,disabled:i})}const $i=[{label:"Image",value:"image"},{label:"Video",value:"video"}];function ce(e,t,n,o){const i=n.map(l=>typeof l=="string"?{label:l,value:l}:l);return{type:"custom",render:({value:l,onChange:a,field:s})=>r(f,{label:e,icon:V(t),children:se({options:i,value:i.some(c=>c.value===l)?l:l||s?.currentValue||o,onChange:a,ariaLabel:e})})}}function Wi(e,t,n){return{type:"custom",[fe]:!0,render:({value:o,onChange:i})=>r(mn,{value:o||"",onChange:i,label:e,accept:t,placeholder:n})}}const Ui={HeroSingle:["imageFocal"],ContactLocations:["locations[].photo"],ProcessSteps:["steps[].image"]};function Ki({value:e,onChange:t,label:n}){const o=e||{},i=!!o.pending,l=i?"var(--fg-dim, #888)":o.ok?"#1d9e75":"#d85a30",a=(s,c)=>t({...o,[s]:c===""?void 0:Number(c)});return y(f,{label:n,icon:r(Q,{}),children:[r("button",{type:"button",disabled:i,onClick:()=>t({...o,pending:!0,ok:!1,status:"Finding…"}),style:{width:"100%",display:"flex",alignItems:"center",justifyContent:"center",gap:6,padding:"8px 10px",fontSize:13,cursor:i?"default":"pointer",opacity:i?.6:1,border:"1px solid var(--border-strong, #ccc)",borderRadius:6,background:"transparent",color:"inherit"},children:i?"Finding…":"Find coordinates"}),o.status&&r("div",{style:{marginTop:6,fontSize:12,lineHeight:1.4,color:l},children:o.status}),r("div",{style:{marginTop:6,fontSize:11,color:"var(--fg-dim, #999)"},children:"Coordinates from OpenStreetMap"}),r("button",{type:"button",onClick:()=>t({...o,manual:!o.manual}),style:{marginTop:8,padding:0,border:"none",background:"none",font:"inherit",fontSize:12,color:"var(--sf-accent, #2563eb)",cursor:"pointer",textDecoration:"underline"},children:o.manual?"Hide manual coordinates":"Enter coordinates manually"}),o.manual&&y("div",{style:{marginTop:8,display:"grid",gap:8},children:[r(f,{label:"Latitude",icon:r(Q,{}),children:r("input",{type:"number",step:"any",placeholder:"e.g. 34.0990198",value:typeof o.lat=="number"?o.lat:"",onChange:s=>a("lat",s.target.value)})}),r(f,{label:"Longitude",icon:r(Q,{}),children:r("input",{type:"number",step:"any",placeholder:"e.g. -117.9842833",value:typeof o.lng=="number"?o.lng:"",onChange:s=>a("lng",s.target.value)})})]})]})}function Uo(e,t){return t===null||t<0||t>=e.length?"":e[t]?.text??""}function Ko(e,t,n){const o=e.map(i=>({text:i?.text??""}));return t===null||t<0||t>=e.length?o:o.map((i,l)=>l===t?{text:n}:i)}function Xi(e,t){return e===null?null:t>e?e:null}function Xo(e,t,n){if(n===null||n>=t.length)return null;for(let o=0;o<n;o+=1)if(e[o]!==t[o])return null;return e[n]!==t[n]&&t.includes(e[n])||e[n]!==t[n]&&t.length!==e.length?null:n}const zi={label:"Ticker items",icon:r(Rt,{})};function Vi(e,t,n,o){return{type:"custom",[T]:{control:"textList",label:e,placeholder:n,itemKey:"text",rendering:o},render:({value:i,onChange:l})=>r(zo,{label:e,icon:V(t),items:Array.isArray(i)?i:[],placeholder:n,onChange:l,markup:o==="markup"})}}function zo({label:e,icon:t,items:n,placeholder:o,onChange:i,markup:l=!1}){const a=q(null),[s,c]=ue(null),d=u=>u.map(p=>({text:p?.text??""}));return r(Zt,{label:e,icon:t,noun:"item",items:n,onChange:u=>{const p=Xo(n,u,s);p===null&&(a.current=null),c(p),i(d(u))},newItem:()=>({text:""}),open:null,onOpen:()=>{},renderItem:()=>null,above:l?r(Ne,{target:a,value:Uo(n,s),onChange:u=>i(Ko(n,s??-1,u)),disabled:s===null,label:s===null?"Formatting — click a row first":`Formatting — row ${s+1}`}):void 0,renderRow:(u,p,h)=>r("input",{type:"text",className:l&&s===p?"sf-list-marking":void 0,value:u?.text??"",placeholder:o,"aria-label":`${e} ${p+1}`,onChange:b=>h({text:b.target.value}),onFocus:b=>{a.current=b.currentTarget,c(p)}})})}function Yi(e,t){const n=`${e.label} — row ${t+1}`;return D({control:"plainText",label:n,placeholder:e.placeholder,offPage:e.offPage},{type:"custom",render:({value:o,onChange:i})=>r(k,{value:o,onChange:i,label:n,placeholder:e.placeholder,hideable:!1,markup:e.rendering==="markup"})})}function ji(e){return{_gCards:C("Cards"),coverIndex:L("Cover image",r(Et,{}),cn,String(un),e?.coverHint??"A card's opening picture — a card pinned to a finish keeps its own."),imageBackground:bo("Image background",wn),cardImage:Vo(),spinOnHover:O("Rotate on hover",e?.spinDefault??!0,r(wt,{}))}}function qi(){return{outline:L("Card outline",r(kt,{}),ln,sn),indexBadge:L("Card number",r(_e,{}),rn,an),showBadge:O("Product badge",!0,r(Ee,{noun:"tag"}))}}function Ji(e){const t=e?.bottomDefault??!0;return{_gShowOnCard:C("Show on a card"),showCardPrice:O("Price",!0,r(St,{})),showCardFinishes:O("Finish swatches",!0,r(It,{})),showCardSizes:O("Sizes",t,r(Pt,{})),showCardBuy:O("Buy button",t,r(ft,{})),showCardPage:O("Page button",t,r(ye,{}))}}function Vo(){return $("Card image",{min:B,max:W,step:et,hint:"Rounds the picture. The card's own corner is in Site styles."})}function Zi(){return $(nt,{min:B,max:W,step:tt,unsetLabel:"Square",hint:"Rounds the picture. Left alone it stays square."})}function Qi(){return{type:"custom",render:({value:e,onChange:t})=>r(Yo,{value:typeof e=="string"?e:"",onChange:t})}}function Yo({value:e,onChange:t}){const[n,o]=ue(null),i=ge.filter(a=>n===null||A[a].across===n),l=e&&e in A?A[e]:null;return y(E,{children:[r(f,{label:"Photos in a row",icon:r(ht,{}),children:y("div",{className:"sf-gallery-filter",children:[r("button",{type:"button","aria-pressed":n===null,onClick:()=>o(null),children:"All"}),rt.map(a=>r("button",{type:"button","aria-pressed":n===a,onClick:()=>o(a),children:a},a))]})}),r(f,{label:"Layout",icon:r(_t,{}),value:l?l.label:"Not chosen",hint:`${i.length} of ${ge.length} layouts`,children:r("div",{className:"sf-gallery-layouts",children:i.map(a=>r(K,{content:A[a].label,className:"sf-tile-tip",children:r("button",{type:"button","aria-pressed":e===a,"aria-label":A[a].label,onClick:()=>t(e===a?"":a),children:r("span",{className:"sf-gallery-pic",children:A[a].desktop.map(([s,c],d)=>r("i",{style:{gridColumn:`span ${s}`,gridRow:`span ${c}`}},d))})})},a))})})]})}export{so as ANCHOR_HINT,Qr as BOUND_TO_POST_NOTE,ii as BUCKET_ICONS,Ui as CUSTOM_FIELD_MEDIA,Ki as CoordsField,Di as EDGE_ARROWS,ve as FOCAL_DEFAULT,Bo as FOCAL_POINTS,J as FOLD_FIELD_MARKER,Ve as FocalPicker,go as GroupLabel,ao as HIGHLIGHT_HINT,k as HidableTextField,me as LINK_FIELD_MARKER,Yr as Label,fe as MEDIA_FIELD_MARKER,$i as MEDIA_TYPE_OPTIONS,ho as PanelNoteLine,Ye as PlacementGridView,he as SCAFFOLD_FIELD_MARKER,ol as SCALAR_TEXT_CONTROLS,Xe as SECTION_BLEEDS_HINT,mo as SectionHeading,se as Segmented,ro as SiteGapDefaultReset,v as Slider,Ue as Swatches,nl as TEXT_CONTROL_KINDS,T as TEXT_FIELD_MARKER,zi as TICKER_ITEMS_ROW,zo as TextListField,io as WidthDefaultReset,Xo as aimAfterListChange,Oi as anchorFields,w as backTo,di as backgroundField,xi as boxAlignField,Ii as boxBlockSpacingField,bi as boxJustifyField,_i as boxPhoneRowField,Si as boxShareField,Ci as boxWrapField,ui as bucketHeader,No as cardCornerSidesField,Lo as cardCornersField,bo as cardImageBackgroundField,Vo as cardImageField,ji as cardMediaFields,gi as cardShapeFields,Ji as cardShowFields,qi as cardStyleFields,Ti as cellWidthFields,Fi as checkbox,Pi as colorInput,ni as copyText,Ni as dateTime,yi as directionField,Hi as edgePad,li as entriesHiddenForTab,wi as focalPicker,Xi as focusAfterRemove,Z as foldMetaOf,Qi as galleryLayoutField,mi as gapField,C as group,vi as heightFields,pe as hidableText,uo as hintIsWhileTyping,V as iconOf,Zi as imageCornersField,ci as isBucketHeader,to as isNoGlyph,oi as linkField,Bi as multiSelect,eo as noGlyph,Ai as pageBackgroundField,ai as panelNote,ko as phoneOverrideField,ki as placementField,po as plainText,ri as plainTextarea,$ as pxField,de as readHidable,Uo as rowText,Gi as searchSelect,si as section,hi as sectionAnimationFields,xo as sectionCornerSidesField,So as sectionCornersField,fi as sectionShapeFields,pi as sectionThemeFields,ce as segmented,L as select,Ko as setRowText,Ei as sizeField,H as slider,Mi as sourceField,Ri as spacingFields,ei as text,Ze as textFieldIdentifier,Jr as textFieldOffPage,Vi as textList,Yi as textListRowField,ti as textarea,O as toggle,Wi as upload,no as usePageWidthDetail,oo as useSiteGapDetail,Li as widthField,Zr as withIdentifier,qr as withOffPage,jr as withScaffold};
@@ -4,3 +4,4 @@ export declare function setEditorPageSlug(slug: string | null): void;
4
4
  export declare function getEditorPageSlug(): string | null;
5
5
  export declare function isEditorOnDynamicPage(): boolean;
6
6
  export declare function editorTemplateProductKind(rootProps?: Record<string, unknown> | null): TemplateProductKind;
7
+ export declare function editorRecordType(rootProps?: Record<string, unknown> | null): string | null;
@@ -1 +1 @@
1
- import{PRODUCT_PAGE_SLUG as r,templateProductKind as i}from"../content/product-page.js";let e=null,n=null;function l(t,o){e=t,n=o}function d(t){l(t,null)}function a(){return e}function g(){return n==="dynamic"||e===r}function P(t){return i(e??"",t)??"alloy-wheel"}export{P as editorTemplateProductKind,a as getEditorPageSlug,g as isEditorOnDynamicPage,l as setEditorPage,d as setEditorPageSlug};
1
+ import{PRODUCT_PAGE_SLUG as n,templateProductKind as i}from"../content/product-page.js";import{declaredRecordType as l}from"../content/record-types.js";let t=null,r=null;function u(e,o){t=e,r=o}function p(e){u(e,null)}function g(){return t}function d(){return r==="dynamic"||t===n}function P(e){return i(t??"",e)??"alloy-wheel"}function f(e){return d()?l(e):null}export{f as editorRecordType,P as editorTemplateProductKind,g as getEditorPageSlug,d as isEditorOnDynamicPage,u as setEditorPage,p as setEditorPageSlug};
@@ -1,3 +1,4 @@
1
+ import { type SelectField } from "./controls.js";
1
2
  export declare function pageWidthField(): {
2
3
  type: "custom";
3
4
  render: ({ value, onChange }: {
@@ -18,7 +19,7 @@ export declare const TOP_SPACE_OPTIONS: readonly [{
18
19
  export declare const GENERAL_ROOT_FIELDS: {
19
20
  title: import("./controls.js").CustomField<import("./controls.js").HidableValue>;
20
21
  pageBackground: import("./controls.js").CustomField<string>;
21
- topSpace: import("./controls.js").SelectField;
22
+ topSpace: SelectField;
22
23
  widthChoice: {
23
24
  type: "custom";
24
25
  render: ({ value, onChange }: {
@@ -27,3 +28,5 @@ export declare const GENERAL_ROOT_FIELDS: {
27
28
  }) => import("react").JSX.Element;
28
29
  };
29
30
  };
31
+ export declare const RECORD_TYPE_LABEL = "Record type";
32
+ export declare function withRecordTypeRow(fields: Record<string, unknown>, rootProps?: Record<string, unknown> | null): Record<string, unknown>;
@@ -1 +1 @@
1
- import{jsx as o}from"react/jsx-runtime";import{PaddingTopIcon as n}from"efficient-easel/icons";import r from"../../components/WidthFollowField.js";import{pageBackgroundField as a,plainText as i,select as s}from"./controls.js";import{DEFAULT_TOP_SPACE as p}from"./header-clearance.js";function d(){return{type:"custom",render:({value:e,onChange:t})=>o(r,{value:e==="full"?"full":e==="content"?"content":void 0,resolved:"content",followsLabel:"Follows the site",hint:"Whether this page sits on the site's content column, or runs edge to edge.",onChange:l=>t(l)})}}const c=[{label:"Auto",value:"auto"},{label:"Shared",value:"shared"},{label:"Its own",value:"own"}],T={title:i("Page Title"),pageBackground:a(),topSpace:s("Top space",o(n,{}),c,p),widthChoice:d()};export{T as GENERAL_ROOT_FIELDS,c as TOP_SPACE_OPTIONS,d as pageWidthField};
1
+ import{jsx as i}from"react/jsx-runtime";import{ListIcon as T,PaddingTopIcon as m}from"efficient-easel/icons";import w from"../../components/WidthFollowField.js";import{PRODUCT_RECORD_TYPE as R,TEMPLATE_RECORD_TYPE_PROP as c,declaredRecordType as f,recordTypes as s,recordTypesRevision as a}from"../content/record-types.js";import{pageBackgroundField as h,plainText as E,select as p}from"./controls.js";import{isEditorOnDynamicPage as g}from"./editor-page-context.js";import{DEFAULT_TOP_SPACE as P}from"./header-clearance.js";function _(){return{type:"custom",render:({value:e,onChange:r})=>i(w,{value:e==="full"?"full":e==="content"?"content":void 0,resolved:"content",followsLabel:"Follows the site",hint:"Whether this page sits on the site's content column, or runs edge to edge.",onChange:o=>r(o)})}}const O=[{label:"Auto",value:"auto"},{label:"Shared",value:"shared"},{label:"Its own",value:"own"}],F={title:E("Page Title"),pageBackground:h(),topSpace:p("Top space",i(m,{}),O,P),widthChoice:_()},y="Record type",l=new Map;let u=-1;function x(e){u!==a()&&(l.clear(),u=a());const r=s(),o=r.some(n=>n.key===e)?"":e;let t=l.get(o);return t||(t=p(y,i(T,{}),[...r.map(n=>({label:n.label,value:n.key})),...o?[{label:o,value:o}]:[]],R),l.set(o,t)),t}const d=new WeakMap;function S(e,r){if(!g()||s().length<2||c in e)return e;const o=x(f(r)),t=d.get(e);if(t&&t.row===o)return t.fields;const n={[c]:o,...e};return d.set(e,{row:o,fields:n}),n}export{F as GENERAL_ROOT_FIELDS,y as RECORD_TYPE_LABEL,O as TOP_SPACE_OPTIONS,_ as pageWidthField,S as withRecordTypeRow};
@@ -1 +1 @@
1
- import{dropEmptyHeadings as r}from"./panel-drop-empty-headings.js";import{applyBlockPasses as l,registryPassContext as d}from"./passes/index.js";import{PASS_INSPECTOR as m}from"./passes/inspector.js";function u(o){const n={...d(Object.keys(o.components),o.categories?.structure?.components??[]),inspector:m};for(const[t,e]of Object.entries(o.components))l(t,e,n);const i=o.root,c=i.resolveFields;return i.resolveFields=c?(t,e)=>{const s=c(t,e);return s instanceof Promise?s.then(p=>r(p??e.fields,"page")):r(s??e.fields,"page")}:(t,e)=>r(e.fields,"page"),n}export{u as finishRegistry};
1
+ import{withRecordTypeRow as l}from"./page-root-fields.js";import{dropEmptyHeadings as m}from"./panel-drop-empty-headings.js";import{applyBlockPasses as f,registryPassContext as d}from"./passes/index.js";import{PASS_INSPECTOR as y}from"./passes/inspector.js";function R(t){const n={...d(Object.keys(t.components),t.categories?.structure?.components??[]),inspector:y};for(const[e,o]of Object.entries(t.components))f(e,o,n);const i=t.root,c=i.resolveFields,s=(e,o)=>m(l(e,o?.props),"page");return i.resolveFields=c?(e,o)=>{const r=c(e,o);return r instanceof Promise?r.then(p=>s(p??o.fields,e)):s(r??o.fields,e)}:(e,o)=>s(o.fields,e),n}export{R as finishRegistry};
@@ -8,6 +8,6 @@ import{ruleChecks as z}from"./rule.js";const g="sf-note";function y(o){const i=[
8
8
  font-size: 12px;
9
9
  `,"font-size")==="12px"&&m(` font-size-adjust: 0.5;
10
10
  `,"font-size")===null),t("a grouping block reports its children, not itself",p(y("@keyframes sf-x { from { opacity: 0; } to { opacity: 1; } }").map(h=>h.selector),["from","to"])),t("braces in comments and strings do not shift nesting",p(y('/* .a { x } */ .b { content: "}"; } .c { color: red; }').map(h=>h.selector),[".b",".c"])),t("modifiers and descendants report the base note class",p([...u(".sf-note--error")],["sf-note"])&&p([...u(".sf-note p + p")],["sf-note"])&&p([...u(`.${e("pages")}, .${e("sm")}`)],[e("pages"),e("sm")])&&u(".sf-notebook").size===0);const f=[`/* Two homes were rejected: \`.${e("pages")}\` belongs to the chrome. */`,`// …and .${e("sm")} is the sitemap's own.`,'const url = "https://x/y";','export const Note = () => <div className="sf-note">hi</div>;'].join(`
11
- `);t("a class a file only TALKS about is not a class it renders, and a `//` in a URL is not a comment",p([...u(b(f))],["sf-note"])&&/https:\/\/x\/y/.test(b(f)))}let r=new Set([g]);if(i.stylesheet){const e=o.find(s=>s.path===i.stylesheet);if(t(`read the stylesheet ${i.stylesheet}`,!!e)&&e){const s=y(e.text);r=new Set;for(const l of s)for(const d of u(l.selector))r.add(d);t(`the stylesheet parses (${s.length} rules, more than 400)`,s.length>400,"the walker looks broken"),t(`the scan is not vacuous: it finds a note class (${r.size})`,r.size>0,"the selector scan looks broken"),t(`the chrome declares exactly ONE note class, .${g}`,p([...r].sort(),[g]),`it declares ${[...r].sort().map(l=>`.${l}`).join(", ")}. One quiet sentence, one class: a note that needs a different INSET takes it from the block it sits in (\`.sf-pages-list > .sf-note\`), never from a new class`);const f=new Map;for(const l of r){const d=s.find(x=>x.selector===`.${l}`),w=d?m(d.body,"font-size"):null;t(`.${l} has a type rule of its own`,!!d,"it is a modifier without a base"),t(`.${l} states its own font-size`,w!==null,"it inherits one — that is a size nobody chose"),f.set(l,w)}const h=new Set(f.values());t("every note class states the same size",h.size<=1,`the chrome's notes are set at ${h.size} sizes: ${[...f].map(([l,d])=>`.${l} ${d}`).join(", ")}`);const $=s.find(l=>l.selector===`.${g}`);t(`the note still reads as a note: .${g} is var(--sf-muted)`,!!$&&m($.body,"color")==="var(--sf-muted)",$?`color: ${m($.body,"color")}`:"the chrome no longer declares it")}}const n=o.filter(e=>/\.(tsx?|jsx?|mjs)$/.test(e.path));t(`read the source (${n.length} JS/TS files, at least ${i.minFiles})`,n.length>=i.minFiles,"fewer means the walk broke, and the check below is vacuous");const a=[];for(const e of n)for(const s of u(b(e.text)))r.has(s)||a.push(`${e.path} ${s}`);return t(`no source file names a note class the chrome does not declare (${[...r].map(e=>`.${e}`).join(", ")})`,a.length===0,`a \`.sf-*\` class is scoped under \`.sf-editor\` in the PARENT document, so a missing rule is not a compile error — the text simply renders at whatever it inherits:
11
+ `);t("a class a file only TALKS about is not a class it renders, and a `//` in a URL is not a comment",p([...u(b(f))],["sf-note"])&&/https:\/\/x\/y/.test(b(f)))}let r=new Set([g]);if(i.stylesheet){const e=o.find(s=>s.path===i.stylesheet);if(t(`read the stylesheet ${i.stylesheet}`,!!e)&&e){const s=y(e.text);r=new Set;for(const l of s)for(const d of u(l.selector))r.add(d);t(`the stylesheet parses (${s.length} rules, more than 300)`,s.length>300,"the walker looks broken"),t(`the scan is not vacuous: it finds a note class (${r.size})`,r.size>0,"the selector scan looks broken"),t(`the chrome declares exactly ONE note class, .${g}`,p([...r].sort(),[g]),`it declares ${[...r].sort().map(l=>`.${l}`).join(", ")}. One quiet sentence, one class: a note that needs a different INSET takes it from the block it sits in (\`.sf-pages-list > .sf-note\`), never from a new class`);const f=new Map;for(const l of r){const d=s.find(x=>x.selector===`.${l}`),w=d?m(d.body,"font-size"):null;t(`.${l} has a type rule of its own`,!!d,"it is a modifier without a base"),t(`.${l} states its own font-size`,w!==null,"it inherits one — that is a size nobody chose"),f.set(l,w)}const h=new Set(f.values());t("every note class states the same size",h.size<=1,`the chrome's notes are set at ${h.size} sizes: ${[...f].map(([l,d])=>`.${l} ${d}`).join(", ")}`);const $=s.find(l=>l.selector===`.${g}`);t(`the note still reads as a note: .${g} is var(--sf-muted)`,!!$&&m($.body,"color")==="var(--sf-muted)",$?`color: ${m($.body,"color")}`:"the chrome no longer declares it")}}const n=o.filter(e=>/\.(tsx?|jsx?|mjs)$/.test(e.path));t(`read the source (${n.length} JS/TS files, at least ${i.minFiles})`,n.length>=i.minFiles,"fewer means the walk broke, and the check below is vacuous");const a=[];for(const e of n)for(const s of u(b(e.text)))r.has(s)||a.push(`${e.path} ${s}`);return t(`no source file names a note class the chrome does not declare (${[...r].map(e=>`.${e}`).join(", ")})`,a.length===0,`a \`.sf-*\` class is scoped under \`.sf-editor\` in the PARENT document, so a missing rule is not a compile error — the text simply renders at whatever it inherits:
12
12
  ${a.join(`
13
13
  `)}`),c()}export{g as CHROME_NOTE_CLASS,m as declaration,S as editorChromeNote,y as leafRules,u as noteClasses,b as withoutComments};
@@ -1,6 +1,6 @@
1
- import{ruleChecks as d}from"./rule.js";const a=n=>JSON.stringify(n),g="the website builder's components/socialIcons.tsx (`<SocialMark>`)",$=/\.(ts|tsx|js|jsx|mjs|cjs)$/,u=/(?:from\s*|import\s*\(\s*|require\s*\(\s*|import\s+)["'](@tabler\/[^"']+)["']/g,f=/(?:import\s*\*\s*as\s+\w+\s*from|export\s*\*\s*(?:as\s+\w+\s*)?from)\s*["']@tabler\/[^"']+["']/,x=["Instagram","Facebook","Tiktok","Youtube","X","Linkedin","Pinterest","Whatsapp"],c=n=>[...n.matchAll(u)].map(t=>t[1]);function k(n,t){const{check:r,report:b}=d("social icons import");{const e=["@tabler","icons-react"].join("/"),s=[["a named import",`import { IconBrandX } from ${a(e)};`,!1],["a dynamic import()",`const m = await import(${a(e)});`,!1],["a require()",`const t = require(${a(e)});`,!1],["a side-effect import",`import ${a(e)};`,!1],["a namespace import",`import * as Tabler from ${a(e)};`,!0],["a star re-export",`export * from ${a(e)};`,!0],["a named star re-export",`export * as T from ${a(e)};`,!0]];for(const[l,o,p]of s)r(`the reader finds ${l}`,c(o).length===1),r(`…and ${p?"flags":"does not flag"} it as the whole set`,f.test(o)===p);r("a package that is not Tabler is not Tabler",c('import x from "@tablerish/x";').length===0)}const i=n.filter(e=>$.test(e.path));r(`read the source (${i.length} JS/TS files, at least ${t.minFiles})`,i.length>=t.minFiles,"fewer means the walk broke, and every check below is vacuous");const m=i.filter(e=>c(e.text).length>0&&e.path!==t.helper).map(e=>e.path);r(t.helper?`only ${t.helper} imports Tabler`:"no file here imports Tabler",m.length===0,`Tabler is imported outside its one home:
1
+ import{ruleChecks as $}from"./rule.js";const a=n=>JSON.stringify(n),w="the website builder's components/socialIcons.tsx (`<SocialMark>`)",u=/\.(ts|tsx|js|jsx|mjs|cjs)$/,x=/(?:from\s*|import\s*\(\s*|require\s*\(\s*|import\s+)["'](@tabler\/[^"']+)["']/g,d=/(?:import\s*\*\s*as\s+\w+\s*from|export\s*\*\s*(?:as\s+\w+\s*)?from)\s*["']@tabler\/[^"']+["']/,k=["Instagram","Facebook","Tiktok","Youtube","X","Linkedin","Pinterest","Whatsapp"],b=["Telegram","Line","Wechat"],h=n=>[...n.matchAll(x)].map(t=>t[1]);function S(n,t){const{check:r,report:g}=$("social icons import");{const e=["@tabler","icons-react"].join("/"),o=[["a named import",`import { IconBrandX } from ${a(e)};`,!1],["a dynamic import()",`const m = await import(${a(e)});`,!1],["a require()",`const t = require(${a(e)});`,!1],["a side-effect import",`import ${a(e)};`,!1],["a namespace import",`import * as Tabler from ${a(e)};`,!0],["a star re-export",`export * from ${a(e)};`,!0],["a named star re-export",`export * as T from ${a(e)};`,!0]];for(const[f,l,c]of o)r(`the reader finds ${f}`,h(l).length===1),r(`…and ${c?"flags":"does not flag"} it as the whole set`,d.test(l)===c);r("a package that is not Tabler is not Tabler",h('import x from "@tablerish/x";').length===0)}const i=n.filter(e=>u.test(e.path));r(`read the source (${i.length} JS/TS files, at least ${t.minFiles})`,i.length>=t.minFiles,"fewer means the walk broke, and every check below is vacuous");const m=i.filter(e=>h(e.text).length>0&&e.path!==t.helper).map(e=>e.path);r(t.helper?`only ${t.helper} imports Tabler`:"no file here imports Tabler",m.length===0,`Tabler is imported outside its one home:
2
2
  ${m.join(`
3
3
  `)}
4
- Draw social marks through ${g} instead.`);const h=i.filter(e=>f.test(e.text)).map(e=>e.path);if(r("nothing imports the whole Tabler set",h.length===0,`a namespace or star import from Tabler ships all ~6,000 icons (552 KB gzip):
5
- ${h.join(`
6
- `)}`),t.helper){const e=i.find(s=>s.path===t.helper);if(r(`read the helper ${t.helper}`,!!e,"the social marks have lost their one home")&&e){const s=[...new Set(c(e.text))];r("the helper imports from @tabler/icons-react only (the React build, per-icon rewritable)",s.length===1&&s[0]==="@tabler/icons-react",JSON.stringify(s));const l=x.flatMap(o=>[`IconBrand${o}`,`IconBrand${o}Filled`]).filter(o=>!new RegExp(`\\b${o},`).test(e.text));r("the helper imports the sixteen marks by name",l.length===0,`no longer imports ${l.join(", ")}`)}}return b()}export{k as socialIconsImport};
4
+ Draw social marks through ${w} instead.`);const p=i.filter(e=>d.test(e.text)).map(e=>e.path);if(r("nothing imports the whole Tabler set",p.length===0,`a namespace or star import from Tabler ships all ~6,000 icons (552 KB gzip):
5
+ ${p.join(`
6
+ `)}`),t.helper){const e=i.find(o=>o.path===t.helper);if(r(`read the helper ${t.helper}`,!!e,"the social marks have lost their one home")&&e){const o=[...new Set(h(e.text))];r("the helper imports from @tabler/icons-react only (the React build, per-icon rewritable)",o.length===1&&o[0]==="@tabler/icons-react",JSON.stringify(o));const l=[...k.flatMap(s=>[`IconBrand${s}`,`IconBrand${s}Filled`]),...b.map(s=>`IconBrand${s}`)].filter(s=>!new RegExp(`\\b${s},`).test(e.text));r("the helper imports the nineteen marks by name",l.length===0,`no longer imports ${l.join(", ")}`);const c=b.filter(s=>!new RegExp(`createReactComponent\\(\\s*"filled",\\s*"brand-${s.toLowerCase()}-filled"`).test(e.text));r("the helper draws the three Solid marks Tabler does not ship",/\bcreateReactComponent,/.test(e.text)&&c.length===0,`no Solid mark for ${c.join(", ")||"any of them: the factory is not imported"}`)}}return g()}export{S as socialIconsImport};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "efficient-web-builder",
3
- "version": "5.4.0",
3
+ "version": "6.0.0",
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,7 +40,7 @@
40
40
  "peerDependencies": {
41
41
  "@tabler/icons-react": "^3.46.0",
42
42
  "efficient-easel": "^2.0.0",
43
- "efficient-shell": "^4.171.0 || ^5.0.0",
43
+ "efficient-shell": "^5.6.0",
44
44
  "isomorphic-dompurify": "^3.18.0",
45
45
  "next": ">=16",
46
46
  "react": ">=19",
@@ -58,8 +58,8 @@
58
58
  "@types/node": "^20",
59
59
  "@types/react": "^19",
60
60
  "@types/react-dom": "^19",
61
- "efficient-easel": "^2.1.0",
62
- "efficient-shell": "^4.180.0",
61
+ "efficient-easel": "^2.2.0",
62
+ "efficient-shell": "^5.6.0",
63
63
  "esbuild": "^0.28.0",
64
64
  "happy-dom": "^20.14.5",
65
65
  "isomorphic-dompurify": "^3.18.0",
@@ -1,16 +0,0 @@
1
- export declare const FOCAL_DEFAULT = "50% 50%";
2
- export declare const FOCAL_NUDGE_STEP = 1;
3
- export declare const FOCAL_NUDGE_COARSE = 10;
4
- export interface FocalPoint {
5
- x: number;
6
- y: number;
7
- }
8
- export declare function parseFocal(value?: string | null): FocalPoint;
9
- export declare function formatFocal(x: number, y: number): string;
10
- export declare function nudgeFocal(value: string | undefined | null, key: string, coarse?: boolean): string | null;
11
- export declare function focalFromRect(rect: {
12
- left: number;
13
- top: number;
14
- width: number;
15
- height: number;
16
- }, clientX: number, clientY: number): FocalPoint;
@@ -1 +0,0 @@
1
- const i="50% 50%",x=1,p=10,c=t=>t<0?0:t>100?100:Math.round(t);function a(t){const r=String(t??"").trim().split(/\s+/);if(r.length!==2)return{x:50,y:50};const e=u=>{const l=/^(-?\d+(?:\.\d+)?)%$/.exec(u);return l?Number(l[1]):null},n=e(r[0]),o=e(r[1]);return n===null||o===null?{x:50,y:50}:{x:c(n),y:c(o)}}function s(t,r){return`${c(t)}% ${c(r)}%`}function f(t,r,e=!1){const n=e?10:1,{x:o,y:u}=a(t);switch(r){case"ArrowLeft":return s(o-n,u);case"ArrowRight":return s(o+n,u);case"ArrowUp":return s(o,u-n);case"ArrowDown":return s(o,u+n);default:return null}}function A(t,r,e){return!(t.width>0)||!(t.height>0)?{x:50,y:50}:{x:c((r-t.left)/t.width*100),y:c((e-t.top)/t.height*100)}}export{i as FOCAL_DEFAULT,p as FOCAL_NUDGE_COARSE,x as FOCAL_NUDGE_STEP,A as focalFromRect,s as formatFocal,f as nudgeFocal,a as parseFocal};