import React, { useRef, useState, useContext, useEffect, Fragment } from "react"; import { Input, Form, Select, InputNumber, InputRef, FormInstance } from "antd"; import classNames from 'classnames'; import './index.less' const { Option } = Select; const EditableContext = React.createContext | null>(null); interface EditableRowProps { index: number; } export const EditableRow: React.FC = ({ index, ...props }) => { const [form] = Form.useForm(); return (
); }; interface EditableCellProps { editable: boolean; cellKey: string, selectedKey: string, children: React.ReactNode; dataIndex: string; record: T; align?: "left" | "center" | "right", type?: 'Input' | 'Select' | 'InputNumberPrice' | 'InputNumber' | 'InputNumberPercent' | 'TextArea'; options?: any[]; allowClear?: boolean; showSelectSearch?: boolean; directEdit?: boolean; // onSelectChange?: (value: any) => void; handleSave?: (record: T) => void; pressEnter?: (record: T) => void; pressTab?: (record: T) => void; onTap?: (record: T, cellKey: string) => void; onRightTap?: (e, record: T, cellKey: string) => void; } export const EditableCell = ({ editable, cellKey, selectedKey, children, dataIndex, record, align, type, options, allowClear, showSelectSearch, directEdit, // onSelectChange, handleSave, pressEnter, pressTab, onTap, onRightTap, ...restProps }: EditableCellProps) => { const [editing, setEditing] = useState(false); const inputRef = useRef(null); const selectRef = useRef(); const form = useContext(EditableContext)!; const divRef = useRef(); useEffect(() => { if (!!cellKey && cellKey === selectedKey) { divRef.current?.focus(); } }, [selectedKey]) useEffect(() => { if (editing) { inputRef.current?.focus({ cursor: 'end', }); selectRef.current?.focus(); } }, [editing]); const onKeydown = (e) => { let keyCode = e.key; if (editing) return; if (keyCode.length === 1 && keyCode.match(/[a-zA-Z0-9\w\W]/i)) { if (!!cellKey && cellKey === selectedKey) { toggleEdit() // divRef.current?.removeEventListener('keydown', onKeydown) } } if (e.key === 'Enter' && !!pressEnter) { pressEnter(record); // divRef.current?.removeEventListener('keydown', onKeydown) } if (e.key === 'Tab' && !!pressTab) { e.preventDefault(); setTimeout(() => { pressTab(record); }, 0) // divRef.current?.removeEventListener('keydown', onKeydown) } } const onKeyPress = (e) => { // if (type === 'TextArea' && e.ctrlKey && e.keyCode === 13) { // onPressEnter(); // } else if (type === 'TextArea' && e.keyCode === 13) { // // inputRef.current?.blur(); // } if (e.key === 'Escape') { // esc toggleEdit(); setTimeout(() => { divRef.current?.focus(); }, 1) } if (e.key === 'Tab') { e.preventDefault(); setTimeout(() => { if (!!pressTab) { pressTab(record); } save(); }, 0) } if (e.key === 'Enter') { e.preventDefault(); setTimeout(() => { onPressEnter(); }, 0) } } const toggleEdit = () => { setEditing(!editing); form.setFieldsValue({ [dataIndex]: record[dataIndex] }); }; const onPressEnter = async () => { try { const values = await form.validateFields(); toggleEdit(); if (!!handleSave) { handleSave({ ...record, ...values }); } if (!!pressEnter) { pressEnter({ ...record, ...values }); } } catch (errInfo) { console.log('Save failed:', errInfo); toggleEdit(); } } const save = async () => { try { const values = await form.validateFields(); toggleEdit(); if (!!handleSave) { handleSave({ ...record, ...values }); } } catch (errInfo) { console.log('Save failed:', errInfo); } }; const selectSave = async _ => { try { const values = await form.validateFields(); toggleEdit(); handleSave({ ...record, ...values }); // if (onSelectChange) { // onSelectChange(e); // } } catch (errInfo) { console.log('Save failed:', errInfo); } } const singleClick = () => { if (!directEdit) { return; } toggleEdit(); } let childNode = children; const cellEditChildren = () => { if (type === 'Select') { return ( ) } else if (type === 'InputNumberPrice') { return ( `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} parser={value => value.replace(/\¥\s?|(,*)/g, '')} /> ) } else if (type === 'InputNumber') { return ( ) } else if (type === 'InputNumberPercent') { return ( `${value}%`} bordered={false} // parser={value => value.replace('%', '')} /> ) } else if (type === 'TextArea') { return ( ) } else { return ( ) } } if (editable) { childNode = editing ? (
{cellEditChildren()} {/* */}
) : (
{ onKeydown(e) }} > {children}
); } return ( { if (onRightTap) onRightTap(e, record, cellKey) }} onClick={() => { if (onTap) onTap(record, cellKey) }}> {childNode} {!!cellKey && cellKey === selectedKey && (
)} ); };