or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

conditional-value-utilities.mdindex.mdproperty-definition.mdruntime-sprinkles.mdsprinkles-creation.md

conditional-value-utilities.mddocs/

0

# Conditional Value Utilities

1

2

Helper functions for working with conditional values in responsive and theme-based styling scenarios. These utilities provide functions for mapping and normalizing conditional values.

3

4

## Capabilities

5

6

### createMapValueFn

7

8

Creates a function for mapping over conditional values. This is useful for converting high-level prop values to low-level sprinkles, e.g. converting left/right to flex-start/end.

9

10

```typescript { .api }

11

/**

12

* Creates a function for mapping over conditional values

13

* @param properties - Sprinkles properties configuration with conditions

14

* @returns Map value function that can transform conditional values

15

*/

16

function createMapValueFn<SprinklesProperties extends Conditions<string>>(

17

properties: SprinklesProperties

18

): <

19

OutputValue extends string | number | boolean | null | undefined,

20

Value extends ConditionalValue<SprinklesProperties, string | number | boolean>

21

>(

22

value: Value,

23

fn: (

24

inputValue: ExtractValue<Value>,

25

key: ExtractConditionNames<SprinklesProperties>

26

) => OutputValue

27

) => Value extends string | number | boolean

28

? OutputValue

29

: Partial<Record<ExtractConditionNames<SprinklesProperties>, OutputValue>>;

30

31

/**

32

* Extract condition names from sprinkles properties

33

*/

34

type ExtractConditionNames<SprinklesProperties extends Conditions<string>> =

35

SprinklesProperties['conditions']['conditionNames'][number];

36

37

/**

38

* Extract value type from conditional value

39

*/

40

type ExtractValue<Value> = Value extends ResponsiveArrayByMaxLength<number, infer T>

41

? NonNullable<T>

42

: Value extends Partial<Record<string, infer T>>

43

? NonNullable<T>

44

: Value;

45

```

46

47

### createNormalizeValueFn

48

49

Creates a function for normalizing conditional values into a consistent object structure. Any primitive values or responsive arrays will be converted to conditional objects.

50

51

```typescript { .api }

52

/**

53

* Creates a function for normalizing conditional values into consistent object structure

54

* @param properties - Sprinkles properties configuration with conditions

55

* @returns Normalize function that converts values to conditional objects

56

*/

57

function createNormalizeValueFn<SprinklesProperties extends Conditions<string>>(

58

properties: SprinklesProperties

59

): <Value extends string | number | boolean>(

60

value: ConditionalValue<SprinklesProperties, Value>

61

) => Partial<Record<ExtractConditionNames<SprinklesProperties>, Value>>;

62

63

/**

64

* Conditions interface for type constraints

65

*/

66

type Conditions<ConditionName extends string> = {

67

conditions: {

68

defaultCondition: ConditionName | false;

69

conditionNames: Array<ConditionName>;

70

responsiveArray?: Array<ConditionName>;

71

};

72

};

73

74

/**

75

* Required conditional object type for strict conditional values

76

*/

77

type RequiredConditionalObject<

78

RequiredConditionName extends string,

79

OptionalConditionNames extends string,

80

Value extends string | number | boolean

81

> = Record<RequiredConditionName, Value> &

82

Partial<Record<OptionalConditionNames, Value>>;

83

```

84

85

## Usage Examples

86

87

**Setting up utility functions:**

88

89

```typescript

90

import {

91

defineProperties,

92

createSprinkles,

93

createMapValueFn,

94

createNormalizeValueFn

95

} from "@vanilla-extract/sprinkles";

96

97

const responsiveProperties = defineProperties({

98

conditions: {

99

mobile: {},

100

tablet: { '@media': 'screen and (min-width: 768px)' },

101

desktop: { '@media': 'screen and (min-width: 1024px)' }

102

},

103

defaultCondition: 'mobile',

104

responsiveArray: ['mobile', 'tablet', 'desktop'],

105

properties: {

106

display: ['flex', 'block', 'none'],

107

alignItems: ['flex-start', 'center', 'flex-end', 'stretch']

108

}

109

});

110

111

export const sprinkles = createSprinkles(responsiveProperties);

112

export const mapResponsiveValue = createMapValueFn(responsiveProperties);

113

export const normalizeResponsiveValue = createNormalizeValueFn(responsiveProperties);

114

```

115

116

**Mapping values with createMapValueFn:**

117

118

```typescript

119

import { mapResponsiveValue } from './sprinkles.css';

120

121

// Define mapping for semantic alignment values

122

const alignToFlexAlign = {

123

left: 'flex-start',

124

center: 'center',

125

right: 'flex-end',

126

stretch: 'stretch'

127

} as const;

128

129

// Map primitive value

130

const mapped = mapResponsiveValue(

131

'left',

132

(value) => alignToFlexAlign[value]

133

);

134

// Result: 'flex-start'

135

136

// Map conditional object

137

const mappedConditional = mapResponsiveValue(

138

{

139

mobile: 'center',

140

desktop: 'left'

141

} as const,

142

(value) => alignToFlexAlign[value]

143

);

144

// Result: { mobile: 'center', desktop: 'flex-start' }

145

146

// Map responsive array

147

const mappedArray = mapResponsiveValue(

148

['center', null, 'left'] as const,

149

(value) => alignToFlexAlign[value]

150

);

151

// Result: { mobile: 'center', desktop: 'flex-start' }

152

153

// Access both value and condition in mapper

154

const mappedWithCondition = mapResponsiveValue(

155

{ mobile: 'small', desktop: 'large' },

156

(value, condition) => `${condition}-${value}`

157

);

158

// Result: { mobile: 'mobile-small', desktop: 'desktop-large' }

159

```

160

161

**Normalizing values with createNormalizeValueFn:**

162

163

```typescript

164

import { normalizeResponsiveValue } from './sprinkles.css';

165

166

// Normalize primitive value

167

const normalized = normalizeResponsiveValue('block');

168

// Result: { mobile: 'block' }

169

170

// Normalize responsive array

171

const normalizedArray = normalizeResponsiveValue(['none', null, 'block']);

172

// Result: { mobile: 'none', desktop: 'block' }

173

174

// Normalize conditional object (already normalized)

175

const normalizedObject = normalizeResponsiveValue({

176

mobile: 'none',

177

desktop: 'block'

178

});

179

// Result: { mobile: 'none', desktop: 'block' }

180

```

181

182

**Building higher-level component APIs:**

183

184

```typescript

185

import { mapResponsiveValue, sprinkles } from './sprinkles.css';

186

187

// Define semantic alignment API

188

type Alignment = 'left' | 'center' | 'right' | 'stretch';

189

type ResponsiveAlignment = Alignment | {

190

mobile?: Alignment;

191

tablet?: Alignment;

192

desktop?: Alignment;

193

} | [Alignment?, Alignment?, Alignment?];

194

195

function createAlignmentStyles(alignment: ResponsiveAlignment) {

196

const alignToFlex = {

197

left: 'flex-start',

198

center: 'center',

199

right: 'flex-end',

200

stretch: 'stretch'

201

} as const;

202

203

const flexAlignment = mapResponsiveValue(

204

alignment,

205

(value) => alignToFlex[value]

206

);

207

208

return sprinkles({

209

display: 'flex',

210

alignItems: flexAlignment

211

});

212

}

213

214

// Usage

215

const leftAligned = createAlignmentStyles('left');

216

const responsiveAligned = createAlignmentStyles({

217

mobile: 'center',

218

desktop: 'left'

219

});

220

const arrayAligned = createAlignmentStyles(['center', 'left', 'right']);

221

```

222

223

**Complex value transformations:**

224

225

```typescript

226

import { mapResponsiveValue } from './sprinkles.css';

227

228

// Transform spacing values

229

const spaceScale = {

230

xs: '4px',

231

sm: '8px',

232

md: '16px',

233

lg: '24px',

234

xl: '32px'

235

} as const;

236

237

function transformSpacing(space: any) {

238

return mapResponsiveValue(space, (value) => {

239

if (typeof value === 'number') {

240

return `${value}px`;

241

}

242

return spaceScale[value] || value;

243

});

244

}

245

246

// Usage

247

const spacing = transformSpacing({

248

mobile: 'sm',

249

tablet: 16,

250

desktop: 'lg'

251

});

252

// Result: { mobile: '8px', tablet: '16px', desktop: '24px' }

253

```

254

255

**Conditional theme mapping:**

256

257

```typescript

258

import { mapResponsiveValue } from './sprinkles.css';

259

260

// Theme-aware color mapping

261

const colorThemes = {

262

light: {

263

primary: '#007bff',

264

secondary: '#6c757d',

265

background: '#ffffff'

266

},

267

dark: {

268

primary: '#66b3ff',

269

secondary: '#9ca3af',

270

background: '#1a1a1a'

271

}

272

} as const;

273

274

function mapThemeColors(colorValue: any, theme: 'light' | 'dark') {

275

return mapResponsiveValue(colorValue, (value, condition) => {

276

// You could use condition to determine theme per breakpoint

277

return colorThemes[theme][value] || value;

278

});

279

}

280

281

// Usage

282

const themedColor = mapThemeColors(

283

{ mobile: 'primary', desktop: 'secondary' },

284

'dark'

285

);

286

// Result: { mobile: '#66b3ff', desktop: '#9ca3af' }

287

```

288

289

**Type-safe custom conditional values:**

290

291

```typescript

292

import { ConditionalValue } from "@vanilla-extract/sprinkles";

293

294

// Create custom conditional value types

295

export type ResponsiveValue<Value extends string | number> =

296

ConditionalValue<typeof responsiveProperties, Value>;

297

298

// Usage in component props

299

interface BoxProps {

300

align?: ResponsiveValue<'left' | 'center' | 'right'>;

301

spacing?: ResponsiveValue<'sm' | 'md' | 'lg'>;

302

}

303

304

function Box({ align = 'left', spacing = 'md' }: BoxProps) {

305

const alignmentClass = createAlignmentStyles(align);

306

const spacingValue = transformSpacing(spacing);

307

308

return sprinkles({

309

className: alignmentClass,

310

padding: spacingValue

311

});

312

}

313

```