@statistikzh/leu 0.3.0 → 0.5.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 (295) hide show
  1. package/.github/workflows/deploy-github-pages.yaml +33 -0
  2. package/.storybook/main.js +27 -1
  3. package/.storybook/manager-head.html +1 -0
  4. package/.storybook/manager.js +9 -0
  5. package/.storybook/preview-head.html +1 -1
  6. package/.storybook/preview.js +59 -6
  7. package/.storybook/static/logo.svg +19 -0
  8. package/.storybook/theme.js +7 -0
  9. package/CHANGELOG.md +54 -0
  10. package/README.md +1 -1
  11. package/custom-elements-manifest.config.js +46 -0
  12. package/dist/Accordion.d.ts +31 -0
  13. package/dist/Accordion.d.ts.map +1 -0
  14. package/dist/Accordion.js +257 -0
  15. package/dist/Breadcrumb.d.ts +69 -0
  16. package/dist/Breadcrumb.d.ts.map +1 -0
  17. package/dist/Breadcrumb.js +392 -0
  18. package/dist/Button-da11d064.d.ts +84 -0
  19. package/dist/Button-da11d064.d.ts.map +1 -0
  20. package/dist/Button-da11d064.js +542 -0
  21. package/dist/Button.d.ts +2 -0
  22. package/dist/Button.d.ts.map +1 -0
  23. package/dist/Button.js +6 -423
  24. package/dist/ButtonGroup.d.ts +24 -0
  25. package/dist/ButtonGroup.d.ts.map +1 -0
  26. package/dist/ButtonGroup.js +72 -43
  27. package/dist/Checkbox.d.ts +13 -0
  28. package/dist/Checkbox.d.ts.map +1 -0
  29. package/dist/Checkbox.js +101 -84
  30. package/dist/CheckboxGroup.d.ts +13 -0
  31. package/dist/CheckboxGroup.d.ts.map +1 -0
  32. package/dist/CheckboxGroup.js +41 -37
  33. package/dist/Chip.d.ts +5 -0
  34. package/dist/Chip.d.ts.map +1 -0
  35. package/dist/{Chip-5f70d04f.js → Chip.js} +21 -6
  36. package/dist/ChipGroup.d.ts +28 -0
  37. package/dist/ChipGroup.d.ts.map +1 -0
  38. package/dist/ChipGroup.js +64 -10
  39. package/dist/ChipLink.d.ts +15 -0
  40. package/dist/ChipLink.d.ts.map +1 -0
  41. package/dist/ChipLink.js +4 -7
  42. package/dist/ChipRemovable.d.ts +13 -0
  43. package/dist/ChipRemovable.d.ts.map +1 -0
  44. package/dist/ChipRemovable.js +5 -8
  45. package/dist/ChipSelectable.d.ts +22 -0
  46. package/dist/ChipSelectable.d.ts.map +1 -0
  47. package/dist/ChipSelectable.js +8 -11
  48. package/dist/Dropdown.d.ts +15 -0
  49. package/dist/Dropdown.d.ts.map +1 -0
  50. package/dist/Dropdown.js +73 -26
  51. package/dist/Input.d.ts +154 -0
  52. package/dist/Input.d.ts.map +1 -0
  53. package/dist/Input.js +42 -35
  54. package/dist/Menu.d.ts +8 -0
  55. package/dist/Menu.d.ts.map +1 -0
  56. package/dist/Menu.js +2 -5
  57. package/dist/MenuItem.d.ts +21 -0
  58. package/dist/MenuItem.d.ts.map +1 -0
  59. package/dist/MenuItem.js +32 -17
  60. package/dist/Pagination.d.ts +27 -0
  61. package/dist/Pagination.d.ts.map +1 -0
  62. package/dist/Pagination.js +121 -89
  63. package/dist/Popup.d.ts +18 -0
  64. package/dist/Popup.d.ts.map +1 -0
  65. package/dist/Popup.js +215 -0
  66. package/dist/Radio.d.ts +12 -0
  67. package/dist/Radio.d.ts.map +1 -0
  68. package/dist/Radio.js +9 -8
  69. package/dist/RadioGroup.d.ts +20 -0
  70. package/dist/RadioGroup.d.ts.map +1 -0
  71. package/dist/RadioGroup.js +41 -39
  72. package/dist/ScrollTop.d.ts +19 -0
  73. package/dist/ScrollTop.d.ts.map +1 -0
  74. package/dist/ScrollTop.js +122 -0
  75. package/dist/Select.d.ts +98 -0
  76. package/dist/Select.d.ts.map +1 -0
  77. package/dist/Select.js +79 -122
  78. package/dist/Table.d.ts +48 -0
  79. package/dist/Table.d.ts.map +1 -0
  80. package/dist/Table.js +141 -121
  81. package/dist/VisuallyHidden.d.ts +8 -0
  82. package/dist/VisuallyHidden.d.ts.map +1 -0
  83. package/dist/VisuallyHidden.js +28 -0
  84. package/dist/_rollupPluginBabelHelpers-20f659f4.d.ts +3 -0
  85. package/dist/_rollupPluginBabelHelpers-20f659f4.d.ts.map +1 -0
  86. package/dist/{defineElement-ba770aed.js → _rollupPluginBabelHelpers-20f659f4.js} +1 -15
  87. package/dist/defineElement-40372b4b.d.ts +9 -0
  88. package/dist/defineElement-40372b4b.d.ts.map +1 -0
  89. package/dist/defineElement-40372b4b.js +15 -0
  90. package/dist/icon-03e86700.d.ts +11 -0
  91. package/dist/icon-03e86700.d.ts.map +1 -0
  92. package/dist/index.js.d.ts +21 -0
  93. package/dist/index.js.d.ts.map +1 -0
  94. package/dist/index.js.js +42 -0
  95. package/dist/leu-accordion.d.ts +3 -0
  96. package/dist/leu-accordion.d.ts.map +1 -0
  97. package/dist/leu-accordion.js +9 -0
  98. package/dist/leu-breadcrumb.d.ts +3 -0
  99. package/dist/leu-breadcrumb.d.ts.map +1 -0
  100. package/dist/leu-breadcrumb.js +23 -0
  101. package/dist/leu-button-group.d.ts +3 -0
  102. package/dist/leu-button-group.d.ts.map +1 -0
  103. package/dist/leu-button-group.js +6 -6
  104. package/dist/leu-button.d.ts +3 -0
  105. package/dist/leu-button.d.ts.map +1 -0
  106. package/dist/leu-button.js +7 -3
  107. package/dist/leu-checkbox-group.d.ts +3 -0
  108. package/dist/leu-checkbox-group.d.ts.map +1 -0
  109. package/dist/leu-checkbox-group.js +6 -3
  110. package/dist/leu-checkbox.d.ts +3 -0
  111. package/dist/leu-checkbox.d.ts.map +1 -0
  112. package/dist/leu-checkbox.js +6 -3
  113. package/dist/leu-chip-group.d.ts +3 -0
  114. package/dist/leu-chip-group.d.ts.map +1 -0
  115. package/dist/leu-chip-group.js +7 -3
  116. package/dist/leu-chip-link.d.ts +3 -0
  117. package/dist/leu-chip-link.d.ts.map +1 -0
  118. package/dist/leu-chip-link.js +7 -4
  119. package/dist/leu-chip-removable.d.ts +3 -0
  120. package/dist/leu-chip-removable.d.ts.map +1 -0
  121. package/dist/leu-chip-removable.js +7 -4
  122. package/dist/leu-chip-selectable.d.ts +3 -0
  123. package/dist/leu-chip-selectable.d.ts.map +1 -0
  124. package/dist/leu-chip-selectable.js +7 -4
  125. package/dist/leu-dropdown.d.ts +3 -0
  126. package/dist/leu-dropdown.d.ts.map +1 -0
  127. package/dist/leu-dropdown.js +15 -4
  128. package/dist/leu-input.d.ts +3 -0
  129. package/dist/leu-input.d.ts.map +1 -0
  130. package/dist/leu-input.js +7 -3
  131. package/dist/leu-menu-item.d.ts +3 -0
  132. package/dist/leu-menu-item.d.ts.map +1 -0
  133. package/dist/leu-menu-item.js +8 -3
  134. package/dist/leu-menu.d.ts +3 -0
  135. package/dist/leu-menu.d.ts.map +1 -0
  136. package/dist/leu-menu.js +6 -3
  137. package/dist/leu-pagination.d.ts +3 -0
  138. package/dist/leu-pagination.d.ts.map +1 -0
  139. package/dist/leu-pagination.js +12 -4
  140. package/dist/leu-popup.d.ts +3 -0
  141. package/dist/leu-popup.d.ts.map +1 -0
  142. package/dist/leu-popup.js +9 -0
  143. package/dist/leu-radio-group.d.ts +3 -0
  144. package/dist/leu-radio-group.d.ts.map +1 -0
  145. package/dist/leu-radio-group.js +6 -3
  146. package/dist/leu-radio.d.ts +3 -0
  147. package/dist/leu-radio.d.ts.map +1 -0
  148. package/dist/leu-radio.js +6 -3
  149. package/dist/leu-scroll-top.d.ts +3 -0
  150. package/dist/leu-scroll-top.d.ts.map +1 -0
  151. package/dist/leu-scroll-top.js +14 -0
  152. package/dist/leu-select.d.ts +3 -0
  153. package/dist/leu-select.d.ts.map +1 -0
  154. package/dist/leu-select.js +16 -4
  155. package/dist/leu-table.d.ts +3 -0
  156. package/dist/leu-table.d.ts.map +1 -0
  157. package/dist/leu-table.js +13 -4
  158. package/dist/leu-visually-hidden.d.ts +3 -0
  159. package/dist/leu-visually-hidden.d.ts.map +1 -0
  160. package/dist/leu-visually-hidden.js +8 -0
  161. package/dist/theme.css +386 -2
  162. package/dist/utils-65469421.d.ts +16 -0
  163. package/dist/utils-65469421.d.ts.map +1 -0
  164. package/dist/utils-65469421.js +35 -0
  165. package/index.js +3 -0
  166. package/package.json +47 -17
  167. package/postcss.config.cjs +2 -0
  168. package/rollup.config.js +21 -40
  169. package/scripts/generate-component/templates/[Name].js +0 -5
  170. package/scripts/generate-component/templates/[name].css +3 -3
  171. package/scripts/generate-component/templates/[namespace]-[name].js +5 -2
  172. package/scripts/postcss-leu-font-styles.cjs +160 -0
  173. package/src/components/accordion/Accordion.js +0 -6
  174. package/src/components/accordion/accordion.css +2 -2
  175. package/src/components/accordion/leu-accordion.js +5 -2
  176. package/src/components/accordion/stories/accordion.stories.js +8 -4
  177. package/src/components/accordion/test/accordion.test.js +95 -3
  178. package/src/components/breadcrumb/Breadcrumb.js +311 -0
  179. package/src/components/breadcrumb/breadcrumb.css +103 -0
  180. package/src/components/breadcrumb/leu-breadcrumb.js +6 -0
  181. package/src/components/breadcrumb/stories/breadcrumb.stories.js +73 -0
  182. package/src/components/breadcrumb/test/breadcrumb.test.js +141 -0
  183. package/src/components/button/Button.js +76 -20
  184. package/src/components/button/button.css +13 -5
  185. package/src/components/button/leu-button.js +5 -2
  186. package/src/components/button/stories/button.stories.js +79 -105
  187. package/src/components/button/test/button.test.js +184 -3
  188. package/src/components/button-group/ButtonGroup.js +76 -40
  189. package/src/components/button-group/leu-button-group.js +5 -2
  190. package/src/components/button-group/stories/button-group.stories.js +19 -6
  191. package/src/components/button-group/test/button-group.test.js +87 -4
  192. package/src/components/checkbox/Checkbox.js +6 -85
  193. package/src/components/checkbox/CheckboxGroup.js +8 -38
  194. package/src/components/checkbox/checkbox-group.css +29 -0
  195. package/src/components/checkbox/checkbox.css +76 -0
  196. package/src/components/checkbox/leu-checkbox-group.js +5 -2
  197. package/src/components/checkbox/leu-checkbox.js +5 -2
  198. package/src/components/checkbox/stories/checkbox-group.stories.js +44 -21
  199. package/src/components/checkbox/stories/checkbox.stories.js +7 -1
  200. package/src/components/checkbox/test/checkbox-group.test.js +124 -0
  201. package/src/components/checkbox/test/checkbox.test.js +72 -59
  202. package/src/components/chip/Chip.js +1 -0
  203. package/src/components/chip/ChipGroup.js +42 -7
  204. package/src/components/chip/ChipLink.js +1 -6
  205. package/src/components/chip/ChipRemovable.js +2 -7
  206. package/src/components/chip/ChipSelectable.js +5 -10
  207. package/src/components/chip/chip-group.css +12 -2
  208. package/src/components/chip/chip.css +14 -3
  209. package/src/components/chip/exports.js +4 -10
  210. package/src/components/chip/leu-chip-group.js +5 -2
  211. package/src/components/chip/leu-chip-link.js +5 -2
  212. package/src/components/chip/leu-chip-removable.js +5 -2
  213. package/src/components/chip/leu-chip-selectable.js +5 -2
  214. package/src/components/chip/stories/chip-group.stories.js +110 -44
  215. package/src/components/chip/stories/chip-link.stories.js +16 -4
  216. package/src/components/chip/stories/chip-removable.stories.js +15 -4
  217. package/src/components/chip/stories/chip-selectable.stories.js +13 -3
  218. package/src/components/chip/test/chip-group.test.js +124 -0
  219. package/src/components/chip/test/chip-link.test.js +58 -0
  220. package/src/components/chip/test/chip-removable.test.js +79 -0
  221. package/src/components/chip/test/chip-selectable.test.js +95 -0
  222. package/src/components/chip/test/chip.test.js +1 -1
  223. package/src/components/dropdown/Dropdown.js +72 -24
  224. package/src/components/dropdown/dropdown.css +1 -2
  225. package/src/components/dropdown/leu-dropdown.js +5 -2
  226. package/src/components/dropdown/stories/dropdown.stories.js +11 -5
  227. package/src/components/dropdown/test/dropdown.test.js +6 -6
  228. package/src/components/icon/icon.js +1 -1
  229. package/src/components/icon/test/icon.test.js +66 -0
  230. package/src/components/input/Input.js +25 -28
  231. package/src/components/input/input.css +11 -8
  232. package/src/components/input/leu-input.js +5 -2
  233. package/src/components/input/stories/input.stories.js +21 -2
  234. package/src/components/input/test/input.test.js +432 -4
  235. package/src/components/menu/Menu.js +0 -5
  236. package/src/components/menu/MenuItem.js +20 -13
  237. package/src/components/menu/leu-menu-item.js +5 -2
  238. package/src/components/menu/leu-menu.js +5 -2
  239. package/src/components/menu/menu-item.css +7 -4
  240. package/src/components/menu/stories/menu-item.stories.js +13 -4
  241. package/src/components/menu/stories/menu.stories.js +11 -5
  242. package/src/components/menu/test/menu-item.test.js +180 -0
  243. package/src/components/menu/test/menu.test.js +10 -2
  244. package/src/components/pagination/Pagination.js +118 -99
  245. package/src/components/pagination/leu-pagination.js +5 -2
  246. package/src/components/pagination/pagination.css +6 -1
  247. package/src/components/pagination/stories/pagination.stories.js +30 -9
  248. package/src/components/pagination/test/pagination.test.js +191 -5
  249. package/src/components/popup/Popup.js +200 -0
  250. package/src/components/popup/leu-popup.js +6 -0
  251. package/src/components/popup/popup.css +27 -0
  252. package/src/components/popup/stories/popup.stories.js +58 -0
  253. package/src/components/popup/test/popup.test.js +29 -0
  254. package/src/components/radio/Radio.js +2 -6
  255. package/src/components/radio/RadioGroup.js +6 -38
  256. package/src/components/radio/leu-radio-group.js +5 -2
  257. package/src/components/radio/leu-radio.js +5 -2
  258. package/src/components/radio/radio-group.css +29 -0
  259. package/src/components/radio/radio.css +1 -1
  260. package/src/components/radio/stories/radio-group.stories.js +38 -19
  261. package/src/components/radio/stories/radio.stories.js +7 -1
  262. package/src/components/radio/test/radio-group.test.js +86 -0
  263. package/src/components/radio/test/radio.test.js +108 -17
  264. package/src/components/scroll-top/ScrollTop.js +87 -0
  265. package/src/components/scroll-top/leu-scroll-top.js +6 -0
  266. package/src/components/scroll-top/scroll-top.css +34 -0
  267. package/src/components/scroll-top/stories/scroll-top.stories.js +217 -0
  268. package/src/components/scroll-top/test/scroll-top.test.js +22 -0
  269. package/src/components/select/Select.js +58 -37
  270. package/src/components/select/leu-select.js +5 -2
  271. package/src/components/select/select.css +15 -15
  272. package/src/components/select/stories/select.stories.js +15 -168
  273. package/src/components/select/test/fixtures.js +162 -0
  274. package/src/components/select/test/select.test.js +236 -12
  275. package/src/components/table/Table.js +43 -118
  276. package/src/components/table/leu-table.js +5 -2
  277. package/src/components/table/stories/table.stories.js +20 -10
  278. package/src/components/table/table.css +99 -0
  279. package/src/components/table/test/table.test.js +1 -1
  280. package/src/components/visually-hidden/VisuallyHidden.js +13 -0
  281. package/src/components/visually-hidden/leu-visually-hidden.js +6 -0
  282. package/src/components/visually-hidden/stories/visually-hidden.stories.js +22 -0
  283. package/src/components/visually-hidden/test/visually-hidden.test.js +36 -0
  284. package/src/components/visually-hidden/visually-hidden.css +10 -0
  285. package/src/lib/defineElement.js +1 -1
  286. package/src/lib/hasSlotController.js +5 -3
  287. package/src/lib/utils.js +35 -0
  288. package/src/styles/custom-properties.css +6 -2
  289. package/src/styles/font-definitions.json +202 -0
  290. package/stylelint.config.mjs +2 -0
  291. package/tsconfig.build.json +21 -0
  292. package/tsconfig.json +16 -0
  293. package/{web-dev-server-storybook.config.mjs → web-dev-server.config.mjs} +1 -2
  294. package/web-test-runner.config.mjs +15 -2
  295. package/dist/index.js +0 -26
@@ -5,16 +5,22 @@ import "../leu-menu-item.js"
5
5
  export default {
6
6
  title: "Menu",
7
7
  component: "leu-menu",
8
+ parameters: {
9
+ design: {
10
+ type: "figma",
11
+ url: "https://www.figma.com/file/d6Pv21UVUbnBs3AdcZijHmbN/KTZH-Design-System?type=design&node-id=17340-82208&mode=design&t=lzVrtq8lxYVJU5TB-11",
12
+ },
13
+ },
8
14
  }
9
15
 
10
16
  function Template() {
11
17
  return html` <leu-menu>
12
- <leu-menu-item before="EMPTY">Menu Item 1</leu-menu-item>
13
- <leu-menu-item before="check" active>Menu Item 2</leu-menu-item>
14
- <leu-menu-item before="EMPTY">Menu Item 3</leu-menu-item>
18
+ <leu-menu-item label="Menu Item 1" before="EMPTY"></leu-menu-item>
19
+ <leu-menu-item label="Menu Item 2" before="check" active></leu-menu-item>
20
+ <leu-menu-item label="Menu Item 3" before="EMPTY"></leu-menu-item>
15
21
  <hr />
16
- <leu-menu-item before="pin" after="CH">Menu Item 3</leu-menu-item>
17
- <leu-menu-item>Menu Item 4</leu-menu-item>
22
+ <leu-menu-item label="Menu Item 3" before="pin" after="CH"></leu-menu-item>
23
+ <leu-menu-item label="Menu Item 4"></leu-menu-item>
18
24
  </leu-menu>`
19
25
  }
20
26
 
@@ -0,0 +1,180 @@
1
+ import { html } from "lit"
2
+ import { fixture, expect, oneEvent } from "@open-wc/testing"
3
+ import { ifDefined } from "lit/directives/if-defined.js"
4
+ import { spy } from "sinon"
5
+
6
+ import "../leu-menu-item.js"
7
+
8
+ async function defaultFixture(args = {}) {
9
+ return fixture(html`
10
+ <leu-menu-item
11
+ label=${args.label}
12
+ before=${ifDefined(args.before)}
13
+ after=${ifDefined(args.after)}
14
+ href=${ifDefined(args.href)}
15
+ ?active=${args.active}
16
+ ?disabled=${args.disabled}
17
+ ></leu-menu-item>
18
+ `)
19
+ }
20
+
21
+ describe("LeuMenuItem", () => {
22
+ it("is a defined element", async () => {
23
+ const el = customElements.get("leu-menu-item")
24
+
25
+ await expect(el).not.to.be.undefined
26
+ })
27
+
28
+ it("passes the a11y audit", async () => {
29
+ const el = await defaultFixture({ label: "Download" })
30
+
31
+ await expect(el).shadowDom.to.be.accessible()
32
+ })
33
+
34
+ it("passes the a11y audit with a link", async () => {
35
+ const el = await defaultFixture({
36
+ label: "Download",
37
+ href: "https://zh.ch",
38
+ })
39
+
40
+ await expect(el).shadowDom.to.be.accessible()
41
+ })
42
+
43
+ it("renders a label", async () => {
44
+ const el = await defaultFixture({ label: "Download" })
45
+
46
+ const button = el.shadowRoot.querySelector("button")
47
+
48
+ expect(button).to.have.trimmed.text("Download")
49
+ })
50
+
51
+ it("renders a button", async () => {
52
+ const el = await defaultFixture({ label: "Download" })
53
+
54
+ const button = el.shadowRoot.querySelector("button")
55
+
56
+ expect(button).to.exist
57
+ })
58
+
59
+ it("renders a link", async () => {
60
+ const el = await defaultFixture({
61
+ label: "Kanton Zürich",
62
+ href: "https://zh.ch",
63
+ })
64
+
65
+ const link = el.shadowRoot.querySelector("a")
66
+
67
+ expect(link).to.exist
68
+ expect(link).to.have.attribute("href", "https://zh.ch")
69
+ expect(link).to.have.trimmed.text("Kanton Zürich")
70
+ })
71
+
72
+ it("renders a before icon", async () => {
73
+ const el = await defaultFixture({ label: "Download", before: "download" })
74
+
75
+ const before = el.shadowRoot.querySelector(".before")
76
+ expect(before).to.exist
77
+
78
+ expect(el).shadowDom.to.equal(
79
+ "<button class='button'><span class='before'></span><span class='label'>Download</span></button>"
80
+ )
81
+ })
82
+
83
+ it("renders a before label", async () => {
84
+ const el = await defaultFixture({ label: "Download", before: "DE" })
85
+
86
+ const before = el.shadowRoot.querySelector(".before")
87
+ expect(before).to.exist
88
+ expect(before).to.have.trimmed.text("DE")
89
+
90
+ expect(el).shadowDom.to.equal(
91
+ "<button class='button'><span class='before'>DE</span><span class='label'>Download</span></button>"
92
+ )
93
+ })
94
+
95
+ it("renders a before placeholder", async () => {
96
+ const el = await defaultFixture({ label: "Download", before: "EMPTY" })
97
+
98
+ const before = el.shadowRoot.querySelector(".before")
99
+ expect(before).to.exist
100
+ expect(before).to.not.have.trimmed.text()
101
+
102
+ const iconPlaceholder = before.querySelector(".icon-placeholder")
103
+ expect(iconPlaceholder).to.exist
104
+
105
+ expect(el).shadowDom.to.equal(
106
+ "<button class='button'><span class='before'><div class='icon-placeholder'></div></span><span class='label'>Download</span></button>"
107
+ )
108
+ })
109
+
110
+ it("renders a after icon", async () => {
111
+ const el = await defaultFixture({ label: "Download", after: "download" })
112
+
113
+ const after = el.shadowRoot.querySelector(".after")
114
+ expect(after).to.exist
115
+
116
+ expect(el).shadowDom.to.equal(
117
+ "<button class='button'><span class='label'>Download</span><span class='after'></span></button>"
118
+ )
119
+ })
120
+
121
+ it("renders a after label", async () => {
122
+ const el = await defaultFixture({ label: "Download", after: "DE" })
123
+
124
+ const after = el.shadowRoot.querySelector(".after")
125
+ expect(after).to.exist
126
+ expect(after).to.have.trimmed.text("DE")
127
+
128
+ expect(el).shadowDom.to.equal(
129
+ "<button class='button'><span class='label'>Download</span><span class='after'>DE</span></button>"
130
+ )
131
+ })
132
+
133
+ it("renders a after placeholder", async () => {
134
+ const el = await defaultFixture({ label: "Download", after: "EMPTY" })
135
+
136
+ const after = el.shadowRoot.querySelector(".after")
137
+ expect(after).to.exist
138
+ expect(after).to.not.have.trimmed.text()
139
+
140
+ const iconPlaceholder = after.querySelector(".icon-placeholder")
141
+ expect(iconPlaceholder).to.exist
142
+
143
+ expect(el).shadowDom.to.equal(
144
+ "<button class='button'><span class='label'>Download</span><span class='after'><div class='icon-placeholder'></div></span></button>"
145
+ )
146
+ })
147
+
148
+ it("passes the disabled attribute to the button", async () => {
149
+ const el = await defaultFixture({ label: "Download", disabled: true })
150
+
151
+ const button = el.shadowRoot.querySelector("button")
152
+ expect(button).to.have.attribute("disabled")
153
+ })
154
+
155
+ it("lets the click event bubble up", async () => {
156
+ const el = await defaultFixture({ label: "Download" })
157
+
158
+ const button = el.shadowRoot.querySelector("button")
159
+
160
+ setTimeout(() => {
161
+ button.click()
162
+ })
163
+
164
+ const event = await oneEvent(el, "click")
165
+
166
+ expect(event).to.exist
167
+ })
168
+
169
+ it("does not let the click event bubble up when disabled", async () => {
170
+ const el = await defaultFixture({ label: "Download", disabled: true })
171
+
172
+ const button = el.shadowRoot.querySelector("button")
173
+ const clickSpy = spy()
174
+ button.addEventListener("click", clickSpy)
175
+
176
+ el.click()
177
+
178
+ expect(clickSpy).to.have.not.been.called
179
+ })
180
+ })
@@ -2,14 +2,22 @@ import { html } from "lit"
2
2
  import { fixture, expect } from "@open-wc/testing"
3
3
 
4
4
  import "../leu-menu.js"
5
+ import "../leu-menu-item.js"
5
6
 
6
7
  async function defaultFixture() {
7
- return fixture(html` <leu-menu /> `)
8
+ return fixture(html` <leu-menu>
9
+ <leu-menu-item label="Menu Item 1" before="EMPTY"></leu-menu-item>
10
+ <leu-menu-item label="Menu Item 2" before="check" active></leu-menu-item>
11
+ <leu-menu-item label="Menu Item 3" before="EMPTY"></leu-menu-item>
12
+ <hr />
13
+ <leu-menu-item label="Menu Item 3" before="pin" after="CH"></leu-menu-item>
14
+ <leu-menu-item label="Menu Item 4"></leu-menu-item>
15
+ </leu-menu>`)
8
16
  }
9
17
 
10
18
  describe("LeuMenu", () => {
11
19
  it("is a defined element", async () => {
12
- const el = await customElements.get("leu-menu")
20
+ const el = customElements.get("leu-menu")
13
21
 
14
22
  await expect(el).not.to.be.undefined
15
23
  })
@@ -1,9 +1,11 @@
1
1
  import { html, LitElement } from "lit"
2
- import { defineElement } from "../../lib/defineElement.js"
3
- import { defineButtonElements } from "../button/Button.js"
2
+ import { live } from "lit/directives/live.js"
4
3
 
4
+ import "../button/leu-button.js"
5
5
  import styles from "./pagination.css"
6
6
 
7
+ import "../visually-hidden/leu-visually-hidden.js"
8
+
7
9
  const MIN_PAGE = 1
8
10
 
9
11
  /**
@@ -12,141 +14,158 @@ const MIN_PAGE = 1
12
14
  export class LeuPagination extends LitElement {
13
15
  static styles = styles
14
16
 
15
- static events = {
16
- range: {},
17
+ /**
18
+ * @internal
19
+ */
20
+ static shadowRootOptions = {
21
+ ...LitElement.shadowRootOptions,
22
+ delegatesFocus: true,
17
23
  }
18
24
 
19
25
  static properties = {
20
- page: { type: Number, reflect: true },
21
- itemsOnAPage: { type: Number, reflect: true },
22
- dataLength: { type: Number, reflect: true },
23
-
24
- _minPage: { type: Number, state: true },
26
+ defaultPage: { type: Number, reflect: true },
27
+ itemsPerPage: { type: Number, reflect: true },
28
+ numOfItems: { type: Number, reflect: true },
29
+
30
+ /**
31
+ * Internal page state that contains an
32
+ * already clamped page number. Should only
33
+ * be accessed through the `page` getter and
34
+ * setter.
35
+ * @type {Number}
36
+ * @internal
37
+ */
38
+ _page: { state: true },
25
39
  }
26
40
 
27
41
  constructor() {
28
42
  super()
29
- /** @type {number} */
30
- this.page = 1
31
- /** @type {number} */
32
- this.dataLength = 0
33
- /** @type {number} */
34
- this.itemsOnAPage = 30
43
+
44
+ /** @type {Number} */
45
+ this.numOfItems = 1
46
+ /** @type {Number} */
47
+ this.itemsPerPage = 1
48
+ /** @type {Number} */
49
+ this._page = 1
35
50
  }
36
51
 
37
- get maxPage() {
38
- return Math.ceil(this.dataLength / this.itemsOnAPage)
52
+ attributeChangedCallback(name, oldVal, newVal) {
53
+ super.attributeChangedCallback(name, oldVal, newVal)
54
+
55
+ if (name === "defaultpage" && newVal !== oldVal) {
56
+ this.page = parseInt(newVal, 10)
57
+ }
39
58
  }
40
59
 
41
- get firstPage() {
42
- return this.page === MIN_PAGE
60
+ get page() {
61
+ return this._page
43
62
  }
44
63
 
45
- get lastPage() {
46
- return this.page === this.maxPage
64
+ set page(page) {
65
+ this._page = this._clampPage(page)
47
66
  }
48
67
 
49
- holdInRange(value) {
50
- return Math.min(Math.max(value, MIN_PAGE), this.maxPage)
68
+ get startIndex() {
69
+ return (this.page - 1) * this.itemsPerPage
51
70
  }
52
71
 
53
- numberUpdate(number) {
54
- this.page = this.holdInRange(number)
72
+ get endIndex() {
73
+ return Math.min(this.startIndex + this.itemsPerPage, this.numOfItems)
74
+ }
55
75
 
56
- const min = (this.page - 1) * this.itemsOnAPage
57
- const max = Math.min(min + this.itemsOnAPage, this.dataLength)
58
- this.dispatchEvent(
59
- new CustomEvent("range-updated", {
60
- detail: {
61
- min,
62
- max,
63
- },
64
- bubbles: false,
65
- })
66
- )
76
+ get _maxPage() {
77
+ return Math.ceil(this.numOfItems / this.itemsPerPage)
67
78
  }
68
79
 
69
- change(event) {
70
- // target.value = this.page // eslint-disable-line
71
- this.numberUpdate(parseInt(event.target.value, 10) || 0)
80
+ _isFirstPage() {
81
+ return this.page === MIN_PAGE
72
82
  }
73
83
 
74
- input(event) {
75
- if (event.target.value !== "") {
76
- event.preventDefault()
77
- this.change(event)
78
- }
84
+ _isLastPage() {
85
+ return this.page === this._maxPage
79
86
  }
80
87
 
81
- keydown(event) {
82
- const specialKeys = [
83
- "ArrowUp",
84
- "ArrowDown",
85
- "ArrowLeft",
86
- "ArrowRight",
87
- "Backspace",
88
- "Enter",
89
- "Tab",
90
- ]
91
- const numberKeys = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
92
- if (!numberKeys.includes(event.key) && !specialKeys.includes(event.key)) {
93
- event.preventDefault()
94
- } else {
95
- if (event.key === "ArrowUp") {
96
- event.preventDefault()
97
- this.numberUpdate(this.page + 1)
98
- }
99
- if (event.key === "ArrowDown") {
100
- event.preventDefault()
101
- this.numberUpdate(this.page - 1)
102
- }
88
+ _clampPage(page) {
89
+ return Math.min(Math.max(page, MIN_PAGE), this._maxPage)
90
+ }
91
+
92
+ _updatePage(page) {
93
+ const prevPage = this.page
94
+ this.page = this._clampPage(page)
95
+
96
+ if (this.page !== prevPage) {
97
+ this.dispatchEvent(
98
+ new CustomEvent("leu:pagechange", {
99
+ detail: {
100
+ startIndex: this.startIndex,
101
+ endIndex: this.endIndex,
102
+ page: this.page,
103
+ },
104
+ bubbles: false,
105
+ })
106
+ )
103
107
  }
104
108
  }
105
109
 
106
- firstUpdated() {
107
- this.numberUpdate(this.page)
110
+ _handleChange(event) {
111
+ this._updatePage(parseInt(event.target.value, 10) || 0)
112
+ }
113
+
114
+ _handleInput(event) {
115
+ if (event.target.value !== "") {
116
+ event.preventDefault()
117
+ this._handleChange(event)
118
+ }
108
119
  }
109
120
 
110
- requestUpdate(name, oldValue, newValue) {
111
- if (name === "itemsOnAPage") {
112
- this.numberUpdate(this.page)
121
+ _handleKeyDown(event) {
122
+ if (event.key === "ArrowUp") {
123
+ event.preventDefault()
124
+ this._updatePage(this.page + 1)
125
+ }
126
+ if (event.key === "ArrowDown") {
127
+ event.preventDefault()
128
+ this._updatePage(this.page - 1)
113
129
  }
114
- return super.requestUpdate(name, oldValue, newValue)
115
130
  }
116
131
 
117
132
  render() {
118
133
  return html`
134
+ <leu-visually-hidden>
135
+ <label for="page-input">Aktuelle Seite</label>
136
+ </leu-visually-hidden>
119
137
  <input
138
+ id="page-input"
120
139
  class="input"
121
- .value=${this.page}
122
- @input=${this.input}
123
- @change=${this.change}
124
- @keydown=${this.keydown}
140
+ min=${MIN_PAGE}
141
+ max=${this._maxPage}
142
+ .value=${live(this.page.toString())}
143
+ @input=${this._handleInput}
144
+ @change=${this._handleChange}
145
+ @keydown=${this._handleKeyDown}
125
146
  type="number"
126
147
  />
127
- <div class="label">von ${this.maxPage}</div>
128
- <leu-button
129
- icon="angleLeft"
130
- variant="secondary"
131
- @click=${(_) => {
132
- this.numberUpdate(this.page - 1)
133
- }}
134
- ?disabled=${this.firstPage}
135
- ></leu-button>
136
- <leu-button
137
- icon="angleRight"
138
- variant="secondary"
139
- @click=${(_) => {
140
- this.numberUpdate(this.page + 1)
141
- }}
142
- ?disabled=${this.lastPage}
143
- style="margin-left:4px;"
144
- ></leu-button>
148
+ <div class="label">von ${this._maxPage}</div>
149
+ <div class="button-group">
150
+ <leu-button
151
+ icon="angleLeft"
152
+ variant="secondary"
153
+ label="Vorherige Seite"
154
+ @click=${(_) => {
155
+ this._updatePage(this.page - 1)
156
+ }}
157
+ ?disabled=${this._isFirstPage()}
158
+ ></leu-button>
159
+ <leu-button
160
+ icon="angleRight"
161
+ variant="secondary"
162
+ label="Nächste Seite"
163
+ @click=${(_) => {
164
+ this._updatePage(this.page + 1)
165
+ }}
166
+ ?disabled=${this._isLastPage()}
167
+ ></leu-button>
168
+ </div>
145
169
  `
146
170
  }
147
171
  }
148
-
149
- export function definePaginationElements() {
150
- defineButtonElements()
151
- defineElement("pagination", LeuPagination)
152
- }
@@ -1,3 +1,6 @@
1
- import { definePaginationElements } from "./Pagination.js"
1
+ import { defineElement } from "../../lib/defineElement.js"
2
+ import { LeuPagination } from "./Pagination.js"
2
3
 
3
- definePaginationElements()
4
+ export { LeuPagination }
5
+
6
+ defineElement("pagination", LeuPagination)
@@ -2,7 +2,7 @@
2
2
  margin-top: 16px;
3
3
  display: flex;
4
4
  justify-content: end;
5
- font-family: var(--leu-font-regular);
5
+ font-family: var(--leu-font-family-regular);
6
6
  }
7
7
 
8
8
  .input {
@@ -47,3 +47,8 @@
47
47
  color: var(--leu-color-black-transp-60);
48
48
  white-space: nowrap;
49
49
  }
50
+
51
+ .button-group {
52
+ display: flex;
53
+ gap: 0.25rem;
54
+ }
@@ -1,8 +1,11 @@
1
1
  import { html } from "lit"
2
+ import { action } from "@storybook/addon-actions"
3
+
2
4
  import "../leu-pagination.js"
3
5
 
4
6
  // https://stackoverflow.com/questions/72566428/storybook-angular-how-to-dynamically-update-args-from-the-template
5
7
  import { UPDATE_STORY_ARGS } from "@storybook/core-events" // eslint-disable-line
8
+ import { ifDefined } from "lit/directives/if-defined.js"
6
9
  function updateStorybookArgss(id, args) {
7
10
  const channel = window.__STORYBOOK_ADDONS_CHANNEL__
8
11
  channel.emit(UPDATE_STORY_ARGS, {
@@ -56,18 +59,34 @@ const items = [
56
59
  export default {
57
60
  title: "Pagination",
58
61
  component: "leu-pagination",
62
+ args: {
63
+ onPageChange: action("leu:pagechange"),
64
+ },
65
+ parameters: {
66
+ design: {
67
+ type: "figma",
68
+ url: "https://www.figma.com/file/d6Pv21UVUbnBs3AdcZijHmbN/KTZH-Design-System?type=design&node-id=17341-82468&mode=design&t=lzVrtq8lxYVJU5TB-11",
69
+ },
70
+ },
59
71
  }
60
72
 
61
- function Template({ min, max }, { id }) {
73
+ function Template(
74
+ { startIndex, endIndex, onPageChange, itemsPerPage, defaultPage },
75
+ { id }
76
+ ) {
62
77
  return html`
63
- ${items.slice(min, max).map((item) => html`<div>${item.label}</div>`)}
78
+ ${items
79
+ .slice(startIndex, endIndex)
80
+ .map((item) => html`<div>${item.label}</div>`)}
64
81
  <leu-pagination
65
- dataLength=${items.length}
66
- itemsOnAPage="5"
67
- @range-updated=${(e) => {
82
+ numOfItems=${items.length}
83
+ itemsPerPage=${ifDefined(itemsPerPage)}
84
+ defaultPage=${ifDefined(defaultPage)}
85
+ @leu:pagechange=${(e) => {
86
+ onPageChange(e)
68
87
  updateStorybookArgss(id, {
69
- min: e.detail.min,
70
- max: e.detail.max,
88
+ startIndex: e.detail.startIndex,
89
+ endIndex: e.detail.endIndex,
71
90
  })
72
91
  }}
73
92
  >
@@ -77,6 +96,8 @@ function Template({ min, max }, { id }) {
77
96
 
78
97
  export const Regular = Template.bind({})
79
98
  Regular.args = {
80
- min: 0,
81
- max: 5,
99
+ startIndex: 0,
100
+ endIndex: 5,
101
+ itemsPerPage: 5,
102
+ // defaultPage: 2,
82
103
  }