@ceriousdevtech/vue-cerious-scroll 1.0.4 → 1.0.5
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 +9 -0
- package/README.md +33 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +125 -95
- package/dist/use-cerious-scroll.d.ts +5 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,15 @@ All notable changes to vue-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.5] - 2026-06-08
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Table mode support** (`:options="{ layout: 'table' }"`). Rows render as real `<td>` cells into the engine's `<tr>`. Each row renders into its own `display: contents` wrapper, isolating Vue's renderer from the engine's `<tr>` recycling (so a fast scroll can't tear nodes out from under Vue) while the cells still lay out as the row's columns.
|
|
12
|
+
- **`#header` slot**. Declarative header (a `<tr>` of `<th>`s) rendered into the engine's `<thead>` in its own reactive effect — same `<table>` as the rows, so columns align natively, and interactive headers (sort state, etc.) update on their own.
|
|
13
|
+
|
|
14
|
+
### Dependencies
|
|
15
|
+
- Bumped `@ceriousdevtech/cerious-scroll` to `^1.0.6`: native table layout, `table.autoSizeColumns` (auto-sized but stable columns), trackpad-only wheel inertia, overlay-scrollbar gutter fix, and exact bottom snap.
|
|
16
|
+
|
|
8
17
|
## [1.0.4] - 2026-06-04
|
|
9
18
|
|
|
10
19
|
### Dependencies
|
package/README.md
CHANGED
|
@@ -113,8 +113,9 @@ const { containerRef } = useCeriousScroll({
|
|
|
113
113
|
| `autoRender` | `boolean` | Re-render on scroll/resize/data changes. Default `true`. |
|
|
114
114
|
|
|
115
115
|
The row is provided by the **`#item` scoped slot** (`{ item, index }`) or the
|
|
116
|
-
`render-item` prop.
|
|
117
|
-
|
|
116
|
+
`render-item` prop. In table mode, a **`#header` slot** renders the `<thead>` row
|
|
117
|
+
(see [Table layout](#table-layout)). Apply `class` / `style` directly to the
|
|
118
|
+
component — they fall through onto the scroll container (set a height!).
|
|
118
119
|
|
|
119
120
|
### Events
|
|
120
121
|
|
|
@@ -138,6 +139,36 @@ const scroll = ref<InstanceType<typeof CeriousScroll> | null>(null);
|
|
|
138
139
|
|
|
139
140
|
---
|
|
140
141
|
|
|
142
|
+
## Table layout
|
|
143
|
+
|
|
144
|
+
Pass `:options="{ layout: 'table' }"` to render real `<table>` / `<tr>` / `<td>` rows with a frozen header and native column alignment. The `#item` slot returns the row's `<td>` cells; a `#header` slot provides the (declarative, reactive) `<thead>` row:
|
|
145
|
+
|
|
146
|
+
```vue
|
|
147
|
+
<CeriousScroll
|
|
148
|
+
class="my-scroll"
|
|
149
|
+
:total-elements="100000"
|
|
150
|
+
:get-item="(i) => i"
|
|
151
|
+
:options="{ layout: 'table', table: { tableClassName: 'my-table', autoSizeColumns: true } }"
|
|
152
|
+
>
|
|
153
|
+
<template #header>
|
|
154
|
+
<tr><th v-for="c in columns" :key="c.key">{{ c.label }}</th></tr>
|
|
155
|
+
</template>
|
|
156
|
+
|
|
157
|
+
<template #item="{ item: index }">
|
|
158
|
+
<td>{{ row(index).id }}</td>
|
|
159
|
+
<td>{{ row(index).name }}</td>
|
|
160
|
+
<td>{{ row(index).email }}</td>
|
|
161
|
+
</template>
|
|
162
|
+
</CeriousScroll>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
- The **`#header` slot** renders into the engine's `<thead>` (same `<table>` as the rows → native column alignment, frozen header) and stays reactive.
|
|
166
|
+
- The **`#item` slot must return `<td>`s**. They render into the row's `<tr>` via a `display: contents` wrapper that isolates Vue's renderer from the engine's row recycling.
|
|
167
|
+
- **`table.autoSizeColumns`** measures column widths once and pins them (auto-sized + stable); or use `table.columnWidths`. Variable row heights work as usual.
|
|
168
|
+
- CSS: `border-collapse: separate` and an **opaque `<thead>` background** (see the core README's [Table Layout](https://github.com/ceriousdevtech/cerious-scroll#-table-layout-layout-table) notes).
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
141
172
|
## Notes
|
|
142
173
|
|
|
143
174
|
- **No height estimation.** Rows are committed with Vue's synchronous `render()`
|
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 r=require("vue"),N=require("@ceriousdevtech/cerious-scroll"),M="data-cerious-scroll-content",q="data-cerious-scroll-row";function L(e){const u=e.querySelector(`[${M}]`);if(u)return u;const o=document.createElement("div");return o.setAttribute(M,""),o.style.position="relative",o.style.width="100%",o.style.height="100%",o.style.overflowY="clip",o.style.overflowX="auto",e.appendChild(o),o}function B(e,u){const o=l=>{const n=l.detail;n&&u({percentage:n.percentage,currentElement:n.currentElement,scrollOffset:n.scrollOffset,result:{element:n.result.element,offset:n.result.offset}})},g=l=>{const n=l.detail;n&&u({percentage:n.percentage,currentElement:n.element,scrollOffset:n.scrollOffset,result:{element:n.element,offset:n.scrollOffset}})};return e.addEventListener("cerious-viewport-change",o),e.addEventListener("viewport-change",g),()=>{e.removeEventListener("cerious-viewport-change",o),e.removeEventListener("viewport-change",g)}}function j(e,u){const o=typeof e=="number"?e:typeof u=="number"?u:void 0;if(o===void 0||Number.isNaN(o))throw new Error("useCeriousScroll: provide `totalElements` or `items`.");return Math.max(1,Math.floor(o))}function P(e){var I,A;const u=(I=r.getCurrentInstance())==null?void 0:I.appContext,o=r.ref(null),g=r.shallowRef(null);let l=null;const n=new Map;let s=null;const b=((A=e.options)==null?void 0:A.layout)==="table";let d=null;const H=t=>{if(!e.renderHeader)return;d==null||d();const c=u??null,a=r.effectScope(!0);a.run(()=>r.watchEffect(()=>{const f=e.renderHeader(),m=Array.isArray(f)?f:[f];for(const i of m)r.isVNode(i)&&(i.appContext=c);const h=r.h(r.Fragment,m);h.appContext=c,r.render(h,t)},{flush:"sync"})),d=()=>a.stop()},R=()=>r.toValue(e.autoRender)??!0,x=t=>{if(e.getItem)return e.getItem(t);const c=r.toValue(e.items);return c?c[t]:void 0},F=(t,c)=>{const a=u??null,f=r.effectScope(!0);return f.run(()=>r.watchEffect(()=>{const m=e.renderItem(x(t),t),h=Array.isArray(m)?m:[m];for(const p of h)r.isVNode(p)&&(p.appContext=a);const i=r.h(r.Fragment,h);i.appContext=a,r.render(i,c)},{flush:"sync"})),()=>f.stop()},T=t=>{t.stop(),r.render(null,t.mount),t.mount.remove()},y=()=>{var p;if(!l)return null;const{scroller:t,contentEl:c,container:a}=l,f=a.clientHeight||a.offsetHeight||0,m=(v,E)=>{const w=document.createElement("div");b&&(w.style.display="contents"),w.setAttribute(q,String(v)),E.appendChild(w);const C=F(v,w);n.set(v,{el:E,mount:w,stop:C})},h=t.renderViewport(f,c,m),i=new Set(t.getRenderedIndices());return n.forEach((v,E)=>{i.has(E)||(T(v),n.delete(E))}),(p=e.onMeasuredViewport)==null||p.call(e,h),h},V=t=>{if(!l)return;const c=l;l=null,c.unsubscribe(),t&&(s={currentElement:c.scroller.currentElement,scrollOffset:c.scroller.scrollOffset}),n.forEach(a=>T(a)),n.clear(),d==null||d(),d=null,c.contentEl.textContent="",c.scroller.detachScrollbar(c.container),c.scroller.dispose(),g.value=null},O=t=>{var v,E,w;const c=L(t),a=e.options??{},f=a.onScroll,m={...a,onScroll:()=>{f==null||f(),R()&&y()}};if(b&&e.renderHeader){const C=(v=a.table)==null?void 0:v.header;m.table={...a.table,header:S=>{C==null||C(S),H(S)}}}const h=j(r.toValue(e.totalElements),((E=r.toValue(e.items))==null?void 0:E.length)??null),i=new N.CeriousScroll(t,h,m);s&&(i.currentElement=Math.min(s.currentElement,h-1),i.scrollOffset=s.scrollOffset,s=null);const p=B(t,C=>{var S;(S=e.onViewportChange)==null||S.call(e,C)});l={scroller:i,contentEl:c,container:t,unsubscribe:p},g.value=i,(w=e.onReady)==null||w.call(e,i),R()&&requestAnimationFrame(()=>y())},_=()=>{V(!0);const t=o.value;t&&O(t)};return r.onMounted(()=>{const t=o.value;t&&O(t)}),r.onBeforeUnmount(()=>{V(!1)}),r.watch(()=>[r.toValue(e.totalElements),r.toValue(e.items)],()=>{var c;if(!l)return;const t=j(r.toValue(e.totalElements),((c=r.toValue(e.items))==null?void 0:c.length)??null);l.scroller.totalElements!==t&&_()}),{containerRef:o,scroller:g,render:y,jumpToElement:t=>l?(l.scroller.jumpToElement(t),y()):null,scrollToPercentage:t=>l?(l.scroller.handleScrollPercentage(t),y()):null,reset:()=>l?(l.scroller.reset(),y()):null,recalculate:()=>l?(l.scroller.clearAllCaches(),y()):null}}const U=r.defineComponent({name:"CeriousScroll",props:{totalElements:{type:Number,default:null},items:{type:Array,default:null},getItem:{type:Function,default:void 0},renderItem:{type:Function,default:void 0},options:{type:Object,default:void 0},autoRender:{type:Boolean,default:!0}},emits:{"viewport-change":e=>!0,"measured-viewport":e=>!0,ready:e=>!0},setup(e,{slots:u,emit:o,expose:g}){const l=(s,b)=>{var d;return e.renderItem?e.renderItem(s,b):(d=u.item)==null?void 0:d.call(u,{item:s,index:b})},n=P({totalElements:()=>e.totalElements,items:()=>e.items,getItem:e.getItem?s=>e.getItem(s):void 0,renderItem:l,renderHeader:u.header?()=>u.header():void 0,options:e.options,autoRender:()=>e.autoRender,onViewportChange:s=>o("viewport-change",s),onMeasuredViewport:s=>o("measured-viewport",s),onReady:s=>o("ready",s)});return g({scroller:n.scroller,render:n.render,jumpToElement:n.jumpToElement,scrollToPercentage:n.scrollToPercentage,reset:n.reset,recalculate:n.recalculate}),()=>{var s;return r.h("div",{ref:n.containerRef,style:{position:"relative",overflow:"hidden"}},(s=u.default)==null?void 0:s.call(u))}}});Object.defineProperty(exports,"CeriousScrollEngine",{enumerable:!0,get:()=>N.CeriousScroll});exports.CeriousScroll=U;exports.useCeriousScroll=P;
|
package/dist/index.js
CHANGED
|
@@ -1,129 +1,156 @@
|
|
|
1
|
-
import { getCurrentInstance as
|
|
2
|
-
import { CeriousScroll as
|
|
3
|
-
import { CeriousScroll as
|
|
4
|
-
const
|
|
5
|
-
function
|
|
6
|
-
const
|
|
7
|
-
if (
|
|
1
|
+
import { getCurrentInstance as U, ref as W, shallowRef as X, onMounted as Y, onBeforeUnmount as z, watch as D, toValue as w, effectScope as N, watchEffect as j, isVNode as H, h as I, Fragment as P, render as T, defineComponent as G } from "vue";
|
|
2
|
+
import { CeriousScroll as J } from "@ceriousdevtech/cerious-scroll";
|
|
3
|
+
import { CeriousScroll as ie } from "@ceriousdevtech/cerious-scroll";
|
|
4
|
+
const _ = "data-cerious-scroll-content", K = "data-cerious-scroll-row";
|
|
5
|
+
function Q(e) {
|
|
6
|
+
const c = e.querySelector(`[${_}]`);
|
|
7
|
+
if (c) return c;
|
|
8
8
|
const n = document.createElement("div");
|
|
9
|
-
return n.setAttribute(
|
|
9
|
+
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;
|
|
10
10
|
}
|
|
11
|
-
function
|
|
11
|
+
function Z(e, c) {
|
|
12
12
|
const n = (o) => {
|
|
13
13
|
const r = o.detail;
|
|
14
|
-
r &&
|
|
14
|
+
r && c({
|
|
15
15
|
percentage: r.percentage,
|
|
16
16
|
currentElement: r.currentElement,
|
|
17
17
|
scrollOffset: r.scrollOffset,
|
|
18
18
|
result: { element: r.result.element, offset: r.result.offset }
|
|
19
19
|
});
|
|
20
|
-
},
|
|
20
|
+
}, h = (o) => {
|
|
21
21
|
const r = o.detail;
|
|
22
|
-
r &&
|
|
22
|
+
r && c({
|
|
23
23
|
percentage: r.percentage,
|
|
24
24
|
currentElement: r.element,
|
|
25
25
|
scrollOffset: r.scrollOffset,
|
|
26
26
|
result: { element: r.element, offset: r.scrollOffset }
|
|
27
27
|
});
|
|
28
28
|
};
|
|
29
|
-
return e.addEventListener("cerious-viewport-change", n), e.addEventListener("viewport-change",
|
|
30
|
-
e.removeEventListener("cerious-viewport-change", n), e.removeEventListener("viewport-change",
|
|
29
|
+
return e.addEventListener("cerious-viewport-change", n), e.addEventListener("viewport-change", h), () => {
|
|
30
|
+
e.removeEventListener("cerious-viewport-change", n), e.removeEventListener("viewport-change", h);
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
function
|
|
34
|
-
const n = typeof e == "number" ? e : typeof
|
|
33
|
+
function F(e, c) {
|
|
34
|
+
const n = typeof e == "number" ? e : typeof c == "number" ? c : void 0;
|
|
35
35
|
if (n === void 0 || Number.isNaN(n))
|
|
36
36
|
throw new Error("useCeriousScroll: provide `totalElements` or `items`.");
|
|
37
37
|
return Math.max(1, Math.floor(n));
|
|
38
38
|
}
|
|
39
|
-
function
|
|
40
|
-
var
|
|
41
|
-
const
|
|
39
|
+
function k(e) {
|
|
40
|
+
var V, x;
|
|
41
|
+
const c = (V = U()) == null ? void 0 : V.appContext, n = W(null), h = X(null);
|
|
42
42
|
let o = null;
|
|
43
43
|
const r = /* @__PURE__ */ new Map();
|
|
44
|
-
let
|
|
45
|
-
const
|
|
44
|
+
let s = null;
|
|
45
|
+
const b = ((x = e.options) == null ? void 0 : x.layout) === "table";
|
|
46
|
+
let f = null;
|
|
47
|
+
const L = (t) => {
|
|
48
|
+
if (!e.renderHeader) return;
|
|
49
|
+
f == null || f();
|
|
50
|
+
const l = c ?? null, u = N(!0);
|
|
51
|
+
u.run(
|
|
52
|
+
() => j(
|
|
53
|
+
() => {
|
|
54
|
+
const a = e.renderHeader(), d = Array.isArray(a) ? a : [a];
|
|
55
|
+
for (const i of d) H(i) && (i.appContext = l);
|
|
56
|
+
const m = I(P, d);
|
|
57
|
+
m.appContext = l, T(m, t);
|
|
58
|
+
},
|
|
59
|
+
{ flush: "sync" }
|
|
60
|
+
)
|
|
61
|
+
), f = () => u.stop();
|
|
62
|
+
}, O = () => w(e.autoRender) ?? !0, $ = (t) => {
|
|
46
63
|
if (e.getItem) return e.getItem(t);
|
|
47
|
-
const
|
|
48
|
-
return
|
|
49
|
-
},
|
|
50
|
-
const u =
|
|
51
|
-
return
|
|
52
|
-
() =>
|
|
64
|
+
const l = w(e.items);
|
|
65
|
+
return l ? l[t] : void 0;
|
|
66
|
+
}, q = (t, l) => {
|
|
67
|
+
const u = c ?? null, a = N(!0);
|
|
68
|
+
return a.run(
|
|
69
|
+
() => j(
|
|
53
70
|
() => {
|
|
54
|
-
const
|
|
55
|
-
for (const
|
|
56
|
-
H(
|
|
57
|
-
const i =
|
|
58
|
-
i.appContext = u,
|
|
71
|
+
const d = e.renderItem($(t), t), m = Array.isArray(d) ? d : [d];
|
|
72
|
+
for (const y of m)
|
|
73
|
+
H(y) && (y.appContext = u);
|
|
74
|
+
const i = I(P, m);
|
|
75
|
+
i.appContext = u, T(i, l);
|
|
59
76
|
},
|
|
60
77
|
{ flush: "sync" }
|
|
61
78
|
)
|
|
62
|
-
), () =>
|
|
79
|
+
), () => a.stop();
|
|
63
80
|
}, S = (t) => {
|
|
64
|
-
t.stop(),
|
|
65
|
-
},
|
|
66
|
-
var
|
|
81
|
+
t.stop(), T(null, t.mount), t.mount.remove();
|
|
82
|
+
}, p = () => {
|
|
83
|
+
var y;
|
|
67
84
|
if (!o) return null;
|
|
68
|
-
const { scroller: t, contentEl:
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
r.set(
|
|
73
|
-
}, m = t.renderViewport(
|
|
74
|
-
return r.forEach((
|
|
75
|
-
i.has(g) || (S(
|
|
76
|
-
}), (
|
|
77
|
-
},
|
|
85
|
+
const { scroller: t, contentEl: l, container: u } = o, a = u.clientHeight || u.offsetHeight || 0, d = (v, g) => {
|
|
86
|
+
const E = document.createElement("div");
|
|
87
|
+
b && (E.style.display = "contents"), E.setAttribute(K, String(v)), g.appendChild(E);
|
|
88
|
+
const C = q(v, E);
|
|
89
|
+
r.set(v, { el: g, mount: E, stop: C });
|
|
90
|
+
}, m = t.renderViewport(a, l, d), i = new Set(t.getRenderedIndices());
|
|
91
|
+
return r.forEach((v, g) => {
|
|
92
|
+
i.has(g) || (S(v), r.delete(g));
|
|
93
|
+
}), (y = e.onMeasuredViewport) == null || y.call(e, m), m;
|
|
94
|
+
}, A = (t) => {
|
|
78
95
|
if (!o) return;
|
|
79
|
-
const
|
|
80
|
-
o = null,
|
|
81
|
-
currentElement:
|
|
82
|
-
scrollOffset:
|
|
83
|
-
}), r.forEach((u) => S(u)), r.clear(),
|
|
84
|
-
},
|
|
85
|
-
var
|
|
86
|
-
const
|
|
96
|
+
const l = o;
|
|
97
|
+
o = null, l.unsubscribe(), t && (s = {
|
|
98
|
+
currentElement: l.scroller.currentElement,
|
|
99
|
+
scrollOffset: l.scroller.scrollOffset
|
|
100
|
+
}), r.forEach((u) => S(u)), r.clear(), f == null || f(), f = null, l.contentEl.textContent = "", l.scroller.detachScrollbar(l.container), l.scroller.dispose(), h.value = null;
|
|
101
|
+
}, M = (t) => {
|
|
102
|
+
var v, g, E;
|
|
103
|
+
const l = Q(t), u = e.options ?? {}, a = u.onScroll, d = {
|
|
87
104
|
...u,
|
|
88
105
|
onScroll: () => {
|
|
89
|
-
|
|
106
|
+
a == null || a(), O() && p();
|
|
90
107
|
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
108
|
+
};
|
|
109
|
+
if (b && e.renderHeader) {
|
|
110
|
+
const C = (v = u.table) == null ? void 0 : v.header;
|
|
111
|
+
d.table = {
|
|
112
|
+
...u.table,
|
|
113
|
+
header: (R) => {
|
|
114
|
+
C == null || C(R), L(R);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const m = F(w(e.totalElements), ((g = w(e.items)) == null ? void 0 : g.length) ?? null), i = new J(t, m, d);
|
|
119
|
+
s && (i.currentElement = Math.min(s.currentElement, m - 1), i.scrollOffset = s.scrollOffset, s = null);
|
|
120
|
+
const y = Z(t, (C) => {
|
|
94
121
|
var R;
|
|
95
|
-
(R = e.onViewportChange) == null || R.call(e,
|
|
122
|
+
(R = e.onViewportChange) == null || R.call(e, C);
|
|
96
123
|
});
|
|
97
|
-
o = { scroller: i, contentEl:
|
|
98
|
-
},
|
|
99
|
-
|
|
124
|
+
o = { scroller: i, contentEl: l, container: t, unsubscribe: y }, h.value = i, (E = e.onReady) == null || E.call(e, i), O() && requestAnimationFrame(() => p());
|
|
125
|
+
}, B = () => {
|
|
126
|
+
A(!0);
|
|
100
127
|
const t = n.value;
|
|
101
|
-
t &&
|
|
128
|
+
t && M(t);
|
|
102
129
|
};
|
|
103
|
-
return
|
|
130
|
+
return Y(() => {
|
|
104
131
|
const t = n.value;
|
|
105
|
-
t &&
|
|
106
|
-
}),
|
|
107
|
-
|
|
108
|
-
}),
|
|
109
|
-
() => [
|
|
132
|
+
t && M(t);
|
|
133
|
+
}), z(() => {
|
|
134
|
+
A(!1);
|
|
135
|
+
}), D(
|
|
136
|
+
() => [w(e.totalElements), w(e.items)],
|
|
110
137
|
() => {
|
|
111
|
-
var
|
|
138
|
+
var l;
|
|
112
139
|
if (!o) return;
|
|
113
|
-
const t =
|
|
114
|
-
o.scroller.totalElements !== t &&
|
|
140
|
+
const t = F(w(e.totalElements), ((l = w(e.items)) == null ? void 0 : l.length) ?? null);
|
|
141
|
+
o.scroller.totalElements !== t && B();
|
|
115
142
|
}
|
|
116
143
|
), {
|
|
117
144
|
containerRef: n,
|
|
118
|
-
scroller:
|
|
119
|
-
render:
|
|
120
|
-
jumpToElement: (t) => o ? (o.scroller.jumpToElement(t),
|
|
121
|
-
scrollToPercentage: (t) => o ? (o.scroller.handleScrollPercentage(t),
|
|
122
|
-
reset: () => o ? (o.scroller.reset(),
|
|
123
|
-
recalculate: () => o ? (o.scroller.clearAllCaches(),
|
|
145
|
+
scroller: h,
|
|
146
|
+
render: p,
|
|
147
|
+
jumpToElement: (t) => o ? (o.scroller.jumpToElement(t), p()) : null,
|
|
148
|
+
scrollToPercentage: (t) => o ? (o.scroller.handleScrollPercentage(t), p()) : null,
|
|
149
|
+
reset: () => o ? (o.scroller.reset(), p()) : null,
|
|
150
|
+
recalculate: () => o ? (o.scroller.clearAllCaches(), p()) : null
|
|
124
151
|
};
|
|
125
152
|
}
|
|
126
|
-
const
|
|
153
|
+
const ce = G({
|
|
127
154
|
name: "CeriousScroll",
|
|
128
155
|
props: {
|
|
129
156
|
/** Total item count. Falls back to `items.length` when omitted. */
|
|
@@ -150,24 +177,27 @@ const te = W({
|
|
|
150
177
|
/** Emitted once the underlying engine instance is ready (and after recreation). */
|
|
151
178
|
ready: (e) => !0
|
|
152
179
|
},
|
|
153
|
-
setup(e, { slots:
|
|
154
|
-
const o = (
|
|
155
|
-
var
|
|
156
|
-
return e.renderItem ? e.renderItem(
|
|
157
|
-
}, r =
|
|
180
|
+
setup(e, { slots: c, emit: n, expose: h }) {
|
|
181
|
+
const o = (s, b) => {
|
|
182
|
+
var f;
|
|
183
|
+
return e.renderItem ? e.renderItem(s, b) : (f = c.item) == null ? void 0 : f.call(c, { item: s, index: b });
|
|
184
|
+
}, r = k({
|
|
158
185
|
totalElements: () => e.totalElements,
|
|
159
186
|
items: () => e.items,
|
|
160
|
-
getItem: e.getItem ? (
|
|
187
|
+
getItem: e.getItem ? (s) => e.getItem(s) : void 0,
|
|
161
188
|
renderItem: o,
|
|
189
|
+
// Table mode: declarative header. Render the `#header` slot (a <tr> of
|
|
190
|
+
// <th>s) into the engine's <thead>. `undefined` when no slot is provided.
|
|
191
|
+
renderHeader: c.header ? () => c.header() : void 0,
|
|
162
192
|
// Engine options are consumed at creation; reading the prop once matches
|
|
163
193
|
// that contract (remount via `:key` to apply new engine options).
|
|
164
194
|
options: e.options,
|
|
165
195
|
autoRender: () => e.autoRender,
|
|
166
|
-
onViewportChange: (
|
|
167
|
-
onMeasuredViewport: (
|
|
168
|
-
onReady: (
|
|
196
|
+
onViewportChange: (s) => n("viewport-change", s),
|
|
197
|
+
onMeasuredViewport: (s) => n("measured-viewport", s),
|
|
198
|
+
onReady: (s) => n("ready", s)
|
|
169
199
|
});
|
|
170
|
-
return
|
|
200
|
+
return h({
|
|
171
201
|
/** The underlying engine instance (`null` before mount). */
|
|
172
202
|
scroller: r.scroller,
|
|
173
203
|
render: r.render,
|
|
@@ -176,21 +206,21 @@ const te = W({
|
|
|
176
206
|
reset: r.reset,
|
|
177
207
|
recalculate: r.recalculate
|
|
178
208
|
}), () => {
|
|
179
|
-
var
|
|
180
|
-
return
|
|
209
|
+
var s;
|
|
210
|
+
return I(
|
|
181
211
|
"div",
|
|
182
212
|
{
|
|
183
213
|
ref: r.containerRef,
|
|
184
214
|
// User-supplied class/style/attrs fall through and merge onto this root.
|
|
185
215
|
style: { position: "relative", overflow: "hidden" }
|
|
186
216
|
},
|
|
187
|
-
(
|
|
217
|
+
(s = c.default) == null ? void 0 : s.call(c)
|
|
188
218
|
);
|
|
189
219
|
};
|
|
190
220
|
}
|
|
191
221
|
});
|
|
192
222
|
export {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
223
|
+
ce as CeriousScroll,
|
|
224
|
+
ie as CeriousScrollEngine,
|
|
225
|
+
k as useCeriousScroll
|
|
196
226
|
};
|
|
@@ -10,6 +10,11 @@ export interface UseCeriousScrollOptions<TItem = unknown> {
|
|
|
10
10
|
getItem?: (index: number) => TItem;
|
|
11
11
|
/** Renders a single row to a Vue VNode. `item` is `undefined` with no data source. */
|
|
12
12
|
renderItem: (item: TItem, index: number) => VNodeChild;
|
|
13
|
+
/**
|
|
14
|
+
* Table mode only: renders the header (a `<tr>` of `<th>`s) into the engine's
|
|
15
|
+
* `<thead>`. Reactive — re-renders when its dependencies change.
|
|
16
|
+
*/
|
|
17
|
+
renderHeader?: () => VNodeChild;
|
|
13
18
|
/** Options forwarded to `new CeriousScroll(...)` (read once, at creation). */
|
|
14
19
|
options?: CeriousScrollOptions;
|
|
15
20
|
/** Automatically render after scroll/resize/data changes. Default: `true`. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ceriousdevtech/vue-cerious-scroll",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Vue 3 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",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"demo:build": "vite build --config demo/vite.config.ts"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@ceriousdevtech/cerious-scroll": "^1.0.
|
|
60
|
+
"@ceriousdevtech/cerious-scroll": "^1.0.6"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
63
|
"vue": "^3.3.0"
|