@statistikzh/leu 0.8.0 → 0.10.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/.github/workflows/release-please.yml +3 -3
- package/CHANGELOG.md +34 -0
- package/dist/Accordion.d.ts +1 -1
- package/dist/Accordion.js +1 -1
- package/dist/Breadcrumb.d.ts +1 -1
- package/dist/Breadcrumb.js +1 -1
- package/dist/Button.d.ts +45 -1
- package/dist/Button.d.ts.map +1 -1
- package/dist/Button.js +473 -6
- package/dist/ButtonGroup.d.ts +1 -1
- package/dist/ButtonGroup.js +1 -1
- package/dist/Checkbox.d.ts +1 -1
- package/dist/Checkbox.js +2 -2
- package/dist/CheckboxGroup.d.ts +1 -1
- package/dist/CheckboxGroup.js +1 -1
- package/dist/Chip.d.ts +1 -1
- package/dist/Chip.js +1 -1
- package/dist/ChipGroup.d.ts +1 -1
- package/dist/ChipGroup.js +2 -2
- package/dist/ChipLink.js +1 -1
- package/dist/ChipRemovable.js +1 -1
- package/dist/ChipSelectable.js +1 -1
- package/dist/Dialog.d.ts +17 -0
- package/dist/Dialog.d.ts.map +1 -0
- package/dist/Dialog.js +255 -0
- package/dist/Dropdown.d.ts +1 -1
- package/dist/Dropdown.d.ts.map +1 -1
- package/dist/Dropdown.js +4 -3
- package/dist/Icon.d.ts +1 -1
- package/dist/Icon.js +1 -1
- package/dist/Input.d.ts +1 -1
- package/dist/Input.d.ts.map +1 -1
- package/dist/Input.js +3 -1
- package/dist/{LeuElement-a20c5fd6.d.ts → LeuElement-6fbc0dee.d.ts} +1 -1
- package/dist/LeuElement-6fbc0dee.d.ts.map +1 -0
- package/dist/{LeuElement-a20c5fd6.js → LeuElement-6fbc0dee.js} +1 -1
- package/dist/Menu.d.ts +1 -1
- package/dist/Menu.js +1 -1
- package/dist/MenuItem.d.ts +5 -1
- package/dist/MenuItem.d.ts.map +1 -1
- package/dist/MenuItem.js +18 -3
- package/dist/Pagination.d.ts +1 -1
- package/dist/Pagination.d.ts.map +1 -1
- package/dist/Pagination.js +3 -2
- package/dist/Popup.d.ts +1 -1
- package/dist/Popup.js +1 -1
- package/dist/Radio.d.ts +1 -1
- package/dist/Radio.js +2 -2
- package/dist/RadioGroup.d.ts +1 -1
- package/dist/RadioGroup.js +1 -1
- package/dist/ScrollTop.d.ts +1 -1
- package/dist/ScrollTop.d.ts.map +1 -1
- package/dist/ScrollTop.js +3 -2
- package/dist/Select.d.ts +1 -1
- package/dist/Select.d.ts.map +1 -1
- package/dist/Select.js +10 -5
- package/dist/Spinner.d.ts +9 -0
- package/dist/Spinner.d.ts.map +1 -0
- package/dist/Spinner.js +53 -0
- package/dist/Table.d.ts +1 -1
- package/dist/Table.d.ts.map +1 -1
- package/dist/Table.js +3 -2
- package/dist/VisuallyHidden.d.ts +1 -1
- package/dist/VisuallyHidden.js +1 -1
- package/dist/hasSlotController-04d0dfa2.d.ts +38 -0
- package/dist/hasSlotController-04d0dfa2.d.ts.map +1 -0
- package/dist/hasSlotController-04d0dfa2.js +75 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -2
- package/dist/leu-accordion.js +1 -1
- package/dist/leu-breadcrumb.js +1 -1
- package/dist/leu-button-group.js +1 -1
- package/dist/leu-button.d.ts +1 -1
- package/dist/leu-button.d.ts.map +1 -1
- package/dist/leu-button.js +3 -2
- package/dist/leu-checkbox-group.js +1 -1
- package/dist/leu-checkbox.js +1 -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.d.ts +3 -0
- package/dist/leu-dialog.d.ts.map +1 -0
- package/dist/leu-dialog.js +11 -0
- package/dist/leu-dropdown.js +3 -2
- 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.js +3 -2
- package/dist/leu-popup.js +1 -1
- package/dist/leu-radio-group.js +1 -1
- package/dist/leu-radio.js +1 -1
- package/dist/leu-scroll-top.js +3 -2
- package/dist/leu-select.js +3 -2
- package/dist/leu-spinner.d.ts +3 -0
- package/dist/leu-spinner.d.ts.map +1 -0
- package/dist/leu-spinner.js +7 -0
- package/dist/leu-table.js +3 -2
- package/dist/leu-visually-hidden.js +1 -1
- package/dist/theme.css +370 -217
- package/dist/vscode.html-custom-data.json +31 -0
- package/dist/vue/index.d.ts +34 -0
- package/dist/web-types.json +47 -1
- package/package.json +1 -1
- package/rollup.config.js +4 -1
- package/scripts/generate-component/templates/[namespace]-[name].js +1 -2
- package/scripts/postcss-leu-font-styles.cjs +29 -35
- package/src/components/button/button.css +2 -3
- package/src/components/checkbox/Checkbox.js +1 -1
- package/src/components/checkbox/stories/checkbox.stories.js +7 -2
- package/src/components/chip/chip-group.css +1 -1
- package/src/components/dialog/Dialog.js +100 -0
- package/src/components/dialog/dialog.css +162 -0
- package/src/components/dialog/leu-dialog.js +5 -0
- package/src/components/dialog/stories/dialog.stories.js +144 -0
- package/src/components/dialog/test/dialog.test.js +85 -0
- package/src/components/dropdown/Dropdown.js +1 -1
- package/src/components/dropdown/test/dropdown.test.js +20 -3
- package/src/components/input/input.css +2 -0
- package/src/components/menu/MenuItem.js +21 -2
- package/src/components/menu/stories/menu-item.stories.js +18 -8
- package/src/components/menu/test/menu-item.test.js +23 -0
- package/src/components/radio/Radio.js +1 -1
- package/src/components/radio/stories/radio.stories.js +7 -1
- package/src/components/select/Select.js +8 -6
- package/src/components/select/test/select.test.js +30 -0
- package/src/components/spinner/Spinner.js +31 -0
- package/src/components/spinner/leu-spinner.js +5 -0
- package/src/components/spinner/spinner.css +20 -0
- package/src/components/spinner/stories/spinner.stories.js +29 -0
- package/src/components/spinner/test/spinner.test.js +30 -0
- package/src/styles/custom-properties.css +35 -3
- package/src/styles/font-definitions.json +27 -19
- package/src/styles/style.stories.js +61 -0
- package/dist/Button-3adfb3ed.d.ts +0 -83
- package/dist/Button-3adfb3ed.d.ts.map +0 -1
- package/dist/Button-3adfb3ed.js +0 -545
- package/dist/LeuElement-a20c5fd6.d.ts.map +0 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import "../leu-dialog.js"
|
|
3
|
+
import "../../input/leu-input.js"
|
|
4
|
+
import "../../button/leu-button.js"
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: "Dialog",
|
|
8
|
+
component: "leu-dialog",
|
|
9
|
+
parameters: {
|
|
10
|
+
design: {
|
|
11
|
+
type: "figma",
|
|
12
|
+
url: "https://www.figma.com/file/d6Pv21UVUbnBs3AdcZijHmbN/KTZH-Design-System?node-id=16052-88818&node-type=canvas&t=swv3JY6UIoCBUpXa-11",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function openDialog() {
|
|
18
|
+
document.querySelector("leu-dialog").show()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function closeDialog() {
|
|
22
|
+
document.querySelector("leu-dialog").close()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function OpenDialogButton() {
|
|
26
|
+
return html` <leu-button @click=${() => openDialog()}>
|
|
27
|
+
Open dialog
|
|
28
|
+
</leu-button>`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function Template({ label, sublabel }) {
|
|
32
|
+
return html`
|
|
33
|
+
${OpenDialogButton()}
|
|
34
|
+
|
|
35
|
+
<leu-dialog label="${label}" sublabel="${sublabel}">
|
|
36
|
+
<leu-input label="Eingabe"></leu-input>
|
|
37
|
+
<br />
|
|
38
|
+
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
|
|
39
|
+
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
|
|
40
|
+
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
|
|
41
|
+
clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
|
|
42
|
+
amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
|
|
43
|
+
nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed
|
|
44
|
+
diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
|
|
45
|
+
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor
|
|
46
|
+
sit amet.
|
|
47
|
+
</leu-dialog>
|
|
48
|
+
`
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export const Regular = Template.bind({})
|
|
52
|
+
Regular.args = {
|
|
53
|
+
label: "Property: label",
|
|
54
|
+
rubric: "Property: sublabel",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function ActionButtonsTemplate({ label, sublabel }) {
|
|
58
|
+
return html`
|
|
59
|
+
${OpenDialogButton()}
|
|
60
|
+
|
|
61
|
+
<leu-dialog label="${label}" sublabel="${sublabel}">
|
|
62
|
+
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
|
|
63
|
+
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
|
|
64
|
+
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
|
|
65
|
+
clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
|
|
66
|
+
amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
|
|
67
|
+
nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed
|
|
68
|
+
diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
|
|
69
|
+
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor
|
|
70
|
+
sit amet.
|
|
71
|
+
<slot slot="actionbar">
|
|
72
|
+
<leu-button
|
|
73
|
+
variant="secondary"
|
|
74
|
+
@click=${() => {
|
|
75
|
+
// eslint-disable-next-line no-alert
|
|
76
|
+
alert("Fenster wird geschlossen")
|
|
77
|
+
closeDialog()
|
|
78
|
+
}}
|
|
79
|
+
>
|
|
80
|
+
Abbrechen
|
|
81
|
+
</leu-button>
|
|
82
|
+
<leu-button
|
|
83
|
+
@click=${() => {
|
|
84
|
+
// eslint-disable-next-line no-alert
|
|
85
|
+
alert("Fenster wird offen gelassen")
|
|
86
|
+
}}
|
|
87
|
+
>
|
|
88
|
+
Anwenden
|
|
89
|
+
</leu-button>
|
|
90
|
+
</slot>
|
|
91
|
+
</leu-dialog>
|
|
92
|
+
`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export const ActionButtons = ActionButtonsTemplate.bind({})
|
|
96
|
+
ActionButtons.args = {
|
|
97
|
+
label: "Property: label",
|
|
98
|
+
sublabel: "Property: sublabel",
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function SmallContentTemplate({ label, sublabel }) {
|
|
102
|
+
return html`
|
|
103
|
+
${OpenDialogButton()}
|
|
104
|
+
|
|
105
|
+
<leu-dialog label="${label}" sublabel="${sublabel}">
|
|
106
|
+
<p>Ein kurzer Text</p>
|
|
107
|
+
</leu-dialog>
|
|
108
|
+
`
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const SmallContent = SmallContentTemplate.bind({})
|
|
112
|
+
SmallContent.args = {
|
|
113
|
+
label: "Dialog Titel",
|
|
114
|
+
sublabel: "Property: sublabel",
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function ScrollablePageTemplate({ label, sublabel }) {
|
|
118
|
+
return html`
|
|
119
|
+
<div style="height: 200vh">
|
|
120
|
+
${OpenDialogButton()}
|
|
121
|
+
|
|
122
|
+
<leu-dialog label="${label}" sublabel="${sublabel}">
|
|
123
|
+
<leu-input label="Eingabe"></leu-input>
|
|
124
|
+
<br />
|
|
125
|
+
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
|
|
126
|
+
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
|
|
127
|
+
voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
|
|
128
|
+
clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit
|
|
129
|
+
amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
|
|
130
|
+
nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat,
|
|
131
|
+
sed diam voluptua. At vero eos et accusam et justo duo dolores et ea
|
|
132
|
+
rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem
|
|
133
|
+
ipsum dolor sit amet.
|
|
134
|
+
</leu-dialog>
|
|
135
|
+
</div>
|
|
136
|
+
<div style="height: 200vh">${OpenDialogButton()}</div>
|
|
137
|
+
`
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export const ScrollablePage = ScrollablePageTemplate.bind({})
|
|
141
|
+
ScrollablePage.args = {
|
|
142
|
+
label: "Dialog Titel",
|
|
143
|
+
sublabel: "Property: sublabel",
|
|
144
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import { fixture, expect } from "@open-wc/testing"
|
|
3
|
+
|
|
4
|
+
import "../leu-dialog.js"
|
|
5
|
+
|
|
6
|
+
async function defaultFixture() {
|
|
7
|
+
return fixture(
|
|
8
|
+
html`<leu-dialog label="Title" sublabel="Category">
|
|
9
|
+
This is the content of the dialog.
|
|
10
|
+
</leu-dialog>`
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("LeuDialog", () => {
|
|
15
|
+
it("is a defined element", async () => {
|
|
16
|
+
const el = await customElements.get("leu-dialog")
|
|
17
|
+
|
|
18
|
+
expect(el).not.to.be.undefined
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it("passes the a11y audit", async () => {
|
|
22
|
+
const el = await defaultFixture()
|
|
23
|
+
|
|
24
|
+
await expect(el).shadowDom.to.be.accessible()
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it("passes the a11y audit when the modal is open", async () => {
|
|
28
|
+
const el = await defaultFixture()
|
|
29
|
+
|
|
30
|
+
el.show()
|
|
31
|
+
|
|
32
|
+
await expect(el).shadowDom.to.be.accessible()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it("opens the dialog when calling show()", async () => {
|
|
36
|
+
const el = await defaultFixture()
|
|
37
|
+
|
|
38
|
+
el.show()
|
|
39
|
+
|
|
40
|
+
const dialog = el.shadowRoot.querySelector("dialog")
|
|
41
|
+
|
|
42
|
+
expect(dialog.open).to.be.true
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it("closes the dialog when calling close()", async () => {
|
|
46
|
+
const el = await defaultFixture()
|
|
47
|
+
|
|
48
|
+
el.show()
|
|
49
|
+
el.close()
|
|
50
|
+
|
|
51
|
+
const dialog = el.shadowRoot.querySelector("dialog")
|
|
52
|
+
|
|
53
|
+
expect(dialog.open).to.be.false
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it("renders a label and a sublabel", async () => {
|
|
57
|
+
const el = await defaultFixture()
|
|
58
|
+
|
|
59
|
+
const label = el.shadowRoot.querySelector("h1")
|
|
60
|
+
const sublabel = el.shadowRoot.querySelector(".subtitle")
|
|
61
|
+
|
|
62
|
+
expect(label).to.have.text("Title")
|
|
63
|
+
expect(sublabel).to.have.text("Category")
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it("renders a close button", async () => {
|
|
67
|
+
const el = await defaultFixture()
|
|
68
|
+
|
|
69
|
+
const closeButton = el.shadowRoot.querySelector(".close-button")
|
|
70
|
+
|
|
71
|
+
expect(closeButton).to.exist
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it("closes the dialog when clicking the close button", async () => {
|
|
75
|
+
const el = await defaultFixture()
|
|
76
|
+
const dialog = el.shadowRoot.querySelector("dialog")
|
|
77
|
+
|
|
78
|
+
el.show()
|
|
79
|
+
|
|
80
|
+
const closeButton = el.shadowRoot.querySelector(".close-button")
|
|
81
|
+
expect(dialog.open).to.be.true
|
|
82
|
+
closeButton.click()
|
|
83
|
+
expect(dialog.open).to.be.false
|
|
84
|
+
})
|
|
85
|
+
})
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { html } from "lit"
|
|
2
|
-
import { fixture, expect } from "@open-wc/testing"
|
|
2
|
+
import { fixture, expect, elementUpdated } from "@open-wc/testing"
|
|
3
3
|
|
|
4
4
|
import "../leu-dropdown.js"
|
|
5
5
|
|
|
6
|
-
async function defaultFixture() {
|
|
7
|
-
return fixture(html` <leu-dropdown
|
|
6
|
+
async function defaultFixture(args = { expanded: false }) {
|
|
7
|
+
return fixture(html` <leu-dropdown
|
|
8
|
+
label="Download"
|
|
9
|
+
?expanded=${args.expanded}
|
|
10
|
+
>
|
|
8
11
|
<leu-menu>
|
|
9
12
|
<leu-menu-item>Als CSV Tabelle</leu-menu-item>
|
|
10
13
|
<leu-menu-item>Als XLS Tabelle</leu-menu-item>
|
|
@@ -28,4 +31,18 @@ describe("LeuDropdown", () => {
|
|
|
28
31
|
|
|
29
32
|
await expect(el).shadowDom.to.be.accessible()
|
|
30
33
|
})
|
|
34
|
+
|
|
35
|
+
it("closes the popup when the document is clicked outside the component", async () => {
|
|
36
|
+
const el = await defaultFixture()
|
|
37
|
+
|
|
38
|
+
const toggleButton = el.shadowRoot.querySelector("leu-button")
|
|
39
|
+
toggleButton.click()
|
|
40
|
+
await elementUpdated(el)
|
|
41
|
+
|
|
42
|
+
expect(el.expanded).to.be.true
|
|
43
|
+
|
|
44
|
+
document.body.click()
|
|
45
|
+
|
|
46
|
+
expect(el.expanded).to.be.false
|
|
47
|
+
})
|
|
31
48
|
})
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
|
|
55
55
|
border: var(--input-border-width) solid var(--input-border-color);
|
|
56
56
|
border-radius: 2px;
|
|
57
|
+
background: var(--leu-color-black-0);
|
|
57
58
|
|
|
58
59
|
line-height: 1;
|
|
59
60
|
}
|
|
@@ -79,6 +80,7 @@
|
|
|
79
80
|
color: var(--input-color);
|
|
80
81
|
|
|
81
82
|
border: 0;
|
|
83
|
+
background: var(--leu-color-black-0);
|
|
82
84
|
|
|
83
85
|
padding-block: 2rem 1rem;
|
|
84
86
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { html } from "lit"
|
|
1
|
+
import { html, nothing } from "lit"
|
|
2
2
|
import { ifDefined } from "lit/directives/if-defined.js"
|
|
3
3
|
|
|
4
4
|
import { LeuElement } from "../../lib/LeuElement.js"
|
|
@@ -15,6 +15,7 @@ import styles from "./menu-item.css"
|
|
|
15
15
|
* @tagname leu-menu-item
|
|
16
16
|
* @slot - The label of the menu item
|
|
17
17
|
* @property {boolean} active - Defines if the item is selected or checked
|
|
18
|
+
* @property {boolean} multipleSelection - If the item is part of a multiple selection. Renders a checkmark before the label when active
|
|
18
19
|
* @property {boolean} disabled - Disables the underlying button or link
|
|
19
20
|
* @property {string} value - The value of the item. It must not contain commas. See `getValue()`
|
|
20
21
|
* @property {string} href - The href of the underlying link
|
|
@@ -38,6 +39,11 @@ export class LeuMenuItem extends LeuElement {
|
|
|
38
39
|
|
|
39
40
|
static properties = {
|
|
40
41
|
active: { type: Boolean, reflect: true },
|
|
42
|
+
multipleSelection: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
reflect: true,
|
|
45
|
+
attr: "multiple-selection",
|
|
46
|
+
},
|
|
41
47
|
disabled: { type: Boolean, reflect: true },
|
|
42
48
|
tabbable: { type: Boolean, reflect: true },
|
|
43
49
|
href: { type: String, reflect: true },
|
|
@@ -50,6 +56,7 @@ export class LeuMenuItem extends LeuElement {
|
|
|
50
56
|
|
|
51
57
|
this.active = false
|
|
52
58
|
this.disabled = false
|
|
59
|
+
this.multipleSelection = false
|
|
53
60
|
this.value = undefined
|
|
54
61
|
this.href = undefined
|
|
55
62
|
this.tabbable = undefined
|
|
@@ -142,9 +149,21 @@ export class LeuMenuItem extends LeuElement {
|
|
|
142
149
|
</button>`
|
|
143
150
|
}
|
|
144
151
|
|
|
152
|
+
_renderBeforeSlotDefault() {
|
|
153
|
+
if (!this.multipleSelection) {
|
|
154
|
+
return nothing
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return this.active
|
|
158
|
+
? html`<leu-icon name="check"></leu-icon>`
|
|
159
|
+
: html`<leu-icon></leu-icon>`
|
|
160
|
+
}
|
|
161
|
+
|
|
145
162
|
render() {
|
|
146
163
|
const content = html`
|
|
147
|
-
<slot class="before" name="before"
|
|
164
|
+
<slot class="before" name="before"
|
|
165
|
+
>${this._renderBeforeSlotDefault()}</slot
|
|
166
|
+
>
|
|
148
167
|
<span class="label"><slot></slot></span>
|
|
149
168
|
<slot class="after" name="after"></slot>
|
|
150
169
|
`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { html } from "lit"
|
|
1
|
+
import { html, nothing } from "lit"
|
|
2
2
|
import { ifDefined } from "lit/directives/if-defined.js"
|
|
3
3
|
|
|
4
4
|
import "../leu-menu-item.js"
|
|
@@ -29,14 +29,19 @@ function Template(args) {
|
|
|
29
29
|
href=${ifDefined(args.href)}
|
|
30
30
|
?active=${args.active}
|
|
31
31
|
?disabled=${args.disabled}
|
|
32
|
+
?multipleSelection=${args.multipleSelection}
|
|
32
33
|
>
|
|
33
|
-
${
|
|
34
|
-
?
|
|
35
|
-
|
|
34
|
+
${args.before
|
|
35
|
+
? isIcon(args.before)
|
|
36
|
+
? html`<leu-icon slot="before" name=${args.before}></leu-icon>`
|
|
37
|
+
: html`<span slot="before">${args.before}</span>`
|
|
38
|
+
: nothing}
|
|
36
39
|
${args.label}
|
|
37
|
-
${
|
|
38
|
-
?
|
|
39
|
-
|
|
40
|
+
${args.after
|
|
41
|
+
? isIcon(args.after)
|
|
42
|
+
? html`<leu-icon slot="after" name=${args.after}></leu-icon>`
|
|
43
|
+
: html`<span slot="after">${args.after}</span>`
|
|
44
|
+
: null}
|
|
40
45
|
</leu-menu-item>
|
|
41
46
|
`
|
|
42
47
|
}
|
|
@@ -50,7 +55,7 @@ Active.args = {
|
|
|
50
55
|
|
|
51
56
|
export const IconBefore = Template.bind({})
|
|
52
57
|
IconBefore.args = {
|
|
53
|
-
before: "
|
|
58
|
+
before: "download",
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
export const IconAfterLink = Template.bind({})
|
|
@@ -69,3 +74,8 @@ export const IconPlaceholder = Template.bind({})
|
|
|
69
74
|
IconPlaceholder.args = {
|
|
70
75
|
before: "EMPTY",
|
|
71
76
|
}
|
|
77
|
+
|
|
78
|
+
export const MultipleSelection = Template.bind({})
|
|
79
|
+
MultipleSelection.args = {
|
|
80
|
+
multipleSelection: true,
|
|
81
|
+
}
|
|
@@ -15,6 +15,7 @@ async function defaultFixture(args = {}) {
|
|
|
15
15
|
?active=${args.active}
|
|
16
16
|
?disabled=${args.disabled}
|
|
17
17
|
?tabbable=${args.tabbable}
|
|
18
|
+
?multipleSelection=${args.multipleSelection}
|
|
18
19
|
>
|
|
19
20
|
${args.label}
|
|
20
21
|
</leu-menu-item>
|
|
@@ -183,4 +184,26 @@ describe("LeuMenuItem", () => {
|
|
|
183
184
|
|
|
184
185
|
expect(el.getValue()).to.equal("download-01")
|
|
185
186
|
})
|
|
187
|
+
|
|
188
|
+
it("renders a palceholder icon when the menu item is part of multiple selection but not active", async () => {
|
|
189
|
+
const el = await defaultFixture({
|
|
190
|
+
label: "Download",
|
|
191
|
+
multipleSelection: true,
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
const icon = el.shadowRoot.querySelector("leu-icon")
|
|
195
|
+
expect(icon).to.exist
|
|
196
|
+
expect(icon).to.have.attribute("name", "EMPTY")
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
it("renders a check icon when the menu item is part of multiple selection and is active", async () => {
|
|
200
|
+
const el = await defaultFixture({
|
|
201
|
+
label: "Download",
|
|
202
|
+
multipleSelection: true,
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
const icon = el.shadowRoot.querySelector("leu-icon")
|
|
206
|
+
expect(icon).to.exist
|
|
207
|
+
expect(icon).to.have.attribute("name", "check")
|
|
208
|
+
})
|
|
186
209
|
})
|
|
@@ -54,7 +54,7 @@ export class LeuRadio extends LeuElement {
|
|
|
54
54
|
@input=${this.handleInput}
|
|
55
55
|
.checked=${this.checked}
|
|
56
56
|
?disabled=${this.disabled}
|
|
57
|
-
.value=${this.value}
|
|
57
|
+
.value=${this.value ?? ""}
|
|
58
58
|
/>
|
|
59
59
|
<label for=${`radio-${this.name}`} class="label"><slot></slot></label>
|
|
60
60
|
`
|
|
@@ -22,9 +22,15 @@ function Template({
|
|
|
22
22
|
value = "",
|
|
23
23
|
checked = false,
|
|
24
24
|
disabled = false,
|
|
25
|
+
name = "",
|
|
25
26
|
}) {
|
|
26
27
|
return html`
|
|
27
|
-
<leu-radio
|
|
28
|
+
<leu-radio
|
|
29
|
+
.value=${value}
|
|
30
|
+
?checked=${checked}
|
|
31
|
+
?disabled=${disabled}
|
|
32
|
+
name=${name}
|
|
33
|
+
>
|
|
28
34
|
${label}
|
|
29
35
|
</leu-radio>
|
|
30
36
|
`
|
|
@@ -146,11 +146,13 @@ export class LeuSelect extends LeuElement {
|
|
|
146
146
|
|
|
147
147
|
if (
|
|
148
148
|
changedProperties.has("value") ||
|
|
149
|
-
changedProperties.has("_optionFilter")
|
|
149
|
+
changedProperties.has("_optionFilter") ||
|
|
150
|
+
changedProperties.has("multiple")
|
|
150
151
|
) {
|
|
151
152
|
this._updateMenuItems({
|
|
152
153
|
value: changedProperties.has("value"),
|
|
153
154
|
optionFilter: changedProperties.has("_optionFilter"),
|
|
155
|
+
multiple: changedProperties.has("multiple"),
|
|
154
156
|
})
|
|
155
157
|
}
|
|
156
158
|
}
|
|
@@ -171,6 +173,10 @@ export class LeuSelect extends LeuElement {
|
|
|
171
173
|
|
|
172
174
|
/* eslint-disable no-param-reassign */
|
|
173
175
|
menuItems.forEach((menuItem) => {
|
|
176
|
+
if (changed.multiple) {
|
|
177
|
+
menuItem.multipleSelection = this.multiple
|
|
178
|
+
}
|
|
179
|
+
|
|
174
180
|
if (changed.optionFilter) {
|
|
175
181
|
menuItem.hidden =
|
|
176
182
|
this._optionFilter !== "" &&
|
|
@@ -203,11 +209,7 @@ export class LeuSelect extends LeuElement {
|
|
|
203
209
|
* @param {MouseEvent} event
|
|
204
210
|
*/
|
|
205
211
|
_handleDocumentClick = (event) => {
|
|
206
|
-
if (
|
|
207
|
-
event.target instanceof Node &&
|
|
208
|
-
!this.contains(event.target) &&
|
|
209
|
-
this.open
|
|
210
|
-
) {
|
|
212
|
+
if (!event.composedPath().includes(this) && this.open) {
|
|
211
213
|
this._closeDropdown()
|
|
212
214
|
}
|
|
213
215
|
}
|
|
@@ -404,4 +404,34 @@ describe("LeuSelect", () => {
|
|
|
404
404
|
const popup = el.shadowRoot.querySelector("leu-popup")
|
|
405
405
|
expect(popup.active).to.not.be.true
|
|
406
406
|
})
|
|
407
|
+
|
|
408
|
+
it("sets the multipleSelection property on the menu items when multiple selection is allowed", async () => {
|
|
409
|
+
const el = await defaultFixture({
|
|
410
|
+
options: MUNICIPALITIES,
|
|
411
|
+
label: "Gemeinde",
|
|
412
|
+
multiple: true,
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
const menuItems = Array.from(el.querySelectorAll("leu-menu-item"))
|
|
416
|
+
expect(menuItems.every((item) => item.multipleSelection)).to.be.true
|
|
417
|
+
|
|
418
|
+
el.multiple = false
|
|
419
|
+
await elementUpdated(el)
|
|
420
|
+
|
|
421
|
+
expect(menuItems.every((item) => !item.multipleSelection)).to.be.true
|
|
422
|
+
|
|
423
|
+
it("closes the popup when the document is clicked outside the component", async () => {
|
|
424
|
+
const el = await defaultFixture({
|
|
425
|
+
options: MUNICIPALITIES,
|
|
426
|
+
label: "Gemeinde",
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
const toggleButton = el.shadowRoot.querySelector(".select-toggle")
|
|
430
|
+
toggleButton.click()
|
|
431
|
+
|
|
432
|
+
document.body.click()
|
|
433
|
+
|
|
434
|
+
const popup = el.shadowRoot.querySelector("leu-popup")
|
|
435
|
+
expect(popup.active).to.not.be.true
|
|
436
|
+
})
|
|
407
437
|
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
|
|
3
|
+
import { LeuElement } from "../../lib/LeuElement.js"
|
|
4
|
+
|
|
5
|
+
import styles from "./spinner.css"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @tagname leu-spinner
|
|
9
|
+
* @cssprop --leu-spinner-size - The size of the spinner.
|
|
10
|
+
*/
|
|
11
|
+
export class LeuSpinner extends LeuElement {
|
|
12
|
+
static styles = styles
|
|
13
|
+
|
|
14
|
+
render() {
|
|
15
|
+
return html`
|
|
16
|
+
<svg
|
|
17
|
+
class="spinner"
|
|
18
|
+
fill="none"
|
|
19
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
20
|
+
viewBox="0 0 56 56"
|
|
21
|
+
role="presentation"
|
|
22
|
+
>
|
|
23
|
+
<path
|
|
24
|
+
d="M13.8579 13.858c7.8105-7.8105 20.4737-7.8105 28.2842 0 7.8105 7.8104 7.8105 20.4737 0 28.2842-7.8105 7.8105-20.4737 7.8105-28.2842 0-4.3487-4.3486-6.2761-10.2016-5.7824-15.8838"
|
|
25
|
+
stroke="currentColor"
|
|
26
|
+
stroke-width="3"
|
|
27
|
+
/>
|
|
28
|
+
</svg>
|
|
29
|
+
`
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
@keyframes leu-spinner-rotate {
|
|
2
|
+
from {
|
|
3
|
+
transform: rotate(0deg);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
to {
|
|
7
|
+
transform: rotate(360deg);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
:host {
|
|
12
|
+
color: var(--leu-color-func-cyan);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.spinner {
|
|
16
|
+
display: block;
|
|
17
|
+
width: var(--leu-spinner-size, 3.5rem);
|
|
18
|
+
height: var(--leu-spinner-size, 3.5rem);
|
|
19
|
+
animation: leu-spinner-rotate 1s cubic-bezier(0.49, 0.12, 0.56, 0.91) infinite;
|
|
20
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import "../leu-spinner.js"
|
|
3
|
+
import { styleMap } from "lit/directives/style-map.js"
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: "Spinner",
|
|
7
|
+
component: "leu-spinner",
|
|
8
|
+
argTypes: {
|
|
9
|
+
color: {
|
|
10
|
+
control: {
|
|
11
|
+
type: "color",
|
|
12
|
+
presetColors: ["#009ee0", "#d93c1a", "#1a7f1f"],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function Template({ size, color }) {
|
|
19
|
+
const styles = styleMap({
|
|
20
|
+
color,
|
|
21
|
+
"--leu-spinner-size": size ? `${size}px` : null,
|
|
22
|
+
})
|
|
23
|
+
return html` <leu-spinner style=${styles}></leu-spinner> `
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const Regular = Template.bind({})
|
|
27
|
+
Regular.args = {
|
|
28
|
+
size: 56,
|
|
29
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import { fixture, expect } from "@open-wc/testing"
|
|
3
|
+
|
|
4
|
+
import "../leu-spinner.js"
|
|
5
|
+
|
|
6
|
+
async function defaultFixture() {
|
|
7
|
+
return fixture(html`<leu-spinner></leu-spinner>`)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
describe("LeuSpinner", () => {
|
|
11
|
+
it("is a defined element", async () => {
|
|
12
|
+
const el = await customElements.get("leu-spinner")
|
|
13
|
+
|
|
14
|
+
await expect(el).not.to.be.undefined
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it("passes the a11y audit", async () => {
|
|
18
|
+
const el = await defaultFixture()
|
|
19
|
+
|
|
20
|
+
await expect(el).shadowDom.to.be.accessible()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it("renders a svg element with a 56x56 viewbox", async () => {
|
|
24
|
+
const el = await defaultFixture()
|
|
25
|
+
|
|
26
|
+
const svg = el.shadowRoot.querySelector("svg")
|
|
27
|
+
|
|
28
|
+
expect(svg).to.have.attribute("viewBox", "0 0 56 56")
|
|
29
|
+
})
|
|
30
|
+
})
|