@gtkx/css 0.18.1 → 0.18.3

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/dist/cache.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  import type { EmotionCache } from "@emotion/cache";
2
2
  export declare const getGtkCache: () => EmotionCache;
3
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAMnD,eAAO,MAAM,WAAW,QAAO,YAa9B,CAAC"}
package/dist/cache.js CHANGED
@@ -12,3 +12,4 @@ export const getGtkCache = () => {
12
12
  }
13
13
  return gtkCache;
14
14
  };
15
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AACA,OAAO,WAAW,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,IAAI,QAAQ,GAAwB,IAAI,CAAC;AAEzC,MAAM,CAAC,MAAM,WAAW,GAAG,GAAiB,EAAE;IAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAE9C,QAAQ,GAAG,WAAW,CAAC;YACnB,GAAG,EAAE,MAAM;YACX,SAAS,EAAE,IAAI;SAClB,CAAC,CAAC;QAEH,QAAQ,CAAC,KAAK,GAAG,KAAyC,CAAC;IAC/D,CAAC;IAED,OAAO,QAAQ,CAAC;AACpB,CAAC,CAAC"}
package/dist/css.d.ts CHANGED
@@ -91,3 +91,4 @@ export declare const cx: (...classNames: (string | boolean | undefined | null)[]
91
91
  */
92
92
  export declare const injectGlobal: (...args: CSSInterpolation[]) => void;
93
93
  export {};
94
+ //# sourceMappingURL=css.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAI3D;;GAEG;AACH,KAAK,YAAY,GAAG,MAAM,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,CAAC;AA6ChD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,GAAG,GAAI,GAAG,MAAM,gBAAgB,EAAE,KAAG,YAcjD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,EAAE,GAAI,GAAG,YAAY,CAAC,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,KAAG,MAAM,EACE,CAAC;AAErF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,YAAY,GAAI,GAAG,MAAM,gBAAgB,EAAE,KAAG,IAQ1D,CAAC"}
package/dist/css.js CHANGED
@@ -142,3 +142,4 @@ export const injectGlobal = (...args) => {
142
142
  cache.inserted[`global-${serialized.name}`] = serialized.styles;
143
143
  }
144
144
  };
145
+ //# sourceMappingURL=css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css.js","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { css, cx, injectGlobal } from "./css.js";
2
2
  import "./style-sheet.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { css, cx, injectGlobal } from "./css.js";
2
2
  import "./style-sheet.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,kBAAkB,CAAC"}
@@ -23,3 +23,4 @@ export declare class StyleSheet {
23
23
  hydrate(_elements: unknown[]): void;
24
24
  }
25
25
  export {};
26
+ //# sourceMappingURL=style-sheet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-sheet.d.ts","sourceRoot":"","sources":["../src/style-sheet.ts"],"names":[],"mappings":"AAIA,KAAK,iBAAiB,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAqBF,qBAAa,UAAU;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,eAAe,CAAS;gBAEpB,OAAO,EAAE,iBAAiB;IAItC,OAAO,CAAC,cAAc;IAgBtB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,cAAc;IAUtB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAW1B,gBAAgB,IAAI,IAAI;IAQxB,KAAK,IAAI,IAAI;IAab,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,IAAI;CACtC"}
@@ -82,3 +82,4 @@ export class StyleSheet {
82
82
  }
83
83
  hydrate(_elements) { }
84
84
  }
85
+ //# sourceMappingURL=style-sheet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"style-sheet.js","sourceRoot":"","sources":["../src/style-sheet.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gtkx/css",
3
- "version": "0.18.1",
3
+ "version": "0.18.3",
4
4
  "description": "Emotion-based CSS-in-JS for GTKX applications",
5
5
  "keywords": [
6
6
  "gtkx",
@@ -33,16 +33,20 @@
33
33
  "default": "./dist/index.js"
34
34
  }
35
35
  },
36
+ "sideEffects": [
37
+ "./dist/index.js"
38
+ ],
36
39
  "files": [
37
- "dist"
40
+ "dist",
41
+ "src"
38
42
  ],
39
43
  "dependencies": {
40
44
  "@emotion/cache": "^11.14.0",
41
45
  "@emotion/serialize": "^1.3.3",
42
- "@gtkx/ffi": "0.18.1"
46
+ "@gtkx/ffi": "0.18.3"
43
47
  },
44
48
  "devDependencies": {
45
- "@gtkx/vitest": "0.18.1"
49
+ "@gtkx/vitest": "0.18.3"
46
50
  },
47
51
  "scripts": {
48
52
  "build": "tsc -b && cp ../../README.md .",
package/src/cache.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { EmotionCache } from "@emotion/cache";
2
+ import createCache from "@emotion/cache";
3
+ import { StyleSheet } from "./style-sheet.js";
4
+
5
+ let gtkCache: EmotionCache | null = null;
6
+
7
+ export const getGtkCache = (): EmotionCache => {
8
+ if (!gtkCache) {
9
+ const sheet = new StyleSheet({ key: "gtkx" });
10
+
11
+ gtkCache = createCache({
12
+ key: "gtkx",
13
+ container: null,
14
+ });
15
+
16
+ gtkCache.sheet = sheet as unknown as typeof gtkCache.sheet;
17
+ }
18
+
19
+ return gtkCache;
20
+ };
package/src/css.ts ADDED
@@ -0,0 +1,162 @@
1
+ import type { CSSInterpolation } from "@emotion/serialize";
2
+ import { serializeStyles } from "@emotion/serialize";
3
+ import { getGtkCache } from "./cache.js";
4
+
5
+ /**
6
+ * Branded type for CSS class names generated by {@link css}.
7
+ */
8
+ type CSSClassName = string & { __brand: "css" };
9
+
10
+ function expandNestedRules(styles: string, className: string): string {
11
+ const selector = `.${className}`;
12
+ const expandedStyles = styles.replace(/&/g, selector);
13
+
14
+ const rules: string[] = [];
15
+ let topLevelProperties = "";
16
+ let currentSegment = "";
17
+ let braceDepth = 0;
18
+
19
+ for (let i = 0; i < expandedStyles.length; i++) {
20
+ const char = expandedStyles[i];
21
+
22
+ if (char === "{") {
23
+ currentSegment += char;
24
+ braceDepth++;
25
+ } else if (char === "}") {
26
+ braceDepth--;
27
+ currentSegment += char;
28
+ if (braceDepth === 0) {
29
+ rules.push(currentSegment.trim());
30
+ currentSegment = "";
31
+ }
32
+ } else if (char === ";" && braceDepth === 0) {
33
+ topLevelProperties += currentSegment + char;
34
+ currentSegment = "";
35
+ } else {
36
+ currentSegment += char;
37
+ }
38
+ }
39
+
40
+ if (currentSegment.trim() && braceDepth === 0) {
41
+ topLevelProperties += currentSegment;
42
+ }
43
+
44
+ const allRules: string[] = [];
45
+ if (topLevelProperties.trim()) {
46
+ allRules.push(`${selector}{${topLevelProperties.trim()}}`);
47
+ }
48
+ allRules.push(...rules);
49
+
50
+ return allRules.join("\n");
51
+ }
52
+
53
+ /**
54
+ * Creates a CSS class from style definitions.
55
+ *
56
+ * Uses Emotion's CSS-in-JS system adapted for GTK CSS. Supports nested selectors
57
+ * using `&` for the parent selector reference.
58
+ *
59
+ * @param args - CSS style definitions (objects, template literals, or interpolations)
60
+ * @returns A unique class name to use with `cssClasses` prop
61
+ *
62
+ * @example
63
+ * ```tsx
64
+ * import { css } from "@gtkx/css";
65
+ *
66
+ * const buttonStyle = css({
67
+ * padding: "8px 16px",
68
+ * borderRadius: "4px",
69
+ * "&:hover": {
70
+ * backgroundColor: "@accent_bg_color",
71
+ * },
72
+ * });
73
+ *
74
+ * <GtkButton cssClasses={[buttonStyle]} label="Styled Button" />
75
+ * ```
76
+ *
77
+ * @example
78
+ * ```tsx
79
+ * // Template literal syntax
80
+ * const labelStyle = css`
81
+ * font-size: 14px;
82
+ * color: @theme_text_color;
83
+ * `;
84
+ * ```
85
+ *
86
+ * @see {@link cx} for combining class names
87
+ * @see {@link injectGlobal} for global styles
88
+ */
89
+ export const css = (...args: CSSInterpolation[]): CSSClassName => {
90
+ const cache = getGtkCache();
91
+ const serialized = serializeStyles(args, cache.registered);
92
+
93
+ const className = `${cache.key}-${serialized.name}`;
94
+
95
+ if (cache.inserted[serialized.name] === undefined) {
96
+ const cssRule = expandNestedRules(serialized.styles, className);
97
+ cache.sheet.insert(cssRule);
98
+ cache.inserted[serialized.name] = serialized.styles;
99
+ cache.registered[className] = serialized.styles;
100
+ }
101
+
102
+ return className as CSSClassName;
103
+ };
104
+
105
+ /**
106
+ * Combines multiple class names into an array for use with cssClasses prop.
107
+ *
108
+ * Filters out falsy values, allowing conditional class application.
109
+ *
110
+ * @param classNames - Class names, booleans, undefined, or null values
111
+ * @returns Array of valid class names
112
+ *
113
+ * @example
114
+ * ```tsx
115
+ * import { css, cx } from "@gtkx/css";
116
+ *
117
+ * const base = css({ padding: "8px" });
118
+ * const active = css({ backgroundColor: "@accent_bg_color" });
119
+ *
120
+ * <GtkButton
121
+ * cssClasses={cx(base, isActive && active, "custom-class")}
122
+ * label="Button"
123
+ * />
124
+ * ```
125
+ */
126
+ export const cx = (...classNames: (string | boolean | undefined | null)[]): string[] =>
127
+ classNames.filter((cn): cn is string => typeof cn === "string" && cn.length > 0);
128
+
129
+ /**
130
+ * Injects global CSS styles without a wrapping class.
131
+ *
132
+ * Use for application-wide styles, CSS variables, or styling native GTK widgets.
133
+ *
134
+ * @param args - CSS style definitions
135
+ *
136
+ * @example
137
+ * ```tsx
138
+ * import { injectGlobal } from "@gtkx/css";
139
+ *
140
+ * injectGlobal`
141
+ * window {
142
+ * background-color: @theme_bg_color;
143
+ * }
144
+ *
145
+ * .title-1 {
146
+ * font-size: 24px;
147
+ * font-weight: bold;
148
+ * }
149
+ * `;
150
+ * ```
151
+ *
152
+ * @see {@link css} for scoped class-based styles
153
+ */
154
+ export const injectGlobal = (...args: CSSInterpolation[]): void => {
155
+ const cache = getGtkCache();
156
+ const serialized = serializeStyles(args, cache.registered);
157
+
158
+ if (cache.inserted[`global-${serialized.name}`] === undefined) {
159
+ cache.sheet.insert(serialized.styles);
160
+ cache.inserted[`global-${serialized.name}`] = serialized.styles;
161
+ }
162
+ };
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { css, cx, injectGlobal } from "./css.js";
2
+
3
+ import "./style-sheet.js";
@@ -0,0 +1,111 @@
1
+ import { events, isStarted } from "@gtkx/ffi";
2
+ import * as Gdk from "@gtkx/ffi/gdk";
3
+ import * as Gtk from "@gtkx/ffi/gtk";
4
+
5
+ type StyleSheetOptions = {
6
+ key: string;
7
+ container?: unknown;
8
+ nonce?: string;
9
+ speedy?: boolean;
10
+ prepend?: boolean;
11
+ };
12
+
13
+ const STYLE_PROVIDER_PRIORITY_APPLICATION = 600;
14
+
15
+ const pendingSheets: StyleSheet[] = [];
16
+
17
+ const flushPendingStyles = (): void => {
18
+ for (const sheet of pendingSheets) {
19
+ sheet.applyQueuedRules();
20
+ }
21
+ pendingSheets.length = 0;
22
+ };
23
+
24
+ const registerStartListener = (): void => {
25
+ events.once("start", flushPendingStyles);
26
+ };
27
+
28
+ if (!isStarted()) {
29
+ registerStartListener();
30
+ }
31
+
32
+ export class StyleSheet {
33
+ key: string;
34
+ private rules: string[] = [];
35
+ private provider: Gtk.CssProvider | null = null;
36
+ private display: Gdk.Display | null = null;
37
+ private isRegistered = false;
38
+ private hasPendingRules = false;
39
+ private updateScheduled = false;
40
+
41
+ constructor(options: StyleSheetOptions) {
42
+ this.key = options.key;
43
+ }
44
+
45
+ private ensureProvider(): void {
46
+ if (!this.provider) {
47
+ this.provider = new Gtk.CssProvider();
48
+ this.display = Gdk.DisplayManager.get().getDefaultDisplay();
49
+
50
+ if (this.display) {
51
+ Gtk.StyleContext.addProviderForDisplay(
52
+ this.display,
53
+ this.provider,
54
+ STYLE_PROVIDER_PRIORITY_APPLICATION,
55
+ );
56
+ this.isRegistered = true;
57
+ }
58
+ }
59
+ }
60
+
61
+ private updateProvider(): void {
62
+ if (this.provider && this.rules.length > 0) {
63
+ const css = this.rules.join("\n");
64
+ this.provider.loadFromString(css);
65
+ }
66
+ }
67
+
68
+ private scheduleUpdate(): void {
69
+ if (this.updateScheduled) return;
70
+ this.updateScheduled = true;
71
+ queueMicrotask(() => {
72
+ this.updateScheduled = false;
73
+ this.ensureProvider();
74
+ this.updateProvider();
75
+ });
76
+ }
77
+
78
+ insert(rule: string): void {
79
+ this.rules.push(rule);
80
+
81
+ if (isStarted()) {
82
+ this.scheduleUpdate();
83
+ } else if (!this.hasPendingRules) {
84
+ this.hasPendingRules = true;
85
+ pendingSheets.push(this);
86
+ }
87
+ }
88
+
89
+ applyQueuedRules(): void {
90
+ if (this.rules.length > 0) {
91
+ this.ensureProvider();
92
+ this.updateProvider();
93
+ }
94
+ this.hasPendingRules = false;
95
+ }
96
+
97
+ flush(): void {
98
+ if (this.provider && this.display && this.isRegistered) {
99
+ Gtk.StyleContext.removeProviderForDisplay(this.display, this.provider);
100
+ this.isRegistered = false;
101
+ }
102
+
103
+ this.rules = [];
104
+ this.provider = null;
105
+ this.display = null;
106
+ this.hasPendingRules = false;
107
+ this.updateScheduled = false;
108
+ }
109
+
110
+ hydrate(_elements: unknown[]): void {}
111
+ }