react-native-unistyles 3.0.0-alpha.35 → 3.0.0-alpha.37

Sign up to get free protection for your applications and to get access to all the features.
Files changed (214) hide show
  1. package/Unistyles.podspec +1 -1
  2. package/android/CMakeLists.txt +19 -36
  3. package/android/build.gradle +2 -1
  4. package/android/src/main/cxx/NativeUnistylesModule.cpp +71 -0
  5. package/android/src/main/cxx/NativeUnistylesModule.h +42 -0
  6. package/android/src/main/cxx/cpp-adapter.cpp +8 -86
  7. package/android/src/main/java/com/unistyles/Equatable.kt +61 -0
  8. package/android/src/main/java/com/unistyles/NativePlatform+android.kt +302 -0
  9. package/android/src/main/java/com/unistyles/NativePlatform+insets.kt +148 -0
  10. package/android/src/main/java/com/unistyles/NativePlatform+listener.kt +54 -0
  11. package/android/src/main/java/com/unistyles/UnistylesModule.kt +51 -0
  12. package/android/src/main/java/com/unistyles/UnistylesPackage.kt +16 -14
  13. package/cxx/NativePlatform.h +11 -0
  14. package/cxx/common/Helpers.h +1 -1
  15. package/cxx/core/Unistyle.h +1 -1
  16. package/cxx/core/UnistyleData.h +1 -1
  17. package/cxx/core/UnistyleWrapper.h +1 -2
  18. package/cxx/core/UnistylesCommitHook.cpp +1 -1
  19. package/cxx/core/UnistylesMountHook.cpp +1 -1
  20. package/cxx/core/UnistylesRegistry.cpp +4 -13
  21. package/cxx/core/UnistylesRegistry.h +2 -3
  22. package/cxx/core/UnistylesState.cpp +10 -7
  23. package/cxx/hybridObjects/HybridNavigationBar.h +3 -3
  24. package/cxx/hybridObjects/HybridStatusBar.h +3 -3
  25. package/cxx/hybridObjects/HybridStyleSheet.cpp +21 -18
  26. package/cxx/hybridObjects/HybridUnistylesRuntime.cpp +4 -8
  27. package/cxx/hybridObjects/HybridUnistylesRuntime.h +2 -3
  28. package/cxx/parser/Parser.cpp +3 -27
  29. package/cxx/parser/Parser.h +2 -3
  30. package/cxx/shadowTree/ShadowTrafficController.h +9 -5
  31. package/cxx/shadowTree/ShadowTreeManager.cpp +10 -5
  32. package/cxx/shadowTree/ShadowTreeManager.h +1 -1
  33. package/lib/commonjs/components/useMedia.js.map +1 -1
  34. package/lib/commonjs/components/useMedia.web.js +43 -0
  35. package/lib/commonjs/components/useMedia.web.js.map +1 -0
  36. package/lib/commonjs/core/createUnistylesComponent.js +57 -4
  37. package/lib/commonjs/core/createUnistylesComponent.js.map +1 -1
  38. package/lib/commonjs/core/createUnistylesComponent.native.js +6 -5
  39. package/lib/commonjs/core/createUnistylesComponent.native.js.map +1 -1
  40. package/lib/commonjs/web/convert/index.js +16 -11
  41. package/lib/commonjs/web/convert/index.js.map +1 -1
  42. package/lib/commonjs/web/convert/object/boxShadow.js +58 -0
  43. package/lib/commonjs/web/convert/object/boxShadow.js.map +1 -0
  44. package/lib/commonjs/web/convert/object/filter.js +42 -0
  45. package/lib/commonjs/web/convert/object/filter.js.map +1 -0
  46. package/lib/commonjs/web/convert/object/index.js +39 -0
  47. package/lib/commonjs/web/convert/object/index.js.map +1 -0
  48. package/lib/commonjs/web/convert/object/objectStyle.js +55 -0
  49. package/lib/commonjs/web/convert/object/objectStyle.js.map +1 -0
  50. package/lib/commonjs/web/convert/object/transform.js +27 -0
  51. package/lib/commonjs/web/convert/object/transform.js.map +1 -0
  52. package/lib/commonjs/web/convert/{boxShadow.js → shadow/boxShadow.js} +9 -24
  53. package/lib/commonjs/web/convert/shadow/boxShadow.js.map +1 -0
  54. package/lib/commonjs/web/convert/shadow/getShadowBreakpoints.js +38 -0
  55. package/lib/commonjs/web/convert/shadow/getShadowBreakpoints.js.map +1 -0
  56. package/lib/commonjs/web/convert/shadow/index.js +28 -0
  57. package/lib/commonjs/web/convert/shadow/index.js.map +1 -0
  58. package/lib/commonjs/web/convert/{textShadow.js → shadow/textShadow.js} +9 -23
  59. package/lib/commonjs/web/convert/shadow/textShadow.js.map +1 -0
  60. package/lib/commonjs/web/convert/utils.js +7 -3
  61. package/lib/commonjs/web/convert/utils.js.map +1 -1
  62. package/lib/commonjs/web/listener.js +10 -0
  63. package/lib/commonjs/web/listener.js.map +1 -1
  64. package/lib/commonjs/web/registry.js +13 -26
  65. package/lib/commonjs/web/registry.js.map +1 -1
  66. package/lib/commonjs/web/runtime.js +3 -0
  67. package/lib/commonjs/web/runtime.js.map +1 -1
  68. package/lib/commonjs/web/shadowRegistry.js +79 -39
  69. package/lib/commonjs/web/shadowRegistry.js.map +1 -1
  70. package/lib/commonjs/web/utils/common.js +3 -33
  71. package/lib/commonjs/web/utils/common.js.map +1 -1
  72. package/lib/commonjs/web/utils/unistyle.js +4 -1
  73. package/lib/commonjs/web/utils/unistyle.js.map +1 -1
  74. package/lib/module/components/useMedia.js.map +1 -1
  75. package/lib/module/components/useMedia.web.js +38 -0
  76. package/lib/module/components/useMedia.web.js.map +1 -0
  77. package/lib/module/core/createUnistylesComponent.js +55 -3
  78. package/lib/module/core/createUnistylesComponent.js.map +1 -1
  79. package/lib/module/core/createUnistylesComponent.native.js +6 -5
  80. package/lib/module/core/createUnistylesComponent.native.js.map +1 -1
  81. package/lib/module/web/convert/index.js +14 -9
  82. package/lib/module/web/convert/index.js.map +1 -1
  83. package/lib/module/web/convert/object/boxShadow.js +53 -0
  84. package/lib/module/web/convert/object/boxShadow.js.map +1 -0
  85. package/lib/module/web/convert/object/filter.js +37 -0
  86. package/lib/module/web/convert/object/filter.js.map +1 -0
  87. package/lib/module/web/convert/object/index.js +6 -0
  88. package/lib/module/web/convert/object/index.js.map +1 -0
  89. package/lib/module/web/convert/object/objectStyle.js +50 -0
  90. package/lib/module/web/convert/object/objectStyle.js.map +1 -0
  91. package/lib/module/web/convert/object/transform.js +22 -0
  92. package/lib/module/web/convert/object/transform.js.map +1 -0
  93. package/lib/module/web/convert/{boxShadow.js → shadow/boxShadow.js} +9 -24
  94. package/lib/module/web/convert/shadow/boxShadow.js.map +1 -0
  95. package/lib/module/web/convert/shadow/getShadowBreakpoints.js +33 -0
  96. package/lib/module/web/convert/shadow/getShadowBreakpoints.js.map +1 -0
  97. package/lib/module/web/convert/shadow/index.js +5 -0
  98. package/lib/module/web/convert/shadow/index.js.map +1 -0
  99. package/lib/module/web/convert/{textShadow.js → shadow/textShadow.js} +9 -23
  100. package/lib/module/web/convert/shadow/textShadow.js.map +1 -0
  101. package/lib/module/web/convert/utils.js +4 -2
  102. package/lib/module/web/convert/utils.js.map +1 -1
  103. package/lib/module/web/listener.js +10 -0
  104. package/lib/module/web/listener.js.map +1 -1
  105. package/lib/module/web/registry.js +14 -27
  106. package/lib/module/web/registry.js.map +1 -1
  107. package/lib/module/web/runtime.js +3 -0
  108. package/lib/module/web/runtime.js.map +1 -1
  109. package/lib/module/web/shadowRegistry.js +80 -40
  110. package/lib/module/web/shadowRegistry.js.map +1 -1
  111. package/lib/module/web/utils/common.js +1 -31
  112. package/lib/module/web/utils/common.js.map +1 -1
  113. package/lib/module/web/utils/unistyle.js +4 -1
  114. package/lib/module/web/utils/unistyle.js.map +1 -1
  115. package/lib/typescript/src/components/useMedia.web.d.ts +6 -0
  116. package/lib/typescript/src/components/useMedia.web.d.ts.map +1 -0
  117. package/lib/typescript/src/core/createUnistylesComponent.d.ts +4 -3
  118. package/lib/typescript/src/core/createUnistylesComponent.d.ts.map +1 -1
  119. package/lib/typescript/src/core/createUnistylesComponent.native.d.ts +4 -3
  120. package/lib/typescript/src/core/createUnistylesComponent.native.d.ts.map +1 -1
  121. package/lib/typescript/src/types/common.d.ts +1 -0
  122. package/lib/typescript/src/types/common.d.ts.map +1 -1
  123. package/lib/typescript/src/web/convert/index.d.ts.map +1 -1
  124. package/lib/typescript/src/web/convert/object/boxShadow.d.ts +9 -0
  125. package/lib/typescript/src/web/convert/object/boxShadow.d.ts.map +1 -0
  126. package/lib/typescript/src/web/convert/object/filter.d.ts +3 -0
  127. package/lib/typescript/src/web/convert/object/filter.d.ts.map +1 -0
  128. package/lib/typescript/src/web/convert/object/index.d.ts +4 -0
  129. package/lib/typescript/src/web/convert/object/index.d.ts.map +1 -0
  130. package/lib/typescript/src/web/convert/object/objectStyle.d.ts +5 -0
  131. package/lib/typescript/src/web/convert/object/objectStyle.d.ts.map +1 -0
  132. package/lib/typescript/src/web/convert/object/transform.d.ts +3 -0
  133. package/lib/typescript/src/web/convert/object/transform.d.ts.map +1 -0
  134. package/lib/typescript/src/web/convert/shadow/boxShadow.d.ts.map +1 -0
  135. package/lib/typescript/src/web/convert/shadow/getShadowBreakpoints.d.ts +2 -0
  136. package/lib/typescript/src/web/convert/shadow/getShadowBreakpoints.d.ts.map +1 -0
  137. package/lib/typescript/src/web/convert/shadow/index.d.ts +3 -0
  138. package/lib/typescript/src/web/convert/shadow/index.d.ts.map +1 -0
  139. package/lib/typescript/src/web/convert/shadow/textShadow.d.ts.map +1 -0
  140. package/lib/typescript/src/web/convert/types.d.ts +7 -1
  141. package/lib/typescript/src/web/convert/types.d.ts.map +1 -1
  142. package/lib/typescript/src/web/convert/utils.d.ts +8 -4
  143. package/lib/typescript/src/web/convert/utils.d.ts.map +1 -1
  144. package/lib/typescript/src/web/create.d.ts +8 -8
  145. package/lib/typescript/src/web/index.d.ts +8 -8
  146. package/lib/typescript/src/web/listener.d.ts +2 -0
  147. package/lib/typescript/src/web/listener.d.ts.map +1 -1
  148. package/lib/typescript/src/web/registry.d.ts +5 -9
  149. package/lib/typescript/src/web/registry.d.ts.map +1 -1
  150. package/lib/typescript/src/web/runtime.d.ts +1 -0
  151. package/lib/typescript/src/web/runtime.d.ts.map +1 -1
  152. package/lib/typescript/src/web/shadowRegistry.d.ts +4 -1
  153. package/lib/typescript/src/web/shadowRegistry.d.ts.map +1 -1
  154. package/lib/typescript/src/web/utils/common.d.ts +1 -6
  155. package/lib/typescript/src/web/utils/common.d.ts.map +1 -1
  156. package/lib/typescript/src/web/utils/unistyle.d.ts.map +1 -1
  157. package/nitrogen/generated/android/c++/JHybridNativePlatformSpec.hpp +6 -0
  158. package/nitrogen/generated/android/kotlin/com/margelo/nitro/unistyles/Dimensions.kt +1 -0
  159. package/nitrogen/generated/android/kotlin/com/margelo/nitro/unistyles/Func_void.kt +1 -0
  160. package/nitrogen/generated/android/kotlin/com/margelo/nitro/unistyles/Func_void_std__vector_UnistyleDependency_.kt +1 -0
  161. package/nitrogen/generated/android/kotlin/com/margelo/nitro/unistyles/Insets.kt +1 -0
  162. package/nitrogen/generated/android/kotlin/com/margelo/nitro/unistyles/UnistylesNativeMiniRuntime.kt +1 -0
  163. package/nitrogen/generated/android/unistyles+autolinking.gradle +2 -0
  164. package/nitrogen/generated/ios/Unistyles+autolinking.rb +1 -1
  165. package/package.json +3 -3
  166. package/src/components/useMedia.ts +1 -1
  167. package/src/components/useMedia.web.ts +47 -0
  168. package/src/core/createUnistylesComponent.native.tsx +12 -10
  169. package/src/core/createUnistylesComponent.tsx +72 -6
  170. package/src/types/common.ts +1 -0
  171. package/src/web/convert/index.ts +16 -9
  172. package/src/web/convert/object/boxShadow.ts +54 -0
  173. package/src/web/convert/object/filter.ts +39 -0
  174. package/src/web/convert/object/index.ts +3 -0
  175. package/src/web/convert/object/objectStyle.ts +68 -0
  176. package/src/web/convert/object/transform.ts +24 -0
  177. package/src/web/convert/{boxShadow.ts → shadow/boxShadow.ts} +9 -30
  178. package/src/web/convert/shadow/getShadowBreakpoints.ts +34 -0
  179. package/src/web/convert/shadow/index.ts +2 -0
  180. package/src/web/convert/{textShadow.ts → shadow/textShadow.ts} +9 -29
  181. package/src/web/convert/types.ts +8 -1
  182. package/src/web/convert/utils.ts +11 -5
  183. package/src/web/listener.ts +10 -0
  184. package/src/web/registry.ts +10 -31
  185. package/src/web/runtime.ts +4 -0
  186. package/src/web/shadowRegistry.ts +85 -46
  187. package/src/web/utils/common.ts +1 -37
  188. package/src/web/utils/unistyle.ts +5 -1
  189. package/android/src/main/cxx/helpers.cpp +0 -105
  190. package/android/src/main/cxx/helpers.h +0 -16
  191. package/android/src/main/cxx/platform.cpp +0 -170
  192. package/android/src/main/cxx/platform.h +0 -20
  193. package/lib/commonjs/web/convert/boxShadow.js.map +0 -1
  194. package/lib/commonjs/web/convert/shadow.js +0 -68
  195. package/lib/commonjs/web/convert/shadow.js.map +0 -1
  196. package/lib/commonjs/web/convert/textShadow.js.map +0 -1
  197. package/lib/commonjs/web/convert/transform.js +0 -72
  198. package/lib/commonjs/web/convert/transform.js.map +0 -1
  199. package/lib/module/web/convert/boxShadow.js.map +0 -1
  200. package/lib/module/web/convert/shadow.js +0 -63
  201. package/lib/module/web/convert/shadow.js.map +0 -1
  202. package/lib/module/web/convert/textShadow.js.map +0 -1
  203. package/lib/module/web/convert/transform.js +0 -67
  204. package/lib/module/web/convert/transform.js.map +0 -1
  205. package/lib/typescript/src/web/convert/boxShadow.d.ts.map +0 -1
  206. package/lib/typescript/src/web/convert/shadow.d.ts +0 -2
  207. package/lib/typescript/src/web/convert/shadow.d.ts.map +0 -1
  208. package/lib/typescript/src/web/convert/textShadow.d.ts.map +0 -1
  209. package/lib/typescript/src/web/convert/transform.d.ts +0 -4
  210. package/lib/typescript/src/web/convert/transform.d.ts.map +0 -1
  211. package/src/web/convert/shadow.ts +0 -68
  212. package/src/web/convert/transform.ts +0 -88
  213. /package/lib/typescript/src/web/convert/{boxShadow.d.ts → shadow/boxShadow.d.ts} +0 -0
  214. /package/lib/typescript/src/web/convert/{textShadow.d.ts → shadow/textShadow.d.ts} +0 -0
@@ -0,0 +1,68 @@
1
+ import { deepMergeObjects, keyInObject } from '../../utils'
2
+
3
+ type Styles = Record<string, any>
4
+ type Normalize<TStyles extends Styles> = (key: keyof TStyles, value: TStyles[keyof TStyles]) => any
5
+
6
+ const createStylesValue = <TStyles extends Styles>(styles: Array<TStyles>, normalize: Normalize<TStyles>) => styles
7
+ .map(style => {
8
+ const [key] = Object.keys(style)
9
+
10
+ if (!key) {
11
+ return undefined
12
+ }
13
+
14
+ return normalize(key, style[key])
15
+ })
16
+ .filter(Boolean)
17
+ .join(' ')
18
+
19
+ export const getObjectStyle = <TStyles extends Styles>(styles: Array<TStyles>, styleKey: string, normalize: Normalize<TStyles>) => {
20
+ const breakpoints = new Set<string>()
21
+ const normalStyles: Array<TStyles> = []
22
+
23
+ styles.forEach(style => {
24
+ const [property] = Object.keys(style)
25
+
26
+ if (!property) {
27
+ return
28
+ }
29
+
30
+ const value = style[property]
31
+
32
+ if (typeof value === 'object' && !Array.isArray(value)) {
33
+ Object.keys(value ?? {}).forEach(breakpoint => breakpoints.add(breakpoint))
34
+
35
+ return
36
+ }
37
+
38
+ normalStyles.push(style)
39
+ })
40
+
41
+ const breakpointStyles = Array.from(breakpoints).flatMap(breakpoint => {
42
+ const stylesPerBreakpoint = styles.flatMap(style => {
43
+ const [property] = Object.keys(style)
44
+
45
+ if (!property) {
46
+ return []
47
+ }
48
+
49
+ const value = style[property]
50
+
51
+ if (typeof value === 'object' && !Array.isArray(value)) {
52
+ return keyInObject(value, breakpoint) ? [{ [property]: value[breakpoint] }] : []
53
+ }
54
+
55
+ return []
56
+ }) as Array<TStyles>
57
+
58
+ return [{
59
+ [breakpoint]: {
60
+ [styleKey]: createStylesValue(stylesPerBreakpoint, normalize)
61
+ }
62
+ }]
63
+ })
64
+
65
+ return deepMergeObjects<Record<string, any>>({
66
+ [styleKey]: createStylesValue(normalStyles, normalize)
67
+ }, ...breakpointStyles)
68
+ }
@@ -0,0 +1,24 @@
1
+ import { getObjectStyle } from './objectStyle'
2
+ import { normalizeNumericValue } from '../utils'
3
+ import type { TransformStyles } from '../../../types/core'
4
+
5
+ const normalizeTransform = (key: string, value: any) => {
6
+ if (key.includes('scale')) {
7
+ return value
8
+ }
9
+
10
+ if (typeof value === 'number') {
11
+ return normalizeNumericValue(value)
12
+ }
13
+
14
+ return value
15
+ }
16
+
17
+ export const getTransformStyle = (transforms: Array<TransformStyles>) => getObjectStyle(transforms, 'transform', (key, value) => {
18
+ switch(key) {
19
+ case 'matrix':
20
+ return `${key}(${(value as Array<number>).join(',')})`
21
+ default:
22
+ return `${key}(${normalizeTransform(key, value)})`
23
+ }
24
+ })
@@ -1,41 +1,20 @@
1
- import { deepMergeObjects, warn } from '../utils'
2
- import { validateShadow } from './shadow'
3
- import { BOX_SHADOW_STYLES, type BoxShadow } from './types'
4
- import { extractShadowValue, normalizeColor, normalizeNumericValue } from './utils'
1
+ import { deepMergeObjects } from '../../utils'
2
+ import { BOX_SHADOW_STYLES, type BoxShadow } from '../types'
3
+ import { extractShadowValue, normalizeColor, normalizeNumericValue } from '../utils'
4
+ import { getShadowBreakpoints } from './getShadowBreakpoints'
5
5
 
6
6
  const createBoxShadowValue = (style: BoxShadow) => {
7
- // at this point every prop is present
8
7
  const { shadowColor, shadowOffset, shadowOpacity, shadowRadius } = style
9
- const offsetX = normalizeNumericValue(shadowOffset.width)
10
- const offsetY = normalizeNumericValue(shadowOffset.height)
11
- const radius = normalizeNumericValue(shadowRadius)
12
- const color = normalizeColor(shadowColor as string, shadowOpacity as number)
8
+ const offsetX = normalizeNumericValue(shadowOffset?.width ?? 0)
9
+ const offsetY = normalizeNumericValue(shadowOffset?.height ?? 0)
10
+ const radius = normalizeNumericValue(shadowRadius ?? 0)
11
+ const color = normalizeColor((shadowColor ?? '#000000') as string, (shadowOpacity ?? 1) as number)
13
12
 
14
13
  return `${offsetX} ${offsetY} ${radius} ${color}`
15
14
  }
16
15
 
17
16
  export const getBoxShadowStyle = (styles: Record<string, any>) => {
18
- const missingStyles = BOX_SHADOW_STYLES.filter(key => !(key in styles))
19
-
20
- if (missingStyles.length) {
21
- warn(`can't apply box shadow as you miss these properties: ${missingStyles.join(', ')}`)
22
-
23
- return {}
24
- }
25
-
26
- const breakpointsSet = new Set<string>()
27
-
28
- try {
29
- validateShadow(BOX_SHADOW_STYLES, styles, breakpointsSet)
30
- } catch (error) {
31
- if (typeof error === 'string') {
32
- warn(error)
33
- }
34
-
35
- return {}
36
- }
37
-
38
- const breakpoints = Array.from(breakpointsSet)
17
+ const breakpoints = getShadowBreakpoints(BOX_SHADOW_STYLES, styles)
39
18
 
40
19
  // If no breakpoints were used return styles without media queries
41
20
  if (breakpoints.length === 0) {
@@ -0,0 +1,34 @@
1
+ import type { ShadowOffset } from '../types'
2
+
3
+ export const getShadowBreakpoints = (shadowProperties: ReadonlyArray<string>, styles: Record<string, any>) => {
4
+ const breakpoints = new Set<string>()
5
+
6
+ shadowProperties.forEach(key => {
7
+ const value = styles[key]
8
+
9
+ if (typeof value !== 'object') {
10
+ return
11
+ }
12
+
13
+ if (key === 'shadowOffset' || key === 'textShadowOffset') {
14
+ const { width, height } = value as ShadowOffset
15
+
16
+ // If shadowOffset.width has breakpoints
17
+ if (typeof width === 'object') {
18
+ Object.keys(width).forEach(breakpoint => breakpoints.add(breakpoint))
19
+ }
20
+
21
+ // If shadowOffset.height has breakpoints
22
+ if (typeof height === 'object') {
23
+ Object.keys(height).forEach(breakpoint => breakpoints.add(breakpoint))
24
+ }
25
+
26
+ return
27
+ }
28
+
29
+ // Collect regular breakpoints
30
+ Object.keys(value).forEach(breakpoint => breakpoints.add(breakpoint))
31
+ })
32
+
33
+ return Array.from(breakpoints)
34
+ }
@@ -0,0 +1,2 @@
1
+ export * from './boxShadow'
2
+ export * from './textShadow'
@@ -1,40 +1,20 @@
1
- import { deepMergeObjects, warn } from '../utils'
2
- import { validateShadow } from './shadow'
3
- import { TEXT_SHADOW_STYLES, type TextShadow } from './types'
4
- import { extractShadowValue, normalizeColor, normalizeNumericValue } from './utils'
1
+ import { deepMergeObjects } from '../../utils'
2
+ import { TEXT_SHADOW_STYLES, type TextShadow } from '../types'
3
+ import { extractShadowValue, normalizeColor, normalizeNumericValue } from '../utils'
4
+ import { getShadowBreakpoints } from './getShadowBreakpoints'
5
5
 
6
6
  const createTextShadowValue = (style: TextShadow) => {
7
7
  const { textShadowColor, textShadowOffset, textShadowRadius } = style
8
- const offsetX = normalizeNumericValue(textShadowOffset.width)
9
- const offsetY = normalizeNumericValue(textShadowOffset.height)
10
- const radius = normalizeNumericValue(textShadowRadius)
11
- const color = normalizeColor(textShadowColor as string)
8
+ const offsetX = normalizeNumericValue(textShadowOffset?.width ?? 0)
9
+ const offsetY = normalizeNumericValue(textShadowOffset?.height ?? 0)
10
+ const radius = normalizeNumericValue(textShadowRadius ?? 0)
11
+ const color = normalizeColor((textShadowColor ?? '#000000') as string)
12
12
 
13
13
  return `${offsetX} ${offsetY} ${radius} ${color}`
14
14
  }
15
15
 
16
16
  export const getTextShadowStyle = (styles: Record<string, any>) => {
17
- const missingStyles = TEXT_SHADOW_STYLES.filter(key => !(key in styles))
18
-
19
- if (missingStyles.length) {
20
- warn(`can't apply text shadow as you miss these properties: ${missingStyles.join(', ')}`)
21
-
22
- return {}
23
- }
24
-
25
- const breakpointsSet = new Set<string>()
26
-
27
- try {
28
- validateShadow(TEXT_SHADOW_STYLES, styles, breakpointsSet)
29
- } catch (error) {
30
- if (typeof error === 'string') {
31
- warn(error)
32
- }
33
-
34
- return {}
35
- }
36
-
37
- const breakpoints = Array.from(breakpointsSet)
17
+ const breakpoints = getShadowBreakpoints(TEXT_SHADOW_STYLES, styles)
38
18
 
39
19
  // If no breakpoints were used return styles without media queries
40
20
  if (breakpoints.length === 0) {
@@ -1,4 +1,4 @@
1
- import type { TextStyle, ViewStyle } from 'react-native'
1
+ import type { FilterFunction, TextStyle, ViewStyle } from 'react-native'
2
2
  import type { ToDeepUnistyles } from '../../types/stylesheet'
3
3
 
4
4
  export type ShadowOffset = ToDeepUnistyles<{ width: number, height: number }>
@@ -14,3 +14,10 @@ export type BoxShadow = Required<Pick<ViewStyle, typeof BOX_SHADOW_STYLES[number
14
14
  export type AllShadow = TextShadow & BoxShadow
15
15
 
16
16
  export type AllShadowKeys = keyof AllShadow
17
+
18
+ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never
19
+ type FilterKeys = keyof UnionToIntersection<FilterFunction>
20
+
21
+ export type Filters = {
22
+ [K in FilterKeys]: UnionToIntersection<FilterFunction>[K]
23
+ }
@@ -1,17 +1,23 @@
1
1
  // based on react-native-web normalizer
2
2
  // https://github.com/necolas/react-native-web
3
3
  import normalizeColors from '@react-native/normalize-colors'
4
- import { BOX_SHADOW_STYLES, TEXT_SHADOW_STYLES, type AllShadow, type AllShadowKeys } from './types'
4
+ import { BOX_SHADOW_STYLES, TEXT_SHADOW_STYLES, type AllShadow, type AllShadowKeys, type Filters } from './types'
5
+ import type { TransformStyles } from '../../types/core'
6
+ import type { BoxShadowValue } from 'react-native'
5
7
 
6
- export const isTransform = (key: string, value: any): value is Array<Record<string, any>> => key === 'transform' && Array.isArray(value)
8
+ export const isTransform = (key: string, value: any): value is Array<TransformStyles> => key === 'transform' && Array.isArray(value)
7
9
 
8
10
  export const isTextShadow = (key: string) => TEXT_SHADOW_STYLES.includes(key as typeof TEXT_SHADOW_STYLES[number])
9
11
 
10
- export const isBoxShadow = (key: string) => BOX_SHADOW_STYLES.includes(key as typeof BOX_SHADOW_STYLES[number])
12
+ export const isShadow = (key: string) => BOX_SHADOW_STYLES.includes(key as typeof BOX_SHADOW_STYLES[number])
11
13
 
12
- export const normalizeNumericValue = (value: number) => value ? `${value}px` : value
14
+ export const isFilter = (key: string, value: any): value is Array<Filters> => key === 'filter' && Array.isArray(value)
13
15
 
14
- export const normalizeColor = (color: string, opacity: number = 1) => {
16
+ export const isBoxShadow = (key: string, value: any): value is Array<BoxShadowValue> => key === 'boxShadow' && Array.isArray(value)
17
+
18
+ export const normalizeNumericValue = (value: number | string) => value && typeof value === 'number' ? `${value}px` : value
19
+
20
+ export const normalizeColor = (color: string, opacity = 1) => {
15
21
  // If the opacity is 1 there's no need to normalize the color
16
22
  if (opacity === 1) {
17
23
  return color
@@ -4,8 +4,10 @@ import { UnistylesRuntime } from './runtime'
4
4
  class UnistylesListenerBuilder {
5
5
  private isInitialized = false
6
6
  private listeners = Array.from({ length: Object.keys(UnistyleDependency).length / 2 }, () => new Set<VoidFunction>())
7
+ private stylesheetListeners = Array.from({ length: Object.keys(UnistyleDependency).length / 2 }, () => new Set<VoidFunction>())
7
8
 
8
9
  emitChange = (dependency: UnistyleDependency) => {
10
+ this.stylesheetListeners[dependency]?.forEach(listener => listener())
9
11
  this.listeners[dependency]?.forEach(listener => listener())
10
12
  }
11
13
 
@@ -28,6 +30,14 @@ class UnistylesListenerBuilder {
28
30
  dependencies.forEach(dependency => this.listeners[dependency]?.delete(listener))
29
31
  }
30
32
  }
33
+
34
+ addStylesheetListeners = (dependencies: Array<UnistyleDependency>, listener: VoidFunction) => {
35
+ dependencies.forEach(dependency => this.stylesheetListeners[dependency]?.add(listener))
36
+
37
+ return () => {
38
+ dependencies.forEach(dependency => this.stylesheetListeners[dependency]?.delete(listener))
39
+ }
40
+ }
31
41
  }
32
42
 
33
43
  export const UnistylesListener = new UnistylesListenerBuilder()
@@ -1,20 +1,11 @@
1
1
  import type { UnistylesTheme, UnistylesValues } from '../types'
2
2
  import type { StyleSheet, StyleSheetWithSuperPowers } from '../types/stylesheet'
3
3
  import { UnistylesRuntime } from './runtime'
4
- import { extractMediaQueryValue, keyInObject, getMediaQuery, generateHash, extractUnistyleDependencies, deepMergeObjects } from './utils'
4
+ import { extractMediaQueryValue, keyInObject, getMediaQuery, generateHash, extractUnistyleDependencies } from './utils'
5
5
  import { UnistylesListener } from './listener'
6
6
  import { convertUnistyles } from './convert'
7
7
  import type { UnistyleDependency } from '../specs/NativePlatform'
8
8
  import type { UnistylesMiniRuntime } from '../specs'
9
- import { getVariants } from './variants'
10
-
11
- type AddProps = {
12
- value: UnistylesValues,
13
- stylesheet: StyleSheetWithSuperPowers<StyleSheet>,
14
- key: string,
15
- args: Array<any>,
16
- variants: Record<string, any>
17
- }
18
9
 
19
10
  type ApplyRuleProps = {
20
11
  hash: string,
@@ -75,7 +66,7 @@ class UnistylesRegistryBuilder {
75
66
 
76
67
  dependencies.forEach(dependency => dependenciesMap.add(dependency))
77
68
 
78
- const dispose = UnistylesListener.addListeners(Array.from(dependenciesMap), () => {
69
+ const dispose = UnistylesListener.addStylesheetListeners(Array.from(dependenciesMap), () => {
79
70
  const newComputedStylesheet = stylesheet(UnistylesRuntime.theme, UnistylesRuntime.miniRuntime)
80
71
 
81
72
  this.stylesheets.set(stylesheet, newComputedStylesheet)
@@ -85,42 +76,26 @@ class UnistylesRegistryBuilder {
85
76
  this.disposeListenersMap.set(stylesheet, dispose)
86
77
  }
87
78
 
88
- add = ({ key, value, stylesheet, args, variants }: AddProps) => {
79
+ add = (value: UnistylesValues) => {
89
80
  const hash = generateHash(value)
90
81
  const existingCounter = this.stylesCounter.get(hash)
91
82
 
92
83
  if (!existingCounter || existingCounter.size === 0) {
93
84
  const counter = new Set<UnistylesValues>()
94
- const dependencies = extractUnistyleDependencies(value)
95
85
 
96
86
  counter.add(value)
97
87
  this.stylesCounter.set(hash, counter)
98
88
  this.applyStyles(hash, convertUnistyles(value))
99
89
 
100
- UnistylesListener.addListeners(dependencies, async () => {
101
- // Move this callback to the end of the event loop
102
- await Promise.resolve()
103
-
104
- const newComputedStyleSheet = this.getComputedStylesheet(stylesheet)
105
- const newValue = newComputedStyleSheet[key]!
106
- const result = typeof newValue === 'function'
107
- ? newValue(...args)
108
- : newValue
109
- const { variantsResult } = Object.fromEntries(getVariants({ variantsResult: result }, variants))
110
- const resultWithVariants = deepMergeObjects(result, variantsResult ?? {})
111
-
112
- this.applyStyles(hash, convertUnistyles(resultWithVariants))
113
- })
114
-
115
- return hash
90
+ return { hash, existingHash: false }
116
91
  }
117
92
 
118
93
  existingCounter.add(value)
119
94
 
120
- return hash
95
+ return { hash, existingHash: true }
121
96
  }
122
97
 
123
- private applyStyles = (hash: string, styles: Record<string, any>) => {
98
+ applyStyles = (hash: string, styles: Record<string, any>) => {
124
99
  Object.entries(styles).forEach(([key, value]) => {
125
100
  if (!this.styleTag.sheet) {
126
101
  return
@@ -228,6 +203,10 @@ class UnistylesRegistryBuilder {
228
203
  if (existingStyles.size === 0) {
229
204
  const ruleIndex = Array.from(this.styleTag.sheet?.cssRules ?? []).findIndex(rule => rule.cssText.includes(`.${hash}`))
230
205
 
206
+ if (ruleIndex === -1) {
207
+ return
208
+ }
209
+
231
210
  this.styleTag.sheet?.deleteRule(ruleIndex)
232
211
  }
233
212
  }
@@ -54,6 +54,10 @@ class UnistylesRuntimeBuilder {
54
54
  return WebContentSizeCategory.Unspecified
55
55
  }
56
56
 
57
+ get breakpoints() {
58
+ return UnistylesState.breakpoints ?? {}
59
+ }
60
+
57
61
  get breakpoint() {
58
62
  return UnistylesState.breakpoint
59
63
  }
@@ -1,6 +1,8 @@
1
1
  import type { UnistylesValues } from '../types'
2
+ import { convertUnistyles } from './convert'
3
+ import { UnistylesListener } from './listener'
2
4
  import { UnistylesRegistry } from './registry'
3
- import { createDoubleMap, deepMergeObjects, equal, extractSecrets, extractUnistyleDependencies, isInDocument } from './utils'
5
+ import { deepMergeObjects, equal, extractSecrets, extractUnistyleDependencies, isInDocument } from './utils'
4
6
  import { getVariants } from './variants'
5
7
 
6
8
  type Style = UnistylesValues | ((...args: Array<any>) => UnistylesValues)
@@ -14,10 +16,13 @@ class UnistylesShadowRegistryBuilder {
14
16
  dispose = () => {}
15
17
  // END MOCKS
16
18
 
17
- private resultsMap = createDoubleMap<HTMLElement, string, UnistylesValues>()
18
- private classNamesMap = createDoubleMap<HTMLElement, string, Array<string>>()
19
+ private resultsMap = new Map<HTMLElement, UnistylesValues>()
20
+ private hashMap = new Map<HTMLElement, string>()
21
+ private classNamesMap = new Map<HTMLElement, Array<string>>()
22
+ private timeoutMap = new Map<HTMLElement, NodeJS.Timeout>()
23
+ private queuedResultMap = new Map<HTMLElement, Record<string, any>>()
19
24
 
20
- add = (ref: any, _style?: Style | Array<Style>, _variants?: Record<string, any>, _args?: Array<any>) => {
25
+ add = (ref: any, _style?: Style | Array<Style>, _variants?: Record<string, any>, _args?: Array<any>) => new Promise<Array<string>>(resolve => {
21
26
  // Style is not provided
22
27
  if (!_style) {
23
28
  return
@@ -39,15 +44,15 @@ class UnistylesShadowRegistryBuilder {
39
44
  if (ref === null) {
40
45
  const secrets = extractSecrets(_style)
41
46
 
42
- secrets.forEach(({ __uni__refs, __uni__key }) => {
47
+ secrets.forEach(({ __uni__refs }) => {
43
48
  __uni__refs.forEach(ref => {
44
49
  if (isInDocument(ref)) {
45
50
  return
46
51
  }
47
52
 
48
- const oldResult = this.resultsMap.get(ref, __uni__key)
49
- this.resultsMap.delete(ref, __uni__key)
50
- this.classNamesMap.delete(ref, __uni__key)
53
+ const oldResult = this.resultsMap.get(ref)
54
+ this.resultsMap.delete(ref)
55
+ this.classNamesMap.delete(ref)
51
56
 
52
57
  if (oldResult) {
53
58
  UnistylesRegistry.remove(oldResult)
@@ -74,46 +79,80 @@ class UnistylesShadowRegistryBuilder {
74
79
  : style
75
80
  const { variantsResult } = Object.fromEntries(getVariants({ variantsResult: result }, variants))
76
81
  const resultWithVariants = deepMergeObjects(result, variantsResult ?? {})
77
- const oldResult = this.resultsMap.get(ref, __uni__key)
78
-
79
- // If results are the same do nothing
80
- if (equal(oldResult, resultWithVariants)) {
81
- return
82
- }
83
-
84
- const oldClassNames = this.classNamesMap.get(ref, __uni__key)
85
-
86
- // Remove old styles
87
- if (oldResult) {
88
- UnistylesRegistry.remove(oldResult)
89
- }
90
-
91
- // Remove old classnames from the ref
92
- oldClassNames?.forEach(className => ref.classList.remove(className))
93
- this.resultsMap.set(ref, __uni__key, resultWithVariants)
94
-
95
- const className = UnistylesRegistry.add({
96
- key: __uni__key,
97
- args,
98
- stylesheet: __uni__stylesheet,
99
- value: resultWithVariants,
100
- variants
82
+
83
+ // Get stored result from queue
84
+ const storedResult = this.queuedResultMap.get(ref) ?? {}
85
+ // Merge stored result with new result
86
+ const newResult = deepMergeObjects(storedResult, resultWithVariants)
87
+ const timeout = this.timeoutMap.get(ref)
88
+
89
+ // Add callback to the queue and remove old one
90
+ this.queuedResultMap.set(ref, newResult)
91
+ clearTimeout(timeout)
92
+ this.timeoutMap.set(ref, setTimeout(() => {
93
+ const oldResult = this.resultsMap.get(ref)
94
+
95
+ // If results are the same do nothing
96
+ if (equal(oldResult, newResult)) {
97
+ return
98
+ }
99
+
100
+ const oldClassNames = this.classNamesMap.get(ref)
101
+
102
+ // Remove old styles
103
+ if (oldResult) {
104
+ UnistylesRegistry.remove(oldResult)
105
+ }
106
+
107
+ // Remove old classnames from the ref
108
+ oldClassNames?.forEach(className => ref.classList.remove(className))
109
+ this.resultsMap.set(ref, newResult)
110
+
111
+ const { hash, existingHash } = UnistylesRegistry.add(newResult)
112
+ const injectedClassNames: Array<string> = newResult?._web?._classNames ?? []
113
+ const newClassNames = injectedClassNames.concat(hash)
114
+ const dependencies = extractUnistyleDependencies(newResult)
115
+
116
+ if (typeof __uni__stylesheet === 'function') {
117
+ // Add dependencies from dynamic styles to stylesheet
118
+ UnistylesRegistry.addDependenciesToStylesheet(__uni__stylesheet, dependencies)
119
+ }
120
+
121
+ __uni__refs.add(ref)
122
+ this.classNamesMap.set(ref, newClassNames)
123
+ // Add new classnames to the ref
124
+ ref.classList.add(...newClassNames)
125
+ resolve(newClassNames)
126
+
127
+ // If it is new hash add it to the map to use for the listener
128
+ if (!existingHash) {
129
+ this.hashMap.set(ref, hash)
130
+ }
131
+ }, 0))
132
+
133
+ // Listen for theme / runtime changes
134
+ const dispose = UnistylesListener.addListeners(extractUnistyleDependencies(newResult), () => {
135
+ const hash = this.hashMap.get(ref)
136
+
137
+ // Dispose listener if there is no hash
138
+ if (!hash) {
139
+ dispose()
140
+
141
+ return
142
+ }
143
+
144
+ const newComputedStyleSheet = UnistylesRegistry.getComputedStylesheet(__uni__stylesheet)
145
+ const newValue = newComputedStyleSheet[__uni__key]!
146
+ const result = typeof newValue === 'function'
147
+ ? newValue(...args)
148
+ : newValue
149
+ const { variantsResult } = Object.fromEntries(getVariants({ variantsResult: result }, variants))
150
+ const resultWithVariants = deepMergeObjects(result, variantsResult ?? {})
151
+
152
+ UnistylesRegistry.applyStyles(hash, convertUnistyles(resultWithVariants))
101
153
  })
102
- const injectedClassNames: Array<string> = resultWithVariants?._web?._classNames ?? []
103
- const newClassNames = injectedClassNames.concat(className)
104
- const dependencies = extractUnistyleDependencies(resultWithVariants)
105
-
106
- if (typeof __uni__stylesheet === 'function') {
107
- // Add dependencies from dynamic styles to stylesheet
108
- UnistylesRegistry.addDependenciesToStylesheet(__uni__stylesheet, dependencies)
109
- }
110
-
111
- __uni__refs.add(ref)
112
- this.classNamesMap.set(ref, __uni__key, newClassNames)
113
- // Add new classnames to the ref
114
- ref.classList.add(...newClassNames)
115
154
  })
116
- }
155
+ })
117
156
 
118
157
  remove = () => {}
119
158
  }
@@ -68,40 +68,4 @@ export const generateHash = (value: any) => {
68
68
  return `unistyles-${(hasher >>> 0).toString(36)}`
69
69
  }
70
70
 
71
- export const createDoubleMap = <TKey, TSecondKey, TValue>() => {
72
- const map = new Map<TKey, Map<TSecondKey, TValue>>()
73
-
74
- return {
75
- get: (key: TKey, secondKey: TSecondKey) => {
76
- const mapForKey = map.get(key)
77
-
78
- if (!mapForKey) {
79
- return undefined
80
- }
81
-
82
- return mapForKey.get(secondKey)
83
- },
84
- set: (key: TKey, secondKey: TSecondKey, value: TValue) => {
85
- const mapForKey = map.get(key) ?? new Map<TSecondKey, TValue>()
86
-
87
- map.set(key, mapForKey)
88
- mapForKey.set(secondKey, value)
89
- },
90
- delete: (key: TKey, secondKey: TSecondKey) => {
91
- const mapForKey = map.get(key)
92
-
93
- if (!mapForKey) {
94
- return
95
- }
96
-
97
- mapForKey.delete(secondKey)
98
- },
99
- forEach: (callback: (key: TKey, secondKey: TSecondKey, value: TValue) => void) => {
100
- map.forEach((mapForKey, key) => {
101
- mapForKey.forEach((value, secondKey) => {
102
- callback(key, secondKey, value)
103
- })
104
- })
105
- }
106
- }
107
- }
71
+ export const hyphenate = (propertyName: string) => propertyName.replace(/[A-Z]/g, (m: string) => `-${m.toLowerCase()}`)
@@ -98,7 +98,11 @@ export const getMediaQuery = (query: string) => {
98
98
  }
99
99
 
100
100
  export const extractUnistyleDependencies = (value: any) => {
101
+ if (!value) {
102
+ return []
103
+ }
104
+
101
105
  const dependencies: Array<UnistyleDependency> = keyInObject(value, 'uni__dependencies') ? value.uni__dependencies : []
102
106
 
103
- return dependencies
107
+ return Array.isArray(dependencies) ? dependencies : []
104
108
  }