Merge branch 'next' into auto-hide-tab-group-scroll-buttons

This commit is contained in:
Cory LaViska
2024-08-05 12:04:37 -04:00
committed by GitHub
11 changed files with 139 additions and 18 deletions

View File

@@ -199,7 +199,63 @@ const App = () => (
### With Dropdowns
Dropdown menus can be placed in a prefix or suffix slot to provide additional options.
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>
);
```
Alternatively, you can place dropdown menus in a prefix or suffix slot.
```html:preview
<sl-breadcrumb>

View File

@@ -15,6 +15,8 @@ New versions of Shoelace are released as-needed and generally occur when a criti
## Next
- Added ability to auto hide scroll buttons for `<sl-tab-group>` when scroll button is not clickable by adding the `auto-hide-scroll-buttons` attribute. [#2128]
- Added support for using `<sl-dropdown>` in `<sl-breadcrumb-item>` default slot [#2015]
- Fixed a bug that caused errors to show in the console when components disconnect before before `firstUpdated()` executes [#2127]
## 2.16.0

View File

@@ -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';
@@ -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.
@@ -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"
@@ -59,7 +89,7 @@ export default class SlBreadcrumbItem extends ShoelaceElement {
<slot name="prefix"></slot>
</span>
${isLink
${this.renderType === 'link'
? html`
<a
part="label"
@@ -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>

View File

@@ -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`

View File

@@ -103,7 +103,7 @@ export default class SlCarousel extends ShoelaceElement {
disconnectedCallback(): void {
super.disconnectedCallback();
this.mutationObserver.disconnect();
this.mutationObserver?.disconnect();
}
protected firstUpdated(): void {

View File

@@ -89,7 +89,7 @@ export default class SlDetails extends ShoelaceElement {
disconnectedCallback() {
super.disconnectedCallback();
this.detailsObserver.disconnect();
this.detailsObserver?.disconnect();
}
private handleSummaryClick(event: MouseEvent) {

View File

@@ -132,7 +132,7 @@ export default class SlRange extends ShoelaceElement implements ShoelaceFormCont
disconnectedCallback() {
super.disconnectedCallback();
this.resizeObserver.unobserve(this.input);
this.resizeObserver?.unobserve(this.input);
}
private handleChange() {

View File

@@ -85,7 +85,7 @@ export default class SlSplitPanel extends ShoelaceElement {
disconnectedCallback() {
super.disconnectedCallback();
this.resizeObserver.unobserve(this);
this.resizeObserver?.unobserve(this);
}
private detectSize() {

View File

@@ -127,8 +127,8 @@ export default class SlTabGroup extends ShoelaceElement {
disconnectedCallback() {
super.disconnectedCallback();
this.mutationObserver.disconnect();
this.resizeObserver.unobserve(this.nav);
this.mutationObserver?.disconnect();
this.resizeObserver?.unobserve(this.nav);
}
private getAllTabs() {

View File

@@ -164,7 +164,7 @@ export default class SlTextarea extends ShoelaceElement implements ShoelaceFormC
disconnectedCallback() {
super.disconnectedCallback();
if (this.input) {
this.resizeObserver.unobserve(this.input);
this.resizeObserver?.unobserve(this.input);
}
}

View File

@@ -111,8 +111,7 @@ export default class SlTree extends ShoelaceElement {
disconnectedCallback() {
super.disconnectedCallback();
this.mutationObserver.disconnect();
this.mutationObserver?.disconnect();
}
// Generates a clone of the expand icon element to use for each tree item