diff --git a/src/components/menu/MenuItem.js b/src/components/menu/MenuItem.js
index 412b957f..8856bafe 100644
--- a/src/components/menu/MenuItem.js
+++ b/src/components/menu/MenuItem.js
@@ -1,4 +1,4 @@
-import { html } from "lit"
+import { html, nothing } from "lit"
import { ifDefined } from "lit/directives/if-defined.js"
import { LeuElement } from "../../lib/LeuElement.js"
@@ -15,6 +15,7 @@ import styles from "./menu-item.css"
* @tagname leu-menu-item
* @slot - The label of the menu item
* @property {boolean} active - Defines if the item is selected or checked
+ * @property {boolean} multipleSelection - If the item is part of a multiple selection. Renders a checkmark before the label when active
* @property {boolean} disabled - Disables the underlying button or link
* @property {string} value - The value of the item. It must not contain commas. See `getValue()`
* @property {string} href - The href of the underlying link
@@ -38,6 +39,11 @@ export class LeuMenuItem extends LeuElement {
static properties = {
active: { type: Boolean, reflect: true },
+ multipleSelection: {
+ type: Boolean,
+ reflect: true,
+ attr: "multiple-selection",
+ },
disabled: { type: Boolean, reflect: true },
tabbable: { type: Boolean, reflect: true },
href: { type: String, reflect: true },
@@ -50,6 +56,7 @@ export class LeuMenuItem extends LeuElement {
this.active = false
this.disabled = false
+ this.multipleSelection = false
this.value = undefined
this.href = undefined
this.tabbable = undefined
@@ -142,9 +149,21 @@ export class LeuMenuItem extends LeuElement {
`
}
+ _renderBeforeSlotDefault() {
+ if (!this.multipleSelection) {
+ return nothing
+ }
+
+ return this.active
+ ? html``
+ : html``
+ }
+
render() {
const content = html`
-
+ ${this._renderBeforeSlotDefault()}
`
diff --git a/src/components/menu/stories/menu-item.stories.js b/src/components/menu/stories/menu-item.stories.js
index cde44096..dfae2602 100644
--- a/src/components/menu/stories/menu-item.stories.js
+++ b/src/components/menu/stories/menu-item.stories.js
@@ -1,4 +1,4 @@
-import { html } from "lit"
+import { html, nothing } from "lit"
import { ifDefined } from "lit/directives/if-defined.js"
import "../leu-menu-item.js"
@@ -29,14 +29,19 @@ function Template(args) {
href=${ifDefined(args.href)}
?active=${args.active}
?disabled=${args.disabled}
+ ?multipleSelection=${args.multipleSelection}
>
- ${isIcon(args.before)
- ? html``
- : html`${args.before}`}
+ ${args.before
+ ? isIcon(args.before)
+ ? html``
+ : html`${args.before}`
+ : nothing}
${args.label}
- ${isIcon(args.after)
- ? html``
- : html`${args.after}`}
+ ${args.after
+ ? isIcon(args.after)
+ ? html``
+ : html`${args.after}`
+ : null}
`
}
@@ -50,7 +55,7 @@ Active.args = {
export const IconBefore = Template.bind({})
IconBefore.args = {
- before: "check",
+ before: "download",
}
export const IconAfterLink = Template.bind({})
@@ -69,3 +74,8 @@ export const IconPlaceholder = Template.bind({})
IconPlaceholder.args = {
before: "EMPTY",
}
+
+export const MultipleSelection = Template.bind({})
+MultipleSelection.args = {
+ multipleSelection: true,
+}
diff --git a/src/components/menu/test/menu-item.test.js b/src/components/menu/test/menu-item.test.js
index 0b3f5334..b1c3b748 100644
--- a/src/components/menu/test/menu-item.test.js
+++ b/src/components/menu/test/menu-item.test.js
@@ -15,6 +15,7 @@ async function defaultFixture(args = {}) {
?active=${args.active}
?disabled=${args.disabled}
?tabbable=${args.tabbable}
+ ?multipleSelection=${args.multipleSelection}
>
${args.label}
@@ -183,4 +184,26 @@ describe("LeuMenuItem", () => {
expect(el.getValue()).to.equal("download-01")
})
+
+ it("renders a palceholder icon when the menu item is part of multiple selection but not active", async () => {
+ const el = await defaultFixture({
+ label: "Download",
+ multipleSelection: true,
+ })
+
+ const icon = el.shadowRoot.querySelector("leu-icon")
+ expect(icon).to.exist
+ expect(icon).to.have.attribute("name", "EMPTY")
+ })
+
+ it("renders a check icon when the menu item is part of multiple selection and is active", async () => {
+ const el = await defaultFixture({
+ label: "Download",
+ multipleSelection: true,
+ })
+
+ const icon = el.shadowRoot.querySelector("leu-icon")
+ expect(icon).to.exist
+ expect(icon).to.have.attribute("name", "check")
+ })
})
diff --git a/src/components/select/Select.js b/src/components/select/Select.js
index 65d30c07..b8564237 100644
--- a/src/components/select/Select.js
+++ b/src/components/select/Select.js
@@ -146,11 +146,13 @@ export class LeuSelect extends LeuElement {
if (
changedProperties.has("value") ||
- changedProperties.has("_optionFilter")
+ changedProperties.has("_optionFilter") ||
+ changedProperties.has("multiple")
) {
this._updateMenuItems({
value: changedProperties.has("value"),
optionFilter: changedProperties.has("_optionFilter"),
+ multiple: changedProperties.has("multiple"),
})
}
}
@@ -171,6 +173,10 @@ export class LeuSelect extends LeuElement {
/* eslint-disable no-param-reassign */
menuItems.forEach((menuItem) => {
+ if (changed.multiple) {
+ menuItem.multipleSelection = this.multiple
+ }
+
if (changed.optionFilter) {
menuItem.hidden =
this._optionFilter !== "" &&
diff --git a/src/components/select/test/select.test.js b/src/components/select/test/select.test.js
index ea719be2..b4a518ff 100644
--- a/src/components/select/test/select.test.js
+++ b/src/components/select/test/select.test.js
@@ -405,6 +405,21 @@ describe("LeuSelect", () => {
expect(popup.active).to.not.be.true
})
+ it("sets the multipleSelection property on the menu items when multiple selection is allowed", async () => {
+ const el = await defaultFixture({
+ options: MUNICIPALITIES,
+ label: "Gemeinde",
+ multiple: true,
+ })
+
+ const menuItems = Array.from(el.querySelectorAll("leu-menu-item"))
+ expect(menuItems.every((item) => item.multipleSelection)).to.be.true
+
+ el.multiple = false
+ await elementUpdated(el)
+
+ expect(menuItems.every((item) => !item.multipleSelection)).to.be.true
+
it("closes the popup when the document is clicked outside the component", async () => {
const el = await defaultFixture({
options: MUNICIPALITIES,