@statistikzh/leu 0.1.0 → 0.2.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/CHANGELOG.md +18 -0
- package/README.md +27 -2
- package/dist/Input.js +8 -0
- package/dist/Menu.js +10 -3
- package/dist/Select.js +23 -7
- package/dist/theme.css +7 -7
- package/package.json +1 -1
- package/src/components/accordion/Accordion.js +102 -0
- package/src/components/accordion/accordion.css +160 -0
- package/src/components/accordion/leu-accordion.js +3 -0
- package/src/components/accordion/stories/accordion.stories.js +55 -0
- package/src/components/accordion/test/accordion.test.js +22 -0
- package/src/components/input/Input.js +10 -0
- package/src/components/menu/menu.css +9 -3
- package/src/components/select/Select.js +28 -8
- package/src/styles/custom-properties.css +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.0](https://github.com/statistikZH/leu/compare/v0.1.0...v0.2.0) (2023-11-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **accordion:** implement accordion component ([b962d2c](https://github.com/statistikZH/leu/commit/b962d2c51aa17dbb909e8cbcb9ed0436d1b4b84d))
|
|
9
|
+
* **input:** move focus into the input field after clearing the value ([#55](https://github.com/statistikZH/leu/issues/55)) ([ec92026](https://github.com/statistikZH/leu/commit/ec9202689ba2997570531c272162be1da54dc156))
|
|
10
|
+
* **select:** add a more specific label if no options are available ([#57](https://github.com/statistikZH/leu/issues/57)) ([9ed62bf](https://github.com/statistikZH/leu/commit/9ed62bf5eb847c0814a92ff6066313eedf32b44a))
|
|
11
|
+
* **select:** close the select element if a click happens outside of the element ([#58](https://github.com/statistikZH/leu/issues/58)) ([b2df185](https://github.com/statistikZH/leu/commit/b2df18537acc294552984eb539706400305564bb))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* **input:** delegate focus to the actual input field ([ee9b21d](https://github.com/statistikZH/leu/commit/ee9b21de69322b1ebc822ab3a2f3bfb1a0ba6572))
|
|
17
|
+
* **menu:** enforce styles of the hr element with important as they are part of the light dom ([d6d7a3f](https://github.com/statistikZH/leu/commit/d6d7a3f1a2182854747908cf142678f352e1e014))
|
|
18
|
+
* **select:** actually set the filter input ref and use the correct attribute ([ee9b21d](https://github.com/statistikZH/leu/commit/ee9b21de69322b1ebc822ab3a2f3bfb1a0ba6572))
|
|
19
|
+
* **theme:** fix a typo inside the hex notation ([82a6961](https://github.com/statistikZH/leu/commit/82a6961ae44c93826f6d97924a845f4d418b8f3b))
|
|
20
|
+
|
|
3
21
|
## [0.1.0](https://github.com/statistikZH/leu/compare/v0.0.2...v0.1.0) (2023-11-15)
|
|
4
22
|
|
|
5
23
|
|
package/README.md
CHANGED
|
@@ -20,12 +20,37 @@ npm i @statistikzh/leu
|
|
|
20
20
|
|
|
21
21
|
## Usage
|
|
22
22
|
|
|
23
|
+
In order for the components to work, you need to load the theme styles and the font definitions globally.
|
|
24
|
+
The theme file is part of the package (`dist/theme.css`).
|
|
25
|
+
The fonts on the other hand have to be licensed and are therefore not included in the package.
|
|
26
|
+
|
|
27
|
+
If you have an environment that resolves bare module imports, you can use the library like this:
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<link rel="stylesheet" href="@statistikzh/leu/theme.css" />
|
|
31
|
+
<script type="module">
|
|
32
|
+
import "@statistikzh/leu/leu-input.js"
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<leu-input></leu-input>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### CDN
|
|
39
|
+
|
|
40
|
+
Browsers can't resolve bare module imports without import maps. But we can use a CDN to resolve the imports for us.
|
|
41
|
+
This is useful if you're just using plain HTML and JavaScript without any build or transformation steps.
|
|
42
|
+
Also this is applicable in an environment like [Observable](https://observablehq.com).
|
|
43
|
+
|
|
23
44
|
```html
|
|
45
|
+
<link
|
|
46
|
+
rel="stylesheet"
|
|
47
|
+
href="https://esm.run/@statistikzh/leu@0.1/dist/theme.css"
|
|
48
|
+
/>
|
|
24
49
|
<script type="module">
|
|
25
|
-
import "
|
|
50
|
+
import "https://esm.run/@statistikzh/leu@0.1/dist/leu-input.js"
|
|
26
51
|
</script>
|
|
27
52
|
|
|
28
|
-
<leu-
|
|
53
|
+
<leu-input></leu-input>
|
|
29
54
|
```
|
|
30
55
|
|
|
31
56
|
## Linting and formatting
|
package/dist/Input.js
CHANGED
|
@@ -443,6 +443,7 @@ class LeuInput extends LitElement {
|
|
|
443
443
|
*/
|
|
444
444
|
clear() {
|
|
445
445
|
this.value = "";
|
|
446
|
+
this._inputRef.value.focus();
|
|
446
447
|
this.dispatchEvent(new CustomEvent("input", {
|
|
447
448
|
bubbles: true,
|
|
448
449
|
composed: true
|
|
@@ -602,6 +603,13 @@ class LeuInput extends LitElement {
|
|
|
602
603
|
}
|
|
603
604
|
}
|
|
604
605
|
_defineProperty(LeuInput, "styles", css_248z);
|
|
606
|
+
/**
|
|
607
|
+
* @internal
|
|
608
|
+
*/
|
|
609
|
+
_defineProperty(LeuInput, "shadowRootOptions", {
|
|
610
|
+
...LitElement.shadowRootOptions,
|
|
611
|
+
delegatesFocus: true
|
|
612
|
+
});
|
|
605
613
|
_defineProperty(LeuInput, "properties", {
|
|
606
614
|
disabled: {
|
|
607
615
|
type: Boolean,
|
package/dist/Menu.js
CHANGED
|
@@ -10,10 +10,17 @@ var css_248z = css`:host,
|
|
|
10
10
|
--menu-divider-color: var(--leu-color-black-transp-20);
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
/*
|
|
14
|
+
* Set styles with important as the hr element is part of the
|
|
15
|
+
* light dom and therefore is affected by the global styles.
|
|
16
|
+
*/
|
|
17
|
+
|
|
13
18
|
:host ::slotted(hr) {
|
|
14
|
-
border: 0;
|
|
15
|
-
border-top: 1px solid var(--menu-divider-color);
|
|
16
|
-
margin: 0.5rem 0;
|
|
19
|
+
border: 0 !important;
|
|
20
|
+
border-top: 1px solid var(--menu-divider-color) !important;
|
|
21
|
+
margin: 0.5rem 0 !important;
|
|
22
|
+
padding: 0 !important;
|
|
23
|
+
background: none !important;
|
|
17
24
|
}
|
|
18
25
|
`;
|
|
19
26
|
|
package/dist/Select.js
CHANGED
|
@@ -369,6 +369,16 @@ class LeuSelect extends LitElement {
|
|
|
369
369
|
constructor() {
|
|
370
370
|
super();
|
|
371
371
|
_defineProperty(this, "hasSlotController", new HasSlotController(this, ["before", "after"]));
|
|
372
|
+
/**
|
|
373
|
+
* Handles clicks outside of the component to close the dropdown.
|
|
374
|
+
* @internal
|
|
375
|
+
* @param {MouseEvent} event
|
|
376
|
+
*/
|
|
377
|
+
_defineProperty(this, "handleDocumentClick", event => {
|
|
378
|
+
if (!this.contains(event.target) && this.open) {
|
|
379
|
+
this.closeDropdown();
|
|
380
|
+
}
|
|
381
|
+
});
|
|
372
382
|
/**
|
|
373
383
|
* @internal
|
|
374
384
|
* @param {KeyboardEvent} e
|
|
@@ -398,9 +408,17 @@ class LeuSelect extends LitElement {
|
|
|
398
408
|
this.optionFilterRef = createRef();
|
|
399
409
|
this.toggleButtonRef = createRef();
|
|
400
410
|
}
|
|
411
|
+
connectedCallback() {
|
|
412
|
+
super.connectedCallback();
|
|
413
|
+
document.addEventListener("click", this.handleDocumentClick);
|
|
414
|
+
}
|
|
415
|
+
disconnectedCallback() {
|
|
416
|
+
super.disconnectedCallback();
|
|
417
|
+
document.removeEventListener("click", this.handleDocumentClick);
|
|
418
|
+
}
|
|
401
419
|
updated(changedProperties) {
|
|
402
420
|
if (changedProperties.has("open") && this.open) {
|
|
403
|
-
if (this.
|
|
421
|
+
if (this.filterable) {
|
|
404
422
|
this.optionFilterRef.value.focus();
|
|
405
423
|
} else {
|
|
406
424
|
this.menuRef.value.focus();
|
|
@@ -446,11 +464,6 @@ class LeuSelect extends LitElement {
|
|
|
446
464
|
}
|
|
447
465
|
this.emitUpdateEvents();
|
|
448
466
|
}
|
|
449
|
-
clearOptionFilter() {
|
|
450
|
-
// refocus before removing the button, otherwise closeDropdown is triggered
|
|
451
|
-
this.optionFilterRef.value.focus();
|
|
452
|
-
this.optionFilter = "";
|
|
453
|
-
}
|
|
454
467
|
toggleDropdown() {
|
|
455
468
|
if (!this.disabled) {
|
|
456
469
|
this.open = !this.open;
|
|
@@ -525,7 +538,9 @@ class LeuSelect extends LitElement {
|
|
|
525
538
|
>
|
|
526
539
|
${LeuSelect.getOptionLabel(option)}
|
|
527
540
|
</leu-menu-item>`;
|
|
528
|
-
}) : html`<leu-menu-item disabled
|
|
541
|
+
}) : html`<leu-menu-item disabled
|
|
542
|
+
>${this.optionFilter === "" ? "Keine Optionen" : "Keine Resultate"}</leu-menu-item
|
|
543
|
+
>`}
|
|
529
544
|
</leu-menu>
|
|
530
545
|
`;
|
|
531
546
|
}
|
|
@@ -536,6 +551,7 @@ class LeuSelect extends LitElement {
|
|
|
536
551
|
size="small"
|
|
537
552
|
@input=${this.handleFilterInput}
|
|
538
553
|
clearable
|
|
554
|
+
ref=${ref(this.optionFilterRef)}
|
|
539
555
|
>Nach Stichwort filtern</leu-input
|
|
540
556
|
>`;
|
|
541
557
|
}
|
package/dist/theme.css
CHANGED
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
--leu-color-accent-violet: #7f3da7;
|
|
30
30
|
--leu-color-accent-gray: var(--leu-color-black-60);
|
|
31
31
|
|
|
32
|
-
--leu-color-accent-blue-soft:
|
|
33
|
-
--leu-color-accent-darkblue-soft:
|
|
34
|
-
--leu-color-accent-turquoise-soft:
|
|
35
|
-
--leu-color-accent-green-soft:
|
|
36
|
-
--leu-color-accent-bordeaux-soft:
|
|
37
|
-
--leu-color-accent-magenta-soft:
|
|
38
|
-
--leu-color-accent-violet-soft:
|
|
32
|
+
--leu-color-accent-blue-soft: #edf5fa;
|
|
33
|
+
--leu-color-accent-darkblue-soft: #e0e8ee;
|
|
34
|
+
--leu-color-accent-turquoise-soft: #e8f3f2;
|
|
35
|
+
--leu-color-accent-green-soft: #ebf6eb;
|
|
36
|
+
--leu-color-accent-bordeaux-soft: #f6e3ea;
|
|
37
|
+
--leu-color-accent-magenta-soft: #fcedf3;
|
|
38
|
+
--leu-color-accent-violet-soft: #ece2f1;
|
|
39
39
|
--leu-color-accent-gray-soft: var(--leu-color-black-10);
|
|
40
40
|
|
|
41
41
|
--leu-color-func-cyan: #009ee0;
|
package/package.json
CHANGED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { LitElement, nothing } from "lit"
|
|
2
|
+
import { html, unsafeStatic } from "lit/static-html.js"
|
|
3
|
+
|
|
4
|
+
import { defineElement } from "../../lib/defineElement.js"
|
|
5
|
+
import styles from "./accordion.css"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @tagname leu-accordion
|
|
9
|
+
* @slot content - The content of the accordion. No styles will be applied to the content.
|
|
10
|
+
* @prop {Number} headingLevel - The heading level of the accordion title. Must be between 1 and 6.
|
|
11
|
+
* @prop {Boolean} open - The expanded state of the accordion.
|
|
12
|
+
* @prop {String} label - The label (title) of the accordion.
|
|
13
|
+
* @prop {String} labelPrefix - The prefix of the accordion label. e.g. "01"
|
|
14
|
+
* @attr {Number} heading-level - The heading level of the accordion title. Must be between 1 and 6.
|
|
15
|
+
* @attr {String} label-prefix - The prefix of the accordion label. e.g. "01"
|
|
16
|
+
*/
|
|
17
|
+
export class LeuAccordion extends LitElement {
|
|
18
|
+
static styles = styles
|
|
19
|
+
|
|
20
|
+
/** @internal */
|
|
21
|
+
static shadowRootOptions = {
|
|
22
|
+
...LitElement.shadowRootOptions,
|
|
23
|
+
delegatesFocus: true,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static properties = {
|
|
27
|
+
headingLevel: { type: Number, attribute: "heading-level" },
|
|
28
|
+
open: { type: Boolean, reflect: true },
|
|
29
|
+
label: { type: String },
|
|
30
|
+
labelPrefix: { type: String, attribute: "label-prefix" },
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
constructor() {
|
|
34
|
+
super()
|
|
35
|
+
this.headingLevel = 2
|
|
36
|
+
this.open = false
|
|
37
|
+
this.label = ""
|
|
38
|
+
this.labelPrefix = ""
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Determines the heading tag of the accordion toggle.
|
|
43
|
+
* The headingLevel shouldn't be used directly to render the heading tag
|
|
44
|
+
* in order to avoid XSS issues.
|
|
45
|
+
* @returns {String} The heading tag of the accordion toggle.
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
_getHeadingTag() {
|
|
49
|
+
let level = 2
|
|
50
|
+
if (this.headingLevel > 0 && this.headingLevel < 7) {
|
|
51
|
+
level = this.headingLevel
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return `h${level}`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Toggles the accordion open state.
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
_handleToggleClick() {
|
|
62
|
+
this.open = !this.open
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
render() {
|
|
66
|
+
const hTag = this._getHeadingTag()
|
|
67
|
+
|
|
68
|
+
/* The eslint rules don't recognize html import from lit/static-html.js */
|
|
69
|
+
/* eslint-disable lit/binding-positions, lit/no-invalid-html */
|
|
70
|
+
return html`<${unsafeStatic(hTag)} class="heading"><button
|
|
71
|
+
id="toggle"
|
|
72
|
+
type="button"
|
|
73
|
+
class="button"
|
|
74
|
+
aria-controls="content"
|
|
75
|
+
aria-expanded="${this.open}"
|
|
76
|
+
@click=${this._handleToggleClick}
|
|
77
|
+
>
|
|
78
|
+
${
|
|
79
|
+
this.labelPrefix
|
|
80
|
+
? html`<span class="label-prefix">${this.labelPrefix}</span>`
|
|
81
|
+
: nothing
|
|
82
|
+
}
|
|
83
|
+
<span class="label">${this.label}</span>
|
|
84
|
+
<div class="plus"></div>
|
|
85
|
+
</button></${unsafeStatic(hTag)}>
|
|
86
|
+
<div
|
|
87
|
+
id="content"
|
|
88
|
+
class="content"
|
|
89
|
+
aria-labelledby="toggle"
|
|
90
|
+
role="region"
|
|
91
|
+
?hidden=${!this.open}
|
|
92
|
+
>
|
|
93
|
+
<slot name="content"></slot>
|
|
94
|
+
</div>
|
|
95
|
+
<hr class="divider" />`
|
|
96
|
+
}
|
|
97
|
+
/* eslint-enable lit/binding-positions, lit/no-invalid-html */
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function defineAccordionElements() {
|
|
101
|
+
defineElement("accordion", LeuAccordion)
|
|
102
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
@import url("../../styles/custom-media.css");
|
|
2
|
+
|
|
3
|
+
:host,
|
|
4
|
+
:host * {
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
:host {
|
|
9
|
+
--accordion-font-regular: var(--leu-font-regular);
|
|
10
|
+
--accordion-font-black: var(--leu-font-black);
|
|
11
|
+
|
|
12
|
+
--accordion-toggle-font: var(--accordion-font-black);
|
|
13
|
+
|
|
14
|
+
--label-color: var(--leu-color-black-60);
|
|
15
|
+
--label-color-active: var(--leu-color-black-100);
|
|
16
|
+
|
|
17
|
+
--divider-color: var(--leu-color-black-20);
|
|
18
|
+
--divider-color-active: var(--leu-color-black-100);
|
|
19
|
+
|
|
20
|
+
--transition: 0.1s ease;
|
|
21
|
+
|
|
22
|
+
font-family: var(--chip-font-regular);
|
|
23
|
+
|
|
24
|
+
position: relative;
|
|
25
|
+
display: grid;
|
|
26
|
+
grid-template-rows: auto 0fr;
|
|
27
|
+
|
|
28
|
+
transition: grid-template-rows var(--transition);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
:host([open]) {
|
|
32
|
+
grid-template-rows: auto 1fr;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.heading {
|
|
36
|
+
margin: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.button {
|
|
40
|
+
width: 100%;
|
|
41
|
+
background: none;
|
|
42
|
+
padding: 1rem 0;
|
|
43
|
+
margin: none;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
|
|
46
|
+
border: none;
|
|
47
|
+
|
|
48
|
+
color: var(--label-color);
|
|
49
|
+
font-family: var(--accordion-toggle-font);
|
|
50
|
+
font-size: 1rem;
|
|
51
|
+
line-height: 1.5rem;
|
|
52
|
+
text-align: left;
|
|
53
|
+
|
|
54
|
+
display: flex;
|
|
55
|
+
gap: 0.25rem;
|
|
56
|
+
|
|
57
|
+
transition: color var(--transition);
|
|
58
|
+
|
|
59
|
+
@media (--viewport-regular) {
|
|
60
|
+
font-size: 1.125rem;
|
|
61
|
+
gap: 0.8rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@media (--viewport-xlarge) {
|
|
65
|
+
font-size: 1.25rem;
|
|
66
|
+
line-height: 1.625rem;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.button:focus-visible {
|
|
71
|
+
outline: 2px solid var(--leu-color-func-cyan);
|
|
72
|
+
outline-offset: 4px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.button:hover,
|
|
76
|
+
.button:focus-visible,
|
|
77
|
+
:host([open]) .button {
|
|
78
|
+
color: var(--label-color-active);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.plus {
|
|
82
|
+
position: relative;
|
|
83
|
+
flex: 0 0 1rem;
|
|
84
|
+
aspect-ratio: 1;
|
|
85
|
+
align-self: center;
|
|
86
|
+
margin-inline: 0.5rem;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.plus::before,
|
|
90
|
+
.plus::after {
|
|
91
|
+
content: "";
|
|
92
|
+
|
|
93
|
+
position: absolute;
|
|
94
|
+
top: calc(50% - 0.0625rem);
|
|
95
|
+
left: 0;
|
|
96
|
+
|
|
97
|
+
display: block;
|
|
98
|
+
width: 1rem;
|
|
99
|
+
height: 0.125rem;
|
|
100
|
+
aspect-ratio: 1 / 0.125;
|
|
101
|
+
background-color: currentcolor;
|
|
102
|
+
transition: transform var(--transition);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.plus::before {
|
|
106
|
+
transform: rotate(90deg);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
:host([open]) .plus::before {
|
|
110
|
+
transform: rotate(180deg);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.label {
|
|
114
|
+
display: block;
|
|
115
|
+
flex-grow: 1;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.content {
|
|
119
|
+
overflow: hidden;
|
|
120
|
+
transition: visibility var(--transition), opacity var(--transition);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.content[hidden] {
|
|
124
|
+
display: block;
|
|
125
|
+
visibility: hidden;
|
|
126
|
+
opacity: 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
slot[name="content"] {
|
|
130
|
+
display: block;
|
|
131
|
+
padding: 0.5rem 0 1.5rem;
|
|
132
|
+
|
|
133
|
+
@media (--viewport-medium) {
|
|
134
|
+
padding: 0.75rem 0 1.5rem;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@media (--viewport-xlarge) {
|
|
138
|
+
padding: 1rem 0 2.5rem;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.divider {
|
|
143
|
+
position: absolute;
|
|
144
|
+
top: 100%;
|
|
145
|
+
left: 0;
|
|
146
|
+
|
|
147
|
+
width: 100%;
|
|
148
|
+
height: 1px;
|
|
149
|
+
margin: 0;
|
|
150
|
+
|
|
151
|
+
border: none;
|
|
152
|
+
background-color: var(--divider-color);
|
|
153
|
+
|
|
154
|
+
transition: transform var(--transition), background-color var(--transition);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
:host(:not([open])) .heading:is(:hover, :focus-visible) ~ .divider {
|
|
158
|
+
background-color: var(--divider-color-active);
|
|
159
|
+
transform: scaleY(3);
|
|
160
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import { ifDefined } from "lit/directives/if-defined.js"
|
|
3
|
+
|
|
4
|
+
import "../leu-accordion.js"
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: "Accordion",
|
|
8
|
+
component: "leu-accordion",
|
|
9
|
+
argTypes: {
|
|
10
|
+
headingLevel: {
|
|
11
|
+
control: {
|
|
12
|
+
type: "select",
|
|
13
|
+
options: [0, 1, 2, 3, 4, 5, 6],
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
content: {
|
|
17
|
+
control: {
|
|
18
|
+
type: "text",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function Template(args) {
|
|
25
|
+
return html` <leu-accordion
|
|
26
|
+
heading-level=${ifDefined(args.headingLevel)}
|
|
27
|
+
label=${ifDefined(args.label)}
|
|
28
|
+
label-prefix=${ifDefined(args.labelPrefix)}
|
|
29
|
+
>
|
|
30
|
+
<div slot="content">${args.content}</div>
|
|
31
|
+
</leu-accordion>`
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const Regular = Template.bind({})
|
|
35
|
+
Regular.args = {
|
|
36
|
+
headingLevel: 2,
|
|
37
|
+
label:
|
|
38
|
+
"Akkordeontitel der lang und noch länger werden kann und dann umbricht",
|
|
39
|
+
content: `Regular Interessierte können ab sofort die Genauigkeit ihrer Smartphones
|
|
40
|
+
und Navigationsgeräte überprüfen. Die Baudirektion hat beim Landesmuseum
|
|
41
|
+
in Zürich einen Kontrollpunkt beim Landesmuseum in Zürich einen
|
|
42
|
+
Kontrollpunktfür mobile Geräte eingerichtet – den ersten in der
|
|
43
|
+
Schweiz.P, Helvetic Roman Interessierte können ab sofort die Genauigkeit
|
|
44
|
+
ihrer Smartphones und Navigationsgeräte überprüfen.
|
|
45
|
+
|
|
46
|
+
Die Zürich einen Kontrollpunktfür mobile einen Kontrollpunkt beim
|
|
47
|
+
Landesmuseum in Zürich einen Kontrollpunktfür mobile Geräte eingerichtet
|
|
48
|
+
– den ersten in der Schweiz.`,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const Prefix = Template.bind({})
|
|
52
|
+
Prefix.args = {
|
|
53
|
+
...Regular.args,
|
|
54
|
+
labelPrefix: "01",
|
|
55
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import { fixture, expect } from "@open-wc/testing"
|
|
3
|
+
|
|
4
|
+
import "../leu-accordion.js"
|
|
5
|
+
|
|
6
|
+
async function defaultFixture() {
|
|
7
|
+
return fixture(html` <leu-accordion /> `)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
describe("LeuAccordion", () => {
|
|
11
|
+
it("is a defined element", async () => {
|
|
12
|
+
const el = await customElements.get("leu-accordion")
|
|
13
|
+
|
|
14
|
+
await expect(el).not.to.be.undefined
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it("passes the a11y audit", async () => {
|
|
18
|
+
const el = await defaultFixture()
|
|
19
|
+
|
|
20
|
+
await expect(el).shadowDom.to.be.accessible()
|
|
21
|
+
})
|
|
22
|
+
})
|
|
@@ -65,6 +65,14 @@ const VALIDATION_MESSAGES = {
|
|
|
65
65
|
export class LeuInput extends LitElement {
|
|
66
66
|
static styles = styles
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* @internal
|
|
70
|
+
*/
|
|
71
|
+
static shadowRootOptions = {
|
|
72
|
+
...LitElement.shadowRootOptions,
|
|
73
|
+
delegatesFocus: true,
|
|
74
|
+
}
|
|
75
|
+
|
|
68
76
|
static properties = {
|
|
69
77
|
disabled: { type: Boolean, reflect: true },
|
|
70
78
|
required: { type: Boolean, reflect: true },
|
|
@@ -223,6 +231,8 @@ export class LeuInput extends LitElement {
|
|
|
223
231
|
clear() {
|
|
224
232
|
this.value = ""
|
|
225
233
|
|
|
234
|
+
this._inputRef.value.focus()
|
|
235
|
+
|
|
226
236
|
this.dispatchEvent(
|
|
227
237
|
new CustomEvent("input", { bubbles: true, composed: true })
|
|
228
238
|
)
|
|
@@ -7,8 +7,14 @@
|
|
|
7
7
|
--menu-divider-color: var(--leu-color-black-transp-20);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/*
|
|
11
|
+
* Set styles with important as the hr element is part of the
|
|
12
|
+
* light dom and therefore is affected by the global styles.
|
|
13
|
+
*/
|
|
10
14
|
:host ::slotted(hr) {
|
|
11
|
-
border: 0;
|
|
12
|
-
border-top: 1px solid var(--menu-divider-color);
|
|
13
|
-
margin: 0.5rem 0;
|
|
15
|
+
border: 0 !important;
|
|
16
|
+
border-top: 1px solid var(--menu-divider-color) !important;
|
|
17
|
+
margin: 0.5rem 0 !important;
|
|
18
|
+
padding: 0 !important;
|
|
19
|
+
background: none !important;
|
|
14
20
|
}
|
|
@@ -74,9 +74,19 @@ export class LeuSelect extends LitElement {
|
|
|
74
74
|
this.toggleButtonRef = createRef()
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
connectedCallback() {
|
|
78
|
+
super.connectedCallback()
|
|
79
|
+
document.addEventListener("click", this.handleDocumentClick)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
disconnectedCallback() {
|
|
83
|
+
super.disconnectedCallback()
|
|
84
|
+
document.removeEventListener("click", this.handleDocumentClick)
|
|
85
|
+
}
|
|
86
|
+
|
|
77
87
|
updated(changedProperties) {
|
|
78
88
|
if (changedProperties.has("open") && this.open) {
|
|
79
|
-
if (this.
|
|
89
|
+
if (this.filterable) {
|
|
80
90
|
this.optionFilterRef.value.focus()
|
|
81
91
|
} else {
|
|
82
92
|
this.menuRef.value.focus()
|
|
@@ -86,6 +96,17 @@ export class LeuSelect extends LitElement {
|
|
|
86
96
|
}
|
|
87
97
|
}
|
|
88
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Handles clicks outside of the component to close the dropdown.
|
|
101
|
+
* @internal
|
|
102
|
+
* @param {MouseEvent} event
|
|
103
|
+
*/
|
|
104
|
+
handleDocumentClick = (event) => {
|
|
105
|
+
if (!this.contains(event.target) && this.open) {
|
|
106
|
+
this.closeDropdown()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
89
110
|
/**
|
|
90
111
|
* @internal
|
|
91
112
|
* @param {KeyboardEvent} e
|
|
@@ -143,12 +164,6 @@ export class LeuSelect extends LitElement {
|
|
|
143
164
|
this.emitUpdateEvents()
|
|
144
165
|
}
|
|
145
166
|
|
|
146
|
-
clearOptionFilter() {
|
|
147
|
-
// refocus before removing the button, otherwise closeDropdown is triggered
|
|
148
|
-
this.optionFilterRef.value.focus()
|
|
149
|
-
this.optionFilter = ""
|
|
150
|
-
}
|
|
151
|
-
|
|
152
167
|
toggleDropdown() {
|
|
153
168
|
if (!this.disabled) {
|
|
154
169
|
this.open = !this.open
|
|
@@ -242,7 +257,11 @@ export class LeuSelect extends LitElement {
|
|
|
242
257
|
${LeuSelect.getOptionLabel(option)}
|
|
243
258
|
</leu-menu-item>`
|
|
244
259
|
})
|
|
245
|
-
: html`<leu-menu-item disabled
|
|
260
|
+
: html`<leu-menu-item disabled
|
|
261
|
+
>${this.optionFilter === ""
|
|
262
|
+
? "Keine Optionen"
|
|
263
|
+
: "Keine Resultate"}</leu-menu-item
|
|
264
|
+
>`}
|
|
246
265
|
</leu-menu>
|
|
247
266
|
`
|
|
248
267
|
}
|
|
@@ -254,6 +273,7 @@ export class LeuSelect extends LitElement {
|
|
|
254
273
|
size="small"
|
|
255
274
|
@input=${this.handleFilterInput}
|
|
256
275
|
clearable
|
|
276
|
+
ref=${ref(this.optionFilterRef)}
|
|
257
277
|
>Nach Stichwort filtern</leu-input
|
|
258
278
|
>`
|
|
259
279
|
}
|
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
--leu-color-accent-violet: #7f3da7;
|
|
30
30
|
--leu-color-accent-gray: var(--leu-color-black-60);
|
|
31
31
|
|
|
32
|
-
--leu-color-accent-blue-soft:
|
|
33
|
-
--leu-color-accent-darkblue-soft:
|
|
34
|
-
--leu-color-accent-turquoise-soft:
|
|
35
|
-
--leu-color-accent-green-soft:
|
|
36
|
-
--leu-color-accent-bordeaux-soft:
|
|
37
|
-
--leu-color-accent-magenta-soft:
|
|
38
|
-
--leu-color-accent-violet-soft:
|
|
32
|
+
--leu-color-accent-blue-soft: #edf5fa;
|
|
33
|
+
--leu-color-accent-darkblue-soft: #e0e8ee;
|
|
34
|
+
--leu-color-accent-turquoise-soft: #e8f3f2;
|
|
35
|
+
--leu-color-accent-green-soft: #ebf6eb;
|
|
36
|
+
--leu-color-accent-bordeaux-soft: #f6e3ea;
|
|
37
|
+
--leu-color-accent-magenta-soft: #fcedf3;
|
|
38
|
+
--leu-color-accent-violet-soft: #ece2f1;
|
|
39
39
|
--leu-color-accent-gray-soft: var(--leu-color-black-10);
|
|
40
40
|
|
|
41
41
|
--leu-color-func-cyan: #009ee0;
|