@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,481 @@
1
+ import { expect, test } from '@playwright/test'
2
+
3
+ /**
4
+ * Tests for motion driver issues on gui.hanzo.ai
5
+ *
6
+ * These tests run against the actual gui.hanzo.ai site (localhost:4444)
7
+ * to test motion driver behavior on the real site components.
8
+ *
9
+ * SKIPPED: requires gui.hanzo.ai running on localhost:4444
10
+ */
11
+
12
+ const SITE_URL = 'http://localhost:4444'
13
+
14
+ test.use({
15
+ video: 'on',
16
+ })
17
+
18
+ test.describe.skip('Gui.dev Motion Issues', () => {
19
+ test.beforeAll(async () => {
20
+ // verify site is running
21
+ })
22
+
23
+ test.describe('Logo Jitter Bug', () => {
24
+ test('dot indicator should not jitter when moving mouse rapidly across HANZO_GUI text', async ({
25
+ page,
26
+ }) => {
27
+ await page.goto(SITE_URL, { waitUntil: 'networkidle' })
28
+ await page.waitForTimeout(1000)
29
+
30
+ // find the logo-words element (in header, not footer)
31
+ const logoWords = page.locator('header .logo-words').first()
32
+ await expect(logoWords).toBeVisible()
33
+
34
+ const logoBox = await logoWords.boundingBox()
35
+ if (!logoBox) {
36
+ throw new Error('Could not find logo-words bounding box')
37
+ }
38
+
39
+ // inject position tracking for the Circle (dot indicator)
40
+ // the dot is a Circle with position absolute inside logo-words
41
+ await page.evaluate(() => {
42
+ ;(window as any).__dotPositions = []
43
+ ;(window as any).__dotDebug = { found: false, selector: null }
44
+ const track = () => {
45
+ // find the circle element inside logo-words
46
+ // it's in the header, which has render="header" so becomes a <header> tag
47
+ const header = document.querySelector('header')
48
+ if (!header) {
49
+ ;(window as any).__dotDebug.selector = 'no header found'
50
+ requestAnimationFrame(track)
51
+ return
52
+ }
53
+ const logoWords = header.querySelector('.logo-words')
54
+ if (!logoWords) {
55
+ ;(window as any).__dotDebug.selector = 'no logo-words in header'
56
+ requestAnimationFrame(track)
57
+ return
58
+ }
59
+ // the circle is the first child element with position absolute (the SVG is not absolute)
60
+ let found = false
61
+ for (const child of Array.from(logoWords.children)) {
62
+ const el = child as HTMLElement
63
+ const computed = getComputedStyle(el)
64
+ if (computed.position === 'absolute') {
65
+ found = true
66
+ ;(window as any).__dotDebug.found = true
67
+ ;(window as any).__dotDebug.selector = 'found absolute positioned child'
68
+ const transform = computed.transform
69
+ if (transform && transform !== 'none') {
70
+ const match = transform.match(
71
+ /matrix\([^,]+,\s*[^,]+,\s*[^,]+,\s*[^,]+,\s*([^,]+),\s*([^)]+)\)/
72
+ )
73
+ if (match) {
74
+ ;(window as any).__dotPositions.push({
75
+ x: parseFloat(match[1]),
76
+ y: parseFloat(match[2]),
77
+ time: Date.now(),
78
+ transform,
79
+ })
80
+ }
81
+ } else {
82
+ // transform may be in translate form or not set yet
83
+ const left = parseFloat(computed.left) || 0
84
+ const top = parseFloat(computed.top) || 0
85
+ ;(window as any).__dotPositions.push({
86
+ x: left,
87
+ y: top,
88
+ time: Date.now(),
89
+ noTransform: true,
90
+ })
91
+ }
92
+ break
93
+ }
94
+ }
95
+ if (!found) {
96
+ ;(window as any).__dotDebug.selector =
97
+ 'no absolute child - children: ' + logoWords.children.length
98
+ }
99
+ requestAnimationFrame(track)
100
+ }
101
+ requestAnimationFrame(track)
102
+ })
103
+
104
+ // hover over logo first to activate animation
105
+ const centerY = logoBox.y + logoBox.height / 2
106
+ await page.mouse.move(logoBox.x + 10, centerY)
107
+ await page.waitForTimeout(300)
108
+
109
+ // do very rapid back-and-forth to trigger jitter
110
+ // mimic user quickly flicking mouse back and forth every few frames
111
+ const screenshots: string[] = []
112
+ for (let sweep = 0; sweep < 20; sweep++) {
113
+ // quick flick right then left - this mimics the user pattern that causes jitter
114
+ // every 2-3 mouse moves we change direction
115
+ const rightX = logoBox.x + logoBox.width * 0.8
116
+ const leftX = logoBox.x + logoBox.width * 0.2
117
+ const midX = logoBox.x + logoBox.width * 0.5
118
+
119
+ // rapid: left->right->left in quick succession
120
+ await page.mouse.move(leftX, centerY)
121
+ await page.waitForTimeout(16) // ~60fps
122
+ await page.mouse.move(rightX, centerY)
123
+ await page.waitForTimeout(16)
124
+ await page.mouse.move(midX, centerY)
125
+ await page.waitForTimeout(16)
126
+
127
+ // take screenshot every few sweeps to see visual state
128
+ if (sweep % 5 === 0) {
129
+ const screenshot = await page.screenshot()
130
+ screenshots.push(screenshot.toString('base64').slice(0, 50) + '...')
131
+ }
132
+ }
133
+
134
+ // also do the continuous sweep pattern
135
+ for (let sweep = 0; sweep < 3; sweep++) {
136
+ for (let i = 0; i <= 10; i++) {
137
+ const t = i / 10
138
+ const x = logoBox.x + logoBox.width * t
139
+ await page.mouse.move(x, centerY)
140
+ await page.waitForTimeout(8)
141
+ }
142
+ for (let i = 0; i <= 10; i++) {
143
+ const t = i / 10
144
+ const x = logoBox.x + logoBox.width - logoBox.width * t
145
+ await page.mouse.move(x, centerY)
146
+ await page.waitForTimeout(8)
147
+ }
148
+ }
149
+
150
+ console.log(`Took ${screenshots.length} screenshots during test`)
151
+
152
+ await page.waitForTimeout(500)
153
+
154
+ // analyze positions for unexpected jumps
155
+ const positions = await page.evaluate(() => (window as any).__dotPositions || [])
156
+ const debug = await page.evaluate(() => (window as any).__dotDebug || {})
157
+
158
+ console.log(`Collected ${positions.length} dot positions`)
159
+ console.log(`Debug:`, debug)
160
+ if (positions.length > 0) {
161
+ console.log('First position:', positions[0])
162
+ console.log('Last position:', positions[positions.length - 1])
163
+ // show all x values to see the pattern
164
+ const xValues = positions.map((p: any) => Math.round(p.x))
165
+ console.log('X values sample (first 50):', xValues.slice(0, 50).join(', '))
166
+ console.log('X values sample (last 50):', xValues.slice(-50).join(', '))
167
+ }
168
+
169
+ // analyze for jitter patterns:
170
+ // 1. Large sudden jumps (>20px in one frame)
171
+ // 2. Rapid back-and-forth oscillations
172
+ const jumps: any[] = []
173
+ const oscillations: any[] = []
174
+
175
+ for (let i = 1; i < positions.length; i++) {
176
+ const prev = positions[i - 1]
177
+ const curr = positions[i]
178
+ const dx = curr.x - prev.x
179
+ const timeDelta = curr.time - prev.time
180
+
181
+ // detect large jumps: >20px change in a single frame
182
+ if (Math.abs(dx) > 20 && timeDelta < 30) {
183
+ jumps.push({
184
+ idx: i,
185
+ from: Math.round(prev.x),
186
+ to: Math.round(curr.x),
187
+ dx: Math.round(dx),
188
+ timeDelta,
189
+ })
190
+ }
191
+ }
192
+
193
+ // detect oscillations: A->B->A pattern in <100ms
194
+ for (let i = 2; i < positions.length; i++) {
195
+ const a = positions[i - 2]
196
+ const b = positions[i - 1]
197
+ const c = positions[i]
198
+ const totalTime = c.time - a.time
199
+
200
+ if (totalTime < 100) {
201
+ // check if c is close to a (returned to original position)
202
+ const returnDistance = Math.abs(c.x - a.x)
203
+ const deviationDistance = Math.abs(b.x - a.x)
204
+ if (returnDistance < 3 && deviationDistance > 8) {
205
+ oscillations.push({
206
+ idx: i,
207
+ pattern: `${Math.round(a.x)} -> ${Math.round(b.x)} -> ${Math.round(c.x)}`,
208
+ totalTime,
209
+ })
210
+ }
211
+ }
212
+ }
213
+
214
+ console.log(`Large jumps (>20px): ${jumps.length}`)
215
+ if (jumps.length > 0) {
216
+ console.log('Jump samples:', jumps.slice(0, 5))
217
+ }
218
+ console.log(`Oscillations: ${oscillations.length}`)
219
+ if (oscillations.length > 0) {
220
+ console.log('Oscillation samples:', oscillations.slice(0, 5))
221
+ }
222
+
223
+ console.log(`Detected ${jumps.length} jitters`)
224
+ if (jumps.length > 0) {
225
+ console.log('First few jitters:', JSON.stringify(jumps.slice(0, 5), null, 2))
226
+ }
227
+
228
+ // allow some jitter but not excessive
229
+ // in a well-behaved animation, we might get 0-3 jitters at direction changes
230
+ // the bug causes 10+ jitters
231
+ expect(jumps.length, `Too many jitters detected: ${jumps.length}`).toBeLessThan(10)
232
+ })
233
+ })
234
+
235
+ test.describe('PromoLinksRow Tooltip Position Jump', () => {
236
+ test('tooltip should not jump when moving between promo buttons', async ({
237
+ page,
238
+ }) => {
239
+ await page.goto(SITE_URL, { waitUntil: 'networkidle' })
240
+ await page.waitForTimeout(1000)
241
+
242
+ // resize to ensure promo buttons are visible
243
+ await page.setViewportSize({ width: 1400, height: 900 })
244
+ await page.waitForTimeout(500)
245
+
246
+ // find the PromoLinksRow buttons (Starter Kit/Takeout, Copy-Paste UI/Bento, Add Even)
247
+ // these are the buttons that use the scoped tooltip with animatePosition
248
+ // the buttons show "Starter Kit", "Copy-Paste UI", "Add Even"
249
+ const takeoutBtn = page.locator('button:has-text("Starter Kit")').first()
250
+ const bentoBtn = page.locator('button:has-text("Copy-Paste UI")').first()
251
+ const consultingBtn = page.locator('button:has-text("Hire Us!")').first()
252
+
253
+ const takeoutVisible = await takeoutBtn.isVisible().catch(() => false)
254
+ const bentoVisible = await bentoBtn.isVisible().catch(() => false)
255
+ const consultingVisible = await consultingBtn.isVisible().catch(() => false)
256
+
257
+ if (!takeoutVisible || !bentoVisible || !consultingVisible) {
258
+ console.log('PromoLinksRow buttons not visible, skipping')
259
+ console.log('Takeout visible:', takeoutVisible)
260
+ console.log('Bento visible:', bentoVisible)
261
+ console.log('Consulting visible:', consultingVisible)
262
+ test.skip()
263
+ return
264
+ }
265
+
266
+ const takeoutBox = await takeoutBtn.boundingBox()
267
+ const bentoBox = await bentoBtn.boundingBox()
268
+ const consultingBox = await consultingBtn.boundingBox()
269
+
270
+ if (!takeoutBox || !bentoBox || !consultingBox) {
271
+ throw new Error('Could not get bounding boxes for promo buttons')
272
+ }
273
+
274
+ console.log('Button positions:')
275
+ console.log(' Takeout (left):', takeoutBox.x)
276
+ console.log(' Bento (middle):', bentoBox.x)
277
+ console.log(' Consulting (right):', consultingBox.x)
278
+
279
+ // inject position tracking for tooltip
280
+ // the tooltip content has animatePosition and scope="promo-tooltip"
281
+ await page.evaluate(() => {
282
+ ;(window as any).__tooltipPositions = []
283
+ ;(window as any).__jumpLog = []
284
+ let lastPos: any = null
285
+
286
+ const track = () => {
287
+ // find tooltip by data-placement attribute (set by Popper)
288
+ const tooltip = document.querySelector('[data-placement]') as HTMLElement
289
+ if (tooltip) {
290
+ // get actual rendered position
291
+ const rect = tooltip.getBoundingClientRect()
292
+ const transform = getComputedStyle(tooltip).transform
293
+ let x = rect.x
294
+ let y = rect.y
295
+
296
+ // also extract matrix values if present
297
+ if (transform && transform !== 'none') {
298
+ const match = transform.match(
299
+ /matrix\([^,]+,\s*[^,]+,\s*[^,]+,\s*[^,]+,\s*([^,]+),\s*([^)]+)\)/
300
+ )
301
+ if (match) {
302
+ // use rect for tracking since that's where it visually appears
303
+ }
304
+ }
305
+
306
+ const pos = { x: rect.x, y: rect.y, time: Date.now() }
307
+ ;(window as any).__tooltipPositions.push(pos)
308
+
309
+ // detect jumps in real-time
310
+ if (lastPos) {
311
+ const dx = Math.abs(x - lastPos.x)
312
+ if (dx > 100) {
313
+ const msg = `JUMP: ${lastPos.x.toFixed(0)} -> ${x.toFixed(0)} (dx: ${dx.toFixed(0)})`
314
+ ;(window as any).__jumpLog.push(msg)
315
+ console.log('%c' + msg, 'color: red; font-weight: bold')
316
+ }
317
+ }
318
+ lastPos = pos
319
+ } else {
320
+ lastPos = null
321
+ }
322
+ requestAnimationFrame(track)
323
+ }
324
+ requestAnimationFrame(track)
325
+ })
326
+
327
+ // step 1: hover on rightmost button (Consulting) to open tooltip
328
+ const consultingCenter = {
329
+ x: consultingBox.x + consultingBox.width / 2,
330
+ y: consultingBox.y + consultingBox.height / 2,
331
+ }
332
+ await page.mouse.move(consultingCenter.x, consultingCenter.y)
333
+ await page.waitForTimeout(800) // wait for tooltip to fully appear
334
+
335
+ // step 2: FAST move to leftmost button (Takeout)
336
+ // this is the pattern that triggers the jump bug
337
+ const takeoutCenter = {
338
+ x: takeoutBox.x + takeoutBox.width / 2,
339
+ y: takeoutBox.y + takeoutBox.height / 2,
340
+ }
341
+
342
+ // fast sweep across all 3 buttons
343
+ const steps = 10
344
+ for (let i = 1; i <= steps; i++) {
345
+ const t = i / steps
346
+ const x = consultingCenter.x + (takeoutCenter.x - consultingCenter.x) * t
347
+ const y = consultingCenter.y + (takeoutCenter.y - consultingCenter.y) * t
348
+ await page.mouse.move(x, y)
349
+ await page.waitForTimeout(10) // fast movement
350
+ }
351
+
352
+ await page.waitForTimeout(400)
353
+
354
+ // analyze for position jumps
355
+ const positions = await page.evaluate(
356
+ () => (window as any).__tooltipPositions || []
357
+ )
358
+ const jumpLog = await page.evaluate(() => (window as any).__jumpLog || [])
359
+
360
+ const jumps: any[] = []
361
+ for (let i = 1; i < positions.length; i++) {
362
+ const prev = positions[i - 1]
363
+ const curr = positions[i]
364
+ const dx = curr.x - prev.x
365
+ const timeDelta = curr.time - prev.time
366
+
367
+ // detect large sudden jumps (>100px in <50ms)
368
+ if (Math.abs(dx) > 100 && timeDelta < 50) {
369
+ jumps.push({
370
+ idx: i,
371
+ from: Math.round(prev.x),
372
+ to: Math.round(curr.x),
373
+ dx: Math.round(dx),
374
+ timeDelta,
375
+ })
376
+ }
377
+ }
378
+
379
+ console.log(`Collected ${positions.length} tooltip positions`)
380
+ if (positions.length > 0) {
381
+ const xValues = positions.map((p: any) => Math.round(p.x))
382
+ console.log('X positions (first 30):', xValues.slice(0, 30).join(', '))
383
+ console.log('X positions (last 30):', xValues.slice(-30).join(', '))
384
+ }
385
+ console.log(`Jump log from browser:`, jumpLog)
386
+ console.log(`Detected ${jumps.length} position jumps`)
387
+ if (jumps.length > 0) {
388
+ console.log('Jumps:', JSON.stringify(jumps.slice(0, 5), null, 2))
389
+ }
390
+
391
+ expect(jumps.length, `Tooltip jumped ${jumps.length} times!`).toBe(0)
392
+ })
393
+
394
+ test('inner content animations should not get stuck at endpoints', async ({
395
+ page,
396
+ }) => {
397
+ await page.goto(SITE_URL, { waitUntil: 'networkidle' })
398
+ await page.waitForTimeout(1000)
399
+
400
+ await page.setViewportSize({ width: 1400, height: 900 })
401
+ await page.waitForTimeout(500)
402
+
403
+ // find header links
404
+ const coreLink = page.locator('a:has-text("Core")').first()
405
+ const menuButton = page.locator('button[aria-label="Open the main menu"]').first()
406
+
407
+ const coreVisible = await coreLink.isVisible().catch(() => false)
408
+ if (!coreVisible) {
409
+ console.log('Core link not visible, skipping')
410
+ test.skip()
411
+ return
412
+ }
413
+
414
+ // inject tracking for Frame (inner content) animations
415
+ await page.evaluate(() => {
416
+ ;(window as any).__framePositions = []
417
+ const track = () => {
418
+ const frames = document.querySelectorAll('.header-popover-frame')
419
+ frames.forEach((frame, idx) => {
420
+ const el = frame as HTMLElement
421
+ const transform = getComputedStyle(el).transform
422
+ const opacity = getComputedStyle(el).opacity
423
+ if (transform && transform !== 'none') {
424
+ const match = transform.match(
425
+ /matrix\([^,]+,\s*[^,]+,\s*[^,]+,\s*[^,]+,\s*([^,]+),\s*([^)]+)\)/
426
+ )
427
+ if (match) {
428
+ ;(window as any).__framePositions.push({
429
+ idx,
430
+ x: parseFloat(match[1]),
431
+ y: parseFloat(match[2]),
432
+ opacity: parseFloat(opacity),
433
+ time: Date.now(),
434
+ })
435
+ }
436
+ }
437
+ })
438
+ requestAnimationFrame(track)
439
+ }
440
+ requestAnimationFrame(track)
441
+ })
442
+
443
+ // hover Core
444
+ await coreLink.hover()
445
+ await page.waitForTimeout(400)
446
+
447
+ // rapidly switch to menu button
448
+ await menuButton.hover()
449
+ await page.waitForTimeout(200)
450
+
451
+ // back to Core
452
+ await coreLink.hover()
453
+ await page.waitForTimeout(200)
454
+
455
+ // to menu
456
+ await menuButton.hover()
457
+ await page.waitForTimeout(200)
458
+
459
+ // to Core
460
+ await coreLink.hover()
461
+ await page.waitForTimeout(400)
462
+
463
+ const positions = await page.evaluate(() => (window as any).__framePositions || [])
464
+ console.log(`Collected ${positions.length} frame positions`)
465
+
466
+ // analyze for stuck animations (opacity stuck at 0 or x stuck at wrong value)
467
+ let stuckAtExit = 0
468
+ for (let i = 0; i < positions.length; i++) {
469
+ const pos = positions[i]
470
+ // check for opacity stuck near 0 when it should be 1
471
+ if (pos.opacity < 0.1 && Math.abs(pos.x) > 30) {
472
+ stuckAtExit++
473
+ }
474
+ }
475
+
476
+ console.log(`Frames stuck at exit state: ${stuckAtExit}`)
477
+ // some exit states during transition are fine, but not excessive
478
+ expect(stuckAtExit).toBeLessThan(50)
479
+ })
480
+ })
481
+ })
@@ -0,0 +1,112 @@
1
+ import { expect, test, type Page } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+
4
+ /**
5
+ * Tests for height media query overriding transform props (scale)
6
+ * Uses v5 config where height-lg breakpoint: minHeight 1024px
7
+ */
8
+
9
+ async function getScale(page: Page, testId: string): Promise<number> {
10
+ return page.evaluate((id) => {
11
+ const el = document.querySelector(`[data-testid="${id}"]`)
12
+ if (!el) return -1
13
+ const transform = getComputedStyle(el).transform
14
+ if (transform === 'none') return 1
15
+ const match = transform.match(/matrix\(([^,]+),/)
16
+ return match ? Number.parseFloat(match[1]) : 1
17
+ }, testId)
18
+ }
19
+
20
+ async function getBgColor(page: Page, testId: string): Promise<string> {
21
+ return page.evaluate((id) => {
22
+ const el = document.querySelector(`[data-testid="${id}"]`)
23
+ return el ? getComputedStyle(el).backgroundColor : ''
24
+ }, testId)
25
+ }
26
+
27
+ test.describe('Height Media Query Override', () => {
28
+ test.beforeEach(async ({ page }) => {
29
+ await setupPage(page, {
30
+ name: 'HeightMediaQueryOverrideCase',
31
+ type: 'useCase',
32
+ searchParams: { v5config: 'true' },
33
+ })
34
+ })
35
+
36
+ test('$height-sm should override base scale=1 when height >= 640', async ({ page }) => {
37
+ await page.setViewportSize({ width: 1200, height: 700 })
38
+ await page.waitForTimeout(300)
39
+
40
+ const scale = await getScale(page, 'test-height-scale')
41
+ // should be 2 from $height-sm, not 1 from base
42
+ expect(scale, 'scale should be 2 at $height-sm, not 1 from base').toBeCloseTo(2, 1)
43
+ })
44
+
45
+ test('$height-lg works when NO base scale is set', async ({ page }) => {
46
+ await page.setViewportSize({ width: 1200, height: 1100 })
47
+ await page.waitForTimeout(300)
48
+
49
+ const scale = await getScale(page, 'test-height-scale-no-base')
50
+ expect(scale, 'scale should be 2 at $height-lg').toBeCloseTo(2, 1)
51
+ })
52
+
53
+ test('base scale=1 should apply when height < 640 (below $height-sm)', async ({
54
+ page,
55
+ }) => {
56
+ await page.setViewportSize({ width: 1200, height: 500 })
57
+ await page.waitForTimeout(300)
58
+
59
+ const scale = await getScale(page, 'test-height-scale')
60
+ expect(scale, 'scale should be 1 at base (below $height-sm)').toBeCloseTo(1, 1)
61
+ })
62
+
63
+ test('$sm width query works for comparison', async ({ page }) => {
64
+ await page.setViewportSize({ width: 800, height: 700 })
65
+ await page.waitForTimeout(300)
66
+
67
+ const scale = await getScale(page, 'test-width-scale')
68
+ expect(scale, 'scale should be 1.5 at $sm').toBeCloseTo(1.5, 1)
69
+ })
70
+
71
+ test('styled component with scale=1 in definition + $height-sm override', async ({
72
+ page,
73
+ }) => {
74
+ await page.setViewportSize({ width: 1200, height: 700 })
75
+ await page.waitForTimeout(300)
76
+
77
+ const scale = await getScale(page, 'test-styled-scale')
78
+ // styled component has scale=1 in definition, $height-sm should override to 2
79
+ expect(scale, 'styled component scale should be 2 at $height-sm').toBeCloseTo(2, 1)
80
+ })
81
+
82
+ test('styled component with $height-sm in definition + runtime $height-sm override', async ({
83
+ page,
84
+ }) => {
85
+ await page.setViewportSize({ width: 1200, height: 700 })
86
+ await page.waitForTimeout(300)
87
+
88
+ const scale = await getScale(page, 'test-styled-media-override')
89
+ // styled has $height-sm: scale=0.5 in definition
90
+ // runtime $height-sm: scale=2 should override
91
+ expect(
92
+ scale,
93
+ 'runtime $height-sm should override styled definition $height-sm'
94
+ ).toBeCloseTo(2, 1)
95
+ })
96
+
97
+ test('ContainerLarge with WIDTH queries in definition + runtime $height-sm scale', async ({
98
+ page,
99
+ }) => {
100
+ // exact scenario from chat app: ContainerLarge has $md/$lg width queries
101
+ // used with scale=1 and $height-sm={{ scale: 2 }}
102
+ await page.setViewportSize({ width: 1200, height: 700 })
103
+ await page.waitForTimeout(300)
104
+
105
+ const scale = await getScale(page, 'test-container-large')
106
+ // should be 2 from $height-sm, not 1 from base
107
+ expect(
108
+ scale,
109
+ 'ContainerLarge with width queries should still allow $height-sm to override scale'
110
+ ).toBeCloseTo(2, 1)
111
+ })
112
+ })
@@ -0,0 +1,55 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ await setupPage(page, { name: 'InputAutoFocusAfterMenuCase', type: 'useCase' })
6
+ })
7
+
8
+ test('standalone Input with autoFocus should be focused on mount', async ({ page }) => {
9
+ const input = page.locator('[data-testid="autofocus-input"]')
10
+ await expect(input).toBeVisible()
11
+ await expect(input).toBeFocused()
12
+ })
13
+
14
+ test('Input with autoFocus should receive focus after menu close', async ({ page }) => {
15
+ const trigger = page.locator('[data-testid="menu-trigger"]')
16
+ await trigger.click()
17
+
18
+ const menuContent = page.locator('[data-testid="menu-content"]')
19
+ await expect(menuContent).toBeVisible()
20
+
21
+ const menuItem = page.locator('[data-testid="menu-item-show-input"]')
22
+ await menuItem.click()
23
+
24
+ const afterMenuInput = page.locator('[data-testid="after-menu-input"]')
25
+ await expect(afterMenuInput).toBeVisible()
26
+
27
+ await page.waitForTimeout(300)
28
+ await expect(afterMenuInput).toBeFocused()
29
+ })
30
+
31
+ test('onCloseAutoFocus preventDefault should prevent default focus restore and allow custom focus', async ({
32
+ page,
33
+ }) => {
34
+ const trigger = page.locator('[data-testid="prevent-default-trigger"]')
35
+ await trigger.click()
36
+
37
+ const menuContent = page.locator('[data-testid="prevent-default-menu-content"]')
38
+ await expect(menuContent).toBeVisible()
39
+
40
+ const menuItem = page.locator('[data-testid="prevent-default-menu-item"]')
41
+ await menuItem.click()
42
+
43
+ // menu should close
44
+ await expect(menuContent).not.toBeVisible()
45
+
46
+ await page.waitForTimeout(300)
47
+
48
+ // custom focus target should be focused (not the trigger)
49
+ const customTarget = page.locator('[data-testid="custom-focus-target"]')
50
+ await expect(customTarget).toBeFocused()
51
+
52
+ // trigger should NOT be focused
53
+ const triggerFocused = await trigger.evaluate((el) => el === document.activeElement)
54
+ expect(triggerFocused).toBe(false)
55
+ })
@@ -0,0 +1,22 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ await setupPage(page, { name: 'InputAutoFocusStyledCase', type: 'useCase' })
6
+ })
7
+
8
+ test('plain Input with autoFocus gets focused on mount', async ({ page }) => {
9
+ await page.locator('[data-testid="show-plain"]').click()
10
+ const input = page.locator('[data-testid="plain-autofocus"]')
11
+ await expect(input).toBeVisible()
12
+ await page.waitForTimeout(200)
13
+ await expect(input).toBeFocused()
14
+ })
15
+
16
+ test('styled(Input) with autoFocus gets focused on mount', async ({ page }) => {
17
+ await page.locator('[data-testid="show-styled"]').click()
18
+ const input = page.locator('[data-testid="styled-autofocus"]')
19
+ await expect(input).toBeVisible()
20
+ await page.waitForTimeout(200)
21
+ await expect(input).toBeFocused()
22
+ })