77 lines
1.6 KiB
TypeScript
77 lines
1.6 KiB
TypeScript
import {
|
|
ref,
|
|
Ref,
|
|
h,
|
|
defineComponent,
|
|
onMounted,
|
|
onBeforeUnmount,
|
|
PropType,
|
|
watchEffect,
|
|
} from 'vue';
|
|
import { useInline } from '../inline';
|
|
|
|
export const SbContenteditable = defineComponent({
|
|
name: 'sb-contenteditable',
|
|
|
|
props: {
|
|
inputRef: {
|
|
type: (null as unknown) as PropType<Ref<HTMLElement|null>>,
|
|
default: ref(null),
|
|
},
|
|
tag: { type: String, default: 'div' },
|
|
|
|
value: { type: String, default: '' },
|
|
|
|
onValueChange: {
|
|
type: (null as unknown) as PropType<(value: string) => void>,
|
|
default: (_:string) => {},
|
|
},
|
|
},
|
|
|
|
setup(props) {
|
|
const {
|
|
registerClient,
|
|
unregisterClient,
|
|
} = useInline();
|
|
const onKeyup = (event: KeyboardEvent) => {
|
|
if (event.code !== 'Backspace' && event.code !== 'Delete') {
|
|
return;
|
|
}
|
|
|
|
if (!props.inputRef.value) {
|
|
return;
|
|
}
|
|
|
|
const textContent = props.inputRef.value.textContent;
|
|
if (textContent === '') {
|
|
props.inputRef.value.innerHTML = '';
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
props.inputRef.value?.focus();
|
|
registerClient(props.inputRef.value!);
|
|
});
|
|
|
|
watchEffect(() => {
|
|
if (props.inputRef.value && props.inputRef.value.innerHTML != props.value) {
|
|
props.inputRef.value.innerHTML = props.value;
|
|
}
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
unregisterClient(props.inputRef.value!);
|
|
});
|
|
|
|
return () => h(props.tag, {
|
|
class: 'sb-contenteditable',
|
|
contenteditable: 'true',
|
|
ref: props.inputRef,
|
|
onKeyup,
|
|
onInput: () => {
|
|
props.onValueChange(props.inputRef.value?.innerHTML || '');
|
|
},
|
|
});
|
|
},
|
|
});
|