@am92/react-design-system 2.9.12 → 2.10.1

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.
Files changed (30) hide show
  1. package/dist/Components/DsBottomSheet/DsBottomSheet.Component.js +6 -6
  2. package/dist/Components/DsDialog/DsDialog.Component.js +4 -4
  3. package/dist/Components/DsFileUploader/DsFileUploader.Component.d.ts +2 -3
  4. package/dist/Components/DsFileUploader/DsFileUploader.Component.js +109 -158
  5. package/dist/Components/DsFileUploader/DsFileUploader.Overrides.d.ts +5 -1
  6. package/dist/Components/DsFileUploader/DsFileUploader.Overrides.js +6 -1
  7. package/dist/Components/DsFileUploader/DsFileUploader.Types.d.ts +306 -13
  8. package/dist/Components/DsFileUploader/DsFileUploader.Types.js +46 -4
  9. package/dist/Components/DsFileUploader/DsFileUploaderPreview/DsFileUploaderImagePreview.Component.d.ts +11 -0
  10. package/dist/Components/DsFileUploader/DsFileUploaderPreview/DsFileUploaderImagePreview.Component.js +68 -0
  11. package/dist/Components/DsFileUploader/DsFileUploaderPreview/DsFileUploaderPreview.Component.d.ts +14 -0
  12. package/dist/Components/DsFileUploader/DsFileUploaderPreview/DsFileUploaderPreview.Component.js +28 -0
  13. package/dist/Components/DsFileUploader/FileUploaderFiles.d.ts +3 -0
  14. package/dist/Components/DsFileUploader/FileUploaderFiles.js +48 -0
  15. package/dist/Components/DsFileUploader/Slots/DsFileUploaderActionButton.Component.d.ts +10 -0
  16. package/dist/Components/DsFileUploader/Slots/DsFileUploaderActionButton.Component.js +18 -0
  17. package/dist/Components/DsFileUploader/Slots/DsFileUploaderDropZone.d.ts +10 -0
  18. package/dist/Components/DsFileUploader/Slots/DsFileUploaderDropZone.js +130 -0
  19. package/dist/Components/DsFileUploader/Slots/DsFileUploaderSelectedFilesSegment.d.ts +10 -0
  20. package/dist/Components/DsFileUploader/Slots/DsFileUploaderSelectedFilesSegment.js +21 -0
  21. package/dist/Components/DsFileUploader/Slots/DsFileUploaderUploadedFilesSegment.d.ts +10 -0
  22. package/dist/Components/DsFileUploader/Slots/DsFileUploaderUploadedFilesSegment.js +21 -0
  23. package/dist/Components/DsFileUploader/converter.d.ts +2 -0
  24. package/dist/Components/DsFileUploader/converter.js +25 -0
  25. package/dist/Components/DsFileUploader/helpers.d.ts +9 -0
  26. package/dist/Components/DsFileUploader/helpers.js +88 -0
  27. package/dist/Components/DsFileUploader/validator.d.ts +2 -0
  28. package/dist/Components/DsFileUploader/validator.js +37 -0
  29. package/dist/Theme/componentOverrides.d.ts +3 -0
  30. package/package.json +1 -1
@@ -0,0 +1,130 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DsBox } from '../../DsBox';
3
+ import { DsButton } from '../../DsButton';
4
+ import { DsInput } from '../../DsInput';
5
+ import { DsRemixIcon } from '../../DsRemixIcon';
6
+ import { DsStack } from '../../DsStack';
7
+ import { DsTypography } from '../../DsTypography';
8
+ import { DsFileUploaderDropzoneDefaultProps } from '../DsFileUploader.Types';
9
+ /**
10
+ * DsFileUploaderDropZone
11
+ *
12
+ * This component renders a drop zone area where users can drag & drop files
13
+ * or click to upload using a hidden input field. It supports two layout variants:
14
+ * - 'DEFAULT': Large button with drag and drop space area
15
+ * - 'COMPRESSED': Smaller area and button size to save space
16
+ */
17
+ export const DsFileUploaderDropZone = (inProps) => {
18
+ const props = {
19
+ ...DsFileUploaderDropzoneDefaultProps,
20
+ ...inProps
21
+ };
22
+ const { variant, IconProps, title, description, InputProps, disabled, ...restDsStackProps } = props;
23
+ const isCompressed = variant === 'COMPRESSED';
24
+ const renderDescription = () => {
25
+ if (!description)
26
+ return null;
27
+ const isArray = Array.isArray(description);
28
+ const isString = typeof description === 'string';
29
+ const shouldRenderCompressedArray = isArray && isCompressed;
30
+ const shouldRenderString = isString;
31
+ if (!shouldRenderCompressedArray && !shouldRenderString)
32
+ return null;
33
+ const color = `var(--ds-colour-${isCompressed ? 'typoPrimary' : 'typoTertiary'})`;
34
+ const containerProps = {
35
+ direction: isCompressed ? 'row' : undefined,
36
+ justifyContent: isCompressed
37
+ ? isArray && description.length > 1
38
+ ? 'space-between'
39
+ : 'center'
40
+ : 'center',
41
+ alignItems: isCompressed ? 'center' : undefined,
42
+ textAlign: isCompressed ? 'center' : undefined,
43
+ pb: isCompressed ? undefined : 'var(--ds-spacing-bitterCold)',
44
+ sx: isCompressed
45
+ ? {
46
+ py: 'var(--ds-spacing-quickFreeze)',
47
+ px: 'var(--ds-spacing-glacial)',
48
+ backgroundColor: 'var(--ds-colour-surfaceSecondary)',
49
+ borderRadius: 'var(--ds-radius-quickFreeze)'
50
+ }
51
+ : undefined
52
+ };
53
+ const renderTypographies = () => {
54
+ const descList = isString ? [description] : description;
55
+ return descList.map((desc, index) => (_jsx(DsTypography, { variant: 'bodyRegularSmall', align: 'center', color: color, children: desc }, index)));
56
+ };
57
+ return (_jsx(DsStack, { ...containerProps, children: renderTypographies() }, 'dropzone-description'));
58
+ };
59
+ return [
60
+ _jsxs(DsBox, { sx: {
61
+ width: '100%',
62
+ position: 'relative',
63
+ borderRadius: 'var(--ds-radius-glacial)',
64
+ borderWidth: '1px',
65
+ borderStyle: 'dashed',
66
+ borderColor: 'var(--ds-colour-strokeDefault)',
67
+ backgroundColor: disabled
68
+ ? 'var(--ds-colour-stateDisabledSurface)'
69
+ : 'var(--ds-colour-surfacePrimary)',
70
+ cursor: disabled ? 'not-allowed' : 'pointer',
71
+ '&:hover': {
72
+ borderColor: disabled
73
+ ? 'var(--ds-colour-strokeDefault)'
74
+ : 'var(--ds-colour-strokeSecondarySelected)',
75
+ '.dropzone-content-wrapper': {
76
+ backgroundColor: disabled
77
+ ? 'var(--ds-colour-stateDisabledSurface)'
78
+ : isCompressed
79
+ ? 'var(--ds-colour-surfaceSecondary)'
80
+ : 'var(--ds-colour-stateSelectedSecondaryHover)'
81
+ }
82
+ }
83
+ }, children: [_jsxs(DsStack, { className: 'dropzone-content-wrapper', flexDirection: isCompressed ? 'row' : 'column', gap: 'var(--ds-spacing-quickFreeze)', justifyContent: 'center', alignItems: 'center', ...restDsStackProps, sx: {
84
+ borderRadius: isCompressed
85
+ ? 'var(--ds-radius-quickFreeze)'
86
+ : 'var(--ds-radius-glacial)',
87
+ m: isCompressed
88
+ ? 'var(--ds-spacing-frostbite)'
89
+ : 'var(--ds-spacing-zero)',
90
+ px: isCompressed
91
+ ? 'var(--ds-spacing-glacial)'
92
+ : 'var(--ds-spacing-bitterCold)',
93
+ pt: isCompressed
94
+ ? 'var(--ds-spacing-zero)'
95
+ : 'var(--ds-spacing-bitterCold)',
96
+ backgroundColor: disabled
97
+ ? 'var(--ds-colour-stateDisabledSurface)'
98
+ : isCompressed
99
+ ? 'var(--ds-colour-surfaceSecondary)'
100
+ : 'var(--ds-colour-surfacePrimary)',
101
+ '&:hover': {
102
+ backgroundColor: isCompressed
103
+ ? 'var(--ds-colour-surfaceSecondary)'
104
+ : 'var(--ds-colour-stateSelectedSecondaryHover)'
105
+ },
106
+ ...restDsStackProps?.sx
107
+ }, children: [_jsx(DsRemixIcon, { className: isCompressed ? 'ri-upload-line' : 'ri-upload-cloud-2-line', fontSize: isCompressed ? 'frostbite' : 'mild', color: disabled ? 'disabled' : 'secondary', ...IconProps }), _jsx(DsButton, { disabled: disabled, variant: 'text', color: 'secondary', children: title }), !isCompressed && renderDescription()] }), _jsx(DsInput, { type: 'file', slot: 'input', disabled: disabled, sx: {
108
+ position: 'absolute',
109
+ top: 0,
110
+ left: 0,
111
+ height: '100%',
112
+ width: '100%',
113
+ opacity: 0,
114
+ margin: 'var(--ds-spacing-zero) !important'
115
+ }, onChange: InputProps?.onChange, onDrop: InputProps?.onDrop, onDragOver: InputProps?.onDragOver, disableUnderline: true, inputProps: {
116
+ title,
117
+ value: '',
118
+ ...InputProps,
119
+ accept: InputProps?.accept,
120
+ multiple: InputProps?.multiple,
121
+ style: {
122
+ height: '100%',
123
+ width: '100%',
124
+ cursor: disabled ? 'not-allowed' : 'pointer',
125
+ ...InputProps?.style
126
+ }
127
+ } })] }, 'dropzone-box'),
128
+ isCompressed && renderDescription()
129
+ ];
130
+ };
@@ -0,0 +1,10 @@
1
+ import { TDsFileUploaderSlotProps } from '../DsFileUploader.Types';
2
+ /**
3
+ * DsFileUploaderSelectedFilesSegment
4
+ *
5
+ * This component is a wrapper to render a labeled section
6
+ * for displaying selected files in a scrollable container.
7
+ *
8
+ * It supports slot-level customization via props and merges them with default values.
9
+ */
10
+ export declare const DsFileUploaderSelectedFilesSegment: (inProps: TDsFileUploaderSlotProps["SelectedItemSegment"]) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DsStack } from '../../DsStack';
3
+ import { DsTypography } from '../../DsTypography';
4
+ import { DsFileUploaderDefaultProps } from '../DsFileUploader.Types';
5
+ import { cloneElement, isValidElement } from 'react';
6
+ /**
7
+ * DsFileUploaderSelectedFilesSegment
8
+ *
9
+ * This component is a wrapper to render a labeled section
10
+ * for displaying selected files in a scrollable container.
11
+ *
12
+ * It supports slot-level customization via props and merges them with default values.
13
+ */
14
+ export const DsFileUploaderSelectedFilesSegment = (inProps) => {
15
+ const props = {
16
+ ...DsFileUploaderDefaultProps.slotProps?.SelectedItemSegment,
17
+ ...inProps
18
+ };
19
+ const { label, children } = props;
20
+ return (_jsxs(DsStack, { spacing: 'var(--ds-spacing-frostbite)', children: [_jsx(DsTypography, { py: 'var(--ds-spacing-glacial)', variant: 'subheadingSemiboldDefault', color: 'var(--ds-colour-typoSecondary)', children: label }), _jsx(DsStack, { spacing: 'var(--ds-spacing-frostbite)', sx: { maxHeight: '440px', overflowY: 'auto' }, children: isValidElement(children) && cloneElement(children, { ...props }) })] }));
21
+ };
@@ -0,0 +1,10 @@
1
+ import { TDsFileUploaderSlotProps } from '../DsFileUploader.Types';
2
+ /**
3
+ * DsFileUploaderSelectedFilesSegment
4
+ *
5
+ * This component is a wrapper to render a labeled section
6
+ * for displaying uploaded files in a scrollable container.
7
+ *
8
+ * It supports slot-level customization via props and merges them with default values.
9
+ */
10
+ export declare const DsFileUploaderUploadedFilesSegment: (inProps: TDsFileUploaderSlotProps["UploadedItemSegment"]) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DsStack } from '../../DsStack';
3
+ import { DsTypography } from '../../DsTypography';
4
+ import { DsFileUploaderDefaultProps } from '../DsFileUploader.Types';
5
+ import { cloneElement, isValidElement } from 'react';
6
+ /**
7
+ * DsFileUploaderSelectedFilesSegment
8
+ *
9
+ * This component is a wrapper to render a labeled section
10
+ * for displaying uploaded files in a scrollable container.
11
+ *
12
+ * It supports slot-level customization via props and merges them with default values.
13
+ */
14
+ export const DsFileUploaderUploadedFilesSegment = (inProps) => {
15
+ const props = {
16
+ ...DsFileUploaderDefaultProps.slotProps?.UploadedItemSegment,
17
+ ...inProps
18
+ };
19
+ const { label, children } = props;
20
+ return (_jsxs(DsStack, { spacing: 'var(--ds-spacing-frostbite)', children: [_jsx(DsTypography, { py: 'var(--ds-spacing-glacial)', variant: 'subheadingSemiboldDefault', color: 'var(--ds-colour-typoSecondary)', children: label }), _jsx(DsStack, { spacing: 'var(--ds-spacing-frostbite)', sx: { maxHeight: '440px', overflowY: 'auto' }, children: isValidElement(children) && cloneElement(children, { ...props }) })] }));
21
+ };
@@ -0,0 +1,2 @@
1
+ import type { TContentType, TFile } from './DsFileUploader.Types';
2
+ export declare const fileToFileUploader: (file: File, contentType: TContentType) => Promise<TFile<TContentType>>;
@@ -0,0 +1,25 @@
1
+ export const fileToFileUploader = async (file, contentType) => {
2
+ const { name, type, size } = file;
3
+ let content = file;
4
+ if (contentType === 'BASE64') {
5
+ content = await fileToBase64(file);
6
+ if (typeof content === 'string' && content.startsWith('data:')) {
7
+ content = content.substring(content.indexOf(',') + 1);
8
+ }
9
+ }
10
+ const fileUploader = {
11
+ name,
12
+ type,
13
+ size,
14
+ content
15
+ };
16
+ return fileUploader;
17
+ };
18
+ const fileToBase64 = (file) => {
19
+ return new Promise((resolve, reject) => {
20
+ const reader = new FileReader();
21
+ reader.readAsDataURL(file);
22
+ reader.onload = () => resolve(reader.result);
23
+ reader.onerror = error => reject(error);
24
+ });
25
+ };
@@ -0,0 +1,9 @@
1
+ import type { IDsFileUploaderProps, TContentType, TErrorValue, TFile, TMultiple, TFileValue } from './DsFileUploader.Types';
2
+ export declare const mergeProps: <T extends Record<string, any>>(inProps: Partial<T>, defaultProps: T) => T;
3
+ export declare const getFileTypeIcon: <ContentType extends TContentType>(file: TFile<ContentType>) => import("react/jsx-runtime").JSX.Element;
4
+ export declare const humanizeFileSize: (bytes: number, decimals?: number) => string;
5
+ export declare const getDefaultValue: <Multiple extends TMultiple, ContentType extends TContentType>(props: IDsFileUploaderProps<Multiple, ContentType>) => TFileValue<Multiple, ContentType> | null;
6
+ export declare const getValidProcessedFile: <Multiple extends TMultiple, ContentType extends TContentType>(filesToProcess: FileList, files: TFileValue<Multiple, ContentType> | null, accept: string, minSize?: number, maxSize?: number, contentType?: TContentType) => Promise<{
7
+ valid: TFileValue<Multiple, ContentType>;
8
+ invalid: TErrorValue<Multiple, ContentType>;
9
+ }>;
@@ -0,0 +1,88 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { DsFileUploaderImagePreview } from './DsFileUploaderPreview/DsFileUploaderImagePreview.Component';
3
+ import { getFileValidator } from './validator';
4
+ import { fileToFileUploader } from './converter';
5
+ import { DsRemixIcon } from '../DsRemixIcon';
6
+ export const mergeProps = (inProps, defaultProps) => {
7
+ return {
8
+ ...defaultProps,
9
+ ...inProps,
10
+ slots: {
11
+ ...defaultProps.slots,
12
+ ...inProps.slots
13
+ },
14
+ slotProps: {
15
+ ...defaultProps.slotProps,
16
+ ...inProps.slotProps,
17
+ SelectedItemSegment: {
18
+ ...defaultProps.slotProps?.SelectedItemSegment,
19
+ ...inProps.slotProps?.SelectedItemSegment
20
+ },
21
+ UploadedItemSegment: {
22
+ ...defaultProps.slotProps?.UploadedItemSegment,
23
+ ...inProps.slotProps?.UploadedItemSegment
24
+ },
25
+ DropZone: {
26
+ ...defaultProps?.slotProps?.DropZone,
27
+ ...inProps.slotProps?.DropZone
28
+ }
29
+ }
30
+ };
31
+ };
32
+ export const getFileTypeIcon = (file) => {
33
+ const { type: mimeType } = file;
34
+ const IMAGE_REGEX = new RegExp('^image/.*');
35
+ const VIDEO_REGEX = new RegExp('^video/.*');
36
+ if (IMAGE_REGEX.test(mimeType)) {
37
+ return _jsx(DsFileUploaderImagePreview, { file: file });
38
+ }
39
+ else if (VIDEO_REGEX.test(mimeType)) {
40
+ return _jsx(DsRemixIcon, { className: "ri-video-line" });
41
+ }
42
+ else {
43
+ return _jsx(DsRemixIcon, { className: "ri-file-list-2-line" });
44
+ }
45
+ };
46
+ export const humanizeFileSize = (bytes, decimals = 2) => {
47
+ if (!+bytes)
48
+ return '0 Bytes';
49
+ const k = 1024;
50
+ const dm = decimals < 0 ? 0 : decimals;
51
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
52
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
53
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
54
+ };
55
+ export const getDefaultValue = (props) => {
56
+ const { value, multiple } = props;
57
+ if (value) {
58
+ return value;
59
+ }
60
+ if (multiple) {
61
+ return [];
62
+ }
63
+ return null;
64
+ };
65
+ export const getValidProcessedFile = async (filesToProcess, files, accept, minSize, maxSize, contentType) => {
66
+ const validator = getFileValidator(accept, minSize, maxSize);
67
+ const isMultiple = Array.isArray(files);
68
+ const validFiles = isMultiple ? [...files] : [];
69
+ const invalidFiles = [];
70
+ const fileList = [...filesToProcess];
71
+ for (const file of fileList) {
72
+ const fileUploader = await fileToFileUploader(file, contentType || 'FILE');
73
+ const errorCode = validator(file);
74
+ if (!errorCode) {
75
+ validFiles.unshift(fileUploader);
76
+ }
77
+ else {
78
+ const temp = {
79
+ file: fileUploader,
80
+ errorCode
81
+ };
82
+ invalidFiles.push(temp);
83
+ }
84
+ }
85
+ const valid = isMultiple ? validFiles : validFiles[0];
86
+ const invalid = (isMultiple ? invalidFiles : invalidFiles[0]);
87
+ return { valid, invalid };
88
+ };
@@ -0,0 +1,2 @@
1
+ import { type TErrorCodes } from './DsFileUploader.Types';
2
+ export declare const getFileValidator: (accept: string, minSize?: number | undefined, maxSize?: number | undefined) => (file: File) => TErrorCodes | undefined;
@@ -0,0 +1,37 @@
1
+ import { ERROR_CODES } from './DsFileUploader.Types';
2
+ export const getFileValidator = (accept, minSize = 0, maxSize = Infinity) => {
3
+ const validateFileType = getFileTypeValidator(accept);
4
+ return (file) => {
5
+ const { size, type } = file;
6
+ if (!validateMinSize(size, minSize)) {
7
+ return ERROR_CODES.FILE_SIZE_BELOW_MIN;
8
+ }
9
+ if (!validateMaxSize(size, maxSize)) {
10
+ return ERROR_CODES.MAX_FILE_SIZE_EXCEEDED;
11
+ }
12
+ if (!validateFileType(type)) {
13
+ return ERROR_CODES.INVALID_FILE_TYPE;
14
+ }
15
+ };
16
+ };
17
+ const validateMinSize = (size, minSize = 0) => {
18
+ return size >= minSize;
19
+ };
20
+ const validateMaxSize = (size, maxSize = Infinity) => {
21
+ return size <= maxSize;
22
+ };
23
+ const getFileTypeValidator = (accept) => {
24
+ // Escape dots and replace wildcards with .* for regex
25
+ const typesPattern = accept
26
+ .split(',')
27
+ .map(type => type.trim())
28
+ .map(type => type.replace(/\./g, '\\.').replace(/\*/g, '.*'))
29
+ .join('|');
30
+ // Create a regex with start and end anchors
31
+ const typesRegex = new RegExp(`^(${typesPattern})$`);
32
+ // Validator function
33
+ const validateFileType = (mimeType) => {
34
+ return typesRegex.test(mimeType);
35
+ };
36
+ return validateFileType;
37
+ };
@@ -1030,6 +1030,9 @@ declare const componentOverrides: {
1030
1030
  };
1031
1031
  };
1032
1032
  };
1033
+ DsFileUploader: {
1034
+ defaultProps: import("../Components").IDsFileUploaderProps<import("../Components").TMultiple, "FILE">;
1035
+ };
1033
1036
  MuiFab: {
1034
1037
  defaultProps: import("../Components").DsFabProps;
1035
1038
  styleOverrides: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@am92/react-design-system",
3
- "version": "2.9.12",
3
+ "version": "2.10.1",
4
4
  "description": "ReactJS Design System using Material UI",
5
5
  "sideEffects": false,
6
6
  "types": "dist/index.d.ts",