feat(ui): add label prop and slot to textarea component
This commit is contained in:
parent
9e3f2cfb57
commit
b2ba7e1e6a
|
@ -4,8 +4,9 @@ import { useTextareaAutosize, computedWithControl, useManualRefHistory, watchDeb
|
|||
|
||||
import Button from './Button.vue'
|
||||
import Markdown from './Markdown.vue'
|
||||
import Layout from '~/components/ui/Layout.vue'
|
||||
|
||||
const { max=Infinity, placeholder='' } = defineProps<{ max?:number,placeholder?:string }>()
|
||||
const { max=Infinity, placeholder='', ...restProps } = defineProps<{ max?:number,placeholder?:string, label?:string }>()
|
||||
|
||||
const model = defineModel<string>({ default: '' })
|
||||
|
||||
|
@ -177,38 +178,48 @@ const focus = () => textarea.value.focus()
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="{ 'has-preview': preview }" class="funkwhale textarea" @mousedown.prevent="focus" @mouseup.prevent="focus">
|
||||
<Markdown :md="model" class="preview" />
|
||||
<textarea ref="textarea" @click="updateLineNumber" @mousedown.stop @mouseup.stop @keydown.left="updateLineNumber"
|
||||
@keydown.right="updateLineNumber" @keydown.up="updateLineNumber" @keydown.down="updateLineNumber"
|
||||
@keydown.enter="newline" @keydown.ctrl.shift.z.exact.prevent="redo" @keydown.ctrl.z.exact.prevent="undo"
|
||||
@keydown.ctrl.b.exact.prevent="bold" @keydown.ctrl.i.exact.prevent="italics"
|
||||
@keydown.ctrl.shift.x.exact.prevent="strikethrough" @keydown.ctrl.k.exact.prevent="link" :maxlength="max"
|
||||
:placeholder="placeholder" v-model="model" id="textarea_id" />
|
||||
<div class="textarea-buttons">
|
||||
<Button @click="preview = !preview" icon="bi-eye" color="secondary" :aria-pressed="preview || undefined" />
|
||||
<Layout stack no-gap label
|
||||
class="funkwhale textarea-label"
|
||||
>
|
||||
<span v-if="$slots['label']" class="label">
|
||||
<slot name="label" />
|
||||
</span>
|
||||
<span v-if="restProps.label" class="label">
|
||||
{{ restProps.label }}
|
||||
</span>
|
||||
<div :class="{ 'has-preview': preview }" class="funkwhale textarea" @mousedown.prevent="focus" @mouseup.prevent="focus">
|
||||
<Markdown :md="model" class="preview" />
|
||||
<textarea ref="textarea" @click="updateLineNumber" @mousedown.stop @mouseup.stop @keydown.left="updateLineNumber"
|
||||
@keydown.right="updateLineNumber" @keydown.up="updateLineNumber" @keydown.down="updateLineNumber"
|
||||
@keydown.enter="newline" @keydown.ctrl.shift.z.exact.prevent="redo" @keydown.ctrl.z.exact.prevent="undo"
|
||||
@keydown.ctrl.b.exact.prevent="bold" @keydown.ctrl.i.exact.prevent="italics"
|
||||
@keydown.ctrl.shift.x.exact.prevent="strikethrough" @keydown.ctrl.k.exact.prevent="link" :maxlength="max"
|
||||
:placeholder="placeholder" v-model="model" id="textarea_id" />
|
||||
<div class="textarea-buttons">
|
||||
<Button @click="preview = !preview" icon="bi-eye" color="secondary" :aria-pressed="preview || undefined" />
|
||||
|
||||
<div class="separator" />
|
||||
<div class="separator" />
|
||||
|
||||
<Button @click="heading1" icon="bi-type-h1" color="secondary" :aria-pressed="isHeading1 || undefined" :disabled="preview" />
|
||||
<Button @click="heading2" icon="bi-type-h2" color="secondary" :aria-pressed="isHeading2 || undefined" :disabled="preview" />
|
||||
<Button @click="paragraph" icon="bi-paragraph" color="secondary" :aria-pressed="isParagraph || undefined" :disabled="preview" />
|
||||
<Button @click="quote" icon="bi-quote" color="secondary" :aria-pressed="isQuote || undefined" :disabled="preview" />
|
||||
<Button @click="orderedList" icon="bi-list-ol" color="secondary" :aria-pressed="isOrderedList || undefined"
|
||||
:disabled="preview" />
|
||||
<Button @click="unorderedList" icon="bi-list-ul" color="secondary" :aria-pressed="isUnorderedList || undefined"
|
||||
:disabled="preview" />
|
||||
<Button @click="heading1" icon="bi-type-h1" color="secondary" :aria-pressed="isHeading1 || undefined" :disabled="preview" />
|
||||
<Button @click="heading2" icon="bi-type-h2" color="secondary" :aria-pressed="isHeading2 || undefined" :disabled="preview" />
|
||||
<Button @click="paragraph" icon="bi-paragraph" color="secondary" :aria-pressed="isParagraph || undefined" :disabled="preview" />
|
||||
<Button @click="quote" icon="bi-quote" color="secondary" :aria-pressed="isQuote || undefined" :disabled="preview" />
|
||||
<Button @click="orderedList" icon="bi-list-ol" color="secondary" :aria-pressed="isOrderedList || undefined"
|
||||
:disabled="preview" />
|
||||
<Button @click="unorderedList" icon="bi-list-ul" color="secondary" :aria-pressed="isUnorderedList || undefined"
|
||||
:disabled="preview" />
|
||||
|
||||
<div class="separator" />
|
||||
<div class="separator" />
|
||||
|
||||
<Button @click="bold" icon="bi-type-bold" color="secondary" :disabled="preview" />
|
||||
<Button @click="italics" icon="bi-type-italic" color="secondary" :disabled="preview" />
|
||||
<Button @click="strikethrough" icon="bi-type-strikethrough" color="secondary" :disabled="preview" />
|
||||
<Button @click="link" icon="bi-link-45deg" color="secondary" :disabled="preview" />
|
||||
<Button @click="bold" icon="bi-type-bold" color="secondary" :disabled="preview" />
|
||||
<Button @click="italics" icon="bi-type-italic" color="secondary" :disabled="preview" />
|
||||
<Button @click="strikethrough" icon="bi-type-strikethrough" color="secondary" :disabled="preview" />
|
||||
<Button @click="link" icon="bi-link-45deg" color="secondary" :disabled="preview" />
|
||||
|
||||
<span v-if="max !== Infinity && typeof max === 'number'" class="letter-count">{{ max - model.length }}</span>
|
||||
<span v-if="max !== Infinity && typeof max === 'number'" class="letter-count">{{ max - model.length }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
.funkwhale {
|
||||
&.textarea-label {
|
||||
display: block;
|
||||
> .label {
|
||||
padding-bottom: 4px;
|
||||
font-size:14px;
|
||||
font-weight:600;
|
||||
}
|
||||
}
|
||||
&.textarea {
|
||||
background-color: var(--fw-bg-color);
|
||||
box-shadow: inset 0 0 0 4px var(--fw-border-color);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import Textarea from '~/components/ui/Textarea.vue'
|
||||
|
||||
import { ref } from 'vue'
|
||||
|
||||
const text1 = ref('# Funk\nwhale')
|
||||
|
@ -27,12 +28,12 @@ Create a textarea and attach its input to a value using a `v-model` directive.
|
|||
|
||||
```vue-html{2}
|
||||
<Textarea
|
||||
v-model="text"
|
||||
v-model="text" label="My Area"
|
||||
/>
|
||||
```
|
||||
|
||||
<ClientOnly>
|
||||
<Textarea v-model="text1" />
|
||||
<Textarea v-model="text1" label="My Area"/>
|
||||
</ClientOnly>
|
||||
|
||||
## Textarea max length
|
||||
|
@ -64,3 +65,27 @@ Add a placeholder to a textarea to guide users on what they should enter by pass
|
|||
<ClientOnly>
|
||||
<Textarea v-model="text3" placeholder="Describe this track here…" />
|
||||
</ClientOnly>
|
||||
|
||||
## Label slot
|
||||
|
||||
```vue-html{2-4}
|
||||
<Textarea>
|
||||
<template #label>
|
||||
About my music
|
||||
</template>
|
||||
</Textarea>
|
||||
```
|
||||
|
||||
<Textarea>
|
||||
<template #label>
|
||||
About my music <span style="color:red; float:right;">*required</span>
|
||||
</template>
|
||||
</Textarea>
|
||||
|
||||
If you just have a string, we have a convenience prop, so instead you can write:
|
||||
|
||||
```vue-html
|
||||
<Textarea label="About my music" />
|
||||
```
|
||||
|
||||
<Textarea label="About my music" />
|
||||
|
|
Loading…
Reference in New Issue