@pyreon/coolgrid 0.24.5 → 0.25.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.
@@ -1,49 +0,0 @@
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
- })
@@ -1,152 +0,0 @@
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', { timeout: 60_000 }, async () => {
33
- // Long timeout: this test dynamic-imports Container on first run,
34
- // which cold-loads the full styler → unistyle chain. On slow CI
35
- // runners it consistently hits ~13-14s, flaking against the
36
- // default 15s timeout. 30s gives comfortable headroom without
37
- // masking real hangs.
38
- const Container = (await import('../Container')).default
39
- const result = asVNode(Container({ children: 'test' }))
40
- expect(result).toBeDefined()
41
- expect(result.type).toBeDefined()
42
- })
43
-
44
- it('has correct displayName', async () => {
45
- const Container = (await import('../Container')).default
46
- expect(Container.displayName).toBe('@pyreon/coolgrid/Container')
47
- })
48
-
49
- it('has correct pkgName', async () => {
50
- const Container = (await import('../Container')).default
51
- expect(Container.pkgName).toBe('@pyreon/coolgrid')
52
- })
53
-
54
- it('has PYREON__COMPONENT static', async () => {
55
- const Container = (await import('../Container')).default
56
- expect(Container.PYREON__COMPONENT).toBe('@pyreon/coolgrid/Container')
57
- })
58
-
59
- it('passes $coolgrid prop with width and extraStyles', async () => {
60
- const Container = (await import('../Container')).default
61
- const result = asVNode(Container({ children: 'test' }))
62
- expect(result.props).toHaveProperty('$coolgrid')
63
- expect(result.props.$coolgrid).toHaveProperty('width')
64
- })
65
-
66
- it('provides ContainerContext', async () => {
67
- const Container = (await import('../Container')).default
68
- Container({ columns: 12, gap: 16, children: 'test' })
69
- expect(mockProvide).toHaveBeenCalledTimes(1)
70
- })
71
-
72
- it('provides context with grid values', async () => {
73
- const Container = (await import('../Container')).default
74
- Container({ columns: 24, gap: 16, gutter: 8, children: 'test' })
75
- const config = mockProvide.mock.calls[0]?.[1] as Record<string, unknown>
76
- expect(config.columns).toBe(24)
77
- expect(config.gap).toBe(16)
78
- expect(config.gutter).toBe(8)
79
- })
80
-
81
- it('uses width prop to override containerWidth', async () => {
82
- const Container = (await import('../Container')).default
83
- const result = asVNode(Container({ width: 960, children: 'test' }))
84
- expect((result.props.$coolgrid as Record<string, unknown>).width).toBe(960)
85
- })
86
-
87
- it('accepts width as function', async () => {
88
- const Container = (await import('../Container')).default
89
- const widthFn = (_containerWidth: any) => 800
90
- const result = asVNode(Container({ width: widthFn as any, children: 'test' }))
91
- expect((result.props.$coolgrid as Record<string, unknown>).width).toBe(800)
92
- })
93
-
94
- it('strips context keys from DOM props', async () => {
95
- const Container = (await import('../Container')).default
96
- const result = asVNode(
97
- Container({
98
- columns: 12,
99
- gap: 16,
100
- 'data-testid': 'container',
101
- children: 'test',
102
- }),
103
- )
104
- expect(result.props['data-testid']).toBe('container')
105
- })
106
-
107
- it('passes css as extraStyles in $coolgrid', async () => {
108
- const Container = (await import('../Container')).default
109
- const customCss = 'background: red;'
110
- const result = asVNode(Container({ css: customCss, children: 'test' }))
111
- expect((result.props.$coolgrid as Record<string, unknown>).extraStyles).toBe(customCss)
112
- })
113
-
114
- it('provides context with all grid keys', async () => {
115
- const Container = (await import('../Container')).default
116
- Container({
117
- columns: 12,
118
- gap: 16,
119
- gutter: 8,
120
- padding: 4,
121
- size: 6,
122
- contentAlignX: 'center',
123
- children: 'test',
124
- })
125
- const config = mockProvide.mock.calls[0]?.[1] as Record<string, unknown>
126
- expect(config).toHaveProperty('columns')
127
- expect(config).toHaveProperty('gap')
128
- expect(config).toHaveProperty('gutter')
129
- expect(config).toHaveProperty('padding')
130
- expect(config).toHaveProperty('size')
131
- expect(config).toHaveProperty('contentAlignX')
132
- })
133
-
134
- it('renders with data-coolgrid attribute in dev mode', async () => {
135
- const Container = (await import('../Container')).default
136
- const result = asVNode(Container({ children: 'test' }))
137
- expect(result.props['data-coolgrid']).toBe('container')
138
- })
139
-
140
- it("passes component prop as 'as'", async () => {
141
- const Container = (await import('../Container')).default
142
- const customComponent = (() => null) as any
143
- const result = asVNode(Container({ component: customComponent, children: 'test' }))
144
- expect(result.props.as).toBe(customComponent)
145
- })
146
-
147
- it('renders children in VNode', async () => {
148
- const Container = (await import('../Container')).default
149
- const result = asVNode(Container({ children: 'hello world' }))
150
- expect(result.children).toBeDefined()
151
- })
152
- })
@@ -1,142 +0,0 @@
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
- // First test in this file pays the cold-import cost for the entire coolgrid
33
- // module graph (@pyreon/core + ui-core + unistyle + styler + rocketstyle).
34
- // Warm it takes ~200ms, but on cold CI shared runners the Vite transform of
35
- // that graph can spike past the 15s default and time out (PR #225 flakes).
36
- // Per-test timeout bump — subsequent tests in the file reuse the cached
37
- // module and run in 0ms, so the global 15s budget stays strict everywhere
38
- // else.
39
- it('returns a VNode', { timeout: 60000 }, async () => {
40
- const Row = (await import('../Row')).default
41
- const result = asVNode(Row({ children: 'test' }))
42
- expect(result).toBeDefined()
43
- expect(result.type).toBeDefined()
44
- })
45
-
46
- it('has correct displayName', async () => {
47
- const Row = (await import('../Row')).default
48
- expect(Row.displayName).toBe('@pyreon/coolgrid/Row')
49
- })
50
-
51
- it('has correct pkgName', async () => {
52
- const Row = (await import('../Row')).default
53
- expect(Row.pkgName).toBe('@pyreon/coolgrid')
54
- })
55
-
56
- it('has PYREON__COMPONENT static', async () => {
57
- const Row = (await import('../Row')).default
58
- expect(Row.PYREON__COMPONENT).toBe('@pyreon/coolgrid/Row')
59
- })
60
-
61
- it('passes $coolgrid prop with row values', async () => {
62
- const Row = (await import('../Row')).default
63
- const result = asVNode(Row({ gap: 16, children: 'test' }))
64
- expect(result.props).toHaveProperty('$coolgrid')
65
- expect(result.props.$coolgrid).toHaveProperty('gap')
66
- })
67
-
68
- it('provides RowContext', async () => {
69
- const Row = (await import('../Row')).default
70
- Row({ gap: 16, columns: 12, children: 'test' })
71
- expect(mockProvide).toHaveBeenCalledTimes(1)
72
- })
73
-
74
- it('provides context with grid values', async () => {
75
- const Row = (await import('../Row')).default
76
- Row({ columns: 24, gap: 16, gutter: 8, children: 'test' })
77
- const config = mockProvide.mock.calls[0]?.[1] as Record<string, unknown>
78
- expect(config.columns).toBe(24)
79
- expect(config.gap).toBe(16)
80
- expect(config.gutter).toBe(8)
81
- })
82
-
83
- it('passes contentAlignX to $coolgrid', async () => {
84
- const Row = (await import('../Row')).default
85
- const result = asVNode(Row({ contentAlignX: 'center', children: 'test' }))
86
- expect((result.props.$coolgrid as Record<string, unknown>).contentAlignX).toBe('center')
87
- })
88
-
89
- it('strips context keys from DOM props', async () => {
90
- const Row = (await import('../Row')).default
91
- const result = asVNode(
92
- Row({
93
- columns: 12,
94
- gap: 16,
95
- 'data-testid': 'row',
96
- children: 'test',
97
- }),
98
- )
99
- expect(result.props['data-testid']).toBe('row')
100
- })
101
-
102
- it('passes css as extraStyles in $coolgrid when provided', async () => {
103
- const Row = (await import('../Row')).default
104
- const customCss = 'background: blue;'
105
- const result = asVNode(Row({ css: customCss, children: 'test' }))
106
- expect((result.props.$coolgrid as Record<string, unknown>).extraStyles).toBe(customCss)
107
- })
108
-
109
- it('passes gutter in $coolgrid', async () => {
110
- const Row = (await import('../Row')).default
111
- const result = asVNode(Row({ gutter: 24, children: 'test' }))
112
- expect((result.props.$coolgrid as Record<string, unknown>).gutter).toBe(24)
113
- })
114
-
115
- it('provides context including colCss and colComponent', async () => {
116
- const Row = (await import('../Row')).default
117
- const colComp = (() => null) as any
118
- Row({ colCss: 'color: red;', colComponent: colComp, children: 'test' })
119
- const config = mockProvide.mock.calls[0]?.[1] as Record<string, unknown>
120
- expect(config.colCss).toBe('color: red;')
121
- expect(config.colComponent).toBe(colComp)
122
- })
123
-
124
- it('renders with data-coolgrid attribute in dev mode', async () => {
125
- const Row = (await import('../Row')).default
126
- const result = asVNode(Row({ children: 'test' }))
127
- expect(result.props['data-coolgrid']).toBe('row')
128
- })
129
-
130
- it("passes component prop as 'as'", async () => {
131
- const Row = (await import('../Row')).default
132
- const customComponent = (() => null) as any
133
- const result = asVNode(Row({ component: customComponent, children: 'test' }))
134
- expect(result.props.as).toBe(customComponent)
135
- })
136
-
137
- it('renders children in VNode', async () => {
138
- const Row = (await import('../Row')).default
139
- const result = asVNode(Row({ children: 'hello' }))
140
- expect(result.children).toBeDefined()
141
- })
142
- })
@@ -1,120 +0,0 @@
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
- })
@@ -1,114 +0,0 @@
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 a ReactiveContext accessor
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
- })