@lightningtv/solid 0.0.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/LICENSE +202 -0
- package/NOTICE +7 -0
- package/README.md +44 -0
- package/dist/esm/index.js +462 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/source/Text.jsx +1 -0
- package/dist/source/View.jsx +1 -0
- package/dist/source/activeElement.js +4 -0
- package/dist/source/index.js +8 -0
- package/dist/source/jsx-runtime.js +1 -0
- package/dist/source/render.js +57 -0
- package/dist/source/solidOpts.js +61 -0
- package/dist/source/utils.js +26 -0
- package/dist/types/Text.d.ts +3 -0
- package/dist/types/View.d.ts +3 -0
- package/dist/types/activeElement.d.ts +2 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/jsx-runtime.d.ts +10 -0
- package/dist/types/render.d.ts +21 -0
- package/dist/types/solidOpts.d.ts +17 -0
- package/dist/types/utils.d.ts +8 -0
- package/package.json +76 -0
- package/src/Text.tsx +6 -0
- package/src/View.tsx +6 -0
- package/src/activeElement.ts +7 -0
- package/src/index.ts +17 -0
- package/src/jsx-runtime.ts +12 -0
- package/src/render.ts +104 -0
- package/src/solidOpts.ts +69 -0
- package/src/utils.ts +33 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { assertTruthy } from '@lightningjs/renderer/utils';
|
|
2
|
+
import { ElementNode, log } from '@lightningtv/core';
|
|
3
|
+
export default {
|
|
4
|
+
createElement(name) {
|
|
5
|
+
return new ElementNode(name);
|
|
6
|
+
},
|
|
7
|
+
createTextNode(text) {
|
|
8
|
+
// A text node is just a string - not the <text> node
|
|
9
|
+
return { type: 2 /* NodeTypes.Text */, text, parent: undefined };
|
|
10
|
+
},
|
|
11
|
+
replaceText(node, value) {
|
|
12
|
+
log('Replace Text: ', node, value);
|
|
13
|
+
node.text = value;
|
|
14
|
+
const parent = node.parent;
|
|
15
|
+
assertTruthy(parent);
|
|
16
|
+
parent.text = parent.getText();
|
|
17
|
+
},
|
|
18
|
+
setProperty(node, name, value = true) {
|
|
19
|
+
node[name] = value;
|
|
20
|
+
},
|
|
21
|
+
insertNode(parent, node, anchor) {
|
|
22
|
+
log('INSERT: ', parent, node, anchor);
|
|
23
|
+
parent.children.insert(node, anchor);
|
|
24
|
+
node._queueDelete = false;
|
|
25
|
+
if (node instanceof ElementNode) {
|
|
26
|
+
parent.rendered && node.render();
|
|
27
|
+
}
|
|
28
|
+
else if (parent.isTextNode()) {
|
|
29
|
+
// TextNodes can be placed outside of <text> nodes when <Show> is used as placeholder
|
|
30
|
+
parent.text = parent.getText();
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
isTextNode(node) {
|
|
34
|
+
return node.isTextNode();
|
|
35
|
+
},
|
|
36
|
+
removeNode(parent, node) {
|
|
37
|
+
log('REMOVE: ', parent, node);
|
|
38
|
+
parent.children.remove(node);
|
|
39
|
+
node._queueDelete = true;
|
|
40
|
+
if (node instanceof ElementNode) {
|
|
41
|
+
// Solid replacesNodes to move them (via insert and remove),
|
|
42
|
+
// so we need to wait for the next microtask to destroy the node
|
|
43
|
+
// in the event it gets a new parent.
|
|
44
|
+
queueMicrotask(() => node.destroy());
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
getParentNode(node) {
|
|
48
|
+
return node.parent;
|
|
49
|
+
},
|
|
50
|
+
getFirstChild(node) {
|
|
51
|
+
return node.children[0];
|
|
52
|
+
},
|
|
53
|
+
getNextSibling(node) {
|
|
54
|
+
const children = node.parent.children || [];
|
|
55
|
+
const index = children.indexOf(node) + 1;
|
|
56
|
+
if (index < children.length) {
|
|
57
|
+
return children[index];
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
},
|
|
61
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { isInteger } from '@lightningtv/core';
|
|
2
|
+
/**
|
|
3
|
+
* Converts a color string to a color number value.
|
|
4
|
+
*/
|
|
5
|
+
export function hexColor(color = '') {
|
|
6
|
+
if (isInteger(color)) {
|
|
7
|
+
return color;
|
|
8
|
+
}
|
|
9
|
+
if (typeof color === 'string') {
|
|
10
|
+
// Renderer expects RGBA values
|
|
11
|
+
if (color.startsWith('#')) {
|
|
12
|
+
return Number(color.replace('#', '0x') + (color.length === 7 ? 'ff' : ''));
|
|
13
|
+
}
|
|
14
|
+
if (color.startsWith('0x')) {
|
|
15
|
+
return Number(color);
|
|
16
|
+
}
|
|
17
|
+
return Number('0x' + (color.length === 6 ? color + 'ff' : color));
|
|
18
|
+
}
|
|
19
|
+
return 0x00000000;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Converts degrees to radians
|
|
23
|
+
*/
|
|
24
|
+
export function deg2rad(deg) {
|
|
25
|
+
return (deg * Math.PI) / 180;
|
|
26
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import './jsx-runtime.js';
|
|
2
|
+
export { For, Show, Suspense, SuspenseList, Switch, Match, Index, ErrorBoundary, } from 'solid-js';
|
|
3
|
+
export * from '@lightningtv/core';
|
|
4
|
+
export * from './activeElement.js';
|
|
5
|
+
export { View } from './View.jsx';
|
|
6
|
+
export { Text } from './Text.jsx';
|
|
7
|
+
export * from './utils.js';
|
|
8
|
+
export * from './render.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IntrinsicNodeProps, IntrinsicTextProps } from '@lightningtv/core';
|
|
2
|
+
declare module 'solid-js' {
|
|
3
|
+
namespace JSX {
|
|
4
|
+
interface IntrinsicElements {
|
|
5
|
+
node: Partial<IntrinsicNodeProps>;
|
|
6
|
+
view: Partial<IntrinsicNodeProps>;
|
|
7
|
+
text: Partial<IntrinsicTextProps>;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type SolidNode } from '@lightningtv/core';
|
|
2
|
+
import { type JSXElement, type ValidComponent } from 'solid-js';
|
|
3
|
+
import type { RendererMainSettings } from '@lightningjs/renderer';
|
|
4
|
+
export declare function startLightning(options?: Partial<RendererMainSettings>, rootId?: string | HTMLElement): Promise<any>;
|
|
5
|
+
export declare const render: (code: () => JSXElement, node?: HTMLElement | string) => Promise<{
|
|
6
|
+
dispose: () => void;
|
|
7
|
+
rootNode: import("@lightningtv/core").ElementNode;
|
|
8
|
+
renderer: RendererMain;
|
|
9
|
+
}>;
|
|
10
|
+
export declare const renderSync: (code: () => JSXElement) => () => void;
|
|
11
|
+
export declare const effect: <T>(fn: (prev?: T) => T, init?: T) => void, memo: <T>(fn: () => T, equal: boolean) => () => T, createComponent: <T>(Comp: (props: T) => SolidNode, props: T) => SolidNode, createElement: (tag: string) => SolidNode, createTextNode: (value: string) => SolidNode, insertNode: (parent: SolidNode, node: SolidNode, anchor?: SolidNode) => void, insert: <T>(parent: any, accessor: T | (() => T), marker?: any) => SolidNode, spread: <T>(node: any, accessor: T | (() => T), skipChildren?: Boolean) => void, setProp: <T>(node: SolidNode, name: string, value: T, prev?: T) => T, mergeProps: (...sources: unknown[]) => unknown, use: <A, T>(fn: (element: SolidNode, arg: A) => T, element: SolidNode, arg: A) => T;
|
|
12
|
+
/**
|
|
13
|
+
* renders an arbitrary custom or native component and passes the other props
|
|
14
|
+
* ```typescript
|
|
15
|
+
* <Dynamic component={multiline() ? 'textarea' : 'input'} value={value()} />
|
|
16
|
+
* ```
|
|
17
|
+
* @description https://www.solidjs.com/docs/latest/api#dynamic
|
|
18
|
+
*/
|
|
19
|
+
export declare function Dynamic<T>(props: T & {
|
|
20
|
+
component?: ValidComponent;
|
|
21
|
+
}): JSXElement;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SolidNode, TextNode } from '@lightningtv/core';
|
|
2
|
+
import { ElementNode } from '@lightningtv/core';
|
|
3
|
+
import type { createRenderer } from 'solid-js/universal';
|
|
4
|
+
export type SolidRendererOptions = Parameters<typeof createRenderer<SolidNode>>[0];
|
|
5
|
+
declare const _default: {
|
|
6
|
+
createElement(name: string): ElementNode;
|
|
7
|
+
createTextNode(text: string): TextNode;
|
|
8
|
+
replaceText(node: TextNode, value: string): void;
|
|
9
|
+
setProperty<T>(node: ElementNode, name: string, value?: any): void;
|
|
10
|
+
insertNode(parent: ElementNode, node: SolidNode, anchor: SolidNode): void;
|
|
11
|
+
isTextNode(node: ElementNode): boolean;
|
|
12
|
+
removeNode(parent: ElementNode, node: SolidNode): void;
|
|
13
|
+
getParentNode(node: SolidNode): ElementNode | undefined;
|
|
14
|
+
getFirstChild(node: ElementNode): SolidNode | undefined;
|
|
15
|
+
getNextSibling(node: SolidNode): SolidNode | undefined;
|
|
16
|
+
};
|
|
17
|
+
export default _default;
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lightningtv/solid",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Lightning Renderer for Solid Universal",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"source": "src/index.ts",
|
|
7
|
+
"main": "./dist/esm/index.js",
|
|
8
|
+
"browser": "./dist/esm/index.js",
|
|
9
|
+
"types": "./dist/types/index.d.ts",
|
|
10
|
+
"sideEffects": false,
|
|
11
|
+
"scripts": {
|
|
12
|
+
"start": "npm run watch",
|
|
13
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
14
|
+
"lint": "npm run lint:prettier && npm run lint:eslint",
|
|
15
|
+
"lint:fix": "npm run lint:fix:prettier && npm run lint:fix:eslint",
|
|
16
|
+
"lint:prettier": "prettier --check \"**/*.{ts,js,cjs,md}\"",
|
|
17
|
+
"lint:fix:prettier": "prettier --write \"**/*.{ts,js,cjs,md}\"",
|
|
18
|
+
"lint:eslint": "eslint .",
|
|
19
|
+
"lint:fix:eslint": "eslint --fix .",
|
|
20
|
+
"build": "npm run tsc && rollup -c",
|
|
21
|
+
"tsc": "tsc",
|
|
22
|
+
"watch": "tsc -w",
|
|
23
|
+
"prepare": "husky",
|
|
24
|
+
"prepack": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"lightning",
|
|
28
|
+
"javascript",
|
|
29
|
+
"canvas",
|
|
30
|
+
"web",
|
|
31
|
+
"tv"
|
|
32
|
+
],
|
|
33
|
+
"author": "Chris Lorenzo",
|
|
34
|
+
"license": "Apache-2.0",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@lightningtv/core": "^0.0.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@rollup/plugin-replace": "^5.0.5",
|
|
40
|
+
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
|
41
|
+
"@typescript-eslint/parser": "^6.21.0",
|
|
42
|
+
"eslint": "^8.57.0",
|
|
43
|
+
"eslint-config-prettier": "^9.1.0",
|
|
44
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
45
|
+
"husky": "^9.0.11",
|
|
46
|
+
"lint-staged": "^15.2.4",
|
|
47
|
+
"prettier": "^3.2.5",
|
|
48
|
+
"rollup": "^4.18.0",
|
|
49
|
+
"rollup-preset-solid": "^2.0.1",
|
|
50
|
+
"solid-js": "^1.8.17",
|
|
51
|
+
"typescript": "^5.4.5"
|
|
52
|
+
},
|
|
53
|
+
"lint-staged": {
|
|
54
|
+
"*.ts": [
|
|
55
|
+
"prettier --write",
|
|
56
|
+
"eslint --fix"
|
|
57
|
+
],
|
|
58
|
+
"*.{js,cjs,md}": "prettier --write"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@lightningjs/renderer": "^0.9.1",
|
|
62
|
+
"solid-js": "*"
|
|
63
|
+
},
|
|
64
|
+
"repository": {
|
|
65
|
+
"type": "git",
|
|
66
|
+
"url": "git+https://github.com/lightning-js/solid.git"
|
|
67
|
+
},
|
|
68
|
+
"files": [
|
|
69
|
+
"dist",
|
|
70
|
+
"src",
|
|
71
|
+
"jsx-runtime.d.ts",
|
|
72
|
+
"LICENSE",
|
|
73
|
+
"NOTICE",
|
|
74
|
+
"README.md"
|
|
75
|
+
]
|
|
76
|
+
}
|
package/src/Text.tsx
ADDED
package/src/View.tsx
ADDED
package/src/index.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import './jsx-runtime.js';
|
|
2
|
+
export {
|
|
3
|
+
For,
|
|
4
|
+
Show,
|
|
5
|
+
Suspense,
|
|
6
|
+
SuspenseList,
|
|
7
|
+
Switch,
|
|
8
|
+
Match,
|
|
9
|
+
Index,
|
|
10
|
+
ErrorBoundary,
|
|
11
|
+
} from 'solid-js';
|
|
12
|
+
export * from '@lightningtv/core';
|
|
13
|
+
export * from './activeElement.js';
|
|
14
|
+
export { View } from './View.jsx';
|
|
15
|
+
export { Text } from './Text.jsx';
|
|
16
|
+
export * from './utils.js';
|
|
17
|
+
export * from './render.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-namespace */
|
|
2
|
+
import type { IntrinsicNodeProps, IntrinsicTextProps } from '@lightningtv/core';
|
|
3
|
+
|
|
4
|
+
declare module 'solid-js' {
|
|
5
|
+
namespace JSX {
|
|
6
|
+
interface IntrinsicElements {
|
|
7
|
+
node: Partial<IntrinsicNodeProps>;
|
|
8
|
+
view: Partial<IntrinsicNodeProps>;
|
|
9
|
+
text: Partial<IntrinsicTextProps>;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
package/src/render.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
2
|
+
import { createRenderer } from 'solid-js/universal';
|
|
3
|
+
import {
|
|
4
|
+
Config,
|
|
5
|
+
startLightningRenderer,
|
|
6
|
+
type SolidNode,
|
|
7
|
+
} from '@lightningtv/core';
|
|
8
|
+
import nodeOpts from './solidOpts.js';
|
|
9
|
+
import {
|
|
10
|
+
splitProps,
|
|
11
|
+
createMemo,
|
|
12
|
+
untrack,
|
|
13
|
+
type JSXElement,
|
|
14
|
+
type ValidComponent,
|
|
15
|
+
} from 'solid-js';
|
|
16
|
+
import type { RendererMain, RendererMainSettings } from '@lightningjs/renderer';
|
|
17
|
+
|
|
18
|
+
const solidRenderer = createRenderer<SolidNode>(nodeOpts);
|
|
19
|
+
|
|
20
|
+
let renderer: RendererMain;
|
|
21
|
+
export async function startLightning(
|
|
22
|
+
options?: Partial<RendererMainSettings>,
|
|
23
|
+
rootId?: string | HTMLElement,
|
|
24
|
+
) {
|
|
25
|
+
renderer = startLightningRenderer(
|
|
26
|
+
options || Config.rendererOptions,
|
|
27
|
+
rootId || 'app',
|
|
28
|
+
);
|
|
29
|
+
return await renderer.init();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const render = async function (
|
|
33
|
+
code: () => JSXElement,
|
|
34
|
+
node?: HTMLElement | string,
|
|
35
|
+
) {
|
|
36
|
+
const rootNode = nodeOpts.createElement('App');
|
|
37
|
+
|
|
38
|
+
await startLightning(undefined, node);
|
|
39
|
+
rootNode.lng = renderer.root!;
|
|
40
|
+
rootNode.rendered = true;
|
|
41
|
+
// @ts-expect-error - code is jsx element and not SolidElement yet
|
|
42
|
+
const dispose = solidRenderer.render(code, rootNode);
|
|
43
|
+
return {
|
|
44
|
+
dispose,
|
|
45
|
+
rootNode,
|
|
46
|
+
renderer,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// used for playground - must be sync so user must await startLightning
|
|
51
|
+
export const renderSync = function (code: () => JSXElement) {
|
|
52
|
+
const rootNode = nodeOpts.createElement('App');
|
|
53
|
+
rootNode.lng = renderer.root!;
|
|
54
|
+
// @ts-expect-error - code is jsx element and not SolidElement yet
|
|
55
|
+
return solidRenderer.render(code, rootNode);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const {
|
|
59
|
+
effect,
|
|
60
|
+
memo,
|
|
61
|
+
createComponent,
|
|
62
|
+
createElement,
|
|
63
|
+
createTextNode,
|
|
64
|
+
insertNode,
|
|
65
|
+
insert,
|
|
66
|
+
spread,
|
|
67
|
+
setProp,
|
|
68
|
+
mergeProps,
|
|
69
|
+
use,
|
|
70
|
+
} = solidRenderer;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* renders an arbitrary custom or native component and passes the other props
|
|
74
|
+
* ```typescript
|
|
75
|
+
* <Dynamic component={multiline() ? 'textarea' : 'input'} value={value()} />
|
|
76
|
+
* ```
|
|
77
|
+
* @description https://www.solidjs.com/docs/latest/api#dynamic
|
|
78
|
+
*/
|
|
79
|
+
export function Dynamic<T>(
|
|
80
|
+
props: T & {
|
|
81
|
+
component?: ValidComponent;
|
|
82
|
+
},
|
|
83
|
+
): JSXElement {
|
|
84
|
+
const [p, others] = splitProps(props, ['component']);
|
|
85
|
+
|
|
86
|
+
const cached = createMemo(() => p.component);
|
|
87
|
+
|
|
88
|
+
return createMemo(() => {
|
|
89
|
+
const component = cached();
|
|
90
|
+
switch (typeof component) {
|
|
91
|
+
case 'function':
|
|
92
|
+
return untrack(() => component(others));
|
|
93
|
+
|
|
94
|
+
case 'string': {
|
|
95
|
+
const el = createElement(component);
|
|
96
|
+
spread(el, others);
|
|
97
|
+
return el;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
default:
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}) as unknown as JSXElement;
|
|
104
|
+
}
|
package/src/solidOpts.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { assertTruthy } from '@lightningjs/renderer/utils';
|
|
2
|
+
import type { SolidNode, TextNode } from '@lightningtv/core';
|
|
3
|
+
import { ElementNode, NodeTypes, log } from '@lightningtv/core';
|
|
4
|
+
import type { createRenderer } from 'solid-js/universal';
|
|
5
|
+
|
|
6
|
+
export type SolidRendererOptions = Parameters<
|
|
7
|
+
typeof createRenderer<SolidNode>
|
|
8
|
+
>[0];
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
createElement(name: string): ElementNode {
|
|
12
|
+
return new ElementNode(name);
|
|
13
|
+
},
|
|
14
|
+
createTextNode(text: string): TextNode {
|
|
15
|
+
// A text node is just a string - not the <text> node
|
|
16
|
+
return { type: NodeTypes.Text, text, parent: undefined };
|
|
17
|
+
},
|
|
18
|
+
replaceText(node: TextNode, value: string): void {
|
|
19
|
+
log('Replace Text: ', node, value);
|
|
20
|
+
node.text = value;
|
|
21
|
+
const parent = node.parent;
|
|
22
|
+
assertTruthy(parent);
|
|
23
|
+
parent.text = parent.getText();
|
|
24
|
+
},
|
|
25
|
+
setProperty(node: ElementNode, name: string, value: any = true): void {
|
|
26
|
+
node[name] = value;
|
|
27
|
+
},
|
|
28
|
+
insertNode(parent: ElementNode, node: SolidNode, anchor: SolidNode): void {
|
|
29
|
+
log('INSERT: ', parent, node, anchor);
|
|
30
|
+
|
|
31
|
+
parent.children.insert(node, anchor);
|
|
32
|
+
node._queueDelete = false;
|
|
33
|
+
|
|
34
|
+
if (node instanceof ElementNode) {
|
|
35
|
+
parent.rendered && node.render();
|
|
36
|
+
} else if (parent.isTextNode()) {
|
|
37
|
+
// TextNodes can be placed outside of <text> nodes when <Show> is used as placeholder
|
|
38
|
+
parent.text = parent.getText();
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
isTextNode(node: ElementNode): boolean {
|
|
42
|
+
return node.isTextNode();
|
|
43
|
+
},
|
|
44
|
+
removeNode(parent: ElementNode, node: SolidNode): void {
|
|
45
|
+
log('REMOVE: ', parent, node);
|
|
46
|
+
parent.children.remove(node);
|
|
47
|
+
node._queueDelete = true;
|
|
48
|
+
if (node instanceof ElementNode) {
|
|
49
|
+
// Solid replacesNodes to move them (via insert and remove),
|
|
50
|
+
// so we need to wait for the next microtask to destroy the node
|
|
51
|
+
// in the event it gets a new parent.
|
|
52
|
+
queueMicrotask(() => node.destroy());
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
getParentNode(node: SolidNode): ElementNode | undefined {
|
|
56
|
+
return node.parent;
|
|
57
|
+
},
|
|
58
|
+
getFirstChild(node: ElementNode): SolidNode | undefined {
|
|
59
|
+
return node.children[0];
|
|
60
|
+
},
|
|
61
|
+
getNextSibling(node: SolidNode): SolidNode | undefined {
|
|
62
|
+
const children = node.parent!.children || [];
|
|
63
|
+
const index = children.indexOf(node) + 1;
|
|
64
|
+
if (index < children.length) {
|
|
65
|
+
return children[index];
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
},
|
|
69
|
+
} satisfies SolidRendererOptions;
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isInteger } from '@lightningtv/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Converts a color string to a color number value.
|
|
5
|
+
*/
|
|
6
|
+
export function hexColor(color: string | number = ''): number {
|
|
7
|
+
if (isInteger(color)) {
|
|
8
|
+
return color;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (typeof color === 'string') {
|
|
12
|
+
// Renderer expects RGBA values
|
|
13
|
+
if (color.startsWith('#')) {
|
|
14
|
+
return Number(
|
|
15
|
+
color.replace('#', '0x') + (color.length === 7 ? 'ff' : ''),
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (color.startsWith('0x')) {
|
|
20
|
+
return Number(color);
|
|
21
|
+
}
|
|
22
|
+
return Number('0x' + (color.length === 6 ? color + 'ff' : color));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return 0x00000000;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Converts degrees to radians
|
|
30
|
+
*/
|
|
31
|
+
export function deg2rad(deg: number) {
|
|
32
|
+
return (deg * Math.PI) / 180;
|
|
33
|
+
}
|