Skip to content

Commit

Permalink
fix(action-menu): stack a "label-only" slot on top of the others to a…
Browse files Browse the repository at this point in the history
…llow no icon menu buttons
  • Loading branch information
Westbrook committed Sep 7, 2023
1 parent 515eaee commit 6b5817d
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 4 deletions.
30 changes: 30 additions & 0 deletions packages/action-menu/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,36 @@ import { ActionMenu } from '@spectrum-web-components/action-menu';

## Variants

### No icon

In order to deliver an `<sp-action-menu>` without an icon, use the `label-only` slot. This will supress any icon from being displayed, both the default ellipsis icon or any icon the user might provide to the element.

<!-- prettier-ignore -->
```html
<sp-action-menu>
<span slot="label-only">More Actions</span>
<sp-menu-item>
Deselect
</sp-menu-item>
<sp-menu-item>
Select inverse
</sp-menu-item>
<sp-menu-item>
Feather...
</sp-menu-item>
<sp-menu-item>
Select and mask...
</sp-menu-item>
<sp-menu-divider></sp-menu-divider>
<sp-menu-item>
Save selection
</sp-menu-item>
<sp-menu-item disabled>
Make work path
</sp-menu-item>
</sp-action-menu>
```

### No visible label

The visible label that is be provided via the default `<slot>` interface can be ommitted in preference of an icon only interface. In this context be sure that the `<sp-action-menu>` continued to be accessible to screen readers by applying the `label` attribute. This will apply an `aria-label` attribute of the same value to the `<button>` element that toggles the menu list.
Expand Down
28 changes: 24 additions & 4 deletions packages/action-menu/src/ActionMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ import {
PropertyValues,
TemplateResult,
} from '@spectrum-web-components/base';
import { state } from '@spectrum-web-components/base/src/decorators.js';
import { ifDefined } from '@spectrum-web-components/base/src/directives.js';
import { property } from '@spectrum-web-components/base/src/decorators.js';
import { PickerBase } from '@spectrum-web-components/picker';
import '@spectrum-web-components/action-button/sp-action-button.js';
import { ObserveSlotPresence } from '@spectrum-web-components/shared/src/observe-slot-presence.js';
import { ObserveSlotText } from '@spectrum-web-components/shared/src/observe-slot-text.js';
import '@spectrum-web-components/icons-workflow/icons/sp-icon-more.js';
import actionMenuStyles from './action-menu.css.js';
Expand All @@ -35,7 +37,10 @@ import actionMenuStyles from './action-menu.css.js';
* you'd like for a selection to be held by the `sp-menu` that it presents in
* its overlay, use `selects="single" to activate this functionality.
*/
export class ActionMenu extends ObserveSlotText(PickerBase, 'label') {
export class ActionMenu extends ObserveSlotPresence(
ObserveSlotText(PickerBase, 'label'),
'[slot="label-only"]'
) {
public static override get styles(): CSSResultArray {
return [actionMenuStyles];
}
Expand All @@ -52,13 +57,28 @@ export class ActionMenu extends ObserveSlotText(PickerBase, 'label') {
return this.slotHasContent;
}

@state()
private get labelOnly(): boolean {
return this.slotContentIsPresent;
}

protected override get buttonContent(): TemplateResult[] {
return [
html`
<slot name="icon" slot="icon" ?icon-only=${!this.hasLabel}>
<sp-icon-more class="icon"></sp-icon-more>
</slot>
${this.labelOnly
? html``
: html`
<slot
name="icon"
slot="icon"
?icon-only=${!this.hasLabel}
?hidden=${this.labelOnly}
>
<sp-icon-more class="icon"></sp-icon-more>
</slot>
`}
<slot name="label" ?hidden=${!this.hasLabel}></slot>
<slot name="label-only"></slot>
<slot name="tooltip"></slot>
`,
];
Expand Down
27 changes: 27 additions & 0 deletions packages/action-menu/stories/action-menu.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,33 @@ quiet.args = {
quiet: true,
};

export const labelOnly = ({
changeHandler = (() => undefined) as (event: Event) => void,
disabled = false,
open = false,
size = 'm' as 'm' | 's' | 'l' | 'xl' | 'xxl',
selects = '' as 'single',
selected = false,
} = {}): TemplateResult => html`
<sp-action-menu
?disabled=${disabled}
?open=${open}
size=${size}
@change="${changeHandler}"
.selects=${selects ? selects : undefined}
value=${selected ? 'Select Inverse' : ''}
>
<span slot="label-only">Label Only</span>
<sp-menu-item>Deselect</sp-menu-item>
<sp-menu-item ?selected=${selected}>Select Inverse</sp-menu-item>
<sp-menu-item>Feather...</sp-menu-item>
<sp-menu-item>Select and Mask...</sp-menu-item>
<sp-menu-divider></sp-menu-divider>
<sp-menu-item>Save Selection</sp-menu-item>
<sp-menu-item disabled>Make Work Path</sp-menu-item>
</sp-action-menu>
`;

export const selects = (args: StoryArgs = {}): TemplateResult =>
Template({
...args,
Expand Down

0 comments on commit 6b5817d

Please sign in to comment.