@statistikzh/leu 0.2.0 → 0.4.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/deploy-github-pages.yaml +33 -0
- package/.storybook/main.js +27 -1
- package/.storybook/manager-head.html +1 -0
- package/.storybook/manager.js +9 -0
- package/.storybook/preview-head.html +1 -1
- package/.storybook/preview.js +59 -5
- package/.storybook/static/logo.svg +19 -0
- package/.storybook/theme.js +7 -0
- package/CHANGELOG.md +43 -0
- package/README.md +1 -1
- package/dist/Button.js +39 -30
- package/dist/ButtonGroup.js +5 -7
- package/dist/Checkbox.js +107 -88
- package/dist/CheckboxGroup.js +43 -38
- package/dist/{Chip-389013ff.js → Chip-dac7337d.js} +7 -2
- package/dist/ChipGroup.js +4 -6
- package/dist/ChipLink.js +6 -8
- package/dist/ChipRemovable.js +4 -7
- package/dist/ChipSelectable.js +10 -10
- package/dist/Dropdown.js +57 -27
- package/dist/Input.js +59 -43
- package/dist/Menu.js +2 -5
- package/dist/MenuItem.js +34 -17
- package/dist/Pagination.js +57 -55
- package/dist/Radio.js +13 -10
- package/dist/RadioGroup.js +43 -40
- package/dist/Select.js +57 -44
- package/dist/Table.js +147 -125
- package/dist/{defineElement-ba770aed.js → _rollupPluginBabelHelpers-20f659f4.js} +1 -15
- package/dist/defineElement-47d4f665.js +15 -0
- package/dist/index.js +29 -19
- package/dist/leu-button-group.js +7 -3
- package/dist/leu-button.js +6 -3
- package/dist/leu-checkbox-group.js +6 -3
- package/dist/leu-checkbox.js +6 -3
- package/dist/leu-chip-group.js +6 -3
- package/dist/leu-chip-link.js +7 -4
- package/dist/leu-chip-removable.js +7 -4
- package/dist/leu-chip-selectable.js +7 -4
- package/dist/leu-dropdown.js +13 -3
- package/dist/leu-input.js +7 -3
- package/dist/leu-menu-item.js +8 -3
- package/dist/leu-menu.js +6 -3
- package/dist/leu-pagination.js +8 -3
- package/dist/leu-popup-4bf6f1f4.js +216 -0
- package/dist/leu-radio-group.js +6 -3
- package/dist/leu-radio.js +6 -3
- package/dist/leu-select.js +14 -3
- package/dist/leu-table.js +9 -3
- package/package.json +29 -12
- package/scripts/generate-component/templates/[Name].js +0 -5
- package/scripts/generate-component/templates/[name].css +1 -1
- package/scripts/generate-component/templates/[namespace]-[name].js +5 -2
- package/src/components/accordion/Accordion.js +3 -9
- package/src/components/accordion/leu-accordion.js +5 -2
- package/src/components/accordion/stories/accordion.stories.js +7 -4
- package/src/components/accordion/test/accordion.test.js +92 -2
- package/src/components/breadcrumb/Breadcrumb.js +310 -0
- package/src/components/breadcrumb/breadcrumb.css +114 -0
- package/src/components/breadcrumb/leu-breadcrumb.js +6 -0
- package/src/components/breadcrumb/stories/breadcrumb.stories.js +73 -0
- package/src/components/breadcrumb/test/breadcrumb.test.js +141 -0
- package/src/components/button/Button.js +22 -27
- package/src/components/button/button.css +3 -3
- package/src/components/button/leu-button.js +5 -2
- package/src/components/button/stories/button.stories.js +58 -37
- package/src/components/button/test/button.test.js +112 -2
- package/src/components/button-group/ButtonGroup.js +1 -7
- package/src/components/button-group/leu-button-group.js +5 -2
- package/src/components/button-group/stories/button-group.stories.js +6 -0
- package/src/components/button-group/test/button-group.test.js +79 -3
- package/src/components/checkbox/Checkbox.js +9 -89
- package/src/components/checkbox/CheckboxGroup.js +9 -39
- package/src/components/checkbox/checkbox-group.css +29 -0
- package/src/components/checkbox/checkbox.css +76 -0
- package/src/components/checkbox/leu-checkbox-group.js +5 -2
- package/src/components/checkbox/leu-checkbox.js +5 -2
- package/src/components/checkbox/stories/checkbox-group.stories.js +44 -21
- package/src/components/checkbox/stories/checkbox.stories.js +7 -1
- package/src/components/checkbox/test/checkbox-group.test.js +124 -0
- package/src/components/checkbox/test/checkbox.test.js +72 -59
- package/src/components/chip/Chip.js +2 -1
- package/src/components/chip/ChipGroup.js +1 -6
- package/src/components/chip/ChipLink.js +2 -8
- package/src/components/chip/ChipRemovable.js +1 -6
- package/src/components/chip/ChipSelectable.js +4 -9
- package/src/components/chip/exports.js +4 -10
- package/src/components/chip/leu-chip-group.js +5 -2
- package/src/components/chip/leu-chip-link.js +5 -2
- package/src/components/chip/leu-chip-removable.js +5 -2
- package/src/components/chip/leu-chip-selectable.js +5 -2
- package/src/components/chip/stories/chip-group.stories.js +18 -6
- package/src/components/chip/stories/chip-link.stories.js +16 -4
- package/src/components/chip/stories/chip-removable.stories.js +15 -4
- package/src/components/chip/stories/chip-selectable.stories.js +13 -3
- package/src/components/chip/test/chip-group.test.js +124 -0
- package/src/components/chip/test/chip-link.test.js +58 -0
- package/src/components/chip/test/chip-removable.test.js +79 -0
- package/src/components/chip/test/chip-selectable.test.js +95 -0
- package/src/components/chip/test/chip.test.js +1 -1
- package/src/components/dropdown/Dropdown.js +53 -25
- package/src/components/dropdown/dropdown.css +1 -2
- package/src/components/dropdown/leu-dropdown.js +5 -2
- package/src/components/dropdown/stories/dropdown.stories.js +11 -5
- package/src/components/dropdown/test/dropdown.test.js +6 -6
- package/src/components/icon/icon.js +1 -1
- package/src/components/icon/test/icon.test.js +66 -0
- package/src/components/input/Input.js +33 -39
- package/src/components/input/input.css +9 -6
- package/src/components/input/leu-input.js +5 -2
- package/src/components/input/stories/input.stories.js +8 -2
- package/src/components/input/test/input.test.js +431 -4
- package/src/components/menu/Menu.js +0 -5
- package/src/components/menu/MenuItem.js +22 -15
- package/src/components/menu/leu-menu-item.js +5 -2
- package/src/components/menu/leu-menu.js +5 -2
- package/src/components/menu/menu-item.css +5 -2
- package/src/components/menu/stories/menu-item.stories.js +13 -4
- package/src/components/menu/stories/menu.stories.js +11 -5
- package/src/components/menu/test/menu-item.test.js +180 -0
- package/src/components/menu/test/menu.test.js +10 -2
- package/src/components/pagination/Pagination.js +53 -65
- package/src/components/pagination/leu-pagination.js +5 -2
- package/src/components/pagination/stories/pagination.stories.js +17 -9
- package/src/components/pagination/test/pagination.test.js +191 -5
- package/src/components/popup/Popup.js +200 -0
- package/src/components/popup/leu-popup.js +6 -0
- package/src/components/popup/popup.css +27 -0
- package/src/components/popup/stories/popup.stories.js +58 -0
- package/src/components/popup/test/popup.test.js +29 -0
- package/src/components/radio/Radio.js +5 -10
- package/src/components/radio/RadioGroup.js +7 -39
- package/src/components/radio/leu-radio-group.js +5 -2
- package/src/components/radio/leu-radio.js +5 -2
- package/src/components/radio/radio-group.css +29 -0
- package/src/components/radio/stories/radio-group.stories.js +38 -19
- package/src/components/radio/stories/radio.stories.js +7 -1
- package/src/components/radio/test/radio-group.test.js +86 -0
- package/src/components/radio/test/radio.test.js +108 -17
- package/src/components/select/Select.js +35 -32
- package/src/components/select/leu-select.js +5 -2
- package/src/components/select/select.css +13 -13
- package/src/components/select/stories/select.stories.js +15 -168
- package/src/components/select/test/fixtures.js +162 -0
- package/src/components/select/test/select.test.js +236 -12
- package/src/components/table/Table.js +48 -123
- package/src/components/table/leu-table.js +5 -2
- package/src/components/table/stories/table.stories.js +20 -10
- package/src/components/table/table.css +99 -0
- package/src/components/table/test/table.test.js +1 -1
- package/src/lib/utils.js +17 -0
- package/{web-dev-server-storybook.config.mjs → web-dev-server.config.mjs} +1 -2
- package/web-test-runner.config.mjs +15 -2
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { LitElement, nothing } from "lit"
|
|
2
|
+
import { html, unsafeStatic } from "lit/static-html.js"
|
|
3
|
+
import { ifDefined } from "lit/directives/if-defined.js"
|
|
4
|
+
|
|
3
5
|
import styles from "./menu-item.css"
|
|
4
6
|
|
|
5
7
|
import { Icon, ICON_NAMES } from "../icon/icon.js"
|
|
@@ -25,16 +27,18 @@ export class LeuMenuItem extends LitElement {
|
|
|
25
27
|
* If no icon with this value is found, it will be displayed as text.
|
|
26
28
|
* If the value is "EMPTY", an empty placeholder with the size of an icon will be displayed.
|
|
27
29
|
*/
|
|
28
|
-
before: { type: String },
|
|
30
|
+
before: { type: String, reflect: true },
|
|
29
31
|
/**
|
|
30
32
|
* Can be either an icon name or a text
|
|
31
33
|
* If no icon with this value is found, it will be displayed as text
|
|
32
34
|
* If the value is "EMPTY", an empty placeholder with the size of an icon will be displayed.
|
|
33
35
|
*/
|
|
34
|
-
after: { type: String },
|
|
36
|
+
after: { type: String, reflect: true },
|
|
35
37
|
active: { type: Boolean, reflect: true },
|
|
36
38
|
highlighted: { type: Boolean, reflect: true },
|
|
37
39
|
disabled: { type: Boolean, reflect: true },
|
|
40
|
+
label: { type: String, reflect: true },
|
|
41
|
+
href: { type: String, reflect: true },
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
constructor() {
|
|
@@ -42,8 +46,6 @@ export class LeuMenuItem extends LitElement {
|
|
|
42
46
|
|
|
43
47
|
this.active = false
|
|
44
48
|
this.disabled = false
|
|
45
|
-
this.before = ""
|
|
46
|
-
this.after = ""
|
|
47
49
|
|
|
48
50
|
/**
|
|
49
51
|
* A programmatic way to highlight the menu item like it is hovered.
|
|
@@ -65,7 +67,7 @@ export class LeuMenuItem extends LitElement {
|
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
renderBefore() {
|
|
68
|
-
if (this.before
|
|
70
|
+
if (this.before) {
|
|
69
71
|
const content = LeuMenuItem.getIconOrText(this.before)
|
|
70
72
|
return html`<span class="before">${content}</span>`
|
|
71
73
|
}
|
|
@@ -74,7 +76,7 @@ export class LeuMenuItem extends LitElement {
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
renderAfter() {
|
|
77
|
-
if (this.after
|
|
79
|
+
if (this.after) {
|
|
78
80
|
const content = LeuMenuItem.getIconOrText(this.after)
|
|
79
81
|
return html`<span class="after">${content}</span>`
|
|
80
82
|
}
|
|
@@ -82,14 +84,19 @@ export class LeuMenuItem extends LitElement {
|
|
|
82
84
|
return nothing
|
|
83
85
|
}
|
|
84
86
|
|
|
87
|
+
getTagName() {
|
|
88
|
+
return this.href ? "a" : "button"
|
|
89
|
+
}
|
|
90
|
+
|
|
85
91
|
render() {
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
/* The eslint rules don't recognize html import from lit/static-html.js */
|
|
93
|
+
/* eslint-disable lit/binding-positions, lit/no-invalid-html */
|
|
94
|
+
return html`<${unsafeStatic(
|
|
95
|
+
this.getTagName()
|
|
96
|
+
)} class="button" href=${ifDefined(this.href)} ?disabled=${this.disabled}>
|
|
97
|
+
${this.renderBefore()}<span class="label">${this.label}</span
|
|
88
98
|
>${this.renderAfter()}
|
|
89
|
-
|
|
99
|
+
</${unsafeStatic(this.getTagName())}>`
|
|
100
|
+
/* eslint-enable lit/binding-positions, lit/no-invalid-html */
|
|
90
101
|
}
|
|
91
102
|
}
|
|
92
|
-
|
|
93
|
-
export function defineMenuItemElements() {
|
|
94
|
-
defineElement("menu-item", LeuMenuItem)
|
|
95
|
-
}
|
|
@@ -7,15 +7,17 @@
|
|
|
7
7
|
--background: var(--leu-color-black-0);
|
|
8
8
|
--background-hover: var(--leu-color-black-10);
|
|
9
9
|
--background-active: var(--leu-color-func-cyan);
|
|
10
|
-
--background-disabled: var(--leu-color-black-0);
|
|
10
|
+
--background-disabled: var(--leu-color-black-black-0);
|
|
11
11
|
--color: var(--leu-color-black-transp-60);
|
|
12
|
+
--color-disabled: var(--leu-color-black-transp-20);
|
|
12
13
|
--font-regular: var(--leu-font-regular);
|
|
13
14
|
--font-black: var(--leu-font-black);
|
|
14
15
|
|
|
15
|
-
font-family: var(--
|
|
16
|
+
font-family: var(--leu-font-regular);
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
.button {
|
|
20
|
+
text-decoration: none;
|
|
19
21
|
appearance: none;
|
|
20
22
|
border: none;
|
|
21
23
|
cursor: pointer;
|
|
@@ -51,6 +53,7 @@
|
|
|
51
53
|
|
|
52
54
|
:host([disabled]) .button {
|
|
53
55
|
--background: var(--background-disabled);
|
|
56
|
+
--color: var(--color-disabled);
|
|
54
57
|
cursor: default;
|
|
55
58
|
}
|
|
56
59
|
|
|
@@ -9,16 +9,24 @@ export default {
|
|
|
9
9
|
args: {
|
|
10
10
|
label: "Menu Item",
|
|
11
11
|
},
|
|
12
|
+
parameters: {
|
|
13
|
+
design: {
|
|
14
|
+
type: "figma",
|
|
15
|
+
url: "https://www.figma.com/file/d6Pv21UVUbnBs3AdcZijHmbN/KTZH-Design-System?type=design&node-id=17340-82208&mode=design&t=lzVrtq8lxYVJU5TB-11",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
function Template(args) {
|
|
15
21
|
return html`
|
|
16
22
|
<leu-menu-item
|
|
23
|
+
label=${args.label}
|
|
17
24
|
before=${ifDefined(args.before)}
|
|
18
25
|
after=${ifDefined(args.after)}
|
|
26
|
+
href=${ifDefined(args.href)}
|
|
19
27
|
?active=${args.active}
|
|
20
|
-
|
|
21
|
-
>
|
|
28
|
+
?disabled=${args.disabled}
|
|
29
|
+
></leu-menu-item>
|
|
22
30
|
`
|
|
23
31
|
}
|
|
24
32
|
|
|
@@ -34,9 +42,10 @@ IconBefore.args = {
|
|
|
34
42
|
before: "check",
|
|
35
43
|
}
|
|
36
44
|
|
|
37
|
-
export const
|
|
38
|
-
|
|
45
|
+
export const IconAfterLink = Template.bind({})
|
|
46
|
+
IconAfterLink.args = {
|
|
39
47
|
after: "arrowRight",
|
|
48
|
+
href: "https://www.zh.ch",
|
|
40
49
|
}
|
|
41
50
|
|
|
42
51
|
export const IconAndTextLabel = Template.bind({})
|
|
@@ -5,16 +5,22 @@ import "../leu-menu-item.js"
|
|
|
5
5
|
export default {
|
|
6
6
|
title: "Menu",
|
|
7
7
|
component: "leu-menu",
|
|
8
|
+
parameters: {
|
|
9
|
+
design: {
|
|
10
|
+
type: "figma",
|
|
11
|
+
url: "https://www.figma.com/file/d6Pv21UVUbnBs3AdcZijHmbN/KTZH-Design-System?type=design&node-id=17340-82208&mode=design&t=lzVrtq8lxYVJU5TB-11",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
8
14
|
}
|
|
9
15
|
|
|
10
16
|
function Template() {
|
|
11
17
|
return html` <leu-menu>
|
|
12
|
-
<leu-menu-item
|
|
13
|
-
<leu-menu-item before="check" active
|
|
14
|
-
<leu-menu-item
|
|
18
|
+
<leu-menu-item label="Menu Item 1" before="EMPTY"></leu-menu-item>
|
|
19
|
+
<leu-menu-item label="Menu Item 2" before="check" active></leu-menu-item>
|
|
20
|
+
<leu-menu-item label="Menu Item 3" before="EMPTY"></leu-menu-item>
|
|
15
21
|
<hr />
|
|
16
|
-
<leu-menu-item before="pin" after="CH"
|
|
17
|
-
<leu-menu-item
|
|
22
|
+
<leu-menu-item label="Menu Item 3" before="pin" after="CH"></leu-menu-item>
|
|
23
|
+
<leu-menu-item label="Menu Item 4"></leu-menu-item>
|
|
18
24
|
</leu-menu>`
|
|
19
25
|
}
|
|
20
26
|
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import { fixture, expect, oneEvent } from "@open-wc/testing"
|
|
3
|
+
import { ifDefined } from "lit/directives/if-defined.js"
|
|
4
|
+
import { spy } from "sinon"
|
|
5
|
+
|
|
6
|
+
import "../leu-menu-item.js"
|
|
7
|
+
|
|
8
|
+
async function defaultFixture(args = {}) {
|
|
9
|
+
return fixture(html`
|
|
10
|
+
<leu-menu-item
|
|
11
|
+
label=${args.label}
|
|
12
|
+
before=${ifDefined(args.before)}
|
|
13
|
+
after=${ifDefined(args.after)}
|
|
14
|
+
href=${ifDefined(args.href)}
|
|
15
|
+
?active=${args.active}
|
|
16
|
+
?disabled=${args.disabled}
|
|
17
|
+
></leu-menu-item>
|
|
18
|
+
`)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("LeuMenuItem", () => {
|
|
22
|
+
it("is a defined element", async () => {
|
|
23
|
+
const el = customElements.get("leu-menu-item")
|
|
24
|
+
|
|
25
|
+
await expect(el).not.to.be.undefined
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it("passes the a11y audit", async () => {
|
|
29
|
+
const el = await defaultFixture({ label: "Download" })
|
|
30
|
+
|
|
31
|
+
await expect(el).shadowDom.to.be.accessible()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it("passes the a11y audit with a link", async () => {
|
|
35
|
+
const el = await defaultFixture({
|
|
36
|
+
label: "Download",
|
|
37
|
+
href: "https://zh.ch",
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
await expect(el).shadowDom.to.be.accessible()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it("renders a label", async () => {
|
|
44
|
+
const el = await defaultFixture({ label: "Download" })
|
|
45
|
+
|
|
46
|
+
const button = el.shadowRoot.querySelector("button")
|
|
47
|
+
|
|
48
|
+
expect(button).to.have.trimmed.text("Download")
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it("renders a button", async () => {
|
|
52
|
+
const el = await defaultFixture({ label: "Download" })
|
|
53
|
+
|
|
54
|
+
const button = el.shadowRoot.querySelector("button")
|
|
55
|
+
|
|
56
|
+
expect(button).to.exist
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it("renders a link", async () => {
|
|
60
|
+
const el = await defaultFixture({
|
|
61
|
+
label: "Kanton Zürich",
|
|
62
|
+
href: "https://zh.ch",
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const link = el.shadowRoot.querySelector("a")
|
|
66
|
+
|
|
67
|
+
expect(link).to.exist
|
|
68
|
+
expect(link).to.have.attribute("href", "https://zh.ch")
|
|
69
|
+
expect(link).to.have.trimmed.text("Kanton Zürich")
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it("renders a before icon", async () => {
|
|
73
|
+
const el = await defaultFixture({ label: "Download", before: "download" })
|
|
74
|
+
|
|
75
|
+
const before = el.shadowRoot.querySelector(".before")
|
|
76
|
+
expect(before).to.exist
|
|
77
|
+
|
|
78
|
+
expect(el).shadowDom.to.equal(
|
|
79
|
+
"<button class='button'><span class='before'></span><span class='label'>Download</span></button>"
|
|
80
|
+
)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it("renders a before label", async () => {
|
|
84
|
+
const el = await defaultFixture({ label: "Download", before: "DE" })
|
|
85
|
+
|
|
86
|
+
const before = el.shadowRoot.querySelector(".before")
|
|
87
|
+
expect(before).to.exist
|
|
88
|
+
expect(before).to.have.trimmed.text("DE")
|
|
89
|
+
|
|
90
|
+
expect(el).shadowDom.to.equal(
|
|
91
|
+
"<button class='button'><span class='before'>DE</span><span class='label'>Download</span></button>"
|
|
92
|
+
)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it("renders a before placeholder", async () => {
|
|
96
|
+
const el = await defaultFixture({ label: "Download", before: "EMPTY" })
|
|
97
|
+
|
|
98
|
+
const before = el.shadowRoot.querySelector(".before")
|
|
99
|
+
expect(before).to.exist
|
|
100
|
+
expect(before).to.not.have.trimmed.text()
|
|
101
|
+
|
|
102
|
+
const iconPlaceholder = before.querySelector(".icon-placeholder")
|
|
103
|
+
expect(iconPlaceholder).to.exist
|
|
104
|
+
|
|
105
|
+
expect(el).shadowDom.to.equal(
|
|
106
|
+
"<button class='button'><span class='before'><div class='icon-placeholder'></div></span><span class='label'>Download</span></button>"
|
|
107
|
+
)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
it("renders a after icon", async () => {
|
|
111
|
+
const el = await defaultFixture({ label: "Download", after: "download" })
|
|
112
|
+
|
|
113
|
+
const after = el.shadowRoot.querySelector(".after")
|
|
114
|
+
expect(after).to.exist
|
|
115
|
+
|
|
116
|
+
expect(el).shadowDom.to.equal(
|
|
117
|
+
"<button class='button'><span class='label'>Download</span><span class='after'></span></button>"
|
|
118
|
+
)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it("renders a after label", async () => {
|
|
122
|
+
const el = await defaultFixture({ label: "Download", after: "DE" })
|
|
123
|
+
|
|
124
|
+
const after = el.shadowRoot.querySelector(".after")
|
|
125
|
+
expect(after).to.exist
|
|
126
|
+
expect(after).to.have.trimmed.text("DE")
|
|
127
|
+
|
|
128
|
+
expect(el).shadowDom.to.equal(
|
|
129
|
+
"<button class='button'><span class='label'>Download</span><span class='after'>DE</span></button>"
|
|
130
|
+
)
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
it("renders a after placeholder", async () => {
|
|
134
|
+
const el = await defaultFixture({ label: "Download", after: "EMPTY" })
|
|
135
|
+
|
|
136
|
+
const after = el.shadowRoot.querySelector(".after")
|
|
137
|
+
expect(after).to.exist
|
|
138
|
+
expect(after).to.not.have.trimmed.text()
|
|
139
|
+
|
|
140
|
+
const iconPlaceholder = after.querySelector(".icon-placeholder")
|
|
141
|
+
expect(iconPlaceholder).to.exist
|
|
142
|
+
|
|
143
|
+
expect(el).shadowDom.to.equal(
|
|
144
|
+
"<button class='button'><span class='label'>Download</span><span class='after'><div class='icon-placeholder'></div></span></button>"
|
|
145
|
+
)
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
it("passes the disabled attribute to the button", async () => {
|
|
149
|
+
const el = await defaultFixture({ label: "Download", disabled: true })
|
|
150
|
+
|
|
151
|
+
const button = el.shadowRoot.querySelector("button")
|
|
152
|
+
expect(button).to.have.attribute("disabled")
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it("lets the click event bubble up", async () => {
|
|
156
|
+
const el = await defaultFixture({ label: "Download" })
|
|
157
|
+
|
|
158
|
+
const button = el.shadowRoot.querySelector("button")
|
|
159
|
+
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
button.click()
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
const event = await oneEvent(el, "click")
|
|
165
|
+
|
|
166
|
+
expect(event).to.exist
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it("does not let the click event bubble up when disabled", async () => {
|
|
170
|
+
const el = await defaultFixture({ label: "Download", disabled: true })
|
|
171
|
+
|
|
172
|
+
const button = el.shadowRoot.querySelector("button")
|
|
173
|
+
const clickSpy = spy()
|
|
174
|
+
button.addEventListener("click", clickSpy)
|
|
175
|
+
|
|
176
|
+
el.click()
|
|
177
|
+
|
|
178
|
+
expect(clickSpy).to.have.not.been.called
|
|
179
|
+
})
|
|
180
|
+
})
|
|
@@ -2,14 +2,22 @@ import { html } from "lit"
|
|
|
2
2
|
import { fixture, expect } from "@open-wc/testing"
|
|
3
3
|
|
|
4
4
|
import "../leu-menu.js"
|
|
5
|
+
import "../leu-menu-item.js"
|
|
5
6
|
|
|
6
7
|
async function defaultFixture() {
|
|
7
|
-
return fixture(html` <leu-menu
|
|
8
|
+
return fixture(html` <leu-menu>
|
|
9
|
+
<leu-menu-item label="Menu Item 1" before="EMPTY"></leu-menu-item>
|
|
10
|
+
<leu-menu-item label="Menu Item 2" before="check" active></leu-menu-item>
|
|
11
|
+
<leu-menu-item label="Menu Item 3" before="EMPTY"></leu-menu-item>
|
|
12
|
+
<hr />
|
|
13
|
+
<leu-menu-item label="Menu Item 3" before="pin" after="CH"></leu-menu-item>
|
|
14
|
+
<leu-menu-item label="Menu Item 4"></leu-menu-item>
|
|
15
|
+
</leu-menu>`)
|
|
8
16
|
}
|
|
9
17
|
|
|
10
18
|
describe("LeuMenu", () => {
|
|
11
19
|
it("is a defined element", async () => {
|
|
12
|
-
const el =
|
|
20
|
+
const el = customElements.get("leu-menu")
|
|
13
21
|
|
|
14
22
|
await expect(el).not.to.be.undefined
|
|
15
23
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { html, LitElement } from "lit"
|
|
2
|
-
import {
|
|
3
|
-
import { defineButtonElements } from "../button/Button.js"
|
|
2
|
+
import { live } from "lit/directives/live.js"
|
|
4
3
|
|
|
4
|
+
import "../button/leu-button.js"
|
|
5
5
|
import styles from "./pagination.css"
|
|
6
6
|
|
|
7
7
|
const MIN_PAGE = 1
|
|
@@ -12,16 +12,22 @@ const MIN_PAGE = 1
|
|
|
12
12
|
export class LeuPagination extends LitElement {
|
|
13
13
|
static styles = styles
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
static shadowRootOptions = {
|
|
19
|
+
...LitElement.shadowRootOptions,
|
|
20
|
+
delegatesFocus: true,
|
|
21
|
+
}
|
|
22
|
+
|
|
15
23
|
static events = {
|
|
16
24
|
range: {},
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
static properties = {
|
|
20
28
|
page: { type: Number, reflect: true },
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
_minPage: { type: Number, state: true },
|
|
29
|
+
itemsPerPage: { type: Number, reflect: true },
|
|
30
|
+
numOfItems: { type: Number, reflect: true },
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
constructor() {
|
|
@@ -29,45 +35,55 @@ export class LeuPagination extends LitElement {
|
|
|
29
35
|
/** @type {number} */
|
|
30
36
|
this.page = 1
|
|
31
37
|
/** @type {number} */
|
|
32
|
-
this.
|
|
38
|
+
this.numOfItems = 1
|
|
33
39
|
/** @type {number} */
|
|
34
|
-
this.
|
|
40
|
+
this.itemsPerPage = 1
|
|
35
41
|
}
|
|
36
42
|
|
|
37
43
|
get maxPage() {
|
|
38
|
-
return Math.ceil(this.
|
|
44
|
+
return Math.ceil(this.numOfItems / this.itemsPerPage)
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
get firstPage() {
|
|
42
|
-
return this.
|
|
48
|
+
return this.boundPage === MIN_PAGE
|
|
43
49
|
}
|
|
44
50
|
|
|
45
51
|
get lastPage() {
|
|
46
|
-
return this.
|
|
52
|
+
return this.boundPage === this.maxPage
|
|
47
53
|
}
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
|
|
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)
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
numberUpdate(number) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
const prevPage = this.page
|
|
68
|
+
this.page = number
|
|
69
|
+
|
|
70
|
+
if (this.page !== prevPage) {
|
|
71
|
+
const startIndex = (this.boundPage - 1) * this.itemsPerPage
|
|
72
|
+
const endIndex = Math.min(startIndex + this.itemsPerPage, this.numOfItems)
|
|
73
|
+
this.dispatchEvent(
|
|
74
|
+
new CustomEvent("leu:pagechange", {
|
|
75
|
+
detail: {
|
|
76
|
+
startIndex,
|
|
77
|
+
endIndex,
|
|
78
|
+
page: this.boundPage,
|
|
79
|
+
},
|
|
80
|
+
bubbles: false,
|
|
81
|
+
})
|
|
82
|
+
)
|
|
83
|
+
}
|
|
67
84
|
}
|
|
68
85
|
|
|
69
86
|
change(event) {
|
|
70
|
-
// target.value = this.page // eslint-disable-line
|
|
71
87
|
this.numberUpdate(parseInt(event.target.value, 10) || 0)
|
|
72
88
|
}
|
|
73
89
|
|
|
@@ -79,46 +95,23 @@ export class LeuPagination extends LitElement {
|
|
|
79
95
|
}
|
|
80
96
|
|
|
81
97
|
keydown(event) {
|
|
82
|
-
|
|
83
|
-
"ArrowUp",
|
|
84
|
-
"ArrowDown",
|
|
85
|
-
"ArrowLeft",
|
|
86
|
-
"ArrowRight",
|
|
87
|
-
"Backspace",
|
|
88
|
-
"Enter",
|
|
89
|
-
"Tab",
|
|
90
|
-
]
|
|
91
|
-
const numberKeys = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
|
|
92
|
-
if (!numberKeys.includes(event.key) && !specialKeys.includes(event.key)) {
|
|
98
|
+
if (event.key === "ArrowUp") {
|
|
93
99
|
event.preventDefault()
|
|
94
|
-
|
|
95
|
-
if (event.key === "ArrowUp") {
|
|
96
|
-
event.preventDefault()
|
|
97
|
-
this.numberUpdate(this.page + 1)
|
|
98
|
-
}
|
|
99
|
-
if (event.key === "ArrowDown") {
|
|
100
|
-
event.preventDefault()
|
|
101
|
-
this.numberUpdate(this.page - 1)
|
|
102
|
-
}
|
|
100
|
+
this.numberUpdate(this.boundPage + 1)
|
|
103
101
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
this.numberUpdate(this.page)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
requestUpdate(name, oldValue, newValue) {
|
|
111
|
-
if (name === "itemsOnAPage") {
|
|
112
|
-
this.numberUpdate(this.page)
|
|
102
|
+
if (event.key === "ArrowDown") {
|
|
103
|
+
event.preventDefault()
|
|
104
|
+
this.numberUpdate(this.boundPage - 1)
|
|
113
105
|
}
|
|
114
|
-
return super.requestUpdate(name, oldValue, newValue)
|
|
115
106
|
}
|
|
116
107
|
|
|
117
108
|
render() {
|
|
118
109
|
return html`
|
|
119
110
|
<input
|
|
120
111
|
class="input"
|
|
121
|
-
|
|
112
|
+
min=${MIN_PAGE}
|
|
113
|
+
max=${this.maxPage}
|
|
114
|
+
.value=${live(this.boundPage.toString())}
|
|
122
115
|
@input=${this.input}
|
|
123
116
|
@change=${this.change}
|
|
124
117
|
@keydown=${this.keydown}
|
|
@@ -129,7 +122,7 @@ export class LeuPagination extends LitElement {
|
|
|
129
122
|
icon="angleLeft"
|
|
130
123
|
variant="secondary"
|
|
131
124
|
@click=${(_) => {
|
|
132
|
-
this.numberUpdate(this.
|
|
125
|
+
this.numberUpdate(this.boundPage - 1)
|
|
133
126
|
}}
|
|
134
127
|
?disabled=${this.firstPage}
|
|
135
128
|
></leu-button>
|
|
@@ -137,7 +130,7 @@ export class LeuPagination extends LitElement {
|
|
|
137
130
|
icon="angleRight"
|
|
138
131
|
variant="secondary"
|
|
139
132
|
@click=${(_) => {
|
|
140
|
-
this.numberUpdate(this.
|
|
133
|
+
this.numberUpdate(this.boundPage + 1)
|
|
141
134
|
}}
|
|
142
135
|
?disabled=${this.lastPage}
|
|
143
136
|
style="margin-left:4px;"
|
|
@@ -145,8 +138,3 @@ export class LeuPagination extends LitElement {
|
|
|
145
138
|
`
|
|
146
139
|
}
|
|
147
140
|
}
|
|
148
|
-
|
|
149
|
-
export function definePaginationElements() {
|
|
150
|
-
defineButtonElements()
|
|
151
|
-
defineElement("pagination", LeuPagination)
|
|
152
|
-
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineElement } from "../../lib/defineElement.js"
|
|
2
|
+
import { LeuPagination } from "./Pagination.js"
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
export { LeuPagination }
|
|
5
|
+
|
|
6
|
+
defineElement("pagination", LeuPagination)
|
|
@@ -56,18 +56,26 @@ const items = [
|
|
|
56
56
|
export default {
|
|
57
57
|
title: "Pagination",
|
|
58
58
|
component: "leu-pagination",
|
|
59
|
+
parameters: {
|
|
60
|
+
design: {
|
|
61
|
+
type: "figma",
|
|
62
|
+
url: "https://www.figma.com/file/d6Pv21UVUbnBs3AdcZijHmbN/KTZH-Design-System?type=design&node-id=17341-82468&mode=design&t=lzVrtq8lxYVJU5TB-11",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
59
65
|
}
|
|
60
66
|
|
|
61
|
-
function Template({
|
|
67
|
+
function Template({ startIndex, endIndex }, { id }) {
|
|
62
68
|
return html`
|
|
63
|
-
${items
|
|
69
|
+
${items
|
|
70
|
+
.slice(startIndex, endIndex)
|
|
71
|
+
.map((item) => html`<div>${item.label}</div>`)}
|
|
64
72
|
<leu-pagination
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
@
|
|
73
|
+
numOfItems=${items.length}
|
|
74
|
+
itemsPerPage="5"
|
|
75
|
+
@leu:pagechange=${(e) => {
|
|
68
76
|
updateStorybookArgss(id, {
|
|
69
|
-
|
|
70
|
-
|
|
77
|
+
startIndex: e.detail.startIndex,
|
|
78
|
+
endIndex: e.detail.endIndex,
|
|
71
79
|
})
|
|
72
80
|
}}
|
|
73
81
|
>
|
|
@@ -77,6 +85,6 @@ function Template({ min, max }, { id }) {
|
|
|
77
85
|
|
|
78
86
|
export const Regular = Template.bind({})
|
|
79
87
|
Regular.args = {
|
|
80
|
-
|
|
81
|
-
|
|
88
|
+
startIndex: 0,
|
|
89
|
+
endIndex: 5,
|
|
82
90
|
}
|