diff --git a/.changeset/fix-svg-classname.md b/.changeset/fix-svg-classname.md new file mode 100644 index 0000000000..59e792df11 --- /dev/null +++ b/.changeset/fix-svg-classname.md @@ -0,0 +1,6 @@ +--- +"@marko/runtime-tags": patch +"marko": patch +--- + +Fix setting `class` on SVG elements throwing `TypeError: setting getter-only property "className"` diff --git a/.sizes.json b/.sizes.json index 2e0e4b44d5..1afe36f060 100644 --- a/.sizes.json +++ b/.sizes.json @@ -7,8 +7,8 @@ { "name": "*", "total": { - "min": 21166, - "brotli": 7935 + "min": 21155, + "brotli": 7926 } }, { diff --git a/.sizes/dom.js b/.sizes/dom.js index 6080a66618..2b2087039f 100644 --- a/.sizes/dom.js +++ b/.sizes/dom.js @@ -1,4 +1,4 @@ -// size: 21166 (min) 7935 (brotli) +// size: 21155 (min) 7926 (brotli) //#region packages/runtime-tags/dist/dom.mjs let empty = [], rest = Symbol(), @@ -1270,11 +1270,13 @@ function setAttribute(element, name, value) { : element.setAttribute(name, value)); } function _attr_class(element, value) { - ((value = - typeof value == "string" + setAttribute( + element, + "class", + (typeof value == "string" ? value - : toDelimitedString(value, " ", stringifyClassObject)), - value !== element.className && (element.className = value)); + : toDelimitedString(value, " ", stringifyClassObject)) || void 0, + ); } function _attr_class_items(element, items) { for (let key in items) _attr_class_item(element, key, items[key]); diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/html.bundle.debug.js b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/html.bundle.debug.js new file mode 100644 index 0000000000..67030923c2 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/html.bundle.debug.js @@ -0,0 +1,8 @@ +// template.marko +var template_default = _template("__tests__/template.marko", (input) => { + const $scope0_reason = _scope_reason(), $sg__input_active = _serialize_guard($scope0_reason, 0); + const $scope0_id = _scope_id(); + const { active } = input; + _html(`${_el_resume($scope0_id, "#circle/1", $sg__input_active)}${_el_resume($scope0_id, "#svg/0", $sg__input_active)}`); + _serialize_if($scope0_reason, 0) && writeScope($scope0_id, {}, "__tests__/template.marko", 0); +}, 1); diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/html.bundle.js b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/html.bundle.js new file mode 100644 index 0000000000..9324473fa1 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/html.bundle.js @@ -0,0 +1,8 @@ +// template.marko +var template_default = _template("a", (input) => { + const $scope0_reason = _scope_reason(), $sg__input_active = _serialize_guard($scope0_reason, 0); + const $scope0_id = _scope_id(); + const { active } = input; + _html(`${_el_resume($scope0_id, "b", $sg__input_active)}${_el_resume($scope0_id, "a", $sg__input_active)}`); + _serialize_if($scope0_reason, 0) && writeScope($scope0_id, {}); +}, 1); diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-csr.debug.md b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-csr.debug.md new file mode 100644 index 0000000000..239a6a8460 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-csr.debug.md @@ -0,0 +1,51 @@ +# Render `{"active":false}` +```html + + + +``` + +# Update `{"active":true}` +```html + + + +``` +## Change +``` +UPDATE: .icon.active[class] "icon" => "icon active" +UPDATE: .on[class] "off" => "on" +``` + +# Update `{"active":false}` +```html + + + +``` +## Change +``` +UPDATE: .icon[class] "icon active" => "icon" +UPDATE: .off[class] "on" => "off" +``` diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-csr.md b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-csr.md new file mode 100644 index 0000000000..239a6a8460 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-csr.md @@ -0,0 +1,51 @@ +# Render `{"active":false}` +```html + + + +``` + +# Update `{"active":true}` +```html + + + +``` +## Change +``` +UPDATE: .icon.active[class] "icon" => "icon active" +UPDATE: .on[class] "off" => "on" +``` + +# Update `{"active":false}` +```html + + + +``` +## Change +``` +UPDATE: .icon[class] "icon active" => "icon" +UPDATE: .off[class] "on" => "off" +``` diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-ssr.debug.md b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-ssr.debug.md new file mode 100644 index 0000000000..285b99ced8 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-ssr.debug.md @@ -0,0 +1,13 @@ +# Render `{"active":false}` +```html + + + +``` diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-ssr.md b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-ssr.md new file mode 100644 index 0000000000..285b99ced8 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/render-ssr.md @@ -0,0 +1,13 @@ +# Render `{"active":false}` +```html + + + +``` diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/writes.debug.html b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/writes.debug.html new file mode 100644 index 0000000000..ba9a15b3bb --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/writes.debug.html @@ -0,0 +1,3 @@ + + + diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/writes.html b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/writes.html new file mode 100644 index 0000000000..48cfd66efb --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/__snapshots__/writes.html @@ -0,0 +1,4 @@ + + + + diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/template.marko b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/template.marko new file mode 100644 index 0000000000..1028b4db06 --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/template.marko @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/test.ts b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/test.ts new file mode 100644 index 0000000000..22aa504cfa --- /dev/null +++ b/packages/runtime-tags/src/__tests__/fixtures/attr-class-svg/test.ts @@ -0,0 +1,6 @@ +import type { TestConfig } from "../../main.test"; + +export const config: TestConfig = { + equivalent: false, + steps: [{ active: false }, { active: true }, { active: false }], +}; diff --git a/packages/runtime-tags/src/__tests__/fixtures/multi-class-toggle/__snapshots__/dom.bundle.js b/packages/runtime-tags/src/__tests__/fixtures/multi-class-toggle/__snapshots__/dom.bundle.js index d609276b6d..2609b95c61 100644 --- a/packages/runtime-tags/src/__tests__/fixtures/multi-class-toggle/__snapshots__/dom.bundle.js +++ b/packages/runtime-tags/src/__tests__/fixtures/multi-class-toggle/__snapshots__/dom.bundle.js @@ -1,4 +1,4 @@ -// total: 2834 (min) 1454 (brotli) +// total: 2916 (min) 1480 (brotli) // template.marko: 144 (min) 130 (brotli) const $count__script = _script("a0", ($scope) => _on($scope.a, "click", function() { $count($scope, $scope.c + 1); diff --git a/packages/runtime-tags/src/dom/dom.ts b/packages/runtime-tags/src/dom/dom.ts index 8958dad7ab..3ab9b02f2c 100644 --- a/packages/runtime-tags/src/dom/dom.ts +++ b/packages/runtime-tags/src/dom/dom.ts @@ -59,13 +59,11 @@ function setAttribute( } export function _attr_class(element: Element, value: unknown) { - value = - typeof value === "string" - ? value - : toDelimitedString(value, " ", stringifyClassObject); - if (value !== element.className) { - element.className = value as string; - } + setAttribute( + element, + "class", + toDelimitedString(value, " ", stringifyClassObject) || undefined, + ); } export function _attr_class_items(