Add button group component

pull/165/head
Cory LaViska 2020-08-06 09:07:24 -04:00
rodzic 767decf6c6
commit 2b2a37bc3f
8 zmienionych plików z 344 dodań i 0 usunięć

Wyświetl plik

@ -2,6 +2,7 @@
## 2.0.0-beta.10
- Added button group component
- Added community page to the docs
- Fixed a bug where many components would erroneously receive an `id` when using the custom elements bundle
- Fixed a bug where tab groups weren't scrollable with the mouse

Wyświetl plik

@ -13,6 +13,7 @@
- [Avatar](/components/avatar.md)
- [Badge](/components/badge.md)
- [Button](/components/button.md)
- [Button Group](/components/button-group.md)
- [Card](/components/card.md)
- [Checkbox](/components/checkbox.md)
- [Color Picker](/components/color-picker.md)

Wyświetl plik

@ -0,0 +1,189 @@
# Button Group
[component-header:sl-button-group]
Button groups can be used to group related buttons into sections.
```html preview
<sl-button-group>
<sl-button>Left</sl-button>
<sl-button>Center</sl-button>
<sl-button>Right</sl-button>
</sl-button-group>
```
## Examples
### Button Sizes
All button sizes are supported, but avoid mixing sizes within the same button group.
```html preview
<sl-button-group>
<sl-button size="small">Left</sl-button>
<sl-button size="small">Center</sl-button>
<sl-button size="small">Right</sl-button>
</sl-button-group>
<br><br>
<sl-button-group>
<sl-button size="medium">Left</sl-button>
<sl-button size="medium">Center</sl-button>
<sl-button size="medium">Right</sl-button>
</sl-button-group>
<br><br>
<sl-button-group>
<sl-button size="large">Left</sl-button>
<sl-button size="large">Center</sl-button>
<sl-button size="large">Right</sl-button>
</sl-button-group>
```
### Theme Buttons
Theme buttons are supported through the button's `type` attribute. Types can be mixed as needed.
```html preview
<sl-button-group>
<sl-button type="primary">Left</sl-button>
<sl-button type="primary">Center</sl-button>
<sl-button type="primary">Right</sl-button>
</sl-button-group>
<br><br>
<sl-button-group>
<sl-button type="info">Left</sl-button>
<sl-button type="info">Center</sl-button>
<sl-button type="info">Right</sl-button>
</sl-button-group>
<br><br>
<sl-button-group>
<sl-button>Create</sl-button>
<sl-button>Edit</sl-button>
<sl-button type="danger">Destroy</sl-button>
</sl-button-group>
```
### Pill Buttons
Pill buttons are supported through the button's `pill` attribute.
```html preview
<sl-button-group>
<sl-button size="small" pill>Left</sl-button>
<sl-button size="small" pill>Center</sl-button>
<sl-button size="small" pill>Right</sl-button>
</sl-button-group>
<br><br>
<sl-button-group>
<sl-button size="medium" pill>Left</sl-button>
<sl-button size="medium" pill>Center</sl-button>
<sl-button size="medium" pill>Right</sl-button>
</sl-button-group>
<br><br>
<sl-button-group>
<sl-button size="large" pill>Left</sl-button>
<sl-button size="large" pill>Center</sl-button>
<sl-button size="large" pill>Right</sl-button>
</sl-button-group>
```
### Dropdowns in Button Groups
Dropdowns can be placed inside button groups as long as the trigger is a `<sl-dropdown>` element.
```html preview
<sl-button-group>
<sl-button>Button</sl-button>
<sl-button>Button</sl-button>
<sl-dropdown>
<sl-button slot="trigger" caret>Dropdown</sl-button>
<sl-menu>
<sl-menu-item>Item 1</sl-menu-item>
<sl-menu-item>Item 2</sl-menu-item>
<sl-menu-item>Item 3</sl-menu-item>
</sl-menu>
</sl-dropdown>
</sl-button-group>
```
### Tooltips in Button Groups
Buttons can be wrapped in tooltips to provide more detail when the user interacts with them.
```html preview
<sl-button-group>
<sl-tooltip content="I'm on the left">
<sl-button>Left</sl-button>
</sl-tooltip>
<sl-tooltip content="I'm in the middle">
<sl-button>Center</sl-button>
</sl-tooltip>
<sl-tooltip content="I'm on the right">
<sl-button>Right</sl-button>
</sl-tooltip>
</sl-button-group>
```
### Toolbar Example
Create interactive toolbars with button groups.
```html preview
<div class="button-group-toolbar">
<sl-button-group label="History">
<sl-tooltip content="Undo">
<sl-button><sl-icon name="arrow-counterclockwise"></sl-icon></sl-button>
</sl-tooltip>
<sl-tooltip content="Redo">
<sl-button><sl-icon name="arrow-clockwise"></sl-icon></sl-button>
</sl-tooltip>
</sl-button-group>
<sl-button-group label="Formatting">
<sl-tooltip content="Bold">
<sl-button><sl-icon name="type-bold"></sl-icon></sl-button>
</sl-tooltip>
<sl-tooltip content="Italic">
<sl-button><sl-icon name="type-italic"></sl-icon></sl-button>
</sl-tooltip>
<sl-tooltip content="Underline">
<sl-button><sl-icon name="type-underline"></sl-icon></sl-button>
</sl-tooltip>
</sl-button-group>
<sl-button-group label="Alignment">
<sl-tooltip content="Align Left">
<sl-button><sl-icon name="justify-left"></sl-icon></sl-button>
</sl-tooltip>
<sl-tooltip content="Align Center">
<sl-button><sl-icon name="justify"></sl-icon></sl-button>
</sl-tooltip>
<sl-tooltip content="Align Right">
<sl-button><sl-icon name="justify-right"></sl-icon></sl-button>
</sl-tooltip>
</sl-button-group>
</div>
<style>
.button-group-toolbar sl-button-group:not(:last-of-type) {
margin-right: .5rem;
}
</style>
```
[component-metadata:sl-button-group]

21
src/components.d.ts vendored
Wyświetl plik

@ -110,6 +110,12 @@ export namespace Components {
*/
"value": string;
}
interface SlButtonGroup {
/**
* A label to use for the button groups `aria-label` attribute.
*/
"label": string;
}
interface SlCard {
}
interface SlCheckbox {
@ -930,6 +936,12 @@ declare global {
prototype: HTMLSlButtonElement;
new (): HTMLSlButtonElement;
};
interface HTMLSlButtonGroupElement extends Components.SlButtonGroup, HTMLStencilElement {
}
var HTMLSlButtonGroupElement: {
prototype: HTMLSlButtonGroupElement;
new (): HTMLSlButtonGroupElement;
};
interface HTMLSlCardElement extends Components.SlCard, HTMLStencilElement {
}
var HTMLSlCardElement: {
@ -1115,6 +1127,7 @@ declare global {
"sl-avatar": HTMLSlAvatarElement;
"sl-badge": HTMLSlBadgeElement;
"sl-button": HTMLSlButtonElement;
"sl-button-group": HTMLSlButtonGroupElement;
"sl-card": HTMLSlCardElement;
"sl-checkbox": HTMLSlCheckboxElement;
"sl-color-picker": HTMLSlColorPickerElement;
@ -1260,6 +1273,12 @@ declare namespace LocalJSX {
*/
"value"?: string;
}
interface SlButtonGroup {
/**
* A label to use for the button groups `aria-label` attribute.
*/
"label"?: string;
}
interface SlCard {
}
interface SlCheckbox {
@ -2143,6 +2162,7 @@ declare namespace LocalJSX {
"sl-avatar": SlAvatar;
"sl-badge": SlBadge;
"sl-button": SlButton;
"sl-button-group": SlButtonGroup;
"sl-card": SlCard;
"sl-checkbox": SlCheckbox;
"sl-color-picker": SlColorPicker;
@ -2183,6 +2203,7 @@ declare module "@stencil/core" {
"sl-avatar": LocalJSX.SlAvatar & JSXBase.HTMLAttributes<HTMLSlAvatarElement>;
"sl-badge": LocalJSX.SlBadge & JSXBase.HTMLAttributes<HTMLSlBadgeElement>;
"sl-button": LocalJSX.SlButton & JSXBase.HTMLAttributes<HTMLSlButtonElement>;
"sl-button-group": LocalJSX.SlButtonGroup & JSXBase.HTMLAttributes<HTMLSlButtonGroupElement>;
"sl-card": LocalJSX.SlCard & JSXBase.HTMLAttributes<HTMLSlCardElement>;
"sl-checkbox": LocalJSX.SlCheckbox & JSXBase.HTMLAttributes<HTMLSlCheckboxElement>;
"sl-color-picker": LocalJSX.SlColorPicker & JSXBase.HTMLAttributes<HTMLSlColorPickerElement>;

Wyświetl plik

@ -0,0 +1,52 @@
//
// In general, we should avoid placing styles in the light DOM. However, we don't have a way to target slotted element
// parts, e.g. `::slotted(sl-button)::part(base)`, so we need these styles to make buttons groups work.
//
// The alternative approach is to set the styles with JavaScript, but this is more expensive because it requires
// multiple listeners + DOM traversals.
//
sl-button-group {
// First
> sl-button:first-child::part(base),
> sl-dropdown:first-child > sl-button[slot='trigger']::part(base),
> sl-tooltip:first-child > sl-button::part(base) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
// Last
> sl-button:last-child::part(base),
> sl-dropdown:last-child > sl-button[slot='trigger']::part(base),
> sl-tooltip:last-child > sl-button::part(base) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
// Interior
> sl-button:not(:first-child):not(:last-child)::part(base),
> sl-dropdown:not(:first-child):not(:last-child) > sl-button[slot='trigger']::part(base),
> sl-tooltip:not(:first-child):not(:last-child) > sl-button::part(base) {
border-radius: 0;
}
// All except the first
> sl-button:not(:first-child),
> sl-dropdown:not(:first-child) > sl-button[slot='trigger'],
> sl-tooltip:not(:first-child) > sl-button {
margin-left: calc(-1 * var(--sl-input-border-width));
}
// Hover
> sl-button:hover,
> sl-dropdown:hover > sl-button[slot='trigger'],
> sl-tooltip:hover > sl-button {
z-index: 1;
}
// Focus
> sl-button.sl-focus,
> sl-dropdown > sl-button[slot='trigger'].sl-focus,
> sl-tooltip > sl-button.sl-focus {
z-index: 2;
}
}

Wyświetl plik

@ -0,0 +1,19 @@
@import 'component';
:host {
display: inline-block;
}
.button-group {
display: flex;
flex-wrap: nowrap;
position: relative;
}
::slotted(.sl-hover) {
z-index: 1;
}
::slotted(.sl-focus) {
z-index: 2;
}

Wyświetl plik

@ -0,0 +1,55 @@
import { Component, Prop, h } from '@stencil/core';
/**
* @since 2.0
* @status stable
*
* @slot - One or more `<sl-button>` elements to display in the button group.
*
* @part base - The component's base wrapper.
*/
@Component({
tag: 'sl-button-group',
styleUrl: 'button-group.scss',
shadow: true
})
export class ButtonGroup {
buttonGroup: HTMLElement;
/** A label to use for the button groups `aria-label` attribute. */
@Prop() label = '';
connectedCallback() {
this.handleFocus = this.handleFocus.bind(this);
this.handleBlur = this.handleBlur.bind(this);
}
componentDidLoad() {
this.buttonGroup.addEventListener('slFocus', this.handleFocus);
this.buttonGroup.addEventListener('slBlur', this.handleBlur);
}
disconnectedCallback() {
this.buttonGroup.removeEventListener('slFocus', this.handleFocus);
this.buttonGroup.removeEventListener('slBlur', this.handleBlur);
}
handleFocus(event: CustomEvent) {
const button = event.target as HTMLElement;
button.classList.add('sl-focus');
}
handleBlur(event: CustomEvent) {
const button = event.target as HTMLElement;
button.classList.remove('sl-focus');
}
render() {
return (
<div ref={el => (this.buttonGroup = el)} part="base" class="button-group" aria-label={this.label}>
<slot />
</div>
);
}
}

Wyświetl plik

@ -265,3 +265,9 @@
.sl-scroll-lock {
overflow: hidden !important;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Component light DOM styles - only follow this pattern when absolutely necessary!
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@import '../components/button-group/button-group.light-dom';