vlist 3.0.0-next.1 → 3.0.0-next.3
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.github.md +111 -65
- package/README.md +70 -54
- package/dist/config.d.ts +105 -14
- package/dist/config.js +1 -1
- package/dist/core/create.d.ts +22 -5
- package/dist/core/dom.d.ts +1 -1
- package/dist/core/hooks.d.ts +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/pipeline.d.ts +1 -1
- package/dist/core/pool.d.ts +1 -1
- package/dist/core/runway.d.ts +6 -2
- package/dist/core/scroll.d.ts +1 -1
- package/dist/core/sizes.d.ts +1 -1
- package/dist/core/state.d.ts +13 -1
- package/dist/core/types.d.ts +134 -62
- package/dist/core/velocity.d.ts +1 -1
- package/dist/index.d.ts +17 -2
- package/dist/index.js +1 -1
- package/dist/internals.d.ts +0 -1
- package/dist/internals.js +1 -1
- package/dist/native.d.ts +6 -10
- package/dist/native.js +1 -1
- package/dist/plugins/a11y/index.d.ts +1 -0
- package/dist/plugins/a11y/plugin.d.ts +1 -1
- package/dist/plugins/autosize/index.d.ts +2 -1
- package/dist/plugins/autosize/plugin.d.ts +13 -2
- package/dist/plugins/carousel/engine.d.ts +1 -1
- package/dist/plugins/carousel/index.d.ts +1 -0
- package/dist/plugins/carousel/plugin.d.ts +30 -2
- package/dist/plugins/carousel/presets.d.ts +1 -1
- package/dist/plugins/data/index.d.ts +1 -0
- package/dist/plugins/data/plugin.d.ts +15 -2
- package/dist/plugins/grid/index.d.ts +2 -1
- package/dist/plugins/grid/plugin.d.ts +14 -2
- package/dist/plugins/groups/index.d.ts +1 -0
- package/dist/plugins/groups/plugin.d.ts +11 -3
- package/dist/plugins/groups/types.d.ts +6 -1
- package/dist/plugins/masonry/index.d.ts +2 -1
- package/dist/plugins/masonry/plugin.d.ts +10 -2
- package/dist/plugins/masonry/renderer.d.ts +5 -1
- package/dist/plugins/page/plugin.d.ts +1 -1
- package/dist/plugins/scrollbar/index.d.ts +2 -1
- package/dist/plugins/scrollbar/plugin.d.ts +7 -2
- package/dist/plugins/search/index.d.ts +1 -0
- package/dist/plugins/search/plugin.d.ts +26 -1
- package/dist/plugins/selection/index.d.ts +2 -1
- package/dist/plugins/selection/plugin.d.ts +23 -2
- package/dist/plugins/snapshots/index.d.ts +1 -0
- package/dist/plugins/snapshots/plugin.d.ts +9 -2
- package/dist/plugins/sortable/index.d.ts +1 -0
- package/dist/plugins/sortable/plugin.d.ts +11 -3
- package/dist/plugins/table/index.d.ts +1 -0
- package/dist/plugins/table/plugin.d.ts +19 -3
- package/dist/plugins/transition/plugin.d.ts +1 -1
- package/dist/plugins/tree/index.d.ts +1 -0
- package/dist/plugins/tree/layout.d.ts +1 -1
- package/dist/plugins/tree/plugin.d.ts +37 -3
- package/dist/plugins/tree/types.d.ts +1 -1
- package/dist/rendering/sizes.d.ts +7 -1
- package/dist/size.json +1 -1
- package/dist/synthetic.d.ts +3 -3
- package/dist/synthetic.js +1 -1
- package/dist/types.d.ts +17 -21
- package/dist/utils/scroll-padding.d.ts +36 -0
- package/dist/utils/stats.d.ts +9 -1
- package/dist/vlist.css +1 -1
- package/package.json +6 -2
- package/dist/plugins/grid/renderer.d.ts +0 -68
package/dist/types.d.ts
CHANGED
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
/** Base event map with index signature */
|
|
6
6
|
export type EventMap = Record<string, unknown>;
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Base item interface: an item only has to carry an id. Plugins that read
|
|
9
|
+
* arbitrary fields (search, table, tree) narrow the item themselves, so an
|
|
10
|
+
* ordinary `interface Row { id: number; name: string }` satisfies this.
|
|
11
|
+
*/
|
|
8
12
|
export interface VListItem {
|
|
9
13
|
id: string | number;
|
|
10
|
-
[key: string]: unknown;
|
|
11
14
|
}
|
|
12
15
|
/** Groups configuration for createVList */
|
|
13
16
|
export interface GroupHeaderConfig {
|
|
@@ -291,8 +294,11 @@ export interface ScrollConfig {
|
|
|
291
294
|
* Useful for carousels, wizards, and circular navigation.
|
|
292
295
|
*/
|
|
293
296
|
wrap?: boolean;
|
|
294
|
-
/**
|
|
295
|
-
|
|
297
|
+
/** Native visibility: "none" hides the browser scrollbar, "native" keeps it.
|
|
298
|
+
* Options are consumed by vlist/config; with the low-level factory install
|
|
299
|
+
* scrollbar() explicitly. The synthetic entry rejects both string values.
|
|
300
|
+
*/
|
|
301
|
+
scrollbar?: "native" | "none" | ScrollbarOptions;
|
|
296
302
|
/** External scroll element for window scrolling */
|
|
297
303
|
element?: Window;
|
|
298
304
|
/** Scroll idle detection timeout in ms (default: 150) */
|
|
@@ -338,20 +344,6 @@ export type ScrollbarPadding = number | {
|
|
|
338
344
|
bottom?: number;
|
|
339
345
|
left?: number;
|
|
340
346
|
};
|
|
341
|
-
/**
|
|
342
|
-
* Scrollbar configuration.
|
|
343
|
-
* @deprecated Use `scroll.scrollbar` in `ScrollConfig` instead.
|
|
344
|
-
*/
|
|
345
|
-
export interface ScrollbarConfig {
|
|
346
|
-
/** Enable scrollbar (default: true) */
|
|
347
|
-
enabled?: boolean;
|
|
348
|
-
/** Auto-hide scrollbar after idle (default: true) */
|
|
349
|
-
autoHide?: boolean;
|
|
350
|
-
/** Auto-hide delay in milliseconds (default: 1000) */
|
|
351
|
-
autoHideDelay?: number;
|
|
352
|
-
/** Minimum thumb size in pixels (default: 30) */
|
|
353
|
-
minThumbSize?: number;
|
|
354
|
-
}
|
|
355
347
|
/** Item template function */
|
|
356
348
|
export type ItemTemplate<T = VListItem> = (item: T, index: number, state: ItemState) => string | HTMLElement;
|
|
357
349
|
/** Tree-specific state available in templates when the tree plugin is active */
|
|
@@ -465,19 +457,23 @@ export interface ErrorViewportSnapshot {
|
|
|
465
457
|
}
|
|
466
458
|
/** Event types and their payloads */
|
|
467
459
|
export interface VListEvents<T extends VListItem = VListItem> extends EventMap {
|
|
468
|
-
/**
|
|
460
|
+
/**
|
|
461
|
+
* Item clicked. `index` is the DATA index — what `getItemAt`,
|
|
462
|
+
* `scrollToIndex` and `removeItem` take — not the layout index, which counts
|
|
463
|
+
* group headers and carousel laps as well.
|
|
464
|
+
*/
|
|
469
465
|
"item:click": {
|
|
470
466
|
item: T;
|
|
471
467
|
index: number;
|
|
472
468
|
event: MouseEvent;
|
|
473
469
|
};
|
|
474
|
-
/** Item double-clicked */
|
|
470
|
+
/** Item double-clicked. `index` is the data index, as for `item:click`. */
|
|
475
471
|
"item:dblclick": {
|
|
476
472
|
item: T;
|
|
477
473
|
index: number;
|
|
478
474
|
event: MouseEvent;
|
|
479
475
|
};
|
|
480
|
-
/** Item right-clicked */
|
|
476
|
+
/** Item right-clicked. `index` is the data index, as for `item:click`. */
|
|
481
477
|
"item:contextmenu": {
|
|
482
478
|
item: T;
|
|
483
479
|
index: number;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist/utils — Scroll Padding Protocol
|
|
3
|
+
*
|
|
4
|
+
* page() keeps a band of the window clear at each end of the main axis — a
|
|
5
|
+
* sticky site header, a floating toolbar — and applies it to every scroll it
|
|
6
|
+
* computes. Layout plugins take over those computations: groups() and
|
|
7
|
+
* masonry() both override `_scrollItemIntoView` and install their own
|
|
8
|
+
* `setToIndexFn`, because only they know where an entry actually sits.
|
|
9
|
+
*
|
|
10
|
+
* So the band is published through the `_getScrollPadding` hook rather than
|
|
11
|
+
* baked into page's own scroll code alone, and the plugins that displace page
|
|
12
|
+
* read it back and fold it into their geometry. Without the hook a caller's
|
|
13
|
+
* `scrollPadding` silently disappeared as soon as either plugin was seated.
|
|
14
|
+
*/
|
|
15
|
+
import type { PluginContext } from "../core/types";
|
|
16
|
+
import type { VListItem } from "../types";
|
|
17
|
+
/** Band to keep clear at each end of the main axis, in pixels. */
|
|
18
|
+
export interface ScrollPadding {
|
|
19
|
+
/** Top (vertical) or left (horizontal). */
|
|
20
|
+
readonly start: number;
|
|
21
|
+
/** Bottom (vertical) or right (horizontal). */
|
|
22
|
+
readonly end: number;
|
|
23
|
+
}
|
|
24
|
+
/** Internal hook name carrying the band across plugins. */
|
|
25
|
+
export declare const SCROLL_PADDING_HOOK = "_getScrollPadding";
|
|
26
|
+
/** No padding — the shape every list without page() sees. */
|
|
27
|
+
export declare const NO_SCROLL_PADDING: ScrollPadding;
|
|
28
|
+
/**
|
|
29
|
+
* Read the published scroll padding, or zero when no plugin publishes one.
|
|
30
|
+
*
|
|
31
|
+
* The hook is resolved on first read instead of during setup: the publisher is
|
|
32
|
+
* not guaranteed to be seated first. The band itself is read on every call,
|
|
33
|
+
* since page() accepts functions that measure a sticky header each time.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createScrollPaddingReader<T extends VListItem>(ctx: PluginContext<T>): () => ScrollPadding;
|
|
36
|
+
//# sourceMappingURL=scroll-padding.d.ts.map
|
package/dist/utils/stats.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface StatsConfig {
|
|
2
|
-
/** Returns the
|
|
2
|
+
/** Returns the unscaled logical position, normally list.getScrollPosition(). */
|
|
3
3
|
getScrollPosition: () => number;
|
|
4
4
|
/** Returns the total number of items */
|
|
5
5
|
getTotal: () => number;
|
|
@@ -33,6 +33,14 @@ export interface Stats {
|
|
|
33
33
|
*
|
|
34
34
|
* All inputs are provided via callbacks so the tracker always reflects
|
|
35
35
|
* the latest values without needing to be recreated when the list changes.
|
|
36
|
+
* Position is an unscaled logical offset on both native and synthetic entries,
|
|
37
|
+
* clamped to the declared content's real scroll range. Progress counts items up
|
|
38
|
+
* to the viewport end (including partial rows), rather than just scroll distance.
|
|
39
|
+
*
|
|
40
|
+
* Native content beyond the browser limit still uses its full declared size:
|
|
41
|
+
* a browser-clamped position is not expanded to the end, so progress may never
|
|
42
|
+
* reach 100%. Handle the core's `content:size:overflow` error and use
|
|
43
|
+
* `vlist/synthetic` when the full range must remain reachable.
|
|
36
44
|
*
|
|
37
45
|
* ```ts
|
|
38
46
|
* const stats = createStats({
|
package/dist/vlist.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@keyframes vlist-fade-in{from{opacity:0.6}to{opacity:1}}@keyframes vlist-placeholder-pulse{0%,100%{opacity:0.6}50%{opacity:0.4}}:root{--vlist-scrollbar-width:8px;--vlist-scrollbar-track-color:transparent;--vlist-scrollbar-radius:4px;--vlist-custom-scrollbar-track-color:transparent;--vlist-custom-scrollbar-padding-top:2px;--vlist-custom-scrollbar-padding-right:2px;--vlist-custom-scrollbar-padding-bottom:2px;--vlist-custom-scrollbar-padding-left:2px;--vlist-custom-scrollbar-min-thumb-size:15px;--vlist-item-padding-x:1rem;--vlist-item-padding-y:0.75rem;--vlist-border-radius:0.5rem;--vlist-transition-duration:150ms;--vlist-transition-timing:ease-in-out;--vlist-bg:#ffffff;--vlist-bg-hover:rgba(0,0,0,0.04);--vlist-bg-striped:rgba(0,0,0,0.02);--vlist-bg-selected:rgba(59,130,246,0.12);--vlist-bg-selected-hover:rgba(59,130,246,0.18);--vlist-border:#e5e7eb;--vlist-border-selected:#3b82f6;--vlist-text:#111827;--vlist-text-muted:#6b7280;--vlist-focus-ring:#3b82f6;--vlist-group-header-bg:#f3f4f6;--vlist-scrollbar-thumb-color:#d1d5db;--vlist-scrollbar-thumb-hover-color:#9ca3af;--vlist-custom-scrollbar-thumb-color:rgba(0,0,0,0.2);--vlist-custom-scrollbar-thumb-hover-color:rgba(0,0,0,0.3);--vlist-placeholder-bg:rgba(0,0,0,0.2);--vlist-placeholder-bg-strong:rgba(0,0,0,0.24)}[data-theme-mode="dark"]{--vlist-bg:#111827;--vlist-bg-hover:rgba(255,255,255,0.06);--vlist-bg-striped:rgba(255,255,255,0.02);--vlist-bg-selected:rgba(59,130,246,0.2);--vlist-bg-selected-hover:rgba(59,130,246,0.28);--vlist-border:#374151;--vlist-border-selected:#3b82f6;--vlist-text:#f9fafb;--vlist-text-muted:#9ca3af;--vlist-focus-ring:#3b82f6;--vlist-group-header-bg:#1e2433;--vlist-scrollbar-thumb-color:#4b5563;--vlist-scrollbar-thumb-hover-color:#6b7280;--vlist-custom-scrollbar-thumb-color:rgba(255,255,255,0.2);--vlist-custom-scrollbar-thumb-hover-color:rgba(255,255,255,0.3);--vlist-placeholder-bg:rgba(255,255,255,0.3);--vlist-placeholder-bg-strong:rgba(255,255,255,0.35)}@media (prefers-color-scheme:dark){:root:not([data-theme-mode="light"]):not([data-theme-mode="dark"]){--vlist-bg:#111827;--vlist-bg-hover:rgba(255,255,255,0.06);--vlist-bg-striped:rgba(255,255,255,0.02);--vlist-bg-selected:rgba(59,130,246,0.2);--vlist-bg-selected-hover:rgba(59,130,246,0.28);--vlist-border:#374151;--vlist-border-selected:#3b82f6;--vlist-text:#f9fafb;--vlist-text-muted:#9ca3af;--vlist-focus-ring:#3b82f6;--vlist-group-header-bg:#1e2433;--vlist-scrollbar-thumb-color:#4b5563;--vlist-scrollbar-thumb-hover-color:#6b7280;--vlist-custom-scrollbar-thumb-color:rgba(255,255,255,0.2);--vlist-custom-scrollbar-thumb-hover-color:rgba(255,255,255,0.3);--vlist-placeholder-bg:rgba(255,255,255,0.3);--vlist-placeholder-bg-strong:rgba(255,255,255,0.35)}}.dark{--vlist-bg:#111827;--vlist-bg-hover:rgba(255,255,255,0.06);--vlist-bg-striped:rgba(255,255,255,0.02);--vlist-bg-selected:rgba(59,130,246,0.2);--vlist-bg-selected-hover:rgba(59,130,246,0.28);--vlist-border:#374151;--vlist-border-selected:#3b82f6;--vlist-text:#f9fafb;--vlist-text-muted:#9ca3af;--vlist-focus-ring:#3b82f6;--vlist-group-header-bg:#1e2433;--vlist-scrollbar-thumb-color:#4b5563;--vlist-scrollbar-thumb-hover-color:#6b7280;--vlist-custom-scrollbar-thumb-color:rgba(255,255,255,0.2);--vlist-custom-scrollbar-thumb-hover-color:rgba(255,255,255,0.3);--vlist-placeholder-bg:rgba(255,255,255,0.3);--vlist-placeholder-bg-strong:rgba(255,255,255,0.35)}.vlist{position:relative;width:100%;height:100%;box-sizing:border-box;overflow:hidden;background-color:var(--vlist-bg);color:var(--vlist-text);color-scheme:light;border:1px solid var(--vlist-border);border-radius:var(--vlist-border-radius);outline:none}[data-theme-mode="dark"] .vlist,.dark .vlist{color-scheme:dark}@media (prefers-color-scheme:dark){:root:not([data-theme-mode="light"]) .vlist{color-scheme:dark}}.vlist:focus,.vlist:focus-visible,.vlist-content:focus,.vlist-content:focus-visible{outline:none}.vlist-viewport{width:100%;height:100%;overflow:auto;scrollbar-color:var(--vlist-scrollbar-thumb-color) var(--vlist-scrollbar-track-color)}@supports (-moz-appearance:none) and (scrollbar-width:1px){.vlist-viewport{scrollbar-width:var(--vlist-scrollbar-width)}}.vlist-viewport::-webkit-scrollbar{width:var(--vlist-scrollbar-width);height:var(--vlist-scrollbar-width)}.vlist-viewport::-webkit-scrollbar-track{background:var(--vlist-scrollbar-track-color)}.vlist-viewport::-webkit-scrollbar-thumb{background-color:var(--vlist-scrollbar-thumb-color);border-radius:var(--vlist-scrollbar-radius)}.vlist-viewport::-webkit-scrollbar-thumb:hover{background-color:var(--vlist-scrollbar-thumb-hover-color)}.vlist-content{position:relative;width:100%;contain:layout style}.vlist-item,.vlist-group-header{position:absolute;top:0;left:0;right:0;display:flex;align-items:center;background-color:var(--vlist-bg);cursor:default;user-select:none;opacity:1;transition:background-color var(--vlist-transition-duration) var(--vlist-transition-timing),opacity var(--vlist-transition-duration) var(--vlist-transition-timing);contain:content;box-sizing:border-box;will-change:transform}.vlist--scrolling .vlist-item,.vlist--settling .vlist-item,.vlist--scrolling .vlist-group-header,.vlist--settling .vlist-group-header{transition:none}.vlist--selectable .vlist-item{cursor:pointer}.vlist--selectable .vlist-item:hover{background-color:var(--vlist-bg-hover)}.vlist-item.vlist-item--odd{background:var(--vlist-bg-striped)}.vlist-item.vlist-item--selected{background-color:var(--vlist-bg-selected)}.vlist-item.vlist-item--odd.vlist-item--selected{background:var(--vlist-bg-selected)}.vlist-item.vlist-item--selected:hover{background-color:var(--vlist-bg-selected-hover)}.vlist-item.vlist-item--odd.vlist-item--selected:hover{background:var(--vlist-bg-selected-hover)}.vlist-item.vlist-item--focused{outline:2px solid var(--vlist-focus-ring,#3b82f6);outline-offset:-2px;z-index:1}.vlist-item--replaced{animation:vlist-fade-in 0.3s ease-out}.vlist-item--placeholder{opacity:0.6;animation:vlist-placeholder-pulse 2s ease-in-out infinite}.vlist-item--placeholder *:not(:has(*)){color:transparent;background-color:var(--vlist-placeholder-bg);border-radius:4px;width:fit-content;line-height:1.2;transform:scaleY(0.8)}.vlist-item--placeholder:is(strong,b,h1,h2,h3,h4):not(:has(*)){background-color:var(--vlist-placeholder-bg-strong)}.vlist-item.vlist-item--selected.vlist-item--focused{outline-color:var(--vlist-border-selected)}.vlist-scrollbar:focus-visible{outline:2px solid currentColor;outline-offset:-2px;opacity:1;pointer-events:auto}.vlist-scrollbar{position:absolute;top:var(--vlist-custom-scrollbar-padding-top);right:var(--vlist-custom-scrollbar-padding-right);bottom:var(--vlist-custom-scrollbar-padding-bottom);width:var(--vlist-custom-scrollbar-width);background-color:var(--vlist-custom-scrollbar-track-color);opacity:0;transition:opacity 0.2s ease-out;touch-action:none;z-index:10;pointer-events:none}.vlist-scrollbar__hover{position:absolute;top:0;right:0;height:100%;z-index:9;touch-action:none;pointer-events:auto}.vlist-scrollbar__hover--horizontal{top:auto;right:auto;bottom:0;left:0;width:100%;height:auto}.vlist-scrollbar--visible{opacity:1;pointer-events:auto}.vlist-scrollbar__thumb{position:absolute;top:0;left:0;right:0;width:100%;background-color:var(--vlist-custom-scrollbar-thumb-color);border-radius:var(--vlist-custom-scrollbar-radius);cursor:pointer;transition:background-color 0.15s ease-out}.vlist-scrollbar__thumb:hover{background-color:var(--vlist-custom-scrollbar-thumb-hover-color)}.vlist-scrollbar--dragging{opacity:1;pointer-events:auto}.vlist-scrollbar--dragging .vlist-scrollbar__thumb{background-color:var(--vlist-custom-scrollbar-thumb-hover-color)}@media (forced-colors:active){.vlist-scrollbar{forced-color-adjust:none;background-color:Canvas}.vlist-scrollbar__thumb{background-color:CanvasText}.vlist-scrollbar__thumb:hover,.vlist-scrollbar--dragging .vlist-scrollbar__thumb{background-color:Highlight}.vlist-scrollbar:focus-visible{outline-color:Highlight}}.vlist-group-header{cursor:default;background-color:var(--vlist-group-header-bg,#f3f4f6);z-index:1;overflow:hidden}.vlist-group-header:hover{background-color:var(--vlist-group-header-bg,#f3f4f6)}.vlist-sticky-header{left:0;right:0;background-color:var(--vlist-group-header-bg,#f3f4f6)}.vlist--horizontal{overflow:hidden}.vlist--horizontal .vlist-viewport{overflow-x:auto;overflow-y:hidden}.vlist--horizontal .vlist-content{height:100%;width:auto}.vlist--horizontal .vlist-item,.vlist--horizontal .vlist-group-header{position:absolute;top:0;bottom:0;left:0;right:auto;display:flex;align-items:center;justify-content:center;border-bottom:none}.vlist-scrollbar--horizontal{top:auto;left:var(--vlist-custom-scrollbar-padding-left);right:var(--vlist-custom-scrollbar-padding-right);bottom:var(--vlist-custom-scrollbar-padding-bottom);width:auto;height:var(--vlist-custom-scrollbar-width)}.vlist-scrollbar--horizontal .vlist-scrollbar__thumb{top:0;left:0;width:auto;height:100%}.vlist-viewport--gutter{padding-right:calc( var(--vlist-custom-scrollbar-padding-right) + var(--vlist-custom-scrollbar-width) + var(--vlist-custom-scrollbar-padding-left) )}.vlist--horizontal .vlist-viewport--gutter{padding-right:0;padding-bottom:calc( var(--vlist-custom-scrollbar-padding-bottom) + var(--vlist-custom-scrollbar-width) + var(--vlist-custom-scrollbar-padding-top) )}.vlist-viewport--custom-scrollbar{scrollbar-width:none;-ms-overflow-style:none}.vlist-viewport--custom-scrollbar::-webkit-scrollbar{display:none}.vlist-viewport--no-scrollbar{scrollbar-width:none;-ms-overflow-style:none}.vlist-viewport--no-scrollbar::-webkit-scrollbar{display:none}.vlist-viewport--gutter-stable{scrollbar-gutter:stable}.vlist-sort-ghost{opacity:0.85;box-shadow:0 4px 16px rgba(0,0,0,0.18);cursor:grabbing}.vlist-item--drag-source{opacity:0 !important;pointer-events:none}.vlist--sorting{cursor:grabbing;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}.vlist--sorting *{cursor:inherit !important}.vlist-item--kb-sorting{outline:2px solid var(--vlist-focus-ring,#3b82f6);outline-offset:-2px;background-color:var(--vlist-bg-selected);z-index:1}
|
|
1
|
+
@keyframes vlist-fade-in{from{opacity:0.6}to{opacity:1}}@keyframes vlist-placeholder-pulse{0%,100%{opacity:0.6}50%{opacity:0.4}}:root{--vlist-scrollbar-width:8px;--vlist-scrollbar-track-color:transparent;--vlist-scrollbar-radius:4px;--vlist-custom-scrollbar-track-color:transparent;--vlist-custom-scrollbar-padding-top:2px;--vlist-custom-scrollbar-padding-right:2px;--vlist-custom-scrollbar-padding-bottom:2px;--vlist-custom-scrollbar-padding-left:2px;--vlist-custom-scrollbar-min-thumb-size:15px;--vlist-item-padding-x:1rem;--vlist-item-padding-y:0.75rem;--vlist-border-radius:0.5rem;--vlist-transition-duration:150ms;--vlist-transition-timing:ease-in-out;--vlist-bg:#ffffff;--vlist-bg-hover:rgba(0,0,0,0.04);--vlist-bg-striped:rgba(0,0,0,0.02);--vlist-bg-selected:rgba(59,130,246,0.12);--vlist-bg-selected-hover:rgba(59,130,246,0.18);--vlist-border:#e5e7eb;--vlist-border-selected:#3b82f6;--vlist-text:#111827;--vlist-text-muted:#6b7280;--vlist-focus-ring:#3b82f6;--vlist-group-header-bg:#f3f4f6;--vlist-scrollbar-thumb-color:#d1d5db;--vlist-scrollbar-thumb-hover-color:#9ca3af;--vlist-custom-scrollbar-thumb-color:rgba(0,0,0,0.2);--vlist-custom-scrollbar-thumb-hover-color:rgba(0,0,0,0.3);--vlist-placeholder-bg:rgba(0,0,0,0.2);--vlist-placeholder-bg-strong:rgba(0,0,0,0.24)}[data-theme-mode="dark"]{--vlist-bg:#111827;--vlist-bg-hover:rgba(255,255,255,0.06);--vlist-bg-striped:rgba(255,255,255,0.02);--vlist-bg-selected:rgba(59,130,246,0.2);--vlist-bg-selected-hover:rgba(59,130,246,0.28);--vlist-border:#374151;--vlist-border-selected:#3b82f6;--vlist-text:#f9fafb;--vlist-text-muted:#9ca3af;--vlist-focus-ring:#3b82f6;--vlist-group-header-bg:#1e2433;--vlist-scrollbar-thumb-color:#4b5563;--vlist-scrollbar-thumb-hover-color:#6b7280;--vlist-custom-scrollbar-thumb-color:rgba(255,255,255,0.2);--vlist-custom-scrollbar-thumb-hover-color:rgba(255,255,255,0.3);--vlist-placeholder-bg:rgba(255,255,255,0.3);--vlist-placeholder-bg-strong:rgba(255,255,255,0.35)}@media (prefers-color-scheme:dark){:root:not([data-theme-mode="light"]):not([data-theme-mode="dark"]){--vlist-bg:#111827;--vlist-bg-hover:rgba(255,255,255,0.06);--vlist-bg-striped:rgba(255,255,255,0.02);--vlist-bg-selected:rgba(59,130,246,0.2);--vlist-bg-selected-hover:rgba(59,130,246,0.28);--vlist-border:#374151;--vlist-border-selected:#3b82f6;--vlist-text:#f9fafb;--vlist-text-muted:#9ca3af;--vlist-focus-ring:#3b82f6;--vlist-group-header-bg:#1e2433;--vlist-scrollbar-thumb-color:#4b5563;--vlist-scrollbar-thumb-hover-color:#6b7280;--vlist-custom-scrollbar-thumb-color:rgba(255,255,255,0.2);--vlist-custom-scrollbar-thumb-hover-color:rgba(255,255,255,0.3);--vlist-placeholder-bg:rgba(255,255,255,0.3);--vlist-placeholder-bg-strong:rgba(255,255,255,0.35)}}.dark{--vlist-bg:#111827;--vlist-bg-hover:rgba(255,255,255,0.06);--vlist-bg-striped:rgba(255,255,255,0.02);--vlist-bg-selected:rgba(59,130,246,0.2);--vlist-bg-selected-hover:rgba(59,130,246,0.28);--vlist-border:#374151;--vlist-border-selected:#3b82f6;--vlist-text:#f9fafb;--vlist-text-muted:#9ca3af;--vlist-focus-ring:#3b82f6;--vlist-group-header-bg:#1e2433;--vlist-scrollbar-thumb-color:#4b5563;--vlist-scrollbar-thumb-hover-color:#6b7280;--vlist-custom-scrollbar-thumb-color:rgba(255,255,255,0.2);--vlist-custom-scrollbar-thumb-hover-color:rgba(255,255,255,0.3);--vlist-placeholder-bg:rgba(255,255,255,0.3);--vlist-placeholder-bg-strong:rgba(255,255,255,0.35)}.vlist{position:relative;width:100%;height:100%;box-sizing:border-box;overflow:hidden;background-color:var(--vlist-bg);color:var(--vlist-text);color-scheme:light;border:1px solid var(--vlist-border);border-radius:var(--vlist-border-radius);outline:none}[data-theme-mode="dark"] .vlist,.dark .vlist{color-scheme:dark}@media (prefers-color-scheme:dark){:root:not([data-theme-mode="light"]) .vlist{color-scheme:dark}}.vlist:focus,.vlist:focus-visible,.vlist-content:focus,.vlist-content:focus-visible{outline:none}.vlist-viewport{width:100%;height:100%;overflow:auto;scrollbar-color:var(--vlist-scrollbar-thumb-color) var(--vlist-scrollbar-track-color)}@supports (-moz-appearance:none) and (scrollbar-width:1px){.vlist-viewport{scrollbar-width:var(--vlist-scrollbar-width)}}.vlist-viewport::-webkit-scrollbar{width:var(--vlist-scrollbar-width);height:var(--vlist-scrollbar-width)}.vlist-viewport::-webkit-scrollbar-track{background:var(--vlist-scrollbar-track-color)}.vlist-viewport::-webkit-scrollbar-thumb{background-color:var(--vlist-scrollbar-thumb-color);border-radius:var(--vlist-scrollbar-radius)}.vlist-viewport::-webkit-scrollbar-thumb:hover{background-color:var(--vlist-scrollbar-thumb-hover-color)}.vlist-content{position:relative;width:100%;contain:layout style}.vlist-item,.vlist-group-header{position:absolute;top:0;left:0;right:0;display:flex;align-items:center;background-color:var(--vlist-bg);cursor:default;user-select:none;opacity:1;transition:background-color var(--vlist-transition-duration) var(--vlist-transition-timing),opacity var(--vlist-transition-duration) var(--vlist-transition-timing);contain:content;box-sizing:border-box;will-change:transform}.vlist--scrolling .vlist-item,.vlist--settling .vlist-item,.vlist--scrolling .vlist-group-header,.vlist--settling .vlist-group-header{transition:none}.vlist--selectable .vlist-item{cursor:pointer}.vlist--selectable .vlist-item:hover{background-color:var(--vlist-bg-hover)}.vlist-item.vlist-item--odd{background:var(--vlist-bg-striped)}.vlist-item.vlist-item--selected{background-color:var(--vlist-bg-selected)}.vlist-item.vlist-item--odd.vlist-item--selected{background:var(--vlist-bg-selected)}.vlist-item.vlist-item--selected:hover{background-color:var(--vlist-bg-selected-hover)}.vlist-item.vlist-item--odd.vlist-item--selected:hover{background:var(--vlist-bg-selected-hover)}.vlist-item.vlist-item--focused{outline:2px solid var(--vlist-focus-ring,#3b82f6);outline-offset:-2px;z-index:1}.vlist-item--replaced{animation:vlist-fade-in 0.3s ease-out}.vlist-item--placeholder{opacity:0.6;animation:vlist-placeholder-pulse 2s ease-in-out infinite}.vlist-item--placeholder *:not(:has(*)){color:transparent;background-color:var(--vlist-placeholder-bg);border-radius:4px;width:fit-content;line-height:1.2;transform:scaleY(0.8)}.vlist-item--placeholder:is(strong,b,h1,h2,h3,h4):not(:has(*)){background-color:var(--vlist-placeholder-bg-strong)}.vlist-item.vlist-item--selected.vlist-item--focused{outline-color:var(--vlist-border-selected)}.vlist-scrollbar:focus-visible{outline:2px solid currentColor;outline-offset:-2px;opacity:1;pointer-events:auto}.vlist-scrollbar{position:absolute;top:var(--vlist-custom-scrollbar-padding-top);right:var(--vlist-custom-scrollbar-padding-right);bottom:var(--vlist-custom-scrollbar-padding-bottom);width:var(--vlist-custom-scrollbar-width);background-color:var(--vlist-custom-scrollbar-track-color);opacity:0;transition:opacity 0.2s ease-out;touch-action:none;z-index:10;pointer-events:none}.vlist-scrollbar__hover{position:absolute;top:0;right:0;height:100%;z-index:9;touch-action:none;pointer-events:auto}.vlist-scrollbar__hover--horizontal{top:auto;right:auto;bottom:0;left:0;width:100%;height:auto}.vlist-scrollbar--visible{opacity:1;pointer-events:auto}.vlist-scrollbar__thumb{position:absolute;top:0;left:0;right:0;width:100%;background-color:var(--vlist-custom-scrollbar-thumb-color);border-radius:var(--vlist-custom-scrollbar-radius);cursor:pointer;transition:background-color 0.15s ease-out}.vlist-scrollbar__thumb:hover{background-color:var(--vlist-custom-scrollbar-thumb-hover-color)}.vlist-scrollbar--dragging{opacity:1;pointer-events:auto}.vlist-scrollbar--dragging .vlist-scrollbar__thumb{background-color:var(--vlist-custom-scrollbar-thumb-hover-color)}@media (forced-colors:active){.vlist-scrollbar{forced-color-adjust:none;background-color:Canvas}.vlist-scrollbar__thumb{background-color:CanvasText}.vlist-scrollbar__thumb:hover,.vlist-scrollbar--dragging .vlist-scrollbar__thumb{background-color:Highlight}.vlist-scrollbar:focus-visible{outline-color:Highlight}}.vlist-group-header{cursor:default;background-color:var(--vlist-group-header-bg,#f3f4f6);z-index:1;overflow:hidden}.vlist-group-header:hover{background-color:var(--vlist-group-header-bg,#f3f4f6)}.vlist-sticky-header{left:0;right:0;background-color:var(--vlist-group-header-bg,#f3f4f6)}.vlist--horizontal{overflow:hidden}.vlist--horizontal .vlist-viewport{overflow-x:auto;overflow-y:hidden}.vlist--horizontal .vlist-content{height:100%;width:auto}.vlist--horizontal .vlist-item,.vlist--horizontal .vlist-group-header{position:absolute;top:0;bottom:0;left:0;right:auto;display:flex;align-items:center;justify-content:center;border-bottom:none}.vlist-scrollbar--horizontal{top:auto;left:var(--vlist-custom-scrollbar-padding-left);right:var(--vlist-custom-scrollbar-padding-right);bottom:var(--vlist-custom-scrollbar-padding-bottom);width:auto;height:var(--vlist-custom-scrollbar-width)}.vlist-scrollbar--horizontal .vlist-scrollbar__thumb{top:0;left:0;width:auto;height:100%}.vlist-viewport--gutter{padding-right:calc( var(--vlist-custom-scrollbar-padding-right) + var(--vlist-custom-scrollbar-width) + var(--vlist-custom-scrollbar-padding-left) )}.vlist--horizontal .vlist-viewport--gutter{padding-right:0;padding-bottom:calc( var(--vlist-custom-scrollbar-padding-bottom) + var(--vlist-custom-scrollbar-width) + var(--vlist-custom-scrollbar-padding-top) )}.vlist-viewport--custom-scrollbar{scrollbar-width:none;-ms-overflow-style:none}.vlist-viewport--custom-scrollbar::-webkit-scrollbar{display:none}.vlist-viewport--no-scrollbar{scrollbar-width:none;-ms-overflow-style:none}.vlist-viewport--no-scrollbar::-webkit-scrollbar{display:none}.vlist-viewport--gutter-stable{scrollbar-gutter:stable}.vlist-sort-ghost{opacity:0.85;box-shadow:0 4px 16px rgba(0,0,0,0.18);cursor:grabbing}.vlist-item--touch-sort{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}.vlist-sort-ghost--touch{outline:2px solid var(--vlist-focus-ring,#3b82f6);outline-offset:2px}.vlist-item--drag-source{opacity:0 !important;pointer-events:none}.vlist--sorting{cursor:grabbing;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}.vlist--sorting *{cursor:inherit !important}.vlist-item--kb-sorting{outline:2px solid var(--vlist-focus-ring,#3b82f6);outline-offset:-2px;background-color:var(--vlist-bg-selected);z-index:1}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vlist",
|
|
3
|
-
"version": "3.0.0-next.
|
|
3
|
+
"version": "3.0.0-next.3",
|
|
4
4
|
"description": "Lightweight, high-performance virtual list with zero dependencies",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Floor IO",
|
|
@@ -79,12 +79,15 @@
|
|
|
79
79
|
"dev": "bun run build.ts --watch",
|
|
80
80
|
"test": "bun test",
|
|
81
81
|
"test:changed": "bun test --changed",
|
|
82
|
-
"
|
|
82
|
+
"test:browser": "bun scripts/rtl-cross-axis-browser.mjs && bun scripts/synthetic-browser.mjs && bun scripts/synthetic-carousel-browser.mjs && bun scripts/synthetic-sortable-browser.mjs",
|
|
83
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.types.json && tsc --noEmit -p tsconfig.test.json",
|
|
83
84
|
"bench": "bun run scripts/bench.ts",
|
|
84
85
|
"bench:quick": "bun run scripts/bench.ts --quick",
|
|
85
86
|
"bench:full": "bun run scripts/bench.ts --full",
|
|
86
87
|
"bench:compare": "bun run scripts/bench.ts --quick --compare",
|
|
87
88
|
"size": "bun run scripts/size.ts",
|
|
89
|
+
"heap": "bun run scripts/heap.ts",
|
|
90
|
+
"docs:check": "bun run scripts/docs-check.ts",
|
|
88
91
|
"release": "bun run scripts/release.ts",
|
|
89
92
|
"prepublishOnly": "bun run build -- --types && cp README.md README.github.md && cp npm-readme.md README.md",
|
|
90
93
|
"postpublish": "cp README.github.md README.md && rm README.github.md"
|
|
@@ -99,6 +102,7 @@
|
|
|
99
102
|
"@types/jsdom": "^27.0.0",
|
|
100
103
|
"happy-dom": "^20.9.0",
|
|
101
104
|
"jsdom": "^28.0.0",
|
|
105
|
+
"puppeteer-core": "^24.43.1",
|
|
102
106
|
"typescript": "^5.0.0"
|
|
103
107
|
}
|
|
104
108
|
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* vlist - Grid Renderer
|
|
3
|
-
* Renders items in a 2D grid layout within the virtual scroll container.
|
|
4
|
-
*
|
|
5
|
-
* Extends the base renderer pattern but positions items using both
|
|
6
|
-
* row offsets (translateY from the size cache) and column offsets
|
|
7
|
-
* (translateX calculated from column index and container width).
|
|
8
|
-
*
|
|
9
|
-
* Key differences from the list renderer:
|
|
10
|
-
* - Items are positioned with translate(x, y) instead of just translateY(y)
|
|
11
|
-
* - Item width is set to columnWidth (containerWidth / columns - gaps)
|
|
12
|
-
* - The "index" in the rendered map is the FLAT ITEM INDEX (not row index)
|
|
13
|
-
* - Row offsets come from the size cache (which operates on row indices)
|
|
14
|
-
* - Column offsets are calculated from itemIndex % columns
|
|
15
|
-
*
|
|
16
|
-
* Performance:
|
|
17
|
-
* - Element pooling avoids createElement cost
|
|
18
|
-
* - Template re-evaluation skipped when item data + state unchanged (change tracking)
|
|
19
|
-
* - Position update skipped when coordinates unchanged (position tracking)
|
|
20
|
-
* - O(1) Set-based visibility diffing (not O(n) .some())
|
|
21
|
-
* - Release grace period prevents boundary thrashing (hover blink, transition replay)
|
|
22
|
-
* - Released elements removed from DOM immediately
|
|
23
|
-
* - DocumentFragment batched insertion for new elements
|
|
24
|
-
*/
|
|
25
|
-
import type { VListItem, ItemTemplate, Range } from "../../types";
|
|
26
|
-
import type { SizeCache } from "../../rendering/sizes";
|
|
27
|
-
import type { GridLayout } from "./types";
|
|
28
|
-
/** Grid renderer instance */
|
|
29
|
-
export interface GridRenderer<T extends VListItem = VListItem> {
|
|
30
|
-
/** Render items for a flat item range, positioned in a 2D grid */
|
|
31
|
-
render: (items: T[], range: Range, selectedIds: Set<string | number>, focusedIndex: number) => void;
|
|
32
|
-
/** Update a single item (used by selection feature for focused item changes) */
|
|
33
|
-
updateItem: (index: number, item: T, isSelected: boolean, isFocused: boolean) => void;
|
|
34
|
-
/** Update only CSS classes on a rendered item (no template re-evaluation) */
|
|
35
|
-
updateItemClasses: (index: number, isSelected: boolean, isFocused: boolean) => void;
|
|
36
|
-
/** Get rendered item element by flat item index */
|
|
37
|
-
getElement: (index: number) => HTMLElement | undefined;
|
|
38
|
-
/**
|
|
39
|
-
* Reorder DOM children to match logical item order (by data-index).
|
|
40
|
-
* Called on scroll idle so screen readers encounter items in the correct
|
|
41
|
-
* sequence. Items are position:absolute so visual layout is unaffected.
|
|
42
|
-
*/
|
|
43
|
-
sortDOM: () => void;
|
|
44
|
-
/** Update container width (call on resize) */
|
|
45
|
-
updateContainerWidth: (width: number) => void;
|
|
46
|
-
/** Clear all rendered items */
|
|
47
|
-
clear: () => void;
|
|
48
|
-
/** Destroy renderer and cleanup */
|
|
49
|
-
destroy: () => void;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Create a grid renderer for managing DOM elements in a 2D layout.
|
|
53
|
-
*
|
|
54
|
-
* The grid renderer receives flat item ranges (not row ranges) and
|
|
55
|
-
* positions each item at the correct (row, col) coordinate.
|
|
56
|
-
*
|
|
57
|
-
* @param itemsContainer - The DOM element that holds rendered items
|
|
58
|
-
* @param template - Item template function
|
|
59
|
-
* @param sizeCache - Size cache operating on ROW indices
|
|
60
|
-
* @param gridLayout - Grid layout for row/col calculations
|
|
61
|
-
* @param classPrefix - CSS class prefix
|
|
62
|
-
* @param initialContainerWidth - Initial container width for column sizing
|
|
63
|
-
* @param totalItemsGetter - Optional getter for total item count (for aria-setsize)
|
|
64
|
-
* @param ariaIdPrefix - Optional unique prefix for element IDs (for aria-activedescendant)
|
|
65
|
-
* @param isHorizontal - Whether layout is horizontal (scrolls right)
|
|
66
|
-
*/
|
|
67
|
-
export declare const createGridRenderer: <T extends VListItem = VListItem>(itemsContainer: HTMLElement, template: ItemTemplate<T>, sizeCache: SizeCache, gridLayout: GridLayout, classPrefix: string, initialContainerWidth: number, totalItemsGetter?: () => number, ariaIdPrefix?: string, isHorizontal?: boolean, ariaPosInSetGetter?: (layoutIndex: number) => number, interactive?: boolean) => GridRenderer<T>;
|
|
68
|
-
//# sourceMappingURL=renderer.d.ts.map
|