@barefootjs/client 0.5.2 → 0.5.3
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 +17 -2
- package/dist/runtime/spread-attrs.d.ts.map +1 -1
- package/dist/runtime/standalone.js +17 -2
- 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 +33 -0
- package/src/runtime/index.ts +2 -0
- 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,CAyIb;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;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,GAAG,gBAAgB,CAcjF"}
|
|
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,CAyIb;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
|
@@ -248,6 +248,8 @@ function classifyDOMProp(key) {
|
|
|
248
248
|
return { kind: "skip", attrName: key };
|
|
249
249
|
if (key === "ref")
|
|
250
250
|
return { kind: "ref", attrName: key };
|
|
251
|
+
if (key === "dangerouslySetInnerHTML")
|
|
252
|
+
return { kind: "innerHTML", attrName: key };
|
|
251
253
|
if (isEventProp(key))
|
|
252
254
|
return { kind: "event", attrName: key };
|
|
253
255
|
const attrName = toHTMLAttrNameRuntime(key);
|
|
@@ -1104,6 +1106,12 @@ function unwrapPropsForTemplate(props) {
|
|
|
1104
1106
|
function escapeAttrGt(html) {
|
|
1105
1107
|
return html.replace(/"[^"]*"/g, (match) => match.replace(/>/g, ">"));
|
|
1106
1108
|
}
|
|
1109
|
+
function escapeAttr(value) {
|
|
1110
|
+
return String(value).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
1111
|
+
}
|
|
1112
|
+
function escapeText(value) {
|
|
1113
|
+
return escapeAttr(value);
|
|
1114
|
+
}
|
|
1107
1115
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1108
1116
|
function parseHTML(html, parent) {
|
|
1109
1117
|
const tpl = document.createElement("template");
|
|
@@ -1932,7 +1940,10 @@ function applyRestAttrs(el, source, excludeKeys) {
|
|
|
1932
1940
|
createEffect2(() => {
|
|
1933
1941
|
for (const { key, c } of attrEntries) {
|
|
1934
1942
|
const value = source[key];
|
|
1935
|
-
if (
|
|
1943
|
+
if (c.kind === "innerHTML") {
|
|
1944
|
+
const html = value;
|
|
1945
|
+
el.innerHTML = html != null && html.__html != null ? String(html.__html) : "";
|
|
1946
|
+
} else if (value != null && value !== false) {
|
|
1936
1947
|
if (c.kind === "property" && c.attrName === "value" && "value" in el) {
|
|
1937
1948
|
const strVal = String(value);
|
|
1938
1949
|
if (el.value !== strVal)
|
|
@@ -1975,6 +1986,8 @@ function spreadAttrs(obj) {
|
|
|
1975
1986
|
const c = classifyDOMProp(key);
|
|
1976
1987
|
if (c.kind === "event" || c.kind === "skip" || c.kind === "ref")
|
|
1977
1988
|
continue;
|
|
1989
|
+
if (c.kind === "innerHTML")
|
|
1990
|
+
continue;
|
|
1978
1991
|
if (c.kind === "style") {
|
|
1979
1992
|
const css = styleToCss(value);
|
|
1980
1993
|
if (css != null)
|
|
@@ -2251,7 +2264,7 @@ function __bfSlot(value, slots) {
|
|
|
2251
2264
|
if (Array.isArray(value)) {
|
|
2252
2265
|
return value.map((v) => __bfSlot(v, slots)).join("");
|
|
2253
2266
|
}
|
|
2254
|
-
return
|
|
2267
|
+
return escapeText(value);
|
|
2255
2268
|
}
|
|
2256
2269
|
// src/runtime/dynamic-text.ts
|
|
2257
2270
|
var END_MARKER = "/";
|
|
@@ -2445,6 +2458,8 @@ export {
|
|
|
2445
2458
|
findSiblingSlot,
|
|
2446
2459
|
findScope,
|
|
2447
2460
|
find,
|
|
2461
|
+
escapeText,
|
|
2462
|
+
escapeAttr,
|
|
2448
2463
|
cssEscape,
|
|
2449
2464
|
createSignal2 as createSignal,
|
|
2450
2465
|
createRoot2 as createRoot,
|
|
@@ -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"}
|
|
@@ -439,6 +439,8 @@ function classifyDOMProp(key) {
|
|
|
439
439
|
return { kind: "skip", attrName: key };
|
|
440
440
|
if (key === "ref")
|
|
441
441
|
return { kind: "ref", attrName: key };
|
|
442
|
+
if (key === "dangerouslySetInnerHTML")
|
|
443
|
+
return { kind: "innerHTML", attrName: key };
|
|
442
444
|
if (isEventProp(key))
|
|
443
445
|
return { kind: "event", attrName: key };
|
|
444
446
|
const attrName = toHTMLAttrNameRuntime(key);
|
|
@@ -1294,6 +1296,12 @@ function unwrapPropsForTemplate(props) {
|
|
|
1294
1296
|
function escapeAttrGt(html) {
|
|
1295
1297
|
return html.replace(/"[^"]*"/g, (match) => match.replace(/>/g, ">"));
|
|
1296
1298
|
}
|
|
1299
|
+
function escapeAttr(value) {
|
|
1300
|
+
return String(value).replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">");
|
|
1301
|
+
}
|
|
1302
|
+
function escapeText(value) {
|
|
1303
|
+
return escapeAttr(value);
|
|
1304
|
+
}
|
|
1297
1305
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
1298
1306
|
function parseHTML(html, parent) {
|
|
1299
1307
|
const tpl = document.createElement("template");
|
|
@@ -2118,7 +2126,10 @@ function applyRestAttrs(el, source, excludeKeys) {
|
|
|
2118
2126
|
createEffect(() => {
|
|
2119
2127
|
for (const { key, c } of attrEntries) {
|
|
2120
2128
|
const value = source[key];
|
|
2121
|
-
if (
|
|
2129
|
+
if (c.kind === "innerHTML") {
|
|
2130
|
+
const html = value;
|
|
2131
|
+
el.innerHTML = html != null && html.__html != null ? String(html.__html) : "";
|
|
2132
|
+
} else if (value != null && value !== false) {
|
|
2122
2133
|
if (c.kind === "property" && c.attrName === "value" && "value" in el) {
|
|
2123
2134
|
const strVal = String(value);
|
|
2124
2135
|
if (el.value !== strVal)
|
|
@@ -2161,6 +2172,8 @@ function spreadAttrs(obj) {
|
|
|
2161
2172
|
const c = classifyDOMProp(key);
|
|
2162
2173
|
if (c.kind === "event" || c.kind === "skip" || c.kind === "ref")
|
|
2163
2174
|
continue;
|
|
2175
|
+
if (c.kind === "innerHTML")
|
|
2176
|
+
continue;
|
|
2164
2177
|
if (c.kind === "style") {
|
|
2165
2178
|
const css = styleToCss(value);
|
|
2166
2179
|
if (css != null)
|
|
@@ -2436,7 +2449,7 @@ function __bfSlot(value, slots) {
|
|
|
2436
2449
|
if (Array.isArray(value)) {
|
|
2437
2450
|
return value.map((v) => __bfSlot(v, slots)).join("");
|
|
2438
2451
|
}
|
|
2439
|
-
return
|
|
2452
|
+
return escapeText(value);
|
|
2440
2453
|
}
|
|
2441
2454
|
// src/runtime/dynamic-text.ts
|
|
2442
2455
|
var END_MARKER = "/";
|
|
@@ -2630,6 +2643,8 @@ export {
|
|
|
2630
2643
|
findSiblingSlot,
|
|
2631
2644
|
findScope,
|
|
2632
2645
|
find,
|
|
2646
|
+
escapeText,
|
|
2647
|
+
escapeAttr,
|
|
2633
2648
|
cssEscape,
|
|
2634
2649
|
createSignal,
|
|
2635
2650
|
createRoot,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barefootjs/client",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
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.5.
|
|
58
|
+
"@barefootjs/shared": "0.5.3"
|
|
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
|
@@ -400,6 +400,39 @@ export function escapeAttrGt(html: string): string {
|
|
|
400
400
|
return html.replace(/"[^"]*"/g, match => match.replace(/>/g, '>'))
|
|
401
401
|
}
|
|
402
402
|
|
|
403
|
+
/**
|
|
404
|
+
* HTML-escape a single attribute *value* before it is concatenated into a
|
|
405
|
+
* client-rendered template string. Matches the SSR adapters' attribute
|
|
406
|
+
* escaping (Hono's `escapeToBuffer`: `& " ' < >`) so client-rendered DOM
|
|
407
|
+
* is byte-identical to the server-rendered form and metacharacter-bearing
|
|
408
|
+
* values (UnoCSS `[class*="size-"]`, `has-[>svg]`, …) don't corrupt
|
|
409
|
+
* attribute parsing when the template is inserted via `innerHTML`. `&` is
|
|
410
|
+
* replaced first so the emitted entities aren't themselves re-escaped.
|
|
411
|
+
*/
|
|
412
|
+
export function escapeAttr(value: unknown): string {
|
|
413
|
+
return String(value)
|
|
414
|
+
.replace(/&/g, '&')
|
|
415
|
+
.replace(/"/g, '"')
|
|
416
|
+
.replace(/'/g, ''')
|
|
417
|
+
.replace(/</g, '<')
|
|
418
|
+
.replace(/>/g, '>')
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* HTML-escape interpolated **text content** before it is concatenated into
|
|
423
|
+
* a client-rendered template string (the `<!--bf:sN-->…<!--/-->` text
|
|
424
|
+
* slots). The HTML spec only requires `& < >` in text, but the SSR
|
|
425
|
+
* adapters (Hono) escape text with the same set as attribute values
|
|
426
|
+
* (`& " ' < >`), and the fixture-hydrate / CSR-conformance layer requires
|
|
427
|
+
* byte-parity with the server-rendered output — so this delegates to
|
|
428
|
+
* `escapeAttr`. Kept as a distinct export so generated code reads
|
|
429
|
+
* `escapeText(...)` at text sites (self-documenting) and so the two
|
|
430
|
+
* contexts can diverge later without touching call sites.
|
|
431
|
+
*/
|
|
432
|
+
export function escapeText(value: unknown): string {
|
|
433
|
+
return escapeAttr(value)
|
|
434
|
+
}
|
|
435
|
+
|
|
403
436
|
const SVG_NS = 'http://www.w3.org/2000/svg'
|
|
404
437
|
|
|
405
438
|
/**
|
package/src/runtime/index.ts
CHANGED
|
@@ -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}"`)
|