mirror of
https://github.com/withastro/astro.git
synced 2025-01-27 22:19:04 -05:00
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 <nate@skypack.dev>
This commit is contained in:
parent
c22e4c69ec
commit
ec01d1b43f
5 changed files with 56 additions and 3 deletions
5
.changeset/gentle-donkeys-rule.md
Normal file
5
.changeset/gentle-donkeys-rule.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@astrojs/renderer-lit': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
renderer-lit will bind to properties rather than attributes fixing certain binding issues
|
|
@ -3,9 +3,26 @@ import { LitElement, html } from 'lit';
|
||||||
export const tagName = 'my-element';
|
export const tagName = 'my-element';
|
||||||
|
|
||||||
export class MyElement extends LitElement {
|
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() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div>Testing...</div>
|
<div>Testing...</div>
|
||||||
|
<div id="bool">${this.bool ? 'A' : 'B'}</div>
|
||||||
|
<div id="str">${this.str}</div>
|
||||||
|
<div id="data">data: ${this.obj.data}</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,11 @@ import '../components/my-element.js';
|
||||||
<title>LitElements</title>
|
<title>LitElements</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<my-element foo="bar"></my-element>
|
<my-element
|
||||||
|
foo="bar"
|
||||||
|
str-attr={'initialized'}
|
||||||
|
bool={false}
|
||||||
|
obj={{data: 1}}>
|
||||||
|
</my-element>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -5,6 +5,7 @@ import { loadFixture } from './test-utils.js';
|
||||||
let fixture;
|
let fixture;
|
||||||
|
|
||||||
const NODE_VERSION = parseFloat(process.versions.node);
|
const NODE_VERSION = parseFloat(process.versions.node);
|
||||||
|
const stripExpressionMarkers = (html) => html.replace(/<!--\/?lit-part-->/g, '')
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
// @lit-labs/ssr/ requires Node 13.9 or higher
|
// @lit-labs/ssr/ requires Node 13.9 or higher
|
||||||
|
@ -27,11 +28,28 @@ describe('LitElement test', () => {
|
||||||
const html = await fixture.readFile('/index.html');
|
const html = await fixture.readFile('/index.html');
|
||||||
const $ = cheerio.load(html);
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
// test 1: attributes rendered
|
// test 1: attributes rendered – non reactive properties
|
||||||
expect($('my-element').attr('foo')).to.equal('bar');
|
expect($('my-element').attr('foo')).to.equal('bar');
|
||||||
|
|
||||||
// test 2: shadow rendered
|
// test 2: shadow rendered
|
||||||
expect($('my-element').html()).to.include(`<div>Testing...</div>`);
|
expect($('my-element').html()).to.include(`<div>Testing...</div>`);
|
||||||
|
|
||||||
|
// test 3: string reactive property set
|
||||||
|
expect(stripExpressionMarkers($('my-element').html())).to.include(`<div id="str">initialized</div>`);
|
||||||
|
|
||||||
|
// test 4: boolean reactive property correctly set
|
||||||
|
// <my-element bool="false"> Lit will equate to true because it uses
|
||||||
|
// this.hasAttribute to determine its value
|
||||||
|
expect(stripExpressionMarkers($('my-element').html())).to.include(`<div id="bool">B</div>`);
|
||||||
|
|
||||||
|
// test 5: object reactive property set
|
||||||
|
// by default objects will be stringifed to [object Object]
|
||||||
|
expect(stripExpressionMarkers($('my-element').html())).to.include(`<div id="data">data: 1</div>`);
|
||||||
|
|
||||||
|
// 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
|
// Skipped because not supported by Lit
|
||||||
|
|
|
@ -28,10 +28,18 @@ function* render(tagName, attrs, children) {
|
||||||
const instance = new LitElementRenderer(tagName);
|
const instance = new LitElementRenderer(tagName);
|
||||||
|
|
||||||
// LitElementRenderer creates a new element instance, so copy over.
|
// LitElementRenderer creates a new element instance, so copy over.
|
||||||
|
const Ctr = getCustomElementConstructor(tagName);
|
||||||
for (let [name, value] of Object.entries(attrs)) {
|
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 `<${tagName}`;
|
||||||
yield* instance.renderAttributes();
|
yield* instance.renderAttributes();
|
||||||
yield `>`;
|
yield `>`;
|
||||||
|
|
Loading…
Add table
Reference in a new issue