refactor(ui): add color and `reset` props to Input component
This commit is contained in:
parent
ee22e02617
commit
6e69a74b75
|
@ -2,13 +2,12 @@
|
|||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import onKeyboardShortcut from '~/composables/onKeyboardShortcut';
|
||||
import { color } from "~/composables/color.ts";
|
||||
import { type ColorProps, type VariantProps, type DefaultProps, type RaisedProps, type PastelProps, color } from "~/composables/color.ts";
|
||||
|
||||
import Button from "~/components/ui/Button.vue"
|
||||
import Layout from "~/components/ui/Layout.vue"
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
const { icon, placeholder, ...props } = defineProps<{
|
||||
icon?: string;
|
||||
placeholder?: string;
|
||||
password?: true;
|
||||
|
@ -16,14 +15,10 @@ const props = withDefaults(
|
|||
numeric?: true;
|
||||
label?: string;
|
||||
autofocus?: boolean;
|
||||
raised?: boolean;
|
||||
}>(),
|
||||
{
|
||||
raised: false, // Default value
|
||||
}
|
||||
);
|
||||
|
||||
const { icon, placeholder, ...restProps } = props;
|
||||
reset?: () => void;
|
||||
} & (ColorProps | DefaultProps | PastelProps )
|
||||
& VariantProps
|
||||
& RaisedProps>()
|
||||
|
||||
// TODO(A11y): Add `inputmode="numeric" pattern="[0-9]*"` to input if model type is number:
|
||||
// https://technology.blog.gov.uk/2020/02/24/why-the-gov-uk-design-system-team-changed-the-input-type-for-numbers/
|
||||
|
@ -37,9 +32,9 @@ onKeyboardShortcut('escape', () => showPassword.value = false)
|
|||
// TODO: Implement `copy password` button?
|
||||
|
||||
const attributes = computed(() => ({
|
||||
...(restProps.password && !showPassword.value? {type: 'password'} : {}),
|
||||
...(restProps.search? {type: 'search'} : {}),
|
||||
...(restProps.numeric? {type: 'numeric'} : {}),
|
||||
...(props.password && !showPassword.value? {type: 'password'} : {}),
|
||||
...(props.search? {type: 'search'} : {}),
|
||||
...(props.numeric? {type: 'numeric'} : {}),
|
||||
}))
|
||||
|
||||
const { t } = useI18n()
|
||||
|
@ -47,10 +42,10 @@ const { t } = useI18n()
|
|||
const input = ref()
|
||||
|
||||
onMounted(() => {
|
||||
if (restProps.autofocus) input.value.focus();
|
||||
if (props.autofocus) input.value.focus();
|
||||
})
|
||||
|
||||
const model = defineModel<string|number>()
|
||||
const model = defineModel<string|number>({ required: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -62,8 +57,8 @@ const model = defineModel<string|number>()
|
|||
<slot name="label" />
|
||||
</span>
|
||||
|
||||
<span v-if="restProps.label" class="label">
|
||||
{{ restProps.label }}
|
||||
<span v-if="props.label" class="label">
|
||||
{{ props.label }}
|
||||
</span>
|
||||
|
||||
<input
|
||||
|
@ -82,7 +77,7 @@ const model = defineModel<string|number>()
|
|||
</div>
|
||||
|
||||
<!-- Search -->
|
||||
<div v-if="restProps.search" class="prefix">
|
||||
<div v-if="props.search" class="prefix">
|
||||
<i class="bi bi-search" />
|
||||
</div>
|
||||
|
||||
|
@ -96,7 +91,7 @@ const model = defineModel<string|number>()
|
|||
|
||||
<!-- Password -->
|
||||
<button
|
||||
v-if="restProps.password"
|
||||
v-if="props.password"
|
||||
style="background:transparent; border:none; appearance:none;"
|
||||
role="switch"
|
||||
type="button"
|
||||
|
@ -110,12 +105,22 @@ const model = defineModel<string|number>()
|
|||
<!-- Search -->
|
||||
<Button
|
||||
solid primary
|
||||
type="submit"
|
||||
v-if="restProps.search"
|
||||
v-if="props.search"
|
||||
class="input-right search"
|
||||
>
|
||||
{{ t('components.Sidebar.link.search') }}
|
||||
</Button>
|
||||
|
||||
<!-- Reset -->
|
||||
|
||||
<Button
|
||||
ghost primary square-small
|
||||
v-if="props.reset"
|
||||
icon="bi-arrow-counterclockwise"
|
||||
class="input-right reset"
|
||||
:onClick="reset"
|
||||
:title="t('components.library.EditForm.button.reset')"
|
||||
/>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -102,17 +102,23 @@
|
|||
border-bottom-left-radius: 0;
|
||||
}
|
||||
}
|
||||
&:has(>.search)>input {
|
||||
padding-right: 140px;
|
||||
}
|
||||
|
||||
> .show-password {
|
||||
justify-content:center;
|
||||
}
|
||||
|
||||
&:has(>.show-password)>input {
|
||||
padding-right: 40px;
|
||||
}
|
||||
|
||||
&:has(>.search)>input {
|
||||
padding-right: 140px;
|
||||
>.reset {
|
||||
min-width: auto;
|
||||
margin: 4px;
|
||||
|
||||
// Make button fit snuggly into rounded border
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,16 +7,21 @@ import Layout from "~/components/ui/Layout.vue"
|
|||
import Spacer from "~/components/ui/Spacer.vue"
|
||||
import Alert from "~/components/ui/Alert.vue"
|
||||
|
||||
const value = ref("Value")
|
||||
const value = ref("Preset Value")
|
||||
const search = ref("")
|
||||
const user = ref("")
|
||||
const password = ref("")
|
||||
|
||||
const reset = () => { console.log("Hello"); value.value = 'Original value' }
|
||||
</script>
|
||||
|
||||
```ts
|
||||
import Input from "~/components/ui/Input.vue"
|
||||
import Input from "~/components/ui/Input.vue";
|
||||
```
|
||||
|
||||
# Input
|
||||
|
||||
Inputs are areas in which users can enter information. In Funkwhale, these mostly take the form of search fields.
|
||||
Inputs are areas in which users can enter a single-line text or a number. Several [presets](#presets) are available.
|
||||
|
||||
| Prop | Data type | Required? | Description |
|
||||
| ------------- | --------- | --------- | --------------------------------------------------------------------------- |
|
||||
|
@ -24,13 +29,17 @@ Inputs are areas in which users can enter information. In Funkwhale, these mostl
|
|||
| `icon` | String | No | The [Bootstrap icon](https://icons.getbootstrap.com/) to show on the input. |
|
||||
| `v-model` | String | Yes | The text entered in the input. |
|
||||
|
||||
You can link a user's input to form data by referencing the data in a `v-model` directive.
|
||||
Link a user's input to form data by referencing the data in a `v-model` of type `string`.
|
||||
|
||||
```ts
|
||||
const value = ref("Preset Value");
|
||||
```
|
||||
|
||||
```vue-html{2}
|
||||
<Input v-model="value" placeholder="Your favorite animal" />
|
||||
```
|
||||
|
||||
<Input placeholder="Your favorite animal" />
|
||||
<Input v-model="value" placeholder="Your favorite animal" />
|
||||
|
||||
## Input icons
|
||||
|
||||
|
@ -45,14 +54,14 @@ Add a [Bootstrap icon](https://icons.getbootstrap.com/) to an input to make its
|
|||
## Label slot
|
||||
|
||||
```vue-html{2-4}
|
||||
<Input>
|
||||
<Input v-model="user">
|
||||
<template #label>
|
||||
User name
|
||||
</template>
|
||||
</Input>
|
||||
```
|
||||
|
||||
<Input>
|
||||
<Input v-model="user">
|
||||
<template #label>
|
||||
User name
|
||||
</template>
|
||||
|
@ -61,10 +70,10 @@ Add a [Bootstrap icon](https://icons.getbootstrap.com/) to an input to make its
|
|||
If you just have a string, we have a convenience prop, so instead you can write:
|
||||
|
||||
```vue-html
|
||||
<Input label="User name" />
|
||||
<Input v-model="user" label="User name" />
|
||||
```
|
||||
|
||||
<Input label="User name" />
|
||||
<Input v-model="user" label="User name" />
|
||||
|
||||
## Input-right slot
|
||||
|
||||
|
@ -78,29 +87,33 @@ You can add a template on the right-hand side of the input to guide the user's i
|
|||
</Input>
|
||||
```
|
||||
|
||||
<Input placeholder="Search">
|
||||
<Input v-model="search" placeholder="Search">
|
||||
<template #input-right>
|
||||
suffix
|
||||
</template>
|
||||
</Input>
|
||||
|
||||
## Color
|
||||
|
||||
See [Button](./button.md#button-colors) for a detailed overview of available props.
|
||||
|
||||
## Presets
|
||||
|
||||
### Search
|
||||
|
||||
```vue-html
|
||||
<Input search />
|
||||
<Input search v-model="search" />
|
||||
```
|
||||
|
||||
<Input search />
|
||||
<Input search v-model="search" />
|
||||
|
||||
### Password
|
||||
|
||||
```vue-html
|
||||
<Spacer :size="64" />
|
||||
<Layout form stack>
|
||||
<Input label="User name" />
|
||||
<Input password label="Password" />
|
||||
<Input v-model="user" label="User name" />
|
||||
<Input password v-model="password" label="Password" />
|
||||
<Layout flex>
|
||||
<Button primary> Submit </Button>
|
||||
<Button> Cancel </Button>
|
||||
|
@ -110,8 +123,8 @@ You can add a template on the right-hand side of the input to guide the user's i
|
|||
|
||||
<Spacer :size="64" />
|
||||
<Layout form stack>
|
||||
<Input label="User name" />
|
||||
<Input password label="Password" />
|
||||
<Input v-model="user" label="User name" />
|
||||
<Input password v-model="password" label="Password" />
|
||||
<Layout flex>
|
||||
<Button primary> Submit </Button>
|
||||
<Button> Cancel </Button>
|
||||
|
@ -124,28 +137,30 @@ We use the spacer to simulate the baseline alignment on page layouts (64px betwe
|
|||
|
||||
:::
|
||||
|
||||
## Value
|
||||
### Add a reset option
|
||||
|
||||
```vue-html
|
||||
<Input v-model="value"/>
|
||||
<Input v-model="value"/>
|
||||
<Input
|
||||
v-model="value"
|
||||
:reset="() => { value = 'Original value' }">
|
||||
</Input>
|
||||
```
|
||||
|
||||
<Layout flex>
|
||||
<Input auto v-model="value"/>
|
||||
<Input auto v-model="value"/>
|
||||
</Layout>
|
||||
<Input
|
||||
v-model="value"
|
||||
:reset="() => { value = 'Original value' }">
|
||||
</Input>
|
||||
|
||||
## Fallthrough attributes
|
||||
|
||||
If you add attributes that are no props, they will be added to the component:
|
||||
|
||||
```vue-html
|
||||
<Input required
|
||||
<Input v-model="password" required
|
||||
field-id="password-field"
|
||||
/>
|
||||
```
|
||||
|
||||
<Input required
|
||||
<Input v-model="password" required
|
||||
field-id="password-field"
|
||||
/>
|
||||
|
|
Loading…
Reference in New Issue