Skip to content

Commit

Permalink
feat(menu-item): add multipleSelection property to display a check ic…
Browse files Browse the repository at this point in the history
…on (#227)
  • Loading branch information
daenub authored Jul 24, 2024
1 parent ba6257e commit 02358cc
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 11 deletions.
23 changes: 21 additions & 2 deletions src/components/menu/MenuItem.js
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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
Expand All @@ -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 },
Expand All @@ -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
Expand Down Expand Up @@ -142,9 +149,21 @@ export class LeuMenuItem extends LeuElement {
</button>`
}

_renderBeforeSlotDefault() {
if (!this.multipleSelection) {
return nothing
}

return this.active
? html`<leu-icon name="check"></leu-icon>`
: html`<leu-icon></leu-icon>`
}

render() {
const content = html`
<slot class="before" name="before"></slot>
<slot class="before" name="before"
>${this._renderBeforeSlotDefault()}</slot
>
<span class="label"><slot></slot></span>
<slot class="after" name="after"></slot>
`
Expand Down
26 changes: 18 additions & 8 deletions src/components/menu/stories/menu-item.stories.js
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -29,14 +29,19 @@ function Template(args) {
href=${ifDefined(args.href)}
?active=${args.active}
?disabled=${args.disabled}
?multipleSelection=${args.multipleSelection}
>
${isIcon(args.before)
? html`<leu-icon slot="before" name=${args.before}></leu-icon>`
: html`<span slot="before">${args.before}</span>`}
${args.before
? isIcon(args.before)
? html`<leu-icon slot="before" name=${args.before}></leu-icon>`
: html`<span slot="before">${args.before}</span>`
: nothing}
${args.label}
${isIcon(args.after)
? html`<leu-icon slot="after" name=${args.after}></leu-icon>`
: html`<span slot="after">${args.after}</span>`}
${args.after
? isIcon(args.after)
? html`<leu-icon slot="after" name=${args.after}></leu-icon>`
: html`<span slot="after">${args.after}</span>`
: null}
</leu-menu-item>
`
}
Expand All @@ -50,7 +55,7 @@ Active.args = {

export const IconBefore = Template.bind({})
IconBefore.args = {
before: "check",
before: "download",
}

export const IconAfterLink = Template.bind({})
Expand All @@ -69,3 +74,8 @@ export const IconPlaceholder = Template.bind({})
IconPlaceholder.args = {
before: "EMPTY",
}

export const MultipleSelection = Template.bind({})
MultipleSelection.args = {
multipleSelection: true,
}
23 changes: 23 additions & 0 deletions src/components/menu/test/menu-item.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ async function defaultFixture(args = {}) {
?active=${args.active}
?disabled=${args.disabled}
?tabbable=${args.tabbable}
?multipleSelection=${args.multipleSelection}
>
${args.label}
</leu-menu-item>
Expand Down Expand Up @@ -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")
})
})
8 changes: 7 additions & 1 deletion src/components/select/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
})
}
}
Expand All @@ -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 !== "" &&
Expand Down
15 changes: 15 additions & 0 deletions src/components/select/test/select.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 02358cc

Please sign in to comment.