Private
Public Access
1
0
Files
power-apps-codeapps-blog-part2/node_modules/@fluentui/react-tabs/lib/components/Tab/useTabStyles.styles.raw.js

686 lines
25 KiB
JavaScript

'use client';
import { makeStyles, mergeClasses, shorthands } from '@griffel/react';
import { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster';
import { tokens, typographyStyles } from '@fluentui/react-theme';
import { useTabAnimatedIndicatorStyles_unstable } from './useTabAnimatedIndicator.styles';
export const tabClassNames = {
root: 'fui-Tab',
icon: 'fui-Tab__icon',
content: 'fui-Tab__content'
};
export const tabReservedSpaceClassNames = {
content: 'fui-Tab__content--reserved-space'
};
// These should match the constants defined in @fluentui/react-icons
// This package avoids taking a dependency on the icons package for only the constants.
const iconClassNames = {
filled: 'fui-Icon-filled',
regular: 'fui-Icon-regular'
};
/**
* Styles for the root slot
*/ const useRootStyles = makeStyles({
root: {
alignItems: 'center',
display: 'grid',
flexShrink: 0,
gridAutoFlow: 'column',
gridTemplateColumns: 'auto',
gridTemplateRows: 'auto',
outlineStyle: 'none',
position: 'relative'
},
button: {
alignItems: 'center',
border: 'none',
borderRadius: tokens.borderRadiusMedium,
cursor: 'pointer',
display: 'grid',
flexShrink: 0,
gridAutoFlow: 'column',
gridTemplateColumns: 'auto',
gridTemplateRows: 'auto',
fontFamily: tokens.fontFamilyBase,
lineHeight: tokens.lineHeightBase300,
outlineStyle: 'none',
position: 'relative',
overflow: 'hidden',
textTransform: 'none'
},
horizontal: {
justifyContent: 'center'
},
vertical: {
justifyContent: 'start'
},
smallHorizontal: {
columnGap: tokens.spacingHorizontalXXS,
padding: `${tokens.spacingVerticalSNudge} ${tokens.spacingHorizontalSNudge}`
},
smallVertical: {
// horizontal spacing is deliberate. This is the gap between icon and content.
columnGap: tokens.spacingHorizontalXXS,
padding: `${tokens.spacingVerticalXXS} ${tokens.spacingHorizontalSNudge}`
},
mediumHorizontal: {
columnGap: tokens.spacingHorizontalSNudge,
padding: `${tokens.spacingVerticalM} ${tokens.spacingHorizontalMNudge}`
},
mediumVertical: {
// horizontal spacing is deliberate. This is the gap between icon and content.
columnGap: tokens.spacingHorizontalSNudge,
padding: `${tokens.spacingVerticalSNudge} ${tokens.spacingHorizontalMNudge}`
},
largeHorizontal: {
columnGap: tokens.spacingHorizontalSNudge,
padding: `${tokens.spacingVerticalL} ${tokens.spacingHorizontalMNudge}`
},
largeVertical: {
// horizontal spacing is deliberate. This is the gap between icon and content.
columnGap: tokens.spacingHorizontalSNudge,
padding: `${tokens.spacingVerticalS} ${tokens.spacingHorizontalMNudge}`
},
transparent: {
backgroundColor: tokens.colorTransparentBackground,
':enabled:hover': {
backgroundColor: tokens.colorTransparentBackgroundHover
},
':enabled:active': {
backgroundColor: tokens.colorTransparentBackgroundPressed
},
[`& .${tabClassNames.icon}`]: {
color: tokens.colorNeutralForeground2
},
[`:enabled:hover .${tabClassNames.icon}`]: {
color: tokens.colorNeutralForeground2Hover
},
[`:enabled:active .${tabClassNames.icon}`]: {
color: tokens.colorNeutralForeground2Pressed
},
[`& .${tabClassNames.content}`]: {
color: tokens.colorNeutralForeground2
},
[`:enabled:hover .${tabClassNames.content}`]: {
color: tokens.colorNeutralForeground2Hover
},
[`:enabled:active .${tabClassNames.content}`]: {
color: tokens.colorNeutralForeground2Pressed
}
},
subtle: {
backgroundColor: tokens.colorSubtleBackground,
':enabled:hover': {
backgroundColor: tokens.colorSubtleBackgroundHover
},
':enabled:active': {
backgroundColor: tokens.colorSubtleBackgroundPressed
},
[`& .${tabClassNames.icon}`]: {
color: tokens.colorNeutralForeground2
},
[`:enabled:hover .${tabClassNames.icon}`]: {
color: tokens.colorNeutralForeground2Hover
},
[`:enabled:active .${tabClassNames.icon}`]: {
color: tokens.colorNeutralForeground2Pressed
},
[`& .${tabClassNames.content}`]: {
color: tokens.colorNeutralForeground2
},
[`:enabled:hover .${tabClassNames.content}`]: {
color: tokens.colorNeutralForeground2Hover
},
[`:enabled:active .${tabClassNames.content}`]: {
color: tokens.colorNeutralForeground2Pressed
}
},
disabledCursor: {
cursor: 'not-allowed'
},
disabled: {
backgroundColor: tokens.colorTransparentBackground,
[`& .${tabClassNames.icon}`]: {
color: tokens.colorNeutralForegroundDisabled
},
[`& .${tabClassNames.content}`]: {
color: tokens.colorNeutralForegroundDisabled
}
},
selected: {
[`& .${tabClassNames.icon}`]: {
color: tokens.colorCompoundBrandForeground1
},
[`:enabled:hover .${tabClassNames.icon}`]: {
color: tokens.colorCompoundBrandForeground1Hover
},
[`:enabled:active .${tabClassNames.icon}`]: {
color: tokens.colorCompoundBrandForeground1Pressed
},
[`& .${tabClassNames.content}`]: {
color: tokens.colorNeutralForeground1
},
[`:enabled:hover .${tabClassNames.content}`]: {
color: tokens.colorNeutralForeground1Hover
},
[`:enabled:active .${tabClassNames.content}`]: {
color: tokens.colorNeutralForeground1Pressed
}
}
});
const useCircularAppearanceStyles = makeStyles({
base: {
borderRadius: tokens.borderRadiusCircular,
border: `solid ${tokens.strokeWidthThin} ${tokens.colorTransparentStroke}`,
[`& .${tabClassNames.icon}`]: {
color: 'inherit'
},
[`& .${tabClassNames.content}`]: {
color: 'inherit'
}
},
small: {
paddingBlock: `calc(${tokens.spacingVerticalXXS} - ${tokens.strokeWidthThin})`
},
medium: {
paddingBlock: `calc(${tokens.spacingVerticalSNudge} - ${tokens.strokeWidthThin})`
},
large: {
paddingBlock: `calc(${tokens.spacingVerticalS} - ${tokens.strokeWidthThin})`
},
subtle: {
backgroundColor: tokens.colorSubtleBackground,
color: tokens.colorNeutralForeground2,
':enabled:hover': {
backgroundColor: tokens.colorSubtleBackgroundHover,
border: `solid ${tokens.strokeWidthThin} ${tokens.colorNeutralStroke1Hover}`,
color: tokens.colorNeutralForeground2Hover
},
':enabled:active': {
backgroundColor: tokens.colorSubtleBackgroundPressed,
border: `solid ${tokens.strokeWidthThin} ${tokens.colorNeutralStroke1Pressed}`,
color: tokens.colorNeutralForeground2Pressed
},
'@media (forced-colors: active)': {
border: `solid ${tokens.strokeWidthThin} Canvas`
}
},
subtleSelected: {
backgroundColor: tokens.colorBrandBackground2,
border: `solid ${tokens.strokeWidthThin} ${tokens.colorCompoundBrandStroke}`,
color: tokens.colorBrandForeground2,
':enabled:hover': {
backgroundColor: tokens.colorBrandBackground2Hover,
border: `solid ${tokens.strokeWidthThin} ${tokens.colorCompoundBrandStrokeHover}`,
color: tokens.colorBrandForeground2Hover
},
':enabled:active': {
backgroundColor: tokens.colorBrandBackground2Pressed,
border: `solid ${tokens.strokeWidthThin} ${tokens.colorCompoundBrandStrokePressed}`,
color: tokens.colorBrandForeground2Pressed
},
'@media (forced-colors: active)': {
border: `solid ${tokens.strokeWidthThin} Highlight`
}
},
subtleDisabled: {
backgroundColor: tokens.colorSubtleBackground,
color: tokens.colorNeutralForegroundDisabled
},
subtleDisabledSelected: {
backgroundColor: tokens.colorNeutralBackgroundDisabled,
border: `solid ${tokens.strokeWidthThin} ${tokens.colorNeutralStrokeDisabled}`,
color: tokens.colorNeutralForegroundDisabled
},
filled: {
backgroundColor: tokens.colorNeutralBackground3,
color: tokens.colorNeutralForeground2,
':enabled:hover': {
backgroundColor: tokens.colorNeutralBackground3Hover,
color: tokens.colorNeutralForeground2Hover
},
':enabled:active': {
backgroundColor: tokens.colorNeutralBackground3Pressed,
color: tokens.colorNeutralForeground2Pressed
},
'@media (forced-colors: active)': {
':enabled:hover': {
backgroundColor: 'Highlight',
forcedColorAdjust: 'none',
[`& .${tabClassNames.content}`]: {
color: 'HighlightText'
},
[`& .${iconClassNames.filled}`]: {
color: 'HighlightText'
},
[`& .${iconClassNames.regular}`]: {
color: 'HighlightText'
}
}
}
},
filledSelected: {
backgroundColor: tokens.colorBrandBackground,
color: tokens.colorNeutralForegroundOnBrand,
':enabled:hover': {
backgroundColor: tokens.colorBrandBackgroundHover,
color: tokens.colorNeutralForegroundOnBrand
},
':enabled:active': {
backgroundColor: tokens.colorBrandBackgroundPressed,
color: tokens.colorNeutralForegroundOnBrand
},
'@media (forced-colors: active)': {
':enabled': {
backgroundColor: 'ButtonText',
[`& .${tabClassNames.content}`]: {
color: 'ButtonFace',
forcedColorAdjust: 'none'
}
},
[`:enabled .${tabClassNames.icon}`]: {
color: 'ButtonFace'
}
}
},
filledDisabled: {
backgroundColor: tokens.colorNeutralBackgroundDisabled,
color: tokens.colorNeutralForegroundDisabled
},
filledDisabledSelected: {
backgroundColor: tokens.colorNeutralBackgroundDisabled,
border: `solid ${tokens.strokeWidthThin} ${tokens.colorNeutralStrokeDisabled}`,
color: tokens.colorNeutralForegroundDisabled
}
});
/**
* Focus styles for the root slot
*/ const useFocusStyles = makeStyles({
// Tab creates a custom focus indicator because the default focus indicator
// is applied using an ::after pseudo-element on the root. Since the selection
// indicator uses an ::after pseudo-element on the root, there is a conflict.
base: createCustomFocusIndicatorStyle({
...shorthands.borderColor('transparent'),
outlineWidth: tokens.strokeWidthThick,
outlineColor: 'transparent',
outlineStyle: 'solid',
boxShadow: `
${tokens.shadow4},
0 0 0 ${tokens.strokeWidthThick} ${tokens.colorStrokeFocus2}
`,
zIndex: 1
}, {
enableOutline: true
}),
circular: createCustomFocusIndicatorStyle({
...shorthands.borderColor('transparent'),
outlineWidth: tokens.strokeWidthThick,
outlineColor: 'transparent',
outlineStyle: 'solid',
boxShadow: `
${tokens.shadow4},
0 0 0 ${tokens.strokeWidthThick} ${tokens.colorStrokeFocus2},
0 0 0 ${tokens.strokeWidthThin} ${tokens.colorNeutralStrokeOnBrand} inset
`,
zIndex: 1
}, {
enableOutline: true
})
});
/** Indicator styles for when pending selection */ const usePendingIndicatorStyles = makeStyles({
base: {
':hover::before': {
backgroundColor: tokens.colorNeutralStroke1Hover,
borderRadius: tokens.borderRadiusCircular,
content: '""',
position: 'absolute'
},
':active::before': {
backgroundColor: tokens.colorNeutralStroke1Pressed,
borderRadius: tokens.borderRadiusCircular,
content: '""',
position: 'absolute'
},
'@media (forced-colors: active)': {
':hover::before': {
backgroundColor: 'Highlight'
},
':active::before': {
backgroundColor: 'Highlight'
}
}
},
disabled: {
':hover::before': {
backgroundColor: tokens.colorTransparentStroke
},
':active::before': {
backgroundColor: tokens.colorTransparentStroke
},
'@media (forced-colors: active)': {
':hover::before': {
backgroundColor: 'transparent'
},
':active::before': {
backgroundColor: 'transparent'
}
}
},
smallHorizontal: {
'::before': {
bottom: 0,
height: tokens.strokeWidthThick,
left: tokens.spacingHorizontalSNudge,
right: tokens.spacingHorizontalSNudge
}
},
smallVertical: {
'::before': {
bottom: tokens.spacingVerticalXS,
left: 0,
top: tokens.spacingVerticalXS,
width: tokens.strokeWidthThicker
}
},
mediumHorizontal: {
'::before': {
bottom: 0,
height: tokens.strokeWidthThicker,
left: tokens.spacingHorizontalM,
right: tokens.spacingHorizontalM
}
},
mediumVertical: {
'::before': {
bottom: tokens.spacingVerticalS,
left: 0,
top: tokens.spacingVerticalS,
width: tokens.strokeWidthThicker
}
},
largeHorizontal: {
'::before': {
bottom: 0,
height: tokens.strokeWidthThicker,
left: tokens.spacingHorizontalM,
right: tokens.spacingHorizontalM
}
},
largeVertical: {
'::before': {
bottom: tokens.spacingVerticalMNudge,
left: 0,
top: tokens.spacingVerticalMNudge,
width: tokens.strokeWidthThicker
}
}
});
const useActiveIndicatorStyles = makeStyles({
base: {
'::after': {
backgroundColor: tokens.colorTransparentStroke,
borderRadius: tokens.borderRadiusCircular,
content: '""',
position: 'absolute'
}
},
selected: {
'::after': {
backgroundColor: tokens.colorCompoundBrandStroke
},
':enabled:hover::after': {
backgroundColor: tokens.colorCompoundBrandStrokeHover
},
':enabled:active::after': {
backgroundColor: tokens.colorCompoundBrandStrokePressed
},
'@media (forced-colors: active)': {
'::after': {
backgroundColor: 'ButtonText'
},
':enabled:hover::after': {
backgroundColor: 'ButtonText'
},
':enabled:active::after': {
backgroundColor: 'ButtonText'
}
}
},
disabled: {
'::after': {
backgroundColor: tokens.colorNeutralForegroundDisabled
}
},
smallHorizontal: {
'::after': {
bottom: 0,
height: tokens.strokeWidthThick,
left: tokens.spacingHorizontalSNudge,
right: tokens.spacingHorizontalSNudge
}
},
smallVertical: {
'::after': {
bottom: tokens.spacingVerticalXS,
left: '0',
top: tokens.spacingVerticalXS,
width: tokens.strokeWidthThicker
}
},
mediumHorizontal: {
'::after': {
bottom: '0',
height: tokens.strokeWidthThicker,
left: tokens.spacingHorizontalM,
right: tokens.spacingHorizontalM
}
},
mediumVertical: {
'::after': {
bottom: tokens.spacingVerticalS,
left: 0,
top: tokens.spacingVerticalS,
width: tokens.strokeWidthThicker
}
},
largeHorizontal: {
'::after': {
bottom: 0,
height: tokens.strokeWidthThicker,
left: tokens.spacingHorizontalM,
right: tokens.spacingHorizontalM
}
},
largeVertical: {
'::after': {
bottom: tokens.spacingVerticalMNudge,
left: 0,
top: tokens.spacingVerticalMNudge,
width: tokens.strokeWidthThicker
}
}
});
/**
* Styles for the icon slot.
*/ const useIconStyles = makeStyles({
base: {
gridColumnStart: 1,
gridRowStart: 1,
alignItems: 'center',
display: 'inline-flex',
justifyContent: 'center',
overflow: 'hidden',
[`& .${iconClassNames.filled}`]: {
display: 'none'
},
[`& .${iconClassNames.regular}`]: {
display: 'inline'
}
},
// per design, the small and medium font sizes are the same.
// the size prop only affects spacing.
small: {
fontSize: '20px',
height: '20px',
width: '20px'
},
medium: {
fontSize: '20px',
height: '20px',
width: '20px'
},
large: {
fontSize: '24px',
height: '24px',
width: '24px'
},
selected: {
[`& .${iconClassNames.filled}`]: {
display: 'inline'
},
[`& .${iconClassNames.regular}`]: {
display: 'none'
}
}
});
/**
* Styles for the content slot (children)
*/ const useContentStyles = makeStyles({
base: {
...typographyStyles.body1,
overflow: 'hidden',
// content padding is the same for medium & small, horizontal & vertical
padding: `${tokens.spacingVerticalNone} ${tokens.spacingHorizontalXXS}`
},
selected: {
...typographyStyles.body1Strong
},
large: {
...typographyStyles.body2
},
largeSelected: {
...typographyStyles.subtitle2
},
noIconBefore: {
gridColumnStart: 1,
gridRowStart: 1
},
iconBefore: {
gridColumnStart: 2,
gridRowStart: 1
},
placeholder: {
visibility: 'hidden'
}
});
/**
* Apply styling to the Tab slots based on the state
*/ export const useTabStyles_unstable = (state)=>{
'use no memo';
useTabIndicatorStyles_unstable(state);
useTabButtonStyles_unstable(state, state.root);
useTabContentStyles_unstable(state);
return state;
};
/**
* Applies styles for the Tab indicator based on its current state.
*
* This hook is typically used internally by `useTabStyles_unstable`. You should
* only use it directly if you're creating a custom `Tab` component.
*
* @param state - The `Tab` component's current state
* @returns The state object with updated button styles
*/ export const useTabIndicatorStyles_unstable = (state)=>{
'use no memo';
const rootStyles = useRootStyles();
const pendingIndicatorStyles = usePendingIndicatorStyles();
const activeIndicatorStyles = useActiveIndicatorStyles();
const { appearance, disabled, selected, size, vertical } = state;
const classes = [
tabClassNames.root,
rootStyles.root
];
if (appearance !== 'subtle-circular' && appearance !== 'filled-circular') {
classes.push(// pending indicator (before pseudo element)
pendingIndicatorStyles.base, size === 'small' && (vertical ? pendingIndicatorStyles.smallVertical : pendingIndicatorStyles.smallHorizontal), size === 'medium' && (vertical ? pendingIndicatorStyles.mediumVertical : pendingIndicatorStyles.mediumHorizontal), size === 'large' && (vertical ? pendingIndicatorStyles.largeVertical : pendingIndicatorStyles.largeHorizontal), disabled && pendingIndicatorStyles.disabled, // active indicator (after pseudo element)
selected && activeIndicatorStyles.base, selected && !disabled && activeIndicatorStyles.selected, selected && size === 'small' && (vertical ? activeIndicatorStyles.smallVertical : activeIndicatorStyles.smallHorizontal), selected && size === 'medium' && (vertical ? activeIndicatorStyles.mediumVertical : activeIndicatorStyles.mediumHorizontal), selected && size === 'large' && (vertical ? activeIndicatorStyles.largeVertical : activeIndicatorStyles.largeHorizontal), selected && disabled && activeIndicatorStyles.disabled);
}
state.root.className = mergeClasses(...classes, state.root.className);
useTabAnimatedIndicatorStyles_unstable(state);
return state;
};
/**
* Applies styles to the Tab button slot based on its current state.
*
* This hook is typically used internally by `useTabStyles_unstable`. You should
* only use it directly if you're creating a custom `Tab` component.
*
* @param state - The Tab component's current state
* @param slot - The button slot of the Tab component
* @returns The state object with updated button styles
*/ export const useTabButtonStyles_unstable = (state, slot)=>{
'use no memo';
const rootStyles = useRootStyles();
const focusStyles = useFocusStyles();
const circularStyles = useCircularAppearanceStyles();
const { appearance, disabled, selected, size, vertical } = state;
const isSubtleCircular = appearance === 'subtle-circular';
const isFilledCircular = appearance === 'filled-circular';
const isCircular = isSubtleCircular || isFilledCircular;
const circularAppearance = [
circularStyles.base,
focusStyles.circular,
// sizes
size === 'small' && circularStyles.small,
size === 'medium' && circularStyles.medium,
size === 'large' && circularStyles.large,
// subtle-circular appearance
isSubtleCircular && circularStyles.subtle,
selected && isSubtleCircular && circularStyles.subtleSelected,
disabled && isSubtleCircular && circularStyles.subtleDisabled,
selected && disabled && isSubtleCircular && circularStyles.subtleDisabledSelected,
// filled-circular appearance
isFilledCircular && circularStyles.filled,
selected && isFilledCircular && circularStyles.filledSelected,
disabled && isFilledCircular && circularStyles.filledDisabled,
selected && disabled && isFilledCircular && circularStyles.filledDisabledSelected
];
const regularAppearance = [
focusStyles.base,
!disabled && appearance === 'subtle' && rootStyles.subtle,
!disabled && appearance === 'transparent' && rootStyles.transparent,
!disabled && selected && rootStyles.selected,
disabled && rootStyles.disabled
];
slot.className = mergeClasses(rootStyles.button, // orientation
vertical ? rootStyles.vertical : rootStyles.horizontal, // size
size === 'small' && (vertical ? rootStyles.smallVertical : rootStyles.smallHorizontal), size === 'medium' && (vertical ? rootStyles.mediumVertical : rootStyles.mediumHorizontal), size === 'large' && (vertical ? rootStyles.largeVertical : rootStyles.largeHorizontal), ...isCircular ? circularAppearance : regularAppearance, disabled && rootStyles.disabledCursor, slot.className);
return state;
};
/**
* Applies styles to the Tab content slot based on its current state.
*
* This hook is typically used internally by `useTabStyles_unstable`. You should
* only use it directly if you're creating a custom `Tab` component.
*
* @param state - The Tab component's current state
* @returns The state object with updated content styles
*/ export const useTabContentStyles_unstable = (state)=>{
'use no memo';
const iconStyles = useIconStyles();
const contentStyles = useContentStyles();
const { selected, size } = state;
if (state.icon) {
state.icon.className = mergeClasses(tabClassNames.icon, iconStyles.base, iconStyles[size], selected && iconStyles.selected, state.icon.className);
}
// This needs to be before state.content.className is updated
if (state.contentReservedSpace) {
state.contentReservedSpace.className = mergeClasses(tabReservedSpaceClassNames.content, contentStyles.base, size === 'large' ? contentStyles.largeSelected : contentStyles.selected, state.icon ? contentStyles.iconBefore : contentStyles.noIconBefore, contentStyles.placeholder, state.content.className);
// FIXME: this is a deprecated API
// should be removed in the next major version
// eslint-disable-next-line @typescript-eslint/no-deprecated
state.contentReservedSpaceClassName = state.contentReservedSpace.className;
}
state.content.className = mergeClasses(tabClassNames.content, contentStyles.base, size === 'large' && contentStyles.large, selected && (size === 'large' ? contentStyles.largeSelected : contentStyles.selected), state.icon ? contentStyles.iconBefore : contentStyles.noIconBefore, state.content.className);
return state;
};