mirror of
https://github.com/primer/css.git
synced 2024-11-26 02:38:32 +03:00
UnderlineNav :focus
styles (#1764)
* add pseudo selectors * adjustments * add stories, cleanup * update mixin * fix mixin * lint * add back overflow styles * adjust focus for better overflow state, scrollsnap * post test adjustments, move hacks to primer css * Stylelint auto-fixes * hover state desktop only * document data-content hack * Create nice-days-jog.md Co-authored-by: Actions Auto Build <actions@github.com> Co-authored-by: simurai <simurai@github.com>
This commit is contained in:
parent
b1c43f1f8d
commit
cdd9728c7e
7
.changeset/nice-days-jog.md
Normal file
7
.changeset/nice-days-jog.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
"@primer/css": minor
|
||||
---
|
||||
|
||||
UnderlineNav `:focus` styles
|
||||
Refactor selected state and spacing
|
||||
Add selected bold state override from github/github
|
@ -0,0 +1,73 @@
|
||||
import React from 'react'
|
||||
import clsx from 'clsx'
|
||||
import {UnderlineNavItemTemplate} from './UnderlineNavItem.stories'
|
||||
|
||||
export default {
|
||||
title: 'Components/Navigation/UnderlineNav',
|
||||
excludeStories: ['UnderlineNavTemplate'],
|
||||
layout: 'padded',
|
||||
argTypes: {
|
||||
variant: {
|
||||
options: [0, 1, 2], // iterator
|
||||
mapping: ['', 'UnderlineNav--right', 'UnderlineNav--full'], // values
|
||||
control: {
|
||||
type: 'inline-radio',
|
||||
labels: ['default', 'align-right', 'fullwidth']
|
||||
},
|
||||
description: 'nav positioning options',
|
||||
table: {
|
||||
category: 'CSS'
|
||||
}
|
||||
},
|
||||
children: {
|
||||
description: 'creates a slot for children',
|
||||
table: {
|
||||
category: 'HTML'
|
||||
}
|
||||
},
|
||||
actionStart: {
|
||||
description: 'action to left of nav',
|
||||
table: {
|
||||
category: 'HTML'
|
||||
}
|
||||
},
|
||||
actionEnd: {
|
||||
description: 'action to right of nav',
|
||||
table: {
|
||||
category: 'HTML'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const UnderlineNavTemplate = ({variant, children, actionStart, actionEnd}) => (
|
||||
<>
|
||||
<nav className={clsx('UnderlineNav', variant && `${variant}`)}>
|
||||
{actionStart}
|
||||
{variant === 'UnderlineNav--full' ? (
|
||||
<div class="container-lg UnderlineNav-container">
|
||||
<ul class="UnderlineNav-body" role="tablist">
|
||||
{children}
|
||||
</ul>
|
||||
</div>
|
||||
) : (
|
||||
<ul class="UnderlineNav-body" role="tablist">
|
||||
{children}
|
||||
</ul>
|
||||
)}
|
||||
{actionEnd}
|
||||
</nav>
|
||||
</>
|
||||
)
|
||||
|
||||
export const Playground = UnderlineNavTemplate.bind({})
|
||||
Playground.args = {
|
||||
variant: 0,
|
||||
children: (
|
||||
<>
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="button" selected usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="button" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="button" usesDataContent />
|
||||
</>
|
||||
)
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
import React from 'react'
|
||||
import clsx from 'clsx'
|
||||
import {ButtonTemplate} from '../Button/Button.stories'
|
||||
import {LinkTemplate} from '../Link/Link.stories'
|
||||
|
||||
export default {
|
||||
title: 'Components/Navigation/UnderlineNav/Action',
|
||||
excludeStories: ['UnderlineNavActionTemplate'],
|
||||
layout: 'padded',
|
||||
argTypes: {
|
||||
semanticItemType: {
|
||||
options: ['button', 'link'],
|
||||
control: {
|
||||
type: 'inline-radio'
|
||||
},
|
||||
description: 'item can be a button or a link',
|
||||
table: {
|
||||
category: 'HTML'
|
||||
}
|
||||
},
|
||||
label: {
|
||||
name: 'label',
|
||||
type: 'string',
|
||||
description: 'Item label text',
|
||||
table: {
|
||||
category: 'HTML'
|
||||
}
|
||||
},
|
||||
focusElement: {
|
||||
control: {type: 'boolean'},
|
||||
description: 'set manual focus on item',
|
||||
table: {
|
||||
category: 'Interactive'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const UnderlineNavActionTemplate = ({semanticItemType, label, focusElement}) => {
|
||||
return (
|
||||
<div class="UnderlineNav-actions">
|
||||
{semanticItemType === 'button' ? (
|
||||
<ButtonTemplate label={label} focusAllElements={focusElement} />
|
||||
) : (
|
||||
<LinkTemplate label={label} focusAllElements={focusElement} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const Playground = UnderlineNavActionTemplate.bind({})
|
||||
Playground.args = {
|
||||
semanticItemType: 'button',
|
||||
label: 'Action',
|
||||
focusElement: false
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
import React from 'react'
|
||||
import clsx from 'clsx'
|
||||
import useToggle from '../../helpers/useToggle.jsx'
|
||||
|
||||
export default {
|
||||
title: 'Components/Navigation/UnderlineNav/Item',
|
||||
excludeStories: ['UnderlineNavItemTemplate'],
|
||||
layout: 'padded',
|
||||
argTypes: {
|
||||
selected: {
|
||||
control: {type: 'boolean'},
|
||||
description: 'active nav item',
|
||||
table: {
|
||||
category: 'CSS'
|
||||
}
|
||||
},
|
||||
usesDataContent: {
|
||||
control: {type: 'boolean'},
|
||||
description: 'creates a hidden label to allow for bold text without layout shift',
|
||||
table: {
|
||||
category: 'CSS'
|
||||
}
|
||||
},
|
||||
semanticItemType: {
|
||||
options: ['button', 'link'],
|
||||
control: {
|
||||
type: 'inline-radio'
|
||||
},
|
||||
description: 'item can be a button or a link',
|
||||
table: {
|
||||
category: 'HTML'
|
||||
}
|
||||
},
|
||||
label: {
|
||||
name: 'label',
|
||||
type: 'string',
|
||||
description: 'Item label text',
|
||||
table: {
|
||||
category: 'HTML'
|
||||
}
|
||||
},
|
||||
focusElement: {
|
||||
control: {type: 'boolean'},
|
||||
description: 'set manual focus on tab item',
|
||||
table: {
|
||||
category: 'Interactive'
|
||||
}
|
||||
},
|
||||
icon: {
|
||||
control: {type: 'boolean'},
|
||||
description: 'show icon',
|
||||
table: {
|
||||
category: 'CSS'
|
||||
}
|
||||
},
|
||||
counter: {
|
||||
control: {type: 'boolean'},
|
||||
description: 'show counter',
|
||||
table: {
|
||||
category: 'CSS'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const UnderlineNavItemTemplate = ({
|
||||
semanticItemType,
|
||||
label,
|
||||
selected,
|
||||
focusElement,
|
||||
icon,
|
||||
counter,
|
||||
usesDataContent
|
||||
}) => {
|
||||
const [isSelected, itemisSelected] = useToggle()
|
||||
return (
|
||||
<li className="d-inline-flex">
|
||||
{semanticItemType === 'button' ? (
|
||||
<button
|
||||
className={clsx('UnderlineNav-item', focusElement && 'focus')}
|
||||
role="tab"
|
||||
aria-selected={selected || isSelected ? 'true' : undefined}
|
||||
onClick={itemisSelected}
|
||||
>
|
||||
{icon && (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
height="16"
|
||||
className="UnderlineNav-octicon"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M14.064 0a8.75 8.75 0 00-6.187 2.563l-.459.458c-.314.314-.616.641-.904.979H3.31a1.75 1.75 0 00-1.49.833L.11 7.607a.75.75 0 00.418 1.11l3.102.954c.037.051.079.1.124.145l2.429 2.428c.046.046.094.088.145.125l.954 3.102a.75.75 0 001.11.418l2.774-1.707a1.75 1.75 0 00.833-1.49V9.485c.338-.288.665-.59.979-.904l.458-.459A8.75 8.75 0 0016 1.936V1.75A1.75 1.75 0 0014.25 0h-.186zM10.5 10.625c-.088.06-.177.118-.266.175l-2.35 1.521.548 1.783 1.949-1.2a.25.25 0 00.119-.213v-2.066zM3.678 8.116L5.2 5.766c.058-.09.117-.178.176-.266H3.309a.25.25 0 00-.213.119l-1.2 1.95 1.782.547zm5.26-4.493A7.25 7.25 0 0114.063 1.5h.186a.25.25 0 01.25.25v.186a7.25 7.25 0 01-2.123 5.127l-.459.458a15.21 15.21 0 01-2.499 2.02l-2.317 1.5-2.143-2.143 1.5-2.317a15.25 15.25 0 012.02-2.5l.458-.458h.002zM12 5a1 1 0 11-2 0 1 1 0 012 0zm-8.44 9.56a1.5 1.5 0 10-2.12-2.12c-.734.73-1.047 2.332-1.15 3.003a.23.23 0 00.265.265c.671-.103 2.273-.416 3.005-1.148z"
|
||||
></path>
|
||||
</svg>
|
||||
)}
|
||||
<span data-content={usesDataContent ? label : undefined}>{label}</span>
|
||||
{counter && <span class="Counter">10</span>}
|
||||
</button>
|
||||
) : (
|
||||
<a
|
||||
className={clsx('UnderlineNav-item', focusElement && 'focus')}
|
||||
aria-current={selected || isSelected ? 'true' : undefined}
|
||||
onClick={itemisSelected}
|
||||
// aria-current={selected ? 'page' : undefined}
|
||||
>
|
||||
{icon && (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
height="16"
|
||||
className="UnderlineNav-octicon"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M14.064 0a8.75 8.75 0 00-6.187 2.563l-.459.458c-.314.314-.616.641-.904.979H3.31a1.75 1.75 0 00-1.49.833L.11 7.607a.75.75 0 00.418 1.11l3.102.954c.037.051.079.1.124.145l2.429 2.428c.046.046.094.088.145.125l.954 3.102a.75.75 0 001.11.418l2.774-1.707a1.75 1.75 0 00.833-1.49V9.485c.338-.288.665-.59.979-.904l.458-.459A8.75 8.75 0 0016 1.936V1.75A1.75 1.75 0 0014.25 0h-.186zM10.5 10.625c-.088.06-.177.118-.266.175l-2.35 1.521.548 1.783 1.949-1.2a.25.25 0 00.119-.213v-2.066zM3.678 8.116L5.2 5.766c.058-.09.117-.178.176-.266H3.309a.25.25 0 00-.213.119l-1.2 1.95 1.782.547zm5.26-4.493A7.25 7.25 0 0114.063 1.5h.186a.25.25 0 01.25.25v.186a7.25 7.25 0 01-2.123 5.127l-.459.458a15.21 15.21 0 01-2.499 2.02l-2.317 1.5-2.143-2.143 1.5-2.317a15.25 15.25 0 012.02-2.5l.458-.458h.002zM12 5a1 1 0 11-2 0 1 1 0 012 0zm-8.44 9.56a1.5 1.5 0 10-2.12-2.12c-.734.73-1.047 2.332-1.15 3.003a.23.23 0 00.265.265c.671-.103 2.273-.416 3.005-1.148z"
|
||||
></path>
|
||||
</svg>
|
||||
)}
|
||||
<span data-content={usesDataContent ? label : undefined}>{label}</span>
|
||||
{counter && <span class="Counter">10</span>}
|
||||
</a>
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
export const Playground = UnderlineNavItemTemplate.bind({})
|
||||
Playground.args = {
|
||||
semanticItemType: 'button',
|
||||
label: 'Item',
|
||||
selected: false,
|
||||
focusElement: false,
|
||||
icon: false,
|
||||
counter: false,
|
||||
usesDataContent: true
|
||||
}
|
@ -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: (
|
||||
<>
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" selectedusesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" usesDataContent />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const ButtonItems = UnderlineNavTemplate.bind({})
|
||||
ButtonItems.args = {
|
||||
children: (
|
||||
<>
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="button" selected usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="button" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="button" usesDataContent />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const NavRight = UnderlineNavTemplate.bind({})
|
||||
NavRight.args = {
|
||||
variant: 'UnderlineNav--right',
|
||||
children: (
|
||||
<>
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" selected usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" usesDataContent />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const NavFullWidth = UnderlineNavTemplate.bind({})
|
||||
NavFullWidth.args = {
|
||||
variant: 'UnderlineNav--full',
|
||||
children: (
|
||||
<>
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" selected usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" usesDataContent />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const ActionRight = UnderlineNavTemplate.bind({})
|
||||
ActionRight.args = {
|
||||
children: (
|
||||
<>
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" selected usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" usesDataContent />
|
||||
</>
|
||||
),
|
||||
actionEnd: <UnderlineNavActionTemplate label="Action" semanticItemType="button" />
|
||||
}
|
||||
|
||||
export const ActionLeft = UnderlineNavTemplate.bind({})
|
||||
ActionLeft.args = {
|
||||
children: (
|
||||
<>
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" selected usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item" semanticItemType="link" usesDataContent />
|
||||
</>
|
||||
),
|
||||
actionStart: <UnderlineNavActionTemplate label="Action" semanticItemType="button" />
|
||||
}
|
||||
|
||||
export const Overflow = UnderlineNavTemplate.bind({})
|
||||
Overflow.args = {
|
||||
children: (
|
||||
<>
|
||||
<UnderlineNavItemTemplate label="Item name 1" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name 2" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name 3" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name 4" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name 5" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name 6" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name 7" semanticItemType="link" selected />
|
||||
<UnderlineNavItemTemplate label="Item name 8" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name 9" semanticItemType="link" usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name 10" semanticItemType="link" usesDataContent />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const Icons = UnderlineNavTemplate.bind({})
|
||||
Icons.args = {
|
||||
children: (
|
||||
<>
|
||||
<UnderlineNavItemTemplate label="Item name" semanticItemType="link" icon usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name" semanticItemType="link" icon usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name" semanticItemType="link" selected icon usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name" semanticItemType="link" icon usesDataContent />
|
||||
<UnderlineNavItemTemplate label="Item name" semanticItemType="link" icon usesDataContent />
|
||||
</>
|
||||
)
|
||||
}
|
@ -1,50 +1,99 @@
|
||||
$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;
|
||||
}
|
||||
|
||||
.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 {
|
||||
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;
|
||||
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]) {
|
||||
&[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;
|
||||
|
||||
.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%);
|
||||
}
|
||||
}
|
||||
|
||||
// remove when global focus state is merged
|
||||
&.focus,
|
||||
&:focus {
|
||||
@include focusOutline;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -63,22 +112,18 @@
|
||||
|
||||
.UnderlineNav--full {
|
||||
display: block;
|
||||
|
||||
// required for underline to align with additional wrapper element
|
||||
.UnderlineNav-body {
|
||||
min-height: $nav-height;
|
||||
}
|
||||
}
|
||||
|
||||
.UnderlineNav-octicon {
|
||||
margin-right: $spacer-1;
|
||||
color: var(--color-fg-subtle);
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
display: inline !important;
|
||||
margin-right: $spacer-2;
|
||||
color: var(--color-fg-muted);
|
||||
fill: var(--color-fg-muted);
|
||||
}
|
||||
|
||||
.UnderlineNav-container {
|
||||
|
@ -24,3 +24,27 @@
|
||||
background-color: $border;
|
||||
}
|
||||
}
|
||||
|
||||
// global focus styles
|
||||
|
||||
@mixin focusOutline {
|
||||
z-index: 1;
|
||||
outline: 2px solid var(--color-accent-fg);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user