@barefootjs/client 0.5.2 → 0.6.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/dist/runtime/apply-rest-attrs.d.ts.map +1 -1
- package/dist/runtime/branch-slot.d.ts +0 -20
- package/dist/runtime/branch-slot.d.ts.map +1 -1
- package/dist/runtime/component.d.ts +22 -0
- package/dist/runtime/component.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +33 -3
- package/dist/runtime/registry.d.ts.map +1 -1
- package/dist/runtime/spread-attrs.d.ts.map +1 -1
- package/dist/runtime/standalone.js +33 -3
- package/package.json +2 -2
- package/src/runtime/apply-rest-attrs.ts +7 -1
- package/src/runtime/branch-slot.ts +10 -3
- package/src/runtime/component.ts +74 -2
- package/src/runtime/index.ts +2 -0
- package/src/runtime/registry.ts +8 -2
- package/src/runtime/spread-attrs.ts +6 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-rest-attrs.d.ts","sourceRoot":"","sources":["../../src/runtime/apply-rest-attrs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,OAAO,EACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,WAAW,EAAE,MAAM,EAAE,GACpB,IAAI,
|
|
1
|
+
{"version":3,"file":"apply-rest-attrs.d.ts","sourceRoot":"","sources":["../../src/runtime/apply-rest-attrs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,OAAO,EACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,WAAW,EAAE,MAAM,EAAE,GACpB,IAAI,CAkEN"}
|
|
@@ -1,22 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Branch-template slot helper (#1213).
|
|
3
|
-
*
|
|
4
|
-
* Conditional `template()` arrows interpolate Child-position expressions
|
|
5
|
-
* via `${expr}`. When `expr` evaluates to a live `Node` (e.g. the result
|
|
6
|
-
* of `_p.renderNode(node())` returning an `HTMLElement` from
|
|
7
|
-
* `createComponent`), the surrounding template literal coerces it via
|
|
8
|
-
* `Object.prototype.toString`, producing `"[object HTMLDivElement]"` and
|
|
9
|
-
* destroying the live node identity on hydration.
|
|
10
|
-
*
|
|
11
|
-
* `__bfSlot` intercepts the value before stringification: if it's a
|
|
12
|
-
* `Node`, it stashes the node into the closure-scoped `slots` array and
|
|
13
|
-
* returns a unique marker comment. The `insert()` runtime then walks the
|
|
14
|
-
* parsed fragment for those markers and splices the original node back
|
|
15
|
-
* in by identity (no `cloneNode`), preserving event listeners and signal
|
|
16
|
-
* bindings.
|
|
17
|
-
*
|
|
18
|
-
* Non-node values fall through to `String(value)` for the existing
|
|
19
|
-
* inline-string path.
|
|
20
|
-
*/
|
|
21
1
|
export declare function __bfSlot(value: unknown, slots: Node[]): string;
|
|
22
2
|
//# sourceMappingURL=branch-slot.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-slot.d.ts","sourceRoot":"","sources":["../../src/runtime/branch-slot.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"branch-slot.d.ts","sourceRoot":"","sources":["../../src/runtime/branch-slot.ts"],"names":[],"mappings":"AA2BA,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,CAW9D"}
|
|
@@ -81,6 +81,28 @@ export declare function renderChild(name: string, props: Record<string, unknown>
|
|
|
81
81
|
* back to ">" in the DOM attribute value, preserving CSS matching.
|
|
82
82
|
*/
|
|
83
83
|
export declare function escapeAttrGt(html: string): string;
|
|
84
|
+
/**
|
|
85
|
+
* HTML-escape a single attribute *value* before it is concatenated into a
|
|
86
|
+
* client-rendered template string. Matches the SSR adapters' attribute
|
|
87
|
+
* escaping (Hono's `escapeToBuffer`: `& " ' < >`) so client-rendered DOM
|
|
88
|
+
* is byte-identical to the server-rendered form and metacharacter-bearing
|
|
89
|
+
* values (UnoCSS `[class*="size-"]`, `has-[>svg]`, …) don't corrupt
|
|
90
|
+
* attribute parsing when the template is inserted via `innerHTML`. `&` is
|
|
91
|
+
* replaced first so the emitted entities aren't themselves re-escaped.
|
|
92
|
+
*/
|
|
93
|
+
export declare function escapeAttr(value: unknown): string;
|
|
94
|
+
/**
|
|
95
|
+
* HTML-escape interpolated **text content** before it is concatenated into
|
|
96
|
+
* a client-rendered template string (the `<!--bf:sN-->…<!--/-->` text
|
|
97
|
+
* slots). The HTML spec only requires `& < >` in text, but the SSR
|
|
98
|
+
* adapters (Hono) escape text with the same set as attribute values
|
|
99
|
+
* (`& " ' < >`), and the fixture-hydrate / CSR-conformance layer requires
|
|
100
|
+
* byte-parity with the server-rendered output — so this delegates to
|
|
101
|
+
* `escapeAttr`. Kept as a distinct export so generated code reads
|
|
102
|
+
* `escapeText(...)` at text sites (self-documenting) and so the two
|
|
103
|
+
* contexts can diverge later without touching call sites.
|
|
104
|
+
*/
|
|
105
|
+
export declare function escapeText(value: unknown): string;
|
|
84
106
|
/**
|
|
85
107
|
* Parse an HTML string into a DocumentFragment, safely escaping ">" in
|
|
86
108
|
* attribute values. All code that sets innerHTML on dynamic HTML should
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/runtime/component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAS3C,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAExD;AAWD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;;;GAGG;AACH;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,GAAG,YAAY,EAChC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACnC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EACrB,IAAI,CAAC,EAAE,uBAAuB,GAC7B,WAAW,
|
|
1
|
+
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../src/runtime/component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAS3C,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAExD;AAWD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;;;GAGG;AACH;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,GAAG,YAAY,EAChC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACnC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EACrB,IAAI,CAAC,EAAE,uBAAuB,GAC7B,WAAW,CAgLb;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAE3F;AAuBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,CAE7G;AAGD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EACrB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAiDR;AA+DD;;;;;GAKG;AACH;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAOjD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEjD;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,gBAAgB,CAcjF"}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export { reconcileElements, getLoopChildren, getLoopNodes } from './reconcile-el
|
|
|
10
10
|
export { qsaItem, upsertChildItem } from './qsa-item';
|
|
11
11
|
export { mapArray, mapArrayAnchored } from './map-array';
|
|
12
12
|
export { registerTemplate, getTemplate, hasTemplate, type TemplateFn } from './template';
|
|
13
|
-
export { createComponent, renderChild, getPropsUpdateFn, getComponentProps, parseHTML, } from './component';
|
|
13
|
+
export { createComponent, renderChild, getPropsUpdateFn, getComponentProps, parseHTML, escapeAttr, escapeText, } from './component';
|
|
14
14
|
export { applyRestAttrs } from './apply-rest-attrs';
|
|
15
15
|
export { spreadAttrs } from './spread-attrs';
|
|
16
16
|
export { styleToCss } from './style';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,UAAU,EACV,UAAU,EACV,SAAS,EACT,OAAO,EACP,OAAO,EACP,KAAK,EACL,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,IAAI,EACT,KAAK,SAAS,EACd,KAAK,QAAQ,GACd,MAAM,6BAA6B,CAAA;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAIlC,OAAO,EACL,aAAa,EACb,UAAU,EACV,cAAc,EACd,eAAe,EACf,KAAK,OAAO,GACb,MAAM,WAAW,CAAA;AAGlB,OAAO,EACL,YAAY,EACZ,WAAW,EACX,eAAe,EACf,wBAAwB,EACxB,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,cAAc,GACpB,MAAM,UAAU,CAAA;AAGjB,OAAO,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACvF,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGxD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAA;AAGxF,OAAO,EACL,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,UAAU,EACV,UAAU,EACV,SAAS,EACT,OAAO,EACP,OAAO,EACP,KAAK,EACL,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,IAAI,EACT,KAAK,SAAS,EACd,KAAK,QAAQ,GACd,MAAM,6BAA6B,CAAA;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAIlC,OAAO,EACL,aAAa,EACb,UAAU,EACV,cAAc,EACd,eAAe,EACf,KAAK,OAAO,GACb,MAAM,WAAW,CAAA;AAGlB,OAAO,EACL,YAAY,EACZ,WAAW,EACX,eAAe,EACf,wBAAwB,EACxB,KAAK,MAAM,EACX,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,cAAc,GACpB,MAAM,UAAU,CAAA;AAGjB,OAAO,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,QAAQ,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACvF,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACrD,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGxD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAA;AAGxF,OAAO,EACL,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,UAAU,EACV,UAAU,GACX,MAAM,aAAa,CAAA;AAGpB,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAGpC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,aAAa,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnG,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AACnF,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxF,OAAO,EAAE,MAAM,EAAE,KAAK,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAGpD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAGlD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAGjC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAGvD,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/runtime/index.js
CHANGED
|
@@ -123,6 +123,7 @@ function loopEndMarker(markerId) {
|
|
|
123
123
|
return `${BF_LOOP_END}:${markerId}`;
|
|
124
124
|
}
|
|
125
125
|
var BF_KEY = "data-key";
|
|
126
|
+
var BF_PLACEHOLDER = "data-bf-ph";
|
|
126
127
|
var BF_ASYNC = "bf-async";
|
|
127
128
|
var BF_ASYNC_RESOLVE = "bf-async-resolve";
|
|
128
129
|
var BF_PARENT_SCOPE_PLACEHOLDER = "__BF_PARENT_SCOPE__";
|
|
@@ -248,6 +249,8 @@ function classifyDOMProp(key) {
|
|
|
248
249
|
return { kind: "skip", attrName: key };
|
|
249
250
|
if (key === "ref")
|
|
250
251
|
return { kind: "ref", attrName: key };
|
|
252
|
+
if (key === "dangerouslySetInnerHTML")
|
|
253
|
+
return { kind: "innerHTML", attrName: key };
|
|
251
254
|
if (isEventProp(key))
|
|
252
255
|
return { kind: "event", attrName: key };
|
|
253
256
|
const attrName = toHTMLAttrNameRuntime(key);
|
|
@@ -791,7 +794,7 @@ function upsertChild(parent, name, slotId, props, key, anchorScope) {
|
|
|
791
794
|
return ssr;
|
|
792
795
|
}
|
|
793
796
|
const phId = slotId ?? name;
|
|
794
|
-
const ph = parent.querySelector(`[
|
|
797
|
+
const ph = parent.getAttribute(BF_PLACEHOLDER) === phId ? parent : parent.querySelector(`[${BF_PLACEHOLDER}="${phId}"]`);
|
|
795
798
|
if (ph) {
|
|
796
799
|
const slot = slotId ? buildSlotInfo(parent, slotId, anchorScope) : undefined;
|
|
797
800
|
const comp = createComponent(name, props, key, slot);
|
|
@@ -1017,10 +1020,24 @@ function createComponent(nameOrDef, props = {}, key, slot) {
|
|
|
1017
1020
|
element.setAttribute(BF_KEY, String(key));
|
|
1018
1021
|
}
|
|
1019
1022
|
const prevScope = setCurrentScope(element);
|
|
1023
|
+
const rootIsDeferredPlaceholder = element.hasAttribute(BF_PLACEHOLDER);
|
|
1024
|
+
let placeholderWrapper = null;
|
|
1025
|
+
if (rootIsDeferredPlaceholder) {
|
|
1026
|
+
placeholderWrapper = parseHTML("<div></div>").firstChild;
|
|
1027
|
+
placeholderWrapper.appendChild(element);
|
|
1028
|
+
}
|
|
1020
1029
|
const initFn = getComponentInit(name);
|
|
1021
1030
|
if (initFn) {
|
|
1022
1031
|
initFn(element, props);
|
|
1023
1032
|
}
|
|
1033
|
+
if (rootIsDeferredPlaceholder && placeholderWrapper) {
|
|
1034
|
+
const materialised = placeholderWrapper.firstElementChild;
|
|
1035
|
+
if (materialised && !materialised.hasAttribute(BF_PLACEHOLDER)) {
|
|
1036
|
+
setCurrentScope(prevScope);
|
|
1037
|
+
return materialised;
|
|
1038
|
+
}
|
|
1039
|
+
placeholderWrapper.removeChild(element);
|
|
1040
|
+
}
|
|
1024
1041
|
if (childrenIsGetter) {
|
|
1025
1042
|
const children = untrack(() => childrenDescriptor.get());
|
|
1026
1043
|
if (children != null) {
|
|
@@ -1104,6 +1121,12 @@ function unwrapPropsForTemplate(props) {
|
|
|
1104
1121
|
function escapeAttrGt(html) {
|
|
1105
1122
|
return html.replace(/"[^"]*"/g, (match) => match.replace(/>/g, ">"));
|
|
1106
1123
|
}
|
|
1124
|
+
function escapeAttr(value) {
|
|
1125
|
+
return String(value).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
1126
|
+
}
|
|
1127
|
+
function escapeText(value) {
|
|
1128
|
+
return escapeAttr(value);
|
|
1129
|
+
}
|
|
1107
1130
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1108
1131
|
function parseHTML(html, parent) {
|
|
1109
1132
|
const tpl = document.createElement("template");
|
|
@@ -1932,7 +1955,10 @@ function applyRestAttrs(el, source, excludeKeys) {
|
|
|
1932
1955
|
createEffect2(() => {
|
|
1933
1956
|
for (const { key, c } of attrEntries) {
|
|
1934
1957
|
const value = source[key];
|
|
1935
|
-
if (
|
|
1958
|
+
if (c.kind === "innerHTML") {
|
|
1959
|
+
const html = value;
|
|
1960
|
+
el.innerHTML = html != null && html.__html != null ? String(html.__html) : "";
|
|
1961
|
+
} else if (value != null && value !== false) {
|
|
1936
1962
|
if (c.kind === "property" && c.attrName === "value" && "value" in el) {
|
|
1937
1963
|
const strVal = String(value);
|
|
1938
1964
|
if (el.value !== strVal)
|
|
@@ -1975,6 +2001,8 @@ function spreadAttrs(obj) {
|
|
|
1975
2001
|
const c = classifyDOMProp(key);
|
|
1976
2002
|
if (c.kind === "event" || c.kind === "skip" || c.kind === "ref")
|
|
1977
2003
|
continue;
|
|
2004
|
+
if (c.kind === "innerHTML")
|
|
2005
|
+
continue;
|
|
1978
2006
|
if (c.kind === "style") {
|
|
1979
2007
|
const css = styleToCss(value);
|
|
1980
2008
|
if (css != null)
|
|
@@ -2251,7 +2279,7 @@ function __bfSlot(value, slots) {
|
|
|
2251
2279
|
if (Array.isArray(value)) {
|
|
2252
2280
|
return value.map((v) => __bfSlot(v, slots)).join("");
|
|
2253
2281
|
}
|
|
2254
|
-
return
|
|
2282
|
+
return escapeText(value);
|
|
2255
2283
|
}
|
|
2256
2284
|
// src/runtime/dynamic-text.ts
|
|
2257
2285
|
var END_MARKER = "/";
|
|
@@ -2445,6 +2473,8 @@ export {
|
|
|
2445
2473
|
findSiblingSlot,
|
|
2446
2474
|
findScope,
|
|
2447
2475
|
find,
|
|
2476
|
+
escapeText,
|
|
2477
|
+
escapeAttr,
|
|
2448
2478
|
cssEscape,
|
|
2449
2479
|
createSignal2 as createSignal,
|
|
2450
2480
|
createRoot2 as createRoot,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/runtime/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAarC;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAclE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,OAAO,GAAG,IAAI,EAC1B,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAClC,IAAI,CAoCN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EACrB,WAAW,CAAC,EAAE,OAAO,GAAG,IAAI,GAC3B,WAAW,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/runtime/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAarC;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAclE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,OAAO,GAAG,IAAI,EAC1B,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAClC,IAAI,CAoCN;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EACrB,WAAW,CAAC,EAAE,OAAO,GAAG,IAAI,GAC3B,WAAW,GAAG,IAAI,CA8BpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spread-attrs.d.ts","sourceRoot":"","sources":["../../src/runtime/spread-attrs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"spread-attrs.d.ts","sourceRoot":"","sources":["../../src/runtime/spread-attrs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAyBhE"}
|
|
@@ -314,6 +314,7 @@ function loopEndMarker(markerId) {
|
|
|
314
314
|
return `${BF_LOOP_END}:${markerId}`;
|
|
315
315
|
}
|
|
316
316
|
var BF_KEY = "data-key";
|
|
317
|
+
var BF_PLACEHOLDER = "data-bf-ph";
|
|
317
318
|
var BF_ASYNC = "bf-async";
|
|
318
319
|
var BF_ASYNC_RESOLVE = "bf-async-resolve";
|
|
319
320
|
var BF_PARENT_SCOPE_PLACEHOLDER = "__BF_PARENT_SCOPE__";
|
|
@@ -439,6 +440,8 @@ function classifyDOMProp(key) {
|
|
|
439
440
|
return { kind: "skip", attrName: key };
|
|
440
441
|
if (key === "ref")
|
|
441
442
|
return { kind: "ref", attrName: key };
|
|
443
|
+
if (key === "dangerouslySetInnerHTML")
|
|
444
|
+
return { kind: "innerHTML", attrName: key };
|
|
442
445
|
if (isEventProp(key))
|
|
443
446
|
return { kind: "event", attrName: key };
|
|
444
447
|
const attrName = toHTMLAttrNameRuntime(key);
|
|
@@ -982,7 +985,7 @@ function upsertChild(parent, name, slotId, props, key, anchorScope) {
|
|
|
982
985
|
return ssr;
|
|
983
986
|
}
|
|
984
987
|
const phId = slotId ?? name;
|
|
985
|
-
const ph = parent.querySelector(`[
|
|
988
|
+
const ph = parent.getAttribute(BF_PLACEHOLDER) === phId ? parent : parent.querySelector(`[${BF_PLACEHOLDER}="${phId}"]`);
|
|
986
989
|
if (ph) {
|
|
987
990
|
const slot = slotId ? buildSlotInfo(parent, slotId, anchorScope) : undefined;
|
|
988
991
|
const comp = createComponent(name, props, key, slot);
|
|
@@ -1207,10 +1210,24 @@ function createComponent(nameOrDef, props = {}, key, slot) {
|
|
|
1207
1210
|
element.setAttribute(BF_KEY, String(key));
|
|
1208
1211
|
}
|
|
1209
1212
|
const prevScope = setCurrentScope(element);
|
|
1213
|
+
const rootIsDeferredPlaceholder = element.hasAttribute(BF_PLACEHOLDER);
|
|
1214
|
+
let placeholderWrapper = null;
|
|
1215
|
+
if (rootIsDeferredPlaceholder) {
|
|
1216
|
+
placeholderWrapper = parseHTML("<div></div>").firstChild;
|
|
1217
|
+
placeholderWrapper.appendChild(element);
|
|
1218
|
+
}
|
|
1210
1219
|
const initFn = getComponentInit(name);
|
|
1211
1220
|
if (initFn) {
|
|
1212
1221
|
initFn(element, props);
|
|
1213
1222
|
}
|
|
1223
|
+
if (rootIsDeferredPlaceholder && placeholderWrapper) {
|
|
1224
|
+
const materialised = placeholderWrapper.firstElementChild;
|
|
1225
|
+
if (materialised && !materialised.hasAttribute(BF_PLACEHOLDER)) {
|
|
1226
|
+
setCurrentScope(prevScope);
|
|
1227
|
+
return materialised;
|
|
1228
|
+
}
|
|
1229
|
+
placeholderWrapper.removeChild(element);
|
|
1230
|
+
}
|
|
1214
1231
|
if (childrenIsGetter) {
|
|
1215
1232
|
const children = untrack(() => childrenDescriptor.get());
|
|
1216
1233
|
if (children != null) {
|
|
@@ -1294,6 +1311,12 @@ function unwrapPropsForTemplate(props) {
|
|
|
1294
1311
|
function escapeAttrGt(html) {
|
|
1295
1312
|
return html.replace(/"[^"]*"/g, (match) => match.replace(/>/g, ">"));
|
|
1296
1313
|
}
|
|
1314
|
+
function escapeAttr(value) {
|
|
1315
|
+
return String(value).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
1316
|
+
}
|
|
1317
|
+
function escapeText(value) {
|
|
1318
|
+
return escapeAttr(value);
|
|
1319
|
+
}
|
|
1297
1320
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1298
1321
|
function parseHTML(html, parent) {
|
|
1299
1322
|
const tpl = document.createElement("template");
|
|
@@ -2118,7 +2141,10 @@ function applyRestAttrs(el, source, excludeKeys) {
|
|
|
2118
2141
|
createEffect(() => {
|
|
2119
2142
|
for (const { key, c } of attrEntries) {
|
|
2120
2143
|
const value = source[key];
|
|
2121
|
-
if (
|
|
2144
|
+
if (c.kind === "innerHTML") {
|
|
2145
|
+
const html = value;
|
|
2146
|
+
el.innerHTML = html != null && html.__html != null ? String(html.__html) : "";
|
|
2147
|
+
} else if (value != null && value !== false) {
|
|
2122
2148
|
if (c.kind === "property" && c.attrName === "value" && "value" in el) {
|
|
2123
2149
|
const strVal = String(value);
|
|
2124
2150
|
if (el.value !== strVal)
|
|
@@ -2161,6 +2187,8 @@ function spreadAttrs(obj) {
|
|
|
2161
2187
|
const c = classifyDOMProp(key);
|
|
2162
2188
|
if (c.kind === "event" || c.kind === "skip" || c.kind === "ref")
|
|
2163
2189
|
continue;
|
|
2190
|
+
if (c.kind === "innerHTML")
|
|
2191
|
+
continue;
|
|
2164
2192
|
if (c.kind === "style") {
|
|
2165
2193
|
const css = styleToCss(value);
|
|
2166
2194
|
if (css != null)
|
|
@@ -2436,7 +2464,7 @@ function __bfSlot(value, slots) {
|
|
|
2436
2464
|
if (Array.isArray(value)) {
|
|
2437
2465
|
return value.map((v) => __bfSlot(v, slots)).join("");
|
|
2438
2466
|
}
|
|
2439
|
-
return
|
|
2467
|
+
return escapeText(value);
|
|
2440
2468
|
}
|
|
2441
2469
|
// src/runtime/dynamic-text.ts
|
|
2442
2470
|
var END_MARKER = "/";
|
|
@@ -2630,6 +2658,8 @@ export {
|
|
|
2630
2658
|
findSiblingSlot,
|
|
2631
2659
|
findScope,
|
|
2632
2660
|
find,
|
|
2661
|
+
escapeText,
|
|
2662
|
+
escapeAttr,
|
|
2633
2663
|
cssEscape,
|
|
2634
2664
|
createSignal,
|
|
2635
2665
|
createRoot,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "BarefootJS client package: reactive primitives (SSR-safe) plus browser runtime under the `/runtime` subpath (compiler target)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"directory": "packages/client"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@barefootjs/shared": "0.
|
|
58
|
+
"@barefootjs/shared": "0.6.0"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@barefootjs/jsx": ">=0.2.0"
|
|
@@ -64,7 +64,13 @@ export function applyRestAttrs(
|
|
|
64
64
|
for (const { key, c } of attrEntries) {
|
|
65
65
|
const value = source[key]
|
|
66
66
|
|
|
67
|
-
if (
|
|
67
|
+
if (c.kind === 'innerHTML') {
|
|
68
|
+
// `dangerouslySetInnerHTML={{ __html }}` arriving via a rest object —
|
|
69
|
+
// set the element's raw innerHTML (the escape hatch), never an
|
|
70
|
+
// attribute. Reactive: re-runs when `source` changes.
|
|
71
|
+
const html = value as { __html?: unknown } | null | undefined
|
|
72
|
+
el.innerHTML = html != null && html.__html != null ? String(html.__html) : ''
|
|
73
|
+
} else if (value != null && value !== false) {
|
|
68
74
|
if (c.kind === 'property' && c.attrName === 'value' && 'value' in el) {
|
|
69
75
|
const strVal = String(value)
|
|
70
76
|
if ((el as HTMLInputElement).value !== strVal) (el as HTMLInputElement).value = strVal
|
|
@@ -15,9 +15,16 @@
|
|
|
15
15
|
* in by identity (no `cloneNode`), preserving event listeners and signal
|
|
16
16
|
* bindings.
|
|
17
17
|
*
|
|
18
|
-
* Non-node values fall through to
|
|
19
|
-
*
|
|
18
|
+
* Non-node values fall through to the inline-string path, HTML-escaped
|
|
19
|
+
* (#1694 follow-up) so a branch-template text value containing `< / &`
|
|
20
|
+
* surfaces as text — not markup — and matches the SSR-rendered bytes.
|
|
21
|
+
* Escaping happens here, on the string path only, so the `<!--bf-slot:N-->`
|
|
22
|
+
* markers returned for live `Node` values are left intact for `insert()`
|
|
23
|
+
* to splice. (Doing it here rather than wrapping the whole `__bfSlot(...)`
|
|
24
|
+
* call in `escapeText` is what lets the marker path stay raw.)
|
|
20
25
|
*/
|
|
26
|
+
import { escapeText } from './component'
|
|
27
|
+
|
|
21
28
|
export function __bfSlot(value: unknown, slots: Node[]): string {
|
|
22
29
|
if (value == null || value === false || value === true) return ''
|
|
23
30
|
if (typeof Node !== 'undefined' && value instanceof Node) {
|
|
@@ -28,5 +35,5 @@ export function __bfSlot(value: unknown, slots: Node[]): string {
|
|
|
28
35
|
if (Array.isArray(value)) {
|
|
29
36
|
return value.map((v) => __bfSlot(v, slots)).join('')
|
|
30
37
|
}
|
|
31
|
-
return
|
|
38
|
+
return escapeText(value)
|
|
32
39
|
}
|
package/src/runtime/component.ts
CHANGED
|
@@ -11,7 +11,7 @@ import { getRegisteredDef } from './hydrate'
|
|
|
11
11
|
import { hydratedScopes } from './hydration-state'
|
|
12
12
|
import { untrack } from '@barefootjs/client/reactive'
|
|
13
13
|
import { setCurrentScope } from './context'
|
|
14
|
-
import { BF_SCOPE, BF_KEY, BF_HOST, BF_AT, BF_PARENT_SCOPE_PLACEHOLDER } from '@barefootjs/shared'
|
|
14
|
+
import { BF_SCOPE, BF_KEY, BF_HOST, BF_AT, BF_PARENT_SCOPE_PLACEHOLDER, BF_PLACEHOLDER } from '@barefootjs/shared'
|
|
15
15
|
import type { ComponentDef } from './types'
|
|
16
16
|
|
|
17
17
|
// Parent scope ID context for renderChild() inside insert() branch templates.
|
|
@@ -186,13 +186,52 @@ export function createComponent(
|
|
|
186
186
|
// This allows context providers in initFn to store context on this element.
|
|
187
187
|
const prevScope = setCurrentScope(element)
|
|
188
188
|
|
|
189
|
+
// 8b. Root-level deferred child (dropped-prop fix): a comment-wrapper
|
|
190
|
+
// parent whose entire render is a single deferred child renders as a
|
|
191
|
+
// bare `data-bf-ph` placeholder. The parent's init calls
|
|
192
|
+
// `upsertChild(__scope, ...)` which replaces the placeholder via
|
|
193
|
+
// `replaceWith` — but a detached root node can't replace itself in
|
|
194
|
+
// place. Park it in a throwaway wrapper so the replacement lands
|
|
195
|
+
// somewhere we can recover, then return the materialised child.
|
|
196
|
+
const rootIsDeferredPlaceholder = element.hasAttribute(BF_PLACEHOLDER)
|
|
197
|
+
let placeholderWrapper: HTMLElement | null = null
|
|
198
|
+
if (rootIsDeferredPlaceholder) {
|
|
199
|
+
placeholderWrapper = parseHTML('<div></div>').firstChild as HTMLElement
|
|
200
|
+
placeholderWrapper.appendChild(element)
|
|
201
|
+
}
|
|
202
|
+
|
|
189
203
|
// 9. Initialize the component (context providers set up here).
|
|
190
204
|
const initFn = getComponentInit(name)
|
|
191
205
|
if (initFn) {
|
|
192
|
-
// Pass original props (with getters) for reactivity
|
|
206
|
+
// Pass original props (with getters) for reactivity. For a root
|
|
207
|
+
// deferred placeholder, init's `upsertChild(element, ...)` matches the
|
|
208
|
+
// placeholder element itself and replaces it inside the wrapper.
|
|
193
209
|
initFn(element, props)
|
|
194
210
|
}
|
|
195
211
|
|
|
212
|
+
if (rootIsDeferredPlaceholder && placeholderWrapper) {
|
|
213
|
+
const materialised = placeholderWrapper.firstElementChild as HTMLElement | null
|
|
214
|
+
if (materialised && !materialised.hasAttribute(BF_PLACEHOLDER)) {
|
|
215
|
+
// The deferred child was created in place of the placeholder.
|
|
216
|
+
// `materialised` is the child's OWN element, created via
|
|
217
|
+
// upsertChild -> createComponent, which already registered itself
|
|
218
|
+
// (hydratedScopes / propsMap / registerPropsUpdate) keyed to the
|
|
219
|
+
// child with the child's own props. We must NOT re-register it here:
|
|
220
|
+
// overwriting propsMap/registerPropsUpdate with the *parent's* props
|
|
221
|
+
// would mis-key the child (e.g. a later getComponentProps would read
|
|
222
|
+
// the parent's props), and re-running the parent's init on an element
|
|
223
|
+
// whose placeholder is already gone could not re-materialise. So just
|
|
224
|
+
// restore the scope and return the already-registered child.
|
|
225
|
+
// (Parent-scope effects are unaffected: createEffect ownership lives
|
|
226
|
+
// in the EffectContext tree, not the discarded placeholder element.)
|
|
227
|
+
setCurrentScope(prevScope)
|
|
228
|
+
return materialised
|
|
229
|
+
}
|
|
230
|
+
// Placeholder was not replaced (no init / no matching child): fall
|
|
231
|
+
// through with the original placeholder element detached from wrapper.
|
|
232
|
+
placeholderWrapper.removeChild(element)
|
|
233
|
+
}
|
|
234
|
+
|
|
196
235
|
// 10. Evaluate getter children and insert them.
|
|
197
236
|
// Children are evaluated NOW (after initFn) so that context provided by
|
|
198
237
|
// the parent is in the global store when children call useContext().
|
|
@@ -400,6 +439,39 @@ export function escapeAttrGt(html: string): string {
|
|
|
400
439
|
return html.replace(/"[^"]*"/g, match => match.replace(/>/g, '>'))
|
|
401
440
|
}
|
|
402
441
|
|
|
442
|
+
/**
|
|
443
|
+
* HTML-escape a single attribute *value* before it is concatenated into a
|
|
444
|
+
* client-rendered template string. Matches the SSR adapters' attribute
|
|
445
|
+
* escaping (Hono's `escapeToBuffer`: `& " ' < >`) so client-rendered DOM
|
|
446
|
+
* is byte-identical to the server-rendered form and metacharacter-bearing
|
|
447
|
+
* values (UnoCSS `[class*="size-"]`, `has-[>svg]`, …) don't corrupt
|
|
448
|
+
* attribute parsing when the template is inserted via `innerHTML`. `&` is
|
|
449
|
+
* replaced first so the emitted entities aren't themselves re-escaped.
|
|
450
|
+
*/
|
|
451
|
+
export function escapeAttr(value: unknown): string {
|
|
452
|
+
return String(value)
|
|
453
|
+
.replace(/&/g, '&')
|
|
454
|
+
.replace(/"/g, '"')
|
|
455
|
+
.replace(/'/g, ''')
|
|
456
|
+
.replace(/</g, '<')
|
|
457
|
+
.replace(/>/g, '>')
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* HTML-escape interpolated **text content** before it is concatenated into
|
|
462
|
+
* a client-rendered template string (the `<!--bf:sN-->…<!--/-->` text
|
|
463
|
+
* slots). The HTML spec only requires `& < >` in text, but the SSR
|
|
464
|
+
* adapters (Hono) escape text with the same set as attribute values
|
|
465
|
+
* (`& " ' < >`), and the fixture-hydrate / CSR-conformance layer requires
|
|
466
|
+
* byte-parity with the server-rendered output — so this delegates to
|
|
467
|
+
* `escapeAttr`. Kept as a distinct export so generated code reads
|
|
468
|
+
* `escapeText(...)` at text sites (self-documenting) and so the two
|
|
469
|
+
* contexts can diverge later without touching call sites.
|
|
470
|
+
*/
|
|
471
|
+
export function escapeText(value: unknown): string {
|
|
472
|
+
return escapeAttr(value)
|
|
473
|
+
}
|
|
474
|
+
|
|
403
475
|
const SVG_NS = 'http://www.w3.org/2000/svg'
|
|
404
476
|
|
|
405
477
|
/**
|
package/src/runtime/index.ts
CHANGED
package/src/runtime/registry.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Each component registers its init function so parents can initialize children with props.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { BF_SCOPE, BF_HOST } from '@barefootjs/shared'
|
|
8
|
+
import { BF_SCOPE, BF_HOST, BF_PLACEHOLDER } from '@barefootjs/shared'
|
|
9
9
|
import { hydratedScopes } from './hydration-state'
|
|
10
10
|
import { setCurrentScope } from './context'
|
|
11
11
|
import { createComponent } from './component'
|
|
@@ -148,8 +148,14 @@ export function upsertChild(
|
|
|
148
148
|
return ssr
|
|
149
149
|
}
|
|
150
150
|
// CSR: replace placeholder with a freshly-created component.
|
|
151
|
+
// The placeholder is normally a descendant of `parent`; but a
|
|
152
|
+
// comment-scope parent whose root IS the deferred child renders the
|
|
153
|
+
// placeholder as `parent` itself (no wrapper element), so match the
|
|
154
|
+
// parent element directly before falling back to a subtree query.
|
|
151
155
|
const phId = slotId ?? name
|
|
152
|
-
const ph = parent.
|
|
156
|
+
const ph = (parent.getAttribute(BF_PLACEHOLDER) === phId
|
|
157
|
+
? (parent as HTMLElement)
|
|
158
|
+
: parent.querySelector(`[${BF_PLACEHOLDER}="${phId}"]`)) as HTMLElement | null
|
|
153
159
|
if (ph) {
|
|
154
160
|
const slot = slotId ? buildSlotInfo(parent, slotId, anchorScope) : undefined
|
|
155
161
|
const comp = createComponent(name, props, key, slot)
|
|
@@ -23,6 +23,12 @@ export function spreadAttrs(obj: Record<string, unknown>): string {
|
|
|
23
23
|
if (value == null || value === false) continue
|
|
24
24
|
const c = classifyDOMProp(key)
|
|
25
25
|
if (c.kind === 'event' || c.kind === 'skip' || c.kind === 'ref') continue
|
|
26
|
+
// `dangerouslySetInnerHTML` is not an attribute — its `{ __html }` is the
|
|
27
|
+
// element's content, which this attribute-string builder can't emit. Skip
|
|
28
|
+
// it so a spread carrying it never serialises a bogus
|
|
29
|
+
// `dangerouslySetInnerHTML="[object Object]"`. (Content is set by the
|
|
30
|
+
// template for an explicit attr, or by `applyRestAttrs` for a rest object.)
|
|
31
|
+
if (c.kind === 'innerHTML') continue
|
|
26
32
|
if (c.kind === 'style') {
|
|
27
33
|
const css = styleToCss(value)
|
|
28
34
|
if (css != null) parts.push(`style="${css}"`)
|