2025-01-04 11:01:02 +00:00
< script setup >
import { computed, ref } from 'vue'
2025-03-09 12:19:05 +00:00
import Pill from '~/components/ui/Pill.vue';
2025-01-04 11:01:02 +00:00
import Pills from '~/components/ui/Pills.vue';
2025-02-21 08:53:09 +00:00
import Spacer from '~/components/ui/Spacer.vue';
2025-01-04 11:01:02 +00:00
import Layout from '~/components/ui/Layout.vue';
2025-01-04 13:34:49 +00:00
import Input from '~/components/ui/Input.vue';
const nullModel = ref({
current: [],
});
2025-01-04 11:01:02 +00:00
const staticModel = ref({
2025-01-29 08:52:52 +00:00
current: ["#Noise", "#FieldRecording", "#Experiment"],
2025-01-04 11:01:02 +00:00
});
const interactiveModel = ref({
2025-01-04 13:34:49 +00:00
current: ["#Noise", "#FieldRecording", "#Experiment"],
2025-01-29 08:52:52 +00:00
others: ["#Melody", "#Rhythm"],
});
const customModel = ref({
2025-01-30 22:27:05 +00:00
current: ["custom", "#FieldRecording", "#Experiment"],
2025-01-29 08:52:52 +00:00
others: ["#Melody", "#Rhythm"],
2025-01-30 22:27:05 +00:00
custom: ["custom"],
2025-01-04 11:01:02 +00:00
});
2025-02-21 08:53:09 +00:00
const search = ref()
2025-03-09 12:19:05 +00:00
const countryInput = ref("")
const inputModel = ref({ input: "Custom", isEditing: false })
const update = (e)=>{console.log(e)}
2025-01-04 11:01:02 +00:00
< / script >
2025-01-10 00:13:17 +00:00
```ts
2025-02-22 16:19:57 +00:00
import Pills from "~/components/ui/Pills.vue"
2025-01-10 00:13:17 +00:00
```
2025-01-04 11:01:02 +00:00
# Pills
2025-01-29 08:52:52 +00:00
Show a dense list of pills representing tags, categories or options.
Users can select a subset of given options and create new ones.
The model you provide will be mutated by this component:
- `current` : these pills are currently selected
- `others` : these pills are currently not selected (but can be selected by the user). This prop is optional. By adding it, you allow users to change the selection.
- `custom` : these pills were created by the user. This prop is optional. Users can edit, add and remove any pill defined in this array. Note that the `custom` array should only contain pills that are either in `current` or in `others` .
2025-01-30 22:27:05 +00:00
::: warning
If you place custom pills into `others` , the user will be able to select, edit and delete them but not to deselect them. If there is a use case for this, we have to design a good UX for deselecting custom pills.
:::
2025-03-09 12:19:05 +00:00
## Test
< label for = "selectTag" >
< b > Select tag< / b >
< Layout flex gap-12 style = "background:transparent;padding:12px; outline-inset: -4px; border-radius: 24px;" >
< Pill >
#Pell
< / Pill >
< input autocomplete = "off" style = "flex-grow: 1; min-width: 44px; flex-basis: 44px; padding: 12px 22px; margin: -12px; border-radius: inherit; outline: 1px solid red;" value = "pill" > < / input >
< Pill >
VeryLongPill
< / Pill >
< Pill >
VeryLongEvenLongerPill
< / Pill >
< Pill v-model = "inputModel" / >
< input id = "selectTag" size = "50" list = "tags" autocomplete = "off" style = "flex-grow: 1; min-width: 44px; flex-basis: 44px; padding: 12px 22px; margin: -12px; border-radius: inherit; outline: 1px solid red;" @input =" update " >
< / input >
<!-- https://www.sitepoint.com/html5 - datalist - autocomplete/ -->
< datalist id = "tags" >
< option > Russia< / option >
< option > Germany< / option >
< option > UnitedKingdom< / option >
< / datalist >
< style scoped >
*:has(> input){
outline: 4px solid transparent;
}
*:has(> input:focus){
outline-color:var(--focus-ring-color)
}
input:focus+datalist {
position: absolute;
max-height: 20em;
border: 0 none;
overflow-x: hidden;
overflow-y: auto;
}
datalist option {
font-size: 0.8em;
padding: 0.3em 1em;
background-color: #ccc ;
cursor: pointer;
}
datalist option:hover, datalist option:focus {
color: #fff ;
background-color: #036 ;
outline: 0 none;
}
< / style >
< / Layout >
< / label >
2025-01-29 08:52:52 +00:00
## No pills
```ts
const nullModel = ref({
2025-02-22 16:19:57 +00:00
current: []
2025-01-29 08:52:52 +00:00
});
```
```vue-html
< Pills v-model = "nullModel" / >
```
< Layout class = "preview" style = "padding:16px" >
< Pills v-model = "nullModel" / >
< / Layout >
## Predefined list of pills
```ts
const staticModel = ref({
2025-02-22 16:19:57 +00:00
current: ["#Noise", "#FieldRecording", "#Experiment"]
2025-01-29 08:52:52 +00:00
});
```
2025-01-15 09:35:43 +00:00
```vue-html
2025-01-16 08:31:31 +00:00
< Pills v-model = "staticModel" label = "Tags" / >
2025-01-15 09:35:43 +00:00
```
2025-01-04 11:01:02 +00:00
< Layout class = "preview" style = "padding:16px" >
< Pills v-model = "staticModel" label = "Tags" / >
< / Layout >
2025-01-29 08:52:52 +00:00
## Let users select and unselect pills
2025-01-04 11:01:02 +00:00
Select a set of pills from presets, and add and remove custom ones
2025-01-29 08:52:52 +00:00
```ts
const interactiveModel = ref({
current: ["#Noise", "#FieldRecording", "#Experiment"],
2025-02-22 16:19:57 +00:00
others: ["#Melody", "#Rhythm"]
2025-01-29 08:52:52 +00:00
});
```
2025-01-15 09:35:43 +00:00
```vue-html
2025-01-16 08:31:31 +00:00
< Pills v-model = "interactiveModel" label = "Tags" / >
2025-01-15 09:35:43 +00:00
```
2025-01-04 11:01:02 +00:00
< Layout class = "preview" style = "padding:16px" >
< Pills v-model = "interactiveModel" label = "Tags" / >
2025-01-04 13:34:49 +00:00
< / Layout >
2025-01-29 08:52:52 +00:00
## Let users add, remove and edit custom pills
2025-01-30 22:27:05 +00:00
Use [reactive ](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#reactive-variables-with-ref ) methods [such as `computed(...)` ](https://vuejs.org/guide/essentials/computed.html ) and `watch(...)` to query the model.
2025-01-29 08:52:52 +00:00
```ts
const customModel = ref({
2025-01-30 22:27:05 +00:00
current: ["custom", "#FieldRecording", "#Experiment"],
2025-01-29 08:52:52 +00:00
others: ["#Melody", "#Rhythm"],
2025-02-22 16:19:57 +00:00
custom: ["custom"]
2025-01-29 08:52:52 +00:00
});
```
2025-01-04 13:34:49 +00:00
2025-01-15 09:35:43 +00:00
```vue-html
2025-01-30 22:27:05 +00:00
< Pills v-model = "customModel" label = "Custom" / >
2025-01-15 09:35:43 +00:00
```
2025-01-04 13:34:49 +00:00
< Layout class = "preview" style = "padding:16px" >
2025-01-30 22:27:05 +00:00
< Pills v-model = "customModel" label = "Custom" / >
2025-01-04 11:01:02 +00:00
< / Layout >
2025-02-21 08:53:09 +00:00
## Combine Pills with other input fields
< Spacer / >
< Layout form flex >
< Input
v-model="search"
label="Search"
style="max-width: 150px;"
/>
< Pills
v-model="customModel"
label="Filter by tags"
style="max-width: 250px;"
/>
< Layout stack noGap label >
< span class = "label" > Ordering < / span >
< select >
< option
v-for="key in ['by date', 'by duration']"
:value="key"
>
key
< / option >
< / select >
< / Layout >
< Input
v-model="search"
label="Option"
style="max-width: 50px;"
/>
< / Layout >