@ceriousdevtech/react-cerious-scroll 1.0.3 → 1.0.4
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 +5 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +123 -111
- package/package.json +2 -2
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.4] - 2026-06-04
|
|
9
|
+
|
|
10
|
+
### Dependencies
|
|
11
|
+
- Bumped `@ceriousdevtech/cerious-scroll` to `^1.0.5`. Consumers get the new wheel input classifier (trackpad / free-scroll mice apply input immediately, ratcheted wheel notches still ease smoothly), the new `wheel.wheelBehavior` option (`'auto' | 'immediate' | 'smooth'`), and a fix for horizontal wheel forwarding in layouts where `overflow-x: auto` lives on an ancestor of `[data-cerious-scroll-content]`.
|
|
12
|
+
|
|
8
13
|
## [1.0.3] - 2026-06-03
|
|
9
14
|
|
|
10
15
|
### Dependencies
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const Q=require("react/jsx-runtime"),r=require("react"),D=require("react-dom"),U=require("react-dom/server"),W=require("@ceriousdevtech/cerious-scroll"),B="data-cerious-scroll-content",Z="data-cerious-scroll-row";function x(e){const l=e.querySelector(`[${B}]`);if(l)return l;const n=document.createElement("div");return n.setAttribute(B,""),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 ee(e,l){const n=d=>{const o=d.detail;o&&l({percentage:o.percentage,currentElement:o.currentElement,scrollOffset:o.scrollOffset,result:{element:o.result.element,offset:o.result.offset}})},i=d=>{const o=d.detail;o&&l({percentage:o.percentage,currentElement:o.element,scrollOffset:o.scrollOffset,result:{element:o.element,offset:o.scrollOffset}})};return e.addEventListener("cerious-viewport-change",n),e.addEventListener("viewport-change",i),()=>{e.removeEventListener("cerious-viewport-change",n),e.removeEventListener("viewport-change",i)}}function te(e,l){const n=typeof e=="number"?e:typeof l=="number"?l: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 X(e){var z;const l=r.useRef(null),n=r.useRef(null),i=r.useRef(new Map),d=r.useRef(new Map),o=r.useRef(null),g=r.useRef(null),[,j]=r.useReducer(t=>t+1,0),[k,b]=r.useState(null),p=r.useRef(e.renderItem),R=r.useRef(e.items??null),S=r.useRef(e.getItem),w=r.useRef(e.options),E=r.useRef(e.autoRender??!0),L=r.useRef(e.totalElements??null),O=r.useRef(e.onViewportChange),T=r.useRef(e.onMeasuredViewport),M=r.useRef(e.onReady);p.current=e.renderItem,R.current=e.items??null,S.current=e.getItem,w.current=e.options,E.current=e.autoRender??!0,L.current=e.totalElements??null,O.current=e.onViewportChange,T.current=e.onMeasuredViewport,M.current=e.onReady;const N=r.useCallback(t=>{const c=S.current;if(c)return c(t);const a=R.current;return a?a[t]:void 0},[]),s=r.useCallback(()=>{var I;const t=n.current;if(!t)return null;const{scroller:c,contentEl:a,container:u}=t,F=u.clientHeight||u.offsetHeight||0,y=[],f=(m,C)=>{const h=document.createElement("div");h.setAttribute(Z,String(m)),h.innerHTML=U.renderToStaticMarkup(r.createElement(r.Fragment,null,p.current(N(m),m))),C.appendChild(h),i.current.set(m,{el:C,mount:h}),y.push(h)},A=c.renderViewport(F,a,f),q=new Set(c.getRenderedIndices());return i.current.forEach((m,C)=>{q.has(C)||i.current.delete(C)}),y.forEach(m=>{m.textContent=""}),D.flushSync(j),(I=T.current)==null||I.call(T,A),A},[]),Y=e.totalElements??((z=e.items)==null?void 0:z.length)??null;r.useEffect(()=>{var I,m;const t=l.current;if(!t)return;const c=x(t),a=w.current??{},u=a.onScroll,F={...a,onScroll:()=>{u==null||u(),E.current&&s()}},y=te(L.current,((I=R.current)==null?void 0:I.length)??null),f=new W.CeriousScroll(t,y,F);g.current&&(f.currentElement=Math.min(g.current.currentElement,y-1),f.scrollOffset=g.current.scrollOffset,g.current=null),n.current={scroller:f,contentEl:c,container:t},b(f);const A=ee(t,C=>{var h;(h=O.current)==null||h.call(O,C)});(m=M.current)==null||m.call(M,f);let q=0;return E.current&&(q=requestAnimationFrame(()=>s())),()=>{cancelAnimationFrame(q),A(),g.current={currentElement:f.currentElement,scrollOffset:f.scrollOffset},i.current.clear(),d.current.clear(),o.current=null,c.textContent="",f.detachScrollbar(t),f.dispose(),n.current=null,b(null)}},[Y,s]),r.useEffect(()=>{if(!n.current||!E.current)return;const t=requestAnimationFrame(()=>s());return()=>cancelAnimationFrame(t)},[e.items,e.getItem]);const $=r.useCallback(t=>{const c=n.current;return c?(c.scroller.jumpToElement(t),s()):null},[s]),G=r.useCallback(t=>{const c=n.current;return c?(c.scroller.handleScrollPercentage(t),s()):null},[s]),J=r.useCallback(()=>{const t=n.current;return t?(t.scroller.reset(),s()):null},[s]),K=r.useCallback(()=>{const t=n.current;return t?(t.scroller.clearAllCaches(),s()):null},[s]),H=R.current,V=!S.current&&H!=null?H.length:null,P=p.current,v=d.current;o.current!==P&&(v.clear(),o.current=P);const _=[];return i.current.forEach((t,c)=>{if(V!==null&&c>=V){v.delete(c);return}const a=N(c);let u=v.get(c);(!u||u.item!==a||u.mount!==t.mount)&&(u={item:a,mount:t.mount,node:D.createPortal(P(a,c),t.mount,String(c))},v.set(c,u)),_.push(u.node)}),v.size>i.current.size&&v.forEach((t,c)=>{i.current.has(c)||v.delete(c)}),{containerRef:l,portals:_,scroller:k,render:s,jumpToElement:$,scrollToPercentage:G,reset:J,recalculate:K}}function re(e,l){const{className:n,style:i,"data-testid":d,children:o,...g}=e,{containerRef:j,portals:k,scroller:b,render:p,jumpToElement:R,scrollToPercentage:S,reset:w,recalculate:E}=X(g);return r.useImperativeHandle(l,()=>({scroller:b,render:p,jumpToElement:R,scrollToPercentage:S,reset:w,recalculate:E}),[b,p,R,S,w,E]),Q.jsxs("div",{ref:j,className:n,"data-testid":d,style:{position:"relative",overflow:"hidden",...i},children:[o,k]})}const ne=r.forwardRef(re);Object.defineProperty(exports,"CeriousScrollEngine",{enumerable:!0,get:()=>W.CeriousScroll});exports.CeriousScroll=ne;exports.useCeriousScroll=X;
|
package/dist/index.js
CHANGED
|
@@ -1,163 +1,175 @@
|
|
|
1
|
-
import { jsxs as
|
|
2
|
-
import { useRef as
|
|
3
|
-
import { flushSync as
|
|
4
|
-
import { renderToStaticMarkup as
|
|
5
|
-
import { CeriousScroll as
|
|
6
|
-
import { CeriousScroll as
|
|
7
|
-
const
|
|
8
|
-
function
|
|
9
|
-
const
|
|
10
|
-
if (
|
|
1
|
+
import { jsxs as K } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as c, useReducer as Q, useState as U, useCallback as S, useEffect as B, createElement as Z, Fragment as x, forwardRef as ee, useImperativeHandle as te } from "react";
|
|
3
|
+
import { flushSync as re, createPortal as ne } from "react-dom";
|
|
4
|
+
import { renderToStaticMarkup as oe } from "react-dom/server";
|
|
5
|
+
import { CeriousScroll as ce } from "@ceriousdevtech/cerious-scroll";
|
|
6
|
+
import { CeriousScroll as we } from "@ceriousdevtech/cerious-scroll";
|
|
7
|
+
const D = "data-cerious-scroll-content", le = "data-cerious-scroll-row";
|
|
8
|
+
function se(e) {
|
|
9
|
+
const l = e.querySelector(`[${D}]`);
|
|
10
|
+
if (l) return l;
|
|
11
11
|
const r = document.createElement("div");
|
|
12
|
-
return r.setAttribute(
|
|
12
|
+
return r.setAttribute(D, ""), r.style.position = "relative", r.style.width = "100%", r.style.height = "100%", r.style.overflowY = "clip", r.style.overflowX = "auto", e.appendChild(r), r;
|
|
13
13
|
}
|
|
14
|
-
function
|
|
15
|
-
const r = (
|
|
16
|
-
const o =
|
|
17
|
-
o &&
|
|
14
|
+
function ue(e, l) {
|
|
15
|
+
const r = (d) => {
|
|
16
|
+
const o = d.detail;
|
|
17
|
+
o && l({
|
|
18
18
|
percentage: o.percentage,
|
|
19
19
|
currentElement: o.currentElement,
|
|
20
20
|
scrollOffset: o.scrollOffset,
|
|
21
21
|
result: { element: o.result.element, offset: o.result.offset }
|
|
22
22
|
});
|
|
23
|
-
},
|
|
24
|
-
const o =
|
|
25
|
-
o &&
|
|
23
|
+
}, i = (d) => {
|
|
24
|
+
const o = d.detail;
|
|
25
|
+
o && l({
|
|
26
26
|
percentage: o.percentage,
|
|
27
27
|
currentElement: o.element,
|
|
28
28
|
scrollOffset: o.scrollOffset,
|
|
29
29
|
result: { element: o.element, offset: o.scrollOffset }
|
|
30
30
|
});
|
|
31
31
|
};
|
|
32
|
-
return e.addEventListener("cerious-viewport-change", r), e.addEventListener("viewport-change",
|
|
33
|
-
e.removeEventListener("cerious-viewport-change", r), e.removeEventListener("viewport-change",
|
|
32
|
+
return e.addEventListener("cerious-viewport-change", r), e.addEventListener("viewport-change", i), () => {
|
|
33
|
+
e.removeEventListener("cerious-viewport-change", r), e.removeEventListener("viewport-change", i);
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
function
|
|
37
|
-
const r = typeof e == "number" ? e : typeof
|
|
36
|
+
function ie(e, l) {
|
|
37
|
+
const r = typeof e == "number" ? e : typeof l == "number" ? l : void 0;
|
|
38
38
|
if (r === void 0 || Number.isNaN(r))
|
|
39
39
|
throw new Error("useCeriousScroll: provide `totalElements` or `items`.");
|
|
40
40
|
return Math.max(1, Math.floor(r));
|
|
41
41
|
}
|
|
42
|
-
function
|
|
43
|
-
var
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
const n =
|
|
42
|
+
function ae(e) {
|
|
43
|
+
var $;
|
|
44
|
+
const l = c(null), r = c(null), i = c(/* @__PURE__ */ new Map()), d = c(/* @__PURE__ */ new Map()), o = c(null), g = c(null), [, N] = Q((t) => t + 1, 0), [P, I] = U(null), w = c(e.renderItem), E = c(e.items ?? null), C = c(e.getItem), T = c(e.options), p = c(e.autoRender ?? !0), V = c(e.totalElements ?? null), y = c(e.onViewportChange), A = c(e.onMeasuredViewport), M = c(e.onReady);
|
|
45
|
+
w.current = e.renderItem, E.current = e.items ?? null, C.current = e.getItem, T.current = e.options, p.current = e.autoRender ?? !0, V.current = e.totalElements ?? null, y.current = e.onViewportChange, A.current = e.onMeasuredViewport, M.current = e.onReady;
|
|
46
|
+
const _ = S((t) => {
|
|
47
|
+
const n = C.current;
|
|
48
48
|
if (n) return n(t);
|
|
49
|
-
const
|
|
50
|
-
return
|
|
51
|
-
}, []),
|
|
52
|
-
var
|
|
49
|
+
const a = E.current;
|
|
50
|
+
return a ? a[t] : void 0;
|
|
51
|
+
}, []), s = S(() => {
|
|
52
|
+
var b;
|
|
53
53
|
const t = r.current;
|
|
54
54
|
if (!t) return null;
|
|
55
|
-
const { scroller: n, contentEl:
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
),
|
|
60
|
-
},
|
|
61
|
-
return
|
|
62
|
-
|
|
63
|
-
}),
|
|
64
|
-
|
|
65
|
-
}),
|
|
66
|
-
}, []),
|
|
67
|
-
|
|
68
|
-
var
|
|
69
|
-
const t =
|
|
55
|
+
const { scroller: n, contentEl: a, container: u } = t, H = u.clientHeight || u.offsetHeight || 0, O = [], f = (m, R) => {
|
|
56
|
+
const h = document.createElement("div");
|
|
57
|
+
h.setAttribute(le, String(m)), h.innerHTML = oe(
|
|
58
|
+
Z(x, null, w.current(_(m), m))
|
|
59
|
+
), R.appendChild(h), i.current.set(m, { el: R, mount: h }), O.push(h);
|
|
60
|
+
}, F = n.renderViewport(H, a, f), L = new Set(n.getRenderedIndices());
|
|
61
|
+
return i.current.forEach((m, R) => {
|
|
62
|
+
L.has(R) || i.current.delete(R);
|
|
63
|
+
}), O.forEach((m) => {
|
|
64
|
+
m.textContent = "";
|
|
65
|
+
}), re(N), (b = A.current) == null || b.call(A, F), F;
|
|
66
|
+
}, []), W = e.totalElements ?? (($ = e.items) == null ? void 0 : $.length) ?? null;
|
|
67
|
+
B(() => {
|
|
68
|
+
var b, m;
|
|
69
|
+
const t = l.current;
|
|
70
70
|
if (!t) return;
|
|
71
|
-
const n =
|
|
72
|
-
...
|
|
71
|
+
const n = se(t), a = T.current ?? {}, u = a.onScroll, H = {
|
|
72
|
+
...a,
|
|
73
73
|
onScroll: () => {
|
|
74
|
-
|
|
74
|
+
u == null || u(), p.current && s();
|
|
75
75
|
}
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
var
|
|
80
|
-
(
|
|
76
|
+
}, O = ie(V.current, ((b = E.current) == null ? void 0 : b.length) ?? null), f = new ce(t, O, H);
|
|
77
|
+
g.current && (f.currentElement = Math.min(g.current.currentElement, O - 1), f.scrollOffset = g.current.scrollOffset, g.current = null), r.current = { scroller: f, contentEl: n, container: t }, I(f);
|
|
78
|
+
const F = ue(t, (R) => {
|
|
79
|
+
var h;
|
|
80
|
+
(h = y.current) == null || h.call(y, R);
|
|
81
81
|
});
|
|
82
|
-
(
|
|
83
|
-
let
|
|
84
|
-
return
|
|
85
|
-
cancelAnimationFrame(
|
|
86
|
-
currentElement:
|
|
87
|
-
scrollOffset:
|
|
88
|
-
},
|
|
82
|
+
(m = M.current) == null || m.call(M, f);
|
|
83
|
+
let L = 0;
|
|
84
|
+
return p.current && (L = requestAnimationFrame(() => s())), () => {
|
|
85
|
+
cancelAnimationFrame(L), F(), g.current = {
|
|
86
|
+
currentElement: f.currentElement,
|
|
87
|
+
scrollOffset: f.scrollOffset
|
|
88
|
+
}, i.current.clear(), d.current.clear(), o.current = null, n.textContent = "", f.detachScrollbar(t), f.dispose(), r.current = null, I(null);
|
|
89
89
|
};
|
|
90
|
-
}, [
|
|
91
|
-
if (!r.current || !
|
|
92
|
-
const t = requestAnimationFrame(() =>
|
|
90
|
+
}, [W, s]), B(() => {
|
|
91
|
+
if (!r.current || !p.current) return;
|
|
92
|
+
const t = requestAnimationFrame(() => s());
|
|
93
93
|
return () => cancelAnimationFrame(t);
|
|
94
94
|
}, [e.items, e.getItem]);
|
|
95
|
-
const
|
|
95
|
+
const X = S(
|
|
96
96
|
(t) => {
|
|
97
97
|
const n = r.current;
|
|
98
|
-
return n ? (n.scroller.jumpToElement(t),
|
|
98
|
+
return n ? (n.scroller.jumpToElement(t), s()) : null;
|
|
99
99
|
},
|
|
100
|
-
[
|
|
101
|
-
),
|
|
100
|
+
[s]
|
|
101
|
+
), Y = S(
|
|
102
102
|
(t) => {
|
|
103
103
|
const n = r.current;
|
|
104
|
-
return n ? (n.scroller.handleScrollPercentage(t),
|
|
104
|
+
return n ? (n.scroller.handleScrollPercentage(t), s()) : null;
|
|
105
105
|
},
|
|
106
|
-
[
|
|
107
|
-
),
|
|
106
|
+
[s]
|
|
107
|
+
), G = S(() => {
|
|
108
108
|
const t = r.current;
|
|
109
|
-
return t ? (t.scroller.reset(),
|
|
110
|
-
}, [
|
|
109
|
+
return t ? (t.scroller.reset(), s()) : null;
|
|
110
|
+
}, [s]), J = S(() => {
|
|
111
111
|
const t = r.current;
|
|
112
|
-
return t ? (t.scroller.clearAllCaches(),
|
|
113
|
-
}, [
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
)
|
|
112
|
+
return t ? (t.scroller.clearAllCaches(), s()) : null;
|
|
113
|
+
}, [s]), q = E.current, k = !C.current && q != null ? q.length : null, j = w.current, v = d.current;
|
|
114
|
+
o.current !== j && (v.clear(), o.current = j);
|
|
115
|
+
const z = [];
|
|
116
|
+
return i.current.forEach((t, n) => {
|
|
117
|
+
if (k !== null && n >= k) {
|
|
118
|
+
v.delete(n);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const a = _(n);
|
|
122
|
+
let u = v.get(n);
|
|
123
|
+
(!u || u.item !== a || u.mount !== t.mount) && (u = {
|
|
124
|
+
item: a,
|
|
125
|
+
mount: t.mount,
|
|
126
|
+
node: ne(j(a, n), t.mount, String(n))
|
|
127
|
+
}, v.set(n, u)), z.push(u.node);
|
|
128
|
+
}), v.size > i.current.size && v.forEach((t, n) => {
|
|
129
|
+
i.current.has(n) || v.delete(n);
|
|
118
130
|
}), {
|
|
119
|
-
containerRef:
|
|
120
|
-
portals:
|
|
121
|
-
scroller:
|
|
122
|
-
render:
|
|
123
|
-
jumpToElement:
|
|
124
|
-
scrollToPercentage:
|
|
125
|
-
reset:
|
|
126
|
-
recalculate:
|
|
131
|
+
containerRef: l,
|
|
132
|
+
portals: z,
|
|
133
|
+
scroller: P,
|
|
134
|
+
render: s,
|
|
135
|
+
jumpToElement: X,
|
|
136
|
+
scrollToPercentage: Y,
|
|
137
|
+
reset: G,
|
|
138
|
+
recalculate: J
|
|
127
139
|
};
|
|
128
140
|
}
|
|
129
|
-
function
|
|
130
|
-
const { className: r, style:
|
|
131
|
-
containerRef:
|
|
132
|
-
portals:
|
|
133
|
-
scroller:
|
|
134
|
-
render:
|
|
135
|
-
jumpToElement:
|
|
136
|
-
scrollToPercentage:
|
|
141
|
+
function fe(e, l) {
|
|
142
|
+
const { className: r, style: i, "data-testid": d, children: o, ...g } = e, {
|
|
143
|
+
containerRef: N,
|
|
144
|
+
portals: P,
|
|
145
|
+
scroller: I,
|
|
146
|
+
render: w,
|
|
147
|
+
jumpToElement: E,
|
|
148
|
+
scrollToPercentage: C,
|
|
137
149
|
reset: T,
|
|
138
|
-
recalculate:
|
|
139
|
-
} =
|
|
140
|
-
return
|
|
141
|
-
|
|
142
|
-
() => ({ scroller:
|
|
143
|
-
[
|
|
144
|
-
), /* @__PURE__ */
|
|
150
|
+
recalculate: p
|
|
151
|
+
} = ae(g);
|
|
152
|
+
return te(
|
|
153
|
+
l,
|
|
154
|
+
() => ({ scroller: I, render: w, jumpToElement: E, scrollToPercentage: C, reset: T, recalculate: p }),
|
|
155
|
+
[I, w, E, C, T, p]
|
|
156
|
+
), /* @__PURE__ */ K(
|
|
145
157
|
"div",
|
|
146
158
|
{
|
|
147
|
-
ref:
|
|
159
|
+
ref: N,
|
|
148
160
|
className: r,
|
|
149
|
-
"data-testid":
|
|
150
|
-
style: { position: "relative", overflow: "hidden", ...
|
|
161
|
+
"data-testid": d,
|
|
162
|
+
style: { position: "relative", overflow: "hidden", ...i },
|
|
151
163
|
children: [
|
|
152
164
|
o,
|
|
153
|
-
|
|
165
|
+
P
|
|
154
166
|
]
|
|
155
167
|
}
|
|
156
168
|
);
|
|
157
169
|
}
|
|
158
|
-
const
|
|
170
|
+
const pe = ee(fe);
|
|
159
171
|
export {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
172
|
+
pe as CeriousScroll,
|
|
173
|
+
we as CeriousScrollEngine,
|
|
174
|
+
ae as useCeriousScroll
|
|
163
175
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ceriousdevtech/react-cerious-scroll",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
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.
|
|
59
|
+
"@ceriousdevtech/cerious-scroll": "^1.0.5"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"react": ">=18 <20",
|