@postnord/web-components
Version:
PostNord Web Components
346 lines (345 loc) • 12 kB
JavaScript
/*!
* Built with Stencil
* By PostNord.
*/
import { createDocumentation, createComponent } from "../../../globals/documentation/story";
import docs from "./pn-input-docs.json";
import { getFigmaUrl } from "../../../globals/figmaLinks";
const { argTypes, textContent } = createDocumentation(docs);
/**
* The `pn-input` is a classic input component.
* It comes packaged with support for label, helpertext and validation style features.
*
* Most common attributes are included, such as placeholder, type, etc...
*/
const meta = {
title: 'Components/Input/Input',
parameters: {
actions: {
handles: ['input'],
},
design: {
type: 'figma',
url: getFigmaUrl(import.meta.url),
},
},
args: {
label: 'Username',
helpertext: '',
inputid: '',
value: '',
language: '',
icon: '',
textPrefix: '',
textSuffix: '',
type: '',
name: '',
placeholder: '',
autocomplete: '',
maxlength: null,
inputmode: null,
list: '',
pattern: '',
min: '',
max: '',
step: '',
arialabel: '',
ariacontrols: '',
disabled: false,
required: false,
readonly: false,
valid: false,
invalid: false,
error: '',
},
argTypes,
};
meta.argTypes.icon.if = { arg: 'textPrefix', eq: '' };
meta.argTypes.textPrefix.if = { arg: 'textSuffix', eq: '' };
meta.argTypes.textSuffix.if = { arg: 'textPrefix', eq: '' };
meta.argTypes.maxlength.type = 'number';
meta.argTypes.valid.if = { arg: 'invalid', eq: false };
meta.argTypes.invalid.if = { arg: 'valid', eq: false };
meta.argTypes.error.if = { arg: 'valid', eq: false };
export default meta;
export const PnInput = {
name: 'pn-input',
parameters: {
docs: {
description: {
story: textContent,
},
},
},
render: args => createComponent('pn-input', args),
};
/**
* We recommend that you always use the `label`, `name` and `type` props.
* This greatly improves user experience as it helps the browser to suggest values for the input.
*
*
*/
export const PnInputAttributes = {
name: 'pn-input (HTML attributes)',
render: PnInput.render,
args: {
label: 'First and last name',
value: 'John Doe',
inputid: 'pn-name',
name: 'first-last-name',
autocomplete: 'name full-name first-name last-name',
maxlength: 40,
required: true,
},
};
/** Provide a description for the input element. */
export const PnInputHelper = {
name: 'pn-input (helpertext)',
render: PnInput.render,
args: {
label: 'Adress',
helpertext: 'Remember to include house number.',
},
};
/**
* Provide a `placeholder` for the input element.
* The `placeholder` should hint the user of what the data should look like.
*
* <pn-toast
* heading="The placeholder is not a replacement for the label prop."
* text="The placeholder disappears as soon as the user enters any data, so put important information in the helpertext prop instead. Always use a label."
* appearance="warning"
* >
* </pn-toast>
**/
export const PnInputPlaceholder = {
name: 'pn-input (placeholder)',
render: PnInput.render,
args: {
label: 'Swedish personal number',
placeholder: 'YYYYMMDD-XXXX',
},
};
/**
* Use one of our icons or your own SVG content.
* Icons are eye candy and should not include text or any other type of information.
*
* If you need additional text to describe the input, use the `prefix` or `suffix` prop.
*
* <pn-toast appearance="warning">Use the icon property sparingly.</pn-toast>
**/
export const PnInputIcon = {
name: 'pn-input (icon)',
render: PnInput.render,
args: {
label: 'Credit card number',
name: 'credit-card',
icon: 'credit_card',
},
};
/**
* Use the `prefix` to add a piece of text infront of the input value.
*
* Cannot be used together with an `icon`.
**/
export const PnInputPrefix = {
name: 'pn-input (prefix)',
render: PnInput.render,
args: {
label: 'Total value',
value: '24',
textPrefix: '€',
},
};
/**
* Use the `suffix` to add a piece of text after the input value.
*
* Cannot be used together with type `search` or `password`.
**/
export const PnInputSuffix = {
name: 'pn-input (suffix)',
render: PnInput.render,
args: {
label: 'Freight weight',
value: '120',
textSuffix: 'kg',
},
};
const types = [
{ type: 'text', value: 'Text value', helpertext: 'The default text type input.' },
{
type: 'password',
value: 'HiddenPassword',
autocomplete: 'off',
helpertext: 'Turn the pn-input into a password field. The show/hide button is transalted in sv, en, da, fi and no. The language is changed automatically based on the topbar. Use the language prop to change manually.',
},
{ type: 'url', value: 'https://portal.postnord.com/se/en/', helpertext: 'Turn the field into a URL type' },
{ type: 'tel', value: '0760388344', helpertext: 'Use the pattern prop to set a constraint on the input.' },
{
type: 'search',
value: 'Search string',
helpertext: 'Turn the pn-input into a search field. When you have entered any value, the "clear" button will appear.',
},
{
type: 'number',
value: '24',
helpertext: 'You can use the pn-input for numbers. You can set step, min and max as well. Need more control? Use the pn-counter component.',
},
{ type: 'email', value: 'jon@arbuckle.com', autocomplete: 'email', helpertext: 'Accept an email value' },
];
/** Get a quick overview of all input types. */
export const PnInputTypes = {
name: 'pn-input (all types)',
render: args => {
const form = document.createElement('form');
form.className = 'sb-button-row';
form.style.flexDirection = 'column';
form.style.width = '20em';
form.style.alignItems = 'stretch';
types.forEach(({ type, value, helpertext, autocomplete = null }) => form.appendChild(createComponent('pn-input', { ...args, type, autocomplete, label: type, value, helpertext })));
return form;
},
};
/**
* Use the `datalist` element and associate the ID with the same ID supplied in the `list` prop.
*
* The dropdown list itself looks a bit different between browsers,
* but has overall support for all modern browsers (except for Firefox on Android).
*
* For the `list` prop to work, you must provide a `<datalist></datalist>` element somewhere in the DOM.
* The `datalist` element must have the same ID as you set in the `list` prop on the `pn-input`.
*
* Read more about how to use the list feature on <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist" target="_blank">MDN web docs</a>.
*/
export const PnInputList = {
name: 'pn-input (list)',
render: (args, context) => {
const div = document.createElement('div');
div.appendChild(PnInput.render(args, context));
div.innerHTML += `<datalist id="${args.list}">
<option value="stockholm">Stockholm</option>
<option value="gothenburg">Gothenburg</option>
<option value="malmo">Malmö</option>
<option value="uppsala">Uppsala</option>
<option value="halmstad">Halmstad</option>
</datalist>
`;
return div;
},
args: {
label: 'Select city',
value: '',
icon: 'search',
type: 'search',
name: 'city',
list: 'pn-list-example-id',
},
};
/** Set the `pn-input` as `valid`. Use this only if you have a validation feature in place, as to not confuse the user. */
export const PnInputValid = {
name: 'pn-input (valid)',
render: PnInput.render,
args: {
label: 'Postal code',
value: '561 39',
helpertext: 'With or out without "-"',
valid: true,
},
};
/**
* Setting the `error` prop/slot will automatically activate the `invalid` style.
* This message will hide the existing `helpertext`, if there is one. Removing the `error` will show the `helpertext` again.
**/
export const PnInputError = {
name: 'pn-input (error)',
render: PnInput.render,
args: {
label: 'Postal code',
helpertext: 'Enter a valid postal code.',
error: 'Invalid input.',
},
};
/**
* We recommend that you always use the `error` prop to trigger the invalid state and give an error message to the user.
* If you already provide the error message in a way that is tied to the input (with a fieldset for example), you may simply want
* to trigger the invalid state without an additional error message with the `invalid` prop.
*/
export const PnInputInvalid = {
name: 'pn-input (invalid)',
render: (args, context) => {
const input = PnInput.render(args, context);
const inputCity = createComponent('pn-input', {
label: 'Postal area',
value: 'Stockholm',
name: 'address.postal-city',
});
const inputStreet = createComponent('pn-input', {
label: 'Adress',
value: 'Terminalvägen 24',
name: 'adress.street',
});
const field = createComponent('pn-fieldset', { legend: 'User info', error: 'No postal code provided.' });
field.appendChild(inputStreet);
field.appendChild(input);
field.appendChild(inputCity);
const form = document.createElement('form');
form.appendChild(field);
return form;
},
args: {
label: 'Postal code',
invalid: true,
name: 'address.postal-code',
},
};
/**
* The **props** `helpertext` and `error` allows you to set the content with a string.
* This way does not allow you to include a link for example.
*
* With the **slots** `helpertext` and `error` you can include additional HTML. This way you keep the accessible markup
* as long as you stay with HTML text and links. Do not include buttons or other input elements in this slot.
**/
export const PnInputHelperSlot = {
name: 'pn-input (helper slot)',
render: (args, context) => {
const input = PnInput.render(args, context);
input.innerHTML += `<span slot="helpertext">Read more about <pn-text-link href="${location.href}">the format of personal IDs.</pn-text-link></span>`;
return input;
},
args: {
label: 'Personal ID',
},
};
/**
* The slots `helpertext` and `error` works the same as the props. If you set an `error` slot or prop, it will hide the `helpertext`.
*
* You can use both the slots and props along side each other.
**/
export const PnInputErrorSlot = {
name: 'pn-input (error slot)',
render: (args, context) => {
const input = PnInput.render(args, context);
const errorMessage = `Wrong format, <pn-text-link href="${location.href}">view personal ID format.</pn-text-link>`;
input.innerHTML += `<span slot="helpertext">Read more about <pn-text-link href="${location.href}">the format of personal ID.</pn-text-link></span>`;
input.innerHTML += `<span slot="error">${errorMessage}</span>`;
input.style.width = '18em';
const button = createComponent('pn-button', { label: 'Toggle Error' });
button.addEventListener('click', () => {
const errorElement = input.querySelector('[slot="error"]');
if (errorElement.innerText)
errorElement.innerHTML = '';
else
errorElement.innerHTML = errorMessage;
});
const div = document.createElement('div');
div.className = 'sb-button-row';
div.style.flexDirection = 'column';
div.appendChild(input);
div.appendChild(button);
return div;
},
args: {
label: 'Personal ID',
},
};
//# sourceMappingURL=pn-input.stories.js.map