@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,70 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+ import { getStyles } from './utils'
4
+ import { TEST_IDS } from '../src/constants/test-ids'
5
+
6
+ test.beforeEach(async ({ page }) => {
7
+ await setupPage(page, { name: 'ThemeChange', type: 'useCase' })
8
+ })
9
+
10
+ test('Initial theme (yellow) renders with correct colors', async ({ page }) => {
11
+ // The expected yellow theme color in RGB format (themeDev palette)
12
+ const expectedYellowColor = 'rgb(255, 221, 0)'
13
+
14
+ // Get the theme info text to verify we're on yellow theme
15
+ const themeInfo0 = await page.locator(`#${TEST_IDS.themeInfo}-0`).textContent()
16
+ const themeInfo1 = await page.locator(`#${TEST_IDS.themeInfo}-1`).textContent()
17
+
18
+ // Verify both levels show yellow theme
19
+ expect(themeInfo0).toContain('"theme":"yellow"')
20
+ expect(themeInfo1).toContain('"theme":"yellow"')
21
+
22
+ // Get the styles for all squares
23
+ const staticSquare0Styles = await getStyles(page.locator(`#${TEST_IDS.staticSquare}-0`))
24
+ const staticSquare1Styles = await getStyles(page.locator(`#${TEST_IDS.staticSquare}-1`))
25
+ const dynamicSquare0Styles = await getStyles(
26
+ page.locator(`#${TEST_IDS.dynamicSquare}-0`)
27
+ )
28
+ const dynamicSquare1Styles = await getStyles(
29
+ page.locator(`#${TEST_IDS.dynamicSquare}-1`)
30
+ )
31
+
32
+ // Verify all squares have the yellow theme color
33
+ expect(staticSquare0Styles.backgroundColor).toBe(expectedYellowColor)
34
+ expect(staticSquare1Styles.backgroundColor).toBe(expectedYellowColor)
35
+ expect(dynamicSquare0Styles.backgroundColor).toBe(expectedYellowColor)
36
+ expect(dynamicSquare1Styles.backgroundColor).toBe(expectedYellowColor)
37
+ })
38
+
39
+ test('Inner theme change does not affect outer theme', async ({ page }) => {
40
+ // Initial colors (themeDev palette)
41
+ const initialYellowColor = 'rgb(255, 221, 0)'
42
+
43
+ // Get initial styles for both levels
44
+ const outerSquareInitial = await getStyles(page.locator(`#${TEST_IDS.staticSquare}-0`))
45
+ const innerSquareInitial = await getStyles(page.locator(`#${TEST_IDS.staticSquare}-1`))
46
+
47
+ // Verify both start with yellow
48
+ expect(outerSquareInitial.backgroundColor).toBe(initialYellowColor)
49
+ expect(innerSquareInitial.backgroundColor).toBe(initialYellowColor)
50
+
51
+ // Click the inner theme change button
52
+ await page.locator(`#${TEST_IDS.changeThemeButton}-1`).click()
53
+
54
+ // Get updated styles
55
+ const outerSquareAfter = await getStyles(page.locator(`#${TEST_IDS.staticSquare}-0`))
56
+ const innerSquareAfter = await getStyles(page.locator(`#${TEST_IDS.staticSquare}-1`))
57
+
58
+ // Verify outer square remains yellow
59
+ expect(outerSquareAfter.backgroundColor).toBe(initialYellowColor)
60
+
61
+ // Verify inner square has changed (not yellow anymore)
62
+ expect(innerSquareAfter.backgroundColor).not.toBe(initialYellowColor)
63
+
64
+ // Verify theme info text reflects changes
65
+ const outerThemeInfo = await page.locator(`#${TEST_IDS.themeInfo}-0`).textContent()
66
+ const innerThemeInfo = await page.locator(`#${TEST_IDS.themeInfo}-1`).textContent()
67
+
68
+ expect(outerThemeInfo).toContain('"theme":"yellow"')
69
+ expect(innerThemeInfo).not.toContain('"theme":"yellow"')
70
+ })
@@ -0,0 +1,82 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+ import { TEST_IDS } from '../src/constants/test-ids'
4
+
5
+ /**
6
+ * Tests for theme component resolution (commit 5839319146 goals)
7
+ *
8
+ * These tests verify that the theme resolution algorithm correctly handles:
9
+ * 1. Explicit scheme overrides (e.g., dark_green inside blue parent)
10
+ * 2. Inheriting scheme from parent for component themes
11
+ * 3. Preserving sub-themes when only componentName is provided (no backtracking)
12
+ */
13
+
14
+ test.beforeEach(async ({ page }) => {
15
+ // Use v4 themes as these tests require theme names like light_green, dark_green, etc.
16
+ await setupPage(page, {
17
+ name: 'ThemeComponentResolution',
18
+ type: 'useCase',
19
+ searchParams: { v4theme: 'true' },
20
+ })
21
+ })
22
+
23
+ test.describe('Goal 1a: Explicit scheme override', () => {
24
+ test('dark_green theme is preserved when nested inside blue parent', async ({
25
+ page,
26
+ }) => {
27
+ // Direct dark_green theme
28
+ const directSquare = page.locator(`#${TEST_IDS.themeExplicitSchemeDirect}`)
29
+ await expect(directSquare).toBeVisible()
30
+
31
+ // Nested: blue → dark_green
32
+ const nestedSquare = page.locator(`#${TEST_IDS.themeExplicitSchemeNested}`)
33
+ await expect(nestedSquare).toBeVisible()
34
+
35
+ // Both should have the same theme name (dark_green)
36
+ const directText = await directSquare.innerText()
37
+ const nestedText = await nestedSquare.innerText()
38
+
39
+ expect(directText).toBe('dark_green')
40
+ expect(nestedText).toBe('dark_green')
41
+ })
42
+ })
43
+
44
+ test.describe('Goal 1b: Inherit scheme from parent', () => {
45
+ test('green theme inherits light scheme from parent', async ({ page }) => {
46
+ // Direct light_green theme
47
+ const directSquare = page.locator(`#${TEST_IDS.themeInheritSchemeDirect}`)
48
+ await expect(directSquare).toBeVisible()
49
+
50
+ // Nested: light → green
51
+ const nestedSquare = page.locator(`#${TEST_IDS.themeInheritSchemeNested}`)
52
+ await expect(nestedSquare).toBeVisible()
53
+
54
+ // Both should resolve to light_green
55
+ const directText = await directSquare.innerText()
56
+ const nestedText = await nestedSquare.innerText()
57
+
58
+ expect(directText).toBe('light_green')
59
+ expect(nestedText).toBe('light_green')
60
+ })
61
+ })
62
+
63
+ test.describe('Goal 2: Sub-theme preservation', () => {
64
+ test('surface1 sub-theme is preserved when nested (no backtracking)', async ({
65
+ page,
66
+ }) => {
67
+ // Direct light_blue_surface1
68
+ const directSquare = page.locator(`#${TEST_IDS.themeSurface1Direct}`)
69
+ await expect(directSquare).toBeVisible()
70
+
71
+ // Nested: blue → surface1
72
+ const nestedSquare = page.locator(`#${TEST_IDS.themeSurface1WithComponent}`)
73
+ await expect(nestedSquare).toBeVisible()
74
+
75
+ // Both should be light_blue_surface1
76
+ const directText = await directSquare.innerText()
77
+ const nestedText = await nestedSquare.innerText()
78
+
79
+ expect(directText).toBe('light_blue_surface1')
80
+ expect(nestedText).toBe('light_blue_surface1')
81
+ })
82
+ })
@@ -0,0 +1,34 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+ import { getStyles } from './utils'
4
+
5
+ test.beforeEach(async ({ page }) => {
6
+ await setupPage(page, { name: 'ThemeConditionalName', type: 'useCase' })
7
+ })
8
+
9
+ test('Theme reverts to parent when name changes from accent to undefined', async ({
10
+ page,
11
+ }) => {
12
+ const parent = page.locator('#theme-conditional-parent')
13
+ const child = page.locator('#theme-conditional-child')
14
+ const toggle = page.locator('#theme-conditional-toggle')
15
+
16
+ // initially active=false, child should match parent (no theme override)
17
+ const parentInitial = await getStyles(parent)
18
+ const childInitial = await getStyles(child)
19
+ expect(childInitial.backgroundColor).toBe(parentInitial.backgroundColor)
20
+
21
+ // toggle active=true, child gets accent theme — should differ from parent
22
+ await toggle.click()
23
+ await page.waitForTimeout(100)
24
+ const parentActive = await getStyles(parent)
25
+ const childActive = await getStyles(child)
26
+ expect(childActive.backgroundColor).not.toBe(parentActive.backgroundColor)
27
+
28
+ // toggle active=false again, child should revert to parent theme
29
+ await toggle.click()
30
+ await page.waitForTimeout(100)
31
+ const parentReverted = await getStyles(parent)
32
+ const childReverted = await getStyles(child)
33
+ expect(childReverted.backgroundColor).toBe(parentReverted.backgroundColor)
34
+ })
@@ -0,0 +1,65 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+
4
+ // $theme-dark + animateOnly fix was intentionally reverted (80d70ce595)
5
+ test.skip()
6
+
7
+ test.describe('Theme Media + Animation', () => {
8
+ test('$theme-dark bg applies when animated with motion driver', async ({ page }) => {
9
+ await setupPage(page, {
10
+ name: 'ThemeMediaAnimationCase',
11
+ type: 'useCase',
12
+ theme: 'dark',
13
+ searchParams: { animationDriver: 'motion' },
14
+ })
15
+
16
+ const animatedBg = await page.evaluate(() => {
17
+ const el = document.querySelector('[data-testid="theme-media-animated"]')
18
+ return el ? getComputedStyle(el).backgroundColor : null
19
+ })
20
+
21
+ const staticBg = await page.evaluate(() => {
22
+ const el = document.querySelector('[data-testid="theme-media-static"]')
23
+ return el ? getComputedStyle(el).backgroundColor : null
24
+ })
25
+
26
+ // both should have the same background color in dark mode
27
+ // ($theme-dark overrides bg to $color3)
28
+ expect(animatedBg).toBeTruthy()
29
+ expect(staticBg).toBeTruthy()
30
+ expect(animatedBg).toBe(staticBg)
31
+ })
32
+
33
+ test('$theme-dark bg differs from light theme when animated', async ({ page }) => {
34
+ // light theme
35
+ await setupPage(page, {
36
+ name: 'ThemeMediaAnimationCase',
37
+ type: 'useCase',
38
+ theme: 'light',
39
+ searchParams: { animationDriver: 'motion' },
40
+ })
41
+
42
+ const lightBg = await page.evaluate(() => {
43
+ const el = document.querySelector('[data-testid="theme-media-animated"]')
44
+ return el ? getComputedStyle(el).backgroundColor : null
45
+ })
46
+
47
+ // dark theme
48
+ await setupPage(page, {
49
+ name: 'ThemeMediaAnimationCase',
50
+ type: 'useCase',
51
+ theme: 'dark',
52
+ searchParams: { animationDriver: 'motion' },
53
+ })
54
+
55
+ const darkBg = await page.evaluate(() => {
56
+ const el = document.querySelector('[data-testid="theme-media-animated"]')
57
+ return el ? getComputedStyle(el).backgroundColor : null
58
+ })
59
+
60
+ // $theme-dark changes bg from $color1 to $color3, so they should differ
61
+ expect(lightBg).toBeTruthy()
62
+ expect(darkBg).toBeTruthy()
63
+ expect(lightBg).not.toBe(darkBg)
64
+ })
65
+ })
@@ -0,0 +1,141 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+ import { getStyles } from './utils'
4
+ import { TEST_IDS } from '../src/constants/test-ids'
5
+
6
+ /**
7
+ * Tests for GitHub issue #3673: Nested theme regression
8
+ *
9
+ * When using nested themes like <Theme name="blue"><Theme name="surface3">,
10
+ * the parent color context (blue) should be preserved, resulting in
11
+ * light_blue_surface3 theme being applied.
12
+ *
13
+ * The bug causes the nested theme to lose the color context, resulting in
14
+ * just light_surface3 being applied instead.
15
+ */
16
+
17
+ test.beforeEach(async ({ page }) => {
18
+ // Test the nested theme regression (issue #3673)
19
+ // Use v4 themes as the bug specifically occurs with @hanzogui/themes/v4
20
+ await setupPage(page, {
21
+ name: 'ThemeNested',
22
+ type: 'useCase',
23
+ searchParams: { v4theme: 'true' },
24
+ })
25
+ })
26
+
27
+ test('Nested blue theme with surface3 matches direct light_blue_surface3', async ({
28
+ page,
29
+ }) => {
30
+ // Get the direct theme element
31
+ const directSquare = page.locator(`#${TEST_IDS.nestedThemeDirect}`)
32
+ await expect(directSquare).toBeVisible()
33
+
34
+ // Get the nested theme element
35
+ const nestedSquare = page.locator(`#${TEST_IDS.nestedThemeNested}`)
36
+ await expect(nestedSquare).toBeVisible()
37
+
38
+ // Get computed styles for both
39
+ const directStyles = await getStyles(directSquare)
40
+ const nestedStyles = await getStyles(nestedSquare)
41
+
42
+ // The nested theme should produce the same background color as the direct theme
43
+ // If the bug is present, nestedStyles will have light_surface3 colors instead of light_blue_surface3
44
+ expect(nestedStyles.backgroundColor).toBe(directStyles.backgroundColor)
45
+ })
46
+
47
+ test('Nested light → blue → surface3 matches direct light_blue_surface3', async ({
48
+ page,
49
+ }) => {
50
+ // Get the direct theme element
51
+ const directSquare = page.locator(`#${TEST_IDS.nestedThemeDirect}`)
52
+ await expect(directSquare).toBeVisible()
53
+
54
+ // Get the nested theme with explicit light parent
55
+ const nestedWithParent = page.locator(`#${TEST_IDS.nestedThemeWithParent}`)
56
+ await expect(nestedWithParent).toBeVisible()
57
+
58
+ // Get computed styles for both
59
+ const directStyles = await getStyles(directSquare)
60
+ const nestedStyles = await getStyles(nestedWithParent)
61
+
62
+ // The nested theme should produce the same background color as the direct theme
63
+ expect(nestedStyles.backgroundColor).toBe(directStyles.backgroundColor)
64
+ })
65
+
66
+ test('Nested red theme with surface3 matches direct light_red_surface3', async ({
67
+ page,
68
+ }) => {
69
+ // Get the direct red theme element
70
+ const redDirectSquare = page.locator(`#${TEST_IDS.nestedThemeRedDirect}`)
71
+ await expect(redDirectSquare).toBeVisible()
72
+
73
+ // Get the nested red theme element
74
+ const redNestedSquare = page.locator(`#${TEST_IDS.nestedThemeRedNested}`)
75
+ await expect(redNestedSquare).toBeVisible()
76
+
77
+ // Get computed styles for both
78
+ const redDirectStyles = await getStyles(redDirectSquare)
79
+ const redNestedStyles = await getStyles(redNestedSquare)
80
+
81
+ // The nested theme should produce the same background color as the direct theme
82
+ expect(redNestedStyles.backgroundColor).toBe(redDirectStyles.backgroundColor)
83
+ })
84
+
85
+ test('Blue surface3 differs from colorless surface3', async ({ page }) => {
86
+ // Get the blue nested theme
87
+ const blueNestedSquare = page.locator(`#${TEST_IDS.nestedThemeNested}`)
88
+ await expect(blueNestedSquare).toBeVisible()
89
+
90
+ // Get the colorless surface3 theme
91
+ const noColorSquare = page.locator(`#${TEST_IDS.nestedThemeNoColor}`)
92
+ await expect(noColorSquare).toBeVisible()
93
+
94
+ // Get computed styles for both
95
+ const blueStyles = await getStyles(blueNestedSquare)
96
+ const noColorStyles = await getStyles(noColorSquare)
97
+
98
+ // The blue surface3 should have a different background than the colorless surface3
99
+ // This verifies that color context actually makes a difference
100
+ expect(blueStyles.backgroundColor).not.toBe(noColorStyles.backgroundColor)
101
+ })
102
+
103
+ test('Blue surface3 differs from red surface3', async ({ page }) => {
104
+ // Get the blue nested theme
105
+ const blueNestedSquare = page.locator(`#${TEST_IDS.nestedThemeNested}`)
106
+ await expect(blueNestedSquare).toBeVisible()
107
+
108
+ // Get the red nested theme
109
+ const redNestedSquare = page.locator(`#${TEST_IDS.nestedThemeRedNested}`)
110
+ await expect(redNestedSquare).toBeVisible()
111
+
112
+ // Get computed styles for both
113
+ const blueStyles = await getStyles(blueNestedSquare)
114
+ const redStyles = await getStyles(redNestedSquare)
115
+
116
+ // Different color contexts should produce different backgrounds
117
+ expect(blueStyles.backgroundColor).not.toBe(redStyles.backgroundColor)
118
+ })
119
+
120
+ test('Nested blue → surface1 → surface3 preserves blue color context', async ({
121
+ page,
122
+ }) => {
123
+ // This is the exact reproduction case from issue #3673
124
+ // Using surface3 theme inside a surface1 theme should preserve the blue color context
125
+
126
+ // Get the direct blue_surface3 element
127
+ const directSquare = page.locator(`#${TEST_IDS.nestedSurface1To3Direct}`)
128
+ await expect(directSquare).toBeVisible()
129
+
130
+ // Get the nested blue → surface1 → surface3 element
131
+ const nestedSquare = page.locator(`#${TEST_IDS.nestedSurface1To3Nested}`)
132
+ await expect(nestedSquare).toBeVisible()
133
+
134
+ // Get computed styles for both
135
+ const directStyles = await getStyles(directSquare)
136
+ const nestedStyles = await getStyles(nestedSquare)
137
+
138
+ // The nested theme should produce the same background color as the direct theme
139
+ // If the bug is present, nestedStyles will have light_surface3 colors instead of light_blue_surface3
140
+ expect(nestedStyles.backgroundColor).toBe(directStyles.backgroundColor)
141
+ })
@@ -0,0 +1,63 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+ import { getStyles } from './utils'
4
+ import { TEST_IDS } from '../src/constants/test-ids'
5
+
6
+ test.beforeEach(async ({ page }) => {
7
+ await setupPage(page, { name: 'ThemeReset', type: 'useCase' })
8
+ })
9
+
10
+ test('Reset from nested themes goes back to grandparent', async ({ page }) => {
11
+ // Case 1: Reset from dark → pink → blue should go back to dark
12
+ const resetButton1 = page.locator(`#${TEST_IDS.resetButton1}`)
13
+ await expect(resetButton1).toBeVisible()
14
+
15
+ // Get the background color of the button
16
+ const button1Styles = await getStyles(resetButton1)
17
+
18
+ // The button should have dark theme background (not pink or blue)
19
+ // Dark theme typically has a dark background
20
+ expect(button1Styles.backgroundColor).not.toBe('rgb(255, 192, 203)') // pink
21
+ expect(button1Styles.backgroundColor).not.toBe('rgb(0, 0, 255)') // blue
22
+ })
23
+
24
+ test('Reset from dark → pink goes back to dark (documentation example)', async ({
25
+ page,
26
+ }) => {
27
+ // Case 2: Reset from dark → pink should go back to dark
28
+ const resetSquare1 = page.locator(`#${TEST_IDS.resetSquare1}`)
29
+ await expect(resetSquare1).toBeVisible()
30
+
31
+ const square1Styles = await getStyles(resetSquare1)
32
+
33
+ // The square should have dark theme background
34
+ // This matches the documentation example
35
+ expect(square1Styles.backgroundColor).not.toBe('rgb(255, 192, 203)') // pink
36
+ })
37
+
38
+ test('Reset from dark only goes to light', async ({ page }) => {
39
+ // Case 3: Reset from dark only should go to light (opposite scheme)
40
+ const resetSquare2 = page.locator(`#${TEST_IDS.resetSquare2}`)
41
+ await expect(resetSquare2).toBeVisible()
42
+
43
+ const square2Styles = await getStyles(resetSquare2)
44
+
45
+ // The square should have light theme background (opposite of dark)
46
+ expect(square2Styles.backgroundColor).not.toBe('rgb(0, 0, 0)') // black/dark
47
+ })
48
+
49
+ test('Reset from dark with button shows different themes', async ({ page }) => {
50
+ // Case 4: Dark button vs reset button should have different themes
51
+ const darkButton = page.locator(`#${TEST_IDS.darkButton}`)
52
+ const resetButton2 = page.locator(`#${TEST_IDS.resetButton2}`)
53
+
54
+ await expect(darkButton).toBeVisible()
55
+ await expect(resetButton2).toBeVisible()
56
+
57
+ const darkButtonStyles = await getStyles(darkButton)
58
+ const resetButton2Styles = await getStyles(resetButton2)
59
+
60
+ // The buttons should have different background colors
61
+ // Dark button should have dark theme, reset button should have light theme
62
+ expect(darkButtonStyles.backgroundColor).not.toBe(resetButton2Styles.backgroundColor)
63
+ })
@@ -0,0 +1,95 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+ import { TEST_IDS } from '../src/constants/test-ids'
4
+
5
+ /**
6
+ * Tests for themeShallow prop DOM structure stability
7
+ *
8
+ * The themeShallow prop should NOT affect DOM structure (span wrapping).
9
+ * It only affects whether grandchildren inherit the theme change.
10
+ *
11
+ * This test verifies that themeShallow doesn't cause unexpected DOM changes.
12
+ */
13
+
14
+ test.beforeEach(async ({ page }) => {
15
+ await setupPage(page, { name: 'ThemeShallowCase', type: 'useCase' })
16
+ })
17
+
18
+ test('themeShallow does not add extra wrapper elements compared to normal theme', async ({
19
+ page,
20
+ }) => {
21
+ const normalContainer = page.locator(`#${TEST_IDS.themeShallowNormal}`)
22
+ const shallowContainer = page.locator(`#${TEST_IDS.themeShallowEnabled}`)
23
+
24
+ await expect(normalContainer).toBeVisible()
25
+ await expect(shallowContainer).toBeVisible()
26
+
27
+ // Get the DOM structure depth for both containers
28
+ // Count the number of wrapper elements between the container and its text content
29
+ const normalDepth = await normalContainer.evaluate((el) => {
30
+ let depth = 0
31
+ let current = el.querySelector('[class*="is_Theme"]')
32
+ while (current && current !== el) {
33
+ depth++
34
+ current = current.parentElement
35
+ }
36
+ return depth
37
+ })
38
+
39
+ const shallowDepth = await shallowContainer.evaluate((el) => {
40
+ let depth = 0
41
+ let current = el.querySelector('[class*="is_Theme"]')
42
+ while (current && current !== el) {
43
+ depth++
44
+ current = current.parentElement
45
+ }
46
+ return depth
47
+ })
48
+
49
+ // The DOM structure depth should be the same regardless of themeShallow
50
+ // themeShallow only affects theme context propagation, not DOM structure
51
+ expect(shallowDepth).toBe(normalDepth)
52
+ })
53
+
54
+ test('themeShallow container has consistent DOM structure', async ({ page }) => {
55
+ const container = page.locator(`#${TEST_IDS.themeShallowContainer}`)
56
+ const inner = page.locator(`#${TEST_IDS.themeShallowInner}`)
57
+
58
+ await expect(container).toBeVisible()
59
+ await expect(inner).toBeVisible()
60
+
61
+ // Snapshot the inner HTML structure to catch any regressions
62
+ const innerHtml = await inner.evaluate((el) => {
63
+ // Normalize the HTML by removing dynamic attributes like data-* IDs
64
+ const clone = el.cloneNode(true) as HTMLElement
65
+ clone.querySelectorAll('*').forEach((node) => {
66
+ // Remove dynamic attributes that change between runs
67
+ Array.from(node.attributes).forEach((attr) => {
68
+ if (
69
+ attr.name.startsWith('data-') &&
70
+ !attr.name.startsWith('data-test') &&
71
+ !attr.name.startsWith('data-disable')
72
+ ) {
73
+ node.removeAttribute(attr.name)
74
+ }
75
+ })
76
+ })
77
+ return clone.innerHTML
78
+ })
79
+
80
+ // The inner container should have text content wrapped appropriately
81
+ expect(innerHtml).toContain('Inner content')
82
+
83
+ // Verify Theme wrapper spans are present (theme always wraps in span on web)
84
+ const themeSpans = await container.locator('span.is_Theme').count()
85
+ expect(themeSpans).toBeGreaterThan(0)
86
+ })
87
+
88
+ test('themeShallow prop does not change element tag type', async ({ page }) => {
89
+ const shallowContainer = page.locator(`#${TEST_IDS.themeShallowEnabled}`)
90
+ await expect(shallowContainer).toBeVisible()
91
+
92
+ // The container itself should be a div (Stack renders as div)
93
+ const tagName = await shallowContainer.evaluate((el) => el.tagName.toLowerCase())
94
+ expect(tagName).toBe('div')
95
+ })
@@ -0,0 +1,106 @@
1
+ import type { Page } from '@playwright/test'
2
+ import { expect, test } from '@playwright/test'
3
+
4
+ import { setupPage } from './test-utils'
5
+
6
+ test.beforeEach(async ({ page }) => {
7
+ await setupPage(page, { name: 'ToastCase', type: 'useCase' })
8
+ })
9
+
10
+ async function buttonIsFocused(page: Page, identifier: number) {
11
+ await expect(page.getByTestId(`toast-button-${identifier}`)).toBeFocused()
12
+ }
13
+
14
+ async function toastIsFocused(page: Page, identifier: number) {
15
+ await expect(page.getByTestId(`toast-${identifier}`)).toBeFocused()
16
+ }
17
+
18
+ test.describe('given zero toasts', () => {
19
+ test('should not interrupt natural tab order in the document', async ({ page }) => {
20
+ await page.getByTestId('button-before').focus()
21
+
22
+ await page.keyboard.press('Tab')
23
+
24
+ await expect(page.getByTestId('button-after')).toBeFocused()
25
+
26
+ await page.keyboard.press('Shift+Tab')
27
+
28
+ await expect(page.getByTestId('button-before')).toBeFocused()
29
+ })
30
+ })
31
+
32
+ test.describe('given multiple toasts', () => {
33
+ test.beforeEach(async ({ page }) => {
34
+ await page.getByTestId('button-add-toast').click()
35
+ await page.getByTestId('button-add-toast').click()
36
+ await new Promise((res) => setTimeout(res, 1000))
37
+ })
38
+
39
+ test('should reverse tab order from most recent to least', async ({ page }) => {
40
+ await page.getByTestId('button-before').focus()
41
+
42
+ await page.keyboard.press('Tab')
43
+ await toastIsFocused(page, 2)
44
+
45
+ // Forward tab
46
+ await page.keyboard.press('Tab')
47
+ await buttonIsFocused(page, 2.1)
48
+
49
+ await page.keyboard.press('Tab')
50
+ await buttonIsFocused(page, 2.2)
51
+
52
+ await page.keyboard.press('Tab')
53
+ await toastIsFocused(page, 1)
54
+
55
+ await page.keyboard.press('Tab')
56
+ await buttonIsFocused(page, 1.1)
57
+
58
+ await page.keyboard.press('Tab')
59
+ await buttonIsFocused(page, 1.2)
60
+
61
+ // End of viewport
62
+ await page.keyboard.press('Tab')
63
+ await expect(page.getByTestId('button-after')).toBeFocused()
64
+
65
+ // Backwards tab
66
+ await page.keyboard.press('Shift+Tab')
67
+ await buttonIsFocused(page, 1.2)
68
+
69
+ await page.keyboard.press('Shift+Tab')
70
+ await buttonIsFocused(page, 1.1)
71
+
72
+ await page.keyboard.press('Shift+Tab')
73
+ await toastIsFocused(page, 1)
74
+
75
+ await page.keyboard.press('Shift+Tab')
76
+ await buttonIsFocused(page, 2.2)
77
+
78
+ await page.keyboard.press('Shift+Tab')
79
+ await buttonIsFocused(page, 2.1)
80
+
81
+ await page.keyboard.press('Shift+Tab')
82
+ await toastIsFocused(page, 2)
83
+
84
+ // Start of viewport
85
+ await page.keyboard.press('Shift+Tab')
86
+ await expect(page.getByTestId('button-before')).toBeFocused()
87
+ })
88
+
89
+ test('should tab forwards from viewport to latest toast or backwards into the document', async ({
90
+ page,
91
+ }) => {
92
+ // Focus viewport directly instead of using F8
93
+ const viewport = page.locator('[role="region"][aria-label="Notifications (F8)"]')
94
+ await viewport.focus()
95
+ await expect(viewport).toBeFocused()
96
+
97
+ // Tab forward from viewport
98
+ await page.keyboard.press('Tab')
99
+ await toastIsFocused(page, 2)
100
+
101
+ // Tab backward from viewport - focus viewport again
102
+ await viewport.focus()
103
+ await page.keyboard.press('Shift+Tab')
104
+ await expect(page.getByTestId('button-before')).toBeFocused()
105
+ })
106
+ })