@statistikzh/leu 0.18.1 → 0.19.1

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 (104) 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 +60 -0
  17. package/dist/FileInput.js +387 -0
  18. package/dist/Icon.js +1 -1
  19. package/dist/Input.js +1 -3
  20. package/dist/{LeuElement-DgiuzsX9.js → LeuElement-CRdVLttR.js} +1 -1
  21. package/dist/Menu.js +1 -1
  22. package/dist/MenuItem.js +1 -1
  23. package/dist/Message.js +1 -1
  24. package/dist/Pagination.js +1 -1
  25. package/dist/Placeholder.js +1 -1
  26. package/dist/Popup.js +1 -1
  27. package/dist/ProgressBar.d.ts +29 -0
  28. package/dist/ProgressBar.js +166 -0
  29. package/dist/Radio.js +1 -1
  30. package/dist/RadioGroup.js +1 -1
  31. package/dist/Range.js +1 -1
  32. package/dist/ScrollTop.js +1 -1
  33. package/dist/Select.js +1 -1
  34. package/dist/Spinner.js +1 -1
  35. package/dist/Table.js +1 -1
  36. package/dist/Tag.js +1 -1
  37. package/dist/VisuallyHidden.js +1 -1
  38. package/dist/components/file-input/FileInput.d.ts +55 -0
  39. package/dist/components/file-input/FileInput.d.ts.map +1 -0
  40. package/dist/components/file-input/leu-file-input.d.ts +3 -0
  41. package/dist/components/file-input/leu-file-input.d.ts.map +1 -0
  42. package/dist/components/file-input/stories/file-input.stories.d.ts +30 -0
  43. package/dist/components/file-input/stories/file-input.stories.d.ts.map +1 -0
  44. package/dist/components/file-input/test/file-input.test.d.ts +2 -0
  45. package/dist/components/file-input/test/file-input.test.d.ts.map +1 -0
  46. package/dist/components/input/Input.d.ts.map +1 -1
  47. package/dist/components/progress-bar/ProgressBar.d.ts +25 -0
  48. package/dist/components/progress-bar/ProgressBar.d.ts.map +1 -0
  49. package/dist/components/progress-bar/leu-progress-bar.d.ts +3 -0
  50. package/dist/components/progress-bar/leu-progress-bar.d.ts.map +1 -0
  51. package/dist/components/progress-bar/stories/progress-bar.stories.d.ts +48 -0
  52. package/dist/components/progress-bar/stories/progress-bar.stories.d.ts.map +1 -0
  53. package/dist/components/progress-bar/test/progress-bar.test.d.ts +2 -0
  54. package/dist/components/progress-bar/test/progress-bar.test.d.ts.map +1 -0
  55. package/dist/index.js +1 -1
  56. package/dist/leu-accordion.js +1 -1
  57. package/dist/leu-button-group.js +1 -1
  58. package/dist/leu-button.js +1 -1
  59. package/dist/leu-chart-wrapper.js +1 -1
  60. package/dist/leu-checkbox-group.js +1 -1
  61. package/dist/leu-checkbox.js +1 -1
  62. package/dist/leu-chip-group.js +1 -1
  63. package/dist/leu-chip-link.js +1 -1
  64. package/dist/leu-chip-removable.js +1 -1
  65. package/dist/leu-chip-selectable.js +1 -1
  66. package/dist/leu-dialog.js +1 -1
  67. package/dist/leu-dropdown.js +1 -1
  68. package/dist/leu-file-input.d.ts +8 -0
  69. package/dist/leu-file-input.js +42 -0
  70. package/dist/leu-icon.js +1 -1
  71. package/dist/leu-input.js +1 -1
  72. package/dist/leu-menu-item.js +1 -1
  73. package/dist/leu-menu.js +1 -1
  74. package/dist/leu-message.js +1 -1
  75. package/dist/leu-pagination.js +1 -1
  76. package/dist/leu-placeholder.js +1 -1
  77. package/dist/leu-popup.js +1 -1
  78. package/dist/leu-progress-bar.d.ts +4 -0
  79. package/dist/leu-progress-bar.js +10 -0
  80. package/dist/leu-radio-group.js +1 -1
  81. package/dist/leu-radio.js +1 -1
  82. package/dist/leu-range.js +1 -1
  83. package/dist/leu-scroll-top.js +1 -1
  84. package/dist/leu-select.js +1 -1
  85. package/dist/leu-spinner.js +1 -1
  86. package/dist/leu-table.js +1 -1
  87. package/dist/leu-tag.js +1 -1
  88. package/dist/leu-visually-hidden.js +1 -1
  89. package/dist/vscode.html-custom-data.json +65 -0
  90. package/dist/vue/index.d.ts +48 -0
  91. package/dist/web-types.json +119 -1
  92. package/package.json +1 -1
  93. package/scripts/generate-component/templates/test/[name].test.ts +4 -3
  94. package/src/components/file-input/FileInput.ts +271 -0
  95. package/src/components/file-input/file-input.css +118 -0
  96. package/src/components/file-input/leu-file-input.ts +5 -0
  97. package/src/components/file-input/stories/file-input.stories.ts +38 -0
  98. package/src/components/file-input/test/file-input.test.ts +25 -0
  99. package/src/components/input/Input.ts +0 -3
  100. package/src/components/progress-bar/ProgressBar.ts +52 -0
  101. package/src/components/progress-bar/leu-progress-bar.ts +5 -0
  102. package/src/components/progress-bar/progress-bar.css +97 -0
  103. package/src/components/progress-bar/stories/progress-bar.stories.ts +39 -0
  104. package/src/components/progress-bar/test/progress-bar.test.ts +61 -0
@@ -0,0 +1,271 @@
1
+ import { html, nothing } from "lit"
2
+ import { property, query, state } from "lit/decorators.js"
3
+ import { ifDefined } from "lit/directives/if-defined.js"
4
+ import { classMap } from "lit/directives/class-map.js"
5
+
6
+ import { LeuElement } from "../../lib/LeuElement.js"
7
+
8
+ import styles from "./file-input.css"
9
+ import { LeuButton } from "../../index.js"
10
+ import { LeuIcon } from "../icon/leu-icon.js"
11
+ import { LeuVisuallyHidden } from "../visually-hidden/VisuallyHidden.js"
12
+
13
+ /**
14
+ * @tagname leu-file-input
15
+ */
16
+ export class LeuFileInput extends LeuElement {
17
+ static dependencies = {
18
+ "leu-icon": LeuIcon,
19
+ "leu-button": LeuButton,
20
+ "leu-visually-hidden": LeuVisuallyHidden,
21
+ }
22
+
23
+ static styles = [LeuElement.styles, styles]
24
+
25
+ static shadowRootOptions = {
26
+ ...LeuElement.shadowRootOptions,
27
+ delegatesFocus: true,
28
+ }
29
+
30
+ static formAssociated = true
31
+
32
+ protected internals: ElementInternals
33
+
34
+ @property({ type: String })
35
+ label: string = ""
36
+
37
+ /** 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). */
38
+ @property({ type: String })
39
+ accept: string = ""
40
+
41
+ /** Whether the file input is disabled. */
42
+ @property({ type: Boolean, reflect: true })
43
+ disabled: boolean = false
44
+
45
+ /** Whether the file input allows multiple files. */
46
+ @property({ type: Boolean, reflect: true })
47
+ multiple: boolean = false
48
+
49
+ /** Whether the file input is required. */
50
+ @property({ type: Boolean, reflect: true })
51
+ required: boolean = false
52
+
53
+ /** The variant of the file list item. `filled` renders a gray background. */
54
+ @property({ type: String, reflect: true })
55
+ variant: "filled" | "transparent" = "filled"
56
+
57
+ @state()
58
+ public files: File[] = []
59
+
60
+ @state()
61
+ private isDragging: boolean = false
62
+
63
+ @query('input[type="file"]')
64
+ input: HTMLInputElement
65
+
66
+ constructor() {
67
+ super()
68
+ // Initialize the ElementInternals for form association
69
+ this.internals = this.attachInternals()
70
+ }
71
+
72
+ get form() {
73
+ return this.internals.form
74
+ }
75
+
76
+ get name() {
77
+ return this.getAttribute("name")
78
+ }
79
+
80
+ updated(changedProperties) {
81
+ if (
82
+ changedProperties.has("files") ||
83
+ changedProperties.has("disabled") ||
84
+ changedProperties.has("multiple")
85
+ ) {
86
+ this.updateFormValue()
87
+ }
88
+ }
89
+
90
+ protected handleInput() {
91
+ // Append selected files
92
+ if (this.input.files) {
93
+ const acceptableFiles = [...this.input.files].filter((file) =>
94
+ this.isAcceptedFile(file),
95
+ )
96
+
97
+ this.files = this.multiple
98
+ ? this.files.concat(acceptableFiles)
99
+ : acceptableFiles.slice(0, 1)
100
+ }
101
+ }
102
+
103
+ public formResetCallback() {
104
+ this.files = []
105
+ this.input.value = ""
106
+ }
107
+
108
+ protected updateFormValue() {
109
+ const formData = new FormData()
110
+
111
+ const files = this.multiple ? this.files : this.files.slice(0, 1)
112
+
113
+ files.forEach((file) => {
114
+ formData.append(this.name, file)
115
+ })
116
+
117
+ this.internals.setFormValue(formData)
118
+ }
119
+
120
+ protected removeFile(fileToRemove: File) {
121
+ this.files = this.files.filter((file) => file !== fileToRemove)
122
+ }
123
+
124
+ protected static formatFileSize(size: number) {
125
+ if (size < 1e3) {
126
+ return html`${size}&nbsp;bytes`
127
+ }
128
+
129
+ if (size >= 1e3 && size < 1e6) {
130
+ return html`${(size / 1e3).toFixed(1)}&nbsp;KB`
131
+ }
132
+
133
+ return html`${(size / 1e6).toFixed(1)}&nbsp;MB`
134
+ }
135
+
136
+ protected handleDragEnter = (event: DragEvent) => {
137
+ if (this.disabled) return
138
+
139
+ event.preventDefault()
140
+ event.stopPropagation()
141
+ this.isDragging = [...event.dataTransfer.items].some(
142
+ (item) => item.kind === "file",
143
+ )
144
+ }
145
+
146
+ // eslint-disable-next-line class-methods-use-this
147
+ protected handleDragOver = (event: DragEvent) => {
148
+ if (this.disabled) return
149
+
150
+ event.preventDefault()
151
+ event.stopPropagation()
152
+ }
153
+
154
+ protected handleDragLeave = (event: DragEvent) => {
155
+ if (this.disabled) return
156
+
157
+ event.preventDefault()
158
+ event.stopPropagation()
159
+ this.isDragging = false
160
+ }
161
+
162
+ protected handleDrop = (event: DragEvent) => {
163
+ if (this.disabled) return
164
+
165
+ event.preventDefault()
166
+ event.stopPropagation()
167
+
168
+ const dt = event.dataTransfer
169
+ const files = dt.files
170
+ const acceptedFiles = [...files].filter((file) => this.isAcceptedFile(file))
171
+
172
+ this.files = this.multiple
173
+ ? this.files.concat(acceptedFiles)
174
+ : acceptedFiles.slice(0, 1)
175
+ this.isDragging = false
176
+ }
177
+
178
+ isAcceptedFile(file: File): boolean {
179
+ const acceptedTypes = this.accept.split(",").map((type) => type.trim())
180
+ const mimeType = file.type
181
+
182
+ for (const acceptedType of acceptedTypes) {
183
+ // Handle file extensions (e.g. .jpg, .png)
184
+ if (acceptedType.startsWith(".")) {
185
+ const name = file.name.toLowerCase()
186
+ const extension = acceptedType.toLowerCase()
187
+
188
+ if (name.endsWith(extension)) {
189
+ return true
190
+ }
191
+ // Handle wildcard types (e.g. image/*)
192
+ } else if (/^\w+\/\*$/.test(acceptedType)) {
193
+ if (mimeType.split("/")[0] === acceptedType.split("/")[0]) {
194
+ return true
195
+ }
196
+ }
197
+
198
+ if (mimeType === acceptedType) {
199
+ return true
200
+ }
201
+ }
202
+
203
+ return false
204
+ }
205
+
206
+ render() {
207
+ const dropzoneClasses = {
208
+ dropzone: true,
209
+ "dropzone--dragging": this.isDragging,
210
+ }
211
+
212
+ return html`
213
+ <div class="container">
214
+ <label class="label" for="input">${this.label}</label>
215
+ <leu-visually-hidden>
216
+ <input
217
+ id="input"
218
+ type="file"
219
+ ?multiple=${this.multiple}
220
+ accept=${ifDefined(this.accept)}
221
+ ?disabled=${this.disabled}
222
+ @input=${this.handleInput}
223
+ />
224
+ </leu-visually-hidden>
225
+ <div
226
+ class=${classMap(dropzoneClasses)}
227
+ @dragenter=${this.handleDragEnter}
228
+ @dragover=${this.handleDragOver}
229
+ @dragleave=${this.handleDragLeave}
230
+ @drop=${this.handleDrop}
231
+ >
232
+ <slot class="dropzone__text"
233
+ ><p>Zum Hochladen Dateien ziehen und hier ablegen.</p></slot
234
+ >
235
+ <leu-button
236
+ variant="secondary"
237
+ ?disabled=${this.disabled}
238
+ @click=${() => this.input.click()}
239
+ >
240
+ Datei auswählen
241
+ <leu-icon name="upload" slot="after"></leu-icon>
242
+ </leu-button>
243
+ </div>
244
+ ${this.files.length > 0
245
+ ? html`<ul class="file-list">
246
+ ${this.files.map(
247
+ (file) =>
248
+ html`<li class="file">
249
+ <strong class="file__name">${file.name}</strong>
250
+ <p class="file__size">
251
+ <span class="file__size-label">Grösse:</span>
252
+ ${LeuFileInput.formatFileSize(file.size)}
253
+ </p>
254
+ <leu-button
255
+ round
256
+ class="file__button"
257
+ label="Datei entfernen"
258
+ size="small"
259
+ variant="secondary"
260
+ ?disabled=${this.disabled}
261
+ @click=${() => this.removeFile(file)}
262
+ ><leu-icon name="delete"></leu-icon
263
+ ></leu-button>
264
+ </li>`,
265
+ )}
266
+ </ul>`
267
+ : nothing}
268
+ </div>
269
+ `
270
+ }
271
+ }
@@ -0,0 +1,118 @@
1
+ @import url("../../styles/custom-media.css");
2
+
3
+ :host {
4
+ --file-input-font-regular: var(--leu-font-family-regular);
5
+ --file-input-font-black: var(--leu-font-family-black);
6
+
7
+ font-family: var(--file-input-font-regular);
8
+ }
9
+
10
+ .label {
11
+ display: block;
12
+ margin-bottom: 0.5rem;
13
+ font: var(--leu-t-curve-regular-black-font);
14
+ }
15
+
16
+ :host([required]) .label::after {
17
+ content: "*";
18
+ }
19
+
20
+ .dropzone {
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ text-align: center;
25
+
26
+ border: 2px dashed var(--leu-color-black-20);
27
+ border-radius: 0.25rem;
28
+
29
+ padding: 2rem 1.5rem;
30
+
31
+ @media (--viewport-regular) {
32
+ padding: 2.5rem 2rem;
33
+ }
34
+
35
+ @media (--viewport-xlarge) {
36
+ padding: 3.5rem 2.5rem;
37
+ }
38
+ }
39
+
40
+ .dropzone--dragging {
41
+ border-color: var(--leu-color-black-60);
42
+ background-color: var(--leu-color-black-transp-5);
43
+ cursor: copy;
44
+ }
45
+
46
+ .dropzone__text {
47
+ font: var(--leu-t-curve-small-regular-font);
48
+ color: var(--leu-color-black-60);
49
+
50
+ margin-bottom: 0.75rem;
51
+
52
+ @media (--viewport-small) {
53
+ margin-bottom: 2rem;
54
+ }
55
+
56
+ @media (--viewport-regular) {
57
+ margin-bottom: 1.25rem;
58
+ }
59
+
60
+ @media (--viewport-xlarge) {
61
+ margin-bottom: 1.5rem;
62
+ }
63
+ }
64
+
65
+ .file-list {
66
+ list-style: none;
67
+ padding: 0;
68
+
69
+ display: flex;
70
+ flex-direction: column;
71
+ gap: 0.125rem;
72
+ }
73
+
74
+ .file {
75
+ display: grid;
76
+ grid-template-columns: minmax(0, 1fr) min-content;
77
+ gap: 0.25rem 0.5rem;
78
+
79
+ place-items: start;
80
+
81
+ background-color: var(--leu-color-black-10);
82
+ padding: 0.75rem 1.25rem;
83
+
84
+ @media (--viewport-regular) {
85
+ column-gap: 0.75rem;
86
+ }
87
+
88
+ @media (--viewport-large) {
89
+ column-gap: 1rem;
90
+ padding: 1.5rem 1rem;
91
+ }
92
+ }
93
+
94
+ .file__name {
95
+ grid-column: 1 / 2;
96
+ font: var(--leu-t-regular-black-font);
97
+ text-overflow: ellipsis;
98
+ overflow: hidden;
99
+ max-width: 100%;
100
+ }
101
+
102
+ .file__size {
103
+ grid-column: 1 / 2;
104
+ display: flex;
105
+ gap: 0.25rem;
106
+ margin: 0;
107
+ font: var(--leu-t-tiny-regular-font);
108
+ }
109
+
110
+ .file__size-label {
111
+ color: var(--leu-color-black-60);
112
+ }
113
+
114
+ .file__button {
115
+ grid-column: 2 / 3;
116
+ grid-row: 1 / 3;
117
+ align-self: center;
118
+ }
@@ -0,0 +1,5 @@
1
+ import { LeuFileInput } from "./FileInput.js"
2
+
3
+ export { LeuFileInput }
4
+
5
+ LeuFileInput.define("leu-file-input")
@@ -0,0 +1,38 @@
1
+ import { Meta, StoryObj } from "@storybook/web-components"
2
+ import { html } from "lit"
3
+ import { ifDefined } from "lit/directives/if-defined.js"
4
+
5
+ import "../leu-file-input.js"
6
+ import { LeuFileInput } from "../FileInput.js"
7
+
8
+ type StoryArgs = LeuFileInput
9
+ type Story = StoryObj<StoryArgs>
10
+
11
+ export default {
12
+ title: "Components/FileInput",
13
+ component: "leu-file-input",
14
+ } satisfies Meta<StoryArgs>
15
+
16
+ const Template: Story = {
17
+ render: (args: StoryArgs) => html`
18
+ <leu-file-input
19
+ name="file"
20
+ label=${ifDefined(args.label)}
21
+ accept=${ifDefined(args.accept)}
22
+ ?disabled=${args.disabled}
23
+ ?multiple=${args.multiple}
24
+ ?required=${args.required}
25
+ ></leu-file-input>
26
+ `,
27
+ }
28
+
29
+ export const Regular = {
30
+ ...Template,
31
+ args: {
32
+ accept: "image/*",
33
+ disabled: false,
34
+ multiple: false,
35
+ label: "Dokumente hochladen",
36
+ // Add default args here
37
+ },
38
+ }
@@ -0,0 +1,25 @@
1
+ import { html } from "lit"
2
+ import { fixture, expect } from "@open-wc/testing"
3
+
4
+ import "../leu-file-input.js"
5
+ import { type LeuFileInput } from "../FileInput.js"
6
+
7
+ async function defaultFixture() {
8
+ return fixture<LeuFileInput>(
9
+ html`<leu-file-input label="File upload"></leu-file-input>`,
10
+ )
11
+ }
12
+
13
+ describe("LeuFileInput", () => {
14
+ it("is a defined element", async () => {
15
+ const el = customElements.get("leu-file-input")
16
+
17
+ expect(el).not.to.be.undefined
18
+ })
19
+
20
+ it("passes the a11y audit", async () => {
21
+ const el = await defaultFixture()
22
+
23
+ await expect(el).shadowDom.to.be.accessible()
24
+ })
25
+ })
@@ -132,9 +132,6 @@ export class LeuInput extends LeuElement {
132
132
  this.novalidate = false
133
133
  this.value = ""
134
134
 
135
- /** @internal */
136
- this._identifier = ""
137
-
138
135
  /**
139
136
  * @internal
140
137
  * @type {import("lit/directives/ref.js").Ref<HTMLInputElement>}
@@ -0,0 +1,52 @@
1
+ import { html, nothing } from "lit"
2
+ import { ifDefined } from "lit/directives/if-defined.js"
3
+ import { property } from "lit/decorators.js"
4
+
5
+ import { LeuElement } from "../../lib/LeuElement.js"
6
+
7
+ import styles from "./progress-bar.css"
8
+
9
+ /**
10
+ * An indicator showing the completion progress of a task
11
+ *
12
+ * @tagname leu-progress-bar
13
+ */
14
+ export class LeuProgressBar extends LeuElement {
15
+ static styles = [LeuElement.styles, styles]
16
+
17
+ static shadowRootOptions = {
18
+ ...LeuElement.shadowRootOptions,
19
+ delegatesFocus: true,
20
+ }
21
+
22
+ /** Progress as a percentage from 0 to 100 */
23
+ @property({ type: Number, reflect: true })
24
+ value: number = 0
25
+
26
+ /** Label that is displayed below the progress bar */
27
+ @property({ type: String, reflect: true })
28
+ label: string = ""
29
+
30
+ /** Whether the progress bar is in indeterminate state. */
31
+ @property({ type: Boolean, reflect: true })
32
+ indeterminate: boolean = false
33
+
34
+ render() {
35
+ return html`
36
+ <progress
37
+ class="progress"
38
+ max=${ifDefined(!this.indeterminate ? 100 : undefined)}
39
+ value=${ifDefined(!this.indeterminate ? this.value : undefined)}
40
+ id="progress"
41
+ ></progress>
42
+ <div class="info">
43
+ ${this.label
44
+ ? html`<label class="label" for="progress">${this.label}</label>`
45
+ : html`<div class="label label--placeholder"></div>`}
46
+ ${this.indeterminate
47
+ ? nothing
48
+ : html`<span class="value">${Math.round(this.value)}&#8239;%</span>`}
49
+ </div>
50
+ `
51
+ }
52
+ }
@@ -0,0 +1,5 @@
1
+ import { LeuProgressBar } from "./ProgressBar.js"
2
+
3
+ export { LeuProgressBar }
4
+
5
+ LeuProgressBar.define("leu-progress-bar")
@@ -0,0 +1,97 @@
1
+ /* :host {
2
+ --progress-bar-font-regular: var(--leu-font-family-regular);
3
+ --progress-bar-font-black: var(--leu-font-family-black);
4
+
5
+ font-family: var(--progress-bar-font-regular);
6
+ } */
7
+
8
+ .progress {
9
+ --_height: 0.5rem;
10
+ --_border-radius: 0.25rem;
11
+ --_progress-color: var(--leu-color-func-cyan);
12
+ --_indeterminate-animation: indeterminate 2s ease infinite;
13
+ --_indeterminate-width: 25%;
14
+
15
+ appearance: none;
16
+ display: block;
17
+ width: 100%;
18
+ height: var(--_height);
19
+
20
+ background-color: var(--leu-color-black-transp-10);
21
+ border: none;
22
+ border-radius: var(--_border-radius);
23
+ margin-bottom: 0.5rem;
24
+ }
25
+
26
+ .progress::-webkit-progress-bar {
27
+ background: transparent;
28
+ border-radius: var(--_border-radius);
29
+ }
30
+
31
+ /* Progress bar */
32
+ .progress::-moz-progress-bar {
33
+ background-color: var(--_progress-color);
34
+ border-radius: var(--_border-radius);
35
+ }
36
+
37
+ .progress::-webkit-progress-value {
38
+ background-color: var(--_progress-color);
39
+ border-radius: var(--_border-radius);
40
+ }
41
+
42
+ /* Indeterminate state */
43
+ .progress:indeterminate::-moz-progress-bar {
44
+ width: var(--_indeterminate-width);
45
+ animation: var(--_indeterminate-animation);
46
+ }
47
+
48
+ /* Safari */
49
+ .progress:indeterminate::-webkit-progress-value {
50
+ display: block;
51
+ width: var(--_indeterminate-width);
52
+ animation: var(--_indeterminate-animation);
53
+ }
54
+
55
+ /* Chrome */
56
+ .progress:indeterminate::before {
57
+ content: "";
58
+ display: block;
59
+ width: var(--_indeterminate-width);
60
+ height: var(--_height);
61
+ background-color: var(--_progress-color);
62
+ border-radius: var(--_border-radius);
63
+ animation: var(--_indeterminate-animation);
64
+ }
65
+
66
+ @keyframes indeterminate {
67
+ 0% {
68
+ margin-left: 0%;
69
+ }
70
+
71
+ 50% {
72
+ margin-left: 75%;
73
+ }
74
+
75
+ 100% {
76
+ margin-left: 0%;
77
+ }
78
+ }
79
+
80
+ /* Info section (text label and value) */
81
+ .info {
82
+ display: flex;
83
+ justify-content: space-between;
84
+ align-items: center;
85
+ flex-wrap: wrap;
86
+ gap: 0.25rem;
87
+ }
88
+
89
+ .label,
90
+ .value {
91
+ font: var(--leu-t-tiny-regular-font);
92
+ color: var(--leu-color-black-60);
93
+ }
94
+
95
+ .value {
96
+ /* margin-left: auto; */
97
+ }
@@ -0,0 +1,39 @@
1
+ import { Meta, StoryObj } from "@storybook/web-components"
2
+ import { html } from "lit"
3
+ import { ifDefined } from "lit/directives/if-defined.js"
4
+
5
+ import "../leu-progress-bar.js"
6
+ import { LeuProgressBar } from "../ProgressBar.js"
7
+
8
+ type StoryArgs = LeuProgressBar
9
+ type Story = StoryObj<StoryArgs>
10
+
11
+ export default {
12
+ title: "Components/ProgressBar",
13
+ component: "leu-progress-bar",
14
+ } satisfies Meta<StoryArgs>
15
+
16
+ const Template: Story = {
17
+ render: ({ label, value, indeterminate }) =>
18
+ html` <leu-progress-bar
19
+ .label="${ifDefined(label)}"
20
+ .value="${ifDefined(value)}"
21
+ ?indeterminate=${indeterminate}
22
+ ></leu-progress-bar>`,
23
+ }
24
+
25
+ export const Regular = {
26
+ ...Template,
27
+ args: {
28
+ value: 50,
29
+ label: "Datei hochladen",
30
+ },
31
+ }
32
+
33
+ export const Indeterminate = {
34
+ ...Template,
35
+ args: {
36
+ indeterminate: true,
37
+ label: "Datei hochladen",
38
+ },
39
+ }