@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.
- package/CHANGELOG.md +31 -0
- package/dist/builder/css-builder.d.ts.map +1 -1
- package/dist/builder/css-builder.js +68 -74
- package/dist/builder/css-builder.js.map +1 -1
- package/dist/builder/keyframes.d.ts +5 -0
- package/dist/builder/keyframes.d.ts.map +1 -1
- package/dist/builder/keyframes.js +12 -14
- package/dist/builder/keyframes.js.map +1 -1
- package/dist/cx.d.ts.map +1 -1
- package/dist/cx.js +23 -18
- package/dist/cx.js.map +1 -1
- package/dist/decorators/param.d.ts +1 -2
- package/dist/decorators/param.d.ts.map +1 -1
- package/dist/decorators/param.js +9 -17
- package/dist/decorators/param.js.map +1 -1
- package/dist/decorators/style.d.ts.map +1 -1
- package/dist/decorators/style.js +61 -33
- package/dist/decorators/style.js.map +1 -1
- package/dist/decorators/styled.d.ts.map +1 -1
- package/dist/decorators/styled.js +112 -95
- package/dist/decorators/styled.js.map +1 -1
- package/dist/extract.d.ts.map +1 -1
- package/dist/extract.js +19 -35
- package/dist/extract.js.map +1 -1
- package/dist/global.d.ts +3 -0
- package/dist/global.d.ts.map +1 -1
- package/dist/global.js +9 -4
- package/dist/global.js.map +1 -1
- package/dist/internal/kebab.d.ts +5 -0
- package/dist/internal/kebab.d.ts.map +1 -0
- package/dist/internal/kebab.js +23 -0
- package/dist/internal/kebab.js.map +1 -0
- package/dist/internal/lifecycle.d.ts +15 -0
- package/dist/internal/lifecycle.d.ts.map +1 -0
- package/dist/internal/lifecycle.js +16 -0
- package/dist/internal/lifecycle.js.map +1 -0
- package/dist/internal/registry.d.ts +5 -1
- package/dist/internal/registry.d.ts.map +1 -1
- package/dist/internal/registry.js +9 -23
- package/dist/internal/registry.js.map +1 -1
- package/dist/internal/sheet.d.ts +20 -0
- package/dist/internal/sheet.d.ts.map +1 -0
- package/dist/internal/sheet.js +56 -0
- package/dist/internal/sheet.js.map +1 -0
- package/dist/internal/static-mode.d.ts +2 -0
- package/dist/internal/static-mode.d.ts.map +1 -0
- package/dist/internal/static-mode.js +2 -0
- package/dist/internal/static-mode.js.map +1 -0
- package/dist/preflight.d.ts +3 -1
- package/dist/preflight.d.ts.map +1 -1
- package/dist/preflight.js +7 -3
- package/dist/preflight.js.map +1 -1
- package/dist/tokens/decorators.d.ts.map +1 -1
- package/dist/tokens/decorators.js +13 -4
- package/dist/tokens/decorators.js.map +1 -1
- package/dist/tokens/theme-instance.d.ts +5 -0
- package/dist/tokens/theme-instance.d.ts.map +1 -1
- package/dist/tokens/theme-instance.js +25 -17
- package/dist/tokens/theme-instance.js.map +1 -1
- package/dist/tokens/token-sheet.d.ts.map +1 -1
- package/dist/tokens/token-sheet.js +12 -9
- package/dist/tokens/token-sheet.js.map +1 -1
- package/package.json +13 -5
- package/src/builder/css-builder.ts +79 -83
- package/src/builder/keyframes.ts +12 -20
- package/src/cx.ts +20 -13
- package/src/decorators/param.ts +12 -16
- package/src/decorators/style.ts +79 -35
- package/src/decorators/styled.ts +127 -111
- package/src/extract.ts +18 -34
- package/src/global.ts +10 -9
- package/src/internal/kebab.ts +23 -0
- package/src/internal/lifecycle.ts +21 -0
- package/src/internal/registry.ts +9 -35
- package/src/internal/sheet.ts +71 -0
- package/src/internal/static-mode.ts +6 -0
- package/src/preflight.ts +8 -3
- package/src/tokens/decorators.ts +15 -3
- package/src/tokens/theme-instance.ts +26 -16
- package/src/tokens/token-sheet.ts +12 -12
- package/dist/__tests__/css-builder.test.d.ts +0 -2
- package/dist/__tests__/css-builder.test.d.ts.map +0 -1
- package/dist/__tests__/css-builder.test.js +0 -198
- package/dist/__tests__/css-builder.test.js.map +0 -1
- package/dist/__tests__/cx.test.d.ts +0 -2
- package/dist/__tests__/cx.test.d.ts.map +0 -1
- package/dist/__tests__/cx.test.js +0 -47
- package/dist/__tests__/cx.test.js.map +0 -1
- package/dist/__tests__/decorators.test.d.ts +0 -2
- package/dist/__tests__/decorators.test.d.ts.map +0 -1
- package/dist/__tests__/decorators.test.js +0 -264
- package/dist/__tests__/decorators.test.js.map +0 -1
- package/dist/__tests__/extract.test.d.ts +0 -2
- package/dist/__tests__/extract.test.d.ts.map +0 -1
- package/dist/__tests__/extract.test.js +0 -416
- package/dist/__tests__/extract.test.js.map +0 -1
- package/dist/__tests__/global.test.d.ts +0 -2
- package/dist/__tests__/global.test.d.ts.map +0 -1
- package/dist/__tests__/global.test.js +0 -136
- package/dist/__tests__/global.test.js.map +0 -1
- package/dist/__tests__/keyframes.test.d.ts +0 -2
- package/dist/__tests__/keyframes.test.d.ts.map +0 -1
- package/dist/__tests__/keyframes.test.js +0 -90
- package/dist/__tests__/keyframes.test.js.map +0 -1
- package/dist/__tests__/preflight.test.d.ts +0 -2
- package/dist/__tests__/preflight.test.d.ts.map +0 -1
- package/dist/__tests__/preflight.test.js +0 -74
- package/dist/__tests__/preflight.test.js.map +0 -1
- package/dist/__tests__/registry.test.d.ts +0 -2
- package/dist/__tests__/registry.test.d.ts.map +0 -1
- package/dist/__tests__/registry.test.js +0 -132
- package/dist/__tests__/registry.test.js.map +0 -1
- package/dist/__tests__/style.test.d.ts +0 -2
- package/dist/__tests__/style.test.d.ts.map +0 -1
- package/dist/__tests__/style.test.js +0 -281
- package/dist/__tests__/style.test.js.map +0 -1
- package/dist/__tests__/styled.test.d.ts +0 -2
- package/dist/__tests__/styled.test.d.ts.map +0 -1
- package/dist/__tests__/styled.test.js +0 -904
- package/dist/__tests__/styled.test.js.map +0 -1
- package/dist/__tests__/theme-instance.test.d.ts +0 -2
- package/dist/__tests__/theme-instance.test.d.ts.map +0 -1
- package/dist/__tests__/theme-instance.test.js +0 -309
- package/dist/__tests__/theme-instance.test.js.map +0 -1
- package/dist/__tests__/theme-uninit.test.d.ts +0 -2
- package/dist/__tests__/theme-uninit.test.d.ts.map +0 -1
- package/dist/__tests__/theme-uninit.test.js +0 -10
- package/dist/__tests__/theme-uninit.test.js.map +0 -1
- package/dist/__tests__/token-sheet.test.d.ts +0 -2
- package/dist/__tests__/token-sheet.test.d.ts.map +0 -1
- package/dist/__tests__/token-sheet.test.js +0 -74
- package/dist/__tests__/token-sheet.test.js.map +0 -1
- package/src/__tests__/css-builder.test.ts +0 -230
- package/src/__tests__/cx.test.ts +0 -63
- package/src/__tests__/decorators.test.ts +0 -127
- package/src/__tests__/extract.test.ts +0 -459
- package/src/__tests__/global.test.ts +0 -163
- package/src/__tests__/keyframes.test.ts +0 -103
- package/src/__tests__/preflight.test.ts +0 -85
- package/src/__tests__/registry.test.ts +0 -151
- package/src/__tests__/style.test.ts +0 -170
- package/src/__tests__/styled.test.ts +0 -443
- package/src/__tests__/theme-instance.test.ts +0 -374
- package/src/__tests__/theme-uninit.test.ts +0 -12
- package/src/__tests__/token-sheet.test.ts +0 -87
- package/tsconfig.json +0 -8
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { hashCSS } from "./hash.js";
|
|
2
|
+
import { isCSSBuilder } from "../builder/css-builder.js";
|
|
3
|
+
const PARAM_META = new WeakMap();
|
|
4
|
+
export function addParamName(ctor, name) {
|
|
5
|
+
let names = PARAM_META.get(ctor);
|
|
6
|
+
if (!names) {
|
|
7
|
+
names = new Set();
|
|
8
|
+
PARAM_META.set(ctor, names);
|
|
9
|
+
}
|
|
10
|
+
names.add(name);
|
|
11
|
+
}
|
|
12
|
+
export function getParamNames(ctor) {
|
|
13
|
+
return PARAM_META.get(ctor);
|
|
14
|
+
}
|
|
15
|
+
const cache = new WeakMap();
|
|
16
|
+
/**
|
|
17
|
+
* Builds the scoped class names and CSS of a `Stylesheet` subclass, once per class: constructing
|
|
18
|
+
* the template instance fires its `@Param()` initializers, which register the param names.
|
|
19
|
+
*/
|
|
20
|
+
export function compileSheet(SheetClass) {
|
|
21
|
+
const cached = cache.get(SheetClass);
|
|
22
|
+
if (cached)
|
|
23
|
+
return cached;
|
|
24
|
+
const template = new SheetClass();
|
|
25
|
+
const paramNames = getParamNames(SheetClass);
|
|
26
|
+
const classMap = {};
|
|
27
|
+
const params = [];
|
|
28
|
+
const defaults = [];
|
|
29
|
+
let css = "";
|
|
30
|
+
for (const key of Object.keys(template)) {
|
|
31
|
+
const value = template[key];
|
|
32
|
+
if (key.startsWith("$")) {
|
|
33
|
+
const rule = typeof value === "string" ? value : isCSSBuilder(value) ? String(value) : null;
|
|
34
|
+
if (rule === null)
|
|
35
|
+
continue;
|
|
36
|
+
const className = `prx-${key.slice(1).replace(/[^\w-]/g, "-")}-${hashCSS(rule)}`;
|
|
37
|
+
classMap[key] = className;
|
|
38
|
+
const block = `.${className} { ${rule.trim()} }`;
|
|
39
|
+
css = css === "" ? block : `${css}\n${block}`;
|
|
40
|
+
}
|
|
41
|
+
else if (paramNames?.has(key) && (typeof value === "string" || typeof value === "number")) {
|
|
42
|
+
params.push(key);
|
|
43
|
+
defaults.push(value);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const compiled = {
|
|
47
|
+
classMap: Object.freeze(classMap),
|
|
48
|
+
css,
|
|
49
|
+
key: css ? hashCSS(css) : "",
|
|
50
|
+
params,
|
|
51
|
+
defaults,
|
|
52
|
+
};
|
|
53
|
+
cache.set(SheetClass, compiled);
|
|
54
|
+
return compiled;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=sheet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sheet.js","sourceRoot":"","sources":["../../src/internal/sheet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-mode.d.ts","sourceRoot":"","sources":["../../src/internal/static-mode.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,EAAE,OAC6C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-mode.js","sourceRoot":"","sources":["../../src/internal/static-mode.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,WAAW,GACtB,OAAO,qBAAqB,KAAK,WAAW,IAAI,qBAAqB,CAAC"}
|
package/dist/preflight.d.ts
CHANGED
|
@@ -23,5 +23,7 @@ export interface PreflightOptions {
|
|
|
23
23
|
* import { preflight } from '@praxisjs/css'
|
|
24
24
|
* preflight()
|
|
25
25
|
*/
|
|
26
|
-
export declare function preflight(
|
|
26
|
+
export declare function preflight(options?: PreflightOptions): void;
|
|
27
|
+
/** The CSS `preflight()` injects — shared with build-time extraction. */
|
|
28
|
+
export declare function preflightCSS({ layer }?: PreflightOptions): string;
|
|
27
29
|
//# sourceMappingURL=preflight.d.ts.map
|
package/dist/preflight.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"AA6KA,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,EAAE,KAAe,EAAE,GAAE,gBAAqB,GAAG,
|
|
1
|
+
{"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"AA6KA,MAAM,WAAW,gBAAgB;IAC/B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAE1D;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,EAAE,KAAe,EAAE,GAAE,gBAAqB,GAAG,MAAM,CAE/E"}
|
package/dist/preflight.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { globalCSS, injectGlobalCSS } from "./global.js";
|
|
2
2
|
// Tailwind CSS preflight — https://github.com/tailwindlabs/tailwindcss/blob/main/packages/tailwindcss/preflight.css
|
|
3
3
|
// --theme() references stripped and replaced with their fallback values.
|
|
4
4
|
const PREFLIGHT = `
|
|
@@ -185,7 +185,11 @@ input:where([type='button'], [type='reset'], [type='submit']),
|
|
|
185
185
|
* import { preflight } from '@praxisjs/css'
|
|
186
186
|
* preflight()
|
|
187
187
|
*/
|
|
188
|
-
export function preflight(
|
|
189
|
-
|
|
188
|
+
export function preflight(options) {
|
|
189
|
+
injectGlobalCSS(preflightCSS(options));
|
|
190
|
+
}
|
|
191
|
+
/** The CSS `preflight()` injects — shared with build-time extraction. */
|
|
192
|
+
export function preflightCSS({ layer = "reset" } = {}) {
|
|
193
|
+
return globalCSS(() => PREFLIGHT, { layer });
|
|
190
194
|
}
|
|
191
195
|
//# sourceMappingURL=preflight.js.map
|
package/dist/preflight.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEzD,oHAAoH;AACpH,yEAAyE;AACzE,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuKjB,CAAC;AAYF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,SAAS,CAAC,OAA0B;IAClD,eAAe,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY,CAAC,EAAE,KAAK,GAAG,OAAO,KAAuB,EAAE;IACrE,OAAO,SAAS,CAAC,GAAG,EAAE,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/tokens/decorators.ts"],"names":[],"mappings":"AASA,OAAO,
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/tokens/decorators.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,EACL,aAAa,EACb,KAAK,YAAY,EAClB,MAAM,qBAAqB,CAAC;AAoC7B;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,MAAM,CACpB,SAAS,EAAE,QAAQ,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EACvD,YAAY,EAAE,UAAU,OAAO,EAC/B,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAE7B,GAAG,CAQL;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,KAAK,IAYF,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,CAAC,GAAG,CAAC,KAAK,IAAI,CACvF;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,CAAC"}
|
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
import { createClassDecorator, ClassBehavior, createFieldDecorator, } from "@praxisjs/decorators";
|
|
2
|
-
import { createThemeInstance, theme, ThemeInstance, } from "./theme-instance.js";
|
|
2
|
+
import { createThemeInstance, isActiveTheme, theme, ThemeInstance, } from "./theme-instance.js";
|
|
3
3
|
// ─── @Themed ─────────────────────────────────────────────────────────────────
|
|
4
|
+
const NO_ENHANCEMENT = Object.freeze({});
|
|
4
5
|
class ThemedBehavior extends ClassBehavior {
|
|
5
6
|
DefaultTheme;
|
|
6
7
|
config;
|
|
8
|
+
#instance = null;
|
|
7
9
|
constructor(DefaultTheme, config) {
|
|
8
10
|
super();
|
|
9
11
|
this.DefaultTheme = DefaultTheme;
|
|
10
12
|
this.config = config;
|
|
11
13
|
}
|
|
14
|
+
// Makes this class's theme the active one again, e.g. after another @Themed class replaced it
|
|
15
|
+
// or it was destroyed. While it is still active it is kept, so a theme the user switched to
|
|
16
|
+
// survives the component being instantiated again.
|
|
12
17
|
create(_instance) {
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
if (!isActiveTheme(this.#instance))
|
|
19
|
+
this.#activate();
|
|
20
|
+
return NO_ENHANCEMENT;
|
|
15
21
|
}
|
|
16
22
|
initialize(_Enhanced, _original) {
|
|
17
|
-
|
|
23
|
+
this.#activate();
|
|
24
|
+
}
|
|
25
|
+
#activate() {
|
|
26
|
+
this.#instance = createThemeInstance(this.DefaultTheme, this.config);
|
|
18
27
|
}
|
|
19
28
|
}
|
|
20
29
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../src/tokens/decorators.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,aAAa,EAEb,oBAAoB,GAErB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,mBAAmB,EACnB,KAAK,EACL,aAAa,GAEd,MAAM,qBAAqB,CAAC;AAE7B,gFAAgF;AAEhF,MAAM,cAAe,SAAQ,aAAa;
|
|
1
|
+
{"version":3,"file":"decorators.js","sourceRoot":"","sources":["../../src/tokens/decorators.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,aAAa,EAEb,oBAAoB,GAErB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,KAAK,EACL,aAAa,GAEd,MAAM,qBAAqB,CAAC;AAE7B,gFAAgF;AAEhF,MAAM,cAAc,GAAqB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAE3D,MAAM,cAAe,SAAQ,aAAa;IAIrB;IACA;IAJnB,SAAS,GAAyB,IAAI,CAAC;IAEvC,YACmB,YAA+B,EAC/B,MAA6B;QAE9C,KAAK,EAAE,CAAC;QAHS,iBAAY,GAAZ,YAAY,CAAmB;QAC/B,WAAM,GAAN,MAAM,CAAuB;IAGhD,CAAC;IAED,8FAA8F;IAC9F,4FAA4F;IAC5F,mDAAmD;IACnD,MAAM,CAAC,SAAwB;QAC7B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC;YAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QACrD,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,UAAU,CACR,SAA8C,EAC9C,SAA8C;QAE9C,IAAI,CAAC,SAAS,EAAE,CAAC;IACnB,CAAC;IAED,SAAS;QACP,IAAI,CAAC,SAAS,GAAG,mBAAmB,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACvE,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,MAAM,CACpB,SAAuD,EACvD,YAA+B,EAC/B,MAA8B;IAG9B,OAAO,oBAAoB,CACzB,IAAI,cAAc,CAAC,YAAY,EAAE,MAAM,IAAI,EAAE,CAAC,CAKvC,CAAC;AACZ,CAAC;AAED,iFAAiF;AAEjF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,KAAK;IACnB,OAAO,oBAAoB,CAAC;QAC1B,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,aAAa;YAClC,OAAO;gBACL,UAAU,EAAE;oBACV,GAAG,KAAoB,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC;oBACxC,gEAAgE;oBAChE,GAAG,KAAU,CAAC;iBACf;aACF,CAAC;QACJ,CAAC;QACD,8DAA8D;KAC/D,CAAqF,CAAC;AACzF,CAAC;AAED,OAAO,EAAE,KAAK,EAAE,aAAa,EAAqB,CAAC"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/** The `--token: value` pairs of a theme instance's string and number fields. */
|
|
2
|
+
export declare function instanceToVars(instance: Record<string, unknown>): Record<string, string>;
|
|
3
|
+
export declare function varsToCSS(vars: Record<string, string>): string;
|
|
1
4
|
export interface ThemedConfig {
|
|
2
5
|
persist: boolean;
|
|
3
6
|
syncTabs: boolean;
|
|
@@ -25,6 +28,8 @@ export declare class ThemeInstance {
|
|
|
25
28
|
destroy(): void;
|
|
26
29
|
}
|
|
27
30
|
export declare function createThemeInstance(DefaultTheme: new () => unknown, config?: Partial<ThemedConfig>): ThemeInstance;
|
|
31
|
+
/** Whether `instance` is the app-wide theme and has not been destroyed. */
|
|
32
|
+
export declare function isActiveTheme(instance: ThemeInstance | null): boolean;
|
|
28
33
|
/**
|
|
29
34
|
* Returns the app-wide {@link ThemeInstance}.
|
|
30
35
|
* Throws if `@Themed()` has not been applied to the root component.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-instance.d.ts","sourceRoot":"","sources":["../../src/tokens/theme-instance.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"theme-instance.d.ts","sourceRoot":"","sources":["../../src/tokens/theme-instance.ts"],"names":[],"mappings":"AAKA,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxF;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAO9D;AAkBD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAG,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AASD;;;;;;;GAOG;AACH,qBAAa,aAAa;;gBAKZ,YAAY,EAAE,UAAU,OAAO,EAAE,MAAM,GAAE,OAAO,CAAC,YAAY,CAAM;IAW/E,2CAA2C;IAC3C,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;OAIG;IACH,MAAM,CAAC,UAAU,EAAE,UAAU,OAAO,GAAG,IAAI;IAS3C,sEAAsE;IACtE,OAAO,IAAI,IAAI;CA8BhB;AAMD,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,UAAU,OAAO,EAC/B,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAC7B,aAAa,CAKf;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,GAAG,OAAO,CAErE;AAED;;;GAGG;AACH,wBAAgB,KAAK,IAAI,aAAa,CAKrC"}
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import { getCollector } from "../internal/collector.js";
|
|
2
|
+
import { toKebab } from "../internal/kebab.js";
|
|
2
3
|
// ─── helpers ──────────────────────────────────────────────────────────────────
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
function instanceToVars(instance) {
|
|
4
|
+
/** The `--token: value` pairs of a theme instance's string and number fields. */
|
|
5
|
+
export function instanceToVars(instance) {
|
|
7
6
|
const result = {};
|
|
8
|
-
for (const
|
|
7
|
+
for (const key of Object.keys(instance)) {
|
|
8
|
+
const val = instance[key];
|
|
9
9
|
if (typeof val === "string" || typeof val === "number") {
|
|
10
|
-
result[`--${
|
|
10
|
+
result[`--${toKebab(key)}`] = String(val);
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
return result;
|
|
14
14
|
}
|
|
15
|
-
function varsToCSS(vars) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
export function varsToCSS(vars) {
|
|
16
|
+
let body = "";
|
|
17
|
+
for (const name of Object.keys(vars)) {
|
|
18
|
+
const line = ` ${name}: ${vars[name]};`;
|
|
19
|
+
body = body === "" ? line : `${body}\n${line}`;
|
|
20
|
+
}
|
|
19
21
|
return `:root {\n${body}\n}`;
|
|
20
22
|
}
|
|
21
23
|
function applyVarsToRoot(vars) {
|
|
@@ -36,6 +38,7 @@ function applyVarsToRoot(vars) {
|
|
|
36
38
|
}
|
|
37
39
|
const STORAGE_KEY = "praxis-theme";
|
|
38
40
|
const BROADCAST_KEY = "praxis-theme";
|
|
41
|
+
const destroyed = new WeakSet();
|
|
39
42
|
// ─── ThemeInstance ────────────────────────────────────────────────────────────
|
|
40
43
|
/**
|
|
41
44
|
* Manages the active design token theme: injects CSS custom properties on
|
|
@@ -53,11 +56,10 @@ export class ThemeInstance {
|
|
|
53
56
|
this.#config = { persist: false, syncTabs: false, ...config };
|
|
54
57
|
this.#current = new DefaultTheme();
|
|
55
58
|
const saved = this.#config.persist ? this.#loadFromStorage() : null;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
59
|
+
// Also reaches an active collector when there is no document (server render).
|
|
60
|
+
applyVarsToRoot(saved ?? instanceToVars(this.#current));
|
|
61
|
+
if (this.#config.syncTabs && typeof document !== "undefined")
|
|
62
|
+
this.#setupBroadcast();
|
|
61
63
|
}
|
|
62
64
|
/** The currently active theme instance. */
|
|
63
65
|
get current() {
|
|
@@ -71,8 +73,7 @@ export class ThemeInstance {
|
|
|
71
73
|
switch(ThemeClass) {
|
|
72
74
|
this.#current = new ThemeClass();
|
|
73
75
|
const vars = instanceToVars(this.#current);
|
|
74
|
-
|
|
75
|
-
applyVarsToRoot(vars);
|
|
76
|
+
applyVarsToRoot(vars);
|
|
76
77
|
if (this.#config.persist)
|
|
77
78
|
this.#saveToStorage(vars);
|
|
78
79
|
if (this.#config.syncTabs)
|
|
@@ -80,6 +81,7 @@ export class ThemeInstance {
|
|
|
80
81
|
}
|
|
81
82
|
/** Removes the injected `<style>` and closes the BroadcastChannel. */
|
|
82
83
|
destroy() {
|
|
84
|
+
destroyed.add(this);
|
|
83
85
|
this.#channel?.close();
|
|
84
86
|
this.#channel = null;
|
|
85
87
|
if (typeof document !== "undefined") {
|
|
@@ -114,9 +116,15 @@ export class ThemeInstance {
|
|
|
114
116
|
// ─── Singleton ────────────────────────────────────────────────────────────────
|
|
115
117
|
let _instance = null;
|
|
116
118
|
export function createThemeInstance(DefaultTheme, config) {
|
|
119
|
+
// The replaced instance would otherwise keep its BroadcastChannel open for the page lifetime.
|
|
120
|
+
_instance?.destroy();
|
|
117
121
|
_instance = new ThemeInstance(DefaultTheme, config);
|
|
118
122
|
return _instance;
|
|
119
123
|
}
|
|
124
|
+
/** Whether `instance` is the app-wide theme and has not been destroyed. */
|
|
125
|
+
export function isActiveTheme(instance) {
|
|
126
|
+
return instance !== null && instance === _instance && !destroyed.has(instance);
|
|
127
|
+
}
|
|
120
128
|
/**
|
|
121
129
|
* Returns the app-wide {@link ThemeInstance}.
|
|
122
130
|
* Throws if `@Themed()` has not been applied to the root component.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-instance.js","sourceRoot":"","sources":["../../src/tokens/theme-instance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"theme-instance.js","sourceRoot":"","sources":["../../src/tokens/theme-instance.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-sheet.d.ts","sourceRoot":"","sources":["../../src/tokens/token-sheet.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"token-sheet.d.ts","sourceRoot":"","sources":["../../src/tokens/token-sheet.ts"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,UAAU,EAcN,QAAQ,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,MAAM,CAAC;AAI7D;;;;;;;;;;;;;;;GAeG;AACH,KAAK,WAAW,CAAC,CAAC,SAAS,QAAQ,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,IAAI;IACzE,QAAQ,EAAE,CAAC,IAAI,MAAM,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAAG,CAAC,GAAG,KAAK,GAAG,MAAM;CAC9E,CAAC;AAEF,wBAAgB,SAAS,CAAC,CAAC,SAAS,QAAQ,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAC9E,GAAG,EAAE,CAAC,GACL,WAAW,CAAC,CAAC,CAAC,CAEhB"}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
function camelToKebab(s) {
|
|
3
|
-
return s.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
4
|
-
}
|
|
1
|
+
import { toKebab } from "../internal/kebab.js";
|
|
5
2
|
// ─── Static props that must never be intercepted ──────────────────────────────
|
|
6
3
|
const SKIP = new Set([
|
|
7
4
|
"length", "name", "prototype", "constructor",
|
|
@@ -11,6 +8,8 @@ const SKIP = new Set([
|
|
|
11
8
|
"__esModule", "then", "catch", "finally",
|
|
12
9
|
]);
|
|
13
10
|
// ─── TokenSheet ───────────────────────────────────────────────────────────────
|
|
11
|
+
// Every static read of a token goes through the trap, so each name's reference is built once.
|
|
12
|
+
const refs = new Map();
|
|
14
13
|
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
|
15
14
|
const _Base = class {
|
|
16
15
|
};
|
|
@@ -39,11 +38,15 @@ const _Base = class {
|
|
|
39
38
|
*/
|
|
40
39
|
export const TokenSheet = new Proxy(_Base, {
|
|
41
40
|
get(target, prop, receiver) {
|
|
42
|
-
if (typeof prop === "string"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
if (typeof prop === "string") {
|
|
42
|
+
const ref = refs.get(prop);
|
|
43
|
+
if (ref !== undefined)
|
|
44
|
+
return ref;
|
|
45
|
+
if (!SKIP.has(prop) && !prop.startsWith("_") && !prop.startsWith("$")) {
|
|
46
|
+
const created = `var(--${toKebab(prop)})`;
|
|
47
|
+
refs.set(prop, created);
|
|
48
|
+
return created;
|
|
49
|
+
}
|
|
47
50
|
}
|
|
48
51
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
49
52
|
return Reflect.get(target, prop, receiver);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-sheet.js","sourceRoot":"","sources":["../../src/tokens/token-sheet.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"token-sheet.js","sourceRoot":"","sources":["../../src/tokens/token-sheet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAE/C,iFAAiF;AAEjF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa;IAC5C,UAAU,EAAE,SAAS,EAAE,gBAAgB;IACvC,gBAAgB,EAAE,eAAe,EAAE,sBAAsB;IACzD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW;IAC9C,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS;CACzC,CAAC,CAAC;AAEH,iFAAiF;AAEjF,8FAA8F;AAC9F,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;AAEvC,kEAAkE;AAClE,MAAM,KAAK,GAAG;CAAQ,CAAC;AAEvB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE;IACzC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ;QACxB,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC3B,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO,GAAG,CAAC;YAClC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtE,MAAM,OAAO,GAAG,SAAS,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;gBAC1C,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBACxB,OAAO,OAAO,CAAC;YACjB,CAAC;QACH,CAAC;QACD,+DAA+D;QAC/D,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC7C,CAAC;CACF,CAA2D,CAAC;AAwB7D,MAAM,UAAU,SAAS,CACvB,GAAM;IAEN,OAAO,GAAgC,CAAC;AAC1C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisjs/css",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -18,16 +18,24 @@
|
|
|
18
18
|
"types": "./dist/extract.d.ts"
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"src",
|
|
24
|
+
"!dist/**/__tests__",
|
|
25
|
+
"!src/**/__tests__",
|
|
26
|
+
"CHANGELOG.md"
|
|
27
|
+
],
|
|
21
28
|
"devDependencies": {
|
|
22
29
|
"typescript": "^6.0.3"
|
|
23
30
|
},
|
|
24
31
|
"dependencies": {
|
|
25
32
|
"csstype": "^3.2.3",
|
|
26
|
-
"@praxisjs/core": "2.
|
|
27
|
-
"@praxisjs/decorators": "
|
|
33
|
+
"@praxisjs/core": "^2.3.1",
|
|
34
|
+
"@praxisjs/decorators": "^2.0.1"
|
|
28
35
|
},
|
|
29
36
|
"scripts": {
|
|
30
|
-
"build": "tsc",
|
|
31
|
-
"dev": "tsc --watch"
|
|
37
|
+
"build": "tsc -p tsconfig.build.json",
|
|
38
|
+
"dev": "tsc -p tsconfig.build.json --watch",
|
|
39
|
+
"typecheck": "tsc --noEmit"
|
|
32
40
|
}
|
|
33
41
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { declarations } from "../internal/kebab.js";
|
|
2
|
+
|
|
1
3
|
import type { Properties } from "csstype";
|
|
2
4
|
|
|
3
5
|
// ─── CSSProperties ────────────────────────────────────────────────────────────
|
|
@@ -113,92 +115,86 @@ export type CSSBuilder = string & {
|
|
|
113
115
|
|
|
114
116
|
// ─── Runtime ──────────────────────────────────────────────────────────────────
|
|
115
117
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
118
|
+
type Props = CSSProperties;
|
|
119
|
+
|
|
120
|
+
// Every method lives once on the prototype: `this.css()` runs for each `$` field of every
|
|
121
|
+
// stylesheet, and a per-builder set of ~40 closures made each call allocate them all.
|
|
122
|
+
class CSSBuilderImpl {
|
|
123
|
+
readonly #parts: string[] = [];
|
|
124
|
+
|
|
125
|
+
constructor(props: Props) {
|
|
126
|
+
const root = declarations(props, "");
|
|
127
|
+
if (root) this.#parts.push(root);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#nest(selector: string, props: Props): this {
|
|
131
|
+
const css = declarations(props, "");
|
|
132
|
+
// Indents every line, including the continuation lines of a multi-line value.
|
|
133
|
+
if (css) this.#parts.push(`${selector} {\n ${css.replaceAll("\n", "\n ")}\n}`);
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
toString(): string {
|
|
138
|
+
return this.#parts.join("\n");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
[Symbol.toPrimitive](): string {
|
|
142
|
+
return this.toString();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Pseudo-classes — interaction
|
|
146
|
+
hover(p: Props): this { return this.#nest("&:hover", p); }
|
|
147
|
+
focus(p: Props): this { return this.#nest("&:focus", p); }
|
|
148
|
+
focusWithin(p: Props): this { return this.#nest("&:focus-within", p); }
|
|
149
|
+
focusVisible(p: Props): this { return this.#nest("&:focus-visible", p); }
|
|
150
|
+
active(p: Props): this { return this.#nest("&:active", p); }
|
|
151
|
+
visited(p: Props): this { return this.#nest("&:visited", p); }
|
|
152
|
+
target(p: Props): this { return this.#nest("&:target", p); }
|
|
153
|
+
|
|
154
|
+
// Pseudo-classes — form state
|
|
155
|
+
disabled(p: Props): this { return this.#nest('&:disabled, &[disabled], &[aria-disabled="true"]', p); }
|
|
156
|
+
enabled(p: Props): this { return this.#nest("&:enabled", p); }
|
|
157
|
+
checked(p: Props): this { return this.#nest("&:checked", p); }
|
|
158
|
+
indeterminate(p: Props): this { return this.#nest("&:indeterminate", p); }
|
|
159
|
+
required(p: Props): this { return this.#nest("&:required", p); }
|
|
160
|
+
optional(p: Props): this { return this.#nest("&:optional", p); }
|
|
161
|
+
valid(p: Props): this { return this.#nest("&:valid", p); }
|
|
162
|
+
invalid(p: Props): this { return this.#nest("&:invalid", p); }
|
|
163
|
+
readOnly(p: Props): this { return this.#nest("&:read-only", p); }
|
|
164
|
+
|
|
165
|
+
// Pseudo-classes — structural
|
|
166
|
+
first(p: Props): this { return this.#nest("&:first-child", p); }
|
|
167
|
+
last(p: Props): this { return this.#nest("&:last-child", p); }
|
|
168
|
+
nthChild(n: string | number, p: Props): this { return this.#nest(`&:nth-child(${String(n)})`, p); }
|
|
169
|
+
empty(p: Props): this { return this.#nest("&:empty", p); }
|
|
170
|
+
|
|
171
|
+
// Pseudo-classes — relational (Selectors Level 4)
|
|
172
|
+
has(sel: string, p: Props): this { return this.#nest(`&:has(${sel})`, p); }
|
|
173
|
+
is(sel: string, p: Props): this { return this.#nest(`&:is(${sel})`, p); }
|
|
174
|
+
where(sel: string, p: Props): this { return this.#nest(`&:where(${sel})`, p); }
|
|
175
|
+
not(sel: string, p: Props): this { return this.#nest(`&:not(${sel})`, p); }
|
|
176
|
+
|
|
177
|
+
// Pseudo-elements
|
|
178
|
+
before(p: Props): this { return this.#nest("&::before", p); }
|
|
179
|
+
after(p: Props): this { return this.#nest("&::after", p); }
|
|
180
|
+
placeholder(p: Props): this { return this.#nest("&::placeholder", p); }
|
|
181
|
+
selection(p: Props): this { return this.#nest("&::selection", p); }
|
|
182
|
+
firstLine(p: Props): this { return this.#nest("&::first-line", p); }
|
|
183
|
+
firstLetter(p: Props): this { return this.#nest("&::first-letter", p); }
|
|
184
|
+
marker(p: Props): this { return this.#nest("&::marker", p); }
|
|
185
|
+
backdrop(p: Props): this { return this.#nest("&::backdrop", p); }
|
|
186
|
+
|
|
187
|
+
// At-rules
|
|
188
|
+
media(q: string, p: Props): this { return this.#nest(`@media (${q})`, p); }
|
|
189
|
+
container(q: string, p: Props): this { return this.#nest(`@container (${q})`, p); }
|
|
190
|
+
supports(cond: string, p: Props): this { return this.#nest(`@supports (${cond})`, p); }
|
|
191
|
+
on(sel: string, p: Props): this { return this.#nest(sel, p); }
|
|
125
192
|
}
|
|
126
193
|
|
|
127
|
-
function
|
|
128
|
-
return
|
|
129
|
-
.filter(([, v]) => v != null)
|
|
130
|
-
.map(([k, v]) => `${toKebab(k)}: ${String(v)};`)
|
|
131
|
-
.join("\n");
|
|
194
|
+
export function isCSSBuilder(value: unknown): boolean {
|
|
195
|
+
return value instanceof CSSBuilderImpl;
|
|
132
196
|
}
|
|
133
197
|
|
|
134
198
|
export function createCSSBuilder(initialProps: CSSProperties): CSSBuilder {
|
|
135
|
-
|
|
136
|
-
const rootCSS = propsToCSS(initialProps);
|
|
137
|
-
if (rootCSS) parts.push(rootCSS);
|
|
138
|
-
|
|
139
|
-
const addNested = (selector: string, props: CSSProperties): CSSBuilder => {
|
|
140
|
-
const rawCSS = propsToCSS(props);
|
|
141
|
-
if (!rawCSS) return builder;
|
|
142
|
-
const inner = rawCSS.split("\n").map((l) => ` ${l}`).join("\n");
|
|
143
|
-
parts.push(`${selector} {\n${inner}\n}`);
|
|
144
|
-
return builder;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
const toCSS = (): string => parts.join("\n");
|
|
148
|
-
|
|
149
|
-
const builder = Object.assign(Object.create(null) as object, {
|
|
150
|
-
[CSS_BUILDER]: true,
|
|
151
|
-
toString: toCSS,
|
|
152
|
-
[Symbol.toPrimitive]: toCSS,
|
|
153
|
-
|
|
154
|
-
// Pseudo-classes — interaction
|
|
155
|
-
hover: (p: CSSProperties) => addNested("&:hover", p),
|
|
156
|
-
focus: (p: CSSProperties) => addNested("&:focus", p),
|
|
157
|
-
focusWithin: (p: CSSProperties) => addNested("&:focus-within", p),
|
|
158
|
-
focusVisible: (p: CSSProperties) => addNested("&:focus-visible", p),
|
|
159
|
-
active: (p: CSSProperties) => addNested("&:active", p),
|
|
160
|
-
visited: (p: CSSProperties) => addNested("&:visited", p),
|
|
161
|
-
target: (p: CSSProperties) => addNested("&:target", p),
|
|
162
|
-
|
|
163
|
-
// Pseudo-classes — form state
|
|
164
|
-
disabled: (p: CSSProperties) => addNested('&:disabled, &[disabled], &[aria-disabled="true"]', p),
|
|
165
|
-
enabled: (p: CSSProperties) => addNested("&:enabled", p),
|
|
166
|
-
checked: (p: CSSProperties) => addNested("&:checked", p),
|
|
167
|
-
indeterminate:(p: CSSProperties) => addNested("&:indeterminate", p),
|
|
168
|
-
required: (p: CSSProperties) => addNested("&:required", p),
|
|
169
|
-
optional: (p: CSSProperties) => addNested("&:optional", p),
|
|
170
|
-
valid: (p: CSSProperties) => addNested("&:valid", p),
|
|
171
|
-
invalid: (p: CSSProperties) => addNested("&:invalid", p),
|
|
172
|
-
readOnly: (p: CSSProperties) => addNested("&:read-only", p),
|
|
173
|
-
|
|
174
|
-
// Pseudo-classes — structural
|
|
175
|
-
first: (p: CSSProperties) => addNested("&:first-child", p),
|
|
176
|
-
last: (p: CSSProperties) => addNested("&:last-child", p),
|
|
177
|
-
nthChild: (n: string | number, p: CSSProperties) => addNested(`&:nth-child(${String(n)})`, p),
|
|
178
|
-
empty: (p: CSSProperties) => addNested("&:empty", p),
|
|
179
|
-
|
|
180
|
-
// Pseudo-classes — relational (Selectors Level 4)
|
|
181
|
-
has: (sel: string, p: CSSProperties) => addNested(`&:has(${sel})`, p),
|
|
182
|
-
is: (sel: string, p: CSSProperties) => addNested(`&:is(${sel})`, p),
|
|
183
|
-
where: (sel: string, p: CSSProperties) => addNested(`&:where(${sel})`, p),
|
|
184
|
-
not: (sel: string, p: CSSProperties) => addNested(`&:not(${sel})`, p),
|
|
185
|
-
|
|
186
|
-
// Pseudo-elements
|
|
187
|
-
before: (p: CSSProperties) => addNested("&::before", p),
|
|
188
|
-
after: (p: CSSProperties) => addNested("&::after", p),
|
|
189
|
-
placeholder: (p: CSSProperties) => addNested("&::placeholder", p),
|
|
190
|
-
selection: (p: CSSProperties) => addNested("&::selection", p),
|
|
191
|
-
firstLine: (p: CSSProperties) => addNested("&::first-line", p),
|
|
192
|
-
firstLetter: (p: CSSProperties) => addNested("&::first-letter", p),
|
|
193
|
-
marker: (p: CSSProperties) => addNested("&::marker", p),
|
|
194
|
-
backdrop: (p: CSSProperties) => addNested("&::backdrop", p),
|
|
195
|
-
|
|
196
|
-
// At-rules
|
|
197
|
-
media: (q: string, p: CSSProperties) => addNested(`@media (${q})`, p),
|
|
198
|
-
container: (q: string, p: CSSProperties) => addNested(`@container (${q})`, p),
|
|
199
|
-
supports: (cond: string, p: CSSProperties) => addNested(`@supports (${cond})`, p),
|
|
200
|
-
on: (sel: string, p: CSSProperties) => addNested(sel, p),
|
|
201
|
-
}) as unknown as CSSBuilder;
|
|
202
|
-
|
|
203
|
-
return builder;
|
|
199
|
+
return new CSSBuilderImpl(initialProps) as unknown as CSSBuilder;
|
|
204
200
|
}
|
package/src/builder/keyframes.ts
CHANGED
|
@@ -1,26 +1,23 @@
|
|
|
1
1
|
import { getCollector } from "../internal/collector.js";
|
|
2
2
|
import { hashCSS } from "../internal/hash.js";
|
|
3
|
+
import { declarations } from "../internal/kebab.js";
|
|
4
|
+
import { STATIC_MODE } from "../internal/static-mode.js";
|
|
3
5
|
|
|
4
6
|
import type { CSSProperties } from "./css-builder.js";
|
|
5
7
|
|
|
6
|
-
// Defined by the Vite CSS plugin — skip DOM injection when CSS is static.
|
|
7
|
-
declare const __PRAXIS_CSS_STATIC__: boolean | undefined;
|
|
8
|
-
const STATIC_MODE: boolean =
|
|
9
|
-
typeof __PRAXIS_CSS_STATIC__ !== "undefined" && __PRAXIS_CSS_STATIC__;
|
|
10
|
-
|
|
11
8
|
type KeyframeStops = Record<string, CSSProperties>;
|
|
12
9
|
|
|
13
10
|
const injected = new Set<string>();
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
/** The scoped name and `@keyframes` rule for a set of stops — shared with build-time extraction. */
|
|
13
|
+
export function keyframesRule(name: string, stops: KeyframeStops): { name: string; css: string } {
|
|
14
|
+
let body = "";
|
|
15
|
+
for (const stop in stops) {
|
|
16
|
+
const block = ` ${stop} {\n${declarations(stops[stop], " ")}\n }`;
|
|
17
|
+
body = body === "" ? block : `${body}\n${block}`;
|
|
18
|
+
}
|
|
19
|
+
const scopedName = `prx-${name}-${hashCSS(body)}`;
|
|
20
|
+
return { name: scopedName, css: `@keyframes ${scopedName} {\n${body}\n}` };
|
|
24
21
|
}
|
|
25
22
|
|
|
26
23
|
/**
|
|
@@ -42,12 +39,7 @@ function stopToCSS(props: CSSProperties): string {
|
|
|
42
39
|
* }
|
|
43
40
|
*/
|
|
44
41
|
export function keyframes(name: string, stops: KeyframeStops): string {
|
|
45
|
-
const
|
|
46
|
-
.map(([stop, props]) => ` ${stop} {\n${stopToCSS(props)}\n }`)
|
|
47
|
-
.join("\n");
|
|
48
|
-
|
|
49
|
-
const scopedName = `prx-${name}-${hashCSS(stopsCSS)}`;
|
|
50
|
-
const kfCSS = `@keyframes ${scopedName} {\n${stopsCSS}\n}`;
|
|
42
|
+
const { name: scopedName, css: kfCSS } = keyframesRule(name, stops);
|
|
51
43
|
|
|
52
44
|
if (STATIC_MODE) return scopedName;
|
|
53
45
|
|