@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,20 +1,13 @@
1
1
  import { getCollector } from "./collector.js";
2
+ import { STATIC_MODE } from "./static-mode.js";
2
3
 
3
- // ─── Static mode ──────────────────────────────────────────────────────────────
4
-
5
- // Defined by the Vite CSS plugin via `define: { __PRAXIS_CSS_STATIC__: true }`.
6
- // When true, CSS is already bundled via virtual:praxisjs/styles — skip DOM injection.
7
- declare const __PRAXIS_CSS_STATIC__: boolean | undefined;
8
-
9
- const STATIC_MODE: boolean =
10
- typeof __PRAXIS_CSS_STATIC__ !== "undefined" && __PRAXIS_CSS_STATIC__;
11
-
12
- // ─── DOM registry ─────────────────────────────────────────────────────────────
13
-
14
- // WeakRef lets the GC reclaim style elements that were removed externally
15
- // without going through releaseStyle (e.g. framework teardown, test cleanup).
16
- const cssRegistry = new Map<string, { ref: WeakRef<HTMLStyleElement>; count: number }>();
4
+ const elements = new Map<string, HTMLStyleElement>();
17
5
 
6
+ /**
7
+ * Makes sure the stylesheet `key` is present: collected while a collector is active (server
8
+ * render), appended once to `document.head` otherwise, and appended again if its element was
9
+ * removed from the document. Idempotent, so it is cheap to call for every component instance.
10
+ */
18
11
  export function injectStyle(key: string, css: string): void {
19
12
  if (STATIC_MODE) return;
20
13
 
@@ -22,30 +15,11 @@ export function injectStyle(key: string, css: string): void {
22
15
  if (col) { col.inject(key, css); return; }
23
16
 
24
17
  if (typeof document === "undefined") return;
25
-
26
- const existing = cssRegistry.get(key);
27
- const existingEl = existing?.ref.deref();
28
-
29
- if (existing && existingEl && document.head.contains(existingEl)) {
30
- existing.count++;
31
- return;
32
- }
18
+ if (elements.get(key)?.isConnected) return;
33
19
 
34
20
  const el = document.createElement("style");
35
21
  el.setAttribute("data-praxis-hash", key);
36
22
  el.textContent = css;
37
23
  document.head.appendChild(el);
38
- cssRegistry.set(key, { ref: new WeakRef(el), count: 1 });
39
- }
40
-
41
- export function releaseStyle(key: string): void {
42
- if (STATIC_MODE) return;
43
-
44
- const entry = cssRegistry.get(key);
45
- if (!entry) return;
46
- entry.count--;
47
- if (entry.count <= 0) {
48
- entry.ref.deref()?.remove();
49
- cssRegistry.delete(key);
50
- }
24
+ elements.set(key, el);
51
25
  }
@@ -0,0 +1,71 @@
1
+ import { hashCSS } from "./hash.js";
2
+ import { isCSSBuilder } from "../builder/css-builder.js";
3
+
4
+ const PARAM_META = new WeakMap<object, Set<string>>();
5
+
6
+ export function addParamName(ctor: object, name: string): void {
7
+ let names = PARAM_META.get(ctor);
8
+ if (!names) { names = new Set(); PARAM_META.set(ctor, names); }
9
+ names.add(name);
10
+ }
11
+
12
+ export function getParamNames(ctor: object): ReadonlySet<string> | undefined {
13
+ return PARAM_META.get(ctor);
14
+ }
15
+
16
+ export interface CompiledSheet {
17
+ /** `$field` → scoped class name. */
18
+ classMap: Readonly<Record<string, string>>;
19
+ /** One `.class { ... }` block per `$` field, or `""` when there is none. */
20
+ css: string;
21
+ /** Content hash of `css`, the key of its `<style>` element. */
22
+ key: string;
23
+ /** `@Param()` field names, in declaration order. */
24
+ params: readonly string[];
25
+ /** Default value of each entry in `params`. */
26
+ defaults: ReadonlyArray<string | number>;
27
+ }
28
+
29
+ const cache = new WeakMap<object, CompiledSheet>();
30
+
31
+ /**
32
+ * Builds the scoped class names and CSS of a `Stylesheet` subclass, once per class: constructing
33
+ * the template instance fires its `@Param()` initializers, which register the param names.
34
+ */
35
+ export function compileSheet(SheetClass: new () => unknown): CompiledSheet {
36
+ const cached = cache.get(SheetClass);
37
+ if (cached) return cached;
38
+
39
+ const template = new SheetClass() as Record<string, unknown>;
40
+ const paramNames = getParamNames(SheetClass);
41
+
42
+ const classMap: Record<string, string> = {};
43
+ const params: string[] = [];
44
+ const defaults: Array<string | number> = [];
45
+ let css = "";
46
+
47
+ for (const key of Object.keys(template)) {
48
+ const value = template[key];
49
+ if (key.startsWith("$")) {
50
+ const rule = typeof value === "string" ? value : isCSSBuilder(value) ? String(value) : null;
51
+ if (rule === null) continue;
52
+ const className = `prx-${key.slice(1).replace(/[^\w-]/g, "-")}-${hashCSS(rule)}`;
53
+ classMap[key] = className;
54
+ const block = `.${className} { ${rule.trim()} }`;
55
+ css = css === "" ? block : `${css}\n${block}`;
56
+ } else if (paramNames?.has(key) && (typeof value === "string" || typeof value === "number")) {
57
+ params.push(key);
58
+ defaults.push(value);
59
+ }
60
+ }
61
+
62
+ const compiled: CompiledSheet = {
63
+ classMap: Object.freeze(classMap),
64
+ css,
65
+ key: css ? hashCSS(css) : "",
66
+ params,
67
+ defaults,
68
+ };
69
+ cache.set(SheetClass, compiled);
70
+ return compiled;
71
+ }
@@ -0,0 +1,6 @@
1
+ // Defined by the Vite CSS plugin via `define: { __PRAXIS_CSS_STATIC__: true }`.
2
+ // When true, CSS is already bundled via virtual:praxisjs/styles — skip DOM injection.
3
+ declare const __PRAXIS_CSS_STATIC__: boolean | undefined;
4
+
5
+ export const STATIC_MODE: boolean =
6
+ typeof __PRAXIS_CSS_STATIC__ !== "undefined" && __PRAXIS_CSS_STATIC__;
package/src/preflight.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { globalStyle } from "./global.js";
1
+ import { globalCSS, injectGlobalCSS } from "./global.js";
2
2
 
3
3
  // Tailwind CSS preflight — https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/preflight.css
4
4
  // --theme() references stripped and replaced with their fallback values.
@@ -197,6 +197,11 @@ export interface PreflightOptions {
197
197
  * import { preflight } from '@praxisjs/css'
198
198
  * preflight()
199
199
  */
200
- export function preflight({ layer = "reset" }: PreflightOptions = {}): void {
201
- globalStyle(_css => PREFLIGHT, { layer });
200
+ export function preflight(options?: PreflightOptions): void {
201
+ injectGlobalCSS(preflightCSS(options));
202
+ }
203
+
204
+ /** The CSS `preflight()` injects — shared with build-time extraction. */
205
+ export function preflightCSS({ layer = "reset" }: PreflightOptions = {}): string {
206
+ return globalCSS(() => PREFLIGHT, { layer });
202
207
  }
@@ -9,6 +9,7 @@ import {
9
9
 
10
10
  import {
11
11
  createThemeInstance,
12
+ isActiveTheme,
12
13
  theme,
13
14
  ThemeInstance,
14
15
  type ThemedConfig,
@@ -16,7 +17,11 @@ import {
16
17
 
17
18
  // ─── @Themed ─────────────────────────────────────────────────────────────────
18
19
 
20
+ const NO_ENHANCEMENT: ClassEnhancement = Object.freeze({});
21
+
19
22
  class ThemedBehavior extends ClassBehavior {
23
+ #instance: ThemeInstance | null = null;
24
+
20
25
  constructor(
21
26
  private readonly DefaultTheme: new () => unknown,
22
27
  private readonly config: Partial<ThemedConfig>,
@@ -24,16 +29,23 @@ class ThemedBehavior extends ClassBehavior {
24
29
  super();
25
30
  }
26
31
 
32
+ // Makes this class's theme the active one again, e.g. after another @Themed class replaced it
33
+ // or it was destroyed. While it is still active it is kept, so a theme the user switched to
34
+ // survives the component being instantiated again.
27
35
  create(_instance: RootComponent): ClassEnhancement {
28
- createThemeInstance(this.DefaultTheme, this.config);
29
- return {};
36
+ if (!isActiveTheme(this.#instance)) this.#activate();
37
+ return NO_ENHANCEMENT;
30
38
  }
31
39
 
32
40
  initialize(
33
41
  _Enhanced: new (...args: unknown[]) => unknown,
34
42
  _original: new (...args: unknown[]) => unknown,
35
43
  ): void {
36
- createThemeInstance(this.DefaultTheme, this.config);
44
+ this.#activate();
45
+ }
46
+
47
+ #activate(): void {
48
+ this.#instance = createThemeInstance(this.DefaultTheme, this.config);
37
49
  }
38
50
  }
39
51
 
@@ -1,25 +1,26 @@
1
1
  import { getCollector } from "../internal/collector.js";
2
+ import { toKebab } from "../internal/kebab.js";
2
3
 
3
4
  // ─── helpers ──────────────────────────────────────────────────────────────────
4
5
 
5
- function camelToKebab(s: string): string {
6
- return s.replace(/([A-Z])/g, "-$1").toLowerCase();
7
- }
8
-
9
- function instanceToVars(instance: Record<string, unknown>): Record<string, string> {
6
+ /** The `--token: value` pairs of a theme instance's string and number fields. */
7
+ export function instanceToVars(instance: Record<string, unknown>): Record<string, string> {
10
8
  const result: Record<string, string> = {};
11
- for (const [key, val] of Object.entries(instance)) {
9
+ for (const key of Object.keys(instance)) {
10
+ const val = instance[key];
12
11
  if (typeof val === "string" || typeof val === "number") {
13
- result[`--${camelToKebab(key)}`] = String(val);
12
+ result[`--${toKebab(key)}`] = String(val);
14
13
  }
15
14
  }
16
15
  return result;
17
16
  }
18
17
 
19
- function varsToCSS(vars: Record<string, string>): string {
20
- const body = Object.entries(vars)
21
- .map(([k, v]) => ` ${k}: ${v};`)
22
- .join("\n");
18
+ export function varsToCSS(vars: Record<string, string>): string {
19
+ let body = "";
20
+ for (const name of Object.keys(vars)) {
21
+ const line = ` ${name}: ${vars[name]};`;
22
+ body = body === "" ? line : `${body}\n${line}`;
23
+ }
23
24
  return `:root {\n${body}\n}`;
24
25
  }
25
26
 
@@ -47,6 +48,8 @@ export interface ThemedConfig {
47
48
  const STORAGE_KEY = "praxis-theme";
48
49
  const BROADCAST_KEY = "praxis-theme";
49
50
 
51
+ const destroyed = new WeakSet<ThemeInstance>();
52
+
50
53
  // ─── ThemeInstance ────────────────────────────────────────────────────────────
51
54
 
52
55
  /**
@@ -68,10 +71,9 @@ export class ThemeInstance {
68
71
 
69
72
  const saved = this.#config.persist ? this.#loadFromStorage() : null;
70
73
 
71
- if (typeof document !== "undefined") {
72
- applyVarsToRoot(saved ?? instanceToVars(this.#current));
73
- if (this.#config.syncTabs) this.#setupBroadcast();
74
- }
74
+ // Also reaches an active collector when there is no document (server render).
75
+ applyVarsToRoot(saved ?? instanceToVars(this.#current));
76
+ if (this.#config.syncTabs && typeof document !== "undefined") this.#setupBroadcast();
75
77
  }
76
78
 
77
79
  /** The currently active theme instance. */
@@ -88,13 +90,14 @@ export class ThemeInstance {
88
90
  this.#current = new ThemeClass() as Record<string, unknown>;
89
91
  const vars = instanceToVars(this.#current);
90
92
 
91
- if (typeof document !== "undefined") applyVarsToRoot(vars);
93
+ applyVarsToRoot(vars);
92
94
  if (this.#config.persist) this.#saveToStorage(vars);
93
95
  if (this.#config.syncTabs) this.#channel?.postMessage({ vars });
94
96
  }
95
97
 
96
98
  /** Removes the injected `<style>` and closes the BroadcastChannel. */
97
99
  destroy(): void {
100
+ destroyed.add(this);
98
101
  this.#channel?.close();
99
102
  this.#channel = null;
100
103
  if (typeof document !== "undefined") {
@@ -133,10 +136,17 @@ export function createThemeInstance(
133
136
  DefaultTheme: new () => unknown,
134
137
  config?: Partial<ThemedConfig>,
135
138
  ): ThemeInstance {
139
+ // The replaced instance would otherwise keep its BroadcastChannel open for the page lifetime.
140
+ _instance?.destroy();
136
141
  _instance = new ThemeInstance(DefaultTheme, config);
137
142
  return _instance;
138
143
  }
139
144
 
145
+ /** Whether `instance` is the app-wide theme and has not been destroyed. */
146
+ export function isActiveTheme(instance: ThemeInstance | null): boolean {
147
+ return instance !== null && instance === _instance && !destroyed.has(instance);
148
+ }
149
+
140
150
  /**
141
151
  * Returns the app-wide {@link ThemeInstance}.
142
152
  * Throws if `@Themed()` has not been applied to the root component.
@@ -1,8 +1,4 @@
1
- // ─── camelCase → --kebab-case ─────────────────────────────────────────────────
2
-
3
- function camelToKebab(s: string): string {
4
- return s.replace(/([A-Z])/g, "-$1").toLowerCase();
5
- }
1
+ import { toKebab } from "../internal/kebab.js";
6
2
 
7
3
  // ─── Static props that must never be intercepted ──────────────────────────────
8
4
 
@@ -16,6 +12,9 @@ const SKIP = new Set([
16
12
 
17
13
  // ─── TokenSheet ───────────────────────────────────────────────────────────────
18
14
 
15
+ // Every static read of a token goes through the trap, so each name's reference is built once.
16
+ const refs = new Map<string, string>();
17
+
19
18
  // eslint-disable-next-line @typescript-eslint/no-extraneous-class
20
19
  const _Base = class {};
21
20
 
@@ -44,13 +43,14 @@ const _Base = class {};
44
43
  */
45
44
  export const TokenSheet = new Proxy(_Base, {
46
45
  get(target, prop, receiver) {
47
- if (
48
- typeof prop === "string" &&
49
- !SKIP.has(prop) &&
50
- !prop.startsWith("_") &&
51
- !prop.startsWith("$")
52
- ) {
53
- return `var(--${camelToKebab(prop)})`;
46
+ if (typeof prop === "string") {
47
+ const ref = refs.get(prop);
48
+ if (ref !== undefined) return ref;
49
+ if (!SKIP.has(prop) && !prop.startsWith("_") && !prop.startsWith("$")) {
50
+ const created = `var(--${toKebab(prop)})`;
51
+ refs.set(prop, created);
52
+ return created;
53
+ }
54
54
  }
55
55
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
56
56
  return Reflect.get(target, prop, receiver);
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=css-builder.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"css-builder.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/css-builder.test.ts"],"names":[],"mappings":""}
@@ -1,198 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { createCSSBuilder, isCSSBuilder } from "../builder/css-builder";
3
- describe("createCSSBuilder()", () => {
4
- it("serialises a flat property object to CSS declarations", () => {
5
- const css = createCSSBuilder({ display: "flex", gap: "12px", padding: "16px" });
6
- expect(String(css)).toBe("display: flex;\ngap: 12px;\npadding: 16px;");
7
- });
8
- it("converts camelCase properties to kebab-case", () => {
9
- const css = createCSSBuilder({ flexDirection: "column", borderRadius: "8px", fontSize: "1rem" });
10
- expect(String(css)).toContain("flex-direction: column;");
11
- expect(String(css)).toContain("border-radius: 8px;");
12
- expect(String(css)).toContain("font-size: 1rem;");
13
- });
14
- it("skips null and undefined values", () => {
15
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
- const css = createCSSBuilder({ display: "flex", color: undefined });
17
- expect(String(css)).toBe("display: flex;");
18
- });
19
- it("returns empty string when no properties are given", () => {
20
- expect(String(createCSSBuilder({}))).toBe("");
21
- });
22
- it("accepts CSS custom properties (--var)", () => {
23
- const css = createCSSBuilder({ "--accent": "#3b82f6" });
24
- expect(String(css)).toContain("--accent: #3b82f6;");
25
- });
26
- });
27
- describe("CSSBuilder — pseudo-state nesting", () => {
28
- it(".hover() adds &:hover block", () => {
29
- const css = createCSSBuilder({ display: "flex" }).hover({ opacity: 0.9 });
30
- const out = String(css);
31
- expect(out).toContain("display: flex;");
32
- expect(out).toContain("&:hover {");
33
- expect(out).toContain(" opacity: 0.9;");
34
- });
35
- it(".focus() adds &:focus block", () => {
36
- const out = String(createCSSBuilder({ color: "red" }).focus({ outline: "2px solid blue" }));
37
- expect(out).toContain("&:focus {");
38
- expect(out).toContain(" outline: 2px solid blue;");
39
- });
40
- it(".focusWithin() adds &:focus-within block", () => {
41
- expect(String(createCSSBuilder({}).focusWithin({ color: "red" }))).toContain("&:focus-within {");
42
- });
43
- it(".focusVisible() adds &:focus-visible block", () => {
44
- expect(String(createCSSBuilder({}).focusVisible({ outline: "none" }))).toContain("&:focus-visible {");
45
- });
46
- it(".active() adds &:active block", () => {
47
- expect(String(createCSSBuilder({}).active({ transform: "scale(0.98)" }))).toContain("&:active {");
48
- });
49
- it(".disabled() adds &:disabled + aria-disabled block", () => {
50
- const out = String(createCSSBuilder({}).disabled({ opacity: 0.4 }));
51
- expect(out).toContain("&:disabled");
52
- expect(out).toContain("aria-disabled");
53
- });
54
- it(".checked() adds &:checked block", () => {
55
- expect(String(createCSSBuilder({}).checked({ background: "blue" }))).toContain("&:checked {");
56
- });
57
- it(".placeholder() adds &::placeholder block", () => {
58
- expect(String(createCSSBuilder({}).placeholder({ color: "#999" }))).toContain("&::placeholder {");
59
- });
60
- it(".first() adds &:first-child block", () => {
61
- expect(String(createCSSBuilder({}).first({ marginTop: 0 }))).toContain("&:first-child {");
62
- });
63
- it(".last() adds &:last-child block", () => {
64
- expect(String(createCSSBuilder({}).last({ marginBottom: 0 }))).toContain("&:last-child {");
65
- });
66
- it(".nthChild() adds &:nth-child(n) block", () => {
67
- expect(String(createCSSBuilder({}).nthChild("2n+1", { background: "#f0f0f0" }))).toContain("&:nth-child(2n+1) {");
68
- });
69
- it(".not() adds &:not(selector) block", () => {
70
- expect(String(createCSSBuilder({}).not(".active", { opacity: 0.5 }))).toContain("&:not(.active) {");
71
- });
72
- });
73
- describe("CSSBuilder — at-rule nesting", () => {
74
- it(".media() adds @media (query) block", () => {
75
- const out = String(createCSSBuilder({ display: "flex" }).media("max-width: 640px", { flexDirection: "column" }));
76
- expect(out).toContain("@media (max-width: 640px) {");
77
- expect(out).toContain(" flex-direction: column;");
78
- });
79
- it(".container() adds @container (query) block", () => {
80
- const out = String(createCSSBuilder({}).container("min-width: 400px", { padding: "16px" }));
81
- expect(out).toContain("@container (min-width: 400px) {");
82
- });
83
- it(".on() adds any arbitrary selector or at-rule", () => {
84
- const out = String(createCSSBuilder({}).on("&::before", { content: '""', display: "block" }));
85
- expect(out).toContain("&::before {");
86
- expect(out).toContain(" content: \"\";");
87
- });
88
- });
89
- describe("CSSBuilder — chaining", () => {
90
- it("chains multiple nesting calls correctly", () => {
91
- const out = String(createCSSBuilder({ display: "flex" })
92
- .hover({ opacity: 0.9 })
93
- .focus({ outline: "2px solid blue" })
94
- .media("max-width: 640px", { flexDirection: "column" }));
95
- expect(out).toContain("display: flex;");
96
- expect(out).toContain("&:hover {");
97
- expect(out).toContain("&:focus {");
98
- expect(out).toContain("@media (max-width: 640px) {");
99
- });
100
- it("each chained call returns the same builder (fluent pattern)", () => {
101
- const b1 = createCSSBuilder({ display: "flex" });
102
- const b2 = b1.hover({ opacity: 0.9 });
103
- expect(b1).toBe(b2);
104
- });
105
- it("skips nested block when props are empty", () => {
106
- const out = String(createCSSBuilder({ display: "flex" }).hover({}));
107
- expect(out).not.toContain("&:hover");
108
- });
109
- });
110
- describe("CSSBuilder — pseudo-elements", () => {
111
- it(".before() adds &::before block", () => {
112
- expect(String(createCSSBuilder({}).before({ content: '""', display: "block" }))).toContain("&::before {");
113
- });
114
- it(".after() adds &::after block", () => {
115
- expect(String(createCSSBuilder({}).after({ content: '""' }))).toContain("&::after {");
116
- });
117
- it(".selection() adds &::selection block", () => {
118
- expect(String(createCSSBuilder({}).selection({ background: "blue" }))).toContain("&::selection {");
119
- });
120
- it(".firstLine() adds &::first-line block", () => {
121
- expect(String(createCSSBuilder({}).firstLine({ fontWeight: "bold" }))).toContain("&::first-line {");
122
- });
123
- it(".firstLetter() adds &::first-letter block", () => {
124
- expect(String(createCSSBuilder({}).firstLetter({ fontSize: "2em" }))).toContain("&::first-letter {");
125
- });
126
- it(".marker() adds &::marker block", () => {
127
- expect(String(createCSSBuilder({}).marker({ color: "red" }))).toContain("&::marker {");
128
- });
129
- it(".backdrop() adds &::backdrop block", () => {
130
- expect(String(createCSSBuilder({}).backdrop({ background: "rgba(0,0,0,0.5)" }))).toContain("&::backdrop {");
131
- });
132
- });
133
- describe("CSSBuilder — form pseudo-classes", () => {
134
- it(".enabled() adds &:enabled block", () => {
135
- expect(String(createCSSBuilder({}).enabled({ opacity: 1 }))).toContain("&:enabled {");
136
- });
137
- it(".indeterminate() adds &:indeterminate block", () => {
138
- expect(String(createCSSBuilder({}).indeterminate({ opacity: 0.5 }))).toContain("&:indeterminate {");
139
- });
140
- it(".required() adds &:required block", () => {
141
- expect(String(createCSSBuilder({}).required({ borderColor: "red" }))).toContain("&:required {");
142
- });
143
- it(".optional() adds &:optional block", () => {
144
- expect(String(createCSSBuilder({}).optional({ borderColor: "gray" }))).toContain("&:optional {");
145
- });
146
- it(".valid() adds &:valid block", () => {
147
- expect(String(createCSSBuilder({}).valid({ borderColor: "green" }))).toContain("&:valid {");
148
- });
149
- it(".invalid() adds &:invalid block", () => {
150
- expect(String(createCSSBuilder({}).invalid({ borderColor: "red" }))).toContain("&:invalid {");
151
- });
152
- it(".readOnly() adds &:read-only block", () => {
153
- expect(String(createCSSBuilder({}).readOnly({ opacity: 0.7 }))).toContain("&:read-only {");
154
- });
155
- it(".visited() adds &:visited block", () => {
156
- expect(String(createCSSBuilder({}).visited({ color: "purple" }))).toContain("&:visited {");
157
- });
158
- it(".target() adds &:target block", () => {
159
- expect(String(createCSSBuilder({}).target({ outline: "2px solid blue" }))).toContain("&:target {");
160
- });
161
- it(".empty() adds &:empty block", () => {
162
- expect(String(createCSSBuilder({}).empty({ display: "none" }))).toContain("&:empty {");
163
- });
164
- });
165
- describe("CSSBuilder — relational pseudo-classes", () => {
166
- it(".has() adds &:has(selector) block", () => {
167
- expect(String(createCSSBuilder({}).has(".active", { fontWeight: "bold" }))).toContain("&:has(.active) {");
168
- });
169
- it(".is() adds &:is(selector) block", () => {
170
- expect(String(createCSSBuilder({}).is("h1, h2", { lineHeight: 1.2 }))).toContain("&:is(h1, h2) {");
171
- });
172
- it(".where() adds &:where(selector) block", () => {
173
- expect(String(createCSSBuilder({}).where("a, button", { cursor: "pointer" }))).toContain("&:where(a, button) {");
174
- });
175
- });
176
- describe("CSSBuilder — @supports", () => {
177
- it(".supports() adds @supports (condition) block", () => {
178
- const out = String(createCSSBuilder({ display: "flex" }).supports("display: grid", { display: "grid" }));
179
- expect(out).toContain("@supports (display: grid) {");
180
- expect(out).toContain(" display: grid;");
181
- });
182
- });
183
- describe("isCSSBuilder()", () => {
184
- it("returns true for a CSSBuilder instance", () => {
185
- expect(isCSSBuilder(createCSSBuilder({ display: "flex" }))).toBe(true);
186
- });
187
- it("returns false for plain strings", () => {
188
- expect(isCSSBuilder("display: flex;")).toBe(false);
189
- });
190
- it("returns false for null and undefined", () => {
191
- expect(isCSSBuilder(null)).toBe(false);
192
- expect(isCSSBuilder(undefined)).toBe(false);
193
- });
194
- it("returns false for plain objects", () => {
195
- expect(isCSSBuilder({ display: "flex" })).toBe(false);
196
- });
197
- });
198
- //# sourceMappingURL=css-builder.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"css-builder.test.js","sourceRoot":"","sources":["../../src/__tests__/css-builder.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=cx.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cx.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cx.test.ts"],"names":[],"mappings":""}
@@ -1,47 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { cx } from "../cx";
3
- describe("cx()", () => {
4
- it("returns empty string with no args", () => {
5
- expect(cx()).toBe("");
6
- });
7
- it("handles plain strings", () => {
8
- expect(cx("a", "b", "c")).toBe("a b c");
9
- });
10
- it("filters falsy values", () => {
11
- expect(cx(null, undefined, false, "valid")).toBe("valid");
12
- });
13
- it("includes 0 as a string", () => {
14
- expect(cx(0)).toBe("0");
15
- });
16
- it("includes numeric class names", () => {
17
- expect(cx(1, 2)).toBe("1 2");
18
- });
19
- it("handles objects — includes truthy keys", () => {
20
- expect(cx({ active: true, disabled: false, loading: true })).toBe("active loading");
21
- });
22
- it("handles objects with zero values as falsy", () => {
23
- expect(cx({ a: 1, b: 0, c: "", d: null, e: "yes" })).toBe("a e");
24
- });
25
- it("handles arrays recursively", () => {
26
- expect(cx("a", ["b", false, "c"])).toBe("a b c");
27
- });
28
- it("handles deeply nested arrays", () => {
29
- expect(cx(["a", ["b", ["c"]]])).toBe("a b c");
30
- });
31
- it("combines strings, objects, and arrays", () => {
32
- expect(cx("base", { active: true, disabled: false }, ["extra"])).toBe("base active extra");
33
- });
34
- it("returns empty string for all-falsy input", () => {
35
- expect(cx(false, null, undefined, "")).toBe("");
36
- });
37
- it("skips empty result from all-falsy nested array", () => {
38
- // inner = cx(false, null) = "" → falsy → not pushed
39
- expect(cx("a", [false, null, undefined])).toBe("a");
40
- expect(cx([false, null])).toBe("");
41
- });
42
- it("ignores boolean true — not a string, number, array, or object", () => {
43
- // boolean true passes the !arg guard but hits the else-if(object) false branch
44
- expect(cx(true, "valid")).toBe("valid");
45
- });
46
- });
47
- //# sourceMappingURL=cx.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cx.test.js","sourceRoot":"","sources":["../../src/__tests__/cx.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=decorators.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"decorators.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/decorators.test.ts"],"names":[],"mappings":""}