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

feat(styles): component form footer #3616

Merged
merged 22 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
6 changes: 6 additions & 0 deletions .changeset/gold-chairs-grin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@swisspost/design-system-documentation': minor
'@swisspost/design-system-styles': minor
---

Added Form Footer component.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
describe('Form footer', () => {
it('default', () => {
cy.visit('/iframe.html?id=snapshots--form-footer');
cy.get('.form-footer post-icon', { timeout: 30000 }).should('be.visible');
cy.percySnapshot('Form footer', { widths: [320, 1440] });
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Canvas, Controls, Meta } from '@storybook/blocks';
import * as FormFooterStories from './form-footer.stories';
import StylesPackageImport from '@/shared/styles-package-import.mdx';

<Meta of={FormFooterStories} />

<div className="docs-title">
# Footer

<nav>
<link-design of={JSON.stringify(FormFooterStories)}></link-design>
</nav>
</div>

<div className="lead">
The form footer is placed at the end/bottom of a form or a form step, in case the form is splitted with a stepper. It provides workflow-related actions to the form or form step.
</div>

<Canvas sourceState="shown" of={FormFooterStories.Default} />
<div className="hide-col-default">
<Controls of={FormFooterStories.Default} />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import type { StoryObj } from '@storybook/web-components';
import meta from './form-footer.stories';
import { FooterArgs } from './form-footer.stories';
import { html } from 'lit';
import { bombArgs } from '@/utils';

const { id, ...metaWithoutId } = meta;

export default {
...metaWithoutId,
title: 'Snapshots',
};

type Story = StoryObj;

export const FormFooter: Story = {
render: () => {
return html`
<div class="d-flex flex-column gap-3">
${['bg-white', 'bg-dark'].map(
bg => html`
<div class="${bg} d-flex flex-column p-3 gap-3">
${bombArgs({
showPrimaryButton: [true, false],
showSecondaryButton: [true, false],
showTertiaryButton: [true, false],
}).map(
args => html`
<div class="form-footer">
${args.showPrimaryButton || args.showSecondaryButton
? html`
<div class="form-footer-primary-actions">
${args.showPrimaryButton
? html`
<button class="btn btn-primary">
${FooterArgs.primaryButtonText}<post-icon
aria-hidden="true"
name="3020"
></post-icon>
</button>
`
: null}
${args.showSecondaryButton
? html`
<button class="btn btn-secondary">
${FooterArgs.secondaryButtonText}
</button>
`
: null}
</div>
`
: null}
${args.showTertiaryButton
? html`
<button class="btn btn-tertiary">
<post-icon aria-hidden="true" name="3024"></post-icon
>${FooterArgs.tertiaryButtonText}
</button>
`
: null}
</div>
`,
)}
</div>
`,
)}
</div>
`;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { Args, StoryObj } from '@storybook/web-components';
import { html } from 'lit';
import { MetaComponent } from '@root/types';

export const FooterArgs = {
showPrimaryButton: true,
primaryButtonText: 'Send',
showSecondaryButton: true,
secondaryButtonText: 'Cancel',
showTertiaryButton: true,
tertiaryButtonText: 'Back',
};

const meta: MetaComponent = {
id: 'f2eddf67-2c3c-40c4-bfec-df49bd028001',
title: 'Components/Forms/Form Footer',
tags: ['package:HTML'],
render: render,
parameters: {
badges: [],
design: {
type: 'figma',
url: 'https://www.figma.com/design/JIT5AdGYqv6bDRpfBPV8XR/Foundations-%26-Components-Next-Level?node-id=1498-28215',
},
},
args: FooterArgs,
argTypes: {
leagrdv marked this conversation as resolved.
Show resolved Hide resolved
showPrimaryButton: {
name: 'Show primary button',
description: 'Show or hide the primary button (last one on the right)',
control: { type: 'boolean' },
table: {
category: 'Primary button',
},
},
primaryButtonText: {
name: 'Primary button text',
description: 'Text to display on the primary button',
control: { type: 'text' },
leagrdv marked this conversation as resolved.
Show resolved Hide resolved
table: {
category: 'Primary button',
},
},
primaryButtonIcon: {
name: 'Primary button icon',
description: 'Icon to display on the primary button',
control: { type: 'text' },
table: {
category: 'Primary button',
},
},
showSecondaryButton: {
name: 'Show secondary button',
description: 'Show or hide the secondary button (first one on the right)',
control: { type: 'boolean' },
table: {
category: 'Secondary button',
},
},
secondaryButtonText: {
name: 'Secondary button text',
description: 'Text to display on the secondary button',
control: { type: 'text' },
table: {
category: 'Secondary button',
},
},
showTertiaryButton: {
name: 'Show tertiary button',
description: 'Show or hide the tertiary button (button on the left)',
control: { type: 'boolean' },
table: {
category: 'Tertiary button',
},
},
tertiaryButtonText: {
name: 'Tertiary button text',
description: 'Text to display on the tertiary button',
control: { type: 'text' },
table: {
category: 'Tertiary button',
},
},
},
};

export default meta;

type Story = StoryObj;

export function render(args: Args) {
return html`
<div class="form-footer">
${args.showPrimaryButton || args.showSecondaryButton
? html`
<div class="form-footer-primary-actions">
${args.showPrimaryButton
? html`<button class="btn btn-primary">
${args.primaryButtonText}<post-icon aria-hidden="true" name="3020"></post-icon>
leagrdv marked this conversation as resolved.
Show resolved Hide resolved
</button>`
: null}
${args.showSecondaryButton
? html`<button class="btn btn-secondary">${args.secondaryButtonText}</button>`
: null}
</div>
`
: null}
${args.showTertiaryButton
? html`<button class="btn btn-tertiary">
<post-icon aria-hidden="true" name="3024"></post-icon>${args.tertiaryButtonText}
</button>`
: null}
</div>
`;
}

export const Default: Story = {};
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,9 @@ To enable screen-readers to detect and read your hints, link the `<input>`
with the aria-describedby attribute to the hint via id.

<Canvas of={FormPatternsStories.Hints} sourceState="shown" />

## Form footer

The form footer is placed at the end/bottom of a form or a form step, in case the form is splitted with a stepper. It provides workflow-related actions to the form or form step.

<Canvas of={FormPatternsStories.Footer} sourceState="shown" />
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { StoryObj } from '@storybook/web-components';
import { html } from 'lit';
import { MetaExtended } from '@root/types';
import * as FormFooterMeta from '../../components/forms/form-footer/form-footer.stories';

const meta: MetaExtended = {
id: 'd83829b2-7de2-48d2-be64-07a80c9caef3',
Expand Down Expand Up @@ -352,3 +353,8 @@ export const Hints: Story = {
</div>
`,
};

export const Footer: Story = {
leagrdv marked this conversation as resolved.
Show resolved Hide resolved
render: FormFooterMeta.render,
args: FormFooterMeta.FooterArgs,
};
1 change: 1 addition & 0 deletions packages/styles/src/components/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
@use 'close';
@use 'elevation';
@use 'error-container';
@use 'form-footer';
@use 'form-range';
@use 'form-select';
@use 'form-textarea';
Expand Down
18 changes: 18 additions & 0 deletions packages/styles/src/components/form-footer.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@use '../mixins/utilities' as utility-mx;
@use '../tokens/components';
@use '../functions/tokens' as tokens;

tokens.$default-map: components.$post-form-footer;

.form-footer {
@include utility-mx.responsive-actions();
border-block-start-width: tokens.get('form-footer-border-block-start-width');
border-block-start-color: tokens.get('form-footer-border-start-color');
border-block-start-style: tokens.get('form-footer-border-block-start-style');
padding-block-start: tokens.get('form-footer-padding-block-start');
gap: tokens.get('form-footer-gap');

&-primary-actions {
gap: tokens.get('form-footer-gap');
}
}
26 changes: 26 additions & 0 deletions packages/styles/src/mixins/_utilities.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
@use './../themes/bootstrap/core' as *;
@use '../variables/spacing';
@use '../variables/commons';
@use '../variables/breakpoints';

@mixin reset-list() {
margin: 0;
Expand Down Expand Up @@ -174,3 +176,27 @@
}
}
}

@mixin responsive-actions {
leagrdv marked this conversation as resolved.
Show resolved Hide resolved
display: flex;
flex-direction: column;
justify-content: space-between;

@include media-breakpoint-up(md) {
flex-direction: row-reverse;

> .btn {
margin-right: auto;
}
}

&-primary-actions {
display: flex;
flex-direction: column;

@include media-breakpoint-up(md) {
flex-direction: row-reverse;
margin-left: auto;
}
}
}