@pyreon/unistyle 0.11.5 → 0.11.7
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/README.md +39 -34
- package/lib/index.d.ts +13 -8
- package/lib/index.js +9 -4
- package/package.json +24 -24
- package/src/__tests__/alignContent.test.ts +57 -57
- package/src/__tests__/borderRadius.test.ts +40 -40
- package/src/__tests__/camelToKebab.test.ts +23 -23
- package/src/__tests__/context.test.ts +28 -28
- package/src/__tests__/createMediaQueries.test.ts +21 -21
- package/src/__tests__/edge.test.ts +76 -76
- package/src/__tests__/enrichTheme.test.ts +13 -13
- package/src/__tests__/index.test.ts +31 -31
- package/src/__tests__/makeItResponsive.test.ts +32 -32
- package/src/__tests__/processDescriptor.test.ts +107 -107
- package/src/__tests__/responsive.test.ts +66 -66
- package/src/__tests__/styles.test.ts +52 -52
- package/src/__tests__/units.test.ts +63 -63
- package/src/context.tsx +11 -6
- package/src/enrichTheme.ts +3 -3
- package/src/index.ts +11 -11
- package/src/responsive/createMediaQueries.ts +4 -4
- package/src/responsive/index.ts +14 -14
- package/src/responsive/makeItResponsive.ts +9 -9
- package/src/responsive/normalizeTheme.ts +2 -2
- package/src/responsive/transformTheme.ts +2 -2
- package/src/styles/alignContent.ts +14 -14
- package/src/styles/extendCss.ts +4 -4
- package/src/styles/index.ts +6 -6
- package/src/styles/shorthands/borderRadius.ts +6 -6
- package/src/styles/shorthands/edge.ts +29 -29
- package/src/styles/shorthands/index.ts +4 -4
- package/src/styles/styles/index.ts +6 -6
- package/src/styles/styles/processDescriptor.ts +31 -31
- package/src/styles/styles/propertyMap.ts +326 -326
- package/src/styles/styles/utils.ts +4 -4
- package/src/types.ts +155 -155
- package/src/units/index.ts +6 -6
- package/src/units/stripUnit.ts +1 -1
- package/src/units/value.ts +20 -20
- package/src/units/values.ts +18 -18
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { describe, expect, it } from
|
|
2
|
-
import processDescriptor from
|
|
3
|
-
import type { PropertyDescriptor } from
|
|
4
|
-
import type { InnerTheme } from
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import processDescriptor from '../styles/styles/processDescriptor'
|
|
3
|
+
import type { PropertyDescriptor } from '../styles/styles/propertyMap'
|
|
4
|
+
import type { InnerTheme } from '../styles/styles/types'
|
|
5
5
|
|
|
6
6
|
// Minimal helpers matching the signature expected by processDescriptor
|
|
7
7
|
const mockCss = (strings: TemplateStringsArray, ...vals: any[]) => {
|
|
8
|
-
let result =
|
|
8
|
+
let result = ''
|
|
9
9
|
for (let i = 0; i < strings.length; i++) {
|
|
10
10
|
result += strings[i]
|
|
11
|
-
if (i < vals.length) result += String(vals[i] ??
|
|
11
|
+
if (i < vals.length) result += String(vals[i] ?? '')
|
|
12
12
|
}
|
|
13
13
|
return result
|
|
14
14
|
}
|
|
@@ -16,7 +16,7 @@ const mockCss = (strings: TemplateStringsArray, ...vals: any[]) => {
|
|
|
16
16
|
const mockCalc = (...params: any[]) => {
|
|
17
17
|
const val = params.find((p) => p != null)
|
|
18
18
|
if (val == null) return null
|
|
19
|
-
if (typeof val ===
|
|
19
|
+
if (typeof val === 'string') return val
|
|
20
20
|
return `${val / 16}rem`
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -25,23 +25,23 @@ const mockBorderRadius = (_props: any) => null
|
|
|
25
25
|
|
|
26
26
|
const t = (overrides: Partial<InnerTheme> = {}): InnerTheme => overrides as InnerTheme
|
|
27
27
|
|
|
28
|
-
describe(
|
|
29
|
-
describe(
|
|
30
|
-
const d: PropertyDescriptor = { kind:
|
|
28
|
+
describe('processDescriptor', () => {
|
|
29
|
+
describe('simple kind', () => {
|
|
30
|
+
const d: PropertyDescriptor = { kind: 'simple', css: 'display', key: 'display' }
|
|
31
31
|
|
|
32
|
-
it(
|
|
32
|
+
it('returns CSS declaration when key has a value', () => {
|
|
33
33
|
const result = processDescriptor(
|
|
34
34
|
d,
|
|
35
|
-
t({ display:
|
|
35
|
+
t({ display: 'flex' }),
|
|
36
36
|
mockCss,
|
|
37
37
|
mockCalc,
|
|
38
38
|
mockEdge as any,
|
|
39
39
|
mockBorderRadius as any,
|
|
40
40
|
)
|
|
41
|
-
expect(result).toBe(
|
|
41
|
+
expect(result).toBe('display: flex;')
|
|
42
42
|
})
|
|
43
43
|
|
|
44
|
-
it(
|
|
44
|
+
it('returns empty string when key is null', () => {
|
|
45
45
|
const result = processDescriptor(
|
|
46
46
|
d,
|
|
47
47
|
t({ display: null as any }),
|
|
@@ -50,10 +50,10 @@ describe("processDescriptor", () => {
|
|
|
50
50
|
mockEdge as any,
|
|
51
51
|
mockBorderRadius as any,
|
|
52
52
|
)
|
|
53
|
-
expect(result).toBe(
|
|
53
|
+
expect(result).toBe('')
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
-
it(
|
|
56
|
+
it('returns empty string when key is undefined', () => {
|
|
57
57
|
const result = processDescriptor(
|
|
58
58
|
d,
|
|
59
59
|
t({}),
|
|
@@ -62,14 +62,14 @@ describe("processDescriptor", () => {
|
|
|
62
62
|
mockEdge as any,
|
|
63
63
|
mockBorderRadius as any,
|
|
64
64
|
)
|
|
65
|
-
expect(result).toBe(
|
|
65
|
+
expect(result).toBe('')
|
|
66
66
|
})
|
|
67
67
|
})
|
|
68
68
|
|
|
69
|
-
describe(
|
|
70
|
-
const d: PropertyDescriptor = { kind:
|
|
69
|
+
describe('convert kind', () => {
|
|
70
|
+
const d: PropertyDescriptor = { kind: 'convert', css: 'width', key: 'width' }
|
|
71
71
|
|
|
72
|
-
it(
|
|
72
|
+
it('returns converted value through calc function', () => {
|
|
73
73
|
const result = processDescriptor(
|
|
74
74
|
d,
|
|
75
75
|
t({ width: 32 } as any),
|
|
@@ -78,30 +78,30 @@ describe("processDescriptor", () => {
|
|
|
78
78
|
mockEdge as any,
|
|
79
79
|
mockBorderRadius as any,
|
|
80
80
|
)
|
|
81
|
-
expect(result).toBe(
|
|
81
|
+
expect(result).toBe('width: 2rem;')
|
|
82
82
|
})
|
|
83
83
|
|
|
84
|
-
it(
|
|
84
|
+
it('passes through string values', () => {
|
|
85
85
|
const result = processDescriptor(
|
|
86
86
|
d,
|
|
87
|
-
t({ width:
|
|
87
|
+
t({ width: '50%' } as any),
|
|
88
88
|
mockCss,
|
|
89
89
|
mockCalc,
|
|
90
90
|
mockEdge as any,
|
|
91
91
|
mockBorderRadius as any,
|
|
92
92
|
)
|
|
93
|
-
expect(result).toBe(
|
|
93
|
+
expect(result).toBe('width: 50%;')
|
|
94
94
|
})
|
|
95
95
|
})
|
|
96
96
|
|
|
97
|
-
describe(
|
|
97
|
+
describe('convert_fallback kind', () => {
|
|
98
98
|
const d: PropertyDescriptor = {
|
|
99
|
-
kind:
|
|
100
|
-
css:
|
|
101
|
-
keys: [
|
|
99
|
+
kind: 'convert_fallback',
|
|
100
|
+
css: 'width',
|
|
101
|
+
keys: ['width', 'size'] as (keyof InnerTheme)[],
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
it(
|
|
104
|
+
it('uses first defined key value', () => {
|
|
105
105
|
const result = processDescriptor(
|
|
106
106
|
d,
|
|
107
107
|
t({ width: 16 } as any),
|
|
@@ -110,13 +110,13 @@ describe("processDescriptor", () => {
|
|
|
110
110
|
mockEdge as any,
|
|
111
111
|
mockBorderRadius as any,
|
|
112
112
|
)
|
|
113
|
-
expect(result).toBe(
|
|
113
|
+
expect(result).toBe('width: 1rem;')
|
|
114
114
|
})
|
|
115
115
|
})
|
|
116
116
|
|
|
117
|
-
describe(
|
|
118
|
-
it(
|
|
119
|
-
const d: PropertyDescriptor = { kind:
|
|
117
|
+
describe('special kind', () => {
|
|
118
|
+
it('returns fullScreen CSS when fullScreen is truthy', () => {
|
|
119
|
+
const d: PropertyDescriptor = { kind: 'special', id: 'fullScreen' }
|
|
120
120
|
const result = processDescriptor(
|
|
121
121
|
d,
|
|
122
122
|
t({ fullScreen: true } as any),
|
|
@@ -125,12 +125,12 @@ describe("processDescriptor", () => {
|
|
|
125
125
|
mockEdge as any,
|
|
126
126
|
mockBorderRadius as any,
|
|
127
127
|
)
|
|
128
|
-
expect(result).toContain(
|
|
129
|
-
expect(result).toContain(
|
|
128
|
+
expect(result).toContain('position: fixed')
|
|
129
|
+
expect(result).toContain('top: 0')
|
|
130
130
|
})
|
|
131
131
|
|
|
132
|
-
it(
|
|
133
|
-
const d: PropertyDescriptor = { kind:
|
|
132
|
+
it('returns empty string when fullScreen is falsy', () => {
|
|
133
|
+
const d: PropertyDescriptor = { kind: 'special', id: 'fullScreen' }
|
|
134
134
|
const result = processDescriptor(
|
|
135
135
|
d,
|
|
136
136
|
t({}),
|
|
@@ -139,37 +139,37 @@ describe("processDescriptor", () => {
|
|
|
139
139
|
mockEdge as any,
|
|
140
140
|
mockBorderRadius as any,
|
|
141
141
|
)
|
|
142
|
-
expect(result).toBe(
|
|
142
|
+
expect(result).toBe('')
|
|
143
143
|
})
|
|
144
144
|
|
|
145
|
-
it(
|
|
146
|
-
const d: PropertyDescriptor = { kind:
|
|
145
|
+
it('returns backgroundImage CSS when set', () => {
|
|
146
|
+
const d: PropertyDescriptor = { kind: 'special', id: 'backgroundImage' }
|
|
147
147
|
const result = processDescriptor(
|
|
148
148
|
d,
|
|
149
|
-
t({ backgroundImage:
|
|
149
|
+
t({ backgroundImage: 'url.png' } as any),
|
|
150
150
|
mockCss,
|
|
151
151
|
mockCalc,
|
|
152
152
|
mockEdge as any,
|
|
153
153
|
mockBorderRadius as any,
|
|
154
154
|
)
|
|
155
|
-
expect(result).toBe(
|
|
155
|
+
expect(result).toBe('background-image: url(url.png);')
|
|
156
156
|
})
|
|
157
157
|
|
|
158
|
-
it(
|
|
159
|
-
const d: PropertyDescriptor = { kind:
|
|
158
|
+
it('returns animation CSS when keyframe is set', () => {
|
|
159
|
+
const d: PropertyDescriptor = { kind: 'special', id: 'animation' }
|
|
160
160
|
const result = processDescriptor(
|
|
161
161
|
d,
|
|
162
|
-
t({ keyframe:
|
|
162
|
+
t({ keyframe: 'fadeIn', animation: '0.3s ease' } as any),
|
|
163
163
|
mockCss,
|
|
164
164
|
mockCalc,
|
|
165
165
|
mockEdge as any,
|
|
166
166
|
mockBorderRadius as any,
|
|
167
167
|
)
|
|
168
|
-
expect(result).toBe(
|
|
168
|
+
expect(result).toBe('animation: fadeIn 0.3s ease;')
|
|
169
169
|
})
|
|
170
170
|
|
|
171
|
-
it(
|
|
172
|
-
const d: PropertyDescriptor = { kind:
|
|
171
|
+
it('returns hideEmpty pseudo-selector when hideEmpty is true', () => {
|
|
172
|
+
const d: PropertyDescriptor = { kind: 'special', id: 'hideEmpty' }
|
|
173
173
|
const result = processDescriptor(
|
|
174
174
|
d,
|
|
175
175
|
t({ hideEmpty: true } as any),
|
|
@@ -178,12 +178,12 @@ describe("processDescriptor", () => {
|
|
|
178
178
|
mockEdge as any,
|
|
179
179
|
mockBorderRadius as any,
|
|
180
180
|
)
|
|
181
|
-
expect(result).toContain(
|
|
182
|
-
expect(result).toContain(
|
|
181
|
+
expect(result).toContain('&:empty')
|
|
182
|
+
expect(result).toContain('display: none')
|
|
183
183
|
})
|
|
184
184
|
|
|
185
|
-
it(
|
|
186
|
-
const d: PropertyDescriptor = { kind:
|
|
185
|
+
it('returns clearFix pseudo-element when clearFix is true', () => {
|
|
186
|
+
const d: PropertyDescriptor = { kind: 'special', id: 'clearFix' }
|
|
187
187
|
const result = processDescriptor(
|
|
188
188
|
d,
|
|
189
189
|
t({ clearFix: true } as any),
|
|
@@ -192,12 +192,12 @@ describe("processDescriptor", () => {
|
|
|
192
192
|
mockEdge as any,
|
|
193
193
|
mockBorderRadius as any,
|
|
194
194
|
)
|
|
195
|
-
expect(result).toContain(
|
|
196
|
-
expect(result).toContain(
|
|
195
|
+
expect(result).toContain('&::after')
|
|
196
|
+
expect(result).toContain('clear: both')
|
|
197
197
|
})
|
|
198
198
|
|
|
199
|
-
it(
|
|
200
|
-
const d: PropertyDescriptor = { kind:
|
|
199
|
+
it('returns empty string for unknown special id', () => {
|
|
200
|
+
const d: PropertyDescriptor = { kind: 'special', id: 'unknown' }
|
|
201
201
|
const result = processDescriptor(
|
|
202
202
|
d,
|
|
203
203
|
t({}),
|
|
@@ -206,26 +206,26 @@ describe("processDescriptor", () => {
|
|
|
206
206
|
mockEdge as any,
|
|
207
207
|
mockBorderRadius as any,
|
|
208
208
|
)
|
|
209
|
-
expect(result).toBe(
|
|
209
|
+
expect(result).toBe('')
|
|
210
210
|
})
|
|
211
211
|
})
|
|
212
212
|
|
|
213
|
-
describe(
|
|
214
|
-
it(
|
|
213
|
+
describe('edge kind', () => {
|
|
214
|
+
it('delegates to shorthand function', () => {
|
|
215
215
|
const d: PropertyDescriptor = {
|
|
216
|
-
kind:
|
|
217
|
-
property:
|
|
216
|
+
kind: 'edge',
|
|
217
|
+
property: 'margin',
|
|
218
218
|
keys: {
|
|
219
|
-
full:
|
|
220
|
-
x:
|
|
221
|
-
y:
|
|
222
|
-
top:
|
|
223
|
-
left:
|
|
224
|
-
bottom:
|
|
225
|
-
right:
|
|
219
|
+
full: 'margin' as keyof InnerTheme,
|
|
220
|
+
x: 'marginX' as keyof InnerTheme,
|
|
221
|
+
y: 'marginY' as keyof InnerTheme,
|
|
222
|
+
top: 'marginTop' as keyof InnerTheme,
|
|
223
|
+
left: 'marginLeft' as keyof InnerTheme,
|
|
224
|
+
bottom: 'marginBottom' as keyof InnerTheme,
|
|
225
|
+
right: 'marginRight' as keyof InnerTheme,
|
|
226
226
|
},
|
|
227
227
|
}
|
|
228
|
-
const customEdge = () =>
|
|
228
|
+
const customEdge = () => 'margin: 1rem;'
|
|
229
229
|
const result = processDescriptor(
|
|
230
230
|
d,
|
|
231
231
|
t({ margin: 16 } as any),
|
|
@@ -234,21 +234,21 @@ describe("processDescriptor", () => {
|
|
|
234
234
|
customEdge as any,
|
|
235
235
|
mockBorderRadius as any,
|
|
236
236
|
)
|
|
237
|
-
expect(result).toBe(
|
|
237
|
+
expect(result).toBe('margin: 1rem;')
|
|
238
238
|
})
|
|
239
239
|
|
|
240
|
-
it(
|
|
240
|
+
it('returns empty string when shorthand returns null', () => {
|
|
241
241
|
const d: PropertyDescriptor = {
|
|
242
|
-
kind:
|
|
243
|
-
property:
|
|
242
|
+
kind: 'edge',
|
|
243
|
+
property: 'padding',
|
|
244
244
|
keys: {
|
|
245
|
-
full:
|
|
246
|
-
x:
|
|
247
|
-
y:
|
|
248
|
-
top:
|
|
249
|
-
left:
|
|
250
|
-
bottom:
|
|
251
|
-
right:
|
|
245
|
+
full: 'padding' as keyof InnerTheme,
|
|
246
|
+
x: 'paddingX' as keyof InnerTheme,
|
|
247
|
+
y: 'paddingY' as keyof InnerTheme,
|
|
248
|
+
top: 'paddingTop' as keyof InnerTheme,
|
|
249
|
+
left: 'paddingLeft' as keyof InnerTheme,
|
|
250
|
+
bottom: 'paddingBottom' as keyof InnerTheme,
|
|
251
|
+
right: 'paddingRight' as keyof InnerTheme,
|
|
252
252
|
},
|
|
253
253
|
}
|
|
254
254
|
const result = processDescriptor(
|
|
@@ -259,27 +259,27 @@ describe("processDescriptor", () => {
|
|
|
259
259
|
mockEdge as any,
|
|
260
260
|
mockBorderRadius as any,
|
|
261
261
|
)
|
|
262
|
-
expect(result).toBe(
|
|
262
|
+
expect(result).toBe('')
|
|
263
263
|
})
|
|
264
264
|
})
|
|
265
265
|
|
|
266
|
-
describe(
|
|
267
|
-
it(
|
|
266
|
+
describe('border_radius kind', () => {
|
|
267
|
+
it('delegates to borderRadius function', () => {
|
|
268
268
|
const d: PropertyDescriptor = {
|
|
269
|
-
kind:
|
|
269
|
+
kind: 'border_radius',
|
|
270
270
|
keys: {
|
|
271
|
-
full:
|
|
272
|
-
top:
|
|
273
|
-
bottom:
|
|
274
|
-
left:
|
|
275
|
-
right:
|
|
276
|
-
topLeft:
|
|
277
|
-
topRight:
|
|
278
|
-
bottomLeft:
|
|
279
|
-
bottomRight:
|
|
271
|
+
full: 'borderRadius' as keyof InnerTheme,
|
|
272
|
+
top: 'borderRadiusTop' as keyof InnerTheme,
|
|
273
|
+
bottom: 'borderRadiusBottom' as keyof InnerTheme,
|
|
274
|
+
left: 'borderRadiusLeft' as keyof InnerTheme,
|
|
275
|
+
right: 'borderRadiusRight' as keyof InnerTheme,
|
|
276
|
+
topLeft: 'borderRadiusTopLeft' as keyof InnerTheme,
|
|
277
|
+
topRight: 'borderRadiusTopRight' as keyof InnerTheme,
|
|
278
|
+
bottomLeft: 'borderRadiusBottomLeft' as keyof InnerTheme,
|
|
279
|
+
bottomRight: 'borderRadiusBottomRight' as keyof InnerTheme,
|
|
280
280
|
},
|
|
281
281
|
}
|
|
282
|
-
const customBR = () =>
|
|
282
|
+
const customBR = () => 'border-radius: 4px;'
|
|
283
283
|
const result = processDescriptor(
|
|
284
284
|
d,
|
|
285
285
|
t({ borderRadius: 4 } as any),
|
|
@@ -288,22 +288,22 @@ describe("processDescriptor", () => {
|
|
|
288
288
|
mockEdge as any,
|
|
289
289
|
customBR as any,
|
|
290
290
|
)
|
|
291
|
-
expect(result).toBe(
|
|
291
|
+
expect(result).toBe('border-radius: 4px;')
|
|
292
292
|
})
|
|
293
293
|
|
|
294
|
-
it(
|
|
294
|
+
it('returns empty string when borderRadius returns null', () => {
|
|
295
295
|
const d: PropertyDescriptor = {
|
|
296
|
-
kind:
|
|
296
|
+
kind: 'border_radius',
|
|
297
297
|
keys: {
|
|
298
|
-
full:
|
|
299
|
-
top:
|
|
300
|
-
bottom:
|
|
301
|
-
left:
|
|
302
|
-
right:
|
|
303
|
-
topLeft:
|
|
304
|
-
topRight:
|
|
305
|
-
bottomLeft:
|
|
306
|
-
bottomRight:
|
|
298
|
+
full: 'borderRadius' as keyof InnerTheme,
|
|
299
|
+
top: 'borderRadiusTop' as keyof InnerTheme,
|
|
300
|
+
bottom: 'borderRadiusBottom' as keyof InnerTheme,
|
|
301
|
+
left: 'borderRadiusLeft' as keyof InnerTheme,
|
|
302
|
+
right: 'borderRadiusRight' as keyof InnerTheme,
|
|
303
|
+
topLeft: 'borderRadiusTopLeft' as keyof InnerTheme,
|
|
304
|
+
topRight: 'borderRadiusTopRight' as keyof InnerTheme,
|
|
305
|
+
bottomLeft: 'borderRadiusBottomLeft' as keyof InnerTheme,
|
|
306
|
+
bottomRight: 'borderRadiusBottomRight' as keyof InnerTheme,
|
|
307
307
|
},
|
|
308
308
|
}
|
|
309
309
|
const result = processDescriptor(
|
|
@@ -314,7 +314,7 @@ describe("processDescriptor", () => {
|
|
|
314
314
|
mockEdge as any,
|
|
315
315
|
mockBorderRadius as any,
|
|
316
316
|
)
|
|
317
|
-
expect(result).toBe(
|
|
317
|
+
expect(result).toBe('')
|
|
318
318
|
})
|
|
319
319
|
})
|
|
320
320
|
})
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { describe, expect, it } from
|
|
2
|
-
import breakpoints from
|
|
3
|
-
import normalizeTheme from
|
|
4
|
-
import optimizeTheme from
|
|
5
|
-
import sortBreakpoints from
|
|
6
|
-
import transformTheme from
|
|
7
|
-
|
|
8
|
-
describe(
|
|
9
|
-
it(
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import breakpoints from '../responsive/breakpoints'
|
|
3
|
+
import normalizeTheme from '../responsive/normalizeTheme'
|
|
4
|
+
import optimizeTheme from '../responsive/optimizeTheme'
|
|
5
|
+
import sortBreakpoints from '../responsive/sortBreakpoints'
|
|
6
|
+
import transformTheme from '../responsive/transformTheme'
|
|
7
|
+
|
|
8
|
+
describe('breakpoints', () => {
|
|
9
|
+
it('has expected default config', () => {
|
|
10
10
|
expect(breakpoints.rootSize).toBe(16)
|
|
11
|
-
expect(breakpoints.breakpoints).toHaveProperty(
|
|
12
|
-
expect(breakpoints.breakpoints).toHaveProperty(
|
|
13
|
-
expect(breakpoints.breakpoints).toHaveProperty(
|
|
14
|
-
expect(breakpoints.breakpoints).toHaveProperty(
|
|
15
|
-
expect(breakpoints.breakpoints).toHaveProperty(
|
|
16
|
-
expect(breakpoints.breakpoints).toHaveProperty(
|
|
11
|
+
expect(breakpoints.breakpoints).toHaveProperty('xs')
|
|
12
|
+
expect(breakpoints.breakpoints).toHaveProperty('sm')
|
|
13
|
+
expect(breakpoints.breakpoints).toHaveProperty('md')
|
|
14
|
+
expect(breakpoints.breakpoints).toHaveProperty('lg')
|
|
15
|
+
expect(breakpoints.breakpoints).toHaveProperty('xl')
|
|
16
|
+
expect(breakpoints.breakpoints).toHaveProperty('xxl')
|
|
17
17
|
})
|
|
18
18
|
|
|
19
|
-
it(
|
|
19
|
+
it('has correct pixel values', () => {
|
|
20
20
|
expect(breakpoints.breakpoints.xs).toBe(0)
|
|
21
21
|
expect(breakpoints.breakpoints.sm).toBe(576)
|
|
22
22
|
expect(breakpoints.breakpoints.md).toBe(768)
|
|
@@ -26,42 +26,42 @@ describe("breakpoints", () => {
|
|
|
26
26
|
})
|
|
27
27
|
})
|
|
28
28
|
|
|
29
|
-
describe(
|
|
30
|
-
it(
|
|
29
|
+
describe('sortBreakpoints', () => {
|
|
30
|
+
it('sorts breakpoints by value ascending, returns keys', () => {
|
|
31
31
|
const bps = { md: 768, xs: 0, xl: 1200, sm: 576 }
|
|
32
32
|
const sorted = sortBreakpoints(bps)
|
|
33
|
-
expect(sorted).toEqual([
|
|
33
|
+
expect(sorted).toEqual(['xs', 'sm', 'md', 'xl'])
|
|
34
34
|
})
|
|
35
35
|
|
|
36
|
-
it(
|
|
36
|
+
it('handles already sorted breakpoints', () => {
|
|
37
37
|
const sorted = sortBreakpoints({ xs: 0, sm: 576, md: 768 })
|
|
38
|
-
expect(sorted).toEqual([
|
|
38
|
+
expect(sorted).toEqual(['xs', 'sm', 'md'])
|
|
39
39
|
})
|
|
40
40
|
|
|
41
|
-
it(
|
|
42
|
-
expect(sortBreakpoints({ xs: 0 })).toEqual([
|
|
41
|
+
it('handles single breakpoint', () => {
|
|
42
|
+
expect(sortBreakpoints({ xs: 0 })).toEqual(['xs'])
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
-
it(
|
|
45
|
+
it('handles empty object', () => {
|
|
46
46
|
expect(sortBreakpoints({})).toEqual([])
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
-
it(
|
|
49
|
+
it('sorts full default breakpoint set', () => {
|
|
50
50
|
const sorted = sortBreakpoints(breakpoints.breakpoints)
|
|
51
|
-
expect(sorted).toEqual([
|
|
51
|
+
expect(sorted).toEqual(['xs', 'sm', 'md', 'lg', 'xl', 'xxl'])
|
|
52
52
|
})
|
|
53
53
|
})
|
|
54
54
|
|
|
55
|
-
describe(
|
|
56
|
-
const bpKeys = [
|
|
55
|
+
describe('normalizeTheme', () => {
|
|
56
|
+
const bpKeys = ['xs', 'sm', 'md', 'lg', 'xl']
|
|
57
57
|
|
|
58
|
-
it(
|
|
59
|
-
const theme = { color:
|
|
58
|
+
it('returns theme as-is when no nested objects/arrays', () => {
|
|
59
|
+
const theme = { color: 'red', fontSize: 16 }
|
|
60
60
|
const result = normalizeTheme({ theme, breakpoints: bpKeys })
|
|
61
61
|
expect(result).toEqual(theme)
|
|
62
62
|
})
|
|
63
63
|
|
|
64
|
-
it(
|
|
64
|
+
it('expands array values across breakpoints', () => {
|
|
65
65
|
const theme = { fontSize: [12, 14, 16, 18, 20] }
|
|
66
66
|
const result = normalizeTheme({ theme, breakpoints: bpKeys })
|
|
67
67
|
expect(result.fontSize).toEqual({
|
|
@@ -73,7 +73,7 @@ describe("normalizeTheme", () => {
|
|
|
73
73
|
})
|
|
74
74
|
})
|
|
75
75
|
|
|
76
|
-
it(
|
|
76
|
+
it('array values use last value for extra breakpoints', () => {
|
|
77
77
|
const theme = { fontSize: [12, 14] }
|
|
78
78
|
const result = normalizeTheme({ theme, breakpoints: bpKeys })
|
|
79
79
|
expect((result.fontSize as Record<string, unknown>).xs).toBe(12)
|
|
@@ -81,7 +81,7 @@ describe("normalizeTheme", () => {
|
|
|
81
81
|
expect((result.fontSize as Record<string, unknown>).md).toBe(14)
|
|
82
82
|
})
|
|
83
83
|
|
|
84
|
-
it(
|
|
84
|
+
it('expands object values with carry-forward', () => {
|
|
85
85
|
const theme = { fontSize: { xs: 12, md: 16 } }
|
|
86
86
|
const result = normalizeTheme({ theme, breakpoints: bpKeys })
|
|
87
87
|
const fs = result.fontSize as Record<string, unknown>
|
|
@@ -91,30 +91,30 @@ describe("normalizeTheme", () => {
|
|
|
91
91
|
expect(fs.lg).toBe(16) // carried from md
|
|
92
92
|
})
|
|
93
93
|
|
|
94
|
-
it(
|
|
94
|
+
it('skips null values', () => {
|
|
95
95
|
const theme = { color: null, fontSize: 16 }
|
|
96
96
|
const result = normalizeTheme({ theme, breakpoints: bpKeys })
|
|
97
97
|
expect(result.color).toBeUndefined()
|
|
98
98
|
})
|
|
99
99
|
})
|
|
100
100
|
|
|
101
|
-
describe(
|
|
102
|
-
const bpKeys = [
|
|
101
|
+
describe('transformTheme', () => {
|
|
102
|
+
const bpKeys = ['xs', 'sm', 'md']
|
|
103
103
|
|
|
104
|
-
it(
|
|
105
|
-
const theme = { color:
|
|
104
|
+
it('pivots scalar values to first breakpoint', () => {
|
|
105
|
+
const theme = { color: 'red' }
|
|
106
106
|
const result = transformTheme({ theme, breakpoints: bpKeys })
|
|
107
|
-
expect(result.xs).toEqual({ color:
|
|
107
|
+
expect(result.xs).toEqual({ color: 'red' })
|
|
108
108
|
})
|
|
109
109
|
|
|
110
|
-
it(
|
|
111
|
-
const theme = { color: { xs:
|
|
110
|
+
it('pivots object values to breakpoints', () => {
|
|
111
|
+
const theme = { color: { xs: 'red', md: 'blue' } }
|
|
112
112
|
const result = transformTheme({ theme, breakpoints: bpKeys })
|
|
113
|
-
expect(result.xs).toEqual({ color:
|
|
114
|
-
expect(result.md).toEqual({ color:
|
|
113
|
+
expect(result.xs).toEqual({ color: 'red' })
|
|
114
|
+
expect(result.md).toEqual({ color: 'blue' })
|
|
115
115
|
})
|
|
116
116
|
|
|
117
|
-
it(
|
|
117
|
+
it('pivots array values by index', () => {
|
|
118
118
|
const theme = { fontSize: [12, 14, 16] }
|
|
119
119
|
const result = transformTheme({ theme, breakpoints: bpKeys })
|
|
120
120
|
expect(result.xs).toEqual({ fontSize: 12 })
|
|
@@ -122,56 +122,56 @@ describe("transformTheme", () => {
|
|
|
122
122
|
expect(result.md).toEqual({ fontSize: 16 })
|
|
123
123
|
})
|
|
124
124
|
|
|
125
|
-
it(
|
|
125
|
+
it('returns empty object for empty theme', () => {
|
|
126
126
|
expect(transformTheme({ theme: {}, breakpoints: bpKeys })).toEqual({})
|
|
127
127
|
})
|
|
128
128
|
|
|
129
|
-
it(
|
|
130
|
-
expect(transformTheme({ theme: { color:
|
|
129
|
+
it('returns empty object for empty breakpoints', () => {
|
|
130
|
+
expect(transformTheme({ theme: { color: 'red' }, breakpoints: [] })).toEqual({})
|
|
131
131
|
})
|
|
132
132
|
|
|
133
|
-
it(
|
|
134
|
-
const theme = { color: { xs:
|
|
133
|
+
it('filters out unexpected breakpoint keys', () => {
|
|
134
|
+
const theme = { color: { xs: 'red', unknown: 'green' } }
|
|
135
135
|
const result = transformTheme({ theme, breakpoints: bpKeys })
|
|
136
|
-
expect(result).not.toHaveProperty(
|
|
136
|
+
expect(result).not.toHaveProperty('unknown')
|
|
137
137
|
})
|
|
138
138
|
})
|
|
139
139
|
|
|
140
|
-
describe(
|
|
141
|
-
const bpKeys = [
|
|
140
|
+
describe('optimizeTheme', () => {
|
|
141
|
+
const bpKeys = ['xs', 'sm', 'md', 'lg']
|
|
142
142
|
|
|
143
|
-
it(
|
|
143
|
+
it('keeps first breakpoint', () => {
|
|
144
144
|
const theme = {
|
|
145
|
-
xs: { color:
|
|
146
|
-
sm: { color:
|
|
145
|
+
xs: { color: 'red' },
|
|
146
|
+
sm: { color: 'blue' },
|
|
147
147
|
}
|
|
148
148
|
const result = optimizeTheme({ theme, breakpoints: bpKeys })
|
|
149
|
-
expect(result.xs).toEqual({ color:
|
|
149
|
+
expect(result.xs).toEqual({ color: 'red' })
|
|
150
150
|
})
|
|
151
151
|
|
|
152
|
-
it(
|
|
152
|
+
it('removes duplicate breakpoints', () => {
|
|
153
153
|
const theme = {
|
|
154
|
-
xs: { color:
|
|
155
|
-
sm: { color:
|
|
156
|
-
md: { color:
|
|
154
|
+
xs: { color: 'red' },
|
|
155
|
+
sm: { color: 'red' },
|
|
156
|
+
md: { color: 'blue' },
|
|
157
157
|
}
|
|
158
158
|
const result = optimizeTheme({ theme, breakpoints: bpKeys })
|
|
159
|
-
expect(result.xs).toEqual({ color:
|
|
159
|
+
expect(result.xs).toEqual({ color: 'red' })
|
|
160
160
|
expect(result.sm).toBeUndefined()
|
|
161
|
-
expect(result.md).toEqual({ color:
|
|
161
|
+
expect(result.md).toEqual({ color: 'blue' })
|
|
162
162
|
})
|
|
163
163
|
|
|
164
|
-
it(
|
|
164
|
+
it('keeps breakpoints with different values', () => {
|
|
165
165
|
const theme = {
|
|
166
|
-
xs: { color:
|
|
167
|
-
sm: { color:
|
|
166
|
+
xs: { color: 'red', fontSize: 12 },
|
|
167
|
+
sm: { color: 'red', fontSize: 14 },
|
|
168
168
|
}
|
|
169
169
|
const result = optimizeTheme({ theme, breakpoints: bpKeys })
|
|
170
170
|
expect(result.xs).toBeDefined()
|
|
171
171
|
expect(result.sm).toBeDefined()
|
|
172
172
|
})
|
|
173
173
|
|
|
174
|
-
it(
|
|
174
|
+
it('handles empty theme', () => {
|
|
175
175
|
expect(optimizeTheme({ theme: {}, breakpoints: bpKeys })).toEqual({})
|
|
176
176
|
})
|
|
177
177
|
})
|