p-elements-core 1.2.32-rc7 → 1.2.32-rc9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +17 -17
- package/.gitlab-ci.yml +18 -18
- package/CHANGELOG.md +201 -201
- package/demo/sample.js +1 -1
- package/demo/screen.css +16 -16
- package/dist/p-elements-core-modern.js +1 -1
- package/dist/p-elements-core.js +1 -1
- package/docs/package-lock.json +6897 -6897
- package/docs/package.json +27 -27
- package/docs/src/404.md +8 -8
- package/docs/src/_data/demos/hello-world/hello-world.tsx +35 -35
- package/docs/src/_data/demos/hello-world/index.html +10 -10
- package/docs/src/_data/demos/hello-world/project.json +7 -7
- package/docs/src/_data/demos/timer/demo-timer.tsx +120 -120
- package/docs/src/_data/demos/timer/icons.tsx +62 -62
- package/docs/src/_data/demos/timer/index.html +12 -12
- package/docs/src/_data/demos/timer/project.json +8 -8
- package/docs/src/_data/global.js +13 -13
- package/docs/src/_data/helpers.js +19 -19
- package/docs/src/_includes/layouts/base.njk +30 -30
- package/docs/src/_includes/layouts/playground.njk +40 -40
- package/docs/src/_includes/partials/app-header.njk +8 -8
- package/docs/src/_includes/partials/head.njk +14 -14
- package/docs/src/_includes/partials/nav.njk +19 -19
- package/docs/src/_includes/partials/top-nav.njk +51 -51
- package/docs/src/documentation/custom-element.md +221 -221
- package/docs/src/documentation/decorators/bind.md +71 -71
- package/docs/src/documentation/decorators/custom-element-config.md +63 -63
- package/docs/src/documentation/decorators/property.md +83 -83
- package/docs/src/documentation/decorators/query.md +66 -66
- package/docs/src/documentation/decorators/render-property-on-set.md +60 -60
- package/docs/src/documentation/decorators.md +9 -9
- package/docs/src/documentation/reactive-properties.md +53 -53
- package/docs/src/index.d.ts +25 -25
- package/docs/src/index.md +3 -3
- package/docs/src/scripts/components/app-mode-switch/app-mode-switch.css +78 -78
- package/docs/src/scripts/components/app-mode-switch/app-mode-switch.tsx +166 -166
- package/docs/src/scripts/components/app-playground/app-playground.tsx +189 -189
- package/docs/tsconfig.json +22 -22
- package/index.html +10 -2
- package/package.json +1 -1
- package/readme.md +206 -206
- package/src/custom-element-controller.ts +31 -31
- package/src/custom-element.test.ts +906 -906
- package/src/custom-element.ts +28 -21
- package/src/decorators/bind.test.ts +163 -163
- package/src/decorators/bind.ts +46 -46
- package/src/decorators/custom-element-config.ts +17 -17
- package/src/decorators/property.test.ts +279 -279
- package/src/decorators/query.test.ts +146 -146
- package/src/decorators/query.ts +12 -12
- package/src/decorators/render-property-on-set.ts +3 -3
- package/src/helpers/css.ts +71 -71
- package/src/maquette/cache.ts +35 -35
- package/src/maquette/dom.ts +115 -115
- package/src/maquette/h.ts +100 -100
- package/src/maquette/index.ts +12 -12
- package/src/maquette/interfaces.ts +536 -536
- package/src/maquette/jsx.ts +61 -61
- package/src/maquette/mapping.ts +56 -56
- package/src/maquette/projection.ts +666 -666
- package/src/maquette/projector.ts +205 -200
- package/src/sample/mixin/highlight.tsx +33 -33
- package/src/sample/sample.tsx +98 -0
package/src/custom-element.ts
CHANGED
|
@@ -71,7 +71,7 @@ export abstract class CustomElement extends HTMLElement {
|
|
|
71
71
|
|
|
72
72
|
#internalsObjectUntilAttached: object | null;
|
|
73
73
|
|
|
74
|
-
#controllers: ICustomElementController[] = [];
|
|
74
|
+
readonly #controllers: ICustomElementController[] = [];
|
|
75
75
|
|
|
76
76
|
/** Promise that resolves when the current update is complete */
|
|
77
77
|
#updatePromise: Promise<void> | null = null;
|
|
@@ -131,7 +131,7 @@ export abstract class CustomElement extends HTMLElement {
|
|
|
131
131
|
*
|
|
132
132
|
* @returns {readonly PropertyOptionsWithName[]} Array of property metadata
|
|
133
133
|
*/
|
|
134
|
-
get properties()
|
|
134
|
+
get properties(): readonly PropertyOptionsWithName[] {
|
|
135
135
|
const ctor = this.constructor as ComponentConstructor;
|
|
136
136
|
if (!ctor._propertyInfo) {
|
|
137
137
|
return [];
|
|
@@ -231,7 +231,7 @@ export abstract class CustomElement extends HTMLElement {
|
|
|
231
231
|
* @public
|
|
232
232
|
*/
|
|
233
233
|
renderNow(): void {
|
|
234
|
-
if (!this.shadowRoot) {
|
|
234
|
+
if (this.#useShadowRoot && !this.shadowRoot) {
|
|
235
235
|
return;
|
|
236
236
|
}
|
|
237
237
|
|
|
@@ -372,11 +372,10 @@ export abstract class CustomElement extends HTMLElement {
|
|
|
372
372
|
this.#initStylesheet(styleElement.textContent);
|
|
373
373
|
styleElement.remove();
|
|
374
374
|
}
|
|
375
|
-
|
|
375
|
+
window.addEventListener("updatecssapply", () => {
|
|
376
376
|
this.#polyfillCssApply();
|
|
377
377
|
});
|
|
378
378
|
|
|
379
|
-
|
|
380
379
|
return fragment;
|
|
381
380
|
}
|
|
382
381
|
|
|
@@ -391,9 +390,13 @@ export abstract class CustomElement extends HTMLElement {
|
|
|
391
390
|
element: Element,
|
|
392
391
|
render: () => VNode,
|
|
393
392
|
): Promise<Projector> {
|
|
393
|
+
await new Promise((resolve) =>
|
|
394
|
+
requestAnimationFrame(() => requestAnimationFrame(resolve)),
|
|
395
|
+
);
|
|
396
|
+
return await this.#createProjector(element, render);
|
|
397
|
+
}
|
|
394
398
|
|
|
395
|
-
|
|
396
|
-
|
|
399
|
+
#createProjector(element: Element, render: () => VNode): Promise<Projector> {
|
|
397
400
|
return new Promise<Projector>((resolve, reject) => {
|
|
398
401
|
let projector: Projector;
|
|
399
402
|
const mode = this.#projectorMode ? this.#projectorMode : "append";
|
|
@@ -403,13 +406,11 @@ export abstract class CustomElement extends HTMLElement {
|
|
|
403
406
|
if (eventName === "renderStart" || eventName === "renderDone") {
|
|
404
407
|
this.#invokeRenderLifecycleFn(eventName);
|
|
405
408
|
}
|
|
406
|
-
}
|
|
409
|
+
},
|
|
407
410
|
});
|
|
408
411
|
projector[mode](element, render.bind(this));
|
|
409
412
|
this.#projector = projector;
|
|
410
|
-
|
|
411
|
-
projector.renderNow();
|
|
412
|
-
});
|
|
413
|
+
projector.renderNow();
|
|
413
414
|
resolve(projector);
|
|
414
415
|
this.dispatchEvent(new CustomEvent("firstRender", {}));
|
|
415
416
|
});
|
|
@@ -428,13 +429,21 @@ export abstract class CustomElement extends HTMLElement {
|
|
|
428
429
|
}
|
|
429
430
|
|
|
430
431
|
#invokeRenderLifecycleFn(eventName: string) {
|
|
431
|
-
if (this[eventName]){
|
|
432
|
-
this[eventName](
|
|
432
|
+
if (this[eventName]) {
|
|
433
|
+
this[eventName](
|
|
434
|
+
eventName === "renderStart"
|
|
435
|
+
? this.#isFirstRenderStart
|
|
436
|
+
: this.#isFirstRenderDone,
|
|
437
|
+
);
|
|
433
438
|
}
|
|
434
439
|
const controllerEventName = `host${eventName.charAt(0).toUpperCase()}${eventName.slice(1)}`;
|
|
435
440
|
this.#controllers.forEach((controller) => {
|
|
436
441
|
if (controller[controllerEventName]) {
|
|
437
|
-
controller[controllerEventName](
|
|
442
|
+
controller[controllerEventName](
|
|
443
|
+
eventName === "renderStart"
|
|
444
|
+
? this.#isFirstRenderStart
|
|
445
|
+
: this.#isFirstRenderDone,
|
|
446
|
+
);
|
|
438
447
|
}
|
|
439
448
|
});
|
|
440
449
|
if (eventName === "renderStart") {
|
|
@@ -491,18 +500,17 @@ export abstract class CustomElement extends HTMLElement {
|
|
|
491
500
|
const div = document.createElement("div");
|
|
492
501
|
this.shadowRoot.appendChild(div);
|
|
493
502
|
requestAnimationFrame(() => {
|
|
494
|
-
this
|
|
503
|
+
this.#createProjector(div, (this as any).render).then(() => {
|
|
495
504
|
this.#upgradeProperties();
|
|
496
|
-
})
|
|
505
|
+
});
|
|
497
506
|
});
|
|
498
|
-
|
|
507
|
+
window.addEventListener("updatecssapply", () => {
|
|
499
508
|
this.#polyfillCssApply();
|
|
500
509
|
});
|
|
501
|
-
|
|
502
510
|
}
|
|
503
511
|
}
|
|
504
512
|
|
|
505
|
-
#polyfillCssApply(): string {
|
|
513
|
+
#polyfillCssApply(): string {
|
|
506
514
|
let style = replaceApplyToCssVars(this.#cssText);
|
|
507
515
|
if (this.#cssText !== style) {
|
|
508
516
|
this.#cssText = style;
|
|
@@ -513,14 +521,13 @@ export abstract class CustomElement extends HTMLElement {
|
|
|
513
521
|
URL.revokeObjectURL(this.#linkElement.href);
|
|
514
522
|
}
|
|
515
523
|
this.#linkElement.href = URL.createObjectURL(
|
|
516
|
-
new Blob([style], { type: "text/css" })
|
|
524
|
+
new Blob([style], { type: "text/css" }),
|
|
517
525
|
);
|
|
518
526
|
}
|
|
519
527
|
}
|
|
520
528
|
return style;
|
|
521
529
|
}
|
|
522
530
|
|
|
523
|
-
|
|
524
531
|
#initStylesheet(style: string) {
|
|
525
532
|
this.#cssText = style;
|
|
526
533
|
if (this.#useShadowRoot && this.shadowRoot) {
|
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for @bind decorator
|
|
3
|
-
* Covers method binding to preserve 'this' context
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { describe, it, expect } from 'vitest';
|
|
7
|
-
import '../test-setup.js';
|
|
8
|
-
import { bind } from './bind.js';
|
|
9
|
-
import { CustomElement } from '../custom-element.js';
|
|
10
|
-
import { customElementConfig } from './custom-element-config.js';
|
|
11
|
-
import { generateUniqueTagName } from '../test-setup.js';
|
|
12
|
-
import { waitForRender } from '../test-utils.js';
|
|
13
|
-
|
|
14
|
-
describe('@bind decorator', () => {
|
|
15
|
-
it('should bind method to instance', async () => {
|
|
16
|
-
const tagName = generateUniqueTagName('bind-test');
|
|
17
|
-
|
|
18
|
-
@customElementConfig({ tagName })
|
|
19
|
-
class BindTest extends CustomElement {
|
|
20
|
-
static style = ':host { display: block; }';
|
|
21
|
-
value = 'bound';
|
|
22
|
-
|
|
23
|
-
@bind
|
|
24
|
-
getValue() {
|
|
25
|
-
return this.value;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
render() {
|
|
29
|
-
return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const el = document.createElement(tagName) as BindTest;
|
|
34
|
-
document.body.appendChild(el);
|
|
35
|
-
await waitForRender(el);
|
|
36
|
-
|
|
37
|
-
const method = el.getValue;
|
|
38
|
-
expect(method()).toBe('bound');
|
|
39
|
-
|
|
40
|
-
document.body.removeChild(el);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should preserve this context when method is extracted', async () => {
|
|
44
|
-
const tagName = generateUniqueTagName('bind-test');
|
|
45
|
-
|
|
46
|
-
@customElementConfig({ tagName })
|
|
47
|
-
class BindTest extends CustomElement {
|
|
48
|
-
static style = ':host { display: block; }';
|
|
49
|
-
name = 'test-element';
|
|
50
|
-
|
|
51
|
-
@bind
|
|
52
|
-
getName() {
|
|
53
|
-
return this.name;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
render() {
|
|
57
|
-
return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const el = document.createElement(tagName) as BindTest;
|
|
62
|
-
document.body.appendChild(el);
|
|
63
|
-
await waitForRender(el);
|
|
64
|
-
|
|
65
|
-
const { getName } = el;
|
|
66
|
-
expect(getName()).toBe('test-element');
|
|
67
|
-
|
|
68
|
-
document.body.removeChild(el);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should work with callbacks', async () => {
|
|
72
|
-
const tagName = generateUniqueTagName('bind-test');
|
|
73
|
-
let result: string;
|
|
74
|
-
|
|
75
|
-
@customElementConfig({ tagName })
|
|
76
|
-
class BindTest extends CustomElement {
|
|
77
|
-
static style = ':host { display: block; }';
|
|
78
|
-
message = 'callback test';
|
|
79
|
-
|
|
80
|
-
@bind
|
|
81
|
-
handleCallback() {
|
|
82
|
-
return this.message;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
render() {
|
|
86
|
-
return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const el = document.createElement(tagName) as BindTest;
|
|
91
|
-
document.body.appendChild(el);
|
|
92
|
-
await waitForRender(el);
|
|
93
|
-
|
|
94
|
-
const callback = el.handleCallback;
|
|
95
|
-
result = callback();
|
|
96
|
-
|
|
97
|
-
expect(result).toBe('callback test');
|
|
98
|
-
|
|
99
|
-
document.body.removeChild(el);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should handle methods with arguments', async () => {
|
|
103
|
-
const tagName = generateUniqueTagName('bind-test');
|
|
104
|
-
|
|
105
|
-
@customElementConfig({ tagName })
|
|
106
|
-
class BindTest extends CustomElement {
|
|
107
|
-
static style = ':host { display: block; }';
|
|
108
|
-
|
|
109
|
-
prefixValue = 'Hello';
|
|
110
|
-
|
|
111
|
-
@bind
|
|
112
|
-
greet(name: string) {
|
|
113
|
-
return `${this.prefixValue}, ${name}!`;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
render() {
|
|
117
|
-
return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const el = document.createElement(tagName) as BindTest;
|
|
122
|
-
document.body.appendChild(el);
|
|
123
|
-
await waitForRender(el);
|
|
124
|
-
|
|
125
|
-
const extracted = el.greet;
|
|
126
|
-
expect(extracted('World')).toBe('Hello, World!');
|
|
127
|
-
|
|
128
|
-
document.body.removeChild(el);
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should preserve bound method reference', async () => {
|
|
132
|
-
const tagName = generateUniqueTagName('bind-test');
|
|
133
|
-
|
|
134
|
-
@customElementConfig({ tagName })
|
|
135
|
-
class BindTest extends CustomElement {
|
|
136
|
-
static style = ':host { display: block; }';
|
|
137
|
-
|
|
138
|
-
valueNum = 42;
|
|
139
|
-
|
|
140
|
-
@bind
|
|
141
|
-
getValue() {
|
|
142
|
-
return this.valueNum;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
render() {
|
|
146
|
-
return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const el = document.createElement(tagName) as BindTest;
|
|
151
|
-
document.body.appendChild(el);
|
|
152
|
-
await waitForRender(el);
|
|
153
|
-
|
|
154
|
-
const bound1 = el.getValue;
|
|
155
|
-
const bound2 = el.getValue;
|
|
156
|
-
|
|
157
|
-
// Should return the same bound function
|
|
158
|
-
expect(bound1).toBe(bound2);
|
|
159
|
-
expect(bound1()).toBe(42);
|
|
160
|
-
|
|
161
|
-
document.body.removeChild(el);
|
|
162
|
-
});
|
|
163
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* Tests for @bind decorator
|
|
3
|
+
* Covers method binding to preserve 'this' context
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import '../test-setup.js';
|
|
8
|
+
import { bind } from './bind.js';
|
|
9
|
+
import { CustomElement } from '../custom-element.js';
|
|
10
|
+
import { customElementConfig } from './custom-element-config.js';
|
|
11
|
+
import { generateUniqueTagName } from '../test-setup.js';
|
|
12
|
+
import { waitForRender } from '../test-utils.js';
|
|
13
|
+
|
|
14
|
+
describe('@bind decorator', () => {
|
|
15
|
+
it('should bind method to instance', async () => {
|
|
16
|
+
const tagName = generateUniqueTagName('bind-test');
|
|
17
|
+
|
|
18
|
+
@customElementConfig({ tagName })
|
|
19
|
+
class BindTest extends CustomElement {
|
|
20
|
+
static style = ':host { display: block; }';
|
|
21
|
+
value = 'bound';
|
|
22
|
+
|
|
23
|
+
@bind
|
|
24
|
+
getValue() {
|
|
25
|
+
return this.value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
render() {
|
|
29
|
+
return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const el = document.createElement(tagName) as BindTest;
|
|
34
|
+
document.body.appendChild(el);
|
|
35
|
+
await waitForRender(el);
|
|
36
|
+
|
|
37
|
+
const method = el.getValue;
|
|
38
|
+
expect(method()).toBe('bound');
|
|
39
|
+
|
|
40
|
+
document.body.removeChild(el);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should preserve this context when method is extracted', async () => {
|
|
44
|
+
const tagName = generateUniqueTagName('bind-test');
|
|
45
|
+
|
|
46
|
+
@customElementConfig({ tagName })
|
|
47
|
+
class BindTest extends CustomElement {
|
|
48
|
+
static style = ':host { display: block; }';
|
|
49
|
+
name = 'test-element';
|
|
50
|
+
|
|
51
|
+
@bind
|
|
52
|
+
getName() {
|
|
53
|
+
return this.name;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
render() {
|
|
57
|
+
return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const el = document.createElement(tagName) as BindTest;
|
|
62
|
+
document.body.appendChild(el);
|
|
63
|
+
await waitForRender(el);
|
|
64
|
+
|
|
65
|
+
const { getName } = el;
|
|
66
|
+
expect(getName()).toBe('test-element');
|
|
67
|
+
|
|
68
|
+
document.body.removeChild(el);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should work with callbacks', async () => {
|
|
72
|
+
const tagName = generateUniqueTagName('bind-test');
|
|
73
|
+
let result: string;
|
|
74
|
+
|
|
75
|
+
@customElementConfig({ tagName })
|
|
76
|
+
class BindTest extends CustomElement {
|
|
77
|
+
static style = ':host { display: block; }';
|
|
78
|
+
message = 'callback test';
|
|
79
|
+
|
|
80
|
+
@bind
|
|
81
|
+
handleCallback() {
|
|
82
|
+
return this.message;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
render() {
|
|
86
|
+
return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const el = document.createElement(tagName) as BindTest;
|
|
91
|
+
document.body.appendChild(el);
|
|
92
|
+
await waitForRender(el);
|
|
93
|
+
|
|
94
|
+
const callback = el.handleCallback;
|
|
95
|
+
result = callback();
|
|
96
|
+
|
|
97
|
+
expect(result).toBe('callback test');
|
|
98
|
+
|
|
99
|
+
document.body.removeChild(el);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should handle methods with arguments', async () => {
|
|
103
|
+
const tagName = generateUniqueTagName('bind-test');
|
|
104
|
+
|
|
105
|
+
@customElementConfig({ tagName })
|
|
106
|
+
class BindTest extends CustomElement {
|
|
107
|
+
static style = ':host { display: block; }';
|
|
108
|
+
|
|
109
|
+
prefixValue = 'Hello';
|
|
110
|
+
|
|
111
|
+
@bind
|
|
112
|
+
greet(name: string) {
|
|
113
|
+
return `${this.prefixValue}, ${name}!`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
render() {
|
|
117
|
+
return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const el = document.createElement(tagName) as BindTest;
|
|
122
|
+
document.body.appendChild(el);
|
|
123
|
+
await waitForRender(el);
|
|
124
|
+
|
|
125
|
+
const extracted = el.greet;
|
|
126
|
+
expect(extracted('World')).toBe('Hello, World!');
|
|
127
|
+
|
|
128
|
+
document.body.removeChild(el);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should preserve bound method reference', async () => {
|
|
132
|
+
const tagName = generateUniqueTagName('bind-test');
|
|
133
|
+
|
|
134
|
+
@customElementConfig({ tagName })
|
|
135
|
+
class BindTest extends CustomElement {
|
|
136
|
+
static style = ':host { display: block; }';
|
|
137
|
+
|
|
138
|
+
valueNum = 42;
|
|
139
|
+
|
|
140
|
+
@bind
|
|
141
|
+
getValue() {
|
|
142
|
+
return this.valueNum;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
render() {
|
|
146
|
+
return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const el = document.createElement(tagName) as BindTest;
|
|
151
|
+
document.body.appendChild(el);
|
|
152
|
+
await waitForRender(el);
|
|
153
|
+
|
|
154
|
+
const bound1 = el.getValue;
|
|
155
|
+
const bound2 = el.getValue;
|
|
156
|
+
|
|
157
|
+
// Should return the same bound function
|
|
158
|
+
expect(bound1).toBe(bound2);
|
|
159
|
+
expect(bound1()).toBe(42);
|
|
160
|
+
|
|
161
|
+
document.body.removeChild(el);
|
|
162
|
+
});
|
|
163
|
+
});
|
package/src/decorators/bind.ts
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
export const bind = (target, key, descriptor) => {
|
|
2
|
-
let fn = descriptor.value;
|
|
3
|
-
// console.warn("@Bind decorator is deprecated, use arrow function expression");
|
|
4
|
-
if (typeof fn !== "function") {
|
|
5
|
-
throw new Error(
|
|
6
|
-
`@Bind decorator can only be applied to methods not: ${typeof fn}`
|
|
7
|
-
);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// In IE11 calling Object.defineProperty has a side-effect of evaluating the
|
|
11
|
-
// getter for the property which is being replaced. This causes infinite
|
|
12
|
-
// recursion and an "Out of stack space" error.
|
|
13
|
-
let definingProperty = false;
|
|
14
|
-
|
|
15
|
-
return {
|
|
16
|
-
configurable: true,
|
|
17
|
-
get() {
|
|
18
|
-
if (
|
|
19
|
-
definingProperty ||
|
|
20
|
-
this === target.prototype ||
|
|
21
|
-
this.hasOwnProperty(key) ||
|
|
22
|
-
typeof fn !== "function"
|
|
23
|
-
) {
|
|
24
|
-
return fn;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let boundFn = fn.bind(this);
|
|
28
|
-
definingProperty = true;
|
|
29
|
-
Object.defineProperty(this, key, {
|
|
30
|
-
configurable: true,
|
|
31
|
-
get() {
|
|
32
|
-
return boundFn;
|
|
33
|
-
},
|
|
34
|
-
set(value) {
|
|
35
|
-
fn = value;
|
|
36
|
-
delete this[key];
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
definingProperty = false;
|
|
40
|
-
return boundFn;
|
|
41
|
-
},
|
|
42
|
-
set(value) {
|
|
43
|
-
fn = value;
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
};
|
|
1
|
+
export const bind = (target, key, descriptor) => {
|
|
2
|
+
let fn = descriptor.value;
|
|
3
|
+
// console.warn("@Bind decorator is deprecated, use arrow function expression");
|
|
4
|
+
if (typeof fn !== "function") {
|
|
5
|
+
throw new Error(
|
|
6
|
+
`@Bind decorator can only be applied to methods not: ${typeof fn}`
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// In IE11 calling Object.defineProperty has a side-effect of evaluating the
|
|
11
|
+
// getter for the property which is being replaced. This causes infinite
|
|
12
|
+
// recursion and an "Out of stack space" error.
|
|
13
|
+
let definingProperty = false;
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
configurable: true,
|
|
17
|
+
get() {
|
|
18
|
+
if (
|
|
19
|
+
definingProperty ||
|
|
20
|
+
this === target.prototype ||
|
|
21
|
+
this.hasOwnProperty(key) ||
|
|
22
|
+
typeof fn !== "function"
|
|
23
|
+
) {
|
|
24
|
+
return fn;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let boundFn = fn.bind(this);
|
|
28
|
+
definingProperty = true;
|
|
29
|
+
Object.defineProperty(this, key, {
|
|
30
|
+
configurable: true,
|
|
31
|
+
get() {
|
|
32
|
+
return boundFn;
|
|
33
|
+
},
|
|
34
|
+
set(value) {
|
|
35
|
+
fn = value;
|
|
36
|
+
delete this[key];
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
definingProperty = false;
|
|
40
|
+
return boundFn;
|
|
41
|
+
},
|
|
42
|
+
set(value) {
|
|
43
|
+
fn = value;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
};
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
export interface IElementConfig {
|
|
2
|
-
tagName: string;
|
|
3
|
-
options?: {
|
|
4
|
-
extends: string;
|
|
5
|
-
};
|
|
6
|
-
}
|
|
7
|
-
export const customElementConfig = (config: IElementConfig) => {
|
|
8
|
-
return (Element) => {
|
|
9
|
-
if (customElements.get(config.tagName)) {
|
|
10
|
-
console.warn(
|
|
11
|
-
`Custom element with tag name ${config.tagName} already exists.`
|
|
12
|
-
);
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
customElements.define(config.tagName, Element, config.options);
|
|
16
|
-
};
|
|
17
|
-
};
|
|
1
|
+
export interface IElementConfig {
|
|
2
|
+
tagName: string;
|
|
3
|
+
options?: {
|
|
4
|
+
extends: string;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
export const customElementConfig = (config: IElementConfig) => {
|
|
8
|
+
return (Element) => {
|
|
9
|
+
if (customElements.get(config.tagName)) {
|
|
10
|
+
console.warn(
|
|
11
|
+
`Custom element with tag name ${config.tagName} already exists.`
|
|
12
|
+
);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
customElements.define(config.tagName, Element, config.options);
|
|
16
|
+
};
|
|
17
|
+
};
|