@statistikzh/leu 0.2.0 → 0.4.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.
- package/.github/workflows/deploy-github-pages.yaml +33 -0
- package/.storybook/main.js +27 -1
- package/.storybook/manager-head.html +1 -0
- package/.storybook/manager.js +9 -0
- package/.storybook/preview-head.html +1 -1
- package/.storybook/preview.js +59 -5
- package/.storybook/static/logo.svg +19 -0
- package/.storybook/theme.js +7 -0
- package/CHANGELOG.md +43 -0
- package/README.md +1 -1
- package/dist/Button.js +39 -30
- package/dist/ButtonGroup.js +5 -7
- package/dist/Checkbox.js +107 -88
- package/dist/CheckboxGroup.js +43 -38
- package/dist/{Chip-389013ff.js → Chip-dac7337d.js} +7 -2
- package/dist/ChipGroup.js +4 -6
- package/dist/ChipLink.js +6 -8
- package/dist/ChipRemovable.js +4 -7
- package/dist/ChipSelectable.js +10 -10
- package/dist/Dropdown.js +57 -27
- package/dist/Input.js +59 -43
- package/dist/Menu.js +2 -5
- package/dist/MenuItem.js +34 -17
- package/dist/Pagination.js +57 -55
- package/dist/Radio.js +13 -10
- package/dist/RadioGroup.js +43 -40
- package/dist/Select.js +57 -44
- package/dist/Table.js +147 -125
- package/dist/{defineElement-ba770aed.js → _rollupPluginBabelHelpers-20f659f4.js} +1 -15
- package/dist/defineElement-47d4f665.js +15 -0
- package/dist/index.js +29 -19
- package/dist/leu-button-group.js +7 -3
- package/dist/leu-button.js +6 -3
- package/dist/leu-checkbox-group.js +6 -3
- package/dist/leu-checkbox.js +6 -3
- package/dist/leu-chip-group.js +6 -3
- package/dist/leu-chip-link.js +7 -4
- package/dist/leu-chip-removable.js +7 -4
- package/dist/leu-chip-selectable.js +7 -4
- package/dist/leu-dropdown.js +13 -3
- package/dist/leu-input.js +7 -3
- package/dist/leu-menu-item.js +8 -3
- package/dist/leu-menu.js +6 -3
- package/dist/leu-pagination.js +8 -3
- package/dist/leu-popup-4bf6f1f4.js +216 -0
- package/dist/leu-radio-group.js +6 -3
- package/dist/leu-radio.js +6 -3
- package/dist/leu-select.js +14 -3
- package/dist/leu-table.js +9 -3
- package/package.json +29 -12
- package/scripts/generate-component/templates/[Name].js +0 -5
- package/scripts/generate-component/templates/[name].css +1 -1
- package/scripts/generate-component/templates/[namespace]-[name].js +5 -2
- package/src/components/accordion/Accordion.js +3 -9
- package/src/components/accordion/leu-accordion.js +5 -2
- package/src/components/accordion/stories/accordion.stories.js +7 -4
- package/src/components/accordion/test/accordion.test.js +92 -2
- package/src/components/breadcrumb/Breadcrumb.js +310 -0
- package/src/components/breadcrumb/breadcrumb.css +114 -0
- package/src/components/breadcrumb/leu-breadcrumb.js +6 -0
- package/src/components/breadcrumb/stories/breadcrumb.stories.js +73 -0
- package/src/components/breadcrumb/test/breadcrumb.test.js +141 -0
- package/src/components/button/Button.js +22 -27
- package/src/components/button/button.css +3 -3
- package/src/components/button/leu-button.js +5 -2
- package/src/components/button/stories/button.stories.js +58 -37
- package/src/components/button/test/button.test.js +112 -2
- package/src/components/button-group/ButtonGroup.js +1 -7
- package/src/components/button-group/leu-button-group.js +5 -2
- package/src/components/button-group/stories/button-group.stories.js +6 -0
- package/src/components/button-group/test/button-group.test.js +79 -3
- package/src/components/checkbox/Checkbox.js +9 -89
- package/src/components/checkbox/CheckboxGroup.js +9 -39
- package/src/components/checkbox/checkbox-group.css +29 -0
- package/src/components/checkbox/checkbox.css +76 -0
- package/src/components/checkbox/leu-checkbox-group.js +5 -2
- package/src/components/checkbox/leu-checkbox.js +5 -2
- package/src/components/checkbox/stories/checkbox-group.stories.js +44 -21
- package/src/components/checkbox/stories/checkbox.stories.js +7 -1
- package/src/components/checkbox/test/checkbox-group.test.js +124 -0
- package/src/components/checkbox/test/checkbox.test.js +72 -59
- package/src/components/chip/Chip.js +2 -1
- package/src/components/chip/ChipGroup.js +1 -6
- package/src/components/chip/ChipLink.js +2 -8
- package/src/components/chip/ChipRemovable.js +1 -6
- package/src/components/chip/ChipSelectable.js +4 -9
- package/src/components/chip/exports.js +4 -10
- package/src/components/chip/leu-chip-group.js +5 -2
- package/src/components/chip/leu-chip-link.js +5 -2
- package/src/components/chip/leu-chip-removable.js +5 -2
- package/src/components/chip/leu-chip-selectable.js +5 -2
- package/src/components/chip/stories/chip-group.stories.js +18 -6
- package/src/components/chip/stories/chip-link.stories.js +16 -4
- package/src/components/chip/stories/chip-removable.stories.js +15 -4
- package/src/components/chip/stories/chip-selectable.stories.js +13 -3
- package/src/components/chip/test/chip-group.test.js +124 -0
- package/src/components/chip/test/chip-link.test.js +58 -0
- package/src/components/chip/test/chip-removable.test.js +79 -0
- package/src/components/chip/test/chip-selectable.test.js +95 -0
- package/src/components/chip/test/chip.test.js +1 -1
- package/src/components/dropdown/Dropdown.js +53 -25
- package/src/components/dropdown/dropdown.css +1 -2
- package/src/components/dropdown/leu-dropdown.js +5 -2
- package/src/components/dropdown/stories/dropdown.stories.js +11 -5
- package/src/components/dropdown/test/dropdown.test.js +6 -6
- package/src/components/icon/icon.js +1 -1
- package/src/components/icon/test/icon.test.js +66 -0
- package/src/components/input/Input.js +33 -39
- package/src/components/input/input.css +9 -6
- package/src/components/input/leu-input.js +5 -2
- package/src/components/input/stories/input.stories.js +8 -2
- package/src/components/input/test/input.test.js +431 -4
- package/src/components/menu/Menu.js +0 -5
- package/src/components/menu/MenuItem.js +22 -15
- package/src/components/menu/leu-menu-item.js +5 -2
- package/src/components/menu/leu-menu.js +5 -2
- package/src/components/menu/menu-item.css +5 -2
- package/src/components/menu/stories/menu-item.stories.js +13 -4
- package/src/components/menu/stories/menu.stories.js +11 -5
- package/src/components/menu/test/menu-item.test.js +180 -0
- package/src/components/menu/test/menu.test.js +10 -2
- package/src/components/pagination/Pagination.js +53 -65
- package/src/components/pagination/leu-pagination.js +5 -2
- package/src/components/pagination/stories/pagination.stories.js +17 -9
- package/src/components/pagination/test/pagination.test.js +191 -5
- package/src/components/popup/Popup.js +200 -0
- package/src/components/popup/leu-popup.js +6 -0
- package/src/components/popup/popup.css +27 -0
- package/src/components/popup/stories/popup.stories.js +58 -0
- package/src/components/popup/test/popup.test.js +29 -0
- package/src/components/radio/Radio.js +5 -10
- package/src/components/radio/RadioGroup.js +7 -39
- package/src/components/radio/leu-radio-group.js +5 -2
- package/src/components/radio/leu-radio.js +5 -2
- package/src/components/radio/radio-group.css +29 -0
- package/src/components/radio/stories/radio-group.stories.js +38 -19
- package/src/components/radio/stories/radio.stories.js +7 -1
- package/src/components/radio/test/radio-group.test.js +86 -0
- package/src/components/radio/test/radio.test.js +108 -17
- package/src/components/select/Select.js +35 -32
- package/src/components/select/leu-select.js +5 -2
- package/src/components/select/select.css +13 -13
- package/src/components/select/stories/select.stories.js +15 -168
- package/src/components/select/test/fixtures.js +162 -0
- package/src/components/select/test/select.test.js +236 -12
- package/src/components/table/Table.js +48 -123
- package/src/components/table/leu-table.js +5 -2
- package/src/components/table/stories/table.stories.js +20 -10
- package/src/components/table/table.css +99 -0
- package/src/components/table/test/table.test.js +1 -1
- package/src/lib/utils.js +17 -0
- package/{web-dev-server-storybook.config.mjs → web-dev-server.config.mjs} +1 -2
- package/web-test-runner.config.mjs +15 -2
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { html, LitElement, nothing } from "lit"
|
|
2
2
|
import { classMap } from "lit/directives/class-map.js"
|
|
3
3
|
import { ifDefined } from "lit/directives/if-defined.js"
|
|
4
|
+
import { live } from "lit/directives/live.js"
|
|
4
5
|
import { createRef, ref } from "lit/directives/ref.js"
|
|
5
6
|
|
|
6
7
|
import { Icon } from "../icon/icon.js"
|
|
7
|
-
import { defineElement } from "../../lib/defineElement.js"
|
|
8
8
|
|
|
9
9
|
import styles from "./input.css"
|
|
10
10
|
|
|
@@ -78,25 +78,25 @@ export class LeuInput extends LitElement {
|
|
|
78
78
|
required: { type: Boolean, reflect: true },
|
|
79
79
|
clearable: { type: Boolean, reflect: true },
|
|
80
80
|
|
|
81
|
-
value: { type: String },
|
|
82
|
-
name: { type: String },
|
|
83
|
-
error: { type: String },
|
|
81
|
+
value: { type: String, reflect: true },
|
|
82
|
+
name: { type: String, reflect: true },
|
|
83
|
+
error: { type: String, reflect: true },
|
|
84
84
|
|
|
85
|
-
label: { type: String },
|
|
86
|
-
prefix: { type: String },
|
|
87
|
-
suffix: { type: String },
|
|
88
|
-
size: { type: String },
|
|
89
|
-
icon: { type: String },
|
|
85
|
+
label: { type: String, reflect: true },
|
|
86
|
+
prefix: { type: String, reflect: true },
|
|
87
|
+
suffix: { type: String, reflect: true },
|
|
88
|
+
size: { type: String, reflect: true },
|
|
89
|
+
icon: { type: String, reflect: true },
|
|
90
90
|
|
|
91
91
|
/* Validation attributes */
|
|
92
|
-
pattern: { type: String },
|
|
93
|
-
type: { type: String },
|
|
94
|
-
min: { type: Number },
|
|
95
|
-
max: { type: Number },
|
|
96
|
-
maxlength: { type: Number },
|
|
97
|
-
minlength: { type: Number },
|
|
92
|
+
pattern: { type: String, reflect: true },
|
|
93
|
+
type: { type: String, reflect: true },
|
|
94
|
+
min: { type: Number, reflect: true },
|
|
95
|
+
max: { type: Number, reflect: true },
|
|
96
|
+
maxlength: { type: Number, reflect: true },
|
|
97
|
+
minlength: { type: Number, reflect: true },
|
|
98
98
|
validationMessages: { type: Object },
|
|
99
|
-
novalidate: { type: Boolean },
|
|
99
|
+
novalidate: { type: Boolean, reflect: true },
|
|
100
100
|
|
|
101
101
|
/** @type {ValidityState} */
|
|
102
102
|
_validity: { state: true },
|
|
@@ -117,19 +117,9 @@ export class LeuInput extends LitElement {
|
|
|
117
117
|
this.required = false
|
|
118
118
|
this.clearable = false
|
|
119
119
|
|
|
120
|
-
this.value = ""
|
|
121
|
-
this.name = ""
|
|
122
|
-
this.error = ""
|
|
123
|
-
|
|
124
|
-
this.label = ""
|
|
125
|
-
this.prefix = ""
|
|
126
|
-
this.suffix = ""
|
|
127
|
-
|
|
128
120
|
/** @type {keyof typeof SIZE_TYPES} */
|
|
129
121
|
this.size = SIZE_TYPES.REGULAR
|
|
130
122
|
|
|
131
|
-
this.icon = ""
|
|
132
|
-
|
|
133
123
|
this.type = "text"
|
|
134
124
|
this._validity = null
|
|
135
125
|
this.validationMessages = {}
|
|
@@ -201,7 +191,9 @@ export class LeuInput extends LitElement {
|
|
|
201
191
|
* @returns {void}
|
|
202
192
|
*/
|
|
203
193
|
handleChange(event) {
|
|
204
|
-
|
|
194
|
+
if (event.target.validity.valid) {
|
|
195
|
+
this.value = event.target.value
|
|
196
|
+
}
|
|
205
197
|
|
|
206
198
|
const customEvent = new CustomEvent(event.type, event)
|
|
207
199
|
this.dispatchEvent(customEvent)
|
|
@@ -217,6 +209,12 @@ export class LeuInput extends LitElement {
|
|
|
217
209
|
*/
|
|
218
210
|
handleInput(event) {
|
|
219
211
|
this.value = event.target.value
|
|
212
|
+
|
|
213
|
+
const customEvent = new CustomEvent("input", {
|
|
214
|
+
bubbles: true,
|
|
215
|
+
composed: true,
|
|
216
|
+
})
|
|
217
|
+
this.dispatchEvent(customEvent)
|
|
220
218
|
}
|
|
221
219
|
|
|
222
220
|
/**
|
|
@@ -348,7 +346,7 @@ export class LeuInput extends LitElement {
|
|
|
348
346
|
return html`<div class="error-icon">${Icon("caution")}</div>`
|
|
349
347
|
}
|
|
350
348
|
|
|
351
|
-
if (this.clearable && this.value
|
|
349
|
+
if (this.clearable && this.value) {
|
|
352
350
|
return html`<button
|
|
353
351
|
class="clear-button"
|
|
354
352
|
@click=${this.clear}
|
|
@@ -359,7 +357,7 @@ export class LeuInput extends LitElement {
|
|
|
359
357
|
</button>`
|
|
360
358
|
}
|
|
361
359
|
|
|
362
|
-
if (this.icon
|
|
360
|
+
if (this.icon) {
|
|
363
361
|
return html`<div class="icon">${Icon(this.icon)}</div>`
|
|
364
362
|
}
|
|
365
363
|
|
|
@@ -367,7 +365,7 @@ export class LeuInput extends LitElement {
|
|
|
367
365
|
}
|
|
368
366
|
|
|
369
367
|
isInvalid() {
|
|
370
|
-
if (this.error
|
|
368
|
+
if (this.error) {
|
|
371
369
|
return true
|
|
372
370
|
}
|
|
373
371
|
|
|
@@ -381,7 +379,7 @@ export class LeuInput extends LitElement {
|
|
|
381
379
|
|
|
382
380
|
const inputWrapperClasses = {
|
|
383
381
|
"input-wrapper": true,
|
|
384
|
-
"input-wrapper--empty": this.value
|
|
382
|
+
"input-wrapper--empty": !this.value,
|
|
385
383
|
"input-wrapper--invalid": isInvalid,
|
|
386
384
|
}
|
|
387
385
|
|
|
@@ -403,20 +401,20 @@ export class LeuInput extends LitElement {
|
|
|
403
401
|
@invalid=${this.handleInvalid}
|
|
404
402
|
?disabled=${this.disabled}
|
|
405
403
|
?required=${this.required}
|
|
404
|
+
.value=${live(this.value ?? "")}
|
|
406
405
|
pattern=${ifDefined(this.pattern)}
|
|
407
406
|
min=${ifDefined(this.min)}
|
|
408
407
|
max=${ifDefined(this.max)}
|
|
409
408
|
maxlength=${ifDefined(this.maxlength)}
|
|
410
409
|
minlength=${ifDefined(this.minlength)}
|
|
411
|
-
.value=${this.value}
|
|
412
410
|
ref=${ref(this._inputRef)}
|
|
413
411
|
aria-invalid=${isInvalid}
|
|
414
412
|
/>
|
|
415
|
-
<label for="input-${this.getId()}" class="label"
|
|
416
|
-
${this.prefix
|
|
413
|
+
<label for="input-${this.getId()}" class="label">${this.label}</label>
|
|
414
|
+
${this.prefix
|
|
417
415
|
? html`<div class="prefix" .aria-hidden=${true}>${this.prefix}</div>`
|
|
418
416
|
: nothing}
|
|
419
|
-
${this.suffix
|
|
417
|
+
${this.suffix
|
|
420
418
|
? html`<div class="suffix" .aria-hidden=${true}>${this.suffix}</div>`
|
|
421
419
|
: nothing}
|
|
422
420
|
${this.renderAfterContent()}
|
|
@@ -425,7 +423,3 @@ export class LeuInput extends LitElement {
|
|
|
425
423
|
`
|
|
426
424
|
}
|
|
427
425
|
}
|
|
428
|
-
|
|
429
|
-
export function defineInputElements() {
|
|
430
|
-
defineElement("input", LeuInput)
|
|
431
|
-
}
|
|
@@ -115,6 +115,7 @@
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
/* is size regular AND (has focus OR contains a value) */
|
|
118
|
+
.input-wrapper--invalid .label,
|
|
118
119
|
:host(:not([size])) .label,
|
|
119
120
|
:host([size="regular"]) .label {
|
|
120
121
|
top: calc(0.75rem - var(--input-border-width));
|
|
@@ -138,18 +139,20 @@
|
|
|
138
139
|
content: "*";
|
|
139
140
|
}
|
|
140
141
|
|
|
142
|
+
/* is not disabled AND has focus AND is empty */
|
|
143
|
+
:host(:not([disabled], :focus-within)) .input-wrapper--empty .label {
|
|
144
|
+
--input-label-color: var(--input-label-color-empty);
|
|
145
|
+
}
|
|
146
|
+
|
|
141
147
|
/* is empty AND has no focus */
|
|
142
|
-
:host(:not(:focus-within))
|
|
148
|
+
:host(:not(:focus-within))
|
|
149
|
+
.input-wrapper--empty:not(.input-wrapper--invalid)
|
|
150
|
+
.label {
|
|
143
151
|
font-family: var(--input-font-regular);
|
|
144
152
|
font-size: 1rem;
|
|
145
153
|
top: calc(1.5rem - var(--input-border-width));
|
|
146
154
|
}
|
|
147
155
|
|
|
148
|
-
/* is not disabled AND has focus AND is empty */
|
|
149
|
-
:host(:not([disabled], :focus-within)) .input-wrapper--empty .label {
|
|
150
|
-
--input-label-color: var(--input-label-color-empty);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
156
|
/* is size small AND has no focus AND is empty */
|
|
154
157
|
:host(:not(:focus-within)[size="small"]) .input-wrapper--empty .label {
|
|
155
158
|
top: calc(0.75rem - var(--input-border-width));
|
|
@@ -14,11 +14,17 @@ export default {
|
|
|
14
14
|
size: {
|
|
15
15
|
control: {
|
|
16
16
|
type: "select",
|
|
17
|
-
options: SIZE_TYPES,
|
|
18
17
|
},
|
|
18
|
+
options: Object.values(SIZE_TYPES),
|
|
19
19
|
},
|
|
20
20
|
icon: { control: "select", options: ICON_NAMES },
|
|
21
21
|
},
|
|
22
|
+
parameters: {
|
|
23
|
+
design: {
|
|
24
|
+
type: "figma",
|
|
25
|
+
url: "https://www.figma.com/file/d6Pv21UVUbnBs3AdcZijHmbN/KTZH-Design-System?type=design&node-id=17340-81934&mode=design&t=lzVrtq8lxYVJU5TB-11",
|
|
26
|
+
},
|
|
27
|
+
},
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
function Template(args) {
|
|
@@ -56,12 +62,12 @@ function Template(args) {
|
|
|
56
62
|
max=${ifDefined(max)}
|
|
57
63
|
minlength=${ifDefined(minlength)}
|
|
58
64
|
maxlength=${ifDefined(maxlength)}
|
|
65
|
+
label=${label}
|
|
59
66
|
?disabled=${disabled}
|
|
60
67
|
?required=${required}
|
|
61
68
|
?clearable=${clearable}
|
|
62
69
|
?novalidate=${novalidate}
|
|
63
70
|
>
|
|
64
|
-
${label}
|
|
65
71
|
</leu-input>
|
|
66
72
|
`
|
|
67
73
|
}
|
|
@@ -1,15 +1,39 @@
|
|
|
1
1
|
import { html } from "lit"
|
|
2
|
-
import {
|
|
2
|
+
import { ifDefined } from "lit/directives/if-defined.js"
|
|
3
|
+
import { fixture, expect, elementUpdated } from "@open-wc/testing"
|
|
4
|
+
import { sendKeys } from "@web/test-runner-commands"
|
|
5
|
+
import { spy } from "sinon"
|
|
3
6
|
|
|
4
7
|
import "../leu-input.js"
|
|
5
8
|
|
|
6
|
-
async function defaultFixture() {
|
|
7
|
-
return fixture(html`
|
|
9
|
+
async function defaultFixture(args = {}) {
|
|
10
|
+
return fixture(html`
|
|
11
|
+
<leu-input
|
|
12
|
+
value=${ifDefined(args.value)}
|
|
13
|
+
error=${ifDefined(args.error)}
|
|
14
|
+
pattern=${ifDefined(args.pattern)}
|
|
15
|
+
prefix=${ifDefined(args.prefix)}
|
|
16
|
+
suffix=${ifDefined(args.suffix)}
|
|
17
|
+
size=${ifDefined(args.size)}
|
|
18
|
+
icon=${ifDefined(args.icon)}
|
|
19
|
+
type=${ifDefined(args.type)}
|
|
20
|
+
min=${ifDefined(args.min)}
|
|
21
|
+
max=${ifDefined(args.max)}
|
|
22
|
+
minlength=${ifDefined(args.minlength)}
|
|
23
|
+
maxlength=${ifDefined(args.maxlength)}
|
|
24
|
+
label=${args.label || "Label"}
|
|
25
|
+
?disabled=${args.disabled}
|
|
26
|
+
?required=${args.required}
|
|
27
|
+
?clearable=${args.clearable}
|
|
28
|
+
?novalidate=${args.novalidate}
|
|
29
|
+
>
|
|
30
|
+
</leu-input>
|
|
31
|
+
`)
|
|
8
32
|
}
|
|
9
33
|
|
|
10
34
|
describe("LeuInput", () => {
|
|
11
35
|
it("is a defined element", async () => {
|
|
12
|
-
const el =
|
|
36
|
+
const el = customElements.get("leu-input")
|
|
13
37
|
|
|
14
38
|
await expect(el).not.to.be.undefined
|
|
15
39
|
})
|
|
@@ -19,4 +43,407 @@ describe("LeuInput", () => {
|
|
|
19
43
|
|
|
20
44
|
await expect(el).shadowDom.to.be.accessible()
|
|
21
45
|
})
|
|
46
|
+
|
|
47
|
+
it("delegates the focus to the input element", async () => {
|
|
48
|
+
const el = await defaultFixture()
|
|
49
|
+
|
|
50
|
+
const input = el.shadowRoot.querySelector("input")
|
|
51
|
+
|
|
52
|
+
el.focus()
|
|
53
|
+
|
|
54
|
+
expect(el.shadowRoot.activeElement).to.equal(input)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it("can't be focused when disabled", async () => {
|
|
58
|
+
const el = await defaultFixture({ disabled: true })
|
|
59
|
+
|
|
60
|
+
el.focus()
|
|
61
|
+
|
|
62
|
+
expect(el.shadowRoot.activeElement).to.be.null
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it("renders the defined label", async () => {
|
|
66
|
+
const el = await defaultFixture({ label: "Vorname" })
|
|
67
|
+
|
|
68
|
+
const label = el.shadowRoot.querySelector("label")
|
|
69
|
+
|
|
70
|
+
expect(label).to.have.text("Vorname")
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it("has type text by default", async () => {
|
|
74
|
+
const el = await defaultFixture()
|
|
75
|
+
|
|
76
|
+
expect(el.type).to.equal("text")
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it("passes the defined type to the input element", async () => {
|
|
80
|
+
const el = await defaultFixture({ type: "email" })
|
|
81
|
+
|
|
82
|
+
const input = el.shadowRoot.querySelector("input")
|
|
83
|
+
|
|
84
|
+
expect(input.type).to.equal("email")
|
|
85
|
+
|
|
86
|
+
el.type = "password"
|
|
87
|
+
await elementUpdated(el)
|
|
88
|
+
|
|
89
|
+
expect(input.type).to.equal("password")
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it("passes the defined value to the input element", async () => {
|
|
93
|
+
const el = await defaultFixture({ label: "Vorname", value: "John" })
|
|
94
|
+
|
|
95
|
+
const input = el.shadowRoot.querySelector("input")
|
|
96
|
+
|
|
97
|
+
expect(input.value).to.equal("John")
|
|
98
|
+
|
|
99
|
+
el.value = "Jane"
|
|
100
|
+
await elementUpdated(el)
|
|
101
|
+
|
|
102
|
+
expect(input.value).to.equal("Jane")
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it("syncs the value property of the input and the value property of the component", async () => {
|
|
106
|
+
const el = await defaultFixture({ label: "Vorname", value: "John" })
|
|
107
|
+
|
|
108
|
+
const input = el.shadowRoot.querySelector("input")
|
|
109
|
+
|
|
110
|
+
el.focus()
|
|
111
|
+
|
|
112
|
+
await sendKeys({ press: "Backspace" })
|
|
113
|
+
await sendKeys({ press: "Backspace" })
|
|
114
|
+
await sendKeys({ press: "Backspace" })
|
|
115
|
+
await sendKeys({ press: "Backspace" })
|
|
116
|
+
await sendKeys({ type: "Jane" })
|
|
117
|
+
await elementUpdated(el)
|
|
118
|
+
|
|
119
|
+
expect(el.value).to.equal("Jane")
|
|
120
|
+
expect(input.value).to.equal("Jane")
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it("doesn't accept letters when type is set to number", async () => {
|
|
124
|
+
const el = await defaultFixture({ label: "Länge", type: "number" })
|
|
125
|
+
|
|
126
|
+
const input = el.shadowRoot.querySelector("input")
|
|
127
|
+
|
|
128
|
+
el.focus()
|
|
129
|
+
|
|
130
|
+
await sendKeys({ type: "123" })
|
|
131
|
+
await elementUpdated(el)
|
|
132
|
+
|
|
133
|
+
expect(el.value).to.equal("123")
|
|
134
|
+
expect(input.value).to.equal("123")
|
|
135
|
+
|
|
136
|
+
await sendKeys({ type: "abc" })
|
|
137
|
+
await elementUpdated(el)
|
|
138
|
+
|
|
139
|
+
expect(el.value).to.not.equal("123abc")
|
|
140
|
+
expect(input.value).to.not.equal("123abc")
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it("fires a change event after losing focus", async () => {
|
|
144
|
+
const el = await defaultFixture({ label: "Vorname" })
|
|
145
|
+
|
|
146
|
+
const input = el.shadowRoot.querySelector("input")
|
|
147
|
+
|
|
148
|
+
const changeSpy = spy()
|
|
149
|
+
input.addEventListener("change", changeSpy)
|
|
150
|
+
|
|
151
|
+
el.focus()
|
|
152
|
+
|
|
153
|
+
await sendKeys({ type: "John" })
|
|
154
|
+
await sendKeys({ press: "Tab" })
|
|
155
|
+
|
|
156
|
+
expect(changeSpy).to.have.been.calledOnce
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it("fires a input event while typing ", async () => {
|
|
160
|
+
const el = await defaultFixture({ label: "Vorname", maxlength: 3 })
|
|
161
|
+
|
|
162
|
+
const input = el.shadowRoot.querySelector("input")
|
|
163
|
+
|
|
164
|
+
const inputSpy = spy()
|
|
165
|
+
input.addEventListener("input", inputSpy)
|
|
166
|
+
|
|
167
|
+
el.focus()
|
|
168
|
+
|
|
169
|
+
await sendKeys({ type: "John" })
|
|
170
|
+
|
|
171
|
+
// Should fire 3 times, because maxlength is set to 3
|
|
172
|
+
expect(inputSpy).to.have.been.called.calledThrice
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it("fires a input event while typing ", async () => {})
|
|
176
|
+
|
|
177
|
+
it("renders a prefix", async () => {
|
|
178
|
+
const el = await defaultFixture({ label: "Preis", prefix: "CHF" })
|
|
179
|
+
|
|
180
|
+
const prefix = el.shadowRoot.querySelector(".prefix")
|
|
181
|
+
|
|
182
|
+
expect(prefix).to.have.text("CHF")
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it("renders a suffix", async () => {
|
|
186
|
+
const el = await defaultFixture({ label: "Länge", suffix: "cm" })
|
|
187
|
+
|
|
188
|
+
const suffix = el.shadowRoot.querySelector(".suffix")
|
|
189
|
+
|
|
190
|
+
expect(suffix).to.have.text("cm")
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it("renders an icon", async () => {
|
|
194
|
+
const _el = await defaultFixture({ label: "Vorname", icon: "user" })
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
it("renders a clear button", async () => {
|
|
198
|
+
const el = await defaultFixture({ label: "Vorname", clearable: true })
|
|
199
|
+
|
|
200
|
+
let clearButton = el.shadowRoot.querySelector(".clear-button")
|
|
201
|
+
expect(clearButton).to.not.exist
|
|
202
|
+
|
|
203
|
+
el.focus()
|
|
204
|
+
await sendKeys({ type: "John" })
|
|
205
|
+
|
|
206
|
+
clearButton = el.shadowRoot.querySelector(".clear-button")
|
|
207
|
+
expect(clearButton).to.not.be.null
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
it("clears the value when clicking the clear button", async () => {
|
|
211
|
+
const el = await defaultFixture({ label: "Vorname", clearable: true })
|
|
212
|
+
|
|
213
|
+
el.focus()
|
|
214
|
+
|
|
215
|
+
await sendKeys({ type: "John" })
|
|
216
|
+
await elementUpdated(el)
|
|
217
|
+
|
|
218
|
+
const clearButton = el.shadowRoot.querySelector(".clear-button")
|
|
219
|
+
clearButton.click()
|
|
220
|
+
|
|
221
|
+
expect(el.value).to.equal("")
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it("renders an error message when value is less than min", async () => {
|
|
225
|
+
const el = await defaultFixture({ label: "Länge", min: 10, type: "number" })
|
|
226
|
+
|
|
227
|
+
el.focus()
|
|
228
|
+
|
|
229
|
+
await sendKeys({ type: "5" })
|
|
230
|
+
await sendKeys({ press: "Tab" })
|
|
231
|
+
await elementUpdated(el)
|
|
232
|
+
|
|
233
|
+
const error = el.shadowRoot.querySelector(".error")
|
|
234
|
+
|
|
235
|
+
expect(error).not.to.be.null
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
it("renders an error message when value greater than max", async () => {
|
|
239
|
+
const el = await defaultFixture({ label: "Länge", max: 10, type: "number" })
|
|
240
|
+
|
|
241
|
+
el.focus()
|
|
242
|
+
|
|
243
|
+
await sendKeys({ type: "15" })
|
|
244
|
+
await sendKeys({ press: "Tab" })
|
|
245
|
+
await elementUpdated(el)
|
|
246
|
+
|
|
247
|
+
const error = el.shadowRoot.querySelector(".error")
|
|
248
|
+
|
|
249
|
+
expect(error).not.to.be.null
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
it("renders an error message when the value doesn't match the step", async () => {
|
|
253
|
+
const el = await defaultFixture({
|
|
254
|
+
label: "Länge",
|
|
255
|
+
step: 10,
|
|
256
|
+
type: "number",
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
el.focus()
|
|
260
|
+
|
|
261
|
+
await sendKeys({ type: "15" })
|
|
262
|
+
await sendKeys({ press: "Tab" })
|
|
263
|
+
await elementUpdated(el)
|
|
264
|
+
|
|
265
|
+
const error = el.shadowRoot.querySelector(".error")
|
|
266
|
+
|
|
267
|
+
expect(error).not.to.be.null
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
it("renders an error message when value is shorter than minlength", async () => {
|
|
271
|
+
const el = await defaultFixture({
|
|
272
|
+
label: "Vorname",
|
|
273
|
+
minlength: 3,
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
el.focus()
|
|
277
|
+
|
|
278
|
+
await sendKeys({ type: "Jo" })
|
|
279
|
+
await sendKeys({ press: "Tab" })
|
|
280
|
+
await elementUpdated(el)
|
|
281
|
+
|
|
282
|
+
const error = el.shadowRoot.querySelector(".error")
|
|
283
|
+
|
|
284
|
+
expect(error).not.to.be.null
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
it("renders an error message when value is longer than maxlength", async () => {
|
|
288
|
+
const el = await defaultFixture({
|
|
289
|
+
label: "Vorname",
|
|
290
|
+
maxlength: 10,
|
|
291
|
+
value: "Andrea Gabathuler",
|
|
292
|
+
})
|
|
293
|
+
|
|
294
|
+
el.focus()
|
|
295
|
+
|
|
296
|
+
/* Remove the selection, if there is one */
|
|
297
|
+
await sendKeys({ press: "ArrowRight" })
|
|
298
|
+
/*
|
|
299
|
+
* Trigger an update of the value that is too long.
|
|
300
|
+
* Browser won't allow to type more than maxlength.
|
|
301
|
+
*/
|
|
302
|
+
await sendKeys({ press: "Backspace" })
|
|
303
|
+
await sendKeys({ press: "Tab" })
|
|
304
|
+
await elementUpdated(el)
|
|
305
|
+
|
|
306
|
+
const error = el.shadowRoot.querySelector(".error")
|
|
307
|
+
|
|
308
|
+
expect(error).not.to.be.null
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
it("renders an error message when value doesn't match pattern", async () => {
|
|
312
|
+
const el = await defaultFixture({
|
|
313
|
+
label: "Vorname",
|
|
314
|
+
pattern: "([A-Z]{2}-)?d{4,5}", // Pseudo zip code e.g. CH-8000 or 8000 or DE-12345
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
el.focus()
|
|
318
|
+
|
|
319
|
+
await sendKeys({ type: "123" })
|
|
320
|
+
await sendKeys({ press: "Tab" })
|
|
321
|
+
await elementUpdated(el)
|
|
322
|
+
|
|
323
|
+
let error = el.shadowRoot.querySelector(".error")
|
|
324
|
+
expect(error).not.to.be.null
|
|
325
|
+
|
|
326
|
+
el.value = ""
|
|
327
|
+
await elementUpdated(el)
|
|
328
|
+
|
|
329
|
+
el.focus()
|
|
330
|
+
|
|
331
|
+
await sendKeys({ type: "DE-987" })
|
|
332
|
+
await sendKeys({ press: "Tab" })
|
|
333
|
+
await elementUpdated(el)
|
|
334
|
+
|
|
335
|
+
error = el.shadowRoot.querySelector(".error")
|
|
336
|
+
expect(error).not.to.be.null
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
it("renders an error message when value is required but is empty", async () => {
|
|
340
|
+
const el = await defaultFixture({
|
|
341
|
+
label: "Vorname",
|
|
342
|
+
required: true,
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
el.focus()
|
|
346
|
+
|
|
347
|
+
await sendKeys({ press: "Tab" })
|
|
348
|
+
await elementUpdated(el)
|
|
349
|
+
|
|
350
|
+
const error = el.shadowRoot.querySelector(".error")
|
|
351
|
+
|
|
352
|
+
expect(error).not.to.be.null
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
it("renders a custom error message", async () => {
|
|
356
|
+
const el = await defaultFixture({
|
|
357
|
+
label: "Vorname",
|
|
358
|
+
error: "Bitte geben Sie einen Vornamen ein.",
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
el.focus()
|
|
362
|
+
|
|
363
|
+
await sendKeys({ press: "Tab" })
|
|
364
|
+
await elementUpdated(el)
|
|
365
|
+
|
|
366
|
+
const error = el.shadowRoot.querySelector(".error")
|
|
367
|
+
|
|
368
|
+
expect(error).to.have.trimmed.text("Bitte geben Sie einen Vornamen ein.")
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
it("resets the error message as soon as value is valid again", async () => {
|
|
372
|
+
const el = await defaultFixture({
|
|
373
|
+
label: "Vorname",
|
|
374
|
+
required: true,
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
el.focus()
|
|
378
|
+
|
|
379
|
+
await sendKeys({ press: "Tab" })
|
|
380
|
+
await elementUpdated(el)
|
|
381
|
+
|
|
382
|
+
let error = el.shadowRoot.querySelector(".error")
|
|
383
|
+
expect(error).not.to.be.null
|
|
384
|
+
|
|
385
|
+
el.focus()
|
|
386
|
+
|
|
387
|
+
await sendKeys({ type: "Jacqueline" })
|
|
388
|
+
await sendKeys({ press: "Tab" })
|
|
389
|
+
await elementUpdated(el)
|
|
390
|
+
|
|
391
|
+
error = el.shadowRoot.querySelector(".error")
|
|
392
|
+
expect(error).to.be.null
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
it("doesn't render an error message when novalidate is set", async () => {
|
|
396
|
+
const el = await defaultFixture({
|
|
397
|
+
label: "Vorname",
|
|
398
|
+
required: true,
|
|
399
|
+
novalidate: true,
|
|
400
|
+
})
|
|
401
|
+
|
|
402
|
+
el.focus()
|
|
403
|
+
|
|
404
|
+
await sendKeys({ press: "Tab" })
|
|
405
|
+
await elementUpdated(el)
|
|
406
|
+
|
|
407
|
+
const error = el.shadowRoot.querySelector(".error")
|
|
408
|
+
|
|
409
|
+
expect(error).to.be.null
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
it("shows only one 'after' element", async () => {
|
|
413
|
+
const el = await defaultFixture({
|
|
414
|
+
label: "Länge",
|
|
415
|
+
type: "number",
|
|
416
|
+
min: 50,
|
|
417
|
+
icon: "user",
|
|
418
|
+
clearable: true,
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
const getErrorIcon = () => el.shadowRoot.querySelector(".error-icon")
|
|
422
|
+
const getClearButton = () => el.shadowRoot.querySelector(".clear-button")
|
|
423
|
+
const getIcon = () => el.shadowRoot.querySelector(".icon")
|
|
424
|
+
|
|
425
|
+
/* Priority: Error > Clear > Icon */
|
|
426
|
+
expect(getErrorIcon()).to.be.null
|
|
427
|
+
expect(getClearButton()).to.be.null
|
|
428
|
+
expect(getIcon()).not.to.be.null
|
|
429
|
+
|
|
430
|
+
el.focus()
|
|
431
|
+
await sendKeys({ type: "60" })
|
|
432
|
+
|
|
433
|
+
expect(getErrorIcon()).to.be.null
|
|
434
|
+
expect(getClearButton()).not.to.be.null
|
|
435
|
+
expect(getIcon()).to.be.null
|
|
436
|
+
|
|
437
|
+
el.value = ""
|
|
438
|
+
await elementUpdated(el)
|
|
439
|
+
|
|
440
|
+
el.focus()
|
|
441
|
+
await sendKeys({ type: "40" })
|
|
442
|
+
await sendKeys({ press: "Tab" })
|
|
443
|
+
await elementUpdated(el)
|
|
444
|
+
|
|
445
|
+
expect(getErrorIcon()).not.to.be.null
|
|
446
|
+
expect(getClearButton()).to.be.null
|
|
447
|
+
expect(getIcon()).to.be.null
|
|
448
|
+
})
|
|
22
449
|
})
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { html, LitElement } from "lit"
|
|
2
|
-
import { defineElement } from "../../lib/defineElement.js"
|
|
3
2
|
import styles from "./menu.css"
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -12,7 +11,3 @@ export class LeuMenu extends LitElement {
|
|
|
12
11
|
return html`<slot></slot>`
|
|
13
12
|
}
|
|
14
13
|
}
|
|
15
|
-
|
|
16
|
-
export function defineMenuElements() {
|
|
17
|
-
defineElement("menu", LeuMenu)
|
|
18
|
-
}
|