优化预览与导出排版
This commit is contained in:
67
src/components/CommitInput.tsx
Normal file
67
src/components/CommitInput.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
|
||||
export interface CommitInputProps
|
||||
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value' | 'type'> {
|
||||
value: string | number;
|
||||
onCommit: (val: string) => void;
|
||||
/** number 类型在编辑时用文本框,提交时由外部校验 min/max */
|
||||
type?: 'text' | 'number';
|
||||
}
|
||||
|
||||
/**
|
||||
* 失焦/回车提交型输入框:编辑过程中不应用 HTML min/max 限制,便于清空后重输。
|
||||
*/
|
||||
export const CommitInput: React.FC<CommitInputProps> = ({
|
||||
value,
|
||||
onCommit,
|
||||
type = 'text',
|
||||
min: _min,
|
||||
max: _max,
|
||||
step: _step,
|
||||
onFocus,
|
||||
onBlur,
|
||||
onKeyDown,
|
||||
...props
|
||||
}) => {
|
||||
const [localVal, setLocalVal] = useState<string>(String(value));
|
||||
const focusedRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!focusedRef.current) {
|
||||
setLocalVal(String(value));
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
|
||||
focusedRef.current = false;
|
||||
onBlur?.(e);
|
||||
if (localVal !== String(value)) {
|
||||
onCommit(localVal);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (e.key === 'Enter') {
|
||||
(e.target as HTMLInputElement).blur();
|
||||
}
|
||||
onKeyDown?.(e);
|
||||
};
|
||||
|
||||
const inputType = type === 'number' ? 'text' : type;
|
||||
|
||||
return (
|
||||
<input
|
||||
{...props}
|
||||
type={inputType}
|
||||
inputMode={type === 'number' ? 'decimal' : props.inputMode}
|
||||
value={localVal}
|
||||
onChange={(e) => setLocalVal(e.target.value)}
|
||||
onFocus={(e) => {
|
||||
focusedRef.current = true;
|
||||
onFocus?.(e);
|
||||
}}
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user