@gen-epix/ui-core-components 4.0.2 → 4.1.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/components/BackdropSpinner/BackdropSpinner.d.ts +2 -1
- package/dist/components/BackdropSpinner/index.js +7 -6
- package/dist/components/BackdropSpinner/index.js.map +1 -1
- package/dist/components/Dialog/Dialog.d.ts +1 -1
- package/dist/components/Dialog/index.js +29 -29
- package/dist/components/Dialog/index.js.map +1 -1
- package/dist/components/FileDropZone/FileDropZone.d.ts +16 -0
- package/dist/components/FileDropZone/index.d.ts +1 -0
- package/dist/components/FileDropZone/index.js +152 -0
- package/dist/components/FileDropZone/index.js.map +1 -0
- package/dist/components/MultiFileUploader/MultiFileUploader.d.ts +7 -0
- package/dist/components/MultiFileUploader/index.d.ts +1 -0
- package/dist/components/MultiFileUploader/index.js +1352 -0
- package/dist/components/MultiFileUploader/index.js.map +1 -0
- package/dist/components/Spinner/Spinner.d.ts +2 -1
- package/dist/components/Spinner/index.js +23 -19
- package/dist/components/Spinner/index.js.map +1 -1
- package/dist/locale/en.json +15 -1
- package/dist/locale/nl.json +16 -2
- package/package.json +12 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SpinnerProps } from '../Spinner';
|
|
2
2
|
export type BackdropSpinnerProps = {
|
|
3
|
+
readonly backgroundColor?: string;
|
|
3
4
|
readonly open: boolean;
|
|
4
5
|
} & Omit<SpinnerProps, 'inline'>;
|
|
5
|
-
export declare const BackdropSpinner: ({ open, ...spinnerProps }: BackdropSpinnerProps) => import("react").JSX.Element;
|
|
6
|
+
export declare const BackdropSpinner: ({ backgroundColor, open, ...spinnerProps }: BackdropSpinnerProps) => import("react").JSX.Element;
|
|
@@ -2,15 +2,16 @@ import { Spinner as e } from "../Spinner/index.js";
|
|
|
2
2
|
import { Backdrop as t, useTheme as n } from "@mui/material";
|
|
3
3
|
import { jsx as r } from "react/jsx-runtime";
|
|
4
4
|
//#region src/components/BackdropSpinner/BackdropSpinner.tsx
|
|
5
|
-
var i = ({
|
|
6
|
-
let
|
|
5
|
+
var i = ({ backgroundColor: i, open: a, ...o }) => {
|
|
6
|
+
let s = n();
|
|
7
7
|
return /* @__PURE__ */ r(t, {
|
|
8
|
-
open:
|
|
8
|
+
open: a,
|
|
9
9
|
sx: {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
backdropFilter: "blur(3px)",
|
|
11
|
+
backgroundColor: i ?? (s.palette.mode === "light" ? "rgba(255, 255, 255, 0.6)" : "rgba(0, 0, 0, 0.6)"),
|
|
12
|
+
zIndex: s.zIndex.drawer + 1
|
|
12
13
|
},
|
|
13
|
-
children:
|
|
14
|
+
children: a && /* @__PURE__ */ r(e, { ...o })
|
|
14
15
|
});
|
|
15
16
|
};
|
|
16
17
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/BackdropSpinner/BackdropSpinner.tsx"],"sourcesContent":["import {\n Backdrop,\n useTheme,\n} from '@mui/material';\n\nimport type { SpinnerProps } from '../Spinner';\nimport { Spinner } from '../Spinner';\n\nexport type BackdropSpinnerProps = {\n readonly open: boolean;\n} & Omit<SpinnerProps, 'inline'>;\n\nexport const BackdropSpinner = ({ open, ...spinnerProps }: BackdropSpinnerProps) => {\n const theme = useTheme();\n return (\n <Backdrop\n open={open}\n sx={{\n backgroundColor: theme.palette.mode === 'light' ? 'rgba(255, 255, 255, 0.
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/BackdropSpinner/BackdropSpinner.tsx"],"sourcesContent":["import {\n Backdrop,\n useTheme,\n} from '@mui/material';\n\nimport type { SpinnerProps } from '../Spinner';\nimport { Spinner } from '../Spinner';\n\nexport type BackdropSpinnerProps = {\n readonly backgroundColor?: string;\n readonly open: boolean;\n} & Omit<SpinnerProps, 'inline'>;\n\nexport const BackdropSpinner = ({ backgroundColor, open, ...spinnerProps }: BackdropSpinnerProps) => {\n const theme = useTheme();\n return (\n <Backdrop\n open={open}\n sx={{\n backdropFilter: 'blur(3px)',\n backgroundColor: backgroundColor ?? (theme.palette.mode === 'light' ? 'rgba(255, 255, 255, 0.6)' : 'rgba(0, 0, 0, 0.6)'),\n zIndex: theme.zIndex.drawer + 1,\n }}\n >\n {open && (\n <Spinner\n {...spinnerProps}\n />\n )}\n </Backdrop>\n );\n};\n"],"mappings":";;;;AAaA,IAAa,KAAmB,EAAE,oBAAiB,SAAM,GAAG,QAAyC;CACnG,IAAM,IAAQ,EAAS;CACvB,OACE,kBAAC,GAAD;EACQ;EACN,IAAI;GACF,gBAAgB;GAChB,iBAAiB,MAAoB,EAAM,QAAQ,SAAS,UAAU,6BAA6B;GACnG,QAAQ,EAAM,OAAO,SAAS;EAChC;EAEC,UAAA,KACC,kBAAC,GAAD,EACE,GAAI,EACL,CAAA;CAEK,CAAA;AAEd"}
|
|
@@ -24,4 +24,4 @@ export type DialogProps = {
|
|
|
24
24
|
readonly title?: string;
|
|
25
25
|
readonly titleVariant?: TypographyVariant;
|
|
26
26
|
};
|
|
27
|
-
export declare const Dialog: ({
|
|
27
|
+
export declare const Dialog: ({ actions, children, dialogContentRef, disableBackdropClick, fullScreen, fullWidth, maxWidth, noCloseButton, noPadding, noTitle, onClose, permalink, testId, title, titleVariant, }: PropsWithChildren<DialogProps>) => ReactElement;
|
|
@@ -9,29 +9,29 @@ import { useTranslation as p } from "react-i18next";
|
|
|
9
9
|
import { TestIdUtil as m } from "@gen-epix/ui-core/utils/TestIdUtil";
|
|
10
10
|
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
11
11
|
//#region src/components/Dialog/Dialog.tsx
|
|
12
|
-
var _ = /* @__PURE__ */ e(t(), 1), v = (e) => (0, _.default)(e) && "label" in e, y = ({
|
|
13
|
-
let { t:
|
|
14
|
-
|
|
15
|
-
}, [
|
|
12
|
+
var _ = /* @__PURE__ */ e(t(), 1), v = (e) => (0, _.default)(e) && "label" in e, y = ({ actions: e, children: t, dialogContentRef: _, disableBackdropClick: y = !1, fullScreen: b = !1, fullWidth: x = !1, maxWidth: S = !1, noCloseButton: C = !1, noPadding: w = !1, noTitle: T = !1, onClose: E, permalink: D, testId: O, title: k, titleVariant: A = "h5" }) => {
|
|
13
|
+
let { t: j } = p(), M = r((e, t) => {
|
|
14
|
+
y && (t === "backdropClick" || t === "escapeKeyDown") || E?.();
|
|
15
|
+
}, [y, E]), N = r(() => D, [D]);
|
|
16
16
|
return /* @__PURE__ */ g(o, {
|
|
17
|
-
...m.createAttributes(
|
|
18
|
-
fullScreen:
|
|
19
|
-
fullWidth:
|
|
20
|
-
maxWidth:
|
|
21
|
-
onClose:
|
|
17
|
+
...m.createAttributes(O, { title: k }),
|
|
18
|
+
fullScreen: b,
|
|
19
|
+
fullWidth: x,
|
|
20
|
+
maxWidth: S,
|
|
21
|
+
onClose: M,
|
|
22
22
|
open: !0,
|
|
23
|
-
sx: { "& .MuiDialogContent-root, & .MuiCardContent-root:last-child": { padding:
|
|
23
|
+
sx: { "& .MuiDialogContent-root, & .MuiCardContent-root:last-child": { padding: w ? "0" : void 0 } },
|
|
24
24
|
children: [
|
|
25
|
-
!
|
|
25
|
+
!T && /* @__PURE__ */ g(i, {
|
|
26
26
|
sx: {
|
|
27
27
|
display: "flex",
|
|
28
28
|
justifyContent: "space-between"
|
|
29
29
|
},
|
|
30
30
|
children: [/* @__PURE__ */ g(l, {
|
|
31
|
-
...m.createAttributes(`${
|
|
31
|
+
...m.createAttributes(`${O}-title`),
|
|
32
32
|
sx: { pr: 3 },
|
|
33
|
-
variant:
|
|
34
|
-
children: [
|
|
33
|
+
variant: A,
|
|
34
|
+
children: [k, D && /* @__PURE__ */ h(i, {
|
|
35
35
|
className: "genepix-permalink",
|
|
36
36
|
sx: {
|
|
37
37
|
display: "inline-block",
|
|
@@ -45,30 +45,30 @@ var _ = /* @__PURE__ */ e(t(), 1), v = (e) => (0, _.default)(e) && "label" in e,
|
|
|
45
45
|
width: 20
|
|
46
46
|
} },
|
|
47
47
|
iconOnly: !0,
|
|
48
|
-
onGetClipboardValue:
|
|
48
|
+
onGetClipboardValue: N
|
|
49
49
|
})
|
|
50
50
|
})]
|
|
51
|
-
}), !
|
|
52
|
-
...m.createAttributes(`${
|
|
53
|
-
"aria-label":
|
|
54
|
-
onClick:
|
|
51
|
+
}), !C && /* @__PURE__ */ h(u, {
|
|
52
|
+
...m.createAttributes(`${O}-closeButton`),
|
|
53
|
+
"aria-label": k ? j("Close dialog with title: {{title}}", { title: k }) : j`Close dialog`,
|
|
54
|
+
onClick: E,
|
|
55
55
|
sx: { color: "grey.500" },
|
|
56
|
-
title:
|
|
56
|
+
title: j`Close`,
|
|
57
57
|
children: /* @__PURE__ */ h(d, {})
|
|
58
58
|
})]
|
|
59
59
|
}),
|
|
60
|
-
!!
|
|
61
|
-
...m.createAttributes(`${
|
|
62
|
-
dividers:
|
|
63
|
-
ref:
|
|
64
|
-
sx: { paddingTop:
|
|
65
|
-
children:
|
|
60
|
+
!!t && /* @__PURE__ */ h(c, {
|
|
61
|
+
...m.createAttributes(`${O}-content`),
|
|
62
|
+
dividers: !0,
|
|
63
|
+
ref: _,
|
|
64
|
+
sx: { paddingTop: b ? 0 : void 0 },
|
|
65
|
+
children: t
|
|
66
66
|
}),
|
|
67
|
-
|
|
68
|
-
...m.createAttributes(`${
|
|
67
|
+
e?.length > 0 && /* @__PURE__ */ h(s, {
|
|
68
|
+
...m.createAttributes(`${O}-actions`),
|
|
69
69
|
children: /* @__PURE__ */ h(i, {
|
|
70
70
|
sx: { "& > button": { margin: 1 } },
|
|
71
|
-
children:
|
|
71
|
+
children: e.map((e) => v(e) ? /* @__PURE__ */ h(a, {
|
|
72
72
|
...e,
|
|
73
73
|
children: e.label
|
|
74
74
|
}, e.label) : e)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import type {\n DialogProps as MuiDialogProps,\n TypographyVariant,\n} from '@mui/material';\nimport {\n Box,\n Button,\n DialogContent,\n DialogTitle,\n IconButton,\n Dialog as MuiDialog,\n DialogActions as MuiDialogActions,\n} from '@mui/material';\nimport CloseIcon from '@mui/icons-material/Close';\nimport LinkIcon from '@mui/icons-material/Link';\nimport isObject from 'lodash/isObject';\nimport type {\n PropsWithChildren,\n ReactElement,\n RefObject,\n} from 'react';\nimport { useCallback } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { TestIdUtil } from '@gen-epix/ui-core/utils/TestIdUtil';\n\nimport { CopyToClipboardButton } from '../CopyToClipboardButton';\n\nexport type DialogAction = DialogActionButton | ReactElement;\n\nexport type DialogActionButton = {\n label: string;\n} & Omit<Parameters<typeof Button>[0], 'children'>;\n\nexport type DialogProps = {\n readonly actionButtons?: () => ReactElement;\n readonly actions?: DialogAction[];\n readonly component?: (props: { onDialogTitleChange?: (title: string) => void }) => ReactElement;\n readonly dialogContentRef?: RefObject<HTMLDivElement>;\n readonly disableBackdropClick?: boolean;\n readonly fullScreen?: boolean;\n readonly fullWidth?: boolean;\n readonly maxWidth?: MuiDialogProps['maxWidth'];\n readonly noCloseButton?: boolean;\n readonly noPadding?: boolean;\n readonly noTitle?: boolean;\n readonly onClose?: () => void;\n readonly permalink?: string;\n readonly testId: string;\n readonly title?: string;\n readonly titleVariant?: TypographyVariant;\n};\n\nconst isDialogActionButton = (action: DialogAction): action is DialogActionButton => {\n return isObject(action) && 'label' in action;\n};\n\nexport const Dialog = ({\n
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Dialog/Dialog.tsx"],"sourcesContent":["import type {\n DialogProps as MuiDialogProps,\n TypographyVariant,\n} from '@mui/material';\nimport {\n Box,\n Button,\n DialogContent,\n DialogTitle,\n IconButton,\n Dialog as MuiDialog,\n DialogActions as MuiDialogActions,\n} from '@mui/material';\nimport CloseIcon from '@mui/icons-material/Close';\nimport LinkIcon from '@mui/icons-material/Link';\nimport isObject from 'lodash/isObject';\nimport type {\n PropsWithChildren,\n ReactElement,\n RefObject,\n} from 'react';\nimport { useCallback } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { TestIdUtil } from '@gen-epix/ui-core/utils/TestIdUtil';\n\nimport { CopyToClipboardButton } from '../CopyToClipboardButton';\n\nexport type DialogAction = DialogActionButton | ReactElement;\n\nexport type DialogActionButton = {\n label: string;\n} & Omit<Parameters<typeof Button>[0], 'children'>;\n\nexport type DialogProps = {\n readonly actionButtons?: () => ReactElement;\n readonly actions?: DialogAction[];\n readonly component?: (props: { onDialogTitleChange?: (title: string) => void }) => ReactElement;\n readonly dialogContentRef?: RefObject<HTMLDivElement>;\n readonly disableBackdropClick?: boolean;\n readonly fullScreen?: boolean;\n readonly fullWidth?: boolean;\n readonly maxWidth?: MuiDialogProps['maxWidth'];\n readonly noCloseButton?: boolean;\n readonly noPadding?: boolean;\n readonly noTitle?: boolean;\n readonly onClose?: () => void;\n readonly permalink?: string;\n readonly testId: string;\n readonly title?: string;\n readonly titleVariant?: TypographyVariant;\n};\n\nconst isDialogActionButton = (action: DialogAction): action is DialogActionButton => {\n return isObject(action) && 'label' in action;\n};\n\nexport const Dialog = ({\n actions,\n children,\n dialogContentRef,\n disableBackdropClick = false,\n fullScreen = false,\n fullWidth = false,\n maxWidth = false,\n noCloseButton = false,\n noPadding = false,\n noTitle = false,\n onClose,\n permalink,\n testId,\n title,\n titleVariant = 'h5',\n}: PropsWithChildren<DialogProps>): ReactElement => {\n const { t } = useTranslation();\n const onMuiDialogClose = useCallback<NonNullable<MuiDialogProps['onClose']>>((_event, reason) => {\n if (disableBackdropClick && (reason === 'backdropClick' || reason === 'escapeKeyDown')) {\n return;\n }\n onClose?.();\n }, [disableBackdropClick, onClose]);\n\n const onGetClipboardValue = useCallback(() => {\n return permalink;\n }, [permalink]);\n\n return (\n <MuiDialog\n {...TestIdUtil.createAttributes(testId, { title })}\n fullScreen={fullScreen}\n fullWidth={fullWidth}\n maxWidth={maxWidth}\n onClose={onMuiDialogClose}\n open\n sx={{\n '& .MuiDialogContent-root, & .MuiCardContent-root:last-child': {\n padding: noPadding ? '0' : undefined,\n },\n }}\n >\n {!noTitle && (\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n }}\n >\n <DialogTitle\n {...TestIdUtil.createAttributes(`${testId}-title`)}\n sx={{\n pr: 3,\n }}\n variant={titleVariant}\n >\n {title}\n {permalink && (\n <Box\n className={'genepix-permalink'}\n sx={{\n display: 'inline-block',\n marginLeft: 1,\n }}\n >\n <CopyToClipboardButton\n baseIcon={<LinkIcon />}\n buttonProps={{\n sx: {\n '& svg': {\n fontSize: 20,\n },\n height: 20,\n width: 20,\n },\n }}\n iconOnly\n onGetClipboardValue={onGetClipboardValue}\n />\n </Box>\n )}\n </DialogTitle>\n {!noCloseButton && (\n <IconButton\n {...TestIdUtil.createAttributes(`${testId}-closeButton`)}\n aria-label={title ? t('Close dialog with title: {{title}}', { title }) : t`Close dialog`}\n onClick={onClose}\n sx={{\n color: 'grey.500',\n }}\n title={t`Close`}\n >\n <CloseIcon />\n </IconButton>\n )}\n </Box>\n )}\n {!!children && (\n <DialogContent\n {...TestIdUtil.createAttributes(`${testId}-content`)}\n dividers\n ref={dialogContentRef}\n sx={{\n paddingTop: fullScreen ? 0 : undefined,\n }}\n >\n {children}\n </DialogContent>\n )}\n {actions?.length > 0 && (\n <MuiDialogActions {...TestIdUtil.createAttributes(`${testId}-actions`)}>\n <Box\n sx={{\n '& > button': {\n margin: 1,\n },\n }}\n >\n {actions.map((action) => {\n if (isDialogActionButton(action)) {\n return (\n <Button\n key={action.label}\n {...action}\n >\n {action.label}\n </Button>\n );\n }\n return action;\n })}\n </Box>\n </MuiDialogActions>\n )}\n </MuiDialog>\n );\n};\n"],"mappings":";;;;;;;;;;;mCAoDM,KAAwB,OAC5B,GAAO,EAAA,QAAA,CAAS,CAAM,KAAK,WAAW,GAG3B,KAAU,EACrB,YACA,aACA,qBACA,0BAAuB,IACvB,gBAAa,IACb,eAAY,IACZ,cAAW,IACX,mBAAgB,IAChB,eAAY,IACZ,aAAU,IACV,YACA,cACA,WACA,UACA,kBAAe,WACmC;CAClD,IAAM,EAAE,SAAM,EAAe,GACvB,IAAmB,GAAqD,GAAQ,MAAW;EAC3F,MAAyB,MAAW,mBAAmB,MAAW,oBAGtE,IAAU;CACZ,GAAG,CAAC,GAAsB,CAAO,CAAC,GAE5B,IAAsB,QACnB,GACN,CAAC,CAAS,CAAC;CAEd,OACE,kBAAC,GAAD;EACE,GAAI,EAAW,iBAAiB,GAAQ,EAAE,SAAM,CAAC;EACrC;EACD;EACD;EACV,SAAS;EACT,MAAA;EACA,IAAI,EACF,+DAA+D,EAC7D,SAAS,IAAY,MAAM,KAAA,EAC7B,EACF;EAXF,UAAA;GAaG,CAAC,KACA,kBAAC,GAAD;IACE,IAAI;KACF,SAAS;KACT,gBAAgB;IAClB;IAJF,UAAA,CAME,kBAAC,GAAD;KACE,GAAI,EAAW,iBAAiB,GAAG,EAAO,OAAO;KACjD,IAAI,EACF,IAAI,EACN;KACA,SAAS;KALX,UAAA,CAOG,GACA,KACC,kBAAC,GAAD;MACE,WAAW;MACX,IAAI;OACF,SAAS;OACT,YAAY;MACd;MAEA,UAAA,kBAAC,GAAD;OACE,UAAU,kBAAC,GAAD,CAAW,CAAA;OACrB,aAAa,EACX,IAAI;QACF,SAAS,EACP,UAAU,GACZ;QACA,QAAQ;QACR,OAAO;OACT,EACF;OACA,UAAA;OACqB;MACtB,CAAA;KACE,CAAA,CAEI;IACZ,CAAA,GAAA,CAAC,KACA,kBAAC,GAAD;KACE,GAAI,EAAW,iBAAiB,GAAG,EAAO,aAAa;KACvD,cAAY,IAAQ,EAAE,sCAAsC,EAAE,SAAM,CAAC,IAAI,CAAC;KAC1E,SAAS;KACT,IAAI,EACF,OAAO,WACT;KACA,OAAO,CAAC;KAER,UAAA,kBAAC,GAAD,CAAY,CAAA;IACF,CAAA,CAEX;;GAEN,CAAC,CAAC,KACD,kBAAC,GAAD;IACE,GAAI,EAAW,iBAAiB,GAAG,EAAO,SAAS;IACnD,UAAA;IACA,KAAK;IACL,IAAI,EACF,YAAY,IAAa,IAAI,KAAA,EAC/B;IAEC;GACY,CAAA;GAEhB,GAAS,SAAS,KACjB,kBAAC,GAAD;IAAkB,GAAI,EAAW,iBAAiB,GAAG,EAAO,SAAS;IACnE,UAAA,kBAAC,GAAD;KACE,IAAI,EACF,cAAc,EACZ,QAAQ,EACV,EACF;KAEC,UAAA,EAAQ,KAAK,MACR,EAAqB,CAAM,IAE3B,kBAAC,GAAD;MAEE,GAAI;MAEH,UAAA,EAAO;KACF,GAJD,EAAO,KAIN,IAGL,CACR;IACE,CAAA;GACW,CAAA;EAEX;;AAEf"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Ref } from 'react';
|
|
2
|
+
export interface FileDropZoneProps {
|
|
3
|
+
readonly accept: string;
|
|
4
|
+
readonly ariaDescribedBy?: string;
|
|
5
|
+
readonly disabled?: boolean;
|
|
6
|
+
readonly error?: boolean;
|
|
7
|
+
readonly files: FileList | null;
|
|
8
|
+
readonly helperText?: string;
|
|
9
|
+
readonly label?: string;
|
|
10
|
+
readonly labelledById?: string;
|
|
11
|
+
readonly multiple?: boolean;
|
|
12
|
+
readonly onBlur?: () => void;
|
|
13
|
+
readonly onFilesSelected: (files: FileList) => void;
|
|
14
|
+
readonly ref?: Ref<HTMLDivElement>;
|
|
15
|
+
}
|
|
16
|
+
export declare const FileDropZone: ({ accept, ariaDescribedBy, disabled, error, files, helperText, label, labelledById, multiple, onBlur, onFilesSelected, ref, }: FileDropZoneProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './FileDropZone';
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { useCallback as e, useEffect as t, useId as n, useRef as r, useState as i } from "react";
|
|
2
|
+
import { Box as a, Typography as o } from "@mui/material";
|
|
3
|
+
import { useTranslation as s } from "react-i18next";
|
|
4
|
+
import { Fragment as c, jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
5
|
+
import { visuallyHidden as d } from "@mui/utils";
|
|
6
|
+
import { FileUtil as f } from "@gen-epix/ui-core/utils/FileUtil";
|
|
7
|
+
import p from "@mui/icons-material/CloudUploadOutlined";
|
|
8
|
+
import m from "@mui/icons-material/InsertDriveFileOutlined";
|
|
9
|
+
//#region src/components/FileDropZone/FileDropZone.tsx
|
|
10
|
+
var h = ({ accept: h, ariaDescribedBy: g, disabled: _, error: v, files: y, helperText: b, label: x, labelledById: S, multiple: C = !1, onBlur: w, onFilesSelected: T, ref: E }) => {
|
|
11
|
+
let { t: D } = s(), [O, k] = i(!1), A = r(null), j = n(), M = D("{{label}} ({{accept}})", {
|
|
12
|
+
accept: h.split(",").join(", "),
|
|
13
|
+
label: x
|
|
14
|
+
});
|
|
15
|
+
t(() => {
|
|
16
|
+
!y && A.current && (A.current.value = "");
|
|
17
|
+
}, [y]);
|
|
18
|
+
let N = e((e) => {
|
|
19
|
+
e.preventDefault(), !_ && k(!0);
|
|
20
|
+
}, [_]), P = e(() => {
|
|
21
|
+
k(!1);
|
|
22
|
+
}, []), F = e((e) => {
|
|
23
|
+
e.preventDefault(), k(!1), !_ && e.dataTransfer.files && e.dataTransfer.files.length > 0 && T(e.dataTransfer.files);
|
|
24
|
+
}, [_, T]), I = e((e) => {
|
|
25
|
+
e.target.files && e.target.files.length > 0 && T(e.target.files);
|
|
26
|
+
}, [T]), L = e(() => {
|
|
27
|
+
_ || A.current?.click();
|
|
28
|
+
}, [_]), R = e((e) => {
|
|
29
|
+
_ || (e.key === "Enter" || e.key === " ") && (e.preventDefault(), A.current?.click());
|
|
30
|
+
}, [_]), z = y ? Array.from(y) : [], B = z.length > 0, V = z.reduce((e, t) => e + t.size, 0), H = "background.paper", U = "divider";
|
|
31
|
+
return _ ? (H = "action.disabledBackground", U = "action.disabled") : O ? (H = "action.hover", U = "primary.main") : v && (U = "error.main"), /* @__PURE__ */ u(a, {
|
|
32
|
+
"aria-describedby": g ? `${g} ${j}` : j,
|
|
33
|
+
"aria-disabled": _,
|
|
34
|
+
"aria-label": S ? void 0 : M,
|
|
35
|
+
"aria-labelledby": S,
|
|
36
|
+
onBlur: w,
|
|
37
|
+
onClick: L,
|
|
38
|
+
onDragLeave: P,
|
|
39
|
+
onDragOver: N,
|
|
40
|
+
onDrop: F,
|
|
41
|
+
onKeyDown: R,
|
|
42
|
+
ref: E,
|
|
43
|
+
role: "button",
|
|
44
|
+
sx: {
|
|
45
|
+
"&:focus-visible": {
|
|
46
|
+
borderColor: "primary.main",
|
|
47
|
+
borderStyle: "solid"
|
|
48
|
+
},
|
|
49
|
+
alignItems: "center",
|
|
50
|
+
backgroundColor: H,
|
|
51
|
+
border: "2px dashed",
|
|
52
|
+
borderColor: U,
|
|
53
|
+
borderRadius: 2,
|
|
54
|
+
cursor: _ ? "default" : "pointer",
|
|
55
|
+
display: "flex",
|
|
56
|
+
flexDirection: "column",
|
|
57
|
+
gap: 1.5,
|
|
58
|
+
justifyContent: "center",
|
|
59
|
+
minHeight: 180,
|
|
60
|
+
opacity: _ ? .6 : 1,
|
|
61
|
+
padding: 3,
|
|
62
|
+
pointerEvents: _ ? "none" : "auto",
|
|
63
|
+
textAlign: "center",
|
|
64
|
+
transition: "all 0.2s ease"
|
|
65
|
+
},
|
|
66
|
+
tabIndex: _ ? -1 : 0,
|
|
67
|
+
children: [
|
|
68
|
+
/* @__PURE__ */ l("input", {
|
|
69
|
+
accept: h,
|
|
70
|
+
disabled: _,
|
|
71
|
+
multiple: C,
|
|
72
|
+
onChange: I,
|
|
73
|
+
ref: A,
|
|
74
|
+
style: { display: "none" },
|
|
75
|
+
type: "file"
|
|
76
|
+
}),
|
|
77
|
+
/* @__PURE__ */ u("span", {
|
|
78
|
+
id: j,
|
|
79
|
+
style: d,
|
|
80
|
+
children: [M, b ? ` ${b}` : ""]
|
|
81
|
+
}),
|
|
82
|
+
/* @__PURE__ */ l(a, {
|
|
83
|
+
"aria-atomic": !0,
|
|
84
|
+
"aria-live": "polite",
|
|
85
|
+
component: "span",
|
|
86
|
+
sx: {
|
|
87
|
+
alignItems: "center",
|
|
88
|
+
display: "flex",
|
|
89
|
+
flexDirection: "column",
|
|
90
|
+
gap: 1.5
|
|
91
|
+
},
|
|
92
|
+
children: B ? /* @__PURE__ */ u(c, { children: [
|
|
93
|
+
/* @__PURE__ */ l(m, {
|
|
94
|
+
color: "primary",
|
|
95
|
+
sx: { fontSize: 40 }
|
|
96
|
+
}),
|
|
97
|
+
/* @__PURE__ */ l(o, {
|
|
98
|
+
color: "success.main",
|
|
99
|
+
sx: { fontWeight: 600 },
|
|
100
|
+
variant: "subtitle1",
|
|
101
|
+
children: z.map((e) => e.name).join(", ")
|
|
102
|
+
}),
|
|
103
|
+
/* @__PURE__ */ u(o, {
|
|
104
|
+
color: "text.secondary",
|
|
105
|
+
variant: "caption",
|
|
106
|
+
children: [
|
|
107
|
+
f.getReadableFileSize(V),
|
|
108
|
+
" — ",
|
|
109
|
+
D("Click or drag to replace")
|
|
110
|
+
]
|
|
111
|
+
})
|
|
112
|
+
] }) : /* @__PURE__ */ u(c, { children: [
|
|
113
|
+
/* @__PURE__ */ l(p, {
|
|
114
|
+
color: "primary",
|
|
115
|
+
sx: { fontSize: 44 }
|
|
116
|
+
}),
|
|
117
|
+
/* @__PURE__ */ l(o, {
|
|
118
|
+
sx: { fontWeight: 600 },
|
|
119
|
+
variant: "subtitle1",
|
|
120
|
+
children: M
|
|
121
|
+
}),
|
|
122
|
+
/* @__PURE__ */ l(o, {
|
|
123
|
+
color: "text.secondary",
|
|
124
|
+
variant: "body2",
|
|
125
|
+
children: b || D("Drag & drop your file here, or click to browse")
|
|
126
|
+
}),
|
|
127
|
+
/* @__PURE__ */ l(a, {
|
|
128
|
+
"aria-hidden": !0,
|
|
129
|
+
component: "span",
|
|
130
|
+
sx: {
|
|
131
|
+
border: "1px solid",
|
|
132
|
+
borderColor: _ ? "action.disabled" : "primary.main",
|
|
133
|
+
borderRadius: 1,
|
|
134
|
+
color: _ ? "action.disabled" : "primary.main",
|
|
135
|
+
fontSize: "0.8125rem",
|
|
136
|
+
fontWeight: 500,
|
|
137
|
+
letterSpacing: "0.02857em",
|
|
138
|
+
mt: 1,
|
|
139
|
+
padding: "5px 14px",
|
|
140
|
+
textTransform: "uppercase"
|
|
141
|
+
},
|
|
142
|
+
children: D("Choose File")
|
|
143
|
+
})
|
|
144
|
+
] })
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
//#endregion
|
|
150
|
+
export { h as FileDropZone };
|
|
151
|
+
|
|
152
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/FileDropZone/FileDropZone.tsx"],"sourcesContent":["import type {\n ChangeEvent,\n DragEvent,\n KeyboardEvent as ReactKeyboardEvent,\n Ref,\n} from 'react';\nimport {\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n} from 'react';\nimport {\n Box,\n Typography,\n} from '@mui/material';\nimport { visuallyHidden } from '@mui/utils';\nimport CloudUploadOutlinedIcon from '@mui/icons-material/CloudUploadOutlined';\nimport InsertDriveFileOutlinedIcon from '@mui/icons-material/InsertDriveFileOutlined';\nimport { useTranslation } from 'react-i18next';\nimport { FileUtil } from '@gen-epix/ui-core/utils/FileUtil';\n\nexport interface FileDropZoneProps {\n readonly accept: string;\n readonly ariaDescribedBy?: string;\n readonly disabled?: boolean;\n readonly error?: boolean;\n readonly files: FileList | null;\n readonly helperText?: string;\n readonly label?: string;\n readonly labelledById?: string;\n readonly multiple?: boolean;\n readonly onBlur?: () => void;\n readonly onFilesSelected: (files: FileList) => void;\n readonly ref?: Ref<HTMLDivElement>;\n}\n\nexport const FileDropZone = ({\n accept,\n ariaDescribedBy,\n disabled,\n error,\n files,\n helperText,\n label,\n labelledById,\n multiple = false,\n onBlur,\n onFilesSelected,\n ref,\n}: FileDropZoneProps) => {\n const { t } = useTranslation();\n const [isDragOver, setIsDragOver] = useState(false);\n const inputRef = useRef<HTMLInputElement>(null);\n const descriptionId = useId();\n\n const translatedLabel = multiple\n ? t('{{label}} ({{accept}})', { accept: accept.split(',').join(', '), label })\n : t('{{label}} ({{accept}})', { accept: accept.split(',').join(', '), label });\n\n useEffect(() => {\n // allows re-selecting the same file after it was cleared externally\n if (!files && inputRef.current) {\n inputRef.current.value = '';\n }\n }, [files]);\n\n const onDragOver = useCallback((e: DragEvent) => {\n e.preventDefault();\n if (disabled) {\n return;\n }\n setIsDragOver(true);\n }, [disabled]);\n\n const onDragLeave = useCallback(() => {\n setIsDragOver(false);\n }, []);\n\n const onDrop = useCallback((e: DragEvent) => {\n e.preventDefault();\n setIsDragOver(false);\n if (disabled) {\n return;\n }\n if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {\n onFilesSelected(e.dataTransfer.files);\n }\n }, [disabled, onFilesSelected]);\n\n const onFileChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {\n if (e.target.files && e.target.files.length > 0) {\n onFilesSelected(e.target.files);\n }\n }, [onFilesSelected]);\n\n const onClick = useCallback(() => {\n if (disabled) {\n return;\n }\n inputRef.current?.click();\n }, [disabled]);\n\n const onKeyDown = useCallback((e: ReactKeyboardEvent) => {\n if (disabled) {\n return;\n }\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n inputRef.current?.click();\n }\n }, [disabled]);\n\n const selectedFiles = files ? Array.from(files) : [];\n const hasFiles = selectedFiles.length > 0;\n const totalSize = selectedFiles.reduce((sum, currentFile) => sum + currentFile.size, 0);\n\n let backgroundColor = 'background.paper';\n let borderColor = 'divider';\n if (disabled) {\n backgroundColor = 'action.disabledBackground';\n borderColor = 'action.disabled';\n } else if (isDragOver) {\n backgroundColor = 'action.hover';\n borderColor = 'primary.main';\n } else if (error) {\n borderColor = 'error.main';\n }\n\n return (\n <Box\n aria-describedby={ariaDescribedBy ? `${ariaDescribedBy} ${descriptionId}` : descriptionId}\n aria-disabled={disabled}\n aria-label={labelledById ? undefined : translatedLabel}\n aria-labelledby={labelledById}\n onBlur={onBlur}\n onClick={onClick}\n onDragLeave={onDragLeave}\n onDragOver={onDragOver}\n onDrop={onDrop}\n onKeyDown={onKeyDown}\n ref={ref}\n role={'button'}\n sx={{\n '&:focus-visible': {\n borderColor: 'primary.main',\n borderStyle: 'solid',\n },\n alignItems: 'center',\n backgroundColor,\n border: '2px dashed',\n borderColor,\n borderRadius: 2,\n cursor: disabled ? 'default' : 'pointer',\n display: 'flex',\n flexDirection: 'column',\n gap: 1.5,\n justifyContent: 'center',\n minHeight: 180,\n opacity: disabled ? 0.6 : 1,\n padding: 3,\n pointerEvents: disabled ? 'none' : 'auto',\n textAlign: 'center',\n transition: 'all 0.2s ease',\n }}\n tabIndex={disabled ? -1 : 0}\n >\n <input\n accept={accept}\n disabled={disabled}\n multiple={multiple}\n onChange={onFileChange}\n ref={inputRef}\n style={{ display: 'none' }}\n type={'file'}\n />\n <span\n id={descriptionId}\n style={visuallyHidden}\n >\n {translatedLabel}\n {helperText ? ` ${helperText}` : ''}\n </span>\n <Box\n aria-atomic\n aria-live={'polite'}\n component={'span'}\n sx={{ alignItems: 'center', display: 'flex', flexDirection: 'column', gap: 1.5 }}\n >\n {hasFiles ? (\n <>\n <InsertDriveFileOutlinedIcon\n color={'primary'}\n sx={{ fontSize: 40 }}\n />\n <Typography\n color={'success.main'}\n sx={{ fontWeight: 600 }}\n variant={'subtitle1'}\n >\n {selectedFiles.map((currentFile) => currentFile.name).join(', ')}\n </Typography>\n <Typography\n color={'text.secondary'}\n variant={'caption'}\n >\n {FileUtil.getReadableFileSize(totalSize)}\n {' — '}\n {t('Click or drag to replace')}\n </Typography>\n </>\n ) : (\n <>\n <CloudUploadOutlinedIcon\n color={'primary'}\n sx={{ fontSize: 44 }}\n />\n <Typography\n sx={{ fontWeight: 600 }}\n variant={'subtitle1'}\n >\n {translatedLabel}\n </Typography>\n <Typography\n color={'text.secondary'}\n variant={'body2'}\n >\n {helperText || t('Drag & drop your file here, or click to browse')}\n </Typography>\n <Box\n aria-hidden\n component={'span'}\n sx={{\n border: '1px solid',\n borderColor: disabled ? 'action.disabled' : 'primary.main',\n borderRadius: 1,\n color: disabled ? 'action.disabled' : 'primary.main',\n fontSize: '0.8125rem',\n fontWeight: 500,\n letterSpacing: '0.02857em',\n mt: 1,\n padding: '5px 14px',\n textTransform: 'uppercase',\n }}\n >\n {t('Choose File')}\n </Box>\n </>\n )}\n </Box>\n </Box>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type MultiFileUploaderProps = {
|
|
2
|
+
readonly accept: string;
|
|
3
|
+
readonly initialDataTransfer?: DataTransfer;
|
|
4
|
+
readonly numFilesAllowed?: number;
|
|
5
|
+
readonly onDataTransferChange: (dataTransfer: DataTransfer) => void;
|
|
6
|
+
};
|
|
7
|
+
export declare const MultiFileUploader: ({ accept, initialDataTransfer: initialDataTransferProp, numFilesAllowed, onDataTransferChange, }: MultiFileUploaderProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './MultiFileUploader';
|