@via-profit/ui-kit 0.8.0 → 0.9.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/Autocomplete/AutocompleteContainer.d.ts +13 -0
- package/Autocomplete/AutocompleteContainer.js +46 -7
- package/Badge/BadgeBase.d.ts +10 -1
- package/Badge/BadgeBase.js +9 -2
- package/Badge/BadgeDot.d.ts +4 -0
- package/Badge/BadgeDot.js +20 -0
- package/Badge/BadgeStyled.js +67 -26
- package/Badge/index.d.ts +4 -4
- package/CHANGELOG.md +12 -0
- package/EmptyState/EmptyStateAction.d.ts +4 -0
- package/EmptyState/EmptyStateAction.js +16 -0
- package/EmptyState/EmptyStateContainer.d.ts +8 -0
- package/EmptyState/EmptyStateContainer.js +34 -0
- package/EmptyState/EmptyStateContent.d.ts +4 -0
- package/EmptyState/EmptyStateContent.js +15 -0
- package/EmptyState/EmptyStateIcon.d.ts +4 -0
- package/EmptyState/EmptyStateIcon.js +38 -0
- package/EmptyState/EmptyStateTitle.d.ts +4 -0
- package/EmptyState/EmptyStateTitle.js +13 -0
- package/EmptyState/index.d.ts +82 -0
- package/EmptyState/index.js +61 -0
- package/FileDropzone/FileDropzoneArea.d.ts +24 -0
- package/FileDropzone/FileDropzoneArea.js +81 -0
- package/FileDropzone/index.d.ts +107 -0
- package/FileDropzone/index.js +169 -0
- package/FileDropzone/utils.d.ts +9 -0
- package/FileDropzone/utils.js +42 -0
- package/HintPopover/HintPopoverButton.d.ts +4 -0
- package/HintPopover/HintPopoverButton.js +67 -0
- package/HintPopover/HintPopoverContainer.d.ts +4 -0
- package/HintPopover/HintPopoverContainer.js +52 -0
- package/HintPopover/index.d.ts +67 -0
- package/HintPopover/index.js +71 -0
- package/InfoNote/InfoNoteContainer.d.ts +14 -0
- package/InfoNote/InfoNoteContainer.js +56 -0
- package/InfoNote/InfoNoteContent.d.ts +4 -0
- package/InfoNote/InfoNoteContent.js +16 -0
- package/InfoNote/InfoNoteIcon.d.ts +9 -0
- package/InfoNote/InfoNoteIcon.js +47 -0
- package/InfoNote/InfoNoteTitle.d.ts +4 -0
- package/InfoNote/InfoNoteTitle.js +13 -0
- package/InfoNote/index.d.ts +65 -0
- package/InfoNote/index.js +59 -0
- package/Skeleton/index.d.ts +39 -0
- package/Skeleton/index.js +69 -0
- package/esm/Autocomplete/AutocompleteContainer.js +46 -7
- package/esm/Badge/BadgeBase.js +9 -2
- package/esm/Badge/BadgeDot.js +15 -0
- package/esm/Badge/BadgeStyled.js +67 -26
- package/esm/EmptyState/EmptyStateAction.js +11 -0
- package/esm/EmptyState/EmptyStateContainer.js +29 -0
- package/esm/EmptyState/EmptyStateContent.js +10 -0
- package/esm/EmptyState/EmptyStateIcon.js +33 -0
- package/esm/EmptyState/EmptyStateTitle.js +8 -0
- package/esm/EmptyState/index.js +42 -0
- package/esm/FileDropzone/FileDropzoneArea.js +76 -0
- package/esm/FileDropzone/index.js +148 -0
- package/esm/FileDropzone/utils.js +37 -0
- package/esm/HintPopover/HintPopoverButton.js +62 -0
- package/esm/HintPopover/HintPopoverContainer.js +47 -0
- package/esm/HintPopover/index.js +52 -0
- package/esm/InfoNote/InfoNoteContainer.js +49 -0
- package/esm/InfoNote/InfoNoteContent.js +11 -0
- package/esm/InfoNote/InfoNoteIcon.js +42 -0
- package/esm/InfoNote/InfoNoteTitle.js +8 -0
- package/esm/InfoNote/index.js +40 -0
- package/esm/Skeleton/index.js +64 -0
- package/package.json +121 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { EmptyStateContainerProps } from './EmptyStateContainer';
|
|
3
|
+
import { EmptyStateIconProps } from './EmptyStateIcon';
|
|
4
|
+
import { EmptyStateTitleProps } from './EmptyStateTitle';
|
|
5
|
+
import { EmptyStateContentProps } from './EmptyStateContent';
|
|
6
|
+
import { EmptyStateActionProps } from './EmptyStateAction';
|
|
7
|
+
export type EmptyStateProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> & {
|
|
8
|
+
/**
|
|
9
|
+
* The short line: what is empty («Заявок нет»)
|
|
10
|
+
*/
|
|
11
|
+
readonly title?: React.ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* The explanation: why it is empty and what to do
|
|
14
|
+
*/
|
|
15
|
+
readonly children?: React.ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* The next step: one or two buttons
|
|
18
|
+
*/
|
|
19
|
+
readonly action?: React.ReactNode;
|
|
20
|
+
/**
|
|
21
|
+
* Replaces the empty box. `false` — no illustration
|
|
22
|
+
*/
|
|
23
|
+
readonly icon?: React.ReactNode;
|
|
24
|
+
/**
|
|
25
|
+
* Takes the whole height of the parent and stands in its middle
|
|
26
|
+
* Default: false
|
|
27
|
+
*/
|
|
28
|
+
readonly fullHeight?: boolean;
|
|
29
|
+
readonly overrides?: EmptyStateOverrides;
|
|
30
|
+
};
|
|
31
|
+
export interface EmptyStateOverrides {
|
|
32
|
+
/**
|
|
33
|
+
* The column in the middle; gets `fullHeight`
|
|
34
|
+
*/
|
|
35
|
+
readonly Container?: React.ComponentType<EmptyStateContainerProps & React.RefAttributes<HTMLDivElement>>;
|
|
36
|
+
/**
|
|
37
|
+
* The illustration; the own one from `icon` comes in `children`
|
|
38
|
+
*/
|
|
39
|
+
readonly Icon?: React.ComponentType<EmptyStateIconProps & React.RefAttributes<HTMLSpanElement>>;
|
|
40
|
+
/**
|
|
41
|
+
* The title. Rendered only with `title`
|
|
42
|
+
*/
|
|
43
|
+
readonly Title?: React.ComponentType<EmptyStateTitleProps & React.RefAttributes<HTMLDivElement>>;
|
|
44
|
+
/**
|
|
45
|
+
* The explanation. Rendered only with `children`
|
|
46
|
+
*/
|
|
47
|
+
readonly Content?: React.ComponentType<EmptyStateContentProps & React.RefAttributes<HTMLDivElement>>;
|
|
48
|
+
/**
|
|
49
|
+
* The buttons. Rendered only with `action`
|
|
50
|
+
*/
|
|
51
|
+
readonly Action?: React.ComponentType<EmptyStateActionProps & React.RefAttributes<HTMLDivElement>>;
|
|
52
|
+
}
|
|
53
|
+
export * from './EmptyStateContainer';
|
|
54
|
+
export * from './EmptyStateIcon';
|
|
55
|
+
export * from './EmptyStateTitle';
|
|
56
|
+
export * from './EmptyStateContent';
|
|
57
|
+
export * from './EmptyStateAction';
|
|
58
|
+
declare const _default: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLDivElement>, "title"> & {
|
|
59
|
+
/**
|
|
60
|
+
* The short line: what is empty («Заявок нет»)
|
|
61
|
+
*/
|
|
62
|
+
readonly title?: React.ReactNode;
|
|
63
|
+
/**
|
|
64
|
+
* The explanation: why it is empty and what to do
|
|
65
|
+
*/
|
|
66
|
+
readonly children?: React.ReactNode;
|
|
67
|
+
/**
|
|
68
|
+
* The next step: one or two buttons
|
|
69
|
+
*/
|
|
70
|
+
readonly action?: React.ReactNode;
|
|
71
|
+
/**
|
|
72
|
+
* Replaces the empty box. `false` — no illustration
|
|
73
|
+
*/
|
|
74
|
+
readonly icon?: React.ReactNode;
|
|
75
|
+
/**
|
|
76
|
+
* Takes the whole height of the parent and stands in its middle
|
|
77
|
+
* Default: false
|
|
78
|
+
*/
|
|
79
|
+
readonly fullHeight?: boolean;
|
|
80
|
+
readonly overrides?: EmptyStateOverrides;
|
|
81
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
82
|
+
export default _default;
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
};
|
|
16
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
17
|
+
var t = {};
|
|
18
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
19
|
+
t[p] = s[p];
|
|
20
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
21
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
22
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
23
|
+
t[p[i]] = s[p[i]];
|
|
24
|
+
}
|
|
25
|
+
return t;
|
|
26
|
+
};
|
|
27
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
28
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
29
|
+
};
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
const react_1 = __importDefault(require("react"));
|
|
32
|
+
const EmptyStateContainer_1 = __importDefault(require("./EmptyStateContainer"));
|
|
33
|
+
const EmptyStateIcon_1 = __importDefault(require("./EmptyStateIcon"));
|
|
34
|
+
const EmptyStateTitle_1 = __importDefault(require("./EmptyStateTitle"));
|
|
35
|
+
const EmptyStateContent_1 = __importDefault(require("./EmptyStateContent"));
|
|
36
|
+
const EmptyStateAction_1 = __importDefault(require("./EmptyStateAction"));
|
|
37
|
+
/**
|
|
38
|
+
* The empty list, the nothing found, the not chosen yet: the illustration, what is empty
|
|
39
|
+
* and what to do next
|
|
40
|
+
*/
|
|
41
|
+
const EmptyState = (props, ref) => {
|
|
42
|
+
const { title, children, action, icon, fullHeight = false, overrides } = props, nativeProps = __rest(props, ["title", "children", "action", "icon", "fullHeight", "overrides"]);
|
|
43
|
+
const overridesMap = react_1.default.useMemo(() => ({
|
|
44
|
+
Container: (overrides === null || overrides === void 0 ? void 0 : overrides.Container) || EmptyStateContainer_1.default,
|
|
45
|
+
Icon: (overrides === null || overrides === void 0 ? void 0 : overrides.Icon) || EmptyStateIcon_1.default,
|
|
46
|
+
Title: (overrides === null || overrides === void 0 ? void 0 : overrides.Title) || EmptyStateTitle_1.default,
|
|
47
|
+
Content: (overrides === null || overrides === void 0 ? void 0 : overrides.Content) || EmptyStateContent_1.default,
|
|
48
|
+
Action: (overrides === null || overrides === void 0 ? void 0 : overrides.Action) || EmptyStateAction_1.default,
|
|
49
|
+
}), [overrides]);
|
|
50
|
+
return (react_1.default.createElement(overridesMap.Container, Object.assign({}, nativeProps, { fullHeight: fullHeight, ref: ref }),
|
|
51
|
+
icon !== false && react_1.default.createElement(overridesMap.Icon, null, icon),
|
|
52
|
+
title && react_1.default.createElement(overridesMap.Title, null, title),
|
|
53
|
+
children && react_1.default.createElement(overridesMap.Content, null, children),
|
|
54
|
+
action && react_1.default.createElement(overridesMap.Action, null, action)));
|
|
55
|
+
};
|
|
56
|
+
__exportStar(require("./EmptyStateContainer"), exports);
|
|
57
|
+
__exportStar(require("./EmptyStateIcon"), exports);
|
|
58
|
+
__exportStar(require("./EmptyStateTitle"), exports);
|
|
59
|
+
__exportStar(require("./EmptyStateContent"), exports);
|
|
60
|
+
__exportStar(require("./EmptyStateAction"), exports);
|
|
61
|
+
exports.default = react_1.default.forwardRef(EmptyState);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export type FileDropzoneAreaProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
3
|
+
/**
|
|
4
|
+
* A file is dragged over the area
|
|
5
|
+
*/
|
|
6
|
+
readonly active: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* The file is chosen: the solid border instead of the dashed one
|
|
9
|
+
*/
|
|
10
|
+
readonly filled: boolean;
|
|
11
|
+
readonly disabled: boolean;
|
|
12
|
+
};
|
|
13
|
+
declare const _default: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
14
|
+
/**
|
|
15
|
+
* A file is dragged over the area
|
|
16
|
+
*/
|
|
17
|
+
readonly active: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* The file is chosen: the solid border instead of the dashed one
|
|
20
|
+
*/
|
|
21
|
+
readonly filled: boolean;
|
|
22
|
+
readonly disabled: boolean;
|
|
23
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
24
|
+
export default _default;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
const react_1 = __importDefault(require("react"));
|
|
18
|
+
const styled_1 = __importDefault(require("@emotion/styled"));
|
|
19
|
+
const react_2 = require("@emotion/react");
|
|
20
|
+
const StyledArea = styled_1.default.div `
|
|
21
|
+
box-sizing: border-box;
|
|
22
|
+
display: flex;
|
|
23
|
+
width: 100%;
|
|
24
|
+
min-height: 6.5em;
|
|
25
|
+
padding: 1em;
|
|
26
|
+
border-radius: ${({ theme }) => theme.shape.radiusFactor * 1.6}em;
|
|
27
|
+
border: 1px ${({ $filled }) => ($filled ? 'solid' : 'dashed')}
|
|
28
|
+
${({ theme, $active }) => ($active ? theme.color.accentPrimary : theme.color.textSecondary.alpha(0.45)).toString()};
|
|
29
|
+
background-color: ${({ theme, $active }) => ($active
|
|
30
|
+
? theme.color.accentPrimary.alpha(0.1)
|
|
31
|
+
: theme.color.textPrimary.alpha(0.03)).toString()};
|
|
32
|
+
color: ${({ theme }) => theme.color.textPrimary.toString()};
|
|
33
|
+
transition:
|
|
34
|
+
border-color 120ms ease-out,
|
|
35
|
+
background-color 120ms ease-out;
|
|
36
|
+
|
|
37
|
+
${({ $filled, $disabled, theme }) => !$filled &&
|
|
38
|
+
!$disabled &&
|
|
39
|
+
(0, react_2.css) `
|
|
40
|
+
cursor: pointer;
|
|
41
|
+
|
|
42
|
+
&:hover,
|
|
43
|
+
&:focus-visible {
|
|
44
|
+
border-color: ${theme.color.accentPrimary.toString()};
|
|
45
|
+
}
|
|
46
|
+
`}
|
|
47
|
+
|
|
48
|
+
${({ $filled }) => $filled
|
|
49
|
+
? (0, react_2.css) `
|
|
50
|
+
flex-direction: row;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: 0.75em;
|
|
53
|
+
`
|
|
54
|
+
: (0, react_2.css) `
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
gap: 0.3em;
|
|
59
|
+
text-align: center;
|
|
60
|
+
`}
|
|
61
|
+
|
|
62
|
+
${({ $disabled }) => $disabled &&
|
|
63
|
+
(0, react_2.css) `
|
|
64
|
+
opacity: 0.5;
|
|
65
|
+
cursor: default;
|
|
66
|
+
`}
|
|
67
|
+
|
|
68
|
+
&:focus-visible {
|
|
69
|
+
outline: 2px solid ${({ theme }) => theme.color.accentPrimary.alpha(0.4).toString()};
|
|
70
|
+
outline-offset: 2px;
|
|
71
|
+
}
|
|
72
|
+
`;
|
|
73
|
+
/**
|
|
74
|
+
* The area: without the file — the icon and two lines in the middle (it chooses the file),
|
|
75
|
+
* with the file — the row of the file
|
|
76
|
+
*/
|
|
77
|
+
const FileDropzoneArea = (props, ref) => {
|
|
78
|
+
const { active, filled, disabled } = props, nativeProps = __rest(props, ["active", "filled", "disabled"]);
|
|
79
|
+
return (react_1.default.createElement(StyledArea, Object.assign({}, nativeProps, { "$active": active, "$filled": filled, "$disabled": disabled, ref: ref })));
|
|
80
|
+
};
|
|
81
|
+
exports.default = react_1.default.forwardRef(FileDropzoneArea);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FileDropzoneAreaProps } from './FileDropzoneArea';
|
|
3
|
+
import { formatFileSize, isFileAccepted } from './utils';
|
|
4
|
+
export { formatFileSize, isFileAccepted };
|
|
5
|
+
export type FileDropzoneRejectReason = 'type' | 'size';
|
|
6
|
+
export type FileDropzoneProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> & {
|
|
7
|
+
/**
|
|
8
|
+
* The chosen file, `null` — no file
|
|
9
|
+
*/
|
|
10
|
+
readonly value: File | null;
|
|
11
|
+
/**
|
|
12
|
+
* Called with the chosen file or `null` when the file is removed
|
|
13
|
+
*/
|
|
14
|
+
readonly onChange: (file: File | null) => void;
|
|
15
|
+
/**
|
|
16
|
+
* The types of the files, as `accept` of the input: `image/png`, `image/*`, `.pdf`
|
|
17
|
+
*/
|
|
18
|
+
readonly accept?: string;
|
|
19
|
+
/**
|
|
20
|
+
* The maximum size of the file in bytes
|
|
21
|
+
*/
|
|
22
|
+
readonly maxSize?: number;
|
|
23
|
+
/**
|
|
24
|
+
* The file is not taken: the type is not in `accept` or it is larger than `maxSize`
|
|
25
|
+
*/
|
|
26
|
+
readonly onReject?: (file: File, reason: FileDropzoneRejectReason) => void;
|
|
27
|
+
/**
|
|
28
|
+
* The line of the empty area
|
|
29
|
+
* Default: `Choose a file`
|
|
30
|
+
*/
|
|
31
|
+
readonly label?: React.ReactNode;
|
|
32
|
+
/**
|
|
33
|
+
* The second line of the empty area: the types and the size
|
|
34
|
+
*/
|
|
35
|
+
readonly hint?: React.ReactNode;
|
|
36
|
+
/**
|
|
37
|
+
* Default: `Replace`
|
|
38
|
+
*/
|
|
39
|
+
readonly replaceLabel?: React.ReactNode;
|
|
40
|
+
/**
|
|
41
|
+
* The name of the delete button for the screen readers and its tooltip
|
|
42
|
+
* Default: `Remove the file`
|
|
43
|
+
*/
|
|
44
|
+
readonly removeLabel?: string;
|
|
45
|
+
/**
|
|
46
|
+
* The size of the chosen file
|
|
47
|
+
* Default: `formatFileSize` — «54.1 KB»
|
|
48
|
+
*/
|
|
49
|
+
readonly formatSize?: (bytes: number) => React.ReactNode;
|
|
50
|
+
readonly disabled?: boolean;
|
|
51
|
+
readonly overrides?: FileDropzoneOverrides;
|
|
52
|
+
};
|
|
53
|
+
export interface FileDropzoneOverrides {
|
|
54
|
+
/**
|
|
55
|
+
* The area with the border: without the file and with it (`filled`)
|
|
56
|
+
*/
|
|
57
|
+
readonly Area?: React.ComponentType<FileDropzoneAreaProps & React.RefAttributes<HTMLDivElement>>;
|
|
58
|
+
}
|
|
59
|
+
export * from './FileDropzoneArea';
|
|
60
|
+
declare const _default: React.ForwardRefExoticComponent<Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
61
|
+
/**
|
|
62
|
+
* The chosen file, `null` — no file
|
|
63
|
+
*/
|
|
64
|
+
readonly value: File | null;
|
|
65
|
+
/**
|
|
66
|
+
* Called with the chosen file or `null` when the file is removed
|
|
67
|
+
*/
|
|
68
|
+
readonly onChange: (file: File | null) => void;
|
|
69
|
+
/**
|
|
70
|
+
* The types of the files, as `accept` of the input: `image/png`, `image/*`, `.pdf`
|
|
71
|
+
*/
|
|
72
|
+
readonly accept?: string;
|
|
73
|
+
/**
|
|
74
|
+
* The maximum size of the file in bytes
|
|
75
|
+
*/
|
|
76
|
+
readonly maxSize?: number;
|
|
77
|
+
/**
|
|
78
|
+
* The file is not taken: the type is not in `accept` or it is larger than `maxSize`
|
|
79
|
+
*/
|
|
80
|
+
readonly onReject?: (file: File, reason: FileDropzoneRejectReason) => void;
|
|
81
|
+
/**
|
|
82
|
+
* The line of the empty area
|
|
83
|
+
* Default: `Choose a file`
|
|
84
|
+
*/
|
|
85
|
+
readonly label?: React.ReactNode;
|
|
86
|
+
/**
|
|
87
|
+
* The second line of the empty area: the types and the size
|
|
88
|
+
*/
|
|
89
|
+
readonly hint?: React.ReactNode;
|
|
90
|
+
/**
|
|
91
|
+
* Default: `Replace`
|
|
92
|
+
*/
|
|
93
|
+
readonly replaceLabel?: React.ReactNode;
|
|
94
|
+
/**
|
|
95
|
+
* The name of the delete button for the screen readers and its tooltip
|
|
96
|
+
* Default: `Remove the file`
|
|
97
|
+
*/
|
|
98
|
+
readonly removeLabel?: string;
|
|
99
|
+
/**
|
|
100
|
+
* The size of the chosen file
|
|
101
|
+
* Default: `formatFileSize` — «54.1 KB»
|
|
102
|
+
*/
|
|
103
|
+
readonly formatSize?: (bytes: number) => React.ReactNode;
|
|
104
|
+
readonly disabled?: boolean;
|
|
105
|
+
readonly overrides?: FileDropzoneOverrides;
|
|
106
|
+
} & React.RefAttributes<HTMLDivElement>>;
|
|
107
|
+
export default _default;
|
|
@@ -0,0 +1,169 @@
|
|
|
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
|
+
};
|
|
16
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
17
|
+
var t = {};
|
|
18
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
19
|
+
t[p] = s[p];
|
|
20
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
21
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
22
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
23
|
+
t[p[i]] = s[p[i]];
|
|
24
|
+
}
|
|
25
|
+
return t;
|
|
26
|
+
};
|
|
27
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
28
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
29
|
+
};
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.isFileAccepted = exports.formatFileSize = void 0;
|
|
32
|
+
const react_1 = __importDefault(require("react"));
|
|
33
|
+
const styled_1 = __importDefault(require("@emotion/styled"));
|
|
34
|
+
const Button_1 = __importDefault(require("../Button"));
|
|
35
|
+
const FileDropzoneArea_1 = __importDefault(require("./FileDropzoneArea"));
|
|
36
|
+
const utils_1 = require("./utils");
|
|
37
|
+
Object.defineProperty(exports, "formatFileSize", { enumerable: true, get: function () { return utils_1.formatFileSize; } });
|
|
38
|
+
Object.defineProperty(exports, "isFileAccepted", { enumerable: true, get: function () { return utils_1.isFileAccepted; } });
|
|
39
|
+
const Icon = styled_1.default.span `
|
|
40
|
+
flex: none;
|
|
41
|
+
display: inline-flex;
|
|
42
|
+
font-size: 1.5em;
|
|
43
|
+
color: ${({ theme }) => theme.color.textSecondary.toString()};
|
|
44
|
+
`;
|
|
45
|
+
const Label = styled_1.default.span `
|
|
46
|
+
font-size: 0.875em;
|
|
47
|
+
font-weight: 600;
|
|
48
|
+
`;
|
|
49
|
+
const Hint = styled_1.default.span `
|
|
50
|
+
font-size: 0.75em;
|
|
51
|
+
color: ${({ theme }) => theme.color.textSecondary.toString()};
|
|
52
|
+
`;
|
|
53
|
+
const FileText = styled_1.default.span `
|
|
54
|
+
flex: 1;
|
|
55
|
+
min-width: 0;
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-direction: column;
|
|
58
|
+
gap: 0.15em;
|
|
59
|
+
text-align: left;
|
|
60
|
+
`;
|
|
61
|
+
/**
|
|
62
|
+
* The long name in one line: the whole name is in the tooltip
|
|
63
|
+
*/
|
|
64
|
+
const FileName = (0, styled_1.default)(Label) `
|
|
65
|
+
white-space: nowrap;
|
|
66
|
+
overflow: hidden;
|
|
67
|
+
text-overflow: ellipsis;
|
|
68
|
+
`;
|
|
69
|
+
const Path = styled_1.default.path `
|
|
70
|
+
fill: currentColor;
|
|
71
|
+
`;
|
|
72
|
+
const UploadIcon = () => (react_1.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24", "aria-hidden": true },
|
|
73
|
+
react_1.default.createElement(Path, { d: "M19.35 10.04A7.49 7.49 0 0 0 12 4C9.11 4 6.6 5.64 5.35 8.04A5.994 5.994 0 0 0 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4 0-2.05 1.53-3.76 3.56-3.97l1.07-.11.5-.95A5.469 5.469 0 0 1 12 6c2.62 0 4.88 1.86 5.39 4.43l.3 1.5 1.53.11A2.98 2.98 0 0 1 22 15c0 1.65-1.35 3-3 3zM8 13h2.55v3h2.9v-3H16l-4-4z" })));
|
|
74
|
+
const FileIcon = () => (react_1.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24", "aria-hidden": true },
|
|
75
|
+
react_1.default.createElement(Path, { d: "M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zM6 20V4h7v5h5v11H6zm2-6h8v2H8zm0 3h5v2H8z" })));
|
|
76
|
+
const TrashIcon = () => (react_1.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24", "aria-hidden": true },
|
|
77
|
+
react_1.default.createElement(Path, { d: "M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z" })));
|
|
78
|
+
/**
|
|
79
|
+
* The file by the click or by the drop: one area with the dashed border. The chosen file
|
|
80
|
+
* is the row with its name and size, «Replace» and the delete button; a new file can be
|
|
81
|
+
* dropped onto it too
|
|
82
|
+
*/
|
|
83
|
+
const FileDropzone = (props, ref) => {
|
|
84
|
+
const { value, onChange, accept, maxSize, onReject, label = 'Choose a file', hint, replaceLabel = 'Replace', removeLabel = 'Remove the file', formatSize = utils_1.formatFileSize, disabled = false, overrides } = props, nativeProps = __rest(props, ["value", "onChange", "accept", "maxSize", "onReject", "label", "hint", "replaceLabel", "removeLabel", "formatSize", "disabled", "overrides"]);
|
|
85
|
+
const AreaComponent = (overrides === null || overrides === void 0 ? void 0 : overrides.Area) || FileDropzoneArea_1.default;
|
|
86
|
+
const inputRef = react_1.default.useRef(null);
|
|
87
|
+
// dragenter/dragleave fire on every child: the counter keeps the highlight steady
|
|
88
|
+
const dragDepthRef = react_1.default.useRef(0);
|
|
89
|
+
const [isDragActive, setDragActive] = react_1.default.useState(false);
|
|
90
|
+
const take = (file) => {
|
|
91
|
+
if (!file) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (!(0, utils_1.isFileAccepted)(file, accept)) {
|
|
95
|
+
onReject === null || onReject === void 0 ? void 0 : onReject(file, 'type');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (typeof maxSize === 'number' && file.size > maxSize) {
|
|
99
|
+
onReject === null || onReject === void 0 ? void 0 : onReject(file, 'size');
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
onChange(file);
|
|
103
|
+
};
|
|
104
|
+
const choose = () => {
|
|
105
|
+
var _a;
|
|
106
|
+
if (!disabled) {
|
|
107
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.click();
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const dropHandlers = disabled
|
|
111
|
+
? {}
|
|
112
|
+
: {
|
|
113
|
+
onDragEnter: (event) => {
|
|
114
|
+
event.preventDefault();
|
|
115
|
+
dragDepthRef.current += 1;
|
|
116
|
+
setDragActive(true);
|
|
117
|
+
},
|
|
118
|
+
onDragOver: (event) => {
|
|
119
|
+
event.preventDefault();
|
|
120
|
+
},
|
|
121
|
+
onDragLeave: () => {
|
|
122
|
+
dragDepthRef.current = Math.max(0, dragDepthRef.current - 1);
|
|
123
|
+
if (dragDepthRef.current === 0) {
|
|
124
|
+
setDragActive(false);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
onDrop: (event) => {
|
|
128
|
+
var _a;
|
|
129
|
+
event.preventDefault();
|
|
130
|
+
dragDepthRef.current = 0;
|
|
131
|
+
setDragActive(false);
|
|
132
|
+
take((_a = event.dataTransfer.files) === null || _a === void 0 ? void 0 : _a[0]);
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
const input = (react_1.default.createElement("input", { hidden: true, ref: inputRef, type: "file", accept: accept, disabled: disabled,
|
|
136
|
+
// the input is inside the area: its click must not reach the area and open the dialog again
|
|
137
|
+
onClick: event => event.stopPropagation(), onChange: event => {
|
|
138
|
+
var _a;
|
|
139
|
+
const file = (_a = event.currentTarget.files) === null || _a === void 0 ? void 0 : _a[0];
|
|
140
|
+
// the same file can be chosen again after the removal
|
|
141
|
+
event.currentTarget.value = '';
|
|
142
|
+
take(file);
|
|
143
|
+
} }));
|
|
144
|
+
if (value) {
|
|
145
|
+
return (react_1.default.createElement(AreaComponent, Object.assign({}, nativeProps, dropHandlers, { active: isDragActive, filled: true, disabled: disabled, ref: ref }),
|
|
146
|
+
input,
|
|
147
|
+
react_1.default.createElement(Icon, null,
|
|
148
|
+
react_1.default.createElement(FileIcon, null)),
|
|
149
|
+
react_1.default.createElement(FileText, null,
|
|
150
|
+
react_1.default.createElement(FileName, { title: value.name }, value.name),
|
|
151
|
+
react_1.default.createElement(Hint, null, formatSize(value.size))),
|
|
152
|
+
react_1.default.createElement(Button_1.default, { type: "button", variant: "plain", disabled: disabled, onClick: choose }, replaceLabel),
|
|
153
|
+
react_1.default.createElement(Button_1.default, { type: "button", variant: "plain", color: "error", iconOnly: true, disabled: disabled, title: removeLabel, "aria-label": removeLabel, onClick: () => onChange(null) },
|
|
154
|
+
react_1.default.createElement(TrashIcon, null))));
|
|
155
|
+
}
|
|
156
|
+
return (react_1.default.createElement(AreaComponent, Object.assign({ role: "button", tabIndex: disabled ? -1 : 0, "aria-disabled": disabled || undefined }, nativeProps, dropHandlers, { active: isDragActive, filled: false, disabled: disabled, onClick: choose, onKeyDown: event => {
|
|
157
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
158
|
+
event.preventDefault();
|
|
159
|
+
choose();
|
|
160
|
+
}
|
|
161
|
+
}, ref: ref }),
|
|
162
|
+
input,
|
|
163
|
+
react_1.default.createElement(Icon, null,
|
|
164
|
+
react_1.default.createElement(UploadIcon, null)),
|
|
165
|
+
react_1.default.createElement(Label, null, label),
|
|
166
|
+
hint && react_1.default.createElement(Hint, null, hint)));
|
|
167
|
+
};
|
|
168
|
+
__exportStar(require("./FileDropzoneArea"), exports);
|
|
169
|
+
exports.default = react_1.default.forwardRef(FileDropzone);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The file matches `accept` of the input: the MIME types (`image/png`), the groups (`image/*`)
|
|
3
|
+
* and the extensions (`.pdf`). The empty `accept` takes any file
|
|
4
|
+
*/
|
|
5
|
+
export declare const isFileAccepted: (file: File, accept?: string) => boolean;
|
|
6
|
+
/**
|
|
7
|
+
* «54.1 KB», «2.3 MB»: the decimal units, as the file managers show
|
|
8
|
+
*/
|
|
9
|
+
export declare const formatFileSize: (bytes: number) => string;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatFileSize = exports.isFileAccepted = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The file matches `accept` of the input: the MIME types (`image/png`), the groups (`image/*`)
|
|
6
|
+
* and the extensions (`.pdf`). The empty `accept` takes any file
|
|
7
|
+
*/
|
|
8
|
+
const isFileAccepted = (file, accept) => {
|
|
9
|
+
if (!accept) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
const name = file.name.toLowerCase();
|
|
13
|
+
const type = file.type.toLowerCase();
|
|
14
|
+
return accept
|
|
15
|
+
.split(',')
|
|
16
|
+
.map(item => item.trim().toLowerCase())
|
|
17
|
+
.filter(Boolean)
|
|
18
|
+
.some(item => {
|
|
19
|
+
if (item.startsWith('.')) {
|
|
20
|
+
return name.endsWith(item);
|
|
21
|
+
}
|
|
22
|
+
if (item.endsWith('/*')) {
|
|
23
|
+
return type.startsWith(item.slice(0, -1));
|
|
24
|
+
}
|
|
25
|
+
return type === item;
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
exports.isFileAccepted = isFileAccepted;
|
|
29
|
+
/**
|
|
30
|
+
* «54.1 KB», «2.3 MB»: the decimal units, as the file managers show
|
|
31
|
+
*/
|
|
32
|
+
const formatFileSize = (bytes) => {
|
|
33
|
+
const units = ['B', 'KB', 'MB', 'GB'];
|
|
34
|
+
let value = bytes;
|
|
35
|
+
let unit = 0;
|
|
36
|
+
while (value >= 1000 && unit < units.length - 1) {
|
|
37
|
+
value /= 1000;
|
|
38
|
+
unit += 1;
|
|
39
|
+
}
|
|
40
|
+
return `${unit === 0 ? value : value.toFixed(1).replace(/\.0$/, '')} ${units[unit]}`;
|
|
41
|
+
};
|
|
42
|
+
exports.formatFileSize = formatFileSize;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
const react_1 = __importDefault(require("react"));
|
|
18
|
+
const styled_1 = __importDefault(require("@emotion/styled"));
|
|
19
|
+
/**
|
|
20
|
+
* The color of the text around: the button stands in the text, in the label of a field,
|
|
21
|
+
* in a colored header of the dialog
|
|
22
|
+
*/
|
|
23
|
+
const StyledButton = styled_1.default.button `
|
|
24
|
+
box-sizing: content-box;
|
|
25
|
+
display: inline-flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
margin: 0 0.15em;
|
|
29
|
+
padding: 0.2em;
|
|
30
|
+
border: none;
|
|
31
|
+
border-radius: 50%;
|
|
32
|
+
background: none;
|
|
33
|
+
font: inherit;
|
|
34
|
+
font-size: 1em;
|
|
35
|
+
line-height: 1;
|
|
36
|
+
color: inherit;
|
|
37
|
+
opacity: 0.6;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
vertical-align: middle;
|
|
40
|
+
transition:
|
|
41
|
+
opacity 120ms ease-out,
|
|
42
|
+
background-color 120ms ease-out;
|
|
43
|
+
|
|
44
|
+
&:hover,
|
|
45
|
+
&:focus-visible,
|
|
46
|
+
&[aria-expanded='true'] {
|
|
47
|
+
opacity: 1;
|
|
48
|
+
background-color: color-mix(in srgb, currentColor 15%, transparent);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
&:focus-visible {
|
|
52
|
+
outline: 2px solid ${({ theme }) => theme.color.accentPrimary.toString()};
|
|
53
|
+
outline-offset: 1px;
|
|
54
|
+
}
|
|
55
|
+
`;
|
|
56
|
+
const Path = styled_1.default.path `
|
|
57
|
+
fill: currentColor;
|
|
58
|
+
`;
|
|
59
|
+
/**
|
|
60
|
+
* «?» in the circle. `children` replaces the icon
|
|
61
|
+
*/
|
|
62
|
+
const HintPopoverButton = (props, ref) => {
|
|
63
|
+
const { children } = props, nativeProps = __rest(props, ["children"]);
|
|
64
|
+
return (react_1.default.createElement(StyledButton, Object.assign({ type: "button" }, nativeProps, { ref: ref }), children !== null && children !== void 0 ? children : (react_1.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 24 24", "aria-hidden": true },
|
|
65
|
+
react_1.default.createElement(Path, { d: "M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z" })))));
|
|
66
|
+
};
|
|
67
|
+
exports.default = react_1.default.forwardRef(HintPopoverButton);
|