p-elements-core 1.2.32-rc2 → 1.2.32-rc4

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 (78) hide show
  1. package/.editorconfig +17 -17
  2. package/.gitlab-ci.yml +18 -18
  3. package/CHANGELOG.md +201 -0
  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 +9 -2
  41. package/readme.md +206 -206
  42. package/src/custom-element-controller.test.ts +226 -0
  43. package/src/custom-element-controller.ts +31 -31
  44. package/src/custom-element.test.ts +906 -0
  45. package/src/custom-element.ts +17 -1
  46. package/src/custom-style-element.ts +4 -1
  47. package/src/decorators/bind.test.ts +163 -0
  48. package/src/decorators/bind.ts +46 -46
  49. package/src/decorators/custom-element-config.ts +17 -17
  50. package/src/decorators/property.test.ts +279 -0
  51. package/src/decorators/property.ts +789 -684
  52. package/src/decorators/query.test.ts +146 -0
  53. package/src/decorators/query.ts +12 -12
  54. package/src/decorators/render-property-on-set.ts +3 -3
  55. package/src/helpers/css.test.ts +150 -0
  56. package/src/helpers/css.ts +71 -71
  57. package/src/maquette/cache.test.ts +150 -0
  58. package/src/maquette/cache.ts +35 -35
  59. package/src/maquette/dom.test.ts +263 -0
  60. package/src/maquette/dom.ts +115 -115
  61. package/src/maquette/h.test.ts +165 -0
  62. package/src/maquette/h.ts +100 -100
  63. package/src/maquette/index.ts +12 -12
  64. package/src/maquette/interfaces.ts +536 -536
  65. package/src/maquette/jsx.ts +61 -61
  66. package/src/maquette/mapping.test.ts +294 -0
  67. package/src/maquette/mapping.ts +56 -56
  68. package/src/maquette/maquette.test.ts +493 -0
  69. package/src/maquette/projection.test.ts +366 -0
  70. package/src/maquette/projection.ts +666 -666
  71. package/src/maquette/projector.test.ts +351 -0
  72. package/src/maquette/projector.ts +200 -200
  73. package/src/sample/mixin/highlight.tsx +33 -33
  74. package/src/test-setup.ts +85 -0
  75. package/src/test-utils.ts +223 -0
  76. package/tsconfig.json +1 -0
  77. package/vitest.config.ts +41 -0
  78. package/webpack.config.js +1 -1
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Test utilities for p-elements-core testing with Vitest
3
+ * Provides helpers for creating and testing custom elements
4
+ */
5
+
6
+ import { CustomElement } from './custom-element.js';
7
+ import { customElementConfig } from './decorators/custom-element-config.js';
8
+ import { generateUniqueTagName, trackElement } from './test-setup.js';
9
+ import type { VNode } from './maquette/interfaces.js';
10
+
11
+ /**
12
+ * Wait for an element to complete its update cycle
13
+ */
14
+ export async function waitForRender(element: CustomElement): Promise<void> {
15
+ // Wait for shadowRoot to be created (async in requestAnimationFrame)
16
+ let attempts = 0;
17
+ const maxAttempts = 100;
18
+ while (!element.shadowRoot && attempts < maxAttempts) {
19
+ await new Promise(resolve => setTimeout(resolve, 10));
20
+ attempts++;
21
+ }
22
+
23
+ if (!element.shadowRoot && attempts >= maxAttempts) {
24
+ console.warn('waitForRender: shadowRoot was not created after max attempts');
25
+ }
26
+
27
+ // Wait for projector to render (also async in requestAnimationFrame)
28
+ await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(() => resolve(undefined))));
29
+
30
+ // Then wait for update to complete
31
+ await element.updateComplete;
32
+ }
33
+
34
+ /**
35
+ * Create and register a test custom element
36
+ * Returns the tag name for the registered element
37
+ */
38
+ export function defineTestElement(
39
+ render: () => VNode,
40
+ options: {
41
+ tagName?: string;
42
+ isFormAssociated?: boolean;
43
+ delegatesFocus?: boolean;
44
+ style?: string;
45
+ extends?: string;
46
+ } = {}
47
+ ): string {
48
+ const tagName = options.tagName || generateUniqueTagName();
49
+
50
+ @customElementConfig({
51
+ tagName,
52
+ options: options.extends ? { extends: options.extends } : undefined,
53
+ })
54
+ class TestElement extends CustomElement {
55
+ static style = options.style || '';
56
+ static isFormAssociated = options.isFormAssociated || false;
57
+ static delegatesFocus = options.delegatesFocus || false;
58
+
59
+ render() {
60
+ return render();
61
+ }
62
+ }
63
+
64
+ return tagName;
65
+ }
66
+
67
+ /**
68
+ * Create a simple test element directly in the DOM
69
+ */
70
+ export async function createTestElement<T extends HTMLElement = HTMLElement>(
71
+ tagName: string,
72
+ attributes: Record<string, any> = {}
73
+ ): Promise<T> {
74
+ const el = document.createElement(tagName) as T;
75
+
76
+ // Set attributes
77
+ Object.entries(attributes).forEach(([key, value]) => {
78
+ if (typeof value === 'boolean') {
79
+ if (value) {
80
+ el.setAttribute(key, '');
81
+ }
82
+ } else if (value !== null && value !== undefined) {
83
+ el.setAttribute(key, String(value));
84
+ }
85
+ });
86
+
87
+ // Add to body for connection
88
+ document.body.appendChild(el);
89
+ trackElement(el);
90
+
91
+ // Wait for render if it's a CustomElement
92
+ if (el instanceof CustomElement) {
93
+ await waitForRender(el as CustomElement);
94
+ }
95
+
96
+ return el;
97
+ }
98
+
99
+ /**
100
+ * Get property descriptor from an element (helps test decorator-generated properties)
101
+ */
102
+ export function getPropertyDescriptor(
103
+ element: any,
104
+ propertyName: string
105
+ ): PropertyDescriptor | undefined {
106
+ let proto = Object.getPrototypeOf(element);
107
+
108
+ while (proto) {
109
+ const descriptor = Object.getOwnPropertyDescriptor(proto, propertyName);
110
+ if (descriptor) {
111
+ return descriptor;
112
+ }
113
+ proto = Object.getPrototypeOf(proto);
114
+ }
115
+
116
+ return undefined;
117
+ }
118
+
119
+ /**
120
+ * Wait for a condition to be true
121
+ */
122
+ export async function waitFor(
123
+ condition: () => boolean,
124
+ timeout: number = 1000,
125
+ interval: number = 10
126
+ ): Promise<void> {
127
+ const startTime = Date.now();
128
+
129
+ while (!condition()) {
130
+ if (Date.now() - startTime > timeout) {
131
+ throw new Error('Timeout waiting for condition');
132
+ }
133
+ await new Promise(resolve => setTimeout(resolve, interval));
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Simulate an attribute change on an element
139
+ */
140
+ export function setAttributeAndNotify(
141
+ element: HTMLElement & { attributeChangedCallback?: Function },
142
+ name: string,
143
+ value: string | null
144
+ ): void {
145
+ const oldValue = element.getAttribute(name);
146
+
147
+ if (value === null) {
148
+ element.removeAttribute(name);
149
+ } else {
150
+ element.setAttribute(name, value);
151
+ }
152
+
153
+ // Manually trigger attributeChangedCallback if it exists
154
+ if (element.attributeChangedCallback) {
155
+ element.attributeChangedCallback(name, oldValue, value);
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Assert that a VNode has specific properties
161
+ */
162
+ export function assertVNode(
163
+ vnode: VNode,
164
+ expected: Partial<{
165
+ vnodeSelector: string;
166
+ text?: string;
167
+ children?: VNode[];
168
+ }>
169
+ ): void {
170
+ if (expected.vnodeSelector) {
171
+ if (vnode.vnodeSelector !== expected.vnodeSelector) {
172
+ throw new Error(
173
+ `Expected vnodeSelector "${expected.vnodeSelector}" but got "${vnode.vnodeSelector}"`
174
+ );
175
+ }
176
+ }
177
+
178
+ if (expected.text !== undefined) {
179
+ if (vnode.text !== expected.text) {
180
+ throw new Error(`Expected text "${expected.text}" but got "${vnode.text}"`);
181
+ }
182
+ }
183
+
184
+ if (expected.children) {
185
+ if (!vnode.children || vnode.children.length !== expected.children.length) {
186
+ throw new Error(
187
+ `Expected ${expected.children.length} children but got ${vnode.children?.length || 0}`
188
+ );
189
+ }
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Get the shadow root of an element, throwing if not found
195
+ */
196
+ export function getShadowRoot(element: HTMLElement): ShadowRoot {
197
+ if (!element.shadowRoot) {
198
+ throw new Error('Element does not have a shadow root');
199
+ }
200
+ return element.shadowRoot;
201
+ }
202
+
203
+ /**
204
+ * Query a selector within an element's shadow DOM
205
+ */
206
+ export function shadowQuery<T extends Element = Element>(
207
+ element: HTMLElement,
208
+ selector: string
209
+ ): T | null {
210
+ return getShadowRoot(element).querySelector<T>(selector);
211
+ }
212
+
213
+ /**
214
+ * Query all selectors within an element's shadow DOM
215
+ */
216
+ export function shadowQueryAll<T extends Element = Element>(
217
+ element: HTMLElement,
218
+ selector: string
219
+ ): NodeListOf<T> {
220
+ return getShadowRoot(element).querySelectorAll<T>(selector);
221
+ }
222
+
223
+
package/tsconfig.json CHANGED
@@ -60,5 +60,6 @@
60
60
  },
61
61
  "exclude": [
62
62
  "docs",
63
+ "vitest.config.ts"
63
64
  ],
64
65
  }
@@ -0,0 +1,41 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ import { playwright } from '@vitest/browser-playwright';
3
+
4
+ export default defineConfig({
5
+ test: {
6
+ browser: {
7
+ enabled: true,
8
+ provider: playwright(),
9
+ headless: process.env.HEADED !== 'true',
10
+ instances: [
11
+ {
12
+ browser: 'chromium',
13
+ },
14
+ ],
15
+ },
16
+ globals: true,
17
+ setupFiles: ['./src/test-setup.ts'],
18
+ include: ['src/**/*.test.{ts,tsx}'],
19
+ exclude: ['node_modules', 'dist', '.idea', '.git', '.cache'],
20
+ coverage: {
21
+ provider: 'v8',
22
+ reporter: ['text', 'json', 'html', 'lcov'],
23
+ reportsDirectory: 'coverage',
24
+ exclude: [
25
+ 'node_modules/',
26
+ 'src/test-setup.ts',
27
+ 'src/test-utils.ts',
28
+ 'src/**/*.test.ts',
29
+ ],
30
+ thresholds: {
31
+ lines: 70,
32
+ functions: 70,
33
+ branches: 60,
34
+ statements: 70,
35
+ },
36
+ },
37
+ testTimeout: 5000,
38
+ hookTimeout: 5000,
39
+ },
40
+ });
41
+
package/webpack.config.js CHANGED
@@ -41,7 +41,7 @@ module.exports = {
41
41
  {
42
42
  test: /\.tsx?$/,
43
43
  use: ["babel-loader", "ts-loader"],
44
- exclude: /node_modules/,
44
+ exclude: [/node_modules/, /\.test\.ts$/],
45
45
  },
46
46
  ],
47
47
  },