efficient-web-builder 16.0.1 → 17.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 (42) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/components/HeroGroup.d.ts +5 -1
  3. package/dist/components/HeroGroup.js +1 -1
  4. package/dist/components/HeroSingle.js +1 -1
  5. package/dist/components/PartSettingsPanel.d.ts +0 -20
  6. package/dist/components/PartSettingsPanel.js +1 -1
  7. package/dist/components/PartTextBox.d.ts +2 -1
  8. package/dist/components/PartTextBox.js +1 -1
  9. package/dist/components/SectionEditor.d.ts +0 -1
  10. package/dist/components/SectionEditor.js +1 -1
  11. package/dist/components/storefront-editor.css +9 -9
  12. package/dist/lib/content/borders.d.ts +21 -0
  13. package/dist/lib/content/borders.js +1 -0
  14. package/dist/lib/editor-words-catalogue.d.ts +14 -12
  15. package/dist/lib/editor-words-catalogue.js +5 -5
  16. package/dist/lib/puck/blocks/general/CategoryBar/fields.js +1 -1
  17. package/dist/lib/puck/blocks/general/Chart/fields.js +1 -1
  18. package/dist/lib/puck/blocks/general/Countdown/fields.js +1 -1
  19. package/dist/lib/puck/blocks/general/Flex/fields.js +1 -1
  20. package/dist/lib/puck/blocks/general/HeroGroup/fields.js +1 -1
  21. package/dist/lib/puck/blocks/general/HeroGroup/render.js +1 -1
  22. package/dist/lib/puck/blocks/general/HeroSlide/fields.js +1 -1
  23. package/dist/lib/puck/blocks/general/ImageBlock/fields.js +1 -1
  24. package/dist/lib/puck/blocks/general/LogoBlock/fields.js +1 -1
  25. package/dist/lib/puck/blocks/general/Logos/fields.js +1 -1
  26. package/dist/lib/puck/blocks/general/SectionHeader/fields.js +1 -1
  27. package/dist/lib/puck/controls.d.ts +17 -0
  28. package/dist/lib/puck/controls.js +1 -1
  29. package/dist/lib/puck/field-groups.js +1 -1
  30. package/dist/lib/puck/part-styles.d.ts +2 -1
  31. package/dist/lib/puck/part-styles.js +2 -2
  32. package/dist/lib/puck/passes/borders.d.ts +2 -0
  33. package/dist/lib/puck/passes/borders.js +1 -0
  34. package/dist/lib/puck/passes/index.js +1 -1
  35. package/dist/lib/puck/passes/inspector.js +1 -1
  36. package/dist/lib/puck/passes/section-padding.js +1 -1
  37. package/dist/lib/puck/passes/types.d.ts +5 -0
  38. package/dist/lib/source-rules/label-vocabulary.js +3 -3
  39. package/dist/lib/source-rules/one-border-resolver.d.ts +4 -0
  40. package/dist/lib/source-rules/one-border-resolver.js +1 -0
  41. package/dist/lib/source-rules/support/part-slider-call-sites.js +3 -3
  42. package/package.json +5 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,72 @@
1
1
  # Changelog
2
2
 
3
+ ## 17.0.0 - 2026-10-16
4
+
5
+ Two builds in one release (GG cuts one 17.0.0, as easel cut one 10.0.0). A major: the efficient-easel peer range narrows to `^10.1.0` (10.0.0 for the text panel and the Border and Padding parts, 10.1.0 for `onChangeMany`, which the four-side Padding row writes with) and the efficient-shell range to `^7.47.0` (7.44.0 for the Border row and the No list glyph, 7.47.0 for the Style list that shows every style whole, scrolls with no cut row, opens small in a small field and is solid: shell#507, Lewis's review 2026-10-16).
6
+
7
+ **A text part draws the one text panel** (card [MERGE] Settings Tabs Into Design And Animation; text panel v3, Lewis final 2026-10-15; wave 3 · W1 of `_desk/plans/2026-10-15-text-panel-build.md`; Italic, Lewis 2026-10-16 via GG). The part panel draws easel 10's `TextPartPanel`, the same panel the email designer draws.
8
+
9
+ ### Changed for merchants
10
+
11
+ - **A text part's words are typed where they are, on the page; the panel draws no text box for them.** Its rows are, in this order: Style (with "*" when the text has its own changes, and Clear changes · Edit styles in the list), Font with an **Italic** button at its end, the number cells (Font size · Line spacing · Letter spacing · Paragraph spacing · Padding · Width), Alignment, and Capitalization.
12
+ - **A text box stays only for words the canvas cannot take**: an image's alt text, a logo's alt text, a slide's name and its reel label, a Box name, a tab name, a category bar's active tab, a countdown's At zero line and a chart's value suffix (each field says so with the new `withPanelOnly` marker), words that never reach the page, and words hidden with the eye. The eye stays where it was.
13
+ - **Italic** (new): the whole text leans; pressing it again follows the style; over an italic site style it shows pressed and turns the text upright. Stored as `_partStyles[part].italic`, painted as `font-style`.
14
+ - **Capitalized** (new): a fourth letter case, beside As typed, Uppercase and Lowercase.
15
+ - **The head names the part**: line 1 is the part's own name, line 2 "Part of ‹section›" (easel's `headWords`). It no longer shows the style's name (gate 4 of the text panel plan; it replaces the 2026-09-07 ruling, with Lewis's "v3 is final").
16
+ - **Link and word colour are not cut**: a part whose words carry marks keeps its panel text box (toolbar only, no cells), because easel's canvas typing bar has no Link and no colour window yet. It goes when easel adds both to the canvas bar (`scripts/test-part-link-colour-kept.tsx`, red before the fix).
17
+ - **A whole text list keeps its style rows** (GG 2026-10-16): a ticker's items, a masthead's issues, an integrations list, a mockup's cards and its terminal lines are one part with no type-in-place kind. They draw the one text panel's rows under the list's own control, as they had the style card in 16.0.2 (`scripts/test-text-lists-keep-style-rows.tsx`, red before the fix).
18
+ - **No Color row and no style card of its own** (v3: a colour is put on selected words from the canvas toolbar). A colour a part already stores still draws, and Clear changes takes it away. "No style" is still the first answer in the Style list; Clear changes keeps the style the part follows.
19
+
20
+ ### Changed for hosts
21
+
22
+ - The settings body wears easel's row inset (`es-insp-body`: 16px, 8px under a 284px panel), and `.sf-insp-body` no longer sets its own side padding; `--sf-insp-pad-x` follows `--es-insp-pad-x`.
23
+ - `controls`: `withPanelOnly(field)` and `textFieldPanelOnly(field)`. `PartTextBox` exports `partTextCells` (the one list of a part's cells).
24
+ - `label-vocabulary`: six more N10.1 Never words — typeface, font family, leading, character spacing, kerning, text transform (the storefront's `doc/naming.md` Never column takes them in the pin PR, as `test-label-vocabulary` there compares the two).
25
+
26
+ ### Guards
27
+
28
+ - New `scripts/test-one-text-panel.tsx` (31 checks: italic stored and painted, Capitalized, the ten marked fields, the panel drawing `TextPartPanel` and no card or Color row, the head, the inset); all failed on 16.0.2.
29
+ - Retired `scripts/test-part-field-icons.tsx` (the rows it checked are easel's `TextPartPanel` now, tested there). `test-part-colour` §7, `test-part-follows-style` §6, `test-part-final-text-box` §5, `test-panel-padding-narrows`, `test-panel-strip-width-stable`, `test-editor-type-steps`, `test-one-dropdown`, `test-one-editor-list` read the new panel.
30
+
31
+ **A section and a Box take a Border** (card [DESIGN] The Hartes Name Block; Box Border approved by Lewis 2026-10-15, GG's order 2026-10-16: the section and Box tier first).
32
+
33
+ ### Added for merchants
34
+
35
+ - **A Border row in every section's Shape group, after Corners** (a Box is a section, so this is the Box's Border too): the shell's `BorderInput` through easel 10's `SettingsBorder`, glyph `border-all`, with the shared `Each side` toggle in its head. One width box, or four (left · top / right · bottom); Solid / Dashed / Dotted; a colour. 0–20px (answer 4). The phone's own value is a second row shown in phone view only (`sectionBorderPhone`); an empty part shows the desktop value in grey there, and the site's Borders colour on desktop.
36
+ - An empty Border is stored as nothing, and a section without a border of its own draws byte for byte as before.
37
+ - **Heading and Text take their own left and right padding** (card [ADD] INOVIT And Hartes Metal US Websites; Lewis 2026-10-16, option A: the Hartes US footer tagline needs 20px more on the right). Their two Padding sliders become ONE `Padding` row: the shell's `SidesInput` through easel `SettingsSides`, glyph `padding-all`, with the `Each side` toggle in its head. Two boxes (left and right · top and bottom), or four. 0–200px, step 4; an empty side adds nothing. The phone's own value is the same row in phone view, its empty sides showing the desktop value in grey. The stored keys do not change (`sectionPaddingTop` / `Bottom` keep their data; `sectionPaddingLeft` / `Right` and the phone twins are new), and a Heading or Text with no padding draws byte for byte as before.
38
+
39
+ - **Every section and every Box take left and right padding, in one four-side Padding row** (four-side Padding v2, Lewis 2026-10-15; GG 2026-10-16, step W-P1). The shared row (`sidesPaddingFields`, the shell's `SidesInput` through easel) replaces the section's two Top/Bottom sliders: two boxes (left and right · top and bottom), or four with `Each side` on, desktop and phone. New stored keys `sectionPaddingLeft` / `sectionPaddingRight` and their phone twins; an empty side draws nothing, so every stored page draws as before. A section draws its left/right on its outer padding wrapper; a Box on a picture still draws all four sides inside the card (its resting figures show grey in the row). The Box's hidden `py-6` is unchanged here (W-P2).
40
+
41
+ - **The Box inside a Hero (HeroGroup) shows the same four-side Padding row** (one grammar, GG 2026-10-16) instead of its Top/Bottom sliders, and draws left/right (and their phone values) on its own root, never a wrapper (the slide's grid placement, card 66290). Nothing set draws what it drew before.
42
+ - **Every phone twin of the Padding row is a phone-only field**: the Left/Right/Bottom phone twins the row keeps were not marked, so copy / paste style counted them as settings of their own ("Pasted N settings").
43
+
44
+ ### Added for hosts
45
+
46
+ - `lib/content/borders.ts`, THE one border resolver: a stored value becomes `--sf-border-{top,right,bottom,left}-width`, `--sf-border-style`, `--sf-border-color` (each again with `-phone`). Only what is set is published, so an unset side or colour follows the tier above. The `sectionBorder` pass puts them on a `display: contents` carrier, `.sf-section-border`, right after the corners carrier. **The host's stylesheet draws the line** from them on `.sf-section-border > *`, as it draws `--sf-section-radius` (the storefront's next pin carries that rule).
47
+ - `sidesPaddingFields(opts)` in `lib/puck/controls`: THE one four-side Padding row builder (keys, phone twin, empty-side value, grid), for every padding place; it writes every side it changes in one write, easel's `onChangeMany` (efficient-easel 10.1.0), never one `onChange` per side. The Heading/Text wrapper (`blockPadding`) draws left and right through `sectionPadAttrs`; a section's outer wrapper still does not.
48
+
49
+ ### Guards
50
+
51
+ - New `scripts/test-section-border.tsx` (8): the resolver (nothing set, width vs side, the Hartes value, clamps, a bad style or colour dropped, the phone suffix), the pass (byte-identical without a border, the carrier with one, phone only), its place after `sectionCorners`, the Shape group's keys, and `source-rules/one-border-resolver` (a second file writing `--sf-border-` fails). Failed before the modules existed.
52
+ - `test-shell-peer-range` and `test-publish-main-action` read the new ranges.
53
+ - New `scripts/test-block-side-padding.tsx`: the draw (left/right and their phone values on Heading and Text, no wrapper when nothing is set, no left/right on a section's outer wrapper), the panel (eight keys on the Design tab, one edit = one patch, the row writes through `onChangeMany` only, the shell's sides group and toggle drawn) and the builder over other keys. Failed before the change. `test-band-row-names` reads the four-side row: it says `Padding`, its boxes name the sides.
54
+
55
+ - New `scripts/test-section-side-padding.tsx` (27): a section and a plain Box draw left/right (desktop and phone), nothing set is not wrapped, a card Box draws none outside, every section's panel declares the eight keys and shows the shared row, and a Box's Border wraps its padding wrapper (the Hartes 20px sits inside the red line). Failed before the change.
56
+ - `test-block-side-padding` §4 and `test-box-card-padding-in-design` §2 read the new rule (a section draws left/right; only the card Box keeps them inside).
57
+
58
+ - New `scripts/test-padding-phone-twins-and-hero-group.tsx` (20): every phone twin is tier mobile, HeroGroup declares the eight keys and shows the shared row, and draws left/right on its root (desktop and phone; nothing set, no padding). Failed before the change (10 of 20).
59
+
60
+ ## 16.0.2 - 2026-10-16
61
+
62
+ **On a phone, a hero with a set height grows to fit its words** (card [ADD] INOVIT And Hartes Metal US Websites, GG 2026-10-15). hartesmetal.com/dealers: the heading "Become a Hartes Metal dealer" is five lines on a phone, and the hero's set phone height (60vh) was a fixed height, so the bottom-aligned words overflowed upward and the heading ran under the logo (181px above the top of the page at 390x844, 267px at 375x667).
63
+
64
+ ### Fixed
65
+
66
+ - **HeroSingle, below 720px, with a set height:** the set phone height is a minimum, the section is a column, and the words layer is in the flow and fills it. The hero is the set height or its words, whichever is taller; words that already fit sit where they did. 720px and up is unchanged (the desktop height is still a height, and the phone minimum is cleared there). Measured in Chrome on the live page with these rules: 390x844, hero 506px to 839px, heading top -181px to +152px; 375x667, 400px to 819px, -267px to +152px; 1440x900 unchanged.
67
+ - A hero with no set height keeps its built-in output (`h-screen min-h-[680px]`), byte for byte.
68
+ - Guard: `scripts/test-hero-grows-on-phone.tsx`.
69
+
3
70
  ## 16.0.1 - 2026-10-15
4
71
 
5
72
  **A page opens even when its header and footer cannot be loaded** (card [DESIGN] Edit The Header And Footer On The Page; found by the storefront-blocks isolation guard while pinning 16.0.0). A patch.
@@ -14,7 +14,11 @@ export interface HeroGroupProps {
14
14
  sectionPaddingBottom?: unknown;
15
15
  sectionPaddingTopPhone?: unknown;
16
16
  sectionPaddingBottomPhone?: unknown;
17
+ sectionPaddingLeft?: unknown;
18
+ sectionPaddingRight?: unknown;
19
+ sectionPaddingLeftPhone?: unknown;
20
+ sectionPaddingRightPhone?: unknown;
17
21
  content?: SlotComponent;
18
22
  dragRef?: ((element: Element | null) => void) | null;
19
23
  }
20
- export default function HeroGroup({ placement, nudgeX, nudgeY, width, gap, direction, justify, align, wrap, sectionPaddingTop, sectionPaddingBottom, sectionPaddingTopPhone, sectionPaddingBottomPhone, content: Content, dragRef, }: HeroGroupProps): import("react").JSX.Element;
24
+ export default function HeroGroup({ placement, nudgeX, nudgeY, width, gap, direction, justify, align, wrap, sectionPaddingTop, sectionPaddingBottom, sectionPaddingTopPhone, sectionPaddingBottomPhone, sectionPaddingLeft, sectionPaddingRight, sectionPaddingLeftPhone, sectionPaddingRightPhone, content: Content, dragRef, }: HeroGroupProps): import("react").JSX.Element;
@@ -1 +1 @@
1
- import{jsx as m}from"react/jsx-runtime";import{containerDirectionClass as P,resolveContainerDirection as j}from"../lib/content/container-direction.js";import{containerGapProps as $}from"../lib/content/container-gap.js";import{boxLayoutClasses as C,boxWrapClass as k}from"../lib/content/box-layout.js";import{sectionPadAttrs as v}from"../lib/content/section-padding.js";import{clampNudge as p,clampWidth as D,normalisePlacement as W,placementParts as w,placementRow as A}from"../lib/hero-group-placement.js";function B({placement:c,nudgeX:f,nudgeY:u,width:r,gap:g,direction:t,justify:y,align:h,wrap:x,sectionPaddingTop:d,sectionPaddingBottom:b,sectionPaddingTopPhone:N,sectionPaddingBottomPhone:G,content:n,dragRef:H}){const s=W(c),a=p(f),l=p(u),i=$("HeroGroup",g,j("HeroGroup",t)==="column"?"block":"inline"),o={"--sf-hg-row":A(s),justifySelf:w(s).column};typeof r=="number"&&Number.isFinite(r)&&(o["--sf-hg-w"]=`${D(r)}%`),(a!==0||l!==0)&&(o["--sf-hg-nudge"]=`${a}px ${l}px`);const e=v(d,b,N,G);return m("div",{className:e?`sf-hero-group ${e.className}`:"sf-hero-group","data-hg":s,style:e?{...o,...e.style}:o,ref:H??void 0,children:n?m(n,{className:["sf-hero-group-blocks flex",P("HeroGroup",t),C(y,h),k(x)].filter(Boolean).join(" ")+i.className,style:i.style,minEmptyHeight:40}):null})}export{B as default};
1
+ import{jsx as m}from"react/jsx-runtime";import{containerDirectionClass as k,resolveContainerDirection as v}from"../lib/content/container-direction.js";import{containerGapProps as D}from"../lib/content/container-gap.js";import{boxLayoutClasses as W,boxWrapClass as w}from"../lib/content/box-layout.js";import{sectionPadAttrs as A}from"../lib/content/section-padding.js";import{clampNudge as p,clampWidth as B,normalisePlacement as E,placementParts as F,placementRow as L}from"../lib/hero-group-placement.js";function R({placement:c,nudgeX:f,nudgeY:u,width:r,gap:g,direction:t,justify:y,align:h,wrap:x,sectionPaddingTop:d,sectionPaddingBottom:b,sectionPaddingTopPhone:N,sectionPaddingBottomPhone:G,sectionPaddingLeft:H,sectionPaddingRight:P,sectionPaddingLeftPhone:j,sectionPaddingRightPhone:$,content:n,dragRef:C}){const s=E(c),a=p(f),l=p(u),i=D("HeroGroup",g,v("HeroGroup",t)==="column"?"block":"inline"),o={"--sf-hg-row":L(s),justifySelf:F(s).column};typeof r=="number"&&Number.isFinite(r)&&(o["--sf-hg-w"]=`${B(r)}%`),(a!==0||l!==0)&&(o["--sf-hg-nudge"]=`${a}px ${l}px`);const e=A(d,b,N,G,H,P,j,$);return m("div",{className:e?`sf-hero-group ${e.className}`:"sf-hero-group","data-hg":s,style:e?{...o,...e.style}:o,ref:C??void 0,children:n?m(n,{className:["sf-hero-group-blocks flex",k("HeroGroup",t),W(y,h),w(x)].filter(Boolean).join(" ")+i.className,style:i.style,minEmptyHeight:40}):null})}export{R as default};
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as N}from"react/jsx-runtime";import{useRef as S}from"react";import E from"./HeroPoster.js";import{resolveMedia as s}from"../lib/media.js";import{hasSectionHeight as j,resolveSectionHeight as c}from"../lib/content/section-height.js";import{DEFAULT_OVERLAY_COLOR as z,DEFAULT_OVERLAY_POSITION as L,overlayGradient as O}from"../lib/sections/hero-overlay.js";import{ON_MEDIA_INK_STYLE as A}from"../lib/content/ink.js";function H({overlay:h=100,overlayColor:f=z,overlayPosition:d=L,mediaType:p="image",mediaSrc:r,poster:t,objectPosition:v,tintColor:u="#000000",tintOpacity:i=0,heightDesktop:a,heightMobile:n,boxes:m,editing:x=!1}){const l=j(a,n),g=l?"h-[var(--sf-hero-h-m)] min-[720px]:h-[var(--sf-hero-h-d)]":"h-screen min-h-[680px]",_=l?{"--sf-hero-h-d":c(a),"--sf-hero-h-m":c(n)}:void 0,o=p==="video",b=o?s(r):void 0,w=o?s(t):s(r)??s(t),y=S(null);return N("section",{ref:y,className:`relative mx-[var(--sf-hero-bleed-m,calc(50%_-_50vw))] w-[var(--sf-hero-bleed-w,100vw)] ${g} max-w-[var(--sf-hero-cap,none)] overflow-hidden`,style:_,children:[e("div",{className:"absolute inset-0 z-[1]",children:e(E,{videoSrc:b,posterSrc:w,showVideo:o,objectPosition:v})}),i>0&&e("div",{className:"pointer-events-none absolute inset-0 z-[2]",style:{background:u,opacity:Math.min(Math.max(i,0),100)/100}}),e("div",{className:"pointer-events-none absolute inset-0 z-[2]",style:{background:O(f,d),opacity:Math.min(Math.max(h,0),100)/100}}),m&&e("div",{className:["sf-hero-group-layer absolute inset-0 z-[3] mx-auto","max-w-[min(var(--sf-page-cap,var(--sf-site-width,1600px)),var(--sf-site-width,1600px))]","px-[var(--sf-site-gutter,40px)] pt-[140px] pb-14",x?"sf-hero-group-layer-edit":""].filter(Boolean).join(" "),style:A,children:e(m,{className:"sf-hero-group-zone",minEmptyHeight:160})})]})}export{H as default};
1
+ "use client";import{jsx as e,jsxs as S}from"react/jsx-runtime";import{useRef as E}from"react";import j from"./HeroPoster.js";import{resolveMedia as o}from"../lib/media.js";import{hasSectionHeight as z,resolveSectionHeight as c}from"../lib/content/section-height.js";import{DEFAULT_OVERLAY_COLOR as L,DEFAULT_OVERLAY_POSITION as O,overlayGradient as A}from"../lib/sections/hero-overlay.js";import{ON_MEDIA_INK_STYLE as H}from"../lib/content/ink.js";function M({overlay:h=100,overlayColor:f=L,overlayPosition:p=O,mediaType:d="image",mediaSrc:t,poster:i,objectPosition:x,tintColor:v="#000000",tintOpacity:a=0,heightDesktop:n,heightMobile:m,boxes:l,editing:u=!1}){const s=z(n,m),g=s?"min-h-[var(--sf-hero-h-m)] max-[720px]:flex max-[720px]:flex-col min-[720px]:min-h-0 min-[720px]:h-[var(--sf-hero-h-d)]":"h-screen min-h-[680px]",w=s?"max-[720px]:relative max-[720px]:flex-auto":"",_=s?{"--sf-hero-h-d":c(n),"--sf-hero-h-m":c(m)}:void 0,r=d==="video",b=r?o(t):void 0,y=r?o(i):o(t)??o(i),N=E(null);return S("section",{ref:N,className:`relative mx-[var(--sf-hero-bleed-m,calc(50%_-_50vw))] w-[var(--sf-hero-bleed-w,100vw)] ${g} max-w-[var(--sf-hero-cap,none)] overflow-hidden`,style:_,children:[e("div",{className:"absolute inset-0 z-[1]",children:e(j,{videoSrc:b,posterSrc:y,showVideo:r,objectPosition:x})}),a>0&&e("div",{className:"pointer-events-none absolute inset-0 z-[2]",style:{background:v,opacity:Math.min(Math.max(a,0),100)/100}}),e("div",{className:"pointer-events-none absolute inset-0 z-[2]",style:{background:A(f,p),opacity:Math.min(Math.max(h,0),100)/100}}),l&&e("div",{className:["sf-hero-group-layer absolute inset-0 z-[3] mx-auto",w,"max-w-[min(var(--sf-page-cap,var(--sf-site-width,1600px)),var(--sf-site-width,1600px))]","px-[var(--sf-site-gutter,40px)] pt-[140px] pb-14",u?"sf-hero-group-layer-edit":""].filter(Boolean).join(" "),style:H,children:e(l,{className:"sf-hero-group-zone",minEmptyHeight:160})})]})}export{M as default};
@@ -4,15 +4,6 @@ import { type FontRole, type FontsValue } from "../lib/fonts.js";
4
4
  import { type TypeGroup } from "../lib/theme.js";
5
5
  import { type PartStyle, type PartStyleBase } from "../lib/puck/part-styles.js";
6
6
  import { type PartSource } from "../lib/puck/source-bound-parts.js";
7
- export declare const PART_FIELDS: readonly [{
8
- readonly key: "font";
9
- readonly label: "Font";
10
- readonly group: "Style";
11
- }, {
12
- readonly key: "color";
13
- readonly label: "Color";
14
- readonly group: "Style";
15
- }];
16
7
  export type PartFace = {
17
8
  kind: "role";
18
9
  role: FontRole;
@@ -32,22 +23,11 @@ export declare function partFace(props: Record<string, unknown>, propKey: string
32
23
  faceRole: FontRole;
33
24
  base: PartStyleBase;
34
25
  } | null, fonts: FontsValue): PartFace;
35
- export declare function partStyleName(props: Record<string, unknown>, propKey: string, reading: {
36
- faceRole: FontRole;
37
- base: PartStyleBase;
38
- } | null, fonts: FontsValue): string | null;
39
26
  export declare function PartStyleSelect({ face, base, onPick, }: {
40
27
  face: PartFace;
41
28
  base: PartStyleBase | null;
42
29
  onPick: (role: FontRole | null) => void;
43
30
  }): import("react").JSX.Element;
44
- export declare function PartStyleCard({ parts, onEditStyle, onClearAll, onFollowStyle, kindLabel, }: {
45
- parts: readonly PanelPart[];
46
- onEditStyle?: () => void;
47
- onClearAll: () => void;
48
- onFollowStyle?: (role: FontRole | null) => void;
49
- kindLabel?: string;
50
- }): import("react").JSX.Element;
51
31
  export { PartResetDot };
52
32
  export declare function PartPanelBody({ sectionName, onBack, textEditor, styleRow, children, }: {
53
33
  sectionName: string;
@@ -1 +1 @@
1
- "use client";import{jsx as t,jsxs as u,Fragment as _}from"react/jsx-runtime";import{useEffect as W,useId as $e,useRef as Z,useState as ee}from"react";import{PartResetDot as ye}from"./PartResetDot.js";import{FieldSelect as ge,InspectorField as De}from"efficient-easel/fields";import{SettingsField as be,SettingsGroup as Ve}from"efficient-easel/panel";import{InspectorUpLevel as G}from"efficient-easel/chrome";import{StylesIcon as Be,TextColorIcon as Me,TypeIcon as Se}from"efficient-easel/icons";import{useEasel as We}from"efficient-easel/easel";import{Tooltip as Ge}from"efficient-shell/ui";import{PartInkControl as je}from"./PartInkControl.js";import{PartTextBox as Ue}from"./PartTextBox.js";import xe from"./UiIcon.js";import{usePreviewHeader as He}from"./PreviewHeaderContext.js";import{usePartStyle as Ke}from"./PreviewPartStyleContext.js";import{say as o}from"../lib/editor-words.js";import{readHidable as j,textFieldOffPage as Xe}from"../lib/puck/controls.js";import{TEXT_FIELD_MARKER as Ye}from"../lib/puck/field-markers.js";import{useSectionOps as qe}from"../lib/puck/use-section-ops.js";import{FONT_OPTIONS as Je,FONT_ROLES as te,FONT_ROLE_LABELS as ne,fontOption as L}from"../lib/fonts.js";import{isMultilineKind as Qe,partPlaceholder as Ze,typeInPlaceKind as et}from"../lib/puck/part-text.js";import{partRowField as tt}from"../lib/puck/part-row-field.js";import{decodePartKey as nt,partPropsWithRowValue as ot,partRowValue as st}from"../lib/puck/part-rows.js";import{PART_WIDTH_MAX as lt,propsWithPartStyleValue as oe,propsWithoutPartStyle as rt,readPartStyle as ve}from"../lib/puck/part-styles.js";import{partInks as at}from"../lib/puck/part-inks.js";import{styleKeyForPart as it,TEXT_KIND_LABELS as ct}from"../lib/sections/section-text-kinds.js";import{commitPartText as dt}from"../lib/puck/part-typing.js";import{keysOnCanvas as ut,useCanvasTypingPart as ft}from"../lib/puck/canvas-typing.js";import{useEditorHost as pt}from"../lib/editor-host.js";import{SOURCE_LINES as mt,SOURCE_ACTIONS as ht,SOURCE_ACTION_LABEL as yt,partSourceOf as gt,sourceSlugOf as Ne}from"../lib/puck/source-bound-parts.js";import{encodePartId as bt,holdsAuthoredText as St}from"../lib/puck/text-parts.js";import{regionsForSection as xt}from"../lib/sections/section-text-regions.js";import{textRegionOfPartKey as vt}from"../lib/sections/text-regions.js";const Nt={400:"Regular",500:"Medium",600:"Semibold",700:"Bold"},ke=[{key:"font",label:"Font",group:"Style"},{key:"color",label:"Color",group:"Style"}],kt=[...new Set(ke.map(e=>e.group))],Pt={font:t(Se,{}),color:t(Me,{})};function A(e){return e?o(e):null}function R(e){return e.kind==="role"?ne[e.role]:e.kind==="custom"?"Custom":null}const wt=e=>e.kind==="role"?`role:${e.role}`:e.kind;function Tt(e){const n=e.role;return n&&te.includes(n)?{kind:"role",role:n}:null}function Et(e,n){if(!e)return{kind:"unread"};const{faceRole:l,base:r}=e;if(n[l]===r.fontKey)return{kind:"role",role:l};const c=Object.keys(n).filter(i=>n[i]===r.fontKey);return c.length===1?{kind:"role",role:c[0]}:{kind:"custom"}}function se(e,n,l,r){return Tt(ve(e,n))??Et(l,r)}function Sn(e,n,l,r){return R(se(e,n,l,r))}function le(e,n){if(!e.length)return null;const l=n(e[0]);return e.every(r=>n(r)===l)?l:null}function Ct(e){return Object.values(e).filter(n=>n!==void 0).length}function Rt(e,n){const l=e.style[n];return n==="color"?l??"":l!==void 0?String(l):e.base.fontKey}function Ft({face:e,base:n,onPick:l}){const[r,c]=ee(!1),i=Z(null),y=Z(null),g=$e();W(()=>{if(!r)return;const a=E=>{i.current&&!i.current.contains(E.target)&&c(!1)};return document.addEventListener("mousedown",a),()=>document.removeEventListener("mousedown",a)},[r]);const f=e.kind==="role"?e.role:null,x=a=>{l(a),c(!1),y.current?.focus()};return u("div",{className:"sf-part-style-pick",ref:i,children:[u("button",{ref:y,type:"button",className:"sf-part-style-trigger","aria-expanded":r,"aria-controls":g,"aria-label":R(e)?o("Follows {name} — change",{name:A(R(e))}):o("Follows no style — change"),onClick:()=>c(a=>!a),onKeyDown:a=>{a.key==="Escape"&&r&&(a.preventDefault(),c(!1))},children:[t("span",{className:"sf-part-style-name",style:{fontFamily:n?.fontKey?`var(${L(n.fontKey)?.cssVar})`:void 0,fontWeight:n?.weight},children:A(R(e))}),t("span",{className:"sf-part-style-sign","aria-hidden":"true"})]}),r&&u("div",{className:"sf-multi-menu sf-part-style-menu",id:g,role:"listbox",onKeyDown:a=>{a.key==="Escape"&&(a.preventDefault(),c(!1),y.current?.focus())},children:[u("button",{type:"button",role:"option","aria-selected":f===null,className:`sf-part-style-option${f===null?" is-on":""}`,onClick:()=>x(null),children:[t("span",{className:"sf-part-style-option-name",children:o("No style")}),t("span",{className:"sf-note",children:o("Section’s own")})]}),te.map(a=>t("button",{type:"button",role:"option","aria-selected":f===a,className:`sf-part-style-option${f===a?" is-on":""}`,onClick:()=>x(a),children:t("span",{className:"sf-part-style-option-name",style:{fontFamily:`var(--font-role-${a})`},children:o(ne[a])})},a))]})]})}const U="";function Ot({face:e,base:n,onPick:l}){const r=e.kind==="role"?e.role:U,c=[{label:o("No style"),value:U},...te.map(i=>({label:o(ne[i]),value:i}))];return t(ge,{ariaLabel:o("Style"),value:r,options:c,inline:!0,onChange:i=>l(i===U?null:i),renderOption:i=>i.value===U?u(_,{children:[t("span",{className:"es-fsel-label sf-part-style-keep",children:i.label}),t("span",{className:"sf-part-style-aside","aria-hidden":"true",children:o("Section’s own")})]}):t("span",{className:"es-fsel-label",style:{fontFamily:`var(--font-role-${i.value})`},children:i.label}),renderValue:()=>t("span",{style:{fontFamily:n?.fontKey?`var(${L(n.fontKey)?.cssVar})`:void 0,fontWeight:n?.weight},children:A(R(e))}),valueText:i=>A(R(e))??i?.label??""})}function It({parts:e,onEditStyle:n,onClearAll:l,onFollowStyle:r,kindLabel:c}){const y=le(e,E=>wt(E.face))?e[0].face:null,g=y?R(y):null,f=y&&y.kind!=="unread"?e[0].base:null,x=e.reduce((E,H)=>E+Ct(H.style),0),a=f?L(f.fontKey)?.label:void 0;return u("div",{className:`sf-part-style${x?" has-overrides":""}`,children:[t("div",{className:"sf-part-style-caption",children:o("Style")}),e.length>1&&t("div",{className:"sf-part-style-count",children:o("{n} selected",{n:e.length})}),e.length===1&&c&&t("div",{className:"sf-part-style-count",children:o("{kind} · every row",{kind:o(c)})}),g&&f?u(_,{children:[r&&y?t(Ft,{face:y,base:f,onPick:r}):t("div",{className:"sf-part-style-name",style:{fontFamily:a?`var(${L(f.fontKey)?.cssVar})`:void 0,fontWeight:f.weight},children:o(g)}),t("div",{className:"sf-part-style-meta",children:[a,`${Math.round(f.sizePx)} px`,o(Nt[f.weight])].filter(Boolean).join(" · ")})]}):t("div",{className:"sf-part-style-name",children:o("Mixed styles")}),u("div",{className:"sf-part-style-top",children:[g?x?u(_,{children:[t("span",{className:"sf-part-chip",children:o("{n} changed",{n:x})}),t("button",{type:"button",className:"sf-part-link",onClick:l,children:o("Clear")})]}):t("span",{className:"sf-part-style-state",children:o("This text follows the site style.")}):t("span",{className:"sf-part-style-state",children:o("Changes apply to all selected.")}),t("span",{className:"sf-part-style-gap"}),g&&n&&t("button",{type:"button",className:"sf-part-link",onClick:n,children:o("Edit")})]})]})}function _t({sectionName:e,onBack:n,textEditor:l,styleRow:r,children:c}){return u("div",{className:"sf-part-panel",children:[t(G,{inline:!0,name:o(e),onSelect:n}),l,r,c]})}function Pe({source:e,slug:n}){const l=pt(),r=ht[e],c=!r.needsSlug||!!n;return t("div",{className:"sf-note sf-note--source",children:u("p",{className:"es-field-hint sf-hint-keep",children:[o(mt[e]),c?u(_,{children:[" ",t("button",{type:"button",className:"sf-source-open",onClick:()=>{r.type==="storefront-editor:open-menus"?l.send(r.type):n&&l.send(r.type,{slug:n})},children:o(yt)})]}):null]})})}const we=4,Lt=120;function At({region:e,sizePx:n,face:l,base:r,onFollowStyle:c,source:i,slug:y,onBack:g}){const f=e.follows;return u("div",{className:"sf-note",children:[t("p",{children:t("strong",{children:o(e.label)})}),t("p",{children:n?o("Its size follows Site styles ▸ {follows} — {px}px right now.",{follows:o(f),px:Math.round(n)}):o("Its size follows Site styles ▸ {follows}.",{follows:o(f)})}),c?t(_,{children:t(be,{label:o("Style"),icon:t(Be,{}),hint:o("Every {part} in this section follows it. The face and the size change; the letter case is the section’s own and stays as it is.",{part:o(e.label).toLowerCase()}),children:t(Ot,{face:l,base:r,onPick:c})})}):t("p",{className:"es-field-hint sf-hint-keep",children:o("Only the size follows a site style. This section sets its own font, weight and letter case.")}),i?t(Pe,{source:i,slug:y}):null,t(G,{inline:!0,name:o("Page"),onSelect:g})]})}function zt({onBack:e}){return u("div",{className:"sf-note",children:[t("p",{children:t("strong",{children:o("This part is no longer here.")})}),t("p",{children:o("The section it belonged to has been changed or removed.")}),t(G,{inline:!0,name:o("Page"),onSelect:e})]})}function $t({onBack:e,partId:n,why:l}){return u("div",{className:"sf-note",children:[t("p",{children:t("strong",{children:o("This part's settings did not open.")})}),t("p",{children:o("The words are still on your page and nothing has been lost. The editor could not work out which control belongs to them, which is a fault on our side. Go back and click the section to open its settings instead.")}),t("p",{className:"sf-note-detail",children:u("code",{children:[n," — ",l]})}),t(G,{inline:!0,name:o("Page"),onSelect:e})]})}function Dt({nodeId:e,propKey:n,onBack:l,onEditStyle:r}){const{getItemById:c,getSelectorForId:i,config:y}=We(s=>s),g=qe(),f=ft(),{partStyle:x}=Ke(),{fonts:a}=He(),[E,H]=ee({}),re=Z(null),b=c(e),v=i(e),ae=b?y.components[b.type]:void 0,{key:C,row:P}=nt(n),ie=ae?.fields?.[C],w=P?tt(ie,P):ie,F=bt(e,n),m=b?.props??{},T=et(w),Te=Xe(w),Ee=St(w),K=b?gt(b.type):null,X=P?st(m[C],P):m[C],ce=!!P&&!(Array.isArray(m[C])&&P.index<m[C].length);W(()=>{if(ut(document))return;re.current?.querySelector(".es-copy [contenteditable='true'], .es-copy textarea, .sf-copybox textarea, .sf-copybox input")?.focus()},[F]);const[Y,de]=ee(0);W(()=>de(0),[F]);const q=!!b&&!ce&&(!v||!w);W(()=>{if(!q||Y>=we)return;const s=setTimeout(()=>de(d=>d+1),Lt);return()=>clearTimeout(s)},[q,Y]);const Ce=q&&Y<we;if(!b||ce)return t(zt,{onBack:l});const z=xt(b.type),ue=z?vt(z,n):null;if(z&&ue){const s=x?.partId===F?x:null,d=z[ue],h=d.writable===!0&&!!v,S=p=>{v&&g.replaceComponent(v.zone,v.index,{...b,props:oe(m,n,"role",p)})};return t(At,{region:d,sizePx:s?.base.sizePx??null,face:se(m,n,s,a),base:s?.base??null,onFollowStyle:h?S:void 0,source:K,slug:Ne(m),onBack:l})}if(!v||!w)return Ce?t("div",{className:"sf-note","aria-busy":"true"}):t($t,{onBack:l,partId:F,why:v?"no field":"no selector"});const $=s=>{g.replaceComponent(v.zone,v.index,{...b,props:s})},J=s=>{if(j(s).hidden!==j(X).hidden||!T){const h=P?ot(m,C,P,s):{...m,[C]:s};h&&$(h);return}dt({node:b,propKey:n,kind:T,zone:v.zone,index:v.index},j(s).text,g.replaceComponent)},Re=X,D=it(b?.type,n),Fe=ve(m,D),V=x?.partId===F?x:null,N=[{partKey:D,face:se(m,D,V,a),sizeGroup:V?.sizeGroup??null,base:V?.base??Vt,style:Fe}],Oe=le(N,s=>s.sizeGroup),fe=at(V?.inks),B=(s,d)=>{let h=m;for(const S of N)h=oe(h,S.partKey,s,d);$(h)},Ie=s=>B("role",s),_e=()=>{let s=m;for(const d of N)s=rt(s,d.partKey);$(s)},Le=s=>{let d=m;for(const h of N)for(const[S,p]of Object.entries(s))d=oe(d,h.partKey,S,p??null);$(d)},Ae=(s,d)=>{const h=N.some(k=>k.style[s]!==void 0),S=le(N,k=>Rt(k,s)),p=S===null,O=`sf-part-${e}-${n}-${s}`;return s==="color"?t(je,{value:p?null:String(S),label:d,colors:fe,onChange:k=>B("color",k)},s):t(be,{label:o(d),icon:Pt[s],className:"sf-part-field",changed:h,htmlFor:O,action:h?t(ye,{label:d,onClear:()=>B(s,null)}):void 0,children:s==="font"?t(ge,{id:O,ariaLabel:o(d),value:!p&&L(String(S))?String(S):void 0,placeholder:p?o("Mixed"):o("Site style"),options:Je.map(k=>({label:k.label,value:k.key})),onChange:k=>B("font",k||null)}):null},s)},pe=T==="text"||T==="textarea",{text:me,hidden:I}=j(X),M=w?.[Ye]?.label??n,he=I?o("Show {label} on the slide",{label:o(M)}):o("Hide {label} on the slide",{label:o(M)}),ze=u("div",{className:"sf-field-head",children:[t(Se,{}),t("span",{className:"sf-field-label sf-field-label--inline",children:o(M)}),pe&&t(Ge,{content:he,children:t("button",{type:"button",className:"sf-field-eye","aria-pressed":I,"aria-label":he,onClick:()=>J({text:me,hidden:!I}),children:I?t(xe,{name:"eye-off",size:14}):t(xe,{name:"eye",size:14})})})]}),Q=!Te&&Ee;return u(_t,{sectionName:ae?.label??b.type,onBack:l,textEditor:u("div",{ref:re,className:"sf-part-text",children:[T?t(Ue,{text:me,onTextChange:s=>J(pe?{text:s,hidden:I}:s),multiline:Qe(T),markup:T!=="plainText",styled:Q,style:N[0].style,base:N[0].base,setValue:Le,colors:fe.map(s=>({name:s.key,label:o(s.name),value:s.value})),placeholder:A(Ze(w))??void 0,ariaLabel:o(M),head:ze,typedOnCanvas:f===F}):t(De,{field:w,name:n,value:Re,onChange:J,id:`sf-part-${e}-${n}`}),Q&&T&&Oe===null&&t("p",{className:"es-field-hint sf-hint-keep",children:o("Fixed size — the site’s Text setting doesn’t resize this.")})]}),children:[K&&t(Pe,{source:K,slug:Ne(m)}),Q&&kt.map(s=>{const d=ke.filter(p=>p.group===s),h=d.filter(p=>N.some(O=>O.style[p.key]!==void 0)).length,S=`sf-part-g-${e}-${n}-${s.replace(/\W+/g,"-")}`;return u(Ve,{id:S,title:o(s),open:E[s]!==!0,onToggle:p=>H(O=>({...O,[s]:!p})),count:h,children:[t(It,{parts:N,onEditStyle:r,onClearAll:_e,onFollowStyle:Ie,kindLabel:ct[D]}),d.map(p=>Ae(p.key,p.label))]},s)})]})}const Vt={fontKey:"",sizePx:16,weight:400,lineRatio:1.4,letterEm:0,align:"left",case:"none",paddingPx:0,widthPx:lt};export{ke as PART_FIELDS,_t as PartPanelBody,ye as PartResetDot,Pe as PartSourceNote,It as PartStyleCard,Ot as PartStyleSelect,Dt as default,se as partFace,Sn as partStyleName};
1
+ "use client";import{jsx as n,Fragment as D,jsxs as h}from"react/jsx-runtime";import{useEffect as $,useRef as Re,useState as Ce}from"react";import{PartResetDot as _e}from"./PartResetDot.js";import{FieldSelect as Fe,InspectorField as Ie}from"efficient-easel/fields";import{SettingsField as ze}from"efficient-easel/panel";import{InspectorUpLevel as z}from"efficient-easel/chrome";import{StylesIcon as Ae,TypeIcon as Le}from"efficient-easel/icons";import{useEasel as Ve}from"efficient-easel/easel";import{TextPartPanel as Be}from"efficient-easel/copy";import{Tooltip as Ke}from"efficient-shell/ui";import{PartTextBox as je,partTextCells as Ge}from"./PartTextBox.js";import he from"./UiIcon.js";import{usePreviewHeader as Me}from"./PreviewHeaderContext.js";import{usePartStyle as Ue}from"./PreviewPartStyleContext.js";import{say as l}from"../lib/editor-words.js";import{readHidable as A,textFieldOffPage as We,textFieldPanelOnly as He}from"../lib/puck/controls.js";import{TEXT_FIELD_MARKER as De}from"../lib/puck/field-markers.js";import{useSectionOps as $e}from"../lib/puck/use-section-ops.js";import{FONT_OPTIONS as Ye,FONT_ROLES as Y,FONT_ROLE_LABELS as X,fontOption as q}from"../lib/fonts.js";import{isMultilineKind as Xe,partPlaceholder as qe,typeInPlaceKind as Je}from"../lib/puck/part-text.js";import{partRowField as Qe}from"../lib/puck/part-row-field.js";import{decodePartKey as Ze,partPropsWithRowValue as et,partRowValue as tt}from"../lib/puck/part-rows.js";import{PART_WIDTH_MAX as nt,propsWithPartStyleValue as L,propsWithoutPartStyle as ot,readPartStyle as ye}from"../lib/puck/part-styles.js";import{partInks as lt}from"../lib/puck/part-inks.js";import{styleKeyForPart as st}from"../lib/sections/section-text-kinds.js";import{commitPartText as rt}from"../lib/puck/part-typing.js";import{keysOnCanvas as it,useCanvasTypingPart as at}from"../lib/puck/canvas-typing.js";import{useEditorHost as ct}from"../lib/editor-host.js";import{SOURCE_LINES as dt,SOURCE_ACTIONS as ut,SOURCE_ACTION_LABEL as ft,partSourceOf as pt,sourceSlugOf as ge}from"../lib/puck/source-bound-parts.js";import{encodePartId as mt,holdsAuthoredText as ht}from"../lib/puck/text-parts.js";import{regionsForSection as yt}from"../lib/sections/section-text-regions.js";import{textRegionOfPartKey as gt}from"../lib/sections/text-regions.js";function J(t){return t?l(t):null}function be(t){return t.kind==="role"?X[t.role]:t.kind==="custom"?"Custom":null}function bt(t){const o=t.role;return o&&Y.includes(o)?{kind:"role",role:o}:null}function xt(t,o){if(!t)return{kind:"unread"};const{faceRole:s,base:r}=t;if(o[s]===r.fontKey)return{kind:"role",role:s};const d=Object.keys(o).filter(i=>o[i]===r.fontKey);return d.length===1?{kind:"role",role:d[0]}:{kind:"custom"}}function Q(t,o,s,r){return bt(ye(t,o))??xt(s,r)}function St(t,o){if(!t.length)return null;const s=o(t[0]);return t.every(r=>o(r)===s)?s:null}const V="";function Pt({face:t,base:o,onPick:s}){const r=t.kind==="role"?t.role:V,d=[{label:l("No style"),value:V},...Y.map(i=>({label:l(X[i]),value:i}))];return n(Fe,{ariaLabel:l("Style"),value:r,options:d,inline:!0,onChange:i=>s(i===V?null:i),renderOption:i=>i.value===V?h(D,{children:[n("span",{className:"es-fsel-label sf-part-style-keep",children:i.label}),n("span",{className:"sf-part-style-aside","aria-hidden":"true",children:l("Section’s own")})]}):n("span",{className:"es-fsel-label",style:{fontFamily:`var(--font-role-${i.value})`},children:i.label}),renderValue:()=>n("span",{style:{fontFamily:o?.fontKey?`var(${q(o.fontKey)?.cssVar})`:void 0,fontWeight:o?.weight},children:J(be(t))}),valueText:i=>J(be(t))??i?.label??""})}function vt({sectionName:t,onBack:o,textEditor:s,styleRow:r,children:d}){return h("div",{className:"sf-part-panel",children:[n(z,{inline:!0,name:l(t),onSelect:o}),s,r,d]})}function xe({source:t,slug:o}){const s=ct(),r=ut[t],d=!r.needsSlug||!!o;return n("div",{className:"sf-note sf-note--source",children:h("p",{className:"es-field-hint sf-hint-keep",children:[l(dt[t]),d?h(D,{children:[" ",n("button",{type:"button",className:"sf-source-open",onClick:()=>{r.type==="storefront-editor:open-menus"?s.send(r.type):o&&s.send(r.type,{slug:o})},children:l(ft)})]}):null]})})}const Se=4,Tt=120;function wt({region:t,sizePx:o,face:s,base:r,onFollowStyle:d,source:i,slug:B,onBack:T}){const O=t.follows;return h("div",{className:"sf-note",children:[n("p",{children:n("strong",{children:l(t.label)})}),n("p",{children:o?l("Its size follows Site styles ▸ {follows} — {px}px right now.",{follows:l(O),px:Math.round(o)}):l("Its size follows Site styles ▸ {follows}.",{follows:l(O)})}),d?n(D,{children:n(ze,{label:l("Style"),icon:n(Ae,{}),hint:l("Every {part} in this section follows it. The face and the size change; the letter case is the section’s own and stays as it is.",{part:l(t.label).toLowerCase()}),children:n(Pt,{face:s,base:r,onPick:d})})}):n("p",{className:"es-field-hint sf-hint-keep",children:l("Only the size follows a site style. This section sets its own font, weight and letter case.")}),i?n(xe,{source:i,slug:B}):null,n(z,{inline:!0,name:l("Page"),onSelect:T})]})}function kt({onBack:t}){return h("div",{className:"sf-note",children:[n("p",{children:n("strong",{children:l("This part is no longer here.")})}),n("p",{children:l("The section it belonged to has been changed or removed.")}),n(z,{inline:!0,name:l("Page"),onSelect:t})]})}function Nt({onBack:t,partId:o,why:s}){return h("div",{className:"sf-note",children:[n("p",{children:n("strong",{children:l("This part's settings did not open.")})}),n("p",{children:l("The words are still on your page and nothing has been lost. The editor could not work out which control belongs to them, which is a fault on our side. Go back and click the section to open its settings instead.")}),n("p",{className:"sf-note-detail",children:h("code",{children:[o," — ",s]})}),n(z,{inline:!0,name:l("Page"),onSelect:t})]})}function Ot({nodeId:t,propKey:o,onBack:s,onEditStyle:r}){const{getItemById:d,getSelectorForId:i,config:B}=Ve(e=>e),T=$e(),O=at(),{partStyle:E}=Ue(),{fonts:R,textStyles:Pe}=Me(),Z=Re(null),u=d(t),p=i(t),ee=u?B.components[u.type]:void 0,{key:x,row:b}=Ze(o),te=ee?.fields?.[x],y=b?Qe(te,b):te,S=mt(t,o),c=u?.props??{},g=Je(y),ne=We(y),oe=ht(y),K=u?pt(u.type):null,j=b?tt(c[x],b):c[x],le=!!b&&!(Array.isArray(c[x])&&b.index<c[x].length);$(()=>{if(it(document))return;Z.current?.querySelector(".es-copy [contenteditable='true'], .es-copy textarea, .sf-copybox textarea, .sf-copybox input")?.focus()},[S]);const[G,se]=Ce(0);$(()=>se(0),[S]);const M=!!u&&!le&&(!p||!y);$(()=>{if(!M||G>=Se)return;const e=setTimeout(()=>se(a=>a+1),Tt);return()=>clearTimeout(e)},[M,G]);const ve=M&&G<Se;if(!u||le)return n(kt,{onBack:s});const C=yt(u.type),re=C?gt(C,o):null;if(C&&re){const e=E?.partId===S?E:null,a=C[re],f=a.writable===!0&&!!p,N=H=>{p&&T.replaceComponent(p.zone,p.index,{...u,props:L(c,o,"role",H)})};return n(wt,{region:a,sizePx:e?.base.sizePx??null,face:Q(c,o,e,R),base:e?.base??null,onFollowStyle:f?N:void 0,source:K,slug:ge(c),onBack:s})}if(!p||!y)return ve?n("div",{className:"sf-note","aria-busy":"true"}):n(Nt,{onBack:s,partId:S,why:p?"no field":"no selector"});const _=e=>{T.replaceComponent(p.zone,p.index,{...u,props:e})},U=e=>{if(A(e).hidden!==A(j).hidden||!g){const f=b?et(c,x,b,e):{...c,[x]:e};f&&_(f);return}rt({node:u,propKey:o,kind:g,zone:p.zone,index:p.index},A(e).text,T.replaceComponent)},Te=j,F=st(u?.type,o),P=ye(c,F),w=E?.partId===S?E:null,m=[{partKey:F,face:Q(c,F,w,R),sizeGroup:w?.sizeGroup??null,base:w?.base??Ct,style:P}],we=St(m,e=>e.sizeGroup),ke=lt(w?.inks),k=(e,a)=>{let f=c;for(const N of m)f=L(f,N.partKey,e,a);_(f)},Ne=e=>k("role",e),ie=e=>{let a=c;for(const f of m)for(const[N,H]of Object.entries(e))a=L(a,f.partKey,N,H??null);_(a)},W=g==="text"||g==="textarea",{text:ae,hidden:v}=A(j),I=y?.[De]?.label??o,ce=v?l("Show {label} on the slide",{label:l(I)}):l("Hide {label} on the slide",{label:l(I)}),de=h("div",{className:"sf-field-head",children:[n(Le,{}),n("span",{className:"sf-field-label sf-field-label--inline",children:l(I)}),W&&n(Ke,{content:ce,children:n("button",{type:"button",className:"sf-field-eye","aria-pressed":v,"aria-label":ce,onClick:()=>U({text:ae,hidden:!v}),children:v?n(he,{name:"eye-off",size:14}):n(he,{name:"eye",size:14})})})]}),ue=!ne&&oe,Oe=!!g&&(He(y)||ne||v||!oe||g!=="plainText"),fe=Q(c,F,w,R),pe=fe.kind==="role"?fe.role:null,me=Object.entries(P).filter(([e,a])=>e!=="role"&&a!==void 0).length,Ee=()=>{let e=c;for(const a of m){const f=a.style.role;e=ot(e,a.partKey),f&&(e=L(e,a.partKey,"role",f))}_(e)};return h(vt,{sectionName:ee?.label??u.type,onBack:s,textEditor:n("div",{ref:Z,className:"sf-part-text",children:Oe?n(je,{text:ae,onTextChange:e=>U(W?{text:e,hidden:v}:e),multiline:Xe(g),markup:g!=="plainText",styled:!1,style:m[0].style,base:m[0].base,setValue:ie,colors:ke.map(e=>({name:e.key,label:l(e.name),value:e.value})),placeholder:J(qe(y))??void 0,ariaLabel:l(I),head:de,typedOnCanvas:O===S}):g?W?de:null:n(Ie,{field:y,name:o,value:Te,onChange:U,id:`sf-part-${t}-${o}`})}),children:[K&&n(xe,{source:K,slug:ge(c)}),ue&&n(Be,{style:{value:pe??"",options:[{value:"",label:l("No style"),description:l("Section’s own")},...Y.map(e=>({value:e,label:l(X[e]),description:q(R[e])?.label}))],onChange:e=>Ne(e||null),changed:me>0,onClearChanges:me>0?Ee:void 0,onEditStyles:r},font:{value:P.font??"",styleValue:q(m[0].base.fontKey)?.label,options:Ye.map(e=>({label:e.label,value:e.key})),onChange:e=>k("font",e||null)},italic:{value:P.italic,styleValue:Rt(Pe,pe),onChange:e=>k("italic",e??null)},cells:Ge(m[0].style,m[0].base,ie),align:{value:P.align??"",styleValue:m[0].base.align,onChange:e=>k("align",e||null)},letterCase:{value:P.case??"",styleValue:m[0].base.case,onChange:e=>k("case",e||null)}}),ue&&we===null&&n("p",{className:"es-field-hint sf-hint-keep",children:l("Fixed size — the site’s Text setting doesn’t resize this.")})]})}const Et={heading:"heading-1",heading2:"heading-2",heading3:"heading-3",body:"body-1",label:"body-5"};function Rt(t,o){const s=o?Et[o]:void 0;return!s||!Array.isArray(t)?!1:t.find(d=>d?.id===s)?.values?.italic===!0}const Ct={fontKey:"",sizePx:16,weight:400,lineRatio:1.4,letterEm:0,align:"left",case:"none",paddingPx:0,widthPx:nt};export{vt as PartPanelBody,_e as PartResetDot,xe as PartSourceNote,Pt as PartStyleSelect,Ot as default,Q as partFace};
@@ -1,9 +1,10 @@
1
1
  import type { ReactNode } from "react";
2
- import { type CopyThemeColor } from "efficient-easel/copy";
2
+ import { type CopyCell, type CopyThemeColor } from "efficient-easel/copy";
3
3
  import { type PartStyle, type PartStyleBase } from "../lib/puck/part-styles.js";
4
4
  export type PartStylePatch = {
5
5
  [K in keyof PartStyle]?: PartStyle[K] | null;
6
6
  };
7
+ export declare function partTextCells(style: PartStyle, base: PartStyleBase, setValue: (patch: PartStylePatch) => void): CopyCell[];
7
8
  export declare function PartTextBox({ text, onTextChange, multiline, markup, styled, style, base, setValue, colors, placeholder, ariaLabel, head, typedOnCanvas, }: {
8
9
  text: string;
9
10
  onTextChange: (next: string) => void;
@@ -1 +1 @@
1
- "use client";import{jsx as o,jsxs as T}from"react/jsx-runtime";import{COPY_CELLS as l,CopyBox as A}from"efficient-easel/copy";import{PaddingYIcon as C,WidthIcon as I}from"efficient-easel/icons";import{say as u}from"../lib/editor-words.js";import{SHOP_MARKUP as R}from"../lib/markup.js";import{partTextTools as D}from"../lib/puck/canvas-typing.js";import{PART_PADDING_MAX as v,PART_PADDING_MIN as H,PART_PADDING_STEP as w,PART_WIDTH_MAX as z,PART_WIDTH_MIN as N,PART_WIDTH_STEP as M,partSpacingOf as j}from"../lib/puck/part-styles.js";const E=["left","center","right","justify"];function Y({text:c,onTextChange:d,multiline:r,markup:p=!0,styled:t=!0,style:e,base:a,setValue:i,colors:h,placeholder:s,ariaLabel:P,head:f,typedOnCanvas:m=!1}){const g=j(e),x=e.size??a.sizePx,_=[{...l.fontSize,value:e.size,styleValue:Math.round(a.sizePx),onChange:n=>i({size:n??null})},{...l.lineHeight,value:g.lineHeight,styleValue:a.lineRatio,onChange:n=>i(n===void 0?{lineHeight:null,line:null}:{lineHeight:n})},{...l.letterSpacing,scale:x,value:g.letterSpacingEm,styleValue:a.letterEm,onChange:n=>i(n===void 0?{letterSpacing:null,letter:null}:{letterSpacing:n})},{...l.paragraphSpacing,value:e.paragraphSpacing,styleValue:0,onChange:n=>i({paragraphSpacing:n??null})},{key:"padding",name:u("Padding"),icon:o(C,{}),unit:"px",step:w,shiftStep:10,min:H,max:v,value:e.padding,styleValue:a.paddingPx,onChange:n=>i({padding:n??null})},{key:"width",name:u("Width"),icon:o(I,{}),unit:"px",step:M,shiftStep:100,min:N,max:z,value:e.width,styleValue:a.widthPx,onChange:n=>i({width:n??null})}],S=D(p,r);return T("div",{className:"sf-part-textbox",children:[f,o(A,{value:c,onChange:d,multiline:r,placeholder:s,ariaLabel:P,rules:R,tools:S,barShows:m?"focus":"always",colors:p?h:[],align:t?{value:e.align??a.align,allow:E,onChange:n=>i({align:n})}:void 0,letterCase:t?{value:e.case??"",onChange:n=>i({case:n||null})}:void 0,cells:t?_:void 0})]})}export{Y as PartTextBox};
1
+ "use client";import{jsx as g,jsxs as _}from"react/jsx-runtime";import{COPY_CELLS as r,CopyBox as T}from"efficient-easel/copy";import{PaddingYIcon as S,WidthIcon as A}from"efficient-easel/icons";import{say as u}from"../lib/editor-words.js";import{SHOP_MARKUP as C}from"../lib/markup.js";import{partTextTools as I}from"../lib/puck/canvas-typing.js";import{PART_PADDING_MAX as R,PART_PADDING_MIN as D,PART_PADDING_STEP as v,PART_WIDTH_MAX as z,PART_WIDTH_MIN as H,PART_WIDTH_STEP as w,partSpacingOf as N}from"../lib/puck/part-styles.js";const M=["left","center","right","justify"];function j(i,a,e){const l=N(i),t=i.size??a.sizePx;return[{...r.fontSize,value:i.size,styleValue:Math.round(a.sizePx),onChange:n=>e({size:n??null})},{...r.lineHeight,value:l.lineHeight,styleValue:a.lineRatio,onChange:n=>e(n===void 0?{lineHeight:null,line:null}:{lineHeight:n})},{...r.letterSpacing,scale:t,value:l.letterSpacingEm,styleValue:a.letterEm,onChange:n=>e(n===void 0?{letterSpacing:null,letter:null}:{letterSpacing:n})},{...r.paragraphSpacing,value:i.paragraphSpacing,styleValue:0,onChange:n=>e({paragraphSpacing:n??null})},{key:"padding",name:u("Padding"),icon:g(S,{}),unit:"px",step:v,shiftStep:10,min:D,max:R,value:i.padding,styleValue:a.paddingPx,onChange:n=>e({padding:n??null})},{key:"width",name:u("Width"),icon:g(A,{}),unit:"px",step:w,shiftStep:100,min:H,max:z,value:i.width,styleValue:a.widthPx,onChange:n=>e({width:n??null})}]}function X({text:i,onTextChange:a,multiline:e,markup:l=!0,styled:t=!0,style:n,base:c,setValue:p,colors:d,placeholder:s,ariaLabel:h,head:f,typedOnCanvas:P=!1}){const m=j(n,c,p),x=I(l,e);return _("div",{className:"sf-part-textbox",children:[f,g(T,{value:i,onChange:a,multiline:e,placeholder:s,ariaLabel:h,rules:C,tools:x,barShows:P?"focus":"always",colors:l?d:[],align:t?{value:n.align??c.align,allow:M,onChange:o=>p({align:o})}:void 0,letterCase:t?{value:n.case==="capitalize"?"":n.case??"",onChange:o=>p({case:o||null})}:void 0,cells:t?m:void 0})]})}export{X as PartTextBox,j as partTextCells};
@@ -31,7 +31,6 @@ type PanelContext = {
31
31
  label: string;
32
32
  fields: Record<string, unknown>;
33
33
  } | null;
34
- styleNameOfPart: (nodeId: string, propKey: string) => string | null;
35
34
  siteId: string | null;
36
35
  websiteName: string | null;
37
36
  notifyParent: SendToHost;
@@ -1 +1 @@
1
- "use client";import{jsx as n,jsxs as f,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 R}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 F}from"./PreviewTickerContext.js";import ge from"./SectionIcon.js";import{PanelHideButton as x}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 Ne from"./TickerSettingsPanel.js";import Le,{PartSourceNote as Oe,partStyleName as Te}from"./PartSettingsPanel.js";import He from"./DuplicateToPageMenu.js";import{useStorefrontDocument as _e}from"./StorefrontDocumentContext.js";import{usePreviewHeader as De}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 Re}from"../lib/editor-screen.js";import{usePreviewParts as Fe}from"./PreviewPartsContext.js";import{entryPartsOf as xe,SectionTextEntries as Be}from"./SectionTextEntries.js";import{SectionTextSuppressProvider as ze}from"../lib/puck/section-text-suppress.js";import{HEADER_TYPE as Ke,ROOT_ZONE as B}from"../lib/puck/content-tree.js";import{websiteDuplicateBlocked as Me}from"../lib/puck/every-page.js";import{FOOTER_TYPE as P}from"../lib/puck/footer-blocks.js";import We from"./SwitchToBoxFooter.js";import{SiteFields as z}from"./SiteFields.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 Ze}from"../lib/puck/part-row-field.js";import{decodePartKey as $e,partRowHeadLabel as qe}from"../lib/puck/part-rows.js";import{encodePartId as K,partHeadLabel as Ge,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 Ut=Re,Yt={kind:"header"},Zt={kind:"website"},$t={kind:"chat"},qt={kind:"social"},g="Part";function M(e){return i("Part of {name}",{name:i(e)})}function et(e,o,r){const c=e.describeNode(o);return{name:r,kindLabel:c?M(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 W({what:e}){const o=tt(e);return f("div",{className:"sf-note",children:[n("p",{children:n("strong",{children:o.title})}),f("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(W,{what:"Social link"})})},ticker:{name:F,kindLabel:g,icon:"ticker",head:(e,o)=>e.kind==="ticker"?et(o,e.heroId,i(F)):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}=$e(e.propKey),w=h?Ze(r.fields[c],h):r.fields[c],u=qe(i(Ge(Je(w??{},c))),h),p=o.styleNameOfPart(e.nodeId,e.propKey);return{name:p!==null?i(p):u,kindLabel:M(r.label)}},render:(e,o)=>e.kind==="part"?n(Le,{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(W,{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:j,currentSlug:U,siteId:E,runAuthed:Y,readOnly:Z}=_e(),{websiteName:$,fonts:q}=De(),{partStyle:I}=Ae(),b=Ce({readOnly:Z}),{select:G}=Fe(),{selectedItem:t,getItemById:N,getSelectorForId:J,config:d,appState:Q}=ue(l=>l),V=be(d,t?{type:t.type,props:t.props}:null),L=t?Qe(V??d.components[t.type]?.fields,t.props):[],X=l=>d.components[l]?.label??l,s=t?J(t.props.id):void 0,a=it(e.kind,p),ee=ke(),O={capabilities:p,tokenRef:y,hostPanels:ee.chrome?.panels,describeNode:l=>{const m=N(l);if(!m)return null;const S=d.components[m.type];return{type:m.type,label:S?.label??m.type,fields:S?.fields??{}}},styleNameOfPart:(l,m)=>{const S=N(l);if(!S)return null;const de=K(l,m),me=I?.partId===de?I:null;return Te(S.props,m,me,q)},siteId:E,websiteName:$??null,notifyParent:j,onNotify:w,onOpenWebsiteSettings:o,onOpenSiteStyles:r,onSelectNode:c},T=a?.head?.(e,O)??null,te=T?.name??(a?i(a.name):t?i(X(t.type)):i("Page settings")),ne=T?.kindLabel??(a?i(a.kindLabel):t?s&&s.zone!==B?i("Block"):i("Section"):i("Page")),oe=a?a.icon:t?t.type:"page",H=a?null:t?d.components[t.type]?.fields??null:d.root?.fields??null,ie=H?Ue(H):2,_=e.kind==="puck"&&t?Ve(t.type):null,re=!!t&&!!s&&s.zone===B&&t.type!==P&&t.type!==Ke,k=Me(Q?.data,t),se=()=>{k||s&&b.duplicateComponent(s.zone,s.index)},ae=()=>{s&&(b.removeComponent(s.zone,s.index),b.select(null))},le=t?d.components[t.type]?.defaultProps?.previewHover:void 0,D=e.kind==="puck"&&!!t&&!!s&&le!==void 0,A=D&&t.props.previewHover===!0,ce=()=>{!t||!s||b.replaceComponent(s.zone,s.index,{...t,props:{...t.props,previewHover:!A}})},[C,pe]=fe(ye);return f("div",{className:`es-sidepanel es-sidepanel--right sf-panel sf-panel--right${C||!(!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?f(v,{children:[n(R,{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:U,siteId:E??void 0,tokenRef:y,runAuthed:Y,onNotify:w}),n(R,{label:i("Remove section"),danger:!0,onClick:ae,children:n(we,{size:15})}),u?n(x,{side:"right",onHide:u,divider:!0}):null]}):u?n(x,{side:"right",onHide:u}):void 0}),D&&f("div",{className:"sf-preview-pin",children:[f("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:A,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,O):t?f(v,{children:[t.type===P&&p.hasSiteSettings&&n(We,{}),n(ze,{children:n(z,{entries:n(Be,{parts:L,heading:!1,onOpen:l=>G(K(t.props.id,l))}),entryCount:xe(L).length})}),_&&n(Oe,{source:_,slug:Xe(t?.props)}),n(Pe,{shown:C,onChange:pe})]}):n(v,{children:n(z,{})})})})]})}export{$t as CHAT_MODE,Yt as HEADER_MODE,Ut 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 m,Fragment as v}from"react/jsx-runtime";import{useState as ae}from"react";import{useEasel as le}from"efficient-easel/easel";import{headWords as ce,InspectorHead as pe,InspectorIconButton as A}from"efficient-easel/chrome";import{DuplicateIcon as de,TrashIcon as me}from"efficient-easel/icons";import{panelFieldsOf as fe}from"../lib/puck/panel-fields.js";import{TICKER_PART_LABEL as C}from"./PreviewTickerContext.js";import ue from"./SectionIcon.js";import{PanelHideButton as R}from"./SidePanelHead.js";import{useEditorSession as he}from"../lib/editor-session-context.js";import{say as o}from"../lib/editor-words.js";import we,{HintsToggle as Se,SHOW_HINTS_DEFAULT as be}from"./WebsiteSettingsPanel.js";import ge from"./ChatSettingsPanel.js";import ke from"./SocialLinksPanel.js";import ve from"./TickerSettingsPanel.js";import Pe,{PartSourceNote as Ee}from"./PartSettingsPanel.js";import ye from"./DuplicateToPageMenu.js";import{useStorefrontDocument as Ie}from"./StorefrontDocumentContext.js";import{usePreviewHeader as Le}from"./PreviewHeaderContext.js";import{useSectionOps as Oe}from"../lib/puck/use-section-ops.js";import{SELECTION_MODE as Te}from"../lib/editor-screen.js";import{usePreviewParts as Ne}from"./PreviewPartsContext.js";import{entryPartsOf as He,SectionTextEntries as _e}from"./SectionTextEntries.js";import{SectionTextSuppressProvider as De}from"../lib/puck/section-text-suppress.js";import{HEADER_TYPE as Ae,ROOT_ZONE as x}from"../lib/puck/content-tree.js";import{websiteDuplicateBlocked as Ce}from"../lib/puck/every-page.js";import{FOOTER_TYPE as P}from"../lib/puck/footer-blocks.js";import Re from"./SwitchToBoxFooter.js";import{SiteFields as F}from"./SiteFields.js";import{SettingsSwitch as xe}from"efficient-easel/panel";import{foldTopTier as Fe}from"../lib/puck/field-groups.js";import{FoldHeadingScope as Be}from"../lib/puck/panel-heading-scope.js";import{partRowField as ze}from"../lib/puck/part-row-field.js";import{decodePartKey as Ke,partRowHeadLabel as Me}from"../lib/puck/part-rows.js";import{encodePartId as We,partHeadLabel as je,partLabel as Ue,sectionTextParts as Ye}from"../lib/puck/text-parts.js";import{partSourceOf as Ze,sourceSlugOf as $e}from"../lib/puck/source-bound-parts.js";const Bt=Te,zt={kind:"header"},Kt={kind:"website"},Mt={kind:"chat"},Wt={kind:"social"},g="Part";function qe(e){return o("Part of {name}",{name:o(e)})}function Ge(e,i,r){const l=e.describeNode(i);return{name:r,kindLabel:l?qe(l.label):o(g)}}function Je(e){switch(e){case"Header":return{title:o("Header settings belong to a website."),own:o("Each website created from this template sets its own header afterwards.")};case"Appearance":return{title:o("Appearance settings belong to a website."),own:o("Each website created from this template sets its own appearance afterwards.")};case"Live chat":return{title:o("Live chat settings belong to a website."),own:o("Each website created from this template sets its own live chat afterwards.")};case"Social link":return{title:o("Social link settings belong to a website."),own:o("Each website created from this template sets its own social link afterwards.")};default:return{title:o("{what} settings belong to a website.",{what:e}),own:o("Each website created from this template sets its own {what} afterwards.",{what:e.toLowerCase()})}}}function B({what:e}){const i=Je(e);return m("div",{className:"sf-note",children:[n("p",{children:n("strong",{children:i.title})}),m("p",{children:[o("A template is a blueprint — it has no website of its own, so there is nothing here to change.")," ",i.own]})]})}const Qe={header:{name:"Header",kindLabel:"Site settings",icon:"header",render:(e,i)=>{const r=i.hostPanels?.header;return r?n(r,{placeholderMode:i.capabilities.placeholderFrames,tokenRef:i.tokenRef,siteId:i.siteId,websiteName:i.websiteName,onOpenWebsiteSettings:i.onOpenWebsiteSettings,onAuthExpired:()=>i.notifyParent("storefront-editor:auth-expired")}):null}},website:{name:"Appearance",kindLabel:"Site settings",icon:"website",render:(e,i)=>n(we,{themeFromDocument:!i.capabilities.hasSiteTheme,tokenRef:i.tokenRef,siteId:i.siteId,onNotify:i.onNotify})},chat:{name:"Live chat",kindLabel:"Site settings",icon:"chat",render:()=>n(ge,{})},social:{name:"Social links",kindLabel:"Site settings",icon:"social",render:()=>n(ke,{unavailable:n(B,{what:"Social link"})})},ticker:{name:C,kindLabel:g,icon:"ticker",head:(e,i)=>e.kind==="ticker"?Ge(i,e.heroId,o(C)):null,render:e=>n(ve,{heroId:e.kind==="ticker"?e.heroId:""})},part:{name:g,kindLabel:g,icon:"Text",head:(e,i)=>{if(e.kind!=="part")return null;const r=i.describeNode(e.nodeId);if(!r)return null;const{key:l,row:u}=Ke(e.propKey),h=u?ze(r.fields[l],u):r.fields[l],f=Me(o(je(Ue(h??{},l))),u),p=ce({name:f,tier:"part",of:o(r.label)},{partOf:({name:w})=>o("Part of {name}",{name:w})});return{name:p.name,kindLabel:p.kind}},render:(e,i)=>e.kind==="part"?n(Pe,{nodeId:e.nodeId,propKey:e.propKey,onBack:()=>i.onSelectNode(e.nodeId),onEditStyle:i.onOpenSiteStyles}):null}},Ve=new Set(["header","website","chat"]);function Xe(e,i){if(e==="puck")return null;const r=Qe[e];return Ve.has(e)&&!i.hasSiteSettings?{...r,kindLabel:"Not part of a template",render:()=>n(B,{what:r.name})}:r}function et({mode:e,onOpenWebsiteSettings:i,onOpenSiteStyles:r,onSelectNode:l,hideNodeActions:u=!1,onNotify:h,onHidePanel:f}){const{capabilities:p,tokenRef:w,notifyParent:z,currentSlug:K,siteId:E,runAuthed:M,readOnly:W}=Ie(),{websiteName:j}=Le(),S=Oe({readOnly:W}),{select:U}=Ne(),{selectedItem:t,getItemById:Y,getSelectorForId:Z,config:d,appState:$}=le(c=>c),q=fe(d,t?{type:t.type,props:t.props}:null),y=t?Ye(q??d.components[t.type]?.fields,t.props):[],G=c=>d.components[c]?.label??c,s=t?Z(t.props.id):void 0,a=Xe(e.kind,p),J=he(),I={capabilities:p,tokenRef:w,hostPanels:J.chrome?.panels,describeNode:c=>{const b=Y(c);if(!b)return null;const D=d.components[b.type];return{type:b.type,label:D?.label??b.type,fields:D?.fields??{}}},siteId:E,websiteName:j??null,notifyParent:z,onNotify:h,onOpenWebsiteSettings:i,onOpenSiteStyles:r,onSelectNode:l},L=a?.head?.(e,I)??null,Q=L?.name??(a?o(a.name):t?o(G(t.type)):o("Page settings")),V=L?.kindLabel??(a?o(a.kindLabel):t?s&&s.zone!==x?o("Block"):o("Section"):o("Page")),X=a?a.icon:t?t.type:"page",O=a?null:t?d.components[t.type]?.fields??null:d.root?.fields??null,ee=O?Fe(O):2,T=e.kind==="puck"&&t?Ze(t.type):null,te=!!t&&!!s&&s.zone===x&&t.type!==P&&t.type!==Ae,k=Ce($?.data,t),ne=()=>{k||s&&S.duplicateComponent(s.zone,s.index)},oe=()=>{s&&(S.removeComponent(s.zone,s.index),S.select(null))},ie=t?d.components[t.type]?.defaultProps?.previewHover:void 0,N=e.kind==="puck"&&!!t&&!!s&&ie!==void 0,H=N&&t.props.previewHover===!0,re=()=>{!t||!s||S.replaceComponent(s.zone,s.index,{...t,props:{...t.props,previewHover:!H}})},[_,se]=ae(be);return m("div",{className:`es-sidepanel es-sidepanel--right sf-panel sf-panel--right${_||!(!a&&!!t)?"":" sf-hints-folded"}`,children:[n(pe,{icon:n(ue,{type:X,size:15}),name:Q,kind:V,actions:!u&&e.kind==="puck"&&t&&t.type!==P?m(v,{children:[n(A,{label:o("Duplicate section"),title:k??void 0,disabled:k!==null,onClick:ne,children:n(de,{size:15})}),te&&p.hasSiteSettings&&n(ye,{node:t,currentSlug:K,siteId:E??void 0,tokenRef:w,runAuthed:M,onNotify:h}),n(A,{label:o("Remove section"),danger:!0,onClick:oe,children:n(me,{size:15})}),f?n(R,{side:"right",onHide:f,divider:!0}):null]}):f?n(R,{side:"right",onHide:f}):void 0}),N&&m("div",{className:"sf-preview-pin",children:[m("div",{className:"sf-preview-pin-text",children:[n("span",{className:"sf-preview-pin-label",children:o("Preview hover state")}),n("span",{className:"sf-preview-pin-hint",children:o("not shown live")})]}),n(xe,{checked:H,onChange:re,ariaLabel:o("Preview hover state")})]}),n(Be,{tier:ee,children:n("div",{className:"sf-insp-body es-insp-body sf-scroll",children:a?a.render(e,I):t?m(v,{children:[t.type===P&&p.hasSiteSettings&&n(Re,{}),n(De,{children:n(F,{entries:n(_e,{parts:y,heading:!1,onOpen:c=>U(We(t.props.id,c))}),entryCount:He(y).length})}),T&&n(Ee,{source:T,slug:$e(t?.props)}),n(Se,{shown:_,onChange:se})]}):n(v,{children:n(F,{})})})})]})}export{Mt as CHAT_MODE,zt as HEADER_MODE,Bt as PUCK_MODE,Wt as SOCIAL_MODE,Kt as WEBSITE_MODE,et as default,Xe as resolvePanel};
@@ -846,8 +846,13 @@
846
846
  came to hang 6px OUTSIDE the panel at every width under 280 (measured: gap
847
847
  -6.0px at 260 and at 220, against 0.0 at the default 320). One name, read
848
848
  by the padding, by the narrow override, and by anything that undoes it. */
849
- --sf-insp-pad-x: var(--space-16);
850
- padding: 4px var(--sf-insp-pad-x) 18px;
849
+ /* THE SIDES ARE EASEL'S NOW (one text panel W1): the body wears
850
+ `es-insp-body` (efficient-easel 9.0.0 chrome.css), the one row inset both
851
+ editors share — 16px, 8px under a 284px panel, the numbers this sheet
852
+ measured and set (card 66212, 2026-10-13). The token stays, as a name for
853
+ that inset, because rules below read it to reach the panel's edge. */
854
+ --sf-insp-pad-x: var(--es-insp-pad-x, var(--space-16));
855
+ padding-block: 4px 18px;
851
856
 
852
857
  /* THE DROPDOWN ARROW, WRITTEN ONCE — card 66399.c.
853
858
  Read by `.sf-insp-body select` at rest AND by the hover rule beside it. The
@@ -912,13 +917,8 @@
912
917
  and 10 has nothing to spare, and type is paid vertically as well — card 66206
913
918
  has just set the row rhythm to 16px, which shrinking type would hand straight
914
919
  back. The padding was the horizontal cost, so the padding is what moved. */
915
- @container (width < 284px) {
916
- .sf-insp-body {
917
- /* The TOKEN, not `padding-inline` — so everything that reads the padding
918
- narrows with it, instead of only the padding itself. */
919
- --sf-insp-pad-x: var(--space-8);
920
- }
921
- }
920
+ /* The narrow inset (8px under a 284px panel) is easel's `.es-insp-body` rule
921
+ now; `--sf-insp-pad-x` follows it, so every reader narrows with it. */
922
922
 
923
923
  /* Floating-styled form controls for Puck's native fields — and ONLY those.
924
924
 
@@ -0,0 +1,21 @@
1
+ import type { CSSProperties } from "react";
2
+ export declare const BORDER_MAX = 20;
3
+ export declare const BORDER_STYLES: readonly ["solid", "dashed", "dotted"];
4
+ export type BorderStyle = (typeof BORDER_STYLES)[number];
5
+ export declare const BORDER_SIDES: readonly ["top", "right", "bottom", "left"];
6
+ export type BorderSide = (typeof BORDER_SIDES)[number];
7
+ export type BorderValue = {
8
+ width?: number | null;
9
+ top?: number | null;
10
+ right?: number | null;
11
+ bottom?: number | null;
12
+ left?: number | null;
13
+ style?: BorderStyle | string | null;
14
+ color?: string | null;
15
+ };
16
+ export declare const SECTION_BORDER_CLASS = "sf-section-border";
17
+ export declare function hasOwnBorder(value: BorderValue | null | undefined): boolean;
18
+ export declare function borderVars(value: BorderValue | null | undefined, { phone }?: {
19
+ phone?: boolean;
20
+ }): Record<string, string> | undefined;
21
+ export declare function sectionBorderStyle(desktop: BorderValue | null | undefined, phone: BorderValue | null | undefined): CSSProperties | undefined;
@@ -0,0 +1 @@
1
+ const h=20,i=["solid","dashed","dotted"],c=["top","right","bottom","left"],b="sf-section-border",p=/^#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,f=t=>typeof t=="number"&&Number.isFinite(t)?`${Math.min(20,Math.max(0,Math.round(t)))}px`:void 0;function u(t){return r(t)!==void 0}function r(t,{phone:n=!1}={}){if(!t||typeof t!="object")return;const e=n?"-phone":"",o={};for(const s of c){const d=f(t[s])??f(t.width);d!==void 0&&(o[`--sf-border-${s}-width${e}`]=d)}return typeof t.style=="string"&&i.includes(t.style)&&(o[`--sf-border-style${e}`]=t.style),typeof t.color=="string"&&p.test(t.color)&&(o[`--sf-border-color${e}`]=t.color.toLowerCase()),Object.keys(o).length?o:void 0}function x(t,n){const e=r(t),o=r(n,{phone:!0});return e||o?{...e,...o}:void 0}export{h as BORDER_MAX,c as BORDER_SIDES,i as BORDER_STYLES,b as SECTION_BORDER_CLASS,r as borderVars,u as hasOwnBorder,x as sectionBorderStyle};
@@ -186,6 +186,14 @@ export declare const WEB_BUILDER_WORDS: {
186
186
  readonly "Bold is the weight above \u2014 one value, two ways to set it.": "Bold is the weight above — one value, two ways to set it.";
187
187
  readonly "Bold word": "Bold word";
188
188
  readonly "Booking Form": "Booking Form";
189
+ readonly Border: "Border";
190
+ readonly "Border bottom": "Border bottom";
191
+ readonly "Border color": "Border color";
192
+ readonly "Border left": "Border left";
193
+ readonly "Border right": "Border right";
194
+ readonly "Border style": "Border style";
195
+ readonly "Border top": "Border top";
196
+ readonly "Border width": "Border width";
189
197
  readonly Borders: "Borders";
190
198
  readonly Bottom: "Bottom";
191
199
  readonly "Bottom center": "Bottom center";
@@ -243,7 +251,6 @@ export declare const WEB_BUILDER_WORDS: {
243
251
  readonly "Cell width": "Cell width";
244
252
  readonly Center: "Center";
245
253
  readonly "Changed on every page": "Changed on every page";
246
- readonly "Changes apply to all selected.": "Changes apply to all selected.";
247
254
  readonly "Changes not live yet": "Changes not live yet";
248
255
  readonly Chart: "Chart";
249
256
  readonly "Chart style": "Chart style";
@@ -260,7 +267,6 @@ export declare const WEB_BUILDER_WORDS: {
260
267
  readonly "City strip": "City strip";
261
268
  readonly "Claims bars": "Claims bars";
262
269
  readonly "Claims panel (rows + defect bars)": "Claims panel (rows + defect bars)";
263
- readonly Clear: "Clear";
264
270
  readonly "Clear change": "Clear change";
265
271
  readonly "Clear change: {label}": "Clear change: {label}";
266
272
  readonly "Clear colors": "Clear colors";
@@ -328,6 +334,7 @@ export declare const WEB_BUILDER_WORDS: {
328
334
  readonly "Dark band": "Dark band";
329
335
  readonly Darken: "Darken";
330
336
  readonly "Darken style": "Darken style";
337
+ readonly Dashed: "Dashed";
331
338
  readonly "Data points": "Data points";
332
339
  readonly Date: "Date";
333
340
  readonly "Deck / standfirst": "Deck / standfirst";
@@ -368,6 +375,7 @@ export declare const WEB_BUILDER_WORDS: {
368
375
  readonly "Donut (split of a whole)": "Donut (split of a whole)";
369
376
  readonly "Dot \u25CF": "Dot ●";
370
377
  readonly Dots: "Dots";
378
+ readonly Dotted: "Dotted";
371
379
  readonly Down: "Down";
372
380
  readonly "Drop in your own sanitized HTML.": "Drop in your own sanitized HTML.";
373
381
  readonly "Duplicate section": "Duplicate section";
@@ -378,6 +386,7 @@ export declare const WEB_BUILDER_WORDS: {
378
386
  readonly "Dynamic Pages": "Dynamic Pages";
379
387
  readonly "EU Tyre Label": "EU Tyre Label";
380
388
  readonly "Each block": "Each block";
389
+ readonly "Each side": "Each side";
381
390
  readonly "Each website created from this template sets its own appearance afterwards.": "Each website created from this template sets its own appearance afterwards.";
382
391
  readonly "Each website created from this template sets its own header afterwards.": "Each website created from this template sets its own header afterwards.";
383
392
  readonly "Each website created from this template sets its own live chat afterwards.": "Each website created from this template sets its own live chat afterwards.";
@@ -449,11 +458,9 @@ export declare const WEB_BUILDER_WORDS: {
449
458
  readonly "Follow the page": "Follow the page";
450
459
  readonly "Follow the slideshow": "Follow the slideshow";
451
460
  readonly "Follows Desktop": "Follows Desktop";
452
- readonly "Follows no style \u2014 change": "Follows no style — change";
453
461
  readonly "Follows the section's Corners until you set a number here.": "Follows the section's Corners until you set a number here.";
454
462
  readonly "Follows the site": "Follows the site";
455
463
  readonly "Follows the style": "Follows the style";
456
- readonly "Follows {name} \u2014 change": "Follows {name} — change";
457
464
  readonly Font: "Font";
458
465
  readonly "Footer Box": "Footer Box";
459
466
  readonly "Footer \u00B7 on every page": "Footer · on every page";
@@ -608,6 +615,7 @@ export declare const WEB_BUILDER_WORDS: {
608
615
  readonly "Leave a blank line between paragraphs to start a new one.": "Leave a blank line between paragraphs to start a new one.";
609
616
  readonly "Leave a field blank to use the built-in wording.": "Leave a field blank to use the built-in wording.";
610
617
  readonly Left: "Left";
618
+ readonly "Left and right": "Left and right";
611
619
  readonly "Left of the copy": "Left of the copy";
612
620
  readonly "Legal & documents": "Legal & documents";
613
621
  readonly "Legal Line": "Legal Line";
@@ -673,7 +681,6 @@ export declare const WEB_BUILDER_WORDS: {
673
681
  readonly "Milestone title.": "Milestone title.";
674
682
  readonly Milestones: "Milestones";
675
683
  readonly Mixed: "Mixed";
676
- readonly "Mixed styles": "Mixed styles";
677
684
  readonly "Mockup Card": "Mockup Card";
678
685
  readonly "Mockup card": "Mockup card";
679
686
  readonly "Mockup position": "Mockup position";
@@ -822,7 +829,6 @@ export declare const WEB_BUILDER_WORDS: {
822
829
  readonly "Reel label": "Reel label";
823
830
  readonly "Refresh now": "Refresh now";
824
831
  readonly "Region \u00B7 country": "Region · country";
825
- readonly Regular: "Regular";
826
832
  readonly "Related Products": "Related Products";
827
833
  readonly "Remove section": "Remove section";
828
834
  readonly "Repeating full-width rows \u2014 eyebrow, title and copy beside a numbered close-up image, alternating sides each row.": "Repeating full-width rows — eyebrow, title and copy beside a numbered close-up image, alternating sides each row.";
@@ -885,7 +891,6 @@ export declare const WEB_BUILDER_WORDS: {
885
891
  readonly "Select a word, then press the highlighter.": "Select a word, then press the highlighter.";
886
892
  readonly "Selector guide (pills + results)": "Selector guide (pills + results)";
887
893
  readonly "Selector pills": "Selector pills";
888
- readonly Semibold: "Semibold";
889
894
  readonly Separator: "Separator";
890
895
  readonly "Series title": "Series title";
891
896
  readonly Serif: "Serif";
@@ -914,7 +919,6 @@ export declare const WEB_BUILDER_WORDS: {
914
919
  readonly "Signup Form": "Signup Form";
915
920
  readonly Simple: "Simple";
916
921
  readonly "Site settings": "Site settings";
917
- readonly "Site style": "Site style";
918
922
  readonly "Site styles": "Site styles";
919
923
  readonly "Six across": "Six across";
920
924
  readonly "Six stagger": "Six stagger";
@@ -1058,7 +1062,6 @@ export declare const WEB_BUILDER_WORDS: {
1058
1062
  readonly "This section runs edge to edge, so its corners sit off the page. Set Width to Content width to use them.": "This section runs edge to edge, so its corners sit off the page. Set Width to Content width to use them.";
1059
1063
  readonly "This site has {n} color theme of its own. Clearing takes them away and puts back the four the shop supplies.": "This site has {n} color theme of its own. Clearing takes them away and puts back the four the shop supplies.";
1060
1064
  readonly "This site has {n} color themes of its own. Clearing takes them away and puts back the four the shop supplies.": "This site has {n} color themes of its own. Clearing takes them away and puts back the four the shop supplies.";
1061
- readonly "This text follows the site style.": "This text follows the site style.";
1062
1065
  readonly "This ticker\u2019s hero is no longer on the page.": "This ticker’s hero is no longer on the page.";
1063
1066
  readonly "Three across": "Three across";
1064
1067
  readonly "Three ladder": "Three ladder";
@@ -1074,6 +1077,7 @@ export declare const WEB_BUILDER_WORDS: {
1074
1077
  readonly Title: "Title";
1075
1078
  readonly Tone: "Tone";
1076
1079
  readonly Top: "Top";
1080
+ readonly "Top and bottom": "Top and bottom";
1077
1081
  readonly "Top border": "Top border";
1078
1082
  readonly "Top center": "Top center";
1079
1083
  readonly "Top left": "Top left";
@@ -1173,6 +1177,7 @@ export declare const WEB_BUILDER_WORDS: {
1173
1177
  readonly manifesto: "manifesto";
1174
1178
  readonly "not set": "not set";
1175
1179
  readonly "not shown live": "not shown live";
1180
+ readonly part: "part";
1176
1181
  readonly px: "px";
1177
1182
  readonly "the Text style in Site styles": "the Text style in Site styles";
1178
1183
  readonly "the admin": "the admin";
@@ -1185,7 +1190,6 @@ export declare const WEB_BUILDER_WORDS: {
1185
1190
  readonly "videos only": "videos only";
1186
1191
  readonly "{face} is loaded without an italic, so it cannot be set in italic. Slanting it would deform the letters rather than style them.": "{face} is loaded without an italic, so it cannot be set in italic. Slanting it would deform the letters rather than style them.";
1187
1192
  readonly "{grade} on the button": "{grade} on the button";
1188
- readonly "{kind} \u00B7 every row": "{kind} · every row";
1189
1193
  readonly "{label} hex code": "{label} hex code";
1190
1194
  readonly "{label} {n}": "{label} {n}";
1191
1195
  readonly "{label} \u2014 row {n}": "{label} — row {n}";
@@ -1193,11 +1197,9 @@ export declare const WEB_BUILDER_WORDS: {
1193
1197
  readonly "{name} (unavailable)": "{name} (unavailable)";
1194
1198
  readonly "{name} is on this section": "{name} is on this section";
1195
1199
  readonly "{name} \u2014 renamed in the Console: {place}.": "{name} — renamed in the Console: {place}.";
1196
- readonly "{n} changed": "{n} changed";
1197
1200
  readonly "{n} cities": "{n} cities";
1198
1201
  readonly "{n} city": "{n} city";
1199
1202
  readonly "{n} of {total} layouts": "{n} of {total} layouts";
1200
- readonly "{n} selected": "{n} selected";
1201
1203
  readonly "{value} from {from}": "{value} from {from}";
1202
1204
  readonly "{value} on desktop": "{value} on desktop";
1203
1205
  readonly "{what} settings belong to a website.": "{what} settings belong to a website.";