Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor "focus-ring" tokens and mixins to support both "active" and "critical" colors #98

Merged
merged 5 commits into from
Mar 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/serious-peas-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashicorp/design-system-tokens": minor
---

refactored “focus-ring” tokens and CSS helpers to support both “action” and “critical“ colors
5 changes: 5 additions & 0 deletions .changeset/thirty-fireants-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashicorp/design-system-components": patch
---

refactored the “focus-ring” mixins to support both “action” (default) and “critical“ colors
12 changes: 6 additions & 6 deletions packages/components/app/styles/mixins/_focus-ring.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@
// - https://github.com/hashicorp/design-system-components/issues/161
// - https://www.tpgi.com/focus-visible-and-backwards-compatibility/

@mixin hds-focus-ring-basic() {
@mixin hds-focus-ring-basic($color: action) {
outline-style: solid; // used to avoid double outline+focus-ring in Safari (see https://github.com/hashicorp/design-system-components/issues/161#issuecomment-1031548656)
outline-color: transparent;

// default focus for browsers that still rely on ":focus"
&:focus,
&.is-focus {
box-shadow: var(--token-focus-ring-box-shadow);
box-shadow: var(--token-focus-ring-#{$color}-box-shadow);
}
// undo the previous declaration for browsers that support ":focus-visible" but wouldn't normally show default focus styles
&:focus:not(:focus-visible) {
box-shadow: none;
}
// set focus for browsers that support ":focus-visible"
&:focus-visible {
box-shadow: var(--token-focus-ring-box-shadow);
box-shadow: var(--token-focus-ring-#{$color}-box-shadow);
}
// remove the focus ring on "active + focused" state (by design)
&:focus:active,
Expand All @@ -26,7 +26,7 @@
}
}

@mixin hds-focus-ring-with-pseudo-element($top: 0, $right: 0, $bottom: 0, $left: 0, $radius: 5px) {
@mixin hds-focus-ring-with-pseudo-element($top: 0, $right: 0, $bottom: 0, $left: 0, $radius: 5px, $color: action) {
isolation: isolate; // used to create a new stacking context (needed to have the pseudo element below text/icon but not the parent container)
outline-style: solid; // used to avoid double outline+focus-ring in Safari (see https://github.com/hashicorp/design-system-components/issues/161#issuecomment-1031548656)
outline-color: transparent;
Expand All @@ -48,7 +48,7 @@
&:focus,
&.is-focus {
&::before {
box-shadow: var(--token-focus-ring-box-shadow);
box-shadow: var(--token-focus-ring-#{$color}-box-shadow);
}
}
// undo the previous declaration for browsers that support ":focus-visible" but wouldn't normally show default focus styles
Expand All @@ -60,7 +60,7 @@
// set focus for browsers that support ":focus-visible"
&:focus-visible {
&::before {
box-shadow: var(--token-focus-ring-box-shadow);
box-shadow: var(--token-focus-ring-#{$color}-box-shadow);
}
}
// remove the focus ring on "active + focused" state (by design)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,77 @@
value).</li>
</ul>

<h4 class="dummy-h4">Sass mixins</h4>
<p class="dummy-paragraph">We have also created two
<strong>Sass mixins</strong>
<code class="dummy-code">hds-focus-ring-basic</code>
and
<code class="dummy-code">hds-focus-ring-with-pseudo-element</code>
but they're mainly used for internal use (to the design system codebase). These mixins do more than just apply the
focus style: they also take care of all the different way to declare the
<code class="dummy-code">:focus/:focus-visible</code>
for different browsers.
</p>
<p class="dummy-paragraph">To use these mixins you have to import the Sass file
<code class="dummy-code">packages/components/app/styles/mixins/_focus-ring.scss</code>
contained in the
<code class="dummy-code">@hashicorp/design-system</code>
monorepo or the same file
<code class="dummy-code">app/styles/mixins/_focus-ring.scss</code>
distributed in the
<code class="dummy-code">@hashicorp/design-system-components</code>
package.</p>
<p class="dummy-paragraph">Then the mixins can be invoked in this way:</p>
{{! prettier-ignore-start }}
<CodeBlock
@language="css"
@code="
/* include the mixin file via @use (path will depend on your context) */
@use '../mixins/focus-ring' as *;

/* apply the focus-ring as box-shadow ('action' will be the default color ) */
.your-selector {
[...your CSS declarations]
@include hds-focus-ring-basic();
}

/* apply the focus-ring as pseudo-element (with 'critical' color ) */
.your-selector {
[...your CSS declarations]
@include hds-focus-ring-with-pseudo-element($top: 0, $right: 0, $bottom: 0, $left: 0, $radius: 5px, $color: critical);
}
"
/>
{{! prettier-ignore-end }}

</section>

<section data-test-percy>
<h3 class="dummy-h3">Showcase</h3>
<h4 class="dummy-h4">Focus ring:</h4>
<p class="dummy-paragraph">Standalone "focus ring" effect</p>
<div class="dummy-focus-ring-samples">
<div class="dummy-focus-ring-sample hds-focus-ring-box-shadow">
<div class="dummy-focus-ring-sample hds-focus-ring-action-box-shadow">
<DummyPlaceholder @text="no radius" @width="100" @height="100" @background="transparent" />
</div>
<div class="dummy-focus-ring-sample dummy-focus-ring-sample--border-radius hds-focus-ring-box-shadow">
<div class="dummy-focus-ring-sample dummy-focus-ring-sample--border-radius hds-focus-ring-action-box-shadow">
<DummyPlaceholder @text="with border radius" @width="100" @height="100" @background="transparent" />
</div>
</div>
<div class="dummy-focus-ring-samples">
<div class="dummy-focus-ring-sample">
<span class="dummy-text-small">action</span>
<br />
<div class="hds-focus-ring-action-box-shadow">
<DummyPlaceholder @text="with border radius" @width="100" @height="100" @background="transparent" />
</div>
</div>
<div class="dummy-focus-ring-sample">
<span class="dummy-text-small">critical</span>
<br />
<div class="hds-focus-ring-critical-box-shadow">
<DummyPlaceholder @text="with border radius" @width="100" @height="100" @background="transparent" />
</div>
</div>
</div>
</section>
5 changes: 3 additions & 2 deletions packages/tokens/dist/devdot/css/helpers/focus-ring.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* Do not edit directly
* Generated on Tue, 22 Feb 2022 21:05:19 GMT
* Generated on Fri, 18 Mar 2022 20:06:01 GMT
*/

.hds-focus-ring-box-shadow { box-shadow: var(--token-focus-ring-box-shadow); }
.hds-focus-ring-action-box-shadow { box-shadow: var(--token-focus-ring-action-box-shadow); }
.hds-focus-ring-critical-box-shadow { box-shadow: var(--token-focus-ring-critical-box-shadow); }
5 changes: 3 additions & 2 deletions packages/tokens/dist/devdot/css/tokens.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Do not edit directly
* Generated on Thu, 17 Mar 2022 08:19:13 GMT
* Generated on Fri, 18 Mar 2022 20:06:01 GMT
*/

:root {
Expand Down Expand Up @@ -238,7 +238,8 @@
--token-surface-high-box-shadow: 0 0 0 1px #656a7640, 0px 2px 3px 0px #656a7626, 0px 16px 16px -10px #656a7633;
--token-surface-higher-box-shadow: 0 0 0 1px #656a7633, 0px 2px 3px 0px #656a761a, 0px 12px 28px 0px #656a7640;
--token-surface-overlay-box-shadow: 0 0 0 1px #3b3d4566, 0px 2px 3px 0px #3b3d4580, 0px 12px 24px 0px #3b3d4599;
--token-focus-ring-box-shadow: inset 0 0 0 1px #0c56e9, 0 0 0 3px #5990ff;
--token-focus-ring-action-box-shadow: inset 0 0 0 1px #0c56e9, 0 0 0 3px #5990ff;
--token-focus-ring-critical-box-shadow: inset 0 0 0 1px #c00005, 0 0 0 3px #dd7578;
--token-typography-font-stack-display: -apple-system, BlinkMacSystemFont, SF Pro Display, Segoe UI Display, Ubuntu, sans-serif;
--token-typography-font-stack-text: -apple-system, BlinkMacSystemFont, SF Pro Text, Segoe UI Text, Ubuntu, sans-serif;
--token-typography-font-stack-code: SF Mono, Consolas, Ubuntu Mono, monospace;
Expand Down
25 changes: 22 additions & 3 deletions packages/tokens/dist/docs/devdot/tokens.json
Original file line number Diff line number Diff line change
Expand Up @@ -5288,15 +5288,34 @@
{
"value": "inset 0 0 0 1px #0c56e9, 0 0 0 3px #5990ff",
"original": {
"value": "{focus-ring.internal.box-shadow.value}, {focus-ring.external.box-shadow.value}"
"value": "{focus-ring.action.internal-box-shadow.value}, {focus-ring.action.external-box-shadow.value}"
},
"name": "token-focus-ring-box-shadow",
"name": "token-focus-ring-action-box-shadow",
"attributes": {
"category": "focus-ring",
"type": "box-shadow"
"type": "action",
"item": "box-shadow"
},
"path": [
"focus-ring",
"action",
"box-shadow"
]
},
{
"value": "inset 0 0 0 1px #c00005, 0 0 0 3px #dd7578",
"original": {
"value": "{focus-ring.critical.internal-box-shadow.value}, {focus-ring.critical.external-box-shadow.value}"
},
"name": "token-focus-ring-critical-box-shadow",
"attributes": {
"category": "focus-ring",
"type": "critical",
"item": "box-shadow"
},
"path": [
"focus-ring",
"critical",
"box-shadow"
]
},
Expand Down
25 changes: 22 additions & 3 deletions packages/tokens/dist/docs/products/tokens.json
Original file line number Diff line number Diff line change
Expand Up @@ -5242,15 +5242,34 @@
{
"value": "inset 0 0 0 1px #0c56e9, 0 0 0 3px #5990ff",
"original": {
"value": "{focus-ring.internal.box-shadow.value}, {focus-ring.external.box-shadow.value}"
"value": "{focus-ring.action.internal-box-shadow.value}, {focus-ring.action.external-box-shadow.value}"
},
"name": "token-focus-ring-box-shadow",
"name": "token-focus-ring-action-box-shadow",
"attributes": {
"category": "focus-ring",
"type": "box-shadow"
"type": "action",
"item": "box-shadow"
},
"path": [
"focus-ring",
"action",
"box-shadow"
]
},
{
"value": "inset 0 0 0 1px #c00005, 0 0 0 3px #dd7578",
"original": {
"value": "{focus-ring.critical.internal-box-shadow.value}, {focus-ring.critical.external-box-shadow.value}"
},
"name": "token-focus-ring-critical-box-shadow",
"attributes": {
"category": "focus-ring",
"type": "critical",
"item": "box-shadow"
},
"path": [
"focus-ring",
"critical",
"box-shadow"
]
},
Expand Down
5 changes: 3 additions & 2 deletions packages/tokens/dist/products/css/helpers/focus-ring.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* Do not edit directly
* Generated on Tue, 22 Feb 2022 21:05:19 GMT
* Generated on Fri, 18 Mar 2022 20:06:01 GMT
*/

.hds-focus-ring-box-shadow { box-shadow: var(--token-focus-ring-box-shadow); }
.hds-focus-ring-action-box-shadow { box-shadow: var(--token-focus-ring-action-box-shadow); }
.hds-focus-ring-critical-box-shadow { box-shadow: var(--token-focus-ring-critical-box-shadow); }
5 changes: 3 additions & 2 deletions packages/tokens/dist/products/css/tokens.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* Do not edit directly
* Generated on Mon, 07 Mar 2022 11:14:41 GMT
* Generated on Fri, 18 Mar 2022 20:06:01 GMT
*/

:root {
Expand Down Expand Up @@ -236,7 +236,8 @@
--token-surface-high-box-shadow: 0 0 0 1px #656a7640, 0px 2px 3px 0px #656a7626, 0px 16px 16px -10px #656a7633;
--token-surface-higher-box-shadow: 0 0 0 1px #656a7633, 0px 2px 3px 0px #656a761a, 0px 12px 28px 0px #656a7640;
--token-surface-overlay-box-shadow: 0 0 0 1px #3b3d4566, 0px 2px 3px 0px #3b3d4580, 0px 12px 24px 0px #3b3d4599;
--token-focus-ring-box-shadow: inset 0 0 0 1px #0c56e9, 0 0 0 3px #5990ff;
--token-focus-ring-action-box-shadow: inset 0 0 0 1px #0c56e9, 0 0 0 3px #5990ff;
--token-focus-ring-critical-box-shadow: inset 0 0 0 1px #c00005, 0 0 0 3px #dd7578;
--token-typography-font-stack-display: -apple-system, BlinkMacSystemFont, SF Pro Display, Segoe UI Display, Ubuntu, sans-serif;
--token-typography-font-stack-text: -apple-system, BlinkMacSystemFont, SF Pro Text, Segoe UI Text, Ubuntu, sans-serif;
--token-typography-font-stack-code: SF Mono, Consolas, Ubuntu Mono, monospace;
Expand Down
14 changes: 7 additions & 7 deletions packages/tokens/scripts/build-parts/generateFocusRingHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ type Helpers = string[];

export function generateFocusRingHelpers(tokens: TransformedTokens): Helpers {

// notice: even if the focus-ring case is much simpler than the other helpers I have
// maintained the same code structure for consistency so it's easier to compare and refactor if needed

const helpersFocusRing: Helpers = [];

if (tokens.hasOwnProperty('box-shadow')) {
const selector = `.${PREFIX}-focus-ring-box-shadow`;
helpersFocusRing.push(`${selector} { box-shadow: var(--token-focus-ring-box-shadow); }`);
}
Object.keys(tokens).forEach((key: string) => {
const color = key;
if (tokens[color].hasOwnProperty('box-shadow')) {
const selector = `.${PREFIX}-focus-ring-${color}-box-shadow`;
helpersFocusRing.push(`${selector} { box-shadow: var(--token-focus-ring-${color}-box-shadow); }`);
}
});

return [...helpersFocusRing];
}
33 changes: 12 additions & 21 deletions packages/tokens/src/global/focus-ring.json
Original file line number Diff line number Diff line change
@@ -1,39 +1,30 @@
{
"focus-ring": {
"internal": {
"spread": {
"value": "1",
"type": "size",
"action": {
"internal-box-shadow": {
"value": "inset 0 0 0 1px {color.focus.action.internal.value}",
"private": true
},
"color": {
"value": "{color.palette.blue-300.value}",
"type": "color",
"external-box-shadow": {
"value": "0 0 0 3px {color.focus.action.external.value}",
"private": true
},
"box-shadow": {
"value": "inset 0 0 0 {focus-ring.internal.spread.value} {focus-ring.internal.color.value}",
"private": true
"value": "{focus-ring.action.internal-box-shadow.value}, {focus-ring.action.external-box-shadow.value}"
}
},
"external": {
"spread": {
"value": "3",
"type": "size",
"critical": {
"internal-box-shadow": {
"value": "inset 0 0 0 1px {color.focus.critical.internal.value}",
"private": true
},
"color": {
"value": "{color.focus.action.external.value}",
"type": "color",
"external-box-shadow": {
"value": "0 0 0 3px {color.focus.critical.external.value}",
"private": true
},
"box-shadow": {
"value": "0 0 0 {focus-ring.external.spread.value} {focus-ring.external.color.value}",
"private": true
"value": "{focus-ring.critical.internal-box-shadow.value}, {focus-ring.critical.external-box-shadow.value}"
}
},
"box-shadow": {
"value": "{focus-ring.internal.box-shadow.value}, {focus-ring.external.box-shadow.value}"
}
}
}