@wavv/ui 2.3.13 → 2.3.15
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/build/components/Avatar.d.ts +6 -1
- package/build/components/Avatar.js +16 -2
- package/build/components/DropZone.js +1 -14
- package/build/components/Inputs/helpers/InputContainerStyles.js +0 -1
- package/build/components/ListHelpers/ListRootStyles.js +1 -1
- package/build/utils/index.d.ts +2 -0
- package/build/utils/index.js +3 -1
- package/build/utils/matchesFileTypes.d.ts +3 -2
- package/build/utils/parseFileSize.d.ts +7 -0
- package/build/utils/parseFileSize.js +16 -0
- package/package.json +1 -1
|
@@ -12,9 +12,14 @@ type Props = {
|
|
|
12
12
|
initials?: string;
|
|
13
13
|
/** File upload props - if provided, enables file upload functionality */
|
|
14
14
|
acceptedFileTypes?: FileTriggerProps['acceptedFileTypes'];
|
|
15
|
+
/** Maximum file size string (e.g., '25MB') */
|
|
16
|
+
maxFileSize?: string;
|
|
15
17
|
/** Callback when a file is selected */
|
|
16
18
|
onSelect?: FileTriggerProps['onSelect'];
|
|
19
|
+
/** Callback when the remove button is clicked */
|
|
17
20
|
onRemove?: () => void;
|
|
21
|
+
/** Callback when file validation fails */
|
|
22
|
+
onError?: (error: 'type' | 'size') => void;
|
|
18
23
|
} & MarginPadding & Pick<FileTriggerProps, 'acceptedFileTypes' | 'onSelect'>;
|
|
19
|
-
declare const Avatar: ({ size, url, icon, initials, acceptedFileTypes, onSelect, onRemove, ...props }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
declare const Avatar: ({ size, url, icon, initials, acceptedFileTypes, onSelect, onError, maxFileSize, onRemove, ...props }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
20
25
|
export default Avatar;
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import styled from "@emotion/styled";
|
|
3
3
|
import { FileTrigger } from "react-aria-components";
|
|
4
|
+
import matchesFileTypes from "../utils/matchesFileTypes.js";
|
|
5
|
+
import parseFileSize from "../utils/parseFileSize.js";
|
|
4
6
|
import Button from "./Button/index.js";
|
|
5
7
|
import getIcon from "./helpers/getIcon.js";
|
|
6
8
|
import { marginProps, paddingProps } from "./helpers/styledProps.js";
|
|
7
|
-
const Avatar = ({ size = 32, url, icon, initials, acceptedFileTypes, onSelect, onRemove, ...props })=>{
|
|
9
|
+
const Avatar = ({ size = 32, url, icon, initials, acceptedFileTypes, onSelect, onError, maxFileSize, onRemove, ...props })=>{
|
|
8
10
|
const imageSize = size - 4;
|
|
9
11
|
const hasUpload = !!acceptedFileTypes || !!onSelect;
|
|
12
|
+
const handleFileSelect = (files)=>{
|
|
13
|
+
if (!files || 0 === files.length) return;
|
|
14
|
+
const file = files[0];
|
|
15
|
+
if (acceptedFileTypes && acceptedFileTypes.length > 0) {
|
|
16
|
+
if (!matchesFileTypes(file, acceptedFileTypes)) return void onError?.('type');
|
|
17
|
+
}
|
|
18
|
+
if (maxFileSize) {
|
|
19
|
+
const maxBytes = parseFileSize(maxFileSize);
|
|
20
|
+
if (null !== maxBytes && file.size > maxBytes) return void onError?.('size');
|
|
21
|
+
}
|
|
22
|
+
onSelect?.(files);
|
|
23
|
+
};
|
|
10
24
|
const displayMode = url ? 'image' : initials ? 'initials' : icon ? 'icon' : 'placeholder';
|
|
11
25
|
const isInitials = 'initials' === displayMode;
|
|
12
26
|
const isImage = 'image' === displayMode;
|
|
@@ -39,7 +53,7 @@ const Avatar = ({ size = 32, url, icon, initials, acceptedFileTypes, onSelect, o
|
|
|
39
53
|
children: [
|
|
40
54
|
/*#__PURE__*/ jsx(FileTrigger, {
|
|
41
55
|
acceptedFileTypes: acceptedFileTypes,
|
|
42
|
-
onSelect:
|
|
56
|
+
onSelect: handleFileSelect,
|
|
43
57
|
children: /*#__PURE__*/ jsx(Button, {
|
|
44
58
|
small: true,
|
|
45
59
|
outline: true,
|
|
@@ -3,6 +3,7 @@ import styled from "@emotion/styled";
|
|
|
3
3
|
import { useId, useState } from "react";
|
|
4
4
|
import { DropZone, Text } from "react-aria-components";
|
|
5
5
|
import matchesFileTypes from "../utils/matchesFileTypes.js";
|
|
6
|
+
import parseFileSize from "../utils/parseFileSize.js";
|
|
6
7
|
import Button from "./Button/index.js";
|
|
7
8
|
import FileTrigger from "./FileTrigger.js";
|
|
8
9
|
import { marginProps, paddingProps, widthHeightProps } from "./helpers/styledProps.js";
|
|
@@ -17,20 +18,6 @@ const DropZone_DropZone = ({ label = 'Drop here', showFileList = true, disabled,
|
|
|
17
18
|
const shouldManageFiles = showFileList || hasFileCallbacks;
|
|
18
19
|
const showFileTrigger = !!acceptedFileTypes || !!allowsMultiple || !!defaultCamera || !!acceptDirectory || hasFileCallbacks;
|
|
19
20
|
const generateFileId = (name, index)=>`${instanceId}-${name}-${Date.now()}-${index}`;
|
|
20
|
-
const parseFileSize = (sizeString)=>{
|
|
21
|
-
const match = sizeString.trim().match(/^(\d+(?:\.\d+)?)\s*(KB|MB|GB|TB|B)$/i);
|
|
22
|
-
if (!match) return null;
|
|
23
|
-
const value = parseFloat(match[1]);
|
|
24
|
-
const unit = match[2].toUpperCase();
|
|
25
|
-
const multipliers = {
|
|
26
|
-
B: 1,
|
|
27
|
-
KB: 1024,
|
|
28
|
-
MB: 1048576,
|
|
29
|
-
GB: 1073741824,
|
|
30
|
-
TB: 1099511627776
|
|
31
|
-
};
|
|
32
|
-
return value * (multipliers[unit] || 1);
|
|
33
|
-
};
|
|
34
21
|
const validateFileSizes = (fileList)=>{
|
|
35
22
|
if (!maxFileSize) return {
|
|
36
23
|
valid: fileList,
|
|
@@ -54,7 +54,6 @@ const backgroundStyles = ({ backgroundColor })=>({
|
|
|
54
54
|
const textOnlyStyles = ({ theme, textOnly, isDisabled })=>({
|
|
55
55
|
padding: textOnly ? 0 : void 0,
|
|
56
56
|
backgroundColor: textOnly ? 'transparent' : void 0,
|
|
57
|
-
width: textOnly ? 'max-content' : void 0,
|
|
58
57
|
height: textOnly ? 'max-content' : void 0,
|
|
59
58
|
minHeight: textOnly ? 'max-content' : void 0,
|
|
60
59
|
color: textOnly && isDisabled ? theme.scale4 : void 0
|
package/build/utils/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { default as chunk } from './chunk';
|
|
2
2
|
export { default as copyToClipboard } from './copyToClipboard';
|
|
3
3
|
export { default as formatDate } from './formatDate';
|
|
4
|
+
export { default as matchesFileTypes } from './matchesFileTypes';
|
|
4
5
|
export { default as numberWithCommas } from './numberWithCommas';
|
|
6
|
+
export { default as parseFileSize } from './parseFileSize';
|
|
5
7
|
export { default as range } from './range';
|
package/build/utils/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import chunk from "./chunk.js";
|
|
2
2
|
import copyToClipboard from "./copyToClipboard.js";
|
|
3
3
|
import formatDate from "./formatDate.js";
|
|
4
|
+
import matchesFileTypes from "./matchesFileTypes.js";
|
|
4
5
|
import numberWithCommas from "./numberWithCommas.js";
|
|
6
|
+
import parseFileSize from "./parseFileSize.js";
|
|
5
7
|
import range from "./range.js";
|
|
6
|
-
export { chunk, copyToClipboard, formatDate, numberWithCommas, range };
|
|
8
|
+
export { chunk, copyToClipboard, formatDate, matchesFileTypes, numberWithCommas, parseFileSize, range };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { FileDropItem } from 'react-aria';
|
|
2
2
|
/**
|
|
3
3
|
* Checks if a file matches any of the accepted file types
|
|
4
|
-
*
|
|
4
|
+
* Works with both File objects and FileDropItem objects
|
|
5
|
+
* @param file - The file to check (File or FileDropItem)
|
|
5
6
|
* @param acceptedFileTypes - The accepted file types
|
|
6
7
|
* @returns True if the file matches any of the accepted file types, false otherwise
|
|
7
8
|
*/
|
|
8
|
-
declare const matchesFileTypes: (file: FileDropItem, acceptedFileTypes?: readonly string[]) => boolean;
|
|
9
|
+
declare const matchesFileTypes: (file: File | FileDropItem, acceptedFileTypes?: readonly string[]) => boolean;
|
|
9
10
|
export default matchesFileTypes;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses a file size string (e.g., '25MB') into bytes
|
|
3
|
+
* @param sizeString - The file size string to parse (e.g., '25MB', '1.5GB')
|
|
4
|
+
* @returns The size in bytes, or null if the format is invalid
|
|
5
|
+
*/
|
|
6
|
+
declare const parseFileSize: (sizeString: string) => number | null;
|
|
7
|
+
export default parseFileSize;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const parseFileSize = (sizeString)=>{
|
|
2
|
+
const match = sizeString.trim().match(/^(\d+(?:\.\d+)?)\s*(KB|MB|GB|TB|B)$/i);
|
|
3
|
+
if (!match) return null;
|
|
4
|
+
const value = parseFloat(match[1]);
|
|
5
|
+
const unit = match[2].toUpperCase();
|
|
6
|
+
const multipliers = {
|
|
7
|
+
B: 1,
|
|
8
|
+
KB: 1024,
|
|
9
|
+
MB: 1048576,
|
|
10
|
+
GB: 1073741824,
|
|
11
|
+
TB: 1099511627776
|
|
12
|
+
};
|
|
13
|
+
return value * (multipliers[unit] || 1);
|
|
14
|
+
};
|
|
15
|
+
const utils_parseFileSize = parseFileSize;
|
|
16
|
+
export { utils_parseFileSize as default };
|