@vaadin/upload 25.1.0-alpha1 → 25.1.0-alpha2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/upload",
3
- "version": "25.1.0-alpha1",
3
+ "version": "25.1.0-alpha2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -34,23 +34,24 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "@open-wc/dedupe-mixin": "^1.3.0",
37
- "@vaadin/a11y-base": "25.1.0-alpha1",
38
- "@vaadin/button": "25.1.0-alpha1",
39
- "@vaadin/component-base": "25.1.0-alpha1",
40
- "@vaadin/progress-bar": "25.1.0-alpha1",
41
- "@vaadin/vaadin-themable-mixin": "25.1.0-alpha1",
37
+ "@vaadin/a11y-base": "25.1.0-alpha2",
38
+ "@vaadin/button": "25.1.0-alpha2",
39
+ "@vaadin/component-base": "25.1.0-alpha2",
40
+ "@vaadin/progress-bar": "25.1.0-alpha2",
41
+ "@vaadin/vaadin-themable-mixin": "25.1.0-alpha2",
42
42
  "lit": "^3.0.0"
43
43
  },
44
44
  "devDependencies": {
45
- "@vaadin/chai-plugins": "25.1.0-alpha1",
46
- "@vaadin/test-runner-commands": "25.1.0-alpha1",
45
+ "@vaadin/aura": "25.1.0-alpha2",
46
+ "@vaadin/chai-plugins": "25.1.0-alpha2",
47
+ "@vaadin/test-runner-commands": "25.1.0-alpha2",
47
48
  "@vaadin/testing-helpers": "^2.0.0",
48
- "@vaadin/vaadin-lumo-styles": "25.1.0-alpha1",
49
+ "@vaadin/vaadin-lumo-styles": "25.1.0-alpha2",
49
50
  "sinon": "^21.0.0"
50
51
  },
51
52
  "web-types": [
52
53
  "web-types.json",
53
54
  "web-types.lit.json"
54
55
  ],
55
- "gitHead": "c789cdd350bcd74b280268a83f5475ad7f2f65e1"
56
+ "gitHead": "dfeb6e14643ec923e5505ca645f7354c6dc170ec"
56
57
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2026 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { CSSResult } from 'lit';
7
+
8
+ export declare const uploadButtonStyles: CSSResult[];
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2026 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { css } from 'lit';
7
+ import { buttonStyles } from '@vaadin/button/src/styles/vaadin-button-base-styles.js';
8
+
9
+ const uploadButton = css``;
10
+
11
+ export const uploadButtonStyles = [buttonStyles, uploadButton];
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2026 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { CSSResult } from 'lit';
7
+
8
+ export declare const uploadDropZoneStyles: CSSResult;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2026 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import '@vaadin/component-base/src/styles/style-props.js';
7
+ import { css } from 'lit';
8
+
9
+ export const uploadDropZoneStyles = css`
10
+ :host {
11
+ display: block;
12
+ position: relative;
13
+ }
14
+
15
+ :host([dragover])::after {
16
+ content: '';
17
+ position: absolute;
18
+ inset: 0;
19
+ background: var(--vaadin-background-container);
20
+ opacity: 0.7;
21
+ }
22
+
23
+ :host([hidden]) {
24
+ display: none !important;
25
+ }
26
+ `;
@@ -8,7 +8,7 @@ import { css } from 'lit';
8
8
 
9
9
  export const uploadFileStyles = css`
10
10
  :host {
11
- align-items: center;
11
+ align-items: baseline;
12
12
  display: grid;
13
13
  gap: var(--vaadin-upload-file-gap, var(--vaadin-gap-s));
14
14
  grid-template-columns: var(--vaadin-icon-size, 1lh) minmax(0, 1fr) auto;
@@ -32,8 +32,9 @@ export const uploadFileStyles = css`
32
32
 
33
33
  [part='done-icon']::before,
34
34
  [part='warning-icon']::before {
35
- content: '';
36
- display: inline-block;
35
+ content: '\\2003' / '';
36
+ display: inline-flex;
37
+ align-items: center;
37
38
  flex: none;
38
39
  height: var(--vaadin-icon-size, 1lh);
39
40
  width: var(--vaadin-icon-size, 1lh);
@@ -82,19 +83,25 @@ export const uploadFileStyles = css`
82
83
  line-height: var(--vaadin-upload-file-error-line-height, inherit);
83
84
  }
84
85
 
86
+ [part='commands'] {
87
+ display: flex;
88
+ align-items: center;
89
+ gap: var(--vaadin-gap-xs);
90
+ height: var(--vaadin-icon-size, 1lh);
91
+ align-self: center;
92
+ }
93
+
85
94
  button {
86
95
  background: var(--vaadin-upload-file-button-background, transparent);
87
- border: var(--vaadin-upload-file-button-border-width, 1px) solid
88
- var(--vaadin-upload-file-button-border-color, transparent);
96
+ border: var(--vaadin-upload-file-button-border-width, 0) solid
97
+ var(--vaadin-upload-file-button-border-color, var(--vaadin-border-color-secondary));
89
98
  border-radius: var(--vaadin-upload-file-button-border-radius, var(--vaadin-radius-m));
90
99
  color: var(--vaadin-upload-file-button-text-color, var(--vaadin-text-color));
91
100
  cursor: var(--vaadin-clickable-cursor);
92
101
  flex-shrink: 0;
93
102
  font: inherit;
94
- padding: var(
95
- --vaadin-upload-file-button-padding,
96
- var(--vaadin-padding-block-container) var(--vaadin-padding-inline-container)
97
- );
103
+ /* Ensure minimum click target (WCAG) */
104
+ padding: var(--vaadin-upload-file-button-padding, max(0px, (24px - var(--vaadin-icon-size, 1lh)) / 2));
98
105
  }
99
106
 
100
107
  button:focus-visible {
@@ -105,8 +112,9 @@ export const uploadFileStyles = css`
105
112
  [part='retry-button']::before,
106
113
  [part='remove-button']::before {
107
114
  background: currentColor;
108
- content: '';
109
- display: block;
115
+ content: '\\2003' / '';
116
+ display: flex;
117
+ align-items: center;
110
118
  height: var(--vaadin-icon-size, 1lh);
111
119
  width: var(--vaadin-icon-size, 1lh);
112
120
  }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2026 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { ButtonMixin } from '@vaadin/button/src/vaadin-button-mixin.js';
7
+ import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
8
+ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
9
+ import type { UploadManager } from './vaadin-upload-manager.js';
10
+
11
+ /**
12
+ * `<vaadin-upload-button>` is a button component for file uploads.
13
+ * When clicked, it opens a file picker dialog and calls addFiles
14
+ * on a linked UploadManager.
15
+ *
16
+ * ```html
17
+ * <vaadin-upload-button>Upload Files</vaadin-upload-button>
18
+ * ```
19
+ *
20
+ * The button must be linked to an UploadManager by setting the
21
+ * `manager` property:
22
+ *
23
+ * ```javascript
24
+ * const button = document.querySelector('vaadin-upload-button');
25
+ * button.manager = uploadManager;
26
+ * ```
27
+ *
28
+ * ### Styling
29
+ *
30
+ * The following shadow DOM parts are available for styling:
31
+ *
32
+ * Part name | Description
33
+ * ----------|-------------
34
+ * `label` | The label (text) inside the button.
35
+ * `prefix` | A slot for content before the label (e.g. an icon).
36
+ * `suffix` | A slot for content after the label (e.g. an icon).
37
+ *
38
+ * The following state attributes are available for styling:
39
+ *
40
+ * Attribute | Description
41
+ * -------------------|-------------
42
+ * `active` | Set when the button is pressed down, either with mouse, touch or the keyboard
43
+ * `disabled` | Set when the button is disabled
44
+ * `focus-ring` | Set when the button is focused using the keyboard
45
+ * `focused` | Set when the button is focused
46
+ * `has-tooltip` | Set when the button has a slotted tooltip
47
+ * `max-files-reached`| Set when the manager has reached maxFiles
48
+ *
49
+ * The following custom CSS properties are available for styling:
50
+ *
51
+ * Custom CSS property |
52
+ * :----------------------------------|
53
+ * | `--vaadin-button-background` |
54
+ * | `--vaadin-button-border-color` |
55
+ * | `--vaadin-button-border-radius` |
56
+ * | `--vaadin-button-border-width` |
57
+ * | `--vaadin-button-font-size` |
58
+ * | `--vaadin-button-font-weight` |
59
+ * | `--vaadin-button-gap` |
60
+ * | `--vaadin-button-height` |
61
+ * | `--vaadin-button-line-height` |
62
+ * | `--vaadin-button-margin` |
63
+ * | `--vaadin-button-padding` |
64
+ * | `--vaadin-button-text-color` |
65
+ *
66
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
67
+ */
68
+ declare class UploadButton extends ButtonMixin(ElementMixin(ThemableMixin(HTMLElement))) {
69
+ /**
70
+ * Reference to an UploadManager.
71
+ * When set, the button will automatically disable when maxFilesReached
72
+ * becomes true on the manager. The file picker will also use the manager's
73
+ * `accept` and `maxFiles` settings.
74
+ */
75
+ manager: UploadManager | null;
76
+
77
+ /**
78
+ * Capture attribute for mobile file input.
79
+ */
80
+ capture: string | undefined;
81
+
82
+ /**
83
+ * True when max files has been reached on the manager.
84
+ * The button will not open the file picker when this is true.
85
+ */
86
+ maxFilesReached: boolean;
87
+
88
+ /**
89
+ * Opens the file picker dialog.
90
+ */
91
+ openFilePicker(): void;
92
+ }
93
+
94
+ declare global {
95
+ interface HTMLElementTagNameMap {
96
+ 'vaadin-upload-button': UploadButton;
97
+ }
98
+ }
99
+
100
+ export { UploadButton };
@@ -0,0 +1,288 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2026 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { html, LitElement } from 'lit';
7
+ import { ButtonMixin } from '@vaadin/button/src/vaadin-button-mixin.js';
8
+ import { defineCustomElement } from '@vaadin/component-base/src/define.js';
9
+ import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
10
+ import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
11
+ import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
12
+ import { LumoInjectionMixin } from '@vaadin/vaadin-themable-mixin/lumo-injection-mixin.js';
13
+ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
14
+ import { uploadButtonStyles } from './styles/vaadin-upload-button-base-styles.js';
15
+ import { UploadManager } from './vaadin-upload-manager.js';
16
+
17
+ /**
18
+ * `<vaadin-upload-button>` is a button component for file uploads.
19
+ * When clicked, it opens a file picker dialog and calls addFiles
20
+ * on a linked UploadManager.
21
+ *
22
+ * ```html
23
+ * <vaadin-upload-button>Upload Files</vaadin-upload-button>
24
+ * ```
25
+ *
26
+ * The button must be linked to an UploadManager by setting the
27
+ * `manager` property:
28
+ *
29
+ * ```javascript
30
+ * const button = document.querySelector('vaadin-upload-button');
31
+ * button.manager = uploadManager;
32
+ * ```
33
+ *
34
+ * ### Styling
35
+ *
36
+ * The following shadow DOM parts are available for styling:
37
+ *
38
+ * Part name | Description
39
+ * ----------|-------------
40
+ * `label` | The label (text) inside the button.
41
+ * `prefix` | A slot for content before the label (e.g. an icon).
42
+ * `suffix` | A slot for content after the label (e.g. an icon).
43
+ *
44
+ * The following state attributes are available for styling:
45
+ *
46
+ * Attribute | Description
47
+ * ---------------|-------------
48
+ * `active` | Set when the button is pressed down, either with mouse, touch or the keyboard
49
+ * `disabled` | Set when the button is disabled
50
+ * `focus-ring` | Set when the button is focused using the keyboard
51
+ * `focused` | Set when the button is focused
52
+ * `has-tooltip` | Set when the button has a slotted tooltip
53
+ *
54
+ * The following custom CSS properties are available for styling:
55
+ *
56
+ * Custom CSS property |
57
+ * :----------------------------------|
58
+ * | `--vaadin-button-background` |
59
+ * | `--vaadin-button-border-color` |
60
+ * | `--vaadin-button-border-radius` |
61
+ * | `--vaadin-button-border-width` |
62
+ * | `--vaadin-button-font-size` |
63
+ * | `--vaadin-button-font-weight` |
64
+ * | `--vaadin-button-gap` |
65
+ * | `--vaadin-button-height` |
66
+ * | `--vaadin-button-line-height` |
67
+ * | `--vaadin-button-margin` |
68
+ * | `--vaadin-button-padding` |
69
+ * | `--vaadin-button-text-color` |
70
+ *
71
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
72
+ *
73
+ * @customElement
74
+ * @extends HTMLElement
75
+ * @mixes ButtonMixin
76
+ * @mixes ElementMixin
77
+ * @mixes ThemableMixin
78
+ */
79
+ class UploadButton extends ButtonMixin(ElementMixin(ThemableMixin(PolylitMixin(LumoInjectionMixin(LitElement))))) {
80
+ static get is() {
81
+ return 'vaadin-upload-button';
82
+ }
83
+
84
+ static get styles() {
85
+ return uploadButtonStyles;
86
+ }
87
+
88
+ static get properties() {
89
+ return {
90
+ /**
91
+ * Reference to an UploadManager.
92
+ * When set, the button will automatically disable when maxFilesReached
93
+ * becomes true on the manager.
94
+ * @type {Object | null}
95
+ */
96
+ manager: {
97
+ type: Object,
98
+ value: null,
99
+ observer: '__managerChanged',
100
+ },
101
+
102
+ /**
103
+ * Capture attribute for mobile file input.
104
+ * @type {string}
105
+ */
106
+ capture: {
107
+ type: String,
108
+ },
109
+
110
+ /**
111
+ * True when max files has been reached on the manager.
112
+ * @type {boolean}
113
+ */
114
+ maxFilesReached: {
115
+ type: Boolean,
116
+ value: false,
117
+ reflect: true,
118
+ attribute: 'max-files-reached',
119
+ },
120
+ };
121
+ }
122
+
123
+ constructor() {
124
+ super();
125
+ this.__syncFromManager = this.__syncFromManager.bind(this);
126
+ this.__explicitDisabled = false;
127
+ }
128
+
129
+ /**
130
+ * Whether the button is disabled.
131
+ * Returns true if either explicitly disabled or maxFilesReached is true.
132
+ * @type {boolean}
133
+ * @override
134
+ */
135
+ get disabled() {
136
+ return super.disabled;
137
+ }
138
+
139
+ set disabled(value) {
140
+ this.__explicitDisabled = Boolean(value);
141
+ // Set super.disabled to effective value - this triggers Lit's property system correctly
142
+ super.disabled = this.__explicitDisabled || this.maxFilesReached;
143
+ }
144
+
145
+ /** @protected */
146
+ render() {
147
+ return html`
148
+ <div class="vaadin-button-container">
149
+ <span part="prefix" aria-hidden="true">
150
+ <slot name="prefix"></slot>
151
+ </span>
152
+ <span part="label">
153
+ <slot></slot>
154
+ </span>
155
+ <span part="suffix" aria-hidden="true">
156
+ <slot name="suffix"></slot>
157
+ </span>
158
+ </div>
159
+ <slot name="tooltip"></slot>
160
+ <input id="fileInput" type="file" hidden @change=${this.__onFileInputChange} />
161
+ `;
162
+ }
163
+
164
+ /** @protected */
165
+ ready() {
166
+ super.ready();
167
+
168
+ // Add tooltip support
169
+ this._tooltipController = new TooltipController(this);
170
+ this.addController(this._tooltipController);
171
+
172
+ // Open file picker on click
173
+ this.addEventListener('click', () => {
174
+ this.openFilePicker();
175
+ });
176
+ }
177
+
178
+ /** @protected */
179
+ disconnectedCallback() {
180
+ super.disconnectedCallback();
181
+
182
+ // Clean up manager listener to prevent memory leaks
183
+ if (this.manager instanceof UploadManager) {
184
+ this.manager.removeEventListener('max-files-reached-changed', this.__syncFromManager);
185
+ }
186
+ }
187
+
188
+ /** @protected */
189
+ connectedCallback() {
190
+ super.connectedCallback();
191
+
192
+ // Re-attach manager listener when reconnected to DOM
193
+ if (this.manager instanceof UploadManager) {
194
+ this.manager.addEventListener('max-files-reached-changed', this.__syncFromManager);
195
+ this.__syncFromManager();
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Opens the file picker dialog.
201
+ */
202
+ openFilePicker() {
203
+ if (this.disabled) {
204
+ return;
205
+ }
206
+
207
+ // Update file input attributes before opening
208
+ this.__updateFileInputAttributes();
209
+
210
+ this.$.fileInput.value = '';
211
+ this.$.fileInput.click();
212
+ }
213
+
214
+ /** @private */
215
+ __updateFileInputAttributes() {
216
+ const { fileInput } = this.$;
217
+
218
+ // Set accept attribute from manager
219
+ const accept = this.manager && this.manager.accept;
220
+ if (accept) {
221
+ fileInput.setAttribute('accept', accept);
222
+ } else {
223
+ fileInput.removeAttribute('accept');
224
+ }
225
+
226
+ // Set multiple attribute based on manager's maxFiles
227
+ const maxFiles = this.manager && this.manager.maxFiles != null ? this.manager.maxFiles : Infinity;
228
+ fileInput.multiple = maxFiles !== 1;
229
+
230
+ // Set capture attribute
231
+ if (this.capture) {
232
+ fileInput.setAttribute('capture', this.capture);
233
+ } else {
234
+ fileInput.removeAttribute('capture');
235
+ }
236
+ }
237
+
238
+ /** @private */
239
+ __onFileInputChange(event) {
240
+ const files = event.target.files;
241
+
242
+ // If we have a manager, call addFiles
243
+ if (this.manager instanceof UploadManager) {
244
+ this.manager.addFiles(files);
245
+ }
246
+ }
247
+
248
+ /** @private */
249
+ __managerChanged(manager, oldManager) {
250
+ // Remove listener from old manager
251
+ if (oldManager instanceof UploadManager) {
252
+ oldManager.removeEventListener('max-files-reached-changed', this.__syncFromManager);
253
+ }
254
+
255
+ // Add listener to new manager and sync state only when connected
256
+ if (this.isConnected && manager instanceof UploadManager) {
257
+ manager.addEventListener('max-files-reached-changed', this.__syncFromManager);
258
+ this.__syncFromManager();
259
+ } else if (this.isConnected) {
260
+ // No manager - reset state
261
+ this.__syncFromManager();
262
+ }
263
+ }
264
+
265
+ /** @private */
266
+ __syncFromManager() {
267
+ if (this.manager instanceof UploadManager) {
268
+ this.maxFilesReached = this.manager.maxFilesReached;
269
+ } else {
270
+ this.maxFilesReached = false;
271
+ }
272
+
273
+ // Sync effective disabled state
274
+ const effectiveDisabled = this.__explicitDisabled || this.maxFilesReached;
275
+ if (super.disabled !== effectiveDisabled) {
276
+ super.disabled = effectiveDisabled;
277
+ }
278
+ }
279
+
280
+ /** @override */
281
+ __shouldAllowFocusWhenDisabled() {
282
+ return window.Vaadin.featureFlags.accessibleDisabledButtons;
283
+ }
284
+ }
285
+
286
+ defineCustomElement(UploadButton);
287
+
288
+ export { UploadButton };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2000 - 2026 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
7
+ import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
8
+ import type { UploadManager } from './vaadin-upload-manager.js';
9
+
10
+ /**
11
+ * `<vaadin-upload-drop-zone>` is a Web Component that can be used as a drop zone
12
+ * for file uploads. When files are dropped on the drop zone, they are added to
13
+ * a linked UploadManager.
14
+ *
15
+ * ```html
16
+ * <vaadin-upload-drop-zone>
17
+ * <p>Drop files here</p>
18
+ * </vaadin-upload-drop-zone>
19
+ * ```
20
+ *
21
+ * The drop zone must be linked to an UploadManager by setting the
22
+ * `manager` property:
23
+ *
24
+ * ```javascript
25
+ * const dropZone = document.querySelector('vaadin-upload-drop-zone');
26
+ * dropZone.manager = uploadManager;
27
+ * ```
28
+ *
29
+ * ### Styling
30
+ *
31
+ * The component has no styling by default. When files are dragged over,
32
+ * the `dragover` attribute is set and the component uses a hover effect.
33
+ * To override the hover effect, use `vaadin-upload-drop-zone[dragover]::after`
34
+ * selector to style the pseudo-element covering the drop zone during dragover.
35
+ *
36
+ * Attribute | Description
37
+ * -------------------|--------------------------------------------
38
+ * `dragover` | Set when files are being dragged over the element
39
+ * `disabled` | Set when the drop zone is explicitly disabled
40
+ * `max-files-reached`| Set when the manager has reached maxFiles
41
+ *
42
+ * See [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.
43
+ */
44
+ declare class UploadDropZone extends HTMLElement {
45
+ /**
46
+ * Reference to an UploadManager.
47
+ * When set, dropped files will be automatically added to the manager.
48
+ */
49
+ manager: UploadManager | null;
50
+
51
+ /**
52
+ * Whether the drop zone is disabled.
53
+ */
54
+ disabled: boolean;
55
+
56
+ /**
57
+ * True when max files has been reached on the manager.
58
+ * The drop zone will not accept files when this is true.
59
+ * @readonly
60
+ */
61
+ readonly maxFilesReached: boolean;
62
+ }
63
+
64
+ interface UploadDropZone extends ElementMixinClass, ThemableMixinClass {}
65
+
66
+ declare global {
67
+ interface HTMLElementTagNameMap {
68
+ 'vaadin-upload-drop-zone': UploadDropZone;
69
+ }
70
+ }
71
+
72
+ export { UploadDropZone };