p-elements-core 1.2.32-rc8 → 1.2.32

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 (64) 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/index.html +10 -2
  41. package/package.json +1 -1
  42. package/readme.md +206 -206
  43. package/src/custom-element-controller.ts +31 -31
  44. package/src/custom-element.test.ts +906 -906
  45. package/src/custom-element.ts +3 -8
  46. package/src/decorators/bind.test.ts +163 -163
  47. package/src/decorators/bind.ts +46 -46
  48. package/src/decorators/custom-element-config.ts +17 -17
  49. package/src/decorators/property.test.ts +279 -279
  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 -205
  63. package/src/sample/mixin/highlight.tsx +33 -33
  64. package/src/sample/sample.tsx +98 -0
@@ -1,146 +1,146 @@
1
- /**
2
- * Tests for @query decorator
3
- * Covers Shadow DOM and Light DOM queries
4
- */
5
-
6
- import { describe, it, expect } from 'vitest';
7
- import '../test-setup.js';
8
- import { query } from './query.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('@query decorator', () => {
15
- it('should query element in shadow DOM by default', async () => {
16
- const tagName = generateUniqueTagName('query-shadow');
17
-
18
- @customElementConfig({ tagName })
19
- class QueryTest extends CustomElement {
20
- static style = ':host { display: block; }';
21
- @query('.test-target')
22
- target: HTMLElement;
23
-
24
- render() {
25
- return {
26
- vnodeSelector: 'div',
27
- properties: {},
28
- children: [
29
- {
30
- vnodeSelector: 'span',
31
- properties: { class: 'test-target' },
32
- text: 'Found me!',
33
- domNode: null as any,
34
- children: []
35
- },
36
- ],
37
- text: undefined,
38
- domNode: null
39
- };
40
- }
41
- }
42
-
43
- const el = document.createElement(tagName) as QueryTest;
44
- document.body.appendChild(el);
45
- await waitForRender(el);
46
-
47
- expect(el.target).toBeDefined();
48
- expect(el.target.tagName).toBe('SPAN');
49
- expect(el.target.classList.contains('test-target')).toBe(true);
50
-
51
- document.body.removeChild(el);
52
- });
53
-
54
- it('should query element in light DOM when useShadowRoot is false', async () => {
55
- const tagName = generateUniqueTagName('query-light');
56
-
57
- @customElementConfig({ tagName })
58
- class QueryTest extends CustomElement {
59
- static style = ':host { display: block; }';
60
- @query('.light-target', false)
61
- target: HTMLElement;
62
-
63
- render() {
64
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
65
- }
66
- }
67
-
68
- const el = document.createElement(tagName) as QueryTest;
69
- const lightChild = document.createElement('div');
70
- lightChild.className = 'light-target';
71
- lightChild.textContent = 'Light DOM';
72
- el.appendChild(lightChild);
73
-
74
- document.body.appendChild(el);
75
- await waitForRender(el);
76
-
77
- expect(el.target).toBeDefined();
78
- expect(el.target.className).toBe('light-target');
79
-
80
- document.body.removeChild(el);
81
- });
82
-
83
- it('should return null when element not found', async () => {
84
- const tagName = generateUniqueTagName('query-missing');
85
-
86
- @customElementConfig({ tagName })
87
- class QueryTest extends CustomElement {
88
- static style = ':host { display: block; }';
89
- @query('.does-not-exist')
90
- target: HTMLElement;
91
-
92
- render() {
93
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
94
- }
95
- }
96
-
97
- const el = document.createElement(tagName) as QueryTest;
98
- document.body.appendChild(el);
99
- await waitForRender(el);
100
-
101
- expect(el.target).toBeNull();
102
-
103
- document.body.removeChild(el);
104
- });
105
-
106
- it('should update query result when DOM changes', async () => {
107
- const tagName = generateUniqueTagName('query-dynamic');
108
- let showElement = false;
109
-
110
- @customElementConfig({ tagName })
111
- class QueryTest extends CustomElement {
112
- static style = ':host { display: block; }';
113
- @query('.dynamic')
114
- target: HTMLElement;
115
-
116
- render() {
117
- const children = showElement
118
- ? [{ vnodeSelector: 'span', properties: { class: 'dynamic' }, text: 'Dynamic', domNode: null as any, children: [] }]
119
- : [];
120
-
121
- return {
122
- vnodeSelector: 'div',
123
- properties: {},
124
- children,
125
- text: undefined,
126
- domNode: null
127
- };
128
- }
129
- }
130
-
131
- const el = document.createElement(tagName) as QueryTest;
132
- document.body.appendChild(el);
133
- await waitForRender(el);
134
-
135
- expect(el.target).toBeNull();
136
-
137
- showElement = true;
138
- el.renderNow();
139
- await waitForRender(el);
140
-
141
- expect(el.target).toBeDefined();
142
- expect(el.target.tagName).toBe('SPAN');
143
-
144
- document.body.removeChild(el);
145
- });
146
- });
1
+ /**
2
+ * Tests for @query decorator
3
+ * Covers Shadow DOM and Light DOM queries
4
+ */
5
+
6
+ import { describe, it, expect } from 'vitest';
7
+ import '../test-setup.js';
8
+ import { query } from './query.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('@query decorator', () => {
15
+ it('should query element in shadow DOM by default', async () => {
16
+ const tagName = generateUniqueTagName('query-shadow');
17
+
18
+ @customElementConfig({ tagName })
19
+ class QueryTest extends CustomElement {
20
+ static style = ':host { display: block; }';
21
+ @query('.test-target')
22
+ target: HTMLElement;
23
+
24
+ render() {
25
+ return {
26
+ vnodeSelector: 'div',
27
+ properties: {},
28
+ children: [
29
+ {
30
+ vnodeSelector: 'span',
31
+ properties: { class: 'test-target' },
32
+ text: 'Found me!',
33
+ domNode: null as any,
34
+ children: []
35
+ },
36
+ ],
37
+ text: undefined,
38
+ domNode: null
39
+ };
40
+ }
41
+ }
42
+
43
+ const el = document.createElement(tagName) as QueryTest;
44
+ document.body.appendChild(el);
45
+ await waitForRender(el);
46
+
47
+ expect(el.target).toBeDefined();
48
+ expect(el.target.tagName).toBe('SPAN');
49
+ expect(el.target.classList.contains('test-target')).toBe(true);
50
+
51
+ document.body.removeChild(el);
52
+ });
53
+
54
+ it('should query element in light DOM when useShadowRoot is false', async () => {
55
+ const tagName = generateUniqueTagName('query-light');
56
+
57
+ @customElementConfig({ tagName })
58
+ class QueryTest extends CustomElement {
59
+ static style = ':host { display: block; }';
60
+ @query('.light-target', false)
61
+ target: HTMLElement;
62
+
63
+ render() {
64
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
65
+ }
66
+ }
67
+
68
+ const el = document.createElement(tagName) as QueryTest;
69
+ const lightChild = document.createElement('div');
70
+ lightChild.className = 'light-target';
71
+ lightChild.textContent = 'Light DOM';
72
+ el.appendChild(lightChild);
73
+
74
+ document.body.appendChild(el);
75
+ await waitForRender(el);
76
+
77
+ expect(el.target).toBeDefined();
78
+ expect(el.target.className).toBe('light-target');
79
+
80
+ document.body.removeChild(el);
81
+ });
82
+
83
+ it('should return null when element not found', async () => {
84
+ const tagName = generateUniqueTagName('query-missing');
85
+
86
+ @customElementConfig({ tagName })
87
+ class QueryTest extends CustomElement {
88
+ static style = ':host { display: block; }';
89
+ @query('.does-not-exist')
90
+ target: HTMLElement;
91
+
92
+ render() {
93
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
94
+ }
95
+ }
96
+
97
+ const el = document.createElement(tagName) as QueryTest;
98
+ document.body.appendChild(el);
99
+ await waitForRender(el);
100
+
101
+ expect(el.target).toBeNull();
102
+
103
+ document.body.removeChild(el);
104
+ });
105
+
106
+ it('should update query result when DOM changes', async () => {
107
+ const tagName = generateUniqueTagName('query-dynamic');
108
+ let showElement = false;
109
+
110
+ @customElementConfig({ tagName })
111
+ class QueryTest extends CustomElement {
112
+ static style = ':host { display: block; }';
113
+ @query('.dynamic')
114
+ target: HTMLElement;
115
+
116
+ render() {
117
+ const children = showElement
118
+ ? [{ vnodeSelector: 'span', properties: { class: 'dynamic' }, text: 'Dynamic', domNode: null as any, children: [] }]
119
+ : [];
120
+
121
+ return {
122
+ vnodeSelector: 'div',
123
+ properties: {},
124
+ children,
125
+ text: undefined,
126
+ domNode: null
127
+ };
128
+ }
129
+ }
130
+
131
+ const el = document.createElement(tagName) as QueryTest;
132
+ document.body.appendChild(el);
133
+ await waitForRender(el);
134
+
135
+ expect(el.target).toBeNull();
136
+
137
+ showElement = true;
138
+ el.renderNow();
139
+ await waitForRender(el);
140
+
141
+ expect(el.target).toBeDefined();
142
+ expect(el.target.tagName).toBe('SPAN');
143
+
144
+ document.body.removeChild(el);
145
+ });
146
+ });
@@ -1,12 +1,12 @@
1
- export const query = (selector: string, useShadowRoot = true) => {
2
- return function(target: Object, propertyKey: string) {
3
- Object.defineProperty(target, propertyKey, {
4
- get: function() {
5
- if (useShadowRoot) {
6
- return this.shadowRoot.querySelector(selector);
7
- }
8
- return this.querySelector(selector);
9
- },
10
- });
11
- }
12
- };
1
+ export const query = (selector: string, useShadowRoot = true) => {
2
+ return function(target: Object, propertyKey: string) {
3
+ Object.defineProperty(target, propertyKey, {
4
+ get: function() {
5
+ if (useShadowRoot) {
6
+ return this.shadowRoot.querySelector(selector);
7
+ }
8
+ return this.querySelector(selector);
9
+ },
10
+ });
11
+ }
12
+ };
@@ -1,3 +1,3 @@
1
- import {property} from "./property";
2
- const propertDecorator = property({});
3
- export const propertyRenderOnSet = propertDecorator;
1
+ import {property} from "./property";
2
+ const propertDecorator = property({});
3
+ export const propertyRenderOnSet = propertDecorator;
@@ -1,71 +1,71 @@
1
- import { CustomStyleElement } from "../custom-style-element";
2
-
3
- const VAR_ASSIGN =
4
- /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};{])+)|\{([^}]*)\}(?:(?=[;\s}])|$))/gi;
5
-
6
- export const cssApplyVars = new Map<string, string[]>();
7
-
8
- function getMixinValues(valueMixin: string): { key: string; value: string }[] {
9
- return valueMixin
10
- ?.split(";")
11
- .map((mixin: string) => {
12
- const [key, value] = mixin.split(":", 2);
13
- return { key: key.trim(), value: value ? value.trim() : "" };
14
- })
15
- .filter(
16
- (mixin: any) =>
17
- mixin.key && mixin.key !== "" && mixin.value !== ""
18
- );
19
- }
20
-
21
- export function cssApplyToCssVars(style: string): string {
22
- let nrOfReplacements = 0;
23
- const cssText = style.replace(
24
- VAR_ASSIGN,
25
- (matchText, propertyName, valueProperty, valueMixin) => {
26
- if (valueMixin) {
27
- nrOfReplacements++;
28
- const values = getMixinValues(valueMixin);
29
- let replaceText = "";
30
- const props: string[] = [];
31
- values.forEach((mixin: any) => {
32
- props.push(mixin.key);
33
- replaceText +=
34
- `${propertyName}_-_${mixin.key}: ${mixin.value};` + "\n";
35
- });
36
- cssApplyVars.set(propertyName, props);
37
- return matchText.replace(
38
- propertyName,
39
- `${replaceText}
40
- ${propertyName}`
41
- );
42
- }
43
- return matchText;
44
- }
45
- );
46
- return nrOfReplacements > 0 ? cssText : null;
47
- }
48
-
49
- export function replaceApplyToCssVars(cssText: string) : string {
50
- const allVars = (
51
- customElements.get("custom-style") as typeof CustomStyleElement
52
- ).cssApplyVars;
53
-
54
- let style = cssText;
55
- const MIXIN_MATCH = /(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi;
56
- let m;
57
- while ((m = MIXIN_MATCH.exec(style))) {
58
- let matchText = m[0];
59
- let mixinName = m[1];
60
- if (allVars.has(mixinName)) {
61
- const searchText = "@apply" + matchText.split("@apply", 2)[1];
62
- const replaceText = allVars
63
- .get(mixinName)
64
- .map((prop: string) => `;${prop}: var(${mixinName}_-_${prop});`)
65
- .join("");
66
-
67
- style = style.replace(searchText, replaceText);
68
- }
69
- }
70
- return style;
71
- }
1
+ import { CustomStyleElement } from "../custom-style-element";
2
+
3
+ const VAR_ASSIGN =
4
+ /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};{])+)|\{([^}]*)\}(?:(?=[;\s}])|$))/gi;
5
+
6
+ export const cssApplyVars = new Map<string, string[]>();
7
+
8
+ function getMixinValues(valueMixin: string): { key: string; value: string }[] {
9
+ return valueMixin
10
+ ?.split(";")
11
+ .map((mixin: string) => {
12
+ const [key, value] = mixin.split(":", 2);
13
+ return { key: key.trim(), value: value ? value.trim() : "" };
14
+ })
15
+ .filter(
16
+ (mixin: any) =>
17
+ mixin.key && mixin.key !== "" && mixin.value !== ""
18
+ );
19
+ }
20
+
21
+ export function cssApplyToCssVars(style: string): string {
22
+ let nrOfReplacements = 0;
23
+ const cssText = style.replace(
24
+ VAR_ASSIGN,
25
+ (matchText, propertyName, valueProperty, valueMixin) => {
26
+ if (valueMixin) {
27
+ nrOfReplacements++;
28
+ const values = getMixinValues(valueMixin);
29
+ let replaceText = "";
30
+ const props: string[] = [];
31
+ values.forEach((mixin: any) => {
32
+ props.push(mixin.key);
33
+ replaceText +=
34
+ `${propertyName}_-_${mixin.key}: ${mixin.value};` + "\n";
35
+ });
36
+ cssApplyVars.set(propertyName, props);
37
+ return matchText.replace(
38
+ propertyName,
39
+ `${replaceText}
40
+ ${propertyName}`
41
+ );
42
+ }
43
+ return matchText;
44
+ }
45
+ );
46
+ return nrOfReplacements > 0 ? cssText : null;
47
+ }
48
+
49
+ export function replaceApplyToCssVars(cssText: string) : string {
50
+ const allVars = (
51
+ customElements.get("custom-style") as typeof CustomStyleElement
52
+ ).cssApplyVars;
53
+
54
+ let style = cssText;
55
+ const MIXIN_MATCH = /(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi;
56
+ let m;
57
+ while ((m = MIXIN_MATCH.exec(style))) {
58
+ let matchText = m[0];
59
+ let mixinName = m[1];
60
+ if (allVars.has(mixinName)) {
61
+ const searchText = "@apply" + matchText.split("@apply", 2)[1];
62
+ const replaceText = allVars
63
+ .get(mixinName)
64
+ .map((prop: string) => `;${prop}: var(${mixinName}_-_${prop});`)
65
+ .join("");
66
+
67
+ style = style.replace(searchText, replaceText);
68
+ }
69
+ }
70
+ return style;
71
+ }
@@ -1,35 +1,35 @@
1
- import { CalculationCache } from "./interfaces";
2
-
3
- /**
4
- * Creates a [[CalculationCache]] object, useful for caching [[VNode]] trees.
5
- * In practice, caching of [[VNode]] trees is not needed, because achieving 60 frames per second is almost never a problem.
6
- * For more information, see [[CalculationCache]].
7
- *
8
- * @param <Result> The type of the value that is cached.
9
- */
10
- export let createCache = <Result,>(): CalculationCache<Result> => {
11
- let cachedInputs: unknown[] | undefined;
12
- let cachedOutcome: Result | undefined;
13
-
14
- return {
15
- invalidate: () => {
16
- cachedOutcome = undefined;
17
- cachedInputs = undefined;
18
- },
19
-
20
- result: (inputs: unknown[], calculation: () => Result) => {
21
- if (cachedInputs) {
22
- for (let i = 0; i < inputs.length; i++) {
23
- if (cachedInputs[i] !== inputs[i]) {
24
- cachedOutcome = undefined;
25
- }
26
- }
27
- }
28
- if (!cachedOutcome) {
29
- cachedOutcome = calculation();
30
- cachedInputs = inputs;
31
- }
32
- return cachedOutcome;
33
- },
34
- };
35
- };
1
+ import { CalculationCache } from "./interfaces";
2
+
3
+ /**
4
+ * Creates a [[CalculationCache]] object, useful for caching [[VNode]] trees.
5
+ * In practice, caching of [[VNode]] trees is not needed, because achieving 60 frames per second is almost never a problem.
6
+ * For more information, see [[CalculationCache]].
7
+ *
8
+ * @param <Result> The type of the value that is cached.
9
+ */
10
+ export let createCache = <Result,>(): CalculationCache<Result> => {
11
+ let cachedInputs: unknown[] | undefined;
12
+ let cachedOutcome: Result | undefined;
13
+
14
+ return {
15
+ invalidate: () => {
16
+ cachedOutcome = undefined;
17
+ cachedInputs = undefined;
18
+ },
19
+
20
+ result: (inputs: unknown[], calculation: () => Result) => {
21
+ if (cachedInputs) {
22
+ for (let i = 0; i < inputs.length; i++) {
23
+ if (cachedInputs[i] !== inputs[i]) {
24
+ cachedOutcome = undefined;
25
+ }
26
+ }
27
+ }
28
+ if (!cachedOutcome) {
29
+ cachedOutcome = calculation();
30
+ cachedInputs = inputs;
31
+ }
32
+ return cachedOutcome;
33
+ },
34
+ };
35
+ };