@styleframe/core 1.0.0 → 1.0.2

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 (48) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -0
  3. package/dist/styleframe.d.ts +301 -0
  4. package/dist/styleframe.js +528 -0
  5. package/dist/styleframe.umd.cjs +1 -0
  6. package/package.json +13 -3
  7. package/.tsbuildinfo +0 -1
  8. package/src/index.ts +0 -5
  9. package/src/styleframe.ts +0 -64
  10. package/src/tokens/atRule.test.ts +0 -1013
  11. package/src/tokens/atRule.ts +0 -67
  12. package/src/tokens/css.test.ts +0 -404
  13. package/src/tokens/css.ts +0 -23
  14. package/src/tokens/declarations.test.ts +0 -584
  15. package/src/tokens/declarations.ts +0 -71
  16. package/src/tokens/index.ts +0 -11
  17. package/src/tokens/modifier.test.ts +0 -90
  18. package/src/tokens/modifier.ts +0 -86
  19. package/src/tokens/recipe.test.ts +0 -105
  20. package/src/tokens/recipe.ts +0 -32
  21. package/src/tokens/ref.test.ts +0 -430
  22. package/src/tokens/ref.ts +0 -24
  23. package/src/tokens/root.test.ts +0 -70
  24. package/src/tokens/root.ts +0 -14
  25. package/src/tokens/selector.test.ts +0 -440
  26. package/src/tokens/selector.ts +0 -47
  27. package/src/tokens/theme.test.ts +0 -338
  28. package/src/tokens/theme.ts +0 -26
  29. package/src/tokens/utility.test.ts +0 -1456
  30. package/src/tokens/utility.ts +0 -92
  31. package/src/tokens/variable.test.ts +0 -235
  32. package/src/tokens/variable.ts +0 -42
  33. package/src/typeGuards.test.ts +0 -33
  34. package/src/typeGuards.ts +0 -98
  35. package/src/types/declarations.ts +0 -42
  36. package/src/types/index.ts +0 -3
  37. package/src/types/options.ts +0 -22
  38. package/src/types/tokens.ts +0 -149
  39. package/src/utils/capitalizeFirst.ts +0 -9
  40. package/src/utils/deepClone.ts +0 -317
  41. package/src/utils/getters.test.ts +0 -399
  42. package/src/utils/getters.ts +0 -36
  43. package/src/utils/index.ts +0 -4
  44. package/src/utils/merge.test.ts +0 -978
  45. package/src/utils/merge.ts +0 -73
  46. package/src/vite-env.d.ts +0 -1
  47. package/tsconfig.json +0 -7
  48. package/vite.config.ts +0 -5
@@ -1,90 +0,0 @@
1
- import { combineKeys } from "./modifier";
2
-
3
- describe("combineKeys", () => {
4
- it("returns empty array for empty input", () => {
5
- expect(combineKeys([])).toEqual([]);
6
- });
7
-
8
- it("handles a single string", () => {
9
- expect(combineKeys([["hover"]])).toEqual([["hover"]]);
10
- });
11
-
12
- it("combines two strings and sorts combinations by length then alphabetically", () => {
13
- const result = combineKeys([["hover"], ["focus"]]);
14
- expect(result).toEqual([["focus"], ["hover"], ["focus", "hover"]]);
15
- });
16
-
17
- it("combines a string with an array, without combining elements within the array", () => {
18
- const result = combineKeys([["hover"], ["sm", "md"]]);
19
- expect(result).toEqual([
20
- // singles (alphabetical)
21
- ["hover"],
22
- ["md"],
23
- ["sm"],
24
- // pairs (alphabetical within and across combinations)
25
- ["hover", "md"],
26
- ["hover", "sm"],
27
- ]);
28
- });
29
-
30
- it("combines two arrays, choosing at most one element from each", () => {
31
- const result = combineKeys([
32
- ["sm", "md"],
33
- ["active", "hover"],
34
- ]);
35
- expect(result).toEqual([
36
- // singles (alphabetical)
37
- ["active"],
38
- ["hover"],
39
- ["md"],
40
- ["sm"],
41
- // pairs (cross-product, alphabetical within and across)
42
- ["active", "md"],
43
- ["active", "sm"],
44
- ["hover", "md"],
45
- ["hover", "sm"],
46
- ]);
47
- });
48
-
49
- it("does not combine elements within the same array when only one array is provided", () => {
50
- const result = combineKeys([["a", "b", "c"]]);
51
- expect(result).toEqual([["a"], ["b"], ["c"]]);
52
- });
53
-
54
- it("generates combinations across three groups and maintains order and uniqueness", () => {
55
- const result = combineKeys([["focus"], ["sm", "md"], ["hover", "active"]]);
56
-
57
- // Expect exact ordering: first by length, then alphabetical within each length
58
- expect(result).toEqual([
59
- // singles
60
- ["active"],
61
- ["focus"],
62
- ["hover"],
63
- ["md"],
64
- ["sm"],
65
- // pairs
66
- ["active", "focus"],
67
- ["active", "md"],
68
- ["active", "sm"],
69
- ["focus", "hover"],
70
- ["focus", "md"],
71
- ["focus", "sm"],
72
- ["hover", "md"],
73
- ["hover", "sm"],
74
- // triples
75
- ["active", "focus", "md"],
76
- ["active", "focus", "sm"],
77
- ["focus", "hover", "md"],
78
- ["focus", "hover", "sm"],
79
- ]);
80
-
81
- // Assert no duplicates present (defensive check)
82
- const unique = new Set(result.map((r) => r.join(",")));
83
- expect(unique.size).toBe(result.length);
84
- });
85
-
86
- it("sorts elements within each combination alphabetically", () => {
87
- const result = combineKeys([["b"], ["a"]]);
88
- expect(result).toEqual([["a"], ["b"], ["a", "b"]]);
89
- });
90
- });
@@ -1,86 +0,0 @@
1
- import type { Container, ModifierFactory, Root } from "../types";
2
- import { deepClone } from "../utils";
3
- import {
4
- createDeclarationsCallbackContext,
5
- parseDeclarationsBlock,
6
- } from "./declarations";
7
-
8
- export function combineKeys(groups: string[][]): string[][] {
9
- const result: string[][] = [];
10
-
11
- // Generate all combinations using recursive approach
12
- function generateCombinations(groupIndex: number, current: string[]) {
13
- // Add current combination if not empty
14
- if (current.length > 0) {
15
- result.push([...current].sort());
16
- }
17
-
18
- // Try adding elements from remaining groups
19
- for (let i = groupIndex; i < groups.length; i++) {
20
- const group = groups[i];
21
-
22
- if (group) {
23
- if (group.length === 1 && !!group[0]) {
24
- // Single element (originally a string) - can always add
25
- generateCombinations(i + 1, [...current, group[0]]);
26
- } else {
27
- // Array group - add at most one element
28
- for (const element of group) {
29
- generateCombinations(i + 1, [...current, element]);
30
- }
31
- }
32
- }
33
- }
34
- }
35
-
36
- generateCombinations(0, []);
37
-
38
- // Sort result: first by length, then alphabetically
39
- return result.sort((a, b) => {
40
- if (a.length !== b.length) return a.length - b.length;
41
- return a.join(",").localeCompare(b.join(","));
42
- });
43
- }
44
-
45
- export function applyModifiers<InstanceType extends Container>(
46
- baseInstance: InstanceType,
47
- root: Root,
48
- modifiers: Map<string, ModifierFactory>,
49
- ): InstanceType {
50
- const instance: InstanceType = {
51
- ...baseInstance,
52
- modifiers: [...modifiers.keys()],
53
- };
54
-
55
- const callbackContext = createDeclarationsCallbackContext(instance, root);
56
-
57
- for (const modifier of modifiers.values()) {
58
- modifier.factory({
59
- ...callbackContext,
60
- declarations: deepClone(instance.declarations),
61
- variables: deepClone(instance.variables),
62
- children: deepClone(instance.children),
63
- });
64
-
65
- parseDeclarationsBlock(instance.declarations, callbackContext);
66
- }
67
-
68
- return instance;
69
- }
70
-
71
- export function createModifierFunction(_parent: Container, root: Root) {
72
- return function modifier<Key extends string>(
73
- key: Key | Key[],
74
- factory: ModifierFactory["factory"],
75
- ): ModifierFactory {
76
- const modifierInstance: ModifierFactory = {
77
- type: "modifier",
78
- key: Array.isArray(key) ? key : [key],
79
- factory,
80
- };
81
-
82
- root.modifiers.push(modifierInstance);
83
-
84
- return modifierInstance;
85
- };
86
- }
@@ -1,105 +0,0 @@
1
- import { beforeEach, describe, expect, test } from "vitest";
2
- import type { Root } from "../types";
3
- import { createRecipeFunction } from "./recipe";
4
- import { createRoot } from "./root";
5
-
6
- describe("createRecipeFunction", () => {
7
- let root: Root;
8
- let recipe: ReturnType<typeof createRecipeFunction>;
9
-
10
- beforeEach(() => {
11
- root = createRoot();
12
- recipe = createRecipeFunction(root, root);
13
- });
14
-
15
- test("should create a recipe function", () => {
16
- expect(recipe).toBeTypeOf("function");
17
- });
18
-
19
- test("should register recipe in root.recipes only", () => {
20
- const instance = recipe(
21
- "button",
22
- { borderWidth: "thin", borderStyle: "solid" },
23
- {
24
- color: {
25
- primary: { background: "primary", color: "white" },
26
- secondary: { background: "secondary", color: "white" },
27
- },
28
- size: {
29
- sm: { padding: "sm" },
30
- md: { padding: "md" },
31
- lg: { padding: "lg" },
32
- },
33
- },
34
- );
35
-
36
- expect(instance).toEqual({
37
- type: "recipe",
38
- name: "button",
39
- defaults: { borderWidth: "thin", borderStyle: "solid" },
40
- variants: {
41
- color: {
42
- primary: { background: "primary", color: "white" },
43
- secondary: { background: "secondary", color: "white" },
44
- },
45
- size: {
46
- sm: { padding: "sm" },
47
- md: { padding: "md" },
48
- lg: { padding: "lg" },
49
- },
50
- },
51
- });
52
-
53
- expect(root.recipes).toHaveLength(1);
54
- expect(root.recipes[0]).toBe(instance);
55
-
56
- // Ensure no selectors/variables were created
57
- expect(root.children).toHaveLength(0);
58
- });
59
-
60
- test("should support options: defaultVariants and compoundVariants", () => {
61
- const instance = recipe(
62
- "chip",
63
- { borderWidth: "thin" },
64
- {
65
- variant: {
66
- filled: { background: "primary", color: "white" },
67
- outline: { background: "transparent", color: "primary" },
68
- },
69
- size: {
70
- sm: { padding: "sm" },
71
- md: { padding: "md" },
72
- },
73
- },
74
- {
75
- defaultVariants: { variant: "filled", size: "sm" },
76
- compoundVariants: [
77
- {
78
- variant: "filled",
79
- size: "sm",
80
- declarations: { background: "primary", color: "white" },
81
- },
82
- ],
83
- },
84
- );
85
-
86
- expect(instance.defaultVariants).toEqual({
87
- variant: "filled",
88
- size: "sm",
89
- });
90
- expect(instance.compoundVariants?.length).toBe(1);
91
- expect(instance.compoundVariants).toEqual([
92
- {
93
- variant: "filled",
94
- size: "sm",
95
- declarations: { background: "primary", color: "white" },
96
- },
97
- ]);
98
- });
99
-
100
- test("should maintain type information for recipe name", () => {
101
- const instance = recipe("typed-recipe", {}, {});
102
- const name: "typed-recipe" = instance.name;
103
- expect(name).toBe("typed-recipe");
104
- });
105
- });
@@ -1,32 +0,0 @@
1
- import type {
2
- Container,
3
- Recipe,
4
- Root,
5
- VariantDeclarationsBlock,
6
- } from "../types";
7
-
8
- export function createRecipeFunction(_parent: Container, root: Root) {
9
- return function recipe<
10
- Name extends string,
11
- Variants extends Record<string, Record<string, VariantDeclarationsBlock>>,
12
- >(
13
- name: Name,
14
- defaults: Recipe<Name, Variants>["defaults"],
15
- variants: Recipe<Name, Variants>["variants"],
16
- options?: {
17
- defaultVariants?: Recipe<Name, Variants>["defaultVariants"];
18
- compoundVariants?: Recipe<Name, Variants>["compoundVariants"];
19
- },
20
- ): Recipe<Name, Variants> {
21
- const instance: Recipe<Name, Variants> = {
22
- type: "recipe",
23
- name,
24
- defaults,
25
- variants,
26
- ...options,
27
- };
28
-
29
- root.recipes.push(instance);
30
- return instance;
31
- };
32
- }