DEV: Support appending glimmer into existing post elements (#20164)

Previously `helper.renderGlimmer()` would always create a new wrapper element. This is required when using `RenderGlimmer` within widgets, where there is no direct access to DOM elements. However, when using within `decorateCooked`, we have the ability to pass an existing element to `{{#in-element}}` and have the glimmer content appended with no additional wrappers.

This commit makes the `renderInto` accept an existing DOM node for this 'append' behavior. The previous 'new wrapper element' behaviour is still used when a string is passed.
This commit is contained in:
David Taylor 2023-02-03 16:07:11 +00:00 committed by GitHub
parent 082cd13909
commit d90a31d5b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 10 deletions

View File

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

View File

@ -118,24 +118,31 @@ class DecoratorHelper {
* import { hbs } from "ember-cli-htmlbars";
*
* api.decorateCookedElement((cooked, helper) => {
* // Generate a new element with glimmer rendered inside
* const glimmerElement = helper.renderGlimmer(
* "div.my-wrapper-class",
* hbs`<DButton @icon={{@data.param}} @translatedLabel="Hello world from Glimmer Component"/>`,
* { param: "user-plus" }
* );
* cooked.appendChild(glimmerElement);
*
* // Or append to an existing element
* helper.renderGlimmer(
* cooked.querySelector(".some-container"),
* hbs`I will be appended to some-container`
* );
* }, { onlyStream: true, id: "my-id" });
* ```
*
*/
renderGlimmer(tagName, template, data) {
renderGlimmer(renderInto, template, data) {
if (!this.widget.postContentsDestroyCallbacks) {
throw "renderGlimmer can only be used in the context of a post";
}
const renderGlimmer = new RenderGlimmer(
this.widget,
tagName,
renderInto,
template,
data
);

View File

@ -78,25 +78,30 @@ export default class RenderGlimmer {
/**
* Create a RenderGlimmer instance
* @param widget - the widget instance which is rendering this content
* @param tagName - tagName for the wrapper element (e.g. `div.my-class`)
* @param renderInto - a string describing a new wrapper element (e.g. `div.my-class`),
* or an existing HTML element to append content into.
* @param template - a glimmer template compiled via ember-cli-htmlbars
* @param data - will be made available at `@data` in your template
*/
constructor(widget, tagName, template, data) {
constructor(widget, renderInto, template, data) {
assert(
"`template` should be a template compiled via `ember-cli-htmlbars`",
template.name === "factory"
);
this.tagName = tagName;
this.renderInto = renderInto;
this.widget = widget;
this.template = template;
this.data = data;
}
init() {
const [type, ...classNames] = this.tagName.split(".");
this.element = document.createElement(type);
this.element.classList.add(...classNames);
if (this.renderInto instanceof Element) {
this.element = this.renderInto;
} else {
const [type, ...classNames] = this.renderInto.split(".");
this.element = document.createElement(type);
this.element.classList.add(...classNames);
}
this.connectComponent();
return this.element;
}
@ -110,7 +115,7 @@ export default class RenderGlimmer {
update(prev) {
if (
prev.template.__id !== this.template.__id ||
prev.tagName !== this.tagName
prev.renderInto !== this.renderInto
) {
// Totally different component, but the widget framework guessed it was the
// same widget. Destroy old component and re-init the new one.

View File

@ -28,6 +28,10 @@ acceptance("Acceptance | decorateCookedElement", function () {
if (helper.getModel().post_number !== 1) {
return;
}
cooked.innerHTML =
"<div class='existing-wrapper'>Some existing content</div>";
// Create new wrapper element and append
cooked.appendChild(
helper.renderGlimmer(
"div.glimmer-wrapper",
@ -35,6 +39,12 @@ acceptance("Acceptance | decorateCookedElement", function () {
{ component: DemoComponent }
)
);
// Append to existing element
helper.renderGlimmer(
cooked.querySelector(".existing-wrapper"),
hbs` with more content from glimmer`
);
});
});
@ -42,6 +52,12 @@ acceptance("Acceptance | decorateCookedElement", function () {
assert.dom("div.glimmer-wrapper").exists();
assert.dom("span.glimmer-component-content").exists();
assert.dom("div.existing-wrapper").exists();
assert
.dom("div.existing-wrapper")
.hasText("Some existing content with more content from glimmer");
assert.deepEqual(DemoComponent.eventLog, ["created"]);
await visit("/");