diff --git a/CHANGELOG.md b/CHANGELOG.md index d00cb70169..6209b8e284 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,11 +16,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] - ### BREAKING CHANGES - Rename `context` prop to `mountNode` in `PortalInner` @layershifter ([#1288](https://github.com/stardust-ui/react/pull/1288)) - Updated Teams' theme color palette values, removed color related site variables @mnajdova ([#1069](https://github.com/stardust-ui/react/pull/1069)) - Remove `defaultTarget` prop in `Popup` component @layershifter ([#1153](https://github.com/stardust-ui/react/pull/1153)) +- Add focus border styling mechanism @Bugaa92 in Teams theme ([#1269](https://github.com/stardust-ui/react/pull/1269)) ### Features - Add default child a11y behavior to `Menu` related behaviors @silviuavram ([#1282](https://github.com/stardust-ui/react/pull/1282)) diff --git a/docs/src/examples/components/Attachment/Slots/AttachmentActionExample.shorthand.tsx b/docs/src/examples/components/Attachment/Slots/AttachmentActionExample.shorthand.tsx index 49f1de37d9..a46db0ac09 100644 --- a/docs/src/examples/components/Attachment/Slots/AttachmentActionExample.shorthand.tsx +++ b/docs/src/examples/components/Attachment/Slots/AttachmentActionExample.shorthand.tsx @@ -9,23 +9,11 @@ class AttachmentActionExampleShorthand extends React.Component {
) diff --git a/docs/src/examples/components/Attachment/Types/AttachmentProgressExample.shorthand.tsx b/docs/src/examples/components/Attachment/Types/AttachmentProgressExample.shorthand.tsx index 26e2408f71..0259c7f7c4 100644 --- a/docs/src/examples/components/Attachment/Types/AttachmentProgressExample.shorthand.tsx +++ b/docs/src/examples/components/Attachment/Types/AttachmentProgressExample.shorthand.tsx @@ -4,13 +4,7 @@ import { Attachment } from '@stardust-ui/react' const AttachmentProgressExampleShorthand = () => ( alert("'X' is clicked!"), - }} + action={{ icon: 'close', onClick: () => alert("'X' is clicked!") }} progress={33} /> ) diff --git a/docs/src/examples/components/Attachment/Variations/AttachmentActionableExample.shorthand.tsx b/docs/src/examples/components/Attachment/Variations/AttachmentActionableExample.shorthand.tsx index a5d4b85d93..4380c299ac 100644 --- a/docs/src/examples/components/Attachment/Variations/AttachmentActionableExample.shorthand.tsx +++ b/docs/src/examples/components/Attachment/Variations/AttachmentActionableExample.shorthand.tsx @@ -14,13 +14,7 @@ class AttachmentActionableExampleShorthand extends React.Component { icon="table" header="Document.docx" description="800 Kb" - action={{ - icon: { - name: 'more', - outline: true, - }, - onClick: this.handleClick('More Action'), - }} + action={{ icon: 'more', onClick: this.handleClick('More Action') }} progress={33} onClick={this.handleClick('Attachment')} /> diff --git a/docs/src/examples/components/Button/Usage/ButtonUsageExample.shorthand.tsx b/docs/src/examples/components/Button/Usage/ButtonUsageExample.shorthand.tsx index 120423fb12..9a65ae1db9 100644 --- a/docs/src/examples/components/Button/Usage/ButtonUsageExample.shorthand.tsx +++ b/docs/src/examples/components/Button/Usage/ButtonUsageExample.shorthand.tsx @@ -8,7 +8,6 @@ const ButtonUsageExampleShorthand = () => ( componentVariables: { Button: siteVariables => ({ color: siteVariables.colors.brand[600], - colorActive: siteVariables.colors.brand[300], colorHover: siteVariables.colors.brand[300], colorFocus: siteVariables.colors.brand[900], backgroundColor: '#252424', // no mapping color - tried - siteVariables.colors.grey[750] @@ -16,10 +15,7 @@ const ButtonUsageExampleShorthand = () => ( backgroundColorHover: siteVariables.colors.brand[50], backgroundColorFocus: siteVariables.colors.brand[200], borderColor: siteVariables.colors.brand[200], - borderColorActive: siteVariables.colors.brand[300], borderColorHover: siteVariables.colors.brand[300], - borderColorFocus: siteVariables.colors.grey[900], - borderColorFocusIndicator: siteVariables.colors.brand[900], }), }, }} @@ -34,7 +30,6 @@ const ButtonUsageExampleShorthand = () => ( componentVariables: { Button: siteVariables => ({ color: siteVariables.colors.brand[600], - colorActive: siteVariables.colors.brand[600], colorHover: siteVariables.colors.brand[600], colorFocus: siteVariables.colors.brand[900], backgroundColor: siteVariables.colors.white, @@ -42,10 +37,7 @@ const ButtonUsageExampleShorthand = () => ( backgroundColorHover: siteVariables.colors.brand[50], backgroundColorFocus: siteVariables.colors.brand[200], borderColor: siteVariables.colors.brand[200], - borderColorActive: siteVariables.colors.brand[300], borderColorHover: siteVariables.colors.brand[300], - borderColorFocus: siteVariables.colors.white, - borderColorFocusIndicator: siteVariables.colors.brand[900], }), }, }} diff --git a/packages/react/src/components/Attachment/Attachment.tsx b/packages/react/src/components/Attachment/Attachment.tsx index d7f0f2117c..6d48ac4f59 100644 --- a/packages/react/src/components/Attachment/Attachment.tsx +++ b/packages/react/src/components/Attachment/Attachment.tsx @@ -104,13 +104,10 @@ class Attachment extends UIComponent, AttachmentStat {...unhandledProps} {...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)} > - {icon && ( -
- {Icon.create(icon, { - defaultProps: { size: 'larger' }, - })} -
- )} + {icon && + Icon.create(icon, { + defaultProps: { size: 'larger', styles: styles.icon }, + })} {(header || description) && (
{Text.create(header, { @@ -122,16 +119,13 @@ class Attachment extends UIComponent, AttachmentStat })}
)} - {action && ( -
- {Button.create(action, { - defaultProps: { iconOnly: true, text: true }, - })} -
- )} + {action && + Button.create(action, { + defaultProps: { iconOnly: true, text: true, styles: styles.action }, + })} {!_.isNil(progress) && Box.create('', { - defaultProps: { className: classes.progress }, + defaultProps: { styles: styles.progress }, })} ) diff --git a/packages/react/src/themes/teams-dark/components/Button/buttonVariables.ts b/packages/react/src/themes/teams-dark/components/Button/buttonVariables.ts index 47c18d77bf..943213be69 100644 --- a/packages/react/src/themes/teams-dark/components/Button/buttonVariables.ts +++ b/packages/react/src/themes/teams-dark/components/Button/buttonVariables.ts @@ -3,7 +3,6 @@ import { ButtonVariables } from '../../../teams/components/Button/buttonVariable export default (siteVars: any): Partial => { return { color: siteVars.colors.white, - colorActive: siteVars.colors.white, colorHover: siteVars.colors.white, colorFocus: siteVars.colors.white, colorDisabled: siteVars.colors.grey[450], @@ -13,16 +12,11 @@ export default (siteVars: any): Partial => { backgroundColorActive: siteVars.colors.grey[500], backgroundColorDisabled: siteVars.colors.grey[550], borderColor: siteVars.colors.grey[500], - borderColorActive: siteVars.colors.grey[450], - borderColorFocus: siteVars.colors.grey[800], borderColorHover: siteVars.colors.grey[450], - borderColorFocusIndicator: siteVars.colors.white, primaryBackgroundColorActive: siteVars.colors.brand[500], primaryBackgroundColorHover: siteVars.colors.brand[500], primaryBackgroundColorFocus: siteVars.colors.brand[800], - primaryBorderColorFocus: siteVars.colors.grey[800], - primaryBorderColorFocusIndicator: siteVars.colors.white, circularColor: siteVars.colors.grey[250], circularColorActive: siteVars.colors.grey[800], @@ -30,7 +24,6 @@ export default (siteVars: any): Partial => { circularBackgroundColorHover: siteVars.colors.grey[300], circularBackgroundColorFocus: siteVars.colors.grey[250], circularBorderColor: siteVars.colors.grey[250], - circularBorderColorFocusIndicator: siteVars.colors.grey[800], textColorHover: siteVars.colors.brand[300], textPrimaryColorHover: siteVars.colors.brand[300], diff --git a/packages/react/src/themes/teams-dark/siteVariables.ts b/packages/react/src/themes/teams-dark/siteVariables.ts index 45b5cb3b98..402bc2ae9b 100644 --- a/packages/react/src/themes/teams-dark/siteVariables.ts +++ b/packages/react/src/themes/teams-dark/siteVariables.ts @@ -1,6 +1,12 @@ import { colors } from '../teams/siteVariables' export { colorScheme } from './colors' +// +// BORDER STYLES +// +export const focusInnerBorderColor = colors.black +export const focusOuterBorderColor = colors.white + // // SHADOW LEVELS // diff --git a/packages/react/src/themes/teams-high-contrast/components/Alert/alertStyles.ts b/packages/react/src/themes/teams-high-contrast/components/Alert/alertStyles.ts index 1818316c74..5ebf5fc904 100644 --- a/packages/react/src/themes/teams-high-contrast/components/Alert/alertStyles.ts +++ b/packages/react/src/themes/teams-high-contrast/components/Alert/alertStyles.ts @@ -1,10 +1,10 @@ import { ComponentSlotStylesInput, ICSSInJSStyle } from '../../../types' import { AlertProps } from '../../../../components/Alert/Alert' import { AlertHighContrastVariables } from './alertVariables' -import { pxToRem } from '../../../../lib' +import getBorderFocusStyles from '../../../teams/getBorderFocusStyles' const alertStyles: ComponentSlotStylesInput = { - action: ({ variables: v, props: p }): ICSSInJSStyle => ({ + action: ({ variables: v, props: p, theme: { siteVariables } }): ICSSInJSStyle => ({ ...(p.isFromKeyboard && { ':focus': { backgroundColor: v.focusBackgroundColor, @@ -18,16 +18,8 @@ const alertStyles: ComponentSlotStylesInput & AlertHighContrastVaria hoverBackgroundColor: siteVars.accessibleYellow, focusBackgroundColor: siteVars.accessibleCyan, - focusInnerBorderColor: siteVars.colors.black, - dangerColor: siteVars.colors.black, dangerBackgroundColor: siteVars.colors.white, dangerBorderColor: siteVars.colors.white, diff --git a/packages/react/src/themes/teams-high-contrast/components/Attachment/attachmentStyles.ts b/packages/react/src/themes/teams-high-contrast/components/Attachment/attachmentStyles.ts index d7457e836a..1174f8ee5b 100644 --- a/packages/react/src/themes/teams-high-contrast/components/Attachment/attachmentStyles.ts +++ b/packages/react/src/themes/teams-high-contrast/components/Attachment/attachmentStyles.ts @@ -33,12 +33,6 @@ const attachmentStyles: ComponentSlotStylesInput ({ - ':hover': { - outline: `1px solid ${v.textColorHover}`, - }, - }), } export default attachmentStyles diff --git a/packages/react/src/themes/teams-high-contrast/components/Button/buttonVariables.ts b/packages/react/src/themes/teams-high-contrast/components/Button/buttonVariables.ts index 23ffef2e90..4c7dc6257d 100644 --- a/packages/react/src/themes/teams-high-contrast/components/Button/buttonVariables.ts +++ b/packages/react/src/themes/teams-high-contrast/components/Button/buttonVariables.ts @@ -10,13 +10,9 @@ export default (siteVars: any): Partial => { backgroundColorFocus: siteVars.accessibleYellow, backgroundColorDisabled: siteVars.accessibleGreen, borderColor: siteVars.colors.white, - borderColorActive: 'transparent', borderColorHover: 'transparent', - borderColorFocus: siteVars.colors.black, - borderColorFocusIndicator: siteVars.colors.white, primaryColor: siteVars.colors.white, - primaryColorActive: siteVars.colors.black, primaryColorHover: siteVars.colors.black, primaryColorFocus: siteVars.colors.black, primaryBackgroundColor: siteVars.colors.black, @@ -24,11 +20,6 @@ export default (siteVars: any): Partial => { primaryBackgroundColorHover: siteVars.accessibleYellow, primaryBackgroundColorFocus: siteVars.accessibleYellow, primaryBorderColor: siteVars.colors.white, - primaryBorderColorFocus: siteVars.colors.black, - primaryBorderColorFocusIndicator: siteVars.colors.white, - primaryBorderWidth: 2, - - primaryCircularBorderColorFocusIndicator: siteVars.colors.black, circularColor: siteVars.colors.white, circularColorActive: siteVars.colors.black, @@ -37,10 +28,8 @@ export default (siteVars: any): Partial => { circularBackgroundColorHover: siteVars.accessibleYellow, circularBackgroundColorFocus: siteVars.accessibleYellow, circularBorderColor: siteVars.colors.white, - circularBorderColorActive: siteVars.colors.white, circularBorderColorHover: siteVars.colors.white, circularBorderColorFocus: siteVars.colors.white, - circularBorderColorFocusIndicator: siteVars.colors.black, textColor: siteVars.accessibleYellow, textColorHover: siteVars.accessibleYellow, diff --git a/packages/react/src/themes/teams-high-contrast/siteVariables.ts b/packages/react/src/themes/teams-high-contrast/siteVariables.ts index 7843e8a036..c0a7633533 100644 --- a/packages/react/src/themes/teams-high-contrast/siteVariables.ts +++ b/packages/react/src/themes/teams-high-contrast/siteVariables.ts @@ -1,5 +1,12 @@ -export * from './colors' import { colors } from '../teams/siteVariables' +import { accessibleCyan } from './colors' +export * from './colors' + +// +// BORDER STYLES +// +export const focusInnerBorderColor = colors.black +export const focusOuterBorderColor = accessibleCyan // // SEMANTIC ASSIGNMENTS diff --git a/packages/react/src/themes/teams/components/Alert/alertStyles.ts b/packages/react/src/themes/teams/components/Alert/alertStyles.ts index 717bd8ae7e..e69f1a1c9e 100644 --- a/packages/react/src/themes/teams/components/Alert/alertStyles.ts +++ b/packages/react/src/themes/teams/components/Alert/alertStyles.ts @@ -2,8 +2,8 @@ import * as React from 'react' import { ComponentSlotStylesInput, ICSSInJSStyle, SiteVariablesPrepared } from '../../../types' import { AlertProps } from '../../../../components/Alert/Alert' import { AlertVariables } from './alertVariables' -import { teamsIconClassNames } from '../Icon/svg' -import { pxToRem } from '../../../../lib' +import getBorderFocusStyles from '../../getBorderFocusStyles' +import getIconFillOrOutlineStyles from '../../getIconFillOrOutlineStyles' const getIntentColorsFromProps = ( p: AlertProps, @@ -95,71 +95,28 @@ const alertStyles: ComponentSlotStylesInput = { flexGrow: 1, }), - action: ({ variables: v, props: p }): ICSSInJSStyle => ({ - height: v.actionSize, - minWidth: v.actionSize, - color: v.actionColor || 'currentColor', - border: 0, - borderRadius: v.borderRadius, - - [`& .${teamsIconClassNames.filled}`]: { - display: 'none', - }, - - [`& .${teamsIconClassNames.outline}`]: { - display: 'block', - }, + action: ({ variables: v, props: p, theme: { siteVariables } }): ICSSInJSStyle => { + const iconFilledStyles = getIconFillOrOutlineStyles({ outline: false }) - ':focus': { outline: 0 }, - - ':hover': { - color: 'currentColor', - - [`& .${teamsIconClassNames.filled}`]: { - display: 'block', - }, - - [`& .${teamsIconClassNames.outline}`]: { - display: 'none', + return { + height: v.actionSize, + minWidth: v.actionSize, + color: v.actionColor || 'currentColor', + border: 0, + borderRadius: v.borderRadius, + ...getIconFillOrOutlineStyles({ outline: true }), + + ':hover': { + color: 'currentColor', + ...iconFilledStyles, }, - }, - ...(p.isFromKeyboard && { ':focus': { - outline: 0, - - [`& .${teamsIconClassNames.filled}`]: { - display: 'block', - }, - - [`& .${teamsIconClassNames.outline}`]: { - display: 'none', - }, - - ':before': { - content: '""', - position: 'absolute', - top: '1px', - right: '1px', - bottom: '1px', - left: '1px', - border: `1px solid ${v.focusInnerBorderColor}`, - borderRadius: pxToRem(2), - }, - - ':after': { - content: '""', - position: 'absolute', - top: 0, - right: 0, - bottom: 0, - left: 0, - border: `1px solid ${v.focusOuterBorderColor}`, - borderRadius: pxToRem(2), - }, + ...(p.isFromKeyboard && iconFilledStyles), + ...getBorderFocusStyles({ siteVariables, isFromKeyboard: p.isFromKeyboard })[':focus'], }, - }), - }), + } + }, } export default alertStyles diff --git a/packages/react/src/themes/teams/components/Alert/alertVariables.ts b/packages/react/src/themes/teams/components/Alert/alertVariables.ts index 7e09b32fc8..225b3c7030 100644 --- a/packages/react/src/themes/teams/components/Alert/alertVariables.ts +++ b/packages/react/src/themes/teams/components/Alert/alertVariables.ts @@ -17,9 +17,6 @@ export interface AlertVariables { actionSize: string actionColor: string - focusInnerBorderColor: string - focusOuterBorderColor: string - dangerColor: string dangerBackgroundColor: string dangerBorderColor: string @@ -56,9 +53,6 @@ export default (siteVars: SiteVariablesPrepared): AlertVariables => { actionSize: minHeight, actionColor: undefined, - focusInnerBorderColor: siteVars.colors.white, - focusOuterBorderColor: siteVars.colors.black, - dangerColor: siteVars.colors.red[400], dangerBackgroundColor: siteVars.colors.red[50], dangerBorderColor: siteVars.colors.red[100], diff --git a/packages/react/src/themes/teams/components/Attachment/attachmentStyles.ts b/packages/react/src/themes/teams/components/Attachment/attachmentStyles.ts index c5f224934f..13d9e77634 100644 --- a/packages/react/src/themes/teams/components/Attachment/attachmentStyles.ts +++ b/packages/react/src/themes/teams/components/Attachment/attachmentStyles.ts @@ -3,10 +3,11 @@ import { AttachmentProps } from '../../../../components/Attachment/Attachment' import { AttachmentVariables } from './attachmentVariables' import { pxToRem } from '../../../../lib' import Icon from '../../../../components/Icon/Icon' -import { teamsIconClassNames } from '../Icon/svg' +import getBorderFocusStyles from '../../getBorderFocusStyles' +import getIconFillOrOutlineStyles from '../../getIconFillOrOutlineStyles' const attachmentStyles: ComponentSlotStylesInput = { - root: ({ props: p, variables: v }): ICSSInJSStyle => ({ + root: ({ props: p, variables: v, theme: { siteVariables } }): ICSSInJSStyle => ({ position: 'relative', display: 'inline-flex', alignItems: 'center', @@ -19,16 +20,13 @@ const attachmentStyles: ComponentSlotStylesInput ({ - flex: '0 0 auto', - - [`& .${Icon.className}`]: { - color: v.textColor, // this breaks the color change on hover - }, + action: ({ props: p, variables: v, theme: { siteVariables } }): ICSSInJSStyle => { + const iconFilledStyles = getIconFillOrOutlineStyles({ outline: false }) - ':hover': { - [`& .${teamsIconClassNames.filled}`]: { - display: 'block', + return { + [`& .${Icon.className}`]: { + color: v.textColor, // this breaks the color change on hover }, - [`& .${teamsIconClassNames.outline}`]: { - display: 'none', + ...getIconFillOrOutlineStyles({ outline: true }), + + ':hover': iconFilledStyles, + + ':focus': { + ...(p.isFromKeyboard && iconFilledStyles), + ...getBorderFocusStyles({ + siteVariables, + isFromKeyboard: p.isFromKeyboard, + borderRadius: v.borderRadius, + })[':focus'], }, - }, - }), + } + }, progress: ({ props: p, variables: v }): ICSSInJSStyle => ({ transition: 'width 0.2s', diff --git a/packages/react/src/themes/teams/components/Attachment/attachmentVariables.ts b/packages/react/src/themes/teams/components/Attachment/attachmentVariables.ts index 98ba367095..fcacc23e4a 100644 --- a/packages/react/src/themes/teams/components/Attachment/attachmentVariables.ts +++ b/packages/react/src/themes/teams/components/Attachment/attachmentVariables.ts @@ -22,9 +22,6 @@ export type AttachmentVariables = { descriptionFontSize: string descriptionFontWeight: number descriptionLineHeight: number - - focusInnerBorderColor: string - focusOuterBorderColor: string } export default (siteVariables: any): AttachmentVariables => ({ @@ -48,7 +45,4 @@ export default (siteVariables: any): AttachmentVariables => ({ descriptionFontSize: siteVariables.fontSizes.small, descriptionFontWeight: siteVariables.fontWeightRegular, descriptionLineHeight: siteVariables.lineHeightSmall, - - focusInnerBorderColor: siteVariables.colors.white, - focusOuterBorderColor: siteVariables.colors.black, }) diff --git a/packages/react/src/themes/teams/components/Button/buttonStyles.ts b/packages/react/src/themes/teams/components/Button/buttonStyles.ts index b7ad8c634d..24bde11ad5 100644 --- a/packages/react/src/themes/teams/components/Button/buttonStyles.ts +++ b/packages/react/src/themes/teams/components/Button/buttonStyles.ts @@ -1,21 +1,23 @@ import { pxToRem } from '../../../../lib' import { ComponentSlotStylesInput, ICSSInJSStyle } from '../../../types' import { ButtonProps, ButtonState } from '../../../../components/Button/Button' +import { ButtonVariables } from './buttonVariables' +import getBorderFocusStyles from '../../getBorderFocusStyles' -const buttonStyles: ComponentSlotStylesInput = { - root: ({ props, variables }): ICSSInJSStyle => { +const buttonStyles: ComponentSlotStylesInput = { + root: ({ props, variables, theme: { siteVariables } }): ICSSInJSStyle => { const { circular, disabled, fluid, primary, text, iconOnly, isFromKeyboard } = props + const { borderWidth } = siteVariables const { height, minWidth, maxWidth, borderRadius, - circularRadius, + circularBorderRadius, paddingLeftRightValue, color, - colorActive, colorHover, colorFocus, colorDisabled, @@ -25,15 +27,10 @@ const buttonStyles: ComponentSlotStylesInput = { backgroundColorFocus, backgroundColorDisabled, borderColor, - borderColorActive, borderColorHover, - borderColorFocus, - borderColorFocusIndicator, borderColorDisabled, - borderWidth, primaryColor, - primaryColorActive, primaryColorHover, primaryColorFocus, primaryBackgroundColor, @@ -41,13 +38,6 @@ const buttonStyles: ComponentSlotStylesInput = { primaryBackgroundColorHover, primaryBackgroundColorFocus, primaryBorderColor, - primaryBorderColorActive, - primaryBorderColorHover, - primaryBorderColorFocus, - primaryBorderColorFocusIndicator, - primaryBorderWidth, - - primaryCircularBorderColorFocusIndicator, circularColor, circularColorActive, @@ -56,19 +46,25 @@ const buttonStyles: ComponentSlotStylesInput = { circularBackgroundColorHover, circularBackgroundColorFocus, circularBorderColor, - circularBorderColorActive, circularBorderColorHover, circularBorderColorFocus, - circularBorderColorFocusIndicator, textColor, textColorHover, textPrimaryColor, textPrimaryColorHover, boxShadow, - borderRadiusFocused, } = variables + const { ':focus': borderFocusStyles } = getBorderFocusStyles({ + siteVariables, + isFromKeyboard, + ...(circular && { + borderRadius: circularBorderRadius, + focusOuterBorderColor: circularBorderColorFocus, + }), + }) + return { height, minWidth, @@ -87,44 +83,27 @@ const buttonStyles: ComponentSlotStylesInput = { // rectangular button defaults ...(!text && { outline: 0, - borderWidth: pxToRem(borderWidth), + borderWidth, borderStyle: 'solid', borderColor, boxShadow, + ':hover': { color: colorHover, backgroundColor: backgroundColorHover, borderColor: borderColorHover, }, - ...(isFromKeyboard && { - ':focus': { - color: colorFocus, - backgroundColor: backgroundColorFocus, - borderColor: borderColorFocus, - ':after': { - content: '""', - position: 'absolute', - top: `-${pxToRem(borderWidth * 2)}`, - right: `-${pxToRem(borderWidth * 2)}`, - bottom: `-${pxToRem(borderWidth * 2)}`, - left: `-${pxToRem(borderWidth * 2)}`, - borderWidth: pxToRem(borderWidth), - borderStyle: 'solid', - borderColor: borderColorFocusIndicator, - borderRadius: borderRadiusFocused, - }, - }, - }), - ...(!isFromKeyboard && { - ':focus': { - ':active': { - color: colorActive, - backgroundColor: backgroundColorActive, - borderColor: borderColorActive, - boxShadow: 'none', - }, - }, - }), + + ':focus': { + boxShadow: 'none', + ...(isFromKeyboard + ? { + color: colorFocus, + backgroundColor: backgroundColorFocus, + ...borderFocusStyles, + } + : { ':active': { backgroundColor: backgroundColorActive } }), + }, }), // circular button defaults @@ -135,41 +114,24 @@ const buttonStyles: ComponentSlotStylesInput = { color: circularColor, backgroundColor: circularBackgroundColor, borderColor: circularBorderColor, - borderRadius: circularRadius, + borderRadius: circularBorderRadius, + ':hover': { color: circularColorActive, backgroundColor: circularBackgroundColorHover, borderColor: circularBorderColorHover, }, - ...(isFromKeyboard && { - ':focus': { - color: circularColorActive, - backgroundColor: circularBackgroundColorFocus, - borderColor: circularBorderColorFocus, - ':after': { - content: '""', - position: 'absolute', - top: '0', - right: '0', - bottom: '0', - left: '0', - borderWidth: `${pxToRem(borderWidth)}`, - borderStyle: 'solid', - borderColor: `${circularBorderColorFocusIndicator}`, - borderRadius: circularRadius, - }, - }, - }), - ...(!isFromKeyboard && { - ':focus': { - ':active': { - color: circularColorActive, - backgroundColor: circularBackgroundColorActive, - borderColor: circularBorderColorActive, - boxShadow: 'none', - }, - }, - }), + + ':focus': { + boxShadow: 'none', + ...(isFromKeyboard + ? { + color: circularColorActive, + backgroundColor: circularBackgroundColorFocus, + ...borderFocusStyles, + } + : { ':active': { backgroundColor: circularBackgroundColorActive } }), + }, }), // text button defaults @@ -193,64 +155,23 @@ const buttonStyles: ComponentSlotStylesInput = { !text && { color: primaryColor, backgroundColor: primaryBackgroundColor, - borderWidth: `${pxToRem(primaryBorderWidth)}`, - borderStyle: 'solid', - borderColor: `${primaryBorderColor}`, + borderColor: primaryBorderColor, + ':hover': { color: primaryColorHover, backgroundColor: primaryBackgroundColorHover, - borderColor: primaryBorderColorHover, }, - ...(isFromKeyboard && - !circular && { - ':focus': { - color: primaryColorFocus, - backgroundColor: primaryBackgroundColorFocus, - borderColor: primaryBorderColorFocus, - ':after': { - content: '""', - position: 'absolute', - top: `-${pxToRem(primaryBorderWidth * 2)}`, - right: `-${pxToRem(primaryBorderWidth * 2)}`, - bottom: `-${pxToRem(primaryBorderWidth * 2)}`, - left: `-${pxToRem(primaryBorderWidth * 2)}`, - borderWidth: pxToRem(primaryBorderWidth), - borderStyle: 'solid', - borderColor: primaryBorderColorFocusIndicator, - borderRadius: borderRadiusFocused, - }, - }, - }), - ...(isFromKeyboard && - circular && { - ':focus': { - color: primaryColorFocus, - backgroundColor: primaryBackgroundColorFocus, - borderColor: primaryBackgroundColorFocus, - ':after': { - content: '""', - position: 'absolute', - top: '0', - right: '0', - bottom: '0', - left: '0', - borderWidth: pxToRem(primaryBorderWidth), - borderStyle: 'solid', - borderColor: primaryCircularBorderColorFocusIndicator, - borderRadius: circularRadius, - }, - }, - }), - ...(!isFromKeyboard && { - ':focus': { - ':active': { - color: primaryColorActive, - backgroundColor: primaryBackgroundColorActive, - borderColor: primaryBorderColorActive, - boxShadow: 'none', - }, - }, - }), + + ':focus': { + boxShadow: 'none', + ...(isFromKeyboard + ? { + color: primaryColorFocus, + backgroundColor: primaryBackgroundColorFocus, + ...borderFocusStyles, + } + : { ':active': { backgroundColor: primaryBackgroundColorActive } }), + }, }), // Overrides for "disabled" buttons @@ -262,7 +183,6 @@ const buttonStyles: ComponentSlotStylesInput = { boxShadow: 'none', ':hover': { backgroundColor: backgroundColorDisabled, - borderColor: borderColorDisabled, }, }), diff --git a/packages/react/src/themes/teams/components/Button/buttonVariables.ts b/packages/react/src/themes/teams/components/Button/buttonVariables.ts index c779631d11..adce62aa28 100644 --- a/packages/react/src/themes/teams/components/Button/buttonVariables.ts +++ b/packages/react/src/themes/teams/components/Button/buttonVariables.ts @@ -1,18 +1,16 @@ +import { FontWeightProperty } from 'csstype' + import { pxToRem } from '../../../../lib' export interface ButtonVariables { - [key: string]: string | number - height: string minWidth: string maxWidth: string borderRadius: string - circularRadius: string paddingLeftRightValue: number - contentFontWeight: string + contentFontWeight: FontWeightProperty color: string - colorActive: string colorHover: string colorFocus: string colorDisabled: string @@ -22,15 +20,10 @@ export interface ButtonVariables { backgroundColorFocus: string backgroundColorDisabled: string borderColor: string - borderColorActive: string borderColorHover: string - borderColorFocus: string - borderColorFocusIndicator: string borderColorDisabled: string - borderWidth: number primaryColor: string - primaryColorActive: string primaryColorHover: string primaryColorFocus: string primaryBackgroundColor: string @@ -38,14 +31,8 @@ export interface ButtonVariables { primaryBackgroundColorHover: string primaryBackgroundColorFocus: string primaryBorderColor: string - primaryBorderColorActive: string - primaryBorderColorHover: string - primaryBorderColorFocus: string - primaryBorderColorFocusIndicator: string - primaryBorderWidth: number - - primaryCircularBorderColorFocusIndicator: string + circularBorderRadius: string circularColor: string circularColorActive: string circularBackgroundColor: string @@ -53,10 +40,8 @@ export interface ButtonVariables { circularBackgroundColorHover: string circularBackgroundColorFocus: string circularBorderColor: string - circularBorderColorActive: string circularBorderColorHover: string circularBorderColorFocus: string - circularBorderColorFocusIndicator: string textColor: string textColorHover: string @@ -66,74 +51,55 @@ export interface ButtonVariables { textSecondaryColorHover: string boxShadow: string - borderRadiusFocused: string } -export default (siteVars: any): ButtonVariables => { - return { - height: pxToRem(32), - minWidth: pxToRem(96), - maxWidth: pxToRem(280), - borderRadius: pxToRem(2), - circularRadius: pxToRem(999), - contentFontWeight: siteVars.fontWeightSemibold, - paddingLeftRightValue: 20, +export default (siteVars: any): ButtonVariables => ({ + height: pxToRem(32), + minWidth: pxToRem(96), + maxWidth: pxToRem(280), + borderRadius: siteVars.borderRadius, + contentFontWeight: siteVars.fontWeightSemibold, + paddingLeftRightValue: 20, - color: siteVars.colors.grey[750], - colorActive: siteVars.colors.grey[750], - colorHover: siteVars.colors.grey[750], - colorFocus: siteVars.colors.grey[750], - colorDisabled: siteVars.colors.grey[250], - backgroundColor: siteVars.colors.white, - backgroundColorActive: siteVars.colors.grey[200], - backgroundColorHover: siteVars.colors.grey[50], - backgroundColorFocus: siteVars.colors.grey[200], - backgroundColorDisabled: siteVars.colors.grey[150], - borderColor: siteVars.colors.grey[200], - borderColorActive: siteVars.colors.grey[250], - borderColorHover: siteVars.colors.grey[250], - borderColorFocus: siteVars.colors.white, - borderColorFocusIndicator: siteVars.colors.grey[750], - borderColorDisabled: 'transparent', - borderWidth: 1, + color: siteVars.colors.grey[750], + colorHover: siteVars.colors.grey[750], + colorFocus: siteVars.colors.grey[750], + colorDisabled: siteVars.colors.grey[250], + backgroundColor: siteVars.colors.white, + backgroundColorActive: siteVars.colors.grey[200], + backgroundColorHover: siteVars.colors.grey[50], + backgroundColorFocus: siteVars.colors.grey[200], + backgroundColorDisabled: siteVars.colors.grey[150], + borderColor: siteVars.colors.grey[200], + borderColorHover: siteVars.colors.grey[250], + borderColorDisabled: 'transparent', - primaryColor: siteVars.colors.white, - primaryColorActive: siteVars.colors.white, - primaryColorHover: siteVars.colors.white, - primaryColorFocus: siteVars.colors.white, - primaryBackgroundColor: siteVars.colors.brand[600], - primaryBackgroundColorActive: siteVars.colors.brand[900], - primaryBackgroundColorHover: siteVars.colors.brand[800], - primaryBackgroundColorFocus: siteVars.colors.brand[800], - primaryBorderColor: 'transparent', - primaryBorderColorActive: 'transparent', - primaryBorderColorHover: 'transparent', - primaryBorderColorFocus: siteVars.colors.white, - primaryBorderColorFocusIndicator: siteVars.colors.grey[750], - primaryBorderWidth: 1, + primaryColor: siteVars.colors.white, + primaryColorHover: siteVars.colors.white, + primaryColorFocus: siteVars.colors.white, + primaryBackgroundColor: siteVars.colors.brand[600], + primaryBackgroundColorActive: siteVars.colors.brand[900], + primaryBackgroundColorHover: siteVars.colors.brand[800], + primaryBackgroundColorFocus: siteVars.colors.brand[800], + primaryBorderColor: 'transparent', - primaryCircularBorderColorFocusIndicator: siteVars.colors.white, + circularBorderRadius: pxToRem(999), + circularColor: siteVars.colors.grey[500], + circularColorActive: siteVars.colors.white, + circularBackgroundColor: 'transparent', + circularBackgroundColorActive: siteVars.colors.grey[500], + circularBackgroundColorHover: siteVars.colors.grey[450], + circularBackgroundColorFocus: siteVars.colors.grey[450], + circularBorderColor: siteVars.colors.grey[500], + circularBorderColorHover: 'transparent', + circularBorderColorFocus: 'transparent', - circularColor: siteVars.colors.grey[500], - circularColorActive: siteVars.colors.white, - circularBackgroundColor: 'transparent', - circularBackgroundColorActive: siteVars.colors.grey[500], - circularBackgroundColorHover: siteVars.colors.grey[450], - circularBackgroundColorFocus: siteVars.colors.grey[450], - circularBorderColor: siteVars.colors.grey[500], - circularBorderColorActive: 'transparent', - circularBorderColorHover: 'transparent', - circularBorderColorFocus: 'transparent', - circularBorderColorFocusIndicator: siteVars.colors.white, + textColor: siteVars.colors.brand[600], + textColorHover: siteVars.colors.brand[800], + textPrimaryColor: siteVars.colors.brand[600], + textPrimaryColorHover: siteVars.colors.brand[800], + textSecondaryColor: siteVars.colors.grey[450], + textSecondaryColorHover: siteVars.colors.brand[800], - textColor: siteVars.colors.brand[600], - textColorHover: siteVars.colors.brand[800], - textPrimaryColor: siteVars.colors.brand[600], - textPrimaryColorHover: siteVars.colors.brand[800], - textSecondaryColor: siteVars.colors.grey[450], - textSecondaryColorHover: siteVars.colors.brand[800], - - boxShadow: siteVars.shadowLevel1, - borderRadiusFocused: pxToRem(3), - } -} + boxShadow: siteVars.shadowLevel1, +}) diff --git a/packages/react/src/themes/teams/components/Menu/menuItemStyles.ts b/packages/react/src/themes/teams/components/Menu/menuItemStyles.ts index a47ea26313..cddeab2f2d 100644 --- a/packages/react/src/themes/teams/components/Menu/menuItemStyles.ts +++ b/packages/react/src/themes/teams/components/Menu/menuItemStyles.ts @@ -3,8 +3,8 @@ import { ComponentSlotStylesInput, ICSSInJSStyle, ColorScheme } from '../../../t import { Extendable } from '../../../../types' import { MenuVariables } from './menuVariables' import { MenuItemProps, MenuItemState } from '../../../../components/Menu/MenuItem' -import { teamsIconClassNames } from '../Icon/svg' import { getColorScheme } from '../../colors' +import getIconFillOrOutlineStyles from '../../getIconFillOrOutlineStyles' type MenuItemPropsAndState = MenuItemProps & MenuItemState @@ -333,14 +333,7 @@ const menuItemStyles: ComponentSlotStylesInput ({ color: textColor, @@ -23,7 +24,8 @@ const radioStyles: ComponentSlotStylesInput< RadioGroupItemProps & RadioGroupItemState, RadioGroupItemVariables > = { - root: ({ props: p, variables: v }): ICSSInJSStyle => ({ + root: ({ props: p, variables: v, theme: { siteVariables } }): ICSSInJSStyle => ({ + position: 'relative', alignItems: 'center', borderStyle: 'solid', borderWidth: `${pxToRem(1)}`, @@ -34,7 +36,6 @@ const radioStyles: ComponentSlotStylesInput< display: p.vertical ? 'flex' : 'inline-flex', fontSize: v.textFontSize, padding: v.padding, - outline: 0, ':hover': { color: v.textColorDefaultHoverFocus, @@ -56,10 +57,7 @@ const radioStyles: ComponentSlotStylesInput< ...restHoverFocusTextColor(v.colorDisabled), }), - ...(p.isFromKeyboard && { - borderColor: v.focusInnerBorderColor, - boxShadow: `0 0 0 ${pxToRem(1)} ${v.focusOuterBorderColor}`, - }), + ...getBorderFocusStyles({ siteVariables, isFromKeyboard: p.isFromKeyboard }), }), icon: ({ props: p, variables: v }): ICSSInJSStyle => ({ diff --git a/packages/react/src/themes/teams/components/RadioGroup/radioGroupItemVariables.ts b/packages/react/src/themes/teams/components/RadioGroup/radioGroupItemVariables.ts index 987f8ee914..0c8c1c9116 100644 --- a/packages/react/src/themes/teams/components/RadioGroup/radioGroupItemVariables.ts +++ b/packages/react/src/themes/teams/components/RadioGroup/radioGroupItemVariables.ts @@ -3,10 +3,6 @@ import { pxToRem } from '../../../../lib' export type RadioGroupItemVariables = { colorDisabled: string - // can these be global colors so we don't have to define for every component? - focusInnerBorderColor: string - focusOuterBorderColor: string - textFontSize: string textColorDefault: string @@ -23,8 +19,6 @@ export type RadioGroupItemVariables = { export default (siteVars: any): RadioGroupItemVariables => ({ colorDisabled: siteVars.colors.grey[250], - focusInnerBorderColor: siteVars.colors.white, - focusOuterBorderColor: siteVars.colors.black, textFontSize: siteVars.fontSizes.medium, diff --git a/packages/react/src/themes/teams/getBorderFocusStyles.ts b/packages/react/src/themes/teams/getBorderFocusStyles.ts new file mode 100644 index 0000000000..3316525301 --- /dev/null +++ b/packages/react/src/themes/teams/getBorderFocusStyles.ts @@ -0,0 +1,75 @@ +import * as React from 'react' + +import { ICSSInJSStyle, SiteVariablesPrepared } from '../types' + +type CSSBorderStyles = Pick + +type BorderFocusStyles = CSSBorderStyles & { + siteVariables?: SiteVariablesPrepared + focusInnerBorderColor?: string + focusOuterBorderColor?: string + isFromKeyboard?: boolean +} + +type BorderPseudoElementStyles = CSSBorderStyles & { borderEdgeValue: string } + +const defaultColor = 'transparent' + +const getPseudoElementStyles = (args: BorderPseudoElementStyles): ICSSInJSStyle => { + const { borderEdgeValue, ...styles } = args + + return { + content: '""', + position: 'absolute', + borderStyle: 'solid', + top: borderEdgeValue, + right: borderEdgeValue, + bottom: borderEdgeValue, + left: borderEdgeValue, + ...styles, + } +} + +/** + * Returns style object that can be used for styling components on focus state. + * NOTE: the element where this is used needs to have relative positioning so that the + * pseudo elements created on focus can be properly positioned. + */ +const getBorderFocusStyles = (args: BorderFocusStyles): ICSSInJSStyle => { + const sv = args.siteVariables + const { + borderWidth = sv.borderWidth, + borderRadius = sv.borderRadius, + focusInnerBorderColor = sv.focusInnerBorderColor || defaultColor, + focusOuterBorderColor = sv.focusOuterBorderColor || defaultColor, + isFromKeyboard, + } = args + + const defaultBorderStyles: React.CSSProperties = { borderWidth, borderRadius } + + return { + ':focus': { + outline: 0, + + ...(isFromKeyboard + ? { + borderColor: 'transparent', + + ':before': getPseudoElementStyles({ + borderEdgeValue: '0', + borderColor: focusInnerBorderColor, + ...defaultBorderStyles, + }), + + ':after': getPseudoElementStyles({ + borderEdgeValue: `-${borderWidth}`, + borderColor: focusOuterBorderColor, + ...defaultBorderStyles, + }), + } + : {}), + }, + } +} + +export default getBorderFocusStyles diff --git a/packages/react/src/themes/teams/getIconFillOrOutlineStyles.ts b/packages/react/src/themes/teams/getIconFillOrOutlineStyles.ts new file mode 100644 index 0000000000..b7fe2fe4cd --- /dev/null +++ b/packages/react/src/themes/teams/getIconFillOrOutlineStyles.ts @@ -0,0 +1,13 @@ +import { teamsIconClassNames } from './components/Icon/svg' + +const getIconFillOrOutlineStyles = ({ outline }: { outline: boolean }): React.CSSProperties => ({ + [`& .${teamsIconClassNames.filled}`]: { + display: outline ? 'none' : 'block', + }, + + [`& .${teamsIconClassNames.outline}`]: { + display: outline ? 'block' : 'none', + }, +}) + +export default getIconFillOrOutlineStyles diff --git a/packages/react/src/themes/teams/siteVariables.ts b/packages/react/src/themes/teams/siteVariables.ts index 1cbebde810..c213e7a9e1 100644 --- a/packages/react/src/themes/teams/siteVariables.ts +++ b/packages/react/src/themes/teams/siteVariables.ts @@ -6,6 +6,14 @@ import { colors } from './colors' // export { colors, emphasisColors, naturalColors, primitiveColors, colorScheme } from './colors' +// +// BORDER STYLES +// +export const borderWidth = '1px' +export const borderRadius = '2px' +export const focusInnerBorderColor = colors.white +export const focusOuterBorderColor = colors.black + // // SHADOW LEVELS //