kopia lustrzana https://github.com/shoelace-style/shoelace
closes #1070
rodzic
b183a04fba
commit
a0fce64fd9
|
@ -47,10 +47,10 @@
|
|||
</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-label>Toggle <kbd>\\</kbd></sl-menu-label>
|
||||
<sl-menu-item value="light">Light</sl-menu-item>
|
||||
<sl-menu-item value="dark">Dark</sl-menu-item>
|
||||
<sl-menu-item type="checkbox" value="light">Light</sl-menu-item>
|
||||
<sl-menu-item type="checkbox" value="dark">Dark</sl-menu-item>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item value="auto">Auto</sl-menu-item>
|
||||
<sl-menu-item type="checkbox" value="auto">Auto</sl-menu-item>
|
||||
</sl-menu>
|
||||
`;
|
||||
document.querySelector('.sidebar-toggle').insertAdjacentElement('afterend', dropdown);
|
||||
|
|
|
@ -203,9 +203,9 @@ Dropdown menus can be placed in a prefix or suffix slot to provide additional op
|
|||
<sl-icon label="More options" name="three-dots"></sl-icon>
|
||||
</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item checked>Web Design</sl-menu-item>
|
||||
<sl-menu-item>Web Development</sl-menu-item>
|
||||
<sl-menu-item>Marketing</sl-menu-item>
|
||||
<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>
|
||||
|
@ -235,9 +235,11 @@ const App = () => (
|
|||
<SlIcon label="More options" name="three-dots"></SlIcon>
|
||||
</SlButton>
|
||||
<SlMenu>
|
||||
<SlMenuItem checked>Web Design</SlMenuItem>
|
||||
<SlMenuItem>Web Development</SlMenuItem>
|
||||
<SlMenuItem>Marketing</SlMenuItem>
|
||||
<SlMenuItem type="checkbox" checked>
|
||||
Web Design
|
||||
</SlMenuItem>
|
||||
<SlMenuItem type="checkbox">Web Development</SlMenuItem>
|
||||
<SlMenuItem type="checkbox">Marketing</SlMenuItem>
|
||||
</SlMenu>
|
||||
</SlDropdown>
|
||||
</SlBreadcrumbItem>
|
||||
|
|
|
@ -14,7 +14,7 @@ Dropdowns are designed to work well with [menus](/components/menu) to provide a
|
|||
<sl-menu-item>Dropdown Item 2</sl-menu-item>
|
||||
<sl-menu-item>Dropdown Item 3</sl-menu-item>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item checked>Checked</sl-menu-item>
|
||||
<sl-menu-item type="checkbox" checked>Checkbox</sl-menu-item>
|
||||
<sl-menu-item disabled>Disabled</sl-menu-item>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item>
|
||||
|
@ -42,7 +42,9 @@ const App = () => (
|
|||
<SlMenuItem>Dropdown Item 2</SlMenuItem>
|
||||
<SlMenuItem>Dropdown Item 3</SlMenuItem>
|
||||
<SlDivider />
|
||||
<SlMenuItem checked>Checked</SlMenuItem>
|
||||
<SlMenuItem type="checkbox" checked>
|
||||
Checkbox
|
||||
</SlMenuItem>
|
||||
<SlMenuItem disabled>Disabled</SlMenuItem>
|
||||
<SlDivider />
|
||||
<SlMenuItem>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<sl-menu-item>Option 2</sl-menu-item>
|
||||
<sl-menu-item>Option 3</sl-menu-item>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item checked>Checked</sl-menu-item>
|
||||
<sl-menu-item type="checkbox" checked>Checkbox</sl-menu-item>
|
||||
<sl-menu-item disabled>Disabled</sl-menu-item>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item>
|
||||
|
@ -31,7 +31,9 @@ const App = () => (
|
|||
<SlMenuItem>Option 2</SlMenuItem>
|
||||
<SlMenuItem>Option 3</SlMenuItem>
|
||||
<SlDivider />
|
||||
<SlMenuItem checked>Checked</SlMenuItem>
|
||||
<SlMenuItem type="checkbox" checked>
|
||||
Checkbox
|
||||
</SlMenuItem>
|
||||
<SlMenuItem disabled>Disabled</SlMenuItem>
|
||||
<SlDivider />
|
||||
<SlMenuItem>
|
||||
|
@ -48,30 +50,6 @@ const App = () => (
|
|||
|
||||
## Examples
|
||||
|
||||
### Checked
|
||||
|
||||
Use the `checked` attribute to draw menu items in a checked state.
|
||||
|
||||
```html preview
|
||||
<sl-menu style="max-width: 200px;">
|
||||
<sl-menu-item>Option 1</sl-menu-item>
|
||||
<sl-menu-item checked>Option 2</sl-menu-item>
|
||||
<sl-menu-item>Option 3</sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { SlMenu, SlMenuItem } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const App = () => (
|
||||
<SlMenu style={{ maxWidth: '200px' }}>
|
||||
<SlMenuItem>Option 1</SlMenuItem>
|
||||
<SlMenuItem checked>Option 2</SlMenuItem>
|
||||
<SlMenuItem>Option 3</SlMenuItem>
|
||||
</SlMenu>
|
||||
);
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Add the `disabled` attribute to disable the menu item so it cannot be selected.
|
||||
|
@ -150,6 +128,34 @@ const App = () => (
|
|||
);
|
||||
```
|
||||
|
||||
### Checkbox Menu Items
|
||||
|
||||
Set the `type` attribute to `checkbox` to create a menu item that will toggle on and off when selected. You can use the `checked` attribute to set the initial state.
|
||||
|
||||
Checkbox menu items are visually indistinguishable from regular menu items. Their ability to be toggled is primarily inferred from context, much like you'd find in the menu of a native app.
|
||||
|
||||
```html preview
|
||||
<sl-menu style="max-width: 200px;">
|
||||
<sl-menu-item type="checkbox">Autosave</sl-menu-item>
|
||||
<sl-menu-item type="checkbox" checked>Check Spelling</sl-menu-item>
|
||||
<sl-menu-item type="checkbox">Word Wrap</sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { SlMenu, SlMenuItem } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const App = () => (
|
||||
<SlMenu style={{ maxWidth: '200px' }}>
|
||||
<SlMenuItem type="checkbox">Autosave</SlMenuItem>
|
||||
<SlMenuItem type="checkbox" checked>
|
||||
Check Spelling
|
||||
</SlMenuItem>
|
||||
<SlMenuItem type="checkbox">Word Wrap</SlMenuItem>
|
||||
</SlMenu>
|
||||
);
|
||||
```
|
||||
|
||||
### Value & Selection
|
||||
|
||||
The `value` attribute can be used to assign a hidden value, such as a unique identifier, to a menu item. When an item is selected, the `sl-select` event will be emitted and a reference to the item will be available at `event.detail.item`. You can use this reference to access the selected item's value, its checked state, and more.
|
||||
|
@ -159,6 +165,10 @@ The `value` attribute can be used to assign a hidden value, such as a unique ide
|
|||
<sl-menu-item value="opt-1">Option 1</sl-menu-item>
|
||||
<sl-menu-item value="opt-2">Option 2</sl-menu-item>
|
||||
<sl-menu-item value="opt-3">Option 3</sl-menu-item>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item type="checkbox" value="opt-4">Checkbox 4</sl-menu-item>
|
||||
<sl-menu-item type="checkbox" value="opt-5">Checkbox 5</sl-menu-item>
|
||||
<sl-menu-item type="checkbox" value="opt-6">Checkbox 6</sl-menu-item>
|
||||
</sl-menu>
|
||||
|
||||
<script>
|
||||
|
@ -167,11 +177,12 @@ The `value` attribute can be used to assign a hidden value, such as a unique ide
|
|||
menu.addEventListener('sl-select', event => {
|
||||
const item = event.detail.item;
|
||||
|
||||
// Toggle checked state
|
||||
item.checked = !item.checked;
|
||||
|
||||
// Log value
|
||||
console.log(`Selected value: ${item.value}`);
|
||||
if (item.type === 'checkbox') {
|
||||
console.log(`Selected value: ${item.value} (${item.checked ? 'checked' : 'unchecked'})`);
|
||||
} else {
|
||||
console.log(`Selected value: ${item.value}`);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
|
|
@ -21,6 +21,9 @@ This release includes a complete rewrite of `<sl-select>` to improve accessibili
|
|||
- 🚨 BREAKING: removed the `sl-label-change` event from `<sl-menu-item>` (listen for `slotchange` instead)
|
||||
- 🚨 BREAKING: removed type to select logic from `<sl-menu>` (this was added specifically for `<sl-select>` which no longer uses `<sl-menu>`)
|
||||
- 🚨 BREAKING: swatches in `<sl-color-picker>` are no longer present by default (but you can set them using the `swatches` attribute now)
|
||||
- 🚨 BREAKING: improved the accessibility of `<sl-menu-item>` so checked items are announced as such
|
||||
- Checkbox menu items must now have `type="checkbox"` before applying the `checked` attribute
|
||||
- Checkbox menu items will now toggle their `checked` state on their own when selected
|
||||
- Added the `<sl-option>` component
|
||||
- Added Traditional Chinese translation [#1086](https://github.com/shoelace-style/shoelace/pull/1086)
|
||||
- Added support for `swatches` to be an attribute of `<sl-color-picker>` so swatches can be defined declaratively (it was previously a property; use a `;` to separate color values)
|
||||
|
|
|
@ -35,6 +35,9 @@ export default class SlMenuItem extends ShoelaceElement {
|
|||
@query('slot:not([name])') defaultSlot: HTMLSlotElement;
|
||||
@query('.menu-item') menuItem: HTMLElement;
|
||||
|
||||
/** The type of menu item to render. To use `checked`, this value must be set to `checkbox`. */
|
||||
@property() type: 'normal' | 'checkbox' = 'normal';
|
||||
|
||||
/** Draws the item in a checked state. */
|
||||
@property({ type: Boolean, reflect: true }) checked = false;
|
||||
|
||||
|
@ -44,10 +47,6 @@ export default class SlMenuItem extends ShoelaceElement {
|
|||
/** Draws the menu item in a disabled state, preventing selection. */
|
||||
@property({ type: Boolean, reflect: true }) disabled = false;
|
||||
|
||||
firstUpdated() {
|
||||
this.setAttribute('role', 'menuitem');
|
||||
}
|
||||
|
||||
private handleDefaultSlotChange() {
|
||||
const textLabel = this.getTextLabel();
|
||||
|
||||
|
@ -66,10 +65,12 @@ export default class SlMenuItem extends ShoelaceElement {
|
|||
|
||||
@watch('checked')
|
||||
handleCheckedChange() {
|
||||
//
|
||||
// TODO - fix a11y bug
|
||||
//
|
||||
// this.setAttribute('aria-checked', this.checked ? 'true' : 'false');
|
||||
this.setAttribute('aria-checked', this.checked ? 'true' : 'false');
|
||||
|
||||
if (this.checked && this.type !== 'checkbox') {
|
||||
this.checked = false;
|
||||
console.error('The checked attribute can only be used on menu items with type="checkbox"', this);
|
||||
}
|
||||
}
|
||||
|
||||
@watch('disabled')
|
||||
|
@ -77,6 +78,11 @@ export default class SlMenuItem extends ShoelaceElement {
|
|||
this.setAttribute('aria-disabled', this.disabled ? 'true' : 'false');
|
||||
}
|
||||
|
||||
@watch('type')
|
||||
handleTypeChange() {
|
||||
this.setAttribute('role', this.type === 'checkbox' ? 'menuitemcheckbox' : 'menuitem');
|
||||
}
|
||||
|
||||
/** Returns a text label based on the contents of the menu item's default slot. */
|
||||
getTextLabel() {
|
||||
return getTextContent(this.defaultSlot);
|
||||
|
|
|
@ -31,7 +31,7 @@ export default class SlMenu extends ShoelaceElement {
|
|||
|
||||
private getAllItems(options: { includeDisabled: boolean } = { includeDisabled: true }) {
|
||||
return [...this.defaultSlot.assignedElements({ flatten: true })].filter((el: HTMLElement) => {
|
||||
if (el.getAttribute('role') !== 'menuitem') {
|
||||
if (!this.isMenuItem(el)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,10 @@ export default class SlMenu extends ShoelaceElement {
|
|||
const item = target.closest('sl-menu-item');
|
||||
|
||||
if (item?.disabled === false) {
|
||||
if (item.type === 'checkbox') {
|
||||
item.checked = !item.checked;
|
||||
}
|
||||
|
||||
this.emit('sl-select', { detail: { item } });
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +106,7 @@ export default class SlMenu extends ShoelaceElement {
|
|||
private handleMouseDown(event: MouseEvent) {
|
||||
const target = event.target as HTMLElement;
|
||||
|
||||
if (target.getAttribute('role') === 'menuitem') {
|
||||
if (this.isMenuItem(target)) {
|
||||
this.setCurrentItem(target as SlMenuItem);
|
||||
}
|
||||
}
|
||||
|
@ -116,6 +120,13 @@ export default class SlMenu extends ShoelaceElement {
|
|||
}
|
||||
}
|
||||
|
||||
private isMenuItem(item: HTMLElement) {
|
||||
return (
|
||||
item.tagName.toLowerCase() === 'sl-menu-item' ||
|
||||
['menuitem', 'menuitemcheckbox', 'menuitemradio'].includes(item.getAttribute('role') ?? '')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Gets the current menu item, which is the menu item that has `tabindex="0"` within the roving tab index.
|
||||
* The menu item may or may not have focus, but for keyboard interaction purposes it's considered the "active" item.
|
||||
|
|
Ładowanie…
Reference in New Issue