@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.
- package/dist/index.d.ts +5 -0
- package/dist/index.js +26 -0
- package/dist/lib/Cacher.d.ts +37 -0
- package/dist/lib/Cacher.js +104 -0
- package/dist/lib/StaleControl.d.ts +21 -0
- package/dist/lib/StaleControl.js +78 -0
- package/dist/lib/StyleCache.d.ts +20 -0
- package/dist/lib/StyleCache.js +52 -0
- package/dist/lib/StylePersistor.d.ts +13 -0
- package/dist/lib/StylePersistor.js +22 -0
- package/dist/lib/StyleRegistry.d.ts +46 -0
- package/dist/lib/StyleRegistry.js +499 -0
- package/dist/lib/borderCreator.d.ts +11 -0
- package/dist/lib/borderCreator.js +44 -0
- package/dist/lib/constants.d.ts +5 -0
- package/dist/lib/constants.js +8 -0
- package/dist/lib/createAppVariants.d.ts +6 -0
- package/dist/lib/createAppVariants.js +9 -0
- package/dist/lib/createStyles.d.ts +4 -0
- package/dist/lib/createStyles.js +27 -0
- package/dist/lib/createTheme.d.ts +7 -0
- package/dist/lib/createTheme.js +76 -0
- package/dist/lib/defaultVariants.d.ts +178 -0
- package/dist/lib/defaultVariants.js +179 -0
- package/dist/lib/dynamicVariants.d.ts +12 -0
- package/dist/lib/dynamicVariants.js +88 -0
- package/dist/lib/hashKey.d.ts +1 -0
- package/dist/lib/hashKey.js +14 -0
- package/dist/lib/hooks.d.ts +8 -0
- package/dist/lib/hooks.js +76 -0
- package/dist/lib/index.d.ts +10 -0
- package/dist/lib/index.js +37 -0
- package/dist/lib/mediaQuery.d.ts +11 -0
- package/dist/lib/mediaQuery.js +65 -0
- package/dist/lib/minifier.d.ts +6 -0
- package/dist/lib/minifier.js +21 -0
- package/dist/lib/multiplierProperty.d.ts +3 -0
- package/dist/lib/multiplierProperty.js +13 -0
- package/dist/lib/spacing.d.ts +11 -0
- package/dist/lib/spacing.js +104 -0
- package/dist/lib/themeStore.d.ts +7 -0
- package/dist/lib/themeStore.js +9 -0
- package/dist/lib/utils.d.ts +8 -0
- package/dist/lib/utils.js +172 -0
- package/dist/lib/validateTheme.d.ts +2 -0
- package/dist/lib/validateTheme.js +68 -0
- package/dist/types/cache.d.ts +1 -0
- package/dist/types/cache.js +2 -0
- package/dist/types/component.d.ts +25 -0
- package/dist/types/component.js +2 -0
- package/dist/types/core.d.ts +20 -0
- package/dist/types/core.js +2 -0
- package/dist/types/icon.d.ts +4 -0
- package/dist/types/icon.js +3 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +21 -0
- package/dist/types/spacing.d.ts +6 -0
- package/dist/types/spacing.js +21 -0
- package/dist/types/style.d.ts +13 -0
- package/dist/types/style.js +2 -0
- package/dist/types/theme.d.ts +62 -0
- package/dist/types/theme.js +2 -0
- package/package.json +34 -0
- package/src/index.ts +7 -0
- package/src/lib/Cacher.ts +131 -0
- package/src/lib/StaleControl.ts +73 -0
- package/src/lib/StyleCache.ts +69 -0
- package/src/lib/StylePersistor.ts +28 -0
- package/src/lib/StyleRegistry.ts +549 -0
- package/src/lib/borderCreator.ts +42 -0
- package/src/lib/constants.ts +6 -0
- package/src/lib/createAppVariants.ts +12 -0
- package/src/lib/createStyles.ts +32 -0
- package/src/lib/createTheme.ts +89 -0
- package/src/lib/defaultVariants.ts +180 -0
- package/src/lib/dynamicVariants.ts +83 -0
- package/src/lib/hashKey.ts +12 -0
- package/src/lib/hooks.ts +52 -0
- package/src/lib/index.ts +11 -0
- package/src/lib/mediaQuery.ts +70 -0
- package/src/lib/minifier.ts +20 -0
- package/src/lib/multiplierProperty.ts +13 -0
- package/src/lib/spacing.ts +83 -0
- package/src/lib/themeStore.ts +14 -0
- package/src/lib/utils.ts +74 -0
- package/src/lib/validateTheme.ts +22 -0
- package/src/types/cache.ts +2 -0
- package/src/types/component.ts +40 -0
- package/src/types/core.ts +40 -0
- package/src/types/icon.ts +8 -0
- package/src/types/index.ts +5 -0
- package/src/types/spacing.ts +35 -0
- package/src/types/style.ts +41 -0
- 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,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
|
+
}
|