From ec01d1b43f069d909a18bfb73ee414f954d25c9a Mon Sep 17 00:00:00 2001 From: Elliott Marquez <5981958+e111077@users.noreply.github.com> Date: Mon, 22 Nov 2021 13:01:32 -0800 Subject: [PATCH] fix(lit-renderer): certain reactive props not init correctly (#1874) * fix(lit-renderer): reactive props not init correctly * test(renderer-lit): implement testing suggestiosn * chore(renderer-lit): upload changeset * fix(renderer-lit): call connCallback on server * fix(renderer-lit): do not set reserved JSX props * fix(renderer-lit): do not check for reserved attributes Co-authored-by: Nate Moore --- .changeset/gentle-donkeys-rule.md | 5 +++++ .../lit-element/src/components/my-element.js | 17 ++++++++++++++++ .../lit-element/src/pages/index.astro | 7 ++++++- packages/astro/test/lit-element.test.js | 20 ++++++++++++++++++- packages/renderers/renderer-lit/server.js | 10 +++++++++- 5 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 .changeset/gentle-donkeys-rule.md diff --git a/.changeset/gentle-donkeys-rule.md b/.changeset/gentle-donkeys-rule.md new file mode 100644 index 000000000..eb33cfce1 --- /dev/null +++ b/.changeset/gentle-donkeys-rule.md @@ -0,0 +1,5 @@ +--- +'@astrojs/renderer-lit': patch +--- + +renderer-lit will bind to properties rather than attributes fixing certain binding issues diff --git a/packages/astro/test/fixtures/lit-element/src/components/my-element.js b/packages/astro/test/fixtures/lit-element/src/components/my-element.js index 7b7eed71c..6466bca02 100644 --- a/packages/astro/test/fixtures/lit-element/src/components/my-element.js +++ b/packages/astro/test/fixtures/lit-element/src/components/my-element.js @@ -3,9 +3,26 @@ import { LitElement, html } from 'lit'; export const tagName = 'my-element'; export class MyElement extends LitElement { + static properties = { + bool: {type: Boolean}, + str: {type: String, attribute: 'str-attr'}, + obj: {type: Object}, + } + + constructor() { + super(); + this.bool = true; + this.str = 'not initialized'; + this.obj = {data: null}; + // not a reactive property + this.foo = 'not initialized'; + } render() { return html`
Testing...
+
${this.bool ? 'A' : 'B'}
+
${this.str}
+
data: ${this.obj.data}
`; } } diff --git a/packages/astro/test/fixtures/lit-element/src/pages/index.astro b/packages/astro/test/fixtures/lit-element/src/pages/index.astro index 771736294..de1140656 100644 --- a/packages/astro/test/fixtures/lit-element/src/pages/index.astro +++ b/packages/astro/test/fixtures/lit-element/src/pages/index.astro @@ -7,6 +7,11 @@ import '../components/my-element.js'; LitElements - + + \ No newline at end of file diff --git a/packages/astro/test/lit-element.test.js b/packages/astro/test/lit-element.test.js index dd44ae3da..eed211d91 100644 --- a/packages/astro/test/lit-element.test.js +++ b/packages/astro/test/lit-element.test.js @@ -5,6 +5,7 @@ import { loadFixture } from './test-utils.js'; let fixture; const NODE_VERSION = parseFloat(process.versions.node); +const stripExpressionMarkers = (html) => html.replace(//g, '') before(async () => { // @lit-labs/ssr/ requires Node 13.9 or higher @@ -27,11 +28,28 @@ describe('LitElement test', () => { const html = await fixture.readFile('/index.html'); const $ = cheerio.load(html); - // test 1: attributes rendered + // test 1: attributes rendered – non reactive properties expect($('my-element').attr('foo')).to.equal('bar'); // test 2: shadow rendered expect($('my-element').html()).to.include(`
Testing...
`); + + // test 3: string reactive property set + expect(stripExpressionMarkers($('my-element').html())).to.include(`
initialized
`); + + // test 4: boolean reactive property correctly set + // Lit will equate to true because it uses + // this.hasAttribute to determine its value + expect(stripExpressionMarkers($('my-element').html())).to.include(`
B
`); + + // test 5: object reactive property set + // by default objects will be stringifed to [object Object] + expect(stripExpressionMarkers($('my-element').html())).to.include(`
data: 1
`); + + // test 6: reactive properties are not rendered as attributes + expect($('my-element').attr('obj')).to.equal(undefined); + expect($('my-element').attr('bool')).to.equal(undefined); + expect($('my-element').attr('str')).to.equal(undefined); }); // Skipped because not supported by Lit diff --git a/packages/renderers/renderer-lit/server.js b/packages/renderers/renderer-lit/server.js index c827f1ad1..e08b2bf9a 100644 --- a/packages/renderers/renderer-lit/server.js +++ b/packages/renderers/renderer-lit/server.js @@ -28,10 +28,18 @@ function* render(tagName, attrs, children) { const instance = new LitElementRenderer(tagName); // LitElementRenderer creates a new element instance, so copy over. + const Ctr = getCustomElementConstructor(tagName); for (let [name, value] of Object.entries(attrs)) { - instance.setAttribute(name, value); + // check if this is a reactive property + if (name in Ctr.prototype) { + instance.setProperty(name, value); + } else { + instance.setAttribute(name, value); + } } + instance.connectedCallback(); + yield `<${tagName}`; yield* instance.renderAttributes(); yield `>`;