Skip to content

Commit

Permalink
feat(components): add a heading-level property to the post-accordion (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
alizedebray authored May 15, 2024
1 parent ad02b5b commit c14c338
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 122 deletions.
7 changes: 7 additions & 0 deletions .changeset/large-pets-complain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@swisspost/design-system-components': minor
'@swisspost/design-system-components-angular': minor
'@swisspost/design-system-components-react': minor
---

Added a `heading-level` property on the `post-accordion` component to set the heading level of all `post-accordion-item` children at once.
14 changes: 12 additions & 2 deletions packages/components/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
* It contains typing information for all components that exist in this project.
*/
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
import { HeadingLevel } from "./components/post-accordion-item/heading-levels";
import { HeadingLevel } from "./types/index";
import { AlertType } from "./components/post-alert/alert-types";
import { Placement } from "@floating-ui/dom";
export { HeadingLevel } from "./components/post-accordion-item/heading-levels";
export { HeadingLevel } from "./types/index";
export { AlertType } from "./components/post-alert/alert-types";
export { Placement } from "@floating-ui/dom";
export namespace Components {
Expand All @@ -21,6 +21,10 @@ export namespace Components {
* Expands all `post-accordion-item`. If `multiple="true"` is not set and all items are closed, it will open the first one. Otherwise, it will keep the opened one.
*/
"expandAll": () => Promise<void>;
/**
* Defines the hierarchical level of the `post-accordion-item` headers within the headings structure.
*/
"headingLevel"?: HeadingLevel;
/**
* If `true`, multiple `post-accordion-item` can be open at the same time.
*/
Expand All @@ -37,6 +41,7 @@ export namespace Components {
"collapsed"?: boolean;
/**
* Defines the hierarchical level of the accordion item header within the headings structure.
* @deprecated set the `heading-level` property on the parent `post-accordion` instead.
*/
"headingLevel"?: HeadingLevel;
/**
Expand Down Expand Up @@ -498,6 +503,10 @@ declare global {
}
declare namespace LocalJSX {
interface PostAccordion {
/**
* Defines the hierarchical level of the `post-accordion-item` headers within the headings structure.
*/
"headingLevel"?: HeadingLevel;
/**
* If `true`, multiple `post-accordion-item` can be open at the same time.
*/
Expand All @@ -510,6 +519,7 @@ declare namespace LocalJSX {
"collapsed"?: boolean;
/**
* Defines the hierarchical level of the accordion item header within the headings structure.
* @deprecated set the `heading-level` property on the parent `post-accordion` instead.
*/
"headingLevel"?: HeadingLevel;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, Element, h, Host, Listen, Method, Prop, State, Watch } from '@stencil/core';
import { version } from '@root/package.json';
import { HEADING_LEVELS, HeadingLevel } from '@/types';
import { checkEmptyOrOneOf } from '@/utils';
import { HEADING_LEVELS, HeadingLevel } from './heading-levels';

/**
* @slot header - Slot for placing custom content within the accordion item's header.
Expand All @@ -28,6 +28,7 @@ export class PostAccordionItem {

/**
* Defines the hierarchical level of the accordion item header within the headings structure.
* @deprecated set the `heading-level` property on the parent `post-accordion` instead.
*/
@Prop() readonly headingLevel?: HeadingLevel = 2;

Expand All @@ -36,7 +37,7 @@ export class PostAccordionItem {
checkEmptyOrOneOf(
newValue,
HEADING_LEVELS,
'The `headingLevel` property of the `post-accordion-item` must be a number between 1 and 6.',
'The `heading-level` property of the `post-accordion-item` must be a number between 1 and 6.',
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

## Properties

| Property | Attribute | Description | Type | Default |
| -------------- | --------------- | ------------------------------------------------------------------------------------------ | ---------------------------- | ------- |
| `collapsed` | `collapsed` | If `true`, the element is initially collapsed otherwise it is displayed. | `boolean` | `false` |
| `headingLevel` | `heading-level` | Defines the hierarchical level of the accordion item header within the headings structure. | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `2` |
| Property | Attribute | Description | Type | Default |
| -------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | ------- |
| `collapsed` | `collapsed` | If `true`, the element is initially collapsed otherwise it is displayed. | `boolean` | `false` |
| `headingLevel` | `heading-level` | <span style="color:red">**[DEPRECATED]**</span> set the `heading-level` property on the parent `post-accordion` instead.<br/><br/>Defines the hierarchical level of the accordion item header within the headings structure. | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `2` |


## Methods
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Component, Element, h, Host, Listen, Method, Prop } from '@stencil/core';
import { Component, Element, h, Host, Listen, Method, Prop, Watch } from '@stencil/core';
import { version } from '@root/package.json';
import { HEADING_LEVELS, HeadingLevel } from '@/types';
import { checkOneOf } from '@/utils';

/**
* @slot default - Slot for placing post-accordion-item components.
Expand All @@ -16,13 +18,34 @@ export class PostAccordion {

@Element() host: HTMLPostAccordionElement;

/**
* Defines the hierarchical level of the `post-accordion-item` headers within the headings structure.
*/
@Prop() readonly headingLevel?: HeadingLevel;

@Watch('headingLevel')
validateHeadingLevel(newValue = this.headingLevel) {
if (!newValue) return;

checkOneOf(
newValue,
HEADING_LEVELS,
'The `heading-level` property of the `post-accordion` must be a number between 1 and 6.',
);

this.accordionItems.forEach(item => {
item.setAttribute('heading-level', String(newValue));
});
}

/**
* If `true`, multiple `post-accordion-item` can be open at the same time.
*/
@Prop() readonly multiple: boolean = false;

componentWillLoad() {
this.registerAccordionItems();
this.validateHeadingLevel();
}

@Listen('postToggle')
Expand Down
7 changes: 4 additions & 3 deletions packages/components/src/components/post-accordion/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@

## Properties

| Property | Attribute | Description | Type | Default |
| ---------- | ---------- | ----------------------------------------------------------------------- | --------- | ------- |
| `multiple` | `multiple` | If `true`, multiple `post-accordion-item` can be open at the same time. | `boolean` | `false` |
| Property | Attribute | Description | Type | Default |
| -------------- | --------------- | -------------------------------------------------------------------------------------------------- | ---------------------------- | ----------- |
| `headingLevel` | `heading-level` | Defines the hierarchical level of the `post-accordion-item` headers within the headings structure. | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `undefined` |
| `multiple` | `multiple` | If `true`, multiple `post-accordion-item` can be open at the same time. | `boolean` | `false` |


## Methods
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/types/heading-levels.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const HEADING_LEVELS = [1, 2, 3, 4, 5, 6] as const;

export type HeadingLevel = typeof HEADING_LEVELS[number];
1 change: 1 addition & 0 deletions packages/components/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './heading-levels';
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import {
defineCustomElements as defineComponents,
} from '@swisspost/design-system-components/loader';
import { setStencilDocJson } from '@pxtrn/storybook-addon-docs-stencil';
import {
StencilJsonDocs,
StencilJsonDocsComponent,
} from '@pxtrn/storybook-addon-docs-stencil/dist/types';
import { StencilJsonDocs } from '@pxtrn/storybook-addon-docs-stencil/dist/types';
import postComponentsDocJson from '@swisspost/design-system-components/dist/docs.json';
import internetHeaderDocJson from '@swisspost/internet-header/dist/docs.json';
import '../../src/shared/link-design/link-design.component';
Expand All @@ -24,14 +21,25 @@ componentsPolyfills().then(() => {
});

if (postComponentsDocJson && internetHeaderDocJson) {
const jsonDocs: StencilJsonDocs = {
timestamp: postComponentsDocJson.timestamp,
compiler: postComponentsDocJson.compiler,
components: [
...postComponentsDocJson.components,
...internetHeaderDocJson.components,
] as StencilJsonDocsComponent[],
let { components, ...docJsonMetaData } = postComponentsDocJson as unknown as StencilJsonDocs;

// add the internet header components to the post component list
components = components.concat((internetHeaderDocJson as StencilJsonDocs).components);

// parse the component properties to show a deprecation message necessary
components.forEach(component => {
component.props.forEach(prop => {
if (prop.deprecation) {
const deprecationAlert = `<span className="mb-micro alert alert-warning alert-sm">**Deprecated:** ${prop.deprecation}</span>`;
prop.docs = `${prop.deprecation ? deprecationAlert : ''}${prop.docs}`;
}
});
});

const stencilJsonDocs: StencilJsonDocs = {
...docJsonMetaData,
components: components,
};

setStencilDocJson(jsonDocs);
setStencilDocJson(stencilJsonDocs);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,20 @@ const meta: Meta = {
id: '3b86bc9b-3dcd-4788-a436-88fd18a6312d',
title: 'Components/Accordion Item',
component: 'post-accordion-item',
parameters: {
controls: {
exclude: [
'accordion-item', // this CSS part is for internal use only
],
},
},
argTypes: {
collapsed: {
control: false,
control: false, // disable the control since it is not usable on the story
},
headingLevel: {
control: false,
name: 'heading-level',
control: false, // disable the control since it is not usable on the story
},
},
};
Expand All @@ -19,10 +27,4 @@ export default meta;
// STORIES
type Story = StoryObj;

export const Default: Story = {
parameters: {
controls: {
exclude: ['accordion-item'],
},
},
};
export const Default: Story = {};
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ or if the accordion is configured with the `multiple="true"` property, all other

<Canvas of={accordionStories.DefaultCollapsedPanels} />

### Heading Levels

To ensure accessibility, all accordion titles are contained within heading tags (`h1`-`h6`) behind the scenes.
It is essential to set the appropriate `heading-level` property on the `post-accordion` so that it matches the structure of your page properly.

<Canvas of={accordionStories.Nested} />

### Custom Trigger

The `<post-accordion>` offers several methods to expand or collapse the `<post-accordion-item>` it contains.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { StoryContext, StoryObj } from '@storybook/web-components';
import meta, { Default } from './accordion.stories';
import meta from './accordion.stories';
import { html } from 'lit';

const { id, ...metaWithoutId } = meta;
Expand All @@ -9,16 +9,19 @@ export default {
title: 'Snapshots',
};

type Story = StoryObj<HTMLPostAccordionElement>;
type Story = StoryObj<HTMLPostAccordionElement & HTMLPostCollapsibleElementEventMap>;

export const Accordion: Story = {
render: (_args: HTMLPostAccordionElement, context: StoryContext<HTMLPostAccordionElement>) => {
render: (
_args: HTMLPostAccordionElement,
context: StoryContext<HTMLPostAccordionElement & HTMLPostCollapsibleElementEventMap>,
) => {
return html`
<div>
${['bg-white', 'bg-light', 'bg-dark'].map(
bg => html`
<div class="${bg} d-flex flex-column gap-regular p-regular mt-regular">
${Default.render?.({ ...context.args }, context)}
${meta.render?.({ ...context.args }, context)}
</div>
`,
)}
Expand Down
Loading

0 comments on commit c14c338

Please sign in to comment.