refactor(ui): user can edit pill content
This commit is contained in:
parent
f48b7c59d5
commit
e5371cddaf
|
@ -1,11 +1,17 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
import { type ColorProps, type PastelProps, type VariantProps, type RaisedProps, color } from '~/composables/color'
|
import { type ColorProps, type PastelProps, type VariantProps, type RaisedProps, color } from '~/composables/color'
|
||||||
|
|
||||||
|
|
||||||
|
const input = ref();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
click: [event: MouseEvent]
|
click: [event: MouseEvent]
|
||||||
}>()
|
}>()
|
||||||
const handleClick = (event: MouseEvent) => {
|
const handleClick = (event: MouseEvent) => {
|
||||||
emit('click', event)
|
emit('click', event);
|
||||||
|
if (model.value !== undefined) {
|
||||||
|
(input.value as HTMLInputElement).focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const props = defineProps<{ noUnderline?:true } & (PastelProps | ColorProps) & VariantProps & RaisedProps>()
|
const props = defineProps<{ noUnderline?:true } & (PastelProps | ColorProps) & VariantProps & RaisedProps>()
|
||||||
const model = defineModel<string>()
|
const model = defineModel<string>()
|
||||||
|
@ -22,7 +28,16 @@ const model = defineModel<string>()
|
||||||
<div v-if="!!$slots.image" class="pill-image">
|
<div v-if="!!$slots.image" class="pill-image">
|
||||||
<slot name="image" />
|
<slot name="image" />
|
||||||
</div>
|
</div>
|
||||||
<input v-if="model" class="pill-content" v-model="model" style="border-radius:16px; min-width: max-content; width:min-content;" />
|
<!-- TODO: Sanitize text on blur? -->
|
||||||
|
<span contenteditable
|
||||||
|
v-if="model !== undefined"
|
||||||
|
ref="input"
|
||||||
|
class="pill-content"
|
||||||
|
@keydown.enter="(e) => (e.target as HTMLInputElement).blur()"
|
||||||
|
@blur="(e) => model = (e.target as HTMLInputElement).innerText.trim()"
|
||||||
|
>
|
||||||
|
{{ model }}
|
||||||
|
</span>
|
||||||
<div class="pill-content" v-if="!!$slots.default">
|
<div class="pill-content" v-if="!!$slots.default">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,10 +47,15 @@ const model = defineModel<string>()
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import './pill.scss';
|
@import './pill.scss';
|
||||||
label.funkwhale.pill.pill {
|
label.funkwhale.pill.pill {
|
||||||
height: 28px;
|
min-width: 40px;
|
||||||
>input {
|
min-height: 28px;
|
||||||
|
white-space: pre;
|
||||||
|
cursor: text;
|
||||||
|
> span[contenteditable] {
|
||||||
// Note that <Input>s can't be styled with `min-width` or `width` directly.
|
// Note that <Input>s can't be styled with `min-width` or `width` directly.
|
||||||
width: 120px;
|
// SOLUTION: Contenteditable. Everything else is a dirty hack.
|
||||||
|
border-radius:16px;
|
||||||
|
outline: 1px solid transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -156,24 +156,32 @@ Image pills contain a small circular image on their left. These can be used for
|
||||||
|
|
||||||
## Editable pill
|
## Editable pill
|
||||||
|
|
||||||
Add `v-model="..."` to link the pill content to a `ref`. Note that the pill is not rendered if v-model is ''.
|
Add `v-model="..."` to link the pill content to a `ref`.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { computed, ref } from "vue";
|
import { ref } from "vue";
|
||||||
const customTag = ref(" ");
|
const customTag = ref("Custom Tag");
|
||||||
const isDeleted = computed(() => customTag.value === "");
|
|
||||||
```
|
```
|
||||||
|
|
||||||
```vue-html
|
```vue-html
|
||||||
<Pill v-model="customTag" />
|
<Pill v-model="customTag" />
|
||||||
|
|
||||||
<Button primary v-if="isDeleted" :onClick="() => customTag=' '">New Pill</Button>
|
<Button primary low-height
|
||||||
|
:disabled="customTag === ''"
|
||||||
|
:onClick="() => customTag = ''"
|
||||||
|
>
|
||||||
|
Reset: {{ customTag }}
|
||||||
|
</Button>
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<Pill v-model="customTag">
|
<Pill no-underline v-model="customTag" />
|
||||||
<template #image>
|
|
||||||
<div style="background-color: #0004" />
|
|
||||||
</template>
|
|
||||||
</Pill>
|
|
||||||
|
|
||||||
<Button primary v-if="isDeleted" :onClick="() => customTag=' '">New Pill</Button>
|
Edit the text, then hit Enter or click outside. The button will show the updated text.
|
||||||
|
|
||||||
|
<Button primary low-height
|
||||||
|
:disabled="customTag === ''"
|
||||||
|
:onClick="() => customTag = ''"
|
||||||
|
>
|
||||||
|
Reset: {{ customTag }}
|
||||||
|
</Button>
|
||||||
|
|
Loading…
Reference in New Issue