kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
refactor(ui): add color and `reset` props to Input component
rodzic
ee22e02617
commit
6e69a74b75
|
@ -2,13 +2,12 @@
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import onKeyboardShortcut from '~/composables/onKeyboardShortcut';
|
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 Button from "~/components/ui/Button.vue"
|
||||||
import Layout from "~/components/ui/Layout.vue"
|
import Layout from "~/components/ui/Layout.vue"
|
||||||
|
|
||||||
const props = withDefaults(
|
const { icon, placeholder, ...props } = defineProps<{
|
||||||
defineProps<{
|
|
||||||
icon?: string;
|
icon?: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
password?: true;
|
password?: true;
|
||||||
|
@ -16,14 +15,10 @@ const props = withDefaults(
|
||||||
numeric?: true;
|
numeric?: true;
|
||||||
label?: string;
|
label?: string;
|
||||||
autofocus?: boolean;
|
autofocus?: boolean;
|
||||||
raised?: boolean;
|
reset?: () => void;
|
||||||
}>(),
|
} & (ColorProps | DefaultProps | PastelProps )
|
||||||
{
|
& VariantProps
|
||||||
raised: false, // Default value
|
& RaisedProps>()
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const { icon, placeholder, ...restProps } = props;
|
|
||||||
|
|
||||||
// TODO(A11y): Add `inputmode="numeric" pattern="[0-9]*"` to input if model type is number:
|
// 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/
|
// 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?
|
// TODO: Implement `copy password` button?
|
||||||
|
|
||||||
const attributes = computed(() => ({
|
const attributes = computed(() => ({
|
||||||
...(restProps.password && !showPassword.value? {type: 'password'} : {}),
|
...(props.password && !showPassword.value? {type: 'password'} : {}),
|
||||||
...(restProps.search? {type: 'search'} : {}),
|
...(props.search? {type: 'search'} : {}),
|
||||||
...(restProps.numeric? {type: 'numeric'} : {}),
|
...(props.numeric? {type: 'numeric'} : {}),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
@ -47,10 +42,10 @@ const { t } = useI18n()
|
||||||
const input = ref()
|
const input = ref()
|
||||||
|
|
||||||
onMounted(() => {
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -62,8 +57,8 @@ const model = defineModel<string|number>()
|
||||||
<slot name="label" />
|
<slot name="label" />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span v-if="restProps.label" class="label">
|
<span v-if="props.label" class="label">
|
||||||
{{ restProps.label }}
|
{{ props.label }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
|
@ -82,7 +77,7 @@ const model = defineModel<string|number>()
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Search -->
|
<!-- Search -->
|
||||||
<div v-if="restProps.search" class="prefix">
|
<div v-if="props.search" class="prefix">
|
||||||
<i class="bi bi-search" />
|
<i class="bi bi-search" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -96,7 +91,7 @@ const model = defineModel<string|number>()
|
||||||
|
|
||||||
<!-- Password -->
|
<!-- Password -->
|
||||||
<button
|
<button
|
||||||
v-if="restProps.password"
|
v-if="props.password"
|
||||||
style="background:transparent; border:none; appearance:none;"
|
style="background:transparent; border:none; appearance:none;"
|
||||||
role="switch"
|
role="switch"
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -110,12 +105,22 @@ const model = defineModel<string|number>()
|
||||||
<!-- Search -->
|
<!-- Search -->
|
||||||
<Button
|
<Button
|
||||||
solid primary
|
solid primary
|
||||||
type="submit"
|
v-if="props.search"
|
||||||
v-if="restProps.search"
|
|
||||||
class="input-right search"
|
class="input-right search"
|
||||||
>
|
>
|
||||||
{{ t('components.Sidebar.link.search') }}
|
{{ t('components.Sidebar.link.search') }}
|
||||||
</Button>
|
</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>
|
</Layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -102,17 +102,23 @@
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&:has(>.search)>input {
|
||||||
|
padding-right: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
> .show-password {
|
> .show-password {
|
||||||
justify-content:center;
|
justify-content:center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:has(>.show-password)>input {
|
&:has(>.show-password)>input {
|
||||||
padding-right: 40px;
|
padding-right: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:has(>.search)>input {
|
>.reset {
|
||||||
padding-right: 140px;
|
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 Spacer from "~/components/ui/Spacer.vue"
|
||||||
import Alert from "~/components/ui/Alert.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>
|
</script>
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import Input from "~/components/ui/Input.vue"
|
import Input from "~/components/ui/Input.vue";
|
||||||
```
|
```
|
||||||
|
|
||||||
# Input
|
# 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 |
|
| 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. |
|
| `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. |
|
| `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}
|
```vue-html{2}
|
||||||
<Input v-model="value" placeholder="Your favorite animal" />
|
<Input v-model="value" placeholder="Your favorite animal" />
|
||||||
```
|
```
|
||||||
|
|
||||||
<Input placeholder="Your favorite animal" />
|
<Input v-model="value" placeholder="Your favorite animal" />
|
||||||
|
|
||||||
## Input icons
|
## Input icons
|
||||||
|
|
||||||
|
@ -45,14 +54,14 @@ Add a [Bootstrap icon](https://icons.getbootstrap.com/) to an input to make its
|
||||||
## Label slot
|
## Label slot
|
||||||
|
|
||||||
```vue-html{2-4}
|
```vue-html{2-4}
|
||||||
<Input>
|
<Input v-model="user">
|
||||||
<template #label>
|
<template #label>
|
||||||
User name
|
User name
|
||||||
</template>
|
</template>
|
||||||
</Input>
|
</Input>
|
||||||
```
|
```
|
||||||
|
|
||||||
<Input>
|
<Input v-model="user">
|
||||||
<template #label>
|
<template #label>
|
||||||
User name
|
User name
|
||||||
</template>
|
</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:
|
If you just have a string, we have a convenience prop, so instead you can write:
|
||||||
|
|
||||||
```vue-html
|
```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
|
## 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>
|
||||||
```
|
```
|
||||||
|
|
||||||
<Input placeholder="Search">
|
<Input v-model="search" placeholder="Search">
|
||||||
<template #input-right>
|
<template #input-right>
|
||||||
suffix
|
suffix
|
||||||
</template>
|
</template>
|
||||||
</Input>
|
</Input>
|
||||||
|
|
||||||
|
## Color
|
||||||
|
|
||||||
|
See [Button](./button.md#button-colors) for a detailed overview of available props.
|
||||||
|
|
||||||
## Presets
|
## Presets
|
||||||
|
|
||||||
### Search
|
### Search
|
||||||
|
|
||||||
```vue-html
|
```vue-html
|
||||||
<Input search />
|
<Input search v-model="search" />
|
||||||
```
|
```
|
||||||
|
|
||||||
<Input search />
|
<Input search v-model="search" />
|
||||||
|
|
||||||
### Password
|
### Password
|
||||||
|
|
||||||
```vue-html
|
```vue-html
|
||||||
<Spacer :size="64" />
|
<Spacer :size="64" />
|
||||||
<Layout form stack>
|
<Layout form stack>
|
||||||
<Input label="User name" />
|
<Input v-model="user" label="User name" />
|
||||||
<Input password label="Password" />
|
<Input password v-model="password" label="Password" />
|
||||||
<Layout flex>
|
<Layout flex>
|
||||||
<Button primary> Submit </Button>
|
<Button primary> Submit </Button>
|
||||||
<Button> Cancel </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" />
|
<Spacer :size="64" />
|
||||||
<Layout form stack>
|
<Layout form stack>
|
||||||
<Input label="User name" />
|
<Input v-model="user" label="User name" />
|
||||||
<Input password label="Password" />
|
<Input password v-model="password" label="Password" />
|
||||||
<Layout flex>
|
<Layout flex>
|
||||||
<Button primary> Submit </Button>
|
<Button primary> Submit </Button>
|
||||||
<Button> Cancel </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
|
```vue-html
|
||||||
<Input v-model="value"/>
|
<Input
|
||||||
<Input v-model="value"/>
|
v-model="value"
|
||||||
|
:reset="() => { value = 'Original value' }">
|
||||||
|
</Input>
|
||||||
```
|
```
|
||||||
|
|
||||||
<Layout flex>
|
<Input
|
||||||
<Input auto v-model="value"/>
|
v-model="value"
|
||||||
<Input auto v-model="value"/>
|
:reset="() => { value = 'Original value' }">
|
||||||
</Layout>
|
</Input>
|
||||||
|
|
||||||
## Fallthrough attributes
|
## Fallthrough attributes
|
||||||
|
|
||||||
If you add attributes that are no props, they will be added to the component:
|
If you add attributes that are no props, they will be added to the component:
|
||||||
|
|
||||||
```vue-html
|
```vue-html
|
||||||
<Input required
|
<Input v-model="password" required
|
||||||
field-id="password-field"
|
field-id="password-field"
|
||||||
/>
|
/>
|
||||||
```
|
```
|
||||||
|
|
||||||
<Input required
|
<Input v-model="password" required
|
||||||
field-id="password-field"
|
field-id="password-field"
|
||||||
/>
|
/>
|
||||||
|
|
Ładowanie…
Reference in New Issue