275 lines
11 KiB
JavaScript
275 lines
11 KiB
JavaScript
'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;
|
|
};
|