@codeandmoney/soelma 0.0.0-dev.0
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/.eslintignore +1 -0
- package/.eslintrc.js +31 -0
- package/.github/workflows/nodejs.yml +33 -0
- package/.size-limit.json +6 -0
- package/CHANGELOG.md +90 -0
- package/LICENSE +21 -0
- package/README.md +169 -0
- package/babel.config.js +3 -0
- package/docs/api.md +103 -0
- package/docs/appearance.md +54 -0
- package/docs/dark-mode.md +46 -0
- package/docs/dimensions.md +29 -0
- package/docs/i18n.md +67 -0
- package/docs/logo.png +0 -0
- package/docs/media-query.md +274 -0
- package/docs/orientation.md +44 -0
- package/docs/safe-area.md +62 -0
- package/docs/testting.md +51 -0
- package/docs/ts.md +127 -0
- package/example/AppStyleX/.watchmanconfig +1 -0
- package/example/AppStyleX/android/build.gradle +26 -0
- package/example/AppStyleX/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/example/AppStyleX/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/example/AppStyleX/android/gradle.properties +53 -0
- package/example/AppStyleX/android/gradlew +249 -0
- package/example/AppStyleX/android/gradlew.bat +92 -0
- package/example/AppStyleX/android/settings.gradle +12 -0
- package/example/AppStyleX/app.json +28 -0
- package/example/AppStyleX/babel.config.js +3 -0
- package/example/AppStyleX/index.js +9 -0
- package/example/AppStyleX/ios/Podfile +7 -0
- package/example/AppStyleX/ios/Podfile.lock +1252 -0
- package/example/AppStyleX/metro.config.js +54 -0
- package/example/AppStyleX/package.json +43 -0
- package/example/AppStyleX/react-native.config.js +23 -0
- package/example/AppStyleX/src/App.tsx +25 -0
- package/example/AppStyleX/src/BottomNav/index.tsx +32 -0
- package/example/AppStyleX/src/BottomNav/styles.ts +42 -0
- package/example/AppStyleX/src/Circle/index.tsx +53 -0
- package/example/AppStyleX/src/Circle/styles.ts +22 -0
- package/example/AppStyleX/src/Root/index.tsx +41 -0
- package/example/AppStyleX/src/Root/styles.ts +18 -0
- package/example/AppStyleX/src/ToggleButton/index.tsx +66 -0
- package/example/AppStyleX/src/ToggleButton/styles.ts +69 -0
- package/example/AppStyleX/src/style-system/hooks/useAnimatedBgColor.ts +5 -0
- package/example/AppStyleX/src/style-system/hooks/useAnimatedTextColor.ts +5 -0
- package/example/AppStyleX/src/style-system/hooks/useIsDark.ts +8 -0
- package/example/AppStyleX/src/style-system/palette.ts +11 -0
- package/example/AppStyleX/src/style-system/theme.ts +14 -0
- package/example/AppStyleX/src/style-system/utils.ts +11 -0
- package/example/AppStyleX/src/stylex.d.ts +6 -0
- package/example/AppStyleX/tsconfig.json +3 -0
- package/example/AppStyleX/yarn.lock +6767 -0
- package/jest.config.js +19 -0
- package/package.json +59 -0
- package/src/DefaultTheme.ts +4 -0
- package/src/__tests__/createBreakpoints.test.ts +152 -0
- package/src/__tests__/createBreakpointsMatcher.test.ts +188 -0
- package/src/__tests__/createBreakpointsMatcher.types-test.ts +81 -0
- package/src/__tests__/createEventEmitter.test.ts +37 -0
- package/src/__tests__/dark-mode.test.ts +56 -0
- package/src/__tests__/dependencyRegistry.test.ts +16 -0
- package/src/__tests__/dependencyUsage.test.ts +13 -0
- package/src/__tests__/dimensions.test.ts +36 -0
- package/src/__tests__/makeUseStyles.types-test.ts +69 -0
- package/src/__tests__/media-query.test.ts +204 -0
- package/src/__tests__/orientation.test.ts +61 -0
- package/src/__tests__/useTheme.test.ts +26 -0
- package/src/__tests__/withStyles.types-test.tsx +173 -0
- package/src/appearance/consts.ts +1 -0
- package/src/appearance/index.ts +37 -0
- package/src/appearance/init.ts +12 -0
- package/src/context.ts +9 -0
- package/src/createEventEmitter.ts +26 -0
- package/src/dark-mode/consts.ts +1 -0
- package/src/dark-mode/index.ts +29 -0
- package/src/dark-mode/init.ts +19 -0
- package/src/dark-mode/state.ts +5 -0
- package/src/dependencyRegistry.ts +21 -0
- package/src/dependencyUsage.ts +31 -0
- package/src/dimensions/consts.ts +2 -0
- package/src/dimensions/index.ts +20 -0
- package/src/dimensions/init.ts +37 -0
- package/src/dimensions/utils.ts +11 -0
- package/src/i18n.ts +18 -0
- package/src/index.ts +7 -0
- package/src/makeUseStyles/createUseStylesTheme.js +42 -0
- package/src/makeUseStyles/createUseStylesTheme.test.js +137 -0
- package/src/makeUseStyles/createUseStylesWithoutTheme.js +38 -0
- package/src/makeUseStyles/createUseStylesWithoutTheme.test.js +63 -0
- package/src/makeUseStyles/index.d.ts +7 -0
- package/src/makeUseStyles/index.js +12 -0
- package/src/makeUseStyles/index.test.js +28 -0
- package/src/makeUseStyles/test-type.js +28 -0
- package/src/makeUseStyles/utils.js +67 -0
- package/src/media-query/base.ts +43 -0
- package/src/media-query/breakpoints.ts +121 -0
- package/src/media-query/index.ts +12 -0
- package/src/orientation.ts +17 -0
- package/src/safe-area/SafeAreaProvider.tsx +17 -0
- package/src/safe-area/StylexSaveAreaConsumer.ts +23 -0
- package/src/safe-area/consts.ts +1 -0
- package/src/safe-area/eventEmitter.ts +4 -0
- package/src/safe-area/index.tsx +16 -0
- package/src/safe-area/init.tsx +6 -0
- package/src/safe-area/state.ts +12 -0
- package/src/safe-area/types.ts +10 -0
- package/src/useColorTransition.ts +50 -0
- package/src/useTheme.ts +16 -0
- package/src/withStyles.tsx +35 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { minAspectRatio, minWidth, minHeight, maxWidth } from "./base";
|
|
2
|
+
|
|
3
|
+
interface BreakpointsMatcher<TBreakpoints> {
|
|
4
|
+
<T>(values: { [mode in keyof TBreakpoints]?: T }): T | undefined;
|
|
5
|
+
<T>(values: { [mode in keyof TBreakpoints]?: T } & { default: T }): T;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const orderByMin = [minWidth, minAspectRatio, minHeight];
|
|
9
|
+
|
|
10
|
+
const toOrderedBreakpointNames = <TBreakpoints extends Record<string, number>>(
|
|
11
|
+
values: any,
|
|
12
|
+
breakpoints: any,
|
|
13
|
+
matchFunction: any
|
|
14
|
+
): Array<keyof TBreakpoints> => {
|
|
15
|
+
const result = Object.keys(values)
|
|
16
|
+
.filter((e) => e !== "default")
|
|
17
|
+
.sort((a, b) => breakpoints[a] - breakpoints[b]);
|
|
18
|
+
|
|
19
|
+
if (orderByMin.includes(matchFunction)) {
|
|
20
|
+
return result.slice().reverse();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/*
|
|
27
|
+
* To debug use analog on CSS: https://codepen.io/retyui/pen/dyOzKzV
|
|
28
|
+
*/
|
|
29
|
+
export function createBreakpointsMatcher<
|
|
30
|
+
TBreakpoints extends Record<string, number>
|
|
31
|
+
>(
|
|
32
|
+
breakpoints: TBreakpoints,
|
|
33
|
+
matchFunction = minWidth
|
|
34
|
+
): BreakpointsMatcher<TBreakpoints> {
|
|
35
|
+
return function breakpointsMatcher(values: any) {
|
|
36
|
+
/* istanbul ignore next */
|
|
37
|
+
// @ts-expect-error: was removed
|
|
38
|
+
if (process.env.NODE_ENV !== "production") {
|
|
39
|
+
const invalidKeys = Object.keys(values).filter((key) => {
|
|
40
|
+
return key !== "default" && breakpoints[key] === undefined;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (invalidKeys.length > 0) {
|
|
44
|
+
console.warn(
|
|
45
|
+
`[react-native-stylex]: Invalid values was passed to 'breakpointsMatcher' function
|
|
46
|
+
|
|
47
|
+
allowed keys: ${Object.keys(breakpoints).join(", ")}
|
|
48
|
+
unexpected keys: ${invalidKeys.join(", ")}
|
|
49
|
+
`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const orderedBreakpointNames = toOrderedBreakpointNames<TBreakpoints>(
|
|
55
|
+
values,
|
|
56
|
+
breakpoints,
|
|
57
|
+
matchFunction
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const key =
|
|
61
|
+
orderedBreakpointNames.find((breakpointName) =>
|
|
62
|
+
matchFunction(
|
|
63
|
+
breakpoints[breakpointName] as number,
|
|
64
|
+
values[breakpointName]
|
|
65
|
+
)
|
|
66
|
+
) || "default";
|
|
67
|
+
|
|
68
|
+
return values[key] || null;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function getNextByKey<TBreakpoints extends Record<string, number>>(
|
|
73
|
+
breakpoints: TBreakpoints,
|
|
74
|
+
key: keyof TBreakpoints
|
|
75
|
+
) {
|
|
76
|
+
type Keys = keyof TBreakpoints;
|
|
77
|
+
|
|
78
|
+
const breakpointsKeys: Array<Keys> = Object.keys(breakpoints).sort(
|
|
79
|
+
(a: Keys, b: Keys) => breakpoints[a]! - breakpoints[b]!
|
|
80
|
+
);
|
|
81
|
+
const index = breakpointsKeys.indexOf(key);
|
|
82
|
+
const nextKey: Keys | undefined = breakpointsKeys[index + 1];
|
|
83
|
+
|
|
84
|
+
return nextKey;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function createBreakpoints<TBreakpoints extends Record<string, number>>(
|
|
88
|
+
breakpoints: TBreakpoints
|
|
89
|
+
) {
|
|
90
|
+
type Keys = keyof TBreakpoints;
|
|
91
|
+
|
|
92
|
+
function up<T>(key: Keys, value: T): T | null {
|
|
93
|
+
return minWidth<T>(breakpoints[key] as number, value);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function down<T>(key: Keys, value: T): T | null {
|
|
97
|
+
return maxWidth<T>(breakpoints[key] as number, value);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function only<T>(key: Keys, value: T): T | null {
|
|
101
|
+
const nextKey = getNextByKey<TBreakpoints>(breakpoints, key);
|
|
102
|
+
|
|
103
|
+
if (nextKey !== undefined) {
|
|
104
|
+
return minWidth(
|
|
105
|
+
breakpoints[key] as number,
|
|
106
|
+
maxWidth(breakpoints[nextKey]! - 0.05, value)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return minWidth(breakpoints[key] as number, value);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function between<T>(start: Keys, end: Keys, value: T): T | null {
|
|
114
|
+
return minWidth(
|
|
115
|
+
breakpoints[start] as number,
|
|
116
|
+
maxWidth(breakpoints[end]! - 0.05, value)
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return { up, down, only, between };
|
|
121
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getScreenDimensions } from "./dimensions";
|
|
2
|
+
|
|
3
|
+
type OrientationType = "portrait" | "landscape";
|
|
4
|
+
|
|
5
|
+
export function orientation<T>(
|
|
6
|
+
spec: { [orientation in OrientationType]?: T }
|
|
7
|
+
): T | undefined {
|
|
8
|
+
const { height, width } = getScreenDimensions();
|
|
9
|
+
|
|
10
|
+
return width <= height ? spec.portrait : spec.landscape;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const portraitOrientation = <T>(portraitStyles: T): T | undefined =>
|
|
14
|
+
orientation<T>({ portrait: portraitStyles });
|
|
15
|
+
|
|
16
|
+
export const landscapeOrientation = <T>(landscapeStyles: T): T | undefined =>
|
|
17
|
+
orientation<T>({ landscape: landscapeStyles });
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { SafeAreaProvider as CoreSafeAreaProvider, initialWindowMetrics,initialWindowSafeAreaInsets } from "react-native-safe-area-context";
|
|
3
|
+
|
|
4
|
+
import { StylexSaveAreaConsumer } from "./StylexSaveAreaConsumer";
|
|
5
|
+
import { SafeAreaViewProps } from "./types";
|
|
6
|
+
|
|
7
|
+
export function SafeAreaProvider(props: SafeAreaViewProps): JSX.Element | null {
|
|
8
|
+
return (
|
|
9
|
+
<CoreSafeAreaProvider
|
|
10
|
+
initialSafeAreaInsets={props.initialSafeAreaInsets || initialWindowSafeAreaInsets}
|
|
11
|
+
initialMetrics={props.initialMetrics || initialWindowMetrics}
|
|
12
|
+
{...props}>
|
|
13
|
+
{props.children}
|
|
14
|
+
<StylexSaveAreaConsumer />
|
|
15
|
+
</CoreSafeAreaProvider>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
2
|
+
import { EdgeInsets } from "./types";
|
|
3
|
+
|
|
4
|
+
import { emit } from "./eventEmitter";
|
|
5
|
+
import { state } from "./state";
|
|
6
|
+
import { useLayoutEffect } from "react";
|
|
7
|
+
|
|
8
|
+
export function StylexSaveAreaConsumer(): JSX.Element | null {
|
|
9
|
+
const insets: EdgeInsets = useSafeAreaInsets();
|
|
10
|
+
|
|
11
|
+
useLayoutEffect(() => {
|
|
12
|
+
const isChanged = Object.entries(insets).some(
|
|
13
|
+
([key, value]) => state.insets[key as keyof EdgeInsets] !== value
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
if (isChanged) {
|
|
17
|
+
state.insets = insets;
|
|
18
|
+
emit();
|
|
19
|
+
}
|
|
20
|
+
}, [insets]);
|
|
21
|
+
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const SAFE_AREA_DEPENDENCY_KEY = "react-native-safe-area-context";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import "./init";
|
|
2
|
+
|
|
3
|
+
import { onUse } from "../dependencyUsage";
|
|
4
|
+
|
|
5
|
+
import { SAFE_AREA_DEPENDENCY_KEY } from "./consts";
|
|
6
|
+
import { EdgeInsets } from "./types";
|
|
7
|
+
import { state } from "./state";
|
|
8
|
+
|
|
9
|
+
export { StylexSaveAreaConsumer } from "./StylexSaveAreaConsumer";
|
|
10
|
+
export { SafeAreaProvider } from "./SafeAreaProvider";
|
|
11
|
+
|
|
12
|
+
export function getSafeArea(): EdgeInsets {
|
|
13
|
+
onUse(SAFE_AREA_DEPENDENCY_KEY);
|
|
14
|
+
|
|
15
|
+
return state.insets;
|
|
16
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
2
|
+
import { Animated } from "react-native";
|
|
3
|
+
import { DefaultTheme } from "./DefaultTheme";
|
|
4
|
+
import { useTheme } from "./useTheme";
|
|
5
|
+
|
|
6
|
+
const { Value, timing } = Animated;
|
|
7
|
+
|
|
8
|
+
const INITIAL_VALUE = 0;
|
|
9
|
+
const defaultOptions = { duration: 250 };
|
|
10
|
+
|
|
11
|
+
export function useColorTransition<Theme = DefaultTheme>(
|
|
12
|
+
colorGetterFn: (theme: Theme) => string,
|
|
13
|
+
options = defaultOptions
|
|
14
|
+
): Animated.AnimatedInterpolation<string> {
|
|
15
|
+
const theme = useTheme<Theme>();
|
|
16
|
+
const currentColor = colorGetterFn(theme);
|
|
17
|
+
const animatedValue = useRef(new Value(INITIAL_VALUE));
|
|
18
|
+
const colors = useRef({
|
|
19
|
+
toValue: INITIAL_VALUE,
|
|
20
|
+
prev: currentColor,
|
|
21
|
+
current: currentColor,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
if (currentColor !== colors.current.current) {
|
|
25
|
+
colors.current = {
|
|
26
|
+
toValue: colors.current.toValue === 0 ? 1 : 0,
|
|
27
|
+
prev: colors.current.current,
|
|
28
|
+
current: currentColor,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const { toValue, prev, current } = colors.current;
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
timing(animatedValue.current, {
|
|
36
|
+
toValue,
|
|
37
|
+
useNativeDriver: false,
|
|
38
|
+
...options,
|
|
39
|
+
}).start();
|
|
40
|
+
}, [toValue]);
|
|
41
|
+
|
|
42
|
+
return useMemo(() => {
|
|
43
|
+
const outputRange = toValue === 1 ? [prev, current] : [current, prev];
|
|
44
|
+
|
|
45
|
+
return animatedValue.current.interpolate({
|
|
46
|
+
inputRange: [0, 1],
|
|
47
|
+
outputRange,
|
|
48
|
+
});
|
|
49
|
+
}, [prev, current]);
|
|
50
|
+
}
|
package/src/useTheme.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useContext } from "react";
|
|
2
|
+
|
|
3
|
+
import { themeContext } from "./context";
|
|
4
|
+
import type { DefaultTheme } from "./DefaultTheme";
|
|
5
|
+
|
|
6
|
+
export const useTheme = <Theme = DefaultTheme>(): Theme => {
|
|
7
|
+
const contextValue = useContext(themeContext);
|
|
8
|
+
|
|
9
|
+
if (!contextValue) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
"[react-native-stylex]: Please make sure that you wrapped your component with <ThemeProvider/>."
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return contextValue as Theme;
|
|
16
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import React, {
|
|
3
|
+
ComponentProps,
|
|
4
|
+
ComponentType,
|
|
5
|
+
forwardRef,
|
|
6
|
+
Ref,
|
|
7
|
+
ElementRef
|
|
8
|
+
} from "react";
|
|
9
|
+
|
|
10
|
+
interface InjectedStyledProps<Styles> {
|
|
11
|
+
styles: Styles;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type InferInjectedStyledProps<
|
|
15
|
+
Fn extends (...args: any) => any
|
|
16
|
+
> = InjectedStyledProps<ReturnType<Fn>>;
|
|
17
|
+
|
|
18
|
+
export function withStyles<Styles>(useStyles: () => Styles) {
|
|
19
|
+
function WithStyles<TComponent extends ComponentType<any>>(
|
|
20
|
+
Component: TComponent
|
|
21
|
+
) {
|
|
22
|
+
const renderComponent = (
|
|
23
|
+
props: Omit<ComponentProps<TComponent>, "styles">,
|
|
24
|
+
ref: Ref<ElementRef<TComponent>>
|
|
25
|
+
) => {
|
|
26
|
+
const styles = useStyles();
|
|
27
|
+
// @ts-expect-error: 'ref' as never
|
|
28
|
+
return <Component {...props} ref={ref} styles={styles} />;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
return forwardRef(renderComponent);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return WithStyles;
|
|
35
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "ESNext",
|
|
4
|
+
"target": "ESNext",
|
|
5
|
+
"lib": ["ESNext"],
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"jsx": "react-native",
|
|
10
|
+
"strict": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"noImplicitAny": true,
|
|
14
|
+
"strictNullChecks": true,
|
|
15
|
+
"strictFunctionTypes": true,
|
|
16
|
+
"strictBindCallApply": true,
|
|
17
|
+
"strictPropertyInitialization": true,
|
|
18
|
+
"noImplicitThis": true,
|
|
19
|
+
"alwaysStrict": true,
|
|
20
|
+
"noUnusedLocals": false,
|
|
21
|
+
"noUnusedParameters": true,
|
|
22
|
+
"noImplicitReturns": true,
|
|
23
|
+
"noFallthroughCasesInSwitch": true,
|
|
24
|
+
"noUncheckedIndexedAccess": true,
|
|
25
|
+
"forceConsistentCasingInFileNames": true,
|
|
26
|
+
"moduleResolution": "node",
|
|
27
|
+
"outDir": "./lib"
|
|
28
|
+
},
|
|
29
|
+
"include": ["./src"]
|
|
30
|
+
}
|