@melodicdev/components 1.2.3 → 1.3.0

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.
Files changed (38) hide show
  1. package/assets/melodic-components.js +32 -7
  2. package/assets/melodic-components.js.map +1 -1
  3. package/assets/melodic-components.min.js +88 -64
  4. package/lib/components/forms/autocomplete/autocomplete.template.js +7 -7
  5. package/lib/components/forms/file-upload/file-icon.component.d.ts +12 -0
  6. package/lib/components/forms/file-upload/file-icon.component.d.ts.map +1 -0
  7. package/lib/components/forms/file-upload/file-icon.component.js +34 -0
  8. package/lib/components/forms/file-upload/file-icon.styles.d.ts +2 -0
  9. package/lib/components/forms/file-upload/file-icon.styles.d.ts.map +1 -0
  10. package/lib/components/forms/file-upload/file-icon.styles.js +124 -0
  11. package/lib/components/forms/file-upload/file-icon.template.d.ts +3 -0
  12. package/lib/components/forms/file-upload/file-icon.template.d.ts.map +1 -0
  13. package/lib/components/forms/file-upload/file-icon.template.js +18 -0
  14. package/lib/components/forms/file-upload/file-upload-item.component.d.ts +17 -0
  15. package/lib/components/forms/file-upload/file-upload-item.component.d.ts.map +1 -0
  16. package/lib/components/forms/file-upload/file-upload-item.component.js +52 -0
  17. package/lib/components/forms/file-upload/file-upload-item.styles.d.ts +2 -0
  18. package/lib/components/forms/file-upload/file-upload-item.styles.d.ts.map +1 -0
  19. package/lib/components/forms/file-upload/file-upload-item.styles.js +172 -0
  20. package/lib/components/forms/file-upload/file-upload-item.template.d.ts +3 -0
  21. package/lib/components/forms/file-upload/file-upload-item.template.d.ts.map +1 -0
  22. package/lib/components/forms/file-upload/file-upload-item.template.js +55 -0
  23. package/lib/components/forms/file-upload/file-upload.component.d.ts +24 -0
  24. package/lib/components/forms/file-upload/file-upload.component.d.ts.map +1 -0
  25. package/lib/components/forms/file-upload/file-upload.component.js +130 -0
  26. package/lib/components/forms/file-upload/file-upload.styles.d.ts +2 -0
  27. package/lib/components/forms/file-upload/file-upload.styles.d.ts.map +1 -0
  28. package/lib/components/forms/file-upload/file-upload.styles.js +125 -0
  29. package/lib/components/forms/file-upload/file-upload.template.d.ts +3 -0
  30. package/lib/components/forms/file-upload/file-upload.template.d.ts.map +1 -0
  31. package/lib/components/forms/file-upload/file-upload.template.js +51 -0
  32. package/lib/components/forms/file-upload/file-upload.types.d.ts +9 -0
  33. package/lib/components/forms/file-upload/file-upload.types.d.ts.map +1 -0
  34. package/lib/components/forms/file-upload/file-upload.types.js +40 -0
  35. package/lib/components/forms/file-upload/index.d.ts +6 -0
  36. package/lib/components/forms/file-upload/index.d.ts.map +1 -0
  37. package/lib/components/forms/file-upload/index.js +4 -0
  38. package/package.json +5 -1
@@ -0,0 +1,17 @@
1
+ import type { IElementRef } from '@melodicdev/core';
2
+ import type { FileUploadStatus } from './file-upload.types.js';
3
+ export declare class FileUploadItemComponent implements IElementRef {
4
+ elementRef: HTMLElement;
5
+ name: string;
6
+ size: string;
7
+ status: FileUploadStatus;
8
+ progress: number;
9
+ error: string;
10
+ file: File | null;
11
+ get extension(): string;
12
+ get displayProgress(): string;
13
+ get progressWidth(): number;
14
+ handleRemove: () => void;
15
+ handleRetry: () => void;
16
+ }
17
+ //# sourceMappingURL=file-upload-item.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-upload-item.component.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/file-upload/file-upload-item.component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAI/D,qBAMa,uBAAwB,YAAW,WAAW;IAC1D,UAAU,EAAG,WAAW,CAAC;IAEzB,IAAI,SAAM;IACV,IAAI,SAAM;IACV,MAAM,EAAE,gBAAgB,CAAU;IAClC,QAAQ,SAAK;IACb,KAAK,SAAM;IACX,IAAI,EAAE,IAAI,GAAG,IAAI,CAAQ;IAEzB,IAAI,SAAS,IAAI,MAAM,CAGtB;IAED,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,YAAY,QAAO,IAAI,CAQrB;IAEF,WAAW,QAAO,IAAI,CAQpB;CACF"}
@@ -0,0 +1,52 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { MelodicComponent } from '@melodicdev/core';
8
+ import { fileUploadItemTemplate } from './file-upload-item.template.js';
9
+ import { fileUploadItemStyles } from './file-upload-item.styles.js';
10
+ let FileUploadItemComponent = class FileUploadItemComponent {
11
+ constructor() {
12
+ this.name = '';
13
+ this.size = '';
14
+ this.status = 'idle';
15
+ this.progress = 0;
16
+ this.error = '';
17
+ this.file = null;
18
+ this.handleRemove = () => {
19
+ this.elementRef.dispatchEvent(new CustomEvent('ml:remove', {
20
+ bubbles: true,
21
+ composed: true,
22
+ detail: { name: this.name, file: this.file }
23
+ }));
24
+ };
25
+ this.handleRetry = () => {
26
+ this.elementRef.dispatchEvent(new CustomEvent('ml:retry', {
27
+ bubbles: true,
28
+ composed: true,
29
+ detail: { name: this.name, file: this.file }
30
+ }));
31
+ };
32
+ }
33
+ get extension() {
34
+ const parts = this.name.split('.');
35
+ return parts.length > 1 ? parts.pop() : '';
36
+ }
37
+ get displayProgress() {
38
+ return `${Math.round(Math.min(Math.max(this.progress, 0), 100))}%`;
39
+ }
40
+ get progressWidth() {
41
+ return Math.min(Math.max(this.progress, 0), 100);
42
+ }
43
+ };
44
+ FileUploadItemComponent = __decorate([
45
+ MelodicComponent({
46
+ selector: 'ml-file-upload-item',
47
+ template: fileUploadItemTemplate,
48
+ styles: fileUploadItemStyles,
49
+ attributes: ['name', 'size', 'status', 'progress', 'error']
50
+ })
51
+ ], FileUploadItemComponent);
52
+ export { FileUploadItemComponent };
@@ -0,0 +1,2 @@
1
+ export declare const fileUploadItemStyles: () => import("@melodicdev/core").TemplateResult;
2
+ //# sourceMappingURL=file-upload-item.styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-upload-item.styles.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/file-upload/file-upload-item.styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,oBAAoB,iDA0KhC,CAAC"}
@@ -0,0 +1,172 @@
1
+ import { css } from '@melodicdev/core';
2
+ export const fileUploadItemStyles = () => css `
3
+ :host {
4
+ display: block;
5
+ width: 100%;
6
+ }
7
+
8
+ .ml-file-item {
9
+ display: flex;
10
+ gap: var(--ml-space-3);
11
+ padding: var(--ml-space-4);
12
+ border: var(--ml-border) solid var(--ml-color-border);
13
+ border-radius: var(--ml-radius-md);
14
+ background-color: var(--ml-color-surface);
15
+ transition: border-color var(--ml-duration-150) var(--ml-ease-in-out);
16
+ }
17
+
18
+ .ml-file-item__icon {
19
+ flex-shrink: 0;
20
+ display: flex;
21
+ align-items: flex-start;
22
+ padding-top: var(--ml-space-0-5);
23
+ }
24
+
25
+ .ml-file-item__content {
26
+ flex: 1;
27
+ min-width: 0;
28
+ display: flex;
29
+ flex-direction: column;
30
+ gap: var(--ml-space-2);
31
+ }
32
+
33
+ .ml-file-item__header {
34
+ display: flex;
35
+ align-items: flex-start;
36
+ justify-content: space-between;
37
+ gap: var(--ml-space-2);
38
+ }
39
+
40
+ .ml-file-item__info {
41
+ min-width: 0;
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: var(--ml-space-0-5);
45
+ }
46
+
47
+ .ml-file-item__name {
48
+ font-size: var(--ml-text-sm);
49
+ font-weight: var(--ml-font-medium);
50
+ color: var(--ml-color-text);
51
+ line-height: var(--ml-leading-tight);
52
+ overflow: hidden;
53
+ text-overflow: ellipsis;
54
+ white-space: nowrap;
55
+ }
56
+
57
+ .ml-file-item__size {
58
+ font-size: var(--ml-text-sm);
59
+ color: var(--ml-color-text-muted);
60
+ line-height: var(--ml-leading-tight);
61
+ }
62
+
63
+ .ml-file-item__remove {
64
+ flex-shrink: 0;
65
+ display: flex;
66
+ align-items: center;
67
+ justify-content: center;
68
+ width: 28px;
69
+ height: 28px;
70
+ padding: 0;
71
+ border: none;
72
+ border-radius: var(--ml-radius);
73
+ background: transparent;
74
+ color: var(--ml-color-text-muted);
75
+ cursor: pointer;
76
+ transition:
77
+ color var(--ml-duration-150) var(--ml-ease-in-out),
78
+ background-color var(--ml-duration-150) var(--ml-ease-in-out);
79
+ }
80
+
81
+ .ml-file-item__remove:hover {
82
+ color: var(--ml-color-danger);
83
+ background-color: var(--ml-color-surface-sunken);
84
+ }
85
+
86
+ .ml-file-item__remove:focus-visible {
87
+ outline: none;
88
+ box-shadow: var(--ml-shadow-focus-ring);
89
+ }
90
+
91
+ /* Progress */
92
+ .ml-file-item__progress {
93
+ display: flex;
94
+ align-items: center;
95
+ gap: var(--ml-space-3);
96
+ }
97
+
98
+ .ml-file-item__progress-track {
99
+ flex: 1;
100
+ height: 6px;
101
+ background-color: var(--ml-color-surface-sunken);
102
+ border-radius: var(--ml-radius-full);
103
+ overflow: hidden;
104
+ }
105
+
106
+ .ml-file-item__progress-fill {
107
+ height: 100%;
108
+ background-color: var(--ml-color-primary);
109
+ border-radius: var(--ml-radius-full);
110
+ transition: width var(--ml-duration-300) var(--ml-ease-out);
111
+ }
112
+
113
+ .ml-file-item__progress-text {
114
+ flex-shrink: 0;
115
+ font-size: var(--ml-text-sm);
116
+ font-weight: var(--ml-font-medium);
117
+ color: var(--ml-color-text-secondary);
118
+ min-width: 32px;
119
+ text-align: right;
120
+ }
121
+
122
+ /* Status row */
123
+ .ml-file-item__status-row {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: var(--ml-space-1-5);
127
+ font-size: var(--ml-text-sm);
128
+ color: var(--ml-color-success);
129
+ line-height: var(--ml-leading-tight);
130
+ }
131
+
132
+ .ml-file-item__status-row--error {
133
+ color: var(--ml-color-danger);
134
+ }
135
+
136
+ .ml-file-item__error-text {
137
+ font-size: var(--ml-text-sm);
138
+ color: var(--ml-color-danger);
139
+ }
140
+
141
+ .ml-file-item__retry {
142
+ padding: 0;
143
+ border: none;
144
+ background: transparent;
145
+ font-size: var(--ml-text-sm);
146
+ font-weight: var(--ml-font-medium);
147
+ color: var(--ml-color-primary);
148
+ cursor: pointer;
149
+ text-decoration: underline;
150
+ font-family: var(--ml-font-sans);
151
+ }
152
+
153
+ .ml-file-item__retry:hover {
154
+ color: var(--ml-color-primary-hover);
155
+ }
156
+
157
+ .ml-file-item__retry:focus-visible {
158
+ outline: none;
159
+ box-shadow: var(--ml-shadow-focus-ring);
160
+ border-radius: var(--ml-radius-xs);
161
+ }
162
+
163
+ /* Error state */
164
+ .ml-file-item--error {
165
+ border-color: var(--ml-color-danger);
166
+ }
167
+
168
+ /* Complete state */
169
+ .ml-file-item--complete {
170
+ border-color: var(--ml-color-success);
171
+ }
172
+ `;
@@ -0,0 +1,3 @@
1
+ import type { FileUploadItemComponent } from './file-upload-item.component.js';
2
+ export declare function fileUploadItemTemplate(c: FileUploadItemComponent): import("@melodicdev/core").TemplateResult;
3
+ //# sourceMappingURL=file-upload-item.template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-upload-item.template.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/file-upload/file-upload-item.template.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE/E,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,uBAAuB,6CAqDhE"}
@@ -0,0 +1,55 @@
1
+ import { html, classMap, styleMap, when } from '@melodicdev/core';
2
+ export function fileUploadItemTemplate(c) {
3
+ return html `
4
+ <div class=${classMap({
5
+ 'ml-file-item': true,
6
+ [`ml-file-item--${c.status}`]: true
7
+ })}>
8
+ <div class="ml-file-item__icon">
9
+ <ml-file-icon extension=${c.extension} size="md"></ml-file-icon>
10
+ </div>
11
+
12
+ <div class="ml-file-item__content">
13
+ <div class="ml-file-item__header">
14
+ <div class="ml-file-item__info">
15
+ <span class="ml-file-item__name">${c.name}</span>
16
+ ${when(!!c.size, () => html `
17
+ <span class="ml-file-item__size">${c.size}</span>
18
+ `)}
19
+ </div>
20
+ <button
21
+ class="ml-file-item__remove"
22
+ type="button"
23
+ aria-label="Remove file"
24
+ @click=${c.handleRemove}
25
+ >
26
+ <ml-icon icon="trash" size="sm"></ml-icon>
27
+ </button>
28
+ </div>
29
+
30
+ ${when(c.status === 'uploading', () => html `
31
+ <div class="ml-file-item__progress">
32
+ <div class="ml-file-item__progress-track">
33
+ <div class="ml-file-item__progress-fill" style=${styleMap({ width: `${c.progressWidth}%` })}></div>
34
+ </div>
35
+ <span class="ml-file-item__progress-text">${c.displayProgress}</span>
36
+ </div>
37
+ `)}
38
+
39
+ ${when(c.status === 'complete', () => html `
40
+ <div class="ml-file-item__status-row">
41
+ <ml-icon icon="check-circle" size="sm"></ml-icon>
42
+ <span>Complete</span>
43
+ </div>
44
+ `)}
45
+
46
+ ${when(c.status === 'error', () => html `
47
+ <div class="ml-file-item__status-row ml-file-item__status-row--error">
48
+ <span class="ml-file-item__error-text">${c.error || 'Upload failed'}</span>
49
+ <button class="ml-file-item__retry" type="button" @click=${c.handleRetry}>Try again</button>
50
+ </div>
51
+ `)}
52
+ </div>
53
+ </div>
54
+ `;
55
+ }
@@ -0,0 +1,24 @@
1
+ import type { IElementRef } from '@melodicdev/core';
2
+ export declare class FileUploadComponent implements IElementRef {
3
+ elementRef: HTMLElement;
4
+ accept: string;
5
+ multiple: boolean;
6
+ maxSize: number;
7
+ maxFiles: number;
8
+ disabled: boolean;
9
+ label: string;
10
+ sublabel: string;
11
+ hint: string;
12
+ error: string;
13
+ icon: string;
14
+ dragOver: boolean;
15
+ _dragCounter: number;
16
+ handleClick: () => void;
17
+ handleFileInput: (event: Event) => void;
18
+ handleDragEnter: (event: DragEvent) => void;
19
+ handleDragOver: (event: DragEvent) => void;
20
+ handleDragLeave: (event: DragEvent) => void;
21
+ handleDrop: (event: DragEvent) => void;
22
+ _processFiles(files: File[]): void;
23
+ }
24
+ //# sourceMappingURL=file-upload.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-upload.component.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/file-upload/file-upload.component.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAKpD,qBAMa,mBAAoB,YAAW,WAAW;IACtD,UAAU,EAAG,WAAW,CAAC;IAEzB,MAAM,SAAM;IACZ,QAAQ,UAAS;IACjB,OAAO,SAAK;IACZ,QAAQ,SAAK;IACb,QAAQ,UAAS;IACjB,KAAK,SAAqB;IAC1B,QAAQ,SAAsB;IAC9B,IAAI,SAAM;IACV,KAAK,SAAM;IACX,IAAI,SAAoB;IAExB,QAAQ,UAAS;IACjB,YAAY,SAAK;IAEjB,WAAW,QAAO,IAAI,CAIpB;IAEF,eAAe,GAAI,OAAO,KAAK,KAAG,IAAI,CAKpC;IAEF,eAAe,GAAI,OAAO,SAAS,KAAG,IAAI,CAQxC;IAEF,cAAc,GAAI,OAAO,SAAS,KAAG,IAAI,CAGvC;IAEF,eAAe,GAAI,OAAO,SAAS,KAAG,IAAI,CAOxC;IAEF,UAAU,GAAI,OAAO,SAAS,KAAG,IAAI,CASnC;IAEF,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI;CAwDlC"}
@@ -0,0 +1,130 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { MelodicComponent } from '@melodicdev/core';
8
+ import { fileUploadTemplate } from './file-upload.template.js';
9
+ import { fileUploadStyles } from './file-upload.styles.js';
10
+ let FileUploadComponent = class FileUploadComponent {
11
+ constructor() {
12
+ this.accept = '';
13
+ this.multiple = false;
14
+ this.maxSize = 0;
15
+ this.maxFiles = 0;
16
+ this.disabled = false;
17
+ this.label = 'Click to upload';
18
+ this.sublabel = 'or drag and drop';
19
+ this.hint = '';
20
+ this.error = '';
21
+ this.icon = 'cloud-arrow-up';
22
+ this.dragOver = false;
23
+ this._dragCounter = 0;
24
+ this.handleClick = () => {
25
+ if (this.disabled)
26
+ return;
27
+ const input = this.elementRef.shadowRoot?.querySelector('input[type="file"]');
28
+ input?.click();
29
+ };
30
+ this.handleFileInput = (event) => {
31
+ const input = event.target;
32
+ if (!input.files?.length)
33
+ return;
34
+ this._processFiles(Array.from(input.files));
35
+ input.value = '';
36
+ };
37
+ this.handleDragEnter = (event) => {
38
+ event.preventDefault();
39
+ event.stopPropagation();
40
+ if (this.disabled)
41
+ return;
42
+ this._dragCounter++;
43
+ if (this._dragCounter === 1) {
44
+ this.dragOver = true;
45
+ }
46
+ };
47
+ this.handleDragOver = (event) => {
48
+ event.preventDefault();
49
+ event.stopPropagation();
50
+ };
51
+ this.handleDragLeave = (event) => {
52
+ event.preventDefault();
53
+ event.stopPropagation();
54
+ this._dragCounter--;
55
+ if (this._dragCounter === 0) {
56
+ this.dragOver = false;
57
+ }
58
+ };
59
+ this.handleDrop = (event) => {
60
+ event.preventDefault();
61
+ event.stopPropagation();
62
+ this._dragCounter = 0;
63
+ this.dragOver = false;
64
+ if (this.disabled)
65
+ return;
66
+ const files = event.dataTransfer?.files;
67
+ if (!files?.length)
68
+ return;
69
+ this._processFiles(Array.from(files));
70
+ };
71
+ }
72
+ _processFiles(files) {
73
+ const errors = [];
74
+ let validFiles = files;
75
+ if (this.accept) {
76
+ const acceptedTypes = this.accept.split(',').map(t => t.trim().toLowerCase());
77
+ validFiles = validFiles.filter(file => {
78
+ const ext = '.' + file.name.split('.').pop()?.toLowerCase();
79
+ const mime = file.type.toLowerCase();
80
+ const matches = acceptedTypes.some(type => {
81
+ if (type.startsWith('.'))
82
+ return ext === type;
83
+ if (type.endsWith('/*'))
84
+ return mime.startsWith(type.replace('/*', '/'));
85
+ return mime === type;
86
+ });
87
+ if (!matches) {
88
+ errors.push({ type: 'accept', file, message: `${file.name} is not an accepted file type` });
89
+ }
90
+ return matches;
91
+ });
92
+ }
93
+ if (this.maxSize > 0) {
94
+ validFiles = validFiles.filter(file => {
95
+ if (file.size > this.maxSize) {
96
+ errors.push({ type: 'max-size', file, message: `${file.name} exceeds maximum size` });
97
+ return false;
98
+ }
99
+ return true;
100
+ });
101
+ }
102
+ if (this.maxFiles > 0 && validFiles.length > this.maxFiles) {
103
+ errors.push({ type: 'max-files', message: `Maximum ${this.maxFiles} files allowed` });
104
+ validFiles = validFiles.slice(0, this.maxFiles);
105
+ }
106
+ if (errors.length > 0) {
107
+ this.elementRef.dispatchEvent(new CustomEvent('ml:error', {
108
+ bubbles: true,
109
+ composed: true,
110
+ detail: { errors }
111
+ }));
112
+ }
113
+ if (validFiles.length > 0) {
114
+ this.elementRef.dispatchEvent(new CustomEvent('ml:change', {
115
+ bubbles: true,
116
+ composed: true,
117
+ detail: { files: validFiles }
118
+ }));
119
+ }
120
+ }
121
+ };
122
+ FileUploadComponent = __decorate([
123
+ MelodicComponent({
124
+ selector: 'ml-file-upload',
125
+ template: fileUploadTemplate,
126
+ styles: fileUploadStyles,
127
+ attributes: ['accept', 'multiple', 'max-size', 'max-files', 'disabled', 'label', 'sublabel', 'hint', 'error', 'icon']
128
+ })
129
+ ], FileUploadComponent);
130
+ export { FileUploadComponent };
@@ -0,0 +1,2 @@
1
+ export declare const fileUploadStyles: () => import("@melodicdev/core").TemplateResult;
2
+ //# sourceMappingURL=file-upload.styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-upload.styles.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/file-upload/file-upload.styles.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,gBAAgB,iDA2H5B,CAAC"}
@@ -0,0 +1,125 @@
1
+ import { css } from '@melodicdev/core';
2
+ export const fileUploadStyles = () => css `
3
+ :host {
4
+ display: block;
5
+ width: 100%;
6
+ }
7
+
8
+ .ml-file-upload {
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: var(--ml-space-1-5);
12
+ }
13
+
14
+ .ml-file-upload__dropzone {
15
+ display: flex;
16
+ flex-direction: column;
17
+ align-items: center;
18
+ justify-content: center;
19
+ gap: var(--ml-space-3);
20
+ padding: var(--ml-space-6) var(--ml-space-6);
21
+ border: 2px dashed var(--ml-color-border);
22
+ border-radius: var(--ml-radius-md);
23
+ background-color: var(--ml-color-surface);
24
+ cursor: pointer;
25
+ transition:
26
+ border-color var(--ml-duration-150) var(--ml-ease-in-out),
27
+ background-color var(--ml-duration-150) var(--ml-ease-in-out);
28
+ }
29
+
30
+ .ml-file-upload__dropzone:hover {
31
+ border-color: var(--ml-color-primary);
32
+ background-color: var(--ml-color-surface-sunken);
33
+ }
34
+
35
+ .ml-file-upload__dropzone:focus-visible {
36
+ outline: none;
37
+ border-color: var(--ml-color-primary);
38
+ box-shadow: var(--ml-shadow-focus-ring);
39
+ }
40
+
41
+ .ml-file-upload__icon {
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ width: 40px;
46
+ height: 40px;
47
+ border-radius: var(--ml-radius-full);
48
+ background-color: var(--ml-color-surface-sunken);
49
+ color: var(--ml-color-text-muted);
50
+ }
51
+
52
+ .ml-file-upload__text {
53
+ display: flex;
54
+ flex-direction: column;
55
+ align-items: center;
56
+ gap: var(--ml-space-1);
57
+ text-align: center;
58
+ }
59
+
60
+ .ml-file-upload__label {
61
+ font-size: var(--ml-text-sm);
62
+ font-weight: var(--ml-font-semibold);
63
+ color: var(--ml-color-primary);
64
+ line-height: var(--ml-leading-tight);
65
+ }
66
+
67
+ .ml-file-upload__sublabel {
68
+ font-size: var(--ml-text-sm);
69
+ color: var(--ml-color-text-muted);
70
+ line-height: var(--ml-leading-tight);
71
+ }
72
+
73
+ .ml-file-upload__input {
74
+ position: absolute;
75
+ width: 1px;
76
+ height: 1px;
77
+ padding: 0;
78
+ margin: -1px;
79
+ overflow: hidden;
80
+ clip: rect(0, 0, 0, 0);
81
+ white-space: nowrap;
82
+ border: 0;
83
+ }
84
+
85
+ .ml-file-upload__hint {
86
+ font-size: var(--ml-text-sm);
87
+ color: var(--ml-color-text-muted);
88
+ line-height: var(--ml-leading-tight);
89
+ }
90
+
91
+ .ml-file-upload__error {
92
+ font-size: var(--ml-text-sm);
93
+ color: var(--ml-color-danger);
94
+ line-height: var(--ml-leading-tight);
95
+ }
96
+
97
+ /* Drag over state */
98
+ .ml-file-upload--drag-over .ml-file-upload__dropzone {
99
+ border-color: var(--ml-color-primary);
100
+ background-color: var(--ml-color-surface-sunken);
101
+ }
102
+
103
+ .ml-file-upload--drag-over .ml-file-upload__icon {
104
+ color: var(--ml-color-primary);
105
+ background-color: var(--ml-color-primary-subtle, rgba(59, 130, 246, 0.1));
106
+ }
107
+
108
+ /* Error state */
109
+ .ml-file-upload--error .ml-file-upload__dropzone {
110
+ border-color: var(--ml-color-danger);
111
+ }
112
+
113
+ /* Disabled state */
114
+ .ml-file-upload--disabled .ml-file-upload__dropzone {
115
+ background-color: var(--ml-color-input-disabled-bg);
116
+ border-color: var(--ml-color-border);
117
+ cursor: not-allowed;
118
+ opacity: 0.6;
119
+ }
120
+
121
+ .ml-file-upload--disabled .ml-file-upload__dropzone:hover {
122
+ border-color: var(--ml-color-border);
123
+ background-color: var(--ml-color-input-disabled-bg);
124
+ }
125
+ `;
@@ -0,0 +1,3 @@
1
+ import type { FileUploadComponent } from './file-upload.component.js';
2
+ export declare function fileUploadTemplate(c: FileUploadComponent): import("@melodicdev/core").TemplateResult;
3
+ //# sourceMappingURL=file-upload.template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-upload.template.d.ts","sourceRoot":"","sources":["../../../../src/components/forms/file-upload/file-upload.template.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,mBAAmB,6CAkDxD"}
@@ -0,0 +1,51 @@
1
+ import { html, classMap, when } from '@melodicdev/core';
2
+ export function fileUploadTemplate(c) {
3
+ return html `
4
+ <div class=${classMap({
5
+ 'ml-file-upload': true,
6
+ 'ml-file-upload--disabled': c.disabled,
7
+ 'ml-file-upload--error': !!c.error,
8
+ 'ml-file-upload--drag-over': c.dragOver
9
+ })}>
10
+ <div
11
+ class="ml-file-upload__dropzone"
12
+ role="button"
13
+ tabindex=${c.disabled ? '-1' : '0'}
14
+ aria-label="Upload file"
15
+ aria-disabled=${c.disabled ? 'true' : 'false'}
16
+ @click=${c.handleClick}
17
+ @keydown=${(e) => { if (e.key === 'Enter' || e.key === ' ') {
18
+ e.preventDefault();
19
+ c.handleClick();
20
+ } }}
21
+ @dragenter=${c.handleDragEnter}
22
+ @dragover=${c.handleDragOver}
23
+ @dragleave=${c.handleDragLeave}
24
+ @drop=${c.handleDrop}
25
+ >
26
+ <div class="ml-file-upload__icon">
27
+ <ml-icon icon=${c.icon} size="lg"></ml-icon>
28
+ </div>
29
+ <div class="ml-file-upload__text">
30
+ <span class="ml-file-upload__label">${c.label}</span>
31
+ ${when(!!c.sublabel, () => html `
32
+ <span class="ml-file-upload__sublabel">${c.sublabel}</span>
33
+ `)}
34
+ </div>
35
+ </div>
36
+
37
+ <input
38
+ type="file"
39
+ class="ml-file-upload__input"
40
+ accept=${c.accept}
41
+ ?multiple=${c.multiple}
42
+ ?disabled=${c.disabled}
43
+ @change=${c.handleFileInput}
44
+ tabindex="-1"
45
+ aria-hidden="true"
46
+ />
47
+
48
+ ${when(!!c.error, () => html `<span class="ml-file-upload__error">${c.error}</span>`, () => html `${when(!!c.hint, () => html `<span class="ml-file-upload__hint">${c.hint}</span>`)}`)}
49
+ </div>
50
+ `;
51
+ }
@@ -0,0 +1,9 @@
1
+ export type FileUploadStatus = 'idle' | 'uploading' | 'complete' | 'error';
2
+ export type FileIconColor = 'red' | 'green' | 'blue' | 'purple' | 'amber' | 'gray';
3
+ export interface FileValidationError {
4
+ type: 'accept' | 'max-size' | 'max-files';
5
+ file?: File;
6
+ message: string;
7
+ }
8
+ export declare function getColorForExtension(ext: string): FileIconColor;
9
+ //# sourceMappingURL=file-upload.types.d.ts.map