@vitus-labs/rocketstyle 2.0.0-alpha.26 → 2.0.0-alpha.28
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/README.md +4 -4
- package/lib/index.d.ts +22 -18
- package/lib/index.js +181 -101
- package/package.json +10 -10
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Multi-dimensional styling system for React.
|
|
|
5
5
|
[](https://www.npmjs.com/package/@vitus-labs/rocketstyle)
|
|
6
6
|
[](https://github.com/vitus-labs/ui-system/blob/main/LICENSE)
|
|
7
7
|
|
|
8
|
-
Organize component styles by dimensions — states, sizes, variants — instead of flat props. Chain theme values, attach
|
|
8
|
+
Organize component styles by dimensions — states, sizes, variants — instead of flat props. Chain theme values, attach CSS via the active connector, and get full TypeScript inference. Built-in pseudo-state handling, light/dark mode, and provider/consumer patterns for parent-child state propagation.
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
@@ -21,7 +21,7 @@ Organize component styles by dimensions — states, sizes, variants — instead
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
npm install @vitus-labs/rocketstyle @vitus-labs/core
|
|
24
|
+
npm install @vitus-labs/rocketstyle @vitus-labs/core
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
## Quick Start
|
|
@@ -110,7 +110,7 @@ Pseudo-state keys nest directly in the theme object:
|
|
|
110
110
|
|
|
111
111
|
### Styles Function
|
|
112
112
|
|
|
113
|
-
The `.styles()` method defines the
|
|
113
|
+
The `.styles()` method defines the CSS template that receives the computed theme:
|
|
114
114
|
|
|
115
115
|
```tsx
|
|
116
116
|
.styles((css) => css`
|
|
@@ -200,7 +200,7 @@ Button.states((theme, mode, css) => ({
|
|
|
200
200
|
|
|
201
201
|
### .styles(callback)
|
|
202
202
|
|
|
203
|
-
Define the
|
|
203
|
+
Define the CSS template using the active connector's `css` tagged template.
|
|
204
204
|
|
|
205
205
|
```tsx
|
|
206
206
|
Button.styles((css) => css`
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { config, context, render } from "@vitus-labs/core";
|
|
2
|
-
import { ComponentType, FC, FocusEventHandler,
|
|
2
|
+
import { ComponentType, FC, FocusEventHandler, MouseEventHandler, ReactNode } from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/context/context.d.ts
|
|
5
5
|
type Theme$1 = {
|
|
@@ -35,6 +35,11 @@ declare const DEFAULT_DIMENSIONS: {
|
|
|
35
35
|
readonly propName: "multiple";
|
|
36
36
|
readonly multi: true;
|
|
37
37
|
};
|
|
38
|
+
readonly modifiers: {
|
|
39
|
+
readonly propName: "modifier";
|
|
40
|
+
readonly multi: true;
|
|
41
|
+
readonly transform: true;
|
|
42
|
+
};
|
|
38
43
|
};
|
|
39
44
|
type DefaultDimensions = typeof DEFAULT_DIMENSIONS;
|
|
40
45
|
//#endregion
|
|
@@ -61,11 +66,9 @@ type PseudoProps = Partial<PseudoState & PseudoActions>;
|
|
|
61
66
|
type TObj = Record<string, unknown>;
|
|
62
67
|
type TFn = (...args: any) => any;
|
|
63
68
|
type CallBackParam = TObj | TFn;
|
|
64
|
-
type ElementType<T extends TObj | unknown = any> =
|
|
65
|
-
[key: string]: any;
|
|
66
|
-
}>) | (ForwardRefExoticComponent<T> & {
|
|
69
|
+
type ElementType<T extends TObj | unknown = any> = ComponentType<T> & Partial<{
|
|
67
70
|
[key: string]: any;
|
|
68
|
-
}
|
|
71
|
+
}>;
|
|
69
72
|
type ValueOf<T> = T[keyof T];
|
|
70
73
|
type ArrayOfValues<T> = T[keyof T][];
|
|
71
74
|
type ArrayOfKeys<T> = Array<keyof T>;
|
|
@@ -78,7 +81,7 @@ type ExtractNullableKeys<T> = { [P in keyof T as IsAny<T[P]> extends true ? P :
|
|
|
78
81
|
type SpreadTwo<L, R> = Id<Pick<L, Exclude<keyof L, keyof R>> & R>;
|
|
79
82
|
type Spread<A extends readonly [...any]> = A extends [infer L, ...infer R] ? SpreadTwo<L, Spread<R>> : unknown;
|
|
80
83
|
type MergeTypes<A extends readonly [...any]> = ExtractNullableKeys<Spread<A>>;
|
|
81
|
-
type ExtractProps<TComponentOrTProps> = TComponentOrTProps extends ComponentType<infer TProps> ? TProps : TComponentOrTProps
|
|
84
|
+
type ExtractProps<TComponentOrTProps> = TComponentOrTProps extends ComponentType<infer TProps> ? TProps : TComponentOrTProps;
|
|
82
85
|
//#endregion
|
|
83
86
|
//#region src/types/styles.d.ts
|
|
84
87
|
interface StylesDefault {}
|
|
@@ -129,16 +132,17 @@ type ExtractDimensionMulti<T extends DimensionValue> = T extends DimensionValueO
|
|
|
129
132
|
type DimensionValuePrimitive = string;
|
|
130
133
|
type DimensionValueObj = {
|
|
131
134
|
propName: string;
|
|
132
|
-
multi?: boolean;
|
|
135
|
+
multi?: boolean; /** When true, this dimension is evaluated last and its values receive the accumulated theme as argument. */
|
|
136
|
+
transform?: boolean;
|
|
133
137
|
};
|
|
134
138
|
type DimensionValue = DimensionValuePrimitive | DimensionValueObj;
|
|
135
139
|
type Dimensions = Record<string, DimensionValue>;
|
|
136
140
|
type MultiKeys<T extends Dimensions = Dimensions> = Partial<Record<ExtractDimensionKey<T[keyof T]>, true>>;
|
|
137
141
|
type DeepPartial<T> = { [K in keyof T]?: T[K] extends ((...args: any[]) => any) ? T[K] : NonNullable<T[K]> extends Record<string, any> ? DeepPartial<NonNullable<T[K]>> | Extract<T[K], null> : T[K] };
|
|
138
|
-
type DimensionResult<CT> = Record<string, boolean | null | DeepPartial<CT
|
|
139
|
-
type DimensionObj<CT> = DimensionResult<CT>;
|
|
140
|
-
type DimensionCb<T, CT> = (theme: T, mode: ThemeModeCallback, css: Css) => DimensionResult<CT>;
|
|
141
|
-
type DimensionCallbackParam<T, CT> = DimensionObj<CT> | DimensionCb<T, CT>;
|
|
142
|
+
type DimensionResult<CT, T = any> = Record<string, boolean | null | DeepPartial<CT> | ((theme: CT, appTheme: T, mode: ThemeModeCallback, css: Css) => DeepPartial<CT>)>;
|
|
143
|
+
type DimensionObj<CT, T = any> = DimensionResult<CT, T>;
|
|
144
|
+
type DimensionCb<T, CT> = (theme: T, mode: ThemeModeCallback, css: Css) => DimensionResult<CT, T>;
|
|
145
|
+
type DimensionCallbackParam<T, CT> = DimensionObj<CT, T> | DimensionCb<T, CT>;
|
|
142
146
|
type TDKP = Record<ExtractDimensionKey<Dimensions[keyof Dimensions]>, Record<string, boolean | never | Record<string, boolean>> | unknown>;
|
|
143
147
|
type DimensionProps<K extends DimensionValue, D extends Dimensions, P extends CallBackParam, DKP extends TDKP> = { [I in ExtractDimensionKey<D[keyof D]>]: I extends ExtractDimensionKey<K> ? ExtractNullableDimensionKeys<Spread<[DKP[I], NullableKeys<ReturnCbParam<P>>]>> : DKP[I] };
|
|
144
148
|
type DimensionTypesHelper<DKP extends TDKP> = { [I in keyof DKP]: keyof DKP[I] };
|
|
@@ -181,6 +185,7 @@ type InitConfiguration<C, D> = {
|
|
|
181
185
|
dimensionKeys: ArrayOfKeys<D>;
|
|
182
186
|
dimensionValues: ArrayOfValues<D>;
|
|
183
187
|
multiKeys: MultiKeys;
|
|
188
|
+
transformKeys: Partial<Record<string, true>>;
|
|
184
189
|
};
|
|
185
190
|
type Configuration<C = ElementType | unknown, D extends Dimensions = Dimensions> = InitConfiguration<C, D> & {
|
|
186
191
|
provider?: boolean;
|
|
@@ -212,10 +217,6 @@ type GenericHoc = (component: ElementType) => ElementType;
|
|
|
212
217
|
type ComposeParam = Record<string, GenericHoc | null | undefined | false>;
|
|
213
218
|
//#endregion
|
|
214
219
|
//#region src/types/rocketstyle.d.ts
|
|
215
|
-
interface ExoticComponent<P = {}> {
|
|
216
|
-
(props: P): ReactNode;
|
|
217
|
-
readonly $$typeof: symbol;
|
|
218
|
-
}
|
|
219
220
|
type RocketStyleComponent<OA extends TObj = {}, EA extends TObj = {}, T extends TObj = {}, CSS extends TObj = {}, S extends TObj = {}, HOC extends TObj = {}, D extends Dimensions = Dimensions, UB extends boolean = boolean, DKP extends TDKP = TDKP> = IRocketStyleComponent<OA, EA, T, CSS, S, HOC, D, UB, DKP> & { [I in keyof D]: <K extends DimensionValue = D[I], P extends DimensionCallbackParam<Theme<T>, Styles<CSS>> = DimensionCallbackParam<Theme<T>, Styles<CSS>>>(param: P) => P extends DimensionCallbackParam<Theme<T>, Styles<CSS>> ? RocketStyleComponent<OA, EA, T, CSS, S, HOC, D, UB, DimensionProps<K, D, P, DKP>> : RocketStyleComponent<OA, EA, T, CSS, S, HOC, D, UB, DKP> };
|
|
220
221
|
/**
|
|
221
222
|
* @param OA Origin component props params.
|
|
@@ -228,7 +229,10 @@ type RocketStyleComponent<OA extends TObj = {}, EA extends TObj = {}, T extends
|
|
|
228
229
|
* @param DKP Dimensions key props.
|
|
229
230
|
* @param DFP Calculated final component props
|
|
230
231
|
*/
|
|
231
|
-
interface IRocketStyleComponent<OA extends TObj = {}, EA extends TObj = {}, T extends TObj = {}, CSS extends TObj = {}, S extends TObj = {}, HOC extends TObj = {}, D extends Dimensions = Dimensions, UB extends boolean = boolean, DKP extends TDKP = TDKP, DFP = MergeTypes<[OA, EA, DefaultProps, ExtractDimensionProps<D, DKP, UB>]>>
|
|
232
|
+
interface IRocketStyleComponent<OA extends TObj = {}, EA extends TObj = {}, T extends TObj = {}, CSS extends TObj = {}, S extends TObj = {}, HOC extends TObj = {}, D extends Dimensions = Dimensions, UB extends boolean = boolean, DKP extends TDKP = TDKP, DFP = MergeTypes<[OA, EA, DefaultProps, ExtractDimensionProps<D, DKP, UB>]>> {
|
|
233
|
+
(props: DFP & {
|
|
234
|
+
ref?: any;
|
|
235
|
+
}): ReactNode;
|
|
232
236
|
/**
|
|
233
237
|
* A chaining method to define default component theme
|
|
234
238
|
* @param param _object_
|
|
@@ -568,11 +572,11 @@ type Rocketstyle = <D extends Dimensions = DefaultDimensions, UB extends boolean
|
|
|
568
572
|
name: string;
|
|
569
573
|
component: C;
|
|
570
574
|
}) => ReturnType<RocketComponent<C, {}, {}, D, UB>>;
|
|
571
|
-
declare const
|
|
575
|
+
declare const typedRocketstyle: Rocketstyle;
|
|
572
576
|
//#endregion
|
|
573
577
|
//#region src/isRocketComponent.d.ts
|
|
574
578
|
type IsRocketComponent = <T>(component: T) => boolean;
|
|
575
579
|
declare const isRocketComponent: IsRocketComponent;
|
|
576
580
|
//#endregion
|
|
577
|
-
export { type AttrsCb, type ComposeParam, type ConfigAttrs, type ConsumerCb, type ConsumerCtxCBValue, type ConsumerCtxCb, type DefaultProps, type DimensionCallbackParam, type DimensionProps, type DimensionValue, type Dimensions, type ElementType, type ExtractDimensionProps, type ExtractDimensions, type ExtractProps, type GenericHoc, type IRocketStyleComponent, type IsRocketComponent, type MergeTypes, Provider, type RocketComponentType, type RocketProviderState, type RocketStyleComponent, type RocketStyleInterpolationProps, type Rocketstyle, type StylesCb, type StylesDefault, type TDKP, type TObj, type TProvider, type ThemeCb, type ThemeDefault, type ThemeMode, type ThemeModeCallback, type ThemeModeKeys, context,
|
|
581
|
+
export { type AttrsCb, type ComposeParam, type ConfigAttrs, type ConsumerCb, type ConsumerCtxCBValue, type ConsumerCtxCb, type DefaultProps, type DimensionCallbackParam, type DimensionProps, type DimensionValue, type Dimensions, type ElementType, type ExtractDimensionProps, type ExtractDimensions, type ExtractProps, type GenericHoc, type IRocketStyleComponent, type IsRocketComponent, type MergeTypes, Provider, type RocketComponentType, type RocketProviderState, type RocketStyleComponent, type RocketStyleInterpolationProps, type Rocketstyle, type StylesCb, type StylesDefault, type TDKP, type TObj, type TProvider, type ThemeCb, type ThemeDefault, type ThemeMode, type ThemeModeCallback, type ThemeModeKeys, context, typedRocketstyle as default, typedRocketstyle as rocketstyle, isRocketComponent };
|
|
578
582
|
//# sourceMappingURL=index2.d.ts.map
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Provider as Provider$1, compose, config, context, get, hoistNonReactStatics, isEmpty, merge, omit, pick, render, set, useStableValue } from "@vitus-labs/core";
|
|
2
|
-
import { createContext,
|
|
2
|
+
import { createContext, useCallback, useContext, useImperativeHandle, useMemo, useRef, useState } from "react";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/constants/index.ts
|
|
@@ -85,6 +85,11 @@ const DEFAULT_DIMENSIONS = {
|
|
|
85
85
|
multiple: {
|
|
86
86
|
propName: "multiple",
|
|
87
87
|
multi: true
|
|
88
|
+
},
|
|
89
|
+
modifiers: {
|
|
90
|
+
propName: "modifier",
|
|
91
|
+
multi: true,
|
|
92
|
+
transform: true
|
|
88
93
|
}
|
|
89
94
|
};
|
|
90
95
|
|
|
@@ -197,12 +202,18 @@ const useThemeAttrs = ({ inversed }) => {
|
|
|
197
202
|
const { theme = {}, mode: ctxMode = "light", isDark: ctxDark } = useContext(context) || {};
|
|
198
203
|
const mode = inversed ? THEME_MODES_INVERSED[ctxMode] : ctxMode;
|
|
199
204
|
const isDark = inversed ? !ctxDark : ctxDark;
|
|
200
|
-
|
|
205
|
+
const isLight = !isDark;
|
|
206
|
+
return useMemo(() => ({
|
|
201
207
|
theme,
|
|
202
208
|
mode,
|
|
203
209
|
isDark,
|
|
204
|
-
isLight
|
|
205
|
-
}
|
|
210
|
+
isLight
|
|
211
|
+
}), [
|
|
212
|
+
theme,
|
|
213
|
+
mode,
|
|
214
|
+
isDark,
|
|
215
|
+
isLight
|
|
216
|
+
]);
|
|
206
217
|
};
|
|
207
218
|
|
|
208
219
|
//#endregion
|
|
@@ -213,13 +224,16 @@ const useThemeAttrs = ({ inversed }) => {
|
|
|
213
224
|
* to its rocketstyle children.
|
|
214
225
|
*/
|
|
215
226
|
const context$1 = createContext({});
|
|
227
|
+
const EMPTY_CTX = { pseudo: {} };
|
|
216
228
|
const useLocalContext = (consumer) => {
|
|
217
229
|
const ctx = useContext(context$1);
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
230
|
+
return useMemo(() => {
|
|
231
|
+
if (!consumer) return EMPTY_CTX;
|
|
232
|
+
return {
|
|
233
|
+
pseudo: {},
|
|
234
|
+
...consumer((callback) => callback(ctx))
|
|
235
|
+
};
|
|
236
|
+
}, [consumer, ctx]);
|
|
223
237
|
};
|
|
224
238
|
const LocalProvider = context$1.Provider;
|
|
225
239
|
|
|
@@ -230,32 +244,35 @@ const LocalProvider = context$1.Provider;
|
|
|
230
244
|
* detecting pseudo-states (hover, focus, pressed) via mouse/focus events
|
|
231
245
|
* and broadcasting them through local context to child rocketstyle components.
|
|
232
246
|
*/
|
|
233
|
-
const RocketStyleProviderComponent = (WrappedComponent) =>
|
|
234
|
-
const {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
});
|
|
247
|
+
const RocketStyleProviderComponent = (WrappedComponent) => {
|
|
248
|
+
const HOC = ({ onMouseEnter, onMouseLeave, onMouseUp, onMouseDown, onFocus, onBlur, $rocketstate, ref, ...props }) => {
|
|
249
|
+
const { state: pseudoState, events: pseudoEvents } = usePseudoState({
|
|
250
|
+
onMouseEnter,
|
|
251
|
+
onMouseLeave,
|
|
252
|
+
onMouseUp,
|
|
253
|
+
onMouseDown,
|
|
254
|
+
onFocus,
|
|
255
|
+
onBlur
|
|
256
|
+
});
|
|
257
|
+
const updatedState = useStableValue({
|
|
258
|
+
...$rocketstate,
|
|
259
|
+
pseudo: {
|
|
260
|
+
...$rocketstate.pseudo,
|
|
261
|
+
...pseudoState
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
return /* @__PURE__ */ jsx(LocalProvider, {
|
|
265
|
+
value: updatedState,
|
|
266
|
+
children: /* @__PURE__ */ jsx(WrappedComponent, {
|
|
267
|
+
...props,
|
|
268
|
+
...pseudoEvents,
|
|
269
|
+
ref,
|
|
270
|
+
$rocketstate: updatedState
|
|
271
|
+
})
|
|
272
|
+
});
|
|
273
|
+
};
|
|
274
|
+
return HOC;
|
|
275
|
+
};
|
|
259
276
|
|
|
260
277
|
//#endregion
|
|
261
278
|
//#region src/utils/attrs.ts
|
|
@@ -283,17 +300,20 @@ const calculateStylingAttrs = ({ useBooleans, multiKeys }) => ({ props, dimensio
|
|
|
283
300
|
else result[item] = void 0;
|
|
284
301
|
});
|
|
285
302
|
if (useBooleans) {
|
|
286
|
-
const propsKeys = Object.keys(props)
|
|
303
|
+
const propsKeys = Object.keys(props);
|
|
287
304
|
Object.entries(result).forEach(([key, value]) => {
|
|
288
305
|
const isMultiKey = multiKeys[key];
|
|
289
306
|
if (!value) {
|
|
290
307
|
let newDimensionValue;
|
|
291
|
-
const
|
|
292
|
-
if (isMultiKey) newDimensionValue = propsKeys.filter((key) =>
|
|
293
|
-
else
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
308
|
+
const keywordSet = new Set(Object.keys(dimensions[key]));
|
|
309
|
+
if (isMultiKey) newDimensionValue = propsKeys.filter((key) => keywordSet.has(key));
|
|
310
|
+
else for (let i = propsKeys.length - 1; i >= 0; i--) {
|
|
311
|
+
const k = propsKeys[i];
|
|
312
|
+
if (keywordSet.has(k) && props[k]) {
|
|
313
|
+
newDimensionValue = k;
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
297
317
|
result[key] = newDimensionValue;
|
|
298
318
|
}
|
|
299
319
|
});
|
|
@@ -312,27 +332,30 @@ const calculateStylingAttrs = ({ useBooleans, multiKeys }) => ({ props, dimensio
|
|
|
312
332
|
const rocketStyleHOC = ({ inversed, attrs, priorityAttrs }) => {
|
|
313
333
|
const calculateAttrs = calculateChainOptions(attrs);
|
|
314
334
|
const calculatePriorityAttrs = calculateChainOptions(priorityAttrs);
|
|
315
|
-
const Enhanced = (WrappedComponent) =>
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
335
|
+
const Enhanced = (WrappedComponent) => {
|
|
336
|
+
const HOC = ({ ref, ...props }) => {
|
|
337
|
+
const { theme, mode, isDark, isLight } = useThemeAttrs({ inversed });
|
|
338
|
+
const callbackParams = [theme, {
|
|
339
|
+
render,
|
|
340
|
+
mode,
|
|
341
|
+
isDark,
|
|
342
|
+
isLight
|
|
343
|
+
}];
|
|
344
|
+
const filteredProps = removeUndefinedProps(props);
|
|
345
|
+
const prioritizedAttrs = calculatePriorityAttrs([filteredProps, ...callbackParams]);
|
|
346
|
+
const finalAttrs = calculateAttrs([{
|
|
347
|
+
...prioritizedAttrs,
|
|
348
|
+
...filteredProps
|
|
349
|
+
}, ...callbackParams]);
|
|
350
|
+
return /* @__PURE__ */ jsx(WrappedComponent, {
|
|
351
|
+
$rocketstyleRef: ref,
|
|
352
|
+
...prioritizedAttrs,
|
|
353
|
+
...finalAttrs,
|
|
354
|
+
...filteredProps
|
|
355
|
+
});
|
|
356
|
+
};
|
|
357
|
+
return HOC;
|
|
358
|
+
};
|
|
336
359
|
return Enhanced;
|
|
337
360
|
};
|
|
338
361
|
|
|
@@ -393,6 +416,12 @@ const getMultipleDimensions = (obj) => getValues(obj).reduce((accumulator, value
|
|
|
393
416
|
}
|
|
394
417
|
return accumulator;
|
|
395
418
|
}, {});
|
|
419
|
+
const getTransformDimensions = (obj) => getValues(obj).reduce((accumulator, value) => {
|
|
420
|
+
if (typeof value === "object") {
|
|
421
|
+
if (value.transform === true) accumulator[value.propName] = true;
|
|
422
|
+
}
|
|
423
|
+
return accumulator;
|
|
424
|
+
}, {});
|
|
396
425
|
|
|
397
426
|
//#endregion
|
|
398
427
|
//#region src/utils/statics.ts
|
|
@@ -421,12 +450,17 @@ const removeNullableValues = (obj) => Object.entries(obj).filter(([, v]) => v !=
|
|
|
421
450
|
|
|
422
451
|
//#endregion
|
|
423
452
|
//#region src/utils/theme.ts
|
|
453
|
+
const MODE_CALLBACK_BRAND = Symbol.for("vl.themeModeCallback");
|
|
424
454
|
/** Creates a mode-switching function that returns the light or dark value based on the active mode. */
|
|
425
|
-
const themeModeCallback = (light, dark) =>
|
|
426
|
-
|
|
427
|
-
|
|
455
|
+
const themeModeCallback = (light, dark) => {
|
|
456
|
+
const fn = (mode) => {
|
|
457
|
+
if (!mode || mode === "light") return light;
|
|
458
|
+
return dark;
|
|
459
|
+
};
|
|
460
|
+
fn.__brand = MODE_CALLBACK_BRAND;
|
|
461
|
+
return fn;
|
|
428
462
|
};
|
|
429
|
-
const isModeCallback = (value) => typeof value === "function" && value.
|
|
463
|
+
const isModeCallback = (value) => typeof value === "function" && value.__brand === MODE_CALLBACK_BRAND;
|
|
430
464
|
const getThemeFromChain = (options, theme) => {
|
|
431
465
|
const result = {};
|
|
432
466
|
if (!options || isEmpty(options)) return result;
|
|
@@ -442,15 +476,22 @@ const getDimensionThemes = (theme, options) => {
|
|
|
442
476
|
return acc;
|
|
443
477
|
}, result);
|
|
444
478
|
};
|
|
445
|
-
const getTheme = ({ rocketstate, themes, baseTheme }) => {
|
|
446
|
-
|
|
479
|
+
const getTheme = ({ rocketstate, themes, baseTheme, transformKeys, appTheme }) => {
|
|
480
|
+
const finalTheme = { ...baseTheme };
|
|
481
|
+
const deferredTransforms = [];
|
|
447
482
|
Object.entries(rocketstate).forEach(([key, value]) => {
|
|
448
483
|
const keyTheme = themes[key];
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
484
|
+
const isTransform = transformKeys?.[key];
|
|
485
|
+
const mergeValue = (item) => {
|
|
486
|
+
const val = keyTheme[item];
|
|
487
|
+
if (val == null) return;
|
|
488
|
+
if (isTransform && typeof val === "function") deferredTransforms.push(val);
|
|
489
|
+
else merge(finalTheme, val);
|
|
490
|
+
};
|
|
491
|
+
if (Array.isArray(value)) value.forEach(mergeValue);
|
|
492
|
+
else mergeValue(value);
|
|
453
493
|
});
|
|
494
|
+
for (const transform of deferredTransforms) merge(finalTheme, transform(finalTheme, appTheme ?? {}, themeModeCallback, config.css));
|
|
454
495
|
return finalTheme;
|
|
455
496
|
};
|
|
456
497
|
const getThemeByMode = (object, mode) => Object.keys(object).reduce((acc, key) => {
|
|
@@ -463,6 +504,32 @@ const getThemeByMode = (object, mode) => Object.keys(object).reduce((acc, key) =
|
|
|
463
504
|
|
|
464
505
|
//#endregion
|
|
465
506
|
//#region src/rocketstyle.tsx
|
|
507
|
+
/**
|
|
508
|
+
* Core rocketstyle component factory. Creates a fully-featured React component
|
|
509
|
+
* that integrates theme management (with light/dark mode support), multi-tier
|
|
510
|
+
* WeakMap caching, dimension-based styling props, pseudo-state detection, and
|
|
511
|
+
* chainable static methods (`.attrs()`, `.theme()`, `.styles()`, `.config()`, etc.).
|
|
512
|
+
* @module rocketstyle
|
|
513
|
+
*/
|
|
514
|
+
const arraysEqual = (a, b) => {
|
|
515
|
+
if (a.length !== b.length) return false;
|
|
516
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
517
|
+
return true;
|
|
518
|
+
};
|
|
519
|
+
const isShallowEqualRocketstate = (a, b) => {
|
|
520
|
+
if (a === b) return true;
|
|
521
|
+
if (!a || !b) return false;
|
|
522
|
+
const aKeys = Object.keys(a);
|
|
523
|
+
if (aKeys.length !== Object.keys(b).length) return false;
|
|
524
|
+
for (const k of aKeys) {
|
|
525
|
+
const av = a[k];
|
|
526
|
+
const bv = b[k];
|
|
527
|
+
if (av === bv) continue;
|
|
528
|
+
if (Array.isArray(av) && Array.isArray(bv) && arraysEqual(av, bv)) continue;
|
|
529
|
+
return false;
|
|
530
|
+
}
|
|
531
|
+
return true;
|
|
532
|
+
};
|
|
466
533
|
/** Clones the current configuration and merges new options, returning a fresh rocketComponent. */
|
|
467
534
|
const cloneAndEnhance = (defaultOpts, opts) => rocketComponent({
|
|
468
535
|
...defaultOpts,
|
|
@@ -486,7 +553,7 @@ const cloneAndEnhance = (defaultOpts, opts) => rocketComponent({
|
|
|
486
553
|
* chainable static enhancers attached to the returned component.
|
|
487
554
|
*/
|
|
488
555
|
const rocketComponent = (options) => {
|
|
489
|
-
const { component, styles } = options;
|
|
556
|
+
const { component, styles, transformKeys } = options;
|
|
490
557
|
const { styled } = config;
|
|
491
558
|
const _calculateStylingAttrs = calculateStylingAttrs({
|
|
492
559
|
multiKeys: options.multiKeys,
|
|
@@ -499,7 +566,7 @@ const rocketComponent = (options) => {
|
|
|
499
566
|
const RenderComponent = options.provider ? RocketStyleProviderComponent(STYLED_COMPONENT) : STYLED_COMPONENT;
|
|
500
567
|
const ThemeManager$1 = new ThemeManager();
|
|
501
568
|
const hocsFuncs = [rocketStyleHOC(options), ...calculateHocsFuncs(options.compose)];
|
|
502
|
-
const EnhancedComponent =
|
|
569
|
+
const EnhancedComponent = ({ $rocketstyleRef, ref, ...props }) => {
|
|
503
570
|
const internalRef = useRocketstyleRef({
|
|
504
571
|
$rocketstyleRef,
|
|
505
572
|
ref
|
|
@@ -547,20 +614,20 @@ const rocketComponent = (options) => {
|
|
|
547
614
|
...rocketstate,
|
|
548
615
|
pseudo: pseudoRocketstate
|
|
549
616
|
};
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
rsKey += k;
|
|
554
|
-
rsKey += Array.isArray(v) ? v.join(",") : v;
|
|
555
|
-
}
|
|
617
|
+
const rocketstateRef = useRef(rocketstate);
|
|
618
|
+
if (!isShallowEqualRocketstate(rocketstateRef.current, rocketstate)) rocketstateRef.current = rocketstate;
|
|
619
|
+
const stableRocketstate = rocketstateRef.current;
|
|
556
620
|
const rocketstyle = useMemo(() => getTheme({
|
|
557
|
-
rocketstate,
|
|
621
|
+
rocketstate: stableRocketstate,
|
|
558
622
|
themes: currentModeThemes,
|
|
559
|
-
baseTheme: currentModeBaseTheme
|
|
623
|
+
baseTheme: currentModeBaseTheme,
|
|
624
|
+
transformKeys,
|
|
625
|
+
appTheme: theme
|
|
560
626
|
}), [
|
|
561
|
-
|
|
627
|
+
stableRocketstate,
|
|
562
628
|
currentModeThemes,
|
|
563
|
-
currentModeBaseTheme
|
|
629
|
+
currentModeBaseTheme,
|
|
630
|
+
theme
|
|
564
631
|
]);
|
|
565
632
|
const finalProps = {
|
|
566
633
|
...omit(mergeProps, [
|
|
@@ -589,7 +656,7 @@ const rocketComponent = (options) => {
|
|
|
589
656
|
}
|
|
590
657
|
}
|
|
591
658
|
return /* @__PURE__ */ jsx(RenderComponent, { ...finalProps });
|
|
592
|
-
}
|
|
659
|
+
};
|
|
593
660
|
const RocketComponent = compose(...hocsFuncs)(EnhancedComponent);
|
|
594
661
|
RocketComponent.IS_ROCKETSTYLE = true;
|
|
595
662
|
RocketComponent.displayName = componentName;
|
|
@@ -662,31 +729,44 @@ const validateInit = (name, component, dimensions) => {
|
|
|
662
729
|
}
|
|
663
730
|
if (!isEmpty(errors)) throw Error(JSON.stringify(errors));
|
|
664
731
|
};
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
732
|
+
/**
|
|
733
|
+
* Generic implementation. The `D | DefaultDimensions` runtime fallback is
|
|
734
|
+
* narrowed to `D` via a single cast — semantically correct because when no
|
|
735
|
+
* user dimensions are supplied, `D` *is* the default (its type-parameter
|
|
736
|
+
* default is `DefaultDimensions`). This single boundary cast replaces the
|
|
737
|
+
* file-wide `@ts-nocheck` previously used here.
|
|
738
|
+
*/
|
|
739
|
+
const rocketstyle = (params) => {
|
|
740
|
+
const dimensions = params?.dimensions ?? DEFAULT_DIMENSIONS;
|
|
741
|
+
const useBooleans = params?.useBooleans ?? true;
|
|
742
|
+
return ({ name, component }) => {
|
|
743
|
+
if (process.env.NODE_ENV !== "production") validateInit(name, component, dimensions);
|
|
744
|
+
return rocketComponent({
|
|
745
|
+
name,
|
|
746
|
+
component,
|
|
747
|
+
useBooleans,
|
|
748
|
+
dimensions,
|
|
749
|
+
dimensionKeys: getKeys(dimensions),
|
|
750
|
+
dimensionValues: getDimensionsValues(dimensions),
|
|
751
|
+
multiKeys: getMultipleDimensions(dimensions),
|
|
752
|
+
transformKeys: getTransformDimensions(dimensions),
|
|
753
|
+
styled: true
|
|
754
|
+
});
|
|
755
|
+
};
|
|
677
756
|
};
|
|
757
|
+
const typedRocketstyle = rocketstyle;
|
|
678
758
|
|
|
679
759
|
//#endregion
|
|
680
760
|
//#region src/isRocketComponent.tsx
|
|
681
761
|
const isRocketComponent = (component) => {
|
|
682
|
-
if (component && typeof component === "object"
|
|
762
|
+
if (component && (typeof component === "object" || typeof component === "function") && Object.hasOwn(component, "IS_ROCKETSTYLE")) return true;
|
|
683
763
|
return false;
|
|
684
764
|
};
|
|
685
765
|
|
|
686
766
|
//#endregion
|
|
687
767
|
//#region src/index.ts
|
|
688
|
-
var src_default =
|
|
768
|
+
var src_default = typedRocketstyle;
|
|
689
769
|
|
|
690
770
|
//#endregion
|
|
691
|
-
export { Provider, context, src_default as default, isRocketComponent, rocketstyle };
|
|
771
|
+
export { Provider, context, src_default as default, isRocketComponent, typedRocketstyle as rocketstyle };
|
|
692
772
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitus-labs/rocketstyle",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.28",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Vit Bokisch <vit@bokisch.cz>",
|
|
6
6
|
"maintainers": [
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"types": "./lib/index.d.ts"
|
|
15
15
|
},
|
|
16
16
|
"types": "./lib/index.d.ts",
|
|
17
|
+
"main": "./lib/index.js",
|
|
17
18
|
"files": [
|
|
18
19
|
"lib",
|
|
19
20
|
"!lib/**/*.map",
|
|
@@ -64,16 +65,15 @@
|
|
|
64
65
|
"version": "node ../../scripts/sync-peer-deps.mjs"
|
|
65
66
|
},
|
|
66
67
|
"peerDependencies": {
|
|
67
|
-
"@vitus-labs/core": "2.0.0-alpha.
|
|
68
|
+
"@vitus-labs/core": "2.0.0-alpha.28",
|
|
68
69
|
"react": ">= 19"
|
|
69
70
|
},
|
|
70
71
|
"devDependencies": {
|
|
71
|
-
"@vitus-labs/core": "
|
|
72
|
-
"@vitus-labs/elements": "
|
|
73
|
-
"@vitus-labs/tools-rolldown": "
|
|
74
|
-
"@vitus-labs/tools-storybook": "
|
|
75
|
-
"@vitus-labs/tools-typescript": "
|
|
76
|
-
"@vitus-labs/unistyle": "
|
|
77
|
-
}
|
|
78
|
-
"gitHead": "69d22f18b093f86a0bee235356ef3064f90c2d40"
|
|
72
|
+
"@vitus-labs/core": "workspace:*",
|
|
73
|
+
"@vitus-labs/elements": "workspace:*",
|
|
74
|
+
"@vitus-labs/tools-rolldown": "2.0.0",
|
|
75
|
+
"@vitus-labs/tools-storybook": "2.0.0",
|
|
76
|
+
"@vitus-labs/tools-typescript": "2.0.0",
|
|
77
|
+
"@vitus-labs/unistyle": "workspace:*"
|
|
78
|
+
}
|
|
79
79
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2023-present Vit Bokisch
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|