@statistikzh/leu 0.4.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 (216) hide show
  1. package/.storybook/preview.js +1 -2
  2. package/CHANGELOG.md +24 -0
  3. package/custom-elements-manifest.config.js +46 -0
  4. package/dist/Accordion.d.ts +31 -0
  5. package/dist/Accordion.d.ts.map +1 -0
  6. package/dist/Accordion.js +257 -0
  7. package/dist/Breadcrumb.d.ts +69 -0
  8. package/dist/Breadcrumb.d.ts.map +1 -0
  9. package/dist/Breadcrumb.js +392 -0
  10. package/dist/Button-da11d064.d.ts +84 -0
  11. package/dist/Button-da11d064.d.ts.map +1 -0
  12. package/dist/Button-da11d064.js +542 -0
  13. package/dist/Button.d.ts +2 -0
  14. package/dist/Button.d.ts.map +1 -0
  15. package/dist/Button.js +6 -420
  16. package/dist/ButtonGroup.d.ts +24 -0
  17. package/dist/ButtonGroup.d.ts.map +1 -0
  18. package/dist/ButtonGroup.js +70 -39
  19. package/dist/Checkbox.d.ts +13 -0
  20. package/dist/Checkbox.d.ts.map +1 -0
  21. package/dist/Checkbox.js +2 -2
  22. package/dist/CheckboxGroup.d.ts +13 -0
  23. package/dist/CheckboxGroup.d.ts.map +1 -0
  24. package/dist/CheckboxGroup.js +3 -3
  25. package/dist/Chip.d.ts +5 -0
  26. package/dist/Chip.d.ts.map +1 -0
  27. package/dist/{Chip-dac7337d.js → Chip.js} +16 -5
  28. package/dist/ChipGroup.d.ts +28 -0
  29. package/dist/ChipGroup.d.ts.map +1 -0
  30. package/dist/ChipGroup.js +62 -5
  31. package/dist/ChipLink.d.ts +15 -0
  32. package/dist/ChipLink.d.ts.map +1 -0
  33. package/dist/ChipLink.js +1 -1
  34. package/dist/ChipRemovable.d.ts +13 -0
  35. package/dist/ChipRemovable.d.ts.map +1 -0
  36. package/dist/ChipRemovable.js +2 -2
  37. package/dist/ChipSelectable.d.ts +22 -0
  38. package/dist/ChipSelectable.d.ts.map +1 -0
  39. package/dist/ChipSelectable.js +5 -5
  40. package/dist/Dropdown.d.ts +15 -0
  41. package/dist/Dropdown.d.ts.map +1 -0
  42. package/dist/Dropdown.js +25 -7
  43. package/dist/Input.d.ts +154 -0
  44. package/dist/Input.d.ts.map +1 -0
  45. package/dist/Input.js +13 -7
  46. package/dist/Menu.d.ts +8 -0
  47. package/dist/Menu.d.ts.map +1 -0
  48. package/dist/MenuItem.d.ts +21 -0
  49. package/dist/MenuItem.d.ts.map +1 -0
  50. package/dist/MenuItem.js +3 -3
  51. package/dist/Pagination.d.ts +27 -0
  52. package/dist/Pagination.d.ts.map +1 -0
  53. package/dist/Pagination.js +93 -61
  54. package/dist/Popup.d.ts +18 -0
  55. package/dist/Popup.d.ts.map +1 -0
  56. package/dist/{leu-popup-4bf6f1f4.js → Popup.js} +4 -5
  57. package/dist/Radio.d.ts +12 -0
  58. package/dist/Radio.d.ts.map +1 -0
  59. package/dist/Radio.js +2 -2
  60. package/dist/RadioGroup.d.ts +20 -0
  61. package/dist/RadioGroup.d.ts.map +1 -0
  62. package/dist/RadioGroup.js +3 -3
  63. package/dist/ScrollTop.d.ts +19 -0
  64. package/dist/ScrollTop.d.ts.map +1 -0
  65. package/dist/ScrollTop.js +122 -0
  66. package/dist/Select.d.ts +98 -0
  67. package/dist/Select.d.ts.map +1 -0
  68. package/dist/Select.js +27 -82
  69. package/dist/Table.d.ts +48 -0
  70. package/dist/Table.d.ts.map +1 -0
  71. package/dist/Table.js +7 -4
  72. package/dist/VisuallyHidden.d.ts +8 -0
  73. package/dist/VisuallyHidden.d.ts.map +1 -0
  74. package/dist/VisuallyHidden.js +28 -0
  75. package/dist/_rollupPluginBabelHelpers-20f659f4.d.ts +3 -0
  76. package/dist/_rollupPluginBabelHelpers-20f659f4.d.ts.map +1 -0
  77. package/dist/defineElement-40372b4b.d.ts +9 -0
  78. package/dist/defineElement-40372b4b.d.ts.map +1 -0
  79. package/dist/{defineElement-47d4f665.js → defineElement-40372b4b.js} +1 -1
  80. package/dist/icon-03e86700.d.ts +11 -0
  81. package/dist/icon-03e86700.d.ts.map +1 -0
  82. package/dist/index.js.d.ts +21 -0
  83. package/dist/index.js.d.ts.map +1 -0
  84. package/dist/{index.js → index.js.js} +14 -8
  85. package/dist/leu-accordion.d.ts +3 -0
  86. package/dist/leu-accordion.d.ts.map +1 -0
  87. package/dist/leu-accordion.js +9 -0
  88. package/dist/leu-breadcrumb.d.ts +3 -0
  89. package/dist/leu-breadcrumb.d.ts.map +1 -0
  90. package/dist/leu-breadcrumb.js +23 -0
  91. package/dist/leu-button-group.d.ts +3 -0
  92. package/dist/leu-button-group.d.ts.map +1 -0
  93. package/dist/leu-button-group.js +1 -5
  94. package/dist/leu-button.d.ts +3 -0
  95. package/dist/leu-button.d.ts.map +1 -0
  96. package/dist/leu-button.js +3 -2
  97. package/dist/leu-checkbox-group.d.ts +3 -0
  98. package/dist/leu-checkbox-group.d.ts.map +1 -0
  99. package/dist/leu-checkbox-group.js +1 -1
  100. package/dist/leu-checkbox.d.ts +3 -0
  101. package/dist/leu-checkbox.d.ts.map +1 -0
  102. package/dist/leu-checkbox.js +1 -1
  103. package/dist/leu-chip-group.d.ts +3 -0
  104. package/dist/leu-chip-group.d.ts.map +1 -0
  105. package/dist/leu-chip-group.js +2 -1
  106. package/dist/leu-chip-link.d.ts +3 -0
  107. package/dist/leu-chip-link.d.ts.map +1 -0
  108. package/dist/leu-chip-link.js +2 -2
  109. package/dist/leu-chip-removable.d.ts +3 -0
  110. package/dist/leu-chip-removable.d.ts.map +1 -0
  111. package/dist/leu-chip-removable.js +2 -2
  112. package/dist/leu-chip-selectable.d.ts +3 -0
  113. package/dist/leu-chip-selectable.d.ts.map +1 -0
  114. package/dist/leu-chip-selectable.js +2 -2
  115. package/dist/leu-dropdown.d.ts +3 -0
  116. package/dist/leu-dropdown.d.ts.map +1 -0
  117. package/dist/leu-dropdown.js +5 -4
  118. package/dist/leu-input.d.ts +3 -0
  119. package/dist/leu-input.d.ts.map +1 -0
  120. package/dist/leu-input.js +1 -1
  121. package/dist/leu-menu-item.d.ts +3 -0
  122. package/dist/leu-menu-item.d.ts.map +1 -0
  123. package/dist/leu-menu-item.js +1 -1
  124. package/dist/leu-menu.d.ts +3 -0
  125. package/dist/leu-menu.d.ts.map +1 -0
  126. package/dist/leu-menu.js +1 -1
  127. package/dist/leu-pagination.d.ts +3 -0
  128. package/dist/leu-pagination.d.ts.map +1 -0
  129. package/dist/leu-pagination.js +5 -2
  130. package/dist/leu-popup.d.ts +3 -0
  131. package/dist/leu-popup.d.ts.map +1 -0
  132. package/dist/leu-popup.js +9 -0
  133. package/dist/leu-radio-group.d.ts +3 -0
  134. package/dist/leu-radio-group.d.ts.map +1 -0
  135. package/dist/leu-radio-group.js +1 -1
  136. package/dist/leu-radio.d.ts +3 -0
  137. package/dist/leu-radio.d.ts.map +1 -0
  138. package/dist/leu-radio.js +1 -1
  139. package/dist/leu-scroll-top.d.ts +3 -0
  140. package/dist/leu-scroll-top.d.ts.map +1 -0
  141. package/dist/leu-scroll-top.js +14 -0
  142. package/dist/leu-select.d.ts +3 -0
  143. package/dist/leu-select.d.ts.map +1 -0
  144. package/dist/leu-select.js +4 -3
  145. package/dist/leu-table.d.ts +3 -0
  146. package/dist/leu-table.d.ts.map +1 -0
  147. package/dist/leu-table.js +5 -2
  148. package/dist/leu-visually-hidden.d.ts +3 -0
  149. package/dist/leu-visually-hidden.d.ts.map +1 -0
  150. package/dist/leu-visually-hidden.js +8 -0
  151. package/dist/theme.css +386 -2
  152. package/dist/utils-65469421.d.ts +16 -0
  153. package/dist/utils-65469421.d.ts.map +1 -0
  154. package/dist/utils-65469421.js +35 -0
  155. package/index.js +3 -0
  156. package/package.json +30 -12
  157. package/postcss.config.cjs +2 -0
  158. package/rollup.config.js +21 -40
  159. package/scripts/generate-component/templates/[name].css +2 -2
  160. package/scripts/postcss-leu-font-styles.cjs +160 -0
  161. package/src/components/accordion/accordion.css +2 -2
  162. package/src/components/accordion/stories/accordion.stories.js +2 -1
  163. package/src/components/accordion/test/accordion.test.js +4 -2
  164. package/src/components/breadcrumb/Breadcrumb.js +2 -1
  165. package/src/components/breadcrumb/breadcrumb.css +2 -13
  166. package/src/components/button/Button.js +69 -8
  167. package/src/components/button/button.css +10 -2
  168. package/src/components/button/stories/button.stories.js +43 -90
  169. package/src/components/button/test/button.test.js +90 -19
  170. package/src/components/button-group/ButtonGroup.js +76 -34
  171. package/src/components/button-group/stories/button-group.stories.js +13 -6
  172. package/src/components/button-group/test/button-group.test.js +38 -31
  173. package/src/components/checkbox/checkbox-group.css +2 -2
  174. package/src/components/checkbox/checkbox.css +1 -1
  175. package/src/components/chip/ChipGroup.js +42 -2
  176. package/src/components/chip/ChipRemovable.js +1 -1
  177. package/src/components/chip/ChipSelectable.js +4 -4
  178. package/src/components/chip/chip-group.css +12 -2
  179. package/src/components/chip/chip.css +14 -3
  180. package/src/components/chip/stories/chip-group.stories.js +100 -46
  181. package/src/components/chip/test/chip-removable.test.js +3 -3
  182. package/src/components/dropdown/Dropdown.js +23 -3
  183. package/src/components/input/Input.js +7 -4
  184. package/src/components/input/input.css +2 -2
  185. package/src/components/input/stories/input.stories.js +13 -0
  186. package/src/components/input/test/input.test.js +1 -0
  187. package/src/components/menu/menu-item.css +3 -3
  188. package/src/components/pagination/Pagination.js +91 -60
  189. package/src/components/pagination/pagination.css +6 -1
  190. package/src/components/pagination/stories/pagination.stories.js +15 -2
  191. package/src/components/pagination/test/pagination.test.js +15 -15
  192. package/src/components/popup/popup.css +2 -2
  193. package/src/components/popup/stories/popup.stories.js +1 -1
  194. package/src/components/radio/radio-group.css +2 -2
  195. package/src/components/radio/radio.css +1 -1
  196. package/src/components/scroll-top/ScrollTop.js +87 -0
  197. package/src/components/scroll-top/leu-scroll-top.js +6 -0
  198. package/src/components/scroll-top/scroll-top.css +34 -0
  199. package/src/components/scroll-top/stories/scroll-top.stories.js +217 -0
  200. package/src/components/scroll-top/test/scroll-top.test.js +22 -0
  201. package/src/components/select/Select.js +24 -6
  202. package/src/components/select/select.css +2 -2
  203. package/src/components/table/table.css +2 -2
  204. package/src/components/visually-hidden/VisuallyHidden.js +13 -0
  205. package/src/components/visually-hidden/leu-visually-hidden.js +6 -0
  206. package/src/components/visually-hidden/stories/visually-hidden.stories.js +22 -0
  207. package/src/components/visually-hidden/test/visually-hidden.test.js +36 -0
  208. package/src/components/visually-hidden/visually-hidden.css +10 -0
  209. package/src/lib/defineElement.js +1 -1
  210. package/src/lib/hasSlotController.js +5 -3
  211. package/src/lib/utils.js +21 -3
  212. package/src/styles/custom-properties.css +6 -2
  213. package/src/styles/font-definitions.json +202 -0
  214. package/stylelint.config.mjs +2 -0
  215. package/tsconfig.build.json +21 -0
  216. package/tsconfig.json +16 -0
@@ -20,8 +20,8 @@
20
20
  --chip-radio-background-default: var(--leu-color-black-0);
21
21
  --chip-radio-background-selected: var(--leu-color-func-cyan);
22
22
 
23
- --chip-font-regular: var(--leu-font-regular);
24
- --chip-font-black: var(--leu-font-black);
23
+ --chip-font-regular: var(--leu-font-family-regular);
24
+ --chip-font-black: var(--leu-font-family-black);
25
25
 
26
26
  --chip-background-color: var(--chip-background-color-default);
27
27
  --chip-color: var(--chip-color-default);
@@ -29,6 +29,9 @@
29
29
  --chip-radio-background: var(--chip-radio-background-default);
30
30
 
31
31
  font-family: var(--chip-font-regular);
32
+
33
+ /* Allow shrinking to achieve text truncation (ellipsis) */
34
+ min-width: 0;
32
35
  }
33
36
 
34
37
  :host([inverted]) {
@@ -61,8 +64,11 @@
61
64
  cursor: pointer;
62
65
 
63
66
  display: inline-flex;
64
- align-items: center;
65
67
  gap: 0.5rem;
68
+
69
+ /* Allow shrinking to achieve text truncation (ellipsis) */
70
+ min-width: 0;
71
+ max-width: 100%;
66
72
  }
67
73
 
68
74
  .button:hover,
@@ -109,6 +115,7 @@
109
115
 
110
116
  :host([variant="radio"]) .button::before {
111
117
  content: "";
118
+ flex: 0 0 1rem;
112
119
  width: 1rem;
113
120
  height: 1rem;
114
121
  background-color: var(--chip-radio-background);
@@ -123,6 +130,10 @@
123
130
  .label {
124
131
  position: relative;
125
132
  top: -0.0625rem;
133
+
134
+ overflow: hidden;
135
+ text-overflow: ellipsis;
136
+ white-space: nowrap;
126
137
  }
127
138
 
128
139
  .icon svg {
@@ -1,7 +1,10 @@
1
1
  import { html } from "lit"
2
+ import { ifDefined } from "lit/directives/if-defined.js"
3
+ import { styleMap } from "lit/directives/style-map.js"
2
4
 
3
5
  import "../leu-chip-selectable.js"
4
6
  import "../leu-chip-removable.js"
7
+ import "../leu-chip-link.js"
5
8
  import "../leu-chip-group.js"
6
9
 
7
10
  import { SELECTION_MODES } from "../ChipGroup.js"
@@ -15,7 +18,13 @@ export default {
15
18
  control: "select",
16
19
  options: Object.values(SELECTION_MODES),
17
20
  },
18
- inverted: { control: "boolean" },
21
+ headingLevel: {
22
+ control: "select",
23
+ options: [1, 2, 3, 4, 5, 6],
24
+ },
25
+ "--leu-chip-group-gap": {
26
+ control: "text",
27
+ },
19
28
  },
20
29
  args: {
21
30
  selectionMode: "",
@@ -32,73 +41,115 @@ export default {
32
41
  },
33
42
  }
34
43
 
35
- const chips = ["Chip 1", "Chip 2", "Chip 3"]
44
+ const chips = [
45
+ "Chip mit einem sehr langen Text der dann hoffentlich mal abgeschnitten wird",
46
+ "Chip 2",
47
+ "Chip 3",
48
+ ]
36
49
 
37
- function invertedBackground(args, content) {
38
- return html`
39
- <div
40
- style="background: ${args.inverted
41
- ? "hsla(209, 83%, 59%, 1)"
42
- : "var(--leu-color-black-5)"}; padding: 1rem;"
43
- data-root
50
+ const links = [
51
+ "Steuererklärung",
52
+ "Abstimmungen",
53
+ "Zentrale Aufnahmeprüfung",
54
+ "Pass & Identitätskarte",
55
+ "Arbeiten beim Kanton",
56
+ ]
57
+
58
+ function invertedBackground({ args, content }) {
59
+ return {
60
+ content: html`
61
+ <div
62
+ style="background: ${args.inverted
63
+ ? "hsla(209, 83%, 59%, 1)"
64
+ : "var(--leu-color-black-5)"}; padding: 1rem;"
65
+ data-root
66
+ >
67
+ ${content}
68
+ </div>
69
+ `,
70
+ args,
71
+ }
72
+ }
73
+
74
+ function chipGroup({ args, content }) {
75
+ const styles = {
76
+ "--leu-chip-group-gap": args["--leu-chip-group-gap"],
77
+ }
78
+
79
+ const nextContent = html`
80
+ <leu-chip-group
81
+ style=${styleMap(styles)}
82
+ selection-mode=${ifDefined(args.selectionMode)}
83
+ heading-level=${ifDefined(args.headingLevel)}
84
+ label=${ifDefined(args.label)}
85
+ ?inverted=${args.inverted}
44
86
  >
45
87
  ${content}
46
- </div>
88
+ </leu-chip-group>
47
89
  `
90
+
91
+ return { args, content: nextContent }
48
92
  }
49
93
 
50
94
  function DefaultTemplate(args) {
51
95
  const content = html`
52
- <leu-chip-group selection-mode=${args.selectionMode}>
53
- ${chips.map(
54
- (chip) => html`
55
- <leu-chip-removable ?inverted=${args.inverted} label=${chip}>
56
- </leu-chip-removable>
57
- `
58
- )}
59
- </leu-chip-group>
96
+ ${chips.map(
97
+ (chip) => html`
98
+ <leu-chip-removable ?inverted=${args.inverted} label=${chip}>
99
+ </leu-chip-removable>
100
+ `
101
+ )}
60
102
  `
61
103
 
62
- return invertedBackground(args, content)
104
+ return invertedBackground(chipGroup({ args, content })).content
63
105
  }
64
106
 
65
107
  function SingleTemplate(args) {
66
108
  const content = html`
67
- <leu-chip-group selection-mode=${args.selectionMode}>
68
- ${chips.map(
69
- (chip) => html`
70
- <leu-chip-selectable
71
- ?inverted=${args.inverted}
72
- variant=${SELECTABLE_VARIANTS.radio}
73
- value="chip-${chip}"
74
- label=${chip}
75
- >
76
- </leu-chip-selectable>
77
- `
78
- )}
79
- </leu-chip-group>
109
+ ${chips.map(
110
+ (chip) => html`
111
+ <leu-chip-selectable
112
+ ?inverted=${args.inverted}
113
+ variant=${SELECTABLE_VARIANTS.radio}
114
+ value="chip-${chip}"
115
+ label=${chip}
116
+ >
117
+ </leu-chip-selectable>
118
+ `
119
+ )}
80
120
  `
81
121
 
82
- return invertedBackground(args, content)
122
+ return invertedBackground(chipGroup({ args, content })).content
83
123
  }
84
124
 
85
125
  function MultipleTemplate(args) {
86
126
  const content = html`
87
- <leu-chip-group selection-mode=${args.selectionMode}>
88
- ${chips.map(
89
- (chip) => html`
90
- <leu-chip-selectable
91
- ?inverted=${args.inverted}
92
- value="chip-${chip}"
93
- label=${chip}
94
- >
95
- </leu-chip-selectable>
96
- `
97
- )}
98
- </leu-chip-group>
127
+ ${chips.map(
128
+ (chip) => html`
129
+ <leu-chip-selectable
130
+ ?inverted=${args.inverted}
131
+ value="chip-${chip}"
132
+ label=${chip}
133
+ >
134
+ </leu-chip-selectable>
135
+ `
136
+ )}
99
137
  `
100
138
 
101
- return invertedBackground(args, content)
139
+ return invertedBackground(chipGroup({ args, content })).content
140
+ }
141
+
142
+ function LabeledTemplate(args) {
143
+ const content = html`
144
+ ${links.map(
145
+ (chip) => html`
146
+ <leu-chip-link ?inverted=${args.inverted} label=${chip}>
147
+ </leu-chip-link>
148
+ `
149
+ )}
150
+ `
151
+
152
+ return invertedBackground(chipGroup({ args, content })).content
102
153
  }
103
154
 
104
155
  export const Default = DefaultTemplate.bind({})
@@ -109,3 +160,6 @@ Single.args = { selectionMode: SELECTION_MODES.single }
109
160
 
110
161
  export const Multiple = MultipleTemplate.bind({})
111
162
  Multiple.args = { selectionMode: SELECTION_MODES.multiple }
163
+
164
+ export const Labeled = LabeledTemplate.bind({})
165
+ Labeled.args = { label: "Top Themen" }
@@ -4,7 +4,7 @@ import { sendKeys } from "@web/test-runner-commands"
4
4
 
5
5
  import { iconPaths } from "../../icon/icon.js"
6
6
 
7
- import "../leu-chip-group.js"
7
+ import "../leu-chip-removable.js"
8
8
 
9
9
  async function defaultFixture() {
10
10
  return fixture(
@@ -62,7 +62,7 @@ describe("LeuChipRemovable", () => {
62
62
  const button = el.shadowRoot.querySelector("button")
63
63
 
64
64
  setTimeout(() => button.click())
65
- const event = await oneEvent(el, "remove")
65
+ const event = await oneEvent(el, "leu:remove")
66
66
 
67
67
  expect(event).to.exist
68
68
  })
@@ -72,7 +72,7 @@ describe("LeuChipRemovable", () => {
72
72
 
73
73
  el.focus()
74
74
  setTimeout(() => sendKeys({ press: "Enter" }))
75
- const event = await oneEvent(el, "remove")
75
+ const event = await oneEvent(el, "leu:remove")
76
76
 
77
77
  expect(event).to.exist
78
78
  })
@@ -25,9 +25,29 @@ export class LeuDropdown extends LitElement {
25
25
  this.menuItems = []
26
26
  }
27
27
 
28
+ connectedCallback() {
29
+ super.connectedCallback()
30
+ this.addEventListener("keyup", this._keyUpHandler)
31
+ document.addEventListener("click", this._documentClickHandler)
32
+ }
33
+
28
34
  disconnectedCallback() {
29
35
  super.disconnectedCallback()
30
36
  this._removeMenuItemListeners()
37
+ this.removeEventListener("keyup", this._keyUpHandler)
38
+ document.removeEventListener("click", this._documentClickHandler)
39
+ }
40
+
41
+ _documentClickHandler = (event) => {
42
+ if (!this.contains(event.target)) {
43
+ this.expanded = false
44
+ }
45
+ }
46
+
47
+ _keyUpHandler(event) {
48
+ if (event.key === "Escape") {
49
+ this.expanded = false
50
+ }
31
51
  }
32
52
 
33
53
  _handleSlotChange() {
@@ -67,13 +87,13 @@ export class LeuDropdown extends LitElement {
67
87
  slot="anchor"
68
88
  icon="download"
69
89
  variant="ghost"
70
- label=${this.label}
71
- expanded=${this.expanded ? "open" : "closed"}
90
+ expanded=${this.expanded ? "true" : "false"}
72
91
  aria-expanded=${this.expanded ? "true" : "false"}
73
92
  aria-controls="content"
74
93
  ?active=${this.expanded}
75
94
  @click=${this._handleToggleClick}
76
- ></leu-button>
95
+ >${this.label}</leu-button
96
+ >
77
97
  <div id="content" class="content" ?hidden=${!this.expanded}>
78
98
  <slot @slotchange=${this._handleSlotChange}></slot>
79
99
  </div>
@@ -56,6 +56,7 @@ const VALIDATION_MESSAGES = {
56
56
  * @prop {string} maxlength - The maximum length of the input element.
57
57
  * @prop {object} validationMessages - Custom validation messages. The key is the name of the validity state and the value is the message.
58
58
  * @prop {boolean} novalidate - Disables the browser's validation.
59
+ * @prop {string} step - The step value of the input element.
59
60
  *
60
61
  * @fires {CustomEvent} input - Dispatched when the value of the input element changes.
61
62
  * @fires {CustomEvent} change - Dispatched when the value of the input element changes and the input element loses focus.
@@ -91,12 +92,13 @@ export class LeuInput extends LitElement {
91
92
  /* Validation attributes */
92
93
  pattern: { type: String, reflect: true },
93
94
  type: { type: String, reflect: true },
94
- min: { type: Number, reflect: true },
95
- max: { type: Number, reflect: true },
96
- maxlength: { type: Number, reflect: true },
97
- minlength: { type: Number, reflect: true },
95
+ min: { type: String, reflect: true },
96
+ max: { type: String, reflect: true },
97
+ maxlength: { type: String, reflect: true },
98
+ minlength: { type: String, reflect: true },
98
99
  validationMessages: { type: Object },
99
100
  novalidate: { type: Boolean, reflect: true },
101
+ step: { type: String, reflect: true },
100
102
 
101
103
  /** @type {ValidityState} */
102
104
  _validity: { state: true },
@@ -407,6 +409,7 @@ export class LeuInput extends LitElement {
407
409
  max=${ifDefined(this.max)}
408
410
  maxlength=${ifDefined(this.maxlength)}
409
411
  minlength=${ifDefined(this.minlength)}
412
+ step=${ifDefined(this.step)}
410
413
  ref=${ref(this._inputRef)}
411
414
  aria-invalid=${isInvalid}
412
415
  />
@@ -26,8 +26,8 @@
26
26
 
27
27
  --input-clear-color: var(--leu-color-black-60);
28
28
 
29
- --input-font-regular: var(--leu-font-regular);
30
- --input-font-black: var(--leu-font-black);
29
+ --input-font-regular: var(--leu-font-family-regular);
30
+ --input-font-black: var(--leu-font-family-black);
31
31
 
32
32
  display: block;
33
33
  font-family: var(--input-font-regular);
@@ -42,12 +42,15 @@ function Template(args) {
42
42
  max,
43
43
  minlength,
44
44
  maxlength,
45
+ step,
45
46
  disabled = false,
46
47
  required = false,
47
48
  clearable = false,
48
49
  novalidate = false,
49
50
  } = args
50
51
 
52
+ console.log(min, max)
53
+
51
54
  return html`
52
55
  <leu-input
53
56
  value=${ifDefined(value)}
@@ -62,6 +65,7 @@ function Template(args) {
62
65
  max=${ifDefined(max)}
63
66
  minlength=${ifDefined(minlength)}
64
67
  maxlength=${ifDefined(maxlength)}
68
+ step=${ifDefined(step)}
65
69
  label=${label}
66
70
  ?disabled=${disabled}
67
71
  ?required=${required}
@@ -189,3 +193,12 @@ Search.parameters = {
189
193
  },
190
194
  },
191
195
  }
196
+
197
+ export const Step = Template.bind({})
198
+ Step.args = {
199
+ label: "Tage",
200
+ type: "number",
201
+ min: "1",
202
+ max: "7",
203
+ step: "1",
204
+ }
@@ -21,6 +21,7 @@ async function defaultFixture(args = {}) {
21
21
  max=${ifDefined(args.max)}
22
22
  minlength=${ifDefined(args.minlength)}
23
23
  maxlength=${ifDefined(args.maxlength)}
24
+ step=${ifDefined(args.step)}
24
25
  label=${args.label || "Label"}
25
26
  ?disabled=${args.disabled}
26
27
  ?required=${args.required}
@@ -10,10 +10,10 @@
10
10
  --background-disabled: var(--leu-color-black-black-0);
11
11
  --color: var(--leu-color-black-transp-60);
12
12
  --color-disabled: var(--leu-color-black-transp-20);
13
- --font-regular: var(--leu-font-regular);
14
- --font-black: var(--leu-font-black);
13
+ --font-regular: var(--leu-font-family-regular);
14
+ --font-black: var(--leu-font-family-black);
15
15
 
16
- font-family: var(--leu-font-regular);
16
+ font-family: var(--leu-font-family-regular);
17
17
  }
18
18
 
19
19
  .button {
@@ -4,6 +4,8 @@ import { live } from "lit/directives/live.js"
4
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
  /**
@@ -20,62 +22,84 @@ export class LeuPagination extends LitElement {
20
22
  delegatesFocus: true,
21
23
  }
22
24
 
23
- static events = {
24
- range: {},
25
- }
26
-
27
25
  static properties = {
28
- page: { type: Number, reflect: true },
26
+ defaultPage: { type: Number, reflect: true },
29
27
  itemsPerPage: { type: Number, reflect: true },
30
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 },
31
39
  }
32
40
 
33
41
  constructor() {
34
42
  super()
35
- /** @type {number} */
36
- this.page = 1
37
- /** @type {number} */
43
+
44
+ /** @type {Number} */
38
45
  this.numOfItems = 1
39
- /** @type {number} */
46
+ /** @type {Number} */
40
47
  this.itemsPerPage = 1
48
+ /** @type {Number} */
49
+ this._page = 1
41
50
  }
42
51
 
43
- get maxPage() {
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
+ }
58
+ }
59
+
60
+ get page() {
61
+ return this._page
62
+ }
63
+
64
+ set page(page) {
65
+ this._page = this._clampPage(page)
66
+ }
67
+
68
+ get startIndex() {
69
+ return (this.page - 1) * this.itemsPerPage
70
+ }
71
+
72
+ get endIndex() {
73
+ return Math.min(this.startIndex + this.itemsPerPage, this.numOfItems)
74
+ }
75
+
76
+ get _maxPage() {
44
77
  return Math.ceil(this.numOfItems / this.itemsPerPage)
45
78
  }
46
79
 
47
- get firstPage() {
48
- return this.boundPage === MIN_PAGE
80
+ _isFirstPage() {
81
+ return this.page === MIN_PAGE
49
82
  }
50
83
 
51
- get lastPage() {
52
- return this.boundPage === this.maxPage
84
+ _isLastPage() {
85
+ return this.page === this._maxPage
53
86
  }
54
87
 
55
- /**
56
- * The boundPage getter is necessary to ensure that the current page (this.page) is always within the valid range of pages.
57
- * It prevents the page number from going below the minimum page limit (MIN_PAGE) or above the maximum page limit (this.maxPage).
58
- * This is important for the correct functioning of the pagination system, as it prevents users from navigating to non-existent pages.
59
- *
60
- * @returns {number}
61
- */
62
- get boundPage() {
63
- return Math.min(Math.max(this.page, MIN_PAGE), this.maxPage)
88
+ _clampPage(page) {
89
+ return Math.min(Math.max(page, MIN_PAGE), this._maxPage)
64
90
  }
65
91
 
66
- numberUpdate(number) {
92
+ _updatePage(page) {
67
93
  const prevPage = this.page
68
- this.page = number
94
+ this.page = this._clampPage(page)
69
95
 
70
96
  if (this.page !== prevPage) {
71
- const startIndex = (this.boundPage - 1) * this.itemsPerPage
72
- const endIndex = Math.min(startIndex + this.itemsPerPage, this.numOfItems)
73
97
  this.dispatchEvent(
74
98
  new CustomEvent("leu:pagechange", {
75
99
  detail: {
76
- startIndex,
77
- endIndex,
78
- page: this.boundPage,
100
+ startIndex: this.startIndex,
101
+ endIndex: this.endIndex,
102
+ page: this.page,
79
103
  },
80
104
  bubbles: false,
81
105
  })
@@ -83,58 +107,65 @@ export class LeuPagination extends LitElement {
83
107
  }
84
108
  }
85
109
 
86
- change(event) {
87
- this.numberUpdate(parseInt(event.target.value, 10) || 0)
110
+ _handleChange(event) {
111
+ this._updatePage(parseInt(event.target.value, 10) || 0)
88
112
  }
89
113
 
90
- input(event) {
114
+ _handleInput(event) {
91
115
  if (event.target.value !== "") {
92
116
  event.preventDefault()
93
- this.change(event)
117
+ this._handleChange(event)
94
118
  }
95
119
  }
96
120
 
97
- keydown(event) {
121
+ _handleKeyDown(event) {
98
122
  if (event.key === "ArrowUp") {
99
123
  event.preventDefault()
100
- this.numberUpdate(this.boundPage + 1)
124
+ this._updatePage(this.page + 1)
101
125
  }
102
126
  if (event.key === "ArrowDown") {
103
127
  event.preventDefault()
104
- this.numberUpdate(this.boundPage - 1)
128
+ this._updatePage(this.page - 1)
105
129
  }
106
130
  }
107
131
 
108
132
  render() {
109
133
  return html`
134
+ <leu-visually-hidden>
135
+ <label for="page-input">Aktuelle Seite</label>
136
+ </leu-visually-hidden>
110
137
  <input
138
+ id="page-input"
111
139
  class="input"
112
140
  min=${MIN_PAGE}
113
- max=${this.maxPage}
114
- .value=${live(this.boundPage.toString())}
115
- @input=${this.input}
116
- @change=${this.change}
117
- @keydown=${this.keydown}
141
+ max=${this._maxPage}
142
+ .value=${live(this.page.toString())}
143
+ @input=${this._handleInput}
144
+ @change=${this._handleChange}
145
+ @keydown=${this._handleKeyDown}
118
146
  type="number"
119
147
  />
120
- <div class="label">von ${this.maxPage}</div>
121
- <leu-button
122
- icon="angleLeft"
123
- variant="secondary"
124
- @click=${(_) => {
125
- this.numberUpdate(this.boundPage - 1)
126
- }}
127
- ?disabled=${this.firstPage}
128
- ></leu-button>
129
- <leu-button
130
- icon="angleRight"
131
- variant="secondary"
132
- @click=${(_) => {
133
- this.numberUpdate(this.boundPage + 1)
134
- }}
135
- ?disabled=${this.lastPage}
136
- style="margin-left:4px;"
137
- ></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>
138
169
  `
139
170
  }
140
171
  }
@@ -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
+ }