@pyreon/rocketstyle 0.11.1 → 0.11.2
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/package.json +8 -7
- package/src/__tests__/attrs.test.ts +190 -0
- package/src/__tests__/chaining.test.ts +86 -0
- package/src/__tests__/collection.test.ts +35 -0
- package/src/__tests__/compose.test.ts +36 -0
- package/src/__tests__/context.test.ts +200 -0
- package/src/__tests__/createLocalProvider.test.ts +248 -0
- package/src/__tests__/dimensions.test.ts +183 -0
- package/src/__tests__/e2e-styler.test.ts +291 -0
- package/src/__tests__/hooks.test.ts +207 -0
- package/src/__tests__/isRocketComponent.test.ts +48 -0
- package/src/__tests__/misc.test.ts +204 -0
- package/src/__tests__/providerConsumer.test.ts +248 -0
- package/src/__tests__/rocketstyleIntegration.test.ts +615 -0
- package/src/__tests__/themeUtils.test.ts +463 -0
- package/src/cache/LocalThemeManager.ts +14 -0
- package/src/cache/index.ts +3 -0
- package/src/constants/booleanTags.ts +32 -0
- package/src/constants/defaultDimensions.ts +23 -0
- package/src/constants/index.ts +44 -0
- package/src/context/context.ts +51 -0
- package/src/context/createLocalProvider.ts +84 -0
- package/src/context/localContext.ts +37 -0
- package/src/hoc/index.ts +3 -0
- package/src/hoc/rocketstyleAttrsHoc.ts +63 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/usePseudoState.ts +79 -0
- package/src/hooks/useTheme.ts +36 -0
- package/src/index.ts +77 -0
- package/src/init.ts +93 -0
- package/src/isRocketComponent.ts +16 -0
- package/src/rocketstyle.ts +320 -0
- package/src/types/attrs.ts +13 -0
- package/src/types/config.ts +48 -0
- package/src/types/configuration.ts +69 -0
- package/src/types/dimensions.ts +106 -0
- package/src/types/hoc.ts +5 -0
- package/src/types/pseudo.ts +19 -0
- package/src/types/rocketComponent.ts +24 -0
- package/src/types/rocketstyle.ts +156 -0
- package/src/types/styles.ts +46 -0
- package/src/types/theme.ts +19 -0
- package/src/types/utils.ts +55 -0
- package/src/utils/attrs.ts +134 -0
- package/src/utils/chaining.ts +58 -0
- package/src/utils/collection.ts +9 -0
- package/src/utils/compose.ts +11 -0
- package/src/utils/dimensions.ts +126 -0
- package/src/utils/statics.ts +44 -0
- package/src/utils/styles.ts +18 -0
- package/src/utils/theme.ts +196 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { config, isEmpty, merge } from "@pyreon/ui-core"
|
|
2
|
+
import type { ThemeModeCallback } from "../types/theme"
|
|
3
|
+
import { removeNullableValues } from "./collection"
|
|
4
|
+
import { isMultiKey } from "./dimensions"
|
|
5
|
+
|
|
6
|
+
// --------------------------------------------------------
|
|
7
|
+
// Theme Mode Callback
|
|
8
|
+
// --------------------------------------------------------
|
|
9
|
+
const MODE_CALLBACK_BRAND = Symbol.for("pyreon.themeModeCallback")
|
|
10
|
+
|
|
11
|
+
/** Creates a mode-switching function that returns the light or dark value based on the active mode. */
|
|
12
|
+
export const themeModeCallback: ThemeModeCallback = (light, dark) => {
|
|
13
|
+
const fn = (mode: string) => {
|
|
14
|
+
if (!mode || mode === "light") return light
|
|
15
|
+
return dark
|
|
16
|
+
}
|
|
17
|
+
;(fn as unknown as Record<string, unknown>).__brand = MODE_CALLBACK_BRAND
|
|
18
|
+
return fn
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// --------------------------------------------------------
|
|
22
|
+
// Theme Mode Callback Check
|
|
23
|
+
// --------------------------------------------------------
|
|
24
|
+
/** Detects whether a value is a `themeModeCallback` function via Symbol brand. */
|
|
25
|
+
type IsModeCallback = (value: unknown) => boolean
|
|
26
|
+
const isModeCallback: IsModeCallback = (value: unknown) =>
|
|
27
|
+
typeof value === "function" &&
|
|
28
|
+
(value as unknown as Record<string, unknown>).__brand === MODE_CALLBACK_BRAND
|
|
29
|
+
|
|
30
|
+
// --------------------------------------------------------
|
|
31
|
+
// Get Theme From Chain
|
|
32
|
+
// --------------------------------------------------------
|
|
33
|
+
/** Reduces an array of chained `.theme()` callbacks into a single merged theme object. */
|
|
34
|
+
type OptionFunc = (...arg: any) => Record<string, unknown>
|
|
35
|
+
type GetThemeFromChain = (
|
|
36
|
+
options: OptionFunc[] | undefined | null,
|
|
37
|
+
theme: Record<string, any>,
|
|
38
|
+
) => ReturnType<OptionFunc>
|
|
39
|
+
|
|
40
|
+
export const getThemeFromChain: GetThemeFromChain = (options, theme) => {
|
|
41
|
+
const result = {}
|
|
42
|
+
if (!options || isEmpty(options)) return result
|
|
43
|
+
|
|
44
|
+
return options.reduce(
|
|
45
|
+
(acc, item) => merge(acc, item(theme, themeModeCallback, config.css)),
|
|
46
|
+
result,
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// --------------------------------------------------------
|
|
51
|
+
// calculate dimension themes
|
|
52
|
+
// --------------------------------------------------------
|
|
53
|
+
/**
|
|
54
|
+
* Computes the theme object for each dimension by evaluating its
|
|
55
|
+
* chained callbacks against the global theme, then strips nullable values.
|
|
56
|
+
*/
|
|
57
|
+
type GetDimensionThemes = (
|
|
58
|
+
theme: Record<string, any>,
|
|
59
|
+
options: Record<string, any>,
|
|
60
|
+
) => Record<string, any>
|
|
61
|
+
|
|
62
|
+
export const getDimensionThemes: GetDimensionThemes = (theme, options) => {
|
|
63
|
+
const result = {}
|
|
64
|
+
|
|
65
|
+
if (isEmpty(options.dimensions)) return result
|
|
66
|
+
|
|
67
|
+
return Object.entries(options.dimensions).reduce(
|
|
68
|
+
(acc, [key, value]) => {
|
|
69
|
+
const [, dimension] = isMultiKey(value as string | Record<string, unknown>)
|
|
70
|
+
|
|
71
|
+
const helper = options[key]
|
|
72
|
+
|
|
73
|
+
if (Array.isArray(helper) && helper.length > 0) {
|
|
74
|
+
const finalDimensionThemes = getThemeFromChain(helper, theme)
|
|
75
|
+
|
|
76
|
+
acc[dimension] = removeNullableValues(finalDimensionThemes)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return acc
|
|
80
|
+
},
|
|
81
|
+
result as Record<string, any>,
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// --------------------------------------------------------
|
|
86
|
+
// combine values
|
|
87
|
+
// --------------------------------------------------------
|
|
88
|
+
/** Reduces an array of option callbacks by calling each with the given args and deep-merging results. */
|
|
89
|
+
type CalculateChainOptions = (
|
|
90
|
+
options: OptionFunc[] | undefined | null,
|
|
91
|
+
args: any[],
|
|
92
|
+
) => Record<string, any>
|
|
93
|
+
|
|
94
|
+
export const calculateChainOptions: CalculateChainOptions = (options, args) => {
|
|
95
|
+
const result = {}
|
|
96
|
+
if (!options || isEmpty(options)) return result
|
|
97
|
+
|
|
98
|
+
return options.reduce((acc, item) => merge(acc, item(...args)), result)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// --------------------------------------------------------
|
|
102
|
+
// generate theme
|
|
103
|
+
// --------------------------------------------------------
|
|
104
|
+
/**
|
|
105
|
+
* Generates the final theme object by starting with the base theme
|
|
106
|
+
* and merging in dimension-specific theme slices based on the current
|
|
107
|
+
* rocketstate (active dimension values). Supports multi-key dimensions.
|
|
108
|
+
*
|
|
109
|
+
* Transform dimensions (marked with `transform: true`) are evaluated last.
|
|
110
|
+
* Their values are functions that receive the fully accumulated theme and
|
|
111
|
+
* return overrides — enabling derived styles like "outlined" or "inversed".
|
|
112
|
+
*/
|
|
113
|
+
export type GetTheme = (params: {
|
|
114
|
+
rocketstate: Record<string, string | string[]>
|
|
115
|
+
themes: Record<string, Record<string, any>>
|
|
116
|
+
baseTheme: Record<string, any>
|
|
117
|
+
transformKeys?: Partial<Record<string, true>>
|
|
118
|
+
/** App theme from context — passed to transform dimension callbacks. */
|
|
119
|
+
appTheme?: Record<string, any>
|
|
120
|
+
}) => Record<string, unknown>
|
|
121
|
+
|
|
122
|
+
export const getTheme: GetTheme = ({ rocketstate, themes, baseTheme, transformKeys, appTheme }) => {
|
|
123
|
+
let finalTheme = { ...baseTheme }
|
|
124
|
+
const deferredTransforms: Array<
|
|
125
|
+
(
|
|
126
|
+
currentTheme: Record<string, any>,
|
|
127
|
+
currentAppTheme: Record<string, any>,
|
|
128
|
+
mode: typeof themeModeCallback,
|
|
129
|
+
cssFn: typeof config.css,
|
|
130
|
+
) => Record<string, any>
|
|
131
|
+
> = []
|
|
132
|
+
|
|
133
|
+
Object.entries(rocketstate).forEach(([key, value]: [string, string | string[]]) => {
|
|
134
|
+
const keyTheme: Record<string, any> = themes[key] ?? {}
|
|
135
|
+
const isTransform = transformKeys?.[key]
|
|
136
|
+
|
|
137
|
+
const mergeValue = (item: string) => {
|
|
138
|
+
const val = keyTheme[item]
|
|
139
|
+
if (isTransform && typeof val === "function") {
|
|
140
|
+
deferredTransforms.push(val)
|
|
141
|
+
} else {
|
|
142
|
+
finalTheme = merge({}, finalTheme, val)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (Array.isArray(value)) {
|
|
147
|
+
value.forEach(mergeValue)
|
|
148
|
+
} else {
|
|
149
|
+
mergeValue(value)
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
// Apply transform dimension values last with the fully accumulated theme
|
|
154
|
+
for (const transform of deferredTransforms) {
|
|
155
|
+
finalTheme = merge(
|
|
156
|
+
{},
|
|
157
|
+
finalTheme,
|
|
158
|
+
transform(finalTheme, appTheme ?? {}, themeModeCallback, config.css),
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return finalTheme
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// --------------------------------------------------------
|
|
166
|
+
// resolve theme by mode
|
|
167
|
+
// --------------------------------------------------------
|
|
168
|
+
/**
|
|
169
|
+
* Recursively traverses a theme object and resolves any `themeModeCallback`
|
|
170
|
+
* functions to their concrete light or dark values for the given mode.
|
|
171
|
+
*/
|
|
172
|
+
export type GetThemeByMode = (
|
|
173
|
+
object: Record<string, any>,
|
|
174
|
+
mode: "light" | "dark",
|
|
175
|
+
) => Partial<{
|
|
176
|
+
baseTheme: Record<string, unknown>
|
|
177
|
+
themes: Record<string, unknown>
|
|
178
|
+
}>
|
|
179
|
+
|
|
180
|
+
export const getThemeByMode: GetThemeByMode = (object, mode) =>
|
|
181
|
+
Object.keys(object).reduce(
|
|
182
|
+
(acc, key) => {
|
|
183
|
+
const value = object[key]
|
|
184
|
+
|
|
185
|
+
if (typeof value === "object" && value !== null) {
|
|
186
|
+
acc[key] = getThemeByMode(value, mode)
|
|
187
|
+
} else if (isModeCallback(value)) {
|
|
188
|
+
acc[key] = value(mode)
|
|
189
|
+
} else {
|
|
190
|
+
acc[key] = value
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return acc
|
|
194
|
+
},
|
|
195
|
+
{} as Record<string, any>,
|
|
196
|
+
)
|