DEV: Introduce dynamic wrapper attributes in RenderGlimmer (#22991)

This commit is contained in:
David Taylor 2023-08-07 13:27:26 +01:00 committed by GitHub
parent 3e44f04ff5
commit 7f2e42c826
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 2 deletions

View File

@ -1,5 +1,8 @@
{{#each this._childComponents as |info|}}
{{#in-element info.element insertBefore=null}}
<info.component @data={{info.data}} />
<info.component
@data={{info.data}}
@setWrapperElementAttrs={{info.setWrapperElementAttrs}}
/>
{{/in-element}}
{{/each}}

View File

@ -4,6 +4,8 @@ import { tracked } from "@glimmer/tracking";
import { assert } from "@ember/debug";
import { createWidgetFrom } from "discourse/widgets/widget";
const INITIAL_CLASSES = Symbol("RENDER_GLIMMER_INITIAL_CLASSES");
/*
This class allows you to render arbitrary Glimmer templates inside widgets.
@ -71,8 +73,14 @@ createWidget("my-widget", {
this.scheduleRerender();
},
});
```
To dynamically control the attributes of the wrapper element, a helper function is provided as an argument to your hbs template.
To use this via a template, you can do something like this:
```
hbs`{{@setWrapperElementAttrs class="some class value" title="title value"}}`
```
If you prefer, you can pass this function down into your own components, and call it from there. Invoked as a helper, this can
be passed (auto-)tracked values, and will update the wrapper element attributes whenever the inputs.
*/
export default class RenderGlimmer {
@ -104,6 +112,7 @@ export default class RenderGlimmer {
const [type, ...classNames] = this.renderInto.split(".");
this.element = document.createElement(type);
this.element.classList.add(...classNames);
this.element[INITIAL_CLASSES] = classNames;
}
this.connectComponent();
return this.element;
@ -147,11 +156,27 @@ export default class RenderGlimmer {
element,
component,
@tracked data: this.data,
setWrapperElementAttrs: (attrs) =>
this.updateElementAttrs(element, attrs),
};
this.parentMountWidgetComponent.mountChildComponent(this._componentInfo);
}
updateElementAttrs(element, attrs) {
for (let [key, value] of Object.entries(attrs)) {
if (key === "class") {
value = [element[INITIAL_CLASSES], value].filter(Boolean).join(" ");
}
if ([null, undefined].includes(value)) {
element.removeAttribute(key);
} else {
element.setAttribute(key, value);
}
}
}
get parentMountWidgetComponent() {
return this.widget?._findView() || this._emberView;
}

View File

@ -133,6 +133,11 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
"div.my-wrapper",
hbs`<span class='shim-content'>{{@data.attr1}}</span>`
);
registerWidgetShim(
"render-glimmer-test-wrapper-attrs",
"div.initial-wrapper-class",
hbs`{{@setWrapperElementAttrs class=(concat-class "static-extra-class" @data.extraClass) data-some-attr=@data.dataAttrValue}}`
);
});
hooks.afterEach(function () {
@ -140,6 +145,7 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
this.registry.unregister("widget:toggle-demo-widget");
this.registry.unregister("component:demo-component");
deleteFromRegistry("render-glimmer-test-shim");
deleteFromRegistry("render-glimmer-test-wrapper-attrs");
});
test("argument handling", async function (assert) {
@ -315,4 +321,31 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
assert.dom("div.my-wrapper span.shim-content").exists();
assert.dom("div.my-wrapper span.shim-content").hasText("val1");
});
test("setWrapperElementAttrs API", async function (assert) {
await render(
hbs`<MountWidget @widget="render-glimmer-test-wrapper-attrs" @args={{hash extraClass=this.extraClass dataAttrValue=this.dataAttrValue}} />`
);
assert.dom("div.initial-wrapper-class").exists();
assert
.dom("div.initial-wrapper-class")
.hasAttribute("class", "initial-wrapper-class static-extra-class");
assert
.dom("div.initial-wrapper-class")
.doesNotHaveAttribute("data-some-attr");
this.set("extraClass", "dynamic-extra-class");
this.set("dataAttrValue", "hello world");
assert
.dom("div.initial-wrapper-class")
.hasAttribute(
"class",
"initial-wrapper-class static-extra-class dynamic-extra-class"
);
assert
.dom("div.initial-wrapper-class")
.hasAttribute("data-some-attr", "hello world");
});
});