solid-tag-runtime 0.0.8 → 0.0.9
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/ARCHITECTURE.md +53 -1
- package/README.md +157 -3
- package/html.d.ts +119 -65
- package/package.json +1 -1
- package/src/html.js +798 -65
- package/src/render.js +205 -0
package/src/render.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { SolidTagRuntimeError } from "./errors.js";
|
|
2
|
+
|
|
3
|
+
export class HTMLRenderError extends SolidTagRuntimeError {
|
|
4
|
+
constructor(message, options = {}) {
|
|
5
|
+
super(message, options);
|
|
6
|
+
this.name = "HTMLRenderError";
|
|
7
|
+
this.moduleId = options.moduleId;
|
|
8
|
+
this.component = options.component;
|
|
9
|
+
this.element = options.element;
|
|
10
|
+
this.cause = options.cause ?? this.cause;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function resolveRenderComponent(namespace, componentName, context = {}) {
|
|
15
|
+
const exportName = componentName || "default";
|
|
16
|
+
if (!namespace || !(exportName in namespace)) {
|
|
17
|
+
const suffix = componentName
|
|
18
|
+
? `Module does not export component ${JSON.stringify(componentName)}.`
|
|
19
|
+
: `Render declaration expected default export, but the module does not export \"default\". Use component=\"Name\" to render a named export.`;
|
|
20
|
+
throw new HTMLRenderError(suffix, {
|
|
21
|
+
moduleId: context.moduleId,
|
|
22
|
+
component: componentName,
|
|
23
|
+
element: context.element,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const Component = namespace[exportName];
|
|
28
|
+
if (typeof Component !== "function") {
|
|
29
|
+
throw new HTMLRenderError(
|
|
30
|
+
`Export ${JSON.stringify(exportName)} from ${JSON.stringify(context.moduleId ?? "module")} is not callable and cannot be rendered as a Solid component.`,
|
|
31
|
+
{
|
|
32
|
+
moduleId: context.moduleId,
|
|
33
|
+
component: componentName,
|
|
34
|
+
element: context.element,
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return { Component, exportName };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function createDefaultHTMLRenderAdapter(runtime) {
|
|
43
|
+
let modulesPromise;
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
async mountContainer({ target, Component, props }) {
|
|
47
|
+
const { Solid, Web } = await getSolidModules();
|
|
48
|
+
if (typeof Web.render !== "function") {
|
|
49
|
+
throw new HTMLRenderError("@solidjs/web does not provide render().");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const reactive = createReactiveProps(Solid, props);
|
|
53
|
+
const createComponent = getCreateComponent(Solid, Web);
|
|
54
|
+
const dispose = Web.render(
|
|
55
|
+
() => createComponent(Component, reactive.props),
|
|
56
|
+
target,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
kind: "container",
|
|
61
|
+
target,
|
|
62
|
+
updateProps: reactive.update,
|
|
63
|
+
dispose: once(() => {
|
|
64
|
+
if (typeof dispose === "function") dispose();
|
|
65
|
+
}),
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
async mountRange({ parent, before, startMarker, endMarker, Component, props }) {
|
|
70
|
+
const { Solid, Web } = await getSolidModules();
|
|
71
|
+
if (typeof Solid.createRoot !== "function") {
|
|
72
|
+
throw new HTMLRenderError("solid-js does not provide createRoot().");
|
|
73
|
+
}
|
|
74
|
+
if (typeof Web.insert !== "function") {
|
|
75
|
+
throw new HTMLRenderError("@solidjs/web does not provide insert() required for in-place rendering.");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const reactive = createReactiveProps(Solid, props);
|
|
79
|
+
const createComponent = getCreateComponent(Solid, Web);
|
|
80
|
+
const disposeRoot = Solid.createRoot(dispose => {
|
|
81
|
+
Web.insert(
|
|
82
|
+
parent,
|
|
83
|
+
() => createComponent(Component, reactive.props),
|
|
84
|
+
before,
|
|
85
|
+
);
|
|
86
|
+
return dispose;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
kind: "range",
|
|
91
|
+
parent,
|
|
92
|
+
startMarker,
|
|
93
|
+
endMarker,
|
|
94
|
+
updateProps: reactive.update,
|
|
95
|
+
dispose: once(() => {
|
|
96
|
+
if (typeof disposeRoot === "function") disposeRoot();
|
|
97
|
+
clearBetween(startMarker, endMarker);
|
|
98
|
+
}),
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
function getSolidModules() {
|
|
104
|
+
if (!modulesPromise) {
|
|
105
|
+
modulesPromise = Promise.all([
|
|
106
|
+
runtime.import("solid-js"),
|
|
107
|
+
importSolidWeb(runtime),
|
|
108
|
+
]).then(([Solid, Web]) => ({ Solid, Web }));
|
|
109
|
+
}
|
|
110
|
+
return modulesPromise;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function importSolidWeb(runtime) {
|
|
115
|
+
try {
|
|
116
|
+
return await runtime.import("@solidjs/web");
|
|
117
|
+
} catch (primaryError) {
|
|
118
|
+
try {
|
|
119
|
+
return await runtime.import("solid-js/web");
|
|
120
|
+
} catch {
|
|
121
|
+
throw primaryError;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function getCreateComponent(Solid, Web) {
|
|
127
|
+
const createComponent = Solid?.createComponent ?? Web?.createComponent;
|
|
128
|
+
if (typeof createComponent === "function") return createComponent;
|
|
129
|
+
return (Component, props) => Component(props);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function createReactiveProps(Solid, initialProps = {}) {
|
|
133
|
+
if (typeof Solid?.createSignal !== "function") {
|
|
134
|
+
let current = initialProps;
|
|
135
|
+
return {
|
|
136
|
+
props: new Proxy(Object.create(null), {
|
|
137
|
+
get(_target, key) {
|
|
138
|
+
return current[key];
|
|
139
|
+
},
|
|
140
|
+
has(_target, key) {
|
|
141
|
+
return key in current;
|
|
142
|
+
},
|
|
143
|
+
ownKeys() {
|
|
144
|
+
return Reflect.ownKeys(current);
|
|
145
|
+
},
|
|
146
|
+
getOwnPropertyDescriptor(_target, key) {
|
|
147
|
+
if (!(key in current)) return undefined;
|
|
148
|
+
return { configurable: true, enumerable: true, value: current[key] };
|
|
149
|
+
},
|
|
150
|
+
}),
|
|
151
|
+
update(next) {
|
|
152
|
+
current = next ?? {};
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const [revision, setRevision] = Solid.createSignal(0);
|
|
158
|
+
let current = initialProps ?? {};
|
|
159
|
+
const props = new Proxy(Object.create(null), {
|
|
160
|
+
get(_target, key) {
|
|
161
|
+
revision();
|
|
162
|
+
return current[key];
|
|
163
|
+
},
|
|
164
|
+
has(_target, key) {
|
|
165
|
+
revision();
|
|
166
|
+
return key in current;
|
|
167
|
+
},
|
|
168
|
+
ownKeys() {
|
|
169
|
+
revision();
|
|
170
|
+
return Reflect.ownKeys(current);
|
|
171
|
+
},
|
|
172
|
+
getOwnPropertyDescriptor(_target, key) {
|
|
173
|
+
revision();
|
|
174
|
+
if (!(key in current)) return undefined;
|
|
175
|
+
return { configurable: true, enumerable: true, value: current[key] };
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
props,
|
|
181
|
+
update(next) {
|
|
182
|
+
current = next ?? {};
|
|
183
|
+
setRevision(value => value + 1);
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function clearBetween(start, end) {
|
|
189
|
+
if (!start || !end) return;
|
|
190
|
+
let node = start.nextSibling;
|
|
191
|
+
while (node && node !== end) {
|
|
192
|
+
const next = node.nextSibling;
|
|
193
|
+
node.parentNode?.removeChild?.(node);
|
|
194
|
+
node = next;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function once(fn) {
|
|
199
|
+
let called = false;
|
|
200
|
+
return () => {
|
|
201
|
+
if (called) return;
|
|
202
|
+
called = true;
|
|
203
|
+
fn?.();
|
|
204
|
+
};
|
|
205
|
+
}
|