Skip to content

Commit eb481ec

Browse files
author
Steve Orvell
authored
Merge pull request #184 from Polymer/export-decorators
Export decorators
2 parents 021cf8a + aadd0a8 commit eb481ec

File tree

8 files changed

+694
-753
lines changed

8 files changed

+694
-753
lines changed

src/demo/ts-element.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import { LitElement, html, property } from '../lit-element.js';
1+
import {html, LitElement, property} from '../lit-element.js';
22

33
class TSElement extends LitElement {
44

5-
@property()
6-
message = 'Hi';
5+
@property() message = 'Hi';
76

8-
@property({attribute: 'more-info', type: (value: string) => `[${value}]`})
7+
@property({attribute : 'more-info', type: (value: string) => `[${value}]`})
98
extra = '';
109

1110
render() {
@@ -18,6 +17,5 @@ class TSElement extends LitElement {
1817
</style>TSElement says: ${message} ${extra}
1918
`;
2019
}
21-
2220
}
2321
customElements.define('ts-element', TSElement);

src/lib/decorators.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
import {LitElement} from '../lit-element.js';
1717

18+
import {PropertyDeclaration, UpdatingElement} from './updating-element.js';
19+
1820
export type Constructor<T> = {
1921
new (...args: unknown[]): T
2022
};
@@ -48,6 +50,16 @@ export const customElement = (tagName: keyof HTMLElementTagNameMap) =>
4850
return clazz as any;
4951
};
5052

53+
/**
54+
* A property decorator which creates a LitElement property which reflects a
55+
* corresponding attribute value. A `PropertyDeclaration` may optionally be
56+
* supplied to configure property features.
57+
*/
58+
export const property = (options?: PropertyDeclaration) => (proto: Object,
59+
name: string) => {
60+
(proto.constructor as typeof UpdatingElement).createProperty(name, options);
61+
};
62+
5163
/**
5264
* A property decorator that converts a class property into a getter that
5365
* executes a querySelector on the element's renderRoot.

src/lib/updating-element.ts

Lines changed: 108 additions & 87 deletions
Large diffs are not rendered by default.

src/lit-element.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,20 @@
1111
* subject to an additional IP rights grant found at
1212
* http://polymer.github.io/PATENTS.txt
1313
*/
14-
import {render} from 'lit-html/lib/shady-render';
1514
import {TemplateResult} from 'lit-html';
16-
import {UpdatingElement, PropertyValues} from './lib/updating-element.js';
15+
import {render} from 'lit-html/lib/shady-render';
16+
17+
import {PropertyValues, UpdatingElement} from './lib/updating-element.js';
1718

1819
export * from './lib/updating-element.js';
20+
export * from './lib/decorators.js';
1921
export {html, svg} from 'lit-html/lit-html';
2022

21-
2223
export abstract class LitElement extends UpdatingElement {
2324

2425
/**
25-
* Render method used to render the lit-html TemplateResult to the element's DOM.
26+
* Render method used to render the lit-html TemplateResult to the element's
27+
* DOM.
2628
* @param {TemplateResult} Template to render.
2729
* @param {Element|DocumentFragment} Node into which to render.
2830
* @param {String} Element name.
@@ -38,7 +40,8 @@ export abstract class LitElement extends UpdatingElement {
3840
protected update(changedProperties: PropertyValues) {
3941
super.update(changedProperties);
4042
if (typeof this.render === 'function') {
41-
(this.constructor as typeof LitElement).render(this.render(), this.renderRoot!, this.localName!);
43+
(this.constructor as typeof LitElement)
44+
.render(this.render(), this.renderRoot!, this.localName!);
4245
} else {
4346
throw new Error('render() not implemented');
4447
}

src/test/lib/decorators_test.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@
1212
* http://polymer.github.io/PATENTS.txt
1313
*/
1414

15-
import {customElement, query, queryAll} from '../../lib/decorators.js';
16-
import {html, LitElement} from '../../lit-element.js';
17-
import { generateElementName } from '../test-helpers.js';
15+
import {
16+
customElement,
17+
html,
18+
LitElement,
19+
query,
20+
queryAll
21+
} from '../../lit-element.js';
22+
import {generateElementName} from '../test-helpers.js';
1823

1924
const assert = chai.assert;
2025

@@ -73,7 +78,7 @@ suite('decorators', () => {
7378
test('returns null when no match', async () => {
7479
const c = new C();
7580
container.appendChild(c);
76-
await Promise.resolve();
81+
await c.updateComplete;
7782
const span = c.nope;
7883
assert.isNull(span);
7984
});

src/test/lit-element_styling_test.ts

Lines changed: 93 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@
1313
*/
1414

1515
import '@webcomponents/shadycss/apply-shim.min.js';
16+
1617
import {
1718
html,
1819
LitElement,
1920
} from '../lit-element.js';
2021

21-
import {generateElementName, nextFrame, getComputedStyleValue} from './test-helpers.js';
22+
import {
23+
generateElementName,
24+
getComputedStyleValue,
25+
nextFrame
26+
} from './test-helpers.js';
2227

2328
declare global {
2429
interface Window {
@@ -45,7 +50,8 @@ suite('Styling', () => {
4550
test('content shadowRoot is styled', async () => {
4651
const name = generateElementName();
4752
customElements.define(name, class extends LitElement {
48-
render() { return html`
53+
render() {
54+
return html`
4955
<style>
5056
div {
5157
border: 2px solid blue;
@@ -69,7 +75,8 @@ suite('Styling', () => {
6975
</style>`;
7076
const name = generateElementName();
7177
customElements.define(name, class extends LitElement {
72-
render() { return html`
78+
render() {
79+
return html`
7380
<style>
7481
div {
7582
border: 2px solid blue;
@@ -89,7 +96,8 @@ suite('Styling', () => {
8996
test('custom properties render', async () => {
9097
const name = generateElementName();
9198
customElements.define(name, class extends LitElement {
92-
render() { return html`
99+
render() {
100+
return html`
93101
<style>
94102
:host {
95103
--border: 8px solid red;
@@ -110,7 +118,8 @@ suite('Styling', () => {
110118

111119
test('custom properties flow to nested elements', async () => {
112120
customElements.define('x-inner', class extends LitElement {
113-
render() { return html`
121+
render() {
122+
return html`
114123
<style>
115124
div {
116125
border: var(--border);
@@ -123,7 +132,8 @@ suite('Styling', () => {
123132
class E extends LitElement {
124133
inner: LitElement|null = null;
125134

126-
render() { return html`
135+
render() {
136+
return html`
127137
<style>
128138
x-inner {
129139
--border: 8px solid red;
@@ -148,72 +158,76 @@ suite('Styling', () => {
148158
assert.equal(getComputedStyleValue(div!, 'border-top-width').trim(), '8px');
149159
});
150160

151-
test('elements with custom properties can move between elements', async () => {
152-
customElements.define('x-inner1', class extends LitElement {
153-
render() { return html`
161+
test('elements with custom properties can move between elements',
162+
async () => {
163+
customElements.define('x-inner1', class extends LitElement {
164+
render() {
165+
return html`
154166
<style>
155167
div {
156168
border: var(--border);
157169
}
158170
</style>
159171
<div>Testing...</div>`;
160-
}
161-
});
162-
const name1 = generateElementName();
163-
customElements.define(name1, class extends LitElement {
164-
165-
inner: Element|null = null;
166-
167-
render() { return html`
172+
}
173+
});
174+
const name1 = generateElementName();
175+
customElements.define(name1, class extends LitElement {
176+
inner: Element|null = null;
177+
178+
render() {
179+
return html`
168180
<style>
169181
x-inner1 {
170182
--border: 2px solid red;
171183
}
172184
</style>
173185
<x-inner1></x-inner1>`;
174-
}
175-
176-
firstUpdated() {
177-
this.inner = this.shadowRoot!.querySelector('x-inner1');
178-
}
179-
});
180-
const name2 = generateElementName();
181-
customElements.define(name2, class extends LitElement {
182-
183-
render() { return html`
186+
}
187+
188+
firstUpdated() {
189+
this.inner = this.shadowRoot!.querySelector('x-inner1');
190+
}
191+
});
192+
const name2 = generateElementName();
193+
customElements.define(name2, class extends LitElement {
194+
render() {
195+
return html`
184196
<style>
185197
x-inner1 {
186198
--border: 8px solid red;
187199
}
188200
</style>`;
189-
}
190-
191-
});
192-
const el = document.createElement(name1) as LitElement;
193-
const el2 = document.createElement(name2);
194-
container.appendChild(el);
195-
container.appendChild(el2);
196-
let div: Element|null;
197-
198-
// Workaround for Safari 9 Promise timing bugs.
199-
await el.updateComplete;
200-
201-
await nextFrame();
202-
const inner = el.shadowRoot!.querySelector('x-inner1');
203-
div = inner!.shadowRoot!.querySelector('div');
204-
assert.equal(getComputedStyleValue(div!, 'border-top-width').trim(), '2px');
205-
el2!.shadowRoot!.appendChild(inner!);
206-
207-
// Workaround for Safari 9 Promise timing bugs.
208-
await el.updateComplete;
209-
210-
await nextFrame();
211-
assert.equal(getComputedStyleValue(div!, 'border-top-width').trim(), '8px');
212-
});
201+
}
202+
});
203+
const el = document.createElement(name1) as LitElement;
204+
const el2 = document.createElement(name2);
205+
container.appendChild(el);
206+
container.appendChild(el2);
207+
let div: Element|null;
208+
209+
// Workaround for Safari 9 Promise timing bugs.
210+
await el.updateComplete;
211+
212+
await nextFrame();
213+
const inner = el.shadowRoot!.querySelector('x-inner1');
214+
div = inner!.shadowRoot!.querySelector('div');
215+
assert.equal(getComputedStyleValue(div!, 'border-top-width').trim(),
216+
'2px');
217+
el2!.shadowRoot!.appendChild(inner!);
218+
219+
// Workaround for Safari 9 Promise timing bugs.
220+
await el.updateComplete;
221+
222+
await nextFrame();
223+
assert.equal(getComputedStyleValue(div!, 'border-top-width').trim(),
224+
'8px');
225+
});
213226

214227
test('@apply renders in nested elements', async () => {
215228
customElements.define('x-inner2', class extends LitElement {
216-
render() { return html`
229+
render() {
230+
return html`
217231
<style>
218232
div {
219233
@apply --bag;
@@ -225,7 +239,8 @@ suite('Styling', () => {
225239
const name = generateElementName();
226240
class E extends LitElement {
227241
inner: LitElement|null = null;
228-
render() { return html`
242+
render() {
243+
return html`
229244
<style>
230245
x-inner2 {
231246
--bag: {
@@ -248,14 +263,14 @@ suite('Styling', () => {
248263
await el.updateComplete && await el.inner!.updateComplete;
249264

250265
await nextFrame();
251-
const div = el.shadowRoot!.querySelector('x-inner2')!.shadowRoot!.querySelector('div');
252-
assert.equal(getComputedStyleValue(div!, 'border-top-width').trim(), '10px');
266+
const div = el.shadowRoot!.querySelector(
267+
'x-inner2')!.shadowRoot!.querySelector('div');
268+
assert.equal(getComputedStyleValue(div!, 'border-top-width').trim(),
269+
'10px');
253270
});
254-
255271
});
256272

257273
suite('ShadyDOM', () => {
258-
259274
let container: HTMLElement;
260275

261276
setup(function() {
@@ -273,28 +288,31 @@ suite('ShadyDOM', () => {
273288
}
274289
});
275290

276-
test('properties in styles render with initial value and cannot be changed', async () => {
277-
let border = `6px solid blue`;
278-
const name = generateElementName();
279-
customElements.define(name, class extends LitElement {
280-
render() { return html`
291+
test('properties in styles render with initial value and cannot be changed',
292+
async () => {
293+
let border = `6px solid blue`;
294+
const name = generateElementName();
295+
customElements.define(name, class extends LitElement {
296+
render() {
297+
return html`
281298
<style>
282299
div {
283300
border: ${border};
284301
}
285302
</style>
286303
<div>Testing...</div>`;
287-
}
288-
});
289-
const el = document.createElement(name) as LitElement;
290-
container.appendChild(el);
291-
await el.updateComplete;
292-
const div = el.shadowRoot!.querySelector('div');
293-
assert.equal(getComputedStyleValue(div!, 'border-top-width').trim(), '6px');
294-
border = `4px solid orange`;
295-
el.requestUpdate();
296-
await el.updateComplete;
297-
assert.equal(getComputedStyleValue(div!, 'border-top-width').trim(), '6px');
298-
});
299-
304+
}
305+
});
306+
const el = document.createElement(name) as LitElement;
307+
container.appendChild(el);
308+
await el.updateComplete;
309+
const div = el.shadowRoot!.querySelector('div');
310+
assert.equal(getComputedStyleValue(div!, 'border-top-width').trim(),
311+
'6px');
312+
border = `4px solid orange`;
313+
el.requestUpdate();
314+
await el.updateComplete;
315+
assert.equal(getComputedStyleValue(div!, 'border-top-width').trim(),
316+
'6px');
317+
});
300318
});

0 commit comments

Comments
 (0)