@statistikzh/leu 0.0.2
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/.editorconfig +29 -0
- package/.eslintrc.json +27 -0
- package/.github/workflows/publish.yml +19 -0
- package/.github/workflows/release-please.yml +19 -0
- package/.github/workflows/test.yml +38 -0
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +4 -0
- package/.prettierignore +1 -0
- package/.storybook/main.js +11 -0
- package/.storybook/preview-head.html +5 -0
- package/.storybook/preview.js +23 -0
- package/CHANGELOG.md +63 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/CONTRIBUTING.md +31 -0
- package/LICENSE +21 -0
- package/README.md +170 -0
- package/commitlint.config.cjs +1 -0
- package/dist/Button-83c6df93.js +403 -0
- package/dist/Checkbox.js +144 -0
- package/dist/CheckboxGroup.js +82 -0
- package/dist/Chip-60af1402.js +162 -0
- package/dist/ChipGroup.js +79 -0
- package/dist/ChipLink.js +46 -0
- package/dist/ChipRemovable.js +43 -0
- package/dist/ChipSelectable.js +92 -0
- package/dist/Input.js +686 -0
- package/dist/Radio.js +156 -0
- package/dist/RadioGroup.js +194 -0
- package/dist/Select.js +859 -0
- package/dist/Table-72d305d7.js +506 -0
- package/dist/Table.js +8 -0
- package/dist/defineElement-47d4f665.js +15 -0
- package/dist/icon-b68c7e1e.js +202 -0
- package/dist/index.js +21 -0
- package/dist/leu-checkbox-group.js +6 -0
- package/dist/leu-checkbox.js +6 -0
- package/dist/leu-chip-group.js +5 -0
- package/dist/leu-chip-link.js +6 -0
- package/dist/leu-chip-removable.js +7 -0
- package/dist/leu-chip-selectable.js +6 -0
- package/dist/leu-input.js +9 -0
- package/dist/leu-radio-group.js +6 -0
- package/dist/leu-radio.js +5 -0
- package/dist/leu-select.js +12 -0
- package/dist/leu-table.js +10 -0
- package/dist/theme.css +51 -0
- package/index.js +10 -0
- package/package.json +85 -0
- package/postcss.config.cjs +14 -0
- package/rollup.config.js +54 -0
- package/scripts/generate-component/generate.js +167 -0
- package/scripts/generate-component/templates/[Name].js +33 -0
- package/scripts/generate-component/templates/[name].css +11 -0
- package/scripts/generate-component/templates/[namespace]-[name].js +3 -0
- package/scripts/generate-component/templates/stories/[name].stories.js +13 -0
- package/scripts/generate-component/templates/test/[name].test.js +22 -0
- package/src/components/button/Button.js +150 -0
- package/src/components/button/button.css +232 -0
- package/src/components/button/leu-button.js +3 -0
- package/src/components/button/stories/button.stories.js +333 -0
- package/src/components/button/test/button.test.js +22 -0
- package/src/components/button-group/ButtonGroup.js +63 -0
- package/src/components/button-group/button-group.css +10 -0
- package/src/components/button-group/leu-button-group.js +3 -0
- package/src/components/button-group/stories/button-group.stories.js +41 -0
- package/src/components/button-group/test/button-group.test.js +22 -0
- package/src/components/checkbox/Checkbox.js +142 -0
- package/src/components/checkbox/CheckboxGroup.js +80 -0
- package/src/components/checkbox/leu-checkbox-group.js +3 -0
- package/src/components/checkbox/leu-checkbox.js +3 -0
- package/src/components/checkbox/stories/checkbox-group.stories.js +52 -0
- package/src/components/checkbox/stories/checkbox.stories.js +43 -0
- package/src/components/checkbox/test/checkbox.test.js +101 -0
- package/src/components/chip/Chip.js +24 -0
- package/src/components/chip/ChipGroup.js +71 -0
- package/src/components/chip/ChipLink.js +45 -0
- package/src/components/chip/ChipRemovable.js +42 -0
- package/src/components/chip/ChipSelectable.js +91 -0
- package/src/components/chip/chip-group.css +5 -0
- package/src/components/chip/chip.css +130 -0
- package/src/components/chip/exports.js +10 -0
- package/src/components/chip/leu-chip-group.js +3 -0
- package/src/components/chip/leu-chip-link.js +3 -0
- package/src/components/chip/leu-chip-removable.js +3 -0
- package/src/components/chip/leu-chip-selectable.js +3 -0
- package/src/components/chip/stories/chip-group.stories.js +99 -0
- package/src/components/chip/stories/chip-link.stories.js +37 -0
- package/src/components/chip/stories/chip-removable.stories.js +28 -0
- package/src/components/chip/stories/chip-selectable.stories.js +46 -0
- package/src/components/chip/test/chip.test.js +22 -0
- package/src/components/dropdown/Dropdown.js +55 -0
- package/src/components/dropdown/dropdown.css +17 -0
- package/src/components/dropdown/leu-dropdown.js +3 -0
- package/src/components/dropdown/stories/dropdown.stories.js +25 -0
- package/src/components/dropdown/test/dropdown.test.js +31 -0
- package/src/components/icon/icon.js +201 -0
- package/src/components/input/Input.js +421 -0
- package/src/components/input/input.css +231 -0
- package/src/components/input/leu-input.js +3 -0
- package/src/components/input/stories/input.stories.js +185 -0
- package/src/components/input/test/input.test.js +22 -0
- package/src/components/menu/Menu.js +18 -0
- package/src/components/menu/MenuItem.js +95 -0
- package/src/components/menu/leu-menu-item.js +3 -0
- package/src/components/menu/leu-menu.js +3 -0
- package/src/components/menu/menu-item.css +72 -0
- package/src/components/menu/menu.css +14 -0
- package/src/components/menu/stories/menu-item.stories.js +51 -0
- package/src/components/menu/stories/menu.stories.js +21 -0
- package/src/components/menu/test/menu.test.js +22 -0
- package/src/components/pagination/Pagination.js +152 -0
- package/src/components/pagination/leu-pagination.js +3 -0
- package/src/components/pagination/pagination.css +49 -0
- package/src/components/pagination/stories/pagination.stories.js +82 -0
- package/src/components/pagination/test/pagination.test.js +22 -0
- package/src/components/radio/Radio.js +62 -0
- package/src/components/radio/RadioGroup.js +193 -0
- package/src/components/radio/leu-radio-group.js +3 -0
- package/src/components/radio/leu-radio.js +3 -0
- package/src/components/radio/radio.css +76 -0
- package/src/components/radio/stories/radio-group.stories.js +49 -0
- package/src/components/radio/stories/radio.stories.js +48 -0
- package/src/components/radio/test/radio.test.js +38 -0
- package/src/components/select/Select.js +350 -0
- package/src/components/select/leu-select.js +3 -0
- package/src/components/select/select.css +215 -0
- package/src/components/select/stories/select.stories.js +302 -0
- package/src/components/select/test/select.test.js +29 -0
- package/src/components/table/Table.js +301 -0
- package/src/components/table/leu-table.js +3 -0
- package/src/components/table/stories/table.stories.js +116 -0
- package/src/components/table/test/table.test.js +36 -0
- package/src/lib/defineElement.js +13 -0
- package/src/lib/hasSlotController.js +85 -0
- package/src/styles/custom-media.css +5 -0
- package/src/styles/custom-properties.css +51 -0
- package/src/styles/theme.css +1 -0
- package/stat_zh.png +0 -0
- package/stylelint.config.mjs +21 -0
- package/web-dev-server-storybook.config.mjs +19 -0
- package/web-test-runner.config.mjs +49 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { html, css, LitElement } from "lit"
|
|
2
|
+
import { classMap } from "lit/directives/class-map.js"
|
|
3
|
+
import { defineElement } from "../../lib/defineElement.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @tagname leu-checkbox-group
|
|
7
|
+
*/
|
|
8
|
+
export class LeuCheckboxGroup extends LitElement {
|
|
9
|
+
static styles = css`
|
|
10
|
+
:host {
|
|
11
|
+
--group-font-regular: var(--leu-font-regular);
|
|
12
|
+
--group-font-black: var(--leu-font-black);
|
|
13
|
+
|
|
14
|
+
font-family: var(--group-font-regular);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.fieldset {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: flex-start;
|
|
20
|
+
flex-wrap: wrap;
|
|
21
|
+
gap: 0.5rem 1rem;
|
|
22
|
+
|
|
23
|
+
border: none;
|
|
24
|
+
padding: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.fieldset--vertical {
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
gap: 1rem;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.legend {
|
|
33
|
+
font-family: var(--group-font-black);
|
|
34
|
+
font-size: 1.125rem;
|
|
35
|
+
line-height: 1.5;
|
|
36
|
+
|
|
37
|
+
margin-bottom: 0.5rem;
|
|
38
|
+
}
|
|
39
|
+
`
|
|
40
|
+
|
|
41
|
+
static properties = {
|
|
42
|
+
orientation: { type: String },
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
constructor() {
|
|
46
|
+
super()
|
|
47
|
+
this.orientation = "HORIZONTAL"
|
|
48
|
+
this.items = []
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get value() {
|
|
52
|
+
return this.items.filter((i) => i.checked).map((i) => i.value)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
handleSlotChange() {
|
|
56
|
+
this.handleItems()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
handleItems() {
|
|
60
|
+
this.items = [...this.querySelectorAll(":scope > *:not([slot])")]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
render() {
|
|
64
|
+
const fieldsetClasses = {
|
|
65
|
+
fieldset: "true",
|
|
66
|
+
"fieldset--vertical": this.orientation === "VERTICAL",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return html`
|
|
70
|
+
<fieldset class=${classMap(fieldsetClasses)}>
|
|
71
|
+
<legend class="legend"><slot name="legend"></slot></legend>
|
|
72
|
+
<slot @slotchange=${this.handleSlotChange}></slot>
|
|
73
|
+
</fieldset>
|
|
74
|
+
`
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function defineCheckboxGroupElements() {
|
|
79
|
+
defineElement("checkbox-group", LeuCheckboxGroup)
|
|
80
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import "../leu-checkbox.js"
|
|
3
|
+
import "../leu-checkbox-group.js"
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title: "Checkbox/Group",
|
|
7
|
+
component: "leu-checkbox-group",
|
|
8
|
+
argTypes: {
|
|
9
|
+
legend: { control: "text" },
|
|
10
|
+
orientation: {
|
|
11
|
+
options: ["VERTICAL", "HORIZONTAL"],
|
|
12
|
+
control: { type: "checkbox" },
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function Template({ legend, orientation }) {
|
|
18
|
+
return html`
|
|
19
|
+
<leu-checkbox-group orientation=${orientation}>
|
|
20
|
+
<span slot="legend">${legend}</span>
|
|
21
|
+
<leu-checkbox identifier="1" value="1" name="checkbox-button" disabled
|
|
22
|
+
>Kurz</leu-checkbox
|
|
23
|
+
>
|
|
24
|
+
<leu-checkbox identifier="2" value="2" name="checkbox-button"
|
|
25
|
+
>Etwas Länger</leu-checkbox
|
|
26
|
+
>
|
|
27
|
+
<leu-checkbox identifier="3" value="3" name="checkbox-button" disabled
|
|
28
|
+
>Deaktiviert dazwischen</leu-checkbox
|
|
29
|
+
>
|
|
30
|
+
<leu-checkbox identifier="4" value="4" name="checkbox-button"
|
|
31
|
+
>Ein langes Label um sicher ein umbruch zu erzwingen</leu-checkbox
|
|
32
|
+
>
|
|
33
|
+
</leu-checkbox-group>
|
|
34
|
+
`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const Horizontal = Template.bind({})
|
|
38
|
+
export const HorizontalLegend = Template.bind({})
|
|
39
|
+
HorizontalLegend.args = {
|
|
40
|
+
legend: "Anrede",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export const Vertical = Template.bind({})
|
|
44
|
+
Vertical.args = {
|
|
45
|
+
orientation: "VERTICAL",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const VerticalLegend = Template.bind({})
|
|
49
|
+
VerticalLegend.args = {
|
|
50
|
+
orientation: "VERTICAL",
|
|
51
|
+
legend: "Anrede",
|
|
52
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import "../leu-checkbox.js"
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: "Checkbox",
|
|
6
|
+
component: "leu-checkbox",
|
|
7
|
+
argTypes: {
|
|
8
|
+
label: {
|
|
9
|
+
control: "text",
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function Template({ label = "Label", value, checked, disabled }) {
|
|
15
|
+
return html`
|
|
16
|
+
<leu-checkbox
|
|
17
|
+
.value=${value}
|
|
18
|
+
?checked=${checked}
|
|
19
|
+
?disabled=${disabled}
|
|
20
|
+
identifier="checkbox-1"
|
|
21
|
+
>
|
|
22
|
+
${label}
|
|
23
|
+
</leu-checkbox>
|
|
24
|
+
`
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const Regular = Template.bind({})
|
|
28
|
+
|
|
29
|
+
export const Checked = Template.bind({})
|
|
30
|
+
Checked.args = {
|
|
31
|
+
checked: true,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const Disabled = Template.bind({})
|
|
35
|
+
Disabled.args = {
|
|
36
|
+
disabled: true,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const CheckedDisabled = Template.bind({})
|
|
40
|
+
CheckedDisabled.args = {
|
|
41
|
+
checked: true,
|
|
42
|
+
disabled: true,
|
|
43
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import { fixture, expect } from "@open-wc/testing"
|
|
3
|
+
|
|
4
|
+
import "../leu-checkbox.js"
|
|
5
|
+
import "../leu-checkbox-group.js"
|
|
6
|
+
|
|
7
|
+
async function defaultFixture() {
|
|
8
|
+
return fixture(html`
|
|
9
|
+
<leu-checkbox-group>
|
|
10
|
+
<leu-checkbox identifier="a" value="1" disabled>1</leu-checkbox>
|
|
11
|
+
<leu-checkbox identifier="b" value="2">2</leu-checkbox>
|
|
12
|
+
<leu-checkbox identifier="c" value="3">3</leu-checkbox>
|
|
13
|
+
</leu-checkbox-group>
|
|
14
|
+
`)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function checkedFixture() {
|
|
18
|
+
return fixture(html`
|
|
19
|
+
<leu-checkbox-group>
|
|
20
|
+
<leu-checkbox identifier="a" value="1" disabled>1</leu-checkbox>
|
|
21
|
+
<leu-checkbox identifier="b" value="2" checked>2</leu-checkbox>
|
|
22
|
+
<leu-checkbox identifier="c" value="3">3</leu-checkbox>
|
|
23
|
+
</leu-checkbox-group>
|
|
24
|
+
`)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
describe("LeuCheckbox", () => {
|
|
28
|
+
it("is a defined element", async () => {
|
|
29
|
+
const el = await customElements.get("leu-checkbox")
|
|
30
|
+
|
|
31
|
+
await expect(el).not.to.be.undefined
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it("passes the a11y audit", async () => {
|
|
35
|
+
const el = await defaultFixture()
|
|
36
|
+
|
|
37
|
+
await expect(el).shadowDom.to.be.accessible()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe("LeuCheckboxGroup", () => {
|
|
41
|
+
it("is a defined element", async () => {
|
|
42
|
+
const el = await customElements.get("leu-checkbox-group")
|
|
43
|
+
|
|
44
|
+
await expect(el).not.to.be.undefined
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it("should have a default value of an empty array", async () => {
|
|
48
|
+
const el = await defaultFixture()
|
|
49
|
+
|
|
50
|
+
expect(el.value).to.deep.equal([])
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it("should update the value when a checkbox is checked", async () => {
|
|
54
|
+
const el = await defaultFixture()
|
|
55
|
+
const leuCheckbox = el.querySelector('leu-checkbox[value="2"]')
|
|
56
|
+
const checkbox = leuCheckbox.shadowRoot.querySelector("input")
|
|
57
|
+
|
|
58
|
+
checkbox.click()
|
|
59
|
+
|
|
60
|
+
expect(el.value).to.deep.equal(["2"])
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it("should update the value when a checkbox is unchecked", async () => {
|
|
64
|
+
const el = await defaultFixture()
|
|
65
|
+
const leuCheckbox = el.querySelector('leu-checkbox[value="2"]')
|
|
66
|
+
const checkbox = leuCheckbox.shadowRoot.querySelector("input")
|
|
67
|
+
|
|
68
|
+
checkbox.click()
|
|
69
|
+
checkbox.click()
|
|
70
|
+
|
|
71
|
+
expect(el.value).to.deep.equal([])
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it("should not update the value when a disabled checkbox is clicked", async () => {
|
|
75
|
+
const el = await defaultFixture()
|
|
76
|
+
const leuCheckbox = el.querySelector('leu-checkbox[value="1"]')
|
|
77
|
+
const checkbox = leuCheckbox.shadowRoot.querySelector("input")
|
|
78
|
+
|
|
79
|
+
checkbox.click()
|
|
80
|
+
|
|
81
|
+
expect(el.value).to.deep.equal([])
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it("should have the option checked by default as a value", async () => {
|
|
85
|
+
const el = await checkedFixture()
|
|
86
|
+
|
|
87
|
+
expect(el.value).to.deep.equal(["2"])
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it("should delegate focus to the first active checkbox", async () => {
|
|
91
|
+
const el = await defaultFixture()
|
|
92
|
+
const leuCheckbox = el.querySelector('leu-checkbox[value="2"]')
|
|
93
|
+
const checkbox = leuCheckbox.shadowRoot.querySelector("input")
|
|
94
|
+
|
|
95
|
+
await leuCheckbox.focus()
|
|
96
|
+
|
|
97
|
+
expect(document.activeElement).to.equal(leuCheckbox)
|
|
98
|
+
expect(leuCheckbox.shadowRoot.activeElement).to.equal(checkbox)
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { LitElement } from "lit"
|
|
2
|
+
import styles from "./chip.css"
|
|
3
|
+
|
|
4
|
+
/* Design: https://www.figma.com/file/d6Pv21UVUbnBs3AdcZijHmbN/KTZH-Design-System?type=design&node-id=21161-184433&mode=design&t=Kjo5VDiqivihn8dh-11 */
|
|
5
|
+
|
|
6
|
+
export class LeuChipBase extends LitElement {
|
|
7
|
+
static styles = styles
|
|
8
|
+
|
|
9
|
+
/** @internal */
|
|
10
|
+
static shadowRootOptions = {
|
|
11
|
+
...LitElement.shadowRootOptions,
|
|
12
|
+
delegatesFocus: true,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
static properties = {
|
|
16
|
+
inverted: { type: Boolean },
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
super()
|
|
21
|
+
|
|
22
|
+
this.inverted = false
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { LitElement, html } from "lit"
|
|
2
|
+
import { defineElement } from "../../lib/defineElement.js"
|
|
3
|
+
import styles from "./chip-group.css"
|
|
4
|
+
|
|
5
|
+
/* Figma https://www.figma.com/file/d6Pv21UVUbnBs3AdcZijHmbN/KTZH-Design-System?type=design&node-id=131766-248643&mode=design&t=Kjo5VDiqivihn8dh-11 */
|
|
6
|
+
|
|
7
|
+
export const SELECTION_MODES = {
|
|
8
|
+
single: "single",
|
|
9
|
+
multiple: "multiple",
|
|
10
|
+
none: "none",
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @slot - Place leu-chip-* elements inside this slot
|
|
15
|
+
* @tagname leu-chip-group
|
|
16
|
+
*/
|
|
17
|
+
export class LeuChipGroup extends LitElement {
|
|
18
|
+
static styles = styles
|
|
19
|
+
|
|
20
|
+
static properties = {
|
|
21
|
+
selectionMode: { type: String, attribute: "selection-mode" },
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
constructor() {
|
|
25
|
+
super()
|
|
26
|
+
|
|
27
|
+
/** @internal */
|
|
28
|
+
this.items = []
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
connectedCallback() {
|
|
32
|
+
super.connectedCallback()
|
|
33
|
+
|
|
34
|
+
this.addEventListener("input", this.handleInput)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
disconnectedCallback() {
|
|
38
|
+
super.disconnectedCallback()
|
|
39
|
+
|
|
40
|
+
this.removeEventListener("input", this.handleInput)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get value() {
|
|
44
|
+
return this.items.filter((i) => i.selected).map((i) => i.value)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** @internal */
|
|
48
|
+
handleInput = (e) => {
|
|
49
|
+
if (this.selectionMode === SELECTION_MODES.single) {
|
|
50
|
+
this.items.forEach((item) => {
|
|
51
|
+
item.selected = item === e.target // eslint-disable-line no-param-reassign
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** @internal */
|
|
57
|
+
handleSlotChange = (e) => {
|
|
58
|
+
const slot = e.target
|
|
59
|
+
const items = slot.assignedElements({ flatten: true })
|
|
60
|
+
|
|
61
|
+
this.items = items
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
render() {
|
|
65
|
+
return html`<slot @slotchange=${this.handleSlotChange}></slot>`
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function defineChipGroupElements() {
|
|
70
|
+
defineElement("chip-group", LeuChipGroup)
|
|
71
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import { defineElement } from "../../lib/defineElement.js"
|
|
3
|
+
|
|
4
|
+
import { LeuChipBase } from "./Chip.js"
|
|
5
|
+
|
|
6
|
+
export const SIZES = {
|
|
7
|
+
regular: "regular",
|
|
8
|
+
large: "large",
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @slot - The content of the chip
|
|
13
|
+
* @tagname leu-chip-link
|
|
14
|
+
*/
|
|
15
|
+
export class LeuChipLink extends LeuChipBase {
|
|
16
|
+
static properties = {
|
|
17
|
+
...LeuChipBase.properties,
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The size of the chip
|
|
21
|
+
* @type {keyof typeof SIZES}
|
|
22
|
+
*/
|
|
23
|
+
size: { type: String },
|
|
24
|
+
|
|
25
|
+
href: { type: String, reflect: true },
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
super()
|
|
30
|
+
|
|
31
|
+
this.inverted = false
|
|
32
|
+
this.size = SIZES.regular
|
|
33
|
+
this.href = ""
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
render() {
|
|
37
|
+
return html`<a href=${this.href} class="button">
|
|
38
|
+
<span class="label"><slot></slot></span>
|
|
39
|
+
</a>`
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function defineChipLinkElements() {
|
|
44
|
+
defineElement("chip-link", LeuChipLink)
|
|
45
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import { defineElement } from "../../lib/defineElement.js"
|
|
3
|
+
|
|
4
|
+
import { LeuChipBase } from "./Chip.js"
|
|
5
|
+
import { Icon } from "../icon/icon.js"
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @slot - The content of the chip
|
|
9
|
+
* @tagname leu-chip-removable
|
|
10
|
+
* @fires remove - Dispatched when the user clicks on the chip
|
|
11
|
+
*/
|
|
12
|
+
export class LeuChipRemovable extends LeuChipBase {
|
|
13
|
+
static properties = {
|
|
14
|
+
...LeuChipBase.properties,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
super()
|
|
19
|
+
|
|
20
|
+
/** @internal */
|
|
21
|
+
this._removeIcon = Icon("close", 16)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
handleClick() {
|
|
25
|
+
const customEvent = new CustomEvent("remove", {
|
|
26
|
+
bubble: true,
|
|
27
|
+
composed: true,
|
|
28
|
+
})
|
|
29
|
+
this.dispatchEvent(customEvent)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
render() {
|
|
33
|
+
return html`<button @click=${(e) => this.handleClick(e)} class="button">
|
|
34
|
+
<span class="label"><slot></slot></span>
|
|
35
|
+
<div class="icon">${this._removeIcon}</div>
|
|
36
|
+
</button>`
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function defineChipRemovableElements() {
|
|
41
|
+
defineElement("chip-removable", LeuChipRemovable)
|
|
42
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { html } from "lit"
|
|
2
|
+
import { defineElement } from "../../lib/defineElement.js"
|
|
3
|
+
|
|
4
|
+
import { LeuChipBase } from "./Chip.js"
|
|
5
|
+
|
|
6
|
+
export const SIZES = {
|
|
7
|
+
small: "small",
|
|
8
|
+
regular: "regular",
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const VARIANTS = {
|
|
12
|
+
default: "default",
|
|
13
|
+
radio: "radio",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A chip component that can be selected.
|
|
18
|
+
* @slot - The content of the chip
|
|
19
|
+
* @tagname leu-chip-selectable
|
|
20
|
+
*/
|
|
21
|
+
export class LeuChipSelectable extends LeuChipBase {
|
|
22
|
+
static properties = {
|
|
23
|
+
...LeuChipBase.properties,
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The size of the chip. Not supported for radio variant.
|
|
27
|
+
* @type {keyof typeof SIZES}
|
|
28
|
+
* @default "regular"
|
|
29
|
+
*/
|
|
30
|
+
size: { type: String },
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The variant of the chip. Has an effect not only on the visual appearance but also on the behavior.
|
|
34
|
+
* - `default`: The chip behaves like a toggle button.
|
|
35
|
+
* - `radio`: The chip behaves like a radio button.
|
|
36
|
+
*
|
|
37
|
+
* @type {keyof typeof VARIANTS}
|
|
38
|
+
* @default "default"
|
|
39
|
+
*/
|
|
40
|
+
variant: { type: String },
|
|
41
|
+
|
|
42
|
+
selected: { type: Boolean, reflect: true },
|
|
43
|
+
value: { type: String },
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
constructor() {
|
|
47
|
+
super()
|
|
48
|
+
this.size = SIZES.regular
|
|
49
|
+
this.variant = VARIANTS.toggle
|
|
50
|
+
this.selected = false
|
|
51
|
+
|
|
52
|
+
if (this.variant === VARIANTS.radio && this.size === SIZES.small) {
|
|
53
|
+
console.warn("Small size has no effect on radio variant")
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
handleClick() {
|
|
58
|
+
let nextSelectedState = this.selected
|
|
59
|
+
|
|
60
|
+
if (this.variant === VARIANTS.radio) {
|
|
61
|
+
nextSelectedState = true
|
|
62
|
+
} else {
|
|
63
|
+
nextSelectedState = !this.selected
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (nextSelectedState !== this.selected) {
|
|
67
|
+
this.selected = nextSelectedState
|
|
68
|
+
this.dispatchEvent(
|
|
69
|
+
new CustomEvent("input", {
|
|
70
|
+
detail: { selected: this.selected },
|
|
71
|
+
bubbles: true,
|
|
72
|
+
composed: true,
|
|
73
|
+
})
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
render() {
|
|
79
|
+
return html`<button
|
|
80
|
+
@click=${(e) => this.handleClick(e)}
|
|
81
|
+
class="button"
|
|
82
|
+
aria-selected=${this.selected ? "true" : "false"}
|
|
83
|
+
>
|
|
84
|
+
<span class="label"><slot></slot></span>
|
|
85
|
+
</button>`
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function defineChipSelectableElements() {
|
|
90
|
+
defineElement("chip-selectable", LeuChipSelectable)
|
|
91
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
:host,
|
|
2
|
+
:host *,
|
|
3
|
+
:host *::before,
|
|
4
|
+
:host *::after {
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
:host {
|
|
9
|
+
--chip-background-color-default: var(--leu-color-black-transp-10);
|
|
10
|
+
--chip-background-color-hover: var(--leu-color-black-transp-20);
|
|
11
|
+
--chip-background-color-selected: var(--leu-color-black-100);
|
|
12
|
+
--chip-background-color-selected-hover: var(--leu-color-black-transp-80);
|
|
13
|
+
|
|
14
|
+
--chip-color-default: var(--leu-color-black-transp-60);
|
|
15
|
+
--chip-color-hover: var(--leu-color-black-100);
|
|
16
|
+
--chip-color-selected: var(--leu-color-black-0);
|
|
17
|
+
|
|
18
|
+
--chip-radio-border-default: var(--leu-color-black-transp-40);
|
|
19
|
+
--chip-radio-border-selected: var(--leu-color-black-0);
|
|
20
|
+
--chip-radio-background-default: var(--leu-color-black-0);
|
|
21
|
+
--chip-radio-background-selected: var(--leu-color-func-cyan);
|
|
22
|
+
|
|
23
|
+
--chip-font-regular: var(--leu-font-regular);
|
|
24
|
+
--chip-font-black: var(--leu-font-black);
|
|
25
|
+
|
|
26
|
+
--chip-background-color: var(--chip-background-color-default);
|
|
27
|
+
--chip-color: var(--chip-color-default);
|
|
28
|
+
--chip-radio-border: var(--chip-radio-border-default);
|
|
29
|
+
--chip-radio-background: var(--chip-radio-background-default);
|
|
30
|
+
|
|
31
|
+
font-family: var(--chip-font-regular);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:host([inverted]) {
|
|
35
|
+
--chip-background-color: var(--leu-color-black-transp-20);
|
|
36
|
+
--chip-background-color-hover: var(--leu-color-black-transp-40);
|
|
37
|
+
|
|
38
|
+
--chip-color-default: var(--leu-color-black-0);
|
|
39
|
+
--chip-color-hover: var(--leu-color-black-0);
|
|
40
|
+
--chip-color-selected: var(--leu-color-black-0);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
:host([selected]) {
|
|
44
|
+
--chip-background-color: var(--chip-background-color-selected);
|
|
45
|
+
--chip-color: var(--chip-color-selected);
|
|
46
|
+
--chip-radio-border: var(--chip-radio-border-selected);
|
|
47
|
+
--chip-radio-background: var(--chip-radio-background-selected);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.button {
|
|
51
|
+
appearance: none;
|
|
52
|
+
border: none;
|
|
53
|
+
border-radius: 1rem;
|
|
54
|
+
background-color: var(--chip-background-color);
|
|
55
|
+
padding: 0.5rem 1rem;
|
|
56
|
+
|
|
57
|
+
color: var(--chip-color);
|
|
58
|
+
font-size: 0.875rem;
|
|
59
|
+
line-height: 1rem;
|
|
60
|
+
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
|
|
63
|
+
display: inline-flex;
|
|
64
|
+
align-items: center;
|
|
65
|
+
gap: 0.5rem;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.button:hover,
|
|
69
|
+
.button:focus-visible {
|
|
70
|
+
--chip-background-color: var(--chip-background-color-hover);
|
|
71
|
+
--chip-color: var(--chip-color-hover);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.button:focus-visible {
|
|
75
|
+
outline: 2px solid var(--leu-color-func-cyan);
|
|
76
|
+
outline-offset: 2px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
:host([href]) .button {
|
|
80
|
+
border-radius: 1.25rem;
|
|
81
|
+
padding: 0.5rem 1rem;
|
|
82
|
+
|
|
83
|
+
font-family: var(--chip-font-black);
|
|
84
|
+
font-size: 1.125rem;
|
|
85
|
+
line-height: 1.5rem;
|
|
86
|
+
text-decoration: none;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
:host([selected]) .button:hover,
|
|
90
|
+
:host([selected]) .button:focus-visible {
|
|
91
|
+
--chip-background-color: var(--chip-background-color-selected-hover);
|
|
92
|
+
--chip-color: var(--chip-color-selected);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
:host([href][size="large"]) .button {
|
|
96
|
+
border-radius: 1.5rem;
|
|
97
|
+
padding: 0.3125rem 1.5rem;
|
|
98
|
+
|
|
99
|
+
font-size: 2rem;
|
|
100
|
+
line-height: 2.375rem;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
:host([size="small"]:not([variant="radio"])) .button {
|
|
104
|
+
padding: 0.5625rem 0.75rem 0.4375rem;
|
|
105
|
+
|
|
106
|
+
font-size: 0.75rem;
|
|
107
|
+
line-height: 1;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
:host([variant="radio"]) .button::before {
|
|
111
|
+
content: "";
|
|
112
|
+
width: 1rem;
|
|
113
|
+
height: 1rem;
|
|
114
|
+
background-color: var(--chip-radio-background);
|
|
115
|
+
border: 2px solid var(--chip-radio-border);
|
|
116
|
+
border-radius: 50%;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
:host([variant="radio"][selected]) .button::before {
|
|
120
|
+
border-width: 3px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.label {
|
|
124
|
+
position: relative;
|
|
125
|
+
top: -0.0625rem;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.icon svg {
|
|
129
|
+
display: block;
|
|
130
|
+
}
|