@statistikzh/leu 0.18.0 → 0.19.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 (106) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +15 -0
  3. package/dist/Accordion.js +1 -1
  4. package/dist/Button.js +1 -1
  5. package/dist/ButtonGroup.js +1 -1
  6. package/dist/ChartWrapper.js +1 -1
  7. package/dist/Checkbox.js +1 -1
  8. package/dist/CheckboxGroup.js +1 -1
  9. package/dist/Chip.js +1 -1
  10. package/dist/ChipGroup.js +1 -1
  11. package/dist/ChipLink.js +1 -1
  12. package/dist/ChipRemovable.js +1 -1
  13. package/dist/ChipSelectable.js +1 -1
  14. package/dist/Dialog.js +1 -1
  15. package/dist/Dropdown.js +1 -1
  16. package/dist/FileInput.d.ts +59 -0
  17. package/dist/FileInput.js +383 -0
  18. package/dist/Icon.js +1 -1
  19. package/dist/Input.d.ts +0 -9
  20. package/dist/Input.js +4 -25
  21. package/dist/{LeuElement-DlQXnrk8.js → LeuElement-CKq5epyY.js} +1 -1
  22. package/dist/Menu.js +1 -1
  23. package/dist/MenuItem.js +1 -1
  24. package/dist/Message.js +1 -1
  25. package/dist/Pagination.js +1 -1
  26. package/dist/Placeholder.js +1 -1
  27. package/dist/Popup.js +1 -1
  28. package/dist/ProgressBar.d.ts +29 -0
  29. package/dist/ProgressBar.js +166 -0
  30. package/dist/Radio.js +1 -1
  31. package/dist/RadioGroup.js +1 -1
  32. package/dist/Range.js +1 -1
  33. package/dist/ScrollTop.js +1 -1
  34. package/dist/Select.js +1 -1
  35. package/dist/Spinner.js +1 -1
  36. package/dist/Table.js +1 -1
  37. package/dist/Tag.js +1 -1
  38. package/dist/VisuallyHidden.js +1 -1
  39. package/dist/components/file-input/FileInput.d.ts +54 -0
  40. package/dist/components/file-input/FileInput.d.ts.map +1 -0
  41. package/dist/components/file-input/leu-file-input.d.ts +3 -0
  42. package/dist/components/file-input/leu-file-input.d.ts.map +1 -0
  43. package/dist/components/file-input/stories/file-input.stories.d.ts +30 -0
  44. package/dist/components/file-input/stories/file-input.stories.d.ts.map +1 -0
  45. package/dist/components/file-input/test/file-input.test.d.ts +2 -0
  46. package/dist/components/file-input/test/file-input.test.d.ts.map +1 -0
  47. package/dist/components/input/Input.d.ts +0 -9
  48. package/dist/components/input/Input.d.ts.map +1 -1
  49. package/dist/components/progress-bar/ProgressBar.d.ts +25 -0
  50. package/dist/components/progress-bar/ProgressBar.d.ts.map +1 -0
  51. package/dist/components/progress-bar/leu-progress-bar.d.ts +3 -0
  52. package/dist/components/progress-bar/leu-progress-bar.d.ts.map +1 -0
  53. package/dist/components/progress-bar/stories/progress-bar.stories.d.ts +48 -0
  54. package/dist/components/progress-bar/stories/progress-bar.stories.d.ts.map +1 -0
  55. package/dist/components/progress-bar/test/progress-bar.test.d.ts +2 -0
  56. package/dist/components/progress-bar/test/progress-bar.test.d.ts.map +1 -0
  57. package/dist/index.js +1 -1
  58. package/dist/leu-accordion.js +1 -1
  59. package/dist/leu-button-group.js +1 -1
  60. package/dist/leu-button.js +1 -1
  61. package/dist/leu-chart-wrapper.js +1 -1
  62. package/dist/leu-checkbox-group.js +1 -1
  63. package/dist/leu-checkbox.js +1 -1
  64. package/dist/leu-chip-group.js +1 -1
  65. package/dist/leu-chip-link.js +1 -1
  66. package/dist/leu-chip-removable.js +1 -1
  67. package/dist/leu-chip-selectable.js +1 -1
  68. package/dist/leu-dialog.js +1 -1
  69. package/dist/leu-dropdown.js +1 -1
  70. package/dist/leu-file-input.d.ts +8 -0
  71. package/dist/leu-file-input.js +42 -0
  72. package/dist/leu-icon.js +1 -1
  73. package/dist/leu-input.js +1 -1
  74. package/dist/leu-menu-item.js +1 -1
  75. package/dist/leu-menu.js +1 -1
  76. package/dist/leu-message.js +1 -1
  77. package/dist/leu-pagination.js +1 -1
  78. package/dist/leu-placeholder.js +1 -1
  79. package/dist/leu-popup.js +1 -1
  80. package/dist/leu-progress-bar.d.ts +4 -0
  81. package/dist/leu-progress-bar.js +10 -0
  82. package/dist/leu-radio-group.js +1 -1
  83. package/dist/leu-radio.js +1 -1
  84. package/dist/leu-range.js +1 -1
  85. package/dist/leu-scroll-top.js +1 -1
  86. package/dist/leu-select.js +1 -1
  87. package/dist/leu-spinner.js +1 -1
  88. package/dist/leu-table.js +1 -1
  89. package/dist/leu-tag.js +1 -1
  90. package/dist/leu-visually-hidden.js +1 -1
  91. package/dist/vscode.html-custom-data.json +65 -0
  92. package/dist/vue/index.d.ts +48 -0
  93. package/dist/web-types.json +119 -1
  94. package/package.json +1 -1
  95. package/scripts/generate-component/templates/test/[name].test.ts +4 -3
  96. package/src/components/file-input/FileInput.ts +266 -0
  97. package/src/components/file-input/file-input.css +118 -0
  98. package/src/components/file-input/leu-file-input.ts +5 -0
  99. package/src/components/file-input/stories/file-input.stories.ts +38 -0
  100. package/src/components/file-input/test/file-input.test.ts +25 -0
  101. package/src/components/input/Input.ts +3 -29
  102. package/src/components/progress-bar/ProgressBar.ts +52 -0
  103. package/src/components/progress-bar/leu-progress-bar.ts +5 -0
  104. package/src/components/progress-bar/progress-bar.css +97 -0
  105. package/src/components/progress-bar/stories/progress-bar.stories.ts +39 -0
  106. package/src/components/progress-bar/test/progress-bar.test.ts +61 -0
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "0.18.0"
2
+ ".": "0.19.0"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.19.0](https://github.com/statistikZH/leu/compare/leu-v0.18.1...leu-v0.19.0) (2025-10-15)
4
+
5
+
6
+ ### Features
7
+
8
+ * **file-input:** add a file input component ([562a6e6](https://github.com/statistikZH/leu/commit/562a6e66d8bde9b321430367520ab64d4d3a588d))
9
+ * **progress-bar:** implement leu-progress-bar component ([#305](https://github.com/statistikZH/leu/issues/305)) ([1609272](https://github.com/statistikZH/leu/commit/160927230963682a54605acd3bde12ea9e916351))
10
+
11
+ ## [0.18.1](https://github.com/statistikZH/leu/compare/leu-v0.18.0...leu-v0.18.1) (2025-09-11)
12
+
13
+
14
+ ### Miscellaneous Chores
15
+
16
+ * release 0.18.1 ([e857924](https://github.com/statistikZH/leu/commit/e8579242a7c6e87dae7b9228baba6bd3ef62cf5d))
17
+
3
18
  ## [0.18.0](https://github.com/statistikZH/leu/compare/leu-v0.17.0...leu-v0.18.0) (2025-09-10)
4
19
 
5
20
 
package/dist/Accordion.js CHANGED
@@ -2,7 +2,7 @@ import { _ as __decorate } from './_tslib-CNEFicEt.js';
2
2
  import { css, nothing } from 'lit';
3
3
  import { unsafeStatic, html } from 'lit/static-html.js';
4
4
  import { property } from 'lit/decorators.js';
5
- import { L as LeuElement } from './LeuElement-DlQXnrk8.js';
5
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
6
6
 
7
7
  var css_248z = css`:host {
8
8
  --accordion-font-regular: var(--leu-font-family-regular);
package/dist/Button.js CHANGED
@@ -4,7 +4,7 @@ import { classMap } from 'lit/directives/class-map.js';
4
4
  import { ifDefined } from 'lit/directives/if-defined.js';
5
5
  import { property } from 'lit/decorators.js';
6
6
  import { LeuIcon } from './Icon.js';
7
- import { L as LeuElement } from './LeuElement-DlQXnrk8.js';
7
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
8
8
  import { H as HasSlotController } from './hasSlotController-Bm2tipvG.js';
9
9
 
10
10
  /**
@@ -1,5 +1,5 @@
1
1
  import { css, html } from 'lit';
2
- import { L as LeuElement } from './LeuElement-DlQXnrk8.js';
2
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
3
3
  import { LeuButton } from './Button.js';
4
4
  import './_tslib-CNEFicEt.js';
5
5
  import 'lit/directives/class-map.js';
@@ -1,7 +1,7 @@
1
1
  import { _ as __decorate } from './_tslib-CNEFicEt.js';
2
2
  import { css, nothing, html } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
- import { L as LeuElement } from './LeuElement-DlQXnrk8.js';
4
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
5
5
  import { H as HasSlotController } from './hasSlotController-Bm2tipvG.js';
6
6
  import { LeuSpinner } from './Spinner.js';
7
7
 
package/dist/Checkbox.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { _ as __decorate } from './_tslib-CNEFicEt.js';
2
2
  import { css, html } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
- import { L as LeuElement } from './LeuElement-DlQXnrk8.js';
4
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
5
5
  import { LeuIcon } from './Icon.js';
6
6
 
7
7
  var css_248z = css`:host {
@@ -2,7 +2,7 @@ import { _ as __decorate } from './_tslib-CNEFicEt.js';
2
2
  import { css, html } from 'lit';
3
3
  import { classMap } from 'lit/directives/class-map.js';
4
4
  import { property } from 'lit/decorators.js';
5
- import { L as LeuElement } from './LeuElement-DlQXnrk8.js';
5
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
6
6
  import { LeuCheckbox } from './Checkbox.js';
7
7
  import './Icon.js';
8
8
 
package/dist/Chip.js CHANGED
@@ -1,4 +1,4 @@
1
- import { L as LeuElement } from './LeuElement-DlQXnrk8.js';
1
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
2
2
  import { css } from 'lit';
3
3
 
4
4
  var css_248z = css`:host *::before,
package/dist/ChipGroup.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { unsafeStatic, html } from 'lit/static-html.js';
2
- import { L as LeuElement } from './LeuElement-DlQXnrk8.js';
2
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
3
3
  import { css } from 'lit';
4
4
 
5
5
  var css_248z = css`.label {
package/dist/ChipLink.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { html } from 'lit';
2
2
  import { LeuChipBase } from './Chip.js';
3
- import './LeuElement-DlQXnrk8.js';
3
+ import './LeuElement-CKq5epyY.js';
4
4
 
5
5
  const SIZES = {
6
6
  regular: "regular",
@@ -1,7 +1,7 @@
1
1
  import { html } from 'lit';
2
2
  import { LeuChipBase } from './Chip.js';
3
3
  import { LeuIcon } from './Icon.js';
4
- import './LeuElement-DlQXnrk8.js';
4
+ import './LeuElement-CKq5epyY.js';
5
5
  import './_tslib-CNEFicEt.js';
6
6
  import 'lit/decorators.js';
7
7
 
@@ -1,6 +1,6 @@
1
1
  import { html } from 'lit';
2
2
  import { LeuChipBase } from './Chip.js';
3
- import './LeuElement-DlQXnrk8.js';
3
+ import './LeuElement-CKq5epyY.js';
4
4
 
5
5
  const SIZES = {
6
6
  small: "small",
package/dist/Dialog.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { css, nothing, html } from 'lit';
2
2
  import { createRef, ref } from 'lit/directives/ref.js';
3
3
  import { classMap } from 'lit/directives/class-map.js';
4
- import { L as LeuElement } from './LeuElement-DlQXnrk8.js';
4
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
5
5
  import { H as HasSlotController } from './hasSlotController-Bm2tipvG.js';
6
6
  import { LeuIcon } from './Icon.js';
7
7
  import './_tslib-CNEFicEt.js';
package/dist/Dropdown.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { css, nothing, html } from 'lit';
2
2
  import { createRef, ref } from 'lit/directives/ref.js';
3
- import { L as LeuElement } from './LeuElement-DlQXnrk8.js';
3
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
4
4
  import { H as HasSlotController } from './hasSlotController-Bm2tipvG.js';
5
5
  import { LeuButton } from './Button.js';
6
6
  import { LeuMenu } from './Menu.js';
@@ -0,0 +1,59 @@
1
+ import * as lit_html from 'lit-html';
2
+ import * as lit from 'lit';
3
+ import { L as LeuElement } from './LeuElement.d-BevHqLUu.js';
4
+ import { LeuButton } from './Button.js';
5
+ import { LeuIcon } from './Icon.js';
6
+ import { LeuVisuallyHidden } from './VisuallyHidden.js';
7
+ import './leu-icon.js';
8
+
9
+ /**
10
+ * @tagname leu-file-input
11
+ */
12
+ declare class LeuFileInput extends LeuElement {
13
+ static dependencies: {
14
+ "leu-icon": typeof LeuIcon;
15
+ "leu-button": typeof LeuButton;
16
+ "leu-visually-hidden": typeof LeuVisuallyHidden;
17
+ };
18
+ static styles: lit.CSSResultGroup[];
19
+ static shadowRootOptions: {
20
+ delegatesFocus: boolean;
21
+ mode: ShadowRootMode;
22
+ serializable?: boolean;
23
+ slotAssignment?: SlotAssignmentMode;
24
+ customElements?: CustomElementRegistry;
25
+ registry?: CustomElementRegistry;
26
+ };
27
+ static formAssociated: boolean;
28
+ protected internals: ElementInternals;
29
+ label: string;
30
+ /** A list of acceptable file types. Must be a comma-separated list of [unique file type specifiers](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers). */
31
+ accept: string;
32
+ /** Whether the file input is disabled. */
33
+ disabled: boolean;
34
+ /** Whether the file input allows multiple files. */
35
+ multiple: boolean;
36
+ /** Whether the file input is required. */
37
+ required: boolean;
38
+ /** The variant of the file list item. `filled` renders a gray background. */
39
+ variant: "filled" | "transparent";
40
+ files: File[];
41
+ private isDragging;
42
+ input: HTMLInputElement;
43
+ constructor();
44
+ get form(): HTMLFormElement;
45
+ get name(): string;
46
+ updated(changedProperties: any): void;
47
+ protected handleInput(): void;
48
+ protected updateFormValue(): void;
49
+ protected removeFile(fileToRemove: File): void;
50
+ protected static formatFileSize(size: number): lit_html.TemplateResult<1>;
51
+ protected handleDragEnter: (event: DragEvent) => void;
52
+ protected handleDragOver: (event: DragEvent) => void;
53
+ protected handleDragLeave: (event: DragEvent) => void;
54
+ protected handleDrop: (event: DragEvent) => void;
55
+ isAcceptedFile(file: File): boolean;
56
+ render(): lit_html.TemplateResult<1>;
57
+ }
58
+
59
+ export { LeuFileInput };
@@ -0,0 +1,383 @@
1
+ import { _ as __decorate } from './_tslib-CNEFicEt.js';
2
+ import { css, html, nothing } from 'lit';
3
+ import { property, state, query } from 'lit/decorators.js';
4
+ import { ifDefined } from 'lit/directives/if-defined.js';
5
+ import { classMap } from 'lit/directives/class-map.js';
6
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
7
+ import './Accordion.js';
8
+ import { LeuButton } from './Button.js';
9
+ import './ButtonGroup.js';
10
+ import './ChartWrapper.js';
11
+ import './Checkbox.js';
12
+ import './CheckboxGroup.js';
13
+ import './ChipGroup.js';
14
+ import './ChipLink.js';
15
+ import './ChipRemovable.js';
16
+ import './ChipSelectable.js';
17
+ import './Dropdown.js';
18
+ import './Input.js';
19
+ import './Menu.js';
20
+ import './MenuItem.js';
21
+ import './Pagination.js';
22
+ import './Popup.js';
23
+ import './Radio.js';
24
+ import './RadioGroup.js';
25
+ import './Select.js';
26
+ import './Table.js';
27
+ import './leu-icon.js';
28
+ import { LeuVisuallyHidden } from './VisuallyHidden.js';
29
+ import { LeuIcon } from './Icon.js';
30
+ import 'lit/static-html.js';
31
+ import './hasSlotController-Bm2tipvG.js';
32
+ import './Spinner.js';
33
+ import './Chip.js';
34
+ import 'lit/directives/ref.js';
35
+ import '@floating-ui/dom';
36
+ import 'lit/directives/live.js';
37
+ import 'lit/directives/style-map.js';
38
+
39
+ var css_248z = css`:host {
40
+ --file-input-font-regular: var(--leu-font-family-regular);
41
+ --file-input-font-black: var(--leu-font-family-black);
42
+
43
+ font-family: var(--file-input-font-regular);
44
+ }
45
+ .label {
46
+ display: block;
47
+ margin-bottom: 0.5rem;
48
+ font: var(--leu-t-curve-regular-black-font);
49
+ }
50
+ :host([required]) .label::after {
51
+ content: "*";
52
+ }
53
+ .dropzone {
54
+ display: flex;
55
+ flex-direction: column;
56
+ align-items: center;
57
+ text-align: center;
58
+
59
+ border: 2px dashed var(--leu-color-black-20);
60
+ border-radius: 0.25rem;
61
+
62
+ padding: 2rem 1.5rem;
63
+ }
64
+ @media (min-width: 600px) {
65
+ .dropzone {
66
+ padding: 2.5rem 2rem;
67
+ }
68
+ }
69
+ @media (min-width: 1280px) {
70
+ .dropzone {
71
+ padding: 3.5rem 2.5rem;
72
+ }
73
+ }
74
+ .dropzone--dragging {
75
+ border-color: var(--leu-color-black-60);
76
+ background-color: var(--leu-color-black-transp-5);
77
+ cursor: copy;
78
+ }
79
+ .dropzone__text {
80
+ font: var(--leu-t-curve-small-regular-font);
81
+ color: var(--leu-color-black-60);
82
+
83
+ margin-bottom: 0.75rem;
84
+ }
85
+ @media (min-width: 400px) {
86
+ .dropzone__text {
87
+ margin-bottom: 2rem;
88
+ }
89
+ }
90
+ @media (min-width: 600px) {
91
+ .dropzone__text {
92
+ margin-bottom: 1.25rem;
93
+ }
94
+ }
95
+ @media (min-width: 1280px) {
96
+ .dropzone__text {
97
+ margin-bottom: 1.5rem;
98
+ }
99
+ }
100
+ .file-list {
101
+ list-style: none;
102
+ padding: 0;
103
+
104
+ display: flex;
105
+ flex-direction: column;
106
+ gap: 0.125rem;
107
+ }
108
+ .file {
109
+ display: grid;
110
+ grid-template-columns: minmax(0, 1fr) min-content;
111
+ grid-gap: 0.25rem 0.5rem;
112
+ gap: 0.25rem 0.5rem;
113
+
114
+ align-items: start;
115
+
116
+ justify-items: start;
117
+
118
+ place-items: start;
119
+
120
+ background-color: var(--leu-color-black-10);
121
+ padding: 0.75rem 1.25rem;
122
+ }
123
+ @media (min-width: 600px) {
124
+ .file {
125
+ -moz-column-gap: 0.75rem;
126
+ column-gap: 0.75rem;
127
+ }
128
+ }
129
+ @media (min-width: 1024px) {
130
+ .file {
131
+ -moz-column-gap: 1rem;
132
+ column-gap: 1rem;
133
+ padding: 1.5rem 1rem;
134
+ }
135
+ }
136
+ .file__name {
137
+ grid-column: 1 / 2;
138
+ font: var(--leu-t-regular-black-font);
139
+ text-overflow: ellipsis;
140
+ overflow: hidden;
141
+ max-width: 100%;
142
+ }
143
+ .file__size {
144
+ grid-column: 1 / 2;
145
+ display: flex;
146
+ gap: 0.25rem;
147
+ margin: 0;
148
+ font: var(--leu-t-tiny-regular-font);
149
+ }
150
+ .file__size-label {
151
+ color: var(--leu-color-black-60);
152
+ }
153
+ .file__button {
154
+ grid-column: 2 / 3;
155
+ grid-row: 1 / 3;
156
+ align-self: center;
157
+ }
158
+ `;
159
+
160
+ /**
161
+ * @tagname leu-file-input
162
+ */
163
+ class LeuFileInput extends LeuElement {
164
+ constructor() {
165
+ super();
166
+ this.label = "";
167
+ /** A list of acceptable file types. Must be a comma-separated list of [unique file type specifiers](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers). */
168
+ this.accept = "";
169
+ /** Whether the file input is disabled. */
170
+ this.disabled = false;
171
+ /** Whether the file input allows multiple files. */
172
+ this.multiple = false;
173
+ /** Whether the file input is required. */
174
+ this.required = false;
175
+ /** The variant of the file list item. `filled` renders a gray background. */
176
+ this.variant = "filled";
177
+ this.files = [];
178
+ this.isDragging = false;
179
+ this.handleDragEnter = (event) => {
180
+ if (this.disabled)
181
+ return;
182
+ event.preventDefault();
183
+ event.stopPropagation();
184
+ this.isDragging = [...event.dataTransfer.items].some((item) => item.kind === "file");
185
+ };
186
+ // eslint-disable-next-line class-methods-use-this
187
+ this.handleDragOver = (event) => {
188
+ if (this.disabled)
189
+ return;
190
+ event.preventDefault();
191
+ event.stopPropagation();
192
+ };
193
+ this.handleDragLeave = (event) => {
194
+ if (this.disabled)
195
+ return;
196
+ event.preventDefault();
197
+ event.stopPropagation();
198
+ this.isDragging = false;
199
+ };
200
+ this.handleDrop = (event) => {
201
+ if (this.disabled)
202
+ return;
203
+ event.preventDefault();
204
+ event.stopPropagation();
205
+ const dt = event.dataTransfer;
206
+ const files = dt.files;
207
+ const acceptedFiles = [...files].filter((file) => this.isAcceptedFile(file));
208
+ this.files = this.multiple
209
+ ? this.files.concat(acceptedFiles)
210
+ : acceptedFiles.slice(0, 1);
211
+ this.isDragging = false;
212
+ };
213
+ // Initialize the ElementInternals for form association
214
+ this.internals = this.attachInternals();
215
+ }
216
+ get form() {
217
+ return this.internals.form;
218
+ }
219
+ get name() {
220
+ return this.getAttribute("name");
221
+ }
222
+ updated(changedProperties) {
223
+ if (changedProperties.has("files") ||
224
+ changedProperties.has("disabled") ||
225
+ changedProperties.has("multiple")) {
226
+ this.updateFormValue();
227
+ }
228
+ }
229
+ handleInput() {
230
+ // Append selected files
231
+ if (this.input.files) {
232
+ const acceptableFiles = [...this.input.files].filter((file) => this.isAcceptedFile(file));
233
+ this.files = this.multiple
234
+ ? this.files.concat(acceptableFiles)
235
+ : acceptableFiles.slice(0, 1);
236
+ }
237
+ }
238
+ updateFormValue() {
239
+ const formData = new FormData();
240
+ const files = this.multiple ? this.files : this.files.slice(0, 1);
241
+ files.forEach((file) => {
242
+ formData.append(this.name, file);
243
+ });
244
+ this.internals.setFormValue(formData);
245
+ }
246
+ removeFile(fileToRemove) {
247
+ this.files = this.files.filter((file) => file !== fileToRemove);
248
+ }
249
+ static formatFileSize(size) {
250
+ if (size < 1e3) {
251
+ return html `${size}&nbsp;bytes`;
252
+ }
253
+ if (size >= 1e3 && size < 1e6) {
254
+ return html `${(size / 1e3).toFixed(1)}&nbsp;KB`;
255
+ }
256
+ return html `${(size / 1e6).toFixed(1)}&nbsp;MB`;
257
+ }
258
+ isAcceptedFile(file) {
259
+ const acceptedTypes = this.accept.split(",").map((type) => type.trim());
260
+ const mimeType = file.type;
261
+ for (const acceptedType of acceptedTypes) {
262
+ // Handle file extensions (e.g. .jpg, .png)
263
+ if (acceptedType.startsWith(".")) {
264
+ const name = file.name.toLowerCase();
265
+ const extension = acceptedType.toLowerCase();
266
+ if (name.endsWith(extension)) {
267
+ return true;
268
+ }
269
+ // Handle wildcard types (e.g. image/*)
270
+ }
271
+ else if (/^\w+\/\*$/.test(acceptedType)) {
272
+ if (mimeType.split("/")[0] === acceptedType.split("/")[0]) {
273
+ return true;
274
+ }
275
+ }
276
+ if (mimeType === acceptedType) {
277
+ return true;
278
+ }
279
+ }
280
+ return false;
281
+ }
282
+ render() {
283
+ const dropzoneClasses = {
284
+ dropzone: true,
285
+ "dropzone--dragging": this.isDragging,
286
+ };
287
+ return html `
288
+ <div class="container">
289
+ <label class="label" for="input">${this.label}</label>
290
+ <leu-visually-hidden>
291
+ <input
292
+ id="input"
293
+ type="file"
294
+ ?multiple=${this.multiple}
295
+ accept=${ifDefined(this.accept)}
296
+ ?disabled=${this.disabled}
297
+ @input=${this.handleInput}
298
+ />
299
+ </leu-visually-hidden>
300
+ <div
301
+ class=${classMap(dropzoneClasses)}
302
+ @dragenter=${this.handleDragEnter}
303
+ @dragover=${this.handleDragOver}
304
+ @dragleave=${this.handleDragLeave}
305
+ @drop=${this.handleDrop}
306
+ >
307
+ <slot class="dropzone__text"
308
+ ><p>Zum Hochladen Dateien ziehen und hier ablegen.</p></slot
309
+ >
310
+ <leu-button
311
+ variant="secondary"
312
+ ?disabled=${this.disabled}
313
+ @click=${() => this.input.click()}
314
+ >
315
+ Datei auswählen
316
+ <leu-icon name="upload" slot="after"></leu-icon>
317
+ </leu-button>
318
+ </div>
319
+ ${this.files.length > 0
320
+ ? html `<ul class="file-list">
321
+ ${this.files.map((file) => html `<li class="file">
322
+ <strong class="file__name">${file.name}</strong>
323
+ <p class="file__size">
324
+ <span class="file__size-label">Grösse:</span>
325
+ ${LeuFileInput.formatFileSize(file.size)}
326
+ </p>
327
+ <leu-button
328
+ round
329
+ class="file__button"
330
+ label="Datei entfernen"
331
+ size="small"
332
+ variant="secondary"
333
+ ?disabled=${this.disabled}
334
+ @click=${() => this.removeFile(file)}
335
+ ><leu-icon name="delete"></leu-icon
336
+ ></leu-button>
337
+ </li>`)}
338
+ </ul>`
339
+ : nothing}
340
+ </div>
341
+ `;
342
+ }
343
+ }
344
+ LeuFileInput.dependencies = {
345
+ "leu-icon": LeuIcon,
346
+ "leu-button": LeuButton,
347
+ "leu-visually-hidden": LeuVisuallyHidden,
348
+ };
349
+ LeuFileInput.styles = [LeuElement.styles, css_248z];
350
+ LeuFileInput.shadowRootOptions = {
351
+ ...LeuElement.shadowRootOptions,
352
+ delegatesFocus: true,
353
+ };
354
+ LeuFileInput.formAssociated = true;
355
+ __decorate([
356
+ property({ type: String })
357
+ ], LeuFileInput.prototype, "label", void 0);
358
+ __decorate([
359
+ property({ type: String })
360
+ ], LeuFileInput.prototype, "accept", void 0);
361
+ __decorate([
362
+ property({ type: Boolean, reflect: true })
363
+ ], LeuFileInput.prototype, "disabled", void 0);
364
+ __decorate([
365
+ property({ type: Boolean, reflect: true })
366
+ ], LeuFileInput.prototype, "multiple", void 0);
367
+ __decorate([
368
+ property({ type: Boolean, reflect: true })
369
+ ], LeuFileInput.prototype, "required", void 0);
370
+ __decorate([
371
+ property({ type: String, reflect: true })
372
+ ], LeuFileInput.prototype, "variant", void 0);
373
+ __decorate([
374
+ state()
375
+ ], LeuFileInput.prototype, "files", void 0);
376
+ __decorate([
377
+ state()
378
+ ], LeuFileInput.prototype, "isDragging", void 0);
379
+ __decorate([
380
+ query('input[type="file"]')
381
+ ], LeuFileInput.prototype, "input", void 0);
382
+
383
+ export { LeuFileInput };
package/dist/Icon.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { _ as __decorate } from './_tslib-CNEFicEt.js';
2
2
  import { css, html, svg } from 'lit';
3
3
  import { property } from 'lit/decorators.js';
4
- import { L as LeuElement } from './LeuElement-DlQXnrk8.js';
4
+ import { L as LeuElement } from './LeuElement-CKq5epyY.js';
5
5
 
6
6
  var css_248z = css`:host {
7
7
  display: contents;
package/dist/Input.d.ts CHANGED
@@ -197,15 +197,6 @@ declare class LeuInput extends LeuElement {
197
197
  * @fires {CustomEvent} change
198
198
  */
199
199
  clear(): void;
200
- /**
201
- * Method for getting the id of the input element.
202
- * If the id attribute is set, the value of the id attribute is returned.
203
- * Otherwise a random id is generated and returned.
204
- *
205
- * @private
206
- * @returns {string} id
207
- */
208
- getId(): any;
209
200
  /**
210
201
  * Merge custom and default validation messages.
211
202
  * A validation message can be a function or a string.