mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-02-17 13:20:52 +08:00
refactor(input): pattern -> allow-input
This commit is contained in:
parent
599d524b35
commit
014ddea7de
@ -15,6 +15,7 @@
|
|||||||
### Feats
|
### Feats
|
||||||
|
|
||||||
- 🌟 `n-pagination` adds dropdown menu for fast jump button.
|
- 🌟 `n-pagination` adds dropdown menu for fast jump button.
|
||||||
|
- `n-input` adds `allow-input` prop.
|
||||||
- `n-tree-select` adds `arrow` slot, closes [#3084](https://github.com/TuSimple/naive-ui/issues/3084).
|
- `n-tree-select` adds `arrow` slot, closes [#3084](https://github.com/TuSimple/naive-ui/issues/3084).
|
||||||
- `n-cascader` will show corresponding submenu after checkbox is clicked, closes [#3079](https://github.com/TuSimple/naive-ui/issues/3079).
|
- `n-cascader` will show corresponding submenu after checkbox is clicked, closes [#3079](https://github.com/TuSimple/naive-ui/issues/3079).
|
||||||
- `n-upload` will disable dragger when maximum number of files was reached.
|
- `n-upload` will disable dragger when maximum number of files was reached.
|
||||||
@ -22,7 +23,6 @@
|
|||||||
- `n-popselect` adds `node-props` prop.
|
- `n-popselect` adds `node-props` prop.
|
||||||
- `n-popselect` adds `virtual-scroll` prop.
|
- `n-popselect` adds `virtual-scroll` prop.
|
||||||
- `n-data-table` adds `scrollTo` method, closes [#2570](https://github.com/TuSimple/naive-ui/issues/2570).
|
- `n-data-table` adds `scrollTo` method, closes [#2570](https://github.com/TuSimple/naive-ui/issues/2570).
|
||||||
- `n-input` adds `pattern` props.
|
|
||||||
|
|
||||||
## 2.30.3
|
## 2.30.3
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
- `n-popselect` 新增 `node-props` 属性
|
- `n-popselect` 新增 `node-props` 属性
|
||||||
- `n-popselect` 新增 `virtual-scroll` 属性
|
- `n-popselect` 新增 `virtual-scroll` 属性
|
||||||
- `n-data-table` 新增 `scrollTo` 方法,关闭 [#2570](https://github.com/TuSimple/naive-ui/issues/2570)
|
- `n-data-table` 新增 `scrollTo` 方法,关闭 [#2570](https://github.com/TuSimple/naive-ui/issues/2570)
|
||||||
- `n-input` 新增 `pattern` 属性
|
- `n-input` 新增 `allow-input` 属性
|
||||||
|
|
||||||
## 2.30.3
|
## 2.30.3
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ pattern.vue
|
|||||||
|
|
||||||
| Name | Type | Default | Description | Version |
|
| Name | Type | Default | Description | Version |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
|
| allow-input | `(value: string) => boolean` | `undefined` | Check the incoming value, if it returns `false`, input will not be accepted. | NEXT_VERSION |
|
||||||
| autofocus | `boolean` | `false` | Whether to autofocus. | |
|
| autofocus | `boolean` | `false` | Whether to autofocus. | |
|
||||||
| autosize | `boolean \| { minRows?: number, maxRows?: number }` | `false` | Sizing property for when the input is of type `textarea`. e.g. `{ minRows: 1, maxRows: 3 }`. | |
|
| autosize | `boolean \| { minRows?: number, maxRows?: number }` | `false` | Sizing property for when the input is of type `textarea`. e.g. `{ minRows: 1, maxRows: 3 }`. | |
|
||||||
| clearable | `boolean` | `false` | Whether the input is clearable. | |
|
| clearable | `boolean` | `false` | Whether the input is clearable. | |
|
||||||
@ -51,7 +52,6 @@ pattern.vue
|
|||||||
| show-password-on | `'click' \| 'mousedown'` | `undefined` | The event to show the password. | |
|
| show-password-on | `'click' \| 'mousedown'` | `undefined` | The event to show the password. | |
|
||||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | Input size. | |
|
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | Input size. | |
|
||||||
| status | `'success' \| 'warning' \| 'error'` | `undefined` | Validaiton status. | 2.25.0 |
|
| status | `'success' \| 'warning' \| 'error'` | `undefined` | Validaiton status. | 2.25.0 |
|
||||||
| pattern | `(value: string) => boolean` | `undefined` | Check the incoming value, if it returns `false`, input will not be accepted. | NEXT_VERSION |
|
|
||||||
| type | `'text' \| 'password' \| 'textarea'` | `'text'` | Input type. | |
|
| type | `'text' \| 'password' \| 'textarea'` | `'text'` | Input type. | |
|
||||||
| value | `string \| [string, string] \| null` | `undefined` | Manually set the input value. When `pair` is `true`, this is an array. | |
|
| value | `string \| [string, string] \| null` | `undefined` | Manually set the input value. When `pair` is `true`, this is an array. | |
|
||||||
| on-blur | `() => void` | `undefined` | Callback triggered when the input is blurred. | |
|
| on-blur | `() => void` | `undefined` | Callback triggered when the input is blurred. | |
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
<markdown>
|
<markdown>
|
||||||
# Input intercept
|
# Limit input format
|
||||||
|
|
||||||
Control the entry format of the input.
|
Use `allow-input` to limit input value to desired format. You can use it to achieve trim effect.
|
||||||
</markdown>
|
</markdown>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<n-space vertical>
|
<n-space vertical>
|
||||||
<n-input
|
<n-input
|
||||||
type="text"
|
type="text"
|
||||||
:pattern="validateOnlyNumber"
|
:allow-input="onlyAllowNumber"
|
||||||
placeholder="Only enter the number."
|
placeholder="Only allow number"
|
||||||
/>
|
/>
|
||||||
<n-input
|
<n-input
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:pattern="validateEmpty"
|
:allow-input="noSideSpace"
|
||||||
placeholder="Can't enter space."
|
placeholder="No leading or trailing space"
|
||||||
/>
|
/>
|
||||||
</n-space>
|
</n-space>
|
||||||
</template>
|
</template>
|
||||||
@ -25,8 +25,8 @@ import { defineComponent } from 'vue'
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup () {
|
setup () {
|
||||||
return {
|
return {
|
||||||
validateOnlyNumber: (value: string) => !value || /^\d+$/.test(value),
|
onlyAllowNumber: (value: string) => !value || /^\d+$/.test(value),
|
||||||
validateEmpty: (value: string) => !/ /g.test(value)
|
noSideSpace: (value: string) => !/ /g.test(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -32,6 +32,7 @@ rtl-debug.vue
|
|||||||
|
|
||||||
| 名称 | 类型 | 默认值 | 说明 | 版本 |
|
| 名称 | 类型 | 默认值 | 说明 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
|
| allow-input | `(value: string) => false` | `undefined` | 校验当前的输入是否合法,如果返回 `false` 输入框便不会响应此次的输入 | NEXT_VERSION |
|
||||||
| autofocus | `boolean` | `false` | 是否自动获取焦点 | |
|
| autofocus | `boolean` | `false` | 是否自动获取焦点 | |
|
||||||
| autosize | `boolean \| { minRows?: number, maxRows?: number }` | `false` | 自适应内容高度,只对 `type="textarea"` 有效,可传入对象,如 `{ minRows: 1, maxRows: 3 }` | |
|
| autosize | `boolean \| { minRows?: number, maxRows?: number }` | `false` | 自适应内容高度,只对 `type="textarea"` 有效,可传入对象,如 `{ minRows: 1, maxRows: 3 }` | |
|
||||||
| clearable | `boolean` | `false` | 是否可清空 | |
|
| clearable | `boolean` | `false` | 是否可清空 | |
|
||||||
@ -52,7 +53,6 @@ rtl-debug.vue
|
|||||||
| show-password-on | `'click' \| 'mousedown'` | `undefined` | 显示密码的时机 | |
|
| show-password-on | `'click' \| 'mousedown'` | `undefined` | 显示密码的时机 | |
|
||||||
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | 输入框尺寸 | |
|
| size | `'small' \| 'medium' \| 'large'` | `'medium'` | 输入框尺寸 | |
|
||||||
| status | `'success' \| 'warning' \| 'error'` | `undefined` | 验证状态 | 2.25.0 |
|
| status | `'success' \| 'warning' \| 'error'` | `undefined` | 验证状态 | 2.25.0 |
|
||||||
| pattern | `(value: string) => false` | `undefined` | 校验当前的输入是否合法,如果返回 `false` 输入框便不会响应此次的输入 | NEXT_VERSION |
|
|
||||||
| type | `'text' \| 'password' \| 'textarea'` | `'text'` | 输入框类型 | |
|
| type | `'text' \| 'password' \| 'textarea'` | `'text'` | 输入框类型 | |
|
||||||
| value | `string \| [string, string] \| null` | `undefined` | 文本输入的值。如果 `pair` 是 `true`,`value` 是一个数组 | |
|
| value | `string \| [string, string] \| null` | `undefined` | 文本输入的值。如果 `pair` 是 `true`,`value` 是一个数组 | |
|
||||||
| on-blur | `() => void` | `undefined` | 输入框失去焦点时触发 | |
|
| on-blur | `() => void` | `undefined` | 输入框失去焦点时触发 | |
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
<markdown>
|
<markdown>
|
||||||
# 输入校验
|
# 输入校验
|
||||||
|
|
||||||
限制输入框的输入格式。
|
使用 `allow-input` 限制输入框的输入格式,你可以使用它来达到 `trim` 的效果。
|
||||||
</markdown>
|
</markdown>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<n-space vertical>
|
<n-space vertical>
|
||||||
<n-input
|
<n-input
|
||||||
type="text"
|
type="text"
|
||||||
:pattern="validateOnlyNumber"
|
:allow-input="onlyAllowNumber"
|
||||||
placeholder="只能输入数字"
|
placeholder="只能输入数字"
|
||||||
/>
|
/>
|
||||||
<n-input
|
<n-input
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:pattern="validateEmpty"
|
:allow-input="noSideSpace"
|
||||||
placeholder="不能输入空格"
|
placeholder="没有前后空格"
|
||||||
/>
|
/>
|
||||||
</n-space>
|
</n-space>
|
||||||
</template>
|
</template>
|
||||||
@ -25,8 +25,9 @@ import { defineComponent } from 'vue'
|
|||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup () {
|
setup () {
|
||||||
return {
|
return {
|
||||||
validateOnlyNumber: (value: string) => !value || /^\d+$/.test(value),
|
onlyAllowNumber: (value: string) => !value || /^\d+$/.test(value),
|
||||||
validateEmpty: (value: string) => !/ /g.test(value)
|
noSideSpace: (value: string) =>
|
||||||
|
!value.startsWith(' ') && !value.endsWith(' ')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -24,6 +24,7 @@ import { VResizeObserver } from 'vueuc'
|
|||||||
import { off, on } from 'evtd'
|
import { off, on } from 'evtd'
|
||||||
import type { FormValidationStatus } from '../../form/src/interface'
|
import type { FormValidationStatus } from '../../form/src/interface'
|
||||||
import { EyeIcon, EyeOffIcon } from '../../_internal/icons'
|
import { EyeIcon, EyeOffIcon } from '../../_internal/icons'
|
||||||
|
import useRtl from '../../_mixins/use-rtl'
|
||||||
import {
|
import {
|
||||||
NBaseClear,
|
NBaseClear,
|
||||||
NBaseIcon,
|
NBaseIcon,
|
||||||
@ -57,10 +58,9 @@ import type {
|
|||||||
InputWrappedRef
|
InputWrappedRef
|
||||||
} from './interface'
|
} from './interface'
|
||||||
import { inputInjectionKey } from './interface'
|
import { inputInjectionKey } from './interface'
|
||||||
import { isEmptyValue, useCursor } from './utils'
|
import { isEmptyInputValue, useCursor } from './utils'
|
||||||
import WordCount from './WordCount'
|
import WordCount from './WordCount'
|
||||||
import style from './styles/input.cssr'
|
import style from './styles/input.cssr'
|
||||||
import useRtl from '../../_mixins/use-rtl'
|
|
||||||
|
|
||||||
const inputProps = {
|
const inputProps = {
|
||||||
...(useTheme.props as ThemeProps<InputTheme>),
|
...(useTheme.props as ThemeProps<InputTheme>),
|
||||||
@ -120,7 +120,7 @@ const inputProps = {
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: undefined
|
default: undefined
|
||||||
},
|
},
|
||||||
pattern: Function as PropType<(value: string) => boolean>,
|
allowInput: Function as PropType<(value: string) => boolean>,
|
||||||
onMousedown: Function as PropType<(e: MouseEvent) => void>,
|
onMousedown: Function as PropType<(e: MouseEvent) => void>,
|
||||||
onKeydown: Function as PropType<(e: KeyboardEvent) => void>,
|
onKeydown: Function as PropType<(e: KeyboardEvent) => void>,
|
||||||
onKeyup: Function as PropType<(e: KeyboardEvent) => void>,
|
onKeyup: Function as PropType<(e: KeyboardEvent) => void>,
|
||||||
@ -200,7 +200,7 @@ export default defineComponent({
|
|||||||
const currentFocusedInputRef = ref<
|
const currentFocusedInputRef = ref<
|
||||||
HTMLInputElement | HTMLTextAreaElement | null
|
HTMLInputElement | HTMLTextAreaElement | null
|
||||||
>(null)
|
>(null)
|
||||||
const focusedInputCorsurControl = useCursor(currentFocusedInputRef)
|
const focusedInputCursorControl = useCursor(currentFocusedInputRef)
|
||||||
const textareaScrollbarInstRef = ref<ScrollbarInst | null>(null)
|
const textareaScrollbarInstRef = ref<ScrollbarInst | null>(null)
|
||||||
// local
|
// local
|
||||||
const { localeRef } = useLocale('Input')
|
const { localeRef } = useLocale('Input')
|
||||||
@ -242,8 +242,8 @@ export default defineComponent({
|
|||||||
const { value: mergedPlaceholder } = mergedPlaceholderRef
|
const { value: mergedPlaceholder } = mergedPlaceholderRef
|
||||||
return (
|
return (
|
||||||
!isComposing &&
|
!isComposing &&
|
||||||
(isEmptyValue(mergedValue) ||
|
(isEmptyInputValue(mergedValue) ||
|
||||||
(Array.isArray(mergedValue) && isEmptyValue(mergedValue[0]))) &&
|
(Array.isArray(mergedValue) && isEmptyInputValue(mergedValue[0]))) &&
|
||||||
mergedPlaceholder[0]
|
mergedPlaceholder[0]
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -254,8 +254,8 @@ export default defineComponent({
|
|||||||
return (
|
return (
|
||||||
!isComposing &&
|
!isComposing &&
|
||||||
mergedPlaceholder[1] &&
|
mergedPlaceholder[1] &&
|
||||||
(isEmptyValue(mergedValue) ||
|
(isEmptyInputValue(mergedValue) ||
|
||||||
(Array.isArray(mergedValue) && isEmptyValue(mergedValue[1])))
|
(Array.isArray(mergedValue) && isEmptyInputValue(mergedValue[1])))
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
// focus
|
// focus
|
||||||
@ -437,7 +437,6 @@ export default defineComponent({
|
|||||||
} else {
|
} else {
|
||||||
handleInput(e, 0)
|
handleInput(e, 0)
|
||||||
}
|
}
|
||||||
focusedInputCorsurControl.recordCursor()
|
|
||||||
}
|
}
|
||||||
function handleInput (
|
function handleInput (
|
||||||
e: InputEvent | CompositionEvent | Event,
|
e: InputEvent | CompositionEvent | Event,
|
||||||
@ -446,7 +445,6 @@ export default defineComponent({
|
|||||||
): void {
|
): void {
|
||||||
const targetValue = (e.target as HTMLInputElement).value
|
const targetValue = (e.target as HTMLInputElement).value
|
||||||
syncMirror(targetValue)
|
syncMirror(targetValue)
|
||||||
focusedInputCorsurControl.recordCursor()
|
|
||||||
if (props.type === 'textarea') {
|
if (props.type === 'textarea') {
|
||||||
const { value: textareaScrollbarInst } = textareaScrollbarInstRef
|
const { value: textareaScrollbarInst } = textareaScrollbarInstRef
|
||||||
if (textareaScrollbarInst) {
|
if (textareaScrollbarInst) {
|
||||||
@ -455,8 +453,9 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
syncSource = targetValue
|
syncSource = targetValue
|
||||||
if (isComposingRef.value) return
|
if (isComposingRef.value) return
|
||||||
const isValidInputValue = matches(targetValue)
|
focusedInputCursorControl.recordCursor()
|
||||||
if (isValidInputValue) {
|
const isIncomingValueValid = allowInput(targetValue)
|
||||||
|
if (isIncomingValueValid) {
|
||||||
if (!props.pair) {
|
if (!props.pair) {
|
||||||
event === 'input' ? doUpdateValue(targetValue) : doChange(targetValue)
|
event === 'input' ? doUpdateValue(targetValue) : doChange(targetValue)
|
||||||
} else {
|
} else {
|
||||||
@ -464,7 +463,7 @@ export default defineComponent({
|
|||||||
if (!Array.isArray(value)) {
|
if (!Array.isArray(value)) {
|
||||||
value = ['', '']
|
value = ['', '']
|
||||||
} else {
|
} else {
|
||||||
value = [...value]
|
value = [value[0], value[1]]
|
||||||
}
|
}
|
||||||
value[index] = targetValue
|
value[index] = targetValue
|
||||||
event === 'input' ? doUpdateValue(value) : doChange(value)
|
event === 'input' ? doUpdateValue(value) : doChange(value)
|
||||||
@ -473,14 +472,14 @@ export default defineComponent({
|
|||||||
// force update to sync input's view with value
|
// force update to sync input's view with value
|
||||||
// if not set, after input, input value won't sync with dom input value
|
// if not set, after input, input value won't sync with dom input value
|
||||||
vm.$forceUpdate()
|
vm.$forceUpdate()
|
||||||
if (!isValidInputValue) {
|
if (!isIncomingValueValid) {
|
||||||
void nextTick(focusedInputCorsurControl.restoreCursor)
|
void nextTick(focusedInputCursorControl.restoreCursor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function matches (value: string): boolean {
|
function allowInput (value: string): boolean {
|
||||||
const { pattern } = props
|
const { allowInput } = props
|
||||||
if (typeof pattern === 'function') {
|
if (typeof allowInput === 'function') {
|
||||||
return pattern(value)
|
return allowInput(value)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -502,7 +501,7 @@ export default defineComponent({
|
|||||||
dealWithEvent(e, 'blur')
|
dealWithEvent(e, 'blur')
|
||||||
currentFocusedInputRef.value = null
|
currentFocusedInputRef.value = null
|
||||||
}
|
}
|
||||||
function handleInputFocus (e: FocusEvent, index?: number): void {
|
function handleInputFocus (e: FocusEvent, index: number): void {
|
||||||
doUpdateValueFocus(e)
|
doUpdateValueFocus(e)
|
||||||
focusedRef.value = true
|
focusedRef.value = true
|
||||||
activatedRef.value = true
|
activatedRef.value = true
|
||||||
@ -512,7 +511,7 @@ export default defineComponent({
|
|||||||
currentFocusedInputRef.value = inputElRef.value
|
currentFocusedInputRef.value = inputElRef.value
|
||||||
} else if (index === 1) {
|
} else if (index === 1) {
|
||||||
currentFocusedInputRef.value = inputEl2Ref.value
|
currentFocusedInputRef.value = inputEl2Ref.value
|
||||||
} else {
|
} else if (index === 2) {
|
||||||
currentFocusedInputRef.value = textareaElRef.value
|
currentFocusedInputRef.value = textareaElRef.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1059,7 +1058,7 @@ export default defineComponent({
|
|||||||
scrollContainerWidthStyle
|
scrollContainerWidthStyle
|
||||||
]}
|
]}
|
||||||
onBlur={this.handleInputBlur}
|
onBlur={this.handleInputBlur}
|
||||||
onFocus={this.handleInputFocus}
|
onFocus={(e) => this.handleInputFocus(e, 2)}
|
||||||
onInput={this.handleInput}
|
onInput={this.handleInput}
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
onScroll={this.handleTextAreaScroll}
|
onScroll={this.handleTextAreaScroll}
|
||||||
|
@ -10,18 +10,17 @@ export function len (s: string): number {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isEmptyValue (value: any): boolean {
|
export function isEmptyInputValue (value: unknown): boolean {
|
||||||
return ['', undefined, null].includes(value)
|
return value === '' || value == null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UseCursorControl {
|
export interface UseCursorControl {
|
||||||
recordCursor: () => void
|
recordCursor: () => void
|
||||||
restoreCursor: () => void
|
restoreCursor: () => void
|
||||||
clearRecord: () => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCursor (
|
export function useCursor (
|
||||||
inputRef: Ref<HTMLInputElement | HTMLTextAreaElement | null>
|
inputElRef: Ref<HTMLInputElement | HTMLTextAreaElement | null>
|
||||||
): UseCursorControl {
|
): UseCursorControl {
|
||||||
const selectionRef = ref<{
|
const selectionRef = ref<{
|
||||||
start: number
|
start: number
|
||||||
@ -31,35 +30,32 @@ export function useCursor (
|
|||||||
} | null>(null)
|
} | null>(null)
|
||||||
|
|
||||||
function recordCursor (): void {
|
function recordCursor (): void {
|
||||||
const { value: input } = inputRef
|
const { value: input } = inputElRef
|
||||||
if (!input || !input.focus) {
|
if (!input || !input.focus) {
|
||||||
clearRecord()
|
reset()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { selectionStart, selectionEnd, value } = input
|
const { selectionStart, selectionEnd, value } = input
|
||||||
// eslint-disable-next-line eqeqeq
|
if (selectionStart == null || selectionEnd == null) {
|
||||||
if (selectionStart == void 0 || selectionEnd == void 0) {
|
reset()
|
||||||
clearRecord()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
selectionRef.value = {
|
selectionRef.value = {
|
||||||
start: selectionStart,
|
start: selectionStart,
|
||||||
end: selectionEnd,
|
end: selectionEnd,
|
||||||
beforeText: value.substring(0, selectionStart),
|
beforeText: value.slice(0, selectionStart),
|
||||||
afterText: value.substring(selectionEnd)
|
afterText: value.slice(selectionEnd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreCursor (): void {
|
function restoreCursor (): void {
|
||||||
const { value: selection } = selectionRef
|
const { value: selection } = selectionRef
|
||||||
const { value: input } = inputRef
|
const { value: inputEl } = inputElRef
|
||||||
if (!selection || !input || !input.focus) {
|
if (!selection || !inputEl) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const { value } = inputEl
|
||||||
const { value } = input
|
|
||||||
const { start, beforeText, afterText } = selection
|
const { start, beforeText, afterText } = selection
|
||||||
|
|
||||||
let startPos = value.length
|
let startPos = value.length
|
||||||
if (value.endsWith(afterText)) {
|
if (value.endsWith(afterText)) {
|
||||||
startPos = value.length - afterText.length
|
startPos = value.length - afterText.length
|
||||||
@ -72,18 +68,16 @@ export function useCursor (
|
|||||||
startPos = newIndex + 1
|
startPos = newIndex + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
inputEl.setSelectionRange?.(startPos, startPos)
|
||||||
input.setSelectionRange?.(startPos, startPos)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearRecord (): void {
|
function reset (): void {
|
||||||
selectionRef.value = null
|
selectionRef.value = null
|
||||||
}
|
}
|
||||||
watch(inputRef, clearRecord)
|
watch(inputElRef, reset)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
recordCursor,
|
recordCursor,
|
||||||
restoreCursor,
|
restoreCursor
|
||||||
clearRecord
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user