1
1
import { LitElement , css , html } from 'lit' ;
2
2
import { defineElement } from '@umbraco-ui/uui-base/lib/registration' ;
3
3
import { property , state } from 'lit/decorators.js' ;
4
+ import { ifDefined } from 'lit/directives/if-defined.js' ;
4
5
import {
5
6
ActiveMixin ,
6
7
LabelMixin ,
7
8
SelectableMixin ,
9
+ SelectOnlyMixin ,
8
10
} from '@umbraco-ui/uui-base/lib/mixins' ;
9
11
import { UUIMenuItemEvent } from './UUIMenuItemEvent' ;
10
12
@@ -21,8 +23,8 @@ import { UUIMenuItemEvent } from './UUIMenuItemEvent';
21
23
*
22
24
*/
23
25
@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 ) ) )
26
28
) {
27
29
static styles = [
28
30
css `
@@ -31,6 +33,8 @@ export class UUIMenuItemElement extends SelectableMixin(
31
33
background-color: var(--uui-interface-surface);
32
34
/** consider transparent. */
33
35
--uui-menu-item-child-indent: calc(var(--uui-menu-item-indent, 0) + 1);
36
+
37
+ user-select: none;
34
38
}
35
39
36
40
#menu-item {
@@ -46,19 +50,20 @@ export class UUIMenuItemElement extends SelectableMixin(
46
50
}
47
51
48
52
button {
49
- display: block;
53
+ display: inline-flex;
54
+ align-items: center;
55
+
50
56
font-family: inherit;
57
+ font-size: inherit;
51
58
52
59
padding: 0;
53
60
text-align: left;
54
- box-shadow: none;
55
61
border: none;
56
62
color: inherit;
57
63
background-color: transparent;
58
64
cursor: pointer;
59
- z-index: 1;
60
- /* padding: 0 var(--uui-size-base-unit) 0 var(--uui-size-base-unit); */
61
65
min-height: var(--uui-size-12);
66
+ z-index: 1;
62
67
}
63
68
/* button:hover {
64
69
color: var(--uui-interface-contrast-hover);
@@ -70,6 +75,16 @@ export class UUIMenuItemElement extends SelectableMixin(
70
75
white-space: nowrap;
71
76
overflow: hidden;
72
77
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. */
73
88
}
74
89
75
90
#caret-button + #label-button {
@@ -101,9 +116,6 @@ export class UUIMenuItemElement extends SelectableMixin(
101
116
transition: opacity 120ms;
102
117
grid-column-start: 3;
103
118
}
104
- #menu-item:hover #actions-container {
105
- opacity: 1;
106
- }
107
119
108
120
#loader {
109
121
position: absolute;
@@ -112,13 +124,12 @@ export class UUIMenuItemElement extends SelectableMixin(
112
124
}
113
125
114
126
#icon {
127
+ display: inline-flex;
115
128
font-size: 16px;
116
- margin-bottom: var(--uui-size-1);
117
129
margin-right: var(--uui-size-2);
118
- display: inline-block;
119
130
}
120
131
121
- :host([disabled]) #label-button {
132
+ :host([disabled]) {
122
133
color: var(--uui-interface-surface-contrast-disabled);
123
134
}
124
135
:host([disabled]) #label-button-background {
@@ -128,10 +139,10 @@ export class UUIMenuItemElement extends SelectableMixin(
128
139
background-color: var(--uui-interface-surface-disabled);
129
140
}
130
141
131
- :host([active]) button {
142
+ :host([active]) {
132
143
color: var(--uui-interface-active-contrast);
133
144
}
134
- :host([active]) button:hover {
145
+ :host([active]) #label- button:hover {
135
146
color: var(--uui-interface-active-contrast-hover);
136
147
}
137
148
:host([active]) #label-button-background {
@@ -145,10 +156,10 @@ export class UUIMenuItemElement extends SelectableMixin(
145
156
background-color: var(--uui-interface-active-disabled);
146
157
}
147
158
148
- :host([selected]) button {
159
+ :host([selected]) {
149
160
color: var(--uui-interface-select-contrast);
150
161
}
151
- :host([selected]) button:hover {
162
+ :host([selected]) #label- button:hover {
152
163
color: var(--uui-interface-select-contrast-hover);
153
164
}
154
165
:host([selected]) #label-button-background {
@@ -218,6 +229,37 @@ export class UUIMenuItemElement extends SelectableMixin(
218
229
@property ( { type : Boolean , attribute : 'loading' } )
219
230
public loading = false ;
220
231
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
+ connectedCallback ( ) {
254
+ super . connectedCallback ( ) ;
255
+ if ( ! this . hasAttribute ( 'role' ) ) this . setAttribute ( 'role' , 'menu' ) ;
256
+ }
257
+
258
+ private iconSlotChanged ( e : any ) : void {
259
+ this . iconSlotHasContent =
260
+ ( e . target as HTMLSlotElement ) . assignedNodes ( { flatten : true } ) . length > 0 ;
261
+ }
262
+
221
263
private onCaretClicked ( ) {
222
264
this . showChildren = ! this . showChildren ;
223
265
const eventName : string = this . showChildren
@@ -232,12 +274,41 @@ export class UUIMenuItemElement extends SelectableMixin(
232
274
this . dispatchEvent ( event ) ;
233
275
}
234
276
235
- @state ( )
236
- private iconSlotHasContent = false ;
277
+ private _renderLabelInside ( ) {
278
+ return html ` < slot
279
+ name ="icon "
280
+ id ="icon "
281
+ style =${ this . iconSlotHasContent ? '' : 'display: none;' }
282
+ @slotchange =${ this . iconSlotChanged } > </ slot >
283
+ ${ this . renderLabel ( ) } ` ;
284
+ }
237
285
238
- private iconSlotChanged ( e : any ) : void {
239
- this . iconSlotHasContent =
240
- ( e . target as HTMLSlotElement ) . assignedNodes ( { flatten : true } ) . length > 0 ;
286
+ private _renderLabelAsAnchor ( ) {
287
+ if ( this . disabled ) {
288
+ return html ` < span id ="label-button ">
289
+ ${ this . _renderLabelInside ( ) }
290
+ </ span > ` ;
291
+ }
292
+ return html ` < a
293
+ id ="label-button "
294
+ href =${ this . href }
295
+ target =${ ifDefined ( this . target || undefined ) }
296
+ rel=${ ifDefined ( this . target === '_blank' ? 'noopener' : undefined ) }
297
+ @click=${ this . onLabelClicked }
298
+ ?disabled=${ this . disabled }
299
+ aria-label="${ this . label } ">
300
+ ${ this . _renderLabelInside ( ) }
301
+ </ a > ` ;
302
+ }
303
+
304
+ private _renderLabelAsButton ( ) {
305
+ return html ` < button
306
+ id ="label-button "
307
+ @click =${ this . onLabelClicked }
308
+ ?disabled =${ this . disabled }
309
+ aria-label="${ this . label } ">
310
+ ${ this . _renderLabelInside ( ) }
311
+ </ button > ` ;
241
312
}
242
313
243
314
render ( ) {
@@ -248,20 +319,12 @@ export class UUIMenuItemElement extends SelectableMixin(
248
319
< uui-symbol-expand ?open =${ this . showChildren } > </ uui-symbol-expand >
249
320
</ button > `
250
321
: '' }
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 >
322
+ ${ this . href ? this . _renderLabelAsAnchor ( ) : this . _renderLabelAsButton ( ) }
323
+
263
324
< div id ="label-button-background "> </ div >
264
- < slot id ="actions-container " name ="actions "> </ slot >
325
+ ${ this . selectOnly === false
326
+ ? html `< slot id ="actions-container " name ="actions "> </ slot > `
327
+ : '' }
265
328
${ this . loading
266
329
? html `< uui-loader-bar id ="loader "> </ uui-loader-bar > `
267
330
: '' }
0 commit comments