@statistikzh/leu 0.5.1 → 0.6.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/.husky/commit-msg +0 -3
- package/.husky/pre-commit +0 -3
- package/CHANGELOG.md +40 -0
- package/dist/Accordion.d.ts +10 -9
- package/dist/Accordion.d.ts.map +1 -1
- package/dist/Accordion.js +12 -11
- package/dist/Breadcrumb.d.ts +4 -4
- package/dist/Breadcrumb.d.ts.map +1 -1
- package/dist/Breadcrumb.js +28 -26
- package/dist/{Button-5326c982.d.ts → Button-9692e403.d.ts} +10 -11
- package/dist/Button-9692e403.d.ts.map +1 -0
- package/dist/{Button-5326c982.js → Button-9692e403.js} +57 -67
- package/dist/Button.d.ts +1 -1
- package/dist/Button.js +3 -3
- package/dist/ButtonGroup.d.ts +2 -2
- package/dist/ButtonGroup.d.ts.map +1 -1
- package/dist/ButtonGroup.js +3 -3
- package/dist/Checkbox.d.ts +4 -3
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/Checkbox.js +14 -19
- package/dist/CheckboxGroup.d.ts +2 -2
- package/dist/CheckboxGroup.d.ts.map +1 -1
- package/dist/CheckboxGroup.js +4 -6
- package/dist/Chip.d.ts +2 -2
- package/dist/Chip.d.ts.map +1 -1
- package/dist/Chip.js +6 -13
- package/dist/ChipGroup.d.ts +9 -7
- package/dist/ChipGroup.d.ts.map +1 -1
- package/dist/ChipGroup.js +8 -5
- package/dist/ChipLink.d.ts +2 -1
- package/dist/ChipLink.d.ts.map +1 -1
- package/dist/ChipLink.js +4 -7
- package/dist/ChipRemovable.d.ts +0 -2
- package/dist/ChipRemovable.d.ts.map +1 -1
- package/dist/ChipRemovable.js +8 -11
- package/dist/ChipSelectable.d.ts +9 -1
- package/dist/ChipSelectable.d.ts.map +1 -1
- package/dist/ChipSelectable.js +12 -16
- package/dist/Dropdown.d.ts +9 -5
- package/dist/Dropdown.d.ts.map +1 -1
- package/dist/Dropdown.js +68 -32
- package/dist/Icon.d.ts +20 -0
- package/dist/Icon.d.ts.map +1 -0
- package/dist/{icon-03e86700.js → Icon.js} +61 -32
- package/dist/Input.d.ts +7 -16
- package/dist/Input.d.ts.map +1 -1
- package/dist/Input.js +24 -28
- package/dist/LeuElement-6de6f209.d.ts +7 -0
- package/dist/LeuElement-6de6f209.d.ts.map +1 -0
- package/dist/LeuElement-6de6f209.js +43 -0
- package/dist/Menu.d.ts +24 -2
- package/dist/Menu.d.ts.map +1 -1
- package/dist/Menu.js +120 -3
- package/dist/MenuItem.d.ts +28 -11
- package/dist/MenuItem.d.ts.map +1 -1
- package/dist/MenuItem.js +110 -63
- package/dist/Pagination.d.ts +10 -3
- package/dist/Pagination.d.ts.map +1 -1
- package/dist/Pagination.js +24 -21
- package/dist/Popup.d.ts +21 -3
- package/dist/Popup.d.ts.map +1 -1
- package/dist/Popup.js +44 -19
- package/dist/Radio.d.ts +4 -2
- package/dist/Radio.d.ts.map +1 -1
- package/dist/Radio.js +9 -16
- package/dist/RadioGroup.d.ts +2 -2
- package/dist/RadioGroup.d.ts.map +1 -1
- package/dist/RadioGroup.js +4 -6
- package/dist/ScrollTop.d.ts +2 -2
- package/dist/ScrollTop.d.ts.map +1 -1
- package/dist/ScrollTop.js +10 -8
- package/dist/Select.d.ts +75 -37
- package/dist/Select.d.ts.map +1 -1
- package/dist/Select.js +279 -183
- package/dist/Table.d.ts +2 -6
- package/dist/Table.d.ts.map +1 -1
- package/dist/Table.js +17 -18
- package/dist/VisuallyHidden.d.ts +2 -2
- package/dist/VisuallyHidden.d.ts.map +1 -1
- package/dist/VisuallyHidden.js +5 -7
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -14
- package/dist/leu-accordion.d.ts.map +1 -1
- package/dist/leu-accordion.js +2 -3
- package/dist/leu-breadcrumb.d.ts.map +1 -1
- package/dist/leu-breadcrumb.js +4 -10
- package/dist/leu-button-group.d.ts.map +1 -1
- package/dist/leu-button-group.js +2 -3
- package/dist/leu-button.d.ts +1 -1
- package/dist/leu-button.d.ts.map +1 -1
- package/dist/leu-button.js +4 -5
- package/dist/leu-checkbox-group.d.ts.map +1 -1
- package/dist/leu-checkbox-group.js +2 -3
- package/dist/leu-checkbox.d.ts.map +1 -1
- package/dist/leu-checkbox.js +3 -4
- package/dist/leu-chip-group.d.ts.map +1 -1
- package/dist/leu-chip-group.js +2 -3
- package/dist/leu-chip-link.d.ts.map +1 -1
- package/dist/leu-chip-link.js +2 -3
- package/dist/leu-chip-removable.d.ts.map +1 -1
- package/dist/leu-chip-removable.js +3 -4
- package/dist/leu-chip-selectable.d.ts.map +1 -1
- package/dist/leu-chip-selectable.js +2 -3
- package/dist/leu-dropdown.d.ts.map +1 -1
- package/dist/leu-dropdown.js +5 -10
- package/dist/leu-icon.d.ts +3 -0
- package/dist/leu-icon.d.ts.map +1 -0
- package/dist/leu-icon.js +7 -0
- package/dist/leu-input.d.ts.map +1 -1
- package/dist/leu-input.js +3 -4
- package/dist/leu-menu-item.d.ts.map +1 -1
- package/dist/leu-menu-item.js +3 -5
- package/dist/leu-menu.d.ts.map +1 -1
- package/dist/leu-menu.js +5 -3
- package/dist/leu-pagination.d.ts.map +1 -1
- package/dist/leu-pagination.js +4 -7
- package/dist/leu-popup.d.ts.map +1 -1
- package/dist/leu-popup.js +2 -3
- package/dist/leu-radio-group.d.ts.map +1 -1
- package/dist/leu-radio-group.js +2 -3
- package/dist/leu-radio.d.ts.map +1 -1
- package/dist/leu-radio.js +2 -3
- package/dist/leu-scroll-top.d.ts.map +1 -1
- package/dist/leu-scroll-top.js +4 -6
- package/dist/leu-select.d.ts.map +1 -1
- package/dist/leu-select.js +5 -13
- package/dist/leu-table.d.ts.map +1 -1
- package/dist/leu-table.js +4 -8
- package/dist/leu-visually-hidden.d.ts.map +1 -1
- package/dist/leu-visually-hidden.js +2 -3
- package/dist/theme.css +2 -0
- package/dist/vscode.html-custom-data.json +116 -79
- package/dist/vue/index.d.ts +80 -76
- package/dist/web-types.json +405 -270
- package/package.json +9 -12
- package/scripts/generate-component/templates/[Name].js +6 -3
- package/scripts/generate-component/templates/test/[name].test.js +1 -1
- package/src/components/accordion/Accordion.js +13 -10
- package/src/components/accordion/leu-accordion.js +1 -2
- package/src/components/breadcrumb/Breadcrumb.js +31 -18
- package/src/components/breadcrumb/leu-breadcrumb.js +1 -2
- package/src/components/button/Button.js +45 -71
- package/src/components/button/button.css +11 -9
- package/src/components/button/leu-button.js +1 -2
- package/src/components/button/stories/button.stories.js +60 -19
- package/src/components/button/test/button.test.js +26 -63
- package/src/components/button-group/ButtonGroup.js +4 -2
- package/src/components/button-group/leu-button-group.js +1 -2
- package/src/components/checkbox/Checkbox.js +17 -11
- package/src/components/checkbox/CheckboxGroup.js +6 -3
- package/src/components/checkbox/leu-checkbox-group.js +1 -2
- package/src/components/checkbox/leu-checkbox.js +1 -2
- package/src/components/checkbox/stories/checkbox-group.stories.js +10 -26
- package/src/components/checkbox/stories/checkbox.stories.js +2 -7
- package/src/components/checkbox/test/checkbox-group.test.js +6 -21
- package/src/components/checkbox/test/checkbox.test.js +1 -12
- package/src/components/chip/Chip.js +5 -4
- package/src/components/chip/ChipGroup.js +10 -4
- package/src/components/chip/ChipLink.js +3 -7
- package/src/components/chip/ChipRemovable.js +8 -11
- package/src/components/chip/ChipSelectable.js +11 -17
- package/src/components/chip/chip.css +3 -4
- package/src/components/chip/leu-chip-group.js +1 -2
- package/src/components/chip/leu-chip-link.js +1 -2
- package/src/components/chip/leu-chip-removable.js +1 -2
- package/src/components/chip/leu-chip-selectable.js +1 -2
- package/src/components/chip/stories/chip-link.stories.js +3 -5
- package/src/components/chip/stories/chip-removable.stories.js +3 -4
- package/src/components/chip/stories/chip-selectable.stories.js +2 -2
- package/src/components/chip/test/chip-group.test.js +15 -30
- package/src/components/chip/test/chip-link.test.js +2 -6
- package/src/components/chip/test/chip-removable.test.js +4 -10
- package/src/components/chip/test/chip-selectable.test.js +3 -5
- package/src/components/dropdown/Dropdown.js +79 -26
- package/src/components/dropdown/leu-dropdown.js +1 -2
- package/src/components/dropdown/stories/dropdown.stories.js +30 -7
- package/src/components/dropdown/test/dropdown.test.js +5 -5
- package/src/components/icon/Icon.js +55 -0
- package/src/components/icon/icon.css +6 -0
- package/src/components/icon/leu-icon.js +5 -0
- package/src/components/icon/{icon.js → paths.js} +4 -37
- package/src/components/icon/stories/icon.stories.js +47 -0
- package/src/components/icon/test/icon.test.js +23 -40
- package/src/components/input/Input.js +21 -23
- package/src/components/input/input.css +4 -2
- package/src/components/input/leu-input.js +1 -2
- package/src/components/input/stories/input.stories.js +2 -2
- package/src/components/input/test/input.test.js +2 -0
- package/src/components/menu/Menu.js +143 -2
- package/src/components/menu/MenuItem.js +104 -52
- package/src/components/menu/leu-menu-item.js +1 -2
- package/src/components/menu/leu-menu.js +1 -2
- package/src/components/menu/menu-item.css +11 -4
- package/src/components/menu/stories/menu-item.stories.js +15 -4
- package/src/components/menu/stories/menu.stories.js +34 -7
- package/src/components/menu/test/menu-item.test.js +88 -82
- package/src/components/menu/test/menu.test.js +101 -8
- package/src/components/pagination/Pagination.js +27 -18
- package/src/components/pagination/leu-pagination.js +1 -2
- package/src/components/popup/Popup.js +39 -16
- package/src/components/popup/leu-popup.js +1 -2
- package/src/components/popup/popup.css +1 -0
- package/src/components/radio/Radio.js +12 -7
- package/src/components/radio/RadioGroup.js +6 -3
- package/src/components/radio/leu-radio-group.js +1 -2
- package/src/components/radio/leu-radio.js +1 -2
- package/src/components/radio/stories/radio-group.stories.js +5 -19
- package/src/components/radio/stories/radio.stories.js +2 -7
- package/src/components/radio/test/radio-group.test.js +6 -9
- package/src/components/radio/test/radio.test.js +3 -13
- package/src/components/scroll-top/ScrollTop.js +15 -5
- package/src/components/scroll-top/leu-scroll-top.js +1 -2
- package/src/components/select/Select.js +279 -175
- package/src/components/select/leu-select.js +1 -2
- package/src/components/select/select.css +20 -12
- package/src/components/select/stories/select.stories.js +16 -2
- package/src/components/select/test/select.test.js +191 -37
- package/src/components/table/Table.js +15 -9
- package/src/components/table/leu-table.js +1 -2
- package/src/components/table/table.css +3 -1
- package/src/components/visually-hidden/VisuallyHidden.js +6 -2
- package/src/components/visually-hidden/leu-visually-hidden.js +1 -2
- package/src/lib/LeuElement.js +23 -0
- package/src/lib/a11y.js +26 -0
- package/src/styles/custom-properties.css +2 -0
- package/web-test-runner.config.mjs +2 -0
- package/dist/Button-5326c982.d.ts.map +0 -1
- package/dist/_rollupPluginBabelHelpers-20f659f4.d.ts +0 -3
- package/dist/_rollupPluginBabelHelpers-20f659f4.d.ts.map +0 -1
- package/dist/_rollupPluginBabelHelpers-20f659f4.js +0 -30
- package/dist/defineElement-40372b4b.d.ts +0 -9
- package/dist/defineElement-40372b4b.d.ts.map +0 -1
- package/dist/defineElement-40372b4b.js +0 -15
- package/dist/icon-03e86700.d.ts +0 -11
- package/dist/icon-03e86700.d.ts.map +0 -1
- package/src/lib/defineElement.js +0 -13
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { html,
|
|
1
|
+
import { html, nothing } from "lit"
|
|
2
2
|
import { classMap } from "lit/directives/class-map.js"
|
|
3
|
-
|
|
4
|
-
import { map } from "lit/directives/map.js"
|
|
5
|
-
import { ifDefined } from "lit/directives/if-defined.js"
|
|
6
3
|
import { createRef, ref } from "lit/directives/ref.js"
|
|
7
4
|
|
|
8
|
-
import {
|
|
5
|
+
import { ifDefined } from "lit/directives/if-defined.js"
|
|
6
|
+
import { LeuElement } from "../../lib/LeuElement.js"
|
|
9
7
|
import { HasSlotController } from "../../lib/hasSlotController.js"
|
|
10
|
-
|
|
11
|
-
import "../
|
|
12
|
-
import "../menu/
|
|
13
|
-
import "../
|
|
14
|
-
import "../
|
|
8
|
+
|
|
9
|
+
import { LeuButton } from "../button/Button.js"
|
|
10
|
+
import { LeuMenu } from "../menu/Menu.js"
|
|
11
|
+
import { LeuMenuItem } from "../menu/MenuItem.js"
|
|
12
|
+
import { LeuIcon } from "../icon/Icon.js"
|
|
13
|
+
import { LeuInput } from "../input/Input.js"
|
|
14
|
+
import { LeuPopup } from "../popup/Popup.js"
|
|
15
15
|
|
|
16
16
|
// @ts-ignore
|
|
17
17
|
import styles from "./select.css"
|
|
@@ -20,21 +20,51 @@ import styles from "./select.css"
|
|
|
20
20
|
* @tagname leu-select
|
|
21
21
|
* @slot before - Optional content the appears before the option list
|
|
22
22
|
* @slot after - Optional content the appears after the option list
|
|
23
|
+
* @property {string} name - Reflects to the name attribute of the hidden input field that would be used in a form
|
|
24
|
+
* @property {boolean} open - The expanded state of the popup
|
|
25
|
+
* @property {string} label - The label of the select
|
|
26
|
+
* @property {array} value - List of selected values. If they're set from outside the component, the select element tries to find all the options with the given values and selects them.
|
|
27
|
+
* @property {boolean} clearable - Show a clearable button to reset the value
|
|
28
|
+
* @property {boolean} disabled - If the select should be disabled
|
|
29
|
+
* @property {boolean} filterable - Show an input field to filter the options inside the popup
|
|
30
|
+
* @property {boolean} multiple - Allow multiple selections
|
|
31
|
+
* @attribute {string} value - The selected values separated by commas.
|
|
23
32
|
*/
|
|
24
|
-
export class LeuSelect extends
|
|
33
|
+
export class LeuSelect extends LeuElement {
|
|
34
|
+
static dependencies = {
|
|
35
|
+
"leu-button": LeuButton,
|
|
36
|
+
"leu-menu": LeuMenu,
|
|
37
|
+
"leu-menu-item": LeuMenuItem,
|
|
38
|
+
"leu-icon": LeuIcon,
|
|
39
|
+
"leu-input": LeuInput,
|
|
40
|
+
"leu-popup": LeuPopup,
|
|
41
|
+
}
|
|
42
|
+
|
|
25
43
|
static styles = styles
|
|
26
44
|
|
|
27
45
|
static get properties() {
|
|
28
46
|
return {
|
|
47
|
+
name: { type: String, reflect: true },
|
|
29
48
|
open: { type: Boolean, reflect: true },
|
|
30
49
|
label: { type: String, reflect: true },
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
value: {
|
|
51
|
+
type: Array,
|
|
52
|
+
converter: {
|
|
53
|
+
fromAttribute(value) {
|
|
54
|
+
if (value) {
|
|
55
|
+
return value.split(",").map((v) => v.trim())
|
|
56
|
+
}
|
|
57
|
+
return value
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
33
61
|
clearable: { type: Boolean, reflect: true },
|
|
34
62
|
disabled: { type: Boolean, reflect: true },
|
|
35
63
|
filterable: { type: Boolean, reflect: true },
|
|
36
64
|
multiple: { type: Boolean, reflect: true },
|
|
37
|
-
|
|
65
|
+
_optionFilter: { state: true },
|
|
66
|
+
_hasFilterResults: { state: true },
|
|
67
|
+
_displayValue: { state: true },
|
|
38
68
|
}
|
|
39
69
|
}
|
|
40
70
|
|
|
@@ -59,54 +89,111 @@ export class LeuSelect extends LitElement {
|
|
|
59
89
|
this.clearable = false
|
|
60
90
|
this.filterable = false
|
|
61
91
|
this.value = []
|
|
62
|
-
this.options = []
|
|
63
92
|
this.label = ""
|
|
93
|
+
this.name = ""
|
|
64
94
|
|
|
65
95
|
/** @internal */
|
|
66
|
-
this.
|
|
96
|
+
this._optionFilter = ""
|
|
67
97
|
|
|
68
98
|
/** @internal */
|
|
69
|
-
this.
|
|
99
|
+
this._hasFilterResults = true
|
|
70
100
|
|
|
71
101
|
/** @internal */
|
|
72
|
-
this.
|
|
102
|
+
this._deferedChangeEvent = false
|
|
73
103
|
|
|
74
104
|
/** @internal */
|
|
75
|
-
this.
|
|
105
|
+
this._displayValue = ""
|
|
76
106
|
|
|
77
|
-
/**
|
|
78
|
-
* @type {import("lit/directives/ref").Ref<import("../menu/Menu").LeuMenu>}
|
|
79
|
-
*/
|
|
80
|
-
this.menuRef = createRef()
|
|
81
107
|
/**
|
|
82
108
|
* @type {import("lit/directives/ref").Ref<import("../input/Input").LeuInput>}
|
|
83
109
|
*/
|
|
84
|
-
this.
|
|
110
|
+
this._optionFilterRef = createRef()
|
|
85
111
|
/**
|
|
86
112
|
* @type {import("lit/directives/ref").Ref<HTMLButtonElement>}
|
|
87
113
|
*/
|
|
88
|
-
this.
|
|
114
|
+
this._toggleButtonRef = createRef()
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @type {import("lit/directives/ref").Ref<import("../menu/Menu").LeuMenu>}
|
|
118
|
+
*/
|
|
119
|
+
this._menuRef = createRef()
|
|
89
120
|
}
|
|
90
121
|
|
|
91
122
|
connectedCallback() {
|
|
92
123
|
super.connectedCallback()
|
|
93
|
-
document.addEventListener("click", this.
|
|
124
|
+
document.addEventListener("click", this._handleDocumentClick)
|
|
94
125
|
}
|
|
95
126
|
|
|
96
127
|
disconnectedCallback() {
|
|
97
128
|
super.disconnectedCallback()
|
|
98
|
-
document.removeEventListener("click", this.
|
|
129
|
+
document.removeEventListener("click", this._handleDocumentClick)
|
|
99
130
|
}
|
|
100
131
|
|
|
101
132
|
updated(changedProperties) {
|
|
102
133
|
if (changedProperties.has("open") && this.open) {
|
|
103
134
|
if (this.filterable) {
|
|
104
|
-
this.
|
|
135
|
+
this._optionFilterRef.value.focus()
|
|
105
136
|
} else {
|
|
106
|
-
this.
|
|
137
|
+
this._menuRef.value.focusItem(0)
|
|
107
138
|
}
|
|
108
139
|
} else if (changedProperties.has("open") && !this.open) {
|
|
109
|
-
|
|
140
|
+
// TODO: Check if the ref is guaranteed to be set
|
|
141
|
+
// in the updated method.
|
|
142
|
+
// According to the lit documentation, a ref callback
|
|
143
|
+
// CAN be called with undefined.
|
|
144
|
+
this._toggleButtonRef.value?.focus()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (
|
|
148
|
+
changedProperties.has("value") ||
|
|
149
|
+
changedProperties.has("_optionFilter")
|
|
150
|
+
) {
|
|
151
|
+
this._updateMenuItems({
|
|
152
|
+
value: changedProperties.has("value"),
|
|
153
|
+
optionFilter: changedProperties.has("_optionFilter"),
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Apply the current state to the menu items.
|
|
160
|
+
* - Set the active property when the value property has changed.
|
|
161
|
+
* - Hide menu items that do not match the filter.
|
|
162
|
+
*/
|
|
163
|
+
async _updateMenuItems(changed) {
|
|
164
|
+
/** @type {LeuMenu} */
|
|
165
|
+
const menu = this._menuRef.value
|
|
166
|
+
|
|
167
|
+
await menu.updateComplete
|
|
168
|
+
|
|
169
|
+
const menuItems = menu.getMenuItems()
|
|
170
|
+
let hasFilterResults = false
|
|
171
|
+
|
|
172
|
+
/* eslint-disable no-param-reassign */
|
|
173
|
+
menuItems.forEach((menuItem) => {
|
|
174
|
+
if (changed.optionFilter) {
|
|
175
|
+
menuItem.hidden =
|
|
176
|
+
this._optionFilter !== "" &&
|
|
177
|
+
!menuItem.textContent
|
|
178
|
+
.toLowerCase()
|
|
179
|
+
.includes(this._optionFilter.toLowerCase())
|
|
180
|
+
|
|
181
|
+
hasFilterResults = hasFilterResults || !menuItem.hidden
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (changed.value) {
|
|
185
|
+
menuItem.active = this._isSelected(menuItem.getValue())
|
|
186
|
+
|
|
187
|
+
if (!this.multiple && menuItem.active) {
|
|
188
|
+
this._displayValue = menuItem.textContent
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
/* eslint-enable no-param-reassign */
|
|
193
|
+
|
|
194
|
+
if (changed.optionFilter) {
|
|
195
|
+
this._hasFilterResults = hasFilterResults
|
|
196
|
+
menu.setCurrentItem(0)
|
|
110
197
|
}
|
|
111
198
|
}
|
|
112
199
|
|
|
@@ -115,49 +202,72 @@ export class LeuSelect extends LitElement {
|
|
|
115
202
|
* @internal
|
|
116
203
|
* @param {MouseEvent} event
|
|
117
204
|
*/
|
|
118
|
-
|
|
205
|
+
_handleDocumentClick = (event) => {
|
|
119
206
|
if (
|
|
120
207
|
event.target instanceof Node &&
|
|
121
208
|
!this.contains(event.target) &&
|
|
122
209
|
this.open
|
|
123
210
|
) {
|
|
124
|
-
this.
|
|
211
|
+
this._closeDropdown()
|
|
125
212
|
}
|
|
126
213
|
}
|
|
127
214
|
|
|
128
215
|
/**
|
|
129
216
|
* @internal
|
|
130
|
-
* @param {KeyboardEvent}
|
|
217
|
+
* @param {KeyboardEvent} event
|
|
131
218
|
*/
|
|
132
|
-
|
|
219
|
+
_handleKeyDown = (event) => {
|
|
133
220
|
if (event.key === "Escape") {
|
|
134
|
-
this.
|
|
221
|
+
this._closeDropdown()
|
|
135
222
|
}
|
|
136
223
|
}
|
|
137
224
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
225
|
+
/**
|
|
226
|
+
* @internal
|
|
227
|
+
* @param {KeyboardEvent} event
|
|
228
|
+
*/
|
|
229
|
+
async _handleToggleKeyDown(event) {
|
|
230
|
+
if (["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
|
|
231
|
+
event.preventDefault()
|
|
232
|
+
|
|
233
|
+
const menu = this._menuRef.value
|
|
234
|
+
|
|
235
|
+
this.open = true
|
|
236
|
+
await this.updateComplete
|
|
142
237
|
|
|
143
|
-
|
|
238
|
+
if (event.key === "ArrowDown" || event.key === "Home") {
|
|
239
|
+
menu.focusItem(0)
|
|
240
|
+
} else if (event.key === "ArrowUp" || event.key === "End") {
|
|
241
|
+
menu.focusItem(-1)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
144
244
|
}
|
|
145
245
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
246
|
+
/**
|
|
247
|
+
* @internal
|
|
248
|
+
* @param {KeyboardEvent} event
|
|
249
|
+
*/
|
|
250
|
+
_handleFilterInputKeyDown(event) {
|
|
251
|
+
if (event.key === "ArrowDown") {
|
|
252
|
+
this._menuRef.value.focusItem(0)
|
|
253
|
+
} else if (event.key === "ArrowUp") {
|
|
254
|
+
this._menuRef.value.focusItem(-1)
|
|
255
|
+
}
|
|
153
256
|
}
|
|
154
257
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
258
|
+
/**
|
|
259
|
+
* Determines the value or label that should be displayed inside the toggle button.
|
|
260
|
+
* @returns {String | nothing}
|
|
261
|
+
*/
|
|
262
|
+
_getDisplayValue() {
|
|
263
|
+
if (this.multiple) {
|
|
264
|
+
return this.value.length === 0 ? `` : `${this.value.length} gewählt`
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return this._displayValue ?? nothing
|
|
158
268
|
}
|
|
159
269
|
|
|
160
|
-
|
|
270
|
+
_emitInputEvent() {
|
|
161
271
|
const inputevent = new CustomEvent("input", {
|
|
162
272
|
composed: true,
|
|
163
273
|
bubbles: true,
|
|
@@ -165,7 +275,7 @@ export class LeuSelect extends LitElement {
|
|
|
165
275
|
this.dispatchEvent(inputevent)
|
|
166
276
|
}
|
|
167
277
|
|
|
168
|
-
|
|
278
|
+
_emitChangeEvent() {
|
|
169
279
|
const changeevent = new CustomEvent("change", {
|
|
170
280
|
composed: true,
|
|
171
281
|
bubbles: true,
|
|
@@ -173,126 +283,94 @@ export class LeuSelect extends LitElement {
|
|
|
173
283
|
this.dispatchEvent(changeevent)
|
|
174
284
|
}
|
|
175
285
|
|
|
176
|
-
|
|
286
|
+
_clearValue(event) {
|
|
177
287
|
if (!this.disabled) {
|
|
178
288
|
event.stopPropagation()
|
|
179
289
|
this.value = []
|
|
180
290
|
}
|
|
181
291
|
|
|
182
|
-
this.
|
|
292
|
+
this._emitInputEvent()
|
|
293
|
+
this._emitChangeEvent()
|
|
183
294
|
}
|
|
184
295
|
|
|
185
|
-
|
|
296
|
+
_toggleDropdown() {
|
|
186
297
|
if (!this.disabled) {
|
|
187
298
|
this.open = !this.open
|
|
188
299
|
}
|
|
189
300
|
}
|
|
190
301
|
|
|
191
|
-
|
|
192
|
-
this.open = true
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
closeDropdown() {
|
|
302
|
+
_closeDropdown() {
|
|
196
303
|
this.open = false
|
|
197
304
|
|
|
198
|
-
if (this.
|
|
199
|
-
this.
|
|
200
|
-
this.
|
|
305
|
+
if (this._deferedChangeEvent) {
|
|
306
|
+
this._emitChangeEvent()
|
|
307
|
+
this._deferedChangeEvent = false
|
|
201
308
|
}
|
|
202
309
|
}
|
|
203
310
|
|
|
311
|
+
_handleFilterInput(event) {
|
|
312
|
+
this._optionFilter = event.target.value
|
|
313
|
+
}
|
|
314
|
+
|
|
204
315
|
/**
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
* @
|
|
316
|
+
* Checks if the given value is selected.
|
|
317
|
+
* @param {String} menuItemValue
|
|
318
|
+
* @returns {Boolean}
|
|
208
319
|
*/
|
|
209
|
-
|
|
210
|
-
|
|
320
|
+
_isSelected(menuItemValue) {
|
|
321
|
+
return this.value.includes(menuItemValue)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
_handleMenuItemClick(event) {
|
|
325
|
+
if (!(event.target instanceof LeuMenuItem) || event.target.disabled) {
|
|
326
|
+
return
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** @type {LeuMenuItem} */
|
|
330
|
+
const menuItem = event.target
|
|
331
|
+
|
|
332
|
+
const value = menuItem.getValue()
|
|
333
|
+
const isSelected = this._isSelected(value)
|
|
211
334
|
|
|
212
335
|
if (this.multiple) {
|
|
213
336
|
this.value = isSelected
|
|
214
|
-
? this.value.filter((v) => v !==
|
|
215
|
-
: this.value.concat(
|
|
337
|
+
? this.value.filter((v) => v !== value)
|
|
338
|
+
: this.value.concat(value)
|
|
216
339
|
|
|
217
|
-
this.
|
|
340
|
+
this._deferedChangeEvent = true
|
|
218
341
|
} else {
|
|
219
|
-
this.value = isSelected ? [] : [
|
|
342
|
+
this.value = isSelected ? [] : [value]
|
|
343
|
+
this._displayValue = isSelected ? "" : menuItem.textContent
|
|
220
344
|
}
|
|
221
345
|
|
|
222
|
-
this.
|
|
346
|
+
this._emitInputEvent()
|
|
223
347
|
|
|
224
348
|
if (!this.multiple) {
|
|
225
|
-
this.
|
|
349
|
+
this._closeDropdown()
|
|
226
350
|
}
|
|
227
351
|
}
|
|
228
352
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
return this.value.includes(option)
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
renderMenu() {
|
|
242
|
-
const menuClasses = {
|
|
243
|
-
"select-menu": true,
|
|
244
|
-
multiple: this.multiple,
|
|
353
|
+
/**
|
|
354
|
+
* Close the dropdown if the focus moves outside the component.
|
|
355
|
+
*/
|
|
356
|
+
_handlePopupFocusOut(event) {
|
|
357
|
+
if (
|
|
358
|
+
!this.contains(event.relatedTarget) &&
|
|
359
|
+
!this.shadowRoot.contains(event.relatedTarget)
|
|
360
|
+
) {
|
|
361
|
+
this._closeDropdown()
|
|
245
362
|
}
|
|
246
|
-
|
|
247
|
-
const filteredOptions = this.getFilteredOptions()
|
|
248
|
-
|
|
249
|
-
return html`
|
|
250
|
-
<leu-menu
|
|
251
|
-
role="listbox"
|
|
252
|
-
class=${classMap(menuClasses)}
|
|
253
|
-
aria-multiselectable="${this.multiple}"
|
|
254
|
-
aria-labelledby="select-label"
|
|
255
|
-
ref=${ref(this.menuRef)}
|
|
256
|
-
>
|
|
257
|
-
${filteredOptions.length > 0
|
|
258
|
-
? map(this.getFilteredOptions(), (option) => {
|
|
259
|
-
const isSelected = this.isSelected(option)
|
|
260
|
-
let beforeIcon
|
|
261
|
-
|
|
262
|
-
if (this.multiple && isSelected) {
|
|
263
|
-
beforeIcon = "check"
|
|
264
|
-
} else if (this.multiple) {
|
|
265
|
-
beforeIcon = "EMPTY"
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
return html`<leu-menu-item
|
|
269
|
-
before=${ifDefined(beforeIcon)}
|
|
270
|
-
@click=${() => this.selectOption(option)}
|
|
271
|
-
role="option"
|
|
272
|
-
label=${LeuSelect.getOptionLabel(option)}
|
|
273
|
-
?active=${isSelected}
|
|
274
|
-
aria-selected=${isSelected}
|
|
275
|
-
>
|
|
276
|
-
</leu-menu-item>`
|
|
277
|
-
})
|
|
278
|
-
: html`<leu-menu-item
|
|
279
|
-
label=${this.optionFilter === ""
|
|
280
|
-
? "Keine Optionen"
|
|
281
|
-
: "Keine Resultate"}
|
|
282
|
-
disabled
|
|
283
|
-
></leu-menu-item>`}
|
|
284
|
-
</leu-menu>
|
|
285
|
-
`
|
|
286
363
|
}
|
|
287
364
|
|
|
288
|
-
|
|
365
|
+
_renderFilterInput() {
|
|
289
366
|
if (this.filterable) {
|
|
290
367
|
return html` <leu-input
|
|
291
368
|
class="select-search"
|
|
292
369
|
size="small"
|
|
293
|
-
@input=${this.
|
|
370
|
+
@input=${this._handleFilterInput}
|
|
371
|
+
@keydown=${this._handleFilterInputKeyDown}
|
|
294
372
|
clearable
|
|
295
|
-
ref=${ref(this.
|
|
373
|
+
ref=${ref(this._optionFilterRef)}
|
|
296
374
|
label="Nach Stichwort filtern"
|
|
297
375
|
></leu-input>`
|
|
298
376
|
}
|
|
@@ -300,23 +378,25 @@ export class LeuSelect extends LitElement {
|
|
|
300
378
|
return nothing
|
|
301
379
|
}
|
|
302
380
|
|
|
303
|
-
|
|
381
|
+
_renderApplyButton() {
|
|
304
382
|
if (this.multiple) {
|
|
305
383
|
return html`
|
|
306
|
-
<
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
384
|
+
<div class="apply-button-wrapper">
|
|
385
|
+
<leu-button
|
|
386
|
+
type="button"
|
|
387
|
+
class="apply-button"
|
|
388
|
+
@click=${this._closeDropdown}
|
|
389
|
+
fluid
|
|
390
|
+
>Anwenden</leu-button
|
|
391
|
+
>
|
|
392
|
+
</div>
|
|
313
393
|
`
|
|
314
394
|
}
|
|
315
395
|
|
|
316
396
|
return nothing
|
|
317
397
|
}
|
|
318
398
|
|
|
319
|
-
|
|
399
|
+
_renderToggleButton() {
|
|
320
400
|
const toggleClasses = {
|
|
321
401
|
"select-toggle": true,
|
|
322
402
|
open: this.open,
|
|
@@ -325,28 +405,32 @@ export class LeuSelect extends LitElement {
|
|
|
325
405
|
}
|
|
326
406
|
|
|
327
407
|
return html`<button
|
|
408
|
+
${ref(this._toggleButtonRef)}
|
|
328
409
|
type="button"
|
|
329
410
|
class=${classMap(toggleClasses)}
|
|
330
|
-
@click=${this.
|
|
331
|
-
|
|
332
|
-
|
|
411
|
+
@click=${this._toggleDropdown}
|
|
412
|
+
@keydown=${this._handleToggleKeyDown}
|
|
413
|
+
?disabled=${this.disabled}
|
|
414
|
+
aria-controls="select-popup"
|
|
333
415
|
aria-expanded="${this.open}"
|
|
416
|
+
aria-labelledby="select-label"
|
|
334
417
|
role="combobox"
|
|
335
|
-
ref=${ref(this.toggleButtonRef)}
|
|
336
418
|
slot="anchor"
|
|
337
419
|
>
|
|
338
420
|
<span class="label" id="select-label">${this.label}</span>
|
|
339
|
-
<span class="value"> ${this.
|
|
340
|
-
<span class="arrow-icon">
|
|
421
|
+
<span class="value"> ${this._getDisplayValue()} </span>
|
|
422
|
+
<span class="arrow-icon">
|
|
423
|
+
<leu-icon name="angleDropDown"></leu-icon>
|
|
424
|
+
</span>
|
|
341
425
|
${this.clearable && this.value.length !== 0
|
|
342
426
|
? html`<button
|
|
343
427
|
type="button"
|
|
344
428
|
class="clear-button"
|
|
345
|
-
@click=${this.
|
|
429
|
+
@click=${this._clearValue}
|
|
346
430
|
aria-label=${`${this.label} zurücksetzen`}
|
|
347
431
|
?disabled=${this.disabled}
|
|
348
432
|
>
|
|
349
|
-
|
|
433
|
+
<leu-icon name="clear"></leu-icon>
|
|
350
434
|
</button>`
|
|
351
435
|
: nothing}
|
|
352
436
|
</button>`
|
|
@@ -359,33 +443,53 @@ export class LeuSelect extends LitElement {
|
|
|
359
443
|
"select--has-after": this.hasSlotController.test("after"),
|
|
360
444
|
}
|
|
361
445
|
|
|
446
|
+
/*
|
|
447
|
+
* We use the click event listener with the event delegation pattern
|
|
448
|
+
* so this is not a violation of the rule.
|
|
449
|
+
*/
|
|
450
|
+
/* eslint-disable lit-a11y/click-events-have-key-events */
|
|
362
451
|
return html`<div
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
aria-readonly="${this.disabled}"
|
|
366
|
-
aria-labelledby="select-label"
|
|
367
|
-
@keydown=${this.handleKeyDown}
|
|
368
|
-
>
|
|
369
|
-
<leu-popup
|
|
370
|
-
?active=${this.open}
|
|
371
|
-
placement="bottom-start"
|
|
372
|
-
flip
|
|
373
|
-
matchSize="width"
|
|
374
|
-
autoSize="height"
|
|
375
|
-
autoSizePadding="8"
|
|
452
|
+
class=${classMap(selectClasses)}
|
|
453
|
+
@keydown=${this._handleKeyDown}
|
|
376
454
|
>
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
455
|
+
<leu-popup
|
|
456
|
+
?active=${this.open}
|
|
457
|
+
placement="bottom-start"
|
|
458
|
+
flip
|
|
459
|
+
matchSize="width"
|
|
460
|
+
autoSize="height"
|
|
461
|
+
autoSizePadding="8"
|
|
382
462
|
>
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
463
|
+
${this._renderToggleButton()}
|
|
464
|
+
<div
|
|
465
|
+
id="select-popup"
|
|
466
|
+
class="select-menu-container"
|
|
467
|
+
@focusout=${this._handlePopupFocusOut}
|
|
468
|
+
>
|
|
469
|
+
<slot name="before" class="before"></slot>
|
|
470
|
+
${this._renderFilterInput()}
|
|
471
|
+
<leu-menu
|
|
472
|
+
ref=${ref(this._menuRef)}
|
|
473
|
+
role="listbox"
|
|
474
|
+
aria-multiselectable=${ifDefined(
|
|
475
|
+
this.multiple ? "true" : undefined
|
|
476
|
+
)}
|
|
477
|
+
class="menu"
|
|
478
|
+
@click=${this._handleMenuItemClick}
|
|
479
|
+
>
|
|
480
|
+
<slot></slot>
|
|
481
|
+
</leu-menu>
|
|
482
|
+
${this._hasFilterResults
|
|
483
|
+
? nothing
|
|
484
|
+
: html` <p class="filter-message-empty" aria-live="polite">
|
|
485
|
+
Keine Resultate
|
|
486
|
+
</p>`}
|
|
487
|
+
${this._renderApplyButton()}
|
|
488
|
+
<slot name="after" class="after"></slot>
|
|
489
|
+
</div>
|
|
490
|
+
</leu-popup>
|
|
491
|
+
</div>
|
|
492
|
+
<input type="hidden" name=${this.name} .value=${this.value.join(",")} />`
|
|
493
|
+
/* eslint-enable lit-a11y/click-events-have-key-events */
|
|
390
494
|
}
|
|
391
495
|
}
|