react-native-unistyles 2.0.0-alpha.1 → 2.0.0-alpha.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (250) hide show
  1. package/README.md +4 -4
  2. package/cxx/UnistylesRuntime.cpp +255 -0
  3. package/cxx/UnistylesRuntime.h +60 -0
  4. package/ios/UnistylesHelpers.h +4 -0
  5. package/ios/UnistylesHelpers.mm +20 -0
  6. package/ios/UnistylesModule.h +10 -0
  7. package/ios/UnistylesModule.mm +158 -0
  8. package/lib/commonjs/common.js +26 -0
  9. package/lib/commonjs/common.js.map +1 -0
  10. package/lib/commonjs/core/UnistyleRegistry.js +38 -0
  11. package/lib/commonjs/core/UnistyleRegistry.js.map +1 -0
  12. package/lib/commonjs/core/Unistyles.js +31 -0
  13. package/lib/commonjs/core/Unistyles.js.map +1 -0
  14. package/lib/commonjs/core/UnistylesModule.js +9 -0
  15. package/lib/commonjs/core/UnistylesModule.js.map +1 -0
  16. package/lib/commonjs/core/UnistylesRuntime.js +66 -0
  17. package/lib/commonjs/core/UnistylesRuntime.js.map +1 -0
  18. package/lib/commonjs/core/index.js +13 -0
  19. package/lib/commonjs/core/index.js.map +1 -0
  20. package/lib/commonjs/createStyleSheet.js +14 -0
  21. package/lib/commonjs/createStyleSheet.js.map +1 -0
  22. package/lib/commonjs/global.js +2 -0
  23. package/lib/commonjs/global.js.map +1 -0
  24. package/lib/commonjs/hooks/index.js +10 -3
  25. package/lib/commonjs/hooks/index.js.map +1 -1
  26. package/lib/commonjs/hooks/useInitialTheme.js +17 -0
  27. package/lib/commonjs/hooks/useInitialTheme.js.map +1 -0
  28. package/lib/commonjs/hooks/useUnistyles.js +54 -0
  29. package/lib/commonjs/hooks/useUnistyles.js.map +1 -0
  30. package/lib/commonjs/index.js +35 -6
  31. package/lib/commonjs/index.js.map +1 -1
  32. package/lib/commonjs/types/common.js +2 -0
  33. package/lib/commonjs/types/{mediaQueries.js.map → common.js.map} +1 -1
  34. package/lib/commonjs/types/index.js +26 -0
  35. package/lib/commonjs/types/index.js.map +1 -1
  36. package/lib/commonjs/types/mq.js +6 -0
  37. package/lib/{module/types/mediaQueries.js.map → commonjs/types/mq.js.map} +1 -1
  38. package/lib/commonjs/types/normalizer.js +6 -0
  39. package/lib/commonjs/types/normalizer.js.map +1 -0
  40. package/lib/commonjs/types/unistyles.js +6 -0
  41. package/lib/commonjs/types/unistyles.js.map +1 -0
  42. package/lib/commonjs/useStyles.js +49 -0
  43. package/lib/commonjs/useStyles.js.map +1 -0
  44. package/lib/commonjs/utils/breakpoints.js +44 -82
  45. package/lib/commonjs/utils/breakpoints.js.map +1 -1
  46. package/lib/commonjs/utils/common.js +10 -3
  47. package/lib/commonjs/utils/common.js.map +1 -1
  48. package/lib/commonjs/utils/index.js +46 -17
  49. package/lib/commonjs/utils/index.js.map +1 -1
  50. package/lib/commonjs/utils/module.d.js +2 -0
  51. package/lib/commonjs/utils/module.d.js.map +1 -0
  52. package/lib/commonjs/utils/mq.js +89 -0
  53. package/lib/commonjs/utils/mq.js.map +1 -0
  54. package/lib/commonjs/utils/mqParser.js +86 -0
  55. package/lib/commonjs/utils/mqParser.js.map +1 -0
  56. package/lib/commonjs/utils/normalizeStyles.web.js +13 -13
  57. package/lib/commonjs/utils/normalizeStyles.web.js.map +1 -1
  58. package/lib/commonjs/utils/normalizer.js +89 -0
  59. package/lib/commonjs/utils/normalizer.js.map +1 -0
  60. package/lib/commonjs/utils/styles.js +17 -57
  61. package/lib/commonjs/utils/styles.js.map +1 -1
  62. package/lib/commonjs/utils/variants.js +20 -0
  63. package/lib/commonjs/utils/variants.js.map +1 -0
  64. package/lib/module/common.js +22 -0
  65. package/lib/module/common.js.map +1 -0
  66. package/lib/module/core/UnistyleRegistry.js +31 -0
  67. package/lib/module/core/UnistyleRegistry.js.map +1 -0
  68. package/lib/module/core/Unistyles.js +25 -0
  69. package/lib/module/core/Unistyles.js.map +1 -0
  70. package/lib/module/core/UnistylesModule.js +3 -0
  71. package/lib/module/core/UnistylesModule.js.map +1 -0
  72. package/lib/module/core/UnistylesRuntime.js +59 -0
  73. package/lib/module/core/UnistylesRuntime.js.map +1 -0
  74. package/lib/module/core/index.js +2 -0
  75. package/lib/module/core/index.js.map +1 -0
  76. package/lib/module/createStyleSheet.js +7 -0
  77. package/lib/module/createStyleSheet.js.map +1 -0
  78. package/lib/module/global.js +2 -0
  79. package/lib/module/global.js.map +1 -0
  80. package/lib/module/hooks/index.js +2 -1
  81. package/lib/module/hooks/index.js.map +1 -1
  82. package/lib/module/hooks/useInitialTheme.js +10 -0
  83. package/lib/module/hooks/useInitialTheme.js.map +1 -0
  84. package/lib/module/hooks/useUnistyles.js +47 -0
  85. package/lib/module/hooks/useUnistyles.js.map +1 -0
  86. package/lib/module/index.js +13 -2
  87. package/lib/module/index.js.map +1 -1
  88. package/lib/module/types/common.js +2 -0
  89. package/lib/module/types/common.js.map +1 -0
  90. package/lib/module/types/index.js +2 -1
  91. package/lib/module/types/index.js.map +1 -1
  92. package/lib/module/types/mq.js +2 -0
  93. package/lib/module/types/mq.js.map +1 -0
  94. package/lib/module/types/normalizer.js +2 -0
  95. package/lib/module/types/normalizer.js.map +1 -0
  96. package/lib/module/types/unistyles.js +2 -0
  97. package/lib/module/types/unistyles.js.map +1 -0
  98. package/lib/module/useStyles.js +42 -0
  99. package/lib/module/useStyles.js.map +1 -0
  100. package/lib/module/utils/breakpoints.js +43 -82
  101. package/lib/module/utils/breakpoints.js.map +1 -1
  102. package/lib/module/utils/common.js +9 -1
  103. package/lib/module/utils/common.js.map +1 -1
  104. package/lib/module/utils/index.js +6 -2
  105. package/lib/module/utils/index.js.map +1 -1
  106. package/lib/module/utils/module.d.js +2 -0
  107. package/lib/module/utils/module.d.js.map +1 -0
  108. package/lib/module/utils/mq.js +83 -0
  109. package/lib/module/utils/mq.js.map +1 -0
  110. package/lib/module/utils/mqParser.js +79 -0
  111. package/lib/module/utils/mqParser.js.map +1 -0
  112. package/lib/module/utils/normalizeStyles.web.js +13 -13
  113. package/lib/module/utils/normalizeStyles.web.js.map +1 -1
  114. package/lib/module/utils/normalizer.js +79 -0
  115. package/lib/module/utils/normalizer.js.map +1 -0
  116. package/lib/module/utils/styles.js +17 -59
  117. package/lib/module/utils/styles.js.map +1 -1
  118. package/lib/module/utils/variants.js +13 -0
  119. package/lib/module/utils/variants.js.map +1 -0
  120. package/lib/typescript/src/common.d.ts +17 -0
  121. package/lib/typescript/src/common.d.ts.map +1 -0
  122. package/lib/typescript/src/core/UnistyleRegistry.d.ts +15 -0
  123. package/lib/typescript/src/core/UnistyleRegistry.d.ts.map +1 -0
  124. package/lib/typescript/src/core/Unistyles.d.ts +13 -0
  125. package/lib/typescript/src/core/Unistyles.d.ts.map +1 -0
  126. package/lib/typescript/src/core/UnistylesModule.d.ts +6 -0
  127. package/lib/typescript/src/core/UnistylesModule.d.ts.map +1 -0
  128. package/lib/typescript/src/core/UnistylesRuntime.d.ts +24 -0
  129. package/lib/typescript/src/core/UnistylesRuntime.d.ts.map +1 -0
  130. package/lib/typescript/src/core/index.d.ts +2 -0
  131. package/lib/typescript/src/core/index.d.ts.map +1 -0
  132. package/lib/typescript/src/createStyleSheet.d.ts +3 -0
  133. package/lib/typescript/src/createStyleSheet.d.ts.map +1 -0
  134. package/lib/typescript/src/global.d.ts +7 -0
  135. package/lib/typescript/src/global.d.ts.map +1 -0
  136. package/lib/typescript/src/hooks/index.d.ts +2 -1
  137. package/lib/typescript/src/hooks/index.d.ts.map +1 -1
  138. package/lib/typescript/src/hooks/useInitialTheme.d.ts +3 -0
  139. package/lib/typescript/src/hooks/useInitialTheme.d.ts.map +1 -0
  140. package/lib/typescript/src/hooks/useUnistyles.d.ts +12 -0
  141. package/lib/typescript/src/hooks/useUnistyles.d.ts.map +1 -0
  142. package/lib/typescript/src/index.d.ts +14 -2
  143. package/lib/typescript/src/index.d.ts.map +1 -1
  144. package/lib/typescript/src/types/breakpoints.d.ts +13 -13
  145. package/lib/typescript/src/types/breakpoints.d.ts.map +1 -1
  146. package/lib/typescript/src/types/common.d.ts +3 -0
  147. package/lib/typescript/src/types/common.d.ts.map +1 -0
  148. package/lib/typescript/src/types/core.d.ts +34 -18
  149. package/lib/typescript/src/types/core.d.ts.map +1 -1
  150. package/lib/typescript/src/types/index.d.ts +6 -2
  151. package/lib/typescript/src/types/index.d.ts.map +1 -1
  152. package/lib/typescript/src/types/mq.d.ts +3 -0
  153. package/lib/typescript/src/types/mq.d.ts.map +1 -0
  154. package/lib/typescript/src/types/normalizer.d.ts +20 -0
  155. package/lib/typescript/src/types/normalizer.d.ts.map +1 -0
  156. package/lib/typescript/src/types/unistyles.d.ts +37 -0
  157. package/lib/typescript/src/types/unistyles.d.ts.map +1 -0
  158. package/lib/typescript/src/useStyles.d.ts +10 -0
  159. package/lib/typescript/src/useStyles.d.ts.map +1 -0
  160. package/lib/typescript/src/utils/breakpoints.d.ts +5 -62
  161. package/lib/typescript/src/utils/breakpoints.d.ts.map +1 -1
  162. package/lib/typescript/src/utils/common.d.ts +9 -1
  163. package/lib/typescript/src/utils/common.d.ts.map +1 -1
  164. package/lib/typescript/src/utils/index.d.ts +6 -2
  165. package/lib/typescript/src/utils/index.d.ts.map +1 -1
  166. package/lib/typescript/src/utils/mq.d.ts +21 -0
  167. package/lib/typescript/src/utils/mq.d.ts.map +1 -0
  168. package/lib/typescript/src/utils/mqParser.d.ts +3 -0
  169. package/lib/typescript/src/utils/mqParser.d.ts.map +1 -0
  170. package/lib/typescript/src/utils/normalizeStyles.web.d.ts +4 -1
  171. package/lib/typescript/src/utils/normalizeStyles.web.d.ts.map +1 -1
  172. package/lib/typescript/src/utils/normalizer.d.ts +11 -0
  173. package/lib/typescript/src/utils/normalizer.d.ts.map +1 -0
  174. package/lib/typescript/src/utils/styles.d.ts +5 -49
  175. package/lib/typescript/src/utils/styles.d.ts.map +1 -1
  176. package/lib/typescript/src/utils/variants.d.ts +3 -0
  177. package/lib/typescript/src/utils/variants.d.ts.map +1 -0
  178. package/package.json +33 -15
  179. package/react-native-unistyles.podspec +22 -0
  180. package/src/common.ts +19 -0
  181. package/src/core/UnistyleRegistry.ts +41 -0
  182. package/src/core/Unistyles.ts +34 -0
  183. package/src/core/UnistylesModule.ts +7 -0
  184. package/src/core/UnistylesRuntime.ts +73 -0
  185. package/src/core/index.ts +1 -0
  186. package/src/createStyleSheet.ts +9 -0
  187. package/src/global.ts +5 -0
  188. package/src/hooks/index.ts +2 -1
  189. package/src/hooks/useInitialTheme.ts +11 -0
  190. package/src/hooks/useUnistyles.ts +55 -0
  191. package/src/index.ts +30 -2
  192. package/src/types/breakpoints.ts +20 -20
  193. package/src/types/common.ts +2 -0
  194. package/src/types/core.ts +42 -24
  195. package/src/types/index.ts +6 -9
  196. package/src/types/mq.ts +3 -0
  197. package/src/types/normalizer.ts +29 -0
  198. package/src/types/unistyles.ts +45 -0
  199. package/src/useStyles.ts +56 -0
  200. package/src/utils/breakpoints.ts +57 -88
  201. package/src/utils/common.ts +10 -1
  202. package/src/utils/index.ts +6 -9
  203. package/src/utils/module.d.ts +3 -0
  204. package/src/utils/mq.ts +106 -0
  205. package/src/utils/mqParser.ts +99 -0
  206. package/src/utils/normalizeStyles.web.ts +21 -42
  207. package/src/utils/normalizer.ts +99 -0
  208. package/src/utils/styles.ts +29 -68
  209. package/src/utils/variants.ts +17 -0
  210. package/lib/commonjs/UnistylesTheme.js +0 -21
  211. package/lib/commonjs/UnistylesTheme.js.map +0 -1
  212. package/lib/commonjs/createUnistyles.js +0 -57
  213. package/lib/commonjs/createUnistyles.js.map +0 -1
  214. package/lib/commonjs/hooks/useDimensions.js +0 -10
  215. package/lib/commonjs/hooks/useDimensions.js.map +0 -1
  216. package/lib/commonjs/hooks/useDimensions.web.js +0 -31
  217. package/lib/commonjs/hooks/useDimensions.web.js.map +0 -1
  218. package/lib/commonjs/types/mediaQueries.js +0 -2
  219. package/lib/commonjs/utils/mediaQueries.js +0 -189
  220. package/lib/commonjs/utils/mediaQueries.js.map +0 -1
  221. package/lib/module/UnistylesTheme.js +0 -12
  222. package/lib/module/UnistylesTheme.js.map +0 -1
  223. package/lib/module/createUnistyles.js +0 -50
  224. package/lib/module/createUnistyles.js.map +0 -1
  225. package/lib/module/hooks/useDimensions.js +0 -3
  226. package/lib/module/hooks/useDimensions.js.map +0 -1
  227. package/lib/module/hooks/useDimensions.web.js +0 -24
  228. package/lib/module/hooks/useDimensions.web.js.map +0 -1
  229. package/lib/module/types/mediaQueries.js +0 -2
  230. package/lib/module/utils/mediaQueries.js +0 -176
  231. package/lib/module/utils/mediaQueries.js.map +0 -1
  232. package/lib/typescript/src/UnistylesTheme.d.ts +0 -9
  233. package/lib/typescript/src/UnistylesTheme.d.ts.map +0 -1
  234. package/lib/typescript/src/createUnistyles.d.ts +0 -10
  235. package/lib/typescript/src/createUnistyles.d.ts.map +0 -1
  236. package/lib/typescript/src/hooks/useDimensions.d.ts +0 -3
  237. package/lib/typescript/src/hooks/useDimensions.d.ts.map +0 -1
  238. package/lib/typescript/src/hooks/useDimensions.web.d.ts +0 -3
  239. package/lib/typescript/src/hooks/useDimensions.web.d.ts.map +0 -1
  240. package/lib/typescript/src/types/mediaQueries.d.ts +0 -8
  241. package/lib/typescript/src/types/mediaQueries.d.ts.map +0 -1
  242. package/lib/typescript/src/utils/mediaQueries.d.ts +0 -130
  243. package/lib/typescript/src/utils/mediaQueries.d.ts.map +0 -1
  244. package/src/UnistylesTheme.tsx +0 -17
  245. package/src/__tests__/createUnistyles.spec.tsx +0 -192
  246. package/src/createUnistyles.ts +0 -70
  247. package/src/hooks/useDimensions.ts +0 -4
  248. package/src/hooks/useDimensions.web.ts +0 -30
  249. package/src/types/mediaQueries.ts +0 -10
  250. package/src/utils/mediaQueries.ts +0 -201
@@ -0,0 +1,45 @@
1
+ import { CxxUnistylesEventTypes, ScreenOrientation } from '../common'
2
+ import type { UnistylesThemes, UnistylesBreakpoints } from '../global'
3
+ import type { ScreenSize } from './core'
4
+ import type { Optional } from './common'
5
+
6
+ export type ColorSchemeName = Optional<'light' | 'dark'>
7
+
8
+ export type UnistylesConfig = {
9
+ adaptiveThemes?: boolean
10
+ }
11
+
12
+ export type UnistylesBridge = {
13
+ // getters
14
+ screenWidth: number,
15
+ screenHeight: number,
16
+ hasAdaptiveThemes: boolean,
17
+ themeName: keyof UnistylesThemes,
18
+ breakpoint: keyof UnistylesBreakpoints,
19
+ colorScheme: ColorSchemeName,
20
+ sortedBreakpointPairs: Array<[keyof UnistylesBreakpoints, UnistylesBreakpoints[keyof UnistylesBreakpoints]]>,
21
+
22
+ // setters
23
+ themes: Array<keyof UnistylesThemes>,
24
+ useBreakpoints(breakpoints: UnistylesBreakpoints): void,
25
+ useTheme(name: keyof UnistylesThemes): void,
26
+ useAdaptiveThemes(enable: boolean): void
27
+ }
28
+
29
+ export type UnistylesThemeEvent = {
30
+ type: CxxUnistylesEventTypes.Theme,
31
+ payload: {
32
+ themeName: keyof UnistylesThemes
33
+ }
34
+ }
35
+
36
+ export type UnistylesMobileLayoutEvent = {
37
+ type: CxxUnistylesEventTypes.Layout,
38
+ payload: {
39
+ screen: ScreenSize,
40
+ breakpoint: keyof UnistylesBreakpoints,
41
+ orientation: ScreenOrientation
42
+ }
43
+ }
44
+
45
+ export type UnistylesEvents = UnistylesThemeEvent | UnistylesMobileLayoutEvent
@@ -0,0 +1,56 @@
1
+ import { useMemo } from 'react'
2
+ import { StyleSheet } from 'react-native'
3
+ import { parseStyle, proxifyFunction } from './utils'
4
+ import type { CreateStylesFactory, CustomNamedStyles, ReactNativeStyleSheet, UnistylesTheme } from './types'
5
+ import { useUnistyles } from './hooks'
6
+ import type { UnistylesBreakpoints } from './global'
7
+
8
+ type ParsedStylesheet<ST extends CustomNamedStyles<ST>> = {
9
+ theme: UnistylesTheme,
10
+ breakpoint: keyof UnistylesBreakpoints,
11
+ styles: ReactNativeStyleSheet<ST>
12
+ }
13
+
14
+ export const useStyles = <ST extends CustomNamedStyles<ST>>(
15
+ stylesheet?: ST | CreateStylesFactory<ST, UnistylesTheme>,
16
+ variant?: string
17
+ ): ParsedStylesheet<ST> => {
18
+ const { theme, layout } = useUnistyles()
19
+ const { screenSize, breakpoint } = layout
20
+
21
+ if (!stylesheet) {
22
+ return {
23
+ theme,
24
+ breakpoint,
25
+ styles: {} as ReactNativeStyleSheet<ST>
26
+ }
27
+ }
28
+
29
+ const parsedStyles = useMemo(() => typeof stylesheet === 'function'
30
+ ? stylesheet(theme)
31
+ : stylesheet, [theme, stylesheet])
32
+
33
+ const dynamicStyleSheet = useMemo(() => Object
34
+ .entries(parsedStyles)
35
+ .reduce((acc, [key, value]) => {
36
+ const style = value as CustomNamedStyles<ST>
37
+
38
+ if (typeof value === 'function') {
39
+ return {
40
+ ...acc,
41
+ [key]: proxifyFunction(value, breakpoint, screenSize, variant)
42
+ }
43
+ }
44
+
45
+ return StyleSheet.create({
46
+ ...acc,
47
+ [key]: parseStyle<ST>(style, breakpoint, screenSize, variant)
48
+ })
49
+ }, {} as ST), [breakpoint, screenSize, parsedStyles, variant]) as ReactNativeStyleSheet<ST>
50
+
51
+ return {
52
+ theme,
53
+ breakpoint,
54
+ styles: dynamicStyleSheet
55
+ }
56
+ }
@@ -1,37 +1,22 @@
1
- import { throwError } from './common'
2
- import type { Breakpoints, ScreenSize, SortedBreakpointEntries } from '../types'
3
- import { getKeyForCustomMediaQuery, isMediaQuery } from './mediaQueries'
4
-
5
- /**
6
- * Sorts the breakpoints object based on its numeric values in ascending order and validates them.
7
- *
8
- * This function takes an object where keys represent breakpoint names and values are numeric.
9
- * It returns a new object with the same keys but sorted based on their corresponding numeric values.
10
- * Additionally, it validates that:
11
- * 1. The first breakpoint starts with a value of 0.
12
- * 2. No duplicate breakpoint values exist.
13
- *
14
- * If the validation fails, appropriate error messages are logged to the console.
15
- *
16
- * @template B - An object type where keys are strings and values are numbers.
17
- * @param {B} breakpoints - The breakpoints object to be sorted and validated.
18
- * @returns {B} A new object with sorted and validated breakpoints.
19
- *
20
- * @example
21
- * const input = { md: 768, lg: 1024, sm: 0 }
22
- * sortAndValidateBreakpoints(input) // returns { sm: 0, md: 768, lg: 1024 }
23
- */
24
- export const sortAndValidateBreakpoints = <B extends Breakpoints>(breakpoints: B): B => {
1
+ import { unistyles } from '../core'
2
+ import { isMobile, Orientation, throwError } from './common'
3
+ import type { NestedStyle, NestedStylePairs, RNValue } from '../types'
4
+ import type { UnistylesBreakpoints } from '../global'
5
+ import { ScreenOrientation } from '../common'
6
+ import { getKeyForUnistylesMediaQuery } from './mqParser'
7
+ import { getKeyForVariant } from './variants'
8
+
9
+ export const sortAndValidateBreakpoints = (breakpoints: UnistylesBreakpoints): UnistylesBreakpoints => {
25
10
  const sortedPairs = Object
26
11
  .entries(breakpoints)
27
12
  .sort((breakpoint1, breakpoint2) => {
28
13
  const [, value1] = breakpoint1
29
14
  const [, value2] = breakpoint2
30
15
 
31
- return value1 - value2
16
+ return (value1 as number) - (value2 as number)
32
17
  })
33
18
 
34
- const sortedBreakpoints = Object.freeze(Object.fromEntries(sortedPairs)) as B
19
+ const sortedBreakpoints = Object.freeze(Object.fromEntries(sortedPairs)) as UnistylesBreakpoints
35
20
  const breakpointValues = Object.values(sortedBreakpoints)
36
21
  const [firstBreakpoint] = breakpointValues
37
22
 
@@ -46,25 +31,10 @@ export const sortAndValidateBreakpoints = <B extends Breakpoints>(breakpoints: B
46
31
  return sortedBreakpoints
47
32
  }
48
33
 
49
- /**
50
- * Determines the appropriate breakpoint key for a given screen width based on provided breakpoints.
51
- *
52
- * This function takes a screen width and an object of breakpoints. It returns the key of the breakpoint
53
- * that the screen width falls into. The breakpoints are assumed to be sorted in ascending order.
54
- *
55
- * @template B - An object type where keys are strings and values are numbers representing screen widths.
56
- * @param {number} width - The screen width to determine the breakpoint for.
57
- * @param breakpointEntries - sorted pairs of breakpoints
58
- * @returns {keyof B & string} The key of the breakpoint that the screen width falls into.
59
- *
60
- * @example
61
- * const breakpoints = { sm: 0, md: 768, lg: 1024 }
62
- * getBreakpointFromScreenWidth(800, breakpoints) // returns 'md'
63
- */
64
- export const getBreakpointFromScreenWidth = <B extends Breakpoints>(width: number, breakpointEntries: SortedBreakpointEntries<B>): keyof B & string => {
34
+ export const getBreakpointFromScreenWidth = (width: number, breakpointEntries: Array<[keyof UnistylesBreakpoints, UnistylesBreakpoints[keyof UnistylesBreakpoints]]>): keyof UnistylesBreakpoints & string => {
65
35
  const [key] = breakpointEntries
66
36
  .find(([, value], index, otherBreakpoints) => {
67
- const minVal = value
37
+ const minVal = value as number
68
38
  const maxVal = otherBreakpoints[index + 1]?.[1]
69
39
 
70
40
  if (!maxVal) {
@@ -72,69 +42,68 @@ export const getBreakpointFromScreenWidth = <B extends Breakpoints>(width: numbe
72
42
  }
73
43
 
74
44
  return width >= minVal && width < maxVal
75
- }) as [keyof B & string, number]
45
+ }) as [keyof UnistylesBreakpoints & string, number]
76
46
 
77
47
  return key
78
48
  }
79
49
 
80
- /**
81
- * Retrieves the value associated with a given breakpoint or custom media query based on the provided screen size.
82
- *
83
- * The function first checks for custom media queries. If a matching custom media query is found, its associated value is returned.
84
- * If no custom media query matches, the function then checks for a direct breakpoint match.
85
- * If there's no direct breakpoint match, the function simulates CSS cascading to find the closest matching breakpoint.
86
- *
87
- * @template B - An object type where keys represent breakpoint names and values represent breakpoint values.
88
- *
89
- * @param {Record<keyof B & string, string | number>} value - An object containing values associated with breakpoints or custom media queries.
90
- * @param {keyof B & string} breakpoint - The breakpoint name to check against.
91
- * @param {ScreenSize} screenSize - An object representing the screen size to be checked against the media queries.
92
- * @param breakpointPairs - sorted pairs of breakpoints
93
- *
94
- * @returns {string | number | undefined} Returns the value associated with the matching breakpoint or custom media query, or `undefined` if no match is found.
95
- *
96
- * @example
97
- *
98
- * const values = { ':w[200]': 'value1', sm: 'value2', md: 'value3' }
99
- * const screenSize = { width: 250, height: 400 }
100
- * const breakpoints = { sm: 300, md: 600, lg: 900 }
101
- *
102
- * getValueForBreakpoint(values, 'sm', screenSize, breakpoints); // 'value1'
103
- */
104
- export const getValueForBreakpoint = <B extends Breakpoints>(
105
- value: Record<keyof B & string, string | number | undefined>,
106
- breakpoint: keyof B & string,
107
- screenSize: ScreenSize,
108
- breakpointPairs: SortedBreakpointEntries<B>
109
- ): string | number | undefined => {
110
- // the highest priority is for custom media queries
111
- const customMediaQueries = Object
112
- .entries(value)
113
- .filter(([key]) => isMediaQuery(key))
114
- const customMediaQueryKey = getKeyForCustomMediaQuery(customMediaQueries, screenSize)
115
-
116
- if (customMediaQueryKey && customMediaQueryKey in value) {
50
+ // todo move it to different file
51
+ export const getValueForNestedStyle = (value: NestedStyle, variant?: string): RNValue => {
52
+ // the highest priority is for variants
53
+ const variantKey = getKeyForVariant(value, variant)
54
+
55
+ if (variantKey) {
56
+ return value.variants[variantKey as string]
57
+ }
58
+
59
+ // then custom media queries
60
+ const customMediaQueryKey = getKeyForUnistylesMediaQuery(
61
+ Object.entries(value) as NestedStylePairs,
62
+ unistyles.runtime.screen
63
+ ) as keyof typeof value
64
+
65
+ if (customMediaQueryKey) {
117
66
  return value[customMediaQueryKey]
118
67
  }
119
68
 
120
- // if no custom media query, or didn't match, proceed with defined breakpoints
121
- const unifiedKey = breakpoint.toLowerCase()
122
- const directBreakpoint = value[unifiedKey]
69
+ // at this point user didn't use custom media queries (:w, :h)
70
+ // check if user defined any breakpoints
71
+ const hasBreakpoints = unistyles.runtime.sortedBreakpoints.length > 0
72
+
73
+ // if not then we can fall back to horizontal and portrait (mobile only)
74
+ if (!hasBreakpoints && isMobile && (Orientation.Landscape in value || Orientation.Portrait in value)) {
75
+ return value[
76
+ unistyles.runtime.orientation === ScreenOrientation.Portrait
77
+ ? Orientation.Portrait
78
+ : Orientation.Landscape
79
+ ]
80
+ }
81
+
82
+ // let's get the current breakpoint
83
+ const breakpoint = unistyles.runtime.breakpoint
84
+
85
+ if (!breakpoint) {
86
+ return undefined
87
+ }
88
+
89
+ // if user defined breakpoints, then we look for the valid one
90
+ const directBreakpoint = value[breakpoint]
123
91
 
124
92
  // if there is a direct key like 'sm' or 'md', or value for this key exists but its undefined
125
- if (directBreakpoint || (unifiedKey in value)) {
93
+ if (directBreakpoint || (breakpoint in value)) {
126
94
  return directBreakpoint
127
95
  }
128
96
 
129
- // there is no direct hit for breakpoint nor media-query, so let's simulate CSS cascading
97
+ // there is no direct hit for breakpoint nor media-query, let's simulate CSS cascading
98
+ const breakpointPairs = unistyles.runtime.sortedBreakpoints
130
99
  const currentBreakpoint = breakpointPairs
131
- .findIndex(([key]) => key === unifiedKey)
100
+ .findIndex(([key]) => key === breakpoint)
132
101
 
133
102
  const availableBreakpoints = breakpointPairs
134
103
  .filter(([key], index) => index < currentBreakpoint && key && key in value)
135
104
  .map(([key]) => key)
136
105
 
137
106
  return breakpointPairs.length > 0
138
- ? value[availableBreakpoints[availableBreakpoints.length - 1] as keyof B & string]
107
+ ? value[availableBreakpoints[availableBreakpoints.length - 1] as keyof UnistylesBreakpoints & string]
139
108
  : undefined
140
109
  }
@@ -8,4 +8,13 @@ export const warn = (message: string) => {
8
8
  console.warn(`🦄 [react-native-unistyles]: ${message}`)
9
9
  }
10
10
 
11
- export const isWeb = () => Platform.OS === 'web'
11
+ export const isMobile = Platform.OS === 'android' || Platform.OS === 'ios'
12
+ export const isWeb = Platform.OS === 'web'
13
+ export const isIOS = Platform.OS === 'ios'
14
+ export const isAndroid = Platform.OS === 'android'
15
+ export const isServer = typeof window === 'undefined'
16
+
17
+ export const Orientation = {
18
+ Landscape: 'landscape',
19
+ Portrait: 'portrait'
20
+ } as const
@@ -1,11 +1,8 @@
1
1
  export { normalizeStyles } from './normalizeStyles'
2
- export { getBreakpointFromScreenWidth, sortAndValidateBreakpoints, getValueForBreakpoint } from './breakpoints'
2
+ export * from './normalizer'
3
+ export { mq, MQSymbol } from './mq'
4
+ export { getKeyForVariant } from './variants'
5
+ export { getKeyForUnistylesMediaQuery } from './mqParser'
6
+ export { getBreakpointFromScreenWidth, sortAndValidateBreakpoints, getValueForNestedStyle } from './breakpoints'
3
7
  export { proxifyFunction, parseStyle } from './styles'
4
- export {
5
- extractValues,
6
- getKeyForCustomMediaQuery,
7
- isMediaQuery,
8
- isWithinTheHeight,
9
- isWithinTheWidth,
10
- isWithinTheWidthAndHeight
11
- } from './mediaQueries'
8
+ export { isServer, Orientation } from './common'
@@ -0,0 +1,3 @@
1
+ declare module '@react-native/normalize-colors' {
2
+ export default function normalizeColor(color: string): number | null
3
+ }
@@ -0,0 +1,106 @@
1
+ import type { MediaQuery, Nullable } from '../types'
2
+ import type { UnistylesBreakpoints } from '../global'
3
+ import { unistyles } from '../core'
4
+
5
+ export const MQSymbol = Symbol('unistyles-mq')
6
+
7
+ type MQValue = keyof UnistylesBreakpoints | number
8
+
9
+ type MQHandler = {
10
+ w(wMin?: Nullable<MQValue>, wMax?: MQValue): WidthHandler,
11
+ width(wMin?: Nullable<MQValue>, wMax?: MQValue): WidthHandler,
12
+ h(hMin?: Nullable<MQValue>, hMax?: MQValue): HeightHandler,
13
+ height(hMin?: Nullable<MQValue>, hMax?: MQValue): HeightHandler
14
+ }
15
+
16
+ type HeightHandler = {
17
+ w(wMin?: Nullable<MQValue>, wMax?: MQValue): MediaQuery,
18
+ width(wMin?: Nullable<MQValue>, wMax?: MQValue): MediaQuery
19
+ } & MediaQuery
20
+
21
+ type WidthHandler = {
22
+ h(hMin?: Nullable<MQValue>, hMax?: MQValue): MediaQuery,
23
+ height(hMin?: Nullable<MQValue>, hMax?: MQValue): MediaQuery
24
+ } & MediaQuery
25
+
26
+ type FinalHandler = {
27
+ [MQSymbol]: true
28
+ }
29
+
30
+ enum MQProp {
31
+ toString = 'toString',
32
+ width = 'width',
33
+ height = 'height',
34
+ shortW = 'w',
35
+ shortH = 'h'
36
+ }
37
+
38
+ const getMQValue = (value: Nullable<MQValue>) => {
39
+ if (typeof value === 'number') {
40
+ return value
41
+ }
42
+
43
+ if (value === null) {
44
+ return 0
45
+ }
46
+
47
+ return unistyles.registry.breakpoints[value] ?? 0
48
+ }
49
+
50
+ const widthHandler = (hMin: Nullable<MQValue> = 0, hMax: MQValue = Infinity) => new Proxy<HeightHandler>({} as HeightHandler, {
51
+ get: (target, prop, receiver) => {
52
+ if (prop === Symbol.toPrimitive || prop === MQProp.toString) {
53
+ return () => `:h[${getMQValue(hMin)}, ${getMQValue(hMax)}]`
54
+ }
55
+
56
+ if (prop === MQProp.width || prop === MQProp.shortW) {
57
+ return (wMin: MQValue = 0, wMax: MQValue = Infinity) => new Proxy<FinalHandler>({} as FinalHandler, {
58
+ get: (target, prop, receiver) => {
59
+ if (prop === Symbol.toPrimitive || prop === MQProp.toString) {
60
+ return () => `:w[${getMQValue(wMin)}, ${getMQValue(wMax)}]:h[${getMQValue(hMin)}, ${getMQValue(hMax)}]`
61
+ }
62
+
63
+ return Reflect.get(target, prop, receiver)
64
+ }
65
+ })
66
+ }
67
+
68
+ return Reflect.get(target, prop, receiver)
69
+ }
70
+ })
71
+
72
+ const heightHandler = (wMin: Nullable<MQValue> = 0, wMax: MQValue = Infinity) => new Proxy({} as WidthHandler, {
73
+ get: (target, prop, receiver) => {
74
+ if (prop === Symbol.toPrimitive || prop === MQProp.toString) {
75
+ return () => `:w[${getMQValue(wMin)}, ${getMQValue(wMax)}]`
76
+ }
77
+
78
+ if (prop === MQProp.height || prop === MQProp.shortH) {
79
+ return (hMin: MQValue = 0, hMax: MQValue = Infinity) => new Proxy<FinalHandler>({} as FinalHandler, {
80
+ get: (target, prop, receiver) => {
81
+ if (prop === Symbol.toPrimitive || MQProp.toString) {
82
+ return () => `:w[${getMQValue(wMin)}, ${getMQValue(wMax)}]:h[${getMQValue(hMin)}, ${getMQValue(hMax)}]`
83
+ }
84
+
85
+ return Reflect.get(target, prop, receiver)
86
+ }
87
+ })
88
+ }
89
+
90
+ return Reflect.get(target, prop, receiver)
91
+ }
92
+ })
93
+
94
+ export const mq = new Proxy({} as MQHandler, {
95
+ get: (target, prop, receiver) => {
96
+ if (prop === MQProp.shortW || prop === MQProp.width) {
97
+ return heightHandler
98
+ }
99
+
100
+ if (prop === MQProp.shortH || prop === MQProp.height) {
101
+ return widthHandler
102
+ }
103
+
104
+ return Reflect.get(target, prop, receiver)
105
+ }
106
+ })
@@ -0,0 +1,99 @@
1
+ import type { NestedStylePairs, Optional, ScreenSize } from '../types'
2
+
3
+ const IS_UNISTYLES_REGEX = /:([hw])\[(\d+)(?:,\s*(\d+|Infinity))?]/
4
+ const UNISTYLES_WIDTH_REGEX = /:(w)\[(\d+)(?:,\s*(\d+|Infinity))?]/
5
+ const UNISTYLES_HEIGHT_REGEX = /:(h)\[(\d+)(?:,\s*(\d+|Infinity))?]/
6
+
7
+ type ParsedMqDimension = {
8
+ from: number,
9
+ to: number
10
+ }
11
+
12
+ type UnistylesParsedMq = {
13
+ width?: ParsedMqDimension,
14
+ height?: ParsedMqDimension
15
+ }
16
+
17
+ const parseMq = (mq: string): UnistylesParsedMq => {
18
+ const [, width, fromW, toW] = UNISTYLES_WIDTH_REGEX.exec(mq) || []
19
+ const [, height, fromH, toH] = UNISTYLES_HEIGHT_REGEX.exec(mq) || []
20
+
21
+ return {
22
+ width: width ? {
23
+ from: Number(fromW),
24
+ to: Number(toW)
25
+ } : undefined,
26
+ height: height ? {
27
+ from: Number(fromH),
28
+ to: Number(toH)
29
+ } : undefined
30
+ }
31
+ }
32
+
33
+ const isUnistylesMq = (mq: string) => IS_UNISTYLES_REGEX.test(mq)
34
+
35
+ const isValidMq = (parsedMq: UnistylesParsedMq) => {
36
+ const { width, height } = parsedMq
37
+
38
+ if (width && height) {
39
+ return width.from <= width.to && height.from <= height.to
40
+ }
41
+
42
+ if (width) {
43
+ return width.from <= width.to
44
+ }
45
+
46
+ if (height) {
47
+ return height.from <= height.to
48
+ }
49
+
50
+ return false
51
+ }
52
+
53
+ const isWithinTheWidthAndHeight = (parsedMq: UnistylesParsedMq, screenSize: ScreenSize): boolean => {
54
+ const { width, height } = parsedMq
55
+
56
+ if (width && height) {
57
+ return isWithinTheWidth(width, screenSize.width) && isWithinTheHeight(height, screenSize.height)
58
+ }
59
+
60
+ if (width) {
61
+ return isWithinTheWidth(width, screenSize.width)
62
+ }
63
+
64
+ if (height) {
65
+ return isWithinTheHeight(height, screenSize.height)
66
+ }
67
+
68
+ return false
69
+ }
70
+
71
+ const isWithinTheWidth = (width: UnistylesParsedMq['width'], screenWidth: number): boolean => {
72
+ const { from, to } = width as ParsedMqDimension
73
+
74
+ return screenWidth >= from && screenWidth <= to
75
+ }
76
+
77
+ const isWithinTheHeight = (height: UnistylesParsedMq['height'], screenHeight: number): boolean => {
78
+ const { from, to } = height as ParsedMqDimension
79
+
80
+ return screenHeight >= from && screenHeight <= to
81
+ }
82
+
83
+ export const getKeyForUnistylesMediaQuery = (mediaQueries: NestedStylePairs, screenSize: ScreenSize) => {
84
+ const mq = mediaQueries.find(([key]) => {
85
+ if (!isUnistylesMq(key as string)) {
86
+ return false
87
+ }
88
+
89
+ const parsedMq = parseMq(key as string)
90
+
91
+ if (!isValidMq(parsedMq)) {
92
+ return false
93
+ }
94
+
95
+ return isWithinTheWidthAndHeight(parsedMq, screenSize)
96
+ })
97
+
98
+ return mq?.at(0) as Optional<string>
99
+ }
@@ -1,29 +1,8 @@
1
1
  import { warn } from './common'
2
+ import { preprocessor } from './normalizer'
3
+ import type { NormalizedBoxShadow, NormalizedTextShadow, BoxShadow, TextShadow, Transforms } from '../types'
2
4
 
3
- const preprocessor: Preprocessor = require('react-native-web/src/exports/StyleSheet/preprocess.js')
4
-
5
- type Preprocessor = {
6
- createTextShadowValue<T>(styles: any): T,
7
- createBoxShadowValue<T>(styles: any): T,
8
- createTransformValue<T>(transforms: any): T,
9
- }
10
-
11
- type NormalizedBoxShadow = {
12
- shadowColor: undefined,
13
- shadowOffset: undefined,
14
- shadowOpacity: undefined,
15
- shadowRadius: undefined,
16
- boxShadow?: string
17
- }
18
-
19
- type NormalizedTextShadow = {
20
- textShadowColor: undefined
21
- textShadowOffset: undefined
22
- textShadowRadius: undefined,
23
- textShadow?: string
24
- }
25
-
26
- const normalizeBoxShadow = <T extends {}>(styles: T): NormalizedBoxShadow => {
5
+ const normalizeBoxShadow = <T extends BoxShadow>(style: T): NormalizedBoxShadow => {
27
6
  const requiredBoxShadowProperties = [
28
7
  'shadowColor',
29
8
  'shadowOffset',
@@ -31,7 +10,7 @@ const normalizeBoxShadow = <T extends {}>(styles: T): NormalizedBoxShadow => {
31
10
  'shadowRadius'
32
11
  ]
33
12
 
34
- if (!requiredBoxShadowProperties.every(prop => prop in styles)) {
13
+ if (!requiredBoxShadowProperties.every(prop => prop in style)) {
35
14
  warn(`can't apply box shadow as you miss at least one of these properties: ${requiredBoxShadowProperties.join(', ')}`)
36
15
 
37
16
  return {
@@ -43,7 +22,7 @@ const normalizeBoxShadow = <T extends {}>(styles: T): NormalizedBoxShadow => {
43
22
  }
44
23
 
45
24
  return {
46
- boxShadow: preprocessor.createBoxShadowValue(styles),
25
+ boxShadow: preprocessor.createBoxShadowValue(style),
47
26
  shadowColor: undefined,
48
27
  shadowOffset: undefined,
49
28
  shadowOpacity: undefined,
@@ -51,14 +30,14 @@ const normalizeBoxShadow = <T extends {}>(styles: T): NormalizedBoxShadow => {
51
30
  }
52
31
  }
53
32
 
54
- const normalizeTextShadow = <T extends {}>(styles: T): NormalizedTextShadow => {
33
+ const normalizeTextShadow = <T extends TextShadow>(style: T): NormalizedTextShadow => {
55
34
  const requiredTextShadowProperties = [
56
35
  'textShadowColor',
57
36
  'textShadowOffset',
58
37
  'textShadowRadius'
59
38
  ]
60
39
 
61
- if (!requiredTextShadowProperties.every(prop => prop in styles)) {
40
+ if (!requiredTextShadowProperties.every(prop => prop in style)) {
62
41
  warn(`can't apply text shadow as you miss at least one of these properties: ${requiredTextShadowProperties.join(', ')}`)
63
42
 
64
43
  return {
@@ -69,33 +48,33 @@ const normalizeTextShadow = <T extends {}>(styles: T): NormalizedTextShadow => {
69
48
  }
70
49
 
71
50
  return {
72
- textShadow: preprocessor.createTextShadowValue(styles),
51
+ textShadow: preprocessor.createTextShadowValue(style),
73
52
  textShadowColor: undefined,
74
53
  textShadowOffset: undefined,
75
54
  textShadowRadius: undefined
76
55
  }
77
56
  }
78
57
 
79
- export const normalizeStyles = <T extends {}>(styles: T): T => {
80
- const normalizedTransform = ('transform' in styles && Array.isArray(styles.transform))
81
- ? { transform: preprocessor.createTransformValue(styles.transform) }
58
+ export const normalizeStyles = <T extends BoxShadow | TextShadow | { transform: Transforms }>(style: T): T => {
59
+ const normalizedTransform = ('transform' in style && Array.isArray(style.transform))
60
+ ? { transform: preprocessor.createTransformValue(style.transform) }
82
61
  : {}
83
62
 
84
63
  const normalizedBoxShadow = (
85
- 'shadowColor' in styles ||
86
- 'shadowOffset' in styles ||
87
- 'shadowOpacity' in styles ||
88
- 'shadowRadius' in styles
89
- ) ? normalizeBoxShadow(styles) : {}
64
+ 'shadowColor' in style ||
65
+ 'shadowOffset' in style ||
66
+ 'shadowOpacity' in style ||
67
+ 'shadowRadius' in style
68
+ ) ? normalizeBoxShadow(style as BoxShadow) : {}
90
69
 
91
70
  const normalizedTextShadow = (
92
- 'textShadowColor' in styles ||
93
- 'textShadowOffset' in styles ||
94
- 'textShadowRadius' in styles
95
- ) ? normalizeTextShadow(styles) : {}
71
+ 'textShadowColor' in style ||
72
+ 'textShadowOffset' in style ||
73
+ 'textShadowRadius' in style
74
+ ) ? normalizeTextShadow(style as TextShadow) : {}
96
75
 
97
76
  return {
98
- ...styles,
77
+ ...style,
99
78
  ...normalizedTransform,
100
79
  ...normalizedBoxShadow,
101
80
  ...normalizedTextShadow