@lightningtv/solid 2.12.3 → 2.12.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/dist/src/primitives/Lazy.d.ts +1 -1
- package/dist/src/primitives/Lazy.jsx +5 -2
- package/dist/src/primitives/Lazy.jsx.map +1 -1
- package/dist/src/primitives/Row.jsx.map +1 -1
- package/dist/src/primitives/Virtual.jsx +2 -2
- package/dist/src/primitives/Virtual.jsx.map +1 -1
- package/dist/src/primitives/VirtualGrid.jsx +26 -5
- package/dist/src/primitives/VirtualGrid.jsx.map +1 -1
- package/dist/src/primitives/useMouse.d.ts +0 -2
- package/dist/src/primitives/useMouse.js +29 -11
- package/dist/src/primitives/useMouse.js.map +1 -1
- package/dist/src/primitives/utils/handleNavigation.js +1 -1
- package/dist/src/primitives/utils/handleNavigation.js.map +1 -1
- package/dist/src/primitives/utils/withScrolling.d.ts +6 -1
- package/dist/src/primitives/utils/withScrolling.js +42 -2
- package/dist/src/primitives/utils/withScrolling.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/primitives/Lazy.tsx +8 -2
- package/src/primitives/Row.tsx +3 -3
- package/src/primitives/Virtual.tsx +2 -2
- package/src/primitives/VirtualGrid.tsx +26 -5
- package/src/primitives/useMouse.ts +46 -14
- package/src/primitives/utils/handleNavigation.ts +1 -1
- package/src/primitives/utils/withScrolling.ts +45 -3
|
@@ -20,7 +20,6 @@ type RenderableNode = ElementNode | ElementText | TextNode;
|
|
|
20
20
|
interface MouseStateOptions {
|
|
21
21
|
hoverState: CustomState;
|
|
22
22
|
pressedState: CustomState;
|
|
23
|
-
pressedStateDuration?: number;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
type UseMouseOptions =
|
|
@@ -29,7 +28,6 @@ type UseMouseOptions =
|
|
|
29
28
|
|
|
30
29
|
declare module '@lightningtv/core' {
|
|
31
30
|
interface ElementNode {
|
|
32
|
-
onEnter?: () => void;
|
|
33
31
|
/** function to be called on mouse click */
|
|
34
32
|
onMouseClick?: (
|
|
35
33
|
this: ElementNode,
|
|
@@ -39,8 +37,6 @@ declare module '@lightningtv/core' {
|
|
|
39
37
|
}
|
|
40
38
|
}
|
|
41
39
|
|
|
42
|
-
const DEFAULT_PRESSED_STATE_DURATION = 150;
|
|
43
|
-
|
|
44
40
|
export function addCustomStateToElement(
|
|
45
41
|
element: RenderableNode,
|
|
46
42
|
state: CustomState,
|
|
@@ -168,25 +164,22 @@ function findElementByActiveElement(e: MouseEvent): ElementNode | null {
|
|
|
168
164
|
function applyPressedState(
|
|
169
165
|
element: ElementNode,
|
|
170
166
|
pressedState: CustomState,
|
|
171
|
-
pressedStateDuration: number = DEFAULT_PRESSED_STATE_DURATION,
|
|
172
167
|
): void {
|
|
173
168
|
addCustomStateToElement(element, pressedState);
|
|
174
|
-
setTimeout(() => {
|
|
175
|
-
removeCustomStateFromElement(element, pressedState);
|
|
176
|
-
}, pressedStateDuration);
|
|
177
169
|
}
|
|
178
170
|
|
|
179
171
|
function handleElementClick(
|
|
180
172
|
clickedElement: ElementNode,
|
|
181
173
|
e: MouseEvent,
|
|
182
174
|
customStates?: MouseStateOptions,
|
|
175
|
+
pressedElementRef?: { current: ElementNode | null },
|
|
183
176
|
): void {
|
|
184
|
-
if (customStates?.pressedState) {
|
|
185
|
-
|
|
186
|
-
|
|
177
|
+
if (customStates?.pressedState && pressedElementRef?.current) {
|
|
178
|
+
removeCustomStateFromElement(
|
|
179
|
+
pressedElementRef.current,
|
|
187
180
|
customStates.pressedState,
|
|
188
|
-
customStates.pressedStateDuration,
|
|
189
181
|
);
|
|
182
|
+
pressedElementRef.current = null;
|
|
190
183
|
}
|
|
191
184
|
|
|
192
185
|
if (isFunc(clickedElement.onMouseClick)) {
|
|
@@ -211,6 +204,7 @@ function handleElementClick(
|
|
|
211
204
|
function createHandleClick<TApp extends ElementNode>(
|
|
212
205
|
myApp: TApp,
|
|
213
206
|
customStates?: MouseStateOptions,
|
|
207
|
+
pressedElementRef?: { current: ElementNode | null },
|
|
214
208
|
) {
|
|
215
209
|
return (e: MouseEvent): void => {
|
|
216
210
|
const clickedElement = customStates
|
|
@@ -226,7 +220,35 @@ function createHandleClick<TApp extends ElementNode>(
|
|
|
226
220
|
return;
|
|
227
221
|
}
|
|
228
222
|
|
|
229
|
-
handleElementClick(clickedElement, e, customStates);
|
|
223
|
+
handleElementClick(clickedElement, e, customStates, pressedElementRef);
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function createHandleMouseDown<TApp extends ElementNode>(
|
|
228
|
+
myApp: TApp,
|
|
229
|
+
customStates?: MouseStateOptions,
|
|
230
|
+
pressedElementRef?: { current: ElementNode | null },
|
|
231
|
+
) {
|
|
232
|
+
return (e: MouseEvent): void => {
|
|
233
|
+
if (!customStates) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const pressedElement = findElementWithCustomState(
|
|
238
|
+
myApp,
|
|
239
|
+
e.clientX,
|
|
240
|
+
e.clientY,
|
|
241
|
+
customStates.hoverState,
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
if (!pressedElement) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
applyPressedState(pressedElement, customStates.pressedState);
|
|
249
|
+
if (pressedElementRef) {
|
|
250
|
+
pressedElementRef.current = pressedElement;
|
|
251
|
+
}
|
|
230
252
|
};
|
|
231
253
|
}
|
|
232
254
|
|
|
@@ -330,16 +352,26 @@ export function useMouse<TApp extends ElementNode = ElementNode>(
|
|
|
330
352
|
const pos = useMousePosition();
|
|
331
353
|
const scheduled = createScheduled((fn) => throttle(fn, throttleBy));
|
|
332
354
|
let previousElement: ElementNode | null = null;
|
|
355
|
+
const pressedElementRef: { current: ElementNode | null } = { current: null };
|
|
333
356
|
const customStates = options?.customStates;
|
|
334
357
|
const hoverState = customStates?.hoverState;
|
|
335
|
-
const handleClick = createHandleClick(myApp, customStates);
|
|
358
|
+
const handleClick = createHandleClick(myApp, customStates, pressedElementRef);
|
|
359
|
+
const handleMouseDown = createHandleMouseDown(
|
|
360
|
+
myApp,
|
|
361
|
+
customStates,
|
|
362
|
+
pressedElementRef,
|
|
363
|
+
);
|
|
336
364
|
const owner = getOwner();
|
|
337
365
|
const handleClickContext = (e: MouseEvent) => {
|
|
338
366
|
runWithOwner(owner, () => handleClick(e));
|
|
339
367
|
};
|
|
368
|
+
const handleMouseDownContext = (e: MouseEvent) => {
|
|
369
|
+
runWithOwner(owner, () => handleMouseDown(e));
|
|
370
|
+
};
|
|
340
371
|
|
|
341
372
|
makeEventListener(window, 'wheel', handleScroll);
|
|
342
373
|
makeEventListener(window, 'click', handleClickContext);
|
|
374
|
+
makeEventListener(window, 'mousedown', handleMouseDownContext);
|
|
343
375
|
createEffect(() => {
|
|
344
376
|
if (scheduled()) {
|
|
345
377
|
const result = getChildrenByPosition(myApp, pos.x, pos.y).filter(
|
|
@@ -138,7 +138,7 @@ export function moveSelection(
|
|
|
138
138
|
if (selected === -1) {
|
|
139
139
|
if (
|
|
140
140
|
!idxInArray(el.selected, el.children) ||
|
|
141
|
-
el.children[el.selected]
|
|
141
|
+
el.children[el.selected]?.skipFocus ||
|
|
142
142
|
lng.isFocused(el.children[el.selected]!)
|
|
143
143
|
) {
|
|
144
144
|
return false;
|
|
@@ -15,10 +15,11 @@ export type Scroller = (
|
|
|
15
15
|
// Adds properties expected by withScrolling
|
|
16
16
|
export interface ScrollableElement extends ElementNode {
|
|
17
17
|
scrollIndex?: number;
|
|
18
|
-
scroll?: 'always' | 'none' | 'edge' | 'auto' | 'center';
|
|
18
|
+
scroll?: 'always' | 'none' | 'edge' | 'auto' | 'center' | 'bounded';
|
|
19
19
|
selected: number;
|
|
20
20
|
offset?: number;
|
|
21
21
|
endOffset?: number;
|
|
22
|
+
upCount?: number;
|
|
22
23
|
onScrolled?: (
|
|
23
24
|
elm: ScrollableElement,
|
|
24
25
|
offset: number,
|
|
@@ -40,6 +41,19 @@ const isNotShown = (node: ElementNode | ElementText) => {
|
|
|
40
41
|
Always scroll moves the list every time
|
|
41
42
|
*/
|
|
42
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Checks if the selected index is in the non-scrollable zone (last upCount items).
|
|
46
|
+
*/
|
|
47
|
+
export function checkIsInNonScrollableZone(
|
|
48
|
+
componentRef: ScrollableElement,
|
|
49
|
+
): boolean {
|
|
50
|
+
const totalItems = componentRef.children.length;
|
|
51
|
+
const upCount = componentRef.upCount || 6;
|
|
52
|
+
const selected = componentRef.selected || 0;
|
|
53
|
+
const nonScrollableZoneStart = Math.max(0, totalItems - upCount);
|
|
54
|
+
return selected >= nonScrollableZoneStart;
|
|
55
|
+
}
|
|
56
|
+
|
|
43
57
|
/** @deprecated Use {@link scrollRow} or {@link scrollColumn} */
|
|
44
58
|
export function withScrolling(isRow: boolean): Scroller {
|
|
45
59
|
const dimension = isRow ? 'width' : 'height';
|
|
@@ -135,6 +149,35 @@ export function withScrolling(isRow: boolean): Scroller {
|
|
|
135
149
|
nextPosition = -selectedPosition + (screenSize - selectedSizeScaled) / 2;
|
|
136
150
|
} else if (scroll === 'always') {
|
|
137
151
|
nextPosition = -selectedPosition + offset;
|
|
152
|
+
} else if (scroll === 'bounded') {
|
|
153
|
+
const totalItems = componentRef.children.length;
|
|
154
|
+
const upCount = componentRef.upCount || 6;
|
|
155
|
+
const nonScrollableZoneStart = Math.max(0, totalItems - upCount);
|
|
156
|
+
const isInNonScrollableZone = selected >= nonScrollableZoneStart;
|
|
157
|
+
const isFirstOfNonScrollableZone = selected === nonScrollableZoneStart;
|
|
158
|
+
const isEnteringZone =
|
|
159
|
+
isFirstOfNonScrollableZone &&
|
|
160
|
+
lastSelected !== undefined &&
|
|
161
|
+
lastSelected < nonScrollableZoneStart;
|
|
162
|
+
|
|
163
|
+
if (!isInNonScrollableZone) {
|
|
164
|
+
nextPosition = -selectedPosition + offset;
|
|
165
|
+
} else if (isIncrementing) {
|
|
166
|
+
if (isEnteringZone) {
|
|
167
|
+
const firstOfZoneElement =
|
|
168
|
+
componentRef.children[nonScrollableZoneStart];
|
|
169
|
+
const firstOfZonePosition = firstOfZoneElement?.[axis] ?? 0;
|
|
170
|
+
nextPosition = firstOfZoneElement
|
|
171
|
+
? -firstOfZonePosition + offset
|
|
172
|
+
: rootPosition;
|
|
173
|
+
} else {
|
|
174
|
+
nextPosition = rootPosition;
|
|
175
|
+
}
|
|
176
|
+
} else if (isFirstOfNonScrollableZone) {
|
|
177
|
+
nextPosition = -selectedPosition + offset;
|
|
178
|
+
} else {
|
|
179
|
+
nextPosition = rootPosition;
|
|
180
|
+
}
|
|
138
181
|
} else if (scroll === 'center') {
|
|
139
182
|
const centerPosition =
|
|
140
183
|
-selectedPosition +
|
|
@@ -160,7 +203,6 @@ export function withScrolling(isRow: boolean): Scroller {
|
|
|
160
203
|
nextPosition = rootPosition + selectedSize + gap;
|
|
161
204
|
}
|
|
162
205
|
} else if (isIncrementing) {
|
|
163
|
-
//nextPosition = -selectedPosition + offset;
|
|
164
206
|
nextPosition = rootPosition - selectedSize - gap;
|
|
165
207
|
} else {
|
|
166
208
|
nextPosition = rootPosition + selectedSize + gap;
|
|
@@ -174,7 +216,7 @@ export function withScrolling(isRow: boolean): Scroller {
|
|
|
174
216
|
|
|
175
217
|
// Prevent container from moving beyond bounds
|
|
176
218
|
nextPosition =
|
|
177
|
-
isIncrementing && scroll !== 'always'
|
|
219
|
+
isIncrementing && scroll !== 'always' && scroll !== 'bounded'
|
|
178
220
|
? Math.max(nextPosition, maxOffset)
|
|
179
221
|
: Math.min(nextPosition, offset);
|
|
180
222
|
|