UNPKG

@postnord/web-components

Version:

PostNord Web Components

231 lines (230 loc) 8.51 kB
/*! * 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