@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,46 @@
1
+ import { Toast, ToastProvider, ToastViewport } from '@hanzogui/toast'
2
+ import React from 'react'
3
+ import { Button, YStack } from '@hanzo/gui'
4
+
5
+ export function ToastCase() {
6
+ const [count, setCount] = React.useState(0)
7
+
8
+ return (
9
+ <ToastProvider>
10
+ <Button
11
+ data-testid="button-add-toast"
12
+ onPress={() => setCount((count) => count + 1)}
13
+ >
14
+ Add toast
15
+ </Button>
16
+ <YStack maxWidth={700} margin={'auto'}>
17
+ <Button data-testid="button-before">Focusable before viewport</Button>
18
+
19
+ {[...Array(count)].map((_, index) => {
20
+ const identifier = index + 1
21
+ return (
22
+ <Toast key={index} open data-testid={`toast-${identifier}`}>
23
+ <Toast.Title>Toast {identifier} title</Toast.Title>
24
+ <Toast.Description>Toast {identifier} description</Toast.Description>
25
+
26
+ <Toast.Close aria-label="Close" asChild>
27
+ <Button
28
+ data-testid={`toast-button-${identifier}.1`}
29
+ >{`Toast button ${identifier}.1`}</Button>
30
+ </Toast.Close>
31
+ <Toast.Action altText="Go and perform an action" mt="$2" asChild>
32
+ <Button
33
+ data-testid={`toast-button-${identifier}.2`}
34
+ >{`Toast button ${identifier}.2`}</Button>
35
+ </Toast.Action>
36
+ </Toast>
37
+ )
38
+ })}
39
+
40
+ <ToastViewport />
41
+
42
+ <Button data-testid="button-after">Focusable after viewport</Button>
43
+ </YStack>
44
+ </ToastProvider>
45
+ )
46
+ }
@@ -0,0 +1,40 @@
1
+ import React from 'react'
2
+ import { SizableText, ToggleGroup, YStack, useToggleGroupItem } from '@hanzo/gui'
3
+
4
+ // Issue #3485: ToggleGroup active prop passed to children
5
+ // Children of ToggleGroup.Item can access active state via useToggleGroupItem hook
6
+
7
+ const CustomItem = ({ children }: { children: React.ReactNode }) => {
8
+ const { active } = useToggleGroupItem()
9
+ return (
10
+ <SizableText id={`custom-item-${children}`} data-active={active ? 'true' : 'false'}>
11
+ {children}
12
+ </SizableText>
13
+ )
14
+ }
15
+
16
+ export function ToggleGroupActiveProps() {
17
+ const [value, setValue] = React.useState('option1')
18
+
19
+ return (
20
+ <YStack p="$4" gap="$4">
21
+ <ToggleGroup
22
+ id="toggle-group"
23
+ type="single"
24
+ value={value}
25
+ onValueChange={(val) => val && setValue(val)}
26
+ disableDeactivation
27
+ >
28
+ <ToggleGroup.Item value="option1" id="item-1">
29
+ <CustomItem>option1</CustomItem>
30
+ </ToggleGroup.Item>
31
+ <ToggleGroup.Item value="option2" id="item-2">
32
+ <CustomItem>option2</CustomItem>
33
+ </ToggleGroup.Item>
34
+ <ToggleGroup.Item value="option3" id="item-3">
35
+ <CustomItem>option3</CustomItem>
36
+ </ToggleGroup.Item>
37
+ </ToggleGroup>
38
+ </YStack>
39
+ )
40
+ }
@@ -0,0 +1,104 @@
1
+ import { useState } from 'react'
2
+ import { Button, ToggleGroup, XGroup, YStack, Text } from '@hanzo/gui'
3
+ import { AlignLeft, AlignCenter, AlignRight } from '@hanzogui/lucide-icons-2'
4
+
5
+ /**
6
+ * Tests two patterns of combining ToggleGroup + XGroup:
7
+ *
8
+ * Pattern A: XGroup.Item wraps ToggleGroup.Item (demo pattern)
9
+ * - XGroup provides border radius management
10
+ * - ToggleGroup.Item handles toggle logic
11
+ * - Radius styles should flow from XGroup.Item to ToggleGroup.Item
12
+ *
13
+ * Pattern B: ToggleGroup.Item asChild wraps XGroup.Item (showcase pattern)
14
+ * - ToggleGroup.Item uses asChild to delegate rendering to XGroup.Item
15
+ * - XGroup.Item wraps Button which renders the visual element
16
+ * - Press events must flow from ToggleGroup.Item through XGroup.Item to Button
17
+ */
18
+ export function ToggleGroupXGroupCase() {
19
+ const [patternAValue, setPatternAValue] = useState<string>('')
20
+ const [patternBValue, setPatternBValue] = useState<string>('')
21
+
22
+ return (
23
+ <YStack gap="$8" p="$4">
24
+ {/* Pattern A: XGroup.Item > ToggleGroup.Item */}
25
+ <YStack gap="$2">
26
+ <Text>Pattern A: XGroup.Item wraps ToggleGroup.Item</Text>
27
+ <Text fontSize="$2" color="$color10">
28
+ value: {patternAValue || 'none'}
29
+ </Text>
30
+ <ToggleGroup
31
+ type="single"
32
+ value={patternAValue}
33
+ onValueChange={setPatternAValue}
34
+ testID="pattern-a-toggle-group"
35
+ >
36
+ <XGroup rounded="$10" testID="pattern-a-xgroup">
37
+ <XGroup.Item>
38
+ <ToggleGroup.Item
39
+ value="left"
40
+ aria-label="Left"
41
+ testID="pattern-a-left"
42
+ borderRadius="$10"
43
+ >
44
+ <AlignLeft size={16} />
45
+ </ToggleGroup.Item>
46
+ </XGroup.Item>
47
+ <XGroup.Item>
48
+ <ToggleGroup.Item
49
+ value="center"
50
+ aria-label="Center"
51
+ testID="pattern-a-center"
52
+ borderRadius="$10"
53
+ >
54
+ <AlignCenter size={16} />
55
+ </ToggleGroup.Item>
56
+ </XGroup.Item>
57
+ <XGroup.Item>
58
+ <ToggleGroup.Item
59
+ value="right"
60
+ aria-label="Right"
61
+ testID="pattern-a-right"
62
+ borderRadius="$10"
63
+ >
64
+ <AlignRight size={16} />
65
+ </ToggleGroup.Item>
66
+ </XGroup.Item>
67
+ </XGroup>
68
+ </ToggleGroup>
69
+ </YStack>
70
+
71
+ {/* Pattern B: ToggleGroup.Item asChild > XGroup.Item > Button */}
72
+ <YStack gap="$2">
73
+ <Text>Pattern B: ToggleGroup.Item asChild wraps XGroup.Item</Text>
74
+ <Text fontSize="$2" color="$color10">
75
+ value: {patternBValue || 'none'}
76
+ </Text>
77
+ <ToggleGroup
78
+ type="single"
79
+ value={patternBValue}
80
+ onValueChange={setPatternBValue}
81
+ testID="pattern-b-toggle-group"
82
+ >
83
+ <XGroup rounded="$10" testID="pattern-b-xgroup">
84
+ <ToggleGroup.Item value="left" aria-label="Left" asChild>
85
+ <XGroup.Item>
86
+ <Button testID="pattern-b-left" size="$3" icon={AlignLeft} />
87
+ </XGroup.Item>
88
+ </ToggleGroup.Item>
89
+ <ToggleGroup.Item value="center" aria-label="Center" asChild>
90
+ <XGroup.Item>
91
+ <Button testID="pattern-b-center" size="$3" icon={AlignCenter} />
92
+ </XGroup.Item>
93
+ </ToggleGroup.Item>
94
+ <ToggleGroup.Item value="right" aria-label="Right" asChild>
95
+ <XGroup.Item>
96
+ <Button testID="pattern-b-right" size="$3" icon={AlignRight} />
97
+ </XGroup.Item>
98
+ </ToggleGroup.Item>
99
+ </XGroup>
100
+ </ToggleGroup>
101
+ </YStack>
102
+ </YStack>
103
+ )
104
+ }
@@ -0,0 +1,99 @@
1
+ import { useState } from 'react'
2
+ import { Button, Paragraph, Tooltip, YStack, XStack } from '@hanzo/gui'
3
+
4
+ /**
5
+ * Test case for validating CSS tooltip animation behavior
6
+ *
7
+ * Tests:
8
+ * 1. Enter animation - y translation and opacity should animate smoothly with intermediate values
9
+ * 2. Exit animation - should fade out and translate with intermediate values
10
+ * 3. First show vs subsequent shows - should behave identically
11
+ * 4. Arrow size validation
12
+ *
13
+ * Uses 1000ms animation for reliable intermediate state capture (same as AnimationBehavior tests)
14
+ */
15
+ export function TooltipAnimationCase() {
16
+ const [showCount, setShowCount] = useState(0)
17
+
18
+ return (
19
+ <YStack
20
+ flex={1}
21
+ gap="$8"
22
+ p="$4"
23
+ bg="$background"
24
+ alignItems="center"
25
+ justifyContent="center"
26
+ >
27
+ <XStack gap="$4">
28
+ <Paragraph data-testid="show-count">Show count: {showCount}</Paragraph>
29
+ </XStack>
30
+
31
+ {/* Main tooltip for animation testing - uses 1000ms animation for reliable intermediate capture */}
32
+ <Tooltip
33
+ placement="bottom"
34
+ delay={0}
35
+ restMs={0}
36
+ onOpenChange={(open) => {
37
+ if (open) setShowCount((c) => c + 1)
38
+ }}
39
+ >
40
+ <Tooltip.Trigger data-testid="tooltip-trigger">
41
+ <Button size="$4">Hover for tooltip</Button>
42
+ </Tooltip.Trigger>
43
+
44
+ <Tooltip.Content
45
+ data-testid="tooltip-content"
46
+ enterStyle={{ y: -20, opacity: 0 }}
47
+ exitStyle={{ y: -20, opacity: 0 }}
48
+ y={0}
49
+ opacity={1}
50
+ transition="lazy"
51
+ animateOnly={['transform', 'opacity']}
52
+ >
53
+ <Tooltip.Arrow data-testid="tooltip-arrow" size="$2" />
54
+ <Paragraph size="$2">Tooltip content</Paragraph>
55
+ </Tooltip.Content>
56
+ </Tooltip>
57
+
58
+ {/* Second tooltip to test first vs subsequent shows */}
59
+ <Tooltip placement="top" delay={0} restMs={0}>
60
+ <Tooltip.Trigger data-testid="tooltip-trigger-2">
61
+ <Button size="$4">Second tooltip</Button>
62
+ </Tooltip.Trigger>
63
+
64
+ <Tooltip.Content
65
+ data-testid="tooltip-content-2"
66
+ enterStyle={{ y: 20, opacity: 0 }}
67
+ exitStyle={{ y: 20, opacity: 0 }}
68
+ y={0}
69
+ opacity={1}
70
+ transition="lazy"
71
+ animateOnly={['transform', 'opacity']}
72
+ >
73
+ <Tooltip.Arrow data-testid="tooltip-arrow-2" size="$2" />
74
+ <Paragraph size="$2">Second tooltip</Paragraph>
75
+ </Tooltip.Content>
76
+ </Tooltip>
77
+
78
+ {/* Quick animation tooltip for comparison - 100ms */}
79
+ <Tooltip placement="right" delay={0} restMs={0}>
80
+ <Tooltip.Trigger data-testid="tooltip-trigger-quick">
81
+ <Button size="$4">Quick animation (100ms)</Button>
82
+ </Tooltip.Trigger>
83
+
84
+ <Tooltip.Content
85
+ data-testid="tooltip-content-quick"
86
+ enterStyle={{ x: -20, opacity: 0 }}
87
+ exitStyle={{ x: -20, opacity: 0 }}
88
+ x={0}
89
+ opacity={1}
90
+ transition="100ms"
91
+ animateOnly={['transform', 'opacity']}
92
+ >
93
+ <Tooltip.Arrow data-testid="tooltip-arrow-quick" size="$3" />
94
+ <Paragraph size="$2">Quick tooltip</Paragraph>
95
+ </Tooltip.Content>
96
+ </Tooltip>
97
+ </YStack>
98
+ )
99
+ }
@@ -0,0 +1,32 @@
1
+ import { Button, Paragraph, Tooltip, TooltipSimple, YStack } from '@hanzo/gui'
2
+
3
+ export function TooltipCase() {
4
+ return (
5
+ <YStack flex={1} gap="$8" p="$4" bg="$background">
6
+ <TooltipComp />
7
+
8
+ <TooltipSimple label="wtf">
9
+ <Button>simple tool</Button>
10
+ </TooltipSimple>
11
+ </YStack>
12
+ )
13
+ }
14
+
15
+ function TooltipComp() {
16
+ return (
17
+ <Tooltip placement="bottom">
18
+ <Tooltip.Trigger>
19
+ <Button>with tooltip</Button>
20
+ </Tooltip.Trigger>
21
+
22
+ <Tooltip.Content
23
+ enterStyle={{ x: 0, y: -4, opacity: 0, scale: 0.96 }}
24
+ exitStyle={{ x: 0, y: -4, opacity: 0, scale: 0.96 }}
25
+ transition="bouncy"
26
+ >
27
+ <Tooltip.Arrow />
28
+ <Paragraph>some tooltip</Paragraph>
29
+ </Tooltip.Content>
30
+ </Tooltip>
31
+ )
32
+ }
@@ -0,0 +1,83 @@
1
+ import { Button, Paragraph, Tooltip, TooltipGroup, YStack, XStack } from '@hanzo/gui'
2
+ import { useState } from 'react'
3
+
4
+ /**
5
+ * Test case for "global tooltip" pattern: a single scoped tooltip with
6
+ * triggers in opposite corners.
7
+ *
8
+ * Bug: when switching between far-apart triggers, the tooltip animates
9
+ * across the screen instead of snapping to the new position.
10
+ */
11
+ export function TooltipGlobalPatternCase() {
12
+ const [label, setLabel] = useState('')
13
+
14
+ return (
15
+ <YStack flex={1} bg="$background" p="$4" minHeight={600} minWidth={800}>
16
+ <TooltipGroup delay={{ open: 0, close: 150 }}>
17
+ <Tooltip scope="global-tip" offset={12} placement="bottom">
18
+ <YStack flex={1} justifyContent="space-between">
19
+ <XStack justifyContent="space-between">
20
+ <Tooltip.Trigger
21
+ scope="global-tip"
22
+ asChild
23
+ onMouseEnter={() => setLabel('Top Left')}
24
+ >
25
+ <Button data-testid="trigger-tl" size="$4">
26
+ Top Left
27
+ </Button>
28
+ </Tooltip.Trigger>
29
+
30
+ <Tooltip.Trigger
31
+ scope="global-tip"
32
+ asChild
33
+ onMouseEnter={() => setLabel('Top Right')}
34
+ >
35
+ <Button data-testid="trigger-tr" size="$4">
36
+ Top Right
37
+ </Button>
38
+ </Tooltip.Trigger>
39
+ </XStack>
40
+
41
+ <XStack justifyContent="space-between">
42
+ <Tooltip.Trigger
43
+ scope="global-tip"
44
+ asChild
45
+ onMouseEnter={() => setLabel('Bottom Left')}
46
+ >
47
+ <Button data-testid="trigger-bl" size="$4">
48
+ Bottom Left
49
+ </Button>
50
+ </Tooltip.Trigger>
51
+
52
+ <Tooltip.Trigger
53
+ scope="global-tip"
54
+ asChild
55
+ onMouseEnter={() => setLabel('Bottom Right')}
56
+ >
57
+ <Button data-testid="trigger-br" size="$4">
58
+ Bottom Right
59
+ </Button>
60
+ </Tooltip.Trigger>
61
+ </XStack>
62
+ </YStack>
63
+
64
+ <Tooltip.Content
65
+ data-testid="global-tip-content"
66
+ animatePosition
67
+ transition="200ms"
68
+ bg="$background"
69
+ elevation="$2"
70
+ rounded="$4"
71
+ px="$2.5"
72
+ py="$1"
73
+ enterStyle={{ y: -4, opacity: 0 }}
74
+ exitStyle={{ y: -4, opacity: 0 }}
75
+ >
76
+ <Tooltip.Arrow />
77
+ <Paragraph size="$3">{label}</Paragraph>
78
+ </Tooltip.Content>
79
+ </Tooltip>
80
+ </TooltipGroup>
81
+ </YStack>
82
+ )
83
+ }
@@ -0,0 +1,102 @@
1
+ import {
2
+ Button,
3
+ Paragraph,
4
+ Tooltip,
5
+ TooltipGroup,
6
+ XStack,
7
+ YStack,
8
+ Text,
9
+ } from '@hanzo/gui'
10
+
11
+ /**
12
+ * Test case for TooltipGroup behavior
13
+ *
14
+ * TooltipGroup should:
15
+ * 1. Apply delay only to the first tooltip shown
16
+ * 2. Show subsequent tooltips immediately when hovering between them
17
+ */
18
+ export function TooltipGroupCase() {
19
+ return (
20
+ <YStack flex={1} gap="$6" p="$4" bg="$background">
21
+ <Text fontWeight="bold">Grouped (1s delay, skip on subsequent):</Text>
22
+ <TooltipGroup delay={{ open: 1000, close: 200 }} timeoutMs={500}>
23
+ <XStack gap="$4" justifyContent="center">
24
+ <Tooltip groupId="1" placement="bottom" restMs={0}>
25
+ <Tooltip.Trigger data-testid="tooltip-trigger-1">
26
+ <Button>Group 1</Button>
27
+ </Tooltip.Trigger>
28
+ <Tooltip.Content
29
+ data-testid="tooltip-content-1"
30
+ enterStyle={{ y: -10, opacity: 0 }}
31
+ exitStyle={{ y: -10, opacity: 0 }}
32
+ >
33
+ <Tooltip.Arrow />
34
+ <Paragraph size="$2">Tooltip 1</Paragraph>
35
+ </Tooltip.Content>
36
+ </Tooltip>
37
+
38
+ <Tooltip groupId="2" placement="bottom" restMs={0}>
39
+ <Tooltip.Trigger data-testid="tooltip-trigger-2">
40
+ <Button>Group 2</Button>
41
+ </Tooltip.Trigger>
42
+ <Tooltip.Content
43
+ data-testid="tooltip-content-2"
44
+ enterStyle={{ y: -10, opacity: 0 }}
45
+ exitStyle={{ y: -10, opacity: 0 }}
46
+ >
47
+ <Tooltip.Arrow />
48
+ <Paragraph size="$2">Tooltip 2</Paragraph>
49
+ </Tooltip.Content>
50
+ </Tooltip>
51
+
52
+ <Tooltip groupId="3" placement="bottom" restMs={0}>
53
+ <Tooltip.Trigger data-testid="tooltip-trigger-3">
54
+ <Button>Group 3</Button>
55
+ </Tooltip.Trigger>
56
+ <Tooltip.Content
57
+ data-testid="tooltip-content-3"
58
+ enterStyle={{ y: -10, opacity: 0 }}
59
+ exitStyle={{ y: -10, opacity: 0 }}
60
+ >
61
+ <Tooltip.Arrow />
62
+ <Paragraph size="$2">Tooltip 3</Paragraph>
63
+ </Tooltip.Content>
64
+ </Tooltip>
65
+ </XStack>
66
+ </TooltipGroup>
67
+
68
+ <Text fontWeight="bold" mt="$4">
69
+ Standalone (1s delay each):
70
+ </Text>
71
+ <XStack gap="$4" justifyContent="center">
72
+ <Tooltip placement="bottom" delay={1000} restMs={0}>
73
+ <Tooltip.Trigger data-testid="tooltip-trigger-standalone-a">
74
+ <Button>Standalone A</Button>
75
+ </Tooltip.Trigger>
76
+ <Tooltip.Content
77
+ data-testid="tooltip-content-standalone-a"
78
+ enterStyle={{ y: -10, opacity: 0 }}
79
+ exitStyle={{ y: -10, opacity: 0 }}
80
+ >
81
+ <Tooltip.Arrow />
82
+ <Paragraph size="$2">Standalone A</Paragraph>
83
+ </Tooltip.Content>
84
+ </Tooltip>
85
+
86
+ <Tooltip placement="bottom" delay={1000} restMs={0}>
87
+ <Tooltip.Trigger data-testid="tooltip-trigger-standalone-b">
88
+ <Button>Standalone B</Button>
89
+ </Tooltip.Trigger>
90
+ <Tooltip.Content
91
+ data-testid="tooltip-content-standalone-b"
92
+ enterStyle={{ y: -10, opacity: 0 }}
93
+ exitStyle={{ y: -10, opacity: 0 }}
94
+ >
95
+ <Tooltip.Arrow />
96
+ <Paragraph size="$2">Standalone B</Paragraph>
97
+ </Tooltip.Content>
98
+ </Tooltip>
99
+ </XStack>
100
+ </YStack>
101
+ )
102
+ }
@@ -0,0 +1,88 @@
1
+ import { useState, useCallback, useRef } from 'react'
2
+ import { Tooltip, TooltipGroup, YStack, SizableText, XStack } from '@hanzo/gui'
3
+
4
+ // test case: matches production PromoLinksRow on gui.hanzo.ai
5
+ // single scoped tooltip with multiple triggers, animatePosition, TooltipGroup
6
+ // rapidly hovering between them should:
7
+ // 1. keep the arrow centered on the tooltip content (no displacement)
8
+ // 2. close properly when cursor leaves all triggers
9
+
10
+ type NavId = 'a' | 'b' | 'c'
11
+ const NAV_IDS: NavId[] = ['a', 'b', 'c']
12
+ const LABELS: Record<NavId, string> = {
13
+ a: 'Takeout — universal RN starter kit',
14
+ b: 'Bento — Free + paid pre-made UI',
15
+ c: 'Add Even — Expert React Native developers',
16
+ }
17
+ const SHORT: Record<NavId, string> = { a: 'First', b: 'Second', c: 'Third' }
18
+
19
+ const tooltipDelay = { open: 0, close: 150 }
20
+
21
+ export function TooltipMultiTriggerCase() {
22
+ const [activeId, setActiveId] = useState<NavId | null>(null)
23
+ const prevIdRef = useRef<NavId | null>(null)
24
+ const displayId = activeId || prevIdRef.current
25
+
26
+ const handleEnter = useCallback(
27
+ (id: NavId) => {
28
+ if (id !== activeId) {
29
+ prevIdRef.current = activeId
30
+ setActiveId(id)
31
+ }
32
+ },
33
+ [activeId]
34
+ )
35
+
36
+ return (
37
+ <YStack padding="$4" gap="$4">
38
+ <SizableText size="$3" color="$color9">
39
+ Tooltip multi-trigger rapid hover test
40
+ </SizableText>
41
+
42
+ <YStack height={80} />
43
+
44
+ <TooltipGroup delay={tooltipDelay}>
45
+ <Tooltip scope="multi-tip" offset={20} placement="bottom">
46
+ <XStack gap="$6" id="tip-triggers">
47
+ {NAV_IDS.map((id) => (
48
+ <Tooltip.Trigger
49
+ key={id}
50
+ scope="multi-tip"
51
+ asChild="except-style"
52
+ onMouseEnter={() => handleEnter(id)}
53
+ >
54
+ <XStack
55
+ id={`tip-trigger-${id}`}
56
+ px="$6"
57
+ py="$3"
58
+ bg="$color3"
59
+ rounded="$4"
60
+ cursor="pointer"
61
+ hoverStyle={{ bg: '$color4' }}
62
+ >
63
+ <SizableText>{SHORT[id]}</SizableText>
64
+ </XStack>
65
+ </Tooltip.Trigger>
66
+ ))}
67
+ </XStack>
68
+
69
+ <Tooltip.Content
70
+ id="tip-content"
71
+ scope="multi-tip"
72
+ animatePosition
73
+ transition="medium"
74
+ enterStyle={{ y: -4, opacity: 0 }}
75
+ exitStyle={{ y: -4, opacity: 0 }}
76
+ >
77
+ <Tooltip.Arrow scope="multi-tip" id="tip-arrow" />
78
+ {displayId && (
79
+ <SizableText id="tip-label" size="$3">
80
+ {LABELS[displayId || 'a']}
81
+ </SizableText>
82
+ )}
83
+ </Tooltip.Content>
84
+ </Tooltip>
85
+ </TooltipGroup>
86
+ </YStack>
87
+ )
88
+ }
@@ -0,0 +1,91 @@
1
+ import {
2
+ Button,
3
+ Paragraph,
4
+ Tooltip,
5
+ TooltipGroup,
6
+ XStack,
7
+ YStack,
8
+ SizableText,
9
+ } from '@hanzo/gui'
10
+ import { useState } from 'react'
11
+
12
+ /**
13
+ * Test case for tooltip position jump bug
14
+ *
15
+ * CRITICAL: This must match the PromoLinksRow pattern from gui.hanzo.ai:
16
+ * - Single Tooltip with scope
17
+ * - Multiple Tooltip.Triggers with same scope
18
+ * - animatePosition on Tooltip.Content
19
+ *
20
+ * The bug: When rapidly moving between triggers, the tooltip JUMPS
21
+ * to wrong position (often near origin/top-left) before animating back.
22
+ */
23
+
24
+ const buttons = [
25
+ { id: 'takeout', label: 'Takeout — universal RN starter kit' },
26
+ { id: 'bento', label: 'Bento — Free + paid pre-made UI' },
27
+ { id: 'hire', label: 'Add Even — Expert React Native developers' },
28
+ ]
29
+
30
+ export function TooltipPositionJumpCase() {
31
+ const [label, setLabel] = useState('')
32
+
33
+ return (
34
+ <YStack
35
+ flex={1}
36
+ gap="$4"
37
+ p="$4"
38
+ bg="$background"
39
+ alignItems="center"
40
+ justifyContent="center"
41
+ >
42
+ <SizableText fontWeight="bold">Tooltip Position Jump Test</SizableText>
43
+ <SizableText size="$2" color="$gray11" textAlign="center">
44
+ 1. Hover rightmost button, wait for tooltip{'\n'}
45
+ 2. Move mouse QUICKLY left across all buttons{'\n'}
46
+ 3. Watch for tooltip jumping to wrong position
47
+ </SizableText>
48
+
49
+ {/* EXACT pattern from PromoLinksRow - scoped tooltip with animatePosition */}
50
+ <TooltipGroup delay={{ open: 0, close: 150 }}>
51
+ <Tooltip scope="promo-tooltip" offset={12} placement="bottom">
52
+ <XStack gap="$3" mt="$4">
53
+ {buttons.map((btn) => (
54
+ <Tooltip.Trigger
55
+ key={btn.id}
56
+ scope="promo-tooltip"
57
+ asChild
58
+ onMouseEnter={() => setLabel(btn.label)}
59
+ >
60
+ <Button data-testid={`tooltip-trigger-${btn.id}`} size="$4">
61
+ {btn.id.toUpperCase()}
62
+ </Button>
63
+ </Tooltip.Trigger>
64
+ ))}
65
+ </XStack>
66
+
67
+ <Tooltip.Content
68
+ data-testid="tooltip-jump-content"
69
+ animatePosition
70
+ transition="quick"
71
+ bg="$background"
72
+ elevation="$2"
73
+ rounded="$4"
74
+ px="$2.5"
75
+ py="$1"
76
+ enterStyle={{ y: -4, opacity: 0 }}
77
+ exitStyle={{ y: -4, opacity: 0 }}
78
+ >
79
+ <Tooltip.Arrow />
80
+ <Paragraph size="$3">{label}</Paragraph>
81
+ </Tooltip.Content>
82
+ </Tooltip>
83
+ </TooltipGroup>
84
+
85
+ <SizableText size="$1" color="$gray9" mt="$8">
86
+ Tooltip content should animate smoothly between buttons.
87
+ {'\n'}If it JUMPS to a wrong position first, the bug is present.
88
+ </SizableText>
89
+ </YStack>
90
+ )
91
+ }