@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,259 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ await setupPage(page, { name: 'SheetSnapPointsFitCase', type: 'useCase' })
6
+ })
7
+
8
+ test.describe('Sheet snapPointsMode="fit"', () => {
9
+ test('standalone sheet with fit mode opens and closes without issues', async ({
10
+ page,
11
+ }) => {
12
+ const trigger = page.getByTestId('standalone-fit-trigger')
13
+ const frame = page.getByTestId('standalone-fit-frame')
14
+ const closeButton = page.getByTestId('standalone-fit-close')
15
+
16
+ // Initial state - sheet should not be visible
17
+ await expect(trigger).toBeVisible()
18
+ await expect(frame).not.toBeInViewport({ ratio: 0.5 })
19
+
20
+ // Open the sheet
21
+ await trigger.click()
22
+
23
+ // Wait for sheet to be visible
24
+ await expect(frame).toBeVisible({ timeout: 5000 })
25
+
26
+ // Close the sheet
27
+ await closeButton.click()
28
+
29
+ // Wait for animation to complete
30
+ await page.waitForTimeout(500)
31
+
32
+ // Sheet should not be visible
33
+ await expect(frame).not.toBeInViewport({ ratio: 0.5 })
34
+ })
35
+
36
+ test('standalone sheet with percent mode opens and closes without issues', async ({
37
+ page,
38
+ }) => {
39
+ const trigger = page.getByTestId('standalone-percent-trigger')
40
+ const frame = page.getByTestId('standalone-percent-frame')
41
+ const closeButton = page.getByTestId('standalone-percent-close')
42
+
43
+ await expect(trigger).toBeVisible()
44
+ await expect(frame).not.toBeInViewport({ ratio: 0.5 })
45
+
46
+ await trigger.click()
47
+ await expect(frame).toBeVisible({ timeout: 5000 })
48
+
49
+ await closeButton.click()
50
+ await page.waitForTimeout(500)
51
+ await expect(frame).not.toBeInViewport({ ratio: 0.5 })
52
+ })
53
+
54
+ test('standalone sheet with constant mode opens and closes without issues', async ({
55
+ page,
56
+ }) => {
57
+ const trigger = page.getByTestId('standalone-constant-trigger')
58
+ const frame = page.getByTestId('standalone-constant-frame')
59
+ const closeButton = page.getByTestId('standalone-constant-close')
60
+
61
+ await expect(trigger).toBeVisible()
62
+ await expect(frame).not.toBeInViewport({ ratio: 0.5 })
63
+
64
+ await trigger.click()
65
+ await expect(frame).toBeVisible({ timeout: 5000 })
66
+
67
+ await closeButton.click()
68
+ await page.waitForTimeout(500)
69
+ await expect(frame).not.toBeInViewport({ ratio: 0.5 })
70
+ })
71
+
72
+ test('rapid open/close interactions work correctly', async ({ page }) => {
73
+ const trigger = page.getByTestId('rapid-toggle-trigger')
74
+ const frame = page.getByTestId('rapid-frame')
75
+ const closeButton = page.getByTestId('rapid-close')
76
+
77
+ await expect(trigger).toBeVisible()
78
+
79
+ // Open the sheet
80
+ await trigger.click()
81
+ await expect(frame).toBeVisible({ timeout: 5000 })
82
+
83
+ // Close and reopen rapidly a few times using the close button
84
+ for (let i = 0; i < 3; i++) {
85
+ await closeButton.click()
86
+ await page.waitForTimeout(300) // Wait for close animation
87
+ await trigger.click()
88
+ await expect(frame).toBeVisible({ timeout: 5000 })
89
+ }
90
+
91
+ // Final close
92
+ await closeButton.click()
93
+ await page.waitForTimeout(500)
94
+
95
+ // Sheet should be closed now
96
+ await expect(frame).not.toBeInViewport({ ratio: 0.5 })
97
+ })
98
+
99
+ test('dynamic content changes while sheet is open', async ({ page }) => {
100
+ const trigger = page.getByTestId('dynamic-content-trigger')
101
+ const frame = page.getByTestId('dynamic-content-frame')
102
+ const closeButton = page.getByTestId('dynamic-content-close')
103
+ const sizeText = page.getByTestId('dynamic-content-size')
104
+ const smallButton = page.getByTestId('dynamic-content-small')
105
+ const mediumButton = page.getByTestId('dynamic-content-medium')
106
+ const largeButton = page.getByTestId('dynamic-content-large')
107
+
108
+ // Open the sheet
109
+ await trigger.click()
110
+ await expect(frame).toBeVisible({ timeout: 5000 })
111
+
112
+ // Initial size should be small
113
+ await expect(sizeText).toContainText('small')
114
+
115
+ // Get initial frame height
116
+ const initialBox = await frame.boundingBox()
117
+ const initialHeight = initialBox?.height ?? 0
118
+
119
+ // Change to medium content
120
+ await mediumButton.click()
121
+ await expect(sizeText).toContainText('medium')
122
+ await page.waitForTimeout(300) // Wait for resize animation
123
+
124
+ // Get medium frame height - should be larger
125
+ const mediumBox = await frame.boundingBox()
126
+ const mediumHeight = mediumBox?.height ?? 0
127
+ expect(mediumHeight).toBeGreaterThan(initialHeight)
128
+
129
+ // Change to large content
130
+ await largeButton.click()
131
+ await expect(sizeText).toContainText('large')
132
+ await page.waitForTimeout(300)
133
+
134
+ // Get large frame height - should be even larger
135
+ const largeBox = await frame.boundingBox()
136
+ const largeHeight = largeBox?.height ?? 0
137
+ expect(largeHeight).toBeGreaterThan(mediumHeight)
138
+
139
+ // Change back to small
140
+ await smallButton.click()
141
+ await expect(sizeText).toContainText('small')
142
+ await page.waitForTimeout(300)
143
+
144
+ // Close the sheet - this is the key test for the white flash fix
145
+ // The sheet should close from its current height without flashing to full viewport
146
+ await closeButton.click()
147
+ await page.waitForTimeout(500)
148
+
149
+ // Sheet should be closed
150
+ await expect(frame).not.toBeInViewport({ ratio: 0.5 })
151
+ })
152
+
153
+ test('sheet closes without white flash - frame height stays stable during close', async ({
154
+ page,
155
+ }) => {
156
+ const trigger = page.getByTestId('standalone-fit-trigger')
157
+ const frame = page.getByTestId('standalone-fit-frame')
158
+ const closeButton = page.getByTestId('standalone-fit-close')
159
+
160
+ // Open the sheet
161
+ await trigger.click()
162
+ await expect(frame).toBeVisible({ timeout: 5000 })
163
+
164
+ // Get the frame height when open
165
+ const openBox = await frame.boundingBox()
166
+ const openHeight = openBox?.height ?? 0
167
+
168
+ // The height should be reasonable (not full viewport)
169
+ // For a fit mode sheet with minimal content, it should be less than half viewport
170
+ const viewportSize = page.viewportSize()
171
+ const viewportHeight = viewportSize?.height ?? 768
172
+ expect(openHeight).toBeLessThan(viewportHeight * 0.6)
173
+
174
+ // Close the sheet and check that height doesn't spike
175
+ await closeButton.click()
176
+
177
+ // Monitor frame height during close animation
178
+ // The fix prevents the frame from expanding to full viewport during close
179
+ let maxHeightDuringClose = openHeight
180
+ for (let i = 0; i < 5; i++) {
181
+ await page.waitForTimeout(100)
182
+ const box = await frame.boundingBox()
183
+ if (box) {
184
+ maxHeightDuringClose = Math.max(maxHeightDuringClose, box.height)
185
+ }
186
+ }
187
+
188
+ // The max height during close should not be significantly larger than when open
189
+ // This verifies the fix for the white flash issue (expanding to full viewport)
190
+ // Allow some tolerance for animation overshoot
191
+ expect(maxHeightDuringClose).toBeLessThan(openHeight * 1.5)
192
+ })
193
+ })
194
+
195
+ test.describe('Adapted Dialog Sheet', () => {
196
+ // TODO: This test is flaky in CI - the adaptation may not trigger reliably at 500px
197
+ // The core functionality is tested by other Sheet tests
198
+ test.skip('dialog adapts to sheet on small screens and closes properly', async ({
199
+ page,
200
+ }) => {
201
+ // Set viewport to small size to trigger adaptation
202
+ await page.setViewportSize({ width: 500, height: 800 })
203
+ await page.reload()
204
+ await page.waitForLoadState('networkidle')
205
+
206
+ const trigger = page.getByTestId('adapted-dialog-trigger')
207
+ const sheetFrame = page.getByTestId('adapted-sheet-frame')
208
+ const dialogContent = page.getByTestId('adapted-dialog-content')
209
+
210
+ await expect(trigger).toBeVisible()
211
+
212
+ // Open - should show as sheet on small viewport
213
+ await trigger.click()
214
+ await page.waitForTimeout(500)
215
+
216
+ // On small viewport, should be adapted to sheet
217
+ const isSheetVisible = await sheetFrame.isVisible()
218
+ const isDialogVisible = await dialogContent.isVisible()
219
+
220
+ // At least one should be visible (either adapted sheet or dialog)
221
+ expect(isSheetVisible || isDialogVisible).toBe(true)
222
+
223
+ // Close via close button (works in both sheet and dialog mode via Adapt.Contents)
224
+ const closeButton = page.getByTestId('adapted-dialog-close')
225
+ await closeButton.click()
226
+ await page.waitForTimeout(500)
227
+
228
+ // Should be closed - sheet frame should not be in viewport
229
+ // Note: dialogContent may still be in DOM but the sheet frame should be off-screen
230
+ await expect(sheetFrame).not.toBeInViewport({ ratio: 0.5 })
231
+ })
232
+
233
+ test('dialog shows as dialog on large screens', async ({ page }) => {
234
+ // Set viewport to large size - no adaptation
235
+ await page.setViewportSize({ width: 1200, height: 800 })
236
+ await page.reload()
237
+ await page.waitForLoadState('networkidle')
238
+
239
+ const trigger = page.getByTestId('adapted-dialog-trigger')
240
+ const dialogContent = page.getByTestId('adapted-dialog-content')
241
+ const closeButton = page.getByTestId('adapted-dialog-close')
242
+
243
+ await expect(trigger).toBeVisible()
244
+
245
+ // Open - should show as dialog on large viewport
246
+ await trigger.click()
247
+ await page.waitForTimeout(500)
248
+
249
+ // Dialog content should be visible
250
+ await expect(dialogContent).toBeVisible()
251
+
252
+ // Close
253
+ await closeButton.click()
254
+ await page.waitForTimeout(500)
255
+
256
+ // Should be closed
257
+ await expect(dialogContent).not.toBeVisible()
258
+ })
259
+ })
@@ -0,0 +1,44 @@
1
+ import { expect, test } from '@playwright/test'
2
+
3
+ import { setupPage } from './test-utils'
4
+ import { getStyles } from './utils'
5
+
6
+ test.beforeEach(async ({ page }) => {
7
+ await setupPage(page, { name: 'ShorthandVariables', type: 'useCase' })
8
+ })
9
+
10
+ test(`boxShadow with $variable resolves correctly`, async ({ page }) => {
11
+ const element = page.locator('#boxshadow-var')
12
+ const styles = await getStyles(element)
13
+
14
+ // Should have boxShadow with resolved color (not containing $)
15
+ expect(styles.boxShadow).toBeDefined()
16
+ expect(styles.boxShadow).not.toContain('$')
17
+ expect(styles.boxShadow).toContain('0px 0px 10px')
18
+ })
19
+
20
+ test(`boxShadow with multiple $variables resolves correctly`, async ({ page }) => {
21
+ const element = page.locator('#boxshadow-multi')
22
+ const styles = await getStyles(element)
23
+
24
+ // Should have boxShadow with multiple shadows, both colors resolved
25
+ expect(styles.boxShadow).toBeDefined()
26
+ expect(styles.boxShadow).not.toContain('$')
27
+ expect(styles.boxShadow).toContain(',') // Multiple shadows separated by comma
28
+ })
29
+
30
+ test(`border with $variable resolves correctly`, async ({ page }) => {
31
+ const element = page.locator('#border-var')
32
+ const styles = await getStyles(element)
33
+
34
+ // border expands to individual props, check one of them
35
+ expect(styles.borderTopColor || styles.borderColor).toBeDefined()
36
+ expect(styles.borderTopWidth || styles.borderWidth).toBeDefined()
37
+ })
38
+
39
+ test(`boxShadow without variables passes through unchanged`, async ({ page }) => {
40
+ const element = page.locator('#boxshadow-plain')
41
+ const styles = await getStyles(element)
42
+
43
+ expect(styles.boxShadow).toBe('rgba(0, 0, 0, 0.2) 0px 0px 10px 0px')
44
+ })
@@ -0,0 +1,67 @@
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: 'SpinnerCustomColors', type: 'useCase' })
7
+ })
8
+
9
+ test('custom color tokens are applied to spinners', async ({ page }) => {
10
+ // Test custom red spinner - check the circle element's stroke
11
+ const redSpinnerStyle = page.locator('#spinner-custom-red circle').first()
12
+ const redSpinnerStroke = (await getStyles(redSpinnerStyle)).stroke
13
+ expect(redSpinnerStroke).toBe('rgb(255, 0, 0)')
14
+
15
+ // Test custom blue spinner
16
+ const blueSpinnerStyle = page.locator('#spinner-custom-blue circle').first()
17
+ const blueSpinnerStroke = (await getStyles(blueSpinnerStyle)).stroke
18
+ expect(blueSpinnerStroke).toBe('rgb(0, 0, 255)')
19
+
20
+ // Test custom green spinner
21
+ const greenSpinnerStyle = page.locator('#spinner-custom-green circle').first()
22
+ const greenSpinnerStroke = (await getStyles(greenSpinnerStyle)).stroke
23
+ expect(greenSpinnerStroke).toBe('rgb(0, 255, 0)')
24
+
25
+ // Test testsomethingdifferent custom color
26
+ const testDifferentStyle = page.locator('#spinner-test-different circle').first()
27
+ const testDifferentStroke = (await getStyles(testDifferentStyle)).stroke
28
+ expect(testDifferentStroke).toBe('rgb(255, 0, 0)') // testsomethingdifferent is also red (#ff0000)
29
+ })
30
+
31
+ test('custom color tokens are available in themes', async ({ page }) => {
32
+ // Verify that custom colors are used through CSS variables
33
+ const customColorVariables = await page.evaluate(() => {
34
+ // Check that the CSS variables exist and have correct values
35
+ const rootStyles = window.getComputedStyle(document.documentElement)
36
+ return {
37
+ customRed: rootStyles.getPropertyValue('--c-color-customRed').trim(),
38
+ customBlue: rootStyles.getPropertyValue('--c-color-customBlue').trim(),
39
+ customGreen: rootStyles.getPropertyValue('--c-color-customGreen').trim(),
40
+ }
41
+ })
42
+
43
+ // Verify CSS variables exist
44
+ expect(customColorVariables.customRed).toBe('#ff0000')
45
+ expect(customColorVariables.customBlue).toBe('#0000ff')
46
+ expect(customColorVariables.customGreen).toBe('#00ff00')
47
+ })
48
+
49
+ test('custom color tokens have correct CSS variables', async ({ page }) => {
50
+ // Check that CSS variables are created for custom colors
51
+ const cssVariables = await page.evaluate(() => {
52
+ const rootStyles = window.getComputedStyle(document.documentElement)
53
+ return {
54
+ customRed: rootStyles.getPropertyValue('--c-color-customRed').trim(),
55
+ customBlue: rootStyles.getPropertyValue('--c-color-customBlue').trim(),
56
+ customGreen: rootStyles.getPropertyValue('--c-color-customGreen').trim(),
57
+ testDifferent: rootStyles
58
+ .getPropertyValue('--c-color-testsomethingdifferent')
59
+ .trim(),
60
+ }
61
+ })
62
+
63
+ expect(cssVariables.customRed).toBe('#ff0000')
64
+ expect(cssVariables.customBlue).toBe('#0000ff')
65
+ expect(cssVariables.customGreen).toBe('#00ff00')
66
+ expect(cssVariables.testDifferent).toBe('#ff0000')
67
+ })
@@ -0,0 +1,51 @@
1
+ import { expect, test } from '@playwright/test'
2
+
3
+ import { setupPage } from './test-utils'
4
+
5
+ test.beforeEach(async ({ page }) => {
6
+ await setupPage(page, { name: 'StackZIndex', type: 'useCase' })
7
+ })
8
+
9
+ // find the portal wrapper's z-index by looking for the ancestor with
10
+ // position:fixed + inline z-index (portal wrappers use inline styles)
11
+ function makeGetZIndexOf(page: any) {
12
+ return async function getZIndexOf(selector: string) {
13
+ return await page.locator(selector).evaluate((el: Element) => {
14
+ let current: Element | null = el
15
+ while (current && current instanceof HTMLElement) {
16
+ if (current.style.position === 'fixed' && current.style.zIndex) {
17
+ return Number.parseInt(current.style.zIndex, 10)
18
+ }
19
+ current = current.parentElement
20
+ }
21
+ throw new Error(`no portal z-index found`)
22
+ })
23
+ }
24
+ }
25
+
26
+ test(`dialogs and portals stack their z-index automatically`, async ({ page }) => {
27
+ const getZIndexOf = makeGetZIndexOf(page)
28
+
29
+ const [a, b, c] = await Promise.all([
30
+ getZIndexOf('#bottom-popover'),
31
+ getZIndexOf('#middle-dialog'),
32
+ getZIndexOf('#top-popover'),
33
+ ])
34
+
35
+ expect(c).toBeGreaterThan(b)
36
+ expect(b).toBeGreaterThan(a)
37
+ })
38
+
39
+ test(`harcoded z-index overrides stacking z-index`, async ({ page }) => {
40
+ const getZIndexOf = makeGetZIndexOf(page)
41
+
42
+ const [a, b, c] = await Promise.all([
43
+ getZIndexOf('#hardcoded-popover'),
44
+ getZIndexOf('#hardcoded-dialog'),
45
+ getZIndexOf('#above-hardcoded-dialog'),
46
+ ])
47
+
48
+ expect(a).toBe(200_000)
49
+ expect(b).toBe(300_000)
50
+ expect(c).toBe(300_001)
51
+ })
@@ -0,0 +1,76 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+
4
+ /**
5
+ * Performance profiling test for the StressPage.
6
+ *
7
+ * Measures render time of a diverse page with ~200+ Hanzo GUI components.
8
+ * Captures both wall-clock render time (performance.mark/measure) and
9
+ * internal @hanzogui/timer breakdown (getSplitStyles, createComponent checkpoints).
10
+ *
11
+ * Run:
12
+ * npx playwright test tests/StressPagePerf.test.tsx --project=default
13
+ */
14
+
15
+ const RUNS = 10
16
+
17
+ test('StressPage render profiling', async ({ page }) => {
18
+ const times: number[] = []
19
+ let lastBreakdown: Record<string, number> | null = null
20
+
21
+ for (let i = 0; i < RUNS; i++) {
22
+ await setupPage(page, {
23
+ name: 'StressPage',
24
+ type: 'useCase',
25
+ searchParams: { profile: 'true' },
26
+ })
27
+
28
+ await page.waitForFunction(() => (window as any).__PERF_RESULT__, {
29
+ timeout: 10_000,
30
+ })
31
+
32
+ const result = await page.evaluate(() => (window as any).__PERF_RESULT__)
33
+ times.push(result.renderMs)
34
+ if (result.breakdown) {
35
+ lastBreakdown = result.breakdown
36
+ }
37
+ }
38
+
39
+ const sorted = [...times].sort((a, b) => a - b)
40
+ const median = sorted[Math.floor(sorted.length / 2)]
41
+ const mean = Math.round((times.reduce((a, b) => a + b, 0) / times.length) * 10) / 10
42
+ const min = sorted[0]
43
+ const max = sorted[sorted.length - 1]
44
+ const trimmed = sorted.slice(1, -1)
45
+ const trimmedMean =
46
+ Math.round((trimmed.reduce((a, b) => a + b, 0) / trimmed.length) * 10) / 10
47
+
48
+ console.log(`\n=== StressPage Render Profile (${RUNS} runs) ===`)
49
+ console.log(` All: ${times.map((t) => t.toFixed(1) + 'ms').join(', ')}`)
50
+ console.log(` Mean: ${mean}ms | Trimmed Mean: ${trimmedMean}ms | Median: ${median}ms`)
51
+ console.log(` Min: ${min}ms | Max: ${max}ms`)
52
+
53
+ if (lastBreakdown) {
54
+ console.log(`\n --- Internal Breakdown (last run) ---`)
55
+ let propTotal = 0
56
+ const entries = Object.entries(lastBreakdown).filter(([k]) => !k.endsWith('(ignore)'))
57
+ const phases: [string, number][] = []
58
+ for (const [label, totalMs] of entries) {
59
+ if (label.startsWith('before-prop-')) {
60
+ propTotal += totalMs
61
+ } else {
62
+ phases.push([label, totalMs])
63
+ }
64
+ }
65
+ phases.push(['before-prop-* (all props)', propTotal])
66
+ phases.sort((a, b) => b[1] - a[1])
67
+ for (const [label, totalMs] of phases) {
68
+ if (totalMs < 0.05) continue
69
+ console.log(` ${label.padStart(35)} | ${totalMs.toFixed(1)}ms`)
70
+ }
71
+ }
72
+
73
+ console.log(`================================================\n`)
74
+
75
+ expect(median).toBeGreaterThan(0)
76
+ })
@@ -0,0 +1,38 @@
1
+ import { expect, test } from '@playwright/test'
2
+ import { setupPage } from './test-utils'
3
+
4
+ test.beforeEach(async ({ page }) => {
5
+ await setupPage(page, { name: 'StylePlatform', type: 'useCase' })
6
+ })
7
+
8
+ test(`styles: $platform-web styles work`, async ({ page }) => {
9
+ const view = page.locator('#style-platform')
10
+
11
+ const styles = await view.evaluate((el) => {
12
+ return window.getComputedStyle(el)
13
+ })
14
+
15
+ expect(styles.marginTop).toBe(`10px`)
16
+ expect(styles.marginBottom).toBe(`10px`)
17
+ expect(styles.backgroundColor).toBe(`rgb(255, 0, 0)`)
18
+ expect(styles.overflowY).toBe(`scroll`)
19
+ })
20
+
21
+ test(`styles: $platform-web hoverStyle works`, async ({ page }) => {
22
+ const view = page.locator('#style-platform-hover')
23
+
24
+ // Before hover: should be blue (base backgroundColor)
25
+ const baseStyles = await view.evaluate((el) => {
26
+ return window.getComputedStyle(el).backgroundColor
27
+ })
28
+ expect(baseStyles).toBe(`rgb(0, 0, 255)`)
29
+
30
+ // Hover: should be green ($platform-web hoverStyle overrides base hoverStyle)
31
+ await view.hover()
32
+ await page.waitForTimeout(100)
33
+
34
+ const hoverStyles = await view.evaluate((el) => {
35
+ return window.getComputedStyle(el).backgroundColor
36
+ })
37
+ expect(hoverStyles).toBe(`rgb(0, 128, 0)`)
38
+ })
@@ -0,0 +1,20 @@
1
+ import { expect, test } from '@playwright/test'
2
+
3
+ import { setupPage } from './test-utils'
4
+ import { getStyles } from './utils'
5
+
6
+ test.beforeEach(async ({ page }) => {
7
+ await setupPage(page, { name: 'StyleProp', type: 'useCase' })
8
+ })
9
+
10
+ test(`style prop flattens`, async ({ page }) => {
11
+ expect((await getStyles(page.getByTestId('style-prop').first())).background).toBe(
12
+ `rgba(0, 0, 0, 0) radial-gradient(rgb(143, 143, 143), rgba(0, 0, 0, 0) 70%) repeat scroll 0% 0% / auto padding-box border-box`
13
+ )
14
+ })
15
+
16
+ test(`className prop flattens`, async ({ page }) => {
17
+ expect((await getStyles(page.getByTestId('class-name').first())).backgroundColor).toBe(
18
+ `rgb(255, 0, 0)`
19
+ )
20
+ })
@@ -0,0 +1,17 @@
1
+ import { expect, test } from '@playwright/test'
2
+
3
+ import { setupPage } from './test-utils'
4
+
5
+ test.beforeEach(async ({ page }) => {
6
+ await setupPage(page, { name: 'StyledAnchor', type: 'useCase' })
7
+ })
8
+
9
+ test(`styled anchor passes non-styled attributes through`, async ({ page }) => {
10
+ const anchor = page.getByTestId('test-anchor')
11
+ expect(await anchor.getAttribute('target')).toBe('_blank')
12
+ expect(await anchor.getAttribute('href')).toBe('https://gui.hanzo.ai/test-link')
13
+
14
+ const anchor2 = page.getByTestId('test-anchor2')
15
+ expect(await anchor2.getAttribute('target')).toBe('_blank')
16
+ expect(await anchor2.getAttribute('href')).toBe('https://gui.hanzo.ai/test-link')
17
+ })
@@ -0,0 +1,22 @@
1
+ import { expect, test } from '@playwright/test'
2
+
3
+ import { setupPage } from './test-utils'
4
+
5
+ test.beforeEach(async ({ page }) => {
6
+ await setupPage(page, { name: 'StyledButtonTheme', type: 'useCase' })
7
+ })
8
+
9
+ test(`button + styled + styleable + theme works`, async ({ page }) => {
10
+ const styles = await page.locator('#test').evaluate((el) => {
11
+ return window.getComputedStyle(el)
12
+ })
13
+
14
+ // Green theme background from themeDev (desaturated green)
15
+ expect(styles.backgroundColor).toBe(`rgb(219, 235, 224)`)
16
+
17
+ const styles2 = await page.locator('#test2').evaluate((el) => {
18
+ return window.getComputedStyle(el)
19
+ })
20
+
21
+ expect(styles2.backgroundColor).toBe(`rgb(0, 0, 0)`)
22
+ })
@@ -0,0 +1,20 @@
1
+ import { expect, test } from '@playwright/test'
2
+
3
+ import { setupPage } from './test-utils'
4
+ import { getHoverStyle, getPressStyle } from './utils'
5
+
6
+ test.beforeEach(async ({ page }) => {
7
+ await setupPage(page, { name: 'StyledButtonVariantPseudo', type: 'useCase' })
8
+ })
9
+
10
+ test(`hover HOC + variant + pseudos work`, async ({ page }) => {
11
+ const button = page.locator('button#test')
12
+ const hoverStyles = await getHoverStyle(button)
13
+ expect(hoverStyles.backgroundColor).toBe(`rgb(0, 128, 0)`)
14
+ })
15
+
16
+ test(`press HOC + variant + pseudos work`, async ({ page }) => {
17
+ const button = page.locator('button')
18
+ const pressStyles = await getPressStyle(button, { delay: 3000 })
19
+ expect(pressStyles.backgroundColor).toBe(`rgb(255, 0, 0)`)
20
+ })
@@ -0,0 +1,33 @@
1
+ import { expect, test } from '@playwright/test'
2
+
3
+ import { setupPage } from './test-utils'
4
+ import { getPressStyle } from './utils'
5
+
6
+ // These tests only run with CSS driver
7
+ test.beforeEach(async ({ page }, testInfo) => {
8
+ const driver = (testInfo.project?.metadata as any)?.animationDriver
9
+ test.skip(driver !== 'css', `skipping for ${driver} driver`)
10
+
11
+ await setupPage(page, { name: 'StyledButtonVariantPseudoMerge', type: 'useCase' })
12
+ })
13
+
14
+ test(`pseudo + variant with pseudo should merge`, async ({ page }) => {
15
+ const button = page.locator('button#test')
16
+ const pressStyles = await getPressStyle(button, { delay: 3000 })
17
+ expect(pressStyles.backgroundColor).toBe(`rgb(255, 0, 0)`)
18
+ expect(pressStyles.transform).toBe(`matrix(0.5, 0, 0, 0.5, 0, 0)`)
19
+ })
20
+
21
+ test(`animation + pseudo + variant with pseudo should merge`, async ({ page }) => {
22
+ const button = page.locator('#animated')
23
+ const pressStyles = await getPressStyle(button, { delay: 3000 })
24
+ expect(pressStyles.backgroundColor).toBe(`rgb(255, 0, 0)`)
25
+ expect(pressStyles.transform).toBe(`matrix(0.5, 0, 0, 0.5, 0, 0)`)
26
+ })
27
+
28
+ test(`styled without variants HOC of HOC + pseudo`, async ({ page }) => {
29
+ const button = page.locator('#double-styled')
30
+ const pressStyles = await getPressStyle(button, { delay: 3000 })
31
+ expect(pressStyles.backgroundColor).toBe(`rgb(255, 0, 0)`)
32
+ expect(pressStyles.transform).toBe(`matrix(0.5, 0, 0, 0.5, 0, 0)`)
33
+ })
@@ -0,0 +1,16 @@
1
+ import { expect, test } from '@playwright/test'
2
+
3
+ import { setupPage } from './test-utils'
4
+
5
+ test.beforeEach(async ({ page }) => {
6
+ await setupPage(page, { name: 'StyledCheckboxTheme', type: 'useCase' })
7
+ })
8
+
9
+ test(`theme passes through .styleable HOC`, async ({ page }) => {
10
+ const styles = await page.locator('button[role=checkbox]').evaluate((el) => {
11
+ return window.getComputedStyle(el)
12
+ })
13
+
14
+ // Green theme background from themeDev
15
+ expect(styles.backgroundColor).toBe(`rgb(232, 242, 235)`)
16
+ })