@lightningtv/solid 2.10.5 → 2.10.7
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/dist/src/primitives/Column.jsx +4 -2
- package/dist/src/primitives/Column.jsx.map +1 -1
- package/dist/src/primitives/Row.jsx +4 -2
- package/dist/src/primitives/Row.jsx.map +1 -1
- package/dist/src/primitives/Virtual.d.ts +3 -2
- package/dist/src/primitives/Virtual.jsx +333 -130
- package/dist/src/primitives/Virtual.jsx.map +1 -1
- package/dist/src/primitives/utils/handleNavigation.d.ts +0 -1
- package/dist/src/primitives/utils/handleNavigation.js +1 -2
- package/dist/src/primitives/utils/handleNavigation.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/primitives/Column.tsx +6 -3
- package/src/primitives/Row.tsx +7 -3
- package/src/primitives/Virtual.tsx +337 -132
- package/src/primitives/utils/handleNavigation.ts +1 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { combineStyles } from '@lightningtv/solid';
|
|
2
|
-
import { navigableForwardFocus,
|
|
2
|
+
import { navigableForwardFocus, handleNavigation } from './utils/handleNavigation.js';
|
|
3
3
|
import { scrollColumn } from './utils/withScrolling.js';
|
|
4
4
|
import { chainFunctions } from './utils/chainFunctions.js';
|
|
5
5
|
const ColumnStyles = {
|
|
@@ -18,8 +18,10 @@ function scrollToIndex(index) {
|
|
|
18
18
|
scrollColumn(index, this);
|
|
19
19
|
this.children[index]?.setFocus();
|
|
20
20
|
}
|
|
21
|
+
const onUp = handleNavigation('up');
|
|
22
|
+
const onDown = handleNavigation('down');
|
|
21
23
|
export const Column = (props) => {
|
|
22
|
-
return (<view {...props} onUp={/* @once */chainFunctions(props.onUp,
|
|
24
|
+
return (<view {...props} onUp={/* @once */chainFunctions(props.onUp, onUp)} onDown={/* @once */chainFunctions(props.onDown, onDown)} selected={props.selected || 0} scrollToIndex={scrollToIndex} forwardFocus={navigableForwardFocus} onLayout={
|
|
23
25
|
/* @once */
|
|
24
26
|
props.selected ? chainFunctions(props.onLayout, scrollColumn) : props.onLayout} onSelectedChanged={
|
|
25
27
|
/* @once */ chainFunctions(props.onSelectedChanged, props.scroll !== 'none' ? scrollColumn : undefined)} style={/* @once */combineStyles(props.style, ColumnStyles)}/>);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Column.jsx","sourceRoot":"","sources":["../../../src/primitives/Column.tsx"],"names":[],"mappings":"AACA,OAAO,EAAe,aAAa,EAAmB,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACL,qBAAqB,EAAE,
|
|
1
|
+
{"version":3,"file":"Column.jsx","sourceRoot":"","sources":["../../../src/primitives/Column.tsx"],"names":[],"mappings":"AACA,OAAO,EAAe,aAAa,EAAmB,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACL,qBAAqB,EAAE,gBAAgB,EACxC,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAG3D,MAAM,YAAY,GAAe;IAC/B,OAAO,EAAE,MAAM;IACf,aAAa,EAAE,QAAQ;IACvB,GAAG,EAAE,EAAE;IACP,UAAU,EAAE;QACV,CAAC,EAAE;YACD,QAAQ,EAAE,GAAG;YACb,MAAM,EAAE,aAAa;SACtB;KACF;CACF,CAAC;AAEF,SAAS,aAAa,CAAoB,KAAa;IACrD,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;IACtB,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;AACpC,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;AAExC,MAAM,CAAC,MAAM,MAAM,GAA2B,CAAC,KAAK,EAAE,EAAE;IACtD,OAAO,CACL,CAAC,IAAI,CACH,IAAI,KAAK,CAAC,CACV,IAAI,CAAC,CAAC,WAAY,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CACnD,MAAM,CAAC,CAAC,WAAY,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CACzD,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC,CAC9B,aAAa,CAAC,CAAC,aAAa,CAAC,CAC7B,YAAY,CAAC,CAAC,qBAAqB,CAAC,CACpC,QAAQ,CAAC,CAAC;QACR,WAAW;QACX,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QACxE,CAAC,CACD,iBAAiB,CAAC,CAAC;QACjB,WAAW,CAAC,cAAc,CACxB,KAAK,CAAC,iBAAiB,EACvB,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAEtD,CAAC,CACD,KAAK,CAAC,CAAC,WAAY,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,EAC5D,CACH,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { combineStyles } from '@lightningtv/solid';
|
|
2
2
|
import { chainFunctions } from './utils/chainFunctions.js';
|
|
3
|
-
import {
|
|
3
|
+
import { handleNavigation, navigableForwardFocus } from './utils/handleNavigation.js';
|
|
4
4
|
import { scrollRow } from './utils/withScrolling.js';
|
|
5
5
|
const RowStyles = {
|
|
6
6
|
display: 'flex',
|
|
@@ -17,8 +17,10 @@ function scrollToIndex(index) {
|
|
|
17
17
|
scrollRow(index, this);
|
|
18
18
|
this.children[index]?.setFocus();
|
|
19
19
|
}
|
|
20
|
+
const onLeft = handleNavigation('left');
|
|
21
|
+
const onRight = handleNavigation('right');
|
|
20
22
|
export const Row = (props) => {
|
|
21
|
-
return (<view {...props} selected={props.selected || 0} onLeft={/* @once */chainFunctions(props.onLeft,
|
|
23
|
+
return (<view {...props} selected={props.selected || 0} onLeft={/* @once */chainFunctions(props.onLeft, onLeft)} onRight={/* @once */chainFunctions(props.onRight, onRight)} forwardFocus={navigableForwardFocus} scrollToIndex={scrollToIndex} onLayout={
|
|
22
24
|
/* @once */
|
|
23
25
|
props.selected ? chainFunctions(props.onLayout, scrollRow) : props.onLayout} onSelectedChanged={
|
|
24
26
|
/* @once */ chainFunctions(props.onSelectedChanged, props.scroll !== 'none' ? scrollRow : undefined)} style={/* @once */combineStyles(props.style, RowStyles)}/>);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Row.jsx","sourceRoot":"","sources":["../../../src/primitives/Row.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAqC,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"Row.jsx","sourceRoot":"","sources":["../../../src/primitives/Row.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAqC,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,MAAM,SAAS,GAAe;IAC5B,OAAO,EAAE,MAAM;IACf,GAAG,EAAE,EAAE;IACP,UAAU,EAAE;QACV,CAAC,EAAE;YACD,QAAQ,EAAE,GAAG;YACb,MAAM,EAAE,aAAa;SACtB;KACF;CACF,CAAC;AAEF,SAAS,aAAa,CAAoB,KAAa;IACrD,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;IACtB,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACvB,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACxC,MAAM,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;AAE1C,MAAM,CAAC,MAAM,GAAG,GAAwB,CAAC,KAAK,EAAE,EAAE;IAChD,OAAO,CACL,CAAC,IAAI,CACH,IAAI,KAAK,CAAC,CACV,QAAQ,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC,CAC9B,MAAM,CAAC,CAAC,WAAY,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CACzD,OAAO,CAAC,CAAC,WAAY,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAC5D,YAAY,CAAC,CAAC,qBAAqB,CAAC,CACpC,aAAa,CAAC,CAAC,aAAa,CAAC,CAC7B,QAAQ,CAAC,CAAC;QACR,WAAW;QACX,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QACrE,CAAC,CACD,iBAAiB,CAAC,CAAC;QACjB,WAAW,CAAC,cAAc,CACxB,KAAK,CAAC,iBAAiB,EACvB,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAEnD,CAAC,CACD,KAAK,CAAC,CAAC,WAAY,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,EACzD,CACH,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -7,10 +7,11 @@ export type VirtualProps<T> = lng.NewOmit<lngp.RowProps, 'children'> & {
|
|
|
7
7
|
bufferSize?: number;
|
|
8
8
|
wrap?: boolean;
|
|
9
9
|
scrollIndex?: number;
|
|
10
|
-
doScroll?: lngp.Scroller;
|
|
11
10
|
onEndReached?: () => void;
|
|
12
11
|
onEndReachedThreshold?: number;
|
|
13
|
-
|
|
12
|
+
debugInfo?: boolean;
|
|
13
|
+
factorScale?: boolean;
|
|
14
|
+
uniformSize?: boolean;
|
|
14
15
|
children: (item: s.Accessor<T>, index: s.Accessor<number>) => s.JSX.Element;
|
|
15
16
|
};
|
|
16
17
|
export declare function VirtualRow<T>(props: VirtualProps<T>): lng.JSX.Element;
|
|
@@ -3,12 +3,10 @@ import * as lng from '@lightningtv/solid';
|
|
|
3
3
|
import * as lngp from '@lightningtv/solid/primitives';
|
|
4
4
|
import { List } from '@solid-primitives/list';
|
|
5
5
|
import * as utils from '../utils.js';
|
|
6
|
-
function createVirtual(component, props,
|
|
6
|
+
function createVirtual(component, props, keyHandlers) {
|
|
7
7
|
const [cursor, setCursor] = s.createSignal(props.selected ?? 0);
|
|
8
8
|
const bufferSize = s.createMemo(() => props.bufferSize || 2);
|
|
9
|
-
const scrollIndex = s.createMemo(() =>
|
|
10
|
-
return props.scrollIndex || 0;
|
|
11
|
-
});
|
|
9
|
+
const scrollIndex = s.createMemo(() => props.scrollIndex || 0);
|
|
12
10
|
const items = s.createMemo(() => props.each || []);
|
|
13
11
|
const itemCount = s.createMemo(() => items().length);
|
|
14
12
|
const scrollType = s.createMemo(() => props.scroll || 'auto');
|
|
@@ -18,158 +16,363 @@ function createVirtual(component, props, scrollFn, keyHandlers) {
|
|
|
18
16
|
}
|
|
19
17
|
return props.selected || 0;
|
|
20
18
|
};
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
let cachedScaledSize;
|
|
20
|
+
let targetPosition;
|
|
21
|
+
let cachedAnimationController;
|
|
22
|
+
const uniformSize = s.createMemo(() => {
|
|
23
|
+
return props.uniformSize !== false;
|
|
24
|
+
});
|
|
25
|
+
const [slice, setSlice] = s.createSignal({
|
|
26
|
+
start: 0,
|
|
27
|
+
slice: [],
|
|
28
|
+
selected: 0,
|
|
29
|
+
delta: 0,
|
|
30
|
+
shiftBy: 0,
|
|
31
|
+
atStart: true,
|
|
32
|
+
});
|
|
33
|
+
function normalizeDeltaForWindow(delta, windowLen) {
|
|
34
|
+
if (!windowLen)
|
|
23
35
|
return 0;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (
|
|
28
|
-
return
|
|
36
|
+
const half = windowLen / 2;
|
|
37
|
+
if (delta > half)
|
|
38
|
+
return delta - windowLen;
|
|
39
|
+
if (delta < -half)
|
|
40
|
+
return delta + windowLen;
|
|
41
|
+
return delta;
|
|
42
|
+
}
|
|
43
|
+
function computeSize(selected = 0) {
|
|
44
|
+
if (uniformSize() && cachedScaledSize) {
|
|
45
|
+
return cachedScaledSize;
|
|
29
46
|
}
|
|
30
|
-
if (
|
|
31
|
-
|
|
47
|
+
else if (viewRef) {
|
|
48
|
+
const gap = viewRef.gap || 0;
|
|
49
|
+
const isRow = component === lngp.Row;
|
|
50
|
+
const dimension = isRow ? 'width' : 'height';
|
|
51
|
+
const prevSelectedChild = viewRef.children[selected];
|
|
52
|
+
if (prevSelectedChild instanceof lng.ElementNode) {
|
|
53
|
+
const itemSize = prevSelectedChild[dimension] || 0;
|
|
54
|
+
const focusStyle = prevSelectedChild.style?.focus;
|
|
55
|
+
const scale = (focusStyle?.scale ?? prevSelectedChild.scale ?? 1);
|
|
56
|
+
const scaledSize = itemSize * (props.factorScale ? scale : 1) + gap;
|
|
57
|
+
cachedScaledSize = scaledSize;
|
|
58
|
+
return scaledSize;
|
|
59
|
+
}
|
|
32
60
|
}
|
|
33
|
-
return
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
function computeSlice(c, delta, prev) {
|
|
64
|
+
const total = itemCount();
|
|
65
|
+
if (total === 0)
|
|
66
|
+
return { start: 0, slice: [], selected: 0, delta, shiftBy: 0, atStart: true };
|
|
67
|
+
const length = props.displaySize + bufferSize();
|
|
68
|
+
let start = prev.start;
|
|
69
|
+
let selected = prev.selected;
|
|
70
|
+
let atStart = prev.atStart;
|
|
71
|
+
let shiftBy = -delta;
|
|
72
|
+
switch (scrollType()) {
|
|
73
|
+
case 'always':
|
|
74
|
+
if (props.wrap) {
|
|
75
|
+
start = utils.mod(c - 1, total);
|
|
76
|
+
selected = 1;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
start = utils.clamp(c - bufferSize(), 0, Math.max(0, total - props.displaySize - bufferSize()));
|
|
80
|
+
if (delta === 0 && c > 3) {
|
|
81
|
+
shiftBy = c < 3 ? -c : -2;
|
|
82
|
+
selected = 2;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
selected =
|
|
86
|
+
c < bufferSize()
|
|
87
|
+
? c
|
|
88
|
+
: c >= total - props.displaySize
|
|
89
|
+
? c - (total - props.displaySize) + bufferSize()
|
|
90
|
+
: bufferSize();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
case 'auto':
|
|
95
|
+
if (props.wrap) {
|
|
96
|
+
if (scrollIndex() && prev.selected < scrollIndex()) {
|
|
97
|
+
start = total - 1;
|
|
98
|
+
selected = Math.max(1, prev.selected + delta);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
start = utils.mod(c - (scrollIndex() || 1), total);
|
|
102
|
+
selected = Math.max(1, prev.selected);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
if (delta < 0) {
|
|
107
|
+
// Moving left
|
|
108
|
+
if (prev.start > 0 && prev.selected >= props.displaySize) {
|
|
109
|
+
// Move selection left inside slice
|
|
110
|
+
start = prev.start;
|
|
111
|
+
selected = prev.selected - 1;
|
|
112
|
+
}
|
|
113
|
+
else if (prev.start > 0) {
|
|
114
|
+
// Move selection left inside slice
|
|
115
|
+
start = prev.start - 1;
|
|
116
|
+
selected = prev.selected;
|
|
117
|
+
// shiftBy = 0;
|
|
118
|
+
}
|
|
119
|
+
else if (prev.start === 0 && !prev.atStart) {
|
|
120
|
+
start = 0;
|
|
121
|
+
selected = prev.selected - 1;
|
|
122
|
+
atStart = true;
|
|
123
|
+
}
|
|
124
|
+
else if (selected >= props.displaySize - 1) {
|
|
125
|
+
// Shift window left, keep selection pinned
|
|
126
|
+
start = 0;
|
|
127
|
+
selected = prev.selected - 1;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
start = 0;
|
|
131
|
+
selected = prev.selected - 1;
|
|
132
|
+
shiftBy = 0;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else if (delta > 0) {
|
|
136
|
+
// Moving right
|
|
137
|
+
if (prev.selected < scrollIndex()) {
|
|
138
|
+
// Move selection right inside slice
|
|
139
|
+
start = prev.start;
|
|
140
|
+
selected = prev.selected + 1;
|
|
141
|
+
shiftBy = 0;
|
|
142
|
+
}
|
|
143
|
+
else if (prev.selected === scrollIndex()) {
|
|
144
|
+
start = prev.start;
|
|
145
|
+
selected = prev.selected + 1;
|
|
146
|
+
atStart = false;
|
|
147
|
+
}
|
|
148
|
+
else if (prev.start === 0 && prev.selected === 0) {
|
|
149
|
+
start = 0;
|
|
150
|
+
selected = 1;
|
|
151
|
+
atStart = false;
|
|
152
|
+
}
|
|
153
|
+
else if (prev.start >= total - props.displaySize) {
|
|
154
|
+
// At end: clamp slice, selection drifts right
|
|
155
|
+
start = prev.start;
|
|
156
|
+
selected = c - start;
|
|
157
|
+
shiftBy = 0;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// Shift window right, keep selection pinned
|
|
161
|
+
start = prev.start + 1;
|
|
162
|
+
selected = Math.max(prev.selected, scrollIndex() + 1);
|
|
163
|
+
;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// Initial setup
|
|
168
|
+
if (c > 0) {
|
|
169
|
+
start = Math.min(c - (scrollIndex() || 1), total - props.displaySize - bufferSize());
|
|
170
|
+
selected = Math.max(scrollIndex() || 1, c - start);
|
|
171
|
+
shiftBy = total - c < 3 ? c - total : -1;
|
|
172
|
+
atStart = false;
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
start = prev.start;
|
|
176
|
+
selected = prev.selected;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
break;
|
|
181
|
+
case 'edge':
|
|
182
|
+
const startScrolling = Math.max(1, props.displaySize - 1);
|
|
183
|
+
if (props.wrap) {
|
|
184
|
+
if (delta > 0) {
|
|
185
|
+
if (prev.selected < startScrolling) {
|
|
186
|
+
selected = prev.selected + 1;
|
|
187
|
+
shiftBy = 0;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
start = utils.mod(prev.start + 1, total);
|
|
191
|
+
selected = startScrolling;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else if (delta < 0) {
|
|
195
|
+
if (prev.selected > 1) {
|
|
196
|
+
selected = prev.selected - 1;
|
|
197
|
+
shiftBy = 0;
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
start = utils.mod(prev.start - 1, total);
|
|
201
|
+
selected = 1;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
start = utils.mod(c - 1, total);
|
|
206
|
+
selected = 1;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
if (delta === 0 && c > 0) {
|
|
211
|
+
//initial setup
|
|
212
|
+
selected = c > startScrolling ? startScrolling : c;
|
|
213
|
+
start = Math.max(0, c - startScrolling + 1);
|
|
214
|
+
shiftBy = c > startScrolling ? -1 : 0;
|
|
215
|
+
atStart = c < startScrolling;
|
|
216
|
+
}
|
|
217
|
+
else if (delta > 0) {
|
|
218
|
+
if (prev.selected < startScrolling - 1) {
|
|
219
|
+
selected = prev.selected + 1;
|
|
220
|
+
shiftBy = 0;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
start = prev.start + 1;
|
|
224
|
+
selected = prev.selected;
|
|
225
|
+
atStart = false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else if (delta < 0) {
|
|
229
|
+
if (prev.selected > 1) {
|
|
230
|
+
selected = prev.selected - 1;
|
|
231
|
+
shiftBy = 0;
|
|
232
|
+
}
|
|
233
|
+
else if (c > 1) {
|
|
234
|
+
start = Math.max(0, c - 1);
|
|
235
|
+
selected = 1;
|
|
236
|
+
}
|
|
237
|
+
else if (!atStart) {
|
|
238
|
+
start = 0;
|
|
239
|
+
selected = 0;
|
|
240
|
+
atStart = true;
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
start = 0;
|
|
244
|
+
selected = 0;
|
|
245
|
+
shiftBy = 0;
|
|
246
|
+
atStart = true;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
break;
|
|
251
|
+
case 'none':
|
|
252
|
+
default:
|
|
253
|
+
start = 0;
|
|
254
|
+
selected = c;
|
|
255
|
+
shiftBy = 0;
|
|
256
|
+
break;
|
|
40
257
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (!props.wrap) {
|
|
47
|
-
return items().slice(start(), end());
|
|
258
|
+
let newSlice = prev.slice;
|
|
259
|
+
if (start !== prev.start || newSlice.length === 0) {
|
|
260
|
+
newSlice = props.wrap
|
|
261
|
+
? Array.from({ length }, (_, i) => items()[utils.mod(start + i, total)])
|
|
262
|
+
: items().slice(start, start + length);
|
|
48
263
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
264
|
+
const state = { start, slice: newSlice, selected, delta, shiftBy, atStart };
|
|
265
|
+
if (props.debugInfo) {
|
|
266
|
+
console.log(`[Virtual]`, {
|
|
267
|
+
cursor: c,
|
|
268
|
+
delta,
|
|
269
|
+
start,
|
|
270
|
+
selected,
|
|
271
|
+
shiftBy,
|
|
272
|
+
slice: state.slice,
|
|
273
|
+
});
|
|
54
274
|
}
|
|
55
|
-
return
|
|
56
|
-
}
|
|
57
|
-
const [slice, setSlice] = s.createSignal(getSlice());
|
|
275
|
+
return state;
|
|
276
|
+
}
|
|
58
277
|
let viewRef;
|
|
59
278
|
function scrollToIndex(index) {
|
|
60
279
|
if (itemCount() === 0)
|
|
61
280
|
return;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
281
|
+
updateSelected([utils.clamp(index, 0, itemCount() - 1)]);
|
|
282
|
+
}
|
|
283
|
+
let lastNavTime = 0;
|
|
284
|
+
function getAdaptiveDuration(duration = 250) {
|
|
285
|
+
const now = performance.now();
|
|
286
|
+
const delta = now - lastNavTime;
|
|
287
|
+
lastNavTime = now;
|
|
288
|
+
if (delta < duration)
|
|
289
|
+
return delta;
|
|
290
|
+
return duration;
|
|
70
291
|
}
|
|
71
292
|
const onSelectedChanged = function (_idx, elm, _active, _lastIdx) {
|
|
72
293
|
let idx = _idx;
|
|
73
294
|
let lastIdx = _lastIdx || 0;
|
|
74
295
|
let active = _active;
|
|
75
296
|
const initialRun = idx === lastIdx;
|
|
297
|
+
const total = itemCount();
|
|
298
|
+
const isRow = component === lngp.Row;
|
|
299
|
+
const axis = isRow ? 'x' : 'y';
|
|
300
|
+
if (props.onSelectedChanged) {
|
|
301
|
+
props.onSelectedChanged.call(this, idx, this, active, lastIdx);
|
|
302
|
+
}
|
|
76
303
|
if (initialRun && !props.wrap)
|
|
77
304
|
return;
|
|
305
|
+
const rawDelta = idx - (lastIdx ?? 0);
|
|
306
|
+
const windowLen = elm?.children?.length ?? props.displaySize + bufferSize();
|
|
307
|
+
const delta = props.wrap
|
|
308
|
+
? normalizeDeltaForWindow(rawDelta, windowLen)
|
|
309
|
+
: rawDelta;
|
|
78
310
|
if (!initialRun) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (props.
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
else if (props.scrollIndex) {
|
|
92
|
-
this.selected = Math.min(c, props.scrollIndex);
|
|
93
|
-
if (c >= itemCount() - props.displaySize + bufferSize()) {
|
|
94
|
-
this.selected = c - (itemCount() - props.displaySize) + bufferSize();
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
else if (scroll === 'always' || scroll === 'auto') {
|
|
98
|
-
if (c < bufferSize()) {
|
|
99
|
-
this.selected = c;
|
|
100
|
-
}
|
|
101
|
-
else if (c >= itemCount() - props.displaySize) {
|
|
102
|
-
this.selected = c - (itemCount() - props.displaySize) + bufferSize();
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
this.selected = bufferSize();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (props.onEndReachedThreshold !== undefined && cursor() >= items().length - props.onEndReachedThreshold) {
|
|
311
|
+
setCursor(c => {
|
|
312
|
+
const next = c + delta;
|
|
313
|
+
return props.wrap
|
|
314
|
+
? utils.mod(next, total)
|
|
315
|
+
: utils.clamp(next, 0, total - 1);
|
|
316
|
+
});
|
|
317
|
+
const newState = computeSlice(cursor(), delta, slice());
|
|
318
|
+
setSlice(newState);
|
|
319
|
+
elm.selected = newState.selected;
|
|
320
|
+
if (props.onEndReachedThreshold !== undefined &&
|
|
321
|
+
cursor() >= itemCount() - props.onEndReachedThreshold) {
|
|
109
322
|
props.onEndReached?.();
|
|
110
323
|
}
|
|
324
|
+
if (newState.shiftBy === 0)
|
|
325
|
+
return;
|
|
111
326
|
}
|
|
112
|
-
const
|
|
113
|
-
const prevChildPos = isRow
|
|
114
|
-
? this.x + active.x
|
|
115
|
-
: this.y + active.y;
|
|
327
|
+
const prevChildPos = (targetPosition ?? this[axis]) + active[axis];
|
|
116
328
|
queueMicrotask(() => {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (scrollIndex() > 0) {
|
|
123
|
-
active = this.children[1];
|
|
124
|
-
}
|
|
329
|
+
elm.updateLayout();
|
|
330
|
+
const childSize = computeSize(slice().selected);
|
|
331
|
+
if (cachedAnimationController && cachedAnimationController.state === 'running') {
|
|
332
|
+
cachedAnimationController.stop();
|
|
333
|
+
;
|
|
125
334
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
this.lng.y = this._targetPosition = prevChildPos - active.y;
|
|
131
|
-
}
|
|
132
|
-
scrollFn(idx, elm, active, lastIdx);
|
|
335
|
+
this.lng[axis] = prevChildPos - active[axis];
|
|
336
|
+
let offset = this.lng[axis] + (childSize * slice().shiftBy);
|
|
337
|
+
targetPosition = offset;
|
|
338
|
+
cachedAnimationController = this.animate({ [axis]: offset }, { ...this.animationSettings, duration: getAdaptiveDuration(this.animationSettings?.duration) }).start();
|
|
133
339
|
});
|
|
134
340
|
};
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
if (!viewRef || selected === undefined)
|
|
341
|
+
const updateSelected = ([sel, _items]) => {
|
|
342
|
+
if (!viewRef || sel === undefined || itemCount() === 0)
|
|
138
343
|
return;
|
|
139
|
-
const sel = selected;
|
|
140
344
|
const item = items()[sel];
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
345
|
+
setCursor(sel);
|
|
346
|
+
const newState = computeSlice(cursor(), 0, slice());
|
|
347
|
+
setSlice(newState);
|
|
348
|
+
queueMicrotask(() => {
|
|
349
|
+
viewRef.updateLayout();
|
|
350
|
+
if (slice().shiftBy) {
|
|
351
|
+
const isRow = component === lngp.Row;
|
|
352
|
+
const axis = isRow ? 'x' : 'y';
|
|
353
|
+
const childSize = computeSize(slice().selected);
|
|
354
|
+
viewRef.lng[axis] = viewRef.lng[axis] + (childSize * slice().shiftBy);
|
|
355
|
+
targetPosition = viewRef.lng[axis];
|
|
356
|
+
}
|
|
357
|
+
let activeIndex = viewRef.children.findIndex(x => x.item === item);
|
|
358
|
+
if (activeIndex === -1)
|
|
359
|
+
return;
|
|
360
|
+
viewRef.selected = activeIndex;
|
|
361
|
+
viewRef.children[activeIndex]?.setFocus();
|
|
362
|
+
});
|
|
160
363
|
};
|
|
161
|
-
s.createEffect(s.on([() => props.selected, items], updateSelected));
|
|
364
|
+
s.createEffect(s.on([() => props.selected, items], updateSelected, { defer: true }));
|
|
162
365
|
s.createEffect(s.on(items, () => {
|
|
163
|
-
if (!viewRef)
|
|
366
|
+
if (!viewRef || itemCount() === 0)
|
|
164
367
|
return;
|
|
165
368
|
if (cursor() >= itemCount()) {
|
|
166
|
-
setCursor(
|
|
369
|
+
setCursor(itemCount() - 1);
|
|
167
370
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
371
|
+
const newState = computeSlice(cursor(), 0, slice());
|
|
372
|
+
setSlice(newState);
|
|
373
|
+
viewRef.selected = newState.selected;
|
|
374
|
+
}));
|
|
375
|
+
return (<view {...props} {...keyHandlers} ref={lngp.chainRefs(el => { viewRef = el; }, props.ref)} selected={selected()} cursor={cursor()} forwardFocus={/* @once */lngp.navigableForwardFocus} scrollToIndex={/* @once */scrollToIndex} onSelectedChanged={/* @once */onSelectedChanged} style={/* @once */lng.combineStyles(props.style, component === lngp.Row
|
|
173
376
|
? {
|
|
174
377
|
display: 'flex',
|
|
175
378
|
gap: 30,
|
|
@@ -181,19 +384,19 @@ function createVirtual(component, props, scrollFn, keyHandlers) {
|
|
|
181
384
|
gap: 30,
|
|
182
385
|
transition: { y: { duration: 250, easing: 'ease-out' } },
|
|
183
386
|
})}>
|
|
184
|
-
<List each={slice()}>{props.children}</List>
|
|
387
|
+
<List each={slice().slice}>{props.children}</List>
|
|
185
388
|
</view>);
|
|
186
389
|
}
|
|
187
390
|
export function VirtualRow(props) {
|
|
188
|
-
return createVirtual(lngp.Row, props,
|
|
189
|
-
onLeft: lngp.chainFunctions(props.onLeft, lngp.
|
|
190
|
-
onRight: lngp.chainFunctions(props.onRight, lngp.
|
|
391
|
+
return createVirtual(lngp.Row, props, {
|
|
392
|
+
onLeft: lngp.chainFunctions(props.onLeft, lngp.handleNavigation('left')),
|
|
393
|
+
onRight: lngp.chainFunctions(props.onRight, lngp.handleNavigation('right')),
|
|
191
394
|
});
|
|
192
395
|
}
|
|
193
396
|
export function VirtualColumn(props) {
|
|
194
|
-
return createVirtual(lngp.Column, props,
|
|
195
|
-
onUp: lngp.chainFunctions(props.onUp, lngp.
|
|
196
|
-
onDown: lngp.chainFunctions(props.onDown, lngp.
|
|
397
|
+
return createVirtual(lngp.Column, props, {
|
|
398
|
+
onUp: lngp.chainFunctions(props.onUp, lngp.handleNavigation('up')),
|
|
399
|
+
onDown: lngp.chainFunctions(props.onDown, lngp.handleNavigation('down')),
|
|
197
400
|
});
|
|
198
401
|
}
|
|
199
402
|
//# sourceMappingURL=Virtual.jsx.map
|