@taprootio/espalier 4.12.0 → 4.13.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.
@@ -71,6 +71,19 @@ export interface EspalierMenuDrawerBrand extends ConfiguredBrandOptions {
71
71
  * </esp-header>
72
72
  * ```
73
73
  *
74
+ * Top-level items in the full-screen panel keep `--esp-menu-drawer-item-font-size`.
75
+ * Items and groups nested inside a group share one smaller size, chosen so the
76
+ * widest nested label fits the viewport on a single line: it starts at
77
+ * `--esp-menu-drawer-nested-item-max-font-size` (90% of the top-level size)
78
+ * and shrinks only as far as that label needs, never below
79
+ * `--esp-menu-drawer-nested-item-min-font-size` (14px, or 0.875rem when the
80
+ * reader's default font is larger). When the floor still cannot fit the widest
81
+ * label, nested labels wrap instead of clipping. The size is measured against
82
+ * hidden probes once the page is idle after mounting — never on the first
83
+ * paint — and again when the viewport resizes, the slotted items change, or
84
+ * web fonts finish loading; a panel opened before the idle pass measures on
85
+ * the spot.
86
+ *
74
87
  * @customElement esp-menu
75
88
  * @slot - `esp-menu-item` and `esp-menu-group` children.
76
89
  * @slot drawer-brand - Custom brand markup for the full-screen drawer. When empty, the brand an owning `esp-header` mirrors in renders instead.
@@ -86,6 +99,8 @@ export interface EspalierMenuDrawerBrand extends ConfiguredBrandOptions {
86
99
  * @cssprop --esp-menu-drawer-shadow - Box shadow for the drawer overlay.
87
100
  * @cssprop --esp-menu-drawer-width - Drawer width. Defaults to `min(22rem, 86vw)`.
88
101
  * @cssprop --esp-menu-drawer-item-font-size - Item label size in the full-screen drawer. Defaults to `var(--esp-type-large)`.
102
+ * @cssprop --esp-menu-drawer-nested-item-max-font-size - Largest size for labels nested inside a group in the full-screen drawer; the measured fit starts here. Defaults to `calc(0.9 * var(--esp-menu-drawer-item-font-size, var(--esp-type-large)))`.
103
+ * @cssprop --esp-menu-drawer-nested-item-min-font-size - Smallest size nested full-screen drawer labels shrink to before they wrap. Defaults to `max(14px, 0.875rem)`: above the ~12-13px critical print size at phone distance (Legge & Bigelow, 2011) and Material's 14sp body minimum, and it rises with a larger default font.
89
104
  * @cssprop --esp-menu-drawer-transition-duration - Duration of the full-screen drawer's transition. Defaults to `0.3s`; reduced motion disables it.
90
105
  * @cssprop --esp-menu-drawer-brand-logo-size - Logo height of the brand centered in the full-screen drawer. Defaults to `calc(3 * var(--esp-size-medium))`.
91
106
  * @cssprop --esp-menu-drawer-brand-color - Text and logo color of the full-screen drawer's brand. Defaults to the mirrored brand color, then `var(--esp-color-headings)`.
@@ -1,28 +1,28 @@
1
- var l=function(w,e,r,i){var t=arguments.length,o=t<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,r):i,s;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(w,e,r,i);else for(var a=w.length-1;a>=0;a--)(s=w[a])&&(o=(t<3?s(o):t>3?s(e,r,o):s(e,r))||o);return t>3&&o&&Object.defineProperty(e,r,o),o},f;import{css as k,html as c,nothing as u}from"lit";import{customElement as M,property as d,state as y}from"lit/decorators.js";import{classMap as S}from"lit/directives/class-map.js";import{unsafeHTML as T}from"lit/directives/unsafe-html.js";import{createRef as m,ref as g}from"lit/directives/ref.js";import{styleMap as z}from"lit/directives/style-map.js";import{EspalierElementBase as E}from"../shared/esp-element-base.js";import{ESP_EVENTS as v}from"../shared/events.js";import{getEspBus as _}from"../shared/bus-events.js";import{normalizePath as $,pathStartsWithSegment as D,pathsMatch as x}from"../shared/path-matching.js";import{renderConfiguredBrand as F}from"../shared/configured-brand.js";import{FOCUSABLE_SELECTOR as A,OverlayController as C}from"../shared/overlay-controller.js";import{SwipeRevealController as L}from"./swipe-reveal-controller.js";import"./esp-menu-item.js";import"./esp-menu-group.js";import"../burger/esp-burger.js";import{EspalierMenuItem as O}from"./esp-menu-item.js";import{EspalierMenuGroup as b}from"./esp-menu-group.js";import{COMPACT_VIEWPORT_MEDIA_QUERY as I}from"../shared/responsive.js";const G=new Set(["panel","full-screen"]),N=new Set(["fade","slide-down","slide-up","slide-left","slide-right"]);let n=f=class extends E{ownsDrawerLock(){return this.isFullScreenDrawer}fullScreenInertAnchor(){return f.inertAnchorFor(this)}static inertAnchorFor(e){let r=e,i=e;for(;;){const t=i.parentElement;if(t){if(t.localName==="esp-page"||t.localName==="esp-root")return i;t===document.body&&(r=i),i=t;continue}const o=i.getRootNode();if(o instanceof ShadowRoot&&o.host instanceof HTMLElement){i=o.host;continue}return r}}constructor(){super(),this.itemsSlot=m(),this.railRef=m(),this.scrimRef=m(),this.drawerRef=m(),this.bus=_(),this.closeTransitionTimer=null,this.drawerGroupOpenOverrides=new Map,this.overlay=new C({host:this,getFocusTrapContainer:()=>this.drawerRef.value??null,getFocusScope:()=>this.fullScreenFocusScope(),getInertAnchor:()=>this.fullScreenInertAnchor(),promote:!1,scrollLock:{preserveScrollPosition:!0}}),this.fullScreenSession=!1,this.openedFullScreen=!1,this.drawerKeydownAttached=!1,this.onOverlayOpened=e=>{if(e===this.overlay||!this.drawerOpen)return;const r=this.drawerTrigger;this.drawerTrigger=null,r&&e.redirectFocusRestore(r),this.swipeController.closeForHandoff(),this.onDrawerTransitionEnd()},this._sliding=!1,this._mobileCollapsed=!1,this.verticalDrawerQuery=null,this.onVerticalDrawerChange=e=>this.setMobileCollapsed(e.matches),this.mode="horizontal",this.overflow="auto",this.side="left",this.drawerPresentation="panel",this.fullScreenTransition="fade",this.drawerBrand=null,this.liftedCloseControl=null,this.ariaLabel=null,this.autoExpand=!1,this.drawerOpen=!1,this.drawerShown=!1,this.drawerTransitioning=!1,this.drawerTrigger=null,this.hasExternalDrawerControl=!1,this.previewCollapseRequested=!1,this.getWidth=()=>{const e=this.railRef.value;return e?Math.max(e.scrollWidth,e.clientWidth):-1},this.onDrawerKeydown=e=>{!this.drawerOpen||!this.openedFullScreen||e.key==="Tab"&&this.overlay.trapFocus(e)},this.onDrawerTransitionEnd=e=>{e&&e.target!==this.drawerRef.value||(this.closeTransitionTimer&&(clearTimeout(this.closeTransitionTimer),this.closeTransitionTimer=null),this.drawerTransitioning=!1,this.drawerOpen||(this.hideDrawerPopover(),this.drawerGroupOpenOverrides.clear()))},this.handleDrawerCloseClick=()=>{this.closeDrawer()},this.swipeController=new L(this,this.side),this.swipeController.enabled=!1}get isFullScreenDrawer(){return G.has(this.drawerPresentation)?this.drawerPresentation==="full-screen":!1}get resolvedFullScreenTransition(){return N.has(this.fullScreenTransition)?this.fullScreenTransition:"fade"}get sliding(){return this._sliding}set sliding(e){const r=this._sliding;this._sliding=e,this.syncSwipeEnabled(),this.propagateToItems(),this.requestUpdate("sliding",r)}get collapsed(){return this.drawerActive}set collapsed(e){e?this.mode="drawer":this.mode==="drawer"&&(this.mode="vertical")}get drawerSide(){return this.overflow==="right-drawer"?"right":this.overflow==="left-drawer"?"left":this.side}get drawerActive(){return this.mode==="drawer"||this._sliding||this.overflow==="left-drawer"||this.overflow==="right-drawer"||this.mode==="vertical"&&(this._mobileCollapsed||this.previewCollapseRequested)&&this.hasExternalDrawerControl}get railMode(){return this.mode==="horizontal"?"horizontal":"vertical"}connectedCallback(){super.connectedCallback(),this.getAttribute("slot")==="right"&&(this.side="right"),!this.verticalDrawerQuery&&typeof window<"u"&&"matchMedia"in window&&(this.verticalDrawerQuery=window.matchMedia(I),this._mobileCollapsed=this.verticalDrawerQuery.matches,this.verticalDrawerQuery.addEventListener("change",this.onVerticalDrawerChange)),this.syncSwipeEnabled(),C.addOpenListener(this.onOverlayOpened)}disconnectedCallback(){C.removeOpenListener(this.onOverlayOpened),this.verticalDrawerQuery?.removeEventListener("change",this.onVerticalDrawerChange),this.verticalDrawerQuery=null,this.detachDrawerKeydown(),this.fullScreenSession=!1,super.disconnectedCallback()}setMobileCollapsed(e){e!==this._mobileCollapsed&&(this._mobileCollapsed=e,this.mode==="vertical"&&this.applyMobileCollapse())}applyMobileCollapse(){this.swipeController.direction=this.drawerSide,this.syncSwipeEnabled(),this.propagateToItems(),this.requestUpdate(),!this.drawerActive&&this.drawerOpen&&this.swipeController.close(!0)}firstUpdated(e){super.firstUpdated(e),this.propagateToItems()}updated(e){super.updated(e),(e.has("mode")||e.has("overflow")||e.has("side")||e.has("hasExternalDrawerControl")||e.has("previewCollapseRequested"))&&(this.swipeController.direction=this.drawerSide,this.syncSwipeEnabled(),this.propagateToItems(),!this.drawerActive&&this.drawerOpen&&this.swipeController.close(!0)),this.drawerOpen&&this.openedFullScreen!==this.isFullScreenDrawer&&this.swipeController.close(!0),this.autoExpand&&(e.has("autoExpand")||e.has("mode")&&this.mode!=="horizontal")?this.expandToCurrentPage():this.mode==="horizontal"&&e.has("mode")&&this.closeHorizontalTopLevelGroups()}openDrawer(e){this.drawerActive&&(e?this.drawerTrigger=e:this.drawerOpen||(this.drawerTrigger=null),this.swipeController.open())}closeDrawer(){this.swipeController.close(!0)}toggleDrawer(e){this.drawerOpen?this.closeDrawer():this.openDrawer(e)}toggleOpened(){this.toggleDrawer()}get isDrawerOpen(){return this.drawerOpen}syncSwipeEnabled(){this.swipeController.direction=this.drawerSide,this.swipeController.enabled=this.drawerActive}getAssignedChildren(){return this.itemsSlot.value?.assignedElements()??[]}propagateToItems(){const e=this.railMode;for(const r of this.getAssignedChildren())r instanceof O?(r.mode=e,r.depth=0,r.touchDevice=this.swipeController.isTouch):r instanceof b&&(r.mode=e,r.depth=0,r.touchDevice=this.swipeController.isTouch)}handleSlotChange(){this.propagateToItems()}onSwipeRevealChanged(e){e!==this.drawerOpen&&(this.drawerOpen=e,e?(this.openedFullScreen=this.isFullScreenDrawer,this.drawerGroupOpenOverrides.clear(),this.bus.publish("close-popovers",{}),this.updateComplete.then(()=>this.showDrawerPopover())):(this.detachDrawerKeydown(),this.fullScreenSession&&(this.fullScreenSession=!1,this.overlay.close()),this.drawerShown=!1,this.drawerTransitioning=!0,this.updateComplete.then(()=>this.startCloseTransition()),requestAnimationFrame(()=>this.restoreDrawerTriggerFocus())),this.dispatchEvent(new CustomEvent(e?v.MENU_DRAWER_OPENED:v.MENU_DRAWER_CLOSED,{bubbles:!0,composed:!0})))}showDrawerPopover(){const e=this.scrimRef.value,r=this.drawerRef.value;if(!(!e||!r||!this.isConnected)){this.swipeController.drawerElement=r;try{this.openedFullScreen||e.showPopover(),r.showPopover()}catch{}this.dispatchEvent(new CustomEvent(v.MENU_DRAWER_PRESENTED,{bubbles:!0,composed:!0})),r.getBoundingClientRect(),requestAnimationFrame(()=>{!this.drawerOpen||!this.isConnected||(this.drawerTransitioning=!0,this.drawerShown=!0,this.openedFullScreen&&(this.fullScreenSession=!0,this.overlay.open(),this.attachDrawerKeydown(),this.updateComplete.then(()=>{this.drawerOpen&&this.overlay.moveFocusInto()})))})}}attachDrawerKeydown(){this.drawerKeydownAttached||(document.addEventListener("keydown",this.onDrawerKeydown),this.drawerKeydownAttached=!0)}detachDrawerKeydown(){this.drawerKeydownAttached&&(document.removeEventListener("keydown",this.onDrawerKeydown),this.drawerKeydownAttached=!1)}fullScreenFocusScope(){const e=this.drawerRef.value;if(!e)return[];const r=s=>s instanceof HTMLElement&&s.getClientRects().length>0,i=[],t=s=>{if(s.matches(A)&&r(s)&&i.push(s),s.shadowRoot)for(const a of s.shadowRoot.querySelectorAll(A))r(a)&&i.push(a)};for(const s of e.querySelectorAll("*"))if(t(s),s instanceof HTMLSlotElement)for(const a of s.assignedElements({flatten:!0})){t(a);for(const p of a.querySelectorAll("*"))t(p)}const o=this.liftedCloseControl;if(o?.isConnected){const s=o.shadowRoot?.querySelector("button")??o;r(s)&&i.push(s)}return i}static drawerTransitionMs(e){const r=getComputedStyle(e),i=a=>a.split(",").map(p=>p.trim()).filter(Boolean).map(p=>{const h=Number.parseFloat(p);return Number.isFinite(h)?p.endsWith("ms")?h:h*1e3:0}),t=i(r.transitionDuration),o=i(r.transitionDelay);let s=0;return t.forEach((a,p)=>{s=Math.max(s,a+(o[p%Math.max(o.length,1)]??0))}),s}startCloseTransition(){const e=this.drawerRef.value;if(!e){this.hideDrawerPopover();return}this.closeTransitionTimer&&clearTimeout(this.closeTransitionTimer);const r=f.drawerTransitionMs(e);if(r===0){this.onDrawerTransitionEnd();return}this.closeTransitionTimer=setTimeout(()=>{this.closeTransitionTimer=null,!this.drawerOpen&&this.drawerTransitioning&&this.onDrawerTransitionEnd()},r+50)}hideDrawerPopover(){const e=this.scrimRef.value,r=this.drawerRef.value;this.swipeController.drawerElement=null,r&&(r.style.cssText="");try{r?.hidePopover()}catch{}try{e?.hidePopover()}catch{}}restoreDrawerTriggerFocus(){const e=this.drawerTrigger;this.drawerTrigger=null,e?.isConnected&&e.focus({preventScroll:!0})}getAutoExpandedGroups(e=!0){const r=new Set;let i=null;for(const o of this.querySelectorAll("esp-menu-item")){const s=o.url||o.getAttribute("url");if(s&&x(s)){i=o;break}}if(!i)for(const o of this.querySelectorAll("esp-menu-group")){const s=o.url||o.getAttribute("url");if(s&&x(s)){i=o;break}}if(!i&&e){for(const o of this.querySelectorAll("esp-menu-group"))o.parentElement===this&&r.add(o);return r}if(!i)return r;i instanceof b&&r.add(i);let t=i.parentElement;for(;t&&t!==this;)t instanceof b&&r.add(t),t=t.parentElement;return r}isHorizontalTopLevelGroup(e){return e.mode==="horizontal"&&e.depth===0}groupUrlPrefixMatches(e){return D(location.pathname,e.urlPrefix)}groupPathMatches(e){if(this.groupUrlPrefixMatches(e))return!0;const r=e.url||e.getAttribute("url");return r?D(location.pathname,$(r)):!1}expandToCurrentPage(){const e=this.getAutoExpandedGroups(),r=this.querySelectorAll("esp-menu-group");for(const i of r)i.open=e.has(i)&&!this.isHorizontalTopLevelGroup(i)}closeHorizontalTopLevelGroups(){for(const e of this.querySelectorAll("esp-menu-group"))this.isHorizontalTopLevelGroup(e)&&(e.open=!1)}getDrawerAutoExpandedGroups(){return this.getAutoExpandedGroups(!1)}collectDrawerNodes(e,r=this.getDrawerAutoExpandedGroups()){const i=[];for(const t of e)if(t instanceof O){const o=t.querySelector(":scope > svg, :scope > img");i.push({kind:"item",label:t.label,url:t.url,open:!1,icon:t.icon,iconHtml:o?.outerHTML||"",children:[],originalItem:t,originalGroup:null})}else if(t instanceof b){const o=t.querySelector(':scope > [slot="icon"]'),s=r.has(t)||this.groupPathMatches(t),a=this.drawerGroupOpenOverrides.get(t)??(t.open||s);i.push({kind:"group",label:t.label,url:t.url||"",open:a,icon:t.icon,iconHtml:o?.outerHTML||"",children:this.collectDrawerNodes(Array.from(t.children),r),originalItem:null,originalGroup:t})}return i}renderDrawerNode(e){return e.kind==="item"?c`<esp-menu-item
1
+ var l=function(g,e,t,i){var r=arguments.length,s=r<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,t):i,n;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(g,e,t,i);else for(var o=g.length-1;o>=0;o--)(n=g[o])&&(s=(r<3?n(s):r>3?n(e,t,s):n(e,t))||s);return r>3&&s&&Object.defineProperty(e,t,s),s},y;import{css as N,html as f,nothing as w}from"lit";import{customElement as M,property as h,state as F}from"lit/decorators.js";import{classMap as x}from"lit/directives/class-map.js";import{unsafeHTML as z}from"lit/directives/unsafe-html.js";import{createRef as c,ref as u}from"lit/directives/ref.js";import{styleMap as k}from"lit/directives/style-map.js";import{EspalierElementBase as P}from"../shared/esp-element-base.js";import{ESP_EVENTS as S}from"../shared/events.js";import{getEspBus as I}from"../shared/bus-events.js";import{normalizePath as $,pathStartsWithSegment as O,pathsMatch as R}from"../shared/path-matching.js";import{renderConfiguredBrand as L}from"../shared/configured-brand.js";import{FOCUSABLE_SELECTOR as A,OverlayController as T}from"../shared/overlay-controller.js";import{SwipeRevealController as _}from"./swipe-reveal-controller.js";import"./esp-menu-item.js";import"./esp-menu-group.js";import"../burger/esp-burger.js";import{EspalierMenuItem as E}from"./esp-menu-item.js";import{EspalierMenuGroup as v}from"./esp-menu-group.js";import{COMPACT_VIEWPORT_MEDIA_QUERY as G}from"../shared/responsive.js";import{RafThrottle as H}from"../shared/raf-throttle.js";import{viewportSize as q}from"../shared/viewport.js";import{solveDrawerNestedFit as B}from"./drawer-nested-fit.js";const K=new Set(["panel","full-screen"]),U=new Set(["fade","slide-down","slide-up","slide-left","slide-right"]);let a=y=class extends P{ownsDrawerLock(){return this.isFullScreenDrawer}fullScreenInertAnchor(){return y.inertAnchorFor(this)}static inertAnchorFor(e){let t=e,i=e;for(;;){const r=i.parentElement;if(r){if(r.localName==="esp-page"||r.localName==="esp-root")return i;r===document.body&&(t=i),i=r;continue}const s=i.getRootNode();if(s instanceof ShadowRoot&&s.host instanceof HTMLElement){i=s.host;continue}return t}}constructor(){super(),this.itemsSlot=c(),this.railRef=c(),this.scrimRef=c(),this.drawerRef=c(),this.bus=I(),this.closeTransitionTimer=null,this.drawerGroupOpenOverrides=new Map,this.overlay=new T({host:this,getFocusTrapContainer:()=>this.drawerRef.value??null,getFocusScope:()=>this.fullScreenFocusScope(),getInertAnchor:()=>this.fullScreenInertAnchor(),promote:!1,scrollLock:{preserveScrollPosition:!0}}),this.fullScreenSession=!1,this.openedFullScreen=!1,this.drawerKeydownAttached=!1,this.nestedFitProbe=c(),this.nestedFitCapProbe=c(),this.nestedFitFloorProbe=c(),this.nestedFitPadProbe=c(),this.nestedFitTextProbe=c(),this.nestedFit=null,this.nestedFitMeasured=!1,this.nestedFitIdleHandle=null,this.nestedFitFallback=null,this.nestedFitResize=new H(()=>this.measureNestedFit()),this.nestedFitObserver=null,this.onNestedFitResize=()=>{this.drawerPresentation==="full-screen"&&this.nestedFitResize.schedule()},this.onNestedFitFontsLoaded=()=>this.scheduleNestedFit(!0),this.onOverlayOpened=e=>{if(e===this.overlay||!this.drawerOpen)return;const t=this.drawerTrigger;this.drawerTrigger=null,t&&e.redirectFocusRestore(t),this.swipeController.closeForHandoff(),this.onDrawerTransitionEnd()},this._sliding=!1,this._mobileCollapsed=!1,this.verticalDrawerQuery=null,this.onVerticalDrawerChange=e=>this.setMobileCollapsed(e.matches),this.mode="horizontal",this.overflow="auto",this.side="left",this.drawerPresentation="panel",this.fullScreenTransition="fade",this.drawerBrand=null,this.liftedCloseControl=null,this.ariaLabel=null,this.autoExpand=!1,this.drawerOpen=!1,this.drawerShown=!1,this.drawerTransitioning=!1,this.drawerTrigger=null,this.hasExternalDrawerControl=!1,this.previewCollapseRequested=!1,this.getWidth=()=>{const e=this.railRef.value;return e?Math.max(e.scrollWidth,e.clientWidth):-1},this.onDrawerKeydown=e=>{!this.drawerOpen||!this.openedFullScreen||e.key==="Tab"&&this.overlay.trapFocus(e)},this.onDrawerTransitionEnd=e=>{e&&e.target!==this.drawerRef.value||(this.closeTransitionTimer&&(clearTimeout(this.closeTransitionTimer),this.closeTransitionTimer=null),this.drawerTransitioning=!1,this.drawerOpen||(this.hideDrawerPopover(),this.drawerGroupOpenOverrides.clear()))},this.handleDrawerCloseClick=()=>{this.closeDrawer()},this.swipeController=new _(this,this.side),this.swipeController.enabled=!1}get isFullScreenDrawer(){return K.has(this.drawerPresentation)?this.drawerPresentation==="full-screen":!1}get resolvedFullScreenTransition(){return U.has(this.fullScreenTransition)?this.fullScreenTransition:"fade"}get sliding(){return this._sliding}set sliding(e){const t=this._sliding;this._sliding=e,this.syncSwipeEnabled(),this.propagateToItems(),this.requestUpdate("sliding",t)}get collapsed(){return this.drawerActive}set collapsed(e){e?this.mode="drawer":this.mode==="drawer"&&(this.mode="vertical")}get drawerSide(){return this.overflow==="right-drawer"?"right":this.overflow==="left-drawer"?"left":this.side}get drawerActive(){return this.mode==="drawer"||this._sliding||this.overflow==="left-drawer"||this.overflow==="right-drawer"||this.mode==="vertical"&&(this._mobileCollapsed||this.previewCollapseRequested)&&this.hasExternalDrawerControl}get railMode(){return this.mode==="horizontal"?"horizontal":"vertical"}connectedCallback(){super.connectedCallback(),this.getAttribute("slot")==="right"&&(this.side="right"),!this.verticalDrawerQuery&&typeof window<"u"&&"matchMedia"in window&&(this.verticalDrawerQuery=window.matchMedia(G),this._mobileCollapsed=this.verticalDrawerQuery.matches,this.verticalDrawerQuery.addEventListener("change",this.onVerticalDrawerChange)),this.syncSwipeEnabled(),T.addOpenListener(this.onOverlayOpened),window.addEventListener("resize",this.onNestedFitResize),typeof document<"u"&&document.fonts&&(document.fonts.addEventListener("loadingdone",this.onNestedFitFontsLoaded),document.fonts.ready.then(()=>{this.isConnected&&this.scheduleNestedFit(!0)})),!this.nestedFitObserver&&typeof MutationObserver<"u"&&(this.nestedFitObserver=new MutationObserver(()=>this.scheduleNestedFit(!0)),this.nestedFitObserver.observe(this,{subtree:!0,childList:!0,attributes:!0,attributeFilter:["label"]}))}disconnectedCallback(){T.removeOpenListener(this.onOverlayOpened),window.removeEventListener("resize",this.onNestedFitResize),document.fonts?.removeEventListener("loadingdone",this.onNestedFitFontsLoaded),this.nestedFitObserver?.disconnect(),this.nestedFitObserver=null,this.nestedFitResize.cancel(),this.cancelNestedFitIdle(),this.nestedFitMeasured=!1,this.verticalDrawerQuery?.removeEventListener("change",this.onVerticalDrawerChange),this.verticalDrawerQuery=null,this.detachDrawerKeydown(),this.fullScreenSession=!1,super.disconnectedCallback()}setMobileCollapsed(e){e!==this._mobileCollapsed&&(this._mobileCollapsed=e,this.mode==="vertical"&&this.applyMobileCollapse())}applyMobileCollapse(){this.swipeController.direction=this.drawerSide,this.syncSwipeEnabled(),this.propagateToItems(),this.requestUpdate(),!this.drawerActive&&this.drawerOpen&&this.swipeController.close(!0)}firstUpdated(e){super.firstUpdated(e),this.propagateToItems(),this.scheduleNestedFit()}updated(e){super.updated(e),(e.has("mode")||e.has("overflow")||e.has("side")||e.has("hasExternalDrawerControl")||e.has("previewCollapseRequested"))&&(this.swipeController.direction=this.drawerSide,this.syncSwipeEnabled(),this.propagateToItems(),!this.drawerActive&&this.drawerOpen&&this.swipeController.close(!0)),e.has("drawerPresentation")&&(this.nestedFitMeasured=!1,this.scheduleNestedFit()),this.drawerOpen&&this.openedFullScreen!==this.isFullScreenDrawer&&this.swipeController.close(!0),this.autoExpand&&(e.has("autoExpand")||e.has("mode")&&this.mode!=="horizontal")?this.expandToCurrentPage():this.mode==="horizontal"&&e.has("mode")&&this.closeHorizontalTopLevelGroups()}openDrawer(e){this.drawerActive&&(e?this.drawerTrigger=e:this.drawerOpen||(this.drawerTrigger=null),this.swipeController.open())}closeDrawer(){this.swipeController.close(!0)}toggleDrawer(e){this.drawerOpen?this.closeDrawer():this.openDrawer(e)}toggleOpened(){this.toggleDrawer()}get isDrawerOpen(){return this.drawerOpen}syncSwipeEnabled(){this.swipeController.direction=this.drawerSide,this.swipeController.enabled=this.drawerActive}getAssignedChildren(){return this.itemsSlot.value?.assignedElements()??[]}propagateToItems(){const e=this.railMode;for(const t of this.getAssignedChildren())t instanceof E?(t.mode=e,t.depth=0,t.touchDevice=this.swipeController.isTouch):t instanceof v&&(t.mode=e,t.depth=0,t.touchDevice=this.swipeController.isTouch)}handleSlotChange(){this.propagateToItems(),this.scheduleNestedFit(!0)}scheduleNestedFit(e=!1){if(this.drawerPresentation!=="full-screen"){this.cancelNestedFitIdle(),this.nestedFit!==null&&(this.nestedFit=null);return}if(e&&(this.nestedFitMeasured=!1),e&&this.drawerShown){this.cancelNestedFitIdle(),this.nestedFitResize.schedule();return}if(this.nestedFitIdleHandle!==null||this.nestedFitFallback!==null)return;const t=()=>{this.nestedFitIdleHandle=null,this.nestedFitFallback=null,this.isConnected&&this.measureNestedFit()};typeof requestIdleCallback=="function"?this.nestedFitIdleHandle=requestIdleCallback(t,{timeout:2e3}):this.nestedFitFallback={stage:"frame",handle:requestAnimationFrame(()=>{this.nestedFitFallback={stage:"timeout",handle:window.setTimeout(t,0)}})}}cancelNestedFitIdle(){this.nestedFitIdleHandle!==null&&(cancelIdleCallback(this.nestedFitIdleHandle),this.nestedFitIdleHandle=null),this.nestedFitFallback!==null&&(this.nestedFitFallback.stage==="frame"?cancelAnimationFrame(this.nestedFitFallback.handle):window.clearTimeout(this.nestedFitFallback.handle),this.nestedFitFallback=null)}ensureNestedFitMeasured(){this.nestedFitMeasured||(this.cancelNestedFitIdle(),this.measureNestedFit())}collectNestedLabels(){const e=[];let t=!1;const i=(r,s)=>{for(const n of r){const o=s>0;n instanceof E?o&&e.push(n.label):n instanceof v&&(o&&(e.push(n.label),n.url&&(t=!0)),i(Array.from(n.children),s+1))}};return i(this.getAssignedChildren(),0),{labels:e,linkedGroup:t}}readNestedFitMetrics(e){const t=this.nestedFitCapProbe.value,i=this.nestedFitFloorProbe.value,r=this.nestedFitPadProbe.value,s=this.nestedFitTextProbe.value;if(!t||!i||!r||!s)return null;const n=parseFloat(getComputedStyle(t).fontSize),o=parseFloat(getComputedStyle(i).fontSize),d=getComputedStyle(r),p=parseFloat(d.paddingInlineStart),b=parseFloat(d.paddingInlineEnd);if(![n,o,p,b].every(m=>Number.isFinite(m)))return null;s.replaceChildren(...e.map(m=>{const D=document.createElement("span");return D.textContent=m,D}));const C=Array.from(s.children,m=>m.getBoundingClientRect().width);return s.replaceChildren(),{capPx:n,floorPx:o,paddingPx:p,smallPx:b,widths:C}}measureNestedFit(){if(!this.isConnected||this.drawerPresentation!=="full-screen")return;const{labels:e,linkedGroup:t}=this.collectNestedLabels();if(this.nestedFitMeasured=!0,e.length===0){this.nestedFit!==null&&(this.nestedFit=null);return}const i=this.readNestedFitMetrics(e);if(!i)return;const r=this.drawerRef.value,s=r&&this.drawerShown?r.getBoundingClientRect().width:0,n=s>0?s:q().width,o=t?2*(2*i.smallPx+4.5):0,d=n-2*i.paddingPx-o,p=B({capPx:i.capPx,floorPx:i.floorPx,availablePx:d,widestAtCapPx:Math.max(0,...i.widths)});this.nestedFit&&this.nestedFit.fontSizePx===p.fontSizePx&&this.nestedFit.wrap===p.wrap||(this.nestedFit=p)}onSwipeRevealChanged(e){e!==this.drawerOpen&&(this.drawerOpen=e,e?(this.openedFullScreen=this.isFullScreenDrawer,this.openedFullScreen&&this.ensureNestedFitMeasured(),this.drawerGroupOpenOverrides.clear(),this.bus.publish("close-popovers",{}),this.updateComplete.then(()=>this.showDrawerPopover())):(this.detachDrawerKeydown(),this.fullScreenSession&&(this.fullScreenSession=!1,this.overlay.close()),this.drawerShown=!1,this.drawerTransitioning=!0,this.updateComplete.then(()=>this.startCloseTransition()),requestAnimationFrame(()=>this.restoreDrawerTriggerFocus())),this.dispatchEvent(new CustomEvent(e?S.MENU_DRAWER_OPENED:S.MENU_DRAWER_CLOSED,{bubbles:!0,composed:!0})))}showDrawerPopover(){const e=this.scrimRef.value,t=this.drawerRef.value;if(!(!e||!t||!this.isConnected)){this.swipeController.drawerElement=t;try{this.openedFullScreen||e.showPopover(),t.showPopover()}catch{}this.dispatchEvent(new CustomEvent(S.MENU_DRAWER_PRESENTED,{bubbles:!0,composed:!0})),t.getBoundingClientRect(),requestAnimationFrame(()=>{!this.drawerOpen||!this.isConnected||(this.drawerTransitioning=!0,this.drawerShown=!0,this.openedFullScreen&&(this.fullScreenSession=!0,this.overlay.open(),this.attachDrawerKeydown(),this.updateComplete.then(()=>{this.drawerOpen&&this.overlay.moveFocusInto()})))})}}attachDrawerKeydown(){this.drawerKeydownAttached||(document.addEventListener("keydown",this.onDrawerKeydown),this.drawerKeydownAttached=!0)}detachDrawerKeydown(){this.drawerKeydownAttached&&(document.removeEventListener("keydown",this.onDrawerKeydown),this.drawerKeydownAttached=!1)}fullScreenFocusScope(){const e=this.drawerRef.value;if(!e)return[];const t=n=>n instanceof HTMLElement&&n.getClientRects().length>0,i=[],r=n=>{if(n.matches(A)&&t(n)&&i.push(n),n.shadowRoot)for(const o of n.shadowRoot.querySelectorAll(A))t(o)&&i.push(o)};for(const n of e.querySelectorAll("*"))if(r(n),n instanceof HTMLSlotElement)for(const o of n.assignedElements({flatten:!0})){r(o);for(const d of o.querySelectorAll("*"))r(d)}const s=this.liftedCloseControl;if(s?.isConnected){const n=s.shadowRoot?.querySelector("button")??s;t(n)&&i.push(n)}return i}static drawerTransitionMs(e){const t=getComputedStyle(e),i=o=>o.split(",").map(d=>d.trim()).filter(Boolean).map(d=>{const p=Number.parseFloat(d);return Number.isFinite(p)?d.endsWith("ms")?p:p*1e3:0}),r=i(t.transitionDuration),s=i(t.transitionDelay);let n=0;return r.forEach((o,d)=>{n=Math.max(n,o+(s[d%Math.max(s.length,1)]??0))}),n}startCloseTransition(){const e=this.drawerRef.value;if(!e){this.hideDrawerPopover();return}this.closeTransitionTimer&&clearTimeout(this.closeTransitionTimer);const t=y.drawerTransitionMs(e);if(t===0){this.onDrawerTransitionEnd();return}this.closeTransitionTimer=setTimeout(()=>{this.closeTransitionTimer=null,!this.drawerOpen&&this.drawerTransitioning&&this.onDrawerTransitionEnd()},t+50)}hideDrawerPopover(){const e=this.scrimRef.value,t=this.drawerRef.value;this.swipeController.drawerElement=null,t&&(t.style.cssText="");try{t?.hidePopover()}catch{}try{e?.hidePopover()}catch{}}restoreDrawerTriggerFocus(){const e=this.drawerTrigger;this.drawerTrigger=null,e?.isConnected&&e.focus({preventScroll:!0})}getAutoExpandedGroups(e=!0){const t=new Set;let i=null;for(const s of this.querySelectorAll("esp-menu-item")){const n=s.url||s.getAttribute("url");if(n&&R(n)){i=s;break}}if(!i)for(const s of this.querySelectorAll("esp-menu-group")){const n=s.url||s.getAttribute("url");if(n&&R(n)){i=s;break}}if(!i&&e){for(const s of this.querySelectorAll("esp-menu-group"))s.parentElement===this&&t.add(s);return t}if(!i)return t;i instanceof v&&t.add(i);let r=i.parentElement;for(;r&&r!==this;)r instanceof v&&t.add(r),r=r.parentElement;return t}isHorizontalTopLevelGroup(e){return e.mode==="horizontal"&&e.depth===0}groupUrlPrefixMatches(e){return O(location.pathname,e.urlPrefix)}groupPathMatches(e){if(this.groupUrlPrefixMatches(e))return!0;const t=e.url||e.getAttribute("url");return t?O(location.pathname,$(t)):!1}expandToCurrentPage(){const e=this.getAutoExpandedGroups(),t=this.querySelectorAll("esp-menu-group");for(const i of t)i.open=e.has(i)&&!this.isHorizontalTopLevelGroup(i)}closeHorizontalTopLevelGroups(){for(const e of this.querySelectorAll("esp-menu-group"))this.isHorizontalTopLevelGroup(e)&&(e.open=!1)}getDrawerAutoExpandedGroups(){return this.getAutoExpandedGroups(!1)}collectDrawerNodes(e,t=this.getDrawerAutoExpandedGroups()){const i=[];for(const r of e)if(r instanceof E){const s=r.querySelector(":scope > svg, :scope > img");i.push({kind:"item",label:r.label,url:r.url,open:!1,icon:r.icon,iconHtml:s?.outerHTML||"",children:[],originalItem:r,originalGroup:null})}else if(r instanceof v){const s=r.querySelector(':scope > [slot="icon"]'),n=t.has(r)||this.groupPathMatches(r),o=this.drawerGroupOpenOverrides.get(r)??(r.open||n);i.push({kind:"group",label:r.label,url:r.url||"",open:o,icon:r.icon,iconHtml:s?.outerHTML||"",children:this.collectDrawerNodes(Array.from(r.children),t),originalItem:null,originalGroup:r})}return i}renderDrawerNode(e){return e.kind==="item"?f`<esp-menu-item
2
2
  label=${e.label}
3
3
  .url=${e.url}
4
4
  .icon=${e.icon}
5
5
  .mode=${"drawer"}
6
6
  @esp-clicked=${()=>!e.url&&e.originalItem?this.handleDrawerItemClick(e.originalItem):void 0}
7
- >${T(e.iconHtml)}</esp-menu-item
8
- >`:c`<esp-menu-group
7
+ >${z(e.iconHtml)}</esp-menu-item
8
+ >`:f`<esp-menu-group
9
9
  label=${e.label}
10
10
  .url=${e.url}
11
11
  .icon=${e.icon}
12
12
  .mode=${"drawer"}
13
13
  .fullScreenPresentation=${this.openedFullScreen}
14
14
  ?open=${e.open}
15
- @esp-menu-group-toggle=${r=>{e.originalGroup&&(this.drawerGroupOpenOverrides.set(e.originalGroup,r.detail.open),this.isHorizontalTopLevelGroup(e.originalGroup)||(e.originalGroup.open=r.detail.open))}}
15
+ @esp-menu-group-toggle=${t=>{e.originalGroup&&(this.drawerGroupOpenOverrides.set(e.originalGroup,t.detail.open),this.isHorizontalTopLevelGroup(e.originalGroup)||(e.originalGroup.open=t.detail.open))}}
16
16
  >
17
- ${e.iconHtml?T(e.iconHtml):u}
18
- ${e.children.map(r=>this.renderDrawerNode(r))}
19
- </esp-menu-group>`}handleDrawerItemClick(e){e.dispatchEvent(new CustomEvent(v.CLICKED,{detail:{},bubbles:!0,composed:!0})),this.swipeController.close(!0)}render(){const e=this.drawerOpen||this.drawerTransitioning,r=this.drawerActive,i={rail:!0,horizontal:this.railMode==="horizontal",vertical:this.railMode==="vertical",wrap:this.overflow==="wrap",scroll:this.overflow==="scroll","drawer-forced":this.drawerActive},t=e?this.openedFullScreen:this.isFullScreenDrawer,o={drawer:!0,"drawer-left":this.drawerSide==="left","drawer-right":this.drawerSide==="right","full-screen":t,[`transition-${this.resolvedFullScreenTransition}`]:t,transitioning:this.drawerTransitioning,open:this.drawerShown},s=e?this.collectDrawerNodes(this.getAssignedChildren()):[],a=this.ariaLabel??"Navigation",p={"--_esp-menu-drawer-brand-color":this.drawerBrand?.brandColor||null},h=t&&e?c`<div class="drawer-chrome">
20
- <div class="drawer-brand" style=${z(p)}>
17
+ ${e.iconHtml?z(e.iconHtml):w}
18
+ ${e.children.map(t=>this.renderDrawerNode(t))}
19
+ </esp-menu-group>`}handleDrawerItemClick(e){e.dispatchEvent(new CustomEvent(S.CLICKED,{detail:{},bubbles:!0,composed:!0})),this.swipeController.close(!0)}render(){const e=this.drawerOpen||this.drawerTransitioning,t=this.drawerActive,i={rail:!0,horizontal:this.railMode==="horizontal",vertical:this.railMode==="vertical",wrap:this.overflow==="wrap",scroll:this.overflow==="scroll","drawer-forced":this.drawerActive},r=e?this.openedFullScreen:this.isFullScreenDrawer,s={drawer:!0,"drawer-left":this.drawerSide==="left","drawer-right":this.drawerSide==="right","full-screen":r,[`transition-${this.resolvedFullScreenTransition}`]:r,transitioning:this.drawerTransitioning,open:this.drawerShown,"nested-wrap":r&&this.nestedFit?.wrap===!0},n={"--_esp-menu-drawer-nested-font-size":r&&this.nestedFit?`${this.nestedFit.fontSizePx}px`:null},o=e?this.collectDrawerNodes(this.getAssignedChildren()):[],d=this.ariaLabel??"Navigation",p={"--_esp-menu-drawer-brand-color":this.drawerBrand?.brandColor||null},b=r&&e?f`<div class="drawer-chrome">
20
+ <div class="drawer-brand" style=${k(p)}>
21
21
  <slot name="drawer-brand"
22
- >${this.drawerBrand?F(this.drawerBrand):u}</slot
22
+ >${this.drawerBrand?L(this.drawerBrand):w}</slot
23
23
  >
24
24
  </div>
25
- ${this.liftedCloseControl?u:c`
25
+ ${this.liftedCloseControl?w:f`
26
26
  <button
27
27
  type="button"
28
28
  class="drawer-close"
@@ -31,31 +31,38 @@ var l=function(w,e,r,i){var t=arguments.length,o=t<3?e:i===null?i=Object.getOwnP
31
31
  >
32
32
  <esp-burger presentation-only menu-open></esp-burger>
33
33
  </button>`}
34
- </div>`:u;return c`
34
+ </div>`:w;return f`
35
35
  <nav
36
- ${g(this.railRef)}
37
- class=${S(i)}
38
- aria-label=${a}
39
- ?hidden=${r}
36
+ ${u(this.railRef)}
37
+ class=${x(i)}
38
+ aria-label=${d}
39
+ ?hidden=${t}
40
40
  >
41
- <slot ${g(this.itemsSlot)} @slotchange=${this.handleSlotChange}></slot>
41
+ <slot ${u(this.itemsSlot)} @slotchange=${this.handleSlotChange}></slot>
42
42
  </nav>
43
43
  <div
44
- ${g(this.scrimRef)}
45
- class=${S({scrim:!0,"full-screen":t,open:this.drawerShown,transitioning:this.drawerTransitioning})}
44
+ ${u(this.scrimRef)}
45
+ class=${x({scrim:!0,"full-screen":r,open:this.drawerShown,transitioning:this.drawerTransitioning})}
46
46
  popover="manual"
47
47
  ></div>
48
48
  <nav
49
- ${g(this.drawerRef)}
50
- class=${S(o)}
51
- aria-label=${a}
49
+ ${u(this.drawerRef)}
50
+ class=${x(s)}
51
+ style=${k(n)}
52
+ aria-label=${d}
52
53
  popover="manual"
53
- ?data-no-swipe=${t}
54
+ ?data-no-swipe=${r}
54
55
  @transitionend=${this.onDrawerTransitionEnd}
55
56
  >
56
- ${h} ${e?s.map(R=>this.renderDrawerNode(R)):u}
57
+ ${b} ${e?o.map(C=>this.renderDrawerNode(C)):w}
57
58
  </nav>
58
- `}};n.styles=[...E.styles,k`
59
+ ${this.drawerPresentation==="full-screen"?f`<div class="nested-fit-probe" aria-hidden="true" ${u(this.nestedFitProbe)}>
60
+ <span class="nested-fit-cap" ${u(this.nestedFitCapProbe)}>&#8203;</span>
61
+ <span class="nested-fit-floor" ${u(this.nestedFitFloorProbe)}>&#8203;</span>
62
+ <span class="nested-fit-pad" ${u(this.nestedFitPadProbe)}>&#8203;</span>
63
+ <div class="nested-fit-text" ${u(this.nestedFitTextProbe)}></div>
64
+ </div>`:w}
65
+ `}};a.styles=[...P.styles,N`
59
66
  :host {
60
67
  display: block;
61
68
  min-width: 0;
@@ -321,6 +328,73 @@ var l=function(w,e,r,i){var t=arguments.length,o=t<3?e:i===null?i=Object.getOwnP
321
328
  text-align: center;
322
329
  }
323
330
 
331
+
332
+ .drawer.full-screen esp-menu-group esp-menu-item,
333
+ .drawer.full-screen esp-menu-group esp-menu-group {
334
+ --esp-menu-item-font-size: var(
335
+ --_esp-menu-drawer-nested-font-size,
336
+ var(
337
+ --esp-menu-drawer-nested-item-max-font-size,
338
+ calc(0.9 * var(--esp-menu-drawer-item-font-size, var(--esp-type-large)))
339
+ )
340
+ );
341
+ }
342
+
343
+
344
+ .drawer.full-screen.nested-wrap esp-menu-group esp-menu-item::part(menu-text),
345
+ .drawer.full-screen.nested-wrap esp-menu-group esp-menu-group::part(menu-text) {
346
+ white-space: normal;
347
+ overflow-wrap: anywhere;
348
+ text-overflow: clip;
349
+ }
350
+
351
+
352
+ .nested-fit-probe {
353
+ position: absolute;
354
+ inset-inline-start: 0;
355
+ top: 0;
356
+ width: 0;
357
+ height: 0;
358
+ overflow: hidden;
359
+ visibility: hidden;
360
+ pointer-events: none;
361
+ contain: strict;
362
+ white-space: nowrap;
363
+ font-family: var(
364
+ --esp-menu-item-font-family,
365
+ var(
366
+ --_esp-font-menu-effective,
367
+ var(
368
+ --esp-font-menu,
369
+ var(--_esp-font-body-effective, var(--esp-font-body, var(--_esp-font-body-fallback)))
370
+ )
371
+ )
372
+ );
373
+
374
+ font-weight: var(--esp-menu-item-active-font-weight, var(--esp-font-weight-headings, 700));
375
+ }
376
+
377
+ .nested-fit-cap,
378
+ .nested-fit-text {
379
+ font-size: var(
380
+ --esp-menu-drawer-nested-item-max-font-size,
381
+ calc(0.9 * var(--esp-menu-drawer-item-font-size, var(--esp-type-large)))
382
+ );
383
+ }
384
+
385
+ .nested-fit-floor {
386
+ font-size: var(--esp-menu-drawer-nested-item-min-font-size, max(14px, 0.875rem));
387
+ }
388
+
389
+ .nested-fit-pad {
390
+ padding-inline: var(--esp-size-normal) var(--esp-size-small);
391
+ }
392
+
393
+ .nested-fit-text > span {
394
+ display: block;
395
+ width: max-content;
396
+ }
397
+
324
398
  @media (prefers-reduced-motion: reduce) {
325
399
  .scrim.transitioning,
326
400
  .drawer.transitioning,
@@ -328,4 +402,4 @@ var l=function(w,e,r,i){var t=arguments.length,o=t<3?e:i===null?i=Object.getOwnP
328
402
  transition: none;
329
403
  }
330
404
  }
331
- `],l([d({type:String,reflect:!0})],n.prototype,"mode",void 0),l([d({type:String,reflect:!0})],n.prototype,"overflow",void 0),l([d({type:String,reflect:!0})],n.prototype,"side",void 0),l([d({attribute:"drawer-presentation",type:String,reflect:!0})],n.prototype,"drawerPresentation",void 0),l([d({attribute:"full-screen-transition",type:String,reflect:!0})],n.prototype,"fullScreenTransition",void 0),l([d({attribute:!1})],n.prototype,"drawerBrand",void 0),l([d({attribute:!1})],n.prototype,"liftedCloseControl",void 0),l([d({attribute:"aria-label",type:String})],n.prototype,"ariaLabel",void 0),l([d({type:Boolean,attribute:"auto-expand"})],n.prototype,"autoExpand",void 0),l([d({type:Boolean})],n.prototype,"sliding",null),l([d({type:Boolean})],n.prototype,"collapsed",null),l([y()],n.prototype,"drawerOpen",void 0),l([y()],n.prototype,"drawerShown",void 0),l([y()],n.prototype,"drawerTransitioning",void 0),l([d({attribute:!1})],n.prototype,"hasExternalDrawerControl",void 0),l([d({attribute:!1})],n.prototype,"previewCollapseRequested",void 0),n=f=l([M("esp-menu")],n);export{n as EspalierMenu};
405
+ `],l([F()],a.prototype,"nestedFit",void 0),l([h({type:String,reflect:!0})],a.prototype,"mode",void 0),l([h({type:String,reflect:!0})],a.prototype,"overflow",void 0),l([h({type:String,reflect:!0})],a.prototype,"side",void 0),l([h({attribute:"drawer-presentation",type:String,reflect:!0})],a.prototype,"drawerPresentation",void 0),l([h({attribute:"full-screen-transition",type:String,reflect:!0})],a.prototype,"fullScreenTransition",void 0),l([h({attribute:!1})],a.prototype,"drawerBrand",void 0),l([h({attribute:!1})],a.prototype,"liftedCloseControl",void 0),l([h({attribute:"aria-label",type:String})],a.prototype,"ariaLabel",void 0),l([h({type:Boolean,attribute:"auto-expand"})],a.prototype,"autoExpand",void 0),l([h({type:Boolean})],a.prototype,"sliding",null),l([h({type:Boolean})],a.prototype,"collapsed",null),l([F()],a.prototype,"drawerOpen",void 0),l([F()],a.prototype,"drawerShown",void 0),l([F()],a.prototype,"drawerTransitioning",void 0),l([h({attribute:!1})],a.prototype,"hasExternalDrawerControl",void 0),l([h({attribute:!1})],a.prototype,"previewCollapseRequested",void 0),a=y=l([M("esp-menu")],a);export{a as EspalierMenu};
@@ -1,4 +1,4 @@
1
- var u=function(h,t,i,e){var n=arguments.length,s=n<3?t:e===null?e=Object.getOwnPropertyDescriptor(t,i):e,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(h,t,i,e);else for(var o=h.length-1;o>=0;o--)(l=h[o])&&(s=(n<3?l(s):n>3?l(t,i,s):l(t,i))||s);return n>3&&s&&Object.defineProperty(t,i,s),s};import{css as d,html as m}from"lit";import{customElement as f,property as I,state as y}from"lit/decorators.js";import{classMap as k}from"lit/directives/class-map.js";import{ref as a}from"lit/directives/ref.js";import"./esp-picker-item.js";import"./esp-picker-menu.js";import{EspalierElementBase as g}from"../shared/esp-element-base.js";import{styleMap as P}from"lit/directives/style-map.js";import{caretUpDown as w}from"../shared/svgs/caret-up-down.js";import{filter as $}from"../shared/svgs/filter.js";import{EspalierPickerBase as p}from"./esp-picker-base.js";import{PickOneSelection as r}from"./pick-one-selection.js";let c=class extends p{constructor(){super(...arguments),this.selection=r.empty(),this.suppressAutoSelect=!1,this.lastMenuPointSelectionAt=Number.NEGATIVE_INFINITY,this.suppressNextHostClick=!1,this.handleHostPointerDown=t=>{this.selectOpenMenuAtPoint(t)&&(this.lastMenuPointSelectionAt=performance.now())},this.handleHostMouseDown=t=>{if(performance.now()-this.lastMenuPointSelectionAt<500){t.preventDefault(),t.stopPropagation();return}this.selectOpenMenuAtPoint(t)}}get selectedItem(){return this.selection.item}decorateFilteredItems(t){if(!this.selectedItem)return t.map(e=>({...e}));const i=this.selectedItem.value;return t.map(e=>({...e,selected:e.value===i}))}get typeaheadRestoreText(){return this.selectedItem?.text??""}get preservesRemoteResultsOnReset(){return this.typeaheadIsRemote&&this.selectedItem!==void 0}get value(){return this.selectedItem?.value}set value(t){const i=this.pickerItems??[];for(const n of i)n.selected=n.value===t;const e=this.pickerMenu.value?.pickerItems;if(e&&e!==i)for(const n of e)n.selected=n.value===t;this.selection=r.resolve(i,t),this.formCtrl.syncValue()}getPickerFormValue(){return this.selectedItem?.value??null}getPickerValidity(){return this.required&&!this.selectedItem?{flags:{valueMissing:!0},message:this.requiredMessage||"Please select an option."}:null}handlePickerReset(){this.selection=r.empty()}handlePickerRestore(t){this.value=t}syncSelectionFromItems(t){if(t.has("pickerItems")){if(this.selection.hasPending){this.value=this.selection.pending;return}if(!this.selectedItem){const i=this.pickerItems.find(e=>e.selected);i&&(this.selection=r.of(i))}}}selectOpenMenuAtPoint(t){return!this.showOptions||!(this.pickerMenu.value?.selectItemAtPoint(t.clientX,t.clientY)??!1)?!1:(this.suppressNextHostClick=!0,t.preventDefault(),t.stopPropagation(),!0)}render(){const{showOptions:t}=this,i={"esp-field":!0,"show-options":t};return m`
1
+ var u=function(h,t,i,e){var s=arguments.length,n=s<3?t:e===null?e=Object.getOwnPropertyDescriptor(t,i):e,o;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")n=Reflect.decorate(h,t,i,e);else for(var r=h.length-1;r>=0;r--)(o=h[r])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};import{css as d,html as m}from"lit";import{customElement as f,property as I,state as y}from"lit/decorators.js";import{classMap as k}from"lit/directives/class-map.js";import{ref as a}from"lit/directives/ref.js";import"./esp-picker-item.js";import"./esp-picker-menu.js";import{EspalierElementBase as g}from"../shared/esp-element-base.js";import{styleMap as P}from"lit/directives/style-map.js";import{caretUpDown as v}from"../shared/svgs/caret-up-down.js";import{filter as w}from"../shared/svgs/filter.js";import{EspalierPickerBase as p}from"./esp-picker-base.js";import{PickOneSelection as l}from"./pick-one-selection.js";let c=class extends p{constructor(){super(...arguments),this.selection=l.empty(),this.suppressAutoSelect=!1,this.lastMenuPointSelectionAt=Number.NEGATIVE_INFINITY,this.suppressNextHostClick=!1,this.handleHostPointerDown=t=>{this.selectOpenMenuAtPoint(t)&&(this.lastMenuPointSelectionAt=performance.now())},this.handleHostMouseDown=t=>{if(performance.now()-this.lastMenuPointSelectionAt<500){t.preventDefault(),t.stopPropagation();return}this.selectOpenMenuAtPoint(t)}}get selectedItem(){return this.selection.item}decorateFilteredItems(t){if(!this.selectedItem)return t.map(e=>({...e}));const i=this.selectedItem.value;return t.map(e=>({...e,selected:e.value===i}))}get typeaheadRestoreText(){return this.selectedItem?.text??""}get preservesRemoteResultsOnReset(){return this.typeaheadIsRemote&&this.selectedItem!==void 0}get value(){return this.selectedItem?.value}set value(t){const i=this.pickerItems??[];for(const s of i)s.selected=s.value===t;const e=this.pickerMenu.value?.pickerItems;if(e&&e!==i)for(const s of e)s.selected=s.value===t;this.selection=l.resolve(i,t),this.formCtrl.syncValue()}getPickerFormValue(){return this.selectedItem?.value??null}getPickerValidity(){return this.required&&!this.selectedItem?{flags:{valueMissing:!0},message:this.requiredMessage||"Please select an option."}:null}handlePickerReset(){this.selection=l.empty()}handlePickerRestore(t){this.value=t}syncSelectionFromItems(t){if(!t.has("pickerItems"))return;if(this.selection.hasPending){this.value=this.selection.pending;return}if(!this.selectedItem){const e=this.pickerItems.find(s=>s.selected);e&&(this.selection=l.of(e));return}const i=this.pickerItems.find(e=>e.value===this.selectedItem.value);i&&i!==this.selectedItem&&(this.selection=l.of(i))}selectOpenMenuAtPoint(t){return!this.showOptions||!(this.pickerMenu.value?.selectItemAtPoint(t.clientX,t.clientY)??!1)?!1:(this.suppressNextHostClick=!0,t.preventDefault(),t.stopPropagation(),!0)}render(){const{showOptions:t}=this,i={"esp-field":!0,"show-options":t};return m`
2
2
  <div
3
3
  ${a(this.pickerField)}
4
4
  tabindex="-1"
@@ -22,7 +22,7 @@ var u=function(h,t,i,e){var n=arguments.length,s=n<3?t:e===null?e=Object.getOwnP
22
22
  @keydown=${e=>{if(this.pickerMenu.value&&!this.handleSharedPickerKeydown(e))switch(e.key){case"ArrowDown":case"ArrowUp":case"Enter":case"Home":case"End":this.handleMenuNavigationKey(e.key,e);break}}}
23
23
  />
24
24
  </section>
25
- <label>${this.typeahead&&this.inputFocused?$:w}</label>
25
+ <label>${this.typeahead&&this.inputFocused?w:v}</label>
26
26
  ${this.renderPickerMenuDismissButton()}
27
27
 
28
28
  <esp-picker-menu
@@ -32,8 +32,8 @@ var u=function(h,t,i,e){var n=arguments.length,s=n<3?t:e===null?e=Object.getOwnP
32
32
  .label=${this.placeholder}
33
33
  tabindex="-1"
34
34
  ${a(this.pickerMenu)}
35
- @esp-picker-menu-selection-changed=${e=>{if(e.stopPropagation(),this.typeahead)return;const n=e.detail,s=n.length>0?n[0]:void 0;(n.length>0?this.selectedItem!==s:this.selectedItem!==void 0)&&(this.selection=this.showOptions?r.of(s):this.selection.withProvisionalItem(s),this.formCtrl.syncValue(),this.emitValueChanged(this.selectedItem))}}
36
- @esp-picker-menu-close-requested=${e=>{if(this.showOptions=!1,this.clearActiveDescendant(),this.typeahead){const n=e.detail,s=n.length>0?n[0]:void 0;if(s?this.selectedItem?.value!==s.value:this.selectedItem!==void 0){if(this.selection=r.of(s),s)for(const o of this.pickerItems)o.selected=o.value===s.value;this.formCtrl.syncValue(),this.emitValueChanged(this.selectedItem)}this.suppressAutoSelect=!0,this.theInput.value?.focus(),this.resetTypeaheadInput()}else this.theInput.value?.focus()}}
35
+ @esp-picker-menu-selection-changed=${e=>{if(e.stopPropagation(),this.typeahead)return;const s=e.detail,n=s.length>0?s[0]:void 0;(s.length>0?this.selectedItem!==n:this.selectedItem!==void 0)&&(this.selection=this.showOptions?l.of(n):this.selection.withProvisionalItem(n),this.formCtrl.syncValue(),this.emitValueChanged(this.selectedItem))}}
36
+ @esp-picker-menu-close-requested=${e=>{if(this.showOptions=!1,this.clearActiveDescendant(),this.typeahead){const s=e.detail,n=s.length>0?s[0]:void 0;if(n?this.selectedItem?.value!==n.value:this.selectedItem!==void 0){if(this.selection=l.of(n),n)for(const r of this.pickerItems)r.selected=r.value===n.value;this.formCtrl.syncValue(),this.emitValueChanged(this.selectedItem)}this.suppressAutoSelect=!0,this.theInput.value?.focus(),this.resetTypeaheadInput()}else this.theInput.value?.focus()}}
37
37
  @esp-picker-menu-dismiss-requested=${this.handleMenuDismissRequested}
38
38
  >
39
39
  </esp-picker-menu>
@@ -30,4 +30,4 @@ export declare function resolveConfiguredBrand({ scheme, brandLogo, brandColor,
30
30
  * Plain anchors and images are intentional: a brand identity should not gain
31
31
  * the interaction chrome of Espalier's application-navigation controls.
32
32
  */
33
- export declare function renderConfiguredBrand({ brandLogo, brandText, brandHref, brandAlt, }: ConfiguredBrandOptions): typeof nothing | import("lit-html").TemplateResult<1>;
33
+ export declare function renderConfiguredBrand({ brandLogo, brandText, brandHref, brandAlt, }: ConfiguredBrandOptions): import("lit-html").TemplateResult<1> | typeof nothing;
@@ -11,7 +11,7 @@
11
11
  * None of these functions touch the DOM or network — they operate
12
12
  * entirely on data.
13
13
  */
14
- import type { GoogleFont } from "../font-picker/esp-font-picker.js";
14
+ import type { FontPickerFont } from "../font-picker/font-types.js";
15
15
  /**
16
16
  * Human-readable labels for the nine standard CSS `font-weight`
17
17
  * values (100–900).
@@ -21,18 +21,22 @@ import type { GoogleFont } from "../font-picker/esp-font-picker.js";
21
21
  */
22
22
  export declare const WEIGHT_LABELS: Readonly<Record<string, string>>;
23
23
  /**
24
- * Extract available non-italic weights from a {@link GoogleFont},
24
+ * Extract available non-italic weights from a `GoogleFont`,
25
25
  * sorted numerically.
26
26
  *
27
27
  * Google Fonts encodes weights as variant strings: `"regular"` maps
28
28
  * to `"400"`, italic variants (e.g. `"300italic"`) are excluded,
29
29
  * and every other variant string is its numeric weight.
30
30
  *
31
- * @param font A Google Font entry, or `null`.
31
+ * A device (web-safe) font reports the weights its stack's faces are
32
+ * expected to carry (ESP0206); the platform snaps to the nearest weight it
33
+ * actually has.
34
+ *
35
+ * @param font A Google Font entry, a web-safe font, or `null`.
32
36
  * @returns Sorted weight strings. Defaults to `["400"]` when the
33
37
  * font is `null` or has no non-italic variants.
34
38
  */
35
- export declare function extractWeights(font: GoogleFont | null): string[];
39
+ export declare function extractWeights(font: FontPickerFont | null): string[];
36
40
  /**
37
41
  * Normalize a CSS `font-weight` keyword to its numeric equivalent.
38
42
  *
@@ -1 +1 @@
1
- const m={100:"100 Thin",200:"200 Extra Light",300:"300 Light",400:"400 Regular",500:"500 Medium",600:"600 Semi Bold",700:"700 Bold",800:"800 Extra Bold",900:"900 Black"};function d(e){if(!e)return["400"];const t=new Set;for(const r of e.variants)r.includes("italic")||t.add(r==="regular"?"400":r);const n=[...t].sort((r,o)=>Number(r)-Number(o));return n.length>0?n:["400"]}function h(e,t){return e?e==="bold"?"700":e==="normal"?"400":e:t}function u(e,t){const n=e===void 0||e===""?t:e;if(n===void 0)return null;if(typeof n=="number")return Number.isInteger(n)&&n>=1&&n<=1e3?n:null;const r=n.trim().toLowerCase();if(r==="normal")return 400;if(r==="bold")return 700;if(!/^\d{1,4}$/.test(r))return null;const o=Number(r);return Number.isInteger(o)&&o>=1&&o<=1e3?o:null}function g(e,t){if(t.length===0)return"400";if(t.includes(e))return e;const n=Number(e);let r=t[0],o=Math.abs(Number(r)-n);for(const s of t){const i=Math.abs(Number(s)-n);i<o&&(r=s,o=i)}return r}function p(e){let t="",n="",r=!1,o=0;for(const i of e.trim()){if(r){t+=i,r=!1;continue}if(i==="\\"){t+=i,r=!0;continue}if(n){t+=i,i===n&&(n="");continue}if(i==='"'||i==="'"){t+=i,n=i;continue}if(i==="("&&(o+=1),i===")"&&(o=Math.max(0,o-1)),i===","&&o===0)break;t+=i}const s=t.trim();return s.length>=2&&(s.startsWith('"')&&s.endsWith('"')||s.startsWith("'")&&s.endsWith("'"))?s.slice(1,-1).replace(/\\([\\"'])/g,"$1"):s}const l=new Set(["serif","sans-serif","monospace","cursive","fantasy","system-ui","ui-serif","ui-sans-serif","ui-monospace","ui-rounded","math","fangsong","-apple-system","blinkmacsystemfont","arial","helvetica","helvetica neue","liberation sans","liberation serif","liberation mono","verdana","tahoma","trebuchet ms","georgia","times new roman","courier new","segoe ui"].map(e=>e.toLowerCase()));function b(e){return l.has(e.trim().toLowerCase())}function x(e){switch(e){case"serif":return"serif";case"monospace":return"monospace";case"handwriting":return"cursive";default:return"sans-serif"}}const a="data-esp-google-font-owner";function f(e,t){const n=u(t,400)??400,r=n!==400?`:wght@${n}`:"";return`https://fonts.googleapis.com/css2?family=${encodeURIComponent(e)}${r}&display=swap`}function c(e){return document.head.querySelector(`link[${a}="${CSS.escape(e)}"]`)}function y(e){const t=c(e.owner),n=e.family.trim(),r=String(u(e.weight,400)??400);if(e.enabled===!1||!n)return t?.remove(),null;if(t?.dataset.espFamily===n&&t.dataset.espWeight===r)return t;t?.remove();const o=document.createElement("link");o.rel="stylesheet",o.href=f(n,r),o.setAttribute(a,e.owner),o.dataset.espFamily=n,o.dataset.espWeight=r;for(const[s,i]of Object.entries(e.attributes??{}))o.setAttribute(s,i);return document.head.appendChild(o),o}function F(e){c(e)?.remove()}function L(e){for(const t of document.head.querySelectorAll(`link[${a}]`))t.getAttribute(a)?.startsWith(e)&&t.remove()}export{a as RUNTIME_GOOGLE_FONT_OWNER_ATTR,m as WEIGHT_LABELS,g as bestAvailableWeight,p as extractFamily,d as extractWeights,x as getFallbackFont,f as googleFontStylesheetUrl,b as isLocalFontFamily,u as normalizeFontFaceWeight,h as normalizeWeight,F as removeRuntimeGoogleFontLink,L as removeRuntimeGoogleFontLinks,y as syncRuntimeGoogleFontLink};
1
+ import{webSafeFontWeights as l}from"./font-stacks.js";const g={100:"100 Thin",200:"200 Extra Light",300:"300 Light",400:"400 Regular",500:"500 Medium",600:"600 Semi Bold",700:"700 Bold",800:"800 Extra Bold",900:"900 Black"},f=e=>e.kind==="web-safe";function p(e){if(!e)return["400"];if(f(e))return l(e);const t=new Set;for(const r of e.variants)r.includes("italic")||t.add(r==="regular"?"400":r);const n=[...t].sort((r,i)=>Number(r)-Number(i));return n.length>0?n:["400"]}function b(e,t){return e?e==="bold"?"700":e==="normal"?"400":e:t}function u(e,t){const n=e===void 0||e===""?t:e;if(n===void 0)return null;if(typeof n=="number")return Number.isInteger(n)&&n>=1&&n<=1e3?n:null;const r=n.trim().toLowerCase();if(r==="normal")return 400;if(r==="bold")return 700;if(!/^\d{1,4}$/.test(r))return null;const i=Number(r);return Number.isInteger(i)&&i>=1&&i<=1e3?i:null}function x(e,t){if(t.length===0)return"400";if(t.includes(e))return e;const n=Number(e);let r=t[0],i=Math.abs(Number(r)-n);for(const s of t){const o=Math.abs(Number(s)-n);o<i&&(r=s,i=o)}return r}function y(e){let t="",n="",r=!1,i=0;for(const o of e.trim()){if(r){t+=o,r=!1;continue}if(o==="\\"){t+=o,r=!0;continue}if(n){t+=o,o===n&&(n="");continue}if(o==='"'||o==="'"){t+=o,n=o;continue}if(o==="("&&(i+=1),o===")"&&(i=Math.max(0,i-1)),o===","&&i===0)break;t+=o}const s=t.trim();return s.length>=2&&(s.startsWith('"')&&s.endsWith('"')||s.startsWith("'")&&s.endsWith("'"))?s.slice(1,-1).replace(/\\([\\"'])/g,"$1"):s}const m=new Set(["serif","sans-serif","monospace","cursive","fantasy","system-ui","ui-serif","ui-sans-serif","ui-monospace","ui-rounded","math","fangsong","-apple-system","blinkmacsystemfont","arial","helvetica","helvetica neue","liberation sans","liberation serif","liberation mono","verdana","tahoma","trebuchet ms","georgia","times new roman","courier new","segoe ui"].map(e=>e.toLowerCase()));function F(e){return m.has(e.trim().toLowerCase())}function W(e){switch(e){case"serif":return"serif";case"monospace":return"monospace";case"handwriting":return"cursive";default:return"sans-serif"}}const a="data-esp-google-font-owner";function d(e,t){const n=u(t,400)??400,r=n!==400?`:wght@${n}`:"";return`https://fonts.googleapis.com/css2?family=${encodeURIComponent(e)}${r}&display=swap`}function c(e){return document.head.querySelector(`link[${a}="${CSS.escape(e)}"]`)}function w(e){const t=c(e.owner),n=e.family.trim(),r=String(u(e.weight,400)??400);if(e.enabled===!1||!n)return t?.remove(),null;if(t?.dataset.espFamily===n&&t.dataset.espWeight===r)return t;t?.remove();const i=document.createElement("link");i.rel="stylesheet",i.href=d(n,r),i.setAttribute(a,e.owner),i.dataset.espFamily=n,i.dataset.espWeight=r;for(const[s,o]of Object.entries(e.attributes??{}))i.setAttribute(s,o);return document.head.appendChild(i),i}function L(e){c(e)?.remove()}function k(e){for(const t of document.head.querySelectorAll(`link[${a}]`))t.getAttribute(a)?.startsWith(e)&&t.remove()}export{a as RUNTIME_GOOGLE_FONT_OWNER_ATTR,g as WEIGHT_LABELS,x as bestAvailableWeight,y as extractFamily,p as extractWeights,W as getFallbackFont,d as googleFontStylesheetUrl,F as isLocalFontFamily,u as normalizeFontFaceWeight,b as normalizeWeight,L as removeRuntimeGoogleFontLink,k as removeRuntimeGoogleFontLinks,w as syncRuntimeGoogleFontLink};
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @module font-stacks
3
+ *
4
+ * Recognize device (web-safe) CSS font stacks (ESP0206).
5
+ *
6
+ * A stored theme may carry a stack that is equivalent to one of the picker's
7
+ * presets without being byte-identical — `system-ui, -apple-system,
8
+ * BlinkMacSystemFont, "Segoe UI", sans-serif` is the same choice as the
9
+ * System Sans preset. These helpers canonicalize a stack, map it to the
10
+ * preset its leading family implies, and describe a stack that matches no
11
+ * preset, so a picker can show the right selection without rewriting what
12
+ * the theme stores. Pure data; no DOM or network.
13
+ */
14
+ import { type WebSafeCategory, type WebSafeFont } from "../font-picker/font-types.js";
15
+ /**
16
+ * Split a CSS `font-family` value into its families, unquoted, trimmed, and
17
+ * lowercased, respecting quotes and escapes. Empty entries are dropped.
18
+ *
19
+ * ```ts
20
+ * parseFontStack('system-ui, "Segoe UI", sans-serif');
21
+ * // ["system-ui", "segoe ui", "sans-serif"]
22
+ * ```
23
+ */
24
+ export declare function parseFontStack(stack: string): string[];
25
+ /** The canonical, comparable form of a stack: its parsed families joined. */
26
+ export declare function canonicalFontStack(stack: string): string;
27
+ /**
28
+ * The category a stack implies: the last generic keyword it names, else the
29
+ * category of its leading family when that family identifies a preset, else
30
+ * `null` for a stack this module knows nothing about.
31
+ */
32
+ export declare function classifyFontStack(stack: string): WebSafeCategory | null;
33
+ /**
34
+ * Whether a stack resolves to device faces: its leading family is a generic
35
+ * keyword, a platform UI face, or a conventional web-safe face. A stack that
36
+ * leads with a downloadable family (`Roboto, system-ui, sans-serif`) is not
37
+ * a device stack even though it falls back to one.
38
+ */
39
+ export declare function isDeviceFontStack(stack: string): boolean;
40
+ /**
41
+ * The preset a stored stack is equivalent to, or `null`.
42
+ *
43
+ * An exact canonical match wins; otherwise the leading family decides, so
44
+ * `system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif`
45
+ * maps to System Sans and `ui-monospace, "SFMono-Regular", Consolas,
46
+ * monospace` to System Monospace. The returned preset is the catalog entry
47
+ * itself; callers keep the stored stack and only use the preset for display.
48
+ */
49
+ export declare function matchWebSafeFont(stack: string, fonts?: ReadonlyArray<WebSafeFont>): WebSafeFont | null;
50
+ /**
51
+ * Describe a device stack that matches no preset so a picker can still show
52
+ * it as selected: the stack is both the label and the value, the category
53
+ * follows its generic, and the weights follow its leading family. Returns
54
+ * `null` for an empty stack.
55
+ */
56
+ export declare function customWebSafeFont(stack: string): WebSafeFont | null;
57
+ /** Numeric weights a device font offers; see {@link WebSafeFont.weights}. */
58
+ export declare function webSafeFontWeights(font: WebSafeFont): string[];
@@ -0,0 +1 @@
1
+ import{DEVICE_DEFAULT_WEIGHTS as f,SYSTEM_TEXT_WEIGHTS as m,WEB_SAFE_FONTS as l}from"../font-picker/font-types.js";const p={serif:"serif","sans-serif":"sans-serif",monospace:"monospace","system-ui":"sans-serif","ui-serif":"serif","ui-sans-serif":"sans-serif","ui-monospace":"monospace","ui-rounded":"sans-serif"},c=[["System Sans",["system-ui","-apple-system","blinkmacsystemfont","ui-sans-serif","ui-rounded","segoe ui","sans-serif"]],["System Serif",["ui-serif","cambria","charter","iowan old style","serif"]],["System Monospace",["ui-monospace","sfmono-regular","sf mono","menlo","monaco","consolas","liberation mono","cascadia code","cascadia mono","monospace"]],["Arial / Helvetica",["arial","helvetica","helvetica neue","liberation sans"]],["Georgia / Times New Roman",["georgia","times new roman","times","liberation serif"]],["Verdana / Geneva",["verdana","geneva"]],["Tahoma / Geneva",["tahoma"]],["Trebuchet MS",["trebuchet ms"]],["Courier New",["courier new","courier"]]],S=new Set([...c[0][1],...c[1][1]]);function h(n){const e=n.trim();return e.length>=2&&(e.startsWith('"')&&e.endsWith('"')||e.startsWith("'")&&e.endsWith("'"))?e.slice(1,-1).replace(/\\([\\"'])/g,"$1"):e}function o(n){const e=[];let t="",s="",r=!1;for(const i of n){if(r){t+=i,r=!1;continue}if(i==="\\"){t+=i,r=!0;continue}if(s){t+=i,i===s&&(s="");continue}if(i==='"'||i==="'"){t+=i,s=i;continue}if(i===","){e.push(t),t="";continue}t+=i}return e.push(t),e.map(i=>h(i).replace(/\s+/g," ").toLowerCase()).filter(i=>i.length>0)}function d(n){return o(n).join(", ")}function g(n){const e=o(n);for(let s=e.length-1;s>=0;s-=1){const r=p[e[s]];if(r)return r}const t=u(e[0]);return t?l.find(s=>s.family===t)?.category??null:null}function u(n){if(!n)return null;for(const[e,t]of c)if(t.includes(n))return e;return null}function y(n){return u(o(n)[0])!==null}function F(n,e=l){const t=o(n);if(t.length===0)return null;const s=t.join(", "),r=e.find(a=>d(a.stack)===s);if(r)return r;const i=u(t[0]);return i?e.find(a=>a.family===i)??null:null}function T(n){const e=o(n);if(e.length===0)return null;const t=g(n)??"sans-serif",s=t!=="monospace"&&S.has(e[0])?[...m]:[...f];return{family:n.trim(),stack:n.trim(),category:t,kind:"web-safe",weights:s}}function _(n){return[...n.weights??f]}export{d as canonicalFontStack,g as classifyFontStack,T as customWebSafeFont,y as isDeviceFontStack,F as matchWebSafeFont,o as parseFontStack,_ as webSafeFontWeights};
@@ -1 +1 @@
1
- import{getEspBus as c}from"./bus-events.js";import{RafThrottle as h}from"./raf-throttle.js";function p(r){const t=[],s=new Set;let e=r;for(;e&&!s.has(e);){s.add(e);const i=e["linked-popover"];if(i){e=i;continue}const o=e.closest("esp-popover");if(o){t.includes(o)||t.push(o),e=o.parentElement||o.getRootNode()?.host;continue}const n=e.getRootNode();e=n instanceof ShadowRoot?n.host:void 0}return t}class d{constructor(t){this.bus=c(),this.positionFrame=new h(()=>this.runPositionUpdate()),this.positionResizeObserver=null,this.trackingPosition=!1,this.handleClosePopovers=s=>{if(!this.opts.isOpen())return;const e=this.opts.host;if(this.opts.closeStrategy==="source-identity"){if(!s.source||s.source===e||s.source instanceof Node&&(e.contains(s.source)||e.shadowRoot?.contains(s.source)))return}else if(s.skipPopovers?.includes(e))return;this.opts.onShouldClose()},this.onScrollOrResize=()=>this.positionFrame.schedule(),this.onDocumentClick=s=>{const e=this.opts.host,i=s.composedPath();if(i.includes(e))return;const o=this.opts.getInsideElements?.()??[];for(const n of o)if(n&&i.includes(n))return;this.opts.isOpen()&&this.opts.onOutsideClick?.()},this.opts=t,t.host.addController(this)}hostConnected(){this.bus.subscribe("close-popovers",this.handleClosePopovers)}hostDisconnected(){this.bus.unsubscribe("close-popovers",this.handleClosePopovers),this.stopTracking(),this.stopOutsideClick()}runPositionUpdate(){if(this.opts.isOpen()){if(this.opts.shouldContinueTracking&&!this.opts.shouldContinueTracking()){this.opts.onShouldClose();return}this.opts.onPositionUpdate?.()}}startTracking(){this.opts.onPositionUpdate&&(this.trackingPosition=!0,window.addEventListener("scroll",this.onScrollOrResize,{capture:!0,passive:!0}),window.addEventListener("resize",this.onScrollOrResize,{passive:!0}),this.refreshPositionElements())}refreshPositionElements(){if(this.positionResizeObserver?.disconnect(),this.positionResizeObserver=null,!this.trackingPosition||!this.opts.getPositionElements||typeof ResizeObserver>"u")return;const t=new Set(this.opts.getPositionElements().filter(Boolean));if(t.size!==0){this.positionResizeObserver=new ResizeObserver(this.onScrollOrResize);for(const s of t)this.positionResizeObserver.observe(s)}}stopTracking(){this.trackingPosition=!1,window.removeEventListener("scroll",this.onScrollOrResize,{capture:!0}),window.removeEventListener("resize",this.onScrollOrResize),this.positionResizeObserver?.disconnect(),this.positionResizeObserver=null,this.positionFrame.cancel()}startOutsideClick(){this.opts.onOutsideClick&&document.addEventListener("click",this.onDocumentClick,!0)}stopOutsideClick(){document.removeEventListener("click",this.onDocumentClick,!0)}publishCloseOthers(t=[]){this.bus.publish("close-popovers",{source:this.opts.host,...t.length>0?{skipPopovers:t}:{}})}}export{d as PopoverController,p as findContainingPopovers};
1
+ import{getEspBus as c}from"./bus-events.js";import{RafThrottle as h}from"./raf-throttle.js";function l(r,t){let e=t;for(;e;){if(e===r)return!0;e=e instanceof ShadowRoot?e.host:e.parentNode}return!1}function d(r){const t=[],e=new Set;let s=r;for(;s&&!e.has(s);){e.add(s);const i=s["linked-popover"];if(i){s=i;continue}const o=s.closest("esp-popover");if(o){t.includes(o)||t.push(o),s=o.parentElement||o.getRootNode()?.host;continue}const n=s.getRootNode();s=n instanceof ShadowRoot?n.host:void 0}return t}class a{constructor(t){this.bus=c(),this.positionFrame=new h(()=>this.runPositionUpdate()),this.positionResizeObserver=null,this.trackingPosition=!1,this.handleClosePopovers=e=>{if(!this.opts.isOpen())return;const s=this.opts.host;if(this.opts.closeStrategy==="source-identity"){if(!e.source||e.source===s||e.source instanceof Node&&l(s,e.source))return}else if(e.skipPopovers?.includes(s))return;this.opts.onShouldClose()},this.onScrollOrResize=()=>this.positionFrame.schedule(),this.onDocumentClick=e=>{const s=this.opts.host,i=e.composedPath();if(i.includes(s))return;const o=this.opts.getInsideElements?.()??[];for(const n of o)if(n&&i.includes(n))return;this.opts.isOpen()&&this.opts.onOutsideClick?.()},this.opts=t,t.host.addController(this)}hostConnected(){this.bus.subscribe("close-popovers",this.handleClosePopovers)}hostDisconnected(){this.bus.unsubscribe("close-popovers",this.handleClosePopovers),this.stopTracking(),this.stopOutsideClick()}runPositionUpdate(){if(this.opts.isOpen()){if(this.opts.shouldContinueTracking&&!this.opts.shouldContinueTracking()){this.opts.onShouldClose();return}this.opts.onPositionUpdate?.()}}startTracking(){this.opts.onPositionUpdate&&(this.trackingPosition=!0,window.addEventListener("scroll",this.onScrollOrResize,{capture:!0,passive:!0}),window.addEventListener("resize",this.onScrollOrResize,{passive:!0}),this.refreshPositionElements())}refreshPositionElements(){if(this.positionResizeObserver?.disconnect(),this.positionResizeObserver=null,!this.trackingPosition||!this.opts.getPositionElements||typeof ResizeObserver>"u")return;const t=new Set(this.opts.getPositionElements().filter(Boolean));if(t.size!==0){this.positionResizeObserver=new ResizeObserver(this.onScrollOrResize);for(const e of t)this.positionResizeObserver.observe(e)}}stopTracking(){this.trackingPosition=!1,window.removeEventListener("scroll",this.onScrollOrResize,{capture:!0}),window.removeEventListener("resize",this.onScrollOrResize),this.positionResizeObserver?.disconnect(),this.positionResizeObserver=null,this.positionFrame.cancel()}startOutsideClick(){this.opts.onOutsideClick&&document.addEventListener("click",this.onDocumentClick,!0)}stopOutsideClick(){document.removeEventListener("click",this.onDocumentClick,!0)}publishCloseOthers(t=[]){this.bus.publish("close-popovers",{source:this.opts.host,...t.length>0?{skipPopovers:t}:{}})}}export{a as PopoverController,d as findContainingPopovers,l as isComposedDescendant};
@@ -1173,6 +1173,14 @@
1173
1173
  "name": "--esp-menu-drawer-item-font-size",
1174
1174
  "description": "Item label size in the full-screen drawer. Defaults to `var(--esp-type-large)`."
1175
1175
  },
1176
+ {
1177
+ "name": "--esp-menu-drawer-nested-item-max-font-size",
1178
+ "description": "Largest size for labels nested inside a group in the full-screen drawer; the measured fit starts here. Defaults to `calc(0.9 * var(--esp-menu-drawer-item-font-size, var(--esp-type-large)))`."
1179
+ },
1180
+ {
1181
+ "name": "--esp-menu-drawer-nested-item-min-font-size",
1182
+ "description": "Smallest size nested full-screen drawer labels shrink to before they wrap. Defaults to `max(14px, 0.875rem)`: above the ~12-13px critical print size at phone distance (Legge & Bigelow, 2011) and Material's 14sp body minimum, and it rises with a larger default font."
1183
+ },
1176
1184
  {
1177
1185
  "name": "--esp-menu-drawer-shadow",
1178
1186
  "description": "Box shadow for the drawer overlay."
@@ -1661,6 +1661,18 @@
1661
1661
  "component": "esp-menu",
1662
1662
  "description": "Item label size in the full-screen drawer. Defaults to `var(--esp-type-large)`."
1663
1663
  },
1664
+ {
1665
+ "name": "--esp-menu-drawer-nested-item-max-font-size",
1666
+ "category": "component",
1667
+ "component": "esp-menu",
1668
+ "description": "Largest size for labels nested inside a group in the full-screen drawer; the measured fit starts here. Defaults to `calc(0.9 * var(--esp-menu-drawer-item-font-size, var(--esp-type-large)))`."
1669
+ },
1670
+ {
1671
+ "name": "--esp-menu-drawer-nested-item-min-font-size",
1672
+ "category": "component",
1673
+ "component": "esp-menu",
1674
+ "description": "Smallest size nested full-screen drawer labels shrink to before they wrap. Defaults to `max(14px, 0.875rem)`: above the ~12-13px critical print size at phone distance (Legge & Bigelow, 2011) and Material's 14sp body minimum, and it rises with a larger default font."
1675
+ },
1664
1676
  {
1665
1677
  "name": "--esp-menu-drawer-shadow",
1666
1678
  "category": "component",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taprootio/espalier",
3
- "version": "4.12.0",
3
+ "version": "4.13.0",
4
4
  "packageManager": "bun@1.3.12",
5
5
  "description": "Espalier — a themeable, accessible, framework-agnostic, enterprise-grade design system built on web standards and love.",
6
6
  "customElements": "custom-elements.json",