@akinon/ui-upload 0.3.0 → 1.0.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/index.css +89 -0
- package/dist/cjs/index.d.ts +14 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +64 -2
- package/dist/cjs/item.d.ts +15 -0
- package/dist/cjs/item.d.ts.map +1 -0
- package/dist/cjs/item.js +45 -0
- package/dist/cjs/types.d.ts +311 -0
- package/dist/esm/index.css +89 -0
- package/dist/esm/index.d.ts +14 -3
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +51 -3
- package/dist/esm/item.d.ts +15 -0
- package/dist/esm/item.d.ts.map +1 -0
- package/dist/esm/item.js +42 -0
- package/dist/esm/types.d.ts +311 -0
- package/package.json +12 -5
package/dist/cjs/index.css
CHANGED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/* TODO: use antd useStyleRegister */
|
|
2
|
+
|
|
3
|
+
.akinon-upload.akinon-upload-select {
|
|
4
|
+
cursor: pointer;
|
|
5
|
+
flex: 1;
|
|
6
|
+
width: 100%;
|
|
7
|
+
/* TODO: use antd tokens */
|
|
8
|
+
padding: 10px 20px;
|
|
9
|
+
font-weight: 600;
|
|
10
|
+
background-color: var(--color-ebonyClay-475);
|
|
11
|
+
border-radius: 5px;
|
|
12
|
+
background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' stroke='black' stroke-width='4' stroke-dasharray='6%2c 12' stroke-dashoffset='0' stroke-linecap='square'/%3e%3c/svg%3e");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.akinon-upload.akinon-upload-select:not(:has(.akinon-upload-list-item)) {
|
|
16
|
+
max-width: 300px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.akinon-upload-wrapper
|
|
20
|
+
.akinon-upload-list:not(.akinon-upload-list-picture-card) {
|
|
21
|
+
line-height: 0;
|
|
22
|
+
max-width: 300px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.akinon-upload-wrapper
|
|
26
|
+
.akinon-upload-list:not(.akinon-upload-list-picture-card)
|
|
27
|
+
.akinon-upload-list-item {
|
|
28
|
+
/* TODO: use antd tokens */
|
|
29
|
+
border-radius: 5px;
|
|
30
|
+
height: unset;
|
|
31
|
+
padding: 10px 20px;
|
|
32
|
+
background-color: var(--color-ebonyClay-550);
|
|
33
|
+
font-size: 14px;
|
|
34
|
+
font-weight: 600;
|
|
35
|
+
gap: 10px;
|
|
36
|
+
align-items: center;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.akinon-upload-wrapper
|
|
40
|
+
.akinon-upload-list:not(.akinon-upload-list-picture-card)
|
|
41
|
+
.akinon-upload-list-item
|
|
42
|
+
.akinon-upload-list-item-name {
|
|
43
|
+
white-space: normal;
|
|
44
|
+
word-break: break-all;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.akinon-upload-wrapper.akinon-upload-picture-card-wrapper
|
|
48
|
+
.akinon-upload-list.akinon-upload-list-picture-card
|
|
49
|
+
.akinon-upload-list-item {
|
|
50
|
+
/* TODO: use antd tokens */
|
|
51
|
+
border-radius: 0;
|
|
52
|
+
border: 2px solid var(--color-neutral-350);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.akinon-upload-wrapper.akinon-upload-picture-card-wrapper
|
|
56
|
+
.akinon-upload-list.akinon-upload-list-picture-card
|
|
57
|
+
.akinon-upload-list-item-error {
|
|
58
|
+
border-color: var(--color-red-500);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.akinon-upload-wrapper.akinon-upload-picture-card-wrapper
|
|
62
|
+
.akinon-upload-list.akinon-upload-list-picture-card
|
|
63
|
+
.akinon-upload-list-item::before {
|
|
64
|
+
display: none;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.akinon-upload-wrapper.akinon-upload-picture-card-wrapper
|
|
68
|
+
.akinon-upload-list.akinon-upload-list-picture-card
|
|
69
|
+
.akinon-upload-list-item-actions {
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
width: fit-content;
|
|
72
|
+
inset: auto 6px 6px auto;
|
|
73
|
+
background-color: rgba(255, 255, 255, 0.5);
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
border-radius: 100%;
|
|
78
|
+
height: 18px;
|
|
79
|
+
width: 18px;
|
|
80
|
+
font-size: 12px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.akinon-upload-wrapper
|
|
84
|
+
.akinon-upload-list
|
|
85
|
+
.akinon-upload-list-item
|
|
86
|
+
.akinon-upload-list-item-actions
|
|
87
|
+
.akinon-upload-list-item-action {
|
|
88
|
+
opacity: 1;
|
|
89
|
+
}
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import './index.css';
|
|
2
2
|
import type { UploadProps as AntUploadProps } from 'antd';
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
|
|
4
|
+
import type { UploadProps } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* Upload component for Akinon UI.
|
|
7
|
+
*
|
|
8
|
+
* The Upload component provides an interface for users to upload files.
|
|
9
|
+
* It supports various configurations like drag-and-drop, previewing files,
|
|
10
|
+
* and customizing request methods. The component is designed to handle multiple
|
|
11
|
+
* file types and offers flexibility for integrating with server-side logic.
|
|
12
|
+
*
|
|
13
|
+
* The component adheres to the Akinon design system, ensuring consistency across applications.
|
|
14
|
+
*/
|
|
5
15
|
declare const Upload: {
|
|
6
|
-
(
|
|
16
|
+
(props: UploadProps): React.JSX.Element;
|
|
7
17
|
Dragger: React.ForwardRefExoticComponent<AntUploadProps<any> & {
|
|
8
|
-
height?: number
|
|
18
|
+
height?: number;
|
|
9
19
|
} & React.RefAttributes<import("antd/es/upload/Upload").UploadRef<any>>>;
|
|
10
20
|
};
|
|
11
21
|
export { Upload };
|
|
22
|
+
export * from './types.d';
|
|
12
23
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/cjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAKrB,OAAO,KAAK,EAAE,WAAW,IAAI,cAAc,EAAE,MAAM,MAAM,CAAC;AAE1D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;;;;;;;GASG;AAEH,QAAA,MAAM,MAAM;YAAW,WAAW;;;;CAiEjC,CAAC;AAGF,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,cAAc,WAAW,CAAC"}
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,11 +1,73 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
17
|
exports.Upload = void 0;
|
|
4
18
|
require("./index.css");
|
|
19
|
+
const ui_image_1 = require("@akinon/ui-image");
|
|
20
|
+
const ui_theme_1 = require("@akinon/ui-theme");
|
|
21
|
+
const cssinjs_1 = require("@ant-design/cssinjs");
|
|
5
22
|
const antd_1 = require("antd");
|
|
6
23
|
const React = require("react");
|
|
7
|
-
const
|
|
8
|
-
|
|
24
|
+
const item_1 = require("./item");
|
|
25
|
+
/**
|
|
26
|
+
* Upload component for Akinon UI.
|
|
27
|
+
*
|
|
28
|
+
* The Upload component provides an interface for users to upload files.
|
|
29
|
+
* It supports various configurations like drag-and-drop, previewing files,
|
|
30
|
+
* and customizing request methods. The component is designed to handle multiple
|
|
31
|
+
* file types and offers flexibility for integrating with server-side logic.
|
|
32
|
+
*
|
|
33
|
+
* The component adheres to the Akinon design system, ensuring consistency across applications.
|
|
34
|
+
*/
|
|
35
|
+
const Upload = (props) => {
|
|
36
|
+
const { getPrefixCls, theme } = React.useContext(antd_1.ConfigProvider.ConfigContext);
|
|
37
|
+
const { token, hashId } = (0, ui_theme_1.useToken)();
|
|
38
|
+
const uploadToken = token.Upload;
|
|
39
|
+
const prefixClsWithoutHash = `${getPrefixCls()}-upload`;
|
|
40
|
+
const prefixCls = `:where(.${hashId}).${prefixClsWithoutHash}`;
|
|
41
|
+
const useStyle = (0, cssinjs_1.useStyleRegister)({
|
|
42
|
+
token: token,
|
|
43
|
+
path: ['Upload'],
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
|
+
theme: theme
|
|
46
|
+
}, () => {
|
|
47
|
+
return {
|
|
48
|
+
[`${prefixCls}-wrapper`]: {
|
|
49
|
+
[`.${prefixClsWithoutHash}-list`]: {
|
|
50
|
+
'&-item-error-border': {
|
|
51
|
+
border: `1px solid ${uploadToken === null || uploadToken === void 0 ? void 0 : uploadToken.colorError}`
|
|
52
|
+
},
|
|
53
|
+
'&-item-actions': {
|
|
54
|
+
'.anticon.anticon-delete': {
|
|
55
|
+
display: 'inline-block',
|
|
56
|
+
textAlign: 'center',
|
|
57
|
+
svg: {
|
|
58
|
+
color: 'black',
|
|
59
|
+
height: '12px',
|
|
60
|
+
width: '12px'
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
return useStyle(React.createElement(ui_image_1.Image.PreviewGroup, null,
|
|
69
|
+
React.createElement(antd_1.Upload, Object.assign({ fileList: props.fileList, itemRender: (originNode, file, fileList, actions) => (React.createElement(item_1.UploadItem, { props: Object.assign({ listType: 'text' }, props), originNode: originNode, file: file, fileList: fileList, actions: actions, prefixClsWithoutHash: prefixClsWithoutHash, onPreview: props.onPreview })) }, props))));
|
|
9
70
|
};
|
|
10
71
|
exports.Upload = Upload;
|
|
11
72
|
Upload.Dragger = antd_1.Upload.Dragger;
|
|
73
|
+
__exportStar(require("./types.d"), exports);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { UploadItemProps } from './types';
|
|
3
|
+
declare const componentMap: {
|
|
4
|
+
readonly 'picture-card': typeof ImageItem;
|
|
5
|
+
readonly text: typeof TextItem;
|
|
6
|
+
};
|
|
7
|
+
export declare function UploadItem({ props, originNode, file, fileList, actions, prefixClsWithoutHash, onPreview, Component }: UploadItemProps & {
|
|
8
|
+
Component?: (typeof componentMap)[keyof typeof componentMap] | React.ComponentType<UploadItemProps & {
|
|
9
|
+
akinonNode: (typeof componentMap)[keyof typeof componentMap];
|
|
10
|
+
}>;
|
|
11
|
+
}): React.JSX.Element;
|
|
12
|
+
declare function ImageItem({ file, onPreview, prefixClsWithoutHash, actions, originNode }: UploadItemProps): React.JSX.Element;
|
|
13
|
+
declare function TextItem({ file, prefixClsWithoutHash, actions }: UploadItemProps): React.JSX.Element;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=item.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"item.d.ts","sourceRoot":"","sources":["../../src/item.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,QAAA,MAAM,YAAY;;;CAGR,CAAC;AAEX,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,oBAAoB,EACpB,SAAS,EACT,SAAqE,EACtE,EAAE,eAAe,GAAG;IACnB,SAAS,CAAC,EACN,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,GAChD,KAAK,CAAC,aAAa,CACjB,eAAe,GAAG;QAChB,UAAU,EAAE,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;KAC9D,CACF,CAAC;CACP,qBAiBA;AAED,iBAAS,SAAS,CAAC,EACjB,IAAI,EACJ,SAAS,EACT,oBAAoB,EACpB,OAAO,EACP,UAAU,EACX,EAAE,eAAe,qBA2BjB;AAED,iBAAS,QAAQ,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,EAAE,eAAe,qBA4CzE"}
|
package/dist/cjs/item.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UploadItem = UploadItem;
|
|
4
|
+
const icons_1 = require("@akinon/icons");
|
|
5
|
+
const ui_image_1 = require("@akinon/ui-image");
|
|
6
|
+
const ui_layout_1 = require("@akinon/ui-layout");
|
|
7
|
+
const ui_tooltip_1 = require("@akinon/ui-tooltip");
|
|
8
|
+
const clsx_1 = require("clsx");
|
|
9
|
+
const react_1 = require("react");
|
|
10
|
+
const componentMap = {
|
|
11
|
+
'picture-card': ImageItem,
|
|
12
|
+
text: TextItem
|
|
13
|
+
};
|
|
14
|
+
function UploadItem({ props, originNode, file, fileList, actions, prefixClsWithoutHash, onPreview, Component = componentMap[props.listType] }) {
|
|
15
|
+
if (Component) {
|
|
16
|
+
return (react_1.default.createElement(Component, { akinonNode: componentMap[props.listType], originNode: originNode, props: props, file: file, fileList: fileList, actions: actions, prefixClsWithoutHash: prefixClsWithoutHash, onPreview: onPreview }));
|
|
17
|
+
}
|
|
18
|
+
return originNode;
|
|
19
|
+
}
|
|
20
|
+
function ImageItem({ file, onPreview, prefixClsWithoutHash, actions, originNode }) {
|
|
21
|
+
return file.thumbUrl ? (react_1.default.createElement("div", { className: (0, clsx_1.default)(`${prefixClsWithoutHash}-list-item`, `${prefixClsWithoutHash}-list-item-${file.status}-border`), onClick: () => {
|
|
22
|
+
actions.preview();
|
|
23
|
+
} },
|
|
24
|
+
react_1.default.createElement(ui_image_1.Image, Object.assign({ src: file.thumbUrl }, (onPreview && { preview: false }))),
|
|
25
|
+
react_1.default.createElement("div", { className: `${prefixClsWithoutHash}-list-item-actions` },
|
|
26
|
+
react_1.default.createElement(icons_1.Icon, { icon: "bin", size: 12, color: "black", onClick: e => {
|
|
27
|
+
e.stopPropagation();
|
|
28
|
+
actions.remove();
|
|
29
|
+
} })))) : (originNode);
|
|
30
|
+
}
|
|
31
|
+
function TextItem({ file, prefixClsWithoutHash, actions }) {
|
|
32
|
+
return (react_1.default.createElement("div", { className: (0, clsx_1.default)(`${prefixClsWithoutHash}-list-item`, `${prefixClsWithoutHash}-list-item-${file.status}-border`) },
|
|
33
|
+
react_1.default.createElement(ui_layout_1.Flex, { flex: 1, justify: "between", align: "center", gap: 8 },
|
|
34
|
+
react_1.default.createElement(ui_layout_1.Flex, { align: "center", gap: 10, flex: 1 },
|
|
35
|
+
react_1.default.createElement("div", { className: `${prefixClsWithoutHash}-list-item-actions` },
|
|
36
|
+
react_1.default.createElement(icons_1.Icon, { cursor: "pointer", icon: "bin", size: 13, color: "var(--color-azure-500)", onClick: e => {
|
|
37
|
+
e.stopPropagation();
|
|
38
|
+
actions.remove();
|
|
39
|
+
} })),
|
|
40
|
+
react_1.default.createElement("div", { className: `${prefixClsWithoutHash}-list-item-name` }, file.name)),
|
|
41
|
+
file.status === 'error' && (
|
|
42
|
+
// TODO: pass proper error messages
|
|
43
|
+
react_1.default.createElement(ui_tooltip_1.Tooltip, { title: "Error" },
|
|
44
|
+
react_1.default.createElement(icons_1.Icon, { className: (0, clsx_1.default)(`${prefixClsWithoutHash}-list-item-${file.status}`), icon: "warning_tri", size: 13, color: "var(--color-azure-500)" }))))));
|
|
45
|
+
}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import type { IProgressProps } from '@akinon/ui-progress';
|
|
2
|
+
import { DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE } from '@akinon/ui-theme';
|
|
3
|
+
import type { UploadFile } from 'antd';
|
|
4
|
+
|
|
5
|
+
export type UploadItemProps = RenderedItemProps & {
|
|
6
|
+
/**
|
|
7
|
+
* Props of the upload component.
|
|
8
|
+
*/
|
|
9
|
+
props: UploadProps;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The original React node for the upload item.
|
|
13
|
+
*/
|
|
14
|
+
originNode: React.ReactElement;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type UploadMethod = 'POST' | 'PUT' | 'PATCH' | 'post' | 'put' | 'patch';
|
|
18
|
+
|
|
19
|
+
export type UploadListType =
|
|
20
|
+
| 'text'
|
|
21
|
+
| 'picture'
|
|
22
|
+
| 'picture-card'
|
|
23
|
+
| 'picture-circle';
|
|
24
|
+
|
|
25
|
+
export interface UploadProps
|
|
26
|
+
extends Omit<
|
|
27
|
+
React.InputHTMLAttributes<HTMLInputElement>,
|
|
28
|
+
'onError' | 'onProgress'
|
|
29
|
+
> {
|
|
30
|
+
/**
|
|
31
|
+
* Whether to control the component internally.
|
|
32
|
+
*/
|
|
33
|
+
hasControlInside?: boolean;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The type of the upload input.
|
|
37
|
+
*/
|
|
38
|
+
type?: 'drag' | 'select';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The name attribute for the file input.
|
|
42
|
+
*/
|
|
43
|
+
name?: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Default list of files.
|
|
47
|
+
*/
|
|
48
|
+
defaultFileList?: UploadFile[];
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Controlled file list.
|
|
52
|
+
*/
|
|
53
|
+
fileList?: UploadFile[];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The URL or function that returns the URL for uploading files.
|
|
57
|
+
*/
|
|
58
|
+
action?: string | ((file: UploadFile) => string | PromiseLike<string>);
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Whether to enable directory upload.
|
|
62
|
+
*/
|
|
63
|
+
directory?: boolean;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Additional data to include in the upload request.
|
|
67
|
+
*/
|
|
68
|
+
data?:
|
|
69
|
+
| Record<string, unknown>
|
|
70
|
+
| ((
|
|
71
|
+
file: UploadFile
|
|
72
|
+
) => Record<string, unknown> | Promise<Record<string, unknown>>);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* HTTP method to use for the upload request.
|
|
76
|
+
*/
|
|
77
|
+
method?: UploadMethod;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Custom headers for the upload request.
|
|
81
|
+
*/
|
|
82
|
+
headers?: Record<string, string>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Configuration for displaying the upload list.
|
|
86
|
+
*/
|
|
87
|
+
showUploadList?:
|
|
88
|
+
| boolean
|
|
89
|
+
| {
|
|
90
|
+
showRemoveIcon?: boolean;
|
|
91
|
+
showPreviewIcon?: boolean;
|
|
92
|
+
showDownloadIcon?: boolean;
|
|
93
|
+
removeIcon?: React.ReactNode | ((file: UploadFile) => React.ReactNode);
|
|
94
|
+
downloadIcon?:
|
|
95
|
+
| React.ReactNode
|
|
96
|
+
| ((file: UploadFile) => React.ReactNode);
|
|
97
|
+
previewIcon?: React.ReactNode | ((file: UploadFile) => React.ReactNode);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Whether to allow uploading multiple files.
|
|
102
|
+
*/
|
|
103
|
+
multiple?: boolean;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The file types that can be uploaded.
|
|
107
|
+
*/
|
|
108
|
+
accept?: string;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Function called before uploading a file.
|
|
112
|
+
*/
|
|
113
|
+
beforeUpload?: (
|
|
114
|
+
file: UploadFile,
|
|
115
|
+
FileList: UploadFile[]
|
|
116
|
+
) =>
|
|
117
|
+
| void
|
|
118
|
+
| boolean
|
|
119
|
+
| string
|
|
120
|
+
| Blob
|
|
121
|
+
| File
|
|
122
|
+
| Promise<void | boolean | string | Blob | File>;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Function called when the file list changes.
|
|
126
|
+
*/
|
|
127
|
+
onChange?: (info: {
|
|
128
|
+
file: UploadFile;
|
|
129
|
+
fileList: UploadFile[];
|
|
130
|
+
event?: {
|
|
131
|
+
percent: number;
|
|
132
|
+
};
|
|
133
|
+
}) => void;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Function called when a file is dropped into the upload area.
|
|
137
|
+
*/
|
|
138
|
+
onDrop?: (event: React.DragEvent<HTMLDivElement>) => void;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Additional class name for the upload component.
|
|
142
|
+
*/
|
|
143
|
+
className?: string;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Root class name for the upload component.
|
|
147
|
+
*/
|
|
148
|
+
rootClassName?: string;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Function called to preview a file.
|
|
152
|
+
*/
|
|
153
|
+
onPreview?: (file: UploadFile) => void;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Function called to download a file.
|
|
157
|
+
*/
|
|
158
|
+
onDownload?: (file: UploadFile) => void;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Function called to remove a file.
|
|
162
|
+
*/
|
|
163
|
+
onRemove?: (file: UploadFile) => void | boolean | Promise<void | boolean>;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Whether to support server-side rendering.
|
|
167
|
+
*/
|
|
168
|
+
supportServerRender?: boolean;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Whether the upload input is disabled.
|
|
172
|
+
*/
|
|
173
|
+
disabled?: boolean;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Custom request function for handling uploads.
|
|
177
|
+
*/
|
|
178
|
+
customRequest?: (options: {
|
|
179
|
+
onProgress?: (event: Partial<ProgressEvent> & { percent?: number }) => void;
|
|
180
|
+
onError?: (
|
|
181
|
+
event:
|
|
182
|
+
| (Error & {
|
|
183
|
+
status?: number;
|
|
184
|
+
method?: UploadMethod;
|
|
185
|
+
})
|
|
186
|
+
| ProgressEvent,
|
|
187
|
+
body?: UploadFile
|
|
188
|
+
) => void;
|
|
189
|
+
onSuccess?: (body: UploadFile, xhr?: XMLHttpRequest) => void;
|
|
190
|
+
data?: Record<string, unknown>;
|
|
191
|
+
filename?: string;
|
|
192
|
+
file: void | string | Blob | UploadFile['originFileObj'];
|
|
193
|
+
withCredentials?: boolean;
|
|
194
|
+
action: string;
|
|
195
|
+
headers?: Record<string, string>;
|
|
196
|
+
method: UploadMethod;
|
|
197
|
+
}) => void;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Whether to send credentials with the upload request.
|
|
201
|
+
*/
|
|
202
|
+
withCredentials?: boolean;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Whether to open the file dialog when clicking on the upload area.
|
|
206
|
+
*/
|
|
207
|
+
openFileDialogOnClick?: boolean;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Locale strings for the upload component.
|
|
211
|
+
*/
|
|
212
|
+
locale?: {
|
|
213
|
+
uploading?: string;
|
|
214
|
+
removeFile?: string;
|
|
215
|
+
downloadFile?: string;
|
|
216
|
+
uploadError?: string;
|
|
217
|
+
previewFile?: string;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* ID for the upload component.
|
|
222
|
+
*/
|
|
223
|
+
id?: string;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Function to generate a preview for a file.
|
|
227
|
+
*/
|
|
228
|
+
previewFile?: (file: File | Blob) => PromiseLike<string>;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Function to render a custom icon for a file.
|
|
232
|
+
*/
|
|
233
|
+
iconRender?: (file: UploadFile, listType?: UploadListType) => React.ReactNode;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Function to determine if a file is an image.
|
|
237
|
+
*/
|
|
238
|
+
isImageUrl?: (file: UploadFile) => boolean;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Progress bar properties for the upload component.
|
|
242
|
+
*/
|
|
243
|
+
progress?: Omit<IProgressProps, 'percent' | 'type'>;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Function to render a custom item in the upload list.
|
|
247
|
+
*/
|
|
248
|
+
itemRender?: Omit<RenderedItemProps, 'prefixClsWithoutHash' | 'onPreview'>;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Maximum number of files that can be uploaded.
|
|
252
|
+
*/
|
|
253
|
+
maxCount?: number;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Child elements to render within the upload component.
|
|
257
|
+
*/
|
|
258
|
+
children?: React.ReactNode;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Type of upload list to display.
|
|
262
|
+
*/
|
|
263
|
+
listType?: UploadListType;
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* @ignore
|
|
267
|
+
*/
|
|
268
|
+
style?: DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export type RenderedItemProps = {
|
|
272
|
+
/**
|
|
273
|
+
* List of files in the upload component.
|
|
274
|
+
*/
|
|
275
|
+
fileList: UploadFile[];
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* The individual file being rendered.
|
|
279
|
+
*/
|
|
280
|
+
file: UploadFile;
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Function to preview the file.
|
|
284
|
+
*/
|
|
285
|
+
onPreview?: (file: UploadFile) => void;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Prefix class name without hash.
|
|
289
|
+
*/
|
|
290
|
+
prefixClsWithoutHash: string;
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Actions available for the file (download, preview, remove).
|
|
294
|
+
*/
|
|
295
|
+
actions: {
|
|
296
|
+
/**
|
|
297
|
+
* Function to download the file.
|
|
298
|
+
*/
|
|
299
|
+
download: () => void;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Function to preview the file.
|
|
303
|
+
*/
|
|
304
|
+
preview: () => void;
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Function to remove the file.
|
|
308
|
+
*/
|
|
309
|
+
remove: () => void;
|
|
310
|
+
};
|
|
311
|
+
};
|
package/dist/esm/index.css
CHANGED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/* TODO: use antd useStyleRegister */
|
|
2
|
+
|
|
3
|
+
.akinon-upload.akinon-upload-select {
|
|
4
|
+
cursor: pointer;
|
|
5
|
+
flex: 1;
|
|
6
|
+
width: 100%;
|
|
7
|
+
/* TODO: use antd tokens */
|
|
8
|
+
padding: 10px 20px;
|
|
9
|
+
font-weight: 600;
|
|
10
|
+
background-color: var(--color-ebonyClay-475);
|
|
11
|
+
border-radius: 5px;
|
|
12
|
+
background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' fill='none' stroke='black' stroke-width='4' stroke-dasharray='6%2c 12' stroke-dashoffset='0' stroke-linecap='square'/%3e%3c/svg%3e");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.akinon-upload.akinon-upload-select:not(:has(.akinon-upload-list-item)) {
|
|
16
|
+
max-width: 300px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.akinon-upload-wrapper
|
|
20
|
+
.akinon-upload-list:not(.akinon-upload-list-picture-card) {
|
|
21
|
+
line-height: 0;
|
|
22
|
+
max-width: 300px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.akinon-upload-wrapper
|
|
26
|
+
.akinon-upload-list:not(.akinon-upload-list-picture-card)
|
|
27
|
+
.akinon-upload-list-item {
|
|
28
|
+
/* TODO: use antd tokens */
|
|
29
|
+
border-radius: 5px;
|
|
30
|
+
height: unset;
|
|
31
|
+
padding: 10px 20px;
|
|
32
|
+
background-color: var(--color-ebonyClay-550);
|
|
33
|
+
font-size: 14px;
|
|
34
|
+
font-weight: 600;
|
|
35
|
+
gap: 10px;
|
|
36
|
+
align-items: center;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.akinon-upload-wrapper
|
|
40
|
+
.akinon-upload-list:not(.akinon-upload-list-picture-card)
|
|
41
|
+
.akinon-upload-list-item
|
|
42
|
+
.akinon-upload-list-item-name {
|
|
43
|
+
white-space: normal;
|
|
44
|
+
word-break: break-all;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.akinon-upload-wrapper.akinon-upload-picture-card-wrapper
|
|
48
|
+
.akinon-upload-list.akinon-upload-list-picture-card
|
|
49
|
+
.akinon-upload-list-item {
|
|
50
|
+
/* TODO: use antd tokens */
|
|
51
|
+
border-radius: 0;
|
|
52
|
+
border: 2px solid var(--color-neutral-350);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.akinon-upload-wrapper.akinon-upload-picture-card-wrapper
|
|
56
|
+
.akinon-upload-list.akinon-upload-list-picture-card
|
|
57
|
+
.akinon-upload-list-item-error {
|
|
58
|
+
border-color: var(--color-red-500);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.akinon-upload-wrapper.akinon-upload-picture-card-wrapper
|
|
62
|
+
.akinon-upload-list.akinon-upload-list-picture-card
|
|
63
|
+
.akinon-upload-list-item::before {
|
|
64
|
+
display: none;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.akinon-upload-wrapper.akinon-upload-picture-card-wrapper
|
|
68
|
+
.akinon-upload-list.akinon-upload-list-picture-card
|
|
69
|
+
.akinon-upload-list-item-actions {
|
|
70
|
+
cursor: pointer;
|
|
71
|
+
width: fit-content;
|
|
72
|
+
inset: auto 6px 6px auto;
|
|
73
|
+
background-color: rgba(255, 255, 255, 0.5);
|
|
74
|
+
display: flex;
|
|
75
|
+
align-items: center;
|
|
76
|
+
justify-content: center;
|
|
77
|
+
border-radius: 100%;
|
|
78
|
+
height: 18px;
|
|
79
|
+
width: 18px;
|
|
80
|
+
font-size: 12px;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.akinon-upload-wrapper
|
|
84
|
+
.akinon-upload-list
|
|
85
|
+
.akinon-upload-list-item
|
|
86
|
+
.akinon-upload-list-item-actions
|
|
87
|
+
.akinon-upload-list-item-action {
|
|
88
|
+
opacity: 1;
|
|
89
|
+
}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import './index.css';
|
|
2
2
|
import type { UploadProps as AntUploadProps } from 'antd';
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
|
|
4
|
+
import type { UploadProps } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* Upload component for Akinon UI.
|
|
7
|
+
*
|
|
8
|
+
* The Upload component provides an interface for users to upload files.
|
|
9
|
+
* It supports various configurations like drag-and-drop, previewing files,
|
|
10
|
+
* and customizing request methods. The component is designed to handle multiple
|
|
11
|
+
* file types and offers flexibility for integrating with server-side logic.
|
|
12
|
+
*
|
|
13
|
+
* The component adheres to the Akinon design system, ensuring consistency across applications.
|
|
14
|
+
*/
|
|
5
15
|
declare const Upload: {
|
|
6
|
-
(
|
|
16
|
+
(props: UploadProps): React.JSX.Element;
|
|
7
17
|
Dragger: React.ForwardRefExoticComponent<AntUploadProps<any> & {
|
|
8
|
-
height?: number
|
|
18
|
+
height?: number;
|
|
9
19
|
} & React.RefAttributes<import("antd/es/upload/Upload").UploadRef<any>>>;
|
|
10
20
|
};
|
|
11
21
|
export { Upload };
|
|
22
|
+
export * from './types.d';
|
|
12
23
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAKrB,OAAO,KAAK,EAAE,WAAW,IAAI,cAAc,EAAE,MAAM,MAAM,CAAC;AAE1D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;;;;;;;GASG;AAEH,QAAA,MAAM,MAAM;YAAW,WAAW;;;;CAiEjC,CAAC;AAGF,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,cAAc,WAAW,CAAC"}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,8 +1,56 @@
|
|
|
1
1
|
import './index.css';
|
|
2
|
-
import {
|
|
2
|
+
import { Image } from '@akinon/ui-image';
|
|
3
|
+
import { useToken } from '@akinon/ui-theme';
|
|
4
|
+
import { useStyleRegister } from '@ant-design/cssinjs';
|
|
5
|
+
import { ConfigProvider, Upload as AntUpload } from 'antd';
|
|
3
6
|
import * as React from 'react';
|
|
4
|
-
|
|
5
|
-
|
|
7
|
+
import { UploadItem } from './item';
|
|
8
|
+
/**
|
|
9
|
+
* Upload component for Akinon UI.
|
|
10
|
+
*
|
|
11
|
+
* The Upload component provides an interface for users to upload files.
|
|
12
|
+
* It supports various configurations like drag-and-drop, previewing files,
|
|
13
|
+
* and customizing request methods. The component is designed to handle multiple
|
|
14
|
+
* file types and offers flexibility for integrating with server-side logic.
|
|
15
|
+
*
|
|
16
|
+
* The component adheres to the Akinon design system, ensuring consistency across applications.
|
|
17
|
+
*/
|
|
18
|
+
const Upload = (props) => {
|
|
19
|
+
const { getPrefixCls, theme } = React.useContext(ConfigProvider.ConfigContext);
|
|
20
|
+
const { token, hashId } = useToken();
|
|
21
|
+
const uploadToken = token.Upload;
|
|
22
|
+
const prefixClsWithoutHash = `${getPrefixCls()}-upload`;
|
|
23
|
+
const prefixCls = `:where(.${hashId}).${prefixClsWithoutHash}`;
|
|
24
|
+
const useStyle = useStyleRegister({
|
|
25
|
+
token: token,
|
|
26
|
+
path: ['Upload'],
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
|
+
theme: theme
|
|
29
|
+
}, () => {
|
|
30
|
+
return {
|
|
31
|
+
[`${prefixCls}-wrapper`]: {
|
|
32
|
+
[`.${prefixClsWithoutHash}-list`]: {
|
|
33
|
+
'&-item-error-border': {
|
|
34
|
+
border: `1px solid ${uploadToken === null || uploadToken === void 0 ? void 0 : uploadToken.colorError}`
|
|
35
|
+
},
|
|
36
|
+
'&-item-actions': {
|
|
37
|
+
'.anticon.anticon-delete': {
|
|
38
|
+
display: 'inline-block',
|
|
39
|
+
textAlign: 'center',
|
|
40
|
+
svg: {
|
|
41
|
+
color: 'black',
|
|
42
|
+
height: '12px',
|
|
43
|
+
width: '12px'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
return useStyle(React.createElement(Image.PreviewGroup, null,
|
|
52
|
+
React.createElement(AntUpload, Object.assign({ fileList: props.fileList, itemRender: (originNode, file, fileList, actions) => (React.createElement(UploadItem, { props: Object.assign({ listType: 'text' }, props), originNode: originNode, file: file, fileList: fileList, actions: actions, prefixClsWithoutHash: prefixClsWithoutHash, onPreview: props.onPreview })) }, props))));
|
|
6
53
|
};
|
|
7
54
|
Upload.Dragger = AntUpload.Dragger;
|
|
8
55
|
export { Upload };
|
|
56
|
+
export * from './types.d';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { UploadItemProps } from './types';
|
|
3
|
+
declare const componentMap: {
|
|
4
|
+
readonly 'picture-card': typeof ImageItem;
|
|
5
|
+
readonly text: typeof TextItem;
|
|
6
|
+
};
|
|
7
|
+
export declare function UploadItem({ props, originNode, file, fileList, actions, prefixClsWithoutHash, onPreview, Component }: UploadItemProps & {
|
|
8
|
+
Component?: (typeof componentMap)[keyof typeof componentMap] | React.ComponentType<UploadItemProps & {
|
|
9
|
+
akinonNode: (typeof componentMap)[keyof typeof componentMap];
|
|
10
|
+
}>;
|
|
11
|
+
}): React.JSX.Element;
|
|
12
|
+
declare function ImageItem({ file, onPreview, prefixClsWithoutHash, actions, originNode }: UploadItemProps): React.JSX.Element;
|
|
13
|
+
declare function TextItem({ file, prefixClsWithoutHash, actions }: UploadItemProps): React.JSX.Element;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=item.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"item.d.ts","sourceRoot":"","sources":["../../src/item.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,QAAA,MAAM,YAAY;;;CAGR,CAAC;AAEX,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,oBAAoB,EACpB,SAAS,EACT,SAAqE,EACtE,EAAE,eAAe,GAAG;IACnB,SAAS,CAAC,EACN,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,GAChD,KAAK,CAAC,aAAa,CACjB,eAAe,GAAG;QAChB,UAAU,EAAE,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;KAC9D,CACF,CAAC;CACP,qBAiBA;AAED,iBAAS,SAAS,CAAC,EACjB,IAAI,EACJ,SAAS,EACT,oBAAoB,EACpB,OAAO,EACP,UAAU,EACX,EAAE,eAAe,qBA2BjB;AAED,iBAAS,QAAQ,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,EAAE,eAAe,qBA4CzE"}
|
package/dist/esm/item.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Icon } from '@akinon/icons';
|
|
2
|
+
import { Image } from '@akinon/ui-image';
|
|
3
|
+
import { Flex } from '@akinon/ui-layout';
|
|
4
|
+
import { Tooltip } from '@akinon/ui-tooltip';
|
|
5
|
+
import clsx from 'clsx';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
const componentMap = {
|
|
8
|
+
'picture-card': ImageItem,
|
|
9
|
+
text: TextItem
|
|
10
|
+
};
|
|
11
|
+
export function UploadItem({ props, originNode, file, fileList, actions, prefixClsWithoutHash, onPreview, Component = componentMap[props.listType] }) {
|
|
12
|
+
if (Component) {
|
|
13
|
+
return (React.createElement(Component, { akinonNode: componentMap[props.listType], originNode: originNode, props: props, file: file, fileList: fileList, actions: actions, prefixClsWithoutHash: prefixClsWithoutHash, onPreview: onPreview }));
|
|
14
|
+
}
|
|
15
|
+
return originNode;
|
|
16
|
+
}
|
|
17
|
+
function ImageItem({ file, onPreview, prefixClsWithoutHash, actions, originNode }) {
|
|
18
|
+
return file.thumbUrl ? (React.createElement("div", { className: clsx(`${prefixClsWithoutHash}-list-item`, `${prefixClsWithoutHash}-list-item-${file.status}-border`), onClick: () => {
|
|
19
|
+
actions.preview();
|
|
20
|
+
} },
|
|
21
|
+
React.createElement(Image, Object.assign({ src: file.thumbUrl }, (onPreview && { preview: false }))),
|
|
22
|
+
React.createElement("div", { className: `${prefixClsWithoutHash}-list-item-actions` },
|
|
23
|
+
React.createElement(Icon, { icon: "bin", size: 12, color: "black", onClick: e => {
|
|
24
|
+
e.stopPropagation();
|
|
25
|
+
actions.remove();
|
|
26
|
+
} })))) : (originNode);
|
|
27
|
+
}
|
|
28
|
+
function TextItem({ file, prefixClsWithoutHash, actions }) {
|
|
29
|
+
return (React.createElement("div", { className: clsx(`${prefixClsWithoutHash}-list-item`, `${prefixClsWithoutHash}-list-item-${file.status}-border`) },
|
|
30
|
+
React.createElement(Flex, { flex: 1, justify: "between", align: "center", gap: 8 },
|
|
31
|
+
React.createElement(Flex, { align: "center", gap: 10, flex: 1 },
|
|
32
|
+
React.createElement("div", { className: `${prefixClsWithoutHash}-list-item-actions` },
|
|
33
|
+
React.createElement(Icon, { cursor: "pointer", icon: "bin", size: 13, color: "var(--color-azure-500)", onClick: e => {
|
|
34
|
+
e.stopPropagation();
|
|
35
|
+
actions.remove();
|
|
36
|
+
} })),
|
|
37
|
+
React.createElement("div", { className: `${prefixClsWithoutHash}-list-item-name` }, file.name)),
|
|
38
|
+
file.status === 'error' && (
|
|
39
|
+
// TODO: pass proper error messages
|
|
40
|
+
React.createElement(Tooltip, { title: "Error" },
|
|
41
|
+
React.createElement(Icon, { className: clsx(`${prefixClsWithoutHash}-list-item-${file.status}`), icon: "warning_tri", size: 13, color: "var(--color-azure-500)" }))))));
|
|
42
|
+
}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import type { IProgressProps } from '@akinon/ui-progress';
|
|
2
|
+
import { DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE } from '@akinon/ui-theme';
|
|
3
|
+
import type { UploadFile } from 'antd';
|
|
4
|
+
|
|
5
|
+
export type UploadItemProps = RenderedItemProps & {
|
|
6
|
+
/**
|
|
7
|
+
* Props of the upload component.
|
|
8
|
+
*/
|
|
9
|
+
props: UploadProps;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The original React node for the upload item.
|
|
13
|
+
*/
|
|
14
|
+
originNode: React.ReactElement;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type UploadMethod = 'POST' | 'PUT' | 'PATCH' | 'post' | 'put' | 'patch';
|
|
18
|
+
|
|
19
|
+
export type UploadListType =
|
|
20
|
+
| 'text'
|
|
21
|
+
| 'picture'
|
|
22
|
+
| 'picture-card'
|
|
23
|
+
| 'picture-circle';
|
|
24
|
+
|
|
25
|
+
export interface UploadProps
|
|
26
|
+
extends Omit<
|
|
27
|
+
React.InputHTMLAttributes<HTMLInputElement>,
|
|
28
|
+
'onError' | 'onProgress'
|
|
29
|
+
> {
|
|
30
|
+
/**
|
|
31
|
+
* Whether to control the component internally.
|
|
32
|
+
*/
|
|
33
|
+
hasControlInside?: boolean;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The type of the upload input.
|
|
37
|
+
*/
|
|
38
|
+
type?: 'drag' | 'select';
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The name attribute for the file input.
|
|
42
|
+
*/
|
|
43
|
+
name?: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Default list of files.
|
|
47
|
+
*/
|
|
48
|
+
defaultFileList?: UploadFile[];
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Controlled file list.
|
|
52
|
+
*/
|
|
53
|
+
fileList?: UploadFile[];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The URL or function that returns the URL for uploading files.
|
|
57
|
+
*/
|
|
58
|
+
action?: string | ((file: UploadFile) => string | PromiseLike<string>);
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Whether to enable directory upload.
|
|
62
|
+
*/
|
|
63
|
+
directory?: boolean;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Additional data to include in the upload request.
|
|
67
|
+
*/
|
|
68
|
+
data?:
|
|
69
|
+
| Record<string, unknown>
|
|
70
|
+
| ((
|
|
71
|
+
file: UploadFile
|
|
72
|
+
) => Record<string, unknown> | Promise<Record<string, unknown>>);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* HTTP method to use for the upload request.
|
|
76
|
+
*/
|
|
77
|
+
method?: UploadMethod;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Custom headers for the upload request.
|
|
81
|
+
*/
|
|
82
|
+
headers?: Record<string, string>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Configuration for displaying the upload list.
|
|
86
|
+
*/
|
|
87
|
+
showUploadList?:
|
|
88
|
+
| boolean
|
|
89
|
+
| {
|
|
90
|
+
showRemoveIcon?: boolean;
|
|
91
|
+
showPreviewIcon?: boolean;
|
|
92
|
+
showDownloadIcon?: boolean;
|
|
93
|
+
removeIcon?: React.ReactNode | ((file: UploadFile) => React.ReactNode);
|
|
94
|
+
downloadIcon?:
|
|
95
|
+
| React.ReactNode
|
|
96
|
+
| ((file: UploadFile) => React.ReactNode);
|
|
97
|
+
previewIcon?: React.ReactNode | ((file: UploadFile) => React.ReactNode);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Whether to allow uploading multiple files.
|
|
102
|
+
*/
|
|
103
|
+
multiple?: boolean;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* The file types that can be uploaded.
|
|
107
|
+
*/
|
|
108
|
+
accept?: string;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Function called before uploading a file.
|
|
112
|
+
*/
|
|
113
|
+
beforeUpload?: (
|
|
114
|
+
file: UploadFile,
|
|
115
|
+
FileList: UploadFile[]
|
|
116
|
+
) =>
|
|
117
|
+
| void
|
|
118
|
+
| boolean
|
|
119
|
+
| string
|
|
120
|
+
| Blob
|
|
121
|
+
| File
|
|
122
|
+
| Promise<void | boolean | string | Blob | File>;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Function called when the file list changes.
|
|
126
|
+
*/
|
|
127
|
+
onChange?: (info: {
|
|
128
|
+
file: UploadFile;
|
|
129
|
+
fileList: UploadFile[];
|
|
130
|
+
event?: {
|
|
131
|
+
percent: number;
|
|
132
|
+
};
|
|
133
|
+
}) => void;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Function called when a file is dropped into the upload area.
|
|
137
|
+
*/
|
|
138
|
+
onDrop?: (event: React.DragEvent<HTMLDivElement>) => void;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Additional class name for the upload component.
|
|
142
|
+
*/
|
|
143
|
+
className?: string;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Root class name for the upload component.
|
|
147
|
+
*/
|
|
148
|
+
rootClassName?: string;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Function called to preview a file.
|
|
152
|
+
*/
|
|
153
|
+
onPreview?: (file: UploadFile) => void;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Function called to download a file.
|
|
157
|
+
*/
|
|
158
|
+
onDownload?: (file: UploadFile) => void;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Function called to remove a file.
|
|
162
|
+
*/
|
|
163
|
+
onRemove?: (file: UploadFile) => void | boolean | Promise<void | boolean>;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Whether to support server-side rendering.
|
|
167
|
+
*/
|
|
168
|
+
supportServerRender?: boolean;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Whether the upload input is disabled.
|
|
172
|
+
*/
|
|
173
|
+
disabled?: boolean;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Custom request function for handling uploads.
|
|
177
|
+
*/
|
|
178
|
+
customRequest?: (options: {
|
|
179
|
+
onProgress?: (event: Partial<ProgressEvent> & { percent?: number }) => void;
|
|
180
|
+
onError?: (
|
|
181
|
+
event:
|
|
182
|
+
| (Error & {
|
|
183
|
+
status?: number;
|
|
184
|
+
method?: UploadMethod;
|
|
185
|
+
})
|
|
186
|
+
| ProgressEvent,
|
|
187
|
+
body?: UploadFile
|
|
188
|
+
) => void;
|
|
189
|
+
onSuccess?: (body: UploadFile, xhr?: XMLHttpRequest) => void;
|
|
190
|
+
data?: Record<string, unknown>;
|
|
191
|
+
filename?: string;
|
|
192
|
+
file: void | string | Blob | UploadFile['originFileObj'];
|
|
193
|
+
withCredentials?: boolean;
|
|
194
|
+
action: string;
|
|
195
|
+
headers?: Record<string, string>;
|
|
196
|
+
method: UploadMethod;
|
|
197
|
+
}) => void;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Whether to send credentials with the upload request.
|
|
201
|
+
*/
|
|
202
|
+
withCredentials?: boolean;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Whether to open the file dialog when clicking on the upload area.
|
|
206
|
+
*/
|
|
207
|
+
openFileDialogOnClick?: boolean;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Locale strings for the upload component.
|
|
211
|
+
*/
|
|
212
|
+
locale?: {
|
|
213
|
+
uploading?: string;
|
|
214
|
+
removeFile?: string;
|
|
215
|
+
downloadFile?: string;
|
|
216
|
+
uploadError?: string;
|
|
217
|
+
previewFile?: string;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* ID for the upload component.
|
|
222
|
+
*/
|
|
223
|
+
id?: string;
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Function to generate a preview for a file.
|
|
227
|
+
*/
|
|
228
|
+
previewFile?: (file: File | Blob) => PromiseLike<string>;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Function to render a custom icon for a file.
|
|
232
|
+
*/
|
|
233
|
+
iconRender?: (file: UploadFile, listType?: UploadListType) => React.ReactNode;
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Function to determine if a file is an image.
|
|
237
|
+
*/
|
|
238
|
+
isImageUrl?: (file: UploadFile) => boolean;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Progress bar properties for the upload component.
|
|
242
|
+
*/
|
|
243
|
+
progress?: Omit<IProgressProps, 'percent' | 'type'>;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Function to render a custom item in the upload list.
|
|
247
|
+
*/
|
|
248
|
+
itemRender?: Omit<RenderedItemProps, 'prefixClsWithoutHash' | 'onPreview'>;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Maximum number of files that can be uploaded.
|
|
252
|
+
*/
|
|
253
|
+
maxCount?: number;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Child elements to render within the upload component.
|
|
257
|
+
*/
|
|
258
|
+
children?: React.ReactNode;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Type of upload list to display.
|
|
262
|
+
*/
|
|
263
|
+
listType?: UploadListType;
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* @ignore
|
|
267
|
+
*/
|
|
268
|
+
style?: DO_NOT_USE_OR_YOU_WILL_BE_FIRED_INTERNAL_STYLE;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export type RenderedItemProps = {
|
|
272
|
+
/**
|
|
273
|
+
* List of files in the upload component.
|
|
274
|
+
*/
|
|
275
|
+
fileList: UploadFile[];
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* The individual file being rendered.
|
|
279
|
+
*/
|
|
280
|
+
file: UploadFile;
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Function to preview the file.
|
|
284
|
+
*/
|
|
285
|
+
onPreview?: (file: UploadFile) => void;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Prefix class name without hash.
|
|
289
|
+
*/
|
|
290
|
+
prefixClsWithoutHash: string;
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Actions available for the file (download, preview, remove).
|
|
294
|
+
*/
|
|
295
|
+
actions: {
|
|
296
|
+
/**
|
|
297
|
+
* Function to download the file.
|
|
298
|
+
*/
|
|
299
|
+
download: () => void;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Function to preview the file.
|
|
303
|
+
*/
|
|
304
|
+
preview: () => void;
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Function to remove the file.
|
|
308
|
+
*/
|
|
309
|
+
remove: () => void;
|
|
310
|
+
};
|
|
311
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akinon/ui-upload",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
@@ -9,14 +9,21 @@
|
|
|
9
9
|
"dist"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"antd": "5.
|
|
12
|
+
"antd": "5.22.6",
|
|
13
|
+
"clsx": "2.1.1"
|
|
13
14
|
},
|
|
14
15
|
"devDependencies": {
|
|
15
16
|
"clean-package": "2.2.0",
|
|
16
17
|
"copyfiles": "^2.4.1",
|
|
17
18
|
"rimraf": "^5.0.5",
|
|
18
|
-
"typescript": "
|
|
19
|
-
"@akinon/
|
|
19
|
+
"typescript": "*",
|
|
20
|
+
"@akinon/icons": "1.0.0",
|
|
21
|
+
"@akinon/ui-layout": "1.0.0",
|
|
22
|
+
"@akinon/ui-theme": "1.0.0",
|
|
23
|
+
"@akinon/ui-progress": "1.0.0",
|
|
24
|
+
"@akinon/ui-image": "1.0.0",
|
|
25
|
+
"@akinon/ui-tooltip": "1.0.0",
|
|
26
|
+
"@akinon/typescript-config": "1.0.0"
|
|
20
27
|
},
|
|
21
28
|
"peerDependencies": {
|
|
22
29
|
"react": ">=18",
|
|
@@ -36,7 +43,7 @@
|
|
|
36
43
|
"build": "pnpm run build:esm && pnpm run build:commonjs && pnpm run copy:files",
|
|
37
44
|
"build:esm": "tsc --outDir dist/esm",
|
|
38
45
|
"build:commonjs": "tsc --module commonjs --outDir dist/cjs",
|
|
39
|
-
"copy:files": "copyfiles -u 1 src
|
|
46
|
+
"copy:files": "copyfiles -u 1 \"src/**/*.!(ts|tsx)\" dist/esm && copyfiles -u 1 \"src/**/*.!(ts|tsx)\" dist/cjs",
|
|
40
47
|
"clean": "rimraf dist/",
|
|
41
48
|
"typecheck": "tsc --noEmit"
|
|
42
49
|
}
|