\ No newline at end of file
diff --git a/packages/components/src/components/hds/application-state/header.ts b/packages/components/src/components/hds/application-state/header.ts
index 24740afec16..6b084dbab65 100644
--- a/packages/components/src/components/hds/application-state/header.ts
+++ b/packages/components/src/components/hds/application-state/header.ts
@@ -3,20 +3,22 @@
* SPDX-License-Identifier: MPL-2.0
*/
-import TemplateOnlyComponent from '@ember/component/template-only';
+import Component from '@glimmer/component';
import type { FlightIconSignature } from '@hashicorp/ember-flight-icons/components/flight-icon';
-
+import type { HdsTextDisplaySignature } from '../text/display';
export interface HdsApplicationStateHeaderSignature {
Args: {
title?: string;
+ titleTag?: HdsTextDisplaySignature['Args']['tag'];
errorCode?: string;
icon?: FlightIconSignature['Args']['name'];
};
Element: HTMLDivElement;
}
-const HdsApplicationStateHeaderComponent =
- TemplateOnlyComponent();
-
-export default HdsApplicationStateHeaderComponent;
+export default class HdsApplicationStateHeaderComponent extends Component {
+ get titleTag() {
+ return this.args.titleTag ?? 'div';
+ }
+}
diff --git a/packages/components/src/components/hds/application-state/index.hbs b/packages/components/src/components/hds/application-state/index.hbs
index e1f53266d8a..1caae7a1905 100644
--- a/packages/components/src/components/hds/application-state/index.hbs
+++ b/packages/components/src/components/hds/application-state/index.hbs
@@ -2,9 +2,10 @@
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: MPL-2.0
}}
-
+
{{yield
(hash
+ Media=(component "hds/application-state/media")
Header=(component "hds/application-state/header")
Body=(component "hds/application-state/body")
Footer=(component "hds/application-state/footer")
diff --git a/packages/components/src/components/hds/application-state/index.ts b/packages/components/src/components/hds/application-state/index.ts
index 454c5fb7a3e..0147cd7b7b6 100644
--- a/packages/components/src/components/hds/application-state/index.ts
+++ b/packages/components/src/components/hds/application-state/index.ts
@@ -3,16 +3,26 @@
* SPDX-License-Identifier: MPL-2.0
*/
-import TemplateOnlyComponent from '@ember/component/template-only';
+import Component from '@glimmer/component';
+import { assert } from '@ember/debug';
+import { HdsApplicationStateAlignValues } from './types.ts';
+
import type { ComponentLike } from '@glint/template';
+import type { HdsApplicationStateAligns } from './types';
+import type { HdsApplicationStateMediaSignature } from './media';
import type { HdsApplicationStateHeaderSignature } from './header';
import type { HdsApplicationStateBodySignature } from './body';
import type { HdsApplicationStateFooterSignature } from './footer';
+export const ALIGNS: string[] = Object.values(HdsApplicationStateAlignValues);
export interface HdsApplicationStateSignature {
+ Args: {
+ align?: HdsApplicationStateAligns;
+ };
Blocks: {
default: [
{
+ Media?: ComponentLike;
Header?: ComponentLike;
Body?: ComponentLike;
Footer?: ComponentLike;
@@ -22,7 +32,28 @@ export interface HdsApplicationStateSignature {
Element: HTMLDivElement;
}
-const HdsApplicationStateComponent =
- TemplateOnlyComponent();
+export default class HdsApplicationStateComponent extends Component {
+ get align(): HdsApplicationStateAligns {
+ const validAlignValues: HdsApplicationStateAligns[] = Object.values(
+ HdsApplicationStateAlignValues
+ );
+
+ assert(
+ `@align for "Hds::ApplicationState" must be one of the following: ${validAlignValues.join(
+ ', '
+ )}; received: ${this.args.align}`,
+ this.args.align == null || validAlignValues.includes(this.args.align)
+ );
+
+ return this.args.align ?? HdsApplicationStateAlignValues.Left;
+ }
-export default HdsApplicationStateComponent;
+ get classNames(): string {
+ const classes = ['hds-application-state'];
+
+ // add a class based on the @align argument
+ classes.push(`hds-application-state--align-${this.align}`);
+
+ return classes.join(' ');
+ }
+}
diff --git a/packages/components/src/components/hds/application-state/media.hbs b/packages/components/src/components/hds/application-state/media.hbs
new file mode 100644
index 00000000000..5ccc4f2b2e9
--- /dev/null
+++ b/packages/components/src/components/hds/application-state/media.hbs
@@ -0,0 +1,8 @@
+{{!
+ Copyright (c) HashiCorp, Inc.
+ SPDX-License-Identifier: MPL-2.0
+}}
+
+
+ {{yield}}
+
\ No newline at end of file
diff --git a/packages/components/src/components/hds/application-state/media.ts b/packages/components/src/components/hds/application-state/media.ts
new file mode 100644
index 00000000000..a6b71b8b1e5
--- /dev/null
+++ b/packages/components/src/components/hds/application-state/media.ts
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import TemplateOnlyComponent from '@ember/component/template-only';
+
+export interface HdsApplicationStateMediaSignature {
+ Blocks: {
+ default: [];
+ };
+ Element: HTMLDivElement;
+}
+
+const HdsApplicationStateMediaComponent =
+ TemplateOnlyComponent();
+
+export default HdsApplicationStateMediaComponent;
diff --git a/packages/components/src/components/hds/application-state/types.ts b/packages/components/src/components/hds/application-state/types.ts
new file mode 100644
index 00000000000..df2c355ab72
--- /dev/null
+++ b/packages/components/src/components/hds/application-state/types.ts
@@ -0,0 +1,5 @@
+export enum HdsApplicationStateAlignValues {
+ Left = 'left',
+ Center = 'center',
+}
+export type HdsApplicationStateAligns = `${HdsApplicationStateAlignValues}`;
diff --git a/packages/components/src/styles/components/application-state.scss b/packages/components/src/styles/components/application-state.scss
index 891d2009819..98a6f169497 100644
--- a/packages/components/src/styles/components/application-state.scss
+++ b/packages/components/src/styles/components/application-state.scss
@@ -7,43 +7,84 @@
// APPLICATION-STATE COMPONENT
//
-$hds-application-state-padding: 12px 0;
+$hds-application-state-content-max-width: 480px;
.hds-application-state {
- width: 19.5rem;
- max-width: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: start;
+ width: fit-content;
margin: 0 auto; // this will center the component in the parent container
+
+ &.hds-application-state--align-center {
+ align-items: center;
+ text-align: center;
+
+ .hds-application-state__header,
+ .hds-application-state__body,
+ .hds-application-state__footer {
+ width: auto;
+ }
+ }
+}
+
+.hds-application-state__media {
+ margin-bottom: 32px;
+
+ > * {
+ display: block;
+ max-width: 100%;
+ }
}
.hds-application-state__header {
display: grid;
+ grid-template-areas:
+ "error error"
+ "icon title";
grid-template-columns: min-content 1fr;
- align-items: start;
- color: var(--token-color-foreground-faint);
+ align-items: center;
+ width: 100%;
+ max-width: $hds-application-state-content-max-width;
+ color: var(--token-color-foreground-strong);
+}
+
+.hds-application-state__error-code {
+ grid-area: error;
+ margin-bottom: 4px;
}
.hds-application-state__icon {
+ grid-area: icon;
margin-right: 8px; // instead of column gap
padding-top: 4px; // this seems to align the icon along with line 21
}
-.hds-application-state__title,
-.hds-application-state__error-code {
- grid-column-start: 2;
+.hds-application-state__title {
+ grid-row: 2;
+ font-weight: var(--token-typography-font-weight-semibold);
+
+ &:not(.hds-application-state__icon + &) {
+ grid-column: icon / title;
+ }
}
.hds-application-state__body {
- padding: $hds-application-state-padding;
- color: var(--token-color-foreground-faint);
+ width: 100%;
+ max-width: $hds-application-state-content-max-width;
+ margin: 12px 0 0;
+ color: var(--token-color-foreground-primary);
}
.hds-application-state__footer {
display: flex;
- gap: 8px;
- justify-content: space-between;
+ gap: 16px;
+ width: 100%;
+ max-width: $hds-application-state-content-max-width;
+ margin-top: 24px;
- &.hds-application-state__footer--has-divider {
- padding: $hds-application-state-padding;
- border-top: 1px solid var(--token-color-border-strong);
+ // forces the third child and on to be on the right side
+ > :nth-child(3) {
+ margin-left: auto;
}
}
diff --git a/packages/components/src/template-registry.ts b/packages/components/src/template-registry.ts
index 8217a8c0c1c..d1f49b5d044 100644
--- a/packages/components/src/template-registry.ts
+++ b/packages/components/src/template-registry.ts
@@ -36,6 +36,7 @@ import type HdsApplicationStateComponent from './components/hds/application-stat
import type HdsApplicationStateBodyComponent from './components/hds/application-state/body';
import type HdsApplicationStateFooterComponent from './components/hds/application-state/footer';
import type HdsApplicationStateHeaderComponent from './components/hds/application-state/header';
+import type HdsApplicationStateMediaComponent from './components/hds/application-state/media';
import type HdsCardContainerComponent from './components/hds/card/container.ts';
import type HdsCopyButtonComponent from './components/hds/copy/button/index';
import type HdsCopySnippetComponent from './components/hds/copy/snippet';
@@ -243,6 +244,9 @@ export default interface HdsComponentsRegistry {
'Hds::ApplicationState::Footer': typeof HdsApplicationStateFooterComponent;
'hds/application-state/footer': typeof HdsApplicationStateFooterComponent;
+ 'Hds::ApplicationState::Media': typeof HdsApplicationStateMediaComponent;
+ 'hds/application-state/media': typeof HdsApplicationStateMediaComponent;
+
// Badge
'Hds::Badge': typeof HdsBadgeComponent;
'hds/badge': typeof HdsBadgeComponent;
diff --git a/showcase/app/controllers/components/application-state.js b/showcase/app/controllers/components/application-state.js
new file mode 100644
index 00000000000..fac5b02a3b2
--- /dev/null
+++ b/showcase/app/controllers/components/application-state.js
@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import Controller from '@ember/controller';
+import { action } from '@ember/object';
+import { tracked } from '@glimmer/tracking';
+
+export default class ApplicationStateController extends Controller {
+ @tracked showHighlight = false;
+
+ @action
+ toggleHighlight() {
+ this.showHighlight = !this.showHighlight;
+ }
+}
diff --git a/showcase/app/routes/components/application-state.js b/showcase/app/routes/components/application-state.js
index b6597889d66..8edb7f1a3e3 100644
--- a/showcase/app/routes/components/application-state.js
+++ b/showcase/app/routes/components/application-state.js
@@ -5,4 +5,12 @@
import Route from '@ember/routing/route';
-export default class ComponentsApplicationStateRoute extends Route {}
+import { ALIGNS } from '@hashicorp/design-system-components/components/hds/application-state';
+
+export default class ComponentsApplicationStateRoute extends Route {
+ model() {
+ return {
+ ALIGNS,
+ };
+ }
+}
diff --git a/showcase/app/styles/app.scss b/showcase/app/styles/app.scss
index e3691e1b1fa..7502284e590 100644
--- a/showcase/app/styles/app.scss
+++ b/showcase/app/styles/app.scss
@@ -32,6 +32,7 @@
@import "./showcase-pages/alert";
@import "./showcase-pages/app-header";
@import "./showcase-pages/app-footer";
+@import "./showcase-pages/application-state";
@import "./showcase-pages/app-frame";
@import "./showcase-pages/badge";
@import "./showcase-pages/breadcrumb";
diff --git a/showcase/app/styles/showcase-pages/application-state.scss b/showcase/app/styles/showcase-pages/application-state.scss
new file mode 100644
index 00000000000..f337920633b
--- /dev/null
+++ b/showcase/app/styles/showcase-pages/application-state.scss
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+// APPLICATION-STATE
+
+body.application-state {
+ .shw-component-application-state-button-highlight {
+ margin: 24px 0;
+ }
+
+ .shw-component-application-state-layout-highlight {
+ .shw-flex__item {
+ outline: 1px dashed #78909c;
+ }
+
+ .hds-application-state {
+ // named color usage purely for layout testing
+ outline: 2px dotted magenta;
+ }
+
+ .hds-application-state__media {
+ // named color usage purely for layout testing
+ outline: 1px solid green;
+ }
+
+ .hds-application-state__header,
+ .hds-application-state__body,
+ .hds-application-state__footer {
+ // named color usage purely for layout testing
+ outline: 1px solid cyan;
+ }
+ }
+
+ .shw-component-application-state-avatar {
+ width: 125px;
+ height: 125px;
+ border-radius: 100%;
+ }
+
+ .shw-component-application-state-banner {
+ width: 680px;
+ }
+}
diff --git a/showcase/app/templates/components/application-state.hbs b/showcase/app/templates/components/application-state.hbs
index 3ffb37c25e1..4f9696e1749 100644
--- a/showcase/app/templates/components/application-state.hbs
+++ b/showcase/app/templates/components/application-state.hbs
@@ -7,124 +7,535 @@
ApplicationState
-
-
-
+
+
+ Content
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
+
-
-
+
-
+
-
+
-
-
+
-
-
-
-
-
-
-
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
-
+
+
+
-
+
-
+
+
-
+
+
-
+
+
+
+
+
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Alignment
+
+
+
+
+ {{#each @model.ALIGNS as |align|}}
+
+
+
+
+
+
+
+
+
+ {{/each}}
+ {{#each @model.ALIGNS as |align|}}
+
+
+
+
+
+
+
+
+
+
+ {{/each}}
+ {{#each @model.ALIGNS as |align|}}
+
+
+
+
+
+
+
+
+
+
+
+ {{/each}}
+ {{#each @model.ALIGNS as |align|}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{/each}}
+ {{#each @model.ALIGNS as |align|}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{/each}}
+
+
+
+
+ With media
+
+
+
+
+ {{#each @model.ALIGNS as |align|}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{/each}}
+ {{#each @model.ALIGNS as |align|}}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{/each}}
+ {{#each @model.ALIGNS as |align|}}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{/each}}
+ {{#each @model.ALIGNS as |align|}}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{/each}}
+
+
+
+
+ With wide media (banner-like)
+
+
+
+
+ {{#each @model.ALIGNS as |align|}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{/each}}
+
+
+
+
+ Responsiveness
+
+
+
+
+ {{#let
+ (array
+ (hash value="100%" label="Both media and content smaller than parent container")
+ (hash value="550px" label="Media larger and content smaller than parent container")
+ (hash value="320px" label="Both media and content larger than parent container")
+ )
+ as |widths|
+ }}
+ {{#each widths as |width|}}
+ {{#each @model.ALIGNS as |align|}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{/each}}
+ {{/each}}
+ {{/let}}
+
+
+
+
+ In a container
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <:head as |H|>
+
+ Lorem
+ Ipsum
+ Dolor
+
+
+ <:body as |B|>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/showcase/public/assets/images/cat-banner.png b/showcase/public/assets/images/cat-banner.png
new file mode 100644
index 00000000000..79937c6e347
Binary files /dev/null and b/showcase/public/assets/images/cat-banner.png differ
diff --git a/showcase/tests/integration/components/hds/application-state/footer-test.js b/showcase/tests/integration/components/hds/application-state/footer-test.js
index 5d94da88872..606998af0f1 100644
--- a/showcase/tests/integration/components/hds/application-state/footer-test.js
+++ b/showcase/tests/integration/components/hds/application-state/footer-test.js
@@ -24,13 +24,6 @@ module(
.dom('#test-application-state-footer')
.hasClass('hds-application-state__footer');
});
- test('if @hasDivider is set to true, a class should be applied to render a visual divider', async function (assert) {
- await render(hbs`
-
- `);
-
- assert.dom('.hds-application-state__footer--has-divider').exists();
- });
// CONTEXTUAL COMPONENTS
diff --git a/showcase/tests/integration/components/hds/application-state/header-test.js b/showcase/tests/integration/components/hds/application-state/header-test.js
index 7ff3d5c2645..ab1298de22b 100644
--- a/showcase/tests/integration/components/hds/application-state/header-test.js
+++ b/showcase/tests/integration/components/hds/application-state/header-test.js
@@ -38,5 +38,21 @@ module(
assert.dom('.hds-application-state__error-code').exists();
});
+
+ test('it should render the title with a `div` tag if no `@titleTag` is provided', async function (assert) {
+ await render(
+ hbs``
+ );
+
+ assert.dom('.hds-application-state__title').hasTagName('div');
+ });
+
+ test('it should render the title with the tag set for `@titleTag`', async function (assert) {
+ await render(
+ hbs``
+ );
+
+ assert.dom('.hds-application-state__title').hasTagName('h1');
+ });
}
);
diff --git a/showcase/tests/integration/components/hds/application-state/index-test.js b/showcase/tests/integration/components/hds/application-state/index-test.js
index ed0dfbb335c..7ca37bfd0ff 100644
--- a/showcase/tests/integration/components/hds/application-state/index-test.js
+++ b/showcase/tests/integration/components/hds/application-state/index-test.js
@@ -5,7 +5,7 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'showcase/tests/helpers';
-import { render } from '@ember/test-helpers';
+import { render, resetOnerror, setupOnerror } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module(
@@ -13,6 +13,10 @@ module(
function (hooks) {
setupRenderingTest(hooks);
+ hooks.afterEach(() => {
+ resetOnerror();
+ });
+
test('it should render with a CSS class that matches the component name', async function (assert) {
await render(hbs`
@@ -22,5 +26,96 @@ module(
assert.dom('#test-application-state').hasClass('hds-application-state');
});
+
+ test('it should have the correct alignment class when no alignment is provided', async function (assert) {
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert
+ .dom('#test-application-state')
+ .hasClass('hds-application-state--align-left');
+ });
+
+ test('it should have the correct alignment class when alignment is set to "left"', async function (assert) {
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert
+ .dom('#test-application-state')
+ .hasClass('hds-application-state--align-left');
+ });
+
+ test('it should have the correct alignment class when alignment is set to "center"', async function (assert) {
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert
+ .dom('#test-application-state')
+ .hasClass('hds-application-state--align-center');
+ });
+
+ // CONTEXTUAL COMPONENTS
+
+ test('it renders the contextual components', async function (assert) {
+ await render(
+ hbs`
+ ApplicationState Media
+
+ ApplicationState Body
+ ApplicationState Footer
+ `
+ );
+ assert
+ .dom('.hds-application-state__media')
+ .hasText('ApplicationState Media');
+ assert
+ .dom('.hds-application-state__header')
+ .hasText('ApplicationState Title');
+ assert
+ .dom('.hds-application-state__body')
+ .hasText('ApplicationState Body');
+ assert
+ .dom('.hds-application-state__footer')
+ .hasText('ApplicationState Footer');
+ });
+ test('it does not render the contextual components if not provided', async function (assert) {
+ await render(hbs``);
+ assert.dom('.hds-application-date__media').doesNotExist();
+ assert.dom('.hds-application-date__header').doesNotExist();
+ assert.dom('.hds-application-date__body').doesNotExist();
+ assert.dom('.hds-application-date__footer').doesNotExist();
+ });
+
+ // ASSERTIONS
+
+ test('it should throw an assertion if an incorrect value for @alignment provided', async function (assert) {
+ const errorMessage =
+ '@align for "Hds::ApplicationState" must be one of the following: left, center; received: test';
+
+ assert.expect(2);
+
+ setupOnerror(function (error) {
+ assert.strictEqual(error.message, `Assertion Failed: ${errorMessage}`);
+ });
+
+ await render(hbs`
+
+ template block text
+
+ `);
+
+ assert.throws(function () {
+ throw new Error(errorMessage);
+ });
+ });
}
);
diff --git a/showcase/tests/integration/components/hds/application-state/media-test.js b/showcase/tests/integration/components/hds/application-state/media-test.js
new file mode 100644
index 00000000000..2128b5ed7ea
--- /dev/null
+++ b/showcase/tests/integration/components/hds/application-state/media-test.js
@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'showcase/tests/helpers';
+import { render } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module(
+ 'Integration | Component | hds/application-state/media',
+ function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it should render with a CSS class that matches the component name', async function (assert) {
+ await render(
+ hbs``
+ );
+
+ assert
+ .dom('#test-application-state-media')
+ .hasClass('hds-application-state__media');
+ });
+
+ test('it should render the yielded content when used in block form', async function (assert) {
+ await render(
+ hbs`
+
test
+ `
+ );
+ assert.dom('#test-application-state-media > pre').exists();
+ assert.dom('#test-application-state-media > pre').hasText('test');
+ });
+ }
+);
diff --git a/website/docs/components/application-state/index.md b/website/docs/components/application-state/index.md
index 093af1feb1b..b04e1eab191 100644
--- a/website/docs/components/application-state/index.md
+++ b/website/docs/components/application-state/index.md
@@ -11,6 +11,7 @@ navigation:
---
+ @include "partials/guidelines/overview.md"
@include "partials/guidelines/guidelines.md"
diff --git a/website/docs/components/application-state/partials/code/component-api.md b/website/docs/components/application-state/partials/code/component-api.md
index f968d4af3c4..223c2193d04 100644
--- a/website/docs/components/application-state/partials/code/component-api.md
+++ b/website/docs/components/application-state/partials/code/component-api.md
@@ -3,6 +3,9 @@
### ApplicationState
+ " @type="yielded component">
+ `ApplicationState::Media` yielded as contextual component (see below).
+ " @type="yielded component">
`ApplicationState::Header` yielded as contextual component (see below).
@@ -19,6 +22,19 @@
### Contextual components
+#### [A].Media
+
+The `ApplicationState::Media` component, yielded as contextual component.
+
+
+
+ Elements passed as children are yielded as inner content of the "media" block.
+
+
+ This component supports use of [`...attributes`](https://guides.emberjs.com/release/in-depth-topics/patterns-for-components/#toc_attribute-ordering).
+
+
+
#### [A].Header
The `ApplicationState::Header` component, yielded as contextual component.
@@ -30,7 +46,12 @@ The `ApplicationState::Header` component, yielded as contextual component.
Adds a leading icon to the title. Accepts any [icon](/icons/library) name.
-
+
+ The text of the title
+
+
+ This component supports use of [`...attributes`](https://guides.emberjs.com/release/in-depth-topics/patterns-for-components/#toc_attribute-ordering).
+
#### [A].Body
@@ -39,10 +60,13 @@ The `ApplicationState::Body` component, yielded as contextual component.
- Supports block invocation for custom content (see [Block Content](https://guides.emberjs.com/release/components/block-content/) in Ember docs).
+ Elements passed as children are yielded as inner content of the "body" block.
- Note: use `@text` for an inline invocation only. This component does not support `@text` on the component invocation if it is used as a block.
+ Note: use `@text` to pass directly text to the "body", with a predefined style. This component does not support `@text` on the component invocation if it is used with yielded content.
+
+
+ This component supports use of [`...attributes`](https://guides.emberjs.com/release/in-depth-topics/patterns-for-components/#toc_attribute-ordering).
@@ -51,10 +75,16 @@ The `ApplicationState::Body` component, yielded as contextual component.
The `ApplicationState::Footer` component, yielded as contextual component.
-
- Indicates if there should be a visible divider above the footer.
+ " @type="yielded component">
+ The `Button` component, yielded as contextual component inside the `"footer"` block of the ApplicationState. It exposes the same API as the [`Button` component](/components/button).
+
+ " @type="yielded component">
+ The `Dropdown` component, yielded as contextual component inside the `"footer"` block of the ApplicationState. It exposes the same API as the [`Dropdown` component](/components/dropdown).
" @type="yielded component">
The `Link::Standalone` component, yielded as contextual component inside the `"footer"` block of the ApplicationState. It exposes the same API as the [`Link::Standalone` component](/components/link/standalone).
+
+ This component supports use of [`...attributes`](https://guides.emberjs.com/release/in-depth-topics/patterns-for-components/#toc_attribute-ordering).
+
diff --git a/website/docs/components/application-state/partials/code/how-to-use.md b/website/docs/components/application-state/partials/code/how-to-use.md
index 7699ffbcc81..266a968a6e7 100644
--- a/website/docs/components/application-state/partials/code/how-to-use.md
+++ b/website/docs/components/application-state/partials/code/how-to-use.md
@@ -33,37 +33,49 @@ This component intends to replace a few different simple error and empty/zero st
```
-#### Empty state with a footer link and divider
+#### Empty state with yielded body block
```handlebars
-
-
-
+
+
+
+
+
```
-#### Empty state with yielded body block
+#### Empty state with body text
```handlebars
-
-
-
+
```
-#### Empty state with body text
+#### Empty state with center alignment
+
+```handlebars
+
+
+
+
+
+
+
+```
+
+#### Empty state with media
```handlebars
+
@@ -124,19 +136,37 @@ To indicate that the message is an error state, add `@errorCode` to the `[A].Hea
```
-#### Error state with a footer divider
+#### Error state with center alignment
+
+```handlebars
+
+
+
+
+
+
+
+
+```
+
+#### Error state with media
```handlebars
+
-
+
-
+
-```
\ No newline at end of file
+```
diff --git a/website/docs/components/application-state/partials/guidelines/guidelines.md b/website/docs/components/application-state/partials/guidelines/guidelines.md
index 9616f856119..f565b06ce5b 100644
--- a/website/docs/components/application-state/partials/guidelines/guidelines.md
+++ b/website/docs/components/application-state/partials/guidelines/guidelines.md
@@ -2,28 +2,117 @@
### When to use
-- When a user’s action does not yield any results due to incorrect or incomplete input.
- When an application encounters an issue or error during its operation.
+- When emphasis is needed on the creation of a new object within a null state.
### When not to use
- When the absence of content is expected and does not require an explanation to the user.
- When there is a clear and intuitive way to add or populate content.
-## Icon
+## Alignment
-- The icon should align with the purpose of the content and effectively communicate the same message.
+The Application State supports two alignment options: `left` (default) and `center`. The alignment affects text alignment, action placement/alignment in the footer, and media placement; however, it does not change the default page alignment.
-## Actions
+!!! Info
-- In the footer, you can include up to two stand-alone links.
-- We don’t recommend using buttons, as most actions will navigate the user away from this page. Learn more about [when to use a link vs. a button](https://helios.hashicorp.design/components/link/standalone#usage).
-- For the standalone link, we recommend using the medium size.
-- Use footer actions to redirect or guide users in solving errors/access issues with actionable steps.
+By default, the Application State has horizontal auto margins applied to it, always centering it on the page or containing element. This can be overridden with CSS properties.
-## Content
+!!!
-- The title should be short and provide a clear and concise message.
-- Focus on relevant information and avoid unnecessary details.
-- Provide a straightforward explanation of the problem or error.
-- Include suggestions or guidance for how the user can resolve the issue, if possible.
+### Left alignment
+
+
+
+### Center alignment
+
+
+
+## Media
+
+The media slot is used to add illustrations to increase the visual impact of the Application State.
+
+This provides additional visual prominence while also elevating the brand experience. If the illustration has a circular container, we recommend setting the `alignment` to `center`.
+
+
+
+
+## Header
+
+### Icon
+
+When set, the icon is displayed side by side with the title.
+
+
+
+This is commonly used when displaying an error state for application failures. The icon must always be accompanied by a title.
+
+### Title
+
+The title should be short and provide a clear and concise message.
+
+### Error code
+
+If enabled and available, an error code will be shown, providing additional information associated with the title.
+
+## Body
+
+Focus on relevant information and avoid unnecessary details. If there is an error, include suggestions or guidance for how the user can resolve the issue, if possible. If no objects are found (zero/empty state), provide a brief explanation on how creating this new object will benefit the user.
+
+The body allows for two types of content: `text` and `generic`.
+
+
+
+
+## Footer
+The Application State supports up to three actions, including [Dropdown](/components/dropdown), [Standalone Link](/components/link/standalone), and [Button](/components/button) components. Use footer actions to help users resolve errors or access issues with actionable steps.
+
+
+
+### Using buttons or links
+
+Buttons, along with links, are the most common actions used in the footer. Buttons are more often used in empty state contexts because they provide high visibility for the primary action on the page. Links are more common in error state contexts as a means to provide a solution to the error they encountered.
+
+Read more about when to use [Buttons](/components/button) and [Links](/components/link/standalone).
+
+!!! Dont
+
+When there is an empty state that occupies the majority of the page, do not display two similar actions in different areas of the UI. In this example, there is a primary button in the Page Header and in the Application State.
+
+
+
+!!!
+
+!!! Do
+
+Instead, use the Application State as the only means of drawing attention to the primary action.
+
+
+
+!!!
+
+### Using dropdowns
+
+Dropdowns can be used as actions in the footer in rare cases. Limit dropdowns to one per Application State.
+
+
+
+## Width constraints
+
+The Application State’s content has a max width of 480 pixels. This is done for better readability, ensuring that the max character count is close to 70 characters per line.
+
+## Examples
+
+Here are some common use cases for the Application State, however, it is not limited to just these two examples.
+
+### Error state
+
+Error states are used when the application encounters an issue or error during its operation. It shows the associated error code, icon, messages, and actions to help users find a solution.
+
+
+
+### Empty state
+
+An empty state occurs when a user has yet to create an object. Illustrations are placed using the `media` slot to further elevate the experience and express the purpose of the object.
+
+
\ No newline at end of file
diff --git a/website/docs/components/application-state/partials/guidelines/overview.md b/website/docs/components/application-state/partials/guidelines/overview.md
new file mode 100644
index 00000000000..7b626210f62
--- /dev/null
+++ b/website/docs/components/application-state/partials/guidelines/overview.md
@@ -0,0 +1 @@
+The Application State is used to communicate status, errors, and zero/empty states.
\ No newline at end of file
diff --git a/website/docs/components/application-state/partials/specifications/anatomy.md b/website/docs/components/application-state/partials/specifications/anatomy.md
index c3ade3e3021..7d5f95a38e6 100644
--- a/website/docs/components/application-state/partials/specifications/anatomy.md
+++ b/website/docs/components/application-state/partials/specifications/anatomy.md
@@ -4,10 +4,10 @@
| Element | Usage |
|------------------|-------------------------------------------------|
+| Media | Optional. |
| Title | Required. |
| Icon | Optional, but recommended with errorCode. |
| errorCode | Optional, but recommended when in errorState. |
| Body | Required. |
-| Separator | Optional, but recommended when separating actions from content. |
| Footer | Optional. |
-| Action | Required, if no footer; optional. |
\ No newline at end of file
+| Actions | Required, if no footer; optional. |
\ No newline at end of file
diff --git a/website/public/assets/components/application-state/application-state-alignment-center.png b/website/public/assets/components/application-state/application-state-alignment-center.png
new file mode 100644
index 00000000000..4f554990b79
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-alignment-center.png differ
diff --git a/website/public/assets/components/application-state/application-state-alignment-left.png b/website/public/assets/components/application-state/application-state-alignment-left.png
new file mode 100644
index 00000000000..a371fdae81b
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-alignment-left.png differ
diff --git a/website/public/assets/components/application-state/application-state-anatomy-page.png b/website/public/assets/components/application-state/application-state-anatomy-page.png
index 71951df5c91..91a3db5d717 100644
Binary files a/website/public/assets/components/application-state/application-state-anatomy-page.png and b/website/public/assets/components/application-state/application-state-anatomy-page.png differ
diff --git a/website/public/assets/components/application-state/application-state-body-content-types.png b/website/public/assets/components/application-state/application-state-body-content-types.png
new file mode 100644
index 00000000000..4387e7db402
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-body-content-types.png differ
diff --git a/website/public/assets/components/application-state/application-state-dropdown-actions.png b/website/public/assets/components/application-state/application-state-dropdown-actions.png
new file mode 100644
index 00000000000..c8462b0fe7b
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-dropdown-actions.png differ
diff --git a/website/public/assets/components/application-state/application-state-empty-state-do-keep-one-primary-cta.png b/website/public/assets/components/application-state/application-state-empty-state-do-keep-one-primary-cta.png
new file mode 100644
index 00000000000..4ed668962b7
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-empty-state-do-keep-one-primary-cta.png differ
diff --git a/website/public/assets/components/application-state/application-state-empty-state-dont-duplicate-buttons.png b/website/public/assets/components/application-state/application-state-empty-state-dont-duplicate-buttons.png
new file mode 100644
index 00000000000..a74d45d172b
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-empty-state-dont-duplicate-buttons.png differ
diff --git a/website/public/assets/components/application-state/application-state-empty-state.png b/website/public/assets/components/application-state/application-state-empty-state.png
new file mode 100644
index 00000000000..6ef8028c2b8
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-empty-state.png differ
diff --git a/website/public/assets/components/application-state/application-state-error-state.png b/website/public/assets/components/application-state/application-state-error-state.png
new file mode 100644
index 00000000000..41126280e7c
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-error-state.png differ
diff --git a/website/public/assets/components/application-state/application-state-footer-action-types.png b/website/public/assets/components/application-state/application-state-footer-action-types.png
new file mode 100644
index 00000000000..aded3e74f31
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-footer-action-types.png differ
diff --git a/website/public/assets/components/application-state/application-state-icon-usage.png b/website/public/assets/components/application-state/application-state-icon-usage.png
new file mode 100644
index 00000000000..0a241f606e2
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-icon-usage.png differ
diff --git a/website/public/assets/components/application-state/application-state-media-slot-icon-tile-center-alignment.png b/website/public/assets/components/application-state/application-state-media-slot-icon-tile-center-alignment.png
new file mode 100644
index 00000000000..868aef1ad8c
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-media-slot-icon-tile-center-alignment.png differ
diff --git a/website/public/assets/components/application-state/application-state-media-slot-spot-illustration-center-alignment.png b/website/public/assets/components/application-state/application-state-media-slot-spot-illustration-center-alignment.png
new file mode 100644
index 00000000000..496bd2e9020
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-media-slot-spot-illustration-center-alignment.png differ
diff --git a/website/public/assets/components/application-state/application-state-media-slot.png b/website/public/assets/components/application-state/application-state-media-slot.png
new file mode 100644
index 00000000000..9bba981be5f
Binary files /dev/null and b/website/public/assets/components/application-state/application-state-media-slot.png differ