@statistikzh/leu 0.14.4 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +8 -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 +153 -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-BhAmogDy.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/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/components/visualization/ChartWrapper.d.ts +34 -0
- package/dist/components/visualization/ChartWrapper.d.ts.map +1 -0
- package/dist/components/visualization/leu-chart-wrapper.d.ts +3 -0
- package/dist/components/visualization/leu-chart-wrapper.d.ts.map +1 -0
- package/dist/components/visualization/stories/chart-wrapper.stories.d.ts +28 -0
- package/dist/components/visualization/stories/chart-wrapper.stories.d.ts.map +1 -0
- package/dist/components/visualization/test/chart-wrapper.test.d.ts +2 -0
- package/dist/components/visualization/test/chart-wrapper.test.d.ts.map +1 -0
- package/dist/index.js +3 -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/vscode.html-custom-data.json +92 -22
- package/dist/vue/index.d.ts +78 -38
- package/dist/web-types.json +208 -66
- package/package.json +1 -1
- package/release-please-config.json +0 -2
- package/scripts/generate-component/templates/stories/[name].stories.ts +17 -4
- 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/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/components/visualization/ChartWrapper.ts +75 -0
- package/src/components/visualization/chart-wrapper.css +78 -0
- package/src/components/visualization/leu-chart-wrapper.ts +5 -0
- package/src/components/visualization/stories/chart-wrapper.stories.ts +52 -0
- package/src/components/visualization/test/chart-wrapper.test.ts +74 -0
- package/src/lib/a11y.ts +2 -2
|
@@ -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() {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { html, nothing } from "lit"
|
|
2
|
+
import { property } from "lit/decorators.js"
|
|
3
|
+
|
|
4
|
+
import { LeuElement } from "../../lib/LeuElement.js"
|
|
5
|
+
|
|
6
|
+
import styles from "./chart-wrapper.css"
|
|
7
|
+
import { HasSlotController } from "../../lib/hasSlotController.js"
|
|
8
|
+
import { LeuSpinner } from "../spinner/Spinner.js"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A wrapper element for charts.
|
|
12
|
+
* @tagname leu-chart-wrapper
|
|
13
|
+
* @slot title - The title of the chart. Use a heading tag (h2-4) depending on your context.
|
|
14
|
+
* @slot description - A description of the chart. Content is wrapped in a `<p>` tag by the component.
|
|
15
|
+
* @slot chart - The actual chart
|
|
16
|
+
* @slot caption - A caption for the chart, e.g. a source or explanation of the data.
|
|
17
|
+
* @slot download - A download button or dropdown to export the chart in different formats.
|
|
18
|
+
*/
|
|
19
|
+
export class LeuChartWrapper extends LeuElement {
|
|
20
|
+
static styles = [LeuElement.styles, styles]
|
|
21
|
+
|
|
22
|
+
static shadowRootOptions = {
|
|
23
|
+
...LeuElement.shadowRootOptions,
|
|
24
|
+
delegatesFocus: true,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static dependencies = {
|
|
28
|
+
"leu-spinner": LeuSpinner,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether the chart is currently loading or not.
|
|
33
|
+
* When set to `true`, a spinner will be shown in the chart container.
|
|
34
|
+
*/
|
|
35
|
+
@property({ type: Boolean, reflect: true })
|
|
36
|
+
pending: boolean = false
|
|
37
|
+
|
|
38
|
+
hasSlotController = new HasSlotController(this, [
|
|
39
|
+
"description",
|
|
40
|
+
"caption",
|
|
41
|
+
"download",
|
|
42
|
+
])
|
|
43
|
+
|
|
44
|
+
render() {
|
|
45
|
+
const hasDescription = this.hasSlotController.test("description")
|
|
46
|
+
const hasCaption = this.hasSlotController.test("caption")
|
|
47
|
+
const hasDownload = this.hasSlotController.test("download")
|
|
48
|
+
|
|
49
|
+
return html`
|
|
50
|
+
<figure>
|
|
51
|
+
<slot name="title" class="title"></slot>
|
|
52
|
+
${hasDescription
|
|
53
|
+
? html`<slot name="description" class="description"></slot>`
|
|
54
|
+
: nothing}
|
|
55
|
+
<div class="chart-container">
|
|
56
|
+
<slot name="chart" class="chart"></slot>
|
|
57
|
+
${this.pending
|
|
58
|
+
? html`<div class="spinner-container">
|
|
59
|
+
<leu-spinner class="spinner"></leu-spinner>
|
|
60
|
+
</div>`
|
|
61
|
+
: nothing}
|
|
62
|
+
</div>
|
|
63
|
+
${hasCaption
|
|
64
|
+
? html`<figcaption>
|
|
65
|
+
<slot name="caption" class="caption"></slot>
|
|
66
|
+
</figcaption>`
|
|
67
|
+
: nothing}
|
|
68
|
+
<hr class="ruler" />
|
|
69
|
+
${hasDownload
|
|
70
|
+
? html`<slot name="download" class="download"></slot>`
|
|
71
|
+
: nothing}
|
|
72
|
+
</figure>
|
|
73
|
+
`
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
@import url("../../styles/custom-media.css");
|
|
2
|
+
|
|
3
|
+
.title::slotted(h2) {
|
|
4
|
+
font: var(--leu-t-curve-large-black-font);
|
|
5
|
+
margin: 0 0 0.75rem;
|
|
6
|
+
|
|
7
|
+
@media (--viewport-medium) {
|
|
8
|
+
margin: 0 0 1.25rem;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@media (--viewport-xlarge) {
|
|
12
|
+
margin: 0 0 1.5rem;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.title::slotted(h3) {
|
|
17
|
+
font: var(--leu-t-curve-medium-black-font);
|
|
18
|
+
margin: 0 0 0.5rem;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.title::slotted(h4) {
|
|
22
|
+
font: var(--leu-t-curve-regular-black-font);
|
|
23
|
+
margin: 0 0 0.5rem;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.description,
|
|
27
|
+
.chart {
|
|
28
|
+
display: block;
|
|
29
|
+
margin-bottom: 0.75rem;
|
|
30
|
+
|
|
31
|
+
@media (--viewport-medium) {
|
|
32
|
+
margin-bottom: 1.25rem;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@media (--viewport-xlarge) {
|
|
36
|
+
margin-bottom: 1.5rem;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.description {
|
|
41
|
+
font: var(--leu-t-curve-small-regular-font);
|
|
42
|
+
color: var(--leu-color-black-60);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.caption {
|
|
46
|
+
font: var(--leu-t-curve-tiny-regular-font);
|
|
47
|
+
color: var(--leu-color-black-60);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.ruler {
|
|
51
|
+
display: block;
|
|
52
|
+
border: none;
|
|
53
|
+
border-top: 1px solid var(--leu-color-black-transp-20);
|
|
54
|
+
margin: 0.75rem 0;
|
|
55
|
+
|
|
56
|
+
@media (--viewport-xlarge) {
|
|
57
|
+
margin-block: 1rem;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.download {
|
|
62
|
+
display: block;
|
|
63
|
+
margin-left: -0.5rem;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.chart-container {
|
|
67
|
+
position: relative;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.spinner-container {
|
|
71
|
+
position: absolute;
|
|
72
|
+
top: 0;
|
|
73
|
+
left: 0;
|
|
74
|
+
width: 100%;
|
|
75
|
+
height: 100%;
|
|
76
|
+
display: grid;
|
|
77
|
+
place-content: center;
|
|
78
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Meta, StoryObj } from "@storybook/web-components"
|
|
2
|
+
import { html } from "lit"
|
|
3
|
+
|
|
4
|
+
import "../../dropdown/leu-dropdown.js"
|
|
5
|
+
import "../leu-chart-wrapper.js"
|
|
6
|
+
import { LeuChartWrapper } from "../ChartWrapper.js"
|
|
7
|
+
|
|
8
|
+
type StoryArgs = LeuChartWrapper
|
|
9
|
+
type Story = StoryObj<StoryArgs>
|
|
10
|
+
|
|
11
|
+
export default {
|
|
12
|
+
title: "Components/ChartWrapper",
|
|
13
|
+
component: "leu-chart-wrapper",
|
|
14
|
+
} satisfies Meta<StoryArgs>
|
|
15
|
+
|
|
16
|
+
const Template: Story = {
|
|
17
|
+
render: ({ pending }) =>
|
|
18
|
+
html`<leu-chart-wrapper ?pending=${pending}>
|
|
19
|
+
<h2 slot="title">Entwicklung der Leerwohnungsziffer seit 1984</h2>
|
|
20
|
+
<span slot="description">Leerwohnungsziffer, in Prozent</span>
|
|
21
|
+
<img
|
|
22
|
+
style="display: block; width: 100%; height: auto;"
|
|
23
|
+
slot="chart"
|
|
24
|
+
src="https://placehold.co/1200x400"
|
|
25
|
+
alt="A placeholder to indicate where a chart would appear"
|
|
26
|
+
/>
|
|
27
|
+
<span slot="caption">Quelle: Statistisches Amt des Kantons Zürich</span>
|
|
28
|
+
<leu-dropdown slot="download" label="Download">
|
|
29
|
+
<leu-icon name="download" slot="icon"></leu-icon>
|
|
30
|
+
<leu-menu>
|
|
31
|
+
<leu-menu-item
|
|
32
|
+
href="https://www.web.statistik.zh.ch/ogd/daten/ressourcen/KTZH_00001120_00002165.csv"
|
|
33
|
+
>OGD Ressource</leu-menu-item
|
|
34
|
+
>
|
|
35
|
+
<leu-menu-item>Als CSV Tabelle</leu-menu-item>
|
|
36
|
+
<leu-menu-item>Als XLS Tabelle</leu-menu-item>
|
|
37
|
+
<hr />
|
|
38
|
+
<leu-menu-item>Als PNG exportieren</leu-menu-item>
|
|
39
|
+
<leu-menu-item>Als SVG exportieren</leu-menu-item>
|
|
40
|
+
<leu-menu-item disabled>Als PDF exportieren</leu-menu-item>
|
|
41
|
+
</leu-menu>
|
|
42
|
+
</leu-dropdown>
|
|
43
|
+
</leu-chart-wrapper>`,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const Regular = {
|
|
47
|
+
...Template,
|
|
48
|
+
args: {
|
|
49
|
+
// Add default args here
|
|
50
|
+
pending: false,
|
|
51
|
+
},
|
|
52
|
+
}
|