@statistikzh/leu 0.14.4 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +17 -0
- package/dist/Accordion.js +2 -30
- package/dist/Button.d.ts +56 -68
- package/dist/Button.js +74 -52
- package/dist/ButtonGroup.d.ts +9 -9
- package/dist/ButtonGroup.js +30 -20
- package/dist/ChartWrapper.d.ts +38 -0
- package/dist/ChartWrapper.js +164 -0
- package/dist/Checkbox.d.ts +6 -21
- package/dist/Checkbox.js +17 -9
- package/dist/CheckboxGroup.d.ts +13 -14
- package/dist/CheckboxGroup.js +18 -11
- package/dist/Chip.js +1 -1
- package/dist/ChipGroup.js +1 -1
- package/dist/ChipLink.js +1 -1
- package/dist/ChipRemovable.js +1 -1
- package/dist/ChipSelectable.js +1 -1
- package/dist/Dialog.js +1 -1
- package/dist/Dropdown.js +3 -1
- package/dist/Icon.js +1 -1
- package/dist/Input.js +1 -1
- package/dist/{LeuElement-x8UlIDDl.js → LeuElement-B84x5CPL.js} +1 -1
- package/dist/Menu.js +1 -1
- package/dist/MenuItem.js +1 -1
- package/dist/Pagination.d.ts +40 -28
- package/dist/Pagination.js +39 -14
- package/dist/Placeholder.d.ts +27 -0
- package/dist/Placeholder.js +90 -0
- package/dist/Popup.js +1 -1
- package/dist/Radio.d.ts +6 -21
- package/dist/Radio.js +17 -9
- package/dist/RadioGroup.d.ts +28 -23
- package/dist/RadioGroup.js +29 -16
- package/dist/Range.js +1 -1
- package/dist/ScrollTop.d.ts +0 -1
- package/dist/ScrollTop.js +3 -1
- package/dist/Select.js +3 -1
- package/dist/Spinner.js +1 -1
- package/dist/Table.d.ts +0 -1
- package/dist/Table.js +3 -1
- package/dist/VisuallyHidden.js +1 -1
- package/dist/_tslib-CNEFicEt.js +30 -0
- package/dist/components/button/Button.d.ts +55 -67
- package/dist/components/button/Button.d.ts.map +1 -1
- package/dist/components/button/stories/button.stories.d.ts.map +1 -1
- package/dist/components/button-group/ButtonGroup.d.ts +9 -9
- package/dist/components/button-group/ButtonGroup.d.ts.map +1 -1
- package/dist/components/chart-wrapper/ChartWrapper.d.ts +34 -0
- package/dist/components/chart-wrapper/ChartWrapper.d.ts.map +1 -0
- package/dist/components/chart-wrapper/leu-chart-wrapper.d.ts +3 -0
- package/dist/components/chart-wrapper/leu-chart-wrapper.d.ts.map +1 -0
- package/dist/components/chart-wrapper/stories/chart-wrapper.stories.d.ts +47 -0
- package/dist/components/chart-wrapper/stories/chart-wrapper.stories.d.ts.map +1 -0
- package/dist/components/chart-wrapper/test/chart-wrapper.test.d.ts +2 -0
- package/dist/components/chart-wrapper/test/chart-wrapper.test.d.ts.map +1 -0
- package/dist/components/checkbox/Checkbox.d.ts +6 -21
- package/dist/components/checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/checkbox/CheckboxGroup.d.ts +13 -14
- package/dist/components/checkbox/CheckboxGroup.d.ts.map +1 -1
- package/dist/components/icon/stories/icon.stories.d.ts +10 -0
- package/dist/components/icon/stories/icon.stories.d.ts.map +1 -1
- package/dist/components/pagination/Pagination.d.ts +40 -27
- package/dist/components/pagination/Pagination.d.ts.map +1 -1
- package/dist/components/pagination/stories/pagination.stories.d.ts +10 -2
- package/dist/components/pagination/stories/pagination.stories.d.ts.map +1 -1
- package/dist/components/placeholder/Placeholder.d.ts +23 -0
- package/dist/components/placeholder/Placeholder.d.ts.map +1 -0
- package/dist/components/placeholder/leu-placeholder.d.ts +3 -0
- package/dist/components/placeholder/leu-placeholder.d.ts.map +1 -0
- package/dist/components/placeholder/stories/placeholder.stories.d.ts +27 -0
- package/dist/components/placeholder/stories/placeholder.stories.d.ts.map +1 -0
- package/dist/components/placeholder/test/placeholder.test.d.ts +2 -0
- package/dist/components/placeholder/test/placeholder.test.d.ts.map +1 -0
- package/dist/components/radio/Radio.d.ts +6 -21
- package/dist/components/radio/Radio.d.ts.map +1 -1
- package/dist/components/radio/RadioGroup.d.ts +28 -23
- package/dist/components/radio/RadioGroup.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/leu-accordion.js +2 -1
- package/dist/leu-button-group.js +8 -1
- package/dist/leu-button.d.ts +0 -1
- package/dist/leu-button.js +3 -1
- package/dist/leu-chart-wrapper.d.ts +6 -0
- package/dist/leu-chart-wrapper.js +11 -0
- package/dist/leu-checkbox-group.js +5 -1
- package/dist/leu-checkbox.js +3 -1
- package/dist/leu-chip-group.js +1 -1
- package/dist/leu-chip-link.js +1 -1
- package/dist/leu-chip-removable.js +1 -1
- package/dist/leu-chip-selectable.js +1 -1
- package/dist/leu-dialog.js +1 -1
- package/dist/leu-dropdown.js +3 -1
- package/dist/leu-icon.js +1 -1
- package/dist/leu-input.js +1 -1
- package/dist/leu-menu-item.js +1 -1
- package/dist/leu-menu.js +1 -1
- package/dist/leu-pagination.d.ts +0 -1
- package/dist/leu-pagination.js +3 -1
- package/dist/leu-placeholder.d.ts +4 -0
- package/dist/leu-placeholder.js +7 -0
- package/dist/leu-popup.js +1 -1
- package/dist/leu-radio-group.js +4 -1
- package/dist/leu-radio.js +3 -1
- package/dist/leu-range.js +1 -1
- package/dist/leu-scroll-top.d.ts +0 -1
- package/dist/leu-scroll-top.js +3 -1
- package/dist/leu-select.js +3 -1
- package/dist/leu-spinner.js +1 -1
- package/dist/leu-table.d.ts +0 -1
- package/dist/leu-table.js +3 -1
- package/dist/leu-visually-hidden.js +1 -1
- package/dist/lib/a11y.d.ts +2 -2
- package/dist/theme.css +18 -18
- package/dist/vscode.html-custom-data.json +95 -25
- package/dist/vue/index.d.ts +86 -46
- package/dist/web-types.json +222 -80
- package/package.json +1 -1
- package/release-please-config.json +1 -2
- package/scripts/generate-component/templates/stories/[name].stories.ts +17 -4
- package/scripts/postcss-leu-font-styles.cjs +10 -10
- package/src/components/button/Button.ts +95 -79
- package/src/components/button/stories/button.stories.ts +5 -6
- package/src/components/button-group/ButtonGroup.ts +18 -13
- package/src/components/chart-wrapper/ChartWrapper.ts +78 -0
- package/src/components/chart-wrapper/chart-wrapper.css +87 -0
- package/src/components/chart-wrapper/leu-chart-wrapper.ts +5 -0
- package/src/components/chart-wrapper/stories/chart-wrapper.stories.ts +58 -0
- package/src/components/chart-wrapper/test/chart-wrapper.test.ts +77 -0
- package/src/components/checkbox/Checkbox.ts +13 -15
- package/src/components/checkbox/CheckboxGroup.ts +20 -16
- package/src/components/icon/stories/icon.stories.ts +27 -0
- package/src/components/pagination/Pagination.ts +45 -32
- package/src/components/pagination/stories/pagination.stories.ts +28 -17
- package/src/components/placeholder/Placeholder.ts +33 -0
- package/src/components/placeholder/leu-placeholder.ts +5 -0
- package/src/components/placeholder/placeholder.css +59 -0
- package/src/components/placeholder/stories/placeholder.stories.ts +34 -0
- package/src/components/placeholder/test/placeholder.test.ts +31 -0
- package/src/components/radio/Radio.ts +13 -15
- package/src/components/radio/RadioGroup.ts +42 -28
- package/src/docs/contributing.mdx +1 -1
- package/src/index.ts +1 -0
- package/src/lib/a11y.ts +2 -2
- package/src/styles/theme.css +89 -1
- package/src/styles/custom-properties.css +0 -89
|
@@ -1,38 +1,42 @@
|
|
|
1
1
|
import { html } from "lit"
|
|
2
2
|
import { classMap } from "lit/directives/class-map.js"
|
|
3
|
+
import { property } from "lit/decorators.js"
|
|
3
4
|
|
|
4
5
|
import { LeuElement } from "../../lib/LeuElement.js"
|
|
5
6
|
|
|
6
7
|
import styles from "./checkbox-group.css"
|
|
8
|
+
import { LeuCheckbox } from "./Checkbox.js"
|
|
7
9
|
|
|
8
10
|
/**
|
|
11
|
+
*
|
|
12
|
+
* @slot - Place the checkboxes inside the default slot.
|
|
9
13
|
* @tagname leu-checkbox-group
|
|
10
14
|
*/
|
|
11
15
|
export class LeuCheckboxGroup extends LeuElement {
|
|
12
16
|
static styles = [LeuElement.styles, styles]
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
+
/**
|
|
19
|
+
* Defines how the checkboxes should be aligned.
|
|
20
|
+
*/
|
|
21
|
+
@property({ type: String, reflect: true })
|
|
22
|
+
orientation: "horizontal" | "vertical" = "horizontal"
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* The label of the checkbox group
|
|
26
|
+
*/
|
|
27
|
+
@property({ type: String, reflect: true })
|
|
28
|
+
label?: string
|
|
29
|
+
|
|
30
|
+
private items: LeuCheckbox[] = []
|
|
25
31
|
|
|
26
32
|
get value() {
|
|
27
33
|
return this.items.filter((i) => i.checked).map((i) => i.value)
|
|
28
34
|
}
|
|
29
35
|
|
|
30
|
-
handleSlotChange() {
|
|
31
|
-
this.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
handleItems() {
|
|
35
|
-
this.items = Array.from(this.querySelectorAll(":scope > *:not([slot])"))
|
|
36
|
+
private handleSlotChange() {
|
|
37
|
+
this.items = Array.from(
|
|
38
|
+
this.querySelectorAll(":scope > *:not([slot])"),
|
|
39
|
+
).filter((el) => el instanceof LeuCheckbox)
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
render() {
|
|
@@ -45,3 +45,30 @@ Colored.args = {
|
|
|
45
45
|
size: 24,
|
|
46
46
|
color: "#d93c1a",
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
export const Overview = {
|
|
50
|
+
render: ({ color, size }) => html`
|
|
51
|
+
<ul
|
|
52
|
+
style="font-family: var(--leu-font-family-regular); color: var(--leu-color-black-60); list-style: none; margin: 0; padding: 0;"
|
|
53
|
+
>
|
|
54
|
+
${Object.keys(paths).map(
|
|
55
|
+
(name) =>
|
|
56
|
+
html`<li
|
|
57
|
+
style="display: flex; align-items: center; margin-bottom: 1rem; gap: 1rem;"
|
|
58
|
+
>
|
|
59
|
+
<leu-icon
|
|
60
|
+
style="color: ${color}; ${size
|
|
61
|
+
? `--leu-icon-size: ${size}px`
|
|
62
|
+
: ""};"
|
|
63
|
+
name=${ifDefined(name)}
|
|
64
|
+
></leu-icon>
|
|
65
|
+
${name}
|
|
66
|
+
</li>`,
|
|
67
|
+
)}
|
|
68
|
+
</ul>
|
|
69
|
+
`,
|
|
70
|
+
args: {
|
|
71
|
+
size: 24,
|
|
72
|
+
color: "#000000",
|
|
73
|
+
},
|
|
74
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { html } from "lit"
|
|
2
2
|
import { live } from "lit/directives/live.js"
|
|
3
|
+
import { property, state } from "lit/decorators.js"
|
|
3
4
|
|
|
4
5
|
import { LeuElement } from "../../lib/LeuElement.js"
|
|
5
6
|
import { LeuButton } from "../button/Button.js"
|
|
@@ -30,32 +31,30 @@ export class LeuPagination extends LeuElement {
|
|
|
30
31
|
delegatesFocus: true,
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
itemsPerPage: { type: Number, reflect: true },
|
|
36
|
-
numOfItems: { type: Number, reflect: true },
|
|
37
|
-
_page: { state: true },
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
constructor() {
|
|
41
|
-
super()
|
|
34
|
+
@property({ type: Number, reflect: true })
|
|
35
|
+
defaultPage?: number
|
|
42
36
|
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Number of items per page.
|
|
39
|
+
*/
|
|
40
|
+
@property({ type: Number, reflect: true })
|
|
41
|
+
itemsPerPage: number = 1
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Total number of items to paginate.
|
|
45
|
+
*/
|
|
46
|
+
@property({ type: Number, reflect: true })
|
|
47
|
+
numOfItems: number = 1
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
49
|
+
/**
|
|
50
|
+
* Internal page state that contains an
|
|
51
|
+
* already clamped page number. Should only
|
|
52
|
+
* be accessed through the `page` getter and
|
|
53
|
+
* setter.
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
@state()
|
|
57
|
+
private _page: number = 1
|
|
59
58
|
|
|
60
59
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
61
60
|
super.attributeChangedCallback(name, oldVal, newVal)
|
|
@@ -65,6 +64,11 @@ export class LeuPagination extends LeuElement {
|
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
|
|
67
|
+
/**
|
|
68
|
+
* The current page number. This is a 1-based index.
|
|
69
|
+
* When setting this value, it will be clamped
|
|
70
|
+
* to the range of valid pages.
|
|
71
|
+
*/
|
|
68
72
|
get page() {
|
|
69
73
|
return this._page
|
|
70
74
|
}
|
|
@@ -73,10 +77,19 @@ export class LeuPagination extends LeuElement {
|
|
|
73
77
|
this._page = this._clampPage(page)
|
|
74
78
|
}
|
|
75
79
|
|
|
80
|
+
/**
|
|
81
|
+
* The index of the first item on the current page.
|
|
82
|
+
*/
|
|
76
83
|
get startIndex() {
|
|
77
84
|
return (this.page - 1) * this.itemsPerPage
|
|
78
85
|
}
|
|
79
86
|
|
|
87
|
+
/**
|
|
88
|
+
* The index of the last item on the current page.
|
|
89
|
+
* This is exclusive, meaning it is one past the last item.
|
|
90
|
+
*
|
|
91
|
+
* @todo This value should be inclusive, meaning it should be the index of the last item on the page.
|
|
92
|
+
*/
|
|
80
93
|
get endIndex() {
|
|
81
94
|
return Math.min(this.startIndex + this.itemsPerPage, this.numOfItems)
|
|
82
95
|
}
|
|
@@ -85,19 +98,19 @@ export class LeuPagination extends LeuElement {
|
|
|
85
98
|
return Math.ceil(this.numOfItems / this.itemsPerPage)
|
|
86
99
|
}
|
|
87
100
|
|
|
88
|
-
_isFirstPage() {
|
|
101
|
+
private _isFirstPage() {
|
|
89
102
|
return this.page === MIN_PAGE
|
|
90
103
|
}
|
|
91
104
|
|
|
92
|
-
_isLastPage() {
|
|
105
|
+
private _isLastPage() {
|
|
93
106
|
return this.page === this._maxPage
|
|
94
107
|
}
|
|
95
108
|
|
|
96
|
-
_clampPage(page) {
|
|
109
|
+
private _clampPage(page: number) {
|
|
97
110
|
return Math.min(Math.max(page, MIN_PAGE), this._maxPage)
|
|
98
111
|
}
|
|
99
112
|
|
|
100
|
-
_updatePage(page) {
|
|
113
|
+
private _updatePage(page) {
|
|
101
114
|
const prevPage = this.page
|
|
102
115
|
this.page = this._clampPage(page)
|
|
103
116
|
|
|
@@ -115,18 +128,18 @@ export class LeuPagination extends LeuElement {
|
|
|
115
128
|
}
|
|
116
129
|
}
|
|
117
130
|
|
|
118
|
-
_handleChange(event) {
|
|
131
|
+
private _handleChange(event: Event & { target: HTMLInputElement }) {
|
|
119
132
|
this._updatePage(parseInt(event.target.value, 10) || 0)
|
|
120
133
|
}
|
|
121
134
|
|
|
122
|
-
_handleInput(event) {
|
|
135
|
+
private _handleInput(event: InputEvent & { target: HTMLInputElement }) {
|
|
123
136
|
if (event.target.value !== "") {
|
|
124
137
|
event.preventDefault()
|
|
125
138
|
this._handleChange(event)
|
|
126
139
|
}
|
|
127
140
|
}
|
|
128
141
|
|
|
129
|
-
_handleKeyDown(event) {
|
|
142
|
+
private _handleKeyDown(event: KeyboardEvent & { target: HTMLInputElement }) {
|
|
130
143
|
if (event.key === "ArrowUp") {
|
|
131
144
|
event.preventDefault()
|
|
132
145
|
this._updatePage(this.page + 1)
|
|
@@ -158,7 +171,7 @@ export class LeuPagination extends LeuElement {
|
|
|
158
171
|
<leu-button
|
|
159
172
|
variant="secondary"
|
|
160
173
|
label="Vorherige Seite"
|
|
161
|
-
@click=${(
|
|
174
|
+
@click=${() => {
|
|
162
175
|
this._updatePage(this.page - 1)
|
|
163
176
|
}}
|
|
164
177
|
?disabled=${this._isFirstPage()}
|
|
@@ -167,7 +180,7 @@ export class LeuPagination extends LeuElement {
|
|
|
167
180
|
<leu-button
|
|
168
181
|
variant="secondary"
|
|
169
182
|
label="Nächste Seite"
|
|
170
|
-
@click=${(
|
|
183
|
+
@click=${() => {
|
|
171
184
|
this._updatePage(this.page + 1)
|
|
172
185
|
}}
|
|
173
186
|
?disabled=${this._isLastPage()}
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { html } from "lit"
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import "../leu-pagination.js"
|
|
2
|
+
import { ifDefined } from "lit/directives/if-defined.js"
|
|
5
3
|
|
|
6
4
|
// https://stackoverflow.com/questions/72566428/storybook-angular-how-to-dynamically-update-args-from-the-template
|
|
7
5
|
import { UPDATE_STORY_ARGS } from "@storybook/core-events" // eslint-disable-line
|
|
8
|
-
import {
|
|
6
|
+
import { action, HandlerFunction } from "@storybook/addon-actions"
|
|
7
|
+
import { Meta, StoryObj } from "@storybook/web-components"
|
|
8
|
+
|
|
9
|
+
import "../leu-pagination.js"
|
|
10
|
+
import { LeuPagination } from "../Pagination.js"
|
|
11
|
+
|
|
12
|
+
interface ExtraArgs {
|
|
13
|
+
onPageChange: HandlerFunction
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type StoryArgs = LeuPagination & ExtraArgs
|
|
17
|
+
type Story = StoryObj<StoryArgs>
|
|
9
18
|
|
|
10
19
|
function updateStorybookArgss(id, args) {
|
|
11
20
|
const channel = window.__STORYBOOK_ADDONS_CHANNEL__
|
|
@@ -69,13 +78,13 @@ export default {
|
|
|
69
78
|
url: "https://www.figma.com/file/d6Pv21UVUbnBs3AdcZijHmbN/KTZH-Design-System?type=design&node-id=17341-82468&mode=design&t=lzVrtq8lxYVJU5TB-11",
|
|
70
79
|
},
|
|
71
80
|
},
|
|
72
|
-
}
|
|
81
|
+
} satisfies Meta<StoryArgs>
|
|
73
82
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
const Template: Story = {
|
|
84
|
+
render: (
|
|
85
|
+
{ startIndex, endIndex, onPageChange, itemsPerPage, defaultPage },
|
|
86
|
+
{ id },
|
|
87
|
+
) => html`
|
|
79
88
|
${items
|
|
80
89
|
.slice(startIndex, endIndex)
|
|
81
90
|
.map((item) => html`<div>${item.label}</div>`)}
|
|
@@ -92,13 +101,15 @@ function Template(
|
|
|
92
101
|
}}
|
|
93
102
|
>
|
|
94
103
|
</leu-pagination>
|
|
95
|
-
|
|
104
|
+
`,
|
|
96
105
|
}
|
|
97
106
|
|
|
98
|
-
export const Regular =
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
107
|
+
export const Regular: Story = {
|
|
108
|
+
...Template,
|
|
109
|
+
args: {
|
|
110
|
+
startIndex: 0,
|
|
111
|
+
endIndex: 5,
|
|
112
|
+
itemsPerPage: 5,
|
|
113
|
+
// defaultPage: 2,
|
|
114
|
+
},
|
|
104
115
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
|
|
3
|
+
import { LeuElement } from "../../lib/LeuElement.js"
|
|
4
|
+
|
|
5
|
+
import styles from "./placeholder.css"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @summary * A placeholder to display when no content is available.
|
|
9
|
+
* @tagname leu-placeholder
|
|
10
|
+
* @slot title - The placeholders title. Use a heading tag (h1-6) depeneding on your context.
|
|
11
|
+
* @slot description - A description of the placeholder. Content is wrapped in a `<p>` tag by the component.
|
|
12
|
+
* @slot cta - A call to action button like "Reload" or "Create". Add a single `<leu-button>`.
|
|
13
|
+
*
|
|
14
|
+
* @todo Add pending state with a skeleton.
|
|
15
|
+
*/
|
|
16
|
+
export class LeuPlaceholder extends LeuElement {
|
|
17
|
+
static styles = [LeuElement.styles, styles]
|
|
18
|
+
|
|
19
|
+
static shadowRootOptions = {
|
|
20
|
+
...LeuElement.shadowRootOptions,
|
|
21
|
+
delegatesFocus: true,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
render() {
|
|
25
|
+
return html`
|
|
26
|
+
<div class="placeholder">
|
|
27
|
+
<slot class="placeholder__title" name="title"></slot>
|
|
28
|
+
<p><slot class="placeholder__description" name="description"></slot></p>
|
|
29
|
+
<slot name="cta"></slot>
|
|
30
|
+
</div>
|
|
31
|
+
`
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
@import url("../../styles/custom-media.css");
|
|
2
|
+
|
|
3
|
+
:host {
|
|
4
|
+
--placeholder-font-regular: var(--leu-font-family-regular);
|
|
5
|
+
--placeholder-font-black: var(--leu-font-family-black);
|
|
6
|
+
|
|
7
|
+
--placeholder-border-color: var(--leu-color-black-20);
|
|
8
|
+
|
|
9
|
+
font-family: var(--placeholder-font-regular);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.placeholder {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
align-items: center;
|
|
16
|
+
text-align: center;
|
|
17
|
+
|
|
18
|
+
border: 2px dashed var(--placeholder-border-color);
|
|
19
|
+
border-radius: 0.25rem;
|
|
20
|
+
|
|
21
|
+
padding: 2rem 1.5rem;
|
|
22
|
+
|
|
23
|
+
@media (--viewport-regular) {
|
|
24
|
+
padding: 2.5rem 2rem;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@media (--viewport-xlarge) {
|
|
28
|
+
padding: 3.5rem 2.5rem;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.placeholder__title {
|
|
33
|
+
display: block;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.placeholder__title::slotted(:where(h1, h2, h3, h4, h5, h6)) {
|
|
37
|
+
font: var(--leu-t-curve-regular-black-font);
|
|
38
|
+
color: var(--leu-color-black-100);
|
|
39
|
+
margin: 0 0 0.5rem;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.placeholder__description {
|
|
43
|
+
font: var(--leu-t-curve-small-regular-font);
|
|
44
|
+
color: var(--leu-color-black-60);
|
|
45
|
+
|
|
46
|
+
margin-bottom: 0.75rem;
|
|
47
|
+
|
|
48
|
+
@media (--viewport-small) {
|
|
49
|
+
margin-bottom: 2rem;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@media (--viewport-regular) {
|
|
53
|
+
margin-bottom: 1.25rem;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@media (--viewport-xlarge) {
|
|
57
|
+
margin-bottom: 1.5rem;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/web-components"
|
|
2
|
+
import { html } from "lit"
|
|
3
|
+
|
|
4
|
+
import "../../button/leu-button.js"
|
|
5
|
+
import "../../icon/leu-icon.js"
|
|
6
|
+
import "../leu-placeholder.js"
|
|
7
|
+
import { LeuPlaceholder } from "../Placeholder.js"
|
|
8
|
+
|
|
9
|
+
type StoryArgs = LeuPlaceholder
|
|
10
|
+
type Story = StoryObj<StoryArgs>
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
title: "Components/Placeholder",
|
|
14
|
+
component: "leu-placeholder",
|
|
15
|
+
} satisfies Meta<StoryArgs>
|
|
16
|
+
|
|
17
|
+
const Template: Story = {
|
|
18
|
+
render: (_args) =>
|
|
19
|
+
html` <leu-placeholder>
|
|
20
|
+
<h2 slot="title">Keine Ergebnisse zu «Regoin Zürich» gefunden.</h2>
|
|
21
|
+
<p slot="description">
|
|
22
|
+
Überprüfen Sie die Schreibweise der eingegebenen Wörter. Versuchen Sie
|
|
23
|
+
andere Stichwörter. Versuchen Sie allgemeinere Stichwörter.
|
|
24
|
+
</p>
|
|
25
|
+
<leu-button slot="cta"> Suche zurücksetzen </leu-button>
|
|
26
|
+
</leu-placeholder>`,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const Regular = {
|
|
30
|
+
...Template,
|
|
31
|
+
args: {
|
|
32
|
+
// Add default args here
|
|
33
|
+
},
|
|
34
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import { fixture, expect } from "@open-wc/testing"
|
|
3
|
+
|
|
4
|
+
import "../leu-placeholder.js"
|
|
5
|
+
|
|
6
|
+
async function defaultFixture() {
|
|
7
|
+
return fixture(
|
|
8
|
+
html`<leu-placeholder>
|
|
9
|
+
<h2 slot="title">Keine Ergebnisse zu «Regoin Zürich» gefunden.</h2>
|
|
10
|
+
<p slot="description">
|
|
11
|
+
Überprüfen Sie die Schreibweise der eingegebenen Wörter. Versuchen Sie
|
|
12
|
+
andere Stichwörter. Versuchen Sie allgemeinere Stichwörter.
|
|
13
|
+
</p>
|
|
14
|
+
<leu-button slot="cta"> Suche zurücksetzen </leu-button>
|
|
15
|
+
</leu-placeholder>`,
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe("LeuPlaceholder", () => {
|
|
20
|
+
it("is a defined element", async () => {
|
|
21
|
+
const el = customElements.get("leu-placeholder")
|
|
22
|
+
|
|
23
|
+
expect(el).not.to.be.undefined
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it("passes the a11y audit", async () => {
|
|
27
|
+
const el = await defaultFixture()
|
|
28
|
+
|
|
29
|
+
await expect(el).shadowDom.to.be.accessible()
|
|
30
|
+
})
|
|
31
|
+
})
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { html } from "lit"
|
|
2
|
+
import { property } from "lit/decorators.js"
|
|
2
3
|
|
|
3
4
|
import { LeuElement } from "../../lib/LeuElement.js"
|
|
4
5
|
|
|
@@ -16,29 +17,26 @@ export class LeuRadio extends LeuElement {
|
|
|
16
17
|
delegatesFocus: true,
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
disabled: { type: Boolean, reflect: true },
|
|
22
|
-
value: { type: String, reflect: true },
|
|
23
|
-
name: { type: String, reflect: true },
|
|
24
|
-
}
|
|
20
|
+
@property({ type: Boolean, reflect: true })
|
|
21
|
+
checked: boolean = false
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
23
|
+
@property({ type: Boolean, reflect: true })
|
|
24
|
+
disabled: boolean = false
|
|
25
|
+
|
|
26
|
+
@property({ type: String, reflect: true })
|
|
27
|
+
value: string = ""
|
|
28
|
+
|
|
29
|
+
@property({ type: String, reflect: true })
|
|
30
|
+
name: string = ""
|
|
33
31
|
|
|
34
|
-
handleChange(event) {
|
|
32
|
+
private handleChange(event: Event & { target: HTMLInputElement }) {
|
|
35
33
|
this.checked = event.target.checked
|
|
36
34
|
|
|
37
35
|
const customEvent = new CustomEvent(event.type, event)
|
|
38
36
|
this.dispatchEvent(customEvent)
|
|
39
37
|
}
|
|
40
38
|
|
|
41
|
-
handleInput(event) {
|
|
39
|
+
private handleInput(event: InputEvent & { target: HTMLInputElement }) {
|
|
42
40
|
this.checked = event.target.checked
|
|
43
41
|
}
|
|
44
42
|
|
|
@@ -1,28 +1,39 @@
|
|
|
1
1
|
import { html } from "lit"
|
|
2
2
|
import { classMap } from "lit/directives/class-map.js"
|
|
3
|
+
import { property } from "lit/decorators.js"
|
|
3
4
|
|
|
4
5
|
import { LeuElement } from "../../lib/LeuElement.js"
|
|
5
6
|
|
|
6
7
|
import styles from "./radio-group.css"
|
|
8
|
+
import { LeuRadio } from "./Radio.js"
|
|
7
9
|
|
|
8
10
|
/**
|
|
11
|
+
* @summary Handles a group of radio buttons, allowing only one to be selected at a time. It provides keyboard navigation and manages focus within the group.
|
|
12
|
+
* @slot - Place the radio buttons inside the default slot.
|
|
9
13
|
* @tagname leu-radio-group
|
|
10
14
|
*/
|
|
11
15
|
export class LeuRadioGroup extends LeuElement {
|
|
12
16
|
static styles = [LeuElement.styles, styles]
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
+
/**
|
|
19
|
+
* Defines how the radio buttons should be aligned.
|
|
20
|
+
*/
|
|
21
|
+
@property({ type: String, reflect: true })
|
|
22
|
+
orientation: "horizontal" | "vertical" = "horizontal"
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* The label of the radio group
|
|
26
|
+
*/
|
|
27
|
+
@property({ type: String, reflect: true })
|
|
28
|
+
label?: string
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Index of the radio button that would be focused
|
|
32
|
+
* when the focus moves into the group.
|
|
33
|
+
*/
|
|
34
|
+
private currentIndex = 0
|
|
35
|
+
|
|
36
|
+
private items: LeuRadio[] = []
|
|
26
37
|
|
|
27
38
|
get value() {
|
|
28
39
|
const checkedValues = this.items
|
|
@@ -42,7 +53,7 @@ export class LeuRadioGroup extends LeuElement {
|
|
|
42
53
|
this.removeEventListeners()
|
|
43
54
|
}
|
|
44
55
|
|
|
45
|
-
addEventListeners() {
|
|
56
|
+
private addEventListeners() {
|
|
46
57
|
/**
|
|
47
58
|
* It is technically possible to add an event listener to the host element
|
|
48
59
|
* before it is connected to the dom. In that case the outside event listener would
|
|
@@ -55,21 +66,21 @@ export class LeuRadioGroup extends LeuElement {
|
|
|
55
66
|
this.addEventListener("keydown", this.handleKeyDown)
|
|
56
67
|
}
|
|
57
68
|
|
|
58
|
-
removeEventListeners() {
|
|
69
|
+
private removeEventListeners() {
|
|
59
70
|
this.removeEventListener("input", this.handleInput, { capture: true })
|
|
60
71
|
this.removeEventListener("focusin", this.handleFocusIn)
|
|
61
72
|
this.removeEventListener("keydown", this.handleKeyDown)
|
|
62
73
|
}
|
|
63
74
|
|
|
64
|
-
handleSlotChange() {
|
|
75
|
+
private handleSlotChange() {
|
|
65
76
|
this.handleItems()
|
|
66
77
|
}
|
|
67
78
|
|
|
68
|
-
handleFocusIn = (e) => {
|
|
69
|
-
this.
|
|
79
|
+
private handleFocusIn = (e: FocusEvent & { target: LeuRadio }) => {
|
|
80
|
+
this.currentIndex = this.items.indexOf(e.target)
|
|
70
81
|
}
|
|
71
82
|
|
|
72
|
-
handleKeyDown = (e) => {
|
|
83
|
+
private handleKeyDown = (e: KeyboardEvent & { target: LeuRadio }) => {
|
|
73
84
|
const currentIndex = this.items.indexOf(e.target)
|
|
74
85
|
|
|
75
86
|
switch (e.key) {
|
|
@@ -93,19 +104,19 @@ export class LeuRadioGroup extends LeuElement {
|
|
|
93
104
|
this.setTabIndex()
|
|
94
105
|
}
|
|
95
106
|
|
|
96
|
-
handleInput = (e) => {
|
|
107
|
+
private handleInput = (e: InputEvent & { target: LeuRadio }) => {
|
|
97
108
|
this.items.forEach((item) => {
|
|
98
109
|
item.checked = item === e.target // eslint-disable-line no-param-reassign
|
|
99
110
|
})
|
|
100
111
|
}
|
|
101
112
|
|
|
102
|
-
selectItem(selectingItem) {
|
|
113
|
+
private selectItem(selectingItem: LeuRadio) {
|
|
103
114
|
this.items.forEach((item) => {
|
|
104
115
|
item.checked = item === selectingItem // eslint-disable-line no-param-reassign
|
|
105
116
|
})
|
|
106
117
|
}
|
|
107
118
|
|
|
108
|
-
selectNextItem(startingIndex, direction) {
|
|
119
|
+
private selectNextItem(startingIndex: number, direction: -1 | 1) {
|
|
109
120
|
let selected = false
|
|
110
121
|
|
|
111
122
|
for (let index = 0; index < this.items.length; index += 1) {
|
|
@@ -124,23 +135,26 @@ export class LeuRadioGroup extends LeuElement {
|
|
|
124
135
|
}
|
|
125
136
|
}
|
|
126
137
|
|
|
127
|
-
setTabIndex() {
|
|
138
|
+
private setTabIndex() {
|
|
128
139
|
this.items.forEach((item, index) => {
|
|
129
|
-
if (index === this.
|
|
130
|
-
item.tabIndex =
|
|
140
|
+
if (index === this.currentIndex) {
|
|
141
|
+
item.tabIndex = 0 // eslint-disable-line no-param-reassign
|
|
131
142
|
} else {
|
|
132
|
-
item.tabIndex =
|
|
143
|
+
item.tabIndex = -1 // eslint-disable-line no-param-reassign
|
|
133
144
|
}
|
|
134
145
|
})
|
|
135
146
|
}
|
|
136
147
|
|
|
137
|
-
handleItems() {
|
|
138
|
-
this.items = Array.from(
|
|
148
|
+
private handleItems() {
|
|
149
|
+
this.items = Array.from(
|
|
150
|
+
this.querySelectorAll(":scope > *:not([slot])"),
|
|
151
|
+
).filter((el) => el instanceof LeuRadio)
|
|
152
|
+
|
|
139
153
|
this.initializeIndex()
|
|
140
154
|
this.setTabIndex()
|
|
141
155
|
}
|
|
142
156
|
|
|
143
|
-
initializeIndex() {
|
|
157
|
+
private initializeIndex() {
|
|
144
158
|
const index = this.items.findIndex(
|
|
145
159
|
(item) => item.hasAttribute("checked") && !item.hasAttribute("disabled"),
|
|
146
160
|
)
|
|
@@ -148,7 +162,7 @@ export class LeuRadioGroup extends LeuElement {
|
|
|
148
162
|
(item) => !item.hasAttribute("disabled"),
|
|
149
163
|
)
|
|
150
164
|
|
|
151
|
-
this.
|
|
165
|
+
this.currentIndex = index >= 0 ? index : nextEnabledIndex
|
|
152
166
|
}
|
|
153
167
|
|
|
154
168
|
render() {
|