@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,231 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ await setupPage(page, { name: 'MenuItemPseudoOverrideCase', type: 'useCase' })
6
+ })
7
+
8
+ test('spread style object: pseudo styles should override variant defaults', async ({
9
+ page,
10
+ }) => {
11
+ // open the menu with spread style object (no unstyled)
12
+ await page.getByTestId('spread-trigger').click()
13
+ await page.waitForTimeout(300)
14
+
15
+ const spreadItem = page.getByTestId('spread-item')
16
+ await expect(spreadItem).toBeVisible()
17
+
18
+ // focus the item to trigger focusStyle
19
+ await spreadItem.focus()
20
+ await page.waitForTimeout(100)
21
+
22
+ // check that the custom focusStyle is applied (red), not the default variant
23
+ const focusedStyles = await spreadItem.evaluate((el) => {
24
+ const computed = window.getComputedStyle(el)
25
+ return {
26
+ backgroundColor: computed.backgroundColor,
27
+ }
28
+ })
29
+
30
+ // user specified rgb(255, 0, 0) which should override the default $backgroundHover
31
+ expect(focusedStyles.backgroundColor).toBe('rgb(255, 0, 0)')
32
+ })
33
+
34
+ test('spread style with unstyled: works correctly', async ({ page }) => {
35
+ // open the menu with spread style + unstyled
36
+ await page.getByTestId('spread-unstyled-trigger').click()
37
+ await page.waitForTimeout(300)
38
+
39
+ const unstyledItem = page.getByTestId('spread-unstyled-item')
40
+ await expect(unstyledItem).toBeVisible()
41
+
42
+ // focus the item to trigger focusStyle
43
+ await unstyledItem.focus()
44
+ await page.waitForTimeout(100)
45
+
46
+ // check that the custom focusStyle is applied
47
+ const focusedStyles = await unstyledItem.evaluate((el) => {
48
+ const computed = window.getComputedStyle(el)
49
+ return {
50
+ backgroundColor: computed.backgroundColor,
51
+ }
52
+ })
53
+
54
+ // user specified rgb(255, 0, 0)
55
+ expect(focusedStyles.backgroundColor).toBe('rgb(255, 0, 0)')
56
+ })
57
+
58
+ test('direct props: user-provided pseudo styles override variant defaults', async ({
59
+ page,
60
+ }) => {
61
+ // open the menu with custom pseudo styles
62
+ await page.getByTestId('custom-trigger').click()
63
+ await page.waitForTimeout(300)
64
+
65
+ const customItem = page.getByTestId('custom-item')
66
+ await expect(customItem).toBeVisible()
67
+
68
+ // focus the item to trigger focusStyle
69
+ await customItem.focus()
70
+ await page.waitForTimeout(100)
71
+
72
+ // check that the custom focusStyle is applied (red), not the default variant
73
+ const focusedStyles = await customItem.evaluate((el) => {
74
+ const computed = window.getComputedStyle(el)
75
+ return {
76
+ backgroundColor: computed.backgroundColor,
77
+ }
78
+ })
79
+
80
+ // user specified rgb(255, 0, 0) which should override the default $backgroundHover
81
+ expect(focusedStyles.backgroundColor).toBe('rgb(255, 0, 0)')
82
+ })
83
+
84
+ test('unstyled item with custom pseudo styles works correctly', async ({ page }) => {
85
+ // open the unstyled menu
86
+ await page.getByTestId('unstyled-trigger').click()
87
+ await page.waitForTimeout(300)
88
+
89
+ const unstyledItem = page.getByTestId('unstyled-item')
90
+ await expect(unstyledItem).toBeVisible()
91
+
92
+ // focus the item to trigger focusStyle
93
+ await unstyledItem.focus()
94
+ await page.waitForTimeout(100)
95
+
96
+ // check that the custom focusStyle is applied
97
+ const focusedStyles = await unstyledItem.evaluate((el) => {
98
+ const computed = window.getComputedStyle(el)
99
+ return {
100
+ backgroundColor: computed.backgroundColor,
101
+ }
102
+ })
103
+
104
+ // user specified rgb(255, 0, 0)
105
+ expect(focusedStyles.backgroundColor).toBe('rgb(255, 0, 0)')
106
+ })
107
+
108
+ test('default item uses variant default pseudo styles', async ({ page }) => {
109
+ // open the menu
110
+ await page.getByTestId('custom-trigger').click()
111
+ await page.waitForTimeout(300)
112
+
113
+ const defaultItem = page.getByTestId('default-item')
114
+ await expect(defaultItem).toBeVisible()
115
+
116
+ // focus the item to trigger focusStyle
117
+ await defaultItem.focus()
118
+ await page.waitForTimeout(100)
119
+
120
+ // check that the default focusStyle is applied (not red, but the theme's $backgroundHover)
121
+ const focusedStyles = await defaultItem.evaluate((el) => {
122
+ const computed = window.getComputedStyle(el)
123
+ return {
124
+ backgroundColor: computed.backgroundColor,
125
+ }
126
+ })
127
+
128
+ // should NOT be red (255, 0, 0) - should be the default variant's $backgroundHover
129
+ expect(focusedStyles.backgroundColor).not.toBe('rgb(255, 0, 0)')
130
+ // should have some background color applied
131
+ expect(focusedStyles.backgroundColor).not.toBe('rgba(0, 0, 0, 0)')
132
+ })
133
+
134
+ test('shorthands: pseudo styles should override variant defaults', async ({ page }) => {
135
+ // open the menu with shorthand styles (no unstyled)
136
+ await page.getByTestId('shorthand-trigger').click()
137
+ await page.waitForTimeout(300)
138
+
139
+ const shorthandItem = page.getByTestId('shorthand-item')
140
+ await expect(shorthandItem).toBeVisible()
141
+
142
+ // focus the item to trigger focusStyle
143
+ await shorthandItem.focus()
144
+ await page.waitForTimeout(100)
145
+
146
+ // check that the custom focusStyle is applied (red)
147
+ const focusedStyles = await shorthandItem.evaluate((el) => {
148
+ const computed = window.getComputedStyle(el)
149
+ return {
150
+ backgroundColor: computed.backgroundColor,
151
+ }
152
+ })
153
+
154
+ // user specified bg: 'rgb(255, 0, 0)' (shorthand) which should override default
155
+ expect(focusedStyles.backgroundColor).toBe('rgb(255, 0, 0)')
156
+ })
157
+
158
+ test('shorthands with unstyled: works correctly', async ({ page }) => {
159
+ // open the menu with shorthand styles + unstyled
160
+ await page.getByTestId('shorthand-unstyled-trigger').click()
161
+ await page.waitForTimeout(300)
162
+
163
+ const shorthandUnstyledItem = page.getByTestId('shorthand-unstyled-item')
164
+ await expect(shorthandUnstyledItem).toBeVisible()
165
+
166
+ // focus the item to trigger focusStyle
167
+ await shorthandUnstyledItem.focus()
168
+ await page.waitForTimeout(100)
169
+
170
+ // check that the custom focusStyle is applied
171
+ const focusedStyles = await shorthandUnstyledItem.evaluate((el) => {
172
+ const computed = window.getComputedStyle(el)
173
+ return {
174
+ backgroundColor: computed.backgroundColor,
175
+ }
176
+ })
177
+
178
+ // user specified bg: 'rgb(255, 0, 0)' (shorthand)
179
+ expect(focusedStyles.backgroundColor).toBe('rgb(255, 0, 0)')
180
+ })
181
+
182
+ test('styled() component: pseudo styles should override variant defaults', async ({
183
+ page,
184
+ }) => {
185
+ // open the menu with styled() component (no unstyled)
186
+ await page.getByTestId('styled-trigger').click()
187
+ await page.waitForTimeout(300)
188
+
189
+ const styledItem = page.getByTestId('styled-item')
190
+ await expect(styledItem).toBeVisible()
191
+
192
+ // focus the item to trigger focusStyle
193
+ await styledItem.focus()
194
+ await page.waitForTimeout(100)
195
+
196
+ // check that the custom focusStyle is applied (red)
197
+ const focusedStyles = await styledItem.evaluate((el) => {
198
+ const computed = window.getComputedStyle(el)
199
+ return {
200
+ backgroundColor: computed.backgroundColor,
201
+ }
202
+ })
203
+
204
+ // styled component specified backgroundColor: 'rgb(255, 0, 0)' in focusStyle
205
+ // this should override the variant's default $backgroundHover
206
+ expect(focusedStyles.backgroundColor).toBe('rgb(255, 0, 0)')
207
+ })
208
+
209
+ test('styled() component with unstyled: works correctly', async ({ page }) => {
210
+ // open the menu with styled() component + unstyled
211
+ await page.getByTestId('styled-unstyled-trigger').click()
212
+ await page.waitForTimeout(300)
213
+
214
+ const styledUnstyledItem = page.getByTestId('styled-unstyled-item')
215
+ await expect(styledUnstyledItem).toBeVisible()
216
+
217
+ // focus the item to trigger focusStyle
218
+ await styledUnstyledItem.focus()
219
+ await page.waitForTimeout(100)
220
+
221
+ // check that the custom focusStyle is applied
222
+ const focusedStyles = await styledUnstyledItem.evaluate((el) => {
223
+ const computed = window.getComputedStyle(el)
224
+ return {
225
+ backgroundColor: computed.backgroundColor,
226
+ }
227
+ })
228
+
229
+ // styled component specified backgroundColor: 'rgb(255, 0, 0)' in focusStyle
230
+ expect(focusedStyles.backgroundColor).toBe('rgb(255, 0, 0)')
231
+ })
@@ -0,0 +1,101 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { getBoundingRect, setupPage } from './test-utils'
3
+
4
+ test.describe('Menu Multi-Trigger', () => {
5
+ test.beforeEach(async ({ page }) => {
6
+ await setupPage(page, {
7
+ name: 'MenuMultiTriggerCase',
8
+ type: 'useCase',
9
+ waitExtra: true,
10
+ })
11
+ })
12
+
13
+ test('clicking trigger A opens content near trigger A', async ({ page }) => {
14
+ const triggerA = page.getByTestId('trigger-a')
15
+ await triggerA.click()
16
+ await page.waitForTimeout(300)
17
+
18
+ const content = page.getByTestId('menu-content')
19
+ await expect(content).toBeVisible()
20
+
21
+ const triggerBox = await getBoundingRect(page, '[data-testid="trigger-a"]')
22
+ const contentBox = await getBoundingRect(page, '[data-testid="menu-content"]')
23
+ expect(triggerBox).not.toBeNull()
24
+ expect(contentBox).not.toBeNull()
25
+
26
+ // content should be horizontally near trigger A
27
+ expect(Math.abs(contentBox!.x - triggerBox!.x)).toBeLessThan(50)
28
+ })
29
+
30
+ test('clicking trigger B re-anchors content to trigger B', async ({ page }) => {
31
+ // open via A first
32
+ const triggerA = page.getByTestId('trigger-a')
33
+ await triggerA.click()
34
+ await page.waitForTimeout(300)
35
+ await expect(page.getByTestId('menu-content')).toBeVisible()
36
+
37
+ // close
38
+ await page.keyboard.press('Escape')
39
+ await page.waitForTimeout(300)
40
+
41
+ // open via B
42
+ const triggerB = page.getByTestId('trigger-b')
43
+ await triggerB.click()
44
+ await page.waitForTimeout(300)
45
+
46
+ const content = page.getByTestId('menu-content')
47
+ await expect(content).toBeVisible()
48
+
49
+ const triggerBBox = await getBoundingRect(page, '[data-testid="trigger-b"]')
50
+ const contentBox = await getBoundingRect(page, '[data-testid="menu-content"]')
51
+ expect(triggerBBox).not.toBeNull()
52
+ expect(contentBox).not.toBeNull()
53
+
54
+ // content should be near trigger B, not trigger A
55
+ expect(Math.abs(contentBox!.x - triggerBBox!.x)).toBeLessThan(50)
56
+ })
57
+
58
+ test('only the active trigger has data-state=open', async ({ page }) => {
59
+ const triggerA = page.getByTestId('trigger-a')
60
+ const triggerB = page.getByTestId('trigger-b')
61
+ const triggerC = page.getByTestId('trigger-c')
62
+
63
+ await triggerB.click()
64
+ await page.waitForTimeout(300)
65
+ await expect(page.getByTestId('menu-content')).toBeVisible()
66
+
67
+ await expect(triggerA).toHaveAttribute('data-state', 'closed')
68
+ await expect(triggerB).toHaveAttribute('data-state', 'open')
69
+ await expect(triggerC).toHaveAttribute('data-state', 'closed')
70
+ })
71
+
72
+ test('keyboard open via Enter re-anchors to focused trigger', async ({ page }) => {
73
+ const triggerC = page.getByTestId('trigger-c')
74
+ await triggerC.focus()
75
+ await page.keyboard.press('Enter')
76
+ await page.waitForTimeout(300)
77
+
78
+ const content = page.getByTestId('menu-content')
79
+ await expect(content).toBeVisible()
80
+
81
+ const triggerCBox = await getBoundingRect(page, '[data-testid="trigger-c"]')
82
+ const contentBox = await getBoundingRect(page, '[data-testid="menu-content"]')
83
+ expect(triggerCBox).not.toBeNull()
84
+ expect(contentBox).not.toBeNull()
85
+
86
+ // content should be near trigger C
87
+ expect(Math.abs(contentBox!.x - triggerCBox!.x)).toBeLessThan(50)
88
+ })
89
+
90
+ test('close returns focus to the trigger that opened the menu', async ({ page }) => {
91
+ const triggerB = page.getByTestId('trigger-b')
92
+ await triggerB.click()
93
+ await page.waitForTimeout(300)
94
+ await expect(page.getByTestId('menu-content')).toBeVisible()
95
+
96
+ await page.keyboard.press('Escape')
97
+ await page.waitForTimeout(300)
98
+
99
+ await expect(triggerB).toBeFocused()
100
+ })
101
+ })
@@ -0,0 +1,93 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+
4
+ // Use smaller viewport to ensure menu needs to scroll
5
+ test.use({ viewport: { width: 800, height: 600 } })
6
+
7
+ test.describe('Menu Overflow', () => {
8
+ test.beforeEach(async ({ page }) => {
9
+ await setupPage(page, { name: 'MenuOverflowCase', type: 'useCase' })
10
+ })
11
+
12
+ test('menu content is constrained to max height', async ({ page }) => {
13
+ await page.waitForLoadState('networkidle')
14
+
15
+ const trigger = page.getByTestId('menu-trigger')
16
+ await trigger.click()
17
+ await page.waitForTimeout(300)
18
+
19
+ const menuContent = page.getByTestId('menu-content')
20
+ await expect(menuContent).toBeVisible()
21
+
22
+ // get menu content bounding box and viewport dimensions
23
+ const boundingBox = await menuContent.boundingBox()
24
+ const viewportSize = page.viewportSize()
25
+
26
+ expect(boundingBox).not.toBeNull()
27
+ expect(viewportSize).not.toBeNull()
28
+
29
+ if (boundingBox && viewportSize) {
30
+ // menu should not extend beyond viewport
31
+ expect(boundingBox.y).toBeGreaterThanOrEqual(0)
32
+ expect(boundingBox.y + boundingBox.height).toBeLessThanOrEqual(viewportSize.height)
33
+ // menu height should be constrained (less than total items would need)
34
+ expect(boundingBox.height).toBeLessThan(1000) // 30 items at ~33px each would be ~1000px
35
+ }
36
+ })
37
+
38
+ test('menu scroll view is scrollable', async ({ page }) => {
39
+ await page.waitForLoadState('networkidle')
40
+
41
+ const trigger = page.getByTestId('menu-trigger')
42
+ await trigger.click()
43
+ await page.waitForTimeout(300)
44
+
45
+ const menuScrollView = page.getByTestId('menu-scroll-view')
46
+ await expect(menuScrollView).toBeVisible()
47
+
48
+ // check that scroll view has overflow (is scrollable)
49
+ const isScrollable = await menuScrollView.evaluate((el) => {
50
+ return el.scrollHeight > el.clientHeight
51
+ })
52
+
53
+ expect(isScrollable).toBe(true)
54
+ })
55
+
56
+ test('scrollbars are hidden', async ({ page }) => {
57
+ await page.waitForLoadState('networkidle')
58
+
59
+ const trigger = page.getByTestId('menu-trigger')
60
+ await trigger.click()
61
+ await page.waitForTimeout(300)
62
+
63
+ const menuScrollView = page.getByTestId('menu-scroll-view')
64
+ await expect(menuScrollView).toBeVisible()
65
+
66
+ // check that scrollbar-width is none (Firefox/modern browsers)
67
+ const scrollbarWidth = await menuScrollView.evaluate((el) => {
68
+ return window.getComputedStyle(el).scrollbarWidth
69
+ })
70
+
71
+ expect(scrollbarWidth).toBe('none')
72
+ })
73
+
74
+ test('first item is visible and last item requires scrolling', async ({ page }) => {
75
+ await page.waitForLoadState('networkidle')
76
+
77
+ const trigger = page.getByTestId('menu-trigger')
78
+ await trigger.click()
79
+ await page.waitForTimeout(300)
80
+
81
+ const menuScrollView = page.getByTestId('menu-scroll-view')
82
+ await expect(menuScrollView).toBeVisible()
83
+
84
+ // first item should be visible
85
+ const firstItem = page.getByTestId('menu-item-1')
86
+ await expect(firstItem).toBeVisible()
87
+
88
+ // last item should exist but not be in view (requires scrolling)
89
+ const lastItem = page.getByTestId('menu-item-30')
90
+ await expect(lastItem).toBeAttached()
91
+ await expect(lastItem).not.toBeInViewport()
92
+ })
93
+ })
@@ -0,0 +1,102 @@
1
+ import { expect, test } from '@playwright/test'
2
+
3
+ test.describe('Menu stayInFrame', () => {
4
+ test('Menu bottom placement should not cover trigger', async ({ page }) => {
5
+ // Small viewport to test constraint behavior
6
+ await page.setViewportSize({ width: 400, height: 300 })
7
+
8
+ await page.goto('/?test=MenuBottomCase')
9
+ await page.waitForTimeout(500)
10
+
11
+ const trigger = page.getByTestId('menu-trigger')
12
+ const triggerBox = await trigger.boundingBox()
13
+ await trigger.click()
14
+ await page.waitForTimeout(300)
15
+
16
+ const menuContent = page.getByTestId('menu-content')
17
+ await expect(menuContent).toBeVisible()
18
+
19
+ const menuBox = await menuContent.boundingBox()
20
+ const viewport = page.viewportSize()!
21
+ const padding = 10
22
+
23
+ // Menu should be BELOW the trigger (placement="bottom-start", allowFlip={false})
24
+ // Menu top should be >= trigger bottom (with some tolerance for offset)
25
+ expect(menuBox!.y).toBeGreaterThanOrEqual(triggerBox!.y + triggerBox!.height - 5)
26
+
27
+ // Menu should fit within viewport with padding
28
+ expect(menuBox!.y + menuBox!.height).toBeLessThanOrEqual(
29
+ viewport.height - padding + 2
30
+ )
31
+ })
32
+
33
+ test('menu should not overflow viewport when near bottom edge', async ({ page }) => {
34
+ // Set a small viewport to make it easier to test overflow
35
+ await page.setViewportSize({ width: 400, height: 300 })
36
+
37
+ await page.goto('/?test=MenuOverflowCase')
38
+ await page.waitForTimeout(500)
39
+
40
+ // Click the menu trigger (it's at the bottom of the page in this test case)
41
+ const trigger = page.getByTestId('menu-trigger')
42
+ await trigger.click()
43
+ await page.waitForTimeout(300)
44
+
45
+ // Get the menu content element
46
+ const menuContent = page.getByTestId('menu-content')
47
+ await expect(menuContent).toBeVisible()
48
+
49
+ // Get the bounding box of the menu
50
+ const menuBox = await menuContent.boundingBox()
51
+ expect(menuBox).not.toBeNull()
52
+
53
+ // Get viewport size
54
+ const viewport = page.viewportSize()
55
+ expect(viewport).not.toBeNull()
56
+
57
+ // Menu should not overflow the viewport with 10px padding
58
+ const padding = 10
59
+
60
+ // Check that menu has at least 10px padding from top
61
+ expect(menuBox!.y).toBeGreaterThanOrEqual(padding - 2) // 2px tolerance
62
+
63
+ // Check that menu has at least 10px padding from bottom
64
+ expect(menuBox!.y + menuBox!.height).toBeLessThanOrEqual(
65
+ viewport!.height - padding + 2
66
+ )
67
+
68
+ // Check that menu right doesn't exceed viewport right
69
+ expect(menuBox!.x + menuBox!.width).toBeLessThanOrEqual(viewport!.width - padding + 5)
70
+
71
+ // Check that menu left doesn't go past viewport left
72
+ expect(menuBox!.x).toBeGreaterThanOrEqual(padding - 5)
73
+ })
74
+
75
+ test('menu should flip when not enough space below', async ({ page }) => {
76
+ await page.setViewportSize({ width: 400, height: 250 })
77
+
78
+ await page.goto('/?test=MenuOverflowCase')
79
+ await page.waitForTimeout(500)
80
+
81
+ const trigger = page.getByTestId('menu-trigger')
82
+ const triggerBox = await trigger.boundingBox()
83
+
84
+ await trigger.click()
85
+ await page.waitForTimeout(300)
86
+
87
+ const menuContent = page.getByTestId('menu-content')
88
+ await expect(menuContent).toBeVisible()
89
+
90
+ const menuBox = await menuContent.boundingBox()
91
+ expect(menuBox).not.toBeNull()
92
+ expect(triggerBox).not.toBeNull()
93
+
94
+ // Since trigger is at bottom and viewport is small, menu should flip to appear above
95
+ // OR stay within bounds via shift
96
+ const viewport = page.viewportSize()!
97
+
98
+ // The key assertion: menu should be fully visible within viewport
99
+ expect(menuBox!.y).toBeGreaterThanOrEqual(0)
100
+ expect(menuBox!.y + menuBox!.height).toBeLessThanOrEqual(viewport.height)
101
+ })
102
+ })