efficient-web-builder 42.0.0 → 43.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +168 -0
- package/dist/editor/components/AnchorField.js +1 -1
- package/dist/editor/components/DuplicatePageDialog.js +1 -1
- package/dist/editor/components/MediaUploadField.d.ts +3 -1
- package/dist/editor/components/MediaUploadField.js +1 -1
- package/dist/editor/components/PagesPanel.js +1 -1
- package/dist/editor/components/SectionEditor.d.ts +5 -1
- package/dist/editor/components/SectionEditor.js +1 -1
- package/dist/editor/components/SectionIcon.js +1 -1
- package/dist/editor/components/SectionThumbnail.js +1 -1
- package/dist/editor/components/SiteFields.d.ts +2 -1
- package/dist/editor/components/SiteFields.js +1 -1
- package/dist/editor/components/StorefrontEditor.js +1 -1
- package/dist/editor/components/StylesPanel.d.ts +3 -1
- package/dist/editor/components/StylesPanel.js +1 -1
- package/dist/editor/components/WebsiteScreenParts.js +1 -1
- package/dist/editor/components/WebsiteSettingsPanel.d.ts +6 -1
- package/dist/editor/components/WebsiteSettingsPanel.js +1 -1
- package/dist/editor/components/useHostDocumentBridge.js +1 -1
- package/dist/editor/components/useLocationsTree.js +1 -1
- package/dist/editor/components/useSectionToBoxPass.js +1 -1
- package/dist/editor/components/useSocialSettings.d.ts +2 -2
- package/dist/editor/lib/document/ColourControl.d.ts +7 -2
- package/dist/editor/lib/document/ColourControl.js +1 -1
- package/dist/editor/lib/document/blocks/general/ButtonBlock/fields.js +1 -1
- package/dist/editor/lib/document/blocks/general/Flex/fields.js +1 -1
- package/dist/editor/lib/document/blocks/general/HeroSlide/fields.js +1 -1
- package/dist/editor/lib/document/blocks/general/Logos/fields.js +1 -1
- package/dist/editor/lib/document/blocks/general/Text/fields.js +1 -1
- package/dist/editor/lib/document/blocks/general/index.d.ts +2 -2
- package/dist/editor/lib/document/canvas-typing.js +1 -1
- package/dist/editor/lib/document/consent-words-field.d.ts +6 -0
- package/dist/editor/lib/document/consent-words-field.js +1 -0
- package/dist/editor/lib/document/controls.d.ts +13 -2
- package/dist/editor/lib/document/controls.js +1 -1
- package/dist/editor/lib/document/field-groups.js +1 -1
- package/dist/editor/lib/document/footer-blocks.js +1 -1
- package/dist/editor/lib/document/locked-blocks.d.ts +3 -0
- package/dist/editor/lib/document/locked-blocks.js +1 -1
- package/dist/editor/lib/document/overrides.js +1 -1
- package/dist/editor/lib/document/page-root-fields.d.ts +1 -0
- package/dist/editor/lib/document/page-root-fields.js +1 -1
- package/dist/editor/lib/document/section-width-fields.js +1 -1
- package/dist/editor/lib/document/selected-host.d.ts +2 -0
- package/dist/editor/lib/document/selected-host.js +1 -0
- package/dist/editor/lib/page-copy.js +1 -1
- package/dist/editor/lib/sections/section-dry-run.d.ts +2 -9
- package/dist/editor/lib/sections/section-dry-run.js +2 -2
- package/dist/format/lib/content/authored-props.js +1 -1
- package/dist/format/lib/content/block-sources.js +1 -1
- package/dist/format/lib/content/box-layout.d.ts +1 -0
- package/dist/format/lib/content/box-layout.js +1 -1
- package/dist/format/lib/content/box-shadow.d.ts +3 -0
- package/dist/format/lib/content/box-shadow.js +1 -0
- package/dist/format/lib/content/button-icon.d.ts +2 -1
- package/dist/format/lib/content/button-icon.js +1 -1
- package/dist/format/lib/content/button-look.d.ts +46 -0
- package/dist/format/lib/content/button-look.js +1 -0
- package/dist/format/lib/content/consent-banner.d.ts +21 -0
- package/dist/format/lib/content/consent-banner.js +1 -1
- package/dist/format/lib/content/contact.js +1 -1
- package/dist/format/lib/content/footer.d.ts +10 -0
- package/dist/format/lib/content/footer.js +1 -1
- package/dist/format/lib/content/gallery-layout.d.ts +12 -0
- package/dist/format/lib/content/gallery-layout.js +1 -1
- package/dist/format/lib/content/section-padding.d.ts +10 -0
- package/dist/format/lib/content/section-padding.js +1 -1
- package/dist/format/lib/content/section-width.d.ts +0 -4
- package/dist/format/lib/content/section-width.js +1 -1
- package/dist/format/lib/document/blocks/general/Logos/meta.d.ts +6 -0
- package/dist/format/lib/document/blocks/general/Logos/meta.js +1 -1
- package/dist/format/lib/document/blocks/general/SectionHeader/meta.js +1 -1
- package/dist/format/lib/document/box-footer.js +1 -1
- package/dist/format/lib/document/container-blocks.js +1 -1
- package/dist/format/lib/document/media-manifest.json +5 -3
- package/dist/format/lib/document/nestable-content-sections.js +1 -1
- package/dist/format/lib/document/passes/settings-groups.js +1 -1
- package/dist/format/lib/document/root-panel.d.ts +8 -0
- package/dist/format/lib/document/root-panel.js +1 -0
- package/dist/format/lib/document/section-catalog.js +1 -1
- package/dist/format/lib/document/source-bound-parts.js +1 -1
- package/dist/format/lib/editor-words-catalogue.d.ts +23 -4
- package/dist/format/lib/editor-words-catalogue.js +4 -4
- package/dist/format/lib/editor-words.js +1 -1
- package/dist/format/lib/hero-texture.js +1 -1
- package/dist/format/lib/hero-video.d.ts +7 -0
- package/dist/format/lib/hero-video.js +1 -1
- package/dist/format/lib/links/page-link-rules.js +1 -1
- package/dist/format/lib/non-empty-string.d.ts +1 -0
- package/dist/format/lib/non-empty-string.js +1 -0
- package/dist/format/lib/popup/look.d.ts +1 -1
- package/dist/format/lib/popup/look.js +1 -1
- package/dist/format/lib/reel.d.ts +2 -1
- package/dist/format/lib/reel.js +1 -1
- package/dist/format/lib/sections/hero-overlay.js +1 -1
- package/dist/format/lib/sections/logo-look.d.ts +7 -0
- package/dist/format/lib/sections/logo-look.js +1 -0
- package/dist/format/lib/sections/section-head-placement.d.ts +1 -0
- package/dist/format/lib/sections/section-head-placement.js +1 -1
- package/dist/format/lib/site-theme-row.d.ts +0 -1
- package/dist/format/lib/slugify.d.ts +1 -1
- package/dist/format/lib/slugify.js +1 -1
- package/dist/format/lib/theme.d.ts +2 -1
- package/dist/format/lib/theme.js +4 -4
- package/dist/render/components/BoxTabs.d.ts +2 -1
- package/dist/render/components/BoxTabs.js +1 -1
- package/dist/render/components/Btn.d.ts +1 -0
- package/dist/render/components/Btn.js +1 -1
- package/dist/render/components/ButtonBlock.d.ts +12 -1
- package/dist/render/components/ButtonBlock.js +1 -1
- package/dist/render/components/DocBody.js +5 -5
- package/dist/render/components/Flex.d.ts +3 -1
- package/dist/render/components/Flex.js +1 -1
- package/dist/render/components/LogoBlock.d.ts +1 -1
- package/dist/render/components/LogoBlock.js +1 -1
- package/dist/render/components/LogoWallContext.d.ts +12 -0
- package/dist/render/components/LogoWallContext.js +1 -0
- package/dist/render/components/Logos.d.ts +16 -1
- package/dist/render/components/Logos.js +1 -1
- package/dist/render/components/PaymentBadges.d.ts +3 -1
- package/dist/render/components/PaymentBadges.js +1 -1
- package/dist/render/components/PreviewHeaderContext.d.ts +1 -3
- package/dist/render/components/PreviewHeaderContext.js +1 -1
- package/dist/render/components/Reel.js +1 -1
- package/dist/render/components/SiteGutterFrame.d.ts +2 -1
- package/dist/render/components/SiteGutterFrame.js +1 -1
- package/dist/render/lib/document/blocks/general/ButtonBlock/render.js +1 -1
- package/dist/render/lib/document/blocks/general/Flex/render.js +1 -1
- package/dist/render/lib/document/blocks/general/HeroSlide/render.js +1 -1
- package/dist/render/lib/document/blocks/general/Logos/render.js +1 -1
- package/dist/render/lib/document/blocks/general/PaymentBadges/render.js +1 -1
- package/dist/render/lib/document/blocks/general/section-to-box-row-parts.d.ts +4 -1
- package/dist/render/lib/document/blocks/general/section-to-box-row-parts.js +1 -1
- package/dist/render/lib/document/blocks/general/section-to-box-rows-logos.d.ts +2 -0
- package/dist/render/lib/document/blocks/general/section-to-box-rows-logos.js +1 -0
- package/dist/render/lib/document/blocks/general/section-to-box-rows-stats.d.ts +5 -0
- package/dist/render/lib/document/blocks/general/section-to-box-rows-stats.js +1 -0
- package/dist/render/lib/document/blocks/general/section-to-box-rows.d.ts +0 -4
- package/dist/render/lib/document/blocks/general/section-to-box-rows.js +1 -1
- package/dist/render/lib/document/page-render.js +1 -1
- package/dist/render/lib/document/part-rows.js +1 -1
- package/dist/render/lib/document/passes/section-anchor.js +1 -1
- package/dist/render/lib/document/text-parts.js +1 -1
- package/dist/render/lib/sections/section-to-box.d.ts +2 -11
- package/dist/render/lib/sections/section-to-box.js +1 -1
- package/dist/render/lib/text-styles/site-text-styles.js +2 -2
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,140 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 43.0.1 - 2026-10-27
|
|
4
|
+
|
|
5
|
+
**PATCH, no visible change** (Victor Mau, 2026-10-27; a maintenance release from `maint-43`, because main already holds 44's breaking changes). The media manifest is regenerated: `mediaKeyNames` gains `videoFrame`, the Hero slide's frame that #335 added to `mediaFields` but not to the derived name list (the file was edited in a merge, not regenerated). The template sanitizer's unknown-block fallback now clears a stored `videoFrame` too. `contentHash` `f94be8c390bc1b18` → `035f4205f0351855`, written by efficient-storefront's `scripts/gen-media-manifest.ts`; the backend re-vendors it. Nothing a page draws or the editor shows changes.
|
|
6
|
+
|
|
7
|
+
## 43.0.0 - 2026-10-27
|
|
8
|
+
|
|
9
|
+
**MAJOR for hosts.** Three peers and names move at once (Victor Mau, 2026-10-27: "cut web-builder 43.0.0 now"; #331, #282, #310 and #311 were not merged and go to the next release):
|
|
10
|
+
|
|
11
|
+
- `efficient-easel` is `^23.0.0` (was `^22.0.0`): the page's own settings are Styles' "This page" group (#314).
|
|
12
|
+
- `efficient-shell` is `^10.13.0` (was `^10.0.0`): Payment Methods draws a way to pay as its mark through `efficient-shell/icons/payment` (#352).
|
|
13
|
+
- Removed published names: `SITE_CARD_THEME_KEY`, `normalizeCardThemeIndex`, `siteCardThemeMetadata`, `siteCardThemeOf` (`lib/content/section-width`), `pageConvertContextOf`, `PageConvertContext`, `ConvertContext.cardTheme`, `SiteFacts.themePresets`, the `add-theme-preset` site write kind, and the `page` argument of `convertSectionsInPage` / `sectionToBoxEdits` (#350).
|
|
14
|
+
|
|
15
|
+
42.0.1 was never published; its section below ships in this release.
|
|
16
|
+
|
|
17
|
+
### Changed (Payment Methods draws a way to pay as its mark; Victor Mau, venue websites, 2026-10-27)
|
|
18
|
+
|
|
19
|
+
- **MAJOR for hosts: `efficient-shell` narrows to `^10.13.0`** (was `^10.0.0`), the release that ships `efficient-shell/icons/payment` (the shell's payment marks, efficient-shell#655). A host moves the shell with this release.
|
|
20
|
+
- **A payment method is drawn as its mark, in the page's own ink** (look B). The card and app brands a customer knows are their marks (Visa, Mastercard, American Express, JCB, Diners Club, Apple Pay, Google Pay, PayPal, Afterpay, Klarna, Alipay, WeChat Pay); cash and a transfer are a glyph beside the method's own name; any other name stays words. Which name or kind is which mark is efficient-shell's `paymentMarks`, the one answer every EFFICIENT surface that says how to pay reads.
|
|
21
|
+
- **A sourced strip reads each method's `kind`** as well as its `label` (the backend's `location-payment-methods`: `cash`, `card`, `wire`, `alipay`, `wechat_pay`), so Alipay and WeChat Pay are their marks whatever the desk called them, and draws each mark once: a venue's starter list (Cash, EFTPOS, Visa / Mastercard, Bank transfer) is cash, Visa, Mastercard, a transfer. `EFTPOS` is Visa and Mastercard.
|
|
22
|
+
- **A typed strip**: an uploaded logo still wins; a name the shell knows is its marks inside its card ("Amex & JCB" is one card of two marks); other words stay as typed, highlights and all. The reading is in the Logos block's Cards look (`components/Logos` `LogoWallMark`, the one drawing of a payment chip since #333), so a strip converted to a Box draws the same; `LogoWallMark` takes a `mark` for a sourced method, and exports `CARD_WORDS_CLASS`. The editor's sample for a sourced strip is Cash, Card and Bank transfer, so the glyphs show.
|
|
23
|
+
- **The footer's "Add block" offers Payment Logos** (`FooterPayment`, drawn by efficient-storefront-blocks): "We accept" and the ways to pay as their marks, typed, or read from what the shop's checkout or a venue's Setup takes. It is a `service` block in the catalogue, wears the shell's `card-payment` glyph, and has the footer blocks' tab strip.
|
|
24
|
+
- **Every new footer says how to pay** (Victor Mau, 2026-10-27): `buildDefaultFooterBlocks` seeds Payment Logos after the email signup, on the host's `shop-payment-methods` source (`FOOTER_PAYMENT_SEED`, `FOOTER_PAYMENT_PH` in `lib/content/footer`), so it carries no store's words and draws nothing where a store takes nothing online. A footer already saved does not change. The platform's shop looks carry no footer of their own, so they get it the same way.
|
|
25
|
+
- **The Box footer carries it**: `FooterPayment` → its page twin `PaymentLogosBlock` (`box-footer`, `container-blocks`, the catalogue, the tab strip, its icon alias and a thumbnail).
|
|
26
|
+
- `scripts/test-payment-marks.tsx` (new) and `scripts/test-contact-payment-sources.tsx` (rows carry `kind`).
|
|
27
|
+
|
|
28
|
+
### Fixed (Fit content fits the content)
|
|
29
|
+
|
|
30
|
+
- **`Fit content` in a Box row makes each block as wide as its content.** `Fit content`, and the absent share every older Box stores, emitted no class, and every block's own frame is `w-full`, so in a row each block's `flex-basis: auto` read 100%: with `Wrap` on the row drew a stack, with `No wrap` the blocks shrank from 100% alike. A row that stores no share (absent, `content`, or an unknown word) now wears `[&>*]:min-[800px]:basis-[content]` (`lib/content/box-layout` `boxFitContentClass`), so each block is sized from its content from 800px up. A column Box, a tabbed Box and a row with a share (Equal, Big left …) are unchanged, byte for byte. **Live:** 5 stored row Boxes change, all on drafts (inovit_au sharpen homepage, 3; inovit_us storefront site-footer, 2); no published page changes.
|
|
31
|
+
- Guards: `scripts/test-box-fit-content.tsx` (red first) draws a whole published page: every Fit content row, wrap stored as `true`, `false`, `"wrap"` or `"nowrap"`, carries the content basis on each block; a shared row does not; column Boxes, the live Hartes Metal shape among them, draw the bytes main drew (`scripts/fixtures/box-column-bytes.json`, redrawn on main `46716ca9` with main's code: only #322's band changed it). `scripts/fixtures/box-shapes-bytes.json` redrawn on main `46716ca9` (after #322 redrew it): the 3 Fit content row shapes gain that one class, nothing else. `scripts/test-box-share.tsx` §1 reads the one new class on an unset row.
|
|
32
|
+
|
|
33
|
+
### Changed (a count says what it counts)
|
|
34
|
+
|
|
35
|
+
- **The Pages panel and the Locations tree hand each count to the shell's `ItemCount` with its noun** (owner 2026-10-23: one count part, a muted box at the END of the row; its words go to the Tooltip and the screen reader). A Pages heading passes `countLabel` "N pages"; a Locations group row passes `count` and `countLabel` "N cities" to easel's `TreeRow`, where it drew its own `<span className="es-group-count">` before (that class is the settings panel's "changed" accent count, another meaning). Needs efficient-easel 21.0.0+ (easel #350) and efficient-shell 10.0.0+ (shell #621): the peers 41.0.0 already pins.
|
|
36
|
+
- Guard: new `scripts/test-counts-are-item-count.ts` (red first on main: both tests fail).
|
|
37
|
+
|
|
38
|
+
### Fixed (Width › Content keeps what was chosen; Lewis, INOVIT home, 2026-10-26)
|
|
39
|
+
|
|
40
|
+
- **`Full width` after `Content width` sticks, and so does ↺.** A section's Content row set `contentWidth` and `contentMax` as TWO writes. Each write reads the node, awaits its `resolveData` and replaces the node, so the second one was built on the node from before the first, and the first was lost: on Image & Text Split at Content width 1600, a click on `Full width` changed nothing; ↺ dropped the number but kept `Content width`; in a header box a dragged number did not stick. The row now writes both keys in ONE change (`useSelectedPatch` in `lib/document/controls`, efficient-easel's `onChangeMany`).
|
|
41
|
+
- **The number picked is the number stored, also when it equals the site's.** A number equal to the site's Content width was stored as "follow the site" (`contentMax: null`). Inside a header group at Full width the site's column is `100vw` (efficient-storefront-blocks `SectionGroupBody`), so the Box header's bar at 1600 (the site's number, and the slider's top) ran full screen while 1550 held. Only ↺ follows the site now. Stored pages do not change; only the next pick of a number does.
|
|
42
|
+
- **One hook reads the panel's host.** `useSelectedHost` (`lib/document/selected-host`) is the one place that catches the "outside an editor" throw of `useSelectedFields()`. `useSelectedSibling`, `useSelectedPatch`, the Padding and Position rows and the media field's focus read call it; five copies of the try/catch are gone.
|
|
43
|
+
- `scripts/test-section-width-one-write.tsx` (red first: 4 of 12 checks, then 2 more for the shared hook): the real Width rows on the engine's store, through `SiteFields`, and no file in `src/` has its own try/catch around `useSelectedFields()`.
|
|
44
|
+
|
|
45
|
+
### Fixed (a section that stores no width follows Site styles; Lewis, INOVIT home, 2026-10-26)
|
|
46
|
+
|
|
47
|
+
- **Site styles › Content width and Background width reach every section that has not set its own.** `resolveSectionWidth` read a section that stored NO width as a pinned answer of its own in 6 of 9 families: Content `Full width` for Split, Breadcrumb, Collections, Product Grid, Product Hero, Scroll-Over Text and Section Header, and Background `Content width` for every Box, Grid, Banner, Stats, Logos, Divider, checkout section and capped section. The panel showed that answer blue with ↺, and the site's value moved none of them (measured in the canvas: the site at 1300 moved Gallery to 1300 and left a bare Split at 1950). An old width key is now read only where one is stored.
|
|
48
|
+
- **Visible change on published pages:** a section of those families that stores no width now draws the site's Content width and Background width. On the local clone (2026-10-26, top-level published sections, all tenants) 254 sections store no width in those families; the largest groups are Section Header 38, Split 25, Product Grid 25.
|
|
49
|
+
- Product Grid's old Content width with no number of its own follows the site's number instead of a built-in 1600. A capped section's stored old key, which its render never read, pins nothing.
|
|
50
|
+
- Scroll-Over Text (IntroBleed) reads ONLY its `fullWidth` switch, so any other stored old key (`widthMode`, `contained`, `pageWidth`) pins nothing there: it follows the site.
|
|
51
|
+
- A stored `widthMode: "inherit"` (the old ↺) counts as nothing stored: those sections follow the site too (Banner, Split and the other "both" and "contained" sections drew Full from it before).
|
|
52
|
+
- A new Section Header stores no width: its default props wrote `fullWidth: true, pageWidth: 1600` into every new node.
|
|
53
|
+
- `scripts/test-section-width-unset-follows-site.ts` (red first: 44 of 76 checks). `scripts/test-section-width-mapping.ts` and `scripts/test-section-width-draw.tsx` §5, §9, §11, §14: the rows that held the old "unset pins" rule now say follow. `scripts/fixtures/box-shapes-bytes.json` is redrawn: 11 of 12 Box shapes that store no width now draw a full-width band with the column inside it (`w-full py-6` › `mx-auto max-w-[site]`) instead of one capped box; with no Box background the pixels are the same.
|
|
54
|
+
|
|
55
|
+
### BREAKING for hosts
|
|
56
|
+
|
|
57
|
+
- **The `efficient-easel` peer and devDependency move from `^22.0.0` to `^23.0.0`.** A host moves easel to 23 with this release. The page's own settings are no longer a Layers row: they are the "This page" group in Styles > Basics, opened by easel's `openPageStyles`.
|
|
58
|
+
|
|
59
|
+
### Changed (the page's own settings leave the Layers tree; structure card v2, Lewis 2026-10-26)
|
|
60
|
+
|
|
61
|
+
- **Styles gets a group, "This page", at the foot of Basics — no fourth tab** (Lewis 2026-10-27: "the site's on top, the page's below; I do not want a new tab"). Background, Top space and Page width (`PAGE_STYLE_FIELDS`, the page root's look rows) sit under every site row and above the hints switch, drawn with the same field definitions and the same easel `Inspector` as before, written through easel's new `useRootFields` (one `replaceRoot`, whatever is selected). Each still follows the site when unset. A system page has none of them, and the group says so. The template's Appearance panel shows the group in its Basics too (`WEBSITE_PAGE_MODE`, `initialTab`). New exports: `SITE_STYLES_BASICS_TAB`, `THIS_PAGE_GROUP_ID`; new optional props `revealPageGroup` and `onPageGroupRevealed` on `WebsiteSettingsPanel` and `StylesPanel`; the `website` inspector mode may carry `revealPageGroup`.
|
|
62
|
+
- **The right panel with nothing selected is the page's, not "Page settings".** It leaves out `PAGE_STYLE_FIELDS` (`SiteFields omit`) and draws what is left: a dynamic page's Product type, Record type and Trust bullets, a system page's whole panel. Its head is the page's name as the Pages list says it, and "Template" on a dynamic page (`lib/document/root-panel`). A normal page has nothing left: the shell's `EmptyState` says "Select a section or block to edit it." with one button, "This page".
|
|
63
|
+
- **`openPageStyles`** (efficient-easel #363, the release after 22.0.0): the tree ground's "This page" and that button open Styles on Basics and scroll to the This page group (the panel scrolls once it is drawn, then says so, so reopening Styles stays put); a template opens Appearance there.
|
|
64
|
+
- **The page's width row is "Page width"** (Lewis 2026-10-27), not "Width": Basics draws the site's "Content width" above it in the same panel. The Header's and Footer's rows keep "Width" (`WidthFollowField label`).
|
|
65
|
+
- **The Pages row's pencil is a gear, "Page settings for “…”"** (Lewis 2026-10-14: the row's gear opens all of that page's settings). It still sends `storefront-editor:open-page`; the admin portal answers it with its one Page Settings window.
|
|
66
|
+
- **Removed:** the head's "Duplicate page" (the Pages row has the same action) and the "Page settings" head word. Words catalogue: gains "This page", "Page width", "Template", "Page settings for “{name}”", "Select a section or block to edit it.", "This page has no look of its own to set."; loses "Page settings" and "Edit “{name}” in {place}".
|
|
67
|
+
- `scripts/test-page-settings-move.tsx` (red first). Updated: `test-site-styles-basics-tab` (three tabs), `test-page-duplicate` (one place), `test-editor-left-view` (three doors), `test-edit-style-opens-text` (`initialTab`), and four guards' menu hosts (no `openPageSettings`).
|
|
68
|
+
|
|
69
|
+
### Removed (the site Card theme index; #350)
|
|
70
|
+
|
|
71
|
+
- **The site "Card theme index" is gone** (Lewis 2026-10-27: dead, no backend field holds it). The editor read, the metadata key and its readers, the page render's convert context, the Banner branch that waited for it, the XM card preset write (`add-theme-preset`) and the dry run's card-theme options are removed; the names are listed at the top of this section.
|
|
72
|
+
|
|
73
|
+
### Added (a Box's own Shadow)
|
|
74
|
+
|
|
75
|
+
- **Every Box has a `Shadow` switch** (cookie banner build, PR 3; design approved by Lewis 2026-10-26). On, the Box follows Site styles' `Card shadow`: its outermost box carries a bare `data-sf-box-shadow` (new `lib/content/box-shadow`), and the host's site sheet draws `var(--sf-shadow-step)` there (efficient-storefront-blocks `globals.css`). It offers no steps of its own. Off is the default, so every Box saved before is drawn byte for byte as before.
|
|
76
|
+
- A picture-card Box already wears the site's Card shadow; the switch adds nothing there.
|
|
77
|
+
- `SiteGutterFrame` takes `outerAttrs`, put on its outermost box (the padding wrapper where there is one, else the root), the box the section corner rule rounds.
|
|
78
|
+
- Group label `Shadow` → Design (`LABEL_GROUP`).
|
|
79
|
+
- Guard: new `scripts/test-box-shadow.tsx` (red first).
|
|
80
|
+
|
|
81
|
+
### Added (gallery: "Two, then threes" and Large tabs; #330)
|
|
82
|
+
|
|
83
|
+
- A twentieth photo wall, "Two, then threes" (`lib/content/gallery-layout` `twoThenThrees`): two photos half wide in the first row, then three across in every row after. A layout may carry a `lead` (and `leadPhone`): cells placed once before the cycle. The nineteen shipped layouts emit the same CSS, byte for byte.
|
|
84
|
+
- A tabbed Box can draw "Large tabs", Tabbed Gallery's strip (letter and name), a seventh `Reel` shape (`lib/reel` `largeTabs`), chosen with a new Box row `Tab shape` (shown in Tabs mode only). A Box that chooses nothing draws the strip it always drew.
|
|
85
|
+
- Not in this release: Tabbed Gallery's per-tab note and item count (see the follow-up above).
|
|
86
|
+
|
|
87
|
+
### Added (merge group 17: Logos and Payment Methods become one Logos block; plan 2026-10-23 §2 row 17)
|
|
88
|
+
|
|
89
|
+
- **Box rows for `Logos` and `PaymentBadges`** (`lib/document/blocks/general/section-to-box-rows-logos`, registered by `registerGeneralSectionRows`), both OFF. Logos → Box › Text heading · Logos block › one `LogoBlock` per stored logo. Payment Methods → the "Payment logos" layout: Box › Box (border top and bottom) › Text heading · Logos block (Logo style Cards, full colour) › Box of reassurance lines. A Payment Methods fed by a data source is skipped (`skip`), with its reason.
|
|
90
|
+
- **The Logos block holds its logos as blocks**: a `logos` slot of Logo blocks (each its own Layers row and panel) and a **Logo style** dropdown (Plain / Cards; `lib/sections/logo-look`). In its Box (`headPlacement: "own-box"`) the logo list, heading and band padding rows are hidden by the splittable sections' one show-when rule (`HEAD_ROWS_SHOW_WHEN`); Logo style is shown only there (`OWN_BOX_ROWS_SHOW_WHEN`), because a stored band's row is always Plain. A band saved before keeps drawing its `items`, byte for byte.
|
|
91
|
+
- **`Logos` may sit in a Box** (`lib/document/nestable-content-sections`).
|
|
92
|
+
- **`wrapperPadKeys(own)`** also takes a function of the old node, for a section whose own padding is a setting.
|
|
93
|
+
|
|
94
|
+
### Changed (merge group 17)
|
|
95
|
+
|
|
96
|
+
- **One drawing of a wall logo**, `LogoWallMark` (`components/Logos`): the Logos band, a Logo block inside a Logos block, and the Payment Methods chip all call it. A Logo block inside a Logos block draws the wall's logo (its height, black and white, Logo style) and, with no picture, its name, never the site's logo.
|
|
97
|
+
|
|
98
|
+
### Added (Hero slide: Show while loading; Lewis 2026-10-26, design approved the same day)
|
|
99
|
+
|
|
100
|
+
- **A Hero slide chooses what it shows until its video plays: `Show while loading`, Video frame or Image.** It replaces the slide's "Video poster" row (on INOVIT's home page a wheel render stood where the video's own frame belonged). Video frame is the video's own still, which the backend cuts once when the video is stored (efficient-backend `poster_url`); picking a video keeps it in the slide's new `videoFrame` key (`upload(…, { frame })`, `MediaUploadField` `frameKey`). Image is the old poster field, key `poster` kept, labelled `Image`. The row reads the choice as a rule (`lib/hero-video` `LOADING_SHOWS_IMAGE`); the page reads `loadingShowsOf`, because a shopper's page never loads the rule reader (`one-show-when` R3). `scripts/test-hero-show-while-loading.tsx` §3b proves both give the same answer for every stored pair.
|
|
101
|
+
- **No published slide changes by itself.** An absent choice is the stored poster's say: a slide that stores a poster shows Image, one that stores none shows Video frame. A Video frame with no frame yet (a video from outside the library) draws the slide's surface until the video plays, and the row says so.
|
|
102
|
+
- The picked file's still is efficient-easel's `HostPickedMedia.posterUrl` (efficient-easel #366, in 21.x); a host that sends none writes "", so the row shows the no-frame note.
|
|
103
|
+
- **Media manifest:** `HeroSlide` gains the media path `videoFrame` (`CUSTOM_FIELD_MEDIA`; `contentHash` `f94be8c390bc1b18`), so the template sanitizer empties it with the slide's other media. The backend vendors it (`vendor_media_manifest.py`).
|
|
104
|
+
- **A Hero slide's video pick writes the video and its frame in ONE change** (`useSelectedPatch`, lib/document/controls, from #319). Two writes raced: the second was built on the node from before the first, and the frame was lost. `scripts/test-hero-video-pick-one-write.tsx` (red first: the frame was not stored).
|
|
105
|
+
- **Three phrases join the editor's words** (`lib/editor-words-catalogue.ts`, `pnpm run words`): "Video frame", "Choose an image" and the no-frame note. "Show while loading" and "Image" were already there. A host's translation list may add them.
|
|
106
|
+
- `scripts/test-hero-show-while-loading.tsx` (red first: 9 of 22 checks).
|
|
107
|
+
- `scripts/test-no-setting-lost.tsx`: `OPENED_BY_CHOICE` — a row a merchant's choice opens is read with that choice made (`HeroSlide.poster`, the Image), so it is not counted as lost.
|
|
108
|
+
- Not yet: the `Frame at` second picker in the approved design. It is a follow-up PR after efficient-backend #3892 (the frame at a chosen second) merges.
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
### Added (Stats with Text on Box and Text, OFF; #338)
|
|
112
|
+
|
|
113
|
+
- **A section-to-box row for Stats with Text (`StatsParagraph`), OFF** (`lib/document/blocks/general/section-to-box-rows-stats`). No new block (Lewis, 2026-10-27; harness UI-49): the head is a row Box of Text blocks over its hairline, and each stat card is a Box (a 1px line on every side, padding 48 / 32) in rows of four. The figure is ONE Text in Heading 1 whose words are built from the card: the number, then the unit gold and italic by its own marks (`28==_yr_==`); a whole-number emphasis is `==_8_==`. The superscript is a second Text beside it, Body 5 in the accent colour. Known gaps are listed in the row's header; the count-up waits for the Text block's own setting.
|
|
114
|
+
- `innerPad` / `innerPadKeys` moved from the batch 1 rows to the row parts (`section-to-box-row-parts`), so the new row imports them.
|
|
115
|
+
- `scripts/test-section-to-box-stats.tsx`: §1 the row answers every key · §2 the Box tree · §3 the figure's words · §4 no size or hex pinned · §5 every old word drawn, in order.
|
|
116
|
+
|
|
117
|
+
### Changed (Button: Fill, Border, Padding, icon at the far end)
|
|
118
|
+
|
|
119
|
+
- **The Button block's `Style` row (Filled / Outline) is gone; its look is three settings of its own** (Lewis 2026-10-26, through GG; Box gaps redo). `Fill color` keeps its key `buttonColor` and gains the shell picker's opacity strip, stored as `buttonFillOpacity` (0-100; 0 is a clear button). `Border` is a new row on `buttonBorder`: the Box's own Border part (easel `SettingsBorder`), width and colour only. `Padding` is the house four-side row on the button's own keys `buttonPaddingTop/Right/Bottom/Left` and their phone twins, inside the button's border; empty shows the built-in 16 / 22. The `Icon` row offers a third position, `Icon at the far end`, on a `Fill` button only: the words sit at the start and the glyph at the end (`Btn` `spread`). The glyph is efficient-shell's `icon-at-end` (efficient-shell #634); until a shell with it is installed the choice draws no picture.
|
|
120
|
+
- **A stored button draws what it drew.** Nothing is written to a page: `lib/content/button-look` (format) reads an old `variant` through the new rows (Filled = full fill, 1px line in the fill colour; Outline = clear fill, 1px line in its own colour or its words'), and paints from the new keys only once one is stored. `variant` stays declared with no row, so a save keeps it. The hover is today's rule for a button with its own colour: no hover change. Once the new rows paint a button, its classes follow its fill: a clear fill draws with the old Outline classes (the words keep their colour; a Filled button made clear would otherwise keep its white button ink and vanish on a light page), any other fill with the Filled ones.
|
|
121
|
+
- `lib/document/ColourControl` (`ColourControl`, `InheritedColourRow`) take an optional opacity. A row WITH one is the shell's own one-line colour row (`ColorPicker` `showHexInput`: swatch, the hex as text, the `%` box), so it stays one line on a 220 panel (Lewis 2026-10-07: a colour row is always one line; measured in the real panel at 220 and 320, desktop and phone). A row without an opacity is what it was. `lib/document/controls`: ONE `BorderRow` (the shell's `BorderInput` under the shell row) draws every Border row; the section/Box row and the Button's `buttonBorderField` pass only what differs (the grey placeholder, `Each side`, line styles). The Fill color row is `colorInput`'s own site-button row with an `opacity` option (`ColourOpacity`: its key, and what it shows while unset), not a second builder (GG duplicate check, 2026-10-26). One new phrase, "Icon at the far end".
|
|
122
|
+
- **A `Text` row under the Button box opens the words' own settings** (Lewis 2026-10-26, option 1, through GG): the v4c box (words + link) is unchanged; under it, `labelText` draws easel's `SettingsDrill` (the row the Text block's `Body` entry is) and opens the words' part panel by the same part selection a click on the words makes (`usePreviewParts`). Its preview is `<style> · <case>` (`buttonWordsSummary`): the style word is the part panel's own (`No style` while the words follow none), the case is the drawn one (capitals until a case is chosen). It stores nothing. `scripts/fixtures/panel-group-order.baseline.json`: ButtonBlock's rows above the first band go from 1 to 2 by hand (the box and this row), as the guard asks for a raised line.
|
|
123
|
+
- `lib/content/section-padding` `padSideAttrs` is the one side / phone padding builder: `sectionPadAttrs` and the Button's `buttonPadAttrs` both call it (every section's attrs are unchanged, `scripts/fixtures/section-pad-attrs.json`, 88 cases). A stored number is read by `lib/finite-number` `finiteNumber`. A stored string by `lib/non-empty-string` `nonEmptyString`, the one reader: eight private copies moved to it (button-look, site-text-styles, source-bound-parts, authored-props, editor-words, controls, the host document bridge); `scripts/test-non-empty-string.ts` fails a new one, as a reader or as a test (`typeof x === "string" && x`, also over a line break); six such tests moved too (block-sources, part-rows, text-parts, editor-words, section-head-placement, button-look). The button's built-in padding has one home, `BUTTON_PAD_CLASSES` (`px-[22px] py-4`, the classes Btn draws); the Padding row's grey numbers are read from it. 22 px is off the 4 px scale and is kept as today's look until Lewis rules on it. `buttonWordsSummary` takes its words from easel (`copy.panel.cases`, `textStyles.styleName`), the part panel's own; the button's stored Border is `lib/content/borders` `BorderValue`.
|
|
124
|
+
- Tests: `scripts/test-button-look-stored-bytes.tsx` (17 stored shapes, the component and the published block, byte for byte against a fixture captured on main a9077808 before the change) and `scripts/test-button-fill-border-padding.tsx` (red first: `lib/content/button-look` did not exist). `scripts/test-button-style-one-word.tsx` now holds that the Button block has no `Style` row; Title With Buttons keeps its own.
|
|
125
|
+
- The email designer's button (efficient-admin-portal `buttonStyleField`: Fill color, Border color, Text color, Corner radius) is unchanged; the difference is written up for Victor (UI-44).
|
|
126
|
+
|
|
127
|
+
### Changed (Button: side padding 24)
|
|
128
|
+
- **A button's built-in left and right padding is 24 px, not 22** (Lewis 2026-10-27). `BUTTON_PAD_CLASSES` is `px-6 py-4`; top and bottom stay 16. A button with no padding of its own is 4 px wider. A button with its own padding is unchanged.
|
|
129
|
+
|
|
130
|
+
### Fixed (a heading's case reaches headings only; #349)
|
|
131
|
+
|
|
132
|
+
- **A Heading style's letter case no longer reaches the next section's body words** (Lewis 2026-10-27, the Stats page). `textStylesCss` puts a heading style's case on `[data-sf-text-style="heading-N"]` and on a heading element in its face (`.font-display:is(h1, h2, h3, h4)`), as its line and letter spacing already were; a body style's case is unchanged.
|
|
133
|
+
|
|
134
|
+
## 42.0.1 - 2026-10-27
|
|
135
|
+
|
|
136
|
+
**PATCH: the last wording of the retired name "Puck" is gone** (Victor Mau, 2026-10-27; wording only, no change to any published path, export or behaviour). Eleven comments in `src/` and `scripts/` that still said "Puck 0.20" now say "the old editor library" or "the document format". `scripts/test-document-names.ts` now lets through only a line that says `began as Puck 0.<n>` (before, any "Puck 0.<n>" passed), and also checks that its scan reaches `README.md`, `package.json`, `doc/` and `src/`, and that no `exports` entry names the old name. What stays: this changelog, and the table of removed paths in `scripts/verify-published-entries.mjs` (a path is the one thing a rename cannot reword).
|
|
137
|
+
|
|
3
138
|
## 42.0.0 - 2026-10-27
|
|
4
139
|
|
|
5
140
|
**MAJOR for hosts: the old "Puck" names 41.0.0 kept are removed** (Victor Mau, 2026-10-26; phase 4 of 4, contract). `efficient-easel` is now `^22.0.0` (was `^21.1.0`; easel 22 removed the `puck` prop, `data-puck-*`, `screen/lib/puck/*` and the inspector mode `"puck"`); `efficient-shell` stays `^10.0.0`. A host moves easel with this release. Nothing saved changes: no saved data ever carried the name.
|
|
@@ -26,6 +161,26 @@
|
|
|
26
161
|
- `scripts/test-document-names.ts` is now the guard that the name is gone (red first on 41.1.0's tree: 900-odd lines in 250 files): no file under `src/`, `scripts/`, `doc/`, no `README.md` or `package.json` (the `exports` map) names it, except a line that says `Puck 0.20`; the new names are exported. `CHANGELOG.md` and the table of removed paths in `verify-published-entries.mjs` are the allow-list.
|
|
27
162
|
- `scripts/verify-dist.mjs` loses §8 (the old-path forwarders it held).
|
|
28
163
|
|
|
164
|
+
### Added (the banner's legal blocks: words locked, look free)
|
|
165
|
+
|
|
166
|
+
- **A Text or Button whose words the consent rules write is locked, and says so** (cookie banner build, PR 4; design final 2026-10-23, §3.4, §3.5, §5). Read off `consentWords` (#286):
|
|
167
|
+
- Locked: no delete, hide, duplicate or drag, and so is any Box that holds one (`lib/content/consent-banner` `isConsentLocked`; the screen's `blockRules.isLockedBlock` asks `lib/document/locked-blocks` `websiteNodeIsLocked`).
|
|
168
|
+
- Its panel: the words row's place (Text's Body, Button's Button box) says `Words · Set by country` in easel's read-only text row (`FieldText readOnly`), with the lock; the Button's link row goes. Every look row stays. New `lib/document/consent-words-field`.
|
|
169
|
+
- `consentWords` is a kept field on every Text and Button (declared, so a save keeps it; draws the no-control mark; reached by the words row).
|
|
170
|
+
- Its words are not typed on the canvas (`lib/document/canvas-typing`).
|
|
171
|
+
- Words catalogue: + `Words`, `Set by country`.
|
|
172
|
+
- Guard: new `scripts/test-consent-locked-words.tsx` (red first: 4 of 4 failed). `test-no-control-fields-draw-the-mark` §3 lists `consentWords` → `label`.
|
|
173
|
+
|
|
174
|
+
### Added (the cookie banner on the popups' structure)
|
|
175
|
+
|
|
176
|
+
- **The cookie banner is built like a popup** (cookie banner build, PR 2; design final 2026-10-23, `~/GitHub/mockups/cookie-banner-editable-2026-10-23/`). `lib/content/consent-banner` gains:
|
|
177
|
+
- `resolveConsentBannerLook(rootProps)`: where the banner sits and how wide it is, as the popup rows say it (`lib/popup/look`). The old `layout` maps in, never migrated: Bar = bottom centre + full width, Card = bottom left + 440. A row the merchant set wins. The banner never takes a tint, a close button or an outside click.
|
|
178
|
+
- `CONSENT_WORDS_PROP` (`consentWords`), `CONSENT_WORD_KEYS` (eyebrow, notice, accept, reject, choose; the button keys are the shop's own `CONSENT_BUTTONS` names) and `consentWordsOf(props)`: a block stores which consent words it shows, never the words.
|
|
179
|
+
- `consentBannerDocument()`: the canvas a banner starts from: Box "Banner" › eyebrow Text, notice Text, Box "Buttons" › Accept all, Reject all, Choose. `withConsentBannerDocument(doc)` gives a banner page with no canvas yet that document (every banner page today).
|
|
180
|
+
- `lib/popup/look` `resolvePopupLook(rootProps, defaults?)`: a page on the same frame passes its own defaults.
|
|
181
|
+
- `CONSENT_BANNER_LAYOUTS`, `CONSENT_BANNER_LAYOUT_LABEL` and the `Layout` row stay until storefront-blocks draws the new page rows (cookie banner PR 5), then go.
|
|
182
|
+
- Guard: new `scripts/test-consent-banner-document.ts` (red first: 8 of 8 failed).
|
|
183
|
+
|
|
29
184
|
### Fixed (the Box footer: columns start level, the email list named once)
|
|
30
185
|
|
|
31
186
|
- **A cell Box made by "Switch to Box footer" stores top and bottom padding 0** (Lewis 2026-10-26, the INOVIT US footer: "this footer is not my design"). A Box is born with `padV2` and 24 / 24 (its defaultProps), and a padV2 Box draws that padding inline on its root, where the row's Gap only rule cannot take it away. So the logo-and-tagline stack and every old Footer Box began 24px under the menu beside them. The old footer's cells had no padding; `lib/document/box-footer` now writes 0 / 0 on both kinds of cell Box. A stored footer does not change.
|
|
@@ -99,6 +254,19 @@ Batch 1 follow-up (#328). Every row stays OFF: no page changes.
|
|
|
99
254
|
|
|
100
255
|
- `scripts/test-gap-only-canvas.tsx` now holds only what the builder owns, and no copy of the host's sheet: §1 the part host carries `data-sf-part-host` and `display: contents`, §2 the builder's `BLOCK_ATTR` is easel's `BLOCK_ATTRIBUTE`, §3 the canvas sheet holds no Gap only rule of its own (red first: the copy was there). The host's rule is tested where it lives, in efficient-storefront-blocks `scripts/test-gap-only-one-rule.tsx`, against its real `globals.css`.
|
|
101
256
|
|
|
257
|
+
### Changed (the shell's text and colour tools; duplicate re-check 2026-10-26, rows R04 and R05)
|
|
258
|
+
|
|
259
|
+
- **`slugify`, the WCAG luminance, `contrastRatio` and `accentInk`'s ink choice are efficient-shell's** (`efficient-shell/format`, shell #603, which took this builder's slug rule as its own). `lib/theme` drops its own `relativeLuminance` and `contrastRatio` and re-exports the shell's `contrastRatio`; `accentInk` is the shell's `readableInk` over `ACCENT_INKS`. `lib/links/page-link-rules` and `lib/page-copy` import the shell's `slugify`.
|
|
260
|
+
- **Renamed copies are gone too:** `components/DocBody`'s `sectionAnchorId` slugs with the shell's `slugify`; `lib/hero-texture` (its `hexToChannels`) and `lib/sections/hero-overlay` (its `rgba`) read a colour with the shell's `hexToRgb`. `components/DuplicatePageDialog`, `lib/content/contact`, `components/AnchorField`, `lib/document/passes/section-anchor` and `lib/links/page-link-rules` call the shell's `slugify` directly, not through `lib/slugify`, `slugifyAnchor` or `slugifyGroupId`.
|
|
261
|
+
- Same anchor ids for every label. The hero texture and the hero overlay give the same gradient for every `#rrggbb` colour. A `#rgb` or `#rrggbbaa` overlay colour, and an `#rrggbbaa` texture colour, now draw that colour (opaque) where they fell back to the default near-black; a texture colour typed without its `#` now falls back to the default.
|
|
262
|
+
- `lib/theme`'s own hex reader (`hexChannels`) is gone too: the colour mixes and `darkerAccents` read a colour with the shell's `hexToRgb`.
|
|
263
|
+
- Same results for every `#rgb` / `#rrggbb` colour and every slug (old against new, 2026-10-26; the hex reader 2026-10-27, 20,012 inputs). One input class changes: an 8-digit `#rrggbbaa` colour is read as its opaque colour. It gets that colour's contrast where the builder said "unknown" (`null`), a mix of it where the mix kept the colour as it was, and three darker shades where `darkerAccents` offered none.
|
|
264
|
+
- `scripts/test-shell-tools-not-copied.ts` (red first: 3 copies by name; then 5 by shape): §1 src/ defines no `slugify`, `hexToRgb`, `relativeLuminance`, `contrastRatio` or `readableInk` of its own; §2 the rule's SHAPE (the slug regex, `parseInt(…, 16)`, `toString(16)`, the WCAG formula) appears only in the files it lists, each with its reason, so a copy under another name fails too; §3 no file imports `@/lib/slugify`. It is still text: a copy written another way passes, and review reads the diff for it.
|
|
265
|
+
|
|
266
|
+
### Deprecated (removed in a later major, after the hosts move)
|
|
267
|
+
|
|
268
|
+
- **`lib/slugify`** (the published path `efficient-web-builder/format/lib/slugify`), **`slugifyAnchor`** (`lib/links/page-link-rules`) and **`slugifyGroupId`** (`lib/content/contact`): each is the shell's `slugify` under an old name. No file of this builder uses them. They stay because hosts import them (efficient-storefront-blocks' `links` entry re-exports `slugifyAnchor`; its `render/lib/wheels/collections` and `scripts/test-slugify.ts` import the other two), and removing a published path or name is a major (harness CI-3). Hosts import `slugify` from `efficient-shell/format`.
|
|
269
|
+
|
|
102
270
|
## 41.1.0 - 2026-10-27
|
|
103
271
|
|
|
104
272
|
Additive: every row written for 41.0.0 converts as before (the three section-to-box guards, unchanged cases, pass).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as n,Fragment as
|
|
1
|
+
"use client";import{jsx as n,Fragment as d,jsxs as m}from"react/jsx-runtime";import{useContext as p,useEffect as u,useId as g,useState as h}from"react";import{SettingsField as x,SettingsSwitch as S}from"efficient-easel/panel";import{AnchorIcon as k}from"efficient-easel/icons";import{ScreenDocumentContext as b}from"efficient-easel/screen/components/ScreenDocumentContext";import{Snippet as I}from"efficient-shell/ui";import{say as f}from"../../format/lib/editor-words.js";import{slugify as j}from"efficient-shell/format";import{anchorPath as w}from"../../format/lib/links/page-link-rules.js";import{shopRouteBase as A}from"../../format/lib/web-runtime.js";import{readHidable as F}from"efficient-easel/draw";function N({value:i,onChange:o,nameBox:a}){const s=F(i).text,[l,c]=h(!1),e=l||s.trim()!=="",t=g();return m(d,{children:[n(x,{label:f("Add an anchor"),labelId:t,icon:n(k,{}),action:n(S,{checked:e,ariaLabelledBy:t,onChange:r=>{c(r),!r&&s!==""&&o("")}})}),e&&a(i,o),e&&n(y,{name:s})]})}function y({name:i}){const o=p(b),a=o?.templateId?"":o?.currentSlug??"",[s,l]=h("");u(()=>l(A()||window.location.origin),[]);const c=j(i);if(!c||!a)return null;const e=`${s}${w(a,c)}`,t=e.replace(/^https?:\/\//,""),r=t.lastIndexOf("#");return n("div",{className:"sf-anchor-link",children:n(I,{value:e,label:f("link"),size:"sm",children:m("span",{className:"sf-anchor-link-text",children:[n("span",{className:"sf-anchor-link-path",children:t.slice(0,r)}),n("span",{className:"sf-anchor-link-hash",children:t.slice(r)})]})})})}export{N as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as l,jsxs as S,Fragment as L}from"react/jsx-runtime";import{useId as C,useState as i}from"react";import{Button as F,Dialog as R,FormField as T,Input as k,Stack as U}from"efficient-shell/ui";import{copySuggestion as _,urlHandleTaken as K}from"../lib/page-copy.js";import{slugify as w}from"
|
|
1
|
+
"use client";import{jsx as l,jsxs as S,Fragment as L}from"react/jsx-runtime";import{useId as C,useState as i}from"react";import{Button as F,Dialog as R,FormField as T,Input as k,Stack as U}from"efficient-shell/ui";import{copySuggestion as _,urlHandleTaken as K}from"../lib/page-copy.js";import{slugify as w}from"efficient-shell/format";import{say as n}from"../../format/lib/editor-words.js";function z({source:t,taken:h,duplicate:x,onClose:f,onDuplicated:I}){const g=C(),m=C(),[j,B]=i(null),[r,p]=i(""),[a,d]=i(""),[E,y]=i(!1),[o,v]=i(!1),[b,u]=i(null);if(t!==j&&(B(t),t)){const e=_(t,h);p(e.title),d(e.slug),y(!1),u(null)}const s=K(a,h),D=!!(t&&r.trim()&&a&&!s&&!o),c=async()=>{if(!(!t||!D)){v(!0),u(null);try{const e=await x(t,{title:r.trim(),slug:a});I(e)}catch{u(n("Couldn’t duplicate the page — please retry."))}finally{v(!1)}}};return l(R,{open:t!==null,onClose:()=>{o||f()},size:"sm",title:n("Duplicate “{name}”",{name:t?.label??""}),description:n("The copy is a draft and stays hidden until you publish it. It opens in the editor."),footer:S(L,{children:[l(F,{variant:"secondary",onClick:f,disabled:o,children:n("Cancel")}),l(F,{onClick:()=>{c()},disabled:!D,loading:o,children:n("Duplicate page")})]}),children:S(U,{gap:4,children:[l(T,{label:n("Title"),htmlFor:g,error:b??void 0,children:l(k,{id:g,value:r,invalid:!!b,onChange:e=>{p(e.target.value),E||d(w(e.target.value))},onKeyDown:e=>{e.key==="Enter"&&c()}})}),l(T,{label:n("URL handle"),htmlFor:m,hint:s?void 0:n("URL: /{slug}",{slug:a}),error:s?n("Another page uses this URL handle."):void 0,children:l(k,{id:m,value:a,invalid:s,onChange:e=>{y(!0),d(w(e.target.value))},onKeyDown:e=>{e.key==="Enter"&&c()}})})]})})}export{z as default};
|
|
@@ -7,6 +7,8 @@ interface Props {
|
|
|
7
7
|
placeholder?: string;
|
|
8
8
|
focusKey?: string;
|
|
9
9
|
focusWhen?: (props: Record<string, unknown>) => boolean;
|
|
10
|
+
frameKey?: string;
|
|
11
|
+
fieldKey?: string;
|
|
10
12
|
}
|
|
11
|
-
export default function MediaUploadField({ value, onChange, label, accept, placeholder, focusKey, focusWhen }: Props): import("react").JSX.Element;
|
|
13
|
+
export default function MediaUploadField({ value, onChange, label, accept, placeholder, focusKey, focusWhen, frameKey, fieldKey }: Props): import("react").JSX.Element;
|
|
12
14
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as t}from"react/jsx-runtime";import{SettingsDefaultReset as
|
|
1
|
+
"use client";import{jsx as t}from"react/jsx-runtime";import{SettingsDefaultReset as D,SettingsField as E}from"efficient-easel/panel";import{useSelectedHost as H}from"../lib/document/selected-host.js";import{FOCAL_DEFAULT as I}from"efficient-shell/format";import{ImageIcon as k,PlayIcon as F}from"efficient-easel/icons";import{MediaUploadField as M}from"efficient-shell/ui";import{useContext as y}from"react";import{ScreenDocumentContext as A}from"efficient-easel/screen/components/ScreenDocumentContext";import{editorEaselWords as B,say as c}from"../../format/lib/editor-words.js";import{phoneKey as L}from"efficient-easel/draw";import{PHONE_CLEAR as O}from"../../format/lib/document/phone-override.js";import{usePreviewDevice as R}from"efficient-easel/draw/client";import{requestMediaPick as T}from"efficient-easel/screen/lib/media-picker";import{useEaselHost as V}from"efficient-easel/screen/lib/host";import{mediaValueSrc as _}from"../../format/lib/media-value.js";import{useSelectedPatch as j}from"../lib/document/controls.js";import{backendOf as N}from"../lib/website-session.js";import{useEaselSession as W}from"efficient-easel/screen/lib/session-context";function q(o,d){const e=H(),n=R()==="mobile";if(!o||!e||d&&!d(e.values??{}))return null;const r=typeof e.values?.[o]=="string"&&e.values[o]?String(e.values[o]):I,s=L(o),p=typeof e.values?.[s]=="string"&&e.values[s]?String(e.values[s]):void 0,m=e.onChange;return{phone:n,desktop:r,own:p,focus:n?p??r:r,set:f=>m(n?s:o,f),clear:()=>m(s,O)}}function z({value:o,onChange:d,label:e,accept:n,placeholder:r,focusKey:s,focusWhen:p,frameKey:m,fieldKey:f}){const b=V(),x=W(),v=c(e),a=n.startsWith("video"),i=q(a?void 0:s,p),g=y(A),w=j(),l=m&&f?{video:f,frame:m}:null,C=u=>T(b,{accept:n,title:v,...u?{file:u}:{}}).then(h=>!h||!l?h?.url??null:(w({[l.video]:h.url,[l.frame]:h.posterUrl??""}),null)),P=l?u=>u?d(u):w({[l.video]:"",[l.frame]:""}):d;if(g&&!g.capabilities.mediaEditing)return t(E,{label:v,icon:a?t(F,{}):t(k,{}),children:t("div",{className:"sf-image-slot-inert",children:a?c("Templates don’t store videos — this slot stays a placeholder. Each website picks its own after it’s created."):c("Templates don’t store images — this slot stays a placeholder. Each website picks its own after it’s created.")})});const S=_(o),U=i?.phone&&S?t(D,{words:B()?.panel,label:c("Image focus"),changed:!!i.own,detail:c("{value} on desktop",{value:i.desktop}),onReset:i.clear}):void 0;return t(E,{label:v,icon:a?t(F,{}):t(k,{}),action:U,children:t("div",{style:{flex:"1 1 auto",minWidth:0},children:t(M,{value:S,onChange:P,onPick:C,accept:a?"video/*":"image/*",kind:a?"video":"image",placeholder:r===void 0?void 0:c(r),maxSizeBytes:N(x).media.maxUploadBytes,...i?{focus:i.focus,onFocusChange:i.set}:{}})})})}export{z as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as t,Fragment as $,jsxs as w}from"react/jsx-runtime";import{Fragment as
|
|
1
|
+
"use client";import{jsx as t,Fragment as $,jsxs as w}from"react/jsx-runtime";import{Fragment as ke,useEffect as Ae,useId as Ie,useMemo as ee,useRef as Re,useState as d}from"react";import{useScreenDocument as De}from"efficient-easel/screen/components/ScreenDocumentContext";import{UiIcon as G}from"efficient-easel/draw/client";import xe from"efficient-easel/screen/components/SidePanelHead";import{useWebsiteName as Ne}from"./WebsiteSettingsPanel.js";import{InspectorIconButton as ve}from"efficient-easel/chrome";import{Button as ne,Dialog as Ee,FormField as Le,Input as te,PopupMenu as Oe,PopupMenuItem as oe,toast as ae}from"efficient-shell/ui";import{LayersTree as Be,TreeGroupLabel as Fe,TreeRow as le,TreeRowAction as x}from"efficient-easel/tree";import{AddIcon as Me,DuplicateIcon as _e,PageIcon as ze,SettingsIcon as Ge}from"efficient-easel/icons";import{PagesIcon as He}from"efficient-easel/rail";import{useEaselHost as Te}from"efficient-easel/screen/lib/host";import{bucketEditorPageRows as Ue,DYNAMIC_PAGES_GROUP_KEY as We,isDynamicPageRow as je,MAIN_PAGES_GROUP as qe}from"../../format/lib/editor-page-rows.js";import{useEaselSession as Ke}from"efficient-easel/screen/lib/session-context";import{holdPageRow as H,usePageRows as Ye}from"../lib/page-rows.js";import{say as n,sayCount as Je}from"../../format/lib/editor-words.js";import{canDuplicatePage as Qe,uniqueSlug as se,usePageDuplicate as Ve}from"../lib/page-copy.js";import Xe from"./DuplicatePageDialog.js";import{newPopupPage as Ze}from"../../format/lib/popup/new-popup.js";const ie="sf-editor-pages-collapsed-groups";function $e({onNavigate:u,onClose:en,activeSurface:T,onPreviewSurface:re}){const C=Ke().chrome?.pageRows,U=Te(),{adapter:p,capabilities:m,ready:N,currentSlug:W}=De(),de=Ne(),{rows:c,reload:v,setRows:j,getRows:ce}=Ye(),[E,ue]=d(""),[i,S]=d(!1),[k,g]=d(null),[q,A]=d(!1),[f,L]=d(""),K=Ie(),O=Ve(),[pe,B]=d(null),[F,me]=d(()=>{if(typeof window>"u")return new Set;try{const e=window.localStorage.getItem(ie);return new Set(e?JSON.parse(e):[])}catch{return new Set}});Ae(()=>{try{window.localStorage.setItem(ie,JSON.stringify([...F]))}catch{}},[F]);const ge=e=>me(a=>{const o=new Set(a);return o.has(e)?o.delete(e):o.add(e),o}),fe=ee(()=>Ue(c??[]),[c]),M=E.trim().toLowerCase(),Y=e=>!M||e.toLowerCase().includes(M),he=e=>M?!0:!F.has(e),I=ee(()=>new Set((c??[]).map(e=>e.slug)),[c]),J=()=>{if(m.pageCreationInAdminForm){U.send("storefront-editor:new-page");return}L(""),g(null),A(!0)},Q=async()=>{const e=f.trim();if(!(!e||!N||i||!p.createPage)){S(!0),g(null);try{const a=await p.createPage({slug:se(e,I),title:e,layout:{}});await v(),A(!1),L(""),u(a.slug)}catch{g(n("Couldn’t add the page — please retry."))}finally{S(!1)}}},R=m.hasSiteSettings&&!!p.createPage,be=async()=>{if(!(!N||i||!p.createPage)){S(!0),g(null);try{const e=await p.createPage(Ze(n("New popup"),I));await v(),u(e.slug)}catch{g(n("Couldn’t add the popup — please retry."))}finally{S(!1)}}},V=Re(null),[h,b]=d(null),Pe=()=>{if(!R)return J();if(h)return b(null);const e=V.current?.getBoundingClientRect();e&&b({top:e.bottom+6,right:Math.max(8,window.innerWidth-e.right)})},ye=e=>{const a=c??[],o=p.deletePage;if(!N||i||!o||a.length<=1)return;const s=a.findIndex(l=>l.id===e.id),r=a.filter(l=>l.id!==e.id),P=e.slug===W;H(e.id,!0),j(r),g(null),P&&r[0]&&u(r[0].slug);const D=()=>{H(e.id,!1);const l=ce()??[];if(l.some(Se=>Se.id===e.id))return;const y=[...l];y.splice(Math.max(0,Math.min(s,y.length)),0,e),j(y)};ae.undoable(n("Deleted “{name}”",{name:e.label}),{actionLabel:n("Undo"),commit:async l=>{await o(e.id,l),H(e.id,!1)},undo:()=>{D(),P&&u(e.slug)},onFail:()=>{D(),ae.error(n("Couldn’t delete the page — please retry."))}})},we=e=>U.send("storefront-editor:open-page",{slug:e}),Ce=e=>{if(!Y(e.label))return null;const a=!T&&e.slug===W,o=m.canDeletePagesInline&&(c??[]).length>1,s=je(e),r=e.kind==="lightbox",P=[...s?[{label:n("Dynamic"),tone:"info"}]:[],...r?[{label:n("Lightbox"),tone:"success"}]:[],...e.draft?[{label:n("draft"),tone:"draft"}]:[]],D=P.length>0?P:void 0,l=!!O&&Qe(e),y=l||m.pageCreationInAdminForm||o?w($,{children:[l&&t(x,{kind:"plain",label:n("Duplicate “{name}”",{name:e.label}),disabled:i,onClick:()=>B(e),children:t(_e,{size:13})}),m.pageCreationInAdminForm&&t(x,{kind:"plain",label:n("Page settings for “{name}”",{name:e.label}),onClick:()=>we(e.slug),children:t(Ge,{size:13})}),o&&t(x,{kind:"delete",label:n("Delete “{name}”",{name:e.label}),disabled:i,onClick:()=>ye(e),children:t(G,{name:"trash",size:13,strokeWidth:1.7,rounded:!0})})]}):void 0;return t(le,{icon:t(ze,{size:14}),name:e.label,selected:a,onSelect:()=>u(e.slug),badge:D,actions:y,rowProps:{"data-page-slug":e.slug}},e.id)},_=(e,a,o)=>{const s=o.filter(Boolean);if(s.length===0)return null;const r=he(e);return w(ke,{children:[t(Fe,{count:s.length,countLabel:Je("{n} page","{n} pages",s.length),expanded:r,onToggle:()=>ge(e),children:a}),r&&s]},e)},X=(C?.rows??[]).filter(e=>Y(e.label)).map(e=>{const a=T===e.key;return t(le,{icon:e.icon,name:e.label,selected:a,onSelect:()=>re(e.key),badge:{label:n("Preview"),tone:"warning"},actions:t(x,{kind:"plain",label:n("Open the {name} in a new tab",{name:e.label}),onClick:()=>window.open(e.href,"_blank","noopener,noreferrer"),children:t(G,{name:"external-link",size:13,strokeWidth:1.7,rounded:!0})}),rowProps:{"data-shop-surface":e.key}},e.key)}),Z=m.hasSiteSettings&&!!C,z=(()=>{if(c===null)return null;const e=[];let a=!1;for(const o of fe){Z&&!a&&o.key.startsWith("system:")&&(e.push(_("shop",C.title,X)),a=!0);const s=o.key===We||o.label===qe?n(o.label):o.label;e.push(_(o.key,s,o.rows.map(Ce)))}return Z&&!a&&e.push(_("shop",C.title,X)),e})();return w("div",{className:"sf-pages",children:[t(xe,{icon:t(He,{}),title:n("Pages"),context:de,actions:t(ve,{buttonRef:V,label:R?n("Add"):n("New page"),hasPopup:R?"menu":void 0,expanded:R?h!==null:void 0,onClick:Pe,children:t(Me,{size:15})})}),h&&t(Oe,{portal:!0,style:{top:h.top,right:h.right},onClose:()=>b(null),children:w("div",{role:"menu","aria-label":n("Add"),children:[t(oe,{role:"menuitem",onClick:()=>{b(null),J()},children:n("Page")}),t(oe,{role:"menuitem",disabled:i,onClick:()=>{b(null),be()},children:n("Popup")})]})}),t("div",{className:"sf-pages-find",children:t(te,{type:"search",leftIcon:t(G,{name:"search",size:14,rounded:!0}),placeholder:n("Search all pages…"),value:E,onChange:e=>ue(e.target.value),"aria-label":n("Search all pages")})}),k&&!q&&t("div",{className:"sf-note sf-note--error",role:"alert",children:k}),z===null?t("div",{className:"sf-note",children:n("Loading…")}):z.some(Boolean)?t(Be,{ariaLabel:n("Pages"),className:"sf-scroll",children:z}):t("div",{className:"sf-note",children:E.trim()?n("No pages match your search"):n("No pages yet. Add one with + above.")}),O&&t(Xe,{source:pe,taken:I,duplicate:O,onClose:()=>B(null),onDuplicated:e=>{B(null),v(),u(e.slug)}}),t(Ee,{open:q,onClose:()=>A(!1),size:"sm",title:n("Add a page"),description:n("Give the new template page a name. It starts blank — add sections once it opens."),footer:w($,{children:[t(ne,{variant:"secondary",onClick:()=>A(!1),children:n("Cancel")}),t(ne,{onClick:()=>{Q()},disabled:i||!f.trim(),loading:i,children:n("Add page")})]}),children:t(Le,{label:n("Page name"),htmlFor:K,hint:f.trim()?n("URL: /{slug}",{slug:se(f,I)}):void 0,error:k??void 0,children:t(te,{id:K,value:f,invalid:!!k,onChange:e=>L(e.target.value),onKeyDown:e=>{e.key==="Enter"&&Q()},placeholder:n("e.g. About")})})})]})}export{$e as default};
|
|
@@ -9,6 +9,8 @@ export type InspectorMode = {
|
|
|
9
9
|
kind: "header";
|
|
10
10
|
} | {
|
|
11
11
|
kind: "website";
|
|
12
|
+
tab?: string;
|
|
13
|
+
revealPageGroup?: boolean;
|
|
12
14
|
} | {
|
|
13
15
|
kind: "chat";
|
|
14
16
|
} | {
|
|
@@ -29,6 +31,7 @@ export type InspectorMode = {
|
|
|
29
31
|
export declare const SELECTION_MODE: InspectorMode;
|
|
30
32
|
export declare const HEADER_MODE: InspectorMode;
|
|
31
33
|
export declare const WEBSITE_MODE: InspectorMode;
|
|
34
|
+
export declare const WEBSITE_PAGE_MODE: InspectorMode;
|
|
32
35
|
export declare const CHAT_MODE: InspectorMode;
|
|
33
36
|
export declare const SOCIAL_MODE: InspectorMode;
|
|
34
37
|
type PanelContext = {
|
|
@@ -60,10 +63,11 @@ export type InspectorPanel = {
|
|
|
60
63
|
render: (mode: InspectorMode, ctx: PanelContext) => ReactNode;
|
|
61
64
|
};
|
|
62
65
|
export declare function resolvePanel(kind: InspectorMode["kind"], capabilities: EditorCapabilities): InspectorPanel | null;
|
|
63
|
-
export default function SectionEditor({ mode, onOpenWebsiteSettings, onOpenSiteStyles, onSelectNode, hideNodeActions, onNotify, onHidePanel, }: {
|
|
66
|
+
export default function SectionEditor({ mode, onOpenWebsiteSettings, onOpenSiteStyles, onOpenPageStyles, onSelectNode, hideNodeActions, onNotify, onHidePanel, }: {
|
|
64
67
|
mode: InspectorMode;
|
|
65
68
|
onOpenWebsiteSettings: () => void;
|
|
66
69
|
onOpenSiteStyles?: () => void;
|
|
70
|
+
onOpenPageStyles?: () => void;
|
|
67
71
|
hideNodeActions?: boolean;
|
|
68
72
|
onNotify?: (msg: string, tone?: "success" | "error") => void;
|
|
69
73
|
onHidePanel?: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as n,jsxs as m,Fragment as k}from"react/jsx-runtime";import{useState as W}from"react";import{useEasel as be}from"efficient-easel/easel";import{headWords as j,InspectorHead as ke,InspectorIconButton as y}from"efficient-easel/chrome";import{DuplicateIcon as U,TrashIcon as Pe}from"efficient-easel/icons";import{panelFieldsOf as Ee}from"efficient-easel/screen/lib/document/panel-fields";import{TICKER_PART_LABEL as Y}from"../../render/components/PreviewTickerContext.js";import ve from"./SectionIcon.js";import{PanelHideButton as N}from"efficient-easel/screen/components/SidePanelHead";import{useEaselSession as Ie}from"efficient-easel/screen/lib/session-context";import{say as o}from"../../format/lib/editor-words.js";import Oe,{HintsToggle as Le,SHOW_HINTS_DEFAULT as ye}from"./WebsiteSettingsPanel.js";import Ne from"./ChatSettingsPanel.js";import Te from"./SocialLinksPanel.js";import De from"./TickerSettingsPanel.js";import He,{PartSourceNote as _e}from"./PartSettingsPanel.js";import Re from"./DuplicateToPageMenu.js";import Ae from"./DuplicatePageDialog.js";import{canDuplicatePage as Ce,usePageDuplicate as Fe}from"../lib/page-copy.js";import{usePageRows as Me}from"../lib/page-rows.js";import{useScreenDocument as xe}from"efficient-easel/screen/components/ScreenDocumentContext";import{usePreviewHeader as Be}from"../../render/components/PreviewHeaderContext.js";import{useSectionOps as ze}from"efficient-easel/screen/lib/document/use-section-ops";import{SELECTION_MODE as Ke,isSelectionMode as P}from"efficient-easel/screen/lib/screen-parts";import{usePreviewParts as We}from"efficient-easel/draw/client";import{entryPartsOf as je,SectionTextEntries as Ue}from"./SectionTextEntries.js";import{SectionTextSuppressProvider as Ye}from"../lib/document/section-text-suppress.js";import{HEADER_TYPE as Ze,ROOT_ZONE as Z}from"efficient-easel/draw";import{websiteDuplicateBlocked as $e}from"../lib/document/every-page.js";import{FOOTER_TYPE as T}from"../lib/document/footer-blocks.js";import qe from"./SwitchToBoxFooter.js";import{SiteFields as $}from"./SiteFields.js";import Ge from"./HeroPartPanel.js";import{HERO_MEDIA_PART_LABELS as Je,HERO_PART_MODE as Qe,heroPartLabel as Ve}from"../../render/lib/document/hero-media-parts.js";import{SettingsSwitch as Xe}from"efficient-easel/panel";import{foldTopTier as et}from"../lib/document/field-groups.js";import{FoldHeadingScope as tt}from"../lib/document/panel-heading-scope.js";import{partRowField as nt}from"../lib/document/part-row-field.js";import{decodePartKey as ot,partRowHeadLabel as it}from"../../render/lib/document/part-rows.js";import{encodePartId as rt,partHeadLabel as st,partLabel as at,sectionTextParts as lt}from"../../render/lib/document/text-parts.js";import{partSourceOf as ct,sourceMenuIdOf as dt,sourceSlugOf as pt}from"../../format/lib/document/source-bound-parts.js";const ln=Ke,cn={kind:"header"},dn={kind:"website"},pn={kind:"chat"},mn={kind:"social"},S="Part";function mt(e){return o("Part of {name}",{name:o(e)})}function ut(e,i,r){const l=e.describeNode(i);return{name:r,kindLabel:l?mt(l.label):o(S)}}function ft(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 q({what:e}){const i=ft(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]})]})}function D(e){const i=Qe[e];return{name:Je[e],kindLabel:S,icon:i,head:(r,l)=>{if(r.kind!==i)return null;const p=l.describeNode(r.nodeId);if(!p)return null;const u=j({name:o(Ve(e,p.props)),tier:"part",of:o(p.label)},{partOf:({name:d})=>o("Part of {name}",{name:d})});return{name:u.name,kindLabel:u.kind}},render:(r,l)=>r.kind===i?n(Ge,{nodeId:r.nodeId,part:e,sectionName:l.describeNode(r.nodeId)?.label??"Hero",onUpToSection:()=>l.onSelectNode(r.nodeId)}):null}}const ht={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(Oe,{themeFromDocument:!i.capabilities.hasSiteTheme,tokenRef:i.tokenRef,siteId:i.siteId,onNotify:i.onNotify})},chat:{name:"Live chat",kindLabel:"Site settings",icon:"chat",render:()=>n(Ne,{})},social:{name:"Social links",kindLabel:"Site settings",icon:"social",render:()=>n(Te,{unavailable:n(q,{what:"Social link"})})},ticker:{name:Y,kindLabel:S,icon:"ticker",head:(e,i)=>e.kind==="ticker"?ut(i,e.heroId,o(Y)):null,render:e=>n(De,{heroId:e.kind==="ticker"?e.heroId:""})},heroMedia:D("media"),heroImage:D("image"),heroImage2:D("image2"),part:{name:S,kindLabel:S,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:p}=ot(e.propKey),u=p?nt(r.fields[l],p):r.fields[l],d=it(o(st(at(u??{},l))),p),f=j({name:d,tier:"part",of:o(r.label)},{partOf:({name:w})=>o("Part of {name}",{name:w})});return{name:f.name,kindLabel:f.kind}},render:(e,i)=>e.kind==="part"?n(He,{nodeId:e.nodeId,propKey:e.propKey,onBack:()=>i.onSelectNode(e.nodeId),onEditStyle:i.onOpenSiteStyles}):null}},gt=new Set(["header","website","chat"]);function St(e,i){if(e==="selection")return null;const r=ht[e];return gt.has(e)&&!i.hasSiteSettings?{...r,kindLabel:"Not part of a template",render:()=>n(q,{what:r.name})}:r}function wt({mode:e,onOpenWebsiteSettings:i,onOpenSiteStyles:r,onSelectNode:l,hideNodeActions:p=!1,onNotify:u,onHidePanel:d}){const{capabilities:f,tokenRef:w,notifyParent:G,currentSlug:H,siteId:E,runAuthed:J,readOnly:Q,navigate:V}=xe(),v=Fe(),{rows:_,reload:X}=Me(),I=_?.find(a=>a.slug===H)??null,[ee,O]=W(null),{websiteName:te}=Be(),b=ze({readOnly:Q}),{select:ne}=We(),{selectedItem:t,getItemById:oe,getSelectorForId:ie,config:h,appState:re}=be(a=>a),se=Ee(h,t?{type:t.type,props:t.props}:null),R=t?lt(se??h.components[t.type]?.fields,t.props):[],ae=a=>h.components[a]?.label??a,s=t?ie(t.props.id):void 0,c=St(e.kind,f),le=Ie(),A={capabilities:f,tokenRef:w,hostPanels:le.chrome?.panels,describeNode:a=>{const g=oe(a);if(!g)return null;const K=h.components[g.type];return{type:g.type,label:K?.label??g.type,fields:K?.fields??{},props:g.props??{}}},siteId:E,websiteName:te??null,notifyParent:G,onNotify:u,onOpenWebsiteSettings:i,onOpenSiteStyles:r,onSelectNode:l},C=c?.head?.(e,A)??null,ce=C?.name??(c?o(c.name):t?o(ae(t.type)):o("Page settings")),de=C?.kindLabel??(c?o(c.kindLabel):t?s&&s.zone!==Z?o("Block"):o("Section"):o("Page")),pe=c?c.icon:t?t.type:"page",F=c?null:t?h.components[t.type]?.fields??null:h.root?.fields??null,me=F?et(F):2,M=P(e)&&t?ct(t.type):null,ue=!!t&&!!s&&s.zone===Z&&t.type!==T&&t.type!==Ze,L=$e(re?.data,t),fe=()=>{L||s&&b.duplicateComponent(s.zone,s.index)},he=()=>{s&&(b.removeComponent(s.zone,s.index),b.select(null))},ge=t?h.components[t.type]?.defaultProps?.previewHover:void 0,x=P(e)&&!!t&&!!s&&ge!==void 0,B=x&&t.props.previewHover===!0,Se=()=>{!t||!s||b.replaceComponent(s.zone,s.index,{...t,props:{...t.props,previewHover:!B}})},[z,we]=W(ye);return m("div",{className:`es-sidepanel es-sidepanel--right sf-panel sf-panel--right${z||!(!c&&!!t)?"":" sf-hints-folded"}`,children:[n(ke,{icon:n(ve,{type:pe,size:15}),name:ce,kind:de,actions:!p&&P(e)&&t&&t.type!==T?m(k,{children:[n(y,{label:o("Duplicate section"),title:L??void 0,disabled:L!==null,onClick:fe,children:n(U,{size:15})}),ue&&f.hasSiteSettings&&n(Re,{node:t,currentSlug:H,siteId:E??void 0,tokenRef:w,runAuthed:J,onNotify:u}),n(y,{label:o("Remove section"),danger:!0,onClick:he,children:n(Pe,{size:15})}),d?n(N,{side:"right",onHide:d,divider:!0}):null]}):!c&&!t&&P(e)&&v&&I&&Ce(I)?m(k,{children:[n(y,{label:o("Duplicate page"),onClick:()=>O(I),children:n(U,{size:15})}),d?n(N,{side:"right",onHide:d,divider:!0}):null]}):d?n(N,{side:"right",onHide:d}):void 0}),v&&n(Ae,{source:ee,taken:new Set((_??[]).map(a=>a.slug)),duplicate:v,onClose:()=>O(null),onDuplicated:a=>{O(null),X(),V({kind:"page",slug:a.slug,siteId:E??void 0})}}),x&&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:B,onChange:Se,ariaLabel:o("Preview hover state")})]}),n(tt,{tier:me,children:n("div",{className:"sf-insp-body es-insp-body sf-scroll",children:c?c.render(e,A):t?m(k,{children:[t.type===T&&f.hasSiteSettings&&n(qe,{}),n(Ye,{children:n($,{entries:n(Ue,{parts:R,heading:!1,onOpen:a=>ne(rt(t.props.id,a))}),entryCount:je(R).length})}),M&&n(_e,{source:M,slug:pt(t?.props),menuId:dt(t?.props)}),n(Le,{shown:z,onChange:we})]}):n(k,{children:n($,{})})})})]})}export{pn as CHAT_MODE,cn as HEADER_MODE,ln as SELECTION_MODE,mn as SOCIAL_MODE,dn as WEBSITE_MODE,wt as default,St as resolvePanel};
|
|
1
|
+
"use client";import{jsx as n,jsxs as f,Fragment as M}from"react/jsx-runtime";import{useState as be}from"react";import{useEasel as we,useRootFields as ge}from"efficient-easel/easel";import{Button as ke,EmptyState as Ee}from"efficient-shell/ui";import{PAGE_STYLE_FIELDS as x}from"../lib/document/page-root-fields.js";import{rootPanelHead as Pe}from"../../format/lib/document/root-panel.js";import{headWords as z,InspectorHead as ve,InspectorIconButton as W}from"efficient-easel/chrome";import{DuplicateIcon as Ie,TrashIcon as Le}from"efficient-easel/icons";import{panelFieldsOf as Te}from"efficient-easel/screen/lib/document/panel-fields";import{TICKER_PART_LABEL as K}from"../../render/components/PreviewTickerContext.js";import Oe from"./SectionIcon.js";import{PanelHideButton as j}from"efficient-easel/screen/components/SidePanelHead";import{useEaselSession as ye}from"efficient-easel/screen/lib/session-context";import{say as o}from"../../format/lib/editor-words.js";import Ne,{HintsToggle as _e,SHOW_HINTS_DEFAULT as He,SITE_STYLES_BASICS_TAB as Re}from"./WebsiteSettingsPanel.js";import Ae from"./ChatSettingsPanel.js";import De from"./SocialLinksPanel.js";import Ce from"./TickerSettingsPanel.js";import Fe,{PartSourceNote as Be}from"./PartSettingsPanel.js";import Me from"./DuplicateToPageMenu.js";import{usePageRows as xe}from"../lib/page-rows.js";import{useScreenDocument as ze}from"efficient-easel/screen/components/ScreenDocumentContext";import{usePreviewHeader as We}from"../../render/components/PreviewHeaderContext.js";import{useSectionOps as Ke}from"efficient-easel/screen/lib/document/use-section-ops";import{SELECTION_MODE as je,isSelectionMode as E}from"efficient-easel/screen/lib/screen-parts";import{usePreviewParts as Ge}from"efficient-easel/draw/client";import{entryPartsOf as Ye,SectionTextEntries as Ue}from"./SectionTextEntries.js";import{SectionTextSuppressProvider as Ze}from"../lib/document/section-text-suppress.js";import{HEADER_TYPE as $e,ROOT_ZONE as G}from"efficient-easel/draw";import{websiteDuplicateBlocked as qe}from"../lib/document/every-page.js";import{FOOTER_TYPE as P}from"../lib/document/footer-blocks.js";import Je from"./SwitchToBoxFooter.js";import{SiteFields as Y}from"./SiteFields.js";import Qe from"./HeroPartPanel.js";import{HERO_MEDIA_PART_LABELS as Ve,HERO_PART_MODE as Xe,heroPartLabel as et}from"../../render/lib/document/hero-media-parts.js";import{SettingsSwitch as tt}from"efficient-easel/panel";import{foldTopTier as nt}from"../lib/document/field-groups.js";import{FoldHeadingScope as ot}from"../lib/document/panel-heading-scope.js";import{partRowField as it}from"../lib/document/part-row-field.js";import{decodePartKey as rt,partRowHeadLabel as st}from"../../render/lib/document/part-rows.js";import{encodePartId as at,partHeadLabel as lt,partLabel as ct,sectionTextParts as dt}from"../../render/lib/document/text-parts.js";import{partSourceOf as pt,sourceMenuIdOf as mt,sourceSlugOf as ft}from"../../format/lib/document/source-bound-parts.js";const mn=je,fn={kind:"header"},un={kind:"website"},hn={kind:"website",tab:Re,revealPageGroup:!0},Sn={kind:"chat"},bn={kind:"social"},w="Part";function ut(e){return o("Part of {name}",{name:o(e)})}function ht(e,i,r){const s=e.describeNode(i);return{name:r,kindLabel:s?ut(s.label):o(w)}}function St(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 U({what:e}){const i=St(e);return f("div",{className:"sf-note",children:[n("p",{children:n("strong",{children:i.title})}),f("p",{children:[o("A template is a blueprint — it has no website of its own, so there is nothing here to change.")," ",i.own]})]})}function v(e){const i=Xe[e];return{name:Ve[e],kindLabel:w,icon:i,head:(r,s)=>{if(r.kind!==i)return null;const d=s.describeNode(r.nodeId);if(!d)return null;const u=z({name:o(et(e,d.props)),tier:"part",of:o(d.label)},{partOf:({name:h})=>o("Part of {name}",{name:h})});return{name:u.name,kindLabel:u.kind}},render:(r,s)=>r.kind===i?n(Qe,{nodeId:r.nodeId,part:e,sectionName:s.describeNode(r.nodeId)?.label??"Hero",onUpToSection:()=>s.onSelectNode(r.nodeId)}):null}}const bt={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(Ne,{initialTab:e.tab,revealPageGroup:e.revealPageGroup,themeFromDocument:!i.capabilities.hasSiteTheme,tokenRef:i.tokenRef,siteId:i.siteId,onNotify:i.onNotify},e.tab??"")},chat:{name:"Live chat",kindLabel:"Site settings",icon:"chat",render:()=>n(Ae,{})},social:{name:"Social links",kindLabel:"Site settings",icon:"social",render:()=>n(De,{unavailable:n(U,{what:"Social link"})})},ticker:{name:K,kindLabel:w,icon:"ticker",head:(e,i)=>e.kind==="ticker"?ht(i,e.heroId,o(K)):null,render:e=>n(Ce,{heroId:e.kind==="ticker"?e.heroId:""})},heroMedia:v("media"),heroImage:v("image"),heroImage2:v("image2"),part:{name:w,kindLabel:w,icon:"Text",head:(e,i)=>{if(e.kind!=="part")return null;const r=i.describeNode(e.nodeId);if(!r)return null;const{key:s,row:d}=rt(e.propKey),u=d?it(r.fields[s],d):r.fields[s],h=st(o(lt(ct(u??{},s))),d),p=z({name:h,tier:"part",of:o(r.label)},{partOf:({name:S})=>o("Part of {name}",{name:S})});return{name:p.name,kindLabel:p.kind}},render:(e,i)=>e.kind==="part"?n(Fe,{nodeId:e.nodeId,propKey:e.propKey,onBack:()=>i.onSelectNode(e.nodeId),onEditStyle:i.onOpenSiteStyles}):null}},wt=new Set(["header","website","chat"]);function gt(e,i){if(e==="selection")return null;const r=bt[e];return wt.has(e)&&!i.hasSiteSettings?{...r,kindLabel:"Not part of a template",render:()=>n(U,{what:r.name})}:r}function kt({mode:e,onOpenWebsiteSettings:i,onOpenSiteStyles:r,onOpenPageStyles:s,onSelectNode:d,hideNodeActions:u=!1,onNotify:h,onHidePanel:p}){const{capabilities:S,tokenRef:I,notifyParent:Z,currentSlug:L,siteId:T,runAuthed:$,readOnly:q,navigate:Et}=ze(),{rows:J}=xe(),O=J?.find(l=>l.slug===L)??null,Q=ge(),V=Object.keys(Q.fields).some(l=>!l.startsWith("_")&&!x.includes(l)),{websiteName:X}=We(),g=Ke({readOnly:q}),{select:ee}=Ge(),{selectedItem:t,getItemById:te,getSelectorForId:ne,config:m,appState:oe}=we(l=>l),ie=Te(m,t?{type:t.type,props:t.props}:null),y=t?dt(ie??m.components[t.type]?.fields,t.props):[],re=l=>m.components[l]?.label??l,a=t?ne(t.props.id):void 0,c=gt(e.kind,S),se=ye(),N={capabilities:S,tokenRef:I,hostPanels:se.chrome?.panels,describeNode:l=>{const b=te(l);if(!b)return null;const B=m.components[b.type];return{type:b.type,label:B?.label??b.type,fields:B?.fields??{},props:b.props??{}}},siteId:T,websiteName:X??null,notifyParent:Z,onNotify:h,onOpenWebsiteSettings:i,onOpenSiteStyles:r,onSelectNode:d},_=c?.head?.(e,N)??null,H=Pe({kind:O?.kind,pageName:O?.label}),ae=_?.name??(c?o(c.name):t?o(re(t.type)):H.name),le=_?.kindLabel??(c?o(c.kindLabel):t?a&&a.zone!==G?o("Block"):o("Section"):H.kindLabel),ce=c?c.icon:t?t.type:"page",R=c?null:t?m.components[t.type]?.fields??null:m.root?.fields??null,de=R?nt(R):2,A=E(e)&&t?pt(t.type):null,pe=!!t&&!!a&&a.zone===G&&t.type!==P&&t.type!==$e,k=qe(oe?.data,t),me=()=>{k||a&&g.duplicateComponent(a.zone,a.index)},fe=()=>{a&&(g.removeComponent(a.zone,a.index),g.select(null))},ue=t?m.components[t.type]?.defaultProps?.previewHover:void 0,D=E(e)&&!!t&&!!a&&ue!==void 0,C=D&&t.props.previewHover===!0,he=()=>{!t||!a||g.replaceComponent(a.zone,a.index,{...t,props:{...t.props,previewHover:!C}})},[F,Se]=be(He);return f("div",{className:`es-sidepanel es-sidepanel--right sf-panel sf-panel--right${F||!(!c&&!!t)?"":" sf-hints-folded"}`,children:[n(ve,{icon:n(Oe,{type:ce,size:15}),name:ae,kind:le,actions:!u&&E(e)&&t&&t.type!==P?f(M,{children:[n(W,{label:o("Duplicate section"),title:k??void 0,disabled:k!==null,onClick:me,children:n(Ie,{size:15})}),pe&&S.hasSiteSettings&&n(Me,{node:t,currentSlug:L,siteId:T??void 0,tokenRef:I,runAuthed:$,onNotify:h}),n(W,{label:o("Remove section"),danger:!0,onClick:fe,children:n(Le,{size:15})}),p?n(j,{side:"right",onHide:p,divider:!0}):null]}):p?n(j,{side:"right",onHide:p}):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:o("Preview hover state")}),n("span",{className:"sf-preview-pin-hint",children:o("not shown live")})]}),n(tt,{checked:C,onChange:he,ariaLabel:o("Preview hover state")})]}),n(ot,{tier:de,children:n("div",{className:"sf-insp-body es-insp-body sf-scroll",children:c?c.render(e,N):t?f(M,{children:[t.type===P&&S.hasSiteSettings&&n(Je,{}),n(Ze,{children:n(Y,{entries:n(Ue,{parts:y,heading:!1,onOpen:l=>ee(at(t.props.id,l))}),entryCount:Ye(y).length})}),A&&n(Be,{source:A,slug:ft(t?.props),menuId:mt(t?.props)}),n(_e,{shown:F,onChange:Se})]}):V?n(Y,{omit:x}):n(Ee,{variant:"none",icon:!1,message:o("Select a section or block to edit it."),children:s&&n(ke,{variant:"secondary",onClick:s,children:o("This page")})})})})]})}export{Sn as CHAT_MODE,fn as HEADER_MODE,mn as SELECTION_MODE,bn as SOCIAL_MODE,un as WEBSITE_MODE,hn as WEBSITE_PAGE_MODE,kt as default,gt as resolvePanel};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{jsx as h,Fragment as t,jsxs as e}from"react/jsx-runtime";import{BlockBannerIcon as
|
|
1
|
+
import{jsx as h,Fragment as t,jsxs as e}from"react/jsx-runtime";import{BlockBannerIcon as n,BlockBoxIcon as M,BlockButtonIcon as y,BlockDividerIcon as x,BlockFooterIcon as a,BlockHeadingIcon as g,BlockProductIcon as p,BlockSocialIcon as w,BlockTextIcon as s,CardPaymentIcon as B,ChatIcon as k,GridIcon as m,ImageIcon as c,MediaIcon as u,PageIcon as S}from"efficient-easel/icons";import{CART_GLYPH as I}from"../../render/components/cartGlyph.js";const F={header:e(t,{children:[h("rect",{x:"3",y:"5",width:"18",height:"14",rx:"2"}),h("path",{d:"M3 9.5h18"})]}),website:e(t,{children:[h("circle",{cx:"12",cy:"12",r:"9"}),h("path",{d:"M3 12h18M12 3c2.6 2.7 2.6 15.3 0 18M12 3c-2.6 2.7-2.6 15.3 0 18"})]}),social:e(t,{children:[h("circle",{cx:"6",cy:"12",r:"2.5"}),h("circle",{cx:"18",cy:"6",r:"2.5"}),h("circle",{cx:"18",cy:"18",r:"2.5"}),h("path",{d:"M8.2 10.8l7.6-3.6M8.2 13.2l7.6 3.6"})]}),ticker:e(t,{children:[h("rect",{x:"3",y:"8.5",width:"18",height:"7",rx:"2"}),h("path",{d:"M6 12h3.5M11.5 12h2M15.5 12h2.5"})]}),FooterLogo:e(t,{children:[h("path",{d:"M4 15.5h6M4 18h4"}),h("path",{d:"M14 8.5l3 7 3-7"})]}),FooterMenu:h("path",{d:"M6 7h12M6 11h12M6 15h8M6 19h8"}),FooterGroup:e(t,{children:[h("rect",{x:"4",y:"4",width:"16",height:"16",rx:"2",strokeDasharray:"3 2.5"}),h("path",{d:"M8 9h8M8 13h8M8 16h5"})]}),FooterText:h("path",{d:"M5 7h14M5 12h14M5 17h9"}),FooterEmailSignup:e(t,{children:[h("rect",{x:"3",y:"6",width:"18",height:"12",rx:"2"}),h("path",{d:"M3.5 7l8.5 6 8.5-6"})]}),SearchBlock:e(t,{children:[h("circle",{cx:"11",cy:"11",r:"6"}),h("path",{d:"M20 20l-4.2-4.2"})]}),CartBlock:I,CountrySwitchBlock:e(t,{children:[h("circle",{cx:"12",cy:"12",r:"8.5"}),h("path",{d:"M3.5 12h17M12 3.5c2.6 2.4 3.6 5.2 3.6 8.5s-1 6.1-3.6 8.5M12 3.5c-2.6 2.4-3.6 5.2-3.6 8.5s1 6.1 3.6 8.5"})]}),AccountBlock:e(t,{children:[h("circle",{cx:"12",cy:"8",r:"4"}),h("path",{d:"M4.5 20c.8-3.8 3.8-6 7.5-6s6.7 2.2 7.5 6"})]}),ThemeSwitchBlock:e(t,{children:[h("circle",{cx:"12",cy:"12",r:"8.5"}),h("path",{d:"M12 3.5v17M12 5.5l6 6M12 10.5l5.2 5.2M12 15.5l2.8 2.8"})]}),LegalLineBlock:e(t,{children:[h("path",{d:"M3 9h18"}),h("path",{d:"M3 14h8M14 14h2M18 14h3"})]}),Hero:e(t,{children:[h("rect",{x:"3",y:"4",width:"18",height:"16",rx:"2"}),h("path",{d:"M7 13.5h7M7 16.5h10"})]}),HeroSlide:e(t,{children:[h("rect",{x:"3",y:"5",width:"18",height:"14",rx:"2"}),h("path",{d:"M7 15h6M16 9.5h.01M9.5 12l-2.5 3"})]}),HeroSingle:e(t,{children:[h("rect",{x:"3",y:"4",width:"18",height:"16",rx:"2"}),h("path",{d:"M10.5 8.5l4 2.5-4 2.5z"}),h("path",{d:"M7 17h7"})]}),Collections:e(t,{children:[h("rect",{x:"3",y:"5",width:"4.6",height:"14",rx:"1.3"}),h("rect",{x:"9.7",y:"5",width:"4.6",height:"14",rx:"1.3"}),h("rect",{x:"16.4",y:"5",width:"4.6",height:"14",rx:"1.3"})]}),CollectionCard:e(t,{children:[h("rect",{x:"6",y:"4",width:"12",height:"16",rx:"2"}),h("path",{d:"M9 15h6M9 17.5h4"})]}),AlloyWheelsListing:e(t,{children:[h("path",{d:"M3 5h5M3 9h5M3 13h5M3 17h5"}),h("rect",{x:"11.5",y:"5",width:"4.2",height:"5",rx:"1"}),h("rect",{x:"17.3",y:"5",width:"4.2",height:"5",rx:"1"}),h("rect",{x:"11.5",y:"12",width:"4.2",height:"5",rx:"1"}),h("rect",{x:"17.3",y:"12",width:"4.2",height:"5",rx:"1"})]}),CatalogFilterBar:e(t,{children:[h("path",{d:"M3 7h9M15.5 7H21"}),h("circle",{cx:"13.5",cy:"7",r:"1.7"}),h("path",{d:"M3 12h4M10.5 12H21"}),h("circle",{cx:"8.5",cy:"12",r:"1.7"}),h("path",{d:"M3 17h9M15.5 17H21"}),h("circle",{cx:"13.5",cy:"17",r:"1.7"})]}),ProductGrid:e(t,{children:[h("rect",{x:"3",y:"5",width:"4.8",height:"6",rx:"1"}),h("rect",{x:"9.6",y:"5",width:"4.8",height:"6",rx:"1"}),h("rect",{x:"16.2",y:"5",width:"4.8",height:"6",rx:"1"}),h("rect",{x:"3",y:"13",width:"4.8",height:"6",rx:"1"}),h("rect",{x:"9.6",y:"13",width:"4.8",height:"6",rx:"1"}),h("rect",{x:"16.2",y:"13",width:"4.8",height:"6",rx:"1"})]}),RelatedProducts:e(t,{children:[h("path",{d:"M3 5h10"}),h("rect",{x:"3",y:"9.5",width:"5",height:"9",rx:"1"}),h("rect",{x:"9.5",y:"9.5",width:"5",height:"9",rx:"1"}),h("rect",{x:"16",y:"9.5",width:"5",height:"9",rx:"1"})]}),Gallery:e(t,{children:[h("rect",{x:"3",y:"4",width:"11",height:"16",rx:"2"}),h("rect",{x:"15.5",y:"4",width:"5.5",height:"7.5",rx:"1.5"}),h("rect",{x:"15.5",y:"12.5",width:"5.5",height:"7.5",rx:"1.5"})]}),GalleryB:e(t,{children:[h("rect",{x:"3.5",y:"4",width:"7.5",height:"7.5",rx:"1.5"}),h("rect",{x:"13",y:"4",width:"7.5",height:"7.5",rx:"1.5"}),h("rect",{x:"3.5",y:"12.5",width:"7.5",height:"7.5",rx:"1.5"}),h("rect",{x:"13",y:"12.5",width:"7.5",height:"7.5",rx:"1.5"})]}),GalleryItem:e(t,{children:[h("rect",{x:"4",y:"5",width:"16",height:"14",rx:"2"}),h("circle",{cx:"9",cy:"10",r:"1.6"}),h("path",{d:"M20 15.5l-4.5-4L7 19"})]}),Events:e(t,{children:[h("rect",{x:"4",y:"5",width:"16",height:"15",rx:"2"}),h("path",{d:"M4 9.5h16M8.5 3v4M15.5 3v4M8 14h2M14 14h2"})]}),PostCard:e(t,{children:[h("rect",{x:"4",y:"3.5",width:"16",height:"17",rx:"2"}),h("rect",{x:"6.5",y:"6",width:"11",height:"6",rx:"1"}),h("path",{d:"M6.5 14.5h11M6.5 17.5h7"})]}),Manifesto:e(t,{children:[h("path",{d:"M7 8h3.2v4c0 1.6-1 2.6-3 3.2"}),h("path",{d:"M14 8h3.2v4c0 1.6-1 2.6-3 3.2"})]}),Stats:e(t,{children:[h("path",{d:"M3.5 20h17"}),h("path",{d:"M6 20v-7M11 20V7M16 20v-5M20.5 20v-9"})]}),Logos:e(t,{children:[h("circle",{cx:"6",cy:"12",r:"2.6"}),h("rect",{x:"10",y:"9.4",width:"5.2",height:"5.2",rx:"1.2"}),h("path",{d:"M19 9.2l2.4 5h-4.8z"})]}),Ticker:e(t,{children:[h("rect",{x:"3",y:"8.5",width:"18",height:"7",rx:"2"}),h("path",{d:"M6 12h3.5M11.5 12h2M15.5 12h2.5"})]}),SectionHeader:e(t,{children:[h("rect",{x:"3.5",y:"6",width:"5",height:"5",rx:"1.2"}),h("path",{d:"M11 8.5h9M3.5 15.5h17"})]}),IntroBleed:e(t,{children:[h("rect",{x:"3",y:"4",width:"18",height:"16",rx:"2"}),h("path",{d:"M3 13.5h18M7 16.8h6"})]}),Split:e(t,{children:[h("rect",{x:"3",y:"5",width:"8",height:"14",rx:"1.5"}),h("path",{d:"M14 8.5h6M14 12h6M14 15.5h4"})]}),Eyebrow:e(t,{children:[h("path",{d:"M4 8.5h4.5M11 8.5h9"}),h("path",{d:"M4 14.5h16"})]}),HeroGroup:e(t,{children:[h("rect",{x:"3.5",y:"4.5",width:"17",height:"15",rx:"2"}),h("path",{d:"M7 9h8M7 12.5h10M7 16h6"})]}),Form:e(t,{children:[h("rect",{x:"3",y:"4",width:"18",height:"16",rx:"2"}),h("path",{d:"M6.5 9h11M6.5 12.5h11"}),h("rect",{x:"6.5",y:"15",width:"6.5",height:"2.6",rx:"1.3"})]}),LogoBlock:h(t,{children:h("path",{d:"M12 3.5l7.5 3.2v5.1c0 4.2-3.2 7.1-7.5 8.7-4.3-1.6-7.5-4.5-7.5-8.7V6.7z"})}),Spacer:e(t,{children:[h("path",{d:"M12 4v6M9.5 6.5L12 4l2.5 2.5M12 20v-6M9.5 17.5L12 20l2.5-2.5"}),h("path",{d:"M5 13h14",strokeDasharray:"2 2.5"})]}),ContactRouting:e(t,{children:[h("rect",{x:"3",y:"4",width:"5",height:"5",rx:"1"}),h("rect",{x:"9.5",y:"4",width:"5",height:"5",rx:"1"}),h("rect",{x:"16",y:"4",width:"5",height:"5",rx:"1"}),h("path",{d:"M4 13.5h11M4 17.5h7"}),h("path",{d:"M17 15l3 2-3 2"})]}),CustomHTML:h("path",{d:"M9 8l-4 4 4 4M15 8l4 4-4 4"})},L=h("rect",{x:"4",y:"4",width:"16",height:"16",rx:"2.5"}),v={footer:a,Footer:a,Divider:x,FooterDivider:x,Banner:n,Flex:M,FooterSocial:w,FooterPayment:B,page:S,chat:k,Heading:g,Text:s,ImageBlock:c,ButtonBlock:y,Grid:m,ProductRef:p,heroMedia:u,heroImage:c,heroImage2:c},H={MenuBlock:"FooterMenu",EmailFormBlock:"FooterEmailSignup",SocialLogosBlock:"FooterSocial",PaymentLogosBlock:"FooterPayment",SiteHeader:"header",SiteFooter:"footer"};function C({type:i,size:r=16,className:d}){const o=H[i]??i,l=v[o];return l?h(l,{size:r,className:d}):h("svg",{width:r,height:r,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:1.7,strokeLinecap:"round",strokeLinejoin:"round",className:d,"aria-hidden":"true",children:F[o]??L})}export{C as default};
|