@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
package/jest.config.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const { resolve } = require("path");
|
|
2
|
+
const { name: displayName } = require("./package");
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
displayName,
|
|
6
|
+
testEnvironment: "node",
|
|
7
|
+
preset: "react-native",
|
|
8
|
+
cacheDirectory: resolve(__dirname, "./node_modules/.jestcache"),
|
|
9
|
+
moduleFileExtensions: ["ts", "tsx", "js"],
|
|
10
|
+
testRegex: "\\.test\\.(js|ts)x?$",
|
|
11
|
+
coveragePathIgnorePatterns: ["init.ts"],
|
|
12
|
+
coverageThreshold: {
|
|
13
|
+
global: {
|
|
14
|
+
branches: 100,
|
|
15
|
+
functions: 100,
|
|
16
|
+
statements: 100,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
package/package.json
CHANGED
|
@@ -3,13 +3,27 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.0.0-dev.
|
|
6
|
+
"version": "0.0.0-dev.10",
|
|
7
7
|
"private": false,
|
|
8
8
|
"main": "index.js",
|
|
9
9
|
"types": "index.d.ts",
|
|
10
10
|
"author": "David <4661784+retyui@users.noreply.github.com>",
|
|
11
11
|
"description": "Fork of git@github.com:retyui/react-native-stylex.git",
|
|
12
12
|
"license": "MIT",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"prebuild": "rm -rf lib",
|
|
15
|
+
"build": "tsc -p ./tsconfig.build.json",
|
|
16
|
+
"postbuild": "mkdir -p lib/make-use-styles && cp src/make-use-styles/* lib/make-use-styles && rm -rf lib/**/*test.* && prettier --write lib/**/*.{js,ts}",
|
|
17
|
+
"clean-publish": "yarn test && yarn build && node ./node_modules/clean-publish/clear-package-json.js package.json > lib/package.json && cp CHANGELOG.md LICENSE README.md lib",
|
|
18
|
+
"pub": "yarn build && node ./node_modules/clean-publish/clear-package-json.js package.json > lib/package.json && cp CHANGELOG.md LICENSE README.md lib",
|
|
19
|
+
"publish-next": "yarn clean-publish && cd lib && npm publish --tag next",
|
|
20
|
+
"presize": "yarn build",
|
|
21
|
+
"postinstall": "rm -rf node_modules/@types/node node_modules/@types/yauzl node_modules/@types/graceful-fs",
|
|
22
|
+
"lint": "eslint './src/*.{js,ts,tsx}' --quiet",
|
|
23
|
+
"test": "jest --coverage",
|
|
24
|
+
"size": "size-limit",
|
|
25
|
+
"ci": "yarn lint && yarn test && yarn size"
|
|
26
|
+
},
|
|
13
27
|
"peerDependencies": {
|
|
14
28
|
"react": ">=16.4.0",
|
|
15
29
|
"react-native": ">=0.59.0"
|
|
@@ -22,7 +36,28 @@
|
|
|
22
36
|
"optional": true
|
|
23
37
|
}
|
|
24
38
|
},
|
|
25
|
-
"
|
|
26
|
-
"
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@react-native/babel-preset": "^0.83.0",
|
|
41
|
+
"@size-limit/preset-app": "^11.0.1",
|
|
42
|
+
"@testing-library/react-hooks": "^8.0.1",
|
|
43
|
+
"@types/jest": "^30.0.0",
|
|
44
|
+
"@types/react": "^19.2.7",
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
|
46
|
+
"@typescript-eslint/parser": "^6.14.0",
|
|
47
|
+
"clean-publish": "^4.2.0",
|
|
48
|
+
"eslint": "^8.56.0",
|
|
49
|
+
"eslint-config-prettier": "^9.1.0",
|
|
50
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
51
|
+
"eslint-plugin-react": "^7.33.2",
|
|
52
|
+
"jest": "^29.7.0",
|
|
53
|
+
"prettier": "^3.1.1",
|
|
54
|
+
"react": "^19.2.3",
|
|
55
|
+
"react-native": "^0.83.0",
|
|
56
|
+
"react-native-dark-mode": "^0.2.2",
|
|
57
|
+
"react-native-safe-area-context": "^5.6.2",
|
|
58
|
+
"react-native-test-app": "^5.0.5",
|
|
59
|
+
"react-test-renderer": "^19.2.3",
|
|
60
|
+
"size-limit": "^11.0.1",
|
|
61
|
+
"typescript": "^5.3.3"
|
|
27
62
|
}
|
|
28
63
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "./init";
|
|
2
|
+
|
|
3
|
+
import { Appearance } from "react-native";
|
|
4
|
+
|
|
5
|
+
import { onUse } from "../dependency-usage";
|
|
6
|
+
|
|
7
|
+
import { UI_MODE_DEPENDENCY_KEY } from "./consts";
|
|
8
|
+
|
|
9
|
+
export type ColorSchemeName = "light" | "dark" | "default";
|
|
10
|
+
|
|
11
|
+
export function appearance<T>({ dark, light, default: defaultScheme }: { [mode in ColorSchemeName]?: T }): T | undefined {
|
|
12
|
+
onUse(UI_MODE_DEPENDENCY_KEY);
|
|
13
|
+
|
|
14
|
+
// Note: getColorScheme() will always return light when debugging with Chrome.
|
|
15
|
+
if (Appearance.getColorScheme() === "light") {
|
|
16
|
+
return light;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (Appearance.getColorScheme() === "dark") {
|
|
20
|
+
return dark;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return defaultScheme;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const darkAppearance = <T>(dark: T): T | undefined => appearance<T>({ dark });
|
|
27
|
+
|
|
28
|
+
export const lightAppearance = <T>(light: T): T | undefined => appearance<T>({ light });
|
|
29
|
+
|
|
30
|
+
export const noPreferenceAppearance = <T>(defaultScheme: T): T | undefined => appearance<T>({ default: defaultScheme });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Appearance } from "react-native";
|
|
2
|
+
|
|
3
|
+
import { addDependency } from "../dependency-registry";
|
|
4
|
+
import { createEventEmitter } from "../create-event-emitter";
|
|
5
|
+
|
|
6
|
+
import { UI_MODE_DEPENDENCY_KEY } from "./consts";
|
|
7
|
+
|
|
8
|
+
const { on, emit } = createEventEmitter(UI_MODE_DEPENDENCY_KEY);
|
|
9
|
+
|
|
10
|
+
addDependency(UI_MODE_DEPENDENCY_KEY, (handler: () => void) => on(handler));
|
|
11
|
+
|
|
12
|
+
Appearance.addChangeListener(emit);
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import { createContext } from "react";
|
|
2
|
-
|
|
2
|
+
import { DefaultTheme } from "./default-theme";
|
|
3
|
+
|
|
4
|
+
export const themeContext = createContext<DefaultTheme | null>(null);
|
|
5
|
+
|
|
3
6
|
export const { Provider: ThemeProvider, Consumer: ThemeConsumer } = themeContext;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
type Handler = () => void;
|
|
2
|
+
type UnSubscribe = () => void;
|
|
3
|
+
|
|
4
|
+
interface EventsRegistry {
|
|
5
|
+
[eventName: string]: Array<Handler>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface Result {
|
|
9
|
+
on: (callback: Handler) => UnSubscribe;
|
|
10
|
+
emit: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const events: EventsRegistry = {};
|
|
14
|
+
|
|
15
|
+
export function createEventEmitter(event: string): Result {
|
|
16
|
+
const emit = (): void => (events[event] || []).forEach((fn) => fn());
|
|
17
|
+
const on = (cb: Handler): UnSubscribe => {
|
|
18
|
+
(events[event] = events[event] || []).push(cb);
|
|
19
|
+
|
|
20
|
+
return () => {
|
|
21
|
+
events[event] = events[event]!.filter((fn) => fn !== cb);
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return { on, emit };
|
|
26
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import "./init";
|
|
2
|
+
|
|
3
|
+
import { onUse } from "../dependency-usage";
|
|
4
|
+
|
|
5
|
+
import { UI_MODE_DEPENDENCY_KEY } from "./consts";
|
|
6
|
+
import { state } from "./state";
|
|
7
|
+
|
|
8
|
+
export type UiType = "dark" | "light";
|
|
9
|
+
|
|
10
|
+
export function uiMode<T>({ dark, light }: { [mode in UiType]?: T }): T | undefined {
|
|
11
|
+
onUse(UI_MODE_DEPENDENCY_KEY);
|
|
12
|
+
|
|
13
|
+
if (state.mode === "dark") {
|
|
14
|
+
return dark;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (state.mode === "light") {
|
|
18
|
+
return light;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const darkUiMode = <T>(dark: T): T | undefined => uiMode<T>({ dark });
|
|
25
|
+
|
|
26
|
+
export const lightUiMode = <T>(light: T): T | undefined => uiMode<T>({ light });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { eventEmitter, Mode } from "react-native-dark-mode";
|
|
2
|
+
|
|
3
|
+
import { addDependency } from "../dependency-registry";
|
|
4
|
+
import { createEventEmitter } from "../create-event-emitter";
|
|
5
|
+
|
|
6
|
+
import { UI_MODE_DEPENDENCY_KEY } from "./consts";
|
|
7
|
+
import { state } from "./state";
|
|
8
|
+
|
|
9
|
+
const { on, emit } = createEventEmitter(UI_MODE_DEPENDENCY_KEY);
|
|
10
|
+
|
|
11
|
+
addDependency(UI_MODE_DEPENDENCY_KEY, (handler: () => void) => on(handler));
|
|
12
|
+
|
|
13
|
+
eventEmitter.on("currentModeChanged", (newMode: Mode) => {
|
|
14
|
+
if (state.mode !== newMode) {
|
|
15
|
+
state.mode = newMode;
|
|
16
|
+
|
|
17
|
+
emit();
|
|
18
|
+
}
|
|
19
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// This interface can be augmented by users to add default types for the theme when using react-native-stylex.
|
|
2
|
+
// Use module augmentation to append your own type definition in a your_custom_stylex_type.d.ts file.
|
|
3
|
+
// https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
|
|
4
|
+
export interface DefaultTheme {}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type UnSubscribeFn = () => void;
|
|
2
|
+
type SubscribeFn = (handler: () => void) => UnSubscribeFn;
|
|
3
|
+
|
|
4
|
+
interface Registry {
|
|
5
|
+
[dependencyName: string]: SubscribeFn;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const registry: Registry = {};
|
|
9
|
+
|
|
10
|
+
export function addDependency(name: string, onChange: SubscribeFn): void {
|
|
11
|
+
if (!registry[name]) {
|
|
12
|
+
Object.defineProperty(registry, name, {
|
|
13
|
+
value: onChange,
|
|
14
|
+
writable: false,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function getDependency(name: string): SubscribeFn | undefined {
|
|
20
|
+
return registry[name];
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface UsingSpec {
|
|
2
|
+
[dependencyName: string]: boolean;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
interface Ref {
|
|
6
|
+
current: UsingSpec;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const ref: Ref = { current: {} };
|
|
10
|
+
|
|
11
|
+
export function resetUsing(): void {
|
|
12
|
+
ref.current = {};
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function getUsing(): UsingSpec {
|
|
16
|
+
return { ...ref.current };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function onUse(name: string): void {
|
|
20
|
+
ref.current[name] = true;
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import "./init";
|
|
2
|
+
|
|
3
|
+
import { Dimensions, ScaledSize } from "react-native";
|
|
4
|
+
|
|
5
|
+
import { onUse } from "../dependency-usage";
|
|
6
|
+
import { WINDOW_DEPENDENCY_KEY, SCREEN_DEPENDENCY_KEY } from "./consts";
|
|
7
|
+
|
|
8
|
+
const get = (dim: "window" | "screen") => Dimensions.get(dim);
|
|
9
|
+
|
|
10
|
+
export function getWindowDimensions(): ScaledSize {
|
|
11
|
+
onUse(WINDOW_DEPENDENCY_KEY);
|
|
12
|
+
|
|
13
|
+
return get("window");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getScreenDimensions(): ScaledSize {
|
|
17
|
+
onUse(SCREEN_DEPENDENCY_KEY);
|
|
18
|
+
|
|
19
|
+
return get("screen");
|
|
20
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Dimensions, ScaledSize } from "react-native";
|
|
2
|
+
|
|
3
|
+
import { createEventEmitter } from "../create-event-emitter";
|
|
4
|
+
import { addDependency } from "../dependency-registry";
|
|
5
|
+
import { SCREEN_DEPENDENCY_KEY, WINDOW_DEPENDENCY_KEY } from "./consts";
|
|
6
|
+
|
|
7
|
+
const { get, addEventListener } = Dimensions;
|
|
8
|
+
|
|
9
|
+
const state = { window: get("window"), screen: get("screen") };
|
|
10
|
+
|
|
11
|
+
const windowEventEmitter = createEventEmitter(WINDOW_DEPENDENCY_KEY);
|
|
12
|
+
const screenEventEmitter = createEventEmitter(SCREEN_DEPENDENCY_KEY);
|
|
13
|
+
|
|
14
|
+
const isNotEqual = (a: ScaledSize, b: ScaledSize) => a.width !== b.width || a.height !== b.height;
|
|
15
|
+
|
|
16
|
+
addDependency(WINDOW_DEPENDENCY_KEY, (handler: () => void) => windowEventEmitter.on(handler));
|
|
17
|
+
|
|
18
|
+
addDependency(SCREEN_DEPENDENCY_KEY, (handler: () => void) => screenEventEmitter.on(handler));
|
|
19
|
+
|
|
20
|
+
addEventListener("change", ({ window, screen }) => {
|
|
21
|
+
if (isNotEqual(screen, state.screen)) {
|
|
22
|
+
state.screen = screen;
|
|
23
|
+
|
|
24
|
+
screenEventEmitter.emit();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isNotEqual(window, state.window)) {
|
|
28
|
+
state.window = window;
|
|
29
|
+
|
|
30
|
+
windowEventEmitter.emit();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SCREEN_DEPENDENCY_KEY, WINDOW_DEPENDENCY_KEY } from "./consts";
|
|
2
|
+
|
|
3
|
+
export const optimizeDependencies = (keys: Record<string, boolean>): Record<string, boolean> => {
|
|
4
|
+
if (keys[WINDOW_DEPENDENCY_KEY] && keys[SCREEN_DEPENDENCY_KEY]) {
|
|
5
|
+
delete keys[SCREEN_DEPENDENCY_KEY];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return keys;
|
|
9
|
+
};
|
package/src/i18n.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { I18nManager } from "react-native";
|
|
2
|
+
|
|
3
|
+
type LayoutDirectionType = "rtl" | "ltr";
|
|
4
|
+
|
|
5
|
+
export function i18n<T>({ rtl, ltr }: { [direction in LayoutDirectionType]?: T }): T | undefined {
|
|
6
|
+
if (I18nManager.isRTL) {
|
|
7
|
+
return rtl;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return ltr;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const rtl = <T>(styles: T): T | undefined => i18n<T>({ rtl: styles });
|
|
14
|
+
|
|
15
|
+
export const ltr = <T>(styles: T): T | undefined => i18n<T>({ ltr: styles });
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { useTheme } from "./use-theme";
|
|
2
|
+
export { withStyles } from "./with-styles";
|
|
3
|
+
export { ThemeProvider, ThemeConsumer } from "./context";
|
|
4
|
+
export { useColorTransition } from "./use-color-transition";
|
|
5
|
+
export { makeUseStyles } from "./make-use-styles";
|
|
6
|
+
export type { DefaultTheme } from "./default-theme";
|
|
7
|
+
export type { InferInjectedStyledProps } from "./with-styles";
|
package/{makeUseStyles/createUseStylesTheme.js → src/make-use-styles/create-use-styles-theme.js}
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { StyleSheet } from "react-native";
|
|
2
|
-
import { useTheme } from "../
|
|
3
|
-
import { resetUsing } from "../
|
|
2
|
+
import { useTheme } from "../use-theme";
|
|
3
|
+
import { resetUsing } from "../dependency-usage";
|
|
4
4
|
import { getDependenciesKeys, useForceUpdate, subscribe } from "./utils";
|
|
5
5
|
|
|
6
|
-
export function createUseStylesTheme(getStyles) {
|
|
6
|
+
export function createUseStylesTheme(getStyles, getVariants) {
|
|
7
7
|
const scope = {
|
|
8
8
|
styles: new WeakMap(),
|
|
9
9
|
forceUpdate: [],
|
|
@@ -20,7 +20,7 @@ export function createUseStylesTheme(getStyles) {
|
|
|
20
20
|
scope.unsubscribe();
|
|
21
21
|
resetUsing();
|
|
22
22
|
|
|
23
|
-
const style = StyleSheet.create(getStyles(theme));
|
|
23
|
+
const style = StyleSheet.create(getStyles?.(theme) ?? {});
|
|
24
24
|
const keys = getDependenciesKeys();
|
|
25
25
|
|
|
26
26
|
scope.unsubscribe = subscribe(keys, onUpdate);
|
|
@@ -28,7 +28,7 @@ export function createUseStylesTheme(getStyles) {
|
|
|
28
28
|
return style;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
function useStyles(variants) {
|
|
32
32
|
const theme = useTheme();
|
|
33
33
|
|
|
34
34
|
useForceUpdate(scope);
|
|
@@ -37,6 +37,23 @@ export function createUseStylesTheme(getStyles) {
|
|
|
37
37
|
scope.styles.set(theme, initStyle(theme));
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
if (getVariants) {
|
|
41
|
+
const configVariants = getVariants(theme);
|
|
42
|
+
const requestedVarians = {};
|
|
43
|
+
|
|
44
|
+
for (const key in variants) {
|
|
45
|
+
const value = configVariants[key][variants[key]];
|
|
46
|
+
Object.assign(requestedVarians, value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
...scope.styles.get(theme),
|
|
51
|
+
...StyleSheet.create({ variants: requestedVarians }),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
40
55
|
return scope.styles.get(theme);
|
|
41
|
-
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return useStyles;
|
|
42
59
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { renderHook, act } from "@testing-library/react-hooks";
|
|
2
|
+
import { createUseStylesTheme } from "./createUseStylesTheme";
|
|
3
|
+
import { ThemeProvider } from "../context";
|
|
4
|
+
import { createEventEmitter } from "../createEventEmitter";
|
|
5
|
+
import { addDependency } from "../dependencyRegistry";
|
|
6
|
+
import { onUse } from "../dependencyUsage";
|
|
7
|
+
|
|
8
|
+
it("should create styles using a theme", () => {
|
|
9
|
+
const mockGetStyles = jest.fn(({ colors }) => ({
|
|
10
|
+
root: { color: colors.red },
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
const useStyles = createUseStylesTheme(mockGetStyles);
|
|
14
|
+
const { result } = renderHook(() => useStyles(), {
|
|
15
|
+
wrapper: ThemeProvider,
|
|
16
|
+
initialProps: { value: { colors: { red: "red" } } },
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
expect(result.current).toEqual({
|
|
20
|
+
root: { color: "red" },
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should create styles once", () => {
|
|
25
|
+
const theme = { colors: { red: "red" } };
|
|
26
|
+
const mockGetStyles = jest.fn(({ colors }) => ({
|
|
27
|
+
root: { color: colors.red },
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
const useStyles = createUseStylesTheme(mockGetStyles);
|
|
31
|
+
|
|
32
|
+
renderHook(
|
|
33
|
+
() => {
|
|
34
|
+
useStyles();
|
|
35
|
+
useStyles();
|
|
36
|
+
useStyles();
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
wrapper: ThemeProvider,
|
|
40
|
+
initialProps: { value: theme },
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
expect(mockGetStyles).toHaveBeenCalledTimes(1);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should not update styles when component rerender", () => {
|
|
48
|
+
const theme = { colors: { red: "red" } };
|
|
49
|
+
const mockGetStyles = jest.fn(({ colors }) => ({
|
|
50
|
+
root: { color: colors.red },
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
const useStyles = createUseStylesTheme(mockGetStyles);
|
|
54
|
+
const { rerender } = renderHook(() => useStyles(), {
|
|
55
|
+
wrapper: ThemeProvider,
|
|
56
|
+
initialProps: { value: theme },
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
rerender({ value: theme, a: 1 });
|
|
60
|
+
rerender({ value: theme, a: 2 });
|
|
61
|
+
rerender({ value: theme, a: 3 });
|
|
62
|
+
|
|
63
|
+
expect(mockGetStyles).toHaveBeenCalledTimes(1);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should use memoized styles when component rerender", () => {
|
|
67
|
+
const theme = { colors: { red: "red" } };
|
|
68
|
+
const mockGetStyles = jest.fn(({ colors }) => ({
|
|
69
|
+
root: { color: colors.red },
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
const useStyles = createUseStylesTheme(mockGetStyles);
|
|
73
|
+
const { rerender, result } = renderHook(() => useStyles(), {
|
|
74
|
+
wrapper: ThemeProvider,
|
|
75
|
+
initialProps: { value: theme },
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const initialStyles = result.current;
|
|
79
|
+
|
|
80
|
+
rerender({ value: theme, a: 1 });
|
|
81
|
+
rerender({ value: theme, a: 2 });
|
|
82
|
+
rerender({ value: theme, a: 3 });
|
|
83
|
+
|
|
84
|
+
const afterUpdateStyles = result.current;
|
|
85
|
+
|
|
86
|
+
expect(afterUpdateStyles).toBe(initialStyles);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should update styles when theme was changed", () => {
|
|
90
|
+
const initialTheme = { colors: { red: "red" } };
|
|
91
|
+
const newTheme = { colors: { red: "white" } };
|
|
92
|
+
|
|
93
|
+
const mockGetStyles = jest.fn(({ colors }) => ({
|
|
94
|
+
root: { color: colors.red },
|
|
95
|
+
}));
|
|
96
|
+
|
|
97
|
+
const useStyles = createUseStylesTheme(mockGetStyles);
|
|
98
|
+
const { rerender } = renderHook(() => useStyles(), {
|
|
99
|
+
wrapper: ThemeProvider,
|
|
100
|
+
initialProps: { value: initialTheme },
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
act(() => {
|
|
104
|
+
rerender({ value: newTheme });
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
expect(mockGetStyles).toHaveBeenCalledTimes(2);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should update styles when dependency changed", () => {
|
|
111
|
+
const theme = { colors: { red: "red" } };
|
|
112
|
+
const TEST_DEPENDENCY_KEY = `test_${Math.random()}`;
|
|
113
|
+
const { on, emit } = createEventEmitter(TEST_DEPENDENCY_KEY);
|
|
114
|
+
const mockGetStyles = jest.fn(({ colors }) => {
|
|
115
|
+
// simulate using a dependency
|
|
116
|
+
onUse(TEST_DEPENDENCY_KEY);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
root: { color: colors.red },
|
|
120
|
+
};
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
addDependency(TEST_DEPENDENCY_KEY, (handler) => on(handler));
|
|
124
|
+
|
|
125
|
+
const useStyles = createUseStylesTheme(mockGetStyles);
|
|
126
|
+
|
|
127
|
+
renderHook(() => useStyles(), {
|
|
128
|
+
wrapper: ThemeProvider,
|
|
129
|
+
initialProps: { value: theme },
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
act(() => {
|
|
133
|
+
emit();
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
expect(mockGetStyles).toHaveBeenCalledTimes(2);
|
|
137
|
+
});
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { StyleSheet } from "react-native";
|
|
2
|
-
import { resetUsing } from "../
|
|
2
|
+
import { resetUsing } from "../dependency-usage";
|
|
3
3
|
import { getDependenciesKeys, subscribe, useForceUpdate } from "./utils";
|
|
4
4
|
|
|
5
|
-
export function createUseStylesWithoutTheme(getStyles) {
|
|
5
|
+
export function createUseStylesWithoutTheme(getStyles, getVariants) {
|
|
6
6
|
const scope = {
|
|
7
7
|
style: null,
|
|
8
|
+
variants: null,
|
|
8
9
|
forceUpdate: [],
|
|
9
10
|
unsubscribe: () => {},
|
|
10
11
|
};
|
|
@@ -19,7 +20,7 @@ export function createUseStylesWithoutTheme(getStyles) {
|
|
|
19
20
|
scope.unsubscribe();
|
|
20
21
|
resetUsing();
|
|
21
22
|
|
|
22
|
-
scope.style = StyleSheet.create(getStyles());
|
|
23
|
+
scope.style = StyleSheet.create(getStyles?.() ?? {});
|
|
23
24
|
|
|
24
25
|
const keys = getDependenciesKeys();
|
|
25
26
|
|
|
@@ -28,9 +29,24 @@ export function createUseStylesWithoutTheme(getStyles) {
|
|
|
28
29
|
|
|
29
30
|
initStyle();
|
|
30
31
|
|
|
31
|
-
function useStyles() {
|
|
32
|
+
function useStyles(variants) {
|
|
32
33
|
useForceUpdate(scope);
|
|
33
34
|
|
|
35
|
+
if (getVariants) {
|
|
36
|
+
const configVariants = getVariants();
|
|
37
|
+
const requestedVarians = {};
|
|
38
|
+
|
|
39
|
+
for (const key in variants) {
|
|
40
|
+
const value = configVariants[key][variants[key]];
|
|
41
|
+
Object.assign(requestedVarians, value);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
...scope.style,
|
|
46
|
+
...StyleSheet.create({ variants: requestedVarians }),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
34
50
|
return scope.style;
|
|
35
51
|
}
|
|
36
52
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { renderHook, act } from "@testing-library/react-hooks";
|
|
2
|
+
import { createUseStylesWithoutTheme } from "./createUseStylesWithoutTheme";
|
|
3
|
+
|
|
4
|
+
import { addDependency } from "../dependencyRegistry";
|
|
5
|
+
import { onUse } from "../dependencyUsage";
|
|
6
|
+
import { createEventEmitter } from "../createEventEmitter";
|
|
7
|
+
|
|
8
|
+
const TEST_DEPENDENCY_KEY = `test_${Math.random()}`;
|
|
9
|
+
|
|
10
|
+
const { on, emit } = createEventEmitter(TEST_DEPENDENCY_KEY);
|
|
11
|
+
|
|
12
|
+
addDependency(TEST_DEPENDENCY_KEY, (handler) => on(handler));
|
|
13
|
+
|
|
14
|
+
const useStyles = createUseStylesWithoutTheme(() => {
|
|
15
|
+
// simulate using a dependency
|
|
16
|
+
onUse(TEST_DEPENDENCY_KEY);
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
root: { color: "red" },
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should use the same styles object to reduce memory usage", () => {
|
|
24
|
+
const { result } = renderHook(() => ({
|
|
25
|
+
stl1: useStyles(),
|
|
26
|
+
stl2: useStyles(),
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
expect(result.current.stl1).toBe(result.current.stl2);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should update styles when dependency changed", () => {
|
|
33
|
+
const { result } = renderHook(() => ({
|
|
34
|
+
stl1: useStyles(),
|
|
35
|
+
stl2: useStyles(),
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
const initialResult = { ...result.current };
|
|
39
|
+
|
|
40
|
+
act(() => {
|
|
41
|
+
emit();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const updatedResult = { ...result.current };
|
|
45
|
+
|
|
46
|
+
expect(initialResult.stl1).not.toBe(updatedResult.stl1);
|
|
47
|
+
expect(initialResult.stl2).not.toBe(updatedResult.stl2);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("should return the same style when component rerender", () => {
|
|
51
|
+
const mockUseStyles = jest.fn(useStyles);
|
|
52
|
+
|
|
53
|
+
const { result, rerender } = renderHook(() => mockUseStyles());
|
|
54
|
+
|
|
55
|
+
const initialResult = result.current;
|
|
56
|
+
|
|
57
|
+
rerender({});
|
|
58
|
+
|
|
59
|
+
const updatedResult = result.current;
|
|
60
|
+
|
|
61
|
+
expect(mockUseStyles).toHaveBeenCalledTimes(2);
|
|
62
|
+
expect(initialResult).toBe(updatedResult);
|
|
63
|
+
});
|