@taprootio/espalier 2.0.2 → 2.1.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.
@@ -144,6 +144,8 @@ type HeaderThemeToggle = "hidden" | "visible";
144
144
  * @cssprop --esp-header-height - The height of the header bar. Defaults to `calc(4.5 * var(--esp-size-small))`.
145
145
  * @cssprop --esp-header-color - The text/icon color inherited by header controls. Defaults to `var(--esp-color-text)`.
146
146
  * @cssprop --esp-header-z-index - The z-index of the header host. Defaults to `20`.
147
+ * @cssprop --esp-header-content-max-width - Surface-alignment contract set by `esp-page`: the maximum width the bar content is constrained to (the bar background stays full-bleed). Defaults to `100%` (no constraint). `esp-page` sets this to its resolved content cap.
148
+ * @cssprop --esp-header-content-lead - Surface-alignment contract set by `esp-page`: the fraction of the leftover width placed before the content, aligning it (`0` = start, `0.5` = center, `1` = end). Defaults to `0`.
147
149
  * @cssprop --esp-header-compact-height - The height of compact scroll-reactive headers. Defaults to `max(44px, calc(3.5 * var(--esp-size-small)))`.
148
150
  * @cssprop --esp-header-extended-menu-height - The second-row menu height for extended layouts. Defaults to `calc(3.5 * var(--esp-size-small))`.
149
151
  * @cssprop --esp-header-extended-menu-border - The border between the primary row and second-row menu in extended layouts. Defaults to `1px solid var(--esp-color-border)`.
@@ -306,6 +308,15 @@ export declare class EspalierHeader extends EspalierElementBase {
306
308
  * menu slotted into the header.
307
309
  */
308
310
  drawerTarget: string;
311
+ /**
312
+ * Opt out of surface alignment. When an `esp-header` is slotted into an
313
+ * `esp-page`, it constrains its bar content to the page's content
314
+ * surface by default (the bar background stays full-bleed). Set this to
315
+ * let the content span the full width instead, as it did before the
316
+ * page grew alignment modes. Standalone headers (outside `esp-page`) are
317
+ * already full-bleed and unaffected.
318
+ */
319
+ fullBleedContent: boolean;
309
320
  /**
310
321
  * The burger element inside the header. External code can use
311
322
  * this to programmatically reset the burger's visual state
@@ -1,7 +1,7 @@
1
- var n=function(p,e,t,o){var s=arguments.length,a=s<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,t):o,i;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")a=Reflect.decorate(p,e,t,o);else for(var h=p.length-1;h>=0;h--)(i=p[h])&&(a=(s<3?i(a):s>3?i(e,t,a):i(e,t))||a);return s>3&&a&&Object.defineProperty(e,t,a),a};import{css as y,html as d,nothing as c}from"lit";import{customElement as x,property as l,state as u}from"lit/decorators.js";import{classMap as M}from"lit/directives/class-map.js";import{styleMap as S}from"lit/directives/style-map.js";import"../burger/esp-burger.js";import{createRef as b,ref as v}from"lit/directives/ref.js";import{EspalierMenu as T}from"./esp-menu.js";import{EspalierElementBase as f}from"../shared/esp-element-base.js";const D="(max-width: 36rem)";let r=class extends f{constructor(){super(...arguments),this.menuOpen=!1,this.menuTooLarge=!1,this.mobileMenu=!1,this.scrolled=!1,this.hiddenByScroll=!1,this.scrollProgress=0,this.showBurger=!1,this.layout="standard",this.brandText="",this.brandLogo="",this.brandHref="",this.brandAlt="",this.brandColor="",this.brandAlign="start",this.brandWrap="truncate",this.menuDisplay="auto",this.themeToggle="hidden",this.scrollBehavior="none",this.scrollThreshold=16,this.dockOffset=0,this.drawerTarget="",this.menuContainer=b(),this.menuButton=b(),this.menu=void 0,this.externalDrawerTarget=null,this.lastScrollY=0,this.lastInlineMenuWidth=0,this.mobileMenuQuery=null,this.menuDrawerListenersAttached=!1,this.observingMenuContainer=!1,this.scrollListenersAttached=!1,this.scrollRafId=null,this.resizeObserver=new ResizeObserver(()=>this.syncMenuLayout()),this.updateScrollState=()=>{this.scrollRafId===null&&(this.scrollRafId=requestAnimationFrame(()=>{this.scrollRafId=null,this.runScrollStateUpdate()}))},this.handleMobileMenuQueryChange=e=>{this.mobileMenu=e.matches,this.syncMenuLayout()},this.toggleTheme=()=>{const e=this.getThemeRoot();e&&(e.scheme=e.scheme==="dark"?"light":"dark")},this.handleMenuToggleClicked=()=>{if(this.menuOpen){this.closeNav();return}this.openNav()},this.onMenuDrawerOpened=()=>{this.menuOpen=!0,document.body.classList.add("menu-open"),this.burger&&(this.burger.menuOpen=!0)},this.onMenuDrawerClosed=()=>{this.menuOpen=!1,document.body.classList.remove("menu-open"),this.burger&&(this.burger.menuOpen=!1)}}syncMenuLayout(){if(!this.menuContainer.value||!this.menu||!this.menu.getWidth)return;const e=this.menuContainer.value.clientWidth,t=this.menu.getWidth();t>0&&(this.lastInlineMenuWidth=t);const o=this.lastInlineMenuWidth||t,s=this.getExternalDrawerTarget(),a=this.menuDisplay!=="inline",i=this.showBurger||this.menuDisplay==="drawer"||this.layout==="minimal";this.menuTooLarge=a&&this.menuDisplay==="auto"&&o>e,this.menu.sliding=a&&!s&&(this.menuTooLarge||i||this.mobileMenu)}getExternalDrawerTarget(){if(!this.drawerTarget)return null;const e=document.getElementById(this.drawerTarget);return e===this.menu?null:e&&"openDrawer"in e&&typeof e.openDrawer=="function"&&"closeDrawer"in e&&typeof e.closeDrawer=="function"?e:null}getBurgerFocusTarget(){const t=this.shadowRoot?.querySelector("esp-header-button.menu-toggle")?.shadowRoot?.querySelector("button"),o=this.menuButton.value?.shadowRoot?.querySelector("button");return t??o??null}getScrollTokens(){const e=this.scrollBehavior.split(/\s+/).map(t=>t.trim().toLowerCase()).filter(Boolean);return new Set(e.filter(t=>t!=="none"))}getEffectiveScrollThreshold(){return Number.isFinite(this.scrollThreshold)?Math.max(0,this.scrollThreshold):0}clearScrollState(){this.scrolled=!1,this.hiddenByScroll=!1,this.scrollProgress=0}runScrollStateUpdate(){const e=this.getScrollTokens();if(!e.size){this.clearScrollState();return}const t=Math.max(0,window.scrollY||document.documentElement.scrollTop||0),o=this.getEffectiveScrollThreshold(),s=Number.isFinite(this.dockOffset)?Math.max(0,this.dockOffset):o,a=t>(e.has("dock")?s:o),i=t>this.lastScrollY,h=e.has("reveal")&&i&&t>o&&!this.menuOpen;if(this.scrolled=a,this.hiddenByScroll=h,e.has("progress")){const m=document.documentElement,g=Math.max(1,m.scrollHeight-window.innerHeight);this.scrollProgress=Math.min(1,t/g)}else this.scrollProgress=0;this.lastScrollY=t}cancelScrollUpdate(){this.scrollRafId!==null&&(cancelAnimationFrame(this.scrollRafId),this.scrollRafId=null)}syncScrollListeners(){const e=this.getScrollTokens().size>0;if(e&&!this.scrollListenersAttached?(window.addEventListener("scroll",this.updateScrollState,{passive:!0}),window.addEventListener("resize",this.updateScrollState,{passive:!0}),this.scrollListenersAttached=!0):!e&&this.scrollListenersAttached&&this.removeScrollListeners(),e){this.updateScrollState();return}this.cancelScrollUpdate(),this.clearScrollState()}removeScrollListeners(){this.scrollListenersAttached&&(window.removeEventListener("scroll",this.updateScrollState),window.removeEventListener("resize",this.updateScrollState),this.scrollListenersAttached=!1)}addMenuDrawerListeners(){!this.menu||this.menuDrawerListenersAttached||(this.menu.addEventListener("drawer-opened",this.onMenuDrawerOpened),this.menu.addEventListener("drawer-closed",this.onMenuDrawerClosed),this.menuDrawerListenersAttached=!0)}removeMenuDrawerListeners(){!this.menu||!this.menuDrawerListenersAttached||(this.menu.removeEventListener("drawer-opened",this.onMenuDrawerOpened),this.menu.removeEventListener("drawer-closed",this.onMenuDrawerClosed),this.menuDrawerListenersAttached=!1)}observeMenuContainer(){!this.menuContainer.value||this.observingMenuContainer||(this.resizeObserver.observe(this.menuContainer.value),this.observingMenuContainer=!0)}disconnectResizeObserver(){this.observingMenuContainer&&(this.resizeObserver.disconnect(),this.observingMenuContainer=!1)}syncMobileMenuQuery(){if("matchMedia"in window){if(!this.mobileMenuQuery){this.mobileMenuQuery=window.matchMedia(D),this.mobileMenu=this.mobileMenuQuery.matches,this.mobileMenuQuery.addEventListener("change",this.handleMobileMenuQueryChange);return}this.mobileMenu=this.mobileMenuQuery.matches}}getThemeRoot(){return this.traverseToClosest("esp-root")}syncExternalDrawerTarget(){const e=this.getExternalDrawerTarget(),t=e===this.menu?null:e;t!==this.externalDrawerTarget&&(this.externalDrawerTarget?.removeEventListener("drawer-opened",this.onMenuDrawerOpened),this.externalDrawerTarget?.removeEventListener("drawer-closed",this.onMenuDrawerClosed),this.externalDrawerTarget=t,this.externalDrawerTarget?.addEventListener("drawer-opened",this.onMenuDrawerOpened),this.externalDrawerTarget?.addEventListener("drawer-closed",this.onMenuDrawerClosed))}openNav(){const e=this.getBurgerFocusTarget(),t=this.getExternalDrawerTarget();if(this.burger&&(this.burger.menuOpen=!0),t){this.menuOpen=!0,t.openDrawer(e),document.body.classList.add("menu-open");return}if(this.menu){this.menu.sliding=!0,this.menuOpen=!0,this.menu.openDrawer(e),document.body.classList.add("menu-open");return}this.burger&&(this.burger.menuOpen=!1)}closeNav(){this.menuOpen=!1,this.burger&&(this.burger.menuOpen=!1);const e=this.getExternalDrawerTarget();if(e){e.closeDrawer(),document.body.classList.remove("menu-open");return}this.menu&&(this.menu.closeDrawer(),document.body.classList.remove("menu-open"))}get burger(){return this.menuButton.value??void 0}firstUpdated(e){if(super.firstUpdated(e),!this.menuContainer.value)return;const s=(this.menuContainer.value.firstElementChild?.assignedElements()??[])[0];s instanceof T?(this.menu=s,this.addMenuDrawerListeners()):s&&console.warn("<esp-header>: the menu slot expects an <esp-menu> element, received",s),this.observeMenuContainer(),this.syncExternalDrawerTarget(),this.syncMobileMenuQuery(),this.syncScrollListeners(),this.syncMenuLayout()}updated(e){super.updated(e),(e.has("showBurger")||e.has("drawerTarget")||e.has("menuDisplay")||e.has("layout"))&&(this.syncExternalDrawerTarget(),this.syncMenuLayout()),e.has("scrollBehavior")?this.syncScrollListeners():(e.has("scrollThreshold")||e.has("dockOffset"))&&this.updateScrollState()}connectedCallback(){super.connectedCallback(),this.syncScrollListeners(),this.syncMobileMenuQuery(),this.addMenuDrawerListeners(),this.syncExternalDrawerTarget(),this.observeMenuContainer()}disconnectedCallback(){this.removeMenuDrawerListeners(),this.externalDrawerTarget?.removeEventListener("drawer-opened",this.onMenuDrawerOpened),this.externalDrawerTarget?.removeEventListener("drawer-closed",this.onMenuDrawerClosed),this.externalDrawerTarget=null,this.mobileMenuQuery?.removeEventListener("change",this.handleMobileMenuQueryChange),this.mobileMenuQuery=null,this.removeScrollListeners(),this.cancelScrollUpdate(),this.disconnectResizeObserver(),super.disconnectedCallback()}renderConfiguredBrand(){if(!this.brandLogo&&!this.brandText)return c;const e=this.brandAlt||(this.brandText?"":"Site logo"),t=d`
1
+ var n=function(p,e,t,a){var s=arguments.length,i=s<3?e:a===null?a=Object.getOwnPropertyDescriptor(e,t):a,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")i=Reflect.decorate(p,e,t,a);else for(var h=p.length-1;h>=0;h--)(l=p[h])&&(i=(s<3?l(i):s>3?l(e,t,i):l(e,t))||i);return s>3&&i&&Object.defineProperty(e,t,i),i};import{css as y,html as d,nothing as c}from"lit";import{customElement as x,property as o,state as u}from"lit/decorators.js";import{classMap as M}from"lit/directives/class-map.js";import{styleMap as S}from"lit/directives/style-map.js";import"../burger/esp-burger.js";import{createRef as b,ref as f}from"lit/directives/ref.js";import{EspalierMenu as T}from"./esp-menu.js";import{EspalierElementBase as v}from"../shared/esp-element-base.js";const D="(max-width: 36rem)";let r=class extends v{constructor(){super(...arguments),this.menuOpen=!1,this.menuTooLarge=!1,this.mobileMenu=!1,this.scrolled=!1,this.hiddenByScroll=!1,this.scrollProgress=0,this.showBurger=!1,this.layout="standard",this.brandText="",this.brandLogo="",this.brandHref="",this.brandAlt="",this.brandColor="",this.brandAlign="start",this.brandWrap="truncate",this.menuDisplay="auto",this.themeToggle="hidden",this.scrollBehavior="none",this.scrollThreshold=16,this.dockOffset=0,this.drawerTarget="",this.fullBleedContent=!1,this.menuContainer=b(),this.menuButton=b(),this.menu=void 0,this.externalDrawerTarget=null,this.lastScrollY=0,this.lastInlineMenuWidth=0,this.mobileMenuQuery=null,this.menuDrawerListenersAttached=!1,this.observingMenuContainer=!1,this.scrollListenersAttached=!1,this.scrollRafId=null,this.resizeObserver=new ResizeObserver(()=>this.syncMenuLayout()),this.updateScrollState=()=>{this.scrollRafId===null&&(this.scrollRafId=requestAnimationFrame(()=>{this.scrollRafId=null,this.runScrollStateUpdate()}))},this.handleMobileMenuQueryChange=e=>{this.mobileMenu=e.matches,this.syncMenuLayout()},this.toggleTheme=()=>{const e=this.getThemeRoot();e&&(e.scheme=e.scheme==="dark"?"light":"dark")},this.handleMenuToggleClicked=()=>{if(this.menuOpen){this.closeNav();return}this.openNav()},this.onMenuDrawerOpened=()=>{this.menuOpen=!0,document.body.classList.add("menu-open"),this.burger&&(this.burger.menuOpen=!0)},this.onMenuDrawerClosed=()=>{this.menuOpen=!1,document.body.classList.remove("menu-open"),this.burger&&(this.burger.menuOpen=!1)}}syncMenuLayout(){if(!this.menuContainer.value||!this.menu||!this.menu.getWidth)return;const e=this.menuContainer.value.clientWidth,t=this.menu.getWidth();t>0&&(this.lastInlineMenuWidth=t);const a=this.lastInlineMenuWidth||t,s=this.getExternalDrawerTarget(),i=this.menuDisplay!=="inline",l=this.showBurger||this.menuDisplay==="drawer"||this.layout==="minimal";this.menuTooLarge=i&&this.menuDisplay==="auto"&&a>e,this.menu.sliding=i&&!s&&(this.menuTooLarge||l||this.mobileMenu)}getExternalDrawerTarget(){if(!this.drawerTarget)return null;const e=document.getElementById(this.drawerTarget);return e===this.menu?null:e&&"openDrawer"in e&&typeof e.openDrawer=="function"&&"closeDrawer"in e&&typeof e.closeDrawer=="function"?e:null}getBurgerFocusTarget(){const t=this.shadowRoot?.querySelector("esp-header-button.menu-toggle")?.shadowRoot?.querySelector("button"),a=this.menuButton.value?.shadowRoot?.querySelector("button");return t??a??null}getScrollTokens(){const e=this.scrollBehavior.split(/\s+/).map(t=>t.trim().toLowerCase()).filter(Boolean);return new Set(e.filter(t=>t!=="none"))}getEffectiveScrollThreshold(){return Number.isFinite(this.scrollThreshold)?Math.max(0,this.scrollThreshold):0}clearScrollState(){this.scrolled=!1,this.hiddenByScroll=!1,this.scrollProgress=0}runScrollStateUpdate(){const e=this.getScrollTokens();if(!e.size){this.clearScrollState();return}const t=Math.max(0,window.scrollY||document.documentElement.scrollTop||0),a=this.getEffectiveScrollThreshold(),s=Number.isFinite(this.dockOffset)?Math.max(0,this.dockOffset):a,i=t>(e.has("dock")?s:a),l=t>this.lastScrollY,h=e.has("reveal")&&l&&t>a&&!this.menuOpen;if(this.scrolled=i,this.hiddenByScroll=h,e.has("progress")){const m=document.documentElement,g=Math.max(1,m.scrollHeight-window.innerHeight);this.scrollProgress=Math.min(1,t/g)}else this.scrollProgress=0;this.lastScrollY=t}cancelScrollUpdate(){this.scrollRafId!==null&&(cancelAnimationFrame(this.scrollRafId),this.scrollRafId=null)}syncScrollListeners(){const e=this.getScrollTokens().size>0;if(e&&!this.scrollListenersAttached?(window.addEventListener("scroll",this.updateScrollState,{passive:!0}),window.addEventListener("resize",this.updateScrollState,{passive:!0}),this.scrollListenersAttached=!0):!e&&this.scrollListenersAttached&&this.removeScrollListeners(),e){this.updateScrollState();return}this.cancelScrollUpdate(),this.clearScrollState()}removeScrollListeners(){this.scrollListenersAttached&&(window.removeEventListener("scroll",this.updateScrollState),window.removeEventListener("resize",this.updateScrollState),this.scrollListenersAttached=!1)}addMenuDrawerListeners(){!this.menu||this.menuDrawerListenersAttached||(this.menu.addEventListener("drawer-opened",this.onMenuDrawerOpened),this.menu.addEventListener("drawer-closed",this.onMenuDrawerClosed),this.menuDrawerListenersAttached=!0)}removeMenuDrawerListeners(){!this.menu||!this.menuDrawerListenersAttached||(this.menu.removeEventListener("drawer-opened",this.onMenuDrawerOpened),this.menu.removeEventListener("drawer-closed",this.onMenuDrawerClosed),this.menuDrawerListenersAttached=!1)}observeMenuContainer(){!this.menuContainer.value||this.observingMenuContainer||(this.resizeObserver.observe(this.menuContainer.value),this.observingMenuContainer=!0)}disconnectResizeObserver(){this.observingMenuContainer&&(this.resizeObserver.disconnect(),this.observingMenuContainer=!1)}syncMobileMenuQuery(){if("matchMedia"in window){if(!this.mobileMenuQuery){this.mobileMenuQuery=window.matchMedia(D),this.mobileMenu=this.mobileMenuQuery.matches,this.mobileMenuQuery.addEventListener("change",this.handleMobileMenuQueryChange);return}this.mobileMenu=this.mobileMenuQuery.matches}}getThemeRoot(){return this.traverseToClosest("esp-root")}syncExternalDrawerTarget(){const e=this.getExternalDrawerTarget(),t=e===this.menu?null:e;t!==this.externalDrawerTarget&&(this.externalDrawerTarget?.removeEventListener("drawer-opened",this.onMenuDrawerOpened),this.externalDrawerTarget?.removeEventListener("drawer-closed",this.onMenuDrawerClosed),this.externalDrawerTarget=t,this.externalDrawerTarget?.addEventListener("drawer-opened",this.onMenuDrawerOpened),this.externalDrawerTarget?.addEventListener("drawer-closed",this.onMenuDrawerClosed))}openNav(){const e=this.getBurgerFocusTarget(),t=this.getExternalDrawerTarget();if(this.burger&&(this.burger.menuOpen=!0),t){this.menuOpen=!0,t.openDrawer(e),document.body.classList.add("menu-open");return}if(this.menu){this.menu.sliding=!0,this.menuOpen=!0,this.menu.openDrawer(e),document.body.classList.add("menu-open");return}this.burger&&(this.burger.menuOpen=!1)}closeNav(){this.menuOpen=!1,this.burger&&(this.burger.menuOpen=!1);const e=this.getExternalDrawerTarget();if(e){e.closeDrawer(),document.body.classList.remove("menu-open");return}this.menu&&(this.menu.closeDrawer(),document.body.classList.remove("menu-open"))}get burger(){return this.menuButton.value??void 0}firstUpdated(e){if(super.firstUpdated(e),!this.menuContainer.value)return;const s=(this.menuContainer.value.firstElementChild?.assignedElements()??[])[0];s instanceof T?(this.menu=s,this.addMenuDrawerListeners()):s&&console.warn("<esp-header>: the menu slot expects an <esp-menu> element, received",s),this.observeMenuContainer(),this.syncExternalDrawerTarget(),this.syncMobileMenuQuery(),this.syncScrollListeners(),this.syncMenuLayout()}updated(e){super.updated(e),(e.has("showBurger")||e.has("drawerTarget")||e.has("menuDisplay")||e.has("layout"))&&(this.syncExternalDrawerTarget(),this.syncMenuLayout()),e.has("scrollBehavior")?this.syncScrollListeners():(e.has("scrollThreshold")||e.has("dockOffset"))&&this.updateScrollState()}connectedCallback(){super.connectedCallback(),this.syncScrollListeners(),this.syncMobileMenuQuery(),this.addMenuDrawerListeners(),this.syncExternalDrawerTarget(),this.observeMenuContainer()}disconnectedCallback(){this.removeMenuDrawerListeners(),this.externalDrawerTarget?.removeEventListener("drawer-opened",this.onMenuDrawerOpened),this.externalDrawerTarget?.removeEventListener("drawer-closed",this.onMenuDrawerClosed),this.externalDrawerTarget=null,this.mobileMenuQuery?.removeEventListener("change",this.handleMobileMenuQueryChange),this.mobileMenuQuery=null,this.removeScrollListeners(),this.cancelScrollUpdate(),this.disconnectResizeObserver(),super.disconnectedCallback()}renderConfiguredBrand(){if(!this.brandLogo&&!this.brandText)return c;const e=this.brandAlt||(this.brandText?"":"Site logo"),t=d`
2
2
  ${this.brandLogo?d`<img class="brand-logo" src=${this.brandLogo} alt=${e} />`:c}
3
3
  ${this.brandText?d`<span class="brand-text">${this.brandText}</span>`:c}
4
- `;return this.brandHref?d`<a class="configured-brand" href=${this.brandHref}>${t}</a>`:d`<span class="configured-brand">${t}</span>`}render(){const{menuOpen:e,menuTooLarge:t,mobileMenu:o}=this,s=this.menuDisplay!=="inline",a=s&&(this.showBurger||this.menuDisplay==="drawer"||this.layout==="minimal"),i=this.getScrollTokens(),h=i.has("progress"),m={"--_esp-header-brand-color":this.brandColor||null,"--_esp-header-scroll-progress":String(this.scrollProgress)},g={"menu-open":e,"too-wide":s&&(t||o||a),[`layout-${this.layout}`]:!0,"is-scrolled":this.scrolled,"hide-on-scroll":this.hiddenByScroll,"scroll-compact":i.has("compact"),"scroll-elevate":i.has("elevate"),"scroll-transparent":i.has("transparent")||i.has("transparent-to-solid"),"scroll-collapse-topbar":i.has("collapse-topbar")},w=this.scheme==="dark"?"light":"dark";return d`
4
+ `;return this.brandHref?d`<a class="configured-brand" href=${this.brandHref}>${t}</a>`:d`<span class="configured-brand">${t}</span>`}render(){const{menuOpen:e,menuTooLarge:t,mobileMenu:a}=this,s=this.menuDisplay!=="inline",i=s&&(this.showBurger||this.menuDisplay==="drawer"||this.layout==="minimal"),l=this.getScrollTokens(),h=l.has("progress"),m={"--_esp-header-brand-color":this.brandColor||null,"--_esp-header-scroll-progress":String(this.scrollProgress)},g={"menu-open":e,"too-wide":s&&(t||a||i),[`layout-${this.layout}`]:!0,"is-scrolled":this.scrolled,"hide-on-scroll":this.hiddenByScroll,"scroll-compact":l.has("compact"),"scroll-elevate":l.has("elevate"),"scroll-transparent":l.has("transparent")||l.has("transparent-to-solid"),"scroll-collapse-topbar":l.has("collapse-topbar")},w=this.scheme==="dark"?"light":"dark";return d`
5
5
  <header class=${M(g)} style=${S(m)}>
6
6
  <section class="topbar">
7
7
  <slot name="topbar"></slot>
@@ -11,7 +11,7 @@ var n=function(p,e,t,o){var s=arguments.length,a=s<3?e:o===null?o=Object.getOwnP
11
11
  <slot name="brand">${this.renderConfiguredBrand()}</slot>
12
12
  </section>
13
13
 
14
- <section ${v(this.menuContainer)} class="menu-container">
14
+ <section ${f(this.menuContainer)} class="menu-container">
15
15
  <slot name="menu"></slot>
16
16
  </section>
17
17
 
@@ -31,12 +31,12 @@ var n=function(p,e,t,o){var s=arguments.length,a=s<3?e:o===null?o=Object.getOwnP
31
31
  aria-expanded=${e?"true":"false"}
32
32
  @clicked=${this.handleMenuToggleClicked}
33
33
  >
34
- <esp-burger ${v(this.menuButton)} presentation-only></esp-burger>
34
+ <esp-burger ${f(this.menuButton)} presentation-only></esp-burger>
35
35
  </esp-header-button>
36
36
  </section>
37
37
  ${h?d`<div class="scroll-progress" aria-hidden="true"></div>`:c}
38
38
  </header>
39
- `}};r.styles=[...f.styles,y`
39
+ `}};r.styles=[...v.styles,y`
40
40
  :host {
41
41
  --_esp-header-current-height: var(--esp-header-height, calc(4.5 * var(--esp-size-small)));
42
42
 
@@ -51,6 +51,14 @@ var n=function(p,e,t,o){var s=arguments.length,a=s<3?e:o===null?o=Object.getOwnP
51
51
  var(--esp-header-brand-color, var(--esp-color-headings))
52
52
  );
53
53
 
54
+
55
+ --_esp-header-content-surplus: max(
56
+ 0px,
57
+ calc(100% - var(--esp-header-content-max-width, 100%))
58
+ );
59
+ padding-inline: calc(var(--_esp-header-content-surplus) * var(--esp-header-content-lead, 0))
60
+ calc(var(--_esp-header-content-surplus) * (1 - var(--esp-header-content-lead, 0)));
61
+
54
62
  display: grid;
55
63
  grid-template-columns: minmax(0, max-content) minmax(0, 1fr) max-content;
56
64
  grid-template-rows: min-content var(--_esp-header-current-height);
@@ -349,6 +357,11 @@ var n=function(p,e,t,o){var s=arguments.length,a=s<3?e:o===null?o=Object.getOwnP
349
357
  }
350
358
  }
351
359
 
360
+
361
+ :host([full-bleed-content]) header {
362
+ padding-inline: 0;
363
+ }
364
+
352
365
  :host([brand-align="center"]) header section.brand {
353
366
  justify-content: center;
354
367
  text-align: center;
@@ -418,4 +431,4 @@ var n=function(p,e,t,o){var s=arguments.length,a=s<3?e:o===null?o=Object.getOwnP
418
431
  transition: none;
419
432
  }
420
433
  }
421
- `],n([u()],r.prototype,"menuOpen",void 0),n([u()],r.prototype,"menuTooLarge",void 0),n([u()],r.prototype,"mobileMenu",void 0),n([u()],r.prototype,"scrolled",void 0),n([u()],r.prototype,"hiddenByScroll",void 0),n([u()],r.prototype,"scrollProgress",void 0),n([l({attribute:"show-burger",type:Boolean})],r.prototype,"showBurger",void 0),n([l({type:String,reflect:!0})],r.prototype,"layout",void 0),n([l({attribute:"brand-text",type:String})],r.prototype,"brandText",void 0),n([l({attribute:"brand-logo",type:String})],r.prototype,"brandLogo",void 0),n([l({attribute:"brand-href",type:String})],r.prototype,"brandHref",void 0),n([l({attribute:"brand-alt",type:String})],r.prototype,"brandAlt",void 0),n([l({attribute:"brand-color",type:String})],r.prototype,"brandColor",void 0),n([l({attribute:"brand-align",type:String,reflect:!0})],r.prototype,"brandAlign",void 0),n([l({attribute:"brand-wrap",type:String,reflect:!0})],r.prototype,"brandWrap",void 0),n([l({attribute:"menu-display",type:String,reflect:!0})],r.prototype,"menuDisplay",void 0),n([l({attribute:"theme-toggle",type:String,reflect:!0})],r.prototype,"themeToggle",void 0),n([l({attribute:"scroll-behavior",type:String})],r.prototype,"scrollBehavior",void 0),n([l({attribute:"scroll-threshold",type:Number})],r.prototype,"scrollThreshold",void 0),n([l({attribute:"dock-offset",type:Number})],r.prototype,"dockOffset",void 0),n([l({attribute:"drawer-target",type:String})],r.prototype,"drawerTarget",void 0),r=n([x("esp-header")],r);export{r as EspalierHeader};
434
+ `],n([u()],r.prototype,"menuOpen",void 0),n([u()],r.prototype,"menuTooLarge",void 0),n([u()],r.prototype,"mobileMenu",void 0),n([u()],r.prototype,"scrolled",void 0),n([u()],r.prototype,"hiddenByScroll",void 0),n([u()],r.prototype,"scrollProgress",void 0),n([o({attribute:"show-burger",type:Boolean})],r.prototype,"showBurger",void 0),n([o({type:String,reflect:!0})],r.prototype,"layout",void 0),n([o({attribute:"brand-text",type:String})],r.prototype,"brandText",void 0),n([o({attribute:"brand-logo",type:String})],r.prototype,"brandLogo",void 0),n([o({attribute:"brand-href",type:String})],r.prototype,"brandHref",void 0),n([o({attribute:"brand-alt",type:String})],r.prototype,"brandAlt",void 0),n([o({attribute:"brand-color",type:String})],r.prototype,"brandColor",void 0),n([o({attribute:"brand-align",type:String,reflect:!0})],r.prototype,"brandAlign",void 0),n([o({attribute:"brand-wrap",type:String,reflect:!0})],r.prototype,"brandWrap",void 0),n([o({attribute:"menu-display",type:String,reflect:!0})],r.prototype,"menuDisplay",void 0),n([o({attribute:"theme-toggle",type:String,reflect:!0})],r.prototype,"themeToggle",void 0),n([o({attribute:"scroll-behavior",type:String})],r.prototype,"scrollBehavior",void 0),n([o({attribute:"scroll-threshold",type:Number})],r.prototype,"scrollThreshold",void 0),n([o({attribute:"dock-offset",type:Number})],r.prototype,"dockOffset",void 0),n([o({attribute:"drawer-target",type:String})],r.prototype,"drawerTarget",void 0),n([o({attribute:"full-bleed-content",type:Boolean,reflect:!0})],r.prototype,"fullBleedContent",void 0),r=n([x("esp-header")],r);export{r as EspalierHeader};
@@ -96,15 +96,33 @@ type HeaderPosition = "normal" | "sticky" | "fixed";
96
96
  * </esp-page>
97
97
  * ```
98
98
  *
99
- * @cssprop --esp-page-background - The background color of the page.
100
- * Defaults to `var(--esp-color-background)`.
99
+ * @cssprop --esp-page-background - The background color of the page. Fills
100
+ * both the surface and the canvas gutters; the canvas tokens paint over it
101
+ * in the gutters only. Defaults to `var(--esp-color-background)`.
101
102
  * @cssprop --esp-page-max-width - The maximum width of the main content
102
103
  * well. Set automatically by the `kind` attribute: `1536px` (wide),
103
- * `768px` (narrow), or `none` (full).
104
+ * `768px` (narrow), or `none` (full). This cap now sizes the main grid
105
+ * track; surplus width beyond it becomes the canvas gutters.
104
106
  * @cssprop --esp-page-background-image - The background image to
105
107
  * display behind page content. Defaults to `none`.
106
108
  * @cssprop --esp-page-background-image-opacity - The opacity of the
107
109
  * background image layer. Defaults to `1`.
110
+ * @cssprop --esp-page-canvas-background - The background color of the
111
+ * canvas gutters (the outer regions revealed when the viewport exceeds
112
+ * the cap). Defaults to `transparent`, so gutters match the page until
113
+ * styled and narrow viewports are unaffected.
114
+ * @cssprop --esp-page-canvas-background-image - A background image for the
115
+ * canvas gutters, mirroring the page background-image knob. Defaults to
116
+ * `none`.
117
+ * @cssprop --esp-page-canvas-background-image-opacity - The opacity of the
118
+ * canvas gutter image layer. Defaults to `1`.
119
+ * @cssprop --esp-page-surface-shadow - The box shadow drawn on the left
120
+ * and right edges of the content surface. On by default; casts into the
121
+ * gutters and is clipped away when the surface fills the viewport, so it
122
+ * only shows above the cap. Set to `none` to remove it.
123
+ * @cssprop --esp-page-surface-border - An optional border on the inline
124
+ * edges of the surface, for themes preferring a hairline over a shadow.
125
+ * Defaults to `none` (e.g. `1px solid var(--esp-color-border)`).
108
126
  * @cssprop --esp-page-fixed-header-offset - Offset reserved for fixed
109
127
  * headers. Defaults to `var(--esp-header-height)`.
110
128
  * @cssprop --esp-page-sticky-header-top - Top inset for sticky headers.
@@ -112,6 +130,9 @@ type HeaderPosition = "normal" | "sticky" | "fixed";
112
130
  * @cssprop --esp-page-header-z-index - Z-index for fixed/sticky header
113
131
  * regions. Defaults to `20`.
114
132
  *
133
+ * @csspart canvas - The two canvas gutter regions flanking the surface.
134
+ * @csspart surface - The surface backdrop carrying the edge shadow/border.
135
+ *
115
136
  * ```html
116
137
  * <style>
117
138
  * esp-page.with-background {
@@ -130,6 +151,29 @@ type HeaderPosition = "normal" | "sticky" | "fixed";
130
151
  * </esp-page>
131
152
  * ```
132
153
  *
154
+ * Use `align` to place the surface within the page once it hits its cap,
155
+ * and the canvas tokens to style the gutters. A low `--esp-page-max-width`
156
+ * is set here only so the gutters are visible inside the narrow demo
157
+ * frame; the surface edge shadow is on by default.
158
+ *
159
+ * ```html
160
+ * <style>
161
+ * esp-page.align-demo {
162
+ * --esp-page-max-width: 520px;
163
+ * --esp-page-canvas-background: var(--esp-color-layer-1);
164
+ * }
165
+ * </style>
166
+ * <esp-page class="docs align-demo" align="center">
167
+ * <div slot="header" style="background-color: red;">header</div>
168
+ * <div slot="sidebar" style="background-color: green;">sidebar</div>
169
+ * <div slot="right" style="background-color: purple;">right</div>
170
+ * <div slot="footer" style="background-color: blue;">footer</div>
171
+ * <div style="background-color: black; overflow: hidden;">
172
+ * content
173
+ * </div>
174
+ * </esp-page>
175
+ * ```
176
+ *
133
177
  * @docPageTitle Page
134
178
  * @docUrl /components/page
135
179
  * @menuGroup Structure
@@ -153,6 +197,38 @@ export declare class EspalierPage extends EspalierElementBase {
153
197
  * maps or design tools.
154
198
  */
155
199
  kind: "wide" | "narrow" | "full";
200
+ /**
201
+ * Horizontal alignment of the content **surface** (left aside + main
202
+ * well + right aside) within the page once the viewport is wider than
203
+ * the content cap. The surplus width becomes styleable **canvas**
204
+ * gutters on the outer edges, weighted by this attribute.
205
+ *
206
+ * - `start` (default) — the surface hugs the leading edge; all spare
207
+ * width collects in the trailing gutter. This reproduces today's
208
+ * layout.
209
+ * - `center` — spare width is split evenly into both gutters, centering
210
+ * the surface.
211
+ * - `end` — the surface hugs the trailing edge; spare width collects in
212
+ * the leading gutter.
213
+ *
214
+ * Has no effect when `kind="full"` (no cap means no gutters) or on
215
+ * viewports narrower than the cap (the surface already fills the width).
216
+ */
217
+ align: "start" | "center" | "end";
218
+ /**
219
+ * When set, the header and footer sit **on** the content surface —
220
+ * the same width as the left aside + main well + right aside — instead
221
+ * of spanning the full viewport. Combined with a styled canvas this
222
+ * frames the whole page as one contained band floating on the canvas,
223
+ * with a single continuous surface edge shadow running from the header
224
+ * through the content to the footer.
225
+ *
226
+ * Below the cap there are no gutters, so a contained page renders
227
+ * identically to the default full-bleed chrome. Designed for
228
+ * `header-position="normal"` or `"sticky"`; a fixed header cannot be
229
+ * banded to the surface.
230
+ */
231
+ contained: boolean;
156
232
  /**
157
233
  * Header positioning behavior for the `header` slot.
158
234
  *
@@ -1,5 +1,8 @@
1
- var n=function(s,e,i,o){var r=arguments.length,t=r<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,i):o,p;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")t=Reflect.decorate(s,e,i,o);else for(var d=s.length-1;d>=0;d--)(p=s[d])&&(t=(r<3?p(t):r>3?p(e,i,t):p(e,i))||t);return r>3&&t&&Object.defineProperty(e,i,t),t};import{css as c,html as f}from"lit";import{customElement as m,property as l}from"lit/decorators.js";import{classMap as u}from"lit/directives/class-map.js";import{createRef as v,ref as x}from"lit/directives/ref.js";import{EspalierElementBase as g}from"../shared/esp-element-base.js";import{BiDirectionalStickyController as h}from"./bi-directional-sticky-controller.js";import{getEspBus as y}from"../shared/bus-events.js";import"../toaster/esp-toaster.js";let a=class extends g{constructor(){super(),this.dialogZone=v(),this.kind="wide",this.headerPosition="normal",this.fixedMenus=!1,new h(this,".esp-page-left > .sticky-wrapper"),new h(this,".esp-page-right > .sticky-wrapper")}AddDialog(e){this.dialogZone.value?.appendChild(e)}updated(e){super.updated(e),(e.has("fixedMenus")||e.has("headerPosition"))&&y().publish("fixed-menus-changed",{fixed:this.fixedMenus||this.headerPosition==="fixed"})}render(){const e=this.fixedMenus||this.headerPosition==="fixed",i=!e&&this.headerPosition==="sticky";return f`
2
- <div part="wrapper" class="esp-page ${u({"fixed-menus":e,"fixed-header":e,"sticky-header":i})}">
1
+ var o=function(n,e,s,r){var d=arguments.length,a=d<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,s):r,p;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")a=Reflect.decorate(n,e,s,r);else for(var l=n.length-1;l>=0;l--)(p=n[l])&&(a=(d<3?p(a):d>3?p(e,s,a):p(e,s))||a);return d>3&&a&&Object.defineProperty(e,s,a),a};import{css as g,html as f}from"lit";import{customElement as u,property as i}from"lit/decorators.js";import{classMap as m}from"lit/directives/class-map.js";import{createRef as v,ref as w}from"lit/directives/ref.js";import{EspalierElementBase as h}from"../shared/esp-element-base.js";import{BiDirectionalStickyController as c}from"./bi-directional-sticky-controller.js";import{getEspBus as b}from"../shared/bus-events.js";import"../toaster/esp-toaster.js";let t=class extends h{constructor(){super(),this.dialogZone=v(),this.kind="wide",this.align="start",this.contained=!1,this.headerPosition="normal",this.fixedMenus=!1,new c(this,".esp-page-left > .sticky-wrapper"),new c(this,".esp-page-right > .sticky-wrapper")}AddDialog(e){this.dialogZone.value?.appendChild(e)}updated(e){super.updated(e),(e.has("fixedMenus")||e.has("headerPosition"))&&b().publish("fixed-menus-changed",{fixed:this.fixedMenus||this.headerPosition==="fixed"})}render(){const e=this.fixedMenus||this.headerPosition==="fixed",s=!e&&this.headerPosition==="sticky";return f`
2
+ <div part="wrapper" class="esp-page ${m({"fixed-menus":e,"fixed-header":e,"sticky-header":s})}">
3
+ <div part="canvas" class="esp-page-canvas esp-page-canvas--left" aria-hidden="true"></div>
4
+ <div part="canvas" class="esp-page-canvas esp-page-canvas--right" aria-hidden="true"></div>
5
+ <div part="surface" class="esp-page-surface" aria-hidden="true"></div>
3
6
  <div class="esp-page-top">
4
7
  <slot name="header"></slot>
5
8
  </div>
@@ -19,12 +22,17 @@ var n=function(s,e,i,o){var r=arguments.length,t=r<3?e:o===null?o=Object.getOwnP
19
22
  <footer>
20
23
  <slot name="footer"></slot>
21
24
  </footer>
22
- <div id="dialog-drop-zone" ${x(this.dialogZone)}></div>
25
+ <div id="dialog-drop-zone" ${w(this.dialogZone)}></div>
23
26
  <esp-toaster></esp-toaster>
24
27
  </div>
25
- `}};a.styles=[...g.styles,c`
28
+ `}};t.styles=[...h.styles,g`
26
29
  :host {
27
30
  --_esp-page-resolved-max-width: var(--esp-page-max-width, 1536px);
31
+
32
+ --_esp-page-main-track: minmax(0, var(--_esp-page-resolved-max-width));
33
+
34
+ --_esp-page-gutter-left: 0;
35
+ --_esp-page-gutter-right: 1fr;
28
36
  --_esp-page-fixed-header-offset: var(
29
37
  --esp-page-fixed-header-offset,
30
38
  var(--esp-header-height, calc(4.5 * var(--esp-size-small)))
@@ -37,8 +45,53 @@ var n=function(s,e,i,o){var r=arguments.length,t=r<3?e:o===null?o=Object.getOwnP
37
45
  --_esp-page-resolved-max-width: var(--esp-page-max-width, 768px);
38
46
  }
39
47
 
48
+ :host([align="center"]) {
49
+ --_esp-page-gutter-left: 1fr;
50
+ --_esp-page-gutter-right: 1fr;
51
+ }
52
+
53
+ :host([align="end"]) {
54
+ --_esp-page-gutter-left: 1fr;
55
+ --_esp-page-gutter-right: 0;
56
+ }
57
+
58
+
40
59
  :host([kind="full"]) {
41
60
  --_esp-page-resolved-max-width: var(--esp-page-max-width, none);
61
+ --_esp-page-main-track: 1fr;
62
+ --_esp-page-gutter-left: 0;
63
+ --_esp-page-gutter-right: 0;
64
+ }
65
+
66
+
67
+ slot[name="header"]::slotted(esp-header) {
68
+ --esp-header-content-max-width: var(--_esp-page-resolved-max-width);
69
+ --esp-header-content-lead: 0;
70
+ }
71
+
72
+ :host([align="center"]) slot[name="header"]::slotted(esp-header) {
73
+ --esp-header-content-lead: 0.5;
74
+ }
75
+
76
+ :host([align="end"]) slot[name="header"]::slotted(esp-header) {
77
+ --esp-header-content-lead: 1;
78
+ }
79
+
80
+
81
+ :host([kind="full"]) slot[name="header"]::slotted(esp-header) {
82
+ --esp-header-content-max-width: 100%;
83
+ }
84
+
85
+
86
+ :host([contained]) .esp-page > div.esp-page-top,
87
+ :host([contained]) .esp-page > footer {
88
+ grid-column: surface;
89
+ }
90
+
91
+
92
+ :host([contained]) slot[name="header"]::slotted(esp-header) {
93
+ --esp-header-content-max-width: 100%;
94
+ --esp-header-shadow: none;
42
95
  }
43
96
 
44
97
  :host([kind="narrow"]) .esp-page > div.esp-page-main {
@@ -57,10 +110,12 @@ var n=function(s,e,i,o){var r=arguments.length,t=r<3?e:o===null?o=Object.getOwnP
57
110
  min-height: 100vh;
58
111
  display: grid;
59
112
  grid-template-columns:
60
- [full-start left-start] min-content
61
- [left-end main-start] 1fr
113
+ [full-start canvas-left-start] var(--_esp-page-gutter-left)
114
+ [canvas-left-end surface-start left-start] min-content
115
+ [left-end main-start] var(--_esp-page-main-track)
62
116
  [main-end right-start] min-content
63
- [right-end full-end];
117
+ [right-end surface-end canvas-right-start] var(--_esp-page-gutter-right)
118
+ [canvas-right-end full-end];
64
119
  grid-template-rows:
65
120
  [top-start] min-content
66
121
  [top-end content-start] 1fr
@@ -113,7 +168,7 @@ var n=function(s,e,i,o){var r=arguments.length,t=r<3?e:o===null?o=Object.getOwnP
113
168
  grid-row: content;
114
169
  position: relative;
115
170
  overflow: hidden;
116
- max-width: var(--_esp-page-resolved-max-width);
171
+
117
172
  contain: inline-size;
118
173
  }
119
174
 
@@ -122,6 +177,48 @@ var n=function(s,e,i,o){var r=arguments.length,t=r<3?e:o===null?o=Object.getOwnP
122
177
  }
123
178
 
124
179
 
180
+ > .esp-page-canvas {
181
+
182
+ grid-row: top-start / footer-end;
183
+ z-index: 1;
184
+ position: relative;
185
+ pointer-events: none;
186
+ background-color: var(--esp-page-canvas-background, transparent);
187
+
188
+
189
+ &::before {
190
+ content: "";
191
+ position: absolute;
192
+ inset: 0;
193
+ background-image: var(--esp-page-canvas-background-image, none);
194
+ opacity: var(--esp-page-canvas-background-image-opacity, 1);
195
+ }
196
+ }
197
+
198
+ > .esp-page-canvas--left {
199
+ grid-column: canvas-left;
200
+ }
201
+
202
+ > .esp-page-canvas--right {
203
+ grid-column: canvas-right;
204
+ }
205
+
206
+
207
+ > .esp-page-surface {
208
+ grid-column: surface;
209
+
210
+ grid-row: top-start / footer-end;
211
+ z-index: 2;
212
+ pointer-events: none;
213
+ box-shadow: var(
214
+ --esp-page-surface-shadow,
215
+ -0.75rem 0 1.5rem -0.75rem var(--esp-color-shadow),
216
+ 0.75rem 0 1.5rem -0.75rem var(--esp-color-shadow)
217
+ );
218
+ border-inline: var(--esp-page-surface-border, none);
219
+ }
220
+
221
+
125
222
  .sticky-wrapper {
126
223
  will-change: top;
127
224
  display: block;
@@ -166,7 +263,9 @@ var n=function(s,e,i,o){var r=arguments.length,t=r<3?e:o===null?o=Object.getOwnP
166
263
 
167
264
  > div.esp-page-main,
168
265
  > aside.esp-page-left,
169
- > aside.esp-page-right {
266
+ > aside.esp-page-right,
267
+ > .esp-page-surface,
268
+ > .esp-page-canvas {
170
269
  margin-top: var(--_esp-page-fixed-header-offset);
171
270
  }
172
271
  }
@@ -194,4 +293,4 @@ var n=function(s,e,i,o){var r=arguments.length,t=r<3?e:o===null?o=Object.getOwnP
194
293
  .esp-page:has(esp-dialog[is-open="true"]) {
195
294
  overflow: hidden;
196
295
  }
197
- `],n([l({reflect:!0})],a.prototype,"kind",void 0),n([l({attribute:"header-position",reflect:!0})],a.prototype,"headerPosition",void 0),n([l({attribute:"fixed-menus",type:Boolean,reflect:!0})],a.prototype,"fixedMenus",void 0),a=n([m("esp-page")],a);export{a as EspalierPage};
296
+ `],o([i({reflect:!0})],t.prototype,"kind",void 0),o([i({reflect:!0})],t.prototype,"align",void 0),o([i({type:Boolean,reflect:!0})],t.prototype,"contained",void 0),o([i({attribute:"header-position",reflect:!0})],t.prototype,"headerPosition",void 0),o([i({attribute:"fixed-menus",type:Boolean,reflect:!0})],t.prototype,"fixedMenus",void 0),t=o([u("esp-page")],t);export{t as EspalierPage};
@@ -842,6 +842,18 @@
842
842
  "component": "esp-header",
843
843
  "description": "The height of compact scroll-reactive headers. Defaults to `max(44px, calc(3.5 * var(--esp-size-small)))`."
844
844
  },
845
+ {
846
+ "name": "--esp-header-content-lead",
847
+ "category": "component",
848
+ "component": "esp-header",
849
+ "description": "Surface-alignment contract set by `esp-page`: the fraction of the leftover width placed before the content, aligning it (`0` = start, `0.5` = center, `1` = end). Defaults to `0`."
850
+ },
851
+ {
852
+ "name": "--esp-header-content-max-width",
853
+ "category": "component",
854
+ "component": "esp-header",
855
+ "description": "Surface-alignment contract set by `esp-page`: the maximum width the bar content is constrained to (the bar background stays full-bleed). Defaults to `100%` (no constraint). `esp-page` sets this to its resolved content cap."
856
+ },
845
857
  {
846
858
  "name": "--esp-header-extended-menu-border",
847
859
  "category": "component",
@@ -1219,7 +1231,7 @@
1219
1231
  "name": "--esp-page-background",
1220
1232
  "category": "component",
1221
1233
  "component": "esp-page",
1222
- "description": "The background color of the page. Defaults to `var(--esp-color-background)`."
1234
+ "description": "The background color of the page. Fills both the surface and the canvas gutters; the canvas tokens paint over it in the gutters only. Defaults to `var(--esp-color-background)`."
1223
1235
  },
1224
1236
  {
1225
1237
  "name": "--esp-page-background-image",
@@ -1231,6 +1243,24 @@
1231
1243
  "category": "root-theme",
1232
1244
  "description": "The opacity of the background image layer. Defaults to `1`."
1233
1245
  },
1246
+ {
1247
+ "name": "--esp-page-canvas-background",
1248
+ "category": "component",
1249
+ "component": "esp-page",
1250
+ "description": "The background color of the canvas gutters (the outer regions revealed when the viewport exceeds the cap). Defaults to `transparent`, so gutters match the page until styled and narrow viewports are unaffected."
1251
+ },
1252
+ {
1253
+ "name": "--esp-page-canvas-background-image",
1254
+ "category": "component",
1255
+ "component": "esp-page",
1256
+ "description": "A background image for the canvas gutters, mirroring the page background-image knob. Defaults to `none`."
1257
+ },
1258
+ {
1259
+ "name": "--esp-page-canvas-background-image-opacity",
1260
+ "category": "component",
1261
+ "component": "esp-page",
1262
+ "description": "The opacity of the canvas gutter image layer. Defaults to `1`."
1263
+ },
1234
1264
  {
1235
1265
  "name": "--esp-page-fixed-header-offset",
1236
1266
  "category": "component",
@@ -1247,7 +1277,7 @@
1247
1277
  "name": "--esp-page-max-width",
1248
1278
  "category": "component",
1249
1279
  "component": "esp-page",
1250
- "description": "The maximum width of the main content well. Set automatically by the `kind` attribute: `1536px` (wide), `768px` (narrow), or `none` (full)."
1280
+ "description": "The maximum width of the main content well. Set automatically by the `kind` attribute: `1536px` (wide), `768px` (narrow), or `none` (full). This cap now sizes the main grid track; surplus width beyond it becomes the canvas gutters."
1251
1281
  },
1252
1282
  {
1253
1283
  "name": "--esp-page-sticky-header-top",
@@ -1255,6 +1285,18 @@
1255
1285
  "component": "esp-page",
1256
1286
  "description": "Top inset for sticky headers. Defaults to `0`."
1257
1287
  },
1288
+ {
1289
+ "name": "--esp-page-surface-border",
1290
+ "category": "component",
1291
+ "component": "esp-page",
1292
+ "description": "An optional border on the inline edges of the surface, for themes preferring a hairline over a shadow. Defaults to `none` (e.g. `1px solid var(--esp-color-border)`)."
1293
+ },
1294
+ {
1295
+ "name": "--esp-page-surface-shadow",
1296
+ "category": "component",
1297
+ "component": "esp-page",
1298
+ "description": "The box shadow drawn on the left and right edges of the content surface. On by default; casts into the gutters and is clipped away when the surface fills the viewport, so it only shows above the cap. Set to `none` to remove it."
1299
+ },
1258
1300
  {
1259
1301
  "name": "--esp-progress-border-color",
1260
1302
  "category": "component",
@@ -14,6 +14,8 @@ removing, or replacing non-code assets.
14
14
  | `dist/shared/virtualizer/**` | Vendored Lit Virtualizer runtime source compiled into Espalier's package. | `licenses/THIRD_PARTY_NOTICES.md` |
15
15
  | Brand favicons/logos | Taproot-owned Espalier brand assets. | None |
16
16
  | Demo textures | Taproot-owned generated PNG textures created for this repository. | None |
17
+ | `assets/canvas-bg.jpg` | Docs-only light canvas texture — Envato Elements item "Seamless Pattern Design With Colorful Flowers" by yusufdemirci; certificate `licenses/license_certificate_A2BVZ6Y9DN.pdf`; attribution not required; kept out of the published `@taprootio/espalier` package. | None |
18
+ | `assets/canvas-bg-dark.jpg` | Docs-only dark canvas texture — Envato Elements item "Nocturnal Garden Pattern" by Webvilla; certificate `licenses/license_certificate_HF5ZVPRNC2.pdf`; attribution not required; kept out of the published package. | None |
17
19
  | Demo JSON data | Taproot-authored fictitious samples or standards-derived factual color data. | None |
18
20
 
19
21
  ## Texture Replacement
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "updatedAt": "2026-06-30",
3
+ "updatedAt": "2026-07-11",
4
4
  "entries": [
5
5
  {
6
6
  "id": "google-font-preview-assets",
@@ -211,6 +211,44 @@
211
211
  "noticeRequirement": "none",
212
212
  "noticePaths": [],
213
213
  "reviewStatus": "documented"
214
+ },
215
+ {
216
+ "id": "envato-canvas-background-texture",
217
+ "paths": [
218
+ "assets/canvas-bg.jpg"
219
+ ],
220
+ "assetType": "decorative floral background texture (JPEG, 400x400 seamless tile)",
221
+ "classification": "third-party licensed",
222
+ "owner": "Envato Elements author \"yusufdemirci\" retains ownership; licensed to Jereme Evans / Taproot under an Envato Elements subscription",
223
+ "source": "Envato Elements item \"Seamless Pattern Design With Colorful Flowers\" (item id ab0dc3dd-7d36-44be-9898-d148173189da, https://app.envato.com/item/ab0dc3dd-7d36-44be-9898-d148173189da), downloaded 2026-07-11 under an active subscription. License certificate A2BVZ6Y9DN on file at licenses/license_certificate_A2BVZ6Y9DN.pdf.",
224
+ "license": "Envato Elements subscription license (certificate A2BVZ6Y9DN): broad commercial use permitted and attribution is not required for this use. The author retains ownership; the item (or any product using it) may not be trademarked or claimed as Taproot-owned, and it must not be redistributed so that others can extract it. Valid only while the Envato subscription remains active.",
225
+ "transformations": [
226
+ "None; used as-is as a repeating docs-site canvas gutter background at 50% image-layer opacity"
227
+ ],
228
+ "packageInclusion": "not included in npm package",
229
+ "docsInclusion": "docs-site only — referenced as --esp-page-canvas-background-image in css/docs.css (which the public @taprootio/espalier package excludes) and served from the Eleventy /assets passthrough",
230
+ "noticeRequirement": "none",
231
+ "noticePaths": [],
232
+ "reviewStatus": "documented"
233
+ },
234
+ {
235
+ "id": "envato-canvas-background-texture-dark",
236
+ "paths": [
237
+ "assets/canvas-bg-dark.jpg"
238
+ ],
239
+ "assetType": "decorative dark botanical background texture (JPEG, 500x500 seamless tile)",
240
+ "classification": "third-party licensed",
241
+ "owner": "Envato Elements author \"Webvilla\" retains ownership; licensed to Jereme Evans / Taproot under an Envato Elements subscription",
242
+ "source": "Envato Elements item \"Nocturnal Garden Pattern\" (item id df520f04-5dfb-41c3-aa87-2ce3c03c8c34, https://app.envato.com/item/df520f04-5dfb-41c3-aa87-2ce3c03c8c34), downloaded 2026-07-11 under an active subscription as the dark-mode counterpart to canvas-bg.jpg. License certificate HF5ZVPRNC2 on file at licenses/license_certificate_HF5ZVPRNC2.pdf.",
243
+ "license": "Envato Elements subscription license (certificate HF5ZVPRNC2), same terms as canvas-bg.jpg: broad commercial use permitted and attribution not required; author retains ownership, no trademark/ownership claims, no redistribution for extraction, valid only while the subscription is active.",
244
+ "transformations": [
245
+ "None; used as-is as a repeating docs-site dark-mode canvas gutter background at 50% image-layer opacity"
246
+ ],
247
+ "packageInclusion": "not included in npm package",
248
+ "docsInclusion": "docs-site only — referenced as --esp-page-canvas-background-image under esp-root[scheme=\"dark\"] in css/docs.css (excluded from the public @taprootio/espalier package) and served from the Eleventy /assets passthrough",
249
+ "noticeRequirement": "none",
250
+ "noticePaths": [],
251
+ "reviewStatus": "documented"
214
252
  }
215
253
  ]
216
254
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taprootio/espalier",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "description": "Espalier — a themeable, accessible, framework-agnostic, enterprise-grade design system built on web standards and love.",
5
5
  "customElements": "custom-elements.json",
6
6
  "type": "module",