@codeandmoney/soelma 0.0.0-dev.1 → 0.0.0-dev.10
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 +27 -0
- package/.github/workflows/nodejs.yml +33 -0
- package/.size-limit.json +6 -0
- package/babel.config.js +3 -0
- package/biome.jsonc +73 -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 +16 -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 +51 -0
- package/example/AppStyleX/package.json +43 -0
- package/example/AppStyleX/react-native.config.js +23 -0
- package/example/AppStyleX/src/App.tsx +22 -0
- package/example/AppStyleX/src/BottomNav/index.tsx +26 -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 +35 -0
- package/example/AppStyleX/src/Root/styles.ts +18 -0
- package/example/AppStyleX/src/ToggleButton/index.tsx +52 -0
- package/example/AppStyleX/src/ToggleButton/styles.ts +67 -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 +8 -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 +38 -3
- package/src/appearance/index.ts +30 -0
- package/src/appearance/init.ts +12 -0
- package/{context.js → src/context.ts} +4 -1
- package/src/create-event-emitter.ts +26 -0
- package/src/dark-mode/index.ts +26 -0
- package/src/dark-mode/init.ts +19 -0
- package/{dark-mode/state.js → src/dark-mode/state.ts} +2 -1
- package/src/default-theme.ts +4 -0
- package/src/dependency-registry.ts +21 -0
- package/src/dependency-usage.ts +21 -0
- package/src/dimensions/index.ts +20 -0
- package/src/dimensions/init.ts +32 -0
- package/src/dimensions/utils.ts +9 -0
- package/src/i18n.ts +15 -0
- package/src/index.ts +7 -0
- package/{makeUseStyles/createUseStylesTheme.js → src/make-use-styles/create-use-styles-theme.js} +23 -6
- package/src/make-use-styles/create-use-styles-theme.test.js +137 -0
- package/{makeUseStyles/createUseStylesWithoutTheme.js → src/make-use-styles/create-use-styles-without-theme.js} +20 -4
- package/src/make-use-styles/create-use-styles-without-theme.test.js +63 -0
- package/src/make-use-styles/index.d.ts +20 -0
- package/src/make-use-styles/index.js +12 -0
- package/src/make-use-styles/index.test.js +28 -0
- package/src/make-use-styles/types.ts +43 -0
- package/{makeUseStyles → src/make-use-styles}/utils.js +5 -10
- package/src/media-query/base.ts +32 -0
- package/src/media-query/breakpoints.ts +96 -0
- package/src/media-query/index.ts +12 -0
- package/src/orientation.ts +13 -0
- package/{safe-area/eventEmitter.js → src/safe-area/event-emitter.ts} +2 -1
- package/src/safe-area/index.tsx +16 -0
- package/src/safe-area/init.tsx +6 -0
- package/src/safe-area/safe-area-provider.tsx +18 -0
- package/{safe-area/state.js → src/safe-area/state.ts} +7 -5
- package/src/safe-area/stylex-save-area-consumer.ts +22 -0
- package/{safe-area/types.d.ts → src/safe-area/types.ts} +7 -6
- 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 +33 -0
- package/src/tests/makeUseStyles.types-test.ts +69 -0
- package/src/tests/media-query.test.ts +196 -0
- package/src/tests/orientation.test.ts +61 -0
- package/src/tests/useTheme.test.ts +26 -0
- package/src/tests/withStyles.types-test.tsx +172 -0
- package/src/use-color-transition.ts +50 -0
- package/src/use-theme.ts +14 -0
- package/src/with-styles.tsx +22 -0
- package/tsconfig.build.json +31 -0
- package/tsconfig.json +30 -0
- package/DefaultTheme.d.ts +0 -2
- package/DefaultTheme.js +0 -1
- package/appearance/consts.d.ts +0 -1
- package/appearance/index.d.ts +0 -8
- package/appearance/index.js +0 -18
- package/appearance/init.d.ts +0 -1
- package/appearance/init.js +0 -7
- package/context.d.ts +0 -4
- package/createEventEmitter.d.ts +0 -8
- package/createEventEmitter.js +0 -11
- package/dark-mode/consts.d.ts +0 -1
- package/dark-mode/index.d.ts +0 -7
- package/dark-mode/index.js +0 -16
- package/dark-mode/init.d.ts +0 -1
- package/dark-mode/init.js +0 -13
- package/dark-mode/state.d.ts +0 -3
- package/dependencyRegistry.d.ts +0 -5
- package/dependencyRegistry.js +0 -12
- package/dependencyUsage.d.ts +0 -7
- package/dependencyUsage.js +0 -10
- package/dimensions/consts.d.ts +0 -2
- package/dimensions/index.d.ts +0 -4
- package/dimensions/index.js +0 -13
- package/dimensions/init.d.ts +0 -1
- package/dimensions/init.js +0 -21
- package/dimensions/utils.d.ts +0 -1
- package/dimensions/utils.js +0 -7
- package/i18n.d.ts +0 -7
- package/i18n.js +0 -9
- package/index.d.ts +0 -7
- package/index.js +0 -5
- package/makeUseStyles/index.d.ts +0 -7
- package/makeUseStyles/index.js +0 -12
- package/media-query/base.d.ts +0 -12
- package/media-query/base.js +0 -18
- package/media-query/breakpoints.d.ts +0 -18
- package/media-query/breakpoints.js +0 -60
- package/media-query/index.d.ts +0 -2
- package/media-query/index.js +0 -2
- package/orientation.d.ts +0 -7
- package/orientation.js +0 -7
- package/safe-area/SafeAreaProvider.d.ts +0 -3
- package/safe-area/SafeAreaProvider.js +0 -9
- package/safe-area/StylexSaveAreaConsumer.d.ts +0 -2
- package/safe-area/StylexSaveAreaConsumer.js +0 -15
- package/safe-area/consts.d.ts +0 -1
- package/safe-area/eventEmitter.d.ts +0 -1
- package/safe-area/index.d.ts +0 -5
- package/safe-area/index.js +0 -10
- package/safe-area/init.d.ts +0 -1
- package/safe-area/init.js +0 -4
- package/safe-area/state.d.ts +0 -8
- package/safe-area/types.js +0 -1
- package/useColorTransition.d.ts +0 -5
- package/useColorTransition.js +0 -38
- package/useTheme.d.ts +0 -2
- package/useTheme.js +0 -9
- package/withStyles.d.ts +0 -7
- package/withStyles.js +0 -13
- /package/{appearance/consts.js → src/appearance/consts.ts} +0 -0
- /package/{dark-mode/consts.js → src/dark-mode/consts.ts} +0 -0
- /package/{dimensions/consts.js → src/dimensions/consts.ts} +0 -0
- /package/{makeUseStyles → src/make-use-styles}/test-type.js +0 -0
- /package/{safe-area/consts.js → src/safe-area/consts.ts} +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
|
|
3
|
+
const exclusionList = (() => {
|
|
4
|
+
try {
|
|
5
|
+
return require("metro-config/src/defaults/exclusionList");
|
|
6
|
+
} catch (_) {
|
|
7
|
+
// `blacklist` was renamed to `exclusionList` in 0.60
|
|
8
|
+
return require("metro-config/src/defaults/blacklist");
|
|
9
|
+
}
|
|
10
|
+
})();
|
|
11
|
+
|
|
12
|
+
const blockList = exclusionList([
|
|
13
|
+
/node_modules\/.*\/node_modules\/react-native\/.*/,
|
|
14
|
+
|
|
15
|
+
// This stops "react-native run-windows" from causing the metro server to
|
|
16
|
+
// crash if its already running
|
|
17
|
+
new RegExp(`${path.join(__dirname, "windows").replace(/[/\\]+/g, "/")}.*`),
|
|
18
|
+
|
|
19
|
+
// Workaround for `EPERM: operation not permitted, lstat '~\midl-MIDLRT-cl.read.1.tlog'`
|
|
20
|
+
/.*\.tlog/,
|
|
21
|
+
|
|
22
|
+
// Prevent Metro from watching temporary files generated by Visual Studio
|
|
23
|
+
// otherwise it may crash when they are removed when closing a project.
|
|
24
|
+
/.*\/.vs\/.*/,
|
|
25
|
+
|
|
26
|
+
// Workaround for `EBUSY: resource busy or locked, open '~\msbuild.ProjectImports.zip'`
|
|
27
|
+
/.*\.ProjectImports\.zip/,
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
const config = {
|
|
31
|
+
resolver: {
|
|
32
|
+
blacklistRE: blockList,
|
|
33
|
+
blockList,
|
|
34
|
+
},
|
|
35
|
+
transformer: {
|
|
36
|
+
getTransformOptions: async () => ({
|
|
37
|
+
transform: {
|
|
38
|
+
experimentalImportSupport: false,
|
|
39
|
+
inlineRequires: false,
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
// Starting with react-native 0.72, we are required to provide a full config.
|
|
47
|
+
const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config");
|
|
48
|
+
module.exports = mergeConfig(getDefaultConfig(__dirname), config);
|
|
49
|
+
} catch (_) {
|
|
50
|
+
module.exports = config;
|
|
51
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "AppStyleX",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"android": "react-native run-android",
|
|
7
|
+
"build:android": "mkdirp dist/res && react-native bundle --entry-file index.js --platform android --dev true --bundle-output dist/main.android.jsbundle --assets-dest dist/res",
|
|
8
|
+
"build:ios": "mkdirp dist && react-native bundle --entry-file index.js --platform ios --dev true --bundle-output dist/main.ios.jsbundle --assets-dest dist",
|
|
9
|
+
"ios": "react-native run-ios",
|
|
10
|
+
"lint": "eslint .",
|
|
11
|
+
"start": "react-native start",
|
|
12
|
+
"test": "jest"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"color": "^4.2.3",
|
|
16
|
+
"react": "18.2.0",
|
|
17
|
+
"react-native": "0.73.1",
|
|
18
|
+
"react-native-safe-area-context": "^4.8.1",
|
|
19
|
+
"react-native-stylex": "latest"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@babel/core": "^7.20.0",
|
|
23
|
+
"@babel/preset-env": "^7.20.0",
|
|
24
|
+
"@babel/runtime": "^7.20.0",
|
|
25
|
+
"@react-native/babel-preset": "^0.73.18",
|
|
26
|
+
"@react-native/eslint-config": "^0.73.1",
|
|
27
|
+
"@react-native/metro-config": "^0.73.2",
|
|
28
|
+
"@react-native/typescript-config": "^0.73.1",
|
|
29
|
+
"@types/react": "^18.2.6",
|
|
30
|
+
"@types/react-test-renderer": "^18.0.0",
|
|
31
|
+
"babel-jest": "^29.6.3",
|
|
32
|
+
"eslint": "^8.19.0",
|
|
33
|
+
"jest": "^29.6.3",
|
|
34
|
+
"mkdirp": "^1.0.0",
|
|
35
|
+
"prettier": "2.8.8",
|
|
36
|
+
"react-native-test-app": "^2.5.34",
|
|
37
|
+
"react-test-renderer": "18.2.0",
|
|
38
|
+
"typescript": "5.0.4"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const project = (() => {
|
|
2
|
+
try {
|
|
3
|
+
const { configureProjects } = require("react-native-test-app");
|
|
4
|
+
return configureProjects({
|
|
5
|
+
android: {
|
|
6
|
+
sourceDir: "android",
|
|
7
|
+
},
|
|
8
|
+
ios: {
|
|
9
|
+
sourceDir: "ios",
|
|
10
|
+
},
|
|
11
|
+
windows: {
|
|
12
|
+
sourceDir: "windows",
|
|
13
|
+
solutionFile: "windows/AppStyleX.sln",
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
} catch (_) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
})();
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
...(project ? { project } : undefined),
|
|
23
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import { ThemeProvider } from "react-native-stylex";
|
|
3
|
+
import { SafeAreaProvider } from "react-native-safe-area-context";
|
|
4
|
+
import { StylexSaveAreaConsumer } from "react-native-stylex/safe-area";
|
|
5
|
+
|
|
6
|
+
import { darkTheme, lightTheme } from "./style-system/theme";
|
|
7
|
+
|
|
8
|
+
import { Root } from "./Root";
|
|
9
|
+
|
|
10
|
+
export const App = () => {
|
|
11
|
+
const [theme, setTheme] = useState(lightTheme);
|
|
12
|
+
const toggleTheme = () => setTheme((currentTheme) => (currentTheme === darkTheme ? lightTheme : darkTheme));
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<SafeAreaProvider>
|
|
16
|
+
<ThemeProvider value={theme}>
|
|
17
|
+
<Root toggleTheme={toggleTheme} />
|
|
18
|
+
</ThemeProvider>
|
|
19
|
+
<StylexSaveAreaConsumer />
|
|
20
|
+
</SafeAreaProvider>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Animated } from "react-native";
|
|
3
|
+
import { useColorTransition } from "react-native-stylex";
|
|
4
|
+
|
|
5
|
+
import { useAnimatedBgColor } from "../style-system/hooks/useAnimatedBgColor";
|
|
6
|
+
import { useAnimatedTextColor } from "../style-system/hooks/useAnimatedTextColor";
|
|
7
|
+
|
|
8
|
+
import { useStyles } from "./styles";
|
|
9
|
+
|
|
10
|
+
export const BottomNav = () => {
|
|
11
|
+
const styles = useStyles();
|
|
12
|
+
const bgStyle = useAnimatedBgColor();
|
|
13
|
+
const textStyle = useAnimatedTextColor();
|
|
14
|
+
const skipAnimatedStyle = {
|
|
15
|
+
color: useColorTransition(({ palette, utils }) => utils.fade(palette.text, 0.5)),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
<Animated.Text style={[styles.skipBtn, skipAnimatedStyle]}>Skip</Animated.Text>
|
|
21
|
+
<Animated.View style={[styles.nextButton, bgStyle]}>
|
|
22
|
+
<Animated.Text style={[styles.nextButtonText, textStyle]}>→</Animated.Text>
|
|
23
|
+
</Animated.View>
|
|
24
|
+
</>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Platform } from "react-native";
|
|
2
|
+
import { makeUseStyles } from "react-native-stylex";
|
|
3
|
+
import { getSafeArea } from "react-native-stylex/safe-area";
|
|
4
|
+
|
|
5
|
+
export const useStyles = makeUseStyles(() => ({
|
|
6
|
+
skipBtn: {
|
|
7
|
+
position: "absolute",
|
|
8
|
+
left: 20,
|
|
9
|
+
bottom: 30 + getSafeArea().bottom,
|
|
10
|
+
fontSize: 20,
|
|
11
|
+
},
|
|
12
|
+
nextButton: {
|
|
13
|
+
position: "absolute",
|
|
14
|
+
right: 20,
|
|
15
|
+
bottom: 20 + getSafeArea().bottom,
|
|
16
|
+
width: 48,
|
|
17
|
+
height: 48,
|
|
18
|
+
borderRadius: 48,
|
|
19
|
+
shadowColor: "#000",
|
|
20
|
+
shadowOffset: { width: 0, height: 2 },
|
|
21
|
+
shadowOpacity: 0.23,
|
|
22
|
+
shadowRadius: 2.62,
|
|
23
|
+
elevation: 4,
|
|
24
|
+
},
|
|
25
|
+
nextButtonText: {
|
|
26
|
+
textAlign: "center",
|
|
27
|
+
...Platform.select({
|
|
28
|
+
ios: {
|
|
29
|
+
fontSize: 26,
|
|
30
|
+
lineHeight: 48,
|
|
31
|
+
},
|
|
32
|
+
android: {
|
|
33
|
+
textAlignVertical: "center",
|
|
34
|
+
fontSize: 36,
|
|
35
|
+
},
|
|
36
|
+
web: {
|
|
37
|
+
fontSize: 36,
|
|
38
|
+
lineHeight: 40,
|
|
39
|
+
},
|
|
40
|
+
}),
|
|
41
|
+
},
|
|
42
|
+
}));
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from "react";
|
|
2
|
+
import { Animated, View } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { useIsDark } from "../style-system/hooks/useIsDark";
|
|
5
|
+
import { useAnimatedBgColor } from "../style-system/hooks/useAnimatedBgColor";
|
|
6
|
+
|
|
7
|
+
import { useStyles } from "./styles";
|
|
8
|
+
|
|
9
|
+
const { Value, timing } = Animated;
|
|
10
|
+
|
|
11
|
+
export const Circle = () => {
|
|
12
|
+
const styles = useStyles();
|
|
13
|
+
const bgStyle = useAnimatedBgColor();
|
|
14
|
+
const isDarkTheme = useIsDark();
|
|
15
|
+
const animatedCircle = useRef(new Value(0));
|
|
16
|
+
const animatedStyle = {
|
|
17
|
+
transform: [
|
|
18
|
+
{
|
|
19
|
+
translateX: animatedCircle.current.interpolate({
|
|
20
|
+
inputRange: [0, 1],
|
|
21
|
+
outputRange: [100, 0],
|
|
22
|
+
}),
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
translateY: animatedCircle.current.interpolate({
|
|
26
|
+
inputRange: [0, 1],
|
|
27
|
+
outputRange: [-100, 0],
|
|
28
|
+
}),
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
scale: animatedCircle.current.interpolate({
|
|
32
|
+
inputRange: [0, 1],
|
|
33
|
+
outputRange: [0.01, 1],
|
|
34
|
+
}),
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
timing(animatedCircle.current, {
|
|
41
|
+
useNativeDriver: false,
|
|
42
|
+
toValue: isDarkTheme ? 1 : 0,
|
|
43
|
+
duration: 250,
|
|
44
|
+
}).start();
|
|
45
|
+
}, [isDarkTheme]);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<View style={styles.root}>
|
|
49
|
+
<View style={styles.circle} />
|
|
50
|
+
<Animated.View style={[styles.overlay, animatedStyle, bgStyle]} />
|
|
51
|
+
</View>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { makeUseStyles } from "react-native-stylex";
|
|
2
|
+
|
|
3
|
+
export const useStyles = makeUseStyles(({ palette }) => ({
|
|
4
|
+
root: {
|
|
5
|
+
alignSelf: "center",
|
|
6
|
+
},
|
|
7
|
+
circle: {
|
|
8
|
+
width: 150,
|
|
9
|
+
height: 150,
|
|
10
|
+
borderRadius: 150,
|
|
11
|
+
backgroundColor: palette.accent,
|
|
12
|
+
marginBottom: 80,
|
|
13
|
+
},
|
|
14
|
+
overlay: {
|
|
15
|
+
position: "absolute",
|
|
16
|
+
right: -20,
|
|
17
|
+
top: -20,
|
|
18
|
+
width: 145,
|
|
19
|
+
height: 145,
|
|
20
|
+
borderRadius: 150,
|
|
21
|
+
},
|
|
22
|
+
}));
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Animated } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { useAnimatedBgColor } from "../style-system/hooks/useAnimatedBgColor";
|
|
5
|
+
import { useAnimatedTextColor } from "../style-system/hooks/useAnimatedTextColor";
|
|
6
|
+
|
|
7
|
+
import { ToggleButton } from "../ToggleButton";
|
|
8
|
+
import { BottomNav } from "../BottomNav";
|
|
9
|
+
import { Circle } from "../Circle";
|
|
10
|
+
|
|
11
|
+
import { useStyles } from "./styles";
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
toggleTheme: () => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Concept: https://dribbble.com/shots/5846239-Light-dark-toggle-switch-InVision-Studio
|
|
18
|
+
export const Root = ({ toggleTheme }: Props) => {
|
|
19
|
+
const styles = useStyles();
|
|
20
|
+
const bgStyle = useAnimatedBgColor();
|
|
21
|
+
const textStyle = useAnimatedTextColor();
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Animated.View style={[styles.root, bgStyle]}>
|
|
25
|
+
<Circle />
|
|
26
|
+
|
|
27
|
+
<Animated.Text style={[styles.title, textStyle]}>Choose a style</Animated.Text>
|
|
28
|
+
<Animated.Text style={[styles.text, textStyle]}>Pop or subtle. Day or night.</Animated.Text>
|
|
29
|
+
<Animated.Text style={[styles.text, textStyle]}>Customize your interface.</Animated.Text>
|
|
30
|
+
|
|
31
|
+
<ToggleButton onPress={toggleTheme} />
|
|
32
|
+
<BottomNav />
|
|
33
|
+
</Animated.View>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { makeUseStyles } from "react-native-stylex";
|
|
2
|
+
|
|
3
|
+
export const useStyles = makeUseStyles(() => ({
|
|
4
|
+
root: {
|
|
5
|
+
flex: 1,
|
|
6
|
+
justifyContent: "center",
|
|
7
|
+
},
|
|
8
|
+
title: {
|
|
9
|
+
textAlign: "center",
|
|
10
|
+
fontSize: 26,
|
|
11
|
+
fontWeight: "600",
|
|
12
|
+
marginBottom: 16,
|
|
13
|
+
},
|
|
14
|
+
text: {
|
|
15
|
+
textAlign: "center",
|
|
16
|
+
fontSize: 20,
|
|
17
|
+
},
|
|
18
|
+
}));
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from "react";
|
|
2
|
+
import { Animated, View, Pressable, Text } from "react-native";
|
|
3
|
+
import { useColorTransition } from "react-native-stylex";
|
|
4
|
+
|
|
5
|
+
import { useIsDark } from "../style-system/hooks/useIsDark";
|
|
6
|
+
|
|
7
|
+
import { useStyles, ROOT_WIDTH } from "./styles";
|
|
8
|
+
|
|
9
|
+
const { Value, spring } = Animated;
|
|
10
|
+
const HALF_ROOT_WIDTH = ROOT_WIDTH / 2;
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
onPress: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const ToggleButton = ({ onPress }: Props) => {
|
|
17
|
+
const styles = useStyles();
|
|
18
|
+
const isDark = useIsDark();
|
|
19
|
+
const bgStyle = {
|
|
20
|
+
backgroundColor: useColorTransition(({ palette }) => palette.bg),
|
|
21
|
+
};
|
|
22
|
+
const animatedOffset = useRef(new Value(0));
|
|
23
|
+
const animatedStyle = {
|
|
24
|
+
transform: [
|
|
25
|
+
{
|
|
26
|
+
translateX: animatedOffset.current.interpolate({
|
|
27
|
+
inputRange: [0, 1],
|
|
28
|
+
outputRange: [0, HALF_ROOT_WIDTH],
|
|
29
|
+
}),
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
spring(animatedOffset.current, {
|
|
36
|
+
useNativeDriver: false,
|
|
37
|
+
toValue: isDark ? 1 : 0,
|
|
38
|
+
}).start();
|
|
39
|
+
}, [isDark]);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Pressable onPress={onPress}>
|
|
43
|
+
<View style={styles.root}>
|
|
44
|
+
<Animated.View style={[styles.activeBg, animatedStyle, bgStyle]} />
|
|
45
|
+
<View style={styles.labelsRoot}>
|
|
46
|
+
<Text style={[styles.labelText, styles.lightLabelText, !isDark && styles.activeLabelText]}>Light</Text>
|
|
47
|
+
<Text style={[styles.labelText, styles.darkLabelText, isDark && styles.activeLabelText]}>Dark</Text>
|
|
48
|
+
</View>
|
|
49
|
+
</View>
|
|
50
|
+
</Pressable>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { makeUseStyles } from "react-native-stylex";
|
|
2
|
+
import { StyleSheet, Platform } from "react-native";
|
|
3
|
+
|
|
4
|
+
export const ROOT_WIDTH = 280;
|
|
5
|
+
|
|
6
|
+
export const useStyles = makeUseStyles(({ palette, utils }) => ({
|
|
7
|
+
root: {
|
|
8
|
+
marginTop: 36,
|
|
9
|
+
alignSelf: "center",
|
|
10
|
+
height: 60,
|
|
11
|
+
borderRadius: 60,
|
|
12
|
+
width: ROOT_WIDTH,
|
|
13
|
+
backgroundColor: utils.isDark(palette.bg) ? utils.lighten(palette.bg, 0.3) : utils.darken(palette.bg, 0.3),
|
|
14
|
+
},
|
|
15
|
+
activeBg: {
|
|
16
|
+
width: "50%",
|
|
17
|
+
height: "100%",
|
|
18
|
+
borderRadius: 60,
|
|
19
|
+
position: "absolute",
|
|
20
|
+
top: 0,
|
|
21
|
+
left: 0,
|
|
22
|
+
backgroundColor: palette.bg,
|
|
23
|
+
|
|
24
|
+
shadowColor: palette.text,
|
|
25
|
+
shadowOffset: {
|
|
26
|
+
width: 0,
|
|
27
|
+
height: 2,
|
|
28
|
+
},
|
|
29
|
+
shadowOpacity: 0.23,
|
|
30
|
+
shadowRadius: 2.62,
|
|
31
|
+
|
|
32
|
+
elevation: 4,
|
|
33
|
+
},
|
|
34
|
+
labelsRoot: {
|
|
35
|
+
...StyleSheet.absoluteFillObject,
|
|
36
|
+
// Hack for Android
|
|
37
|
+
elevation: 5,
|
|
38
|
+
},
|
|
39
|
+
labelText: {
|
|
40
|
+
position: "absolute",
|
|
41
|
+
height: "100%",
|
|
42
|
+
width: "50%",
|
|
43
|
+
top: 0,
|
|
44
|
+
|
|
45
|
+
fontSize: 20,
|
|
46
|
+
fontWeight: "700",
|
|
47
|
+
color: utils.fade(palette.text, 0.5),
|
|
48
|
+
textAlign: "center",
|
|
49
|
+
...Platform.select({
|
|
50
|
+
web: {
|
|
51
|
+
lineHeight: 60,
|
|
52
|
+
},
|
|
53
|
+
default: {
|
|
54
|
+
lineHeight: 55,
|
|
55
|
+
},
|
|
56
|
+
}),
|
|
57
|
+
},
|
|
58
|
+
lightLabelText: {
|
|
59
|
+
left: 0,
|
|
60
|
+
},
|
|
61
|
+
darkLabelText: {
|
|
62
|
+
right: 0,
|
|
63
|
+
},
|
|
64
|
+
activeLabelText: {
|
|
65
|
+
color: palette.text,
|
|
66
|
+
},
|
|
67
|
+
}));
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { lightPalette, darkPalette } from "./palette";
|
|
2
|
+
import { utils } from "./utils";
|
|
3
|
+
|
|
4
|
+
export const lightTheme = {
|
|
5
|
+
palette: lightPalette,
|
|
6
|
+
utils,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type Theme = typeof lightTheme;
|
|
10
|
+
|
|
11
|
+
export const darkTheme: Theme = {
|
|
12
|
+
palette: darkPalette,
|
|
13
|
+
utils,
|
|
14
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import Color from "color";
|
|
2
|
+
|
|
3
|
+
export const utils = {
|
|
4
|
+
isDark: (color: string): boolean => Color(color).isDark(),
|
|
5
|
+
fade: (color: string, alpha: number): string => Color(color).alpha(alpha).string(),
|
|
6
|
+
lighten: (color: string, val: number): string => Color(color).lighten(val).string(),
|
|
7
|
+
darken: (color: string, val: number): string => Color(color).darken(val).string(),
|
|
8
|
+
};
|