@styleframe/transpiler 1.0.0

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 (57) hide show
  1. package/.tsbuildinfo +1 -0
  2. package/CHANGELOG.md +12 -0
  3. package/package.json +43 -0
  4. package/src/constants.ts +4 -0
  5. package/src/consume/at-rule.test.ts +339 -0
  6. package/src/consume/at-rule.ts +34 -0
  7. package/src/consume/consume.test.ts +259 -0
  8. package/src/consume/consume.ts +60 -0
  9. package/src/consume/container.test.ts +501 -0
  10. package/src/consume/container.ts +73 -0
  11. package/src/consume/css.test.ts +184 -0
  12. package/src/consume/css.ts +17 -0
  13. package/src/consume/declarations.test.ts +210 -0
  14. package/src/consume/declarations.ts +17 -0
  15. package/src/consume/index.ts +12 -0
  16. package/src/consume/primitive.test.ts +52 -0
  17. package/src/consume/primitive.ts +16 -0
  18. package/src/consume/ref.test.ts +84 -0
  19. package/src/consume/ref.ts +22 -0
  20. package/src/consume/root.test.ts +353 -0
  21. package/src/consume/root.ts +19 -0
  22. package/src/consume/selector.test.ts +441 -0
  23. package/src/consume/selector.ts +17 -0
  24. package/src/consume/theme.test.ts +215 -0
  25. package/src/consume/theme.ts +15 -0
  26. package/src/consume/utility.test.ts +696 -0
  27. package/src/consume/utility.ts +31 -0
  28. package/src/consume/variable.test.ts +197 -0
  29. package/src/consume/variable.ts +20 -0
  30. package/src/defaults.ts +21 -0
  31. package/src/generator/genAtRuleQuery.test.ts +148 -0
  32. package/src/generator/genAtRuleQuery.ts +3 -0
  33. package/src/generator/genDeclaration.test.ts +283 -0
  34. package/src/generator/genDeclaration.ts +9 -0
  35. package/src/generator/genDeclarationsBlock.test.ts +278 -0
  36. package/src/generator/genDeclarationsBlock.ts +7 -0
  37. package/src/generator/genDeclareVariable.test.ts +323 -0
  38. package/src/generator/genDeclareVariable.ts +6 -0
  39. package/src/generator/genInlineAtRule.test.ts +351 -0
  40. package/src/generator/genInlineAtRule.ts +5 -0
  41. package/src/generator/genReferenceVariable.test.ts +392 -0
  42. package/src/generator/genReferenceVariable.ts +5 -0
  43. package/src/generator/genSafePropertyName.test.ts +489 -0
  44. package/src/generator/genSafePropertyName.ts +5 -0
  45. package/src/generator/genSafeVariableName.test.ts +358 -0
  46. package/src/generator/genSafeVariableName.ts +21 -0
  47. package/src/generator/genSelector.test.ts +357 -0
  48. package/src/generator/genSelector.ts +5 -0
  49. package/src/generator/index.ts +9 -0
  50. package/src/index.ts +6 -0
  51. package/src/transpile.test.ts +825 -0
  52. package/src/transpile.ts +21 -0
  53. package/src/types.ts +15 -0
  54. package/src/utils.ts +18 -0
  55. package/src/vite-env.d.ts +1 -0
  56. package/tsconfig.json +7 -0
  57. package/vite.config.ts +5 -0
@@ -0,0 +1,184 @@
1
+ import type { Root, StyleframeOptions } from "@styleframe/core";
2
+ import {
3
+ createCssFunction,
4
+ createRefFunction,
5
+ createRoot,
6
+ createVariableFunction,
7
+ } from "@styleframe/core";
8
+ import { createCSSConsumer } from "./css";
9
+ import { consume } from "./consume";
10
+
11
+ describe("createCSSConsumer", () => {
12
+ let root: Root;
13
+ let css: ReturnType<typeof createCssFunction>;
14
+ let variable: ReturnType<typeof createVariableFunction>;
15
+ let ref: ReturnType<typeof createRefFunction>;
16
+
17
+ const consumeCSS = createCSSConsumer(consume);
18
+ const options: StyleframeOptions = {};
19
+
20
+ beforeEach(() => {
21
+ root = createRoot();
22
+ css = createCssFunction(root, root);
23
+ variable = createVariableFunction(root, root);
24
+ ref = createRefFunction(root, root);
25
+ });
26
+
27
+ it("should process a simple CSS value", () => {
28
+ const cssValue = css`16px`;
29
+ expect(consumeCSS(cssValue, options)).toBe("16px");
30
+ });
31
+
32
+ it("should handle CSS values with variable references", () => {
33
+ const spacingVar = variable("spacing-md", "1rem");
34
+ const paddingValue = css`
35
+ ${ref(spacingVar)} calc(${ref(spacingVar)} * 2)
36
+ `;
37
+
38
+ expect(consumeCSS(paddingValue, options)).toBe(
39
+ "var(--spacing-md) calc(var(--spacing-md) * 2)",
40
+ );
41
+ });
42
+
43
+ it("should handle empty CSS values", () => {
44
+ const emptyCss = css``;
45
+ expect(consumeCSS(emptyCss, options)).toBe("");
46
+ });
47
+
48
+ it("should respect prefix in options if provided", () => {
49
+ const prefixOptions: StyleframeOptions = {
50
+ variables: {
51
+ name: ({ name }) => `--sf-${name}`,
52
+ },
53
+ };
54
+
55
+ const colorVar = variable("color-primary", "#0066ff");
56
+ const colorValue = css`
57
+ ${ref(colorVar)}
58
+ `;
59
+
60
+ expect(consumeCSS(colorValue, prefixOptions)).toBe(
61
+ "var(--sf-color-primary)",
62
+ );
63
+ });
64
+
65
+ it("should handle CSS values with numeric interpolations", () => {
66
+ const zIndex = 100;
67
+ const zIndexValue = css`
68
+ ${zIndex}
69
+ `;
70
+
71
+ expect(consumeCSS(zIndexValue, options)).toBe("100");
72
+ });
73
+
74
+ it("should handle CSS values with string interpolations", () => {
75
+ const borderWidth = "2px";
76
+ const borderStyle = "solid";
77
+ const borderColor = "#000";
78
+ const borderValue = css`
79
+ ${borderWidth} ${borderStyle} ${borderColor}
80
+ `;
81
+
82
+ expect(consumeCSS(borderValue, options)).toBe("2px solid #000");
83
+ });
84
+
85
+ it("should handle CSS values with array interpolations", () => {
86
+ const gridAreas = ["header", "main", "footer"];
87
+ const gridTemplateValue = css`"${gridAreas[0]}" "${gridAreas[1]}" "${gridAreas[2]}"`;
88
+
89
+ expect(consumeCSS(gridTemplateValue, options)).toBe(
90
+ '"header" "main" "footer"',
91
+ );
92
+ });
93
+
94
+ it("should handle complex CSS values with multiple variable references", () => {
95
+ const fontSize = variable("font-size-base", "16px");
96
+ const lineHeight = variable("line-height-normal", "1.5");
97
+ const fontFamily = variable("font-family-sans", "system-ui, sans-serif");
98
+
99
+ const fontValue = css`
100
+ ${ref(fontSize)}/${ref(lineHeight)} ${ref(fontFamily)}
101
+ `;
102
+
103
+ expect(consumeCSS(fontValue, options)).toBe(
104
+ "var(--font-size-base)/var(--line-height-normal) var(--font-family-sans)",
105
+ );
106
+ });
107
+
108
+ it("should handle CSS values with calculations", () => {
109
+ const spacing = variable("spacing", "8px");
110
+ const calcValue = css`calc(100% - ${ref(spacing)} * 2)`;
111
+
112
+ expect(consumeCSS(calcValue, options)).toBe(
113
+ "calc(100% - var(--spacing) * 2)",
114
+ );
115
+ });
116
+
117
+ it("should handle CSS values with color functions", () => {
118
+ const primaryColor = variable("color-primary", "#006cff");
119
+ const colorValue = css`rgba(${ref(primaryColor)}, 0.5)`;
120
+
121
+ expect(consumeCSS(colorValue, options)).toBe(
122
+ "rgba(var(--color-primary), 0.5)",
123
+ );
124
+ });
125
+
126
+ it("should handle CSS values with gradient functions", () => {
127
+ const primaryColor = variable("color-primary", "#006cff");
128
+ const secondaryColor = variable("color-secondary", "#ff6b6b");
129
+
130
+ const gradientValue = css`linear-gradient(135deg, ${ref(primaryColor)} 0%, ${ref(secondaryColor)} 100%)`;
131
+
132
+ expect(consumeCSS(gradientValue, options)).toBe(
133
+ "linear-gradient(135deg, var(--color-primary) 0%, var(--color-secondary) 100%)",
134
+ );
135
+ });
136
+
137
+ it("should handle CSS values with conditional interpolations", () => {
138
+ const isLarge = true;
139
+ const conditionalValue = css`
140
+ ${isLarge ? "2rem" : "1rem"}
141
+ `;
142
+
143
+ expect(consumeCSS(conditionalValue, options)).toBe("2rem");
144
+ });
145
+
146
+ it("should handle CSS values with fallback references", () => {
147
+ const spacingValue = css`
148
+ ${ref("custom-spacing", "16px")}
149
+ `;
150
+
151
+ expect(consumeCSS(spacingValue, options)).toBe(
152
+ "var(--custom-spacing, 16px)",
153
+ );
154
+ });
155
+
156
+ it("should handle complex CSS values with multiple expressions", () => {
157
+ const primary = variable("color-primary", "#006cff");
158
+ const secondary = variable("color-secondary", "#ff6b6b");
159
+ const spacing = variable("spacing", "8px");
160
+
161
+ const complexValue = css`
162
+ ${ref(spacing)} solid ${ref(primary)},
163
+ calc(${ref(spacing)} * 2) dashed ${ref(secondary)}
164
+ `;
165
+
166
+ // The function might normalize whitespace
167
+ const result = consumeCSS(complexValue, options);
168
+ expect(result).toContain("var(--spacing) solid var(--color-primary)");
169
+ expect(result).toContain(
170
+ "calc(var(--spacing) * 2) dashed var(--color-secondary)",
171
+ );
172
+ });
173
+
174
+ it("should handle CSS values with nested expressions", () => {
175
+ const baseSize = variable("size-base", "16px");
176
+ const multiplier = 1.5;
177
+
178
+ const nestedValue = css`calc(${ref(baseSize)} * ${multiplier})`;
179
+
180
+ expect(consumeCSS(nestedValue, options)).toBe(
181
+ "calc(var(--size-base) * 1.5)",
182
+ );
183
+ });
184
+ });
@@ -0,0 +1,17 @@
1
+ import type { CSS, StyleframeOptions } from "@styleframe/core";
2
+ import type { ConsumeFunction } from "../types";
3
+
4
+ /**
5
+ * Consumes a CSS value, equivalent to the string body of a selector
6
+ */
7
+ export function createCSSConsumer(consume: ConsumeFunction) {
8
+ return function consumeCSS(
9
+ instance: CSS,
10
+ options: StyleframeOptions,
11
+ ): string {
12
+ return instance.value
13
+ .map((part) => consume(part, options))
14
+ .join("")
15
+ .trim();
16
+ };
17
+ }
@@ -0,0 +1,210 @@
1
+ import type { DeclarationsBlock, StyleframeOptions } from "@styleframe/core";
2
+ import {
3
+ createCssFunction,
4
+ createRefFunction,
5
+ createRoot,
6
+ createVariableFunction,
7
+ } from "@styleframe/core";
8
+ import { consume } from "./consume";
9
+ import { createDeclarationsConsumer } from "./declarations";
10
+
11
+ describe("createDeclarationsConsumer", () => {
12
+ let root: ReturnType<typeof createRoot>;
13
+ let ref: ReturnType<typeof createRefFunction>;
14
+ let variable: ReturnType<typeof createVariableFunction>;
15
+ let css: ReturnType<typeof createCssFunction>;
16
+
17
+ const consumeDeclarations = createDeclarationsConsumer(consume);
18
+ const options: StyleframeOptions = {};
19
+
20
+ beforeEach(() => {
21
+ root = createRoot();
22
+ ref = createRefFunction(root, root);
23
+ variable = createVariableFunction(root, root);
24
+ css = createCssFunction(root, root);
25
+ });
26
+
27
+ it("should convert a simple declarations block to CSS declarations", () => {
28
+ const declarations: DeclarationsBlock = {
29
+ color: "#ff0000",
30
+ fontSize: "16px",
31
+ margin: "10px",
32
+ };
33
+
34
+ const result = consumeDeclarations(declarations, options);
35
+
36
+ expect(result).toEqual([
37
+ "color: #ff0000;",
38
+ "font-size: 16px;",
39
+ "margin: 10px;",
40
+ ]);
41
+ });
42
+
43
+ it("should handle empty declarations block", () => {
44
+ const declarations: DeclarationsBlock = {};
45
+
46
+ const result = consumeDeclarations(declarations, options);
47
+
48
+ expect(result).toEqual([]);
49
+ });
50
+
51
+ it("should handle declarations with variable references", () => {
52
+ const colorVar = variable("color-primary", "#006cff");
53
+ const fontSizeVar = variable("font-size", "16px");
54
+
55
+ const declarations: DeclarationsBlock = {
56
+ color: ref(colorVar),
57
+ fontSize: ref(fontSizeVar),
58
+ };
59
+
60
+ const result = consumeDeclarations(declarations, options);
61
+
62
+ expect(result).toEqual([
63
+ "color: var(--color-primary);",
64
+ "font-size: var(--font-size);",
65
+ ]);
66
+ });
67
+
68
+ it("should handle declarations with string references", () => {
69
+ const declarations: DeclarationsBlock = {
70
+ color: ref("color-primary"),
71
+ fontSize: ref("font-size"),
72
+ };
73
+
74
+ const result = consumeDeclarations(declarations, options);
75
+
76
+ expect(result).toEqual([
77
+ "color: var(--color-primary);",
78
+ "font-size: var(--font-size);",
79
+ ]);
80
+ });
81
+
82
+ it("should handle declarations with references that have fallbacks", () => {
83
+ const declarations: DeclarationsBlock = {
84
+ color: ref("color-primary", "#006cff"),
85
+ fontSize: ref("font-size", "16px"),
86
+ };
87
+
88
+ const result = consumeDeclarations(declarations, options);
89
+
90
+ expect(result).toEqual([
91
+ "color: var(--color-primary, #006cff);",
92
+ "font-size: var(--font-size, 16px);",
93
+ ]);
94
+ });
95
+
96
+ it("should handle declarations with CSS values", () => {
97
+ const declarations: DeclarationsBlock = {
98
+ boxShadow: css`0 2px 4px rgba(0, 0, 0, 0.1)`,
99
+ transform: css`translate(10px, 20px)`,
100
+ };
101
+
102
+ const result = consumeDeclarations(declarations, options);
103
+
104
+ expect(result).toEqual([
105
+ "box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);",
106
+ "transform: translate(10px, 20px);",
107
+ ]);
108
+ });
109
+
110
+ it("should handle declarations with complex CSS values that include references", () => {
111
+ const spacingVar = variable("spacing", "8px");
112
+
113
+ const declarations: DeclarationsBlock = {
114
+ padding: css`
115
+ ${ref(spacingVar)} calc(${ref(spacingVar)} * 2)
116
+ `,
117
+ margin: css`
118
+ ${ref("margin", "10px")} auto
119
+ `,
120
+ };
121
+
122
+ const result = consumeDeclarations(declarations, options);
123
+
124
+ expect(result).toEqual([
125
+ "padding: var(--spacing) calc(var(--spacing) * 2);",
126
+ "margin: var(--margin, 10px) auto;",
127
+ ]);
128
+ });
129
+
130
+ it("should handle declarations with null or undefined values", () => {
131
+ const declarations: DeclarationsBlock = {
132
+ color: null,
133
+ fontSize: undefined,
134
+ };
135
+
136
+ const result = consumeDeclarations(declarations, options);
137
+
138
+ expect(result).toEqual(["color: ;", "font-size: ;"]);
139
+ });
140
+
141
+ it("should handle declarations with numeric values", () => {
142
+ const declarations: DeclarationsBlock = {
143
+ zIndex: 100,
144
+ opacity: 0.5,
145
+ flex: 1,
146
+ };
147
+
148
+ const result = consumeDeclarations(declarations, options);
149
+
150
+ expect(result).toEqual(["z-index: 100;", "opacity: 0.5;", "flex: 1;"]);
151
+ });
152
+
153
+ it("should respect variable prefix in options if provided", () => {
154
+ const prefixOptions: StyleframeOptions = {
155
+ variables: {
156
+ name: ({ name }) => `--sf-${name}`,
157
+ },
158
+ };
159
+
160
+ const colorVar = variable("color-primary", "#006cff");
161
+
162
+ const declarations: DeclarationsBlock = {
163
+ color: ref(colorVar),
164
+ backgroundColor: ref("color-secondary"),
165
+ };
166
+
167
+ const result = consumeDeclarations(declarations, prefixOptions);
168
+
169
+ expect(result).toEqual([
170
+ "color: var(--sf-color-primary);",
171
+ "background-color: var(--sf-color-secondary);",
172
+ ]);
173
+ });
174
+
175
+ it("should handle declarations with boolean values", () => {
176
+ const declarations: DeclarationsBlock = {
177
+ // These would be converted to strings in CSS
178
+ visible: true,
179
+ disabled: false,
180
+ };
181
+
182
+ const result = consumeDeclarations(declarations, options);
183
+
184
+ expect(result).toEqual(["visible: true;", "disabled: false;"]);
185
+ });
186
+
187
+ it("should handle declarations with array values", () => {
188
+ const declarations: DeclarationsBlock = {
189
+ fontFamily: ["Helvetica", "Arial", "sans-serif"],
190
+ };
191
+
192
+ const result = consumeDeclarations(declarations, options);
193
+
194
+ expect(result).toEqual(["font-family: Helvetica,Arial,sans-serif;"]);
195
+ });
196
+
197
+ it("should handle custom property names", () => {
198
+ const declarations: DeclarationsBlock = {
199
+ "--customProperty": "value",
200
+ "--another-custom": 42,
201
+ };
202
+
203
+ const result = consumeDeclarations(declarations, options);
204
+
205
+ expect(result).toEqual([
206
+ "--customProperty: value;",
207
+ "--another-custom: 42;",
208
+ ]);
209
+ });
210
+ });
@@ -0,0 +1,17 @@
1
+ import type { DeclarationsBlock, StyleframeOptions } from "@styleframe/core";
2
+ import { genDeclaration } from "../generator";
3
+ import type { ConsumeFunction } from "../types";
4
+
5
+ /**
6
+ * Consumes a declarations block, equivalent to setting CSS properties
7
+ */
8
+ export function createDeclarationsConsumer(consume: ConsumeFunction) {
9
+ return function consumeDeclarations(
10
+ instance: DeclarationsBlock,
11
+ options: StyleframeOptions,
12
+ ): string[] {
13
+ return Object.entries(instance).map(([propertyName, propertyValue]) => {
14
+ return genDeclaration(propertyName, consume(propertyValue, options));
15
+ });
16
+ };
17
+ }
@@ -0,0 +1,12 @@
1
+ export * from "./at-rule";
2
+ export * from "./consume";
3
+ export * from "./container";
4
+ export * from "./css";
5
+ export * from "./declarations";
6
+ export * from "./primitive";
7
+ export * from "./ref";
8
+ export * from "./root";
9
+ export * from "./selector";
10
+ export * from "./theme";
11
+ export * from "./utility";
12
+ export * from "./variable";
@@ -0,0 +1,52 @@
1
+ import type { StyleframeOptions } from "@styleframe/core";
2
+ import { createPrimitiveConsumer } from "./primitive";
3
+ import { consume } from "./consume";
4
+
5
+ describe("createPrimitiveConsumer", () => {
6
+ const consumePrimitive = createPrimitiveConsumer(consume);
7
+ const options: StyleframeOptions = {};
8
+
9
+ it("should return a string representation of a number", () => {
10
+ expect(consumePrimitive(42, options)).toBe("42");
11
+ });
12
+
13
+ it("should return a string representation of a string", () => {
14
+ expect(consumePrimitive("test", options)).toBe("test");
15
+ });
16
+
17
+ it("should return a string representation of a boolean", () => {
18
+ expect(consumePrimitive(true, options)).toBe("true");
19
+ expect(consumePrimitive(false, options)).toBe("false");
20
+ });
21
+
22
+ it("should return a string representation of zero", () => {
23
+ expect(consumePrimitive(0, options)).toBe("0");
24
+ });
25
+
26
+ it("should return a string representation of an empty string", () => {
27
+ expect(consumePrimitive("", options)).toBe("");
28
+ });
29
+
30
+ it("should return an empty string for null", () => {
31
+ expect(consumePrimitive(null, options)).toBe("");
32
+ });
33
+
34
+ it("should return an empty string for undefined", () => {
35
+ expect(consumePrimitive(undefined, options)).toBe("");
36
+ });
37
+
38
+ it("should convert objects to string representation", () => {
39
+ const obj = { a: 1, b: 2 };
40
+ expect(consumePrimitive(obj, options)).toBe("[object Object]");
41
+ });
42
+
43
+ it("should convert arrays to string representation", () => {
44
+ const arr = [1, 2, 3];
45
+ expect(consumePrimitive(arr, options)).toBe("1,2,3");
46
+ });
47
+
48
+ it("should handle special values like NaN and Infinity", () => {
49
+ expect(consumePrimitive(NaN, options)).toBe("NaN");
50
+ expect(consumePrimitive(Infinity, options)).toBe("Infinity");
51
+ });
52
+ });
@@ -0,0 +1,16 @@
1
+ import type { StyleframeOptions } from "@styleframe/core";
2
+ import type { ConsumeFunction } from "../types";
3
+
4
+ /**
5
+ * Consumes a primitive instance, equivalent to setting a CSS value
6
+ */
7
+ export function createPrimitiveConsumer(_consume: ConsumeFunction) {
8
+ return function consumePrimitive(
9
+ instance: unknown,
10
+ _options: StyleframeOptions,
11
+ ): string {
12
+ return instance !== undefined && instance !== null
13
+ ? `${instance as string}`
14
+ : "";
15
+ };
16
+ }
@@ -0,0 +1,84 @@
1
+ import type { Root, StyleframeOptions } from "@styleframe/core";
2
+ import {
3
+ createRefFunction,
4
+ createRoot,
5
+ createVariableFunction,
6
+ } from "@styleframe/core";
7
+ import { createRefConsumer } from "./ref";
8
+ import { consume } from "./consume";
9
+
10
+ describe("createRefConsumer", () => {
11
+ let root: Root;
12
+ let ref: ReturnType<typeof createRefFunction>;
13
+ let variable: ReturnType<typeof createVariableFunction>;
14
+
15
+ const consumeRef = createRefConsumer(consume);
16
+ const options: StyleframeOptions = {};
17
+
18
+ beforeEach(() => {
19
+ root = createRoot();
20
+ variable = createVariableFunction(root, root);
21
+ ref = createRefFunction(root, root);
22
+ });
23
+
24
+ it("should convert a simple reference to CSS var() syntax", () => {
25
+ const colorRef = ref("color-primary");
26
+ expect(consumeRef(colorRef, options)).toBe("var(--color-primary)");
27
+ });
28
+
29
+ it("should handle references created from variables", () => {
30
+ const colorVar = variable("color-primary", "#0066ff");
31
+ const colorRef = ref(colorVar);
32
+ expect(consumeRef(colorRef, options)).toBe("var(--color-primary)");
33
+ });
34
+
35
+ it("should include fallback value when provided", () => {
36
+ const sizeRef = ref("font-size", "16px");
37
+ expect(consumeRef(sizeRef, options)).toBe("var(--font-size, 16px)");
38
+ });
39
+
40
+ it("should handle references with dashes in the name", () => {
41
+ const spacingRef = ref("spacing--md");
42
+ expect(consumeRef(spacingRef, options)).toBe("var(--spacing--md)");
43
+ });
44
+
45
+ it("should not modify variable names", () => {
46
+ // Assuming the normalizeVariableName function is used internally
47
+ // and converts camelCase to kebab-case
48
+ const colorRef = ref("colorPrimary");
49
+ expect(consumeRef(colorRef, options)).toBe("var(--colorPrimary)");
50
+ });
51
+
52
+ it("should handle complex fallback values", () => {
53
+ const marginRef = ref("margin-x", "calc(2rem + 10px)");
54
+ expect(consumeRef(marginRef, options)).toBe(
55
+ "var(--margin-x, calc(2rem + 10px))",
56
+ );
57
+ });
58
+
59
+ it("should respect prefix in options if provided", () => {
60
+ const prefixOptions: StyleframeOptions = {
61
+ variables: {
62
+ name: ({ name }) => `--sf-${name}`,
63
+ },
64
+ };
65
+ const colorRef = ref("color-primary");
66
+ expect(consumeRef(colorRef, prefixOptions)).toBe("var(--sf-color-primary)");
67
+ });
68
+
69
+ it("should handle references with empty fallback values", () => {
70
+ const emptyRef = ref("empty-var", "");
71
+ expect(consumeRef(emptyRef, options)).toBe("var(--empty-var)");
72
+ });
73
+
74
+ it("should handle references with undefined fallback", () => {
75
+ const undefinedRef = ref("undefined-var", undefined);
76
+ expect(consumeRef(undefinedRef, options)).toBe("var(--undefined-var)");
77
+ });
78
+
79
+ it("should handle references with null fallback value", () => {
80
+ // @ts-expect-error Passing null for testing purposes
81
+ const nullRef = ref("null-var", null);
82
+ expect(consumeRef(nullRef, options)).toBe("var(--null-var)");
83
+ });
84
+ });
@@ -0,0 +1,22 @@
1
+ import type { Reference, StyleframeOptions } from "@styleframe/core";
2
+ import { defaultVariableNameFn } from "../defaults";
3
+ import { genReferenceVariable } from "../generator";
4
+ import type { ConsumeFunction } from "../types";
5
+
6
+ /**
7
+ * Consumes a ref instance, equivalent to referencing a CSS variable with optional fallback
8
+ */
9
+ export function createRefConsumer(consume: ConsumeFunction) {
10
+ return function consumeRef(
11
+ instance: Reference,
12
+ options: StyleframeOptions,
13
+ ): string {
14
+ const variableNameFn = options.variables?.name ?? defaultVariableNameFn;
15
+ const variableName = variableNameFn({ name: instance.name });
16
+
17
+ return genReferenceVariable(
18
+ variableName,
19
+ instance.fallback ? consume(instance.fallback, options) : undefined,
20
+ );
21
+ };
22
+ }