This repository has been archived by the owner on Feb 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
202 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
<template> | ||
<div | ||
class="input-field group flex flex-row items-center gap-4 pe-4 hover:bg-dark-charcoal-06 h-12 border border-dark-charcoal-20 rounded-sm overflow-hidden focus-within:ring focus-within:ring-pink focus-within:border-white" | ||
:class="[ | ||
{ | ||
'border-s-0 rounded-s-none': connectionSides.includes('start'), | ||
'border-e-0 rounded-e-none': connectionSides.includes('end'), | ||
}, | ||
]" | ||
> | ||
<!-- eslint-disable vuejs-accessibility/form-control-has-label --> | ||
<!-- The `inputId` prop is provided so that the user of the component can associate a label --> | ||
<input | ||
v-bind="$attrs" | ||
:id="inputId" | ||
v-model="text" | ||
type="text" | ||
class="flex-grow leading-none font-semibold bg-tx ps-4 h-full focus:outline-none" | ||
/> | ||
<!-- eslint-enable vuejs-accessibility/form-control-has-label --> | ||
<div | ||
class="info font-semibold text-xs text-dark-charcoal-70 group-hover:text-dark-charcoal" | ||
> | ||
<!-- @slot Extra information goes here --> | ||
<slot /> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script> | ||
import { computed } from '@nuxtjs/composition-api' | ||
/** | ||
* Provides a control to enter text as input. | ||
*/ | ||
export default { | ||
name: 'InputField', | ||
inheritAttrs: false, | ||
model: { | ||
prop: 'value', | ||
event: 'input', | ||
}, | ||
props: { | ||
/** | ||
* the textual content of the input field | ||
*/ | ||
value: { | ||
type: String, | ||
default: '', | ||
}, | ||
/** | ||
* the ID to associate with the internal `<input>` element; This should be | ||
* used to associate a label and is recommended for a11y. | ||
*/ | ||
inputId: { | ||
type: String, | ||
}, | ||
/** | ||
* list of sides where the field is connected to other controls | ||
*/ | ||
connectionSides: { | ||
type: Array, | ||
default: () => [], | ||
validator: (val) => val.every((item) => ['start', 'end'].includes(item)), | ||
}, | ||
}, | ||
setup(props, { emit }) { | ||
const text = computed({ | ||
get() { | ||
return props.value | ||
}, | ||
set(value) { | ||
emit('input', value) | ||
}, | ||
}) | ||
return { | ||
text, | ||
} | ||
}, | ||
} | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
import { | ||
ArgsTable, | ||
Canvas, | ||
Description, | ||
Meta, | ||
Story, | ||
} from '@storybook/addon-docs' | ||
|
||
import InputField from '~/components/InputField/InputField.vue' | ||
|
||
<Meta | ||
title="Components/Input field" | ||
component={InputField} | ||
argTypes={{ | ||
input: { | ||
action: 'input', | ||
}, | ||
}} | ||
/> | ||
|
||
export const Template = (args, { argTypes }) => ({ | ||
template: ` | ||
<InputField v-bind="$props" v-on="$props"> | ||
Extra info | ||
</InputField> | ||
`, | ||
components: { InputField }, | ||
props: Object.keys(argTypes), | ||
}) | ||
|
||
# Input field | ||
|
||
<Description of={InputField} /> | ||
|
||
<ArgsTable of={InputField} /> | ||
|
||
The component emits an `input` event with the new contents of the field whenever | ||
the field receives an input. | ||
|
||
<Canvas> | ||
<Story | ||
name="Default" | ||
args={{ | ||
value: 'Text goes here', | ||
}} | ||
> | ||
{Template.bind({})} | ||
</Story> | ||
</Canvas> | ||
|
||
The recommended way to use it is with `v-model` mapping to a `String`. | ||
|
||
export const vModelTemplate = () => ({ | ||
template: ` | ||
<div> | ||
<InputField v-model="text"> | ||
{{ text.length }} | ||
</InputField> | ||
{{ text }} | ||
</div> | ||
`, | ||
components: { InputField }, | ||
data() { | ||
return { | ||
text: 'Hello, World!', | ||
} | ||
}, | ||
}) | ||
|
||
<Canvas> | ||
<Story name="v-model">{vModelTemplate.bind({})}</Story> | ||
</Canvas> | ||
|
||
The component is a transparent wrapper over `<input>` so all attributes of the | ||
input element can be applied to it, e.g. `placeholder`. It is recommended not to | ||
change the type as the field is specifically designed for text. | ||
|
||
<Canvas> | ||
<Story | ||
name="With placeholder" | ||
args={{ | ||
placeholder: 'Enter something here', | ||
}} | ||
> | ||
{Template.bind({})} | ||
</Story> | ||
</Canvas> | ||
|
||
For a11y, it is recommended that the input field be associated with a label. The | ||
approach for this is to set the `inputId` prop and use the ID as the `for` | ||
attribute of a `<label>` element. | ||
|
||
export const labelTemplate = () => ({ | ||
template: ` | ||
<div> | ||
<label for="field">Label:</label> | ||
<InputField input-id="field"/> | ||
</div> | ||
`, | ||
components: { InputField }, | ||
}) | ||
|
||
<Canvas> | ||
<Story name="With label">{labelTemplate.bind({})}</Story> | ||
</Canvas> | ||
|
||
The field can be conjoined with other controls on either the start or the end | ||
side and as such it provides the `connectionSides` prop to make the connections | ||
seamless. The field has no border or rounded corners on the connected sides. | ||
|
||
<Canvas> | ||
<Story | ||
name="With connections" | ||
args={{ | ||
connectionSides: ['start', 'end'], | ||
}} | ||
> | ||
{Template.bind({})} | ||
</Story> | ||
</Canvas> |