@praxisjs/css 0.3.4 → 0.3.6

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 (146) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/builder/css-builder.d.ts.map +1 -1
  3. package/dist/builder/css-builder.js +68 -74
  4. package/dist/builder/css-builder.js.map +1 -1
  5. package/dist/builder/keyframes.d.ts +5 -0
  6. package/dist/builder/keyframes.d.ts.map +1 -1
  7. package/dist/builder/keyframes.js +12 -14
  8. package/dist/builder/keyframes.js.map +1 -1
  9. package/dist/cx.d.ts.map +1 -1
  10. package/dist/cx.js +23 -18
  11. package/dist/cx.js.map +1 -1
  12. package/dist/decorators/param.d.ts +1 -2
  13. package/dist/decorators/param.d.ts.map +1 -1
  14. package/dist/decorators/param.js +9 -17
  15. package/dist/decorators/param.js.map +1 -1
  16. package/dist/decorators/style.d.ts.map +1 -1
  17. package/dist/decorators/style.js +61 -33
  18. package/dist/decorators/style.js.map +1 -1
  19. package/dist/decorators/styled.d.ts.map +1 -1
  20. package/dist/decorators/styled.js +112 -95
  21. package/dist/decorators/styled.js.map +1 -1
  22. package/dist/extract.d.ts.map +1 -1
  23. package/dist/extract.js +19 -35
  24. package/dist/extract.js.map +1 -1
  25. package/dist/global.d.ts +3 -0
  26. package/dist/global.d.ts.map +1 -1
  27. package/dist/global.js +9 -4
  28. package/dist/global.js.map +1 -1
  29. package/dist/internal/kebab.d.ts +5 -0
  30. package/dist/internal/kebab.d.ts.map +1 -0
  31. package/dist/internal/kebab.js +23 -0
  32. package/dist/internal/kebab.js.map +1 -0
  33. package/dist/internal/lifecycle.d.ts +15 -0
  34. package/dist/internal/lifecycle.d.ts.map +1 -0
  35. package/dist/internal/lifecycle.js +16 -0
  36. package/dist/internal/lifecycle.js.map +1 -0
  37. package/dist/internal/registry.d.ts +5 -1
  38. package/dist/internal/registry.d.ts.map +1 -1
  39. package/dist/internal/registry.js +9 -23
  40. package/dist/internal/registry.js.map +1 -1
  41. package/dist/internal/sheet.d.ts +20 -0
  42. package/dist/internal/sheet.d.ts.map +1 -0
  43. package/dist/internal/sheet.js +56 -0
  44. package/dist/internal/sheet.js.map +1 -0
  45. package/dist/internal/static-mode.d.ts +2 -0
  46. package/dist/internal/static-mode.d.ts.map +1 -0
  47. package/dist/internal/static-mode.js +2 -0
  48. package/dist/internal/static-mode.js.map +1 -0
  49. package/dist/preflight.d.ts +3 -1
  50. package/dist/preflight.d.ts.map +1 -1
  51. package/dist/preflight.js +7 -3
  52. package/dist/preflight.js.map +1 -1
  53. package/dist/tokens/decorators.d.ts.map +1 -1
  54. package/dist/tokens/decorators.js +13 -4
  55. package/dist/tokens/decorators.js.map +1 -1
  56. package/dist/tokens/theme-instance.d.ts +5 -0
  57. package/dist/tokens/theme-instance.d.ts.map +1 -1
  58. package/dist/tokens/theme-instance.js +25 -17
  59. package/dist/tokens/theme-instance.js.map +1 -1
  60. package/dist/tokens/token-sheet.d.ts.map +1 -1
  61. package/dist/tokens/token-sheet.js +12 -9
  62. package/dist/tokens/token-sheet.js.map +1 -1
  63. package/package.json +13 -5
  64. package/src/builder/css-builder.ts +79 -83
  65. package/src/builder/keyframes.ts +12 -20
  66. package/src/cx.ts +20 -13
  67. package/src/decorators/param.ts +12 -16
  68. package/src/decorators/style.ts +79 -35
  69. package/src/decorators/styled.ts +127 -111
  70. package/src/extract.ts +18 -34
  71. package/src/global.ts +10 -9
  72. package/src/internal/kebab.ts +23 -0
  73. package/src/internal/lifecycle.ts +21 -0
  74. package/src/internal/registry.ts +9 -35
  75. package/src/internal/sheet.ts +71 -0
  76. package/src/internal/static-mode.ts +6 -0
  77. package/src/preflight.ts +8 -3
  78. package/src/tokens/decorators.ts +15 -3
  79. package/src/tokens/theme-instance.ts +26 -16
  80. package/src/tokens/token-sheet.ts +12 -12
  81. package/dist/__tests__/css-builder.test.d.ts +0 -2
  82. package/dist/__tests__/css-builder.test.d.ts.map +0 -1
  83. package/dist/__tests__/css-builder.test.js +0 -198
  84. package/dist/__tests__/css-builder.test.js.map +0 -1
  85. package/dist/__tests__/cx.test.d.ts +0 -2
  86. package/dist/__tests__/cx.test.d.ts.map +0 -1
  87. package/dist/__tests__/cx.test.js +0 -47
  88. package/dist/__tests__/cx.test.js.map +0 -1
  89. package/dist/__tests__/decorators.test.d.ts +0 -2
  90. package/dist/__tests__/decorators.test.d.ts.map +0 -1
  91. package/dist/__tests__/decorators.test.js +0 -264
  92. package/dist/__tests__/decorators.test.js.map +0 -1
  93. package/dist/__tests__/extract.test.d.ts +0 -2
  94. package/dist/__tests__/extract.test.d.ts.map +0 -1
  95. package/dist/__tests__/extract.test.js +0 -416
  96. package/dist/__tests__/extract.test.js.map +0 -1
  97. package/dist/__tests__/global.test.d.ts +0 -2
  98. package/dist/__tests__/global.test.d.ts.map +0 -1
  99. package/dist/__tests__/global.test.js +0 -136
  100. package/dist/__tests__/global.test.js.map +0 -1
  101. package/dist/__tests__/keyframes.test.d.ts +0 -2
  102. package/dist/__tests__/keyframes.test.d.ts.map +0 -1
  103. package/dist/__tests__/keyframes.test.js +0 -90
  104. package/dist/__tests__/keyframes.test.js.map +0 -1
  105. package/dist/__tests__/preflight.test.d.ts +0 -2
  106. package/dist/__tests__/preflight.test.d.ts.map +0 -1
  107. package/dist/__tests__/preflight.test.js +0 -74
  108. package/dist/__tests__/preflight.test.js.map +0 -1
  109. package/dist/__tests__/registry.test.d.ts +0 -2
  110. package/dist/__tests__/registry.test.d.ts.map +0 -1
  111. package/dist/__tests__/registry.test.js +0 -132
  112. package/dist/__tests__/registry.test.js.map +0 -1
  113. package/dist/__tests__/style.test.d.ts +0 -2
  114. package/dist/__tests__/style.test.d.ts.map +0 -1
  115. package/dist/__tests__/style.test.js +0 -281
  116. package/dist/__tests__/style.test.js.map +0 -1
  117. package/dist/__tests__/styled.test.d.ts +0 -2
  118. package/dist/__tests__/styled.test.d.ts.map +0 -1
  119. package/dist/__tests__/styled.test.js +0 -904
  120. package/dist/__tests__/styled.test.js.map +0 -1
  121. package/dist/__tests__/theme-instance.test.d.ts +0 -2
  122. package/dist/__tests__/theme-instance.test.d.ts.map +0 -1
  123. package/dist/__tests__/theme-instance.test.js +0 -309
  124. package/dist/__tests__/theme-instance.test.js.map +0 -1
  125. package/dist/__tests__/theme-uninit.test.d.ts +0 -2
  126. package/dist/__tests__/theme-uninit.test.d.ts.map +0 -1
  127. package/dist/__tests__/theme-uninit.test.js +0 -10
  128. package/dist/__tests__/theme-uninit.test.js.map +0 -1
  129. package/dist/__tests__/token-sheet.test.d.ts +0 -2
  130. package/dist/__tests__/token-sheet.test.d.ts.map +0 -1
  131. package/dist/__tests__/token-sheet.test.js +0 -74
  132. package/dist/__tests__/token-sheet.test.js.map +0 -1
  133. package/src/__tests__/css-builder.test.ts +0 -230
  134. package/src/__tests__/cx.test.ts +0 -63
  135. package/src/__tests__/decorators.test.ts +0 -127
  136. package/src/__tests__/extract.test.ts +0 -459
  137. package/src/__tests__/global.test.ts +0 -163
  138. package/src/__tests__/keyframes.test.ts +0 -103
  139. package/src/__tests__/preflight.test.ts +0 -85
  140. package/src/__tests__/registry.test.ts +0 -151
  141. package/src/__tests__/style.test.ts +0 -170
  142. package/src/__tests__/styled.test.ts +0 -443
  143. package/src/__tests__/theme-instance.test.ts +0 -374
  144. package/src/__tests__/theme-uninit.test.ts +0 -12
  145. package/src/__tests__/token-sheet.test.ts +0 -87
  146. package/tsconfig.json +0 -8
@@ -1,443 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
3
- import { StatefulComponent } from "@praxisjs/core";
4
- import { setComponentAnchor } from "@praxisjs/core/internal";
5
- import { Component } from "@praxisjs/decorators";
6
- import { Param } from "../decorators/param";
7
- import { ReactiveStylesheet, Stylesheet } from "../base/stylesheet";
8
- import { Styled } from "../decorators/styled";
9
-
10
- type WithLifecycle = { onMount?(): void; onUnmount?(): void };
11
-
12
- beforeEach(() => {
13
- document
14
- .head
15
- .querySelectorAll("style[data-praxis-hash]")
16
- .forEach((el) => el.remove());
17
- });
18
-
19
- afterEach(() => {
20
- document
21
- .head
22
- .querySelectorAll("style[data-praxis-hash]")
23
- .forEach((el) => el.remove());
24
- });
25
-
26
- // ─── CSS class fields ($-prefixed) ────────────────────────────────────────────
27
-
28
- class BtnStyle extends Stylesheet {
29
- $base = `display: inline-flex; padding: 8px 16px;`;
30
- $primary = `background: var(--accent); color: white;`;
31
- }
32
-
33
- describe("@Styled — $-prefixed CSS class fields", () => {
34
- it("transforms $-fields to scoped class names", () => {
35
- class Comp {
36
- @Styled(BtnStyle) $btn!: BtnStyle;
37
- }
38
-
39
- const { $btn } = new Comp();
40
- expect($btn.$base).toMatch(/^prx-base-/);
41
- expect($btn.$primary).toMatch(/^prx-primary-/);
42
- });
43
-
44
- it("class names are distinct for distinct CSS", () => {
45
- class Comp {
46
- @Styled(BtnStyle) $btn!: BtnStyle;
47
- }
48
-
49
- const { $btn } = new Comp();
50
- expect($btn.$base).not.toBe($btn.$primary);
51
- });
52
-
53
- it("same CSS content produces the same hash suffix across different keys", () => {
54
- class SA extends Stylesheet { $x = `color: red;`; }
55
- class SB extends Stylesheet { $y = `color: red;`; }
56
-
57
- const hashA = new (class { @Styled(SA) $a!: SA; })().$a.$x.split("-").pop();
58
- const hashB = new (class { @Styled(SB) $b!: SB; })().$b.$y.split("-").pop();
59
- expect(hashA).toBe(hashB);
60
- });
61
-
62
- it("caches the class map — same object reference across instances", () => {
63
- class Comp {
64
- @Styled(BtnStyle) $btn!: BtnStyle;
65
- }
66
-
67
- expect(new Comp().$btn).toBe(new Comp().$btn);
68
- });
69
-
70
- it("injects a style element into document.head eagerly at decoration time", () => {
71
- // Before any class definition: no style element
72
- expect(document.head.querySelector("style[data-praxis-hash]")).toBeNull();
73
-
74
- // Defining a class with @Styled injects immediately (before any mount)
75
- class Comp {
76
- @Styled(BtnStyle) $btn!: BtnStyle;
77
- }
78
-
79
- expect(document.head.querySelector("style[data-praxis-hash]")).not.toBeNull();
80
- // Style is present even before instantiation or mount
81
- void Comp;
82
- });
83
-
84
- it("style is present before onMount is called", () => {
85
- class Comp {
86
- @Styled(BtnStyle) $btn!: BtnStyle;
87
- }
88
-
89
- // Style injected at decoration time — no mount needed
90
- expect(document.head.querySelector("style[data-praxis-hash]")).not.toBeNull();
91
- const inst = new Comp() as WithLifecycle;
92
- // Still present before mount
93
- expect(document.head.querySelector("style[data-praxis-hash]")).not.toBeNull();
94
- inst.onMount?.();
95
- expect(document.head.querySelector("style[data-praxis-hash]")).not.toBeNull();
96
- });
97
-
98
- it("injected CSS contains the generated class names", () => {
99
- class Comp {
100
- @Styled(BtnStyle) $btn!: BtnStyle;
101
- }
102
-
103
- const css = document.head.querySelector("style[data-praxis-hash]")?.textContent ?? "";
104
- expect(css).toContain(new Comp().$btn.$base);
105
- });
106
-
107
- it("reference-counts — injects once for multiple instances", () => {
108
- class Comp {
109
- @Styled(BtnStyle) $btn!: BtnStyle;
110
- }
111
-
112
- const i1 = new Comp() as WithLifecycle;
113
- const i2 = new Comp() as WithLifecycle;
114
- i1.onMount?.();
115
- i2.onMount?.();
116
- expect(document.head.querySelectorAll("style[data-praxis-hash]").length).toBe(1);
117
- });
118
-
119
- it("style persists after all instances unmount (decoration-time base reference)", () => {
120
- // The eager injection at decoration time holds a permanent reference.
121
- // Unmounting all instances decrements their ref-count but does not remove the style.
122
- class Comp {
123
- @Styled(BtnStyle) $btn!: BtnStyle;
124
- }
125
-
126
- const inst = new Comp() as WithLifecycle;
127
- inst.onMount?.();
128
- inst.onUnmount?.();
129
- expect(document.head.querySelector("style[data-praxis-hash]")).not.toBeNull();
130
- });
131
-
132
- it("keeps style when one of two instances unmounts", () => {
133
- class Comp {
134
- @Styled(BtnStyle) $btn!: BtnStyle;
135
- }
136
-
137
- const i1 = new Comp() as WithLifecycle;
138
- const i2 = new Comp() as WithLifecycle;
139
- i1.onMount?.();
140
- i2.onMount?.();
141
-
142
- i1.onUnmount?.();
143
- expect(document.head.querySelector("style[data-praxis-hash]")).not.toBeNull();
144
-
145
- i2.onUnmount?.();
146
- expect(document.head.querySelector("style[data-praxis-hash]")).not.toBeNull();
147
- });
148
-
149
- it("multiple @Styled fields inject separate stylesheets", () => {
150
- class SA extends Stylesheet { $foo = `color: tomato;`; }
151
- class SB extends Stylesheet { $bar = `color: steelblue;`; }
152
-
153
- class Comp {
154
- @Styled(SA) $a!: SA;
155
- @Styled(SB) $b!: SB;
156
- }
157
-
158
- // Both injected at decoration time
159
- expect(document.head.querySelectorAll("style[data-praxis-hash]").length).toBe(2);
160
-
161
- const inst = new Comp() as WithLifecycle;
162
- inst.onMount?.();
163
- expect(document.head.querySelectorAll("style[data-praxis-hash]").length).toBe(2);
164
- inst.onUnmount?.();
165
- expect(document.head.querySelectorAll("style[data-praxis-hash]").length).toBe(2);
166
- });
167
-
168
- it("works with @Component() in the class stack", () => {
169
- @Component()
170
- class Card extends StatefulComponent {
171
- @Styled(BtnStyle) $btn!: BtnStyle;
172
- render() { return document.createElement("div"); }
173
- }
174
-
175
- const inst = new Card();
176
- expect(inst.$btn.$base).toMatch(/^prx-base-/);
177
- });
178
-
179
- it("skips $-prefixed fields that are neither string nor CSSBuilder", () => {
180
- class S extends Stylesheet {
181
- $root = 42 as unknown as string;
182
- $base = `display: flex;`;
183
- }
184
- class Comp {
185
- @Styled(S) $s!: S;
186
- }
187
- const inst = new Comp();
188
- expect((inst.$s as unknown as Record<string, unknown>).$root).toBeUndefined();
189
- expect(inst.$s.$base).toMatch(/^prx-base-/);
190
- });
191
-
192
- it("processes CSSBuilder fields (this.css({}))", () => {
193
- class S extends Stylesheet {
194
- $root = this.css({ display: "flex", gap: "12px" })
195
- .hover({ opacity: 0.9 });
196
- }
197
- class Comp {
198
- @Styled(S) $s!: S;
199
- }
200
- const inst = new Comp() as WithLifecycle & Comp;
201
- expect(inst.$s.$root).toMatch(/^prx-root-/);
202
-
203
- const css = document.head.querySelector("style[data-praxis-hash]")?.textContent ?? "";
204
- expect(css).toContain("display: flex;");
205
- expect(css).toContain("&:hover");
206
- inst.onUnmount?.();
207
- });
208
- });
209
-
210
- // ─── @Param() reactive CSS vars ─────────────────────────────────────────────────
211
-
212
- function makeAnchor(parent: HTMLElement): Comment {
213
- const anchor = document.createComment("[/Comp]");
214
- parent.appendChild(anchor);
215
- return anchor;
216
- }
217
-
218
- describe("@Param — reactive CSS custom properties", () => {
219
- it("@Param() field exposes a getter/setter on the stylesheet object", () => {
220
- class S extends ReactiveStylesheet {
221
- @Param() color = "#3b82f6";
222
- $root = `background: var(--color);`;
223
- }
224
-
225
- class Comp extends StatefulComponent {
226
- @Styled(S) $s!: S;
227
- render() { return document.createElement("div"); }
228
- }
229
-
230
- const inst = new Comp();
231
- expect(inst.$s.color).toBe("#3b82f6");
232
-
233
- inst.$s.color = "red";
234
- expect(inst.$s.color).toBe("red");
235
- });
236
-
237
- it("sets the CSS var on the element when onMount fires", () => {
238
- const container = document.createElement("div");
239
- document.body.appendChild(container);
240
-
241
- class S extends ReactiveStylesheet {
242
- @Param() accent = "#3b82f6";
243
- $root = `color: var(--accent);`;
244
- }
245
-
246
- class Comp extends StatefulComponent {
247
- constructor() {
248
- super();
249
- setComponentAnchor(this, makeAnchor(container));
250
- }
251
- @Styled(S) $s!: S;
252
- render() { return document.createElement("div"); }
253
- }
254
-
255
- const inst = new Comp() as WithLifecycle;
256
- inst.onMount?.();
257
-
258
- expect(container.style.getPropertyValue("--accent")).toBe("#3b82f6");
259
- container.remove();
260
- });
261
-
262
- it("updates the CSS var reactively when the field is set", () => {
263
- const container = document.createElement("div");
264
- document.body.appendChild(container);
265
-
266
- class S extends ReactiveStylesheet {
267
- @Param() color = "blue";
268
- $root = `color: var(--color);`;
269
- }
270
-
271
- class Comp extends StatefulComponent {
272
- constructor() {
273
- super();
274
- setComponentAnchor(this, makeAnchor(container));
275
- }
276
- @Styled(S) $s!: S;
277
- render() { return document.createElement("div"); }
278
- }
279
-
280
- const inst = new Comp() as WithLifecycle & Comp;
281
- inst.onMount?.();
282
- expect(container.style.getPropertyValue("--color")).toBe("blue");
283
-
284
- inst.$s.color = "red";
285
- expect(container.style.getPropertyValue("--color")).toBe("red");
286
-
287
- container.remove();
288
- });
289
-
290
- it("removes CSS vars on onUnmount", () => {
291
- const container = document.createElement("div");
292
- document.body.appendChild(container);
293
-
294
- class S extends ReactiveStylesheet {
295
- @Param() size = "16px";
296
- $root = `font-size: var(--size);`;
297
- }
298
-
299
- class Comp extends StatefulComponent {
300
- constructor() {
301
- super();
302
- setComponentAnchor(this, makeAnchor(container));
303
- }
304
- @Styled(S) $s!: S;
305
- render() { return document.createElement("div"); }
306
- }
307
-
308
- const inst = new Comp() as WithLifecycle;
309
- inst.onMount?.();
310
- expect(container.style.getPropertyValue("--size")).toBe("16px");
311
-
312
- inst.onUnmount?.();
313
- expect(container.style.getPropertyValue("--size")).toBe("");
314
-
315
- container.remove();
316
- });
317
-
318
- it("each instance gets independent signal state", () => {
319
- const c1 = document.createElement("div");
320
- const c2 = document.createElement("div");
321
- document.body.append(c1, c2);
322
-
323
- class S extends ReactiveStylesheet {
324
- @Param() color = "blue";
325
- $root = `color: var(--color);`;
326
- }
327
-
328
- class Comp extends StatefulComponent {
329
- constructor(anchor: Comment) {
330
- super();
331
- setComponentAnchor(this, anchor);
332
- }
333
- @Styled(S) $s!: S;
334
- render() { return document.createElement("div"); }
335
- }
336
-
337
- const i1 = new Comp(makeAnchor(c1)) as WithLifecycle & Comp;
338
- const i2 = new Comp(makeAnchor(c2)) as WithLifecycle & Comp;
339
- i1.onMount?.();
340
- i2.onMount?.();
341
-
342
- i1.$s.color = "red";
343
- expect(c1.style.getPropertyValue("--color")).toBe("red");
344
- expect(c2.style.getPropertyValue("--color")).toBe("blue");
345
-
346
- c1.remove();
347
- c2.remove();
348
- });
349
-
350
- it("Stylesheet with only @Param() fields (no $ CSS) — no style element injected", () => {
351
- class S extends ReactiveStylesheet {
352
- @Param() color = "red";
353
- }
354
- class Comp extends StatefulComponent {
355
- @Styled(S) $s!: S;
356
- render() { return document.createElement("div"); }
357
- }
358
- const inst = new Comp() as WithLifecycle;
359
- inst.onMount?.();
360
- expect(document.head.querySelector("style[data-praxis-hash]")).toBeNull();
361
- inst.onUnmount?.();
362
- });
363
-
364
- it("@Param() field with non-string/non-number value is skipped (defensive)", () => {
365
- class S extends ReactiveStylesheet {
366
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
367
- @(Param() as any) items = [] as unknown as string;
368
- $root = `display: flex;`;
369
- }
370
- class Comp extends StatefulComponent {
371
- @Styled(S) $s!: S;
372
- render() { return document.createElement("div"); }
373
- }
374
- const inst = new Comp();
375
- expect(inst.$s.$root).toMatch(/^prx-root-/);
376
- expect((inst.$s as unknown as Record<string, unknown>).items).toBeUndefined();
377
- });
378
-
379
- it("non-$ non-@Param() fields in Stylesheet are silently ignored", () => {
380
- class S extends ReactiveStylesheet {
381
- $root = `display: flex;`;
382
- description = "a plain field that should be skipped";
383
- }
384
- class Comp extends StatefulComponent {
385
- @Styled(S) $s!: S;
386
- render() { return document.createElement("div"); }
387
- }
388
- const inst = new Comp();
389
- expect(inst.$s.$root).toMatch(/^prx-root-/);
390
- expect((inst.$s as unknown as Record<string, unknown>).description).toBeUndefined();
391
- });
392
-
393
- it("two @Param() fields on the same class — PARAM_META entry reused", () => {
394
- class S extends ReactiveStylesheet {
395
- @Param() color = "blue";
396
- @Param() radius = "8px";
397
- $root = `color: var(--color); border-radius: var(--radius);`;
398
- }
399
- class Comp extends StatefulComponent {
400
- @Styled(S) $s!: S;
401
- render() { return document.createElement("div"); }
402
- }
403
- const inst = new Comp();
404
- expect(inst.$s.color).toBe("blue");
405
- expect(inst.$s.radius).toBe("8px");
406
- });
407
-
408
- it("onUnmount removes CSS vars from element when el is present", () => {
409
- const container = document.createElement("div");
410
- document.body.appendChild(container);
411
-
412
- class S extends ReactiveStylesheet {
413
- @Param() color = "red";
414
- $root = `color: var(--color);`;
415
- }
416
- class Comp extends StatefulComponent {
417
- constructor() {
418
- super();
419
- setComponentAnchor(this, makeAnchor(container));
420
- }
421
- @Styled(S) $s!: S;
422
- render() { return document.createElement("div"); }
423
- }
424
- const inst = new Comp() as WithLifecycle;
425
- inst.onMount?.();
426
- expect(container.style.getPropertyValue("--color")).toBe("red");
427
- inst.onUnmount?.();
428
- expect(container.style.getPropertyValue("--color")).toBe("");
429
- container.remove();
430
- });
431
-
432
- it("@Param() cannot be applied outside ReactiveStylesheet — enforced at TypeScript level", () => {
433
- expect(() => {
434
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
435
- const dec = (Param as any);
436
- const fakeCtx = {
437
- name: "foo",
438
- addInitializer(fn: () => void) { fn.call({ constructor: class {} }); },
439
- };
440
- dec(undefined, fakeCtx);
441
- }).not.toThrow();
442
- });
443
- });