Skip to content

Commit

Permalink
Add support for sl-dropdown in the default slot of sl-breadcrumb-item (
Browse files Browse the repository at this point in the history
…#2015)

* Add support for dropdowns in the default slot

* Make sure to register changes to the href attribute, too

* Update src/components/breadcrumb-item/breadcrumb-item.component.ts

Co-authored-by: Konnor Rogers <konnor5456@gmail.com>

* Update src/components/breadcrumb-item/breadcrumb-item.component.ts

Co-authored-by: Konnor Rogers <konnor5456@gmail.com>

* Update src/components/breadcrumb-item/breadcrumb-item.component.ts

Co-authored-by: Konnor Rogers <konnor5456@gmail.com>

* Prettier

---------

Co-authored-by: Konnor Rogers <konnor5456@gmail.com>
  • Loading branch information
schilchSICKAG and KonnorRogers authored Aug 5, 2024
1 parent bc6d25a commit 2704f72
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 8 deletions.
58 changes: 58 additions & 0 deletions docs/pages/components/breadcrumb.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,61 @@ const App = () => (
</SlBreadcrumb>
);
```

### With Dropdowns in default slot

Dropdown menus can be placed in the default slot to provide additional options.

```html:preview
<sl-breadcrumb>
<sl-breadcrumb-item>Homepage</sl-breadcrumb-item>
<sl-breadcrumb-item>
<sl-dropdown>
<sl-button slot="trigger" size="small" circle>
<sl-icon label="More options" name="three-dots"></sl-icon>
</sl-button>
<sl-menu>
<sl-menu-item type="checkbox" checked>Web Design</sl-menu-item>
<sl-menu-item type="checkbox">Web Development</sl-menu-item>
<sl-menu-item type="checkbox">Marketing</sl-menu-item>
</sl-menu>
</sl-dropdown>
</sl-breadcrumb-item>
<sl-breadcrumb-item>Our Services</sl-breadcrumb-item>
<sl-breadcrumb-item>Digital Media</sl-breadcrumb-item>
</sl-breadcrumb>
```

```jsx:react
import {
SlBreadcrumb,
SlBreadcrumbItem,
SlButton,
SlDropdown,
SlIcon,
SlMenu,
SlMenuItem
} from '@shoelace-style/shoelace/dist/react';
const App = () => (
<SlBreadcrumb>
<SlBreadcrumbItem>Homepage</SlBreadcrumbItem>
<SlBreadcrumbItem>
<SlDropdown slot="suffix">
<SlButton slot="trigger" size="small" circle>
<SlIcon label="More options" name="three-dots"></SlIcon>
</SlButton>
<SlMenu>
<SlMenuItem type="checkbox" checked>
Web Design
</SlMenuItem>
<SlMenuItem type="checkbox">Web Development</SlMenuItem>
<SlMenuItem type="checkbox">Marketing</SlMenuItem>
</SlMenu>
</SlDropdown>
</SlBreadcrumbItem>
<SlBreadcrumbItem>Our Services</SlBreadcrumbItem>
<SlBreadcrumbItem>Digital Media</SlBreadcrumbItem>
</SlBreadcrumb>
);
```
1 change: 1 addition & 0 deletions docs/pages/resources/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ New versions of Shoelace are released as-needed and generally occur when a criti

## 2.15.1

- Added support for using `<sl-dropdown>` in `<sl-breadcrumb-item>` default slot [#2015]
- Fixed a bug in `<sl-radio-group>` where if a click did not contain a `<sl-radio>` it would show a console error. [#2009]
- Fixed a bug in `<sl-split-panel>` that caused it not to recalculate it's position when going from being `display: none;` to its original display value. [#1942]
- Fixed a bug in `<dialog>` where when it showed it would cause a layout shift. [#1967]
Expand Down
56 changes: 48 additions & 8 deletions src/components/breadcrumb-item/breadcrumb-item.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { classMap } from 'lit/directives/class-map.js';
import { HasSlotController } from '../../internal/slot.js';
import { html } from 'lit';
import { ifDefined } from 'lit/directives/if-defined.js';
import { property } from 'lit/decorators.js';
import { property, query, state } from 'lit/decorators.js';
import { watch } from '../../internal/watch.js';
import componentStyles from '../../styles/component.styles.js';
import ShoelaceElement from '../../internal/shoelace-element.js';
import styles from './breadcrumb-item.styles.js';
Expand Down Expand Up @@ -31,6 +32,10 @@ export default class SlBreadcrumbItem extends ShoelaceElement {

private readonly hasSlotController = new HasSlotController(this, 'prefix', 'suffix');

@query('slot:not([name])') defaultSlot: HTMLSlotElement;

@state() private renderType: 'button' | 'link' | 'dropdown' = 'button';

/**
* Optional URL to direct the user to when the breadcrumb item is activated. When set, a link will be rendered
* internally. When unset, a button will be rendered instead.
Expand All @@ -43,9 +48,34 @@ export default class SlBreadcrumbItem extends ShoelaceElement {
/** The `rel` attribute to use on the link. Only used when `href` is set. */
@property() rel = 'noreferrer noopener';

render() {
const isLink = this.href ? true : false;
private setRenderType() {
const hasDropdown =
this.defaultSlot.assignedElements({ flatten: true }).filter(i => i.tagName.toLowerCase() === 'sl-dropdown')
.length > 0;

if (this.href) {
this.renderType = 'link';
return;
}

if (hasDropdown) {
this.renderType = 'dropdown';
return;
}

this.renderType = 'button';
}

@watch('href', { waitUntilFirstUpdate: true })
hrefChanged() {
this.setRenderType();
}

handleSlotChange() {
this.setRenderType();
}

render() {
return html`
<div
part="base"
Expand All @@ -59,7 +89,7 @@ export default class SlBreadcrumbItem extends ShoelaceElement {
<slot name="prefix"></slot>
</span>
${isLink
${this.renderType === 'link'
? html`
<a
part="label"
Expand All @@ -68,14 +98,24 @@ export default class SlBreadcrumbItem extends ShoelaceElement {
target="${ifDefined(this.target ? this.target : undefined)}"
rel=${ifDefined(this.target ? this.rel : undefined)}
>
<slot></slot>
<slot @slotchange=${this.handleSlotChange}></slot>
</a>
`
: html`
: ''}
${this.renderType === 'button'
? html`
<button part="label" type="button" class="breadcrumb-item__label breadcrumb-item__label--button">
<slot></slot>
<slot @slotchange=${this.handleSlotChange}></slot>
</button>
`}
`
: ''}
${this.renderType === 'dropdown'
? html`
<div part="label" class="breadcrumb-item__label breadcrumb-item__label--drop-down">
<slot @slotchange=${this.handleSlotChange}></slot>
</div>
`
: ''}
<span part="suffix" class="breadcrumb-item__suffix">
<slot name="suffix"></slot>
Expand Down
24 changes: 24 additions & 0 deletions src/components/breadcrumb-item/breadcrumb-item.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,30 @@ describe('<sl-breadcrumb-item>', () => {
});
});

describe('when rendering a sl-dropdown in the default slot', () => {
it('should not render a link or button tag, but a div wrapper', async () => {
el = await fixture<SlBreadcrumbItem>(html`
<sl-breadcrumb-item>
<sl-dropdown>
<sl-button slot="trigger" size="small" circle>
<sl-icon label="More options" name="three-dots"></sl-icon>
</sl-button>
<sl-menu>
<sl-menu-item type="checkbox" checked>Web Design</sl-menu-item>
<sl-menu-item type="checkbox">Web Development</sl-menu-item>
<sl-menu-item type="checkbox">Marketing</sl-menu-item>
</sl-menu>
</sl-dropdown>
</sl-breadcrumb-item>
`);

await expect(el).to.be.accessible();
expect(el.shadowRoot!.querySelector('a')).to.be.null;
expect(el.shadowRoot!.querySelector('button')).to.be.null;
expect(el.shadowRoot!.querySelector('div.breadcrumb-item__label--drop-down')).not.to.be.null;
});
});

describe('when provided an element in the slot "prefix" to support prefix icons', () => {
before(async () => {
el = await fixture<SlBreadcrumbItem>(html`
Expand Down

0 comments on commit 2704f72

Please sign in to comment.