From bb98233f361fd9b6f02ee3be908cf4225f34bcf7 Mon Sep 17 00:00:00 2001 From: Ethan Wallace Date: Wed, 11 Dec 2024 15:46:21 -0500 Subject: [PATCH] feat: New gcds-notice component (#627) * First commit: new gcds-notice component * gcds-notice stories * gcds-notice spec and e2e tests * fix CSS + format index.html * Storybook fixes + upodate notice to use section * Update to new tokens package version * PR feedback: Notice formatting + clean up * Remove unused line of CSS * Add missing lang attribute in storybook * PR feedback: fix typos * First version of icon notice * Update notice component to use icon instead of text label * Update spec unit tests * Update icon selection method * Update tokens package * PR feedback * Add new notice-title-tag property * Fix notice-title-tag comment * Add invalid tag value test * Modify internal heading margin-top to new spacing token value * fix: notice heading spacing * Update tokens package version --- .../src/lib/stencil-generated/components.ts | 22 ++ .../src/lib/stencil-generated/index.ts | 1 + .../src/components/stencil-generated/index.ts | 1 + packages/vue/lib/components.ts | 7 + packages/web/src/components.d.ts | 37 +++ .../web/src/components/gcds-heading/readme.md | 2 + .../web/src/components/gcds-icon/readme.md | 2 + .../components/gcds-notice/gcds-notice.css | 110 +++++++ .../components/gcds-notice/gcds-notice.tsx | 151 ++++++++++ .../web/src/components/gcds-notice/readme.md | 34 +++ .../stories/gcds-notice.stories.tsx | 196 ++++++++++++ .../gcds-notice/stories/overview.mdx | 67 +++++ .../gcds-notice/stories/properties.mdx | 15 + .../gcds-notice/test/gcds-notice.e2e.ts | 120 ++++++++ .../gcds-notice/test/gcds-notice.spec.tsx | 278 ++++++++++++++++++ packages/web/src/index.html | 29 +- 16 files changed, 1071 insertions(+), 1 deletion(-) create mode 100644 packages/web/src/components/gcds-notice/gcds-notice.css create mode 100644 packages/web/src/components/gcds-notice/gcds-notice.tsx create mode 100644 packages/web/src/components/gcds-notice/readme.md create mode 100644 packages/web/src/components/gcds-notice/stories/gcds-notice.stories.tsx create mode 100644 packages/web/src/components/gcds-notice/stories/overview.mdx create mode 100644 packages/web/src/components/gcds-notice/stories/properties.mdx create mode 100644 packages/web/src/components/gcds-notice/test/gcds-notice.e2e.ts create mode 100644 packages/web/src/components/gcds-notice/test/gcds-notice.spec.tsx diff --git a/packages/angular/src/lib/stencil-generated/components.ts b/packages/angular/src/lib/stencil-generated/components.ts index a44c1b37e..a3d93b1f4 100644 --- a/packages/angular/src/lib/stencil-generated/components.ts +++ b/packages/angular/src/lib/stencil-generated/components.ts @@ -837,6 +837,28 @@ export declare interface GcdsNavLink extends Components.GcdsNavLink { } +@ProxyCmp({ + inputs: ['noticeTitle', 'noticeTitleTag', 'type'] +}) +@Component({ + selector: 'gcds-notice', + changeDetection: ChangeDetectionStrategy.OnPush, + template: '', + // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property + inputs: ['noticeTitle', 'noticeTitleTag', 'type'], +}) +export class GcdsNotice { + protected el: HTMLElement; + constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) { + c.detach(); + this.el = r.nativeElement; + } +} + + +export declare interface GcdsNotice extends Components.GcdsNotice {} + + @ProxyCmp({ inputs: ['currentPage', 'display', 'label', 'nextHref', 'nextLabel', 'previousHref', 'previousLabel', 'totalPages', 'url'], outputs: ['gcdsFocus', 'gcdsBlur', 'gcdsClick'] diff --git a/packages/angular/src/lib/stencil-generated/index.ts b/packages/angular/src/lib/stencil-generated/index.ts index 3339b43d2..4430ec404 100644 --- a/packages/angular/src/lib/stencil-generated/index.ts +++ b/packages/angular/src/lib/stencil-generated/index.ts @@ -29,6 +29,7 @@ export const DIRECTIVES = [ d.GcdsLink, d.GcdsNavGroup, d.GcdsNavLink, + d.GcdsNotice, d.GcdsPagination, d.GcdsPhaseBanner, d.GcdsRadioGroup, diff --git a/packages/react/src/components/stencil-generated/index.ts b/packages/react/src/components/stencil-generated/index.ts index b8dbdbac6..269331900 100644 --- a/packages/react/src/components/stencil-generated/index.ts +++ b/packages/react/src/components/stencil-generated/index.ts @@ -35,6 +35,7 @@ export const GcdsLangToggle = /*@__PURE__*/createReactComponent('gcds-link'); export const GcdsNavGroup = /*@__PURE__*/createReactComponent('gcds-nav-group'); export const GcdsNavLink = /*@__PURE__*/createReactComponent('gcds-nav-link'); +export const GcdsNotice = /*@__PURE__*/createReactComponent('gcds-notice'); export const GcdsPagination = /*@__PURE__*/createReactComponent('gcds-pagination'); export const GcdsPhaseBanner = /*@__PURE__*/createReactComponent('gcds-phase-banner'); export const GcdsRadioGroup = /*@__PURE__*/createReactComponent('gcds-radio-group'); diff --git a/packages/vue/lib/components.ts b/packages/vue/lib/components.ts index c948311df..65bfec370 100644 --- a/packages/vue/lib/components.ts +++ b/packages/vue/lib/components.ts @@ -318,6 +318,13 @@ export const GcdsNavLink = /*@__PURE__*/ defineContainer('gcds- ]); +export const GcdsNotice = /*@__PURE__*/ defineContainer('gcds-notice', undefined, [ + 'type', + 'noticeTitle', + 'noticeTitleTag' +]); + + export const GcdsPagination = /*@__PURE__*/ defineContainer('gcds-pagination', undefined, [ 'display', 'label', diff --git a/packages/web/src/components.d.ts b/packages/web/src/components.d.ts index f362eca38..1940a87e7 100644 --- a/packages/web/src/components.d.ts +++ b/packages/web/src/components.d.ts @@ -752,6 +752,20 @@ export namespace Components { */ "href": string; } + interface GcdsNotice { + /** + * Set the notice title. + */ + "noticeTitle": string; + /** + * Set notice title heading tag. + */ + "noticeTitleTag": 'h2' | 'h3' | 'h4' | 'h5'; + /** + * Set notice type. + */ + "type": 'danger' | 'info' | 'success' | 'warning'; + } interface GcdsPagination { /** * List display - Current page number @@ -1484,6 +1498,12 @@ declare global { prototype: HTMLGcdsNavLinkElement; new (): HTMLGcdsNavLinkElement; }; + interface HTMLGcdsNoticeElement extends Components.GcdsNotice, HTMLStencilElement { + } + var HTMLGcdsNoticeElement: { + prototype: HTMLGcdsNoticeElement; + new (): HTMLGcdsNoticeElement; + }; interface HTMLGcdsPaginationElementEventMap { "gcdsFocus": void; "gcdsBlur": void; @@ -1669,6 +1689,7 @@ declare global { "gcds-link": HTMLGcdsLinkElement; "gcds-nav-group": HTMLGcdsNavGroupElement; "gcds-nav-link": HTMLGcdsNavLinkElement; + "gcds-notice": HTMLGcdsNoticeElement; "gcds-pagination": HTMLGcdsPaginationElement; "gcds-phase-banner": HTMLGcdsPhaseBannerElement; "gcds-radio-group": HTMLGcdsRadioGroupElement; @@ -2580,6 +2601,20 @@ declare namespace LocalJSX { */ "onGcdsFocus"?: (event: GcdsNavLinkCustomEvent) => void; } + interface GcdsNotice { + /** + * Set the notice title. + */ + "noticeTitle": string; + /** + * Set notice title heading tag. + */ + "noticeTitleTag": 'h2' | 'h3' | 'h4' | 'h5'; + /** + * Set notice type. + */ + "type": 'danger' | 'info' | 'success' | 'warning'; + } interface GcdsPagination { /** * List display - Current page number @@ -3004,6 +3039,7 @@ declare namespace LocalJSX { "gcds-link": GcdsLink; "gcds-nav-group": GcdsNavGroup; "gcds-nav-link": GcdsNavLink; + "gcds-notice": GcdsNotice; "gcds-pagination": GcdsPagination; "gcds-phase-banner": GcdsPhaseBanner; "gcds-radio-group": GcdsRadioGroup; @@ -3051,6 +3087,7 @@ declare module "@stencil/core" { "gcds-link": LocalJSX.GcdsLink & JSXBase.HTMLAttributes; "gcds-nav-group": LocalJSX.GcdsNavGroup & JSXBase.HTMLAttributes; "gcds-nav-link": LocalJSX.GcdsNavLink & JSXBase.HTMLAttributes; + "gcds-notice": LocalJSX.GcdsNotice & JSXBase.HTMLAttributes; "gcds-pagination": LocalJSX.GcdsPagination & JSXBase.HTMLAttributes; "gcds-phase-banner": LocalJSX.GcdsPhaseBanner & JSXBase.HTMLAttributes; "gcds-radio-group": LocalJSX.GcdsRadioGroup & JSXBase.HTMLAttributes; diff --git a/packages/web/src/components/gcds-heading/readme.md b/packages/web/src/components/gcds-heading/readme.md index 0a409cb8e..22afde381 100644 --- a/packages/web/src/components/gcds-heading/readme.md +++ b/packages/web/src/components/gcds-heading/readme.md @@ -20,12 +20,14 @@ ### Used by - [gcds-error-summary](../gcds-error-summary) + - [gcds-notice](../gcds-notice) - [gcds-stepper](../gcds-stepper) ### Graph ```mermaid graph TD; gcds-error-summary --> gcds-heading + gcds-notice --> gcds-heading gcds-stepper --> gcds-heading style gcds-heading fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/packages/web/src/components/gcds-icon/readme.md b/packages/web/src/components/gcds-icon/readme.md index 9be161c96..1a59fe7f2 100644 --- a/packages/web/src/components/gcds-icon/readme.md +++ b/packages/web/src/components/gcds-icon/readme.md @@ -28,6 +28,7 @@ - [gcds-file-uploader](../gcds-file-uploader) - [gcds-link](../gcds-link) - [gcds-nav-group](../gcds-nav-group) + - [gcds-notice](../gcds-notice) - [gcds-pagination](../gcds-pagination) - [gcds-search](../gcds-search) - [gcds-topic-menu](../gcds-topic-menu) @@ -41,6 +42,7 @@ graph TD; gcds-file-uploader --> gcds-icon gcds-link --> gcds-icon gcds-nav-group --> gcds-icon + gcds-notice --> gcds-icon gcds-pagination --> gcds-icon gcds-search --> gcds-icon gcds-topic-menu --> gcds-icon diff --git a/packages/web/src/components/gcds-notice/gcds-notice.css b/packages/web/src/components/gcds-notice/gcds-notice.css new file mode 100644 index 000000000..b1bdd9438 --- /dev/null +++ b/packages/web/src/components/gcds-notice/gcds-notice.css @@ -0,0 +1,110 @@ +@layer reset, default, type; + +@layer reset { + :host { + display: block; + + .gcds-notice { + text-align: left; + box-sizing: border-box; + + slot { + display: initial; + } + } + } +} + +@layer default { + :host .gcds-notice { + color: var(--gcds-notice-text); + display: grid; + grid-template-columns: var(--gcds-notice-icon-width) auto; + gap: var(--gcds-notice-icon-gap); + + .notice__heading { + --gcds-heading-h2-desktop: var( + --gcds-notice-content-heading-font-desktop + ); + --gcds-heading-h2-mobile: var(--gcds-notice-content-heading-font-mobile); + --gcds-heading-h4-desktop: var( + --gcds-notice-content-heading-font-desktop + ); + --gcds-heading-h4-mobile: var(--gcds-notice-content-heading-font-mobile); + --gcds-heading-h5-desktop: var( + --gcds-notice-content-heading-font-desktop + ); + --gcds-heading-h5-mobile: var(--gcds-notice-content-heading-font-mobile); + margin-block-start: var(--gcds-notice-content-heading-margin-block-start-desktop); + + @media only screen and (width < 48em) { + margin-block-start: var(--gcds-notice-content-heading-margin-block-start-mobile); + } + } + + .notice__icon { + margin: var(--gcds-notice-icon-margin); + + &:before { + display: block; + width: var(--gcds-notice-border-width); + margin: 0 auto; + height: var(--gcds-notice-icon-before-height); + content: ''; + background-color: currentColor; + } + + &:after { + display: block; + width: var(--gcds-notice-border-width); + margin: 0 auto; + height: var(--gcds-notice-icon-after-height); + content: ''; + background-color: currentColor; + } + } + + ::slotted(*) { + margin-block-start: 0; + font: var(--gcds-notice-content-slotted-font-desktop); + + @media only screen and (width < 48em) { + font: var(--gcds-notice-content-slotted-font-mobile); + } + } + + ::slotted(*:last-child) { + margin-block-end: 0; + } + + ::slotted(*:not(:last-child)) { + margin-block-end: var(--gcds-notice-content-slotted-margin); + } + + ::slotted(ol), + ::slotted(ul) { + margin-inline-start: var(--gcds-notice-content-slotted-list-margin); + padding: 0; + } + } +} + +@layer type { + :host .gcds-notice { + &.notice--type-danger .notice__icon { + color: var(--gcds-notice-danger-text); + } + + &.notice--type-info .notice__icon { + color: var(--gcds-notice-info-text); + } + + &.notice--type-success .notice__icon { + color: var(--gcds-notice-success-text); + } + + &.notice--type-warning .notice__icon { + color: var(--gcds-notice-warning-text); + } + } +} diff --git a/packages/web/src/components/gcds-notice/gcds-notice.tsx b/packages/web/src/components/gcds-notice/gcds-notice.tsx new file mode 100644 index 000000000..15e968503 --- /dev/null +++ b/packages/web/src/components/gcds-notice/gcds-notice.tsx @@ -0,0 +1,151 @@ +import { Component, Element, Host, Prop, State, h } from '@stencil/core'; +import { assignLanguage, observerConfig, logError } from '../../utils/utils'; + +@Component({ + tag: 'gcds-notice', + styleUrl: 'gcds-notice.css', + shadow: true, +}) +export class GcdsNotice { + @Element() el: HTMLElement; + + /** + * Props + */ + + /** + * Set notice type. + */ + @Prop() type!: 'danger' | 'info' | 'success' | 'warning'; + validateType() { + if (!this.type) { + this.errors.push('type'); + } else if (this.errors.includes('type')) { + this.errors.splice(this.errors.indexOf('type'), 1); + } + } + + /** + * Set the notice title. + */ + @Prop() noticeTitle!: string; + validateNoticeTitle() { + if (!this.noticeTitle || this.noticeTitle === '') { + this.errors.push('noticeTitle'); + } else if (this.errors.includes('noticeTitle')) { + this.errors.splice(this.errors.indexOf('noticeTitle'), 1); + } + } + + /** + * Set notice title heading tag. + */ + @Prop() noticeTitleTag!: 'h2' | 'h3' | 'h4' | 'h5'; + validateNoticeTitleTag() { + if ( + !this.noticeTitleTag || + !['h2', 'h3', 'h4', 'h5'].includes(this.noticeTitleTag) + ) { + this.errors.push('noticeTitleTag'); + } else if (this.errors.includes('noticeTitleTag')) { + this.errors.splice(this.errors.indexOf('noticeTitleTag'), 1); + } + } + + /** + * States + */ + + /** + * State to track validation on properties + * Contains a list of properties that have an error associated with them + */ + @State() errors: Array = []; + + /** + * Language of rendered component + */ + @State() lang: string; + + /* + * Observe lang attribute change + */ + updateLang() { + const observer = new MutationObserver(mutations => { + if (mutations[0].oldValue != this.el.lang) { + this.lang = this.el.lang; + } + }); + observer.observe(this.el, observerConfig); + } + + private validateChildren() { + if (this.el.innerHTML.trim() == '') { + this.errors.push('children'); + } else if (this.errors.includes('children')) { + this.errors.splice(this.errors.indexOf('children'), 1); + } + } + + private validateRequiredProps() { + this.validateNoticeTitle(); + this.validateType(); + this.validateNoticeTitleTag(); + this.validateChildren(); + + if ( + this.errors.includes('type') || + this.errors.includes('noticeTitle') || + this.errors.includes('noticeTitleTag') || + this.errors.includes('children') + ) { + return false; + } + return true; + } + + async componentWillLoad() { + // Define lang attribute + this.lang = assignLanguage(this.el); + + this.updateLang(); + + let valid = this.validateRequiredProps(); + + if (!valid) { + logError('gcds-notice', this.errors); + } + } + + render() { + const { type, noticeTitle, noticeTitleTag } = this; + + const iconTypes = { + danger: 'exclamation-circle', + info: 'info-circle', + success: 'check-circle', + warning: 'exclamation-triangle', + }; + + return ( + + {this.validateRequiredProps() && ( +
+ +
+ + {noticeTitle} + + +
+
+ )} +
+ ); + } +} diff --git a/packages/web/src/components/gcds-notice/readme.md b/packages/web/src/components/gcds-notice/readme.md new file mode 100644 index 000000000..f28fd97d8 --- /dev/null +++ b/packages/web/src/components/gcds-notice/readme.md @@ -0,0 +1,34 @@ +# gcds-notice + + + + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ----------------------------- | ------------------ | ----------------------------- | ---------------------------------------------- | ----------- | +| `noticeTitle` _(required)_ | `notice-title` | Set the notice title. | `string` | `undefined` | +| `noticeTitleTag` _(required)_ | `notice-title-tag` | Set notice title heading tag. | `"h2" \| "h3" \| "h4" \| "h5"` | `undefined` | +| `type` _(required)_ | `type` | Set notice type. | `"danger" \| "info" \| "success" \| "warning"` | `undefined` | + + +## Dependencies + +### Depends on + +- [gcds-icon](../gcds-icon) +- [gcds-heading](../gcds-heading) + +### Graph +```mermaid +graph TD; + gcds-notice --> gcds-icon + gcds-notice --> gcds-heading + style gcds-notice fill:#f9f,stroke:#333,stroke-width:4px +``` + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/packages/web/src/components/gcds-notice/stories/gcds-notice.stories.tsx b/packages/web/src/components/gcds-notice/stories/gcds-notice.stories.tsx new file mode 100644 index 000000000..894572d0a --- /dev/null +++ b/packages/web/src/components/gcds-notice/stories/gcds-notice.stories.tsx @@ -0,0 +1,196 @@ +import { langProp } from '../../../utils/storybook/component-properties'; + +export default { + title: 'Components/Notice', + + argTypes: { + // Props + noticeTitle: { + name: 'notice-title', + control: 'text', + table: { + type: { summary: 'string' }, + defaultValue: { summary: '-' }, + }, + type: { + required: true, + }, + }, + noticeTitleTag: { + name: 'notice-title-tag', + control: { type: 'select' }, + options: ['h2', 'h3', 'h4', 'h5'], + table: { + type: { summary: 'string' }, + defaultValue: { summary: '-' }, + }, + type: { + required: true, + }, + }, + type: { + control: { type: 'select' }, + options: ['success', 'danger', 'info', 'warning'], + table: { + type: { summary: 'string' }, + defaultValue: { summary: '-' }, + }, + type: { + required: true, + }, + }, + ...langProp, + + // Slots + default: { + control: { + type: 'text', + }, + description: + 'Customize the content or include additional elements. | Personnalisez le contenu ou ajoutez des éléments supplémentaires.', + table: { + category: 'Slots | Fentes', + }, + }, + }, +}; + +const Template = args => + ` + + + ${args.default.trim() != '' ? `${args.default}` : null} + + + + + ${args.default.trim() != '' ? `${args.default}` : null} + +`.replace(/ null/g, ''); + +const TemplatePlayground = args => ` + + ${args.default.trim() != '' ? `${args.default}` : null} + +`; + +// ------ Notice default ------ + +export const Default = Template.bind({}); +Default.args = { + noticeTitle: 'Title', + noticeTitleTag: 'h2', + type: 'success', + default: 'Message.', + lang: 'en', +}; + +// ------ Notice success ------ + +export const Success = Template.bind({}); +Success.args = { + noticeTitle: 'Title', + noticeTitleTag: 'h2', + type: 'success', + default: 'Message.', + lang: 'en', +}; + +// ------ Notice danger ------ + +export const Danger = Template.bind({}); +Danger.args = { + noticeTitle: 'Title', + noticeTitleTag: 'h2', + type: 'danger', + default: 'Message.', + lang: 'en', +}; + +// ------ Notice info ------ + +export const Info = Template.bind({}); +Info.args = { + noticeTitle: 'Title', + noticeTitleTag: 'h2', + type: 'info', + default: 'Message.', + lang: 'en', +}; + +// ------ Notice warning ------ + +export const Warning = Template.bind({}); +Warning.args = { + noticeTitle: 'Title', + noticeTitleTag: 'h2', + type: 'warning', + default: 'Message.', + lang: 'en', +}; + +// ------ Title tag h2 ------ + +export const h2 = Template.bind({}); +h2.args = { + noticeTitle: 'Title', + noticeTitleTag: 'h2', + type: 'success', + default: 'Message.', + lang: 'en', +}; + +// ------ Title tag h3 ------ + +export const h3 = Template.bind({}); +h3.args = { + noticeTitle: 'Title', + noticeTitleTag: 'h3', + type: 'success', + default: 'Message.', + lang: 'en', +}; + +// ------ Title tag h4 ------ + +export const h4 = Template.bind({}); +h4.args = { + noticeTitle: 'Title', + noticeTitleTag: 'h4', + type: 'success', + default: 'Message.', + lang: 'en', +}; + +// ------ Title tag h5 ------ + +export const h5 = Template.bind({}); +h5.args = { + noticeTitle: 'Title', + noticeTitleTag: 'h5', + type: 'success', + default: 'Message.', + lang: 'en', +}; + +// ------ Notice events & props ------ + +export const Props = Template.bind({}); +Props.args = { + noticeTitle: 'Title', + noticeTitleTag: 'h2', + type: 'success', + default: 'Message.', + lang: 'en', +}; + +// ------ Notice playground ------ + +export const Playground = TemplatePlayground.bind({}); +Playground.args = { + noticeTitle: 'Title', + noticeTitleTag: 'h2', + type: 'success', + default: 'Message.', + lang: 'en', +}; diff --git a/packages/web/src/components/gcds-notice/stories/overview.mdx b/packages/web/src/components/gcds-notice/stories/overview.mdx new file mode 100644 index 000000000..cd4175b66 --- /dev/null +++ b/packages/web/src/components/gcds-notice/stories/overview.mdx @@ -0,0 +1,67 @@ +import { Meta, Canvas, Story } from '@storybook/blocks'; +import * as Notice from './gcds-notice.stories'; + + + +# Notice
`` + +_Also called: Contextual alert_ + +The notice is a prominent message to draw attention to important information or change. + + + +## Examples + +
+ +### Types + +#### Success + + + +#### Danger + + + +#### Info + + + +#### Warning + + + +### Title tag + +#### Heading tag 2 + + + +#### Heading tag 3 + + + +#### Heading tag 4 + + + +#### Heading tag 5 + + + +## Resources + +{/* prettier-ignore */} +
    +
  • + Guidance +
  • +
  • + Github +
  • +
  • + Figma +
  • +
diff --git a/packages/web/src/components/gcds-notice/stories/properties.mdx b/packages/web/src/components/gcds-notice/stories/properties.mdx new file mode 100644 index 000000000..0344ed77b --- /dev/null +++ b/packages/web/src/components/gcds-notice/stories/properties.mdx @@ -0,0 +1,15 @@ +import { Meta, Canvas, Controls } from '@storybook/blocks'; +import * as Notice from './gcds-notice.stories'; + + + +{!(new URLSearchParams(window.location.search)).get('demo') &&

Events & properties

} + + + + diff --git a/packages/web/src/components/gcds-notice/test/gcds-notice.e2e.ts b/packages/web/src/components/gcds-notice/test/gcds-notice.e2e.ts new file mode 100644 index 000000000..db08d35f5 --- /dev/null +++ b/packages/web/src/components/gcds-notice/test/gcds-notice.e2e.ts @@ -0,0 +1,120 @@ +import { newE2EPage } from '@stencil/core/testing'; +const { AxePuppeteer } = require('@axe-core/puppeteer'); + +describe('gcds-notice', () => { + it('renders', async () => { + const page = await newE2EPage(); + await page.setContent(` + Provide additonal information + `); + + const element = await page.find('gcds-notice'); + expect(element).toHaveClass('hydrated'); + }); +}); + +/** + * Accessibility tests + * Axe-core rules: https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md#wcag-21-level-a--aa-rules + */ + +describe('gcds-notice a11y tests', () => { + /** + * Colour contrast test + */ + it('colour contrast danger notice', async () => { + const page = await newE2EPage(); + await page.setViewport({ + width: 600, + height: 400, + }); + await page.setContent(` + + Provide additonal information + + `); + + const colorContrastTest = new AxePuppeteer(page) + .withRules('color-contrast') + .analyze(); + const results = await colorContrastTest; + + expect(results.violations.length).toBe(0); + }); + + it('colour contrast info notice', async () => { + const page = await newE2EPage(); + await page.setViewport({ + width: 600, + height: 400, + }); + await page.setContent(` + + Provide additonal information + + `); + + const colorContrastTest = new AxePuppeteer(page) + .withRules('color-contrast') + .analyze(); + const results = await colorContrastTest; + + expect(results.violations.length).toBe(0); + }); + + it('colour contrast success notice', async () => { + const page = await newE2EPage(); + await page.setViewport({ + width: 600, + height: 400, + }); + await page.setContent(` + + Provide additonal information + + `); + + const colorContrastTest = new AxePuppeteer(page) + .withRules('color-contrast') + .analyze(); + const results = await colorContrastTest; + + expect(results.violations.length).toBe(0); + }); + + it('colour contrast warning notice', async () => { + const page = await newE2EPage(); + await page.setViewport({ + width: 600, + height: 400, + }); + await page.setContent(` + + Provide additonal information + + `); + + const colorContrastTest = new AxePuppeteer(page) + .withRules('color-contrast') + .analyze(); + const results = await colorContrastTest; + + expect(results.violations.length).toBe(0); + }); + + it('heading text', async () => { + const page = await newE2EPage(); + await page.setContent(` + + Provide additonal information + + `); + + const emptyHeadingtest = new AxePuppeteer(page) + .withRules('empty-heading') + .analyze(); + const results = await emptyHeadingtest; + + expect(results.violations.length).toBe(0); + }); +}); diff --git a/packages/web/src/components/gcds-notice/test/gcds-notice.spec.tsx b/packages/web/src/components/gcds-notice/test/gcds-notice.spec.tsx new file mode 100644 index 000000000..e7d87c222 --- /dev/null +++ b/packages/web/src/components/gcds-notice/test/gcds-notice.spec.tsx @@ -0,0 +1,278 @@ +import { newSpecPage } from '@stencil/core/testing'; +import { GcdsNotice } from '../gcds-notice'; + +describe('gcds-notice', () => { + it('renders - success type', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + Provide additonal information + `, + }); + expect(page.root) + .toEqualHtml(` + +
+ +
+ + GC Design System notice + + +
+
+
+ + Provide additonal information + +
+ `); + }); + + it('renders - danger type', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + Provide additonal information + `, + }); + expect(page.root) + .toEqualHtml(` + +
+ +
+ + GC Design System notice + + +
+
+
+ + Provide additonal information + +
+ `); + }); + + it('renders - info type', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + Provide additonal information + `, + }); + expect(page.root) + .toEqualHtml(` + +
+ +
+ + GC Design System notice + + +
+
+
+ + Provide additonal information + +
+ `); + }); + + it('renders - warning type', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + Provide additonal information + `, + }); + expect(page.root) + .toEqualHtml(` + +
+ +
+ + GC Design System notice + + +
+
+
+ + Provide additonal information + +
+ `); + }); + + it('renders - title tag h3', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + Provide additonal information + `, + }); + expect(page.root) + .toEqualHtml(` + +
+ +
+ + GC Design System notice + + +
+
+
+ + Provide additonal information + +
+ `); + }); + + it('renders - title tag h4', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + Provide additonal information + `, + }); + expect(page.root) + .toEqualHtml(` + +
+ +
+ + GC Design System notice + + +
+
+
+ + Provide additonal information + +
+ `); + }); + + it('renders - title tag h5', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + Provide additonal information + `, + }); + expect(page.root) + .toEqualHtml(` + +
+ +
+ + GC Design System notice + + +
+
+
+ + Provide additonal information + +
+ `); + }); + + it('does not render - no type', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + Provide additonal information + `, + }); + expect(page.root) + .toEqualHtml(` + + + + Provide additonal information + + + `); + }); + + it('does not render - no notice title', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + Provide additonal information + `, + }); + expect(page.root).toEqualHtml(` + + + + Provide additonal information + + + `); + }); + + it('does not render - no passed message', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + `, + }); + expect(page.root) + .toEqualHtml(` + + + + `); + }); + + it('does not render - no notice title tag', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + Provide additonal information + `, + }); + expect(page.root) + .toEqualHtml(` + + + + Provide additonal information + + + `); + }); + + it('does not render - invalid notice title tag value', async () => { + const page = await newSpecPage({ + components: [GcdsNotice], + html: ` + Provide additonal information + `, + }); + expect(page.root) + .toEqualHtml(` + + + + Provide additonal information + + + `); + }); +}); diff --git a/packages/web/src/index.html b/packages/web/src/index.html index cb355f67d..9e1d7b5fa 100644 --- a/packages/web/src/index.html +++ b/packages/web/src/index.html @@ -476,6 +476,34 @@
+ + + Notices + + + Please pay attention to this notice. +
    +
  • Information 1
  • +
  • Information 2
  • +
+
+ + Please pay attention to this notice. +
    +
  1. Information
  2. +
  3. Information
  4. +
+
+ + Please pay attention to this notice. + This line as well + + + Please pay attention to this notice. + + +
+ Text @@ -628,7 +656,6 @@ total-pages="22" current-page="8" url='{"queryStrings": { "querystring::offset": 10 }, "fragment": "main" }' - pageChangeHandler="{}" >