infinity-ui-elements 1.8.13 → 1.8.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/dist/components/SelectTextField/SelectTextField.stories.d.ts.map +1 -1
- package/dist/components/UploadBox/UploadBox.d.ts +49 -0
- package/dist/components/UploadBox/UploadBox.d.ts.map +1 -0
- package/dist/components/UploadBox/UploadBox.stories.d.ts +29 -0
- package/dist/components/UploadBox/UploadBox.stories.d.ts.map +1 -0
- package/dist/components/UploadBox/index.d.ts +3 -0
- package/dist/components/UploadBox/index.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +362 -3
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +363 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/icons.d.ts +2 -0
- package/dist/lib/icons.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -82,6 +82,14 @@ const iconRegistry = {
|
|
|
82
82
|
close: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
83
83
|
<path d="M18 6L6 18M6 6L18 18" stroke="#081416" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
84
84
|
</svg>`,
|
|
85
|
+
upload: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
86
|
+
<path d="M4 19H20V12H22V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V12H4V19ZM13 9V16H11V9H6L12 3L18 9H13Z" fill="#081416"/>
|
|
87
|
+
</svg>
|
|
88
|
+
`,
|
|
89
|
+
file: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
90
|
+
<path d="M19.1111 21H4.88889C4.39797 21 4 20.5971 4 20.1V3.9C4 3.40295 4.39797 3 4.88889 3H19.1111C19.602 3 20 3.40295 20 3.9V20.1C20 20.5971 19.602 21 19.1111 21ZM18.2222 19.2V4.8H5.77778V19.2H18.2222ZM8.44444 9.3H15.5556V11.1H8.44444V9.3ZM8.44444 12.9H15.5556V14.7H8.44444V12.9Z" fill="#081416"/>
|
|
91
|
+
</svg>
|
|
92
|
+
`,
|
|
85
93
|
};
|
|
86
94
|
const Icon = ({ name, size = 24, className = "", style = {}, ...props }) => {
|
|
87
95
|
const svgContent = iconRegistry[name];
|
|
@@ -3105,7 +3113,7 @@ const Radio = React__namespace.forwardRef(({ label, errorText, size = "medium",
|
|
|
3105
3113
|
});
|
|
3106
3114
|
Radio.displayName = "Radio";
|
|
3107
3115
|
|
|
3108
|
-
const textFieldVariants = classVarianceAuthority.cva("relative flex items-center gap-2 border rounded-large transition-all font-
|
|
3116
|
+
const textFieldVariants = classVarianceAuthority.cva("relative flex items-center gap-2 border rounded-large transition-all font-functional font-size-100 leading-100", {
|
|
3109
3117
|
variants: {
|
|
3110
3118
|
size: {
|
|
3111
3119
|
small: "h-[28px] px-3 text-xs gap-2",
|
|
@@ -3197,7 +3205,7 @@ const TextField = React__namespace.forwardRef(({ label, helperText, errorText, s
|
|
|
3197
3205
|
? "text-feedback-ink-positive-intense"
|
|
3198
3206
|
: currentValidationState === "negative"
|
|
3199
3207
|
? "text-feedback-ink-negative-subtle"
|
|
3200
|
-
: "text-surface-ink-neutral-muted"), children: prefix })), jsxRuntime.jsx("input", { ref: ref, value: inputValue, onChange: handleChange, disabled: isDisabled, required: isRequired, className: cn("flex-1 bg-transparent border-none outline-none text-surface-ink-neutral-normal placeholder:text-surface-ink-neutral-muted disabled:cursor-not-allowed disabled:text-surface-ink-neutral-disabled
|
|
3208
|
+
: "text-surface-ink-neutral-muted"), children: prefix })), jsxRuntime.jsx("input", { ref: ref, value: inputValue, onChange: handleChange, disabled: isDisabled, required: isRequired, className: cn("flex-1 bg-transparent border-none outline-none text-surface-ink-neutral-normal placeholder:text-surface-ink-neutral-muted disabled:cursor-not-allowed disabled:text-surface-ink-neutral-disabled", inputClassName), ...props }), showClearButton && hasValue && !isDisabled && (jsxRuntime.jsx("button", { type: "button", onClick: handleClear, className: "shrink-0 flex items-center justify-center text-surface-ink-neutral-muted hover:text-surface-ink-neutral-normal transition-colors", tabIndex: -1, children: jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })), suffix && (jsxRuntime.jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
|
|
3201
3209
|
? "text-surface-ink-neutral-disabled"
|
|
3202
3210
|
: currentValidationState === "positive"
|
|
3203
3211
|
? "text-feedback-ink-positive-intense"
|
|
@@ -4236,6 +4244,357 @@ const TextArea = React__namespace.forwardRef(({ label, helperText, errorText, su
|
|
|
4236
4244
|
});
|
|
4237
4245
|
TextArea.displayName = "TextArea";
|
|
4238
4246
|
|
|
4247
|
+
const uploadBoxVariants = classVarianceAuthority.cva("relative flex flex-col items-center justify-center border-2 border-dashed rounded-large transition-all font-display", {
|
|
4248
|
+
variants: {
|
|
4249
|
+
size: {
|
|
4250
|
+
small: "min-h-[120px] p-4 gap-2",
|
|
4251
|
+
medium: "min-h-[160px] p-6 gap-3",
|
|
4252
|
+
large: "min-h-[200px] p-8 gap-4",
|
|
4253
|
+
},
|
|
4254
|
+
validationState: {
|
|
4255
|
+
none: `
|
|
4256
|
+
border-action-outline-neutral-faded
|
|
4257
|
+
hover:border-action-outline-primary-hover
|
|
4258
|
+
focus-within:border-action-outline-primary-hover
|
|
4259
|
+
focus-within:ring-2
|
|
4260
|
+
ring-action-outline-primary-faded-hover
|
|
4261
|
+
bg-surface-fill-neutral-intense`,
|
|
4262
|
+
positive: `
|
|
4263
|
+
border-action-outline-positive-default
|
|
4264
|
+
focus-within:border-action-outline-positive-hover
|
|
4265
|
+
focus-within:ring-2
|
|
4266
|
+
ring-action-outline-positive-faded-hover
|
|
4267
|
+
bg-surface-fill-neutral-intense`,
|
|
4268
|
+
negative: `
|
|
4269
|
+
border-action-outline-negative-default
|
|
4270
|
+
focus-within:border-action-outline-negative-hover
|
|
4271
|
+
focus-within:ring-2
|
|
4272
|
+
ring-action-outline-negative-faded-hover
|
|
4273
|
+
bg-surface-fill-neutral-intense`,
|
|
4274
|
+
},
|
|
4275
|
+
isDisabled: {
|
|
4276
|
+
true: `
|
|
4277
|
+
border-[var(--border-width-thinner)]
|
|
4278
|
+
hover:border-action-outline-neutral-disabled
|
|
4279
|
+
border-action-outline-neutral-disabled
|
|
4280
|
+
bg-surface-fill-neutral-intense
|
|
4281
|
+
cursor-not-allowed
|
|
4282
|
+
opacity-60`,
|
|
4283
|
+
false: "cursor-pointer",
|
|
4284
|
+
},
|
|
4285
|
+
isDragging: {
|
|
4286
|
+
true: "border-action-outline-primary-hover bg-action-fill-primary-faded",
|
|
4287
|
+
false: "",
|
|
4288
|
+
},
|
|
4289
|
+
},
|
|
4290
|
+
defaultVariants: {
|
|
4291
|
+
size: "medium",
|
|
4292
|
+
validationState: "none",
|
|
4293
|
+
isDisabled: false,
|
|
4294
|
+
isDragging: false,
|
|
4295
|
+
},
|
|
4296
|
+
});
|
|
4297
|
+
const formatFileSize = (bytes) => {
|
|
4298
|
+
if (bytes === 0)
|
|
4299
|
+
return "0 Bytes";
|
|
4300
|
+
const k = 1024;
|
|
4301
|
+
const sizes = ["Bytes", "KB", "MB", "GB"];
|
|
4302
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
4303
|
+
return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + " " + sizes[i];
|
|
4304
|
+
};
|
|
4305
|
+
const isImageFile = (file, url) => {
|
|
4306
|
+
if (file) {
|
|
4307
|
+
return file.type.startsWith("image/");
|
|
4308
|
+
}
|
|
4309
|
+
if (url) {
|
|
4310
|
+
const lowerUrl = url.toLowerCase();
|
|
4311
|
+
return (lowerUrl.match(/\.(jpg|jpeg|png|gif|bmp|webp|svg)(\?.*)?$/i) !== null ||
|
|
4312
|
+
url.match(/data:image\//) !== null);
|
|
4313
|
+
}
|
|
4314
|
+
return false;
|
|
4315
|
+
};
|
|
4316
|
+
const isPdfFile = (file, url) => {
|
|
4317
|
+
if (file) {
|
|
4318
|
+
return file.type === "application/pdf";
|
|
4319
|
+
}
|
|
4320
|
+
if (url) {
|
|
4321
|
+
return url.toLowerCase().match(/\.pdf(\?.*)?$/i) !== null;
|
|
4322
|
+
}
|
|
4323
|
+
return false;
|
|
4324
|
+
};
|
|
4325
|
+
const getFileNameFromUrl = (url) => {
|
|
4326
|
+
try {
|
|
4327
|
+
const urlObj = new URL(url);
|
|
4328
|
+
const pathname = urlObj.pathname;
|
|
4329
|
+
const fileName = pathname.split("/").pop() || "file";
|
|
4330
|
+
return decodeURIComponent(fileName);
|
|
4331
|
+
}
|
|
4332
|
+
catch {
|
|
4333
|
+
// If URL parsing fails, try to extract from the string
|
|
4334
|
+
const parts = url.split("/");
|
|
4335
|
+
const lastPart = parts[parts.length - 1] || "file";
|
|
4336
|
+
return decodeURIComponent(lastPart.split("?")[0]);
|
|
4337
|
+
}
|
|
4338
|
+
};
|
|
4339
|
+
// Component to handle image preview with error fallback
|
|
4340
|
+
const ImagePreview = ({ src, alt }) => {
|
|
4341
|
+
const [hasError, setHasError] = React__namespace.useState(false);
|
|
4342
|
+
if (hasError) {
|
|
4343
|
+
return (jsxRuntime.jsx("div", { className: "shrink-0 w-16 h-16 rounded-medium flex items-center justify-center bg-surface-fill-neutral-subtle", children: jsxRuntime.jsx(Icon, { name: "file", size: 24, className: "text-surface-ink-neutral-subtle" }) }));
|
|
4344
|
+
}
|
|
4345
|
+
return (jsxRuntime.jsx("div", { className: "shrink-0 w-16 h-16 rounded-medium overflow-hidden ", children: jsxRuntime.jsx("img", { src: src, alt: alt, className: "w-full h-full object-cover", onError: () => setHasError(true) }) }));
|
|
4346
|
+
};
|
|
4347
|
+
const UploadBox = React__namespace.forwardRef(({ label, helperText, errorText, successText, size = "medium", validationState = "none", isDisabled = false, isRequired = false, isOptional = false, accept, multiple = false, maxSize, maxFiles, value, onChange, onFileRemove, containerClassName, labelClassName, uploadAreaClassName, previewClassName, infoHeading, infoDescription, LinkComponent, linkText, linkHref, onLinkClick, uploadText, dragText, showPreview = true, className, ...props }, ref) => {
|
|
4348
|
+
const fileInputRef = React__namespace.useRef(null);
|
|
4349
|
+
const [isDragging, setIsDragging] = React__namespace.useState(false);
|
|
4350
|
+
const [uploadedFiles, setUploadedFiles] = React__namespace.useState([]);
|
|
4351
|
+
const [error, setError] = React__namespace.useState(null);
|
|
4352
|
+
// Initialize uploaded files from value prop
|
|
4353
|
+
React__namespace.useEffect(() => {
|
|
4354
|
+
if (value) {
|
|
4355
|
+
const filesArray = Array.isArray(value) ? value : [value];
|
|
4356
|
+
const processedFiles = filesArray.map((item) => {
|
|
4357
|
+
if (item instanceof File) {
|
|
4358
|
+
const uploadedFile = {
|
|
4359
|
+
file: item,
|
|
4360
|
+
name: item.name,
|
|
4361
|
+
size: item.size,
|
|
4362
|
+
id: `${item.name}-${item.size}-${item.lastModified}`,
|
|
4363
|
+
};
|
|
4364
|
+
if (isImageFile(item) && showPreview) {
|
|
4365
|
+
uploadedFile.preview = URL.createObjectURL(item);
|
|
4366
|
+
}
|
|
4367
|
+
return uploadedFile;
|
|
4368
|
+
}
|
|
4369
|
+
else if (typeof item === "string") {
|
|
4370
|
+
// It's a URL string
|
|
4371
|
+
const uploadedFile = {
|
|
4372
|
+
url: item,
|
|
4373
|
+
name: getFileNameFromUrl(item),
|
|
4374
|
+
id: `url-${item}-${Date.now()}`,
|
|
4375
|
+
};
|
|
4376
|
+
// Always set preview for URLs when showPreview is true
|
|
4377
|
+
// The rendering logic will determine if it's an image or PDF
|
|
4378
|
+
if (showPreview) {
|
|
4379
|
+
uploadedFile.preview = item;
|
|
4380
|
+
}
|
|
4381
|
+
return uploadedFile;
|
|
4382
|
+
}
|
|
4383
|
+
else {
|
|
4384
|
+
// It's already an UploadedFile
|
|
4385
|
+
const uploadedFile = item;
|
|
4386
|
+
// If it has a URL but no preview set, set it
|
|
4387
|
+
if (uploadedFile.url && !uploadedFile.preview && showPreview) {
|
|
4388
|
+
uploadedFile.preview = uploadedFile.url;
|
|
4389
|
+
}
|
|
4390
|
+
return uploadedFile;
|
|
4391
|
+
}
|
|
4392
|
+
});
|
|
4393
|
+
setUploadedFiles(processedFiles);
|
|
4394
|
+
}
|
|
4395
|
+
else {
|
|
4396
|
+
setUploadedFiles([]);
|
|
4397
|
+
}
|
|
4398
|
+
}, [value, showPreview]);
|
|
4399
|
+
// Cleanup preview URLs (only revoke object URLs, not regular URLs)
|
|
4400
|
+
React__namespace.useEffect(() => {
|
|
4401
|
+
return () => {
|
|
4402
|
+
uploadedFiles.forEach((uploadedFile) => {
|
|
4403
|
+
// Only revoke object URLs (created with URL.createObjectURL)
|
|
4404
|
+
// Regular URLs (http/https) should not be revoked
|
|
4405
|
+
if (uploadedFile.preview &&
|
|
4406
|
+
uploadedFile.preview.startsWith("blob:")) {
|
|
4407
|
+
URL.revokeObjectURL(uploadedFile.preview);
|
|
4408
|
+
}
|
|
4409
|
+
});
|
|
4410
|
+
};
|
|
4411
|
+
}, [uploadedFiles]);
|
|
4412
|
+
const processFiles = (files) => {
|
|
4413
|
+
const fileArray = Array.from(files);
|
|
4414
|
+
const validFiles = [];
|
|
4415
|
+
let currentError = null;
|
|
4416
|
+
// Check max files limit
|
|
4417
|
+
if (maxFiles && uploadedFiles.length + fileArray.length > maxFiles) {
|
|
4418
|
+
currentError = `Maximum ${maxFiles} file(s) allowed`;
|
|
4419
|
+
setError(currentError);
|
|
4420
|
+
return validFiles;
|
|
4421
|
+
}
|
|
4422
|
+
fileArray.forEach((file) => {
|
|
4423
|
+
// Check file size
|
|
4424
|
+
if (maxSize && file.size > maxSize) {
|
|
4425
|
+
currentError = `File "${file.name}" exceeds maximum size of ${formatFileSize(maxSize)}`;
|
|
4426
|
+
setError(currentError);
|
|
4427
|
+
return;
|
|
4428
|
+
}
|
|
4429
|
+
// Check if file type is accepted
|
|
4430
|
+
if (accept) {
|
|
4431
|
+
const acceptedTypes = accept.split(",").map((type) => type.trim());
|
|
4432
|
+
const isAccepted = acceptedTypes.some((type) => {
|
|
4433
|
+
if (type.startsWith(".")) {
|
|
4434
|
+
return file.name.toLowerCase().endsWith(type.toLowerCase());
|
|
4435
|
+
}
|
|
4436
|
+
if (type.includes("/*")) {
|
|
4437
|
+
const baseType = type.split("/")[0];
|
|
4438
|
+
return file.type.startsWith(baseType + "/");
|
|
4439
|
+
}
|
|
4440
|
+
return file.type === type;
|
|
4441
|
+
});
|
|
4442
|
+
if (!isAccepted) {
|
|
4443
|
+
currentError = `File type "${file.type}" is not accepted`;
|
|
4444
|
+
setError(currentError);
|
|
4445
|
+
return;
|
|
4446
|
+
}
|
|
4447
|
+
}
|
|
4448
|
+
validFiles.push(file);
|
|
4449
|
+
});
|
|
4450
|
+
if (currentError) {
|
|
4451
|
+
setError(currentError);
|
|
4452
|
+
}
|
|
4453
|
+
else {
|
|
4454
|
+
setError(null);
|
|
4455
|
+
}
|
|
4456
|
+
return validFiles;
|
|
4457
|
+
};
|
|
4458
|
+
const handleFiles = (files) => {
|
|
4459
|
+
if (files.length === 0)
|
|
4460
|
+
return;
|
|
4461
|
+
const newUploadedFiles = files.map((file) => {
|
|
4462
|
+
const uploadedFile = {
|
|
4463
|
+
file,
|
|
4464
|
+
id: `${file.name}-${file.size}-${file.lastModified}-${Date.now()}`,
|
|
4465
|
+
};
|
|
4466
|
+
if (isImageFile(file) && showPreview) {
|
|
4467
|
+
uploadedFile.preview = URL.createObjectURL(file);
|
|
4468
|
+
}
|
|
4469
|
+
return uploadedFile;
|
|
4470
|
+
});
|
|
4471
|
+
const updatedFiles = multiple
|
|
4472
|
+
? [...uploadedFiles, ...newUploadedFiles]
|
|
4473
|
+
: newUploadedFiles;
|
|
4474
|
+
setUploadedFiles(updatedFiles);
|
|
4475
|
+
// Call onChange with File objects only (filter out URL-only items)
|
|
4476
|
+
if (onChange) {
|
|
4477
|
+
const filesToReturn = updatedFiles
|
|
4478
|
+
.map((uf) => uf.file)
|
|
4479
|
+
.filter((file) => file !== undefined);
|
|
4480
|
+
onChange(multiple ? filesToReturn : filesToReturn[0] || null);
|
|
4481
|
+
}
|
|
4482
|
+
};
|
|
4483
|
+
const handleFileInputChange = (e) => {
|
|
4484
|
+
if (e.target.files && e.target.files.length > 0) {
|
|
4485
|
+
const validFiles = processFiles(e.target.files);
|
|
4486
|
+
if (validFiles.length > 0) {
|
|
4487
|
+
handleFiles(validFiles);
|
|
4488
|
+
}
|
|
4489
|
+
// Reset input value to allow selecting the same file again
|
|
4490
|
+
e.target.value = "";
|
|
4491
|
+
}
|
|
4492
|
+
};
|
|
4493
|
+
const handleDragOver = (e) => {
|
|
4494
|
+
e.preventDefault();
|
|
4495
|
+
e.stopPropagation();
|
|
4496
|
+
if (!isDisabled) {
|
|
4497
|
+
setIsDragging(true);
|
|
4498
|
+
}
|
|
4499
|
+
};
|
|
4500
|
+
const handleDragLeave = (e) => {
|
|
4501
|
+
e.preventDefault();
|
|
4502
|
+
e.stopPropagation();
|
|
4503
|
+
setIsDragging(false);
|
|
4504
|
+
};
|
|
4505
|
+
const handleDrop = (e) => {
|
|
4506
|
+
e.preventDefault();
|
|
4507
|
+
e.stopPropagation();
|
|
4508
|
+
setIsDragging(false);
|
|
4509
|
+
if (isDisabled)
|
|
4510
|
+
return;
|
|
4511
|
+
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
|
|
4512
|
+
const validFiles = processFiles(e.dataTransfer.files);
|
|
4513
|
+
if (validFiles.length > 0) {
|
|
4514
|
+
handleFiles(validFiles);
|
|
4515
|
+
}
|
|
4516
|
+
}
|
|
4517
|
+
};
|
|
4518
|
+
const handleClick = () => {
|
|
4519
|
+
if (!isDisabled && fileInputRef.current) {
|
|
4520
|
+
fileInputRef.current.click();
|
|
4521
|
+
}
|
|
4522
|
+
};
|
|
4523
|
+
const handleRemoveFile = (e, uploadedFile) => {
|
|
4524
|
+
e.stopPropagation();
|
|
4525
|
+
if (isDisabled)
|
|
4526
|
+
return;
|
|
4527
|
+
// Revoke preview URL if exists
|
|
4528
|
+
if (uploadedFile.preview) {
|
|
4529
|
+
URL.revokeObjectURL(uploadedFile.preview);
|
|
4530
|
+
}
|
|
4531
|
+
const updatedFiles = uploadedFiles.filter((f) => f.id !== uploadedFile.id);
|
|
4532
|
+
setUploadedFiles(updatedFiles);
|
|
4533
|
+
if (onFileRemove) {
|
|
4534
|
+
onFileRemove(uploadedFile);
|
|
4535
|
+
}
|
|
4536
|
+
if (onChange) {
|
|
4537
|
+
// Only return File objects (filter out URL-only items)
|
|
4538
|
+
const filesToReturn = updatedFiles
|
|
4539
|
+
.map((uf) => uf.file)
|
|
4540
|
+
.filter((file) => file !== undefined);
|
|
4541
|
+
onChange(multiple ? filesToReturn : filesToReturn[0] || null);
|
|
4542
|
+
}
|
|
4543
|
+
};
|
|
4544
|
+
// Determine which helper text to show
|
|
4545
|
+
const displayHelperText = errorText || successText || helperText || error;
|
|
4546
|
+
const currentValidationState = errorText
|
|
4547
|
+
? "negative"
|
|
4548
|
+
: successText
|
|
4549
|
+
? "positive"
|
|
4550
|
+
: validationState;
|
|
4551
|
+
const sizeConfig = {
|
|
4552
|
+
small: {
|
|
4553
|
+
gap: "gap-2",
|
|
4554
|
+
iconSize: 16,
|
|
4555
|
+
textSize: "text-body-small-medium",
|
|
4556
|
+
},
|
|
4557
|
+
medium: {
|
|
4558
|
+
gap: "gap-2",
|
|
4559
|
+
iconSize: 16,
|
|
4560
|
+
textSize: "text-body-small-medium",
|
|
4561
|
+
},
|
|
4562
|
+
large: {
|
|
4563
|
+
gap: "gap-3",
|
|
4564
|
+
iconSize: 16,
|
|
4565
|
+
textSize: "text-body-small-medium",
|
|
4566
|
+
},
|
|
4567
|
+
};
|
|
4568
|
+
const config = sizeConfig[size];
|
|
4569
|
+
const defaultUploadText = "Click to upload or drag and drop";
|
|
4570
|
+
const defaultDragText = "Drop files here";
|
|
4571
|
+
return (jsxRuntime.jsxs("div", { ref: ref, className: cn("w-full flex flex-col", config.gap, containerClassName), ...props, children: [label && (jsxRuntime.jsx(FormHeader, { label: label, size: size, isRequired: isRequired, isOptional: isOptional, infoHeading: infoHeading, infoDescription: infoDescription, LinkComponent: LinkComponent, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, className: "mb-2", labelClassName: labelClassName })), jsxRuntime.jsxs("div", { className: cn(uploadBoxVariants({
|
|
4572
|
+
size,
|
|
4573
|
+
validationState: currentValidationState,
|
|
4574
|
+
isDisabled,
|
|
4575
|
+
isDragging,
|
|
4576
|
+
}), uploadAreaClassName, className), onDragOver: handleDragOver, onDragLeave: handleDragLeave, onDrop: handleDrop, onClick: handleClick, children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", accept: accept, multiple: multiple, disabled: isDisabled, onChange: handleFileInputChange, className: "hidden", "aria-label": label || "File upload" }), uploadedFiles.length === 0 ? (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center gap-2 text-center", children: [jsxRuntime.jsx("div", { className: "flex items-center justify-center w-8 h-8 rounded-full bg-surface-fill-neutral-subtle", children: jsxRuntime.jsx(Icon, { name: "upload", size: config.iconSize }) }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [jsxRuntime.jsx(Text, { variant: "body", size: "small", weight: "medium", color: isDisabled ? "disabled" : "default", children: isDragging
|
|
4577
|
+
? dragText || defaultDragText
|
|
4578
|
+
: uploadText || defaultUploadText }), accept && (jsxRuntime.jsxs(Text, { variant: "caption", size: "small", color: isDisabled ? "disabled" : "muted", children: ["Accepted: ", accept] })), maxSize && (jsxRuntime.jsxs(Text, { variant: "caption", size: "small", color: isDisabled ? "disabled" : "muted", children: ["Max size: ", formatFileSize(maxSize)] }))] })] })) : (jsxRuntime.jsxs("div", { className: cn("w-full flex flex-col gap-3", previewClassName), children: [uploadedFiles.map((uploadedFile) => {
|
|
4579
|
+
const { file, url, preview, name, size, id } = uploadedFile;
|
|
4580
|
+
const fileName = name ||
|
|
4581
|
+
file?.name ||
|
|
4582
|
+
(url ? getFileNameFromUrl(url) : "Unknown file");
|
|
4583
|
+
const fileSize = size || file?.size;
|
|
4584
|
+
const canPreview = showPreview && preview;
|
|
4585
|
+
const isImage = isImageFile(file, url);
|
|
4586
|
+
const isPdf = isPdfFile(file, url);
|
|
4587
|
+
// For URLs, try to show as image if not explicitly a PDF
|
|
4588
|
+
// If it's a URL without extension, assume it might be an image
|
|
4589
|
+
// Always try to show URLs as images unless they're explicitly PDFs
|
|
4590
|
+
const shouldShowAsImage = canPreview && preview && (isImage || (url && !isPdf));
|
|
4591
|
+
return (jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-3 border border-surface-outline-neutral-muted rounded-large bg-surface-fill-neutral-intense", children: [shouldShowAsImage ? (jsxRuntime.jsx(ImagePreview, { src: preview, alt: fileName })) : canPreview && isPdf ? (jsxRuntime.jsx("div", { className: "shrink-0 w-16 h-16 rounded-medium border border-action-outline-neutral-faded flex items-center justify-center bg-surface-fill-neutral-subtle", children: jsxRuntime.jsx(Icon, { name: "file", size: 24, className: "text-surface-ink-neutral-subtle" }) })) : (jsxRuntime.jsx("div", { className: "shrink-0 w-16 h-16 rounded-medium border border-action-outline-neutral-faded flex items-center justify-center bg-surface-fill-neutral-subtle", children: jsxRuntime.jsx(Icon, { name: "file", size: 24, className: "text-surface-ink-neutral-subtle" }) })), jsxRuntime.jsxs("div", { className: "flex-1 min-w-0 flex flex-col gap-1", children: [jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: jsxRuntime.jsx(Text, { variant: "body", size: "small", weight: "medium", color: isDisabled ? "disabled" : "default", as: "span", className: "truncate", title: fileName, children: fileName }) }), fileSize !== undefined && (jsxRuntime.jsx(Text, { variant: "caption", size: "small", color: isDisabled ? "disabled" : "muted", as: "span", children: formatFileSize(fileSize) }))] }), !isDisabled && (jsxRuntime.jsx(IconButton, { icon: "close", size: "xsmall", onClick: (e) => handleRemoveFile(e, uploadedFile), "aria-label": `Remove ${fileName}` }))] }, id));
|
|
4592
|
+
}), multiple && !isDisabled && (jsxRuntime.jsx(Button, { variant: "tertiary", color: "primary", size: "small", onClick: handleClick, leadingIcon: jsxRuntime.jsx(Icon, { name: "add", size: 16 }), className: "mt-2 w-fit", children: "Add more files" }))] }))] }), jsxRuntime.jsx(FormFooter, { helperText: displayHelperText || undefined, validationState: currentValidationState === "none"
|
|
4593
|
+
? "default"
|
|
4594
|
+
: currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
|
|
4595
|
+
});
|
|
4596
|
+
UploadBox.displayName = "UploadBox";
|
|
4597
|
+
|
|
4239
4598
|
exports.Alert = Alert;
|
|
4240
4599
|
exports.Amount = Amount;
|
|
4241
4600
|
exports.Avatar = Avatar;
|
|
@@ -4275,6 +4634,7 @@ exports.Text = Text;
|
|
|
4275
4634
|
exports.TextArea = TextArea;
|
|
4276
4635
|
exports.TextField = TextField;
|
|
4277
4636
|
exports.Tooltip = Tooltip;
|
|
4637
|
+
exports.UploadBox = UploadBox;
|
|
4278
4638
|
exports.alertVariants = alertVariants;
|
|
4279
4639
|
exports.avatarVariants = avatarVariants;
|
|
4280
4640
|
exports.badgeVariants = badgeVariants;
|
|
@@ -4302,4 +4662,5 @@ exports.tableVariants = tableVariants;
|
|
|
4302
4662
|
exports.textAreaVariants = textAreaVariants;
|
|
4303
4663
|
exports.textFieldVariants = textFieldVariants;
|
|
4304
4664
|
exports.tooltipVariants = tooltipVariants;
|
|
4665
|
+
exports.uploadBoxVariants = uploadBoxVariants;
|
|
4305
4666
|
//# sourceMappingURL=index.js.map
|