From 67a8fd2d8d92527480e597dca0e2c3b79031df2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5=D0=B9=20=D0=9A=D1=80?= =?UTF-8?q?=D1=8F=D0=B6=D0=B5=D0=B2?= Date: Tue, 9 Apr 2024 12:54:09 +0300 Subject: [PATCH] provide default values for hooks --- .eslintrc.cjs | 3 +- packages/react-imask/src/hook.ts | 116 +++++++++++++++++---------- packages/vue-imask/example.html | 18 ++++- packages/vue-imask/src/composable.ts | 74 +++++++++-------- 4 files changed, 133 insertions(+), 78 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 3a9fb2b6..9b351cd3 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -19,6 +19,7 @@ module.exports = { '@typescript-eslint/ban-ts-comment': 'off', '@typescript-eslint/ban-types': 'warn', '@typescript-eslint/no-empty-function': 'warn', - 'no-empty': ["error", { "allowEmptyCatch": true }], + 'no-empty': ['error', { allowEmptyCatch: true }], + 'prefer-const': ['error', { destructuring: 'all' }], }, }; diff --git a/packages/react-imask/src/hook.ts b/packages/react-imask/src/hook.ts index 51dbe4df..5854375b 100644 --- a/packages/react-imask/src/hook.ts +++ b/packages/react-imask/src/hook.ts @@ -9,10 +9,20 @@ function useIMask< Opts extends FactoryOpts=FactoryOpts, >( opts: Opts, - { onAccept, onComplete, ref=useRef(null) }: { + { + onAccept, + onComplete, + ref=useRef(null), + defaultValue, + defaultUnmaskedValue, + defaultTypedValue, + }: { ref?: MutableRefObject, onAccept?: (value: InputMask['value'], maskRef: InputMask, e?: InputEvent) => void; onComplete?: (value: InputMask['value'], maskRef: InputMask, e?: InputEvent) => void; + defaultValue?: InputMask['value'], + defaultUnmaskedValue?: InputMask['unmaskedValue'], + defaultTypedValue?: InputMask['typedValue'], } = {} ): { ref: MutableRefObject, @@ -25,7 +35,6 @@ function useIMask< setTypedValue: Dispatch['typedValue']>, } { const maskRef = useRef | null>(null); - const [initialized, setInitialized] = useState(false); const [lastAcceptState, setLastAcceptState] = useState<{ value?: InputMask['value'], unmaskedValue?: InputMask['unmaskedValue'], @@ -36,34 +45,79 @@ function useIMask< const [typedValue, setTypedValue] = useState['typedValue']>(); const _destroyMask = useCallback(() => { - if (!initialized) return; maskRef.current?.destroy(); maskRef.current = null; }, []); + const storeLastAcceptedValues = useCallback(() => { + const m = maskRef.current; + if (!m) return; + + setLastAcceptState({ + value: m.value, + unmaskedValue: m.unmaskedValue, + typedValue: m.typedValue, + }); + + setTypedValue(m.typedValue); + setUnmaskedValue(m.unmaskedValue); + setValue(m.value); + }, []); + const _onAccept = useCallback( (event?: InputEvent) => { const m = maskRef.current; if (!m) return; - setLastAcceptState({ - value: m.value, - unmaskedValue: m.unmaskedValue, - typedValue: m.typedValue, - }); - setTypedValue(m.typedValue); - setUnmaskedValue(m.unmaskedValue); - setValue(m.value); + storeLastAcceptedValues(); + onAccept?.(m.value, m, event); - }, - [onAccept], - ); + }, [onAccept]); const _onComplete = useCallback( (event?: InputEvent) => maskRef.current && onComplete?.(maskRef.current.value, maskRef.current, event), [onComplete], ); + useEffect(() => { + const { value: lastAcceptValue, ...state } = lastAcceptState; + const mask = maskRef.current; + + if (!mask || value === undefined) return; + + if (lastAcceptValue !== value) { + mask.value = value; + if (mask.value !== value) _onAccept(); + } + setLastAcceptState(state); + }, [value]); + + useEffect(() => { + const { unmaskedValue: lastAcceptUnmaskedValue, ...state } = lastAcceptState; + const mask = maskRef.current; + + if (!mask || unmaskedValue === undefined) return; + + if (lastAcceptUnmaskedValue !== unmaskedValue) { + mask.unmaskedValue = unmaskedValue; + if (mask.unmaskedValue !== unmaskedValue) _onAccept(); + } + setLastAcceptState(state); + }, [unmaskedValue]); + + useEffect(() => { + const { typedValue: lastAcceptTypedValue, ...state } = lastAcceptState; + const mask = maskRef.current; + + if (!mask || typedValue === undefined) return; + + if (lastAcceptTypedValue !== typedValue) { + mask.typedValue = typedValue; + if (!mask.masked.typedValueEquals(typedValue)) _onAccept(); + } + setLastAcceptState(state); + }, [typedValue]); + useEffect(() => { const el = ref.current; @@ -74,12 +128,15 @@ function useIMask< if (!mask) { if (el && opts?.mask) { maskRef.current = IMask(el, opts); - _onAccept(); + storeLastAcceptedValues(); + + if (defaultValue !== undefined) setValue(defaultValue); + if (defaultUnmaskedValue !== undefined) setUnmaskedValue(defaultUnmaskedValue); + if (defaultTypedValue !== undefined) setTypedValue(defaultTypedValue); } } else { mask?.updateOptions(opts as any); // TODO fix no idea } - setInitialized(Boolean(maskRef.current)); }, [opts, _destroyMask, _onAccept]); useEffect(() => { @@ -96,33 +153,6 @@ function useIMask< }; }, [_onAccept, _onComplete]); - useEffect(() => { - const { value: lastAcceptValue, ...state } = lastAcceptState; - const mask = maskRef.current; - if (mask && initialized) { - if (lastAcceptValue !== value) mask.value = value; - setLastAcceptState(state); - } - }, [value]); - - useEffect(() => { - const { unmaskedValue: lastAcceptUnmaskedValue, ...state } = lastAcceptState; - const mask = maskRef.current; - if (mask && initialized) { - if (lastAcceptUnmaskedValue !== unmaskedValue) mask.unmaskedValue = unmaskedValue; - setLastAcceptState(state); - } - }, [unmaskedValue]); - - useEffect(() => { - const { typedValue: lastAcceptTypedValue, ...state } = lastAcceptState; - const mask = maskRef.current; - if (mask && initialized) { - if (lastAcceptTypedValue !== typedValue) mask.typedValue = typedValue; - setLastAcceptState(state); - } - }, [typedValue]); - useEffect(() => _destroyMask, [_destroyMask]); return { diff --git a/packages/vue-imask/example.html b/packages/vue-imask/example.html index 4e8b9cd8..0536d978 100644 --- a/packages/vue-imask/example.html +++ b/packages/vue-imask/example.html @@ -19,7 +19,7 @@

Vue IMask Plugin Demo