'use client'; 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'; export const toggleButtonClassNames = { root: 'fui-ToggleButton', icon: 'fui-ToggleButton__icon' }; const useRootCheckedStyles = makeStyles({ // Base styles base: { backgroundColor: tokens.colorNeutralBackground1Selected, ...shorthands.borderColor(tokens.colorNeutralStroke1), color: tokens.colorNeutralForeground1Selected, ...shorthands.borderWidth(tokens.strokeWidthThin), [`& .${iconFilledClassName}`]: { display: 'inline' }, [`& .${iconRegularClassName}`]: { display: 'none' }, ':hover': { backgroundColor: tokens.colorNeutralBackground1Hover, ...shorthands.borderColor(tokens.colorNeutralStroke1Hover), color: tokens.colorNeutralForeground1Hover }, ':hover:active,:active:focus-visible': { backgroundColor: tokens.colorNeutralBackground1Pressed, ...shorthands.borderColor(tokens.colorNeutralStroke1Pressed), color: tokens.colorNeutralForeground1Pressed } }, // High contrast styles highContrast: { '@media (forced-colors: active)': { backgroundColor: 'Highlight', ...shorthands.borderColor('Highlight'), color: 'HighlightText', forcedColorAdjust: 'none', ':hover': { backgroundColor: 'HighlightText', ...shorthands.borderColor('Highlight'), color: 'Highlight' }, ':hover:active,:active:focus-visible': { backgroundColor: 'HighlightText', ...shorthands.borderColor('Highlight'), color: 'Highlight' }, ':focus': { border: '1px solid HighlightText', outlineColor: 'Highlight' } } }, // Appearance variations outline: { backgroundColor: tokens.colorTransparentBackgroundSelected, ...shorthands.borderColor(tokens.colorNeutralStroke1), ...shorthands.borderWidth(tokens.strokeWidthThicker), ':hover': { backgroundColor: tokens.colorTransparentBackgroundHover }, ':hover:active,:active:focus-visible': { backgroundColor: tokens.colorTransparentBackgroundPressed }, ...createCustomFocusIndicatorStyle({ ...shorthands.borderColor(tokens.colorNeutralStroke1) }) }, primary: { backgroundColor: tokens.colorBrandBackgroundSelected, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForegroundOnBrand, ':hover': { backgroundColor: tokens.colorBrandBackgroundHover, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForegroundOnBrand }, ':hover:active,:active:focus-visible': { backgroundColor: tokens.colorBrandBackgroundPressed, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForegroundOnBrand } }, secondary: { }, subtle: { backgroundColor: tokens.colorSubtleBackgroundSelected, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForeground2Selected, ':hover': { backgroundColor: tokens.colorSubtleBackgroundHover, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForeground2Hover }, ':hover:active,:active:focus-visible': { backgroundColor: tokens.colorSubtleBackgroundPressed, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForeground2Pressed } }, transparent: { backgroundColor: tokens.colorTransparentBackgroundSelected, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForeground2BrandSelected, ':hover': { backgroundColor: tokens.colorTransparentBackgroundHover, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForeground2BrandHover }, ':hover:active,:active:focus-visible': { backgroundColor: tokens.colorTransparentBackgroundPressed, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForeground2BrandPressed } } }); const useCheckedAccessibleStyles = makeStyles({ // Base styles base: { backgroundColor: tokens.colorBrandBackground, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForegroundOnBrand, ':hover': { backgroundColor: tokens.colorBrandBackgroundHover, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForegroundOnBrand }, ':hover:active,:active:focus-visible': { backgroundColor: tokens.colorBrandBackgroundPressed, ...shorthands.borderColor('transparent'), color: tokens.colorNeutralForegroundOnBrand } }, // Appearance variations outline: { // There's no longer a reason to thicken the outline variant's border ...shorthands.borderWidth(tokens.strokeWidthThin) }, primary: { // primary has an inner stroke for the checked style outline: `${tokens.strokeWidthThin} solid ${tokens.colorNeutralForegroundOnBrand}`, outlineOffset: `calc(${tokens.strokeWidthThicker} * -1)`, // need to not have the default focus style that removes the outline ...createCustomFocusIndicatorStyle({ outline: `${tokens.strokeWidthThin} solid ${tokens.colorNeutralForegroundOnBrand}`, outlineOffset: `calc(${tokens.strokeWidthThickest} * -1)` }) }, subtle: { // override subtle-appearance-specific icon color on hover ':hover': { [`& .${toggleButtonClassNames.icon}`]: { color: tokens.colorNeutralForegroundOnBrand } } }, transparent: { }, secondary: { } }); const useRootDisabledStyles = makeStyles({ // Base styles base: { backgroundColor: tokens.colorNeutralBackgroundDisabled, ...shorthands.borderColor(tokens.colorNeutralStrokeDisabled), color: tokens.colorNeutralForegroundDisabled, ':hover': { backgroundColor: tokens.colorNeutralBackgroundDisabled, ...shorthands.borderColor(tokens.colorNeutralStrokeDisabled), color: tokens.colorNeutralForegroundDisabled }, ':hover:active,:active:focus-visible': { backgroundColor: tokens.colorNeutralBackgroundDisabled, ...shorthands.borderColor(tokens.colorNeutralStrokeDisabled), color: tokens.colorNeutralForegroundDisabled } }, // Appearance variations outline: { }, primary: { ...shorthands.borderColor('transparent'), ':hover': { ...shorthands.borderColor('transparent') }, ':hover:active,:active:focus-visible': { ...shorthands.borderColor('transparent') } }, secondary: { }, subtle: { backgroundColor: tokens.colorTransparentBackground, ...shorthands.borderColor('transparent'), ':hover': { backgroundColor: tokens.colorTransparentBackgroundHover, ...shorthands.borderColor('transparent') }, ':hover:active,:active:focus-visible': { backgroundColor: tokens.colorTransparentBackgroundPressed, ...shorthands.borderColor('transparent') } }, transparent: { backgroundColor: tokens.colorTransparentBackground, ...shorthands.borderColor('transparent'), ':hover': { backgroundColor: tokens.colorTransparentBackgroundHover, ...shorthands.borderColor('transparent') }, ':hover:active,:active:focus-visible': { backgroundColor: tokens.colorTransparentBackgroundPressed, ...shorthands.borderColor('transparent') } } }); const useIconCheckedStyles = makeStyles({ // Appearance variations with isAccessible=false subtleOrTransparent: { color: tokens.colorNeutralForeground2BrandSelected }, // High contrast styles highContrast: { '@media (forced-colors: active)': { forcedColorAdjust: 'auto' } } }); const usePrimaryHighContrastStyles = makeStyles({ // Do not use primary variant high contrast styles for toggle buttons // otherwise there isn't enough difference between on/off states base: { '@media (forced-colors: active)': { backgroundColor: 'ButtonFace', ...shorthands.borderColor('ButtonBorder'), color: 'ButtonText', forcedColorAdjust: 'auto' } }, disabled: { '@media (forced-colors: active)': { ...shorthands.borderColor('GrayText'), color: 'GrayText', ':focus': { ...shorthands.borderColor('GrayText') } } } }); export const useToggleButtonStyles_unstable = (state)=>{ 'use no memo'; const rootCheckedStyles = useRootCheckedStyles(); const accessibleCheckedStyles = useCheckedAccessibleStyles(); const rootDisabledStyles = useRootDisabledStyles(); const iconCheckedStyles = useIconCheckedStyles(); const primaryHighContrastStyles = usePrimaryHighContrastStyles(); const { appearance, checked, disabled, disabledFocusable, isAccessible } = state; state.root.className = mergeClasses(toggleButtonClassNames.root, // Primary high contrast styles appearance === 'primary' && primaryHighContrastStyles.base, appearance === 'primary' && (disabled || disabledFocusable) && primaryHighContrastStyles.disabled, // Checked styles checked && rootCheckedStyles.base, checked && rootCheckedStyles.highContrast, appearance && checked && rootCheckedStyles[appearance], // Opt-in accessible checked styles isAccessible && checked && accessibleCheckedStyles.base, isAccessible && appearance && checked && accessibleCheckedStyles[appearance], // Disabled styles (disabled || disabledFocusable) && rootDisabledStyles.base, appearance && (disabled || disabledFocusable) && rootDisabledStyles[appearance], // User provided class name state.root.className); if (state.icon) { state.icon.className = mergeClasses(toggleButtonClassNames.icon, checked && !isAccessible && (appearance === 'subtle' || appearance === 'transparent') && iconCheckedStyles.subtleOrTransparent, iconCheckedStyles.highContrast, state.icon.className); } useButtonStyles_unstable(state); return state; };