@redvars/peacock 3.6.2 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/dist/ButtonConstants-D06bY4uy.js +114 -0
  2. package/dist/ButtonConstants-D06bY4uy.js.map +1 -0
  3. package/dist/{BaseHyperlinkMixin-BNuwbiEf.js → NativeHyperlinkMixin-DrYXyfMQ.js} +8 -10
  4. package/dist/NativeHyperlinkMixin-DrYXyfMQ.js.map +1 -0
  5. package/dist/assets/components.css +1 -1
  6. package/dist/assets/components.css.map +1 -1
  7. package/dist/assets/styles.css +1 -1
  8. package/dist/assets/styles.css.map +1 -1
  9. package/dist/button-colors-Dwnez1tR.js +586 -0
  10. package/dist/button-colors-Dwnez1tR.js.map +1 -0
  11. package/dist/button-group.js +8 -8
  12. package/dist/button-group.js.map +1 -1
  13. package/dist/button.js +236 -133
  14. package/dist/button.js.map +1 -1
  15. package/dist/calendar-column-view.js +0 -1
  16. package/dist/calendar-column-view.js.map +1 -1
  17. package/dist/calendar-month-view.js +0 -1
  18. package/dist/calendar-month-view.js.map +1 -1
  19. package/dist/canvas.js +126 -107
  20. package/dist/canvas.js.map +1 -1
  21. package/dist/card-content.js +0 -1
  22. package/dist/card-content.js.map +1 -1
  23. package/dist/card.js +96 -90
  24. package/dist/card.js.map +1 -1
  25. package/dist/cb-compound-expression.js +4 -1
  26. package/dist/cb-compound-expression.js.map +1 -1
  27. package/dist/cb-divider.js +0 -1
  28. package/dist/cb-divider.js.map +1 -1
  29. package/dist/cb-expression.js +0 -2
  30. package/dist/cb-expression.js.map +1 -1
  31. package/dist/cb-predicate.js +0 -1
  32. package/dist/cb-predicate.js.map +1 -1
  33. package/dist/code-highlighter.js +23 -6
  34. package/dist/code-highlighter.js.map +1 -1
  35. package/dist/custom-elements-jsdocs.json +5079 -17882
  36. package/dist/custom-elements.json +19272 -19314
  37. package/dist/fab.js +181 -117
  38. package/dist/fab.js.map +1 -1
  39. package/dist/flow-designer.js +4 -4
  40. package/dist/icon-button-DJ0kZXYr.js +318 -0
  41. package/dist/icon-button-DJ0kZXYr.js.map +1 -0
  42. package/dist/index.js +7 -7
  43. package/dist/{navigation-rail-CD7IrqbN.js → navigation-rail-CM_svs5_.js} +1311 -730
  44. package/dist/navigation-rail-CM_svs5_.js.map +1 -0
  45. package/dist/observe-slot-change-D8Xg-kSS.js +60 -0
  46. package/dist/observe-slot-change-D8Xg-kSS.js.map +1 -0
  47. package/dist/peacock-loader.js +10 -7
  48. package/dist/peacock-loader.js.map +1 -1
  49. package/dist/popover-content.js +0 -1
  50. package/dist/popover-content.js.map +1 -1
  51. package/dist/search.js +15 -15
  52. package/dist/search.js.map +1 -1
  53. package/dist/src/__controllers/attachable-controller.d.ts +109 -0
  54. package/dist/src/__mixins/{BaseButtonMixin.d.ts → NativeButtonMixin.d.ts} +3 -3
  55. package/dist/src/__mixins/{BaseHyperlinkMixin.d.ts → NativeHyperlinkMixin.d.ts} +3 -4
  56. package/dist/src/__utils/is-link.d.ts +1 -0
  57. package/dist/src/__utils/observe-slot-change.d.ts +1 -1
  58. package/dist/src/accordion/accordion-item.d.ts +0 -1
  59. package/dist/src/breadcrumb/breadcrumb-item/breadcrumb-item.d.ts +0 -1
  60. package/dist/src/button/ButtonConstants.d.ts +1 -0
  61. package/dist/src/button/GroupButtonInterface.d.ts +4 -0
  62. package/dist/src/button/button/button.d.ts +32 -7
  63. package/dist/src/button/button-group/button-group.d.ts +2 -1
  64. package/dist/src/button/icon-button/icon-button.d.ts +26 -5
  65. package/dist/src/button/index.d.ts +1 -1
  66. package/dist/src/calendar/calendar-column-view.d.ts +0 -1
  67. package/dist/src/calendar/calendar-month-view.d.ts +0 -1
  68. package/dist/src/canvas/canvas.d.ts +3 -3
  69. package/dist/src/card/card-content.d.ts +0 -1
  70. package/dist/src/card/card.d.ts +9 -6
  71. package/dist/src/chip/chip/chip.d.ts +22 -3
  72. package/dist/src/condition-builder/cb-compound-expression.d.ts +0 -1
  73. package/dist/src/condition-builder/cb-divider.d.ts +0 -1
  74. package/dist/src/condition-builder/cb-expression.d.ts +0 -1
  75. package/dist/src/condition-builder/cb-predicate.d.ts +0 -1
  76. package/dist/src/fab/fab.d.ts +20 -6
  77. package/dist/src/field/field.d.ts +1 -0
  78. package/dist/src/focus-ring/focus-ring.d.ts +26 -20
  79. package/dist/src/image/image.d.ts +2 -2
  80. package/dist/src/index.d.ts +1 -0
  81. package/dist/src/input/input.d.ts +1 -3
  82. package/dist/src/item/index.d.ts +1 -0
  83. package/dist/src/item/item.d.ts +49 -0
  84. package/dist/src/link/link.d.ts +1 -1
  85. package/dist/src/list/list-item.d.ts +1 -2
  86. package/dist/src/menu/menu-item/menu-item.d.ts +9 -11
  87. package/dist/src/menu/sub-menu/sub-menu.d.ts +1 -1
  88. package/dist/src/navigation-rail/navigation-rail-item.d.ts +0 -2
  89. package/dist/src/navigation-rail/navigation-rail.d.ts +2 -6
  90. package/dist/src/popover/popover-content.d.ts +0 -1
  91. package/dist/src/ripple/ripple.d.ts +9 -1
  92. package/dist/src/search/search.d.ts +2 -6
  93. package/dist/src/segmented-button/segmented-button.d.ts +0 -1
  94. package/dist/src/select/option.d.ts +0 -1
  95. package/dist/src/sidebar-menu/sidebar-menu-item.d.ts +0 -1
  96. package/dist/src/sidebar-menu/sidebar-sub-menu.d.ts +0 -1
  97. package/dist/src/tabs/tab-panel.d.ts +0 -1
  98. package/dist/src/tabs/tab.d.ts +4 -6
  99. package/dist/test/item.test.d.ts +1 -0
  100. package/dist/tsconfig.tsbuildinfo +1 -1
  101. package/package.json +4 -2
  102. package/readme.md +2 -2
  103. package/scss/components.scss +0 -1
  104. package/scss/mixin.scss +33 -13
  105. package/scss/styles.scss +1 -3
  106. package/src/__controllers/attachable-controller.ts +198 -0
  107. package/src/__mixins/NativeButtonMixin.ts +87 -0
  108. package/src/__mixins/{BaseHyperlinkMixin.ts → NativeHyperlinkMixin.ts} +15 -15
  109. package/src/__utils/is-link.ts +3 -0
  110. package/src/__utils/observe-slot-change.ts +46 -14
  111. package/src/accordion/accordion-item.scss +1 -1
  112. package/src/accordion/accordion-item.ts +0 -1
  113. package/src/breadcrumb/breadcrumb-item/breadcrumb-item.ts +0 -1
  114. package/src/button/ButtonConstants.ts +1 -0
  115. package/src/button/GroupButtonInterface.ts +4 -0
  116. package/src/button/button/button-colors.scss +2 -2
  117. package/src/button/button/button-layers.scss +124 -0
  118. package/src/button/button/button-sizes.scss +31 -53
  119. package/src/button/button/button.scss +139 -262
  120. package/src/button/button/button.ts +260 -106
  121. package/src/button/button/only-button.scss +13 -0
  122. package/src/button/button-group/button-group.ts +59 -17
  123. package/src/button/icon-button/icon-button-sizes.scss +12 -27
  124. package/src/button/icon-button/icon-button.ts +191 -83
  125. package/src/button/index.ts +1 -1
  126. package/src/calendar/calendar-column-view.ts +0 -1
  127. package/src/calendar/calendar-month-view.ts +0 -1
  128. package/src/canvas/canvas.scss +18 -6
  129. package/src/canvas/canvas.ts +125 -103
  130. package/src/card/card-content.ts +2 -3
  131. package/src/card/card.scss +87 -95
  132. package/src/card/card.ts +62 -60
  133. package/src/chip/chip/chip.scss +66 -71
  134. package/src/chip/chip/chip.ts +155 -56
  135. package/src/code-highlighter/code-highlighter.scss +1 -1
  136. package/src/code-highlighter/code-highlighter.ts +20 -5
  137. package/src/condition-builder/cb-compound-expression.scss +4 -0
  138. package/src/condition-builder/cb-compound-expression.ts +0 -1
  139. package/src/condition-builder/cb-divider.ts +0 -1
  140. package/src/condition-builder/cb-expression.scss +0 -1
  141. package/src/condition-builder/cb-expression.ts +0 -1
  142. package/src/condition-builder/cb-predicate.ts +0 -1
  143. package/src/elevation/elevation.scss +5 -1
  144. package/src/empty-state/empty-state.scss +1 -0
  145. package/src/fab/fab-colors.scss +2 -2
  146. package/src/fab/fab-sizes.scss +24 -34
  147. package/src/fab/fab.scss +77 -71
  148. package/src/fab/fab.ts +141 -65
  149. package/src/field/field.ts +6 -0
  150. package/src/focus-ring/focus-ring.ts +81 -72
  151. package/src/image/image.scss +21 -16
  152. package/src/image/image.ts +13 -14
  153. package/src/index.ts +1 -0
  154. package/src/input/input.ts +16 -25
  155. package/src/item/index.ts +1 -0
  156. package/src/item/item.scss +195 -0
  157. package/src/item/item.ts +362 -0
  158. package/src/link/link.scss +1 -10
  159. package/src/link/link.ts +4 -2
  160. package/src/list/list-item.ts +8 -8
  161. package/src/menu/menu/menu.ts +5 -9
  162. package/src/menu/menu-item/menu-item.scss +30 -108
  163. package/src/menu/menu-item/menu-item.ts +102 -133
  164. package/src/menu/sub-menu/sub-menu.ts +6 -3
  165. package/src/navigation-rail/navigation-rail-item.scss +5 -0
  166. package/src/navigation-rail/navigation-rail-item.ts +10 -15
  167. package/src/navigation-rail/navigation-rail.ts +2 -6
  168. package/src/peacock-loader.ts +5 -1
  169. package/src/popover/popover-content.ts +0 -1
  170. package/src/ripple/ripple.ts +52 -20
  171. package/src/search/search.scss +3 -0
  172. package/src/search/search.ts +11 -16
  173. package/src/segmented-button/segmented-button.ts +0 -1
  174. package/src/select/option.ts +1 -2
  175. package/src/select/select.scss +1 -10
  176. package/src/select/select.ts +2 -0
  177. package/src/sidebar-menu/sidebar-menu-item.ts +0 -1
  178. package/src/sidebar-menu/sidebar-sub-menu.ts +0 -1
  179. package/src/skeleton/skeleton.scss +5 -1
  180. package/src/tabs/tab-panel.ts +0 -1
  181. package/src/tabs/tab.ts +60 -70
  182. package/src/text/text.css-component.scss +3 -21
  183. package/src/tooltip/tooltip.scss +5 -8
  184. package/src/tooltip/tooltip.ts +1 -2
  185. package/dist/BaseButton-BNFAYn-S.js +0 -219
  186. package/dist/BaseButton-BNFAYn-S.js.map +0 -1
  187. package/dist/BaseHyperlinkMixin-BNuwbiEf.js.map +0 -1
  188. package/dist/button-colors-AvGh22Zn.js +0 -561
  189. package/dist/button-colors-AvGh22Zn.js.map +0 -1
  190. package/dist/icon-button-ohxHhy4t.js +0 -247
  191. package/dist/icon-button-ohxHhy4t.js.map +0 -1
  192. package/dist/navigation-rail-CD7IrqbN.js.map +0 -1
  193. package/dist/observe-slot-change-BGJfgg2E.js +0 -31
  194. package/dist/observe-slot-change-BGJfgg2E.js.map +0 -1
  195. package/dist/src/button/BaseButton.d.ts +0 -28
  196. package/dist/src/focus-ring/FocusAttachableController.d.ts +0 -8
  197. package/src/__mixins/BaseButtonMixin.ts +0 -83
  198. package/src/button/BaseButton.ts +0 -113
  199. package/src/focus-ring/FocusAttachableController.ts +0 -28
  200. package/src/popover/tooltip.css-component.scss +0 -19
@@ -3,8 +3,9 @@ import { property, query, state } from 'lit/decorators.js';
3
3
  import { classMap } from 'lit/directives/class-map.js';
4
4
  import { ifDefined } from 'lit/directives/if-defined.js';
5
5
  import styles from './list-item.scss';
6
- import BaseButtonMixin from '@/__mixins/BaseButtonMixin.js';
7
- import BaseHyperlinkMixin from '@/__mixins/BaseHyperlinkMixin.js';
6
+ import NativeButtonMixin from '@/__mixins/NativeButtonMixin.js';
7
+ import NativeHyperlinkMixin from '@/__mixins/NativeHyperlinkMixin.js';
8
+ import { isLink } from '@/__utils/is-link.js';
8
9
  import {
9
10
  dispatchActivationClick,
10
11
  isActivationClick,
@@ -14,7 +15,6 @@ import {
14
15
  * @label List Item
15
16
  * @tag wc-list-item
16
17
  * @rawTag list-item
17
- * @parentRawTag list
18
18
  *
19
19
  * @summary A Material 3 list item with leading, trailing and content slots.
20
20
  *
@@ -28,7 +28,9 @@ import {
28
28
  * ```
29
29
  * @tags display
30
30
  */
31
- export class ListItem extends BaseButtonMixin(BaseHyperlinkMixin(LitElement)) {
31
+ export class ListItem extends NativeButtonMixin(
32
+ NativeHyperlinkMixin(LitElement),
33
+ ) {
32
34
  static styles = [styles];
33
35
 
34
36
  @property({ type: Boolean, reflect: true }) selected = false;
@@ -82,7 +84,7 @@ export class ListItem extends BaseButtonMixin(BaseHyperlinkMixin(LitElement)) {
82
84
  return;
83
85
  }
84
86
 
85
- if (event.key === 'Enter' && !this.__isLink()) {
87
+ if (event.key === 'Enter' && !isLink(this)) {
86
88
  event.preventDefault();
87
89
  this.itemElement.click();
88
90
  }
@@ -105,8 +107,6 @@ export class ListItem extends BaseButtonMixin(BaseHyperlinkMixin(LitElement)) {
105
107
  };
106
108
 
107
109
  render() {
108
- const isLink = this.__isLink();
109
-
110
110
  const cssClasses = {
111
111
  'list-item': true,
112
112
  'item-element': true,
@@ -115,7 +115,7 @@ export class ListItem extends BaseButtonMixin(BaseHyperlinkMixin(LitElement)) {
115
115
  pressed: this.isPressed,
116
116
  };
117
117
 
118
- if (!isLink) {
118
+ if (!isLink(this)) {
119
119
  return html`
120
120
  <button
121
121
  id="item"
@@ -235,9 +235,7 @@ export class Menu extends LitElement {
235
235
  private _isEventFromThisMenu(event: Event) {
236
236
  const path = event.composedPath();
237
237
  const sourceMenu = path.find(
238
- target =>
239
- target instanceof HTMLElement &&
240
- target.tagName.toLowerCase() === 'wc-menu',
238
+ target => target instanceof Menu,
241
239
  );
242
240
 
243
241
  return sourceMenu === this;
@@ -252,12 +250,10 @@ export class Menu extends LitElement {
252
250
  const ownedItems = this.items;
253
251
 
254
252
  for (const target of path) {
255
- if (target instanceof HTMLElement) {
256
- if (target.tagName.toLowerCase() === 'wc-menu-item') {
257
- const ownedItem = ownedItems.find(item => item === target);
258
- if (ownedItem) {
259
- return ownedItem;
260
- }
253
+ if (target instanceof MenuItem) {
254
+ const ownedItem = ownedItems.find(item => item === target);
255
+ if (ownedItem) {
256
+ return ownedItem;
261
257
  }
262
258
  }
263
259
  }
@@ -3,118 +3,40 @@
3
3
  @include mixin.base-styles;
4
4
 
5
5
  :host {
6
- padding-inline: var(--spacing-050);
7
6
  outline: none;
8
- }
9
-
10
- .menu-item {
11
- position: relative;
12
- height: 3rem;
13
- display: flex;
14
- align-items: center;
15
- padding-inline: 0.75rem;
16
- outline: 0;
17
- text-decoration: none;
18
-
19
- @include mixin.get-typography(label-large);
20
-
21
- .menu-item-content {
22
- display: flex;
23
- align-items: center;
24
- z-index: 1;
25
- width: 100%;
26
- gap: var(--spacing-100);
27
-
28
- color: var(--_label-text-color);
29
- opacity: var(--_label-text-opacity, 1);
30
- --icon-size: var(--button-icon-size, var(--_button-icon-size));
31
- --icon-color: var(--_label-text-color);
32
-
33
- .slot-container {
34
- flex: 1;
35
- }
36
- }
37
-
38
-
39
- .background {
40
- display: block;
41
- position: absolute;
42
- left: 0;
43
- top: 0;
44
- width: 100%;
45
- height: 100%;
46
- background-color: var(--_container-color);
47
- opacity: var(--_container-opacity, 1);
48
7
 
49
- border-start-start-radius: var(--_container-shape-start-start);
50
- border-start-end-radius: var(--_container-shape-start-end);
51
- border-end-start-radius: var(--_container-shape-end-start);
52
- border-end-end-radius: var(--_container-shape-end-end);
53
- corner-shape: var(--_container-corner-shape-variant);
54
- pointer-events: none;
55
- }
56
-
57
- /*
58
- Background layers
59
- */
60
- .focus-ring {
61
- z-index: 2;
62
- --focus-ring-container-shape-start-start: var(--_container-shape-start-start);
63
- --focus-ring-container-shape-start-end: var(--_container-shape-start-end);
64
- --focus-ring-container-shape-end-start: var(--_container-shape-end-start);
65
- --focus-ring-container-shape-end-end: var(--_container-shape-end-end);
66
- --focus-ring-container-shape-variant: var(--_container-corner-shape-variant);
67
- }
68
-
69
- .ripple {
70
- --ripple-state-opacity: var(--_container-state-opacity, 0);
71
- --ripple-pressed-color: var(--_container-state-color);
72
- border-start-start-radius: var(--_container-shape-start-start);
73
- border-start-end-radius: var(--_container-shape-start-end);
74
- border-end-start-radius: var(--_container-shape-end-start);
75
- border-end-end-radius: var(--_container-shape-end-end);
76
- corner-shape: var(--_container-corner-shape-variant);
77
- }
8
+ --menu-item-container-shape-start-start: var(--shape-corner-extra-small);
9
+ --menu-item-container-shape-start-end: var(--shape-corner-extra-small);
10
+ --menu-item-container-shape-end-start: var(--shape-corner-extra-small);
11
+ --menu-item-container-shape-end-end: var(--shape-corner-extra-small);
78
12
  }
79
13
 
80
-
81
14
  .menu-item {
15
+ width: 100%;
16
+ --item-height: 3rem;
17
+ --item-container-shape-start-start: var(--menu-item-container-shape-start-start);
18
+ --item-container-shape-start-end: var(--menu-item-container-shape-start-end);
19
+ --item-container-shape-end-start: var(--menu-item-container-shape-end-start);
20
+ --item-container-shape-end-end: var(--menu-item-container-shape-end-end);
21
+ --item-container-shape-variant: none;
22
+
23
+ --item-label-font-family: var(--typography-label-large-font-family);
24
+ --item-label-font-size: var(--typography-label-large-font-size);
25
+ --item-label-font-weight: var(--typography-label-large-font-weight);
26
+ --item-label-line-height: var(--typography-label-large-line-height);
27
+ --item-label-letter-spacing: var(--typography-label-large-letter-spacing);
28
+
29
+ --item-label-text-color: var(--menu-item-label-color);
30
+ --item-leading-trailing-color: var(--menu-item-label-color);
31
+ --item-supporting-text-color: var(--menu-item-label-color);
32
+ --item-container-selected-color: var(--menu-item-container-selected-color);
33
+ --item-label-text-selected-color: var(--menu-item-label-selected-color);
34
+ --item-icon-size: var(--button-icon-size, var(--_button-icon-size));
35
+ }
82
36
 
83
- --_container-shape-start-start: var(--menu-item-container-shape-start-start, var(--shape-corner-extra-small));
84
- --_container-shape-start-end: var(--menu-item-container-shape-start-end, var(--shape-corner-extra-small));
85
- --_container-shape-end-start: var(--menu-item-container-shape-end-start, var(--shape-corner-extra-small));
86
- --_container-shape-end-end: var(--menu-item-container-shape-end-end, var(--shape-corner-extra-small));
87
- --_container-corner-shape-variant: none;
88
- --_label-text-color: var(--menu-item-label-color);
89
- --_container-state-color: var(--_label-text-color);
90
-
91
- &:hover:not(:where(.disabled, .selected)) {
92
- --_container-state-opacity: 0.08;
93
- }
94
-
95
- &.pressed:not(:where(.disabled)) {
96
- --_container-state-opacity: 0.12;
97
- }
98
-
99
- &.selected {
100
- --_container-color: var(--menu-item-container-selected-color);
101
- --_label-text-color: var(--menu-item-label-selected-color);
102
- --_container-shape-start-start: var(--shape-corner-large);
103
- --_container-shape-start-end: var(--shape-corner-large);
104
- --_container-shape-end-start: var(--shape-corner-large);
105
- --_container-shape-end-end: var(--shape-corner-large);
106
- --_container-corner-shape-variant: none;
107
- }
108
-
109
- &.disabled {
110
- cursor: not-allowed;
111
- --_container-color: var(--color-on-surface);
112
- --_container-opacity: 0.1;
113
- --_label-text-color: var(--color-on-surface);
114
- --_label-text-opacity: 0.38;
115
-
116
- .ripple {
117
- display: none;
118
- }
119
- }
37
+ :host([selected]) {
38
+ --menu-item-container-shape-start-start: var(--shape-corner-large);
39
+ --menu-item-container-shape-start-end: var(--shape-corner-large);
40
+ --menu-item-container-shape-end-start: var(--shape-corner-large);
41
+ --menu-item-container-shape-end-end: var(--shape-corner-large);
120
42
  }
@@ -1,17 +1,16 @@
1
1
  import { html, LitElement, nothing } from 'lit';
2
- import { property, query, state } from 'lit/decorators.js';
3
- import { classMap } from 'lit/directives/class-map.js';
2
+ import { property, query } from 'lit/decorators.js';
3
+ import { ifDefined } from 'lit/directives/if-defined.js';
4
4
  import styles from './menu-item.scss';
5
5
  import colorStyles from './menu-item-colors.scss';
6
- import BaseButtonMixin from '@/__mixins/BaseButtonMixin.js';
7
- import BaseHyperlinkMixin from '@/__mixins/BaseHyperlinkMixin.js';
8
- import { dispatchActivationClick, isActivationClick } from '@/__utils/dispatch-event-utils.js';
6
+ import NativeButtonMixin from '@/__mixins/NativeButtonMixin.js';
7
+ import NativeHyperlinkMixin from '@/__mixins/NativeHyperlinkMixin.js';
8
+ import { Item } from '@/item/item.js';
9
9
 
10
10
  /**
11
11
  * @label Menu Item
12
12
  * @tag wc-menu-item
13
13
  * @rawTag menu-item
14
- * @parentRawTag menu
15
14
  * @summary An item in a menu list.
16
15
  * @tags navigation
17
16
  *
@@ -20,8 +19,9 @@ import { dispatchActivationClick, isActivationClick } from '@/__utils/dispatch-e
20
19
  * <wc-menu-item>Menu Item</wc-menu-item>
21
20
  * ```
22
21
  */
23
- export class MenuItem extends BaseButtonMixin(BaseHyperlinkMixin(LitElement)) {
24
-
22
+ export class MenuItem extends NativeButtonMixin(
23
+ NativeHyperlinkMixin(LitElement),
24
+ ) {
25
25
  @property({ type: String }) value = '';
26
26
 
27
27
  @property({ type: Boolean, reflect: true }) selected = false;
@@ -37,31 +37,40 @@ export class MenuItem extends BaseButtonMixin(BaseHyperlinkMixin(LitElement)) {
37
37
 
38
38
  static styles = [styles, colorStyles];
39
39
 
40
- @query('#item') readonly itemElement!: HTMLElement | null;
40
+ @query('wc-item') readonly itemElement!: Item | null;
41
41
 
42
- /**
43
- * States
44
- */
45
- @state()
46
- isPressed = false;
42
+ private readonly _contentObserver = new MutationObserver(() => {
43
+ this.requestUpdate();
44
+ });
45
+
46
+ private _rovingTabIndex = -1;
47
47
 
48
48
  connectedCallback() {
49
49
  // eslint-disable-next-line wc/guard-super-call
50
50
  super.connectedCallback();
51
- if (!this.hasAttribute('role')) {
52
- this.setAttribute('role', 'menuitem');
53
- }
54
-
55
- this.addEventListener('click', this.__dispatchClickWithThrottle);
56
- window.addEventListener('mouseup', this.__handlePress);
51
+ this._contentObserver.observe(this, {
52
+ subtree: true,
53
+ childList: true,
54
+ characterData: true,
55
+ attributes: true,
56
+ attributeFilter: ['slot'],
57
+ });
57
58
  }
58
59
 
59
60
  disconnectedCallback() {
60
- window.removeEventListener('mouseup', this.__handlePress);
61
- this.removeEventListener('click', this.__dispatchClickWithThrottle);
61
+ this._contentObserver.disconnect();
62
62
  super.disconnectedCallback();
63
63
  }
64
64
 
65
+ override get tabIndex() {
66
+ return this._rovingTabIndex;
67
+ }
68
+
69
+ override set tabIndex(value: number) {
70
+ this._rovingTabIndex = value;
71
+ this.requestUpdate();
72
+ }
73
+
65
74
  override focus() {
66
75
  this.itemElement?.focus();
67
76
  }
@@ -70,129 +79,89 @@ export class MenuItem extends BaseButtonMixin(BaseHyperlinkMixin(LitElement)) {
70
79
  this.itemElement?.blur();
71
80
  }
72
81
 
73
- __dispatchClickWithThrottle: (event: MouseEvent | KeyboardEvent) => void =
74
- event => {
75
- this.__dispatchClick(event);
76
- };
77
-
78
- __dispatchClick = (event: MouseEvent | KeyboardEvent) => {
79
- // If the button is soft-disabled or a disabled link, we need to explicitly
80
- // prevent the click from propagating to other event listeners as well as
81
- // prevent the default action.
82
- if (this.softDisabled || (this.disabled && this.href)) {
83
- event.stopImmediatePropagation();
84
- event.preventDefault();
85
- return;
86
- }
87
-
88
- if (!isActivationClick(event) || !this.itemElement) {
89
- return;
90
- }
91
-
92
- this.focus();
93
- dispatchActivationClick(this.itemElement);
94
- };
95
-
96
- __handleKeyDown = (event: KeyboardEvent) => {
97
- this.__handlePress(event);
98
-
99
- if (this.disabled || this.softDisabled || !this.itemElement) {
100
- return;
101
- }
102
-
103
- if (event.key === ' ') {
104
- event.preventDefault();
105
- this.itemElement.click();
106
- return;
107
- }
108
-
109
- if (event.key === 'Enter' && !this.__isLink()) {
110
- event.preventDefault();
111
- this.itemElement.click();
112
- }
113
- };
114
-
115
- __handlePress = (event: KeyboardEvent | MouseEvent) => {
116
- if (this.disabled || this.softDisabled) return;
117
- if (
118
- event instanceof KeyboardEvent &&
119
- event.type === 'keydown' &&
120
- (event.key === 'Enter' || event.key === ' ')
121
- ) {
122
- this.isPressed = true;
123
- } else if (event.type === 'mousedown') {
124
- this.isPressed = true;
125
- } else {
126
- this.isPressed = false;
127
- }
128
- };
129
-
130
- render() {
131
- const isLink = this.__isLink();
82
+ private _hasNamedSlot(...names: string[]) {
83
+ return names.some(name =>
84
+ Array.from(this.children).some(
85
+ child => child.getAttribute('slot') === name,
86
+ ),
87
+ );
88
+ }
132
89
 
133
- const cssClasses = {
134
- 'menu-item': true,
135
- disabled: this.disabled,
136
- selected: this.selected,
137
- pressed: this.isPressed,
138
- };
90
+ private _hasDefaultSlot() {
91
+ return Array.from(this.childNodes).some(node => {
92
+ if (node.nodeType === Node.TEXT_NODE) {
93
+ return Boolean(node.textContent?.trim());
94
+ }
95
+
96
+ return (
97
+ node.nodeType === Node.ELEMENT_NODE &&
98
+ !(node as Element).hasAttribute('slot')
99
+ );
100
+ });
101
+ }
139
102
 
103
+ render() {
140
104
  const controls = this.getAttribute('aria-controls');
141
105
 
142
- if (isLink) {
143
- return html`<a
106
+ return html`
107
+ <wc-item
144
108
  id="item"
145
- class=${classMap(cssClasses)}
146
- href=${this.href}
147
- target=${this.target}
148
- tabindex=${this.disabled ? '-1' : '0'}
149
-
150
- @click=${this.__dispatchClickWithThrottle}
151
- @mousedown=${this.__handlePress}
152
- @keydown=${this.__handleKeyDown}
153
- @keyup=${this.__handlePress}
154
-
155
- aria-disabled=${String(this.disabled)}
109
+ class="menu-item"
110
+ role="menuitem"
111
+ tabindex=${String(this.tabIndex)}
112
+ ?selected=${this.selected}
113
+ ?disabled=${this.disabled}
114
+ .softDisabled=${this.softDisabled}
115
+ .htmlType=${this.htmlType}
116
+ .href=${this.href}
117
+ .target=${this.target}
118
+ .rel=${this.rel}
119
+ .download=${this.download}
156
120
  aria-haspopup=${this.hasSubmenu ? 'menu' : nothing}
157
- aria-controls=${this.hasSubmenu && controls ? controls : nothing}
158
- aria-expanded=${this.hasSubmenu ? String(this.submenuOpen) : nothing}
121
+ aria-controls=${ifDefined(
122
+ this.hasSubmenu && controls ? controls : undefined,
123
+ )}
124
+ aria-expanded=${ifDefined(
125
+ this.hasSubmenu ? String(this.submenuOpen) : undefined,
126
+ )}
159
127
  >
160
128
  ${this.renderContent()}
161
- </a> `;
162
- }
163
-
164
- return html`<div
165
- id="item"
166
- class=${classMap(cssClasses)}
167
- tabindex=${this.disabled ? '-1' : '0'}
168
-
169
- @click=${this.__dispatchClick}
170
- @mousedown=${this.__handlePress}
171
- @keydown=${this.__handleKeyDown}
172
- @keyup=${this.__handlePress}
173
-
174
- aria-disabled=${String(this.disabled)}
175
- aria-haspopup=${this.hasSubmenu ? 'menu' : nothing}
176
- aria-controls=${this.hasSubmenu && controls ? controls : nothing}
177
- aria-expanded=${this.hasSubmenu ? String(this.submenuOpen) : nothing}
178
- >
179
- ${this.renderContent()}
180
- </div>`;
129
+ </wc-item>
130
+ `;
181
131
  }
182
132
 
183
133
  renderContent() {
134
+ const hasStart = this._hasNamedSlot('start');
135
+ const hasOverline = this._hasNamedSlot('overline');
136
+ const hasHeadline = this._hasNamedSlot('headline');
137
+ const hasDefault = this._hasDefaultSlot();
138
+ const hasSupportingText = this._hasNamedSlot('supporting-text');
139
+ const hasTrailingSupportingText = this._hasNamedSlot(
140
+ 'trailing-supporting-text',
141
+ );
142
+ const hasEnd = this._hasNamedSlot('end');
143
+
184
144
  return html`
185
- <wc-focus-ring class="focus-ring" for='item'></wc-focus-ring>
186
- <div class="background"></div>
187
- <wc-ripple class="ripple"></wc-ripple>
188
-
189
- <div class="menu-item-content" data-variant=${this.variant}>
190
- <slot name="leading-icon"></slot>
191
- <div class="slot-container">
192
- <slot></slot>
193
- </div>
194
- <slot name="trailing-supporting-text"></slot>
195
- </div>
145
+ ${hasStart ? html`<slot name="start" slot="start"></slot>` : nothing}
146
+ ${hasOverline
147
+ ? html`<slot name="overline" slot="overline"></slot>`
148
+ : nothing}
149
+ ${hasHeadline
150
+ ? html`<slot name="headline" slot="headline"></slot>`
151
+ : nothing}
152
+ ${hasDefault ? html`<slot></slot>` : nothing}
153
+ ${hasSupportingText
154
+ ? html`<slot name="supporting-text" slot="supporting-text"></slot>`
155
+ : nothing}
156
+ ${hasTrailingSupportingText
157
+ ? html`
158
+ <slot
159
+ name="trailing-supporting-text"
160
+ slot="trailing-supporting-text"
161
+ ></slot>
162
+ `
163
+ : nothing}
164
+ ${hasEnd ? html`<slot name="end" slot="end"></slot>` : nothing}
196
165
  `;
197
166
  }
198
167
  }
@@ -10,7 +10,6 @@ let subMenuIdCounter = 0;
10
10
  * @label Sub Menu
11
11
  * @tag wc-sub-menu
12
12
  * @rawTag sub-menu
13
- * @parentRawTag menu
14
13
  * @summary Connects a menu item to a nested menu.
15
14
  */
16
15
  export class SubMenu extends LitElement {
@@ -38,6 +37,10 @@ export class SubMenu extends LitElement {
38
37
 
39
38
  private _closeTimeout?: number;
40
39
 
40
+ private _resolveAnchorElement(item: MenuItem) {
41
+ return item.itemElement?.itemElement ?? item.itemElement ?? item;
42
+ }
43
+
41
44
  private readonly _onChildMenuOpened = () => {
42
45
  const { item } = this;
43
46
  if (!item) {
@@ -91,7 +94,7 @@ export class SubMenu extends LitElement {
91
94
  return;
92
95
  }
93
96
 
94
- menu.anchorElement = item;
97
+ menu.anchorElement = this._resolveAnchorElement(item);
95
98
  menu.isSubmenu = true;
96
99
  menu.show();
97
100
 
@@ -152,7 +155,7 @@ export class SubMenu extends LitElement {
152
155
  menu.addEventListener('closed', this._onChildMenuClosed);
153
156
 
154
157
  menu.isSubmenu = true;
155
- menu.anchorElement = item;
158
+ menu.anchorElement = this._resolveAnchorElement(item);
156
159
  menu.placement =
157
160
  getComputedStyle(this).direction === 'rtl' ? 'left-start' : 'right-start';
158
161
  menu.offset = 4;
@@ -99,6 +99,11 @@
99
99
  font-weight var(--duration-short4, 200ms) var(--easing-standard, ease);
100
100
  }
101
101
 
102
+ /* Hide label when collapsed via class */
103
+ .label.hidden {
104
+ display: none;
105
+ }
106
+
102
107
  /* Active icon slot: hidden by default */
103
108
  .active-icon-slot {
104
109
  display: none;
@@ -1,16 +1,19 @@
1
1
  import { html, LitElement, nothing } from 'lit';
2
2
  import { property, query, state } from 'lit/decorators.js';
3
3
  import { classMap } from 'lit/directives/class-map.js';
4
- import { dispatchActivationClick, isActivationClick } from '@/__utils/dispatch-event-utils.js';
4
+ import {
5
+ dispatchActivationClick,
6
+ isActivationClick,
7
+ } from '@/__utils/dispatch-event-utils.js';
5
8
  import { observerSlotChangesWithCallback } from '@/__utils/observe-slot-change.js';
6
9
  import { throttle } from '@/__utils/throttle.js';
10
+ import { isLink } from '@/__utils/is-link.js';
7
11
  import styles from './navigation-rail-item.scss';
8
12
 
9
13
  /**
10
14
  * @label Navigation Rail Item
11
15
  * @tag wc-navigation-rail-item
12
16
  * @rawTag navigation-rail-item
13
- * @parentRawTag navigation-rail
14
17
  *
15
18
  * @summary An individual item within a navigation rail.
16
19
  * @overview
@@ -77,7 +80,7 @@ export class NavigationRailItem extends LitElement {
77
80
  );
78
81
 
79
82
  observerSlotChangesWithCallback(
80
- this.renderRoot.querySelector('slot:not([name])'),
83
+ this.renderRoot.querySelector('slot.label'),
81
84
  hasContent => {
82
85
  this._hasLabel = hasContent;
83
86
  this.requestUpdate();
@@ -85,7 +88,7 @@ export class NavigationRailItem extends LitElement {
85
88
  );
86
89
 
87
90
  observerSlotChangesWithCallback(
88
- this.renderRoot.querySelector('slot[name="active-icon"]'),
91
+ this.renderRoot.querySelector('slot.active-icon-slot'),
89
92
  hasContent => {
90
93
  this._hasActiveIcon = hasContent;
91
94
  this.requestUpdate();
@@ -128,10 +131,6 @@ export class NavigationRailItem extends LitElement {
128
131
  }
129
132
  };
130
133
 
131
- __isLink() {
132
- return !!this.href;
133
- }
134
-
135
134
  __getDisabledReasonID() {
136
135
  return this.disabled && this.disabledReason
137
136
  ? `disabled-reason-${this.#id}`
@@ -154,7 +153,7 @@ export class NavigationRailItem extends LitElement {
154
153
 
155
154
  __renderItemContent() {
156
155
  return html`
157
- <wc-focus-ring class="focus-ring" for='item'></wc-focus-ring>
156
+ <wc-focus-ring class="focus-ring" for="item"></wc-focus-ring>
158
157
 
159
158
  <div class="item-content">
160
159
  <div class="indicator">
@@ -164,9 +163,7 @@ export class NavigationRailItem extends LitElement {
164
163
  <slot name="icon" class="icon-slot"></slot>
165
164
  </div>
166
165
  </div>
167
- ${this._hasLabel && !this.collapsed
168
- ? html`<div class="label"><slot></slot></div>`
169
- : html`<slot class="hidden-slot"></slot>`}
166
+ <div class="label ${this.collapsed ? 'hidden' : ''}"><slot></slot></div>
170
167
  </div>
171
168
 
172
169
  ${this.__renderDisabledReason()}
@@ -174,8 +171,6 @@ export class NavigationRailItem extends LitElement {
174
171
  }
175
172
 
176
173
  render() {
177
- const isLink = this.__isLink();
178
-
179
174
  const cssClasses = {
180
175
  item: true,
181
176
  'item-element': true,
@@ -186,7 +181,7 @@ export class NavigationRailItem extends LitElement {
186
181
  'has-active-icon': this._hasActiveIcon,
187
182
  };
188
183
 
189
- if (!isLink) {
184
+ if (!isLink(this)) {
190
185
  return html`<button
191
186
  id="item"
192
187
  class=${classMap(cssClasses)}
@@ -32,17 +32,13 @@ import { NavigationRailItem } from './navigation-rail-item.js';
32
32
  * ```html
33
33
  * <wc-navigation-rail>
34
34
  * <wc-navigation-rail-item active>
35
- * <wc-icon slot="icon">home</wc-icon>
35
+ * <wc-icon slot="icon" name="home"></wc-icon>
36
36
  * Home
37
37
  * </wc-navigation-rail-item>
38
38
  * <wc-navigation-rail-item>
39
- * <wc-icon slot="icon">search</wc-icon>
39
+ * <wc-icon slot="icon" name="search"></wc-icon>
40
40
  * Search
41
41
  * </wc-navigation-rail-item>
42
- * <wc-navigation-rail-item>
43
- * <wc-icon slot="icon">settings</wc-icon>
44
- * Settings
45
- * </wc-navigation-rail-item>
46
42
  * </wc-navigation-rail>
47
43
  * ```
48
44
  * @tags navigation