efficient-web-builder 18.2.0 → 18.3.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 CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 18.3.1 - 2026-10-17
4
+
5
+ **A preset's picture reaches the edge of its half** (GG 2026-10-17). 18.3.0 seeds a new Box with `padV2` and Padding 24/24, and the section presets (Brand Text, Image & Text Split) build their boxes from those defaults, so their PICTURE box was born storing 24/24, against the presets' own words ("No padding, so the picture bleeds"). The picture box now keeps `padV2` and stores no top or bottom padding, so it draws none (`pictureBox` in `lib/sections/section-presets`). The words' box keeps its 100s. Only a preset placed from now on changes; every stored page draws what it drew.
6
+
7
+ - Guard: `scripts/test-preset-picture-bleeds.tsx` (6). Failed before the change (4 of 6).
8
+
9
+ ## 18.3.0 - 2026-10-17
10
+
11
+ **A Box's padding number is the gap you see** (W-P2; Lewis's padding answer 2, 2026-10-15; GG 2026-10-17 chose the per-node marker). A minor: every stored page draws exactly what it drew.
12
+
13
+ ### Changed for merchants
14
+
15
+ - **A new Box draws exactly the Padding it shows.** It is born with `padV2: true` and Padding top and bottom 24, so it looks like a Box always has; the hidden `py-6` is gone for it, and a Padding of 0 is now really 0. Its empty sides show 0 in grey.
16
+ - **An existing Box is unchanged** until the ops converter (efficient-ops, box padding v2) adds 24 to its top/bottom and marks it `padV2`; until then it draws its `py-6` as before and its empty top/bottom show 24 in grey (what it draws). A Box on a picture and a Box in the site header never had `py-6` and are untouched.
17
+
18
+ ### Added for hosts
19
+
20
+ - `padV2` on a Box (`Flex`): a marker prop with no field. With it, `components/Flex` draws no `py-6` and adds no frame to its root padding (18.2.0's `rootPadAttrs` frame is 0). Easel never back-fills a stored node, so the marker only reaches new Boxes and converted ones.
21
+
22
+ ### Guards
23
+
24
+ - New `scripts/test-box-pad-v2.tsx` (9): an old Box draws as before; a padV2 Box draws what it stores (desktop, phone, top of a page); a new Box is born padV2 with 24/24; a card is untouched; the panel's grey is 24 for an old Box and 0 for a padV2 one. Failed before the change (6 of 9).
25
+ - Four older guards render an old STORED Box (the defaults minus padV2 and 24/24).
26
+
3
27
  ## 18.2.0 - 2026-10-17
4
28
 
5
29
  **A block inside a Box or a row takes its padding and its Border ON ITS OWN ROOT, never in a wrapper** (GG 2026-10-16/17; agreed with the US-websites window). A minor: no stored key changes, and every stored page draws what it drew.
@@ -3,6 +3,7 @@ type Direction = "row" | "column" | "tabs";
3
3
  type Justify = "start" | "center" | "between" | "end";
4
4
  type AlignItems = "start" | "center" | "stretch";
5
5
  interface FlexProps {
6
+ padV2?: boolean;
6
7
  border?: unknown;
7
8
  borderPhone?: unknown;
8
9
  direction: Direction;
@@ -30,5 +31,5 @@ interface FlexProps {
30
31
  fillHeight?: boolean;
31
32
  content: SlotComponent;
32
33
  }
33
- export default function Flex({ direction, label, gap, justify, align, wrap, share, phoneRow, blockSpacing, bgImage, darken, darkenStyle, placement, border, borderPhone, padTop, padBottom, padTopPhone, padBottomPhone, padLeft, padRight, padLeftPhone, padRightPhone, contained, fillHeight, content: Content, }: FlexProps): import("react").JSX.Element;
34
+ export default function Flex({ direction, label, gap, justify, align, wrap, share, phoneRow, blockSpacing, bgImage, darken, darkenStyle, placement, padV2, border, borderPhone, padTop, padBottom, padTopPhone, padBottomPhone, padLeft, padRight, padLeftPhone, padRightPhone, contained, fillHeight, content: Content, }: FlexProps): import("react").JSX.Element;
34
35
  export {};
@@ -1 +1 @@
1
- import{jsx as s,jsxs as Y,Fragment as q}from"react/jsx-runtime";import J from"./BoxTabs.js";import Q from"./SiteGutterFrame.js";import{BoxSurfaceProvider as T}from"./BoxSurfaceContext.js";import{useInSiteHeader as V}from"./PhoneMenuTools.js";import{FRAME_BASE as Z,FRAME_GUTTER as ee}from"./BlockFrame.js";import{containerGapProps as se}from"../lib/content/container-gap.js";import{boxLayoutClasses as re,boxBlockSpacingClass as oe,boxPhoneRowClasses as te,boxShareClasses as ne,boxWrapClass as le}from"../lib/content/box-layout.js";import{BOX_CARD_PAD as e,BOX_OWNS_SIDES_CLASS as ae,boxDarkenStyle as ie,boxPlacementClasses as me,CARD_SHADOW_CLASS as ce,isBackgroundBox as fe}from"../lib/content/box-background.js";import{sectionBorderStyle as ue}from"../lib/content/borders.js";import{sectionPadAttrs as de}from"../lib/content/section-padding.js";import{ON_MEDIA_INK_STYLE as be}from"../lib/content/ink.js";import{sizedBackground as ye}from"../lib/sized-image.js";function xe({direction:t,label:g,gap:k,justify:v,align:E,wrap:P,share:w,phoneRow:B,blockSpacing:D,bgImage:S,darken:F,darkenStyle:j,placement:O,border:z,borderPhone:H,padTop:a,padBottom:i,padTopPhone:m,padBottomPhone:c,padLeft:f,padRight:u,padLeftPhone:d,padRightPhone:b,contained:I=!0,fillHeight:G=!1,content:M}){const o=fe(S),p=V(),$=[ne(w),oe(D)].filter(Boolean).join(" "),W=$?` ${$}`:"",C=["flex",t==="row"?`flex-row ${te(B)}`:"flex-col",le(P),o?me(O??"center",t):re(v,E)].join(" ")+W,r=G||o?" h-full":"",y=o||p?"":" py-6",L=`${Z}${y} ${ee}${r}`,R=p?r.trim():`w-full${y}${r}`,n=se("Flex",k,t==="row"?"inline":"block"),_=s(M,{className:`${C}${n.className}${r}`,style:n.style,minEmptyHeight:120}),h=t==="tabs"?s(J,{className:`${C}${n.className}${r}`,style:n.style,children:_}):_,X=g?.trim()||void 0,K={values:{top:a,bottom:i,topPhone:m,bottomPhone:c,left:f,right:u,leftPhone:d,rightPhone:b},frame:y?24:0},A=U=>s(Q,{contained:I,framedClass:L,fillClass:R,tabLabel:X,pad:o?void 0:K,border:ue(z,H),children:U});if(!o)return A(h);const l=ie(F,j),x=de(typeof a=="number"?a:e.desktop,typeof i=="number"?i:e.desktop,typeof m=="number"?m:e.phone,typeof c=="number"?c:e.phone,typeof f=="number"?f:e.side,typeof u=="number"?u:e.side,typeof d=="number"?d:e.sidePhone,typeof b=="number"?b:e.sidePhone),N=s("div",{className:`relative z-[1] ${ae} ${x?.className??""}`.trimEnd(),style:l?{...x?.style,...be}:x?.style,children:h});return A(s(q,{children:Y("div",{className:`relative isolate overflow-hidden ${ce}${r}`,style:{backgroundImage:ye(S??""),backgroundSize:"cover",backgroundPosition:"center"},children:[l&&s("div",{className:"absolute inset-0 z-0",style:l,"aria-hidden":!0}),l?s(T,{children:N}):N]})}))}export{xe as default};
1
+ import{jsx as s,jsxs as q,Fragment as J}from"react/jsx-runtime";import Q from"./BoxTabs.js";import T from"./SiteGutterFrame.js";import{BoxSurfaceProvider as V}from"./BoxSurfaceContext.js";import{useInSiteHeader as Z}from"./PhoneMenuTools.js";import{FRAME_BASE as ee,FRAME_GUTTER as se}from"./BlockFrame.js";import{containerGapProps as re}from"../lib/content/container-gap.js";import{boxLayoutClasses as oe,boxBlockSpacingClass as te,boxPhoneRowClasses as ne,boxShareClasses as le,boxWrapClass as ae}from"../lib/content/box-layout.js";import{BOX_CARD_PAD as e,BOX_OWNS_SIDES_CLASS as ie,boxDarkenStyle as me,boxPlacementClasses as ce,CARD_SHADOW_CLASS as fe,isBackgroundBox as ue}from"../lib/content/box-background.js";import{sectionBorderStyle as de}from"../lib/content/borders.js";import{sectionPadAttrs as be}from"../lib/content/section-padding.js";import{ON_MEDIA_INK_STYLE as ye}from"../lib/content/ink.js";import{sizedBackground as xe}from"../lib/sized-image.js";function Se({direction:t,label:g,gap:k,justify:v,align:E,wrap:P,share:w,phoneRow:B,blockSpacing:D,bgImage:S,darken:F,darkenStyle:j,placement:O,padV2:z=!1,border:H,borderPhone:I,padTop:a,padBottom:i,padTopPhone:m,padBottomPhone:c,padLeft:f,padRight:u,padLeftPhone:d,padRightPhone:b,contained:G=!0,fillHeight:M=!1,content:W}){const o=ue(S),p=Z(),$=[le(w),te(D)].filter(Boolean).join(" "),L=$?` ${$}`:"",C=["flex",t==="row"?`flex-row ${ne(B)}`:"flex-col",ae(P),o?ce(O??"center",t):oe(v,E)].join(" ")+L,r=M||o?" h-full":"",y=o||p||z?"":" py-6",R=`${ee}${y} ${se}${r}`,X=p?r.trim():`w-full${y}${r}`,n=re("Flex",k,t==="row"?"inline":"block"),_=s(W,{className:`${C}${n.className}${r}`,style:n.style,minEmptyHeight:120}),h=t==="tabs"?s(Q,{className:`${C}${n.className}${r}`,style:n.style,children:_}):_,K=g?.trim()||void 0,U={values:{top:a,bottom:i,topPhone:m,bottomPhone:c,left:f,right:u,leftPhone:d,rightPhone:b},frame:y?24:0},A=Y=>s(T,{contained:G,framedClass:R,fillClass:X,tabLabel:K,pad:o?void 0:U,border:de(H,I),children:Y});if(!o)return A(h);const l=me(F,j),x=be(typeof a=="number"?a:e.desktop,typeof i=="number"?i:e.desktop,typeof m=="number"?m:e.phone,typeof c=="number"?c:e.phone,typeof f=="number"?f:e.side,typeof u=="number"?u:e.side,typeof d=="number"?d:e.sidePhone,typeof b=="number"?b:e.sidePhone),N=s("div",{className:`relative z-[1] ${ie} ${x?.className??""}`.trimEnd(),style:l?{...x?.style,...ye}:x?.style,children:h});return A(s(J,{children:q("div",{className:`relative isolate overflow-hidden ${fe}${r}`,style:{backgroundImage:xe(S??""),backgroundSize:"cover",backgroundPosition:"center"},children:[l&&s("div",{className:"absolute inset-0 z-0",style:l,"aria-hidden":!0}),l?s(V,{children:N}):N]})}))}export{Se as default};
@@ -1 +1 @@
1
- import{jsx as d}from"react/jsx-runtime";import{BOX_CARD_PAD as n,BOX_DARKEN as e,BOX_DARKEN_STYLES as p,isBackgroundBox as f}from"../../../../content/box-background.js";import{containerDirectionPoints as b}from"../../../../content/container-direction.js";import{OpacityIcon as k,StylesIcon as u}from"efficient-easel/icons";import{boxAlignField as x,boxBlockSpacingField as F,boxJustifyField as y,boxPhoneRowField as S,boxShareField as _,boxWrapField as B,gapField as O,group as l,placementField as D,plainText as h,select as j,sidesPaddingFields as A,slider as I,upload as P,withPanelOnly as R}from"../../../controls.js";import{FlexSlots as w}from"./render.js";const K={fields:{_gContent:l("Content"),content:w.content,_gLayout:l("Layout"),direction:{type:"radio",options:b("Flex")},label:R(h("Tab name")),gap:O("Flex"),justify:y(),align:x(),wrap:B(),share:_(),phoneRow:S(),blockSpacing:F(),_gBackground:l("Background image"),bgImage:P("Image","image/*"),darken:I("Darken",d(k,{}),e.min,e.max,e.step,e.fallback,e.unit),darkenStyle:j("Darken style",d(u,{}),p,p[0].value),placement:D("Content position",{stacking:!1})},resolveFields:(c,{fields:r})=>{const g=c.props;if(f(g.bgImage)){const i=A({fallback:{top:n.desktop,bottom:n.desktop,left:n.side,right:n.side}}),o={};let a=!1;for(const[s,m]of Object.entries(r)){if(s in i){a||Object.assign(o,i),a=!0;continue}o[s]=m}return a||Object.assign(o,i),o}const t={...r};return delete t.darken,delete t.darkenStyle,delete t.placement,t}};export{K as FlexFields};
1
+ import{jsx as c}from"react/jsx-runtime";import{BOX_CARD_PAD as l,BOX_DARKEN as n,BOX_DARKEN_STYLES as p,isBackgroundBox as m}from"../../../../content/box-background.js";import{containerDirectionPoints as f}from"../../../../content/container-direction.js";import{OpacityIcon as b,StylesIcon as u}from"efficient-easel/icons";import{boxAlignField as k,boxBlockSpacingField as x,boxJustifyField as F,boxPhoneRowField as y,boxShareField as S,boxWrapField as _,gapField as B,group as s,placementField as O,plainText as D,select as h,sidesPaddingFields as d,slider as j,upload as P,withPanelOnly as w}from"../../../controls.js";import{FlexSlots as A}from"./render.js";const X={fields:{_gContent:s("Content"),content:A.content,_gLayout:s("Layout"),direction:{type:"radio",options:f("Flex")},label:w(D("Tab name")),gap:B("Flex"),justify:F(),align:k(),wrap:_(),share:S(),phoneRow:y(),blockSpacing:x(),_gBackground:s("Background image"),bgImage:P("Image","image/*"),darken:j("Darken",c(b,{}),n.min,n.max,n.step,n.fallback,n.unit),darkenStyle:h("Darken style",c(u,{}),p,p[0].value),placement:O("Content position",{stacking:!1})},resolveFields:(i,{fields:e})=>{const o=i.props;if(m(o.bgImage)){const r=d({fallback:{top:l.desktop,bottom:l.desktop,left:l.side,right:l.side}});return g(e,r)}const t=i.props.padV2!==!0?g(e,d({fallback:{top:24,bottom:24}})):{...e};return delete t.darken,delete t.darkenStyle,delete t.placement,t}};function g(i,e){const o={};let a=!1;for(const[t,r]of Object.entries(i)){if(t in e){a||Object.assign(o,e),a=!0;continue}o[t]=r}return a||Object.assign(o,e),o}export{X as FlexFields};
@@ -1 +1 @@
1
- import{jsx as t}from"react/jsx-runtime";import n from"../../../../../components/Flex.js";import{sectionFillsHeight as a}from"../../../../content/section-min-height.js";const i={content:{type:"slot"}},l={label:"Box",fields:i,defaultProps:{direction:"row",justify:"start",align:"stretch",wrap:!0,content:[],share:"equal",blockSpacing:"gap"},render:e=>t(n,{direction:e.direction,label:e.label,gap:e.gap,justify:e.justify,align:e.align,wrap:e.wrap,share:e.share,phoneRow:e.phoneRow,blockSpacing:e.blockSpacing,bgImage:e.bgImage,darken:e.darken,darkenStyle:e.darkenStyle,placement:e.placement,border:e.sectionBorder,borderPhone:e.sectionBorderPhone,padTop:e.sectionPaddingTop,padBottom:e.sectionPaddingBottom,padTopPhone:e.sectionPaddingTopPhone,padBottomPhone:e.sectionPaddingBottomPhone,padLeft:e.sectionPaddingLeft,padRight:e.sectionPaddingRight,padLeftPhone:e.sectionPaddingLeftPhone,padRightPhone:e.sectionPaddingRightPhone,contained:e.contained,fillHeight:a(e),content:e.content})};export{l as FlexRender,i as FlexSlots};
1
+ import{jsx as t}from"react/jsx-runtime";import n from"../../../../../components/Flex.js";import{sectionFillsHeight as a}from"../../../../content/section-min-height.js";const i={content:{type:"slot"}},g={label:"Box",fields:i,defaultProps:{direction:"row",justify:"start",align:"stretch",wrap:!0,content:[],share:"equal",blockSpacing:"gap",padV2:!0,sectionPaddingTop:24,sectionPaddingBottom:24},render:e=>t(n,{direction:e.direction,label:e.label,gap:e.gap,justify:e.justify,align:e.align,wrap:e.wrap,share:e.share,phoneRow:e.phoneRow,blockSpacing:e.blockSpacing,bgImage:e.bgImage,darken:e.darken,darkenStyle:e.darkenStyle,placement:e.placement,padV2:e.padV2===!0,border:e.sectionBorder,borderPhone:e.sectionBorderPhone,padTop:e.sectionPaddingTop,padBottom:e.sectionPaddingBottom,padTopPhone:e.sectionPaddingTopPhone,padBottomPhone:e.sectionPaddingBottomPhone,padLeft:e.sectionPaddingLeft,padRight:e.sectionPaddingRight,padLeftPhone:e.sectionPaddingLeftPhone,padRightPhone:e.sectionPaddingRightPhone,contained:e.contained,fillHeight:a(e),content:e.content})};export{g as FlexRender,i as FlexSlots};
@@ -1 +1 @@
1
- import{BOX_TYPE as o}from"../puck/container-blocks.js";function t(i,n,e,c={}){return{type:i,props:{...n(i),id:e(i),...c}}}const g={Manifesto:(i,n)=>({type:o,props:{...i(o),id:n(o),direction:"row",share:"equal",sectionHeightMode:"screen",name:"Brand Text",content:[t(o,i,n,{direction:"column",justify:"center",blockSpacing:"gap",name:"Text",sectionPaddingTop:100,sectionPaddingBottom:100,sectionPaddingLeft:40,sectionPaddingRight:40,content:[t("Eyebrow",i,n,{eyebrowLook:"plain"}),t("Heading",i,n),t("Text",i,n),t("Stats",i,n)]}),t(o,i,n,{direction:"column",name:"Picture",content:[]})]}}),Split:(i,n)=>({type:o,props:{...i(o),id:n(o),direction:"row",share:"equal",sectionHeightMode:"screen",sectionHeightValue:70,name:"Image & Text Split",content:[t(o,i,n,{direction:"column",justify:"center",blockSpacing:"gap",name:"Text",sectionPaddingTop:100,sectionPaddingBottom:100,sectionPaddingLeft:60,sectionPaddingRight:60,content:[t("Eyebrow",i,n,{eyebrowLook:"plain"}),t("Heading",i,n),t("Text",i,n),t("ButtonBlock",i,n)]}),t(o,i,n,{direction:"column",name:"Image",content:[t("ImageBlock",i,n)]})]}}),Subscribe:(i,n)=>({type:o,props:{...i(o),id:n(o),direction:"column",name:"Subscribe",content:[t("Heading",i,n),t("Text",i,n),t("Form",i,n)]}})};function r(i){return g[i]??null}export{g as SECTION_PRESETS,r as presetFor};
1
+ import{BOX_TYPE as e}from"../puck/container-blocks.js";function t(n,i,o,g={}){return{type:n,props:{...i(n),id:o(n),...g}}}function c(n,i,o){return t(e,n,i,{...o,sectionPaddingTop:void 0,sectionPaddingBottom:void 0})}const p={Manifesto:(n,i)=>({type:e,props:{...n(e),id:i(e),direction:"row",share:"equal",sectionHeightMode:"screen",name:"Brand Text",content:[t(e,n,i,{direction:"column",justify:"center",blockSpacing:"gap",name:"Text",sectionPaddingTop:100,sectionPaddingBottom:100,sectionPaddingLeft:40,sectionPaddingRight:40,content:[t("Eyebrow",n,i,{eyebrowLook:"plain"}),t("Heading",n,i),t("Text",n,i),t("Stats",n,i)]}),c(n,i,{direction:"column",name:"Picture",content:[]})]}}),Split:(n,i)=>({type:e,props:{...n(e),id:i(e),direction:"row",share:"equal",sectionHeightMode:"screen",sectionHeightValue:70,name:"Image & Text Split",content:[t(e,n,i,{direction:"column",justify:"center",blockSpacing:"gap",name:"Text",sectionPaddingTop:100,sectionPaddingBottom:100,sectionPaddingLeft:60,sectionPaddingRight:60,content:[t("Eyebrow",n,i,{eyebrowLook:"plain"}),t("Heading",n,i),t("Text",n,i),t("ButtonBlock",n,i)]}),c(n,i,{direction:"column",name:"Image",content:[t("ImageBlock",n,i)]})]}}),Subscribe:(n,i)=>({type:e,props:{...n(e),id:i(e),direction:"column",name:"Subscribe",content:[t("Heading",n,i),t("Text",n,i),t("Form",n,i)]}})};function a(n){return p[n]??null}export{p as SECTION_PRESETS,a as presetFor};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "efficient-web-builder",
3
- "version": "18.2.0",
3
+ "version": "18.3.1",
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",