@hanzogui/kitchen-sink 3.0.5

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 (431) hide show
  1. package/.detoxrc.js +130 -0
  2. package/.env.production +2 -0
  3. package/.maestro/config.yaml +4 -0
  4. package/.maestro/flows/shorthand-variables.yaml +23 -0
  5. package/.watchmanconfig +1 -0
  6. package/LICENSE +21 -0
  7. package/README.md +11 -0
  8. package/app.json +43 -0
  9. package/assets/adaptive-icon.png +0 -0
  10. package/assets/favicon.png +0 -0
  11. package/assets/icon.png +0 -0
  12. package/assets/splash.png +0 -0
  13. package/babel.config.js +25 -0
  14. package/e2e/CompilerExtraction.test.ts +147 -0
  15. package/e2e/GroupPressNative.test.ts +167 -0
  16. package/e2e/MediaQueryGtMd.test.ts +71 -0
  17. package/e2e/NativePortal.test.ts +113 -0
  18. package/e2e/PointerEvents.test.ts +116 -0
  19. package/e2e/PressStyleNative.noRngh.test.ts +191 -0
  20. package/e2e/PressStyleNative.test.ts +231 -0
  21. package/e2e/SafeArea.test.ts +57 -0
  22. package/e2e/SelectAndroidOnPress.test.ts +181 -0
  23. package/e2e/SelectRemount.test.ts +137 -0
  24. package/e2e/SheetDragResist.test.ts +370 -0
  25. package/e2e/SheetKeyboardDrag.test.ts +249 -0
  26. package/e2e/SheetScrollableDrag.test.ts +560 -0
  27. package/e2e/ShorthandVariables.test.ts +53 -0
  28. package/e2e/ThemeChangeBasic.test.ts +123 -0
  29. package/e2e/ThemeMutation.test.ts +80 -0
  30. package/e2e/check-rngh-status.test.ts +31 -0
  31. package/e2e/jest.config.js +19 -0
  32. package/e2e/utils/colors.ts +75 -0
  33. package/e2e/utils/navigation.ts +53 -0
  34. package/eas.json +22 -0
  35. package/flows/AlertDialog.yaml +17 -0
  36. package/flows/OpenApp.yaml +25 -0
  37. package/flows/Select.yaml +13 -0
  38. package/flows/Sheet.yaml +12 -0
  39. package/flows/Tabs.yaml +13 -0
  40. package/flows/Toast.yaml +14 -0
  41. package/flows/WarmUp.yaml +24 -0
  42. package/index.html +21 -0
  43. package/index.js +17 -0
  44. package/metro.config.js +64 -0
  45. package/next-router-shim.ts +9 -0
  46. package/package.json +118 -0
  47. package/plans/toast-2.md +471 -0
  48. package/playwright.config.ts +71 -0
  49. package/plugins/expo-modules-core-swift6.js +76 -0
  50. package/pod-install.sh +7 -0
  51. package/public/favicon.svg +70 -0
  52. package/public/fonts/inter.css +15 -0
  53. package/public/fonts/noto-cn.otf +0 -0
  54. package/public/gui-icon.svg +68 -0
  55. package/run-detox.sh +230 -0
  56. package/run-native-tests.sh +4 -0
  57. package/run-tests-parallel.ts +195 -0
  58. package/screenshots/Screenshotter.test.tsx +48 -0
  59. package/src/AnimationDemos.tsx +131 -0
  60. package/src/App.native.tsx +121 -0
  61. package/src/App.tsx +121 -0
  62. package/src/Navigation.tsx +98 -0
  63. package/src/Sandbox.tsx +87 -0
  64. package/src/TestDynamicEval.tsx +33 -0
  65. package/src/TestNativeSheet.tsx +100 -0
  66. package/src/components/TimedRender.tsx +18 -0
  67. package/src/constants/test-ids.ts +52 -0
  68. package/src/features/demos/demo-screen.tsx +72 -0
  69. package/src/features/home/ColorSchemeListItem.tsx +41 -0
  70. package/src/features/home/TestBuildAButton.tsx +102 -0
  71. package/src/features/home/TestSeparator.tsx +0 -0
  72. package/src/features/home/screen.tsx +285 -0
  73. package/src/features/testcases/screen.tsx +59 -0
  74. package/src/features/testcases/test-screen.tsx +50 -0
  75. package/src/generatedV5Theme.ts +112 -0
  76. package/src/gui.config.ts +411 -0
  77. package/src/guy.png +0 -0
  78. package/src/index.tsx +6 -0
  79. package/src/provider/index.tsx +18 -0
  80. package/src/test-gui-stack.tsx +11 -0
  81. package/src/test.tsx +3 -0
  82. package/src/useKitchenSinkTheme.tsx +15 -0
  83. package/src/usecases/ActionsSheetComparison.tsx +194 -0
  84. package/src/usecases/AnimatePresenceEnterExitCase.tsx +255 -0
  85. package/src/usecases/AnimatePresenceExitTest.tsx +69 -0
  86. package/src/usecases/AnimatedByProp.tsx +39 -0
  87. package/src/usecases/AnimationComprehensiveCase.tsx +2515 -0
  88. package/src/usecases/AnimationValueLoggingCase.tsx +526 -0
  89. package/src/usecases/AnimationsWithMediaQueriesCase.tsx +110 -0
  90. package/src/usecases/Benchmark.tsx +148 -0
  91. package/src/usecases/BenchmarkSelect.tsx +34 -0
  92. package/src/usecases/ButtonCircular.tsx +3 -0
  93. package/src/usecases/ButtonCustom.tsx +33 -0
  94. package/src/usecases/ButtonIconColor.tsx +18 -0
  95. package/src/usecases/ButtonInverse.tsx +30 -0
  96. package/src/usecases/ButtonUnstyled.tsx +31 -0
  97. package/src/usecases/CheckboxDisabledOnPress.tsx +62 -0
  98. package/src/usecases/ClickDuringEnterCase.tsx +59 -0
  99. package/src/usecases/CodeExamplesInput.tsx +9 -0
  100. package/src/usecases/ColorTokenFallback.tsx +52 -0
  101. package/src/usecases/CompilerExtraction.tsx +380 -0
  102. package/src/usecases/ComplexVariants.tsx +164 -0
  103. package/src/usecases/CrashAdaptSheet.tsx +98 -0
  104. package/src/usecases/CustomStyledAnimatedPopover.tsx +42 -0
  105. package/src/usecases/CustomStyledAnimatedTooltip.tsx +72 -0
  106. package/src/usecases/DOMNodeAPIs.tsx +154 -0
  107. package/src/usecases/DialogFocusScopeCase.tsx +277 -0
  108. package/src/usecases/DialogFocusScopeDebug.tsx +85 -0
  109. package/src/usecases/DialogNestedCase.tsx +121 -0
  110. package/src/usecases/DialogOpenControlled.tsx +49 -0
  111. package/src/usecases/DialogPointerEventsCase.tsx +58 -0
  112. package/src/usecases/DialogScopedCase.tsx +106 -0
  113. package/src/usecases/DialogSheetAdaptCase.tsx +178 -0
  114. package/src/usecases/DialogSheetAdaptResizeCase.tsx +98 -0
  115. package/src/usecases/DismissLayerStackingCase.tsx +223 -0
  116. package/src/usecases/DriverDisableAnimationPropsCase.tsx +44 -0
  117. package/src/usecases/Example.tsx +10 -0
  118. package/src/usecases/ExitCompletionCase.tsx +713 -0
  119. package/src/usecases/FocusVisibleButton.tsx +14 -0
  120. package/src/usecases/FocusVisibleButtonPointer.tsx +13 -0
  121. package/src/usecases/FocusVisibleButtonWithFocusStyle.tsx +16 -0
  122. package/src/usecases/FocusWithinCase.tsx +55 -0
  123. package/src/usecases/FontTokensInVariants.tsx +14 -0
  124. package/src/usecases/FormButtonTypeCase.tsx +34 -0
  125. package/src/usecases/GlobalScopedTriggerIsolationCase.tsx +178 -0
  126. package/src/usecases/GroupHoverMobile.tsx +39 -0
  127. package/src/usecases/GroupPressInVariant.tsx +92 -0
  128. package/src/usecases/GroupPressNative.tsx +200 -0
  129. package/src/usecases/GroupProp.tsx +96 -0
  130. package/src/usecases/GroupPseudoVariantOverride.tsx +56 -0
  131. package/src/usecases/GroupUseCases.tsx +94 -0
  132. package/src/usecases/HeightMediaQueryOverrideCase.tsx +183 -0
  133. package/src/usecases/InputAutoFocusAfterMenuCase.tsx +105 -0
  134. package/src/usecases/InputAutoFocusStyledCase.tsx +39 -0
  135. package/src/usecases/KeyboardControllerTest.tsx +146 -0
  136. package/src/usecases/ListItem.tsx +123 -0
  137. package/src/usecases/MediaQueriesV5.tsx +137 -0
  138. package/src/usecases/MediaQueryGtMd.tsx +73 -0
  139. package/src/usecases/MenuAboveDialogCase.tsx +75 -0
  140. package/src/usecases/MenuAccessibilityCase.tsx +133 -0
  141. package/src/usecases/MenuAnimatePositionCase.tsx +41 -0
  142. package/src/usecases/MenuArrowAnimatePresenceCase.tsx +98 -0
  143. package/src/usecases/MenuAsChildPositionCase.tsx +24 -0
  144. package/src/usecases/MenuAutoResizeCase.tsx +57 -0
  145. package/src/usecases/MenuBottomCase.tsx +55 -0
  146. package/src/usecases/MenuFocusLeaveCase.tsx +135 -0
  147. package/src/usecases/MenuHighlightCase.tsx +44 -0
  148. package/src/usecases/MenuItemFocusCase.tsx +79 -0
  149. package/src/usecases/MenuItemPseudoOverrideCase.tsx +270 -0
  150. package/src/usecases/MenuMultiTriggerCase.tsx +47 -0
  151. package/src/usecases/MenuOverflowCase.tsx +60 -0
  152. package/src/usecases/MenuSubCase.tsx +223 -0
  153. package/src/usecases/MenuSubLeftCase.tsx +178 -0
  154. package/src/usecases/MenuSubNestedPositionCase.tsx +171 -0
  155. package/src/usecases/MenuSubStyledCase.tsx +145 -0
  156. package/src/usecases/MenuThemeCase.tsx +50 -0
  157. package/src/usecases/MenuUnstyledCase.tsx +52 -0
  158. package/src/usecases/MultiDriverAnimation.tsx +118 -0
  159. package/src/usecases/NativePortalTest.tsx +179 -0
  160. package/src/usecases/NewInputBasic.tsx +16 -0
  161. package/src/usecases/NewInputEvents.tsx +29 -0
  162. package/src/usecases/NonGuiTextStyledType.tsx +23 -0
  163. package/src/usecases/OnLayoutCase.tsx +134 -0
  164. package/src/usecases/OnLayoutScaleCase.tsx +88 -0
  165. package/src/usecases/OnLayoutStressCase.tsx +353 -0
  166. package/src/usecases/OpacityModifierCase.tsx +113 -0
  167. package/src/usecases/OverlayStyled.tsx +66 -0
  168. package/src/usecases/ParagraphSpanFontInheritance.tsx +53 -0
  169. package/src/usecases/PlaceholderTextColor.tsx +20 -0
  170. package/src/usecases/PointerEventsCase.tsx +100 -0
  171. package/src/usecases/PopoverAndMenuMultiTriggerCase.tsx +138 -0
  172. package/src/usecases/PopoverCase.tsx +222 -0
  173. package/src/usecases/PopoverContentStyledPlusAnimations.tsx +44 -0
  174. package/src/usecases/PopoverFocusScopeCase.tsx +171 -0
  175. package/src/usecases/PopoverHoverableCase.tsx +167 -0
  176. package/src/usecases/PopoverHoverableDisableClickCase.tsx +118 -0
  177. package/src/usecases/PopoverHoverableRapidCase.tsx +103 -0
  178. package/src/usecases/PopoverHoverableScopedCase.tsx +135 -0
  179. package/src/usecases/PopoverScopedCase.tsx +76 -0
  180. package/src/usecases/PopoverTriggerIsolationCase.tsx +80 -0
  181. package/src/usecases/PressStyleNative.tsx +143 -0
  182. package/src/usecases/PseudoStyleMerge.tsx +25 -0
  183. package/src/usecases/PseudoTransitionCase.tsx +174 -0
  184. package/src/usecases/RawAnimatedValueCase.tsx +231 -0
  185. package/src/usecases/RemoveScrollCase.tsx +66 -0
  186. package/src/usecases/RenderPropCase.tsx +263 -0
  187. package/src/usecases/SafeAreaCase.tsx +236 -0
  188. package/src/usecases/ScrollViewRefCase.tsx +88 -0
  189. package/src/usecases/SecondPage.tsx +5 -0
  190. package/src/usecases/SelectAndroidOnPress.tsx +129 -0
  191. package/src/usecases/SelectFocusScopeCase.tsx +270 -0
  192. package/src/usecases/SelectRemount.tsx +136 -0
  193. package/src/usecases/Shadows.tsx +5 -0
  194. package/src/usecases/SheetAnimationCase.tsx +155 -0
  195. package/src/usecases/SheetDragCase.tsx +183 -0
  196. package/src/usecases/SheetDragResistCase.tsx +433 -0
  197. package/src/usecases/SheetDragResistCase.web.tsx +359 -0
  198. package/src/usecases/SheetKeyboardDragCase.tsx +328 -0
  199. package/src/usecases/SheetKeyboardFitContentCase.tsx +165 -0
  200. package/src/usecases/SheetOnAnimationCompleteCase.tsx +54 -0
  201. package/src/usecases/SheetScrollLockCase.tsx +166 -0
  202. package/src/usecases/SheetScrollableDrag.tsx +249 -0
  203. package/src/usecases/SheetSnapPointsFitCase.tsx +393 -0
  204. package/src/usecases/ShorthandVariables.tsx +49 -0
  205. package/src/usecases/SlowThemeReRender.tsx +48 -0
  206. package/src/usecases/SpinnerCustomColors.tsx +34 -0
  207. package/src/usecases/StackZIndex.tsx +82 -0
  208. package/src/usecases/StressPage.tsx +301 -0
  209. package/src/usecases/StylePlatform.tsx +30 -0
  210. package/src/usecases/StyleProp.tsx +29 -0
  211. package/src/usecases/StyledAnchor.tsx +27 -0
  212. package/src/usecases/StyledButtonAnimationAuto.tsx +99 -0
  213. package/src/usecases/StyledButtonTheme.tsx +63 -0
  214. package/src/usecases/StyledButtonVariantPseudo.tsx +25 -0
  215. package/src/usecases/StyledButtonVariantPseudoMerge.tsx +77 -0
  216. package/src/usecases/StyledCheckboxTheme.tsx +23 -0
  217. package/src/usecases/StyledContextColor.tsx +246 -0
  218. package/src/usecases/StyledContextTokens.tsx +147 -0
  219. package/src/usecases/StyledHOCNamed.tsx +20 -0
  220. package/src/usecases/StyledHtmlCase.tsx +144 -0
  221. package/src/usecases/StyledIconColor.tsx +19 -0
  222. package/src/usecases/StyledInputFocusStyle.tsx +21 -0
  223. package/src/usecases/StyledInputOnFocus.tsx +30 -0
  224. package/src/usecases/StyledMediaQueryMerge.tsx +95 -0
  225. package/src/usecases/StyledOverridePsuedo.tsx +26 -0
  226. package/src/usecases/StyledRNW.tsx +61 -0
  227. package/src/usecases/StyledStyleableInputOnFocus.tsx +34 -0
  228. package/src/usecases/StyledStyleableInputVariant.tsx +48 -0
  229. package/src/usecases/StyledStyledStyleableInputOnFocus.tsx +36 -0
  230. package/src/usecases/StyledVariantTextColor.tsx +25 -0
  231. package/src/usecases/StyledViewOnFocus.tsx +32 -0
  232. package/src/usecases/TabHoverAnimationCase.tsx +212 -0
  233. package/src/usecases/TextNestedInheritance.tsx +80 -0
  234. package/src/usecases/ThemeChange.tsx +100 -0
  235. package/src/usecases/ThemeChangeBasic.tsx +52 -0
  236. package/src/usecases/ThemeComponentResolution.tsx +119 -0
  237. package/src/usecases/ThemeConditionalName.tsx +31 -0
  238. package/src/usecases/ThemeMediaAnimationCase.tsx +39 -0
  239. package/src/usecases/ThemeMutation.tsx +86 -0
  240. package/src/usecases/ThemeNested.tsx +103 -0
  241. package/src/usecases/ThemeReset.tsx +62 -0
  242. package/src/usecases/ThemeShallowCase.tsx +83 -0
  243. package/src/usecases/ToastCase.tsx +46 -0
  244. package/src/usecases/ToggleGroupActiveProps.tsx +40 -0
  245. package/src/usecases/ToggleGroupXGroupCase.tsx +104 -0
  246. package/src/usecases/TooltipAnimationCase.tsx +99 -0
  247. package/src/usecases/TooltipCase.tsx +32 -0
  248. package/src/usecases/TooltipGlobalPatternCase.tsx +83 -0
  249. package/src/usecases/TooltipGroupCase.tsx +102 -0
  250. package/src/usecases/TooltipMultiTriggerCase.tsx +88 -0
  251. package/src/usecases/TooltipPositionJumpCase.tsx +91 -0
  252. package/src/usecases/TooltipTriggerInlineCase.tsx +60 -0
  253. package/src/usecases/TransformMediaQueryMerge.tsx +98 -0
  254. package/src/usecases/UseCases.tsx +409 -0
  255. package/src/usecases/UseTheme.tsx +41 -0
  256. package/src/usecases/V5ThemeBuilderOutput.tsx +231 -0
  257. package/src/usecases/VariantFontFamily.tsx +25 -0
  258. package/src/usecases/VariantsOrder.tsx +117 -0
  259. package/src/usecases/ZIndex.tsx +155 -0
  260. package/src/usecases/helpers.tsx +44 -0
  261. package/src/usecases/index.native.ts +122 -0
  262. package/src/usecases/index.ts +3 -0
  263. package/src/usecases/index.web.ts +177 -0
  264. package/tests/AnimatePresenceEnterExit.animated.test.tsx +176 -0
  265. package/tests/AnimatedByProp.animated.test.tsx +138 -0
  266. package/tests/AnimationBehavior.animated.test.tsx +543 -0
  267. package/tests/AnimationTiming.animated.test.tsx +195 -0
  268. package/tests/AnimationsWithMediaQueries.animated.test.tsx +154 -0
  269. package/tests/BuildAButton.test.tsx +87 -0
  270. package/tests/ButtonCircular.test.tsx +17 -0
  271. package/tests/ButtonCustom.test.tsx +17 -0
  272. package/tests/ButtonIconColor.test.tsx +23 -0
  273. package/tests/ButtonUnstyled.test.tsx +56 -0
  274. package/tests/ClickDuringEnter.animated.test.tsx +174 -0
  275. package/tests/ColorTokenFallback.test.tsx +45 -0
  276. package/tests/DOMNodeAPIs.test.tsx +161 -0
  277. package/tests/DialogFocusScope.animated.test.tsx +309 -0
  278. package/tests/DialogNested.test.tsx +128 -0
  279. package/tests/DialogOpenControlled.test.tsx +42 -0
  280. package/tests/DialogPointerEvents.animated.test.tsx +108 -0
  281. package/tests/DialogScoped.test.tsx +137 -0
  282. package/tests/DialogSheetAdapt.test.tsx +68 -0
  283. package/tests/DialogSheetAdaptResize.test.tsx +161 -0
  284. package/tests/DismissLayerStacking.test.tsx +292 -0
  285. package/tests/DriverDisableAnimationProps.animated.test.tsx +157 -0
  286. package/tests/ExitCompletion.animated.test.tsx +425 -0
  287. package/tests/ExitTimingCheck.animated.test.ts +34 -0
  288. package/tests/FocusVisibleButton.test.tsx +41 -0
  289. package/tests/FocusVisibleButtonPointerFocus.test.tsx +23 -0
  290. package/tests/FocusVisibleButtonPointerFocusWithFocusStyle.test.tsx +40 -0
  291. package/tests/FocusWithinStyle.animated.test.tsx +66 -0
  292. package/tests/FocusWithinStyle.test.tsx +60 -0
  293. package/tests/FormButtonType.test.tsx +42 -0
  294. package/tests/GlobalScopedTriggerIsolation.test.tsx +89 -0
  295. package/tests/GroupHoverMobile.test.tsx +52 -0
  296. package/tests/GroupPressInVariant.test.tsx +82 -0
  297. package/tests/GroupProp.test.tsx +30 -0
  298. package/tests/GroupPseudoVariantOverride.test.tsx +57 -0
  299. package/tests/GroupUseCases.test.tsx +111 -0
  300. package/tests/GuiSiteMotion.test.ts +481 -0
  301. package/tests/HeightMediaQueryOverride.test.tsx +112 -0
  302. package/tests/InputAutoFocusAfterMenu.test.tsx +55 -0
  303. package/tests/InputAutoFocusStyled.test.tsx +22 -0
  304. package/tests/ListItem.test.tsx +129 -0
  305. package/tests/MediaQueriesV5.test.tsx +113 -0
  306. package/tests/MediaQueryGtMd.test.tsx +84 -0
  307. package/tests/MenuAboveDialog.test.tsx +108 -0
  308. package/tests/MenuAccessibility.test.tsx +346 -0
  309. package/tests/MenuAnimatePosition.animated.test.tsx +57 -0
  310. package/tests/MenuArrowAnimatePresence.animated.test.tsx +71 -0
  311. package/tests/MenuAsChildPosition.test.tsx +16 -0
  312. package/tests/MenuAutoResize.test.tsx +54 -0
  313. package/tests/MenuFocusLeave.test.tsx +181 -0
  314. package/tests/MenuHighlight.test.tsx +165 -0
  315. package/tests/MenuHoverKeyboardBugs.test.tsx +252 -0
  316. package/tests/MenuItemFocus.test.tsx +59 -0
  317. package/tests/MenuItemPseudoOverride.test.tsx +231 -0
  318. package/tests/MenuMultiTrigger.test.tsx +101 -0
  319. package/tests/MenuOverflow.test.tsx +93 -0
  320. package/tests/MenuStayInFrame.test.tsx +102 -0
  321. package/tests/MenuSubKeyboardFocus.test.tsx +220 -0
  322. package/tests/MenuSubLeftSafePolygon.test.tsx +88 -0
  323. package/tests/MenuSubNestedPosition.test.tsx +48 -0
  324. package/tests/MenuSubSafePolygon.test.tsx +97 -0
  325. package/tests/MenuSubStyled.test.tsx +40 -0
  326. package/tests/MenuTheme.test.tsx +34 -0
  327. package/tests/MenuUnstyled.test.tsx +56 -0
  328. package/tests/MultiDriverAnimation.test.tsx +207 -0
  329. package/tests/NewInputBasic.test.tsx +50 -0
  330. package/tests/NewInputEvents.test.tsx +55 -0
  331. package/tests/OnLayout.test.tsx +163 -0
  332. package/tests/OnLayoutScale.test.tsx +100 -0
  333. package/tests/OnLayoutStress.test.tsx +304 -0
  334. package/tests/ParagraphSpanFontInheritance.test.tsx +73 -0
  335. package/tests/PointerEvents.test.tsx +123 -0
  336. package/tests/Popover.animated.test.tsx +234 -0
  337. package/tests/PopoverAndMenuMultiTrigger.test.tsx +184 -0
  338. package/tests/PopoverAnimatePosition.animated.test.tsx +51 -0
  339. package/tests/PopoverClickDuringEnter.animated.test.tsx +197 -0
  340. package/tests/PopoverFocusScope.test.tsx +242 -0
  341. package/tests/PopoverHoverable.test.tsx +383 -0
  342. package/tests/PopoverHoverableDisableClick.test.tsx +106 -0
  343. package/tests/PopoverHoverableRapid.test.tsx +129 -0
  344. package/tests/PopoverHoverableReposition.test.tsx +111 -0
  345. package/tests/PopoverHoverableScoped.animated.test.tsx +103 -0
  346. package/tests/PopoverHoverableStress.test.tsx +169 -0
  347. package/tests/PopoverInitialPosition.animated.test.tsx +82 -0
  348. package/tests/PopoverMiddlewareSkipRegression.animated.test.tsx +221 -0
  349. package/tests/PopoverScoped.test.tsx +128 -0
  350. package/tests/PopoverScopedPositionGlitch.animated.test.tsx +184 -0
  351. package/tests/PopoverTriggerIsolation.test.tsx +62 -0
  352. package/tests/PseudoTransition.animated.test.tsx +319 -0
  353. package/tests/RawAnimatedValue.test.tsx +147 -0
  354. package/tests/RemoveScroll.test.tsx +223 -0
  355. package/tests/RenderProp.test.tsx +293 -0
  356. package/tests/ScrollViewRef.test.tsx +39 -0
  357. package/tests/SelectClickHold.test.tsx +147 -0
  358. package/tests/SelectFocusScope.test.tsx +176 -0
  359. package/tests/SelectInnerPositioning.test.tsx +82 -0
  360. package/tests/SelectKeyboardNav.test.tsx +173 -0
  361. package/tests/SelectPositioning.test.tsx +56 -0
  362. package/tests/SelectTypeahead.test.tsx +63 -0
  363. package/tests/Shadows.test.tsx +14 -0
  364. package/tests/SheetAnimation.animated.test.tsx +413 -0
  365. package/tests/SheetDrag.animated.test.tsx +223 -0
  366. package/tests/SheetDragResist.animated.test.tsx +393 -0
  367. package/tests/SheetOnAnimationComplete.animated.test.tsx +62 -0
  368. package/tests/SheetScrollLock.animated.test.tsx +287 -0
  369. package/tests/SheetScrollableDrag.animated.test.tsx +1264 -0
  370. package/tests/SheetSnapPointsFit.animated.test.tsx +259 -0
  371. package/tests/ShorthandVariables.test.tsx +44 -0
  372. package/tests/SpinnerCustomColors.test.tsx +67 -0
  373. package/tests/StackZIndex.test.tsx +51 -0
  374. package/tests/StressPagePerf.test.tsx +76 -0
  375. package/tests/StylePlatform.test.tsx +38 -0
  376. package/tests/StyleProp.test.tsx +20 -0
  377. package/tests/StyledAnchor.test.tsx +17 -0
  378. package/tests/StyledButtonTheme.test.tsx +22 -0
  379. package/tests/StyledButtonVariantPseudo.test.tsx +20 -0
  380. package/tests/StyledButtonVariantPseudoMerge.animated.test.tsx +33 -0
  381. package/tests/StyledCheckboxTheme.test.tsx +16 -0
  382. package/tests/StyledContextColor.test.tsx +119 -0
  383. package/tests/StyledContextTokens.test.tsx +56 -0
  384. package/tests/StyledHOCNamed.test.tsx +16 -0
  385. package/tests/StyledHtml.test.tsx +161 -0
  386. package/tests/StyledIconColor.test.tsx +32 -0
  387. package/tests/StyledInputFocusStyle.test.tsx +19 -0
  388. package/tests/StyledInputOnFocus.test.tsx +27 -0
  389. package/tests/StyledMediaQueryMerge.test.tsx +66 -0
  390. package/tests/StyledRNW.test.tsx +17 -0
  391. package/tests/StyledStyleableInputOnFocus.test.tsx +27 -0
  392. package/tests/StyledStyleableInputVariant.test.tsx +22 -0
  393. package/tests/StyledStyledStyleableInputOnFocus.test.tsx +27 -0
  394. package/tests/StyledVariantTextColor.test.tsx +24 -0
  395. package/tests/StyledViewOnFocus.test.tsx +27 -0
  396. package/tests/TabHoverAnimation.animated.test.tsx +468 -0
  397. package/tests/TabHoverPositionSmooth.animated.test.tsx +129 -0
  398. package/tests/TextNestedInheritance.test.tsx +93 -0
  399. package/tests/ThemeChange.test.tsx +70 -0
  400. package/tests/ThemeComponentResolution.test.tsx +82 -0
  401. package/tests/ThemeConditionalName.test.tsx +34 -0
  402. package/tests/ThemeMediaAnimation.test.tsx +65 -0
  403. package/tests/ThemeNested.test.tsx +141 -0
  404. package/tests/ThemeReset.test.tsx +63 -0
  405. package/tests/ThemeShallow.test.tsx +95 -0
  406. package/tests/Toast.test.tsx +106 -0
  407. package/tests/ToggleGroup.test.tsx +61 -0
  408. package/tests/ToggleGroupActiveProps.test.tsx +38 -0
  409. package/tests/ToggleGroupXGroup.test.tsx +172 -0
  410. package/tests/TooltipAnimation.animated.test.tsx +260 -0
  411. package/tests/TooltipEnterInterrupt.animated.test.tsx +76 -0
  412. package/tests/TooltipGlobalPattern.animated.test.tsx +208 -0
  413. package/tests/TooltipGroup.animated.test.tsx +79 -0
  414. package/tests/TooltipMultiTrigger.test.tsx +116 -0
  415. package/tests/TooltipPositionJump.animated.test.tsx +229 -0
  416. package/tests/TooltipPositionJumpNotes.md +219 -0
  417. package/tests/TooltipRapidSwitch.animated.test.tsx +399 -0
  418. package/tests/TooltipTriggerInline.test.tsx +65 -0
  419. package/tests/TransformMediaQueryMerge.test.tsx +104 -0
  420. package/tests/TransitionEnterExit.animated.test.tsx +311 -0
  421. package/tests/UseTheme.test.tsx +16 -0
  422. package/tests/V5ThemeBuilderOutput.test.tsx +164 -0
  423. package/tests/VariantFontFamily.test.tsx +11 -0
  424. package/tests/VariantsOrder.test.tsx +53 -0
  425. package/tests/_debug_position.mjs +52 -0
  426. package/tests/test-utils.ts +106 -0
  427. package/tests/utils.tsx +54 -0
  428. package/tsconfig.json +45 -0
  429. package/vite-env.d.ts +1 -0
  430. package/vite.config.ts +14 -0
  431. package/webpack.config.js +139 -0
@@ -0,0 +1,167 @@
1
+ import { Popover, YStack, SizableText, XStack } from '@hanzo/gui'
2
+
3
+ // each case is isolated for clean testing
4
+
5
+ export function PopoverHoverableDelayCase() {
6
+ return (
7
+ <YStack padding="$10" alignItems="center" gap="$4">
8
+ <SizableText size="$3" color="$color9">
9
+ Hover delay: open should delay 400ms, close should delay 400ms
10
+ </SizableText>
11
+ <Popover placement="bottom" hoverable={{ delay: 400 }} offset={8}>
12
+ <Popover.Trigger asChild>
13
+ <XStack
14
+ id="delay-trigger"
15
+ px="$4"
16
+ py="$2"
17
+ bg="$color3"
18
+ rounded="$4"
19
+ cursor="pointer"
20
+ >
21
+ <SizableText>Hover me (delay: 400ms)</SizableText>
22
+ </XStack>
23
+ </Popover.Trigger>
24
+ <Popover.Content
25
+ id="delay-content"
26
+ disableFocusScope
27
+ unstyled
28
+ transition="200ms"
29
+ animateOnly={['opacity', 'transform']}
30
+ enterStyle={{ opacity: 0, y: -4 }}
31
+ exitStyle={{ opacity: 0, y: -4 }}
32
+ bg="$color4"
33
+ rounded="$4"
34
+ px="$4"
35
+ py="$3"
36
+ >
37
+ <SizableText>Popover content (delay test)</SizableText>
38
+ </Popover.Content>
39
+ </Popover>
40
+ </YStack>
41
+ )
42
+ }
43
+
44
+ export function PopoverHoverableRestMsCase() {
45
+ return (
46
+ <YStack padding="$10" alignItems="center" gap="$4">
47
+ <SizableText size="$3" color="$color9">
48
+ restMs: opens after 400ms rest, exit should NOT have extra delay
49
+ </SizableText>
50
+ <Popover placement="bottom" hoverable={{ restMs: 400 }} offset={8}>
51
+ <Popover.Trigger asChild>
52
+ <XStack
53
+ id="restms-trigger"
54
+ px="$4"
55
+ py="$2"
56
+ bg="$color3"
57
+ rounded="$4"
58
+ cursor="pointer"
59
+ >
60
+ <SizableText>Hover me (restMs: 400ms)</SizableText>
61
+ </XStack>
62
+ </Popover.Trigger>
63
+ <Popover.Content
64
+ id="restms-content"
65
+ disableFocusScope
66
+ unstyled
67
+ transition="200ms"
68
+ animateOnly={['opacity', 'transform']}
69
+ enterStyle={{ opacity: 0, y: -4 }}
70
+ exitStyle={{ opacity: 0, y: -4 }}
71
+ bg="$color4"
72
+ rounded="$4"
73
+ px="$4"
74
+ py="$3"
75
+ >
76
+ <SizableText>Popover content (restMs test)</SizableText>
77
+ </Popover.Content>
78
+ </Popover>
79
+ </YStack>
80
+ )
81
+ }
82
+
83
+ // tests restMs re-hover and safePolygon (hovering content via the gap)
84
+ export function PopoverHoverableSafePolygonCase() {
85
+ return (
86
+ <YStack padding="$10" alignItems="center" gap="$4">
87
+ <SizableText size="$3" color="$color9">
88
+ restMs: 60, offset: 20 - should be able to hover content through gap
89
+ </SizableText>
90
+ <Popover placement="bottom" hoverable={{ restMs: 260, delay: 0 }} offset={80}>
91
+ <Popover.Trigger asChild>
92
+ <XStack
93
+ id="safepoly-trigger"
94
+ px="$4"
95
+ py="$2"
96
+ bg="$color3"
97
+ rounded="$4"
98
+ cursor="pointer"
99
+ >
100
+ <SizableText>Hover me (safePolygon test)</SizableText>
101
+ </XStack>
102
+ </Popover.Trigger>
103
+ <Popover.Content
104
+ id="safepoly-content"
105
+ disableFocusScope
106
+ unstyled
107
+ transition="200ms"
108
+ animateOnly={['opacity', 'transform']}
109
+ enterStyle={{ opacity: 0, y: -4 }}
110
+ exitStyle={{ opacity: 0, y: -4 }}
111
+ bg="$color4"
112
+ rounded="$4"
113
+ px="$4"
114
+ py="$3"
115
+ >
116
+ <SizableText id="safepoly-text">Popover content (safePolygon)</SizableText>
117
+ </Popover.Content>
118
+ </Popover>
119
+ </YStack>
120
+ )
121
+ }
122
+
123
+ export function PopoverHoverableExitAnimCase() {
124
+ return (
125
+ <YStack padding="$10" alignItems="center" gap="$4">
126
+ <SizableText size="$3" color="$color9">
127
+ Exit animation: should animate out (not instant disappear)
128
+ </SizableText>
129
+
130
+ {/* target to move mouse to - far from popover */}
131
+ <XStack id="away-target" position="absolute" bottom="$4" left="$4" opacity={0.01}>
132
+ <SizableText>away</SizableText>
133
+ </XStack>
134
+
135
+ <Popover placement="bottom" hoverable offset={8}>
136
+ <Popover.Trigger asChild>
137
+ <XStack
138
+ id="exitanim-trigger"
139
+ px="$4"
140
+ py="$2"
141
+ bg="$color3"
142
+ rounded="$4"
143
+ cursor="pointer"
144
+ >
145
+ <SizableText>Hover me (exit animation)</SizableText>
146
+ </XStack>
147
+ </Popover.Trigger>
148
+ <Popover.Content
149
+ id="exitanim-content"
150
+ disableFocusScope
151
+ unstyled
152
+ transition="500ms"
153
+ animateOnly={['opacity', 'transform']}
154
+ opacity={1}
155
+ enterStyle={{ opacity: 0, y: -4 }}
156
+ exitStyle={{ opacity: 0, y: -4 }}
157
+ bg="$color4"
158
+ rounded="$4"
159
+ px="$4"
160
+ py="$3"
161
+ >
162
+ <SizableText>Popover content (exit anim test)</SizableText>
163
+ </Popover.Content>
164
+ </Popover>
165
+ </YStack>
166
+ )
167
+ }
@@ -0,0 +1,118 @@
1
+ import { useState } from 'react'
2
+ import { Popover, YStack, SizableText, XStack } from '@hanzo/gui'
3
+
4
+ /**
5
+ * Tests the disablePressTrigger prop on Popover.Trigger.
6
+ *
7
+ * Bug scenario: hoverable popover where user dismisses via onPressIn.
8
+ * Without disablePressTrigger, the built-in onPress handler fires after onPressIn
9
+ * and re-opens the popover (state oscillation: close → open → close).
10
+ *
11
+ * With disablePressTrigger, the trigger's built-in click toggle is suppressed,
12
+ * so the user's onPressIn dismiss works cleanly.
13
+ */
14
+
15
+ export function PopoverHoverableDisableClickCase() {
16
+ const [open, setOpen] = useState(false)
17
+ const [log, setLog] = useState<string[]>([])
18
+
19
+ const addLog = (msg: string) => {
20
+ setLog((prev) => [...prev.slice(-9), msg])
21
+ }
22
+
23
+ return (
24
+ <YStack padding="$10" alignItems="center" gap="$4">
25
+ <SizableText size="$3" color="$color9">
26
+ Hoverable popover with disablePressTrigger - clicking should dismiss via onPressIn
27
+ only
28
+ </SizableText>
29
+
30
+ <Popover
31
+ placement="bottom"
32
+ hoverable={{ delay: 0 }}
33
+ offset={8}
34
+ open={open}
35
+ onOpenChange={(next) => {
36
+ addLog(`onOpenChange: ${next}`)
37
+ setOpen(next)
38
+ }}
39
+ >
40
+ <Popover.Trigger
41
+ asChild
42
+ disablePressTrigger
43
+ onPressIn={() => {
44
+ if (open) {
45
+ addLog('onPressIn: dismissing')
46
+ setOpen(false)
47
+ }
48
+ }}
49
+ >
50
+ <XStack
51
+ id="disableclick-trigger"
52
+ px="$4"
53
+ py="$2"
54
+ bg="$color3"
55
+ rounded="$4"
56
+ cursor="pointer"
57
+ >
58
+ <SizableText>Hover me (disablePressTrigger)</SizableText>
59
+ </XStack>
60
+ </Popover.Trigger>
61
+ <Popover.Content
62
+ id="disableclick-content"
63
+ disableFocusScope
64
+ unstyled
65
+ transition="200ms"
66
+ animateOnly={['opacity', 'transform']}
67
+ enterStyle={{ opacity: 0, y: -4 }}
68
+ exitStyle={{ opacity: 0, y: -4 }}
69
+ bg="$color4"
70
+ rounded="$4"
71
+ px="$4"
72
+ py="$3"
73
+ >
74
+ <SizableText>Popover content (disablePressTrigger test)</SizableText>
75
+ </Popover.Content>
76
+ </Popover>
77
+
78
+ {/* without disablePressTrigger for comparison */}
79
+ <Popover placement="bottom" hoverable={{ delay: 0 }} offset={8}>
80
+ <Popover.Trigger asChild>
81
+ <XStack
82
+ id="withclick-trigger"
83
+ px="$4"
84
+ py="$2"
85
+ bg="$color3"
86
+ rounded="$4"
87
+ cursor="pointer"
88
+ >
89
+ <SizableText>Hover me (normal click)</SizableText>
90
+ </XStack>
91
+ </Popover.Trigger>
92
+ <Popover.Content
93
+ id="withclick-content"
94
+ disableFocusScope
95
+ unstyled
96
+ transition="200ms"
97
+ animateOnly={['opacity', 'transform']}
98
+ enterStyle={{ opacity: 0, y: -4 }}
99
+ exitStyle={{ opacity: 0, y: -4 }}
100
+ bg="$color4"
101
+ rounded="$4"
102
+ px="$4"
103
+ py="$3"
104
+ >
105
+ <SizableText>Popover content (normal click)</SizableText>
106
+ </Popover.Content>
107
+ </Popover>
108
+
109
+ <YStack id="open-state-log" gap="$1" mt="$4">
110
+ {log.map((entry, i) => (
111
+ <SizableText key={i} size="$2" color="$color8" fontFamily="$mono">
112
+ {entry}
113
+ </SizableText>
114
+ ))}
115
+ </YStack>
116
+ </YStack>
117
+ )
118
+ }
@@ -0,0 +1,103 @@
1
+ import { useState, useCallback, useRef } from 'react'
2
+ import { Popover, YStack, SizableText, XStack } from '@hanzo/gui'
3
+
4
+ // test case: rapidly moving across many side-by-side triggers with short restMs
5
+ // should track the hovered trigger, not get "stuck" on a past one
6
+
7
+ type NavId = 'a' | 'b' | 'c' | 'd' | 'e' | 'f'
8
+ const NAV_IDS: NavId[] = ['a', 'b', 'c', 'd', 'e', 'f']
9
+
10
+ export function PopoverHoverableRapidCase() {
11
+ const [open, setOpen] = useState(false)
12
+ const [activeId, setActiveId] = useState<NavId | null>(null)
13
+ const prevIdRef = useRef<NavId | null>(null)
14
+ const displayId = activeId || prevIdRef.current
15
+
16
+ const handleEnter = useCallback(
17
+ (id: NavId) => {
18
+ if (id !== activeId) {
19
+ prevIdRef.current = activeId
20
+ setActiveId(id)
21
+ }
22
+ },
23
+ [activeId]
24
+ )
25
+
26
+ return (
27
+ <YStack padding="$4" gap="$4">
28
+ <SizableText size="$3" color="$color9">
29
+ Rapid hover across many triggers - should track current trigger
30
+ </SizableText>
31
+
32
+ <YStack height={60} />
33
+
34
+ <Popover
35
+ scope="rapid"
36
+ open={open}
37
+ onOpenChange={setOpen}
38
+ hoverable={{ restMs: 60, delay: 0 }}
39
+ offset={8}
40
+ placement="bottom"
41
+ >
42
+ {/* larger gaps to expose the race condition - mouse must cross gap */}
43
+ <XStack gap="$6" id="rapid-triggers">
44
+ {NAV_IDS.map((id) => (
45
+ <Popover.Trigger
46
+ key={id}
47
+ scope="rapid"
48
+ display="contents"
49
+ asChild="except-style"
50
+ onMouseEnter={() => handleEnter(id)}
51
+ >
52
+ <XStack
53
+ id={`rapid-trigger-${id}`}
54
+ px="$4"
55
+ py="$2"
56
+ bg={open && displayId === id ? '$color5' : '$color3'}
57
+ rounded="$4"
58
+ cursor="pointer"
59
+ hoverStyle={{ bg: '$color4' }}
60
+ >
61
+ <SizableText>{id.toUpperCase()}</SizableText>
62
+ </XStack>
63
+ </Popover.Trigger>
64
+ ))}
65
+ </XStack>
66
+
67
+ <Popover.Content
68
+ id="rapid-content"
69
+ scope="rapid"
70
+ unstyled
71
+ disableFocusScope
72
+ transition="100ms"
73
+ animateOnly={['transform', 'opacity']}
74
+ opacity={1}
75
+ enterStyle={{ y: -4, opacity: 0 }}
76
+ exitStyle={{ y: 4, opacity: 0 }}
77
+ width={200}
78
+ height={80}
79
+ >
80
+ <YStack
81
+ bg="$color2"
82
+ rounded="$5"
83
+ outlineColor="$color4"
84
+ outlineWidth={1}
85
+ outlineStyle="solid"
86
+ width={200}
87
+ height={80}
88
+ overflow="hidden"
89
+ position="relative"
90
+ alignItems="center"
91
+ justifyContent="center"
92
+ >
93
+ {displayId && (
94
+ <SizableText id="rapid-panel-label" size="$5" fontWeight="600">
95
+ Panel {displayId.toUpperCase()}
96
+ </SizableText>
97
+ )}
98
+ </YStack>
99
+ </Popover.Content>
100
+ </Popover>
101
+ </YStack>
102
+ )
103
+ }
@@ -0,0 +1,135 @@
1
+ import { useState, useCallback, useRef } from 'react'
2
+ import { AnimatePresence, Popover, YStack, SizableText, XStack, styled } from '@hanzo/gui'
3
+
4
+ // mirrors the WebsiteHeader pattern:
5
+ // - controlled open state
6
+ // - scope + multiple triggers
7
+ // - hoverable with delay/restMs
8
+ // - animated content panels with AnimatePresence inside
9
+
10
+ type NavId = 'about' | 'blog' | 'contact'
11
+ const NAV_IDS: NavId[] = ['about', 'blog', 'contact']
12
+
13
+ const PanelFrame = styled(YStack, {
14
+ position: 'absolute',
15
+ inset: 0,
16
+ padding: '$4',
17
+ opacity: 1,
18
+ x: 0,
19
+ variants: {
20
+ going: {
21
+ ':number': (going) => ({
22
+ enterStyle: { x: going > 0 ? 80 : -80, opacity: 0 },
23
+ exitStyle: { x: going < 0 ? 80 : -80, opacity: 0 },
24
+ }),
25
+ },
26
+ } as const,
27
+ })
28
+
29
+ export function PopoverHoverableScopedCase() {
30
+ const [open, setOpen] = useState(false)
31
+ const [activeId, setActiveId] = useState<NavId | null>(null)
32
+ const [going, setGoing] = useState(0)
33
+ const prevIdRef = useRef<NavId | null>(null)
34
+ const displayId = activeId || prevIdRef.current
35
+
36
+ const handleEnter = useCallback(
37
+ (id: NavId) => {
38
+ if (id !== activeId) {
39
+ if (activeId) {
40
+ const pi = NAV_IDS.indexOf(activeId)
41
+ const ni = NAV_IDS.indexOf(id)
42
+ setGoing(ni > pi ? 1 : -1)
43
+ }
44
+ prevIdRef.current = activeId
45
+ setActiveId(id)
46
+ }
47
+ },
48
+ [activeId]
49
+ )
50
+
51
+ return (
52
+ <YStack padding="$4" gap="$4">
53
+ <SizableText size="$3" color="$color9">
54
+ Scoped hoverable popover - mirrors WebsiteHeader pattern
55
+ </SizableText>
56
+
57
+ {/* large spacer so popover content opens in a clear area below triggers */}
58
+ <YStack height={60} />
59
+
60
+ <Popover
61
+ scope="nav"
62
+ open={open}
63
+ onOpenChange={setOpen}
64
+ hoverable={{ delay: 300, restMs: 300 }}
65
+ offset={8}
66
+ placement="bottom"
67
+ >
68
+ <XStack gap="$2" id="nav-triggers">
69
+ {NAV_IDS.map((id) => (
70
+ <Popover.Trigger
71
+ key={id}
72
+ scope="nav"
73
+ display="contents"
74
+ asChild="except-style"
75
+ onMouseEnter={() => handleEnter(id)}
76
+ >
77
+ <XStack
78
+ id={`nav-trigger-${id}`}
79
+ px="$4"
80
+ py="$2"
81
+ bg={open && displayId === id ? '$color4' : '$color3'}
82
+ rounded="$4"
83
+ cursor="pointer"
84
+ hoverStyle={{ bg: '$color4' }}
85
+ >
86
+ <SizableText>{id.charAt(0).toUpperCase() + id.slice(1)}</SizableText>
87
+ </XStack>
88
+ </Popover.Trigger>
89
+ ))}
90
+ </XStack>
91
+
92
+ <Popover.Content
93
+ id="nav-content"
94
+ scope="nav"
95
+ unstyled
96
+ disableFocusScope
97
+ animatePosition
98
+ transition="500ms"
99
+ animateOnly={['transform', 'opacity']}
100
+ opacity={1}
101
+ enterStyle={{ y: -6, opacity: 0 }}
102
+ exitStyle={{ y: 4, opacity: 0 }}
103
+ width={300}
104
+ height={200}
105
+ >
106
+ {/* bounding wrapper so position:absolute panels don't escape to the portal root */}
107
+ <YStack
108
+ bg="$color2"
109
+ rounded="$5"
110
+ outlineColor="$color4"
111
+ outlineWidth={1}
112
+ outlineStyle="solid"
113
+ width={300}
114
+ height={200}
115
+ overflow="hidden"
116
+ position="relative"
117
+ >
118
+ <AnimatePresence initial={false} custom={{ going }}>
119
+ {displayId && (
120
+ <PanelFrame key={displayId} going={going}>
121
+ <SizableText id={`nav-panel-${displayId}`} size="$5" fontWeight="600">
122
+ {displayId.charAt(0).toUpperCase() + displayId.slice(1)} Panel
123
+ </SizableText>
124
+ <SizableText size="$3" color="$color9">
125
+ Content for {displayId}
126
+ </SizableText>
127
+ </PanelFrame>
128
+ )}
129
+ </AnimatePresence>
130
+ </YStack>
131
+ </Popover.Content>
132
+ </Popover>
133
+ </YStack>
134
+ )
135
+ }
@@ -0,0 +1,76 @@
1
+ import { Adapt, Button, Paragraph, Popover, Sheet, XStack, YStack } from '@hanzo/gui'
2
+
3
+ export function PopoverScopedCase() {
4
+ const shouldAdapt = window.location.search.includes('adapt=true')
5
+
6
+ return (
7
+ <YStack padding="$4" gap="$4">
8
+ <Popover size="$5" allowFlip stayInFrame offset={15} resize>
9
+ <TestPopoverContent shouldAdapt={shouldAdapt} name="plain" />
10
+ <Popover.Trigger asChild>
11
+ <Button data-testid={`plain-trigger`}>Open Plain</Button>
12
+ </Popover.Trigger>
13
+ </Popover>
14
+
15
+ <Popover scope="PopoverA" size="$5" allowFlip stayInFrame offset={15} resize>
16
+ <TestPopoverContent shouldAdapt={shouldAdapt} name="a" />
17
+
18
+ <Popover scope="PopoverB" size="$5" allowFlip stayInFrame offset={15} resize>
19
+ <TestPopoverContent shouldAdapt={shouldAdapt} name="b" />
20
+
21
+ <Popover.Trigger asChild scope="PopoverA">
22
+ <Button data-testid={`a-trigger`}>Open A</Button>
23
+ </Popover.Trigger>
24
+
25
+ <Popover.Trigger asChild scope="PopoverB">
26
+ <Button data-testid={`b-trigger`}>Open B</Button>
27
+ </Popover.Trigger>
28
+ </Popover>
29
+ </Popover>
30
+ </YStack>
31
+ )
32
+ }
33
+
34
+ const TestPopoverContent = ({ name, shouldAdapt }) => {
35
+ return (
36
+ <>
37
+ <Popover.Content
38
+ borderWidth={1}
39
+ borderColor="$borderColor"
40
+ width={300}
41
+ height={300}
42
+ elevate
43
+ >
44
+ <Popover.Arrow borderWidth={1} borderColor="$borderColor" />
45
+
46
+ <YStack data-testid={`${name}-popover-content`} gap="$3">
47
+ <XStack gap="$3">
48
+ <Paragraph size="$3">Popover {name}</Paragraph>
49
+ </XStack>
50
+
51
+ <Popover.Close asChild>
52
+ <Button size="$3" data-testid={`popover-close`}>
53
+ Close
54
+ </Button>
55
+ </Popover.Close>
56
+ </YStack>
57
+ </Popover.Content>
58
+
59
+ {shouldAdapt && (
60
+ <Adapt when={true}>
61
+ <Sheet transition="medium" modal dismissOnSnapToBottom>
62
+ <Sheet.Frame data-testid={`${name}-sheet-contents`} padding="$4">
63
+ <Adapt.Contents />
64
+ </Sheet.Frame>
65
+ <Sheet.Overlay
66
+ backgroundColor="$shadowColor"
67
+ transition="lazy"
68
+ enterStyle={{ opacity: 0 }}
69
+ exitStyle={{ opacity: 0 }}
70
+ />
71
+ </Sheet>
72
+ </Adapt>
73
+ )}
74
+ </>
75
+ )
76
+ }
@@ -0,0 +1,80 @@
1
+ import { memo, useRef, useState } from 'react'
2
+ import { Button, Paragraph, Popover, XStack, YStack, Text, View } from '@hanzo/gui'
3
+
4
+ /**
5
+ * Test case for Popover trigger render isolation
6
+ *
7
+ * With push-based registration, only the ACTIVE trigger re-renders when
8
+ * the popover opens - other triggers stay untouched.
9
+ */
10
+
11
+ // component that tracks its render count - must be memoized to isolate from parent re-renders
12
+ const RenderCountingTrigger = memo(function RenderCountingTrigger({
13
+ testId,
14
+ label,
15
+ scope,
16
+ }: {
17
+ testId: string
18
+ label: string
19
+ scope: string
20
+ }) {
21
+ const renderCountRef = useRef(0)
22
+ renderCountRef.current++
23
+
24
+ return (
25
+ <View>
26
+ <Popover.Trigger scope={scope} asChild>
27
+ <Button data-testid={testId}>{label}</Button>
28
+ </Popover.Trigger>
29
+ <Text data-testid={`${testId}-render-count`} fontSize="$1" textAlign="center">
30
+ renders: {renderCountRef.current}
31
+ </Text>
32
+ </View>
33
+ )
34
+ })
35
+
36
+ export function PopoverTriggerIsolationCase() {
37
+ const [open, setOpen] = useState(false)
38
+
39
+ return (
40
+ <YStack flex={1} gap="$6" p="$4" bg="$background">
41
+ <Text fontWeight="bold">Trigger isolation: only active trigger re-renders</Text>
42
+
43
+ <Popover scope="isolated" open={open} onOpenChange={setOpen}>
44
+ <XStack gap="$4" justifyContent="center">
45
+ <RenderCountingTrigger
46
+ testId="isolated-trigger-1"
47
+ label="Trigger 1"
48
+ scope="isolated"
49
+ />
50
+ <RenderCountingTrigger
51
+ testId="isolated-trigger-2"
52
+ label="Trigger 2"
53
+ scope="isolated"
54
+ />
55
+ <RenderCountingTrigger
56
+ testId="isolated-trigger-3"
57
+ label="Trigger 3"
58
+ scope="isolated"
59
+ />
60
+ </XStack>
61
+
62
+ <Popover.Content
63
+ scope="isolated"
64
+ data-testid="isolated-popover-content"
65
+ enterStyle={{ y: -10, opacity: 0 }}
66
+ exitStyle={{ y: -10, opacity: 0 }}
67
+ p="$4"
68
+ >
69
+ <Popover.Arrow scope="isolated" />
70
+ <Paragraph>Shared popover content</Paragraph>
71
+ <Popover.Close scope="isolated" asChild>
72
+ <Button data-testid="isolated-close" size="$2" mt="$2">
73
+ Close
74
+ </Button>
75
+ </Popover.Close>
76
+ </Popover.Content>
77
+ </Popover>
78
+ </YStack>
79
+ )
80
+ }