@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,61 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
test.describe('ToggleGroup', () => {
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await page.goto('/?demo=ToggleGroup')
|
|
6
|
+
await page.waitForLoadState('networkidle')
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
test('single mode: clicking toggle item should toggle active state', async ({
|
|
10
|
+
page,
|
|
11
|
+
}) => {
|
|
12
|
+
await page.waitForSelector('[aria-label="Left aligned"]')
|
|
13
|
+
|
|
14
|
+
const leftButton = page.locator('[aria-label="Left aligned"]').first()
|
|
15
|
+
|
|
16
|
+
const initialState = await leftButton.getAttribute('data-state')
|
|
17
|
+
expect(initialState).toBe('off')
|
|
18
|
+
|
|
19
|
+
await leftButton.click()
|
|
20
|
+
await page.waitForTimeout(100)
|
|
21
|
+
|
|
22
|
+
const stateAfterClick = await leftButton.getAttribute('data-state')
|
|
23
|
+
expect(stateAfterClick).toBe('on')
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('single mode with disableDeactivation: cannot turn off active item', async ({
|
|
27
|
+
page,
|
|
28
|
+
}) => {
|
|
29
|
+
await page.waitForSelector('[aria-label="Left aligned"]')
|
|
30
|
+
|
|
31
|
+
const leftButton = page.locator('[aria-label="Left aligned"]').first()
|
|
32
|
+
|
|
33
|
+
await leftButton.click()
|
|
34
|
+
await page.waitForTimeout(100)
|
|
35
|
+
expect(await leftButton.getAttribute('data-state')).toBe('on')
|
|
36
|
+
|
|
37
|
+
// clicking again should not turn it off due to disableDeactivation
|
|
38
|
+
await leftButton.click()
|
|
39
|
+
await page.waitForTimeout(100)
|
|
40
|
+
expect(await leftButton.getAttribute('data-state')).toBe('on')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('single mode: clicking different item should change selection', async ({
|
|
44
|
+
page,
|
|
45
|
+
}) => {
|
|
46
|
+
await page.waitForSelector('[aria-label="Left aligned"]')
|
|
47
|
+
|
|
48
|
+
const leftButton = page.locator('[aria-label="Left aligned"]').first()
|
|
49
|
+
const centerButton = page.locator('[aria-label="Center aligned"]').first()
|
|
50
|
+
|
|
51
|
+
await leftButton.click()
|
|
52
|
+
await page.waitForTimeout(100)
|
|
53
|
+
expect(await leftButton.getAttribute('data-state')).toBe('on')
|
|
54
|
+
expect(await centerButton.getAttribute('data-state')).toBe('off')
|
|
55
|
+
|
|
56
|
+
await centerButton.click()
|
|
57
|
+
await page.waitForTimeout(100)
|
|
58
|
+
expect(await leftButton.getAttribute('data-state')).toBe('off')
|
|
59
|
+
expect(await centerButton.getAttribute('data-state')).toBe('on')
|
|
60
|
+
})
|
|
61
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
import { setupPage } from './test-utils'
|
|
4
|
+
|
|
5
|
+
test.beforeEach(async ({ page }) => {
|
|
6
|
+
await setupPage(page, { name: 'ToggleGroupActiveProps', type: 'useCase' })
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
test(`ToggleGroup.Item passes active prop to children - initially selected item`, async ({
|
|
10
|
+
page,
|
|
11
|
+
}) => {
|
|
12
|
+
// option1 is selected by default
|
|
13
|
+
const activeItem = page.locator('#custom-item-option1')
|
|
14
|
+
await expect(activeItem).toHaveAttribute('data-active', 'true')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test(`ToggleGroup.Item passes active prop to children - non-selected items`, async ({
|
|
18
|
+
page,
|
|
19
|
+
}) => {
|
|
20
|
+
// option2 and option3 are not selected
|
|
21
|
+
const item2 = page.locator('#custom-item-option2')
|
|
22
|
+
const item3 = page.locator('#custom-item-option3')
|
|
23
|
+
|
|
24
|
+
await expect(item2).toHaveAttribute('data-active', 'false')
|
|
25
|
+
await expect(item3).toHaveAttribute('data-active', 'false')
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test(`ToggleGroup.Item updates active prop when selection changes`, async ({ page }) => {
|
|
29
|
+
// Click on option2
|
|
30
|
+
await page.click('#item-2')
|
|
31
|
+
|
|
32
|
+
// option2 should now be active
|
|
33
|
+
const item1 = page.locator('#custom-item-option1')
|
|
34
|
+
const item2 = page.locator('#custom-item-option2')
|
|
35
|
+
|
|
36
|
+
await expect(item1).toHaveAttribute('data-active', 'false')
|
|
37
|
+
await expect(item2).toHaveAttribute('data-active', 'true')
|
|
38
|
+
})
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
test.describe('ToggleGroup + XGroup integration', () => {
|
|
4
|
+
test.beforeEach(async ({ page }) => {
|
|
5
|
+
await page.goto('/?test=ToggleGroupXGroupCase')
|
|
6
|
+
await page.waitForLoadState('networkidle')
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
test.describe('Pattern A: XGroup.Item wraps ToggleGroup.Item', () => {
|
|
10
|
+
test('clicking item changes toggle value', async ({ page }) => {
|
|
11
|
+
const leftButton = page.getByTestId('pattern-a-left')
|
|
12
|
+
await leftButton.waitFor({ state: 'visible' })
|
|
13
|
+
|
|
14
|
+
// initial state should be off
|
|
15
|
+
const initialState = await leftButton.getAttribute('data-state')
|
|
16
|
+
expect(initialState).toBe('off')
|
|
17
|
+
|
|
18
|
+
// click to toggle on
|
|
19
|
+
await leftButton.click()
|
|
20
|
+
await page.waitForTimeout(100)
|
|
21
|
+
|
|
22
|
+
const stateAfterClick = await leftButton.getAttribute('data-state')
|
|
23
|
+
expect(stateAfterClick).toBe('on')
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('clicking different items changes selection', async ({ page }) => {
|
|
27
|
+
const leftButton = page.getByTestId('pattern-a-left')
|
|
28
|
+
const centerButton = page.getByTestId('pattern-a-center')
|
|
29
|
+
await leftButton.waitFor({ state: 'visible' })
|
|
30
|
+
|
|
31
|
+
await leftButton.click()
|
|
32
|
+
await page.waitForTimeout(100)
|
|
33
|
+
expect(await leftButton.getAttribute('data-state')).toBe('on')
|
|
34
|
+
expect(await centerButton.getAttribute('data-state')).toBe('off')
|
|
35
|
+
|
|
36
|
+
await centerButton.click()
|
|
37
|
+
await page.waitForTimeout(100)
|
|
38
|
+
expect(await leftButton.getAttribute('data-state')).toBe('off')
|
|
39
|
+
expect(await centerButton.getAttribute('data-state')).toBe('on')
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('XGroup properly applies radius styles to items', async ({ page }) => {
|
|
43
|
+
const leftButton = page.getByTestId('pattern-a-left')
|
|
44
|
+
const centerButton = page.getByTestId('pattern-a-center')
|
|
45
|
+
const rightButton = page.getByTestId('pattern-a-right')
|
|
46
|
+
await leftButton.waitFor({ state: 'visible' })
|
|
47
|
+
|
|
48
|
+
// first item: should have left border radius, zeroed right
|
|
49
|
+
const leftStyles = await leftButton.evaluate((el) => {
|
|
50
|
+
const style = window.getComputedStyle(el)
|
|
51
|
+
return {
|
|
52
|
+
borderTopLeftRadius: style.borderTopLeftRadius,
|
|
53
|
+
borderBottomLeftRadius: style.borderBottomLeftRadius,
|
|
54
|
+
borderTopRightRadius: style.borderTopRightRadius,
|
|
55
|
+
borderBottomRightRadius: style.borderBottomRightRadius,
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
// first item should have zero right radii
|
|
59
|
+
expect(parseFloat(leftStyles.borderTopRightRadius)).toBe(0)
|
|
60
|
+
expect(parseFloat(leftStyles.borderBottomRightRadius)).toBe(0)
|
|
61
|
+
|
|
62
|
+
// center item: should have all corners zeroed
|
|
63
|
+
const centerStyles = await centerButton.evaluate((el) => {
|
|
64
|
+
const style = window.getComputedStyle(el)
|
|
65
|
+
return {
|
|
66
|
+
borderTopLeftRadius: style.borderTopLeftRadius,
|
|
67
|
+
borderBottomLeftRadius: style.borderBottomLeftRadius,
|
|
68
|
+
borderTopRightRadius: style.borderTopRightRadius,
|
|
69
|
+
borderBottomRightRadius: style.borderBottomRightRadius,
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
expect(parseFloat(centerStyles.borderTopLeftRadius)).toBe(0)
|
|
73
|
+
expect(parseFloat(centerStyles.borderBottomLeftRadius)).toBe(0)
|
|
74
|
+
expect(parseFloat(centerStyles.borderTopRightRadius)).toBe(0)
|
|
75
|
+
expect(parseFloat(centerStyles.borderBottomRightRadius)).toBe(0)
|
|
76
|
+
|
|
77
|
+
// last item: should have zero left radii
|
|
78
|
+
const rightStyles = await rightButton.evaluate((el) => {
|
|
79
|
+
const style = window.getComputedStyle(el)
|
|
80
|
+
return {
|
|
81
|
+
borderTopLeftRadius: style.borderTopLeftRadius,
|
|
82
|
+
borderBottomLeftRadius: style.borderBottomLeftRadius,
|
|
83
|
+
borderTopRightRadius: style.borderTopRightRadius,
|
|
84
|
+
borderBottomRightRadius: style.borderBottomRightRadius,
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
expect(parseFloat(rightStyles.borderTopLeftRadius)).toBe(0)
|
|
88
|
+
expect(parseFloat(rightStyles.borderBottomLeftRadius)).toBe(0)
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test.describe('Pattern B: ToggleGroup.Item asChild wraps XGroup.Item', () => {
|
|
93
|
+
test('clicking item changes toggle value', async ({ page }) => {
|
|
94
|
+
const leftButton = page.getByTestId('pattern-b-left')
|
|
95
|
+
await leftButton.waitFor({ state: 'visible' })
|
|
96
|
+
|
|
97
|
+
// click to toggle on
|
|
98
|
+
await leftButton.click()
|
|
99
|
+
await page.waitForTimeout(100)
|
|
100
|
+
|
|
101
|
+
// verify toggle group value changed via data-state or aria-pressed
|
|
102
|
+
const stateAfterClick = await leftButton.getAttribute('data-state')
|
|
103
|
+
expect(stateAfterClick).toBe('on')
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
test('clicking different items changes selection', async ({ page }) => {
|
|
107
|
+
const leftButton = page.getByTestId('pattern-b-left')
|
|
108
|
+
const centerButton = page.getByTestId('pattern-b-center')
|
|
109
|
+
await leftButton.waitFor({ state: 'visible' })
|
|
110
|
+
|
|
111
|
+
await leftButton.click()
|
|
112
|
+
await page.waitForTimeout(100)
|
|
113
|
+
expect(await leftButton.getAttribute('data-state')).toBe('on')
|
|
114
|
+
expect(await centerButton.getAttribute('data-state')).toBe('off')
|
|
115
|
+
|
|
116
|
+
await centerButton.click()
|
|
117
|
+
await page.waitForTimeout(100)
|
|
118
|
+
expect(await leftButton.getAttribute('data-state')).toBe('off')
|
|
119
|
+
expect(await centerButton.getAttribute('data-state')).toBe('on')
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
test('XGroup properly applies radius styles through asChild chain', async ({
|
|
123
|
+
page,
|
|
124
|
+
}) => {
|
|
125
|
+
const leftButton = page.getByTestId('pattern-b-left')
|
|
126
|
+
const centerButton = page.getByTestId('pattern-b-center')
|
|
127
|
+
const rightButton = page.getByTestId('pattern-b-right')
|
|
128
|
+
await leftButton.waitFor({ state: 'visible' })
|
|
129
|
+
|
|
130
|
+
// first item: should have left border radius preserved, zeroed right
|
|
131
|
+
const leftStyles = await leftButton.evaluate((el) => {
|
|
132
|
+
const style = window.getComputedStyle(el)
|
|
133
|
+
return {
|
|
134
|
+
borderTopLeftRadius: style.borderTopLeftRadius,
|
|
135
|
+
borderBottomLeftRadius: style.borderBottomLeftRadius,
|
|
136
|
+
borderTopRightRadius: style.borderTopRightRadius,
|
|
137
|
+
borderBottomRightRadius: style.borderBottomRightRadius,
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
expect(parseFloat(leftStyles.borderTopRightRadius)).toBe(0)
|
|
141
|
+
expect(parseFloat(leftStyles.borderBottomRightRadius)).toBe(0)
|
|
142
|
+
|
|
143
|
+
// center item: should have all corners zeroed
|
|
144
|
+
const centerStyles = await centerButton.evaluate((el) => {
|
|
145
|
+
const style = window.getComputedStyle(el)
|
|
146
|
+
return {
|
|
147
|
+
borderTopLeftRadius: style.borderTopLeftRadius,
|
|
148
|
+
borderBottomLeftRadius: style.borderBottomLeftRadius,
|
|
149
|
+
borderTopRightRadius: style.borderTopRightRadius,
|
|
150
|
+
borderBottomRightRadius: style.borderBottomRightRadius,
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
expect(parseFloat(centerStyles.borderTopLeftRadius)).toBe(0)
|
|
154
|
+
expect(parseFloat(centerStyles.borderBottomLeftRadius)).toBe(0)
|
|
155
|
+
expect(parseFloat(centerStyles.borderTopRightRadius)).toBe(0)
|
|
156
|
+
expect(parseFloat(centerStyles.borderBottomRightRadius)).toBe(0)
|
|
157
|
+
|
|
158
|
+
// last item: should have zero left radii
|
|
159
|
+
const rightStyles = await rightButton.evaluate((el) => {
|
|
160
|
+
const style = window.getComputedStyle(el)
|
|
161
|
+
return {
|
|
162
|
+
borderTopLeftRadius: style.borderTopLeftRadius,
|
|
163
|
+
borderBottomLeftRadius: style.borderBottomLeftRadius,
|
|
164
|
+
borderTopRightRadius: style.borderTopRightRadius,
|
|
165
|
+
borderBottomRightRadius: style.borderBottomRightRadius,
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
expect(parseFloat(rightStyles.borderTopLeftRadius)).toBe(0)
|
|
169
|
+
expect(parseFloat(rightStyles.borderBottomLeftRadius)).toBe(0)
|
|
170
|
+
})
|
|
171
|
+
})
|
|
172
|
+
})
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { expect, test, type Page } from '@playwright/test'
|
|
2
|
+
import { setupPage } from './test-utils'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* TOOLTIP CSS ANIMATION TESTS
|
|
6
|
+
*
|
|
7
|
+
* Validates that CSS tooltip animations have proper intermediate states:
|
|
8
|
+
* 1. Enter animation should animate y translation AND opacity smoothly
|
|
9
|
+
* 2. Exit animation should animate y translation AND opacity smoothly
|
|
10
|
+
* 3. First show should behave identically to subsequent shows
|
|
11
|
+
* 4. Arrow should have proper size
|
|
12
|
+
*
|
|
13
|
+
* Uses "lazy" animation (1000ms) for reliable intermediate capture.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const TOLERANCE = 0.1
|
|
17
|
+
|
|
18
|
+
async function getOpacity(page: Page, testId: string): Promise<number> {
|
|
19
|
+
return page.evaluate((id) => {
|
|
20
|
+
const el = document.querySelector(`[data-testid="${id}"]`)
|
|
21
|
+
if (!el) return -1
|
|
22
|
+
return Number.parseFloat(getComputedStyle(el).opacity)
|
|
23
|
+
}, testId)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function getTranslateY(page: Page, testId: string): Promise<number> {
|
|
27
|
+
return page.evaluate((id) => {
|
|
28
|
+
const el = document.querySelector(`[data-testid="${id}"]`)
|
|
29
|
+
if (!el) return -9999
|
|
30
|
+
const transform = getComputedStyle(el).transform
|
|
31
|
+
if (transform === 'none') return 0
|
|
32
|
+
// matrix(a, b, c, d, tx, ty) - translateY is in the 'ty' position (6th value)
|
|
33
|
+
const match = transform.match(/matrix\([^,]+,[^,]+,[^,]+,[^,]+,[^,]+,\s*([^)]+)\)/)
|
|
34
|
+
return match ? Number.parseFloat(match[1]) : 0
|
|
35
|
+
}, testId)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function elementExists(page: Page, testId: string): Promise<boolean> {
|
|
39
|
+
return page.evaluate((id) => !!document.querySelector(`[data-testid="${id}"]`), testId)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isIntermediate(
|
|
43
|
+
value: number,
|
|
44
|
+
start: number,
|
|
45
|
+
end: number,
|
|
46
|
+
tolerance = TOLERANCE
|
|
47
|
+
): boolean {
|
|
48
|
+
const notAtStart = Math.abs(value - start) > tolerance
|
|
49
|
+
const notAtEnd = Math.abs(value - end) > tolerance
|
|
50
|
+
const min = Math.min(start, end)
|
|
51
|
+
const max = Math.max(start, end)
|
|
52
|
+
const inRange = value >= min - tolerance && value <= max + tolerance
|
|
53
|
+
return notAtStart && notAtEnd && inRange
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
test.describe('Tooltip animation', () => {
|
|
57
|
+
test.beforeEach(async ({ page }, testInfo) => {
|
|
58
|
+
// These tests validate CSS transition intermediate states using transition="lazy"
|
|
59
|
+
// which is CSS-specific. Skip for non-CSS animation drivers.
|
|
60
|
+
const animationDriver = testInfo.project.metadata?.animationDriver
|
|
61
|
+
if (animationDriver && animationDriver !== 'css') {
|
|
62
|
+
test.skip()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
await setupPage(page, {
|
|
66
|
+
name: 'TooltipAnimationCase',
|
|
67
|
+
type: 'useCase',
|
|
68
|
+
})
|
|
69
|
+
await page.waitForTimeout(500)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// TEST 1: Enter animation opacity intermediate values
|
|
73
|
+
test('enter animation has intermediate opacity values', async ({ page }) => {
|
|
74
|
+
const START_OPACITY = 0
|
|
75
|
+
const END_OPACITY = 1
|
|
76
|
+
|
|
77
|
+
// Tooltip should not be visible initially
|
|
78
|
+
expect(await elementExists(page, 'tooltip-content'), 'Initially hidden').toBe(false)
|
|
79
|
+
|
|
80
|
+
// Hover to trigger tooltip
|
|
81
|
+
await page.getByTestId('tooltip-trigger').hover()
|
|
82
|
+
|
|
83
|
+
// Wait for tooltip to appear
|
|
84
|
+
await page.waitForTimeout(50)
|
|
85
|
+
expect(
|
|
86
|
+
await elementExists(page, 'tooltip-content'),
|
|
87
|
+
'Element exists after hover'
|
|
88
|
+
).toBe(true)
|
|
89
|
+
|
|
90
|
+
// Capture mid-animation value (after ~400ms of 1000ms animation)
|
|
91
|
+
await page.waitForTimeout(350)
|
|
92
|
+
const midOpacity = await getOpacity(page, 'tooltip-content')
|
|
93
|
+
|
|
94
|
+
// Wait for animation to complete
|
|
95
|
+
await page.waitForTimeout(1200)
|
|
96
|
+
const endOpacity = await getOpacity(page, 'tooltip-content')
|
|
97
|
+
|
|
98
|
+
expect(endOpacity, 'End opacity').toBeCloseTo(END_OPACITY, 1)
|
|
99
|
+
expect(
|
|
100
|
+
isIntermediate(midOpacity, START_OPACITY, END_OPACITY),
|
|
101
|
+
`Mid opacity (${midOpacity.toFixed(3)}) should be intermediate between ${START_OPACITY} and ${END_OPACITY}`
|
|
102
|
+
).toBe(true)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// TEST 2: Enter animation translateY intermediate values
|
|
106
|
+
// timing sensitive - on fast machines animation may complete before sample
|
|
107
|
+
test('enter animation has intermediate translateY values', async ({ page }) => {
|
|
108
|
+
const START_Y = -20 // enterStyle y value
|
|
109
|
+
const END_Y = 0
|
|
110
|
+
|
|
111
|
+
// Hover to trigger tooltip
|
|
112
|
+
await page.getByTestId('tooltip-trigger').hover()
|
|
113
|
+
|
|
114
|
+
// Wait for tooltip to appear
|
|
115
|
+
await page.waitForTimeout(50)
|
|
116
|
+
expect(
|
|
117
|
+
await elementExists(page, 'tooltip-content'),
|
|
118
|
+
'Element exists after hover'
|
|
119
|
+
).toBe(true)
|
|
120
|
+
|
|
121
|
+
// Capture mid-animation value (sample earlier on fast machines)
|
|
122
|
+
await page.waitForTimeout(200)
|
|
123
|
+
const midY = await getTranslateY(page, 'tooltip-content')
|
|
124
|
+
|
|
125
|
+
// Wait for animation to complete
|
|
126
|
+
await page.waitForTimeout(1200)
|
|
127
|
+
const endY = await getTranslateY(page, 'tooltip-content')
|
|
128
|
+
|
|
129
|
+
expect(endY, 'End translateY').toBeCloseTo(END_Y, 0)
|
|
130
|
+
// Allow either intermediate value OR at end (animation completed fast)
|
|
131
|
+
// The key thing is that the animation didn't snap to START_Y
|
|
132
|
+
const isAnimating = isIntermediate(midY, START_Y, END_Y) || Math.abs(midY - END_Y) < 1
|
|
133
|
+
expect(
|
|
134
|
+
isAnimating,
|
|
135
|
+
`Mid translateY (${midY.toFixed(2)}) should be animating (not stuck at start ${START_Y})`
|
|
136
|
+
).toBe(true)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
// TEST 3: First show should animate same as subsequent shows (not snap on first)
|
|
140
|
+
// timing sensitive - on fast machines animation may complete before sample
|
|
141
|
+
test('first show animates same as subsequent shows', async ({ page }) => {
|
|
142
|
+
// First show
|
|
143
|
+
await page.getByTestId('tooltip-trigger').hover()
|
|
144
|
+
await page.waitForTimeout(50)
|
|
145
|
+
expect(
|
|
146
|
+
await elementExists(page, 'tooltip-content'),
|
|
147
|
+
'First show: element exists'
|
|
148
|
+
).toBe(true)
|
|
149
|
+
|
|
150
|
+
// Capture first show mid-animation values (sample earlier on fast machines)
|
|
151
|
+
await page.waitForTimeout(200)
|
|
152
|
+
const firstMidOpacity = await getOpacity(page, 'tooltip-content')
|
|
153
|
+
const firstMidY = await getTranslateY(page, 'tooltip-content')
|
|
154
|
+
|
|
155
|
+
// Wait for first animation to complete
|
|
156
|
+
await page.waitForTimeout(1200)
|
|
157
|
+
|
|
158
|
+
// Move away to hide tooltip
|
|
159
|
+
await page.mouse.move(0, 0)
|
|
160
|
+
await page.waitForTimeout(1500) // Wait for exit animation
|
|
161
|
+
|
|
162
|
+
// Second show
|
|
163
|
+
await page.getByTestId('tooltip-trigger').hover()
|
|
164
|
+
await page.waitForTimeout(50)
|
|
165
|
+
expect(
|
|
166
|
+
await elementExists(page, 'tooltip-content'),
|
|
167
|
+
'Second show: element exists'
|
|
168
|
+
).toBe(true)
|
|
169
|
+
|
|
170
|
+
// Capture second show mid-animation values
|
|
171
|
+
await page.waitForTimeout(200)
|
|
172
|
+
const secondMidOpacity = await getOpacity(page, 'tooltip-content')
|
|
173
|
+
const secondMidY = await getTranslateY(page, 'tooltip-content')
|
|
174
|
+
|
|
175
|
+
// Both should be animating (intermediate or at end for fast machines)
|
|
176
|
+
// The key is they shouldn't be stuck at start (0 opacity, -20 Y)
|
|
177
|
+
const firstAnimating = isIntermediate(firstMidOpacity, 0, 1) || firstMidOpacity > 0.5
|
|
178
|
+
const secondAnimating =
|
|
179
|
+
isIntermediate(secondMidOpacity, 0, 1) || secondMidOpacity > 0.5
|
|
180
|
+
|
|
181
|
+
expect(
|
|
182
|
+
firstAnimating,
|
|
183
|
+
`First mid opacity (${firstMidOpacity.toFixed(3)}) should be animating`
|
|
184
|
+
).toBe(true)
|
|
185
|
+
|
|
186
|
+
expect(
|
|
187
|
+
secondAnimating,
|
|
188
|
+
`Second mid opacity (${secondMidOpacity.toFixed(3)}) should be animating`
|
|
189
|
+
).toBe(true)
|
|
190
|
+
|
|
191
|
+
// Y should also be animating (not stuck at -20)
|
|
192
|
+
const firstYAnimating = isIntermediate(firstMidY, -20, 0) || Math.abs(firstMidY) < 5
|
|
193
|
+
const secondYAnimating =
|
|
194
|
+
isIntermediate(secondMidY, -20, 0) || Math.abs(secondMidY) < 5
|
|
195
|
+
|
|
196
|
+
expect(
|
|
197
|
+
firstYAnimating,
|
|
198
|
+
`First mid Y (${firstMidY.toFixed(2)}) should be animating`
|
|
199
|
+
).toBe(true)
|
|
200
|
+
|
|
201
|
+
expect(
|
|
202
|
+
secondYAnimating,
|
|
203
|
+
`Second mid Y (${secondMidY.toFixed(2)}) should be animating`
|
|
204
|
+
).toBe(true)
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
// TEST 4: Exit animation intermediate values
|
|
208
|
+
test('exit animation has intermediate opacity values', async ({ page }) => {
|
|
209
|
+
const START_OPACITY = 1
|
|
210
|
+
const END_OPACITY = 0
|
|
211
|
+
|
|
212
|
+
// Show tooltip first
|
|
213
|
+
await page.getByTestId('tooltip-trigger').hover()
|
|
214
|
+
await page.waitForTimeout(1500) // Wait for enter animation to complete
|
|
215
|
+
|
|
216
|
+
const startOpacity = await getOpacity(page, 'tooltip-content')
|
|
217
|
+
expect(startOpacity, 'Start opacity before exit').toBeCloseTo(START_OPACITY, 1)
|
|
218
|
+
|
|
219
|
+
// Move away to trigger exit
|
|
220
|
+
await page.mouse.move(0, 0)
|
|
221
|
+
|
|
222
|
+
// Capture mid-exit animation
|
|
223
|
+
await page.waitForTimeout(400)
|
|
224
|
+
|
|
225
|
+
// Element should still exist during exit animation
|
|
226
|
+
const stillExists = await elementExists(page, 'tooltip-content')
|
|
227
|
+
|
|
228
|
+
if (stillExists) {
|
|
229
|
+
const midOpacity = await getOpacity(page, 'tooltip-content')
|
|
230
|
+
expect(
|
|
231
|
+
isIntermediate(midOpacity, START_OPACITY, END_OPACITY) ||
|
|
232
|
+
midOpacity < START_OPACITY,
|
|
233
|
+
`Mid exit opacity (${midOpacity.toFixed(3)}) should be animating`
|
|
234
|
+
).toBe(true)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Wait for exit to complete
|
|
238
|
+
await page.waitForTimeout(1500)
|
|
239
|
+
expect(await elementExists(page, 'tooltip-content'), 'Hidden after exit').toBe(false)
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
// TEST 5: Arrow size validation - SKIPPED pending Tooltip arrow sizing fix
|
|
243
|
+
test.skip('arrow has proper size (not tiny)', async ({ page }) => {
|
|
244
|
+
// Show tooltip
|
|
245
|
+
await page.getByTestId('tooltip-trigger').hover()
|
|
246
|
+
await page.waitForTimeout(1500)
|
|
247
|
+
|
|
248
|
+
const arrowSize = await page.evaluate(() => {
|
|
249
|
+
const arrow = document.querySelector('[data-testid="tooltip-arrow"]')
|
|
250
|
+
if (!arrow) return { width: 0, height: 0, exists: false }
|
|
251
|
+
const rect = arrow.getBoundingClientRect()
|
|
252
|
+
return { width: rect.width, height: rect.height, exists: true }
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
expect(arrowSize.exists, 'Arrow element exists').toBe(true)
|
|
256
|
+
// Arrow should have reasonable size (size="$2" should be ~16px, not tiny)
|
|
257
|
+
expect(arrowSize.width, 'Arrow width should not be tiny').toBeGreaterThan(8)
|
|
258
|
+
expect(arrowSize.height, 'Arrow height should not be tiny').toBeGreaterThan(8)
|
|
259
|
+
})
|
|
260
|
+
})
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
import { setupPage } from './test-utils'
|
|
3
|
+
|
|
4
|
+
test.describe('Tooltip enter animation interrupted by trigger switch', () => {
|
|
5
|
+
test.beforeEach(async ({ page }) => {
|
|
6
|
+
await setupPage(page, {
|
|
7
|
+
name: 'TooltipMultiTriggerCase',
|
|
8
|
+
type: 'useCase',
|
|
9
|
+
})
|
|
10
|
+
await page.waitForLoadState('networkidle')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('enter animation completes after quick trigger switch', async ({ page }) => {
|
|
14
|
+
const content = page.locator('#tip-content')
|
|
15
|
+
|
|
16
|
+
// hover trigger A to start opening
|
|
17
|
+
await page.locator('#tip-trigger-a').hover()
|
|
18
|
+
// wait just long enough for tooltip to mount but enter animation to still be in-flight
|
|
19
|
+
await page.waitForTimeout(80)
|
|
20
|
+
|
|
21
|
+
// quickly switch to trigger C (interrupts the enter animation mid-flight)
|
|
22
|
+
const triggerC = page.locator('#tip-trigger-c')
|
|
23
|
+
const cBox = await triggerC.boundingBox()
|
|
24
|
+
await page.mouse.move(cBox!.x + cBox!.width / 2, cBox!.y + cBox!.height / 2, {
|
|
25
|
+
steps: 2,
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
// wait for animations to settle
|
|
29
|
+
await page.waitForTimeout(600)
|
|
30
|
+
|
|
31
|
+
await expect(content).toBeVisible({ timeout: 2000 })
|
|
32
|
+
|
|
33
|
+
// the tooltip should be fully opaque — not stuck at a mid-flight value
|
|
34
|
+
const opacity = await content.evaluate((el) => {
|
|
35
|
+
return parseFloat(getComputedStyle(el).opacity)
|
|
36
|
+
})
|
|
37
|
+
expect(
|
|
38
|
+
opacity,
|
|
39
|
+
'tooltip should be fully opaque after enter completes'
|
|
40
|
+
).toBeGreaterThan(0.9)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('enter animation completes after rapid multi-trigger sweep', async ({ page }) => {
|
|
44
|
+
const content = page.locator('#tip-content')
|
|
45
|
+
|
|
46
|
+
// hover trigger A
|
|
47
|
+
await page.locator('#tip-trigger-a').hover()
|
|
48
|
+
await page.waitForTimeout(60)
|
|
49
|
+
|
|
50
|
+
// rapidly sweep A → B → C
|
|
51
|
+
const triggerB = page.locator('#tip-trigger-b')
|
|
52
|
+
const triggerC = page.locator('#tip-trigger-c')
|
|
53
|
+
const bBox = await triggerB.boundingBox()
|
|
54
|
+
const cBox = await triggerC.boundingBox()
|
|
55
|
+
|
|
56
|
+
await page.mouse.move(bBox!.x + bBox!.width / 2, bBox!.y + bBox!.height / 2, {
|
|
57
|
+
steps: 2,
|
|
58
|
+
})
|
|
59
|
+
await page.waitForTimeout(30)
|
|
60
|
+
await page.mouse.move(cBox!.x + cBox!.width / 2, cBox!.y + cBox!.height / 2, {
|
|
61
|
+
steps: 2,
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// wait for animations to settle
|
|
65
|
+
await page.waitForTimeout(600)
|
|
66
|
+
|
|
67
|
+
await expect(content).toBeVisible({ timeout: 2000 })
|
|
68
|
+
|
|
69
|
+
const opacity = await content.evaluate((el) => {
|
|
70
|
+
return parseFloat(getComputedStyle(el).opacity)
|
|
71
|
+
})
|
|
72
|
+
expect(opacity, 'tooltip should be fully opaque after rapid sweep').toBeGreaterThan(
|
|
73
|
+
0.9
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
})
|