solid-js 1.1.6 → 1.2.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/README.md +2 -4
- package/dist/dev.cjs +23 -13
- package/dist/dev.js +23 -13
- package/dist/solid.cjs +23 -13
- package/dist/solid.js +23 -13
- package/h/README.md +99 -0
- package/html/README.md +84 -0
- package/html/dist/html.cjs +24 -6
- package/html/dist/html.js +25 -7
- package/package.json +14 -2
- package/store/README.md +23 -0
- package/types/jsx.d.ts +6 -3
- package/types/reactive/signal.d.ts +2 -2
- package/types/render/component.d.ts +1 -1
- package/universal/README.md +102 -0
- package/universal/dist/dev.cjs +258 -0
- package/universal/dist/dev.js +254 -0
- package/universal/dist/universal.cjs +258 -0
- package/universal/dist/universal.js +254 -0
- package/universal/package.json +8 -0
- package/universal/types/index.d.ts +2 -0
- package/universal/types/universal.d.ts +29 -0
- package/web/README.md +7 -0
- package/web/types/client.d.ts +1 -1
package/html/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Solid Tagged Template Literals
|
|
2
|
+
|
|
3
|
+
This sub module provides a Tagged Template Literal `html` method for Solid. This is useful to use Solid in non-compiled environments. This method can be used as replacement for JSX.
|
|
4
|
+
|
|
5
|
+
`html` uses `${}` to escape into JavaScript expressions. Components are closed with `<//>`
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
// create an element with a title attribute
|
|
9
|
+
html`<button title="My button">Click Me</button>`
|
|
10
|
+
|
|
11
|
+
// create a component with a title prop
|
|
12
|
+
html`<${Button} title="My button">Click me<//>`
|
|
13
|
+
|
|
14
|
+
// create an element with dynamic attribute and spread
|
|
15
|
+
html`<div title=${() => selectedClass()} ...${props} />`
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Using `html` is slightly less efficient than JSX(but more than HyperScript), requires a larger runtime that isn't treeshakebable, and cannot leverage expression analysis, so it requires manual wrapping of expressions and has a few other caveats (see below).
|
|
19
|
+
|
|
20
|
+
## Example
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
import { render } from "solid-js/web";
|
|
24
|
+
import html from "solid-js/html";
|
|
25
|
+
import { createSignal } from "solid-js";
|
|
26
|
+
|
|
27
|
+
function Button(props) {
|
|
28
|
+
return html`<button class="btn-primary" ...${props} />`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function Counter() {
|
|
32
|
+
const [count, setCount] = createSignal(0);
|
|
33
|
+
const increment = (e) => setCount((c) => c + 1);
|
|
34
|
+
|
|
35
|
+
return html`<${Button} type="button" onClick=${increment}>${count}<//>`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
render(Counter, document.getElementById("app"));
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Differences from JSX
|
|
42
|
+
|
|
43
|
+
There are a few differences from Solid's JSX that are important to note.
|
|
44
|
+
|
|
45
|
+
1. Reactive expression must be manually wrapped in functions to be reactive.
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
// jsx
|
|
49
|
+
<div id={props.id}>{firstName() + lastName()}</div>
|
|
50
|
+
|
|
51
|
+
// hyperscript
|
|
52
|
+
html`<div id=${() => props.id}>${() => firstName() + lastName()}</div>`
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
2. Events on components require explicit event in the arguments
|
|
56
|
+
|
|
57
|
+
Solid's Tagged Template Literals automatically wraps functions passed to props of components with no arguments in getters so you need to provide one to prevent this. The same applies to render props like in the `<For>` component.
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
// good
|
|
61
|
+
html`<${Button} onClick=${(e) => console.log("Hi")} />`;
|
|
62
|
+
|
|
63
|
+
// bad
|
|
64
|
+
html`<${Button} onClick=${() => console.log("Hi")} />`;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
4. All refs are callback form
|
|
68
|
+
|
|
69
|
+
We can't do the compiled assigment trick so only the callback form is supported.
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
let myEl;
|
|
73
|
+
html`<div ref=${(el) => myEl = el} />`;
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
5. There can be multiple top level elements
|
|
77
|
+
|
|
78
|
+
No need for fragments just:
|
|
79
|
+
```js
|
|
80
|
+
html`
|
|
81
|
+
<div>1</div>
|
|
82
|
+
<div>2</div>
|
|
83
|
+
`
|
|
84
|
+
```
|
package/html/dist/html.cjs
CHANGED
|
@@ -213,7 +213,7 @@ function createHTML(r, {
|
|
|
213
213
|
markup = markup + statics[i] + "<!--#-->";
|
|
214
214
|
}
|
|
215
215
|
markup = markup + statics[i];
|
|
216
|
-
markup = markup.replace(selfClosing, fullClosing).replace(/<(<!--#-->)/g, "<###").replace(attrSeeker, attrReplacer).replace(/>\n+\s*/g, ">").replace(/\n+\s*</g, "<").replace(/\s+</g, " <").replace(/>\s+/g, "> ");
|
|
216
|
+
markup = markup.replace(selfClosing, fullClosing).replace(/<(<!--#-->)/g, "<###").replace(/\.\.\.(<!--#-->)/g, "###").replace(attrSeeker, attrReplacer).replace(/>\n+\s*/g, ">").replace(/\n+\s*</g, "<").replace(/\s+</g, " <").replace(/>\s+/g, "> ");
|
|
217
217
|
const [html, code] = parseTemplate(parse(markup)),
|
|
218
218
|
templates = [];
|
|
219
219
|
for (let i = 0; i < html.length; i++) {
|
|
@@ -323,16 +323,29 @@ function createHTML(r, {
|
|
|
323
323
|
options.counter = childOptions.counter;
|
|
324
324
|
options.templateId = childOptions.templateId;
|
|
325
325
|
}
|
|
326
|
+
function processComponentProps(propGroups) {
|
|
327
|
+
let result = [];
|
|
328
|
+
for (const props of propGroups) {
|
|
329
|
+
if (Array.isArray(props)) {
|
|
330
|
+
if (!props.length) continue;
|
|
331
|
+
result.push(`r.wrapProps({${props.join(",") || ""}})`);
|
|
332
|
+
} else result.push(props);
|
|
333
|
+
}
|
|
334
|
+
return result.length > 1 ? `r.mergeProps(${result.join(",")})` : result[0];
|
|
335
|
+
}
|
|
326
336
|
function processComponent(node, options) {
|
|
337
|
+
let props = [];
|
|
327
338
|
const keys = Object.keys(node.attrs),
|
|
328
|
-
|
|
339
|
+
propGroups = [props],
|
|
329
340
|
componentIdentifier = options.counter++;
|
|
330
341
|
for (let i = 0; i < keys.length; i++) {
|
|
331
342
|
const name = keys[i],
|
|
332
343
|
value = node.attrs[name];
|
|
333
|
-
if (
|
|
334
|
-
|
|
335
|
-
|
|
344
|
+
if (name === "###") {
|
|
345
|
+
propGroups.push(`exprs[${options.counter++}]`);
|
|
346
|
+
propGroups.push(props = []);
|
|
347
|
+
} else if (value === "###") {
|
|
348
|
+
props.push(`${name}: exprs[${options.counter++}]`);
|
|
336
349
|
} else props.push(`${name}: "${value}"`);
|
|
337
350
|
}
|
|
338
351
|
if (node.children.length === 1 && node.children[0].type === "comment" && node.children[0].content === "#") {
|
|
@@ -357,7 +370,7 @@ function createHTML(r, {
|
|
|
357
370
|
tag = `_$el${uuid++}`;
|
|
358
371
|
options.decl.push(`${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
|
|
359
372
|
}
|
|
360
|
-
if (options.parent) options.exprs.push(`r.insert(${options.parent}, r.createComponent(exprs[${componentIdentifier}]
|
|
373
|
+
if (options.parent) options.exprs.push(`r.insert(${options.parent}, r.createComponent(exprs[${componentIdentifier}],${processComponentProps(propGroups)})${tag ? `, ${tag}` : ""})`);else options.exprs.push(`${options.fragment ? "" : "return "}r.createComponent(exprs[${componentIdentifier}],${processComponentProps(propGroups)})`);
|
|
361
374
|
options.path = tag;
|
|
362
375
|
options.first = false;
|
|
363
376
|
}
|
|
@@ -410,6 +423,9 @@ function createHTML(r, {
|
|
|
410
423
|
if (value === "###") {
|
|
411
424
|
delete node.attrs[name];
|
|
412
425
|
parseAttribute(tag, name, isSVG, isCE, options);
|
|
426
|
+
} else if (name === "###") {
|
|
427
|
+
delete node.attrs[name];
|
|
428
|
+
options.exprs.push(`r.spread(${tag},exprs[${options.counter++}],${isSVG},${!!node.children.length})`);
|
|
413
429
|
}
|
|
414
430
|
}
|
|
415
431
|
options.path = tag;
|
|
@@ -470,9 +486,11 @@ var index = createHTML({
|
|
|
470
486
|
effect: web.effect,
|
|
471
487
|
style: web.style,
|
|
472
488
|
insert: web.insert,
|
|
489
|
+
spread: web.spread,
|
|
473
490
|
createComponent: web.createComponent,
|
|
474
491
|
delegateEvents: web.delegateEvents,
|
|
475
492
|
classList: web.classList,
|
|
493
|
+
mergeProps: web.mergeProps,
|
|
476
494
|
dynamicProperty: web.dynamicProperty,
|
|
477
495
|
setAttribute: web.setAttribute,
|
|
478
496
|
setAttributeNS: web.setAttributeNS,
|
package/html/dist/html.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { effect, style, insert, createComponent, delegateEvents, classList, dynamicProperty, setAttribute, setAttributeNS, addEventListener, Aliases, PropAliases, Properties, ChildProperties, DelegatedEvents, SVGElements, SVGNamespace } from 'solid-js/web';
|
|
1
|
+
import { effect, style, insert, spread, createComponent, delegateEvents, classList, mergeProps, dynamicProperty, setAttribute, setAttributeNS, addEventListener, Aliases, PropAliases, Properties, ChildProperties, DelegatedEvents, SVGElements, SVGNamespace } from 'solid-js/web';
|
|
2
2
|
|
|
3
3
|
var attrRE, lookup, parseTag, pushCommentNode, pushTextNode, tagRE;
|
|
4
4
|
tagRE = /(?:<!--[\S\s]*?-->|<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>)/g;
|
|
@@ -211,7 +211,7 @@ function createHTML(r, {
|
|
|
211
211
|
markup = markup + statics[i] + "<!--#-->";
|
|
212
212
|
}
|
|
213
213
|
markup = markup + statics[i];
|
|
214
|
-
markup = markup.replace(selfClosing, fullClosing).replace(/<(<!--#-->)/g, "<###").replace(attrSeeker, attrReplacer).replace(/>\n+\s*/g, ">").replace(/\n+\s*</g, "<").replace(/\s+</g, " <").replace(/>\s+/g, "> ");
|
|
214
|
+
markup = markup.replace(selfClosing, fullClosing).replace(/<(<!--#-->)/g, "<###").replace(/\.\.\.(<!--#-->)/g, "###").replace(attrSeeker, attrReplacer).replace(/>\n+\s*/g, ">").replace(/\n+\s*</g, "<").replace(/\s+</g, " <").replace(/>\s+/g, "> ");
|
|
215
215
|
const [html, code] = parseTemplate(parse(markup)),
|
|
216
216
|
templates = [];
|
|
217
217
|
for (let i = 0; i < html.length; i++) {
|
|
@@ -321,16 +321,29 @@ function createHTML(r, {
|
|
|
321
321
|
options.counter = childOptions.counter;
|
|
322
322
|
options.templateId = childOptions.templateId;
|
|
323
323
|
}
|
|
324
|
+
function processComponentProps(propGroups) {
|
|
325
|
+
let result = [];
|
|
326
|
+
for (const props of propGroups) {
|
|
327
|
+
if (Array.isArray(props)) {
|
|
328
|
+
if (!props.length) continue;
|
|
329
|
+
result.push(`r.wrapProps({${props.join(",") || ""}})`);
|
|
330
|
+
} else result.push(props);
|
|
331
|
+
}
|
|
332
|
+
return result.length > 1 ? `r.mergeProps(${result.join(",")})` : result[0];
|
|
333
|
+
}
|
|
324
334
|
function processComponent(node, options) {
|
|
335
|
+
let props = [];
|
|
325
336
|
const keys = Object.keys(node.attrs),
|
|
326
|
-
|
|
337
|
+
propGroups = [props],
|
|
327
338
|
componentIdentifier = options.counter++;
|
|
328
339
|
for (let i = 0; i < keys.length; i++) {
|
|
329
340
|
const name = keys[i],
|
|
330
341
|
value = node.attrs[name];
|
|
331
|
-
if (
|
|
332
|
-
|
|
333
|
-
|
|
342
|
+
if (name === "###") {
|
|
343
|
+
propGroups.push(`exprs[${options.counter++}]`);
|
|
344
|
+
propGroups.push(props = []);
|
|
345
|
+
} else if (value === "###") {
|
|
346
|
+
props.push(`${name}: exprs[${options.counter++}]`);
|
|
334
347
|
} else props.push(`${name}: "${value}"`);
|
|
335
348
|
}
|
|
336
349
|
if (node.children.length === 1 && node.children[0].type === "comment" && node.children[0].content === "#") {
|
|
@@ -355,7 +368,7 @@ function createHTML(r, {
|
|
|
355
368
|
tag = `_$el${uuid++}`;
|
|
356
369
|
options.decl.push(`${tag} = ${options.path}.${options.first ? "firstChild" : "nextSibling"}`);
|
|
357
370
|
}
|
|
358
|
-
if (options.parent) options.exprs.push(`r.insert(${options.parent}, r.createComponent(exprs[${componentIdentifier}]
|
|
371
|
+
if (options.parent) options.exprs.push(`r.insert(${options.parent}, r.createComponent(exprs[${componentIdentifier}],${processComponentProps(propGroups)})${tag ? `, ${tag}` : ""})`);else options.exprs.push(`${options.fragment ? "" : "return "}r.createComponent(exprs[${componentIdentifier}],${processComponentProps(propGroups)})`);
|
|
359
372
|
options.path = tag;
|
|
360
373
|
options.first = false;
|
|
361
374
|
}
|
|
@@ -408,6 +421,9 @@ function createHTML(r, {
|
|
|
408
421
|
if (value === "###") {
|
|
409
422
|
delete node.attrs[name];
|
|
410
423
|
parseAttribute(tag, name, isSVG, isCE, options);
|
|
424
|
+
} else if (name === "###") {
|
|
425
|
+
delete node.attrs[name];
|
|
426
|
+
options.exprs.push(`r.spread(${tag},exprs[${options.counter++}],${isSVG},${!!node.children.length})`);
|
|
411
427
|
}
|
|
412
428
|
}
|
|
413
429
|
options.path = tag;
|
|
@@ -468,9 +484,11 @@ var index = createHTML({
|
|
|
468
484
|
effect,
|
|
469
485
|
style,
|
|
470
486
|
insert,
|
|
487
|
+
spread,
|
|
471
488
|
createComponent,
|
|
472
489
|
delegateEvents,
|
|
473
490
|
classList,
|
|
491
|
+
mergeProps,
|
|
474
492
|
dynamicProperty,
|
|
475
493
|
setAttribute,
|
|
476
494
|
setAttributeNS,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solid-js",
|
|
3
3
|
"description": "A declarative JavaScript library for building user interfaces.",
|
|
4
|
-
"version": "1.1
|
|
4
|
+
"version": "1.2.1",
|
|
5
5
|
"author": "Ryan Carniato",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/solidjs/solid#readme",
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
"h/types",
|
|
30
30
|
"html/dist",
|
|
31
31
|
"html/types",
|
|
32
|
+
"universal/dist",
|
|
33
|
+
"universal/types",
|
|
32
34
|
"types",
|
|
33
35
|
"jsx-runtime.d.ts"
|
|
34
36
|
],
|
|
@@ -84,6 +86,15 @@
|
|
|
84
86
|
"require": "./web/dist/web.cjs"
|
|
85
87
|
},
|
|
86
88
|
"./web/dist/*": "./web/dist/*",
|
|
89
|
+
"./universal": {
|
|
90
|
+
"development": {
|
|
91
|
+
"import": "./universal/dist/dev.js",
|
|
92
|
+
"require": "./universal/dist/dev.cjs"
|
|
93
|
+
},
|
|
94
|
+
"import": "./universal/dist/universal.js",
|
|
95
|
+
"require": "./universal/dist/universal.cjs"
|
|
96
|
+
},
|
|
97
|
+
"./universal/dist/*": "./universal/dist/*",
|
|
87
98
|
"./h": {
|
|
88
99
|
"import": "./h/dist/h.js",
|
|
89
100
|
"require": "./h/dist/h.cjs"
|
|
@@ -106,6 +117,7 @@
|
|
|
106
117
|
"build:types-web": "tsc --project ./web/tsconfig.json && tsconfig-replace-paths --project ./web/tsconfig.types.json",
|
|
107
118
|
"build:types-html": "tsc --project ./html/tsconfig.json",
|
|
108
119
|
"build:types-h": "tsc --project ./h/tsconfig.json",
|
|
120
|
+
"build:types-universal": "tsc --project ./universal/tsconfig.json",
|
|
109
121
|
"bench": "node --allow-natives-syntax bench/bench.cjs",
|
|
110
122
|
"test": "jest && npm run test:types",
|
|
111
123
|
"test:coverage": "jest --coverage && npm run test:types",
|
|
@@ -120,5 +132,5 @@
|
|
|
120
132
|
"compiler",
|
|
121
133
|
"performance"
|
|
122
134
|
],
|
|
123
|
-
"gitHead": "
|
|
135
|
+
"gitHead": "8bca8fa83837ac7406bc76813fedbc72bbe11a01"
|
|
124
136
|
}
|
package/store/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Solid Store
|
|
2
|
+
|
|
3
|
+
This submodules contains the means for handling deeps nested reactivity. It provides 2 main primitives `createStore` and `createMutable` which leverage proxies to create dynamic nested reactive structures.
|
|
4
|
+
|
|
5
|
+
This also contains helper methods `produce` and `reconcile` which augment the behavior of the store setter method to allow for localized mutationa and data diffing.
|
|
6
|
+
|
|
7
|
+
For full documentation, check out the [website](https://www.solidjs.com/docs/latest/api).
|
|
8
|
+
|
|
9
|
+
## Example
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import { createStore } from "solid-js/store";
|
|
13
|
+
|
|
14
|
+
const [store, setStore] = createStore({
|
|
15
|
+
user: {
|
|
16
|
+
firstName: "John",
|
|
17
|
+
lastName: "Smith"
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// update store.user.firstName
|
|
22
|
+
setStore("user", "firstName", "Will");
|
|
23
|
+
```
|
package/types/jsx.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export namespace JSX {
|
|
|
11
11
|
| Node
|
|
12
12
|
| ArrayElement
|
|
13
13
|
| FunctionElement
|
|
14
|
-
| string
|
|
14
|
+
| (string & {})
|
|
15
15
|
| number
|
|
16
16
|
| boolean
|
|
17
17
|
| null
|
|
@@ -1674,6 +1674,7 @@ export namespace JSX {
|
|
|
1674
1674
|
| "unsafe-url";
|
|
1675
1675
|
type HTMLIframeSandbox =
|
|
1676
1676
|
| "allow-downloads-without-user-activation"
|
|
1677
|
+
| "allow-downloads"
|
|
1677
1678
|
| "allow-forms"
|
|
1678
1679
|
| "allow-modals"
|
|
1679
1680
|
| "allow-orientation-lock"
|
|
@@ -2116,7 +2117,7 @@ export namespace JSX {
|
|
|
2116
2117
|
height?: number | string;
|
|
2117
2118
|
name?: string;
|
|
2118
2119
|
referrerpolicy?: HTMLReferrerPolicy;
|
|
2119
|
-
sandbox?: HTMLIframeSandbox;
|
|
2120
|
+
sandbox?: HTMLIframeSandbox | string;
|
|
2120
2121
|
src?: string;
|
|
2121
2122
|
srcdoc?: string;
|
|
2122
2123
|
width?: number | string;
|
|
@@ -2873,7 +2874,8 @@ export namespace JSX {
|
|
|
2873
2874
|
extends FilterPrimitiveElementSVGAttributes<T>,
|
|
2874
2875
|
ExternalResourceSVGAttributes,
|
|
2875
2876
|
StylableSVGAttributes {
|
|
2876
|
-
preserveAspectRatio
|
|
2877
|
+
preserveAspectRatio?: SVGPreserveAspectRatio;
|
|
2878
|
+
href?: string;
|
|
2877
2879
|
}
|
|
2878
2880
|
interface FeMergeSVGAttributes<T>
|
|
2879
2881
|
extends FilterPrimitiveElementSVGAttributes<T>,
|
|
@@ -2976,6 +2978,7 @@ export namespace JSX {
|
|
|
2976
2978
|
width?: number | string;
|
|
2977
2979
|
height?: number | string;
|
|
2978
2980
|
preserveAspectRatio?: ImagePreserveAspectRatio;
|
|
2981
|
+
href?: string;
|
|
2979
2982
|
}
|
|
2980
2983
|
interface LineSVGAttributes<T>
|
|
2981
2984
|
extends GraphicsElementSVGAttributes<T>,
|
|
@@ -248,7 +248,7 @@ export declare function createDeferred<T>(source: Accessor<T>, options?: {
|
|
|
248
248
|
/**
|
|
249
249
|
* Creates a conditional signal that only notifies subscribers when entering or exiting their key matching the value
|
|
250
250
|
* ```typescript
|
|
251
|
-
* export function
|
|
251
|
+
* export function createSelector<T, U>(
|
|
252
252
|
* source: () => T
|
|
253
253
|
* fn: (a: U, b: T) => boolean,
|
|
254
254
|
* options?: { name?: string }
|
|
@@ -267,7 +267,7 @@ export declare function createDeferred<T>(source: Accessor<T>, options?: {
|
|
|
267
267
|
*
|
|
268
268
|
* This makes the operation O(2) instead of O(n).
|
|
269
269
|
*
|
|
270
|
-
* @description https://www.solidjs.com/docs/latest/api#
|
|
270
|
+
* @description https://www.solidjs.com/docs/latest/api#createselector
|
|
271
271
|
*/
|
|
272
272
|
export declare function createSelector<T, U>(source: Accessor<T>, fn?: (a: U, b: T) => boolean, options?: {
|
|
273
273
|
name?: string;
|
|
@@ -15,7 +15,7 @@ export declare function createComponent<T>(Comp: (props: T) => JSX.Element, prop
|
|
|
15
15
|
declare type BoxedTupleTypes<T extends any[]> = {
|
|
16
16
|
[P in keyof T]: [T[P]];
|
|
17
17
|
}[Exclude<keyof T, keyof any[]>];
|
|
18
|
-
declare type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
|
|
18
|
+
declare type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
19
19
|
declare type UnboxIntersection<T> = T extends {
|
|
20
20
|
0: infer U;
|
|
21
21
|
} ? U : never;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Solid Universal
|
|
2
|
+
|
|
3
|
+
This contains the means to create the runtime for a custom renderer for Solid. This can enable using Solid to render to different platforms like native mobile and desktop, canvas or WebGL, or even the terminal. It relies on custom compilation from `babel-preset-solid` and exporting the result of `createRenderer` at a referenceable location.
|
|
4
|
+
|
|
5
|
+
## Example
|
|
6
|
+
|
|
7
|
+
To use a custom renderer available in the (fictional) `solid-custom-dom` package you'd configure your babelrc as:
|
|
8
|
+
```json
|
|
9
|
+
{
|
|
10
|
+
"presets": [
|
|
11
|
+
[
|
|
12
|
+
"babel-preset-solid",
|
|
13
|
+
{
|
|
14
|
+
"moduleName": "solid-custom-dom",
|
|
15
|
+
"generate": "universal"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
To create a custom renderer you must implement certain methods and export (as named exports) the results. You may also want to forward `solid-js` control flow to allow them to be auto imported as well.
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
// example custom dom renderer
|
|
26
|
+
import { createRenderer } from "solid-js/universal";
|
|
27
|
+
|
|
28
|
+
const PROPERTIES = new Set(["className", "textContent"]);
|
|
29
|
+
|
|
30
|
+
export const {
|
|
31
|
+
render,
|
|
32
|
+
effect,
|
|
33
|
+
memo,
|
|
34
|
+
createComponent,
|
|
35
|
+
createElement,
|
|
36
|
+
createTextNode,
|
|
37
|
+
insertNode,
|
|
38
|
+
insert,
|
|
39
|
+
spread,
|
|
40
|
+
setProp,
|
|
41
|
+
mergeProps
|
|
42
|
+
} = createRenderer({
|
|
43
|
+
createElement(string) {
|
|
44
|
+
return document.createElement(string);
|
|
45
|
+
},
|
|
46
|
+
createTextNode(value) {
|
|
47
|
+
return document.createTextNode(value);
|
|
48
|
+
},
|
|
49
|
+
replaceText(textNode, value) {
|
|
50
|
+
textNode.data = value;
|
|
51
|
+
},
|
|
52
|
+
setProperty(node, name, value) {
|
|
53
|
+
if (name === "style") Object.assign(node.style, value);
|
|
54
|
+
else if (name.startsWith("on")) node[name.toLowerCase()] = value;
|
|
55
|
+
else if (PROPERTIES.has(name)) node[name] = value;
|
|
56
|
+
else node.setAttribute(name, value);
|
|
57
|
+
},
|
|
58
|
+
insertNode(parent, node, anchor) {
|
|
59
|
+
parent.insertBefore(node, anchor);
|
|
60
|
+
},
|
|
61
|
+
isTextNode(node) {
|
|
62
|
+
return node.type === 3;
|
|
63
|
+
},
|
|
64
|
+
removeNode(parent, node) {
|
|
65
|
+
parent.removeChild(node);
|
|
66
|
+
},
|
|
67
|
+
getParentNode(node) {
|
|
68
|
+
return node.parentNode;
|
|
69
|
+
},
|
|
70
|
+
getFirstChild(node) {
|
|
71
|
+
return node.firstChild;
|
|
72
|
+
},
|
|
73
|
+
getNextSibling(node) {
|
|
74
|
+
return node.nextSibling;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Forward Solid control flow
|
|
79
|
+
export {
|
|
80
|
+
For,
|
|
81
|
+
Show,
|
|
82
|
+
Suspense,
|
|
83
|
+
SuspenseList,
|
|
84
|
+
Switch,
|
|
85
|
+
Match,
|
|
86
|
+
Index,
|
|
87
|
+
ErrorBoundary
|
|
88
|
+
} from "solid-js";
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Then to consume:
|
|
92
|
+
```js
|
|
93
|
+
import { render } from "solid-custom-dom";
|
|
94
|
+
|
|
95
|
+
function App() {
|
|
96
|
+
// the skies the limits
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
render(() => <App />, mountNode)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
> Note: For TypeScript support of non-standard JSX you will need to provide your own types at a jsx-runtime entry on your package so that it can be set as the `jsxImportSource`. If mixing and matching different JSX implementations you will need use the per file pragmas.
|