@postnord/web-components
Version:
PostNord Web Components
231 lines (230 loc) • 8.51 kB
JavaScript
/*!
* Built with Stencil
* By PostNord.
*/
import { createDocumentation, createComponent } from "../../../globals/documentation/story";
import docs from "./pn-toast-docs.json";
import { getFigmaUrl } from "../../../globals/figmaLinks";
const { argTypes, textContent } = createDocumentation(docs);
/**
* The toast is intended to display a short piece of information to the user.
* These can be informal, positive, warnings and error related toasts.
**/
const meta = {
title: 'Components/Feedback/Toast',
parameters: {
layout: 'padded',
design: {
type: 'figma',
url: getFigmaUrl(import.meta.url),
},
actions: {
handles: ['close', 'hidden'],
},
},
args: {
heading: '',
text: 'A business account is required to access reports.',
toastId: '',
appearance: '',
icon: '',
temporary: false,
illustration: '',
closable: false,
hide: false,
language: '',
},
argTypes,
};
meta.argTypes.heading.if = { arg: 'text', truthy: true };
meta.argTypes.language.if = { arg: 'closable', eq: true };
meta.argTypes.icon.if = { arg: 'illustration', eq: '' };
meta.argTypes.illustration.if = { arg: 'icon', eq: '' };
export default meta;
export const PnToast = {
name: 'pn-toast',
render: args => createComponent('pn-toast', args),
parameters: {
docs: {
description: {
story: textContent,
},
},
},
};
/**
* A new feature for the `pn-toast` is built in `heading` and `text` props.
* This is to make it easier to align the toasts visual design and less markup for devs to create.
*
* You can still use the regular `slot` to include any HTML content you need just like before.
* It even works along side the heading and text content.
*
* You **must** have a `text` prop for the `heading` to show.
*/
export const PnToastText = {
name: 'pn-toast (text & heading)',
render: PnToast.render,
args: {
heading: 'Announcement',
text: 'New features are here in v18.1.0',
},
};
/**
* All appearances lined up! Rather self explanatory, but there are a few things to keep in mind.
*
* Its important to use the right appearance for the right type of information.
* All of the apperances uses the HTML `role="status"`, expect for `error` variant, that uses the `role="alert"`.
*
* The following example have some extra CSS added to transition the space between each toast a bit smoother.
*/
export const PnToastApperances = {
name: 'pn-toast (all appearances)',
render: (args, context) => {
const div = document.createElement('div');
document.querySelector('style').innerHTML += `
pn-button[label="Reset toasts"] {
margin-bottom: .5em;
}
pn-toast {
transition: margin-bottom 0.4s cubic-bezier(0.7, 0, 0.3, 1);
margin-bottom: 0.5em;
}
`;
const reset = createComponent('pn-button', { label: 'Reset toasts', small: true });
reset.addEventListener('pnClick', () => {
Array.from(div.querySelectorAll('pn-toast')).forEach(toast => {
toast.style.display = '';
requestAnimationFrame(() => {
toast.style.marginBottom = '';
toast.hide = false;
});
});
});
div.appendChild(reset);
const list = [
{ heading: 'Update', text: 'New features are available.', appearance: '' },
{ heading: 'Message sent', text: 'The message was saved and submitted.', appearance: 'success' },
{ heading: 'Warning', text: 'An invoice is about to expire.', appearance: 'warning' },
{ heading: 'API Error', text: 'Could not fetch contracts.', appearance: 'error' },
];
list.forEach(customArgs => {
const toast = PnToast.render({ ...args, ...customArgs }, context);
div.appendChild(toast);
});
div.addEventListener('close', event => {
event.target.style.marginBottom = '0em';
});
div.addEventListener('hidden', event => {
const target = event.target;
target.style.display = 'none';
});
return div;
},
args: {
closable: true,
},
};
/**
* The `temporary` prop adds a shadow and border to the toast.
* Often used for toasts that are layered on top of the page, such as a toast about "Saving done!" when you clicked saved or something similar.
**/
export const PnToastTemporary = {
name: 'pn-toast (temporary)',
render: PnToastApperances.render,
args: {
closable: true,
temporary: true,
},
};
/** Overwrite the default icon with your own. Works for all appearances. */
export const PnToastIcon = {
name: 'pn-toast (icon/flag)',
render: PnToast.render,
args: {
text: 'Deliveries to the Czech Republic are delayed.',
icon: 'cz_flag',
},
};
/** Use an illustration inside the toast. Cannot be combined with an icon. */
export const PnToastIllustration = {
name: 'pn-toast (illustration)',
render: PnToast.render,
args: {
heading: 'Reminder',
text: 'You have incoming parcels that need your attention.',
appearance: 'warning',
illustration: 'truck_packages_plant',
},
};
/**
* Allow the user to close the toast.
*
* A new feature compared to v6 and below, is that the toast will now collapse its height if inlined in content.
* Previously, you would have to either remove it entierly from the DOM or hide it will your own CSS.
* All you have to to now is to just set the `hide` prop to `true` in order to hide it.
*
* Use the `hidden` event to remove it from the DOM entirely. If you remove the toast when the `close` event triggers,
* you will not see the closing animation.
*/
export const PnToastClosable = {
name: 'pn-toast (closable)',
render: (args, context) => {
const div = document.createElement('div');
div.setAttribute('style', 'max-width: 15em; margin: 0 auto; display: flex; gap: .5em; flex-direction: column;');
const toast = PnToast.render(args, context);
const button = createComponent('pn-button', { label: 'Toggle toast', appearance: 'light', variant: 'outlined' });
button.addEventListener('pnClick', () => toast.toggleAttribute('hide'));
div.appendChild(button);
div.appendChild(toast);
return div;
},
args: {
heading: '',
text: 'Settings saved!',
appearance: 'success',
closable: true,
},
};
/**
* Here is an example using many of the features of the `pn-toast` at the same time.
*
* We use the heading and text prop. An illustration and additional HTML in the slot to create a CTA `pn-button`.
*/
export const PnToastExample = {
name: 'pn-toast (example)',
parameters: {
layout: 'padded',
},
render: (args, context) => {
const div = document.createElement('div');
div.setAttribute('style', 'max-width: 35em; margin: 0 auto; min-height: 20em');
const toast = PnToast.render(args, context);
const cta = createComponent('pn-text-link', {
label: 'Onboard today',
href: 'https://portal.postnord.com/onboard/',
small: true,
icon: 'open_in_new',
});
toast.appendChild(cta);
const button = createComponent('pn-button', { label: 'Toggle toast', appearance: 'light', variant: 'outlined' });
button.addEventListener('click', () => toast.toggleAttribute('hide'));
const createText = (txt) => {
const text = document.createElement('p');
text.setAttribute('style', 'margin: 1em 0');
text.innerText = txt;
return text;
};
div.appendChild(button);
div.appendChild(createText('Imagine this is a long line of text in an article. You read on and then in the middle, we have a CTA toast.'));
div.appendChild(toast);
div.appendChild(createText('Then, the article continues underneath it. More filler text for this example, just writing and writing.'));
return div;
},
args: {
closable: true,
heading: 'Portal Business',
text: 'Upgrade your account today!',
illustration: 'package_calendar',
},
};
//# sourceMappingURL=pn-toast.stories.js.map