coldwired 0.18.0
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 +21 -0
- package/README.md +168 -0
- package/dist/actions-CQVSvZlC.d.mts +134 -0
- package/dist/actions-k0j8z15o.mjs +883 -0
- package/dist/actions.d.mts +2 -0
- package/dist/actions.mjs +2 -0
- package/dist/react.d.mts +88 -0
- package/dist/react.mjs +635 -0
- package/dist/turbo-stream.d.mts +7 -0
- package/dist/turbo-stream.mjs +72 -0
- package/dist/utils-C2S0wWJJ.mjs +350 -0
- package/dist/utils.d.mts +80 -0
- package/dist/utils.mjs +2 -0
- package/package.json +72 -0
package/dist/react.mjs
ADDED
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
import { _ as isElement, z as parseHTMLFragment } from "./utils-C2S0wWJJ.mjs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
import { createRoot as createRoot$1 } from "react-dom/client";
|
|
5
|
+
import { Fragment, StrictMode, createElement, useEffect, useSyncExternalStore } from "react";
|
|
6
|
+
import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
|
|
7
|
+
import { decode } from "html-entities";
|
|
8
|
+
//#region \0rolldown/runtime.js
|
|
9
|
+
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
10
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/react/plugin.ts
|
|
13
|
+
function createReactPlugin(root) {
|
|
14
|
+
const pending = /* @__PURE__ */ new Set();
|
|
15
|
+
return {
|
|
16
|
+
init(element) {
|
|
17
|
+
let onReady;
|
|
18
|
+
const ready = new Promise((resolve) => {
|
|
19
|
+
onReady = resolve;
|
|
20
|
+
});
|
|
21
|
+
pending.add(ready);
|
|
22
|
+
const mountAndRender = async () => {
|
|
23
|
+
const batch = root.render(element);
|
|
24
|
+
if (batch.count != 0) await batch.done;
|
|
25
|
+
};
|
|
26
|
+
mountAndRender().then(() => {
|
|
27
|
+
pending.delete(ready);
|
|
28
|
+
onReady();
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
async ready() {
|
|
32
|
+
await Promise.all(pending);
|
|
33
|
+
},
|
|
34
|
+
validate(element) {
|
|
35
|
+
if (root.contains("body" in element ? element.body : element)) throw new Error("Cannot apply actions inside fragment");
|
|
36
|
+
},
|
|
37
|
+
onCreateElement(element) {
|
|
38
|
+
const batch = root.render(element);
|
|
39
|
+
if (batch.count == 0) return false;
|
|
40
|
+
pending.add(batch.done);
|
|
41
|
+
batch.done.then(() => pending.delete(batch.done));
|
|
42
|
+
return true;
|
|
43
|
+
},
|
|
44
|
+
onBeforeUpdateElement(element, toElement) {
|
|
45
|
+
const batch = root.render(element, toElement);
|
|
46
|
+
if (batch.count == 0) return false;
|
|
47
|
+
pending.add(batch.done);
|
|
48
|
+
batch.done.then(() => pending.delete(batch.done));
|
|
49
|
+
return true;
|
|
50
|
+
},
|
|
51
|
+
onBeforeDestroyElement(element) {
|
|
52
|
+
return root.remove(element);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/react/preload.ts
|
|
58
|
+
const defaultSchema$1 = {
|
|
59
|
+
componentTagName: "react-component",
|
|
60
|
+
slotTagName: "react-slot",
|
|
61
|
+
nameAttribute: "name",
|
|
62
|
+
propsAttribute: "props"
|
|
63
|
+
};
|
|
64
|
+
function preload(documentOrFragment, loader, schema) {
|
|
65
|
+
const { componentTagName, nameAttribute } = Object.assign({}, defaultSchema$1, schema);
|
|
66
|
+
const components = documentOrFragment.querySelectorAll(componentTagName);
|
|
67
|
+
return loader([...new Set(Array.from(components).map((component) => {
|
|
68
|
+
const name = component.getAttribute(nameAttribute);
|
|
69
|
+
if (!name) throw new Error(`Missing "${nameAttribute}" attribute on <${componentTagName}>`);
|
|
70
|
+
return name;
|
|
71
|
+
}))]);
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/react/tree-builder.react.ts
|
|
75
|
+
var import_react_error_boundary = (/* @__PURE__ */ __commonJSMin(((exports) => {
|
|
76
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
77
|
+
const s = __require("react"), c = s.createContext(null), u = {
|
|
78
|
+
didCatch: !1,
|
|
79
|
+
error: null
|
|
80
|
+
};
|
|
81
|
+
var y = class extends s.Component {
|
|
82
|
+
constructor(e) {
|
|
83
|
+
super(e), this.resetErrorBoundary = this.resetErrorBoundary.bind(this), this.state = u;
|
|
84
|
+
}
|
|
85
|
+
static getDerivedStateFromError(e) {
|
|
86
|
+
return {
|
|
87
|
+
didCatch: !0,
|
|
88
|
+
error: e
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
resetErrorBoundary(...e) {
|
|
92
|
+
const { error: t } = this.state;
|
|
93
|
+
t !== null && (this.props.onReset?.({
|
|
94
|
+
args: e,
|
|
95
|
+
reason: "imperative-api"
|
|
96
|
+
}), this.setState(u));
|
|
97
|
+
}
|
|
98
|
+
componentDidCatch(e, t) {
|
|
99
|
+
this.props.onError?.(e, t);
|
|
100
|
+
}
|
|
101
|
+
componentDidUpdate(e, t) {
|
|
102
|
+
const { didCatch: o } = this.state, { resetKeys: n } = this.props;
|
|
103
|
+
o && t.error !== null && h(e.resetKeys, n) && (this.props.onReset?.({
|
|
104
|
+
next: n,
|
|
105
|
+
prev: e.resetKeys,
|
|
106
|
+
reason: "keys"
|
|
107
|
+
}), this.setState(u));
|
|
108
|
+
}
|
|
109
|
+
render() {
|
|
110
|
+
const { children: e, fallbackRender: t, FallbackComponent: o, fallback: n } = this.props, { didCatch: a, error: i } = this.state;
|
|
111
|
+
let d = e;
|
|
112
|
+
if (a) {
|
|
113
|
+
const l = {
|
|
114
|
+
error: i,
|
|
115
|
+
resetErrorBoundary: this.resetErrorBoundary
|
|
116
|
+
};
|
|
117
|
+
if (typeof t == "function") d = t(l);
|
|
118
|
+
else if (o) d = s.createElement(o, l);
|
|
119
|
+
else if (n !== void 0) d = n;
|
|
120
|
+
else throw i;
|
|
121
|
+
}
|
|
122
|
+
return s.createElement(c.Provider, { value: {
|
|
123
|
+
didCatch: a,
|
|
124
|
+
error: i,
|
|
125
|
+
resetErrorBoundary: this.resetErrorBoundary
|
|
126
|
+
} }, d);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
function h(r = [], e = []) {
|
|
130
|
+
return r.length !== e.length || r.some((t, o) => !Object.is(t, e[o]));
|
|
131
|
+
}
|
|
132
|
+
function E(r) {
|
|
133
|
+
return r !== null && typeof r == "object" && "didCatch" in r && typeof r.didCatch == "boolean" && "error" in r && "resetErrorBoundary" in r && typeof r.resetErrorBoundary == "function";
|
|
134
|
+
}
|
|
135
|
+
function f(r) {
|
|
136
|
+
if (!E(r)) throw new Error("ErrorBoundaryContext not found");
|
|
137
|
+
}
|
|
138
|
+
function p() {
|
|
139
|
+
const r = s.useContext(c);
|
|
140
|
+
f(r);
|
|
141
|
+
const { error: e, resetErrorBoundary: t } = r, [o, n] = s.useState({
|
|
142
|
+
error: null,
|
|
143
|
+
hasError: !1
|
|
144
|
+
}), a = s.useMemo(() => ({
|
|
145
|
+
error: e,
|
|
146
|
+
resetBoundary: () => {
|
|
147
|
+
t(), n({
|
|
148
|
+
error: null,
|
|
149
|
+
hasError: !1
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
showBoundary: (i) => n({
|
|
153
|
+
error: i,
|
|
154
|
+
hasError: !0
|
|
155
|
+
})
|
|
156
|
+
}), [e, t]);
|
|
157
|
+
if (o.hasError) throw o.error;
|
|
158
|
+
return a;
|
|
159
|
+
}
|
|
160
|
+
function B(r) {
|
|
161
|
+
switch (typeof r) {
|
|
162
|
+
case "object":
|
|
163
|
+
if (r !== null && "message" in r && typeof r.message == "string") return r.message;
|
|
164
|
+
break;
|
|
165
|
+
case "string": return r;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function m(r, e) {
|
|
169
|
+
const t = s.forwardRef((n, a) => s.createElement(y, e, s.createElement(r, {
|
|
170
|
+
...n,
|
|
171
|
+
ref: a
|
|
172
|
+
})));
|
|
173
|
+
return t.displayName = `withErrorBoundary(${r.displayName || r.name || "Unknown"})`, t;
|
|
174
|
+
}
|
|
175
|
+
exports.ErrorBoundary = y;
|
|
176
|
+
exports.ErrorBoundaryContext = c;
|
|
177
|
+
exports.getErrorMessage = B;
|
|
178
|
+
exports.useErrorBoundary = p;
|
|
179
|
+
exports.withErrorBoundary = m;
|
|
180
|
+
})))();
|
|
181
|
+
function isReactElement(node) {
|
|
182
|
+
return !!(node && typeof node == "object" && "tagName" in node && "attributes" in node);
|
|
183
|
+
}
|
|
184
|
+
function isReactComponent(node) {
|
|
185
|
+
return !!(node && typeof node == "object" && "name" in node && "props" in node);
|
|
186
|
+
}
|
|
187
|
+
function hydrate(documentOrFragment, manifest, schema) {
|
|
188
|
+
const { children: tree } = hydrateChildNodes(getChildNodes(documentOrFragment), Object.assign({}, defaultSchema$1, schema));
|
|
189
|
+
return createReactTree(tree, manifest);
|
|
190
|
+
}
|
|
191
|
+
function createReactTree(tree, manifest) {
|
|
192
|
+
if (Array.isArray(tree)) return createElement(Fragment, null, ...tree.map((child) => createChild(child, manifest)));
|
|
193
|
+
else if (typeof tree == "string") return createElement(Fragment, null, tree);
|
|
194
|
+
return createElementOrComponent(tree, manifest);
|
|
195
|
+
}
|
|
196
|
+
function getChildNodes(documentOrFragment) {
|
|
197
|
+
return "body" in documentOrFragment ? documentOrFragment.body.childNodes : documentOrFragment.childNodes;
|
|
198
|
+
}
|
|
199
|
+
function hydrateChildNodes(childNodes, schema) {
|
|
200
|
+
const result = {
|
|
201
|
+
children: [],
|
|
202
|
+
props: {}
|
|
203
|
+
};
|
|
204
|
+
childNodes.forEach((childNode) => {
|
|
205
|
+
if (isTextNode(childNode)) {
|
|
206
|
+
const text = childNode.textContent;
|
|
207
|
+
if (text?.trim()) result.children.push(text);
|
|
208
|
+
} else if (isElementNode(childNode)) {
|
|
209
|
+
const tagName = childNode.tagName.toLowerCase();
|
|
210
|
+
const { children, props } = hydrateChildNodes(childNode.childNodes, schema);
|
|
211
|
+
if (tagName == schema.componentTagName) {
|
|
212
|
+
const name = childNode.getAttribute(schema.nameAttribute);
|
|
213
|
+
if (!name) throw new Error(`Missing "${schema.nameAttribute}" attribute on <${schema.componentTagName}>`);
|
|
214
|
+
const hydratedProps = hydrateProps(childNode, schema.propsAttribute);
|
|
215
|
+
result.children.push({
|
|
216
|
+
name,
|
|
217
|
+
props: {
|
|
218
|
+
...hydratedProps,
|
|
219
|
+
...props
|
|
220
|
+
},
|
|
221
|
+
children
|
|
222
|
+
});
|
|
223
|
+
} else {
|
|
224
|
+
if (Object.keys(props).length > 0) throw new Error(`<${schema.slotTagName}> only allowed as direct child of <${schema.componentTagName}>`);
|
|
225
|
+
if (tagName == schema.slotTagName) {
|
|
226
|
+
const name = childNode.getAttribute(schema.nameAttribute);
|
|
227
|
+
if (!name) throw new Error(`Missing "${schema.nameAttribute}" attribute on <${schema.slotTagName}>`);
|
|
228
|
+
if (children.length == 1) {
|
|
229
|
+
const child = children[0];
|
|
230
|
+
if (typeof child == "string") result.props[name] = {
|
|
231
|
+
name: "Fragment",
|
|
232
|
+
props: {},
|
|
233
|
+
children: [child]
|
|
234
|
+
};
|
|
235
|
+
else result.props[name] = child;
|
|
236
|
+
} else result.props[name] = {
|
|
237
|
+
name: "Fragment",
|
|
238
|
+
props: {},
|
|
239
|
+
children
|
|
240
|
+
};
|
|
241
|
+
} else result.children.push({
|
|
242
|
+
tagName,
|
|
243
|
+
attributes: Array.from(childNode.attributes).reduce((attrs, attr) => ({
|
|
244
|
+
...attrs,
|
|
245
|
+
[attr.name]: attr.value
|
|
246
|
+
}), {}),
|
|
247
|
+
children
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
function decodeProps(props) {
|
|
255
|
+
return JSON.parse(decode(props));
|
|
256
|
+
}
|
|
257
|
+
function hydrateProps(childNode, propsAttribute) {
|
|
258
|
+
const serializedProps = childNode.getAttribute(propsAttribute);
|
|
259
|
+
return serializedProps ? decodeProps(serializedProps) : {};
|
|
260
|
+
}
|
|
261
|
+
function createElementOrComponent(child, manifest) {
|
|
262
|
+
if ("tagName" in child) {
|
|
263
|
+
const attributes = Object.fromEntries(Object.entries(child.attributes).map(([key, value]) => {
|
|
264
|
+
const attrName = transformAttributeName(key);
|
|
265
|
+
const attrValue = transformAttributeValue(key, value);
|
|
266
|
+
if (attrName.match(/^on[A-Z]/) && typeof attrValue != "function") throw new Error(`Event handler must be a function: ${key}`);
|
|
267
|
+
return [attrName, attrValue];
|
|
268
|
+
}));
|
|
269
|
+
const children = child.children?.map((child) => createChild(child, manifest)) || [];
|
|
270
|
+
return createElement(child.tagName, attributes, ...children);
|
|
271
|
+
}
|
|
272
|
+
const ComponentImpl = child.name == "Fragment" ? Fragment : manifest[child.name];
|
|
273
|
+
if (!ComponentImpl) throw new Error(`Unknown component: ${child.name}`);
|
|
274
|
+
return createElement(ComponentImpl, Object.fromEntries(Object.entries(child.props).map(([key, value]) => {
|
|
275
|
+
const propName = transformPropName(key);
|
|
276
|
+
if (isReactElement(value) || isReactComponent(value)) return [propName, createElementOrComponent(value, manifest)];
|
|
277
|
+
const propValue = transformPropValue(value);
|
|
278
|
+
if (propName.match(/^on[A-Z]/) && typeof propValue != "function") throw new Error(`Event handler must be a function: ${key}`);
|
|
279
|
+
return [propName, propValue];
|
|
280
|
+
})), ...child.children?.map((child) => createChild(child, manifest)) || []);
|
|
281
|
+
}
|
|
282
|
+
function createChild(child, manifest) {
|
|
283
|
+
if (typeof child == "string") return child;
|
|
284
|
+
return createElementOrComponent(child, manifest);
|
|
285
|
+
}
|
|
286
|
+
function transformAttributeName(name) {
|
|
287
|
+
const attributeName = cebabCase(name);
|
|
288
|
+
if (attributeMap[attributeName]) return attributeMap[attributeName];
|
|
289
|
+
else if (attributeName.startsWith("aria-")) return attributeName;
|
|
290
|
+
return camelcase(attributeName);
|
|
291
|
+
}
|
|
292
|
+
function transformAttributeValue(name, value) {
|
|
293
|
+
if (name == "style") return parseStyleAttribute(value);
|
|
294
|
+
if (booleanAttribute.includes(name)) return value != "false" && value != "off" && value != "0";
|
|
295
|
+
return transformStringValue(value);
|
|
296
|
+
}
|
|
297
|
+
function transformPropName(name) {
|
|
298
|
+
if (defaultAttributeMap[name]) return name;
|
|
299
|
+
return transformAttributeName(name);
|
|
300
|
+
}
|
|
301
|
+
function transformPropValue(value) {
|
|
302
|
+
if (isPlainObject(value)) return Object.fromEntries(Object.entries(value).map(([key, value]) => [key, transformPropValue(value)]));
|
|
303
|
+
if (Array.isArray(value)) return value.map((value) => transformPropValue(value));
|
|
304
|
+
if (typeof value == "string") return transformStringValue(value);
|
|
305
|
+
return value;
|
|
306
|
+
}
|
|
307
|
+
function transformStringValue(value) {
|
|
308
|
+
if (value[0] == "$") switch (value[1]) {
|
|
309
|
+
case "$": return value.slice(1);
|
|
310
|
+
case "D": return new Date(Date.parse(value.slice(2)));
|
|
311
|
+
case "n": return BigInt(value.slice(2));
|
|
312
|
+
}
|
|
313
|
+
return value;
|
|
314
|
+
}
|
|
315
|
+
const reactAttributeMap = {
|
|
316
|
+
"accept-charset": "acceptCharset",
|
|
317
|
+
accesskey: "accessKey",
|
|
318
|
+
allowfullscreen: "allowFullScreen",
|
|
319
|
+
allowtransparency: "allowTransparency",
|
|
320
|
+
autocomplete: "autoComplete",
|
|
321
|
+
autofocus: "autoFocus",
|
|
322
|
+
autoplay: "autoPlay",
|
|
323
|
+
cellpadding: "cellPadding",
|
|
324
|
+
cellspacing: "cellSpacing",
|
|
325
|
+
charset: "charSet",
|
|
326
|
+
class: "className",
|
|
327
|
+
colspan: "colSpan",
|
|
328
|
+
contenteditable: "contentEditable",
|
|
329
|
+
contextmenu: "contextMenu",
|
|
330
|
+
crossorigin: "crossOrigin",
|
|
331
|
+
datetime: "dateTime",
|
|
332
|
+
enctype: "encType",
|
|
333
|
+
formaction: "formAction",
|
|
334
|
+
formenctype: "formEncType",
|
|
335
|
+
formmethod: "formMethod",
|
|
336
|
+
formnovalidate: "formNoValidate",
|
|
337
|
+
formtarget: "formTarget",
|
|
338
|
+
frameborder: "frameBorder",
|
|
339
|
+
hreflang: "hrefLang",
|
|
340
|
+
for: "htmlFor",
|
|
341
|
+
inputmode: "inputMode",
|
|
342
|
+
tabindex: "tabIndex",
|
|
343
|
+
usemap: "useMap",
|
|
344
|
+
maxlength: "maxLength",
|
|
345
|
+
minlength: "minLength",
|
|
346
|
+
readonly: "readOnly",
|
|
347
|
+
srcdoc: "srcDoc",
|
|
348
|
+
srclang: "srcLang",
|
|
349
|
+
srcset: "srcSet",
|
|
350
|
+
spellcheck: "spellCheck"
|
|
351
|
+
};
|
|
352
|
+
const defaultAttributeMap = {
|
|
353
|
+
value: "defaultValue",
|
|
354
|
+
checked: "defaultChecked",
|
|
355
|
+
selected: "defaultSelected"
|
|
356
|
+
};
|
|
357
|
+
const attributeMap = {
|
|
358
|
+
...reactAttributeMap,
|
|
359
|
+
...defaultAttributeMap
|
|
360
|
+
};
|
|
361
|
+
const booleanAttribute = [
|
|
362
|
+
"allowfullscreen",
|
|
363
|
+
"autofocus",
|
|
364
|
+
"checked",
|
|
365
|
+
"disabled",
|
|
366
|
+
"formnovalidate",
|
|
367
|
+
"hidden",
|
|
368
|
+
"multiple",
|
|
369
|
+
"novalidate",
|
|
370
|
+
"readonly",
|
|
371
|
+
"required",
|
|
372
|
+
"selected"
|
|
373
|
+
];
|
|
374
|
+
const isElementNode = (node) => node.nodeType == Node.ELEMENT_NODE;
|
|
375
|
+
const isTextNode = (node) => node.nodeType == Node.TEXT_NODE;
|
|
376
|
+
function parseStyleAttribute(styleString) {
|
|
377
|
+
return Object.fromEntries(styleString.split(";").filter((pair) => !!pair.trim()).map((pair) => {
|
|
378
|
+
const [key, value] = pair.split(":");
|
|
379
|
+
if (key && value) return [camelcase(key).trim(), value.trim()];
|
|
380
|
+
throw new Error(`Invalid style attribute: ${styleString}`);
|
|
381
|
+
}));
|
|
382
|
+
}
|
|
383
|
+
function camelcase(str) {
|
|
384
|
+
return str.replace(/-([a-z])/g, ([, a]) => a.toUpperCase());
|
|
385
|
+
}
|
|
386
|
+
function cebabCase(str) {
|
|
387
|
+
return str.replace(/_/g, "-");
|
|
388
|
+
}
|
|
389
|
+
function isPlainObject(value) {
|
|
390
|
+
return typeof value == "object" && value != null && value.constructor == Object;
|
|
391
|
+
}
|
|
392
|
+
//#endregion
|
|
393
|
+
//#region src/react/root.react.tsx
|
|
394
|
+
function createAndRenderReactRoot({ container, subscribe, getSnapshot, onMounted, LayoutComponent, ErrorBoundaryFallbackComponent }) {
|
|
395
|
+
const props = {
|
|
396
|
+
subscribe,
|
|
397
|
+
getSnapshot,
|
|
398
|
+
onMounted,
|
|
399
|
+
ErrorBoundaryFallback: ErrorBoundaryFallbackComponent || DefaultErrorBoundaryFallbackComponent
|
|
400
|
+
};
|
|
401
|
+
const Layout = LayoutComponent || DefaultLayoutComponent;
|
|
402
|
+
const root = createRoot$1(container);
|
|
403
|
+
root.render(/* @__PURE__ */ jsx(Layout, { children: /* @__PURE__ */ jsx(RootProvider, { ...props }) }));
|
|
404
|
+
return () => root.unmount();
|
|
405
|
+
}
|
|
406
|
+
const DefaultLayoutComponent = StrictMode;
|
|
407
|
+
const DefaultErrorBoundaryFallbackComponent = ({ error, element }) => {
|
|
408
|
+
return /* @__PURE__ */ jsx("div", {
|
|
409
|
+
role: "alert",
|
|
410
|
+
children: /* @__PURE__ */ jsx("pre", {
|
|
411
|
+
style: { color: "red" },
|
|
412
|
+
children: element.getAttribute("fallback-message") ?? error.message
|
|
413
|
+
})
|
|
414
|
+
});
|
|
415
|
+
};
|
|
416
|
+
function RootProvider({ subscribe, getSnapshot, onMounted, ErrorBoundaryFallback }) {
|
|
417
|
+
useEffect(onMounted, []);
|
|
418
|
+
const cache = useSyncExternalStore(subscribe, getSnapshot);
|
|
419
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: [...Array.from(cache).map(([element, content]) => createPortal(/* @__PURE__ */ jsx(import_react_error_boundary.ErrorBoundary, {
|
|
420
|
+
fallbackRender: (props) => /* @__PURE__ */ jsx(ErrorBoundaryFallback, {
|
|
421
|
+
element,
|
|
422
|
+
...props
|
|
423
|
+
}),
|
|
424
|
+
children: content
|
|
425
|
+
}), element, getKeyForElement(element)))] });
|
|
426
|
+
}
|
|
427
|
+
const keys = /* @__PURE__ */ new WeakMap();
|
|
428
|
+
function getKeyForElement(element) {
|
|
429
|
+
let key = keys.get(element);
|
|
430
|
+
if (!key) {
|
|
431
|
+
key = Math.random().toString(36).slice(2);
|
|
432
|
+
keys.set(element, key);
|
|
433
|
+
}
|
|
434
|
+
return key;
|
|
435
|
+
}
|
|
436
|
+
//#endregion
|
|
437
|
+
//#region src/react/root.ts
|
|
438
|
+
const defaultSchema = {
|
|
439
|
+
...defaultSchema$1,
|
|
440
|
+
fragmentTagName: "react-fragment",
|
|
441
|
+
loadingClassName: "loading"
|
|
442
|
+
};
|
|
443
|
+
const containerElementMap = /* @__PURE__ */ new Map();
|
|
444
|
+
function findOrCreateContainerElement(id) {
|
|
445
|
+
let container = containerElementMap.get(id) ?? null;
|
|
446
|
+
if (container?.isConnected) return container;
|
|
447
|
+
container = document.querySelector(`body > #${id}`);
|
|
448
|
+
if (container?.isConnected) {
|
|
449
|
+
containerElementMap.set(id, container);
|
|
450
|
+
return container;
|
|
451
|
+
}
|
|
452
|
+
container = document.createElement("div");
|
|
453
|
+
container.id = id;
|
|
454
|
+
document.body.appendChild(container);
|
|
455
|
+
containerElementMap.set(id, container);
|
|
456
|
+
return container;
|
|
457
|
+
}
|
|
458
|
+
function createRoot(containerOrOptions, maybeOptions) {
|
|
459
|
+
const container = containerOrOptions instanceof Element ? containerOrOptions : findOrCreateContainerElement("react-root");
|
|
460
|
+
const options = containerOrOptions instanceof Element ? maybeOptions : containerOrOptions;
|
|
461
|
+
const { loader, manifest: preloadedManifest } = options;
|
|
462
|
+
let isDestroyed = false;
|
|
463
|
+
let cache = /* @__PURE__ */ new Map();
|
|
464
|
+
const mounted = /* @__PURE__ */ new Map();
|
|
465
|
+
const subscriptions = /* @__PURE__ */ new Set();
|
|
466
|
+
const manifest = Object.assign({}, preloadedManifest);
|
|
467
|
+
const schema = Object.assign({}, defaultSchema, options.schema);
|
|
468
|
+
const notify = () => {
|
|
469
|
+
if (!isDestroyed) {
|
|
470
|
+
cache.forEach((_, element) => {
|
|
471
|
+
if (!element.isConnected) {
|
|
472
|
+
cache.delete(element);
|
|
473
|
+
mounted.delete(element);
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
cache = new Map(cache);
|
|
477
|
+
subscriptions.forEach((callback) => callback());
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
const render = async (element, fragmentOrHTML, reset) => {
|
|
481
|
+
const fragment = typeof fragmentOrHTML == "string" ? parseHTMLFragment(fragmentOrHTML, element.ownerDocument) : fragmentOrHTML;
|
|
482
|
+
if (isElement(fragment) && fragment.tagName.toLowerCase() != schema.fragmentTagName) throw new Error("Cannot rerender with a non-fragment element");
|
|
483
|
+
await preload(fragment, (names) => manifestLoader(names, loader, manifest), schema);
|
|
484
|
+
const tree = hydrate(fragment, manifest, schema);
|
|
485
|
+
if (options.cache) saveFragmentCache(element, fragmentOrHTML);
|
|
486
|
+
if (reset) element.innerHTML = "";
|
|
487
|
+
cache.set(element, tree);
|
|
488
|
+
notify();
|
|
489
|
+
element.classList.remove(schema.loadingClassName);
|
|
490
|
+
if (element.classList.length == 0) element.removeAttribute("class");
|
|
491
|
+
};
|
|
492
|
+
const registerDestroyer = (element) => {
|
|
493
|
+
const observer = new MutationObserver((mutations) => {
|
|
494
|
+
const node = mutations.flatMap((mutation) => Array.from(mutation.removedNodes)).find((node) => node == element);
|
|
495
|
+
if (node && !node.isConnected) {
|
|
496
|
+
mounted.delete(element);
|
|
497
|
+
cache.delete(element);
|
|
498
|
+
observer.disconnect();
|
|
499
|
+
notify();
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
observer.observe(element.parentNode, { childList: true });
|
|
503
|
+
};
|
|
504
|
+
const create = async (element) => {
|
|
505
|
+
if (!isDestroyed && !mounted.has(element)) {
|
|
506
|
+
await mounting;
|
|
507
|
+
mounted.set(element, (fragmentOrHTML) => render(element, fragmentOrHTML, false));
|
|
508
|
+
registerDestroyer(element);
|
|
509
|
+
if (options.cache) restoreFragmentCache(element);
|
|
510
|
+
await render(element, element, true);
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
const getSnapshot = () => cache;
|
|
514
|
+
const subscribe = (callback) => {
|
|
515
|
+
if (!isDestroyed) subscriptions.add(callback);
|
|
516
|
+
return () => {
|
|
517
|
+
subscriptions.delete(callback);
|
|
518
|
+
};
|
|
519
|
+
};
|
|
520
|
+
let mounting;
|
|
521
|
+
let unmount;
|
|
522
|
+
const mount = async () => {
|
|
523
|
+
if (isDestroyed) throw new Error("Root is destroyed");
|
|
524
|
+
let onMounted = () => {};
|
|
525
|
+
const mounting = new Promise((resolve) => {
|
|
526
|
+
onMounted = resolve;
|
|
527
|
+
});
|
|
528
|
+
const [LayoutComponent, ErrorBoundaryFallbackComponent] = await Promise.all([getLayoutComponent(loader, options.layoutComponentName), getErrorBoundaryFallbackComponent(loader, options.errorBoundaryFallbackComponentName)]);
|
|
529
|
+
unmount = createAndRenderReactRoot({
|
|
530
|
+
container,
|
|
531
|
+
subscribe,
|
|
532
|
+
getSnapshot,
|
|
533
|
+
onMounted,
|
|
534
|
+
LayoutComponent,
|
|
535
|
+
ErrorBoundaryFallbackComponent
|
|
536
|
+
});
|
|
537
|
+
await mounting;
|
|
538
|
+
};
|
|
539
|
+
return {
|
|
540
|
+
render(element, fragmentOrHTML) {
|
|
541
|
+
if (fragmentOrHTML) {
|
|
542
|
+
const update = mounted.get(element);
|
|
543
|
+
if (update) return {
|
|
544
|
+
count: 1,
|
|
545
|
+
done: update(fragmentOrHTML)
|
|
546
|
+
};
|
|
547
|
+
} else {
|
|
548
|
+
if (!mounting) mounting = mount();
|
|
549
|
+
if (element.tagName.toLowerCase() == schema.fragmentTagName) return {
|
|
550
|
+
count: 1,
|
|
551
|
+
done: create(element)
|
|
552
|
+
};
|
|
553
|
+
else {
|
|
554
|
+
const elements = Array.from(element.querySelectorAll(schema.fragmentTagName));
|
|
555
|
+
if (elements.length) return {
|
|
556
|
+
count: elements.length,
|
|
557
|
+
done: Promise.all(elements.map(create)).then(() => void 0)
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return {
|
|
562
|
+
count: 0,
|
|
563
|
+
done: Promise.resolve()
|
|
564
|
+
};
|
|
565
|
+
},
|
|
566
|
+
remove(element) {
|
|
567
|
+
if (mounted.has(element)) {
|
|
568
|
+
mounted.delete(element);
|
|
569
|
+
cache.delete(element);
|
|
570
|
+
notify();
|
|
571
|
+
return true;
|
|
572
|
+
}
|
|
573
|
+
return false;
|
|
574
|
+
},
|
|
575
|
+
contains(element) {
|
|
576
|
+
return element.tagName.toLowerCase() != schema.fragmentTagName && !!element.closest(schema.fragmentTagName);
|
|
577
|
+
},
|
|
578
|
+
destroy() {
|
|
579
|
+
isDestroyed = true;
|
|
580
|
+
cache.clear();
|
|
581
|
+
notify();
|
|
582
|
+
subscriptions.clear();
|
|
583
|
+
unmount?.();
|
|
584
|
+
mounted.clear();
|
|
585
|
+
container.remove();
|
|
586
|
+
containerElementMap.clear();
|
|
587
|
+
},
|
|
588
|
+
getCache() {
|
|
589
|
+
return cache;
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
async function manifestLoader(names, loader, manifest) {
|
|
594
|
+
await Promise.all(names.filter((name) => !manifest[name]).map((name) => loader(name).then((component) => {
|
|
595
|
+
manifest[name] = component;
|
|
596
|
+
})));
|
|
597
|
+
return manifest;
|
|
598
|
+
}
|
|
599
|
+
async function getLayoutComponent(loader, name) {
|
|
600
|
+
if (name) return await loader(name);
|
|
601
|
+
}
|
|
602
|
+
async function getErrorBoundaryFallbackComponent(loader, name) {
|
|
603
|
+
if (name) return await loader(name);
|
|
604
|
+
}
|
|
605
|
+
let fragmentCacheIdSequence = 0;
|
|
606
|
+
const fragmentCacheIdAttributeName = "data-fragment-id";
|
|
607
|
+
const fragmentCache = /* @__PURE__ */ new Map();
|
|
608
|
+
function resetFragmentCache() {
|
|
609
|
+
fragmentCache.clear();
|
|
610
|
+
}
|
|
611
|
+
function saveFragmentCache(element, fragment) {
|
|
612
|
+
let fragmentCacheId = element.getAttribute(fragmentCacheIdAttributeName);
|
|
613
|
+
if (!fragmentCacheId) {
|
|
614
|
+
fragmentCacheId = `fragment-${fragmentCacheIdSequence++}`;
|
|
615
|
+
element.setAttribute(fragmentCacheIdAttributeName, fragmentCacheId);
|
|
616
|
+
}
|
|
617
|
+
fragmentCache.set(fragmentCacheId, stringifyFragment(fragment));
|
|
618
|
+
}
|
|
619
|
+
function restoreFragmentCache(element) {
|
|
620
|
+
const fragmentCacheId = element.getAttribute(fragmentCacheIdAttributeName);
|
|
621
|
+
if (fragmentCacheId) {
|
|
622
|
+
const html = fragmentCache.get(fragmentCacheId);
|
|
623
|
+
if (html) element.innerHTML = html;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
function stringifyFragment(fragmentOrHTML) {
|
|
627
|
+
if (typeof fragmentOrHTML == "string") return fragmentOrHTML;
|
|
628
|
+
if (isElement(fragmentOrHTML)) return fragmentOrHTML.innerHTML;
|
|
629
|
+
const html = [];
|
|
630
|
+
for (const node of fragmentOrHTML.childNodes) if (isElement(node)) html.push(node.outerHTML);
|
|
631
|
+
else if (node.nodeType == Node.TEXT_NODE && node.textContent) html.push(node.textContent);
|
|
632
|
+
return html.join(" ");
|
|
633
|
+
}
|
|
634
|
+
//#endregion
|
|
635
|
+
export { createReactPlugin, createRoot, defaultSchema, findOrCreateContainerElement, preload, resetFragmentCache };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { f as Action, m as Actions } from "./actions-CQVSvZlC.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/turbo-stream.d.ts
|
|
4
|
+
declare function renderTurboStream(actions: Actions, stream: string): Promise<void>;
|
|
5
|
+
declare function parseTurboStream(stream: Element): Action;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { parseTurboStream, renderTurboStream };
|