From 1801b73b3c11c58f6670137c7130a95d1effefe6 Mon Sep 17 00:00:00 2001 From: Brian Heston <47367562+bheston@users.noreply.github.com> Date: Mon, 12 Sep 2022 15:53:58 -0700 Subject: [PATCH 1/4] Standardized focus treatment to use `outline` instead of a combination of `border` and `box-shadow` --- .../accordion-item/accordion-item.styles.ts | 18 ++++------ .../breadcrumb-item/breadcrumb-item.styles.ts | 17 +++------- .../src/checkbox/checkbox.styles.ts | 12 ++----- .../src/combobox/combobox.styles.ts | 25 +++++++++----- .../src/data-grid/data-grid-cell.styles.ts | 12 ++----- .../src/flipper/flipper.styles.ts | 12 +++---- .../listbox-option/listbox-option.styles.ts | 9 ++--- .../src/listbox/listbox.styles.ts | 6 ++-- .../src/menu-item/menu-item.styles.ts | 16 +++------ .../progress-ring/progress-ring.styles.ts | 1 - .../src/progress/progress/progress.styles.ts | 1 - .../web-components/src/radio/radio.styles.ts | 13 ++------ .../src/select/select.styles.ts | 15 ++------- .../src/slider/slider.styles.ts | 1 - .../src/styles/patterns/button.styles.ts | 33 +++++++------------ .../src/styles/patterns/focus.ts | 14 ++++++++ .../src/styles/patterns/input.styles.ts | 9 ----- .../src/switch/switch.styles.ts | 23 +++---------- .../web-components/src/tabs/tab/tab.styles.ts | 10 ++---- .../src/text-area/text-area.stories.ts | 4 +-- .../src/toolbar/toolbar.styles.ts | 7 ++-- .../src/tree-item/tree-item.styles.ts | 18 ++-------- .../src/tree-view/tree-view.styles.ts | 4 --- 23 files changed, 99 insertions(+), 181 deletions(-) create mode 100644 packages/web-components/src/styles/patterns/focus.ts diff --git a/packages/web-components/src/accordion/accordion-item/accordion-item.styles.ts b/packages/web-components/src/accordion/accordion-item/accordion-item.styles.ts index 31eaf5be37ea9..14d8433f066e7 100644 --- a/packages/web-components/src/accordion/accordion-item/accordion-item.styles.ts +++ b/packages/web-components/src/accordion/accordion-item/accordion-item.styles.ts @@ -12,8 +12,6 @@ import { Swatch } from '../../color/swatch'; import { controlCornerRadius, designUnit, - focusStrokeOuter, - focusStrokeWidth, layerCornerRadius, neutralFillLayerAltRest, neutralFillLayerRecipe, @@ -23,6 +21,7 @@ import { neutralStrokeLayerRest, strokeWidth, } from '../../design-tokens'; +import { insetFocusTreatment } from '../../styles/patterns/focus'; import { typeRampBase } from '../../styles/patterns/type-ramp'; import { heightNumber } from '../../styles/size'; @@ -96,18 +95,16 @@ export const accordionItemStyles: ( .button::before { content: ''; position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; + top: calc(${strokeWidth} * -1px); + left: calc(${strokeWidth} * -1px); + right: calc(${strokeWidth} * -1px); + bottom: calc(${strokeWidth} * -1px); cursor: pointer; } .button:${focusVisible}::before { - outline: none; - border: calc(${strokeWidth} * 1px) solid ${focusStrokeOuter}; + ${insetFocusTreatment} border-radius: calc(${layerCornerRadius} * 1px); - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${focusStrokeOuter}; } :host(.expanded) .button:${focusVisible}::before { @@ -184,8 +181,7 @@ export const accordionItemStyles: ( forcedColorsStylesheetBehavior( css` .button:${focusVisible}::before { - border-color: ${SystemColors.Highlight}; - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${SystemColors.Highlight}; + outline-color: ${SystemColors.Highlight}; } .icon { fill: ${SystemColors.ButtonText}; diff --git a/packages/web-components/src/breadcrumb-item/breadcrumb-item.styles.ts b/packages/web-components/src/breadcrumb-item/breadcrumb-item.styles.ts index 7844bb39a5613..4064cc90ef46b 100644 --- a/packages/web-components/src/breadcrumb-item/breadcrumb-item.styles.ts +++ b/packages/web-components/src/breadcrumb-item/breadcrumb-item.styles.ts @@ -9,15 +9,13 @@ import { import { SystemColors } from '@microsoft/fast-web-utilities'; import { controlCornerRadius, - focusStrokeOuter, - focusStrokeWidth, neutralForegroundActive, neutralForegroundHover, neutralForegroundRest, - strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; import { heightNumber } from '../styles/index'; +import { offsetFocusTreatment } from '../styles/patterns/focus'; export const breadcrumbItemStyles: ( context: ElementDefinitionContext, @@ -32,7 +30,6 @@ export const breadcrumbItemStyles: ( ${typeRampBase}; min-width: calc(${heightNumber} * 1px); border-radius: calc(${controlCornerRadius} * 1px); - outline: none; } .listitem { @@ -63,12 +60,8 @@ export const breadcrumbItemStyles: ( color: ${neutralForegroundActive}; } - .control:${focusVisible}::after { - content: ''; - position: absolute; - inset: calc(${strokeWidth} * -1px); - box-shadow: 0 0 0 calc(${focusStrokeWidth} * 1px) ${focusStrokeOuter} inset; - border-radius: inherit; + .control:${focusVisible} { + ${offsetFocusTreatment} } :host(:not([href])), @@ -115,8 +108,8 @@ export const breadcrumbItemStyles: ( color: ${SystemColors.HighlightText}; fill: currentcolor; } - :host([href]) .control:${focusVisible}::after { - box-shadow: 0 0 0 calc(${focusStrokeWidth} * 1px) ${SystemColors.LinkText} inset; + .control:${focusVisible} { + outline-color: ${SystemColors.LinkText}; } `, ), diff --git a/packages/web-components/src/checkbox/checkbox.styles.ts b/packages/web-components/src/checkbox/checkbox.styles.ts index 20e9563d8ef89..7b773b2ef0780 100644 --- a/packages/web-components/src/checkbox/checkbox.styles.ts +++ b/packages/web-components/src/checkbox/checkbox.styles.ts @@ -16,8 +16,6 @@ import { controlCornerRadius, designUnit, disabledOpacity, - fillColor, - focusStrokeOuter, foregroundOnAccentRest, neutralFillInputAltActive, neutralFillInputAltFocus, @@ -30,6 +28,7 @@ import { strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; +import { offsetFocusTreatment } from '../styles/patterns/focus'; export const checkboxStyles: (context: ElementDefinitionContext, definition: CheckboxOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -55,7 +54,6 @@ export const checkboxStyles: (context: ElementDefinitionContext, definition: Che border-radius: calc(${controlCornerRadius} * 1px); border: calc(${strokeWidth} * 1px) solid ${neutralStrokeStrongRest}; background: ${neutralFillInputAltRest}; - outline: none; cursor: pointer; } @@ -107,9 +105,8 @@ export const checkboxStyles: (context: ElementDefinitionContext, definition: Che } :host(:${focusVisible}) .control { - box-shadow: 0 0 0 1px ${fillColor}, 0 0 0 3px ${focusStrokeOuter}; background: ${neutralFillInputAltFocus}; - border-color: ${focusStrokeOuter}; + ${offsetFocusTreatment} } :host(.checked) .control { @@ -160,7 +157,7 @@ export const checkboxStyles: (context: ElementDefinitionContext, definition: Che } :host(:${focusVisible}) .control { forced-color-adjust: none; - box-shadow: 0 0 0 1px ${SystemColors.Field}, 0 0 0 3px ${SystemColors.FieldText}; + outline-color: ${SystemColors.FieldText}; background: ${SystemColors.Field}; border-color: ${SystemColors.Highlight}; } @@ -173,9 +170,6 @@ export const checkboxStyles: (context: ElementDefinitionContext, definition: Che background: ${SystemColors.HighlightText}; border-color: ${SystemColors.Highlight}; } - :host(.checked:${focusVisible}) .control { - box-shadow: 0 0 0 1px ${SystemColors.Field}, 0 0 0 3px ${SystemColors.FieldText}; - } :host(.checked) slot[name='checked-indicator'], :host(.checked) slot[name='indeterminate-indicator'] { fill: ${SystemColors.HighlightText}; diff --git a/packages/web-components/src/combobox/combobox.styles.ts b/packages/web-components/src/combobox/combobox.styles.ts index 0f05172d3b45f..8e7e0061baf3a 100644 --- a/packages/web-components/src/combobox/combobox.styles.ts +++ b/packages/web-components/src/combobox/combobox.styles.ts @@ -1,8 +1,8 @@ import { css, ElementStyles } from '@microsoft/fast-element'; -import { ComboboxOptions, disabledCursor, ElementDefinitionContext, focusVisible } from '@microsoft/fast-foundation'; +import { ComboboxOptions, disabledCursor, ElementDefinitionContext } from '@microsoft/fast-foundation'; import { selectFilledStyles, selectStyles } from '../select/select.styles'; import { appearanceBehavior } from '../utilities/behaviors'; -import { strokeWidth } from '../design-tokens'; +import { neutralFillInputActive, neutralFillInputHover, neutralFillInputRest, neutralStrokeInputActive, neutralStrokeInputHover, neutralStrokeInputRest, strokeWidth } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; export const comboboxStyles: (context: ElementDefinitionContext, definition: ComboboxOptions) => ElementStyles = ( @@ -12,6 +12,21 @@ export const comboboxStyles: (context: ElementDefinitionContext, definition: Com css` ${selectStyles(context, definition)} + :host { + background: padding-box linear-gradient(${neutralFillInputRest}, ${neutralFillInputRest}), + border-box ${neutralStrokeInputRest}; + } + + :host(:not([disabled]):not([open]):hover) { + background: padding-box linear-gradient(${neutralFillInputHover}, ${neutralFillInputHover}), + border-box ${neutralStrokeInputHover}; + } + + :host(:not([disabled]):not([open]):active) { + background: padding-box linear-gradient(${neutralFillInputActive}, ${neutralFillInputActive}), + border-box ${neutralStrokeInputActive}; + } + :host(:empty) .listbox { display: none; } @@ -35,12 +50,6 @@ export const comboboxStyles: (context: ElementDefinitionContext, definition: Com height: calc(100% - ${strokeWidth} * 1px)); margin: auto 0; width: 100%; - } - - .selected-value:hover, - .selected-value:${focusVisible}, - .selected-value:disabled, - .selected-value:active { outline: none; } `.withBehaviors( diff --git a/packages/web-components/src/data-grid/data-grid-cell.styles.ts b/packages/web-components/src/data-grid/data-grid-cell.styles.ts index c761584b60dd4..44aa407625766 100644 --- a/packages/web-components/src/data-grid/data-grid-cell.styles.ts +++ b/packages/web-components/src/data-grid/data-grid-cell.styles.ts @@ -9,11 +9,10 @@ import { import { controlCornerRadius, designUnit, - focusStrokeOuter, - focusStrokeWidth, neutralForegroundRest, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; +import { insetFocusTreatment } from '../styles/patterns/focus'; export const dataGridCellStyles: ( context: ElementDefinitionContext, @@ -25,9 +24,7 @@ export const dataGridCellStyles: ( color: ${neutralForegroundRest}; box-sizing: border-box; ${typeRampBase} - border: transparent calc(${focusStrokeWidth} * 1px) solid; overflow: hidden; - outline: none; white-space: nowrap; border-radius: calc(${controlCornerRadius} * 1px); } @@ -37,22 +34,19 @@ export const dataGridCellStyles: ( } :host(:${focusVisible}) { - border-color: ${focusStrokeOuter}; + ${insetFocusTreatment} } `.withBehaviors( forcedColorsStylesheetBehavior( css` :host { forced-color-adjust: none; - border-color: transparent; background: ${SystemColors.Field}; color: ${SystemColors.FieldText}; } :host(:${focusVisible}) { - border-color: ${SystemColors.FieldText}; - box-shadow: 0 0 0 2px inset ${SystemColors.Field}; - color: ${SystemColors.FieldText}; + outline-color: ${SystemColors.FieldText}; } `, ), diff --git a/packages/web-components/src/flipper/flipper.styles.ts b/packages/web-components/src/flipper/flipper.styles.ts index ed5692712cf28..325f0017a2e6a 100644 --- a/packages/web-components/src/flipper/flipper.styles.ts +++ b/packages/web-components/src/flipper/flipper.styles.ts @@ -13,14 +13,14 @@ import { controlCornerRadius, designUnit, disabledOpacity, - focusStrokeOuter, - focusStrokeWidth, neutralFillRest, neutralFillStrongActive, neutralFillStrongHover, neutralFillStrongRest, neutralStrokeControlRest, + strokeWidth, } from '../design-tokens'; +import { insetFocusTreatment } from '../styles/patterns/focus'; export const flipperStyles: (context: ElementDefinitionContext, definition: FlipperOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -36,9 +36,8 @@ export const flipperStyles: (context: ElementDefinitionContext, definition: Flip background: padding-box linear-gradient(${neutralFillRest}, ${neutralFillRest}), border-box ${neutralStrokeControlRest}; box-sizing: border-box; - border: calc(${focusStrokeWidth} * 1px) solid transparent; + border: calc(${strokeWidth} * 1px) solid transparent; border-radius: calc(${controlCornerRadius} * 1px); - outline: none; padding: 0; } @@ -66,7 +65,7 @@ export const flipperStyles: (context: ElementDefinitionContext, definition: Flip } :host(:${focusVisible}) { - border-color: ${focusStrokeOuter}; + ${insetFocusTreatment} } :host::-moz-focus-inner { @@ -104,8 +103,7 @@ export const flipperStyles: (context: ElementDefinitionContext, definition: Flip } :host(:${focusVisible}) { forced-color-adjust: none; - border-color: ${SystemColors.Highlight}; - box-shadow: 0 0 0 2px ${SystemColors.ButtonFace}, 0 0 0 4px ${SystemColors.ButtonText}; + outline-color: ${SystemColors.Highlight}; } `, ), diff --git a/packages/web-components/src/listbox-option/listbox-option.styles.ts b/packages/web-components/src/listbox-option/listbox-option.styles.ts index 3869cb88aac26..92db48f2af9d6 100644 --- a/packages/web-components/src/listbox-option/listbox-option.styles.ts +++ b/packages/web-components/src/listbox-option/listbox-option.styles.ts @@ -14,7 +14,6 @@ import { controlCornerRadius, designUnit, disabledOpacity, - focusStrokeOuter, focusStrokeWidth, neutralFillSecondaryActive, neutralFillSecondaryHover, @@ -26,6 +25,7 @@ import { neutralForegroundRest, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; +import { insetFocusTreatment } from '../styles/patterns/focus'; export const optionStyles: ( context: ElementDefinitionContext, @@ -37,13 +37,11 @@ export const optionStyles: ( ${typeRampBase} background: ${neutralFillStealthRest}; border-radius: calc(${controlCornerRadius} * 1px); - border: calc(${focusStrokeWidth} * 1px) solid transparent; box-sizing: border-box; color: ${neutralForegroundRest}; cursor: pointer; fill: currentcolor; height: calc(${heightNumber} * 1px); - outline: none; overflow: hidden; align-items: center; padding: 0 calc(${designUnit} * 2.25px); @@ -81,7 +79,7 @@ export const optionStyles: ( } :host(:${focusVisible}) { - border-color: ${focusStrokeOuter}; + ${insetFocusTreatment} background: ${neutralFillStealthFocus}; } @@ -156,6 +154,9 @@ export const optionStyles: ( fill: currentcolor; opacity: 1; } + :host(:${focusVisible}) { + outline-color: ${SystemColors.CanvasText}; + } `, ), ); diff --git a/packages/web-components/src/listbox/listbox.styles.ts b/packages/web-components/src/listbox/listbox.styles.ts index 9537045888a4a..155c54a9e0d04 100644 --- a/packages/web-components/src/listbox/listbox.styles.ts +++ b/packages/web-components/src/listbox/listbox.styles.ts @@ -8,10 +8,10 @@ import { import { controlCornerRadius, designUnit, - focusStrokeOuter, neutralStrokeRest, strokeWidth, } from '../design-tokens'; +import { insetFocusTreatment } from '../styles/patterns/focus'; export const listboxStyles: ( context: ElementDefinitionContext, @@ -24,7 +24,6 @@ export const listboxStyles: ( box-sizing: border-box; flex-direction: column; padding: calc(${designUnit} * 1px) 0; - outline: none; } ::slotted(${context.tagFor(ListboxOption)}) { @@ -32,7 +31,6 @@ export const listboxStyles: ( } :host(:focus-within:not([disabled])) { - border-color: ${focusStrokeOuter}; - box-shadow: 0 0 0 1px ${focusStrokeOuter} inset; + ${insetFocusTreatment} } ` diff --git a/packages/web-components/src/menu-item/menu-item.styles.ts b/packages/web-components/src/menu-item/menu-item.styles.ts index 227bbcb227207..a8ea608650e3f 100644 --- a/packages/web-components/src/menu-item/menu-item.styles.ts +++ b/packages/web-components/src/menu-item/menu-item.styles.ts @@ -12,15 +12,13 @@ import { DirectionalStyleSheetBehavior, heightNumber } from '../styles/index'; import { controlCornerRadius, disabledOpacity, - focusStrokeOuter, - focusStrokeWidth, neutralFillStealthActive, neutralFillStealthHover, neutralForegroundHint, neutralForegroundRest, - strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; +import { insetFocusTreatment } from '../styles/patterns/focus'; export const menuItemStyles: (context: ElementDefinitionContext, definition: MenuItemOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -31,7 +29,6 @@ export const menuItemStyles: (context: ElementDefinitionContext, definition: Men contain: layout; overflow: visible; ${typeRampBase} - outline: none; box-sizing: border-box; height: calc(${heightNumber} * 1px); grid-template-columns: minmax(32px, auto) 1fr minmax(32px, auto); @@ -44,7 +41,6 @@ export const menuItemStyles: (context: ElementDefinitionContext, definition: Men fill: currentcolor; cursor: pointer; border-radius: calc(${controlCornerRadius} * 1px); - border: calc(${strokeWidth} * 1px) solid transparent; } :host(.indent-0) { @@ -86,8 +82,7 @@ export const menuItemStyles: (context: ElementDefinitionContext, definition: Men } :host(:${focusVisible}) { - border: calc(${strokeWidth} * 1px) solid ${focusStrokeOuter}; - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${focusStrokeOuter}; + ${insetFocusTreatment} } :host(:not([disabled]):hover) { @@ -173,7 +168,6 @@ export const menuItemStyles: (context: ElementDefinitionContext, definition: Men justify-content: center; position: relative; box-sizing: border-box; - outline: none; } :host .checkbox-indicator, @@ -221,13 +215,11 @@ export const menuItemStyles: (context: ElementDefinitionContext, definition: Men } :host(.expanded) { background: ${SystemColors.Highlight}; - border-color: ${SystemColors.Highlight}; color: ${SystemColors.HighlightText}; } :host(:${focusVisible}) { background: ${SystemColors.Highlight}; - border-color: ${SystemColors.ButtonText}; - box-shadow: 0 0 0 calc(${strokeWidth} * 1px) inset ${SystemColors.HighlightText}; + outline-color: ${SystemColors.ButtonText}; color: ${SystemColors.HighlightText}; fill: currentcolor; } @@ -243,7 +235,7 @@ export const menuItemStyles: (context: ElementDefinitionContext, definition: Men opacity: 1; } :host([disabled]:${focusVisible}) { - border-color: ${SystemColors.GrayText}; + outline-color: ${SystemColors.GrayText}; } :host .expanded-toggle, :host .checkbox, diff --git a/packages/web-components/src/progress/progress-ring/progress-ring.styles.ts b/packages/web-components/src/progress/progress-ring/progress-ring.styles.ts index e3e4c5a49776a..a42897c1f3ad2 100644 --- a/packages/web-components/src/progress/progress-ring/progress-ring.styles.ts +++ b/packages/web-components/src/progress/progress-ring/progress-ring.styles.ts @@ -16,7 +16,6 @@ export const progressRingStyles: ( css` ${display('flex')} :host { align-items: center; - outline: none; height: calc(${heightNumber} * 1px); width: calc(${heightNumber} * 1px); } diff --git a/packages/web-components/src/progress/progress/progress.styles.ts b/packages/web-components/src/progress/progress/progress.styles.ts index a0b502a4d42c6..249df334ee10a 100644 --- a/packages/web-components/src/progress/progress/progress.styles.ts +++ b/packages/web-components/src/progress/progress/progress.styles.ts @@ -21,7 +21,6 @@ export const progressStyles: (context: ElementDefinitionContext, definition: Pro css` ${display('flex')} :host { align-items: center; - outline: none; height: calc((${strokeWidth} * 3) * 1px); } diff --git a/packages/web-components/src/radio/radio.styles.ts b/packages/web-components/src/radio/radio.styles.ts index 1d5aef8794ff8..2e0c025e60eeb 100644 --- a/packages/web-components/src/radio/radio.styles.ts +++ b/packages/web-components/src/radio/radio.styles.ts @@ -15,8 +15,6 @@ import { accentFillRest, designUnit, disabledOpacity, - fillColor, - focusStrokeOuter, foregroundOnAccentRest, neutralFillInputAltActive, neutralFillInputAltFocus, @@ -29,6 +27,7 @@ import { strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; +import { offsetFocusTreatment } from '../styles/patterns/focus'; export const radioStyles: (context: ElementDefinitionContext, definition: RadioOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -58,7 +57,6 @@ export const radioStyles: (context: ElementDefinitionContext, definition: RadioO border-radius: 50%; border: calc(${strokeWidth} * 1px) solid ${neutralStrokeStrongRest}; background: ${neutralFillInputAltRest}; - outline: none; cursor: pointer; } @@ -108,9 +106,8 @@ export const radioStyles: (context: ElementDefinitionContext, definition: RadioO } :host(:${focusVisible}) .control { - box-shadow: 0 0 0 1px ${fillColor}, 0 0 0 3px ${focusStrokeOuter}; + ${offsetFocusTreatment} background: ${neutralFillInputAltFocus}; - border-color: ${focusStrokeOuter}; } :host(.checked) .control { @@ -155,18 +152,14 @@ export const radioStyles: (context: ElementDefinitionContext, definition: RadioO } :host(:${focusVisible}) .control { forced-color-adjust: none; - box-shadow: 0 0 0 1px ${SystemColors.Field}, 0 0 0 3px ${SystemColors.FieldText}; background: ${SystemColors.Field}; - border-color: ${SystemColors.Highlight}; + outline-color: ${SystemColors.FieldText}; } :host(.checked:not(.disabled):hover) .control, :host(.checked:not(.disabled):active) .control { border-color: ${SystemColors.Highlight}; background: ${SystemColors.Highlight}; } - :host(.checked:${focusVisible}) .control { - box-shadow: 0 0 0 1px ${SystemColors.Field}, 0 0 0 3px ${SystemColors.FieldText}; - } :host(.checked) slot[name='checked-indicator'] { fill: ${SystemColors.Highlight}; } diff --git a/packages/web-components/src/select/select.styles.ts b/packages/web-components/src/select/select.styles.ts index 61b88e68c7043..fcb328b83651e 100644 --- a/packages/web-components/src/select/select.styles.ts +++ b/packages/web-components/src/select/select.styles.ts @@ -17,7 +17,6 @@ import { designUnit, disabledOpacity, fillColor, - focusStrokeOuter, layerCornerRadius, neutralFillActive, neutralFillHover, @@ -35,6 +34,7 @@ import { strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; +import { insetFocusTreatment } from '../styles/patterns/focus'; export const selectFilledStyles: (context: ElementDefinitionContext, definition: SelectOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -64,12 +64,6 @@ export const selectFilledStyles: (context: ElementDefinitionContext, definition: :host(:not([disabled]):not([open]):active) { border-color: ${SystemColors.Highlight}; } - :host(:${focusVisible}) { - forced-color-adjust: none; - background: transparent; - border-color: ${SystemColors.Highlight}; - box-shadow: 0 0 0 1px inset ${SystemColors.Highlight}; - } `, ) ); @@ -156,9 +150,7 @@ export const selectStyles = (context, definition) => } :host(:${focusVisible}) { - border-color: ${focusStrokeOuter}; - outline: none; - box-shadow: 0 0 0 1px inset ${focusStrokeOuter}; + ${insetFocusTreatment} } :host([disabled]) { @@ -235,8 +227,7 @@ export const selectStyles = (context, definition) => } :host(:${focusVisible}) { forced-color-adjust: none; - border-color: ${SystemColors.Highlight}; - box-shadow: 0 0 0 1px inset ${SystemColors.Highlight}; + outline-color: ${SystemColors.Highlight}; } :host([open]) .listbox { background: ${SystemColors.ButtonFace}; diff --git a/packages/web-components/src/slider/slider.styles.ts b/packages/web-components/src/slider/slider.styles.ts index c2a45db00e1f3..3b38064b5cae1 100644 --- a/packages/web-components/src/slider/slider.styles.ts +++ b/packages/web-components/src/slider/slider.styles.ts @@ -42,7 +42,6 @@ export const sliderStyles: (context: ElementDefinitionContext, definition: Slide user-select: none; box-sizing: border-box; border-radius: calc(${controlCornerRadius} * 1px); - outline: none; cursor: pointer; } :host(.horizontal) .positioning-region { diff --git a/packages/web-components/src/styles/patterns/button.styles.ts b/packages/web-components/src/styles/patterns/button.styles.ts index f34d108211627..9b3c0dadf2c80 100644 --- a/packages/web-components/src/styles/patterns/button.styles.ts +++ b/packages/web-components/src/styles/patterns/button.styles.ts @@ -22,7 +22,6 @@ import { density, designUnit, focusStrokeInner, - focusStrokeOuter, focusStrokeWidth, foregroundOnAccentActive, foregroundOnAccentHover, @@ -43,6 +42,7 @@ import { strokeWidth, } from '../../design-tokens'; import { typeRampBase } from '../../styles/patterns/type-ramp'; +import { insetFocusTreatment, offsetFocusTreatment } from './focus'; /** * @internal @@ -57,7 +57,6 @@ export const baseButtonStyles = ( ${display('inline-flex')} :host { position: relative; box-sizing: border-box; - outline: none; ${typeRampBase} height: calc(${heightNumber} * 1px); min-width: calc(${heightNumber} * 1px); @@ -109,8 +108,7 @@ export const baseButtonStyles = ( } :host .control:${focusVisible} { - border-color: ${focusStrokeOuter} !important; - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${focusStrokeOuter} inset !important; + ${insetFocusTreatment} } :host .control${nonInteractivitySelector} { @@ -159,8 +157,7 @@ export const baseButtonStyles = ( :host(:${focusVisible}) .control { forced-color-adjust: none; background: ${SystemColors.ButtonFace}; - border-color: ${SystemColors.Highlight} !important; - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${SystemColors.Highlight} !important; + outline-color: ${SystemColors.Highlight}; } :host([href]) .control { background: ${SystemColors.ButtonFace}; @@ -177,8 +174,7 @@ export const baseButtonStyles = ( } :host([href]) .control:${focusVisible}{ forced-color-adjust: none; - border-color: ${SystemColors.LinkText} !important; - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${SystemColors.LinkText} !important; + outline-color: ${SystemColors.LinkText}; } `, ), @@ -213,8 +209,8 @@ export const AccentButtonStyles = ( } :host .control:${focusVisible} { - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${focusStrokeOuter} inset, - 0 0 0 calc(((${focusStrokeWidth} + ${strokeWidth}) - ${strokeWidth}) * 1px) ${focusStrokeInner} inset !important; + ${insetFocusTreatment} + box-shadow: 0 0 0 calc(((${focusStrokeWidth} + ${strokeWidth}) - ${strokeWidth}) * 1px) ${focusStrokeInner} inset !important; } :host .control${nonInteractivitySelector} { @@ -236,8 +232,8 @@ export const AccentButtonStyles = ( } :host .control:${focusVisible} { background: ${SystemColors.Highlight}; - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${SystemColors.Highlight} inset, - 0 0 0 calc(((${focusStrokeWidth} + ${strokeWidth}) - ${strokeWidth}) * 1px) ${SystemColors.HighlightText} inset !important; + outline-color: ${SystemColors.Highlight}; + box-shadow: 0 0 0 calc(((${focusStrokeWidth} + ${strokeWidth}) - ${strokeWidth}) * 1px) ${SystemColors.HighlightText} inset !important; } :host([href]) .control { background: ${SystemColors.LinkText}; @@ -246,14 +242,13 @@ export const AccentButtonStyles = ( :host([href]) .control:hover { background: ${SystemColors.ButtonFace}; border-color: ${SystemColors.LinkText}; - box-shadow: none; color: ${SystemColors.LinkText}; fill: currentcolor; } :host([href]) .control:${focusVisible} { background: ${SystemColors.LinkText}; - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${SystemColors.LinkText} inset, - 0 0 0 calc(((${focusStrokeWidth} + ${strokeWidth}) - ${strokeWidth}) * 1px) ${SystemColors.HighlightText} inset !important; + outline-color: ${SystemColors.LinkText}; + box-shadow: 0 0 0 calc(((${focusStrokeWidth} + ${strokeWidth}) - ${strokeWidth}) * 1px) ${SystemColors.HighlightText} inset !important; color: ${SystemColors.HighlightText}; fill: currentcolor; } @@ -311,7 +306,7 @@ export const HypertextStyles = ( } :host .control:${focusVisible} { - box-shadow: 0 0 0 calc(${focusStrokeWidth} * 1px) ${focusStrokeOuter} !important; + ${offsetFocusTreatment} } :host .control${nonInteractivitySelector} { @@ -374,7 +369,6 @@ export const LightweightButtonStyles = ( :host .control:${focusVisible} { border-color: ${SystemColors.Highlight}; background: ${SystemColors.Highlight}; - box-shadow: none; color: ${SystemColors.HighlightText}; } :host([href]) .control { @@ -384,7 +378,6 @@ export const LightweightButtonStyles = ( :host([href]) .control:hover, :host([href]) .control:${focusVisible} { background: ${SystemColors.ButtonFace}; - box-shadow: none; color: ${SystemColors.LinkText}; } `, @@ -432,7 +425,7 @@ export const OutlineButtonStyles = ( border-color: ${SystemColors.LinkText}; } :host([href]) .control:hover { - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${SystemColors.LinkText}; + outline-color: ${SystemColors.LinkText}; color: ${SystemColors.LinkText}; } `, @@ -478,7 +471,6 @@ export const StealthButtonStyles = ( :host .control:${focusVisible} { background: ${SystemColors.Highlight}; border-color: ${SystemColors.Highlight}; - box-shadow: none !important; color: ${SystemColors.HighlightText}; fill: currentcolor; } @@ -490,7 +482,6 @@ export const StealthButtonStyles = ( :host([href]) .control:${focusVisible} { background: ${SystemColors.LinkText}; border-color: ${SystemColors.LinkText}; - box-shadow: none !important; color: ${SystemColors.HighlightText}; fill: currentcolor; } diff --git a/packages/web-components/src/styles/patterns/focus.ts b/packages/web-components/src/styles/patterns/focus.ts new file mode 100644 index 0000000000000..878d4f78a0eef --- /dev/null +++ b/packages/web-components/src/styles/patterns/focus.ts @@ -0,0 +1,14 @@ +import { cssPartial } from '@microsoft/fast-element'; +import { focusStrokeOuter, focusStrokeWidth, strokeWidth } from '../../design-tokens'; + +/** @public */ +export const insetFocusTreatment = cssPartial` + outline: calc(${focusStrokeWidth} * 1px) solid ${focusStrokeOuter}; + outline-offset: calc(${focusStrokeWidth} * -1px); +`; + +/** @public */ +export const offsetFocusTreatment = cssPartial` + outline: calc(${focusStrokeWidth} * 1px) solid ${focusStrokeOuter}; + outline-offset: calc(${strokeWidth} * 1px); +`; diff --git a/packages/web-components/src/styles/patterns/input.styles.ts b/packages/web-components/src/styles/patterns/input.styles.ts index 610ccd5c76a0a..fdb8c5cb54d68 100644 --- a/packages/web-components/src/styles/patterns/input.styles.ts +++ b/packages/web-components/src/styles/patterns/input.styles.ts @@ -3,7 +3,6 @@ import { DesignToken, disabledCursor, ElementDefinitionContext, - focusVisible, FoundationElementDefinition, } from '@microsoft/fast-foundation'; import { SystemColors } from '@microsoft/fast-web-utilities'; @@ -74,7 +73,6 @@ export const inputStyles: ( ${typeRampBase} color: ${neutralForegroundRest}; fill: currentcolor; - outline: none; user-select: none; position: relative; } @@ -95,12 +93,6 @@ export const inputStyles: ( .control { width: 100%; - } - - .control:hover, - .control:${focusVisible}, - .control:disabled, - .control:active { outline: none; } @@ -224,7 +216,6 @@ export const inputFilledStyles: ( :host(:focus-within:not([disabled])) ${rootSelector} { border-color: transparent; - box-shadow: none; } `; diff --git a/packages/web-components/src/switch/switch.styles.ts b/packages/web-components/src/switch/switch.styles.ts index f0ff793923e50..e4138bf460ea1 100644 --- a/packages/web-components/src/switch/switch.styles.ts +++ b/packages/web-components/src/switch/switch.styles.ts @@ -16,8 +16,6 @@ import { bodyFont, designUnit, disabledOpacity, - fillColor, - focusStrokeOuter, foregroundOnAccentActive, foregroundOnAccentHover, foregroundOnAccentRest, @@ -32,6 +30,7 @@ import { strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; +import { offsetFocusTreatment } from '../styles/patterns/focus'; export const switchStyles: (context: ElementDefinitionContext, definition: SwitchOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -44,7 +43,6 @@ export const switchStyles: (context: ElementDefinitionContext, definition: Switc ${display('inline-flex')} :host { align-items: center; - outline: none; font-family: ${bodyFont}; ${ /* @@ -69,7 +67,6 @@ export const switchStyles: (context: ElementDefinitionContext, definition: Switc .switch { position: relative; - outline: none; box-sizing: border-box; width: calc(((${heightNumber} / 2) + ${designUnit}) * 2px); height: calc(((${heightNumber} / 2) + ${designUnit}) * 1px); @@ -90,9 +87,8 @@ export const switchStyles: (context: ElementDefinitionContext, definition: Switc } :host(:${focusVisible}) .switch { - box-shadow: 0 0 0 1px ${fillColor}, 0 0 0 3px ${focusStrokeOuter}; + ${offsetFocusTreatment} background: ${neutralFillInputAltFocus}; - border-color: ${focusStrokeOuter}; } :host(.checked) .switch { @@ -166,11 +162,6 @@ export const switchStyles: (context: ElementDefinitionContext, definition: Switc fill: ${foregroundOnAccentActive}; } - :host(.checked:${focusVisible}:not(.disabled)) .switch { - box-shadow: 0 0 0 1px ${fillColor}, 0 0 0 3px ${focusStrokeOuter}; - border-color: transparent; - } - .unchecked-message { display: block; } @@ -237,15 +228,9 @@ export const switchStyles: (context: ElementDefinitionContext, definition: Switc } :host(:${focusVisible}) .switch { forced-color-adjust: none; - background: ${SystemColors.Field}; + background: ${SystemColors.Field}; border-color: ${SystemColors.Highlight}; - box-shadow: 0 0 0 1px ${SystemColors.Highlight}, 0 0 0 3px ${SystemColors.FieldText}; - } - :host(.checked:${focusVisible}:not(.disabled)) .switch { - forced-color-adjust: none; - background: ${SystemColors.Highlight}; - box-shadow: 0 0 0 1px ${SystemColors.Field}, 0 0 0 3px ${SystemColors.FieldText}; - border-color: ${SystemColors.Field}; + outline-color: ${SystemColors.FieldText}; } :host(.disabled) { opacity: 1; diff --git a/packages/web-components/src/tabs/tab/tab.styles.ts b/packages/web-components/src/tabs/tab/tab.styles.ts index aa6bdfd4f7746..411de057f3f7c 100644 --- a/packages/web-components/src/tabs/tab/tab.styles.ts +++ b/packages/web-components/src/tabs/tab/tab.styles.ts @@ -12,12 +12,11 @@ import { controlCornerRadius, density, designUnit, - focusStrokeOuter, - focusStrokeWidth, neutralForegroundRest, strokeWidth, } from '../../design-tokens'; import { typeRampBase } from '../../styles/patterns/type-ramp'; +import { insetFocusTreatment } from '../../styles/patterns/focus'; export const tabStyles: (context: ElementDefinitionContext, definition: FoundationElementDefinition) => ElementStyles = (context: ElementDefinitionContext, definition: FoundationElementDefinition) => @@ -34,7 +33,6 @@ export const tabStyles: (context: ElementDefinitionContext, definition: Foundati justify-content: center; grid-row: 1 / 3; cursor: pointer; - outline: none; } :host([aria-selected='true']) { @@ -47,8 +45,7 @@ export const tabStyles: (context: ElementDefinitionContext, definition: Foundati } :host(:${focusVisible}) { - border-color: ${focusStrokeOuter}; - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${focusStrokeOuter} inset; + ${insetFocusTreatment} } :host(.vertical) { @@ -90,8 +87,7 @@ export const tabStyles: (context: ElementDefinitionContext, definition: Foundati } :host(:${focusVisible}) { background: transparent; - border-color: ${SystemColors.ButtonText}; - box-shadow: none; + outline-color: ${SystemColors.ButtonText}; } `, ), diff --git a/packages/web-components/src/text-area/text-area.stories.ts b/packages/web-components/src/text-area/text-area.stories.ts index c69e25f309001..6fd839ae872ed 100644 --- a/packages/web-components/src/text-area/text-area.stories.ts +++ b/packages/web-components/src/text-area/text-area.stories.ts @@ -5,8 +5,8 @@ export default { component: fluentTextArea, argTypes: { appearance: { - defaultValue: 'outlined', - options: ['filled', 'outlined'], + defaultValue: 'outline', + options: ['filled', 'outline'], control: { type: 'radio' }, }, autoFocus: { diff --git a/packages/web-components/src/toolbar/toolbar.styles.ts b/packages/web-components/src/toolbar/toolbar.styles.ts index d3ed4abdc4ca9..f173491b3f71c 100644 --- a/packages/web-components/src/toolbar/toolbar.styles.ts +++ b/packages/web-components/src/toolbar/toolbar.styles.ts @@ -7,7 +7,8 @@ import { FoundationElementDefinition, } from '@microsoft/fast-foundation'; import { SystemColors } from '@microsoft/fast-web-utilities'; -import { designUnit, fillColor, focusStrokeWidth, neutralStrokeFocus, strokeWidth } from '../design-tokens'; +import { designUnit, fillColor } from '../design-tokens'; +import { insetFocusTreatment } from '../styles/patterns/focus'; export const toolbarStyles: ( context: ElementDefinitionContext, @@ -24,7 +25,7 @@ export const toolbarStyles: ( } :host(${focusVisible}) { - outline: calc(${strokeWidth} * 1px) solid ${neutralStrokeFocus}; + ${insetFocusTreatment} } .positioning-region { @@ -78,7 +79,7 @@ export const toolbarStyles: ( forcedColorsStylesheetBehavior( css` :host(:${focusVisible}) { - box-shadow: 0 0 0 calc(${focusStrokeWidth} * 1px) ${SystemColors.Highlight}; + outline-color: ${SystemColors.Highlight}; color: ${SystemColors.ButtonText}; forced-color-adjust: none; } diff --git a/packages/web-components/src/tree-item/tree-item.styles.ts b/packages/web-components/src/tree-item/tree-item.styles.ts index 95f20b7194f94..902a993f6fae5 100644 --- a/packages/web-components/src/tree-item/tree-item.styles.ts +++ b/packages/web-components/src/tree-item/tree-item.styles.ts @@ -18,7 +18,6 @@ import { density, designUnit, disabledOpacity, - focusStrokeOuter, focusStrokeWidth, neutralFillSecondaryRecipe, neutralFillSecondaryRest, @@ -31,6 +30,7 @@ import { } from '../design-tokens'; import { Swatch } from '../color/swatch'; import { typeRampBase } from '../styles/patterns/type-ramp'; +import { insetFocusTreatment } from '../styles/patterns/focus'; const ltr = css` .expand-collapse-button svg { @@ -87,7 +87,6 @@ export const treeItemStyles: (context: ElementDefinitionContext, definition: Tre ${display('block')} :host { contain: content; position: relative; - outline: none; color: ${neutralForegroundRest}; fill: currentcolor; cursor: pointer; @@ -96,14 +95,6 @@ export const treeItemStyles: (context: ElementDefinitionContext, definition: Tre --tree-item-nested-width: 0; } - :host(:focus) > .positioning-region { - outline: none; - } - - :host(:focus) .content-region { - outline: none; - } - .positioning-region { display: flex; position: relative; @@ -115,8 +106,7 @@ export const treeItemStyles: (context: ElementDefinitionContext, definition: Tre } :host(:${focusVisible}) .positioning-region { - border-color: ${focusStrokeOuter}; - box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${focusStrokeOuter} inset; + ${insetFocusTreatment} } .positioning-region::before { @@ -156,7 +146,6 @@ export const treeItemStyles: (context: ElementDefinitionContext, definition: Tre background: none; border: none; border-radius: calc(${controlCornerRadius} * 1px); - outline: none; ${ /* Width and Height should be based off calc(glyph-size-number + (design-unit * 4) * 1px) - update when density story is figured out */ '' @@ -269,8 +258,7 @@ export const treeItemStyles: (context: ElementDefinitionContext, definition: Tre } :host(:${focusVisible}) .positioning-region { forced-color-adjust: none; - border-color: ${SystemColors.ButtonText}; - box-shadow: 0 0 0 2px inset ${SystemColors.ButtonFace}; + outline-color: ${SystemColors.ButtonFace}; } :host([disabled]), :host([disabled]) .content-region, diff --git a/packages/web-components/src/tree-view/tree-view.styles.ts b/packages/web-components/src/tree-view/tree-view.styles.ts index e55a6c889a664..84ddd37d2b77c 100644 --- a/packages/web-components/src/tree-view/tree-view.styles.ts +++ b/packages/web-components/src/tree-view/tree-view.styles.ts @@ -15,8 +15,4 @@ export const treeViewStyles: ( min-width: fit-content; font-size: 0; } - - :host:focus-visible { - outline: none; - } `; From 75a8d077e627417ee4c578ce7c619fa978c4a3b3 Mon Sep 17 00:00:00 2001 From: Brian Heston <47367562+bheston@users.noreply.github.com> Date: Mon, 12 Sep 2022 16:00:33 -0700 Subject: [PATCH 2/4] Change files --- ...eb-components-d424d9c8-3c64-4787-bb4b-e3323ae05884.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@fluentui-web-components-d424d9c8-3c64-4787-bb4b-e3323ae05884.json diff --git a/change/@fluentui-web-components-d424d9c8-3c64-4787-bb4b-e3323ae05884.json b/change/@fluentui-web-components-d424d9c8-3c64-4787-bb4b-e3323ae05884.json new file mode 100644 index 0000000000000..7e5f03576ad0b --- /dev/null +++ b/change/@fluentui-web-components-d424d9c8-3c64-4787-bb4b-e3323ae05884.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Standardized focus treatment to use `outline` instead of a combination of `border` and `box-shadow`", + "packageName": "@fluentui/web-components", + "email": "47367562+bheston@users.noreply.github.com", + "dependentChangeType": "patch" +} From 6fbbc55ad9dc602bb429b86ba689dddad80a8843 Mon Sep 17 00:00:00 2001 From: Brian Heston <47367562+bheston@users.noreply.github.com> Date: Thu, 15 Sep 2022 18:38:53 -0700 Subject: [PATCH 3/4] Fix some unintended sizing changes --- .../web-components/src/data-grid/data-grid-cell.styles.ts | 5 ++++- .../src/listbox-option/listbox-option.styles.ts | 6 ++++-- packages/web-components/src/menu-item/menu-item.styles.ts | 2 ++ packages/web-components/src/menu/menu.styles.ts | 2 +- packages/web-components/src/slider/slider.styles.ts | 1 + packages/web-components/src/switch/switch.styles.ts | 1 + packages/web-components/src/tree-item/tree-item.styles.ts | 1 + 7 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/web-components/src/data-grid/data-grid-cell.styles.ts b/packages/web-components/src/data-grid/data-grid-cell.styles.ts index 44aa407625766..6e48867c3b1c2 100644 --- a/packages/web-components/src/data-grid/data-grid-cell.styles.ts +++ b/packages/web-components/src/data-grid/data-grid-cell.styles.ts @@ -9,7 +9,9 @@ import { import { controlCornerRadius, designUnit, + focusStrokeWidth, neutralForegroundRest, + strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; import { insetFocusTreatment } from '../styles/patterns/focus'; @@ -20,10 +22,11 @@ export const dataGridCellStyles: ( ) => ElementStyles = (context: ElementDefinitionContext, definition: FoundationElementDefinition) => css` :host { - padding: calc(${designUnit} * 1px) calc(${designUnit} * 3px); + padding: calc((${designUnit} + ${focusStrokeWidth} - ${strokeWidth}) * 1px) calc(((${designUnit} * 3) + ${focusStrokeWidth} - ${strokeWidth}) * 1px); color: ${neutralForegroundRest}; box-sizing: border-box; ${typeRampBase} + border: transparent calc(${strokeWidth} * 1px) solid; overflow: hidden; white-space: nowrap; border-radius: calc(${controlCornerRadius} * 1px); diff --git a/packages/web-components/src/listbox-option/listbox-option.styles.ts b/packages/web-components/src/listbox-option/listbox-option.styles.ts index 92db48f2af9d6..2a34982ef79c7 100644 --- a/packages/web-components/src/listbox-option/listbox-option.styles.ts +++ b/packages/web-components/src/listbox-option/listbox-option.styles.ts @@ -23,6 +23,7 @@ import { neutralFillStealthHover, neutralFillStealthRest, neutralForegroundRest, + strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; import { insetFocusTreatment } from '../styles/patterns/focus'; @@ -37,6 +38,7 @@ export const optionStyles: ( ${typeRampBase} background: ${neutralFillStealthRest}; border-radius: calc(${controlCornerRadius} * 1px); + border: calc(${strokeWidth} * 1px) solid transparent; box-sizing: border-box; color: ${neutralForegroundRest}; cursor: pointer; @@ -44,7 +46,7 @@ export const optionStyles: ( height: calc(${heightNumber} * 1px); overflow: hidden; align-items: center; - padding: 0 calc(${designUnit} * 2.25px); + padding: 0 calc(((${designUnit} * 3) - ${strokeWidth} - 1) * 1px); user-select: none; white-space: nowrap; } @@ -53,7 +55,7 @@ export const optionStyles: ( content: ''; display: block; position: absolute; - left: 0; + left: calc((${focusStrokeWidth} - ${strokeWidth}) * 1px); top: calc((${heightNumber} / 4) - ${focusStrokeWidth} * 1px); width: 3px; height: calc((${heightNumber} / 2) * 1px); diff --git a/packages/web-components/src/menu-item/menu-item.styles.ts b/packages/web-components/src/menu-item/menu-item.styles.ts index a8ea608650e3f..fd58cf835d0c9 100644 --- a/packages/web-components/src/menu-item/menu-item.styles.ts +++ b/packages/web-components/src/menu-item/menu-item.styles.ts @@ -16,6 +16,7 @@ import { neutralFillStealthHover, neutralForegroundHint, neutralForegroundRest, + strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; import { insetFocusTreatment } from '../styles/patterns/focus'; @@ -41,6 +42,7 @@ export const menuItemStyles: (context: ElementDefinitionContext, definition: Men fill: currentcolor; cursor: pointer; border-radius: calc(${controlCornerRadius} * 1px); + border: calc(${strokeWidth} * 1px) solid transparent; } :host(.indent-0) { diff --git a/packages/web-components/src/menu/menu.styles.ts b/packages/web-components/src/menu/menu.styles.ts index c36f16776fb4c..2935999cf06bb 100644 --- a/packages/web-components/src/menu/menu.styles.ts +++ b/packages/web-components/src/menu/menu.styles.ts @@ -20,7 +20,7 @@ export const menuStyles: ( border: calc(${strokeWidth} * 1px) solid transparent; border-radius: calc(${layerCornerRadius} * 1px); box-shadow: ${elevationShadowFlyout}; - padding: calc(${designUnit} * 1px) 0; + padding: calc((${designUnit} - ${strokeWidth}) * 1px) 0; max-width: 368px; min-width: 64px; } diff --git a/packages/web-components/src/slider/slider.styles.ts b/packages/web-components/src/slider/slider.styles.ts index 3b38064b5cae1..c2a45db00e1f3 100644 --- a/packages/web-components/src/slider/slider.styles.ts +++ b/packages/web-components/src/slider/slider.styles.ts @@ -42,6 +42,7 @@ export const sliderStyles: (context: ElementDefinitionContext, definition: Slide user-select: none; box-sizing: border-box; border-radius: calc(${controlCornerRadius} * 1px); + outline: none; cursor: pointer; } :host(.horizontal) .positioning-region { diff --git a/packages/web-components/src/switch/switch.styles.ts b/packages/web-components/src/switch/switch.styles.ts index e4138bf460ea1..da8469badaa6f 100644 --- a/packages/web-components/src/switch/switch.styles.ts +++ b/packages/web-components/src/switch/switch.styles.ts @@ -43,6 +43,7 @@ export const switchStyles: (context: ElementDefinitionContext, definition: Switc ${display('inline-flex')} :host { align-items: center; + outline: none; font-family: ${bodyFont}; ${ /* diff --git a/packages/web-components/src/tree-item/tree-item.styles.ts b/packages/web-components/src/tree-item/tree-item.styles.ts index 902a993f6fae5..28ac08970e629 100644 --- a/packages/web-components/src/tree-item/tree-item.styles.ts +++ b/packages/web-components/src/tree-item/tree-item.styles.ts @@ -87,6 +87,7 @@ export const treeItemStyles: (context: ElementDefinitionContext, definition: Tre ${display('block')} :host { contain: content; position: relative; + outline: none; color: ${neutralForegroundRest}; fill: currentcolor; cursor: pointer; From 618d27e0bd692083727cb22e9aac399455c55c6f Mon Sep 17 00:00:00 2001 From: Brian Heston <47367562+bheston@users.noreply.github.com> Date: Fri, 16 Sep 2022 10:37:17 -0700 Subject: [PATCH 4/4] Fix naming convention and export --- packages/web-components/docs/api-report.md | 6 +++++ .../accordion-item/accordion-item.styles.ts | 4 ++-- .../breadcrumb-item/breadcrumb-item.styles.ts | 4 ++-- .../src/checkbox/checkbox.styles.ts | 4 ++-- .../src/data-grid/data-grid-cell.styles.ts | 4 ++-- .../src/flipper/flipper.styles.ts | 4 ++-- .../listbox-option/listbox-option.styles.ts | 4 ++-- .../src/listbox/listbox.styles.ts | 4 ++-- .../src/menu-item/menu-item.styles.ts | 4 ++-- .../web-components/src/radio/radio.styles.ts | 4 ++-- .../src/select/select.styles.ts | 4 ++-- packages/web-components/src/styles/focus.ts | 23 +++++++++++++++++++ packages/web-components/src/styles/index.ts | 1 + .../src/styles/patterns/button.styles.ts | 8 +++---- .../src/styles/patterns/focus.ts | 14 ----------- .../src/switch/switch.styles.ts | 4 ++-- .../web-components/src/tabs/tab/tab.styles.ts | 4 ++-- .../src/toolbar/toolbar.styles.ts | 4 ++-- .../src/tree-item/tree-item.styles.ts | 4 ++-- 19 files changed, 62 insertions(+), 46 deletions(-) create mode 100644 packages/web-components/src/styles/focus.ts delete mode 100644 packages/web-components/src/styles/patterns/focus.ts diff --git a/packages/web-components/docs/api-report.md b/packages/web-components/docs/api-report.md index 84250ba5eeee9..17cf813173b60 100644 --- a/packages/web-components/docs/api-report.md +++ b/packages/web-components/docs/api-report.md @@ -789,6 +789,12 @@ export const focusStrokeOuterRecipe: DesignToken; // @public (undocumented) export const focusStrokeWidth: CSSDesignToken; +// @public +export const focusTreatmentBase: CSSDirective; + +// @public +export const focusTreatmentTight: CSSDirective; + // @public (undocumented) export const fontWeight: CSSDesignToken; diff --git a/packages/web-components/src/accordion/accordion-item/accordion-item.styles.ts b/packages/web-components/src/accordion/accordion-item/accordion-item.styles.ts index 14d8433f066e7..718f4f8d1201d 100644 --- a/packages/web-components/src/accordion/accordion-item/accordion-item.styles.ts +++ b/packages/web-components/src/accordion/accordion-item/accordion-item.styles.ts @@ -21,7 +21,7 @@ import { neutralStrokeLayerRest, strokeWidth, } from '../../design-tokens'; -import { insetFocusTreatment } from '../../styles/patterns/focus'; +import { focusTreatmentBase } from '../../styles/focus'; import { typeRampBase } from '../../styles/patterns/type-ramp'; import { heightNumber } from '../../styles/size'; @@ -103,7 +103,7 @@ export const accordionItemStyles: ( } .button:${focusVisible}::before { - ${insetFocusTreatment} + ${focusTreatmentBase} border-radius: calc(${layerCornerRadius} * 1px); } diff --git a/packages/web-components/src/breadcrumb-item/breadcrumb-item.styles.ts b/packages/web-components/src/breadcrumb-item/breadcrumb-item.styles.ts index 4064cc90ef46b..b08e47d4c5087 100644 --- a/packages/web-components/src/breadcrumb-item/breadcrumb-item.styles.ts +++ b/packages/web-components/src/breadcrumb-item/breadcrumb-item.styles.ts @@ -15,7 +15,7 @@ import { } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; import { heightNumber } from '../styles/index'; -import { offsetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentTight } from '../styles/focus'; export const breadcrumbItemStyles: ( context: ElementDefinitionContext, @@ -61,7 +61,7 @@ export const breadcrumbItemStyles: ( } .control:${focusVisible} { - ${offsetFocusTreatment} + ${focusTreatmentTight} } :host(:not([href])), diff --git a/packages/web-components/src/checkbox/checkbox.styles.ts b/packages/web-components/src/checkbox/checkbox.styles.ts index 7b773b2ef0780..589c2233b68bf 100644 --- a/packages/web-components/src/checkbox/checkbox.styles.ts +++ b/packages/web-components/src/checkbox/checkbox.styles.ts @@ -28,7 +28,7 @@ import { strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; -import { offsetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentTight } from '../styles/focus'; export const checkboxStyles: (context: ElementDefinitionContext, definition: CheckboxOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -106,7 +106,7 @@ export const checkboxStyles: (context: ElementDefinitionContext, definition: Che :host(:${focusVisible}) .control { background: ${neutralFillInputAltFocus}; - ${offsetFocusTreatment} + ${focusTreatmentTight} } :host(.checked) .control { diff --git a/packages/web-components/src/data-grid/data-grid-cell.styles.ts b/packages/web-components/src/data-grid/data-grid-cell.styles.ts index 6e48867c3b1c2..7af16ffcfdcbb 100644 --- a/packages/web-components/src/data-grid/data-grid-cell.styles.ts +++ b/packages/web-components/src/data-grid/data-grid-cell.styles.ts @@ -14,7 +14,7 @@ import { strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; -import { insetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentBase } from '../styles/focus'; export const dataGridCellStyles: ( context: ElementDefinitionContext, @@ -37,7 +37,7 @@ export const dataGridCellStyles: ( } :host(:${focusVisible}) { - ${insetFocusTreatment} + ${focusTreatmentBase} } `.withBehaviors( forcedColorsStylesheetBehavior( diff --git a/packages/web-components/src/flipper/flipper.styles.ts b/packages/web-components/src/flipper/flipper.styles.ts index 325f0017a2e6a..397069fda8ef0 100644 --- a/packages/web-components/src/flipper/flipper.styles.ts +++ b/packages/web-components/src/flipper/flipper.styles.ts @@ -20,7 +20,7 @@ import { neutralStrokeControlRest, strokeWidth, } from '../design-tokens'; -import { insetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentBase } from '../styles/focus'; export const flipperStyles: (context: ElementDefinitionContext, definition: FlipperOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -65,7 +65,7 @@ export const flipperStyles: (context: ElementDefinitionContext, definition: Flip } :host(:${focusVisible}) { - ${insetFocusTreatment} + ${focusTreatmentBase} } :host::-moz-focus-inner { diff --git a/packages/web-components/src/listbox-option/listbox-option.styles.ts b/packages/web-components/src/listbox-option/listbox-option.styles.ts index 2a34982ef79c7..cf03f9a2a0c44 100644 --- a/packages/web-components/src/listbox-option/listbox-option.styles.ts +++ b/packages/web-components/src/listbox-option/listbox-option.styles.ts @@ -26,7 +26,7 @@ import { strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; -import { insetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentBase } from '../styles/focus'; export const optionStyles: ( context: ElementDefinitionContext, @@ -81,7 +81,7 @@ export const optionStyles: ( } :host(:${focusVisible}) { - ${insetFocusTreatment} + ${focusTreatmentBase} background: ${neutralFillStealthFocus}; } diff --git a/packages/web-components/src/listbox/listbox.styles.ts b/packages/web-components/src/listbox/listbox.styles.ts index 155c54a9e0d04..98ab211e32a9d 100644 --- a/packages/web-components/src/listbox/listbox.styles.ts +++ b/packages/web-components/src/listbox/listbox.styles.ts @@ -11,7 +11,7 @@ import { neutralStrokeRest, strokeWidth, } from '../design-tokens'; -import { insetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentBase } from '../styles/focus'; export const listboxStyles: ( context: ElementDefinitionContext, @@ -31,6 +31,6 @@ export const listboxStyles: ( } :host(:focus-within:not([disabled])) { - ${insetFocusTreatment} + ${focusTreatmentBase} } ` diff --git a/packages/web-components/src/menu-item/menu-item.styles.ts b/packages/web-components/src/menu-item/menu-item.styles.ts index fd58cf835d0c9..6dfc6a2d00d8d 100644 --- a/packages/web-components/src/menu-item/menu-item.styles.ts +++ b/packages/web-components/src/menu-item/menu-item.styles.ts @@ -19,7 +19,7 @@ import { strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; -import { insetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentBase } from '../styles/focus'; export const menuItemStyles: (context: ElementDefinitionContext, definition: MenuItemOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -84,7 +84,7 @@ export const menuItemStyles: (context: ElementDefinitionContext, definition: Men } :host(:${focusVisible}) { - ${insetFocusTreatment} + ${focusTreatmentBase} } :host(:not([disabled]):hover) { diff --git a/packages/web-components/src/radio/radio.styles.ts b/packages/web-components/src/radio/radio.styles.ts index 2e0c025e60eeb..641ea2eb3ca37 100644 --- a/packages/web-components/src/radio/radio.styles.ts +++ b/packages/web-components/src/radio/radio.styles.ts @@ -27,7 +27,7 @@ import { strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; -import { offsetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentTight } from '../styles/focus'; export const radioStyles: (context: ElementDefinitionContext, definition: RadioOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -106,7 +106,7 @@ export const radioStyles: (context: ElementDefinitionContext, definition: RadioO } :host(:${focusVisible}) .control { - ${offsetFocusTreatment} + ${focusTreatmentTight} background: ${neutralFillInputAltFocus}; } diff --git a/packages/web-components/src/select/select.styles.ts b/packages/web-components/src/select/select.styles.ts index fcb328b83651e..3580a6dcb318d 100644 --- a/packages/web-components/src/select/select.styles.ts +++ b/packages/web-components/src/select/select.styles.ts @@ -34,7 +34,7 @@ import { strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; -import { insetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentBase } from '../styles/focus'; export const selectFilledStyles: (context: ElementDefinitionContext, definition: SelectOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -150,7 +150,7 @@ export const selectStyles = (context, definition) => } :host(:${focusVisible}) { - ${insetFocusTreatment} + ${focusTreatmentBase} } :host([disabled]) { diff --git a/packages/web-components/src/styles/focus.ts b/packages/web-components/src/styles/focus.ts new file mode 100644 index 0000000000000..cb5d22389a7e7 --- /dev/null +++ b/packages/web-components/src/styles/focus.ts @@ -0,0 +1,23 @@ +import { cssPartial } from '@microsoft/fast-element'; +import { focusStrokeOuter, focusStrokeWidth, strokeWidth } from '../design-tokens'; + +/** + * Partial CSS for the focus treatment for most typical sized components like Button, Menu Item, etc. + * + * @public + */ +export const focusTreatmentBase = cssPartial` + outline: calc(${focusStrokeWidth} * 1px) solid ${focusStrokeOuter}; + outline-offset: calc(${focusStrokeWidth} * -1px); +`; + +/** + * Partial CSS for the focus treatment for tighter components with spacing constraints, like Checkbox + * and Radio, or plain text like Hypertext appearance Anchor or Breadcrumb Item. + * + * @public + */ +export const focusTreatmentTight = cssPartial` + outline: calc(${focusStrokeWidth} * 1px) solid ${focusStrokeOuter}; + outline-offset: calc(${strokeWidth} * 1px); +`; diff --git a/packages/web-components/src/styles/index.ts b/packages/web-components/src/styles/index.ts index 678d41b288a83..a7def19ce9136 100644 --- a/packages/web-components/src/styles/index.ts +++ b/packages/web-components/src/styles/index.ts @@ -1,4 +1,5 @@ export * from './direction'; export * from './elevation'; +export * from './focus'; export * from './patterns/'; export * from './size'; diff --git a/packages/web-components/src/styles/patterns/button.styles.ts b/packages/web-components/src/styles/patterns/button.styles.ts index 9b3c0dadf2c80..de364724422e8 100644 --- a/packages/web-components/src/styles/patterns/button.styles.ts +++ b/packages/web-components/src/styles/patterns/button.styles.ts @@ -42,7 +42,7 @@ import { strokeWidth, } from '../../design-tokens'; import { typeRampBase } from '../../styles/patterns/type-ramp'; -import { insetFocusTreatment, offsetFocusTreatment } from './focus'; +import { focusTreatmentBase, focusTreatmentTight } from '../focus'; /** * @internal @@ -108,7 +108,7 @@ export const baseButtonStyles = ( } :host .control:${focusVisible} { - ${insetFocusTreatment} + ${focusTreatmentBase} } :host .control${nonInteractivitySelector} { @@ -209,7 +209,7 @@ export const AccentButtonStyles = ( } :host .control:${focusVisible} { - ${insetFocusTreatment} + ${focusTreatmentBase} box-shadow: 0 0 0 calc(((${focusStrokeWidth} + ${strokeWidth}) - ${strokeWidth}) * 1px) ${focusStrokeInner} inset !important; } @@ -306,7 +306,7 @@ export const HypertextStyles = ( } :host .control:${focusVisible} { - ${offsetFocusTreatment} + ${focusTreatmentTight} } :host .control${nonInteractivitySelector} { diff --git a/packages/web-components/src/styles/patterns/focus.ts b/packages/web-components/src/styles/patterns/focus.ts deleted file mode 100644 index 878d4f78a0eef..0000000000000 --- a/packages/web-components/src/styles/patterns/focus.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { cssPartial } from '@microsoft/fast-element'; -import { focusStrokeOuter, focusStrokeWidth, strokeWidth } from '../../design-tokens'; - -/** @public */ -export const insetFocusTreatment = cssPartial` - outline: calc(${focusStrokeWidth} * 1px) solid ${focusStrokeOuter}; - outline-offset: calc(${focusStrokeWidth} * -1px); -`; - -/** @public */ -export const offsetFocusTreatment = cssPartial` - outline: calc(${focusStrokeWidth} * 1px) solid ${focusStrokeOuter}; - outline-offset: calc(${strokeWidth} * 1px); -`; diff --git a/packages/web-components/src/switch/switch.styles.ts b/packages/web-components/src/switch/switch.styles.ts index da8469badaa6f..5f6f8c3fa6716 100644 --- a/packages/web-components/src/switch/switch.styles.ts +++ b/packages/web-components/src/switch/switch.styles.ts @@ -30,7 +30,7 @@ import { strokeWidth, } from '../design-tokens'; import { typeRampBase } from '../styles/patterns/type-ramp'; -import { offsetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentTight } from '../styles/focus'; export const switchStyles: (context: ElementDefinitionContext, definition: SwitchOptions) => ElementStyles = ( context: ElementDefinitionContext, @@ -88,7 +88,7 @@ export const switchStyles: (context: ElementDefinitionContext, definition: Switc } :host(:${focusVisible}) .switch { - ${offsetFocusTreatment} + ${focusTreatmentTight} background: ${neutralFillInputAltFocus}; } diff --git a/packages/web-components/src/tabs/tab/tab.styles.ts b/packages/web-components/src/tabs/tab/tab.styles.ts index 411de057f3f7c..1f56be856a648 100644 --- a/packages/web-components/src/tabs/tab/tab.styles.ts +++ b/packages/web-components/src/tabs/tab/tab.styles.ts @@ -16,7 +16,7 @@ import { strokeWidth, } from '../../design-tokens'; import { typeRampBase } from '../../styles/patterns/type-ramp'; -import { insetFocusTreatment } from '../../styles/patterns/focus'; +import { focusTreatmentBase } from '../../styles/focus'; export const tabStyles: (context: ElementDefinitionContext, definition: FoundationElementDefinition) => ElementStyles = (context: ElementDefinitionContext, definition: FoundationElementDefinition) => @@ -45,7 +45,7 @@ export const tabStyles: (context: ElementDefinitionContext, definition: Foundati } :host(:${focusVisible}) { - ${insetFocusTreatment} + ${focusTreatmentBase} } :host(.vertical) { diff --git a/packages/web-components/src/toolbar/toolbar.styles.ts b/packages/web-components/src/toolbar/toolbar.styles.ts index f173491b3f71c..75c1ebac76f31 100644 --- a/packages/web-components/src/toolbar/toolbar.styles.ts +++ b/packages/web-components/src/toolbar/toolbar.styles.ts @@ -8,7 +8,7 @@ import { } from '@microsoft/fast-foundation'; import { SystemColors } from '@microsoft/fast-web-utilities'; import { designUnit, fillColor } from '../design-tokens'; -import { insetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentBase } from '../styles/focus'; export const toolbarStyles: ( context: ElementDefinitionContext, @@ -25,7 +25,7 @@ export const toolbarStyles: ( } :host(${focusVisible}) { - ${insetFocusTreatment} + ${focusTreatmentBase} } .positioning-region { diff --git a/packages/web-components/src/tree-item/tree-item.styles.ts b/packages/web-components/src/tree-item/tree-item.styles.ts index 28ac08970e629..28a6efc4dd63d 100644 --- a/packages/web-components/src/tree-item/tree-item.styles.ts +++ b/packages/web-components/src/tree-item/tree-item.styles.ts @@ -30,7 +30,7 @@ import { } from '../design-tokens'; import { Swatch } from '../color/swatch'; import { typeRampBase } from '../styles/patterns/type-ramp'; -import { insetFocusTreatment } from '../styles/patterns/focus'; +import { focusTreatmentBase } from '../styles/focus'; const ltr = css` .expand-collapse-button svg { @@ -107,7 +107,7 @@ export const treeItemStyles: (context: ElementDefinitionContext, definition: Tre } :host(:${focusVisible}) .positioning-region { - ${insetFocusTreatment} + ${focusTreatmentBase} } .positioning-region::before {