mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 04:09:12 +00:00
* [Menu-item] Drop `base` wrapper (rel #207) Also add two states: `has-submenu` and `submenu-expanded` * Add `checked-icon` and `submenu-icon` slots * [Menu-label] Drop `base` part * update changelog --------- Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
This commit is contained in:
@@ -33,6 +33,8 @@ During the alpha period, things might break! We take breaking changes very serio
|
||||
- Added the [`.wa-cloak` utility](/docs/utilities/fouce) to prevent FOUCE
|
||||
- Added the [`allDefined()` utility](/docs/usage/#all-defined) for awaiting component registration
|
||||
- Simplified `<wa-breadcrumb-item>` by removing the `base` CSS part
|
||||
- Simplified `<wa-menu-item>` and `<wa-menu-label>` by removing the `base` CSS part
|
||||
- Added slots to `checked-icon` and `submenu-icon` in `<wa-menu-item>` so custom icons can be used
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
||||
@@ -5,13 +5,6 @@
|
||||
|
||||
display: block;
|
||||
color: var(--wa-color-text-normal);
|
||||
}
|
||||
|
||||
:host([inert]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
@@ -25,22 +18,26 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:host([disabled]) .menu-item {
|
||||
:host([inert]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host([disabled]) {
|
||||
outline: none;
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.menu-item.menu-item--loading {
|
||||
:host([loading]) {
|
||||
outline: none;
|
||||
cursor: wait;
|
||||
}
|
||||
|
||||
.menu-item.menu-item--loading *:not(wa-spinner) {
|
||||
:host([loading]) *:not(wa-spinner) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.menu-item--loading wa-spinner {
|
||||
:host([loading]) wa-spinner {
|
||||
--indicator-color: currentColor;
|
||||
--track-width: 0.0625rem;
|
||||
position: absolute;
|
||||
@@ -50,35 +47,35 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.menu-item .label {
|
||||
.label {
|
||||
flex: 1 1 auto;
|
||||
display: inline-block;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.menu-item .prefix {
|
||||
.prefix {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.menu-item .prefix::slotted(*) {
|
||||
.prefix::slotted(*) {
|
||||
margin-inline-end: var(--wa-space-xs);
|
||||
}
|
||||
|
||||
.menu-item .suffix {
|
||||
.suffix {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.menu-item .suffix::slotted(*) {
|
||||
.suffix::slotted(*) {
|
||||
margin-inline-start: var(--wa-space-xs);
|
||||
}
|
||||
|
||||
/* Safe triangle */
|
||||
.menu-item--submenu-expanded::after {
|
||||
:host(:state(submenu-expanded))::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
z-index: 899;
|
||||
@@ -97,13 +94,13 @@
|
||||
outline: none;
|
||||
}
|
||||
|
||||
:host(:hover:not([aria-disabled='true'], :focus-visible)) .menu-item,
|
||||
.menu-item--submenu-expanded {
|
||||
:host(:hover:not([aria-disabled='true'], :focus-visible)),
|
||||
:host(:state(submenu-expanded)) {
|
||||
background-color: var(--background-color-hover);
|
||||
color: var(--text-color-hover);
|
||||
}
|
||||
|
||||
:host(:focus-visible) .menu-item {
|
||||
:host(:focus-visible) {
|
||||
outline: var(--wa-focus-ring);
|
||||
outline-offset: calc(-1 * var(--wa-focus-ring-width));
|
||||
background: var(--background-color-hover);
|
||||
@@ -111,8 +108,8 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.menu-item .check,
|
||||
.menu-item .chevron {
|
||||
.check,
|
||||
.chevron {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -122,8 +119,8 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.menu-item--checked .check,
|
||||
.menu-item--has-submenu .chevron {
|
||||
:host([checked]) .check,
|
||||
:host(:state(has-submenu)) .chevron {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@@ -139,8 +136,8 @@ wa-popup:dir(rtl)::part(popup) {
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
:host(:hover:not([aria-disabled='true'])) .menu-item,
|
||||
:host(:focus-visible) .menu-item {
|
||||
:host(:hover:not([aria-disabled='true'])),
|
||||
:host(:focus-visible) {
|
||||
outline: dashed 1px SelectedItem;
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { PropertyValues } from 'lit';
|
||||
import { html } from 'lit';
|
||||
import { customElement, property, query, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import getText from '../../internal/get-text.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import { LocalizeController } from '../../utilities/localize.js';
|
||||
@@ -24,8 +23,9 @@ import { SubmenuController } from './submenu-controller.js';
|
||||
* @slot prefix - Used to prepend an icon or similar element to the menu item.
|
||||
* @slot suffix - Used to append an icon or similar element to the menu item.
|
||||
* @slot submenu - Used to denote a nested menu.
|
||||
* @slot checked-icon - The icon used to indicate that this menu item is checked. Usually a `<wa-icon>`.
|
||||
* @slot submenu-icon - The icon used to indicate that this menu item has a submenu. Usually a `<wa-icon>`.
|
||||
*
|
||||
* @csspart base - The component's base wrapper.
|
||||
* @csspart checked-icon - The checked icon, which is only visible when the menu item is checked.
|
||||
* @csspart prefix - The prefix container.
|
||||
* @csspart label - The menu item label.
|
||||
@@ -37,6 +37,9 @@ import { SubmenuController } from './submenu-controller.js';
|
||||
* @cssproperty --background-color-hover - The menu item's background color on hover.
|
||||
* @cssproperty --text-color-hover - The label color on hover.
|
||||
* @cssproperty [--submenu-offset=-2px] - The distance submenus shift to overlap the parent menu.
|
||||
*
|
||||
* @cssstate has-submenu - Applied when the menu item has a submenu.
|
||||
* @cssstate submenu-expanded - Applied when the menu item has a submenu and it is expanded.
|
||||
*/
|
||||
@customElement('wa-menu-item')
|
||||
export default class WaMenuItem extends WebAwesomeElement {
|
||||
@@ -129,6 +132,8 @@ export default class WaMenuItem extends WebAwesomeElement {
|
||||
/** @internal - prevent the CEM from recording this event */
|
||||
this.dispatchEvent(new Event('slotchange', { bubbles: true, composed: false, cancelable: false }));
|
||||
}
|
||||
|
||||
this.toggleCustomState('has-submenu', this.isSubmenu());
|
||||
}
|
||||
|
||||
private handleHostClick = (event: MouseEvent) => {
|
||||
@@ -188,49 +193,40 @@ export default class WaMenuItem extends WebAwesomeElement {
|
||||
return changed;
|
||||
}
|
||||
|
||||
isSubmenu() {
|
||||
/** Does this element have a submenu? */
|
||||
private isSubmenu() {
|
||||
return this.hasUpdated ? this.querySelector(`:scope > [slot="submenu"]`) !== null : this.withSubmenu;
|
||||
}
|
||||
|
||||
render() {
|
||||
const isRtl = this.hasUpdated ? this.localize.dir() === 'rtl' : this.dir === 'rtl';
|
||||
const isSubmenuExpanded = this.submenuController.isExpanded();
|
||||
this.toggleCustomState('submenu-expanded', isSubmenuExpanded);
|
||||
|
||||
this.internals.ariaHasPopup = this.isSubmenu() + '';
|
||||
this.internals.ariaExpanded = isSubmenuExpanded + '';
|
||||
|
||||
return html`
|
||||
<div
|
||||
id="anchor"
|
||||
part="base"
|
||||
class=${classMap({
|
||||
'menu-item': true,
|
||||
'menu-item--checked': this.checked,
|
||||
'menu-item--loading': this.loading,
|
||||
'menu-item--has-submenu': this.isSubmenu(),
|
||||
'menu-item--submenu-expanded': isSubmenuExpanded,
|
||||
})}
|
||||
?aria-haspopup="${this.isSubmenu()}"
|
||||
?aria-expanded="${isSubmenuExpanded ? true : false}"
|
||||
>
|
||||
<span part="checked-icon" class="check">
|
||||
<wa-icon name="check" library="system" variant="solid" aria-hidden="true"></wa-icon>
|
||||
</span>
|
||||
<slot name="checked-icon" part="checked-icon" class="check">
|
||||
<wa-icon name="check" library="system" variant="solid" aria-hidden="true"></wa-icon>
|
||||
</slot>
|
||||
|
||||
<slot name="prefix" part="prefix" class="prefix"></slot>
|
||||
<slot name="prefix" part="prefix" class="prefix"></slot>
|
||||
|
||||
<slot part="label" class="label" @slotchange=${this.handleDefaultSlotChange}></slot>
|
||||
<slot part="label" class="label" @slotchange=${this.handleDefaultSlotChange}></slot>
|
||||
|
||||
<slot name="suffix" part="suffix" class="suffix"></slot>
|
||||
<slot name="suffix" part="suffix" class="suffix"></slot>
|
||||
|
||||
<span part="submenu-icon" class="chevron">
|
||||
<wa-icon
|
||||
name=${isRtl ? 'chevron-left' : 'chevron-right'}
|
||||
library="system"
|
||||
variant="solid"
|
||||
aria-hidden="true"
|
||||
></wa-icon>
|
||||
</span>
|
||||
<slot name="submenu-icon" part="submenu-icon" class="chevron">
|
||||
<wa-icon
|
||||
name=${isRtl ? 'chevron-left' : 'chevron-right'}
|
||||
library="system"
|
||||
variant="solid"
|
||||
aria-hidden="true"
|
||||
></wa-icon>
|
||||
</slot>
|
||||
|
||||
${this.submenuController.renderSubmenu()} ${this.loading ? html`<wa-spinner part="spinner"></wa-spinner>` : ''}
|
||||
</div>
|
||||
${this.submenuController.renderSubmenu()} ${this.loading ? html`<wa-spinner part="spinner"></wa-spinner>` : ''}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ export class SubmenuController implements ReactiveController {
|
||||
<wa-popup
|
||||
${ref(this.popupRef)}
|
||||
placement=${isRtl ? 'left-start' : 'right-start'}
|
||||
anchor="anchor"
|
||||
.anchor="${this.host}"
|
||||
flip
|
||||
flip-fallback-strategy="best-fit"
|
||||
skidding="${this.skidding}"
|
||||
|
||||
@@ -3,12 +3,7 @@
|
||||
color: var(--wa-color-text-quiet);
|
||||
font-size: var(--wa-font-size-s);
|
||||
font-weight: var(--wa-font-weight-semibold);
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
display: inline-block;
|
||||
font: inherit;
|
||||
padding: var(--wa-space-2xs) calc(var(--wa-space-2xs) + var(--wa-space-xl));
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -10,15 +10,13 @@ import styles from './menu-label.css';
|
||||
* @since 2.0
|
||||
*
|
||||
* @slot - The menu label's content.
|
||||
*
|
||||
* @csspart base - The component's base wrapper.
|
||||
*/
|
||||
@customElement('wa-menu-label')
|
||||
export default class WaMenuLabel extends WebAwesomeElement {
|
||||
static shadowStyle = styles;
|
||||
|
||||
render() {
|
||||
return html` <slot part="base" class="menu-label"></slot> `;
|
||||
return html`<slot></slot>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user