vlist 3.0.0 → 3.0.1-next.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.github.md +25 -25
- package/README.md +25 -25
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/constants.d.ts +0 -16
- package/dist/core/adapter.d.ts +3 -3
- package/dist/core/create.d.ts +10 -5
- package/dist/core/fold.d.ts +3 -3
- package/dist/core/logical.d.ts +93 -0
- package/dist/core/runway.d.ts +20 -106
- package/dist/core/state.d.ts +2 -2
- package/dist/core/types.d.ts +4 -2
- package/dist/index.js +1 -1
- package/dist/internals.js +1 -1
- package/dist/plugins/carousel/plugin.d.ts +2 -3
- package/dist/size.json +1 -1
- package/dist/synthetic/driver.d.ts +26 -0
- package/dist/synthetic/handler.d.ts +4 -4
- package/dist/synthetic-driver.js +1 -0
- package/dist/synthetic.d.ts +7 -0
- package/dist/synthetic.js +1 -1
- package/dist/types.d.ts +22 -3
- package/dist/version.json +1 -0
- package/package.json +3 -2
package/dist/core/adapter.d.ts
CHANGED
|
@@ -90,9 +90,9 @@ export declare function normalizeLogical(sizeCache: SizeCache, pos: LogicalScrol
|
|
|
90
90
|
/**
|
|
91
91
|
* Create a {@link ScrollAdapter} over an existing pixel-based scroll source.
|
|
92
92
|
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
93
|
+
* The source behind `getPixel` / `setPixel` is the native viewport scroll or a
|
|
94
|
+
* logical handler (synthetic input, carousel runway); plugins that use the
|
|
95
|
+
* adapter do not change with it.
|
|
96
96
|
*/
|
|
97
97
|
export declare function createScrollAdapter(config: ScrollAdapterConfig): ScrollAdapter;
|
|
98
98
|
//# sourceMappingURL=adapter.d.ts.map
|
package/dist/core/create.d.ts
CHANGED
|
@@ -7,12 +7,17 @@
|
|
|
7
7
|
import type { VListItem } from "../types";
|
|
8
8
|
import type { CreateVListConfig, PluginMethods, VListPlugin, VList } from "./types";
|
|
9
9
|
import type { SizeCache } from "./sizes";
|
|
10
|
-
import type {
|
|
10
|
+
import type { LogicalScrollHandler, LogicalScrollConfig } from "./logical";
|
|
11
11
|
import type { ScrollHandler, ScrollHandlerConfig } from "./scroll";
|
|
12
12
|
import { type Emitter } from "../events";
|
|
13
13
|
import type { VListEvents } from "../types";
|
|
14
|
+
type SyntheticFactory = (config: LogicalScrollConfig & {
|
|
15
|
+
sizeCache: SizeCache;
|
|
16
|
+
}) => LogicalScrollHandler;
|
|
17
|
+
type SyntheticDriver = typeof import("../synthetic/driver");
|
|
14
18
|
/**
|
|
15
|
-
* Create a list
|
|
19
|
+
* Create a list. `scroll.mode` chooses who owns input: `"auto"` (default)
|
|
20
|
+
* scrolls natively and goes synthetic past the browser's size limit.
|
|
16
21
|
*
|
|
17
22
|
* Let the item type be inferred from the config — its `items`, or the
|
|
18
23
|
* `template` parameter — rather than passing it as a type argument. The list's
|
|
@@ -34,12 +39,12 @@ export declare function createVList<T extends VListItem = VListItem, const P ext
|
|
|
34
39
|
/** @internal Shared factory; entries select the input handler. */
|
|
35
40
|
export declare function createCore<T extends VListItem = VListItem>(rawConfig: CreateVListConfig<T>, plugins?: VListPlugin<T>[],
|
|
36
41
|
/** @internal Omitted by the native entry. */
|
|
37
|
-
logicalHandlerFactory?:
|
|
38
|
-
sizeCache: SizeCache;
|
|
39
|
-
}) => BoundedScrollHandler, nativeOptions?: {
|
|
42
|
+
logicalHandlerFactory?: SyntheticFactory, nativeOptions?: {
|
|
40
43
|
native: (config: ScrollHandlerConfig) => ScrollHandler & {
|
|
41
44
|
commitScroll(pos?: number): void;
|
|
42
45
|
};
|
|
46
|
+
load: () => Promise<SyntheticDriver>;
|
|
43
47
|
onContentSize: (size: number, emitter: Emitter<VListEvents<T>>) => void;
|
|
44
48
|
}): VList<T>;
|
|
49
|
+
export {};
|
|
45
50
|
//# sourceMappingURL=create.d.ts.map
|
package/dist/core/fold.d.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* positions are unchanged. Re-keying the map (and the `id` that encodes the
|
|
6
6
|
* virtual index) lets the next commit find them instead of releasing,
|
|
7
7
|
* re-templating and re-inserting the viewport. Lives here — not in pipeline
|
|
8
|
-
* or create — so a native list that never wraps does not import it (
|
|
9
|
-
*
|
|
8
|
+
* or create — so a native list that never wraps does not import it (the
|
|
9
|
+
* carousel runway pulls it). The synthetic handler imports it because wrap
|
|
10
10
|
* folds for that entry go through commit(), not wrapRebase; putting the
|
|
11
11
|
* import in create.ts would charge every native list.
|
|
12
12
|
*
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* `focusedIndex` (data space under `indexMap`), snapshots (`dataIndex`).
|
|
19
19
|
*/
|
|
20
20
|
import type { EngineState } from "./state";
|
|
21
|
-
import type { WrapConfig } from "./
|
|
21
|
+
import type { WrapConfig } from "./logical";
|
|
22
22
|
/**
|
|
23
23
|
* Move every `rendered` key by `-indexShift` without touching the DOM tree.
|
|
24
24
|
* `data-index` / `aria-posinset` carry the public index and stay put.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* vlist — logical scroll handlers (RFC-012)
|
|
3
|
+
*
|
|
4
|
+
* A handler that owns the logical position itself, instead of reading it from
|
|
5
|
+
* a native scroll offset: the synthetic driver (`scroll.mode`, RFC-014/015) and
|
|
6
|
+
* the carousel's wrap runway. Both render through `state.baseOffset`: items are
|
|
7
|
+
* placed at `getOffset(index) - baseOffset`, so the content element never has
|
|
8
|
+
* to be as large as the list.
|
|
9
|
+
*/
|
|
10
|
+
import type { SizeCache } from "./sizes";
|
|
11
|
+
import type { EngineState } from "./state";
|
|
12
|
+
import type { ScrollHandler } from "./scroll";
|
|
13
|
+
export interface LogicalScrollHandler extends ScrollHandler {
|
|
14
|
+
/** Move to an absolute logical (virtual pixel) position; renders + schedules idle. */
|
|
15
|
+
setLogical(logicalPx: number): void;
|
|
16
|
+
/** Current absolute logical position (== state.scrollPosition). */
|
|
17
|
+
getLogical(): number;
|
|
18
|
+
/** Non-cancelling coordinate correction, when supported by the input provider. */
|
|
19
|
+
shiftBy?(delta: number): void;
|
|
20
|
+
/** Maximum scrollable logical position (`virtualTotal - containerSize`, >= 0). */
|
|
21
|
+
getMaxLogical(): number;
|
|
22
|
+
/** Recompute derived geometry from the total size and resize the content element. */
|
|
23
|
+
refresh(totalSize: number): void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Infinite-loop (wrap) configuration for a logical handler (carousel, RFC-011).
|
|
27
|
+
*
|
|
28
|
+
* In wrap mode the logical position is never clamped to a maximum: instead it is
|
|
29
|
+
* periodically folded back toward {@link home} by whole laps once it drifts more
|
|
30
|
+
* than {@link thresholdLaps} laps away. Because the consumer maps virtual indices
|
|
31
|
+
* to real items via `index % realTotal`, shifting the logical position (and
|
|
32
|
+
* baseOffset) by a whole lap leaves the rendered items and their on-screen
|
|
33
|
+
* positions unchanged — the loop is seamless. The content element stays a few
|
|
34
|
+
* viewports long, so large item counts never blow the browser's element-size
|
|
35
|
+
* limit.
|
|
36
|
+
*/
|
|
37
|
+
export interface WrapConfig {
|
|
38
|
+
/** Current lap period in virtual px (`realTotal × stepSize`). */
|
|
39
|
+
readonly lapSize: () => number;
|
|
40
|
+
/**
|
|
41
|
+
* Real items in one lap (e.g. the carousel's `realTotal`). The wrap handler
|
|
42
|
+
* uses this to re-key mounted elements on a fold so the same DOM nodes
|
|
43
|
+
* survive the virtual-index shift — only the key changed; paint did not.
|
|
44
|
+
*/
|
|
45
|
+
readonly itemsPerLap: () => number;
|
|
46
|
+
/** Logical position to fold back toward (the home lap). */
|
|
47
|
+
readonly home: () => number;
|
|
48
|
+
/** Fold the logical position back toward `home` once it drifts this many laps away. */
|
|
49
|
+
readonly thresholdLaps: number;
|
|
50
|
+
/** @internal Notify the wrap owner when its logical coordinates fold. */
|
|
51
|
+
readonly onFold?: (shift: number) => void;
|
|
52
|
+
}
|
|
53
|
+
export interface LogicalScrollConfig {
|
|
54
|
+
/** Logical row geometry for opt-in input providers (keyboard row steps). */
|
|
55
|
+
readonly sizeCache?: Pick<SizeCache, "getSize" | "indexAtOffset" | "getTotalSize">;
|
|
56
|
+
readonly state: EngineState;
|
|
57
|
+
readonly viewport: HTMLElement;
|
|
58
|
+
readonly content: HTMLElement;
|
|
59
|
+
readonly isX: boolean;
|
|
60
|
+
readonly wheelEnabled: boolean;
|
|
61
|
+
readonly idleTimeout: number;
|
|
62
|
+
readonly scrollTarget?: EventTarget;
|
|
63
|
+
/** Main-axis padding folded into the virtual total (matches native content sizing). */
|
|
64
|
+
readonly mainAxisPadding: number;
|
|
65
|
+
/** Runway size as a multiple of the viewport (defaults to RUNWAY_FACTOR). */
|
|
66
|
+
readonly runwayFactor?: number;
|
|
67
|
+
/** Infinite-loop config (carousel). When set, the logical position wraps by
|
|
68
|
+
* whole laps toward `home` instead of clamping to a maximum. */
|
|
69
|
+
readonly wrap?: WrapConfig;
|
|
70
|
+
/**
|
|
71
|
+
* Mounted row map. A wrap fold re-keys it in place so phase 2 finds the
|
|
72
|
+
* same nodes; omitted when the handler is constructed without a viewport.
|
|
73
|
+
*/
|
|
74
|
+
readonly rendered?: Map<number, HTMLElement>;
|
|
75
|
+
/**
|
|
76
|
+
* Class prefix for rewriting `id` / `aria-activedescendant` on a wrap fold.
|
|
77
|
+
* Passed explicitly — a prefix containing `-content` cannot be recovered
|
|
78
|
+
* from the content element's class name.
|
|
79
|
+
*/
|
|
80
|
+
readonly classPrefix?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Stripe class (`{prefix}-item--odd`). Re-toggled on a wrap fold when
|
|
83
|
+
* `indexShift` is odd, so virtual-index parity survives the re-key.
|
|
84
|
+
*/
|
|
85
|
+
readonly oddClass?: string;
|
|
86
|
+
/** @internal Coordinate fold: shift core telemetry references before rendering. */
|
|
87
|
+
readonly onFold?: (shift: number) => void;
|
|
88
|
+
/** Called synchronously per frame — triggers the 2-phase pipeline. */
|
|
89
|
+
readonly onFrame: () => void;
|
|
90
|
+
/** Called when scrolling becomes idle. */
|
|
91
|
+
readonly onIdle: () => void;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=logical.d.ts.map
|
package/dist/core/runway.d.ts
CHANGED
|
@@ -1,113 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* vlist —
|
|
2
|
+
* vlist — carousel runway (RFC-011, RFC-012)
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* The carousel's infinite loop scrolls a native element that is only a few
|
|
5
|
+
* viewports long: the *runway*. The logical position is `baseOffset +
|
|
6
|
+
* scrollTop`; as scrollTop nears an edge of the runway, baseOffset and
|
|
7
|
+
* scrollTop shift together by the same delta, so the logical position and
|
|
8
|
+
* what is on screen stay put. The scroll event that shift triggers reads the
|
|
9
|
+
* same logical position and is dropped by the "logical unchanged" guard. In
|
|
10
|
+
* wrap mode the position also folds back by whole laps toward home.
|
|
6
11
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* This sidesteps the browser's ~16.7M px element-size limit without compressing
|
|
10
|
-
* the coordinate space — no compression ratio leaks into offsets or hit-testing.
|
|
11
|
-
*
|
|
12
|
-
* Coordinates:
|
|
13
|
-
* logical = baseOffset + scrollTop (absolute virtual pixel position)
|
|
14
|
-
*
|
|
15
|
-
* - `state.scrollPosition` always holds the *logical* (absolute) position, so
|
|
16
|
-
* the render pipeline's `indexAtOffset(scrollPosition)` keeps working over
|
|
17
|
-
* the full size cache, and the public pixel-equivalent surface is unchanged.
|
|
18
|
-
* - `state.baseOffset` is the virtual offset that maps to native scrollTop=0.
|
|
19
|
-
* The pipeline renders each item at `getOffset(index) - baseOffset`, so items
|
|
20
|
-
* land inside the bounded runway. baseOffset is 0 for small lists (native).
|
|
21
|
-
*
|
|
22
|
-
* Rebasing: as native scrollTop approaches a runway edge we shift baseOffset and
|
|
23
|
-
* scrollTop together by the same delta, preserving `logical`. The synthetic
|
|
24
|
-
* scroll event this triggers reads the same logical position and is dropped by
|
|
25
|
-
* the "logical unchanged" guard — no suppress flag needed. The repositioning of
|
|
26
|
-
* items (their transforms depend on baseOffset) is committed by the explicit
|
|
27
|
-
* render that the rebasing scroll frame performs.
|
|
12
|
+
* Engine code (it owns the scroll coordinates), but only `carousel()` imports
|
|
13
|
+
* it: a list without it never bundles it.
|
|
28
14
|
*/
|
|
29
|
-
import type {
|
|
30
|
-
import type { EngineState } from "./state";
|
|
31
|
-
import type { ScrollHandler } from "./scroll";
|
|
32
|
-
export interface BoundedScrollHandler extends ScrollHandler {
|
|
33
|
-
/** Move to an absolute logical (virtual pixel) position; renders + schedules idle. */
|
|
34
|
-
setLogical(logicalPx: number): void;
|
|
35
|
-
/** Current absolute logical position (== state.scrollPosition). */
|
|
36
|
-
getLogical(): number;
|
|
37
|
-
/** Non-cancelling coordinate correction, when supported by the input provider. */
|
|
38
|
-
shiftBy?(delta: number): void;
|
|
39
|
-
/** Maximum scrollable logical position (`virtualTotal - containerSize`, >= 0). */
|
|
40
|
-
getMaxLogical(): number;
|
|
41
|
-
/** Recompute runway/derived values and resize the content element. */
|
|
42
|
-
refresh(totalSize: number): void;
|
|
43
|
-
}
|
|
15
|
+
import type { LogicalScrollConfig, LogicalScrollHandler } from "./logical";
|
|
44
16
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* periodically folded back toward {@link home} by whole laps once it drifts more
|
|
49
|
-
* than {@link thresholdLaps} laps away. Because the consumer maps virtual indices
|
|
50
|
-
* to real items via `index % realTotal`, shifting the logical position (and
|
|
51
|
-
* baseOffset) by a whole lap leaves the rendered items and their on-screen
|
|
52
|
-
* positions unchanged — the loop is seamless. The content element is sized to the
|
|
53
|
-
* runway exactly as in non-wrap mode, so large item counts never blow the
|
|
54
|
-
* browser's element-size limit.
|
|
17
|
+
* Runway size as a multiple of the viewport: the content element is
|
|
18
|
+
* `containerSize × this` (capped at the total size), which gives the native
|
|
19
|
+
* scrollbar room to move before a rebase shifts the logical origin.
|
|
55
20
|
*/
|
|
56
|
-
export
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
* survive the virtual-index shift — only the key changed; paint did not.
|
|
63
|
-
*/
|
|
64
|
-
readonly itemsPerLap: () => number;
|
|
65
|
-
/** Logical position to fold back toward (the home lap). */
|
|
66
|
-
readonly home: () => number;
|
|
67
|
-
/** Fold the logical position back toward `home` once it drifts this many laps away. */
|
|
68
|
-
readonly thresholdLaps: number;
|
|
69
|
-
/** @internal Notify the wrap owner when its logical coordinates fold. */
|
|
70
|
-
readonly onFold?: (shift: number) => void;
|
|
71
|
-
}
|
|
72
|
-
export interface BoundedScrollConfig {
|
|
73
|
-
/** Logical row geometry for opt-in input providers (keyboard row steps). */
|
|
74
|
-
readonly sizeCache?: Pick<SizeCache, "getSize" | "indexAtOffset" | "getTotalSize">;
|
|
75
|
-
readonly state: EngineState;
|
|
76
|
-
readonly viewport: HTMLElement;
|
|
77
|
-
readonly content: HTMLElement;
|
|
78
|
-
readonly isX: boolean;
|
|
79
|
-
readonly wheelEnabled: boolean;
|
|
80
|
-
readonly idleTimeout: number;
|
|
81
|
-
readonly scrollTarget?: EventTarget;
|
|
82
|
-
/** Main-axis padding folded into the virtual total (matches native content sizing). */
|
|
83
|
-
readonly mainAxisPadding: number;
|
|
84
|
-
/** Runway size as a multiple of the viewport (defaults to BOUNDED_RUNWAY_FACTOR). */
|
|
85
|
-
readonly runwayFactor?: number;
|
|
86
|
-
/** Infinite-loop config (carousel). When set, the logical position wraps by
|
|
87
|
-
* whole laps toward `home` instead of clamping to a maximum. */
|
|
88
|
-
readonly wrap?: WrapConfig;
|
|
89
|
-
/**
|
|
90
|
-
* Mounted row map. A wrap fold re-keys it in place so phase 2 finds the
|
|
91
|
-
* same nodes; omitted when the handler is constructed without a viewport.
|
|
92
|
-
*/
|
|
93
|
-
readonly rendered?: Map<number, HTMLElement>;
|
|
94
|
-
/**
|
|
95
|
-
* Class prefix for rewriting `id` / `aria-activedescendant` on a wrap fold.
|
|
96
|
-
* Passed explicitly — a prefix containing `-content` cannot be recovered
|
|
97
|
-
* from the content element's class name.
|
|
98
|
-
*/
|
|
99
|
-
readonly classPrefix?: string;
|
|
100
|
-
/**
|
|
101
|
-
* Stripe class (`{prefix}-item--odd`). Re-toggled on a wrap fold when
|
|
102
|
-
* `indexShift` is odd, so virtual-index parity survives the re-key.
|
|
103
|
-
*/
|
|
104
|
-
readonly oddClass?: string;
|
|
105
|
-
/** @internal Coordinate fold: shift core telemetry references before rendering. */
|
|
106
|
-
readonly onFold?: (shift: number) => void;
|
|
107
|
-
/** Called synchronously per frame — triggers the 2-phase pipeline. */
|
|
108
|
-
readonly onFrame: () => void;
|
|
109
|
-
/** Called when scrolling becomes idle. */
|
|
110
|
-
readonly onIdle: () => void;
|
|
111
|
-
}
|
|
112
|
-
export declare function createBoundedScrollHandler(config: BoundedScrollConfig): BoundedScrollHandler;
|
|
21
|
+
export declare const RUNWAY_FACTOR = 2;
|
|
22
|
+
/** Rebase back when scrollTop drops below this fraction of the runway (away from the logical start). */
|
|
23
|
+
export declare const RUNWAY_REBASE_LOW = 0.25;
|
|
24
|
+
/** Rebase forward when scrollTop rises above this fraction of the runway (away from the logical end). */
|
|
25
|
+
export declare const RUNWAY_REBASE_HIGH = 0.75;
|
|
26
|
+
export declare function createRunwayHandler(config: LogicalScrollConfig): LogicalScrollHandler;
|
|
113
27
|
//# sourceMappingURL=runway.d.ts.map
|
package/dist/core/state.d.ts
CHANGED
|
@@ -25,8 +25,8 @@ export interface EngineState {
|
|
|
25
25
|
/** 1 = forward, -1 = backward, 0 = idle */
|
|
26
26
|
scrollDirection: number;
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
* Logical-scroll origin (RFC-012): the virtual offset at the content
|
|
29
|
+
* element's start, moved by a logical handler (synthetic input, carousel runway). Items render at `getOffset(index) - baseOffset`.
|
|
30
30
|
* Defaults to 0, which makes native mode byte-identical (`offset - 0`).
|
|
31
31
|
*/
|
|
32
32
|
baseOffset: number;
|
package/dist/core/types.d.ts
CHANGED
|
@@ -90,8 +90,10 @@ export interface ScrollCapability extends ScrollAdapter {
|
|
|
90
90
|
onContentSize?(px: number): void;
|
|
91
91
|
}): void;
|
|
92
92
|
setTarget(target: EventTarget): void;
|
|
93
|
-
/** Request
|
|
94
|
-
|
|
93
|
+
/** Request a logical handler in infinite-loop (wrap) mode, built by `createHandler` (carousel). */
|
|
94
|
+
setWrap(config: import("./logical").WrapConfig, createHandler: (config: import("./logical").LogicalScrollConfig) => import("./logical").LogicalScrollHandler): void;
|
|
95
|
+
/** @deprecated Renamed `setWrap` in 3.0.x; kept for 3.0 plugins. */
|
|
96
|
+
setBoundedWrap(config: import("./logical").WrapConfig, createHandler: (config: import("./logical").LogicalScrollConfig) => import("./logical").LogicalScrollHandler): void;
|
|
95
97
|
setToPosFn(fn: (index: number, sizeCache: import("./sizes").SizeCache, containerSize: number, totalItems: number, align: string) => number): void;
|
|
96
98
|
setToIndexFn(fn: (index: number, align: string, behavior?: string, duration?: number, easing?: (t: number) => number) => void | false): void;
|
|
97
99
|
onFrame(): void;
|