From e786e0e78fcc77694301bc48ac570ef97fb5005d Mon Sep 17 00:00:00 2001 From: Eric Liu Date: Sun, 15 Dec 2019 15:25:48 -0800 Subject: [PATCH] feat(components): add TextInput --- README.md | 25 ++-- src/components/TextInput/PasswordInput.svelte | 112 ++++++++++++++++++ .../TextInput/TextInput.Skeleton.svelte | 17 +++ .../TextInput/TextInput.Story.svelte | 42 +++++++ src/components/TextInput/TextInput.stories.js | 89 ++++++++++++++ src/components/TextInput/TextInput.svelte | 79 ++++++++++++ src/components/TextInput/index.js | 5 + src/index.js | 4 + 8 files changed, 362 insertions(+), 11 deletions(-) create mode 100644 src/components/TextInput/PasswordInput.svelte create mode 100644 src/components/TextInput/TextInput.Skeleton.svelte create mode 100644 src/components/TextInput/TextInput.Story.svelte create mode 100644 src/components/TextInput/TextInput.stories.js create mode 100644 src/components/TextInput/TextInput.svelte create mode 100644 src/components/TextInput/index.js diff --git a/README.md b/README.md index 45923d6b..f721b6f8 100644 --- a/README.md +++ b/README.md @@ -18,16 +18,16 @@ Currently, the following components are supported: - Accordion - AccordionItem -- AccordionSkeleton + - AccordionSkeleton - Breadcrumb - BreadcrumbItem -- BreadcrumbSkeleton + - BreadcrumbSkeleton - Button -- ButtonSkeleton + - ButtonSkeleton - Checkbox -- CheckboxSkeleton + - CheckboxSkeleton - CodeSnippet -- CodeSnippetSkeleton + - CodeSnippetSkeleton - Copy - CopyButton - InlineLoading @@ -36,19 +36,22 @@ Currently, the following components are supported: - ListItem - OrderedList - RadioButton -- RadioButtonSkeleton + - RadioButtonSkeleton - Search -- SearchSkeleton + - SearchSkeleton - SkeletonPlaceholder - SkeletonText - Tag -- TagSkeleton + - TagSkeleton - TextArea -- TextAreaSkeleton + - TextAreaSkeleton +- TextInput + - TextInputSkeleton + - PasswordInput - Toggle -- ToggleSkeleton + - ToggleSkeleton - ToggleSmall -- ToggleSmallSkeleton + - ToggleSmallSkeleton - TooltipDefinition - TooltipIcon - UnorderedList diff --git a/src/components/TextInput/PasswordInput.svelte b/src/components/TextInput/PasswordInput.svelte new file mode 100644 index 00000000..d6b76eb3 --- /dev/null +++ b/src/components/TextInput/PasswordInput.svelte @@ -0,0 +1,112 @@ + + +
+ {#if labelText} + + {/if} + + {#if helperText} +
{helperText}
+ {/if} +
+ {#if invalid} + + {/if} + { + if (!disabled) { + dispatch('click', event); + } + }} + on:change={event => { + if (!disabled) { + dispatch('change', event); + } + }} + on:input={event => { + value = event.target.value; + if (!disabled) { + dispatch('input', event); + } + }} + data-invalid={invalid || undefined} + aria-invalid={invalid || undefined} + aria-describedby={invalid ? errorId : undefined} + {id} + {placeholder} + {type} + {value} + {disabled} /> + +
+ {#if invalid} +
{invalidText}
+ {/if} +
diff --git a/src/components/TextInput/TextInput.Skeleton.svelte b/src/components/TextInput/TextInput.Skeleton.svelte new file mode 100644 index 00000000..d1229907 --- /dev/null +++ b/src/components/TextInput/TextInput.Skeleton.svelte @@ -0,0 +1,17 @@ + + +
+ {#if !hideLabel} + + {/if} +
+
diff --git a/src/components/TextInput/TextInput.Story.svelte b/src/components/TextInput/TextInput.Story.svelte new file mode 100644 index 00000000..11eaae77 --- /dev/null +++ b/src/components/TextInput/TextInput.Story.svelte @@ -0,0 +1,42 @@ + + + + {value} + {#if story === 'skeleton'} +
+ +
+ +
+ {:else if story === 'password-visibility'} + + {:else if story === 'controlled'} + +
+ + +
+ {:else} + + {/if} +
diff --git a/src/components/TextInput/TextInput.stories.js b/src/components/TextInput/TextInput.stories.js new file mode 100644 index 00000000..8d843bbe --- /dev/null +++ b/src/components/TextInput/TextInput.stories.js @@ -0,0 +1,89 @@ +import { withKnobs, boolean, text, select } from '@storybook/addon-knobs'; +import Component from './TextInput.Story.svelte'; + +export default { title: 'TextInput', decorators: [withKnobs] }; + +export const Default = () => ({ + Component, + props: { + disabled: boolean('Disabled (disabled)', false), + light: boolean('Light variant (light)', false), + hideLabel: boolean('No label (hideLabel)', false), + labelText: text('Label text (labelText)', 'Text Input label'), + invalid: boolean('Show form validation UI (invalid)', false), + invalidText: text('Content of form validation UI (invalidText)', 'A valid value is required'), + helperText: text('Helper text (helperText)', 'Optional helper text.'), + placeholder: text('Placeholder text (placeholder)', 'Placeholder text.'), + id: 'text-input' + } +}); + +export const TogglePasswordVisibility = () => ({ + Component, + props: { + story: 'password-visibility', + disabled: boolean('Disabled (disabled)', false), + light: boolean('Light variant (light)', false), + hideLabel: boolean('No label (hideLabel)', false), + labelText: text('Label text (labelText)', 'Text Input label'), + invalid: boolean('Show form validation UI (invalid)', false), + invalidText: text('Content of form validation UI (invalidText)', 'A valid value is required'), + helperText: text('Helper text (helperText)', 'Optional helper text.'), + placeholder: text('Placeholder text (placeholder)', 'Placeholder text.'), + id: 'text-input', + tooltipPosition: select( + 'Tooltip position (tooltipPosition)', + ['top', 'right', 'bottom', 'left'], + 'bottom' + ), + tooltipAlignment: select( + 'Tooltip alignment (tooltipAlignment)', + ['start', 'center', 'end'], + 'center' + ), + hidePasswordLabel: text( + '"Hide password" tooltip label for password visibility toggle (hidePasswordLabel)', + 'Hide password' + ), + showPasswordLabel: text( + '"Show password" tooltip label for password visibility toggle (showPasswordLabel)', + 'Show password' + ) + } +}); + +export const ControlledTogglePasswordVisibility = () => ({ + Component, + props: { + story: 'controlled', + disabled: boolean('Disabled (disabled)', false), + light: boolean('Light variant (light)', false), + hideLabel: boolean('No label (hideLabel)', false), + labelText: text('Label text (labelText)', 'Text Input label'), + invalid: boolean('Show form validation UI (invalid)', false), + invalidText: text('Content of form validation UI (invalidText)', 'A valid value is required'), + helperText: text('Helper text (helperText)', 'Optional helper text.'), + placeholder: text('Placeholder text (placeholder)', 'Placeholder text.'), + id: 'text-input', + tooltipPosition: select( + 'Tooltip position (tooltipPosition)', + ['top', 'right', 'bottom', 'left'], + 'bottom' + ), + tooltipAlignment: select( + 'Tooltip alignment (tooltipAlignment)', + ['start', 'center', 'end'], + 'center' + ), + hidePasswordLabel: text( + '"Hide password" tooltip label for password visibility toggle (hidePasswordLabel)', + 'Hide password' + ), + showPasswordLabel: text( + '"Show password" tooltip label for password visibility toggle (showPasswordLabel)', + 'Show password' + ) + } +}); + +export const Skeleton = () => ({ Component, props: { story: 'skeleton' } }); diff --git a/src/components/TextInput/TextInput.svelte b/src/components/TextInput/TextInput.svelte new file mode 100644 index 00000000..b1db81e7 --- /dev/null +++ b/src/components/TextInput/TextInput.svelte @@ -0,0 +1,79 @@ + + +
+ {#if labelText} + + {/if} + {#if helperText} +
{helperText}
+ {/if} +
+ {#if invalid} + + {/if} + { + if (!disabled) { + dispatch('click', event); + } + }} + on:change={event => { + if (!disabled) { + dispatch('change', event); + } + }} + on:input={event => { + value = event.target.value; + if (!disabled) { + dispatch('input', event); + } + }} + data-invalid={invalid || undefined} + aria-invalid={invalid || undefined} + aria-describedby={invalid ? errorId : undefined} + {id} + {placeholder} + {type} + {value} + {disabled} /> +
+ {#if invalid} +
{invalidText}
+ {/if} +
diff --git a/src/components/TextInput/index.js b/src/components/TextInput/index.js new file mode 100644 index 00000000..d9d66545 --- /dev/null +++ b/src/components/TextInput/index.js @@ -0,0 +1,5 @@ +import TextInput from './TextInput.svelte'; + +export default TextInput; +export { default as TextInputSkeleton } from './TextInput.Skeleton.svelte'; +export { default as PasswordInput } from './PasswordInput.svelte'; diff --git a/src/index.js b/src/index.js index 9e613179..9134d5c6 100644 --- a/src/index.js +++ b/src/index.js @@ -16,6 +16,7 @@ import SkeletonPlaceholder from './components/SkeletonPlaceholder'; import SkeletonText from './components/SkeletonText'; import Tag, { TagSkeleton } from './components/Tag'; import TextArea, { TextAreaSkeleton } from './components/TextArea'; +import TextInput, { TextInputSkeleton, PasswordInput } from './components/TextInput'; import Toggle, { ToggleSkeleton } from './components/Toggle'; import ToggleSmall, { ToggleSmallSkeleton } from './components/ToggleSmall'; import TooltipDefinition from './components/TooltipDefinition'; @@ -52,6 +53,9 @@ export { TagSkeleton, TextArea, TextAreaSkeleton, + TextInput, + TextInputSkeleton, + PasswordInput, Toggle, ToggleSkeleton, ToggleSmall,