Skip to content

Commit

Permalink
Feat(web): Introduce Toast component #DS-1112
Browse files Browse the repository at this point in the history
  • Loading branch information
adamkudrna committed Feb 23, 2024
1 parent 23f0c9b commit d00a196
Show file tree
Hide file tree
Showing 7 changed files with 507 additions and 0 deletions.
12 changes: 12 additions & 0 deletions packages/web/src/scss/components/Toast/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Toast

Toast displays a brief, temporary notification that appears at a prescribed location of an application window.

TODO

### Accessibility

The wrapping container has the [`role="status"`][mdn-role-status] to announce the toast to screen readers. It has an
implicit `aria-live` value of `polite` and an implicit `aria-atomic` value of `true`.

[mdn-role-status]: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/status_role
73 changes: 73 additions & 0 deletions packages/web/src/scss/components/Toast/_Toast.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// 1. Spread the `Toast` container over the viewport.
// 2. On devices with rounded displays (like iPhone X and later), prefer the safe area value over our spacing, if
// bigger. The `viewport-fit="cover"` meta must be present in HTML for this to work.
// 3. Allow scrolling when the messages do not fit the screen.
// 4. Because the `Toast` container is present on the page all the time, we must allow interaction with the page content
// beneath it.
// 5. The toast queue element is in place so we can reverse the visual order of child toast messages when alignment-y is
// set to `bottom`.

@use 'sass:map';
@use '../../tools/breakpoint';
@use 'theme';

.Toast {
--toast-padding-x: #{theme.$padding-x};
--toast-padding-y: #{theme.$padding-y};

position: fixed; // 1.
inset: 0; // 1.
display: grid;
grid-auto-flow: row;
align-content: var(--toast-alignment-y);
justify-content: var(--toast-alignment-x);

// 2.
padding: max(var(--toast-padding-y), env(safe-area-inset-top))
max(var(--toast-padding-x), env(safe-area-inset-right)) max(var(--toast-padding-y), env(safe-area-inset-bottom))
max(var(--toast-padding-x), env(safe-area-inset-left));
overflow-y: auto; // 3. TODO
pointer-events: none; // 4.

@include breakpoint.up(map.get(theme.$breakpoints, tablet)) {
--toast-padding-x: #{theme.$padding-x-tablet};
}

@include breakpoint.up(map.get(theme.$breakpoints, desktop)) {
--toast-padding-x: #{theme.$padding-x-desktop};
}
}

// 5.
.Toast__queue {
display: flex;
flex-direction: column;
row-gap: theme.$gap;
align-items: var(--toast-alignment-x);
}

// TODO responsive
.Toast--top {
--toast-alignment-y: start;
}

.Toast--bottom {
--toast-alignment-y: end;
}

.Toast--left {
--toast-alignment-x: start;
}

.Toast--center {
--toast-alignment-x: center;
}

.Toast--right {
--toast-alignment-x: end;
}

// 5.
.Toast--bottom > .Toast__queue {
flex-direction: column-reverse;
}
47 changes: 47 additions & 0 deletions packages/web/src/scss/components/Toast/_ToastBar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// 1. Restore pointer events that have been disabled by parent `Toast` component.

@use '../../tools/dictionaries';
@use '../../tools/typography';
@use 'theme';

.ToastBar {
display: grid;
column-gap: theme.$gap;
align-items: start;
max-width: theme.$bar-max-width;
padding: theme.$bar-padding;
border-radius: theme.$bar-border-radius;
box-shadow: theme.$bar-box-shadow;
pointer-events: initial; // 1.
}

.ToastBar--dismissible {
grid-template-columns: 1fr auto;
}

.ToastBar__content {
display: grid;
grid-template-columns: auto 1fr;
column-gap: theme.$bar-content-gap;
align-self: center;
}

.ToastBar__message {
@include typography.generate(theme.$bar-typography);

display: flex;
flex-wrap: wrap;
gap: theme.$bar-message-gap-y theme.$bar-message-gap-x;
}

.ToastBar--dismissible .ToastBar__message > :is(a, button):last-child {
margin-inline-end: 8px;
font-weight: 400;
}

.ToastBar--inverted {
color: theme.$bar-inverted-color;
background-color: theme.$bar-inverted-background;
}

@include dictionaries.generate-colors('ToastBar', theme.$color-dictionary, theme.$color-dictionary-config);
30 changes: 30 additions & 0 deletions packages/web/src/scss/components/Toast/_theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@use 'sass:list';
@use '@tokens' as tokens;
@use '../../settings/dictionaries';

$breakpoints: tokens.$breakpoints;

$gap: tokens.$space-600;
$padding-x: tokens.$space-700;
$padding-x-tablet: tokens.$space-800;
$padding-x-desktop: tokens.$space-900;
$padding-y: tokens.$space-700;

$bar-typography: tokens.$body-small-text-bold;
$bar-max-width: 460px;
$bar-gap: tokens.$space-600;
$bar-padding: tokens.$space-600;
$bar-border-radius: tokens.$radius-200;
$bar-box-shadow: tokens.$shadow-400;
$bar-content-gap: tokens.$space-500;
$bar-message-gap-x: tokens.$space-700;
$bar-message-gap-y: tokens.$space-500;

$bar-inverted-color: tokens.$text-primary-inverted-default;
$bar-inverted-background: tokens.$background-inverted;

$color-dictionary: dictionaries.$emotion-colors;
$color-dictionary-config: (
color: tokens.$text-primary-inverted-default,
background-color: 'default',
);
Loading

0 comments on commit d00a196

Please sign in to comment.