diff --git a/change/@fluentui-react-avatar-0172fa1d-9de1-463f-9fe9-29f20a05717b.json b/change/@fluentui-react-avatar-0172fa1d-9de1-463f-9fe9-29f20a05717b.json new file mode 100644 index 0000000000000..53a79cc9490cb --- /dev/null +++ b/change/@fluentui-react-avatar-0172fa1d-9de1-463f-9fe9-29f20a05717b.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "fix: Fix wrong border radius for outline in webkit browsers.", + "packageName": "@fluentui/react-avatar", + "email": "esteban.230@hotmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-avatar/src/components/AvatarGroup/useAvatarGroupStyles.ts b/packages/react-components/react-avatar/src/components/AvatarGroup/useAvatarGroupStyles.ts index 047014c096cf6..04fe6f70d00cc 100644 --- a/packages/react-components/react-avatar/src/components/AvatarGroup/useAvatarGroupStyles.ts +++ b/packages/react-components/react-avatar/src/components/AvatarGroup/useAvatarGroupStyles.ts @@ -50,6 +50,11 @@ const useOverflowButtonStyles = makeStyles({ ...shorthands.borderRadius(tokens.borderRadiusCircular), ...shorthands.borderStyle('solid'), ...shorthands.padding(0), + + // match color to Avatar's outline color + '@media (forced-colors: active)': { + ...shorthands.borderColor('CanvasText'), + }, }, // These styles match the default button styles @@ -121,7 +126,7 @@ export const useAvatarGroupStyles_unstable = (state: AvatarGroupState): AvatarGr const overflowContentStyles = useOverflowContentStyles(); const overflowButtonStyles = useOverflowButtonStyles(); - const groupChildClassName = useGroupChildClassName(layout, size); + const groupChildClassName = useGroupChildClassName(layout, size, true); state.root.className = mergeClasses( avatarGroupClassNames.root, diff --git a/packages/react-components/react-avatar/src/components/AvatarGroupItem/useAvatarGroupItemStyles.ts b/packages/react-components/react-avatar/src/components/AvatarGroupItem/useAvatarGroupItemStyles.ts index db27f04cfb75d..cf3871d2f7990 100644 --- a/packages/react-components/react-avatar/src/components/AvatarGroupItem/useAvatarGroupItemStyles.ts +++ b/packages/react-components/react-avatar/src/components/AvatarGroupItem/useAvatarGroupItemStyles.ts @@ -96,12 +96,91 @@ const usePieStyles = makeStyles({ const useStackStyles = makeStyles({ base: { - outlineColor: tokens.colorNeutralBackground2, - outlineStyle: 'solid', + '&::after': { + content: "''", + position: 'absolute', + display: 'inline-flex', + // Border is used instead of outline due to a bug in webkit browsers where border-radius is ignored in outline. + ...shorthands.borderColor(tokens.colorNeutralBackground2), + ...shorthands.borderRadius(tokens.borderRadiusCircular), + ...shorthands.borderStyle('solid'), + + '@media (forced-colors: active)': { + forcedColorAdjust: 'none', + }, + }, + }, + overflowButton: { + // border-color has to be set to transparent when there's focus due to the outline overlapping the focus ring. + '&:focus': { + '&::after': { + ...shorthands.borderColor('transparent'), + }, + }, + // hide inner border when using high contrast mode and use the outer (::after) to match Avatar's outline + '@media (forced-colors: active)': { + ...shorthands.borderColor('Canvas'), + }, + }, + thick: { + '&::after': { + width: '100%', + height: '100%', + left: `calc(-1 * ${tokens.strokeWidthThick})`, + top: `calc(-1 * ${tokens.strokeWidthThick})`, + ...shorthands.borderWidth(tokens.strokeWidthThick), + }, + }, + thicker: { + '&::after': { + width: '100%', + height: '100%', + left: `calc(-1 * ${tokens.strokeWidthThicker})`, + top: `calc(-1 * ${tokens.strokeWidthThicker})`, + ...shorthands.borderWidth(tokens.strokeWidthThicker), + }, + }, + thickest: { + '&::after': { + width: '100%', + height: '100%', + left: `calc(-1 * ${tokens.strokeWidthThickest})`, + top: `calc(-1 * ${tokens.strokeWidthThickest})`, + ...shorthands.borderWidth(tokens.strokeWidthThickest), + }, + }, + borderThin: { + '&::after': { + width: `calc(100% + ${tokens.strokeWidthThin} * 2)`, + height: `calc(100% + ${tokens.strokeWidthThin} * 2)`, + left: `calc(-1 * (${tokens.strokeWidthThick} + ${tokens.strokeWidthThin}))`, + top: `calc(-1 * (${tokens.strokeWidthThick} + ${tokens.strokeWidthThin}))`, + }, + }, + borderThick: { + '&::after': { + width: `calc(100% + ${tokens.strokeWidthThick} * 2)`, + height: `calc(100% + ${tokens.strokeWidthThick} * 2)`, + left: `calc(-1 * ${tokens.strokeWidthThick} * 2)`, + top: `calc(-1 * ${tokens.strokeWidthThick} * 2)`, + }, + }, + borderThicker: { + '&::after': { + width: `calc(100% + ${tokens.strokeWidthThicker} * 2)`, + height: `calc(100% + ${tokens.strokeWidthThicker} * 2)`, + left: `calc(-1 * ${tokens.strokeWidthThicker} * 2)`, + top: `calc(-1 * ${tokens.strokeWidthThicker} * 2)`, + }, + }, + borderThickest: { + '&::after': { + width: `calc(100% + ${tokens.strokeWidthThickest} * 2)`, + height: `calc(100% + ${tokens.strokeWidthThickest} * 2)`, + left: `calc(-1 * ${tokens.strokeWidthThickest} * 2)`, + top: `calc(-1 * ${tokens.strokeWidthThickest} * 2)`, + }, }, - thick: { outlineWidth: tokens.strokeWidthThick }, - thicker: { outlineWidth: tokens.strokeWidthThicker }, - thickest: { outlineWidth: tokens.strokeWidthThickest }, xxs: { '&:not(:first-child)': { marginLeft: `calc(-1 * ${tokens.spacingHorizontalXXS})` } }, xs: { '&:not(:first-child)': { marginLeft: `calc(-1 * ${tokens.spacingHorizontalXS})` } }, s: { '&:not(:first-child)': { marginLeft: `calc(-1 * ${tokens.spacingHorizontalS})` } }, @@ -182,7 +261,11 @@ export const useAvatarGroupItemStyles_unstable = (state: AvatarGroupItemState): * Hook for getting the className for the children of AvatarGroup. This hook will provide the spacing and outlines * needed for each layout. */ -export const useGroupChildClassName = (layout: AvatarGroupProps['layout'], size: AvatarSizes): string => { +export const useGroupChildClassName = ( + layout: AvatarGroupProps['layout'], + size: AvatarSizes, + isOverflowButton?: boolean, +): string => { const stackStyles = useStackStyles(); const spreadStyles = useSpreadStyles(); const layoutClasses = []; @@ -199,6 +282,22 @@ export const useGroupChildClassName = (layout: AvatarGroupProps['layout'], size: layoutClasses.push(stackStyles.thickest); } + // When the child is an overflowButton, we have to calculate the overflowButton's border + width + outline width + // since the ::after pseudo-element doesn't take the overflowButton's border for its size. + if (isOverflowButton) { + layoutClasses.push(stackStyles.overflowButton); + + if (size < 36) { + layoutClasses.push(stackStyles.borderThin); + } else if (size < 56) { + layoutClasses.push(stackStyles.borderThick); + } else if (size < 72) { + layoutClasses.push(stackStyles.borderThicker); + } else { + layoutClasses.push(stackStyles.borderThickest); + } + } + if (size < 24) { layoutClasses.push(stackStyles.xxs); } else if (size < 48) {