From 81628a41504579588915fbd3bc13b91f470f564e Mon Sep 17 00:00:00 2001 From: mainframev Date: Thu, 13 Jun 2024 10:15:06 +0200 Subject: [PATCH] fix(react-button): apply hover only on devices that support hover --- .../library/src/components/Button/Button.tsx | 2 +- .../{consts.ts => constants.ts} | 0 .../Button/useButtonStyles/index.ts | 67 +---------- .../useButtonStyles/useButtonStyles.styles.ts | 63 ++++++++++ .../useIconBaseClassName.styles.ts | 2 +- .../useButtonStyles/useIconStyles.styles.ts | 2 +- .../useRootBaseClassName.styles.ts | 29 +++-- .../useRootDisabledStyles.styles.ts | 76 +++++++----- .../useRootFocusStyles.styles.ts | 18 ++- .../useRootIconOnlyStates.styles.ts | 2 +- .../useButtonStyles/useRootStyles.styles.ts | 112 +++++++++++------- .../useCompoundButtonStyles.styles.ts | 74 ++++++++---- .../MenuButton/useMenuButtonStyles.styles.ts | 9 +- .../useSplitButtonStyles.styles.ts | 54 ++++++--- .../useToggleButtonStyles.styles.ts | 100 ++++++++++------ 15 files changed, 367 insertions(+), 243 deletions(-) rename packages/react-components/react-button/library/src/components/Button/useButtonStyles/{consts.ts => constants.ts} (100%) create mode 100644 packages/react-components/react-button/library/src/components/Button/useButtonStyles/useButtonStyles.styles.ts diff --git a/packages/react-components/react-button/library/src/components/Button/Button.tsx b/packages/react-components/react-button/library/src/components/Button/Button.tsx index 2ab70e0fec1df6..9e608b6130cdf0 100644 --- a/packages/react-components/react-button/library/src/components/Button/Button.tsx +++ b/packages/react-components/react-button/library/src/components/Button/Button.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { renderButton_unstable } from './renderButton'; import { useButton_unstable } from './useButton'; -import { useButtonStyles_unstable } from './useButtonStyles.styles'; +import { useButtonStyles_unstable } from './useButtonStyles'; import type { ButtonProps } from './Button.types'; import type { ForwardRefComponent } from '@fluentui/react-utilities'; import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts'; diff --git a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/consts.ts b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/constants.ts similarity index 100% rename from packages/react-components/react-button/library/src/components/Button/useButtonStyles/consts.ts rename to packages/react-components/react-button/library/src/components/Button/useButtonStyles/constants.ts diff --git a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/index.ts b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/index.ts index ed68e85f0cefac..78e8f774d5f74d 100644 --- a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/index.ts +++ b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/index.ts @@ -1,65 +1,2 @@ -import { mergeClasses } from '@griffel/react'; -import type { ButtonState } from '../Button.types'; -import { buttonClassNames } from './consts'; -import { useRootBaseClassName } from './useRootBaseClassName.styles'; -import { useIconBaseClassName } from './useIconBaseClassName.styles'; -import { useRootStyles } from './useRootStyles.styles'; -import { useRootDisabledStyles } from './useRootDisabledStyles.styles'; -import { useRootFocusStyles } from './useRootFocusStyles.styles'; -import { useRootIconOnlyStyles } from './useRootIconOnlyStates.styles'; -import { useIconStyles } from './useIconStyles.styles'; - -export const useButtonStyles_unstable = (state: ButtonState): ButtonState => { - const rootBaseClassName = useRootBaseClassName(); - const iconBaseClassName = useIconBaseClassName(); - - const rootStyles = useRootStyles(); - const rootDisabledStyles = useRootDisabledStyles(); - const rootFocusStyles = useRootFocusStyles(); - const rootIconOnlyStyles = useRootIconOnlyStyles(); - const iconStyles = useIconStyles(); - - const { appearance, disabled, disabledFocusable, icon, iconOnly, iconPosition, shape, size } = state; - - state.root.className = mergeClasses( - buttonClassNames.root, - rootBaseClassName, - - appearance && rootStyles[appearance], - - rootStyles[size], - icon && size === 'small' && rootStyles.smallWithIcon, - icon && size === 'large' && rootStyles.largeWithIcon, - rootStyles[shape], - - // Disabled styles - (disabled || disabledFocusable) && rootDisabledStyles.base, - (disabled || disabledFocusable) && rootDisabledStyles.highContrast, - appearance && (disabled || disabledFocusable) && rootDisabledStyles[appearance], - - // Focus styles - appearance === 'primary' && rootFocusStyles.primary, - rootFocusStyles[size], - rootFocusStyles[shape], - - // Icon-only styles - iconOnly && rootIconOnlyStyles[size], - - // User provided class name - state.root.className, - ); - - if (state.icon) { - state.icon.className = mergeClasses( - buttonClassNames.icon, - iconBaseClassName, - !!state.root.children && iconStyles[iconPosition], - iconStyles[size], - state.icon.className, - ); - } - - return state; -}; - -export { buttonClassNames }; +export { useButtonStyles_unstable } from './useButtonStyles.styles'; +export { buttonClassNames } from './constants'; diff --git a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useButtonStyles.styles.ts b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useButtonStyles.styles.ts new file mode 100644 index 00000000000000..144e0249c83635 --- /dev/null +++ b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useButtonStyles.styles.ts @@ -0,0 +1,63 @@ +import { mergeClasses } from '@griffel/react'; +import type { ButtonState } from '../Button.types'; +import { buttonClassNames } from './constants'; +import { useRootBaseClassName } from './useRootBaseClassName.styles'; +import { useIconBaseClassName } from './useIconBaseClassName.styles'; +import { useRootStyles } from './useRootStyles.styles'; +import { useRootDisabledStyles } from './useRootDisabledStyles.styles'; +import { useRootFocusStyles } from './useRootFocusStyles.styles'; +import { useRootIconOnlyStyles } from './useRootIconOnlyStates.styles'; +import { useIconStyles } from './useIconStyles.styles'; + +export const useButtonStyles_unstable = (state: ButtonState): ButtonState => { + const rootBaseClassName = useRootBaseClassName(); + const iconBaseClassName = useIconBaseClassName(); + + const rootStyles = useRootStyles(); + const rootDisabledStyles = useRootDisabledStyles(); + const rootFocusStyles = useRootFocusStyles(); + const rootIconOnlyStyles = useRootIconOnlyStyles(); + const iconStyles = useIconStyles(); + + const { appearance, disabled, disabledFocusable, icon, iconOnly, iconPosition, shape, size } = state; + + state.root.className = mergeClasses( + buttonClassNames.root, + rootBaseClassName, + + appearance && rootStyles[appearance], + + rootStyles[size], + icon && size === 'small' && rootStyles.smallWithIcon, + icon && size === 'large' && rootStyles.largeWithIcon, + rootStyles[shape], + + // Disabled styles + (disabled || disabledFocusable) && rootDisabledStyles.base, + (disabled || disabledFocusable) && rootDisabledStyles.highContrast, + appearance && (disabled || disabledFocusable) && rootDisabledStyles[appearance], + + // Focus styles + appearance === 'primary' && rootFocusStyles.primary, + rootFocusStyles[size], + rootFocusStyles[shape], + + // Icon-only styles + iconOnly && rootIconOnlyStyles[size], + + // User provided class name + state.root.className, + ); + + if (state.icon) { + state.icon.className = mergeClasses( + buttonClassNames.icon, + iconBaseClassName, + !!state.root.children && iconStyles[iconPosition], + iconStyles[size], + state.icon.className, + ); + } + + return state; +}; diff --git a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useIconBaseClassName.styles.ts b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useIconBaseClassName.styles.ts index af776fb3285e90..328f72a66a4fe2 100644 --- a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useIconBaseClassName.styles.ts +++ b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useIconBaseClassName.styles.ts @@ -1,5 +1,5 @@ import { makeResetStyles } from '@griffel/react'; -import { iconSpacingVar } from './consts'; +import { iconSpacingVar } from './constants'; import { tokens } from '@fluentui/react-theme'; export const useIconBaseClassName = makeResetStyles({ diff --git a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useIconStyles.styles.ts b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useIconStyles.styles.ts index 3f2e1caf8851cc..4e90e60ab08fc0 100644 --- a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useIconStyles.styles.ts +++ b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useIconStyles.styles.ts @@ -1,6 +1,6 @@ import { tokens } from '@fluentui/react-theme'; import { makeStyles } from '@griffel/react'; -import { iconSpacingVar } from './consts'; +import { iconSpacingVar } from './constants'; export const useIconStyles = makeStyles({ // Size variations diff --git a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootBaseClassName.styles.ts b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootBaseClassName.styles.ts index 2fbc146a3d7937..9acc149e554029 100644 --- a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootBaseClassName.styles.ts +++ b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootBaseClassName.styles.ts @@ -1,7 +1,7 @@ import { makeResetStyles } from '@griffel/react'; import { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster'; import { tokens } from '@fluentui/react-theme'; -import { boxShadowStrokeWidthThinMoz, buttonSpacingMedium } from './consts'; +import { boxShadowStrokeWidthThinMoz, buttonSpacingMedium } from './constants'; export const useRootBaseClassName = makeResetStyles({ alignItems: 'center', @@ -21,13 +21,15 @@ export const useRootBaseClassName = makeResetStyles({ fontFamily: tokens.fontFamilyBase, outlineStyle: 'none', - // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#hover - ':hover': { - backgroundColor: tokens.colorNeutralBackground1Hover, - borderColor: tokens.colorNeutralStroke1Hover, - color: tokens.colorNeutralForeground1Hover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorNeutralBackground1Hover, + borderColor: tokens.colorNeutralStroke1Hover, + color: tokens.colorNeutralForeground1Hover, - cursor: 'pointer', + cursor: 'pointer', + }, }, ':hover:active': { @@ -62,11 +64,14 @@ export const useRootBaseClassName = makeResetStyles({ borderColor: 'ButtonText', }, - ':hover': { - backgroundColor: 'HighlightText', - borderColor: 'Highlight', - color: 'Highlight', - forcedColorAdjust: 'none', + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: 'HighlightText', + borderColor: 'Highlight', + color: 'Highlight', + forcedColorAdjust: 'none', + }, }, ':hover:active': { diff --git a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootDisabledStyles.styles.ts b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootDisabledStyles.styles.ts index 8cfd68163cbcfc..c2fb26ea78cfae 100644 --- a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootDisabledStyles.styles.ts +++ b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootDisabledStyles.styles.ts @@ -1,7 +1,7 @@ import { tokens } from '@fluentui/react-theme'; import { shorthands, makeStyles } from '@griffel/react'; import { iconFilledClassName, iconRegularClassName } from '@fluentui/react-icons'; -import { buttonClassNames } from './consts'; +import { buttonClassNames } from './constants'; export const useRootDisabledStyles = makeStyles({ // Base styles @@ -15,21 +15,24 @@ export const useRootDisabledStyles = makeStyles({ color: tokens.colorNeutralForegroundDisabled, }, - ':hover': { - backgroundColor: tokens.colorNeutralBackgroundDisabled, - ...shorthands.borderColor(tokens.colorNeutralStrokeDisabled), - color: tokens.colorNeutralForegroundDisabled, - - cursor: 'not-allowed', - - [`& .${iconFilledClassName}`]: { - display: 'none', - }, - [`& .${iconRegularClassName}`]: { - display: 'inline', - }, - [`& .${buttonClassNames.icon}`]: { + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorNeutralBackgroundDisabled, + ...shorthands.borderColor(tokens.colorNeutralStrokeDisabled), color: tokens.colorNeutralForegroundDisabled, + + cursor: 'not-allowed', + + [`& .${iconFilledClassName}`]: { + display: 'none', + }, + [`& .${iconRegularClassName}`]: { + display: 'inline', + }, + [`& .${buttonClassNames.icon}`]: { + color: tokens.colorNeutralForegroundDisabled, + }, }, }, @@ -63,10 +66,13 @@ export const useRootDisabledStyles = makeStyles({ ...shorthands.borderColor('GrayText'), }, - ':hover': { - backgroundColor: 'ButtonFace', - ...shorthands.borderColor('GrayText'), - color: 'GrayText', + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: 'ButtonFace', + ...shorthands.borderColor('GrayText'), + color: 'GrayText', + }, }, ':hover:active': { @@ -80,8 +86,11 @@ export const useRootDisabledStyles = makeStyles({ // Appearance variations outline: { backgroundColor: tokens.colorTransparentBackground, - ':hover': { - backgroundColor: tokens.colorTransparentBackground, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorTransparentBackground, + }, }, ':hover:active': { @@ -90,8 +99,11 @@ export const useRootDisabledStyles = makeStyles({ }, primary: { ...shorthands.borderColor('transparent'), - ':hover': { - ...shorthands.borderColor('transparent'), + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + ...shorthands.borderColor('transparent'), + }, }, ':hover:active': { @@ -104,9 +116,12 @@ export const useRootDisabledStyles = makeStyles({ subtle: { backgroundColor: tokens.colorTransparentBackground, ...shorthands.borderColor('transparent'), - ':hover': { - backgroundColor: tokens.colorTransparentBackground, - ...shorthands.borderColor('transparent'), + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorTransparentBackground, + ...shorthands.borderColor('transparent'), + }, }, ':hover:active': { @@ -117,9 +132,12 @@ export const useRootDisabledStyles = makeStyles({ transparent: { backgroundColor: tokens.colorTransparentBackground, ...shorthands.borderColor('transparent'), - ':hover': { - backgroundColor: tokens.colorTransparentBackground, - ...shorthands.borderColor('transparent'), + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorTransparentBackground, + ...shorthands.borderColor('transparent'), + }, }, ':hover:active': { diff --git a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootFocusStyles.styles.ts b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootFocusStyles.styles.ts index c3f36875b4676a..1aba6f66fdeda5 100644 --- a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootFocusStyles.styles.ts +++ b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootFocusStyles.styles.ts @@ -1,7 +1,7 @@ import { makeStyles, shorthands } from '@griffel/react'; import { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster'; import { tokens } from '@fluentui/react-theme'; -import { boxShadowStrokeWidthThinMoz } from './consts'; +import { boxShadowStrokeWidthThinMoz } from './constants'; export const useRootFocusStyles = makeStyles({ // Shape variations @@ -16,9 +16,12 @@ export const useRootFocusStyles = makeStyles({ ...createCustomFocusIndicatorStyle({ ...shorthands.borderColor(tokens.colorStrokeFocus2), boxShadow: `${tokens.shadow2}, 0 0 0 ${tokens.strokeWidthThin} ${tokens.colorStrokeFocus2} inset, 0 0 0 ${tokens.strokeWidthThick} ${tokens.colorNeutralForegroundOnBrand} inset`, - ':hover': { - boxShadow: `${tokens.shadow2}, 0 0 0 ${tokens.strokeWidthThin} ${tokens.colorStrokeFocus2} inset`, - ...shorthands.borderColor(tokens.colorStrokeFocus2), + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + boxShadow: `${tokens.shadow2}, 0 0 0 ${tokens.strokeWidthThin} ${tokens.colorStrokeFocus2} inset`, + ...shorthands.borderColor(tokens.colorStrokeFocus2), + }, }, }), @@ -26,8 +29,11 @@ export const useRootFocusStyles = makeStyles({ '@supports (-moz-appearance:button)': { ...createCustomFocusIndicatorStyle({ boxShadow: `${tokens.shadow2}, 0 0 0 ${boxShadowStrokeWidthThinMoz} ${tokens.colorStrokeFocus2} inset, 0 0 0 ${tokens.strokeWidthThick} ${tokens.colorNeutralForegroundOnBrand} inset`, - ':hover': { - boxShadow: `${tokens.shadow2}, 0 0 0 ${boxShadowStrokeWidthThinMoz} ${tokens.colorStrokeFocus2} inset`, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + boxShadow: `${tokens.shadow2}, 0 0 0 ${boxShadowStrokeWidthThinMoz} ${tokens.colorStrokeFocus2} inset`, + }, }, }), }, diff --git a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootIconOnlyStates.styles.ts b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootIconOnlyStates.styles.ts index 2d28bef716e336..40a1ece3a8554f 100644 --- a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootIconOnlyStates.styles.ts +++ b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootIconOnlyStates.styles.ts @@ -1,5 +1,5 @@ import { makeStyles } from '@griffel/react'; -import { buttonSpacingLargeWithIcon, buttonSpacingMedium, buttonSpacingSmallWithIcon } from './consts'; +import { buttonSpacingLargeWithIcon, buttonSpacingMedium, buttonSpacingSmallWithIcon } from './constants'; export const useRootIconOnlyStyles = makeStyles({ // Size variations diff --git a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootStyles.styles.ts b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootStyles.styles.ts index 0d619bdedcd9d7..9d0f2cd372cbcd 100644 --- a/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootStyles.styles.ts +++ b/packages/react-components/react-button/library/src/components/Button/useButtonStyles/useRootStyles.styles.ts @@ -7,15 +7,17 @@ import { buttonSpacingSmallWithIcon, buttonSpacingSmall, buttonSpacingLarge, -} from './consts'; +} from './constants'; export const useRootStyles = makeStyles({ // Appearance variations outline: { backgroundColor: tokens.colorTransparentBackground, - - ':hover': { - backgroundColor: tokens.colorTransparentBackgroundHover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorTransparentBackgroundHover, + }, }, ':hover:active': { @@ -27,11 +29,13 @@ export const useRootStyles = makeStyles({ backgroundColor: tokens.colorBrandBackground, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForegroundOnBrand, - - ':hover': { - backgroundColor: tokens.colorBrandBackgroundHover, - ...shorthands.borderColor('transparent'), - color: tokens.colorNeutralForegroundOnBrand, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorBrandBackgroundHover, + ...shorthands.borderColor('transparent'), + color: tokens.colorNeutralForegroundOnBrand, + }, }, ':hover:active': { @@ -46,11 +50,13 @@ export const useRootStyles = makeStyles({ color: 'HighlightText', forcedColorAdjust: 'none', - // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#hover - ':hover': { - backgroundColor: 'HighlightText', - ...shorthands.borderColor('Highlight'), - color: 'Highlight', + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: 'HighlightText', + ...shorthands.borderColor('Highlight'), + color: 'Highlight', + }, }, ':hover:active': { @@ -68,18 +74,21 @@ export const useRootStyles = makeStyles({ ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForeground2, - ':hover': { - backgroundColor: tokens.colorSubtleBackgroundHover, - ...shorthands.borderColor('transparent'), - color: tokens.colorNeutralForeground2Hover, - [`& .${iconFilledClassName}`]: { - display: 'inline', - }, - [`& .${iconRegularClassName}`]: { - display: 'none', - }, - [`& .${buttonClassNames.icon}`]: { - color: tokens.colorNeutralForeground2BrandHover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorSubtleBackgroundHover, + ...shorthands.borderColor('transparent'), + color: tokens.colorNeutralForeground2Hover, + [`& .${iconFilledClassName}`]: { + display: 'inline', + }, + [`& .${iconRegularClassName}`]: { + display: 'none', + }, + [`& .${buttonClassNames.icon}`]: { + color: tokens.colorNeutralForeground2BrandHover, + }, }, }, @@ -96,8 +105,11 @@ export const useRootStyles = makeStyles({ [`& .${buttonClassNames.icon}`]: { color: tokens.colorNeutralForeground2BrandPressed, }, + }, - '@media (forced-colors: active)': { + '@media (forced-colors: active)': { + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { ':hover': { color: 'Highlight', @@ -105,12 +117,13 @@ export const useRootStyles = makeStyles({ color: 'Highlight', }, }, - ':hover:active': { - color: 'Highlight', + }, - [`& .${buttonClassNames.icon}`]: { - color: 'Highlight', - }, + ':hover:active': { + color: 'Highlight', + + [`& .${buttonClassNames.icon}`]: { + color: 'Highlight', }, }, }, @@ -120,15 +133,18 @@ export const useRootStyles = makeStyles({ ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForeground2, - ':hover': { - backgroundColor: tokens.colorTransparentBackgroundHover, - ...shorthands.borderColor('transparent'), - color: tokens.colorNeutralForeground2BrandHover, - [`& .${iconFilledClassName}`]: { - display: 'inline', - }, - [`& .${iconRegularClassName}`]: { - display: 'none', + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorTransparentBackgroundHover, + ...shorthands.borderColor('transparent'), + color: tokens.colorNeutralForeground2BrandHover, + [`& .${iconFilledClassName}`]: { + display: 'inline', + }, + [`& .${iconRegularClassName}`]: { + display: 'none', + }, }, }, @@ -142,16 +158,20 @@ export const useRootStyles = makeStyles({ [`& .${iconRegularClassName}`]: { display: 'none', }, + }, - '@media (forced-colors: active)': { + '@media (forced-colors: active)': { + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { ':hover': { backgroundColor: tokens.colorTransparentBackground, color: 'Highlight', }, - ':hover:active': { - backgroundColor: tokens.colorTransparentBackground, - color: 'Highlight', - }, + }, + + ':hover:active': { + backgroundColor: tokens.colorTransparentBackground, + color: 'Highlight', }, }, }, diff --git a/packages/react-components/react-button/library/src/components/CompoundButton/useCompoundButtonStyles.styles.ts b/packages/react-components/react-button/library/src/components/CompoundButton/useCompoundButtonStyles.styles.ts index 9916fcecadfafc..ae5bd0f3d53e09 100644 --- a/packages/react-components/react-button/library/src/components/CompoundButton/useCompoundButtonStyles.styles.ts +++ b/packages/react-components/react-button/library/src/components/CompoundButton/useCompoundButtonStyles.styles.ts @@ -1,6 +1,6 @@ import { tokens } from '@fluentui/react-theme'; import { mergeClasses, makeStyles } from '@griffel/react'; -import { useButtonStyles_unstable } from '../Button/useButtonStyles.styles'; +import { useButtonStyles_unstable } from '../Button/useButtonStyles'; import type { SlotClassNames } from '@fluentui/react-utilities'; import type { CompoundButtonSlots, CompoundButtonState } from './CompoundButton.types'; @@ -20,9 +20,12 @@ const useRootStyles = makeStyles({ color: tokens.colorNeutralForeground2, }, - ':hover': { - [`& .${compoundButtonClassNames.secondaryContent}`]: { - color: tokens.colorNeutralForeground2Hover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${compoundButtonClassNames.secondaryContent}`]: { + color: tokens.colorNeutralForeground2Hover, + }, }, }, @@ -36,9 +39,12 @@ const useRootStyles = makeStyles({ // High contrast styles highContrast: { '@media (forced-colors: active)': { - ':hover': { - [`& .${compoundButtonClassNames.secondaryContent}`]: { - color: 'Highlight', + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${compoundButtonClassNames.secondaryContent}`]: { + color: 'Highlight', + }, }, }, @@ -59,9 +65,12 @@ const useRootStyles = makeStyles({ color: tokens.colorNeutralForegroundOnBrand, }, - ':hover': { - [`& .${compoundButtonClassNames.secondaryContent}`]: { - color: tokens.colorNeutralForegroundOnBrand, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${compoundButtonClassNames.secondaryContent}`]: { + color: tokens.colorNeutralForegroundOnBrand, + }, }, }, @@ -85,9 +94,12 @@ const useRootStyles = makeStyles({ color: tokens.colorNeutralForeground2, }, - ':hover': { - [`& .${compoundButtonClassNames.secondaryContent}`]: { - color: tokens.colorNeutralForeground2Hover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${compoundButtonClassNames.secondaryContent}`]: { + color: tokens.colorNeutralForeground2Hover, + }, }, }, @@ -98,9 +110,12 @@ const useRootStyles = makeStyles({ }, '@media (forced-colors: active)': { - ':hover': { - [`& .${compoundButtonClassNames.secondaryContent}`]: { - color: 'Canvas', + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${compoundButtonClassNames.secondaryContent}`]: { + color: 'Canvas', + }, }, }, ':hover:active': { @@ -115,9 +130,12 @@ const useRootStyles = makeStyles({ color: tokens.colorNeutralForeground2, }, - ':hover': { - [`& .${compoundButtonClassNames.secondaryContent}`]: { - color: tokens.colorNeutralForeground2BrandHover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${compoundButtonClassNames.secondaryContent}`]: { + color: tokens.colorNeutralForeground2BrandHover, + }, }, }, @@ -154,9 +172,12 @@ const useRootStyles = makeStyles({ color: tokens.colorNeutralForegroundDisabled, }, - ':hover': { - [`& .${compoundButtonClassNames.secondaryContent}`]: { - color: tokens.colorNeutralForegroundDisabled, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${compoundButtonClassNames.secondaryContent}`]: { + color: tokens.colorNeutralForegroundDisabled, + }, }, }, @@ -174,9 +195,12 @@ const useRootStyles = makeStyles({ color: 'GrayText', }, - ':hover': { - [`& .${compoundButtonClassNames.secondaryContent}`]: { - color: 'GrayText', + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${compoundButtonClassNames.secondaryContent}`]: { + color: 'GrayText', + }, }, }, diff --git a/packages/react-components/react-button/library/src/components/MenuButton/useMenuButtonStyles.styles.ts b/packages/react-components/react-button/library/src/components/MenuButton/useMenuButtonStyles.styles.ts index 5eb7412fdced45..5bb350d65b855a 100644 --- a/packages/react-components/react-button/library/src/components/MenuButton/useMenuButtonStyles.styles.ts +++ b/packages/react-components/react-button/library/src/components/MenuButton/useMenuButtonStyles.styles.ts @@ -2,7 +2,7 @@ import { iconFilledClassName, iconRegularClassName } from '@fluentui/react-icons import { tokens } from '@fluentui/react-theme'; import type { SlotClassNames } from '@fluentui/react-utilities'; import { mergeClasses, makeStyles, shorthands } from '@griffel/react'; -import { useButtonStyles_unstable } from '../Button/useButtonStyles.styles'; +import { useButtonStyles_unstable } from '../Button/useButtonStyles'; import type { MenuButtonSlots, MenuButtonState } from './MenuButton.types'; export const menuButtonClassNames: SlotClassNames = { @@ -65,8 +65,11 @@ const useIconExpandedStyles = makeStyles({ highContrast: { // High contrast styles '@media (forced-colors: active)': { - ':hover': { - color: 'Canvas', + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + color: 'Canvas', + }, }, }, }, diff --git a/packages/react-components/react-button/library/src/components/SplitButton/useSplitButtonStyles.styles.ts b/packages/react-components/react-button/library/src/components/SplitButton/useSplitButtonStyles.styles.ts index 7115b633bda11c..cf5bec888f8e83 100644 --- a/packages/react-components/react-button/library/src/components/SplitButton/useSplitButtonStyles.styles.ts +++ b/packages/react-components/react-button/library/src/components/SplitButton/useSplitButtonStyles.styles.ts @@ -53,9 +53,12 @@ const useRootStyles = makeStyles({ borderRightColor: tokens.colorNeutralStrokeOnBrand, }, - ':hover': { - [`& .${splitButtonClassNames.primaryActionButton}`]: { - borderRightColor: tokens.colorNeutralStrokeOnBrand, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${splitButtonClassNames.primaryActionButton}`]: { + borderRightColor: tokens.colorNeutralStrokeOnBrand, + }, }, }, @@ -70,9 +73,12 @@ const useRootStyles = makeStyles({ borderRightColor: 'HighlightText', }, - ':hover': { - [`& .${splitButtonClassNames.primaryActionButton}`]: { - borderRightColor: 'Highlight', + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${splitButtonClassNames.primaryActionButton}`]: { + borderRightColor: 'Highlight', + }, }, }, @@ -91,9 +97,12 @@ const useRootStyles = makeStyles({ borderRightColor: tokens.colorNeutralStroke1, }, - ':hover': { - [`& .${splitButtonClassNames.primaryActionButton}`]: { - borderRightColor: tokens.colorNeutralStroke1Hover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${splitButtonClassNames.primaryActionButton}`]: { + borderRightColor: tokens.colorNeutralStroke1Hover, + }, }, }, @@ -108,9 +117,12 @@ const useRootStyles = makeStyles({ borderRightColor: tokens.colorNeutralStroke1, }, - ':hover': { - [`& .${splitButtonClassNames.primaryActionButton}`]: { - borderRightColor: tokens.colorNeutralStroke1Hover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${splitButtonClassNames.primaryActionButton}`]: { + borderRightColor: tokens.colorNeutralStroke1Hover, + }, }, }, @@ -132,9 +144,12 @@ const useRootStyles = makeStyles({ borderRightColor: tokens.colorNeutralStrokeDisabled, }, - ':hover': { - [`& .${splitButtonClassNames.primaryActionButton}`]: { - borderRightColor: tokens.colorNeutralStrokeDisabled, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${splitButtonClassNames.primaryActionButton}`]: { + borderRightColor: tokens.colorNeutralStrokeDisabled, + }, }, }, @@ -152,9 +167,12 @@ const useRootStyles = makeStyles({ borderRightColor: 'GrayText', }, - ':hover': { - [`& .${splitButtonClassNames.primaryActionButton}`]: { - borderRightColor: 'GrayText', + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + [`& .${splitButtonClassNames.primaryActionButton}`]: { + borderRightColor: 'GrayText', + }, }, }, diff --git a/packages/react-components/react-button/library/src/components/ToggleButton/useToggleButtonStyles.styles.ts b/packages/react-components/react-button/library/src/components/ToggleButton/useToggleButtonStyles.styles.ts index 885928459ddc7c..6a91707dc14f60 100644 --- a/packages/react-components/react-button/library/src/components/ToggleButton/useToggleButtonStyles.styles.ts +++ b/packages/react-components/react-button/library/src/components/ToggleButton/useToggleButtonStyles.styles.ts @@ -2,7 +2,7 @@ import { iconFilledClassName, iconRegularClassName } from '@fluentui/react-icons import { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster'; import { tokens } from '@fluentui/react-theme'; import { shorthands, mergeClasses, makeStyles } from '@griffel/react'; -import { useButtonStyles_unstable } from '../Button/useButtonStyles.styles'; +import { useButtonStyles_unstable } from '../Button/useButtonStyles'; import type { SlotClassNames } from '@fluentui/react-utilities'; import type { ButtonSlots } from '../Button/Button.types'; import type { ToggleButtonState } from './ToggleButton.types'; @@ -28,10 +28,13 @@ const useRootCheckedStyles = makeStyles({ display: 'none', }, - ':hover': { - backgroundColor: tokens.colorNeutralBackground1Hover, - ...shorthands.borderColor(tokens.colorNeutralStroke1Hover), - color: tokens.colorNeutralForeground1Hover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorNeutralBackground1Hover, + ...shorthands.borderColor(tokens.colorNeutralStroke1Hover), + color: tokens.colorNeutralForeground1Hover, + }, }, ':hover:active': { @@ -49,10 +52,13 @@ const useRootCheckedStyles = makeStyles({ color: 'HighlightText', forcedColorAdjust: 'none', - ':hover': { - backgroundColor: 'HighlightText', - ...shorthands.borderColor('Highlight'), - color: 'Highlight', + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: 'HighlightText', + ...shorthands.borderColor('Highlight'), + color: 'Highlight', + }, }, ':hover:active': { @@ -74,8 +80,11 @@ const useRootCheckedStyles = makeStyles({ ...shorthands.borderColor(tokens.colorNeutralStroke1), ...shorthands.borderWidth(tokens.strokeWidthThicker), - ':hover': { - backgroundColor: tokens.colorTransparentBackgroundHover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorTransparentBackgroundHover, + }, }, ':hover:active': { @@ -91,10 +100,13 @@ const useRootCheckedStyles = makeStyles({ ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForegroundOnBrand, - ':hover': { - backgroundColor: tokens.colorBrandBackgroundHover, - ...shorthands.borderColor('transparent'), - color: tokens.colorNeutralForegroundOnBrand, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorBrandBackgroundHover, + ...shorthands.borderColor('transparent'), + color: tokens.colorNeutralForegroundOnBrand, + }, }, ':hover:active': { @@ -111,10 +123,13 @@ const useRootCheckedStyles = makeStyles({ ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForeground2Selected, - ':hover': { - backgroundColor: tokens.colorSubtleBackgroundHover, - ...shorthands.borderColor('transparent'), - color: tokens.colorNeutralForeground2Hover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorSubtleBackgroundHover, + ...shorthands.borderColor('transparent'), + color: tokens.colorNeutralForeground2Hover, + }, }, ':hover:active': { @@ -128,10 +143,13 @@ const useRootCheckedStyles = makeStyles({ ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForeground2BrandSelected, - ':hover': { - backgroundColor: tokens.colorTransparentBackgroundHover, - ...shorthands.borderColor('transparent'), - color: tokens.colorNeutralForeground2BrandHover, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorTransparentBackgroundHover, + ...shorthands.borderColor('transparent'), + color: tokens.colorNeutralForeground2BrandHover, + }, }, ':hover:active': { @@ -149,10 +167,13 @@ const useRootDisabledStyles = makeStyles({ ...shorthands.borderColor(tokens.colorNeutralStrokeDisabled), color: tokens.colorNeutralForegroundDisabled, - ':hover': { - backgroundColor: tokens.colorNeutralBackgroundDisabled, - ...shorthands.borderColor(tokens.colorNeutralStrokeDisabled), - color: tokens.colorNeutralForegroundDisabled, + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorNeutralBackgroundDisabled, + ...shorthands.borderColor(tokens.colorNeutralStrokeDisabled), + color: tokens.colorNeutralForegroundDisabled, + }, }, ':hover:active': { @@ -169,8 +190,11 @@ const useRootDisabledStyles = makeStyles({ primary: { ...shorthands.borderColor('transparent'), - ':hover': { - ...shorthands.borderColor('transparent'), + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + ...shorthands.borderColor('transparent'), + }, }, ':hover:active': { @@ -184,9 +208,12 @@ const useRootDisabledStyles = makeStyles({ backgroundColor: tokens.colorTransparentBackground, ...shorthands.borderColor('transparent'), - ':hover': { - backgroundColor: tokens.colorTransparentBackgroundHover, - ...shorthands.borderColor('transparent'), + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorTransparentBackgroundHover, + ...shorthands.borderColor('transparent'), + }, }, ':hover:active': { @@ -198,9 +225,12 @@ const useRootDisabledStyles = makeStyles({ backgroundColor: tokens.colorTransparentBackground, ...shorthands.borderColor('transparent'), - ':hover': { - backgroundColor: tokens.colorTransparentBackgroundHover, - ...shorthands.borderColor('transparent'), + // Query devices that support hover: https://www.w3.org/TR/mediaqueries-4/#any-input + '@media (any-hover: hover)': { + ':hover': { + backgroundColor: tokens.colorTransparentBackgroundHover, + ...shorthands.borderColor('transparent'), + }, }, ':hover:active': {