add header-actions slot

This commit is contained in:
Cory LaViska
2022-11-29 11:17:15 -05:00
parent 0c18880e5c
commit 488088d5f0
7 changed files with 153 additions and 24 deletions

View File

@@ -151,6 +151,59 @@ const App = () => {
};
```
### Header Actions
The header shows a functional close button by default. You can use the `header-actions` slot to add additional [icon buttons](/components/icon-button) if needed.
```html preview
<sl-dialog label="Dialog" class="dialog-header-actions">
<sl-icon-button class="new-window" slot="header-actions" name="box-arrow-up-right"></sl-icon-button>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<sl-button slot="footer" variant="primary">Close</sl-button>
</sl-dialog>
<sl-button>Open Dialog</sl-button>
<script>
const dialog = document.querySelector('.dialog-header-actions');
const openButton = dialog.nextElementSibling;
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
const newWindowButton = dialog.querySelector('.new-window');
openButton.addEventListener('click', () => dialog.show());
closeButton.addEventListener('click', () => dialog.hide());
newWindowButton.addEventListener('click', () => window.open(location.href));
</script>
```
```jsx react
import { useState } from 'react';
import { SlButton, SlDialog, SlIconButton } from '@shoelace-style/shoelace/dist/react';
const App = () => {
const [open, setOpen] = useState(false);
return (
<>
<SlDialog label="Dialog" open={open} onSlAfterHide={() => setOpen(false)}>
<SlIconButton
class="new-window"
slot="header-actions"
name="box-arrow-up-right"
onClick={() => window.open(location.href)}
/>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<SlButton slot="footer" variant="primary" onClick={() => setOpen(false)}>
Close
</SlButton>
</SlDialog>
<SlButton onClick={() => setOpen(true)}>Open Dialog</SlButton>
</>
);
};
```
### Preventing the Dialog from Closing
By default, dialogs will close when the user clicks the close button, clicks the overlay, or presses the <kbd>Escape</kbd> key. In most cases, the default behavior is the best behavior in terms of UX. However, there are situations where this may be undesirable, such as when data loss will occur.

View File

@@ -338,6 +338,54 @@ const App = () => {
};
```
### Header Actions
The header shows a functional close button by default. You can use the `header-actions` slot to add additional [icon buttons](/components/icon-button) if needed.
```html preview
<sl-drawer label="Drawer" class="drawer-header-actions">
<sl-icon-button class="new-window" slot="header-actions" name="box-arrow-up-right"></sl-icon-button>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<sl-button slot="footer" variant="primary">Close</sl-button>
</sl-drawer>
<sl-button>Open Drawer</sl-button>
<script>
const drawer = document.querySelector('.drawer-header-actions');
const openButton = drawer.nextElementSibling;
const closeButton = drawer.querySelector('sl-button[variant="primary"]');
const newWindowButton = drawer.querySelector('.new-window');
openButton.addEventListener('click', () => drawer.show());
closeButton.addEventListener('click', () => drawer.hide());
newWindowButton.addEventListener('click', () => window.open(location.href));
</script>
```
```jsx react
import { useState } from 'react';
import { SlButton, SlDrawer, SlIconButton } from '@shoelace-style/shoelace/dist/react';
const App = () => {
const [open, setOpen] = useState(false);
return (
<>
<SlDrawer label="Drawer" open={open} onSlAfterHide={() => setOpen(false)}>
<SlIconButton slot="header-actions" name="box-arrow-up-right" onClick={() => window.open(location.href)} />
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<SlButton slot="footer" variant="primary" onClick={() => setOpen(false)}>
Close
</SlButton>
</SlDrawer>
<SlButton onClick={() => setOpen(true)}>Open Drawer</SlButton>
</>
);
};
```
### Preventing the Drawer from Closing
By default, drawers will close when the user clicks the close button, clicks the overlay, or presses the <kbd>Escape</kbd> key. In most cases, the default behavior is the best behavior in terms of UX. However, there are situations where this may be undesirable, such as when data loss will occur.

View File

@@ -10,10 +10,12 @@ New versions of Shoelace are released as-needed and generally occur when a criti
## Next
- Added `header-actions` slot to `<sl-dialog>` and `<sl-drawer>`
- Fixed a bug in `<sl-tree-item>` where `sl-selection-change` was emitted when the selection didn't change [#1030](https://github.com/shoelace-style/shoelace/pull/1030)
- Improved IntelliSense in VS Code, courtesy of [Burton's amazing CEM Analyzer plugin](https://github.com/break-stuff/cem-plugin-vs-code-custom-data-generator)
- Improved accessibility of `<sl-alert>` so the alert is announced and the close button has a label
- Removed unused aria attributes from `<sl-skeleton>`
- Replaced the `x` icon in the system icon library with `x-lg` to improve icon consistency
## 2.0.0-beta.85

View File

@@ -68,12 +68,21 @@ export default css`
margin: 0;
}
.dialog__close {
.dialog__header-actions {
flex-shrink: 0;
display: flex;
flex-wrap: wrap;
justify-content: end;
gap: var(--sl-spacing-2x-small);
padding: 0 var(--header-spacing);
}
.dialog__header-actions sl-icon-button,
.dialog__header-actions ::slotted(sl-icon-button) {
flex: 0 0 auto;
display: flex;
align-items: center;
font-size: var(--sl-font-size-x-large);
padding: 0 var(--header-spacing);
font-size: var(--sl-font-size-medium);
}
.dialog__body {

View File

@@ -42,6 +42,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart overlay - The overlay.
* @csspart panel - The dialog panel (where the dialog and its content is rendered).
* @csspart header - The dialog header.
* @csspart header-actions - Optional actions to add to the header. Works best with `<sl-icon-button>`.
* @csspart title - The dialog title.
* @csspart close-button - The close button.
* @csspart close-button__base - The close button's `base` part.
@@ -279,15 +280,18 @@ export default class SlDialog extends ShoelaceElement {
<h2 part="title" class="dialog__title" id="title">
<slot name="label"> ${this.label.length > 0 ? this.label : String.fromCharCode(65279)} </slot>
</h2>
<sl-icon-button
part="close-button"
exportparts="base:close-button__base"
class="dialog__close"
name="x"
label=${this.localize.term('close')}
library="system"
@click="${() => this.requestClose('close-button')}"
></sl-icon-button>
<div part="header-actions" class="dialog__header-actions">
<slot name="header-actions"></slot>
<sl-icon-button
part="close-button"
exportparts="base:close-button__base"
class="dialog__close"
name="x-lg"
label=${this.localize.term('close')}
library="system"
@click="${() => this.requestClose('close-button')}"
></sl-icon-button>
</div>
</header>
`
: ''}

View File

@@ -99,12 +99,21 @@ export default css`
margin: 0;
}
.drawer__close {
.drawer__header-actions {
flex-shrink: 0;
display: flex;
flex-wrap: wrap;
justify-content: end;
gap: var(--sl-spacing-2x-small);
padding: 0 var(--header-spacing);
}
.drawer__header-actions sl-icon-button,
.drawer__header-actions ::slotted(sl-icon-button) {
flex: 0 0 auto;
display: flex;
align-items: center;
font-size: var(--sl-font-size-x-large);
padding: 0 var(--header-spacing);
font-size: var(--sl-font-size-medium);
}
.drawer__body {

View File

@@ -43,6 +43,7 @@ import type { CSSResultGroup } from 'lit';
* @csspart overlay - The overlay.
* @csspart panel - The drawer panel (where the drawer and its content is rendered).
* @csspart header - The drawer header.
* @csspart header-actions - Optional actions to add to the header. Works best with `<sl-icon-button>`.
* @csspart title - The drawer title.
* @csspart close-button - The close button.
* @csspart close-button__base - The close button's `base` part.
@@ -310,15 +311,18 @@ export default class SlDrawer extends ShoelaceElement {
<!-- If there's no label, use an invisible character to prevent the header from collapsing -->
<slot name="label"> ${this.label.length > 0 ? this.label : String.fromCharCode(65279)} </slot>
</h2>
<sl-icon-button
part="close-button"
exportparts="base:close-button__base"
class="drawer__close"
name="x"
label=${this.localize.term('close')}
library="system"
@click=${() => this.requestClose('close-button')}
></sl-icon-button>
<div part="header-actions" class="drawer__header-actions">
<slot name="header-actions"></slot>
<sl-icon-button
part="close-button"
exportparts="base:close-button__base"
class="drawer__close"
name="x-lg"
label=${this.localize.term('close')}
library="system"
@click=${() => this.requestClose('close-button')}
></sl-icon-button>
</div>
</header>
`
: ''}