@floor/vlist 0.5.7 → 0.6.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/README.md +793 -592
- package/dist/async/index.js +1 -0
- package/dist/builder/context.d.ts +3 -3
- package/dist/builder/context.d.ts.map +1 -1
- package/dist/builder/core.d.ts +1 -1
- package/dist/builder/core.d.ts.map +1 -1
- package/dist/builder/index.js +1 -250
- package/dist/builder/types.d.ts +3 -3
- package/dist/builder/types.d.ts.map +1 -1
- package/dist/compression/index.js +1 -104
- package/dist/core/core.js +1 -0
- package/dist/core/full.d.ts +22 -0
- package/dist/core/full.d.ts.map +1 -0
- package/dist/core/index.js +1 -133
- package/dist/core/lite.d.ts +129 -0
- package/dist/core/lite.d.ts.map +1 -0
- package/dist/core/minimal.d.ts +104 -0
- package/dist/core/minimal.d.ts.map +1 -0
- package/dist/core-light.js +1 -68
- package/dist/data/index.js +1 -233
- package/dist/features/async/index.d.ts +9 -0
- package/dist/features/async/index.d.ts.map +1 -0
- package/dist/features/async/manager.d.ts +103 -0
- package/dist/features/async/manager.d.ts.map +1 -0
- package/dist/features/async/placeholder.d.ts +62 -0
- package/dist/features/async/placeholder.d.ts.map +1 -0
- package/dist/features/async/plugin.d.ts +60 -0
- package/dist/features/async/plugin.d.ts.map +1 -0
- package/dist/features/async/sparse.d.ts +91 -0
- package/dist/features/async/sparse.d.ts.map +1 -0
- package/dist/features/grid/index.d.ts +9 -0
- package/dist/features/grid/index.d.ts.map +1 -0
- package/dist/features/grid/layout.d.ts +29 -0
- package/dist/features/grid/layout.d.ts.map +1 -0
- package/dist/features/grid/plugin.d.ts +48 -0
- package/dist/features/grid/plugin.d.ts.map +1 -0
- package/dist/features/grid/renderer.d.ts +55 -0
- package/dist/features/grid/renderer.d.ts.map +1 -0
- package/dist/features/grid/types.d.ts +71 -0
- package/dist/features/grid/types.d.ts.map +1 -0
- package/dist/features/page/index.d.ts +8 -0
- package/dist/features/page/index.d.ts.map +1 -0
- package/dist/features/page/plugin.d.ts +53 -0
- package/dist/features/page/plugin.d.ts.map +1 -0
- package/dist/features/scale/index.d.ts +10 -0
- package/dist/features/scale/index.d.ts.map +1 -0
- package/dist/features/scale/plugin.d.ts +42 -0
- package/dist/features/scale/plugin.d.ts.map +1 -0
- package/dist/features/scrollbar/controller.d.ts +121 -0
- package/dist/features/scrollbar/controller.d.ts.map +1 -0
- package/dist/features/scrollbar/index.d.ts +8 -0
- package/dist/features/scrollbar/index.d.ts.map +1 -0
- package/dist/features/scrollbar/plugin.d.ts +60 -0
- package/dist/features/scrollbar/plugin.d.ts.map +1 -0
- package/dist/features/scrollbar/scrollbar.d.ts +73 -0
- package/dist/features/scrollbar/scrollbar.d.ts.map +1 -0
- package/dist/features/sections/index.d.ts +10 -0
- package/dist/features/sections/index.d.ts.map +1 -0
- package/dist/features/sections/layout.d.ts +46 -0
- package/dist/features/sections/layout.d.ts.map +1 -0
- package/dist/features/sections/plugin.d.ts +64 -0
- package/dist/features/sections/plugin.d.ts.map +1 -0
- package/dist/features/sections/sticky.d.ts +33 -0
- package/dist/features/sections/sticky.d.ts.map +1 -0
- package/dist/features/sections/types.d.ts +86 -0
- package/dist/features/sections/types.d.ts.map +1 -0
- package/dist/features/selection/index.d.ts +7 -0
- package/dist/features/selection/index.d.ts.map +1 -0
- package/dist/features/selection/plugin.d.ts +44 -0
- package/dist/features/selection/plugin.d.ts.map +1 -0
- package/dist/features/selection/state.d.ts +102 -0
- package/dist/features/selection/state.d.ts.map +1 -0
- package/dist/features/snapshots/index.d.ts +8 -0
- package/dist/features/snapshots/index.d.ts.map +1 -0
- package/dist/features/snapshots/plugin.d.ts +44 -0
- package/dist/features/snapshots/plugin.d.ts.map +1 -0
- package/dist/grid/index.js +1 -198
- package/dist/groups/index.js +1 -204
- package/dist/index.d.ts +17 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1129
- package/dist/page/index.js +1 -0
- package/dist/plugins/groups/plugin.d.ts +3 -2
- package/dist/plugins/groups/plugin.d.ts.map +1 -1
- package/dist/react/index.js +1 -1024
- package/dist/react/react.js +1 -0
- package/dist/rendering/heights.d.ts +63 -0
- package/dist/rendering/heights.d.ts.map +1 -0
- package/dist/rendering/index.d.ts +9 -0
- package/dist/rendering/index.d.ts.map +1 -0
- package/dist/rendering/renderer.d.ts +103 -0
- package/dist/rendering/renderer.d.ts.map +1 -0
- package/dist/rendering/scale.d.ts +116 -0
- package/dist/rendering/scale.d.ts.map +1 -0
- package/dist/rendering/viewport.d.ts +139 -0
- package/dist/rendering/viewport.d.ts.map +1 -0
- package/dist/scale/index.js +1 -0
- package/dist/scroll/index.js +1 -116
- package/dist/scrollbar/index.js +1 -0
- package/dist/sections/index.js +1 -0
- package/dist/selection/index.js +1 -96
- package/dist/snapshots/index.js +1 -21
- package/dist/svelte/index.js +1 -1012
- package/dist/svelte/svelte.js +1 -0
- package/dist/vue/index.js +1 -1018
- package/dist/vue/vue.js +1 -0
- package/dist/window/index.js +1 -18
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var Ke=Object.defineProperty;var bn=Object.getOwnPropertyDescriptor;var vn=Object.getOwnPropertyNames;var yn=Object.prototype.hasOwnProperty;var Fe=(t,o)=>()=>(t&&(o=t(t=0)),o);var Tn=(t,o)=>{for(var r in o)Ke(t,r,{get:o[r],enumerable:!0})},Sn=(t,o,r,e)=>{if(o&&typeof o=="object"||typeof o=="function")for(let a of vn(o))!yn.call(t,a)&&a!==r&&Ke(t,a,{get:()=>o[a],enumerable:!(e=bn(o,a))||e.enumerable});return t};var In=t=>Sn(Ke({},"__esModule",{value:!0}),t);var yt,Xe,je,Tt=Fe(()=>{"use strict";yt=(t,o,r,e)=>{if(e===0)return 0;if(!t.isVariable())return Math.ceil(r/t.getHeight(0));let a=0,n=0,s=o;for(;s<e&&n<r;)n+=t.getHeight(s),a++,s++;return Math.max(1,a)},Xe=(t,o,r)=>{if(r===0)return 0;if(!t.isVariable())return Math.floor(o/t.getHeight(0));let e=0,a=0;for(let n=r-1;n>=0;n--){let s=t.getHeight(n);if(a+s>o)break;a+=s,e++}return Math.max(e,1)},je=(t,o,r)=>{if(r===0)return 0;let e=Math.floor(o),a=o-e,n=Math.max(0,Math.min(e,r-1));return t.getOffset(n)+a*t.getHeight(n)}});var Te,St,Ge,It,Ze=Fe(()=>{"use strict";Tt();Te=(t,o)=>{let r=o.getTotalHeight(),e=r>16e6,a=e?16e6:r,n=r>0?a/r:1;return{isCompressed:e,actualHeight:r,virtualHeight:a,ratio:n}},St=(t,o,r,e,a,n)=>{if(e===0||o===0)return n.start=0,n.end=-1,n;if(!a.isCompressed){let c=r.indexAtOffset(t),m=r.indexAtOffset(t+o);return m<e-1&&m++,n.start=Math.max(0,c),n.end=Math.min(e-1,Math.max(0,m)),n}let{virtualHeight:s}=a,y=t/s*e,f=Math.floor(y),u=yt(r,Math.max(0,f),o,e),T=Math.ceil(y)+u,L=s-o-t;if(L<=o&&L>=-1){let c=Xe(r,o,e),m=Math.max(0,e-c),b=Math.max(0,Math.min(1,1-L/o));f=Math.floor(f+(m-f)*b),T=L<=1?e-1:Math.min(e-1,f+u)}return n.start=Math.max(0,f),n.end=Math.min(e-1,Math.max(0,T)),n},Ge=(t,o,r,e,a,n,s)=>{if(!n.isCompressed||e===0)return r.getOffset(t);let{virtualHeight:l}=n,y=l-a,f=y-o;if(f<=a&&f>=-1){if(o>=y-1){let H=r.getTotalHeight()-r.getOffset(t);return a-H}let I=Xe(r,a,e),L=Math.max(0,e-I),m=o/l*e,b=Math.max(0,Math.min(1,1-f/a)),v=r.getOffset(t)-r.getOffset(L),S=r.getOffset(t)-je(r,m,e);return S+(v-S)*b}let T=o/l*e;return r.getOffset(t)-je(r,T,e)},It=(t,o,r,e,a,n="start")=>{if(e===0)return 0;let s;if(a.isCompressed){if(n==="end"&&t===e-1)return Math.max(0,a.virtualHeight-r);s=t/e*a.virtualHeight}else s=o.getOffset(t);let l=o.getHeight(t);switch(n){case"center":s-=(r-l)/2;break;case"end":s-=r-l;break}let y=a.virtualHeight-r;return Math.max(0,Math.min(s,y))}});var Me,Qe=Fe(()=>{"use strict";Me=t=>t!==null&&typeof t=="object"&&t.__groupHeader===!0});var Ct={};Tn(Ct,{createGridRenderer:()=>Je});var On,Je,et=Fe(()=>{"use strict";Ze();Qe();On=(t=200)=>{let o=[];return{acquire:()=>{let n=o.pop();if(n)return n;let s=document.createElement("div");return s.setAttribute("role","option"),s},release:n=>{o.length<t&&(n.className="",n.textContent="",n.removeAttribute("style"),n.removeAttribute("data-index"),n.removeAttribute("data-id"),n.removeAttribute("data-row"),n.removeAttribute("data-col"),o.push(n))},clear:()=>{o.length=0}}},Je=(t,o,r,e,a,n,s,l)=>{let y=On(),f=new Map,u=n,T=!1,I=null,L=0,c="",m=C=>(I&&L===C||(I=Te(C,r),L=C),I),b={selected:!1,focused:!1},v=(C,x)=>(b.selected=C,b.focused=x,b),S=`${a}-item ${a}-grid-item`,H=`${a}-item--selected`,h=`${a}-item--focused`,M=(C,x)=>{typeof x=="string"?C.innerHTML=x:C.replaceChildren(x)},d=(C,x,D)=>{C.classList.toggle(H,x),C.classList.toggle(h,D)},E=(C,x)=>{let D=e.getRow(C);if(x){let O=x.totalItems,N=m(O);if(N.isCompressed)return Ge(D,x.scrollTop,r,O,x.containerHeight,N,x.rangeStart)}return r.getOffset(D)},p=(C,x,D)=>{let O=C.dataset.id?.startsWith("__group_header"),N=O?0:e.getCol(x),Y=O?0:e.getColumnOffset(N,u),oe;if(T){let de=e.getRow(x),$=0,ae=new Set;for(let j=0;j<x;j++){let re=e.getRow(j);if(re<de&&!ae.has(re)){let Q=r.getHeight(j);$+=Q,ae.add(re)}}oe=$}else oe=E(x,D);C.style.transform=`translate(${Math.round(Y)}px, ${Math.round(oe)}px)`},V=(C,x)=>{let D=C.dataset.id?.startsWith("__group_header"),O=D?u:e.getColumnWidth(u),N;if(T||D)N=r.getHeight(x)-e.gap;else{let Y=e.getRow(x);N=r.getHeight(Y)-e.gap}C.style.width=`${O}px`,C.style.height=`${N}px`},z=(C,x,D,O,N)=>{let Y=y.acquire(),oe=v(D,O);Y.className=S,Y.dataset.index=String(C),Y.dataset.id=String(x.id),Y.dataset.row=String(e.getRow(C)),Y.dataset.col=String(e.getCol(C)),Y.ariaSelected=String(D),l&&(Y.id=`${l}-item-${C}`),s&&(c=String(s()),Y.setAttribute("aria-setsize",c),Y.setAttribute("aria-posinset",String(C+1))),V(Y,C);let de=o(x,C,oe);return M(Y,de),d(Y,D,O),p(Y,C,N),Y},X=(C,x,D,O,N)=>{x.start===0&&C.length>0&&(T=Me(C[0]));for(let[$,ae]of f)($<x.start||$>x.end)&&(ae.element.remove(),y.release(ae.element),f.delete($));let Y=!1;if(s){let $=String(s());Y=$!==c,c=$}let oe=document.createDocumentFragment(),de=[];for(let $=x.start;$<=x.end;$++){let ae=$-x.start,j=C[ae];if(!j){console.warn(`\u26A0\uFE0F RENDER: Missing item at index ${$} (range: ${x.start}-${x.end}, items.length: ${C.length})`);continue}let re=D.has(j.id),Q=$===O,te=f.get($);if(te){let _=te.element.dataset.id,P=String(j.id);if(_!==P){let J=v(re,Q),B=o(j,$,J);M(te.element,B),te.element.dataset.id=P,te.element.dataset.row=String(e.getRow($)),te.element.dataset.col=String(e.getCol($)),V(te.element,$)}d(te.element,re,Q),te.element.ariaSelected=String(re),p(te.element,$,N),Y&&te.element.setAttribute("aria-setsize",c)}else{let _=z($,j,re,Q,N);oe.appendChild(_),de.push({index:$,element:_})}}if(de.length>0){t.appendChild(oe);for(let{index:$,element:ae}of de)f.set($,{index:$,element:ae})}},U=C=>{for(let[x,D]of f)p(D.element,x,C)},ee=(C,x,D,O)=>{let N=f.get(C);if(N){let Y=v(D,O),oe=o(x,C,Y);M(N.element,oe),d(N.element,D,O),N.element.dataset.id=String(x.id),N.element.ariaSelected=String(D),V(N.element,C)}},Z=(C,x,D)=>{let O=f.get(C);O&&d(O.element,x,D)},R=C=>f.get(C)?.element,A=C=>{if(!(Math.abs(C-u)<1)){u=C;for(let[x,D]of f)V(D.element,x),p(D.element,x)}},G=()=>{for(let[,C]of f)C.element.remove(),y.release(C.element);f.clear()};return{render:X,updatePositions:U,updateItem:ee,updateItemClasses:Z,getElement:R,updateContainerWidth:A,clear:G,destroy:()=>{G(),y.clear()}}}});import{useRef as xe,useEffect as ct,useCallback as Kn}from"react";var Cn="vlist";var wn=0,Ce=5,Ln=100,qe=2,Hn=(t=0)=>{let o=new Array(Ce);for(let r=0;r<Ce;r++)o[r]={position:0,time:0};return{velocity:0,lastPosition:t,lastTime:performance.now(),samples:o,sampleIndex:0,sampleCount:0}},Mn=(t,o)=>{let r=performance.now(),e=r-t.lastTime;if(e===0)return t;if(e>Ln){t.sampleCount=0,t.sampleIndex=0,t.velocity=0;let n=t.samples[0];return n.position=o,n.time=r,t.sampleIndex=1,t.sampleCount=1,t.lastPosition=o,t.lastTime=r,t}let a=t.samples[t.sampleIndex];if(a.position=o,a.time=r,t.sampleIndex=(t.sampleIndex+1)%Ce,t.sampleCount=Math.min(t.sampleCount+1,Ce),t.sampleCount>=qe){let n=(t.sampleIndex-t.sampleCount+Ce)%Ce,s=t.samples[n],l=o-s.position,y=r-s.time;t.velocity=y>0?Math.abs(l)/y:0}return t.lastPosition=o,t.lastTime=r,t},bt=(t,o)=>{if(typeof t=="number"){let n=o;return{getOffset:s=>s*t,getHeight:()=>t,indexAtOffset:s=>n===0||t===0?0:Math.max(0,Math.min(Math.floor(s/t),n-1)),getTotalHeight:()=>n*t,getTotal:()=>n,rebuild:s=>{n=s},isVariable:()=>!1}}let r=o,e=new Float64Array(0),a=n=>{r=n,e=new Float64Array(n+1),e[0]=0;for(let s=0;s<n;s++)e[s+1]=e[s]+t(s)};return a(o),{getOffset:n=>n<=0?0:n>=r?e[r]:e[n],getHeight:n=>t(n),indexAtOffset:n=>{if(r===0||n<=0)return 0;if(n>=e[r])return r-1;let s=0,l=r-1;for(;s<l;){let y=s+l+1>>>1;e[y]<=n?s=y:l=y-1}return s},getTotalHeight:()=>e[r]??0,getTotal:()=>r,rebuild:n=>a(n),isVariable:()=>!0}},Rn=()=>{let t={},o=(n,s)=>(t[n]||(t[n]=new Set),t[n].add(s),()=>r(n,s)),r=(n,s)=>{t[n]?.delete(s)};return{on:o,off:r,emit:(n,s)=>{t[n]?.forEach(l=>{try{l(s)}catch(y){console.error(`[vlist] Error in "${n}" handler:`,y)}})},clear:()=>{for(let n in t)delete t[n]}}},En=t=>{if(typeof t=="string"){let o=document.querySelector(t);if(!o)throw new Error(`[vlist/builder] Container not found: ${t}`);return o}return t},xn=(t,o,r,e)=>{let a=document.createElement("div");a.className=o,e&&a.classList.add(`${o}--horizontal`),a.setAttribute("role","listbox"),a.setAttribute("tabindex","0"),r&&a.setAttribute("aria-label",r),e&&a.setAttribute("aria-orientation","horizontal");let n=document.createElement("div");n.className=`${o}-viewport`,e?(n.style.overflowX="auto",n.style.overflowY="hidden"):n.style.overflow="auto",n.style.height="100%",n.style.width="100%";let s=document.createElement("div");s.className=`${o}-content`,s.style.position="relative",e?s.style.height="100%":s.style.width="100%";let l=document.createElement("div");return l.className=`${o}-items`,l.style.position="relative",e?l.style.height="100%":l.style.width="100%",s.appendChild(l),n.appendChild(s),a.appendChild(n),t.appendChild(a),{root:a,viewport:n,content:s,items:l}},Vn=(t=100)=>{let o=[];return{acquire:()=>{let r=o.pop();if(r)return r;let e=document.createElement("div");return e.setAttribute("role","option"),e},release:r=>{o.length<t&&(r.className="",r.textContent="",r.removeAttribute("style"),r.removeAttribute("data-index"),r.removeAttribute("data-id"),o.push(r))},clear:()=>{o.length=0}}},An=(t,o,r,e,a)=>{if(e===0||o===0){a.start=0,a.end=0;return}let n=r.indexAtOffset(t),s=r.indexAtOffset(t+o);s<e-1&&s++,a.start=Math.max(0,n),a.end=Math.min(e-1,Math.max(0,s))},_n=(t,o,r,e)=>{if(r===0){e.start=0,e.end=0;return}e.start=Math.max(0,t.start-o),e.end=Math.min(r-1,t.end+o)},Pn=(t,o,r,e,a)=>{if(e===0)return 0;let n=Math.max(0,Math.min(t,e-1)),s=o.getOffset(n),l=o.getHeight(n),y=Math.max(0,o.getTotalHeight()-r),f;switch(a){case"center":f=s-(r-l)/2;break;case"end":f=s-r+l;break;default:f=s}return Math.max(0,Math.min(f,y))},Fn=t=>t<.5?2*t*t:-1+(4-2*t)*t,Gn=t=>typeof t=="string"?{align:t,behavior:"auto",duration:300}:t&&typeof t=="object"?{align:t.align??"start",behavior:t.behavior??"auto",duration:t.duration??300}:{align:"start",behavior:"auto",duration:300},Ye=t=>{if(!t.container)throw new Error("[vlist/builder] Container is required");if(!t.item)throw new Error("[vlist/builder] item configuration is required");let o=t.direction==="horizontal",r=o?"width":"height",e=o?t.item.width:t.item.height;if(e==null)throw new Error(`[vlist/builder] item.${r} is required${o?" when direction is 'horizontal'":""}`);if(typeof e=="number"&&e<=0)throw new Error(`[vlist/builder] item.${r} must be a positive number`);if(typeof e!="number"&&typeof e!="function")throw new Error(`[vlist/builder] item.${r} must be a number or a function (index) => number`);if(!t.item.template)throw new Error("[vlist/builder] item.template is required");if(o&&t.reverse)throw new Error("[vlist/builder] horizontal direction cannot be combined with reverse mode");let a=new Map,n=!1,s={use(l){if(n)throw new Error("[vlist/builder] Cannot call .use() after .build()");return a.set(l.name,l),s},build(){if(n)throw new Error("[vlist/builder] .build() can only be called once");return n=!0,kn(t,a,o,e)}};return s};function kn(t,o,r,e){let{item:a,items:n,overscan:s=3,classPrefix:l=Cn,ariaLabel:y,reverse:f=!1,scroll:u}=t,T=u?.wheel??!0,I=u?.wrap??!1,L=f,c=`${l}-${wn++}`,m=e,b=r?typeof a.height=="number"?a.height:void 0:typeof a.width=="number"?a.width:void 0,v=a.template,S={overscan:s,classPrefix:l,reverse:L,wrap:I,horizontal:r,ariaIdPrefix:c},H=Array.from(o.values()).sort((i,g)=>(i.priority??50)-(g.priority??50)),h=new Set(H.map(i=>i.name));for(let i of H)if(i.conflicts){for(let g of i.conflicts)if(h.has(g))throw new Error(`[vlist/builder] ${i.name} and ${g} cannot be combined`)}if(r){if(h.has("withGrid"))throw new Error("[vlist/builder] withGrid cannot be used with direction: 'horizontal'");if(h.has("withGroups"))throw new Error("[vlist/builder] withGroups cannot be used with direction: 'horizontal'")}if(L){if(h.has("withGrid"))throw new Error("[vlist/builder] withGrid cannot be used with reverse: true");if(h.has("withGroups"))throw new Error("[vlist/builder] withGroups cannot be used with reverse: true")}let M=En(t.container),d=xn(M,l,y,r),E=Rn(),p=n?[...n]:[],V=bt(m,p.length),z=Vn(),X=d.viewport.clientHeight,U=d.viewport.clientWidth,ee=!1,Z=!1,R=0,A=null,G=null,k=Hn(0),C={start:0,end:0},x={start:0,end:0},D={start:-1,end:-1},O={viewportState:{scrollTop:0,containerHeight:X,totalHeight:V.getTotalHeight(),actualHeight:V.getTotalHeight(),isCompressed:!1,compressionRatio:1,visibleRange:{start:0,end:0},renderRange:{start:0,end:0}},lastRenderRange:{start:-1,end:-1},isInitialized:!1,isDestroyed:!1,cachedCompression:null},N=new Map,Y={selected:!1,focused:!1},oe=`${l}-item`,de="",$=new Map,ae=()=>{$.clear();for(let i=0;i<p.length;i++){let g=p[i];g&&$.set(g.id,i)}};ae();let j=null,re=()=>j?j.getTotal():p.length,Q=[],te=[],_=[],P=[],K=[],J=[],B=new Map,ne=()=>r?d.viewport.scrollLeft:d.viewport.scrollTop,se=i=>{r?d.viewport.scrollLeft=i:d.viewport.scrollTop=i},be=(i=2)=>{let g=V.getTotalHeight();return R+X>=g-i},ue=!1,ie,fe,le=(i,g,w,F,q)=>{An(i,g,w,F,q)},he=(i,g,w,F,q)=>Pn(i,g,w,F,q),ce=(i,g)=>{typeof g=="string"?i.innerHTML=g:i.replaceChildren(g)},ye=(i,g)=>{let w=Math.round(V.getOffset(g));r?i.style.transform=`translateX(${w}px)`:i.style.transform=`translateY(${w}px)`},Zt=(i,g)=>{let w=z.acquire();return w.className=oe,r?(w.style.width=`${V.getHeight(i)}px`,b!=null&&(w.style.height=`${b}px`)):w.style.height=`${V.getHeight(i)}px`,w.dataset.index=String(i),w.dataset.id=String(g.id),w.ariaSelected="false",w.id=`${c}-item-${i}`,de=String(re()),w.setAttribute("aria-setsize",de),w.setAttribute("aria-posinset",String(i+1)),ce(w,v(g,i,Y)),ye(w,i),w},Le=()=>{let i=`${V.getTotalHeight()}px`;r?d.content.style.width=i:d.content.style.height=i},Be=new Set,ze=-1,Qt=()=>{if(ee)return;let i=re();if(le(R,X,V,i,C),_n(C,s,i,x),x.start===D.start&&x.end===D.end)return;let g=String(i),w=g!==de;de=g;for(let[W,ge]of N)(W<x.start||W>x.end)&&(ge.remove(),z.release(ge),N.delete(W));let F=document.createDocumentFragment(),q=[];for(let W=x.start;W<=x.end;W++){let ge=j?j.getItem(W):p[W];if(!ge)continue;let pe=N.get(W);if(pe){let ve=pe.dataset.id,_e=String(ge.id);ve!==_e&&(ce(pe,v(ge,W,Y)),pe.dataset.id=_e,r?pe.style.width=`${V.getHeight(W)}px`:pe.style.height=`${V.getHeight(W)}px`),ye(pe,W);let Pe=Be.has(ge.id),hn=W===ze;pe.classList.toggle(`${l}-item--selected`,Pe),pe.classList.toggle(`${l}-item--focused`,hn),pe.ariaSelected=Pe?"true":"false",w&&pe.setAttribute("aria-setsize",de)}else{let ve=Zt(W,ge),_e=Be.has(ge.id),Pe=W===ze;_e&&(ve.classList.add(`${l}-item--selected`),ve.ariaSelected="true"),Pe&&ve.classList.add(`${l}-item--focused`),F.appendChild(ve),q.push({index:W,element:ve})}}if(q.length>0){d.items.appendChild(F);for(let{index:W,element:ge}of q)N.set(W,ge)}D.start=x.start,D.end=x.end,O.lastRenderRange.start=x.start,O.lastRenderRange.end=x.end,O.viewportState.scrollTop=R,O.viewportState.visibleRange.start=C.start,O.viewportState.visibleRange.end=C.end,O.viewportState.renderRange.start=x.start,O.viewportState.renderRange.end=x.end,E.emit("range:change",{range:{start:x.start,end:x.end}})},Jt=()=>{D.start=-1,D.end=-1,ie()};ie=Qt,fe=Jt;let He=()=>{if(ee)return;let i=ne(),g=i>=R?"down":"up";k=Mn(k,i),d.root.classList.contains(`${l}--scrolling`)||d.root.classList.add(`${l}--scrolling`),R=i,ie(),E.emit("scroll",{scrollTop:i,direction:g}),E.emit("velocity:change",{velocity:k.velocity,reliable:k.sampleCount>=qe});for(let w=0;w<Q.length;w++)Q[w](i,g);G&&clearTimeout(G),G=setTimeout(()=>{d.root.classList.remove(`${l}--scrolling`),k.velocity=0,k.sampleCount=0,E.emit("velocity:change",{velocity:0,reliable:!1})},u?.idleTimeout??150)},Ve=null,Ie=d.viewport;Ie.addEventListener("scroll",He,{passive:!0}),r&&T&&(Ve=i=>{i.deltaX||(i.preventDefault(),d.viewport.scrollLeft+=i.deltaY)},d.viewport.addEventListener("wheel",Ve)),d.viewport.classList.add(`${l}-viewport--custom-scrollbar`);let mt=i=>{let w=i.target.closest("[data-index]");if(w){let F=parseInt(w.dataset.index??"-1",10);if(F>=0){let q=j?.getItem(F)??p[F];if(q){if(q.__groupHeader)return;E.emit("item:click",{item:q,index:F,event:i})}}}for(let F=0;F<te.length;F++)te[F](i)},en=i=>{let w=i.target.closest("[data-index]");if(w){let F=parseInt(w.dataset.index??"-1",10);if(F>=0){let q=j?.getItem(F)??p[F];if(q){if(q.__groupHeader)return;E.emit("item:dblclick",{item:q,index:F,event:i})}}}},gt=i=>{for(let g=0;g<_.length;g++)_[g](i)};d.items.addEventListener("click",mt),d.items.addEventListener("dblclick",en),d.root.addEventListener("keydown",gt);let Ue=!0,tn=()=>U,nn=()=>X,Ne=new ResizeObserver(i=>{if(!ee)for(let g of i){let w=g.contentRect.height,F=g.contentRect.width,q=r?F:w;if(U=F,Math.abs(q-X)>1&&(X=q,O.viewportState.containerHeight=q,Z&&(Le(),ie(),E.emit("resize",{height:w,width:F}))),Z)for(let W=0;W<P.length;W++)P[W](F,w)}});Ue&&Ne.observe(d.viewport);let me={get dom(){return d},get heightCache(){return V},get emitter(){return E},get config(){return S},get rawConfig(){return t},get renderer(){return{render:(i,g,w,F,q)=>{Be=w,ze=F,fe()},updateItemClasses:(i,g,w)=>{let F=N.get(i);F&&(F.classList.toggle(`${l}-item--selected`,g),F.classList.toggle(`${l}-item--focused`,w),F.ariaSelected=g?"true":"false")},updatePositions:()=>{},updateItem:()=>{},getElement:i=>N.get(i)??null,clear:()=>{},destroy:()=>{}}},set renderer(i){},get dataManager(){return j},set dataManager(i){j=i},get scrollController(){return We},set scrollController(i){We=i},state:O,getContainerWidth(){return U},afterScroll:Q,clickHandlers:te,keydownHandlers:_,resizeHandlers:P,contentSizeHandlers:K,destroyHandlers:J,methods:B,replaceTemplate(i){v=i},replaceRenderer(i){},replaceDataManager(i){j=i},replaceScrollController(i){We=i},getItemsForRange(i){let g=[];for(let w=i.start;w<=i.end;w++){let F=j?j.getItem(w):p[w];F&&g.push(F)}return g},getAllLoadedItems(){if(j){let i=j.getTotal(),g=[];for(let w=0;w<i;w++){let F=j.getItem(w);F&&g.push(F)}return g}return[...p]},getVirtualTotal(){return re()},getCachedCompression(){return{isCompressed:!1,actualHeight:V.getTotalHeight(),virtualHeight:V.getTotalHeight(),ratio:1}},getCompressionContext(){return{scrollTop:R,totalItems:re(),containerHeight:X,rangeStart:x.start}},renderIfNeeded(){ie()},forceRender(){fe()},getRenderFns(){return{renderIfNeeded:ie,forceRender:fe}},setRenderFns(i,g){ie=i,fe=g},setVirtualTotalFn(i){re=i},rebuildHeightCache(i){V.rebuild(i??re())},setHeightConfig(i){V=bt(i,re())},updateContentSize(i){let g=`${i}px`;r?d.content.style.width=g:d.content.style.height=g},updateCompressionMode(){},setVisibleRangeFn(i){le=i},setScrollToPosFn(i){he=i},setPositionElementFn(i){ye=i},setScrollFns(i,g){ne=i,se=w=>{g(w),He()}},setScrollTarget(i){Ie.removeEventListener("scroll",He),Ie=i,Ie.addEventListener("scroll",He,{passive:!0})},getScrollTarget(){return Ie},setContainerDimensions(i){tn=i.width,nn=i.height,U=i.width(),X=i.height(),O.viewportState.containerHeight=X},disableViewportResize(){Ue&&(Ue=!1,Ne.unobserve(d.viewport))}};j={getState:()=>({total:p.length,cached:p.length,isLoading:!1,pendingRanges:[],error:void 0,hasMore:!1,cursor:void 0}),getTotal:()=>p.length,getCached:()=>p.length,getIsLoading:()=>!1,getHasMore:()=>!1,getStorage:()=>null,getPlaceholders:()=>null,getItem:i=>p[i],getItemById:i=>{let g=$.get(i);return g!==void 0?p[g]:void 0},getIndexById:i=>$.get(i)??-1,isItemLoaded:i=>i>=0&&i<p.length&&p[i]!==void 0,getItemsInRange:(i,g)=>{let w=[],F=Math.max(0,i),q=Math.min(g,p.length-1);for(let W=F;W<=q;W++)w.push(p[W]);return w},setTotal:i=>{},setItems:(i,g=0,w)=>{if(g===0&&(w!==void 0||p.length===0))p=[...i];else{let F=g+i.length;p.length<F&&(p.length=F);for(let q=0;q<i.length;q++)p[g+q]=i[q]}if(ae(),Z){V.rebuild(re()),Le(),me.updateCompressionMode();for(let F=0;F<K.length;F++)K[F]();fe()}},updateItem:(i,g)=>{let w=$.get(i);if(w===void 0)return!1;let F=p[w];if(!F)return!1;p[w]={...F,...g},g.id!==void 0&&g.id!==i&&($.delete(i),$.set(g.id,w));let q=N.get(w);return q&&(ce(q,v(p[w],w,Y)),q.dataset.id=String(p[w].id)),!0},removeItem:i=>{let g=$.get(i);if(g===void 0)return!1;if(p.splice(g,1),ae(),Z){V.rebuild(re()),Le(),me.updateCompressionMode();for(let w=0;w<K.length;w++)K[w]();fe()}return!0},loadRange:async()=>{},ensureRange:async()=>{},loadInitial:async()=>{},loadMore:async()=>!1,reload:async()=>{},evictDistant:()=>{},clear:()=>{p=[],$.clear()},reset:()=>{p=[],$.clear(),Z&&(V.rebuild(0),Le(),fe())}};let We={getScrollTop:()=>ne(),scrollTo:i=>{se(i),R=i,ie()},scrollBy:i=>{let g=ne()+i;se(g),R=g,ie()},isAtTop:()=>R<=2,isAtBottom:(i=2)=>be(i),getScrollPercentage:()=>{let i=V.getTotalHeight(),g=Math.max(0,i-X);return g>0?R/g:0},getVelocity:()=>k.velocity,isTracking:()=>k.sampleCount>=qe,isScrolling:()=>d.root.classList.contains(`${l}--scrolling`),updateConfig:()=>{},enableCompression:()=>{},disableCompression:()=>{},isCompressed:()=>ue,isWindowMode:()=>!1,updateContainerHeight:i=>{X=i},destroy:()=>{}},pt=new Map;for(let i of H)if(i.methods)for(let g of i.methods){let w=pt.get(g);if(w)throw new Error(`[vlist/builder] Method "${g}" is registered by both "${w}" and "${i.name}"`);pt.set(g,i.name)}for(let i of H)i.setup(me);if(Z=!0,me.state.isInitialized=!0,Le(),ie(),L&&p.length>0){let i=he(p.length-1,V,X,p.length,"end");se(i),R=i,ie()}let rn=i=>{me.dataManager.setItems(i,0,i.length)},on=L?i=>{let g=be(2),w=p.length;if(me.dataManager.setItems(i,w),g&&p.length>0){let F=he(p.length-1,V,X,p.length,"end");se(F),R=F,ie()}}:i=>{let g=p.length;me.dataManager.setItems(i,g)},sn=L?i=>{let g=ne(),w=V.getTotalHeight(),F=[...p];me.dataManager.clear(),me.dataManager.setItems([...i,...F],0);let W=V.getTotalHeight()-w;W>0&&(se(g+W),R=g+W)}:i=>{let g=[...p];me.dataManager.clear(),me.dataManager.setItems([...i,...g],0)},an=(i,g)=>{me.dataManager.updateItem(i,g)},ln=i=>{me.dataManager.removeItem(i)},dn=async()=>{me.dataManager.reload&&await me.dataManager.reload()},Ae=()=>{A!==null&&(cancelAnimationFrame(A),A=null)},un=(i,g,w)=>{if(Ae(),Math.abs(g-i)<1){se(g),R=g,ie();return}let F=performance.now(),q=W=>{let ge=W-F,pe=Math.min(ge/w,1),ve=i+(g-i)*Fn(pe);se(ve),R=ve,ie(),pe<1?A=requestAnimationFrame(q):A=null};A=requestAnimationFrame(q)},ft=(i,g)=>{let{align:w,behavior:F,duration:q}=Gn(g),W=re(),ge=i;I&&W>0&&(ge=(ge%W+W)%W);let pe=he(ge,V,X,W,w);F==="smooth"?un(ne(),pe,q):(Ae(),se(pe))},cn=(i,g)=>{let w=$.get(i)??me.dataManager.getIndexById(i);w>=0&&ft(w,g)},mn=()=>ne(),gn=(i,g)=>E.on(i,g),pn=(i,g)=>{E.off(i,g)},fn=()=>{if(!ee){ee=!0,me.state.isDestroyed=!0,d.items.removeEventListener("click",mt),d.root.removeEventListener("keydown",gt),Ie.removeEventListener("scroll",He),Ne.disconnect(),Ve&&d.viewport.removeEventListener("wheel",Ve),G&&clearTimeout(G);for(let i=0;i<J.length;i++)J[i]();for(let i of H)i.destroy&&i.destroy();Ae();for(let[,i]of N)i.remove(),z.release(i);N.clear(),z.clear(),E.clear(),d.root.remove()}},ht={get element(){return d.root},get items(){return B.has("_getItems")?B.get("_getItems")():p},get total(){return B.has("_getTotal")?B.get("_getTotal")():re()},setItems:B.has("setItems")?B.get("setItems"):rn,appendItems:B.has("appendItems")?B.get("appendItems"):on,prependItems:B.has("prependItems")?B.get("prependItems"):sn,updateItem:B.has("updateItem")?B.get("updateItem"):an,removeItem:B.has("removeItem")?B.get("removeItem"):ln,reload:B.has("reload")?B.get("reload"):dn,scrollToIndex:B.has("scrollToIndex")?B.get("scrollToIndex"):ft,scrollToItem:B.has("scrollToItem")?B.get("scrollToItem"):cn,cancelScroll:B.has("cancelScroll")?B.get("cancelScroll"):Ae,getScrollPosition:B.has("getScrollPosition")?B.get("getScrollPosition"):mn,on:gn,off:pn,destroy:fn};for(let[i,g]of B)i==="setItems"||i==="appendItems"||i==="prependItems"||i==="updateItem"||i==="removeItem"||i==="reload"||i==="scrollToIndex"||i==="scrollToItem"||i==="cancelScroll"||i==="getScrollPosition"||(ht[i]=g);return ht}var vt=t=>{let o=Math.max(1,Math.floor(t.columns)),r=t.gap??0,e=t.isHeaderFn,a={row:0,col:0},n=c=>{if(c<=0)return 0;if(!e)return Math.ceil(c/o);let m=0,b=0,v=0;for(let S=0;S<c;S++)e(S)?(v++,b>0&&(m++,b=0),m++,b=0):(b++,b>=o&&(m++,b=0));return b>0&&m++,m},s=c=>(a.row=l(c),a.col=y(c),a),l=c=>{if(!e)return Math.floor(c/o);let m=0,b=0;for(let v=0;v<=c;v++)if(e(v)){if(b>0&&(m++,b=0),v===c)return m;m++,b=0}else{if(v===c)return m;b++,b>=o&&(m++,b=0)}return console.warn(`\u26A0\uFE0F getRow(${c}) fell through - returning ${m}`),m},y=c=>{if(!e)return c%o;if(e(c))return 0;let m=0;for(let b=0;b<=c;b++)if(e(b))m=0;else{if(b===c)return m;m++,m>=o&&(m=0)}return m},f=(c,m,b)=>{if(b<=0)return{start:0,end:-1};if(!e){let M=Math.max(0,c*o),d=Math.min(b-1,(m+1)*o-1);return{start:M,end:d}}let v=-1,S=-1,H=0,h=0;for(let M=0;M<b&&(e(M)?(h>0&&(H++,h=0),H>=c&&H<=m&&(v===-1&&(v=M),S=M),H++,h=0):(H>=c&&H<=m&&(v===-1&&(v=M),S=M),h++,h>=o&&(H++,h=0)),!(H>m&&h===0));M++);return v===-1?{start:0,end:-1}:{start:v,end:S}},u=(c,m,b)=>{if(m<0||m>=o)return-1;let v=c*o+m;return v<0||v>=b?-1:v},T=c=>{let m=(o-1)*r;return Math.max(0,(c-m)/o)};return{get columns(){return o},get gap(){return r},update:c=>{c.columns!==void 0&&(o=Math.max(1,Math.floor(c.columns))),c.gap!==void 0&&(r=c.gap),c.isHeaderFn!==void 0&&(e=c.isHeaderFn)},getTotalRows:n,getPosition:s,getRow:l,getCol:y,getItemRange:f,getItemIndex:u,getColumnWidth:T,getColumnOffset:(c,m)=>{let b=T(m);return c*(b+r)}}};et();var wt=(t,o,r,e,a,n)=>{if(e===0||o===0)return n.start=0,n.end=-1,n;let s=r.indexAtOffset(t),l=r.indexAtOffset(t+o);return l<e-1&&l++,n.start=Math.max(0,s),n.end=Math.min(e-1,Math.max(0,l)),n},Lt=(t,o,r,e)=>r===0?(e.start=0,e.end=-1,e):(e.start=Math.max(0,t.start-o),e.end=Math.min(r-1,t.end+o),e),Ht=(t,o,r,e,a,n)=>{if(e===0)return 0;let s=Math.max(0,Math.min(t,e-1)),l=o.getOffset(s),y=o.getHeight(s),f=o.getTotalHeight(),u=Math.max(0,f-r),T;switch(n){case"center":T=l-r/2+y/2;break;case"end":T=l-r+y;break;default:T=l;break}return Math.max(0,Math.min(T,u))};var tt=(t,o,r,e,a,n=wt)=>(n(t.scrollTop,t.containerHeight,o,r,a,t.visibleRange),Lt(t.visibleRange,e,r,t.renderRange),t.totalHeight=a.virtualHeight,t.actualHeight=a.actualHeight,t.isCompressed=a.isCompressed,t.compressionRatio=a.ratio,t),Se=(t,o,r,e,a="start",n,s=Ht)=>s(t,o,r,e,n,a);var Mt=t=>{if(!t.columns||t.columns<1)throw new Error("[vlist/builder] withGrid: columns must be a positive integer >= 1");let o=null,r=null;return{name:"withGrid",priority:10,setup(e){let{dom:a,emitter:n,config:s,rawConfig:l}=e,{classPrefix:y}=s;if(s.horizontal)throw new Error("[vlist/builder] withGrid cannot be used with direction: 'horizontal'");if(s.reverse)throw new Error("[vlist/builder] withGrid cannot be used with reverse: true");let f=l.items?.some(h=>h.__groupHeader===!0),u={columns:t.columns,gap:t.gap??0};f&&(u.isHeaderFn=h=>{let M=e.dataManager.getItem(h);return!!(M&&M.__groupHeader===!0)}),o=vt(u);let T=o.gap;e.setVirtualTotalFn(()=>{let h=e.dataManager.getTotal();return o.getTotalRows(h)});let I=l.item,L=s.horizontal?I.width:I.height,c={containerWidth:e.getContainerWidth(),columns:o.columns,gap:o.gap};typeof L=="function"?e.setHeightConfig(h=>{let M=c.containerWidth-2,d=(c.columns-1)*c.gap,E=(M-d)/c.columns,p={containerWidth:c.containerWidth,columns:c.columns,gap:c.gap,columnWidth:E,row:o.getRow(h),column:o.getCol(h),totalRows:o.getTotalRows(e.dataManager.getTotal()),totalColumns:c.columns};return L(h,p)+c.gap}):T>0&&e.setHeightConfig(L+T),e.rebuildHeightCache(),a.root.classList.add(`${y}--grid`);let m=e.getContainerWidth(),b=l.item.template,v=()=>{r=Je(a.items,b,e.heightCache,o,y,m,()=>e.dataManager.getTotal(),s.ariaIdPrefix),e.replaceRenderer(r)};v(),e.methods.set("_getGridLayout",()=>o),e.methods.set("_getGridConfig",()=>u),e.methods.set("_replaceGridRenderer",h=>{r=h}),e.methods.set("_updateGridLayoutForGroups",h=>{o.update({isHeaderFn:h});let M=e.dataManager.getTotal(),d=0;for(let E=0;E<M;E++)if(o.getCol(E)===0){let p=e.heightCache.getHeight(E);d+=p}e.heightCache.getTotalHeight=()=>d,e.dom.content.style.height=`${d}px`,v()}),e.methods.set("updateGrid",h=>{if(h.columns!==void 0){if(!Number.isInteger(h.columns)||h.columns<1)throw new Error("[vlist/builder] updateGrid: columns must be a positive integer >= 1");u.columns=h.columns}if(h.gap!==void 0){if(h.gap<0)throw new Error("[vlist/builder] updateGrid: gap must be non-negative");u.gap=h.gap}o&&o.update(u);let M=e.getContainerWidth();c.containerWidth=M,c.columns=u.columns,c.gap=u.gap??0,r&&r.updateContainerWidth(M),e.rebuildHeightCache(),e.updateContentSize(e.heightCache.getTotalHeight()),e.updateCompressionMode();for(let d=0;d<e.contentSizeHandlers.length;d++)e.contentSizeHandlers[d]();r&&r.clear(),e.forceRender()});let S=()=>{if(e.state.isDestroyed)return;let h=e.scrollController.getScrollTop(),M=e.state.viewportState.containerHeight,d=e.getVirtualTotal(),E={start:0,end:0};if(d===0||M===0)E.start=0,E.end=0;else{E.start=Math.max(0,e.heightCache.indexAtOffset(h));let A=e.heightCache.indexAtOffset(h+M);A<d-1&&A++,E.end=Math.min(d-1,Math.max(0,A))}let p=s.overscan??3,V={start:Math.max(0,E.start-p),end:Math.min(d-1,E.end+p)};e.state.viewportState.scrollTop=h,e.state.viewportState.visibleRange=E,e.state.viewportState.renderRange=V;let z=e.state.lastRenderRange,X=e.state.viewportState.isCompressed;if(V.start===z.start&&V.end===z.end){X&&r.updatePositions(e.getCompressionContext());return}let U=e.dataManager.getTotal(),ee=o.getItemRange(V.start,V.end,U),Z=e.dataManager.getItemsInRange(ee.start,ee.end),R=X?e.getCompressionContext():void 0;r.render(Z,ee,new Set,-1,R),e.state.lastRenderRange={...V},n.emit("range:change",{range:V})},H=()=>{e.state.isDestroyed||(e.state.lastRenderRange={start:-1,end:-1},S())};e.setRenderFns(S,H),e.resizeHandlers.push((h,M)=>{r&&r.updateContainerWidth(h)}),e.methods.set("scrollToIndex",(h,M)=>{let d=Math.floor(h/t.columns),{align:E,behavior:p}=$n(M),V=e.dataManager.getState(),z=o.getTotalRows(V.total),X=Math.max(0,Math.min(d,z-1)),U=Se(X,e.heightCache,e.state.viewportState.containerHeight,z,E,e.getCachedCompression());e.scrollController.scrollTo(U)}),e.methods.has("_getTotal")||e.methods.set("_getTotal",()=>e.dataManager.getTotal()),e.destroyHandlers.push(()=>{r&&(r.destroy(),r=null),a.root.classList.remove(`${y}--grid`)})},destroy(){r&&(r.destroy(),r=null)}}},nt=300,$n=t=>typeof t=="string"?{align:t,behavior:"auto",duration:nt}:t&&typeof t=="object"?{align:t.align??"start",behavior:t.behavior??"auto",duration:t.duration??nt}:{align:"start",behavior:"auto",duration:nt};var rt=(t,o)=>{let r=0,e=t.length-1;for(;r<e;){let a=r+e+1>>>1;t[a].headerLayoutIndex<=o?r=a:e=a-1}return r},Rt=(t,o)=>{let r=0,e=t.length-1;for(;r<e;){let a=r+e+1>>>1;t[a].firstDataIndex<=o?r=a:e=a-1}return r},Et=(t,o)=>{if(t===0)return[];let r=[],e=o(0),a=0,n=0;for(let s=1;s<t;s++){let l=o(s);if(l!==e){let y=s-a;r.push({key:e,groupIndex:r.length,headerLayoutIndex:n,firstDataIndex:a,count:y}),n=n+1+y,e=l,a=s}}return r.push({key:e,groupIndex:r.length,headerLayoutIndex:n,firstDataIndex:a,count:t-a}),r},ot=(t,o)=>{if(t.length===0||o.length===0)return[];let r=t.length+o.length,e=new Array(r),a=0;for(let n of o){e[a]={id:`__group_header_${n.groupIndex}`,__groupHeader:!0,groupKey:n.key,groupIndex:n.groupIndex},a++;for(let s=0;s<n.count;s++)e[a]=t[n.firstDataIndex+s],a++}return e},st=(t,o)=>{let r=typeof o=="number"?e=>o:o;return e=>{let a=t.getEntry(e);return a.type==="header"?t.getHeaderHeight(a.group.groupIndex):r(a.dataIndex)}},xt=(t,o)=>{let r=Et(t,o.getGroupForIndex),e=t+r.length,a=o.headerHeight;return{get totalEntries(){return e},get groupCount(){return r.length},get groups(){return r},getEntry:I=>{if(r.length===0)return{type:"item",dataIndex:I,group:{key:"",groupIndex:0,headerLayoutIndex:0,firstDataIndex:0,count:0}};let L=rt(r,I),c=r[L];if(I===c.headerLayoutIndex)return{type:"header",group:c};let m=I-c.headerLayoutIndex-1;return{type:"item",dataIndex:c.firstDataIndex+m,group:c}},layoutToDataIndex:I=>{if(r.length===0)return I;let L=rt(r,I),c=r[L];if(I===c.headerLayoutIndex)return-1;let m=I-c.headerLayoutIndex-1;return c.firstDataIndex+m},dataToLayoutIndex:I=>{if(r.length===0)return I;let L=Rt(r,I),c=r[L],m=I-c.firstDataIndex;return c.headerLayoutIndex+1+m},getGroupAtLayoutIndex:I=>{if(r.length===0)return{key:"",groupIndex:0,headerLayoutIndex:0,firstDataIndex:0,count:0};let L=rt(r,I);return r[L]},getGroupAtDataIndex:I=>{if(r.length===0)return{key:"",groupIndex:0,headerLayoutIndex:0,firstDataIndex:0,count:0};let L=Rt(r,I);return r[L]},getHeaderHeight:typeof a=="number"?I=>a:I=>{let L=r[I];return L?a(L.key,I):0},rebuild:I=>{r=Et(I,o.getGroupForIndex),e=I+r.length}}};var Vt=(t,o,r,e,a)=>{let n=document.createElement("div");n.className=`${a}-sticky-header`,n.setAttribute("role","presentation"),n.setAttribute("aria-hidden","true"),n.style.position="absolute",n.style.top="0",n.style.left="0",n.style.right="0",n.style.zIndex="5",n.style.pointerEvents="none",n.style.willChange="transform",n.style.overflow="hidden",t.insertBefore(n,t.firstChild);let s=-1,l=!1,y=0,f=m=>{if(m===s)return;s=m;let b=o.groups;if(m<0||m>=b.length){n.textContent="";return}let v=b[m],S=e.headerTemplate(v.key,v.groupIndex),H=o.getHeaderHeight(m);n.style.height=`${H}px`,typeof S=="string"?n.innerHTML=S:n.replaceChildren(S)},u=m=>{let b=o.groups;if(b.length===0){I();return}let v=0;for(let d=b.length-1;d>=0;d--)if(r.getOffset(b[d].headerLayoutIndex)<=m){v=d;break}let S=r.getOffset(b[0].headerLayoutIndex);if(m<S){I();return}l||T(),f(v);let H=o.getHeaderHeight(v),h=0,M=v+1;if(M<b.length){let E=r.getOffset(b[M].headerLayoutIndex)-m;E<H&&(h=E-H)}h!==y&&(y=h,n.style.transform=h===0?"":`translateY(${Math.round(h)}px)`)},T=()=>{l||(l=!0,n.style.display="")},I=()=>{l&&(l=!1,n.style.display="none",s=-1,y=0,n.style.transform="")},L=()=>{let m=s;s=-1,m>=0&&f(m)},c=()=>{n.remove(),s=-1,l=!1};return n.style.display="none",{update:u,refresh:L,show:T,hide:I,destroy:c}};Qe();var At=t=>{if(!t.getGroupForIndex)throw new Error("[vlist/builder] withGroups: getGroupForIndex is required");if(t.headerHeight==null||t.headerHeight<=0)throw new Error("[vlist/builder] withGroups: headerHeight must be a positive number");if(!t.headerTemplate)throw new Error("[vlist/builder] withGroups: headerTemplate is required");let o=null,r=null,e=[],a=[];return{name:"withGroups",priority:10,setup(n){let{dom:s,config:l,rawConfig:y}=n,{classPrefix:f}=l;if(l.horizontal)throw new Error("[vlist/builder] withGroups cannot be used with direction: 'horizontal'");if(l.reverse)throw new Error("[vlist/builder] withGroups cannot be used with reverse: true");let T=y.item.height;e=y.items?[...y.items]:[];let I=e.length,L={getGroupForIndex:t.getGroupForIndex,headerHeight:t.headerHeight,headerTemplate:t.headerTemplate,sticky:t.sticky??!1};o=xt(I,L),a=ot(e,o.groups);let c=st(o,T);n.setHeightConfig(c),n.rebuildHeightCache(a.length),n.dataManager.setItems(a,0,a.length);let m=y.item.template,{headerTemplate:b}=t,v=((d,E,p)=>Me(d)?b(d.groupKey,d.groupIndex):m(d,E,p)),S=n.methods.get("_getGridLayout"),H=n.methods.get("_replaceGridRenderer"),h=n.methods.get("_updateGridLayoutForGroups");if(S&&H){h&&h(V=>{let z=a[V];return!!(z&&Me(z))});let{createGridRenderer:d}=(et(),In(Ct)),E=S(),p=d(s.items,v,n.heightCache,E,f,n.getContainerWidth(),()=>n.dataManager.getTotal(),l.ariaIdPrefix);H(p)}else n.replaceTemplate(v);if(s.root.classList.add(`${f}--grouped`),t.sticky!==!1){r=Vt(s.root,o,n.heightCache,{...L,sticky:L.sticky??!1},f);let d=r;n.afterScroll.push((E,p)=>{d.update(E)}),r.update(n.scrollController.getScrollTop())}let M=()=>{if(!o)return;o.rebuild(e.length),a=ot(e,o.groups);let d=st(o,T);n.setHeightConfig(d),n.rebuildHeightCache(a.length),n.dataManager.setItems(a,0,a.length),r&&r.refresh()};n.methods.set("setItems",d=>{e=[...d],M()}),n.methods.set("appendItems",d=>{e=[...e,...d],M()}),n.methods.set("prependItems",d=>{e=[...d,...e],M()}),n.methods.set("removeItem",d=>{e=e.filter(E=>E.id!==d),M()}),n.methods.set("scrollToIndex",(d,E)=>{let p=o.dataToLayoutIndex(d),{align:V,behavior:z}=Bn(E),X=n.dataManager.getTotal(),U=Se(p,n.heightCache,n.state.viewportState.containerHeight,X,V,n.getCachedCompression());n.scrollController.scrollTo(U)}),n.methods.set("_getItems",()=>e),n.methods.set("_getTotal",()=>e.length),n.destroyHandlers.push(()=>{r&&(r.destroy(),r=null),s.root.classList.remove(`${f}--grouped`)})},destroy(){r&&(r.destroy(),r=null)}}},it=300,Bn=t=>typeof t=="string"?{align:t,behavior:"auto",duration:it}:t&&typeof t=="object"?{align:t.align??"start",behavior:t.behavior??"auto",duration:t.duration??it}:{align:"start",behavior:"auto",duration:it};var _t=t=>({selected:new Set(t??[]),focusedIndex:-1}),at=(t,o,r)=>{if(r==="none")return t;let e=new Set(t.selected);if(r==="single")e.clear(),o.length>0&&e.add(o[0]);else for(let a of o)e.add(a);return{...t,selected:e}},lt=(t,o)=>{let r=new Set(t.selected);for(let e of o)r.delete(e);return{...t,selected:r}},ke=(t,o,r)=>r==="none"?t:t.selected.has(o)?lt(t,[o]):at(t,[o],r),Pt=(t,o,r)=>r!=="multiple"?t:{...t,selected:new Set(o.map(e=>e.id))},Ft=t=>({...t,selected:new Set}),Gt=(t,o)=>(t.focusedIndex=o,t),kt=(t,o,r=!0)=>{if(o===0)return t;let e=t.focusedIndex-1;return e<0&&(e=r?o-1:0),t.focusedIndex=e,t},Dt=(t,o,r=!0)=>{if(o===0)return t;let e=t.focusedIndex+1;return e>=o&&(e=r?0:o-1),t.focusedIndex=e,t},Ot=(t,o)=>(o===0||(t.focusedIndex=0),t),$t=(t,o)=>(o===0||(t.focusedIndex=o-1),t);var De=t=>Array.from(t.selected),Oe=(t,o)=>{let r=[];for(let e of t.selected){let a=o(e);a&&r.push(a)}return r};var dt=t=>{let o=t?.mode??"single",r=t?.initial,e=_t(r),a=null;return{name:"withSelection",priority:50,methods:["select","deselect","toggleSelect","selectAll","clearSelection","getSelected","getSelectedItems"],setup(n){let{dom:s,emitter:l,config:y}=n,{classPrefix:f,ariaIdPrefix:u}=y;if(o==="none"){n.methods.set("select",()=>{}),n.methods.set("deselect",()=>{}),n.methods.set("toggleSelect",()=>{}),n.methods.set("selectAll",()=>{}),n.methods.set("clearSelection",()=>{}),n.methods.set("getSelected",()=>[]),n.methods.set("getSelectedItems",()=>[]),n.methods.set("setSelectionMode",()=>{});return}let{renderIfNeeded:T,forceRender:I}=n.getRenderFns(),L=()=>{n.dom.items.querySelectorAll("[data-index]").forEach(H=>{let h=H,M=h.dataset.id;if(M!==void 0){let d=/^\d+$/.test(M)?parseInt(M,10):M,E=e.selected.has(d),V=parseInt(h.dataset.index??"-1",10)===e.focusedIndex;h.classList.toggle(`${f}-item--selected`,E),h.classList.toggle(`${f}-item--focused`,V),h.ariaSelected=E?"true":"false"}})},c=()=>{n.state.isDestroyed||(T(),L())},m=()=>{n.state.isDestroyed||(I(),L())};n.setRenderFns(c,m);let b=()=>{L(),l.emit("selection:change",{selected:De(e),items:Oe(e,S=>n.dataManager.getItemById(S))})};a=document.createElement("div"),a.setAttribute("aria-live","polite"),a.setAttribute("aria-atomic","true"),a.className=`${f}-live-region`,a.style.cssText="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0",s.root.appendChild(a);let v=a;l.on("selection:change",({selected:S})=>{let H=S.length;H===0?v.textContent="":H===1?v.textContent="1 item selected":v.textContent=`${H} items selected`}),n.clickHandlers.push(S=>{if(n.state.isDestroyed)return;let h=S.target.closest("[data-index]");if(!h)return;let M=parseInt(h.dataset.index??"-1",10);if(M<0)return;let d=n.dataManager.getItem(M);d&&(l.emit("item:click",{item:d,index:M,event:S}),e=Gt(e,M),s.root.setAttribute("aria-activedescendant",`${u}-item-${M}`),e=ke(e,d.id,o),b())}),n.keydownHandlers.push(S=>{if(n.state.isDestroyed)return;let H=n.dataManager.getTotal(),h=e.focusedIndex,M=!1,d=!1,E=e;switch(S.key){case"ArrowUp":E=kt(e,H),M=!0,d=!0;break;case"ArrowDown":E=Dt(e,H),M=!0,d=!0;break;case"Home":E=Ot(e,H),M=!0,d=!0;break;case"End":E=$t(e,H),M=!0,d=!0;break;case" ":case"Enter":if(e.focusedIndex>=0){let p=n.dataManager.getItem(e.focusedIndex);p&&(E=ke(e,p.id,o)),M=!0}break}if(M){S.preventDefault(),e=E;let p=e.focusedIndex;if(p>=0){let V=n.dataManager.getState(),z=Se(p,n.heightCache,n.state.viewportState.containerHeight,V.total,"center",n.getCachedCompression());n.scrollController.scrollTo(z),s.root.setAttribute("aria-activedescendant",`${u}-item-${p}`)}else s.root.removeAttribute("aria-activedescendant");if(d){let{selected:V}=e;if(h>=0&&h!==p){let z=n.dataManager.getItem(h);z&&n.renderer.updateItemClasses(h,V.has(z.id),!1)}if(p>=0){let z=n.dataManager.getItem(p);z&&n.renderer.updateItemClasses(p,V.has(z.id),!0)}}else m(),l.emit("selection:change",{selected:De(e),items:Oe(e,V=>n.dataManager.getItemById(V))})}}),n.methods.set("select",(...S)=>{e=at(e,S,o),b()}),n.methods.set("deselect",(...S)=>{e=lt(e,S),b()}),n.methods.set("toggleSelect",S=>{e=ke(e,S,o),b()}),n.methods.set("selectAll",()=>{if(o!=="multiple")return;let S=n.getAllLoadedItems();e=Pt(e,S,o),b()}),n.methods.set("clearSelection",()=>{e=Ft(e);let{renderRange:S,isCompressed:H}=n.state.viewportState,h=n.getItemsForRange(S),M=H?n.getCompressionContext():void 0;n.renderer.render(h,S,e.selected,e.focusedIndex,M),l.emit("selection:change",{selected:[],items:[]})}),n.methods.set("getSelected",()=>De(e)),n.methods.set("getSelectedItems",()=>Oe(e,S=>n.dataManager.getItemById(S))),n.destroyHandlers.push(()=>{v&&v.parentNode&&v.remove()})},destroy(){a&&a.parentNode&&a.remove(),a=null}}};var Re=(t,o,r={},e="vlist",a=!1)=>{let{autoHide:n=!0,autoHideDelay:s=1e3,minThumbSize:l=30,showOnHover:y=!0,hoverZoneWidth:f=16,showOnViewportEnter:u=!0}=r,T=0,I=0,L=0,c=0,m=!1,b=!1,v=0,S=0,H=0,h=null,M=!1,d=null,E=null,p=a?"width":"height",V=a?"translateX":"translateY",z=a?Q=>Q.clientX:Q=>Q.clientY,X=a?"left":"top",U=document.createElement("div"),ee=document.createElement("div"),Z=y?document.createElement("div"):null,R=()=>{U.className=`${e}-scrollbar`,ee.className=`${e}-scrollbar-thumb`,a&&U.classList.add(`${e}-scrollbar--horizontal`),U.appendChild(ee),t.appendChild(U),Z&&(Z.className=`${e}-scrollbar-hover`,a?(Z.classList.add(`${e}-scrollbar-hover--horizontal`),Z.style.height=`${f}px`):Z.style.width=`${f}px`,t.appendChild(Z))},A=()=>{h&&(clearTimeout(h),h=null)},G=()=>{n&&(A(),h=setTimeout(C,s))},k=()=>{T<=I||(A(),M||(U.classList.add(`${e}-scrollbar--visible`),M=!0),n&&!m&&!b&&G())},C=()=>{m||b||(U.classList.remove(`${e}-scrollbar--visible`),M=!1)},x=(Q,te)=>{T=Q,I=te;let _=T>I;if(U.style.display=_?"":"none",!_){C();return}let P=I/T;L=Math.max(l,P*I),ee.style[p]=`${L}px`,c=I-L,D(H)},D=Q=>{if(H=Q,T<=I||c<=0)return;let te=T-I,P=Math.min(1,Math.max(0,Q/te))*c;ee.style.transform=`${V}(${P}px)`},O=Q=>{if(Q.target===ee)return;let te=U.getBoundingClientRect(),K=z(Q)-te[X]-L/2,B=Math.max(0,Math.min(K,c))/c,ne=T-I,se=B*ne;o(se),k()},N=Q=>{Q.preventDefault(),Q.stopPropagation(),m=!0,v=z(Q),S=H,A(),U.classList.add(`${e}-scrollbar--dragging`),document.addEventListener("mousemove",Y),document.addEventListener("mouseup",oe)},Y=Q=>{if(!m)return;let te=z(Q)-v,_=c>0?te/c:0,P=T-I,K=_*P,J=Math.max(0,Math.min(S+K,P)),ne=J/P*c;ee.style.transform=`${V}(${ne}px)`,E=J,d===null&&(d=requestAnimationFrame(()=>{E!==null&&o(E),d=null}))},oe=()=>{m=!1,d!==null&&(cancelAnimationFrame(d),d=null),E!==null&&(o(E),E=null),U.classList.remove(`${e}-scrollbar--dragging`),n&&!b&&G(),document.removeEventListener("mousemove",Y),document.removeEventListener("mouseup",oe)},de=()=>{u&&k()},$=()=>{m||(b=!1,n&&G())},ae=()=>{b=!0,A(),k()},j=()=>{b=!1,!m&&n&&G()},re=()=>{A(),d!==null&&(cancelAnimationFrame(d),d=null),U.removeEventListener("click",O),U.removeEventListener("mouseenter",ae),U.removeEventListener("mouseleave",j),ee.removeEventListener("mousedown",N),t.removeEventListener("mouseenter",de),t.removeEventListener("mouseleave",$),document.removeEventListener("mousemove",Y),document.removeEventListener("mouseup",oe),Z&&(Z.removeEventListener("mouseenter",ae),Z.removeEventListener("mouseleave",j),Z.parentNode&&Z.parentNode.removeChild(Z)),U.parentNode&&U.parentNode.removeChild(U)};return R(),U.addEventListener("click",O),U.addEventListener("mouseenter",ae),U.addEventListener("mouseleave",j),ee.addEventListener("mousedown",N),t.addEventListener("mouseenter",de),t.addEventListener("mouseleave",$),Z&&(Z.addEventListener("mouseenter",ae),Z.addEventListener("mouseleave",j)),{show:k,hide:C,updateBounds:x,updatePosition:D,isVisible:()=>M,destroy:re}};var Bt=t=>{let o=null;return{name:"withScrollbar",priority:30,setup(r){let{dom:e,config:a}=r,{classPrefix:n,horizontal:s}=a;o=Re(e.viewport,f=>r.scrollController.scrollTo(f),t??{},n,s),e.viewport.classList.contains(`${n}-viewport--custom-scrollbar`)||e.viewport.classList.add(`${n}-viewport--custom-scrollbar`);let l=r.getCachedCompression();o.updateBounds(l.virtualHeight,r.state.viewportState.containerHeight);let y=o;r.afterScroll.push((f,u)=>{y.updatePosition(f),y.show()}),r.resizeHandlers.push((f,u)=>{if(y){let T=r.getCachedCompression();y.updateBounds(T.virtualHeight,r.state.viewportState.containerHeight)}}),r.contentSizeHandlers.push(()=>{if(y){let f=r.getCachedCompression();y.updateBounds(f.virtualHeight,r.state.viewportState.containerHeight)}}),r.destroyHandlers.push(()=>{y&&y.destroy()})},destroy(){o&&(o.destroy(),o=null)}}};Ze();var zt=()=>{let t=null,o=0,r=!1;return{name:"withCompression",priority:20,setup(e){let{dom:a,config:n}=e,{classPrefix:s,horizontal:l}=n,y=()=>{let u=e.getVirtualTotal(),T=Te(u,e.heightCache);if(T.isCompressed&&!r){r=!0,e.scrollController.enableCompression(T),e.updateContentSize(T.virtualHeight),e.setScrollFns(()=>o,m=>{o=m});let I=a.viewport,L=m=>{m.preventDefault();let b=T.virtualHeight-e.state.viewportState.containerHeight;o=Math.max(0,Math.min(o+m.deltaY,b)),e.scrollController.scrollTo(o)};if(I.addEventListener("wheel",L,{passive:!1}),e.destroyHandlers.push(()=>{I.removeEventListener("wheel",L)}),!a.viewport.querySelector(`.${s}-scrollbar-track`)){t=Re(a.viewport,b=>e.scrollController.scrollTo(b),{},s,l),a.viewport.classList.contains(`${s}-viewport--custom-scrollbar`)||a.viewport.classList.add(`${s}-viewport--custom-scrollbar`),t.updateBounds(T.virtualHeight,e.state.viewportState.containerHeight);let m=t;e.afterScroll.push((b,v)=>{m&&(m.updatePosition(b),m.show())}),e.resizeHandlers.push((b,v)=>{if(m){let S=e.getCachedCompression();m.updateBounds(S.virtualHeight,e.state.viewportState.containerHeight)}})}}else!T.isCompressed&&r?(r=!1,e.scrollController.disableCompression(),e.updateContentSize(T.actualHeight)):T.isCompressed&&(e.scrollController.updateConfig({compression:T}),e.updateContentSize(T.virtualHeight));t&&t.updateBounds(T.virtualHeight,e.state.viewportState.containerHeight),e.state.cachedCompression={state:T,totalItems:u}};e.updateCompressionMode=y;let f=e.getCachedCompression.bind(e);e.getCachedCompression=()=>e.state.cachedCompression?e.state.cachedCompression.state:f(),e.setVisibleRangeFn((u,T,I,L,c)=>{let m=Te(L,I);St(u,T,I,L,m,c)}),e.setScrollToPosFn((u,T,I,L,c)=>{let m=Te(L,T);return It(u,T,I,L,m,c)}),e.setPositionElementFn((u,T)=>{let I=e.getVirtualTotal(),L=Te(I,e.heightCache);if(L.isCompressed){let c=Math.round(Ge(T,e.scrollController.getScrollTop(),e.heightCache,I,e.state.viewportState.containerHeight,L)),m=e.config.horizontal;u.style.transform=m?`translateX(${c}px)`:`translateY(${c}px)`}else{let c=Math.round(e.heightCache.getOffset(T)),m=e.config.horizontal;u.style.transform=m?`translateX(${c}px)`:`translateY(${c}px)`}}),y(),e.destroyHandlers.push(()=>{t&&(t.destroy(),t=null)})},destroy(){t&&(t.destroy(),t=null)}}};var Ut=()=>({name:"withSnapshots",priority:50,methods:["getScrollSnapshot","restoreScroll"],setup(t){t.methods.set("getScrollSnapshot",()=>{let o=t.scrollController.getScrollTop(),r=t.getCachedCompression(),e=t.getVirtualTotal(),a=t.methods.get("getSelected"),n=a&&a().length>0?a():void 0;if(e===0){let f={index:0,offsetInItem:0};return n&&(f.selectedIds=n),f}let s,l;if(r.isCompressed){let u=o/r.virtualHeight*e;s=Math.max(0,Math.min(Math.floor(u),e-1)),l=(u-s)*t.heightCache.getHeight(s)}else s=t.heightCache.indexAtOffset(o),l=o-t.heightCache.getOffset(s);l=Math.max(0,l);let y={index:s,offsetInItem:l};return n&&(y.selectedIds=n),y}),t.methods.set("restoreScroll",o=>{let{index:r,offsetInItem:e,selectedIds:a}=o,n=t.getCachedCompression(),s=t.getVirtualTotal();if(s===0)return;let l=Math.max(0,Math.min(r,s-1)),y;if(n.isCompressed){let u=t.heightCache.getHeight(l),T=u>0?e/u:0;y=(l+T)/s*n.virtualHeight}else y=t.heightCache.getOffset(l)+e;let f=Math.max(0,n.virtualHeight-t.state.viewportState.containerHeight);if(y=Math.max(0,Math.min(y,f)),t.scrollController.scrollTo(y),a&&a.length>0){let u=t.methods.get("select");u&&u(...a)}})}});var Nt=(t={})=>{let{chunkSize:o=100,maxCachedItems:r=5e3,evictionBuffer:e=200,onEvict:a}=t,n=new Map,s=0,l=0,y=R=>{let A=n.get(R);return A?A.lastAccess=Date.now():(A={items:new Array(o),count:0,lastAccess:Date.now()},n.set(R,A)),A},f=R=>Math.floor(R/o),u=R=>R%o,T=()=>s,I=R=>{s=R},L=R=>{if(R<0||R>=s)return;let A=f(R),G=n.get(A);if(G)return G.items[u(R)]},c=R=>{if(R<0||R>=s)return!1;let A=f(R),G=n.get(A);return G?G.items[u(R)]!==void 0:!1},m=(R,A)=>{let G=f(R),k=y(G),C=u(R),x=k.items[C]===void 0;k.items[C]=A,x&&(k.count++,l++),R>=s&&(s=R+1)},b=(R,A)=>{for(let G=0;G<A.length;G++){let k=A[G];k!==void 0&&m(R+G,k)}},v=R=>{if(R<0||R>=s)return!1;let A=f(R),G=n.get(A);if(!G)return!1;let k=u(R);return G.items[k]===void 0?!1:(G.items[k]=void 0,G.count--,l--,G.count===0&&n.delete(A),!0)},S=(R,A)=>{let G=[];for(let k=R;k<=A&&k<s;k++)G.push(L(k));return G},H=(R,A)=>{for(let G=R;G<=A&&G<s;G++)if(!c(G))return!1;return!0},h=()=>{let R=[],A=null,G=Array.from(n.keys()).sort((k,C)=>k-C);for(let k of G){let C=n.get(k);if(!C)continue;let x=k*o;for(let D=0;D<o;D++){let O=x+D;if(O>=s)break;C.items[D]!==void 0?A===null?A={start:O,end:O}:O===A.end+1?A.end=O:(R.push(A),A={start:O,end:O}):A!==null&&(R.push(A),A=null)}}return A!==null&&R.push(A),R},M=(R,A)=>{let G=[],k=null;for(let C=R;C<=A&&C<s;C++)c(C)?k!==null&&(G.push(k),k=null):k===null?k={start:C,end:C}:k.end=C;return k!==null&&G.push(k),G},d=R=>n.has(R),E=R=>{let A=n.get(R);A&&(A.lastAccess=Date.now())},p=(R,A)=>{if(R>A||n.size===0)return;let G=Date.now(),k=f(Math.max(0,R)),C=f(Math.min(s-1,A));for(let x=k;x<=C;x++){let D=n.get(x);D&&(D.lastAccess=G)}},V=(R,A)=>{if(l<=r)return 0;let G=Math.max(0,R-e),k=Math.min(s-1,A+e),C=f(G),x=f(k),D=0,O=[];for(let[N,Y]of n)(N<C||N>x)&&(D+=Y.count,O.push(N),l-=Y.count,n.delete(N));return D>0&&a&&a(D,O),D},z=()=>{if(l<=r)return 0;let R=Array.from(n.entries()).sort(([,k],[,C])=>k.lastAccess-C.lastAccess),A=0,G=[];for(let[k,C]of R){if(l<=r)break;A+=C.count,l-=C.count,G.push(k),n.delete(k)}return A>0&&a&&a(A,G),A},X=()=>({totalItems:s,cachedItems:l,cachedChunks:n.size,chunkSize:o,maxCachedItems:r,memoryEfficiency:s>0?1-l/s:1}),U=()=>l,ee=()=>{n.clear(),l=0};return{chunkSize:o,maxCachedItems:r,getTotal:T,setTotal:I,get:L,has:c,set:m,setRange:b,delete:v,getRange:S,isRangeLoaded:H,getLoadedRanges:h,findUnloadedRanges:M,getChunkIndex:f,isChunkLoaded:d,touchChunk:E,touchChunksForRange:p,evictDistant:V,evictToLimit:z,getStats:X,getCachedCount:U,clear:ee,reset:()=>{ee(),s=0}}},zn=t=>{if(t.length===0)return[];let o=[...t].sort((e,a)=>e.start-a.start),r=[{...o[0]}];for(let e=1;e<o.length;e++){let a=o[e],n=r[r.length-1];a.start<=n.end+1?n.end=Math.max(n.end,a.end):r.push({...a})}return r},Wt=(t,o,r)=>{let e=Math.floor(t.start/r)*r,a=Math.ceil((t.end+1)/r)*r-1,n={start:e,end:a};if(o.length===0)return[n];let s=[],l=zn(o),y=n.start;for(let f of l)if(!(f.end<y)&&(f.start>n.end||(f.start>y&&s.push({start:y,end:Math.min(f.start-1,n.end)}),y=f.end+1,y>n.end)))break;return y<=n.end&&s.push({start:y,end:n.end}),s};var Ee="_isPlaceholder",Un="__placeholder_",Kt=(t={})=>{let{enabled:o=!0,maskCharacter:r="\u2588",randomVariance:e=!0,maxSampleSize:a=20,customGenerator:n}=t,s=null,l=!1,y=0,f=v=>{if(!o||l||v.length===0)return;let S=new Map,H=new Map,h=Math.min(v.length,a);for(let M=0;M<h;M++){let d=v[M];if(!(!d||typeof d!="object"))for(let[E,p]of Object.entries(d)){if(E.startsWith("_")||E==="id")continue;H.has(E)||H.set(E,{lengths:[],types:new Set});let V=H.get(E),z=Array.isArray(p)?"array":typeof p;V.types.add(z),typeof p=="string"?V.lengths.push(p.length):p!=null&&V.lengths.push(String(p).length)}}for(let[M,d]of H){if(d.lengths.length===0)continue;let E=Math.min(...d.lengths),p=Math.max(...d.lengths),V=Math.round(d.lengths.reduce((X,U)=>X+U,0)/d.lengths.length),z="string";d.types.has("number")&&d.types.size===1?z="number":d.types.has("boolean")&&d.types.size===1?z="boolean":d.types.has("array")?z="array":d.types.has("object")&&!d.types.has("string")&&(z="object"),S.set(M,{minLength:E,maxLength:p,avgLength:V,type:z})}s=S,l=!0},u=()=>l,T=v=>{let S=v.avgLength;return e&&v.minLength!==v.maxLength&&(S=Math.floor(Math.random()*(v.maxLength-v.minLength+1)+v.minLength),Math.random()<.3&&(S=Math.max(1,S+Math.floor(Math.random()*3)-1))),r.repeat(Math.max(1,S))},I=v=>{if(n)return{...n(v),[Ee]:!0};let S={id:`${Un}${y++}`,[Ee]:!0,_index:v};if(!s||s.size===0)return S.label=r.repeat(12),S;for(let[H,h]of s)switch(h.type){case"string":S[H]=T(h);break;case"number":S[H]=0;break;case"boolean":S[H]=!1;break;case"array":S[H]=[];break;case"object":S[H]={};break;default:S[H]=T(h)}return S};return{analyzeStructure:f,hasAnalyzedStructure:u,generate:I,generateRange:(v,S)=>{let H=[];for(let h=v;h<=S;h++)H.push(I(h));return H},isPlaceholder:v=>!v||typeof v!="object"?!1:v[Ee]===!0,getPlaceholderKey:()=>Ee,clear:()=>{s=null,l=!1,y=0}}},$e=t=>!t||typeof t!="object"?!1:t[Ee]===!0;var Nn=50,qt=(t={})=>{let{adapter:o,initialItems:r,initialTotal:e,storage:a,placeholder:n,pageSize:s=Nn,onStateChange:l,onItemsLoaded:y,onItemsEvicted:f}=t,u=Nt({...a,onEvict:(_,P)=>{f?.(_),h()}}),T=null,I=()=>(T||(T=Kt(n)),T),L=new Map,c=!1,m,b=!0,v,S=[],H=new Map,h=()=>{l?.(ee())},M=()=>{L.clear();let _=u.getLoadedRanges();for(let P of _)for(let K=P.start;K<=P.end;K++){let J=u.get(K);J&&!$e(J)&&L.set(J.id,K)}},d=(_,P)=>{$e(P)||L.set(P.id,_)},E=_=>{L.delete(_)},p=(_,P)=>`${_}-${P}`,V=()=>u.getTotal(),z=()=>u.getCachedCount(),X=()=>c,U=()=>b,ee=()=>({total:u.getTotal(),cached:u.getCachedCount(),isLoading:c,pendingRanges:S,error:m,hasMore:b,cursor:v}),Z=()=>u,R=()=>I(),A=_=>{let P=u.get(_);if(P!==void 0)return P;if(_>=0&&_<u.getTotal())return I().generate(_)},G=_=>{let P=L.get(_);if(P!==void 0)return u.get(P)},k=_=>L.get(_)??-1,C=_=>{let P=u.get(_);return P!==void 0&&!$e(P)},x=(_,P)=>{let K=[],J=u.getTotal(),B=0,ne=0;u.touchChunksForRange(_,Math.min(P,J-1));for(let se=_;se<=P&&se<J;se++){let be=u.get(se);be!==void 0?(K.push(be),B++):(K.push(I().generate(se)),ne++)}return K},D=_=>{u.setTotal(_),b=u.getCachedCount()<_,h()},O=(_,P=0,K)=>{T&&!T.hasAnalyzedStructure()&&_.length>0&&T.analyzeStructure(_);for(let J=0;J<_.length;J++){let B=_[J];if(B!==void 0){let ne=P+J;u.set(ne,B),d(ne,B)}}K!==void 0?u.setTotal(K):P+_.length>u.getTotal()&&u.setTotal(P+_.length),b=u.getCachedCount()<u.getTotal(),y?.(_,P,u.getTotal()),h()},N=(_,P)=>{let K=L.get(_);if(K===void 0)return!1;let J=u.get(K);if(!J)return!1;let B={...J,...P};return u.set(K,B),P.id!==void 0&&P.id!==_&&(E(_),d(K,B)),h(),!0},Y=_=>{let P=L.get(_);if(P===void 0)return!1;u.delete(P),E(_);let K=u.getTotal();return K>0&&u.setTotal(K-1),h(),!0},oe=async(_,P)=>{if(!o)return;let K=p(_,P);if(H.has(K))return;let J=u.getLoadedRanges(),B=Wt({start:_,end:P},J,u.chunkSize);if(B.length===0)return;let ne=u.chunkSize,se=[];for(let ue of B){let ie=Math.floor(ue.start/ne),fe=Math.floor(ue.end/ne);for(let le=ie;le<=fe;le++){let he=le*ne,ce=he+ne-1,we=p(he,ce);!se.some(ye=>ye.start===he)&&!H.has(we)&&se.push({start:he,end:ce})}}let be=[];for(let ue of B){let ie=Math.floor(ue.start/ne),fe=Math.floor(ue.end/ne);for(let le=ie;le<=fe;le++){let he=le*ne,ce=he+ne-1,we=p(he,ce);if(H.has(we)){let ye=H.get(we);be.includes(ye)||be.push(ye)}}}for(let ue of se){let ie=p(ue.start,ue.end),fe=(async()=>{S.push(ue),c=!0,m=void 0,h();try{let le=ue.end-ue.start+1,he={offset:ue.start,limit:le,cursor:void 0},ce=await o.read(he);O(ce.items,ue.start,ce.total),ce.cursor&&(v=ce.cursor),ce.hasMore!==void 0?b=ce.hasMore:ce.total!==void 0&&(b=u.getCachedCount()<ce.total)}catch(le){m=le instanceof Error?le:new Error(String(le))}finally{H.delete(ie),S=S.filter(le=>le.start!==ue.start||le.end!==ue.end),c=H.size>0,h()}})();H.set(ie,fe),be.push(fe)}await Promise.all(be)},de=async(_,P)=>{u.isRangeLoaded(_,P)||await oe(_,P)},$=async()=>{o&&await oe(0,s-1)},ae=async()=>{if(!o||c||!b)return!1;let _=u.getCachedCount(),P=u.getTotal(),K=_,J=Math.min(K+s-1,P>0?P-1:K+s-1);return K>=P&&P>0?(b=!1,!1):(await oe(K,J),u.getCachedCount()>_)},j=async()=>{u.clear(),L.clear(),T&&T.clear(),v=void 0,b=!0,m=void 0,h(),await $()},re=(_,P)=>{u.evictDistant(_,P)>0&&M()},Q=()=>{u.clear(),L.clear(),v=void 0,m=void 0,S=[],c=!1,h()},te=()=>{u.reset(),L.clear(),T&&T.clear(),v=void 0,b=!0,m=void 0,S=[],c=!1,h()};return r&&r.length>0?O(r,0,e??r.length):e!==void 0&&u.setTotal(e),{getState:ee,getTotal:V,getCached:z,getIsLoading:X,getHasMore:U,getStorage:Z,getPlaceholders:R,getItem:A,getItemById:G,getIndexById:k,isItemLoaded:C,getItemsInRange:x,setTotal:D,setItems:O,updateItem:N,removeItem:Y,loadRange:oe,ensureRange:de,loadInitial:$,loadMore:ae,reload:j,evictDistant:re,clear:Q,reset:te}};var Yt=t=>{let{adapter:o,loading:r}=t,e=r?.cancelThreshold??15,a=r?.preloadThreshold??2,n=r?.preloadAhead??50;return{name:"withData",priority:20,methods:["reload"],setup(s){let{emitter:l}=s,y=s.config.reverse,f=s.config.overscan,u=qt({adapter:o,pageSize:50,onStateChange:()=>{s.state.isInitialized&&(s.heightCache.rebuild(s.getVirtualTotal()),s.updateCompressionMode(),s.state.viewportState=tt(s.state.viewportState,s.heightCache,s.getVirtualTotal(),f,s.getCachedCompression()),s.updateContentSize(s.state.viewportState.totalHeight),s.renderIfNeeded())},onItemsLoaded:(v,S,H)=>{s.state.isInitialized&&(s.heightCache.rebuild(s.getVirtualTotal()),s.forceRender(),l.emit("load:end",{items:v,total:H}))}});s.replaceDataManager(u);let T=null,I=null,L=0,c=()=>{if(I){let v=I;I=null,s.dataManager.ensureRange(v.start,v.end).catch(S=>{l.emit("error",{error:S,context:"ensureRange"})})}};s.afterScroll.push((v,S)=>{if(s.state.isDestroyed)return;let H=s.scrollController.getVelocity(),M=s.scrollController.isTracking()&&H<=e;if(I&&L>e&&H<=e){let p=I;I=null,s.dataManager.ensureRange(p.start,p.end).catch(V=>{l.emit("error",{error:V,context:"ensureRange"})})}L=H,M&&!s.dataManager.getIsLoading()&&s.dataManager.getHasMore()&&(y?v<200&&(l.emit("load:start",{offset:s.dataManager.getCached(),limit:50}),s.dataManager.loadMore().catch(p=>{l.emit("error",{error:p,context:"loadMore"})})):s.state.viewportState.totalHeight-v-s.state.viewportState.containerHeight<200&&(l.emit("load:start",{offset:s.dataManager.getCached(),limit:50}),s.dataManager.loadMore().catch(V=>{l.emit("error",{error:V,context:"loadMore"})})));let{renderRange:d}=s.state.viewportState;if(!T||d.start!==T.start||d.end!==T.end)if(T={start:d.start,end:d.end},M){I=null;let p=d.start,V=d.end,z=s.getVirtualTotal();H>a&&(S==="down"?V=Math.min(d.end+n,z-1):p=Math.max(d.start-n,0)),s.dataManager.ensureRange(p,V).catch(X=>{l.emit("error",{error:X,context:"ensureRange"})})}else I={start:d.start,end:d.end}});let m=200,b=null;s.afterScroll.push((v,S)=>{b!==null&&clearTimeout(b),b=setTimeout(()=>{b=null,c()},m)}),s.destroyHandlers.push(()=>{b!==null&&(clearTimeout(b),b=null)}),l.on("load:start",()=>{s.dom.root.setAttribute("aria-busy","true")}),l.on("load:end",()=>{s.dom.root.removeAttribute("aria-busy")}),s.methods.set("reload",async()=>{await s.dataManager.reload()}),l.emit("load:start",{offset:0,limit:50}),s.dataManager.loadInitial().catch(v=>{l.emit("error",{error:v,context:"loadInitial"})})}}};var Xt=()=>{let t=null;return{name:"withWindow",priority:5,setup(o){let{dom:r,state:e,config:a,emitter:n}=o;r.root.style.overflow="visible",r.root.style.height="auto",r.viewport.classList.remove(`${a.classPrefix}-viewport--custom-scrollbar`),o.disableViewportResize(),o.setScrollTarget(window),o.setScrollFns(()=>{let f=r.viewport.getBoundingClientRect();return a.horizontal?Math.max(0,-f.left):Math.max(0,-f.top)},f=>{let u=r.viewport.getBoundingClientRect();if(a.horizontal){let T=u.left+window.scrollX;window.scrollTo(T+f,window.scrollY)}else{let T=u.top+window.scrollY;window.scrollTo(window.scrollX,T+f)}}),o.setContainerDimensions({width:()=>window.innerWidth,height:()=>window.innerHeight}),e.viewportState.containerHeight=window.innerHeight;let s=window.innerHeight,l=window.innerWidth,y=()=>{let f=window.innerWidth,u=window.innerHeight,T=a.horizontal?f:u,I=a.horizontal?l:s;if(!(Math.abs(T-I)<=1)){s=u,l=f,e.viewportState.containerHeight=u,n.emit("resize",{width:f,height:u});for(let L=0;L<o.resizeHandlers.length;L++)o.resizeHandlers[L](f,u);o.renderIfNeeded()}};window.addEventListener("resize",y,{passive:!0}),t=()=>{window.removeEventListener("resize",y)},o.destroyHandlers.push(t)},destroy(){t&&(t(),t=null)}}};var jt=t=>{let o=Ye(t);if(t.scroll?.element===window&&(o=o.use(Xt())),t.adapter&&(o=o.use(Yt({adapter:t.adapter,...t.loading&&{loading:t.loading}}))),t.layout==="grid"){if(!t.grid)throw new Error("[vlist/builder] grid configuration is required when layout is 'grid'");if(!t.grid.columns||t.grid.columns<1)throw new Error("[vlist/builder] grid.columns must be a positive integer >= 1");let n={columns:t.grid.columns};t.grid.gap!==void 0&&(n.gap=t.grid.gap),o=o.use(Mt(n))}if(t.groups){if(t.direction==="horizontal")throw new Error("[vlist/builder] horizontal direction cannot be combined with groups");let n={getGroupForIndex:t.groups.getGroupForIndex,headerHeight:typeof t.groups.headerHeight=="function"?t.groups.headerHeight("",0):t.groups.headerHeight,headerTemplate:t.groups.headerTemplate};t.groups.sticky!==void 0&&(n.sticky=t.groups.sticky),o=o.use(At(n))}let r=t.selection?.mode||"none";if(r!=="none"){let n={mode:r};t.selection?.initial!==void 0&&(n.initial=t.selection.initial),o=o.use(dt(n))}else o=o.use(dt({mode:"none"}));o=o.use(zt());let e=t.scroll?.scrollbar||t.scrollbar;if(e!=="none"){let n=typeof e=="object"?e:{};o=o.use(Bt(n))}o=o.use(Ut());let a=o.build();return a.update=n=>{n.grid&&a.updateGrid&&a.updateGrid(n.grid),n.selectionMode!==void 0&&a.setSelectionMode&&a.setSelectionMode(n.selectionMode),n.itemHeight!==void 0&&console.warn("[vlist] Updating itemHeight via update() is not yet supported with the builder pattern. Please recreate the instance or use the full API from 'vlist/full'."),n.overscan!==void 0&&console.warn("[vlist] Updating overscan via update() is not yet supported with the builder pattern.")},a};function ho(t){let o=xe(null),r=xe(null),e=xe(t);e.current=t;let a=xe(!1);ct(()=>{let s=o.current;if(!s)return;let l=jt({...e.current,container:s});return r.current=l,a.current=!0,()=>{a.current=!1,l.destroy(),r.current=null}},[]),ct(()=>{!a.current||!r.current||t.items&&r.current.setItems(t.items)},[t.items]);let n=Kn(()=>r.current,[]);return{containerRef:o,instanceRef:r,getInstance:n}}function bo(t,o,r){let e=xe(r);e.current=r,ct(()=>{let a=t.current;if(!a)return;let n=l=>{e.current(l)};return a.on(o,n)},[t.current,o])}export{ho as useVList,bo as useVListEvent};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist - Height Cache
|
|
3
|
+
* Efficient height management for fixed and variable item heights
|
|
4
|
+
*
|
|
5
|
+
* Provides two implementations:
|
|
6
|
+
* - Fixed: O(1) operations using multiplication (zero overhead, matches existing behavior)
|
|
7
|
+
* - Variable: O(1) offset lookup via prefix sums, O(log n) binary search for index-at-offset
|
|
8
|
+
*
|
|
9
|
+
* The HeightCache abstraction allows all virtual scrolling and compression code
|
|
10
|
+
* to work identically with both fixed and variable heights.
|
|
11
|
+
*/
|
|
12
|
+
/** Height cache for efficient offset/index lookups */
|
|
13
|
+
export interface HeightCache {
|
|
14
|
+
/** Get offset (Y position) for an item index — O(1) */
|
|
15
|
+
getOffset(index: number): number;
|
|
16
|
+
/** Get height of a specific item */
|
|
17
|
+
getHeight(index: number): number;
|
|
18
|
+
/** Find item index at a scroll offset — O(1) fixed, O(log n) variable */
|
|
19
|
+
indexAtOffset(offset: number): number;
|
|
20
|
+
/** Total content height */
|
|
21
|
+
getTotalHeight(): number;
|
|
22
|
+
/** Current total item count */
|
|
23
|
+
getTotal(): number;
|
|
24
|
+
/** Rebuild cache (call when items change) */
|
|
25
|
+
rebuild(totalItems: number): void;
|
|
26
|
+
/** Whether heights are variable (false = fixed fast path) */
|
|
27
|
+
isVariable(): boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create a height cache — returns fixed or variable implementation
|
|
31
|
+
*
|
|
32
|
+
* When height is a number, returns a zero-overhead fixed implementation.
|
|
33
|
+
* When height is a function, builds a prefix-sum array for efficient lookups.
|
|
34
|
+
*/
|
|
35
|
+
export declare const createHeightCache: (height: number | ((index: number) => number), initialTotal: number) => HeightCache;
|
|
36
|
+
/**
|
|
37
|
+
* Count how many items fit in a given container height starting from startIndex
|
|
38
|
+
* Used for compressed mode visible range calculations
|
|
39
|
+
*
|
|
40
|
+
* For fixed heights: O(1) via division
|
|
41
|
+
* For variable heights: O(k) where k = visible item count (typically 10-50)
|
|
42
|
+
*/
|
|
43
|
+
export declare const countVisibleItems: (heightCache: HeightCache, startIndex: number, containerHeight: number, totalItems: number) => number;
|
|
44
|
+
/**
|
|
45
|
+
* Count how many items fit starting from the bottom of the list
|
|
46
|
+
* Used for near-bottom interpolation in compressed mode
|
|
47
|
+
*
|
|
48
|
+
* For fixed heights: O(1) via division
|
|
49
|
+
* For variable heights: O(k) where k = items fitting (typically 10-50)
|
|
50
|
+
*/
|
|
51
|
+
export declare const countItemsFittingFromBottom: (heightCache: HeightCache, containerHeight: number, totalItems: number) => number;
|
|
52
|
+
/**
|
|
53
|
+
* Calculate the pixel offset for a fractional virtual scroll index
|
|
54
|
+
*
|
|
55
|
+
* In compressed mode, the scroll position maps to a fractional item index
|
|
56
|
+
* (e.g., 5.3 means 30% into item 5). This function calculates the actual
|
|
57
|
+
* pixel offset for such a fractional position using variable heights.
|
|
58
|
+
*
|
|
59
|
+
* For fixed heights this reduces to: virtualIndex * itemHeight
|
|
60
|
+
* For variable heights: offset(floor) + frac * height(floor)
|
|
61
|
+
*/
|
|
62
|
+
export declare const getOffsetForVirtualIndex: (heightCache: HeightCache, virtualIndex: number, totalItems: number) => number;
|
|
63
|
+
//# sourceMappingURL=heights.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heights.d.ts","sourceRoot":"","sources":["../../src/rendering/heights.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,sDAAsD;AACtD,MAAM,WAAW,WAAW;IAC1B,uDAAuD;IACvD,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAEjC,oCAAoC;IACpC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAEjC,yEAAyE;IACzE,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtC,2BAA2B;IAC3B,cAAc,IAAI,MAAM,CAAC;IAEzB,+BAA+B;IAC/B,QAAQ,IAAI,MAAM,CAAC;IAEnB,6CAA6C;IAC7C,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,6DAA6D;IAC7D,UAAU,IAAI,OAAO,CAAC;CACvB;AAiID;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,EAC5C,cAAc,MAAM,KACnB,WAKF,CAAC;AAMF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC5B,aAAa,WAAW,EACxB,YAAY,MAAM,EAClB,iBAAiB,MAAM,EACvB,YAAY,MAAM,KACjB,MAkBF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,GACtC,aAAa,WAAW,EACxB,iBAAiB,MAAM,EACvB,YAAY,MAAM,KACjB,MAkBF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,GACnC,aAAa,WAAW,EACxB,cAAc,MAAM,EACpB,YAAY,MAAM,KACjB,MAUF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist - Rendering Domain
|
|
3
|
+
* Rendering, virtualization, and scaling for large datasets
|
|
4
|
+
*/
|
|
5
|
+
export { createHeightCache, countVisibleItems, countItemsFittingFromBottom, getOffsetForVirtualIndex, type HeightCache, } from "./heights";
|
|
6
|
+
export { createRenderer, createDOMStructure, updateContentHeight, updateContentWidth, resolveContainer, getContainerDimensions, type Renderer, type DOMStructure, type CompressionContext, type CompressedPositionFn, type CompressionStateFn, } from "./renderer";
|
|
7
|
+
export { createViewportState, updateViewportState, updateViewportSize, updateViewportItems, calculateRenderRange, calculateTotalHeight, calculateActualHeight, calculateItemOffset, calculateScrollToIndex, clampScrollPosition, getScrollDirection, rangesEqual, isInRange, getRangeCount, diffRanges, getSimpleCompressionState, simpleVisibleRange, simpleScrollToIndex, NO_COMPRESSION, type CompressionState, type VisibleRangeFn, type ScrollToIndexFn, } from "./viewport";
|
|
8
|
+
export { MAX_VIRTUAL_HEIGHT, getCompressionState, getCompressionState as getCompression, needsCompression, getMaxItemsWithoutCompression, getCompressionInfo, calculateCompressedVisibleRange, calculateCompressedRenderRange, calculateCompressedItemPosition, calculateCompressedScrollToIndex, calculateIndexFromScrollPosition, } from "./scale";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rendering/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,2BAA2B,EAC3B,wBAAwB,EACxB,KAAK,WAAW,GACjB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,EACtB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,GACxB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,SAAS,EACT,aAAa,EACb,UAAU,EACV,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,IAAI,cAAc,EACrC,gBAAgB,EAChB,6BAA6B,EAC7B,kBAAkB,EAClB,+BAA+B,EAC/B,8BAA8B,EAC9B,+BAA+B,EAC/B,gCAAgC,EAChC,gCAAgC,GACjC,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist - DOM Rendering
|
|
3
|
+
* Efficient DOM rendering with element pooling
|
|
4
|
+
* Supports compression for large lists (1M+ items)
|
|
5
|
+
*/
|
|
6
|
+
import type { VListItem, ItemTemplate, Range } from "../types";
|
|
7
|
+
import type { CompressionState } from "./viewport";
|
|
8
|
+
import type { HeightCache } from "./heights";
|
|
9
|
+
/**
|
|
10
|
+
* Optional compression position calculator.
|
|
11
|
+
* Injected by the monolithic factory or the withCompression plugin.
|
|
12
|
+
* When not provided, the renderer uses simple heightCache offsets.
|
|
13
|
+
*/
|
|
14
|
+
export type CompressedPositionFn = (index: number, scrollTop: number, heightCache: HeightCache, totalItems: number, containerHeight: number, compression: CompressionState, rangeStart?: number) => number;
|
|
15
|
+
/**
|
|
16
|
+
* Optional compression state getter.
|
|
17
|
+
* Injected by the monolithic factory or the withCompression plugin.
|
|
18
|
+
* When not provided, the renderer assumes no compression.
|
|
19
|
+
*/
|
|
20
|
+
export type CompressionStateFn = (totalItems: number, heightCache: HeightCache) => CompressionState;
|
|
21
|
+
/** Element pool for recycling DOM elements */
|
|
22
|
+
export interface ElementPool {
|
|
23
|
+
/** Get an element from the pool (or create new) */
|
|
24
|
+
acquire: () => HTMLElement;
|
|
25
|
+
/** Return an element to the pool */
|
|
26
|
+
release: (element: HTMLElement) => void;
|
|
27
|
+
/** Clear the pool */
|
|
28
|
+
clear: () => void;
|
|
29
|
+
/** Get pool statistics */
|
|
30
|
+
stats: () => {
|
|
31
|
+
poolSize: number;
|
|
32
|
+
created: number;
|
|
33
|
+
reused: number;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** Compression context for positioning */
|
|
37
|
+
export interface CompressionContext {
|
|
38
|
+
scrollTop: number;
|
|
39
|
+
totalItems: number;
|
|
40
|
+
containerHeight: number;
|
|
41
|
+
rangeStart: number;
|
|
42
|
+
}
|
|
43
|
+
/** DOM structure created by createDOMStructure */
|
|
44
|
+
export interface DOMStructure {
|
|
45
|
+
root: HTMLElement;
|
|
46
|
+
viewport: HTMLElement;
|
|
47
|
+
content: HTMLElement;
|
|
48
|
+
items: HTMLElement;
|
|
49
|
+
}
|
|
50
|
+
/** Renderer instance */
|
|
51
|
+
export interface Renderer<T extends VListItem = VListItem> {
|
|
52
|
+
/** Render items for a range */
|
|
53
|
+
render: (items: T[], range: Range, selectedIds: Set<string | number>, focusedIndex: number, compressionCtx?: CompressionContext) => void;
|
|
54
|
+
/** Update item positions (for compressed scrolling) */
|
|
55
|
+
updatePositions: (compressionCtx: CompressionContext) => void;
|
|
56
|
+
/** Update a single item */
|
|
57
|
+
updateItem: (index: number, item: T, isSelected: boolean, isFocused: boolean) => void;
|
|
58
|
+
/** Update only CSS classes on a rendered item (no template re-evaluation) */
|
|
59
|
+
updateItemClasses: (index: number, isSelected: boolean, isFocused: boolean) => void;
|
|
60
|
+
/** Get rendered item element by index */
|
|
61
|
+
getElement: (index: number) => HTMLElement | undefined;
|
|
62
|
+
/** Clear all rendered items */
|
|
63
|
+
clear: () => void;
|
|
64
|
+
/** Destroy renderer and cleanup */
|
|
65
|
+
destroy: () => void;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Create an element pool for recycling DOM elements
|
|
69
|
+
* Reduces garbage collection and improves performance
|
|
70
|
+
*/
|
|
71
|
+
export declare const createElementPool: (tagName?: string, maxSize?: number) => ElementPool;
|
|
72
|
+
/**
|
|
73
|
+
* Create a renderer for managing DOM elements
|
|
74
|
+
* Supports compression for large lists
|
|
75
|
+
*/
|
|
76
|
+
export declare const createRenderer: <T extends VListItem = VListItem>(itemsContainer: HTMLElement, template: ItemTemplate<T>, heightCache: HeightCache, classPrefix: string, totalItemsGetter?: () => number, ariaIdPrefix?: string, horizontal?: boolean, crossAxisSize?: number, compressionFns?: {
|
|
77
|
+
getState: CompressionStateFn;
|
|
78
|
+
getPosition: CompressedPositionFn;
|
|
79
|
+
}) => Renderer<T>;
|
|
80
|
+
/**
|
|
81
|
+
* Create the vlist DOM structure
|
|
82
|
+
*/
|
|
83
|
+
export declare const createDOMStructure: (container: HTMLElement, classPrefix: string, ariaLabel?: string, horizontal?: boolean) => DOMStructure;
|
|
84
|
+
/**
|
|
85
|
+
* Update content height for virtual scrolling
|
|
86
|
+
*/
|
|
87
|
+
export declare const updateContentHeight: (content: HTMLElement, totalHeight: number) => void;
|
|
88
|
+
/**
|
|
89
|
+
* Update content width for horizontal virtual scrolling
|
|
90
|
+
*/
|
|
91
|
+
export declare const updateContentWidth: (content: HTMLElement, totalWidth: number) => void;
|
|
92
|
+
/**
|
|
93
|
+
* Get container dimensions
|
|
94
|
+
*/
|
|
95
|
+
export declare const getContainerDimensions: (viewport: HTMLElement) => {
|
|
96
|
+
width: number;
|
|
97
|
+
height: number;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Resolve container from selector or element
|
|
101
|
+
*/
|
|
102
|
+
export declare const resolveContainer: (container: HTMLElement | string) => HTMLElement;
|
|
103
|
+
//# sourceMappingURL=renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/rendering/renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist - Compression Module
|
|
3
|
+
* Pure functions for handling large lists that exceed browser height limits
|
|
4
|
+
*
|
|
5
|
+
* When a list's total height (totalItems × itemHeight) exceeds the browser's
|
|
6
|
+
* maximum element height (~16.7M pixels), we "compress" the virtual scroll space.
|
|
7
|
+
*
|
|
8
|
+
* Key concepts:
|
|
9
|
+
* - actualHeight: The true height if all items were rendered
|
|
10
|
+
* - virtualHeight: The capped height used for the scroll container (≤ MAX_VIRTUAL_HEIGHT)
|
|
11
|
+
* - compressionRatio: virtualHeight / actualHeight (1 = no compression, <1 = compressed)
|
|
12
|
+
*
|
|
13
|
+
* When compressed:
|
|
14
|
+
* - Scroll position maps to item index via ratio, not pixel math
|
|
15
|
+
* - Item positions are calculated relative to a "virtual index" at current scroll
|
|
16
|
+
* - Near-bottom interpolation ensures the last items are reachable
|
|
17
|
+
*/
|
|
18
|
+
import type { Range } from "../types";
|
|
19
|
+
import { MAX_VIRTUAL_HEIGHT } from "../constants";
|
|
20
|
+
import type { HeightCache } from "./heights";
|
|
21
|
+
export { MAX_VIRTUAL_HEIGHT };
|
|
22
|
+
/** Compression calculation result */
|
|
23
|
+
export interface CompressionState {
|
|
24
|
+
/** Whether compression is active */
|
|
25
|
+
isCompressed: boolean;
|
|
26
|
+
/** The actual total height */
|
|
27
|
+
actualHeight: number;
|
|
28
|
+
/** The virtual height (capped at MAX_VIRTUAL_HEIGHT) */
|
|
29
|
+
virtualHeight: number;
|
|
30
|
+
/** Compression ratio (1 = no compression, <1 = compressed) */
|
|
31
|
+
ratio: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Calculate compression state for a list
|
|
35
|
+
* Pure function - no side effects
|
|
36
|
+
*/
|
|
37
|
+
export declare const getCompressionState: (_totalItems: number, heightCache: HeightCache) => CompressionState;
|
|
38
|
+
/**
|
|
39
|
+
* Calculate visible range with compression support
|
|
40
|
+
* Pure function - no side effects
|
|
41
|
+
*
|
|
42
|
+
* @param scrollTop - Current scroll position
|
|
43
|
+
* @param containerHeight - Viewport container height
|
|
44
|
+
* @param heightCache - Height cache for item heights/offsets
|
|
45
|
+
* @param totalItems - Total number of items
|
|
46
|
+
* @param compression - Compression state
|
|
47
|
+
* @param out - Output range to mutate (avoids allocation on hot path)
|
|
48
|
+
*/
|
|
49
|
+
export declare const calculateCompressedVisibleRange: (scrollTop: number, containerHeight: number, heightCache: HeightCache, totalItems: number, compression: CompressionState, out: Range) => Range;
|
|
50
|
+
/**
|
|
51
|
+
* Calculate render range with compression support (adds overscan)
|
|
52
|
+
* Pure function - no side effects
|
|
53
|
+
*
|
|
54
|
+
* @param out - Output range to mutate (avoids allocation on hot path)
|
|
55
|
+
*/
|
|
56
|
+
export declare const calculateCompressedRenderRange: (visibleRange: Range, overscan: number, totalItems: number, out: Range) => Range;
|
|
57
|
+
/**
|
|
58
|
+
* Calculate item position (translateY) with compression support
|
|
59
|
+
* Pure function - no side effects
|
|
60
|
+
*
|
|
61
|
+
* In compressed mode (manual wheel scrolling, overflow: hidden), items are
|
|
62
|
+
* positioned RELATIVE TO THE VIEWPORT. The scroll container doesn't actually
|
|
63
|
+
* scroll - we intercept wheel events and manually position items.
|
|
64
|
+
*
|
|
65
|
+
* Key insight:
|
|
66
|
+
* - Calculate a "virtual scroll index" from the scroll ratio
|
|
67
|
+
* - Items are positioned relative to this virtual index using actual heights
|
|
68
|
+
* - Each item keeps its full height for proper rendering
|
|
69
|
+
*
|
|
70
|
+
* @param index - Item index
|
|
71
|
+
* @param scrollTop - Current (virtual) scroll position
|
|
72
|
+
* @param heightCache - Height cache for item heights/offsets
|
|
73
|
+
* @param totalItems - Total number of items
|
|
74
|
+
* @param containerHeight - Viewport container height
|
|
75
|
+
* @param compression - Compression state
|
|
76
|
+
* @param _rangeStart - (unused, kept for API compatibility)
|
|
77
|
+
*/
|
|
78
|
+
export declare const calculateCompressedItemPosition: (index: number, scrollTop: number, heightCache: HeightCache, totalItems: number, containerHeight: number, compression: CompressionState, _rangeStart?: number) => number;
|
|
79
|
+
/**
|
|
80
|
+
* Calculate scroll position to bring an index into view (with compression)
|
|
81
|
+
* Pure function - no side effects
|
|
82
|
+
*
|
|
83
|
+
* @param index - Target item index
|
|
84
|
+
* @param heightCache - Height cache for item heights/offsets
|
|
85
|
+
* @param containerHeight - Viewport container height
|
|
86
|
+
* @param totalItems - Total number of items
|
|
87
|
+
* @param compression - Compression state
|
|
88
|
+
* @param align - Alignment within viewport
|
|
89
|
+
*/
|
|
90
|
+
export declare const calculateCompressedScrollToIndex: (index: number, heightCache: HeightCache, containerHeight: number, totalItems: number, compression: CompressionState, align?: "start" | "center" | "end") => number;
|
|
91
|
+
/**
|
|
92
|
+
* Calculate the approximate item index at a given scroll position
|
|
93
|
+
* Useful for debugging and scroll position restoration
|
|
94
|
+
* Pure function - no side effects
|
|
95
|
+
*/
|
|
96
|
+
export declare const calculateIndexFromScrollPosition: (scrollTop: number, heightCache: HeightCache, totalItems: number, compression: CompressionState) => number;
|
|
97
|
+
/**
|
|
98
|
+
* Check if compression is needed for a list configuration
|
|
99
|
+
* Pure function - no side effects
|
|
100
|
+
*
|
|
101
|
+
* Note: This overload accepts a HeightCache for variable heights.
|
|
102
|
+
* For simple fixed-height checks, use needsCompressionFixed().
|
|
103
|
+
*/
|
|
104
|
+
export declare const needsCompression: (totalItems: number, heightOrCache: number | HeightCache) => boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Calculate maximum items supported without compression
|
|
107
|
+
* Only meaningful for fixed-height items
|
|
108
|
+
* Pure function - no side effects
|
|
109
|
+
*/
|
|
110
|
+
export declare const getMaxItemsWithoutCompression: (itemHeight: number) => number;
|
|
111
|
+
/**
|
|
112
|
+
* Get human-readable compression info for debugging
|
|
113
|
+
* Pure function - no side effects
|
|
114
|
+
*/
|
|
115
|
+
export declare const getCompressionInfo: (totalItems: number, heightCache: HeightCache) => string;
|
|
116
|
+
//# sourceMappingURL=scale.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scale.d.ts","sourceRoot":"","sources":["../../src/rendering/scale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAQ7C,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAM9B,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,YAAY,EAAE,OAAO,CAAC;IAEtB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IAErB,wDAAwD;IACxD,aAAa,EAAE,MAAM,CAAC;IAEtB,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC9B,aAAa,MAAM,EACnB,aAAa,WAAW,KACvB,gBAYF,CAAC;AAMF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,+BAA+B,GAC1C,WAAW,MAAM,EACjB,iBAAiB,MAAM,EACvB,aAAa,WAAW,EACxB,YAAY,MAAM,EAClB,aAAa,gBAAgB,EAC7B,KAAK,KAAK,KACT,KAmEF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,GACzC,cAAc,KAAK,EACnB,UAAU,MAAM,EAChB,YAAY,MAAM,EAClB,KAAK,KAAK,KACT,KAUF,CAAC;AAMF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,+BAA+B,GAC1C,OAAO,MAAM,EACb,WAAW,MAAM,EACjB,aAAa,WAAW,EACxB,YAAY,MAAM,EAClB,iBAAiB,MAAM,EACvB,aAAa,gBAAgB,EAC7B,cAAc,MAAM,KACnB,MAyDF,CAAC;AAMF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gCAAgC,GAC3C,OAAO,MAAM,EACb,aAAa,WAAW,EACxB,iBAAiB,MAAM,EACvB,YAAY,MAAM,EAClB,aAAa,gBAAgB,EAC7B,QAAO,OAAO,GAAG,QAAQ,GAAG,KAAe,KAC1C,MAmCF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gCAAgC,GAC3C,WAAW,MAAM,EACjB,aAAa,WAAW,EACxB,YAAY,MAAM,EAClB,aAAa,gBAAgB,KAC5B,MASF,CAAC;AAMF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,YAAY,MAAM,EAClB,eAAe,MAAM,GAAG,WAAW,KAClC,OAKF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,GAAI,YAAY,MAAM,KAAG,MAGlE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,YAAY,MAAM,EAClB,aAAa,WAAW,KACvB,MASF,CAAC"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist - Virtual Scrolling Core
|
|
3
|
+
* Pure functions for virtual scroll calculations
|
|
4
|
+
*
|
|
5
|
+
* Compression support is NOT imported here — it's injected via
|
|
6
|
+
* CompressionState parameters. When compression is inactive
|
|
7
|
+
* (the common case), all calculations use simple height-cache math
|
|
8
|
+
* with zero dependency on the compression module.
|
|
9
|
+
*
|
|
10
|
+
* This keeps the builder core lightweight. The withCompression plugin
|
|
11
|
+
* and the monolithic createVList entry point import compression
|
|
12
|
+
* separately and pass the state in.
|
|
13
|
+
*/
|
|
14
|
+
import type { Range, ViewportState } from "../types";
|
|
15
|
+
import type { HeightCache } from "./heights";
|
|
16
|
+
/** Compression calculation result */
|
|
17
|
+
export interface CompressionState {
|
|
18
|
+
/** Whether compression is active */
|
|
19
|
+
isCompressed: boolean;
|
|
20
|
+
/** The actual total height */
|
|
21
|
+
actualHeight: number;
|
|
22
|
+
/** The virtual height (capped at MAX_VIRTUAL_HEIGHT) */
|
|
23
|
+
virtualHeight: number;
|
|
24
|
+
/** Compression ratio (1 = no compression, <1 = compressed) */
|
|
25
|
+
ratio: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A "no compression" state for lists that don't need it.
|
|
29
|
+
* Used by the builder core when withCompression is not installed.
|
|
30
|
+
*/
|
|
31
|
+
export declare const NO_COMPRESSION: CompressionState;
|
|
32
|
+
/**
|
|
33
|
+
* Create a trivial compression state from a height cache.
|
|
34
|
+
* No compression logic — just reads the total height.
|
|
35
|
+
* For use when the full compression module is not loaded.
|
|
36
|
+
*/
|
|
37
|
+
export declare const getSimpleCompressionState: (_totalItems: number, heightCache: HeightCache) => CompressionState;
|
|
38
|
+
/**
|
|
39
|
+
* Signature for the function that calculates the visible item range.
|
|
40
|
+
* The compression module provides a version that handles compressed scroll;
|
|
41
|
+
* virtual.ts provides a simple fallback for non-compressed lists.
|
|
42
|
+
*/
|
|
43
|
+
export type VisibleRangeFn = (scrollTop: number, containerHeight: number, heightCache: HeightCache, totalItems: number, compression: CompressionState, out: Range) => Range;
|
|
44
|
+
/**
|
|
45
|
+
* Signature for the scroll-to-index calculator.
|
|
46
|
+
*/
|
|
47
|
+
export type ScrollToIndexFn = (index: number, heightCache: HeightCache, containerHeight: number, totalItems: number, compression: CompressionState, align: "start" | "center" | "end") => number;
|
|
48
|
+
/**
|
|
49
|
+
* Calculate visible range using height cache lookups.
|
|
50
|
+
* Fast path for lists that don't need compression (< ~350 000 items at 48px).
|
|
51
|
+
* Mutates `out` to avoid allocation on the scroll hot path.
|
|
52
|
+
*/
|
|
53
|
+
export declare const simpleVisibleRange: VisibleRangeFn;
|
|
54
|
+
/**
|
|
55
|
+
* Calculate render range (adds overscan around visible range).
|
|
56
|
+
* This function is compression-agnostic — works for both paths.
|
|
57
|
+
* Mutates `out` to avoid allocation on the scroll hot path.
|
|
58
|
+
*/
|
|
59
|
+
export declare const calculateRenderRange: (visibleRange: Range, overscan: number, totalItems: number, out: Range) => Range;
|
|
60
|
+
/**
|
|
61
|
+
* Simple scroll-to-index calculation (non-compressed).
|
|
62
|
+
* Uses height cache offsets directly.
|
|
63
|
+
*/
|
|
64
|
+
export declare const simpleScrollToIndex: ScrollToIndexFn;
|
|
65
|
+
/**
|
|
66
|
+
* Calculate total content height.
|
|
67
|
+
* Uses compression's virtualHeight when compressed, raw height otherwise.
|
|
68
|
+
*/
|
|
69
|
+
export declare const calculateTotalHeight: (_totalItems: number, heightCache: HeightCache, compression?: CompressionState | null) => number;
|
|
70
|
+
/**
|
|
71
|
+
* Calculate actual total height (without compression cap)
|
|
72
|
+
*/
|
|
73
|
+
export declare const calculateActualHeight: (_totalItems: number, heightCache: HeightCache) => number;
|
|
74
|
+
/**
|
|
75
|
+
* Calculate the offset (translateY) for an item
|
|
76
|
+
* For non-compressed lists only
|
|
77
|
+
*/
|
|
78
|
+
export declare const calculateItemOffset: (index: number, heightCache: HeightCache) => number;
|
|
79
|
+
/**
|
|
80
|
+
* Clamp scroll position to valid range
|
|
81
|
+
*/
|
|
82
|
+
export declare const clampScrollPosition: (scrollTop: number, totalHeight: number, containerHeight: number) => number;
|
|
83
|
+
/**
|
|
84
|
+
* Determine scroll direction
|
|
85
|
+
*/
|
|
86
|
+
export declare const getScrollDirection: (currentScrollTop: number, previousScrollTop: number) => "up" | "down";
|
|
87
|
+
/**
|
|
88
|
+
* Create initial viewport state.
|
|
89
|
+
*
|
|
90
|
+
* Accepts an optional `visibleRangeFn` so that compression-aware callers
|
|
91
|
+
* can inject the compressed version. Defaults to `simpleVisibleRange`.
|
|
92
|
+
*/
|
|
93
|
+
export declare const createViewportState: (containerHeight: number, heightCache: HeightCache, totalItems: number, overscan: number, compression: CompressionState, visibleRangeFn?: VisibleRangeFn) => ViewportState;
|
|
94
|
+
/**
|
|
95
|
+
* Update viewport state after scroll.
|
|
96
|
+
* Mutates state in place for performance on the scroll hot path.
|
|
97
|
+
*/
|
|
98
|
+
export declare const updateViewportState: (state: ViewportState, scrollTop: number, heightCache: HeightCache, totalItems: number, overscan: number, compression: CompressionState, visibleRangeFn?: VisibleRangeFn) => ViewportState;
|
|
99
|
+
/**
|
|
100
|
+
* Update viewport state when container resizes.
|
|
101
|
+
* Mutates state in place for performance.
|
|
102
|
+
*/
|
|
103
|
+
export declare const updateViewportSize: (state: ViewportState, containerHeight: number, heightCache: HeightCache, totalItems: number, overscan: number, compression: CompressionState, visibleRangeFn?: VisibleRangeFn) => ViewportState;
|
|
104
|
+
/**
|
|
105
|
+
* Update viewport state when total items changes.
|
|
106
|
+
* Mutates state in place for performance.
|
|
107
|
+
*/
|
|
108
|
+
export declare const updateViewportItems: (state: ViewportState, heightCache: HeightCache, totalItems: number, overscan: number, compression: CompressionState, visibleRangeFn?: VisibleRangeFn) => ViewportState;
|
|
109
|
+
/**
|
|
110
|
+
* Calculate scroll position to bring an index into view.
|
|
111
|
+
*
|
|
112
|
+
* Accepts an optional `scrollToIndexFn` so that compression-aware callers
|
|
113
|
+
* can inject the compressed version. Defaults to `simpleScrollToIndex`.
|
|
114
|
+
*/
|
|
115
|
+
export declare const calculateScrollToIndex: (index: number, heightCache: HeightCache, containerHeight: number, totalItems: number, align: "start" | "center" | "end" | undefined, compression: CompressionState, scrollToIndexFn?: ScrollToIndexFn) => number;
|
|
116
|
+
/**
|
|
117
|
+
* Check if two ranges are equal
|
|
118
|
+
*/
|
|
119
|
+
export declare const rangesEqual: (a: Range, b: Range) => boolean;
|
|
120
|
+
/**
|
|
121
|
+
* Check if an index is within a range
|
|
122
|
+
*/
|
|
123
|
+
export declare const isInRange: (index: number, range: Range) => boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Get the count of items in a range
|
|
126
|
+
*/
|
|
127
|
+
export declare const getRangeCount: (range: Range) => number;
|
|
128
|
+
/**
|
|
129
|
+
* Create an array of indices from a range
|
|
130
|
+
*/
|
|
131
|
+
export declare const rangeToIndices: (range: Range) => number[];
|
|
132
|
+
/**
|
|
133
|
+
* Calculate which indices need to be added/removed when range changes
|
|
134
|
+
*/
|
|
135
|
+
export declare const diffRanges: (oldRange: Range, newRange: Range) => {
|
|
136
|
+
add: number[];
|
|
137
|
+
remove: number[];
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=viewport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewport.d.ts","sourceRoot":"","sources":["../../src/rendering/viewport.ts"],"names":[],"mappings":"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"}
|