@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,543 @@
|
|
|
1
|
+
import { expect, test, type Page } from '@playwright/test'
|
|
2
|
+
import { setupPage } from './test-utils'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ANIMATION BEHAVIOR TESTS
|
|
6
|
+
*
|
|
7
|
+
* Tests animation behavior across all configured drivers.
|
|
8
|
+
* Driver is determined by the playwright project (css, native, reanimated, motion).
|
|
9
|
+
* All tests verify start, intermediate, and end states.
|
|
10
|
+
* Uses scenario-36 (1000ms timing) for reliable intermediate capture.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const TOLERANCE = 0.05
|
|
14
|
+
|
|
15
|
+
async function getOpacity(page: Page, testId: string): Promise<number> {
|
|
16
|
+
return page.evaluate((id) => {
|
|
17
|
+
const el = document.querySelector(`[data-testid="${id}"]`)
|
|
18
|
+
if (!el) return -1
|
|
19
|
+
return Number.parseFloat(getComputedStyle(el).opacity)
|
|
20
|
+
}, testId)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function getScale(page: Page, testId: string): Promise<number> {
|
|
24
|
+
return page.evaluate((id) => {
|
|
25
|
+
const el = document.querySelector(`[data-testid="${id}"]`)
|
|
26
|
+
if (!el) return -1
|
|
27
|
+
const transform = getComputedStyle(el).transform
|
|
28
|
+
if (transform === 'none') return 1
|
|
29
|
+
const match = transform.match(/matrix\(([^,]+),/)
|
|
30
|
+
return match ? Number.parseFloat(match[1]) : 1
|
|
31
|
+
}, testId)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function getTranslateX(page: Page, testId: string): Promise<number> {
|
|
35
|
+
return page.evaluate((id) => {
|
|
36
|
+
const el = document.querySelector(`[data-testid="${id}"]`)
|
|
37
|
+
if (!el) return -1
|
|
38
|
+
const transform = getComputedStyle(el).transform
|
|
39
|
+
if (transform === 'none') return 0
|
|
40
|
+
const match = transform.match(/matrix\([^,]+,[^,]+,[^,]+,[^,]+,([^,]+),/)
|
|
41
|
+
return match ? Number.parseFloat(match[1]) : 0
|
|
42
|
+
}, testId)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function elementExists(page: Page, testId: string): Promise<boolean> {
|
|
46
|
+
return page.evaluate((id) => !!document.querySelector(`[data-testid="${id}"]`), testId)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function isIntermediate(
|
|
50
|
+
value: number,
|
|
51
|
+
start: number,
|
|
52
|
+
end: number,
|
|
53
|
+
tolerance = TOLERANCE
|
|
54
|
+
): boolean {
|
|
55
|
+
const notAtStart = Math.abs(value - start) > tolerance
|
|
56
|
+
const notAtEnd = Math.abs(value - end) > tolerance
|
|
57
|
+
const min = Math.min(start, end)
|
|
58
|
+
const max = Math.max(start, end)
|
|
59
|
+
const inRange = value >= min - tolerance && value <= max + tolerance
|
|
60
|
+
return notAtStart && notAtEnd && inRange
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
test.describe('Animation Behavior', () => {
|
|
64
|
+
test.beforeEach(async ({ page }) => {
|
|
65
|
+
// Skip native driver - it has issues with data-testid attributes on web
|
|
66
|
+
const driver = (test.info().project?.metadata as any)?.animationDriver
|
|
67
|
+
test.skip(driver === 'native', 'native driver has element detection issues on web')
|
|
68
|
+
|
|
69
|
+
await setupPage(page, {
|
|
70
|
+
name: 'AnimationComprehensiveCase',
|
|
71
|
+
type: 'useCase',
|
|
72
|
+
})
|
|
73
|
+
// CI can be slow - allow more time for initial render
|
|
74
|
+
await page.waitForTimeout(1000)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test('timing animation has start, intermediate, and end states', async ({ page }) => {
|
|
78
|
+
const START = 1,
|
|
79
|
+
END = 0.2
|
|
80
|
+
|
|
81
|
+
const startOpacity = await getOpacity(page, 'scenario-36-target')
|
|
82
|
+
expect(startOpacity, 'Start').toBeCloseTo(START, 1)
|
|
83
|
+
|
|
84
|
+
// poll via rAF for reliable intermediate capture across CI environments
|
|
85
|
+
const samples: number[] = await page.evaluate(() => {
|
|
86
|
+
return new Promise<number[]>((resolve) => {
|
|
87
|
+
const el = document.querySelector('[data-testid="scenario-36-target"]')!
|
|
88
|
+
const vals: number[] = []
|
|
89
|
+
const start = performance.now()
|
|
90
|
+
function tick() {
|
|
91
|
+
vals.push(Number(getComputedStyle(el).opacity))
|
|
92
|
+
if (performance.now() - start < 800) requestAnimationFrame(tick)
|
|
93
|
+
else resolve(vals)
|
|
94
|
+
}
|
|
95
|
+
;(
|
|
96
|
+
document.querySelector('[data-testid="scenario-36-trigger"]') as HTMLElement
|
|
97
|
+
).click()
|
|
98
|
+
requestAnimationFrame(tick)
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
const endOpacity = samples[samples.length - 1]
|
|
103
|
+
expect(endOpacity, 'End').toBeCloseTo(END, 1)
|
|
104
|
+
|
|
105
|
+
// verify real interpolation: multiple frames between start and end
|
|
106
|
+
const intermediates = samples.filter(
|
|
107
|
+
(v) => Math.abs(v - START) > TOLERANCE && Math.abs(v - END) > TOLERANCE
|
|
108
|
+
)
|
|
109
|
+
expect(
|
|
110
|
+
intermediates.length,
|
|
111
|
+
`Should have multiple intermediate opacity frames (got ${intermediates.length})`
|
|
112
|
+
).toBeGreaterThanOrEqual(2)
|
|
113
|
+
|
|
114
|
+
// verify animation doesn't complete instantly
|
|
115
|
+
const earlyEnd = samples.slice(0, 3).every((v) => Math.abs(v - END) < TOLERANCE)
|
|
116
|
+
expect(earlyEnd, 'Opacity animation should not complete in first 3 frames').toBe(
|
|
117
|
+
false
|
|
118
|
+
)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
test('scale timing animation has intermediate values', async ({ page }) => {
|
|
122
|
+
const START = 1,
|
|
123
|
+
END = 1.5
|
|
124
|
+
|
|
125
|
+
const startScale = await getScale(page, 'scenario-36-target')
|
|
126
|
+
expect(startScale, 'Start').toBeCloseTo(START, 1)
|
|
127
|
+
|
|
128
|
+
// poll via rAF for reliable intermediate capture across CI environments
|
|
129
|
+
const samples: number[] = await page.evaluate(() => {
|
|
130
|
+
return new Promise<number[]>((resolve) => {
|
|
131
|
+
const el = document.querySelector('[data-testid="scenario-36-target"]')!
|
|
132
|
+
const vals: number[] = []
|
|
133
|
+
const start = performance.now()
|
|
134
|
+
function tick() {
|
|
135
|
+
const t = getComputedStyle(el).transform
|
|
136
|
+
const m = t.match(/matrix\(([^,]+),/)
|
|
137
|
+
vals.push(m ? Number.parseFloat(m[1]) : 1)
|
|
138
|
+
if (performance.now() - start < 800) requestAnimationFrame(tick)
|
|
139
|
+
else resolve(vals)
|
|
140
|
+
}
|
|
141
|
+
;(
|
|
142
|
+
document.querySelector('[data-testid="scenario-36-trigger"]') as HTMLElement
|
|
143
|
+
).click()
|
|
144
|
+
requestAnimationFrame(tick)
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
const endScale = samples[samples.length - 1]
|
|
149
|
+
expect(endScale, 'End').toBeCloseTo(END, 1)
|
|
150
|
+
|
|
151
|
+
// verify real interpolation: multiple frames between start and end
|
|
152
|
+
const intermediates = samples.filter(
|
|
153
|
+
(v) => Math.abs(v - START) > TOLERANCE && Math.abs(v - END) > TOLERANCE
|
|
154
|
+
)
|
|
155
|
+
expect(
|
|
156
|
+
intermediates.length,
|
|
157
|
+
`Should have multiple intermediate scale frames (got ${intermediates.length})`
|
|
158
|
+
).toBeGreaterThanOrEqual(2)
|
|
159
|
+
|
|
160
|
+
// verify animation doesn't complete instantly
|
|
161
|
+
const earlyEnd = samples.slice(0, 3).every((v) => Math.abs(v - END) < TOLERANCE)
|
|
162
|
+
expect(earlyEnd, 'Scale animation should not complete in first 3 frames').toBe(false)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
test('animation with delay completes correctly', async ({ page }) => {
|
|
166
|
+
const START = 1,
|
|
167
|
+
END = 0.3
|
|
168
|
+
|
|
169
|
+
const startOpacity = await getOpacity(page, 'scenario-20-target')
|
|
170
|
+
expect(startOpacity, 'Start').toBeCloseTo(START, 1)
|
|
171
|
+
|
|
172
|
+
await page.getByTestId('scenario-20-trigger').click()
|
|
173
|
+
await page.waitForTimeout(2500)
|
|
174
|
+
const endOpacity = await getOpacity(page, 'scenario-20-target')
|
|
175
|
+
|
|
176
|
+
expect(endOpacity, 'End').toBeCloseTo(END, 1)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
test('multi-property animation completes correctly', async ({ page }) => {
|
|
180
|
+
const OPACITY_END = 0.5,
|
|
181
|
+
SCALE_END = 1.3
|
|
182
|
+
|
|
183
|
+
await page.getByTestId('scenario-28-trigger').click()
|
|
184
|
+
await page.waitForTimeout(3000)
|
|
185
|
+
|
|
186
|
+
const endOpacity = await getOpacity(page, 'scenario-28-target')
|
|
187
|
+
const endScale = await getScale(page, 'scenario-28-target')
|
|
188
|
+
|
|
189
|
+
expect(endOpacity, 'End opacity').toBeCloseTo(OPACITY_END, 0)
|
|
190
|
+
expect(endScale, 'End scale').toBeCloseTo(SCALE_END, 0)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test('per-property configs complete correctly', async ({ page }) => {
|
|
194
|
+
const OPACITY_END = 0.3,
|
|
195
|
+
SCALE_END = 1.5
|
|
196
|
+
|
|
197
|
+
await page.getByTestId('scenario-31-trigger').click()
|
|
198
|
+
await page.waitForTimeout(3000)
|
|
199
|
+
|
|
200
|
+
const endOpacity = await getOpacity(page, 'scenario-31-target')
|
|
201
|
+
const endScale = await getScale(page, 'scenario-31-target')
|
|
202
|
+
|
|
203
|
+
expect(endOpacity, 'End opacity').toBeCloseTo(OPACITY_END, 0)
|
|
204
|
+
expect(endScale, 'End scale').toBeCloseTo(SCALE_END, 0)
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
test('enterStyle animates on mount', async ({ page }) => {
|
|
208
|
+
const trigger = page.getByTestId('scenario-21-trigger')
|
|
209
|
+
await trigger.click() // Hide
|
|
210
|
+
await page.waitForTimeout(1000)
|
|
211
|
+
|
|
212
|
+
expect(await elementExists(page, 'scenario-21-target'), 'Hidden').toBe(false)
|
|
213
|
+
|
|
214
|
+
await trigger.click() // Show
|
|
215
|
+
await page.waitForTimeout(2000)
|
|
216
|
+
|
|
217
|
+
expect(await elementExists(page, 'scenario-21-target'), 'Shown').toBe(true)
|
|
218
|
+
expect(await getOpacity(page, 'scenario-21-target'), 'End opacity').toBeCloseTo(1, 0)
|
|
219
|
+
expect(await getScale(page, 'scenario-21-target'), 'End scale').toBeCloseTo(1, 0)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
test('exitStyle has intermediate values during exit animation', async ({
|
|
223
|
+
page,
|
|
224
|
+
}, testInfo) => {
|
|
225
|
+
const driver = (testInfo.project?.metadata as any)?.animationDriver
|
|
226
|
+
const START_OPACITY = 1,
|
|
227
|
+
END_OPACITY = 0
|
|
228
|
+
|
|
229
|
+
// Element should be visible initially
|
|
230
|
+
expect(await elementExists(page, 'scenario-22-target'), 'Initially visible').toBe(
|
|
231
|
+
true
|
|
232
|
+
)
|
|
233
|
+
expect(await getOpacity(page, 'scenario-22-target'), 'Start opacity').toBeCloseTo(
|
|
234
|
+
START_OPACITY,
|
|
235
|
+
1
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
// Click to trigger exit animation
|
|
239
|
+
await page.getByTestId('scenario-22-trigger').click()
|
|
240
|
+
|
|
241
|
+
// CSS bouncy is 200ms, spring bouncy takes longer
|
|
242
|
+
// for CSS, check at 100ms; for spring, check at 150ms
|
|
243
|
+
const checkTime = driver === 'css' ? 100 : 150
|
|
244
|
+
await page.waitForTimeout(checkTime)
|
|
245
|
+
|
|
246
|
+
const exists = await elementExists(page, 'scenario-22-target')
|
|
247
|
+
if (exists) {
|
|
248
|
+
const midOpacity = await getOpacity(page, 'scenario-22-target')
|
|
249
|
+
// Mid values should be intermediate (not at start, not at end)
|
|
250
|
+
expect(
|
|
251
|
+
isIntermediate(midOpacity, START_OPACITY, END_OPACITY) ||
|
|
252
|
+
midOpacity < START_OPACITY,
|
|
253
|
+
`Mid opacity (${midOpacity.toFixed(2)}) should be animating`
|
|
254
|
+
).toBe(true)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Wait for animation to complete (spring animations can be slow)
|
|
258
|
+
await page.waitForTimeout(2500)
|
|
259
|
+
|
|
260
|
+
// Element should be gone after exit animation completes
|
|
261
|
+
expect(await elementExists(page, 'scenario-22-target'), 'Hidden after exit').toBe(
|
|
262
|
+
false
|
|
263
|
+
)
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
test('interruption redirects to new target', async ({ page }) => {
|
|
267
|
+
const START = 0,
|
|
268
|
+
FINAL = 100
|
|
269
|
+
|
|
270
|
+
expect(await getTranslateX(page, 'scenario-25-target'), 'Start').toBeCloseTo(START, 0)
|
|
271
|
+
|
|
272
|
+
await page.getByTestId('scenario-25-trigger').click()
|
|
273
|
+
await page.waitForTimeout(3000)
|
|
274
|
+
|
|
275
|
+
expect(await getTranslateX(page, 'scenario-25-target'), 'End').toBeCloseTo(FINAL, 0)
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
test('complex multi-property completes correctly', async ({ page }) => {
|
|
279
|
+
const OPACITY_END = 0.7,
|
|
280
|
+
SCALE_END = 1.2
|
|
281
|
+
|
|
282
|
+
await page.getByTestId('scenario-34-trigger').click()
|
|
283
|
+
await page.waitForTimeout(4000)
|
|
284
|
+
|
|
285
|
+
const endOpacity = await getOpacity(page, 'scenario-34-target')
|
|
286
|
+
const endScale = await getScale(page, 'scenario-34-target')
|
|
287
|
+
|
|
288
|
+
expect(endOpacity, 'End opacity').toBeCloseTo(OPACITY_END, 0)
|
|
289
|
+
expect(endScale, 'End scale').toBeCloseTo(SCALE_END, 0)
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
test('enterStyle with scaleX animates from 0 to 1', async ({ page }) => {
|
|
293
|
+
const END_SCALE_X = 1
|
|
294
|
+
const END_OPACITY = 1
|
|
295
|
+
|
|
296
|
+
// Element should not exist initially
|
|
297
|
+
expect(await elementExists(page, 'scenario-37-target'), 'Initially hidden').toBe(
|
|
298
|
+
false
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
// Click to show element
|
|
302
|
+
await page.getByTestId('scenario-37-trigger').click()
|
|
303
|
+
|
|
304
|
+
// Wait a moment for the element to appear and start animating
|
|
305
|
+
await page.waitForTimeout(100)
|
|
306
|
+
|
|
307
|
+
// Element should exist now
|
|
308
|
+
expect(
|
|
309
|
+
await elementExists(page, 'scenario-37-target'),
|
|
310
|
+
'Should exist after click'
|
|
311
|
+
).toBe(true)
|
|
312
|
+
|
|
313
|
+
// Get scaleX value (first value in matrix transform)
|
|
314
|
+
const getScaleX = async () => {
|
|
315
|
+
return page.evaluate(() => {
|
|
316
|
+
const el = document.querySelector('[data-testid="scenario-37-target"]')
|
|
317
|
+
if (!el) return -1
|
|
318
|
+
const transform = getComputedStyle(el).transform
|
|
319
|
+
if (transform === 'none') return 1
|
|
320
|
+
// matrix(a, b, c, d, tx, ty) - scaleX is in the 'a' position
|
|
321
|
+
const match = transform.match(/matrix\(([^,]+),/)
|
|
322
|
+
return match ? Number.parseFloat(match[1]) : 1
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Wait for animation to complete (lazy animation takes a while)
|
|
327
|
+
await page.waitForTimeout(2000)
|
|
328
|
+
|
|
329
|
+
const endScaleX = await getScaleX()
|
|
330
|
+
const endOpacity = await getOpacity(page, 'scenario-37-target')
|
|
331
|
+
|
|
332
|
+
expect(endScaleX, 'End scaleX').toBeCloseTo(END_SCALE_X, 1)
|
|
333
|
+
expect(endOpacity, 'End opacity').toBeCloseTo(END_OPACITY, 1)
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
test('per-property config with transform: unlisted properties still animate', async ({
|
|
337
|
+
page,
|
|
338
|
+
}) => {
|
|
339
|
+
// this tests the "animationClamped" pattern fix
|
|
340
|
+
// transition={['quick', { opacity: '200ms', backgroundColor: '200ms' }]}
|
|
341
|
+
// scale and y are NOT in the per-property config but should still animate
|
|
342
|
+
const OPACITY_END = 0.5
|
|
343
|
+
const SCALE_END = 1.3
|
|
344
|
+
|
|
345
|
+
// scroll to the element first (it's at the bottom of the page)
|
|
346
|
+
await page.getByTestId('scenario-38-trigger').scrollIntoViewIfNeeded()
|
|
347
|
+
|
|
348
|
+
// initial state
|
|
349
|
+
const initialOpacity = await getOpacity(page, 'scenario-38-target')
|
|
350
|
+
const initialScale = await getScale(page, 'scenario-38-target')
|
|
351
|
+
expect(initialOpacity, 'Initial opacity').toBeCloseTo(1, 1)
|
|
352
|
+
expect(initialScale, 'Initial scale').toBeCloseTo(1, 1)
|
|
353
|
+
|
|
354
|
+
// trigger animation
|
|
355
|
+
await page.getByTestId('scenario-38-trigger').click()
|
|
356
|
+
await page.waitForTimeout(1500)
|
|
357
|
+
|
|
358
|
+
// both should reach end state - the key test is that scale animates
|
|
359
|
+
// even though it wasn't listed in the per-property config
|
|
360
|
+
const endOpacity = await getOpacity(page, 'scenario-38-target')
|
|
361
|
+
const endScale = await getScale(page, 'scenario-38-target')
|
|
362
|
+
|
|
363
|
+
expect(endOpacity, 'End opacity').toBeCloseTo(OPACITY_END, 1)
|
|
364
|
+
expect(endScale, 'End scale').toBeCloseTo(SCALE_END, 1)
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
test('object format per-property config: unlisted properties still animate', async ({
|
|
368
|
+
page,
|
|
369
|
+
}) => {
|
|
370
|
+
// same as above but using object format: { opacity: '200ms', default: 'quick' }
|
|
371
|
+
const OPACITY_END = 0.5
|
|
372
|
+
const SCALE_END = 1.3
|
|
373
|
+
|
|
374
|
+
const initialScale = await getScale(page, 'scenario-39-target')
|
|
375
|
+
expect(initialScale, 'Initial scale').toBeCloseTo(1, 1)
|
|
376
|
+
|
|
377
|
+
await page.getByTestId('scenario-39-trigger').click()
|
|
378
|
+
await page.waitForTimeout(2500)
|
|
379
|
+
|
|
380
|
+
const endOpacity = await getOpacity(page, 'scenario-39-target')
|
|
381
|
+
const endScale = await getScale(page, 'scenario-39-target')
|
|
382
|
+
|
|
383
|
+
expect(endOpacity, 'End opacity').toBeCloseTo(OPACITY_END, 1)
|
|
384
|
+
expect(endScale, 'End scale').toBeCloseTo(SCALE_END, 1)
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
test('object format WITHOUT default: only specified properties animate', async ({
|
|
388
|
+
page,
|
|
389
|
+
}, testInfo) => {
|
|
390
|
+
// this test is CSS-driver specific - other drivers may handle transitions differently
|
|
391
|
+
const driver = (testInfo.project?.metadata as any)?.animationDriver
|
|
392
|
+
if (driver !== 'css') {
|
|
393
|
+
test.skip()
|
|
394
|
+
return
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// transition={{ opacity: '200ms' }} - NO default key
|
|
398
|
+
// opacity should animate, scale should snap instantly
|
|
399
|
+
const OPACITY_END = 0.5
|
|
400
|
+
const SCALE_END = 1.3
|
|
401
|
+
|
|
402
|
+
const initialScale = await getScale(page, 'scenario-40-target')
|
|
403
|
+
expect(initialScale, 'Initial scale').toBeCloseTo(1, 1)
|
|
404
|
+
|
|
405
|
+
await page.getByTestId('scenario-40-trigger').click()
|
|
406
|
+
|
|
407
|
+
// check immediately - scale should snap to end value (no transition)
|
|
408
|
+
await page.waitForTimeout(50)
|
|
409
|
+
const immediateScale = await getScale(page, 'scenario-40-target')
|
|
410
|
+
expect(immediateScale, 'Scale should snap immediately').toBeCloseTo(SCALE_END, 1)
|
|
411
|
+
|
|
412
|
+
// wait for opacity animation to complete (500ms animation + buffer)
|
|
413
|
+
await page.waitForTimeout(800)
|
|
414
|
+
const endOpacity = await getOpacity(page, 'scenario-40-target')
|
|
415
|
+
expect(endOpacity, 'Opacity should animate to end').toBeCloseTo(OPACITY_END, 1)
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
test('per-property config with delay: both delay and per-property work together', async ({
|
|
419
|
+
page,
|
|
420
|
+
}) => {
|
|
421
|
+
// transition={['quick', { delay: 300, opacity: '500ms' }]}
|
|
422
|
+
// 300ms delay, then opacity=500ms, scale=quick
|
|
423
|
+
const OPACITY_START = 1,
|
|
424
|
+
OPACITY_END = 0.5
|
|
425
|
+
const SCALE_END = 1.3
|
|
426
|
+
|
|
427
|
+
const initialOpacity = await getOpacity(page, 'scenario-41-target')
|
|
428
|
+
expect(initialOpacity, 'Initial opacity').toBeCloseTo(OPACITY_START, 1)
|
|
429
|
+
|
|
430
|
+
await page.getByTestId('scenario-41-trigger').click()
|
|
431
|
+
|
|
432
|
+
// at 150ms (before delay ends), values should still be at start
|
|
433
|
+
await page.waitForTimeout(150)
|
|
434
|
+
const duringDelay = await getOpacity(page, 'scenario-41-target')
|
|
435
|
+
expect(duringDelay, 'During delay, opacity should be near start').toBeCloseTo(
|
|
436
|
+
OPACITY_START,
|
|
437
|
+
0
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
// wait for delay + animations to complete (300ms delay + 500ms opacity + buffer)
|
|
441
|
+
await page.waitForTimeout(1000)
|
|
442
|
+
|
|
443
|
+
const endOpacity = await getOpacity(page, 'scenario-41-target')
|
|
444
|
+
const endScale = await getScale(page, 'scenario-41-target')
|
|
445
|
+
|
|
446
|
+
expect(endOpacity, 'End opacity').toBeCloseTo(OPACITY_END, 1)
|
|
447
|
+
expect(endScale, 'End scale').toBeCloseTo(SCALE_END, 1)
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
test('animateOnly with exitStyle has intermediate values during exit animation', async ({
|
|
451
|
+
page,
|
|
452
|
+
}, testInfo) => {
|
|
453
|
+
const driver = (testInfo.project?.metadata as any)?.animationDriver
|
|
454
|
+
const START_OPACITY = 1,
|
|
455
|
+
END_OPACITY = 0
|
|
456
|
+
|
|
457
|
+
// scroll to the element first
|
|
458
|
+
await page.getByTestId('scenario-48-trigger').scrollIntoViewIfNeeded()
|
|
459
|
+
await page.waitForTimeout(200)
|
|
460
|
+
|
|
461
|
+
// element should be visible initially
|
|
462
|
+
expect(await elementExists(page, 'scenario-48-target'), 'Initially visible').toBe(
|
|
463
|
+
true
|
|
464
|
+
)
|
|
465
|
+
expect(await getOpacity(page, 'scenario-48-target'), 'Start opacity').toBeCloseTo(
|
|
466
|
+
START_OPACITY,
|
|
467
|
+
1
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
// click to trigger exit animation
|
|
471
|
+
await page.getByTestId('scenario-48-trigger').click()
|
|
472
|
+
|
|
473
|
+
// 500ms animation - check at 250ms for reliable intermediate capture
|
|
474
|
+
await page.waitForTimeout(250)
|
|
475
|
+
|
|
476
|
+
const exists = await elementExists(page, 'scenario-48-target')
|
|
477
|
+
if (exists) {
|
|
478
|
+
const midOpacity = await getOpacity(page, 'scenario-48-target')
|
|
479
|
+
// mid values should be intermediate (not at start, not at end)
|
|
480
|
+
expect(
|
|
481
|
+
isIntermediate(midOpacity, START_OPACITY, END_OPACITY) ||
|
|
482
|
+
midOpacity < START_OPACITY,
|
|
483
|
+
`Mid opacity (${midOpacity.toFixed(2)}) should be animating`
|
|
484
|
+
).toBe(true)
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// wait for animation to complete
|
|
488
|
+
await page.waitForTimeout(800)
|
|
489
|
+
|
|
490
|
+
// element should be gone after exit animation completes
|
|
491
|
+
expect(await elementExists(page, 'scenario-48-target'), 'Hidden after exit').toBe(
|
|
492
|
+
false
|
|
493
|
+
)
|
|
494
|
+
})
|
|
495
|
+
|
|
496
|
+
test('animateOnly with enterStyle and exitStyle animates correctly', async ({
|
|
497
|
+
page,
|
|
498
|
+
}, testInfo) => {
|
|
499
|
+
const driver = (testInfo.project?.metadata as any)?.animationDriver
|
|
500
|
+
const END_OPACITY = 1
|
|
501
|
+
|
|
502
|
+
// scroll to the element first
|
|
503
|
+
await page.getByTestId('scenario-49-trigger').scrollIntoViewIfNeeded()
|
|
504
|
+
|
|
505
|
+
// element should be visible initially (after enterStyle animation completes)
|
|
506
|
+
expect(await elementExists(page, 'scenario-49-target'), 'Initially visible').toBe(
|
|
507
|
+
true
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
// wait for enter animation to complete if it's still running
|
|
511
|
+
await page.waitForTimeout(800)
|
|
512
|
+
|
|
513
|
+
// should be at final state (opacity: 1, scale: 1)
|
|
514
|
+
expect(
|
|
515
|
+
await getOpacity(page, 'scenario-49-target'),
|
|
516
|
+
'Opacity after enter'
|
|
517
|
+
).toBeCloseTo(END_OPACITY, 1)
|
|
518
|
+
|
|
519
|
+
// click to trigger exit animation
|
|
520
|
+
await page.getByTestId('scenario-49-trigger').click()
|
|
521
|
+
|
|
522
|
+
// check at midpoint (250ms into 500ms animation)
|
|
523
|
+
await page.waitForTimeout(250)
|
|
524
|
+
|
|
525
|
+
const exists = await elementExists(page, 'scenario-49-target')
|
|
526
|
+
if (exists) {
|
|
527
|
+
const midOpacity = await getOpacity(page, 'scenario-49-target')
|
|
528
|
+
// mid values should be animating (not at start 1, heading toward 0)
|
|
529
|
+
expect(
|
|
530
|
+
midOpacity < END_OPACITY,
|
|
531
|
+
`Mid opacity (${midOpacity.toFixed(2)}) should be animating toward 0`
|
|
532
|
+
).toBe(true)
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// wait for animation to complete
|
|
536
|
+
await page.waitForTimeout(800)
|
|
537
|
+
|
|
538
|
+
// element should be gone after exit animation completes
|
|
539
|
+
expect(await elementExists(page, 'scenario-49-target'), 'Hidden after exit').toBe(
|
|
540
|
+
false
|
|
541
|
+
)
|
|
542
|
+
})
|
|
543
|
+
})
|