efficient-web-builder 10.0.0 → 11.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,139 @@
1
1
  # Changelog
2
2
 
3
+ ## 11.0.0 - 2026-10-14
4
+
5
+ - **Breaking: the settings panel has two tabs, Design and Animation** (owner,
6
+ final 2026-10-10). It had four: Content, Style, Layout and Animation. A
7
+ section, a Box (`Flex`) and a block all get the same two. The tab strip is
8
+ efficient-easel's `Inspector` (icon-only, equal width); this package only
9
+ sorts the fields into it.
10
+ - **Inside Design the groups have one order**: the Content part first (the
11
+ text box, then the rows that were the Content tab), then Size, Design,
12
+ Layout, Position and Anchor, each under its `DESIGN_GROUP_KEY`. A group with
13
+ no rows is not emitted.
14
+ - **Folding groups, one level** (Lewis 2026-10-13: "Or should these fold like
15
+ this? It is getting messy." — one kind of group heading per panel). Every
16
+ group in a tabbed panel is the same grey band that folds (efficient-easel's
17
+ `SettingsGroup`, − / + on its right, open by default), drawn by the
18
+ Inspector from FOLD MARKERS: the text box is a band titled "Text"
19
+ (`leadFold`); each heading of the Content part is a band titled with its
20
+ label; `_dSize` … `_dAnchor` are bands titled Size, Design, Layout,
21
+ Position, Anchor; each heading of the Animation tab is a band. A heading
22
+ INSIDE Size … Anchor (Width, Height, Padding, Shape, Color, Motion …) draws
23
+ nothing: one level only. Every heading keeps its key and its fold payload as
24
+ a marker (`foldMarker`, `quietMarker`, `foldTitleOf` in `lib/puck/controls`),
25
+ so no key is lost. The text box no longer draws its own "TEXT" caption
26
+ (`SectionTextEntries`' new `heading`, false in the panel).
27
+ - **A band of one labelled row draws no band** (editor-panel-design §2b.1, a
28
+ group of one needs no heading): `SiteFields` measures what each band draws
29
+ and, when exactly one row shows and that row has its own label, the band goes
30
+ and the row stands alone at its place (its marker becomes `fold: false`,
31
+ so the row does not join the band above). A band whose one row has no label
32
+ keeps its band (it is the row's only name). The text box gets a band only
33
+ over two or more rows. The rule is `lib/puck/panel-bands` (new).
34
+ - **A block list is named as a row, not a sub-heading.** `SlotChildRows`
35
+ (Blocks, Slides, Groups …) drew its name as an uppercase `GroupLabel` with
36
+ the count ("BLOCKS · 0"), a second kind of heading in the Design tab. It is
37
+ now the list's row label (`SettingsField`, the Layers glyph) with the count on
38
+ the right.
39
+ - **Row names for one-level bands** (Lewis picked option A, 2026-10-14).
40
+ With no sub-head inside a band, a row says its own full name: the height
41
+ strip (`Auto | Fixed | Screen`) shows the label "Height" with its glyph, on
42
+ the shared row (desktop and phone); every padding row says "Padding top",
43
+ "Padding bottom" (a card's "Padding left", "Padding right"), never a bare
44
+ side; Split's overlay pair is "Overlay button" / "Overlay button link", so
45
+ it no longer reads "Button" / "Button link" twice. Labels only: no key
46
+ moves. `scripts/test-band-row-names.tsx` (new) renders every row of every
47
+ tabbed panel and holds all three.
48
+ - **More row names for one-level bands: one label per row in a panel**
49
+ (GG, 2026-10-14). `scripts/test-band-row-names.tsx` §4 fails when two rows
50
+ of one tabbed panel show the same label (a desktop row and its phone twin
51
+ count as one; a pair that must repeat is listed in `MAY_REPEAT` with its
52
+ reason, and none is). It found two panels. Split: the text column's
53
+ background picture says "Background image", not "Image" (the image column
54
+ keeps "Image"). Hero: "Show texture", "Show slide picker", "Show arrows",
55
+ "Slide picker shape", "Arrows shape", "Slide picker placement", "Arrows
56
+ placement" (they were "Show" three times, "Shape" and "Placement" twice;
57
+ the sub-heads that told them apart draw nothing in option A). `Arrows`
58
+ stays plural, the feature's one word (card 66250). Labels only: no key
59
+ moves.
60
+ - **Two more names** (GG, 2026-10-14): Hero's texture colour row says "Texture color", and LongRead's article heading says "Article title", so its text box no longer lists "Heading" twice (N10.1: the section's own heading is `Heading`, an item's is `Title`). Labels only; keys unchanged.
61
+ - **A closed band stays closed** across selections for the editor's life:
62
+ closing Size on one section keeps Size closed on the next one (`SiteFields`,
63
+ keyed by the band's field key).
64
+ The Content part starts with a `_dContent` marker that draws nothing, so
65
+ Copy style (efficient-easel 4.0.0) can tell content from a look.
66
+ - **Where each group went** (GG, 2026-10-13): Content keeps every Content
67
+ label and takes the pictures that were in Style (`Media`, `Image`, `Images`,
68
+ `Image column`, `Gallery`, `Logo`). Size: `Width`, `Height`, `Cell width`.
69
+ Design: the rest of Style. Layout: the rest of Layout, Padding included.
70
+ Position: `Nudge`. Anchor: `Anchor`. The Text and Heading blocks' Padding
71
+ goes in Size, beside Width (`BLOCK_KEY_GROUP`).
72
+ - **No setting is cut.** `scripts/test-no-setting-lost.tsx` checks every field
73
+ key of 6.0.0 against a record made on 6.0.0
74
+ (`scripts/fixtures/settings-before-two-tabs.json`): 871 keys over 54
75
+ components, all still there (still 871 on 10.0.0: main's work since added
76
+ and removed none), Animation unchanged, every key of the old
77
+ Content tab in the Content part, before every other group, every old Style
78
+ key in the Design group or the Content part, and every old Layout key in
79
+ Size, Layout, Position or Anchor.
80
+ - **Countdown has tabs now** (GG, 2026-10-13). It was added after every
81
+ placeable section was grouped, and nobody added it to `GROUPED_SECTIONS`, so
82
+ its 16 settings sat in one list with no tabs. Now its own 4 rows (Heading, At
83
+ zero, Ends, Unit labels) open the Content part of Design, the 11 shared rows
84
+ sit in Size, Design, Layout and Anchor, and its motion row is in Animation.
85
+ - **Breaking: `lib/puck/field-groups` API.** `LABEL_BUCKET` is `LABEL_GROUP`
86
+ and `KEY_BUCKET` is `KEY_GROUP`; their values are a Design group or
87
+ `"Animation"` (`Place`), not a tab. New: `BLOCK_KEY_GROUP`, `placeOf`,
88
+ `bucketOfPlace`, `headerKeysOf`, `headerKeysOfPlace`, `PLACE_WORDS`,
89
+ `INJECTED_RETIRED`, `DESIGN_GROUPS` and `DESIGN_GROUP_KEY` (also from
90
+ `lib/puck/field-buckets`). `bucketOf` still answers the tab.
91
+ `seatContentBucket` is `seatDesignBucket`. `BUCKET_KEY` has `Design` and
92
+ `Animation` only; a section that declares `_sContent`, `_sStyle`, `_sLayout`
93
+ or `_sMedia` now throws. A section opens a Design group itself with its key
94
+ (`_dDesign: section("Design")`, as Prose, ProcessSteps, Footprint, Timeline
95
+ and TimelineTrack now do).
96
+ - **`RETIRED` keeps every heading it retired.** A row now retires a level-2
97
+ heading whose label repeats the word of the PLACE it sits in (`PLACE_WORDS`:
98
+ "Content" in the Content part, "Style" or "Design" in the Design group,
99
+ "Layout" in Layout, …), with the same exact checks. The `Anchor` heading
100
+ every section gets is retired by key (`INJECTED_RETIRED`), because the
101
+ Anchor group heading above it says the same word.
102
+ - **The keep-lists follow the groups.** `LAYOUT_FIELD_KEYS`,
103
+ `SECTION_THEME_FIELD_KEYS`, `SECTION_SHAPE_FIELD_KEYS`,
104
+ `SECTION_ANIM_FIELD_KEYS` and `BOUND_CARD_MEDIA_FIELD_KEYS` carry the new tab
105
+ and group heading keys, read off the builders' own headings.
106
+ - **The text entries open the Design tab.** `SiteFields` hands them to the
107
+ Inspector as `lead` (drawn before the rows), and `entriesHiddenForTab` shows
108
+ them on Design only. `BUCKET_ICONS`: Design is the shell's `adjust`,
109
+ Animation the shell's `animation`.
110
+ - **Breaking: efficient-easel ^6.2.0** (peer and dev; was `^4.0.0`):
111
+ `SETTINGS_BUCKETS` Design/Animation, `DESIGN_GROUPS`, `DESIGN_GROUP_KEY`,
112
+ the panel words' `designGroups`, the Inspector's `lead`, `leadFold`,
113
+ `closedFolds` and `onFold`, and the fold markers are easel 5.0.0's; 6.0.0
114
+ draws the text box's toolbar from the shell (`TextToolbar`), which this
115
+ package does not touch. **Breaking: efficient-shell ^7.22.1** (peer; dev
116
+ `^7.23.1`; was `^7.21.0`): easel 6's own floor, and the first shell with
117
+ the `slide-picker-*` / `slide-arrows-*` glyphs and the seven-character
118
+ `HexInput` the Hero's rows use. `scripts/test-part-final-text-box.tsx` now
119
+ finds the text box's toolbar as the shell's `.rosh-tb` (easel 6 draws
120
+ `TextToolbar`; `.es-tb` is gone).
121
+ - New guard `scripts/test-panel-one-level-bands.tsx`: in every tabbed panel
122
+ (declared and resolved) every heading is a marker, so none is drawn; the
123
+ five groups and every Content and Animation heading are bands, nothing inside
124
+ Size … Anchor is; the bands come in order and every look row sits in its own
125
+ group's band; every branch of §2b.1; and `SiteFields` mounted: the band
126
+ order, the text box's band, a one-labelled-row band dropped, a one-unlabelled
127
+ -row band kept, no other heading kind, and a closed band kept closed on the
128
+ next node.
129
+ - Host follow-ups when taking this release: efficient-storefront-blocks (about
130
+ 15 guards that name the old tabs, `DetailRows`' `_sStyle: section("Style")`,
131
+ two uses of `BUCKET_KEY.Content`) and efficient-storefront (the pin, and about
132
+ 10 guards), each in its own pull request.
133
+ - `editor-words-catalogue` carries the new row and tab words (Design,
134
+ Animation, Arrows placement, Arrows shape, Article title …; `Show` is no
135
+ longer said alone), so a host can translate them.
136
+
3
137
  ## 10.0.0 - 2026-10-14
4
138
 
5
139
  - **The `Which corners` cells and the nine-square grid are efficient-shell
@@ -1 +1 @@
1
- "use client";import{jsx as n,jsxs as d,Fragment as v}from"react/jsx-runtime";import{useState as fe}from"react";import{useEasel as ue}from"efficient-easel/easel";import{InspectorHead as he,InspectorIconButton as x}from"efficient-easel/chrome";import{DuplicateIcon as Se,TrashIcon as we}from"efficient-easel/icons";import{panelFieldsOf as be}from"../lib/puck/panel-fields.js";import{TICKER_PART_LABEL as B}from"./PreviewTickerContext.js";import ge from"./SectionIcon.js";import{PanelHideButton as z}from"./SidePanelHead.js";import{useEditorSession as ke}from"../lib/editor-session-context.js";import{say as i}from"../lib/editor-words.js";import ve,{HintsToggle as Pe,SHOW_HINTS_DEFAULT as ye}from"./WebsiteSettingsPanel.js";import Ee from"./ChatSettingsPanel.js";import Ie from"./SocialLinksPanel.js";import Le from"./TickerSettingsPanel.js";import Ne,{PartSourceNote as Oe,partStyleName as Te}from"./PartSettingsPanel.js";import He from"./DuplicateToPageMenu.js";import{useStorefrontDocument as _e}from"./StorefrontDocumentContext.js";import{usePreviewHeader as Re}from"./PreviewHeaderContext.js";import{usePartStyle as Ae}from"./PreviewPartStyleContext.js";import{useSectionOps as Ce}from"../lib/puck/use-section-ops.js";import{SELECTION_MODE as De}from"../lib/editor-screen.js";import{usePreviewParts as Fe}from"./PreviewPartsContext.js";import{SectionTextEntries as xe}from"./SectionTextEntries.js";import{SectionTextSuppressProvider as Be}from"../lib/puck/section-text-suppress.js";import{HEADER_TYPE as ze,ROOT_ZONE as K}from"../lib/puck/content-tree.js";import{duplicateBlocked as Ke}from"../lib/hero-group-placement.js";import{FOOTER_TYPE as P}from"../lib/puck/footer-blocks.js";import Me from"./SwitchToBoxFooter.js";import{SiteFields as M}from"./SiteFields.js";import{SITE_FOOTER_SLUG as We}from"../lib/content/footer.js";import{SettingsSwitch as je}from"efficient-easel/panel";import{foldTopTier as Ue}from"../lib/puck/field-groups.js";import{FoldHeadingScope as Ye}from"../lib/puck/panel-heading-scope.js";import{partRowField as Ge}from"../lib/puck/part-row-field.js";import{decodePartKey as Ze,partRowHeadLabel as $e}from"../lib/puck/part-rows.js";import{encodePartId as W,partHeadLabel as qe,partLabel as Je,sectionTextParts as Qe}from"../lib/puck/text-parts.js";import{partSourceOf as Ve,sourceSlugOf as Xe}from"../lib/puck/source-bound-parts.js";const Yt=De,Gt={kind:"header"},Zt={kind:"website"},$t={kind:"chat"},qt={kind:"social"},g="Part";function j(e){return i("Part of {name}",{name:i(e)})}function et(e,o,r){const c=e.describeNode(o);return{name:r,kindLabel:c?j(c.label):i(g)}}function tt(e){switch(e){case"Header":return{title:i("Header settings belong to a website."),own:i("Each website created from this template sets its own header afterwards.")};case"Appearance":return{title:i("Appearance settings belong to a website."),own:i("Each website created from this template sets its own appearance afterwards.")};case"Live chat":return{title:i("Live chat settings belong to a website."),own:i("Each website created from this template sets its own live chat afterwards.")};case"Social link":return{title:i("Social link settings belong to a website."),own:i("Each website created from this template sets its own social link afterwards.")};default:return{title:i("{what} settings belong to a website.",{what:e}),own:i("Each website created from this template sets its own {what} afterwards.",{what:e.toLowerCase()})}}}function U({what:e}){const o=tt(e);return d("div",{className:"sf-note",children:[n("p",{children:n("strong",{children:o.title})}),d("p",{children:[i("A template is a blueprint — it has no website of its own, so there is nothing here to change.")," ",o.own]})]})}const nt={header:{name:"Header",kindLabel:"Site settings",icon:"header",render:(e,o)=>{const r=o.hostPanels?.header;return r?n(r,{placeholderMode:o.capabilities.placeholderFrames,tokenRef:o.tokenRef,siteId:o.siteId,websiteName:o.websiteName,onOpenWebsiteSettings:o.onOpenWebsiteSettings,onAuthExpired:()=>o.notifyParent("storefront-editor:auth-expired")}):null}},website:{name:"Appearance",kindLabel:"Site settings",icon:"website",render:(e,o)=>n(ve,{themeFromDocument:!o.capabilities.hasSiteTheme,tokenRef:o.tokenRef,siteId:o.siteId,onNotify:o.onNotify})},chat:{name:"Live chat",kindLabel:"Site settings",icon:"chat",render:()=>n(Ee,{})},social:{name:"Social links",kindLabel:"Site settings",icon:"social",render:()=>n(Ie,{unavailable:n(U,{what:"Social link"})})},ticker:{name:B,kindLabel:g,icon:"ticker",head:(e,o)=>e.kind==="ticker"?et(o,e.heroId,i(B)):null,render:e=>n(Le,{heroId:e.kind==="ticker"?e.heroId:""})},part:{name:g,kindLabel:g,icon:"Text",head:(e,o)=>{if(e.kind!=="part")return null;const r=o.describeNode(e.nodeId);if(!r)return null;const{key:c,row:h}=Ze(e.propKey),w=h?Ge(r.fields[c],h):r.fields[c],u=$e(i(qe(Je(w??{},c))),h),p=o.styleNameOfPart(e.nodeId,e.propKey);return{name:p!==null?i(p):u,kindLabel:j(r.label)}},render:(e,o)=>e.kind==="part"?n(Ne,{nodeId:e.nodeId,propKey:e.propKey,onBack:()=>o.onSelectNode(e.nodeId),onEditStyle:o.onOpenSiteStyles}):null}},ot=new Set(["header","website","chat"]);function it(e,o){if(e==="puck")return null;const r=nt[e];return ot.has(e)&&!o.hasSiteSettings?{...r,kindLabel:"Not part of a template",render:()=>n(U,{what:r.name})}:r}function rt({mode:e,onOpenWebsiteSettings:o,onOpenSiteStyles:r,onSelectNode:c,hideNodeActions:h=!1,onNotify:w,onHidePanel:u}){const{capabilities:p,tokenRef:y,notifyParent:Y,currentSlug:E,siteId:I,runAuthed:G,readOnly:Z}=_e(),{websiteName:$,fonts:q}=Re(),{partStyle:L}=Ae(),b=Ce({readOnly:Z}),{select:J}=Fe(),{selectedItem:t,getItemById:N,getSelectorForId:Q,config:m,appState:V}=ue(l=>l),X=be(m,t?{type:t.type,props:t.props}:null),ee=l=>m.components[l]?.label??l,s=t?Q(t.props.id):void 0,a=it(e.kind,p),O=ke(),T=O.chrome?.panels?.chromePage,H={capabilities:p,tokenRef:y,hostPanels:O.chrome?.panels,describeNode:l=>{const f=N(l);if(!f)return null;const S=m.components[f.type];return{type:f.type,label:S?.label??f.type,fields:S?.fields??{}}},styleNameOfPart:(l,f)=>{const S=N(l);if(!S)return null;const de=W(l,f),me=L?.partId===de?L:null;return Te(S.props,f,me,q)},siteId:I,websiteName:$??null,notifyParent:Y,onNotify:w,onOpenWebsiteSettings:o,onOpenSiteStyles:r,onSelectNode:c},_=a?.head?.(e,H)??null,te=_?.name??(a?i(a.name):t?i(ee(t.type)):i("Page settings")),ne=_?.kindLabel??(a?i(a.kindLabel):t?s&&s.zone!==K?i("Block"):i("Section"):i("Page")),oe=a?a.icon:t?t.type:"page",R=a?null:t?m.components[t.type]?.fields??null:m.root?.fields??null,ie=R?Ue(R):2,A=e.kind==="puck"&&t?Ve(t.type):null,re=!!t&&!!s&&s.zone===K&&t.type!==P&&t.type!==ze,k=Ke(V?.data,t),se=()=>{k||s&&b.duplicateComponent(s.zone,s.index)},ae=()=>{s&&(b.removeComponent(s.zone,s.index),b.select(null))},le=t?m.components[t.type]?.defaultProps?.previewHover:void 0,C=e.kind==="puck"&&!!t&&!!s&&le!==void 0,D=C&&t.props.previewHover===!0,ce=()=>{!t||!s||b.replaceComponent(s.zone,s.index,{...t,props:{...t.props,previewHover:!D}})},[F,pe]=fe(ye);return d("div",{className:`es-sidepanel es-sidepanel--right sf-panel sf-panel--right${F||!(!a&&!!t)?"":" sf-hints-folded"}`,children:[n(he,{icon:n(ge,{type:oe,size:15}),name:te,kind:ne,actions:!h&&e.kind==="puck"&&t&&t.type!==P?d(v,{children:[n(x,{label:i("Duplicate section"),title:k??void 0,disabled:k!==null,onClick:se,children:n(Se,{size:15})}),re&&p.hasSiteSettings&&n(He,{node:t,currentSlug:E,siteId:I??void 0,tokenRef:y,runAuthed:G,onNotify:w}),n(x,{label:i("Remove section"),danger:!0,onClick:ae,children:n(we,{size:15})}),u?n(z,{side:"right",onHide:u,divider:!0}):null]}):u?n(z,{side:"right",onHide:u}):void 0}),C&&d("div",{className:"sf-preview-pin",children:[d("div",{className:"sf-preview-pin-text",children:[n("span",{className:"sf-preview-pin-label",children:i("Preview hover state")}),n("span",{className:"sf-preview-pin-hint",children:i("not shown live")})]}),n(je,{checked:D,onChange:ce,ariaLabel:i("Preview hover state")})]}),n(Ye,{tier:ie,children:n("div",{className:"sf-insp-body sf-scroll",children:a?a.render(e,H):t?d(v,{children:[n(Be,{children:n(M,{entries:n(xe,{parts:Qe(X??m.components[t.type]?.fields,t.props),onOpen:l=>J(W(t.props.id,l))})})}),t.type===P&&p.hasSiteSettings&&n(Me,{}),A&&n(Oe,{source:A,slug:Xe(t?.props)}),n(Pe,{shown:F,onChange:pe})]}):d(v,{children:[n(M,{}),E===We&&p.hasSiteSettings&&T&&n(T,{})]})})})]})}export{$t as CHAT_MODE,Gt as HEADER_MODE,Yt as PUCK_MODE,qt as SOCIAL_MODE,Zt as WEBSITE_MODE,rt as default,it as resolvePanel};
1
+ "use client";import{jsx as n,jsxs as d,Fragment as v}from"react/jsx-runtime";import{useState as ue}from"react";import{useEasel as he}from"efficient-easel/easel";import{InspectorHead as Se,InspectorIconButton as B}from"efficient-easel/chrome";import{DuplicateIcon as we,TrashIcon as be}from"efficient-easel/icons";import{panelFieldsOf as ge}from"../lib/puck/panel-fields.js";import{TICKER_PART_LABEL as z}from"./PreviewTickerContext.js";import ke from"./SectionIcon.js";import{PanelHideButton as K}from"./SidePanelHead.js";import{useEditorSession as ve}from"../lib/editor-session-context.js";import{say as i}from"../lib/editor-words.js";import Pe,{HintsToggle as ye,SHOW_HINTS_DEFAULT as Ee}from"./WebsiteSettingsPanel.js";import Ie from"./ChatSettingsPanel.js";import Le from"./SocialLinksPanel.js";import Ne from"./TickerSettingsPanel.js";import Oe,{PartSourceNote as Te,partStyleName as He}from"./PartSettingsPanel.js";import _e from"./DuplicateToPageMenu.js";import{useStorefrontDocument as Ce}from"./StorefrontDocumentContext.js";import{usePreviewHeader as Re}from"./PreviewHeaderContext.js";import{usePartStyle as Ae}from"./PreviewPartStyleContext.js";import{useSectionOps as De}from"../lib/puck/use-section-ops.js";import{SELECTION_MODE as Fe}from"../lib/editor-screen.js";import{usePreviewParts as xe}from"./PreviewPartsContext.js";import{entryPartsOf as Be,SectionTextEntries as ze}from"./SectionTextEntries.js";import{SectionTextSuppressProvider as Ke}from"../lib/puck/section-text-suppress.js";import{HEADER_TYPE as Me,ROOT_ZONE as M}from"../lib/puck/content-tree.js";import{duplicateBlocked as We}from"../lib/hero-group-placement.js";import{FOOTER_TYPE as P}from"../lib/puck/footer-blocks.js";import je from"./SwitchToBoxFooter.js";import{SiteFields as W}from"./SiteFields.js";import{SITE_FOOTER_SLUG as Ue}from"../lib/content/footer.js";import{SettingsSwitch as Ye}from"efficient-easel/panel";import{foldTopTier as Ge}from"../lib/puck/field-groups.js";import{FoldHeadingScope as Ze}from"../lib/puck/panel-heading-scope.js";import{partRowField as $e}from"../lib/puck/part-row-field.js";import{decodePartKey as qe,partRowHeadLabel as Je}from"../lib/puck/part-rows.js";import{encodePartId as j,partHeadLabel as Qe,partLabel as Ve,sectionTextParts as Xe}from"../lib/puck/text-parts.js";import{partSourceOf as et,sourceSlugOf as tt}from"../lib/puck/source-bound-parts.js";const Zt=Fe,$t={kind:"header"},qt={kind:"website"},Jt={kind:"chat"},Qt={kind:"social"},g="Part";function U(e){return i("Part of {name}",{name:i(e)})}function nt(e,o,r){const c=e.describeNode(o);return{name:r,kindLabel:c?U(c.label):i(g)}}function ot(e){switch(e){case"Header":return{title:i("Header settings belong to a website."),own:i("Each website created from this template sets its own header afterwards.")};case"Appearance":return{title:i("Appearance settings belong to a website."),own:i("Each website created from this template sets its own appearance afterwards.")};case"Live chat":return{title:i("Live chat settings belong to a website."),own:i("Each website created from this template sets its own live chat afterwards.")};case"Social link":return{title:i("Social link settings belong to a website."),own:i("Each website created from this template sets its own social link afterwards.")};default:return{title:i("{what} settings belong to a website.",{what:e}),own:i("Each website created from this template sets its own {what} afterwards.",{what:e.toLowerCase()})}}}function Y({what:e}){const o=ot(e);return d("div",{className:"sf-note",children:[n("p",{children:n("strong",{children:o.title})}),d("p",{children:[i("A template is a blueprint — it has no website of its own, so there is nothing here to change.")," ",o.own]})]})}const it={header:{name:"Header",kindLabel:"Site settings",icon:"header",render:(e,o)=>{const r=o.hostPanels?.header;return r?n(r,{placeholderMode:o.capabilities.placeholderFrames,tokenRef:o.tokenRef,siteId:o.siteId,websiteName:o.websiteName,onOpenWebsiteSettings:o.onOpenWebsiteSettings,onAuthExpired:()=>o.notifyParent("storefront-editor:auth-expired")}):null}},website:{name:"Appearance",kindLabel:"Site settings",icon:"website",render:(e,o)=>n(Pe,{themeFromDocument:!o.capabilities.hasSiteTheme,tokenRef:o.tokenRef,siteId:o.siteId,onNotify:o.onNotify})},chat:{name:"Live chat",kindLabel:"Site settings",icon:"chat",render:()=>n(Ie,{})},social:{name:"Social links",kindLabel:"Site settings",icon:"social",render:()=>n(Le,{unavailable:n(Y,{what:"Social link"})})},ticker:{name:z,kindLabel:g,icon:"ticker",head:(e,o)=>e.kind==="ticker"?nt(o,e.heroId,i(z)):null,render:e=>n(Ne,{heroId:e.kind==="ticker"?e.heroId:""})},part:{name:g,kindLabel:g,icon:"Text",head:(e,o)=>{if(e.kind!=="part")return null;const r=o.describeNode(e.nodeId);if(!r)return null;const{key:c,row:h}=qe(e.propKey),w=h?$e(r.fields[c],h):r.fields[c],u=Je(i(Qe(Ve(w??{},c))),h),p=o.styleNameOfPart(e.nodeId,e.propKey);return{name:p!==null?i(p):u,kindLabel:U(r.label)}},render:(e,o)=>e.kind==="part"?n(Oe,{nodeId:e.nodeId,propKey:e.propKey,onBack:()=>o.onSelectNode(e.nodeId),onEditStyle:o.onOpenSiteStyles}):null}},rt=new Set(["header","website","chat"]);function st(e,o){if(e==="puck")return null;const r=it[e];return rt.has(e)&&!o.hasSiteSettings?{...r,kindLabel:"Not part of a template",render:()=>n(Y,{what:r.name})}:r}function at({mode:e,onOpenWebsiteSettings:o,onOpenSiteStyles:r,onSelectNode:c,hideNodeActions:h=!1,onNotify:w,onHidePanel:u}){const{capabilities:p,tokenRef:y,notifyParent:G,currentSlug:E,siteId:I,runAuthed:Z,readOnly:$}=Ce(),{websiteName:q,fonts:J}=Re(),{partStyle:L}=Ae(),b=De({readOnly:$}),{select:Q}=xe(),{selectedItem:t,getItemById:N,getSelectorForId:V,config:m,appState:X}=he(l=>l),ee=ge(m,t?{type:t.type,props:t.props}:null),O=t?Xe(ee??m.components[t.type]?.fields,t.props):[],te=l=>m.components[l]?.label??l,s=t?V(t.props.id):void 0,a=st(e.kind,p),T=ve(),H=T.chrome?.panels?.chromePage,_={capabilities:p,tokenRef:y,hostPanels:T.chrome?.panels,describeNode:l=>{const f=N(l);if(!f)return null;const S=m.components[f.type];return{type:f.type,label:S?.label??f.type,fields:S?.fields??{}}},styleNameOfPart:(l,f)=>{const S=N(l);if(!S)return null;const me=j(l,f),fe=L?.partId===me?L:null;return He(S.props,f,fe,J)},siteId:I,websiteName:q??null,notifyParent:G,onNotify:w,onOpenWebsiteSettings:o,onOpenSiteStyles:r,onSelectNode:c},C=a?.head?.(e,_)??null,ne=C?.name??(a?i(a.name):t?i(te(t.type)):i("Page settings")),oe=C?.kindLabel??(a?i(a.kindLabel):t?s&&s.zone!==M?i("Block"):i("Section"):i("Page")),ie=a?a.icon:t?t.type:"page",R=a?null:t?m.components[t.type]?.fields??null:m.root?.fields??null,re=R?Ge(R):2,A=e.kind==="puck"&&t?et(t.type):null,se=!!t&&!!s&&s.zone===M&&t.type!==P&&t.type!==Me,k=We(X?.data,t),ae=()=>{k||s&&b.duplicateComponent(s.zone,s.index)},le=()=>{s&&(b.removeComponent(s.zone,s.index),b.select(null))},ce=t?m.components[t.type]?.defaultProps?.previewHover:void 0,D=e.kind==="puck"&&!!t&&!!s&&ce!==void 0,F=D&&t.props.previewHover===!0,pe=()=>{!t||!s||b.replaceComponent(s.zone,s.index,{...t,props:{...t.props,previewHover:!F}})},[x,de]=ue(Ee);return d("div",{className:`es-sidepanel es-sidepanel--right sf-panel sf-panel--right${x||!(!a&&!!t)?"":" sf-hints-folded"}`,children:[n(Se,{icon:n(ke,{type:ie,size:15}),name:ne,kind:oe,actions:!h&&e.kind==="puck"&&t&&t.type!==P?d(v,{children:[n(B,{label:i("Duplicate section"),title:k??void 0,disabled:k!==null,onClick:ae,children:n(we,{size:15})}),se&&p.hasSiteSettings&&n(_e,{node:t,currentSlug:E,siteId:I??void 0,tokenRef:y,runAuthed:Z,onNotify:w}),n(B,{label:i("Remove section"),danger:!0,onClick:le,children:n(be,{size:15})}),u?n(K,{side:"right",onHide:u,divider:!0}):null]}):u?n(K,{side:"right",onHide:u}):void 0}),D&&d("div",{className:"sf-preview-pin",children:[d("div",{className:"sf-preview-pin-text",children:[n("span",{className:"sf-preview-pin-label",children:i("Preview hover state")}),n("span",{className:"sf-preview-pin-hint",children:i("not shown live")})]}),n(Ye,{checked:F,onChange:pe,ariaLabel:i("Preview hover state")})]}),n(Ze,{tier:re,children:n("div",{className:"sf-insp-body sf-scroll",children:a?a.render(e,_):t?d(v,{children:[n(Ke,{children:n(W,{entries:n(ze,{parts:O,heading:!1,onOpen:l=>Q(j(t.props.id,l))}),entryCount:Be(O).length})}),t.type===P&&p.hasSiteSettings&&n(je,{}),A&&n(Te,{source:A,slug:tt(t?.props)}),n(ye,{shown:x,onChange:de})]}):d(v,{children:[n(W,{}),E===Ue&&p.hasSiteSettings&&H&&n(H,{})]})})})]})}export{Jt as CHAT_MODE,$t as HEADER_MODE,Zt as PUCK_MODE,Qt as SOCIAL_MODE,qt as WEBSITE_MODE,at as default,st as resolvePanel};
@@ -1,5 +1,7 @@
1
1
  import type { SectionTextPart } from "../lib/puck/text-parts.js";
2
- export declare function SectionTextEntries({ parts, onOpen, }: {
2
+ export declare function entryPartsOf(parts: SectionTextPart[]): SectionTextPart[];
3
+ export declare function SectionTextEntries({ parts, onOpen, heading, }: {
3
4
  parts: SectionTextPart[];
4
5
  onOpen: (key: string) => void;
6
+ heading?: boolean;
5
7
  }): import("react").JSX.Element | null;
@@ -1 +1 @@
1
- "use client";import{jsx as n,jsxs as r}from"react/jsx-runtime";import{SettingsDrill as f}from"efficient-easel/panel";import a from"./UiIcon.js";import{say as i}from"../lib/editor-words.js";const l="Not shown on the page";function m({part:e,onOpen:o}){return n(f,{name:i(e.label),preview:e.offPage?i(l):e.preview||i("Empty"),offPage:e.offPage,status:e.hidden?n("span",{className:"sf-entry-eye",role:"img","aria-label":i("Hidden on the page"),children:n(a,{name:"eye-off",size:14})}):void 0,onOpen:()=>o(e.key)})}function u({parts:e,onOpen:o}){const t=e.filter(s=>!s.identifier);return t.length?r("div",{className:"sf-entries",children:[n("h3",{className:"sf-entries-head",children:i("Text")}),t.map(s=>n(m,{part:s,onOpen:o},s.key))]}):null}export{u as SectionTextEntries};
1
+ "use client";import{jsx as t,jsxs as f}from"react/jsx-runtime";import{SettingsDrill as a}from"efficient-easel/panel";import l from"./UiIcon.js";import{say as i}from"../lib/editor-words.js";const m="Not shown on the page";function c({part:e,onOpen:n}){return t(a,{name:i(e.label),preview:e.offPage?i(m):e.preview||i("Empty"),offPage:e.offPage,status:e.hidden?t("span",{className:"sf-entry-eye",role:"img","aria-label":i("Hidden on the page"),children:t(l,{name:"eye-off",size:14})}):void 0,onOpen:()=>n(e.key)})}function u(e){return e.filter(n=>!n.identifier)}function g({parts:e,onOpen:n,heading:o=!0}){const r=u(e);return r.length?f("div",{className:"sf-entries",children:[o?t("h3",{className:"sf-entries-head",children:i("Text")}):null,r.map(s=>t(c,{part:s,onOpen:n},s.key))]}):null}export{g as SectionTextEntries,u as entryPartsOf};
@@ -1,6 +1,7 @@
1
1
  import { type ReactNode } from "react";
2
2
  import { type SettingsBucket } from "efficient-easel/fields";
3
3
  export declare const TAB_ICONS: Record<SettingsBucket, ReactNode>;
4
- export declare function SiteFields({ entries }: {
4
+ export declare function SiteFields({ entries, entryCount }: {
5
5
  entries?: ReactNode;
6
+ entryCount?: number;
6
7
  }): import("react").JSX.Element;
@@ -1 +1 @@
1
- "use client";import{jsx as l}from"react/jsx-runtime";import{useState as b}from"react";import{useSelectedFields as S}from"efficient-easel/easel";import{Inspector as C,planFields as T}from"efficient-easel/fields";import{BUCKET_ICONS as g,entriesHiddenForTab as h}from"../lib/puck/controls.js";import{BUCKETS as x}from"../lib/puck/field-groups.js";import{say as y}from"../lib/editor-words.js";const i=new Map,O=Object.fromEntries(x.map(t=>{const e=g[t];return[t,l(e,{},t)]}));function w({entries:t}){const{id:e,fields:a,values:m,readOnly:d,onChange:p}=S(),[s,f]=b(()=>i.get(e)),o=i.get(e),n=T(a).buckets,r=o&&n.includes(o)?o:s&&n.includes(s)?s:n[0],u=r===void 0||h(n,r)!==!0;return l(C,{fields:a,values:m,onChange:p,readOnly:d,tab:r,onTab:c=>{i.set(e,c),f(c)},tabIcons:O,idPrefix:e,ariaLabel:y("Section settings"),children:u?t:null})}export{w as SiteFields,O as TAB_ICONS};
1
+ "use client";import{jsx as S}from"react/jsx-runtime";import{useLayoutEffect as O,useMemo as B,useRef as k,useState as T}from"react";import{useSelectedFields as D}from"efficient-easel/easel";import{Inspector as K,planFields as x}from"efficient-easel/fields";import{BUCKET_ICONS as j,entriesHiddenForTab as v}from"../lib/puck/controls.js";import{BUCKETS as L}from"../lib/puck/field-groups.js";import{say as q}from"../lib/editor-words.js";import{bandIsDropped as R,droppedBands as U,sameKeys as X,TEXT_BAND_KEY as F,TEXT_BAND_TITLE as G,withoutBands as H}from"../lib/puck/panel-bands.js";const E=new Map,f=new Set;function P(n,r){const s=new Map;for(const l of n.querySelectorAll(".es-insp-row[data-field]"))s.set(l.getAttribute("data-field")??"",l);const o=[];for(const[l,m]of r)o.push({key:l,rows:m.map(p=>{const d=s.get(p),c=!!d&&[...d.children].some(w=>!w.hidden),i=d?.querySelector(".es-field-label, .es-list-label")?.textContent?.trim();return{shown:c,labelled:c&&!!i}})});return o}const Y=Object.fromEntries(L.map(n=>{const r=j[n];return[n,S(r,{},n)]}));function te({entries:n,entryCount:r=0}){const{id:s,fields:o,values:l,readOnly:m,onChange:p}=D(),[d,c]=T(()=>new Set(f)),[i,w]=T(()=>new Set),g=k(null),C=B(()=>{const e=new Map;for(const t of x(o).rows){if(!t.fold)continue;const a=e.get(t.fold.key)??[];a.push(t.name),e.set(t.fold.key,a)}return e},[o]);O(()=>{const e=g.current?.parentElement;if(!e)return;const t=new Set(U(P(e,C)));w(a=>X(a,t)?a:t)});const _=B(()=>H(o,i),[o,i]),A={key:F,rows:Array.from({length:r},()=>({shown:!0,labelled:!0}))},I=r>0&&!R(A)?{key:F,title:G}:void 0,[b,M]=T(()=>E.get(s)),h=E.get(s),u=x(o).buckets,y=h&&u.includes(h)?h:b&&u.includes(b)?b:u[0],N=y===void 0||v(u,y)!==!0;return S(K,{fields:_,values:l,onChange:p,readOnly:m,tab:y,onTab:e=>{E.set(s,e),M(e)},tabIcons:Y,idPrefix:s,ariaLabel:q("Section settings"),lead:N?n:null,leadFold:I,closedFolds:d,onFold:(e,t)=>{t?f.delete(e):f.add(e),c(new Set(f))},children:S("span",{ref:g,hidden:!0})})}export{te as SiteFields,Y as TAB_ICONS};
@@ -1 +1 @@
1
- "use client";import{jsx as s,jsxs as b}from"react/jsx-runtime";import{useEasel as x}from"efficient-easel/easel";import{SettingsDrill as A}from"efficient-easel/panel";import C from"./AddBlockRow.js";import N from"./AddChildRow.js";import{useSlotChildActions as k}from"./SlotChildActionsContext.js";import{HERO_GROUP_TYPE as $,heroGroupNestDepth as j}from"../lib/hero-group-placement.js";import{canAddTo as w}from"../lib/puck/add-target.js";import{GroupLabel as D}from"../lib/puck/controls.js";import{say as _}from"../lib/editor-words.js";function E({parent:o,parentType:t,label:d,rowName:r,onSelectChild:e,onAddChild:m,nestDepth:p=0}){const u=w(t,p);if(!u)return null;const{slot:n,choices:f,spec:i}=u,a=String(o.props.id),h=`${a}:${n}`,l=Array.isArray(o.props[n])?o.props[n]:[],R=i?.addBlocked?.(l)??null,S=i?.notice?.(l)??null;return b("div",{className:"sf-slot-rows",children:[d?s(D,{label:`${_(d)} · ${l.length}`}):null,S?s("p",{className:"sf-note",children:S}):null,l.map((c,g)=>s(A,{name:r(c),onOpen:()=>e(h,g,String(c.props.id),t)},String(c.props.id??`${h}-${g}`))),f?s(C,{choices:f,onPick:c=>m(a,n,c,l.length,t)}):i.fixed?null:s(N,{label:i.addLabel,blocked:R,onAdd:()=>m(a,n,i.childType,l.length,t)})]})}function G(o,t){return w(t)?.source==="footer"?o.blockRowName:o.childRowName}function O({parentType:o,label:t}){const{appState:d,selectedItem:r}=x(p=>p),e=k();if(!e||!r||r.type!==o)return null;const m=o===$?j(d?.data,String(r.props.id)):0;return s(E,{parent:r,parentType:o,label:t,rowName:G(e,o),onSelectChild:e.selectChild,onAddChild:e.addChild,nestDepth:m})}export{E as SlotChildRows,O as default,G as rowNamerFor};
1
+ "use client";import{jsx as e,Fragment as A,jsxs as C}from"react/jsx-runtime";import{useEasel as N}from"efficient-easel/easel";import{LayersIcon as b}from"efficient-easel/icons";import{SettingsDrill as k,SettingsField as F}from"efficient-easel/panel";import _ from"./AddBlockRow.js";import j from"./AddChildRow.js";import{useSlotChildActions as D}from"./SlotChildActionsContext.js";import{HERO_GROUP_TYPE as $,heroGroupNestDepth as E}from"../lib/hero-group-placement.js";import{canAddTo as R}from"../lib/puck/add-target.js";import{say as I}from"../lib/editor-words.js";function O({parent:o,parentType:t,label:d,rowName:r,onSelectChild:s,onAddChild:m,nestDepth:a=0}){const h=R(t,a);if(!h)return null;const{slot:n,choices:u,spec:i}=h,p=String(o.props.id),f=`${p}:${n}`,l=Array.isArray(o.props[n])?o.props[n]:[],x=i?.addBlocked?.(l)??null,g=i?.notice?.(l)??null,S=C(A,{children:[g?e("p",{className:"sf-note",children:g}):null,l.map((c,w)=>e(k,{name:r(c),onOpen:()=>s(f,w,String(c.props.id),t)},String(c.props.id??`${f}-${w}`))),u?e(_,{choices:u,onPick:c=>m(p,n,c,l.length,t)}):i.fixed?null:e(j,{label:i.addLabel,blocked:x,onAdd:()=>m(p,n,i.childType,l.length,t)})]});return e("div",{className:"sf-slot-rows",children:d?e(F,{label:I(d),icon:e(b,{}),value:String(l.length),children:S}):S})}function P(o,t){return R(t)?.source==="footer"?o.blockRowName:o.childRowName}function v({parentType:o,label:t}){const{appState:d,selectedItem:r}=N(a=>a),s=D();if(!s||!r||r.type!==o)return null;const m=o===$?E(d?.data,String(r.props.id)):0;return e(O,{parent:r,parentType:o,label:t,rowName:P(s,o),onSelectChild:s.selectChild,onAddChild:s.addChild,nestDepth:m})}export{O as SlotChildRows,v as default,P as rowNamerFor};
@@ -2238,11 +2238,12 @@
2238
2238
  .es-field-head > .sf-colour {
2239
2239
  margin-left: auto;
2240
2240
  }
2241
- /* Seven monospaced characters and the box's padding — no wider, so a two-word
2242
- label keeps its line beside the swatch. */
2241
+ /* The hex box's width is the SHELL's: `HexInput` is never narrower than its
2242
+ seven characters and its padding. This sheet held it at 4.75rem, which cut
2243
+ "#0A0A0A" to "#0A0A0" in the Hero's Texture color row (Lewis, 2026-10-14). */
2243
2244
  .sf-colour-hexwrap {
2244
2245
  flex: none;
2245
- width: 4.75rem;
2246
+ display: flex;
2246
2247
  }
2247
2248
  .sf-colour-caption {
2248
2249
  font-size: var(--text-xs);
@@ -114,6 +114,7 @@ export declare const WEB_BUILDER_WORDS: {
114
114
  readonly "An empty section. Add whatever you want inside.": "An empty section. Add whatever you want inside.";
115
115
  readonly Anchor: "Anchor";
116
116
  readonly "Anchor name": "Anchor name";
117
+ readonly Animation: "Animation";
117
118
  readonly "Another group already uses this heading \u2014 pick a different one.": "Another group already uses this heading — pick a different one.";
118
119
  readonly Answer: "Answer";
119
120
  readonly "Any color": "Any color";
@@ -128,10 +129,13 @@ export declare const WEB_BUILDER_WORDS: {
128
129
  readonly "Approved customer reviews in a star-rated card grid, pulled live.": "Approved customer reviews in a star-rated card grid, pulled live.";
129
130
  readonly Arrow: "Arrow";
130
131
  readonly Arrows: "Arrows";
132
+ readonly "Arrows placement": "Arrows placement";
133
+ readonly "Arrows shape": "Arrows shape";
131
134
  readonly Article: "Article";
132
135
  readonly "Article *headline* goes here.": "Article *headline* goes here.";
133
136
  readonly "Article Text": "Article Text";
134
137
  readonly "Article headline": "Article headline";
138
+ readonly "Article title": "Article title";
135
139
  readonly "As designed": "As designed";
136
140
  readonly "As shot": "As shot";
137
141
  readonly "As typed": "As typed";
@@ -342,6 +346,7 @@ export declare const WEB_BUILDER_WORDS: {
342
346
  readonly "Describe this section in a sentence or two.": "Describe this section in a sentence or two.";
343
347
  readonly "Describe this step in a sentence or two.": "Describe this step in a sentence or two.";
344
348
  readonly "Describe what happened, in a sentence or two.": "Describe what happened, in a sentence or two.";
349
+ readonly Design: "Design";
345
350
  readonly Detail: "Detail";
346
351
  readonly "Detail line": "Detail line";
347
352
  readonly Direction: "Direction";
@@ -721,6 +726,7 @@ export declare const WEB_BUILDER_WORDS: {
721
726
  readonly Overlay: "Overlay";
722
727
  readonly "Overlay - CartDrawer": "Overlay - CartDrawer";
723
728
  readonly "Overlay button": "Overlay button";
729
+ readonly "Overlay button link": "Overlay button link";
724
730
  readonly "Overlay color": "Overlay color";
725
731
  readonly "Overlay position": "Overlay position";
726
732
  readonly Padding: "Padding";
@@ -756,6 +762,7 @@ export declare const WEB_BUILDER_WORDS: {
756
762
  readonly "Plays well with\n*your favourite apps.*": "Plays well with\n*your favourite apps.*";
757
763
  readonly "Pop up - SubscribePopup": "Pop up - SubscribePopup";
758
764
  readonly "Portal card (stock + button + orders)": "Portal card (stock + button + orders)";
765
+ readonly Position: "Position";
759
766
  readonly Positions: "Positions";
760
767
  readonly "Post Card": "Post Card";
761
768
  readonly Prefix: "Prefix";
@@ -873,10 +880,12 @@ export declare const WEB_BUILDER_WORDS: {
873
880
  readonly "Short description of this figure.": "Short description of this figure.";
874
881
  readonly "Short detail line": "Short detail line";
875
882
  readonly "Short supporting line": "Short supporting line";
876
- readonly Show: "Show";
883
+ readonly "Show arrows": "Show arrows";
877
884
  readonly "Show cover image": "Show cover image";
878
885
  readonly "Show hints": "Show hints";
879
886
  readonly "Show on a card": "Show on a card";
887
+ readonly "Show slide picker": "Show slide picker";
888
+ readonly "Show texture": "Show texture";
880
889
  readonly "Show the chat bubble": "Show the chat bubble";
881
890
  readonly "Show the chat bubble on the whole site": "Show the chat bubble on the whole site";
882
891
  readonly "Show ticker": "Show ticker";
@@ -897,6 +906,8 @@ export declare const WEB_BUILDER_WORDS: {
897
906
  readonly "Slash /": "Slash /";
898
907
  readonly "Slide name": "Slide name";
899
908
  readonly "Slide picker": "Slide picker";
909
+ readonly "Slide picker placement": "Slide picker placement";
910
+ readonly "Slide picker shape": "Slide picker shape";
900
911
  readonly Small: "Small";
901
912
  readonly "Social Logos": "Social Logos";
902
913
  readonly "Social link settings belong to a website.": "Social link settings belong to a website.";
@@ -991,6 +1002,7 @@ export declare const WEB_BUILDER_WORDS: {
991
1002
  readonly "Text style": "Text style";
992
1003
  readonly Texts: "Texts";
993
1004
  readonly Texture: "Texture";
1005
+ readonly "Texture color": "Texture color";
994
1006
  readonly "Texture opacity": "Texture opacity";
995
1007
  readonly "Thanks \u2014 we'll email you to confirm.": "Thanks — we'll email you to confirm.";
996
1008
  readonly "The built-in spacing.": "The built-in spacing.";