diff --git a/.github/workflows/next_major.yml b/.github/workflows/next_major.yml new file mode 100644 index 0000000000..7270404858 --- /dev/null +++ b/.github/workflows/next_major.yml @@ -0,0 +1,14 @@ +name: Next Major Pull Request +on: + push: + branches: + - 'changeset-release/next_major' + +jobs: + next_major_pr: + runs-on: ubuntu-latest + steps: + - name: Don't Merge + run: | + echo "Don't merge the next_major, changeset pr into next_major. Instead when you're ready to release a new major version, change the base of this pr to main, and merge." + exit 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 68c971b9a4..e62b656afe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # @primer/css +## 20.0.0 + +### Major Changes + +- [#2049](https://github.com/primer/css/pull/2049) [`f4dba96e`](https://github.com/primer/css/commit/f4dba96e0cb78d3d451226cf60b01187678ced45) Thanks [@langermank](https://github.com/langermank)! - Comment box upload focus border-radius + +* [#1744](https://github.com/primer/css/pull/1744) [`942f65a4`](https://github.com/primer/css/commit/942f65a45a18b7042ba1ce2703688b62d874cf18) Thanks [@langermank](https://github.com/langermank)! - Global CSS focus styles + +- [#1767](https://github.com/primer/css/pull/1767) [`7e01db97`](https://github.com/primer/css/commit/7e01db97f3f2b9d9383f66385ca16f0bdc06abd1) Thanks [@tobiasahlin](https://github.com/tobiasahlin)! - Marketing: Remove unused pullquote selector + +* [#1821](https://github.com/primer/css/pull/1821) [`daa2685c`](https://github.com/primer/css/commit/daa2685c596d894b3bae1896bf97c3319cd9816c) Thanks [@jonrohan](https://github.com/jonrohan)! - UnderlineNav `:focus` styles + Refactor selected state and spacing + Add selected bold state override from github/github + +- [#2047](https://github.com/primer/css/pull/2047) [`553d72cc`](https://github.com/primer/css/commit/553d72cc1baaf43a4c743c50cc8881f3811123e9) Thanks [@langermank](https://github.com/langermank)! - UnderlineNav bug fix + +* [#2046](https://github.com/primer/css/pull/2046) [`55e2b069`](https://github.com/primer/css/commit/55e2b069a4cbd225af676bef918bbbe2e6cd73b7) Thanks [@langermank](https://github.com/langermank)! - Global focus style CSS from feature flag (next major) + +### Patch Changes + +- [#2048](https://github.com/primer/css/pull/2048) [`dc529e31`](https://github.com/primer/css/commit/dc529e3102788d5caa136a9d30c58e56721427a7) Thanks [@simurai](https://github.com/simurai)! - Fix headings with an anchor in a summary + +* [#2041](https://github.com/primer/css/pull/2041) [`20550bbf`](https://github.com/primer/css/commit/20550bbfaa236ac197ca58805542eaab0bf38fd4) Thanks [@jonrohan](https://github.com/jonrohan)! - Upgrading to stylelint-config-12.4.0 + ## 19.8.2 ### Patch Changes diff --git a/docs/src/stories/components/Forms/FormGroups.stories.jsx b/docs/src/stories/components/Forms/FormGroup.stories.jsx similarity index 100% rename from docs/src/stories/components/Forms/FormGroups.stories.jsx rename to docs/src/stories/components/Forms/FormGroup.stories.jsx diff --git a/docs/src/stories/components/Link/Link.stories.jsx b/docs/src/stories/components/Link/Link.stories.jsx index b153ae71dd..a4a43380f6 100644 --- a/docs/src/stories/components/Link/Link.stories.jsx +++ b/docs/src/stories/components/Link/Link.stories.jsx @@ -71,7 +71,7 @@ export const LinkTemplate = ({label, variant, href, noUnderline, focusElement, f <> {label} diff --git a/docs/src/stories/components/Marketing/MarketingButton.stories.jsx b/docs/src/stories/components/Marketing/MarketingButton.stories.jsx index 69ef74016b..d523944fc7 100644 --- a/docs/src/stories/components/Marketing/MarketingButton.stories.jsx +++ b/docs/src/stories/components/Marketing/MarketingButton.stories.jsx @@ -7,7 +7,7 @@ export default { layout: 'padded' }, - excludeStories: ['ButtonTemplate'], + excludeStories: ['MarketingButtonTemplate'], argTypes: { variant: { options: [0, 1, 2, 3], // iterator @@ -77,7 +77,7 @@ const focusMethod = function getFocus() { button.focus() } -export const ButtonTemplate = ({label, variant, disabled, size, animated, focusElement, focusAllElements}) => ( +export const MarketingButtonTemplate = ({label, variant, disabled, size, animated, focusElement, focusAllElements}) => ( <> + ) : ( + + {icon && ( + + + + )} + {label} + {counter && 10} + + )} + + ) +} + +export const Playground = UnderlineNavItemTemplate.bind({}) +Playground.args = { + semanticItemType: 'button', + label: 'Item', + selected: false, + focusElement: false, + icon: false, + counter: false, + usesDataContent: true +} diff --git a/docs/src/stories/components/Navigation/UnderlineNavPatterns.stories.jsx b/docs/src/stories/components/Navigation/UnderlineNavPatterns.stories.jsx new file mode 100644 index 0000000000..f5b152b6b0 --- /dev/null +++ b/docs/src/stories/components/Navigation/UnderlineNavPatterns.stories.jsx @@ -0,0 +1,111 @@ +import React from 'react' +import clsx from 'clsx' +import {UnderlineNavTemplate} from './UnderlineNav.stories' +import {UnderlineNavItemTemplate} from './UnderlineNavItem.stories' +import {UnderlineNavActionTemplate} from './UnderlineNavAction.stories' + +export default { + title: 'Components/Navigation/UnderlineNav/Features', + layout: 'padded' +} + +export const LinkItems = UnderlineNavTemplate.bind({}) +LinkItems.args = { + children: ( + <> + + + + + ) +} + +export const ButtonItems = UnderlineNavTemplate.bind({}) +ButtonItems.args = { + children: ( + <> + + + + + ) +} + +export const NavRight = UnderlineNavTemplate.bind({}) +NavRight.args = { + variant: 'UnderlineNav--right', + children: ( + <> + + + + + ) +} + +export const NavFullWidth = UnderlineNavTemplate.bind({}) +NavFullWidth.args = { + variant: 'UnderlineNav--full', + children: ( + <> + + + + + ) +} + +export const ActionRight = UnderlineNavTemplate.bind({}) +ActionRight.args = { + children: ( + <> + + + + + ), + actionEnd: +} + +export const ActionLeft = UnderlineNavTemplate.bind({}) +ActionLeft.args = { + children: ( + <> + + + + + ), + actionStart: +} + +export const Overflow = UnderlineNavTemplate.bind({}) +Overflow.args = { + children: ( + <> + + + + + + + + + + + + ) +} + +export const Icons = UnderlineNavTemplate.bind({}) +Icons.args = { + children: ( + <> + + + + + + + ) +} diff --git a/docs/src/stories/patterns/FocusStyles.stories.jsx b/docs/src/stories/patterns/FocusStyles.stories.jsx new file mode 100644 index 0000000000..7b3dd2f747 --- /dev/null +++ b/docs/src/stories/patterns/FocusStyles.stories.jsx @@ -0,0 +1,88 @@ +import React from 'react' +import clsx from 'clsx' +import {ButtonTemplate} from '../components/Button/Button.stories.jsx' +import {CheckboxTemplate} from '../components/Forms/Checkbox.stories.jsx' +import {InputTemplate} from '../components/Forms/Input.stories.jsx' +import {SelectTemplate} from '../components/Forms/Select.stories.jsx' +import {TextareaTemplate} from '../components/Forms/Textarea.stories.jsx' +import {LinkTemplate} from '../components/Link/Link.stories.jsx' +import {MarketingButtonTemplate} from '../components/Marketing/MarketingButton.stories.jsx' +import {MarketingLinkTemplate} from '../components/Marketing/MarketingLink.stories.jsx' +import {TabNavTemplate} from '../components/Navigation/TabNav.stories.jsx' +import {TabNavItemTemplate} from '../components/Navigation/TabNavItem.stories.jsx' + +export default { + title: 'Patterns/FocusStyles', + layout: 'padded' +} + +export const FocusStyles = ({}) => ( +
+
+ + + + + + + + + `} + /> + + + + + + +
+
+ + + + + + + + Link with no CSS class + + +
+
+ + + + +
+ +
:target styles
+ +
+) diff --git a/package.json b/package.json index e4c19ce299..b8bc4d0a24 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@primer/css", - "version": "19.8.2", + "version": "20.0.0", "description": "The CSS implementation of GitHub's Primer Design System", "homepage": "https://primer.style/css", "author": "GitHub, Inc.", @@ -48,7 +48,7 @@ "@changesets/cli": "2.22.0", "@github/prettier-config": "0.0.4", "@koddsson/postcss-sass": "5.0.1", - "@primer/stylelint-config": "^12.3.3", + "@primer/stylelint-config": "^12.4.0", "autoprefixer": "10.4.4", "chokidar-cli": "3.0.0", "cssstats": "4.0.5", diff --git a/src/actionlist/action-list-item.scss b/src/actionlist/action-list-item.scss index f658277845..5f4ecb1a83 100644 --- a/src/actionlist/action-list-item.scss +++ b/src/actionlist/action-list-item.scss @@ -1,12 +1,5 @@ // stylelint-disable max-nesting-depth, selector-max-specificity, selector-max-compound-selectors -@mixin focusOutline { - position: relative; - z-index: 1; - outline: none; - box-shadow: 0 0 0 2px var(--color-accent-fg); // this color breaks convention -} - @mixin activeIndicatorLine { position: absolute; top: calc(50% - 12px); @@ -314,6 +307,16 @@ text-decoration: none; } + &:focus { + @include focusOutline; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + } + } + + // default focus state &:focus-visible { @include focusOutline; } diff --git a/src/autocomplete/autocomplete.scss b/src/autocomplete/autocomplete.scss index f0bf279e25..9d403f3fbb 100644 --- a/src/autocomplete/autocomplete.scss +++ b/src/autocomplete/autocomplete.scss @@ -31,9 +31,9 @@ align-items: center; &:focus-within { - border-color: var(--color-accent-emphasis); - outline: none; - box-shadow: var(--color-primer-shadow-focus); + border-color: var(--color-accent-fg); + + @include focusBoxShadowInset; } .form-control { @@ -46,6 +46,10 @@ &:focus { box-shadow: none; } + + &:focus-visible { + box-shadow: none; + } } } diff --git a/src/base/base.scss b/src/base/base.scss index c0772e871c..7778f4b5d3 100644 --- a/src/base/base.scss +++ b/src/base/base.scss @@ -1,4 +1,4 @@ -// stylelint-disable selector-max-type +// stylelint-disable selector-max-type, selector-no-qualifying-type * { box-sizing: border-box; } @@ -77,10 +77,70 @@ button { } details { - summary { cursor: pointer; } + summary { + cursor: pointer; + } &:not([open]) { // Set details content hidden by default for browsers that don't do this - > *:not(summary) { display: none !important; } + > *:not(summary) { + display: none !important; + } + } +} + +// global focus styles + +a, +button, +[role='button'], +input[type='radio'], +input[type='checkbox'] { + transition: 80ms cubic-bezier(0.33, 1, 0.68, 1); + transition-property: color, background-color, box-shadow, border-color; + // fallback :focus state + &:focus { + @include focusOutline; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + } + } + + // default focus state + &:focus-visible { + @include focusOutline; + } +} + +a:not([class]), +input[type='radio'], +input[type='checkbox'] { + &:focus, + &:focus-visible { + outline-offset: 0; + } +} + +// for handling focus conditionally +.focus { + @include focusBoxShadowInset; +} + +// Windows High Contrast mode +@media (forced-colors: active) { + *:focus, + *:focus-visible { + outline: solid 1px transparent; + } + + input:not([type='radio'], [type='checkbox']), + textarea, + select { + &:focus, + &:focus-visible { + outline-offset: 2px; + } } } diff --git a/src/base/normalize.scss b/src/base/normalize.scss index 70222f260d..193a138a3d 100644 --- a/src/base/normalize.scss +++ b/src/base/normalize.scss @@ -39,7 +39,8 @@ header, main, /* 2 */ menu, nav, -section { /* 1 */ +section { + /* 1 */ display: block; } @@ -96,16 +97,6 @@ a { background-color: transparent; /* 1 */ } -/** - * Remove the outline on focused links when they are also active or hovered - * in all browsers (opinionated). - */ - -a:active, -a:hover { - outline-width: 0; -} - /* Text-level semantics ========================================================================== */ @@ -278,7 +269,8 @@ optgroup { */ button, -input { /* 1 */ +input { + /* 1 */ overflow: visible; } @@ -288,7 +280,8 @@ input { /* 1 */ */ button, -select { /* 1 */ +select { + /* 1 */ text-transform: none; } @@ -305,29 +298,6 @@ html [type="button"], /* 1 */ -webkit-appearance: button; /* 2 */ } -/** - * Remove the inner border and padding in Firefox. - */ - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; -} - -/** - * Restore the focus styles unset by the previous rule. - */ - -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; -} - /** * Change the border, margin, and padding in all browsers (opinionated). */ @@ -367,8 +337,8 @@ textarea { * 2. Remove the padding in IE 10-. */ -[type="checkbox"], -[type="radio"] { +[type='checkbox'], +[type='radio'] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } @@ -377,27 +347,17 @@ textarea { * Correct the cursor style of increment and decrement buttons in Chrome. */ -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { +[type='number']::-webkit-inner-spin-button, +[type='number']::-webkit-outer-spin-button { height: auto; } -/** - * 1. Correct the odd appearance in Chrome and Safari. - * 2. Correct the outline style in Safari. - */ - -[type="search"] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} - /** * Remove the inner padding and cancel buttons in Chrome and Safari on OS X. */ -[type="search"]::-webkit-search-cancel-button, -[type="search"]::-webkit-search-decoration { +[type='search']::-webkit-search-cancel-button, +[type='search']::-webkit-search-decoration { -webkit-appearance: none; } diff --git a/src/box/box-overlay.scss b/src/box/box-overlay.scss index aa26b51e91..ed8f273364 100644 --- a/src/box/box-overlay.scss +++ b/src/box/box-overlay.scss @@ -1,4 +1,5 @@ .Box--overlay { + // stylelint-disable-next-line primer/responsive-widths width: 448px; margin-right: auto; margin-left: auto; @@ -22,6 +23,7 @@ } .Box-overlay--wide { + // stylelint-disable-next-line primer/responsive-widths width: 640px; } diff --git a/src/buttons/button.scss b/src/buttons/button.scss index 316b54caf2..27563db247 100644 --- a/src/buttons/button.scss +++ b/src/buttons/button.scss @@ -66,8 +66,8 @@ background-color: var(--color-btn-bg); border-color: var(--color-btn-border); box-shadow: var(--color-btn-shadow), var(--color-btn-inset-shadow); - transition: 0.2s cubic-bezier(0.3, 0, 0.5, 1); - transition-property: color, background-color, border-color; + transition: 80ms cubic-bezier(0.33, 1, 0.68, 1); + transition-property: color, background-color, box-shadow, border-color; &:hover, &.hover, @@ -100,14 +100,6 @@ color: var(--color-primer-fg-disabled); } } - - // Keep :focus after :disabled. Allows to see the focus ring even on disabled buttons - &:focus, - &.focus { - border-color: var(--color-btn-focus-border); - outline: none; - box-shadow: var(--color-btn-focus-shadow); - } } // Primary button @@ -125,6 +117,22 @@ border-color: var(--color-btn-primary-hover-border); } + // fallback :focus state + &:focus { + @include focusOutlineOnEmphasis; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + box-shadow: none; + } + } + + // default focus state + &:focus-visible { + @include focusOutlineOnEmphasis; + } + &:active, &.selected, &[aria-selected='true'] { @@ -144,13 +152,6 @@ } } - &:focus, - &.focus { - background-color: var(--color-btn-primary-focus-bg); - border-color: var(--color-btn-primary-focus-border); - box-shadow: var(--color-btn-primary-focus-shadow); - } - .Counter { color: inherit; background-color: var(--color-btn-primary-counter-bg); @@ -161,6 +162,26 @@ } } +// ensure links styled as button primary gets proper focus style +// stylelint-disable-next-line selector-no-qualifying-type +a.btn-primary { + // fallback :focus state + &:focus { + @include focusOutlineOnEmphasis; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + box-shadow: none; + } + } + + // default focus state + &:focus-visible { + @include focusOutlineOnEmphasis; + } +} + // Outline button .btn-outline { @@ -189,6 +210,22 @@ background-color: var(--color-btn-outline-selected-bg); border-color: var(--color-btn-outline-selected-border); box-shadow: var(--color-btn-outline-selected-shadow); + + // fallback :focus state + &:focus { + @include focusOutlineOnEmphasis; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + box-shadow: none; + } + } + + // default focus state + &:focus-visible { + @include focusOutlineOnEmphasis; + } } &:disabled, @@ -204,11 +241,6 @@ } } - &:focus { - border-color: var(--color-btn-outline-focus-border); - box-shadow: var(--color-btn-outline-focus-shadow); - } - .Counter { color: inherit; background-color: var(--color-btn-outline-counter-bg); @@ -266,11 +298,6 @@ } } - &:focus { - border-color: var(--color-btn-danger-focus-border); - box-shadow: var(--color-btn-danger-focus-shadow); - } - .Counter { color: inherit; background-color: var(--color-btn-danger-counter-bg); diff --git a/src/buttons/misc.scss b/src/buttons/misc.scss index bc42d6751d..328b2fe27a 100644 --- a/src/buttons/misc.scss +++ b/src/buttons/misc.scss @@ -28,6 +28,14 @@ cursor: default; } } + + &:not(.dropdown-item) { + &:focus, + &:focus-visible { + border-radius: $border-radius; + outline-offset: 0; + } + } } // Invisible button @@ -37,6 +45,7 @@ color: var(--color-accent-fg); background-color: transparent; // Reset default gradient backgrounds and colors border: 0; + border-radius: $border-radius; box-shadow: none; &:hover, @@ -48,15 +57,14 @@ } &:active, - &:focus, &.selected, &[aria-selected='true'], &.zeroclipboard-is-active { color: var(--color-accent-fg); - background-color: none; + background: none; border-color: var(--color-btn-active-border); - outline: none; - box-shadow: var(--color-btn-focus-shadow); + + @include focusOutline; } &:active &.zeroclipboard-is-active { @@ -89,14 +97,23 @@ border: 0; box-shadow: none; - &:hover { color: var(--color-accent-fg); } + &:hover { + color: var(--color-accent-fg); + } + + &:focus, + &:focus-visible { + border-radius: $border-radius; + } &.disabled, &[aria-disabled='true'] { color: var(--color-primer-fg-disabled); cursor: default; - &:hover { color: var(--color-primer-fg-disabled); } + &:hover { + color: var(--color-primer-fg-disabled); + } } } @@ -112,18 +129,13 @@ color: var(--color-fg-muted); background: transparent; border: 0; - outline: none; &:hover { color: var(--color-fg-default); } - &:active, - &:focus { - color: var(--color-fg-muted); - border-color: var(--color-btn-active-border); - outline: none; - box-shadow: var(--color-btn-focus-shadow); + &:active { + @include focusOutline; } } @@ -216,10 +228,4 @@ color: var(--color-accent-fg); cursor: pointer; } - - &:focus { - z-index: 1; - outline: 0; - box-shadow: var(--color-primer-shadow-focus); - } } diff --git a/src/dropdown/dropdown.scss b/src/dropdown/dropdown.scss index 4789eccd0c..bf959e154f 100644 --- a/src/dropdown/dropdown.scss +++ b/src/dropdown/dropdown.scss @@ -82,12 +82,10 @@ text-overflow: ellipsis; white-space: nowrap; - &:focus, &:hover { color: var(--color-fg-on-emphasis); text-decoration: none; background-color: var(--color-accent-emphasis); - outline: none; > .octicon { color: inherit; diff --git a/src/forms/form-control.scss b/src/forms/form-control.scss index 23dfc33f30..b8eb49990a 100644 --- a/src/forms/form-control.scss +++ b/src/forms/form-control.scss @@ -29,14 +29,32 @@ label { background-position: right 8px center; // For form validation. This keeps images 8px from right and centered vertically. border: $border-width $border-style var(--color-border-default); border-radius: $border-radius; - outline: none; box-shadow: var(--color-primer-shadow-inset); + transition: 80ms cubic-bezier(0.33, 1, 0.68, 1); + transition-property: color, background-color, box-shadow, border-color; - &.focus, &:focus { - border-color: var(--color-accent-emphasis); - outline: none; - box-shadow: var(--color-primer-shadow-focus); + @include focusBoxShadowInset; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + border-color: transparent; + + @include focusBoxShadowInset(1px, transparent); + } + } + + // default focus state + &:focus-visible { + @include focusBoxShadowInset; + } + + // override form controls with no border in focused state + &.border-0 { + &:focus, + &:focus-visible { + border: $border-width $border-style var(--color-accent-fg) !important; + } } &[disabled] { diff --git a/src/forms/form-group.scss b/src/forms/form-group.scss index 1ec0f8a278..188bfd6449 100644 --- a/src/forms/form-group.scss +++ b/src/forms/form-group.scss @@ -23,6 +23,7 @@ // Text fields .form-control { + // stylelint-disable-next-line primer/responsive-widths width: 440px; max-width: 100%; // stylelint-disable-next-line primer/spacing @@ -33,12 +34,18 @@ background-color: var(--color-canvas-default); } - &.shorter { width: 130px; } + &.shorter { + width: 130px; + } - &.short { width: 250px; } + &.short { + width: 250px; + } &.input-block, - &.long { width: 100%; } + &.long { + width: 100%; + } } // Textarea @@ -89,9 +96,13 @@ h4 { margin: $spacer-1 0 0; - &.is-error { color: var(--color-danger-fg); } + &.is-error { + color: var(--color-danger-fg); + } - &.is-success { color: var(--color-success-fg); } + &.is-success { + color: var(--color-success-fg); + } + .note { margin-top: 0; @@ -203,13 +214,18 @@ background-image: linear-gradient(var(--color-success-subtle), var(--color-success-subtle)); border-color: var(--color-success-muted); - &::after { border-bottom-color: var(--color-success-subtle); } - &::before { border-bottom-color: var(--color-success-muted); } + &::after { + border-bottom-color: var(--color-success-subtle); + } + + &::before { + border-bottom-color: var(--color-success-muted); + } } } &.warn { - .form-control { + .form-control:not(:focus, :focus-visible) { border-color: var(--color-attention-emphasis); } @@ -219,13 +235,18 @@ background-image: linear-gradient(var(--color-attention-subtle), var(--color-attention-subtle)); border-color: var(--color-attention-muted); - &::after { border-bottom-color: var(--color-attention-subtle); } - &::before { border-bottom-color: var(--color-attention-muted); } + &::after { + border-bottom-color: var(--color-attention-subtle); + } + + &::before { + border-bottom-color: var(--color-attention-muted); + } } } &.errored { - .form-control { + .form-control:not(:focus, :focus-visible) { border-color: var(--color-danger-emphasis); } @@ -239,8 +260,13 @@ background-image: linear-gradient(var(--color-danger-subtle), var(--color-danger-subtle)); border-color: var(--color-danger-muted); - &::after { border-bottom-color: var(--color-danger-subtle); } - &::before { border-bottom-color: var(--color-danger-muted); } + &::after { + border-bottom-color: var(--color-danger-subtle); + } + + &::before { + border-bottom-color: var(--color-danger-muted); + } } } } diff --git a/src/forms/form-validation.scss b/src/forms/form-validation.scss index bb96b73a1f..e0c27b94ba 100644 --- a/src/forms/form-validation.scss +++ b/src/forms/form-validation.scss @@ -235,15 +235,20 @@ dl.form-group > dd, // TODO: Deprecate } &.focused { + border-color: var(--color-accent-fg); border-radius: $border-radius; - box-shadow: var(--color-primer-shadow-inset), var(--color-primer-shadow-focus); + outline: none; + // stylelint-disable-next-line primer/box-shadow + box-shadow: 0 0 0 2px var(--color-accent-fg); .form-control { + border-color: transparent; + border-bottom-color: var(--color-accent-fg); box-shadow: none; } .drag-and-drop { - border-color: var(--color-accent-emphasis); + border-color: transparent; } } } @@ -272,7 +277,9 @@ dl.form-group > dd, // TODO: Deprecate border: $border-width $border-style var(--color-border-default); } - .comment-form-error { margin-bottom: $spacer-2; } + .comment-form-error { + margin-bottom: $spacer-2; + } .write-content, .preview-content { @@ -317,8 +324,10 @@ div.composer { min-height: 200px; } -// stylelint-disable-next-line primer/spacing -.composer .tabnav { margin: 0 0 10px; } +.composer .tabnav { + // stylelint-disable-next-line primer/spacing + margin: 0 0 10px; +} // Misc CSS // diff --git a/src/forms/input-group.scss b/src/forms/input-group.scss index 1186c4694a..01534cb5a4 100644 --- a/src/forms/input-group.scss +++ b/src/forms/input-group.scss @@ -19,6 +19,14 @@ display: inline-table; } + // within input group, if button exists change focus styles to match input (no offset) + &:focus-within { + // stylelint-disable-next-line selector-max-type + button { + outline-offset: 0; + } + } + // Autocomplete with embedded icon .form-control.autocomplete-embedded-icon-wrap { display: inline-flex; diff --git a/src/links/link.scss b/src/links/link.scss index 80cad058e7..f29cef3d91 100644 --- a/src/links/link.scss +++ b/src/links/link.scss @@ -7,6 +7,11 @@ text-decoration: underline; cursor: pointer; } + + &:focus, + &:focus-visible { + outline-offset: 0; + } } .Link--primary { diff --git a/src/markdown/headings.scss b/src/markdown/headings.scss index b9d420ebed..03a1311779 100644 --- a/src/markdown/headings.scss +++ b/src/markdown/headings.scss @@ -80,6 +80,11 @@ h5, h6 { display: inline-block; + + .anchor { + // stylelint-disable-next-line primer/spacing + margin-left: -40px; + } } h1, diff --git a/src/marketing/buttons/button.scss b/src/marketing/buttons/button.scss index 8638eee851..854b3ec31f 100644 --- a/src/marketing/buttons/button.scss +++ b/src/marketing/buttons/button.scss @@ -13,11 +13,13 @@ white-space: nowrap; vertical-align: middle; user-select: none; - background: linear-gradient(180deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0) 100%), var(--color-mktg-btn-bg) !important; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.15) 0%, rgba(255, 255, 255, 0) 100%), + var(--color-mktg-btn-bg) !important; border: 0; // stylelint-disable-next-line primer/borders border-radius: 0.375rem; - transition: box-shadow 0.2s; + transition: box-shadow 0.2s, outline 0.2s ease; appearance: none !important; &::before { @@ -42,29 +44,32 @@ box-shadow: var(--color-mktg-btn-shadow-hover) !important; } - &:focus, - &.focus { - outline: 0; - box-shadow: var(--color-mktg-btn-shadow-focus), var(--color-mktg-btn-shadow-hover) !important; - } - &:hover, &:focus, + &:focus-visible, &.focus { &::before { opacity: 1; } + } + + // fallback :focus state + &:focus { + @include focusOutline(2px, var(--color-accent-fg)); - &:disabled { - box-shadow: none !important; + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + box-shadow: none; } } - &:active { - outline: none; - // stylelint-disable-next-line primer/box-shadow - box-shadow: 0 0 0 transparent; + // default focus state + &:focus-visible { + @include focusOutline(2px, var(--color-accent-fg)); + } + &:active { &::before { opacity: 0.5 !important; } @@ -91,11 +96,6 @@ box-shadow: var(--color-mktg-btn-shadow-hover-muted) !important; } - &:focus, - &.focus { - box-shadow: var(--color-mktg-btn-shadow-hover-muted), var(--color-mktg-btn-shadow-focus) !important; - } - &:active { // stylelint-disable-next-line primer/box-shadow box-shadow: var(--color-fg-default) 0 0 0 3px inset !important; @@ -119,11 +119,6 @@ &:hover { box-shadow: var(--color-mktg-btn-shadow-hover-muted) !important; } - - &:focus, - .focus { - box-shadow: var(--color-mktg-btn-shadow-hover-muted), var(--color-mktg-btn-shadow-focus) !important; - } } .btn-signup-mktg { @@ -137,9 +132,20 @@ background: linear-gradient(180deg, rgba(52, 183, 89, 0.15) 0%, rgba(46, 164, 79, 0) 100%) !important; } + // fallback :focus state &:focus { - // stylelint-disable-next-line primer/box-shadow - box-shadow: rgba(46, 164, 79, 0.45) 0 0 0 4px !important; + @include focusOutline(2px, var(--color-accent-fg)); + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + box-shadow: none; + } + } + + // default focus state + &:focus-visible { + @include focusOutline(2px, var(--color-accent-fg)); } } diff --git a/src/marketing/links/link.scss b/src/marketing/links/link.scss index 13dd30aadc..9e87d28ebe 100644 --- a/src/marketing/links/link.scss +++ b/src/marketing/links/link.scss @@ -6,10 +6,6 @@ text-decoration: none; } - &:active { - outline: none; - } - &::after, &.link-emphasis-mktg::before { position: absolute; @@ -35,13 +31,17 @@ } &:hover, - &:focus, &:active { &::after { transform: scaleX(1); } } + &:focus, + &:focus-visible { + outline-offset: 2px; + } + &.arrow-target-mktg { .arrow-symbol-mktg { margin-left: -$em-spacer-3; diff --git a/src/marketing/type/typography.scss b/src/marketing/type/typography.scss index 94dde0d7a2..1ec7764c23 100644 --- a/src/marketing/type/typography.scss +++ b/src/marketing/type/typography.scss @@ -15,18 +15,25 @@ @each $header, $sizes in $mktg-headers { .h#{$header}-mktg { + // stylelint-disable-next-line function-no-unknown $pairing: map-get($mktg-header-pairings, nth($sizes, 1)); + // stylelint-disable-next-line function-no-unknown $pairing-md: map-get($mktg-header-pairings, nth($sizes, 2)); + // stylelint-disable-next-line function-no-unknown $pairing-lg: map-get($mktg-header-pairings, nth($sizes, 3)); + // stylelint-disable-next-line function-no-unknown font-size: map-get($pairing, 'size') !important; + // stylelint-disable-next-line function-no-unknown line-height: map-get($pairing, 'lh') !important; @if (map-get($pairing, 'size') >= $mktg-header-weight-threshold) { font-weight: $mktg-header-weight-large !important; } @if (nth($sizes, 1) != nth($sizes, 2)) { @include breakpoint(md) { + // stylelint-disable-next-line function-no-unknown font-size: map-get($pairing-md, 'size') !important; + // stylelint-disable-next-line function-no-unknown line-height: map-get($pairing-md, 'lh') !important; @if (map-get($pairing-md, 'size') >= $mktg-header-spacing-threshold and map-get($pairing, 'size') < $mktg-header-spacing-threshold) { @@ -41,7 +48,9 @@ @if (nth($sizes, 2) != nth($sizes, 3)) { @include breakpoint(lg) { + // stylelint-disable-next-line function-no-unknown font-size: map-get($pairing-lg, 'size') !important; + // stylelint-disable-next-line function-no-unknown line-height: map-get($pairing-lg, 'lh') !important; @if (map-get($pairing-lg, 'size') >= $mktg-header-spacing-threshold and map-get($pairing-md, 'size') < $mktg-header-spacing-threshold) { @@ -70,11 +79,16 @@ @each $body, $sizes in $mktg-bodies { .f#{$body}-mktg { + // stylelint-disable-next-line function-no-unknown $pairing: map-get($mktg-body-pairings, nth($sizes, 1)); + // stylelint-disable-next-line function-no-unknown $pairing-md: map-get($mktg-body-pairings, nth($sizes, 2)); + // stylelint-disable-next-line function-no-unknown $pairing-lg: map-get($mktg-body-pairings, nth($sizes, 3)); + // stylelint-disable-next-line function-no-unknown font-size: map-get($pairing, 'size') !important; + // stylelint-disable-next-line function-no-unknown line-height: map-get($pairing, 'lh') !important; @if (map-get($pairing, 'size') >= $mktg-body-spacing-threshold) { letter-spacing: $mktg-body-spacing-large !important; } @@ -83,7 +97,9 @@ @if (nth($sizes, 1) != nth($sizes, 2)) { @include breakpoint(md) { + // stylelint-disable-next-line function-no-unknown font-size: map-get($pairing-md, 'size') !important; + // stylelint-disable-next-line function-no-unknown line-height: map-get($pairing-md, 'lh') !important; @if (map-get($pairing-md, 'size') >= $mktg-body-spacing-threshold and map-get($pairing, 'size') < $mktg-body-spacing-threshold) { @@ -98,7 +114,9 @@ @if (nth($sizes, 2) != nth($sizes, 3)) { @include breakpoint(lg) { + // stylelint-disable-next-line function-no-unknown font-size: map-get($pairing-lg, 'size') !important; + // stylelint-disable-next-line function-no-unknown line-height: map-get($pairing-lg, 'lh') !important; @if (map-get($pairing-lg, 'size') >= $mktg-body-spacing-threshold and map-get($pairing-md, 'size') < $mktg-body-spacing-threshold) { @@ -116,32 +134,3 @@ .text-medium { font-weight: $font-weight-medium !important; } - -// Pullquote - -@mixin pullquote { - padding-top: 0; - padding-bottom: 0; - // stylelint-disable-next-line primer/spacing - padding-left: $spacer; - margin-bottom: $spacer-4; - font-family: $mono-font; - font-size: $h4-size; - line-height: 1.4; - color: var(--color-color-text-secondary); - border-left: 3px solid var(--color-border-default); - - @include breakpoint(md) { - // stylelint-disable-next-line primer/spacing - padding-left: $spacer * 1.5; - margin-bottom: $spacer-5; - // stylelint-disable-next-line primer/spacing - margin-left: (-$spacer * 1.5) - 3px; - font-size: 18px; - line-height: $lh-default; - } -} - -.pullquote { - @include pullquote; -} diff --git a/src/marketing/utilities/layout.scss b/src/marketing/utilities/layout.scss index 6f464beb4d..94301c1647 100644 --- a/src/marketing/utilities/layout.scss +++ b/src/marketing/utilities/layout.scss @@ -27,7 +27,7 @@ @each $breakpoint, $variant in $responsive-variants { @include breakpoint($breakpoint) { @for $offset from 1 through 7 { - // stylelint-disable-next-line primer/spacing + // stylelint-disable-next-line primer/spacing, function-no-unknown .offset#{$variant}-n#{$offset} { margin-left: -($offset * 0.0833333333 * 100%); } } } diff --git a/src/navigation/filter-list.scss b/src/navigation/filter-list.scss index 68a317cbaa..9eac3d8aec 100644 --- a/src/navigation/filter-list.scss +++ b/src/navigation/filter-list.scss @@ -1,3 +1,5 @@ +// stylelint-disable selector-max-specificity + // Filters list // // A vertical list of filters. @@ -45,6 +47,22 @@ &[aria-current]:not([aria-current='false']) { color: var(--color-fg-on-emphasis); background-color: var(--color-accent-emphasis); + + // fallback :focus state + &:focus { + @include focusOutlineOnEmphasis; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + box-shadow: none; + } + } + + // default focus state + &:focus-visible { + @include focusOutlineOnEmphasis; + } } .count { diff --git a/src/navigation/menu.scss b/src/navigation/menu.scss index ef921593cd..0cfb57b622 100644 --- a/src/navigation/menu.scss +++ b/src/navigation/menu.scss @@ -22,7 +22,9 @@ border-top-left-radius: $border-radius; border-top-right-radius: $border-radius; - &::before { border-top-left-radius: $border-radius; } + &::before { + border-top-left-radius: $border-radius; + } } &:last-child { @@ -30,13 +32,9 @@ border-bottom-right-radius: $border-radius; border-bottom-left-radius: $border-radius; - &::before { border-bottom-left-radius: $border-radius; } - } - - &:focus { - z-index: 1; - outline: none; - box-shadow: var(--color-primer-shadow-focus); + &::before { + border-bottom-left-radius: $border-radius; + } } &:hover { diff --git a/src/navigation/sidenav.scss b/src/navigation/sidenav.scss index 7fb8a90dd3..26d8d0a180 100644 --- a/src/navigation/sidenav.scss +++ b/src/navigation/sidenav.scss @@ -43,16 +43,9 @@ // States -.SideNav-item:focus { - z-index: 1; - outline: none; - box-shadow: var(--color-primer-shadow-focus); -} - .SideNav-item:hover { text-decoration: none; background-color: var(--color-neutral-subtle); - outline: none; } .SideNav-item:active { @@ -94,11 +87,9 @@ border: 0; } -.SideNav-subItem:hover, -.SideNav-subItem:focus { +.SideNav-subItem:hover { color: var(--color-fg-default); text-decoration: none; - outline: none; } .SideNav-subItem[aria-current]:not([aria-current='false']), diff --git a/src/navigation/subnav.scss b/src/navigation/subnav.scss index 89e03e8fa9..c973d64e35 100644 --- a/src/navigation/subnav.scss +++ b/src/navigation/subnav.scss @@ -1,3 +1,5 @@ +// stylelint-disable selector-max-specificity + // Needs refactoring // Sub nav .subnav { @@ -46,6 +48,22 @@ color: var(--color-fg-on-emphasis); background-color: var(--color-accent-emphasis); border-color: var(--color-accent-emphasis); + + // fallback :focus state + &:focus { + @include focusOutlineOnEmphasis; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + box-shadow: none; + } + } + + // default focus state + &:focus-visible { + @include focusOutlineOnEmphasis; + } } &:first-child { @@ -72,6 +90,7 @@ } .subnav-search-input-wide { + // stylelint-disable-next-line primer/responsive-widths width: 500px; } diff --git a/src/navigation/tabnav.scss b/src/navigation/tabnav.scss index 5d52cc5693..1df230af96 100644 --- a/src/navigation/tabnav.scss +++ b/src/navigation/tabnav.scss @@ -40,13 +40,18 @@ } } - &:hover, - &:focus { + &:hover { color: var(--color-fg-default); text-decoration: none; transition-duration: 0.1s; } + &:focus, + &:focus-visible { + border-radius: $border-radius $border-radius 0 0 !important; + outline-offset: -6px; + } + &:active { color: var(--color-fg-muted); } diff --git a/src/navigation/underline-nav.scss b/src/navigation/underline-nav.scss index f188899df1..356fea8b70 100644 --- a/src/navigation/underline-nav.scss +++ b/src/navigation/underline-nav.scss @@ -1,50 +1,104 @@ +$nav-height: $spacer-3 * 3 !default; // 48px + .UnderlineNav { display: flex; + min-height: $nav-height; overflow-x: auto; overflow-y: hidden; // stylelint-disable-next-line primer/box-shadow box-shadow: inset 0 -1px 0 var(--color-border-muted); + -webkit-overflow-scrolling: auto; justify-content: space-between; + + .Counter { + margin-left: $spacer-2; + color: var(--color-fg-default); + background-color: var(--color-neutral-muted); + + &--primary { + color: var(--color-fg-on-emphasis); + background-color: var(--color-neutral-emphasis); + } + } } .UnderlineNav-body { display: flex; + align-items: center; + gap: $spacer-2; + list-style: none; } .UnderlineNav-item { - padding: $spacer-2 $spacer-3; + position: relative; + display: flex; + padding: 0 $spacer-2; font-size: $body-font-size; // stylelint-disable-next-line primer/typography line-height: 30px; color: var(--color-fg-default); text-align: center; white-space: nowrap; + cursor: pointer; background-color: transparent; border: 0; - // stylelint-disable-next-line primer/borders - border-bottom: 2px $border-style transparent; + border-radius: $border-radius; + align-items: center; &:hover, - &:focus { + &:focus, + &:focus-visible { color: var(--color-fg-default); text-decoration: none; border-bottom-color: var(--color-neutral-muted); - outline: 1px dotted transparent; // Support Firefox custom colors - outline-offset: -1px; + outline-offset: -2px; transition: border-bottom-color 0.12s ease-out; } + // renders a visibly hidden "copy" of the label in bold, reserving box space for when label becomes bold on selected + [data-content]::before { + display: block; + height: 0; + font-weight: $font-weight-bold; + visibility: hidden; + content: attr(data-content); + } + + // increase touch target area + &::before { + @include minTouchTarget($min-height: $nav-height); + } + + // hover state was "sticking" on mobile after click + @media (pointer: fine) { + &:hover { + color: var(--color-fg-default); + text-decoration: none; + background: var(--color-action-list-item-default-hover-bg); + transition: background 0.12s ease-out; + } + } + &.selected, &[role='tab'][aria-selected='true'], &[aria-current]:not([aria-current='false']) { font-weight: $font-weight-bold; color: var(--color-fg-default); border-bottom-color: var(--color-primer-border-active); - outline: 1px dotted transparent; // Support Firefox custom colors - outline-offset: -1px; + outline-offset: -8px; - .UnderlineNav-octicon { - color: var(--color-fg-muted); + // current/selected underline + &::after { + position: absolute; + right: 50%; + // 48px total height / 2 (24px) + 1px + bottom: calc(50% - 25px); + width: 100%; + height: 2px; + content: ''; + background: var(--color-primer-border-active); + border-radius: $border-radius; + transform: translate(50%, -50%); } } } @@ -63,22 +117,18 @@ .UnderlineNav--full { display: block; -} -.UnderlineNav-octicon { - margin-right: $spacer-1; - color: var(--color-fg-subtle); + // required for underline to align with additional wrapper element + .UnderlineNav-body { + min-height: $nav-height; + } } -.UnderlineNav .Counter { - margin-left: $spacer-1; - color: var(--color-fg-default); - background-color: var(--color-neutral-muted); - - &--primary { - color: var(--color-fg-on-emphasis); - background-color: var(--color-neutral-emphasis); - } +.UnderlineNav-octicon { + display: inline !important; + margin-right: $spacer-2; + color: var(--color-fg-muted); + fill: var(--color-fg-muted); } .UnderlineNav-container { diff --git a/src/pagination/pagination.scss b/src/pagination/pagination.scss index 475ef0c044..43090b4e74 100644 --- a/src/pagination/pagination.scss +++ b/src/pagination/pagination.scss @@ -24,7 +24,6 @@ &:focus { text-decoration: none; border-color: var(--color-border-default); - outline: 0; transition-duration: 0.1s; } @@ -74,13 +73,35 @@ // chevron-left .previous_page::before { margin-right: $spacer-1; - clip-path: polygon(9.8px 12.8px, 8.7px 12.8px, 4.5px 8.5px, 4.5px 7.5px, 8.7px 3.2px, 9.8px 4.3px, 6.1px 8px, 9.8px 11.7px, 9.8px 12.8px); + clip-path: + polygon( + 9.8px 12.8px, + 8.7px 12.8px, + 4.5px 8.5px, + 4.5px 7.5px, + 8.7px 3.2px, + 9.8px 4.3px, + 6.1px 8px, + 9.8px 11.7px, + 9.8px 12.8px + ); } // chevron-right .next_page::after { margin-left: $spacer-1; - clip-path: polygon(6.2px 3.2px, 7.3px 3.2px, 11.5px 7.5px, 11.5px 8.5px, 7.3px 12.8px, 6.2px 11.7px, 9.9px 8px, 6.2px 4.3px, 6.2px 3.2px); + clip-path: + polygon( + 6.2px 3.2px, + 7.3px 3.2px, + 11.5px 7.5px, + 11.5px 8.5px, + 7.3px 12.8px, + 6.2px 11.7px, + 9.9px 8px, + 6.2px 4.3px, + 6.2px 3.2px + ); } } diff --git a/src/popover/popover.scss b/src/popover/popover.scss index 082a48fbb8..e283d9e9a7 100644 --- a/src/popover/popover.scss +++ b/src/popover/popover.scss @@ -122,6 +122,7 @@ } &::before { + // stylelint-disable-next-line function-no-unknown margin-top: -($spacer-2 + 1); } diff --git a/src/support/mixins/color-modes.scss b/src/support/mixins/color-modes.scss index 6383c27931..3a5335d64c 100644 --- a/src/support/mixins/color-modes.scss +++ b/src/support/mixins/color-modes.scss @@ -84,10 +84,12 @@ @each $name, $value in $color-map { @each $type, $color in $value { @if $type == dark { + // stylelint-disable-next-line function-no-unknown $dark-colors: append($dark-colors, (--color-#{$name}, #{$color})); } @else { + // stylelint-disable-next-line function-no-unknown $light-colors: append($light-colors, (--color-#{$name}, #{$color})); } } diff --git a/src/support/mixins/layout.scss b/src/support/mixins/layout.scss index a3c51d705f..dfd0613d18 100644 --- a/src/support/mixins/layout.scss +++ b/src/support/mixins/layout.scss @@ -7,6 +7,7 @@ @else { // Retrieves the value from the key + // stylelint-disable-next-line function-no-unknown $value: map-get($breakpoints, $breakpoint); // If the key exists in the map diff --git a/src/support/mixins/misc.scss b/src/support/mixins/misc.scss index d04208f9cf..90d4eeb1b9 100644 --- a/src/support/mixins/misc.scss +++ b/src/support/mixins/misc.scss @@ -16,7 +16,7 @@ &::after { // stylelint-disable-next-line primer/spacing - margin-left: 1px; + margin-left: 2px; background-color: var(--color-canvas-default); background-image: linear-gradient($background, $background); } @@ -25,3 +25,49 @@ background-color: $border; } } + +// global focus styles + +// inset box-shadow for form controls +@mixin focusBoxShadowInset($outlineWidth: 1px, $outlineColor: var(--color-accent-fg)) { + border-color: var(--color-accent-fg); + outline: none; + box-shadow: inset 0 0 0 $outlineWidth $outlineColor; +} + +// box-shadow for :target styles (no inset) +// !important to override PCSS utilities +@mixin targetBoxShadow($outlineWidth: 2px, $outlineColor: var(--color-accent-fg)) { + outline: none !important; + box-shadow: 0 0 0 $outlineWidth $outlineColor !important; +} + +// outline +@mixin focusOutline($outlineOffset: -2px, $outlineColor: var(--color-accent-fg)) { + outline: 2px solid $outlineColor; + outline-offset: $outlineOffset; + box-shadow: none; +} + +// outline with fg box-shadow for buttons +@mixin focusOutlineOnEmphasis($outlineOffset: -2px, $outlineColor: var(--color-accent-fg)) { + outline: 2px solid $outlineColor; + outline-offset: $outlineOffset; + box-shadow: inset 0 0 0 3px var(--color-fg-on-emphasis); +} + +// if min-width is undefined, return only min-height +@mixin minTouchTarget($min-height: 32px, $min-width: '') { + position: absolute; + top: 50%; + left: 50%; + width: 100%; + height: 100%; + min-height: $min-height; + content: ''; + transform: translateX(-50%) translateY(-50%); + + @if $min-width != '' { + min-width: $min-width; + } +} diff --git a/src/support/variables/layout.scss b/src/support/variables/layout.scss index 47dbbf72b8..2f99101725 100644 --- a/src/support/variables/layout.scss +++ b/src/support/variables/layout.scss @@ -82,6 +82,7 @@ $spacers-large: ( 12: $spacer-12, ) !default; +// stylelint-disable-next-line function-no-unknown $spacer-map-extended: map-merge( ( 0: 0, diff --git a/src/timeline/timeline-item.scss b/src/timeline/timeline-item.scss index fcbf377c2a..18907bdc88 100644 --- a/src/timeline/timeline-item.scss +++ b/src/timeline/timeline-item.scss @@ -57,6 +57,7 @@ .TimelineItem-avatar { position: absolute; + // stylelint-disable-next-line function-no-unknown left: -($spacer-6 + $spacer-5); z-index: 1; } @@ -67,6 +68,7 @@ height: $spacer-4; margin: 0; margin-bottom: -$spacer-3; + // stylelint-disable-next-line function-no-unknown margin-left: -($spacer-6 + $spacer-3); background-color: var(--color-canvas-default); border: 0; diff --git a/src/toasts/toasts.scss b/src/toasts/toasts.scss index 3558a5b3ad..ed1cb21da9 100644 --- a/src/toasts/toasts.scss +++ b/src/toasts/toasts.scss @@ -40,9 +40,7 @@ background-color: transparent; border: 0; - &:focus, &:hover { - outline: none; opacity: 0.7; } @@ -119,6 +117,11 @@ } @keyframes Toast--spinner { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } } diff --git a/src/utilities/details.scss b/src/utilities/details.scss index ad214f5654..df25180e46 100644 --- a/src/utilities/details.scss +++ b/src/utilities/details.scss @@ -1,4 +1,4 @@ -// stylelint-disable selector-max-type +// stylelint-disable selector-max-type, selector-max-specificity, max-nesting-depth, selector-no-qualifying-type .details-overlay[open] > summary::before { position: fixed; @@ -20,9 +20,86 @@ .details-reset { // Remove marker added by the display: list-item browser default - > summary { list-style: none; } + > summary { + list-style: none; + transition: 80ms cubic-bezier(0.33, 1, 0.68, 1); + transition-property: color, background-color, box-shadow, border-color; + // fallback :focus state + &:focus { + @include focusOutline; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + } + } + + // default focus state + &:focus-visible { + @include focusOutline; + } + + &.btn-primary { + // fallback :focus state + &:focus { + @include focusOutlineOnEmphasis; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + box-shadow: none; + } + } + + // default focus state + &:focus-visible { + @include focusOutlineOnEmphasis; + } + } + } // Remove marker added by details polyfill - > summary::before { display: none; } + > summary::before { + display: none; + } // Remove marker added by Chrome - > summary::-webkit-details-marker { display: none; } + > summary::-webkit-details-marker { + display: none; + } +} + +.details-overlay > summary { + transition: 80ms cubic-bezier(0.33, 1, 0.68, 1); + transition-property: color, background-color, box-shadow, border-color; + // fallback :focus state + &:focus { + @include focusOutline; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + } + } + + // default focus state + &:focus-visible { + @include focusOutline; + } + + &.btn-primary { + // fallback :focus state + &:focus { + @include focusOutlineOnEmphasis; + + // remove fallback :focus if :focus-visible is supported + &:not(:focus-visible) { + outline: solid 1px transparent; + box-shadow: none; + } + } + + // default focus state + &:focus-visible { + @include focusOutlineOnEmphasis; + } + } } diff --git a/yarn.lock b/yarn.lock index d098eab482..cccd6dfaee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1167,10 +1167,10 @@ resolved "https://registry.yarnpkg.com/@primer/primitives/-/primitives-7.7.0.tgz#4e838afaf997036720a43ebab0211d2de77b1606" integrity sha512-LSd96U2/A70obilbdYiEKI8D/wXUtZnKmUI/ScLOlGDju4iuwd3pJsmFoBwM1Us6vV23V6mapIG+lh27RzauaA== -"@primer/stylelint-config@^12.3.3": - version "12.3.3" - resolved "https://registry.yarnpkg.com/@primer/stylelint-config/-/stylelint-config-12.3.3.tgz#f4ef0548a7884229358e5243d746d6d3af6a73a5" - integrity sha512-PHcBGEM/8mToW9aVrcRi9RVZN0WpW8zHN1C8+deP6tozclP06jzHsdprJG02buyR6N1BmDllsEBYZ2KK4Y71Bg== +"@primer/stylelint-config@^12.4.0": + version "12.4.0" + resolved "https://registry.yarnpkg.com/@primer/stylelint-config/-/stylelint-config-12.4.0.tgz#3a9e8ed20673ed6ea17c703bb754b95b82a8a0f4" + integrity sha512-7fjs9KBnMdXLlWbPO7Q9WLS1y4kFitmISdVoADtvLxx0k5bY9XWc0sOhEiazioYo9ipwk80VwF4LlijeaZT7JA== dependencies: anymatch "^3.1.1" globby "^11.0.1" @@ -1178,7 +1178,7 @@ postcss-scss "^4.0.2" postcss-value-parser "^4.0.2" string.prototype.matchall "^4.0.2" - stylelint-config-standard "24.0.0" + stylelint-config-standard "25.0.0" stylelint-no-unsupported-browser-features "^5.0.1" stylelint-order "^5.0.0" stylelint-scss "^4.0.0" @@ -5383,17 +5383,17 @@ style-search@^0.1.0: resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= -stylelint-config-recommended@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-6.0.0.tgz#fd2523a322836005ad9bf473d3e5534719c09f9d" - integrity sha512-ZorSSdyMcxWpROYUvLEMm0vSZud2uB7tX1hzBZwvVY9SV/uly4AvvJPPhCcymZL3fcQhEQG5AELmrxWqtmzacw== +stylelint-config-recommended@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz#7497372ae83ab7a6fffc18d7d7b424c6480ae15e" + integrity sha512-yGn84Bf/q41J4luis1AZ95gj0EQwRX8lWmGmBwkwBNSkpGSpl66XcPTulxGa/Z91aPoNGuIGBmFkcM1MejMo9Q== -stylelint-config-standard@24.0.0: - version "24.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-24.0.0.tgz#6823f207ab997ae0b641f9a636d007cc44d77541" - integrity sha512-+RtU7fbNT+VlNbdXJvnjc3USNPZRiRVp/d2DxOF/vBDDTi0kH5RX2Ny6errdtZJH3boO+bmqIYEllEmok4jiuw== +stylelint-config-standard@25.0.0: + version "25.0.0" + resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-25.0.0.tgz#2c916984e6655d40d6e8748b19baa8603b680bff" + integrity sha512-21HnP3VSpaT1wFjFvv9VjvOGDtAviv47uTp3uFmzcN+3Lt+RYRv6oAplLaV51Kf792JSxJ6svCJh/G18E9VnCA== dependencies: - stylelint-config-recommended "^6.0.0" + stylelint-config-recommended "^7.0.0" stylelint-no-unsupported-browser-features@^5.0.1: version "5.0.2"