@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.
Files changed (236) hide show
  1. package/.husky/commit-msg +0 -3
  2. package/.husky/pre-commit +0 -3
  3. package/CHANGELOG.md +40 -0
  4. package/dist/Accordion.d.ts +10 -9
  5. package/dist/Accordion.d.ts.map +1 -1
  6. package/dist/Accordion.js +12 -11
  7. package/dist/Breadcrumb.d.ts +4 -4
  8. package/dist/Breadcrumb.d.ts.map +1 -1
  9. package/dist/Breadcrumb.js +28 -26
  10. package/dist/{Button-5326c982.d.ts → Button-9692e403.d.ts} +10 -11
  11. package/dist/Button-9692e403.d.ts.map +1 -0
  12. package/dist/{Button-5326c982.js → Button-9692e403.js} +57 -67
  13. package/dist/Button.d.ts +1 -1
  14. package/dist/Button.js +3 -3
  15. package/dist/ButtonGroup.d.ts +2 -2
  16. package/dist/ButtonGroup.d.ts.map +1 -1
  17. package/dist/ButtonGroup.js +3 -3
  18. package/dist/Checkbox.d.ts +4 -3
  19. package/dist/Checkbox.d.ts.map +1 -1
  20. package/dist/Checkbox.js +14 -19
  21. package/dist/CheckboxGroup.d.ts +2 -2
  22. package/dist/CheckboxGroup.d.ts.map +1 -1
  23. package/dist/CheckboxGroup.js +4 -6
  24. package/dist/Chip.d.ts +2 -2
  25. package/dist/Chip.d.ts.map +1 -1
  26. package/dist/Chip.js +6 -13
  27. package/dist/ChipGroup.d.ts +9 -7
  28. package/dist/ChipGroup.d.ts.map +1 -1
  29. package/dist/ChipGroup.js +8 -5
  30. package/dist/ChipLink.d.ts +2 -1
  31. package/dist/ChipLink.d.ts.map +1 -1
  32. package/dist/ChipLink.js +4 -7
  33. package/dist/ChipRemovable.d.ts +0 -2
  34. package/dist/ChipRemovable.d.ts.map +1 -1
  35. package/dist/ChipRemovable.js +8 -11
  36. package/dist/ChipSelectable.d.ts +9 -1
  37. package/dist/ChipSelectable.d.ts.map +1 -1
  38. package/dist/ChipSelectable.js +12 -16
  39. package/dist/Dropdown.d.ts +9 -5
  40. package/dist/Dropdown.d.ts.map +1 -1
  41. package/dist/Dropdown.js +68 -32
  42. package/dist/Icon.d.ts +20 -0
  43. package/dist/Icon.d.ts.map +1 -0
  44. package/dist/{icon-03e86700.js → Icon.js} +61 -32
  45. package/dist/Input.d.ts +7 -16
  46. package/dist/Input.d.ts.map +1 -1
  47. package/dist/Input.js +24 -28
  48. package/dist/LeuElement-6de6f209.d.ts +7 -0
  49. package/dist/LeuElement-6de6f209.d.ts.map +1 -0
  50. package/dist/LeuElement-6de6f209.js +43 -0
  51. package/dist/Menu.d.ts +24 -2
  52. package/dist/Menu.d.ts.map +1 -1
  53. package/dist/Menu.js +120 -3
  54. package/dist/MenuItem.d.ts +28 -11
  55. package/dist/MenuItem.d.ts.map +1 -1
  56. package/dist/MenuItem.js +110 -63
  57. package/dist/Pagination.d.ts +10 -3
  58. package/dist/Pagination.d.ts.map +1 -1
  59. package/dist/Pagination.js +24 -21
  60. package/dist/Popup.d.ts +21 -3
  61. package/dist/Popup.d.ts.map +1 -1
  62. package/dist/Popup.js +44 -19
  63. package/dist/Radio.d.ts +4 -2
  64. package/dist/Radio.d.ts.map +1 -1
  65. package/dist/Radio.js +9 -16
  66. package/dist/RadioGroup.d.ts +2 -2
  67. package/dist/RadioGroup.d.ts.map +1 -1
  68. package/dist/RadioGroup.js +4 -6
  69. package/dist/ScrollTop.d.ts +2 -2
  70. package/dist/ScrollTop.d.ts.map +1 -1
  71. package/dist/ScrollTop.js +10 -8
  72. package/dist/Select.d.ts +75 -37
  73. package/dist/Select.d.ts.map +1 -1
  74. package/dist/Select.js +279 -183
  75. package/dist/Table.d.ts +2 -6
  76. package/dist/Table.d.ts.map +1 -1
  77. package/dist/Table.js +17 -18
  78. package/dist/VisuallyHidden.d.ts +2 -2
  79. package/dist/VisuallyHidden.d.ts.map +1 -1
  80. package/dist/VisuallyHidden.js +5 -7
  81. package/dist/index.d.ts +2 -2
  82. package/dist/index.js +5 -14
  83. package/dist/leu-accordion.d.ts.map +1 -1
  84. package/dist/leu-accordion.js +2 -3
  85. package/dist/leu-breadcrumb.d.ts.map +1 -1
  86. package/dist/leu-breadcrumb.js +4 -10
  87. package/dist/leu-button-group.d.ts.map +1 -1
  88. package/dist/leu-button-group.js +2 -3
  89. package/dist/leu-button.d.ts +1 -1
  90. package/dist/leu-button.d.ts.map +1 -1
  91. package/dist/leu-button.js +4 -5
  92. package/dist/leu-checkbox-group.d.ts.map +1 -1
  93. package/dist/leu-checkbox-group.js +2 -3
  94. package/dist/leu-checkbox.d.ts.map +1 -1
  95. package/dist/leu-checkbox.js +3 -4
  96. package/dist/leu-chip-group.d.ts.map +1 -1
  97. package/dist/leu-chip-group.js +2 -3
  98. package/dist/leu-chip-link.d.ts.map +1 -1
  99. package/dist/leu-chip-link.js +2 -3
  100. package/dist/leu-chip-removable.d.ts.map +1 -1
  101. package/dist/leu-chip-removable.js +3 -4
  102. package/dist/leu-chip-selectable.d.ts.map +1 -1
  103. package/dist/leu-chip-selectable.js +2 -3
  104. package/dist/leu-dropdown.d.ts.map +1 -1
  105. package/dist/leu-dropdown.js +5 -10
  106. package/dist/leu-icon.d.ts +3 -0
  107. package/dist/leu-icon.d.ts.map +1 -0
  108. package/dist/leu-icon.js +7 -0
  109. package/dist/leu-input.d.ts.map +1 -1
  110. package/dist/leu-input.js +3 -4
  111. package/dist/leu-menu-item.d.ts.map +1 -1
  112. package/dist/leu-menu-item.js +3 -5
  113. package/dist/leu-menu.d.ts.map +1 -1
  114. package/dist/leu-menu.js +5 -3
  115. package/dist/leu-pagination.d.ts.map +1 -1
  116. package/dist/leu-pagination.js +4 -7
  117. package/dist/leu-popup.d.ts.map +1 -1
  118. package/dist/leu-popup.js +2 -3
  119. package/dist/leu-radio-group.d.ts.map +1 -1
  120. package/dist/leu-radio-group.js +2 -3
  121. package/dist/leu-radio.d.ts.map +1 -1
  122. package/dist/leu-radio.js +2 -3
  123. package/dist/leu-scroll-top.d.ts.map +1 -1
  124. package/dist/leu-scroll-top.js +4 -6
  125. package/dist/leu-select.d.ts.map +1 -1
  126. package/dist/leu-select.js +5 -13
  127. package/dist/leu-table.d.ts.map +1 -1
  128. package/dist/leu-table.js +4 -8
  129. package/dist/leu-visually-hidden.d.ts.map +1 -1
  130. package/dist/leu-visually-hidden.js +2 -3
  131. package/dist/theme.css +2 -0
  132. package/dist/vscode.html-custom-data.json +116 -79
  133. package/dist/vue/index.d.ts +80 -76
  134. package/dist/web-types.json +405 -270
  135. package/package.json +9 -12
  136. package/scripts/generate-component/templates/[Name].js +6 -3
  137. package/scripts/generate-component/templates/test/[name].test.js +1 -1
  138. package/src/components/accordion/Accordion.js +13 -10
  139. package/src/components/accordion/leu-accordion.js +1 -2
  140. package/src/components/breadcrumb/Breadcrumb.js +31 -18
  141. package/src/components/breadcrumb/leu-breadcrumb.js +1 -2
  142. package/src/components/button/Button.js +45 -71
  143. package/src/components/button/button.css +11 -9
  144. package/src/components/button/leu-button.js +1 -2
  145. package/src/components/button/stories/button.stories.js +60 -19
  146. package/src/components/button/test/button.test.js +26 -63
  147. package/src/components/button-group/ButtonGroup.js +4 -2
  148. package/src/components/button-group/leu-button-group.js +1 -2
  149. package/src/components/checkbox/Checkbox.js +17 -11
  150. package/src/components/checkbox/CheckboxGroup.js +6 -3
  151. package/src/components/checkbox/leu-checkbox-group.js +1 -2
  152. package/src/components/checkbox/leu-checkbox.js +1 -2
  153. package/src/components/checkbox/stories/checkbox-group.stories.js +10 -26
  154. package/src/components/checkbox/stories/checkbox.stories.js +2 -7
  155. package/src/components/checkbox/test/checkbox-group.test.js +6 -21
  156. package/src/components/checkbox/test/checkbox.test.js +1 -12
  157. package/src/components/chip/Chip.js +5 -4
  158. package/src/components/chip/ChipGroup.js +10 -4
  159. package/src/components/chip/ChipLink.js +3 -7
  160. package/src/components/chip/ChipRemovable.js +8 -11
  161. package/src/components/chip/ChipSelectable.js +11 -17
  162. package/src/components/chip/chip.css +3 -4
  163. package/src/components/chip/leu-chip-group.js +1 -2
  164. package/src/components/chip/leu-chip-link.js +1 -2
  165. package/src/components/chip/leu-chip-removable.js +1 -2
  166. package/src/components/chip/leu-chip-selectable.js +1 -2
  167. package/src/components/chip/stories/chip-link.stories.js +3 -5
  168. package/src/components/chip/stories/chip-removable.stories.js +3 -4
  169. package/src/components/chip/stories/chip-selectable.stories.js +2 -2
  170. package/src/components/chip/test/chip-group.test.js +15 -30
  171. package/src/components/chip/test/chip-link.test.js +2 -6
  172. package/src/components/chip/test/chip-removable.test.js +4 -10
  173. package/src/components/chip/test/chip-selectable.test.js +3 -5
  174. package/src/components/dropdown/Dropdown.js +79 -26
  175. package/src/components/dropdown/leu-dropdown.js +1 -2
  176. package/src/components/dropdown/stories/dropdown.stories.js +30 -7
  177. package/src/components/dropdown/test/dropdown.test.js +5 -5
  178. package/src/components/icon/Icon.js +55 -0
  179. package/src/components/icon/icon.css +6 -0
  180. package/src/components/icon/leu-icon.js +5 -0
  181. package/src/components/icon/{icon.js → paths.js} +4 -37
  182. package/src/components/icon/stories/icon.stories.js +47 -0
  183. package/src/components/icon/test/icon.test.js +23 -40
  184. package/src/components/input/Input.js +21 -23
  185. package/src/components/input/input.css +4 -2
  186. package/src/components/input/leu-input.js +1 -2
  187. package/src/components/input/stories/input.stories.js +2 -2
  188. package/src/components/input/test/input.test.js +2 -0
  189. package/src/components/menu/Menu.js +143 -2
  190. package/src/components/menu/MenuItem.js +104 -52
  191. package/src/components/menu/leu-menu-item.js +1 -2
  192. package/src/components/menu/leu-menu.js +1 -2
  193. package/src/components/menu/menu-item.css +11 -4
  194. package/src/components/menu/stories/menu-item.stories.js +15 -4
  195. package/src/components/menu/stories/menu.stories.js +34 -7
  196. package/src/components/menu/test/menu-item.test.js +88 -82
  197. package/src/components/menu/test/menu.test.js +101 -8
  198. package/src/components/pagination/Pagination.js +27 -18
  199. package/src/components/pagination/leu-pagination.js +1 -2
  200. package/src/components/popup/Popup.js +39 -16
  201. package/src/components/popup/leu-popup.js +1 -2
  202. package/src/components/popup/popup.css +1 -0
  203. package/src/components/radio/Radio.js +12 -7
  204. package/src/components/radio/RadioGroup.js +6 -3
  205. package/src/components/radio/leu-radio-group.js +1 -2
  206. package/src/components/radio/leu-radio.js +1 -2
  207. package/src/components/radio/stories/radio-group.stories.js +5 -19
  208. package/src/components/radio/stories/radio.stories.js +2 -7
  209. package/src/components/radio/test/radio-group.test.js +6 -9
  210. package/src/components/radio/test/radio.test.js +3 -13
  211. package/src/components/scroll-top/ScrollTop.js +15 -5
  212. package/src/components/scroll-top/leu-scroll-top.js +1 -2
  213. package/src/components/select/Select.js +279 -175
  214. package/src/components/select/leu-select.js +1 -2
  215. package/src/components/select/select.css +20 -12
  216. package/src/components/select/stories/select.stories.js +16 -2
  217. package/src/components/select/test/select.test.js +191 -37
  218. package/src/components/table/Table.js +15 -9
  219. package/src/components/table/leu-table.js +1 -2
  220. package/src/components/table/table.css +3 -1
  221. package/src/components/visually-hidden/VisuallyHidden.js +6 -2
  222. package/src/components/visually-hidden/leu-visually-hidden.js +1 -2
  223. package/src/lib/LeuElement.js +23 -0
  224. package/src/lib/a11y.js +26 -0
  225. package/src/styles/custom-properties.css +2 -0
  226. package/web-test-runner.config.mjs +2 -0
  227. package/dist/Button-5326c982.d.ts.map +0 -1
  228. package/dist/_rollupPluginBabelHelpers-20f659f4.d.ts +0 -3
  229. package/dist/_rollupPluginBabelHelpers-20f659f4.d.ts.map +0 -1
  230. package/dist/_rollupPluginBabelHelpers-20f659f4.js +0 -30
  231. package/dist/defineElement-40372b4b.d.ts +0 -9
  232. package/dist/defineElement-40372b4b.d.ts.map +0 -1
  233. package/dist/defineElement-40372b4b.js +0 -15
  234. package/dist/icon-03e86700.d.ts +0 -11
  235. package/dist/icon-03e86700.d.ts.map +0 -1
  236. package/src/lib/defineElement.js +0 -13
@@ -42,7 +42,7 @@
42
42
  font-family: var(--select-font-regular);
43
43
  }
44
44
 
45
- .select[disabled] {
45
+ :host([disabled]) {
46
46
  --select-color: var(--select-color-disabled);
47
47
  --select-color-focus: var(--select-color-disabled);
48
48
  --select-border-color: var(--select-border-color-disabled);
@@ -121,19 +121,18 @@
121
121
  outline-offset: 2px;
122
122
  }
123
123
 
124
- .select[disabled] .select-toggle,
125
- .select[disabled] .clear-button {
124
+ .select-toggle[disabled],
125
+ .select-toggle[disabled] .clear-button {
126
126
  cursor: unset;
127
127
  }
128
128
 
129
- .select[disabled] .label {
129
+ .select-toggle[disabled] .label {
130
130
  color: var(--select-label-color);
131
131
  }
132
132
 
133
133
  .select-toggle.open .label,
134
134
  .select-toggle.filled .label,
135
- .select:not([disabled]) .select-toggle:focus .label,
136
- .select:not([disabled]) .select-toggle:active:not([disabled]) .label {
135
+ .select-toggle:focus .label {
137
136
  color: var(--select-label-color);
138
137
  font-family: var(--select-font-black);
139
138
  font-size: 0.75rem;
@@ -172,7 +171,7 @@
172
171
  flex-direction: column;
173
172
 
174
173
  width: 100%;
175
- max-height: var(--auto-size-available-height);
174
+ max-height: min(var(--auto-size-available-height), 24rem);
176
175
 
177
176
  padding: 0;
178
177
  margin: 0;
@@ -183,12 +182,9 @@
183
182
  box-shadow: var(--select-box-shadow-regular), var(--select-box-shadow-short);
184
183
  }
185
184
 
186
- .select-menu {
185
+ .menu {
187
186
  display: block;
188
- padding: 0;
189
- margin: 0;
190
187
  overflow: auto;
191
- max-height: 100%;
192
188
  }
193
189
 
194
190
  .before,
@@ -205,11 +201,23 @@
205
201
  display: none;
206
202
  }
207
203
 
204
+ .apply-button-wrapper {
205
+ background-color: var(--leu-color-black-10);
206
+ padding: 0.75rem;
207
+ }
208
+
208
209
  .apply-button {
209
210
  display: block;
210
- margin: 0.75rem;
211
211
  }
212
212
 
213
213
  .select-search {
214
214
  margin: 0.75rem;
215
215
  }
216
+
217
+ .filter-message-empty {
218
+ background: var(--leu-color-black-0);
219
+ color: var(--leu-color-black-transp-60);
220
+
221
+ padding: 0.75rem;
222
+ margin: 0;
223
+ }
@@ -1,7 +1,10 @@
1
1
  import { html } from "lit"
2
2
  import { ifDefined } from "lit/directives/if-defined.js"
3
3
 
4
- import "../leu-select.js"
4
+ import { LeuSelect } from "../leu-select.js"
5
+ import "../../menu/leu-menu.js"
6
+ import "../../menu/leu-menu-item.js"
7
+
5
8
  import { MUNICIPALITIES } from "../test/fixtures.js"
6
9
 
7
10
  export default {
@@ -37,7 +40,6 @@ function Template({
37
40
  <div style="margin-top: 50vh"></div>
38
41
  <leu-select
39
42
  class="dropdown"
40
- .options=${options}
41
43
  label=${ifDefined(label)}
42
44
  .value=${ifDefined(value)}
43
45
  ?clearable=${clearable}
@@ -47,6 +49,18 @@ function Template({
47
49
  >
48
50
  ${before ? html`<div slot="before">${before}</div>` : ""}
49
51
  ${after ? html`<div slot="after">${after}</div>` : ""}
52
+ ${options.map(
53
+ (option) => html`
54
+ <leu-menu-item
55
+ .value=${typeof option === "object" && option !== null
56
+ ? option.value
57
+ : option}
58
+ .label=${LeuSelect.getOptionLabel(option)}
59
+ >
60
+ ${LeuSelect.getOptionLabel(option)}
61
+ </leu-menu-item>
62
+ `
63
+ )}
50
64
  </leu-select>
51
65
  <div style="margin-top: 50vh"></div>
52
66
  `
@@ -4,11 +4,11 @@ import { fixture, expect, elementUpdated } from "@open-wc/testing"
4
4
  import { sendKeys } from "@web/test-runner-commands"
5
5
 
6
6
  import "../leu-select.js"
7
+ import "../../menu/leu-menu-item.js"
7
8
  import { MUNICIPALITIES } from "./fixtures.js"
8
9
 
9
10
  async function defaultFixture(args = {}) {
10
11
  return fixture(html`<leu-select
11
- .options=${args.options}
12
12
  label=${ifDefined(args.label)}
13
13
  .value=${args.value ?? []}
14
14
  ?clearable=${args.clearable}
@@ -16,6 +16,7 @@ async function defaultFixture(args = {}) {
16
16
  ?filterable=${args.filterable}
17
17
  ?multiple=${args.multiple}
18
18
  >
19
+ ${args.options.map((o) => html`<leu-menu-item>${o}</leu-menu-item>`)}
19
20
  </leu-select> `)
20
21
  }
21
22
 
@@ -45,6 +46,17 @@ describe("LeuSelect", () => {
45
46
  await expect(el).shadowDom.to.be.accessible()
46
47
  })
47
48
 
49
+ it("passes the a11y audit when a value is set", async () => {
50
+ const el = await defaultFixture({
51
+ options: MUNICIPALITIES,
52
+ label: "Gemeinde",
53
+ value: ["Affoltern am Albis"],
54
+ clearable: true,
55
+ })
56
+
57
+ await expect(el).shadowDom.to.be.accessible()
58
+ })
59
+
48
60
  it("renders a label", async () => {
49
61
  const el = await defaultFixture({
50
62
  options: MUNICIPALITIES,
@@ -56,15 +68,14 @@ describe("LeuSelect", () => {
56
68
  expect(toggleButton).to.have.trimmed.text("Gemeinde")
57
69
  })
58
70
 
59
- it("doesn't show the list of options by default", async () => {
71
+ it("doesn't display the popup in the default state", async () => {
60
72
  const el = await defaultFixture({
61
73
  options: MUNICIPALITIES,
62
74
  label: "Gemeinde",
63
75
  })
64
76
 
65
- const dialog = el.shadowRoot.querySelector("dialog")
66
-
67
- expect(dialog).to.not.have.attribute("open")
77
+ const popup = el.shadowRoot.querySelector("leu-popup")
78
+ expect(popup).to.not.have.attribute("active")
68
79
  })
69
80
 
70
81
  it("opens the list of options when the toggle button is clicked", async () => {
@@ -76,10 +87,10 @@ describe("LeuSelect", () => {
76
87
  const toggleButton = el.shadowRoot.querySelector(".select-toggle")
77
88
  toggleButton.click()
78
89
 
79
- const dialog = el.shadowRoot.querySelector("dialog")
90
+ const popup = el.shadowRoot.querySelector("leu-popup")
80
91
  await elementUpdated(el)
81
92
 
82
- expect(dialog).to.have.attribute("open")
93
+ expect(popup).to.have.attribute("active")
83
94
  })
84
95
 
85
96
  it("has a default value of an empty array", async () => {
@@ -91,29 +102,71 @@ describe("LeuSelect", () => {
91
102
  expect(el.value).to.deep.equal([])
92
103
  })
93
104
 
94
- it("marks the menu item as selected a the value is set", async () => {
105
+ it("marks the menu item as selected if the value is set", async () => {
95
106
  const el = await defaultFixture({
96
107
  options: MUNICIPALITIES,
97
108
  label: "Gemeinde",
98
- value: "Affoltern am Albis",
109
+ value: ["Affoltern am Albis"],
99
110
  })
100
111
 
101
- const toggleButton = el.shadowRoot.querySelector(".select-toggle")
102
- toggleButton.click()
112
+ await elementUpdated(el)
113
+
114
+ const menuItems = Array.from(el.querySelectorAll("leu-menu-item"))
103
115
 
104
- const menuItem = el.shadowRoot.querySelector(
105
- "leu-menu-item[label='Affoltern am Albis']"
116
+ const menuItem = menuItems.find(
117
+ (item) => item.textContent === "Affoltern am Albis"
106
118
  )
107
119
 
108
120
  expect(menuItem).to.have.attribute("active")
109
- expect(menuItem).to.have.attribute("aria-selected")
121
+
122
+ el.value = ["Affoltern a.A."] // This name doesn't match the name in the options
123
+ await elementUpdated(el)
124
+
125
+ // The value doesn't match any of the options
126
+ expect(menuItems.every((item) => !item.active)).to.be.true
127
+ })
128
+
129
+ it("converts the value to an array if it is a string", async () => {
130
+ const el = await defaultFixture({
131
+ options: ["Option 1", "Option 2", "Option 3"],
132
+ label: "Options",
133
+ })
134
+
135
+ el.setAttribute("value", "Option 1, Option 2")
136
+ expect(el.value).to.deep.equal(["Option 1", "Option 2"])
137
+
138
+ el.setAttribute("value", "Option 3")
139
+ expect(el.value).to.deep.equal(["Option 3"])
140
+
141
+ el.setAttribute("value", "Option 1 Option 2")
142
+ expect(el.value).to.deep.equal(["Option 1 Option 2"])
143
+ })
144
+
145
+ it("renders the label of the selected option", async () => {
146
+ const el = await defaultFixture({
147
+ options: MUNICIPALITIES,
148
+ label: "Gemeinde",
149
+ value: ["Affoltern am Albis"],
150
+ })
151
+
152
+ const toggleButton = el.shadowRoot.querySelector(".select-toggle .value")
153
+ expect(toggleButton).to.have.trimmed.text("Affoltern am Albis")
154
+
155
+ el.multiple = true
156
+ await elementUpdated(el)
157
+
158
+ expect(toggleButton).to.have.trimmed.text("1 gewählt")
159
+
160
+ el.value = ["Affoltern am Albis", "Maur"]
161
+ await elementUpdated(el)
162
+ expect(toggleButton).to.have.trimmed.text("2 gewählt")
110
163
  })
111
164
 
112
165
  it("shows the clear button when a value is set", async () => {
113
166
  const el = await defaultFixture({
114
167
  options: MUNICIPALITIES,
115
168
  label: "Gemeinde",
116
- value: "Affoltern am Albis",
169
+ value: ["Affoltern am Albis"],
117
170
  clearable: true,
118
171
  })
119
172
 
@@ -149,8 +202,11 @@ describe("LeuSelect", () => {
149
202
 
150
203
  await sendKeys({ type: "am albis" })
151
204
 
152
- const menuItems = el.shadowRoot.querySelectorAll("leu-menu-item")
153
- expect(menuItems.length).to.equal(6)
205
+ const menuItems = el.querySelectorAll("leu-menu-item")
206
+ const visibleMenuItems = Array.from(menuItems).filter(
207
+ (menuItem) => !menuItem.hidden
208
+ )
209
+ expect(visibleMenuItems.length).to.equal(6)
154
210
  })
155
211
 
156
212
  it("resets the filter when the filter input is cleared", async () => {
@@ -173,21 +229,12 @@ describe("LeuSelect", () => {
173
229
  clearFilterButton.click()
174
230
  await elementUpdated(el)
175
231
 
176
- const menuItems = el.shadowRoot.querySelectorAll("leu-menu-item")
177
- expect(menuItems.length).to.equal(MUNICIPALITIES.length)
178
- })
179
-
180
- it("renders a message when no options are available", async () => {
181
- const el = await defaultFixture({
182
- options: [],
183
- label: "Gemeinde",
184
- })
185
-
186
- const toggleButton = el.shadowRoot.querySelector(".select-toggle")
187
- toggleButton.click()
232
+ const menuItems = el.querySelectorAll("leu-menu-item")
233
+ const visibleMenuItems = Array.from(menuItems).filter(
234
+ (menuItem) => !menuItem.hidden
235
+ )
188
236
 
189
- const menuItem = el.shadowRoot.querySelector("leu-menu-item")
190
- expect(menuItem).to.have.attribute("label", "Keine Optionen")
237
+ expect(visibleMenuItems.length).to.equal(MUNICIPALITIES.length)
191
238
  })
192
239
 
193
240
  it("renders a message when no options are available after filtering", async () => {
@@ -204,9 +251,11 @@ describe("LeuSelect", () => {
204
251
  filterInput.focus()
205
252
 
206
253
  await sendKeys({ type: "am albissss" })
254
+ await elementUpdated(el)
207
255
 
208
- const menuItem = el.shadowRoot.querySelector("leu-menu-item")
209
- expect(menuItem).to.have.attribute("label", "Keine Resultate")
256
+ const emptyMessage = el.shadowRoot.querySelector(".filter-message-empty")
257
+ expect(emptyMessage).to.exist
258
+ expect(emptyMessage).to.have.attribute("aria-live", "polite")
210
259
  })
211
260
 
212
261
  it("renders a apply button when multiple selection is allowed", async () => {
@@ -216,10 +265,27 @@ describe("LeuSelect", () => {
216
265
  multiple: true,
217
266
  })
218
267
 
219
- const applyButton = el.shadowRoot.querySelector("leu-menu + .apply-button")
268
+ const applyButton = el.shadowRoot.querySelector(".apply-button")
220
269
  expect(applyButton).to.exist
221
270
  })
222
271
 
272
+ it("closes the popup when the apply button is clicked", async () => {
273
+ const el = await defaultFixture({
274
+ options: MUNICIPALITIES,
275
+ label: "Gemeinde",
276
+ multiple: true,
277
+ })
278
+
279
+ const toggleButton = el.shadowRoot.querySelector(".select-toggle")
280
+ toggleButton.click()
281
+
282
+ const applyButton = el.shadowRoot.querySelector(".apply-button")
283
+ applyButton.click()
284
+
285
+ const popup = el.shadowRoot.querySelector("leu-popup")
286
+ expect(popup).to.not.have.attribute("active")
287
+ })
288
+
223
289
  it("updates the value when an option is selected", async () => {
224
290
  const el = await defaultFixture({
225
291
  options: MUNICIPALITIES,
@@ -229,7 +295,9 @@ describe("LeuSelect", () => {
229
295
  const toggleButton = el.shadowRoot.querySelector(".select-toggle")
230
296
  toggleButton.click()
231
297
 
232
- const menuItem = el.shadowRoot.querySelector("leu-menu-item[label='Maur']")
298
+ const menuItem = Array.from(el.querySelectorAll("leu-menu-item")).find(
299
+ (item) => item.textContent === "Maur"
300
+ )
233
301
  menuItem.click()
234
302
 
235
303
  expect(el.value).to.deep.equal(["Maur"])
@@ -245,9 +313,95 @@ describe("LeuSelect", () => {
245
313
  const toggleButton = el.shadowRoot.querySelector(".select-toggle")
246
314
  toggleButton.click()
247
315
 
248
- el.shadowRoot.querySelector("leu-menu-item[label='Maur']").click()
249
- el.shadowRoot.querySelector("leu-menu-item[label='Zollikon']").click()
316
+ const menuItems = Array.from(el.querySelectorAll("leu-menu-item"))
317
+
318
+ menuItems.find((item) => item.textContent === "Maur").click()
319
+ menuItems.find((item) => item.textContent === "Zollikon").click()
250
320
 
251
321
  expect(el.value).to.deep.equal(["Maur", "Zollikon"])
252
322
  })
323
+
324
+ it("closes the popup when an item is selected", async () => {
325
+ const el = await defaultFixture({
326
+ options: MUNICIPALITIES,
327
+ label: "Gemeinde",
328
+ })
329
+
330
+ const toggleButton = el.shadowRoot.querySelector(".select-toggle")
331
+ toggleButton.click()
332
+
333
+ const menuItem = Array.from(el.querySelectorAll("leu-menu-item")).find(
334
+ (item) => item.textContent === "Hedingen"
335
+ )
336
+ menuItem.click()
337
+
338
+ const popup = el.shadowRoot.querySelector("leu-popup")
339
+ expect(popup).to.not.have.attribute("active")
340
+ })
341
+
342
+ it("keeps the popup open after selecting an item when multiple selection is allowed", async () => {
343
+ const el = await defaultFixture({
344
+ options: MUNICIPALITIES,
345
+ label: "Gemeinde",
346
+ multiple: true,
347
+ })
348
+
349
+ const toggleButton = el.shadowRoot.querySelector(".select-toggle")
350
+ toggleButton.click()
351
+
352
+ const menuItem = Array.from(el.querySelectorAll("leu-menu-item")).find(
353
+ (item) => item.textContent === "Hedingen"
354
+ )
355
+ menuItem.click()
356
+
357
+ const popup = el.shadowRoot.querySelector("leu-popup")
358
+ expect(popup).to.not.have.attribute("active")
359
+ })
360
+
361
+ it("focuses the filter input when the popup is opened", async () => {
362
+ const el = await defaultFixture({
363
+ options: MUNICIPALITIES,
364
+ label: "Gemeinde",
365
+ filterable: true,
366
+ })
367
+
368
+ const toggleButton = el.shadowRoot.querySelector(".select-toggle")
369
+ toggleButton.click()
370
+
371
+ await elementUpdated(el)
372
+
373
+ const filterInput = el.shadowRoot.querySelector(".select-search")
374
+ expect(filterInput).to.equal(el.shadowRoot.activeElement)
375
+ })
376
+
377
+ it("focuses the first menu item when the popup is opened", async () => {
378
+ const el = await defaultFixture({
379
+ options: MUNICIPALITIES,
380
+ label: "Gemeinde",
381
+ })
382
+
383
+ const toggleButton = el.shadowRoot.querySelector(".select-toggle")
384
+ toggleButton.click()
385
+
386
+ await elementUpdated(el)
387
+
388
+ const menuItems = el.querySelectorAll("leu-menu-item")
389
+ const firstMenuItem = menuItems[0]
390
+ expect(firstMenuItem).to.equal(document.activeElement)
391
+ })
392
+
393
+ it("closes the popup when the escape key is pressed", async () => {
394
+ const el = await defaultFixture({
395
+ options: MUNICIPALITIES,
396
+ label: "Gemeinde",
397
+ })
398
+
399
+ const toggleButton = el.shadowRoot.querySelector(".select-toggle")
400
+ toggleButton.click()
401
+
402
+ await sendKeys({ press: "Escape" })
403
+
404
+ const popup = el.shadowRoot.querySelector("leu-popup")
405
+ expect(popup.active).to.not.be.true
406
+ })
253
407
  })
@@ -1,16 +1,24 @@
1
- import { html, LitElement, nothing } from "lit"
1
+ import { html, nothing } from "lit"
2
2
  import { classMap } from "lit/directives/class-map.js"
3
3
  import { styleMap } from "lit/directives/style-map.js"
4
4
  import { createRef, ref } from "lit/directives/ref.js"
5
- import { Icon } from "../icon/icon.js"
6
- import "../pagination/leu-pagination.js"
7
5
 
6
+ import { LeuElement } from "../../lib/LeuElement.js"
7
+ import { LeuIcon } from "../icon/Icon.js"
8
+ import { LeuPagination } from "../pagination/Pagination.js"
9
+
10
+ // @ts-ignore
8
11
  import styles from "./table.css"
9
12
 
10
13
  /**
11
14
  * @tagname leu-table
12
15
  */
13
- export class LeuTable extends LitElement {
16
+ export class LeuTable extends LeuElement {
17
+ static dependencies = {
18
+ "leu-icon": LeuIcon,
19
+ "leu-pagination": LeuPagination,
20
+ }
21
+
14
22
  static styles = styles
15
23
 
16
24
  static properties = {
@@ -44,10 +52,6 @@ export class LeuTable extends LitElement {
44
52
  /** @type {number} */
45
53
  this.width = null
46
54
 
47
- /** @internal */
48
- this._sortArrowDown = Icon("arrowDown", 20)
49
- /** @internal */
50
- this._sortArrowUp = Icon("arrowUp", 20)
51
55
  /** @internal */
52
56
  this._shadowLeft = false
53
57
  /** @internal */
@@ -116,7 +120,9 @@ export class LeuTable extends LitElement {
116
120
  }
117
121
 
118
122
  sortArrowIcon() {
119
- return html`${this.sortOrderAsc ? this._sortArrowDown : this._sortArrowUp}`
123
+ return html`<leu-icon
124
+ name=${this.sortOrderAsc ? "arrowDown" : "arrowUp"}
125
+ ></leu-icon>`
120
126
  }
121
127
 
122
128
  sortArrow(col) {
@@ -1,6 +1,5 @@
1
- import { defineElement } from "../../lib/defineElement.js"
2
1
  import { LeuTable } from "./Table.js"
3
2
 
4
3
  export { LeuTable }
5
4
 
6
- defineElement("table", LeuTable)
5
+ LeuTable.define("leu-table")
@@ -73,7 +73,9 @@ button {
73
73
  font-family: inherit;
74
74
  }
75
75
 
76
- thead svg {
76
+ thead leu-icon {
77
+ --leu-icon-size: 1.25rem;
78
+
77
79
  display: inline-block;
78
80
  color: var(--leu-color-accent-blue);
79
81
  padding: 0;
@@ -1,10 +1,14 @@
1
- import { html, LitElement } from "lit"
1
+ import { html } from "lit"
2
+
3
+ import { LeuElement } from "../../lib/LeuElement.js"
4
+
5
+ // @ts-ignore
2
6
  import styles from "./visually-hidden.css"
3
7
 
4
8
  /**
5
9
  * @tagname leu-visually-hidden
6
10
  */
7
- export class LeuVisuallyHidden extends LitElement {
11
+ export class LeuVisuallyHidden extends LeuElement {
8
12
  static styles = styles
9
13
 
10
14
  render() {
@@ -1,6 +1,5 @@
1
- import { defineElement } from "../../lib/defineElement.js"
2
1
  import { LeuVisuallyHidden } from "./VisuallyHidden.js"
3
2
 
4
3
  export { LeuVisuallyHidden }
5
4
 
6
- defineElement("visually-hidden", LeuVisuallyHidden)
5
+ LeuVisuallyHidden.define("leu-visually-hidden")
@@ -0,0 +1,23 @@
1
+ import { LitElement } from "lit"
2
+
3
+ export class LeuElement extends LitElement {
4
+ static dependencies = {}
5
+
6
+ static define(name, constructor = this, options = {}) {
7
+ if (!customElements.get(name)) {
8
+ customElements.define(name, constructor, options)
9
+ } else {
10
+ console.info(`${name} is already defined`)
11
+ }
12
+ }
13
+
14
+ constructor() {
15
+ super()
16
+
17
+ Object.entries(this.constructor.dependencies).forEach(
18
+ ([name, component]) => {
19
+ this.constructor.define(name, component)
20
+ }
21
+ )
22
+ }
23
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * All roles that are associated with a aria-checked attribute
3
+ * @link https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-checked
4
+ */
5
+ export const ARIA_CHECKED_ROLES = [
6
+ "checkbox",
7
+ "menuitemcheckbox",
8
+ "menuitemradio",
9
+ "option",
10
+ "radio",
11
+ "switch",
12
+ ]
13
+
14
+ /**
15
+ * All roles that are associated with a aria-selected attribute
16
+ * @link https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-selected
17
+ */
18
+ export const ARIA_SELECTED_ROLES = [
19
+ "gridcell",
20
+ "option",
21
+ "row",
22
+ "tab",
23
+ "columnheader",
24
+ "rowheader",
25
+ "treeitem",
26
+ ]
@@ -51,5 +51,7 @@
51
51
  --leu-box-shadow-regular: 0px 0px 16px var(--leu-color-black-transp-20);
52
52
  --leu-box-shadow-long: 0px 0px 80px var(--leu-color-black-transp-20);
53
53
 
54
+ --leu-z-index-popup: 100;
55
+
54
56
  @leu-font-styles './font-definitions.json';
55
57
  }
@@ -45,6 +45,8 @@ export default /** @type {import("@web/test-runner").TestRunnerConfig} */ ({
45
45
  // playwrightLauncher({ product: "webkit" }),
46
46
  ],
47
47
 
48
+ testsFinishTimeout: 10000,
49
+
48
50
  testRunnerHtml: (testFramework) =>
49
51
  `<html>
50
52
  <head>
@@ -1 +0,0 @@
1
- {"version":3,"file":"Button-5326c982.d.ts","sourceRoot":"","sources":["Button-5326c982.js"],"names":[],"mappings":";;;iCAaa,OAAO,KAAK,EAAE,kBAAkB;AA2V7C,wCAA0D;AAlW1D;;;GAGG;AAEH;;;;GAIG;AACH;IACE,uCAcC;IAHC,UAAgB;IAEhB,eAA0B;IAG5B;;;OAGG;IACH,uBAeC;IAED;;;;OAIG;IACH,qBAEC;IAED;;;OAGG;IACH,gCAEC;IACD,sBAEC;IACD,yBAEC;CACF;AAiTD;;GAEG;AACH;IAQI,WAAiB;IACjB,qBAAqB;IACrB,MADW,MAAM,CACD;IAChB,yFAAyF;IACzF,cADW,CAAC,QAAQ,GAAG,OAAO,CAAC,CACH;IAC5B,qBAAqB;IACrB,MADW,MAAM,CACI;IACrB,qBAAqB;IACrB,SADW,MAAM,CACO;IACxB,4CAA4C;IAC5C,MADW,QAAQ,GAAG,QAAQ,GAAG,OAAO,CACpB;IAEpB,sBAAsB;IACtB,UADW,OAAO,CACG;IACrB,+EAA+E;IAC/E,OADW,OAAO,CACA;IAClB,sBAAsB;IACtB,QADW,OAAO,CACC;IACnB,wDAAwD;IACxD,UADW,OAAO,CACG;IAErB,gGAAgG;IAChG,OADW,OAAO,CACA;IAElB;;;OAGG;IACH,UAFU,CAAC,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAEf;IAE3B,uBAEC;IACD,0EAOC;IACD,yEAOC;IACD,6EAOC;IACD;;;MAaC;IACD,+CA0BC;CACF;AAhID,qCAA0C;AAE1C,qCAAmD;AAEnD,gDAAkD;2BA7WH,KAAK;wBAAL,KAAK"}
@@ -1,3 +0,0 @@
1
- export { _defineProperty as _ };
2
- declare function _defineProperty(obj: any, key: any, value: any): any;
3
- //# sourceMappingURL=_rollupPluginBabelHelpers-20f659f4.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_rollupPluginBabelHelpers-20f659f4.d.ts","sourceRoot":"","sources":["_rollupPluginBabelHelpers-20f659f4.js"],"names":[],"mappings":";AAAA,sEAaC"}
@@ -1,30 +0,0 @@
1
- function _defineProperty(obj, key, value) {
2
- key = _toPropertyKey(key);
3
- if (key in obj) {
4
- Object.defineProperty(obj, key, {
5
- value: value,
6
- enumerable: true,
7
- configurable: true,
8
- writable: true
9
- });
10
- } else {
11
- obj[key] = value;
12
- }
13
- return obj;
14
- }
15
- function _toPrimitive(input, hint) {
16
- if (typeof input !== "object" || input === null) return input;
17
- var prim = input[Symbol.toPrimitive];
18
- if (prim !== undefined) {
19
- var res = prim.call(input, hint || "default");
20
- if (typeof res !== "object") return res;
21
- throw new TypeError("@@toPrimitive must return a primitive value.");
22
- }
23
- return (hint === "string" ? String : Number)(input);
24
- }
25
- function _toPropertyKey(arg) {
26
- var key = _toPrimitive(arg, "string");
27
- return typeof key === "symbol" ? key : String(key);
28
- }
29
-
30
- export { _defineProperty as _ };
@@ -1,9 +0,0 @@
1
- export { defineElement as d };
2
- /**
3
- * Adds a definition for a custom element to the custom element
4
- * registry if it isn't defined before. Prefixes the name with `leu-`.
5
- * @param {string} name
6
- * @param {CustomElementConstructor} constructor
7
- */
8
- declare function defineElement(name: string, constructor: CustomElementConstructor): void;
9
- //# sourceMappingURL=defineElement-40372b4b.d.ts.map