@codeleap/styles 4.0.1

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.
Files changed (94) hide show
  1. package/dist/index.d.ts +5 -0
  2. package/dist/index.js +26 -0
  3. package/dist/lib/Cacher.d.ts +37 -0
  4. package/dist/lib/Cacher.js +104 -0
  5. package/dist/lib/StaleControl.d.ts +21 -0
  6. package/dist/lib/StaleControl.js +78 -0
  7. package/dist/lib/StyleCache.d.ts +20 -0
  8. package/dist/lib/StyleCache.js +52 -0
  9. package/dist/lib/StylePersistor.d.ts +13 -0
  10. package/dist/lib/StylePersistor.js +22 -0
  11. package/dist/lib/StyleRegistry.d.ts +46 -0
  12. package/dist/lib/StyleRegistry.js +499 -0
  13. package/dist/lib/borderCreator.d.ts +11 -0
  14. package/dist/lib/borderCreator.js +44 -0
  15. package/dist/lib/constants.d.ts +5 -0
  16. package/dist/lib/constants.js +8 -0
  17. package/dist/lib/createAppVariants.d.ts +6 -0
  18. package/dist/lib/createAppVariants.js +9 -0
  19. package/dist/lib/createStyles.d.ts +4 -0
  20. package/dist/lib/createStyles.js +27 -0
  21. package/dist/lib/createTheme.d.ts +7 -0
  22. package/dist/lib/createTheme.js +76 -0
  23. package/dist/lib/defaultVariants.d.ts +178 -0
  24. package/dist/lib/defaultVariants.js +179 -0
  25. package/dist/lib/dynamicVariants.d.ts +12 -0
  26. package/dist/lib/dynamicVariants.js +88 -0
  27. package/dist/lib/hashKey.d.ts +1 -0
  28. package/dist/lib/hashKey.js +14 -0
  29. package/dist/lib/hooks.d.ts +8 -0
  30. package/dist/lib/hooks.js +76 -0
  31. package/dist/lib/index.d.ts +10 -0
  32. package/dist/lib/index.js +37 -0
  33. package/dist/lib/mediaQuery.d.ts +11 -0
  34. package/dist/lib/mediaQuery.js +65 -0
  35. package/dist/lib/minifier.d.ts +6 -0
  36. package/dist/lib/minifier.js +21 -0
  37. package/dist/lib/multiplierProperty.d.ts +3 -0
  38. package/dist/lib/multiplierProperty.js +13 -0
  39. package/dist/lib/spacing.d.ts +11 -0
  40. package/dist/lib/spacing.js +104 -0
  41. package/dist/lib/themeStore.d.ts +7 -0
  42. package/dist/lib/themeStore.js +9 -0
  43. package/dist/lib/utils.d.ts +8 -0
  44. package/dist/lib/utils.js +172 -0
  45. package/dist/lib/validateTheme.d.ts +2 -0
  46. package/dist/lib/validateTheme.js +68 -0
  47. package/dist/types/cache.d.ts +1 -0
  48. package/dist/types/cache.js +2 -0
  49. package/dist/types/component.d.ts +25 -0
  50. package/dist/types/component.js +2 -0
  51. package/dist/types/core.d.ts +20 -0
  52. package/dist/types/core.js +2 -0
  53. package/dist/types/icon.d.ts +4 -0
  54. package/dist/types/icon.js +3 -0
  55. package/dist/types/index.d.ts +5 -0
  56. package/dist/types/index.js +21 -0
  57. package/dist/types/spacing.d.ts +6 -0
  58. package/dist/types/spacing.js +21 -0
  59. package/dist/types/style.d.ts +13 -0
  60. package/dist/types/style.js +2 -0
  61. package/dist/types/theme.d.ts +62 -0
  62. package/dist/types/theme.js +2 -0
  63. package/package.json +34 -0
  64. package/src/index.ts +7 -0
  65. package/src/lib/Cacher.ts +131 -0
  66. package/src/lib/StaleControl.ts +73 -0
  67. package/src/lib/StyleCache.ts +69 -0
  68. package/src/lib/StylePersistor.ts +28 -0
  69. package/src/lib/StyleRegistry.ts +549 -0
  70. package/src/lib/borderCreator.ts +42 -0
  71. package/src/lib/constants.ts +6 -0
  72. package/src/lib/createAppVariants.ts +12 -0
  73. package/src/lib/createStyles.ts +32 -0
  74. package/src/lib/createTheme.ts +89 -0
  75. package/src/lib/defaultVariants.ts +180 -0
  76. package/src/lib/dynamicVariants.ts +83 -0
  77. package/src/lib/hashKey.ts +12 -0
  78. package/src/lib/hooks.ts +52 -0
  79. package/src/lib/index.ts +11 -0
  80. package/src/lib/mediaQuery.ts +70 -0
  81. package/src/lib/minifier.ts +20 -0
  82. package/src/lib/multiplierProperty.ts +13 -0
  83. package/src/lib/spacing.ts +83 -0
  84. package/src/lib/themeStore.ts +14 -0
  85. package/src/lib/utils.ts +74 -0
  86. package/src/lib/validateTheme.ts +22 -0
  87. package/src/types/cache.ts +2 -0
  88. package/src/types/component.ts +40 -0
  89. package/src/types/core.ts +40 -0
  90. package/src/types/icon.ts +8 -0
  91. package/src/types/index.ts +5 -0
  92. package/src/types/spacing.ts +35 -0
  93. package/src/types/style.ts +41 -0
  94. package/src/types/theme.ts +77 -0
@@ -0,0 +1,549 @@
1
+ /* eslint-disable dot-notation */
2
+ import { AnyRecord, AnyStyledComponent, ICSS, ITheme, StyleProp, VariantStyleSheet } from '../types'
3
+ import { ThemeStore, themeStore } from './themeStore'
4
+ import deepmerge from '@fastify/deepmerge'
5
+ import { MultiplierFunction } from './spacing'
6
+ import { defaultVariants } from './defaultVariants'
7
+ import { dynamicVariants } from './dynamicVariants'
8
+ import { ignoredStyleKeys, isSpacingKey } from './utils'
9
+ import { StyleCache } from './StyleCache'
10
+ import { minifier } from './minifier'
11
+ import { StateStorage } from 'zustand/middleware'
12
+
13
+ export class CodeleapStyleRegistry {
14
+ stylesheets: Record<string, VariantStyleSheet> = {}
15
+
16
+ commonVariants: Record<string, ICSS | MultiplierFunction> = {}
17
+
18
+ components: Record<string, AnyStyledComponent> = {}
19
+
20
+ private theme: ThemeStore
21
+
22
+ private styleCache: StyleCache
23
+
24
+ constructor(storage: StateStorage) {
25
+ this.styleCache = new StyleCache(storage)
26
+
27
+ this.theme = themeStore.getState()
28
+
29
+ this.registerCommonVariants()
30
+
31
+ const currentColorScheme = this.theme?.current?.['currentColorScheme'] ?? this.theme?.colorScheme ?? 'default'
32
+
33
+ this.styleCache.registerBaseKey([currentColorScheme, this.theme.current, this.commonVariants])
34
+ }
35
+
36
+ computeCommonVariantStyle(componentName: string, variant: string, component = null) {
37
+ const cache = this.styleCache.keyFor('common', variant)
38
+
39
+ if (!!cache.value) {
40
+ return {
41
+ [component]: this.createStyle(cache.value),
42
+ }
43
+ }
44
+
45
+ const theme = this.theme.current
46
+
47
+ let mediaQuery = null
48
+
49
+ let [variantName, value] = variant?.includes(':') ? variant?.split(':') : [variant, null]
50
+
51
+ // @ts-expect-error
52
+ if (!!theme?.breakpoints[variantName]) {
53
+ const [breakpoint, _variantName, _value] = variant?.split(':')?.length == 2 ? [...variant?.split(':'), null] : variant?.split(':')
54
+
55
+ // @ts-expect-error
56
+ mediaQuery = theme.media.down(breakpoint)
57
+ value = _value
58
+ variantName = _variantName
59
+ }
60
+
61
+ const variantStyle = this.commonVariants[variantName] ?? this.commonVariants[variant]
62
+
63
+ let style = null
64
+
65
+ if (typeof variantStyle == 'function') {
66
+ style = isSpacingKey(variantName) ? variantStyle(value) : variantStyle(theme, value)
67
+ } else {
68
+ style = variantStyle
69
+ }
70
+
71
+ if (!style) return null
72
+
73
+ if (!!mediaQuery) {
74
+ style = {
75
+ [mediaQuery]: style,
76
+ }
77
+ }
78
+
79
+ const commonStyles = {
80
+ [component]: this.createStyle(style),
81
+ }
82
+
83
+ this.styleCache.cacheFor('common', cache.key, style)
84
+
85
+ return commonStyles
86
+ }
87
+
88
+ computeVariantStyle(componentName: string, variants: string[], _component = null): ICSS {
89
+ const { rootElement } = this.getRegisteredComponent(componentName)
90
+
91
+ const component = _component ?? rootElement
92
+
93
+ const stylesheet = minifier.decompress(this.stylesheets[componentName])
94
+
95
+ const cache = this.styleCache.keyFor('variants', { componentName, component, stylesheet, variants })
96
+
97
+ if (!!cache.value) {
98
+ return cache.value
99
+ }
100
+
101
+ const theme = this.theme.current
102
+
103
+ const variantStyles = variants.map((variant) => {
104
+ if (!!stylesheet[variant]) {
105
+ return stylesheet[variant]
106
+ }
107
+
108
+ const [breakpoint, variantName] = variant?.includes(':') ? variant?.split(':') : []
109
+
110
+ // @ts-ignore
111
+ if (!!theme?.breakpoints[breakpoint] && !!stylesheet[variantName]) {
112
+ // @ts-ignore
113
+ const mediaQuery = theme.media.down(breakpoint)
114
+
115
+ return {
116
+ [component]: this.createStyle({
117
+ [mediaQuery]: stylesheet[variantName][component],
118
+ }),
119
+ }
120
+ }
121
+
122
+ return this.computeCommonVariantStyle(componentName, variant, component)
123
+ }).filter(variantStyle => !!variantStyle)
124
+
125
+ const variantStyle = deepmerge({ all: true })(...variantStyles)
126
+
127
+ this.styleCache.cacheFor('variants', cache.key, variantStyle)
128
+
129
+ return variantStyle
130
+ }
131
+
132
+ isCompositionStyle(component: AnyStyledComponent, style: any) {
133
+ const composition = {}
134
+
135
+ if (!style) {
136
+ return {
137
+ isComposition: false,
138
+ composition,
139
+ }
140
+ }
141
+
142
+ const styleKeys = Object.keys(style)
143
+
144
+ let elements = []
145
+
146
+ for (const element of component?.elements) {
147
+ const componentElements = styleKeys?.filter(k => k?.startsWith(element) && !ignoredStyleKeys?.includes(k))
148
+
149
+ if (componentElements?.length >= 1) {
150
+ elements = [...elements, ...componentElements]
151
+ }
152
+ }
153
+
154
+ for (const element of elements) {
155
+ composition[element] = style[element]
156
+ }
157
+
158
+ return {
159
+ isComposition: elements?.length >= 1,
160
+ composition,
161
+ }
162
+ }
163
+
164
+ isResponsiveStyle(style: any) {
165
+ const responsiveStyleKey = 'breakpoints'
166
+
167
+ if (!style) {
168
+ return {
169
+ responsiveStyleKey,
170
+ isResponsive: false,
171
+ }
172
+ }
173
+
174
+ return {
175
+ responsiveStyleKey,
176
+ isResponsive: !!style[responsiveStyleKey],
177
+ }
178
+ }
179
+
180
+ getDefaultVariantStyle(componentName: string, defaultVariantStyleName = 'default') {
181
+ const stylesheet = minifier.decompress(this.stylesheets[componentName])
182
+
183
+ const defaultStyle = stylesheet?.[defaultVariantStyleName]
184
+
185
+ if (!!defaultStyle) {
186
+ return defaultStyle
187
+ } else {
188
+ return {}
189
+ }
190
+ }
191
+
192
+ mergeStylesWithCache<T = unknown>(styles: ICSS[], key: string): T {
193
+ const mergedStyles = deepmerge({ all: true })(...styles)
194
+
195
+ this.styleCache.cacheFor('components', key, mergedStyles)
196
+
197
+ return mergedStyles as T
198
+ }
199
+
200
+ getRegisteredComponent(componentName: string) {
201
+ const registeredComponent = this.components[componentName]
202
+
203
+ if (!registeredComponent) {
204
+ throw new Error(`Component ${componentName} not registered`)
205
+ }
206
+
207
+ const rootElement = registeredComponent?.rootElement ?? 'wrapper'
208
+
209
+ return {
210
+ rootElement,
211
+ registeredComponent,
212
+ }
213
+ }
214
+
215
+ getResponsiveStyle(componentName: string, responsiveStyleKey: string, style: object) {
216
+ const responsiveStyles = style[responsiveStyleKey]
217
+
218
+ if (!responsiveStyles) return {}
219
+
220
+ const stylesheet = minifier.decompress(this.stylesheets[componentName])
221
+
222
+ const cache = this.styleCache.keyFor('responsive', { componentName, responsiveStyles, stylesheet })
223
+
224
+ if (!!cache.value) {
225
+ return cache.value
226
+ }
227
+
228
+ const styles = {}
229
+
230
+ for (const responsiveStyle in responsiveStyles) {
231
+ const mediaQuery = this.getMediaQuery(responsiveStyle)
232
+
233
+ const breakpointStyle = responsiveStyles[responsiveStyle]
234
+
235
+ const componentStyles = this.styleFor(componentName, breakpointStyle, false)
236
+
237
+ // @ts-ignore
238
+ for (const composition in componentStyles) {
239
+ styles[composition] = {
240
+ [mediaQuery]: componentStyles[composition],
241
+ }
242
+ }
243
+ }
244
+
245
+ this.styleCache.cacheFor('responsive', cache.key, styles)
246
+
247
+ return styles
248
+ }
249
+
250
+ getStyles(componentName: string, _style: any, component?: any, predicateObj?: (style: any) => any) {
251
+ let styles = {}
252
+
253
+ const style = typeof _style == 'string' ? [_style] : _style
254
+
255
+ if (Array.isArray(style)) {
256
+ const variants = []
257
+
258
+ for (const s of style) {
259
+ if (typeof s === 'string') {
260
+ variants.push(s)
261
+ } else {
262
+ styles = deepmerge({ all: true })(styles, !!predicateObj ? predicateObj(s) : s)
263
+ }
264
+ }
265
+
266
+ if (variants?.length >= 1) {
267
+ const computedVariantStyle = this.computeVariantStyle(
268
+ componentName,
269
+ variants,
270
+ component,
271
+ )
272
+
273
+ styles = deepmerge({ all: true })(styles, computedVariantStyle[component])
274
+ }
275
+ } else if (typeof style === 'object') {
276
+ styles = !!predicateObj ? predicateObj(style) : style
277
+ }
278
+
279
+ return styles
280
+ }
281
+
282
+ private getMediaQuery(responsiveKey: string) {
283
+ const [breakpoint, query] = responsiveKey?.includes(':') ? responsiveKey?.split(':') : [responsiveKey, 'down']
284
+
285
+ // @ts-expect-error - media not has type
286
+ const mediaQuery = this.theme.current.media?.[query]?.(breakpoint)
287
+
288
+ return mediaQuery
289
+ }
290
+
291
+ getStyleWithResponsive(componentName: string, style: any, component?: any) {
292
+ if (!style) return style
293
+
294
+ const { isResponsive, responsiveStyleKey } = this.isResponsiveStyle(style)
295
+
296
+ if (isResponsive) {
297
+ let responsiveStyles = {}
298
+
299
+ for (const responsiveStyle in style[responsiveStyleKey]) {
300
+ const mediaQuery = this.getMediaQuery(responsiveStyle)
301
+
302
+ const breakpointStyle = style[responsiveStyleKey][responsiveStyle]
303
+
304
+ responsiveStyles = deepmerge({ all: true })(responsiveStyles, {
305
+ [mediaQuery]: this.getStyles(componentName, breakpointStyle, component),
306
+ })
307
+ }
308
+
309
+ delete style[responsiveStyleKey]
310
+
311
+ return deepmerge({ all: true })(style, responsiveStyles)
312
+ } else {
313
+ return style
314
+ }
315
+ }
316
+
317
+ getCompositionStyle(componentName: string, composition: Record<string, any>, style: any) {
318
+ const cache = this.styleCache.keyFor('compositions', { componentName, composition, style })
319
+
320
+ if (!!cache.value) {
321
+ return cache.value
322
+ }
323
+
324
+ const styles = []
325
+
326
+ for (const component in composition) {
327
+ const componentStyles = composition[component]
328
+
329
+ const componentStyle = this.getStyles(
330
+ componentName,
331
+ componentStyles,
332
+ component,
333
+ s => this.getStyleWithResponsive(componentName, s, component),
334
+ )
335
+
336
+ styles.push({ [component]: componentStyle })
337
+
338
+ delete style[component]
339
+ }
340
+
341
+ this.styleCache.cacheFor('compositions', cache.key, styles)
342
+
343
+ return styles
344
+ }
345
+
346
+ styleFor<T = unknown>(componentName: string, componentStyle: StyleProp<T>, mergeWithDefaultStyle = true): T {
347
+ const cache = this.styleCache.keyFor('components', { componentName, componentStyle, stylesheet: this.stylesheets[componentName] })
348
+
349
+ if (!!cache.value) {
350
+ return cache.value as T
351
+ }
352
+
353
+ const style = this.copyStyle(componentStyle)
354
+
355
+ const isStyleArray = Array.isArray(style)
356
+
357
+ const { rootElement, registeredComponent } = this.getRegisteredComponent(componentName)
358
+ const defaultStyle = mergeWithDefaultStyle ? this.getDefaultVariantStyle(componentName) : {}
359
+
360
+ if (!style) {
361
+ return this.mergeStylesWithCache([defaultStyle], cache.key)
362
+ }
363
+
364
+ const isStyleObject = typeof style === 'object' && !isStyleArray
365
+
366
+ if (typeof style === 'string') {
367
+ const computedVariantStyle = this.computeVariantStyle(componentName, [style])
368
+
369
+ return this.mergeStylesWithCache(
370
+ [defaultStyle, computedVariantStyle],
371
+ cache.key,
372
+ )
373
+ }
374
+
375
+ if (isStyleObject) {
376
+ const { isComposition, composition } = this.isCompositionStyle(registeredComponent, style)
377
+
378
+ const { isResponsive, responsiveStyleKey } = this.isResponsiveStyle(style)
379
+
380
+ const responsiveStyles = this.getResponsiveStyle(componentName, responsiveStyleKey, style)
381
+
382
+ if (isResponsive) {
383
+ delete style[responsiveStyleKey]
384
+ }
385
+
386
+ if (isComposition) {
387
+ const compositionStyles = this.getCompositionStyle(componentName, composition, style)
388
+
389
+ const styles = [defaultStyle, responsiveStyles, ...compositionStyles]
390
+
391
+ styles.push({ [rootElement]: style })
392
+
393
+ return this.mergeStylesWithCache(styles, cache.key)
394
+ } else {
395
+ return this.mergeStylesWithCache(
396
+ [defaultStyle, responsiveStyles, { [rootElement]: style }],
397
+ cache.key,
398
+ )
399
+ }
400
+ }
401
+
402
+ if (isStyleArray) {
403
+ const filteredStyle = (style as Array<any>)?.filter(s => !!s)
404
+
405
+ const variants: string[] = []
406
+ const styles: ICSS[] = [defaultStyle]
407
+ let idx = 0
408
+
409
+ for (const s of filteredStyle) {
410
+ if (typeof s === 'string') {
411
+ variants.push(s)
412
+ }
413
+
414
+ if (typeof s === 'object') {
415
+ const { isComposition, composition } = this.isCompositionStyle(registeredComponent, s)
416
+
417
+ if (isComposition) {
418
+ const compositionStyles = this.getCompositionStyle(componentName, composition, s)
419
+
420
+ styles.push(...compositionStyles)
421
+ }
422
+
423
+ const { isResponsive, responsiveStyleKey } = this.isResponsiveStyle(s)
424
+
425
+ if (isResponsive) {
426
+ const responsiveStyles = this.getResponsiveStyle(componentName, responsiveStyleKey, s)
427
+
428
+ styles.push(responsiveStyles)
429
+
430
+ delete s[responsiveStyleKey]
431
+ }
432
+
433
+ styles.push({ [rootElement]: s })
434
+ }
435
+
436
+ if (idx === filteredStyle.length - 1 && variants.length > 0) {
437
+ const computedVariantStyle = this.computeVariantStyle(componentName, variants)
438
+ styles.push(computedVariantStyle)
439
+ }
440
+
441
+ idx++
442
+ }
443
+
444
+ return this.mergeStylesWithCache(styles, cache.key)
445
+ }
446
+
447
+ console.warn('Invalid style prop for ', componentName, style)
448
+
449
+ return {} as T
450
+ }
451
+
452
+ registerCommonVariants() {
453
+ const spacingVariants = this.theme.current?.['spacing']
454
+
455
+ const insetVariants = this.theme.current?.['inset']
456
+
457
+ const appVariants = this.theme.variants
458
+
459
+ const commonVariants = deepmerge({ all: true })(
460
+ defaultVariants,
461
+ appVariants,
462
+ dynamicVariants,
463
+ spacingVariants,
464
+ insetVariants,
465
+ )
466
+
467
+ this.commonVariants = commonVariants
468
+ }
469
+
470
+ registerVariants(componentName: string, variants: VariantStyleSheet) {
471
+ if (this.stylesheets[componentName]) {
472
+ throw new Error(`Variants for ${componentName} already registered`)
473
+ }
474
+
475
+ this.stylesheets[componentName] = minifier.compress(variants)
476
+ }
477
+
478
+ registerComponent(component: AnyStyledComponent) {
479
+ const componentData = {
480
+ styleRegistryName: component?.styleRegistryName,
481
+ elements: component?.elements,
482
+ rootElement: component?.rootElement,
483
+ }
484
+
485
+ this.components[component.styleRegistryName] = componentData as any
486
+ }
487
+
488
+ /**
489
+ * These should be overwritten by the end-user to support
490
+ * custom style merging logic, such as StyleSheet.flatten
491
+ */
492
+ createStyle(css: ICSS): ICSS {
493
+ throw new Error('createStyle: Not implemented')
494
+ }
495
+
496
+ update() {
497
+ this.theme = themeStore.getState()
498
+
499
+ const currentColorScheme = this.theme?.current?.['currentColorScheme'] ?? this.theme?.colorScheme ?? 'default'
500
+
501
+ this.styleCache.registerBaseKey([currentColorScheme, this.theme.current, this.commonVariants])
502
+ }
503
+
504
+ private copyStyle(style: any) {
505
+ let copiedStyle = null
506
+
507
+ if (Array.isArray(style)) {
508
+ copiedStyle = [...style]
509
+ } else if (typeof style == 'object') {
510
+ copiedStyle = {...style}
511
+ } else {
512
+ copiedStyle = style
513
+ }
514
+
515
+ return copiedStyle
516
+ }
517
+
518
+ createStyles<K extends string = string>(styles: Record<K, StyleProp<AnyRecord, ''>> | ((theme: ITheme) => Record<K, StyleProp<AnyRecord, ''>>)): Record<K, ICSS> {
519
+ const compute = () => {
520
+ const current = themeStore.getState().current
521
+
522
+ const stylesObj = typeof styles === 'function' ? styles(current) : styles
523
+
524
+ const cache = this.styleCache.keyFor('styles', stylesObj)
525
+
526
+ if (!!cache.value) {
527
+ return cache.value
528
+ }
529
+
530
+ const createdStyles = {} as Record<K, any>
531
+
532
+ for (const key in stylesObj) {
533
+ const style = this.styleFor('MyComponent', stylesObj[key], false)
534
+
535
+ createdStyles[key] = style?.wrapper ?? style
536
+ }
537
+
538
+ this.styleCache.cacheFor('styles', cache.key, createdStyles)
539
+
540
+ return createdStyles
541
+ }
542
+
543
+ return new Proxy(compute(), {
544
+ get(target, prop) {
545
+ return compute()[prop as string]
546
+ },
547
+ })
548
+ }
549
+ }
@@ -0,0 +1,42 @@
1
+ import { IColors, ICSS } from '../types'
2
+ import { borderDirection } from './dynamicVariants'
3
+ import { themeStore } from './themeStore'
4
+ import { capitalize } from './utils'
5
+
6
+ type BorderCreatorArgs = {
7
+ color: keyof IColors | (string & {})
8
+ width?: number | string
9
+ directions?: typeof borderDirection[number][]
10
+ // @ts-expect-error borderStyle not exists
11
+ style?: ICSS['borderStyle']
12
+ }
13
+
14
+ export type BorderCreator = (args: BorderCreatorArgs) => ICSS
15
+
16
+ export const borderCreator: BorderCreator = (args) => {
17
+ const {
18
+ color: colorKey,
19
+ width = 1,
20
+ style = 'solid',
21
+ directions = ['left', 'top', 'bottom', 'right']
22
+ } = args
23
+
24
+ const theme = themeStore.getState().current
25
+
26
+ const color = theme?.['colors']?.[colorKey] ?? colorKey
27
+
28
+ const borderStyles: ICSS = {}
29
+
30
+ for (const direction of directions) {
31
+ const property = `border${capitalize(direction)}`
32
+
33
+ borderStyles[`${property}Color`] = color
34
+ borderStyles[`${property}Width`] = width
35
+
36
+ if (typeof localStorage !== 'undefined') {
37
+ borderStyles[`${property}Style`] = style
38
+ }
39
+ }
40
+
41
+ return borderStyles
42
+ }
@@ -0,0 +1,6 @@
1
+
2
+ export const StyleConstants = {
3
+ STORES_PERSIST_VERSION: 1,
4
+ STORE_CACHE_ENABLED: true,
5
+ CACHE_ENABLED: true,
6
+ }
@@ -0,0 +1,12 @@
1
+ import { ICSS, ITheme } from '../types'
2
+ import { themeStore } from './themeStore'
3
+
4
+ type AppVariantsMap = {
5
+ [x: string]: ICSS | ((theme: ITheme) => ICSS)
6
+ }
7
+
8
+ export function createAppVariants<T extends AppVariantsMap>(variants: T) {
9
+ themeStore.setState({ variants })
10
+
11
+ return variants
12
+ }
@@ -0,0 +1,32 @@
1
+ import { ICSS, ITheme, AnyRecord } from '../types'
2
+ import { themeStore } from './themeStore'
3
+
4
+ type StylesShape<K extends string, P extends AnyRecord> = Partial<Record<K, ICSS & Partial<P>>>
5
+
6
+ export function createStyles<K extends string, P extends AnyRecord = AnyRecord>(
7
+ styles: StylesShape<K, P> | ((theme: ITheme) => StylesShape<K, P>),
8
+ ) {
9
+
10
+ const compute = () => {
11
+ let styleObj = {} as StylesShape<K, P>
12
+ const current = themeStore.getState().current
13
+
14
+ if (typeof styles === 'function') {
15
+ styleObj = styles(current)
16
+ } else {
17
+ styleObj = styles
18
+ }
19
+
20
+ return styleObj
21
+ }
22
+
23
+ // We use a proxy here so that the color scheme is recomputed every time the
24
+ // theme changes. This is necessary because the theme is a singleton which does not cause
25
+ // a re-render when it changes. The end-user will only have to worry about remounting the root component
26
+ // when the theme changes in order to get the new color scheme due to this proxy.
27
+ return new Proxy(compute() as StylesShape<K, P>, {
28
+ get(target, prop) {
29
+ return compute()[prop as string]
30
+ },
31
+ })
32
+ }