@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.
- package/.detoxrc.js +130 -0
- package/.env.production +2 -0
- package/.maestro/config.yaml +4 -0
- package/.maestro/flows/shorthand-variables.yaml +23 -0
- package/.watchmanconfig +1 -0
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/app.json +43 -0
- package/assets/adaptive-icon.png +0 -0
- package/assets/favicon.png +0 -0
- package/assets/icon.png +0 -0
- package/assets/splash.png +0 -0
- package/babel.config.js +25 -0
- package/e2e/CompilerExtraction.test.ts +147 -0
- package/e2e/GroupPressNative.test.ts +167 -0
- package/e2e/MediaQueryGtMd.test.ts +71 -0
- package/e2e/NativePortal.test.ts +113 -0
- package/e2e/PointerEvents.test.ts +116 -0
- package/e2e/PressStyleNative.noRngh.test.ts +191 -0
- package/e2e/PressStyleNative.test.ts +231 -0
- package/e2e/SafeArea.test.ts +57 -0
- package/e2e/SelectAndroidOnPress.test.ts +181 -0
- package/e2e/SelectRemount.test.ts +137 -0
- package/e2e/SheetDragResist.test.ts +370 -0
- package/e2e/SheetKeyboardDrag.test.ts +249 -0
- package/e2e/SheetScrollableDrag.test.ts +560 -0
- package/e2e/ShorthandVariables.test.ts +53 -0
- package/e2e/ThemeChangeBasic.test.ts +123 -0
- package/e2e/ThemeMutation.test.ts +80 -0
- package/e2e/check-rngh-status.test.ts +31 -0
- package/e2e/jest.config.js +19 -0
- package/e2e/utils/colors.ts +75 -0
- package/e2e/utils/navigation.ts +53 -0
- package/eas.json +22 -0
- package/flows/AlertDialog.yaml +17 -0
- package/flows/OpenApp.yaml +25 -0
- package/flows/Select.yaml +13 -0
- package/flows/Sheet.yaml +12 -0
- package/flows/Tabs.yaml +13 -0
- package/flows/Toast.yaml +14 -0
- package/flows/WarmUp.yaml +24 -0
- package/index.html +21 -0
- package/index.js +17 -0
- package/metro.config.js +64 -0
- package/next-router-shim.ts +9 -0
- package/package.json +118 -0
- package/plans/toast-2.md +471 -0
- package/playwright.config.ts +71 -0
- package/plugins/expo-modules-core-swift6.js +76 -0
- package/pod-install.sh +7 -0
- package/public/favicon.svg +70 -0
- package/public/fonts/inter.css +15 -0
- package/public/fonts/noto-cn.otf +0 -0
- package/public/gui-icon.svg +68 -0
- package/run-detox.sh +230 -0
- package/run-native-tests.sh +4 -0
- package/run-tests-parallel.ts +195 -0
- package/screenshots/Screenshotter.test.tsx +48 -0
- package/src/AnimationDemos.tsx +131 -0
- package/src/App.native.tsx +121 -0
- package/src/App.tsx +121 -0
- package/src/Navigation.tsx +98 -0
- package/src/Sandbox.tsx +87 -0
- package/src/TestDynamicEval.tsx +33 -0
- package/src/TestNativeSheet.tsx +100 -0
- package/src/components/TimedRender.tsx +18 -0
- package/src/constants/test-ids.ts +52 -0
- package/src/features/demos/demo-screen.tsx +72 -0
- package/src/features/home/ColorSchemeListItem.tsx +41 -0
- package/src/features/home/TestBuildAButton.tsx +102 -0
- package/src/features/home/TestSeparator.tsx +0 -0
- package/src/features/home/screen.tsx +285 -0
- package/src/features/testcases/screen.tsx +59 -0
- package/src/features/testcases/test-screen.tsx +50 -0
- package/src/generatedV5Theme.ts +112 -0
- package/src/gui.config.ts +411 -0
- package/src/guy.png +0 -0
- package/src/index.tsx +6 -0
- package/src/provider/index.tsx +18 -0
- package/src/test-gui-stack.tsx +11 -0
- package/src/test.tsx +3 -0
- package/src/useKitchenSinkTheme.tsx +15 -0
- package/src/usecases/ActionsSheetComparison.tsx +194 -0
- package/src/usecases/AnimatePresenceEnterExitCase.tsx +255 -0
- package/src/usecases/AnimatePresenceExitTest.tsx +69 -0
- package/src/usecases/AnimatedByProp.tsx +39 -0
- package/src/usecases/AnimationComprehensiveCase.tsx +2515 -0
- package/src/usecases/AnimationValueLoggingCase.tsx +526 -0
- package/src/usecases/AnimationsWithMediaQueriesCase.tsx +110 -0
- package/src/usecases/Benchmark.tsx +148 -0
- package/src/usecases/BenchmarkSelect.tsx +34 -0
- package/src/usecases/ButtonCircular.tsx +3 -0
- package/src/usecases/ButtonCustom.tsx +33 -0
- package/src/usecases/ButtonIconColor.tsx +18 -0
- package/src/usecases/ButtonInverse.tsx +30 -0
- package/src/usecases/ButtonUnstyled.tsx +31 -0
- package/src/usecases/CheckboxDisabledOnPress.tsx +62 -0
- package/src/usecases/ClickDuringEnterCase.tsx +59 -0
- package/src/usecases/CodeExamplesInput.tsx +9 -0
- package/src/usecases/ColorTokenFallback.tsx +52 -0
- package/src/usecases/CompilerExtraction.tsx +380 -0
- package/src/usecases/ComplexVariants.tsx +164 -0
- package/src/usecases/CrashAdaptSheet.tsx +98 -0
- package/src/usecases/CustomStyledAnimatedPopover.tsx +42 -0
- package/src/usecases/CustomStyledAnimatedTooltip.tsx +72 -0
- package/src/usecases/DOMNodeAPIs.tsx +154 -0
- package/src/usecases/DialogFocusScopeCase.tsx +277 -0
- package/src/usecases/DialogFocusScopeDebug.tsx +85 -0
- package/src/usecases/DialogNestedCase.tsx +121 -0
- package/src/usecases/DialogOpenControlled.tsx +49 -0
- package/src/usecases/DialogPointerEventsCase.tsx +58 -0
- package/src/usecases/DialogScopedCase.tsx +106 -0
- package/src/usecases/DialogSheetAdaptCase.tsx +178 -0
- package/src/usecases/DialogSheetAdaptResizeCase.tsx +98 -0
- package/src/usecases/DismissLayerStackingCase.tsx +223 -0
- package/src/usecases/DriverDisableAnimationPropsCase.tsx +44 -0
- package/src/usecases/Example.tsx +10 -0
- package/src/usecases/ExitCompletionCase.tsx +713 -0
- package/src/usecases/FocusVisibleButton.tsx +14 -0
- package/src/usecases/FocusVisibleButtonPointer.tsx +13 -0
- package/src/usecases/FocusVisibleButtonWithFocusStyle.tsx +16 -0
- package/src/usecases/FocusWithinCase.tsx +55 -0
- package/src/usecases/FontTokensInVariants.tsx +14 -0
- package/src/usecases/FormButtonTypeCase.tsx +34 -0
- package/src/usecases/GlobalScopedTriggerIsolationCase.tsx +178 -0
- package/src/usecases/GroupHoverMobile.tsx +39 -0
- package/src/usecases/GroupPressInVariant.tsx +92 -0
- package/src/usecases/GroupPressNative.tsx +200 -0
- package/src/usecases/GroupProp.tsx +96 -0
- package/src/usecases/GroupPseudoVariantOverride.tsx +56 -0
- package/src/usecases/GroupUseCases.tsx +94 -0
- package/src/usecases/HeightMediaQueryOverrideCase.tsx +183 -0
- package/src/usecases/InputAutoFocusAfterMenuCase.tsx +105 -0
- package/src/usecases/InputAutoFocusStyledCase.tsx +39 -0
- package/src/usecases/KeyboardControllerTest.tsx +146 -0
- package/src/usecases/ListItem.tsx +123 -0
- package/src/usecases/MediaQueriesV5.tsx +137 -0
- package/src/usecases/MediaQueryGtMd.tsx +73 -0
- package/src/usecases/MenuAboveDialogCase.tsx +75 -0
- package/src/usecases/MenuAccessibilityCase.tsx +133 -0
- package/src/usecases/MenuAnimatePositionCase.tsx +41 -0
- package/src/usecases/MenuArrowAnimatePresenceCase.tsx +98 -0
- package/src/usecases/MenuAsChildPositionCase.tsx +24 -0
- package/src/usecases/MenuAutoResizeCase.tsx +57 -0
- package/src/usecases/MenuBottomCase.tsx +55 -0
- package/src/usecases/MenuFocusLeaveCase.tsx +135 -0
- package/src/usecases/MenuHighlightCase.tsx +44 -0
- package/src/usecases/MenuItemFocusCase.tsx +79 -0
- package/src/usecases/MenuItemPseudoOverrideCase.tsx +270 -0
- package/src/usecases/MenuMultiTriggerCase.tsx +47 -0
- package/src/usecases/MenuOverflowCase.tsx +60 -0
- package/src/usecases/MenuSubCase.tsx +223 -0
- package/src/usecases/MenuSubLeftCase.tsx +178 -0
- package/src/usecases/MenuSubNestedPositionCase.tsx +171 -0
- package/src/usecases/MenuSubStyledCase.tsx +145 -0
- package/src/usecases/MenuThemeCase.tsx +50 -0
- package/src/usecases/MenuUnstyledCase.tsx +52 -0
- package/src/usecases/MultiDriverAnimation.tsx +118 -0
- package/src/usecases/NativePortalTest.tsx +179 -0
- package/src/usecases/NewInputBasic.tsx +16 -0
- package/src/usecases/NewInputEvents.tsx +29 -0
- package/src/usecases/NonGuiTextStyledType.tsx +23 -0
- package/src/usecases/OnLayoutCase.tsx +134 -0
- package/src/usecases/OnLayoutScaleCase.tsx +88 -0
- package/src/usecases/OnLayoutStressCase.tsx +353 -0
- package/src/usecases/OpacityModifierCase.tsx +113 -0
- package/src/usecases/OverlayStyled.tsx +66 -0
- package/src/usecases/ParagraphSpanFontInheritance.tsx +53 -0
- package/src/usecases/PlaceholderTextColor.tsx +20 -0
- package/src/usecases/PointerEventsCase.tsx +100 -0
- package/src/usecases/PopoverAndMenuMultiTriggerCase.tsx +138 -0
- package/src/usecases/PopoverCase.tsx +222 -0
- package/src/usecases/PopoverContentStyledPlusAnimations.tsx +44 -0
- package/src/usecases/PopoverFocusScopeCase.tsx +171 -0
- package/src/usecases/PopoverHoverableCase.tsx +167 -0
- package/src/usecases/PopoverHoverableDisableClickCase.tsx +118 -0
- package/src/usecases/PopoverHoverableRapidCase.tsx +103 -0
- package/src/usecases/PopoverHoverableScopedCase.tsx +135 -0
- package/src/usecases/PopoverScopedCase.tsx +76 -0
- package/src/usecases/PopoverTriggerIsolationCase.tsx +80 -0
- package/src/usecases/PressStyleNative.tsx +143 -0
- package/src/usecases/PseudoStyleMerge.tsx +25 -0
- package/src/usecases/PseudoTransitionCase.tsx +174 -0
- package/src/usecases/RawAnimatedValueCase.tsx +231 -0
- package/src/usecases/RemoveScrollCase.tsx +66 -0
- package/src/usecases/RenderPropCase.tsx +263 -0
- package/src/usecases/SafeAreaCase.tsx +236 -0
- package/src/usecases/ScrollViewRefCase.tsx +88 -0
- package/src/usecases/SecondPage.tsx +5 -0
- package/src/usecases/SelectAndroidOnPress.tsx +129 -0
- package/src/usecases/SelectFocusScopeCase.tsx +270 -0
- package/src/usecases/SelectRemount.tsx +136 -0
- package/src/usecases/Shadows.tsx +5 -0
- package/src/usecases/SheetAnimationCase.tsx +155 -0
- package/src/usecases/SheetDragCase.tsx +183 -0
- package/src/usecases/SheetDragResistCase.tsx +433 -0
- package/src/usecases/SheetDragResistCase.web.tsx +359 -0
- package/src/usecases/SheetKeyboardDragCase.tsx +328 -0
- package/src/usecases/SheetKeyboardFitContentCase.tsx +165 -0
- package/src/usecases/SheetOnAnimationCompleteCase.tsx +54 -0
- package/src/usecases/SheetScrollLockCase.tsx +166 -0
- package/src/usecases/SheetScrollableDrag.tsx +249 -0
- package/src/usecases/SheetSnapPointsFitCase.tsx +393 -0
- package/src/usecases/ShorthandVariables.tsx +49 -0
- package/src/usecases/SlowThemeReRender.tsx +48 -0
- package/src/usecases/SpinnerCustomColors.tsx +34 -0
- package/src/usecases/StackZIndex.tsx +82 -0
- package/src/usecases/StressPage.tsx +301 -0
- package/src/usecases/StylePlatform.tsx +30 -0
- package/src/usecases/StyleProp.tsx +29 -0
- package/src/usecases/StyledAnchor.tsx +27 -0
- package/src/usecases/StyledButtonAnimationAuto.tsx +99 -0
- package/src/usecases/StyledButtonTheme.tsx +63 -0
- package/src/usecases/StyledButtonVariantPseudo.tsx +25 -0
- package/src/usecases/StyledButtonVariantPseudoMerge.tsx +77 -0
- package/src/usecases/StyledCheckboxTheme.tsx +23 -0
- package/src/usecases/StyledContextColor.tsx +246 -0
- package/src/usecases/StyledContextTokens.tsx +147 -0
- package/src/usecases/StyledHOCNamed.tsx +20 -0
- package/src/usecases/StyledHtmlCase.tsx +144 -0
- package/src/usecases/StyledIconColor.tsx +19 -0
- package/src/usecases/StyledInputFocusStyle.tsx +21 -0
- package/src/usecases/StyledInputOnFocus.tsx +30 -0
- package/src/usecases/StyledMediaQueryMerge.tsx +95 -0
- package/src/usecases/StyledOverridePsuedo.tsx +26 -0
- package/src/usecases/StyledRNW.tsx +61 -0
- package/src/usecases/StyledStyleableInputOnFocus.tsx +34 -0
- package/src/usecases/StyledStyleableInputVariant.tsx +48 -0
- package/src/usecases/StyledStyledStyleableInputOnFocus.tsx +36 -0
- package/src/usecases/StyledVariantTextColor.tsx +25 -0
- package/src/usecases/StyledViewOnFocus.tsx +32 -0
- package/src/usecases/TabHoverAnimationCase.tsx +212 -0
- package/src/usecases/TextNestedInheritance.tsx +80 -0
- package/src/usecases/ThemeChange.tsx +100 -0
- package/src/usecases/ThemeChangeBasic.tsx +52 -0
- package/src/usecases/ThemeComponentResolution.tsx +119 -0
- package/src/usecases/ThemeConditionalName.tsx +31 -0
- package/src/usecases/ThemeMediaAnimationCase.tsx +39 -0
- package/src/usecases/ThemeMutation.tsx +86 -0
- package/src/usecases/ThemeNested.tsx +103 -0
- package/src/usecases/ThemeReset.tsx +62 -0
- package/src/usecases/ThemeShallowCase.tsx +83 -0
- package/src/usecases/ToastCase.tsx +46 -0
- package/src/usecases/ToggleGroupActiveProps.tsx +40 -0
- package/src/usecases/ToggleGroupXGroupCase.tsx +104 -0
- package/src/usecases/TooltipAnimationCase.tsx +99 -0
- package/src/usecases/TooltipCase.tsx +32 -0
- package/src/usecases/TooltipGlobalPatternCase.tsx +83 -0
- package/src/usecases/TooltipGroupCase.tsx +102 -0
- package/src/usecases/TooltipMultiTriggerCase.tsx +88 -0
- package/src/usecases/TooltipPositionJumpCase.tsx +91 -0
- package/src/usecases/TooltipTriggerInlineCase.tsx +60 -0
- package/src/usecases/TransformMediaQueryMerge.tsx +98 -0
- package/src/usecases/UseCases.tsx +409 -0
- package/src/usecases/UseTheme.tsx +41 -0
- package/src/usecases/V5ThemeBuilderOutput.tsx +231 -0
- package/src/usecases/VariantFontFamily.tsx +25 -0
- package/src/usecases/VariantsOrder.tsx +117 -0
- package/src/usecases/ZIndex.tsx +155 -0
- package/src/usecases/helpers.tsx +44 -0
- package/src/usecases/index.native.ts +122 -0
- package/src/usecases/index.ts +3 -0
- package/src/usecases/index.web.ts +177 -0
- package/tests/AnimatePresenceEnterExit.animated.test.tsx +176 -0
- package/tests/AnimatedByProp.animated.test.tsx +138 -0
- package/tests/AnimationBehavior.animated.test.tsx +543 -0
- package/tests/AnimationTiming.animated.test.tsx +195 -0
- package/tests/AnimationsWithMediaQueries.animated.test.tsx +154 -0
- package/tests/BuildAButton.test.tsx +87 -0
- package/tests/ButtonCircular.test.tsx +17 -0
- package/tests/ButtonCustom.test.tsx +17 -0
- package/tests/ButtonIconColor.test.tsx +23 -0
- package/tests/ButtonUnstyled.test.tsx +56 -0
- package/tests/ClickDuringEnter.animated.test.tsx +174 -0
- package/tests/ColorTokenFallback.test.tsx +45 -0
- package/tests/DOMNodeAPIs.test.tsx +161 -0
- package/tests/DialogFocusScope.animated.test.tsx +309 -0
- package/tests/DialogNested.test.tsx +128 -0
- package/tests/DialogOpenControlled.test.tsx +42 -0
- package/tests/DialogPointerEvents.animated.test.tsx +108 -0
- package/tests/DialogScoped.test.tsx +137 -0
- package/tests/DialogSheetAdapt.test.tsx +68 -0
- package/tests/DialogSheetAdaptResize.test.tsx +161 -0
- package/tests/DismissLayerStacking.test.tsx +292 -0
- package/tests/DriverDisableAnimationProps.animated.test.tsx +157 -0
- package/tests/ExitCompletion.animated.test.tsx +425 -0
- package/tests/ExitTimingCheck.animated.test.ts +34 -0
- package/tests/FocusVisibleButton.test.tsx +41 -0
- package/tests/FocusVisibleButtonPointerFocus.test.tsx +23 -0
- package/tests/FocusVisibleButtonPointerFocusWithFocusStyle.test.tsx +40 -0
- package/tests/FocusWithinStyle.animated.test.tsx +66 -0
- package/tests/FocusWithinStyle.test.tsx +60 -0
- package/tests/FormButtonType.test.tsx +42 -0
- package/tests/GlobalScopedTriggerIsolation.test.tsx +89 -0
- package/tests/GroupHoverMobile.test.tsx +52 -0
- package/tests/GroupPressInVariant.test.tsx +82 -0
- package/tests/GroupProp.test.tsx +30 -0
- package/tests/GroupPseudoVariantOverride.test.tsx +57 -0
- package/tests/GroupUseCases.test.tsx +111 -0
- package/tests/GuiSiteMotion.test.ts +481 -0
- package/tests/HeightMediaQueryOverride.test.tsx +112 -0
- package/tests/InputAutoFocusAfterMenu.test.tsx +55 -0
- package/tests/InputAutoFocusStyled.test.tsx +22 -0
- package/tests/ListItem.test.tsx +129 -0
- package/tests/MediaQueriesV5.test.tsx +113 -0
- package/tests/MediaQueryGtMd.test.tsx +84 -0
- package/tests/MenuAboveDialog.test.tsx +108 -0
- package/tests/MenuAccessibility.test.tsx +346 -0
- package/tests/MenuAnimatePosition.animated.test.tsx +57 -0
- package/tests/MenuArrowAnimatePresence.animated.test.tsx +71 -0
- package/tests/MenuAsChildPosition.test.tsx +16 -0
- package/tests/MenuAutoResize.test.tsx +54 -0
- package/tests/MenuFocusLeave.test.tsx +181 -0
- package/tests/MenuHighlight.test.tsx +165 -0
- package/tests/MenuHoverKeyboardBugs.test.tsx +252 -0
- package/tests/MenuItemFocus.test.tsx +59 -0
- package/tests/MenuItemPseudoOverride.test.tsx +231 -0
- package/tests/MenuMultiTrigger.test.tsx +101 -0
- package/tests/MenuOverflow.test.tsx +93 -0
- package/tests/MenuStayInFrame.test.tsx +102 -0
- package/tests/MenuSubKeyboardFocus.test.tsx +220 -0
- package/tests/MenuSubLeftSafePolygon.test.tsx +88 -0
- package/tests/MenuSubNestedPosition.test.tsx +48 -0
- package/tests/MenuSubSafePolygon.test.tsx +97 -0
- package/tests/MenuSubStyled.test.tsx +40 -0
- package/tests/MenuTheme.test.tsx +34 -0
- package/tests/MenuUnstyled.test.tsx +56 -0
- package/tests/MultiDriverAnimation.test.tsx +207 -0
- package/tests/NewInputBasic.test.tsx +50 -0
- package/tests/NewInputEvents.test.tsx +55 -0
- package/tests/OnLayout.test.tsx +163 -0
- package/tests/OnLayoutScale.test.tsx +100 -0
- package/tests/OnLayoutStress.test.tsx +304 -0
- package/tests/ParagraphSpanFontInheritance.test.tsx +73 -0
- package/tests/PointerEvents.test.tsx +123 -0
- package/tests/Popover.animated.test.tsx +234 -0
- package/tests/PopoverAndMenuMultiTrigger.test.tsx +184 -0
- package/tests/PopoverAnimatePosition.animated.test.tsx +51 -0
- package/tests/PopoverClickDuringEnter.animated.test.tsx +197 -0
- package/tests/PopoverFocusScope.test.tsx +242 -0
- package/tests/PopoverHoverable.test.tsx +383 -0
- package/tests/PopoverHoverableDisableClick.test.tsx +106 -0
- package/tests/PopoverHoverableRapid.test.tsx +129 -0
- package/tests/PopoverHoverableReposition.test.tsx +111 -0
- package/tests/PopoverHoverableScoped.animated.test.tsx +103 -0
- package/tests/PopoverHoverableStress.test.tsx +169 -0
- package/tests/PopoverInitialPosition.animated.test.tsx +82 -0
- package/tests/PopoverMiddlewareSkipRegression.animated.test.tsx +221 -0
- package/tests/PopoverScoped.test.tsx +128 -0
- package/tests/PopoverScopedPositionGlitch.animated.test.tsx +184 -0
- package/tests/PopoverTriggerIsolation.test.tsx +62 -0
- package/tests/PseudoTransition.animated.test.tsx +319 -0
- package/tests/RawAnimatedValue.test.tsx +147 -0
- package/tests/RemoveScroll.test.tsx +223 -0
- package/tests/RenderProp.test.tsx +293 -0
- package/tests/ScrollViewRef.test.tsx +39 -0
- package/tests/SelectClickHold.test.tsx +147 -0
- package/tests/SelectFocusScope.test.tsx +176 -0
- package/tests/SelectInnerPositioning.test.tsx +82 -0
- package/tests/SelectKeyboardNav.test.tsx +173 -0
- package/tests/SelectPositioning.test.tsx +56 -0
- package/tests/SelectTypeahead.test.tsx +63 -0
- package/tests/Shadows.test.tsx +14 -0
- package/tests/SheetAnimation.animated.test.tsx +413 -0
- package/tests/SheetDrag.animated.test.tsx +223 -0
- package/tests/SheetDragResist.animated.test.tsx +393 -0
- package/tests/SheetOnAnimationComplete.animated.test.tsx +62 -0
- package/tests/SheetScrollLock.animated.test.tsx +287 -0
- package/tests/SheetScrollableDrag.animated.test.tsx +1264 -0
- package/tests/SheetSnapPointsFit.animated.test.tsx +259 -0
- package/tests/ShorthandVariables.test.tsx +44 -0
- package/tests/SpinnerCustomColors.test.tsx +67 -0
- package/tests/StackZIndex.test.tsx +51 -0
- package/tests/StressPagePerf.test.tsx +76 -0
- package/tests/StylePlatform.test.tsx +38 -0
- package/tests/StyleProp.test.tsx +20 -0
- package/tests/StyledAnchor.test.tsx +17 -0
- package/tests/StyledButtonTheme.test.tsx +22 -0
- package/tests/StyledButtonVariantPseudo.test.tsx +20 -0
- package/tests/StyledButtonVariantPseudoMerge.animated.test.tsx +33 -0
- package/tests/StyledCheckboxTheme.test.tsx +16 -0
- package/tests/StyledContextColor.test.tsx +119 -0
- package/tests/StyledContextTokens.test.tsx +56 -0
- package/tests/StyledHOCNamed.test.tsx +16 -0
- package/tests/StyledHtml.test.tsx +161 -0
- package/tests/StyledIconColor.test.tsx +32 -0
- package/tests/StyledInputFocusStyle.test.tsx +19 -0
- package/tests/StyledInputOnFocus.test.tsx +27 -0
- package/tests/StyledMediaQueryMerge.test.tsx +66 -0
- package/tests/StyledRNW.test.tsx +17 -0
- package/tests/StyledStyleableInputOnFocus.test.tsx +27 -0
- package/tests/StyledStyleableInputVariant.test.tsx +22 -0
- package/tests/StyledStyledStyleableInputOnFocus.test.tsx +27 -0
- package/tests/StyledVariantTextColor.test.tsx +24 -0
- package/tests/StyledViewOnFocus.test.tsx +27 -0
- package/tests/TabHoverAnimation.animated.test.tsx +468 -0
- package/tests/TabHoverPositionSmooth.animated.test.tsx +129 -0
- package/tests/TextNestedInheritance.test.tsx +93 -0
- package/tests/ThemeChange.test.tsx +70 -0
- package/tests/ThemeComponentResolution.test.tsx +82 -0
- package/tests/ThemeConditionalName.test.tsx +34 -0
- package/tests/ThemeMediaAnimation.test.tsx +65 -0
- package/tests/ThemeNested.test.tsx +141 -0
- package/tests/ThemeReset.test.tsx +63 -0
- package/tests/ThemeShallow.test.tsx +95 -0
- package/tests/Toast.test.tsx +106 -0
- package/tests/ToggleGroup.test.tsx +61 -0
- package/tests/ToggleGroupActiveProps.test.tsx +38 -0
- package/tests/ToggleGroupXGroup.test.tsx +172 -0
- package/tests/TooltipAnimation.animated.test.tsx +260 -0
- package/tests/TooltipEnterInterrupt.animated.test.tsx +76 -0
- package/tests/TooltipGlobalPattern.animated.test.tsx +208 -0
- package/tests/TooltipGroup.animated.test.tsx +79 -0
- package/tests/TooltipMultiTrigger.test.tsx +116 -0
- package/tests/TooltipPositionJump.animated.test.tsx +229 -0
- package/tests/TooltipPositionJumpNotes.md +219 -0
- package/tests/TooltipRapidSwitch.animated.test.tsx +399 -0
- package/tests/TooltipTriggerInline.test.tsx +65 -0
- package/tests/TransformMediaQueryMerge.test.tsx +104 -0
- package/tests/TransitionEnterExit.animated.test.tsx +311 -0
- package/tests/UseTheme.test.tsx +16 -0
- package/tests/V5ThemeBuilderOutput.test.tsx +164 -0
- package/tests/VariantFontFamily.test.tsx +11 -0
- package/tests/VariantsOrder.test.tsx +53 -0
- package/tests/_debug_position.mjs +52 -0
- package/tests/test-utils.ts +106 -0
- package/tests/utils.tsx +54 -0
- package/tsconfig.json +45 -0
- package/vite-env.d.ts +1 -0
- package/vite.config.ts +14 -0
- package/webpack.config.js +139 -0
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tests for multi-driver animation config: { default: motion, css: cssDriver }
|
|
5
|
+
*
|
|
6
|
+
* This test ONLY runs with ?animationDriver=multi which sets up:
|
|
7
|
+
* animations: { default: animationsMotion, css: animationsCSS }
|
|
8
|
+
*
|
|
9
|
+
* Verifies:
|
|
10
|
+
* 1. animatedBy="default" uses motion driver (JS-based animation)
|
|
11
|
+
* 2. animatedBy="css" uses CSS driver (CSS transitions)
|
|
12
|
+
* 3. no animatedBy defaults to motion driver
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
test.describe('Multi-driver animation config', () => {
|
|
16
|
+
test.beforeEach(async ({ page }) => {
|
|
17
|
+
// specifically load with multi-driver config
|
|
18
|
+
await page.goto('/?test=MultiDriverAnimation&animationDriver=multi')
|
|
19
|
+
await page.waitForLoadState('networkidle')
|
|
20
|
+
await page.waitForTimeout(300)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('animatedBy="default" uses motion driver (animates smoothly)', async ({
|
|
24
|
+
page,
|
|
25
|
+
}) => {
|
|
26
|
+
const element = page.getByTestId('driver-default')
|
|
27
|
+
|
|
28
|
+
const initialOpacity = await element.evaluate((el) =>
|
|
29
|
+
Number(getComputedStyle(el).opacity)
|
|
30
|
+
)
|
|
31
|
+
expect(initialOpacity).toBeCloseTo(0.3, 1)
|
|
32
|
+
|
|
33
|
+
// use in-browser rAF polling to reliably capture mid-animation frames
|
|
34
|
+
// (Playwright waitForTimeout is too slow on CI to catch intermediate values)
|
|
35
|
+
const samples: number[] = await page.evaluate(() => {
|
|
36
|
+
return new Promise<number[]>((resolve) => {
|
|
37
|
+
const el = document.querySelector('[data-testid="driver-default"]')!
|
|
38
|
+
const vals: number[] = []
|
|
39
|
+
const start = performance.now()
|
|
40
|
+
function tick() {
|
|
41
|
+
vals.push(Number(getComputedStyle(el).opacity))
|
|
42
|
+
if (performance.now() - start < 500) requestAnimationFrame(tick)
|
|
43
|
+
else resolve(vals)
|
|
44
|
+
}
|
|
45
|
+
;(document.querySelector('[data-testid="toggle-multi"]') as HTMLElement).click()
|
|
46
|
+
requestAnimationFrame(tick)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const finalOpacity = samples[samples.length - 1]
|
|
51
|
+
expect(finalOpacity).toBeGreaterThan(0.9)
|
|
52
|
+
|
|
53
|
+
// motion driver should show intermediate values (not jump instantly)
|
|
54
|
+
const intermediates = samples.filter((v) => v > 0.35 && v < 0.95)
|
|
55
|
+
expect(
|
|
56
|
+
intermediates.length,
|
|
57
|
+
`Motion driver should animate with interpolation (got ${intermediates.length} intermediate frames). ` +
|
|
58
|
+
`Samples: [${samples
|
|
59
|
+
.slice(0, 8)
|
|
60
|
+
.map((s) => s.toFixed(2))
|
|
61
|
+
.join(', ')}...]`
|
|
62
|
+
).toBeGreaterThanOrEqual(2)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('animatedBy="css" uses CSS driver (CSS transitions)', async ({ page }) => {
|
|
66
|
+
const element = page.getByTestId('driver-css')
|
|
67
|
+
|
|
68
|
+
const initialOpacity = await element.evaluate((el) =>
|
|
69
|
+
Number(getComputedStyle(el).opacity)
|
|
70
|
+
)
|
|
71
|
+
expect(initialOpacity).toBeCloseTo(0.3, 1)
|
|
72
|
+
|
|
73
|
+
// trigger animation
|
|
74
|
+
await page.getByTestId('toggle-multi').click()
|
|
75
|
+
|
|
76
|
+
// css driver uses CSS transitions - 200ms
|
|
77
|
+
await page.waitForTimeout(350)
|
|
78
|
+
const finalOpacity = await element.evaluate((el) =>
|
|
79
|
+
Number(getComputedStyle(el).opacity)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
expect(finalOpacity).toBeGreaterThan(0.9)
|
|
83
|
+
|
|
84
|
+
// verify it's using CSS transition
|
|
85
|
+
const transition = await element.evaluate((el) => getComputedStyle(el).transition)
|
|
86
|
+
expect(transition.length).toBeGreaterThan(0)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
test('no animatedBy defaults to motion driver', async ({ page }) => {
|
|
90
|
+
const initialOpacity = await page
|
|
91
|
+
.getByTestId('driver-none')
|
|
92
|
+
.evaluate((el) => Number(getComputedStyle(el).opacity))
|
|
93
|
+
expect(initialOpacity).toBeCloseTo(0.3, 1)
|
|
94
|
+
|
|
95
|
+
// poll via rAF to capture intermediate values reliably in slow CI
|
|
96
|
+
const samples: number[] = await page.evaluate(() => {
|
|
97
|
+
return new Promise<number[]>((resolve) => {
|
|
98
|
+
const el = document.querySelector('[data-testid="driver-none"]')!
|
|
99
|
+
const vals: number[] = []
|
|
100
|
+
const start = performance.now()
|
|
101
|
+
function tick() {
|
|
102
|
+
vals.push(Number(getComputedStyle(el).opacity))
|
|
103
|
+
if (performance.now() - start < 500) requestAnimationFrame(tick)
|
|
104
|
+
else resolve(vals)
|
|
105
|
+
}
|
|
106
|
+
;(document.querySelector('[data-testid="toggle-multi"]') as HTMLElement).click()
|
|
107
|
+
requestAnimationFrame(tick)
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const finalOpacity = samples[samples.length - 1]
|
|
112
|
+
expect(finalOpacity).toBeGreaterThan(0.9)
|
|
113
|
+
|
|
114
|
+
// verify motion driver: multiple frames of interpolation between 0.3 and ~1.0
|
|
115
|
+
const intermediates = samples.filter((v) => v > 0.35 && v < 0.95)
|
|
116
|
+
expect(
|
|
117
|
+
intermediates.length,
|
|
118
|
+
`Default should use motion with real interpolation (got ${intermediates.length} intermediate frames). ` +
|
|
119
|
+
`Samples: [${samples
|
|
120
|
+
.slice(0, 8)
|
|
121
|
+
.map((s) => s.toFixed(2))
|
|
122
|
+
.join(', ')}...]`
|
|
123
|
+
).toBeGreaterThanOrEqual(2)
|
|
124
|
+
|
|
125
|
+
// first frames should still be near start (animation has real duration)
|
|
126
|
+
const earlyEnd = samples.slice(0, 3).every((v) => v > 0.95)
|
|
127
|
+
expect(earlyEnd, 'Animation should not complete in first 3 frames').toBe(false)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
test('different drivers produce different animation behavior', async ({ page }) => {
|
|
131
|
+
// trigger animation
|
|
132
|
+
await page.getByTestId('toggle-multi').click()
|
|
133
|
+
|
|
134
|
+
// capture at same moment
|
|
135
|
+
await page.waitForTimeout(100)
|
|
136
|
+
|
|
137
|
+
const [defaultOpacity, cssOpacity] = await Promise.all([
|
|
138
|
+
page
|
|
139
|
+
.getByTestId('driver-default')
|
|
140
|
+
.evaluate((el) => Number(getComputedStyle(el).opacity)),
|
|
141
|
+
page
|
|
142
|
+
.getByTestId('driver-css')
|
|
143
|
+
.evaluate((el) => Number(getComputedStyle(el).opacity)),
|
|
144
|
+
])
|
|
145
|
+
|
|
146
|
+
// both should be animating but may have different values due to different drivers
|
|
147
|
+
// this just verifies both are in valid range
|
|
148
|
+
expect(defaultOpacity).toBeGreaterThanOrEqual(0.3)
|
|
149
|
+
expect(defaultOpacity).toBeLessThanOrEqual(1)
|
|
150
|
+
expect(cssOpacity).toBeGreaterThanOrEqual(0.3)
|
|
151
|
+
expect(cssOpacity).toBeLessThanOrEqual(1)
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
test.describe('Multi-driver group hover transitions', () => {
|
|
156
|
+
test.beforeEach(async ({ page }) => {
|
|
157
|
+
await page.goto('/?test=MultiDriverAnimation&animationDriver=multi')
|
|
158
|
+
await page.waitForLoadState('networkidle')
|
|
159
|
+
await page.waitForTimeout(300)
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
test('group hover with motion driver animates child', async ({ page }) => {
|
|
163
|
+
const group = page.getByTestId('group-motion')
|
|
164
|
+
const child = page.getByTestId('group-motion-child')
|
|
165
|
+
|
|
166
|
+
const initialOpacity = await child.evaluate((el) =>
|
|
167
|
+
Number(getComputedStyle(el).opacity)
|
|
168
|
+
)
|
|
169
|
+
expect(initialOpacity).toBeCloseTo(0.5, 1)
|
|
170
|
+
|
|
171
|
+
// hover over group - 100ms enter transition
|
|
172
|
+
await group.hover()
|
|
173
|
+
await page.waitForTimeout(200)
|
|
174
|
+
|
|
175
|
+
const hoverOpacity = await child.evaluate((el) =>
|
|
176
|
+
Number(getComputedStyle(el).opacity)
|
|
177
|
+
)
|
|
178
|
+
expect(hoverOpacity).toBeGreaterThan(0.9)
|
|
179
|
+
|
|
180
|
+
// exit hover - 500ms exit transition
|
|
181
|
+
await page.mouse.move(0, 0)
|
|
182
|
+
await page.waitForTimeout(700)
|
|
183
|
+
|
|
184
|
+
const exitOpacity = await child.evaluate((el) => Number(getComputedStyle(el).opacity))
|
|
185
|
+
expect(exitOpacity).toBeCloseTo(0.5, 1)
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
test('group hover with css driver uses CSS transitions', async ({ page }) => {
|
|
189
|
+
const group = page.getByTestId('group-css')
|
|
190
|
+
const child = page.getByTestId('group-css-child')
|
|
191
|
+
|
|
192
|
+
const initialOpacity = await child.evaluate((el) =>
|
|
193
|
+
Number(getComputedStyle(el).opacity)
|
|
194
|
+
)
|
|
195
|
+
expect(initialOpacity).toBeCloseTo(0.5, 1)
|
|
196
|
+
|
|
197
|
+
await group.hover()
|
|
198
|
+
// css driver hover transition should complete
|
|
199
|
+
await page.waitForTimeout(400)
|
|
200
|
+
|
|
201
|
+
const hoverOpacity = await child.evaluate((el) =>
|
|
202
|
+
Number(getComputedStyle(el).opacity)
|
|
203
|
+
)
|
|
204
|
+
// CSS driver group hover should animate to full opacity
|
|
205
|
+
expect(hoverOpacity).toBeGreaterThan(0.8)
|
|
206
|
+
})
|
|
207
|
+
})
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
import { setupPage } from './test-utils'
|
|
3
|
+
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await setupPage(page, { name: 'NewInputBasic', type: 'useCase' })
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('renders basic input', async ({ page }) => {
|
|
9
|
+
const input = page.locator('[data-testid="basic-input"]')
|
|
10
|
+
await expect(input).toBeVisible()
|
|
11
|
+
await expect(input).toHaveAttribute('placeholder', 'Basic input')
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
test('renders password input with correct type', async ({ page }) => {
|
|
15
|
+
const input = page.locator('[data-testid="password-input"]')
|
|
16
|
+
await expect(input).toBeVisible()
|
|
17
|
+
await expect(input).toHaveAttribute('type', 'password')
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('renders email input with correct type', async ({ page }) => {
|
|
21
|
+
const input = page.locator('[data-testid="email-input"]')
|
|
22
|
+
await expect(input).toBeVisible()
|
|
23
|
+
await expect(input).toHaveAttribute('type', 'email')
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('renders number input with correct type', async ({ page }) => {
|
|
27
|
+
const input = page.locator('[data-testid="number-input"]')
|
|
28
|
+
await expect(input).toBeVisible()
|
|
29
|
+
await expect(input).toHaveAttribute('type', 'number')
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('renders disabled input', async ({ page }) => {
|
|
33
|
+
const input = page.locator('[data-testid="disabled-input"]')
|
|
34
|
+
await expect(input).toBeVisible()
|
|
35
|
+
await expect(input).toBeDisabled()
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('renders readonly input', async ({ page }) => {
|
|
39
|
+
const input = page.locator('[data-testid="readonly-input"]')
|
|
40
|
+
await expect(input).toBeVisible()
|
|
41
|
+
await expect(input).toHaveAttribute('readonly', '')
|
|
42
|
+
await expect(input).toHaveValue('Read only value')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('renders textarea', async ({ page }) => {
|
|
46
|
+
const textarea = page.locator('[data-testid="basic-textarea"]')
|
|
47
|
+
await expect(textarea).toBeVisible()
|
|
48
|
+
// Textarea should be rendered as textarea element
|
|
49
|
+
await expect(textarea).toHaveAttribute('placeholder', 'Basic textarea')
|
|
50
|
+
})
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
import { setupPage } from './test-utils'
|
|
3
|
+
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await setupPage(page, { name: 'NewInputEvents', type: 'useCase' })
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
test('onChange updates value display', async ({ page }) => {
|
|
9
|
+
const input = page.locator('[data-testid="event-input"]')
|
|
10
|
+
const valueDisplay = page.locator('[data-testid="value-display"]')
|
|
11
|
+
|
|
12
|
+
await input.fill('hello world')
|
|
13
|
+
|
|
14
|
+
await expect(valueDisplay).toContainText('Value: hello world')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('onChange increments change count', async ({ page }) => {
|
|
18
|
+
const input = page.locator('[data-testid="event-input"]')
|
|
19
|
+
const changeCount = page.locator('[data-testid="change-count"]')
|
|
20
|
+
|
|
21
|
+
await expect(changeCount).toContainText('Changes: 0')
|
|
22
|
+
|
|
23
|
+
await input.fill('a')
|
|
24
|
+
await expect(changeCount).toContainText('Changes: 1')
|
|
25
|
+
|
|
26
|
+
await input.fill('ab')
|
|
27
|
+
await expect(changeCount).toContainText('Changes: 2')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('onSubmitEditing fires on Enter', async ({ page }) => {
|
|
31
|
+
const input = page.locator('[data-testid="event-input"]')
|
|
32
|
+
const submitCount = page.locator('[data-testid="submit-count"]')
|
|
33
|
+
|
|
34
|
+
await expect(submitCount).toContainText('Submits: 0')
|
|
35
|
+
|
|
36
|
+
await input.focus()
|
|
37
|
+
await input.press('Enter')
|
|
38
|
+
|
|
39
|
+
await expect(submitCount).toContainText('Submits: 1')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('typing and submitting works together', async ({ page }) => {
|
|
43
|
+
const input = page.locator('[data-testid="event-input"]')
|
|
44
|
+
const valueDisplay = page.locator('[data-testid="value-display"]')
|
|
45
|
+
const submitCount = page.locator('[data-testid="submit-count"]')
|
|
46
|
+
|
|
47
|
+
await input.fill('test value')
|
|
48
|
+
await expect(valueDisplay).toContainText('Value: test value')
|
|
49
|
+
|
|
50
|
+
await input.press('Enter')
|
|
51
|
+
await expect(submitCount).toContainText('Submits: 1')
|
|
52
|
+
|
|
53
|
+
// Value should still be there after submit
|
|
54
|
+
await expect(valueDisplay).toContainText('Value: test value')
|
|
55
|
+
})
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { expect, test, type Page } from '@playwright/test'
|
|
2
|
+
import { setupPage } from './test-utils'
|
|
3
|
+
|
|
4
|
+
// poll interval is ~233ms (14 frames), give generous margin
|
|
5
|
+
const POLL_WAIT = 800
|
|
6
|
+
|
|
7
|
+
function parseLayout(text: string) {
|
|
8
|
+
// format: "A:120x60@0,0#1"
|
|
9
|
+
const m = text.match(/^([AB]):(\d+)x(\d+)@(-?\d+),(-?\d+)#(\d+)$/)
|
|
10
|
+
if (!m) throw new Error(`bad layout string: ${text}`)
|
|
11
|
+
return {
|
|
12
|
+
label: m[1],
|
|
13
|
+
width: Number(m[2]),
|
|
14
|
+
height: Number(m[3]),
|
|
15
|
+
x: Number(m[4]),
|
|
16
|
+
y: Number(m[5]),
|
|
17
|
+
count: Number(m[6]),
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function getLayout(page: Page, testId: string) {
|
|
22
|
+
const text = await page.getByTestId(testId).innerText()
|
|
23
|
+
return parseLayout(text)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
test.beforeEach(async ({ page }) => {
|
|
27
|
+
await setupPage(page, { name: 'OnLayoutCase', type: 'useCase' })
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('fires on mount with correct dimensions', async ({ page }) => {
|
|
31
|
+
// onLayout should fire at least once on mount with accurate size
|
|
32
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
33
|
+
const a = await getLayout(page, 'layout-a')
|
|
34
|
+
expect(a.count).toBeGreaterThanOrEqual(1)
|
|
35
|
+
expect(a.width).toBe(120)
|
|
36
|
+
expect(a.height).toBe(60)
|
|
37
|
+
// x should be 0 (no margin) relative to parent
|
|
38
|
+
expect(a.x).toBe(0)
|
|
39
|
+
|
|
40
|
+
// box B should also have fired
|
|
41
|
+
const b = await getLayout(page, 'layout-b')
|
|
42
|
+
expect(b.count).toBeGreaterThanOrEqual(1)
|
|
43
|
+
expect(b.width).toBe(200)
|
|
44
|
+
expect(b.height).toBe(50)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('detects position change', async ({ page }) => {
|
|
48
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
49
|
+
const before = await getLayout(page, 'layout-a')
|
|
50
|
+
expect(before.x).toBe(0)
|
|
51
|
+
|
|
52
|
+
await page.getByTestId('btn-move').click()
|
|
53
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
54
|
+
|
|
55
|
+
const after = await getLayout(page, 'layout-a')
|
|
56
|
+
expect(after.x).toBe(100)
|
|
57
|
+
expect(after.count).toBeGreaterThan(before.count)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('detects size change', async ({ page }) => {
|
|
61
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
62
|
+
const before = await getLayout(page, 'layout-a')
|
|
63
|
+
expect(before.width).toBe(120)
|
|
64
|
+
expect(before.height).toBe(60)
|
|
65
|
+
|
|
66
|
+
await page.getByTestId('btn-resize').click()
|
|
67
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
68
|
+
|
|
69
|
+
const after = await getLayout(page, 'layout-a')
|
|
70
|
+
expect(after.width).toBe(180)
|
|
71
|
+
expect(after.height).toBe(80)
|
|
72
|
+
expect(after.count).toBeGreaterThan(before.count)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
test('detects parent size change via child resize', async ({ page }) => {
|
|
76
|
+
// parent shrinking alone won't re-fire onLayout if the child rect is unchanged.
|
|
77
|
+
// combine parent resize + child resize to verify the parent rect is picked up.
|
|
78
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
79
|
+
const before = await getLayout(page, 'layout-a')
|
|
80
|
+
|
|
81
|
+
// resize both parent and child
|
|
82
|
+
await page.getByTestId('btn-parent-resize').click()
|
|
83
|
+
await page.getByTestId('btn-resize').click()
|
|
84
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
85
|
+
|
|
86
|
+
const after = await getLayout(page, 'layout-a')
|
|
87
|
+
expect(after.count).toBeGreaterThan(before.count)
|
|
88
|
+
// child resized to 180x80
|
|
89
|
+
expect(after.width).toBe(180)
|
|
90
|
+
expect(after.height).toBe(80)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
test('unmount cleans up and remount re-fires', async ({ page }) => {
|
|
94
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
95
|
+
const before = await getLayout(page, 'layout-a')
|
|
96
|
+
expect(before.count).toBeGreaterThanOrEqual(1)
|
|
97
|
+
|
|
98
|
+
// unmount
|
|
99
|
+
await page.getByTestId('btn-toggle-mount').click()
|
|
100
|
+
await page.waitForTimeout(200)
|
|
101
|
+
// layout text should reset to zeros since state resets
|
|
102
|
+
const unmounted = await getLayout(page, 'layout-a')
|
|
103
|
+
// count shouldn't have increased (component reset its state)
|
|
104
|
+
// but we can't assert count=0 because state persists in parent
|
|
105
|
+
// instead verify box-a is gone from DOM
|
|
106
|
+
await expect(page.getByTestId('box-a')).not.toBeVisible()
|
|
107
|
+
|
|
108
|
+
// remount
|
|
109
|
+
await page.getByTestId('btn-toggle-mount').click()
|
|
110
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
111
|
+
const remounted = await getLayout(page, 'layout-a')
|
|
112
|
+
expect(remounted.count).toBeGreaterThan(unmounted.count)
|
|
113
|
+
expect(remounted.width).toBe(120)
|
|
114
|
+
expect(remounted.height).toBe(60)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
test('node swap fires onLayout for new element', async ({ page }) => {
|
|
118
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
119
|
+
const before = await getLayout(page, 'layout-a')
|
|
120
|
+
expect(before.count).toBeGreaterThanOrEqual(1)
|
|
121
|
+
|
|
122
|
+
// swap replaces the element via different key (box-a-default -> box-a-alt)
|
|
123
|
+
await page.getByTestId('btn-swap').click()
|
|
124
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
125
|
+
|
|
126
|
+
const after = await getLayout(page, 'layout-a')
|
|
127
|
+
// should have fired for the new node
|
|
128
|
+
expect(after.count).toBeGreaterThan(before.count)
|
|
129
|
+
// dimensions should be the same since props match
|
|
130
|
+
expect(after.width).toBe(120)
|
|
131
|
+
expect(after.height).toBe(60)
|
|
132
|
+
|
|
133
|
+
// verify the background color changed (proves DOM node actually swapped)
|
|
134
|
+
const bg = await page.getByTestId('box-a').evaluate((el) => {
|
|
135
|
+
return getComputedStyle(el).backgroundColor
|
|
136
|
+
})
|
|
137
|
+
// blue8 instead of red8 — just check it's not the original red
|
|
138
|
+
expect(bg).not.toContain('rgb(229, 72, 77)')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
test('multiple instances do not cross-contaminate', async ({ page }) => {
|
|
142
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
143
|
+
const a = await getLayout(page, 'layout-a')
|
|
144
|
+
const b = await getLayout(page, 'layout-b')
|
|
145
|
+
|
|
146
|
+
// both should have independent correct values
|
|
147
|
+
expect(a.width).toBe(120)
|
|
148
|
+
expect(b.width).toBe(200)
|
|
149
|
+
|
|
150
|
+
// move box A — box B should not change
|
|
151
|
+
await page.getByTestId('btn-move').click()
|
|
152
|
+
await page.waitForTimeout(POLL_WAIT)
|
|
153
|
+
|
|
154
|
+
const a2 = await getLayout(page, 'layout-a')
|
|
155
|
+
const b2 = await getLayout(page, 'layout-b')
|
|
156
|
+
|
|
157
|
+
expect(a2.x).toBe(100)
|
|
158
|
+
// B's values should be unchanged
|
|
159
|
+
expect(b2.width).toBe(b.width)
|
|
160
|
+
expect(b2.height).toBe(b.height)
|
|
161
|
+
expect(b2.x).toBe(b.x)
|
|
162
|
+
expect(b2.y).toBe(b.y)
|
|
163
|
+
})
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
import { setupPage } from './test-utils'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* tests for onLayout with CSS scale transform.
|
|
6
|
+
*
|
|
7
|
+
* default behavior (no flag):
|
|
8
|
+
* - onLayout reports transformed dimensions (getBoundingClientRect behavior)
|
|
9
|
+
* - a 200x200 element with scale(0.5) reports 100x100
|
|
10
|
+
*
|
|
11
|
+
* with __HANZO_GUI_ONLAYOUT_PRETRANSFORM = true:
|
|
12
|
+
* - onLayout should report pre-transform dimensions (matching RN behavior)
|
|
13
|
+
* - a 200x200 element with scale(0.5) should report 200x200
|
|
14
|
+
*
|
|
15
|
+
* see: https://github.com/hanzoai/gui/pull/2329
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
test.describe('onLayout with CSS scale', () => {
|
|
19
|
+
test.beforeEach(async ({ page }) => {
|
|
20
|
+
await setupPage(page, {
|
|
21
|
+
name: 'OnLayoutScaleCase',
|
|
22
|
+
type: 'useCase',
|
|
23
|
+
waitExtra: true,
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('unscaled box always reports correct dimensions (200x200)', async ({ page }) => {
|
|
28
|
+
await page.waitForTimeout(500)
|
|
29
|
+
|
|
30
|
+
const layoutText = await page.getByTestId('layout-no-scale').textContent()
|
|
31
|
+
|
|
32
|
+
expect(layoutText).toContain('200')
|
|
33
|
+
expect(layoutText).toMatch(/200.*200/)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('scaled box reports transformed dimensions by default (100x100)', async ({
|
|
37
|
+
page,
|
|
38
|
+
}) => {
|
|
39
|
+
// ensure flag is OFF
|
|
40
|
+
await page.evaluate(() => {
|
|
41
|
+
;(globalThis as any).__HANZO_GUI_ONLAYOUT_PRETRANSFORM = false
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// trigger relayout to pick up the flag change
|
|
45
|
+
await page.getByTestId('trigger-relayout').click()
|
|
46
|
+
await page.waitForTimeout(500)
|
|
47
|
+
|
|
48
|
+
const layoutText = await page.getByTestId('layout-with-scale').textContent()
|
|
49
|
+
|
|
50
|
+
// without flag: 200x200 with scale(0.5) should report 100x100 (transformed)
|
|
51
|
+
expect(layoutText).toContain('100')
|
|
52
|
+
expect(layoutText).toMatch(/100.*100/)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('scaled box reports pre-transform dimensions with flag enabled (200x200)', async ({
|
|
56
|
+
page,
|
|
57
|
+
}) => {
|
|
58
|
+
// enable the flag
|
|
59
|
+
await page.evaluate(() => {
|
|
60
|
+
;(globalThis as any).__HANZO_GUI_ONLAYOUT_PRETRANSFORM = true
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// trigger relayout to pick up the flag change
|
|
64
|
+
await page.getByTestId('trigger-relayout').click()
|
|
65
|
+
await page.waitForTimeout(500)
|
|
66
|
+
|
|
67
|
+
const layoutText = await page.getByTestId('layout-with-scale').textContent()
|
|
68
|
+
|
|
69
|
+
// with flag: 200x200 with scale(0.5) should report 200x200 (pre-transform, RN behavior)
|
|
70
|
+
expect(layoutText).toContain('200')
|
|
71
|
+
expect(layoutText).toMatch(/200.*200/)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
test('both boxes report same dimensions with flag enabled', async ({ page }) => {
|
|
75
|
+
// enable the flag
|
|
76
|
+
await page.evaluate(() => {
|
|
77
|
+
;(globalThis as any).__HANZO_GUI_ONLAYOUT_PRETRANSFORM = true
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
// trigger relayout
|
|
81
|
+
await page.getByTestId('trigger-relayout').click()
|
|
82
|
+
await page.waitForTimeout(500)
|
|
83
|
+
|
|
84
|
+
const noScaleText = await page.getByTestId('layout-no-scale').textContent()
|
|
85
|
+
const withScaleText = await page.getByTestId('layout-with-scale').textContent()
|
|
86
|
+
|
|
87
|
+
// extract dimensions
|
|
88
|
+
const noScaleMatch = noScaleText?.match(/(\d+)x(\d+)/)
|
|
89
|
+
const withScaleMatch = withScaleText?.match(/(\d+)x(\d+)/)
|
|
90
|
+
|
|
91
|
+
expect(noScaleMatch).toBeTruthy()
|
|
92
|
+
expect(withScaleMatch).toBeTruthy()
|
|
93
|
+
|
|
94
|
+
if (noScaleMatch && withScaleMatch) {
|
|
95
|
+
// with flag enabled, both should report same pre-transform dimensions
|
|
96
|
+
expect(withScaleMatch[1]).toBe(noScaleMatch[1])
|
|
97
|
+
expect(withScaleMatch[2]).toBe(noScaleMatch[2])
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
})
|