virtua 0.1.12 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  A zero-config, fast and small (3kB) virtual list component for [React](https://github.com/facebook/react).
6
6
 
7
+ If you want to check the difference with the alternatives right away, [see comparison section](#comparison).
8
+
7
9
  ## Motivation
8
10
 
9
11
  This project is a challenge to rethink virtualization. The goals are...
@@ -12,7 +14,7 @@ This project is a challenge to rethink virtualization. The goals are...
12
14
  - **Fast:** Scrolling without frame drop needs optimization in many aspects (reduce CPU usage, reduce GC, [reduce layout recalculation](https://gist.github.com/paulirish/5d52fb081b3570c81e3a), optimize for frameworks, etc). We are trying to combine the best of them.
13
15
  - **Small:** Its bundle size should be small as much as possible to be friendly with modern web development. Currently [about 3kB gzipped](https://bundlephobia.com/package/virtua).
14
16
  - **Flexible:** Aiming to support many usecases - fixed size, dynamic size, horizontal scrolling, reverse scrolling, rtl direction, sticky, infinite scrolling, placeholder, scrollTo, dnd, table, and more. See [live demo](#demo).
15
- - **Framework agnostic (WIP):** Currently only for React but we could support Vue, Svelte, Solid and more in the future.
17
+ - **Framework agnostic (WIP):** Currently only for React but we could support Vue, Svelte, Solid, Web Components and more in the future.
16
18
 
17
19
  ## Demo
18
20
 
@@ -33,16 +35,16 @@ If you use ESM and webpack 5, use react >= 18 to avoid [Can't resolve `react/jsx
33
35
  ## Usage
34
36
 
35
37
  ```tsx
36
- import { List } from "virtua";
38
+ import { VList } from "virtua";
37
39
 
38
40
  export const App = () => {
39
41
  return (
40
- <List style={{ height: 800 }}>
42
+ <VList style={{ height: 800 }}>
41
43
  {Array.from({ length: 1000 }).map((_, i) => (
42
44
  <div
43
45
  key={i}
44
46
  style={{
45
- height: Math.floor(Math.random() * 10) * 10 + 5,
47
+ height: Math.floor(Math.random() * 10) * 10 + 10,
46
48
  borderBottom: "solid 1px gray",
47
49
  background: "white",
48
50
  }}
@@ -50,7 +52,7 @@ export const App = () => {
50
52
  {i}
51
53
  </div>
52
54
  ))}
53
- </List>
55
+ </VList>
54
56
  );
55
57
  };
56
58
  ```
@@ -61,6 +63,33 @@ And see [examples](./stories) for more usages.
61
63
 
62
64
  - [API reference](./docs/API.md)
63
65
 
66
+ ## Comparison
67
+
68
+ ### Benchmarks
69
+
70
+ WIP
71
+
72
+ ### Features
73
+
74
+ | | [virtua](https://github.com/inokawa/virtua) | [react-virtuoso](https://github.com/petyosi/react-virtuoso) | [react-virtualized](https://github.com/bvaughn/react-virtualized) | [react-window](https://github.com/bvaughn/react-window) | [@tanstack/react-virtual](https://github.com/TanStack/virtual) | [react-cool-virtual](https://github.com/wellyshen/react-cool-virtual) |
75
+ | :------------------------------------------------- | :------------------------------------------------------- | :---------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------ | :-------------------------------------------------------------------- |
76
+ | Bundle size | [3.1kB gzipped](https://bundlephobia.com/package/virtua) | [16.3kB gzipped](https://bundlephobia.com/package/react-virtuoso) | [27.3kB gzipped](https://bundlephobia.com/package/react-virtualized) | [6.4kB gzipped](https://bundlephobia.com/package/react-window) | [2.3kB gzipped](https://bundlephobia.com/package/@tanstack/react-virtual) | [3.1kB gzipped](https://bundlephobia.com/package/react-cool-virtual) |
77
+ | Vertical scroll | ✅ | ✅ | ✅ | ✅ | 🟠 (needs customization) | 🟠 (needs customization) |
78
+ | Horizontal scroll | ✅ | ✅ | ✅ | ✅ | 🟠 (needs customization) | 🟠 (needs customization) |
79
+ | Grid | ❌ | ✅ | ✅ | ✅ | 🟠 (needs customization) | 🟠 (needs customization) |
80
+ | Table | 🟠 (needs customization) | ✅ | ✅ | 🟠 (needs customization) | 🟠 (needs customization) | 🟠 (needs customization) |
81
+ | Window scroller | ❌ | ✅ | ✅ ([WindowScroller](https://github.com/bvaughn/react-virtualized/blob/master/docs/WindowScroller.md)) | ❌ | ✅ | ❌ |
82
+ | Dynamic list size | ✅ | ✅ | 🟠 (needs [AutoSizer](https://github.com/bvaughn/react-virtualized/blob/master/docs/AutoSizer.md)) | 🟠 (needs [AutoSizer](https://github.com/bvaughn/react-virtualized/blob/master/docs/AutoSizer.md)) | ✅ | ✅ |
83
+ | Dynamic item size | ✅ | ✅ | 🟠 (needs [CellMeasurer](https://github.com/bvaughn/react-virtualized/blob/master/docs/CellMeasurer.md) and has wrong destination when scrolling to item imperatively) | 🟠 (needs additional codes and has wrong destination when scrolling to item imperatively) | 🟠 (has wrong destination when scrolling to item imperatively) | 🟠 (has wrong destination when scrolling to item imperatively) |
84
+ | Reverse scroll | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
85
+ | Infinite scroll | ✅ | ✅ | 🟠 (needs [InfiniteLoader](https://github.com/bvaughn/react-virtualized/blob/master/docs/InfiniteLoader.md)) | 🟠 (needs [react-window-infinite-loader](https://github.com/bvaughn/react-window-infinite-loader)) | ✅ | ✅ |
86
+ | RTL | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ |
87
+ | Display exceeding browser's max element size limit | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
88
+
89
+ - ✅ - Built-in supported
90
+ - 🟠 - Supported but partial, limited or requires some user custom code
91
+ - ❌ - Not officially supported
92
+
64
93
  ## Contribute
65
94
 
66
95
  All contributions are welcome.
@@ -7,7 +7,8 @@ export type Scroller = {
7
7
  _initRoot: (rootElement: HTMLElement) => () => void;
8
8
  _initItem: (itemElement: HTMLElement, index: number) => () => void;
9
9
  _getActualScrollSize: () => number;
10
- _scrollTo: (index: number, getCurrentOffset: () => number) => void;
10
+ _scrollTo: (offset: number) => void;
11
+ _scrollToIndex: (index: number, count: number) => void;
11
12
  _fixScrollJump: (jump: ScrollJump, startIndex: number) => void;
12
13
  };
13
14
  export declare const createScroller: (store: VirtualStore, emitScrollOffsetChange: (offset: number) => void, emitScrollStateChange: (scrolling: boolean) => void) => Scroller;
package/lib/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { List } from "./react/List";
2
- export type { ListProps, ListHandle, CustomItemComponent, CustomItemComponentProps, CustomWindowComponent, CustomWindowComponentProps, } from "./react/List";
1
+ export { VList } from "./react/VList";
2
+ export type { VListProps, VListHandle, CustomItemComponent, CustomItemComponentProps, CustomWindowComponent, CustomWindowComponentProps, WindowComponentAttributes, } from "./react/VList";
package/lib/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var e=require("react/jsx-runtime"),t=require("react"),r=require("use-sync-external-store/shim/index.js");const n=Math.min,o=Math.max,l=Math.abs,s=Date.now,i=e=>null!=e,c=(e,t)=>Array.from({length:e},((e,r)=>t(r))),u=(e,t)=>{const r=e.t[t];return-1===r?e.o:r},a=(e,t,r)=>{if(!e.l)return 0;if(e.i>=t)return r?e.u[t]+u(e,t):e.u[t];let n=e.i,o=e.u[n];for(;n<=t&&(e.u[n]=o,n!==t||r);)o+=u(e,n),n++;return e.i=t,o},f=(e,t)=>a(e,t),d=(e,t,r)=>{let l=0;if(r>=0)for(;t<e.l-1;){const n=u(e,t++);if((l+=n)>=r){l-n/2>=r&&t--;break}}else for(;t>0;){const n=u(e,--t);if((l-=n)<=r){l+n/2<r&&t++;break}}return n(o(t,0),e.l-1)},_=(e,t,r,n)=>d(e,r,t-n),h=d,m=(e,t,r)=>({o:t,l:e,i:r?n(r.i,e-1):0,t:c(e,(e=>{const t=r&&r.t[e];return i(t)?t:-1})),u:c(e,(e=>{if(0===e)return 0;const t=r&&r.u[e];return i(t)?t:-1}))}),g="undefined"!=typeof window?t.useLayoutEffect:t.useEffect,p=(e,t)=>r.useSyncExternalStore(e,t,t),w="current",S=e=>{const r=t.useRef();return r[w]||(r[w]=e())},y=e=>{const r=t.useRef(e);return g((()=>{r[w]=e}),[e]),t.useCallback(((...e)=>{r[w]&&r[w](...e)}),[])},z=t.memo((({_:r,h:n,m:o,g:l,p:s})=>{const i=t.useRef(null),c=p(o.S,(()=>o.v(l))),u=p(o.S,(()=>o.I(l)));return g((()=>n.T(i[w],l)),[l]),e.jsx(s,{ref:i,style:t.useMemo((()=>{const e=o.O(),t=o.R()?"right":"left",r={margin:0,padding:0,position:"absolute",[e?"height":"width"]:"100%",[e?"top":t]:0,[e?t:"top"]:c};return e&&(r.display="flex"),u&&(r.visibility="hidden"),r}),[c,u]),children:r})})),v=t.forwardRef((({children:r,style:n,scrollSize:o,scrolling:l,horizontal:s,rtl:i},c)=>e.jsx("div",{ref:c,style:n,children:e.jsx("div",{style:t.useMemo((()=>{const e=s?o:"100%",t=s?"100%":o;return{position:"absolute",top:0,[i?"right":"left"]:0,width:e,height:t,minWidth:e,minHeight:t,pointerEvents:l?"none":"auto"}}),[o,l]),children:r})}))),I=({_:r,M:n,m:o,p:l,k:s,q:i})=>{const c=p(o.S,o.j),u=o.O();return e.jsx(l,{ref:n,scrollSize:c,scrolling:s,horizontal:u,rtl:o.R(),style:t.useMemo((()=>({overflow:u?"auto hidden":"hidden auto",position:"relative",contain:"strict",width:"100%",height:"100%",padding:0,margin:0,...i})),[i]),children:r})},x=t.forwardRef((({children:r,itemSize:c=40,overscan:d=4,horizontal:x,rtl:b,endThreshold:T=0,style:O,element:R=v,itemElement:M="div",onEndReached:k,onScroll:q,onScrollStop:E},j)=>{const A=t.useMemo((()=>{const e=[];return t.Children.forEach(r,(t=>{(e=>!i(e)||"boolean"==typeof e)(t)||e.push(t)})),e}),[r]),D=A.length,F=S((()=>((e,t,r,o)=>{let l,s=0,i=0,c=0,d=[],g=m(e,t),p=[0,0];const w=new Set,S=()=>r?s:i;return{A(){const[e,t]=p,r=f(g,e),n=_(g,c,e,r),o=h(g,n,S());return e===n&&t===o?p:p=[n,o]},I:e=>-1===g.t[e],D:e=>((e,t,r)=>{for(let n=t;n<=r;n++)if(-1===e.t[n])return!0;return!1})(g,e,h(g,e,S())),v:e=>f(g,e),F:()=>c,H:()=>S(),j:()=>(e=>a(e,e.l-1,!0))(g),J:()=>g.l,P:()=>d,O:()=>r,R:()=>o,U:e=>_(g,e,0,0),W:()=>(l&&l[1](),new Promise(((e,t)=>{l=[()=>{Promise.resolve().then((()=>{e(),l=void 0}))},t]}))),S:e=>(w.add(e),()=>{w.delete(e)}),C(e,r){(()=>{switch(e){case 0:return g.l!==r&&(g=m(r,t,g),!0);case 1:{const e=r.filter((([e,t])=>g.t[e]!==t));if(!e.length)return!1;const t=[];return e.forEach((([e,r])=>{t.push([e,r-u(g,e)]),((e,t,r)=>{e.t[t]=r,e.i=n(t,e.i)})(g,e,r)})),d=t,!0}case 2:return(s!==r.L||i!==r.V)&&(s=r.L,i=r.V,!0);case 3:{const e=c;return(c=r)!==e}}})()&&(w.forEach((e=>{e()})),l&&1===e&&l[0]())}}})(D,c,!!x,!!b))),[H,J]=p(F.S,F.A),P=p(F.S,F.P),U=t.useRef(null),W=t.useRef(-1),C=y(q),L=y(E),[V,B]=t.useState(new Set),[G,K]=t.useState(!1),N=S((()=>((e,t,r)=>{let n,o,c,u=-1,a=0,f=!1;const d=e.O(),_=e.R(),h=d?"scrollLeft":"scrollTop",m=new WeakMap,g=()=>c||(c=new ResizeObserver((t=>{const r=[];for(const n of t)if(n.target===o)e.C(2,{L:n.contentRect.width,V:n.contentRect.height});else{const e=m.get(n.target);i(e)&&r.push([e,n.contentRect[d?"width":"height"]])}r.length&&(e.C(1,r),f=!0)}))),p=()=>o?e.O()?o.scrollWidth:o.scrollHeight:0,w=(e,t)=>{if(o){if(_){if(!i(n)){const e=o[h];o[h]=1,n=0===o[h],o[h]=e}n&&(e*=-1)}t?o[h]+=e:(o[h]=e,a=3)}};return{B(n){o=n;const c=g(),m=()=>{let r=n[h];_&&(r=l(r)),u!==r&&(0!==a&&f?f=!1:3!==a&&(a=u>r?2:1),e.C(3,u=r),t(r))},p=(()=>{let e;const t=()=>{i(e)&&clearTimeout(e)},n=()=>{t(),e=setTimeout((()=>{e=null,m(),a=0,r(!1)}),150)};return n.G=t,n})(),w=()=>{const e=0===a;m(),e&&r(!0),p()},S=(()=>{let t=s()-50;return(...r)=>{const n=s();t+50<n&&(t=n,(t=>{0!==a&&(t.ctrlKey||(d?t.deltaX:t.deltaY)&&u>0&&u<e.j()-e.H()&&p())})(...r))}})();return c.observe(n),n.addEventListener("scroll",w),n.addEventListener("wheel",S,{passive:!0}),()=>{c.disconnect(),n.removeEventListener("scroll",w),n.removeEventListener("wheel",S),p.G()}},T(e,t){const r=g();return m.set(e,t),r.observe(e),()=>{m.delete(e),r.unobserve(e)}},K:p,N:async(t,r)=>{const n=()=>{let t=r();const n=p(),o=e.H();return n-(t+o)<=0&&(t=n-o),t};if(e.D(t)){do{e.C(3,n());try{await e.W()}catch(e){return}}while(e.D(t));w(n())}else{const t=n();w(t),e.C(3,t)}},X:(t,r)=>{if(2===a){const e=t.reduce(((e,[,t])=>e+t),0);e&&w(e,!0)}else if(3===a){const n=e.F();if(0===n);else{const o=t.reduce(((e,[,t])=>e+t),0);if(e.j()-(n+e.H()+o)<=0)o&&w(n+o);else{const e=t.reduce(((e,[t,n])=>(t<r&&(e+=n),e)),0);e&&w(e,!0)}}}}}})(F,C,(e=>{K(e),e||(B(new Set),L())})))),Q=n(D,F.J());g((()=>{F.C(0,D)}),[D]),g((()=>N.B(U[w])),[]),g((()=>{P.length&&N.X(P,H)}),[P]),t.useEffect((()=>{k&&(W[w]>Q&&(W[w]=-1),Q-1-J<=T&&W[w]<Q&&(W[w]=Q,k()))}),[J]),t.useImperativeHandle(j,(()=>({get scrollOffset(){return F.F()},get scrollSize(){return N.K()},scrollToIndex(e){e=o(n(e,Q-1),0),N.N(e,(()=>F.v(e)))},scrollToOffset(e){e=o(e,0),N.N(F.U(e),(()=>e))}})),[Q]);const X=o(H-d,0),Y=n(J+d,Q-1),Z=t.useMemo((()=>{const t=[];for(let e=X;e<=Y;e++)V.add(e);return V.forEach((r=>{const n=A[r];t.push(e.jsx(z,{h:N,m:F,g:r,p:M,_:n},(null==n?void 0:n.key)||r))})),t}),[A,V,X,Y]);return e.jsx(I,{M:U,m:F,p:R,k:G,q:O,_:Z})}));exports.List=x;
1
+ var e=require("react/jsx-runtime"),t=require("react"),r=require("use-sync-external-store/shim/index.js");const n=Math.min,o=Math.max,s=Math.abs,l=Date.now,i=e=>null!=e,c=(e,t)=>Array.from({length:e},((e,r)=>t(r))),u=(e,t)=>{const r=e.t[t];return-1===r?e.o:r},a=(e,t,r)=>{if(!e.l)return 0;if(e.i>=t)return r?e.u[t]+u(e,t):e.u[t];let n=e.i,o=e.u[n];for(;n<=t&&(e.u[n]=o,n!==t||r);)o+=u(e,n),n++;return e.i=t,o},_=(e,t)=>a(e,t),d=(e,t,r)=>{let s=0;if(r>=0)for(;t<e.l-1;){const n=u(e,t++);if((s+=n)>=r){s-n/2>=r&&t--;break}}else for(;t>0;){const n=u(e,--t);if((s-=n)<=r){s+n/2<r&&t++;break}}return n(o(t,0),e.l-1)},f=(e,t,r,n)=>d(e,r,t-n),h=d,g=(e,t,r)=>({o:t,l:e,i:r?n(r.i,e-1):0,t:c(e,(e=>{const t=r&&r.t[e];return i(t)?t:-1})),u:c(e,(e=>{if(0===e)return 0;const t=r&&r.u[e];return i(t)?t:-1}))}),m="undefined"!=typeof window?t.useLayoutEffect:t.useEffect,w=(e,t)=>r.useSyncExternalStore(e,t,t),S="current",p=e=>{const r=t.useRef();return r[S]||(r[S]=e())},v=e=>{const r=t.useRef(e);return m((()=>{r[S]=e}),[e]),r},z=t.memo((({_:r,h:n,g:o,m:s,S:l})=>{const i=t.useRef(null),c=w(o.p,(()=>o.v(s))),u=w(o.p,(()=>o.I(s)));return m((()=>n.T(i[S],s)),[s]),e.jsx(l,{ref:i,style:t.useMemo((()=>{const e=o.R(),t=o.M()?"right":"left",r={margin:0,padding:0,position:"absolute",[e?"height":"width"]:"100%",[e?"top":t]:0,[e?t:"top"]:c,visibility:u?"hidden":"visible"};return e&&(r.display="flex"),r}),[c,u]),children:r})})),I=t.forwardRef((({children:r,scrollSize:n,scrolling:o,horizontal:s,attrs:l},i)=>e.jsx("div",{ref:i,...l,children:e.jsx("div",{style:t.useMemo((()=>({position:"relative",visibility:"hidden",width:s?n:"100%",height:s?"100%":n,pointerEvents:o?"none":"auto"})),[n,o]),children:r})}))),x=({_:r,O:n,g:o,S:s,k:l,q:i})=>{const c=w(o.p,o.j),u=o.R();return e.jsx(s,{ref:n,scrollSize:c,scrolling:l,horizontal:u,attrs:t.useMemo((()=>({...i,style:{overflow:u?"auto hidden":"hidden auto",contain:"strict",width:"100%",height:"100%",padding:0,margin:0,...i.style}})),[i]),children:r})},y=t.forwardRef((({children:r,itemSize:c=40,overscan:d=4,horizontal:y,rtl:b,element:T=I,itemElement:R="div",onScroll:M,onScrollStop:O,onRangeChange:k,...q},j)=>{const A=t.useMemo((()=>{const e=[];return t.Children.forEach(r,(t=>{(e=>!i(e)||"boolean"==typeof e)(t)||e.push(t)})),e}),[r]),C=A.length,D=p((()=>((e,t,r,o)=>{let s,l=0,i=0,c=0,d=[],m=g(e,t),w=[0,0];const S=new Set,p=()=>r?l:i;return{A(){const[e,t]=w,r=_(m,e),n=f(m,c,e,r),o=h(m,n,p());return e===n&&t===o?w:w=[n,o]},I:e=>-1===m.t[e],C:e=>((e,t,r)=>{for(let n=t;n<=r;n++)if(-1===e.t[n])return!0;return!1})(m,e,h(m,e,p())),v:e=>_(m,e),D:()=>c,F:()=>p(),j:()=>(e=>a(e,e.l-1,!0))(m),J:()=>m.l,P:()=>d,R:()=>r,M:()=>o,U:e=>f(m,e,0,0),B:()=>(s&&s[1](),new Promise(((e,t)=>{s=[()=>{Promise.resolve().then((()=>{e(),s=void 0}))},t]}))),p:e=>(S.add(e),()=>{S.delete(e)}),H(e,r){(()=>{switch(e){case 0:return m.l!==r&&(m=g(r,t,m),!0);case 1:{const e=r.filter((([e,t])=>m.t[e]!==t));if(!e.length)return!1;const t=[];return e.forEach((([e,r])=>{t.push([e,r-u(m,e)]),((e,t,r)=>{e.t[t]=r,e.i=n(t,e.i)})(m,e,r)})),d=t,!0}case 2:return(l!==r.L||i!==r.V)&&(l=r.L,i=r.V,!0);case 3:{const e=c;return(c=r)!==e}}})()&&(S.forEach((e=>{e()})),s&&1===e&&s[0]())}}})(C,c,!!y,!!b))),[E,F]=w(D.p,D.A),J=w(D.p,D.P),P=t.useRef(null),U=v(M),B=v(O),[H,L]=t.useState(new Set),[V,W]=t.useState(!1),G=p((()=>((e,t,r)=>{let c,u,a,_=-1,d=0,f=!1;const h=e.R(),g=e.M(),m=h?"scrollLeft":"scrollTop",w=new WeakMap,S=()=>a||(a=new ResizeObserver((t=>{const r=[];for(const n of t)if(n.target===u)e.H(2,{L:n.contentRect.width,V:n.contentRect.height});else{const e=w.get(n.target);i(e)&&r.push([e,n.contentRect[h?"width":"height"]])}r.length&&(e.H(1,r),f=!0)}))),p=()=>u?e.R()?u.scrollWidth:u.scrollHeight:0,v=(e,t)=>{if(u){if(g){if(!i(c)){const e=u[m];u[m]=1,c=0===u[m],u[m]=e}c&&(e*=-1)}t?u[m]+=e:(u[m]=e,d=3)}},z=async(t,r)=>{const n=()=>{let t=r();const n=p(),o=e.F();return n-(t+o)<=0&&(t=n-o),t};if(e.C(t)){do{e.H(3,n());try{await e.B()}catch(e){return}}while(e.C(t));v(n())}else{const t=n();v(t),e.H(3,t)}},I=e=>e.reduce(((e,[,t])=>e+t),0);return{W(n){u=n;const o=S(),c=()=>{let r=n[m];g&&(r=s(r)),_!==r&&(0!==d&&f?f=!1:3!==d&&(d=_>r?2:1),e.H(3,_=r),t(r))},a=(()=>{let e;const t=()=>{i(e)&&clearTimeout(e)},n=()=>{t(),e=setTimeout((()=>{e=null,c(),d=0,r(!1)}),150)};return n.G=t,n})(),w=()=>{const e=0===d;c(),e&&r(!0),a()},p=(()=>{let t=l()-50;return(...r)=>{const n=l();t+50<n&&(t=n,(t=>{0!==d&&(t.ctrlKey||(h?t.deltaX:t.deltaY)&&_>0&&_<e.j()-e.F()&&a())})(...r))}})();return o.observe(n),n.addEventListener("scroll",w),n.addEventListener("wheel",p,{passive:!0}),()=>{o.disconnect(),n.removeEventListener("scroll",w),n.removeEventListener("wheel",p),a.G()}},T(e,t){const r=S();return w.set(e,t),r.observe(e),()=>{w.delete(e),r.unobserve(e)}},K:p,N(t){t=o(t,0),z(e.U(t),(()=>t))},X(t,r){t=o(n(t,r-1),0),z(t,(()=>e.v(t)))},Y:(t,r)=>{if(2===d){const e=I(t);e&&v(e,!0)}else if(3===d){const n=e.D();if(0===n);else{const o=I(t);if(e.j()-(n+e.F()+o)<=0)o&&v(n+o);else{const e=t.reduce(((e,[t,n])=>(t<r&&(e+=n),e)),0);e&&v(e,!0)}}}}}})(D,(e=>{U[S]&&U[S](e)}),(e=>{W(e),e||(L(new Set),B[S]&&B[S]())})))),K=n(C,D.J());m((()=>{D.H(0,C)}),[C]),m((()=>G.W(P[S])),[]),m((()=>{J.length&&G.Y(J,E)}),[J]),t.useEffect((()=>{k&&k({start:E,end:F,count:K})}),[E,F]),t.useImperativeHandle(j,(()=>({get scrollOffset(){return D.D()},get scrollSize(){return G.K()},get viewportSize(){return D.F()},scrollToIndex(e){G.X(e,K)},scrollTo:G.N,scrollBy(e){G.N(D.D()+e)}})),[K]);const N=o(E-d,0),Q=n(F+d,K-1),X=t.useMemo((()=>{const t=[];for(let e=N;e<=Q;e++)H.add(e);return H.forEach((r=>{const n=A[r];i(n)&&t.push(e.jsx(z,{h:G,g:D,m:r,S:R,_:n},(null==n?void 0:n.key)||r))})),t}),[A,H,N,Q]);return e.jsx(x,{O:P,g:D,S:T,k:V,_:X,q})}));exports.VList=y;
2
2
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/src/core/utils.ts","../src/src/core/cache.ts","../src/src/react/useIsomorphicLayoutEffect.ts","../src/src/react/useSyncExternalStore.ts","../src/src/react/utils.ts","../src/src/react/useStatic.ts","../src/src/react/useEvent.ts","../src/src/react/List.tsx","../src/src/core/store.ts","../src/src/core/scroller.ts"],"sourcesContent":["export const min = Math.min;\nexport const max = Math.max;\nexport const abs = Math.abs;\nexport const now = Date.now;\n\nexport const exists = <T>(v: T): v is Exclude<T, null | undefined> => v != null;\n\nexport const range = <T>(length: number, cb: (i: number) => T): T[] =>\n Array.from({ length }, (_, i) => cb(i));\n\nexport const debounce = <T extends (...args: any[]) => void>(\n fn: T,\n ms: number\n) => {\n let id: NodeJS.Timeout | undefined | null;\n\n const cancel = () => {\n if (exists(id)) {\n clearTimeout(id);\n }\n };\n const debouncedFn = () => {\n cancel();\n id = setTimeout(() => {\n id = null;\n fn();\n }, ms);\n };\n debouncedFn._cancel = cancel;\n return debouncedFn;\n};\n\nexport const throttle = <T extends (...args: any[]) => void>(\n fn: T,\n ms: number\n) => {\n let time = now() - ms;\n return (...args: Parameters<T>) => {\n const n = now();\n if (time + ms < n) {\n time = n;\n fn(...args);\n }\n };\n};\n","import type { DeepReadonly, Writeable } from \"./types\";\nimport { exists, max, min, range } from \"./utils\";\n\nexport const UNCACHED = -1;\n\nexport type Cache = DeepReadonly<{\n _defaultItemSize: number;\n _length: number;\n _sizes: number[];\n _measuredOffsetIndex: number;\n _offsets: number[];\n}>;\n\nexport const getItemSize = (cache: Cache, index: number): number => {\n const size = cache._sizes[index]!;\n return size === UNCACHED ? cache._defaultItemSize : size;\n};\n\nexport const setItemSize = (\n cache: Writeable<Cache>,\n index: number,\n size: number\n) => {\n cache._sizes[index] = size;\n // mark as dirty\n cache._measuredOffsetIndex = min(index, cache._measuredOffsetIndex);\n};\n\nconst computeOffset = (\n cache: Writeable<Cache>,\n index: number,\n isTotal?: boolean\n): number => {\n if (!cache._length) return 0;\n if (cache._measuredOffsetIndex >= index) {\n if (isTotal) {\n return cache._offsets[index]! + getItemSize(cache, index);\n } else {\n return cache._offsets[index]!;\n }\n }\n\n let i = cache._measuredOffsetIndex;\n let top = cache._offsets[i]!;\n while (i <= index) {\n cache._offsets[i] = top;\n if (i === index && !isTotal) {\n break;\n }\n top += getItemSize(cache, i);\n i++;\n }\n // mark as measured\n cache._measuredOffsetIndex = index;\n return top;\n};\n\nexport const computeTotalSize = (cache: Writeable<Cache>): number => {\n return computeOffset(cache, cache._length - 1, true);\n};\n\nexport const computeStartOffset = (\n cache: Writeable<Cache>,\n index: number\n): number => {\n return computeOffset(cache, index);\n};\n\nconst findIndex = (cache: Cache, i: number, distance: number): number => {\n let sum = 0;\n if (distance >= 0) {\n // search forward\n while (i < cache._length - 1) {\n const h = getItemSize(cache, i++);\n if ((sum += h) >= distance) {\n if (sum - h / 2 >= distance) {\n i--;\n }\n break;\n }\n }\n } else {\n // search backward\n while (i > 0) {\n const h = getItemSize(cache, --i);\n if ((sum -= h) <= distance) {\n if (sum + h / 2 < distance) {\n i++;\n }\n break;\n }\n }\n }\n\n return min(max(i, 0), cache._length - 1);\n};\n\nexport const findStartIndexWithOffset = (\n cache: Cache,\n offset: number,\n prevStartIndex: number,\n prevOffset: number\n): number => {\n return findIndex(cache, prevStartIndex, offset - prevOffset);\n};\n\nexport const findEndIndex = findIndex;\n\nexport const hasUnmeasuredItemsInRange = (\n cache: Cache,\n startIndex: number,\n endIndex: number\n): boolean => {\n for (let i = startIndex; i <= endIndex; i++) {\n if (cache._sizes[i] === UNCACHED) {\n return true;\n }\n }\n return false;\n};\n\nexport const resetCache = (\n length: number,\n itemSize: number,\n cache?: Cache\n): Cache => {\n return {\n _defaultItemSize: itemSize,\n _length: length,\n _measuredOffsetIndex: cache\n ? min(cache._measuredOffsetIndex, length - 1)\n : 0,\n _sizes: range(length, (i) => {\n const size = cache && cache._sizes[i];\n if (exists(size)) {\n return size;\n }\n return UNCACHED;\n }),\n _offsets: range(length, (i) => {\n if (i === 0) {\n // first offset must be 0\n return 0;\n }\n const offset = cache && cache._offsets[i];\n if (exists(offset)) {\n return offset;\n }\n return UNCACHED;\n }),\n };\n};\n","import { useEffect, useLayoutEffect } from \"react\";\n\n// https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85\nexport const useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n","import { useSyncExternalStore as _useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\n\nexport const useSyncExternalStore = <T>(\n subscibe: (onStoreChange: () => void) => () => void,\n getSnapShot: () => T\n): T => {\n return _useSyncExternalStore(subscibe, getSnapShot, getSnapShot);\n};\n","export const refKey = \"current\";\n","import { useRef } from \"react\";\nimport { refKey } from \"./utils\";\n\nexport const useStatic = <T>(init: () => T): T => {\n const ref = useRef<T>();\n return ref[refKey] || (ref[refKey] = init());\n};\n","import { useCallback, useRef } from \"react\";\n\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\nimport { refKey } from \"./utils\";\n\nexport const useEvent = <T extends (...args: any[]) => void>(\n handler: T | undefined\n) => {\n const handlerRef = useRef<T | undefined>(handler);\n\n useIsomorphicLayoutEffect(() => {\n handlerRef[refKey] = handler;\n }, [handler]);\n\n return useCallback((...args: Parameters<T>): void => {\n handlerRef[refKey] && handlerRef[refKey](...args);\n }, []);\n};\n","import {\n Children,\n memo,\n useRef,\n useMemo,\n CSSProperties,\n ReactElement,\n forwardRef,\n useImperativeHandle,\n ReactNode,\n useEffect,\n RefObject,\n useState,\n} from \"react\";\nimport {\n ACTION_UPDATE_CACHE_LENGTH,\n VirtualStore,\n createVirtualStore,\n} from \"../core/store\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\nimport { useSyncExternalStore } from \"./useSyncExternalStore\";\nimport { exists, max, min } from \"../core/utils\";\nimport { createScroller, Scroller } from \"../core/scroller\";\nimport { refKey } from \"./utils\";\nimport { useStatic } from \"./useStatic\";\nimport { useEvent } from \"./useEvent\";\n\nconst INITIAL_END_REACHED_INDEX = -1;\n\ntype ItemProps = {\n _children: ReactNode;\n _scroller: Scroller;\n _store: VirtualStore;\n _index: number;\n _element: \"div\";\n};\n\nconst Item = memo(\n ({\n _children: children,\n _scroller: scroller,\n _store: store,\n _index: index,\n _element: Element,\n }: ItemProps): ReactElement => {\n const ref = useRef<HTMLDivElement>(null);\n\n const offset = useSyncExternalStore(store._subscribe, () =>\n store._getItemOffset(index)\n );\n const hide = useSyncExternalStore(store._subscribe, () =>\n store._isUnmeasuredItem(index)\n );\n\n // The index may be changed if elements are inserted to or removed from the start of props.children\n useIsomorphicLayoutEffect(\n () => scroller._initItem(ref[refKey]!, index),\n [index]\n );\n\n return (\n <Element\n ref={ref}\n style={useMemo((): CSSProperties => {\n const isHorizontal = store._isHorizontal();\n const leftOrRightKey = store._isRtl() ? \"right\" : \"left\";\n const style: CSSProperties = {\n margin: 0,\n padding: 0,\n position: \"absolute\",\n [isHorizontal ? \"height\" : \"width\"]: \"100%\",\n [isHorizontal ? \"top\" : leftOrRightKey]: 0,\n [isHorizontal ? leftOrRightKey : \"top\"]: offset,\n // willChange: \"transform\",\n };\n if (isHorizontal) {\n style.display = \"flex\";\n }\n if (hide) {\n style.visibility = \"hidden\";\n }\n return style;\n }, [offset, hide])}\n >\n {children}\n </Element>\n );\n }\n);\n\nconst isInvalidElement = <T extends ReactNode>(\n e: T\n): e is Extract<T, null | undefined | boolean> =>\n !exists(e) || typeof e === \"boolean\";\n\n/**\n * Props of customized scrollable component.\n */\nexport interface CustomWindowComponentProps {\n children: ReactNode;\n style: CSSProperties;\n scrollSize: number;\n scrolling: boolean;\n horizontal: boolean;\n rtl: boolean;\n}\n\nconst DefaultWindow = forwardRef<any, CustomWindowComponentProps>(\n (\n { children, style, scrollSize, scrolling, horizontal, rtl },\n ref\n ): ReactElement => {\n return (\n <div ref={ref} style={style}>\n <div\n style={useMemo((): CSSProperties => {\n const width = horizontal ? scrollSize : \"100%\";\n const height = horizontal ? \"100%\" : scrollSize;\n return {\n position: \"absolute\",\n top: 0,\n [rtl ? \"right\" : \"left\"]: 0,\n width,\n height,\n minWidth: width,\n minHeight: height,\n pointerEvents: scrolling ? \"none\" : \"auto\",\n };\n }, [scrollSize, scrolling])}\n >\n {children}\n </div>\n </div>\n );\n }\n);\n\nexport type CustomWindowComponent = typeof DefaultWindow;\n\nconst Window = ({\n _children: children,\n _ref: ref,\n _store: store,\n _element: Element,\n _scrolling: scrolling,\n _style: style,\n}: {\n _children: ReactNode;\n _ref: RefObject<HTMLDivElement>;\n _store: VirtualStore;\n _element: CustomWindowComponent;\n _scrolling: boolean;\n _style: CSSProperties | undefined;\n}) => {\n const scrollSize = useSyncExternalStore(\n store._subscribe,\n store._getScrollSize\n );\n\n const horizontal = store._isHorizontal();\n\n return (\n <Element\n ref={ref}\n scrollSize={scrollSize}\n scrolling={scrolling}\n horizontal={horizontal}\n rtl={store._isRtl()}\n style={useMemo(\n (): CSSProperties => ({\n overflow: horizontal ? \"auto hidden\" : \"hidden auto\",\n position: \"relative\",\n contain: \"strict\",\n // transform: \"translate3d(0px, 0px, 0px)\",\n // willChange: \"scroll-position\",\n // backfaceVisibility: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n padding: 0,\n margin: 0,\n ...style,\n }),\n [style]\n )}\n >\n {children}\n </Element>\n );\n};\n\n/**\n * Props of customized item component.\n */\nexport interface CustomItemComponentProps {\n style: CSSProperties;\n children: ReactNode;\n}\n\nexport type CustomItemComponent = React.ForwardRefExoticComponent<\n React.PropsWithoutRef<CustomItemComponentProps> & React.RefAttributes<any>\n>;\n\ntype CustomItemComponentOrElement =\n | keyof JSX.IntrinsicElements\n | CustomItemComponent;\n\n/**\n * Methods of {@link List}.\n */\nexport interface ListHandle {\n /**\n * Get current scrollTop or scrollLeft.\n */\n scrollOffset: number;\n /**\n * Get current scrollHeight or scrollWidth.\n */\n scrollSize: number;\n /**\n * Scroll to the item specified by index.\n * @param index index of item\n */\n scrollToIndex(index: number): void;\n /**\n * Scroll to the item specified by offset.\n * @param offset offset from start\n */\n scrollToOffset(offset: number): void;\n}\n\n/**\n * Props of {@link List}.\n */\nexport interface ListProps {\n /**\n * Elements rendered by this component.\n */\n children: ReactNode;\n /**\n * Item size hint for unmeasured items. It's recommended to specify this prop if item sizes are fixed and known, or much larger than the defaultValue. It will help to reduce scroll jump when items are measured.\n * @defaultValue 40\n */\n itemSize?: number;\n /**\n * Number of items to render above/below the visible bounds of the list. You can increase to avoid showing blank items in fast scrolling.\n * @defaultValue 4\n */\n overscan?: number;\n /**\n * If true, rendered as a horizontally scrollable list. Otherwise rendered as a vertically scrollable list.\n */\n horizontal?: boolean;\n /**\n * You have to set true if you use this component under `direction: rtl` style.\n */\n rtl?: boolean;\n /**\n * Number of items to be the margin from the end of the scroll. See also {@link onEndReached}.\n * @defaultValue 0\n */\n endThreshold?: number;\n /**\n * Inline style prop to override style of scrollable element.\n */\n style?: CSSProperties;\n /**\n * Customized element type for scrollable element. This element will get {@link CustomWindowComponentProps} as props.\n * @defaultValue {@link DefaultWindow}\n */\n element?: CustomWindowComponent;\n /**\n * Customized element type for item element. This element will get {@link CustomItemComponentProps} as props.\n * @defaultValue \"div\"\n */\n itemElement?: CustomItemComponentOrElement;\n /**\n * Callback invoked when scrolling reached to the end. The margin from the end is specified by {@link endThreshold}.\n */\n onEndReached?: () => void;\n /**\n * Callback invoked whenever scroll offset changes.\n * @param offset Current scrollTop or scrollLeft.\n */\n onScroll?: (offset: number) => void;\n /**\n * Callback invoked when scrolling stops.\n */\n onScrollStop?: () => void;\n}\n\n/**\n * Virtualized list component. See {@link ListProps} and {@link ListHandle}.\n */\nexport const List = forwardRef<ListHandle, ListProps>(\n (\n {\n children,\n itemSize: itemSizeProp = 40,\n overscan = 4,\n horizontal: horizontalProp,\n rtl: rtlProp,\n endThreshold = 0,\n style: styleProp,\n element = DefaultWindow,\n itemElement = \"div\",\n onEndReached,\n onScroll: onScrollProp,\n onScrollStop: onScrollStopProp,\n },\n ref\n ): ReactElement => {\n // Memoize element array\n const elements = useMemo(() => {\n const arr: ReactNode[] = [];\n Children.forEach(children, (e) => {\n if (isInvalidElement(e)) {\n return;\n }\n arr.push(e);\n });\n return arr;\n }, [children]);\n const elementsCount = elements.length;\n\n // https://github.com/facebook/react/issues/25191#issuecomment-1237456448\n const store = useStatic(() =>\n createVirtualStore(\n elementsCount,\n itemSizeProp,\n !!horizontalProp,\n !!rtlProp\n )\n );\n const [startIndex, endIndex] = useSyncExternalStore(\n store._subscribe,\n store._getRange\n );\n const jump = useSyncExternalStore(store._subscribe, store._getJump);\n const rootRef = useRef<HTMLDivElement>(null);\n\n const onEndReachedCalledIndex = useRef<number>(INITIAL_END_REACHED_INDEX);\n const onScroll = useEvent(onScrollProp);\n const onScrollStop = useEvent(onScrollStopProp);\n\n const [mountedIndexes, reset] = useState<Set<number>>(new Set<number>());\n const [scrolling, setScrolling] = useState(false);\n const scroller = useStatic(() =>\n createScroller(store, onScroll, (isScrolling) => {\n setScrolling(isScrolling);\n if (!isScrolling) {\n reset(new Set());\n onScrollStop();\n }\n })\n );\n\n // The elements length and cached items length are different just after element is added/removed.\n const count = min(elementsCount, store._getItemCount());\n\n // So update cache length. Updating state in render will cause warn so use useEffect for now.\n useIsomorphicLayoutEffect(() => {\n store._update(ACTION_UPDATE_CACHE_LENGTH, elementsCount);\n }, [elementsCount]);\n\n useIsomorphicLayoutEffect(() => scroller._initRoot(rootRef[refKey]!), []);\n\n useIsomorphicLayoutEffect(() => {\n if (!jump.length) return;\n\n scroller._fixScrollJump(jump, startIndex);\n }, [jump]);\n\n useEffect(() => {\n if (!onEndReached) return;\n\n if (onEndReachedCalledIndex[refKey] > count) {\n // Probably items have been refreshed, so reset index\n onEndReachedCalledIndex[refKey] = INITIAL_END_REACHED_INDEX;\n }\n\n const endMargin = count - 1 - endIndex;\n if (\n endMargin <= endThreshold &&\n onEndReachedCalledIndex[refKey] < count\n ) {\n onEndReachedCalledIndex[refKey] = count;\n onEndReached();\n }\n }, [endIndex]);\n\n useImperativeHandle(\n ref,\n () => {\n return {\n get scrollOffset() {\n return store._getScrollOffset();\n },\n get scrollSize() {\n return scroller._getActualScrollSize();\n },\n scrollToIndex(index) {\n index = max(min(index, count - 1), 0);\n\n scroller._scrollTo(index, () => store._getItemOffset(index));\n },\n scrollToOffset(offset) {\n offset = max(offset, 0);\n\n scroller._scrollTo(\n store._getItemIndexForScrollTo(offset),\n () => offset\n );\n },\n };\n },\n [count]\n );\n\n const startIndexWithMargin = max(startIndex - overscan, 0);\n const endIndexWithMargin = min(endIndex + overscan, count - 1);\n const items = useMemo(() => {\n const res: ReactElement[] = [];\n for (let i = startIndexWithMargin; i <= endIndexWithMargin; i++) {\n // https://github.com/sergi/virtual-list/commit/8e7e06dc63568334c1ab809ea83c1be36572e9ed\n mountedIndexes.add(i);\n }\n mountedIndexes.forEach((i) => {\n const e = elements[i];\n res.push(\n <Item\n key={(e as { key?: ReactElement[\"key\"] })?.key || i}\n _scroller={scroller}\n _store={store}\n _index={i}\n _element={itemElement as \"div\"}\n _children={e}\n />\n );\n });\n return res;\n }, [elements, mountedIndexes, startIndexWithMargin, endIndexWithMargin]);\n\n return (\n <Window\n _ref={rootRef}\n _store={store}\n _element={element}\n _scrolling={scrolling}\n _style={styleProp}\n _children={items}\n />\n );\n }\n);\n","import {\n findStartIndexWithOffset,\n resetCache,\n getItemSize,\n computeTotalSize,\n findEndIndex,\n computeStartOffset,\n Cache,\n UNCACHED,\n setItemSize,\n hasUnmeasuredItemsInRange,\n} from \"./cache\";\nimport type { Writeable } from \"./types\";\n\nexport type ScrollJump = Readonly<[index: number, sizeDiff: number][]>;\nexport type ItemResize = [index: number, size: number];\ntype ItemsRange = [startIndex: number, endIndex: number];\n\nexport const ACTION_UPDATE_CACHE_LENGTH = 0;\nexport const ACTION_UPDATE_ITEM_SIZES = 1;\nexport const ACTION_UPDATE_VIEWPORT = 2;\nexport const ACTION_HANDLE_SCROLL = 3;\n\ntype Actions =\n | [type: typeof ACTION_UPDATE_CACHE_LENGTH, length: number]\n | [type: typeof ACTION_UPDATE_ITEM_SIZES, entries: ItemResize[]]\n | [\n type: typeof ACTION_UPDATE_VIEWPORT,\n rect: { _width: number; _height: number }\n ]\n | [type: typeof ACTION_HANDLE_SCROLL, offset: number];\n\nexport type VirtualStore = {\n _getRange(): ItemsRange;\n _isUnmeasuredItem(index: number): boolean;\n _hasUnmeasuredItemsInRange(startIndex: number): boolean;\n _getItemOffset(index: number): number;\n _getScrollOffset(): number;\n _getViewportSize(): number;\n _getScrollSize(): number;\n _getItemCount(): number;\n _getJump(): ScrollJump;\n _isHorizontal(): boolean;\n _isRtl(): boolean;\n _getItemIndexForScrollTo(offset: number): number;\n _waitForScrollDestinationItemsMeasured(): Promise<void>;\n _subscribe(cb: () => void): () => void;\n _update(...action: Actions): void;\n};\n\nexport const createVirtualStore = (\n itemCount: number,\n itemSize: number,\n isHorizontal: boolean,\n isRtl: boolean\n): VirtualStore => {\n let viewportWidth = 0;\n let viewportHeight = 0;\n let scrollOffset = 0;\n let jump: ScrollJump = [];\n let cache = resetCache(itemCount, itemSize);\n let _prevRange: ItemsRange = [0, 0];\n let _scrollToQueue: [() => void, () => void] | undefined;\n\n const subscribers = new Set<() => void>();\n const getViewportSize = (): number =>\n isHorizontal ? viewportWidth : viewportHeight;\n\n return {\n _getRange() {\n const [prevStartIndex, prevEndIndex] = _prevRange;\n const prevOffset = computeStartOffset(\n cache as Writeable<Cache>,\n prevStartIndex\n );\n const start = findStartIndexWithOffset(\n cache,\n scrollOffset,\n prevStartIndex,\n prevOffset\n );\n const end = findEndIndex(cache, start, getViewportSize());\n if (prevStartIndex === start && prevEndIndex === end) {\n return _prevRange;\n }\n return (_prevRange = [start, end]);\n },\n _isUnmeasuredItem(index) {\n return cache._sizes[index] === UNCACHED;\n },\n _hasUnmeasuredItemsInRange(startIndex) {\n return hasUnmeasuredItemsInRange(\n cache,\n startIndex,\n findEndIndex(cache, startIndex, getViewportSize())\n );\n },\n _getItemOffset(index) {\n return computeStartOffset(cache as Writeable<Cache>, index);\n },\n _getScrollOffset() {\n return scrollOffset;\n },\n _getViewportSize() {\n return getViewportSize();\n },\n _getScrollSize() {\n return computeTotalSize(cache as Writeable<Cache>);\n },\n _getItemCount() {\n return cache._length;\n },\n _getJump() {\n return jump;\n },\n _isHorizontal() {\n return isHorizontal;\n },\n _isRtl() {\n return isRtl;\n },\n _getItemIndexForScrollTo(offset) {\n return findStartIndexWithOffset(cache, offset, 0, 0);\n },\n _waitForScrollDestinationItemsMeasured() {\n if (_scrollToQueue) {\n // Cancel waiting scrollTo\n _scrollToQueue[1]();\n }\n // The measurement will be done asynchronously and the timing is not predictable so we use promise.\n // For example, ResizeObserver may not fire when window is not visible.\n return new Promise((resolve, reject) => {\n _scrollToQueue = [\n () => {\n // HACK: It should be resolved in the next microtask that is after React's render\n Promise.resolve().then(() => {\n resolve();\n _scrollToQueue = undefined;\n });\n },\n reject,\n ];\n });\n },\n _subscribe(cb) {\n subscribers.add(cb);\n return () => {\n subscribers.delete(cb);\n };\n },\n _update(type, payload) {\n const mutated = ((): boolean => {\n switch (type) {\n case ACTION_UPDATE_CACHE_LENGTH: {\n if (cache._length === payload) return false;\n cache = resetCache(payload, itemSize, cache);\n return true;\n }\n case ACTION_UPDATE_ITEM_SIZES: {\n const updated = payload.filter(\n ([index, size]) => cache._sizes[index] !== size\n );\n // Skip if all items are cached and not updated\n if (!updated.length) {\n return false;\n }\n\n const updatedJump: [index: number, sizeDiff: number][] = [];\n updated.forEach(([index, size]) => {\n updatedJump.push([index, size - getItemSize(cache, index)]);\n setItemSize(cache as Writeable<Cache>, index, size);\n });\n jump = updatedJump;\n return true;\n }\n case ACTION_UPDATE_VIEWPORT: {\n if (\n viewportWidth === payload._width &&\n viewportHeight === payload._height\n ) {\n return false;\n }\n viewportWidth = payload._width;\n viewportHeight = payload._height;\n return true;\n }\n case ACTION_HANDLE_SCROLL: {\n const prevOffset = scrollOffset;\n return (scrollOffset = payload) !== prevOffset;\n }\n }\n })();\n\n if (mutated) {\n subscribers.forEach((cb) => {\n cb();\n });\n if (_scrollToQueue && type === ACTION_UPDATE_ITEM_SIZES) {\n _scrollToQueue[0]();\n }\n }\n },\n };\n};\n","import {\n ACTION_HANDLE_SCROLL,\n ACTION_UPDATE_ITEM_SIZES,\n ACTION_UPDATE_VIEWPORT,\n ItemResize,\n ScrollJump,\n VirtualStore,\n} from \"./store\";\nimport { abs, debounce, throttle, exists } from \"./utils\";\n\nexport const SCROLL_STOP = 0;\nexport const SCROLL_DOWN = 1;\nexport const SCROLL_UP = 2;\nexport const SCROLL_MANUAL = 3;\ntype ScrollDirection =\n | typeof SCROLL_STOP\n | typeof SCROLL_DOWN\n | typeof SCROLL_UP\n | typeof SCROLL_MANUAL;\n\nexport type Scroller = {\n _initRoot: (rootElement: HTMLElement) => () => void;\n _initItem: (itemElement: HTMLElement, index: number) => () => void;\n _getActualScrollSize: () => number;\n _scrollTo: (index: number, getCurrentOffset: () => number) => void;\n _fixScrollJump: (jump: ScrollJump, startIndex: number) => void;\n};\n\nexport const createScroller = (\n store: VirtualStore,\n emitScrollOffsetChange: (offset: number) => void,\n emitScrollStateChange: (scrolling: boolean) => void\n): Scroller => {\n let prevOffset = -1;\n let scrollDirection: ScrollDirection = SCROLL_STOP;\n let resized = false;\n let isNegativeOffset: boolean | undefined;\n let rootElement: HTMLElement | undefined;\n let _ro: ResizeObserver | undefined;\n const isHorizontal = store._isHorizontal();\n const isRtl = store._isRtl();\n const scrollToKey = isHorizontal ? \"scrollLeft\" : \"scrollTop\";\n const mountedIndexes = new WeakMap<Element, number>();\n const getResizeObserver = (): ResizeObserver => {\n // Initialize ResizeObserver lazily for SSR\n return (\n _ro ||\n (_ro = new ResizeObserver((entries) => {\n // https://www.w3.org/TR/resize-observer/#intro\n const resizes: ItemResize[] = [];\n for (const entry of entries) {\n if (entry.target === rootElement) {\n store._update(ACTION_UPDATE_VIEWPORT, {\n _width: entry.contentRect.width,\n _height: entry.contentRect.height,\n });\n } else {\n const index = mountedIndexes.get(entry.target);\n if (exists(index)) {\n resizes.push([\n index,\n entry.contentRect[isHorizontal ? \"width\" : \"height\"],\n ]);\n }\n }\n }\n\n if (resizes.length) {\n store._update(ACTION_UPDATE_ITEM_SIZES, resizes);\n resized = true;\n }\n }))\n );\n };\n const getActualScrollSize = (): number => {\n if (!rootElement) return 0;\n // Use element's scrollHeight/scrollWidth instead of stored scrollSize.\n // This is because stored size may differ from the actual size, for example when a new item is added and not yet measured.\n return store._isHorizontal()\n ? rootElement.scrollWidth\n : rootElement.scrollHeight;\n };\n const updateScrollPosition = (offset: number, diff?: boolean) => {\n if (!rootElement) return;\n if (isRtl) {\n if (!exists(isNegativeOffset)) {\n // Assume offset type in rtl direction.\n // The scroll position is negative in spec however its not in some browsers, for example Chrome earlier than v85.\n // https://github.com/othree/jquery.rtl-scroll-type\n const prev = rootElement[scrollToKey];\n rootElement[scrollToKey] = 1;\n isNegativeOffset = rootElement[scrollToKey] === 0;\n rootElement[scrollToKey] = prev;\n }\n if (isNegativeOffset) {\n offset *= -1;\n }\n }\n if (diff) {\n rootElement[scrollToKey] += offset;\n } else {\n rootElement[scrollToKey] = offset;\n scrollDirection = SCROLL_MANUAL;\n }\n };\n const scrollTo = async (index: number, getCurrentOffset: () => number) => {\n const getOffset = (): number => {\n let offset = getCurrentOffset();\n const scrollSize = getActualScrollSize();\n const viewportSize = store._getViewportSize();\n if (scrollSize - (offset + viewportSize) <= 0) {\n // Adjust if the offset is over the end, to get correct startIndex.\n offset = scrollSize - viewportSize;\n }\n return offset;\n };\n\n if (store._hasUnmeasuredItemsInRange(index)) {\n do {\n // In order to scroll to the correct position, mount the items and measure their sizes before scrolling.\n store._update(ACTION_HANDLE_SCROLL, getOffset());\n try {\n // Wait for the scroll destination items to be measured.\n await store._waitForScrollDestinationItemsMeasured();\n } catch (e) {\n // canceled\n return;\n }\n } while (store._hasUnmeasuredItemsInRange(index));\n\n // Scroll with the updated value\n updateScrollPosition(getOffset());\n } else {\n const offset = getOffset();\n updateScrollPosition(offset);\n // Sync viewport to scroll destination\n store._update(ACTION_HANDLE_SCROLL, offset);\n }\n };\n\n return {\n _initRoot(root) {\n rootElement = root;\n const ro = getResizeObserver();\n\n const syncViewportToScrollPosition = () => {\n let offset = root[scrollToKey];\n if (isRtl) {\n // The scroll position may be negative value in rtl direction.\n // https://github.com/othree/jquery.rtl-scroll-type\n offset = abs(offset);\n }\n if (prevOffset === offset) {\n return;\n }\n // Skip scroll direction detection just after resizing because it may result in the opposite direction.\n // Scroll events are dispatched enough so it's ok to skip some of them.\n if (scrollDirection === SCROLL_STOP || !resized) {\n // Ignore until manual scrolling\n if (scrollDirection !== SCROLL_MANUAL) {\n scrollDirection = prevOffset > offset ? SCROLL_UP : SCROLL_DOWN;\n }\n } else {\n resized = false;\n }\n store._update(ACTION_HANDLE_SCROLL, (prevOffset = offset));\n emitScrollOffsetChange(offset);\n };\n\n const onScrollStopped = debounce(() => {\n // Check scroll position once just after scrolling stopped\n syncViewportToScrollPosition();\n scrollDirection = SCROLL_STOP;\n emitScrollStateChange(false);\n }, 150);\n\n const onScroll = () => {\n const isScrollStart = scrollDirection === SCROLL_STOP;\n syncViewportToScrollPosition();\n if (isScrollStart) {\n emitScrollStateChange(true);\n }\n onScrollStopped();\n };\n\n // Infer scroll state also from wheel events\n // Sometimes scroll events do not fire when frame dropped even if the visual have been already scrolled\n const onWheel = throttle((e: WheelEvent) => {\n if (scrollDirection === SCROLL_STOP) {\n // Scroll start should be detected with scroll event\n return;\n }\n if (e.ctrlKey) {\n // Probably a pinch-to-zoom gesture\n return;\n }\n // Get delta before checking deltaMode for firefox behavior\n // https://github.com/w3c/uievents/issues/181#issuecomment-392648065\n // https://bugzilla.mozilla.org/show_bug.cgi?id=1392460#c34\n if (isHorizontal ? e.deltaX : e.deltaY) {\n if (\n prevOffset > 0 &&\n prevOffset < store._getScrollSize() - store._getViewportSize()\n ) {\n onScrollStopped();\n }\n }\n }, 50);\n\n ro.observe(root);\n root.addEventListener(\"scroll\", onScroll);\n root.addEventListener(\"wheel\", onWheel, { passive: true });\n\n return () => {\n ro.disconnect();\n root.removeEventListener(\"scroll\", onScroll);\n root.removeEventListener(\"wheel\", onWheel);\n onScrollStopped._cancel();\n };\n },\n _initItem(el, i) {\n const ro = getResizeObserver();\n mountedIndexes.set(el, i);\n ro.observe(el);\n return () => {\n mountedIndexes.delete(el);\n ro.unobserve(el);\n };\n },\n _getActualScrollSize: getActualScrollSize,\n _scrollTo: scrollTo,\n _fixScrollJump: (jump, startIndex) => {\n // Compensate scroll jump\n if (scrollDirection === SCROLL_UP) {\n const diff = jump.reduce((acc, [, j]) => acc + j, 0);\n if (diff) {\n updateScrollPosition(diff, true);\n }\n } else if (scrollDirection === SCROLL_MANUAL) {\n const offset = store._getScrollOffset();\n if (offset === 0) {\n // Do nothing to stick to the start\n } else {\n const allDiff = jump.reduce((acc, [, j]) => acc + j, 0);\n if (\n store._getScrollSize() -\n (offset + store._getViewportSize() + allDiff) <=\n 0\n ) {\n // Keep end to stick to the end\n if (allDiff) {\n updateScrollPosition(offset + allDiff);\n }\n } else {\n // Keep start at mid\n const diff = jump.reduce((acc, [index, j]) => {\n if (index < startIndex) {\n acc += j;\n }\n return acc;\n }, 0);\n if (diff) {\n updateScrollPosition(diff, true);\n }\n }\n }\n } else {\n // NOP\n }\n },\n };\n};\n"],"names":["min","Math","max","abs","now","Date","exists","v","range","length","cb","Array","from","_","i","getItemSize","cache","index","size","_sizes","_defaultItemSize","computeOffset","isTotal","_length","_measuredOffsetIndex","_offsets","top","computeStartOffset","findIndex","distance","sum","h","findStartIndexWithOffset","offset","prevStartIndex","prevOffset","findEndIndex","resetCache","itemSize","useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect","useSyncExternalStore","subscibe","getSnapShot","_useSyncExternalStore","refKey","useStatic","init","ref","useRef","useEvent","handler","handlerRef","useCallback","args","Item","memo","_children","children","_scroller","scroller","_store","store","_index","_element","Element","_subscribe","_getItemOffset","hide","_isUnmeasuredItem","_initItem","_jsx","style","useMemo","isHorizontal","_isHorizontal","leftOrRightKey","_isRtl","margin","padding","position","display","visibility","DefaultWindow","forwardRef","scrollSize","scrolling","horizontal","rtl","jsx","width","height","minWidth","minHeight","pointerEvents","Window","_ref","_scrolling","_style","_getScrollSize","overflow","contain","List","itemSizeProp","overscan","horizontalProp","rtlProp","endThreshold","styleProp","element","itemElement","onEndReached","onScroll","onScrollProp","onScrollStop","onScrollStopProp","elements","arr","Children","forEach","e","isInvalidElement","push","elementsCount","createVirtualStore","itemCount","isRtl","_scrollToQueue","viewportWidth","viewportHeight","scrollOffset","jump","_prevRange","subscribers","Set","getViewportSize","_getRange","prevEndIndex","start","end","_hasUnmeasuredItemsInRange","startIndex","hasUnmeasuredItemsInRange","endIndex","_getScrollOffset","_getViewportSize","computeTotalSize","_getItemCount","_getJump","_getItemIndexForScrollTo","_waitForScrollDestinationItemsMeasured","Promise","resolve","reject","then","undefined","add","delete","_update","type","payload","updated","filter","updatedJump","setItemSize","_width","_height","rootRef","onEndReachedCalledIndex","mountedIndexes","reset","useState","setScrolling","createScroller","emitScrollOffsetChange","emitScrollStateChange","isNegativeOffset","rootElement","_ro","scrollDirection","resized","scrollToKey","WeakMap","getResizeObserver","ResizeObserver","entries","resizes","entry","target","contentRect","get","getActualScrollSize","scrollWidth","scrollHeight","updateScrollPosition","diff","prev","_initRoot","root","ro","syncViewportToScrollPosition","onScrollStopped","debounce","id","cancel","clearTimeout","debouncedFn","setTimeout","_cancel","isScrollStart","onWheel","throttle","time","n","ctrlKey","deltaX","deltaY","fn","observe","addEventListener","passive","disconnect","removeEventListener","el","set","unobserve","_getActualScrollSize","_scrollTo","async","getCurrentOffset","getOffset","viewportSize","_fixScrollJump","reduce","acc","j","allDiff","isScrolling","count","useImperativeHandle","scrollToIndex","scrollToOffset","startIndexWithMargin","endIndexWithMargin","items","res","key"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/src/core/utils.ts","../src/src/core/cache.ts","../src/src/react/useIsomorphicLayoutEffect.ts","../src/src/react/useSyncExternalStore.ts","../src/src/react/utils.ts","../src/src/react/useStatic.ts","../src/src/react/useRefWithUpdate.ts","../src/src/react/VList.tsx","../src/src/core/store.ts","../src/src/core/scroller.ts"],"sourcesContent":["export const min = Math.min;\nexport const max = Math.max;\nexport const abs = Math.abs;\nexport const now = Date.now;\n\nexport const exists = <T>(v: T): v is Exclude<T, null | undefined> => v != null;\n\nexport const range = <T>(length: number, cb: (i: number) => T): T[] =>\n Array.from({ length }, (_, i) => cb(i));\n\nexport const debounce = <T extends (...args: any[]) => void>(\n fn: T,\n ms: number\n) => {\n let id: NodeJS.Timeout | undefined | null;\n\n const cancel = () => {\n if (exists(id)) {\n clearTimeout(id);\n }\n };\n const debouncedFn = () => {\n cancel();\n id = setTimeout(() => {\n id = null;\n fn();\n }, ms);\n };\n debouncedFn._cancel = cancel;\n return debouncedFn;\n};\n\nexport const throttle = <T extends (...args: any[]) => void>(\n fn: T,\n ms: number\n) => {\n let time = now() - ms;\n return (...args: Parameters<T>) => {\n const n = now();\n if (time + ms < n) {\n time = n;\n fn(...args);\n }\n };\n};\n","import type { DeepReadonly, Writeable } from \"./types\";\nimport { exists, max, min, range } from \"./utils\";\n\nexport const UNCACHED = -1;\n\nexport type Cache = DeepReadonly<{\n _defaultItemSize: number;\n _length: number;\n _sizes: number[];\n _measuredOffsetIndex: number;\n _offsets: number[];\n}>;\n\nexport const getItemSize = (cache: Cache, index: number): number => {\n const size = cache._sizes[index]!;\n return size === UNCACHED ? cache._defaultItemSize : size;\n};\n\nexport const setItemSize = (\n cache: Writeable<Cache>,\n index: number,\n size: number\n) => {\n cache._sizes[index] = size;\n // mark as dirty\n cache._measuredOffsetIndex = min(index, cache._measuredOffsetIndex);\n};\n\nconst computeOffset = (\n cache: Writeable<Cache>,\n index: number,\n isTotal?: boolean\n): number => {\n if (!cache._length) return 0;\n if (cache._measuredOffsetIndex >= index) {\n if (isTotal) {\n return cache._offsets[index]! + getItemSize(cache, index);\n } else {\n return cache._offsets[index]!;\n }\n }\n\n let i = cache._measuredOffsetIndex;\n let top = cache._offsets[i]!;\n while (i <= index) {\n cache._offsets[i] = top;\n if (i === index && !isTotal) {\n break;\n }\n top += getItemSize(cache, i);\n i++;\n }\n // mark as measured\n cache._measuredOffsetIndex = index;\n return top;\n};\n\nexport const computeTotalSize = (cache: Writeable<Cache>): number => {\n return computeOffset(cache, cache._length - 1, true);\n};\n\nexport const computeStartOffset = (\n cache: Writeable<Cache>,\n index: number\n): number => {\n return computeOffset(cache, index);\n};\n\nconst findIndex = (cache: Cache, i: number, distance: number): number => {\n let sum = 0;\n if (distance >= 0) {\n // search forward\n while (i < cache._length - 1) {\n const h = getItemSize(cache, i++);\n if ((sum += h) >= distance) {\n if (sum - h / 2 >= distance) {\n i--;\n }\n break;\n }\n }\n } else {\n // search backward\n while (i > 0) {\n const h = getItemSize(cache, --i);\n if ((sum -= h) <= distance) {\n if (sum + h / 2 < distance) {\n i++;\n }\n break;\n }\n }\n }\n\n return min(max(i, 0), cache._length - 1);\n};\n\nexport const findStartIndexWithOffset = (\n cache: Cache,\n offset: number,\n prevStartIndex: number,\n prevOffset: number\n): number => {\n return findIndex(cache, prevStartIndex, offset - prevOffset);\n};\n\nexport const findEndIndex = findIndex;\n\nexport const hasUnmeasuredItemsInRange = (\n cache: Cache,\n startIndex: number,\n endIndex: number\n): boolean => {\n for (let i = startIndex; i <= endIndex; i++) {\n if (cache._sizes[i] === UNCACHED) {\n return true;\n }\n }\n return false;\n};\n\nexport const resetCache = (\n length: number,\n itemSize: number,\n cache?: Cache\n): Cache => {\n return {\n _defaultItemSize: itemSize,\n _length: length,\n _measuredOffsetIndex: cache\n ? min(cache._measuredOffsetIndex, length - 1)\n : 0,\n _sizes: range(length, (i) => {\n const size = cache && cache._sizes[i];\n if (exists(size)) {\n return size;\n }\n return UNCACHED;\n }),\n _offsets: range(length, (i) => {\n if (i === 0) {\n // first offset must be 0\n return 0;\n }\n const offset = cache && cache._offsets[i];\n if (exists(offset)) {\n return offset;\n }\n return UNCACHED;\n }),\n };\n};\n","import { useEffect, useLayoutEffect } from \"react\";\n\n// https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85\nexport const useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n","import { useSyncExternalStore as _useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\n\nexport const useSyncExternalStore = <T>(\n subscibe: (onStoreChange: () => void) => () => void,\n getSnapShot: () => T\n): T => {\n return _useSyncExternalStore(subscibe, getSnapShot, getSnapShot);\n};\n","export const refKey = \"current\";\n","import { useRef } from \"react\";\nimport { refKey } from \"./utils\";\n\nexport const useStatic = <T>(init: () => T): T => {\n const ref = useRef<T>();\n return ref[refKey] || (ref[refKey] = init());\n};\n","import { useRef } from \"react\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\nimport { refKey } from \"./utils\";\n\nexport const useRefWithUpdate = <T>(value: T) => {\n const ref = useRef<T>(value);\n\n useIsomorphicLayoutEffect(() => {\n ref[refKey] = value;\n }, [value]);\n\n return ref;\n};\n","import {\n Children,\n memo,\n useRef,\n useMemo,\n CSSProperties,\n ReactElement,\n forwardRef,\n useImperativeHandle,\n ReactNode,\n useEffect,\n RefObject,\n useState,\n ReactFragment,\n} from \"react\";\nimport {\n ACTION_UPDATE_CACHE_LENGTH,\n VirtualStore,\n createVirtualStore,\n} from \"../core/store\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\nimport { useSyncExternalStore } from \"./useSyncExternalStore\";\nimport { exists, max, min } from \"../core/utils\";\nimport { createScroller, Scroller } from \"../core/scroller\";\nimport { refKey } from \"./utils\";\nimport { useStatic } from \"./useStatic\";\nimport { useRefWithUpdate } from \"./useRefWithUpdate\";\n\ntype ItemProps = {\n _children: ReactNode;\n _scroller: Scroller;\n _store: VirtualStore;\n _index: number;\n _element: \"div\";\n};\n\nconst Item = memo(\n ({\n _children: children,\n _scroller: scroller,\n _store: store,\n _index: index,\n _element: Element,\n }: ItemProps): ReactElement => {\n const ref = useRef<HTMLDivElement>(null);\n\n const offset = useSyncExternalStore(store._subscribe, () =>\n store._getItemOffset(index)\n );\n const hide = useSyncExternalStore(store._subscribe, () =>\n store._isUnmeasuredItem(index)\n );\n\n // The index may be changed if elements are inserted to or removed from the start of props.children\n useIsomorphicLayoutEffect(\n () => scroller._initItem(ref[refKey]!, index),\n [index]\n );\n\n return (\n <Element\n ref={ref}\n style={useMemo((): CSSProperties => {\n const isHorizontal = store._isHorizontal();\n const leftOrRightKey = store._isRtl() ? \"right\" : \"left\";\n const style: CSSProperties = {\n margin: 0,\n padding: 0,\n position: \"absolute\",\n [isHorizontal ? \"height\" : \"width\"]: \"100%\",\n [isHorizontal ? \"top\" : leftOrRightKey]: 0,\n [isHorizontal ? leftOrRightKey : \"top\"]: offset,\n visibility: hide ? \"hidden\" : \"visible\",\n // willChange: \"transform\",\n };\n if (isHorizontal) {\n style.display = \"flex\";\n }\n return style;\n }, [offset, hide])}\n >\n {children}\n </Element>\n );\n }\n);\n\nconst isInvalidElement = <T extends ReactNode>(\n e: T\n): e is Extract<T, null | undefined | boolean> =>\n !exists(e) || typeof e === \"boolean\";\n\nexport type WindowComponentAttributes = Pick<\n React.HTMLAttributes<HTMLElement>,\n \"className\" | \"style\" | \"id\" | \"role\" | \"tabIndex\"\n> &\n React.AriaAttributes;\n\n/**\n * Props of customized scrollable component.\n */\nexport interface CustomWindowComponentProps {\n children: ReactNode;\n scrollSize: number;\n scrolling: boolean;\n horizontal: boolean;\n attrs: WindowComponentAttributes;\n}\n\nconst DefaultWindow = forwardRef<any, CustomWindowComponentProps>(\n (\n { children, scrollSize, scrolling, horizontal, attrs },\n ref\n ): ReactElement => {\n return (\n <div ref={ref} {...attrs}>\n <div\n style={useMemo((): CSSProperties => {\n return {\n position: \"relative\",\n visibility: \"hidden\",\n width: horizontal ? scrollSize : \"100%\",\n height: horizontal ? \"100%\" : scrollSize,\n pointerEvents: scrolling ? \"none\" : \"auto\",\n };\n }, [scrollSize, scrolling])}\n >\n {children}\n </div>\n </div>\n );\n }\n);\n\nexport type CustomWindowComponent = typeof DefaultWindow;\n\nconst Window = ({\n _children: children,\n _ref: ref,\n _store: store,\n _element: Element,\n _scrolling: scrolling,\n _attrs: attrs,\n}: {\n _children: ReactNode;\n _ref: RefObject<HTMLDivElement>;\n _store: VirtualStore;\n _element: CustomWindowComponent;\n _scrolling: boolean;\n _attrs: WindowComponentAttributes;\n}) => {\n const scrollSize = useSyncExternalStore(\n store._subscribe,\n store._getScrollSize\n );\n\n const horizontal = store._isHorizontal();\n\n return (\n <Element\n ref={ref}\n scrollSize={scrollSize}\n scrolling={scrolling}\n horizontal={horizontal}\n attrs={useMemo(\n () => ({\n ...attrs,\n style: {\n overflow: horizontal ? \"auto hidden\" : \"hidden auto\",\n contain: \"strict\",\n // transform: \"translate3d(0px, 0px, 0px)\",\n // willChange: \"scroll-position\",\n // backfaceVisibility: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n padding: 0,\n margin: 0,\n ...attrs.style,\n },\n }),\n [attrs]\n )}\n >\n {children}\n </Element>\n );\n};\n\n/**\n * Props of customized item component.\n */\nexport interface CustomItemComponentProps {\n style: CSSProperties;\n children: ReactNode;\n}\n\nexport type CustomItemComponent = React.ForwardRefExoticComponent<\n React.PropsWithoutRef<CustomItemComponentProps> & React.RefAttributes<any>\n>;\n\ntype CustomItemComponentOrElement =\n | keyof JSX.IntrinsicElements\n | CustomItemComponent;\n\n/**\n * Methods of {@link VList}.\n */\nexport interface VListHandle {\n /**\n * Get current scrollTop or scrollLeft.\n */\n readonly scrollOffset: number;\n /**\n * Get current scrollHeight or scrollWidth.\n */\n readonly scrollSize: number;\n /**\n * Get current offsetHeight or offsetWidth.\n */\n readonly viewportSize: number;\n /**\n * Scroll to the item specified by index.\n * @param index index of item\n */\n scrollToIndex(index: number): void;\n /**\n * Scroll to the given offset.\n * @param offset offset from start\n */\n scrollTo(offset: number): void;\n /**\n * Scroll by the given offset.\n * @param offset offset from current position\n */\n scrollBy(offset: number): void;\n}\n\n/**\n * Props of {@link VList}.\n */\nexport interface VListProps extends WindowComponentAttributes {\n /**\n * Elements rendered by this component.\n */\n children: ReactNode;\n /**\n * Item size hint for unmeasured items. It's recommended to specify this prop if item sizes are fixed and known, or much larger than the defaultValue. It will help to reduce scroll jump when items are measured.\n * @defaultValue 40\n */\n itemSize?: number;\n /**\n * Number of items to render above/below the visible bounds of the list. You can increase to avoid showing blank items in fast scrolling.\n * @defaultValue 4\n */\n overscan?: number;\n /**\n * If true, rendered as a horizontally scrollable list. Otherwise rendered as a vertically scrollable list.\n */\n horizontal?: boolean;\n /**\n * You have to set true if you use this component under `direction: rtl` style.\n */\n rtl?: boolean;\n /**\n * Customized element type for scrollable element. This element will get {@link CustomWindowComponentProps} as props.\n * @defaultValue {@link DefaultWindow}\n */\n element?: CustomWindowComponent;\n /**\n * Customized element type for item element. This element will get {@link CustomItemComponentProps} as props.\n * @defaultValue \"div\"\n */\n itemElement?: CustomItemComponentOrElement;\n /**\n * Callback invoked whenever scroll offset changes.\n * @param offset Current scrollTop or scrollLeft.\n */\n onScroll?: (offset: number) => void;\n /**\n * Callback invoked when scrolling stops.\n */\n onScrollStop?: () => void;\n /**\n * Callback invoked when visible items range changes.\n * @param payload `start` is the start index of viewable items. `end` is the end index of viewable items. `count` is the total count of items.\n */\n onRangeChange?: (payload: {\n start: number;\n end: number;\n count: number;\n }) => void;\n}\n\n/**\n * Virtualized list component. See {@link VListProps} and {@link VListHandle}.\n */\nexport const VList = forwardRef<VListHandle, VListProps>(\n (\n {\n children,\n itemSize: itemSizeProp = 40,\n overscan = 4,\n horizontal: horizontalProp,\n rtl: rtlProp,\n element = DefaultWindow,\n itemElement = \"div\",\n onScroll: onScrollProp,\n onScrollStop: onScrollStopProp,\n onRangeChange: onRangeChangeProp,\n ...windowAttrs\n },\n ref\n ): ReactElement => {\n // Memoize element array\n const elements = useMemo(() => {\n const arr: (ReactElement | ReactFragment | string | number)[] = [];\n Children.forEach(children, (e) => {\n if (isInvalidElement(e)) {\n return;\n }\n arr.push(e);\n });\n return arr;\n }, [children]);\n const elementsCount = elements.length;\n\n // https://github.com/facebook/react/issues/25191#issuecomment-1237456448\n const store = useStatic(() =>\n createVirtualStore(\n elementsCount,\n itemSizeProp,\n !!horizontalProp,\n !!rtlProp\n )\n );\n const [startIndex, endIndex] = useSyncExternalStore(\n store._subscribe,\n store._getRange\n );\n const jump = useSyncExternalStore(store._subscribe, store._getJump);\n const rootRef = useRef<HTMLDivElement>(null);\n\n const onScroll = useRefWithUpdate(onScrollProp);\n const onScrollStop = useRefWithUpdate(onScrollStopProp);\n\n const [mountedIndexes, reset] = useState<Set<number>>(new Set<number>());\n const [scrolling, setScrolling] = useState(false);\n const scroller = useStatic(() =>\n createScroller(\n store,\n (offset) => {\n onScroll[refKey] && onScroll[refKey](offset);\n },\n (isScrolling) => {\n setScrolling(isScrolling);\n if (!isScrolling) {\n reset(new Set());\n onScrollStop[refKey] && onScrollStop[refKey]();\n }\n }\n )\n );\n\n // The elements length and cached items length are different just after element is added/removed.\n const count = min(elementsCount, store._getItemCount());\n\n // So update cache length. Updating state in render will cause warn so use useEffect for now.\n useIsomorphicLayoutEffect(() => {\n store._update(ACTION_UPDATE_CACHE_LENGTH, elementsCount);\n }, [elementsCount]);\n\n useIsomorphicLayoutEffect(() => scroller._initRoot(rootRef[refKey]!), []);\n\n useIsomorphicLayoutEffect(() => {\n if (!jump.length) return;\n\n scroller._fixScrollJump(jump, startIndex);\n }, [jump]);\n\n useEffect(() => {\n if (!onRangeChangeProp) return;\n\n onRangeChangeProp({\n start: startIndex,\n end: endIndex,\n count,\n });\n }, [startIndex, endIndex]);\n\n useImperativeHandle(\n ref,\n () => {\n return {\n get scrollOffset() {\n return store._getScrollOffset();\n },\n get scrollSize() {\n return scroller._getActualScrollSize();\n },\n get viewportSize() {\n return store._getViewportSize();\n },\n scrollToIndex(index) {\n scroller._scrollToIndex(index, count);\n },\n scrollTo: scroller._scrollTo,\n scrollBy(offset) {\n scroller._scrollTo(store._getScrollOffset() + offset);\n },\n };\n },\n [count]\n );\n\n const startIndexWithMargin = max(startIndex - overscan, 0);\n const endIndexWithMargin = min(endIndex + overscan, count - 1);\n const items = useMemo(() => {\n const res: ReactElement[] = [];\n for (let i = startIndexWithMargin; i <= endIndexWithMargin; i++) {\n // https://github.com/sergi/virtual-list/commit/8e7e06dc63568334c1ab809ea83c1be36572e9ed\n mountedIndexes.add(i);\n }\n mountedIndexes.forEach((i) => {\n const e = elements[i];\n // This can be undefined when items are removed\n if (exists(e)) {\n res.push(\n <Item\n key={(e as { key?: ReactElement[\"key\"] })?.key || i}\n _scroller={scroller}\n _store={store}\n _index={i}\n _element={itemElement as \"div\"}\n _children={e}\n />\n );\n }\n });\n return res;\n }, [elements, mountedIndexes, startIndexWithMargin, endIndexWithMargin]);\n\n return (\n <Window\n _ref={rootRef}\n _store={store}\n _element={element}\n _scrolling={scrolling}\n _children={items}\n _attrs={windowAttrs}\n />\n );\n }\n);\n","import {\n findStartIndexWithOffset,\n resetCache,\n getItemSize,\n computeTotalSize,\n findEndIndex,\n computeStartOffset,\n Cache,\n UNCACHED,\n setItemSize,\n hasUnmeasuredItemsInRange,\n} from \"./cache\";\nimport type { Writeable } from \"./types\";\n\nexport type ScrollJump = Readonly<[index: number, sizeDiff: number][]>;\nexport type ItemResize = [index: number, size: number];\ntype ItemsRange = [startIndex: number, endIndex: number];\n\nexport const ACTION_UPDATE_CACHE_LENGTH = 0;\nexport const ACTION_UPDATE_ITEM_SIZES = 1;\nexport const ACTION_UPDATE_VIEWPORT = 2;\nexport const ACTION_HANDLE_SCROLL = 3;\n\ntype Actions =\n | [type: typeof ACTION_UPDATE_CACHE_LENGTH, length: number]\n | [type: typeof ACTION_UPDATE_ITEM_SIZES, entries: ItemResize[]]\n | [\n type: typeof ACTION_UPDATE_VIEWPORT,\n rect: { _width: number; _height: number }\n ]\n | [type: typeof ACTION_HANDLE_SCROLL, offset: number];\n\nexport type VirtualStore = {\n _getRange(): ItemsRange;\n _isUnmeasuredItem(index: number): boolean;\n _hasUnmeasuredItemsInRange(startIndex: number): boolean;\n _getItemOffset(index: number): number;\n _getScrollOffset(): number;\n _getViewportSize(): number;\n _getScrollSize(): number;\n _getItemCount(): number;\n _getJump(): ScrollJump;\n _isHorizontal(): boolean;\n _isRtl(): boolean;\n _getItemIndexForScrollTo(offset: number): number;\n _waitForScrollDestinationItemsMeasured(): Promise<void>;\n _subscribe(cb: () => void): () => void;\n _update(...action: Actions): void;\n};\n\nexport const createVirtualStore = (\n itemCount: number,\n itemSize: number,\n isHorizontal: boolean,\n isRtl: boolean\n): VirtualStore => {\n let viewportWidth = 0;\n let viewportHeight = 0;\n let scrollOffset = 0;\n let jump: ScrollJump = [];\n let cache = resetCache(itemCount, itemSize);\n let _prevRange: ItemsRange = [0, 0];\n let _scrollToQueue: [() => void, () => void] | undefined;\n\n const subscribers = new Set<() => void>();\n const getViewportSize = (): number =>\n isHorizontal ? viewportWidth : viewportHeight;\n\n return {\n _getRange() {\n const [prevStartIndex, prevEndIndex] = _prevRange;\n const prevOffset = computeStartOffset(\n cache as Writeable<Cache>,\n prevStartIndex\n );\n const start = findStartIndexWithOffset(\n cache,\n scrollOffset,\n prevStartIndex,\n prevOffset\n );\n const end = findEndIndex(cache, start, getViewportSize());\n if (prevStartIndex === start && prevEndIndex === end) {\n return _prevRange;\n }\n return (_prevRange = [start, end]);\n },\n _isUnmeasuredItem(index) {\n return cache._sizes[index] === UNCACHED;\n },\n _hasUnmeasuredItemsInRange(startIndex) {\n return hasUnmeasuredItemsInRange(\n cache,\n startIndex,\n findEndIndex(cache, startIndex, getViewportSize())\n );\n },\n _getItemOffset(index) {\n return computeStartOffset(cache as Writeable<Cache>, index);\n },\n _getScrollOffset() {\n return scrollOffset;\n },\n _getViewportSize() {\n return getViewportSize();\n },\n _getScrollSize() {\n return computeTotalSize(cache as Writeable<Cache>);\n },\n _getItemCount() {\n return cache._length;\n },\n _getJump() {\n return jump;\n },\n _isHorizontal() {\n return isHorizontal;\n },\n _isRtl() {\n return isRtl;\n },\n _getItemIndexForScrollTo(offset) {\n return findStartIndexWithOffset(cache, offset, 0, 0);\n },\n _waitForScrollDestinationItemsMeasured() {\n if (_scrollToQueue) {\n // Cancel waiting scrollTo\n _scrollToQueue[1]();\n }\n // The measurement will be done asynchronously and the timing is not predictable so we use promise.\n // For example, ResizeObserver may not fire when window is not visible.\n return new Promise((resolve, reject) => {\n _scrollToQueue = [\n () => {\n // HACK: It should be resolved in the next microtask that is after React's render\n Promise.resolve().then(() => {\n resolve();\n _scrollToQueue = undefined;\n });\n },\n reject,\n ];\n });\n },\n _subscribe(cb) {\n subscribers.add(cb);\n return () => {\n subscribers.delete(cb);\n };\n },\n _update(type, payload) {\n const mutated = ((): boolean => {\n switch (type) {\n case ACTION_UPDATE_CACHE_LENGTH: {\n if (cache._length === payload) return false;\n cache = resetCache(payload, itemSize, cache);\n return true;\n }\n case ACTION_UPDATE_ITEM_SIZES: {\n const updated = payload.filter(\n ([index, size]) => cache._sizes[index] !== size\n );\n // Skip if all items are cached and not updated\n if (!updated.length) {\n return false;\n }\n\n const updatedJump: [index: number, sizeDiff: number][] = [];\n updated.forEach(([index, size]) => {\n updatedJump.push([index, size - getItemSize(cache, index)]);\n setItemSize(cache as Writeable<Cache>, index, size);\n });\n jump = updatedJump;\n return true;\n }\n case ACTION_UPDATE_VIEWPORT: {\n if (\n viewportWidth === payload._width &&\n viewportHeight === payload._height\n ) {\n return false;\n }\n viewportWidth = payload._width;\n viewportHeight = payload._height;\n return true;\n }\n case ACTION_HANDLE_SCROLL: {\n const prevOffset = scrollOffset;\n return (scrollOffset = payload) !== prevOffset;\n }\n }\n })();\n\n if (mutated) {\n subscribers.forEach((cb) => {\n cb();\n });\n if (_scrollToQueue && type === ACTION_UPDATE_ITEM_SIZES) {\n _scrollToQueue[0]();\n }\n }\n },\n };\n};\n","import {\n ACTION_HANDLE_SCROLL,\n ACTION_UPDATE_ITEM_SIZES,\n ACTION_UPDATE_VIEWPORT,\n ItemResize,\n ScrollJump,\n VirtualStore,\n} from \"./store\";\nimport { abs, debounce, throttle, exists, max, min } from \"./utils\";\n\nexport const SCROLL_STOP = 0;\nexport const SCROLL_DOWN = 1;\nexport const SCROLL_UP = 2;\nexport const SCROLL_MANUAL = 3;\ntype ScrollDirection =\n | typeof SCROLL_STOP\n | typeof SCROLL_DOWN\n | typeof SCROLL_UP\n | typeof SCROLL_MANUAL;\n\nexport type Scroller = {\n _initRoot: (rootElement: HTMLElement) => () => void;\n _initItem: (itemElement: HTMLElement, index: number) => () => void;\n _getActualScrollSize: () => number;\n _scrollTo: (offset: number) => void;\n _scrollToIndex: (index: number, count: number) => void;\n _fixScrollJump: (jump: ScrollJump, startIndex: number) => void;\n};\n\nexport const createScroller = (\n store: VirtualStore,\n emitScrollOffsetChange: (offset: number) => void,\n emitScrollStateChange: (scrolling: boolean) => void\n): Scroller => {\n let prevOffset = -1;\n let scrollDirection: ScrollDirection = SCROLL_STOP;\n let resized = false;\n let isNegativeOffset: boolean | undefined;\n let rootElement: HTMLElement | undefined;\n let _ro: ResizeObserver | undefined;\n const isHorizontal = store._isHorizontal();\n const isRtl = store._isRtl();\n const scrollToKey = isHorizontal ? \"scrollLeft\" : \"scrollTop\";\n const mountedIndexes = new WeakMap<Element, number>();\n const getResizeObserver = (): ResizeObserver => {\n // Initialize ResizeObserver lazily for SSR\n return (\n _ro ||\n (_ro = new ResizeObserver((entries) => {\n // https://www.w3.org/TR/resize-observer/#intro\n const resizes: ItemResize[] = [];\n for (const entry of entries) {\n if (entry.target === rootElement) {\n store._update(ACTION_UPDATE_VIEWPORT, {\n _width: entry.contentRect.width,\n _height: entry.contentRect.height,\n });\n } else {\n const index = mountedIndexes.get(entry.target);\n if (exists(index)) {\n resizes.push([\n index,\n entry.contentRect[isHorizontal ? \"width\" : \"height\"],\n ]);\n }\n }\n }\n\n if (resizes.length) {\n store._update(ACTION_UPDATE_ITEM_SIZES, resizes);\n resized = true;\n }\n }))\n );\n };\n const getActualScrollSize = (): number => {\n if (!rootElement) return 0;\n // Use element's scrollHeight/scrollWidth instead of stored scrollSize.\n // This is because stored size may differ from the actual size, for example when a new item is added and not yet measured.\n return store._isHorizontal()\n ? rootElement.scrollWidth\n : rootElement.scrollHeight;\n };\n const updateScrollPosition = (offset: number, diff?: boolean) => {\n if (!rootElement) return;\n if (isRtl) {\n if (!exists(isNegativeOffset)) {\n // Assume offset type in rtl direction.\n // The scroll position is negative in spec however its not in some browsers, for example Chrome earlier than v85.\n // https://github.com/othree/jquery.rtl-scroll-type\n const prev = rootElement[scrollToKey];\n rootElement[scrollToKey] = 1;\n isNegativeOffset = rootElement[scrollToKey] === 0;\n rootElement[scrollToKey] = prev;\n }\n if (isNegativeOffset) {\n offset *= -1;\n }\n }\n if (diff) {\n rootElement[scrollToKey] += offset;\n } else {\n rootElement[scrollToKey] = offset;\n scrollDirection = SCROLL_MANUAL;\n }\n };\n const scrollTo = async (index: number, getCurrentOffset: () => number) => {\n const getOffset = (): number => {\n let offset = getCurrentOffset();\n const scrollSize = getActualScrollSize();\n const viewportSize = store._getViewportSize();\n if (scrollSize - (offset + viewportSize) <= 0) {\n // Adjust if the offset is over the end, to get correct startIndex.\n offset = scrollSize - viewportSize;\n }\n return offset;\n };\n\n if (store._hasUnmeasuredItemsInRange(index)) {\n do {\n // In order to scroll to the correct position, mount the items and measure their sizes before scrolling.\n store._update(ACTION_HANDLE_SCROLL, getOffset());\n try {\n // Wait for the scroll destination items to be measured.\n await store._waitForScrollDestinationItemsMeasured();\n } catch (e) {\n // canceled\n return;\n }\n } while (store._hasUnmeasuredItemsInRange(index));\n\n // Scroll with the updated value\n updateScrollPosition(getOffset());\n } else {\n const offset = getOffset();\n updateScrollPosition(offset);\n // Sync viewport to scroll destination\n store._update(ACTION_HANDLE_SCROLL, offset);\n }\n };\n\n const calcTotalJump = (jump: ScrollJump): number =>\n jump.reduce((acc, [, j]) => acc + j, 0);\n\n return {\n _initRoot(root) {\n rootElement = root;\n const ro = getResizeObserver();\n\n const syncViewportToScrollPosition = () => {\n let offset = root[scrollToKey];\n if (isRtl) {\n // The scroll position may be negative value in rtl direction.\n // https://github.com/othree/jquery.rtl-scroll-type\n offset = abs(offset);\n }\n if (prevOffset === offset) {\n return;\n }\n // Skip scroll direction detection just after resizing because it may result in the opposite direction.\n // Scroll events are dispatched enough so it's ok to skip some of them.\n if (scrollDirection === SCROLL_STOP || !resized) {\n // Ignore until manual scrolling\n if (scrollDirection !== SCROLL_MANUAL) {\n scrollDirection = prevOffset > offset ? SCROLL_UP : SCROLL_DOWN;\n }\n } else {\n resized = false;\n }\n store._update(ACTION_HANDLE_SCROLL, (prevOffset = offset));\n emitScrollOffsetChange(offset);\n };\n\n const onScrollStopped = debounce(() => {\n // Check scroll position once just after scrolling stopped\n syncViewportToScrollPosition();\n scrollDirection = SCROLL_STOP;\n emitScrollStateChange(false);\n }, 150);\n\n const onScroll = () => {\n const isScrollStart = scrollDirection === SCROLL_STOP;\n syncViewportToScrollPosition();\n if (isScrollStart) {\n emitScrollStateChange(true);\n }\n onScrollStopped();\n };\n\n // Infer scroll state also from wheel events\n // Sometimes scroll events do not fire when frame dropped even if the visual have been already scrolled\n const onWheel = throttle((e: WheelEvent) => {\n if (scrollDirection === SCROLL_STOP) {\n // Scroll start should be detected with scroll event\n return;\n }\n if (e.ctrlKey) {\n // Probably a pinch-to-zoom gesture\n return;\n }\n // Get delta before checking deltaMode for firefox behavior\n // https://github.com/w3c/uievents/issues/181#issuecomment-392648065\n // https://bugzilla.mozilla.org/show_bug.cgi?id=1392460#c34\n if (isHorizontal ? e.deltaX : e.deltaY) {\n if (\n prevOffset > 0 &&\n prevOffset < store._getScrollSize() - store._getViewportSize()\n ) {\n onScrollStopped();\n }\n }\n }, 50);\n\n ro.observe(root);\n root.addEventListener(\"scroll\", onScroll);\n root.addEventListener(\"wheel\", onWheel, { passive: true });\n\n return () => {\n ro.disconnect();\n root.removeEventListener(\"scroll\", onScroll);\n root.removeEventListener(\"wheel\", onWheel);\n onScrollStopped._cancel();\n };\n },\n _initItem(el, i) {\n const ro = getResizeObserver();\n mountedIndexes.set(el, i);\n ro.observe(el);\n return () => {\n mountedIndexes.delete(el);\n ro.unobserve(el);\n };\n },\n _getActualScrollSize: getActualScrollSize,\n _scrollTo(offset) {\n offset = max(offset, 0);\n\n scrollTo(store._getItemIndexForScrollTo(offset), () => offset);\n },\n _scrollToIndex(index, count) {\n index = max(min(index, count - 1), 0);\n\n scrollTo(index, () => store._getItemOffset(index));\n },\n _fixScrollJump: (jump, startIndex) => {\n // Compensate scroll jump\n if (scrollDirection === SCROLL_UP) {\n const diff = calcTotalJump(jump);\n if (diff) {\n updateScrollPosition(diff, true);\n }\n } else if (scrollDirection === SCROLL_MANUAL) {\n const offset = store._getScrollOffset();\n if (offset === 0) {\n // Do nothing to stick to the start\n } else {\n const allDiff = calcTotalJump(jump);\n if (\n store._getScrollSize() -\n (offset + store._getViewportSize() + allDiff) <=\n 0\n ) {\n // Keep end to stick to the end\n if (allDiff) {\n updateScrollPosition(offset + allDiff);\n }\n } else {\n // Keep start at mid\n const diff = jump.reduce((acc, [index, j]) => {\n if (index < startIndex) {\n acc += j;\n }\n return acc;\n }, 0);\n if (diff) {\n updateScrollPosition(diff, true);\n }\n }\n }\n } else {\n // NOP\n }\n },\n };\n};\n"],"names":["min","Math","max","abs","now","Date","exists","v","range","length","cb","Array","from","_","i","getItemSize","cache","index","size","_sizes","_defaultItemSize","computeOffset","isTotal","_length","_measuredOffsetIndex","_offsets","top","computeStartOffset","findIndex","distance","sum","h","findStartIndexWithOffset","offset","prevStartIndex","prevOffset","findEndIndex","resetCache","itemSize","useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect","useSyncExternalStore","subscibe","getSnapShot","_useSyncExternalStore","refKey","useStatic","init","ref","useRef","useRefWithUpdate","value","Item","memo","_children","children","_scroller","scroller","_store","store","_index","_element","Element","_subscribe","_getItemOffset","hide","_isUnmeasuredItem","_initItem","_jsx","style","useMemo","isHorizontal","_isHorizontal","leftOrRightKey","_isRtl","margin","padding","position","visibility","display","DefaultWindow","forwardRef","scrollSize","scrolling","horizontal","attrs","jsx","width","height","pointerEvents","Window","_ref","_scrolling","_attrs","_getScrollSize","overflow","contain","VList","itemSizeProp","overscan","horizontalProp","rtl","rtlProp","element","itemElement","onScroll","onScrollProp","onScrollStop","onScrollStopProp","onRangeChange","onRangeChangeProp","windowAttrs","elements","arr","Children","forEach","e","isInvalidElement","push","elementsCount","createVirtualStore","itemCount","isRtl","_scrollToQueue","viewportWidth","viewportHeight","scrollOffset","jump","_prevRange","subscribers","Set","getViewportSize","_getRange","prevEndIndex","start","end","_hasUnmeasuredItemsInRange","startIndex","hasUnmeasuredItemsInRange","endIndex","_getScrollOffset","_getViewportSize","computeTotalSize","_getItemCount","_getJump","_getItemIndexForScrollTo","_waitForScrollDestinationItemsMeasured","Promise","resolve","reject","then","undefined","add","delete","_update","type","payload","updated","filter","updatedJump","setItemSize","_width","_height","rootRef","mountedIndexes","reset","useState","setScrolling","createScroller","emitScrollOffsetChange","emitScrollStateChange","isNegativeOffset","rootElement","_ro","scrollDirection","resized","scrollToKey","WeakMap","getResizeObserver","ResizeObserver","entries","resizes","entry","target","contentRect","get","getActualScrollSize","scrollWidth","scrollHeight","updateScrollPosition","diff","prev","scrollTo","async","getCurrentOffset","getOffset","viewportSize","calcTotalJump","reduce","acc","j","_initRoot","root","ro","syncViewportToScrollPosition","onScrollStopped","debounce","id","cancel","clearTimeout","debouncedFn","setTimeout","_cancel","isScrollStart","onWheel","throttle","time","args","n","ctrlKey","deltaX","deltaY","fn","observe","addEventListener","passive","disconnect","removeEventListener","el","set","unobserve","_getActualScrollSize","_scrollTo","_scrollToIndex","count","_fixScrollJump","allDiff","isScrolling","useImperativeHandle","scrollToIndex","scrollBy","startIndexWithMargin","endIndexWithMargin","items","res","key"],"mappings":"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"}
package/lib/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{jsx as e}from"react/jsx-runtime";import{useLayoutEffect as t,useEffect as r,useRef as n,useCallback as o,memo as l,useMemo as s,forwardRef as i,Children as c,useState as u,useImperativeHandle as a}from"react";import{useSyncExternalStore as f}from"use-sync-external-store/shim/index.js";const d=Math.min,_=Math.max,h=Math.abs,m=Date.now,g=e=>null!=e,p=(e,t)=>Array.from({length:e},((e,r)=>t(r))),S=(e,t)=>{const r=e.t[t];return-1===r?e.o:r},w=(e,t,r)=>{if(!e.l)return 0;if(e.i>=t)return r?e.u[t]+S(e,t):e.u[t];let n=e.i,o=e.u[n];for(;n<=t&&(e.u[n]=o,n!==t||r);)o+=S(e,n),n++;return e.i=t,o},y=(e,t)=>w(e,t),z=(e,t,r)=>{let n=0;if(r>=0)for(;t<e.l-1;){const o=S(e,t++);if((n+=o)>=r){n-o/2>=r&&t--;break}}else for(;t>0;){const o=S(e,--t);if((n-=o)<=r){n+o/2<r&&t++;break}}return d(_(t,0),e.l-1)},x=(e,t,r,n)=>z(e,r,t-n),I=z,v=(e,t,r)=>({o:t,l:e,i:r?d(r.i,e-1):0,t:p(e,(e=>{const t=r&&r.t[e];return g(t)?t:-1})),u:p(e,(e=>{if(0===e)return 0;const t=r&&r.u[e];return g(t)?t:-1}))}),b="undefined"!=typeof window?t:r,T=(e,t)=>f(e,t,t),O="current",R=e=>{const t=n();return t[O]||(t[O]=e())},M=e=>{const t=n(e);return b((()=>{t[O]=e}),[e]),o(((...e)=>{t[O]&&t[O](...e)}),[])},E=/*#__PURE__*/l((({_:t,h:r,m:o,g:l,p:i})=>{const c=n(null),u=T(o.S,(()=>o.I(l))),a=T(o.S,(()=>o.v(l)));return b((()=>r.T(c[O],l)),[l]),e(i,{ref:c,style:s((()=>{const e=o.O(),t=o.R()?"right":"left",r={margin:0,padding:0,position:"absolute",[e?"height":"width"]:"100%",[e?"top":t]:0,[e?t:"top"]:u};return e&&(r.display="flex"),a&&(r.visibility="hidden"),r}),[u,a]),children:t})})),k=/*#__PURE__*/i((({children:t,style:r,scrollSize:n,scrolling:o,horizontal:l,rtl:i},c)=>e("div",{ref:c,style:r,children:e("div",{style:s((()=>{const e=l?n:"100%",t=l?"100%":n;return{position:"absolute",top:0,[i?"right":"left"]:0,width:e,height:t,minWidth:e,minHeight:t,pointerEvents:o?"none":"auto"}}),[n,o]),children:t})}))),j=({_:t,M:r,m:n,p:o,k:l,j:i})=>{const c=T(n.S,n.A),u=n.O();return e(o,{ref:r,scrollSize:c,scrolling:l,horizontal:u,rtl:n.R(),style:s((()=>({overflow:u?"auto hidden":"hidden auto",position:"relative",contain:"strict",width:"100%",height:"100%",padding:0,margin:0,...i})),[i]),children:t})},A=/*#__PURE__*/i((({children:t,itemSize:o=40,overscan:l=4,horizontal:i,rtl:f,endThreshold:p=0,style:z,element:A=k,itemElement:D="div",onEndReached:F,onScroll:H,onScrollStop:J},P)=>{const U=s((()=>{const e=[];return c.forEach(t,(t=>{(e=>!g(e)||"boolean"==typeof e)(t)||e.push(t)})),e}),[t]),W=U.length,C=R((()=>((e,t,r,n)=>{let o,l=0,s=0,i=0,c=[],u=v(e,t),a=[0,0];const f=new Set,_=()=>r?l:s;return{D(){const[e,t]=a,r=y(u,e),n=x(u,i,e,r),o=I(u,n,_());return e===n&&t===o?a:a=[n,o]},v:e=>-1===u.t[e],F:e=>((e,t,r)=>{for(let n=t;n<=r;n++)if(-1===e.t[n])return!0;return!1})(u,e,I(u,e,_())),I:e=>y(u,e),H:()=>i,J:()=>_(),A:()=>(e=>w(e,e.l-1,!0))(u),P:()=>u.l,U:()=>c,O:()=>r,R:()=>n,W:e=>x(u,e,0,0),C:()=>(o&&o[1](),new Promise(((e,t)=>{o=[()=>{Promise.resolve().then((()=>{e(),o=void 0}))},t]}))),S:e=>(f.add(e),()=>{f.delete(e)}),L(e,r){(()=>{switch(e){case 0:return u.l!==r&&(u=v(r,t,u),!0);case 1:{const e=r.filter((([e,t])=>u.t[e]!==t));if(!e.length)return!1;const t=[];return e.forEach((([e,r])=>{t.push([e,r-S(u,e)]),((e,t,r)=>{e.t[t]=r,e.i=d(t,e.i)})(u,e,r)})),c=t,!0}case 2:return(l!==r.V||s!==r.q)&&(l=r.V,s=r.q,!0);case 3:{const e=i;return(i=r)!==e}}})()&&(f.forEach((e=>{e()})),o&&1===e&&o[0]())}}})(W,o,!!i,!!f))),[L,V]=T(C.S,C.D),q=T(C.S,C.U),B=n(null),G=n(-1),K=M(H),N=M(J),[Q,X]=u(new Set),[Y,Z]=u(!1),$=R((()=>((e,t,r)=>{let n,o,l,s=-1,i=0,c=!1;const u=e.O(),a=e.R(),f=u?"scrollLeft":"scrollTop",d=new WeakMap,_=()=>l||(l=new ResizeObserver((t=>{const r=[];for(const n of t)if(n.target===o)e.L(2,{V:n.contentRect.width,q:n.contentRect.height});else{const e=d.get(n.target);g(e)&&r.push([e,n.contentRect[u?"width":"height"]])}r.length&&(e.L(1,r),c=!0)}))),p=()=>o?e.O()?o.scrollWidth:o.scrollHeight:0,S=(e,t)=>{if(o){if(a){if(!g(n)){const e=o[f];o[f]=1,n=0===o[f],o[f]=e}n&&(e*=-1)}t?o[f]+=e:(o[f]=e,i=3)}};return{B(n){o=n;const l=_(),d=()=>{let r=n[f];a&&(r=h(r)),s!==r&&(0!==i&&c?c=!1:3!==i&&(i=s>r?2:1),e.L(3,s=r),t(r))},p=(()=>{let e;const t=()=>{g(e)&&clearTimeout(e)},n=()=>{t(),e=setTimeout((()=>{e=null,d(),i=0,r(!1)}),150)};return n.G=t,n})(),S=()=>{const e=0===i;d(),e&&r(!0),p()},w=(()=>{let t=m()-50;return(...r)=>{const n=m();t+50<n&&(t=n,(t=>{0!==i&&(t.ctrlKey||(u?t.deltaX:t.deltaY)&&s>0&&s<e.A()-e.J()&&p())})(...r))}})();return l.observe(n),n.addEventListener("scroll",S),n.addEventListener("wheel",w,{passive:!0}),()=>{l.disconnect(),n.removeEventListener("scroll",S),n.removeEventListener("wheel",w),p.G()}},T(e,t){const r=_();return d.set(e,t),r.observe(e),()=>{d.delete(e),r.unobserve(e)}},K:p,N:async(t,r)=>{const n=()=>{let t=r();const n=p(),o=e.J();return n-(t+o)<=0&&(t=n-o),t};if(e.F(t)){do{e.L(3,n());try{await e.C()}catch(e){return}}while(e.F(t));S(n())}else{const t=n();S(t),e.L(3,t)}},X:(t,r)=>{if(2===i){const e=t.reduce(((e,[,t])=>e+t),0);e&&S(e,!0)}else if(3===i){const n=e.H();if(0===n);else{const o=t.reduce(((e,[,t])=>e+t),0);if(e.A()-(n+e.J()+o)<=0)o&&S(n+o);else{const e=t.reduce(((e,[t,n])=>(t<r&&(e+=n),e)),0);e&&S(e,!0)}}}}}})(C,K,(e=>{Z(e),e||(X(new Set),N())})))),ee=d(W,C.P());b((()=>{C.L(0,W)}),[W]),b((()=>$.B(B[O])),[]),b((()=>{q.length&&$.X(q,L)}),[q]),r((()=>{F&&(G[O]>ee&&(G[O]=-1),ee-1-V<=p&&G[O]<ee&&(G[O]=ee,F()))}),[V]),a(P,(()=>({get scrollOffset(){return C.H()},get scrollSize(){return $.K()},scrollToIndex(e){e=_(d(e,ee-1),0),$.N(e,(()=>C.I(e)))},scrollToOffset(e){e=_(e,0),$.N(C.W(e),(()=>e))}})),[ee]);const te=_(L-l,0),re=d(V+l,ee-1),ne=s((()=>{const t=[];for(let e=te;e<=re;e++)Q.add(e);return Q.forEach((r=>{const n=U[r];t.push(e(E,{h:$,m:C,g:r,p:D,_:n},(null==n?void 0:n.key)||r))})),t}),[U,Q,te,re]);return e(j,{M:B,m:C,p:A,k:Y,j:z,_:ne})}));export{A as List};
1
+ import{jsx as e}from"react/jsx-runtime";import{useLayoutEffect as t,useEffect as r,useRef as n,memo as o,useMemo as s,forwardRef as l,Children as i,useState as c,useImperativeHandle as u}from"react";import{useSyncExternalStore as a}from"use-sync-external-store/shim/index.js";const f=Math.min,_=Math.max,d=Math.abs,h=Date.now,m=e=>null!=e,g=(e,t)=>Array.from({length:e},((e,r)=>t(r))),S=(e,t)=>{const r=e.t[t];return-1===r?e.o:r},p=(e,t,r)=>{if(!e.l)return 0;if(e.i>=t)return r?e.u[t]+S(e,t):e.u[t];let n=e.i,o=e.u[n];for(;n<=t&&(e.u[n]=o,n!==t||r);)o+=S(e,n),n++;return e.i=t,o},w=(e,t)=>p(e,t),v=(e,t,r)=>{let n=0;if(r>=0)for(;t<e.l-1;){const o=S(e,t++);if((n+=o)>=r){n-o/2>=r&&t--;break}}else for(;t>0;){const o=S(e,--t);if((n-=o)<=r){n+o/2<r&&t++;break}}return f(_(t,0),e.l-1)},z=(e,t,r,n)=>v(e,r,t-n),x=v,y=(e,t,r)=>({o:t,l:e,i:r?f(r.i,e-1):0,t:g(e,(e=>{const t=r&&r.t[e];return m(t)?t:-1})),u:g(e,(e=>{if(0===e)return 0;const t=r&&r.u[e];return m(t)?t:-1}))}),I="undefined"!=typeof window?t:r,b=(e,t)=>a(e,t,t),T="current",R=e=>{const t=n();return t[T]||(t[T]=e())},M=e=>{const t=n(e);return I((()=>{t[T]=e}),[e]),t},O=/*#__PURE__*/o((({_:t,h:r,m:o,g:l,S:i})=>{const c=n(null),u=b(o.p,(()=>o.v(l))),a=b(o.p,(()=>o.I(l)));return I((()=>r.T(c[T],l)),[l]),e(i,{ref:c,style:s((()=>{const e=o.R(),t=o.M()?"right":"left",r={margin:0,padding:0,position:"absolute",[e?"height":"width"]:"100%",[e?"top":t]:0,[e?t:"top"]:u,visibility:a?"hidden":"visible"};return e&&(r.display="flex"),r}),[u,a]),children:t})})),k=/*#__PURE__*/l((({children:t,scrollSize:r,scrolling:n,horizontal:o,attrs:l},i)=>e("div",{ref:i,...l,children:e("div",{style:s((()=>({position:"relative",visibility:"hidden",width:o?r:"100%",height:o?"100%":r,pointerEvents:n?"none":"auto"})),[r,n]),children:t})}))),E=({_:t,O:r,m:n,S:o,k:l,j:i})=>{const c=b(n.p,n.A),u=n.R();return e(o,{ref:r,scrollSize:c,scrolling:l,horizontal:u,attrs:s((()=>({...i,style:{overflow:u?"auto hidden":"hidden auto",contain:"strict",width:"100%",height:"100%",padding:0,margin:0,...i.style}})),[i]),children:t})},j=/*#__PURE__*/l((({children:t,itemSize:o=40,overscan:l=4,horizontal:a,rtl:g,element:v=k,itemElement:j="div",onScroll:A,onScrollStop:C,onRangeChange:D,...F},J)=>{const P=s((()=>{const e=[];return i.forEach(t,(t=>{(e=>!m(e)||"boolean"==typeof e)(t)||e.push(t)})),e}),[t]),U=P.length,B=R((()=>((e,t,r,n)=>{let o,s=0,l=0,i=0,c=[],u=y(e,t),a=[0,0];const _=new Set,d=()=>r?s:l;return{C(){const[e,t]=a,r=w(u,e),n=z(u,i,e,r),o=x(u,n,d());return e===n&&t===o?a:a=[n,o]},I:e=>-1===u.t[e],D:e=>((e,t,r)=>{for(let n=t;n<=r;n++)if(-1===e.t[n])return!0;return!1})(u,e,x(u,e,d())),v:e=>w(u,e),F:()=>i,J:()=>d(),A:()=>(e=>p(e,e.l-1,!0))(u),P:()=>u.l,U:()=>c,R:()=>r,M:()=>n,B:e=>z(u,e,0,0),H:()=>(o&&o[1](),new Promise(((e,t)=>{o=[()=>{Promise.resolve().then((()=>{e(),o=void 0}))},t]}))),p:e=>(_.add(e),()=>{_.delete(e)}),L(e,r){(()=>{switch(e){case 0:return u.l!==r&&(u=y(r,t,u),!0);case 1:{const e=r.filter((([e,t])=>u.t[e]!==t));if(!e.length)return!1;const t=[];return e.forEach((([e,r])=>{t.push([e,r-S(u,e)]),((e,t,r)=>{e.t[t]=r,e.i=f(t,e.i)})(u,e,r)})),c=t,!0}case 2:return(s!==r.V||l!==r.W)&&(s=r.V,l=r.W,!0);case 3:{const e=i;return(i=r)!==e}}})()&&(_.forEach((e=>{e()})),o&&1===e&&o[0]())}}})(U,o,!!a,!!g))),[H,L]=b(B.p,B.C),V=b(B.p,B.U),W=n(null),q=M(A),G=M(C),[K,N]=c(new Set),[Q,X]=c(!1),Y=R((()=>((e,t,r)=>{let n,o,s,l=-1,i=0,c=!1;const u=e.R(),a=e.M(),g=u?"scrollLeft":"scrollTop",S=new WeakMap,p=()=>s||(s=new ResizeObserver((t=>{const r=[];for(const n of t)if(n.target===o)e.L(2,{V:n.contentRect.width,W:n.contentRect.height});else{const e=S.get(n.target);m(e)&&r.push([e,n.contentRect[u?"width":"height"]])}r.length&&(e.L(1,r),c=!0)}))),w=()=>o?e.R()?o.scrollWidth:o.scrollHeight:0,v=(e,t)=>{if(o){if(a){if(!m(n)){const e=o[g];o[g]=1,n=0===o[g],o[g]=e}n&&(e*=-1)}t?o[g]+=e:(o[g]=e,i=3)}},z=async(t,r)=>{const n=()=>{let t=r();const n=w(),o=e.J();return n-(t+o)<=0&&(t=n-o),t};if(e.D(t)){do{e.L(3,n());try{await e.H()}catch(e){return}}while(e.D(t));v(n())}else{const t=n();v(t),e.L(3,t)}},x=e=>e.reduce(((e,[,t])=>e+t),0);return{q(n){o=n;const s=p(),f=()=>{let r=n[g];a&&(r=d(r)),l!==r&&(0!==i&&c?c=!1:3!==i&&(i=l>r?2:1),e.L(3,l=r),t(r))},_=(()=>{let e;const t=()=>{m(e)&&clearTimeout(e)},n=()=>{t(),e=setTimeout((()=>{e=null,f(),i=0,r(!1)}),150)};return n.G=t,n})(),S=()=>{const e=0===i;f(),e&&r(!0),_()},w=(()=>{let t=h()-50;return(...r)=>{const n=h();t+50<n&&(t=n,(t=>{0!==i&&(t.ctrlKey||(u?t.deltaX:t.deltaY)&&l>0&&l<e.A()-e.J()&&_())})(...r))}})();return s.observe(n),n.addEventListener("scroll",S),n.addEventListener("wheel",w,{passive:!0}),()=>{s.disconnect(),n.removeEventListener("scroll",S),n.removeEventListener("wheel",w),_.G()}},T(e,t){const r=p();return S.set(e,t),r.observe(e),()=>{S.delete(e),r.unobserve(e)}},K:w,N(t){t=_(t,0),z(e.B(t),(()=>t))},X(t,r){t=_(f(t,r-1),0),z(t,(()=>e.v(t)))},Y:(t,r)=>{if(2===i){const e=x(t);e&&v(e,!0)}else if(3===i){const n=e.F();if(0===n);else{const o=x(t);if(e.A()-(n+e.J()+o)<=0)o&&v(n+o);else{const e=t.reduce(((e,[t,n])=>(t<r&&(e+=n),e)),0);e&&v(e,!0)}}}}}})(B,(e=>{q[T]&&q[T](e)}),(e=>{X(e),e||(N(new Set),G[T]&&G[T]())})))),Z=f(U,B.P());I((()=>{B.L(0,U)}),[U]),I((()=>Y.q(W[T])),[]),I((()=>{V.length&&Y.Y(V,H)}),[V]),r((()=>{D&&D({start:H,end:L,count:Z})}),[H,L]),u(J,(()=>({get scrollOffset(){return B.F()},get scrollSize(){return Y.K()},get viewportSize(){return B.J()},scrollToIndex(e){Y.X(e,Z)},scrollTo:Y.N,scrollBy(e){Y.N(B.F()+e)}})),[Z]);const $=_(H-l,0),ee=f(L+l,Z-1),te=s((()=>{const t=[];for(let e=$;e<=ee;e++)K.add(e);return K.forEach((r=>{const n=P[r];m(n)&&t.push(e(O,{h:Y,m:B,g:r,S:j,_:n},(null==n?void 0:n.key)||r))})),t}),[P,K,$,ee]);return e(E,{O:W,m:B,S:v,k:Q,_:te,j:F})}));export{j as VList};
2
2
  //# sourceMappingURL=index.mjs.map
package/lib/index.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/src/core/utils.ts","../src/src/core/cache.ts","../src/src/react/useIsomorphicLayoutEffect.ts","../src/src/react/useSyncExternalStore.ts","../src/src/react/utils.ts","../src/src/react/useStatic.ts","../src/src/react/useEvent.ts","../src/src/react/List.tsx","../src/src/core/store.ts","../src/src/core/scroller.ts"],"sourcesContent":["export const min = Math.min;\nexport const max = Math.max;\nexport const abs = Math.abs;\nexport const now = Date.now;\n\nexport const exists = <T>(v: T): v is Exclude<T, null | undefined> => v != null;\n\nexport const range = <T>(length: number, cb: (i: number) => T): T[] =>\n Array.from({ length }, (_, i) => cb(i));\n\nexport const debounce = <T extends (...args: any[]) => void>(\n fn: T,\n ms: number\n) => {\n let id: NodeJS.Timeout | undefined | null;\n\n const cancel = () => {\n if (exists(id)) {\n clearTimeout(id);\n }\n };\n const debouncedFn = () => {\n cancel();\n id = setTimeout(() => {\n id = null;\n fn();\n }, ms);\n };\n debouncedFn._cancel = cancel;\n return debouncedFn;\n};\n\nexport const throttle = <T extends (...args: any[]) => void>(\n fn: T,\n ms: number\n) => {\n let time = now() - ms;\n return (...args: Parameters<T>) => {\n const n = now();\n if (time + ms < n) {\n time = n;\n fn(...args);\n }\n };\n};\n","import type { DeepReadonly, Writeable } from \"./types\";\nimport { exists, max, min, range } from \"./utils\";\n\nexport const UNCACHED = -1;\n\nexport type Cache = DeepReadonly<{\n _defaultItemSize: number;\n _length: number;\n _sizes: number[];\n _measuredOffsetIndex: number;\n _offsets: number[];\n}>;\n\nexport const getItemSize = (cache: Cache, index: number): number => {\n const size = cache._sizes[index]!;\n return size === UNCACHED ? cache._defaultItemSize : size;\n};\n\nexport const setItemSize = (\n cache: Writeable<Cache>,\n index: number,\n size: number\n) => {\n cache._sizes[index] = size;\n // mark as dirty\n cache._measuredOffsetIndex = min(index, cache._measuredOffsetIndex);\n};\n\nconst computeOffset = (\n cache: Writeable<Cache>,\n index: number,\n isTotal?: boolean\n): number => {\n if (!cache._length) return 0;\n if (cache._measuredOffsetIndex >= index) {\n if (isTotal) {\n return cache._offsets[index]! + getItemSize(cache, index);\n } else {\n return cache._offsets[index]!;\n }\n }\n\n let i = cache._measuredOffsetIndex;\n let top = cache._offsets[i]!;\n while (i <= index) {\n cache._offsets[i] = top;\n if (i === index && !isTotal) {\n break;\n }\n top += getItemSize(cache, i);\n i++;\n }\n // mark as measured\n cache._measuredOffsetIndex = index;\n return top;\n};\n\nexport const computeTotalSize = (cache: Writeable<Cache>): number => {\n return computeOffset(cache, cache._length - 1, true);\n};\n\nexport const computeStartOffset = (\n cache: Writeable<Cache>,\n index: number\n): number => {\n return computeOffset(cache, index);\n};\n\nconst findIndex = (cache: Cache, i: number, distance: number): number => {\n let sum = 0;\n if (distance >= 0) {\n // search forward\n while (i < cache._length - 1) {\n const h = getItemSize(cache, i++);\n if ((sum += h) >= distance) {\n if (sum - h / 2 >= distance) {\n i--;\n }\n break;\n }\n }\n } else {\n // search backward\n while (i > 0) {\n const h = getItemSize(cache, --i);\n if ((sum -= h) <= distance) {\n if (sum + h / 2 < distance) {\n i++;\n }\n break;\n }\n }\n }\n\n return min(max(i, 0), cache._length - 1);\n};\n\nexport const findStartIndexWithOffset = (\n cache: Cache,\n offset: number,\n prevStartIndex: number,\n prevOffset: number\n): number => {\n return findIndex(cache, prevStartIndex, offset - prevOffset);\n};\n\nexport const findEndIndex = findIndex;\n\nexport const hasUnmeasuredItemsInRange = (\n cache: Cache,\n startIndex: number,\n endIndex: number\n): boolean => {\n for (let i = startIndex; i <= endIndex; i++) {\n if (cache._sizes[i] === UNCACHED) {\n return true;\n }\n }\n return false;\n};\n\nexport const resetCache = (\n length: number,\n itemSize: number,\n cache?: Cache\n): Cache => {\n return {\n _defaultItemSize: itemSize,\n _length: length,\n _measuredOffsetIndex: cache\n ? min(cache._measuredOffsetIndex, length - 1)\n : 0,\n _sizes: range(length, (i) => {\n const size = cache && cache._sizes[i];\n if (exists(size)) {\n return size;\n }\n return UNCACHED;\n }),\n _offsets: range(length, (i) => {\n if (i === 0) {\n // first offset must be 0\n return 0;\n }\n const offset = cache && cache._offsets[i];\n if (exists(offset)) {\n return offset;\n }\n return UNCACHED;\n }),\n };\n};\n","import { useEffect, useLayoutEffect } from \"react\";\n\n// https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85\nexport const useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n","import { useSyncExternalStore as _useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\n\nexport const useSyncExternalStore = <T>(\n subscibe: (onStoreChange: () => void) => () => void,\n getSnapShot: () => T\n): T => {\n return _useSyncExternalStore(subscibe, getSnapShot, getSnapShot);\n};\n","export const refKey = \"current\";\n","import { useRef } from \"react\";\nimport { refKey } from \"./utils\";\n\nexport const useStatic = <T>(init: () => T): T => {\n const ref = useRef<T>();\n return ref[refKey] || (ref[refKey] = init());\n};\n","import { useCallback, useRef } from \"react\";\n\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\nimport { refKey } from \"./utils\";\n\nexport const useEvent = <T extends (...args: any[]) => void>(\n handler: T | undefined\n) => {\n const handlerRef = useRef<T | undefined>(handler);\n\n useIsomorphicLayoutEffect(() => {\n handlerRef[refKey] = handler;\n }, [handler]);\n\n return useCallback((...args: Parameters<T>): void => {\n handlerRef[refKey] && handlerRef[refKey](...args);\n }, []);\n};\n","import {\n Children,\n memo,\n useRef,\n useMemo,\n CSSProperties,\n ReactElement,\n forwardRef,\n useImperativeHandle,\n ReactNode,\n useEffect,\n RefObject,\n useState,\n} from \"react\";\nimport {\n ACTION_UPDATE_CACHE_LENGTH,\n VirtualStore,\n createVirtualStore,\n} from \"../core/store\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\nimport { useSyncExternalStore } from \"./useSyncExternalStore\";\nimport { exists, max, min } from \"../core/utils\";\nimport { createScroller, Scroller } from \"../core/scroller\";\nimport { refKey } from \"./utils\";\nimport { useStatic } from \"./useStatic\";\nimport { useEvent } from \"./useEvent\";\n\nconst INITIAL_END_REACHED_INDEX = -1;\n\ntype ItemProps = {\n _children: ReactNode;\n _scroller: Scroller;\n _store: VirtualStore;\n _index: number;\n _element: \"div\";\n};\n\nconst Item = memo(\n ({\n _children: children,\n _scroller: scroller,\n _store: store,\n _index: index,\n _element: Element,\n }: ItemProps): ReactElement => {\n const ref = useRef<HTMLDivElement>(null);\n\n const offset = useSyncExternalStore(store._subscribe, () =>\n store._getItemOffset(index)\n );\n const hide = useSyncExternalStore(store._subscribe, () =>\n store._isUnmeasuredItem(index)\n );\n\n // The index may be changed if elements are inserted to or removed from the start of props.children\n useIsomorphicLayoutEffect(\n () => scroller._initItem(ref[refKey]!, index),\n [index]\n );\n\n return (\n <Element\n ref={ref}\n style={useMemo((): CSSProperties => {\n const isHorizontal = store._isHorizontal();\n const leftOrRightKey = store._isRtl() ? \"right\" : \"left\";\n const style: CSSProperties = {\n margin: 0,\n padding: 0,\n position: \"absolute\",\n [isHorizontal ? \"height\" : \"width\"]: \"100%\",\n [isHorizontal ? \"top\" : leftOrRightKey]: 0,\n [isHorizontal ? leftOrRightKey : \"top\"]: offset,\n // willChange: \"transform\",\n };\n if (isHorizontal) {\n style.display = \"flex\";\n }\n if (hide) {\n style.visibility = \"hidden\";\n }\n return style;\n }, [offset, hide])}\n >\n {children}\n </Element>\n );\n }\n);\n\nconst isInvalidElement = <T extends ReactNode>(\n e: T\n): e is Extract<T, null | undefined | boolean> =>\n !exists(e) || typeof e === \"boolean\";\n\n/**\n * Props of customized scrollable component.\n */\nexport interface CustomWindowComponentProps {\n children: ReactNode;\n style: CSSProperties;\n scrollSize: number;\n scrolling: boolean;\n horizontal: boolean;\n rtl: boolean;\n}\n\nconst DefaultWindow = forwardRef<any, CustomWindowComponentProps>(\n (\n { children, style, scrollSize, scrolling, horizontal, rtl },\n ref\n ): ReactElement => {\n return (\n <div ref={ref} style={style}>\n <div\n style={useMemo((): CSSProperties => {\n const width = horizontal ? scrollSize : \"100%\";\n const height = horizontal ? \"100%\" : scrollSize;\n return {\n position: \"absolute\",\n top: 0,\n [rtl ? \"right\" : \"left\"]: 0,\n width,\n height,\n minWidth: width,\n minHeight: height,\n pointerEvents: scrolling ? \"none\" : \"auto\",\n };\n }, [scrollSize, scrolling])}\n >\n {children}\n </div>\n </div>\n );\n }\n);\n\nexport type CustomWindowComponent = typeof DefaultWindow;\n\nconst Window = ({\n _children: children,\n _ref: ref,\n _store: store,\n _element: Element,\n _scrolling: scrolling,\n _style: style,\n}: {\n _children: ReactNode;\n _ref: RefObject<HTMLDivElement>;\n _store: VirtualStore;\n _element: CustomWindowComponent;\n _scrolling: boolean;\n _style: CSSProperties | undefined;\n}) => {\n const scrollSize = useSyncExternalStore(\n store._subscribe,\n store._getScrollSize\n );\n\n const horizontal = store._isHorizontal();\n\n return (\n <Element\n ref={ref}\n scrollSize={scrollSize}\n scrolling={scrolling}\n horizontal={horizontal}\n rtl={store._isRtl()}\n style={useMemo(\n (): CSSProperties => ({\n overflow: horizontal ? \"auto hidden\" : \"hidden auto\",\n position: \"relative\",\n contain: \"strict\",\n // transform: \"translate3d(0px, 0px, 0px)\",\n // willChange: \"scroll-position\",\n // backfaceVisibility: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n padding: 0,\n margin: 0,\n ...style,\n }),\n [style]\n )}\n >\n {children}\n </Element>\n );\n};\n\n/**\n * Props of customized item component.\n */\nexport interface CustomItemComponentProps {\n style: CSSProperties;\n children: ReactNode;\n}\n\nexport type CustomItemComponent = React.ForwardRefExoticComponent<\n React.PropsWithoutRef<CustomItemComponentProps> & React.RefAttributes<any>\n>;\n\ntype CustomItemComponentOrElement =\n | keyof JSX.IntrinsicElements\n | CustomItemComponent;\n\n/**\n * Methods of {@link List}.\n */\nexport interface ListHandle {\n /**\n * Get current scrollTop or scrollLeft.\n */\n scrollOffset: number;\n /**\n * Get current scrollHeight or scrollWidth.\n */\n scrollSize: number;\n /**\n * Scroll to the item specified by index.\n * @param index index of item\n */\n scrollToIndex(index: number): void;\n /**\n * Scroll to the item specified by offset.\n * @param offset offset from start\n */\n scrollToOffset(offset: number): void;\n}\n\n/**\n * Props of {@link List}.\n */\nexport interface ListProps {\n /**\n * Elements rendered by this component.\n */\n children: ReactNode;\n /**\n * Item size hint for unmeasured items. It's recommended to specify this prop if item sizes are fixed and known, or much larger than the defaultValue. It will help to reduce scroll jump when items are measured.\n * @defaultValue 40\n */\n itemSize?: number;\n /**\n * Number of items to render above/below the visible bounds of the list. You can increase to avoid showing blank items in fast scrolling.\n * @defaultValue 4\n */\n overscan?: number;\n /**\n * If true, rendered as a horizontally scrollable list. Otherwise rendered as a vertically scrollable list.\n */\n horizontal?: boolean;\n /**\n * You have to set true if you use this component under `direction: rtl` style.\n */\n rtl?: boolean;\n /**\n * Number of items to be the margin from the end of the scroll. See also {@link onEndReached}.\n * @defaultValue 0\n */\n endThreshold?: number;\n /**\n * Inline style prop to override style of scrollable element.\n */\n style?: CSSProperties;\n /**\n * Customized element type for scrollable element. This element will get {@link CustomWindowComponentProps} as props.\n * @defaultValue {@link DefaultWindow}\n */\n element?: CustomWindowComponent;\n /**\n * Customized element type for item element. This element will get {@link CustomItemComponentProps} as props.\n * @defaultValue \"div\"\n */\n itemElement?: CustomItemComponentOrElement;\n /**\n * Callback invoked when scrolling reached to the end. The margin from the end is specified by {@link endThreshold}.\n */\n onEndReached?: () => void;\n /**\n * Callback invoked whenever scroll offset changes.\n * @param offset Current scrollTop or scrollLeft.\n */\n onScroll?: (offset: number) => void;\n /**\n * Callback invoked when scrolling stops.\n */\n onScrollStop?: () => void;\n}\n\n/**\n * Virtualized list component. See {@link ListProps} and {@link ListHandle}.\n */\nexport const List = forwardRef<ListHandle, ListProps>(\n (\n {\n children,\n itemSize: itemSizeProp = 40,\n overscan = 4,\n horizontal: horizontalProp,\n rtl: rtlProp,\n endThreshold = 0,\n style: styleProp,\n element = DefaultWindow,\n itemElement = \"div\",\n onEndReached,\n onScroll: onScrollProp,\n onScrollStop: onScrollStopProp,\n },\n ref\n ): ReactElement => {\n // Memoize element array\n const elements = useMemo(() => {\n const arr: ReactNode[] = [];\n Children.forEach(children, (e) => {\n if (isInvalidElement(e)) {\n return;\n }\n arr.push(e);\n });\n return arr;\n }, [children]);\n const elementsCount = elements.length;\n\n // https://github.com/facebook/react/issues/25191#issuecomment-1237456448\n const store = useStatic(() =>\n createVirtualStore(\n elementsCount,\n itemSizeProp,\n !!horizontalProp,\n !!rtlProp\n )\n );\n const [startIndex, endIndex] = useSyncExternalStore(\n store._subscribe,\n store._getRange\n );\n const jump = useSyncExternalStore(store._subscribe, store._getJump);\n const rootRef = useRef<HTMLDivElement>(null);\n\n const onEndReachedCalledIndex = useRef<number>(INITIAL_END_REACHED_INDEX);\n const onScroll = useEvent(onScrollProp);\n const onScrollStop = useEvent(onScrollStopProp);\n\n const [mountedIndexes, reset] = useState<Set<number>>(new Set<number>());\n const [scrolling, setScrolling] = useState(false);\n const scroller = useStatic(() =>\n createScroller(store, onScroll, (isScrolling) => {\n setScrolling(isScrolling);\n if (!isScrolling) {\n reset(new Set());\n onScrollStop();\n }\n })\n );\n\n // The elements length and cached items length are different just after element is added/removed.\n const count = min(elementsCount, store._getItemCount());\n\n // So update cache length. Updating state in render will cause warn so use useEffect for now.\n useIsomorphicLayoutEffect(() => {\n store._update(ACTION_UPDATE_CACHE_LENGTH, elementsCount);\n }, [elementsCount]);\n\n useIsomorphicLayoutEffect(() => scroller._initRoot(rootRef[refKey]!), []);\n\n useIsomorphicLayoutEffect(() => {\n if (!jump.length) return;\n\n scroller._fixScrollJump(jump, startIndex);\n }, [jump]);\n\n useEffect(() => {\n if (!onEndReached) return;\n\n if (onEndReachedCalledIndex[refKey] > count) {\n // Probably items have been refreshed, so reset index\n onEndReachedCalledIndex[refKey] = INITIAL_END_REACHED_INDEX;\n }\n\n const endMargin = count - 1 - endIndex;\n if (\n endMargin <= endThreshold &&\n onEndReachedCalledIndex[refKey] < count\n ) {\n onEndReachedCalledIndex[refKey] = count;\n onEndReached();\n }\n }, [endIndex]);\n\n useImperativeHandle(\n ref,\n () => {\n return {\n get scrollOffset() {\n return store._getScrollOffset();\n },\n get scrollSize() {\n return scroller._getActualScrollSize();\n },\n scrollToIndex(index) {\n index = max(min(index, count - 1), 0);\n\n scroller._scrollTo(index, () => store._getItemOffset(index));\n },\n scrollToOffset(offset) {\n offset = max(offset, 0);\n\n scroller._scrollTo(\n store._getItemIndexForScrollTo(offset),\n () => offset\n );\n },\n };\n },\n [count]\n );\n\n const startIndexWithMargin = max(startIndex - overscan, 0);\n const endIndexWithMargin = min(endIndex + overscan, count - 1);\n const items = useMemo(() => {\n const res: ReactElement[] = [];\n for (let i = startIndexWithMargin; i <= endIndexWithMargin; i++) {\n // https://github.com/sergi/virtual-list/commit/8e7e06dc63568334c1ab809ea83c1be36572e9ed\n mountedIndexes.add(i);\n }\n mountedIndexes.forEach((i) => {\n const e = elements[i];\n res.push(\n <Item\n key={(e as { key?: ReactElement[\"key\"] })?.key || i}\n _scroller={scroller}\n _store={store}\n _index={i}\n _element={itemElement as \"div\"}\n _children={e}\n />\n );\n });\n return res;\n }, [elements, mountedIndexes, startIndexWithMargin, endIndexWithMargin]);\n\n return (\n <Window\n _ref={rootRef}\n _store={store}\n _element={element}\n _scrolling={scrolling}\n _style={styleProp}\n _children={items}\n />\n );\n }\n);\n","import {\n findStartIndexWithOffset,\n resetCache,\n getItemSize,\n computeTotalSize,\n findEndIndex,\n computeStartOffset,\n Cache,\n UNCACHED,\n setItemSize,\n hasUnmeasuredItemsInRange,\n} from \"./cache\";\nimport type { Writeable } from \"./types\";\n\nexport type ScrollJump = Readonly<[index: number, sizeDiff: number][]>;\nexport type ItemResize = [index: number, size: number];\ntype ItemsRange = [startIndex: number, endIndex: number];\n\nexport const ACTION_UPDATE_CACHE_LENGTH = 0;\nexport const ACTION_UPDATE_ITEM_SIZES = 1;\nexport const ACTION_UPDATE_VIEWPORT = 2;\nexport const ACTION_HANDLE_SCROLL = 3;\n\ntype Actions =\n | [type: typeof ACTION_UPDATE_CACHE_LENGTH, length: number]\n | [type: typeof ACTION_UPDATE_ITEM_SIZES, entries: ItemResize[]]\n | [\n type: typeof ACTION_UPDATE_VIEWPORT,\n rect: { _width: number; _height: number }\n ]\n | [type: typeof ACTION_HANDLE_SCROLL, offset: number];\n\nexport type VirtualStore = {\n _getRange(): ItemsRange;\n _isUnmeasuredItem(index: number): boolean;\n _hasUnmeasuredItemsInRange(startIndex: number): boolean;\n _getItemOffset(index: number): number;\n _getScrollOffset(): number;\n _getViewportSize(): number;\n _getScrollSize(): number;\n _getItemCount(): number;\n _getJump(): ScrollJump;\n _isHorizontal(): boolean;\n _isRtl(): boolean;\n _getItemIndexForScrollTo(offset: number): number;\n _waitForScrollDestinationItemsMeasured(): Promise<void>;\n _subscribe(cb: () => void): () => void;\n _update(...action: Actions): void;\n};\n\nexport const createVirtualStore = (\n itemCount: number,\n itemSize: number,\n isHorizontal: boolean,\n isRtl: boolean\n): VirtualStore => {\n let viewportWidth = 0;\n let viewportHeight = 0;\n let scrollOffset = 0;\n let jump: ScrollJump = [];\n let cache = resetCache(itemCount, itemSize);\n let _prevRange: ItemsRange = [0, 0];\n let _scrollToQueue: [() => void, () => void] | undefined;\n\n const subscribers = new Set<() => void>();\n const getViewportSize = (): number =>\n isHorizontal ? viewportWidth : viewportHeight;\n\n return {\n _getRange() {\n const [prevStartIndex, prevEndIndex] = _prevRange;\n const prevOffset = computeStartOffset(\n cache as Writeable<Cache>,\n prevStartIndex\n );\n const start = findStartIndexWithOffset(\n cache,\n scrollOffset,\n prevStartIndex,\n prevOffset\n );\n const end = findEndIndex(cache, start, getViewportSize());\n if (prevStartIndex === start && prevEndIndex === end) {\n return _prevRange;\n }\n return (_prevRange = [start, end]);\n },\n _isUnmeasuredItem(index) {\n return cache._sizes[index] === UNCACHED;\n },\n _hasUnmeasuredItemsInRange(startIndex) {\n return hasUnmeasuredItemsInRange(\n cache,\n startIndex,\n findEndIndex(cache, startIndex, getViewportSize())\n );\n },\n _getItemOffset(index) {\n return computeStartOffset(cache as Writeable<Cache>, index);\n },\n _getScrollOffset() {\n return scrollOffset;\n },\n _getViewportSize() {\n return getViewportSize();\n },\n _getScrollSize() {\n return computeTotalSize(cache as Writeable<Cache>);\n },\n _getItemCount() {\n return cache._length;\n },\n _getJump() {\n return jump;\n },\n _isHorizontal() {\n return isHorizontal;\n },\n _isRtl() {\n return isRtl;\n },\n _getItemIndexForScrollTo(offset) {\n return findStartIndexWithOffset(cache, offset, 0, 0);\n },\n _waitForScrollDestinationItemsMeasured() {\n if (_scrollToQueue) {\n // Cancel waiting scrollTo\n _scrollToQueue[1]();\n }\n // The measurement will be done asynchronously and the timing is not predictable so we use promise.\n // For example, ResizeObserver may not fire when window is not visible.\n return new Promise((resolve, reject) => {\n _scrollToQueue = [\n () => {\n // HACK: It should be resolved in the next microtask that is after React's render\n Promise.resolve().then(() => {\n resolve();\n _scrollToQueue = undefined;\n });\n },\n reject,\n ];\n });\n },\n _subscribe(cb) {\n subscribers.add(cb);\n return () => {\n subscribers.delete(cb);\n };\n },\n _update(type, payload) {\n const mutated = ((): boolean => {\n switch (type) {\n case ACTION_UPDATE_CACHE_LENGTH: {\n if (cache._length === payload) return false;\n cache = resetCache(payload, itemSize, cache);\n return true;\n }\n case ACTION_UPDATE_ITEM_SIZES: {\n const updated = payload.filter(\n ([index, size]) => cache._sizes[index] !== size\n );\n // Skip if all items are cached and not updated\n if (!updated.length) {\n return false;\n }\n\n const updatedJump: [index: number, sizeDiff: number][] = [];\n updated.forEach(([index, size]) => {\n updatedJump.push([index, size - getItemSize(cache, index)]);\n setItemSize(cache as Writeable<Cache>, index, size);\n });\n jump = updatedJump;\n return true;\n }\n case ACTION_UPDATE_VIEWPORT: {\n if (\n viewportWidth === payload._width &&\n viewportHeight === payload._height\n ) {\n return false;\n }\n viewportWidth = payload._width;\n viewportHeight = payload._height;\n return true;\n }\n case ACTION_HANDLE_SCROLL: {\n const prevOffset = scrollOffset;\n return (scrollOffset = payload) !== prevOffset;\n }\n }\n })();\n\n if (mutated) {\n subscribers.forEach((cb) => {\n cb();\n });\n if (_scrollToQueue && type === ACTION_UPDATE_ITEM_SIZES) {\n _scrollToQueue[0]();\n }\n }\n },\n };\n};\n","import {\n ACTION_HANDLE_SCROLL,\n ACTION_UPDATE_ITEM_SIZES,\n ACTION_UPDATE_VIEWPORT,\n ItemResize,\n ScrollJump,\n VirtualStore,\n} from \"./store\";\nimport { abs, debounce, throttle, exists } from \"./utils\";\n\nexport const SCROLL_STOP = 0;\nexport const SCROLL_DOWN = 1;\nexport const SCROLL_UP = 2;\nexport const SCROLL_MANUAL = 3;\ntype ScrollDirection =\n | typeof SCROLL_STOP\n | typeof SCROLL_DOWN\n | typeof SCROLL_UP\n | typeof SCROLL_MANUAL;\n\nexport type Scroller = {\n _initRoot: (rootElement: HTMLElement) => () => void;\n _initItem: (itemElement: HTMLElement, index: number) => () => void;\n _getActualScrollSize: () => number;\n _scrollTo: (index: number, getCurrentOffset: () => number) => void;\n _fixScrollJump: (jump: ScrollJump, startIndex: number) => void;\n};\n\nexport const createScroller = (\n store: VirtualStore,\n emitScrollOffsetChange: (offset: number) => void,\n emitScrollStateChange: (scrolling: boolean) => void\n): Scroller => {\n let prevOffset = -1;\n let scrollDirection: ScrollDirection = SCROLL_STOP;\n let resized = false;\n let isNegativeOffset: boolean | undefined;\n let rootElement: HTMLElement | undefined;\n let _ro: ResizeObserver | undefined;\n const isHorizontal = store._isHorizontal();\n const isRtl = store._isRtl();\n const scrollToKey = isHorizontal ? \"scrollLeft\" : \"scrollTop\";\n const mountedIndexes = new WeakMap<Element, number>();\n const getResizeObserver = (): ResizeObserver => {\n // Initialize ResizeObserver lazily for SSR\n return (\n _ro ||\n (_ro = new ResizeObserver((entries) => {\n // https://www.w3.org/TR/resize-observer/#intro\n const resizes: ItemResize[] = [];\n for (const entry of entries) {\n if (entry.target === rootElement) {\n store._update(ACTION_UPDATE_VIEWPORT, {\n _width: entry.contentRect.width,\n _height: entry.contentRect.height,\n });\n } else {\n const index = mountedIndexes.get(entry.target);\n if (exists(index)) {\n resizes.push([\n index,\n entry.contentRect[isHorizontal ? \"width\" : \"height\"],\n ]);\n }\n }\n }\n\n if (resizes.length) {\n store._update(ACTION_UPDATE_ITEM_SIZES, resizes);\n resized = true;\n }\n }))\n );\n };\n const getActualScrollSize = (): number => {\n if (!rootElement) return 0;\n // Use element's scrollHeight/scrollWidth instead of stored scrollSize.\n // This is because stored size may differ from the actual size, for example when a new item is added and not yet measured.\n return store._isHorizontal()\n ? rootElement.scrollWidth\n : rootElement.scrollHeight;\n };\n const updateScrollPosition = (offset: number, diff?: boolean) => {\n if (!rootElement) return;\n if (isRtl) {\n if (!exists(isNegativeOffset)) {\n // Assume offset type in rtl direction.\n // The scroll position is negative in spec however its not in some browsers, for example Chrome earlier than v85.\n // https://github.com/othree/jquery.rtl-scroll-type\n const prev = rootElement[scrollToKey];\n rootElement[scrollToKey] = 1;\n isNegativeOffset = rootElement[scrollToKey] === 0;\n rootElement[scrollToKey] = prev;\n }\n if (isNegativeOffset) {\n offset *= -1;\n }\n }\n if (diff) {\n rootElement[scrollToKey] += offset;\n } else {\n rootElement[scrollToKey] = offset;\n scrollDirection = SCROLL_MANUAL;\n }\n };\n const scrollTo = async (index: number, getCurrentOffset: () => number) => {\n const getOffset = (): number => {\n let offset = getCurrentOffset();\n const scrollSize = getActualScrollSize();\n const viewportSize = store._getViewportSize();\n if (scrollSize - (offset + viewportSize) <= 0) {\n // Adjust if the offset is over the end, to get correct startIndex.\n offset = scrollSize - viewportSize;\n }\n return offset;\n };\n\n if (store._hasUnmeasuredItemsInRange(index)) {\n do {\n // In order to scroll to the correct position, mount the items and measure their sizes before scrolling.\n store._update(ACTION_HANDLE_SCROLL, getOffset());\n try {\n // Wait for the scroll destination items to be measured.\n await store._waitForScrollDestinationItemsMeasured();\n } catch (e) {\n // canceled\n return;\n }\n } while (store._hasUnmeasuredItemsInRange(index));\n\n // Scroll with the updated value\n updateScrollPosition(getOffset());\n } else {\n const offset = getOffset();\n updateScrollPosition(offset);\n // Sync viewport to scroll destination\n store._update(ACTION_HANDLE_SCROLL, offset);\n }\n };\n\n return {\n _initRoot(root) {\n rootElement = root;\n const ro = getResizeObserver();\n\n const syncViewportToScrollPosition = () => {\n let offset = root[scrollToKey];\n if (isRtl) {\n // The scroll position may be negative value in rtl direction.\n // https://github.com/othree/jquery.rtl-scroll-type\n offset = abs(offset);\n }\n if (prevOffset === offset) {\n return;\n }\n // Skip scroll direction detection just after resizing because it may result in the opposite direction.\n // Scroll events are dispatched enough so it's ok to skip some of them.\n if (scrollDirection === SCROLL_STOP || !resized) {\n // Ignore until manual scrolling\n if (scrollDirection !== SCROLL_MANUAL) {\n scrollDirection = prevOffset > offset ? SCROLL_UP : SCROLL_DOWN;\n }\n } else {\n resized = false;\n }\n store._update(ACTION_HANDLE_SCROLL, (prevOffset = offset));\n emitScrollOffsetChange(offset);\n };\n\n const onScrollStopped = debounce(() => {\n // Check scroll position once just after scrolling stopped\n syncViewportToScrollPosition();\n scrollDirection = SCROLL_STOP;\n emitScrollStateChange(false);\n }, 150);\n\n const onScroll = () => {\n const isScrollStart = scrollDirection === SCROLL_STOP;\n syncViewportToScrollPosition();\n if (isScrollStart) {\n emitScrollStateChange(true);\n }\n onScrollStopped();\n };\n\n // Infer scroll state also from wheel events\n // Sometimes scroll events do not fire when frame dropped even if the visual have been already scrolled\n const onWheel = throttle((e: WheelEvent) => {\n if (scrollDirection === SCROLL_STOP) {\n // Scroll start should be detected with scroll event\n return;\n }\n if (e.ctrlKey) {\n // Probably a pinch-to-zoom gesture\n return;\n }\n // Get delta before checking deltaMode for firefox behavior\n // https://github.com/w3c/uievents/issues/181#issuecomment-392648065\n // https://bugzilla.mozilla.org/show_bug.cgi?id=1392460#c34\n if (isHorizontal ? e.deltaX : e.deltaY) {\n if (\n prevOffset > 0 &&\n prevOffset < store._getScrollSize() - store._getViewportSize()\n ) {\n onScrollStopped();\n }\n }\n }, 50);\n\n ro.observe(root);\n root.addEventListener(\"scroll\", onScroll);\n root.addEventListener(\"wheel\", onWheel, { passive: true });\n\n return () => {\n ro.disconnect();\n root.removeEventListener(\"scroll\", onScroll);\n root.removeEventListener(\"wheel\", onWheel);\n onScrollStopped._cancel();\n };\n },\n _initItem(el, i) {\n const ro = getResizeObserver();\n mountedIndexes.set(el, i);\n ro.observe(el);\n return () => {\n mountedIndexes.delete(el);\n ro.unobserve(el);\n };\n },\n _getActualScrollSize: getActualScrollSize,\n _scrollTo: scrollTo,\n _fixScrollJump: (jump, startIndex) => {\n // Compensate scroll jump\n if (scrollDirection === SCROLL_UP) {\n const diff = jump.reduce((acc, [, j]) => acc + j, 0);\n if (diff) {\n updateScrollPosition(diff, true);\n }\n } else if (scrollDirection === SCROLL_MANUAL) {\n const offset = store._getScrollOffset();\n if (offset === 0) {\n // Do nothing to stick to the start\n } else {\n const allDiff = jump.reduce((acc, [, j]) => acc + j, 0);\n if (\n store._getScrollSize() -\n (offset + store._getViewportSize() + allDiff) <=\n 0\n ) {\n // Keep end to stick to the end\n if (allDiff) {\n updateScrollPosition(offset + allDiff);\n }\n } else {\n // Keep start at mid\n const diff = jump.reduce((acc, [index, j]) => {\n if (index < startIndex) {\n acc += j;\n }\n return acc;\n }, 0);\n if (diff) {\n updateScrollPosition(diff, true);\n }\n }\n }\n } else {\n // NOP\n }\n },\n };\n};\n"],"names":["min","Math","max","abs","now","Date","exists","v","range","length","cb","Array","from","_","i","getItemSize","cache","index","size","_sizes","_defaultItemSize","computeOffset","isTotal","_length","_measuredOffsetIndex","_offsets","top","computeStartOffset","findIndex","distance","sum","h","findStartIndexWithOffset","offset","prevStartIndex","prevOffset","findEndIndex","resetCache","itemSize","useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect","useSyncExternalStore","subscibe","getSnapShot","_useSyncExternalStore","refKey","useStatic","init","ref","useRef","useEvent","handler","handlerRef","useCallback","args","Item","memo","_children","children","_scroller","scroller","_store","store","_index","_element","Element","_subscribe","_getItemOffset","hide","_isUnmeasuredItem","_initItem","_jsx","style","useMemo","isHorizontal","_isHorizontal","leftOrRightKey","_isRtl","margin","padding","position","display","visibility","DefaultWindow","forwardRef","scrollSize","scrolling","horizontal","rtl","width","height","minWidth","minHeight","pointerEvents","Window","_ref","_scrolling","_style","_getScrollSize","overflow","contain","List","itemSizeProp","overscan","horizontalProp","rtlProp","endThreshold","styleProp","element","itemElement","onEndReached","onScroll","onScrollProp","onScrollStop","onScrollStopProp","elements","arr","Children","forEach","e","isInvalidElement","push","elementsCount","createVirtualStore","itemCount","isRtl","_scrollToQueue","viewportWidth","viewportHeight","scrollOffset","jump","_prevRange","subscribers","Set","getViewportSize","_getRange","prevEndIndex","start","end","_hasUnmeasuredItemsInRange","startIndex","hasUnmeasuredItemsInRange","endIndex","_getScrollOffset","_getViewportSize","computeTotalSize","_getItemCount","_getJump","_getItemIndexForScrollTo","_waitForScrollDestinationItemsMeasured","Promise","resolve","reject","then","undefined","add","delete","_update","type","payload","updated","filter","updatedJump","setItemSize","_width","_height","rootRef","onEndReachedCalledIndex","mountedIndexes","reset","useState","setScrolling","createScroller","emitScrollOffsetChange","emitScrollStateChange","isNegativeOffset","rootElement","_ro","scrollDirection","resized","scrollToKey","WeakMap","getResizeObserver","ResizeObserver","entries","resizes","entry","target","contentRect","get","getActualScrollSize","scrollWidth","scrollHeight","updateScrollPosition","diff","prev","_initRoot","root","ro","syncViewportToScrollPosition","onScrollStopped","debounce","id","cancel","clearTimeout","debouncedFn","setTimeout","_cancel","isScrollStart","onWheel","throttle","time","n","ctrlKey","deltaX","deltaY","fn","observe","addEventListener","passive","disconnect","removeEventListener","el","set","unobserve","_getActualScrollSize","_scrollTo","async","getCurrentOffset","getOffset","viewportSize","_fixScrollJump","reduce","acc","j","allDiff","isScrolling","count","useImperativeHandle","scrollToIndex","scrollToOffset","startIndexWithMargin","endIndexWithMargin","items","res","key"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/src/core/utils.ts","../src/src/core/cache.ts","../src/src/react/useIsomorphicLayoutEffect.ts","../src/src/react/useSyncExternalStore.ts","../src/src/react/utils.ts","../src/src/react/useStatic.ts","../src/src/react/useRefWithUpdate.ts","../src/src/react/VList.tsx","../src/src/core/store.ts","../src/src/core/scroller.ts"],"sourcesContent":["export const min = Math.min;\nexport const max = Math.max;\nexport const abs = Math.abs;\nexport const now = Date.now;\n\nexport const exists = <T>(v: T): v is Exclude<T, null | undefined> => v != null;\n\nexport const range = <T>(length: number, cb: (i: number) => T): T[] =>\n Array.from({ length }, (_, i) => cb(i));\n\nexport const debounce = <T extends (...args: any[]) => void>(\n fn: T,\n ms: number\n) => {\n let id: NodeJS.Timeout | undefined | null;\n\n const cancel = () => {\n if (exists(id)) {\n clearTimeout(id);\n }\n };\n const debouncedFn = () => {\n cancel();\n id = setTimeout(() => {\n id = null;\n fn();\n }, ms);\n };\n debouncedFn._cancel = cancel;\n return debouncedFn;\n};\n\nexport const throttle = <T extends (...args: any[]) => void>(\n fn: T,\n ms: number\n) => {\n let time = now() - ms;\n return (...args: Parameters<T>) => {\n const n = now();\n if (time + ms < n) {\n time = n;\n fn(...args);\n }\n };\n};\n","import type { DeepReadonly, Writeable } from \"./types\";\nimport { exists, max, min, range } from \"./utils\";\n\nexport const UNCACHED = -1;\n\nexport type Cache = DeepReadonly<{\n _defaultItemSize: number;\n _length: number;\n _sizes: number[];\n _measuredOffsetIndex: number;\n _offsets: number[];\n}>;\n\nexport const getItemSize = (cache: Cache, index: number): number => {\n const size = cache._sizes[index]!;\n return size === UNCACHED ? cache._defaultItemSize : size;\n};\n\nexport const setItemSize = (\n cache: Writeable<Cache>,\n index: number,\n size: number\n) => {\n cache._sizes[index] = size;\n // mark as dirty\n cache._measuredOffsetIndex = min(index, cache._measuredOffsetIndex);\n};\n\nconst computeOffset = (\n cache: Writeable<Cache>,\n index: number,\n isTotal?: boolean\n): number => {\n if (!cache._length) return 0;\n if (cache._measuredOffsetIndex >= index) {\n if (isTotal) {\n return cache._offsets[index]! + getItemSize(cache, index);\n } else {\n return cache._offsets[index]!;\n }\n }\n\n let i = cache._measuredOffsetIndex;\n let top = cache._offsets[i]!;\n while (i <= index) {\n cache._offsets[i] = top;\n if (i === index && !isTotal) {\n break;\n }\n top += getItemSize(cache, i);\n i++;\n }\n // mark as measured\n cache._measuredOffsetIndex = index;\n return top;\n};\n\nexport const computeTotalSize = (cache: Writeable<Cache>): number => {\n return computeOffset(cache, cache._length - 1, true);\n};\n\nexport const computeStartOffset = (\n cache: Writeable<Cache>,\n index: number\n): number => {\n return computeOffset(cache, index);\n};\n\nconst findIndex = (cache: Cache, i: number, distance: number): number => {\n let sum = 0;\n if (distance >= 0) {\n // search forward\n while (i < cache._length - 1) {\n const h = getItemSize(cache, i++);\n if ((sum += h) >= distance) {\n if (sum - h / 2 >= distance) {\n i--;\n }\n break;\n }\n }\n } else {\n // search backward\n while (i > 0) {\n const h = getItemSize(cache, --i);\n if ((sum -= h) <= distance) {\n if (sum + h / 2 < distance) {\n i++;\n }\n break;\n }\n }\n }\n\n return min(max(i, 0), cache._length - 1);\n};\n\nexport const findStartIndexWithOffset = (\n cache: Cache,\n offset: number,\n prevStartIndex: number,\n prevOffset: number\n): number => {\n return findIndex(cache, prevStartIndex, offset - prevOffset);\n};\n\nexport const findEndIndex = findIndex;\n\nexport const hasUnmeasuredItemsInRange = (\n cache: Cache,\n startIndex: number,\n endIndex: number\n): boolean => {\n for (let i = startIndex; i <= endIndex; i++) {\n if (cache._sizes[i] === UNCACHED) {\n return true;\n }\n }\n return false;\n};\n\nexport const resetCache = (\n length: number,\n itemSize: number,\n cache?: Cache\n): Cache => {\n return {\n _defaultItemSize: itemSize,\n _length: length,\n _measuredOffsetIndex: cache\n ? min(cache._measuredOffsetIndex, length - 1)\n : 0,\n _sizes: range(length, (i) => {\n const size = cache && cache._sizes[i];\n if (exists(size)) {\n return size;\n }\n return UNCACHED;\n }),\n _offsets: range(length, (i) => {\n if (i === 0) {\n // first offset must be 0\n return 0;\n }\n const offset = cache && cache._offsets[i];\n if (exists(offset)) {\n return offset;\n }\n return UNCACHED;\n }),\n };\n};\n","import { useEffect, useLayoutEffect } from \"react\";\n\n// https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85\nexport const useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n","import { useSyncExternalStore as _useSyncExternalStore } from \"use-sync-external-store/shim/index.js\";\n\nexport const useSyncExternalStore = <T>(\n subscibe: (onStoreChange: () => void) => () => void,\n getSnapShot: () => T\n): T => {\n return _useSyncExternalStore(subscibe, getSnapShot, getSnapShot);\n};\n","export const refKey = \"current\";\n","import { useRef } from \"react\";\nimport { refKey } from \"./utils\";\n\nexport const useStatic = <T>(init: () => T): T => {\n const ref = useRef<T>();\n return ref[refKey] || (ref[refKey] = init());\n};\n","import { useRef } from \"react\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\nimport { refKey } from \"./utils\";\n\nexport const useRefWithUpdate = <T>(value: T) => {\n const ref = useRef<T>(value);\n\n useIsomorphicLayoutEffect(() => {\n ref[refKey] = value;\n }, [value]);\n\n return ref;\n};\n","import {\n Children,\n memo,\n useRef,\n useMemo,\n CSSProperties,\n ReactElement,\n forwardRef,\n useImperativeHandle,\n ReactNode,\n useEffect,\n RefObject,\n useState,\n ReactFragment,\n} from \"react\";\nimport {\n ACTION_UPDATE_CACHE_LENGTH,\n VirtualStore,\n createVirtualStore,\n} from \"../core/store\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\nimport { useSyncExternalStore } from \"./useSyncExternalStore\";\nimport { exists, max, min } from \"../core/utils\";\nimport { createScroller, Scroller } from \"../core/scroller\";\nimport { refKey } from \"./utils\";\nimport { useStatic } from \"./useStatic\";\nimport { useRefWithUpdate } from \"./useRefWithUpdate\";\n\ntype ItemProps = {\n _children: ReactNode;\n _scroller: Scroller;\n _store: VirtualStore;\n _index: number;\n _element: \"div\";\n};\n\nconst Item = memo(\n ({\n _children: children,\n _scroller: scroller,\n _store: store,\n _index: index,\n _element: Element,\n }: ItemProps): ReactElement => {\n const ref = useRef<HTMLDivElement>(null);\n\n const offset = useSyncExternalStore(store._subscribe, () =>\n store._getItemOffset(index)\n );\n const hide = useSyncExternalStore(store._subscribe, () =>\n store._isUnmeasuredItem(index)\n );\n\n // The index may be changed if elements are inserted to or removed from the start of props.children\n useIsomorphicLayoutEffect(\n () => scroller._initItem(ref[refKey]!, index),\n [index]\n );\n\n return (\n <Element\n ref={ref}\n style={useMemo((): CSSProperties => {\n const isHorizontal = store._isHorizontal();\n const leftOrRightKey = store._isRtl() ? \"right\" : \"left\";\n const style: CSSProperties = {\n margin: 0,\n padding: 0,\n position: \"absolute\",\n [isHorizontal ? \"height\" : \"width\"]: \"100%\",\n [isHorizontal ? \"top\" : leftOrRightKey]: 0,\n [isHorizontal ? leftOrRightKey : \"top\"]: offset,\n visibility: hide ? \"hidden\" : \"visible\",\n // willChange: \"transform\",\n };\n if (isHorizontal) {\n style.display = \"flex\";\n }\n return style;\n }, [offset, hide])}\n >\n {children}\n </Element>\n );\n }\n);\n\nconst isInvalidElement = <T extends ReactNode>(\n e: T\n): e is Extract<T, null | undefined | boolean> =>\n !exists(e) || typeof e === \"boolean\";\n\nexport type WindowComponentAttributes = Pick<\n React.HTMLAttributes<HTMLElement>,\n \"className\" | \"style\" | \"id\" | \"role\" | \"tabIndex\"\n> &\n React.AriaAttributes;\n\n/**\n * Props of customized scrollable component.\n */\nexport interface CustomWindowComponentProps {\n children: ReactNode;\n scrollSize: number;\n scrolling: boolean;\n horizontal: boolean;\n attrs: WindowComponentAttributes;\n}\n\nconst DefaultWindow = forwardRef<any, CustomWindowComponentProps>(\n (\n { children, scrollSize, scrolling, horizontal, attrs },\n ref\n ): ReactElement => {\n return (\n <div ref={ref} {...attrs}>\n <div\n style={useMemo((): CSSProperties => {\n return {\n position: \"relative\",\n visibility: \"hidden\",\n width: horizontal ? scrollSize : \"100%\",\n height: horizontal ? \"100%\" : scrollSize,\n pointerEvents: scrolling ? \"none\" : \"auto\",\n };\n }, [scrollSize, scrolling])}\n >\n {children}\n </div>\n </div>\n );\n }\n);\n\nexport type CustomWindowComponent = typeof DefaultWindow;\n\nconst Window = ({\n _children: children,\n _ref: ref,\n _store: store,\n _element: Element,\n _scrolling: scrolling,\n _attrs: attrs,\n}: {\n _children: ReactNode;\n _ref: RefObject<HTMLDivElement>;\n _store: VirtualStore;\n _element: CustomWindowComponent;\n _scrolling: boolean;\n _attrs: WindowComponentAttributes;\n}) => {\n const scrollSize = useSyncExternalStore(\n store._subscribe,\n store._getScrollSize\n );\n\n const horizontal = store._isHorizontal();\n\n return (\n <Element\n ref={ref}\n scrollSize={scrollSize}\n scrolling={scrolling}\n horizontal={horizontal}\n attrs={useMemo(\n () => ({\n ...attrs,\n style: {\n overflow: horizontal ? \"auto hidden\" : \"hidden auto\",\n contain: \"strict\",\n // transform: \"translate3d(0px, 0px, 0px)\",\n // willChange: \"scroll-position\",\n // backfaceVisibility: \"hidden\",\n width: \"100%\",\n height: \"100%\",\n padding: 0,\n margin: 0,\n ...attrs.style,\n },\n }),\n [attrs]\n )}\n >\n {children}\n </Element>\n );\n};\n\n/**\n * Props of customized item component.\n */\nexport interface CustomItemComponentProps {\n style: CSSProperties;\n children: ReactNode;\n}\n\nexport type CustomItemComponent = React.ForwardRefExoticComponent<\n React.PropsWithoutRef<CustomItemComponentProps> & React.RefAttributes<any>\n>;\n\ntype CustomItemComponentOrElement =\n | keyof JSX.IntrinsicElements\n | CustomItemComponent;\n\n/**\n * Methods of {@link VList}.\n */\nexport interface VListHandle {\n /**\n * Get current scrollTop or scrollLeft.\n */\n readonly scrollOffset: number;\n /**\n * Get current scrollHeight or scrollWidth.\n */\n readonly scrollSize: number;\n /**\n * Get current offsetHeight or offsetWidth.\n */\n readonly viewportSize: number;\n /**\n * Scroll to the item specified by index.\n * @param index index of item\n */\n scrollToIndex(index: number): void;\n /**\n * Scroll to the given offset.\n * @param offset offset from start\n */\n scrollTo(offset: number): void;\n /**\n * Scroll by the given offset.\n * @param offset offset from current position\n */\n scrollBy(offset: number): void;\n}\n\n/**\n * Props of {@link VList}.\n */\nexport interface VListProps extends WindowComponentAttributes {\n /**\n * Elements rendered by this component.\n */\n children: ReactNode;\n /**\n * Item size hint for unmeasured items. It's recommended to specify this prop if item sizes are fixed and known, or much larger than the defaultValue. It will help to reduce scroll jump when items are measured.\n * @defaultValue 40\n */\n itemSize?: number;\n /**\n * Number of items to render above/below the visible bounds of the list. You can increase to avoid showing blank items in fast scrolling.\n * @defaultValue 4\n */\n overscan?: number;\n /**\n * If true, rendered as a horizontally scrollable list. Otherwise rendered as a vertically scrollable list.\n */\n horizontal?: boolean;\n /**\n * You have to set true if you use this component under `direction: rtl` style.\n */\n rtl?: boolean;\n /**\n * Customized element type for scrollable element. This element will get {@link CustomWindowComponentProps} as props.\n * @defaultValue {@link DefaultWindow}\n */\n element?: CustomWindowComponent;\n /**\n * Customized element type for item element. This element will get {@link CustomItemComponentProps} as props.\n * @defaultValue \"div\"\n */\n itemElement?: CustomItemComponentOrElement;\n /**\n * Callback invoked whenever scroll offset changes.\n * @param offset Current scrollTop or scrollLeft.\n */\n onScroll?: (offset: number) => void;\n /**\n * Callback invoked when scrolling stops.\n */\n onScrollStop?: () => void;\n /**\n * Callback invoked when visible items range changes.\n * @param payload `start` is the start index of viewable items. `end` is the end index of viewable items. `count` is the total count of items.\n */\n onRangeChange?: (payload: {\n start: number;\n end: number;\n count: number;\n }) => void;\n}\n\n/**\n * Virtualized list component. See {@link VListProps} and {@link VListHandle}.\n */\nexport const VList = forwardRef<VListHandle, VListProps>(\n (\n {\n children,\n itemSize: itemSizeProp = 40,\n overscan = 4,\n horizontal: horizontalProp,\n rtl: rtlProp,\n element = DefaultWindow,\n itemElement = \"div\",\n onScroll: onScrollProp,\n onScrollStop: onScrollStopProp,\n onRangeChange: onRangeChangeProp,\n ...windowAttrs\n },\n ref\n ): ReactElement => {\n // Memoize element array\n const elements = useMemo(() => {\n const arr: (ReactElement | ReactFragment | string | number)[] = [];\n Children.forEach(children, (e) => {\n if (isInvalidElement(e)) {\n return;\n }\n arr.push(e);\n });\n return arr;\n }, [children]);\n const elementsCount = elements.length;\n\n // https://github.com/facebook/react/issues/25191#issuecomment-1237456448\n const store = useStatic(() =>\n createVirtualStore(\n elementsCount,\n itemSizeProp,\n !!horizontalProp,\n !!rtlProp\n )\n );\n const [startIndex, endIndex] = useSyncExternalStore(\n store._subscribe,\n store._getRange\n );\n const jump = useSyncExternalStore(store._subscribe, store._getJump);\n const rootRef = useRef<HTMLDivElement>(null);\n\n const onScroll = useRefWithUpdate(onScrollProp);\n const onScrollStop = useRefWithUpdate(onScrollStopProp);\n\n const [mountedIndexes, reset] = useState<Set<number>>(new Set<number>());\n const [scrolling, setScrolling] = useState(false);\n const scroller = useStatic(() =>\n createScroller(\n store,\n (offset) => {\n onScroll[refKey] && onScroll[refKey](offset);\n },\n (isScrolling) => {\n setScrolling(isScrolling);\n if (!isScrolling) {\n reset(new Set());\n onScrollStop[refKey] && onScrollStop[refKey]();\n }\n }\n )\n );\n\n // The elements length and cached items length are different just after element is added/removed.\n const count = min(elementsCount, store._getItemCount());\n\n // So update cache length. Updating state in render will cause warn so use useEffect for now.\n useIsomorphicLayoutEffect(() => {\n store._update(ACTION_UPDATE_CACHE_LENGTH, elementsCount);\n }, [elementsCount]);\n\n useIsomorphicLayoutEffect(() => scroller._initRoot(rootRef[refKey]!), []);\n\n useIsomorphicLayoutEffect(() => {\n if (!jump.length) return;\n\n scroller._fixScrollJump(jump, startIndex);\n }, [jump]);\n\n useEffect(() => {\n if (!onRangeChangeProp) return;\n\n onRangeChangeProp({\n start: startIndex,\n end: endIndex,\n count,\n });\n }, [startIndex, endIndex]);\n\n useImperativeHandle(\n ref,\n () => {\n return {\n get scrollOffset() {\n return store._getScrollOffset();\n },\n get scrollSize() {\n return scroller._getActualScrollSize();\n },\n get viewportSize() {\n return store._getViewportSize();\n },\n scrollToIndex(index) {\n scroller._scrollToIndex(index, count);\n },\n scrollTo: scroller._scrollTo,\n scrollBy(offset) {\n scroller._scrollTo(store._getScrollOffset() + offset);\n },\n };\n },\n [count]\n );\n\n const startIndexWithMargin = max(startIndex - overscan, 0);\n const endIndexWithMargin = min(endIndex + overscan, count - 1);\n const items = useMemo(() => {\n const res: ReactElement[] = [];\n for (let i = startIndexWithMargin; i <= endIndexWithMargin; i++) {\n // https://github.com/sergi/virtual-list/commit/8e7e06dc63568334c1ab809ea83c1be36572e9ed\n mountedIndexes.add(i);\n }\n mountedIndexes.forEach((i) => {\n const e = elements[i];\n // This can be undefined when items are removed\n if (exists(e)) {\n res.push(\n <Item\n key={(e as { key?: ReactElement[\"key\"] })?.key || i}\n _scroller={scroller}\n _store={store}\n _index={i}\n _element={itemElement as \"div\"}\n _children={e}\n />\n );\n }\n });\n return res;\n }, [elements, mountedIndexes, startIndexWithMargin, endIndexWithMargin]);\n\n return (\n <Window\n _ref={rootRef}\n _store={store}\n _element={element}\n _scrolling={scrolling}\n _children={items}\n _attrs={windowAttrs}\n />\n );\n }\n);\n","import {\n findStartIndexWithOffset,\n resetCache,\n getItemSize,\n computeTotalSize,\n findEndIndex,\n computeStartOffset,\n Cache,\n UNCACHED,\n setItemSize,\n hasUnmeasuredItemsInRange,\n} from \"./cache\";\nimport type { Writeable } from \"./types\";\n\nexport type ScrollJump = Readonly<[index: number, sizeDiff: number][]>;\nexport type ItemResize = [index: number, size: number];\ntype ItemsRange = [startIndex: number, endIndex: number];\n\nexport const ACTION_UPDATE_CACHE_LENGTH = 0;\nexport const ACTION_UPDATE_ITEM_SIZES = 1;\nexport const ACTION_UPDATE_VIEWPORT = 2;\nexport const ACTION_HANDLE_SCROLL = 3;\n\ntype Actions =\n | [type: typeof ACTION_UPDATE_CACHE_LENGTH, length: number]\n | [type: typeof ACTION_UPDATE_ITEM_SIZES, entries: ItemResize[]]\n | [\n type: typeof ACTION_UPDATE_VIEWPORT,\n rect: { _width: number; _height: number }\n ]\n | [type: typeof ACTION_HANDLE_SCROLL, offset: number];\n\nexport type VirtualStore = {\n _getRange(): ItemsRange;\n _isUnmeasuredItem(index: number): boolean;\n _hasUnmeasuredItemsInRange(startIndex: number): boolean;\n _getItemOffset(index: number): number;\n _getScrollOffset(): number;\n _getViewportSize(): number;\n _getScrollSize(): number;\n _getItemCount(): number;\n _getJump(): ScrollJump;\n _isHorizontal(): boolean;\n _isRtl(): boolean;\n _getItemIndexForScrollTo(offset: number): number;\n _waitForScrollDestinationItemsMeasured(): Promise<void>;\n _subscribe(cb: () => void): () => void;\n _update(...action: Actions): void;\n};\n\nexport const createVirtualStore = (\n itemCount: number,\n itemSize: number,\n isHorizontal: boolean,\n isRtl: boolean\n): VirtualStore => {\n let viewportWidth = 0;\n let viewportHeight = 0;\n let scrollOffset = 0;\n let jump: ScrollJump = [];\n let cache = resetCache(itemCount, itemSize);\n let _prevRange: ItemsRange = [0, 0];\n let _scrollToQueue: [() => void, () => void] | undefined;\n\n const subscribers = new Set<() => void>();\n const getViewportSize = (): number =>\n isHorizontal ? viewportWidth : viewportHeight;\n\n return {\n _getRange() {\n const [prevStartIndex, prevEndIndex] = _prevRange;\n const prevOffset = computeStartOffset(\n cache as Writeable<Cache>,\n prevStartIndex\n );\n const start = findStartIndexWithOffset(\n cache,\n scrollOffset,\n prevStartIndex,\n prevOffset\n );\n const end = findEndIndex(cache, start, getViewportSize());\n if (prevStartIndex === start && prevEndIndex === end) {\n return _prevRange;\n }\n return (_prevRange = [start, end]);\n },\n _isUnmeasuredItem(index) {\n return cache._sizes[index] === UNCACHED;\n },\n _hasUnmeasuredItemsInRange(startIndex) {\n return hasUnmeasuredItemsInRange(\n cache,\n startIndex,\n findEndIndex(cache, startIndex, getViewportSize())\n );\n },\n _getItemOffset(index) {\n return computeStartOffset(cache as Writeable<Cache>, index);\n },\n _getScrollOffset() {\n return scrollOffset;\n },\n _getViewportSize() {\n return getViewportSize();\n },\n _getScrollSize() {\n return computeTotalSize(cache as Writeable<Cache>);\n },\n _getItemCount() {\n return cache._length;\n },\n _getJump() {\n return jump;\n },\n _isHorizontal() {\n return isHorizontal;\n },\n _isRtl() {\n return isRtl;\n },\n _getItemIndexForScrollTo(offset) {\n return findStartIndexWithOffset(cache, offset, 0, 0);\n },\n _waitForScrollDestinationItemsMeasured() {\n if (_scrollToQueue) {\n // Cancel waiting scrollTo\n _scrollToQueue[1]();\n }\n // The measurement will be done asynchronously and the timing is not predictable so we use promise.\n // For example, ResizeObserver may not fire when window is not visible.\n return new Promise((resolve, reject) => {\n _scrollToQueue = [\n () => {\n // HACK: It should be resolved in the next microtask that is after React's render\n Promise.resolve().then(() => {\n resolve();\n _scrollToQueue = undefined;\n });\n },\n reject,\n ];\n });\n },\n _subscribe(cb) {\n subscribers.add(cb);\n return () => {\n subscribers.delete(cb);\n };\n },\n _update(type, payload) {\n const mutated = ((): boolean => {\n switch (type) {\n case ACTION_UPDATE_CACHE_LENGTH: {\n if (cache._length === payload) return false;\n cache = resetCache(payload, itemSize, cache);\n return true;\n }\n case ACTION_UPDATE_ITEM_SIZES: {\n const updated = payload.filter(\n ([index, size]) => cache._sizes[index] !== size\n );\n // Skip if all items are cached and not updated\n if (!updated.length) {\n return false;\n }\n\n const updatedJump: [index: number, sizeDiff: number][] = [];\n updated.forEach(([index, size]) => {\n updatedJump.push([index, size - getItemSize(cache, index)]);\n setItemSize(cache as Writeable<Cache>, index, size);\n });\n jump = updatedJump;\n return true;\n }\n case ACTION_UPDATE_VIEWPORT: {\n if (\n viewportWidth === payload._width &&\n viewportHeight === payload._height\n ) {\n return false;\n }\n viewportWidth = payload._width;\n viewportHeight = payload._height;\n return true;\n }\n case ACTION_HANDLE_SCROLL: {\n const prevOffset = scrollOffset;\n return (scrollOffset = payload) !== prevOffset;\n }\n }\n })();\n\n if (mutated) {\n subscribers.forEach((cb) => {\n cb();\n });\n if (_scrollToQueue && type === ACTION_UPDATE_ITEM_SIZES) {\n _scrollToQueue[0]();\n }\n }\n },\n };\n};\n","import {\n ACTION_HANDLE_SCROLL,\n ACTION_UPDATE_ITEM_SIZES,\n ACTION_UPDATE_VIEWPORT,\n ItemResize,\n ScrollJump,\n VirtualStore,\n} from \"./store\";\nimport { abs, debounce, throttle, exists, max, min } from \"./utils\";\n\nexport const SCROLL_STOP = 0;\nexport const SCROLL_DOWN = 1;\nexport const SCROLL_UP = 2;\nexport const SCROLL_MANUAL = 3;\ntype ScrollDirection =\n | typeof SCROLL_STOP\n | typeof SCROLL_DOWN\n | typeof SCROLL_UP\n | typeof SCROLL_MANUAL;\n\nexport type Scroller = {\n _initRoot: (rootElement: HTMLElement) => () => void;\n _initItem: (itemElement: HTMLElement, index: number) => () => void;\n _getActualScrollSize: () => number;\n _scrollTo: (offset: number) => void;\n _scrollToIndex: (index: number, count: number) => void;\n _fixScrollJump: (jump: ScrollJump, startIndex: number) => void;\n};\n\nexport const createScroller = (\n store: VirtualStore,\n emitScrollOffsetChange: (offset: number) => void,\n emitScrollStateChange: (scrolling: boolean) => void\n): Scroller => {\n let prevOffset = -1;\n let scrollDirection: ScrollDirection = SCROLL_STOP;\n let resized = false;\n let isNegativeOffset: boolean | undefined;\n let rootElement: HTMLElement | undefined;\n let _ro: ResizeObserver | undefined;\n const isHorizontal = store._isHorizontal();\n const isRtl = store._isRtl();\n const scrollToKey = isHorizontal ? \"scrollLeft\" : \"scrollTop\";\n const mountedIndexes = new WeakMap<Element, number>();\n const getResizeObserver = (): ResizeObserver => {\n // Initialize ResizeObserver lazily for SSR\n return (\n _ro ||\n (_ro = new ResizeObserver((entries) => {\n // https://www.w3.org/TR/resize-observer/#intro\n const resizes: ItemResize[] = [];\n for (const entry of entries) {\n if (entry.target === rootElement) {\n store._update(ACTION_UPDATE_VIEWPORT, {\n _width: entry.contentRect.width,\n _height: entry.contentRect.height,\n });\n } else {\n const index = mountedIndexes.get(entry.target);\n if (exists(index)) {\n resizes.push([\n index,\n entry.contentRect[isHorizontal ? \"width\" : \"height\"],\n ]);\n }\n }\n }\n\n if (resizes.length) {\n store._update(ACTION_UPDATE_ITEM_SIZES, resizes);\n resized = true;\n }\n }))\n );\n };\n const getActualScrollSize = (): number => {\n if (!rootElement) return 0;\n // Use element's scrollHeight/scrollWidth instead of stored scrollSize.\n // This is because stored size may differ from the actual size, for example when a new item is added and not yet measured.\n return store._isHorizontal()\n ? rootElement.scrollWidth\n : rootElement.scrollHeight;\n };\n const updateScrollPosition = (offset: number, diff?: boolean) => {\n if (!rootElement) return;\n if (isRtl) {\n if (!exists(isNegativeOffset)) {\n // Assume offset type in rtl direction.\n // The scroll position is negative in spec however its not in some browsers, for example Chrome earlier than v85.\n // https://github.com/othree/jquery.rtl-scroll-type\n const prev = rootElement[scrollToKey];\n rootElement[scrollToKey] = 1;\n isNegativeOffset = rootElement[scrollToKey] === 0;\n rootElement[scrollToKey] = prev;\n }\n if (isNegativeOffset) {\n offset *= -1;\n }\n }\n if (diff) {\n rootElement[scrollToKey] += offset;\n } else {\n rootElement[scrollToKey] = offset;\n scrollDirection = SCROLL_MANUAL;\n }\n };\n const scrollTo = async (index: number, getCurrentOffset: () => number) => {\n const getOffset = (): number => {\n let offset = getCurrentOffset();\n const scrollSize = getActualScrollSize();\n const viewportSize = store._getViewportSize();\n if (scrollSize - (offset + viewportSize) <= 0) {\n // Adjust if the offset is over the end, to get correct startIndex.\n offset = scrollSize - viewportSize;\n }\n return offset;\n };\n\n if (store._hasUnmeasuredItemsInRange(index)) {\n do {\n // In order to scroll to the correct position, mount the items and measure their sizes before scrolling.\n store._update(ACTION_HANDLE_SCROLL, getOffset());\n try {\n // Wait for the scroll destination items to be measured.\n await store._waitForScrollDestinationItemsMeasured();\n } catch (e) {\n // canceled\n return;\n }\n } while (store._hasUnmeasuredItemsInRange(index));\n\n // Scroll with the updated value\n updateScrollPosition(getOffset());\n } else {\n const offset = getOffset();\n updateScrollPosition(offset);\n // Sync viewport to scroll destination\n store._update(ACTION_HANDLE_SCROLL, offset);\n }\n };\n\n const calcTotalJump = (jump: ScrollJump): number =>\n jump.reduce((acc, [, j]) => acc + j, 0);\n\n return {\n _initRoot(root) {\n rootElement = root;\n const ro = getResizeObserver();\n\n const syncViewportToScrollPosition = () => {\n let offset = root[scrollToKey];\n if (isRtl) {\n // The scroll position may be negative value in rtl direction.\n // https://github.com/othree/jquery.rtl-scroll-type\n offset = abs(offset);\n }\n if (prevOffset === offset) {\n return;\n }\n // Skip scroll direction detection just after resizing because it may result in the opposite direction.\n // Scroll events are dispatched enough so it's ok to skip some of them.\n if (scrollDirection === SCROLL_STOP || !resized) {\n // Ignore until manual scrolling\n if (scrollDirection !== SCROLL_MANUAL) {\n scrollDirection = prevOffset > offset ? SCROLL_UP : SCROLL_DOWN;\n }\n } else {\n resized = false;\n }\n store._update(ACTION_HANDLE_SCROLL, (prevOffset = offset));\n emitScrollOffsetChange(offset);\n };\n\n const onScrollStopped = debounce(() => {\n // Check scroll position once just after scrolling stopped\n syncViewportToScrollPosition();\n scrollDirection = SCROLL_STOP;\n emitScrollStateChange(false);\n }, 150);\n\n const onScroll = () => {\n const isScrollStart = scrollDirection === SCROLL_STOP;\n syncViewportToScrollPosition();\n if (isScrollStart) {\n emitScrollStateChange(true);\n }\n onScrollStopped();\n };\n\n // Infer scroll state also from wheel events\n // Sometimes scroll events do not fire when frame dropped even if the visual have been already scrolled\n const onWheel = throttle((e: WheelEvent) => {\n if (scrollDirection === SCROLL_STOP) {\n // Scroll start should be detected with scroll event\n return;\n }\n if (e.ctrlKey) {\n // Probably a pinch-to-zoom gesture\n return;\n }\n // Get delta before checking deltaMode for firefox behavior\n // https://github.com/w3c/uievents/issues/181#issuecomment-392648065\n // https://bugzilla.mozilla.org/show_bug.cgi?id=1392460#c34\n if (isHorizontal ? e.deltaX : e.deltaY) {\n if (\n prevOffset > 0 &&\n prevOffset < store._getScrollSize() - store._getViewportSize()\n ) {\n onScrollStopped();\n }\n }\n }, 50);\n\n ro.observe(root);\n root.addEventListener(\"scroll\", onScroll);\n root.addEventListener(\"wheel\", onWheel, { passive: true });\n\n return () => {\n ro.disconnect();\n root.removeEventListener(\"scroll\", onScroll);\n root.removeEventListener(\"wheel\", onWheel);\n onScrollStopped._cancel();\n };\n },\n _initItem(el, i) {\n const ro = getResizeObserver();\n mountedIndexes.set(el, i);\n ro.observe(el);\n return () => {\n mountedIndexes.delete(el);\n ro.unobserve(el);\n };\n },\n _getActualScrollSize: getActualScrollSize,\n _scrollTo(offset) {\n offset = max(offset, 0);\n\n scrollTo(store._getItemIndexForScrollTo(offset), () => offset);\n },\n _scrollToIndex(index, count) {\n index = max(min(index, count - 1), 0);\n\n scrollTo(index, () => store._getItemOffset(index));\n },\n _fixScrollJump: (jump, startIndex) => {\n // Compensate scroll jump\n if (scrollDirection === SCROLL_UP) {\n const diff = calcTotalJump(jump);\n if (diff) {\n updateScrollPosition(diff, true);\n }\n } else if (scrollDirection === SCROLL_MANUAL) {\n const offset = store._getScrollOffset();\n if (offset === 0) {\n // Do nothing to stick to the start\n } else {\n const allDiff = calcTotalJump(jump);\n if (\n store._getScrollSize() -\n (offset + store._getViewportSize() + allDiff) <=\n 0\n ) {\n // Keep end to stick to the end\n if (allDiff) {\n updateScrollPosition(offset + allDiff);\n }\n } else {\n // Keep start at mid\n const diff = jump.reduce((acc, [index, j]) => {\n if (index < startIndex) {\n acc += j;\n }\n return acc;\n }, 0);\n if (diff) {\n updateScrollPosition(diff, true);\n }\n }\n }\n } else {\n // NOP\n }\n },\n };\n};\n"],"names":["min","Math","max","abs","now","Date","exists","v","range","length","cb","Array","from","_","i","getItemSize","cache","index","size","_sizes","_defaultItemSize","computeOffset","isTotal","_length","_measuredOffsetIndex","_offsets","top","computeStartOffset","findIndex","distance","sum","h","findStartIndexWithOffset","offset","prevStartIndex","prevOffset","findEndIndex","resetCache","itemSize","useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect","useSyncExternalStore","subscibe","getSnapShot","_useSyncExternalStore","refKey","useStatic","init","ref","useRef","useRefWithUpdate","value","Item","memo","_children","children","_scroller","scroller","_store","store","_index","_element","Element","_subscribe","_getItemOffset","hide","_isUnmeasuredItem","_initItem","_jsx","style","useMemo","isHorizontal","_isHorizontal","leftOrRightKey","_isRtl","margin","padding","position","visibility","display","DefaultWindow","forwardRef","scrollSize","scrolling","horizontal","attrs","width","height","pointerEvents","Window","_ref","_scrolling","_attrs","_getScrollSize","overflow","contain","VList","itemSizeProp","overscan","horizontalProp","rtl","rtlProp","element","itemElement","onScroll","onScrollProp","onScrollStop","onScrollStopProp","onRangeChange","onRangeChangeProp","windowAttrs","elements","arr","Children","forEach","e","isInvalidElement","push","elementsCount","createVirtualStore","itemCount","isRtl","_scrollToQueue","viewportWidth","viewportHeight","scrollOffset","jump","_prevRange","subscribers","Set","getViewportSize","_getRange","prevEndIndex","start","end","_hasUnmeasuredItemsInRange","startIndex","hasUnmeasuredItemsInRange","endIndex","_getScrollOffset","_getViewportSize","computeTotalSize","_getItemCount","_getJump","_getItemIndexForScrollTo","_waitForScrollDestinationItemsMeasured","Promise","resolve","reject","then","undefined","add","delete","_update","type","payload","updated","filter","updatedJump","setItemSize","_width","_height","rootRef","mountedIndexes","reset","useState","setScrolling","createScroller","emitScrollOffsetChange","emitScrollStateChange","isNegativeOffset","rootElement","_ro","scrollDirection","resized","scrollToKey","WeakMap","getResizeObserver","ResizeObserver","entries","resizes","entry","target","contentRect","get","getActualScrollSize","scrollWidth","scrollHeight","updateScrollPosition","diff","prev","scrollTo","async","getCurrentOffset","getOffset","viewportSize","calcTotalJump","reduce","acc","j","_initRoot","root","ro","syncViewportToScrollPosition","onScrollStopped","debounce","id","cancel","clearTimeout","debouncedFn","setTimeout","_cancel","isScrollStart","onWheel","throttle","time","args","n","ctrlKey","deltaX","deltaY","fn","observe","addEventListener","passive","disconnect","removeEventListener","el","set","unobserve","_getActualScrollSize","_scrollTo","_scrollToIndex","count","_fixScrollJump","allDiff","isScrolling","useImperativeHandle","scrollToIndex","scrollBy","startIndexWithMargin","endIndexWithMargin","items","res","key"],"mappings":"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"}
@@ -1,14 +1,14 @@
1
1
  import { CSSProperties, ReactNode } from "react";
2
+ export type WindowComponentAttributes = Pick<React.HTMLAttributes<HTMLElement>, "className" | "style" | "id" | "role" | "tabIndex"> & React.AriaAttributes;
2
3
  /**
3
4
  * Props of customized scrollable component.
4
5
  */
5
6
  export interface CustomWindowComponentProps {
6
7
  children: ReactNode;
7
- style: CSSProperties;
8
8
  scrollSize: number;
9
9
  scrolling: boolean;
10
10
  horizontal: boolean;
11
- rtl: boolean;
11
+ attrs: WindowComponentAttributes;
12
12
  }
13
13
  declare const DefaultWindow: import("react").ForwardRefExoticComponent<CustomWindowComponentProps & import("react").RefAttributes<any>>;
14
14
  export type CustomWindowComponent = typeof DefaultWindow;
@@ -22,32 +22,41 @@ export interface CustomItemComponentProps {
22
22
  export type CustomItemComponent = React.ForwardRefExoticComponent<React.PropsWithoutRef<CustomItemComponentProps> & React.RefAttributes<any>>;
23
23
  type CustomItemComponentOrElement = keyof JSX.IntrinsicElements | CustomItemComponent;
24
24
  /**
25
- * Methods of {@link List}.
25
+ * Methods of {@link VList}.
26
26
  */
27
- export interface ListHandle {
27
+ export interface VListHandle {
28
28
  /**
29
29
  * Get current scrollTop or scrollLeft.
30
30
  */
31
- scrollOffset: number;
31
+ readonly scrollOffset: number;
32
32
  /**
33
33
  * Get current scrollHeight or scrollWidth.
34
34
  */
35
- scrollSize: number;
35
+ readonly scrollSize: number;
36
+ /**
37
+ * Get current offsetHeight or offsetWidth.
38
+ */
39
+ readonly viewportSize: number;
36
40
  /**
37
41
  * Scroll to the item specified by index.
38
42
  * @param index index of item
39
43
  */
40
44
  scrollToIndex(index: number): void;
41
45
  /**
42
- * Scroll to the item specified by offset.
46
+ * Scroll to the given offset.
43
47
  * @param offset offset from start
44
48
  */
45
- scrollToOffset(offset: number): void;
49
+ scrollTo(offset: number): void;
50
+ /**
51
+ * Scroll by the given offset.
52
+ * @param offset offset from current position
53
+ */
54
+ scrollBy(offset: number): void;
46
55
  }
47
56
  /**
48
- * Props of {@link List}.
57
+ * Props of {@link VList}.
49
58
  */
50
- export interface ListProps {
59
+ export interface VListProps extends WindowComponentAttributes {
51
60
  /**
52
61
  * Elements rendered by this component.
53
62
  */
@@ -70,15 +79,6 @@ export interface ListProps {
70
79
  * You have to set true if you use this component under `direction: rtl` style.
71
80
  */
72
81
  rtl?: boolean;
73
- /**
74
- * Number of items to be the margin from the end of the scroll. See also {@link onEndReached}.
75
- * @defaultValue 0
76
- */
77
- endThreshold?: number;
78
- /**
79
- * Inline style prop to override style of scrollable element.
80
- */
81
- style?: CSSProperties;
82
82
  /**
83
83
  * Customized element type for scrollable element. This element will get {@link CustomWindowComponentProps} as props.
84
84
  * @defaultValue {@link DefaultWindow}
@@ -89,10 +89,6 @@ export interface ListProps {
89
89
  * @defaultValue "div"
90
90
  */
91
91
  itemElement?: CustomItemComponentOrElement;
92
- /**
93
- * Callback invoked when scrolling reached to the end. The margin from the end is specified by {@link endThreshold}.
94
- */
95
- onEndReached?: () => void;
96
92
  /**
97
93
  * Callback invoked whenever scroll offset changes.
98
94
  * @param offset Current scrollTop or scrollLeft.
@@ -102,9 +98,18 @@ export interface ListProps {
102
98
  * Callback invoked when scrolling stops.
103
99
  */
104
100
  onScrollStop?: () => void;
101
+ /**
102
+ * Callback invoked when visible items range changes.
103
+ * @param payload `start` is the start index of viewable items. `end` is the end index of viewable items. `count` is the total count of items.
104
+ */
105
+ onRangeChange?: (payload: {
106
+ start: number;
107
+ end: number;
108
+ count: number;
109
+ }) => void;
105
110
  }
106
111
  /**
107
- * Virtualized list component. See {@link ListProps} and {@link ListHandle}.
112
+ * Virtualized list component. See {@link VListProps} and {@link VListHandle}.
108
113
  */
109
- export declare const List: import("react").ForwardRefExoticComponent<ListProps & import("react").RefAttributes<ListHandle>>;
114
+ export declare const VList: import("react").ForwardRefExoticComponent<VListProps & import("react").RefAttributes<VListHandle>>;
110
115
  export {};
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare const useRefWithUpdate: <T>(value: T) => import("react").MutableRefObject<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "virtua",
3
- "version": "0.1.12",
3
+ "version": "0.2.1",
4
4
  "description": "A zero-config, fast and small (3kB) virtual list component for React.",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/index.mjs",
@@ -17,6 +17,7 @@
17
17
  "storybook": "storybook dev -p 6006",
18
18
  "storybook:build": "storybook build",
19
19
  "storybook:test": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"npm run storybook -- --quiet --no-open\" \"wait-on tcp:6006 && test-storybook\"",
20
+ "e2e": "npx playwright test",
20
21
  "typedoc": "typedoc",
21
22
  "prepublishOnly": "npm run typedoc && rimraf lib && npm run build"
22
23
  },
@@ -27,29 +28,30 @@
27
28
  "@babel/plugin-transform-react-pure-annotations": "7.18.6",
28
29
  "@dnd-kit/core": "6.0.8",
29
30
  "@dnd-kit/sortable": "7.0.2",
30
- "@emotion/react": "11.10.6",
31
- "@emotion/styled": "11.10.6",
31
+ "@emotion/react": "11.10.8",
32
+ "@emotion/styled": "11.10.8",
32
33
  "@faker-js/faker": "7.6.0",
33
- "@mui/material": "5.11.15",
34
+ "@mui/material": "5.12.3",
35
+ "@playwright/test": "^1.33.0",
34
36
  "@rollup/plugin-babel": "6.0.3",
35
37
  "@rollup/plugin-terser": "0.4.1",
36
38
  "@rollup/plugin-typescript": "11.1.0",
37
- "@storybook/addon-docs": "7.0.5",
38
- "@storybook/react": "7.0.6",
39
- "@storybook/react-vite": "^7.0.6",
40
- "@storybook/test-runner": "0.10.0-next.13",
39
+ "@storybook/addon-docs": "7.0.8",
40
+ "@storybook/react": "7.0.8",
41
+ "@storybook/react-vite": "^7.0.8",
42
+ "@storybook/test-runner": "0.10.0",
41
43
  "@tanstack/react-virtual": "3.0.0-alpha.0",
42
44
  "@testing-library/react": "14.0.0",
43
- "@types/react": "18.0.32",
45
+ "@types/react": "18.2.5",
44
46
  "@types/react-virtualized": "9.21.21",
45
47
  "@types/react-window": "1.8.5",
46
48
  "@types/use-sync-external-store": "0.0.3",
47
- "@typescript-eslint/parser": "5.55.0",
48
- "concurrently": "7.2.2",
49
- "eslint": "8.36.0",
49
+ "@typescript-eslint/parser": "5.59.2",
50
+ "concurrently": "8.0.1",
51
+ "eslint": "8.39.0",
50
52
  "eslint-plugin-react-hooks": "4.6.0",
51
- "jest": "29.0.2",
52
- "jest-environment-jsdom": "29.0.2",
53
+ "jest": "29.5.0",
54
+ "jest-environment-jsdom": "29.5.0",
53
55
  "re-resizable": "6.9.9",
54
56
  "react": "18.2.0",
55
57
  "react-content-loader": "6.2.1",
@@ -57,19 +59,20 @@
57
59
  "react-dom": "18.2.0",
58
60
  "react-is": "18.2.0",
59
61
  "react-merge-refs": "2.0.1",
60
- "react-select": "5.7.2",
61
- "react-virtualized": "9.22.3",
62
- "react-virtuoso": "4.2.0",
63
- "react-window": "1.8.8",
64
- "rimraf": "3.0.2",
65
- "rollup": "3.20.2",
66
- "storybook": "^7.0.6",
67
- "ts-jest": "29.0.5",
68
- "typedoc": "0.23.28",
69
- "typedoc-plugin-markdown": "3.14.0",
62
+ "react-select": "5.7.3",
63
+ "react-virtualized": "9.22.5",
64
+ "react-virtuoso": "4.3.5",
65
+ "react-window": "1.8.9",
66
+ "rimraf": "5.0.0",
67
+ "rollup": "3.21.5",
68
+ "storybook": "^7.0.8",
69
+ "ts-jest": "29.1.0",
70
+ "typedoc": "0.24.6",
71
+ "typedoc-plugin-markdown": "3.15.3",
70
72
  "typescript": "5.0.4",
71
- "vite": "4.3.0",
72
- "wait-on": "6.0.1"
73
+ "virtua": "^0.2.0",
74
+ "vite": "4.3.4",
75
+ "wait-on": "7.0.1"
73
76
  },
74
77
  "peerDependencies": {
75
78
  "react": ">=16.14.0"
@@ -1 +0,0 @@
1
- export declare const useEvent: <T extends (...args: any[]) => void>(handler: T | undefined) => (...args: Parameters<T>) => void;