UNPKG

@trimble-oss/moduswebcomponents

Version:

Modus Web Components is a modern, accessible UI library built with Stencil JS that provides reusable web components following Trimble's Modus design system. This updated version focuses on improved flexibility, enhanced theming options, comprehensive cust

354 lines (345 loc) 12.7 kB
import { withActions } from "@storybook/addon-actions/decorator"; import { html } from "lit"; import { ifDefined } from "lit/directives/if-defined.js"; import { createShadowHostClass } from "../../providers/shadow-dom/shadow-host-helper"; const meta = { title: 'Components/File Dropzone', component: 'modus-wc-file-dropzone', args: { 'accept-file-types': '.doc, .docx, .pdf', disabled: false, 'include-state-icon': true, instructions: 'Drag files here or browse to upload', }, argTypes: { 'accept-file-types': { control: 'text', description: "Accepted file types (e.g. '.jpg,.png' or 'image/*')", }, 'custom-class': { control: 'text', description: 'Custom CSS class to apply to the file dropzone element', }, disabled: { control: 'boolean', description: 'Disable the file input', table: { defaultValue: { summary: 'false' }, }, }, feedback: { control: 'object', description: 'External feedback to display info, success, or error state with optional custom icon and message', table: { type: { summary: 'IFileDropzoneFeedback', detail: `{ type: 'info' | 'error' | 'success'; icon?: string; message?: string; }`, }, }, }, instructions: { control: 'text', description: 'Default instructions displayed in the dropzone', }, 'invalid-file-type-message': { control: 'text', description: 'Custom error message displayed when an invalid file type is selected', }, 'max-file-name-length': { control: 'number', description: 'Maximum allowed length of filename, will show error if exceeded', }, 'max-file-count': { control: 'number', description: 'Maximum number of files allowed, will show error if exceeded', }, 'max-total-file-size-bytes': { control: 'number', description: 'Maximum total file size in bytes allowed, will show error if exceeded', }, multiple: { control: 'boolean', description: 'Allow multiple file selection', table: { defaultValue: { summary: 'false' }, }, }, reset: { description: 'Reset the dropzone to its initial state, clearing all error and success states', table: { category: 'Methods', type: { summary: '() => Promise<void>' }, }, }, }, decorators: [withActions], parameters: { actions: { handles: ['fileSelect'], }, }, }; export default meta; export const Default = { render: (args) => html ` <modus-wc-file-dropzone accept-file-types=${ifDefined(args['accept-file-types'])} custom-class=${ifDefined(args['custom-class'])} ?disabled=${args.disabled} file-dragged-over-instructions=${ifDefined(args['file-dragged-over-instructions'])} ?include-state-icon=${args['include-state-icon']} instructions=${ifDefined(args['instructions'])} 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} success-message=${ifDefined(args['success-message'])} .feedback=${args.feedback} ></modus-wc-file-dropzone> `, }; export const customContent = { args: { 'accept-file-types': '.pdf, .doc, .docx', 'success-message': 'Files uploaded successfully!', }, parameters: { docs: { source: { code: `<div style="display: flex; flex-direction: column; gap: 1rem;"> <modus-wc-file-dropzone id="custom-dropzone" accept-file-types=".pdf, .doc, .docx" success-message="Files uploaded successfully!" instructions="Drag files here or browse to upload" > <div slot="dropzone" style="width: 300px; margin-top: 1rem;"> <modus-wc-progress value="70" label="70% Uploaded"></modus-wc-progress> </div> </modus-wc-file-dropzone> <modus-wc-button id="reset-button"> Reset Dropzone </modus-wc-button> </div> <script> const dropzone = document.getElementById('custom-dropzone'); const resetButton = document.getElementById('reset-button'); resetButton.addEventListener('click', () => { if (dropzone?.reset) { dropzone.reset(); } }); </script>`, }, }, }, render: (args) => html ` <div style="display: flex; flex-direction: column; gap: 1rem;"> <modus-wc-file-dropzone id="custom-dropzone" accept-file-types=${ifDefined(args['accept-file-types'])} success-message=${ifDefined(args['success-message'])} instructions="Drag files here or browse to upload" > <div slot="dropzone" style="width: 300px; margin-top: 1rem;"> <modus-wc-progress value="70" label="70% Uploaded" ></modus-wc-progress> </div> </modus-wc-file-dropzone> <modus-wc-button @buttonClick=${() => { const dropzone = document.getElementById('custom-dropzone'); if (dropzone === null || dropzone === void 0 ? void 0 : dropzone.reset) { void dropzone.reset(); } }} > Reset Dropzone </modus-wc-button> </div> `, }; export const fileValidations = { args: { multiple: true, '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.', }, render: (args) => html ` <modus-wc-file-dropzone accept-file-types=${ifDefined(args['accept-file-types'])} 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} instructions="Upload files (max 3 files, 10MB total, filename ≤ 20 chars)" ></modus-wc-file-dropzone> `, }; export const multipleFiles = { args: { multiple: true, 'accept-file-types': 'image/*', }, render: (args) => html ` <modus-wc-file-dropzone accept-file-types=${ifDefined(args['accept-file-types'])} multiple=${args.multiple} instructions="Select multiple image files" ></modus-wc-file-dropzone> `, }; const successFeedback = { type: 'success', message: 'Files uploaded successfully!', }; const errorFeedback = { type: 'error', message: 'Upload failed. Please try again.', }; const infoFeedback = { type: 'info', message: 'Release to upload your files', }; export const withFeedback = { args: { 'accept-file-types': '.pdf, .doc, .docx', feedback: successFeedback, }, parameters: { docs: { source: { code: `<div style="display: flex; flex-direction: column; gap: 1rem;"> <modus-wc-file-dropzone id="feedback-dropzone" accept-file-types=".pdf, .doc, .docx" instructions="Drag files here or browse to upload" ></modus-wc-file-dropzone> <div style="display: flex; gap: 0.5rem;"> <modus-wc-button id="success-button">Show Success</modus-wc-button> <modus-wc-button id="error-button" color="danger">Show Error</modus-wc-button> <modus-wc-button id="info-button" color="tertiary">Show Info</modus-wc-button> <modus-wc-button id="clear-button" color="secondary">Clear Feedback</modus-wc-button> </div> </div> <script> const dropzone = document.getElementById('feedback-dropzone'); const successFeedback = { type: 'success', message: 'Files uploaded successfully!' }; const errorFeedback = { type: 'error', message: 'Upload failed. Please try again.' }; const infoFeedback = { type: 'info', message: 'Release to upload your files' }; document.getElementById('success-button')?.addEventListener('click', () => { if (dropzone) dropzone.feedback = successFeedback; }); document.getElementById('error-button')?.addEventListener('click', () => { if (dropzone) dropzone.feedback = errorFeedback; }); document.getElementById('info-button')?.addEventListener('click', () => { if (dropzone) dropzone.feedback = infoFeedback; }); document.getElementById('clear-button')?.addEventListener('click', () => { if (dropzone) dropzone.feedback = undefined; }); </script>`, }, }, }, render: (args) => html ` <div style="display: flex; flex-direction: column; gap: 1rem;"> <modus-wc-file-dropzone id="feedback-dropzone" accept-file-types=${ifDefined(args['accept-file-types'])} .feedback=${args.feedback} ?include-state-icon=${args['include-state-icon']} instructions="Drag files here or browse to upload" ></modus-wc-file-dropzone> <div style="display: flex; gap: 0.5rem;"> <modus-wc-button @buttonClick=${() => { const dropzone = document.getElementById('feedback-dropzone'); if (dropzone) { dropzone.feedback = successFeedback; } }} > Show Success </modus-wc-button> <modus-wc-button color="danger" @buttonClick=${() => { const dropzone = document.getElementById('feedback-dropzone'); if (dropzone) { dropzone.feedback = errorFeedback; } }} > Show Error </modus-wc-button> <modus-wc-button color="tertiary" @buttonClick=${() => { const dropzone = document.getElementById('feedback-dropzone'); if (dropzone) { dropzone.feedback = infoFeedback; } }} > Show Info </modus-wc-button> <modus-wc-button color="secondary" @buttonClick=${() => { const dropzone = document.getElementById('feedback-dropzone'); if (dropzone) { dropzone.feedback = undefined; } }} > Clear Feedback </modus-wc-button> </div> </div> `, }; export const ShadowDomParent = { render: (args) => { if (!customElements.get('file-dropzone-shadow-host')) { const FileDropzoneShadowHost = createShadowHostClass({ componentTag: 'modus-wc-file-dropzone', propsMapper: (v, el) => { var _a, _b, _c, _d, _e, _f, _g, _h; const dropzoneEl = el; dropzoneEl.acceptFileTypes = (_a = v['accept-file-types']) !== null && _a !== void 0 ? _a : ''; dropzoneEl.customClass = v['custom-class'] || ''; dropzoneEl.disabled = Boolean(v.disabled); dropzoneEl.feedback = v.feedback; dropzoneEl.fileDraggedOverInstructions = (_b = v['file-dragged-over-instructions']) !== null && _b !== void 0 ? _b : ''; dropzoneEl.includeStateIcon = Boolean(v['include-state-icon']); dropzoneEl.instructions = (_c = v.instructions) !== null && _c !== void 0 ? _c : ''; dropzoneEl.invalidFileTypeMessage = (_d = v['invalid-file-type-message']) !== null && _d !== void 0 ? _d : ''; dropzoneEl.maxFileCount = (_e = v['max-file-count']) !== null && _e !== void 0 ? _e : 0; dropzoneEl.maxFileNameLength = (_f = v['max-file-name-length']) !== null && _f !== void 0 ? _f : 0; dropzoneEl.maxTotalFileSizeBytes = (_g = v['max-total-file-size-bytes']) !== null && _g !== void 0 ? _g : 0; dropzoneEl.multiple = Boolean(v.multiple); dropzoneEl.successMessage = (_h = v['success-message']) !== null && _h !== void 0 ? _h : ''; }, }); customElements.define('file-dropzone-shadow-host', FileDropzoneShadowHost); } return html `<file-dropzone-shadow-host .props=${Object.assign({}, args)} ></file-dropzone-shadow-host>`; }, };