p-elements-core 1.2.32-rc6 → 1.2.32-rc8

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.
Files changed (63) hide show
  1. package/.editorconfig +17 -17
  2. package/.gitlab-ci.yml +18 -18
  3. package/CHANGELOG.md +201 -201
  4. package/demo/sample.js +1 -1
  5. package/demo/screen.css +16 -16
  6. package/dist/p-elements-core-modern.js +1 -1
  7. package/dist/p-elements-core.js +1 -1
  8. package/docs/package-lock.json +6897 -6897
  9. package/docs/package.json +27 -27
  10. package/docs/src/404.md +8 -8
  11. package/docs/src/_data/demos/hello-world/hello-world.tsx +35 -35
  12. package/docs/src/_data/demos/hello-world/index.html +10 -10
  13. package/docs/src/_data/demos/hello-world/project.json +7 -7
  14. package/docs/src/_data/demos/timer/demo-timer.tsx +120 -120
  15. package/docs/src/_data/demos/timer/icons.tsx +62 -62
  16. package/docs/src/_data/demos/timer/index.html +12 -12
  17. package/docs/src/_data/demos/timer/project.json +8 -8
  18. package/docs/src/_data/global.js +13 -13
  19. package/docs/src/_data/helpers.js +19 -19
  20. package/docs/src/_includes/layouts/base.njk +30 -30
  21. package/docs/src/_includes/layouts/playground.njk +40 -40
  22. package/docs/src/_includes/partials/app-header.njk +8 -8
  23. package/docs/src/_includes/partials/head.njk +14 -14
  24. package/docs/src/_includes/partials/nav.njk +19 -19
  25. package/docs/src/_includes/partials/top-nav.njk +51 -51
  26. package/docs/src/documentation/custom-element.md +221 -221
  27. package/docs/src/documentation/decorators/bind.md +71 -71
  28. package/docs/src/documentation/decorators/custom-element-config.md +63 -63
  29. package/docs/src/documentation/decorators/property.md +83 -83
  30. package/docs/src/documentation/decorators/query.md +66 -66
  31. package/docs/src/documentation/decorators/render-property-on-set.md +60 -60
  32. package/docs/src/documentation/decorators.md +9 -9
  33. package/docs/src/documentation/reactive-properties.md +53 -53
  34. package/docs/src/index.d.ts +25 -25
  35. package/docs/src/index.md +3 -3
  36. package/docs/src/scripts/components/app-mode-switch/app-mode-switch.css +78 -78
  37. package/docs/src/scripts/components/app-mode-switch/app-mode-switch.tsx +166 -166
  38. package/docs/src/scripts/components/app-playground/app-playground.tsx +189 -189
  39. package/docs/tsconfig.json +22 -22
  40. package/package.json +2 -2
  41. package/readme.md +206 -206
  42. package/src/custom-element-controller.ts +31 -31
  43. package/src/custom-element.test.ts +906 -906
  44. package/src/custom-element.ts +27 -15
  45. package/src/decorators/bind.test.ts +163 -163
  46. package/src/decorators/bind.ts +46 -46
  47. package/src/decorators/custom-element-config.ts +17 -17
  48. package/src/decorators/property.test.ts +279 -279
  49. package/src/decorators/property.ts +0 -1
  50. package/src/decorators/query.test.ts +146 -146
  51. package/src/decorators/query.ts +12 -12
  52. package/src/decorators/render-property-on-set.ts +3 -3
  53. package/src/helpers/css.ts +71 -71
  54. package/src/maquette/cache.ts +35 -35
  55. package/src/maquette/dom.ts +115 -115
  56. package/src/maquette/h.ts +100 -100
  57. package/src/maquette/index.ts +12 -12
  58. package/src/maquette/interfaces.ts +536 -536
  59. package/src/maquette/jsx.ts +61 -61
  60. package/src/maquette/mapping.ts +56 -56
  61. package/src/maquette/projection.ts +666 -666
  62. package/src/maquette/projector.ts +205 -200
  63. package/src/sample/mixin/highlight.tsx +33 -33
@@ -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() : readonly PropertyOptionsWithName[] {
134
+ get properties(): readonly PropertyOptionsWithName[] {
135
135
  const ctor = this.constructor as ComponentConstructor;
136
136
  if (!ctor._propertyInfo) {
137
137
  return [];
@@ -374,11 +374,10 @@ export abstract class CustomElement extends HTMLElement {
374
374
  this.#initStylesheet(styleElement.textContent);
375
375
  styleElement.remove();
376
376
  }
377
- window.addEventListener("updatecssapply", () => {
377
+ window.addEventListener("updatecssapply", () => {
378
378
  this.#polyfillCssApply();
379
379
  });
380
380
 
381
-
382
381
  return fragment;
383
382
  }
384
383
 
@@ -389,10 +388,17 @@ export abstract class CustomElement extends HTMLElement {
389
388
  this.addStylesheetToRootNode(css, root);
390
389
  }
391
390
 
392
- protected createProjector(
391
+ protected async createProjector(
393
392
  element: Element,
394
393
  render: () => VNode,
395
394
  ): Promise<Projector> {
395
+ await new Promise((resolve) =>
396
+ requestAnimationFrame(() => requestAnimationFrame(resolve)),
397
+ );
398
+ return await this.#createProjector(element, render);
399
+ }
400
+
401
+ #createProjector(element: Element, render: () => VNode): Promise<Projector> {
396
402
  return new Promise<Projector>((resolve, reject) => {
397
403
  let projector: Projector;
398
404
  const mode = this.#projectorMode ? this.#projectorMode : "append";
@@ -402,7 +408,7 @@ export abstract class CustomElement extends HTMLElement {
402
408
  if (eventName === "renderStart" || eventName === "renderDone") {
403
409
  this.#invokeRenderLifecycleFn(eventName);
404
410
  }
405
- }
411
+ },
406
412
  });
407
413
  projector[mode](element, render.bind(this));
408
414
  this.#projector = projector;
@@ -425,13 +431,21 @@ export abstract class CustomElement extends HTMLElement {
425
431
  }
426
432
 
427
433
  #invokeRenderLifecycleFn(eventName: string) {
428
- if (this[eventName]){
429
- this[eventName](eventName === "renderStart" ? this.#isFirstRenderStart : this.#isFirstRenderDone);
434
+ if (this[eventName]) {
435
+ this[eventName](
436
+ eventName === "renderStart"
437
+ ? this.#isFirstRenderStart
438
+ : this.#isFirstRenderDone,
439
+ );
430
440
  }
431
441
  const controllerEventName = `host${eventName.charAt(0).toUpperCase()}${eventName.slice(1)}`;
432
442
  this.#controllers.forEach((controller) => {
433
443
  if (controller[controllerEventName]) {
434
- controller[controllerEventName](eventName === "renderStart" ? this.#isFirstRenderStart : this.#isFirstRenderDone);
444
+ controller[controllerEventName](
445
+ eventName === "renderStart"
446
+ ? this.#isFirstRenderStart
447
+ : this.#isFirstRenderDone,
448
+ );
435
449
  }
436
450
  });
437
451
  if (eventName === "renderStart") {
@@ -488,18 +502,17 @@ export abstract class CustomElement extends HTMLElement {
488
502
  const div = document.createElement("div");
489
503
  this.shadowRoot.appendChild(div);
490
504
  requestAnimationFrame(() => {
491
- this.createProjector(div, (this as any).render).then(() => {
505
+ this.#createProjector(div, (this as any).render).then(() => {
492
506
  this.#upgradeProperties();
493
- })
507
+ });
494
508
  });
495
- window.addEventListener("updatecssapply", () => {
509
+ window.addEventListener("updatecssapply", () => {
496
510
  this.#polyfillCssApply();
497
511
  });
498
-
499
512
  }
500
513
  }
501
514
 
502
- #polyfillCssApply(): string {
515
+ #polyfillCssApply(): string {
503
516
  let style = replaceApplyToCssVars(this.#cssText);
504
517
  if (this.#cssText !== style) {
505
518
  this.#cssText = style;
@@ -510,14 +523,13 @@ export abstract class CustomElement extends HTMLElement {
510
523
  URL.revokeObjectURL(this.#linkElement.href);
511
524
  }
512
525
  this.#linkElement.href = URL.createObjectURL(
513
- new Blob([style], { type: "text/css" })
526
+ new Blob([style], { type: "text/css" }),
514
527
  );
515
528
  }
516
529
  }
517
530
  return style;
518
531
  }
519
532
 
520
-
521
533
  #initStylesheet(style: string) {
522
534
  this.#cssText = style;
523
535
  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
+ });
@@ -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
+ };