Skip to content

Commit 81a3d98

Browse files
Sprinkles: Support boolean conditional values (#605)
1 parent b221532 commit 81a3d98

File tree

4 files changed

+91
-37
lines changed

4 files changed

+91
-37
lines changed

.changeset/itchy-eyes-protect.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@vanilla-extract/sprinkles': minor
3+
---
4+
5+
Support boolean conditional values, e.g. `{ mobile: false, desktop: true }`

packages/sprinkles/src/createUtils.ts

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@ type ExtractValue<
88
Value extends
99
| string
1010
| number
11-
| Partial<Record<string, string | number>>
12-
| ResponsiveArrayByMaxLength<number, string | number | null>,
13-
> = Value extends ResponsiveArrayByMaxLength<number, string | number | null>
11+
| boolean
12+
| Partial<Record<string, string | number | boolean>>
13+
| ResponsiveArrayByMaxLength<number, string | number | boolean | null>,
14+
> = Value extends ResponsiveArrayByMaxLength<
15+
number,
16+
string | number | boolean | null
17+
>
1418
? NonNullable<Value[number]>
15-
: Value extends Partial<Record<string, string | number>>
19+
: Value extends Partial<Record<string, string | number | boolean>>
1620
? NonNullable<Value[keyof Value]>
1721
: Value;
1822

@@ -32,7 +36,7 @@ type ExtractConditionNames<SprinklesProperties extends Conditions<string>> =
3236

3337
export type ConditionalValue<
3438
SprinklesProperties extends Conditions<string>,
35-
Value extends string | number,
39+
Value extends string | number | boolean,
3640
> =
3741
| (ExtractDefaultCondition<SprinklesProperties> extends false ? never : Value)
3842
| Partial<Record<ExtractConditionNames<SprinklesProperties>, Value>>
@@ -48,13 +52,13 @@ export type ConditionalValue<
4852
type RequiredConditionalObject<
4953
RequiredConditionName extends string,
5054
OptionalConditionNames extends string,
51-
Value extends string | number,
55+
Value extends string | number | boolean,
5256
> = Record<RequiredConditionName, Value> &
5357
Partial<Record<OptionalConditionNames, Value>>;
5458

5559
export type RequiredConditionalValue<
5660
SprinklesProperties extends Conditions<string>,
57-
Value extends string | number,
61+
Value extends string | number | boolean,
5862
> = ExtractDefaultCondition<SprinklesProperties> extends false
5963
? never
6064
:
@@ -80,7 +84,7 @@ export function createNormalizeValueFn<
8084
SprinklesProperties extends Conditions<string>,
8185
>(
8286
properties: SprinklesProperties,
83-
): <Value extends string | number>(
87+
): <Value extends string | number | boolean>(
8488
value: ConditionalValue<SprinklesProperties, Value>,
8589
) => Partial<Record<ExtractConditionNames<SprinklesProperties>, Value>> {
8690
const { conditions } = properties;
@@ -90,7 +94,11 @@ export function createNormalizeValueFn<
9094
}
9195

9296
function normalizeValue(value: any) {
93-
if (typeof value === 'string' || typeof value === 'number') {
97+
if (
98+
typeof value === 'string' ||
99+
typeof value === 'number' ||
100+
typeof value === 'boolean'
101+
) {
94102
if (!conditions.defaultCondition) {
95103
throw new Error('No default condition');
96104
}
@@ -130,14 +138,17 @@ export function createMapValueFn<
130138
properties: SprinklesProperties,
131139
): <
132140
OutputValue extends string | number | boolean | null | undefined,
133-
Value extends ConditionalValue<SprinklesProperties, string | number>,
141+
Value extends ConditionalValue<
142+
SprinklesProperties,
143+
string | number | boolean
144+
>,
134145
>(
135146
value: Value,
136147
fn: (
137148
inputValue: ExtractValue<Value>,
138149
key: ExtractConditionNames<SprinklesProperties>,
139150
) => OutputValue,
140-
) => Value extends string | number
151+
) => Value extends string | number | boolean
141152
? OutputValue
142153
: Partial<Record<ExtractConditionNames<SprinklesProperties>, OutputValue>> {
143154
const { conditions } = properties;
@@ -149,7 +160,11 @@ export function createMapValueFn<
149160
const normalizeValue = createNormalizeValueFn(properties);
150161

151162
function mapValue(value: any, mapFn: any) {
152-
if (typeof value === 'string' || typeof value === 'number') {
163+
if (
164+
typeof value === 'string' ||
165+
typeof value === 'number' ||
166+
typeof value === 'boolean'
167+
) {
153168
if (!conditions.defaultCondition) {
154169
throw new Error('No default condition');
155170
}

tests/sprinkles/sprinkles-type-tests.ts

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ const noop = (...args: Array<any>) => {};
133133
mobille: '',
134134
});
135135

136-
function testGenericNormalizeValue<Key extends string | number>(
136+
function testGenericNormalizeValue<Key extends string | number | boolean>(
137137
value: ResponsiveValue<Key>,
138138
): Key | undefined {
139139
const normalizedValue = normalizeValue(value);
@@ -161,32 +161,45 @@ const noop = (...args: Array<any>) => {};
161161
// @ts-expect-error - Should force conditional value as no default condition
162162
mapValueWithoutDefaultCondition('test');
163163

164-
type ResponsiveValue<Value extends string | number> = ConditionalValue<
165-
typeof conditionalProperties,
166-
Value
167-
>;
164+
type ResponsiveValue<Value extends string | number | boolean> =
165+
ConditionalValue<typeof conditionalProperties, Value>;
168166

169-
let responsiveValue: ResponsiveValue<'row' | 'column'>;
167+
let responsiveValue: ResponsiveValue<'row' | 'column' | boolean>;
170168

171169
// Valid values
172170
responsiveValue = 'row';
173171
responsiveValue = 'column';
174172
responsiveValue = [null];
175173
responsiveValue = ['row', 'column'];
176174
responsiveValue = ['row', null, 'column'];
175+
responsiveValue = true;
176+
responsiveValue = false;
177+
responsiveValue = [false];
178+
responsiveValue = [false, null, true];
177179
responsiveValue = {};
178180
responsiveValue = { mobile: 'row' };
179181
responsiveValue = { tablet: 'column' };
180182
responsiveValue = { desktop: 'column' };
183+
responsiveValue = { mobile: true };
184+
responsiveValue = { mobile: false };
181185
responsiveValue = {
182186
mobile: 'row',
183187
tablet: 'column',
184188
};
189+
responsiveValue = {
190+
mobile: true,
191+
tablet: false,
192+
};
185193
responsiveValue = {
186194
mobile: 'row',
187195
tablet: 'column',
188196
desktop: 'row',
189197
};
198+
responsiveValue = {
199+
mobile: false,
200+
tablet: true,
201+
desktop: false,
202+
};
190203

191204
// Invalid values
192205
// @ts-expect-error
@@ -221,17 +234,22 @@ const noop = (...args: Array<any>) => {};
221234

222235
noop(responsiveValue);
223236

224-
type RequiredResponsiveValue<Value extends string | number> =
225-
RequiredConditionalValue<typeof conditionalProperties, Value>;
226-
227-
let requiredValue: RequiredResponsiveValue<'row' | 'column'>;
237+
let requiredValue: RequiredConditionalValue<
238+
typeof conditionalProperties,
239+
'row' | 'column' | boolean
240+
>;
228241

229242
// Valid values
230243
requiredValue = 'row';
231244
requiredValue = { mobile: 'row' };
232245
requiredValue = { mobile: 'row', desktop: 'column' };
246+
requiredValue = true;
247+
requiredValue = { mobile: false };
248+
requiredValue = { mobile: false, desktop: true };
233249
requiredValue = ['row'];
234250
requiredValue = ['row', null, 'column'];
251+
requiredValue = [false];
252+
requiredValue = [false, null, true];
235253

236254
// @ts-expect-error
237255
requiredValue = [];
@@ -242,9 +260,13 @@ const noop = (...args: Array<any>) => {};
242260
// @ts-expect-error
243261
requiredValue = [null, null, 'column'];
244262
// @ts-expect-error
263+
requiredValue = [null, null, true];
264+
// @ts-expect-error
245265
requiredValue = {};
246266
// @ts-expect-error
247267
requiredValue = { desktop: 'column' };
268+
// @ts-expect-error
269+
requiredValue = { desktop: true };
248270

249271
noop(requiredValue);
250272

tests/sprinkles/sprinkles.test.ts

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -451,13 +451,23 @@ describe('sprinkles', () => {
451451
`);
452452
});
453453

454+
it('should handle unresponsive booleans', () => {
455+
const normalizeValue = createNormalizeValueFn(conditionalProperties);
456+
457+
expect(normalizeValue(false)).toMatchInlineSnapshot(`
458+
Object {
459+
"mobile": false,
460+
}
461+
`);
462+
});
463+
454464
it('should handle responsive arrays', () => {
455465
const normalizeValue = createNormalizeValueFn(conditionalProperties);
456466

457-
expect(normalizeValue(['one', 'two'])).toMatchInlineSnapshot(`
467+
expect(normalizeValue([false, true])).toMatchInlineSnapshot(`
458468
Object {
459-
"mobile": "one",
460-
"tablet": "two",
469+
"mobile": false,
470+
"tablet": true,
461471
}
462472
`);
463473
});
@@ -477,10 +487,10 @@ describe('sprinkles', () => {
477487
it('should handle responsive arrays with nulls', () => {
478488
const normalizeValue = createNormalizeValueFn(conditionalProperties);
479489

480-
expect(normalizeValue(['one', null, 'three'])).toMatchInlineSnapshot(`
490+
expect(normalizeValue(['mobile', null, true])).toMatchInlineSnapshot(`
481491
Object {
482-
"desktop": "three",
483-
"mobile": "one",
492+
"desktop": true,
493+
"mobile": "mobile",
484494
}
485495
`);
486496
});
@@ -560,24 +570,26 @@ describe('sprinkles', () => {
560570

561571
it('should handle conditional nulls', () => {
562572
const mapValue = createMapValueFn(conditionalProperties);
563-
const value = mapValue({ mobile: 1, tablet: 2, desktop: 3 }, (value) =>
564-
value === 2 ? null : value,
573+
const value = mapValue(
574+
{ mobile: 1, tablet: false, desktop: 3 },
575+
(value) => value || null,
565576
);
566577

567578
expect(value).toStrictEqual({ mobile: 1, tablet: null, desktop: 3 });
568579
});
569580

570581
it('should handle undefined', () => {
571582
const mapValue = createMapValueFn(conditionalProperties);
572-
const value = mapValue(123, () => undefined);
583+
const value = mapValue(true, () => undefined);
573584

574585
expect(value).toBe(undefined);
575586
});
576587

577588
it('should handle conditional undefined', () => {
578589
const mapValue = createMapValueFn(conditionalProperties);
579-
const value = mapValue({ mobile: 1, tablet: 2, desktop: 3 }, (value) =>
580-
value === 2 ? undefined : value,
590+
const value = mapValue(
591+
{ mobile: 1, tablet: false, desktop: 3 },
592+
(value) => value || undefined,
581593
);
582594

583595
expect(value).toStrictEqual({ mobile: 1, tablet: undefined, desktop: 3 });
@@ -612,15 +624,15 @@ describe('sprinkles', () => {
612624
it('should handle responsive arrays', () => {
613625
const mapValue = createMapValueFn(conditionalProperties);
614626
const value = mapValue(
615-
['one', 'two', 'three'],
627+
[false, true, false],
616628
(value, key) => `${value}_${key}` as const,
617629
);
618630

619631
expect(value).toMatchInlineSnapshot(`
620632
Object {
621-
"desktop": "three_desktop",
622-
"mobile": "one_mobile",
623-
"tablet": "two_tablet",
633+
"desktop": "false_desktop",
634+
"mobile": "false_mobile",
635+
"tablet": "true_tablet",
624636
}
625637
`);
626638
});

0 commit comments

Comments
 (0)