DEV: Allow registering a widget shim which renders using hbs (#20177)

This is an alternative way to use `RenderGlimmer` which can be more ergonomic for iterative updates of a codebase. For documentation, see `widgets/render-glimmer.js`
This commit is contained in:
David Taylor 2023-02-06 14:10:44 +00:00 committed by GitHub
parent 2f8ad17aed
commit 95999c80ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 7 deletions

View File

@ -2,6 +2,7 @@ import templateOnly from "@ember/component/template-only";
import { setComponentTemplate } from "@ember/component";
import { tracked } from "@glimmer/tracking";
import { assert } from "@ember/debug";
import { createWidgetFrom } from "discourse/widgets/widget";
/*
@ -89,7 +90,9 @@ export default class RenderGlimmer {
template.name === "factory"
);
this.renderInto = renderInto;
this.widget = widget;
if (widget) {
this.widget = widget;
}
this.template = template;
this.data = data;
}
@ -108,7 +111,9 @@ export default class RenderGlimmer {
destroy() {
if (this._componentInfo) {
this.widget._findView().unmountChildComponent(this._componentInfo);
this.parentMountWidgetComponent.unmountChildComponent(
this._componentInfo
);
}
}
@ -132,7 +137,7 @@ export default class RenderGlimmer {
}
connectComponent() {
const { element, template, widget } = this;
const { element, template } = this;
const component = templateOnly();
component.name = "Widgets/RenderGlimmer";
@ -143,9 +148,39 @@ export default class RenderGlimmer {
component,
@tracked data: this.data,
};
const parentMountWidgetComponent = widget._findView();
parentMountWidgetComponent.mountChildComponent(this._componentInfo);
this.parentMountWidgetComponent.mountChildComponent(this._componentInfo);
}
get parentMountWidgetComponent() {
return this.widget?._findView() || this._emberView;
}
}
RenderGlimmer.prototype.type = "Widget";
/**
* Define a widget shim which renders a Glimmer template. Designed for incrementally migrating
* a widget-based UI to Glimmer. Widget attrs will be made available to your template at `@data`.
* For more details, see documentation for the RenderGlimmer class.
* @param name - the widget's name (which can then be used in `.attach` elsewhere)
* @param tagName - a string describing a new wrapper element (e.g. `div.my-class`)
* @param template - a glimmer template compiled via ember-cli-htmlbars
*/
export function registerWidgetShim(name, tagName, template) {
const RenderGlimmerShim = class MyClass extends RenderGlimmer {
constructor(attrs) {
super(null, tagName, template, attrs);
return this;
}
get widget() {
return this.parentWidget;
}
didRenderWidget() {}
willRerenderWidget() {}
};
createWidgetFrom(RenderGlimmerShim, name, {});
}

View File

@ -30,6 +30,10 @@ export function queryRegistry(name) {
return _registry[name];
}
export function deleteFromRegistry(name) {
return delete _registry[name];
}
const _decorators = {};
export function decorateWidget(widgetName, cb) {

View File

@ -4,9 +4,11 @@ import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, fillIn, render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import widgetHbs from "discourse/widgets/hbs-compiler";
import Widget from "discourse/widgets/widget";
import Widget, { deleteFromRegistry } from "discourse/widgets/widget";
import ClassicComponent from "@ember/component";
import RenderGlimmer from "discourse/widgets/render-glimmer";
import RenderGlimmer, {
registerWidgetShim,
} from "discourse/widgets/render-glimmer";
import { bind } from "discourse-common/utils/decorators";
class DemoWidget extends Widget {
@ -126,12 +128,18 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
this.registry.register("widget:demo-widget", DemoWidget);
this.registry.register("widget:toggle-demo-widget", ToggleDemoWidget);
this.registry.register("component:demo-component", DemoComponent);
registerWidgetShim(
"render-glimmer-test-shim",
"div.my-wrapper",
hbs`<span class='shim-content'>{{@data.attr1}}</span>`
);
});
hooks.afterEach(function () {
this.registry.unregister("widget:demo-widget");
this.registry.unregister("widget:toggle-demo-widget");
this.registry.unregister("component:demo-component");
deleteFromRegistry("render-glimmer-test-shim");
});
test("argument handling", async function (assert) {
@ -310,4 +318,13 @@ module("Integration | Component | Widget | render-glimmer", function (hooks) {
await click(".toggleButton");
assert.strictEqual(query("div.glimmer-wrapper").innerText, "One");
});
test("registerWidgetShim can register a fake widget", async function (assert) {
await render(
hbs`<MountWidget @widget="render-glimmer-test-shim" @args={{hash attr1="val1"}} />`
);
assert.dom("div.my-wrapper span.shim-content").exists();
assert.dom("div.my-wrapper span.shim-content").hasText("val1");
});
});