@statistikzh/leu 0.18.1 → 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 (104) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +8 -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.js +1 -3
  20. package/dist/{LeuElement-DgiuzsX9.js → LeuElement-CKq5epyY.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 +54 -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 +266 -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,266 @@
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
+ protected updateFormValue() {
104
+ const formData = new FormData()
105
+
106
+ const files = this.multiple ? this.files : this.files.slice(0, 1)
107
+
108
+ files.forEach((file) => {
109
+ formData.append(this.name, file)
110
+ })
111
+
112
+ this.internals.setFormValue(formData)
113
+ }
114
+
115
+ protected removeFile(fileToRemove: File) {
116
+ this.files = this.files.filter((file) => file !== fileToRemove)
117
+ }
118
+
119
+ protected static formatFileSize(size: number) {
120
+ if (size < 1e3) {
121
+ return html`${size}&nbsp;bytes`
122
+ }
123
+
124
+ if (size >= 1e3 && size < 1e6) {
125
+ return html`${(size / 1e3).toFixed(1)}&nbsp;KB`
126
+ }
127
+
128
+ return html`${(size / 1e6).toFixed(1)}&nbsp;MB`
129
+ }
130
+
131
+ protected handleDragEnter = (event: DragEvent) => {
132
+ if (this.disabled) return
133
+
134
+ event.preventDefault()
135
+ event.stopPropagation()
136
+ this.isDragging = [...event.dataTransfer.items].some(
137
+ (item) => item.kind === "file",
138
+ )
139
+ }
140
+
141
+ // eslint-disable-next-line class-methods-use-this
142
+ protected handleDragOver = (event: DragEvent) => {
143
+ if (this.disabled) return
144
+
145
+ event.preventDefault()
146
+ event.stopPropagation()
147
+ }
148
+
149
+ protected handleDragLeave = (event: DragEvent) => {
150
+ if (this.disabled) return
151
+
152
+ event.preventDefault()
153
+ event.stopPropagation()
154
+ this.isDragging = false
155
+ }
156
+
157
+ protected handleDrop = (event: DragEvent) => {
158
+ if (this.disabled) return
159
+
160
+ event.preventDefault()
161
+ event.stopPropagation()
162
+
163
+ const dt = event.dataTransfer
164
+ const files = dt.files
165
+ const acceptedFiles = [...files].filter((file) => this.isAcceptedFile(file))
166
+
167
+ this.files = this.multiple
168
+ ? this.files.concat(acceptedFiles)
169
+ : acceptedFiles.slice(0, 1)
170
+ this.isDragging = false
171
+ }
172
+
173
+ isAcceptedFile(file: File): boolean {
174
+ const acceptedTypes = this.accept.split(",").map((type) => type.trim())
175
+ const mimeType = file.type
176
+
177
+ for (const acceptedType of acceptedTypes) {
178
+ // Handle file extensions (e.g. .jpg, .png)
179
+ if (acceptedType.startsWith(".")) {
180
+ const name = file.name.toLowerCase()
181
+ const extension = acceptedType.toLowerCase()
182
+
183
+ if (name.endsWith(extension)) {
184
+ return true
185
+ }
186
+ // Handle wildcard types (e.g. image/*)
187
+ } else if (/^\w+\/\*$/.test(acceptedType)) {
188
+ if (mimeType.split("/")[0] === acceptedType.split("/")[0]) {
189
+ return true
190
+ }
191
+ }
192
+
193
+ if (mimeType === acceptedType) {
194
+ return true
195
+ }
196
+ }
197
+
198
+ return false
199
+ }
200
+
201
+ render() {
202
+ const dropzoneClasses = {
203
+ dropzone: true,
204
+ "dropzone--dragging": this.isDragging,
205
+ }
206
+
207
+ return html`
208
+ <div class="container">
209
+ <label class="label" for="input">${this.label}</label>
210
+ <leu-visually-hidden>
211
+ <input
212
+ id="input"
213
+ type="file"
214
+ ?multiple=${this.multiple}
215
+ accept=${ifDefined(this.accept)}
216
+ ?disabled=${this.disabled}
217
+ @input=${this.handleInput}
218
+ />
219
+ </leu-visually-hidden>
220
+ <div
221
+ class=${classMap(dropzoneClasses)}
222
+ @dragenter=${this.handleDragEnter}
223
+ @dragover=${this.handleDragOver}
224
+ @dragleave=${this.handleDragLeave}
225
+ @drop=${this.handleDrop}
226
+ >
227
+ <slot class="dropzone__text"
228
+ ><p>Zum Hochladen Dateien ziehen und hier ablegen.</p></slot
229
+ >
230
+ <leu-button
231
+ variant="secondary"
232
+ ?disabled=${this.disabled}
233
+ @click=${() => this.input.click()}
234
+ >
235
+ Datei auswählen
236
+ <leu-icon name="upload" slot="after"></leu-icon>
237
+ </leu-button>
238
+ </div>
239
+ ${this.files.length > 0
240
+ ? html`<ul class="file-list">
241
+ ${this.files.map(
242
+ (file) =>
243
+ html`<li class="file">
244
+ <strong class="file__name">${file.name}</strong>
245
+ <p class="file__size">
246
+ <span class="file__size-label">Grösse:</span>
247
+ ${LeuFileInput.formatFileSize(file.size)}
248
+ </p>
249
+ <leu-button
250
+ round
251
+ class="file__button"
252
+ label="Datei entfernen"
253
+ size="small"
254
+ variant="secondary"
255
+ ?disabled=${this.disabled}
256
+ @click=${() => this.removeFile(file)}
257
+ ><leu-icon name="delete"></leu-icon
258
+ ></leu-button>
259
+ </li>`,
260
+ )}
261
+ </ul>`
262
+ : nothing}
263
+ </div>
264
+ `
265
+ }
266
+ }
@@ -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
+ }