@ceriousdevtech/react-cerious-scroll 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,11 @@ All notable changes to react-cerious-scroll will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.0.6] - 2026-06-11
9
+
10
+ ### Fixed
11
+ - **`recalculate()` now refreshes row content, not just heights.** It re-runs `renderItem` for every currently-rendered row (busting the per-index portal cache), so rows whose content depends on state outside `(item, index)` — e.g. a sliding/windowed data source where index → content shifts — update on an in-place refresh. Previously `recalculate()` only cleared the engine's height caches and re-measured, leaving such rows showing stale content; this now matches the Vue/Angular wrappers, whose `recalculate()` re-runs the row template/slot. A plain scroll still reuses cached portals for unchanged rows, so heavy rows stay cheap to scroll.
12
+
8
13
  ## [1.0.5] - 2026-06-08
9
14
 
10
15
  ### Added
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ee=require("react/jsx-runtime"),r=require("react"),z=require("react-dom"),te=require("react-dom/server"),G=require("@ceriousdevtech/cerious-scroll"),$="data-cerious-scroll-content",re="data-cerious-scroll-row";function ne(e){const s=e.querySelector(`[${$}]`);if(s)return s;const n=document.createElement("div");return n.setAttribute($,""),n.style.position="relative",n.style.width="100%",n.style.height="100%",n.style.overflowY="clip",n.style.overflowX="auto",e.appendChild(n),n}function ce(e,s){const n=h=>{const l=h.detail;l&&s({percentage:l.percentage,currentElement:l.currentElement,scrollOffset:l.scrollOffset,result:{element:l.result.element,offset:l.result.offset}})},f=h=>{const l=h.detail;l&&s({percentage:l.percentage,currentElement:l.element,scrollOffset:l.scrollOffset,result:{element:l.element,offset:l.scrollOffset}})};return e.addEventListener("cerious-viewport-change",n),e.addEventListener("viewport-change",f),()=>{e.removeEventListener("cerious-viewport-change",n),e.removeEventListener("viewport-change",f)}}function le(e,s){const n=typeof e=="number"?e:typeof s=="number"?s:void 0;if(n===void 0||Number.isNaN(n))throw new Error("useCeriousScroll: provide `totalElements` or `items`.");return Math.max(1,Math.floor(n))}function J(e){var Y;const s=r.useRef(null),n=r.useRef(null),f=r.useRef(new Map),h=r.useRef(new Map),l=r.useRef(null),R=r.useRef(null),S=r.useRef(null),T=r.useRef(e.tableHeader),[,M]=r.useReducer(t=>t+1,0),[A,p]=r.useState(null),b=r.useRef(e.renderItem),g=r.useRef(e.items??null),v=r.useRef(e.getItem),L=r.useRef(e.options),q=r.useRef(e.autoRender??!0),D=r.useRef(e.totalElements??null),H=r.useRef(e.onViewportChange),P=r.useRef(e.onMeasuredViewport),j=r.useRef(e.onReady);b.current=e.renderItem,g.current=e.items??null,v.current=e.getItem,T.current=e.tableHeader,L.current=e.options,q.current=e.autoRender??!0,D.current=e.totalElements??null,H.current=e.onViewportChange,P.current=e.onMeasuredViewport,j.current=e.onReady;const B=r.useCallback(t=>{const c=v.current;if(c)return c(t);const o=g.current;return o?o[t]:void 0},[]),u=r.useCallback(()=>{var I,O;const t=n.current;if(!t)return null;const{scroller:c,contentEl:o,container:a}=t,k=a.clientHeight||a.offsetHeight||0,w=[],m=((I=L.current)==null?void 0:I.layout)==="table",_=(i,d)=>{const C=document.createElement("div");m&&(C.style.display="contents"),C.setAttribute(re,String(i)),C.innerHTML=te.renderToStaticMarkup(r.createElement(r.Fragment,null,b.current(B(i),i))),d.appendChild(C),f.current.set(i,{el:d,mount:C}),w.push(C)},y=c.renderViewport(k,o,_),F=new Set(c.getRenderedIndices());return f.current.forEach((i,d)=>{F.has(d)||f.current.delete(d)}),w.forEach(i=>{i.textContent=""}),z.flushSync(M),(O=P.current)==null||O.call(P,y),y},[]),K=e.totalElements??((Y=e.items)==null?void 0:Y.length)??null;r.useEffect(()=>{var F,I,O;const t=s.current;if(!t)return;const c=ne(t),o=L.current??{},a=o.onScroll,k={...o,onScroll:()=>{a==null||a(),q.current&&u()}};if(o.layout==="table"&&T.current!=null){const i=(F=o.table)==null?void 0:F.header;k.table={...o.table,header:d=>{S.current=d,i==null||i(d)}}}const w=le(D.current,((I=g.current)==null?void 0:I.length)??null),m=new G.CeriousScroll(t,w,k);R.current&&(m.currentElement=Math.min(R.current.currentElement,w-1),m.scrollOffset=R.current.scrollOffset,R.current=null),n.current={scroller:m,contentEl:c,container:t},p(m);const _=ce(t,i=>{var d;(d=H.current)==null||d.call(H,i)});(O=j.current)==null||O.call(j,m);let y=0;return q.current&&(y=requestAnimationFrame(()=>u())),()=>{cancelAnimationFrame(y),_(),R.current={currentElement:m.currentElement,scrollOffset:m.scrollOffset},f.current.clear(),h.current.clear(),l.current=null,c.textContent="",m.detachScrollbar(t),m.dispose(),n.current=null,p(null)}},[K,u]),r.useEffect(()=>{if(!n.current||!q.current)return;const t=requestAnimationFrame(()=>u());return()=>cancelAnimationFrame(t)},[e.items,e.getItem]);const Q=r.useCallback(t=>{const c=n.current;return c?(c.scroller.jumpToElement(t),u()):null},[u]),U=r.useCallback(t=>{const c=n.current;return c?(c.scroller.handleScrollPercentage(t),u()):null},[u]),Z=r.useCallback(()=>{const t=n.current;return t?(t.scroller.reset(),u()):null},[u]),x=r.useCallback(()=>{const t=n.current;return t?(t.scroller.clearAllCaches(),u()):null},[u]),W=g.current,X=!v.current&&W!=null?W.length:null,N=b.current,E=h.current;l.current!==N&&(E.clear(),l.current=N);const V=[];return f.current.forEach((t,c)=>{if(X!==null&&c>=X){E.delete(c);return}const o=B(c);let a=E.get(c);(!a||a.item!==o||a.mount!==t.mount)&&(a={item:o,mount:t.mount,node:z.createPortal(N(o,c),t.mount,String(c))},E.set(c,a)),V.push(a.node)}),E.size>f.current.size&&E.forEach((t,c)=>{f.current.has(c)||E.delete(c)}),e.tableHeader!=null&&S.current&&V.push(z.createPortal(e.tableHeader,S.current,"cerious-thead")),{containerRef:s,portals:V,scroller:A,render:u,jumpToElement:Q,scrollToPercentage:U,reset:Z,recalculate:x}}function oe(e,s){const{className:n,style:f,"data-testid":h,children:l,...R}=e,{containerRef:S,portals:T,scroller:M,render:A,jumpToElement:p,scrollToPercentage:b,reset:g,recalculate:v}=J(R);return r.useImperativeHandle(s,()=>({scroller:M,render:A,jumpToElement:p,scrollToPercentage:b,reset:g,recalculate:v}),[M,A,p,b,g,v]),ee.jsxs("div",{ref:S,className:n,"data-testid":h,style:{position:"relative",overflow:"hidden",...f},children:[l,T]})}const se=r.forwardRef(oe);Object.defineProperty(exports,"CeriousScrollEngine",{enumerable:!0,get:()=>G.CeriousScroll});exports.CeriousScroll=se;exports.useCeriousScroll=J;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const ee=require("react/jsx-runtime"),r=require("react"),z=require("react-dom"),te=require("react-dom/server"),G=require("@ceriousdevtech/cerious-scroll"),$="data-cerious-scroll-content",re="data-cerious-scroll-row";function ne(e){const u=e.querySelector(`[${$}]`);if(u)return u;const n=document.createElement("div");return n.setAttribute($,""),n.style.position="relative",n.style.width="100%",n.style.height="100%",n.style.overflowY="clip",n.style.overflowX="auto",e.appendChild(n),n}function ce(e,u){const n=h=>{const l=h.detail;l&&u({percentage:l.percentage,currentElement:l.currentElement,scrollOffset:l.scrollOffset,result:{element:l.result.element,offset:l.result.offset}})},f=h=>{const l=h.detail;l&&u({percentage:l.percentage,currentElement:l.element,scrollOffset:l.scrollOffset,result:{element:l.element,offset:l.scrollOffset}})};return e.addEventListener("cerious-viewport-change",n),e.addEventListener("viewport-change",f),()=>{e.removeEventListener("cerious-viewport-change",n),e.removeEventListener("viewport-change",f)}}function le(e,u){const n=typeof e=="number"?e:typeof u=="number"?u:void 0;if(n===void 0||Number.isNaN(n))throw new Error("useCeriousScroll: provide `totalElements` or `items`.");return Math.max(1,Math.floor(n))}function J(e){var Y;const u=r.useRef(null),n=r.useRef(null),f=r.useRef(new Map),h=r.useRef(new Map),l=r.useRef(null),R=r.useRef(null),S=r.useRef(null),T=r.useRef(e.tableHeader),[,M]=r.useReducer(t=>t+1,0),[A,p]=r.useState(null),b=r.useRef(e.renderItem),g=r.useRef(e.items??null),v=r.useRef(e.getItem),L=r.useRef(e.options),q=r.useRef(e.autoRender??!0),D=r.useRef(e.totalElements??null),H=r.useRef(e.onViewportChange),P=r.useRef(e.onMeasuredViewport),j=r.useRef(e.onReady);b.current=e.renderItem,g.current=e.items??null,v.current=e.getItem,T.current=e.tableHeader,L.current=e.options,q.current=e.autoRender??!0,D.current=e.totalElements??null,H.current=e.onViewportChange,P.current=e.onMeasuredViewport,j.current=e.onReady;const B=r.useCallback(t=>{const c=v.current;if(c)return c(t);const o=g.current;return o?o[t]:void 0},[]),s=r.useCallback(()=>{var I,O;const t=n.current;if(!t)return null;const{scroller:c,contentEl:o,container:a}=t,k=a.clientHeight||a.offsetHeight||0,w=[],m=((I=L.current)==null?void 0:I.layout)==="table",_=(i,d)=>{const C=document.createElement("div");m&&(C.style.display="contents"),C.setAttribute(re,String(i)),C.innerHTML=te.renderToStaticMarkup(r.createElement(r.Fragment,null,b.current(B(i),i))),d.appendChild(C),f.current.set(i,{el:d,mount:C}),w.push(C)},y=c.renderViewport(k,o,_),F=new Set(c.getRenderedIndices());return f.current.forEach((i,d)=>{F.has(d)||f.current.delete(d)}),w.forEach(i=>{i.textContent=""}),z.flushSync(M),(O=P.current)==null||O.call(P,y),y},[]),K=e.totalElements??((Y=e.items)==null?void 0:Y.length)??null;r.useEffect(()=>{var F,I,O;const t=u.current;if(!t)return;const c=ne(t),o=L.current??{},a=o.onScroll,k={...o,onScroll:()=>{a==null||a(),q.current&&s()}};if(o.layout==="table"&&T.current!=null){const i=(F=o.table)==null?void 0:F.header;k.table={...o.table,header:d=>{S.current=d,i==null||i(d)}}}const w=le(D.current,((I=g.current)==null?void 0:I.length)??null),m=new G.CeriousScroll(t,w,k);R.current&&(m.currentElement=Math.min(R.current.currentElement,w-1),m.scrollOffset=R.current.scrollOffset,R.current=null),n.current={scroller:m,contentEl:c,container:t},p(m);const _=ce(t,i=>{var d;(d=H.current)==null||d.call(H,i)});(O=j.current)==null||O.call(j,m);let y=0;return q.current&&(y=requestAnimationFrame(()=>s())),()=>{cancelAnimationFrame(y),_(),R.current={currentElement:m.currentElement,scrollOffset:m.scrollOffset},f.current.clear(),h.current.clear(),l.current=null,c.textContent="",m.detachScrollbar(t),m.dispose(),n.current=null,p(null)}},[K,s]),r.useEffect(()=>{if(!n.current||!q.current)return;const t=requestAnimationFrame(()=>s());return()=>cancelAnimationFrame(t)},[e.items,e.getItem]);const Q=r.useCallback(t=>{const c=n.current;return c?(c.scroller.jumpToElement(t),s()):null},[s]),U=r.useCallback(t=>{const c=n.current;return c?(c.scroller.handleScrollPercentage(t),s()):null},[s]),Z=r.useCallback(()=>{const t=n.current;return t?(t.scroller.reset(),s()):null},[s]),x=r.useCallback(()=>{const t=n.current;return t?(t.scroller.clearAllCaches(),h.current.clear(),s()):null},[s]),W=g.current,X=!v.current&&W!=null?W.length:null,N=b.current,E=h.current;l.current!==N&&(E.clear(),l.current=N);const V=[];return f.current.forEach((t,c)=>{if(X!==null&&c>=X){E.delete(c);return}const o=B(c);let a=E.get(c);(!a||a.item!==o||a.mount!==t.mount)&&(a={item:o,mount:t.mount,node:z.createPortal(N(o,c),t.mount,String(c))},E.set(c,a)),V.push(a.node)}),E.size>f.current.size&&E.forEach((t,c)=>{f.current.has(c)||E.delete(c)}),e.tableHeader!=null&&S.current&&V.push(z.createPortal(e.tableHeader,S.current,"cerious-thead")),{containerRef:u,portals:V,scroller:A,render:s,jumpToElement:Q,scrollToPercentage:U,reset:Z,recalculate:x}}function oe(e,u){const{className:n,style:f,"data-testid":h,children:l,...R}=e,{containerRef:S,portals:T,scroller:M,render:A,jumpToElement:p,scrollToPercentage:b,reset:g,recalculate:v}=J(R);return r.useImperativeHandle(u,()=>({scroller:M,render:A,jumpToElement:p,scrollToPercentage:b,reset:g,recalculate:v}),[M,A,p,b,g,v]),ee.jsxs("div",{ref:S,className:n,"data-testid":h,style:{position:"relative",overflow:"hidden",...f},children:[l,T]})}const ue=r.forwardRef(oe);Object.defineProperty(exports,"CeriousScrollEngine",{enumerable:!0,get:()=>G.CeriousScroll});exports.CeriousScroll=ue;exports.useCeriousScroll=J;
package/dist/index.js CHANGED
@@ -119,7 +119,7 @@ function he(e) {
119
119
  return t ? (t.scroller.reset(), u()) : null;
120
120
  }, [u]), x = w(() => {
121
121
  const t = r.current;
122
- return t ? (t.scroller.clearAllCaches(), u()) : null;
122
+ return t ? (t.scroller.clearAllCaches(), h.current.clear(), u()) : null;
123
123
  }, [u]), D = E.current, W = !R.current && D != null ? D.length : null, q = v.current, p = h.current;
124
124
  c.current !== q && (p.clear(), c.current = q);
125
125
  const k = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ceriousdevtech/react-cerious-scroll",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "React bindings for CeriousScroll — high-performance virtual scrolling with O(1) memory and no height estimation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -56,7 +56,7 @@
56
56
  "demo:build": "vite build --config demo/vite.config.ts"
57
57
  },
58
58
  "dependencies": {
59
- "@ceriousdevtech/cerious-scroll": "^1.0.6"
59
+ "@ceriousdevtech/cerious-scroll": "^1.0.7"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "react": ">=18 <20",