virtua
Version:
A zero-config, fast and small (~3kB) virtual list (and grid) component for React, Vue, Solid and Svelte.
3 lines (2 loc) • 9.65 kB
JavaScript
const e=null,{min:t,max:o,abs:r,floor:s}=Math,n=(e,r,s)=>t(s,o(r,e)),c=e=>[...e].sort(((e,t)=>e-t)),i="function"==typeof queueMicrotask?queueMicrotask:e=>{Promise.resolve().then(e)},l=e=>{let t;return()=>(e&&(t=e(),e=void 0),t)},f=-1,a=(e,t,o)=>{const r=o?"unshift":"push";for(let o=0;o<t;o++)e[r](f);return e},u=(e,t)=>{const o=e.t[t];return o===f?e.o:o},p=(e,o,r)=>{const s=e.t[o]===f;return e.t[o]=r,e.i=t(o,e.i),s},d=(e,t)=>{if(!e.l)return 0;if(e.i>=t)return e.u[t];e.i<0&&(e.u[0]=0,e.i=0);let o=e.i,r=e.u[o];for(;o<t;)r+=u(e,o),e.u[++o]=r;return e.i=t,r},$=(e,t,o=0,r=e.l-1)=>{for(;o<=r;){const n=s((o+r)/2),c=d(e,n);if(c<=t){if(c+u(e,n)>t)return n;o=n+1}else r=n-1}return n(o,0,e.l-1)},h=(e,o,r)=>{const s=o-e.l;return e.i=r?-1:t(o-1,e.i),e.l=o,s>0?(a(e.u,s),a(e.t,s,r),e.o*s):(e.u.splice(s),(r?e.t.splice(0,-s):e.t.splice(s)).reduce(((t,o)=>t-(o===f?e.o:o)),0))},m="undefined"!=typeof window,w=()=>document.documentElement,x=e=>e.ownerDocument,g=e=>e.defaultView,v=/*#__PURE__*/l((()=>!!m&&"rtl"===getComputedStyle(w()).direction)),b=/*#__PURE__*/l((()=>/iP(hone|od|ad)/.test(navigator.userAgent))),S=/*#__PURE__*/l((()=>"scrollBehavior"in w().style)),I=e=>!!e.$getViewportSize(),y=setTimeout,k=(e,t)=>t&&v()?-e:e,_=(t,o,r,s,n,c)=>{const i=Date.now;let l=0,f=!1,a=!1,u=!1,p=!1;const d=(()=>{let o;const r=()=>{o!=e&&clearTimeout(o)},s=()=>{r(),o=y((()=>{o=e,(()=>{if(f||a)return f=!1,void d();u=!1,t.$update(2)})()}),150)};return s.p=r,s})(),$=()=>{l=i(),u&&(p=!0),c&&t.$update(6,c()),t.$update(1,s()),d()},h=e=>{if(f||!t.$isScrolling()||e.ctrlKey)return;const o=i()-l;150>o&&50<o&&(r?e.deltaX:e.deltaY)&&(f=!0)},m=()=>{a=!0,u=p=!1},w=()=>{a=!1,b()&&(u=!0)};return o.addEventListener("scroll",$),o.addEventListener("wheel",h,{passive:!0}),o.addEventListener("touchstart",m,{passive:!0}),o.addEventListener("touchend",w,{passive:!0}),{$:()=>{o.removeEventListener("scroll",$),o.removeEventListener("wheel",h),o.removeEventListener("touchstart",m),o.removeEventListener("touchend",w),d.p()},h:()=>{const[e,o]=t.m();e&&(n(k(e,r),o,p),p=!1,o&&t.$getViewportSize()>t.$getTotalSize()&&t.$update(1,s()))}}},z=(e,t)=>{let o,r,s;const c=t?"scrollLeft":"scrollTop",l=t?"overflowX":"overflowY",f=async(r,n)=>{if(!o)return void i((()=>f(r,n)));s&&s();const l=()=>{let t;return[new Promise(((o,r)=>{t=o,s=r,I(e)&&y(r,150)})),e.$subscribe(2,(()=>{t&&t()}))]};if(n&&S()){for(;e.$update(8,r()),e.v();){const[e,t]=l();try{await e}catch(e){return}finally{t()}}o.scrollTo({[t?"left":"top"]:k(r(),t),behavior:"smooth"})}else for(;;){const[s,n]=l();try{o[c]=k(r(),t),e.$update(7),await s}catch(e){return}finally{n()}}};return{$observe(n){o=n,r=_(e,n,t,(()=>k(n[c],t)),((t,o,r)=>{if(r){const e=n.style,t=e[l];e[l]="hidden",y((()=>{e[l]=t}))}o?(n[c]=e.$getScrollOffset()+t,s&&s()):n[c]+=t}))},$dispose(){r&&r.$()},$scrollTo(e){f((()=>e))},$scrollBy(t){t+=e.$getScrollOffset(),f((()=>t))},$scrollToIndex(t,{align:o,smooth:r,offset:s=0}={}){if(t=n(t,0,e.$getItemsLength()-1),"nearest"===o){const r=e.$getItemOffset(t),s=e.$getScrollOffset();if(r<s)o="start";else{if(!(r+e.$getItemSize(t)>s+e.$getViewportSize()))return;o="end"}}f((()=>s+e.$getStartSpacerSize()+e.$getItemOffset(t)+("end"===o?e.$getItemSize(t)-e.$getViewportSize():"center"===o?(e.$getItemSize(t)-e.$getViewportSize())/2:0)),r)},$fixScrollJump:()=>{r&&r.h()}}},T=e=>{let t;return{S(o){(t||(t=new(g(x(o)).ResizeObserver)(e))).observe(o)},I(e){t.unobserve(e)},$(){t&&t.disconnect()}}};exports.ACTION_ITEMS_LENGTH_CHANGE=5,exports.ACTION_START_OFFSET_CHANGE=6,exports.UPDATE_SCROLL_END_EVENT=8,exports.UPDATE_SCROLL_EVENT=4,exports.UPDATE_VIRTUAL_STATE=1,exports.createGridResizer=(e,t)=>{let r;const s="height",n="width",c=new WeakMap,i=new Set,l=new Set,f=new Map,a=(e,t)=>`${e}-${t}`,u=T((u=>{const p=new Set,d=new Set;for(const{target:o,contentRect:i}of u)if(o.offsetParent)if(o===r)e.$update(4,i[s]),t.$update(4,i[n]);else{const e=c.get(o);if(e){const[t,o]=e,r=a(t,o),c=f.get(r),l=[i[s],i[n]];let u,$;c?(c[0]!==l[0]&&(u=!0),c[1]!==l[1]&&($=!0)):u=$=!0,u&&p.add(t),$&&d.add(o),(u||$)&&f.set(r,l)}}if(p.size){const t=[];p.forEach((e=>{let r=0;l.forEach((t=>{const s=f.get(a(e,t));s&&(r=o(r,s[0]))})),r&&t.push([e,r])})),e.$update(3,t)}if(d.size){const e=[];d.forEach((t=>{let r=0;i.forEach((e=>{const s=f.get(a(e,t));s&&(r=o(r,s[1]))})),r&&e.push([t,r])})),t.$update(3,e)}}));return{$observeRoot(e){u.S(r=e)},$observeItem:(e,t,o)=>(c.set(e,[t,o]),i.add(t),l.add(o),u.S(e),()=>{c.delete(e),u.I(e)}),$resizeCols(o){for(const[t]of o)for(let o=0;o<e.$getItemsLength();o++)f.delete(a(o,t));t.$update(3,o)},$resizeRows(o){for(const[e]of o)for(let o=0;o<t.$getItemsLength();o++)f.delete(a(e,o));e.$update(3,o)},$dispose:u.$}},exports.createGridScroller=(e,t)=>{const o=z(e,!1),r=z(t,!0);return{$observe(e){o.$observe(e),r.$observe(e)},$dispose(){o.$dispose(),r.$dispose()},$scrollTo(e,t){o.$scrollTo(t),r.$scrollTo(e)},$scrollBy(e,t){o.$scrollBy(t),r.$scrollBy(e)},$scrollToIndex(e,t){o.$scrollToIndex(t),r.$scrollToIndex(e)},$fixScrollJump(){o.$fixScrollJump(),r.$fixScrollJump()}}},exports.createResizer=(t,o)=>{let r;const s=o?"width":"height",n=new WeakMap,c=T((o=>{const c=[];for(const{target:i,contentRect:l}of o)if(i.offsetParent)if(i===r)t.$update(4,l[s]);else{const t=n.get(i);t!=e&&c.push([t,l[s]])}c.length&&t.$update(3,c)}));return{$observeRoot(e){c.S(r=e)},$observeItem:(e,t)=>(n.set(e,t),c.S(e),()=>{n.delete(e),c.I(e)}),$dispose:c.$}},exports.createScroller=z,exports.createVirtualStore=(s,n=40,i=4,l=0,m,w=!1)=>{let x=!!l,g=1,v=0,S=0,I=0,y=0,k=0,_=0,z=0,T=0,R=x?[0,o(l-1,0)]:e,M=[0,0],J=0;const P=((e,r,s)=>({o:s?s[1]:r,t:s&&s[0]?a(s[0].slice(0,t(e,s[0].length)),o(0,e-s[0].length)):a([],e),l:e,i:-1,u:a([],e)}))(s,n,m),W=new Set,B=()=>I-S,C=()=>B()+k+y,L=e=>((e,o,r,s)=>{if(s=t(s,e.l-1),d(e,s)<=o){const t=$(e,o+r,s);return[$(e,o,s,t),t]}{const t=$(e,o,void 0,s);return[t,$(e,o+r,t)]}})(P,e,v,M[0]),O=()=>(e=>e.l?d(e,e.l-1)+u(e,e.l-1):0)(P),q=e=>d(P,e)-k,U=e=>u(P,e),V=e=>{e&&(b()&&0!==z?k+=e:y+=e)};return{$getStateVersion:()=>g,$getCacheSnapshot:()=>(e=>[e.t.slice(),e.o])(P),$getRange:()=>{let e,r;return _?[e,r]=M:([e,r]=M=L(o(0,C())),R&&(e=t(e,R[0]),r=o(r,R[1]))),1!==z&&(e-=o(0,i)),2!==z&&(r+=o(0,i)),[o(e,0),t(r,P.l-1)]},$findStartIndex:()=>$(P,C()),$findEndIndex:()=>$(P,C()+v),$isUnmeasuredItem:e=>P.t[e]===f,v:()=>!!R&&P.t.slice(o(0,R[0]-1),t(P.l-1,R[1]+1)+1).includes(f),$getItemOffset:q,$getItemSize:U,$getItemsLength:()=>P.l,$getScrollOffset:()=>I,$isScrolling:()=>0!==z,$getViewportSize:()=>v,$getStartSpacerSize:()=>S,$getTotalSize:O,m:()=>(_=y,y=0,[_,2===T||B()+v>=O()]),$subscribe:(e,t)=>{const o=[e,t];return W.add(o),()=>{W.delete(o)}},$update:(t,s)=>{let n,i,l=0;switch(t){case 1:{const t=_;_=0;const o=s-I,n=r(o);t&&n<r(t)+1||0!==T||(z=o<0?2:1),x&&(R=e,x=!1),I=s,l=4;const c=B();c>=-v&&c<=O()&&(l+=1,i=n>v);break}case 2:l=8,0!==z&&(n=!0,l+=1),z=0,T=0,R=e;break;case 3:{const e=s.filter((([e,t])=>P.t[e]!==t));if(!e.length)break;V(e.reduce(((e,[t,o])=>((2===T||(R?!x&&t<R[0]:q(t)+(0===z&&0===T?U(t):0)<B()))&&(e+=o-U(t)),e)),0));for(const[t,o]of e){const e=U(t),r=p(P,t,o);w&&(J+=r?o:o-e)}w&&v&&J>v&&(V(((e,t)=>{let r=0;const s=[];e.t.forEach(((e,o)=>{e!==f&&(s.push(e),o<t&&r++)})),e.i=-1;const n=c(s),i=n.length,l=i/2|0,a=i%2==0?(n[l-1]+n[l])/2:n[l],u=e.o;return((e.o=a)-u)*o(t-r,0)})(P,$(P,C()))),w=!1),l=3,i=!0;break}case 4:v!==s&&(v=s,l=3);break;case 5:s[1]?(V(h(P,s[0],!0)),T=2,l=1):(h(P,s[0]),l=1);break;case 6:S=s;break;case 7:T=1;break;case 8:R=L(s),l=1}l&&(g=1+(2147483647&g),n&&k&&(y+=k,k=0),W.forEach((([e,t])=>{l&e&&t(i)})))}}},exports.createWindowResizer=(t,o)=>{const r=o?"width":"height",s=o?"innerWidth":"innerHeight",n=new WeakMap,c=T((o=>{const s=[];for(const{target:t,contentRect:c}of o){if(!t.offsetParent)continue;const o=n.get(t);o!=e&&s.push([o,c[r]])}s.length&&t.$update(3,s)}));let i;return{$observeRoot(e){const o=g(x(e)),r=()=>{t.$update(4,o[s])};o.addEventListener("resize",r),r(),i=()=>{o.removeEventListener("resize",r)}},$observeItem:(e,t)=>(n.set(e,t),c.S(e),()=>{n.delete(e),c.I(e)}),$dispose(){i&&i(),c.$()}}},exports.createWindowScroller=(e,t)=>{let o,r,s;const c=(e,t,o,r,s=0)=>{const n=r?"offsetLeft":"offsetTop",i=s+(r&&v()?o.innerWidth-e[n]-e.offsetWidth:e[n]),l=e.offsetParent;return e!==t&&l?c(l,t,o,r,i):i},l=async(r,n)=>{if(!o)return void i((()=>l(r,n)));s&&s();const c=()=>{let t;return[new Promise(((o,r)=>{t=o,s=r,I(e)&&y(r,150)})),e.$subscribe(2,(()=>{t&&t()}))]},f=g(x(o));if(n&&S()){for(;e.$update(8,r()),e.v();){const[e,t]=c();try{await e}catch(e){return}finally{t()}}f.scroll({[t?"left":"top"]:k(r(),t),behavior:"smooth"})}else for(;;){const[o,s]=c();try{f.scroll({[t?"left":"top"]:k(r(),t)}),e.$update(7),await o}catch(e){return}finally{s()}}};return{$observe(s){o=s;const n=t?"scrollX":"scrollY",i=x(s),l=g(i),f=i.body;r=_(e,l,t,(()=>k(l[n],t)),((o,r)=>{r?l.scroll({[t?"left":"top"]:e.$getScrollOffset()+o}):l.scrollBy(t?o:0,t?0:o)}),(()=>c(s,f,l,t)))},$dispose(){r&&r.$(),o=void 0},$fixScrollJump:()=>{r&&r.h()},$scrollToIndex(r,{align:s,smooth:i,offset:f=0}={}){if(!o)return;if(r=n(r,0,e.$getItemsLength()-1),"nearest"===s){const t=e.$getItemOffset(r),o=e.$getScrollOffset();if(t<o)s="start";else{if(!(t+e.$getItemSize(r)>o+e.$getViewportSize()))return;s="end"}}const a=x(o),u=g(a),p=a.documentElement,d=()=>e.$getViewportSize()-(t?p.clientWidth:p.clientHeight);l((()=>f+c(o,a.body,u,t)+e.$getItemOffset(r)+("end"===s?e.$getItemSize(r)-(e.$getViewportSize()-d()):"center"===s?(e.$getItemSize(r)-(e.$getViewportSize()-d()))/2:0)),i)}}},exports.getScrollSize=e=>o(e.$getTotalSize(),e.$getViewportSize()),exports.isBrowser=m,exports.isRTLDocument=v,exports.microtask=i,exports.sort=c;
//# sourceMappingURL=index.js.map