@hanzogui/web 7.3.2 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (347) hide show
  1. package/.turbo/turbo-build.log +2 -0
  2. package/dist/cjs/_withStableStyle.cjs +2 -2
  3. package/dist/cjs/_withStableStyle.native.js +2 -2
  4. package/dist/cjs/_withStableStyle.native.js.map +1 -1
  5. package/dist/cjs/config.cjs +18 -10
  6. package/dist/cjs/config.native.js +19 -10
  7. package/dist/cjs/config.native.js.map +1 -1
  8. package/dist/cjs/constants/constants.cjs +1 -1
  9. package/dist/cjs/constants/constants.native.js +1 -1
  10. package/dist/cjs/constants/constants.native.js.map +1 -1
  11. package/dist/cjs/createComponent.cjs +68 -28
  12. package/dist/cjs/createComponent.native.js +75 -30
  13. package/dist/cjs/createComponent.native.js.map +1 -1
  14. package/dist/cjs/createGui.cjs +1 -1
  15. package/dist/cjs/createGui.native.js +1 -1
  16. package/dist/cjs/createGui.native.js.map +1 -1
  17. package/dist/cjs/eventHandling.cjs +2 -2
  18. package/dist/cjs/eventHandling.native.js +73 -54
  19. package/dist/cjs/eventHandling.native.js.map +1 -1
  20. package/dist/cjs/helpers/createDesignSystem.cjs +2 -2
  21. package/dist/cjs/helpers/defaultAnimationDriver.cjs +1 -1
  22. package/dist/cjs/helpers/defaultAnimationDriver.native.js +1 -1
  23. package/dist/cjs/helpers/expandStyle.cjs +46 -5
  24. package/dist/cjs/helpers/expandStyle.native.js +36 -30
  25. package/dist/cjs/helpers/expandStyle.native.js.map +1 -1
  26. package/dist/cjs/helpers/getGroupPropParts.cjs +1 -1
  27. package/dist/cjs/helpers/getGroupPropParts.native.js +1 -1
  28. package/dist/cjs/helpers/getSplitStyles.cjs +76 -31
  29. package/dist/cjs/helpers/getSplitStyles.native.js +140 -85
  30. package/dist/cjs/helpers/getSplitStyles.native.js.map +1 -1
  31. package/dist/cjs/helpers/getTokenForKey.cjs +5 -5
  32. package/dist/cjs/helpers/getTokenForKey.native.js +5 -5
  33. package/dist/cjs/helpers/getTokenForKey.native.js.map +1 -1
  34. package/dist/cjs/helpers/getVariantExtras.cjs +7 -3
  35. package/dist/cjs/helpers/getVariantExtras.native.js +7 -3
  36. package/dist/cjs/helpers/getVariantExtras.native.js.map +1 -1
  37. package/dist/cjs/helpers/insertStyleRule.cjs +4 -4
  38. package/dist/cjs/helpers/insertStyleRule.native.js +3 -3
  39. package/dist/cjs/helpers/insertStyleRule.native.js.map +1 -1
  40. package/dist/cjs/helpers/mainThreadPressEvents.native.js +32 -4
  41. package/dist/cjs/helpers/mainThreadPressEvents.native.js.map +1 -1
  42. package/dist/cjs/helpers/normalizeStyle.cjs +22 -1
  43. package/dist/cjs/helpers/normalizeStyle.native.js +41 -1
  44. package/dist/cjs/helpers/normalizeStyle.native.js.map +1 -1
  45. package/dist/cjs/helpers/platformResolveValue.cjs +1 -1
  46. package/dist/cjs/helpers/platformResolveValue.native.js +1 -1
  47. package/dist/cjs/helpers/platformResolveValue.native.js.map +1 -1
  48. package/dist/cjs/helpers/pointerEvents.native.js +26 -20
  49. package/dist/cjs/helpers/pointerEvents.native.js.map +1 -1
  50. package/dist/cjs/helpers/propMapper.cjs +31 -7
  51. package/dist/cjs/helpers/propMapper.native.js +70 -20
  52. package/dist/cjs/helpers/propMapper.native.js.map +1 -1
  53. package/dist/cjs/helpers/resolveSafeArea.native.js +1 -1
  54. package/dist/cjs/helpers/resolveSafeArea.native.js.map +1 -1
  55. package/dist/cjs/helpers/styleOriginalValues.cjs +28 -0
  56. package/dist/cjs/helpers/styleOriginalValues.native.js +31 -0
  57. package/dist/cjs/helpers/styleOriginalValues.native.js.map +1 -0
  58. package/dist/cjs/helpers/styleProvenance.cjs +43 -0
  59. package/dist/cjs/helpers/styleProvenance.native.js +46 -0
  60. package/dist/cjs/helpers/styleProvenance.native.js.map +1 -0
  61. package/dist/cjs/helpers/wrapStyleTags.cjs +35 -11
  62. package/dist/cjs/helpers/wrapStyleTags.native.js.map +1 -1
  63. package/dist/cjs/hooks/getThemeProxied.cjs +1 -1
  64. package/dist/cjs/hooks/getThemeProxied.native.js +4 -4
  65. package/dist/cjs/hooks/getThemeProxied.native.js.map +1 -1
  66. package/dist/cjs/hooks/useComponentState.cjs +29 -3
  67. package/dist/cjs/hooks/useComponentState.native.js +30 -4
  68. package/dist/cjs/hooks/useComponentState.native.js.map +1 -1
  69. package/dist/cjs/hooks/useMedia.cjs +107 -42
  70. package/dist/cjs/hooks/useMedia.native.js +149 -60
  71. package/dist/cjs/hooks/useMedia.native.js.map +1 -1
  72. package/dist/cjs/hooks/useTheme.cjs +18 -5
  73. package/dist/cjs/hooks/useTheme.native.js +19 -5
  74. package/dist/cjs/hooks/useTheme.native.js.map +1 -1
  75. package/dist/cjs/hooks/useThemeState.cjs +143 -72
  76. package/dist/cjs/hooks/useThemeState.native.js +155 -74
  77. package/dist/cjs/hooks/useThemeState.native.js.map +1 -1
  78. package/dist/cjs/index.cjs +3 -0
  79. package/dist/cjs/index.native.js +3 -0
  80. package/dist/cjs/index.native.js.map +1 -1
  81. package/dist/cjs/opacityModifier.test-d.cjs +36 -0
  82. package/dist/cjs/opacityModifier.test-d.native.js +39 -0
  83. package/dist/cjs/opacityModifier.test-d.native.js.map +1 -0
  84. package/dist/cjs/styledNonStyleProps.test-d.cjs +63 -0
  85. package/dist/cjs/styledNonStyleProps.test-d.native.js +66 -0
  86. package/dist/cjs/styledNonStyleProps.test-d.native.js.map +1 -0
  87. package/dist/cjs/views/GuiProvider.cjs +2 -2
  88. package/dist/cjs/views/Text.cjs +1 -0
  89. package/dist/cjs/views/Text.native.js +1 -0
  90. package/dist/cjs/views/Text.native.js.map +1 -1
  91. package/dist/cjs/views/Theme.cjs +1 -1
  92. package/dist/cjs/views/Theme.native.js +1 -1
  93. package/dist/cjs/views/Theme.native.js.map +1 -1
  94. package/dist/esm/_withStableStyle.mjs +2 -2
  95. package/dist/esm/_withStableStyle.mjs.map +1 -1
  96. package/dist/esm/_withStableStyle.native.js +2 -2
  97. package/dist/esm/_withStableStyle.native.js.map +1 -1
  98. package/dist/esm/config.mjs +18 -11
  99. package/dist/esm/config.mjs.map +1 -1
  100. package/dist/esm/config.native.js +19 -11
  101. package/dist/esm/config.native.js.map +1 -1
  102. package/dist/esm/constants/constants.mjs +1 -1
  103. package/dist/esm/constants/constants.native.js +1 -1
  104. package/dist/esm/constants/constants.native.js.map +1 -1
  105. package/dist/esm/createComponent.mjs +74 -35
  106. package/dist/esm/createComponent.mjs.map +1 -1
  107. package/dist/esm/createComponent.native.js +90 -42
  108. package/dist/esm/createComponent.native.js.map +1 -1
  109. package/dist/esm/createGui.mjs +6 -6
  110. package/dist/esm/createGui.mjs.map +1 -1
  111. package/dist/esm/createGui.native.js +6 -6
  112. package/dist/esm/createGui.native.js.map +1 -1
  113. package/dist/esm/eventHandling.mjs +2 -2
  114. package/dist/esm/eventHandling.mjs.map +1 -1
  115. package/dist/esm/eventHandling.native.js +74 -55
  116. package/dist/esm/eventHandling.native.js.map +1 -1
  117. package/dist/esm/helpers/createDesignSystem.mjs +2 -2
  118. package/dist/esm/helpers/createDesignSystem.mjs.map +1 -1
  119. package/dist/esm/helpers/createDesignSystem.native.js +1 -2
  120. package/dist/esm/helpers/createDesignSystem.native.js.map +1 -1
  121. package/dist/esm/helpers/defaultAnimationDriver.mjs +1 -1
  122. package/dist/esm/helpers/defaultAnimationDriver.mjs.map +1 -1
  123. package/dist/esm/helpers/defaultAnimationDriver.native.js +1 -1
  124. package/dist/esm/helpers/expandStyle.mjs +47 -8
  125. package/dist/esm/helpers/expandStyle.mjs.map +1 -1
  126. package/dist/esm/helpers/expandStyle.native.js +36 -30
  127. package/dist/esm/helpers/expandStyle.native.js.map +1 -1
  128. package/dist/esm/helpers/expandStyles.mjs.map +1 -1
  129. package/dist/esm/helpers/expandStyles.native.js.map +1 -1
  130. package/dist/esm/helpers/getGroupPropParts.mjs +1 -1
  131. package/dist/esm/helpers/getGroupPropParts.mjs.map +1 -1
  132. package/dist/esm/helpers/getGroupPropParts.native.js +1 -1
  133. package/dist/esm/helpers/getSplitStyles.mjs +86 -45
  134. package/dist/esm/helpers/getSplitStyles.mjs.map +1 -1
  135. package/dist/esm/helpers/getSplitStyles.native.js +146 -98
  136. package/dist/esm/helpers/getSplitStyles.native.js.map +1 -1
  137. package/dist/esm/helpers/getThemeCSSRules.mjs +1 -1
  138. package/dist/esm/helpers/getThemeCSSRules.mjs.map +1 -1
  139. package/dist/esm/helpers/getTokenForKey.mjs +5 -5
  140. package/dist/esm/helpers/getTokenForKey.mjs.map +1 -1
  141. package/dist/esm/helpers/getTokenForKey.native.js +5 -5
  142. package/dist/esm/helpers/getTokenForKey.native.js.map +1 -1
  143. package/dist/esm/helpers/getVariantExtras.mjs +7 -3
  144. package/dist/esm/helpers/getVariantExtras.mjs.map +1 -1
  145. package/dist/esm/helpers/getVariantExtras.native.js +7 -3
  146. package/dist/esm/helpers/getVariantExtras.native.js.map +1 -1
  147. package/dist/esm/helpers/insertStyleRule.mjs +4 -6
  148. package/dist/esm/helpers/insertStyleRule.mjs.map +1 -1
  149. package/dist/esm/helpers/insertStyleRule.native.js +0 -26
  150. package/dist/esm/helpers/insertStyleRule.native.js.map +1 -1
  151. package/dist/esm/helpers/isActivePlatform.mjs.map +1 -1
  152. package/dist/esm/helpers/isActivePlatform.native.js.map +1 -1
  153. package/dist/esm/helpers/log.mjs.map +1 -1
  154. package/dist/esm/helpers/log.native.js.map +1 -1
  155. package/dist/esm/helpers/mainThreadPressEvents.native.js +32 -4
  156. package/dist/esm/helpers/mainThreadPressEvents.native.js.map +1 -1
  157. package/dist/esm/helpers/normalizeStyle.mjs +22 -1
  158. package/dist/esm/helpers/normalizeStyle.mjs.map +1 -1
  159. package/dist/esm/helpers/normalizeStyle.native.js +41 -1
  160. package/dist/esm/helpers/normalizeStyle.native.js.map +1 -1
  161. package/dist/esm/helpers/platformResolveValue.mjs +1 -1
  162. package/dist/esm/helpers/platformResolveValue.mjs.map +1 -1
  163. package/dist/esm/helpers/platformResolveValue.native.js +1 -1
  164. package/dist/esm/helpers/platformResolveValue.native.js.map +1 -1
  165. package/dist/esm/helpers/pointerEvents.native.js +26 -20
  166. package/dist/esm/helpers/pointerEvents.native.js.map +1 -1
  167. package/dist/esm/helpers/propMapper.mjs +32 -11
  168. package/dist/esm/helpers/propMapper.mjs.map +1 -1
  169. package/dist/esm/helpers/propMapper.native.js +71 -22
  170. package/dist/esm/helpers/propMapper.native.js.map +1 -1
  171. package/dist/esm/helpers/resolveSafeArea.native.js +1 -1
  172. package/dist/esm/helpers/resolveSafeArea.native.js.map +1 -1
  173. package/dist/esm/helpers/skipProps.mjs +0 -1
  174. package/dist/esm/helpers/skipProps.mjs.map +1 -1
  175. package/dist/esm/helpers/skipProps.native.js +0 -1
  176. package/dist/esm/helpers/skipProps.native.js.map +1 -1
  177. package/dist/esm/helpers/styleOriginalValues.mjs +3 -0
  178. package/dist/esm/helpers/styleOriginalValues.mjs.map +1 -0
  179. package/dist/esm/helpers/styleOriginalValues.native.js +3 -0
  180. package/dist/esm/helpers/styleOriginalValues.native.js.map +1 -0
  181. package/dist/esm/helpers/styleProvenance.mjs +16 -0
  182. package/dist/esm/helpers/styleProvenance.mjs.map +1 -0
  183. package/dist/esm/helpers/styleProvenance.native.js +16 -0
  184. package/dist/esm/helpers/styleProvenance.native.js.map +1 -0
  185. package/dist/esm/helpers/useRenderElement.mjs.map +1 -1
  186. package/dist/esm/helpers/useRenderElement.native.js.map +1 -1
  187. package/dist/esm/helpers/wrapStyleTags.mjs +35 -11
  188. package/dist/esm/helpers/wrapStyleTags.mjs.map +1 -1
  189. package/dist/esm/helpers/wrapStyleTags.native.js +0 -2
  190. package/dist/esm/helpers/wrapStyleTags.native.js.map +1 -1
  191. package/dist/esm/hooks/getThemeProxied.mjs +2 -5
  192. package/dist/esm/hooks/getThemeProxied.mjs.map +1 -1
  193. package/dist/esm/hooks/getThemeProxied.native.js +5 -5
  194. package/dist/esm/hooks/getThemeProxied.native.js.map +1 -1
  195. package/dist/esm/hooks/useComponentState.mjs +31 -5
  196. package/dist/esm/hooks/useComponentState.mjs.map +1 -1
  197. package/dist/esm/hooks/useComponentState.native.js +32 -6
  198. package/dist/esm/hooks/useComponentState.native.js.map +1 -1
  199. package/dist/esm/hooks/useMedia.mjs +108 -43
  200. package/dist/esm/hooks/useMedia.mjs.map +1 -1
  201. package/dist/esm/hooks/useMedia.native.js +150 -61
  202. package/dist/esm/hooks/useMedia.native.js.map +1 -1
  203. package/dist/esm/hooks/useTheme.mjs +18 -5
  204. package/dist/esm/hooks/useTheme.mjs.map +1 -1
  205. package/dist/esm/hooks/useTheme.native.js +19 -5
  206. package/dist/esm/hooks/useTheme.native.js.map +1 -1
  207. package/dist/esm/hooks/useThemeState.mjs +141 -70
  208. package/dist/esm/hooks/useThemeState.mjs.map +1 -1
  209. package/dist/esm/hooks/useThemeState.native.js +154 -73
  210. package/dist/esm/hooks/useThemeState.native.js.map +1 -1
  211. package/dist/esm/index.js +4 -4
  212. package/dist/esm/index.js.map +1 -1
  213. package/dist/esm/index.mjs +4 -4
  214. package/dist/esm/index.mjs.map +1 -1
  215. package/dist/esm/index.native.js +4 -4
  216. package/dist/esm/index.native.js.map +1 -1
  217. package/dist/esm/insertFont.mjs.map +1 -1
  218. package/dist/esm/insertFont.native.js +0 -1
  219. package/dist/esm/insertFont.native.js.map +1 -1
  220. package/dist/esm/opacityModifier.test-d.mjs +37 -0
  221. package/dist/esm/opacityModifier.test-d.mjs.map +1 -0
  222. package/dist/esm/opacityModifier.test-d.native.js +37 -0
  223. package/dist/esm/opacityModifier.test-d.native.js.map +1 -0
  224. package/dist/esm/styledNonStyleProps.test-d.mjs +64 -0
  225. package/dist/esm/styledNonStyleProps.test-d.mjs.map +1 -0
  226. package/dist/esm/styledNonStyleProps.test-d.native.js +64 -0
  227. package/dist/esm/styledNonStyleProps.test-d.native.js.map +1 -0
  228. package/dist/esm/views/GuiProvider.mjs +2 -2
  229. package/dist/esm/views/GuiProvider.mjs.map +1 -1
  230. package/dist/esm/views/GuiProvider.native.js +6 -6
  231. package/dist/esm/views/GuiProvider.native.js.map +1 -1
  232. package/dist/esm/views/Text.mjs +1 -0
  233. package/dist/esm/views/Text.mjs.map +1 -1
  234. package/dist/esm/views/Text.native.js +1 -0
  235. package/dist/esm/views/Text.native.js.map +1 -1
  236. package/dist/esm/views/Theme.mjs +1 -1
  237. package/dist/esm/views/Theme.mjs.map +1 -1
  238. package/dist/esm/views/Theme.native.js +1 -1
  239. package/dist/esm/views/Theme.native.js.map +1 -1
  240. package/dist/esm/views/ThemeProvider.mjs.map +1 -1
  241. package/dist/esm/views/ThemeProvider.native.js +2 -4
  242. package/dist/esm/views/ThemeProvider.native.js.map +1 -1
  243. package/inject-styles/index.cjs +2 -0
  244. package/inject-styles/index.js +2 -0
  245. package/package.json +27 -40
  246. package/src/_withStableStyle.tsx +9 -3
  247. package/src/config.ts +24 -14
  248. package/src/constants/accessibilityDirectMap.tsx +1 -1
  249. package/src/constants/constants.ts +1 -1
  250. package/src/createComponent.tsx +161 -26
  251. package/src/createGui.ts +2 -2
  252. package/src/eventHandling.native.ts +143 -52
  253. package/src/eventHandling.ts +4 -2
  254. package/src/helpers/createDesignSystem.ts +2 -2
  255. package/src/helpers/createMediaStyle.ts +1 -1
  256. package/src/helpers/defaultAnimationDriver.tsx +1 -1
  257. package/src/helpers/expandStyle.ts +108 -40
  258. package/src/helpers/getGroupPropParts.ts +1 -1
  259. package/src/helpers/getSplitStyles.tsx +178 -72
  260. package/src/helpers/getTokenForKey.ts +5 -5
  261. package/src/helpers/getVariantExtras.tsx +5 -4
  262. package/src/helpers/insertStyleRule.tsx +7 -7
  263. package/src/helpers/mainThreadPressEvents.native.ts +42 -2
  264. package/src/helpers/mergeProps.ts +1 -1
  265. package/src/helpers/normalizeStyle.ts +23 -1
  266. package/src/helpers/platformResolveValue.native.ts +4 -1
  267. package/src/helpers/platformResolveValue.ts +5 -1
  268. package/src/helpers/pointerEvents.native.ts +26 -19
  269. package/src/helpers/propMapper.ts +61 -6
  270. package/src/helpers/resolveSafeArea.native.ts +1 -1
  271. package/src/helpers/styleOriginalValues.ts +2 -0
  272. package/src/helpers/styleProvenance.ts +49 -0
  273. package/src/helpers/wrapStyleTags.tsx +63 -20
  274. package/src/hooks/getThemeProxied.ts +14 -8
  275. package/src/hooks/useComponentState.ts +56 -4
  276. package/src/hooks/useMedia.tsx +156 -43
  277. package/src/hooks/useTheme.tsx +28 -6
  278. package/src/hooks/useThemeState.ts +284 -142
  279. package/src/index.ts +9 -1
  280. package/src/interfaces/GuiComponentPropsBaseBase.tsx +2 -2
  281. package/src/opacityModifier.test-d.ts +65 -0
  282. package/src/styled.tsx +1 -1
  283. package/src/styledNonStyleProps.test-d.ts +106 -0
  284. package/src/types.tsx +120 -22
  285. package/src/views/GuiProvider.tsx +2 -2
  286. package/src/views/Text.tsx +1 -0
  287. package/src/views/Theme.tsx +4 -1
  288. package/tsconfig.json +44 -0
  289. package/tsconfig.test.json +9 -0
  290. package/types/_withStableStyle.d.ts.map +1 -1
  291. package/types/config.d.ts +3 -1
  292. package/types/config.d.ts.map +1 -1
  293. package/types/constants/constants.d.ts +1 -1
  294. package/types/constants/constants.d.ts.map +1 -1
  295. package/types/createComponent.d.ts.map +1 -1
  296. package/types/eventHandling.d.ts +2 -2
  297. package/types/eventHandling.d.ts.map +1 -1
  298. package/types/eventHandling.native.d.ts +3 -3
  299. package/types/eventHandling.native.d.ts.map +1 -1
  300. package/types/helpers/expandStyle.d.ts +2 -1
  301. package/types/helpers/expandStyle.d.ts.map +1 -1
  302. package/types/helpers/getSplitStyles.d.ts +4 -2
  303. package/types/helpers/getSplitStyles.d.ts.map +1 -1
  304. package/types/helpers/getVariantExtras.d.ts.map +1 -1
  305. package/types/helpers/mainThreadPressEvents.native.d.ts.map +1 -1
  306. package/types/helpers/normalizeStyle.d.ts.map +1 -1
  307. package/types/helpers/platformResolveValue.d.ts.map +1 -1
  308. package/types/helpers/platformResolveValue.native.d.ts.map +1 -1
  309. package/types/helpers/pointerEvents.native.d.ts.map +1 -1
  310. package/types/helpers/propMapper.d.ts.map +1 -1
  311. package/types/helpers/styleOriginalValues.d.ts +2 -0
  312. package/types/helpers/styleOriginalValues.d.ts.map +1 -0
  313. package/types/helpers/styleProvenance.d.ts +11 -0
  314. package/types/helpers/styleProvenance.d.ts.map +1 -0
  315. package/types/helpers/wrapStyleTags.d.ts +1 -1
  316. package/types/helpers/wrapStyleTags.d.ts.map +1 -1
  317. package/types/hooks/getThemeProxied.d.ts.map +1 -1
  318. package/types/hooks/useComponentState.d.ts +2 -1
  319. package/types/hooks/useComponentState.d.ts.map +1 -1
  320. package/types/hooks/useMedia.d.ts.map +1 -1
  321. package/types/hooks/useTheme.d.ts +1 -1
  322. package/types/hooks/useTheme.d.ts.map +1 -1
  323. package/types/hooks/useThemeState.d.ts +1 -1
  324. package/types/hooks/useThemeState.d.ts.map +1 -1
  325. package/types/index.d.ts +3 -3
  326. package/types/index.d.ts.map +1 -1
  327. package/types/interfaces/GuiComponentPropsBaseBase.d.ts +2 -2
  328. package/types/types.d.ts +33 -16
  329. package/types/types.d.ts.map +1 -1
  330. package/types/views/Configuration.d.ts +1 -1
  331. package/types/views/Configuration.d.ts.map +1 -1
  332. package/types/views/FontLanguage.d.ts +1 -1
  333. package/types/views/FontLanguage.native.d.ts +1 -2
  334. package/types/views/FontLanguage.native.d.ts.map +1 -1
  335. package/types/views/GuiProvider.d.ts +1 -2
  336. package/types/views/GuiProvider.d.ts.map +1 -1
  337. package/types/views/GuiRoot.d.ts +1 -1
  338. package/types/views/GuiRoot.d.ts.map +1 -1
  339. package/types/views/Slot.d.ts +1 -1
  340. package/types/views/Text.d.ts.map +1 -1
  341. package/types/views/Theme.d.ts.map +1 -1
  342. package/types/views/ThemeProvider.d.ts +1 -1
  343. package/types/views/ThemeProvider.d.ts.map +1 -1
  344. package/vitest.config.d.ts +3 -0
  345. package/vitest.config.d.ts.map +1 -0
  346. package/vitest.config.ts +14 -0
  347. package/LICENSE +0 -42
@@ -2,7 +2,10 @@ import type { GetStyleState, SplitStyleProps } from '../types'
2
2
  import { getTokenForKey } from './getTokenForKey'
3
3
  import { parseNativeStyle } from './parseNativeStyle'
4
4
 
5
- const tokenPattern = /(\$[\w.-]+)/g
5
+ // includes the optional `/NN` opacity-modifier suffix ($color9/50) so
6
+ // getTokenForKey receives it and can apply the alpha — without it the token
7
+ // resolves but the bare `/50` is left behind in the parsed gradient string
8
+ const tokenPattern = /(\$[\w.-]+(?:\/[\d.]+)?)/g
6
9
 
7
10
  // keys that need native object parsing (DynamicColorIOS support)
8
11
  const nativeParseKeys: Record<string, boolean> = {
@@ -1,7 +1,11 @@
1
1
  import type { GetStyleState, SplitStyleProps } from '../types'
2
2
  import { getTokenForKey } from './getTokenForKey'
3
3
 
4
- const tokenPattern = /(\$[\w.-]+)/g
4
+ // includes the optional `/NN` opacity-modifier suffix ($color9/50) so
5
+ // getTokenForKey receives it and can apply the alpha — without it the token
6
+ // resolves but the bare `/50` is left behind in the CSS string, which makes
7
+ // the whole declaration invalid
8
+ const tokenPattern = /(\$[\w.-]+(?:\/[\d.]+)?)/g
5
9
 
6
10
  /**
7
11
  * web: resolves embedded $tokens in compound CSS strings via simple regex replacement.
@@ -25,13 +25,20 @@ export function usePointerEvents(props: any, viewProps: any) {
25
25
  onPointerEnter ||
26
26
  onPointerLeave
27
27
 
28
- // track if pointer is currently inside bounds (for enter/leave)
29
- const isInsideRef = useRef(false)
30
- const layoutRef = useRef({ width: 0, height: 0 })
31
- // track if pointer is captured (for move events outside bounds)
32
- const isCapturedRef = useRef(false)
28
+ // single ref-bag (was three separate useRef slots) one hook slot per
29
+ // component instead of three. isInside = pointer within bounds (enter/leave),
30
+ // layout = measured bounds, isCaptured = setPointerCapture state for moves.
31
+ const ref = useRef<{
32
+ isInside: boolean
33
+ layout: { width: number; height: number }
34
+ isCaptured: boolean
35
+ } | null>(null)
36
+ if (!ref.current) {
37
+ ref.current = { isInside: false, layout: { width: 0, height: 0 }, isCaptured: false }
38
+ }
33
39
 
34
40
  if (!hasPointerEvents) return
41
+ const bag = ref.current
35
42
 
36
43
  // create normalized event with setPointerCapture support
37
44
  const createNormalizedEvent = (e: any) => {
@@ -49,10 +56,10 @@ export function usePointerEvents(props: any, viewProps: any) {
49
56
  nativeEvent: touch,
50
57
  target: {
51
58
  setPointerCapture: (_pointerId: number) => {
52
- isCapturedRef.current = true
59
+ bag.isCaptured = true
53
60
  },
54
61
  releasePointerCapture: (_pointerId: number) => {
55
- isCapturedRef.current = false
62
+ bag.isCaptured = false
56
63
  },
57
64
  },
58
65
  }
@@ -69,7 +76,7 @@ export function usePointerEvents(props: any, viewProps: any) {
69
76
  // pointer up
70
77
  if (onPointerUp) {
71
78
  viewProps.onTouchEnd = composeEventHandlers(viewProps.onTouchEnd, (e: any) => {
72
- isCapturedRef.current = false // auto-release on up
79
+ bag.isCaptured = false // auto-release on up
73
80
  onPointerUp(createNormalizedEvent(e))
74
81
  })
75
82
  }
@@ -78,12 +85,12 @@ export function usePointerEvents(props: any, viewProps: any) {
78
85
  if (onPointerMove) {
79
86
  viewProps.onTouchMove = composeEventHandlers(viewProps.onTouchMove, (e: any) => {
80
87
  const { locationX, locationY } = e.nativeEvent
81
- const { width, height } = layoutRef.current
88
+ const { width, height } = bag.layout
82
89
  const isInBounds =
83
90
  locationX >= 0 && locationX <= width && locationY >= 0 && locationY <= height
84
91
 
85
92
  // fire if captured OR in bounds (matches web behavior)
86
- if (isCapturedRef.current || isInBounds) {
93
+ if (bag.isCaptured || isInBounds) {
87
94
  onPointerMove(createNormalizedEvent(e))
88
95
  }
89
96
  })
@@ -92,7 +99,7 @@ export function usePointerEvents(props: any, viewProps: any) {
92
99
  // pointer cancel
93
100
  if (onPointerCancel) {
94
101
  viewProps.onTouchCancel = composeEventHandlers(viewProps.onTouchCancel, (e: any) => {
95
- isCapturedRef.current = false
102
+ bag.isCaptured = false
96
103
  onPointerCancel(createNormalizedEvent(e))
97
104
  })
98
105
  }
@@ -101,7 +108,7 @@ export function usePointerEvents(props: any, viewProps: any) {
101
108
  if (onPointerEnter || onPointerLeave || onPointerMove) {
102
109
  // track layout for bounds checking
103
110
  viewProps.onLayout = composeEventHandlers(viewProps.onLayout, (e: any) => {
104
- layoutRef.current = {
111
+ bag.layout = {
105
112
  width: e.nativeEvent.layout.width,
106
113
  height: e.nativeEvent.layout.height,
107
114
  }
@@ -112,9 +119,9 @@ export function usePointerEvents(props: any, viewProps: any) {
112
119
  if (onPointerEnter) {
113
120
  viewProps.onTouchStart = composeEventHandlers(viewProps.onTouchStart, (e: any) => {
114
121
  const { locationX, locationY } = e.nativeEvent
115
- const { width, height } = layoutRef.current
122
+ const { width, height } = bag.layout
116
123
  if (locationX >= 0 && locationX <= width && locationY >= 0 && locationY <= height) {
117
- isInsideRef.current = true
124
+ bag.isInside = true
118
125
  onPointerEnter(createNormalizedEvent(e))
119
126
  }
120
127
  })
@@ -124,18 +131,18 @@ export function usePointerEvents(props: any, viewProps: any) {
124
131
  if (onPointerLeave) {
125
132
  viewProps.onTouchMove = composeEventHandlers(viewProps.onTouchMove, (e: any) => {
126
133
  const { locationX, locationY } = e.nativeEvent
127
- const { width, height } = layoutRef.current
134
+ const { width, height } = bag.layout
128
135
  const isInside =
129
136
  locationX >= 0 && locationX <= width && locationY >= 0 && locationY <= height
130
- if (isInsideRef.current && !isInside) {
131
- isInsideRef.current = false
137
+ if (bag.isInside && !isInside) {
138
+ bag.isInside = false
132
139
  onPointerLeave(createNormalizedEvent(e))
133
140
  }
134
141
  })
135
142
 
136
143
  viewProps.onTouchEnd = composeEventHandlers(viewProps.onTouchEnd, (e: any) => {
137
- if (isInsideRef.current) {
138
- isInsideRef.current = false
144
+ if (bag.isInside) {
145
+ bag.isInside = false
139
146
  onPointerLeave(createNormalizedEvent(e))
140
147
  }
141
148
  })
@@ -24,6 +24,7 @@ import { pseudoDescriptors } from './pseudoDescriptors'
24
24
  import { resolveCompoundTokens } from './resolveCompoundTokens'
25
25
  import { isRemValue, resolveRem } from './resolveRem'
26
26
  import { skipProps } from './skipProps'
27
+ import { styleOriginalValues } from './styleOriginalValues'
27
28
 
28
29
  export { getTokenForKey } from './getTokenForKey'
29
30
 
@@ -42,11 +43,36 @@ export const propMapper: PropMapper = (key, value, styleState, disabled, map) =>
42
43
  const { conf, styleProps, staticConfig } = styleState
43
44
  const { variants } = staticConfig
44
45
 
46
+ // "unset" is a CSS-wide keyword: valid CSS on web, but React Native
47
+ // style props reject it (e.g. aspectRatio throws "must be a number, a
48
+ // ratio string or `auto`"). On native, clear anything an earlier prop or
49
+ // styled default already merged for this key — matching web, where unset
50
+ // resets toward initial — then drop the value so RN never sees it.
51
+ if (process.env.GUI_TARGET === 'native' && value === 'unset') {
52
+ const expandedKey =
53
+ (!styleProps.disableExpandShorthands && conf.shorthands[key]) || key
54
+ const expanded = styleProps.noExpand
55
+ ? null
56
+ : expandStyle(expandedKey, value, conf.settings.styleCompat || 'web')
57
+ if (styleState.style) {
58
+ if (expanded) {
59
+ for (const [nkey] of expanded) {
60
+ delete styleState.style[nkey]
61
+ }
62
+ } else {
63
+ delete styleState.style[expandedKey]
64
+ }
65
+ }
66
+ return
67
+ }
68
+
45
69
  if (!styleProps.noExpand) {
46
70
  if (variants && key in variants) {
47
71
  const variantValue = resolveVariants(key, value, styleProps, styleState, '')
48
72
  if (variantValue) {
49
- variantValue.forEach(([key, value]) => map(key, value))
73
+ variantValue.forEach(([key, value, originalValue]) => {
74
+ map(key, value, originalValue)
75
+ })
50
76
  return
51
77
  }
52
78
  }
@@ -105,13 +131,15 @@ export const propMapper: PropMapper = (key, value, styleState, disabled, map) =>
105
131
  styleState.fontFamily = fontToken
106
132
  }
107
133
 
108
- const expanded = styleProps.noExpand ? null : expandStyle(key, value)
134
+ const expanded = styleProps.noExpand
135
+ ? null
136
+ : expandStyle(key, value, conf.settings.styleCompat || 'web')
109
137
 
110
138
  if (expanded) {
111
139
  const max = expanded.length
112
140
  for (let i = 0; i < max; i++) {
113
- const [nkey, nvalue] = expanded[i]
114
- map(nkey, nvalue, originalValue)
141
+ const [nkey, nvalue, noriginalValue] = expanded[i]
142
+ map(nkey, nvalue, noriginalValue ?? originalValue)
115
143
  }
116
144
  } else {
117
145
  map(key, value, originalValue)
@@ -205,13 +233,14 @@ const resolveVariants: StyleResolver = (
205
233
  console.info(` expanding styles from `, variantValue, `to`, expanded)
206
234
  }
207
235
  const next = Object.entries(expanded)
236
+ const originalValues = styleOriginalValues.get(expanded)
208
237
 
209
238
  // store any changed font family (only support variables for now)
210
239
  if (fontFamilyResult && fontFamilyResult[0] === '$') {
211
240
  setLastFontFamilyToken(getVariableValue(fontFamilyResult))
212
241
  }
213
242
 
214
- return next
243
+ return next.map(([key, value]) => [key, value, originalValues?.[key]])
215
244
  }
216
245
  }
217
246
 
@@ -249,6 +278,7 @@ const resolveTokensAndVariants: StyleResolver<object> = (
249
278
  const { conf, staticConfig, debug, theme } = styleState
250
279
  const { variants } = staticConfig
251
280
  const res = {}
281
+ let originalValues: Record<string, any> | undefined
252
282
 
253
283
  if (process.env.NODE_ENV === 'development' && debug === 'verbose') {
254
284
  console.info(` - resolveTokensAndVariants`, key, value)
@@ -262,6 +292,9 @@ const resolveTokensAndVariants: StyleResolver<object> = (
262
292
  continue
263
293
  }
264
294
 
295
+ originalValues ||= {}
296
+ originalValues[subKey] = val
297
+
265
298
  // Track context overrides for any key that's in context props (issues #3670, #3676)
266
299
  // Store the ORIGINAL token value (like '$8') before resolution so that
267
300
  // children's functional variants can look up token values
@@ -291,13 +324,24 @@ const resolveTokensAndVariants: StyleResolver<object> = (
291
324
 
292
325
  // apply, merging sub-styles
293
326
  if (variantOut) {
294
- for (const [key, val] of variantOut) {
327
+ for (const [key, val, originalVal] of variantOut) {
295
328
  if (val == null) continue
296
329
  if (key in pseudoDescriptors) {
297
330
  res[key] ??= {}
298
331
  Object.assign(res[key], val)
332
+ const subOriginalValues = styleOriginalValues.get(val)
333
+ if (subOriginalValues) {
334
+ styleOriginalValues.set(res[key], {
335
+ ...styleOriginalValues.get(res[key]),
336
+ ...subOriginalValues,
337
+ })
338
+ }
299
339
  } else {
300
340
  res[key] = val
341
+ if (originalVal !== undefined) {
342
+ originalValues ||= {}
343
+ originalValues[key] = originalVal
344
+ }
301
345
  }
302
346
  }
303
347
  }
@@ -335,6 +379,13 @@ const resolveTokensAndVariants: StyleResolver<object> = (
335
379
  // sub-objects: media queries, pseudos, shadowOffset
336
380
  res[subKey] ??= {}
337
381
  Object.assign(res[subKey], subObject)
382
+ const subOriginalValues = styleOriginalValues.get(subObject)
383
+ if (subOriginalValues) {
384
+ styleOriginalValues.set(res[subKey], {
385
+ ...styleOriginalValues.get(res[subKey]),
386
+ ...subOriginalValues,
387
+ })
388
+ }
338
389
  } else {
339
390
  // nullish values cant be tokens, need no extra parsing
340
391
  res[subKey] = val
@@ -354,6 +405,10 @@ const resolveTokensAndVariants: StyleResolver<object> = (
354
405
  }
355
406
  }
356
407
 
408
+ if (originalValues) {
409
+ styleOriginalValues.set(res, originalValues)
410
+ }
411
+
357
412
  return res
358
413
  }
359
414
 
@@ -10,7 +10,7 @@ export function resolveSafeAreaValue(value: string): number | undefined {
10
10
  if (!edge) return undefined
11
11
 
12
12
  const g = globalThis as any
13
- const state = g.__gui_native_safe_area_state__
13
+ const state = g.__hanzogui_native_safe_area_state__
14
14
  if (state?.enabled && state.initialMetrics) {
15
15
  return state.initialMetrics.insets[edge]
16
16
  }
@@ -0,0 +1,2 @@
1
+ // stores raw style values before token and unit normalization
2
+ export const styleOriginalValues = new WeakMap<object, Record<string, any>>()
@@ -0,0 +1,49 @@
1
+ // developer-tools contract: exact token provenance for a component's final
2
+ // winning native style object. hanzogui only records it in development when
3
+ // GUI_ENABLE_STYLE_TOKEN_PROVENANCE=1.
4
+ //
5
+ // this is a pure inspection side channel. it records, per resolved style key,
6
+ // which token produced the value and the full theme name that resolved it
7
+ // (e.g. { backgroundColor: { token: '$background', theme: 'light_accent' } }).
8
+ // a literal value produces NO entry, which is how a literal that happens to
9
+ // equal a token value stays distinguishable from the token.
10
+ //
11
+ // the data is attached as a NON-ENUMERABLE, symbol-keyed property so it never
12
+ // changes the style object's enumerable keys or the React Native output, and
13
+ // hanzogui's own rendering never reads it back. this mirrors the
14
+ // `styleOriginalValues` WeakMap precedent (metadata beside the style, keyed off
15
+ // to the side), but uses an own-property so a cross-package consumer can read it
16
+ // without importing hanzogui.
17
+ //
18
+ // consumers read the property by the SAME registered symbol —
19
+ // `Symbol.for(STYLE_TOKEN_PROVENANCE_KEY)` — which shares one global registry
20
+ // per realm, so no shared module import is required.
21
+
22
+ export const STYLE_TOKEN_PROVENANCE_KEY = 'hanzogui.styleTokenProvenance'
23
+
24
+ const provenanceSymbol = /* @__PURE__ */ Symbol.for(STYLE_TOKEN_PROVENANCE_KEY)
25
+
26
+ export type StyleTokenBinding = {
27
+ /** original token string before resolution, e.g. '$background' or '$color9' */
28
+ token: string
29
+ /** full resolved theme name that produced the value, e.g. 'light_accent' */
30
+ theme: string
31
+ }
32
+
33
+ export type StyleTokenProvenance = Record<string, StyleTokenBinding>
34
+
35
+ export function setStyleTokenProvenance(style: object, provenance: StyleTokenProvenance) {
36
+ Object.defineProperty(style, provenanceSymbol, {
37
+ value: provenance,
38
+ enumerable: false,
39
+ configurable: true,
40
+ writable: true,
41
+ })
42
+ }
43
+
44
+ export function getStyleTokenProvenance(
45
+ style: object | null | undefined
46
+ ): StyleTokenProvenance | undefined {
47
+ if (!style) return undefined
48
+ return (style as Record<symbol, StyleTokenProvenance>)[provenanceSymbol]
49
+ }
@@ -1,31 +1,74 @@
1
+ import type { ReactNode } from 'react'
1
2
  import { StyleObjectIdentifier, StyleObjectRules } from '@hanzogui/helpers'
2
3
  import type { StyleObject } from '../types'
3
4
 
4
5
  // turns out this is pretty slow, creating a bunch of extra tags...
5
6
 
7
+ const styleTagCache = new Map<
8
+ string,
9
+ {
10
+ element: ReactNode
11
+ len: number
12
+ first: string | undefined
13
+ last: string | undefined
14
+ }
15
+ >()
16
+
17
+ let clearStyleTagCacheQueued = false
18
+
19
+ function queueStyleTagCacheClear() {
20
+ if (clearStyleTagCacheQueued) return
21
+
22
+ clearStyleTagCacheQueued = true
23
+ queueMicrotask(() => {
24
+ styleTagCache.clear()
25
+ clearStyleTagCacheQueued = false
26
+ })
27
+ }
28
+
29
+ function getCachedStyleTag(styleObject: StyleObject) {
30
+ const identifier = styleObject[StyleObjectIdentifier]
31
+ const rules = styleObject[StyleObjectRules]
32
+ const cached = styleTagCache.get(identifier)
33
+
34
+ if (
35
+ cached &&
36
+ cached.len === rules.length &&
37
+ cached.first === rules[0] &&
38
+ cached.last === rules[rules.length - 1]
39
+ ) {
40
+ return cached.element
41
+ }
42
+
43
+ const element = (
44
+ <style
45
+ key={identifier}
46
+ // @ts-ignore
47
+ href={`t_${identifier}`}
48
+ // @ts-ignore
49
+ precedence="default"
50
+ // we remove after first render in favor of inserting to a global stylesheet (faster)
51
+ suppressHydrationWarning
52
+ >
53
+ {rules.join('\n')}
54
+ </style>
55
+ )
56
+
57
+ styleTagCache.set(identifier, {
58
+ element,
59
+ len: rules.length,
60
+ first: rules[0],
61
+ last: rules[rules.length - 1],
62
+ })
63
+
64
+ return element
65
+ }
66
+
6
67
  export function getStyleTags(styles: StyleObject[]) {
7
68
  if (process.env.GUI_TARGET !== 'native') {
8
69
  if (styles.length) {
9
- return (
10
- <>
11
- {styles.map((styleObject) => {
12
- const identifier = styleObject[StyleObjectIdentifier]
13
- return (
14
- <style
15
- key={identifier}
16
- // @ts-ignore
17
- href={`t_${identifier}`}
18
- // @ts-ignore
19
- precedence="default"
20
- // we remove after first render in favor of inserting to a global stylesheet (faster)
21
- suppressHydrationWarning
22
- >
23
- {styleObject[StyleObjectRules].join('\n')}
24
- </style>
25
- )
26
- })}
27
- </>
28
- )
70
+ queueStyleTagCacheClear()
71
+ return <>{styles.map(getCachedStyleTag)}</>
29
72
  }
30
73
  }
31
74
  }
@@ -1,4 +1,4 @@
1
- import { isIos } from '@hanzogui/constants'
1
+ import { supportsDynamicColorIOS } from '@hanzogui/constants'
2
2
  import type { MutableRefObject } from 'react'
3
3
  import { getConfig, getSetting } from '../config'
4
4
  import { getVariable } from '../createVariable'
@@ -113,7 +113,7 @@ export function getThemeProxied(
113
113
  ...value,
114
114
  get val() {
115
115
  // when they touch the actual value we only track it if its a variable (web), its ignored!
116
- if (!globalThis.guiAvoidTracking) {
116
+ if (!globalThis.hanzoguiAvoidTracking) {
117
117
  // always track .val - not scheme optimized since they're getting raw value
118
118
  track(key, false)
119
119
  }
@@ -126,23 +126,29 @@ export function getThemeProxied(
126
126
  const { name, scheme } = curState
127
127
 
128
128
  if (process.env.GUI_TARGET === 'native') {
129
- // ios can avoid re-rendering for scheme changes (light↔dark) when using DynamicColorIOS
130
- // this does NOT work for sub-theme changes (red→blue) or when scheme inverses from parent
129
+ // ios can avoid re-rendering for scheme changes (light↔dark) when using DynamicColorIOS.
130
+ // DynamicColorIOS always resolves by the OS appearance, so this is only correct for a
131
+ // subtree that follows the OS scheme. it does NOT work when a <Theme> forces a scheme
132
+ // away from the OS/root — at any depth. `inverses` counts scheme flips from the root, so
133
+ // `inverses === 0` is exactly "this subtree still follows the OS". isInverse alone was
134
+ // wrong: a sub-theme keeping its parent's forced scheme (dark_blue under a forced dark,
135
+ // light root) has isInverse=false yet must NOT optimize, or iOS would pick the OS-scheme
136
+ // value (light) instead of the forced dark value.
131
137
  const fastSchemeChange = getSetting('fastSchemeChange')
132
138
  const rootMatchesSystem = doesRootSchemeMatchSystem()
133
139
  const shouldOptimize =
134
140
  scheme &&
135
141
  platform !== 'web' &&
136
- isIos &&
142
+ supportsDynamicColorIOS &&
137
143
  !curProps.deopt &&
138
- !curState.isInverse &&
144
+ !curState.inverses &&
139
145
  fastSchemeChange &&
140
146
  rootMatchesSystem
141
147
 
142
148
  if (process.env.NODE_ENV === 'development' && curProps.debug === 'verbose') {
143
149
  console.info(
144
150
  ` 🎨 useTheme().get(${key}) theme=${name} scheme=${scheme}`,
145
- `\n shouldOptimize=${shouldOptimize} (iOS=${isIos} deopt=${curProps.deopt} isInverse=${curState.isInverse} fastScheme=${fastSchemeChange} rootMatch=${rootMatchesSystem})`
151
+ `\n shouldOptimize=${shouldOptimize} (dynamicColorIOS=${supportsDynamicColorIOS} deopt=${curProps.deopt} inverses=${curState.inverses} fastScheme=${fastSchemeChange} rootMatch=${rootMatchesSystem})`
146
152
  )
147
153
  }
148
154
 
@@ -177,7 +183,7 @@ export function getThemeProxied(
177
183
  if (process.env.NODE_ENV === 'development' && curProps.debug) {
178
184
  console.info(
179
185
  ` 🎨 useTheme().get(${key}) tracking key (not optimizing)`,
180
- `\n platform=${platform} isIOS=${isIos} deopt=${curProps.deopt} fastScheme=${fastSchemeChange}`
186
+ `\n platform=${platform} dynamicColorIOS=${supportsDynamicColorIOS} deopt=${curProps.deopt} fastScheme=${fastSchemeChange}`
181
187
  )
182
188
  }
183
189
 
@@ -1,5 +1,5 @@
1
- import { isServer, isWeb } from '@hanzogui/constants'
2
- import { useCreateShallowSetState } from '@hanzogui/is-equal-shallow'
1
+ import { getPlatformDriver, isServer, isWeb } from '@hanzogui/constants'
2
+ import { mergeIfNotShallowEqual } from '@hanzogui/is-equal-shallow'
3
3
  import { useDidFinishSSR, useIsClientOnly } from '@hanzogui/use-did-finish-ssr'
4
4
  import { useRef, useState } from 'react'
5
5
  import { getSetting } from '../config'
@@ -63,8 +63,22 @@ export const useComponentState = (
63
63
  curStateRef.hasAnimated = true
64
64
  }
65
65
 
66
+ // a renderer platform driver with native pseudo states (react-native-gpui)
67
+ // makes ANY component with runtime pseudo styles ride the animation-driver
68
+ // emitter path — no per-site transition/animation prop required. the flip is
69
+ // driver-sourced (hover) or event-sourced (press/focus) but either way applies
70
+ // through the emitter with zero React commits; with no transition declared it
71
+ // resolves instant (see createComponent's effectiveTransition default).
72
+ const platformPseudo = Boolean(
73
+ !isHOC &&
74
+ useAnimations &&
75
+ animationDriver?.avoidReRenders &&
76
+ getPlatformDriver()?.pseudo &&
77
+ ('hoverStyle' in props || 'pressStyle' in props || 'focusStyle' in props)
78
+ )
79
+
66
80
  const willBeAnimatedClient = (() => {
67
- const next = !!(hasAnimationProp && !isHOC && useAnimations)
81
+ const next = !!((hasAnimationProp || platformPseudo) && !isHOC && useAnimations)
68
82
  return Boolean(next || curStateRef.hasAnimated)
69
83
  })()
70
84
 
@@ -162,7 +176,44 @@ export const useComponentState = (
162
176
 
163
177
  const groupName = props.group as any as string | undefined
164
178
 
165
- const setStateShallow = useCreateShallowSetState(setState, props.debug)
179
+ // hoisted shallow-set closure: created once per component instance and
180
+ // reused every render. drops the useCallback hook that useCreateShallowSetState
181
+ // would otherwise add. setState from useState is stable per instance so we
182
+ // can safely capture it. debug is read off stateRef at call time.
183
+ //
184
+ // important: this lives on `baseSetStateShallow`, not `setStateShallow`.
185
+ // createComponent's avoidReRenders path overwrites `stateRef.current.setStateShallow`
186
+ // with an emitter wrapper and captures this base as its real-re-render escape hatch.
187
+ // if the base shared the `setStateShallow` field, on the 2nd+ render this hook would
188
+ // read back the wrapper, the wrapper's escape hatch would point at itself, and a real
189
+ // re-render (e.g. unmounted 'should-enter' -> false) would never reach React, leaving
190
+ // enter animations stuck at opacity 0.
191
+ if (!stateRef.current.baseSetStateShallow) {
192
+ const r = stateRef.current
193
+ r.baseSetStateShallow = (stateOrGetState: any) => {
194
+ setState((prev: any) => {
195
+ const next =
196
+ typeof stateOrGetState === 'function' ? stateOrGetState(prev) : stateOrGetState
197
+ const update = mergeIfNotShallowEqual(prev, next)
198
+ if (process.env.NODE_ENV === 'development') {
199
+ const dbg = (r as any).__debug
200
+ if (dbg && update !== prev) {
201
+ console.groupCollapsed(`setStateShallow CHANGE`, '=>', update)
202
+ console.info(`previously`, prev)
203
+ console.trace()
204
+ console.groupEnd()
205
+ }
206
+ }
207
+ return update
208
+ })
209
+ }
210
+ }
211
+ if (process.env.NODE_ENV === 'development') {
212
+ ;(stateRef.current as any).__debug = props.debug
213
+ }
214
+ const setStateShallow = stateRef.current.baseSetStateShallow!
215
+ if (process.env.NODE_ENV === 'development' && globalThis.time)
216
+ globalThis.time`state-useCreateShallowSetState`
166
217
 
167
218
  // set enter/exit variants onto our new props object
168
219
  if (presenceState && isAnimated && isHydrated && staticConfig.variants) {
@@ -247,6 +298,7 @@ export const useComponentState = (
247
298
  outputStyle,
248
299
  willBeAnimated,
249
300
  willBeAnimatedClient,
301
+ platformPseudo,
250
302
  }
251
303
  }
252
304