Skip to content

Commit

Permalink
feat(components): add composable footer (#4190)
Browse files Browse the repository at this point in the history
Co-authored-by: Philipp Gfeller <[email protected]>
  • Loading branch information
oliverschuerch and gfellerph authored Dec 13, 2024
1 parent b4179db commit 14b4de9
Show file tree
Hide file tree
Showing 43 changed files with 953 additions and 43 deletions.
6 changes: 6 additions & 0 deletions .changeset/calm-rabbits-pull.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@swisspost/design-system-components': minor
'@swisspost/design-system-styles': minor
---

Added composable footer component.
5 changes: 5 additions & 0 deletions .changeset/gorgeous-needles-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-components': patch
---

Added a fixed slot `post-list-item` on the `post-list-item` host element, so it is no longer necessary to add it manually.
5 changes: 5 additions & 0 deletions .changeset/heavy-eyes-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-components': patch
---

Fixed the used `headingLevel` in the `post-accorddion-item` component. The component now uses the value from its closest `post-accorddion` parent component, if this is specified and falls back to `h2` if not specified.
5 changes: 5 additions & 0 deletions .changeset/hungry-penguins-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-styles': patch
---

Fixed the `btn-icon` styles, so icons within can no longer be rendered too small, because of the inline-padding on the button.
5 changes: 5 additions & 0 deletions .changeset/new-cougars-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-components': minor
---

Added the parts `button` and `body` in the `post-accordion-item` component, so one can override styles from the outside.
5 changes: 5 additions & 0 deletions .changeset/nine-baboons-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-styles': patch
---

Fixed the appstore-badge styles to get rid of the inline gap below.
5 changes: 5 additions & 0 deletions .changeset/old-spiders-travel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-styles': minor
---

Added the possibility to define a `$child-selector` parameter with our list mixins, so they can be used also with custom elements.
6 changes: 6 additions & 0 deletions .changeset/tender-laws-confess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@swisspost/design-system-documentation': minor
'@swisspost/design-system-components': minor
---

Added the css parts `button` and `body` in the `post-accorddion-item` component.
54 changes: 54 additions & 0 deletions packages/components/cypress/e2e/footer.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const FOOTER_ID = 'd97528b3-a9ef-4201-bf28-9caf6e8997dc';

describe('Footer', () => {
describe('Structure & Props', () => {
beforeEach(() => {
cy.getComponent('footer', FOOTER_ID);
cy.get('@footer').find('> footer h2.visually-hidden').as('label');
});

it('should render', () => {
cy.get('@footer').should('exist');
});

it('should set label text according to "label" prop', () => {
cy.get('@label').should('have.text', 'Footer label');
});

it('should render the post-accorddion on mobile', () => {
cy.viewport('iphone-3');
cy.get('@footer').find('post-accorddion').as('accorddion');

cy.get('@accorddion').should('exist');
});

it('should have accorddion-items with slotted elements on mobile', () => {
cy.viewport('iphone-3');
cy.get('@footer').find('post-accorddion').as('accorddion');
cy.get('@accorddion').find('post-accordion-item').as('accordionItems');

cy.get('@accordionItems').should('have.length', 4);
cy.get('@accordionItems')
.find('slot[name="header"]')
.each($slot => {
const headerSlot = $slot.get(0) as HTMLSlotElement;

expect(headerSlot.assignedElements().length).to.be.greaterThan(0);
});
cy.get('@accordionItems')
.find('slot:not([name])')
.each($slot => {
const slotDefault = $slot.get(0) as HTMLSlotElement;

expect(slotDefault.assignedElements().length).to.be.greaterThan(0);
});
});
});

describe('Accessibility', () => {
it('Has no detectable a11y violations', () => {
cy.getSnapshots('footer');
cy.checkA11y('#root-inner');
});
});
});
21 changes: 21 additions & 0 deletions packages/components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ export namespace Components {
*/
"update": () => Promise<void>;
}
interface PostFooter {
/**
* The label to add to the footer (visually hidden).
*/
"label": string;
}
interface PostHeader {
/**
* Toggles the mobile navigation.
Expand Down Expand Up @@ -604,6 +610,12 @@ declare global {
prototype: HTMLPostCollapsibleTriggerElement;
new (): HTMLPostCollapsibleTriggerElement;
};
interface HTMLPostFooterElement extends Components.PostFooter, HTMLStencilElement {
}
var HTMLPostFooterElement: {
prototype: HTMLPostFooterElement;
new (): HTMLPostFooterElement;
};
interface HTMLPostHeaderElement extends Components.PostHeader, HTMLStencilElement {
}
var HTMLPostHeaderElement: {
Expand Down Expand Up @@ -828,6 +840,7 @@ declare global {
"post-closebutton": HTMLPostClosebuttonElement;
"post-collapsible": HTMLPostCollapsibleElement;
"post-collapsible-trigger": HTMLPostCollapsibleTriggerElement;
"post-footer": HTMLPostFooterElement;
"post-header": HTMLPostHeaderElement;
"post-icon": HTMLPostIconElement;
"post-language-option": HTMLPostLanguageOptionElement;
Expand Down Expand Up @@ -993,6 +1006,12 @@ declare namespace LocalJSX {
*/
"for"?: string;
}
interface PostFooter {
/**
* The label to add to the footer (visually hidden).
*/
"label": string;
}
interface PostHeader {
}
/**
Expand Down Expand Up @@ -1247,6 +1266,7 @@ declare namespace LocalJSX {
"post-closebutton": PostClosebutton;
"post-collapsible": PostCollapsible;
"post-collapsible-trigger": PostCollapsibleTrigger;
"post-footer": PostFooter;
"post-header": PostHeader;
"post-icon": PostIcon;
"post-language-option": PostLanguageOption;
Expand Down Expand Up @@ -1288,6 +1308,7 @@ declare module "@stencil/core" {
"post-closebutton": LocalJSX.PostClosebutton & JSXBase.HTMLAttributes<HTMLPostClosebuttonElement>;
"post-collapsible": LocalJSX.PostCollapsible & JSXBase.HTMLAttributes<HTMLPostCollapsibleElement>;
"post-collapsible-trigger": LocalJSX.PostCollapsibleTrigger & JSXBase.HTMLAttributes<HTMLPostCollapsibleTriggerElement>;
"post-footer": LocalJSX.PostFooter & JSXBase.HTMLAttributes<HTMLPostFooterElement>;
"post-header": LocalJSX.PostHeader & JSXBase.HTMLAttributes<HTMLPostHeaderElement>;
/**
* @class PostIcon - representing a stencil component
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { HEADING_LEVELS, HeadingLevel } from '@/types';
import { checkEmptyOrOneOf } from '@/utils';

/**
* @part button - The pseudo-element, used to override styles on the components internal header `button` element.
* @part body - The pseudo-element, used to override styles on the components internal `body` element.
* @slot logo - Slot for the placing a logo before the header.
* @slot header - Slot for placing custom content within the accordion item's header.
* @slot default - Slot for placing content within the accordion item's body.
Expand Down Expand Up @@ -79,14 +81,19 @@ export class PostAccordionItem {
}

render() {
const HeadingTag = `h${this.headingLevel ?? 2}`;
const headingLevel = this.host.closest('post-accorddion')?.getAttribute('heading-level');
const HeadingTag = `h${headingLevel ?? this.headingLevel ?? 2}`;

return (
<Host id={this.id} data-version={version}>
<div part="accordion-item" class="accordion-item">
<post-collapsible-trigger for={`${this.id}--collapse`}>
<HeadingTag class="accordion-header" id={`${this.id}--header`}>
<button type="button" class={`accordion-button${this.collapsed ? ' collapsed' : ''}`}>
<button
type="button"
class={`accordion-button${this.collapsed ? ' collapsed' : ''}`}
part="button"
>
<span
class={{
'logo-container': true,
Expand All @@ -106,7 +113,7 @@ export class PostAccordionItem {
collapsed={this.collapsed}
ref={el => (this.collapsible = el)}
>
<div class="accordion-body">
<div class="accordion-body" part="body">
<slot />
</div>
</post-collapsible>
Expand Down
13 changes: 10 additions & 3 deletions packages/components/src/components/post-accordion-item/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,19 @@ Type: `Promise<boolean>`

## Shadow Parts

| Part | Description |
| ------------------ | ----------- |
| `"accordion-item"` | |
| Part | Description |
| ------------------ | ----------------------------------------------------------------------------------------------- |
| `"accordion-item"` | |
| `"body"` | The pseudo-element, used to override styles on the components internal `body` element. |
| `"button"` | The pseudo-element, used to override styles on the components internal header `button` element. |


## Dependencies

### Used by

- [post-footer](../post-footer)

### Depends on

- [post-collapsible-trigger](../post-collapsible-trigger)
Expand All @@ -62,6 +68,7 @@ graph TD;
post-accordion-item --> post-collapsible-trigger
post-accordion-item --> post-icon
post-accordion-item --> post-collapsible
post-footer --> post-accordion-item
style post-accordion-item fill:#f9f,stroke:#333,stroke-width:4px
```

Expand Down
153 changes: 153 additions & 0 deletions packages/components/src/components/post-footer/post-footer.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
@use '@swisspost/design-system-styles/variables/color';
@use '@swisspost/design-system-styles/mixins/media';
@use '@swisspost/design-system-styles/mixins/list';
@use '@swisspost/design-system-styles/mixins/utilities';

:host {
display: block;
}

footer {
background-color: color.$yellow;

// mobile
--post-footer-container-padding-block: 32px;
--post-footer-container-padding-inline: 16px;
--post-footer-container-max-width: 1200px;

--post-footer-grid-template: auto / auto;
--post-footer-grid-row-gap: 0;
--post-footer-grid-column-gap: 0;
--post-footer-grid-margin-block-end: 24px;
--post-footer-grid-padding-block-end: 0;

--post-footer-column-flex-direction: column;
--post-footer-column-align-items: start;
--post-footer-column-gap: 0;

--post-footer-post-list-flex-direction: column;
--post-footer-post-list-gap: 8px;
--post-footer-post-list-align-items: start;

--post-footer-socialmedia-margin-block-end: var(--post-footer-grid-margin-block-end);
--post-footer-app-margin-block-end: var(--post-footer-grid-margin-block-end);
--post-footer-businesssectors-margin-block-end: var(--post-footer-grid-margin-block-end);

--post-footer-meta-margin-block-end: 16px;
--post-footer-meta-font-size: inherit;

--post-footer-copyright-font-size: var(--post-footer-meta-font-size);

// tablet sm
@include media.min(sm) {
--post-footer-container-padding-block: 40px;

--post-footer-grid-template: repeat(2, auto) / repeat(2, auto);
--post-footer-grid-row-gap: 32px;
--post-footer-grid-column-gap: 16px;
--post-footer-grid-margin-block-end: 32px;
--post-footer-grid-padding-block-end: 32px;

--post-footer-post-list-flex-direction: row;
--post-footer-post-list-gap: 16px;
--post-footer-post-list-align-items: center;

--post-footer-meta-margin-block-end: 8px;
}

// tablet md
@include media.min(md) {
--post-footer-container-padding-inline: 40px;
}

// desktop lg
@include media.min(lg) {
--post-footer-container-padding-block: 56px;

--post-footer-grid-template: auto / repeat(4, auto);
--post-footer-grid-row-gap: 0;
--post-footer-grid-column-gap: 24px;
--post-footer-grid-margin-block-end: 40px;

--post-footer-column-flex-direction: row;
--post-footer-column-align-items: center;
--post-footer-column-gap: 32px;

--post-footer-post-list-gap: 24px;

--post-footer-businesssectors-margin-block-end: 24px;

--post-footer-meta-font-size: 16px;
}
}

.visually-hidden {
@include utilities.visuallyhidden();
}

.footer-container {
box-sizing: content-box;
margin: 0 auto;
padding: var(--post-footer-container-padding-block) var(--post-footer-container-padding-inline);
max-width: var(--post-footer-container-max-width);
}

.footer-grid {
display: grid;
grid-template: var(--post-footer-grid-template);
row-gap: var(--post-footer-grid-row-gap);
column-gap: var(--post-footer-grid-column-gap);
margin-block-end: var(--post-footer-grid-margin-block-end);
padding-block-end: var(--post-footer-grid-padding-block-end);

// post-accordion-item
::part(button),
::part(body) {
padding-inline: 0;
}
}

.footer-column {
display: flex;
flex-direction: var(--post-footer-column-flex-direction);
flex-wrap: wrap;
justify-content: space-between;
align-items: var(--post-footer-column-align-items);
column-gap: var(--post-footer-column-gap);
}

.footer-socialmedia,
.footer-app,
.footer-businesssectors,
.footer-meta {
::slotted(post-list) {
display: flex !important;
flex-direction: var(--post-footer-post-list-flex-direction) !important;
gap: var(--post-footer-post-list-gap) !important;
align-items: var(--post-footer-post-list-align-items) !important;
}
}

.footer-socialmedia {
margin-block-end: var(--post-footer-socialmedia-margin-block-end);
}

.footer-app {
margin-block-end: var(--post-footer-app-margin-block-end);
}

.footer-businesssectors {
margin-block-end: var(--post-footer-businesssectors-margin-block-end);
}

.footer-meta {
margin-block-end: var(--post-footer-meta-margin-block-end);
font-size: var(--post-footer-meta-font-size);
}

.footer-copyright {
display: flex;
flex-wrap: wrap;
column-gap: 0.5rem;
font-size: var(--post-footer-copyright-font-size);
}
Loading

0 comments on commit 14b4de9

Please sign in to comment.