@pyreon/coolgrid 0.11.0 → 0.11.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.
@@ -0,0 +1,49 @@
1
+ import { describe, expect, it } from "vitest"
2
+ import { getContainerWidth } from "../Container/utils"
3
+
4
+ describe("Container/utils – getContainerWidth", () => {
5
+ it("returns width from props when present", () => {
6
+ const result = getContainerWidth({ width: 960 }, {})
7
+ expect(result).toBe(960)
8
+ })
9
+
10
+ it("prefers props.width over theme.grid.container", () => {
11
+ const result = getContainerWidth(
12
+ { width: 800 },
13
+ { grid: { container: { xs: "100%", md: 720 } } },
14
+ )
15
+ expect(result).toBe(800)
16
+ })
17
+
18
+ it("falls back to theme.grid.container", () => {
19
+ const result = getContainerWidth({}, { grid: { container: { xs: "100%", md: 720 } } })
20
+ expect(result).toEqual({ xs: "100%", md: 720 })
21
+ })
22
+
23
+ it("falls back to theme.coolgrid.container when grid is missing", () => {
24
+ const result = getContainerWidth({}, { coolgrid: { container: { xs: "100%", lg: 960 } } })
25
+ expect(result).toEqual({ xs: "100%", lg: 960 })
26
+ })
27
+
28
+ it("returns undefined/falsy when nothing matches", () => {
29
+ expect(getContainerWidth({}, {})).toBeFalsy()
30
+ })
31
+
32
+ it("returns undefined/falsy when both are undefined", () => {
33
+ expect(getContainerWidth(undefined, undefined)).toBeFalsy()
34
+ })
35
+
36
+ it("returns undefined/falsy when both are empty objects", () => {
37
+ expect(getContainerWidth({}, {})).toBeFalsy()
38
+ })
39
+
40
+ it("returns string width from props", () => {
41
+ const result = getContainerWidth({ width: "100%" }, {})
42
+ expect(result).toBe("100%")
43
+ })
44
+
45
+ it("returns responsive object from props", () => {
46
+ const result = getContainerWidth({ width: { xs: "100%", md: 720, lg: 960 } }, {})
47
+ expect(result).toEqual({ xs: "100%", md: 720, lg: 960 })
48
+ })
49
+ })
@@ -0,0 +1,147 @@
1
+ import type { VNode } from "@pyreon/core"
2
+ import { beforeEach, describe, expect, it, vi } from "vitest"
3
+
4
+ const mockProvide = vi.fn()
5
+ const mockUseContext = vi.fn()
6
+
7
+ vi.mock("@pyreon/core", async (importOriginal) => {
8
+ const original = await importOriginal<typeof import("@pyreon/core")>()
9
+ return {
10
+ ...original,
11
+ provide: (...args: any[]) => {
12
+ mockProvide(...args)
13
+ },
14
+ useContext: (ctx: any) => {
15
+ if (mockUseContext.mock.calls.length > 0) {
16
+ return mockUseContext(ctx)
17
+ }
18
+ return original.useContext(ctx)
19
+ },
20
+ }
21
+ })
22
+
23
+ const asVNode = (v: unknown) => v as VNode
24
+
25
+ describe("Container", () => {
26
+ beforeEach(() => {
27
+ vi.clearAllMocks()
28
+ // unistyle context returns empty theme
29
+ mockUseContext.mockReturnValue({ theme: {} })
30
+ })
31
+
32
+ it("returns a VNode", async () => {
33
+ const Container = (await import("../Container")).default
34
+ const result = asVNode(Container({ children: "test" }))
35
+ expect(result).toBeDefined()
36
+ expect(result.type).toBeDefined()
37
+ })
38
+
39
+ it("has correct displayName", async () => {
40
+ const Container = (await import("../Container")).default
41
+ expect(Container.displayName).toBe("@pyreon/coolgrid/Container")
42
+ })
43
+
44
+ it("has correct pkgName", async () => {
45
+ const Container = (await import("../Container")).default
46
+ expect(Container.pkgName).toBe("@pyreon/coolgrid")
47
+ })
48
+
49
+ it("has PYREON__COMPONENT static", async () => {
50
+ const Container = (await import("../Container")).default
51
+ expect(Container.PYREON__COMPONENT).toBe("@pyreon/coolgrid/Container")
52
+ })
53
+
54
+ it("passes $coolgrid prop with width and extraStyles", async () => {
55
+ const Container = (await import("../Container")).default
56
+ const result = asVNode(Container({ children: "test" }))
57
+ expect(result.props).toHaveProperty("$coolgrid")
58
+ expect(result.props.$coolgrid).toHaveProperty("width")
59
+ })
60
+
61
+ it("provides ContainerContext", async () => {
62
+ const Container = (await import("../Container")).default
63
+ Container({ columns: 12, gap: 16, children: "test" })
64
+ expect(mockProvide).toHaveBeenCalledTimes(1)
65
+ })
66
+
67
+ it("provides context with grid values", async () => {
68
+ const Container = (await import("../Container")).default
69
+ Container({ columns: 24, gap: 16, gutter: 8, children: "test" })
70
+ const config = mockProvide.mock.calls[0]?.[1] as Record<string, unknown>
71
+ expect(config.columns).toBe(24)
72
+ expect(config.gap).toBe(16)
73
+ expect(config.gutter).toBe(8)
74
+ })
75
+
76
+ it("uses width prop to override containerWidth", async () => {
77
+ const Container = (await import("../Container")).default
78
+ const result = asVNode(Container({ width: 960, children: "test" }))
79
+ expect((result.props.$coolgrid as Record<string, unknown>).width).toBe(960)
80
+ })
81
+
82
+ it("accepts width as function", async () => {
83
+ const Container = (await import("../Container")).default
84
+ const widthFn = (_containerWidth: any) => 800
85
+ const result = asVNode(Container({ width: widthFn as any, children: "test" }))
86
+ expect((result.props.$coolgrid as Record<string, unknown>).width).toBe(800)
87
+ })
88
+
89
+ it("strips context keys from DOM props", async () => {
90
+ const Container = (await import("../Container")).default
91
+ const result = asVNode(
92
+ Container({
93
+ columns: 12,
94
+ gap: 16,
95
+ "data-testid": "container",
96
+ children: "test",
97
+ }),
98
+ )
99
+ expect(result.props["data-testid"]).toBe("container")
100
+ })
101
+
102
+ it("passes css as extraStyles in $coolgrid", async () => {
103
+ const Container = (await import("../Container")).default
104
+ const customCss = "background: red;"
105
+ const result = asVNode(Container({ css: customCss, children: "test" }))
106
+ expect((result.props.$coolgrid as Record<string, unknown>).extraStyles).toBe(customCss)
107
+ })
108
+
109
+ it("provides context with all grid keys", async () => {
110
+ const Container = (await import("../Container")).default
111
+ Container({
112
+ columns: 12,
113
+ gap: 16,
114
+ gutter: 8,
115
+ padding: 4,
116
+ size: 6,
117
+ contentAlignX: "center",
118
+ children: "test",
119
+ })
120
+ const config = mockProvide.mock.calls[0]?.[1] as Record<string, unknown>
121
+ expect(config).toHaveProperty("columns")
122
+ expect(config).toHaveProperty("gap")
123
+ expect(config).toHaveProperty("gutter")
124
+ expect(config).toHaveProperty("padding")
125
+ expect(config).toHaveProperty("size")
126
+ expect(config).toHaveProperty("contentAlignX")
127
+ })
128
+
129
+ it("renders with data-coolgrid attribute in dev mode", async () => {
130
+ const Container = (await import("../Container")).default
131
+ const result = asVNode(Container({ children: "test" }))
132
+ expect(result.props["data-coolgrid"]).toBe("container")
133
+ })
134
+
135
+ it("passes component prop as 'as'", async () => {
136
+ const Container = (await import("../Container")).default
137
+ const customComponent = (() => null) as any
138
+ const result = asVNode(Container({ component: customComponent, children: "test" }))
139
+ expect(result.props.as).toBe(customComponent)
140
+ })
141
+
142
+ it("renders children in VNode", async () => {
143
+ const Container = (await import("../Container")).default
144
+ const result = asVNode(Container({ children: "hello world" }))
145
+ expect(result.children).toBeDefined()
146
+ })
147
+ })
@@ -0,0 +1,135 @@
1
+ import type { VNode } from "@pyreon/core"
2
+ import { beforeEach, describe, expect, it, vi } from "vitest"
3
+
4
+ const mockProvide = vi.fn()
5
+ const mockUseContext = vi.fn()
6
+
7
+ vi.mock("@pyreon/core", async (importOriginal) => {
8
+ const original = await importOriginal<typeof import("@pyreon/core")>()
9
+ return {
10
+ ...original,
11
+ provide: (...args: any[]) => {
12
+ mockProvide(...args)
13
+ },
14
+ useContext: (ctx: any) => {
15
+ if (mockUseContext.mock.calls.length > 0) {
16
+ return mockUseContext(ctx)
17
+ }
18
+ return original.useContext(ctx)
19
+ },
20
+ }
21
+ })
22
+
23
+ const asVNode = (v: unknown) => v as VNode
24
+
25
+ describe("Row", () => {
26
+ beforeEach(() => {
27
+ vi.clearAllMocks()
28
+ // unistyle context returns empty theme, container context returns empty
29
+ mockUseContext.mockReturnValue({})
30
+ })
31
+
32
+ it("returns a VNode", async () => {
33
+ const Row = (await import("../Row")).default
34
+ const result = asVNode(Row({ children: "test" }))
35
+ expect(result).toBeDefined()
36
+ expect(result.type).toBeDefined()
37
+ })
38
+
39
+ it("has correct displayName", async () => {
40
+ const Row = (await import("../Row")).default
41
+ expect(Row.displayName).toBe("@pyreon/coolgrid/Row")
42
+ })
43
+
44
+ it("has correct pkgName", async () => {
45
+ const Row = (await import("../Row")).default
46
+ expect(Row.pkgName).toBe("@pyreon/coolgrid")
47
+ })
48
+
49
+ it("has PYREON__COMPONENT static", async () => {
50
+ const Row = (await import("../Row")).default
51
+ expect(Row.PYREON__COMPONENT).toBe("@pyreon/coolgrid/Row")
52
+ })
53
+
54
+ it("passes $coolgrid prop with row values", async () => {
55
+ const Row = (await import("../Row")).default
56
+ const result = asVNode(Row({ gap: 16, children: "test" }))
57
+ expect(result.props).toHaveProperty("$coolgrid")
58
+ expect(result.props.$coolgrid).toHaveProperty("gap")
59
+ })
60
+
61
+ it("provides RowContext", async () => {
62
+ const Row = (await import("../Row")).default
63
+ Row({ gap: 16, columns: 12, children: "test" })
64
+ expect(mockProvide).toHaveBeenCalledTimes(1)
65
+ })
66
+
67
+ it("provides context with grid values", async () => {
68
+ const Row = (await import("../Row")).default
69
+ Row({ columns: 24, gap: 16, gutter: 8, children: "test" })
70
+ const config = mockProvide.mock.calls[0]?.[1] as Record<string, unknown>
71
+ expect(config.columns).toBe(24)
72
+ expect(config.gap).toBe(16)
73
+ expect(config.gutter).toBe(8)
74
+ })
75
+
76
+ it("passes contentAlignX to $coolgrid", async () => {
77
+ const Row = (await import("../Row")).default
78
+ const result = asVNode(Row({ contentAlignX: "center", children: "test" }))
79
+ expect((result.props.$coolgrid as Record<string, unknown>).contentAlignX).toBe("center")
80
+ })
81
+
82
+ it("strips context keys from DOM props", async () => {
83
+ const Row = (await import("../Row")).default
84
+ const result = asVNode(
85
+ Row({
86
+ columns: 12,
87
+ gap: 16,
88
+ "data-testid": "row",
89
+ children: "test",
90
+ }),
91
+ )
92
+ expect(result.props["data-testid"]).toBe("row")
93
+ })
94
+
95
+ it("passes css as extraStyles in $coolgrid when provided", async () => {
96
+ const Row = (await import("../Row")).default
97
+ const customCss = "background: blue;"
98
+ const result = asVNode(Row({ css: customCss, children: "test" }))
99
+ expect((result.props.$coolgrid as Record<string, unknown>).extraStyles).toBe(customCss)
100
+ })
101
+
102
+ it("passes gutter in $coolgrid", async () => {
103
+ const Row = (await import("../Row")).default
104
+ const result = asVNode(Row({ gutter: 24, children: "test" }))
105
+ expect((result.props.$coolgrid as Record<string, unknown>).gutter).toBe(24)
106
+ })
107
+
108
+ it("provides context including colCss and colComponent", async () => {
109
+ const Row = (await import("../Row")).default
110
+ const colComp = (() => null) as any
111
+ Row({ colCss: "color: red;", colComponent: colComp, children: "test" })
112
+ const config = mockProvide.mock.calls[0]?.[1] as Record<string, unknown>
113
+ expect(config.colCss).toBe("color: red;")
114
+ expect(config.colComponent).toBe(colComp)
115
+ })
116
+
117
+ it("renders with data-coolgrid attribute in dev mode", async () => {
118
+ const Row = (await import("../Row")).default
119
+ const result = asVNode(Row({ children: "test" }))
120
+ expect(result.props["data-coolgrid"]).toBe("row")
121
+ })
122
+
123
+ it("passes component prop as 'as'", async () => {
124
+ const Row = (await import("../Row")).default
125
+ const customComponent = (() => null) as any
126
+ const result = asVNode(Row({ component: customComponent, children: "test" }))
127
+ expect(result.props.as).toBe(customComponent)
128
+ })
129
+
130
+ it("renders children in VNode", async () => {
131
+ const Row = (await import("../Row")).default
132
+ const result = asVNode(Row({ children: "hello" }))
133
+ expect(result.children).toBeDefined()
134
+ })
135
+ })
@@ -0,0 +1,120 @@
1
+ import { describe, expect, it } from "vitest"
2
+
3
+ describe("config", () => {
4
+ describe("theme defaults", () => {
5
+ it("has correct default theme", async () => {
6
+ const theme = (await import("../theme")).default
7
+ expect(theme).toEqual({
8
+ rootSize: 16,
9
+ breakpoints: {
10
+ xs: 0,
11
+ sm: 576,
12
+ md: 768,
13
+ lg: 992,
14
+ xl: 1200,
15
+ },
16
+ grid: {
17
+ columns: 12,
18
+ container: {
19
+ xs: "100%",
20
+ sm: 540,
21
+ md: 720,
22
+ lg: 960,
23
+ xl: 1140,
24
+ },
25
+ },
26
+ })
27
+ })
28
+ })
29
+
30
+ describe("defaultBreakpoints", () => {
31
+ it("has all standard breakpoints", async () => {
32
+ const { defaultBreakpoints } = await import("../theme")
33
+ expect(defaultBreakpoints).toEqual({
34
+ xs: 0,
35
+ sm: 576,
36
+ md: 768,
37
+ lg: 992,
38
+ xl: 1200,
39
+ })
40
+ })
41
+
42
+ it("breakpoints are in ascending order", async () => {
43
+ const { defaultBreakpoints } = await import("../theme")
44
+ const values = Object.values(defaultBreakpoints)
45
+ for (let i = 1; i < values.length; i++) {
46
+ expect(values[i]).toBeGreaterThan(values[i - 1] as number)
47
+ }
48
+ })
49
+ })
50
+
51
+ describe("defaultContainerWidths", () => {
52
+ it("has widths for all breakpoints", async () => {
53
+ const { defaultContainerWidths } = await import("../theme")
54
+ expect(defaultContainerWidths).toEqual({
55
+ xs: "100%",
56
+ sm: 540,
57
+ md: 720,
58
+ lg: 960,
59
+ xl: 1140,
60
+ })
61
+ })
62
+
63
+ it("xs is percentage, others are numbers", async () => {
64
+ const { defaultContainerWidths } = await import("../theme")
65
+ expect(typeof defaultContainerWidths.xs).toBe("string")
66
+ expect(typeof defaultContainerWidths.sm).toBe("number")
67
+ expect(typeof defaultContainerWidths.md).toBe("number")
68
+ expect(typeof defaultContainerWidths.lg).toBe("number")
69
+ expect(typeof defaultContainerWidths.xl).toBe("number")
70
+ })
71
+
72
+ it("numeric widths are in ascending order", async () => {
73
+ const { defaultContainerWidths } = await import("../theme")
74
+ const numericWidths = [
75
+ defaultContainerWidths.sm,
76
+ defaultContainerWidths.md,
77
+ defaultContainerWidths.lg,
78
+ defaultContainerWidths.xl,
79
+ ] as number[]
80
+ for (let i = 1; i < numericWidths.length; i++) {
81
+ expect(numericWidths[i]).toBeGreaterThan(numericWidths[i - 1] as number)
82
+ }
83
+ })
84
+ })
85
+
86
+ describe("ContainerContext", () => {
87
+ it("is created via createContext with an id", async () => {
88
+ const { ContainerContext } = await import("../context")
89
+ expect(ContainerContext).toHaveProperty("id")
90
+ })
91
+ })
92
+
93
+ describe("RowContext", () => {
94
+ it("is created via createContext with an id", async () => {
95
+ const { RowContext } = await import("../context")
96
+ expect(RowContext).toHaveProperty("id")
97
+ })
98
+ })
99
+
100
+ describe("constants", () => {
101
+ it("has correct PKG_NAME", async () => {
102
+ const { PKG_NAME } = await import("../constants")
103
+ expect(PKG_NAME).toBe("@pyreon/coolgrid")
104
+ })
105
+
106
+ it("has CONTEXT_KEYS", async () => {
107
+ const { CONTEXT_KEYS } = await import("../constants")
108
+ expect(CONTEXT_KEYS).toContain("columns")
109
+ expect(CONTEXT_KEYS).toContain("size")
110
+ expect(CONTEXT_KEYS).toContain("gap")
111
+ expect(CONTEXT_KEYS).toContain("padding")
112
+ expect(CONTEXT_KEYS).toContain("gutter")
113
+ expect(CONTEXT_KEYS).toContain("colCss")
114
+ expect(CONTEXT_KEYS).toContain("colComponent")
115
+ expect(CONTEXT_KEYS).toContain("rowCss")
116
+ expect(CONTEXT_KEYS).toContain("rowComponent")
117
+ expect(CONTEXT_KEYS).toContain("contentAlignX")
118
+ })
119
+ })
120
+ })
@@ -0,0 +1,114 @@
1
+ import type { VNode } from "@pyreon/core"
2
+ import { beforeEach, describe, expect, it, vi } from "vitest"
3
+
4
+ const mockProvide = vi.fn()
5
+ const mockUseContext = vi.fn()
6
+
7
+ vi.mock("@pyreon/core", async (importOriginal) => {
8
+ const original = await importOriginal<typeof import("@pyreon/core")>()
9
+ return {
10
+ ...original,
11
+ provide: (...args: any[]) => {
12
+ mockProvide(...args)
13
+ },
14
+ useContext: (...args: any[]) => {
15
+ return mockUseContext(...args)
16
+ },
17
+ }
18
+ })
19
+
20
+ const asVNode = (v: unknown) => v as VNode
21
+
22
+ describe("Context cascading: Container -> Row -> Col", () => {
23
+ beforeEach(() => {
24
+ vi.clearAllMocks()
25
+ // Default: unistyle theme context returns empty theme
26
+ mockUseContext.mockReturnValue({ theme: {} })
27
+ })
28
+
29
+ it("Container provides context with grid config", async () => {
30
+ const Container = (await import("../Container")).default
31
+ // Container calls useContext once (for unistyle theme)
32
+ Container({ columns: 12, gap: 16, gutter: 8, padding: 4, children: "test" })
33
+
34
+ expect(mockProvide).toHaveBeenCalledTimes(1)
35
+ const config = mockProvide.mock.calls[0]?.[1] as Record<string, unknown>
36
+
37
+ expect(config.columns).toBe(12)
38
+ expect(config.gap).toBe(16)
39
+ expect(config.gutter).toBe(8)
40
+ expect(config.padding).toBe(4)
41
+ })
42
+
43
+ it("Row reads Container context and provides its own", async () => {
44
+ const Row = (await import("../Row")).default
45
+
46
+ // Row calls useContext twice:
47
+ // 1st: ContainerContext (grid config from parent)
48
+ // 2nd: unistyle context (theme) inside useGridContext
49
+ mockUseContext
50
+ .mockReturnValueOnce({
51
+ columns: 12,
52
+ gap: 16,
53
+ gutter: 8,
54
+ padding: 4,
55
+ })
56
+ .mockReturnValueOnce({ theme: {} })
57
+
58
+ Row({ children: "test" })
59
+
60
+ const rowConfig = mockProvide.mock.calls[0]?.[1] as Record<string, unknown>
61
+
62
+ expect(rowConfig.columns).toBe(12)
63
+ expect(rowConfig.gap).toBe(16)
64
+ expect(rowConfig.gutter).toBe(8)
65
+ expect(rowConfig.padding).toBe(4)
66
+ })
67
+
68
+ it("Row can override Container values", async () => {
69
+ const Row = (await import("../Row")).default
70
+
71
+ // 1st call: ContainerContext, 2nd call: unistyle theme
72
+ mockUseContext.mockReturnValueOnce({ columns: 12, gap: 8 }).mockReturnValueOnce({ theme: {} })
73
+
74
+ Row({ columns: 24, gap: 32, children: "test" })
75
+
76
+ const rowConfig = mockProvide.mock.calls[0]?.[1] as Record<string, unknown>
77
+
78
+ expect(rowConfig.columns).toBe(24)
79
+ expect(rowConfig.gap).toBe(32)
80
+ })
81
+
82
+ it("Col reads Row context and passes $coolgrid", async () => {
83
+ const Col = (await import("../Col")).default
84
+
85
+ // Col calls useContext twice:
86
+ // 1st: RowContext, 2nd: unistyle theme inside useGridContext
87
+ mockUseContext.mockReturnValueOnce({ columns: 12, gap: 20 }).mockReturnValueOnce({ theme: {} })
88
+
89
+ const result = asVNode(Col({ size: 4, children: "test" }))
90
+ expect(result.props.$coolgrid).toBeDefined()
91
+ expect((result.props.$coolgrid as Record<string, unknown>).size).toBe(4)
92
+ })
93
+
94
+ it("Col does not provide context", async () => {
95
+ const Col = (await import("../Col")).default
96
+
97
+ Col({ size: 6, children: "test" })
98
+ expect(mockProvide).not.toHaveBeenCalled()
99
+ })
100
+
101
+ it("Container calls provide", async () => {
102
+ const Container = (await import("../Container")).default
103
+ Container({ children: "test" })
104
+
105
+ expect(mockProvide).toHaveBeenCalledTimes(1)
106
+ })
107
+
108
+ it("Row calls provide", async () => {
109
+ const Row = (await import("../Row")).default
110
+ Row({ children: "test" })
111
+
112
+ expect(mockProvide).toHaveBeenCalledTimes(1)
113
+ })
114
+ })
@@ -0,0 +1,35 @@
1
+ import { describe, expect, it } from "vitest"
2
+
3
+ describe("index exports", () => {
4
+ it("exports Container", async () => {
5
+ const mod = await import("../index")
6
+ expect(mod.Container).toBeDefined()
7
+ expect(typeof mod.Container).toBe("function")
8
+ })
9
+
10
+ it("exports Row", async () => {
11
+ const mod = await import("../index")
12
+ expect(mod.Row).toBeDefined()
13
+ expect(typeof mod.Row).toBe("function")
14
+ })
15
+
16
+ it("exports Col", async () => {
17
+ const mod = await import("../index")
18
+ expect(mod.Col).toBeDefined()
19
+ expect(typeof mod.Col).toBe("function")
20
+ })
21
+
22
+ it("exports Provider", async () => {
23
+ const mod = await import("../index")
24
+ expect(mod.Provider).toBeDefined()
25
+ expect(typeof mod.Provider).toBe("function")
26
+ })
27
+
28
+ it("exports theme", async () => {
29
+ const mod = await import("../index")
30
+ expect(mod.theme).toBeDefined()
31
+ expect(mod.theme).toHaveProperty("rootSize")
32
+ expect(mod.theme).toHaveProperty("breakpoints")
33
+ expect(mod.theme).toHaveProperty("grid")
34
+ })
35
+ })
@@ -0,0 +1,92 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest"
2
+
3
+ const mockUseContext = vi.fn()
4
+
5
+ vi.mock("@pyreon/core", async (importOriginal) => {
6
+ const original = await importOriginal<typeof import("@pyreon/core")>()
7
+ return {
8
+ ...original,
9
+ useContext: mockUseContext,
10
+ }
11
+ })
12
+
13
+ describe("useGridContext", () => {
14
+ beforeEach(() => {
15
+ vi.clearAllMocks()
16
+ // Default: empty theme context
17
+ mockUseContext.mockReturnValue({ theme: {} })
18
+ })
19
+
20
+ it("returns props merged with theme grid context", async () => {
21
+ mockUseContext.mockReturnValue({
22
+ theme: {
23
+ grid: {
24
+ columns: 12,
25
+ container: { xs: "100%", md: 720 },
26
+ },
27
+ },
28
+ })
29
+ const useGridContext = (await import("../useContext")).default
30
+ const result = useGridContext({ gap: 16 })
31
+ expect(result.gap).toBe(16)
32
+ expect(result.columns).toBe(12)
33
+ })
34
+
35
+ it("props override theme values", async () => {
36
+ mockUseContext.mockReturnValue({
37
+ theme: {
38
+ grid: { columns: 12 },
39
+ },
40
+ })
41
+ const useGridContext = (await import("../useContext")).default
42
+ const result = useGridContext({ columns: 24 })
43
+ expect(result.columns).toBe(24)
44
+ })
45
+
46
+ it("falls back to coolgrid namespace in theme", async () => {
47
+ mockUseContext.mockReturnValue({
48
+ theme: {
49
+ coolgrid: {
50
+ columns: 16,
51
+ container: { xs: "100%" },
52
+ },
53
+ },
54
+ })
55
+ const useGridContext = (await import("../useContext")).default
56
+ const result = useGridContext({})
57
+ expect(result.columns).toBe(16)
58
+ })
59
+
60
+ it("returns empty context when no theme or props", async () => {
61
+ mockUseContext.mockReturnValue({ theme: {} })
62
+ const useGridContext = (await import("../useContext")).default
63
+ const result = useGridContext({})
64
+ expect(result).toBeDefined()
65
+ })
66
+ })
67
+
68
+ describe("getGridContext", () => {
69
+ it("resolves columns from props first", async () => {
70
+ const { getGridContext } = await import("../useContext")
71
+ const result = getGridContext({ columns: 24 }, { grid: { columns: 12 } })
72
+ expect(result.columns).toBe(24)
73
+ })
74
+
75
+ it("resolves columns from theme.grid", async () => {
76
+ const { getGridContext } = await import("../useContext")
77
+ const result = getGridContext({}, { grid: { columns: 12 } })
78
+ expect(result.columns).toBe(12)
79
+ })
80
+
81
+ it("resolves columns from theme.coolgrid", async () => {
82
+ const { getGridContext } = await import("../useContext")
83
+ const result = getGridContext({}, { coolgrid: { columns: 16 } })
84
+ expect(result.columns).toBe(16)
85
+ })
86
+
87
+ it("resolves containerWidth from theme.grid.container", async () => {
88
+ const { getGridContext } = await import("../useContext")
89
+ const result = getGridContext({}, { grid: { container: { xs: "100%" } } })
90
+ expect(result.containerWidth).toEqual({ xs: "100%" })
91
+ })
92
+ })