Sharkey/src/client/components/form/textarea.vue

164 lines
2.8 KiB
Vue
Raw Normal View History

<template>
2021-02-13 05:28:26 +02:00
<FormGroup class="_formItem">
<template #label><slot></slot></template>
<div class="rivhosbp _formItem" :class="{ tall, pre }">
<div class="input _formPanel">
<textarea ref="input" :class="{ code, _monospace: code }"
v-model="v"
:required="required"
:readonly="readonly"
:pattern="pattern"
:autocomplete="autocomplete"
:spellcheck="!code"
@input="onInput"
@focus="focused = true"
@blur="focused = false"
></textarea>
</div>
</div>
2021-02-13 05:28:26 +02:00
<template #caption><slot name="desc"></slot></template>
<FormButton v-if="manualSave && changed" @click="updated" primary><Fa :icon="faSave"/> {{ $ts.save }}</FormButton>
</FormGroup>
</template>
<script lang="ts">
2021-02-13 05:28:26 +02:00
import { defineComponent, ref, toRefs, watch } from 'vue';
import { faSave } from '@fortawesome/free-solid-svg-icons';
import './form.scss';
2021-02-13 05:28:26 +02:00
import FormButton from './button.vue';
import FormGroup from './group.vue';
export default defineComponent({
2021-02-13 05:28:26 +02:00
components: {
FormGroup,
FormButton,
},
props: {
value: {
required: false
},
required: {
type: Boolean,
required: false
},
readonly: {
type: Boolean,
required: false
},
pattern: {
type: String,
required: false
},
autocomplete: {
type: String,
required: false
},
code: {
type: Boolean,
required: false
},
tall: {
type: Boolean,
required: false,
default: false
},
pre: {
type: Boolean,
required: false,
default: false
},
2021-02-13 05:28:26 +02:00
manualSave: {
type: Boolean,
required: false,
2021-02-13 05:28:26 +02:00
default: false
},
},
2021-02-13 05:28:26 +02:00
setup(props, context) {
const { value } = toRefs(props);
const v = ref(value.value);
const changed = ref(false);
const inputEl = ref(null);
const focus = () => inputEl.value.focus();
const onInput = (ev) => {
changed.value = true;
context.emit('change', ev);
};
const updated = () => {
changed.value = false;
context.emit('update:value', v.value);
};
watch(value, newValue => {
v.value = newValue;
});
watch(v, newValue => {
if (!props.manualSave) {
updated();
}
});
return {
2021-02-13 05:28:26 +02:00
v,
updated,
changed,
focus,
onInput,
faSave,
};
}
});
</script>
<style lang="scss" scoped>
.rivhosbp {
position: relative;
> .input {
position: relative;
> textarea {
display: block;
width: 100%;
min-width: 100%;
max-width: 100%;
min-height: 130px;
margin: 0;
padding: 16px;
box-sizing: border-box;
font: inherit;
font-weight: normal;
font-size: 1em;
background: transparent;
border: none;
border-radius: 0;
outline: none;
box-shadow: none;
color: var(--fg);
&.code {
tab-size: 2;
}
}
}
&.tall {
> .input {
> textarea {
min-height: 200px;
}
}
}
&.pre {
> .input {
> textarea {
white-space: pre;
}
}
}
}
</style>