@lightningtv/solid 3.0.3 → 3.0.4
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/core/elementNode.d.ts +8 -0
- package/dist/src/core/elementNode.js +36 -16
- package/dist/src/core/elementNode.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/primitives/index.d.ts +1 -1
- package/dist/src/primitives/index.js +1 -1
- package/dist/src/primitives/index.js.map +1 -1
- package/dist/src/primitives/utils/handleNavigation.js +2 -1
- package/dist/src/primitives/utils/handleNavigation.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/core/elementNode.ts +126 -41
- package/src/core/intrinsicTypes.ts +25 -5
- package/src/index.ts +10 -1
- package/src/primitives/index.ts +5 -1
- package/src/primitives/utils/handleNavigation.ts +39 -10
package/src/core/elementNode.ts
CHANGED
|
@@ -49,7 +49,11 @@ import type {
|
|
|
49
49
|
} from '@lightningjs/renderer';
|
|
50
50
|
import { assertTruthy } from '@lightningjs/renderer/utils';
|
|
51
51
|
import { NodeType } from './nodeTypes.js';
|
|
52
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
ForwardFocusHandler,
|
|
54
|
+
setActiveElement,
|
|
55
|
+
FocusNode,
|
|
56
|
+
} from './focusManager.js';
|
|
53
57
|
import simpleAnimation, { SimpleAnimationSettings } from './animation.js';
|
|
54
58
|
|
|
55
59
|
let layoutRunQueued = false;
|
|
@@ -73,7 +77,11 @@ function runLayout() {
|
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
|
|
76
|
-
const parseAndAssignShaderProps = (
|
|
80
|
+
const parseAndAssignShaderProps = (
|
|
81
|
+
prefix: string,
|
|
82
|
+
obj: Record<string, any>,
|
|
83
|
+
props: Record<string, any> = {},
|
|
84
|
+
) => {
|
|
77
85
|
if (!obj) return;
|
|
78
86
|
props[prefix] = obj;
|
|
79
87
|
Object.entries(obj).forEach(([key, value]) => {
|
|
@@ -172,7 +180,12 @@ declare global {
|
|
|
172
180
|
}
|
|
173
181
|
|
|
174
182
|
export type RendererNode = AddColorString<
|
|
175
|
-
Partial<
|
|
183
|
+
Partial<
|
|
184
|
+
NewOmit<
|
|
185
|
+
INode,
|
|
186
|
+
'parent' | 'shader' | 'src' | 'children' | 'id' | 'removeChild'
|
|
187
|
+
>
|
|
188
|
+
>
|
|
176
189
|
>;
|
|
177
190
|
export interface ElementNode extends RendererNode, FocusNode {
|
|
178
191
|
[key: string]: unknown;
|
|
@@ -257,7 +270,10 @@ export interface ElementNode extends RendererNode, FocusNode {
|
|
|
257
270
|
/**
|
|
258
271
|
* The underlying Lightning Renderer node object. This is where the properties are ultimately set for rendering.
|
|
259
272
|
*/
|
|
260
|
-
lng:
|
|
273
|
+
lng:
|
|
274
|
+
| Partial<ElementNode>
|
|
275
|
+
| IRendererNode
|
|
276
|
+
| (IRendererTextNode & { shader?: any });
|
|
261
277
|
/**
|
|
262
278
|
* A reference to the `ElementNode` instance. Can be an object or a callback function.
|
|
263
279
|
*/
|
|
@@ -413,7 +429,13 @@ export interface ElementNode extends RendererNode, FocusNode {
|
|
|
413
429
|
*
|
|
414
430
|
* @see @see https://lightning-tv.github.io/solid/#/flow/layout?id=flex
|
|
415
431
|
*/
|
|
416
|
-
justifyContent?:
|
|
432
|
+
justifyContent?:
|
|
433
|
+
| 'flexStart'
|
|
434
|
+
| 'flexEnd'
|
|
435
|
+
| 'center'
|
|
436
|
+
| 'spaceBetween'
|
|
437
|
+
| 'spaceAround'
|
|
438
|
+
| 'spaceEvenly';
|
|
417
439
|
/**
|
|
418
440
|
* Applies a linear gradient effect to the element.
|
|
419
441
|
*
|
|
@@ -486,6 +508,14 @@ export interface ElementNode extends RendererNode, FocusNode {
|
|
|
486
508
|
* @see https://lightning-tv.github.io/solid/#/flow/layout
|
|
487
509
|
*/
|
|
488
510
|
h: number;
|
|
511
|
+
/**
|
|
512
|
+
* The maximum width of the element.
|
|
513
|
+
*/
|
|
514
|
+
maxWidth?: number;
|
|
515
|
+
/**
|
|
516
|
+
* The maximum height of the element.
|
|
517
|
+
*/
|
|
518
|
+
maxHeight?: number;
|
|
489
519
|
/**
|
|
490
520
|
* The z-index of the element, which affects its stacking order.
|
|
491
521
|
*
|
|
@@ -497,7 +527,10 @@ export interface ElementNode extends RendererNode, FocusNode {
|
|
|
497
527
|
*
|
|
498
528
|
* @see https://lightning-tv.github.io/solid/#/essentials/transitions?id=transitions-animations
|
|
499
529
|
*/
|
|
500
|
-
transition?:
|
|
530
|
+
transition?:
|
|
531
|
+
| Record<string, AnimationSettings | undefined | true | false>
|
|
532
|
+
| true
|
|
533
|
+
| false;
|
|
501
534
|
/**
|
|
502
535
|
* Optional handlers for animation events.
|
|
503
536
|
*
|
|
@@ -628,19 +661,19 @@ export class ElementNode extends Object {
|
|
|
628
661
|
}
|
|
629
662
|
}
|
|
630
663
|
|
|
631
|
-
get height() {
|
|
632
|
-
return this.h;
|
|
664
|
+
get height(): number {
|
|
665
|
+
return this.maxHeight || this.h;
|
|
633
666
|
}
|
|
634
667
|
|
|
635
|
-
set height(h) {
|
|
668
|
+
set height(h: number) {
|
|
636
669
|
this.h = h;
|
|
637
670
|
}
|
|
638
671
|
|
|
639
|
-
get width() {
|
|
640
|
-
return this.w;
|
|
672
|
+
get width(): number {
|
|
673
|
+
return this.maxWidth || this.w;
|
|
641
674
|
}
|
|
642
675
|
|
|
643
|
-
set width(w) {
|
|
676
|
+
set width(w: number) {
|
|
644
677
|
this.w = w;
|
|
645
678
|
}
|
|
646
679
|
|
|
@@ -650,7 +683,10 @@ export class ElementNode extends Object {
|
|
|
650
683
|
}
|
|
651
684
|
|
|
652
685
|
this._fontWeight = v;
|
|
653
|
-
const weight =
|
|
686
|
+
const weight =
|
|
687
|
+
(Config.fontWeightAlias &&
|
|
688
|
+
(Config.fontWeightAlias[v as string] as number | string)) ??
|
|
689
|
+
v;
|
|
654
690
|
(this.lng as any).fontFamily = `${this.fontFamily}${weight}`;
|
|
655
691
|
}
|
|
656
692
|
|
|
@@ -667,7 +703,10 @@ export class ElementNode extends Object {
|
|
|
667
703
|
return this._fontFamily || Config.fontSettings?.fontFamily;
|
|
668
704
|
}
|
|
669
705
|
|
|
670
|
-
insertChild(
|
|
706
|
+
insertChild(
|
|
707
|
+
node: ElementNode | ElementText | TextNode,
|
|
708
|
+
beforeNode?: ElementNode | ElementText | TextNode | null,
|
|
709
|
+
) {
|
|
671
710
|
// always remove nodes if they have a parent - for back swap of node
|
|
672
711
|
// this will then put the node at the end of the array when re-added
|
|
673
712
|
if (node.parent) {
|
|
@@ -716,8 +755,12 @@ export class ElementNode extends Object {
|
|
|
716
755
|
return undefined;
|
|
717
756
|
}
|
|
718
757
|
|
|
719
|
-
set shader(
|
|
720
|
-
|
|
758
|
+
set shader(
|
|
759
|
+
shaderProps: IRendererShader | [kind: string, props: IRendererShaderProps],
|
|
760
|
+
) {
|
|
761
|
+
this.lng.shader = isArray(shaderProps)
|
|
762
|
+
? renderer.createShader(...shaderProps)
|
|
763
|
+
: shaderProps;
|
|
721
764
|
}
|
|
722
765
|
|
|
723
766
|
_sendToLightningAnimatable(name: string, value: number) {
|
|
@@ -725,7 +768,9 @@ export class ElementNode extends Object {
|
|
|
725
768
|
this.transition &&
|
|
726
769
|
this.rendered &&
|
|
727
770
|
Config.animationsEnabled &&
|
|
728
|
-
(this.transition === true ||
|
|
771
|
+
(this.transition === true ||
|
|
772
|
+
this.transition[name] ||
|
|
773
|
+
this.transition[getPropertyAlias(name)])
|
|
729
774
|
) {
|
|
730
775
|
const animationSettings =
|
|
731
776
|
this.transition === true || this.transition[name] === true
|
|
@@ -737,20 +782,29 @@ export class ElementNode extends Object {
|
|
|
737
782
|
this,
|
|
738
783
|
name,
|
|
739
784
|
value,
|
|
740
|
-
animationSettings ||
|
|
785
|
+
animationSettings ||
|
|
786
|
+
(this.animationSettings as SimpleAnimationSettings),
|
|
741
787
|
);
|
|
742
788
|
simpleAnimation.register(renderer.stage);
|
|
743
789
|
return;
|
|
744
790
|
} else {
|
|
745
|
-
const animationController = this.animate(
|
|
791
|
+
const animationController = this.animate(
|
|
792
|
+
{ [name]: value },
|
|
793
|
+
animationSettings,
|
|
794
|
+
);
|
|
746
795
|
|
|
747
796
|
if (this.onAnimation) {
|
|
748
|
-
const animationEvents = Object.keys(
|
|
797
|
+
const animationEvents = Object.keys(
|
|
798
|
+
this.onAnimation,
|
|
799
|
+
) as AnimationEvents[];
|
|
749
800
|
for (const event of animationEvents) {
|
|
750
801
|
const handler = this.onAnimation[event];
|
|
751
|
-
animationController.on(
|
|
752
|
-
|
|
753
|
-
|
|
802
|
+
animationController.on(
|
|
803
|
+
event,
|
|
804
|
+
(controller: IAnimationController, props?: any) => {
|
|
805
|
+
handler!.call(this, controller, name, value, props);
|
|
806
|
+
},
|
|
807
|
+
);
|
|
754
808
|
}
|
|
755
809
|
}
|
|
756
810
|
|
|
@@ -765,11 +819,18 @@ export class ElementNode extends Object {
|
|
|
765
819
|
props: Partial<INodeAnimateProps<CoreShaderNode>>,
|
|
766
820
|
animationSettings?: AnimationSettings,
|
|
767
821
|
): IAnimationController {
|
|
768
|
-
isDev &&
|
|
769
|
-
|
|
822
|
+
isDev &&
|
|
823
|
+
assertTruthy(this.rendered, 'Node must be rendered before animating');
|
|
824
|
+
return (this.lng as IRendererNode).animate(
|
|
825
|
+
props,
|
|
826
|
+
animationSettings || this.animationSettings || {},
|
|
827
|
+
);
|
|
770
828
|
}
|
|
771
829
|
|
|
772
|
-
chain(
|
|
830
|
+
chain(
|
|
831
|
+
props: Partial<INodeAnimateProps<CoreShaderNode>>,
|
|
832
|
+
animationSettings?: AnimationSettings,
|
|
833
|
+
) {
|
|
773
834
|
if (this._animationRunning) {
|
|
774
835
|
this._animationQueue = [];
|
|
775
836
|
this._animationRunning = false;
|
|
@@ -778,7 +839,8 @@ export class ElementNode extends Object {
|
|
|
778
839
|
if (animationSettings) {
|
|
779
840
|
this._animationQueueSettings = animationSettings;
|
|
780
841
|
} else if (!this._animationQueueSettings) {
|
|
781
|
-
this._animationQueueSettings =
|
|
842
|
+
this._animationQueueSettings =
|
|
843
|
+
animationSettings || this.animationSettings;
|
|
782
844
|
}
|
|
783
845
|
animationSettings = animationSettings || this._animationQueueSettings;
|
|
784
846
|
this._animationQueue = this._animationQueue || [];
|
|
@@ -790,7 +852,9 @@ export class ElementNode extends Object {
|
|
|
790
852
|
let animation = this._animationQueue!.shift();
|
|
791
853
|
while (animation) {
|
|
792
854
|
this._animationRunning = true;
|
|
793
|
-
await this.animate(animation.props, animation.animationSettings)
|
|
855
|
+
await this.animate(animation.props, animation.animationSettings)
|
|
856
|
+
.start()
|
|
857
|
+
.waitUntilStopped();
|
|
794
858
|
animation = this._animationQueue!.shift();
|
|
795
859
|
}
|
|
796
860
|
this._animationRunning = false;
|
|
@@ -822,7 +886,8 @@ export class ElementNode extends Object {
|
|
|
822
886
|
return;
|
|
823
887
|
}
|
|
824
888
|
} else {
|
|
825
|
-
const focusedIndex =
|
|
889
|
+
const focusedIndex =
|
|
890
|
+
typeof this.forwardFocus === 'number' ? this.forwardFocus : null;
|
|
826
891
|
const nodes = this.children;
|
|
827
892
|
if (focusedIndex !== null && focusedIndex < nodes.length) {
|
|
828
893
|
const child = nodes[focusedIndex];
|
|
@@ -946,7 +1011,9 @@ export class ElementNode extends Object {
|
|
|
946
1011
|
}
|
|
947
1012
|
|
|
948
1013
|
set states(states: NodeStates) {
|
|
949
|
-
this._states = this._states
|
|
1014
|
+
this._states = this._states
|
|
1015
|
+
? this._states.merge(states)
|
|
1016
|
+
: new States(this._stateChanged.bind(this), states);
|
|
950
1017
|
if (this.rendered) {
|
|
951
1018
|
this._stateChanged();
|
|
952
1019
|
}
|
|
@@ -1014,7 +1081,8 @@ export class ElementNode extends Object {
|
|
|
1014
1081
|
|
|
1015
1082
|
const flexChanged = this.display === 'flex' && calculateFlex(this);
|
|
1016
1083
|
layoutQueue.delete(this);
|
|
1017
|
-
const onLayoutChanged =
|
|
1084
|
+
const onLayoutChanged =
|
|
1085
|
+
isFunc(this.onLayout) && this.onLayout.call(this, this);
|
|
1018
1086
|
|
|
1019
1087
|
if ((flexChanged || onLayoutChanged) && this.parent) {
|
|
1020
1088
|
addToLayoutQueue(this.parent);
|
|
@@ -1071,7 +1139,9 @@ export class ElementNode extends Object {
|
|
|
1071
1139
|
let newStyles: Styles;
|
|
1072
1140
|
if (numStates === 1) {
|
|
1073
1141
|
newStyles = this[states[0] as keyof Styles] as Styles;
|
|
1074
|
-
newStyles = stylesToUndo
|
|
1142
|
+
newStyles = stylesToUndo
|
|
1143
|
+
? { ...stylesToUndo, ...newStyles }
|
|
1144
|
+
: newStyles;
|
|
1075
1145
|
} else {
|
|
1076
1146
|
newStyles = states.reduce((acc, state) => {
|
|
1077
1147
|
const styles = this[state];
|
|
@@ -1186,13 +1256,17 @@ export class ElementNode extends Object {
|
|
|
1186
1256
|
}
|
|
1187
1257
|
|
|
1188
1258
|
if (!textProps.maxWidth) {
|
|
1189
|
-
textProps.maxWidth =
|
|
1259
|
+
textProps.maxWidth =
|
|
1260
|
+
parentWidth - textProps.x! - (textProps.marginRight || 0);
|
|
1190
1261
|
}
|
|
1191
1262
|
|
|
1192
1263
|
if (textProps.contain === 'both' && !textProps.maxHeight) {
|
|
1193
|
-
textProps.maxHeight =
|
|
1264
|
+
textProps.maxHeight =
|
|
1265
|
+
parentHeight - textProps.y! - (textProps.marginBottom || 0);
|
|
1194
1266
|
} else if (textProps.maxLines === 1) {
|
|
1195
|
-
textProps.maxHeight = (textProps.maxHeight ||
|
|
1267
|
+
textProps.maxHeight = (textProps.maxHeight ||
|
|
1268
|
+
textProps.lineHeight ||
|
|
1269
|
+
textProps.fontSize) as number;
|
|
1196
1270
|
}
|
|
1197
1271
|
|
|
1198
1272
|
textProps.w = textProps.h = undefined;
|
|
@@ -1204,7 +1278,9 @@ export class ElementNode extends Object {
|
|
|
1204
1278
|
}
|
|
1205
1279
|
|
|
1206
1280
|
isDev && log('Rendering: ', this, props);
|
|
1207
|
-
node.lng = renderer.createTextNode(
|
|
1281
|
+
node.lng = renderer.createTextNode(
|
|
1282
|
+
props as unknown as IRendererTextNodeProps,
|
|
1283
|
+
);
|
|
1208
1284
|
if (parent.requiresLayout()) {
|
|
1209
1285
|
if (!textProps.maxWidth || !textProps.maxHeight) {
|
|
1210
1286
|
node._layoutOnLoad();
|
|
@@ -1334,7 +1410,9 @@ function createRawShaderAccessor<T>(key: keyof StyleEffects) {
|
|
|
1334
1410
|
};
|
|
1335
1411
|
}
|
|
1336
1412
|
|
|
1337
|
-
function shaderAccessor<T extends Record<string, any> | number>(
|
|
1413
|
+
function shaderAccessor<T extends Record<string, any> | number>(
|
|
1414
|
+
key: 'border' | 'shadow' | 'rounded',
|
|
1415
|
+
) {
|
|
1338
1416
|
return {
|
|
1339
1417
|
set(this: ElementNode, value: T) {
|
|
1340
1418
|
let target = this.lng.shader || {};
|
|
@@ -1343,12 +1421,17 @@ function shaderAccessor<T extends Record<string, any> | number>(key: 'border' |
|
|
|
1343
1421
|
if (this.lng.shader?.program) {
|
|
1344
1422
|
target = this.lng.shader.props;
|
|
1345
1423
|
const transitionKey = key === 'rounded' ? 'borderRadius' : key;
|
|
1346
|
-
if (
|
|
1424
|
+
if (
|
|
1425
|
+
this.transition &&
|
|
1426
|
+
(this.transition === true || this.transition[transitionKey])
|
|
1427
|
+
) {
|
|
1347
1428
|
target = {};
|
|
1348
1429
|
animationSettings =
|
|
1349
1430
|
this.transition === true || this.transition[transitionKey] === true
|
|
1350
1431
|
? undefined
|
|
1351
|
-
: (this.transition[transitionKey] as
|
|
1432
|
+
: (this.transition[transitionKey] as
|
|
1433
|
+
| undefined
|
|
1434
|
+
| AnimationSettings);
|
|
1352
1435
|
}
|
|
1353
1436
|
}
|
|
1354
1437
|
|
|
@@ -1388,6 +1471,8 @@ Object.defineProperties(ElementNode.prototype, {
|
|
|
1388
1471
|
rounded: shaderAccessor<BorderRadius>('rounded'),
|
|
1389
1472
|
// Alias for rounded
|
|
1390
1473
|
borderRadius: shaderAccessor<BorderRadius>('rounded'),
|
|
1391
|
-
linearGradient:
|
|
1392
|
-
|
|
1474
|
+
linearGradient:
|
|
1475
|
+
createRawShaderAccessor<LinearGradientProps>('linearGradient'),
|
|
1476
|
+
radialGradient:
|
|
1477
|
+
createRawShaderAccessor<RadialGradientProps>('radialGradient'),
|
|
1393
1478
|
});
|
|
@@ -9,7 +9,12 @@ import {
|
|
|
9
9
|
ShaderRoundedProps,
|
|
10
10
|
ShaderShadowProps,
|
|
11
11
|
} from './shaders.js';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
EventHandlers,
|
|
14
|
+
DefaultKeyMap,
|
|
15
|
+
KeyHoldMap,
|
|
16
|
+
FocusNode,
|
|
17
|
+
} from './focusKeyTypes.js';
|
|
13
18
|
import type { JSXElement } from 'solid-js';
|
|
14
19
|
|
|
15
20
|
export type AnimationSettings = Partial<lngr.AnimationSettings>;
|
|
@@ -47,7 +52,9 @@ export type RemoveUnderscoreProps<T> = {
|
|
|
47
52
|
[K in keyof T as K extends `_${string}` ? never : K]: T[K];
|
|
48
53
|
};
|
|
49
54
|
|
|
50
|
-
type RendererText = AddColorString<
|
|
55
|
+
type RendererText = AddColorString<
|
|
56
|
+
Partial<Omit<lngr.ITextNodeProps, 'debug' | 'shader' | 'parent'>>
|
|
57
|
+
>;
|
|
51
58
|
|
|
52
59
|
type CleanElementNode = NewOmit<
|
|
53
60
|
RemoveUnderscoreProps<ElementNode>,
|
|
@@ -73,7 +80,10 @@ type CleanElementNode = NewOmit<
|
|
|
73
80
|
>;
|
|
74
81
|
/** Node text, children of a ElementNode of type TextNode */
|
|
75
82
|
export interface ElementText
|
|
76
|
-
extends NewOmit<
|
|
83
|
+
extends NewOmit<
|
|
84
|
+
ElementNode,
|
|
85
|
+
'_type' | 'parent' | 'children' | 'src' | 'scale' | 'fontFamily'
|
|
86
|
+
>,
|
|
77
87
|
NewOmit<RendererText, 'x' | 'y' | 'w' | 'h'> {
|
|
78
88
|
_type: 'textNode';
|
|
79
89
|
parent?: ElementNode;
|
|
@@ -97,7 +107,14 @@ export interface NodeProps
|
|
|
97
107
|
Partial<
|
|
98
108
|
NewOmit<
|
|
99
109
|
CleanElementNode,
|
|
100
|
-
|
|
110
|
+
| 'children'
|
|
111
|
+
| 'text'
|
|
112
|
+
| 'lng'
|
|
113
|
+
| 'rendered'
|
|
114
|
+
| 'renderer'
|
|
115
|
+
| 'emit'
|
|
116
|
+
| 'preFlexwidth'
|
|
117
|
+
| 'preFlexHeight'
|
|
101
118
|
>
|
|
102
119
|
> {
|
|
103
120
|
states?: NodeStates;
|
|
@@ -172,7 +189,10 @@ type EventPayloadMap = {
|
|
|
172
189
|
|
|
173
190
|
type NodeEvents = keyof EventPayloadMap;
|
|
174
191
|
|
|
175
|
-
type EventHandler<E extends NodeEvents> = (
|
|
192
|
+
type EventHandler<E extends NodeEvents> = (
|
|
193
|
+
target: ElementNode,
|
|
194
|
+
event?: EventPayloadMap[E],
|
|
195
|
+
) => void;
|
|
176
196
|
|
|
177
197
|
export type OnEvent = Partial<{
|
|
178
198
|
[K in NodeEvents]: EventHandler<K>;
|
package/src/index.ts
CHANGED
|
@@ -6,4 +6,13 @@ export * from './activeElement.js';
|
|
|
6
6
|
export * from './utils.js';
|
|
7
7
|
export * from './render.js';
|
|
8
8
|
export * from './types.js';
|
|
9
|
-
export {
|
|
9
|
+
export {
|
|
10
|
+
For,
|
|
11
|
+
Show,
|
|
12
|
+
Suspense,
|
|
13
|
+
SuspenseList,
|
|
14
|
+
Switch,
|
|
15
|
+
Match,
|
|
16
|
+
Index,
|
|
17
|
+
ErrorBoundary,
|
|
18
|
+
} from 'solid-js';
|
package/src/primitives/index.ts
CHANGED
|
@@ -24,7 +24,11 @@ export * from './VirtualGrid.jsx';
|
|
|
24
24
|
export * from './Virtual.jsx';
|
|
25
25
|
export * from './utils/withScrolling.js';
|
|
26
26
|
export * from './createTag.jsx';
|
|
27
|
-
export {
|
|
27
|
+
export {
|
|
28
|
+
type AnyFunction,
|
|
29
|
+
chainFunctions,
|
|
30
|
+
chainRefs,
|
|
31
|
+
} from './utils/chainFunctions.js';
|
|
28
32
|
export * from './utils/handleNavigation.js';
|
|
29
33
|
export { createSpriteMap, type SpriteDef } from './utils/createSpriteMap.js';
|
|
30
34
|
export { createBlurredImage } from './utils/createBlurredImage.js';
|
|
@@ -6,7 +6,11 @@ function idxInArray(idx: number, arr: readonly any[]): boolean {
|
|
|
6
6
|
return idx >= 0 && idx < arr.length;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
function findFirstFocusableChildIdx(
|
|
9
|
+
function findFirstFocusableChildIdx(
|
|
10
|
+
el: lngp.NavigableElement,
|
|
11
|
+
from = 0,
|
|
12
|
+
delta = 1,
|
|
13
|
+
): number {
|
|
10
14
|
for (let i = from; ; i += delta) {
|
|
11
15
|
if (!idxInArray(i, el.children)) {
|
|
12
16
|
if (el.wrap) {
|
|
@@ -42,7 +46,9 @@ function selectChild(el: lngp.NavigableElement, index: number): boolean {
|
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
/** @deprecated Use {@link navigableForwardFocus} instead */
|
|
45
|
-
export function onGridFocus(
|
|
49
|
+
export function onGridFocus(
|
|
50
|
+
_?: lngp.OnSelectedChanged,
|
|
51
|
+
): lng.ForwardFocusHandler {
|
|
46
52
|
return function () {
|
|
47
53
|
return navigableForwardFocus.call(this, this);
|
|
48
54
|
};
|
|
@@ -83,9 +89,14 @@ export const navigableForwardFocus: lng.ForwardFocusHandler = function () {
|
|
|
83
89
|
return selectChild(navigable, selected);
|
|
84
90
|
};
|
|
85
91
|
|
|
86
|
-
export function handleNavigation(
|
|
92
|
+
export function handleNavigation(
|
|
93
|
+
direction: 'up' | 'right' | 'down' | 'left',
|
|
94
|
+
): lng.KeyHandler {
|
|
87
95
|
return function () {
|
|
88
|
-
return moveSelection(
|
|
96
|
+
return moveSelection(
|
|
97
|
+
this as lngp.NavigableElement,
|
|
98
|
+
direction === 'up' || direction === 'left' ? -1 : 1,
|
|
99
|
+
);
|
|
89
100
|
};
|
|
90
101
|
}
|
|
91
102
|
|
|
@@ -106,13 +117,19 @@ export function handleNavigation(direction: 'up' | 'right' | 'down' | 'left'): l
|
|
|
106
117
|
* ```
|
|
107
118
|
*/
|
|
108
119
|
export const navigableHandleNavigation: lng.KeyHandler = function (e) {
|
|
109
|
-
return moveSelection(
|
|
120
|
+
return moveSelection(
|
|
121
|
+
this as lngp.NavigableElement,
|
|
122
|
+
e.key === 'ArrowUp' || e.key === 'ArrowLeft' ? -1 : 1,
|
|
123
|
+
);
|
|
110
124
|
};
|
|
111
125
|
|
|
112
126
|
/**
|
|
113
127
|
* Moves the selection within a {@link lngp.NavigableElement}.
|
|
114
128
|
*/
|
|
115
|
-
export function moveSelection(
|
|
129
|
+
export function moveSelection(
|
|
130
|
+
el: lngp.NavigableElement,
|
|
131
|
+
delta: number,
|
|
132
|
+
): boolean {
|
|
116
133
|
let selected = findFirstFocusableChildIdx(el, el.selected + delta, delta);
|
|
117
134
|
|
|
118
135
|
if (selected === -1) {
|
|
@@ -135,7 +152,8 @@ export function moveSelection(el: lngp.NavigableElement, delta: number): boolean
|
|
|
135
152
|
lng.assertTruthy(lastSelectedChild instanceof lng.ElementNode);
|
|
136
153
|
|
|
137
154
|
const num = lastSelectedChild.selected || 0;
|
|
138
|
-
active.selected =
|
|
155
|
+
active.selected =
|
|
156
|
+
num < active.children.length ? num : active.children.length - 1;
|
|
139
157
|
}
|
|
140
158
|
|
|
141
159
|
return selectChild(el, selected);
|
|
@@ -147,7 +165,10 @@ function distanceBetweenRectCenters(a: lng.Rect, b: lng.Rect): number {
|
|
|
147
165
|
return Math.sqrt(dx * dx + dy * dy);
|
|
148
166
|
}
|
|
149
167
|
|
|
150
|
-
function findClosestFocusableChildIdx(
|
|
168
|
+
function findClosestFocusableChildIdx(
|
|
169
|
+
el: lng.ElementNode,
|
|
170
|
+
prevEl: lng.ElementNode,
|
|
171
|
+
): number {
|
|
151
172
|
// select child closest to the previous active element
|
|
152
173
|
const prevRect = lng.getElementScreenRect(prevEl);
|
|
153
174
|
const elRect = lng.getElementScreenRect(el);
|
|
@@ -255,7 +276,11 @@ export const spatialHandleNavigation: lng.KeyHandler = function (e) {
|
|
|
255
276
|
|
|
256
277
|
// Select next/prev child in the current column/row
|
|
257
278
|
if (flexDelta !== 0) {
|
|
258
|
-
for (
|
|
279
|
+
for (
|
|
280
|
+
let i = selected + flexDelta;
|
|
281
|
+
idxInArray(i, this.children);
|
|
282
|
+
i += flexDelta
|
|
283
|
+
) {
|
|
259
284
|
const child = this.children[i]!;
|
|
260
285
|
if (child.skipFocus) continue;
|
|
261
286
|
|
|
@@ -270,7 +295,11 @@ export const spatialHandleNavigation: lng.KeyHandler = function (e) {
|
|
|
270
295
|
let closestIdx = -1;
|
|
271
296
|
let closestDist = Infinity;
|
|
272
297
|
|
|
273
|
-
for (
|
|
298
|
+
for (
|
|
299
|
+
let i = selected + crossDelta;
|
|
300
|
+
idxInArray(i, this.children);
|
|
301
|
+
i += crossDelta
|
|
302
|
+
) {
|
|
274
303
|
const child = this.children[i]!;
|
|
275
304
|
if (child.skipFocus) continue;
|
|
276
305
|
|