@pyreon/rocketstyle 0.24.4 → 0.24.6
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 -10
- package/src/__tests__/attrs-overloads.test.ts +0 -97
- package/src/__tests__/attrs.test.ts +0 -190
- package/src/__tests__/cache-key-boolean-collision.test.ts +0 -54
- package/src/__tests__/chaining.test.ts +0 -86
- package/src/__tests__/collection.test.ts +0 -35
- package/src/__tests__/compose.test.ts +0 -36
- package/src/__tests__/context.test.ts +0 -200
- package/src/__tests__/createLocalProvider.test.ts +0 -280
- package/src/__tests__/dimensions.test.ts +0 -183
- package/src/__tests__/e2e-styler.test.ts +0 -299
- package/src/__tests__/hooks.test.ts +0 -178
- package/src/__tests__/isRocketComponent.test.ts +0 -48
- package/src/__tests__/memo-cap.test.ts +0 -174
- package/src/__tests__/minimal-theme.test.ts +0 -62
- package/src/__tests__/misc.test.ts +0 -204
- package/src/__tests__/native-marker.test.ts +0 -9
- package/src/__tests__/providerConsumer.test.ts +0 -183
- package/src/__tests__/reactive-props-preservation.test.ts +0 -195
- package/src/__tests__/rocketstyle.browser.test.tsx +0 -481
- package/src/__tests__/rocketstyleIntegration.test.ts +0 -711
- package/src/__tests__/theme-integration.test.tsx +0 -254
- package/src/__tests__/themeUtils.test.ts +0 -463
- package/src/cache/LocalThemeManager.ts +0 -14
- package/src/cache/index.ts +0 -3
- package/src/constants/booleanTags.ts +0 -32
- package/src/constants/defaultDimensions.ts +0 -23
- package/src/constants/index.ts +0 -59
- package/src/context/context.ts +0 -70
- package/src/context/createLocalProvider.ts +0 -97
- package/src/context/localContext.ts +0 -37
- package/src/env.d.ts +0 -6
- package/src/hoc/index.ts +0 -3
- package/src/hoc/rocketstyleAttrsHoc.ts +0 -76
- package/src/hooks/index.ts +0 -4
- package/src/hooks/usePseudoState.ts +0 -79
- package/src/hooks/useTheme.ts +0 -48
- package/src/index.ts +0 -95
- package/src/init.ts +0 -93
- package/src/isRocketComponent.ts +0 -16
- package/src/rocketstyle.ts +0 -640
- package/src/types/attrs.ts +0 -23
- package/src/types/config.ts +0 -48
- package/src/types/configuration.ts +0 -69
- package/src/types/dimensions.ts +0 -109
- package/src/types/hoc.ts +0 -5
- package/src/types/pseudo.ts +0 -19
- package/src/types/rocketComponent.ts +0 -24
- package/src/types/rocketstyle.ts +0 -220
- package/src/types/styles.ts +0 -61
- package/src/types/theme.ts +0 -18
- package/src/types/utils.ts +0 -98
- package/src/utils/attrs.ts +0 -181
- package/src/utils/chaining.ts +0 -58
- package/src/utils/collection.ts +0 -9
- package/src/utils/compose.ts +0 -11
- package/src/utils/dimensions.ts +0 -126
- package/src/utils/statics.ts +0 -44
- package/src/utils/styles.ts +0 -18
- package/src/utils/theme.ts +0 -211
package/src/utils/attrs.ts
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import type { MultiKeys } from '../types/dimensions'
|
|
2
|
-
|
|
3
|
-
// --------------------------------------------------------
|
|
4
|
-
// remove undefined props
|
|
5
|
-
// --------------------------------------------------------
|
|
6
|
-
/**
|
|
7
|
-
* Strips keys with `undefined` values so they don't shadow default props during merging.
|
|
8
|
-
*
|
|
9
|
-
* Copies own property DESCRIPTORS rather than values so that reactive
|
|
10
|
-
* getter-shaped props (compiler-emitted `_rp(() => signal())` converted
|
|
11
|
-
* to getters by `makeReactiveProps`) survive the pipeline with their
|
|
12
|
-
* subscription intact. Reading `props[key]` here would fire the getter
|
|
13
|
-
* at HOC setup time (outside any tracking scope) and collapse the prop
|
|
14
|
-
* to a static value — every downstream JSX accessor that reads
|
|
15
|
-
* `props.x` would see the captured-once value, not the live signal.
|
|
16
|
-
*
|
|
17
|
-
* For getter descriptors we keep the descriptor as-is (the
|
|
18
|
-
* undefined-filter doesn't apply — we can't peek into the getter
|
|
19
|
-
* without firing it). For data descriptors we drop entries whose
|
|
20
|
-
* value is `undefined` to preserve the original merge semantics.
|
|
21
|
-
*/
|
|
22
|
-
type RemoveUndefinedProps = <T extends Record<string, any>>(props: T) => Partial<T>
|
|
23
|
-
|
|
24
|
-
export const removeUndefinedProps: RemoveUndefinedProps = (props) => {
|
|
25
|
-
const result: Partial<typeof props> = {}
|
|
26
|
-
const descriptors = Object.getOwnPropertyDescriptors(props)
|
|
27
|
-
for (const key of Object.keys(descriptors)) {
|
|
28
|
-
const d = descriptors[key]!
|
|
29
|
-
if (d.get || d.value !== undefined) {
|
|
30
|
-
Object.defineProperty(result, key, d)
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return result
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// --------------------------------------------------------
|
|
37
|
-
// merge descriptors
|
|
38
|
-
// --------------------------------------------------------
|
|
39
|
-
/**
|
|
40
|
-
* Like `Object.assign(target, ...sources)` but copies own property
|
|
41
|
-
* DESCRIPTORS instead of reading + writing values. Later sources
|
|
42
|
-
* override earlier ones (same semantics as spread / Object.assign).
|
|
43
|
-
*
|
|
44
|
-
* Required for reactive-prop preservation through the rocketstyle
|
|
45
|
-
* pipeline: a plain `{ ...A, ...B }` spread fires every getter on A
|
|
46
|
-
* and B and stores the resolved value, breaking the reactive
|
|
47
|
-
* subscription. This helper copies descriptors so getters survive
|
|
48
|
-
* the merge.
|
|
49
|
-
*/
|
|
50
|
-
export const mergeDescriptors = (
|
|
51
|
-
...sources: ReadonlyArray<Record<string, any> | null | undefined>
|
|
52
|
-
): Record<string, any> => {
|
|
53
|
-
const result: Record<string, any> = {}
|
|
54
|
-
for (const source of sources) {
|
|
55
|
-
if (!source) continue
|
|
56
|
-
const descriptors = Object.getOwnPropertyDescriptors(source)
|
|
57
|
-
for (const key of Object.keys(descriptors)) {
|
|
58
|
-
Object.defineProperty(result, key, descriptors[key]!)
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return result
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// --------------------------------------------------------
|
|
65
|
-
// pick styled props
|
|
66
|
-
// --------------------------------------------------------
|
|
67
|
-
/** Picks only the props whose keys exist in the dimension keywords lookup and have truthy values. */
|
|
68
|
-
export const pickStyledAttrs = <
|
|
69
|
-
T extends Record<string, any>,
|
|
70
|
-
K extends Record<string, true | undefined>,
|
|
71
|
-
>(
|
|
72
|
-
props: T,
|
|
73
|
-
keywords: K,
|
|
74
|
-
): { [I in keyof K & keyof T]: T[I] } => {
|
|
75
|
-
// Direct `for...in` avoids the `Object.keys(props)` array allocation
|
|
76
|
-
// that `for (const key of Object.keys(props))` paid on every render.
|
|
77
|
-
// The hot path is rocketstyle's `EnhancedComponent` body — fires once
|
|
78
|
-
// per render of every rocketstyle-wrapped component. Ported from
|
|
79
|
-
// vitus-labs `00fdadc2`.
|
|
80
|
-
const result: Record<string, unknown> = {}
|
|
81
|
-
for (const key in props) {
|
|
82
|
-
if (keywords[key] && props[key]) result[key] = props[key]
|
|
83
|
-
}
|
|
84
|
-
return result as { [I in keyof K & keyof T]: T[I] }
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// --------------------------------------------------------
|
|
88
|
-
// combine values
|
|
89
|
-
// --------------------------------------------------------
|
|
90
|
-
/**
|
|
91
|
-
* Returns a curried function that evaluates an array of `.attrs()` callbacks,
|
|
92
|
-
* spreading each result into a single merged props object via `Object.assign`.
|
|
93
|
-
*/
|
|
94
|
-
type OptionFunc<A> = (...arg: A[]) => Record<string, unknown>
|
|
95
|
-
type CalculateChainOptions = <A>(
|
|
96
|
-
options?: OptionFunc<A>[],
|
|
97
|
-
) => (args: A[]) => ReturnType<OptionFunc<A>>
|
|
98
|
-
|
|
99
|
-
export const calculateChainOptions: CalculateChainOptions = (options) => (args) => {
|
|
100
|
-
if (!options || options.length === 0) return {}
|
|
101
|
-
|
|
102
|
-
return options.reduce<Record<string, unknown>>(
|
|
103
|
-
(acc, item) => Object.assign(acc, item(...args)),
|
|
104
|
-
{},
|
|
105
|
-
)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// --------------------------------------------------------
|
|
109
|
-
// get style attributes
|
|
110
|
-
// --------------------------------------------------------
|
|
111
|
-
/**
|
|
112
|
-
* Resolves the active value for each styling dimension from component props.
|
|
113
|
-
* First checks for explicit prop values (string, number, or array for multi-keys),
|
|
114
|
-
* then falls back to boolean shorthand props when `useBooleans` is enabled.
|
|
115
|
-
*/
|
|
116
|
-
type CalculateStylingAttrs = ({
|
|
117
|
-
useBooleans,
|
|
118
|
-
multiKeys,
|
|
119
|
-
}: {
|
|
120
|
-
useBooleans?: boolean
|
|
121
|
-
multiKeys?: MultiKeys
|
|
122
|
-
}) => ({
|
|
123
|
-
props,
|
|
124
|
-
dimensions,
|
|
125
|
-
}: {
|
|
126
|
-
props: Record<string, unknown>
|
|
127
|
-
dimensions: Record<string, unknown>
|
|
128
|
-
}) => Record<string, any>
|
|
129
|
-
export const calculateStylingAttrs: CalculateStylingAttrs =
|
|
130
|
-
({ useBooleans, multiKeys }) =>
|
|
131
|
-
({ props, dimensions }) => {
|
|
132
|
-
const result: Record<string, any> = {}
|
|
133
|
-
|
|
134
|
-
// (1) find dimension keys values & initialize
|
|
135
|
-
for (const item in dimensions) {
|
|
136
|
-
const pickedProp = props[item]
|
|
137
|
-
const t = typeof pickedProp
|
|
138
|
-
|
|
139
|
-
if (multiKeys?.[item] && Array.isArray(pickedProp)) {
|
|
140
|
-
result[item] = pickedProp
|
|
141
|
-
} else if (t === 'string' || t === 'number') {
|
|
142
|
-
result[item] = pickedProp
|
|
143
|
-
} else {
|
|
144
|
-
result[item] = undefined
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// (2) if booleans are being used let's find the rest
|
|
149
|
-
// Use `in` operator on the dimension map instead of allocating
|
|
150
|
-
// a new Set per dimension — the map is already an object with
|
|
151
|
-
// the keywords as keys.
|
|
152
|
-
if (useBooleans) {
|
|
153
|
-
for (const key in result) {
|
|
154
|
-
if (result[key]) continue // already assigned
|
|
155
|
-
|
|
156
|
-
const dimensionMap = dimensions[key] as Record<string, unknown>
|
|
157
|
-
const isMultiKey = multiKeys?.[key]
|
|
158
|
-
let newDimensionValue: string | string[] | undefined
|
|
159
|
-
|
|
160
|
-
if (isMultiKey) {
|
|
161
|
-
const matches: string[] = []
|
|
162
|
-
for (const propKey in props) {
|
|
163
|
-
if (propKey in dimensionMap) matches.push(propKey)
|
|
164
|
-
}
|
|
165
|
-
newDimensionValue = matches.length > 0 ? matches : undefined
|
|
166
|
-
} else {
|
|
167
|
-
// Iterate props to find last matching keyword
|
|
168
|
-
// (last wins for priority)
|
|
169
|
-
for (const k in props) {
|
|
170
|
-
if (k in dimensionMap && props[k]) {
|
|
171
|
-
newDimensionValue = k
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
result[key] = newDimensionValue
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return result
|
|
181
|
-
}
|
package/src/utils/chaining.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
type Func = (...args: any) => Record<string, unknown>
|
|
2
|
-
type Obj = Record<string, unknown>
|
|
3
|
-
|
|
4
|
-
// --------------------------------------------------------
|
|
5
|
-
// Chain Options
|
|
6
|
-
// --------------------------------------------------------
|
|
7
|
-
/**
|
|
8
|
-
* Appends a new option (function or plain object) to an existing chain
|
|
9
|
-
* of option callbacks. Objects are wrapped in a thunk for uniform handling.
|
|
10
|
-
*/
|
|
11
|
-
type ChainOptions = (opts: Obj | Func | undefined, defaultOpts: Func[]) => Func[]
|
|
12
|
-
|
|
13
|
-
export const chainOptions: ChainOptions = (opts, defaultOpts = []) => {
|
|
14
|
-
const result = [...defaultOpts]
|
|
15
|
-
|
|
16
|
-
if (typeof opts === 'function') result.push(opts)
|
|
17
|
-
else if (typeof opts === 'object') result.push(() => opts)
|
|
18
|
-
|
|
19
|
-
return result
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// --------------------------------------------------------
|
|
23
|
-
// Chain Or Options
|
|
24
|
-
// --------------------------------------------------------
|
|
25
|
-
/**
|
|
26
|
-
* For each key, picks the new value if truthy, otherwise falls back
|
|
27
|
-
* to the default. Used for config keys that replace rather than merge.
|
|
28
|
-
*/
|
|
29
|
-
type ChainOrOptions = (
|
|
30
|
-
keys: readonly string[],
|
|
31
|
-
opts: Obj,
|
|
32
|
-
defaultOpts: Obj,
|
|
33
|
-
) => Record<string, unknown>
|
|
34
|
-
|
|
35
|
-
export const chainOrOptions: ChainOrOptions = (keys, opts, defaultOpts) =>
|
|
36
|
-
keys.reduce((acc, item) => ({ ...acc, [item]: opts[item] || defaultOpts[item] }), {})
|
|
37
|
-
|
|
38
|
-
// --------------------------------------------------------
|
|
39
|
-
// Chain Reserved Options
|
|
40
|
-
// --------------------------------------------------------
|
|
41
|
-
/**
|
|
42
|
-
* Chains option callbacks for reserved dimension and styling keys,
|
|
43
|
-
* delegating to `chainOptions` for each key individually.
|
|
44
|
-
*/
|
|
45
|
-
type ChainReservedKeyOptions = (
|
|
46
|
-
keys: readonly string[],
|
|
47
|
-
opts: Record<string, Obj | Func>,
|
|
48
|
-
defaultOpts: Record<string, Func[]>,
|
|
49
|
-
) => Record<string, ReturnType<typeof chainOptions>>
|
|
50
|
-
|
|
51
|
-
export const chainReservedKeyOptions: ChainReservedKeyOptions = (keys, opts, defaultOpts) =>
|
|
52
|
-
keys.reduce(
|
|
53
|
-
(acc, item) => ({
|
|
54
|
-
...acc,
|
|
55
|
-
[item]: chainOptions(opts[item], defaultOpts[item] ?? []),
|
|
56
|
-
}),
|
|
57
|
-
{},
|
|
58
|
-
)
|
package/src/utils/collection.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// --------------------------------------------------------
|
|
2
|
-
// Remove Nullable values
|
|
3
|
-
// --------------------------------------------------------
|
|
4
|
-
/** Filters out entries with `null`, `undefined`, or `false` values from an object. */
|
|
5
|
-
type RemoveNullableValues = (obj: Record<string, any>) => Record<string, any>
|
|
6
|
-
export const removeNullableValues: RemoveNullableValues = (obj) =>
|
|
7
|
-
Object.entries(obj)
|
|
8
|
-
.filter(([, v]) => v != null && v !== false)
|
|
9
|
-
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {})
|
package/src/utils/compose.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extracts HOC functions from the compose configuration object,
|
|
3
|
-
* filters out non-function entries, and reverses them so the
|
|
4
|
-
* outermost HOC in the chain wraps first (inside-out composition).
|
|
5
|
-
*/
|
|
6
|
-
type CalculateHocsFuncs = (options: Record<string, any>) => ((arg: any) => any)[]
|
|
7
|
-
|
|
8
|
-
export const calculateHocsFuncs: CalculateHocsFuncs = (options = {}) =>
|
|
9
|
-
Object.values(options)
|
|
10
|
-
.filter((item) => typeof item === 'function')
|
|
11
|
-
.reverse()
|
package/src/utils/dimensions.ts
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { get, isEmpty, set } from '@pyreon/ui-core'
|
|
2
|
-
import type { Dimensions, DimensionValue, MultiKeys } from '../types/dimensions'
|
|
3
|
-
|
|
4
|
-
// --------------------------------------------------------
|
|
5
|
-
// Is value a valid key
|
|
6
|
-
// --------------------------------------------------------
|
|
7
|
-
/** Checks whether a dimension value is defined and not explicitly disabled (false). */
|
|
8
|
-
type IsValidKey = (value: any) => boolean
|
|
9
|
-
export const isValidKey: IsValidKey = (value) =>
|
|
10
|
-
value !== undefined && value !== null && value !== false
|
|
11
|
-
|
|
12
|
-
// --------------------------------------------------------
|
|
13
|
-
// Is value a multi key
|
|
14
|
-
// --------------------------------------------------------
|
|
15
|
-
/** Determines if a dimension value is a multi-key config object, returning [isMulti, propName]. */
|
|
16
|
-
type IsMultiKey = (value: string | Record<string, unknown>) => [boolean, string]
|
|
17
|
-
export const isMultiKey: IsMultiKey = (value) => {
|
|
18
|
-
if (typeof value === 'object' && value !== null) return [true, get(value, 'propName') as string]
|
|
19
|
-
return [false, value]
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// --------------------------------------------------------
|
|
23
|
-
// calculate dimensions map
|
|
24
|
-
// --------------------------------------------------------
|
|
25
|
-
/**
|
|
26
|
-
* Builds a two-level map (`keysMap`) of dimension -> option -> true,
|
|
27
|
-
* and a flat `keywords` lookup of all prop names reserved by dimensions
|
|
28
|
-
* (including boolean shorthand keys when `useBooleans` is enabled).
|
|
29
|
-
*/
|
|
30
|
-
type GetDimensionsMap = <T extends Record<string, any>>({
|
|
31
|
-
themes,
|
|
32
|
-
useBooleans,
|
|
33
|
-
}: {
|
|
34
|
-
themes: T
|
|
35
|
-
useBooleans?: boolean
|
|
36
|
-
}) => { keysMap: Record<string, any>; keywords: Record<string, any> }
|
|
37
|
-
|
|
38
|
-
export const getDimensionsMap: GetDimensionsMap = ({ themes, useBooleans }) => {
|
|
39
|
-
const result = {
|
|
40
|
-
keysMap: {} as Record<string, any>,
|
|
41
|
-
keywords: {} as Record<string, any>,
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (isEmpty(themes)) return result
|
|
45
|
-
|
|
46
|
-
return Object.entries(themes).reduce((accumulator, [key, value]) => {
|
|
47
|
-
const { keysMap, keywords } = accumulator
|
|
48
|
-
keywords[key] = true
|
|
49
|
-
|
|
50
|
-
Object.entries(value).forEach(([itemKey, itemValue]) => {
|
|
51
|
-
if (!isValidKey(itemValue)) return
|
|
52
|
-
|
|
53
|
-
if (useBooleans) {
|
|
54
|
-
keywords[itemKey] = true
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
set(keysMap, [key, itemKey], true)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
return accumulator
|
|
61
|
-
}, result)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// --------------------------------------------------------
|
|
65
|
-
// simple object getters
|
|
66
|
-
// --------------------------------------------------------
|
|
67
|
-
/** Returns the keys of an object with proper typing. */
|
|
68
|
-
type GetKeys = <T extends Record<string, unknown>>(obj: T) => Array<keyof T>
|
|
69
|
-
export const getKeys: GetKeys = (obj) => Object.keys(obj)
|
|
70
|
-
|
|
71
|
-
type GetValues = <T extends Record<string, unknown>, K extends keyof T>(obj: T) => T[K][]
|
|
72
|
-
export const getValues = (<T extends Record<string, unknown>>(obj: T) =>
|
|
73
|
-
Object.values(obj)) as GetValues
|
|
74
|
-
|
|
75
|
-
// --------------------------------------------------------
|
|
76
|
-
// get dimensions values array
|
|
77
|
-
// --------------------------------------------------------
|
|
78
|
-
/** Extracts the prop name from each dimension value, unwrapping multi-key config objects. */
|
|
79
|
-
type ValueType<T> = T extends string ? T : T[][0]
|
|
80
|
-
type GetDimensionsValues = <T extends Dimensions, K extends keyof T>(obj: T) => ValueType<T[K]>[]
|
|
81
|
-
|
|
82
|
-
export const getDimensionsValues = (<T extends Dimensions>(obj: T) =>
|
|
83
|
-
getValues(obj).map((item: DimensionValue) => {
|
|
84
|
-
if (typeof item === 'object') {
|
|
85
|
-
return item.propName as string
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return item
|
|
89
|
-
})) as GetDimensionsValues
|
|
90
|
-
|
|
91
|
-
// --------------------------------------------------------
|
|
92
|
-
// get multiple dimensions map
|
|
93
|
-
// --------------------------------------------------------
|
|
94
|
-
/** Builds a lookup of dimension prop names that accept multiple simultaneous values. */
|
|
95
|
-
type GetMultipleDimensions = <T extends Dimensions>(obj: T) => MultiKeys<T>
|
|
96
|
-
|
|
97
|
-
export const getMultipleDimensions: GetMultipleDimensions = (obj) =>
|
|
98
|
-
getValues(obj).reduce(
|
|
99
|
-
(accumulator, value: DimensionValue) => {
|
|
100
|
-
if (typeof value === 'object') {
|
|
101
|
-
if (value.multi === true) accumulator[value.propName] = true
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return accumulator
|
|
105
|
-
},
|
|
106
|
-
{} as Record<string, true>,
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
// --------------------------------------------------------
|
|
110
|
-
// get transform dimensions map
|
|
111
|
-
// --------------------------------------------------------
|
|
112
|
-
/** Builds a lookup of dimension prop names that are transform dimensions (evaluated last with function values). */
|
|
113
|
-
type TransformKeys = Partial<Record<string, true>>
|
|
114
|
-
type GetTransformDimensions = <T extends Dimensions>(obj: T) => TransformKeys
|
|
115
|
-
|
|
116
|
-
export const getTransformDimensions: GetTransformDimensions = (obj) =>
|
|
117
|
-
getValues(obj).reduce(
|
|
118
|
-
(accumulator, value: DimensionValue) => {
|
|
119
|
-
if (typeof value === 'object') {
|
|
120
|
-
if (value.transform === true) accumulator[value.propName] = true
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return accumulator
|
|
124
|
-
},
|
|
125
|
-
{} as Record<string, true>,
|
|
126
|
-
)
|
package/src/utils/statics.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { isEmpty } from '@pyreon/ui-core'
|
|
2
|
-
import { STATIC_KEYS } from '../constants'
|
|
3
|
-
|
|
4
|
-
// --------------------------------------------------------
|
|
5
|
-
// helpers for create statics chaining methods on component
|
|
6
|
-
// --------------------------------------------------------
|
|
7
|
-
/**
|
|
8
|
-
* Attaches chaining static methods (e.g. `.states()`, `.sizes()`, `.theme()`)
|
|
9
|
-
* to a component. Each method calls `cloneAndEnhance` with the corresponding key.
|
|
10
|
-
*/
|
|
11
|
-
type CreateStaticsChainingEnhancers = <O extends Record<string, any>, DK extends string[]>(props: {
|
|
12
|
-
context: Record<string, any>
|
|
13
|
-
dimensionKeys: DK
|
|
14
|
-
func: (defaultOpts: O, opts: any) => void
|
|
15
|
-
options: O
|
|
16
|
-
}) => void
|
|
17
|
-
|
|
18
|
-
export const createStaticsChainingEnhancers: CreateStaticsChainingEnhancers = ({
|
|
19
|
-
context,
|
|
20
|
-
dimensionKeys,
|
|
21
|
-
func,
|
|
22
|
-
options,
|
|
23
|
-
}) => {
|
|
24
|
-
const keys = [...dimensionKeys, ...STATIC_KEYS]
|
|
25
|
-
|
|
26
|
-
keys.forEach((item) => {
|
|
27
|
-
context[item] = (props: any) => func(options, { [item]: props })
|
|
28
|
-
})
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// --------------------------------------------------------
|
|
32
|
-
// helpers for create statics on component
|
|
33
|
-
// --------------------------------------------------------
|
|
34
|
-
/** Copies user-defined static properties onto the component's `meta` object. */
|
|
35
|
-
type CreateStaticsEnhancers = (params: {
|
|
36
|
-
context: Record<string, any>
|
|
37
|
-
options: Record<string, any>
|
|
38
|
-
}) => void
|
|
39
|
-
|
|
40
|
-
export const createStaticsEnhancers: CreateStaticsEnhancers = ({ context, options }) => {
|
|
41
|
-
if (!isEmpty(options)) {
|
|
42
|
-
Object.assign(context, options)
|
|
43
|
-
}
|
|
44
|
-
}
|
package/src/utils/styles.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { config } from '@pyreon/ui-core'
|
|
2
|
-
import type { StylesCbArray } from '../types/styles'
|
|
3
|
-
|
|
4
|
-
// --------------------------------------------------------
|
|
5
|
-
// Calculate styles
|
|
6
|
-
// --------------------------------------------------------
|
|
7
|
-
/**
|
|
8
|
-
* Evaluates an array of style callback functions with the configured
|
|
9
|
-
* `css` tagged-template helper, producing the final CSS interpolations
|
|
10
|
-
* to be passed into the styled-component template literal.
|
|
11
|
-
*/
|
|
12
|
-
type CalculateStyles = (styles: StylesCbArray | undefined) => ReturnType<StylesCbArray[number]>[]
|
|
13
|
-
|
|
14
|
-
export const calculateStyles: CalculateStyles = (styles) => {
|
|
15
|
-
if (!styles) return []
|
|
16
|
-
|
|
17
|
-
return styles.map((item) => item(config.css as Parameters<typeof item>[0]))
|
|
18
|
-
}
|
package/src/utils/theme.ts
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
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 dims = options.dimensions
|
|
64
|
-
if (isEmpty(dims)) return {}
|
|
65
|
-
|
|
66
|
-
const result: Record<string, any> = {}
|
|
67
|
-
|
|
68
|
-
for (const key in dims) {
|
|
69
|
-
const [, dimension] = isMultiKey(dims[key] as string | Record<string, unknown>)
|
|
70
|
-
const helper = options[key]
|
|
71
|
-
|
|
72
|
-
if (Array.isArray(helper) && helper.length > 0) {
|
|
73
|
-
result[dimension] = removeNullableValues(getThemeFromChain(helper, theme))
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return result
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// --------------------------------------------------------
|
|
81
|
-
// combine values
|
|
82
|
-
// --------------------------------------------------------
|
|
83
|
-
/** Reduces an array of option callbacks by calling each with the given args and deep-merging results. */
|
|
84
|
-
type CalculateChainOptions = (
|
|
85
|
-
options: OptionFunc[] | undefined | null,
|
|
86
|
-
args: any[],
|
|
87
|
-
) => Record<string, any>
|
|
88
|
-
|
|
89
|
-
export const calculateChainOptions: CalculateChainOptions = (options, args) => {
|
|
90
|
-
const result = {}
|
|
91
|
-
if (!options || isEmpty(options)) return result
|
|
92
|
-
|
|
93
|
-
return options.reduce((acc, item) => merge(acc, item(...args)), result)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// --------------------------------------------------------
|
|
97
|
-
// generate theme
|
|
98
|
-
// --------------------------------------------------------
|
|
99
|
-
/**
|
|
100
|
-
* Generates the final theme object by starting with the base theme
|
|
101
|
-
* and merging in dimension-specific theme slices based on the current
|
|
102
|
-
* rocketstate (active dimension values). Supports multi-key dimensions.
|
|
103
|
-
*
|
|
104
|
-
* Transform dimensions (marked with `transform: true`) are evaluated last.
|
|
105
|
-
* Their values are functions that receive the fully accumulated theme and
|
|
106
|
-
* return overrides — enabling derived styles like "outlined" or "inversed".
|
|
107
|
-
*/
|
|
108
|
-
export type GetTheme = (params: {
|
|
109
|
-
rocketstate: Record<string, string | string[]>
|
|
110
|
-
themes: Record<string, Record<string, any>>
|
|
111
|
-
baseTheme: Record<string, any>
|
|
112
|
-
transformKeys?: Partial<Record<string, true>>
|
|
113
|
-
/** App theme from context — passed to transform dimension callbacks. */
|
|
114
|
-
appTheme?: Record<string, any>
|
|
115
|
-
}) => Record<string, unknown>
|
|
116
|
-
|
|
117
|
-
// Shared empty object for pseudo-state defaults — allocated once, reused by
|
|
118
|
-
// every getTheme call. Frozen to prevent accidental mutation.
|
|
119
|
-
const EMPTY_PSEUDO: Record<string, never> = Object.freeze({}) as Record<string, never>
|
|
120
|
-
|
|
121
|
-
export const getTheme: GetTheme = ({ rocketstate, themes, baseTheme, transformKeys, appTheme }) => {
|
|
122
|
-
// Spread baseTheme into result — this is unavoidable (we must not mutate
|
|
123
|
-
// the cached baseTheme). But we merge dimension slices in-place onto
|
|
124
|
-
// finalTheme instead of creating a new {} target each merge() call.
|
|
125
|
-
const finalTheme: Record<string, any> = { ...baseTheme }
|
|
126
|
-
type TransformFn = (
|
|
127
|
-
currentTheme: Record<string, any>,
|
|
128
|
-
currentAppTheme: Record<string, any>,
|
|
129
|
-
mode: typeof themeModeCallback,
|
|
130
|
-
cssFn: typeof config.css,
|
|
131
|
-
) => Record<string, any>
|
|
132
|
-
const deferredTransforms: TransformFn[] = []
|
|
133
|
-
|
|
134
|
-
for (const key in rocketstate) {
|
|
135
|
-
const value = rocketstate[key]
|
|
136
|
-
if (value == null) continue
|
|
137
|
-
const keyTheme: Record<string, any> = themes[key] ?? {}
|
|
138
|
-
const isTransform = transformKeys?.[key]
|
|
139
|
-
|
|
140
|
-
const mergeValue = (item: string) => {
|
|
141
|
-
const val = keyTheme[item]
|
|
142
|
-
if (val == null) return
|
|
143
|
-
if (isTransform && typeof val === 'function') {
|
|
144
|
-
deferredTransforms.push(val as TransformFn)
|
|
145
|
-
} else {
|
|
146
|
-
// Merge in-place onto finalTheme — avoids allocating a fresh {}
|
|
147
|
-
// as merge target on every dimension slice.
|
|
148
|
-
merge(finalTheme, val)
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (Array.isArray(value)) {
|
|
153
|
-
for (let i = 0; i < value.length; i++) mergeValue(value[i] as string)
|
|
154
|
-
} else {
|
|
155
|
-
mergeValue(value as string)
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Apply transform dimension values last with the fully accumulated theme
|
|
160
|
-
for (let i = 0; i < deferredTransforms.length; i++) {
|
|
161
|
-
merge(finalTheme, deferredTransforms[i]!(finalTheme, appTheme ?? {}, themeModeCallback, config.css))
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Ensure pseudo-state keys always exist as objects so .styles() can
|
|
165
|
-
// destructure without defaults: const { hover, focus, ... } = $rocketstyle
|
|
166
|
-
// Uses a frozen shared empty object instead of allocating 6 new {} per call.
|
|
167
|
-
finalTheme.hover ??= EMPTY_PSEUDO
|
|
168
|
-
finalTheme.focus ??= EMPTY_PSEUDO
|
|
169
|
-
finalTheme.active ??= EMPTY_PSEUDO
|
|
170
|
-
finalTheme.disabled ??= EMPTY_PSEUDO
|
|
171
|
-
finalTheme.pressed ??= EMPTY_PSEUDO
|
|
172
|
-
finalTheme.readOnly ??= EMPTY_PSEUDO
|
|
173
|
-
|
|
174
|
-
return finalTheme
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// --------------------------------------------------------
|
|
178
|
-
// resolve theme by mode
|
|
179
|
-
// --------------------------------------------------------
|
|
180
|
-
/**
|
|
181
|
-
* Recursively traverses a theme object and resolves any `themeModeCallback`
|
|
182
|
-
* functions to their concrete light or dark values for the given mode.
|
|
183
|
-
*/
|
|
184
|
-
export type GetThemeByMode = (
|
|
185
|
-
object: Record<string, any>,
|
|
186
|
-
mode: 'light' | 'dark',
|
|
187
|
-
) => Partial<{
|
|
188
|
-
baseTheme: Record<string, unknown>
|
|
189
|
-
themes: Record<string, unknown>
|
|
190
|
-
}>
|
|
191
|
-
|
|
192
|
-
export const getThemeByMode: GetThemeByMode = (object, mode) => {
|
|
193
|
-
// Recursive theme walker — `for...in` avoids the per-node
|
|
194
|
-
// `Object.keys` array allocation that the prior reduce paid. Called
|
|
195
|
-
// from inside cached `LocalThemeManager` WeakMap tiers (one per
|
|
196
|
-
// theme/mode transition), so the win is smaller than per-render
|
|
197
|
-
// helpers but the pattern is consistent. Ported from vitus-labs
|
|
198
|
-
// `00fdadc2`.
|
|
199
|
-
const acc: Record<string, any> = {}
|
|
200
|
-
for (const key in object) {
|
|
201
|
-
const value = object[key]
|
|
202
|
-
if (typeof value === 'object' && value !== null) {
|
|
203
|
-
acc[key] = getThemeByMode(value, mode)
|
|
204
|
-
} else if (isModeCallback(value)) {
|
|
205
|
-
acc[key] = value(mode)
|
|
206
|
-
} else {
|
|
207
|
-
acc[key] = value
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
return acc
|
|
211
|
-
}
|