efficient-web-builder 25.0.0 → 26.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/dist/editor/components/StorefrontEditor.js +1 -1
- package/dist/editor/components/useSocialSettings.js +1 -1
- package/dist/editor/components/useWebsiteMainAction.js +1 -1
- package/dist/editor/lib/editor-document-adapter.d.ts +2 -1
- package/dist/editor/lib/editor-document-adapter.js +1 -1
- package/dist/editor/lib/page-live-state.d.ts +4 -2
- package/dist/editor/lib/page-live-state.js +1 -1
- package/dist/editor/lib/puck/hidable-rows-drawn.d.ts +21 -0
- package/dist/editor/lib/puck/hidable-rows-drawn.js +1 -0
- package/dist/editor/lib/site-live-state.d.ts +7 -0
- package/dist/editor/lib/site-live-state.js +1 -0
- package/dist/editor/lib/theme-row-persist.js +1 -1
- package/dist/editor/lib/web-backend.d.ts +16 -0
- package/dist/format/lib/editor-words-catalogue.d.ts +1 -0
- package/dist/format/lib/editor-words-catalogue.js +1 -1
- package/dist/format/lib/site-writes.d.ts +3 -0
- package/dist/format/lib/site-writes.js +1 -0
- package/dist/format/lib/source-rules/button-corners.js +2 -2
- package/dist/format/lib/source-rules/panel-rows-use-the-shared-row.js +20 -19
- package/dist/format/lib/source-rules/puck-document-surfaces.js +3 -3
- package/dist/format/lib/source-rules/section-theme-preview.js +3 -3
- package/dist/format/lib/source-rules/source-status-is-shared.js +1 -1
- package/dist/format/lib/source-rules/support/ts-source.d.ts +1 -0
- package/dist/format/lib/source-rules/support/ts-source.js +3 -3
- package/dist/render/lib/puck/blocks/general/Chart/render.js +2 -2
- package/dist/render/lib/puck/blocks/general/Integrations/render.js +2 -2
- package/dist/render/lib/puck/blocks/general/Mockup/render.js +2 -2
- package/dist/render/lib/puck/blocks/scaffold.d.ts +1 -0
- package/dist/render/lib/puck/blocks/scaffold.js +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 26.0.0 - 2026-10-20
|
|
6
|
+
|
|
7
|
+
**One Publish puts the whole website live** (Lewis, 2026-10-19: like Wix; the site-wide Publish plan, PR 5). Where the backend offers it, every edit in the editor is a draft, and Publish puts the pages and every site-wide draft live together; the ▾ menu lists what the press will put live.
|
|
8
|
+
|
|
9
|
+
### Changed for merchants
|
|
10
|
+
|
|
11
|
+
- Where the backend publishes the whole website (efficient-backend 87.x, through the host's adapter), **Publish puts the whole website live**: every page waiting, Site styles, the header, the live chat, the social links and the menus, in one press. The status under Publish is the website's ("Changes not live yet" / "Everything is live"), and the ▾ menu lists each thing that will go live, a page taken down said so ("About (taken down)").
|
|
12
|
+
- An edit made just before the press goes live with it: the Site styles queue and the live chat (each waits 500 ms) send what they hold first.
|
|
13
|
+
- If one of those writes fails, nothing goes live: Publish shows the editor's save error, and the edit stays waiting, so the next Publish sends it first.
|
|
14
|
+
- Where the backend publishes per page, nothing changes.
|
|
15
|
+
|
|
16
|
+
### Changed for hosts (breaking)
|
|
17
|
+
|
|
18
|
+
- **BREAKING: `WebsiteSite.publish?(scope)` and `WebsiteSite.liveState?(scope)`** (lib/web-backend), offered together. A backend that offers them keeps EVERY site-wide write as a draft (the `theme`, `chat` and `social` rows' `update`, a new page and a page's settings) and the editor's main action calls `site.publish` instead of `pages.publish`; its status is `liveState` (`SiteLiveState`, `SiteChange`, `SitePublishAnswer`). A host must turn on drafts and these two members together (efficient-storefront-blocks' adapter does, in its next release). A backend without them is served exactly as before.
|
|
19
|
+
- **BREAKING: `efficient-easel` peer and dev range `^13.3.0`** (it was `^13.2.0`): the main action hands easel `ScreenMainAction.goingLive` (easel #299).
|
|
20
|
+
- `WebsiteDocumentAdapter.siteLiveState?` (lib/editor-document-adapter): the website's state, where Publish is the whole site's.
|
|
21
|
+
- New `lib/site-live-state` (the website's state, read when the editor opens and after each write, written by a Publish's answer) and `lib/site-writes` (the writes still waiting, sent before a Publish).
|
|
22
|
+
- The header and footer document is not published again on its own when the site's Publish puts it live with everything else.
|
|
23
|
+
|
|
24
|
+
### Guards
|
|
25
|
+
|
|
26
|
+
- `scripts/test-site-publish.tsx`: Publish is the site's (no page publish, every waiting write sent first); the website's state (read, written by a Publish, a late answer dropped); the bar's status and the list of what goes live; the Site styles queue going first; per-page Publish unchanged without the site's; a waiting write that fails stops the Publish, and its edit is sent by the next one.
|
|
27
|
+
- `scripts/test-two-ways-to-add.ts` §1: the easel peer and dev range are `^13.3.0`.
|
|
28
|
+
|
|
29
|
+
## 25.1.0 - 2026-10-20
|
|
30
|
+
|
|
31
|
+
**Chart, Integrations and Mockup no longer crash a published page; the rules over source read a host's imports** (keep editor code off shopper pages, storefront step 2b). A MINOR: two exports are added (below), none changes or goes.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- **A published Chart, Integrations or Mockup crashed once a merchant typed into one of its text rows.** A row with an eye (`text()` / `textarea()`) stores `{ text, hidden }` after the first keystroke, and these three renders passed every such row but the heading on raw: `ChartSection` called `(body ?? "").trim()` on the object and threw. Each render now reads every hideable row through the one reader: `hidableRow` (`lib/puck/blocks/scaffold`, beside `phHide`) gives the words, `""` when the eye is shut, and nothing when nothing was stored, so a bare string — a row stored before it had an eye — draws byte for byte as before. **Both stored shapes are safe, so no stored page needs a change.**
|
|
36
|
+
- Since 24.0.0 a host imports the builder by package name and side (`efficient-web-builder/render/components/Btn`), while the builder's own `src/` writes `@/components/Btn`. Five rules knew only the second spelling: `button-corners`, `panel-rows-use-the-shared-row`, `puck-document-surfaces`, `section-theme-preview` and `source-status-is-shared`. On a host each one read none of its imports, so a floor such as "the sweep found at least 9 files importing Btn" failed for a reason that was not the rule's. Each now reads both spellings through one helper, `builderModuleSpec` (`lib/source-rules/support/ts-source`), and the rules with an import reader on a fixture check the host's spelling too.
|
|
37
|
+
- `panel-rows-use-the-shared-row` read a WRAPPED row's arguments wrong: for `withShowWhen(segmented("Shape", <SquareIcon />, …), rule)` it took the wrapper's paren and read `rule` as the glyph, so a row with a glyph was reported bare. `callParen` returns the paren that ends the match. A fixture holds both cases: the glyphed wrapped row passes and a bare one is caught.
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- `hidableRow` (`efficient-web-builder/render/lib/puck/blocks/scaffold`): a hideable row as a component that takes a plain string reads it. Built on `readHidable`, the one reader.
|
|
42
|
+
- `lib/puck/hidable-rows-drawn` (`efficient-web-builder/editor/lib/puck/hidable-rows-drawn`): the check that every hideable row draws in both stored shapes and that a shut eye hides it, at a block's defaults and in every variant. One definition: the builder runs it over the general set (`scripts/test-hidable-rows-drawn.tsx`), a host over its own blocks with its own providers (it hands in the drawing). A planted render that passes a row raw fails it.
|
|
43
|
+
|
|
5
44
|
## 25.0.0 - 2026-10-19
|
|
6
45
|
|
|
7
46
|
**The letter cases are one code, easel's (#159), and the builder runs on efficient-shell 8** (SSOT cleanup, GG 2026-10-17; keep editor code off shopper pages, efficient-shell #553). Every site draws what it drew. A MAJOR for hosts, for the two reasons below.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as s,jsxs as dt}from"react/jsx-runtime";import{useCallback as n,useEffect as m,useMemo as R,useRef as S,useState as r}from"react";import"efficient-easel/easel.css";import"efficient-easel/shell.css";import"efficient-easel/rail.css";import"efficient-easel/panel.css";import"efficient-easel/fields.css";import"efficient-easel/pick.css";import"efficient-easel/copy.css";import"efficient-easel/gold.css";import"efficient-easel/text-styles.css";import"efficient-easel/menu.css";import"efficient-easel/chrome.css";import"efficient-easel/tree.css";import"efficient-easel/drag.css";import"efficient-easel/screen.css";import"./storefront-editor.css";import{buildConfig as ut}from"../lib/puck/build-config.js";import{ChromeWrap as ht}from"../lib/editor-chrome.js";import{sessionRegistry as lt}from"../../render/lib/editor-session.js";import{refreshSiteLiveState as mt}from"../lib/site-live-state.js";import{holdSiteWrites as pt}from"../../format/lib/site-writes.js";import{backendOf as G,blocksOf as St}from"../lib/website-session.js";import{useEditorSession as ft}from"../lib/editor-session-context.js";import{withSiteBlockGapFields as wt}from"../../format/lib/puck/site-gap-fields.js";import{withTemplateMediaPlaceholders as gt}from"../../format/lib/puck/templateFields.js";import{setEditorPage as ue}from"../../format/lib/puck/editor-page-context.js";import{resolveSiteName as Ct}from"../../format/lib/content/site-name.js";import{normalizeSiteGutter as Tt,normalizeSiteWidth as yt}from"../../format/lib/content/page-width.js";import{normalizeSiteBlockGap as _t}from"../../format/lib/content/container-gap.js";import Et,{DocumentScreen as Pt}from"./EditorScreenMount.js";import{useStorefrontDocument as vt}from"./StorefrontDocumentContext.js";import{PreviewHeaderProvider as Ht}from"../../render/components/PreviewHeaderContext.js";import{PreviewFooterProvider as It}from"./PreviewFooterContext.js";import{PreviewChatProvider as Mt,DEFAULT_CHAT_PREVIEW as Rt}from"./PreviewChatContext.js";import{PreviewSocialProvider as Gt}from"../../render/components/PreviewSocialContext.js";import{useSocialSettings as Ft}from"./useSocialSettings.js";import{PreviewSurfaceProvider as Wt}from"./PreviewSurfaceContext.js";import{WEBSITE_ADDRESSING as kt}from"../lib/website-document-addressing.js";import{PreviewTickerProvider as At}from"../../render/components/PreviewTickerContext.js";import{PreviewHeroPartProvider as Dt}from"../../render/components/PreviewHeroPartContext.js";import{PreviewPartsProvider as xt}from"efficient-easel/draw/client";import{PreviewLocationPartProvider as Bt}from"../../render/components/PreviewLocationPartContext.js";import{PreviewPartStyleProvider as Nt}from"./PreviewPartStyleContext.js";import{SiteMapsProvider as Ot,readSiteMapsKey as bt,writeSiteMapsKey as he,readSiteMapId as zt,writeSiteMapId as Kt}from"../../render/lib/maps-config.js";import{CORNER_STYLE_TO_PX as Lt,DEFAULT_HEADING_COMPRESSION as Yt,DEFAULT_HEADING_TYPOGRAPHY as Ut,DEFAULT_SWITCH_SHOWN as F,DEFAULT_SIZES as jt,DEFAULT_THEME_MODE as y,normalizeCornerRadius as Vt,normalizeCornerStyle as Xt,normalizeCardShadow as Zt,normalizeCardGap as qt,normalizeHoverEffect as Jt,normalizeShadowColor as Qt,IDENTITY_CARD_GAP as le,IDENTITY_CARD_SHADOW as $t,IDENTITY_HOVER_EFFECT as er,THEME_MODE_KEY as me,THEME_STORAGE_KEY as tr,THEME_SWITCH_HIDE as pe,THEME_SWITCH_KEY as W}from"../../format/lib/theme.js";import{DEFAULT_FONTS as rr}from"../../format/lib/fonts.js";import{WEBSITE_SCREEN as or}from"./WebsiteScreenParts.js";import{routeWebsiteHostMessage as nr}from"../../format/lib/website-host-inbound.js";import{siteTextFromRow as ar}from"../lib/site-text-styles.js";import{wordStylesFromRow as ir}from"../../format/lib/word-styles.js";import{chatPreviewFrom as cr}from"./PreviewChatContext.js";const sr=()=>{if(typeof window>"u")return y;try{const i=window.localStorage.getItem(me);return i==="light"||i==="dark"||i==="auto"?i:y}catch{return y}},Se=i=>{if(!(typeof window>"u"))try{window.localStorage.setItem(me,i)}catch{}},dr=()=>{if(typeof window>"u")return F;try{return window.localStorage.getItem(W)!==pe}catch{return F}},ur=()=>{if(!(typeof window>"u"))try{window.localStorage.removeItem(tr)}catch{}},fe=i=>{if(!(typeof window>"u"))try{i?window.localStorage.removeItem(W):window.localStorage.setItem(W,pe)}catch{}};function hr(){const{adapter:i,capabilities:d,templateId:k,ready:g,token:l,siteId:c,currentSlug:A,currentKind:D}=vt();m(()=>(ue(A,D),()=>ue(null,null)),[A,D]);const _=d.placeholderFrames,[we,x]=r(null),[ge,B]=r("");m(()=>{const e=i.templateName;if(!g||!k||!e){B("");return}let o=!1;return e().then(u=>!o&&B(u??"")).catch(()=>{}),()=>{o=!0}},[g,l,k,i]);const[Ce,E]=r(y),[Te,P]=r(F),[ye,N]=r({selected:0,themes:[]}),[_e,O]=r(rr),[Ee,b]=r(jt),[Pe,z]=r(null),[ve,K]=r(Yt),[He,L]=r(null),[Ie,Y]=r(null),[Me,U]=r(le),[Re,j]=r(null),[Ge,V]=r(null),[Fe,X]=r(null),[v,Z]=r(null),h=ft(),q=R(()=>ut(lt(h),St(h)),[h]),We=R(()=>wt(gt(q,_),v),[q,_,v]),[ke,J]=r(Ut),[Ae,Q]=r(null),[De,$]=r(null),[xe,ee]=r(null),te=S(null),a=S(!1);m(()=>{E(sr()),P(dr())},[]);const Be=n(e=>{a.current=!0,ur(),Se(e),E(e)},[]),Ne=n(e=>{a.current=!0,fe(e),P(e)},[]),Oe=n(e=>{a.current=!0,N(e)},[]),be=n(e=>{a.current=!0,O(e)},[]),ze=n(e=>{a.current=!0,b(e)},[]),Ke=n(e=>{a.current=!0,z(e)},[]),Le=n(e=>{a.current=!0,K(e)},[]),Ye=n(e=>{a.current=!0,L(e)},[]),Ue=n(e=>{a.current=!0,Y(e)},[]),je=n(e=>{a.current=!0,U(e)},[]),Ve=n(e=>{a.current=!0,j(e)},[]),Xe=n(e=>{a.current=!0,J(e)},[]),[Ze,re]=r(null),[qe,Je]=r(null),Qe=n(e=>{a.current=!0,re(e)},[]),$e=n(e=>{a.current=!0,V(e)},[]),et=n(e=>{a.current=!0,X(e)},[]),tt=n(e=>{a.current=!0,Z(e)},[]),rt=n(e=>{a.current=!0,Q(e)},[]),ot=n(e=>{a.current=!0,$(e)},[]),nt=n(e=>{a.current=!0,ee(e)},[]);m(()=>{const e=G(h).theme;if(!l||!d.hasSiteTheme||!e)return;const o=c??"";te.current!==o&&(te.current=o,a.current=!1);let u=!1;return e.get(c?{siteId:c}:void 0).then(t=>{if(u||a.current)return;Se(t.default_mode),fe(t.show_theme_switch),E(t.default_mode),P(t.show_theme_switch),N({selected:t.selected_preset,themes:t.theme_presets});const p=ar(t);O(p.fonts),b(p.sizes),z(t.corner_radius_px===void 0?Lt[Xt(t.corner_style)]:Vt(t.corner_radius_px)),K(p.compression),L(t.card_shadow==null?$t:Zt(t.card_shadow)),U(t.card_gap==null?le:qt(t.card_gap)),j(t.hover_effect==null?er:Jt(t.hover_effect)),Y(Qt(t.shadow_color)),V(yt(t.site_width)),X(Tt(t.site_gutter)),Z(_t(t.block_gap)),J(p.typography),re(p.textStyles),Je(ir(t)),Q(t.hero_background_follows_width===!0),$(t.photography_grayscale===!0),ee(t.share_button_on_posts===!0)}).catch(()=>{}),()=>{u=!0}},[l,c,d.hasSiteTheme,h]);const at=Ft({token:l,siteId:c,enabled:d.hasSiteSettings}),[it,oe]=r(Rt),ne=S(null),H=S(!1),f=S(null),w=S({}),C=n(async()=>{f.current&&clearTimeout(f.current),f.current=null;const e=w.current;w.current={};try{await G(h).chat?.update(e,c?{siteId:c}:void 0),mt()}catch(o){throw w.current={...e,...w.current},o}},[h,c]);m(()=>pt(()=>f.current||Object.keys(w.current).length>0?C():void 0),[C]);const ct=n(e=>{H.current=!0,oe(o=>({...o,...e})),!(!d.hasSiteSettings||!l)&&(w.current={...w.current,...e},f.current&&clearTimeout(f.current),f.current=setTimeout(()=>{C().catch(()=>{})},500))},[d.hasSiteSettings,l,C]);m(()=>{if(!l||!d.hasSiteSettings)return;const e=c??"";ne.current!==e&&(ne.current=e,H.current=!1);let o=!1;const u=G(h).chat;if(u)return u.get(c?{siteId:c}:void 0).then(t=>{o||H.current||oe(cr(t))}).catch(()=>{}),()=>{o=!0}},[l,c,d.hasSiteSettings,h]);const[T,I]=r(""),ae=S(null),M=S(!1);m(()=>I(bt()),[]);const ie=n(e=>{const o=e.trim();if(o===T)return;M.current=!0,he(o),I(o);const u=i.updateSite;!d.canEditSiteRecord||!g||!u||u({mapsApiKey:o}).catch(()=>{})},[T,d.canEditSiteRecord,g,i]),[ce,se]=r("");m(()=>se(zt()),[]),m(()=>{const e=i.site;if(!g||!d.hasSiteRecord||!e){x(null);return}const o=c??"";ae.current!==o&&(ae.current=o,M.current=!1);let u=!1;return e().then(t=>{if(u||(x(Ct(t.name)),M.current))return;const p=t.mapsApiKey??"";he(p),I(p);const de=t.mapsMapId??"";Kt(de),se(de)}).catch(()=>{}),()=>{u=!0}},[g,l,d.hasSiteRecord,c,i]);const st=R(()=>({apiKey:T,setApiKey:ie,mapId:ce}),[T,ie,ce]);return s(Pt,{config:We,parts:or,wrap:(e,o)=>s(Ht,{websiteName:we,templateChrome:_,templateName:ge||null,themeMode:Ce,onThemeModeChange:Be,themeSwitchShown:Te,onThemeSwitchShownChange:Ne,theme:ye,onThemeChange:Oe,fonts:_e,onFontsChange:be,cornerRadiusPx:Pe,onCornerRadiusPxChange:Ke,cardShadow:He,onCardShadowChange:Ye,shadowColor:Ie,onShadowColorChange:Ue,cardGap:Me,onCardGapChange:je,hoverEffect:Re,onHoverEffectChange:Ve,headingCompression:ve,onHeadingCompressionChange:Le,headingTypography:ke,onHeadingTypographyChange:Xe,textStyles:Ze,onTextStylesChange:Qe,wordStyles:qe,sizes:Ee,onSizesChange:ze,siteWidth:Ge,onSiteWidthChange:$e,siteGutter:Fe,onSiteGutterChange:et,blockGap:v,onBlockGapChange:tt,heroBackgroundFollowsWidth:Ae,onHeroBackgroundFollowsWidthChange:rt,photographyGrayscale:De,onPhotographyGrayscaleChange:ot,shareButtonOnPosts:xe,onShareButtonOnPostsChange:nt,themeFromDocument:!d.hasSiteTheme,children:s(It,{children:s(ht,{wrap:h.chrome?.wrap,surface:"page",children:s(At,{children:s(Dt,{children:s(xt,{children:s(Bt,{children:s(Nt,{children:dt(Ot,{value:st,children:[s(Mt,{chat:it,onChatChange:ct,children:s(Gt,{value:at,children:s(Wt,{children:e})})}),o]})})})})})})})})})})}function lr({target:i}){return s(Et,{target:i,addressing:kt,onHostMessage:nr,children:s(hr,{})})}export{lr as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{useCallback as
|
|
1
|
+
"use client";import{useCallback as d,useEffect as p,useMemo as E,useRef as h,useState as A}from"react";import{EMPTY_SOCIAL_ROWS as L}from"../../render/components/PreviewSocialContext.js";import{SOCIAL_PLATFORMS as O,normalizeSocialLinks as C}from"../../format/lib/content/social-links.js";import{refreshSiteLiveState as w}from"../lib/site-live-state.js";import{backendOf as y}from"../lib/website-session.js";import{useEditorSession as _}from"../lib/editor-session-context.js";import{WebsiteBackendError as g}from"../lib/web-backend.js";const F="Could not save this link. Check your connection and try again.";function R(n,e){if(!(n instanceof g)||n.kind!=="invalid")return null;const s=n.fields?.[e];return typeof s=="string"&&s.trim()?s:null}function T(n){return Object.fromEntries(O.map(e=>[e,{value:n[e]??"",error:null}]))}function D({token:n,siteId:e,enabled:s}){const[i,c]=A(L),m=h(null),a=h(!1),b=_(),t=y(b).social,o=s&&!!n&&!!e&&!!t;p(()=>{if(!o||!n||!e||!t)return;m.current!==e&&(m.current=e,a.current=!1,c(L));let r=!1;return t.get({siteId:e}).then(l=>{!r&&!a.current&&c(T(l))}).catch(()=>{}),()=>{r=!0}},[o,n,e,t]);const S=d(async(r,l)=>{if(!o||!n||!e||!t)return{ok:!1,error:"There is no website to save to."};try{const f=await t.update({[r]:l.trim()},{siteId:e});return a.current=!0,w(),c(u=>({...u,[r]:{value:f[r]??"",error:null}})),{ok:!0}}catch(f){const u=R(f,r)??F;return c(v=>({...v,[r]:{...v[r],error:u}})),{ok:!1,error:u}}},[o,n,e,t]),k=E(()=>C(Object.fromEntries(O.map(r=>[r,i[r].value]))),[i]);return E(()=>({links:k,rows:i,canSave:o,saveLink:S}),[k,i,o,S])}export{F as SOCIAL_SAVE_FAILED,R as socialFieldError,D as useSocialSettings};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{useCallback as
|
|
1
|
+
"use client";import{useCallback as b,useEffect as f,useRef as d,useState as P}from"react";import{useStorefrontDocument as y}from"./StorefrontDocumentContext.js";import{useOpenPinnedChromeReport as C,usePinnedChromeState as R}from"./usePinnedChromeState.js";import{effectiveLive as A,goingLiveLines as E,mainActionFor as l,usePageLiveState as U}from"../lib/page-live-state.js";import{readSiteLiveStateWith as p,refreshSiteLiveState as W,useSiteLiveState as k}from"../lib/site-live-state.js";function M(i){const{docId:m,capabilities:v,hasUnsavedEdits:r,onPublish:s,adapter:h}=y(),S=A(U(m??null),r),g=R(C()),e=h.siteLiveState;f(()=>{if(e)return p(e),W(0),()=>p(null)},[e]);const t=k(),[u,o]=P(!1),a=d(i);a.current=i;const n=d(!0);f(()=>(n.current=!0,()=>{n.current=!1}),[]);const c=b(()=>{o(!0),s(a.current).finally(()=>{n.current&&o(!1)})},[s]);if(v.canPublish){if(e){const L=t===void 0?void 0:r||t.state==="changed"?"changed":"live";return l({live:L,onPress:c,busy:u,goingLive:E(t?.changes??[])})}return l({live:S,onPress:c,busy:u,pinnedUnpublished:g?.unpublished??!1})}}export{M as useWebsiteMainAction};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { LockHolder, SaveConflict } from "efficient-easel/edit-lock";
|
|
2
2
|
import { type OfferedSets } from "./editor-blocks.js";
|
|
3
3
|
import type { EditorCapabilities, EditorDocument, EditorDocumentAdapter } from "../../format/lib/editor-document-contract.js";
|
|
4
|
-
import type { EditorPageRow, WebsiteBackend } from "./web-backend.js";
|
|
4
|
+
import type { EditorPageRow, SiteLiveState, WebsiteBackend } from "./web-backend.js";
|
|
5
5
|
export type { EditorPageRow };
|
|
6
6
|
export type { EditorCapabilities, EditorDocument, EditorDocumentAdapter };
|
|
7
7
|
export type WebsiteCapabilities = EditorCapabilities & {
|
|
@@ -22,6 +22,7 @@ export interface PinnedChromeReport {
|
|
|
22
22
|
export type WebsiteDocumentAdapter = EditorDocumentAdapter & {
|
|
23
23
|
capabilities: WebsiteCapabilities;
|
|
24
24
|
pinnedChrome?: PinnedChromeReport;
|
|
25
|
+
siteLiveState?: () => Promise<SiteLiveState>;
|
|
25
26
|
};
|
|
26
27
|
export type SitePageAdapterOptions = {
|
|
27
28
|
editsPinnedInPlace?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{SITE_FOOTER_SLUG as
|
|
1
|
+
"use client";import{SITE_FOOTER_SLUG as g}from"../../format/lib/content/footer.js";import{offeredSetsOf as T}from"./editor-blocks.js";import{isBackendError as B}from"./editor-backend-error.js";import{isEfficientBackend as b}from"../../render/lib/editor-session.js";import{noteLoaded as O,notePublished as J,noteSaved as j,pageLiveState as _}from"./page-live-state.js";import{noteSiteLiveState as D,refreshSiteLiveState as E}from"./site-live-state.js";import{sendSiteWrites as G}from"../../format/lib/site-writes.js";import{spliceChrome as M,splitChrome as k}from"./pinned-chrome-doc.js";import{setActivePinnedChrome as N}from"../../format/lib/pinned-chrome-lock.js";import{backendOf as R}from"./website-session.js";function x(t){return!!(t?.publish&&t.liveState)}function U(t,o){return async(i,r)=>(await G(),(await t.publish(o)).state==="live"?D({state:"live",changes:[]}):E(0),{version:r??null})}function F(t,o,i){const r=o?{siteId:o}:void 0;return{resolve:s=>t.load({slug:s,...r}).then(e=>(e&&O(e.id,e.live),e)),saveLayout:(s,e,u,m)=>t.save(s,{layout:e},{version:u,clientId:m??""}).then(f=>(j(s,f.live),E(),f)),rereadVersion:t.version?s=>t.version(s):void 0,publish:x(i)?U(i,r):t.publish?(s,e)=>t.publish(s,e?{version:e}:void 0).then(u=>(J(s,u.live),u)):void 0,listPages:()=>t.list(r),createPage:t.create?s=>t.create({...s,...r}):void 0,deletePage:t.remove?(s,e)=>t.remove(s,e):void 0}}function V(t,o,i,r,s=!1){let e=null;const u=new Set;let m=!1,f={docId:null,lockHolder:null,conflict:null,saveFailed:!1,unpublished:!1,loadFailed:!1};const P=new Set,p=()=>{if(!e)return!1;const n=_(e.id);return n==="changed"||n==="never"||n===void 0&&m},h=n=>{f={...f,...n,docId:e?.id??null,unpublished:p()};for(const c of P)c()},y=n=>n&&typeof n=="object"&&!Array.isArray(n)?n:{},S=n=>!!e&&u.has(n),C={state:()=>f,subscribe:n=>(P.add(n),()=>{P.delete(n)})};return{resolve:async n=>{if(N(n===g?null:C),n===g)return i.resolve(n);let c=!1;const[d,a]=await Promise.all([i.resolve(n),t.load({slug:g,...o}).catch(()=>(c=!0,null))]);if(a){O(a.id,a.live);const v=y(a.layout);e={id:a.id,layout:v,version:a.version,savedJson:""}}else e=null;if(m=!1,!d||!e)return h({conflict:null,saveFailed:!1,loadFailed:c}),d;const l=M(y(d.layout),e.layout);return e.savedJson=JSON.stringify(k(l,e.layout).chrome),u.add(d.id),h({conflict:null,saveFailed:!1,loadFailed:!1}),{...d,layout:l}},saveLayout:async(n,c,d,a)=>{if(!e||!S(n))return i.saveLayout(n,c,d,a);const l=e,v=k(c,l.layout),H=await i.saveLayout(n,v.page,d,a),A=JSON.stringify(v.chrome);if(!v.chrome||A===l.savedJson||f.lockHolder)return H;try{const w=await t.save(l.id,{layout:v.chrome},{version:l.version,clientId:a??""});j(l.id,w.live),E(),l.layout=v.chrome,l.version=w.version,l.savedJson=A,m=!0,h({conflict:null,saveFailed:!1})}catch(w){B(w,"changed-elsewhere")?h({conflict:w.conflict??{savedBy:"",savedByYou:!1,secondsAgo:0}}):B(w,"lock-taken")?h({lockHolder:w.holder??{name:"",secondsSinceSeen:0,secondsSinceHeld:0}}):h({saveFailed:!0})}return H},publish:i.publish?async(n,c)=>{const d=await i.publish(n,c),a=e;if(a&&S(n)&&!s&&t.publish&&p()&&!f.lockHolder){const l=await t.publish(a.id,a.version?{version:a.version}:void 0);J(a.id,l.live),l.version!==null&&(a.version=l.version),m=!1,h({})}return d}:void 0,lock:r?{claim:async(n,c,d)=>{const a=await r.claim(n,c,d),l=e;if(l&&S(n))try{await r.claim(l.id,c,!1),f.lockHolder&&h({lockHolder:null})}catch(v){B(v,"lock-taken")&&h({lockHolder:v.holder??{name:"",secondsSinceSeen:0,secondsSinceHeld:0}})}return a},release:async(n,c)=>{await r.release(n,c);const d=e;d&&S(n)&&!f.lockHolder&&await r.release(d.id,c).catch(()=>{})}}:void 0,pinnedChrome:C}}function ne(t,o=R(),i=T(),r={}){const s=b(o),e=t?{siteId:t}:void 0,u=s?!!t:!0,m=o.site.update,f=s&&i.commerce&&i.service,P=!!r.editsPinnedInPlace&&f,p=x(o.site)?o.site:void 0,h=F(o.pages,t,p),y=P?V(o.pages,e,h,o.lock,!!p):null;return{capabilities:{canPublish:!!p||!!o.pages.publish,hasSiteSettings:s,hasSiteTheme:!!o.theme,placeholderFrames:!1,mediaEditing:!0,pageCreationInAdminForm:!o.pages.create,canDeletePagesInline:!!o.pages.remove,hasEditLock:!!o.lock,hasEditGuard:!0,hasPinnedChrome:f,editsPinnedInPlace:P,explainsSiteSettings:!1,hasSiteRecord:u,canEditSiteRecord:u&&!!m,hasPreviewLink:s||!!o.preview,hasCatalog:s&&i.commerce,hasForms:s&&i.service,hasBlog:!!o.blog&&i.service,offersCommerce:i.commerce,offersService:i.service},...h,...I(h.resolve),lock:o.lock,...y,site:u?()=>o.site.get(e):void 0,siteLiveState:p?()=>p.liveState(e):void 0,updateSite:u&&m?S=>m(S,e):void 0,previewHref:o.preview?S=>o.preview.href(S):void 0}}function te(t,o=R(),i=T()){const r=b(o),s=o.templates,e=s?s.pages(t):{list:()=>Promise.reject(new Error(L)),load:()=>Promise.reject(new Error(L)),save:()=>Promise.reject(new Error(L))};return{capabilities:{canPublish:!1,hasSiteSettings:!1,hasSiteTheme:!1,placeholderFrames:!0,mediaEditing:!1,pageCreationInAdminForm:!e.create,canDeletePagesInline:!!e.remove,hasEditLock:!1,hasEditGuard:!1,hasPinnedChrome:r&&i.commerce&&i.service,editsPinnedInPlace:!1,explainsSiteSettings:r,hasSiteRecord:!1,canEditSiteRecord:!1,hasPreviewLink:!1,hasCatalog:r&&i.commerce,hasForms:r&&i.service,hasBlog:!!o.blog&&i.service,offersCommerce:i.commerce,offersService:i.service},...F(e,void 0),...I(F(e,void 0).resolve),publish:void 0,templateName:s?()=>s.get(t).then(u=>u.name):void 0}}function I(t){return{resolve:o=>(N(null),t(o))}}const L="This editor's backend has no website templates.";export{ne as makeSitePageAdapter,te as makeTemplatePageAdapter};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ScreenMainAction } from "./editor-screen.js";
|
|
2
|
-
import type { PageLiveState } from "./web-backend.js";
|
|
2
|
+
import type { PageLiveState, SiteChange } from "./web-backend.js";
|
|
3
3
|
export type { PageLiveState };
|
|
4
4
|
export declare function noteLoaded(id: string, live: PageLiveState | undefined): void;
|
|
5
5
|
export declare function noteSaved(id: string, live: PageLiveState | undefined): void;
|
|
@@ -7,9 +7,11 @@ export declare function notePublished(id: string, live: PageLiveState | undefine
|
|
|
7
7
|
export declare function pageLiveState(id: string): PageLiveState | undefined;
|
|
8
8
|
export declare function usePageLiveState(id: string | null): PageLiveState | undefined;
|
|
9
9
|
export declare function effectiveLive(live: PageLiveState | undefined, hasUnsavedEdits: boolean): PageLiveState | undefined;
|
|
10
|
-
export declare function mainActionFor({ live, onPress, busy, pinnedUnpublished, }: {
|
|
10
|
+
export declare function mainActionFor({ live, onPress, busy, pinnedUnpublished, goingLive, }: {
|
|
11
11
|
live: PageLiveState | undefined;
|
|
12
12
|
onPress: () => void;
|
|
13
13
|
busy?: boolean;
|
|
14
14
|
pinnedUnpublished?: boolean;
|
|
15
|
+
goingLive?: readonly string[];
|
|
15
16
|
}): ScreenMainAction;
|
|
17
|
+
export declare function goingLiveLines(changes: readonly SiteChange[]): string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useSyncExternalStore as l}from"react";import{say as n}from"../../format/lib/editor-words.js";const r=new Map,s=new Set;function
|
|
1
|
+
import{useSyncExternalStore as l}from"react";import{say as n}from"../../format/lib/editor-words.js";const r=new Map,s=new Set;function u(e,t){if(!(r.has(e)&&r.get(e)===t)){r.set(e,t);for(const o of s)o()}}function d(e,t){u(e,t)}function v(e,t){const o=r.get(e);u(e,t??(o==="live"?"changed":o))}function m(e,t){u(e,t??"live")}function x(e){return r.get(e)}function g(e){return s.add(e),()=>{s.delete(e)}}function y(e){const t=()=>e?r.get(e):void 0;return l(g,t,t)}function b(e,t){return e==="live"&&t?"changed":e}function P({live:e,onPress:t,busy:o=!1,pinnedUnpublished:i=!1,goingLive:a}){const c=e==="live"&&!i,f=e==="changed"?n("Changes not live yet"):e==="never"?n("Never published"):i?n("Header and footer not live yet"):e==="live"?n("Everything is live"):null;return{label:n("Publish"),tooltip:e==="never"?n("Put this page on your site"):n("Put your changes on your site"),status:f,quiet:c?{label:n("Published"),reason:n("Everything is live")}:null,...a&&a.length?{goingLive:a}:{},onPress:t,busy:o}}function S(e){return e.map(t=>t.change==="take_down"?n("{name} (taken down)",{name:t.name}):t.name)}export{b as effectiveLive,S as goingLiveLines,P as mainActionFor,d as noteLoaded,m as notePublished,v as noteSaved,x as pageLiveState,y as usePageLiveState};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type HidableCheckField = {
|
|
2
|
+
type?: string;
|
|
3
|
+
arrayFields?: Record<string, unknown>;
|
|
4
|
+
options?: {
|
|
5
|
+
value?: unknown;
|
|
6
|
+
}[];
|
|
7
|
+
} & Record<string, unknown>;
|
|
8
|
+
export type HidableCheckBlock = {
|
|
9
|
+
fields?: Record<string, HidableCheckField | undefined>;
|
|
10
|
+
defaultProps?: Record<string, unknown>;
|
|
11
|
+
};
|
|
12
|
+
export type HidableCheckDraw = (type: string, props: Record<string, unknown>) => {
|
|
13
|
+
html?: string;
|
|
14
|
+
error?: string;
|
|
15
|
+
};
|
|
16
|
+
export declare const isHideableRow: (field: unknown) => boolean;
|
|
17
|
+
export declare function hidableRowProblems(blocks: Record<string, HidableCheckBlock>, types: readonly string[], draw: HidableCheckDraw): {
|
|
18
|
+
list: string[];
|
|
19
|
+
rows: number;
|
|
20
|
+
drawings: number;
|
|
21
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{textControlKind as m}from"../../../render/lib/puck/part-text.js";const v=new Set(["text","textarea"]),g=s=>v.has(m(s)??""),d=s=>`Zq${s.replace(/[^A-Za-z0-9]/g,"")}Zq`,j=(s,n)=>n==="bare"?d(s):{text:d(s),hidden:n==="shut"};function $(s,n){const t={...s.defaultProps??{},id:"t-1",puck:{isEditing:!1}},r=[];for(const[e,o]of Object.entries(s.fields??{}))if(o){if(o.type==="slot")t[e]=()=>null;else if(g(o))t[e]=j(e,n),r.push(d(e));else if(o.type==="array"&&o.arrayFields){const i=Object.entries(o.arrayFields).filter(([,a])=>g(a));if(!i.length)continue;const c=Array.isArray(t[e])&&t[e].length?t[e]:[{},{}];t[e]=c.map((a,f)=>{const u={...a??{}};for(const[l]of i)u[l]=j(`${e}${f}${l}`,n),r.push(d(`${e}${f}${l}`));return u})}}return{props:t,needles:r}}function A(s){const n=[{label:"",props:{}}];for(const[t,r]of Object.entries(s.fields??{})){const e=r?.options;if(!(!Array.isArray(e)||e.length>16))for(const o of e)o&&typeof o.value!="object"&&n.push({label:` (${t}=${String(o.value)})`,props:{[t]:o.value}})}return n}function k(s,n,t){const r=[];let e=0,o=0;for(const i of n){const c=s[i];if(!c)continue;const a=$(c,"open");if(e+=a.needles.length,!a.needles.length)continue;const f=$(c,"shut"),u=$(c,"bare");for(const l of A(c)){o+=1;const p=`${i}${l.label}`,h=t(i,{...a.props,...l.props});h.error?r.push(`${p}: a typed row ({ text, hidden: false }) throws — ${h.error}`):h.html?.includes("[object Object]")&&r.push(`${p}: a typed row reaches the page as [object Object]`);const b=t(i,{...f.props,...l.props});if(b.error)r.push(`${p}: a hidden row ({ text, hidden: true }) throws — ${b.error}`);else{const y=f.needles.filter(x=>b.html?.includes(x));y.length&&r.push(`${p}: a hidden row still draws its words (${y.join(", ")})`)}const w=t(i,{...u.props,...l.props});w.error&&r.push(`${p}: a row stored as a bare string throws — ${w.error}`)}}return{list:r,rows:e,drawings:o}}export{k as hidableRowProblems,g as isHideableRow};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SiteLiveState } from "./web-backend.js";
|
|
2
|
+
export type { SiteLiveState };
|
|
3
|
+
export declare function readSiteLiveStateWith(read: (() => Promise<SiteLiveState>) | null): void;
|
|
4
|
+
export declare function noteSiteLiveState(state: SiteLiveState): void;
|
|
5
|
+
export declare function refreshSiteLiveState(delayMs?: number): void;
|
|
6
|
+
export declare function siteLiveState(): SiteLiveState | undefined;
|
|
7
|
+
export declare function useSiteLiveState(): SiteLiveState | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useSyncExternalStore as a}from"react";let c,i=null,t=null,r=0;const o=new Set;function u(e){c=e;for(const n of o)n()}function m(e){i=e,r+=1,t&&clearTimeout(t),t=null,u(void 0)}function p(e){r+=1,u(e)}function x(e=250){i&&(t&&clearTimeout(t),t=setTimeout(()=>{t=null;const n=i;if(!n)return;const l=++r;n().then(s=>{l===r&&u(s)}).catch(()=>{})},e))}function f(){return c}function S(e){return o.add(e),()=>{o.delete(e)}}function v(){return a(S,f,f)}export{p as noteSiteLiveState,m as readSiteLiveStateWith,x as refreshSiteLiveState,f as siteLiveState,v as useSiteLiveState};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{useCallback as m,useEffect as
|
|
1
|
+
import{useCallback as m,useEffect as h,useRef as p}from"react";import{currentEditorSession as S}from"../../render/lib/editor-session.js";import{backendOf as T}from"./website-session.js";import{useEditorSession as b}from"./editor-session-context.js";import{refreshSiteLiveState as g}from"./site-live-state.js";import{holdSiteWrites as x}from"../../format/lib/site-writes.js";import{WebsiteBackendError as E}from"./web-backend.js";function w(r=S()){return(u,c,o)=>{const e=T(r).theme;return e?e.update(u,o?{siteId:o}:void 0):Promise.reject(new E("invalid","This backend stores no site theme."))}}function y(r){return r.themeFromDocument?{status:"skipped",reason:"template"}:r.token?null:{status:"skipped",reason:"no-token"}}async function j(r,u=w()){const{themeFromDocument:c,token:o,siteId:e,patch:n}=r,a=y({themeFromDocument:c,token:o});if(a)return a;if(Object.keys(n).length===0)return{status:"skipped",reason:"empty"};try{return await u(n,o,e??void 0),{status:"saved"}}catch(f){return{status:"failed",error:f}}}function Q({themeFromDocument:r,tokenRef:u,siteId:c,onResult:o}){const e=p(null),n=p({}),a=b(),f=p(o);f.current=o;const d=p(null),l=m(t=>{if(t.status==="skipped"){const s=`skipped:${t.reason}`;if(d.current===s)return;d.current=s}else d.current=null;f.current?.(t)},[]),i=m(async()=>{e.current&&(clearTimeout(e.current),e.current=null);const t=n.current;n.current={};const s=await j({themeFromDocument:r,token:u?.current,siteId:c,patch:t},w(a));return l(s),s.status==="saved"&&g(),s.status==="failed"&&(n.current={...t,...n.current}),s},[r,u,c,l,a]),v=m((t,s=!1)=>{const k=y({themeFromDocument:r,token:u?.current});if(k){l(k);return}n.current={...n.current,...t},e.current&&clearTimeout(e.current),s?i():e.current=setTimeout(()=>{i()},500)},[r,u,i,l]);return h(()=>()=>{i()},[i]),h(()=>x(async()=>{if(!e.current&&Object.keys(n.current).length===0)return;const t=await i();if(t.status==="failed")throw t.error}),[i]),{persist:v,flush:i}}export{y as refusalToQueue,w as themeRowSender,Q as useThemeRowPersist,j as writeThemeRow};
|
|
@@ -62,9 +62,25 @@ export interface WebsitePages {
|
|
|
62
62
|
}): Promise<void>;
|
|
63
63
|
linkTargets?(scope?: SiteScope): Promise<LinkTargetPage[]>;
|
|
64
64
|
}
|
|
65
|
+
export interface SiteChange {
|
|
66
|
+
kind: string;
|
|
67
|
+
id: string;
|
|
68
|
+
name: string;
|
|
69
|
+
change: "publish" | "take_down" | "update";
|
|
70
|
+
}
|
|
71
|
+
export interface SiteLiveState {
|
|
72
|
+
state: "live" | "changed";
|
|
73
|
+
changes: SiteChange[];
|
|
74
|
+
}
|
|
75
|
+
export interface SitePublishAnswer {
|
|
76
|
+
state: "live" | "changed";
|
|
77
|
+
published: SiteChange[];
|
|
78
|
+
}
|
|
65
79
|
export interface WebsiteSite {
|
|
66
80
|
get(scope?: SiteScope): Promise<SiteRecord>;
|
|
67
81
|
update?(patch: SiteRecordPatch, scope?: SiteScope): Promise<SiteRecord>;
|
|
82
|
+
publish?(scope?: SiteScope): Promise<SitePublishAnswer>;
|
|
83
|
+
liveState?(scope?: SiteScope): Promise<SiteLiveState>;
|
|
68
84
|
languages?(): Promise<{
|
|
69
85
|
base: string;
|
|
70
86
|
others: string[];
|
|
@@ -1195,6 +1195,7 @@ export declare const WEB_BUILDER_WORDS: {
|
|
|
1195
1195
|
readonly "{label} {n}": "{label} {n}";
|
|
1196
1196
|
readonly "{label} \u2014 row {n}": "{label} — row {n}";
|
|
1197
1197
|
readonly "{letter} \u00B7 Step": "{letter} · Step";
|
|
1198
|
+
readonly "{name} (taken down)": "{name} (taken down)";
|
|
1198
1199
|
readonly "{name} (unavailable)": "{name} (unavailable)";
|
|
1199
1200
|
readonly "{name} is editing the header and footer. Nothing you change in them here is saved.": "{name} is editing the header and footer. Nothing you change in them here is saved.";
|
|
1200
1201
|
readonly "{name} is on this section": "{name} is on this section";
|
|
@@ -8,4 +8,4 @@ const e={"$ efficient …":"$ efficient …","0 min":"0 min","0 min read":"0 min
|
|
|
8
8
|
*the counter.*`,"Select a word, then press the highlighter.":"Select a word, then press the highlighter.","Selector guide (pills + results)":"Selector guide (pills + results)","Selector pills":"Selector pills",Separator:"Separator","Series title":"Series title",Serif:"Serif","Set this card's corners first.":"Set this card's corners first.","Shadow color":"Shadow color",Shape:"Shape","Share button":"Share button",Shared:"Shared","Shop & galleries":"Shop & galleries","Short description of this figure.":"Short description of this figure.","Short detail line":"Short detail line","Short supporting line":"Short supporting line",Show:"Show","Show arrows":"Show arrows","Show cover image":"Show cover image","Show hints":"Show hints","Show on a card":"Show on a card","Show on phones":"Show on phones","Show slide picker":"Show slide picker","Show texture":"Show texture","Show the chat bubble":"Show the chat bubble","Show the chat bubble on the whole site":"Show the chat bubble on the whole site","Show ticker":"Show ticker","Show {label} on the slide":"Show {label} on the slide","Shown beside the heading":"Shown beside the heading","Shows when a visitor points at the button":"Shows when a visitor points at the button","Side space":"Side space","Side-by-side image and text in two columns.":"Side-by-side image and text in two columns.",Sideways:"Sideways","Signup Form":"Signup Form",Simple:"Simple","Site button color":"Site button color","Site settings":"Site settings","Site styles":"Site styles","Six across":"Six across","Six stagger":"Six stagger",Size:"Size",Sizes:"Sizes","Slash /":"Slash /","Slide name":"Slide name","Slide picker":"Slide picker","Slide picker placement":"Slide picker placement","Slide picker shape":"Slide picker shape",Small:"Small","Social Logos":"Social Logos","Social link settings belong to a website.":"Social link settings belong to a website.","Social links":"Social links",Soft:"Soft",Solid:"Solid","Somebody else":"Somebody else",Source:"Source","Space above and below":"Space above and below","Space between":"Space between",Spacer:"Spacer","Spec Strip":"Spec Strip","Spec Table":"Spec Table","Spec label":"Spec label","Spec tiles":"Spec tiles","Spec value":"Spec value","Spine (single rail)":"Spine (single rail)","Split (editorial aside)":"Split (editorial aside)",Square:"Square",Squares:"Squares",Stacked:"Stacked",Standard:"Standard",Start:"Start",Stat:"Stat","Stat & note":"Stat & note","Stat label":"Stat label","Stat name":"Stat name","Stat value":"Stat value",State:"State","State / Province":"State / Province",Statement:"Statement",Stats:"Stats","Stats & social proof":"Stats & social proof","Stats with Text":"Stats with Text","Status chip":"Status chip","Step *one*":"Step *one*","Step *three*":"Step *three*","Step *two*":"Step *two*","Stick to top":"Stick to top","Still time per slide":"Still time per slide","Storefront → Blog":"Storefront → Blog","Storefront ▸ Sites ▸ Settings":"Storefront ▸ Sites ▸ Settings","Story Timeline":"Story Timeline","Street address":"Street address",Stretch:"Stretch","Strip fill":"Strip fill","Strip items":"Strip items","Stripes · bold":"Stripes · bold","Stripes · fine":"Stripes · fine","Stripes · medium":"Stripes · medium",Style:"Style","Sub-title":"Sub-title","Sub-total lines":"Sub-total lines",Subtitle:"Subtitle","Subtitle font size":"Subtitle font size",Subtotal:"Subtotal","Success heading":"Success heading","Success message":"Success message",Superscript:"Superscript",Surfaces:"Surfaces","Switch now":"Switch now","Switch to Box footer":"Switch to Box footer","Synced from the blog post.":"Synced from the blog post.","Synced from the product.":"Synced from the product.","Synced from the site menu.":"Synced from the site menu.","Syncing from {place}…":"Syncing from {place}…",Tab:"Tab","Tab label":"Tab label","Tab name":"Tab name","Tabbed Gallery":"Tabbed Gallery",Tabs:"Tabs","Tall (3:4)":"Tall (3:4)","Tall first":"Tall first","Tall middle":"Tall middle","Team four":"Team four","Team one":"Team one","Team three":"Team three","Team two":"Team two",Telegram:"Telegram","Templates don’t store images — this slot stays a placeholder. Each website picks its own after it’s created.":"Templates don’t store images — this slot stays a placeholder. Each website picks its own after it’s created.","Templates don’t store videos — this slot stays a placeholder. Each website picks its own after it’s created.":"Templates don’t store videos — this slot stays a placeholder. Each website picks its own after it’s created.","Templates keep their look. Press Done.":"Templates keep their look. Press Done.",Terminal:"Terminal","Terminal (CLI session)":"Terminal (CLI session)","Terminal lines":"Terminal lines",Testimonials:"Testimonials",Text:"Text","Text & content":"Text & content","Text & media":"Text & media","Text color":"Text color","Text column":"Text column","Text height":"Text height","Text position":"Text position","Text size":"Text size","Text style":"Text style",Texts:"Texts",Texture:"Texture","Texture color":"Texture color","Texture opacity":"Texture opacity","Thanks — we'll email you to confirm.":"Thanks — we'll email you to confirm.","The chat bubble is hidden across the whole site.":"The chat bubble is hidden across the whole site.","The current product's compatible tyres — image, size, key specs and price per tyre, with an inquiry link. Display only.":"The current product's compatible tyres — image, size, key specs and price per tyre, with an inquiry link. Display only.","The current product's related items in a tidy row — the product page's built-in 'Pair with' cross-sell.":"The current product's related items in a tidy row — the product page's built-in 'Pair with' cross-sell.","The floating chat bubble shows in the corner of every page.":"The floating chat bubble shows in the corner of every page.","The footer cannot take another one of these":"The footer cannot take another one of these","The footer holds at most 6 sections":"The footer holds at most 6 sections","The header and footer could not load. They are hidden for now and nothing in them is saved. Reload to try again.":"The header and footer could not load. They are hidden for now and nothing in them is saved. Reload to try again.","The header and footer did not save. They are sent again with your next change.":"The header and footer did not save. They are sent again with your next change.","The header and footer were changed somewhere else. Nothing you change in them here is saved. Reload to get the latest.":"The header and footer were changed somewhere else. Nothing you change in them here is saved. Reload to get the latest.","The header cannot take another one of these":"The header cannot take another one of these","The header holds at most 3 sections":"The header holds at most 3 sections","The room left at the left and right edge of every page.":"The room left at the left and right edge of every page.","The section is full width, so this card follows Site styles ▸ Basics ▸ Corners.":"The section is full width, so this card follows Site styles ▸ Basics ▸ Corners.","The section it belonged to has been changed or removed.":"The section it belonged to has been changed or removed.","The standard width every page on this site renders at.":"The standard width every page on this site renders at.","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.":"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.",Theme:"Theme","Theme {n}":"Theme {n}","Theme {n} background":"Theme {n} background","Theme {n} main color":"Theme {n} main color","Theme {n} text color":"Theme {n} text color","Third item":"Third item","This cannot be undone.":"This cannot be undone.","This card is not in a section that can share corners.":"This card is not in a section that can share corners.","This color is hard to read on this theme's page. The buttons below are the same hue, darkened.":"This color is hard to read on this theme's page. The buttons below are the same hue, darkened.","This color is hard to read on your page background. Pick one further from it — lighter if your pages are dark, deeper if they are light.":"This color is hard to read on your page background. Pick one further from it — lighter if your pages are dark, deeper if they are light.","This color reads clearly on your pages.":"This color reads clearly on your pages.","This footer uses the old layout":"This footer uses the old layout","This is the only card in the section.":"This is the only card in the section.","This part is no longer here.":"This part is no longer here.","This part's settings did not open.":"This part's settings did not open.","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.","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.","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.","This ticker’s hero is no longer on the page.":"This ticker’s hero is no longer on the page.","Three across":"Three across","Three ladder":"Three ladder","Three stagger":"Three stagger",Ticker:"Ticker","Ticker items":"Ticker items",TikTok:"TikTok","Timeline entries":"Timeline entries","Timezone chip":"Timezone chip","Tint color":"Tint color","Tint opacity":"Tint opacity",Title:"Title",Tone:"Tone",Top:"Top","Top and bottom":"Top and bottom","Top border":"Top border","Top center":"Top center","Top left":"Top left","Top right":"Top right","Top row":"Top row","Top space":"Top space",Total:"Total","Total amount":"Total amount","Total label":"Total label","Total line":"Total line","Trailing note":"Trailing note","Triangle ▼":"Triangle ▼","Trusted by *teams worldwide*":"Trusted by *teams worldwide*","Two across":"Two across","Two image galleries with tabs and filters.":"Two image galleries with tabs and filters.","Two tall":"Two tall",Type:"Type","Type a postcode or address":"Type a postcode or address","Typed here":"Typed here","Typed in":"Typed in","Tyre Fitment Form":"Tyre Fitment Form","Tyre Sizes":"Tyre Sizes","URL pill":"URL pill","URL: /{slug}":"URL: /{slug}",Undo:"Undo",Ungrouped:"Ungrouped",Unit:"Unit","Unit labels":"Unit labels",Up:"Up","Up and down":"Up and down",Upcoming:"Upcoming","Update style":"Update style","Update {style}?":"Update {style}?",Upload:"Upload","Upload a background image":"Upload a background image","Upload a poster still":"Upload a poster still","Uppercase heading":"Uppercase heading","Use {colour}":"Use {colour}",Value:"Value","Value suffix":"Value suffix","Vertical breathing room between sections.":"Vertical breathing room between sections.",Video:"Video","Video file":"Video file","Video poster":"Video poster","View all":"View all","View all questions":"View all questions","View series →":"View series →",Volume:"Volume","Ways to pay":"Ways to pay",WeChat:"WeChat","What people *say.*":"What people *say.*",WhatsApp:"WhatsApp","Whether this page sits on the site's content column, or runs edge to edge.":"Whether this page sits on the site's content column, or runs edge to edge.","Whole number Theme Color":"Whole number Theme Color","Wide (2:1)":"Wide (2:1)","Wide promo strip with background image.":"Wide promo strip with background image.",Width:"Width","With us":"With us",Wording:"Wording",Wrap:"Wrap","Write the answer here.":"Write the answer here.","Write the opening paragraph here.\n\n- Start a line with a dash for a bullet.\n- Add as many as you like.":`Write the opening paragraph here.
|
|
9
9
|
|
|
10
10
|
- Start a line with a dash for a bullet.
|
|
11
|
-
- Add as many as you like.`,X:"X","X-Large":"X-Large",Year:"Year","Year →":"Year →",Years:"Years",YouTube:"YouTube","YouTube link":"YouTube link","Your *first* section.":"Your *first* section.","Your *second* section.":"Your *second* section.","Your fifth question goes here?":"Your fifth question goes here?","Your first question goes here?":"Your first question goes here?","Your fourth question goes here?":"Your fourth question goes here?","Your locations as a city gallery plus address and map cards.":"Your locations as a city gallery plus address and map cards.","Your review":"Your review","Your second question goes here?":"Your second question goes here?","Your third question goes here?":"Your third question goes here?",Zigzag:"Zigzag",accent:"accent","all theme colors":"all theme colors","body text":"body text",button:"button",card:"card",city:"city",draft:"draft","e.g. About":"e.g. About","e.g. Americas":"e.g. Americas","e.g. about":"e.g. about","e.g. {example}":"e.g. {example}","each block's own spacing":"each block's own spacing",entries:"entries",group:"group","https://youtu.be/…":"https://youtu.be/…",item:"item",label:"label",manifesto:"manifesto","not set":"not set","not shown live":"not shown live",part:"part",px:"px","the Text style in Site styles":"the Text style in Site styles","the admin":"the admin","the built-in corners":"the built-in corners","the page":"the page","the same as Desktop":"the same as Desktop","the section":"the section","the theme's image stage":"the theme's image stage","the theme's section background":"the theme's section background","this container's own spacing":"this container's own spacing","{grade} on the button":"{grade} on the button","{label} hex code":"{label} hex code","{label} {n}":"{label} {n}","{label} — row {n}":"{label} — row {n}","{letter} · Step":"{letter} · Step","{name} (unavailable)":"{name} (unavailable)","{name} is editing the header and footer. Nothing you change in them here is saved.":"{name} is editing the header and footer. Nothing you change in them here is saved.","{name} is on this section":"{name} is on this section","{name} — renamed in the Console: {place}.":"{name} — renamed in the Console: {place}.","{n} cities":"{n} cities","{n} city":"{n} city","{n} of {total} layouts":"{n} of {total} layouts","{value} from {from}":"{value} from {from}","{value} on desktop":"{value} on desktop","{what} settings belong to a website.":"{what} settings belong to a website.","— Articles in total":"— Articles in total","— Label":"— Label","— Name, Year":"— Name, Year"};export{e as WEB_BUILDER_WORDS};
|
|
11
|
+
- Add as many as you like.`,X:"X","X-Large":"X-Large",Year:"Year","Year →":"Year →",Years:"Years",YouTube:"YouTube","YouTube link":"YouTube link","Your *first* section.":"Your *first* section.","Your *second* section.":"Your *second* section.","Your fifth question goes here?":"Your fifth question goes here?","Your first question goes here?":"Your first question goes here?","Your fourth question goes here?":"Your fourth question goes here?","Your locations as a city gallery plus address and map cards.":"Your locations as a city gallery plus address and map cards.","Your review":"Your review","Your second question goes here?":"Your second question goes here?","Your third question goes here?":"Your third question goes here?",Zigzag:"Zigzag",accent:"accent","all theme colors":"all theme colors","body text":"body text",button:"button",card:"card",city:"city",draft:"draft","e.g. About":"e.g. About","e.g. Americas":"e.g. Americas","e.g. about":"e.g. about","e.g. {example}":"e.g. {example}","each block's own spacing":"each block's own spacing",entries:"entries",group:"group","https://youtu.be/…":"https://youtu.be/…",item:"item",label:"label",manifesto:"manifesto","not set":"not set","not shown live":"not shown live",part:"part",px:"px","the Text style in Site styles":"the Text style in Site styles","the admin":"the admin","the built-in corners":"the built-in corners","the page":"the page","the same as Desktop":"the same as Desktop","the section":"the section","the theme's image stage":"the theme's image stage","the theme's section background":"the theme's section background","this container's own spacing":"this container's own spacing","{grade} on the button":"{grade} on the button","{label} hex code":"{label} hex code","{label} {n}":"{label} {n}","{label} — row {n}":"{label} — row {n}","{letter} · Step":"{letter} · Step","{name} (taken down)":"{name} (taken down)","{name} (unavailable)":"{name} (unavailable)","{name} is editing the header and footer. Nothing you change in them here is saved.":"{name} is editing the header and footer. Nothing you change in them here is saved.","{name} is on this section":"{name} is on this section","{name} — renamed in the Console: {place}.":"{name} — renamed in the Console: {place}.","{n} cities":"{n} cities","{n} city":"{n} city","{n} of {total} layouts":"{n} of {total} layouts","{value} from {from}":"{value} from {from}","{value} on desktop":"{value} on desktop","{what} settings belong to a website.":"{what} settings belong to a website.","— Articles in total":"— Articles in total","— Label":"— Label","— Name, Year":"— Name, Year"};export{e as WEB_BUILDER_WORDS};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const n=new Set;function s(t){return n.add(t),()=>{n.delete(t)}}async function a(){const i=(await Promise.allSettled([...n].map(async e=>e()))).find(e=>e.status==="rejected");if(i)throw i.reason}export{s as holdSiteWrites,a as sendSiteWrites};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ruleChecks as
|
|
2
|
-
`)};n("§6/§7 the readers find a Btn import and a rounded-* className handed to it",
|
|
1
|
+
import{ruleChecks as p}from"./rule.js";import{builderModuleSpec as g}from"./support/ts-source.js";const l="--sf-button-radius",b="sf-button",$=i=>i.replace(/\/\*[\s\S]*?\*\//g,t=>" ".repeat(t.length)),w=new RegExp(`^import\\s+Btn\\s+from\\s+["'](?:${g("components/Btn")}|\\.{1,2}\\/(?:[\\w-]+\\/)*Btn)["'];?$`,"m"),c=i=>w.test(i);function m(i){const t=[],n=/<Btn\b[^>]*className=(?:"([^"]*)"|\{`([^`]*)`\})/g;let h;for(;(h=n.exec(i.text))!==null;){const u=h[1]??h[2]??"";/\brounded-/.test(u)&&t.push(`${i.path}: ${u}`)}return t}function x(i,t){const{check:n,report:h}=p("button corners"),u=e=>i.find(s=>s.path===e);{const e={path:"fixture.tsx",text:['import Btn from "@/components/Btn";','<Btn href="/x" className="mt-4 rounded-lg">Go</Btn>',"<Btn className={`mt-2`}>Go</Btn>"].join(`
|
|
2
|
+
`)};n("§6/§7 the readers find a Btn import and a rounded-* className handed to it",c(e.text)&&m(e).length===1),n("§7 …and a host's import of it by package name and side (efficient-web-builder 24)",c('import Btn from "efficient-web-builder/render/components/Btn";')&&!c('import Btn from "efficient-web-builder/render/components/BtnGroup";'))}if(t.stylesheet!==void 0){const e=u(t.stylesheet);if(n(`§1 read the stylesheet ${t.stylesheet}`,!!e)){const s=/\.sf-button\s*\{([^}]*)\}/.exec($(e.text));n(`§1 ${t.stylesheet} carries a \`.sf-button\` rule`,s!==null,"without it the class is decoration and the setting reaches no button"),s&&(n(`§1 the .sf-button rule reads \`var(${l}, 0)\``,/border-radius:\s*var\(--sf-button-radius,\s*0\)/.test(s[1]),`the property for the setting, and the \`0\` for every site that never chose one — got: ${s[1].trim()}`),n("§1 the .sf-button rule does not clip",!/overflow/.test(s[1]),`the trailing arrow translates 3px right on hover and would be shaved — got: ${s[1].trim()}`))}}if(t.button!==void 0){const e=u(t.button);n(`§2 read the shared button ${t.button}`,!!e)&&n(`§2 ${t.button} writes no \`rounded-*\` utility`,!/\brounded-(?!full\b)[a-z0-9[]/.test(e.text.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm,"")),"every one carries a built-in value, so an untouched site would jump from square to a radius the day it shipped");const s=t.rendered??[];n(`§2 the button was rendered (${s.length} shapes, at least 4)`,s.length>=4,"both variants as a link and as a button");for(const[r,a]of s)n(`§2 ${r}: the rendered button carries \`${b}\``,new RegExp(`class="${b}\\b`).test(a),`it is the element's only ear for Corners — got: ${a.slice(0,140)}`)}const o=t.cornerRadiusTokens;if(o){n("§3 a site that never chose a corner publishes NO button radius",!(l in o(null)),`that absence is what leaves it square, byte for byte as before — got: ${JSON.stringify(o(null))}`),n("§3 `0` is an ANSWER, not an absence: it publishes a flattened radius",o(0)[l]==="0",JSON.stringify(o(0)));for(const[d,f]of[[0,"0"],[9,"0.28125rem"],[16,"0.5rem"],[40,"1.25rem"]])n(`§3 ${d}px publishes ${l}: ${f}`,o(d)[l]===f,`a button is half the card, which is what inputs and panels beside it read — got: ${String(o(d)[l])}`);const[e,s]=t.radiusRange??[Number.NaN,Number.NaN];n(`§3 both ends of the track (${e}, ${s}) publish a button radius`,t.radiusRange!==void 0&&o(e)[l]!==void 0&&o(s)[l]!==void 0);const r=[null,0,9,40].map(d=>o(d)[l]??"0");n("§4 not-set and square both DRAW a square button",r[0]==="0"&&r[1]==="0",`they differ in what they publish, not in today's picture — got: ${JSON.stringify(r)}`),n("§4 9 and 40 draw two different NON-square buttons",r[2]!=="0"&&r[3]!=="0"&&r[2]!==r[3],`a setting that names buttons and moves none of them is this card's defect restored — got: ${JSON.stringify(r)}`);const a="--radius-full";for(const d of[0,9,16,40])n(`§5 ${d}px does not publish the fully-round token`,!(a in o(d)),"swatches, toggle knobs and status dots are a SHAPE, not a corner")}{const e=[];for(const s of t.callers){const r=u(s);r&&e.push(...m(r))}n(`§6 no caller hands \`Btn\` a \`rounded-*\` class (${t.callers.length} callers)`,e.length===0,`\`.sf-button\` is unlayered and would silently beat it; give the caller its own property instead — ${e.join(" | ")}`)}{const e=i.filter(a=>a.path.endsWith(".tsx")&&c(a.text)).map(a=>a.path).sort();n(`§7 the tree sweep found ${e.length} file(s) importing Btn (at least ${t.callerFloor})`,e.length>=t.callerFloor&&e.length>0,`too few to be real, so §7 is measuring nothing — ${JSON.stringify(e)}`);const s=e.filter(a=>!t.callers.includes(a));n("§7 the callers list names every file that imports `Btn`",s.length===0,`${JSON.stringify(s)} import(s) Btn and ${s.length===1?"is":"are"} not listed — a caller missing from it is a caller §6 never looks at. Add the path — the list is kept by hand on purpose, so a new caller is a visible line in a diff.`);const r=t.callers.filter(a=>!e.includes(a));n("§7 the callers list names no file that stopped importing `Btn`",r.length===0,`${JSON.stringify(r)} ${r.length===1?"is":"are"} listed and no longer import Btn — a dead row is a sweep over nothing. Drop the path, or say in a comment why the file is still worth sweeping.`)}return h()}export{x as buttonCorners};
|
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import{ruleChecks as
|
|
2
|
-
`),
|
|
3
|
-
`);p.forEach((b,h)=>{const m=b.trim();if(
|
|
4
|
-
`).length+
|
|
5
|
-
`);
|
|
6
|
-
`);if(!
|
|
7
|
-
`);
|
|
8
|
-
`);/\blabel=/.test(
|
|
9
|
-
`)},n=
|
|
10
|
-
`)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
${
|
|
14
|
-
|
|
15
|
-
${
|
|
16
|
-
|
|
1
|
+
import{ruleChecks as P}from"./rule.js";import{builderModuleSpec as W}from"./support/ts-source.js";import{isRegistryPath as F,registryFiles as A}from"./support/registry-source.js";const L="lib/puck/controls.tsx",k={},N={},E=["boxShareField","edgePad","placementField","CoordsField","textList","segmented","select","slider"],T=/sf-field-label|<Label>/,R=/<[A-Z][A-Za-z0-9]*Icon\s*\/>/,C=s=>s.startsWith("//")||s.startsWith("*")||s.startsWith("/*");function _(s,o){const e=s.indexOf("(",o);if(e===-1)return"";let u=0;const c=[];let g=e+1;for(let d=e;d<s.length;d+=1){const i=s[d];if(i==="("||i==="["||i==="{")u+=1;else if(i===")"||i==="]"||i==="}"){if(u-=1,u===0){c.push(s.slice(g,d));break}}else if(i===","&&u===1&&(c.push(s.slice(g,d)),g=d+1,c.length===2))break}return c[1]??""}function z(s,o){const e=new RegExp(`(?:^|[^.\\w])${o}\\s*(?:<[^()]*?>)?\\s*\\(|\\bcontrols\\.${o}\\s*(?:<[^()]*?>)?\\s*\\(`).exec(s);return e?e.index+e[0].length-1:s.indexOf("(")}function M(s,o){const e=s.slice(0,o);return e.includes("//")?!1:(e.match(/"/g)??[]).length%2===0&&(e.match(/`/g)??[]).length%2===0&&(e.match(/'/g)??[]).length%2===0}const G=W("lib/puck/controls"),B=(s,o)=>new RegExp(`import \\{[^}]*\\b${o}\\b[^}]*\\} from "${G}"`).test(s)||new RegExp(`import \\* as controls from "${G}"`).test(s);function I(s,o,e){const u=new RegExp(`(^|[^.\\w])${o}\\s*(<[^()]*?>)?\\s*\\(|\\bcontrols\\.${o}\\s*(<[^()]*?>)?\\s*\\(`,"g"),c=new RegExp(`^(export )?function ${o}(<[^>]*>)?\\(`),g=[];let d=0;for(const i of s){const p=i.text.split(`
|
|
2
|
+
`),w=p.join(`
|
|
3
|
+
`);p.forEach((b,h)=>{const m=b.trim();if(C(m)||c.test(m))return;u.lastIndex=0;const $=u.exec(b);if(!$||!M(b,$.index))return;d+=1;const t=_(w,p.slice(0,h).join(`
|
|
4
|
+
`).length+z(b,o));R.test(t)||/<FieldGlyph\b/.test(t)||e.some(n=>n.test(t))||g.push(`${i.path}:${h+1} ${m.slice(0,80)}`)})}return{bare:g,total:d}}function U(s){const o={};for(const e of s){const u=e.text.split(`
|
|
5
|
+
`);u.forEach((c,g)=>{if(!/className="sf-field"/.test(c))return;const d=u.slice(g,g+9).join(`
|
|
6
|
+
`);if(!T.test(d))return;const i=d.match(/sf-field-label[^>]*>([^<{][^<]*)</),p=d.match(/sf-field-label[^>]*>\{([^}]*)\}/),w=d.match(/<Label>([^<{][^<]*)</),b=d.match(/<Label>\{([^}]*)\}/),h=$=>$.trim()==="label"?"{label}":"{...}",m=i?i[1].trim():p?h(p[1]):w?w[1].trim():b?h(b[1]):"{...}";(o[e.path]??=[]).push(m)})}return o}function J(s){const o=[];let e=0;for(const u of s){const c=u.text.split(`
|
|
7
|
+
`);c.forEach((g,d)=>{if(!/<SettingsField\b/.test(g))return;const i=[];let p=!1;for(let b=d;b<Math.min(d+40,c.length)&&!p;b+=1){let h=c[b];if(h=h.replace(/\/\*[\s\S]*?\*\//g," "),/\/\*/.test(h)&&(h=h.slice(0,h.indexOf("/*"))),/^\s*\*/.test(c[b]))continue;const m=h.indexOf("//");m!==-1&&(h=h.slice(0,m)),i.push(h),h.includes(">")&&(p=!0)}const w=i.join(`
|
|
8
|
+
`);/\blabel=/.test(w)&&(e+=1,!/\bicon=/.test(w)&&o.push(`${u.path}:${d+1} ${g.trim().slice(0,80)}`))})}return{seen:e,bare:o}}function H(s,o){const{check:e,report:u}=P("panel rows use the shared row"),c=o.exceptions??[],{floors:g}=o;{const t={path:"fixture.tsx",text:['import { slider, textList } from "@/lib/puck/controls";','const a = { textList: () => controls.textList("Items", <ListIcon />, x) };','const b = slider("Thickness", 0, 10);','const c = slider("Gap", <GapIcon />, 0, 10);','// slider("In a comment", 0, 10) is not a row'].join(`
|
|
9
|
+
`)},n=I([t],"textList",[]),a=I([t],"slider",[]);e("the reader reads a namespaced call's own arguments, not the arrow's",n.total===1&&n.bare.length===0,JSON.stringify(n)),e("the reader flags a bare row whose neighbour has a glyph, and skips a comment",a.total===2&&a.bare.length===1&&a.bare[0].startsWith("fixture.tsx:3"),JSON.stringify(a));const f={path:"wrapped.tsx",text:['const a = { shape: withShowWhen(segmented("Shape", <SquareIcon />, opts), rule) };','const b = { size: withShowWhen(segmented("Size", opts), rule) };'].join(`
|
|
10
|
+
`)},r=I([f],"segmented",[]);e("the reader reads a wrapped call's own arguments: the glyphed row passes, the bare one is caught",r.total===2&&r.bare.length===1&&r.bare[0].startsWith("wrapped.tsx:2"),JSON.stringify(r))}const i=new Map(s.map(t=>[t.path,t])).get(L);e(o.writesBuilders?`read ${L}, where the builders are declared`:`${L} is not among this repository's files (it calls the builders, it does not declare them)`,!!i===o.writesBuilders);const p=A(s);e(`read this repository's share of the block registry (${p.length} files)`,p.length>0);const w=s.filter(t=>/^components\/[^/]+\.tsx$/.test(t.path)),b=s.filter(t=>/^scripts\/[^/]+\.tsx$/.test(t.path)),h=[...p,...i?[i]:[],...w],m=t=>t.path===L;{const t=h.filter(r=>m(r)||B(r.text,"toggle")),n=t.filter(r=>m(r)||F(r.path));e("only the known files use the toggle builder",t.length===n.length&&(!o.writesBuilders||n.some(m))&&n.some(r=>F(r.path)),t.map(r=>r.path).join(" · "));const a=[];let f=0;for(const r of n)r.text.split(`
|
|
11
|
+
`).forEach((x,l)=>{const y=x.trim();C(y)||/classList\.toggle/.test(x)||/^export function toggle\(/.test(y)||/(^|[^.\w])toggle\(/.test(x)&&(f+=1,!(R.test(x)||/<FieldGlyph\b/.test(x))&&a.push(`${r.path}:${l+1} ${y.slice(0,80)}`))});e("every toggle() row carries a glyph",a.length===0,`
|
|
12
|
+
${a.join(`
|
|
13
|
+
`)}`),e(`…and there are rows to check (${f} toggle() call sites, at least ${g.toggle})`,f>=g.toggle,"the scan is reading nothing")}const $=[{builder:"textList",inControls:!1,accept:[/TICKER_ITEMS_ROW\.icon/],name:"every textList() row carries a glyph"},{builder:"segmented",inControls:!0,accept:[/\bnoGlyph\(/],name:"every segmented() row carries a glyph (or a ruled noGlyph)"},{builder:"select",inControls:!0,accept:[/\btextKindGlyph\(/,/\bnoGlyph\(/],name:"every select() row carries a glyph (or a ruled noGlyph)"},{builder:"slider",inControls:!0,accept:[/\bnoGlyph\(/],name:"every slider() row carries a glyph"}];for(const t of $){const n=[...p,...t.inControls&&i?[i]:[],...b].filter(r=>t.inControls&&m(r)||F(r.path)||B(r.text,t.builder)),{bare:a,total:f}=I(n,t.builder,t.accept);e(t.name,a.length===0,`
|
|
14
|
+
${a.join(`
|
|
15
|
+
`)}`),e(`…and the ${t.builder} scan actually read rows (${f} call sites in ${n.length} files, at least ${g[t.builder]})`,f>=g[t.builder])}{const t=U(h);for(const l of c)e(`the exception still names a real row — ${l.label}`,(t[l.file]??[]).includes(l.label),`${l.file} no longer draws it`);const n={};for(const[l,y]of Object.entries(t)){const O=y.filter(S=>!c.some(j=>j.file===l&&j.label===S));O.length&&(n[l]=O)}const a=l=>l.slice().sort(),f=[];for(const[l,y]of Object.entries(n)){const O=k[l];if(!O){f.push(`${l} — hand-rolls ${y.length} row(s) and is not in PENDING`);continue}const S=a(y),j=a(O);(S.length!==j.length||S.some((v,D)=>v!==j[D]))&&f.push(`${l} — found [${S.join(" · ")}] but PENDING says [${j.join(" · ")}]`)}e("no NEW hand-rolled settings row",f.length===0,`
|
|
16
|
+
${f.join(`
|
|
17
|
+
`)}`);const r=Object.keys(k).filter(l=>!n[l]);e("no PENDING entry has outlived its subject",r.length===0,r.join(" · "));const x=Object.values(n).reduce((l,y)=>l+y.length,0);e("the hand-rolled rows are GONE — the count is zero",x===0,`${x}`),e("…and no file is left hand-rolling one",Object.keys(k).length===0,Object.keys(k).join(" · ")),e(`…and the rulings are exactly ${o.rulings} (a new one is argued in review, not added)`,c.length===o.rulings&&c.every(l=>l.why.trim().length>40),`${c.length}`),e("…and BlogSource is not among them, because its row is gone",!c.some(l=>l.file.endsWith("BlogSource.tsx")))}{const t=Object.values(N).reduce((n,a)=>n+a,0);if(e("every builder is finished — nothing left to count",t===0,`${t}`),e("…and the emptiness is because FOUR builders are done, not because the list was cleared",E.length===8&&["textList","segmented","select","slider"].every(n=>E.includes(n)),E.join(" · ")),e("…and a finished builder has left the list",E.every(n=>!(n in N)),E.join(" · ")),i){const n=Object.keys(N).filter(a=>!new RegExp(`(export )?function ${a}\\(`).test(i.text));e(`…and every builder it names is really declared in ${L}`,n.length===0,n.join(" · "))}}if(i){const t=i.text,n=t.indexOf("export function backgroundField("),a=n===-1?"":t.slice(n),f=a.slice(0,a.indexOf(`
|
|
17
18
|
}
|
|
18
|
-
`));e("backgroundField is declared",n!==-1),e("backgroundField renders SettingsField",/<SettingsField/.test(
|
|
19
|
+
`));e("backgroundField is declared",n!==-1),e("backgroundField renders SettingsField",/<SettingsField/.test(f)),e("…and hand-rolls no row of its own",f.length>0&&!/className="sf-field"/.test(f)),e("…and passes `BackgroundIcon`, not merely some glyph",/icon=\{<BackgroundIcon \/>\}/.test(f));const r=t.indexOf("export function cardImageBackgroundField("),x=r===-1?"":t.slice(r);e("…and cardImageBackgroundField still passes `GroundIcon`",/icon=\{<GroundIcon \/>\}/.test(x.slice(0,x.indexOf(`
|
|
19
20
|
}
|
|
20
|
-
`))))}{const{seen:t,bare:n}=
|
|
21
|
+
`))))}{const{seen:t,bare:n}=J(w);e(`the hand-rolled row scan read something (${t} hand-drawn SettingsField rows across ${w.length} files, at least ${g.handDrawn})`,t>=g.handDrawn),e("no hand-rolled SettingsField row goes without a glyph",n.length===0,`
|
|
21
22
|
${n.join(`
|
|
22
|
-
`)}`)}return
|
|
23
|
+
`)}`)}return u()}export{L as CONTROLS_FILE,z as callParen,H as panelRowsUseTheSharedRow,_ as secondArg};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{ruleChecks as
|
|
1
|
+
import{ruleChecks as R}from"./rule.js";import{builderModuleSpec as S}from"./support/ts-source.js";const o=/<(Render|Puck|SiteEditorProvider|EditorStoreProvider|ScreenStoreProvider)\b[^<>]*\bdata=\{/,m=/migrateRenamedProps\s*\(/,p=/export function migrateRenamedProps\b/;function v(l,r){const{check:t,report:g}=R("puck document surfaces"),a=e=>l.find(s=>s.path===e)?.text;{const e=n=>`<${n}`;t("a mount is found",o.test(`${e("Render")} config={c} data={doc} />`)),t("…across lines",o.test(`${e("SiteEditorProvider")}
|
|
2
2
|
config={c}
|
|
3
3
|
data={initial}
|
|
4
|
-
>`)),t("…and the screen's store provider is one under either of its names",["Editor","Screen"].every(n=>o.test(`${e(`${n}StoreProvider`)} config={c} data={doc}>`))),t("…and a tag named in prose is not one",!o.test(`the ${e("Puck")}> mounts, then its data={x} is read`)),t("…nor the composition API",!o.test(`${e("Puck.Preview")} />`));const s="migrateRenamedProps";t("a call is found",m.test(`const d = ${s}(stored);`)),t("…and a mention is not one",!m.test(`// runs ${s} first`)),t("the declaration is found, generic as it is",
|
|
4
|
+
>`)),t("…and the screen's store provider is one under either of its names",["Editor","Screen"].every(n=>o.test(`${e(`${n}StoreProvider`)} config={c} data={doc}>`))),t("…and a tag named in prose is not one",!o.test(`the ${e("Puck")}> mounts, then its data={x} is read`)),t("…nor the composition API",!o.test(`${e("Puck.Preview")} />`));const s="migrateRenamedProps";t("a call is found",m.test(`const d = ${s}(stored);`)),t("…and a mention is not one",!m.test(`// runs ${s} first`)),t("the declaration is found, generic as it is",p.test(`export function ${s}<T>(data: T): T {`))}const d=l.filter(e=>/\.tsx?$/.test(e.path));t(`the source scan reached the app (${d.length} TS/TSX files, at least ${r.minFiles})`,d.length>=r.minFiles);const c=d.filter(e=>o.test(e.text)).map(e=>e.path).sort(),$=Object.keys(r.mounts).sort(),u=c.filter(e=>!(e in r.mounts)),f=$.filter(e=>!c.includes(e));t(`every mount is declared (${c.length} found) — a NEW one must say whether its document comes from stored props (migrate it) or is a mock (say so)`,u.length===0,u.map(e=>`UNDECLARED: ${e}`).join(`
|
|
5
5
|
`)),t("every declared mount is a real mount — a stale row would shelter a surface that later stops migrating",f.length===0,f.map(e=>`NOT FOUND: ${e}`).join(`
|
|
6
6
|
`));const i=Object.entries(r.mounts).filter(([,e])=>e.migratedBy!==null),h=i.filter(([,e])=>!m.test(a(e.migratedBy)??""));if(t(`SURFACES=${i.length} — every mount fed from STORED props runs migrateRenamedProps, so a renamed prop key cannot silently reset a live section`,h.length===0,h.map(([e,s])=>`${e}
|
|
7
7
|
→ ${s.migratedBy} never calls migrateRenamedProps(`).join(`
|
|
8
|
-
`)),r.handedMigrator){const{rules:e,entry:s}=r.handedMigrator,n=a(e)??"";t(`${e} carries the REAL migrateRenamedProps, not a stand-in
|
|
8
|
+
`)),r.handedMigrator){const{rules:e,entry:s}=r.handedMigrator,n=a(e)??"";t(`${e} carries the REAL migrateRenamedProps, not a stand-in`,new RegExp(`import \\{ migrateRenamedProps \\} from "${S("lib/puck/renamed-props")}";`).test(n)&&/^\s*migrateRenamedProps,$/m.test(n)),t(`…${s} passes those rules to the screen's mount`,/<(?:EditorScreenMount|ScreenMount)\b[^>]*addressing=\{WEBSITE_ADDRESSING\}/.test(a(s)??""))}return t(`at least ${r.storedFloor} mount(s) fed from stored props (found ${i.length})`,i.length>=r.storedFloor,"if this drops, a surface was reclassified as a mock rather than fixed"),r.migrator&&t(`${r.migrator} still exports migrateRenamedProps — the function §2 hunts calls of is live`,p.test(a(r.migrator)??"")),g()}export{v as puckDocumentSurfaces};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{ruleChecks as u}from"./rule.js";const o="sf-theme-page",d=new RegExp(`["\`\\s]${o}`),
|
|
1
|
+
import{ruleChecks as u}from"./rule.js";import{builderModuleSpec as w}from"./support/ts-source.js";const o="sf-theme-page",d=new RegExp(`["\`\\s]${o}`),g=new RegExp(`from\\s+"${w("components/ThemeCard")}"`),m=/ThemeColourRow\b(?!s)/;function f(r,n){const t=r.indexOf(`
|
|
2
2
|
${n} {`);if(t<0)return"";const i=r.indexOf("{",t);return r.slice(i+1,r.indexOf(`
|
|
3
|
-
}`,i)).replace(/\/\*[\s\S]*?\*\//g,"")}function
|
|
3
|
+
}`,i)).replace(/\/\*[\s\S]*?\*\//g,"")}function $(r,n){const{check:t,report:i}=u("section theme preview"),h=r.filter(e=>e.path.endsWith(".tsx")),c=e=>r.find(s=>s.path===e)?.text;t("the class reader finds the preview class written into markup",d.test(`<div className="${o} x" />`)),t("…and not a longer class that only starts the same",!d.test(`<div className="x-${o}" />`)),t("a single colour row is told apart from the shared run",m.test("<ThemeColourRow label />")&&!m.test("<ThemeColourRows colors={c} />")),t("the rule-body reader cuts the comment and keeps the declaration",f(`
|
|
4
4
|
.m {
|
|
5
5
|
/* not #eff6ff */
|
|
6
6
|
background: var(--sf-accent-tint);
|
|
7
7
|
}
|
|
8
|
-
`,".m").trim()==="background: var(--sf-accent-tint);"),t(`read the .tsx files (${h.length}, at least ${n.minFiles})`,h.length>=n.minFiles,"fewer means the walk broke");const a=h.filter(e=>d.test(e.text)).map(e=>e.path);t(n.home?`\`.${o}\` is written by exactly one component, and it is ${n.home}`:`no file here writes \`.${o}\``,n.home?a.length===1&&a[0]===n.home:a.length===0,`it is written by ${a.length?a.join(", "):"nothing"}. Two files drawing one preview is the defect card 66503 closes, one level along: they match on the day they are written and drift on every day after — draw it with the builder's components/ThemeCard.tsx`);for(const e of n.panels??[]){const s=c(e)??"";t(`${e} reaches the drawing by import`,
|
|
8
|
+
`,".m").trim()==="background: var(--sf-accent-tint);"),t(`read the .tsx files (${h.length}, at least ${n.minFiles})`,h.length>=n.minFiles,"fewer means the walk broke");const a=h.filter(e=>d.test(e.text)).map(e=>e.path);t(n.home?`\`.${o}\` is written by exactly one component, and it is ${n.home}`:`no file here writes \`.${o}\``,n.home?a.length===1&&a[0]===n.home:a.length===0,`it is written by ${a.length?a.join(", "):"nothing"}. Two files drawing one preview is the defect card 66503 closes, one level along: they match on the day they are written and drift on every day after — draw it with the builder's components/ThemeCard.tsx`);for(const e of n.panels??[]){const s=c(e)??"";t(`${e} reaches the drawing by import`,g.test(s),"it imports no shared drawing, so whatever it puts on screen is its own"),t(`${e} draws no colour row of its own`,s.length>0&&!m.test(s),"it reaches a row directly instead of drawing the shared run, which is how the two lists drifted apart the first time")}for(const e of n.triggerPanels??[])t(`${e} reaches the closed drawing by import too`,/ThemeCardTrigger/.test(c(e)??""),"a trigger assembled in the panel is a second file drawing a theme");if(n.menuSheet){const e=c(n.menuSheet)??"",s=f(e,".sf-secttheme-menu"),l=f(e,".sf-multi-menu");t(`the instrument found both rules in ${n.menuSheet}, so the absences below mean something`,/background/.test(s)&&/border/.test(l),`.sf-secttheme-menu read ${s.length} chars and .sf-multi-menu ${l.length}`),t("the theme list fills itself with the accent tint",/background:\s*var\(--sf-accent-tint\)/.test(s)),t("…as the FILL, leaving the shared grey frame alone",!/border(-color)?:/.test(s)),t("…and NO literal colour is written there",!/#[0-9a-fA-F]{3,8}\b/.test(s)&&!/\brgba?\(/.test(s),"it must be `--sf-accent-tint`"),t("the SHARED dropdown container is still untinted",!/--sf-accent-tint/.test(l),"`.sf-multi-menu` is worn by MultiSelectField too; tinting every dropdown was offered and declined")}return i()}export{$ as sectionThemePreview};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ruleChecks as d}from"./rule.js";const
|
|
1
|
+
import{ruleChecks as d}from"./rule.js";import{builderModuleSpec as u}from"./support/ts-source.js";const l=/sf-blogsource-status/,r=new RegExp(`from "${u("components/SourceStatus")}"`);function g(m,t){const{check:s,report:i}=d("source status is shared");s("the import reader finds the shared block's import",r.test('import SourceStatus from "@/components/SourceStatus";')),s("…and a host's, by package name and side (efficient-web-builder 24)",r.test('import SourceStatus from "efficient-web-builder/render/components/SourceStatus";')),s("…and not a module whose name only starts the same",!r.test('import X from "@/components/SourceStatusLegacy";')),s("the class reader finds a hand-drawn status line",l.test('<p className="sf-blogsource-status" data-state={s}>'));const a=m.filter(e=>e.path.endsWith(".tsx"));s(`read the .tsx files (${a.length}, at least ${t.minFiles})`,a.length>=t.minFiles,"fewer means the walk broke, and every absence below is vacuous");const o=a.filter(e=>e.path!==t.home&&l.test(e.text)).map(e=>e.path);if(s(t.home?`only ${t.home} draws the status line`:"no file here draws the status line",o.length===0,`${o.join(" · ")} — draw it with the builder's components/SourceStatus.tsx`),t.home){const e=a.find(n=>n.path===t.home);s(`…and ${t.home} really does draw it`,!!e&&l.test(e?.text??""))}const h=t.callers.filter(e=>!r.test(a.find(n=>n.path===e)?.text??""));s(`every named caller imports the shared block (${t.callers.length})`,t.callers.length>0&&h.length===0,t.callers.length===0?"no caller is named — this half measures nothing":h.join(" · "));const c=a.filter(e=>e.path!==t.home&&!t.callers.includes(e.path)&&r.test(e.text)).map(e=>e.path);return s("…and no caller is missing from the list",c.length===0,c.join(" · ")),i()}export{g as sourceStatusIsShared};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
const f={single:"'",double:'"',template:"`"};function
|
|
2
|
-
`?(n="code",t+=e):t+=" ",o+=1;continue}if(n==="block"){if(e==="*"&&
|
|
3
|
-
`?e:" ",o+=1;continue}if(e==="\\"){t+=e+(
|
|
1
|
+
const f={single:"'",double:'"',template:"`"};function r(i){let t="",n="code",o=0;for(;o<i.length;){const e=i[o],c=i[o+1];if(n==="code"){if(e==="/"&&c==="/"){n="line",t+=" ",o+=2;continue}if(e==="/"&&c==="*"){n="block",t+=" ",o+=2;continue}e==="'"?n="single":e==='"'?n="double":e==="`"&&(n="template"),t+=e,o+=1;continue}if(n==="line"){e===`
|
|
2
|
+
`?(n="code",t+=e):t+=" ",o+=1;continue}if(n==="block"){if(e==="*"&&c==="/"){n="code",t+=" ",o+=2;continue}t+=e===`
|
|
3
|
+
`?e:" ",o+=1;continue}if(e==="\\"){t+=e+(c??""),o+=2;continue}e===f[n]&&(n="code"),t+=e,o+=1}return t}function d(i,t){const n=r(i),o=n.indexOf(t);if(o<0)throw new Error(`ts-source: marker not found: ${t}`);const e=n.indexOf("{",o+t.length-1);if(e<0)throw new Error(`ts-source: no block opens after: ${t}`);let c=0;for(let l=e;l<n.length;l+=1)if(n[l]==="{")c+=1;else if(n[l]==="}"&&(c-=1,c===0))return i.slice(e,l+1);throw new Error(`ts-source: unbalanced block after: ${t}`)}function s(i){return`(?:@\\/|efficient-web-builder\\/(?:render|format|editor)\\/)${i.replace(/[.*+?^${}()|[\]\\/]/g,"\\$&")}`}export{d as balancedBlockAfter,s as builderModuleSpec,r as stripComments};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as
|
|
2
|
-
*a thousand rows.*`},
|
|
1
|
+
import{jsx as m}from"react/jsx-runtime";import d from"../../../../../components/ChartSection.js";import{phRows as y,phHide as o,hidableRow as t}from"../../scaffold.js";import{say as r}from"../../../../../../format/lib/editor-words.js";const a={eyebrow:"By the numbers",title:`A picture worth
|
|
2
|
+
*a thousand rows.*`},p=()=>[{label:r("Before"),value:"9"},{label:r("After"),value:"3"},{label:r("With us"),value:"1"}],S={label:"Chart",defaultProps:{eyebrow:"",title:"",body:"",items:[],caption:"",chartStyle:"bars",valueSuffix:""},render:({eyebrow:i,title:l,body:s,items:b,caption:f,chartStyle:h,valueSuffix:n,puck:e})=>m(d,{eyebrow:o(i,a.eyebrow,e),title:o(l,a.title,e),body:t(s),items:y(b,p(),e),chartStyle:h,valueSuffix:t(n),caption:t(f),editing:e?.isEditing})};export{a as CHART_PH,S as ChartRender};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as p}from"react/jsx-runtime";import
|
|
2
|
-
*your favourite apps.*`,
|
|
1
|
+
import{jsx as p}from"react/jsx-runtime";import b from"../../../../../components/IntegrationsSection.js";import{phHide as o,hidableRow as t}from"../../scaffold.js";const f={label:"Integrations Grid",defaultProps:{eyebrow:"",title:"",body:"",apps:[],statValue:"",statLabel:"",note:""},render:({eyebrow:a,title:i,body:r,apps:s,statValue:n,statLabel:l,note:d,puck:e})=>p(b,{eyebrow:o(a,"Integrations",e),title:o(i,`Plays well with
|
|
2
|
+
*your favourite apps.*`,e),body:t(r),apps:s,statValue:t(n),statLabel:t(l),note:t(d),editing:e?.isEditing})};export{f as IntegrationsRender};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as E}from"react/jsx-runtime";import I from"../../../../../components/MockupSection.js";import{phHide as
|
|
2
|
-
*the counter.*`,
|
|
1
|
+
import{jsx as E}from"react/jsx-runtime";import I from"../../../../../components/MockupSection.js";import{phHide as o,hidableRow as e}from"../../scaffold.js";const z={label:"Mockup Card",defaultProps:{eyebrow:"",title:"",body:"",variant:"spec-card",cardHeader:"",badge:"",cardTitle:"",cardSubtitle:"",pills:[],tiles:[],rows:[],button:"",footnote:"",col1Title:"",col1Cards:[],col2Title:"",col2Cards:[],col3Title:"",col3Cards:[],col4Title:"",col4Cards:[],barsHeading:"",bars:[],termLines:[],urlText:"",heroTitle:"",heroButton:"",products:[],align:"right"},render:({eyebrow:r,title:l,body:i,variant:a,cardHeader:d,badge:c,cardTitle:s,cardSubtitle:n,pills:b,tiles:u,rows:T,button:p,footnote:g,col1Title:h,col1Cards:m,col2Title:C,col2Cards:f,col3Title:w,col3Cards:x,col4Title:H,col4Cards:y,barsHeading:S,bars:M,termLines:j,urlText:v,heroTitle:B,heroButton:L,products:R,align:k,puck:t})=>E(I,{eyebrow:o(r,"In the product",t),title:o(l,`Seen from
|
|
2
|
+
*the counter.*`,t),body:e(i),variant:a,cardHeader:e(d),badge:e(c),cardTitle:e(s),cardSubtitle:e(n),pills:b,tiles:u,rows:T,button:e(p),footnote:e(g),col1Title:e(h),col1Cards:m,col2Title:e(C),col2Cards:f,col3Title:e(w),col3Cards:x,col4Title:e(H),col4Cards:y,barsHeading:e(S),bars:M,termLines:j,urlText:e(v),heroTitle:e(B),heroButton:e(L),products:R,align:k,editing:t?.isEditing})};export{z as MockupRender};
|
|
@@ -11,6 +11,7 @@ export type HidableProp = {
|
|
|
11
11
|
export declare function phHide(value: HidableProp, placeholder: string, puck?: {
|
|
12
12
|
isEditing?: boolean;
|
|
13
13
|
}): string | undefined;
|
|
14
|
+
export declare function hidableRow(value: HidableProp): string | undefined;
|
|
14
15
|
export declare function phHideDefault(value: HidableProp, placeholder: string, puck?: {
|
|
15
16
|
isEditing?: boolean;
|
|
16
17
|
}): string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{say as
|
|
1
|
+
import{say as f}from"../../../../format/lib/editor-words.js";import{readHidable as i}from"efficient-easel/draw";import{CTA_PH as o}from"../../../../format/lib/puck/blocks/placeholders.js";function u(t,n,e){return t||(e?.isEditing?f(n):void 0)}function x(t,n,e){const r=Array.isArray(t)?t:[];return r.length?r:e?.isEditing?n:[]}function d(t,n,e){const r=i(t);if(!r.hidden)return u(r.text,n,e)}function s(t){if(t==null)return;const n=i(t);return n.hidden?"":n.text}function m(t,n,e){return i(t).hidden?"":d(t,n,e)}function a(t,n,e){return{text:d(t,o.text,e),href:n||o.href}}export{a as ctaHide,s as hidableRow,d as phHide,m as phHideDefault,u as phPrev,x as phRows};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "efficient-web-builder",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "26.0.0",
|
|
4
4
|
"description": "The EFFICIENT website builder: the website editor, the general sections and the renderer that draws them, compiled. Hostable by any EFFICIENT product; nothing here imports a host.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"author": "Efficient Pty Ltd",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"@tabler/icons-react": "^3.46.0",
|
|
55
|
-
"efficient-easel": "^13.
|
|
55
|
+
"efficient-easel": "^13.3.0",
|
|
56
56
|
"efficient-shell": "^7.75.0 || ^8.0.0",
|
|
57
57
|
"isomorphic-dompurify": "^3.18.0",
|
|
58
58
|
"next": ">=16",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@types/node": "^20",
|
|
73
73
|
"@types/react": "^19",
|
|
74
74
|
"@types/react-dom": "^19",
|
|
75
|
-
"efficient-easel": "^13.
|
|
75
|
+
"efficient-easel": "^13.3.0",
|
|
76
76
|
"efficient-shell": "^8.0.0",
|
|
77
77
|
"esbuild": "^0.28.0",
|
|
78
78
|
"happy-dom": "^20.14.5",
|