@lightningtv/solid 3.0.4 → 3.0.6

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.
@@ -3,6 +3,12 @@ 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
+ import {
7
+ defaultTransitionBack,
8
+ defaultTransitionForward,
9
+ defaultTransitionDown,
10
+ defaultTransitionUp,
11
+ } from './utils/handleNavigation.js';
6
12
 
7
13
  export type VirtualProps<T> = lng.NewOmit<lngp.RowProps, 'children'> & {
8
14
  each: readonly T[] | undefined | null | false;
@@ -21,7 +27,7 @@ export type VirtualProps<T> = lng.NewOmit<lngp.RowProps, 'children'> & {
21
27
  function createVirtual<T>(
22
28
  component: typeof lngp.Row | typeof lngp.Column,
23
29
  props: VirtualProps<T>,
24
- keyHandlers: Record<string, lng.KeyHandler>
30
+ keyHandlers: Record<string, lng.KeyHandler>,
25
31
  ) {
26
32
  const isRow = component === lngp.Row;
27
33
  const axis = isRow ? 'x' : 'y';
@@ -46,81 +52,102 @@ function createVirtual<T>(
46
52
  return props.uniformSize !== false;
47
53
  });
48
54
 
49
- type SliceState = { start: number; slice: T[]; selected: number, delta: number, shiftBy: number, atStart: boolean; cursor: number };
50
- const [slice, setSlice] = s.createSignal<SliceState>({
51
- start: 0,
52
- slice: [],
53
- selected: 0,
54
- delta: 0,
55
- shiftBy: 0,
56
- atStart: true,
57
- cursor: 0,
58
- });
55
+ type SliceState = {
56
+ start: number;
57
+ slice: T[];
58
+ selected: number;
59
+ delta: number;
60
+ shiftBy: number;
61
+ atStart: boolean;
62
+ cursor: number;
63
+ };
64
+ const [slice, setSlice] = s.createSignal<SliceState>({
65
+ start: 0,
66
+ slice: [],
67
+ selected: 0,
68
+ delta: 0,
69
+ shiftBy: 0,
70
+ atStart: true,
71
+ cursor: 0,
72
+ });
59
73
 
60
- function normalizeDeltaForWindow(delta: number, windowLen: number): number {
61
- if (!windowLen) return 0;
62
- const half = windowLen / 2;
63
- if (delta > half) return delta - windowLen;
64
- if (delta < -half) return delta + windowLen;
65
- return delta;
66
- }
74
+ function normalizeDeltaForWindow(delta: number, windowLen: number): number {
75
+ if (!windowLen) return 0;
76
+ const half = windowLen / 2;
77
+ if (delta > half) return delta - windowLen;
78
+ if (delta < -half) return delta + windowLen;
79
+ return delta;
80
+ }
67
81
 
68
- function computeSize(selected: number = 0) {
69
- if (uniformSize() && cachedScaledSize) {
70
- return cachedScaledSize;
71
- } else if (viewRef) {
72
- const gap = viewRef.gap || 0;
73
- const dimension = isRow ? 'width' : 'height'; // This can't be moved up as it depends on viewRef
74
- const prevSelectedChild = viewRef.children[selected];
75
-
76
- if (prevSelectedChild instanceof lng.ElementNode) {
77
- const itemSize = prevSelectedChild[dimension] || 0;
78
- const focusStyle = (prevSelectedChild.style?.focus as lng.NodeStyles);
79
- const scale = (focusStyle?.scale ?? prevSelectedChild.scale ?? 1);
80
- const scaledSize = itemSize * (props.factorScale ? scale : 1) + gap;
81
- cachedScaledSize = scaledSize;
82
- return scaledSize;
83
- }
82
+ function computeSize(selected: number = 0) {
83
+ if (uniformSize() && cachedScaledSize) {
84
+ return cachedScaledSize;
85
+ } else if (viewRef) {
86
+ const gap = viewRef.gap || 0;
87
+ const dimension = isRow ? 'width' : 'height'; // This can't be moved up as it depends on viewRef
88
+ const prevSelectedChild = viewRef.children[selected];
89
+
90
+ if (prevSelectedChild instanceof lng.ElementNode) {
91
+ const itemSize = prevSelectedChild[dimension] || 0;
92
+ const focusStyle = prevSelectedChild.style?.focus as lng.NodeStyles;
93
+ const scale = focusStyle?.scale ?? prevSelectedChild.scale ?? 1;
94
+ const scaledSize = itemSize * (props.factorScale ? scale : 1) + gap;
95
+ cachedScaledSize = scaledSize;
96
+ return scaledSize;
84
97
  }
85
- return 0;
86
98
  }
99
+ return 0;
100
+ }
87
101
 
88
- function computeSlice(c: number, delta: number, prev: SliceState): SliceState {
89
- const total = itemCount();
90
- if (total === 0) return { start: 0, slice: [], selected: 0, delta, shiftBy: 0, atStart: true, cursor: 0 };
91
-
92
- const length = props.displaySize + bufferSize();
93
- let start = prev.start;
94
- let selected = prev.selected;
95
- let atStart = prev.atStart;
96
- let shiftBy = -delta;
97
-
98
- switch (scrollType()) {
99
- case 'always':
100
- if (props.wrap) {
101
- start = utils.mod(c - 1, total);
102
- selected = 1;
102
+ function computeSlice(
103
+ c: number,
104
+ delta: number,
105
+ prev: SliceState,
106
+ ): SliceState {
107
+ const total = itemCount();
108
+ if (total === 0)
109
+ return {
110
+ start: 0,
111
+ slice: [],
112
+ selected: 0,
113
+ delta,
114
+ shiftBy: 0,
115
+ atStart: true,
116
+ cursor: 0,
117
+ };
118
+
119
+ const length = props.displaySize + bufferSize();
120
+ let start = prev.start;
121
+ let selected = prev.selected;
122
+ let atStart = prev.atStart;
123
+ let shiftBy = -delta;
124
+
125
+ switch (scrollType()) {
126
+ case 'always':
127
+ if (props.wrap) {
128
+ start = utils.mod(c - 1, total);
129
+ selected = 1;
130
+ } else {
131
+ start = utils.clamp(
132
+ c - bufferSize(),
133
+ 0,
134
+ Math.max(0, total - props.displaySize - bufferSize()),
135
+ );
136
+ if (delta === 0 && c > 3) {
137
+ shiftBy = c < 3 ? -c : -2;
138
+ selected = 2;
103
139
  } else {
104
- start = utils.clamp(
105
- c - bufferSize(),
106
- 0,
107
- Math.max(0, total - props.displaySize - bufferSize()),
108
- );
109
- if (delta === 0 && c > 3) {
110
- shiftBy = c < 3 ? -c : -2;
111
- selected = 2;
112
- } else {
113
- selected =
114
- c < bufferSize()
115
- ? c
116
- : c >= total - props.displaySize
140
+ selected =
141
+ c < bufferSize()
142
+ ? c
143
+ : c >= total - props.displaySize
117
144
  ? c - (total - props.displaySize) + bufferSize()
118
145
  : bufferSize();
119
- }
120
146
  }
121
- break;
147
+ }
148
+ break;
122
149
 
123
- case 'auto':
150
+ case 'auto':
124
151
  if (props.wrap) {
125
152
  if (delta === 0) {
126
153
  selected = scrollIndex() || 1;
@@ -144,7 +171,7 @@ function createVirtual<T>(
144
171
  start = 0;
145
172
  selected = prev.selected - 1;
146
173
  atStart = true;
147
- } else if (selected >= props.displaySize - 1) {
174
+ } else if (selected >= props.displaySize - 1) {
148
175
  // Shift window left, keep selection pinned
149
176
  start = 0;
150
177
  selected = prev.selected - 1;
@@ -176,12 +203,15 @@ function createVirtual<T>(
176
203
  } else {
177
204
  // Shift window right, keep selection pinned
178
205
  start = prev.start + 1;
179
- selected = Math.max(prev.selected, scrollIndex() + 1);;
206
+ selected = Math.max(prev.selected, scrollIndex() + 1);
180
207
  }
181
208
  } else {
182
209
  // Initial setup
183
210
  if (c > 0) {
184
- start = Math.min(c - (scrollIndex() || 1), total - props.displaySize - bufferSize());
211
+ start = Math.min(
212
+ c - (scrollIndex() || 1),
213
+ total - props.displaySize - bufferSize(),
214
+ );
185
215
  selected = Math.max(scrollIndex() || 1, c - start);
186
216
  shiftBy = total - c < 3 ? c - total : -1;
187
217
  atStart = false;
@@ -202,107 +232,118 @@ function createVirtual<T>(
202
232
  }
203
233
  break;
204
234
 
205
- case 'edge':
206
- const startScrolling = Math.max(1, props.displaySize + (atStart ? -1 : 0));
207
- if (props.wrap) {
208
- if (delta > 0) {
209
- if (prev.selected < startScrolling) {
210
- selected = prev.selected + 1;
211
- shiftBy = 0;
212
- } else if (prev.selected === startScrolling && atStart) {
213
- selected = prev.selected + 1;
214
- atStart = false;
215
- } else {
216
- start = utils.mod(prev.start + 1, total);
217
- selected = prev.selected;
218
- }
219
- } else if (delta < 0) {
220
- if (prev.selected > 1) {
221
- selected = prev.selected - 1;
222
- shiftBy = 0;
223
- } else {
224
- start = utils.mod(prev.start - 1, total);
225
- selected = 1;
226
- }
235
+ case 'edge':
236
+ const startScrolling = Math.max(
237
+ 1,
238
+ props.displaySize + (atStart ? -1 : 0),
239
+ );
240
+ if (props.wrap) {
241
+ if (delta > 0) {
242
+ if (prev.selected < startScrolling) {
243
+ selected = prev.selected + 1;
244
+ shiftBy = 0;
245
+ } else if (prev.selected === startScrolling && atStart) {
246
+ selected = prev.selected + 1;
247
+ atStart = false;
248
+ } else {
249
+ start = utils.mod(prev.start + 1, total);
250
+ selected = prev.selected;
251
+ }
252
+ } else if (delta < 0) {
253
+ if (prev.selected > 1) {
254
+ selected = prev.selected - 1;
255
+ shiftBy = 0;
227
256
  } else {
228
- start = utils.mod(c - 1, total);
257
+ start = utils.mod(prev.start - 1, total);
229
258
  selected = 1;
230
- shiftBy = -1;
231
- atStart = false;
232
259
  }
233
260
  } else {
234
- if (delta === 0 && c > 0) {
235
- //initial setup
236
- selected = c > startScrolling ? startScrolling : c;
237
- start = Math.max(0, c - startScrolling + 1);
238
- shiftBy = c > startScrolling ? -1 : 0;
239
- atStart = c < startScrolling;
240
- } else if (delta > 0) {
241
- if (prev.selected < startScrolling) {
242
- selected = prev.selected + 1;
243
- shiftBy = 0;
244
- } else if (prev.selected === startScrolling && atStart) {
245
- selected = prev.selected + 1;
246
- atStart = false;
247
- } else {
248
- start = prev.start + 1;
249
- selected = prev.selected;
250
- atStart = false;
251
- }
252
- } else if (delta < 0) {
253
- if (prev.selected > 1) {
254
- selected = prev.selected - 1;
255
- shiftBy = 0;
256
- } else if (c > 1) {
257
- start = Math.max(0, c - 1);
258
- selected = 1;
259
- } else if (c === 1) {
260
- start = 0;
261
- selected = 1;
262
- } else {
263
- start = 0;
264
- selected = 0;
265
- shiftBy = atStart ? 0 : shiftBy;
266
- atStart = true;
267
- }
261
+ start = utils.mod(c - 1, total);
262
+ selected = 1;
263
+ shiftBy = -1;
264
+ atStart = false;
265
+ }
266
+ } else {
267
+ if (delta === 0 && c > 0) {
268
+ //initial setup
269
+ selected = c > startScrolling ? startScrolling : c;
270
+ start = Math.max(0, c - startScrolling + 1);
271
+ shiftBy = c > startScrolling ? -1 : 0;
272
+ atStart = c < startScrolling;
273
+ } else if (delta > 0) {
274
+ if (prev.selected < startScrolling) {
275
+ selected = prev.selected + 1;
276
+ shiftBy = 0;
277
+ } else if (prev.selected === startScrolling && atStart) {
278
+ selected = prev.selected + 1;
279
+ atStart = false;
280
+ } else {
281
+ start = prev.start + 1;
282
+ selected = prev.selected;
283
+ atStart = false;
284
+ }
285
+ } else if (delta < 0) {
286
+ if (prev.selected > 1) {
287
+ selected = prev.selected - 1;
288
+ shiftBy = 0;
289
+ } else if (c > 1) {
290
+ start = Math.max(0, c - 1);
291
+ selected = 1;
292
+ } else if (c === 1) {
293
+ start = 0;
294
+ selected = 1;
295
+ } else {
296
+ start = 0;
297
+ selected = 0;
298
+ shiftBy = atStart ? 0 : shiftBy;
299
+ atStart = true;
268
300
  }
269
301
  }
270
- break;
271
-
272
- case 'none':
273
- default:
274
- start = 0;
275
- selected = c;
276
- shiftBy = 0;
277
- break;
278
- }
302
+ }
303
+ break;
279
304
 
280
- let newSlice = prev.slice;
281
- if (start !== prev.start || newSlice.length === 0) {
282
- newSlice = props.wrap
283
- ? Array.from(
284
- { length },
285
- (_, i) => items()[utils.mod(start + i, total)],
286
- ) as T[]
287
- : items().slice(start, start + length);
288
- }
305
+ case 'none':
306
+ default:
307
+ start = 0;
308
+ selected = c;
309
+ shiftBy = 0;
310
+ break;
311
+ }
289
312
 
290
- const state: SliceState = { start, slice: newSlice, selected, delta, shiftBy, atStart, cursor: c };
291
-
292
- if (props.debugInfo) {
293
- console.log(`[Virtual]`, {
294
- cursor: c,
295
- delta,
296
- start,
297
- selected,
298
- shiftBy,
299
- slice: state.slice,
300
- });
301
- }
313
+ let newSlice = prev.slice;
314
+ if (start !== prev.start || newSlice.length === 0) {
315
+ newSlice = props.wrap
316
+ ? (Array.from(
317
+ { length },
318
+ (_, i) => items()[utils.mod(start + i, total)],
319
+ ) as T[])
320
+ : items().slice(start, start + length);
321
+ }
302
322
 
303
- return state;
323
+ const state: SliceState = {
324
+ start,
325
+ slice: newSlice,
326
+ selected,
327
+ delta,
328
+ shiftBy,
329
+ atStart,
330
+ cursor: c,
331
+ };
332
+
333
+ if (props.debugInfo) {
334
+ console.log(`[Virtual]`, {
335
+ cursor: c,
336
+ delta,
337
+ start,
338
+ selected,
339
+ shiftBy,
340
+ slice: state.slice,
341
+ });
304
342
  }
305
343
 
344
+ return state;
345
+ }
346
+
306
347
  let viewRef!: lngp.NavigableElement;
307
348
 
308
349
  function scrollToIndex(this: lng.ElementNode, index: number) {
@@ -334,7 +375,12 @@ function createVirtual<T>(
334
375
  }
335
376
 
336
377
  let originalPosition: number | undefined;
337
- const onSelectedChanged: lngp.OnSelectedChanged = function (_idx, elm, _active, _lastIdx) {
378
+ const onSelectedChanged: lngp.OnSelectedChanged = function (
379
+ _idx,
380
+ elm,
381
+ _active,
382
+ _lastIdx,
383
+ ) {
338
384
  let idx = _idx;
339
385
  let lastIdx = _lastIdx || 0;
340
386
  let active = _active;
@@ -343,19 +389,24 @@ function createVirtual<T>(
343
389
  originalPosition = originalPosition ?? elm[axis];
344
390
 
345
391
  if (props.onSelectedChanged) {
346
- props.onSelectedChanged.call(this as lngp.NavigableElement, idx, this as lngp.NavigableElement, active, lastIdx);
392
+ props.onSelectedChanged.call(
393
+ this as lngp.NavigableElement,
394
+ idx,
395
+ this as lngp.NavigableElement,
396
+ active,
397
+ lastIdx,
398
+ );
347
399
  }
348
400
 
349
401
  if (noChange) return;
350
402
 
351
403
  const rawDelta = idx - (lastIdx ?? 0);
352
- const windowLen =
353
- elm?.children?.length ?? props.displaySize + bufferSize();
404
+ const windowLen = elm?.children?.length ?? props.displaySize + bufferSize();
354
405
  const delta = props.wrap
355
- ? normalizeDeltaForWindow(rawDelta, windowLen)
356
- : rawDelta;
406
+ ? normalizeDeltaForWindow(rawDelta, windowLen)
407
+ : rawDelta;
357
408
 
358
- setCursor(c => {
409
+ setCursor((c) => {
359
410
  const next = c + delta;
360
411
  return props.wrap
361
412
  ? utils.mod(next, total)
@@ -381,19 +432,25 @@ function createVirtual<T>(
381
432
  elm.updateLayout();
382
433
  const childSize = computeSize(slice().selected);
383
434
 
384
- if (cachedAnimationController && cachedAnimationController.state === 'running') {
385
- cachedAnimationController.stop();;
435
+ if (
436
+ cachedAnimationController &&
437
+ cachedAnimationController.state === 'running'
438
+ ) {
439
+ cachedAnimationController.stop();
386
440
  }
387
441
 
388
442
  if (lng.Config.animationsEnabled) {
389
443
  this.lng[axis] = prevChildPos - active[axis];
390
- targetPosition = this.lng[axis] + (childSize * slice().shiftBy);
444
+ targetPosition = this.lng[axis] + childSize * slice().shiftBy;
391
445
  cachedAnimationController = this.animate(
392
446
  { [axis]: targetPosition },
393
- { ...this.animationSettings, duration: getAdaptiveDuration(this.animationSettings?.duration)}
447
+ {
448
+ ...this.animationSettings,
449
+ duration: getAdaptiveDuration(this.animationSettings?.duration),
450
+ },
394
451
  ).start();
395
452
  } else {
396
- this.lng[axis] = this.lng[axis]! + (childSize * slice().shiftBy);
453
+ this.lng[axis] = this.lng[axis]! + childSize * slice().shiftBy;
397
454
  }
398
455
  });
399
456
  };
@@ -407,7 +464,7 @@ function createVirtual<T>(
407
464
 
408
465
  queueMicrotask(() => {
409
466
  viewRef.updateLayout();
410
- let activeIndex = viewRef.children.findIndex(x => x.item === item);
467
+ let activeIndex = viewRef.children.findIndex((x) => x.item === item);
411
468
  if (activeIndex === -1) return;
412
469
  viewRef.selected = activeIndex;
413
470
  if (lng.hasFocus(viewRef)) {
@@ -421,60 +478,72 @@ function createVirtual<T>(
421
478
  originalPosition = originalPosition ?? viewRef.lng[axis];
422
479
  targetPosition = targetPosition ?? viewRef.lng[axis];
423
480
 
424
- viewRef.lng[axis] = (viewRef.lng[axis] || 0) + (childSize * -1);
481
+ viewRef.lng[axis] = (viewRef.lng[axis] || 0) + childSize * -1;
425
482
  });
426
483
  };
427
484
 
428
485
  let doOnce = false;
429
- s.createEffect(s.on([() => props.wrap, items], () => {
430
- if (!viewRef || itemCount() === 0 || !props.wrap || doOnce) return;
431
- doOnce = true;
432
- // offset just for wrap so we keep one item before
433
- queueMicrotask(() => {
434
- const childSize = computeSize(slice().selected);
435
- viewRef.lng[axis] = (viewRef.lng[axis] || 0) + (childSize * -1);
436
- // Original Position is offset to support scrollToIndex
437
- originalPosition = viewRef.lng[axis];
438
- targetPosition = viewRef.lng[axis];
439
- });
440
- }));
486
+ s.createEffect(
487
+ s.on([() => props.wrap, items], () => {
488
+ if (!viewRef || itemCount() === 0 || !props.wrap || doOnce) return;
489
+ doOnce = true;
490
+ // offset just for wrap so we keep one item before
491
+ queueMicrotask(() => {
492
+ const childSize = computeSize(slice().selected);
493
+ viewRef.lng[axis] = (viewRef.lng[axis] || 0) + childSize * -1;
494
+ // Original Position is offset to support scrollToIndex
495
+ originalPosition = viewRef.lng[axis];
496
+ targetPosition = viewRef.lng[axis];
497
+ });
498
+ }),
499
+ );
441
500
 
442
501
  s.createEffect(s.on([() => props.selected, items], updateSelected));
443
502
 
444
- s.createEffect(s.on(items, () => {
445
- if (!viewRef) return;
446
- if (cursor() >= itemCount()) {
447
- setCursor(Math.max(0, itemCount() - 1));
448
- }
449
- const newState = computeSlice(cursor(), 0, slice());
450
- setSlice(newState);
451
- viewRef.selected = newState.selected;
452
- }));
503
+ s.createEffect(
504
+ s.on(items, () => {
505
+ if (!viewRef) return;
506
+ if (cursor() >= itemCount()) {
507
+ setCursor(Math.max(0, itemCount() - 1));
508
+ }
509
+ const newState = computeSlice(cursor(), 0, slice());
510
+ setSlice(newState);
511
+ viewRef.selected = newState.selected;
512
+ }),
513
+ );
453
514
 
454
- return (<view
515
+ return (
516
+ <view
517
+ transition={/* @once */ {}}
518
+ transitionLeft={isRow ? defaultTransitionBack : undefined}
519
+ transitionRight={isRow ? defaultTransitionForward : undefined}
520
+ transitionUp={!isRow ? defaultTransitionUp : undefined}
521
+ transitionDown={!isRow ? defaultTransitionDown : undefined}
455
522
  {...props}
456
523
  {...keyHandlers}
457
- ref={lngp.chainRefs(el => { viewRef = el as lngp.NavigableElement; }, props.ref)}
524
+ ref={lngp.chainRefs((el) => {
525
+ viewRef = el as lngp.NavigableElement;
526
+ }, props.ref)}
458
527
  selected={selected()}
459
528
  cursor={cursor()}
460
529
  forwardFocus={/* @once */ lngp.navigableForwardFocus}
461
530
  scrollToIndex={/* @once */ scrollToIndex}
462
531
  onSelectedChanged={/* @once */ onSelectedChanged}
463
- style={/* @once */ lng.combineStyles(
464
- props.style,
465
- component === lngp.Row
466
- ? {
467
- display: 'flex',
468
- gap: 30,
469
- transition: { x: { duration: 250, easing: 'ease-out' } },
470
- }
471
- : {
472
- display: 'flex',
473
- flexDirection: 'column',
474
- gap: 30,
475
- transition: { y: { duration: 250, easing: 'ease-out' } },
476
- }
477
- )}
532
+ style={
533
+ /* @once */ lng.combineStyles(
534
+ props.style,
535
+ component === lngp.Row
536
+ ? {
537
+ display: 'flex',
538
+ gap: 30,
539
+ }
540
+ : {
541
+ display: 'flex',
542
+ flexDirection: 'column',
543
+ gap: 30,
544
+ },
545
+ )
546
+ }
478
547
  >
479
548
  <List each={slice().slice}>{props.children}</List>
480
549
  </view>
@@ -483,14 +552,26 @@ function createVirtual<T>(
483
552
 
484
553
  export function VirtualRow<T>(props: VirtualProps<T>) {
485
554
  return createVirtual(lngp.Row, props, {
486
- onLeft: lngp.chainFunctions(props.onLeft, lngp.handleNavigation('left')) as lng.KeyHandler,
487
- onRight: lngp.chainFunctions(props.onRight, lngp.handleNavigation('right')) as lng.KeyHandler,
555
+ onLeft: lngp.chainFunctions(
556
+ props.onLeft,
557
+ lngp.handleNavigation('left'),
558
+ ) as lng.KeyHandler,
559
+ onRight: lngp.chainFunctions(
560
+ props.onRight,
561
+ lngp.handleNavigation('right'),
562
+ ) as lng.KeyHandler,
488
563
  });
489
564
  }
490
565
 
491
566
  export function VirtualColumn<T>(props: VirtualProps<T>) {
492
567
  return createVirtual(lngp.Column, props, {
493
- onUp: lngp.chainFunctions(props.onUp, lngp.handleNavigation('up')) as lng.KeyHandler,
494
- onDown: lngp.chainFunctions(props.onDown, lngp.handleNavigation('down')) as lng.KeyHandler,
568
+ onUp: lngp.chainFunctions(
569
+ props.onUp,
570
+ lngp.handleNavigation('up'),
571
+ ) as lng.KeyHandler,
572
+ onDown: lngp.chainFunctions(
573
+ props.onDown,
574
+ lngp.handleNavigation('down'),
575
+ ) as lng.KeyHandler,
495
576
  });
496
577
  }