|
@@ -4,6 +4,40 @@ import { useClientSide, useFallbackId, useProxyInput } from '@modal-sh/react-uti |
|
|
|
|
|
|
|
|
const { tw } = tailwind; |
|
|
const { tw } = tailwind; |
|
|
|
|
|
|
|
|
|
|
|
const digitalUnits = [ |
|
|
|
|
|
'byte', |
|
|
|
|
|
'kilobyte', |
|
|
|
|
|
'megabyte', |
|
|
|
|
|
'gigabyte', |
|
|
|
|
|
'terabyte', |
|
|
|
|
|
'petabyte', |
|
|
|
|
|
'exabyte', |
|
|
|
|
|
'zettabyte', |
|
|
|
|
|
'yottabyte', |
|
|
|
|
|
'brontobyte', |
|
|
|
|
|
] as const; |
|
|
|
|
|
|
|
|
|
|
|
const getCompactDigitalUnitValue = (byteCount: number) => { |
|
|
|
|
|
// kibibytes, mebibytes... |
|
|
|
|
|
// return byteCount / (2 ** (10 * getCompactDigitalUnitTier(byteCount))); |
|
|
|
|
|
return byteCount / (10 ** (3 * getCompactDigitalUnitTier(byteCount))); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const getCompactDigitalUnitTier = (byteCount: string | number | bigint) => { |
|
|
|
|
|
const byteCountBigInt = BigInt(byteCount); |
|
|
|
|
|
for (let i = 0; i < digitalUnits.length - 1; i += 1) { |
|
|
|
|
|
// kibibytes, mebibytes... |
|
|
|
|
|
// if (byteCountBigInt < BigInt(2) ** BigInt(10 * i)) { |
|
|
|
|
|
// return i - 1; |
|
|
|
|
|
// } |
|
|
|
|
|
if (byteCountBigInt < BigInt(10) ** BigInt(3 * i)) { |
|
|
|
|
|
return i - 1; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return digitalUnits.length - 1; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
const FileSelectBoxDefaultPreviewComponentDerivedElementComponent = 'div' as const; |
|
|
const FileSelectBoxDefaultPreviewComponentDerivedElementComponent = 'div' as const; |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
@@ -62,9 +96,9 @@ export const FileSelectBoxDefaultPreviewComponent = React.forwardRef< |
|
|
</div> |
|
|
</div> |
|
|
{!mini && ( |
|
|
{!mini && ( |
|
|
<> |
|
|
<> |
|
|
{typeof file?.type === 'string' && ( |
|
|
|
|
|
<div className="w-full whitespace-nowrap overflow-hidden text-ellipsis">{file?.type}</div> |
|
|
|
|
|
)} |
|
|
|
|
|
|
|
|
<div className="w-full whitespace-nowrap text-sm overflow-hidden text-ellipsis"> |
|
|
|
|
|
{file?.type || 'application/octet-stream'} |
|
|
|
|
|
</div> |
|
|
{typeof file?.size === 'number' && ( |
|
|
{typeof file?.size === 'number' && ( |
|
|
<div |
|
|
<div |
|
|
title={new Intl.NumberFormat(undefined, { |
|
|
title={new Intl.NumberFormat(undefined, { |
|
@@ -72,17 +106,17 @@ export const FileSelectBoxDefaultPreviewComponent = React.forwardRef< |
|
|
unit: 'byte', |
|
|
unit: 'byte', |
|
|
unitDisplay: 'long', |
|
|
unitDisplay: 'long', |
|
|
}).format(file.size)} |
|
|
}).format(file.size)} |
|
|
className="w-full whitespace-nowrap overflow-hidden text-ellipsis tabular-nums" |
|
|
|
|
|
|
|
|
className="w-full whitespace-nowrap text-sm overflow-hidden text-ellipsis tabular-nums" |
|
|
> |
|
|
> |
|
|
{new Intl.NumberFormat(undefined, { |
|
|
{new Intl.NumberFormat(undefined, { |
|
|
style: 'unit', |
|
|
style: 'unit', |
|
|
unit: 'kilobyte', |
|
|
|
|
|
unitDisplay: 'long', |
|
|
|
|
|
}).format(file.size)} |
|
|
|
|
|
|
|
|
unit: digitalUnits[getCompactDigitalUnitTier(file.size)], |
|
|
|
|
|
unitDisplay: getCompactDigitalUnitTier(file.size) === 0 ? 'long' : 'short', |
|
|
|
|
|
}).format(getCompactDigitalUnitValue(file.size))} |
|
|
</div> |
|
|
</div> |
|
|
)} |
|
|
)} |
|
|
{typeof file?.lastModified === 'number' && ( |
|
|
{typeof file?.lastModified === 'number' && ( |
|
|
<div className="w-full whitespace-nowrap overflow-hidden text-ellipsis"> |
|
|
|
|
|
|
|
|
<div className="w-full whitespace-nowrap text-sm overflow-hidden text-ellipsis"> |
|
|
<time dateTime={new Date(file.lastModified).toISOString()}> |
|
|
<time dateTime={new Date(file.lastModified).toISOString()}> |
|
|
{new Date(file.lastModified).toDateString()} |
|
|
{new Date(file.lastModified).toDateString()} |
|
|
</time> |
|
|
</time> |
|
@@ -93,10 +127,6 @@ export const FileSelectBoxDefaultPreviewComponent = React.forwardRef< |
|
|
</FileSelectBoxDefaultPreviewComponentDerivedElementComponent> |
|
|
</FileSelectBoxDefaultPreviewComponentDerivedElementComponent> |
|
|
)); |
|
|
)); |
|
|
|
|
|
|
|
|
const DEFAULT_ENHANCED_HEIGHT_PX = 64 as const; |
|
|
|
|
|
|
|
|
|
|
|
const DEFAULT_NON_ENHANCED_SIDE_HEIGHT_PX = 256 as const; |
|
|
|
|
|
|
|
|
|
|
|
const FileSelectBoxRootElementComponent = 'div' as const; |
|
|
const FileSelectBoxRootElementComponent = 'div' as const; |
|
|
|
|
|
|
|
|
type FileSelectBoxRootElement = HTMLElementTagNameMap[typeof FileSelectBoxRootElementComponent]; |
|
|
type FileSelectBoxRootElement = HTMLElementTagNameMap[typeof FileSelectBoxRootElementComponent]; |
|
@@ -463,7 +493,7 @@ export const FileSelectBox = React.forwardRef<FileSelectBoxDerivedElement, FileS |
|
|
onKeyDown={clientSide ? handleKeyDown : undefined} |
|
|
onKeyDown={clientSide ? handleKeyDown : undefined} |
|
|
onKeyUp={clientSide ? doSetFileList : undefined} |
|
|
onKeyUp={clientSide ? doSetFileList : undefined} |
|
|
className={tw( |
|
|
className={tw( |
|
|
'peer box-border focus:outline-0 file:cursor-pointer disabled:file:cursor-pointer block cursor-pointer disabled:cursor-not-allowed file:bg-transparent file:text-primary file:block file:font-bold file:font-semi-expanded file:uppercase file:p-0 file:border-0 group-focus-within:file:text-secondary', |
|
|
|
|
|
|
|
|
'peer text-sm box-border focus:outline-0 file:cursor-pointer disabled:file:cursor-pointer block cursor-pointer disabled:cursor-not-allowed file:bg-transparent file:text-primary file:block file:font-bold file:font-semi-expanded file:uppercase file:p-0 file:border-0 group-focus-within:file:text-secondary', |
|
|
{ |
|
|
{ |
|
|
'sr-only': clientSide, |
|
|
'sr-only': clientSide, |
|
|
'h-full w-full px-4': !clientSide, |
|
|
'h-full w-full px-4': !clientSide, |
|
|