kopia lustrzana https://github.com/shoelace-style/shoelace
Add loading attribute to menu-item
rodzic
12a45eb65d
commit
468b0b9e66
|
@ -9,7 +9,7 @@ layout: component
|
||||||
<sl-menu style="max-width: 200px;">
|
<sl-menu style="max-width: 200px;">
|
||||||
<sl-menu-item>Option 1</sl-menu-item>
|
<sl-menu-item>Option 1</sl-menu-item>
|
||||||
<sl-menu-item>Option 2</sl-menu-item>
|
<sl-menu-item>Option 2</sl-menu-item>
|
||||||
<sl-menu-item>Option 3</sl-menu-item>
|
<sl-menu-item loading>Option 3</sl-menu-item>
|
||||||
<sl-divider></sl-divider>
|
<sl-divider></sl-divider>
|
||||||
<sl-menu-item type="checkbox" checked>Checkbox</sl-menu-item>
|
<sl-menu-item type="checkbox" checked>Checkbox</sl-menu-item>
|
||||||
<sl-menu-item disabled>Disabled</sl-menu-item>
|
<sl-menu-item disabled>Disabled</sl-menu-item>
|
||||||
|
@ -37,7 +37,7 @@ const App = () => (
|
||||||
<SlMenu style={{ maxWidth: '200px' }}>
|
<SlMenu style={{ maxWidth: '200px' }}>
|
||||||
<SlMenuItem>Option 1</SlMenuItem>
|
<SlMenuItem>Option 1</SlMenuItem>
|
||||||
<SlMenuItem>Option 2</SlMenuItem>
|
<SlMenuItem>Option 2</SlMenuItem>
|
||||||
<SlMenuItem>Option 3</SlMenuItem>
|
<SlMenuItem loading>Option 3</SlMenuItem>
|
||||||
<SlDivider />
|
<SlDivider />
|
||||||
<SlMenuItem type="checkbox" checked>
|
<SlMenuItem type="checkbox" checked>
|
||||||
Checkbox
|
Checkbox
|
||||||
|
@ -60,6 +60,35 @@ const App = () => (
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
### Loading
|
||||||
|
|
||||||
|
Use the `loading` attribute to make a menu item busy. Clicks will be suppressed until the loading state is removed.
|
||||||
|
|
||||||
|
```html:preview
|
||||||
|
<sl-menu style="max-width: 200px;">
|
||||||
|
<sl-menu-item>Option 1</sl-menu-item>
|
||||||
|
<sl-menu-item loading>Option 2</sl-menu-item>
|
||||||
|
<sl-menu-item>Option 3</sl-menu-item>
|
||||||
|
</sl-menu>
|
||||||
|
```
|
||||||
|
|
||||||
|
{% raw %}
|
||||||
|
|
||||||
|
```jsx:react
|
||||||
|
import SlMenu from '@shoelace-style/shoelace/dist/react/menu';
|
||||||
|
import SlMenuItem from '@shoelace-style/shoelace/dist/react/menu-item';
|
||||||
|
|
||||||
|
const App = () => (
|
||||||
|
<SlMenu style={{ maxWidth: '200px' }}>
|
||||||
|
<SlMenuItem>Option 1</SlMenuItem>
|
||||||
|
<SlMenuItem loading>Option 2</SlMenuItem>
|
||||||
|
<SlMenuItem>Option 3</SlMenuItem>
|
||||||
|
</SlMenu>
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
{% endraw %}
|
||||||
|
|
||||||
### Disabled
|
### Disabled
|
||||||
|
|
||||||
Add the `disabled` attribute to disable the menu item so it cannot be selected.
|
Add the `disabled` attribute to disable the menu item so it cannot be selected.
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { watch } from '../../internal/watch.js';
|
||||||
import ShoelaceElement from '../../internal/shoelace-element.js';
|
import ShoelaceElement from '../../internal/shoelace-element.js';
|
||||||
import SlIcon from '../icon/icon.component.js';
|
import SlIcon from '../icon/icon.component.js';
|
||||||
import SlPopup from '../popup/popup.component.js';
|
import SlPopup from '../popup/popup.component.js';
|
||||||
|
import SlSpinner from '../spinner/spinner.component.js';
|
||||||
import styles from './menu-item.styles.js';
|
import styles from './menu-item.styles.js';
|
||||||
import type { CSSResultGroup } from 'lit';
|
import type { CSSResultGroup } from 'lit';
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ import type { CSSResultGroup } from 'lit';
|
||||||
*
|
*
|
||||||
* @dependency sl-icon
|
* @dependency sl-icon
|
||||||
* @dependency sl-popup
|
* @dependency sl-popup
|
||||||
|
* @dependency sl-spinner
|
||||||
*
|
*
|
||||||
* @slot - The menu item's label.
|
* @slot - The menu item's label.
|
||||||
* @slot prefix - Used to prepend an icon or similar element to the menu item.
|
* @slot prefix - Used to prepend an icon or similar element to the menu item.
|
||||||
|
@ -30,6 +32,7 @@ import type { CSSResultGroup } from 'lit';
|
||||||
* @csspart prefix - The prefix container.
|
* @csspart prefix - The prefix container.
|
||||||
* @csspart label - The menu item label.
|
* @csspart label - The menu item label.
|
||||||
* @csspart suffix - The suffix container.
|
* @csspart suffix - The suffix container.
|
||||||
|
* @csspart spinner - The spinner that shows when the menu item is in the loading state.
|
||||||
* @csspart submenu-icon - The submenu icon, visible only when the menu item has a submenu (not yet implemented).
|
* @csspart submenu-icon - The submenu icon, visible only when the menu item has a submenu (not yet implemented).
|
||||||
*
|
*
|
||||||
* @cssproperty [--submenu-offset=-2px] - The distance submenus shift to overlap the parent menu.
|
* @cssproperty [--submenu-offset=-2px] - The distance submenus shift to overlap the parent menu.
|
||||||
|
@ -38,7 +41,8 @@ export default class SlMenuItem extends ShoelaceElement {
|
||||||
static styles: CSSResultGroup = styles;
|
static styles: CSSResultGroup = styles;
|
||||||
static dependencies = {
|
static dependencies = {
|
||||||
'sl-icon': SlIcon,
|
'sl-icon': SlIcon,
|
||||||
'sl-popup': SlPopup
|
'sl-popup': SlPopup,
|
||||||
|
'sl-spinner': SlSpinner
|
||||||
};
|
};
|
||||||
|
|
||||||
private cachedTextLabel: string;
|
private cachedTextLabel: string;
|
||||||
|
@ -55,6 +59,9 @@ export default class SlMenuItem extends ShoelaceElement {
|
||||||
/** A unique value to store in the menu item. This can be used as a way to identify menu items when selected. */
|
/** A unique value to store in the menu item. This can be used as a way to identify menu items when selected. */
|
||||||
@property() value = '';
|
@property() value = '';
|
||||||
|
|
||||||
|
/** Draws the menu item in a loading state. */
|
||||||
|
@property({ type: Boolean, reflect: true }) loading = false;
|
||||||
|
|
||||||
/** Draws the menu item in a disabled state, preventing selection. */
|
/** Draws the menu item in a disabled state, preventing selection. */
|
||||||
@property({ type: Boolean, reflect: true }) disabled = false;
|
@property({ type: Boolean, reflect: true }) disabled = false;
|
||||||
|
|
||||||
|
@ -158,6 +165,7 @@ export default class SlMenuItem extends ShoelaceElement {
|
||||||
'menu-item--rtl': isRtl,
|
'menu-item--rtl': isRtl,
|
||||||
'menu-item--checked': this.checked,
|
'menu-item--checked': this.checked,
|
||||||
'menu-item--disabled': this.disabled,
|
'menu-item--disabled': this.disabled,
|
||||||
|
'menu-item--loading': this.loading,
|
||||||
'menu-item--has-submenu': this.isSubmenu(),
|
'menu-item--has-submenu': this.isSubmenu(),
|
||||||
'menu-item--submenu-expanded': isSubmenuExpanded
|
'menu-item--submenu-expanded': isSubmenuExpanded
|
||||||
})}
|
})}
|
||||||
|
@ -179,6 +187,7 @@ export default class SlMenuItem extends ShoelaceElement {
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
${this.submenuController.renderSubmenu()}
|
${this.submenuController.renderSubmenu()}
|
||||||
|
${this.loading ? html`<sl-spinner part="spinner"></sl-spinner>` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,4 +139,30 @@ export default css`
|
||||||
outline-offset: -1px;
|
outline-offset: -1px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loading modifier
|
||||||
|
*/
|
||||||
|
|
||||||
|
.menu-item--loading {
|
||||||
|
position: relative;
|
||||||
|
cursor: wait;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item--loading .menu-item__prefix,
|
||||||
|
.menu-item--loading .menu-item__label,
|
||||||
|
.menu-item--loading .menu-item__suffix,
|
||||||
|
.menu-item--loading .menu-item__check {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item--loading sl-spinner {
|
||||||
|
--indicator-color: currentColor;
|
||||||
|
position: absolute;
|
||||||
|
font-size: 1em;
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
top: calc(50% - 0.5em);
|
||||||
|
left: calc(50% - 0.5em);
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -40,6 +40,7 @@ describe('<sl-menu-item>', () => {
|
||||||
|
|
||||||
expect(el.value).to.equal('');
|
expect(el.value).to.equal('');
|
||||||
expect(el.disabled).to.be.false;
|
expect(el.disabled).to.be.false;
|
||||||
|
expect(el.loading).to.equal(false);
|
||||||
expect(el.getAttribute('aria-disabled')).to.equal('false');
|
expect(el.getAttribute('aria-disabled')).to.equal('false');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -48,6 +49,13 @@ describe('<sl-menu-item>', () => {
|
||||||
expect(el.getAttribute('aria-disabled')).to.equal('true');
|
expect(el.getAttribute('aria-disabled')).to.equal('true');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when loading', () => {
|
||||||
|
it('should have a spinner present', async () => {
|
||||||
|
const el = await fixture<SlMenuItem>(html` <sl-menu-item loading>Menu Item Label</sl-menu-item> `);
|
||||||
|
expect(el.shadowRoot!.querySelector('sl-spinner')).to.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should return a text label when calling getTextLabel()', async () => {
|
it('should return a text label when calling getTextLabel()', async () => {
|
||||||
const el = await fixture<SlMenuItem>(html` <sl-menu-item>Test</sl-menu-item> `);
|
const el = await fixture<SlMenuItem>(html` <sl-menu-item>Test</sl-menu-item> `);
|
||||||
expect(el.getTextLabel()).to.equal('Test');
|
expect(el.getTextLabel()).to.equal('Test');
|
||||||
|
|
Ładowanie…
Reference in New Issue