@taprootio/espalier 2.13.1 → 2.15.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.
- package/CHANGELOG.md +34 -0
- package/custom-elements.json +7051 -5344
- package/dist/date-picker/esp-date-picker.js +22 -22
- package/dist/flyout/esp-flyout.js +14 -14
- package/dist/font-picker/esp-font-picker.js +3 -3
- package/dist/form/esp-form.js +1 -1
- package/dist/grid/esp-grid.d.ts +4 -12
- package/dist/grid/esp-grid.js +5 -5
- package/dist/header/esp-header.js +7 -7
- package/dist/lightbox/esp-lightbox.js +16 -16
- package/dist/page/esp-page.d.ts +27 -14
- package/dist/page/esp-page.js +85 -33
- package/dist/page/workspace-width.js +1 -0
- package/dist/pickers/esp-pick-one.d.ts +9 -30
- package/dist/pickers/esp-pick-one.js +18 -50
- package/dist/pickers/esp-pick-some.d.ts +4 -29
- package/dist/pickers/esp-pick-some.js +15 -42
- package/dist/pickers/esp-picker-base.d.ts +95 -0
- package/dist/pickers/esp-picker-base.js +33 -1
- package/dist/pickers/esp-picker-menu.d.ts +0 -2
- package/dist/pickers/esp-picker-menu.js +6 -6
- package/dist/pickers/pick-one-selection.js +1 -0
- package/dist/popover/esp-popover.js +6 -6
- package/dist/repeater/esp-repeater.d.ts +11 -8
- package/dist/repeater/esp-repeater.js +4 -4
- package/dist/shared/color-engine.js +1 -1
- package/dist/shared/cursor-pagination.d.ts +76 -0
- package/dist/shared/cursor-pagination.js +1 -0
- package/dist/shared/intent-values.d.ts +13 -2
- package/dist/shared/intent-values.js +1 -1
- package/dist/shared/popover-controller.js +1 -1
- package/dist/shared/raf-throttle.js +1 -0
- package/dist/shared/utilities.d.ts +27 -27
- package/dist/shared/utilities.js +1 -1
- package/dist/shared/viewport.d.ts +89 -0
- package/dist/shared/viewport.js +1 -0
- package/package.json +9 -1
- package/dist/header/esp-menu-group.js +0 -1
- package/dist/header/esp-menu-item.js +0 -1
- package/dist/header/esp-menu.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var l=function(y,e,t,i){var r=arguments.length,s=r<3?e:i===null?i=Object.getOwnPropertyDescriptor(e,t):i,
|
|
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
2
|
${i(e,t)}
|
|
3
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
|
|
4
4
|
class="repeater-row"
|
|
@@ -9,7 +9,7 @@ var l=function(y,e,t,i){var r=arguments.length,s=r<3?e:i===null?i=Object.getOwnP
|
|
|
9
9
|
${e.items.map((r,s)=>d`<div class="repeater-item repeater-grid-cell" part="item" role="listitem">
|
|
10
10
|
${t(r,e.startIndex+s)}
|
|
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.pageLoadVersion,s=this.activatePageScrollStabilizer(t,r);this.activePageScrollStabilizer=s;try{const o=await i({cursor:e,limit:this.normalizedPageSize});if(r!==this.pageLoadVersion)return;e===null?this.loadedItems=[...o.items]:this.loadedItems=[...this.loadedItems,...o.items],this.nextCursor=o.nextCursor,this.hasMoreData=o.nextCursor!==null,this.loadError=""}catch(o){if(r!==this.pageLoadVersion)return;this.nextCursor=null,this.hasMoreData=!1,this.loadError=o instanceof Error&&o.message.length>0?o.message:"Unable to load items."}finally{try{r===this.pageLoadVersion&&(this.isLoadingPage=!1),r===this.pageLoadVersion&&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||t!==this.pageLoadVersion)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 o="",g=r>0?Math.max(64,r*.5):Number.POSITIVE_INFINITY;let u=e,p=window.scrollY;const m=()=>{if(t!==this.pageLoadVersion)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=o)}}}async restorePageScrollPositionIfNeeded(e,t){if(e===null||!this.isPageScrollModel||t!==this.pageLoadVersion)return;await this.updateComplete;const i=this.getVirtualizerElement();i?.updateComplete&&await i.updateComplete,await new Promise(r=>requestAnimationFrame(r)),i?.layoutComplete&&await i.layoutComplete,t===this.pageLoadVersion&&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.pageLoadVersion+=1,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 o=0,g=!1;if(s.forEach(n=>{const f=n.offsetHeight;f===0&&(g=!0),o+=f}),s.length===0||g||o===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),o=0,s.forEach(n=>{o+=n.offsetHeight}));const z=t.querySelector(":scope > .status-footer")?.offsetHeight??0,v=o+z,x=t.offsetHeight,V=this.virtualizerItems.length;let R=!1;v>0&&v<x&&s.length>=V&&(i.style.minHeight=`${o}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(k=>{const H=k.offsetHeight;H===0&&(L=!0),S+=H}),C.length===0||L||S===0)return;const $=n.querySelector(":scope > .status-footer")?.offsetHeight??0,P=S+$;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(o=>o.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):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")}>
|
|
13
13
|
<slot name=${e}>
|
|
14
14
|
<div class="state-message">${t}</div>
|
|
15
15
|
</slot>
|
|
@@ -41,7 +41,7 @@ var l=function(y,e,t,i){var r=arguments.length,s=r<3?e:i===null?i=Object.getOwnP
|
|
|
41
41
|
>
|
|
42
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}
|
|
43
43
|
${this.renderFooterState()}
|
|
44
|
-
</div>`}};
|
|
44
|
+
</div>`}};o.styles=[...E.styles,V`
|
|
45
45
|
.repeater-container {
|
|
46
46
|
display: flex;
|
|
47
47
|
flex-direction: column;
|
|
@@ -119,4 +119,4 @@ var l=function(y,e,t,i){var r=arguments.length,s=r<3?e:i===null?i=Object.getOwnP
|
|
|
119
119
|
margin: 0;
|
|
120
120
|
white-space: pre-wrap;
|
|
121
121
|
}
|
|
122
|
-
`],l([b()],
|
|
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};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
const S=Math.PI/180,s=1e-4,w=50;function P(t){const o=t.h*S;return{L:t.l,a:t.c*Math.cos(o),b:t.c*Math.sin(o)}}function k(t){const o=t.L+.3963377774*t.a+.2158037573*t.b,e=t.L-.1055613458*t.a-.0638541728*t.b,n=t.L-.0894841775*t.a-1.291485548*t.b,r=o*o*o,c=e*e*e,a=n*n*n;return{r:4.0767416621*r-3.3077115913*c+.2309699292*a,g:-1.2684380046*r+2.6097574011*c-.3413193965*a,b:-.0041960863*r-.7034186147*c+1.707614701*a}}function p(t){return t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055}function N(t){return{r:p(t.r),g:p(t.g),b:p(t.b)}}function O(t){return t.r>=-s&&t.r<=1+s&&t.g>=-s&&t.g<=1+s&&t.b>=-s&&t.b<=1+s}function M(t){return Math.max(0,Math.min(1,t))}function X(t){const e=t.trim().match(/^oklch\(\s*([\d.]+)(%?)\s+([\d.]+)\s+([\d.]+)\s*\)$/i);if(!e)return null;let n=parseFloat(e[1]);e[2]==="%"&&(n/=100);const r=parseFloat(e[3]),c=parseFloat(e[4]);return isNaN(n)||isNaN(r)||isNaN(c)?null:{l:n,c:r,h:(c%360+360)%360}}function $(t){const o=T(t.l,6),e=T(t.c,6),n=T((t.h%360+360)%360,4);return`oklch(${o} ${e} ${n})`}function m(t){return N(k(P(t)))}function _(t){return O(m(t))}function h(t){if(t.c<=s||_(t))return{...t};let o=0,e=t.c,n={...t};for(let r=0;r<w;r++){const c=(o+e)/2;if(n={l:t.l,c,h:t.h},_(n)?o=c:e=c,e-o<s)break}return{l:t.l,c:o,h:t.h}}function E(t,o,e){const n={l:t.l,c:Math.max(o,Math.min(e,t.c)),h:t.h};return h(n)}const f=.022,G=.012,x=.022,C=.57,L=.56,R=1.14,A=.001,l=.027;function d(t){const o=Math.pow(M(t.r),2.4),e=Math.pow(M(t.g),2.4),n=Math.pow(M(t.b),2.4);return .2126729*o+.7151522*e+.072175*n}function B(t,o){const e=m(h(t)),n=m(h(o));let r=d(e),c=d(n);if(r=r>f?r:r+Math.pow(f-r,1.414),c=c>f?c:c+Math.pow(f-c,1.414),Math.abs(c-r)<A)return 0;let a;if(c>r){const i=Math.pow(c,L),u=Math.pow(r,C);if(a=(i-u)*R,a<A)return 0;a=a<l?a-a*x*l:a-x}else{const i=Math.pow(c,L),u=Math.pow(r,C);if(a=(i-u)*R,a>-A)return 0;a=a>-l?a-a*G*l:a+G}return a*100}function F(t,o,e=60){let n=h({...t}),r=Math.abs(B(n,o));if(r>=e)return n;const c=o.l>.5,a=.01,i=c?0:1;for(let u=0;u<100;u++){if(c?n.l=Math.max(i,n.l-a):n.l=Math.min(i,n.l+a),n=h(n),r=Math.abs(B(n,o)),r>=e)return n;if(n.l<=0||n.l>=1)break}return n}function b(t,o){return((t+o)%360+360)%360}function I(t,o,e,n){return E({l:o,c:t.c,h:t.h},e,n)}function W(t,o,e,n,r,c=60){const a=I(t,o,e,n);return F(a,r,c)}function T(t,o){const e=Math.pow(10,o);return Math.round(t*e)/e}export{B as apcaContrast,E as clampChromaAndGamutMap,I as deriveSemantic,W as deriveSemanticWithContrast,F as ensureContrast,h as gamutMapToSRGB,_ as isInSRGBGamut,m as oklchToSRGB,X as parseOklch,b as rotateHue,$ as serializeOklch};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module cursor-pagination
|
|
3
|
+
*
|
|
4
|
+
* Shared vocabulary and the stale-response guard for cursor-paginated
|
|
5
|
+
* components (`esp-grid`, `esp-repeater`).
|
|
6
|
+
*
|
|
7
|
+
* **Why this is types plus one small class, and not a controller.** Both
|
|
8
|
+
* components run the same four-step core — bump a version, fetch, discard the
|
|
9
|
+
* response if a newer request started, replace-or-append — but everything
|
|
10
|
+
* around it differs: the grid dispatches four lifecycle events, rethrows, and
|
|
11
|
+
* resets the virtualizer's scroll; the repeater runs a page-scroll stabilizer
|
|
12
|
+
* and swallows errors into a `loadError` string. A controller covering both
|
|
13
|
+
* would need roughly five configuration hooks to absorb ~36 lines of shared
|
|
14
|
+
* code — more interface than implementation, for two callers.
|
|
15
|
+
*
|
|
16
|
+
* So the parts that genuinely benefit from being shared are extracted: the
|
|
17
|
+
* public type vocabulary, which was duplicated under two sets of names, and the
|
|
18
|
+
* version guard, which is the correctness core and the piece most likely to be
|
|
19
|
+
* subtly wrong when written twice.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* The request for one page of cursor-paginated data.
|
|
23
|
+
*
|
|
24
|
+
* Components may extend this with their own query context — see `esp-grid`'s
|
|
25
|
+
* `CursorFetchParams`, which adds search and sort.
|
|
26
|
+
*/
|
|
27
|
+
export interface CursorPageRequest {
|
|
28
|
+
/** Cursor for the page to fetch. `null` means the first page. */
|
|
29
|
+
cursor: string | null;
|
|
30
|
+
/** How many items to request. */
|
|
31
|
+
limit: number;
|
|
32
|
+
}
|
|
33
|
+
/** One page of cursor-paginated results. */
|
|
34
|
+
export interface CursorPageResult<T> {
|
|
35
|
+
/** The items for this page. */
|
|
36
|
+
items: T[];
|
|
37
|
+
/** Cursor for the next page, or `null` when there are none. */
|
|
38
|
+
nextCursor: string | null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Monotonic token issuer for discarding superseded async responses.
|
|
42
|
+
*
|
|
43
|
+
* A user typing in a search box, or scrolling fast enough to trigger several
|
|
44
|
+
* page loads, produces overlapping requests that can resolve out of order.
|
|
45
|
+
* Without a guard, a slow early response overwrites a fast later one and the
|
|
46
|
+
* component shows stale data.
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* const token = this.pageLoads.begin();
|
|
50
|
+
* const result = await fetchPage(params);
|
|
51
|
+
* if (!this.pageLoads.isCurrent(token)) return; // superseded — drop it
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* Every `await` boundary in the load path needs a re-check: being current
|
|
55
|
+
* before the fetch says nothing about being current after it.
|
|
56
|
+
*/
|
|
57
|
+
export declare class RequestVersionGuard {
|
|
58
|
+
/** Start a request and take its token. Supersedes every outstanding one. */
|
|
59
|
+
begin(): number;
|
|
60
|
+
/** Whether `token` is still the newest request. */
|
|
61
|
+
isCurrent(token: number): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Supersede every outstanding request without starting a new one.
|
|
64
|
+
*
|
|
65
|
+
* Use when a component disconnects or its data source changes and in-flight
|
|
66
|
+
* responses should be dropped rather than applied.
|
|
67
|
+
*/
|
|
68
|
+
invalidate(): void;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Apply a page of results to an accumulated list: the first page replaces,
|
|
72
|
+
* subsequent pages append.
|
|
73
|
+
*
|
|
74
|
+
* Always returns a new array so Lit sees the change.
|
|
75
|
+
*/
|
|
76
|
+
export declare function accumulatePage<T>(current: readonly T[], page: readonly T[], cursor: string | null): T[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class n{constructor(){this.version=0}begin(){return++this.version}isCurrent(r){return r===this.version}invalidate(){this.version++}}function i(e,r,t){return t===null?[...r]:[...e,...r]}export{n as RequestVersionGuard,i as accumulatePage};
|
|
@@ -3,8 +3,19 @@ export declare const DEFAULT_ICON_SPRITE_URL = "/assets/icons.svg";
|
|
|
3
3
|
export declare const DEFAULT_ICON_VIEW_BOX = "0 0 24 24";
|
|
4
4
|
export declare const INTENT_VARIANTS: readonly EspalierIntentVariant[];
|
|
5
5
|
export declare function normalizeIntentVariant(value: string | null | undefined): EspalierIntentVariant;
|
|
6
|
-
export declare function
|
|
7
|
-
|
|
6
|
+
export declare function getIconHrefForHost(icon: string | null | undefined, host?: Element | null | undefined): string;
|
|
7
|
+
/**
|
|
8
|
+
* Former name of `getIconHrefForHost`.
|
|
9
|
+
*
|
|
10
|
+
* @deprecated Use `getIconHrefForHost`. This alias is retained for one release
|
|
11
|
+
* so existing consumers keep compiling; it will be removed after that.
|
|
12
|
+
*
|
|
13
|
+
* NOTE: do not use an inline `{@link}` tag in this comment. On an exported
|
|
14
|
+
* `const` alias the custom-elements-manifest analyzer tries to resolve the link
|
|
15
|
+
* target and serializes the TypeScript AST node, which fails `build-cem` with
|
|
16
|
+
* "Converting circular structure to JSON". A plain backticked name is safe.
|
|
17
|
+
*/
|
|
18
|
+
export declare const getIconHref: typeof getIconHrefForHost;
|
|
8
19
|
export declare function getIconSpriteUrl(host: Element | null | undefined): string;
|
|
9
20
|
/**
|
|
10
21
|
* Reset the per-process record of which invalid icon names have
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{traverseToClosest as a}from"./utilities.js";const i="/assets/icons.svg",p="0 0 24 24",c=/^[A-Za-z0-9][A-Za-z0-9_-]*$/u,l=100,r=new Set,o=[],u=["neutral","success","warning","danger","info"];function N(n){return u.includes(n)?n:"neutral"}function I(n,t=null){const e=n?.trim()??"";if(!c.test(e))return e.length>0&&m(e)&&console.warn(`Invalid Espalier icon name "${e}". Icon names must start with a letter or number and may only contain letters, numbers, dashes, and underscores.`),"";const s=d(t);return s?`${s}#${e}`:""}const _=I;function d(n){const t=n?a(n,"esp-root"):null;return(t?(t.iconSpriteUrl??"").trim():i).split("#")[0]?.trim()||""}function m(n){if(r.has(n))return!1;if(r.add(n),o.push(n),o.length>l){const t=o.shift();t&&r.delete(t)}return!0}function g(){r.clear(),o.length=0}export{i as DEFAULT_ICON_SPRITE_URL,p as DEFAULT_ICON_VIEW_BOX,u as INTENT_VARIANTS,
|
|
1
|
+
import{traverseToClosest as a}from"./utilities.js";const i="/assets/icons.svg",p="0 0 24 24",c=/^[A-Za-z0-9][A-Za-z0-9_-]*$/u,l=100,r=new Set,o=[],u=["neutral","success","warning","danger","info"];function N(n){return u.includes(n)?n:"neutral"}function I(n,t=null){const e=n?.trim()??"";if(!c.test(e))return e.length>0&&m(e)&&console.warn(`Invalid Espalier icon name "${e}". Icon names must start with a letter or number and may only contain letters, numbers, dashes, and underscores.`),"";const s=d(t);return s?`${s}#${e}`:""}const _=I;function d(n){const t=n?a(n,"esp-root"):null;return(t?(t.iconSpriteUrl??"").trim():i).split("#")[0]?.trim()||""}function m(n){if(r.has(n))return!1;if(r.add(n),o.push(n),o.length>l){const t=o.shift();t&&r.delete(t)}return!0}function g(){r.clear(),o.length=0}export{i as DEFAULT_ICON_SPRITE_URL,p as DEFAULT_ICON_VIEW_BOX,u as INTENT_VARIANTS,_ as getIconHref,I as getIconHrefForHost,d as getIconSpriteUrl,N as normalizeIntentVariant,g as resetWarnedInvalidIconNames};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getEspBus as c}from"./bus-events.js";function
|
|
1
|
+
import{getEspBus as c}from"./bus-events.js";import{RafThrottle as h}from"./raf-throttle.js";function p(r){const t=[],s=new Set;let e=r;for(;e&&!s.has(e);){s.add(e);const i=e["linked-popover"];if(i){e=i;continue}const o=e.closest("esp-popover");if(o){t.includes(o)||t.push(o),e=o.parentElement||o.getRootNode()?.host;continue}const n=e.getRootNode();e=n instanceof ShadowRoot?n.host:void 0}return t}class d{constructor(t){this.bus=c(),this.positionFrame=new h(()=>this.runPositionUpdate()),this.positionResizeObserver=null,this.handleClosePopovers=s=>{if(!this.opts.isOpen())return;const e=this.opts.host;if(this.opts.closeStrategy==="source-identity"){if(!s.source||s.source===e||s.source instanceof Node&&(e.contains(s.source)||e.shadowRoot?.contains(s.source)))return}else if(s.skipPopovers?.includes(e))return;this.opts.onShouldClose()},this.onScrollOrResize=()=>this.positionFrame.schedule(),this.onDocumentClick=s=>{const e=this.opts.host,i=s.composedPath();if(i.includes(e))return;const o=this.opts.getInsideElements?.()??[];for(const n of o)if(n&&i.includes(n))return;this.opts.isOpen()&&this.opts.onOutsideClick?.()},this.opts=t,t.host.addController(this)}hostConnected(){this.bus.subscribe("close-popovers",this.handleClosePopovers)}hostDisconnected(){this.bus.unsubscribe("close-popovers",this.handleClosePopovers),this.stopTracking(),this.stopOutsideClick()}runPositionUpdate(){if(this.opts.isOpen()){if(this.opts.shouldContinueTracking&&!this.opts.shouldContinueTracking()){this.opts.onShouldClose();return}this.opts.onPositionUpdate?.()}}startTracking(){if(this.opts.onPositionUpdate&&(window.addEventListener("scroll",this.onScrollOrResize,{capture:!0,passive:!0}),window.addEventListener("resize",this.onScrollOrResize,{passive:!0}),this.opts.getPositionElements&&typeof ResizeObserver<"u")){this.positionResizeObserver?.disconnect(),this.positionResizeObserver=new ResizeObserver(this.onScrollOrResize);const t=new Set(this.opts.getPositionElements().filter(Boolean));for(const s of t)this.positionResizeObserver.observe(s)}}stopTracking(){window.removeEventListener("scroll",this.onScrollOrResize,{capture:!0}),window.removeEventListener("resize",this.onScrollOrResize),this.positionResizeObserver?.disconnect(),this.positionResizeObserver=null,this.positionFrame.cancel()}startOutsideClick(){this.opts.onOutsideClick&&document.addEventListener("click",this.onDocumentClick,!0)}stopOutsideClick(){document.removeEventListener("click",this.onDocumentClick,!0)}publishCloseOthers(t=[]){this.bus.publish("close-popovers",{source:this.opts.host,...t.length>0?{skipPopovers:t}:{}})}}export{d as PopoverController,p as findContainingPopovers};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class l{constructor(e){this.callback=e,this.frameId=null}get isScheduled(){return this.frameId!==null}schedule(){this.frameId===null&&(this.frameId=requestAnimationFrame(()=>{this.frameId=null,this.callback()}))}restart(){this.cancel(),this.schedule()}cancel(){this.frameId!==null&&(cancelAnimationFrame(this.frameId),this.frameId=null)}}export{l as RafThrottle};
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
type SpaceAboveBelow = {
|
|
2
|
-
spaceAbove: number;
|
|
3
|
-
spaceBelow: number;
|
|
4
|
-
};
|
|
5
1
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* @returns An object containing spaceAbove and spaceBelow in pixels
|
|
2
|
+
* `getSpaceAboveBelow` now lives in `./viewport.js` alongside the rest of the
|
|
3
|
+
* viewport measurement helpers. It is re-exported here because
|
|
4
|
+
* `@taprootio/espalier/shared/utilities` is a published entry point.
|
|
10
5
|
*/
|
|
11
|
-
export
|
|
6
|
+
export { getSpaceAboveBelow, type SpaceAboveBelow } from "./viewport.js";
|
|
12
7
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
8
|
+
* Scroll an element into view within a scrollable container.
|
|
9
|
+
*
|
|
10
|
+
* @deprecated No longer used by Espalier. Prefer `Element.scrollIntoView` with
|
|
11
|
+
* `block: "nearest"`, which the platform implements natively. Scheduled for
|
|
12
|
+
* removal in the next major release.
|
|
15
13
|
*
|
|
16
14
|
* @param container - The scrollable container element
|
|
17
15
|
* @param element - The element to scroll into view
|
|
@@ -19,31 +17,34 @@ export declare function getSpaceAboveBelow(element: HTMLElement): SpaceAboveBelo
|
|
|
19
17
|
*/
|
|
20
18
|
export declare function scrollElementIntoView(container: HTMLElement, element: HTMLElement, up: boolean): void;
|
|
21
19
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
* Whether an element or any ancestor is fixed-positioned, crossing shadow
|
|
21
|
+
* boundaries.
|
|
24
22
|
*
|
|
25
|
-
* @
|
|
26
|
-
*
|
|
27
|
-
* @param selector - The CSS selector to match against
|
|
28
|
-
* @returns The closest matching element, or null if none found
|
|
29
|
-
*/
|
|
30
|
-
export declare function traverseToClosest<TElement extends HTMLElement>(fromElement: Element, selector: string): TElement | null;
|
|
31
|
-
/**
|
|
32
|
-
* Checks if an element or any of its ancestors have a fixed position within a Shadow DOM.
|
|
33
|
-
* Recursively traverses the Shadow DOM tree to detect fixed positioning.
|
|
23
|
+
* @deprecated No longer used by Espalier. Scheduled for removal in the next
|
|
24
|
+
* major release.
|
|
34
25
|
*
|
|
35
26
|
* @param element - The element to check
|
|
36
|
-
* @returns True if the element or any ancestor is fixed-positioned within Shadow DOM, false otherwise
|
|
37
27
|
*/
|
|
38
28
|
export declare function isFixedInShadowDom(element: HTMLElement): boolean;
|
|
39
29
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
30
|
+
* Whether an element or any light-DOM ancestor is fixed-positioned.
|
|
31
|
+
*
|
|
32
|
+
* @deprecated No longer used by Espalier. Scheduled for removal in the next
|
|
33
|
+
* major release.
|
|
42
34
|
*
|
|
43
35
|
* @param element - The element to check
|
|
44
|
-
* @returns True if the element or any ancestor has position: fixed, false otherwise
|
|
45
36
|
*/
|
|
46
37
|
export declare function isFixedOrAncestorFixed(element: HTMLElement): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Traverses up the DOM tree from a given element to find the closest matching element.
|
|
40
|
+
* Handles traversal across Shadow DOM boundaries to locate elements in parent scopes.
|
|
41
|
+
*
|
|
42
|
+
* @template TElement - The expected type of the returned element
|
|
43
|
+
* @param fromElement - The element to start the search from
|
|
44
|
+
* @param selector - The CSS selector to match against
|
|
45
|
+
* @returns The closest matching element, or null if none found
|
|
46
|
+
*/
|
|
47
|
+
export declare function traverseToClosest<TElement extends HTMLElement>(fromElement: Element, selector: string): TElement | null;
|
|
47
48
|
/**
|
|
48
49
|
* Compares two arrays to check if they contain the same values for a specific key.
|
|
49
50
|
* Arrays are compared by extracting values for the given key, sorting them, and checking equality.
|
|
@@ -55,4 +56,3 @@ export declare function isFixedOrAncestorFixed(element: HTMLElement): boolean;
|
|
|
55
56
|
* @returns True if both arrays have the same length and matching values for the key, false otherwise
|
|
56
57
|
*/
|
|
57
58
|
export declare const arrayKeysMatch: (arr1: Array<Record<string, unknown>>, arr2: Array<Record<string, unknown>>, key: string) => boolean;
|
|
58
|
-
export {};
|
package/dist/shared/utilities.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import{getSpaceAboveBelow as g}from"./viewport.js";function c(t,e,o){const n=t.getBoundingClientRect(),r=e.getBoundingClientRect();if(r.top<n.top||r.bottom>n.bottom){const s=r.top-n.top;o||s<0?t.scrollTop+=s:t.scrollBy({top:r.height})}}function f(t){let e=t;for(;e;){if(i(e.assignedSlot?.parentNode)||getComputedStyle(e).position==="fixed")return!0;const o=e.assignedSlot?e.assignedSlot.getRootNode():e.getRootNode();if(!(o instanceof ShadowRoot))break;e=o.host}return!1}function i(t){if(!t||!(t instanceof HTMLElement))return!1;let e=t;for(;e;){if(getComputedStyle(e).position==="fixed")return!0;e=e.parentElement}return!1}function u(t,e){let o=t,n=null;for(;!n&&o&&o.closest;)if(n=o.closest(e),!n){const r=o.getRootNode();r instanceof ShadowRoot?o=r.host:o=void 0}return n}const d=(t,e,o)=>{if(t.length!==e.length)return!1;const n=t.map(s=>s[o]).sort(),r=e.map(s=>s[o]).sort();return n.every((s,l)=>s===r[l])};export{d as arrayKeysMatch,g as getSpaceAboveBelow,f as isFixedInShadowDom,i as isFixedOrAncestorFixed,c as scrollElementIntoView,u as traverseToClosest};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module viewport
|
|
3
|
+
*
|
|
4
|
+
* Shared viewport measurement for anchored surfaces (picker menus, popovers,
|
|
5
|
+
* date-picker calendars).
|
|
6
|
+
*
|
|
7
|
+
* Before this module the expression
|
|
8
|
+
* `window.innerHeight || document.documentElement.clientHeight` appeared in six
|
|
9
|
+
* files, and the `spaceAbove` / `spaceBelow` pair was recomputed inline at three
|
|
10
|
+
* call sites even though `getSpaceAboveBelow` already existed and had no
|
|
11
|
+
* callers.
|
|
12
|
+
*
|
|
13
|
+
* **On `visualViewport`:** `esp-page` deliberately measures against
|
|
14
|
+
* `window.visualViewport` so a pinch-zoomed or split-pane page allocates panes
|
|
15
|
+
* against what is actually visible. The anchored surfaces here intentionally do
|
|
16
|
+
* **not**: `visualViewport.height` shrinks when the software keyboard opens,
|
|
17
|
+
* and the pickers' keyboard-avoidance logic (`KEYBOARD_THRESHOLD` in
|
|
18
|
+
* `esp-picker-base`) is tuned against `innerHeight` staying stable. Unifying the
|
|
19
|
+
* two is a real improvement but a behavioural change, so it is deliberately not
|
|
20
|
+
* bundled into this refactor.
|
|
21
|
+
*/
|
|
22
|
+
export interface ViewportSize {
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
}
|
|
26
|
+
export interface SpaceAboveBelow {
|
|
27
|
+
spaceAbove: number;
|
|
28
|
+
spaceBelow: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The layout viewport in CSS pixels.
|
|
32
|
+
*
|
|
33
|
+
* `innerHeight` / `innerWidth` are the primary source; the `documentElement`
|
|
34
|
+
* client dimensions are the fallback for environments that report zero (notably
|
|
35
|
+
* happy-dom in tests).
|
|
36
|
+
*/
|
|
37
|
+
export declare function viewportSize(): ViewportSize;
|
|
38
|
+
/**
|
|
39
|
+
* Space above and below an already-measured rect.
|
|
40
|
+
*
|
|
41
|
+
* Prefer this over {@link getSpaceAboveBelow} in scroll- or resize-driven paths
|
|
42
|
+
* where the caller already holds a rect — it avoids a second forced layout.
|
|
43
|
+
*
|
|
44
|
+
* @param rect - A rect in viewport coordinates
|
|
45
|
+
* @param height - Viewport height; measured when omitted
|
|
46
|
+
*/
|
|
47
|
+
export declare function spaceAroundRect(rect: DOMRect, height?: number): SpaceAboveBelow;
|
|
48
|
+
/**
|
|
49
|
+
* Space above and below an element, relative to the viewport.
|
|
50
|
+
*
|
|
51
|
+
* @param element - The element to measure
|
|
52
|
+
*/
|
|
53
|
+
export declare function getSpaceAboveBelow(element: HTMLElement): SpaceAboveBelow;
|
|
54
|
+
/**
|
|
55
|
+
* Whether the user has asked the platform to reduce motion.
|
|
56
|
+
*
|
|
57
|
+
* Defaults to `false` where `matchMedia` is missing or returns nothing, so a
|
|
58
|
+
* constrained runtime gets ordinary motion rather than a thrown error.
|
|
59
|
+
*/
|
|
60
|
+
export declare function prefersReducedMotion(): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* The scroll behavior to use for programmatic scrolling — `"auto"` when the
|
|
63
|
+
* user prefers reduced motion, `"smooth"` otherwise.
|
|
64
|
+
*
|
|
65
|
+
* Every programmatic scroll in the library should go through this rather than
|
|
66
|
+
* hard-coding `behavior: "smooth"`.
|
|
67
|
+
*/
|
|
68
|
+
export declare function scrollBehavior(): ScrollBehavior;
|
|
69
|
+
/**
|
|
70
|
+
* Gap left between an anchored surface and the viewport edge after scrolling it
|
|
71
|
+
* back into view, so the surface does not sit flush against the edge.
|
|
72
|
+
*/
|
|
73
|
+
export declare const ANCHORED_SURFACE_SCROLL_MARGIN = 8;
|
|
74
|
+
/**
|
|
75
|
+
* Scroll the page so that an anchor (a trigger field) and its anchored surface
|
|
76
|
+
* (a dropdown, menu, or calendar) are both visible.
|
|
77
|
+
*
|
|
78
|
+
* Called when the viewport shrinks out from under an open surface — most often
|
|
79
|
+
* a software keyboard appearing on mobile. Does nothing when the pair already
|
|
80
|
+
* fits.
|
|
81
|
+
*
|
|
82
|
+
* `onReposition` runs on the next frame so the caller can re-run its own
|
|
83
|
+
* placement math against the new scroll offset.
|
|
84
|
+
*
|
|
85
|
+
* @param anchor - The trigger element
|
|
86
|
+
* @param surface - The open surface anchored to it
|
|
87
|
+
* @param onReposition - Re-placement callback, invoked only when a scroll happened
|
|
88
|
+
*/
|
|
89
|
+
export declare function scrollToContainAnchoredSurface(anchor: HTMLElement, surface: HTMLElement, onReposition: () => void): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function d(){return{width:window.innerWidth||document.documentElement.clientWidth,height:window.innerHeight||document.documentElement.clientHeight}}function l(t,e=d().height){return{spaceAbove:t.top,spaceBelow:e-t.bottom}}function m(t){return l(t.getBoundingClientRect())}function h(){return window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches??!1}function p(){return h()?"auto":"smooth"}const s=8;function w(t,e,a){const o=t.getBoundingClientRect(),n=e.getBoundingClientRect(),{height:i}=d(),c=Math.min(o.top,n.top),r=Math.max(o.bottom,n.bottom),u=p();if(r>i)window.scrollBy({top:r-i+s,behavior:u});else if(c<0)window.scrollBy({top:c-s,behavior:u});else return;requestAnimationFrame(a)}export{s as ANCHORED_SURFACE_SCROLL_MARGIN,m as getSpaceAboveBelow,h as prefersReducedMotion,p as scrollBehavior,w as scrollToContainAnchoredSurface,l as spaceAroundRect,d as viewportSize};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taprootio/espalier",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.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",
|
|
@@ -270,6 +270,14 @@
|
|
|
270
270
|
"types": "./dist/shared/font-helpers.d.ts",
|
|
271
271
|
"import": "./dist/shared/font-helpers.js"
|
|
272
272
|
},
|
|
273
|
+
"./shared/cursor-pagination": {
|
|
274
|
+
"types": "./dist/shared/cursor-pagination.d.ts",
|
|
275
|
+
"import": "./dist/shared/cursor-pagination.js"
|
|
276
|
+
},
|
|
277
|
+
"./shared/viewport": {
|
|
278
|
+
"types": "./dist/shared/viewport.d.ts",
|
|
279
|
+
"import": "./dist/shared/viewport.js"
|
|
280
|
+
},
|
|
273
281
|
"./shared/utilities": {
|
|
274
282
|
"types": "./dist/shared/utilities.d.ts",
|
|
275
283
|
"import": "./dist/shared/utilities.js"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export*from"../menu/esp-menu-group.js";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export*from"../menu/esp-menu-item.js";
|
package/dist/header/esp-menu.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export*from"../menu/esp-menu.js";
|