deepsea-components 5.5.14 → 5.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/InputFile.d.ts +2 -0
- package/dist/cjs/components/InputFile.js +53 -10
- package/dist/cjs/components/InputFile.js.map +2 -2
- package/dist/esm/components/InputFile.d.ts +2 -0
- package/dist/esm/components/InputFile.js +55 -8
- package/dist/esm/components/InputFile.js.map +1 -1
- package/package.json +1 -1
- package/src/components/InputFile.tsx +52 -11
|
@@ -44,10 +44,12 @@ export declare function getFileData<T extends InputFileDataType>(file: File, typ
|
|
|
44
44
|
export declare const InputFile: import("react").ForwardRefExoticComponent<InputFileProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
45
45
|
export type InputFileButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
46
46
|
input: InputFileProps;
|
|
47
|
+
dragFile?: boolean;
|
|
47
48
|
};
|
|
48
49
|
/** 专用于读取文件的 button 组件 */
|
|
49
50
|
export declare const InputFileButton: import("react").ForwardRefExoticComponent<ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
50
51
|
input: InputFileProps;
|
|
52
|
+
dragFile?: boolean | undefined;
|
|
51
53
|
} & import("react").RefAttributes<HTMLButtonElement>>;
|
|
52
54
|
export interface ImportExcelProps extends Omit<InputFileProps, "multiple" | "onChange" | "accept" | "type"> {
|
|
53
55
|
onChange?: (data: Record<string, string>[]) => void;
|
|
@@ -79,27 +79,70 @@ var InputFile = (0, import_react.forwardRef)((props, ref) => {
|
|
|
79
79
|
file: files[0]
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
|
-
|
|
82
|
+
} finally {
|
|
83
83
|
if (clearAfterChange)
|
|
84
84
|
input.value = "";
|
|
85
|
-
} catch (error) {
|
|
86
85
|
setDisabled(false);
|
|
87
|
-
if (clearAfterChange)
|
|
88
|
-
input.value = "";
|
|
89
|
-
throw error;
|
|
90
86
|
}
|
|
91
87
|
}
|
|
92
88
|
return /* @__PURE__ */ React.createElement("input", { ref, disabled: disabled || inputDisabled, type: "file", multiple, onChange: onInputChange, ...rest });
|
|
93
89
|
});
|
|
94
90
|
var InputFileButton = (0, import_react.forwardRef)((props, ref) => {
|
|
95
|
-
const { onClick, input: inputProps, ...rest } = props;
|
|
96
|
-
const { style, ...restInputProps } = inputProps;
|
|
91
|
+
const { onClick: _onClick, input: inputProps, onDrop: _onDrop, onDragOver: _onDragOver, dragFile, disabled: _disabled, ...rest } = props;
|
|
92
|
+
const { style, disabled: __disabled, multiple, onChange, type = "file", ...restInputProps } = inputProps;
|
|
93
|
+
const [disabled, setDisabled] = (0, import_react.useState)(false);
|
|
97
94
|
const input = (0, import_react.useRef)(null);
|
|
98
|
-
function
|
|
95
|
+
function onClick(e) {
|
|
99
96
|
input.current?.click();
|
|
100
|
-
|
|
97
|
+
_onClick?.(e);
|
|
101
98
|
}
|
|
102
|
-
|
|
99
|
+
async function onDrop(e) {
|
|
100
|
+
_onDrop?.(e);
|
|
101
|
+
if (disabled || !dragFile)
|
|
102
|
+
return;
|
|
103
|
+
e.preventDefault();
|
|
104
|
+
const { files } = e.dataTransfer;
|
|
105
|
+
if (!files || files.length === 0)
|
|
106
|
+
return;
|
|
107
|
+
setDisabled(true);
|
|
108
|
+
try {
|
|
109
|
+
if (multiple) {
|
|
110
|
+
const result = [];
|
|
111
|
+
for (const file of Array.from(files)) {
|
|
112
|
+
result.push({
|
|
113
|
+
result: await getFileData(file, type),
|
|
114
|
+
file
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
onChange?.(result);
|
|
118
|
+
} else {
|
|
119
|
+
onChange?.({
|
|
120
|
+
result: await getFileData(files[0], type),
|
|
121
|
+
file: files[0]
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
} finally {
|
|
125
|
+
setDisabled(false);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function onDragOver(e) {
|
|
129
|
+
_onDragOver?.(e);
|
|
130
|
+
if (disabled || !dragFile)
|
|
131
|
+
return;
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
}
|
|
134
|
+
return /* @__PURE__ */ React.createElement(import_react.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
135
|
+
InputFile,
|
|
136
|
+
{
|
|
137
|
+
ref: input,
|
|
138
|
+
disabled: disabled || _disabled || __disabled,
|
|
139
|
+
style: { display: "none", ...style },
|
|
140
|
+
multiple,
|
|
141
|
+
onChange,
|
|
142
|
+
type,
|
|
143
|
+
...restInputProps
|
|
144
|
+
}
|
|
145
|
+
), /* @__PURE__ */ React.createElement("button", { ref, type: "button", disabled: disabled || _disabled, onClick, onDrop, onDragOver, ...rest }));
|
|
103
146
|
});
|
|
104
147
|
var ImportExcel = (0, import_react.forwardRef)((props, ref) => {
|
|
105
148
|
const { onChange, ...rest } = props;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/InputFile.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\r\n\r\nimport { ButtonHTMLAttributes, ChangeEvent, Fragment, InputHTMLAttributes, MouseEvent as ReactMouseEvent, forwardRef, useRef, useState } from \"react\"\r\nimport { read, utils, writeFile } from \"xlsx\"\r\n\r\nexport interface InputFileDataTypes {\r\n base64: string\r\n text: string\r\n arrayBuffer: ArrayBuffer\r\n binary: string\r\n file: File\r\n}\r\n\r\nexport type InputFileDataType = keyof InputFileDataTypes\r\n\r\nexport interface InputFileData<T> {\r\n result: T\r\n file: File\r\n}\r\n\r\nexport type InputFileProps = (\r\n | {\r\n multiple?: false\r\n type: \"base64\" | \"text\" | \"binary\"\r\n onChange?: (data: InputFileData<string>) => void\r\n }\r\n | {\r\n multiple?: false\r\n type: \"arrayBuffer\"\r\n onChange?: (data: InputFileData<ArrayBuffer>) => void\r\n }\r\n | {\r\n multiple?: false\r\n type?: \"file\"\r\n onChange?: (data: InputFileData<File>) => void\r\n }\r\n | {\r\n multiple: true\r\n type: \"base64\" | \"text\" | \"binary\"\r\n onChange?: (data: InputFileData<string>[]) => void\r\n }\r\n | {\r\n multiple: true\r\n type: \"arrayBuffer\"\r\n onChange?: (data: InputFileData<ArrayBuffer>[]) => void\r\n }\r\n | {\r\n multiple: true\r\n type?: \"file\"\r\n onChange?: (data: InputFileData<File>[]) => void\r\n }\r\n) &\r\n Omit<InputHTMLAttributes<HTMLInputElement>, \"onChange\" | \"multiple\" | \"type\"> & {\r\n /** 是否在捕获文件后清除 input 上的文件,默认为 false,主要区别在于如果不清除,连续两次选择同样的文件不会触发 onChange 事件,如果用于 form 表单,请设置为 flase */\r\n clearAfterChange?: boolean\r\n }\r\n\r\nexport async function getFileData<T extends InputFileDataType>(file: File, type: T): Promise<InputFileDataTypes[T]> {\r\n const fileReader = new FileReader()\r\n switch (type) {\r\n case \"arrayBuffer\":\r\n fileReader.readAsArrayBuffer(file)\r\n break\r\n case \"binary\":\r\n fileReader.readAsBinaryString(file)\r\n break\r\n case \"base64\":\r\n fileReader.readAsDataURL(file)\r\n break\r\n case \"text\":\r\n fileReader.readAsText(file)\r\n break\r\n default:\r\n return file as any\r\n }\r\n return new Promise(resolve => {\r\n fileReader.addEventListener(\"load\", () => {\r\n resolve(fileReader.result as any)\r\n })\r\n })\r\n}\r\n\r\n/** 专用于读取文件的组件 */\r\nexport const InputFile = forwardRef<HTMLInputElement, InputFileProps>((props, ref) => {\r\n const { multiple = false, type = \"file\", onChange, disabled: inputDisabled, clearAfterChange, ...rest } = props\r\n const [disabled, setDisabled] = useState(false)\r\n\r\n async function onInputChange(e: ChangeEvent<HTMLInputElement>) {\r\n const input = e.target\r\n const { files } = input\r\n if (!files || files.length === 0) return\r\n setDisabled(true)\r\n try {\r\n if (multiple) {\r\n const result: any[] = []\r\n for (const file of Array.from(files)) {\r\n result.push({\r\n result: await getFileData(file, type),\r\n file\r\n })\r\n }\r\n onChange?.(result as any)\r\n } else {\r\n onChange?.({\r\n result: await getFileData(files[0], type),\r\n file: files[0]\r\n } as any)\r\n }\r\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,
|
|
4
|
+
"sourcesContent": ["\"use client\"\r\n\r\nimport { ButtonHTMLAttributes, ChangeEvent, Fragment, InputHTMLAttributes, MouseEvent as ReactMouseEvent, forwardRef, useRef, useState, DragEvent } from \"react\"\r\nimport { read, utils, writeFile } from \"xlsx\"\r\n\r\nexport interface InputFileDataTypes {\r\n base64: string\r\n text: string\r\n arrayBuffer: ArrayBuffer\r\n binary: string\r\n file: File\r\n}\r\n\r\nexport type InputFileDataType = keyof InputFileDataTypes\r\n\r\nexport interface InputFileData<T> {\r\n result: T\r\n file: File\r\n}\r\n\r\nexport type InputFileProps = (\r\n | {\r\n multiple?: false\r\n type: \"base64\" | \"text\" | \"binary\"\r\n onChange?: (data: InputFileData<string>) => void\r\n }\r\n | {\r\n multiple?: false\r\n type: \"arrayBuffer\"\r\n onChange?: (data: InputFileData<ArrayBuffer>) => void\r\n }\r\n | {\r\n multiple?: false\r\n type?: \"file\"\r\n onChange?: (data: InputFileData<File>) => void\r\n }\r\n | {\r\n multiple: true\r\n type: \"base64\" | \"text\" | \"binary\"\r\n onChange?: (data: InputFileData<string>[]) => void\r\n }\r\n | {\r\n multiple: true\r\n type: \"arrayBuffer\"\r\n onChange?: (data: InputFileData<ArrayBuffer>[]) => void\r\n }\r\n | {\r\n multiple: true\r\n type?: \"file\"\r\n onChange?: (data: InputFileData<File>[]) => void\r\n }\r\n) &\r\n Omit<InputHTMLAttributes<HTMLInputElement>, \"onChange\" | \"multiple\" | \"type\"> & {\r\n /** 是否在捕获文件后清除 input 上的文件,默认为 false,主要区别在于如果不清除,连续两次选择同样的文件不会触发 onChange 事件,如果用于 form 表单,请设置为 flase */\r\n clearAfterChange?: boolean\r\n }\r\n\r\nexport async function getFileData<T extends InputFileDataType>(file: File, type: T): Promise<InputFileDataTypes[T]> {\r\n const fileReader = new FileReader()\r\n switch (type) {\r\n case \"arrayBuffer\":\r\n fileReader.readAsArrayBuffer(file)\r\n break\r\n case \"binary\":\r\n fileReader.readAsBinaryString(file)\r\n break\r\n case \"base64\":\r\n fileReader.readAsDataURL(file)\r\n break\r\n case \"text\":\r\n fileReader.readAsText(file)\r\n break\r\n default:\r\n return file as any\r\n }\r\n return new Promise(resolve => {\r\n fileReader.addEventListener(\"load\", () => {\r\n resolve(fileReader.result as any)\r\n })\r\n })\r\n}\r\n\r\n/** 专用于读取文件的组件 */\r\nexport const InputFile = forwardRef<HTMLInputElement, InputFileProps>((props, ref) => {\r\n const { multiple = false, type = \"file\", onChange, disabled: inputDisabled, clearAfterChange, ...rest } = props\r\n const [disabled, setDisabled] = useState(false)\r\n\r\n async function onInputChange(e: ChangeEvent<HTMLInputElement>) {\r\n const input = e.target\r\n const { files } = input\r\n if (!files || files.length === 0) return\r\n setDisabled(true)\r\n try {\r\n if (multiple) {\r\n const result: any[] = []\r\n for (const file of Array.from(files)) {\r\n result.push({\r\n result: await getFileData(file, type),\r\n file\r\n })\r\n }\r\n onChange?.(result as any)\r\n } else {\r\n onChange?.({\r\n result: await getFileData(files[0], type),\r\n file: files[0]\r\n } as any)\r\n }\r\n } finally {\r\n if (clearAfterChange) input.value = \"\"\r\n setDisabled(false)\r\n }\r\n }\r\n\r\n return <input ref={ref} disabled={disabled || inputDisabled} type=\"file\" multiple={multiple} onChange={onInputChange} {...rest} />\r\n})\r\n\r\nexport type InputFileButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {\r\n input: InputFileProps\r\n dragFile?: boolean\r\n}\r\n\r\n/** 专用于读取文件的 button 组件 */\r\nexport const InputFileButton = forwardRef<HTMLButtonElement, InputFileButtonProps>((props, ref) => {\r\n const { onClick: _onClick, input: inputProps, onDrop: _onDrop, onDragOver: _onDragOver, dragFile, disabled: _disabled, ...rest } = props\r\n const { style, disabled: __disabled, multiple, onChange, type = \"file\", ...restInputProps } = inputProps\r\n const [disabled, setDisabled] = useState(false)\r\n const input = useRef<HTMLInputElement>(null)\r\n\r\n function onClick(e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) {\r\n input.current?.click()\r\n _onClick?.(e)\r\n }\r\n\r\n async function onDrop(e: DragEvent<HTMLButtonElement>) {\r\n _onDrop?.(e)\r\n if (disabled || !dragFile) return\r\n e.preventDefault()\r\n const { files } = e.dataTransfer\r\n if (!files || files.length === 0) return\r\n setDisabled(true)\r\n try {\r\n if (multiple) {\r\n const result: any[] = []\r\n for (const file of Array.from(files)) {\r\n result.push({\r\n result: await getFileData(file, type),\r\n file\r\n })\r\n }\r\n onChange?.(result as any)\r\n } else {\r\n onChange?.({\r\n result: await getFileData(files[0], type),\r\n file: files[0]\r\n } as any)\r\n }\r\n } finally {\r\n setDisabled(false)\r\n }\r\n }\r\n\r\n function onDragOver(e: DragEvent<HTMLButtonElement>) {\r\n _onDragOver?.(e)\r\n if (disabled || !dragFile) return\r\n e.preventDefault()\r\n }\r\n\r\n return (\r\n <Fragment>\r\n <InputFile\r\n ref={input}\r\n disabled={disabled || _disabled || __disabled}\r\n style={{ display: \"none\", ...style }}\r\n multiple={multiple as any}\r\n onChange={onChange as any}\r\n type={type as any}\r\n {...restInputProps}\r\n />\r\n <button ref={ref} type=\"button\" disabled={disabled || _disabled} onClick={onClick} onDrop={onDrop} onDragOver={onDragOver} {...rest} />\r\n </Fragment>\r\n )\r\n})\r\n\r\nexport interface ImportExcelProps extends Omit<InputFileProps, \"multiple\" | \"onChange\" | \"accept\" | \"type\"> {\r\n onChange?: (data: Record<string, string>[]) => void\r\n}\r\n\r\n/** 专门用于读取 excel 的组件 */\r\nexport const ImportExcel = forwardRef<HTMLInputElement, ImportExcelProps>((props, ref) => {\r\n const { onChange, ...rest } = props\r\n\r\n function onInputChange(data: InputFileData<ArrayBuffer>) {\r\n const wb = read(data.result)\r\n const result = utils.sheet_to_json<any>(wb.Sheets[wb.SheetNames[0]])\r\n if (typeof result === \"object\") {\r\n const $ = result.map(it => {\r\n const _: Record<string, string> = {}\r\n Object.keys(it)\r\n .filter(key => key !== \"__rowNum__\")\r\n .forEach(key => (_[key] = String(it[key])))\r\n return _\r\n })\r\n onChange?.($)\r\n }\r\n }\r\n\r\n return <InputFile ref={ref} accept=\".xlsx\" type=\"arrayBuffer\" onChange={onInputChange} {...rest} />\r\n})\r\n\r\n/** 手动导出 excel */\r\nexport function exportExcel(data: Record<string, string>[], name: string) {\r\n const workSheet = utils.json_to_sheet(data)\r\n const workBook = utils.book_new()\r\n utils.book_append_sheet(workBook, workSheet)\r\n writeFile(workBook, `${name}${name.endsWith(\".xlsx\") ? \"\" : \".xlsx\"}`)\r\n}\r\n\r\nexport interface ExportExcelProps extends ButtonHTMLAttributes<HTMLButtonElement> {\r\n data: Record<string, string>[]\r\n fileName: string\r\n}\r\n\r\n/** 导出 excel 的 button 组件 */\r\nexport const ExportExcel = forwardRef<HTMLButtonElement, ExportExcelProps>((props, ref) => {\r\n const { data, fileName, onClick, ...rest } = props\r\n\r\n function onButtonClick(e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) {\r\n exportExcel(data, fileName)\r\n onClick?.(e)\r\n }\r\n\r\n return <button ref={ref} onClick={onButtonClick} {...rest} />\r\n})\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -44,10 +44,12 @@ export declare function getFileData<T extends InputFileDataType>(file: File, typ
|
|
|
44
44
|
export declare const InputFile: import("react").ForwardRefExoticComponent<InputFileProps & import("react").RefAttributes<HTMLInputElement>>;
|
|
45
45
|
export type InputFileButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
46
46
|
input: InputFileProps;
|
|
47
|
+
dragFile?: boolean;
|
|
47
48
|
};
|
|
48
49
|
/** 专用于读取文件的 button 组件 */
|
|
49
50
|
export declare const InputFileButton: import("react").ForwardRefExoticComponent<ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
50
51
|
input: InputFileProps;
|
|
52
|
+
dragFile?: boolean | undefined;
|
|
51
53
|
} & import("react").RefAttributes<HTMLButtonElement>>;
|
|
52
54
|
export interface ImportExcelProps extends Omit<InputFileProps, "multiple" | "onChange" | "accept" | "type"> {
|
|
53
55
|
onChange?: (data: Record<string, string>[]) => void;
|
|
@@ -63,12 +63,9 @@ export const InputFile = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
63
63
|
file: files[0]
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
|
-
|
|
66
|
+
} finally {
|
|
67
67
|
if (clearAfterChange) input.value = "";
|
|
68
|
-
} catch (error) {
|
|
69
68
|
setDisabled(false);
|
|
70
|
-
if (clearAfterChange) input.value = "";
|
|
71
|
-
throw error;
|
|
72
69
|
}
|
|
73
70
|
}
|
|
74
71
|
return /*#__PURE__*/_jsx("input", {
|
|
@@ -83,31 +80,81 @@ export const InputFile = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
83
80
|
/** 专用于读取文件的 button 组件 */
|
|
84
81
|
export const InputFileButton = /*#__PURE__*/forwardRef((props, ref) => {
|
|
85
82
|
const {
|
|
86
|
-
onClick,
|
|
83
|
+
onClick: _onClick,
|
|
87
84
|
input: inputProps,
|
|
85
|
+
onDrop: _onDrop,
|
|
86
|
+
onDragOver: _onDragOver,
|
|
87
|
+
dragFile,
|
|
88
|
+
disabled: _disabled,
|
|
88
89
|
...rest
|
|
89
90
|
} = props;
|
|
90
91
|
const {
|
|
91
92
|
style,
|
|
93
|
+
disabled: __disabled,
|
|
94
|
+
multiple,
|
|
95
|
+
onChange,
|
|
96
|
+
type = "file",
|
|
92
97
|
...restInputProps
|
|
93
98
|
} = inputProps;
|
|
99
|
+
const [disabled, setDisabled] = useState(false);
|
|
94
100
|
const input = useRef(null);
|
|
95
|
-
function
|
|
101
|
+
function onClick(e) {
|
|
96
102
|
input.current?.click();
|
|
97
|
-
|
|
103
|
+
_onClick?.(e);
|
|
104
|
+
}
|
|
105
|
+
async function onDrop(e) {
|
|
106
|
+
_onDrop?.(e);
|
|
107
|
+
if (disabled || !dragFile) return;
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
const {
|
|
110
|
+
files
|
|
111
|
+
} = e.dataTransfer;
|
|
112
|
+
if (!files || files.length === 0) return;
|
|
113
|
+
setDisabled(true);
|
|
114
|
+
try {
|
|
115
|
+
if (multiple) {
|
|
116
|
+
const result = [];
|
|
117
|
+
for (const file of Array.from(files)) {
|
|
118
|
+
result.push({
|
|
119
|
+
result: await getFileData(file, type),
|
|
120
|
+
file
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
onChange?.(result);
|
|
124
|
+
} else {
|
|
125
|
+
onChange?.({
|
|
126
|
+
result: await getFileData(files[0], type),
|
|
127
|
+
file: files[0]
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
} finally {
|
|
131
|
+
setDisabled(false);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function onDragOver(e) {
|
|
135
|
+
_onDragOver?.(e);
|
|
136
|
+
if (disabled || !dragFile) return;
|
|
137
|
+
e.preventDefault();
|
|
98
138
|
}
|
|
99
139
|
return /*#__PURE__*/_jsxs(Fragment, {
|
|
100
140
|
children: [/*#__PURE__*/_jsx(InputFile, {
|
|
101
141
|
ref: input,
|
|
142
|
+
disabled: disabled || _disabled || __disabled,
|
|
102
143
|
style: {
|
|
103
144
|
display: "none",
|
|
104
145
|
...style
|
|
105
146
|
},
|
|
147
|
+
multiple: multiple,
|
|
148
|
+
onChange: onChange,
|
|
149
|
+
type: type,
|
|
106
150
|
...restInputProps
|
|
107
151
|
}), /*#__PURE__*/_jsx("button", {
|
|
108
152
|
ref: ref,
|
|
109
153
|
type: "button",
|
|
110
|
-
|
|
154
|
+
disabled: disabled || _disabled,
|
|
155
|
+
onClick: onClick,
|
|
156
|
+
onDrop: onDrop,
|
|
157
|
+
onDragOver: onDragOver,
|
|
111
158
|
...rest
|
|
112
159
|
})]
|
|
113
160
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Fragment","forwardRef","useRef","useState","read","utils","writeFile","jsx","_jsx","jsxs","_jsxs","getFileData","file","type","fileReader","FileReader","readAsArrayBuffer","readAsBinaryString","readAsDataURL","readAsText","Promise","resolve","addEventListener","result","InputFile","props","ref","multiple","onChange","disabled","inputDisabled","clearAfterChange","rest","setDisabled","onInputChange","e","input","target","files","length","Array","from","push","value","error","InputFileButton","onClick","inputProps","style","restInputProps","onBtnClick","current","click","children","display","ImportExcel","data","wb","sheet_to_json","Sheets","SheetNames","$","map","it","_","Object","keys","filter","key","forEach","String","accept","exportExcel","name","workSheet","json_to_sheet","workBook","book_new","book_append_sheet","endsWith","ExportExcel","fileName","onButtonClick"],"sources":["../../../src/components/InputFile.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { ButtonHTMLAttributes, ChangeEvent, Fragment, InputHTMLAttributes, MouseEvent as ReactMouseEvent, forwardRef, useRef, useState } from \"react\"\r\nimport { read, utils, writeFile } from \"xlsx\"\r\n\r\nexport interface InputFileDataTypes {\r\n base64: string\r\n text: string\r\n arrayBuffer: ArrayBuffer\r\n binary: string\r\n file: File\r\n}\r\n\r\nexport type InputFileDataType = keyof InputFileDataTypes\r\n\r\nexport interface InputFileData<T> {\r\n result: T\r\n file: File\r\n}\r\n\r\nexport type InputFileProps = (\r\n | {\r\n multiple?: false\r\n type: \"base64\" | \"text\" | \"binary\"\r\n onChange?: (data: InputFileData<string>) => void\r\n }\r\n | {\r\n multiple?: false\r\n type: \"arrayBuffer\"\r\n onChange?: (data: InputFileData<ArrayBuffer>) => void\r\n }\r\n | {\r\n multiple?: false\r\n type?: \"file\"\r\n onChange?: (data: InputFileData<File>) => void\r\n }\r\n | {\r\n multiple: true\r\n type: \"base64\" | \"text\" | \"binary\"\r\n onChange?: (data: InputFileData<string>[]) => void\r\n }\r\n | {\r\n multiple: true\r\n type: \"arrayBuffer\"\r\n onChange?: (data: InputFileData<ArrayBuffer>[]) => void\r\n }\r\n | {\r\n multiple: true\r\n type?: \"file\"\r\n onChange?: (data: InputFileData<File>[]) => void\r\n }\r\n) &\r\n Omit<InputHTMLAttributes<HTMLInputElement>, \"onChange\" | \"multiple\" | \"type\"> & {\r\n /** 是否在捕获文件后清除 input 上的文件,默认为 false,主要区别在于如果不清除,连续两次选择同样的文件不会触发 onChange 事件,如果用于 form 表单,请设置为 flase */\r\n clearAfterChange?: boolean\r\n }\r\n\r\nexport async function getFileData<T extends InputFileDataType>(file: File, type: T): Promise<InputFileDataTypes[T]> {\r\n const fileReader = new FileReader()\r\n switch (type) {\r\n case \"arrayBuffer\":\r\n fileReader.readAsArrayBuffer(file)\r\n break\r\n case \"binary\":\r\n fileReader.readAsBinaryString(file)\r\n break\r\n case \"base64\":\r\n fileReader.readAsDataURL(file)\r\n break\r\n case \"text\":\r\n fileReader.readAsText(file)\r\n break\r\n default:\r\n return file as any\r\n }\r\n return new Promise(resolve => {\r\n fileReader.addEventListener(\"load\", () => {\r\n resolve(fileReader.result as any)\r\n })\r\n })\r\n}\r\n\r\n/** 专用于读取文件的组件 */\r\nexport const InputFile = forwardRef<HTMLInputElement, InputFileProps>((props, ref) => {\r\n const { multiple = false, type = \"file\", onChange, disabled: inputDisabled, clearAfterChange, ...rest } = props\r\n const [disabled, setDisabled] = useState(false)\r\n\r\n async function onInputChange(e: ChangeEvent<HTMLInputElement>) {\r\n const input = e.target\r\n const { files } = input\r\n if (!files || files.length === 0) return\r\n setDisabled(true)\r\n try {\r\n if (multiple) {\r\n const result: any[] = []\r\n for (const file of Array.from(files)) {\r\n result.push({\r\n result: await getFileData(file, type),\r\n file\r\n })\r\n }\r\n onChange?.(result as any)\r\n } else {\r\n onChange?.({\r\n result: await getFileData(files[0], type),\r\n file: files[0]\r\n } as any)\r\n }\r\n setDisabled(false)\r\n if (clearAfterChange) input.value = \"\"\r\n } catch (error) {\r\n setDisabled(false)\r\n if (clearAfterChange) input.value = \"\"\r\n throw error\r\n }\r\n }\r\n\r\n return <input ref={ref} disabled={disabled || inputDisabled} type=\"file\" multiple={multiple} onChange={onInputChange} {...rest} />\r\n})\r\n\r\nexport type InputFileButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {\r\n input: InputFileProps\r\n}\r\n\r\n/** 专用于读取文件的 button 组件 */\r\nexport const InputFileButton = forwardRef<HTMLButtonElement, InputFileButtonProps>((props, ref) => {\r\n const { onClick, input: inputProps, ...rest } = props\r\n const { style, ...restInputProps } = inputProps\r\n const input = useRef<HTMLInputElement>(null)\r\n\r\n function onBtnClick(e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) {\r\n input.current?.click()\r\n onClick?.(e)\r\n }\r\n\r\n return (\r\n <Fragment>\r\n <InputFile ref={input} style={{ display: \"none\", ...style }} {...restInputProps} />\r\n <button ref={ref} type=\"button\" onClick={onBtnClick} {...rest} />\r\n </Fragment>\r\n )\r\n})\r\n\r\nexport interface ImportExcelProps extends Omit<InputFileProps, \"multiple\" | \"onChange\" | \"accept\" | \"type\"> {\r\n onChange?: (data: Record<string, string>[]) => void\r\n}\r\n\r\n/** 专门用于读取 excel 的组件 */\r\nexport const ImportExcel = forwardRef<HTMLInputElement, ImportExcelProps>((props, ref) => {\r\n const { onChange, ...rest } = props\r\n\r\n function onInputChange(data: InputFileData<ArrayBuffer>) {\r\n const wb = read(data.result)\r\n const result = utils.sheet_to_json<any>(wb.Sheets[wb.SheetNames[0]])\r\n if (typeof result === \"object\") {\r\n const $ = result.map(it => {\r\n const _: Record<string, string> = {}\r\n Object.keys(it)\r\n .filter(key => key !== \"__rowNum__\")\r\n .forEach(key => (_[key] = String(it[key])))\r\n return _\r\n })\r\n onChange?.($)\r\n }\r\n }\r\n\r\n return <InputFile ref={ref} accept=\".xlsx\" type=\"arrayBuffer\" onChange={onInputChange} {...rest} />\r\n})\r\n\r\n/** 手动导出 excel */\r\nexport function exportExcel(data: Record<string, string>[], name: string) {\r\n const workSheet = utils.json_to_sheet(data)\r\n const workBook = utils.book_new()\r\n utils.book_append_sheet(workBook, workSheet)\r\n writeFile(workBook, `${name}${name.endsWith(\".xlsx\") ? \"\" : \".xlsx\"}`)\r\n}\r\n\r\nexport interface ExportExcelProps extends ButtonHTMLAttributes<HTMLButtonElement> {\r\n data: Record<string, string>[]\r\n fileName: string\r\n}\r\n\r\n/** 导出 excel 的 button 组件 */\r\nexport const ExportExcel = forwardRef<HTMLButtonElement, ExportExcelProps>((props, ref) => {\r\n const { data, fileName, onClick, ...rest } = props\r\n\r\n function onButtonClick(e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) {\r\n exportExcel(data, fileName)\r\n onClick?.(e)\r\n }\r\n\r\n return <button ref={ref} onClick={onButtonClick} {...rest} />\r\n})\r\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["Fragment","forwardRef","useRef","useState","read","utils","writeFile","jsx","_jsx","jsxs","_jsxs","getFileData","file","type","fileReader","FileReader","readAsArrayBuffer","readAsBinaryString","readAsDataURL","readAsText","Promise","resolve","addEventListener","result","InputFile","props","ref","multiple","onChange","disabled","inputDisabled","clearAfterChange","rest","setDisabled","onInputChange","e","input","target","files","length","Array","from","push","value","InputFileButton","onClick","_onClick","inputProps","onDrop","_onDrop","onDragOver","_onDragOver","dragFile","_disabled","style","__disabled","restInputProps","current","click","preventDefault","dataTransfer","children","display","ImportExcel","data","wb","sheet_to_json","Sheets","SheetNames","$","map","it","_","Object","keys","filter","key","forEach","String","accept","exportExcel","name","workSheet","json_to_sheet","workBook","book_new","book_append_sheet","endsWith","ExportExcel","fileName","onButtonClick"],"sources":["../../../src/components/InputFile.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport { ButtonHTMLAttributes, ChangeEvent, Fragment, InputHTMLAttributes, MouseEvent as ReactMouseEvent, forwardRef, useRef, useState, DragEvent } from \"react\"\r\nimport { read, utils, writeFile } from \"xlsx\"\r\n\r\nexport interface InputFileDataTypes {\r\n base64: string\r\n text: string\r\n arrayBuffer: ArrayBuffer\r\n binary: string\r\n file: File\r\n}\r\n\r\nexport type InputFileDataType = keyof InputFileDataTypes\r\n\r\nexport interface InputFileData<T> {\r\n result: T\r\n file: File\r\n}\r\n\r\nexport type InputFileProps = (\r\n | {\r\n multiple?: false\r\n type: \"base64\" | \"text\" | \"binary\"\r\n onChange?: (data: InputFileData<string>) => void\r\n }\r\n | {\r\n multiple?: false\r\n type: \"arrayBuffer\"\r\n onChange?: (data: InputFileData<ArrayBuffer>) => void\r\n }\r\n | {\r\n multiple?: false\r\n type?: \"file\"\r\n onChange?: (data: InputFileData<File>) => void\r\n }\r\n | {\r\n multiple: true\r\n type: \"base64\" | \"text\" | \"binary\"\r\n onChange?: (data: InputFileData<string>[]) => void\r\n }\r\n | {\r\n multiple: true\r\n type: \"arrayBuffer\"\r\n onChange?: (data: InputFileData<ArrayBuffer>[]) => void\r\n }\r\n | {\r\n multiple: true\r\n type?: \"file\"\r\n onChange?: (data: InputFileData<File>[]) => void\r\n }\r\n) &\r\n Omit<InputHTMLAttributes<HTMLInputElement>, \"onChange\" | \"multiple\" | \"type\"> & {\r\n /** 是否在捕获文件后清除 input 上的文件,默认为 false,主要区别在于如果不清除,连续两次选择同样的文件不会触发 onChange 事件,如果用于 form 表单,请设置为 flase */\r\n clearAfterChange?: boolean\r\n }\r\n\r\nexport async function getFileData<T extends InputFileDataType>(file: File, type: T): Promise<InputFileDataTypes[T]> {\r\n const fileReader = new FileReader()\r\n switch (type) {\r\n case \"arrayBuffer\":\r\n fileReader.readAsArrayBuffer(file)\r\n break\r\n case \"binary\":\r\n fileReader.readAsBinaryString(file)\r\n break\r\n case \"base64\":\r\n fileReader.readAsDataURL(file)\r\n break\r\n case \"text\":\r\n fileReader.readAsText(file)\r\n break\r\n default:\r\n return file as any\r\n }\r\n return new Promise(resolve => {\r\n fileReader.addEventListener(\"load\", () => {\r\n resolve(fileReader.result as any)\r\n })\r\n })\r\n}\r\n\r\n/** 专用于读取文件的组件 */\r\nexport const InputFile = forwardRef<HTMLInputElement, InputFileProps>((props, ref) => {\r\n const { multiple = false, type = \"file\", onChange, disabled: inputDisabled, clearAfterChange, ...rest } = props\r\n const [disabled, setDisabled] = useState(false)\r\n\r\n async function onInputChange(e: ChangeEvent<HTMLInputElement>) {\r\n const input = e.target\r\n const { files } = input\r\n if (!files || files.length === 0) return\r\n setDisabled(true)\r\n try {\r\n if (multiple) {\r\n const result: any[] = []\r\n for (const file of Array.from(files)) {\r\n result.push({\r\n result: await getFileData(file, type),\r\n file\r\n })\r\n }\r\n onChange?.(result as any)\r\n } else {\r\n onChange?.({\r\n result: await getFileData(files[0], type),\r\n file: files[0]\r\n } as any)\r\n }\r\n } finally {\r\n if (clearAfterChange) input.value = \"\"\r\n setDisabled(false)\r\n }\r\n }\r\n\r\n return <input ref={ref} disabled={disabled || inputDisabled} type=\"file\" multiple={multiple} onChange={onInputChange} {...rest} />\r\n})\r\n\r\nexport type InputFileButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {\r\n input: InputFileProps\r\n dragFile?: boolean\r\n}\r\n\r\n/** 专用于读取文件的 button 组件 */\r\nexport const InputFileButton = forwardRef<HTMLButtonElement, InputFileButtonProps>((props, ref) => {\r\n const { onClick: _onClick, input: inputProps, onDrop: _onDrop, onDragOver: _onDragOver, dragFile, disabled: _disabled, ...rest } = props\r\n const { style, disabled: __disabled, multiple, onChange, type = \"file\", ...restInputProps } = inputProps\r\n const [disabled, setDisabled] = useState(false)\r\n const input = useRef<HTMLInputElement>(null)\r\n\r\n function onClick(e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) {\r\n input.current?.click()\r\n _onClick?.(e)\r\n }\r\n\r\n async function onDrop(e: DragEvent<HTMLButtonElement>) {\r\n _onDrop?.(e)\r\n if (disabled || !dragFile) return\r\n e.preventDefault()\r\n const { files } = e.dataTransfer\r\n if (!files || files.length === 0) return\r\n setDisabled(true)\r\n try {\r\n if (multiple) {\r\n const result: any[] = []\r\n for (const file of Array.from(files)) {\r\n result.push({\r\n result: await getFileData(file, type),\r\n file\r\n })\r\n }\r\n onChange?.(result as any)\r\n } else {\r\n onChange?.({\r\n result: await getFileData(files[0], type),\r\n file: files[0]\r\n } as any)\r\n }\r\n } finally {\r\n setDisabled(false)\r\n }\r\n }\r\n\r\n function onDragOver(e: DragEvent<HTMLButtonElement>) {\r\n _onDragOver?.(e)\r\n if (disabled || !dragFile) return\r\n e.preventDefault()\r\n }\r\n\r\n return (\r\n <Fragment>\r\n <InputFile\r\n ref={input}\r\n disabled={disabled || _disabled || __disabled}\r\n style={{ display: \"none\", ...style }}\r\n multiple={multiple as any}\r\n onChange={onChange as any}\r\n type={type as any}\r\n {...restInputProps}\r\n />\r\n <button ref={ref} type=\"button\" disabled={disabled || _disabled} onClick={onClick} onDrop={onDrop} onDragOver={onDragOver} {...rest} />\r\n </Fragment>\r\n )\r\n})\r\n\r\nexport interface ImportExcelProps extends Omit<InputFileProps, \"multiple\" | \"onChange\" | \"accept\" | \"type\"> {\r\n onChange?: (data: Record<string, string>[]) => void\r\n}\r\n\r\n/** 专门用于读取 excel 的组件 */\r\nexport const ImportExcel = forwardRef<HTMLInputElement, ImportExcelProps>((props, ref) => {\r\n const { onChange, ...rest } = props\r\n\r\n function onInputChange(data: InputFileData<ArrayBuffer>) {\r\n const wb = read(data.result)\r\n const result = utils.sheet_to_json<any>(wb.Sheets[wb.SheetNames[0]])\r\n if (typeof result === \"object\") {\r\n const $ = result.map(it => {\r\n const _: Record<string, string> = {}\r\n Object.keys(it)\r\n .filter(key => key !== \"__rowNum__\")\r\n .forEach(key => (_[key] = String(it[key])))\r\n return _\r\n })\r\n onChange?.($)\r\n }\r\n }\r\n\r\n return <InputFile ref={ref} accept=\".xlsx\" type=\"arrayBuffer\" onChange={onInputChange} {...rest} />\r\n})\r\n\r\n/** 手动导出 excel */\r\nexport function exportExcel(data: Record<string, string>[], name: string) {\r\n const workSheet = utils.json_to_sheet(data)\r\n const workBook = utils.book_new()\r\n utils.book_append_sheet(workBook, workSheet)\r\n writeFile(workBook, `${name}${name.endsWith(\".xlsx\") ? \"\" : \".xlsx\"}`)\r\n}\r\n\r\nexport interface ExportExcelProps extends ButtonHTMLAttributes<HTMLButtonElement> {\r\n data: Record<string, string>[]\r\n fileName: string\r\n}\r\n\r\n/** 导出 excel 的 button 组件 */\r\nexport const ExportExcel = forwardRef<HTMLButtonElement, ExportExcelProps>((props, ref) => {\r\n const { data, fileName, onClick, ...rest } = props\r\n\r\n function onButtonClick(e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) {\r\n exportExcel(data, fileName)\r\n onClick?.(e)\r\n }\r\n\r\n return <button ref={ref} onClick={onButtonClick} {...rest} />\r\n})\r\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
-
import { ButtonHTMLAttributes, ChangeEvent, Fragment, InputHTMLAttributes, MouseEvent as ReactMouseEvent, forwardRef, useRef, useState } from "react"
|
|
3
|
+
import { ButtonHTMLAttributes, ChangeEvent, Fragment, InputHTMLAttributes, MouseEvent as ReactMouseEvent, forwardRef, useRef, useState, DragEvent } from "react"
|
|
4
4
|
import { read, utils, writeFile } from "xlsx"
|
|
5
5
|
|
|
6
6
|
export interface InputFileDataTypes {
|
|
@@ -106,12 +106,9 @@ export const InputFile = forwardRef<HTMLInputElement, InputFileProps>((props, re
|
|
|
106
106
|
file: files[0]
|
|
107
107
|
} as any)
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
} finally {
|
|
110
110
|
if (clearAfterChange) input.value = ""
|
|
111
|
-
} catch (error) {
|
|
112
111
|
setDisabled(false)
|
|
113
|
-
if (clearAfterChange) input.value = ""
|
|
114
|
-
throw error
|
|
115
112
|
}
|
|
116
113
|
}
|
|
117
114
|
|
|
@@ -120,23 +117,67 @@ export const InputFile = forwardRef<HTMLInputElement, InputFileProps>((props, re
|
|
|
120
117
|
|
|
121
118
|
export type InputFileButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
122
119
|
input: InputFileProps
|
|
120
|
+
dragFile?: boolean
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
/** 专用于读取文件的 button 组件 */
|
|
126
124
|
export const InputFileButton = forwardRef<HTMLButtonElement, InputFileButtonProps>((props, ref) => {
|
|
127
|
-
const { onClick, input: inputProps, ...rest } = props
|
|
128
|
-
const { style, ...restInputProps } = inputProps
|
|
125
|
+
const { onClick: _onClick, input: inputProps, onDrop: _onDrop, onDragOver: _onDragOver, dragFile, disabled: _disabled, ...rest } = props
|
|
126
|
+
const { style, disabled: __disabled, multiple, onChange, type = "file", ...restInputProps } = inputProps
|
|
127
|
+
const [disabled, setDisabled] = useState(false)
|
|
129
128
|
const input = useRef<HTMLInputElement>(null)
|
|
130
129
|
|
|
131
|
-
function
|
|
130
|
+
function onClick(e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) {
|
|
132
131
|
input.current?.click()
|
|
133
|
-
|
|
132
|
+
_onClick?.(e)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function onDrop(e: DragEvent<HTMLButtonElement>) {
|
|
136
|
+
_onDrop?.(e)
|
|
137
|
+
if (disabled || !dragFile) return
|
|
138
|
+
e.preventDefault()
|
|
139
|
+
const { files } = e.dataTransfer
|
|
140
|
+
if (!files || files.length === 0) return
|
|
141
|
+
setDisabled(true)
|
|
142
|
+
try {
|
|
143
|
+
if (multiple) {
|
|
144
|
+
const result: any[] = []
|
|
145
|
+
for (const file of Array.from(files)) {
|
|
146
|
+
result.push({
|
|
147
|
+
result: await getFileData(file, type),
|
|
148
|
+
file
|
|
149
|
+
})
|
|
150
|
+
}
|
|
151
|
+
onChange?.(result as any)
|
|
152
|
+
} else {
|
|
153
|
+
onChange?.({
|
|
154
|
+
result: await getFileData(files[0], type),
|
|
155
|
+
file: files[0]
|
|
156
|
+
} as any)
|
|
157
|
+
}
|
|
158
|
+
} finally {
|
|
159
|
+
setDisabled(false)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function onDragOver(e: DragEvent<HTMLButtonElement>) {
|
|
164
|
+
_onDragOver?.(e)
|
|
165
|
+
if (disabled || !dragFile) return
|
|
166
|
+
e.preventDefault()
|
|
134
167
|
}
|
|
135
168
|
|
|
136
169
|
return (
|
|
137
170
|
<Fragment>
|
|
138
|
-
<InputFile
|
|
139
|
-
|
|
171
|
+
<InputFile
|
|
172
|
+
ref={input}
|
|
173
|
+
disabled={disabled || _disabled || __disabled}
|
|
174
|
+
style={{ display: "none", ...style }}
|
|
175
|
+
multiple={multiple as any}
|
|
176
|
+
onChange={onChange as any}
|
|
177
|
+
type={type as any}
|
|
178
|
+
{...restInputProps}
|
|
179
|
+
/>
|
|
180
|
+
<button ref={ref} type="button" disabled={disabled || _disabled} onClick={onClick} onDrop={onDrop} onDragOver={onDragOver} {...rest} />
|
|
140
181
|
</Fragment>
|
|
141
182
|
)
|
|
142
183
|
})
|