@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,319 @@
|
|
|
1
|
+
import { expect, test, type Page } from '@playwright/test'
|
|
2
|
+
import { setupPage } from './test-utils'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* PSEUDO TRANSITION TESTS
|
|
6
|
+
*
|
|
7
|
+
* Tests for the `transition` prop inside pseudo-style props (hoverStyle, pressStyle, etc.)
|
|
8
|
+
*
|
|
9
|
+
* CSS semantics:
|
|
10
|
+
* - Enter pseudo state (e.g., hover): use that pseudo's transition (200ms)
|
|
11
|
+
* - Exit pseudo state (e.g., unhover): use base transition (1000ms)
|
|
12
|
+
*
|
|
13
|
+
* These tests run across all animation drivers (css, native, reanimated, motion).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
async function getBackgroundColor(page: Page, testId: string): Promise<string> {
|
|
17
|
+
return page.evaluate((id) => {
|
|
18
|
+
const el = document.querySelector(`[data-testid="${id}"]`)
|
|
19
|
+
if (!el) return ''
|
|
20
|
+
return getComputedStyle(el).backgroundColor
|
|
21
|
+
}, testId)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function getOpacity(page: Page, testId: string): Promise<number> {
|
|
25
|
+
return page.evaluate((id) => {
|
|
26
|
+
const el = document.querySelector(`[data-testid="${id}"]`)
|
|
27
|
+
if (!el) return -1
|
|
28
|
+
return Number.parseFloat(getComputedStyle(el).opacity)
|
|
29
|
+
}, testId)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function parseRgb(color: string): { r: number; g: number; b: number } | null {
|
|
33
|
+
const match = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/)
|
|
34
|
+
if (!match) return null
|
|
35
|
+
return {
|
|
36
|
+
r: Number.parseInt(match[1], 10),
|
|
37
|
+
g: Number.parseInt(match[2], 10),
|
|
38
|
+
b: Number.parseInt(match[3], 10),
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
test.describe('Pseudo Transition Tests', () => {
|
|
43
|
+
test.beforeEach(async ({ page }) => {
|
|
44
|
+
const driver = (test.info().project?.metadata as any)?.animationDriver
|
|
45
|
+
test.skip(driver === 'native', 'native driver has issues on web')
|
|
46
|
+
|
|
47
|
+
await setupPage(page, {
|
|
48
|
+
name: 'PseudoTransitionCase',
|
|
49
|
+
type: 'useCase',
|
|
50
|
+
})
|
|
51
|
+
// wait for initial render
|
|
52
|
+
await page.waitForTimeout(500)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('scenario 1: hoverStyle transition - fast enter (200ms), slow exit (1000ms)', async ({
|
|
56
|
+
page,
|
|
57
|
+
}) => {
|
|
58
|
+
const target = page.getByTestId('scenario-1-target')
|
|
59
|
+
const initialColor = await getBackgroundColor(page, 'scenario-1-target')
|
|
60
|
+
|
|
61
|
+
// hover to trigger enter animation (should be fast - 200ms)
|
|
62
|
+
await target.hover()
|
|
63
|
+
|
|
64
|
+
// wait for enter to complete
|
|
65
|
+
await page.waitForTimeout(350)
|
|
66
|
+
const hoverColor = await getBackgroundColor(page, 'scenario-1-target')
|
|
67
|
+
expect(hoverColor, 'Color should change on hover').not.toBe(initialColor)
|
|
68
|
+
|
|
69
|
+
// move mouse away to trigger exit animation (should be slow - 1000ms)
|
|
70
|
+
await page.mouse.move(0, 0)
|
|
71
|
+
|
|
72
|
+
// at 400ms, exit should still be in progress (1000ms animation)
|
|
73
|
+
await page.waitForTimeout(400)
|
|
74
|
+
const midExitColor = await getBackgroundColor(page, 'scenario-1-target')
|
|
75
|
+
const midExitRgb = parseRgb(midExitColor)
|
|
76
|
+
const hoverRgb = parseRgb(hoverColor)
|
|
77
|
+
const initialRgb = parseRgb(initialColor)
|
|
78
|
+
|
|
79
|
+
// check that exit is still in progress (color not yet back to initial)
|
|
80
|
+
if (midExitRgb && hoverRgb && initialRgb) {
|
|
81
|
+
expect(
|
|
82
|
+
midExitColor,
|
|
83
|
+
'At 400ms into 1000ms exit, color should not be fully reset'
|
|
84
|
+
).not.toBe(initialColor)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// wait for full exit
|
|
88
|
+
await page.waitForTimeout(800)
|
|
89
|
+
const finalColor = await getBackgroundColor(page, 'scenario-1-target')
|
|
90
|
+
expect(finalColor, 'Color should return to initial').toBe(initialColor)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
test('scenario 2: pressStyle transition - fast press (200ms), slow release (1000ms)', async ({
|
|
94
|
+
page,
|
|
95
|
+
}) => {
|
|
96
|
+
const target = page.getByTestId('scenario-2-target')
|
|
97
|
+
const initialColor = await getBackgroundColor(page, 'scenario-2-target')
|
|
98
|
+
|
|
99
|
+
// press to trigger enter animation
|
|
100
|
+
const box = await target.boundingBox()
|
|
101
|
+
if (!box) throw new Error('Target not found')
|
|
102
|
+
|
|
103
|
+
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2)
|
|
104
|
+
await page.mouse.down()
|
|
105
|
+
|
|
106
|
+
// wait for press animation (200ms + buffer)
|
|
107
|
+
await page.waitForTimeout(350)
|
|
108
|
+
const pressColor = await getBackgroundColor(page, 'scenario-2-target')
|
|
109
|
+
expect(pressColor, 'Color should change on press').not.toBe(initialColor)
|
|
110
|
+
|
|
111
|
+
// release to trigger exit animation (should be slow - 1000ms)
|
|
112
|
+
await page.mouse.up()
|
|
113
|
+
|
|
114
|
+
// at 400ms, exit should still be in progress if using 1000ms base
|
|
115
|
+
await page.waitForTimeout(400)
|
|
116
|
+
const midReleaseColor = await getBackgroundColor(page, 'scenario-2-target')
|
|
117
|
+
|
|
118
|
+
// check exit is still in progress across drivers
|
|
119
|
+
const midRgb = parseRgb(midReleaseColor)
|
|
120
|
+
const pressRgb = parseRgb(pressColor)
|
|
121
|
+
const initRgb = parseRgb(initialColor)
|
|
122
|
+
|
|
123
|
+
if (midRgb && pressRgb && initRgb) {
|
|
124
|
+
expect(
|
|
125
|
+
midReleaseColor,
|
|
126
|
+
'At 400ms into 1000ms release, color should not be fully reset'
|
|
127
|
+
).not.toBe(initialColor)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// wait for full exit
|
|
131
|
+
await page.waitForTimeout(800)
|
|
132
|
+
const finalColor = await getBackgroundColor(page, 'scenario-2-target')
|
|
133
|
+
expect(finalColor, 'Color should return to initial').toBe(initialColor)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
test('scenario 6: opacity hover - fast fade in (200ms), slow fade out (1000ms)', async ({
|
|
137
|
+
page,
|
|
138
|
+
}) => {
|
|
139
|
+
// CSS driver now supports pseudo-class transitions via !important CSS rules
|
|
140
|
+
|
|
141
|
+
const target = page.getByTestId('scenario-6-target')
|
|
142
|
+
const initialOpacity = await getOpacity(page, 'scenario-6-target')
|
|
143
|
+
expect(initialOpacity, 'Initial opacity should be ~0.3').toBeCloseTo(0.3, 1)
|
|
144
|
+
|
|
145
|
+
// hover to trigger opacity increase
|
|
146
|
+
await target.hover()
|
|
147
|
+
|
|
148
|
+
// wait for enter to complete (200ms + buffer for springs)
|
|
149
|
+
await page.waitForTimeout(400)
|
|
150
|
+
const hoverOpacity = await getOpacity(page, 'scenario-6-target')
|
|
151
|
+
expect(hoverOpacity, 'Hover opacity should be > 0.6').toBeGreaterThan(0.6)
|
|
152
|
+
|
|
153
|
+
// move away to trigger opacity decrease (slow - 1000ms)
|
|
154
|
+
await page.mouse.move(0, 0)
|
|
155
|
+
|
|
156
|
+
// at 300ms, opacity should still be elevated if using 1000ms exit
|
|
157
|
+
await page.waitForTimeout(300)
|
|
158
|
+
const midExitOpacity = await getOpacity(page, 'scenario-6-target')
|
|
159
|
+
|
|
160
|
+
expect(
|
|
161
|
+
midExitOpacity,
|
|
162
|
+
'Opacity at 300ms of 1000ms exit should still be elevated'
|
|
163
|
+
).toBeGreaterThan(0.4)
|
|
164
|
+
|
|
165
|
+
// wait for full exit
|
|
166
|
+
await page.waitForTimeout(800)
|
|
167
|
+
const finalOpacity = await getOpacity(page, 'scenario-6-target')
|
|
168
|
+
expect(finalOpacity, 'Final opacity should be ~0.3').toBeCloseTo(0.3, 1)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
// BUG TEST: First pseudo interaction should use pseudo transition
|
|
172
|
+
// Regression test for: prevPseudoState not initialized, causing first hover to use base transition
|
|
173
|
+
test('first hover should use pseudo transition (not base)', async ({ page }) => {
|
|
174
|
+
const driver = (test.info().project?.metadata as any)?.animationDriver
|
|
175
|
+
|
|
176
|
+
const target = page.getByTestId('scenario-6-target')
|
|
177
|
+
const initialOpacity = await getOpacity(page, 'scenario-6-target')
|
|
178
|
+
expect(initialOpacity, 'Initial opacity should be ~0.3').toBeCloseTo(0.3, 1)
|
|
179
|
+
|
|
180
|
+
// FIRST hover - should use fast 200ms pseudo transition
|
|
181
|
+
await target.hover()
|
|
182
|
+
|
|
183
|
+
// at 350ms, a 200ms animation should be complete (extra buffer for springs)
|
|
184
|
+
await page.waitForTimeout(350)
|
|
185
|
+
const firstHoverOpacity = await getOpacity(page, 'scenario-6-target')
|
|
186
|
+
|
|
187
|
+
// if prevPseudoState wasn't initialized, this would use 1000ms base transition
|
|
188
|
+
// and opacity would still be low (~0.4-0.5). with proper 200ms, should be > 0.6
|
|
189
|
+
expect(
|
|
190
|
+
firstHoverOpacity,
|
|
191
|
+
`First hover should complete quickly with pseudo transition (got ${firstHoverOpacity}, driver: ${driver})`
|
|
192
|
+
).toBeGreaterThan(0.6)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
// BUG TEST: Exit should use base transition, not cached pseudo transition
|
|
196
|
+
// Regression test for: reanimated keeps pseudo config on exit instead of restoring base
|
|
197
|
+
test('exit should use base transition timing (not cached pseudo)', async ({ page }) => {
|
|
198
|
+
const driver = (test.info().project?.metadata as any)?.animationDriver
|
|
199
|
+
|
|
200
|
+
const target = page.getByTestId('scenario-6-target')
|
|
201
|
+
|
|
202
|
+
// hover to enter (fast 200ms) - wait longer for springs
|
|
203
|
+
await target.hover()
|
|
204
|
+
await page.waitForTimeout(400)
|
|
205
|
+
const hoverOpacity = await getOpacity(page, 'scenario-6-target')
|
|
206
|
+
expect(hoverOpacity, 'Should be at hover state').toBeGreaterThan(0.7)
|
|
207
|
+
|
|
208
|
+
// exit hover - should use SLOW 1000ms base transition
|
|
209
|
+
await page.mouse.move(0, 0)
|
|
210
|
+
|
|
211
|
+
// at 250ms into a 1000ms exit, should still be > 0.4
|
|
212
|
+
// if using cached 200ms pseudo transition, would already be near 0.3
|
|
213
|
+
await page.waitForTimeout(250)
|
|
214
|
+
const midExitOpacity = await getOpacity(page, 'scenario-6-target')
|
|
215
|
+
|
|
216
|
+
expect(
|
|
217
|
+
midExitOpacity,
|
|
218
|
+
`Exit at 250ms of 1000ms should still be > 0.4 (got ${midExitOpacity}, driver: ${driver})`
|
|
219
|
+
).toBeGreaterThan(0.4)
|
|
220
|
+
|
|
221
|
+
// wait for exit to complete
|
|
222
|
+
await page.waitForTimeout(900)
|
|
223
|
+
const finalOpacity = await getOpacity(page, 'scenario-6-target')
|
|
224
|
+
expect(finalOpacity, 'Should return to initial').toBeCloseTo(0.3, 1)
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
test('scenario 6: repeated hover cycles keep slow exit timing (reanimated regression)', async ({
|
|
228
|
+
page,
|
|
229
|
+
}) => {
|
|
230
|
+
const driver = (test.info().project?.metadata as any)?.animationDriver
|
|
231
|
+
test.skip(
|
|
232
|
+
driver !== 'reanimated',
|
|
233
|
+
'Reanimated-specific config cache regression coverage'
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
const target = page.getByTestId('scenario-6-target')
|
|
237
|
+
const initialOpacity = await getOpacity(page, 'scenario-6-target')
|
|
238
|
+
expect(initialOpacity, 'Initial opacity should be ~0.3').toBeCloseTo(0.3, 1)
|
|
239
|
+
|
|
240
|
+
const runCycle = async () => {
|
|
241
|
+
await target.hover()
|
|
242
|
+
await page.waitForTimeout(350)
|
|
243
|
+
const hoveredOpacity = await getOpacity(page, 'scenario-6-target')
|
|
244
|
+
expect(
|
|
245
|
+
hoveredOpacity,
|
|
246
|
+
'Enter should move quickly toward hover opacity'
|
|
247
|
+
).toBeGreaterThan(0.7)
|
|
248
|
+
|
|
249
|
+
await page.mouse.move(0, 0)
|
|
250
|
+
await page.waitForTimeout(300)
|
|
251
|
+
const midExitOpacity = await getOpacity(page, 'scenario-6-target')
|
|
252
|
+
expect(
|
|
253
|
+
midExitOpacity,
|
|
254
|
+
'Exit should still be in progress at 300ms (base 1000ms transition)'
|
|
255
|
+
).toBeGreaterThan(0.5)
|
|
256
|
+
|
|
257
|
+
await page.waitForTimeout(900)
|
|
258
|
+
const finalOpacity = await getOpacity(page, 'scenario-6-target')
|
|
259
|
+
expect(finalOpacity, 'Cycle should return to base opacity').toBeCloseTo(0.3, 1)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
await runCycle()
|
|
263
|
+
await runCycle()
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
test('scenario 4: group hover transition - fast enter (200ms)', async ({ page }) => {
|
|
267
|
+
const driver = (test.info().project?.metadata as any)?.animationDriver
|
|
268
|
+
|
|
269
|
+
const container = page.getByTestId('scenario-4-container')
|
|
270
|
+
const initialOpacity = await getOpacity(page, 'scenario-4-target')
|
|
271
|
+
expect(initialOpacity, 'Initial opacity should be ~0.3').toBeCloseTo(0.3, 1)
|
|
272
|
+
|
|
273
|
+
// hover over container to trigger group hover (should be fast - 200ms)
|
|
274
|
+
await container.hover()
|
|
275
|
+
|
|
276
|
+
// at 350ms, a 200ms animation should be complete (extra buffer for springs)
|
|
277
|
+
await page.waitForTimeout(350)
|
|
278
|
+
const hoverOpacity = await getOpacity(page, 'scenario-4-target')
|
|
279
|
+
|
|
280
|
+
// if using 200ms transition, opacity should be close to 1 (>0.8)
|
|
281
|
+
// if using 1000ms base transition incorrectly, would be ~0.5
|
|
282
|
+
expect(
|
|
283
|
+
hoverOpacity,
|
|
284
|
+
`Group hover enter should complete quickly with 200ms transition (got ${hoverOpacity}, driver: ${driver})`
|
|
285
|
+
).toBeGreaterThan(0.8)
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
test('scenario 4: group hover transition - slow exit (1000ms base)', async ({
|
|
289
|
+
page,
|
|
290
|
+
}) => {
|
|
291
|
+
const container = page.getByTestId('scenario-4-container')
|
|
292
|
+
const initialOpacity = await getOpacity(page, 'scenario-4-target')
|
|
293
|
+
expect(initialOpacity, 'Initial opacity should be ~0.3').toBeCloseTo(0.3, 1)
|
|
294
|
+
|
|
295
|
+
// hover over container to trigger group hover
|
|
296
|
+
await container.hover()
|
|
297
|
+
|
|
298
|
+
// wait for hover state to be fully applied (use longer time for all drivers)
|
|
299
|
+
await page.waitForTimeout(1200)
|
|
300
|
+
const hoverOpacity = await getOpacity(page, 'scenario-4-target')
|
|
301
|
+
expect(hoverOpacity, 'Hover opacity should be ~1').toBeGreaterThan(0.9)
|
|
302
|
+
|
|
303
|
+
// move away to trigger exit (slow - 1000ms base transition)
|
|
304
|
+
await page.mouse.move(0, 0)
|
|
305
|
+
|
|
306
|
+
// KEY TEST: at 300ms into 1000ms linear exit, opacity should still be > 0.5
|
|
307
|
+
await page.waitForTimeout(300)
|
|
308
|
+
const midExitOpacity = await getOpacity(page, 'scenario-4-target')
|
|
309
|
+
expect(
|
|
310
|
+
midExitOpacity,
|
|
311
|
+
'Opacity should still be elevated during slow group-hover exit'
|
|
312
|
+
).toBeGreaterThan(0.5)
|
|
313
|
+
|
|
314
|
+
// wait for full exit
|
|
315
|
+
await page.waitForTimeout(900)
|
|
316
|
+
const finalOpacity = await getOpacity(page, 'scenario-4-target')
|
|
317
|
+
expect(finalOpacity, 'Final opacity should be ~0.3').toBeCloseTo(0.3, 1)
|
|
318
|
+
})
|
|
319
|
+
})
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
import { setupPage } from './test-utils'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Tests for raw Animated.Value with Animated.createAnimatedComponent
|
|
6
|
+
*
|
|
7
|
+
* This validates that react-native-web-lite properly handles AnimatedValue
|
|
8
|
+
* objects when passed as style props to Animated components.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
test.describe('Raw Animated.Value', () => {
|
|
12
|
+
test.beforeEach(async ({ page }) => {
|
|
13
|
+
await setupPage(page, {
|
|
14
|
+
name: 'RawAnimatedValueCase',
|
|
15
|
+
type: 'useCase',
|
|
16
|
+
})
|
|
17
|
+
await page.waitForTimeout(500)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('initial state applies animated values correctly', async ({ page }) => {
|
|
21
|
+
const box = page.getByTestId('animated-box')
|
|
22
|
+
|
|
23
|
+
// initial values: opacity=0, scale=0.5, translateY=50, backgroundColor=red
|
|
24
|
+
const opacity = await box.evaluate((el) => getComputedStyle(el).opacity)
|
|
25
|
+
const transform = await box.evaluate((el) => getComputedStyle(el).transform)
|
|
26
|
+
const bgColor = await box.evaluate((el) => getComputedStyle(el).backgroundColor)
|
|
27
|
+
|
|
28
|
+
expect(opacity).toBe('0')
|
|
29
|
+
// matrix(scaleX, 0, 0, scaleY, translateX, translateY)
|
|
30
|
+
expect(transform).toContain('matrix')
|
|
31
|
+
expect(transform).toContain('0.5') // scale
|
|
32
|
+
expect(transform).toContain('50') // translateY
|
|
33
|
+
expect(bgColor).toBe('rgb(255, 0, 0)') // red
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('animate in changes values over time', async ({ page }) => {
|
|
37
|
+
const box = page.getByTestId('animated-box')
|
|
38
|
+
const trigger = page.getByTestId('animate-in-trigger')
|
|
39
|
+
|
|
40
|
+
// capture initial
|
|
41
|
+
const initialOpacity = await box.evaluate((el) =>
|
|
42
|
+
parseFloat(getComputedStyle(el).opacity)
|
|
43
|
+
)
|
|
44
|
+
expect(initialOpacity).toBe(0)
|
|
45
|
+
|
|
46
|
+
// click animate in
|
|
47
|
+
await trigger.click()
|
|
48
|
+
|
|
49
|
+
// wait a bit for animation to progress
|
|
50
|
+
await page.waitForTimeout(100)
|
|
51
|
+
|
|
52
|
+
// capture mid-animation value
|
|
53
|
+
const midOpacity = await box.evaluate((el) =>
|
|
54
|
+
parseFloat(getComputedStyle(el).opacity)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
// wait for animation to complete
|
|
58
|
+
await page.waitForTimeout(400)
|
|
59
|
+
|
|
60
|
+
// capture final
|
|
61
|
+
const finalOpacity = await box.evaluate((el) =>
|
|
62
|
+
parseFloat(getComputedStyle(el).opacity)
|
|
63
|
+
)
|
|
64
|
+
const finalTransform = await box.evaluate((el) => getComputedStyle(el).transform)
|
|
65
|
+
const finalBgColor = await box.evaluate((el) => getComputedStyle(el).backgroundColor)
|
|
66
|
+
|
|
67
|
+
// final values should be: opacity=1, scale=1, translateY=0, backgroundColor=green
|
|
68
|
+
expect(finalOpacity).toBeCloseTo(1, 1)
|
|
69
|
+
|
|
70
|
+
// transform should be identity or close to it (scale=1, translateY=0)
|
|
71
|
+
// matrix(1, 0, 0, 1, 0, 0) or 'none'
|
|
72
|
+
if (finalTransform !== 'none') {
|
|
73
|
+
expect(finalTransform).toMatch(/matrix\(1,?\s*0,?\s*0,?\s*1,?\s*0,?\s*0\)/)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// backgroundColor should be green
|
|
77
|
+
expect(finalBgColor).toBe('rgb(0, 255, 0)')
|
|
78
|
+
|
|
79
|
+
// the mid-animation value should show progress (not jumped instantly)
|
|
80
|
+
// if animation is working, mid should be between 0 and 1
|
|
81
|
+
console.log(
|
|
82
|
+
`Animation progress: initial=${initialOpacity}, mid=${midOpacity}, final=${finalOpacity}`
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
// key test: animation should have progressed, not jumped
|
|
86
|
+
const animationProgressed = midOpacity > 0.05 && midOpacity < 0.95
|
|
87
|
+
expect(
|
|
88
|
+
animationProgressed || finalOpacity === 1,
|
|
89
|
+
`Animation should progress smoothly. mid=${midOpacity}`
|
|
90
|
+
).toBe(true)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
test('animate out returns to initial values', async ({ page }) => {
|
|
94
|
+
const box = page.getByTestId('animated-box')
|
|
95
|
+
const animateIn = page.getByTestId('animate-in-trigger')
|
|
96
|
+
const animateOut = page.getByTestId('animate-out-trigger')
|
|
97
|
+
|
|
98
|
+
// first animate in
|
|
99
|
+
await animateIn.click()
|
|
100
|
+
await page.waitForTimeout(400)
|
|
101
|
+
|
|
102
|
+
// verify we're at end state
|
|
103
|
+
let opacity = await box.evaluate((el) => parseFloat(getComputedStyle(el).opacity))
|
|
104
|
+
expect(opacity).toBeCloseTo(1, 1)
|
|
105
|
+
|
|
106
|
+
// now animate out
|
|
107
|
+
await animateOut.click()
|
|
108
|
+
await page.waitForTimeout(400)
|
|
109
|
+
|
|
110
|
+
// should be back to initial
|
|
111
|
+
opacity = await box.evaluate((el) => parseFloat(getComputedStyle(el).opacity))
|
|
112
|
+
const transform = await box.evaluate((el) => getComputedStyle(el).transform)
|
|
113
|
+
const bgColor = await box.evaluate((el) => getComputedStyle(el).backgroundColor)
|
|
114
|
+
|
|
115
|
+
expect(opacity).toBeCloseTo(0, 1)
|
|
116
|
+
expect(transform).toContain('0.5') // scale back to 0.5
|
|
117
|
+
expect(transform).toContain('50') // translateY back to 50
|
|
118
|
+
expect(bgColor).toBe('rgb(255, 0, 0)') // back to red
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
test('interpolated color animates correctly', async ({ page }) => {
|
|
122
|
+
const box = page.getByTestId('animated-box')
|
|
123
|
+
const trigger = page.getByTestId('animate-in-trigger')
|
|
124
|
+
|
|
125
|
+
// initial color is red
|
|
126
|
+
let bgColor = await box.evaluate((el) => getComputedStyle(el).backgroundColor)
|
|
127
|
+
expect(bgColor).toBe('rgb(255, 0, 0)')
|
|
128
|
+
|
|
129
|
+
// animate
|
|
130
|
+
await trigger.click()
|
|
131
|
+
|
|
132
|
+
// capture mid-animation color
|
|
133
|
+
await page.waitForTimeout(150)
|
|
134
|
+
const midColor = await box.evaluate((el) => getComputedStyle(el).backgroundColor)
|
|
135
|
+
|
|
136
|
+
// wait for completion
|
|
137
|
+
await page.waitForTimeout(300)
|
|
138
|
+
bgColor = await box.evaluate((el) => getComputedStyle(el).backgroundColor)
|
|
139
|
+
|
|
140
|
+
// final should be green
|
|
141
|
+
expect(bgColor).toBe('rgb(0, 255, 0)')
|
|
142
|
+
|
|
143
|
+
// mid color should be somewhere between red and green
|
|
144
|
+
// (not exactly red and not exactly green if interpolation works)
|
|
145
|
+
console.log(`Color interpolation: mid=${midColor}, final=${bgColor}`)
|
|
146
|
+
})
|
|
147
|
+
})
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { expect, test, type Page } from '@playwright/test'
|
|
2
|
+
import { setupPage } from './test-utils'
|
|
3
|
+
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await setupPage(page, { name: 'RemoveScrollCase', type: 'useCase' })
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* helper: scroll, open select, wait for viewport
|
|
10
|
+
*/
|
|
11
|
+
async function scrollAndOpenSelect(page: Page, scrollY: number) {
|
|
12
|
+
if (scrollY > 0) {
|
|
13
|
+
await page.evaluate((y) => window.scrollTo(0, y), scrollY)
|
|
14
|
+
await page.waitForTimeout(100)
|
|
15
|
+
const actual = await page.evaluate(() => window.scrollY)
|
|
16
|
+
expect(actual).toBeGreaterThanOrEqual(scrollY - 2)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const trigger = page.getByTestId('rs-select-trigger')
|
|
20
|
+
await trigger.scrollIntoViewIfNeeded()
|
|
21
|
+
await trigger.click()
|
|
22
|
+
|
|
23
|
+
const viewport = page.getByTestId('rs-select-viewport')
|
|
24
|
+
await expect(viewport).toBeVisible({ timeout: 5000 })
|
|
25
|
+
await page.waitForTimeout(200)
|
|
26
|
+
|
|
27
|
+
return viewport
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// --- positive: scroll position IS restored ---
|
|
31
|
+
|
|
32
|
+
test.describe('scroll position restored after close', () => {
|
|
33
|
+
test('preserved when closing by selecting an item', async ({ page }) => {
|
|
34
|
+
await scrollAndOpenSelect(page, 500)
|
|
35
|
+
const preClose = await page.evaluate(() => window.scrollY)
|
|
36
|
+
|
|
37
|
+
const item = page.getByTestId('rs-select-apple')
|
|
38
|
+
await item.click()
|
|
39
|
+
await page.waitForTimeout(300)
|
|
40
|
+
|
|
41
|
+
const viewport = page.getByTestId('rs-select-viewport')
|
|
42
|
+
await expect(viewport).not.toBeVisible()
|
|
43
|
+
|
|
44
|
+
const postClose = await page.evaluate(() => window.scrollY)
|
|
45
|
+
expect(Math.abs(postClose - preClose)).toBeLessThanOrEqual(2)
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('preserved when closing by pressing Escape', async ({ page }) => {
|
|
49
|
+
await scrollAndOpenSelect(page, 500)
|
|
50
|
+
const preClose = await page.evaluate(() => window.scrollY)
|
|
51
|
+
|
|
52
|
+
await page.keyboard.press('Escape')
|
|
53
|
+
await page.waitForTimeout(300)
|
|
54
|
+
|
|
55
|
+
const viewport = page.getByTestId('rs-select-viewport')
|
|
56
|
+
await expect(viewport).not.toBeVisible()
|
|
57
|
+
|
|
58
|
+
const postClose = await page.evaluate(() => window.scrollY)
|
|
59
|
+
expect(Math.abs(postClose - preClose)).toBeLessThanOrEqual(2)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('preserved when closing by clicking outside', async ({ page }) => {
|
|
63
|
+
await scrollAndOpenSelect(page, 500)
|
|
64
|
+
const preClose = await page.evaluate(() => window.scrollY)
|
|
65
|
+
|
|
66
|
+
// click far from the select content to dismiss
|
|
67
|
+
await page.mouse.click(10, 10)
|
|
68
|
+
await page.waitForTimeout(300)
|
|
69
|
+
|
|
70
|
+
const viewport = page.getByTestId('rs-select-viewport')
|
|
71
|
+
await expect(viewport).not.toBeVisible({ timeout: 5000 })
|
|
72
|
+
|
|
73
|
+
const postClose = await page.evaluate(() => window.scrollY)
|
|
74
|
+
expect(Math.abs(postClose - preClose)).toBeLessThanOrEqual(2)
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
// --- negative: things that should NOT happen ---
|
|
79
|
+
|
|
80
|
+
test.describe('scroll lock prevents body scroll while open', () => {
|
|
81
|
+
test('overflow:hidden applied to html while Select is open', async ({ page }) => {
|
|
82
|
+
await scrollAndOpenSelect(page, 300)
|
|
83
|
+
|
|
84
|
+
const htmlOverflow = await page.evaluate(
|
|
85
|
+
() => getComputedStyle(document.documentElement).overflow
|
|
86
|
+
)
|
|
87
|
+
expect(htmlOverflow).toBe('hidden')
|
|
88
|
+
|
|
89
|
+
// close and verify released
|
|
90
|
+
await page.keyboard.press('Escape')
|
|
91
|
+
await page.waitForTimeout(300)
|
|
92
|
+
|
|
93
|
+
const afterOverflow = await page.evaluate(
|
|
94
|
+
() => getComputedStyle(document.documentElement).overflow
|
|
95
|
+
)
|
|
96
|
+
expect(afterOverflow).not.toBe('hidden')
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
test.describe('edge cases', () => {
|
|
101
|
+
test('no scroll jump when scrollY is 0', async ({ page }) => {
|
|
102
|
+
// already at top
|
|
103
|
+
await scrollAndOpenSelect(page, 0)
|
|
104
|
+
|
|
105
|
+
const item = page.getByTestId('rs-select-banana')
|
|
106
|
+
await item.click()
|
|
107
|
+
await page.waitForTimeout(300)
|
|
108
|
+
|
|
109
|
+
const postClose = await page.evaluate(() => window.scrollY)
|
|
110
|
+
// should still be at 0, no negative jump or weird offset
|
|
111
|
+
expect(postClose).toBe(0)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
test('scroll position stable across multiple open/close cycles', async ({ page }) => {
|
|
115
|
+
await page.evaluate(() => window.scrollTo(0, 400))
|
|
116
|
+
await page.waitForTimeout(100)
|
|
117
|
+
|
|
118
|
+
for (let i = 0; i < 3; i++) {
|
|
119
|
+
const trigger = page.getByTestId('rs-select-trigger')
|
|
120
|
+
await trigger.scrollIntoViewIfNeeded()
|
|
121
|
+
await trigger.click()
|
|
122
|
+
|
|
123
|
+
const viewport = page.getByTestId('rs-select-viewport')
|
|
124
|
+
await expect(viewport).toBeVisible({ timeout: 5000 })
|
|
125
|
+
await page.waitForTimeout(200)
|
|
126
|
+
|
|
127
|
+
await page.keyboard.press('Escape')
|
|
128
|
+
await page.waitForTimeout(300)
|
|
129
|
+
await expect(viewport).not.toBeVisible()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const finalScroll = await page.evaluate(() => window.scrollY)
|
|
133
|
+
expect(Math.abs(finalScroll - 400)).toBeLessThanOrEqual(2)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
test('selecting different items preserves scroll each time', async ({ page }) => {
|
|
137
|
+
const items = ['rs-select-apple', 'rs-select-banana', 'rs-select-orange']
|
|
138
|
+
|
|
139
|
+
for (const itemId of items) {
|
|
140
|
+
// re-scroll to target before each iteration
|
|
141
|
+
await page.evaluate(() => window.scrollTo(0, 600))
|
|
142
|
+
await page.waitForTimeout(200)
|
|
143
|
+
|
|
144
|
+
const trigger = page.getByTestId('rs-select-trigger')
|
|
145
|
+
// click trigger directly without scrollIntoViewIfNeeded
|
|
146
|
+
await trigger.click()
|
|
147
|
+
|
|
148
|
+
const viewport = page.getByTestId('rs-select-viewport')
|
|
149
|
+
await expect(viewport).toBeVisible({ timeout: 5000 })
|
|
150
|
+
await page.waitForTimeout(200)
|
|
151
|
+
|
|
152
|
+
// capture scroll position while select is open (scroll is locked here)
|
|
153
|
+
const whileOpen = await page.evaluate(() => window.scrollY)
|
|
154
|
+
|
|
155
|
+
const item = page.getByTestId(itemId)
|
|
156
|
+
await item.click()
|
|
157
|
+
await page.waitForTimeout(500)
|
|
158
|
+
await expect(viewport).not.toBeVisible()
|
|
159
|
+
|
|
160
|
+
const afterClose = await page.evaluate(() => window.scrollY)
|
|
161
|
+
// scroll should be restored to where it was when the select opened
|
|
162
|
+
expect(Math.abs(afterClose - whileOpen)).toBeLessThanOrEqual(2)
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
// --- mobile/touch device tests (chrome mobile emulation) ---
|
|
168
|
+
|
|
169
|
+
test.describe('mobile touch device', () => {
|
|
170
|
+
test.use({
|
|
171
|
+
viewport: { width: 390, height: 844 },
|
|
172
|
+
hasTouch: true,
|
|
173
|
+
isMobile: true,
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
test('scroll position restored after selecting item on mobile', async ({ page }) => {
|
|
177
|
+
await page.evaluate(() => window.scrollTo(0, 400))
|
|
178
|
+
await page.waitForTimeout(100)
|
|
179
|
+
|
|
180
|
+
const trigger = page.getByTestId('rs-select-trigger')
|
|
181
|
+
await trigger.scrollIntoViewIfNeeded()
|
|
182
|
+
const preOpen = await page.evaluate(() => window.scrollY)
|
|
183
|
+
await trigger.click()
|
|
184
|
+
|
|
185
|
+
const viewport = page.getByTestId('rs-select-viewport')
|
|
186
|
+
await expect(viewport).toBeVisible({ timeout: 5000 })
|
|
187
|
+
await page.waitForTimeout(200)
|
|
188
|
+
|
|
189
|
+
const item = page.getByTestId('rs-select-apple')
|
|
190
|
+
await item.click()
|
|
191
|
+
await page.waitForTimeout(300)
|
|
192
|
+
await expect(viewport).not.toBeVisible()
|
|
193
|
+
|
|
194
|
+
const postClose = await page.evaluate(() => window.scrollY)
|
|
195
|
+
expect(Math.abs(postClose - preOpen)).toBeLessThanOrEqual(2)
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
test('scroll lock active on mobile while Select open', async ({ page }) => {
|
|
199
|
+
await page.evaluate(() => window.scrollTo(0, 300))
|
|
200
|
+
await page.waitForTimeout(100)
|
|
201
|
+
|
|
202
|
+
const trigger = page.getByTestId('rs-select-trigger')
|
|
203
|
+
await trigger.scrollIntoViewIfNeeded()
|
|
204
|
+
await trigger.click()
|
|
205
|
+
|
|
206
|
+
const viewport = page.getByTestId('rs-select-viewport')
|
|
207
|
+
await expect(viewport).toBeVisible({ timeout: 5000 })
|
|
208
|
+
await page.waitForTimeout(200)
|
|
209
|
+
|
|
210
|
+
const htmlOverflow = await page.evaluate(
|
|
211
|
+
() => getComputedStyle(document.documentElement).overflow
|
|
212
|
+
)
|
|
213
|
+
expect(htmlOverflow).toBe('hidden')
|
|
214
|
+
|
|
215
|
+
await page.keyboard.press('Escape')
|
|
216
|
+
await page.waitForTimeout(300)
|
|
217
|
+
|
|
218
|
+
const afterOverflow = await page.evaluate(
|
|
219
|
+
() => getComputedStyle(document.documentElement).overflow
|
|
220
|
+
)
|
|
221
|
+
expect(afterOverflow).not.toBe('hidden')
|
|
222
|
+
})
|
|
223
|
+
})
|