@taprootio/espalier 4.9.1 → 4.11.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.
@@ -75,6 +75,12 @@ export declare function parseImageRatio(value: string): string | null;
75
75
  * </esp-image>
76
76
  * ```
77
77
  *
78
+ * For a long projected lazy-image list, `defer-offscreen` keeps the served
79
+ * `sizes` hint until an image approaches the viewport. This avoids replacing a
80
+ * small fallback selection with a larger candidate before the image can be
81
+ * seen. Eager projected images and every non-projected source keep the normal
82
+ * immediate measured-size behavior.
83
+ *
78
84
  * Banner mode gives all three source modes the same focal position, scrim,
79
85
  * texture, and semantic overlay stack. `ratio` applies at wide widths and
80
86
  * `compact-ratio` below the component-relative compact threshold.
@@ -284,6 +290,13 @@ export declare class EspalierImage extends EspalierElementBase {
284
290
  * retain the consumer's own loading attributes.
285
291
  */
286
292
  loading: "eager" | "lazy";
293
+ /**
294
+ * For lazy projected images, defer measured `sizes` upgrades until the image
295
+ * approaches the viewport. A 200px prefetch margin keeps the full-size
296
+ * candidate ready before it is visible. Eager projections and internally
297
+ * rendered images keep their normal immediate measurements.
298
+ */
299
+ deferOffscreen: boolean;
287
300
  /** Enable borderless banner defaults and the decorative/content layer stack. */
288
301
  banner: boolean;
289
302
  /**
@@ -1,21 +1,21 @@
1
- var n=function(p,e,t,r){var i=arguments.length,o=i<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,s;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(p,e,t,r);else for(var c=p.length-1;c>=0;c--)(s=p[c])&&(o=(i<3?s(o):i>3?s(e,t,o):s(e,t))||o);return i>3&&o&&Object.defineProperty(e,t,o),o},m;import{css as T,html as d,nothing as N}from"lit";import{customElement as P,property as l,state as u}from"lit/decorators.js";import{EspalierElementBase as y}from"../shared/esp-element-base.js";import{slotHasContent as f}from"../shared/slot-content.js";import{renderVisualOverlay as R,visualOverlayStyles as I}from"../shared/visual-overlay.js";import{focusConverter as E,normalizeFocus as O}from"./image-focus.js";import{ensureImageTextureFilters as A,imageTextureFilterId as W}from"./image-texture-filters.js";import{getImageTexture as b,isBuiltInImageTexture as x,subscribeToImageTextureRegistry as H}from"../shared/image-texture-registry.js";import{validImageDimensions as _}from"./image-dimensions.js";import"./esp-image-option.js";const k=new Set(["auto","none","flat","top","bottom","left","right","radial"]),S=new Set(["soft","medium","strong"]),w=new Set(["fine","medium","coarse"]),z=new Set(["auto","light","dark"]),j=new Set(["bottom-start","bottom","bottom-end","center","top-start","top","top-end"]);function h(p,e){return{fromAttribute(t){return t&&p.has(t)?t:e},toAttribute(t){return p.has(t)?t:e}}}function C(p){const e=p.trim();if(!e)return null;const t=e.split("/").map(i=>i.trim());if(t.length>2||t.some(i=>i.length===0))return null;const r=t.map(Number);return r.some(i=>!Number.isFinite(i)||i<=0)?null:r.length===1?String(r[0]):`${r[0]} / ${r[1]}`}let a=m=class extends y{constructor(){super(...arguments),this.originalHeight=0,this.originalWidth=0,this.imageUrl="",this.localImage="",this.caption="",this.sizes="100vw",this.loading="eager",this.banner=!1,this.bannerScheme="auto",this.scrim="auto",this.scrimStrength="medium",this.texture="none",this.textureScale="medium",this.contentPosition="bottom-start",this.focusPoint={x:.5,y:.5},this.ratio="",this.compactRatio="",this.renderedWidth=0,this.compact=!1,this.overlayHasContent=!1,this.resizeObserver=null,this.unsubscribeTextures=null,this.handleSlotChange=e=>{if(e.target instanceof HTMLSlotElement){if(e.target.name==="overlay"){const t=f(e.target);t!==this.overlayHasContent&&(this.overlayHasContent=t);return}this.requestUpdate()}}}get isPortrait(){const e=_(this.originalWidth,this.originalHeight);return e!==null&&e.height>e.width}findProjected(){for(const e of this.children)if(e.tagName==="PICTURE"||e.tagName==="IMG")return e;return null}connectedCallback(){super.connectedCallback(),m.ensureProjectionStyles(this.getRootNode()),this.unsubscribeTextures??=H(()=>this.requestUpdate()),this.resizeObserver??=new ResizeObserver(e=>{const t=e[0]?.contentBoxSize?.[0],r=Math.round(t?t.inlineSize:e[0]?.contentRect.width??0);r>0&&r!==this.renderedWidth&&(this.renderedWidth=r)}),this.resizeObserver.observe(this)}disconnectedCallback(){super.disconnectedCallback(),this.unsubscribeTextures?.(),this.unsubscribeTextures=null,this.resizeObserver?.disconnect(),this.resizeObserver=null}effectiveSizes(){return this.renderedWidth>0?`${this.renderedWidth}px`:this.sizes}buildSources(){const e=new Map;for(const t of this.querySelectorAll("esp-image-option")){const r=t.getAttribute("url"),i=Number(t.getAttribute("width"));if(!r||!Number.isFinite(i)||i<=0)continue;const o=t.getAttribute("type")??"",s=e.get(o)??[];s.push({url:r,width:i}),e.set(o,s)}return Array.from(e,([t,r])=>({type:t,srcset:r.sort((i,o)=>i.width-o.width).map(i=>`${i.url} ${i.width}w`).join(", ")})).filter(t=>t.srcset.length>0)}resolvedBannerScheme(){return this.bannerScheme!=="auto"?this.bannerScheme:this.scheme==="dark"?"dark":"light"}resolvedTexture(){return x(this.texture)?this.texture:b(this.texture)?this.texture:"none"}resolvedScrim(){return this.scrim!=="auto"?this.scrim:this.overlayHasContent?this.contentPosition.startsWith("top")?"top":this.contentPosition.startsWith("bottom")?"bottom":"radial":"none"}resolvedAspectRatio(){const e=_(this.originalWidth,this.originalHeight);if(!this.banner)return e?`${e.width} / ${e.height}`:null;const t=C(this.ratio);return(this.compact?C(this.compactRatio):null)??t??(e?`${e.width} / ${e.height}`:null)}normalizeEnums(e){e.has("scrim")&&!k.has(this.scrim)&&(this.scrim="auto"),e.has("bannerScheme")&&!z.has(this.bannerScheme)&&(this.bannerScheme="auto"),e.has("scrimStrength")&&!S.has(this.scrimStrength)&&(this.scrimStrength="medium"),e.has("textureScale")&&!w.has(this.textureScale)&&(this.textureScale="medium"),e.has("contentPosition")&&!j.has(this.contentPosition)&&(this.contentPosition="bottom-start")}willUpdate(e){super.willUpdate(e),this.normalizeEnums(e);const t=O(this.focusPoint),r=Number((t.x*100).toFixed(4)),i=Number((t.y*100).toFixed(4));this.style.setProperty("--_esp-image-object-position",`${r}% ${i}%`);const o=this.resolvedAspectRatio();o?this.style.setProperty("--_esp-image-aspect-ratio",o):this.style.removeProperty("--_esp-image-aspect-ratio");const s=this.resolvedTexture();if(["paper","grain","grunge"].includes(s)){const g=s==="grunge"&&this.resolvedBannerScheme()==="light"?"grunge-light":s;this.style.setProperty("--_esp-image-texture-filter",`url(#${W(g,this.textureScale)})`)}else this.style.removeProperty("--_esp-image-texture-filter");const c=x(s)?void 0:b(s),$=[["--_esp-image-registered-image",c?.image],["--_esp-image-registered-size",c?.size],["--_esp-image-registered-repeat",c?.repeat],["--_esp-image-registered-position",c?.position],["--_esp-image-registered-opacity",c?.opacity?.toString()],["--_esp-image-registered-blend-mode",c?.blendMode]];for(const[g,v]of $)v===void 0?this.style.removeProperty(g):this.style.setProperty(g,v)}firstUpdated(e){super.firstUpdated(e);const t=this.shadowRoot?.querySelector('slot[name="overlay"]');t&&(this.overlayHasContent=f(t))}updated(e){if(super.updated(e),["paper","grain","grunge"].includes(this.resolvedTexture())&&this.renderRoot&&A(this.renderRoot),this.renderedWidth>0){const s=this.shadowRoot?.querySelector(".compact-sentinel")?.getBoundingClientRect().width??0,c=s>0&&this.renderedWidth<s;c!==this.compact&&(this.compact=c)}if(this.renderedWidth<=0)return;const t=this.findProjected();if(!t)return;const r=this.effectiveSizes();if(t.tagName==="PICTURE")for(const o of t.querySelectorAll("source"))o.setAttribute("sizes",r);const i=t.tagName==="IMG"?t:t.querySelector("img");i?.hasAttribute("srcset")&&i.setAttribute("sizes",r)}renderMedia(){if(this.localImage)return d`<img
1
+ var n=function(d,e,t,r){var i=arguments.length,s=i<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,o;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(d,e,t,r);else for(var l=d.length-1;l>=0;l--)(o=d[l])&&(s=(i<3?o(s):i>3?o(e,t,s):o(e,t))||s);return i>3&&s&&Object.defineProperty(e,t,s),s},p;import{css as I,html as m,nothing as C}from"lit";import{customElement as $,property as c,state as g}from"lit/decorators.js";import{EspalierElementBase as v}from"../shared/esp-element-base.js";import{slotHasContent as y}from"../shared/slot-content.js";import{renderVisualOverlay as T,visualOverlayStyles as A}from"../shared/visual-overlay.js";import{focusConverter as N,normalizeFocus as R}from"./image-focus.js";import{ensureImageTextureFilters as W,imageTextureFilterId as E}from"./image-texture-filters.js";import{getImageTexture as b,isBuiltInImageTexture as x,subscribeToImageTextureRegistry as M}from"../shared/image-texture-registry.js";import{validImageDimensions as _}from"./image-dimensions.js";import"./esp-image-option.js";const k=new Set(["auto","none","flat","top","bottom","left","right","radial"]),S=new Set(["soft","medium","strong"]),w=new Set(["fine","medium","coarse"]),j=new Set(["auto","light","dark"]),O=new Set(["bottom-start","bottom","bottom-end","center","top-start","top","top-end"]);function h(d,e){return{fromAttribute(t){return t&&d.has(t)?t:e},toAttribute(t){return d.has(t)?t:e}}}function z(d){const e=d.trim();if(!e)return null;const t=e.split("/").map(i=>i.trim());if(t.length>2||t.some(i=>i.length===0))return null;const r=t.map(Number);return r.some(i=>!Number.isFinite(i)||i<=0)?null:r.length===1?String(r[0]):`${r[0]} / ${r[1]}`}let a=p=class extends v{constructor(){super(...arguments),this.originalHeight=0,this.originalWidth=0,this.imageUrl="",this.localImage="",this.caption="",this.sizes="100vw",this.loading="eager",this.deferOffscreen=!1,this.banner=!1,this.bannerScheme="auto",this.scrim="auto",this.scrimStrength="medium",this.texture="none",this.textureScale="medium",this.contentPosition="bottom-start",this.focusPoint={x:.5,y:.5},this.ratio="",this.compactRatio="",this.renderedWidth=0,this.measuredWidth=0,this.compact=!1,this.overlayHasContent=!1,this.resizeObserver=null,this.offscreenObserver=null,this.offscreenAdmitted=!1,this.deferredProjectedImage=null,this.unsubscribeTextures=null,this.handleSlotChange=e=>{if(e.target instanceof HTMLSlotElement){if(e.target.name==="overlay"){const t=y(e.target);t!==this.overlayHasContent&&(this.overlayHasContent=t);return}this.requestUpdate()}}}get isPortrait(){const e=_(this.originalWidth,this.originalHeight);return e!==null&&e.height>e.width}findProjected(){for(const e of this.children)if(e.tagName==="PICTURE"||e.tagName==="IMG")return e;return null}findProjectedImage(e=this.findProjected()){return e?e.tagName==="IMG"?e:e.querySelector("img"):null}requiresOffscreenDeferral(e=this.findProjectedImage()){return this.deferOffscreen&&e?.getAttribute("loading")?.toLowerCase()==="lazy"}shouldDeferProjectedSizes(){return this.requiresOffscreenDeferral()&&!this.offscreenAdmitted}applyMeasuredWidth(){this.measuredWidth>0&&this.measuredWidth!==this.renderedWidth&&(this.renderedWidth=this.measuredWidth)}syncOffscreenDeferral(){const e=this.findProjectedImage();if(e!==this.deferredProjectedImage&&(this.offscreenAdmitted=!1,this.offscreenObserver?.disconnect(),this.offscreenObserver=null,this.deferredProjectedImage=e),!this.requiresOffscreenDeferral(e)){this.offscreenObserver?.disconnect(),this.offscreenObserver=null,this.offscreenAdmitted=!1,this.deferredProjectedImage=null,this.applyMeasuredWidth();return}if(!this.offscreenAdmitted){if(typeof IntersectionObserver>"u"){this.offscreenAdmitted=!0,this.applyMeasuredWidth();return}if(!this.offscreenObserver){const t=e,r=new IntersectionObserver(i=>{if(this.offscreenObserver===r){if(this.findProjectedImage()!==t){this.syncOffscreenDeferral();return}i.some(s=>s.isIntersecting)&&(this.offscreenAdmitted=!0,this.offscreenObserver?.disconnect(),this.offscreenObserver=null,this.applyMeasuredWidth(),this.requestUpdate())}},{rootMargin:"200px"});this.offscreenObserver=r}this.offscreenObserver.observe(this)}}connectedCallback(){super.connectedCallback(),p.ensureProjectionStyles(this.getRootNode()),this.unsubscribeTextures??=M(()=>this.requestUpdate()),this.resizeObserver??=new ResizeObserver(e=>{const t=e[0]?.contentBoxSize?.[0],r=Math.round(t?t.inlineSize:e[0]?.contentRect.width??0);r<=0||(this.measuredWidth=r,this.syncOffscreenDeferral(),this.applyMeasuredWidth())}),this.resizeObserver.observe(this),this.syncOffscreenDeferral()}disconnectedCallback(){super.disconnectedCallback(),this.unsubscribeTextures?.(),this.unsubscribeTextures=null,this.resizeObserver?.disconnect(),this.resizeObserver=null,this.offscreenObserver?.disconnect(),this.offscreenObserver=null,this.offscreenAdmitted=!1,this.deferredProjectedImage=null}effectiveSizes(){return this.renderedWidth>0?`${this.renderedWidth}px`:this.sizes}buildSources(){const e=new Map;for(const t of this.querySelectorAll("esp-image-option")){const r=t.getAttribute("url"),i=Number(t.getAttribute("width"));if(!r||!Number.isFinite(i)||i<=0)continue;const s=t.getAttribute("type")??"",o=e.get(s)??[];o.push({url:r,width:i}),e.set(s,o)}return Array.from(e,([t,r])=>({type:t,srcset:r.sort((i,s)=>i.width-s.width).map(i=>`${i.url} ${i.width}w`).join(", ")})).filter(t=>t.srcset.length>0)}resolvedBannerScheme(){return this.bannerScheme!=="auto"?this.bannerScheme:this.scheme==="dark"?"dark":"light"}resolvedTexture(){return x(this.texture)?this.texture:b(this.texture)?this.texture:"none"}resolvedScrim(){return this.scrim!=="auto"?this.scrim:this.overlayHasContent?this.contentPosition.startsWith("top")?"top":this.contentPosition.startsWith("bottom")?"bottom":"radial":"none"}resolvedAspectRatio(){const e=_(this.originalWidth,this.originalHeight);if(!this.banner)return e?`${e.width} / ${e.height}`:null;const t=z(this.ratio);return(this.compact?z(this.compactRatio):null)??t??(e?`${e.width} / ${e.height}`:null)}normalizeEnums(e){e.has("scrim")&&!k.has(this.scrim)&&(this.scrim="auto"),e.has("bannerScheme")&&!j.has(this.bannerScheme)&&(this.bannerScheme="auto"),e.has("scrimStrength")&&!S.has(this.scrimStrength)&&(this.scrimStrength="medium"),e.has("textureScale")&&!w.has(this.textureScale)&&(this.textureScale="medium"),e.has("contentPosition")&&!O.has(this.contentPosition)&&(this.contentPosition="bottom-start")}willUpdate(e){super.willUpdate(e),this.normalizeEnums(e);const t=R(this.focusPoint),r=Number((t.x*100).toFixed(4)),i=Number((t.y*100).toFixed(4));this.style.setProperty("--_esp-image-object-position",`${r}% ${i}%`);const s=this.resolvedAspectRatio();s?this.style.setProperty("--_esp-image-aspect-ratio",s):this.style.removeProperty("--_esp-image-aspect-ratio");const o=this.resolvedTexture();if(["paper","grain","grunge"].includes(o)){const u=o==="grunge"&&this.resolvedBannerScheme()==="light"?"grunge-light":o;this.style.setProperty("--_esp-image-texture-filter",`url(#${E(u,this.textureScale)})`)}else this.style.removeProperty("--_esp-image-texture-filter");const l=x(o)?void 0:b(o),P=[["--_esp-image-registered-image",l?.image],["--_esp-image-registered-size",l?.size],["--_esp-image-registered-repeat",l?.repeat],["--_esp-image-registered-position",l?.position],["--_esp-image-registered-opacity",l?.opacity?.toString()],["--_esp-image-registered-blend-mode",l?.blendMode]];for(const[u,f]of P)f===void 0?this.style.removeProperty(u):this.style.setProperty(u,f)}firstUpdated(e){super.firstUpdated(e);const t=this.shadowRoot?.querySelector('slot[name="overlay"]');t&&(this.overlayHasContent=y(t))}updated(e){if(super.updated(e),this.syncOffscreenDeferral(),["paper","grain","grunge"].includes(this.resolvedTexture())&&this.renderRoot&&W(this.renderRoot),this.renderedWidth>0){const o=this.shadowRoot?.querySelector(".compact-sentinel")?.getBoundingClientRect().width??0,l=o>0&&this.renderedWidth<o;l!==this.compact&&(this.compact=l)}if(this.renderedWidth<=0||this.shouldDeferProjectedSizes())return;const t=this.findProjected();if(!t)return;const r=this.effectiveSizes();if(t.tagName==="PICTURE")for(const s of t.querySelectorAll("source"))s.setAttribute("sizes",r);const i=this.findProjectedImage(t);i?.hasAttribute("srcset")&&i.setAttribute("sizes",r)}renderMedia(){if(this.localImage)return m`<img
2
2
  src=${this.localImage}
3
3
  alt=${this.caption}
4
4
  decoding="async"
5
5
  loading=${this.loading}
6
- />`;const e=d`<slot @slotchange=${this.handleSlotChange}></slot>`;if(this.findProjected())return e;const t=this.buildSources();return d`
6
+ />`;const e=m`<slot @slotchange=${this.handleSlotChange}></slot>`;if(this.findProjected())return e;const t=this.buildSources();return m`
7
7
  <picture>
8
- ${t.map(r=>d`
8
+ ${t.map(r=>m`
9
9
  <source
10
10
  srcset=${r.srcset}
11
11
  sizes=${this.effectiveSizes()}
12
- type=${r.type||N}
12
+ type=${r.type||C}
13
13
  />
14
14
  `)}
15
15
  <img src=${this.imageUrl} alt=${this.caption} decoding="async" loading=${this.loading} />
16
16
  </picture>
17
17
  ${e}
18
- `}render(){return d`
18
+ `}render(){return m`
19
19
  <div
20
20
  part="frame"
21
21
  class="frame"
@@ -27,13 +27,13 @@ var n=function(p,e,t,r){var i=arguments.length,o=i<3?e:r===null?r=Object.getOwnP
27
27
  data-content-position=${this.contentPosition}
28
28
  >
29
29
  <div part="image" class="image">${this.renderMedia()}</div>
30
- ${R({className:"banner-layers",imagePart:"texture",scrimPart:"scrim",texturePart:"texture"})}
30
+ ${T({className:"banner-layers",imagePart:"texture",scrimPart:"scrim",texturePart:"texture"})}
31
31
  <div part="overlay" class="overlay" ?hidden=${!this.banner||!this.overlayHasContent}>
32
32
  <slot name="overlay" @slotchange=${this.handleSlotChange}></slot>
33
33
  </div>
34
34
  <span class="compact-sentinel" aria-hidden="true"></span>
35
35
  </div>
36
- `}static ensureProjectionStyles(e){const t=e.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&"host"in e?e:e.nodeType===Node.DOCUMENT_NODE?e.head:e.ownerDocument?.head??document.head,r=Array.from(t.querySelectorAll("style[data-esp-image-projection-styles]")),i=r.find(s=>s.textContent===m.projectionStyles);if(i){for(const s of r)s!==i&&s.remove();return}for(const s of r)s.remove();const o=t.ownerDocument.createElement("style");o.dataset.espImageProjectionStyles="",o.textContent=m.projectionStyles,t.append(o)}};a.projectionStyles=`
36
+ `}static ensureProjectionStyles(e){const t=e.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&"host"in e?e:e.nodeType===Node.DOCUMENT_NODE?e.head:e.ownerDocument?.head??document.head,r=Array.from(t.querySelectorAll("style[data-esp-image-projection-styles]")),i=r.find(o=>o.textContent===p.projectionStyles);if(i){for(const o of r)o!==i&&o.remove();return}for(const o of r)o.remove();const s=t.ownerDocument.createElement("style");s.dataset.espImageProjectionStyles="",s.textContent=p.projectionStyles,t.append(s)}};a.projectionStyles=`
37
37
  esp-image > picture,
38
38
  esp-image > img {
39
39
  display: block;
@@ -49,7 +49,7 @@ var n=function(p,e,t,r){var i=arguments.length,o=i<3?e:r===null?r=Object.getOwnP
49
49
  object-fit: var(--_esp-image-object-fit, cover);
50
50
  object-position: var(--esp-image-object-position, var(--_esp-image-object-position, center));
51
51
  }
52
- `,a.styles=[...y.styles,T`
52
+ `,a.styles=[...v.styles,I`
53
53
  :host {
54
54
  display: block;
55
55
  aspect-ratio: var(--_esp-image-aspect-ratio, auto);
@@ -439,4 +439,4 @@ var n=function(p,e,t,r){var i=arguments.length,o=i<3?e:r===null?r=Object.getOwnP
439
439
  transition: none !important;
440
440
  }
441
441
  }
442
- `,I],n([l({attribute:"original-height",type:Number})],a.prototype,"originalHeight",void 0),n([l({attribute:"original-width",type:Number})],a.prototype,"originalWidth",void 0),n([l({attribute:"low-res",type:String})],a.prototype,"imageUrl",void 0),n([l({attribute:"local-image",type:String})],a.prototype,"localImage",void 0),n([l({type:String})],a.prototype,"caption",void 0),n([l({attribute:"sizes",type:String})],a.prototype,"sizes",void 0),n([l({attribute:"loading",type:String})],a.prototype,"loading",void 0),n([l({type:Boolean,reflect:!0})],a.prototype,"banner",void 0),n([l({attribute:"banner-scheme",converter:h(z,"auto"),reflect:!0})],a.prototype,"bannerScheme",void 0),n([l({converter:h(k,"auto"),reflect:!0})],a.prototype,"scrim",void 0),n([l({attribute:"scrim-strength",converter:h(S,"medium"),reflect:!0})],a.prototype,"scrimStrength",void 0),n([l({type:String,reflect:!0})],a.prototype,"texture",void 0),n([l({attribute:"texture-scale",converter:h(w,"medium"),reflect:!0})],a.prototype,"textureScale",void 0),n([l({attribute:"content-position",converter:h(j,"bottom-start"),reflect:!0})],a.prototype,"contentPosition",void 0),n([l({attribute:"focus",converter:E,reflect:!0})],a.prototype,"focusPoint",void 0),n([l({type:String})],a.prototype,"ratio",void 0),n([l({attribute:"compact-ratio",type:String})],a.prototype,"compactRatio",void 0),n([u()],a.prototype,"renderedWidth",void 0),n([u()],a.prototype,"compact",void 0),n([u()],a.prototype,"overlayHasContent",void 0),a=m=n([P("esp-image")],a);export{a as EspalierImage,C as parseImageRatio};
442
+ `,A],n([c({attribute:"original-height",type:Number})],a.prototype,"originalHeight",void 0),n([c({attribute:"original-width",type:Number})],a.prototype,"originalWidth",void 0),n([c({attribute:"low-res",type:String})],a.prototype,"imageUrl",void 0),n([c({attribute:"local-image",type:String})],a.prototype,"localImage",void 0),n([c({type:String})],a.prototype,"caption",void 0),n([c({attribute:"sizes",type:String})],a.prototype,"sizes",void 0),n([c({attribute:"loading",type:String})],a.prototype,"loading",void 0),n([c({attribute:"defer-offscreen",type:Boolean})],a.prototype,"deferOffscreen",void 0),n([c({type:Boolean,reflect:!0})],a.prototype,"banner",void 0),n([c({attribute:"banner-scheme",converter:h(j,"auto"),reflect:!0})],a.prototype,"bannerScheme",void 0),n([c({converter:h(k,"auto"),reflect:!0})],a.prototype,"scrim",void 0),n([c({attribute:"scrim-strength",converter:h(S,"medium"),reflect:!0})],a.prototype,"scrimStrength",void 0),n([c({type:String,reflect:!0})],a.prototype,"texture",void 0),n([c({attribute:"texture-scale",converter:h(w,"medium"),reflect:!0})],a.prototype,"textureScale",void 0),n([c({attribute:"content-position",converter:h(O,"bottom-start"),reflect:!0})],a.prototype,"contentPosition",void 0),n([c({attribute:"focus",converter:N,reflect:!0})],a.prototype,"focusPoint",void 0),n([c({type:String})],a.prototype,"ratio",void 0),n([c({attribute:"compact-ratio",type:String})],a.prototype,"compactRatio",void 0),n([g()],a.prototype,"renderedWidth",void 0),n([g()],a.prototype,"compact",void 0),n([g()],a.prototype,"overlayHasContent",void 0),a=p=n([$("esp-image")],a);export{a as EspalierImage,z as parseImageRatio};
@@ -157,6 +157,21 @@ export declare class EspalierImageUpload extends EspalierElementBase {
157
157
  * are skipped and reported via the `esp-image-upload-files-rejected` event.
158
158
  */
159
159
  accept: string;
160
+ /**
161
+ * Maximum number of image previews in each justified row. Positive integers
162
+ * create a hard row boundary; omitted, non-finite, non-integer, and
163
+ * nonpositive values leave rows unlimited.
164
+ *
165
+ * @type {number}
166
+ */
167
+ maxImagesPerRow?: number;
168
+ /**
169
+ * Maximum preview-row height as a percentage of the layout viewport. Values
170
+ * outside the inclusive integer range `1…100` fall back to 90.
171
+ *
172
+ * @type {number}
173
+ */
174
+ maxRowHeightVh: number;
160
175
  connectedCallback(): void;
161
176
  disconnectedCallback(): void;
162
177
  /**
@@ -1,25 +1,25 @@
1
- var g=function(v,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnPropertyDescriptor(e,t):r,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(v,e,t,r);else for(var i=v.length-1;i>=0;i--)(l=v[i])&&(s=(n<3?l(s):n>3?l(e,t,s):l(e,t))||s);return n>3&&s&&Object.defineProperty(e,t,s),s},_;import{css as P,html as m}from"lit";import{customElement as D,property as A,state as w}from"lit/decorators.js";import{createRef as b,ref as x}from"lit/directives/ref.js";import"./esp-image-preview.js";import{classMap as S}from"lit/directives/class-map.js";import{getImageDetails as k,releasePreviewUrl as I}from"./image-helpers.js";const C=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
1
+ var f=function(_,e,t,i){var o=arguments.length,r=o<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,t):i,d;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(_,e,t,i);else for(var n=_.length-1;n>=0;n--)(d=_[n])&&(r=(o<3?d(r):o>3?d(e,t,r):d(e,t))||r);return o>3&&r&&Object.defineProperty(e,t,r),r},m;import{css as A,html as w}from"lit";import{customElement as R,property as x,state as b}from"lit/decorators.js";import{createRef as I,ref as E}from"lit/directives/ref.js";import"./esp-image-preview.js";import{classMap as P}from"lit/directives/class-map.js";import{getImageDetails as M,releasePreviewUrl as y}from"./image-helpers.js";const U=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
2
2
  <path stroke="none" d="M0 0h24v24H0z" fill="none" />
3
3
  <path d="M11.911 3.634a2 2 0 0 1 1.089 1.78l.001 2.586h6.999a2 2 0 0 1 2 2v4l-.005 .15a2 2 0 0 1 -1.995 1.85l-6.999 -.001l-.001 2.587a2 2 0 0 1 -3.414 1.414l-6.586 -6.586a2 2 0 0 1 0 -2.828l6.586 -6.586a2 2 0 0 1 2.18 -.434l.145 .068z" />
4
- </svg>`,M=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
4
+ </svg>`,k=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
5
5
  <path stroke="none" d="M0 0h24v24H0z" fill="none" />
6
6
  <path d="M12.089 3.634a2 2 0 0 0 -1.089 1.78l-.001 2.586h-6.999a2 2 0 0 0 -2 2v4l.005 .15a2 2 0 0 0 1.995 1.85l6.999 -.001l.001 2.587a2 2 0 0 0 3.414 1.414l6.586 -6.586a2 2 0 0 0 0 -2.828l-6.586 -6.586a2 2 0 0 0 -2.18 -.434l-.145 .068z" />
7
- </svg>`;import{EspalierElementBase as y}from"../shared/esp-element-base.js";import{calculatePhotoLayout as R}from"../shared/justified-layout.js";import{ESP_EVENTS as f}from"../shared/events.js";const E=220,U=4,L=8e3;let u=_=class extends y{constructor(){super(...arguments),this.uploadInput=b(),this.previewsDiv=b(),this.dropAreaDiv=b(),this.draggingOver=!1,this.uploadedImages=[],this.accept="image/jpeg, image/png, image/webp",this._rejectionNotice="",this._uploadState=new WeakMap,this._selectionGeneration=0,this._chromeWidth=null,this._resizeObserver=new ResizeObserver(()=>{this._chromeWidth=null,this.requestUpdate()}),this._dragPointerId=null,this._dragSourceIndex=null,this._dragOverIndex=null,this._dragStartX=0,this._dragStartY=0,this._dragActive=!1,this._ghostEl=null,this._ghostHalfW=0,this._ghostHalfH=0,this._arrowEl=null,this._cachedPreviews=null,this._lastDropHit=null,this._savedBodyUserSelect="",this._handleDragPointerDown=e=>{if(e.button!==0||this._dragPointerId!==null||e.composedPath().some(n=>n instanceof HTMLElement&&(n.tagName==="BUTTON"||n.tagName==="ESP-BUTTON")))return;const r=this._getPreviewIndex(e);r!==null&&(this._dragPointerId=e.pointerId,this._dragSourceIndex=r,this._dragStartX=e.clientX,this._dragStartY=e.clientY,this._dragActive=!1,document.addEventListener("pointermove",this._onDocPointerMove),document.addEventListener("pointerup",this._onDocPointerUp),document.addEventListener("pointercancel",this._onDocPointerUp))},this._onDocPointerMove=e=>{if(this._dragSourceIndex===null||e.pointerId!==this._dragPointerId)return;const t=e.clientX-this._dragStartX,r=e.clientY-this._dragStartY;if(!this._dragActive){if(Math.sqrt(t*t+r*r)<_._DRAG_THRESHOLD)return;this._dragActive=!0,this._createGhost(e.clientX,e.clientY);const i=this.shadowRoot?.querySelectorAll("esp-image-preview");i&&(this._cachedPreviews=Array.from(i).map(o=>({el:o,rect:o.getBoundingClientRect()})),this._dragSourceIndex!==null&&this._dragSourceIndex<this._cachedPreviews.length&&(this._cachedPreviews[this._dragSourceIndex].el.style.opacity="0.3")),this._savedBodyUserSelect=document.body.style.userSelect,document.body.style.userSelect="none",this.previewsDiv.value&&(this.previewsDiv.value.style.touchAction="none")}this._ghostEl&&(this._ghostEl.style.transform=`translate(${e.clientX-this._ghostHalfW}px, ${e.clientY-this._ghostHalfH}px)`);const n=this._cachedPreviews;if(!n||n.length===0)return;let s=null,l=!1;for(let i=0;i<n.length;i++){const o=n[i].rect;if(e.clientX>=o.left&&e.clientX<=o.right&&e.clientY>=o.top&&e.clientY<=o.bottom){s=i,l=e.clientX>o.left+o.width/2;break}}if(s===null){let i=1/0;for(let o=0;o<n.length;o++){const a=n[o].rect,d=e.clientX-(a.left+a.width/2),h=e.clientY-(a.top+a.height/2),c=d*d+h*h;c<i&&(i=c,s=o)}if(s!==null){const o=n[s].rect;l=e.clientX>o.left+o.width/2}}s!==null&&(this._dragOverIndex=l?s+1:s,!(this._lastDropHit&&this._lastDropHit.index===s&&this._lastDropHit.after===l)&&(this._lastDropHit={index:s,after:l},this._updateDropTargets(n.map(i=>i.el),s,l)))},this._onDocPointerUp=e=>{if(e.pointerId===this._dragPointerId){if(this._dragActive&&this._dragSourceIndex!==null&&this._dragOverIndex!==null&&this._dragSourceIndex!==this._dragOverIndex&&this._dragSourceIndex+1!==this._dragOverIndex){const t=[...this.uploadedImages],[r]=t.splice(this._dragSourceIndex,1),n=this._dragOverIndex>this._dragSourceIndex?this._dragOverIndex-1:this._dragOverIndex;t.splice(n,0,r),this.uploadedImages=t,this.dispatchEvent(new CustomEvent(f.IMAGE_UPLOAD_IMAGES_REORDERED,{detail:{images:this.uploadedImages},bubbles:!0,composed:!0}))}this._clearDragState()}},this._arrowColor=null,this.filesSelected=async e=>{const t=[],r=[];for(const d of e)(this._isAccepted(d)?t:r).push(d);if(!t.length){r.length&&this._reportRejectedFiles({unsupported:r,unreadable:[]});return}const n=this._selectionGeneration,s=Math.round(E*Math.min(globalThis.devicePixelRatio||1,2)),l=new Array(t.length).fill(null),i=[];let o=0;const a=async()=>{for(;o<t.length;){const d=o++,h=t[d];try{const c=await k(h,{thumbnailHeight:s});if(n!==this._selectionGeneration){I(c);continue}this._addSelectedImage(l,d,c)}catch{i.push(h)}}};await Promise.all(Array.from({length:Math.min(U,t.length)},()=>a())),(r.length||i.length)&&n===this._selectionGeneration&&this._reportRejectedFiles({unsupported:r,unreadable:i})},this._makeCallbacks=e=>({onProgress:t=>{const r=this._uploadState.get(e);r&&(r.progress=t,r.failed=!1,this.requestUpdate())},onComplete:t=>{if(!this._uploadState.get(e))return;e.uploadedId=t,this._uploadState.delete(e),!this.uploadedImages.find(s=>!s.uploadedId)?this.uploadedImages=[...this.uploadedImages]:this.requestUpdate()},onFailed:()=>{const t=this._uploadState.get(e);t&&(t.progress=void 0,t.failed=!0,this.requestUpdate())}}),this._fullPreviewUrls=new Map,this.setExistingImages=e=>{this._selectionGeneration++,this._releaseSelectedImages(),this.uploadedImages=e.filter(t=>t.url&&t.uploadedId&&Number.isFinite(t.width)&&t.width>0&&Number.isFinite(t.height)&&t.height>0).map(t=>({source:"existing",url:t.url,urls:t.urls,height:t.height,width:t.width,uploadedId:t.uploadedId,orientation:t.width>t.height?"landscape":"portrait"})),this._uploadState=new WeakMap}}connectedCallback(){super.connectedCallback(),this._resizeObserver.observe(this)}disconnectedCallback(){super.disconnectedCallback(),this._resizeObserver.disconnect(),this._clearDragState(),clearTimeout(this._noticeTimer),this._selectionGeneration++,this._releaseSelectedImages()}_getPreviewIndex(e){const t=this.shadowRoot?.querySelectorAll("esp-image-preview");if(!t)return null;for(const r of e.composedPath())if(r instanceof HTMLElement&&r.tagName==="ESP-IMAGE-PREVIEW"){for(let n=0;n<t.length;n++)if(t[n]===r)return n}return null}_clearDragState(){document.removeEventListener("pointermove",this._onDocPointerMove),document.removeEventListener("pointerup",this._onDocPointerUp),document.removeEventListener("pointercancel",this._onDocPointerUp),this._dragActive&&(this._cachedPreviews&&this._dragSourceIndex!==null&&this._dragSourceIndex<this._cachedPreviews.length&&(this._cachedPreviews[this._dragSourceIndex].el.style.opacity=""),this._clearDropTargets(),document.body.style.userSelect=this._savedBodyUserSelect,this.previewsDiv.value&&(this.previewsDiv.value.style.touchAction="")),this._ghostEl?.remove(),this._ghostEl=null,this._cachedPreviews=null,this._lastDropHit=null,this._dragPointerId=null,this._dragSourceIndex=null,this._dragOverIndex=null,this._dragActive=!1}_createGhost(e,t){const r=this.shadowRoot?.querySelectorAll("esp-image-preview");if(!r||this._dragSourceIndex===null)return;const n=r[this._dragSourceIndex],s=n.getBoundingClientRect(),l=document.createElement("div"),i=Math.min(120/s.width,120/s.height),o=s.width*i,a=s.height*i;l.style.cssText=`
7
+ </svg>`;import{EspalierElementBase as D}from"../shared/esp-element-base.js";import{calculateAlbumLayout as C,DEFAULT_ALBUM_MAX_ROW_HEIGHT_VH as L,normalizeAlbumMaxRowHeightVh as O}from"../shared/justified-layout.js";import{ESP_EVENTS as v}from"../shared/events.js";import{viewportSize as H}from"../shared/viewport.js";const S=220,T=4,$=8e3;let c=m=class extends D{constructor(){super(...arguments),this.uploadInput=I(),this.previewsDiv=I(),this.dropAreaDiv=I(),this.draggingOver=!1,this.uploadedImages=[],this.accept="image/jpeg, image/png, image/webp",this.maxRowHeightVh=L,this._rejectionNotice="",this._uploadState=new WeakMap,this._selectionGeneration=0,this._chromeWidth=null,this._resizeObserver=new ResizeObserver(()=>{this._chromeWidth=null,this.requestUpdate()}),this._handleViewportResize=()=>{this._chromeWidth=null,this.requestUpdate()},this._dragPointerId=null,this._dragSourceIndex=null,this._dragOverIndex=null,this._dragStartX=0,this._dragStartY=0,this._dragActive=!1,this._ghostEl=null,this._ghostHalfW=0,this._ghostHalfH=0,this._arrowEl=null,this._cachedPreviews=null,this._lastDropHit=null,this._savedBodyUserSelect="",this._handleDragPointerDown=e=>{if(e.button!==0||this._dragPointerId!==null||e.composedPath().some(o=>o instanceof HTMLElement&&(o.tagName==="BUTTON"||o.tagName==="ESP-BUTTON")))return;const i=this._getPreviewIndex(e);i!==null&&(this._dragPointerId=e.pointerId,this._dragSourceIndex=i,this._dragStartX=e.clientX,this._dragStartY=e.clientY,this._dragActive=!1,document.addEventListener("pointermove",this._onDocPointerMove),document.addEventListener("pointerup",this._onDocPointerUp),document.addEventListener("pointercancel",this._onDocPointerUp))},this._onDocPointerMove=e=>{if(this._dragSourceIndex===null||e.pointerId!==this._dragPointerId)return;const t=e.clientX-this._dragStartX,i=e.clientY-this._dragStartY;if(!this._dragActive){if(Math.sqrt(t*t+i*i)<m._DRAG_THRESHOLD)return;this._dragActive=!0,this._createGhost(e.clientX,e.clientY);const n=this.shadowRoot?.querySelectorAll("esp-image-preview");n&&(this._cachedPreviews=Array.from(n).map(s=>({el:s,rect:s.getBoundingClientRect()})),this._dragSourceIndex!==null&&this._dragSourceIndex<this._cachedPreviews.length&&(this._cachedPreviews[this._dragSourceIndex].el.style.opacity="0.3")),this._savedBodyUserSelect=document.body.style.userSelect,document.body.style.userSelect="none",this.previewsDiv.value&&(this.previewsDiv.value.style.touchAction="none")}this._ghostEl&&(this._ghostEl.style.transform=`translate(${e.clientX-this._ghostHalfW}px, ${e.clientY-this._ghostHalfH}px)`);const o=this._cachedPreviews;if(!o||o.length===0)return;let r=null,d=!1;for(let n=0;n<o.length;n++){const s=o[n].rect;if(e.clientX>=s.left&&e.clientX<=s.right&&e.clientY>=s.top&&e.clientY<=s.bottom){r=n,d=e.clientX>s.left+s.width/2;break}}if(r===null){let n=1/0;for(let s=0;s<o.length;s++){const l=o[s].rect,a=e.clientX-(l.left+l.width/2),h=e.clientY-(l.top+l.height/2),p=a*a+h*h;p<n&&(n=p,r=s)}if(r!==null){const s=o[r].rect;d=e.clientX>s.left+s.width/2}}r!==null&&(this._dragOverIndex=d?r+1:r,!(this._lastDropHit&&this._lastDropHit.index===r&&this._lastDropHit.after===d)&&(this._lastDropHit={index:r,after:d},this._updateDropTargets(o.map(n=>n.el),r,d)))},this._onDocPointerUp=e=>{if(e.pointerId===this._dragPointerId){if(this._dragActive&&this._dragSourceIndex!==null&&this._dragOverIndex!==null&&this._dragSourceIndex!==this._dragOverIndex&&this._dragSourceIndex+1!==this._dragOverIndex){const t=[...this.uploadedImages],[i]=t.splice(this._dragSourceIndex,1),o=this._dragOverIndex>this._dragSourceIndex?this._dragOverIndex-1:this._dragOverIndex;t.splice(o,0,i),this.uploadedImages=t,this.dispatchEvent(new CustomEvent(v.IMAGE_UPLOAD_IMAGES_REORDERED,{detail:{images:this.uploadedImages},bubbles:!0,composed:!0}))}this._clearDragState()}},this._arrowColor=null,this.filesSelected=async e=>{const t=[],i=[];for(const a of e)(this._isAccepted(a)?t:i).push(a);if(!t.length){i.length&&this._reportRejectedFiles({unsupported:i,unreadable:[]});return}const o=this._selectionGeneration,r=Math.round(S*Math.min(globalThis.devicePixelRatio||1,2)),d=new Array(t.length).fill(null),n=[];let s=0;const l=async()=>{for(;s<t.length;){const a=s++,h=t[a];try{const p=await M(h,{thumbnailHeight:r});if(o!==this._selectionGeneration){y(p);continue}this._addSelectedImage(d,a,p)}catch{n.push(h)}}};await Promise.all(Array.from({length:Math.min(T,t.length)},()=>l())),(i.length||n.length)&&o===this._selectionGeneration&&this._reportRejectedFiles({unsupported:i,unreadable:n})},this._makeCallbacks=e=>({onProgress:t=>{const i=this._uploadState.get(e);i&&(i.progress=t,i.failed=!1,this.requestUpdate())},onComplete:t=>{if(!this._uploadState.get(e))return;e.uploadedId=t,this._uploadState.delete(e),!this.uploadedImages.find(r=>!r.uploadedId)?this.uploadedImages=[...this.uploadedImages]:this.requestUpdate()},onFailed:()=>{const t=this._uploadState.get(e);t&&(t.progress=void 0,t.failed=!0,this.requestUpdate())}}),this._fullPreviewUrls=new Map,this.setExistingImages=e=>{this._selectionGeneration++,this._releaseSelectedImages(),this.uploadedImages=e.filter(t=>t.url&&t.uploadedId&&Number.isFinite(t.width)&&t.width>0&&Number.isFinite(t.height)&&t.height>0).map(t=>({source:"existing",url:t.url,urls:t.urls,height:t.height,width:t.width,uploadedId:t.uploadedId,orientation:t.width>t.height?"landscape":"portrait"})),this._uploadState=new WeakMap}}connectedCallback(){super.connectedCallback(),this._resizeObserver.observe(this),window.addEventListener("resize",this._handleViewportResize)}disconnectedCallback(){super.disconnectedCallback(),this._resizeObserver.disconnect(),window.removeEventListener("resize",this._handleViewportResize),this._clearDragState(),clearTimeout(this._noticeTimer),this._selectionGeneration++,this._releaseSelectedImages()}_getPreviewIndex(e){const t=this.shadowRoot?.querySelectorAll("esp-image-preview");if(!t)return null;for(const i of e.composedPath())if(i instanceof HTMLElement&&i.tagName==="ESP-IMAGE-PREVIEW"){for(let o=0;o<t.length;o++)if(t[o]===i)return o}return null}_clearDragState(){document.removeEventListener("pointermove",this._onDocPointerMove),document.removeEventListener("pointerup",this._onDocPointerUp),document.removeEventListener("pointercancel",this._onDocPointerUp),this._dragActive&&(this._cachedPreviews&&this._dragSourceIndex!==null&&this._dragSourceIndex<this._cachedPreviews.length&&(this._cachedPreviews[this._dragSourceIndex].el.style.opacity=""),this._clearDropTargets(),document.body.style.userSelect=this._savedBodyUserSelect,this.previewsDiv.value&&(this.previewsDiv.value.style.touchAction="")),this._ghostEl?.remove(),this._ghostEl=null,this._cachedPreviews=null,this._lastDropHit=null,this._dragPointerId=null,this._dragSourceIndex=null,this._dragOverIndex=null,this._dragActive=!1}_createGhost(e,t){const i=this.shadowRoot?.querySelectorAll("esp-image-preview");if(!i||this._dragSourceIndex===null)return;const o=i[this._dragSourceIndex],r=o.getBoundingClientRect(),d=document.createElement("div"),n=Math.min(120/r.width,120/r.height),s=r.width*n,l=r.height*n;d.style.cssText=`
8
8
  position: fixed;
9
9
  left: 0;
10
10
  top: 0;
11
11
  z-index: 10001;
12
12
  pointer-events: none;
13
- width: ${o}px;
14
- height: ${a}px;
13
+ width: ${s}px;
14
+ height: ${l}px;
15
15
  border: 2px dashed var(--esp-color-action-background, #4aa);
16
16
  border-radius: var(--esp-size-border-radius, 4px);
17
17
  background-size: cover;
18
18
  background-position: center;
19
19
  opacity: 0.85;
20
20
  will-change: transform;
21
- transform: translate(${e-o/2}px, ${t-a/2}px);
22
- `;const d=n.shadowRoot?.querySelector("img");d&&(l.style.backgroundImage=`url(${d.src})`),document.body.appendChild(l),this._ghostEl=l,this._ghostHalfW=o/2,this._ghostHalfH=a/2}_updateDropTargets(e,t,r){for(let d=0;d<e.length;d++){const h=e[d];d===t&&d!==this._dragSourceIndex?h.setAttribute("data-drop-side",r?"right":"left"):h.removeAttribute("data-drop-side")}if(t===this._dragSourceIndex){this._arrowEl&&(this._arrowEl.style.display="none");return}const n=this._cachedPreviews,s=n?n[t].rect:e[t].getBoundingClientRect(),l=r?M:C;if(!this._arrowEl){const d=document.createElement("div");d.style.cssText=`
21
+ transform: translate(${e-s/2}px, ${t-l/2}px);
22
+ `;const a=o.shadowRoot?.querySelector("img");a&&(d.style.backgroundImage=`url(${a.src})`),document.body.appendChild(d),this._ghostEl=d,this._ghostHalfW=s/2,this._ghostHalfH=l/2}_updateDropTargets(e,t,i){for(let a=0;a<e.length;a++){const h=e[a];a===t&&a!==this._dragSourceIndex?h.setAttribute("data-drop-side",i?"right":"left"):h.removeAttribute("data-drop-side")}if(t===this._dragSourceIndex){this._arrowEl&&(this._arrowEl.style.display="none");return}const o=this._cachedPreviews,r=o?o[t].rect:e[t].getBoundingClientRect(),d=i?k:U;if(!this._arrowEl){const a=document.createElement("div");a.style.cssText=`
23
23
  position: fixed;
24
24
  left: 0;
25
25
  top: 0;
@@ -30,38 +30,38 @@ var g=function(v,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnP
30
30
  justify-content: center;
31
31
  will-change: transform;
32
32
  filter: drop-shadow(0 1px 3px rgba(0,0,0,0.4));
33
- `,document.body.appendChild(d),this._arrowEl=d;const h=e[t],p=getComputedStyle(h).getPropertyValue("--esp-color-complementary").trim();this._arrowColor=p?`oklch(from ${p} var(--esp-l-accent) c h)`:"oklch(0.7 0.2 330)"}this._arrowEl.innerHTML=l;const i=this._arrowEl.querySelector("svg");i&&(i.style.width="40px",i.style.height="40px",i.style.color=this._arrowColor??"oklch(0.7 0.2 330)"),this._arrowEl.style.display="flex";const o=r?s.left+s.width*.75:s.left+s.width*.25,a=s.top+s.height/2;this._arrowEl.style.transform=`translate(${o-20}px, ${a-20}px)`}_clearDropTargets(){const e=this.shadowRoot?.querySelectorAll("esp-image-preview");if(e)for(const t of e)t.removeAttribute("data-drop-side");this._arrowEl?.remove(),this._arrowEl=null,this._arrowColor=null}getContainerWidth(){const e=this.parentElement??this.offsetParent,t=e?e.getBoundingClientRect().width:window.innerWidth;if(t<=0){const r=window.innerWidth;return r<640?r-32:r<1024?r*90/100-32:Math.min(r*85/100-32,1400)}if(this._chromeWidth===null){const r=this.previewsDiv.value;if(r){const n=a=>{const d=parseFloat(a);return Number.isFinite(d)?d:0},s=getComputedStyle(r),l=n(s.paddingLeft)+n(s.paddingRight),i=this.shadowRoot?.querySelector(".esp-field"),o=i?n(getComputedStyle(i).borderLeftWidth)+n(getComputedStyle(i).borderRightWidth):0;this._chromeWidth=l+o}}return Math.max(t-(this._chromeWidth??0),1)}_isAccepted(e){const t=this.accept.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);if(!t.length)return e.type.toLowerCase().startsWith("image/");const r=e.type.toLowerCase(),n=e.name.toLowerCase();return t.some(s=>s.startsWith(".")?n.endsWith(s):s.endsWith("/*")?r.startsWith(s.slice(0,-1)):r===s)}_addSelectedImage(e,t,r){e[t]=r;const n=[...this.uploadedImages];let s=-1;for(let i=t-1;i>=0&&s<0;i--){const o=e[i];if(!o)continue;const a=n.indexOf(o);a>=0&&(s=a+1)}for(let i=t+1;i<e.length&&s<0;i++){const o=e[i];if(!o)continue;const a=n.indexOf(o);a>=0&&(s=a)}s<0&&(s=n.length),n.splice(s,0,r);const l=new AbortController;this._uploadState.set(r,{progress:null,failed:!1,controller:l}),this.uploadedImages=n,this.dispatchEvent(new CustomEvent(f.IMAGE_UPLOAD_FILE_SELECTED,{detail:{image:r,signal:l.signal,...this._makeCallbacks(r)},bubbles:!0,composed:!0}))}_reportRejectedFiles(e){this.dispatchEvent(new CustomEvent(f.IMAGE_UPLOAD_FILES_REJECTED,{detail:e,bubbles:!0,composed:!0}));const t=n=>n===1?"file":"files",r=[];e.unsupported.length&&r.push(`${e.unsupported.length} unsupported ${t(e.unsupported.length)} skipped`),e.unreadable.length&&r.push(`${e.unreadable.length} ${t(e.unreadable.length)} could not be read`),this._rejectionNotice=r.join("; "),clearTimeout(this._noticeTimer),this._noticeTimer=setTimeout(()=>{this._rejectionNotice=""},L)}_previewUrlFor(e,t){if(e.source!=="selected")return this._pickExistingPreviewUrl(e,t);const r=Math.min(globalThis.devicePixelRatio||1,2),n=E*r;if(t*r<=n*_._THUMBNAIL_UPSCALE_SLACK||e.height<=n)return e.url;let i=this._fullPreviewUrls.get(e);return i||(i=URL.createObjectURL(e.file),this._fullPreviewUrls.set(e,i)),i}_pickExistingPreviewUrl(e,t){const r=e.urls;if(!r?.length)return e.url;const n=Math.min(globalThis.devicePixelRatio||1,2),s=e.height>0?e.width/e.height:1,l=t*s*n,i=[...r].sort((a,d)=>a.minWidth-d.minWidth);return(i.find(a=>a.minWidth>=l)??i[i.length-1]).url}_releaseFullPreviewUrl(e){if(e.source!=="selected")return;const t=this._fullPreviewUrls.get(e);t&&(URL.revokeObjectURL(t),this._fullPreviewUrls.delete(e))}_releaseSelectedImages(){for(const e of this.uploadedImages)e.source==="selected"&&(this._uploadState.get(e)?.controller.abort(),I(e));for(const e of this._fullPreviewUrls.values())URL.revokeObjectURL(e);this._fullPreviewUrls.clear()}render(){const{draggingOver:e,uploadedImages:t}=this,r={"dragging-over":e,"has-previews":t.length},n=this.getContainerWidth(),s=window.innerHeight>0?window.innerHeight/2:Number.POSITIVE_INFINITY,l=R(t,n,E,8,s);return m` <div
33
+ `,document.body.appendChild(a),this._arrowEl=a;const h=e[t],u=getComputedStyle(h).getPropertyValue("--esp-color-complementary").trim();this._arrowColor=u?`oklch(from ${u} var(--esp-l-accent) c h)`:"oklch(0.7 0.2 330)"}this._arrowEl.innerHTML=d;const n=this._arrowEl.querySelector("svg");n&&(n.style.width="40px",n.style.height="40px",n.style.color=this._arrowColor??"oklch(0.7 0.2 330)"),this._arrowEl.style.display="flex";const s=i?r.left+r.width*.75:r.left+r.width*.25,l=r.top+r.height/2;this._arrowEl.style.transform=`translate(${s-20}px, ${l-20}px)`}_clearDropTargets(){const e=this.shadowRoot?.querySelectorAll("esp-image-preview");if(e)for(const t of e)t.removeAttribute("data-drop-side");this._arrowEl?.remove(),this._arrowEl=null,this._arrowColor=null}getContainerWidth(){const e=this.parentElement??this.offsetParent,t=e?e.getBoundingClientRect().width:window.innerWidth;if(t<=0){const i=window.innerWidth;return i<640?i-32:i<1024?i*90/100-32:Math.min(i*85/100-32,1400)}if(this._chromeWidth===null){const i=this.previewsDiv.value;if(i){const o=l=>{const a=parseFloat(l);return Number.isFinite(a)?a:0},r=getComputedStyle(i),d=o(r.paddingLeft)+o(r.paddingRight),n=this.shadowRoot?.querySelector(".esp-field"),s=n?o(getComputedStyle(n).borderLeftWidth)+o(getComputedStyle(n).borderRightWidth):0;this._chromeWidth=d+s}}return Math.max(t-(this._chromeWidth??0),1)}_isAccepted(e){const t=this.accept.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean);if(!t.length)return e.type.toLowerCase().startsWith("image/");const i=e.type.toLowerCase(),o=e.name.toLowerCase();return t.some(r=>r.startsWith(".")?o.endsWith(r):r.endsWith("/*")?i.startsWith(r.slice(0,-1)):i===r)}_addSelectedImage(e,t,i){e[t]=i;const o=[...this.uploadedImages];let r=-1;for(let n=t-1;n>=0&&r<0;n--){const s=e[n];if(!s)continue;const l=o.indexOf(s);l>=0&&(r=l+1)}for(let n=t+1;n<e.length&&r<0;n++){const s=e[n];if(!s)continue;const l=o.indexOf(s);l>=0&&(r=l)}r<0&&(r=o.length),o.splice(r,0,i);const d=new AbortController;this._uploadState.set(i,{progress:null,failed:!1,controller:d}),this.uploadedImages=o,this.dispatchEvent(new CustomEvent(v.IMAGE_UPLOAD_FILE_SELECTED,{detail:{image:i,signal:d.signal,...this._makeCallbacks(i)},bubbles:!0,composed:!0}))}_reportRejectedFiles(e){this.dispatchEvent(new CustomEvent(v.IMAGE_UPLOAD_FILES_REJECTED,{detail:e,bubbles:!0,composed:!0}));const t=o=>o===1?"file":"files",i=[];e.unsupported.length&&i.push(`${e.unsupported.length} unsupported ${t(e.unsupported.length)} skipped`),e.unreadable.length&&i.push(`${e.unreadable.length} ${t(e.unreadable.length)} could not be read`),this._rejectionNotice=i.join("; "),clearTimeout(this._noticeTimer),this._noticeTimer=setTimeout(()=>{this._rejectionNotice=""},$)}_previewUrlFor(e,t,i){const o=e.width>0&&e.height>0?e.width/e.height:1,r=Math.max(t,(i??0)/o);if(e.source!=="selected")return this._pickExistingPreviewUrl(e,r);const d=Math.min(globalThis.devicePixelRatio||1,2),n=S*d;if(r*d<=n*m._THUMBNAIL_UPSCALE_SLACK||e.height<=n)return e.url;let a=this._fullPreviewUrls.get(e);return a||(a=URL.createObjectURL(e.file),this._fullPreviewUrls.set(e,a)),a}_pickExistingPreviewUrl(e,t){const i=e.urls;if(!i?.length)return e.url;const o=Math.min(globalThis.devicePixelRatio||1,2),r=e.height>0?e.width/e.height:1,d=t*r*o,n=[...i].sort((l,a)=>l.minWidth-a.minWidth);return(n.find(l=>l.minWidth>=d)??n[n.length-1]).url}_releaseFullPreviewUrl(e){if(e.source!=="selected")return;const t=this._fullPreviewUrls.get(e);t&&(URL.revokeObjectURL(t),this._fullPreviewUrls.delete(e))}_releaseSelectedImages(){for(const e of this.uploadedImages)e.source==="selected"&&(this._uploadState.get(e)?.controller.abort(),y(e));for(const e of this._fullPreviewUrls.values())URL.revokeObjectURL(e);this._fullPreviewUrls.clear()}render(){const{draggingOver:e,uploadedImages:t}=this,i={"dragging-over":e,"has-previews":t.length},o=this.getContainerWidth(),{height:r}=H(),d=r>0?r*O(this.maxRowHeightVh)/100:Number.POSITIVE_INFINITY,n=C(t,{containerWidth:o,targetRowHeight:S,gap:8,maxRowHeight:d,maxImagesPerRow:this.maxImagesPerRow});return w` <div
34
34
  class="esp-field"
35
35
  @click=${()=>{this.dropAreaDiv.value?.focus({preventScroll:!0})}}
36
- @dragover=${i=>{i.preventDefault(),this.draggingOver=!0}}
37
- @dragleave=${i=>{i.preventDefault(),this.draggingOver=!1}}
38
- @drop=${i=>{i.preventDefault(),this.draggingOver=!1;const o=i.dataTransfer?.files;o&&o.length&&this.filesSelected(o)}}
36
+ @dragover=${s=>{s.preventDefault(),this.draggingOver=!0}}
37
+ @dragleave=${s=>{s.preventDefault(),this.draggingOver=!1}}
38
+ @drop=${s=>{s.preventDefault(),this.draggingOver=!1;const l=s.dataTransfer?.files;l&&l.length&&this.filesSelected(l)}}
39
39
  >
40
40
  <div
41
- ${x(this.previewsDiv)}
42
- class=${S({previews:!0,...r})}
41
+ ${E(this.previewsDiv)}
42
+ class=${P({previews:!0,...i})}
43
43
  @pointerdown=${this._handleDragPointerDown}
44
44
  >
45
- ${l.map(i=>m`<div class="photo-row" style="height: ${i.height}px;">
46
- ${i.images.map(o=>{const a=i.height,d=o.width/o.height*a,h=this._uploadState.get(o);return m`<esp-image-preview
47
- style="width: ${d}px; height: ${a}px; flex-shrink: 0;"
48
- .url=${this._previewUrlFor(o,a)}
49
- .alt=${o.source==="selected"?o.file.name:""}
50
- .progress=${h?.progress}
51
- .failed=${h?.failed??!1}
52
- @esp-internal-image-preview-remove=${()=>{const c=this.uploadedImages.indexOf(o);if(c<0)return;this._uploadState.get(o)?.controller.abort(),this._uploadState.delete(o),I(o),this._releaseFullPreviewUrl(o);const p=[...this.uploadedImages];p.splice(c,1),this.uploadedImages=p,this.dispatchEvent(new CustomEvent(f.IMAGE_UPLOAD_FILE_REMOVED,{detail:o,bubbles:!0,composed:!0}))}}
53
- @esp-internal-image-preview-retry=${()=>{if(o.source!=="selected")return;const c=new AbortController,p=this._uploadState.get(o);p?(p.failed=!1,p.progress=null,p.controller=c):this._uploadState.set(o,{progress:null,failed:!1,controller:c}),this.requestUpdate(),this.dispatchEvent(new CustomEvent(f.IMAGE_UPLOAD_RETRY,{detail:{image:o,signal:c.signal,...this._makeCallbacks(o)},bubbles:!0,composed:!0}))}}
45
+ ${n.map(s=>w`<div class="photo-row" style="height: ${s.height}px;">
46
+ ${s.items.map(({image:l,width:a})=>{const h=s.height,p=this._uploadState.get(l);return w`<esp-image-preview
47
+ style="width: ${a}px; height: ${h}px; flex-shrink: 0;"
48
+ .url=${this._previewUrlFor(l,h,a)}
49
+ .alt=${l.source==="selected"?l.file.name:""}
50
+ .progress=${p?.progress}
51
+ .failed=${p?.failed??!1}
52
+ @esp-internal-image-preview-remove=${()=>{const u=this.uploadedImages.indexOf(l);if(u<0)return;this._uploadState.get(l)?.controller.abort(),this._uploadState.delete(l),y(l),this._releaseFullPreviewUrl(l);const g=[...this.uploadedImages];g.splice(u,1),this.uploadedImages=g,this.dispatchEvent(new CustomEvent(v.IMAGE_UPLOAD_FILE_REMOVED,{detail:l,bubbles:!0,composed:!0}))}}
53
+ @esp-internal-image-preview-retry=${()=>{if(l.source!=="selected")return;const u=new AbortController,g=this._uploadState.get(l);g?(g.failed=!1,g.progress=null,g.controller=u):this._uploadState.set(l,{progress:null,failed:!1,controller:u}),this.requestUpdate(),this.dispatchEvent(new CustomEvent(v.IMAGE_UPLOAD_RETRY,{detail:{image:l,signal:u.signal,...this._makeCallbacks(l)},bubbles:!0,composed:!0}))}}
54
54
  ></esp-image-preview>`})}
55
55
  </div>`)}
56
56
  </div>
57
57
  <div
58
- ${x(this.dropAreaDiv)}
58
+ ${E(this.dropAreaDiv)}
59
59
  tabindex="0"
60
60
  role="button"
61
61
  aria-label="Add photos"
62
- class=${S({"drop-area":!0,...r})}
62
+ class=${P({"drop-area":!0,...i})}
63
63
  @click=${()=>{this.uploadInput.value?.click()}}
64
- @keydown=${i=>{(i.code==="Enter"||i.code==="Space")&&(i.preventDefault(),this.uploadInput.value?.click())}}
64
+ @keydown=${s=>{(s.code==="Enter"||s.code==="Space")&&(s.preventDefault(),this.uploadInput.value?.click())}}
65
65
  >
66
66
  <svg
67
67
  xmlns="http://www.w3.org/2000/svg"
@@ -104,14 +104,14 @@ var g=function(v,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnP
104
104
  <p class="rejection-notice" role="status">${this._rejectionNotice}</p>
105
105
  </div>
106
106
  <input
107
- ${x(this.uploadInput)}
107
+ ${E(this.uploadInput)}
108
108
  type="file"
109
109
  multiple
110
110
  accept=${this.accept}
111
111
  hidden
112
- @change=${()=>{const i=this.uploadInput.value;!i||!i.files||!i.files.length||(this.filesSelected(i.files),i.value="")}}
112
+ @change=${()=>{const s=this.uploadInput.value;!s||!s.files||!s.files.length||(this.filesSelected(s.files),s.value="")}}
113
113
  />
114
- </div>`}};u._DRAG_THRESHOLD=8,u._THUMBNAIL_UPSCALE_SLACK=1.1,u.styles=[...y.styles,P`
114
+ </div>`}};c._DRAG_THRESHOLD=8,c._THUMBNAIL_UPSCALE_SLACK=1.1,c.styles=[...D.styles,A`
115
115
  :host {
116
116
  overflow: hidden;
117
117
  }
@@ -237,4 +237,4 @@ var g=function(v,e,t,r){var n=arguments.length,s=n<3?e:r===null?r=Object.getOwnP
237
237
  }
238
238
  }
239
239
  }
240
- `],g([w()],u.prototype,"draggingOver",void 0),g([w()],u.prototype,"uploadedImages",void 0),g([A({type:String})],u.prototype,"accept",void 0),g([w()],u.prototype,"_rejectionNotice",void 0),u=_=g([D("esp-image-upload")],u);export{u as EspalierImageUpload};
240
+ `],f([b()],c.prototype,"draggingOver",void 0),f([b()],c.prototype,"uploadedImages",void 0),f([x({type:String})],c.prototype,"accept",void 0),f([x({attribute:"max-images-per-row",type:Number})],c.prototype,"maxImagesPerRow",void 0),f([x({attribute:"max-row-height-vh",type:Number})],c.prototype,"maxRowHeightVh",void 0),f([b()],c.prototype,"_rejectionNotice",void 0),c=m=f([R("esp-image-upload")],c);export{c as EspalierImageUpload};
package/dist/index.d.ts CHANGED
@@ -71,7 +71,7 @@ export { requestHelp, type HelpRequest, type HelpState } from "./shared/help-eve
71
71
  export { getEspBus, type EspBusEventMap, type SchemeEvents, type ToastEvents, type FlyoutEvents, type HelpEvents, type PopoverEvents, type SizeEvents, type PageEventMap, type SeedColorRoot, } from "./shared/bus-events.js";
72
72
  export * from "./shared/events.js";
73
73
  export { getImageDetails, releasePreviewUrl, type EspalierUploadImage, type ImageDetailsOptions, type SelectedUploadImage, type ExistingUploadImage, type ExistingImage, type ResponsiveImageUrl, type UploadCallbacks, type UploadEventDetail, } from "./image-upload/image-helpers.js";
74
- export { calculatePhotoLayout, type LayoutImage, type PhotoRow, } from "./shared/justified-layout.js";
74
+ export { calculateAlbumLayout, calculatePhotoLayout, DEFAULT_ALBUM_MAX_ROW_HEIGHT_VH, normalizeAlbumMaxRowHeightVh, normalizeMaxImagesPerRow, type AlbumLayoutItem, type AlbumLayoutOptions, type AlbumLayoutRow, type LayoutImage, type PhotoRow, } from "./shared/justified-layout.js";
75
75
  export { type TypeaheadFetchItems } from "./pickers/types.js";
76
76
  export { type EspalierTheme, type LightnessKey, type LightnessReference, type PartialTheme, type PartialThemeContexts, type PartialThemeTones, type ThemeContext, type ThemeContexts, type ThemeTones, type ToneReference, type VariantColorSource, encodeTheme, parseTheme, mergePartials, layerThemes, validateThemePair, resolveContextTheme, isObjectRecord, isSemanticColorName, buildTaprootLightTheme, buildTaprootDarkTheme, NESTED_THEME_KEYS, } from "./shared/theme.js";
77
77
  export { auditDataPalette, describePaletteCollision, generateSequentialRamp, generateDivergingRamp, COLOR_VISION_SIMULATIONS, DATA_SERIES_KEYS, DEFAULT_DATA_PALETTE, DEFAULT_DATA_RAMP_STEPS, DEFAULT_DIVERGING_NEUTRAL, MAX_DATA_RAMP_STEPS, MIN_DATA_COLOR_DISTANCE, MIN_DATA_RAMP_LIGHTNESS_STEP, MIN_DATA_RAMP_STEPS, type ColorVisionSimulation, type DataPalette, type DataPaletteIssue, type DataRamp, type DataRamps, type DataSeriesKey, type DivergingDataRamp, type DivergingRampOptions, type PartialDataRamp, type PartialDataRamps, type SequentialDataRamp, type SequentialRampOptions, } from "./shared/data-colors.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export*from"./box/esp-box.js";export*from"./action-menu/esp-action-menu.js";export*from"./action-menu/esp-action-menu-item.js";export*from"./avatar/esp-avatar.js";export*from"./avatar/esp-profile-chip.js";export*from"./badge/esp-badge.js";export*from"./checkbox/esp-checkbox.js";export*from"./checkbox/esp-checkbox-group.js";export*from"./data-cell/esp-data-cell.js";export*from"./radio-button/esp-radio-button.js";export*from"./radio-button/esp-radio-button-group.js";export*from"./repeater/esp-repeater.js";export*from"./breadcrumbs/esp-breadcrumbs.js";export*from"./button/esp-button.js";export*from"./button/esp-button-group.js";export*from"./color-picker/esp-color-picker.js";export*from"./flyout/esp-flyout.js";export*from"./form/esp-form.js";export*from"./form-item/esp-form-item.js";export*from"./help/esp-help-button.js";export*from"./help/esp-help-provider.js";export*from"./header/index.js";export*from"./page/esp-page.js";export*from"./section/esp-section.js";export*from"./stack/esp-stack.js";export*from"./row/esp-row.js";export*from"./popover/esp-popover.js";export*from"./dialog/esp-dialog.js";export*from"./empty-state/esp-empty-state.js";export*from"./image-upload/esp-image-upload.js";export*from"./file-upload/esp-file-upload.js";export*from"./font-picker/esp-font-picker.js";export*from"./focus-picker/esp-focus-picker.js";export*from"./footer/index.js";export*from"./grid/esp-grid.js";export*from"./image/esp-image.js";export*from"./image/image-focus.js";export*from"./lightbox/esp-lightbox.js";export*from"./info/esp-info.js";export*from"./input/esp-input.js";export*from"./textarea/esp-textarea.js";export*from"./pickers/esp-pick-one.js";export*from"./pickers/esp-pick-some.js";export*from"./pickers/esp-picker-menu.js";export*from"./pickers/esp-picker-item.js";export*from"./root/esp-root.js";export*from"./menu/index.js";export*from"./burger/esp-burger.js";export*from"./date-picker/esp-date-picker.js";export*from"./details/esp-details.js";export*from"./details/esp-details-group.js";export*from"./tabs/esp-tab.js";export*from"./tabs/esp-tab-group.js";export*from"./slider/esp-slider.js";export*from"./switch/esp-switch.js";export*from"./toaster/esp-toaster.js";export*from"./tooltip/esp-tooltip.js";export*from"./progress/esp-progress.js";export*from"./search/esp-search.js";export*from"./status-indicator/esp-status-indicator.js";export*from"./tree/esp-tree.js";export*from"./tree/esp-tree-item.js";import{DEFAULT_ICON_SPRITE_URL as _o,DEFAULT_ICON_VIEW_BOX as Io,INTENT_VARIANTS as ao,normalizeIntentVariant as io,getIconHrefForHost as lo,getIconSpriteUrl as Fo,getIconSpriteReference as Ao}from"./shared/intent-values.js";import{EspalierElementBase as So}from"./shared/esp-element-base.js";import{VALIDITY_CHANGED_EVENT as Lo}from"./shared/validation.js";import{FormFieldController as Do}from"./shared/form-field-controller.js";import{traverseToClosest as go}from"./shared/utilities.js";import{showToast as ho}from"./shared/toast-events.js";import{showFlyout as Mo,closeFlyout as Oo}from"./shared/flyout-events.js";import{requestHelp as Co}from"./shared/help-events.js";import{getEspBus as Uo}from"./shared/bus-events.js";export*from"./shared/events.js";import{getImageDetails as vo,releasePreviewUrl as yo}from"./image-upload/image-helpers.js";import{calculatePhotoLayout as ko}from"./shared/justified-layout.js";import{encodeTheme as wo,parseTheme as Bo,mergePartials as Ko,layerThemes as qo,validateThemePair as zo,resolveContextTheme as Xo,isObjectRecord as Yo,isSemanticColorName as jo,buildTaprootLightTheme as Jo,buildTaprootDarkTheme as Qo,NESTED_THEME_KEYS as Zo}from"./shared/theme.js";import{auditDataPalette as oe,describePaletteCollision as ee,generateSequentialRamp as re,generateDivergingRamp as te,COLOR_VISION_SIMULATIONS as me,DATA_SERIES_KEYS as pe,DEFAULT_DATA_PALETTE as Te,DEFAULT_DATA_RAMP_STEPS as fe,DEFAULT_DIVERGING_NEUTRAL as xe,MAX_DATA_RAMP_STEPS as Ee,MIN_DATA_COLOR_DISTANCE as _e,MIN_DATA_RAMP_LIGHTNESS_STEP as Ie,MIN_DATA_RAMP_STEPS as ae}from"./shared/data-colors.js";import{WEIGHT_LABELS as le,extractWeights as Fe,normalizeWeight as Ae,bestAvailableWeight as ne,extractFamily as Se,getFallbackFont as se,googleFontStylesheetUrl as Le,isLocalFontFamily as Re,normalizeFontFaceWeight as De,removeRuntimeGoogleFontLink as Ne,removeRuntimeGoogleFontLinks as ge,syncRuntimeGoogleFontLink as ce,RUNTIME_GOOGLE_FONT_OWNER_ATTR as he}from"./shared/font-helpers.js";import{compileFontPlan as Me,fontFallbackAliases as Oe,fontFallbackBaseIndexes as He,fontFaceRequestKey as Ce}from"./shared/font-plan.js";import{getGoogleFonts as Ue}from"./font-picker/esp-font-picker.js";import{ROOT_SURFACE as de,THEME_FIT_ANCHOR_FIELDS as be,THEME_FIT_APCA_FIELDS as ve,THEME_FIT_DATA_PALETTE_LINT_FIELDS as ye,THEME_FIT_DATA_PALETTE_LINT_IDS as Ve,THEME_FIT_EXPLICIT_VALUES as ke,THEME_FIT_LINT_FIELDS as We,THEME_FIT_LINT_IDS as we,THEME_FIT_LINT_SEVERITIES as Be,THEME_FIT_REPORT_FIELDS as Ke,THEME_FIT_SUITE_FIELDS as qe,THEME_FIT_TOKEN_FIELDS as ze,themeFitReport as Xe,themeFitRows as Ye,themeFitLints as je,themeFitReportSuite as Je,printThemeFitReport as Qe}from"./shared/theme-fit-report.js";import{ICON_SPRITE as $e,ICON_SPRITE_ID as or,installIconSprite as er}from"./icons/index.js";import{deriveLightnessRamp as tr,themeFromSwatches as mr}from"./shared/theme-swatches.js";export{me as COLOR_VISION_SIMULATIONS,pe as DATA_SERIES_KEYS,Te as DEFAULT_DATA_PALETTE,fe as DEFAULT_DATA_RAMP_STEPS,xe as DEFAULT_DIVERGING_NEUTRAL,_o as DEFAULT_ICON_SPRITE_URL,Io as DEFAULT_ICON_VIEW_BOX,So as EspalierElementBase,Do as FormFieldController,$e as ICON_SPRITE,or as ICON_SPRITE_ID,ao as INTENT_VARIANTS,Ee as MAX_DATA_RAMP_STEPS,_e as MIN_DATA_COLOR_DISTANCE,Ie as MIN_DATA_RAMP_LIGHTNESS_STEP,ae as MIN_DATA_RAMP_STEPS,Zo as NESTED_THEME_KEYS,de as ROOT_SURFACE,he as RUNTIME_GOOGLE_FONT_OWNER_ATTR,be as THEME_FIT_ANCHOR_FIELDS,ve as THEME_FIT_APCA_FIELDS,ye as THEME_FIT_DATA_PALETTE_LINT_FIELDS,Ve as THEME_FIT_DATA_PALETTE_LINT_IDS,ke as THEME_FIT_EXPLICIT_VALUES,We as THEME_FIT_LINT_FIELDS,we as THEME_FIT_LINT_IDS,Be as THEME_FIT_LINT_SEVERITIES,Ke as THEME_FIT_REPORT_FIELDS,qe as THEME_FIT_SUITE_FIELDS,ze as THEME_FIT_TOKEN_FIELDS,Lo as VALIDITY_CHANGED_EVENT,le as WEIGHT_LABELS,oe as auditDataPalette,ne as bestAvailableWeight,Qo as buildTaprootDarkTheme,Jo as buildTaprootLightTheme,ko as calculatePhotoLayout,Oo as closeFlyout,Me as compileFontPlan,tr as deriveLightnessRamp,ee as describePaletteCollision,wo as encodeTheme,Se as extractFamily,Fe as extractWeights,Ce as fontFaceRequestKey,Oe as fontFallbackAliases,He as fontFallbackBaseIndexes,te as generateDivergingRamp,re as generateSequentialRamp,Uo as getEspBus,se as getFallbackFont,Ue as getGoogleFonts,lo as getIconHrefForHost,Ao as getIconSpriteReference,Fo as getIconSpriteUrl,vo as getImageDetails,Le as googleFontStylesheetUrl,er as installIconSprite,Re as isLocalFontFamily,Yo as isObjectRecord,jo as isSemanticColorName,qo as layerThemes,Ko as mergePartials,De as normalizeFontFaceWeight,io as normalizeIntentVariant,Ae as normalizeWeight,Bo as parseTheme,Qe as printThemeFitReport,yo as releasePreviewUrl,Ne as removeRuntimeGoogleFontLink,ge as removeRuntimeGoogleFontLinks,Co as requestHelp,Xo as resolveContextTheme,Mo as showFlyout,ho as showToast,ce as syncRuntimeGoogleFontLink,je as themeFitLints,Xe as themeFitReport,Je as themeFitReportSuite,Ye as themeFitRows,mr as themeFromSwatches,go as traverseToClosest,zo as validateThemePair};
1
+ export*from"./box/esp-box.js";export*from"./action-menu/esp-action-menu.js";export*from"./action-menu/esp-action-menu-item.js";export*from"./avatar/esp-avatar.js";export*from"./avatar/esp-profile-chip.js";export*from"./badge/esp-badge.js";export*from"./checkbox/esp-checkbox.js";export*from"./checkbox/esp-checkbox-group.js";export*from"./data-cell/esp-data-cell.js";export*from"./radio-button/esp-radio-button.js";export*from"./radio-button/esp-radio-button-group.js";export*from"./repeater/esp-repeater.js";export*from"./breadcrumbs/esp-breadcrumbs.js";export*from"./button/esp-button.js";export*from"./button/esp-button-group.js";export*from"./color-picker/esp-color-picker.js";export*from"./flyout/esp-flyout.js";export*from"./form/esp-form.js";export*from"./form-item/esp-form-item.js";export*from"./help/esp-help-button.js";export*from"./help/esp-help-provider.js";export*from"./header/index.js";export*from"./page/esp-page.js";export*from"./section/esp-section.js";export*from"./stack/esp-stack.js";export*from"./row/esp-row.js";export*from"./popover/esp-popover.js";export*from"./dialog/esp-dialog.js";export*from"./empty-state/esp-empty-state.js";export*from"./image-upload/esp-image-upload.js";export*from"./file-upload/esp-file-upload.js";export*from"./font-picker/esp-font-picker.js";export*from"./focus-picker/esp-focus-picker.js";export*from"./footer/index.js";export*from"./grid/esp-grid.js";export*from"./image/esp-image.js";export*from"./image/image-focus.js";export*from"./lightbox/esp-lightbox.js";export*from"./info/esp-info.js";export*from"./input/esp-input.js";export*from"./textarea/esp-textarea.js";export*from"./pickers/esp-pick-one.js";export*from"./pickers/esp-pick-some.js";export*from"./pickers/esp-picker-menu.js";export*from"./pickers/esp-picker-item.js";export*from"./root/esp-root.js";export*from"./menu/index.js";export*from"./burger/esp-burger.js";export*from"./date-picker/esp-date-picker.js";export*from"./details/esp-details.js";export*from"./details/esp-details-group.js";export*from"./tabs/esp-tab.js";export*from"./tabs/esp-tab-group.js";export*from"./slider/esp-slider.js";export*from"./switch/esp-switch.js";export*from"./toaster/esp-toaster.js";export*from"./tooltip/esp-tooltip.js";export*from"./progress/esp-progress.js";export*from"./search/esp-search.js";export*from"./status-indicator/esp-status-indicator.js";export*from"./tree/esp-tree.js";export*from"./tree/esp-tree-item.js";import{DEFAULT_ICON_SPRITE_URL as Eo,DEFAULT_ICON_VIEW_BOX as ao,INTENT_VARIANTS as Io,normalizeIntentVariant as lo,getIconHrefForHost as io,getIconSpriteUrl as Fo,getIconSpriteReference as Ao}from"./shared/intent-values.js";import{EspalierElementBase as So}from"./shared/esp-element-base.js";import{VALIDITY_CHANGED_EVENT as so}from"./shared/validation.js";import{FormFieldController as Do}from"./shared/form-field-controller.js";import{traverseToClosest as go}from"./shared/utilities.js";import{showToast as ho}from"./shared/toast-events.js";import{showFlyout as Po,closeFlyout as Ho}from"./shared/flyout-events.js";import{requestHelp as uo}from"./shared/help-events.js";import{getEspBus as Uo}from"./shared/bus-events.js";export*from"./shared/events.js";import{getImageDetails as Vo,releasePreviewUrl as yo}from"./image-upload/image-helpers.js";import{calculateAlbumLayout as Wo,calculatePhotoLayout as ko,DEFAULT_ALBUM_MAX_ROW_HEIGHT_VH as wo,normalizeAlbumMaxRowHeightVh as Bo,normalizeMaxImagesPerRow as zo}from"./shared/justified-layout.js";import{encodeTheme as Xo,parseTheme as qo,mergePartials as Yo,layerThemes as jo,validateThemePair as Jo,resolveContextTheme as Qo,isObjectRecord as Zo,isSemanticColorName as $o,buildTaprootLightTheme as oe,buildTaprootDarkTheme as ee,NESTED_THEME_KEYS as re}from"./shared/theme.js";import{auditDataPalette as me,describePaletteCollision as pe,generateSequentialRamp as Te,generateDivergingRamp as xe,COLOR_VISION_SIMULATIONS as fe,DATA_SERIES_KEYS as _e,DEFAULT_DATA_PALETTE as Ee,DEFAULT_DATA_RAMP_STEPS as ae,DEFAULT_DIVERGING_NEUTRAL as Ie,MAX_DATA_RAMP_STEPS as le,MIN_DATA_COLOR_DISTANCE as ie,MIN_DATA_RAMP_LIGHTNESS_STEP as Fe,MIN_DATA_RAMP_STEPS as Ae}from"./shared/data-colors.js";import{WEIGHT_LABELS as Se,extractWeights as Le,normalizeWeight as se,bestAvailableWeight as Re,extractFamily as De,getFallbackFont as Ne,googleFontStylesheetUrl as ge,isLocalFontFamily as ce,normalizeFontFaceWeight as he,removeRuntimeGoogleFontLink as Me,removeRuntimeGoogleFontLinks as Pe,syncRuntimeGoogleFontLink as He,RUNTIME_GOOGLE_FONT_OWNER_ATTR as Oe}from"./shared/font-helpers.js";import{compileFontPlan as Ce,fontFallbackAliases as Ue,fontFallbackBaseIndexes as Ge,fontFaceRequestKey as be}from"./shared/font-plan.js";import{getGoogleFonts as de}from"./font-picker/esp-font-picker.js";import{ROOT_SURFACE as ve,THEME_FIT_ANCHOR_FIELDS as We,THEME_FIT_APCA_FIELDS as ke,THEME_FIT_DATA_PALETTE_LINT_FIELDS as we,THEME_FIT_DATA_PALETTE_LINT_IDS as Be,THEME_FIT_EXPLICIT_VALUES as ze,THEME_FIT_LINT_FIELDS as Ke,THEME_FIT_LINT_IDS as Xe,THEME_FIT_LINT_SEVERITIES as qe,THEME_FIT_REPORT_FIELDS as Ye,THEME_FIT_SUITE_FIELDS as je,THEME_FIT_TOKEN_FIELDS as Je,themeFitReport as Qe,themeFitRows as Ze,themeFitLints as $e,themeFitReportSuite as or,printThemeFitReport as er}from"./shared/theme-fit-report.js";import{ICON_SPRITE as tr,ICON_SPRITE_ID as mr,installIconSprite as pr}from"./icons/index.js";import{deriveLightnessRamp as xr,themeFromSwatches as fr}from"./shared/theme-swatches.js";export{fe as COLOR_VISION_SIMULATIONS,_e as DATA_SERIES_KEYS,wo as DEFAULT_ALBUM_MAX_ROW_HEIGHT_VH,Ee as DEFAULT_DATA_PALETTE,ae as DEFAULT_DATA_RAMP_STEPS,Ie as DEFAULT_DIVERGING_NEUTRAL,Eo as DEFAULT_ICON_SPRITE_URL,ao as DEFAULT_ICON_VIEW_BOX,So as EspalierElementBase,Do as FormFieldController,tr as ICON_SPRITE,mr as ICON_SPRITE_ID,Io as INTENT_VARIANTS,le as MAX_DATA_RAMP_STEPS,ie as MIN_DATA_COLOR_DISTANCE,Fe as MIN_DATA_RAMP_LIGHTNESS_STEP,Ae as MIN_DATA_RAMP_STEPS,re as NESTED_THEME_KEYS,ve as ROOT_SURFACE,Oe as RUNTIME_GOOGLE_FONT_OWNER_ATTR,We as THEME_FIT_ANCHOR_FIELDS,ke as THEME_FIT_APCA_FIELDS,we as THEME_FIT_DATA_PALETTE_LINT_FIELDS,Be as THEME_FIT_DATA_PALETTE_LINT_IDS,ze as THEME_FIT_EXPLICIT_VALUES,Ke as THEME_FIT_LINT_FIELDS,Xe as THEME_FIT_LINT_IDS,qe as THEME_FIT_LINT_SEVERITIES,Ye as THEME_FIT_REPORT_FIELDS,je as THEME_FIT_SUITE_FIELDS,Je as THEME_FIT_TOKEN_FIELDS,so as VALIDITY_CHANGED_EVENT,Se as WEIGHT_LABELS,me as auditDataPalette,Re as bestAvailableWeight,ee as buildTaprootDarkTheme,oe as buildTaprootLightTheme,Wo as calculateAlbumLayout,ko as calculatePhotoLayout,Ho as closeFlyout,Ce as compileFontPlan,xr as deriveLightnessRamp,pe as describePaletteCollision,Xo as encodeTheme,De as extractFamily,Le as extractWeights,be as fontFaceRequestKey,Ue as fontFallbackAliases,Ge as fontFallbackBaseIndexes,xe as generateDivergingRamp,Te as generateSequentialRamp,Uo as getEspBus,Ne as getFallbackFont,de as getGoogleFonts,io as getIconHrefForHost,Ao as getIconSpriteReference,Fo as getIconSpriteUrl,Vo as getImageDetails,ge as googleFontStylesheetUrl,pr as installIconSprite,ce as isLocalFontFamily,Zo as isObjectRecord,$o as isSemanticColorName,jo as layerThemes,Yo as mergePartials,Bo as normalizeAlbumMaxRowHeightVh,he as normalizeFontFaceWeight,lo as normalizeIntentVariant,zo as normalizeMaxImagesPerRow,se as normalizeWeight,qo as parseTheme,er as printThemeFitReport,yo as releasePreviewUrl,Me as removeRuntimeGoogleFontLink,Pe as removeRuntimeGoogleFontLinks,uo as requestHelp,Qo as resolveContextTheme,Po as showFlyout,ho as showToast,He as syncRuntimeGoogleFontLink,$e as themeFitLints,Qe as themeFitReport,or as themeFitReportSuite,Ze as themeFitRows,fr as themeFromSwatches,go as traverseToClosest,Jo as validateThemePair};
@@ -17,6 +17,60 @@ export interface PhotoRow<T extends LayoutImage = LayoutImage> {
17
17
  images: T[];
18
18
  height: number;
19
19
  }
20
+ /** One image's explicit cell geometry in an album row. */
21
+ export interface AlbumLayoutItem<T extends LayoutImage = LayoutImage> {
22
+ /** The source image, retained by reference. */
23
+ image: T;
24
+ /** The rendered cell width in CSS pixels. */
25
+ width: number;
26
+ }
27
+ /**
28
+ * A row in a bounded album layout.
29
+ *
30
+ * `fillsContainer` is true for completed rows, including rows whose cells
31
+ * widen proportionally at a height ceiling and therefore crop their images.
32
+ * `isPartial` identifies the final, under-filled max-count row, which keeps
33
+ * its image proportions and intentionally leaves its trailing space empty.
34
+ */
35
+ export interface AlbumLayoutRow<T extends LayoutImage = LayoutImage> {
36
+ items: AlbumLayoutItem<T>[];
37
+ height: number;
38
+ isPartial: boolean;
39
+ fillsContainer: boolean;
40
+ }
41
+ /** Options for {@link calculateAlbumLayout}. */
42
+ export interface AlbumLayoutOptions {
43
+ /** Available row width in CSS pixels, before gaps. */
44
+ containerWidth: number;
45
+ /** Preferred row height used while grouping images. Defaults to 220. */
46
+ targetRowHeight?: number;
47
+ /** Horizontal gap between cells. Defaults to 8. */
48
+ gap?: number;
49
+ /** Maximum rendered row height in CSS pixels. Defaults to no ceiling. */
50
+ maxRowHeight?: number;
51
+ /** Positive-integer image count that makes a completed row. */
52
+ maxImagesPerRow?: number;
53
+ }
54
+ /** The default viewport-height ceiling used by bounded album consumers. */
55
+ export declare const DEFAULT_ALBUM_MAX_ROW_HEIGHT_VH = 90;
56
+ /**
57
+ * Normalize the public album viewport-height ceiling.
58
+ *
59
+ * The value is deliberately a percentage rather than an arbitrary pixel
60
+ * count, so a consumer can apply the same policy across responsive layouts.
61
+ */
62
+ export declare function normalizeAlbumMaxRowHeightVh(value: unknown): number;
63
+ /**
64
+ * Resolve a consumer-provided image-row ceiling to a usable positive integer.
65
+ * Values outside `1…maximum`, including non-numbers and non-finite values,
66
+ * return `fallback`. The default fallback and maximum leave row lengths
67
+ * unlimited.
68
+ *
69
+ * @param value Consumer-provided row ceiling to validate
70
+ * @param fallback Value returned when `value` is invalid
71
+ * @param maximum Largest accepted row ceiling
72
+ */
73
+ export declare function normalizeMaxImagesPerRow(value: unknown, fallback?: number, maximum?: number): number;
20
74
  /**
21
75
  * Compute justified layout rows for a list of images.
22
76
  *
@@ -39,5 +93,25 @@ export interface PhotoRow<T extends LayoutImage = LayoutImage> {
39
93
  * @param gap Horizontal gap in px between images within a row
40
94
  * @param maxRowHeight Ceiling for row heights — keeps a stretched final row
41
95
  * (or a single image) from ballooning past e.g. half the viewport height
96
+ * @param maxImagesPerRow Optional positive-integer ceiling for the number of
97
+ * images in each row. Omit it, or pass an invalid value, for an unlimited row
98
+ * length.
99
+ */
100
+ export declare function calculatePhotoLayout<T extends LayoutImage>(images: T[], containerWidth: number, targetRowHeight?: number, gap?: number, maxRowHeight?: number, maxImagesPerRow?: number): PhotoRow<T>[];
101
+ /**
102
+ * Compute bounded album geometry with explicit cell widths.
103
+ *
104
+ * This is the opt-in counterpart to {@link calculatePhotoLayout}. Completed
105
+ * rows always span the available width. When their justified height exceeds
106
+ * `maxRowHeight`, their cells retain their relative widths while expanding to
107
+ * the row width at the ceiling; a renderer can use `object-fit: cover` to crop
108
+ * the resulting cells. A final row below a finite `maxImagesPerRow` instead
109
+ * remains partial and preserves its image proportions. Its height is capped by
110
+ * the tallest preceding row (or the target height when it is the only row) and
111
+ * by `maxRowHeight`.
112
+ *
113
+ * With an omitted or invalid `maxImagesPerRow`, every row remains completed.
114
+ * That preserves the legacy unlimited-row distribution for callers that have
115
+ * not opted into bounded albums.
42
116
  */
43
- export declare function calculatePhotoLayout<T extends LayoutImage>(images: T[], containerWidth: number, targetRowHeight?: number, gap?: number, maxRowHeight?: number): PhotoRow<T>[];
117
+ export declare function calculateAlbumLayout<T extends LayoutImage>(images: T[], options: AlbumLayoutOptions): AlbumLayoutRow<T>[];
@@ -1 +1 @@
1
- function T(o,u,h=220,l=8,w=Number.POSITIVE_INFINITY){if(o.length===0)return[];const i=t=>t.reduce((e,s)=>e+s.width/s.height,0),c=t=>{const e=(t.length-1)*l;return(u-e)/i(t)},d=t=>t>h?t/h:h/t,p=[];let n=[];const r=(t,e)=>{p.push({images:[...t],height:Math.min(e,w)})};for(let t=0;t<o.length;t++){n.push(o[t]);const s=i(n)*h+(n.length-1)*l>u,a=t===o.length-1;if(s&&n.length>1){const f=c(n),I=c(n.slice(0,-1));d(f)<=d(I)?r(n,f):(n.pop(),t--,r(n,I)),n=[]}else a&&(r(n,c(n)),n=[])}return p}export{T as calculatePhotoLayout};
1
+ const E=90;function H(t){return typeof t=="number"&&Number.isInteger(t)&&t>=1&&t<=100?t:90}function R(t,r=Number.POSITIVE_INFINITY,u=Number.POSITIVE_INFINITY){return typeof t=="number"&&Number.isInteger(t)&&t>0&&t<=u?t:r}function M(t,r,u=220,a=8,w=Number.POSITIVE_INFINITY,d=Number.POSITIVE_INFINITY){if(t.length===0)return[];const f=R(d),N=o=>o.reduce((c,l)=>c+l.width/l.height,0),I=o=>{const c=(o.length-1)*a;return(r-c)/N(o)},p=o=>o>u?o/u:u/o,m=[];let n=[];const g=(o,c)=>{m.push({images:[...o],height:Math.min(c,w)})};for(let o=0;o<t.length;o++){n.push(t[o]);const l=N(n)*u+(n.length-1)*a>r,b=o===t.length-1;if(l&&n.length>1){const i=I(n),e=I(n.slice(0,-1));p(i)<=p(e)?g(n,i):(n.pop(),o--,g(n,e)),n=[]}else n.length>=f?(g(n,I(n)),n=[]):b&&(g(n,I(n)),n=[])}return m}function P(t,r){if(t.length===0)return[];const u=A(r.containerWidth,0),a=W(r.targetRowHeight,220),w=A(r.gap,8),d=W(r.maxRowHeight,Number.POSITIVE_INFINITY),f=R(r.maxImagesPerRow),N=Number.isFinite(f),I=e=>{const s=e.width/e.height;return Number.isFinite(s)&&s>0?s:1},p=e=>e.reduce((s,h)=>s+I(h),0),m=e=>Math.max(u-(e.length-1)*w,0),n=e=>m(e)/p(e),g=e=>e>a?e/a:a/e,o=[];let c=0;const l=e=>{const s=n(e),h=Math.min(s,d),T=m(e),F=h<s?T/p(e):h;o.push({items:e.map(x=>({image:x,width:I(x)*F})),height:h,isPartial:!1,fillsContainer:!0}),c=Math.max(c,h)},b=e=>{const s=Math.min(n(e),d,c||a);o.push({items:e.map(h=>({image:h,width:I(h)*s})),height:s,isPartial:!0,fillsContainer:!1})};let i=[];for(let e=0;e<t.length;e++){i.push(t[e]);const h=p(i)*a+(i.length-1)*w>u,T=e===t.length-1;if(h&&i.length>1){const _=n(i),F=n(i.slice(0,-1));g(_)<=g(F)||(i.pop(),e--),l(i),i=[]}else i.length>=f?(l(i),i=[]):T&&(N&&i.length<f?b(i):l(i),i=[])}return o}function A(t,r){return typeof t=="number"&&Number.isFinite(t)&&t>=0?t:r}function W(t,r){return typeof t=="number"&&t>0&&(Number.isFinite(t)||t===1/0)?t:r}export{E as DEFAULT_ALBUM_MAX_ROW_HEIGHT_VH,P as calculateAlbumLayout,M as calculatePhotoLayout,H as normalizeAlbumMaxRowHeightVh,R as normalizeMaxImagesPerRow};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taprootio/espalier",
3
- "version": "4.9.1",
3
+ "version": "4.11.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",