Skip to content

Commit 739ea60

Browse files
committed
support href and render a anchor tag
1 parent 7f5a2ac commit 739ea60

File tree

4 files changed

+231
-47
lines changed

4 files changed

+231
-47
lines changed

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/uui-menu-item/lib/uui-menu-item.element.ts

Lines changed: 92 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { LitElement, css, html } from 'lit';
22
import { defineElement } from '@umbraco-ui/uui-base/lib/registration';
33
import { property, state } from 'lit/decorators.js';
4+
import { ifDefined } from 'lit/directives/if-defined.js';
45
import {
56
ActiveMixin,
67
LabelMixin,
78
SelectableMixin,
9+
SelectOnlyMixin,
810
} from '@umbraco-ui/uui-base/lib/mixins';
911
import { UUIMenuItemEvent } from './UUIMenuItemEvent';
1012

@@ -21,8 +23,8 @@ import { UUIMenuItemEvent } from './UUIMenuItemEvent';
2123
*
2224
*/
2325
@defineElement('uui-menu-item')
24-
export class UUIMenuItemElement extends SelectableMixin(
25-
ActiveMixin(LabelMixin('label', LitElement))
26+
export class UUIMenuItemElement extends SelectOnlyMixin(
27+
SelectableMixin(ActiveMixin(LabelMixin('label', LitElement)))
2628
) {
2729
static styles = [
2830
css`
@@ -31,6 +33,8 @@ export class UUIMenuItemElement extends SelectableMixin(
3133
background-color: var(--uui-interface-surface);
3234
/** consider transparent. */
3335
--uui-menu-item-child-indent: calc(var(--uui-menu-item-indent, 0) + 1);
36+
37+
user-select: none;
3438
}
3539
3640
#menu-item {
@@ -46,19 +50,20 @@ export class UUIMenuItemElement extends SelectableMixin(
4650
}
4751
4852
button {
49-
display: block;
53+
display: inline-flex;
54+
align-items: center;
55+
5056
font-family: inherit;
57+
font-size: inherit;
5158
5259
padding: 0;
5360
text-align: left;
54-
box-shadow: none;
5561
border: none;
5662
color: inherit;
5763
background-color: transparent;
5864
cursor: pointer;
59-
z-index: 1;
60-
/* padding: 0 var(--uui-size-base-unit) 0 var(--uui-size-base-unit); */
6165
min-height: var(--uui-size-12);
66+
z-index: 1;
6267
}
6368
/* button:hover {
6469
color: var(--uui-interface-contrast-hover);
@@ -70,6 +75,16 @@ export class UUIMenuItemElement extends SelectableMixin(
7075
white-space: nowrap;
7176
overflow: hidden;
7277
text-overflow: ellipsis;
78+
79+
display: inline-flex;
80+
align-items: center;
81+
text-decoration: none;
82+
color: currentColor;
83+
min-height: var(--uui-size-12);
84+
z-index: 1;
85+
}
86+
span#label-button {
87+
pointer-events: none; /* avoid hovering state on this. */
7388
}
7489
7590
#caret-button + #label-button {
@@ -101,9 +116,6 @@ export class UUIMenuItemElement extends SelectableMixin(
101116
transition: opacity 120ms;
102117
grid-column-start: 3;
103118
}
104-
#menu-item:hover #actions-container {
105-
opacity: 1;
106-
}
107119
108120
#loader {
109121
position: absolute;
@@ -112,13 +124,12 @@ export class UUIMenuItemElement extends SelectableMixin(
112124
}
113125
114126
#icon {
127+
display: inline-flex;
115128
font-size: 16px;
116-
margin-bottom: var(--uui-size-1);
117129
margin-right: var(--uui-size-2);
118-
display: inline-block;
119130
}
120131
121-
:host([disabled]) #label-button {
132+
:host([disabled]) {
122133
color: var(--uui-interface-surface-contrast-disabled);
123134
}
124135
:host([disabled]) #label-button-background {
@@ -128,10 +139,10 @@ export class UUIMenuItemElement extends SelectableMixin(
128139
background-color: var(--uui-interface-surface-disabled);
129140
}
130141
131-
:host([active]) button {
142+
:host([active]) {
132143
color: var(--uui-interface-active-contrast);
133144
}
134-
:host([active]) button:hover {
145+
:host([active]) #label-button:hover {
135146
color: var(--uui-interface-active-contrast-hover);
136147
}
137148
:host([active]) #label-button-background {
@@ -145,10 +156,10 @@ export class UUIMenuItemElement extends SelectableMixin(
145156
background-color: var(--uui-interface-active-disabled);
146157
}
147158
148-
:host([selected]) button {
159+
:host([selected]) {
149160
color: var(--uui-interface-select-contrast);
150161
}
151-
:host([selected]) button:hover {
162+
:host([selected]) #label-button:hover {
152163
color: var(--uui-interface-select-contrast-hover);
153164
}
154165
:host([selected]) #label-button-background {
@@ -218,6 +229,32 @@ export class UUIMenuItemElement extends SelectableMixin(
218229
@property({ type: Boolean, attribute: 'loading' })
219230
public loading = false;
220231

232+
/**
233+
* Set an href, this will turns the label into a anchor tag.
234+
* @type {string}
235+
* @attr
236+
* @default undefined
237+
*/
238+
@property({ type: String })
239+
public href?: string;
240+
241+
/**
242+
* Set an anchor tag target, only used when using href.
243+
* @type {string}
244+
* @attr
245+
* @default undefined
246+
*/
247+
@property({ type: String })
248+
public target?: '_blank' | '_parent' | '_self' | '_top';
249+
250+
@state()
251+
private iconSlotHasContent = false;
252+
253+
private iconSlotChanged(e: any): void {
254+
this.iconSlotHasContent =
255+
(e.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0;
256+
}
257+
221258
private onCaretClicked() {
222259
this.showChildren = !this.showChildren;
223260
const eventName: string = this.showChildren
@@ -232,12 +269,41 @@ export class UUIMenuItemElement extends SelectableMixin(
232269
this.dispatchEvent(event);
233270
}
234271

235-
@state()
236-
private iconSlotHasContent = false;
272+
private _renderLabelInside() {
273+
return html` <slot
274+
name="icon"
275+
id="icon"
276+
style=${this.iconSlotHasContent ? '' : 'display: none;'}
277+
@slotchange=${this.iconSlotChanged}></slot>
278+
${this.renderLabel()}`;
279+
}
237280

238-
private iconSlotChanged(e: any): void {
239-
this.iconSlotHasContent =
240-
(e.target as HTMLSlotElement).assignedNodes({ flatten: true }).length > 0;
281+
private _renderLabelAsAnchor() {
282+
if (this.disabled) {
283+
return html` <span id="label-button">
284+
${this._renderLabelInside()}
285+
</span>`;
286+
}
287+
return html` <a
288+
id="label-button"
289+
href=${this.href}
290+
target=${ifDefined(this.target || undefined)}
291+
rel=${ifDefined(this.target === '_blank' ? 'noopener' : undefined)}
292+
@click=${this.onLabelClicked}
293+
?disabled=${this.disabled}
294+
aria-label="${this.label}">
295+
${this._renderLabelInside()}
296+
</a>`;
297+
}
298+
299+
private _renderLabelAsButton() {
300+
return html` <button
301+
id="label-button"
302+
@click=${this.onLabelClicked}
303+
?disabled=${this.disabled}
304+
aria-label="${this.label}">
305+
${this._renderLabelInside()}
306+
</button>`;
241307
}
242308

243309
render() {
@@ -248,20 +314,12 @@ export class UUIMenuItemElement extends SelectableMixin(
248314
<uui-symbol-expand ?open=${this.showChildren}></uui-symbol-expand>
249315
</button>`
250316
: ''}
251-
<button
252-
id="label-button"
253-
@click=${this.onLabelClicked}
254-
?disabled=${this.disabled}
255-
aria-label="${this.label}">
256-
<slot
257-
name="icon"
258-
id="icon"
259-
style=${this.iconSlotHasContent ? '' : 'display: none;'}
260-
@slotchange=${this.iconSlotChanged}></slot>
261-
${this.renderLabel()}
262-
</button>
317+
${this.href ? this._renderLabelAsAnchor() : this._renderLabelAsButton()}
318+
263319
<div id="label-button-background"></div>
264-
<slot id="actions-container" name="actions"></slot>
320+
${this.selectOnly === false
321+
? html`<slot id="actions-container" name="actions"></slot>`
322+
: ''}
265323
${this.loading
266324
? html`<uui-loader-bar id="loader"></uui-loader-bar>`
267325
: ''}

0 commit comments

Comments
 (0)