@taprootio/espalier 4.13.2 → 4.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- var p=function(r,t,e,s){var i=arguments.length,o=i<3?t:s===null?s=Object.getOwnPropertyDescriptor(t,e):s,c;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(r,t,e,s);else for(var a=r.length-1;a>=0;a--)(c=r[a])&&(o=(i<3?c(o):i>3?c(t,e,o):c(t,e))||o);return i>3&&o&&Object.defineProperty(t,e,o),o};import{css as f,html as l}from"lit";import{customElement as v,property as d}from"lit/decorators.js";import{EspalierElementBase as m}from"../shared/esp-element-base.js";import{ESP_EVENTS as h}from"../shared/events.js";import{intentSurfaceTokens as u}from"../shared/style-fragments.js";import{classMap as b}from"lit/directives/class-map.js";import{trashSVG as g}from"../shared/svgs/trash.js";import{ref as y}from"lit/directives/ref.js";import{getIconHrefForHost as S}from"../shared/intent-values.js";import{SlottedIconController as E}from"../shared/slotted-icon-controller.js";import{renderSpriteIcon as _}from"../shared/svgs/render-sprite-icon.js";let n=class extends m{constructor(){super(...arguments),this.intentEmitsTokens=!1,this.iconSlot=new E(this),this.intentBacker="info",this.icon="",this.destroyable=!1}render(){const t=S(this.icon,this),e=this.iconSlot.hasSlottedIcon('[slot="icon-slot"]');return l`
1
+ var p=function(s,t,o,n){var i=arguments.length,e=i<3?t:n===null?n=Object.getOwnPropertyDescriptor(t,o):n,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")e=Reflect.decorate(s,t,o,n);else for(var l=s.length-1;l>=0;l--)(a=s[l])&&(e=(i<3?a(e):i>3?a(t,o,e):a(t,o))||e);return i>3&&e&&Object.defineProperty(t,o,e),e};import{css as f,html as c}from"lit";import{customElement as u,property as d}from"lit/decorators.js";import{EspalierElementBase as m}from"../shared/esp-element-base.js";import{ESP_EVENTS as h}from"../shared/events.js";import{intentSurfaceTokens as v}from"../shared/style-fragments.js";import{classMap as b}from"lit/directives/class-map.js";import{trashSVG as g}from"../shared/svgs/trash.js";import{ref as y}from"lit/directives/ref.js";import{getIconHrefForHost as S}from"../shared/intent-values.js";import{SlottedIconController as E}from"../shared/slotted-icon-controller.js";import{renderSpriteIcon as _}from"../shared/svgs/render-sprite-icon.js";let r=class extends m{constructor(){super(...arguments),this.intentEmitsTokens=!1,this.iconSlot=new E(this),this.intentBacker="info",this.icon="",this.destroyable=!1}render(){const t=S(this.icon,this),o=this.iconSlot.hasSlottedIcon('[slot="icon-slot"]');return c`
2
2
  <section class=${b({[`intent-${this.intent}`]:!0})}>
3
3
  <div class="icon">
4
4
  <slot
@@ -6,21 +6,21 @@ var p=function(r,t,e,s){var i=arguments.length,o=i<3?t:s===null?s=Object.getOwnP
6
6
  ${y(this.iconSlot.slotRef)}
7
7
  @slotchange=${this.iconSlot.handleSlotChange}
8
8
  ></slot>
9
- ${!e&&t?_(t):l``}
9
+ ${!o&&t?_(t):c``}
10
10
  </div>
11
11
  <div class="message">
12
12
  <slot></slot>
13
13
  </div>
14
- ${this.destroyable?l`<esp-button
14
+ ${this.destroyable?c`<esp-button
15
15
  class="destroy-button"
16
16
  intent="danger"
17
17
  icon-only
18
18
  @esp-clicked=${()=>{this.dispatchEvent(new CustomEvent(h.INFO_DESTROY,{detail:{toDestroy:this}}))}}
19
19
  >
20
20
  ${g}
21
- </esp-button>`:l``}
21
+ </esp-button>`:c``}
22
22
  </section>
23
- `}};n.styles=[...m.styles,u,f`
23
+ `}};r.styles=[...m.styles,v,f`
24
24
  :host {
25
25
  display: block;
26
26
  }
@@ -37,6 +37,9 @@ var p=function(r,t,e,s){var i=arguments.length,o=i<3?t:s===null?s=Object.getOwnP
37
37
  div.icon {
38
38
  display: grid;
39
39
  place-content: center;
40
+
41
+ border-start-start-radius: max(0px, calc(var(--esp-size-border-radius) - 1px));
42
+ border-end-start-radius: max(0px, calc(var(--esp-size-border-radius) - 1px));
40
43
  padding: var(--esp-size-tiny);
41
44
  background: var(--esp-info-color-border, var(--_esp-intent-border-color));
42
45
  color: var(--esp-info-color-background, var(--_esp-intent-background));
@@ -58,4 +61,4 @@ var p=function(r,t,e,s){var i=arguments.length,o=i<3?t:s===null?s=Object.getOwnP
58
61
  margin: var(--esp-size-tiny);
59
62
  }
60
63
  }
61
- `],p([d({type:String})],n.prototype,"icon",void 0),p([d({type:Boolean})],n.prototype,"destroyable",void 0),n=p([v("esp-info")],n);export{n as EspalierInfo};
64
+ `],p([d({type:String})],r.prototype,"icon",void 0),p([d({type:Boolean})],r.prototype,"destroyable",void 0),r=p([u("esp-info")],r);export{r as EspalierInfo};
@@ -418,7 +418,8 @@ import{css as a,unsafeCSS as e}from"lit";import{EspalierElementBase as i}from"..
418
418
  grid-column: main;
419
419
  grid-row: content;
420
420
  position: relative;
421
- overflow: hidden;
421
+
422
+ overflow: clip;
422
423
 
423
424
  background: var(--esp-page-main-background, transparent);
424
425
 
@@ -2,7 +2,7 @@ import { nothing, type PropertyValues, type TemplateResult } from "lit";
2
2
  import { EspalierElementBase } from "../shared/esp-element-base.js";
3
3
  import { type CursorPageRequest, type CursorPageResult } from "../shared/cursor-pagination.js";
4
4
  import "../shared/virtualizer/lit-virtualizer.js";
5
- export type RepeaterLayout = "list" | "grid";
5
+ export type RepeaterLayout = "list" | "grid" | "masonry";
6
6
  export type RepeaterScrollModel = "contained" | "page";
7
7
  export type RepeaterRenderValue = TemplateResult | Node | string | number | boolean | typeof nothing | null | undefined;
8
8
  export type RepeaterRenderItem<T = unknown> = (item: T, index: number) => RepeaterRenderValue;
@@ -19,6 +19,15 @@ export type RepeaterRenderItem<T = unknown> = (item: T, index: number) => Repeat
19
19
  * provide a fixed fallback with `grid-columns` and override the live column
20
20
  * count with `--esp-repeater-grid-columns` in media queries.
21
21
  *
22
+ * Use `layout="masonry"` for cards of uneven height, such as an image library
23
+ * mixing portrait and landscape photos. Items keep their document order and
24
+ * flow into the same responsive column count as `grid`, but each card takes
25
+ * only the height it needs and the next card starts directly below it, so
26
+ * columns pack tightly instead of leaving blank space under shorter cards.
27
+ * Masonry measures every card, so it keeps all loaded items in the DOM
28
+ * instead of virtualizing them; pair it with cursor paging for large
29
+ * collections.
30
+ *
22
31
  * Use `scroll-model="page"` when the repeater should participate in the
23
32
  * document's natural page scroll instead of owning a nested scrolling
24
33
  * viewport. In page mode, `list-height` is ignored.
@@ -35,9 +44,9 @@ export type RepeaterRenderItem<T = unknown> = (item: T, index: number) => Repeat
35
44
  * @cssprop --esp-repeater-gap - Space between repeated items.
36
45
  * @cssprop --esp-repeater-padding - Padding used by repeater state panels and the loading/error footer.
37
46
  * @cssprop --esp-repeater-content-padding - Padding inside the virtualized content region. Defaults to `0`.
38
- * @cssprop --esp-repeater-grid-columns - Grid column count when `layout="grid"`. Supports media-query overrides.
39
- * @cssprop --esp-repeater-grid-column-gap - Horizontal gap between grid columns.
40
- * @cssprop --esp-repeater-grid-row-gap - Vertical gap between grid rows.
47
+ * @cssprop --esp-repeater-grid-columns - Column count when `layout="grid"` or `layout="masonry"`. Supports media-query overrides.
48
+ * @cssprop --esp-repeater-grid-column-gap - Horizontal gap between grid or masonry columns.
49
+ * @cssprop --esp-repeater-grid-row-gap - Vertical gap between grid rows or stacked masonry cards.
41
50
  *
42
51
  * @docPageTitle Repeater
43
52
  * @docUrl /components/repeater
@@ -268,6 +277,74 @@ export type RepeaterRenderItem<T = unknown> = (item: T, index: number) => Repeat
268
277
  * };
269
278
  * </script>
270
279
  * ```
280
+ *
281
+ * @example Masonry gallery with mixed portrait and landscape cards
282
+ * ```html
283
+ * <style>
284
+ * esp-repeater[layout="masonry"] {
285
+ * --esp-repeater-grid-columns: 1;
286
+ * --esp-repeater-grid-column-gap: var(--esp-size-padding);
287
+ * --esp-repeater-grid-row-gap: var(--esp-size-padding);
288
+ * }
289
+ *
290
+ * @media (min-width: 48rem) {
291
+ * esp-repeater[layout="masonry"] {
292
+ * --esp-repeater-grid-columns: 2;
293
+ * }
294
+ * }
295
+ *
296
+ * @media (min-width: 72rem) {
297
+ * esp-repeater[layout="masonry"] {
298
+ * --esp-repeater-grid-columns: 3;
299
+ * }
300
+ * }
301
+ * </style>
302
+ *
303
+ * <esp-repeater
304
+ * id="masonry-gallery"
305
+ * layout="masonry"
306
+ * scroll-model="page"
307
+ * grid-columns="1"
308
+ * page-size="9"
309
+ * aria-label="Masonry image gallery"
310
+ * ></esp-repeater>
311
+ * <script>
312
+ * const repeater = findByTagName("esp-repeater")[0];
313
+ * const allImages = Array.from({ length: 30 }, (_, index) => {
314
+ * const portrait = index % 3 === 1;
315
+ * return {
316
+ * id: index + 1,
317
+ * title: `Image ${index + 1}`,
318
+ * ratio: portrait ? "2 / 3" : "3 / 2",
319
+ * thumbnail: portrait
320
+ * ? `https://picsum.photos/seed/masonry-${index + 1}/320/480`
321
+ * : `https://picsum.photos/seed/masonry-${index + 1}/480/320`,
322
+ * };
323
+ * });
324
+ *
325
+ * repeater.renderItem = (image) => {
326
+ * const card = document.createElement("esp-box");
327
+ * card.innerHTML = `
328
+ * <article style="display:grid; gap:var(--esp-size-small);">
329
+ * <img src="${image.thumbnail}" alt="" style="width:100%; aspect-ratio:${image.ratio}; object-fit:cover; border-radius:var(--esp-size-border-radius);" />
330
+ * <h3 style="margin:0;">${image.title}</h3>
331
+ * </article>
332
+ * `;
333
+ * return card;
334
+ * };
335
+ *
336
+ * repeater.fetchPage = async ({ cursor, limit }) => {
337
+ * const start = cursor ? Number(cursor) : 0;
338
+ * const items = allImages.slice(start, start + limit);
339
+ * const nextStart = start + limit;
340
+ *
341
+ * return {
342
+ * items,
343
+ * nextCursor: nextStart < allImages.length ? String(nextStart) : null,
344
+ * };
345
+ * };
346
+ * </script>
347
+ * ```
271
348
  */
272
349
  export declare class EspalierRepeater extends EspalierElementBase {
273
350
  /**
@@ -288,9 +365,11 @@ export declare class EspalierRepeater extends EspalierElementBase {
288
365
  * Visual layout mode for the rendered content.
289
366
  *
290
367
  * Use `grid` to opt into responsive card-style rows while
291
- * preserving virtualization and paging behavior.
368
+ * preserving virtualization and paging behavior. Use `masonry` to
369
+ * pack cards of uneven height into the same responsive columns;
370
+ * masonry keeps every loaded item in the DOM rather than virtualizing.
292
371
  *
293
- * @type {"list" | "grid"}
372
+ * @type {"list" | "grid" | "masonry"}
294
373
  */
295
374
  layout: RepeaterLayout;
296
375
  /**
@@ -304,9 +383,9 @@ export declare class EspalierRepeater extends EspalierElementBase {
304
383
  */
305
384
  scrollModel: RepeaterScrollModel;
306
385
  /**
307
- * Fixed grid column count fallback used when `layout="grid"`
308
- * and no `--esp-repeater-grid-columns` custom property override
309
- * is applied.
386
+ * Fixed column count fallback used when `layout="grid"` or
387
+ * `layout="masonry"` and no `--esp-repeater-grid-columns` custom
388
+ * property override is applied.
310
389
  *
311
390
  * @type {number}
312
391
  */
@@ -1,28 +1,44 @@
1
- var l=function(y,e,t,i){var r=arguments.length,s=r<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,t):i,a;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")s=Reflect.decorate(y,e,t,i);else for(var g=y.length-1;g>=0;g--)(a=y[g])&&(s=(r<3?a(s):r>3?a(e,t,s):a(e,t))||s);return r>3&&s&&Object.defineProperty(e,t,s),s};import{css as V,html as d,nothing as I}from"lit";import{customElement as F,property as h,state as b}from"lit/decorators.js";import{keyed as j}from"lit/directives/keyed.js";import{ifDefined as M}from"lit/directives/if-defined.js";import{createRef as G,ref as O}from"lit/directives/ref.js";import{styleMap as A}from"lit/directives/style-map.js";import{EspalierElementBase as E}from"../shared/esp-element-base.js";import{accumulatePage as N,RequestVersionGuard as B}from"../shared/cursor-pagination.js";import"../shared/virtualizer/lit-virtualizer.js";let o=class extends E{constructor(){super(...arguments),this.virtualizerRef=G(),this.containerRef=G(),this.pageLoads=new B,this.nextCursor=null,this.lastObservedWidth=0,this.observersAttached=!1,this.gridObserversAttached=!1,this.resolvedGridColumns=1,this.memoizedGridRowsSource=null,this.memoizedGridRowsColumns=0,this.memoizedGridRows=[],this.hostAttributeObserver=null,this.resizeObserver=null,this.viewportResizeListener=null,this.pageScrollStabilizerActive=!1,this.activePageScrollStabilizer=null,this.isAdjustingHeight=!1,this.pendingHeightRetry=!1,this.heightRetryObserver=null,this.isLoadingPage=!1,this.loadedItems=[],this.hasMoreData=!1,this.effectiveListHeight="60vh",this.loadError="",this.items=[],this.renderItem=null,this.layout="list",this.scrollModel="contained",this.gridColumns=1,this.ariaLabel=null,this.listHeight="60vh",this.pageSize=25,this.prefetchThreshold=5,this.loading=!1,this.loadingMessage="Loading items\u2026",this.emptyMessage="No items found",this.errorMessage="",this.fetchPageBacker=null,this.renderVirtualItem=(e,t)=>{if(e===void 0)return d``;const i=this.renderItem??(r=>this.renderFallbackItem(r));return d`<div class="repeater-item" part="item" role="listitem">
2
- ${i(e,t)}
3
- </div>`},this.renderVirtualRow=e=>{if(e===void 0)return d``;const t=this.renderItem??(r=>this.renderFallbackItem(r)),i={gridTemplateColumns:`repeat(${this.effectiveGridColumns}, minmax(0, 1fr))`};return d`<div
1
+ var n=function(f,e,t,s){var r=arguments.length,o=r<3?e:s===null?s=Object.getOwnPropertyDescriptor(e,t):s,i;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")o=Reflect.decorate(f,e,t,s);else for(var c=f.length-1;c>=0;c--)(i=f[c])&&(o=(r<3?i(o):r>3?i(e,t,o):i(e,t))||o);return r>3&&o&&Object.defineProperty(e,t,o),o};import{css as B,html as h,nothing as S}from"lit";import{customElement as N,property as d,state as g}from"lit/decorators.js";import{keyed as q}from"lit/directives/keyed.js";import{ifDefined as M}from"lit/directives/if-defined.js";import{createRef as R,ref as w}from"lit/directives/ref.js";import{repeat as T}from"lit/directives/repeat.js";import{styleMap as p}from"lit/directives/style-map.js";import{EspalierElementBase as I}from"../shared/esp-element-base.js";import{accumulatePage as V,RequestVersionGuard as j}from"../shared/cursor-pagination.js";import"../shared/virtualizer/lit-virtualizer.js";const P=4;let a=class extends I{constructor(){super(...arguments),this.virtualizerRef=R(),this.containerRef=R(),this.pageLoads=new j,this.nextCursor=null,this.lastRangeEnd=-1,this.lastObservedWidth=0,this.observersAttached=!1,this.gridObserversAttached=!1,this.resolvedGridColumns=1,this.memoizedGridRowsSource=null,this.memoizedGridRowsColumns=0,this.memoizedGridRows=[],this.hostAttributeObserver=null,this.resizeObserver=null,this.viewportResizeListener=null,this.masonryRef=R(),this.masonryCellObserver=null,this.masonryObservedCells=new Set,this.masonryPrefetchObserver=null,this.footerHoldScrollListener=null,this.isAdjustingHeight=!1,this.pendingHeightRetry=!1,this.heightRetryObserver=null,this.isLoadingPage=!1,this.loadedItems=[],this.hasMoreData=!1,this.effectiveListHeight="60vh",this.loadError="",this.footerHoldHeight=0,this.items=[],this.renderItem=null,this.layout="list",this.scrollModel="contained",this.gridColumns=1,this.ariaLabel=null,this.listHeight="60vh",this.pageSize=25,this.prefetchThreshold=5,this.loading=!1,this.loadingMessage="Loading items\u2026",this.emptyMessage="No items found",this.errorMessage="",this.fetchPageBacker=null,this.renderVirtualItem=(e,t)=>{if(e===void 0)return h``;const s=this.renderItem??(r=>this.renderFallbackItem(r));return h`<div class="repeater-item" part="item" role="listitem">
2
+ ${s(e,t)}
3
+ </div>`},this.renderVirtualRow=e=>{if(e===void 0)return h``;const t=this.renderItem??(r=>this.renderFallbackItem(r)),s={gridTemplateColumns:`repeat(${this.effectiveGridColumns}, minmax(0, 1fr))`};return h`<div
4
4
  class="repeater-row"
5
5
  part="row"
6
6
  role="presentation"
7
- style=${A(i)}
7
+ style=${p(s)}
8
8
  >
9
- ${e.items.map((r,s)=>d`<div class="repeater-item repeater-grid-cell" part="item" role="listitem">
10
- ${t(r,e.startIndex+s)}
9
+ ${e.items.map((r,o)=>h`<div class="repeater-item repeater-grid-cell" part="item" role="listitem">
10
+ ${t(r,e.startIndex+o)}
11
11
  </div>`)}
12
- </div>`},this.renderGridVirtualItem=(e,t)=>this.isGridRow(e)?this.renderVirtualRow(e,t):d``}get fetchPage(){return this.fetchPageBacker}set fetchPage(e){const t=this.fetchPageBacker;t!==e&&(this.fetchPageBacker=e,this.requestUpdate("fetchPage",t),this.resetPagedState(),e&&this.hasUpdated&&this.startPagedLoad(null))}get isPagedMode(){return this.fetchPage!==null}get isGridLayout(){return this.layout==="grid"}get isPageScrollModel(){return this.scrollModel==="page"}get isContainedScrollModel(){return!this.isPageScrollModel}get renderedItems(){return this.isPagedMode?this.loadedItems:this.items}get virtualizerItems(){return this.isGridLayout?this.buildGridRows(this.renderedItems,this.effectiveGridColumns):this.renderedItems}get isBusy(){return this.loading||this.isLoadingPage}get activeErrorMessage(){return this.errorMessage||this.loadError}get normalizedPageSize(){const e=Number(this.pageSize);return Number.isFinite(e)&&e>0?Math.floor(e):25}get normalizedPrefetchThreshold(){const e=Number(this.prefetchThreshold);return Number.isFinite(e)&&e>0?Math.floor(e):1}get normalizedGridColumns(){const e=Number(this.gridColumns);return Number.isFinite(e)&&e>0?Math.floor(e):1}get effectiveGridColumns(){return this.isGridLayout?this.resolvedGridColumns:1}connectedCallback(){super.connectedCallback(),this.attachObservers(),this.lastObservedWidth=this.clientWidth,this.syncResolvedGridColumns(),this.hasUpdated&&this.isContainedScrollModel&&this.adjustListHeight()}firstUpdated(e){if(super.firstUpdated(e),this.lastObservedWidth=this.clientWidth,this.fetchPage){this.startPagedLoad(null);return}this.adjustListHeight()}disconnectedCallback(){this.releaseActivePageScrollStabilizer(),this.heightRetryObserver?.disconnect(),this.heightRetryObserver=null,this.pendingHeightRetry=!1,this.detachObservers(),super.disconnectedCallback()}willUpdate(e){super.willUpdate(e),(e.has("layout")||e.has("gridColumns"))&&this.syncResolvedGridColumns()}updated(e){super.updated(e),e.has("layout")&&this.syncGridObservers(),(e.has("items")||e.has("loadedItems")||e.has("listHeight")||e.has("layout")||e.has("gridColumns")||e.has("scrollModel"))&&this.adjustListHeight()}parsePositiveIntegerToken(e){const t=Number(e.trim());return Number.isFinite(t)&&t>0?Math.floor(t):null}attachObservers(){this.observersAttached||(this.observersAttached=!0,this.getResizeObserver().observe(this),this.syncGridObservers())}detachObservers(){this.observersAttached&&(this.observersAttached=!1,this.detachGridObservers(),this.resizeObserver?.disconnect())}syncGridObservers(){if(this.observersAttached){if(!this.isGridLayout){this.detachGridObservers();return}this.gridObserversAttached||(this.gridObserversAttached=!0,this.getHostAttributeObserver().observe(this,{attributes:!0,attributeFilter:["class","style"]}),window.addEventListener("resize",this.getViewportResizeListener()))}}detachGridObservers(){if(!this.gridObserversAttached)return;this.gridObserversAttached=!1,this.hostAttributeObserver?.disconnect();const e=this.viewportResizeListener;e&&window.removeEventListener("resize",e)}getHostAttributeObserver(){return this.hostAttributeObserver||(this.hostAttributeObserver=new MutationObserver(()=>{this.refreshResolvedGridColumns()})),this.hostAttributeObserver}getResizeObserver(){return this.resizeObserver||(this.resizeObserver=new ResizeObserver(()=>{const e=this.clientWidth,t=e!==this.lastObservedWidth;this.lastObservedWidth=e;const i=this.isGridLayout?this.refreshResolvedGridColumns():!1;t&&!i&&this.isContainedScrollModel&&this.adjustListHeight()})),this.resizeObserver}getViewportResizeListener(){return this.viewportResizeListener||(this.viewportResizeListener=()=>{this.refreshResolvedGridColumns()}),this.viewportResizeListener}syncResolvedGridColumns(){this.resolvedGridColumns=this.isGridLayout?this.readResolvedGridColumns():1}readResolvedGridColumns(){return!this.isGridLayout||!this.isConnected?this.normalizedGridColumns:this.parsePositiveIntegerToken(getComputedStyle(this).getPropertyValue("--esp-repeater-grid-columns"))??this.normalizedGridColumns}refreshResolvedGridColumns(){if(!this.isGridLayout)return!1;const e=this.readResolvedGridColumns();return e===this.resolvedGridColumns?!1:(this.resolvedGridColumns=e,this.hasUpdated&&(this.requestUpdate(),this.adjustListHeight()),!0)}buildGridRows(e,t){if(this.memoizedGridRowsSource===e&&this.memoizedGridRowsColumns===t)return this.memoizedGridRows;const i=[];for(let r=0;r<e.length;r+=t)i.push({items:e.slice(r,r+t),startIndex:r});return this.memoizedGridRowsSource=e,this.memoizedGridRowsColumns=t,this.memoizedGridRows=i,i}isGridRow(e){return e!==null&&typeof e=="object"&&Array.isArray(e.items)&&typeof e.startIndex=="number"}renderFallbackItem(e){if(typeof e=="string"||typeof e=="number"||typeof e=="boolean")return String(e);let t="";try{t=JSON.stringify(e,null,2)??this.describeFallbackItem(e)}catch{t=this.describeFallbackItem(e)}return d`<pre>${t}</pre>`}describeFallbackItem(e){try{return String(e)}catch{return"Unrenderable item"}}async startPagedLoad(e){if(!this.fetchPage||this.isLoadingPage)return;const t=this.capturePageScrollTop(e);this.isLoadingPage=!0,await this.loadPage(e,t)}async loadPage(e,t){const i=this.fetchPage;if(!i)return;const r=this.pageLoads.begin(),s=this.activatePageScrollStabilizer(t,r);this.activePageScrollStabilizer=s;try{const a=await i({cursor:e,limit:this.normalizedPageSize});if(!this.pageLoads.isCurrent(r))return;this.loadedItems=N(this.loadedItems,a.items,e),this.nextCursor=a.nextCursor,this.hasMoreData=a.nextCursor!==null,this.loadError=""}catch(a){if(!this.pageLoads.isCurrent(r))return;this.nextCursor=null,this.hasMoreData=!1,this.loadError=a instanceof Error&&a.message.length>0?a.message:"Unable to load items."}finally{try{this.pageLoads.isCurrent(r)&&(this.isLoadingPage=!1),this.pageLoads.isCurrent(r)&&await this.restorePageScrollPositionIfNeeded(s.getRestoreScrollTop(),r)}finally{this.activePageScrollStabilizer===s&&this.releaseActivePageScrollStabilizer()}}}capturePageScrollTop(e){return!this.isPageScrollModel||e===null?null:window.scrollY}activatePageScrollStabilizer(e,t){if(e===null||!this.isPageScrollModel||!this.pageLoads.isCurrent(t))return{release:()=>{},getRestoreScrollTop:()=>e};this.pageScrollStabilizerActive=!0;const i=this.getVirtualizerElement(),r=i?.getBoundingClientRect().height??0,s=this.activePageScrollStabilizer;s&&(this.activePageScrollStabilizer=null,s.release(),this.pageScrollStabilizerActive=!0),i&&r>0&&(i.style.minHeight=`${r}px`);const a="",g=r>0?Math.max(64,r*.5):Number.POSITIVE_INFINITY;let u=e,p=window.scrollY;const m=()=>{if(!this.pageLoads.isCurrent(t))return;const c=window.scrollY;if(c>u+1){u=c,p=c;return}if(c+1>=u){p=c;return}const z=c<=1,v=p+1>=u&&p-c>=g;if(!z&&!v){u=c,p=c;return}window.scrollTo({top:u,left:window.scrollX,behavior:"auto"}),p=u};return window.addEventListener("scroll",m,{passive:!0}),{getRestoreScrollTop:()=>u,release:()=>{window.removeEventListener("scroll",m),this.pageScrollStabilizerActive=!1,i&&(i.style.minHeight=a)}}}async restorePageScrollPositionIfNeeded(e,t){if(e===null||!this.isPageScrollModel||!this.pageLoads.isCurrent(t))return;await this.updateComplete;const i=this.getVirtualizerElement();i?.updateComplete&&await i.updateComplete,await new Promise(r=>requestAnimationFrame(r)),i?.layoutComplete&&await i.layoutComplete,this.pageLoads.isCurrent(t)&&window.scrollY+1<e&&window.scrollTo({top:e,left:window.scrollX,behavior:"auto"})}onRangeChanged(e){if(!this.isPagedMode||this.activeErrorMessage.length>0||!this.hasMoreData||this.isLoadingPage||this.nextCursor===null)return;const t=this.normalizedPrefetchThreshold;this.getLastVisibleItemIndex(e.last)>=this.loadedItems.length-t&&this.startPagedLoad(this.nextCursor)}getLastVisibleItemIndex(e){return this.isGridLayout?Math.min((e+1)*this.effectiveGridColumns-1,this.renderedItems.length-1):e}resetPagedState(){this.releaseActivePageScrollStabilizer(),this.pageLoads.invalidate(),this.isLoadingPage=!1,this.loadedItems=[],this.nextCursor=null,this.hasMoreData=!1,this.loadError=""}releaseActivePageScrollStabilizer(){const e=this.activePageScrollStabilizer;if(this.activePageScrollStabilizer=null,!e){this.pageScrollStabilizerActive=!1;return}e.release(),this.adjustListHeight()}async adjustListHeight(){if(!this.isContainedScrollModel){const e=this.getVirtualizerElement();e&&!this.pageScrollStabilizerActive&&(e.style.minHeight="");return}if(!this.isAdjustingHeight){this.isAdjustingHeight=!0;try{this.effectiveListHeight=this.listHeight;const e=this.getVirtualizerElement();e&&(e.style.minHeight=""),await this.updateComplete;const t=this.containerRef.value,i=this.getVirtualizerElement();if(!t)return;if(this.renderedItems.length===0||!i){let n=0;t.querySelectorAll(":scope > *").forEach(w=>{n+=w.offsetHeight});const f=t.offsetHeight;n>0&&n<f&&(this.effectiveListHeight=`${n}px`);return}if(this.hasMoreData||this.isBusy||this.activeErrorMessage.length>0)return;const r=this.isGridLayout?".repeater-row":".repeater-item",s=i.querySelectorAll(r);let a=0,g=!1;if(s.forEach(n=>{const f=n.offsetHeight;f===0&&(g=!0),a+=f}),s.length===0||g||a===0){this.pendingHeightRetry||(this.pendingHeightRetry=!0,this.observeForHeightRetry(i));return}const u=this.isGridLayout?".repeater-row :defined":".repeater-item :defined",p=i.querySelectorAll(u),m=[];p.forEach(n=>{"updateComplete"in n&&m.push(n.updateComplete)}),m.length>0&&(await Promise.all(m),a=0,s.forEach(n=>{a+=n.offsetHeight}));const z=t.querySelector(":scope > .status-footer")?.offsetHeight??0,v=a+z,x=t.offsetHeight,$=this.virtualizerItems.length;let R=!1;v>0&&v<x&&s.length>=$&&(i.style.minHeight=`${a}px`,this.effectiveListHeight=`${v}px`,R=!0),R&&!this.hasMoreData&&!this.pendingHeightRetry&&(this.pendingHeightRetry=!0,setTimeout(()=>{if(this.pendingHeightRetry=!1,!this.isContainedScrollModel||this.isBusy||this.activeErrorMessage.length>0)return;const n=this.containerRef.value,f=this.getVirtualizerElement();if(!n||!f||this.hasMoreData)return;const w=this.isGridLayout?".repeater-row":".repeater-item",C=f.querySelectorAll(w);let S=0,L=!1;if(C.forEach(T=>{const H=T.offsetHeight;H===0&&(L=!0),S+=H}),C.length===0||L||S===0)return;const k=n.querySelector(":scope > .status-footer")?.offsetHeight??0,P=S+k;P<n.offsetHeight&&C.length>=this.virtualizerItems.length&&(f.style.minHeight=`${S}px`,this.effectiveListHeight=`${P}px`)},100))}finally{this.isAdjustingHeight=!1}}}observeForHeightRetry(e){this.heightRetryObserver?.disconnect(),this.heightRetryObserver=new IntersectionObserver(t=>{if(!t.some(a=>a.isIntersecting))return;if(this.heightRetryObserver?.disconnect(),this.heightRetryObserver=null,!this.isContainedScrollModel){this.pendingHeightRetry=!1;return}let r=0;const s=()=>{this.pendingHeightRetry=!1,this.adjustListHeight(),this.pendingHeightRetry&&++r<5&&setTimeout(s,100)};requestAnimationFrame(()=>setTimeout(s,50))},{threshold:0}),this.heightRetryObserver.observe(e)}clear(){if(this.isPagedMode){this.resetPagedState(),this.adjustListHeight();return}this.items=[]}async reload(){this.isPagedMode&&(this.resetPagedState(),await this.startPagedLoad(null))}async scrollToIndex(e,t="center"){await this.updateComplete;const i=this.getVirtualizerElement();!i||!i.scrollToIndex||(await i.updateComplete,await new Promise(r=>requestAnimationFrame(r)),await i.layoutComplete,i.scrollToIndex(this.isGridLayout?Math.floor(e/this.effectiveGridColumns):e,t))}getVirtualizerElement(){return this.virtualizerRef.value}renderBlockingState(e,t,i){return d`<div class="state-panel" part="state" role=${i} aria-live=${M(i==="alert"?void 0:"polite")}>
12
+ </div>`},this.renderGridVirtualItem=(e,t)=>this.isGridRow(e)?this.renderVirtualRow(e,t):h``}get fetchPage(){return this.fetchPageBacker}set fetchPage(e){const t=this.fetchPageBacker;t!==e&&(this.fetchPageBacker=e,this.requestUpdate("fetchPage",t),this.resetPagedState(),e&&this.hasUpdated&&this.startPagedLoad(null))}get isPagedMode(){return this.fetchPage!==null}get isGridLayout(){return this.layout==="grid"}get isMasonryLayout(){return this.layout==="masonry"}get usesColumns(){return this.isGridLayout||this.isMasonryLayout}get isPageScrollModel(){return this.scrollModel==="page"}get isContainedScrollModel(){return!this.isPageScrollModel}get renderedItems(){return this.isPagedMode?this.loadedItems:this.items}get virtualizerItems(){return this.isGridLayout?this.buildGridRows(this.renderedItems,this.effectiveGridColumns):this.renderedItems}get isBusy(){return this.loading||this.isLoadingPage}get activeErrorMessage(){return this.errorMessage||this.loadError}get normalizedPageSize(){const e=Number(this.pageSize);return Number.isFinite(e)&&e>0?Math.floor(e):25}get normalizedPrefetchThreshold(){const e=Number(this.prefetchThreshold);return Number.isFinite(e)&&e>0?Math.floor(e):1}get normalizedGridColumns(){const e=Number(this.gridColumns);return Number.isFinite(e)&&e>0?Math.floor(e):1}get effectiveGridColumns(){return this.usesColumns?this.resolvedGridColumns:1}connectedCallback(){super.connectedCallback(),this.attachObservers(),this.lastObservedWidth=this.clientWidth,this.syncResolvedGridColumns(),this.hasUpdated&&this.isContainedScrollModel&&this.adjustListHeight(),this.hasUpdated&&this.isMasonryLayout&&this.syncMasonryObservers()}firstUpdated(e){if(super.firstUpdated(e),this.lastObservedWidth=this.clientWidth,this.fetchPage){this.startPagedLoad(null);return}this.adjustListHeight()}disconnectedCallback(){this.disconnectMasonryObservers(),this.releaseFooterHold(),this.heightRetryObserver?.disconnect(),this.heightRetryObserver=null,this.pendingHeightRetry=!1,this.detachObservers(),super.disconnectedCallback()}willUpdate(e){super.willUpdate(e),(e.has("layout")||e.has("gridColumns"))&&this.syncResolvedGridColumns()}updated(e){if(super.updated(e),e.has("layout")&&(this.syncGridObservers(),this.isMasonryLayout||this.disconnectMasonryObservers()),this.isMasonryLayout&&(e.has("items")||e.has("loadedItems")||e.has("layout")||e.has("fetchPage")||e.has("prefetchThreshold")||e.has("scrollModel")))this.syncMasonryObservers();else if(this.isMasonryLayout&&e.has("isLoadingPage")){const t=this.masonryRef.value;t&&this.syncMasonryPrefetchTarget(t)}(e.has("items")||e.has("loadedItems")||e.has("listHeight")||e.has("layout")||e.has("gridColumns")||e.has("scrollModel"))&&this.adjustListHeight()}syncMasonryObservers(){for(const t of this.masonryObservedCells)t.isConnected||(this.masonryCellObserver?.unobserve(t),this.masonryObservedCells.delete(t));const e=this.masonryRef.value;if(!e){this.disconnectMasonryPrefetchObserver();return}this.masonryCellObserver||(this.masonryCellObserver=new ResizeObserver(t=>{this.applyMasonrySpans(t)}));for(const t of e.querySelectorAll(":scope > .repeater-masonry-cell"))this.masonryObservedCells.has(t)||(this.masonryObservedCells.add(t),this.masonryCellObserver.observe(t,{box:"border-box"}));this.syncMasonryPrefetchTarget(e)}applyMasonrySpans(e){for(const t of e){const s=t.target,r=t.borderBoxSize?.[0]?.blockSize??s.getBoundingClientRect().height,i=`span ${Math.max(1,Math.ceil(r/P))}`;s.style.gridRowEnd!==i&&(s.style.gridRowEnd=i)}this.isContainedScrollModel&&this.adjustListHeight()}syncMasonryPrefetchTarget(e){if(!this.isPagedMode){this.disconnectMasonryPrefetchObserver();return}const t=e.querySelectorAll(":scope > .repeater-masonry-cell"),s=t[Math.max(0,t.length-this.normalizedPrefetchThreshold)]??null;this.disconnectMasonryPrefetchObserver(),s&&(this.masonryPrefetchObserver=new IntersectionObserver(r=>{r.some(o=>o.isIntersecting)&&this.requestNextPageIfNeeded()},{root:this.isContainedScrollModel?e:null}),this.masonryPrefetchObserver.observe(s))}disconnectMasonryPrefetchObserver(){this.masonryPrefetchObserver?.disconnect(),this.masonryPrefetchObserver=null}disconnectMasonryObservers(){this.masonryCellObserver?.disconnect(),this.masonryCellObserver=null,this.masonryObservedCells.clear(),this.disconnectMasonryPrefetchObserver()}parsePositiveIntegerToken(e){const t=Number(e.trim());return Number.isFinite(t)&&t>0?Math.floor(t):null}attachObservers(){this.observersAttached||(this.observersAttached=!0,this.getResizeObserver().observe(this),this.syncGridObservers())}detachObservers(){this.observersAttached&&(this.observersAttached=!1,this.detachGridObservers(),this.resizeObserver?.disconnect())}syncGridObservers(){if(this.observersAttached){if(!this.usesColumns){this.detachGridObservers();return}this.gridObserversAttached||(this.gridObserversAttached=!0,this.getHostAttributeObserver().observe(this,{attributes:!0,attributeFilter:["class","style"]}),window.addEventListener("resize",this.getViewportResizeListener()))}}detachGridObservers(){if(!this.gridObserversAttached)return;this.gridObserversAttached=!1,this.hostAttributeObserver?.disconnect();const e=this.viewportResizeListener;e&&window.removeEventListener("resize",e)}getHostAttributeObserver(){return this.hostAttributeObserver||(this.hostAttributeObserver=new MutationObserver(()=>{this.refreshResolvedGridColumns()})),this.hostAttributeObserver}getResizeObserver(){return this.resizeObserver||(this.resizeObserver=new ResizeObserver(()=>{const e=this.clientWidth,t=e!==this.lastObservedWidth;this.lastObservedWidth=e;const s=this.usesColumns?this.refreshResolvedGridColumns():!1;t&&!s&&this.isContainedScrollModel&&this.adjustListHeight()})),this.resizeObserver}getViewportResizeListener(){return this.viewportResizeListener||(this.viewportResizeListener=()=>{this.refreshResolvedGridColumns()}),this.viewportResizeListener}syncResolvedGridColumns(){this.resolvedGridColumns=this.usesColumns?this.readResolvedGridColumns():1}readResolvedGridColumns(){return!this.usesColumns||!this.isConnected?this.normalizedGridColumns:this.parsePositiveIntegerToken(getComputedStyle(this).getPropertyValue("--esp-repeater-grid-columns"))??this.normalizedGridColumns}refreshResolvedGridColumns(){if(!this.usesColumns)return!1;const e=this.readResolvedGridColumns();return e===this.resolvedGridColumns?!1:(this.resolvedGridColumns=e,this.hasUpdated&&(this.requestUpdate(),this.adjustListHeight()),!0)}buildGridRows(e,t){if(this.memoizedGridRowsSource===e&&this.memoizedGridRowsColumns===t)return this.memoizedGridRows;const s=[];for(let r=0;r<e.length;r+=t)s.push({items:e.slice(r,r+t),startIndex:r});return this.memoizedGridRowsSource=e,this.memoizedGridRowsColumns=t,this.memoizedGridRows=s,s}isGridRow(e){return e!==null&&typeof e=="object"&&Array.isArray(e.items)&&typeof e.startIndex=="number"}renderFallbackItem(e){if(typeof e=="string"||typeof e=="number"||typeof e=="boolean")return String(e);let t="";try{t=JSON.stringify(e,null,2)??this.describeFallbackItem(e)}catch{t=this.describeFallbackItem(e)}return h`<pre>${t}</pre>`}describeFallbackItem(e){try{return String(e)}catch{return"Unrenderable item"}}async startPagedLoad(e){!this.fetchPage||this.isLoadingPage||(this.releaseFooterHold(),this.isLoadingPage=!0,await this.loadPage(e))}async loadPage(e){const t=this.fetchPage;if(!t)return;const s=this.pageLoads.begin();let r=0,o=!1;try{const i=await t({cursor:e,limit:this.normalizedPageSize});if(!this.pageLoads.isCurrent(s))return;r=this.measureContentHeight(),this.loadedItems=V(this.loadedItems,i.items,e),o=e!==null&&i.items.length>0,this.nextCursor=i.nextCursor,this.hasMoreData=i.nextCursor!==null,this.loadError=""}catch(i){if(!this.pageLoads.isCurrent(s))return;this.nextCursor=null,this.hasMoreData=!1,this.loadError=i instanceof Error&&i.message.length>0?i.message:"Unable to load items."}finally{this.pageLoads.isCurrent(s)&&o&&this.isPageScrollModel&&await this.waitForContentGrowth(r,s),this.pageLoads.isCurrent(s)&&(this.isPageScrollModel&&this.holdFooterSpace(),this.isLoadingPage=!1,this.isMasonryLayout||this.requestNextPageForRange())}}footerHoldFor(e,t,s,r){return e<=0?0:t+s>r-e?e:0}holdFooterSpace(){const e=this.containerRef.value?.querySelector(":scope > .status-footer"),t=this.footerHoldFor(e?.getBoundingClientRect().height??0,window.scrollY,window.innerHeight,document.documentElement.scrollHeight);t<=0||(this.footerHoldHeight=t,this.footerHoldScrollListener||(this.footerHoldScrollListener=()=>this.releaseFooterHoldIfSafe(),window.addEventListener("scroll",this.footerHoldScrollListener,{passive:!0})))}releaseFooterHoldIfSafe(){const e=document.documentElement.scrollHeight;window.scrollY+window.innerHeight<=e-this.footerHoldHeight&&this.releaseFooterHold()}releaseFooterHold(){this.footerHoldScrollListener&&(window.removeEventListener("scroll",this.footerHoldScrollListener),this.footerHoldScrollListener=null),this.footerHoldHeight=0}measureContentHeight(){return(this.masonryRef.value??this.getVirtualizerElement())?.getBoundingClientRect().height??0}async waitForContentGrowth(e,t){await this.updateComplete;for(let s=0;s<12&&this.pageLoads.isCurrent(t);s+=1){if(this.measureContentHeight()>e)return;await new Promise(r=>requestAnimationFrame(r))}}requestNextPageIfNeeded(){!this.isPagedMode||this.activeErrorMessage.length>0||!this.hasMoreData||this.isLoadingPage||this.nextCursor===null||this.startPagedLoad(this.nextCursor)}onRangeChanged(e){this.lastRangeEnd=e.last,!(!this.isPagedMode||this.isLoadingPage)&&this.requestNextPageForRange()}requestNextPageForRange(){if(this.lastRangeEnd<0)return;const e=this.normalizedPrefetchThreshold;this.getLastVisibleItemIndex(this.lastRangeEnd)>=this.loadedItems.length-e&&this.requestNextPageIfNeeded()}getLastVisibleItemIndex(e){return this.isGridLayout?Math.min((e+1)*this.effectiveGridColumns-1,this.renderedItems.length-1):e}resetPagedState(){this.releaseFooterHold(),this.pageLoads.invalidate(),this.lastRangeEnd=-1,this.isLoadingPage=!1,this.loadedItems=[],this.nextCursor=null,this.hasMoreData=!1,this.loadError=""}async adjustListHeight(){if(this.isContainedScrollModel&&!this.isAdjustingHeight){this.isAdjustingHeight=!0;try{this.effectiveListHeight=this.listHeight;const e=this.getVirtualizerElement();e&&(e.style.minHeight=""),await this.updateComplete;const t=this.containerRef.value,s=this.getVirtualizerElement();if(!t)return;if(this.renderedItems.length===0||!s){if(this.isMasonryLayout&&(this.hasMoreData||this.isBusy))return;let l=0;t.querySelectorAll(":scope > *").forEach(b=>{l+=b.offsetHeight});const u=t.offsetHeight;l>0&&l<u&&(this.effectiveListHeight=`${l}px`);return}if(this.hasMoreData||this.isBusy||this.activeErrorMessage.length>0)return;const r=this.isGridLayout?".repeater-row":".repeater-item",o=s.querySelectorAll(r);let i=0,c=!1;if(o.forEach(l=>{const u=l.offsetHeight;u===0&&(c=!0),i+=u}),o.length===0||c||i===0){this.pendingHeightRetry||(this.pendingHeightRetry=!0,this.observeForHeightRetry(s));return}const G=this.isGridLayout?".repeater-row :defined":".repeater-item :defined",x=s.querySelectorAll(G),v=[];x.forEach(l=>{"updateComplete"in l&&v.push(l.updateComplete)}),v.length>0&&(await Promise.all(v),i=0,o.forEach(l=>{i+=l.offsetHeight}));const E=t.querySelector(":scope > .status-footer")?.offsetHeight??0,y=i+E,$=t.offsetHeight,A=this.virtualizerItems.length;let H=!1;y>0&&y<$&&o.length>=A&&(s.style.minHeight=`${i}px`,this.effectiveListHeight=`${y}px`,H=!0),H&&!this.hasMoreData&&!this.pendingHeightRetry&&(this.pendingHeightRetry=!0,setTimeout(()=>{if(this.pendingHeightRetry=!1,!this.isContainedScrollModel||this.isBusy||this.activeErrorMessage.length>0)return;const l=this.containerRef.value,u=this.getVirtualizerElement();if(!l||!u||this.hasMoreData)return;const b=this.isGridLayout?".repeater-row":".repeater-item",C=u.querySelectorAll(b);let m=0,L=!1;if(C.forEach(k=>{const z=k.offsetHeight;z===0&&(L=!0),m+=z}),C.length===0||L||m===0)return;const F=l.querySelector(":scope > .status-footer")?.offsetHeight??0,O=m+F;O<l.offsetHeight&&C.length>=this.virtualizerItems.length&&(u.style.minHeight=`${m}px`,this.effectiveListHeight=`${O}px`)},100))}finally{this.isAdjustingHeight=!1}}}observeForHeightRetry(e){this.heightRetryObserver?.disconnect(),this.heightRetryObserver=new IntersectionObserver(t=>{if(!t.some(i=>i.isIntersecting))return;if(this.heightRetryObserver?.disconnect(),this.heightRetryObserver=null,!this.isContainedScrollModel){this.pendingHeightRetry=!1;return}let r=0;const o=()=>{this.pendingHeightRetry=!1,this.adjustListHeight(),this.pendingHeightRetry&&++r<5&&setTimeout(o,100)};requestAnimationFrame(()=>setTimeout(o,50))},{threshold:0}),this.heightRetryObserver.observe(e)}clear(){if(this.isPagedMode){this.resetPagedState(),this.adjustListHeight();return}this.items=[]}async reload(){this.isPagedMode&&(this.resetPagedState(),await this.startPagedLoad(null))}async scrollToIndex(e,t="center"){if(await this.updateComplete,this.isMasonryLayout){this.masonryRef.value?.querySelectorAll(":scope > .repeater-masonry-cell")?.[e]?.scrollIntoView({block:t});return}const s=this.getVirtualizerElement();!s||!s.scrollToIndex||(await s.updateComplete,await new Promise(r=>requestAnimationFrame(r)),await s.layoutComplete,s.scrollToIndex(this.isGridLayout?Math.floor(e/this.effectiveGridColumns):e,t))}getVirtualizerElement(){return this.virtualizerRef.value}renderBlockingState(e,t,s){return h`<div class="state-panel" part="state" role=${s} aria-live=${M(s==="alert"?void 0:"polite")}>
13
13
  <slot name=${e}>
14
14
  <div class="state-message">${t}</div>
15
15
  </slot>
16
- </div>`}renderFooterState(){return this.renderedItems.length===0?I:this.activeErrorMessage.length>0?d`<div class="status-footer" part="footer" role="alert">
16
+ </div>`}renderFooterState(){return this.renderedItems.length===0?S:this.activeErrorMessage.length>0?h`<div class="status-footer" part="footer" role="alert">
17
17
  <slot name="error">
18
18
  <div class="state-message">${this.activeErrorMessage}</div>
19
19
  </slot>
20
- </div>`:this.isBusy?d`<div class="status-footer" part="footer" role="status" aria-live="polite">
20
+ </div>`:this.isBusy?h`<div class="status-footer" part="footer" role="status" aria-live="polite">
21
21
  <slot name="loading">
22
22
  <div class="state-message">${this.loadingMessage}</div>
23
23
  </slot>
24
- </div>`:I}render(){const e=this.isContainedScrollModel?{height:this.effectiveListHeight}:{},t=this.isGridLayout?this.renderGridVirtualItem:this.renderVirtualItem,i=j(this.scrollModel,d`<lit-virtualizer
25
- ${O(this.virtualizerRef)}
24
+ </div>`:this.footerHoldHeight>0?h`<div
25
+ class="status-footer-hold"
26
+ aria-hidden="true"
27
+ style=${p({height:`${this.footerHoldHeight}px`})}
28
+ ></div>`:S}renderMasonry(){const e=this.renderItem??(s=>this.renderFallbackItem(s)),t={gridTemplateColumns:`repeat(${this.effectiveGridColumns}, minmax(0, 1fr))`,gridAutoRows:`${P}px`};return h`<div
29
+ ${w(this.masonryRef)}
30
+ class="repeater-masonry"
31
+ part="scroller"
32
+ role="list"
33
+ aria-busy=${this.isBusy?"true":"false"}
34
+ aria-label=${M(this.ariaLabel??void 0)}
35
+ style=${p(t)}
36
+ >
37
+ ${T(this.renderedItems,(s,r)=>r,(s,r)=>h`<div class="repeater-item repeater-masonry-cell" part="item" role="listitem">
38
+ ${e(s,r)}
39
+ </div>`)}
40
+ </div>`}render(){const e=this.isContainedScrollModel?{height:this.effectiveListHeight}:{},t=this.isGridLayout?this.renderGridVirtualItem:this.renderVirtualItem,s=q(this.scrollModel,h`<lit-virtualizer
41
+ ${w(this.virtualizerRef)}
26
42
  class="repeater-virtualizer"
27
43
  part="scroller"
28
44
  ?scroller=${this.isContainedScrollModel}
@@ -33,15 +49,15 @@ var l=function(y,e,t,i){var r=arguments.length,s=r<3?e:i===null?i=Object.getOwnP
33
49
  .items=${this.virtualizerItems}
34
50
  .renderItem=${t}
35
51
  @rangeChanged=${r=>this.onRangeChanged(r)}
36
- ></lit-virtualizer>`);return d`<div
52
+ ></lit-virtualizer>`);return h`<div
37
53
  class="repeater-container"
38
54
  part="container"
39
- ${O(this.containerRef)}
40
- style=${A(e)}
55
+ ${w(this.containerRef)}
56
+ style=${p(e)}
41
57
  >
42
- ${this.renderedItems.length===0?this.activeErrorMessage.length>0?this.renderBlockingState("error",this.activeErrorMessage,"alert"):this.isBusy?this.renderBlockingState("skeleton",this.loadingMessage,"status"):this.renderBlockingState("empty",this.emptyMessage,"status"):i}
58
+ ${this.renderedItems.length===0?this.activeErrorMessage.length>0?this.renderBlockingState("error",this.activeErrorMessage,"alert"):this.isBusy?this.renderBlockingState("skeleton",this.loadingMessage,"status"):this.renderBlockingState("empty",this.emptyMessage,"status"):this.isMasonryLayout?this.renderMasonry():s}
43
59
  ${this.renderFooterState()}
44
- </div>`}};o.styles=[...E.styles,V`
60
+ </div>`}};a.styles=[...I.styles,B`
45
61
  .repeater-container {
46
62
  display: flex;
47
63
  flex-direction: column;
@@ -73,6 +89,10 @@ var l=function(y,e,t,i){var r=arguments.length,s=r<3?e:i===null?i=Object.getOwnP
73
89
  flex-shrink: 0;
74
90
  }
75
91
 
92
+ .status-footer-hold {
93
+ flex-shrink: 0;
94
+ }
95
+
76
96
  .state-message {
77
97
  color: var(--esp-color-text);
78
98
  font-style: italic;
@@ -115,8 +135,38 @@ var l=function(y,e,t,i){var r=arguments.length,s=r<3?e:i===null?i=Object.getOwnP
115
135
  padding-bottom: 0;
116
136
  }
117
137
 
138
+
139
+ .repeater-masonry {
140
+ display: grid;
141
+ grid-auto-flow: row dense;
142
+ align-items: start;
143
+ column-gap: var(
144
+ --esp-repeater-grid-column-gap,
145
+ var(--esp-repeater-gap, var(--esp-size-small))
146
+ );
147
+ min-height: 0;
148
+ padding: var(--esp-repeater-content-padding, 0);
149
+ }
150
+
151
+ :host([scroll-model="contained"]) .repeater-masonry {
152
+ flex: 0 1 auto;
153
+ overflow: auto;
154
+ }
155
+
156
+ :host([scroll-model="page"]) .repeater-masonry {
157
+ overflow: visible;
158
+ }
159
+
160
+ .repeater-masonry-cell {
161
+ min-width: 0;
162
+ padding-bottom: var(
163
+ --esp-repeater-grid-row-gap,
164
+ var(--esp-repeater-gap, var(--esp-size-small))
165
+ );
166
+ }
167
+
118
168
  pre {
119
169
  margin: 0;
120
170
  white-space: pre-wrap;
121
171
  }
122
- `],l([b()],o.prototype,"isLoadingPage",void 0),l([b()],o.prototype,"loadedItems",void 0),l([b()],o.prototype,"hasMoreData",void 0),l([b()],o.prototype,"effectiveListHeight",void 0),l([b()],o.prototype,"loadError",void 0),l([h({type:Array})],o.prototype,"items",void 0),l([h({attribute:!1})],o.prototype,"renderItem",void 0),l([h({type:String,reflect:!0})],o.prototype,"layout",void 0),l([h({attribute:"scroll-model",type:String,reflect:!0})],o.prototype,"scrollModel",void 0),l([h({attribute:"grid-columns",type:Number})],o.prototype,"gridColumns",void 0),l([h({attribute:"aria-label",type:String})],o.prototype,"ariaLabel",void 0),l([h({attribute:"list-height",type:String})],o.prototype,"listHeight",void 0),l([h({attribute:"page-size",type:Number})],o.prototype,"pageSize",void 0),l([h({attribute:"prefetch-threshold",type:Number})],o.prototype,"prefetchThreshold",void 0),l([h({type:Boolean})],o.prototype,"loading",void 0),l([h({attribute:"loading-message",type:String})],o.prototype,"loadingMessage",void 0),l([h({attribute:"empty-message",type:String})],o.prototype,"emptyMessage",void 0),l([h({attribute:"error-message",type:String})],o.prototype,"errorMessage",void 0),l([h({attribute:!1})],o.prototype,"fetchPage",null),o=l([F("esp-repeater")],o);export{o as EspalierRepeater};
172
+ `],n([g()],a.prototype,"isLoadingPage",void 0),n([g()],a.prototype,"loadedItems",void 0),n([g()],a.prototype,"hasMoreData",void 0),n([g()],a.prototype,"effectiveListHeight",void 0),n([g()],a.prototype,"loadError",void 0),n([g()],a.prototype,"footerHoldHeight",void 0),n([d({type:Array})],a.prototype,"items",void 0),n([d({attribute:!1})],a.prototype,"renderItem",void 0),n([d({type:String,reflect:!0})],a.prototype,"layout",void 0),n([d({attribute:"scroll-model",type:String,reflect:!0})],a.prototype,"scrollModel",void 0),n([d({attribute:"grid-columns",type:Number})],a.prototype,"gridColumns",void 0),n([d({attribute:"aria-label",type:String})],a.prototype,"ariaLabel",void 0),n([d({attribute:"list-height",type:String})],a.prototype,"listHeight",void 0),n([d({attribute:"page-size",type:Number})],a.prototype,"pageSize",void 0),n([d({attribute:"prefetch-threshold",type:Number})],a.prototype,"prefetchThreshold",void 0),n([d({type:Boolean})],a.prototype,"loading",void 0),n([d({attribute:"loading-message",type:String})],a.prototype,"loadingMessage",void 0),n([d({attribute:"empty-message",type:String})],a.prototype,"emptyMessage",void 0),n([d({attribute:"error-message",type:String})],a.prototype,"errorMessage",void 0),n([d({attribute:!1})],a.prototype,"fetchPage",null),a=n([N("esp-repeater")],a);export{a as EspalierRepeater};
@@ -137,6 +137,9 @@ var n=function(t,e,o,a){var l=arguments.length,i=l<3?e:a===null?a=Object.getOwnP
137
137
  }
138
138
 
139
139
  .status-popover {
140
+
141
+ white-space: normal;
142
+ overflow-wrap: anywhere;
140
143
  max-width: var(--esp-status-indicator-popover-max-width, 32ch);
141
144
  border: 1px solid var(--esp-color-border);
142
145
  border-radius: var(--esp-size-border-radius);
@@ -1,4 +1,4 @@
1
- var o=function(a,e,t,n){var p=arguments.length,r=p<3?e:n===null?n=Object.getOwnPropertyDescriptor(e,t):n,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(a,e,t,n);else for(var d=a.length-1;d>=0;d--)(l=a[d])&&(r=(p<3?l(r):p>3?l(e,t,r):l(e,t))||r);return p>3&&r&&Object.defineProperty(e,t,r),r};import{css as f,html as u,nothing as b}from"lit";import{customElement as y,property as s}from"lit/decorators.js";import{createRef as h,ref as c}from"lit/directives/ref.js";import{EspalierElementBase as g}from"../shared/esp-element-base.js";import"../popover/esp-popover.js";import{syncDescribedByTokens as v}from"../shared/aria-describedby.js";let x=0,i=class extends g{constructor(){super(...arguments),this.popoverRef=h(),this.contentRef=h(),this.tooltipId=`esp-tooltip-${++x}`,this.text="",this.attach="above",this.align="center",this.offset="4px",this.showDelay=300,this.hideDelay=100,this.triggerTabindexBacker=0,this.triggerTabindexExplicit=!1,this.handleKeydown=e=>{e.key==="Escape"&&this.popoverRef.value?.closePopover()},this.handleSlotChange=()=>{this.requestUpdate(),this.syncTriggerDescribedBy()}}get triggerTabindex(){return this.triggerTabindexBacker}set triggerTabindex(e){const t=this.triggerTabindexBacker;this.triggerTabindexExplicit=e!==null,this.triggerTabindexBacker=e!==null&&Number.isFinite(e)?e:0,this.requestUpdate("triggerTabindex",t)}get effectiveTriggerTabindex(){return this.triggerTabindexExplicit?this.triggerTabindex:this.hasButtonTrigger()?-1:0}hasButtonTrigger(){const e=Array.from(this.children).find(t=>t.tagName!=="TEMPLATE")?.tagName;return e==="BUTTON"||e==="ESP-BUTTON"}connectedCallback(){super.connectedCallback(),this.addEventListener("keydown",this.handleKeydown)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener("keydown",this.handleKeydown)}firstUpdated(e){super.firstUpdated(e);const t=this.querySelector("template");t&&this.contentRef.value&&this.contentRef.value.appendChild(t.content.cloneNode(!0)),this.syncTriggerDescribedBy()}updated(e){super.updated(e),e.has("triggerTabindex")&&this.syncTriggerDescribedBy()}syncTriggerDescribedBy(){const e=Array.from(this.children).find(t=>t.tagName!=="TEMPLATE");e&&v(e,{add:this.effectiveTriggerTabindex<0?[this.tooltipId]:[],remove:[this.tooltipId]})}render(){return u`
1
+ var o=function(a,e,t,n){var p=arguments.length,r=p<3?e:n===null?n=Object.getOwnPropertyDescriptor(e,t):n,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")r=Reflect.decorate(a,e,t,n);else for(var d=a.length-1;d>=0;d--)(l=a[d])&&(r=(p<3?l(r):p>3?l(e,t,r):l(e,t))||r);return p>3&&r&&Object.defineProperty(e,t,r),r};import{css as f,html as u,nothing as y}from"lit";import{customElement as b,property as s}from"lit/decorators.js";import{createRef as h,ref as c}from"lit/directives/ref.js";import{EspalierElementBase as g}from"../shared/esp-element-base.js";import"../popover/esp-popover.js";import{syncDescribedByTokens as v}from"../shared/aria-describedby.js";let x=0,i=class extends g{constructor(){super(...arguments),this.popoverRef=h(),this.contentRef=h(),this.tooltipId=`esp-tooltip-${++x}`,this.text="",this.attach="above",this.align="center",this.offset="4px",this.showDelay=300,this.hideDelay=100,this.triggerTabindexBacker=0,this.triggerTabindexExplicit=!1,this.handleKeydown=e=>{e.key==="Escape"&&this.popoverRef.value?.closePopover()},this.handleSlotChange=()=>{this.requestUpdate(),this.syncTriggerDescribedBy()}}get triggerTabindex(){return this.triggerTabindexBacker}set triggerTabindex(e){const t=this.triggerTabindexBacker;this.triggerTabindexExplicit=e!==null,this.triggerTabindexBacker=e!==null&&Number.isFinite(e)?e:0,this.requestUpdate("triggerTabindex",t)}get effectiveTriggerTabindex(){return this.triggerTabindexExplicit?this.triggerTabindex:this.hasButtonTrigger()?-1:0}hasButtonTrigger(){const e=Array.from(this.children).find(t=>t.tagName!=="TEMPLATE")?.tagName;return e==="BUTTON"||e==="ESP-BUTTON"}connectedCallback(){super.connectedCallback(),this.addEventListener("keydown",this.handleKeydown)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener("keydown",this.handleKeydown)}firstUpdated(e){super.firstUpdated(e);const t=this.querySelector("template");t&&this.contentRef.value&&this.contentRef.value.appendChild(t.content.cloneNode(!0)),this.syncTriggerDescribedBy()}updated(e){super.updated(e),e.has("triggerTabindex")&&this.syncTriggerDescribedBy()}syncTriggerDescribedBy(){const e=Array.from(this.children).find(t=>t.tagName!=="TEMPLATE");e&&v(e,{add:this.effectiveTriggerTabindex<0?[this.tooltipId]:[],remove:[this.tooltipId]})}render(){return u`
2
2
  <esp-popover
3
3
  ${c(this.popoverRef)}
4
4
  trigger="focus-hover"
@@ -23,7 +23,7 @@ var o=function(a,e,t,n){var p=arguments.length,r=p<3?e:n===null?n=Object.getOwnP
23
23
  role="tooltip"
24
24
  class="tooltip-content"
25
25
  >
26
- ${this.text?this.text:b}
26
+ ${this.text?this.text:y}
27
27
  </div>
28
28
  </esp-popover>
29
29
  `}};i.styles=[...g.styles,f`
@@ -44,6 +44,9 @@ var o=function(a,e,t,n){var p=arguments.length,r=p<3?e:n===null?n=Object.getOwnP
44
44
  }
45
45
 
46
46
  .tooltip-content {
47
+
48
+ white-space: normal;
49
+ overflow-wrap: anywhere;
47
50
  background: var(--esp-tooltip-background, var(--esp-color-layer-1));
48
51
  color: var(--esp-tooltip-color, var(--esp-color-text));
49
52
  border: var(--esp-tooltip-border, 1px solid var(--esp-color-border));
@@ -54,4 +57,4 @@ var o=function(a,e,t,n){var p=arguments.length,r=p<3?e:n===null?n=Object.getOwnP
54
57
  box-shadow: var(--esp-tooltip-shadow, 2px 2px 4px var(--esp-color-shadow));
55
58
  line-height: 1.4;
56
59
  }
57
- `],o([s({type:String})],i.prototype,"text",void 0),o([s({type:String})],i.prototype,"attach",void 0),o([s({type:String})],i.prototype,"align",void 0),o([s({type:String})],i.prototype,"offset",void 0),o([s({attribute:"show-delay",type:Number})],i.prototype,"showDelay",void 0),o([s({attribute:"hide-delay",type:Number})],i.prototype,"hideDelay",void 0),o([s({attribute:"trigger-tabindex",type:Number,hasChanged:()=>!0})],i.prototype,"triggerTabindex",null),i=o([y("esp-tooltip")],i);export{i as EspalierTooltip};
60
+ `],o([s({type:String})],i.prototype,"text",void 0),o([s({type:String})],i.prototype,"attach",void 0),o([s({type:String})],i.prototype,"align",void 0),o([s({type:String})],i.prototype,"offset",void 0),o([s({attribute:"show-delay",type:Number})],i.prototype,"showDelay",void 0),o([s({attribute:"hide-delay",type:Number})],i.prototype,"hideDelay",void 0),o([s({attribute:"trigger-tabindex",type:Number,hasChanged:()=>!0})],i.prototype,"triggerTabindex",null),i=o([b("esp-tooltip")],i);export{i as EspalierTooltip};
@@ -1523,15 +1523,15 @@
1523
1523
  },
1524
1524
  {
1525
1525
  "name": "--esp-repeater-grid-column-gap",
1526
- "description": "Horizontal gap between grid columns."
1526
+ "description": "Horizontal gap between grid or masonry columns."
1527
1527
  },
1528
1528
  {
1529
1529
  "name": "--esp-repeater-grid-columns",
1530
- "description": "Grid column count when `layout=\"grid\"`. Supports media-query overrides."
1530
+ "description": "Column count when `layout=\"grid\"` or `layout=\"masonry\"`. Supports media-query overrides."
1531
1531
  },
1532
1532
  {
1533
1533
  "name": "--esp-repeater-grid-row-gap",
1534
- "description": "Vertical gap between grid rows."
1534
+ "description": "Vertical gap between grid rows or stacked masonry cards."
1535
1535
  },
1536
1536
  {
1537
1537
  "name": "--esp-repeater-padding",
@@ -2185,19 +2185,19 @@
2185
2185
  "name": "--esp-repeater-grid-column-gap",
2186
2186
  "category": "component",
2187
2187
  "component": "esp-repeater",
2188
- "description": "Horizontal gap between grid columns."
2188
+ "description": "Horizontal gap between grid or masonry columns."
2189
2189
  },
2190
2190
  {
2191
2191
  "name": "--esp-repeater-grid-columns",
2192
2192
  "category": "component",
2193
2193
  "component": "esp-repeater",
2194
- "description": "Grid column count when `layout=\"grid\"`. Supports media-query overrides."
2194
+ "description": "Column count when `layout=\"grid\"` or `layout=\"masonry\"`. Supports media-query overrides."
2195
2195
  },
2196
2196
  {
2197
2197
  "name": "--esp-repeater-grid-row-gap",
2198
2198
  "category": "component",
2199
2199
  "component": "esp-repeater",
2200
- "description": "Vertical gap between grid rows."
2200
+ "description": "Vertical gap between grid rows or stacked masonry cards."
2201
2201
  },
2202
2202
  {
2203
2203
  "name": "--esp-repeater-padding",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taprootio/espalier",
3
- "version": "4.13.2",
3
+ "version": "4.14.1",
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",