diff --git a/src/components.d.ts b/src/components.d.ts
index 564ab0aa2..8dbfc41ab 100644
--- a/src/components.d.ts
+++ b/src/components.d.ts
@@ -8,6 +8,7 @@ import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
import { AutocompleteTypes, DaisySize, Density, IAutocompleteItem, IAutocompleteNoResults, IInputFeedbackProp, ModusSize, Orientation, PopoverPlacement, SelectionMode, TextFieldTypes, TypographyHierarchy, TypographySize, TypographyWeight, WeekStartDay } from "./components/types";
import { IBreadcrumb } from "./components/modus-wc-breadcrumbs/modus-wc-breadcrumbs";
import { ICollapseOptions } from "./components/modus-wc-collapse/modus-wc-collapse";
+import { IFileDropzoneErrorMessages } from "./components/modus-wc-file-dropzone/modus-wc-file-dropzone";
import { IInputFeedbackLevel } from "./components/modus-wc-input-feedback/modus-wc-input-feedback";
import { LoaderColor, LoaderVariant } from "./components/modus-wc-loader/modus-wc-loader";
import { LogoName } from "./components/modus-wc-logo/logo-constants";
@@ -25,6 +26,7 @@ import { ToastPosition } from "./components/modus-wc-toast/modus-wc-toast";
export { AutocompleteTypes, DaisySize, Density, IAutocompleteItem, IAutocompleteNoResults, IInputFeedbackProp, ModusSize, Orientation, PopoverPlacement, SelectionMode, TextFieldTypes, TypographyHierarchy, TypographySize, TypographyWeight, WeekStartDay } from "./components/types";
export { IBreadcrumb } from "./components/modus-wc-breadcrumbs/modus-wc-breadcrumbs";
export { ICollapseOptions } from "./components/modus-wc-collapse/modus-wc-collapse";
+export { IFileDropzoneErrorMessages } from "./components/modus-wc-file-dropzone/modus-wc-file-dropzone";
export { IInputFeedbackLevel } from "./components/modus-wc-input-feedback/modus-wc-input-feedback";
export { LoaderColor, LoaderVariant } from "./components/modus-wc-loader/modus-wc-loader";
export { LogoName } from "./components/modus-wc-logo/logo-constants";
@@ -711,6 +713,10 @@ export namespace Components {
* Disable the file input
*/
"disabled"?: boolean;
+ /**
+ * Custom error messages displayed when file validation fails
+ */
+ "errorMessages"?: IFileDropzoneErrorMessages;
/**
* Custom instructions shown when files are dragged over the dropzone
*/
@@ -3934,6 +3940,10 @@ declare namespace LocalJSX {
* Disable the file input
*/
"disabled"?: boolean;
+ /**
+ * Custom error messages displayed when file validation fails
+ */
+ "errorMessages"?: IFileDropzoneErrorMessages;
/**
* Custom instructions shown when files are dragged over the dropzone
*/
diff --git a/src/components/modus-wc-file-dropzone/modus-wc-file-dropzone.spec.ts b/src/components/modus-wc-file-dropzone/modus-wc-file-dropzone.spec.ts
index c64caee37..f2bc02310 100644
--- a/src/components/modus-wc-file-dropzone/modus-wc-file-dropzone.spec.ts
+++ b/src/components/modus-wc-file-dropzone/modus-wc-file-dropzone.spec.ts
@@ -408,6 +408,45 @@ describe('modus-wc-file-dropzone', () => {
expect(component.uploadSuccess).toBe(true);
});
+ it('should use custom error message when file count validation fails', async () => {
+ const page = await newSpecPage({
+ components: [ModusWcFileDropzone],
+ html: '',
+ });
+
+ const component = page.rootInstance;
+ const fileSelectSpy = jest.spyOn(component.fileSelect, 'emit');
+ component.errorMessages = {
+ invalidCount: 'Custom file count error',
+ };
+
+ const file1 = new File(['test content 1'], 'file1.txt', {
+ type: 'text/plain',
+ });
+ const file2 = new File(['test content 2'], 'file2.txt', {
+ type: 'text/plain',
+ });
+ const tooManyFiles = {
+ 0: file1,
+ 1: file2,
+ length: 2,
+ item: (idx: number) => [file1, file2][idx],
+ } as unknown as FileList;
+
+ const invalidEvent = {
+ target: {
+ files: tooManyFiles,
+ value: '',
+ },
+ } as unknown as Event;
+
+ component.handleFileChange(invalidEvent);
+
+ expect(fileSelectSpy).not.toHaveBeenCalled();
+ expect(component.invalidFile).toBe('count');
+ expect(component.errorMessage).toBe('Custom file count error');
+ });
+
it('should validate total file size', async () => {
const page = await newSpecPage({
components: [ModusWcFileDropzone],
@@ -1337,6 +1376,54 @@ describe('modus-wc-file-dropzone', () => {
expect(errorMessage).toBe('Validation error');
});
+ it('should return custom error messages from errorMessages', async () => {
+ const page = await newSpecPage({
+ components: [ModusWcFileDropzone],
+ html: '',
+ });
+
+ const component = page.rootInstance;
+ component.errorMessages = {
+ invalidCount: 'Custom count message',
+ invalidName: 'Custom name message',
+ invalidSize: 'Custom size message',
+ invalidType: 'Custom type message',
+ };
+
+ type PrivateMethods = {
+ getErrorMessage: (type: string) => string;
+ };
+
+ const getErrorMessage = (component as unknown as PrivateMethods)[
+ 'getErrorMessage'
+ ].bind(component);
+
+ expect(getErrorMessage('count')).toBe('Custom count message');
+ expect(getErrorMessage('name')).toBe('Custom name message');
+ expect(getErrorMessage('size')).toBe('Custom size message');
+ expect(getErrorMessage('type')).toBe('Custom type message');
+ });
+
+ it('should fallback to invalidFileTypeMessage when errorMessages type is not provided', async () => {
+ const page = await newSpecPage({
+ components: [ModusWcFileDropzone],
+ html: '',
+ });
+
+ const component = page.rootInstance;
+ component.errorMessages = {};
+
+ type PrivateMethods = {
+ getErrorMessage: (type: string) => string;
+ };
+
+ const errorMessage = (component as unknown as PrivateMethods)[
+ 'getErrorMessage'
+ ]('type');
+
+ expect(errorMessage).toBe('Legacy type message');
+ });
+
it('should return "0 Bytes" for zero or undefined bytes in formatFileSize', async () => {
const page = await newSpecPage({
components: [ModusWcFileDropzone],
diff --git a/src/components/modus-wc-file-dropzone/modus-wc-file-dropzone.stories.ts b/src/components/modus-wc-file-dropzone/modus-wc-file-dropzone.stories.ts
index e6eee782a..64e1537cb 100644
--- a/src/components/modus-wc-file-dropzone/modus-wc-file-dropzone.stories.ts
+++ b/src/components/modus-wc-file-dropzone/modus-wc-file-dropzone.stories.ts
@@ -2,6 +2,7 @@ import { withActions } from '@storybook/addon-actions/decorator';
import { Meta, StoryObj } from '@storybook/web-components';
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
+import type { IFileDropzoneErrorMessages } from './modus-wc-file-dropzone';
import { createShadowHostClass } from '../../providers/shadow-dom/shadow-host-helper';
interface FileDropzoneArgs {
@@ -12,6 +13,7 @@ interface FileDropzoneArgs {
'include-state-icon'?: boolean;
instructions?: string;
'invalid-file-type-message'?: string;
+ 'error-messages'?: IFileDropzoneErrorMessages;
'max-file-name-length'?: number;
'max-file-count'?: number;
'max-total-file-size-bytes'?: number;
@@ -54,6 +56,10 @@ const meta: Meta = {
description:
'Custom error message displayed when an invalid file type is selected',
},
+ 'error-messages': {
+ control: 'object',
+ description: 'Custom error messages displayed when file validation fails',
+ },
'max-file-name-length': {
control: 'number',
description:
@@ -107,11 +113,12 @@ export const Default: Story = {
)}
?include-state-icon=${args['include-state-icon']}
instructions=${ifDefined(args['instructions'])}
+ .errorMessages=${args['error-messages']}
invalid-file-type-message=${ifDefined(args['invalid-file-type-message'])}
max-file-name-length=${ifDefined(args['max-file-name-length'])}
max-file-count=${ifDefined(args['max-file-count'])}
max-total-file-size-bytes=${ifDefined(args['max-total-file-size-bytes'])}
- ?multiple=${args.multiple}
+ ?multiple=${args['multiple']}
success-message=${ifDefined(args['success-message'])}
>
`,
@@ -197,12 +204,43 @@ export const fileValidations: Story = {
'max-file-name-length': 20,
'max-file-count': 3,
'max-total-file-size-bytes': 10485760, // 10MB
- 'invalid-file-type-message':
- 'Invalid file format. Please upload correct file type.',
+ errorMessages: {
+ invalidCount: 'You can add up to 3 files.',
+ invalidName: 'Filename must be 20 characters or fewer.',
+ invalidSize: 'Total file size must be 10MB or less.',
+ invalidType: 'Invalid file format. Please upload correct file type.',
+ },
+ },
+ parameters: {
+ docs: {
+ source: {
+ code: `
+
+`,
+ },
+ },
},
render: (args) => html`
` called 'dropzone' for adding custom content su
## Properties
-| Property | Attribute | Description | Type | Default |
-| ----------------------------- | -------------------------------- | --------------------------------------------------------------------- | ---------------------- | ----------- |
-| `acceptFileTypes` | `accept-file-types` | Accepted file types (e.g. '.jpg,.png' or 'image/*') | `string \| undefined` | `undefined` |
-| `customClass` | `custom-class` | Custom CSS class to apply to the file dropzone element | `string \| undefined` | `''` |
-| `disabled` | `disabled` | Disable the file input | `boolean \| undefined` | `undefined` |
-| `fileDraggedOverInstructions` | `file-dragged-over-instructions` | Custom instructions shown when files are dragged over the dropzone | `string \| undefined` | `undefined` |
-| `includeStateIcon` | `include-state-icon` | Include state icon (upload, success, error) | `boolean \| undefined` | `true` |
-| `instructions` | `instructions` | Custom instructions shown as the default dropzone message | `string \| undefined` | `undefined` |
-| `invalidFileTypeMessage` | `invalid-file-type-message` | Custom error message displayed when an invalid file type is selected | `string \| undefined` | `undefined` |
-| `maxFileCount` | `max-file-count` | Maximum number of files allowed, will show error if exceeded | `number \| undefined` | `undefined` |
-| `maxFileNameLength` | `max-file-name-length` | Maximum allowed length of filename, will show error if exceeded | `number \| undefined` | `undefined` |
-| `maxTotalFileSizeBytes` | `max-total-file-size-bytes` | Maximum total file size in bytes allowed, will show error if exceeded | `number \| undefined` | `undefined` |
-| `multiple` | `multiple` | Allow multiple file selection | `boolean \| undefined` | `undefined` |
-| `successMessage` | `success-message` | Success message displayed when files are uploaded successfully | `string \| undefined` | `undefined` |
+| Property | Attribute | Description | Type | Default |
+| ----------------------------- | -------------------------------- | --------------------------------------------------------------------- | ----------------------------------------- | ----------- |
+| `acceptFileTypes` | `accept-file-types` | Accepted file types (e.g. '.jpg,.png' or 'image/*') | `string \| undefined` | `undefined` |
+| `customClass` | `custom-class` | Custom CSS class to apply to the file dropzone element | `string \| undefined` | `''` |
+| `disabled` | `disabled` | Disable the file input | `boolean \| undefined` | `undefined` |
+| `errorMessages` | `error-messages` | Custom error messages displayed when file validation fails | `IFileDropzoneErrorMessages \| undefined` | `undefined` |
+| `fileDraggedOverInstructions` | `file-dragged-over-instructions` | Custom instructions shown when files are dragged over the dropzone | `string \| undefined` | `undefined` |
+| `includeStateIcon` | `include-state-icon` | Include state icon (upload, success, error) | `boolean \| undefined` | `true` |
+| `instructions` | `instructions` | Custom instructions shown as the default dropzone message | `string \| undefined` | `undefined` |
+| `invalidFileTypeMessage` | `invalid-file-type-message` | Custom error message displayed when an invalid file type is selected | `string \| undefined` | `undefined` |
+| `maxFileCount` | `max-file-count` | Maximum number of files allowed, will show error if exceeded | `number \| undefined` | `undefined` |
+| `maxFileNameLength` | `max-file-name-length` | Maximum allowed length of filename, will show error if exceeded | `number \| undefined` | `undefined` |
+| `maxTotalFileSizeBytes` | `max-total-file-size-bytes` | Maximum total file size in bytes allowed, will show error if exceeded | `number \| undefined` | `undefined` |
+| `multiple` | `multiple` | Allow multiple file selection | `boolean \| undefined` | `undefined` |
+| `successMessage` | `success-message` | Success message displayed when files are uploaded successfully | `string \| undefined` | `undefined` |
## Events
diff --git a/src/custom-elements.json b/src/custom-elements.json
index b2eae9f2a..ad2993ab9 100644
--- a/src/custom-elements.json
+++ b/src/custom-elements.json
@@ -3019,6 +3019,14 @@
"text": "boolean"
}
},
+ {
+ "name": "error-messages",
+ "fieldName": "errorMessages",
+ "description": "Custom error messages displayed when file validation fails",
+ "type": {
+ "text": "IFileDropzoneErrorMessages"
+ }
+ },
{
"name": "file-dragged-over-instructions",
"fieldName": "fileDraggedOverInstructions",