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

Alert (Page) and Alert (Inline) #124

Merged
merged 31 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
99d4bc0
Change alert name types per latest from CRD
amyrlam Mar 24, 2022
3587aca
Implement color manually
amyrlam Mar 25, 2022
dc93906
Add icon implementation with manual showcase
amyrlam Mar 26, 2022
1e8fc6e
Made showcase and API description tweaks for clarity
amyrlam Mar 26, 2022
8146dde
Make styling tweaks from Figma
amyrlam Mar 26, 2022
fd9f1e0
Add a11y section and make docs tweaks
amyrlam Mar 26, 2022
16d5f69
DRY description styling
amyrlam Mar 26, 2022
9f7490b
More alert tweaks
amyrlam Mar 26, 2022
b0eaeef
Fix lint
amyrlam Mar 26, 2022
dd964a8
Tweak Percy
amyrlam Mar 26, 2022
2280ec0
Address PR feedback, with addl edits
amyrlam Mar 29, 2022
6bd33a8
added the “actions” for the “Alert” component as named block with yi…
didoo Mar 28, 2022
e21735f
fixed wrong nesting
didoo Mar 28, 2022
92f8ea7
fixed regex used in the “DummyPlaceholder”
didoo Mar 28, 2022
156bf05
added showcase for “actions” in “Alert” component
didoo Mar 28, 2022
6f1e2cc
added TODO in component API for the “actions”
didoo Mar 28, 2022
5a35035
Merge pull request #130 from hashicorp/alert-actions-as-named-block
amyrlam Mar 29, 2022
7e0fa17
Make docs tweaks pre-type extraction
amyrlam Mar 29, 2022
de912c6
Add page styling
amyrlam Mar 29, 2022
7dc4120
Improve readability of .hbs
amyrlam Mar 29, 2022
5765ef1
Fix lint
amyrlam Mar 29, 2022
11a056b
Tweak docs
amyrlam Mar 29, 2022
ecf9886
Add Alert (Inline)
amyrlam Mar 29, 2022
c954945
Update Actions Showcases to use default icon
amyrlam Mar 29, 2022
2d400a2
More docs tweaks
amyrlam Mar 29, 2022
c69d33f
More docs tweaks
amyrlam Mar 29, 2022
a8117b3
Update packages/components/app/styles/components/alert.scss
amyrlam Mar 29, 2022
0350cb1
Address PR feedback / questions
amyrlam Mar 29, 2022
86a28ab
Merge branch 'amy/alert-page' of github.com:hashicorp/design-system i…
amyrlam Mar 29, 2022
ecf3890
Update color order to match Figma
amyrlam Mar 29, 2022
e01372d
Improve no icon logic with test
amyrlam Mar 30, 2022
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
37 changes: 23 additions & 14 deletions packages/components/addon/components/hds/alert/index.hbs
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
<div class={{this.classNames}} ...attributes role="alert">
{{#if @icon}}
{{#if this.icon}}
<div class="hds-alert__icon">
<FlightIcon
@name={{this.icon}}
@size="24"
{{! TODO: Replace w/dynamic color, once color prop implemented }}
@color="var(--token-color-foreground-warning-on-surface)"
@isInlineBlock={{false}}
/>
<FlightIcon @name={{this.icon}} @size="24" @isInlineBlock={{false}} />
</div>
{{/if}}

<div class="hds-alert__text">
{{#if @title}}
<div class="hds-alert__title">{{@title}}</div>
{{/if}}
<div class="hds-alert__content">
<div class="hds-alert__text">
{{#if @title}}
<div class="hds-alert__title">{{@title}}</div>
{{/if}}
{{#if @description}}
<div class="hds-alert__description">{{html-safe @description}}</div>
{{/if}}
</div>

{{#if @description}}
<div class="hds-alert__description">{{html-safe @description}}</div>
{{#if (has-block "actions")}}
{{! IMPORTANT: don't change the formatting or it will add empty space inside the element (we're using ":empty" in CSS to hide it when it's empty!) }}
<div class="hds-alert__actions">
{{yield
(hash
Button=(component "hds/button")
Link::Standalone=(component "hds/link/standalone")
LinkTo::Standalone=(component "hds/link-to/standalone")
)
to="actions"
}}
</div>
{{/if}}
</div>
</div>
79 changes: 75 additions & 4 deletions packages/components/addon/components/hds/alert/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
import Component from '@glimmer/component';
import { assert } from '@ember/debug';

export const DEFAULT_TYPE = 'page';
export const TYPES = ['page', 'inline', 'compact', 'toast'];
export const DEFAULT_COLOR = 'neutral';
export const COLORS = [
'neutral',
'highlight',
'success',
'warning',
'critical',
];
export const MAPPING_COLORS_TO_ICONS = {
Copy link
Contributor

@didoo didoo Mar 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@amyrlam notice: for now this works perfectly, but I've just realized that these icons can be filled or not depending if they are in the "compact" alert or not, so it's likely we'll have to move this mapping logic inside the get icon() method directly, and use the @type/this.type as an extra condition to determine which icon to use

@amyrlam @Dhaulagiri @MelSumner can you see now the power of moving the logic in the "right" place? can you imagine doing all these conditionals only at template level?

see how it was before

{{#if (or @icon @color)}}
<div class="hds-alert__icon">
{{#if @icon}}
<FlightIcon @name={{@icon}} @size="24" @isInlineBlock={{false}} />
{{else if (or (eq @color "neutral") (eq @color "highlight"))}}
<FlightIcon @name="info" @size="24" @isInlineBlock={{false}} />
{{else if (eq @color "success")}}
<FlightIcon @name="check-circle" @size="24" @isInlineBlock={{false}} />
{{else if (eq @color "warning")}}
<FlightIcon @name="alert-triangle" @size="24" @isInlineBlock={{false}} />
{{else if (eq @color "critical")}}
<FlightIcon @name="alert-octagon" @size="24" @isInlineBlock={{false}} />
{{/if}}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We talked about ^^ in a meeting, I'll address the compact type shortly. I get what you're saying now. Compact type has a different mapping of which default icon it informs. It will have some .hbs logic as well, as certain elements will be hidden, but can discuss when up soon

critical: 'alert-octagon',
warning: 'alert-triangle',
neutral: 'info',
highlight: 'info',
success: 'check-circle',
};

export default class HdsAlertIndexComponent extends Component {
constructor() {
super(...arguments);
Expand All @@ -11,26 +29,79 @@ export default class HdsAlertIndexComponent extends Component {
);
}

/**
* @param type
* @type {enum}
* @default page
* @description Determines the type of the alert.
*/
get type() {
let { type = DEFAULT_TYPE } = this.args;

assert(
`@type for "Hds::Alert" must be one of the following: ${TYPES.join(
', '
)}; received: ${type}`,
TYPES.includes(type)
);

return type;
}

/**
* @param color
* @type {enum}
* @default neutral
* @description Determines the color scheme for the alert.
*/
get color() {
let { color = DEFAULT_COLOR } = this.args;

assert(
`@color for "Hds::Alert" must be one of the following: ${COLORS.join(
', '
)}; received: ${color}`,
COLORS.includes(color)
);

return color;
}

/**
* @param icon
* @type {string}
* @default null
* @description The name of the icon to be used.
*/
get icon() {
return this.args.icon ?? null;
let { icon } = this.args;

// If `icon` isn't passed, use the pre-defined one from `color`
if (icon === undefined) {
return MAPPING_COLORS_TO_ICONS[this.color];
// If `icon` is set explicitly to false, user doesn't want any icon in the alert
} else if (icon === false) {
return false;
} else {
// If a name for `icon` is passed, set FlightIcon to that name
return icon;
}
}

/**
* Get the class names to apply to the component.
* @method Alert#classNames
* @return {string} The "class" attribute to apply to the component.
*/
// "hds-alert"
get classNames() {
let classes = ['hds-alert'];

// TODO: Add type classes, once type implemented
return classes;
// Add a class based on the @type argument
classes.push(`hds-alert--type-${this.type}`);

// Add a class based on the @color argument
classes.push(`hds-alert--color-${this.color}`);

return classes.join(' ');
}
}
115 changes: 110 additions & 5 deletions packages/components/app/styles/components/alert.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@

.hds-alert {
align-content: flex-start;
background-color: var(--token-color-surface-warning);
display: flex;
padding: 1.25rem; // 20px
padding: 1rem; // 16px
}

.hds-alert__icon {
Expand All @@ -27,12 +26,12 @@
font-weight: var(--token-typography-font-weight-semibold);
}


.hds-alert__description {
font-weight: var(--token-typography-font-weight-regular);
color: var(--token-color-foreground-primary);

.hds-alert__title + & {
margin-top: 0.75rem; // 12px
margin-top: 0.25rem; // 4px
}

strong {
Expand All @@ -46,7 +45,7 @@
// Notice: in the future this may become a "Link::Inline" component (for now we declare the styles directly here)
a {
color: var(--token-color-foreground-action);
// at the moment the "focus" state is not well defined in design (the one that is in Figma does not work) so we just apply a simple color to the default outline
// At the moment the "focus" state is not well defined in design (the one that is in Figma does not work) so we just apply a simple color to the default outline
outline-color: var(--token-color-focus-action-external);

&:hover {
Expand All @@ -58,3 +57,109 @@
}
}
}

//
// COLOR & TYPE
//
.hds-alert--color-neutral {
background-color: var(--token-color-surface-faint);

&.hds-alert--type-page {
box-shadow: 0px 1px 0px 0px var(--token-color-palette-alpha-300);
}

&.hds-alert--type-inline {
border-color: var(--token-color-border-strong);
}

.hds-alert__icon, .hds-alert__title {
color: var(--token-color-foreground-primary);
}
}

.hds-alert--color-highlight {
background-color: var(--token-color-surface-highlight);

&.hds-alert--type-page {
box-shadow: 0px 1px 0px 0px var(--token-color-border-highlight);
}

&.hds-alert--type-inline {
border-color: var(--token-color-border-highlight);
}

.hds-alert__icon, .hds-alert__title {
color: var(--token-color-foreground-highlight-on-surface);
}
}

.hds-alert--color-success {
background-color: var(--token-color-surface-success);

&.hds-alert--type-page {
box-shadow: 0px 1px 0px 0px var(--token-color-border-success);
}

&.hds-alert--type-inline {
border-color: var(--token-color-border-success);
}

.hds-alert__icon, .hds-alert__title {
color: var(--token-color-foreground-success-on-surface);
}
}

.hds-alert--color-warning {
background-color: var(--token-color-surface-warning);

&.hds-alert--type-page {
box-shadow: 0px 1px 0px 0px var(--token-color-border-warning);
}

&.hds-alert--type-inline {
border-color: var(--token-color-border-warning);
}

.hds-alert__icon, .hds-alert__title {
color: var(--token-color-foreground-warning-on-surface);
}
}

.hds-alert--color-critical {
background-color: var(--token-color-surface-critical);

&.hds-alert--type-page {
box-shadow: 0px 1px 0px 0px var(--token-color-border-critical);
}

&.hds-alert--type-inline {
border-color: var(--token-color-border-critical);
}

.hds-alert__icon, .hds-alert__title {
color: var(--token-color-foreground-critical-on-surface);
}
}

.hds-alert--type-inline {
border-width: 1px;
border-style: solid;
border-radius: 6px;
}

//
// ACTIONS
//
.hds-alert__actions {
align-items: center;
display: flex;
margin-top: 1rem; // 16px

> * + * {
margin-left: 1rem; // 16px
}

&:empty {
display: none;
}
}
3 changes: 3 additions & 0 deletions packages/components/tests/acceptance/percy-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ module('Acceptance | Percy test', function (hooks) {
await visit('/foundations/focus-ring');
await percySnapshot('FocusRing');

await visit('/components/alert');
await percySnapshot('Alert');

await visit('/components/badge');
await percySnapshot('Badge');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default class DummyPlaceholderIndexComponent extends Component {
get width() {
let { width = '100%' } = this.args;

if (typeof width === 'string' && width.match(/[\d]+/)) {
if (typeof width === 'string' && width.match(/^[\d]+$/)) {
width = `${parseInt(width, 10)}px`;
}

Expand All @@ -28,7 +28,7 @@ export default class DummyPlaceholderIndexComponent extends Component {
get height() {
let { height = '100%' } = this.args;

if (typeof height === 'string' && height.match(/[\d]+/)) {
if (typeof height === 'string' && height.match(/^[\d]+$/)) {
height = `${parseInt(height, 10)}px`;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/components/tests/dummy/app/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

@import "./_typography";

@import "./pages/db-alert";
@import "./pages/db-badge";
@import "./pages/db-breadcrumb";
@import "./pages/db-button";
Expand Down Expand Up @@ -208,7 +209,6 @@ body.dummy-app {
border-color: #f5c6cb;
}


// Percy (percySnapshot) doesn't allow to target specific DOM elements, so we have to "blacklist" the elements
// that we want to exclude from the snapshots using their own "Percy-specific CSS".
// see: https://docs.percy.io/docs/percy-specific-css#section-hiding-regions-with-percy-specific-css
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
line-height: 1.2;
max-width: 64rem;

.dummy-indent {
margin-left: 30px;
}

dt {
color: #1F69FF;
font-size: 1rem;
Expand Down
15 changes: 15 additions & 0 deletions packages/components/tests/dummy/app/styles/pages/db-alert.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// ALERT

.dummy-alert-sample-custom-actions__actions {
display: flex;
gap: 16px;
align-items: center;
}

.dummy-alert-sample-custom-actions__text {
@include dummyFontFamily();
@include dummyFontSize(0.8rem);
display: block;
color: #999;
margin-top: 1rem;
}
Loading