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,279 +1,279 @@
1
- /**
2
- * Tests for @property decorator
3
- * Covers type conversion, attribute reflection, custom converters, and lifecycle integration
4
- */
5
-
6
- import { describe, it, expect } from 'vitest';
7
- import '../test-setup.js';
8
- import { property } from './property.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('@property decorator', () => {
15
- describe('Type: String', () => {
16
- it('should convert attribute to string property', async () => {
17
- const tagName = generateUniqueTagName('prop-string');
18
-
19
- @customElementConfig({ tagName })
20
- class StringTest extends CustomElement {
21
- static style = ':host { display: block; }';
22
- @property({ type: String })
23
- text = 'default';
24
-
25
- render() {
26
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
27
- }
28
- }
29
-
30
- const el = document.createElement(tagName) as StringTest;
31
- el.setAttribute('text', 'hello');
32
- document.body.appendChild(el);
33
- await waitForRender(el);
34
-
35
- expect(el.text).toBe('hello');
36
-
37
- document.body.removeChild(el);
38
- });
39
-
40
- it('should set property from JavaScript', async () => {
41
- const tagName = generateUniqueTagName('prop-string');
42
-
43
- @customElementConfig({ tagName })
44
- class StringTest extends CustomElement {
45
- static style = ':host { display: block; }';
46
- @property({ type: String })
47
- text = 'default';
48
-
49
- render() {
50
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
51
- }
52
- }
53
-
54
- const el = document.createElement(tagName) as StringTest;
55
- document.body.appendChild(el);
56
-
57
- el.text = 'updated';
58
- await waitForRender(el);
59
-
60
- expect(el.text).toBe('updated');
61
-
62
- document.body.removeChild(el);
63
- });
64
- });
65
-
66
- describe('Type: Number', () => {
67
- it('should convert attribute to number property', async () => {
68
- const tagName = generateUniqueTagName('prop-number');
69
-
70
- @customElementConfig({ tagName })
71
- class NumberTest extends CustomElement {
72
- static style = ':host { display: block; }';
73
- @property({ type: Number })
74
- count = 0;
75
-
76
- render() {
77
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
78
- }
79
- }
80
-
81
- const el = document.createElement(tagName) as NumberTest;
82
- el.setAttribute('count', '42');
83
- document.body.appendChild(el);
84
- await waitForRender(el);
85
-
86
- expect(el.count).toBe(42);
87
-
88
- document.body.removeChild(el);
89
- });
90
- });
91
-
92
- describe('Type: Boolean', () => {
93
- it('should convert presence of attribute to true', async () => {
94
- const tagName = generateUniqueTagName('prop-bool');
95
-
96
- @customElementConfig({ tagName })
97
- class BooleanTest extends CustomElement {
98
- static style = ':host { display: block; }';
99
- @property({ type: Boolean })
100
- active = false;
101
-
102
- render() {
103
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
104
- }
105
- }
106
-
107
- const el = document.createElement(tagName) as BooleanTest;
108
- el.setAttribute('active', '');
109
- document.body.appendChild(el);
110
- await waitForRender(el);
111
-
112
- expect(el.active).toBe(true);
113
-
114
- document.body.removeChild(el);
115
- });
116
- });
117
-
118
- describe('Attribute reflection (reflect: true)', () => {
119
- it('should reflect string property to attribute', async () => {
120
- const tagName = generateUniqueTagName('prop-reflect');
121
-
122
- @customElementConfig({ tagName })
123
- class ReflectTest extends CustomElement {
124
- static style = ':host { display: block; }';
125
- @property({ type: String, reflect: true })
126
- status = 'pending';
127
-
128
- render() {
129
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
130
- }
131
- }
132
-
133
- const el = document.createElement(tagName) as ReflectTest;
134
- document.body.appendChild(el);
135
-
136
- el.status = 'complete';
137
- await waitForRender(el);
138
-
139
- expect(el.getAttribute('status')).toBe('complete');
140
-
141
- document.body.removeChild(el);
142
- });
143
-
144
- it('should reflect boolean property to attribute', async () => {
145
- const tagName = generateUniqueTagName('prop-reflect');
146
-
147
- @customElementConfig({ tagName })
148
- class ReflectTest extends CustomElement {
149
- static style = ':host { display: block; }';
150
- @property({ type: Boolean, reflect: true })
151
- active = false;
152
-
153
- render() {
154
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
155
- }
156
- }
157
-
158
- const el = document.createElement(tagName) as ReflectTest;
159
- document.body.appendChild(el);
160
-
161
- el.active = true;
162
- await waitForRender(el);
163
- expect(el.hasAttribute('active')).toBe(true);
164
-
165
- el.active = false;
166
- await waitForRender(el);
167
- expect(el.hasAttribute('active')).toBe(false);
168
-
169
- document.body.removeChild(el);
170
- });
171
-
172
- it('should reflect number property to attribute', async () => {
173
- const tagName = generateUniqueTagName('prop-reflect');
174
-
175
- @customElementConfig({ tagName })
176
- class ReflectTest extends CustomElement {
177
- static style = ':host { display: block; }';
178
- @property({ type: Number, reflect: true })
179
- count = 0;
180
-
181
- render() {
182
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
183
- }
184
- }
185
-
186
- const el = document.createElement(tagName) as ReflectTest;
187
- document.body.appendChild(el);
188
-
189
- el.count = 42;
190
- await waitForRender(el);
191
-
192
- expect(el.getAttribute('count')).toBe('42');
193
-
194
- document.body.removeChild(el);
195
- });
196
- });
197
-
198
- describe('Property without type conversion', () => {
199
- it('should handle object properties', async () => {
200
- const tagName = generateUniqueTagName('prop-object');
201
-
202
- @customElementConfig({ tagName })
203
- class ObjectTest extends CustomElement {
204
- static style = ':host { display: block; }';
205
- @property()
206
- data: any = null;
207
-
208
- render() {
209
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
210
- }
211
- }
212
-
213
- const el = document.createElement(tagName) as ObjectTest;
214
- document.body.appendChild(el);
215
-
216
- const testData = { foo: 'bar', num: 123 };
217
- el.data = testData;
218
- await waitForRender(el);
219
-
220
- expect(el.data).toBe(testData);
221
- expect(el.data.foo).toBe('bar');
222
-
223
- document.body.removeChild(el);
224
- });
225
-
226
- it('should handle array properties', async () => {
227
- const tagName = generateUniqueTagName('prop-array');
228
-
229
- @customElementConfig({ tagName })
230
- class ArrayTest extends CustomElement {
231
- static style = ':host { display: block; }';
232
- @property()
233
- items: string[] = [];
234
-
235
- render() {
236
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
237
- }
238
- }
239
-
240
- const el = document.createElement(tagName) as ArrayTest;
241
- document.body.appendChild(el);
242
-
243
- el.items = ['a', 'b', 'c'];
244
- await waitForRender(el);
245
-
246
- expect(el.items.length).toBe(3);
247
- expect(el.items[0]).toBe('a');
248
-
249
- document.body.removeChild(el);
250
- });
251
- });
252
-
253
- describe('Custom attribute names', () => {
254
- it('should support custom attribute names', async () => {
255
- const tagName = generateUniqueTagName('prop-custom');
256
-
257
- @customElementConfig({ tagName })
258
- class CustomAttrTest extends CustomElement {
259
- static style = ':host { display: block; }';
260
- @property({ type: String, attribute: 'data-value' })
261
- value = '';
262
-
263
- render() {
264
- return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
265
- }
266
- }
267
-
268
- const el = document.createElement(tagName) as CustomAttrTest;
269
- document.body.appendChild(el);
270
-
271
- el.setAttribute('data-value', 'test');
272
- await new Promise(resolve => setTimeout(resolve, 10));
273
-
274
- expect(el.value).toBe('test');
275
-
276
- document.body.removeChild(el);
277
- });
278
- });
279
- });
1
+ /**
2
+ * Tests for @property decorator
3
+ * Covers type conversion, attribute reflection, custom converters, and lifecycle integration
4
+ */
5
+
6
+ import { describe, it, expect } from 'vitest';
7
+ import '../test-setup.js';
8
+ import { property } from './property.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('@property decorator', () => {
15
+ describe('Type: String', () => {
16
+ it('should convert attribute to string property', async () => {
17
+ const tagName = generateUniqueTagName('prop-string');
18
+
19
+ @customElementConfig({ tagName })
20
+ class StringTest extends CustomElement {
21
+ static style = ':host { display: block; }';
22
+ @property({ type: String })
23
+ text = 'default';
24
+
25
+ render() {
26
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
27
+ }
28
+ }
29
+
30
+ const el = document.createElement(tagName) as StringTest;
31
+ el.setAttribute('text', 'hello');
32
+ document.body.appendChild(el);
33
+ await waitForRender(el);
34
+
35
+ expect(el.text).toBe('hello');
36
+
37
+ document.body.removeChild(el);
38
+ });
39
+
40
+ it('should set property from JavaScript', async () => {
41
+ const tagName = generateUniqueTagName('prop-string');
42
+
43
+ @customElementConfig({ tagName })
44
+ class StringTest extends CustomElement {
45
+ static style = ':host { display: block; }';
46
+ @property({ type: String })
47
+ text = 'default';
48
+
49
+ render() {
50
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
51
+ }
52
+ }
53
+
54
+ const el = document.createElement(tagName) as StringTest;
55
+ document.body.appendChild(el);
56
+
57
+ el.text = 'updated';
58
+ await waitForRender(el);
59
+
60
+ expect(el.text).toBe('updated');
61
+
62
+ document.body.removeChild(el);
63
+ });
64
+ });
65
+
66
+ describe('Type: Number', () => {
67
+ it('should convert attribute to number property', async () => {
68
+ const tagName = generateUniqueTagName('prop-number');
69
+
70
+ @customElementConfig({ tagName })
71
+ class NumberTest extends CustomElement {
72
+ static style = ':host { display: block; }';
73
+ @property({ type: Number })
74
+ count = 0;
75
+
76
+ render() {
77
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
78
+ }
79
+ }
80
+
81
+ const el = document.createElement(tagName) as NumberTest;
82
+ el.setAttribute('count', '42');
83
+ document.body.appendChild(el);
84
+ await waitForRender(el);
85
+
86
+ expect(el.count).toBe(42);
87
+
88
+ document.body.removeChild(el);
89
+ });
90
+ });
91
+
92
+ describe('Type: Boolean', () => {
93
+ it('should convert presence of attribute to true', async () => {
94
+ const tagName = generateUniqueTagName('prop-bool');
95
+
96
+ @customElementConfig({ tagName })
97
+ class BooleanTest extends CustomElement {
98
+ static style = ':host { display: block; }';
99
+ @property({ type: Boolean })
100
+ active = false;
101
+
102
+ render() {
103
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
104
+ }
105
+ }
106
+
107
+ const el = document.createElement(tagName) as BooleanTest;
108
+ el.setAttribute('active', '');
109
+ document.body.appendChild(el);
110
+ await waitForRender(el);
111
+
112
+ expect(el.active).toBe(true);
113
+
114
+ document.body.removeChild(el);
115
+ });
116
+ });
117
+
118
+ describe('Attribute reflection (reflect: true)', () => {
119
+ it('should reflect string property to attribute', async () => {
120
+ const tagName = generateUniqueTagName('prop-reflect');
121
+
122
+ @customElementConfig({ tagName })
123
+ class ReflectTest extends CustomElement {
124
+ static style = ':host { display: block; }';
125
+ @property({ type: String, reflect: true })
126
+ status = 'pending';
127
+
128
+ render() {
129
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
130
+ }
131
+ }
132
+
133
+ const el = document.createElement(tagName) as ReflectTest;
134
+ document.body.appendChild(el);
135
+
136
+ el.status = 'complete';
137
+ await waitForRender(el);
138
+
139
+ expect(el.getAttribute('status')).toBe('complete');
140
+
141
+ document.body.removeChild(el);
142
+ });
143
+
144
+ it('should reflect boolean property to attribute', async () => {
145
+ const tagName = generateUniqueTagName('prop-reflect');
146
+
147
+ @customElementConfig({ tagName })
148
+ class ReflectTest extends CustomElement {
149
+ static style = ':host { display: block; }';
150
+ @property({ type: Boolean, reflect: true })
151
+ active = false;
152
+
153
+ render() {
154
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
155
+ }
156
+ }
157
+
158
+ const el = document.createElement(tagName) as ReflectTest;
159
+ document.body.appendChild(el);
160
+
161
+ el.active = true;
162
+ await waitForRender(el);
163
+ expect(el.hasAttribute('active')).toBe(true);
164
+
165
+ el.active = false;
166
+ await waitForRender(el);
167
+ expect(el.hasAttribute('active')).toBe(false);
168
+
169
+ document.body.removeChild(el);
170
+ });
171
+
172
+ it('should reflect number property to attribute', async () => {
173
+ const tagName = generateUniqueTagName('prop-reflect');
174
+
175
+ @customElementConfig({ tagName })
176
+ class ReflectTest extends CustomElement {
177
+ static style = ':host { display: block; }';
178
+ @property({ type: Number, reflect: true })
179
+ count = 0;
180
+
181
+ render() {
182
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
183
+ }
184
+ }
185
+
186
+ const el = document.createElement(tagName) as ReflectTest;
187
+ document.body.appendChild(el);
188
+
189
+ el.count = 42;
190
+ await waitForRender(el);
191
+
192
+ expect(el.getAttribute('count')).toBe('42');
193
+
194
+ document.body.removeChild(el);
195
+ });
196
+ });
197
+
198
+ describe('Property without type conversion', () => {
199
+ it('should handle object properties', async () => {
200
+ const tagName = generateUniqueTagName('prop-object');
201
+
202
+ @customElementConfig({ tagName })
203
+ class ObjectTest extends CustomElement {
204
+ static style = ':host { display: block; }';
205
+ @property()
206
+ data: any = null;
207
+
208
+ render() {
209
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
210
+ }
211
+ }
212
+
213
+ const el = document.createElement(tagName) as ObjectTest;
214
+ document.body.appendChild(el);
215
+
216
+ const testData = { foo: 'bar', num: 123 };
217
+ el.data = testData;
218
+ await waitForRender(el);
219
+
220
+ expect(el.data).toBe(testData);
221
+ expect(el.data.foo).toBe('bar');
222
+
223
+ document.body.removeChild(el);
224
+ });
225
+
226
+ it('should handle array properties', async () => {
227
+ const tagName = generateUniqueTagName('prop-array');
228
+
229
+ @customElementConfig({ tagName })
230
+ class ArrayTest extends CustomElement {
231
+ static style = ':host { display: block; }';
232
+ @property()
233
+ items: string[] = [];
234
+
235
+ render() {
236
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
237
+ }
238
+ }
239
+
240
+ const el = document.createElement(tagName) as ArrayTest;
241
+ document.body.appendChild(el);
242
+
243
+ el.items = ['a', 'b', 'c'];
244
+ await waitForRender(el);
245
+
246
+ expect(el.items.length).toBe(3);
247
+ expect(el.items[0]).toBe('a');
248
+
249
+ document.body.removeChild(el);
250
+ });
251
+ });
252
+
253
+ describe('Custom attribute names', () => {
254
+ it('should support custom attribute names', async () => {
255
+ const tagName = generateUniqueTagName('prop-custom');
256
+
257
+ @customElementConfig({ tagName })
258
+ class CustomAttrTest extends CustomElement {
259
+ static style = ':host { display: block; }';
260
+ @property({ type: String, attribute: 'data-value' })
261
+ value = '';
262
+
263
+ render() {
264
+ return { vnodeSelector: 'div', properties: {}, children: [], text: undefined, domNode: null };
265
+ }
266
+ }
267
+
268
+ const el = document.createElement(tagName) as CustomAttrTest;
269
+ document.body.appendChild(el);
270
+
271
+ el.setAttribute('data-value', 'test');
272
+ await new Promise(resolve => setTimeout(resolve, 10));
273
+
274
+ expect(el.value).toBe('test');
275
+
276
+ document.body.removeChild(el);
277
+ });
278
+ });
279
+ });