@redvars/peacock 3.4.0 → 3.5.1

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 (258) hide show
  1. package/dist/BaseButton-DuASuVth.js +219 -0
  2. package/dist/BaseButton-DuASuVth.js.map +1 -0
  3. package/dist/BaseHyperlinkMixin-BNuwbiEf.js +65 -0
  4. package/dist/BaseHyperlinkMixin-BNuwbiEf.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/banner.js +187 -0
  10. package/dist/banner.js.map +1 -0
  11. package/dist/bottom-sheet.js +2 -2
  12. package/dist/{button-COYCtuA8.js → button-DouvOfEU.js} +92 -283
  13. package/dist/button-DouvOfEU.js.map +1 -0
  14. package/dist/{button-group-DsXquZQn.js → button-group-CEdMwvJJ.js} +72 -48
  15. package/dist/button-group-CEdMwvJJ.js.map +1 -0
  16. package/dist/button-group.js +8 -5
  17. package/dist/button-group.js.map +1 -1
  18. package/dist/button.js +7 -4
  19. package/dist/button.js.map +1 -1
  20. package/dist/card.js +29 -74
  21. package/dist/card.js.map +1 -1
  22. package/dist/chart-bar.js +2 -2
  23. package/dist/chart-bar.js.map +1 -1
  24. package/dist/chart-doughnut.js +2 -2
  25. package/dist/chart-doughnut.js.map +1 -1
  26. package/dist/chart-pie.js +2 -2
  27. package/dist/chart-pie.js.map +1 -1
  28. package/dist/chart-stacked-bar.js +2 -2
  29. package/dist/chart-stacked-bar.js.map +1 -1
  30. package/dist/{class-map-3TAnCMAX.js → class-map-YU7g0o3B.js} +2 -2
  31. package/dist/{class-map-3TAnCMAX.js.map → class-map-YU7g0o3B.js.map} +1 -1
  32. package/dist/clock.js.map +1 -1
  33. package/dist/code-editor.js +4 -4
  34. package/dist/code-editor.js.map +1 -1
  35. package/dist/code-highlighter.js +5 -4
  36. package/dist/code-highlighter.js.map +1 -1
  37. package/dist/custom-elements-jsdocs.json +6627 -3477
  38. package/dist/custom-elements.json +10954 -7810
  39. package/dist/directive-ZPhl09Yt.js +9 -0
  40. package/dist/directive-ZPhl09Yt.js.map +1 -0
  41. package/dist/dispatch-event-utils-CuEqjlPT.js +127 -0
  42. package/dist/dispatch-event-utils-CuEqjlPT.js.map +1 -0
  43. package/dist/fab.js +423 -0
  44. package/dist/fab.js.map +1 -0
  45. package/dist/index.js +17 -9
  46. package/dist/index.js.map +1 -1
  47. package/dist/{observe-theme-change-DKAIv5BB.js → is-dark-mode-DicqGkCJ.js} +6 -2
  48. package/dist/is-dark-mode-DicqGkCJ.js.map +1 -0
  49. package/dist/{select-C3XAzenC.js → navigation-rail-Lxetd5-Z.js} +2426 -898
  50. package/dist/navigation-rail-Lxetd5-Z.js.map +1 -0
  51. package/dist/notification.js +418 -0
  52. package/dist/notification.js.map +1 -0
  53. package/dist/number-counter.js +2 -2
  54. package/dist/number-counter.js.map +1 -1
  55. package/dist/observe-slot-change-BGJfgg2E.js +31 -0
  56. package/dist/observe-slot-change-BGJfgg2E.js.map +1 -0
  57. package/dist/peacock-loader.js +48 -13
  58. package/dist/peacock-loader.js.map +1 -1
  59. package/dist/search.js +456 -0
  60. package/dist/search.js.map +1 -0
  61. package/dist/side-sheet.js +2 -2
  62. package/dist/src/__mixins/BaseButtonMixin.d.ts +20 -0
  63. package/dist/src/__mixins/BaseHyperlinkMixin.d.ts +18 -0
  64. package/dist/src/__mixins/MixinConstructor.d.ts +1 -0
  65. package/dist/src/__utils/cache-fetch.d.ts +1 -0
  66. package/dist/src/__utils/is-dark-mode.d.ts +1 -0
  67. package/dist/src/__utils/is-in-viewport.d.ts +1 -0
  68. package/dist/src/__utils/observe-slot-change.d.ts +1 -0
  69. package/dist/src/__utils/sanitize-svg.d.ts +1 -0
  70. package/dist/src/__utils/throttle.d.ts +4 -0
  71. package/dist/src/accordion/accordion-item.d.ts +33 -9
  72. package/dist/src/accordion/accordion.d.ts +21 -5
  73. package/dist/src/banner/banner.d.ts +43 -0
  74. package/dist/src/banner/index.d.ts +1 -0
  75. package/dist/src/button/BaseButton.d.ts +7 -57
  76. package/dist/src/button/button/button.d.ts +32 -3
  77. package/dist/src/button/button-group/button-group.d.ts +4 -4
  78. package/dist/src/button/icon-button/icon-button.d.ts +33 -8
  79. package/dist/src/card/card.d.ts +4 -15
  80. package/dist/src/empty-state/empty-state.d.ts +1 -1
  81. package/dist/src/fab/fab.d.ts +80 -0
  82. package/dist/src/fab/index.d.ts +1 -0
  83. package/dist/src/focus-ring/focus-ring.d.ts +11 -5
  84. package/dist/src/index.d.ts +8 -1
  85. package/dist/src/link/link.d.ts +3 -10
  86. package/dist/src/menu/menu/menu.d.ts +3 -2
  87. package/dist/src/menu/sub-menu/sub-menu.d.ts +1 -0
  88. package/dist/src/navigation-rail/index.d.ts +2 -0
  89. package/dist/src/navigation-rail/navigation-rail-item.d.ts +55 -0
  90. package/dist/src/navigation-rail/navigation-rail.d.ts +71 -0
  91. package/dist/src/notification/index.d.ts +1 -0
  92. package/dist/src/notification/notification.d.ts +69 -0
  93. package/dist/src/pagination/pagination.d.ts +8 -1
  94. package/dist/src/search/index.d.ts +1 -0
  95. package/dist/src/search/search.d.ts +76 -0
  96. package/dist/src/select/select.d.ts +3 -5
  97. package/dist/src/sidebar-menu/index.d.ts +3 -0
  98. package/dist/src/sidebar-menu/sidebar-menu-item.d.ts +58 -0
  99. package/dist/src/sidebar-menu/sidebar-menu.d.ts +38 -0
  100. package/dist/src/sidebar-menu/sidebar-sub-menu.d.ts +35 -0
  101. package/dist/src/slider/slider.d.ts +4 -0
  102. package/dist/src/snackbar/snackbar.d.ts +14 -1
  103. package/dist/src/toolbar/index.d.ts +1 -0
  104. package/dist/src/toolbar/toolbar.d.ts +86 -0
  105. package/dist/src/tooltip/tooltip.d.ts +3 -0
  106. package/dist/src/url-field/index.d.ts +1 -0
  107. package/dist/src/url-field/url-field.d.ts +48 -0
  108. package/dist/{style-map-CRFEoCEg.js → style-map-DVmWOuYy.js} +2 -2
  109. package/dist/{style-map-CRFEoCEg.js.map → style-map-DVmWOuYy.js.map} +1 -1
  110. package/dist/test/banner.test.d.ts +1 -0
  111. package/dist/test/search.test.d.ts +1 -0
  112. package/dist/test/sidebar-menu.test.d.ts +1 -0
  113. package/dist/test/toolbar.test.d.ts +1 -0
  114. package/dist/toolbar.js +306 -0
  115. package/dist/toolbar.js.map +1 -0
  116. package/dist/tsconfig.tsbuildinfo +1 -1
  117. package/dist/{unsafe-html-D3GHRaGQ.js → unsafe-html-BsGUjx94.js} +2 -2
  118. package/dist/{unsafe-html-D3GHRaGQ.js.map → unsafe-html-BsGUjx94.js.map} +1 -1
  119. package/package.json +1 -1
  120. package/readme.md +73 -65
  121. package/scss/mixin.scss +16 -0
  122. package/scss/styles.scss +4 -0
  123. package/src/__mixins/BaseButtonMixin.ts +83 -0
  124. package/src/__mixins/BaseHyperlinkMixin.ts +68 -0
  125. package/src/__mixins/MixinConstructor.ts +1 -0
  126. package/src/__mixins/README.md +19 -0
  127. package/src/__utils/cache-fetch.ts +65 -0
  128. package/src/__utils/is-dark-mode.ts +3 -0
  129. package/src/__utils/is-in-viewport.ts +6 -0
  130. package/src/__utils/observe-slot-change.ts +38 -0
  131. package/src/__utils/sanitize-svg.ts +27 -0
  132. package/src/__utils/throttle.ts +27 -0
  133. package/src/accordion/accordion-item.scss +136 -65
  134. package/src/accordion/accordion-item.ts +117 -44
  135. package/src/accordion/accordion.scss +24 -5
  136. package/src/accordion/accordion.ts +29 -23
  137. package/src/accordion/demo/index.html +74 -35
  138. package/src/banner/banner.scss +83 -0
  139. package/src/banner/banner.ts +101 -0
  140. package/src/banner/index.ts +1 -0
  141. package/src/button/BaseButton.ts +13 -115
  142. package/src/button/button/button-colors.scss +14 -14
  143. package/src/button/button/button-sizes.scss +4 -2
  144. package/src/button/button/button.ts +80 -26
  145. package/src/button/button-group/button-group.ts +5 -5
  146. package/src/button/icon-button/icon-button.ts +79 -44
  147. package/src/card/card.ts +50 -100
  148. package/src/chart-bar/chart-bar.ts +10 -15
  149. package/src/chart-bar/chart-stacked-bar.ts +15 -19
  150. package/src/chart-doughnut/chart-doughnut.ts +24 -28
  151. package/src/chart-pie/chart-pie.ts +20 -24
  152. package/src/checkbox/checkbox.scss +17 -34
  153. package/src/checkbox/checkbox.ts +4 -2
  154. package/src/clock/clock.ts +1 -1
  155. package/src/code-editor/code-editor.ts +4 -4
  156. package/src/code-highlighter/code-highlighter.scss +1 -0
  157. package/src/code-highlighter/code-highlighter.ts +3 -3
  158. package/src/date-picker/date-picker.ts +6 -3
  159. package/src/divider/divider.ts +3 -1
  160. package/src/elevation/elevation.scss +5 -5
  161. package/src/empty-state/empty-state.scss +7 -9
  162. package/src/empty-state/empty-state.ts +1 -1
  163. package/src/fab/fab-colors.scss +49 -0
  164. package/src/fab/fab-sizes.scss +47 -0
  165. package/src/fab/fab.scss +137 -0
  166. package/src/fab/fab.ts +214 -0
  167. package/src/fab/index.ts +1 -0
  168. package/src/field/field.ts +3 -1
  169. package/src/focus-ring/focus-ring.ts +47 -40
  170. package/src/icon/datasource.ts +1 -1
  171. package/src/icon/icon.ts +3 -1
  172. package/src/image/image.ts +3 -2
  173. package/src/index.ts +8 -1
  174. package/src/input/input.ts +8 -3
  175. package/src/link/link.ts +2 -15
  176. package/src/menu/menu/menu.scss +7 -0
  177. package/src/menu/menu/menu.ts +7 -4
  178. package/src/menu/menu-item/menu-item.ts +3 -1
  179. package/src/menu/sub-menu/sub-menu.ts +1 -0
  180. package/src/navigation-rail/index.ts +2 -0
  181. package/src/navigation-rail/navigation-rail-item.scss +216 -0
  182. package/src/navigation-rail/navigation-rail-item.ts +223 -0
  183. package/src/navigation-rail/navigation-rail.scss +72 -0
  184. package/src/navigation-rail/navigation-rail.ts +149 -0
  185. package/src/notification/index.ts +1 -0
  186. package/src/notification/notification.scss +201 -0
  187. package/src/notification/notification.ts +207 -0
  188. package/src/number-counter/number-counter.ts +3 -1
  189. package/src/number-field/number-field.ts +10 -6
  190. package/src/pagination/pagination.scss +33 -24
  191. package/src/pagination/pagination.ts +115 -60
  192. package/src/peacock-loader.ts +42 -5
  193. package/src/radio/radio.ts +3 -1
  194. package/src/search/index.ts +1 -0
  195. package/src/search/search-colors.scss +14 -0
  196. package/src/search/search.scss +204 -0
  197. package/src/search/search.ts +244 -0
  198. package/src/select/option.ts +1 -1
  199. package/src/select/select.scss +5 -0
  200. package/src/select/select.ts +71 -37
  201. package/src/sidebar-menu/demo/index.html +68 -0
  202. package/src/sidebar-menu/index.ts +3 -0
  203. package/src/sidebar-menu/sidebar-menu-item.scss +102 -0
  204. package/src/sidebar-menu/sidebar-menu-item.ts +151 -0
  205. package/src/{tree-view/tree-view.scss → sidebar-menu/sidebar-menu.scss} +1 -1
  206. package/src/sidebar-menu/sidebar-menu.ts +182 -0
  207. package/src/sidebar-menu/sidebar-sub-menu.scss +130 -0
  208. package/src/sidebar-menu/sidebar-sub-menu.ts +160 -0
  209. package/src/skeleton/skeleton.scss +18 -24
  210. package/src/slider/slider.scss +19 -0
  211. package/src/slider/slider.ts +30 -19
  212. package/src/snackbar/snackbar.scss +62 -31
  213. package/src/snackbar/snackbar.ts +91 -11
  214. package/src/switch/switch.ts +3 -1
  215. package/src/table/table.ts +3 -1
  216. package/src/tabs/tab.ts +10 -6
  217. package/src/text/text.css-component.scss +7 -1
  218. package/src/textarea/textarea.ts +4 -2
  219. package/src/time-picker/time-picker.ts +5 -3
  220. package/src/toolbar/index.ts +1 -0
  221. package/src/toolbar/toolbar-colors.scss +16 -0
  222. package/src/toolbar/toolbar.scss +165 -0
  223. package/src/toolbar/toolbar.ts +137 -0
  224. package/src/tooltip/tooltip.ts +24 -0
  225. package/src/url-field/index.ts +1 -0
  226. package/src/url-field/url-field.scss +50 -0
  227. package/src/url-field/url-field.ts +239 -0
  228. package/dist/button-COYCtuA8.js.map +0 -1
  229. package/dist/button-group-DsXquZQn.js.map +0 -1
  230. package/dist/directive-Cuw6h7YA.js +0 -9
  231. package/dist/directive-Cuw6h7YA.js.map +0 -1
  232. package/dist/dispatch-event-utils-B4odODQf.js +0 -277
  233. package/dist/dispatch-event-utils-B4odODQf.js.map +0 -1
  234. package/dist/observe-theme-change-DKAIv5BB.js.map +0 -1
  235. package/dist/select-C3XAzenC.js.map +0 -1
  236. package/dist/src/styleMixins.css.d.ts +0 -9
  237. package/dist/src/tree-view/index.d.ts +0 -2
  238. package/dist/src/tree-view/tree-node.d.ts +0 -69
  239. package/dist/src/tree-view/tree-view.d.ts +0 -40
  240. package/dist/src/tree-view/wc-tree-view.d.ts +0 -6
  241. package/dist/src/utils.d.ts +0 -9
  242. package/dist/test/tree-view.test.d.ts +0 -1
  243. package/src/styleMixins.css.ts +0 -55
  244. package/src/tree-view/demo/index.html +0 -57
  245. package/src/tree-view/index.ts +0 -2
  246. package/src/tree-view/tree-node.scss +0 -101
  247. package/src/tree-view/tree-node.ts +0 -268
  248. package/src/tree-view/tree-view.ts +0 -182
  249. package/src/tree-view/wc-tree-view.ts +0 -9
  250. package/src/utils.ts +0 -193
  251. /package/dist/src/{spread.d.ts → __directive/spread.d.ts} +0 -0
  252. /package/dist/src/{utils → __utils}/copy-to-clipboard.d.ts +0 -0
  253. /package/dist/src/{utils → __utils}/dispatch-event-utils.d.ts +0 -0
  254. /package/dist/src/{utils → __utils}/observe-theme-change.d.ts +0 -0
  255. /package/src/{spread.ts → __directive/spread.ts} +0 -0
  256. /package/src/{utils → __utils}/copy-to-clipboard.ts +0 -0
  257. /package/src/{utils → __utils}/dispatch-event-utils.ts +0 -0
  258. /package/src/{utils → __utils}/observe-theme-change.ts +0 -0
@@ -1,7 +1,8 @@
1
1
  import { LitElement, html } from 'lit';
2
2
  import { property, state } from 'lit/decorators.js';
3
- import { isDarkMode } from '../utils.js';
4
- import { observeThemeChange } from '../utils/observe-theme-change.js';
3
+
4
+ import { isDarkMode } from '@/__utils/is-dark-mode.js';
5
+ import { observeThemeChange } from '@/__utils/observe-theme-change.js';
5
6
 
6
7
  import styles from './image.scss';
7
8
 
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@ export { Divider } from './divider/index.js';
5
5
  export { Clock } from './clock/index.js';
6
6
  export { Elevation } from './elevation/index.js';
7
7
  export { Button, ButtonGroup, IconButton } from './button/index.js';
8
+ export { Fab } from './fab/index.js';
8
9
  export { SegmentedButton, SegmentedButtonGroup } from './segmented-button/index.js';
9
10
 
10
11
  export { FocusRing } from './focus-ring/index.js';
@@ -17,6 +18,7 @@ export { LinearProgress } from './progress/linear-progress/index.js';
17
18
  export { CircularProgress } from './progress/circular-progress/index.js';
18
19
  export { Skeleton } from './skeleton/index.js';
19
20
  export { Input } from './input/index.js';
21
+ export { UrlField } from './url-field/index.js';
20
22
  export { Field } from './field/index.js';
21
23
  export { NumberField } from './number-field/index.js';
22
24
  export { DatePicker } from './date-picker/index.js';
@@ -43,8 +45,10 @@ export { ChartPie } from './chart-pie/index.js';
43
45
  export { ChartBar, ChartStackedBar } from './chart-bar/index.js';
44
46
  export { Table } from './table/index.js';
45
47
  export { Pagination } from './pagination/index.js';
46
- export { TreeView, TreeNode } from './tree-view/index.js';
48
+ export { SidebarMenu, SidebarMenuItem, SidebarSubMenu } from './sidebar-menu/index.js';
47
49
  export { Card } from './card/index.js';
50
+ export { Banner } from './banner/index.js';
51
+ export { Notification } from './notification/index.js';
48
52
  export { Snackbar } from './snackbar/index.js';
49
53
  export { Radio } from './radio/index.js';
50
54
  export { BottomSheet } from './bottom-sheet/index.js';
@@ -52,4 +56,7 @@ export { SideSheet } from './side-sheet/index.js';
52
56
  export { Select } from './select/index.js';
53
57
  export type { SelectOption } from './select/index.js';
54
58
  export { SelectOptionElement } from './select/index.js';
59
+ export { Search } from './search/index.js';
60
+ export { Toolbar } from './toolbar/index.js';
61
+ export { NavigationRail, NavigationRailItem } from './navigation-rail/index.js';
55
62
 
@@ -1,9 +1,12 @@
1
1
  import { html, nothing } from 'lit';
2
2
  import { property, query, state } from 'lit/decorators.js';
3
- import { redispatchEvent } from 'src/utils/dispatch-event-utils.js';
3
+
4
+ import { redispatchEvent } from '@/__utils/dispatch-event-utils.js';
5
+ import { spread } from '@/__directive/spread.js';
6
+
4
7
  import BaseInput from './BaseInput.js';
5
8
  import styles from './input.scss';
6
- import { spread } from '../spread.js';
9
+
7
10
  /**
8
11
  * @label Input
9
12
  * @tag wc-input
@@ -175,11 +178,13 @@ export class Input extends BaseInput {
175
178
  <wc-icon-button
176
179
  class="password-toggle"
177
180
  variant="text"
178
- name=${this.passwordVisible ? 'visibility_off' : 'visibility'}
179
181
  @click=${() => {
180
182
  this.passwordVisible = !this.passwordVisible;
181
183
  }}
182
184
  >
185
+ <wc-icon
186
+ name=${this.passwordVisible ? 'visibility_off' : 'visibility'}
187
+ ></wc-icon>
183
188
  </wc-icon-button>
184
189
  </pc-tooltip>
185
190
  `
package/src/link/link.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { html, LitElement } from 'lit';
2
- import { property, state } from 'lit/decorators.js';
3
2
  import { classMap } from 'lit/directives/class-map.js';
3
+ import BaseHyperlinkMixin from '../__mixins/BaseHyperlinkMixin.js';
4
4
  import styles from './link.scss';
5
5
 
6
6
  /**
@@ -16,22 +16,9 @@ import styles from './link.scss';
16
16
  * <wc-link href="#">Link</wc-link>
17
17
  * ```
18
18
  */
19
- export class Link extends LitElement {
19
+ export class Link extends BaseHyperlinkMixin(LitElement) {
20
20
  static styles = [styles];
21
21
 
22
- /**
23
- * Hyperlink to navigate to on click.
24
- */
25
- @property({ reflect: true }) href?: string;
26
-
27
- /**
28
- * Sets or retrieves the window or frame at which to target content.
29
- */
30
- @property() target: '_self' | '_parent' | '_blank' | '_top' | string =
31
- '_self';
32
-
33
- @state() tabIndexValue?: number;
34
-
35
22
  render() {
36
23
  return html`<a
37
24
  class=${classMap({
@@ -6,6 +6,8 @@
6
6
  display: flex;
7
7
  position: fixed;
8
8
  z-index: var(--menu-z-index, 1000);
9
+ width: var(--menu-width, max-content);
10
+ max-width: 100vw;
9
11
  min-width: 112px;
10
12
  padding-block: var(--spacing-050);
11
13
  transform-origin: top center;
@@ -37,6 +39,11 @@
37
39
  transition-timing-function: var(--_menu-enter-easing), var(--_menu-enter-easing), linear;
38
40
  }
39
41
 
42
+ &.preview {
43
+ position: relative;
44
+ pointer-events: auto;
45
+ }
46
+
40
47
  .menu-content {
41
48
  display: flex;
42
49
  flex-direction: column;
@@ -22,9 +22,9 @@ type CloseReason =
22
22
  *
23
23
  * @example
24
24
  * ```html
25
- * <wc-menu>
25
+ * <wc-menu preview>
26
26
  * <wc-menu-item>Item 1</wc-menu-item>
27
- * <wc-menu-item>Item 2</wc-menu-item>
27
+ * <wc-menu-item selected>Item 2</wc-menu-item>
28
28
  * </wc-menu>
29
29
  * ```
30
30
  */
@@ -40,6 +40,8 @@ export class Menu extends LitElement {
40
40
 
41
41
  @property({ type: String }) anchor = '';
42
42
 
43
+ @property({ type: Boolean, reflect: true }) preview = false;
44
+
43
45
  @property({ type: Boolean, attribute: 'stay-open-on-outside-click' })
44
46
  stayOpenOnOutsideClick = false;
45
47
 
@@ -448,8 +450,9 @@ export class Menu extends LitElement {
448
450
  return html`<div
449
451
  class=${classMap({
450
452
  'menu': true,
451
- open: this.open,
452
- closed: !this.open,
453
+ open: !this.preview && this.open,
454
+ closed: !this.preview && !this.open,
455
+ preview: this.preview,
453
456
  [`variant-${this.variant}`]: true,
454
457
  })}
455
458
  aria-hidden=${String(!this.open)}
@@ -151,6 +151,7 @@ export class MenuItem extends LitElement {
151
151
 
152
152
  if (isLink) {
153
153
  return html`<a
154
+ id="item"
154
155
  class=${classMap(cssClasses)}
155
156
  href=${this.href}
156
157
  target=${this.target}
@@ -164,6 +165,7 @@ export class MenuItem extends LitElement {
164
165
  }
165
166
 
166
167
  return html`<div
168
+ id="item"
167
169
  class=${classMap(cssClasses)}
168
170
  aria-disabled=${String(this.disabled)}
169
171
  aria-haspopup=${this.hasSubmenu ? 'menu' : nothing}
@@ -176,7 +178,7 @@ export class MenuItem extends LitElement {
176
178
 
177
179
  renderContent() {
178
180
  return html`
179
- <wc-focus-ring class="focus-ring" .control=${this} .forElement=${this}></wc-focus-ring>
181
+ <wc-focus-ring class="focus-ring" for='item'></wc-focus-ring>
180
182
  <div class="background"></div>
181
183
  <wc-ripple class="ripple"></wc-ripple>
182
184
 
@@ -10,6 +10,7 @@ let subMenuIdCounter = 0;
10
10
  * @label Sub Menu
11
11
  * @tag wc-sub-menu
12
12
  * @rawTag sub-menu
13
+ * @parentRawTag menu
13
14
  * @summary Connects a menu item to a nested menu.
14
15
  */
15
16
  export class SubMenu extends LitElement {
@@ -0,0 +1,2 @@
1
+ export { NavigationRail } from './navigation-rail.js';
2
+ export { NavigationRailItem } from './navigation-rail-item.js';
@@ -0,0 +1,216 @@
1
+ @use '../../scss/mixin';
2
+
3
+ @include mixin.base-styles;
4
+
5
+ :host {
6
+ display: block;
7
+ }
8
+
9
+ /* Reset native button/link styles */
10
+ .item-element {
11
+ background: transparent;
12
+ border: none;
13
+ appearance: none;
14
+ margin: 0;
15
+ outline: none;
16
+ text-decoration: none;
17
+ text-align: unset;
18
+ color: inherit;
19
+ }
20
+
21
+ .item {
22
+ position: relative;
23
+ display: flex;
24
+ flex-direction: column;
25
+ align-items: center;
26
+ justify-content: center;
27
+ width: 100%;
28
+ min-height: 3.5rem; /* 56dp */
29
+ padding-block: 0.25rem; /* 4dp vertical padding */
30
+ cursor: pointer;
31
+ gap: 0.25rem; /* 4dp gap between indicator and label */
32
+ box-sizing: border-box;
33
+
34
+ /* Color tokens */
35
+ --_inactive-icon-color: var(--nav-rail-inactive-icon-color, var(--color-on-surface-variant));
36
+ --_active-icon-color: var(--nav-rail-active-icon-color, var(--color-on-secondary-container));
37
+ --_inactive-label-color: var(--nav-rail-inactive-label-color, var(--color-on-surface-variant));
38
+ --_active-label-color: var(--nav-rail-active-label-color, var(--color-on-surface));
39
+ --_indicator-color: var(--nav-rail-indicator-color, var(--color-secondary-container));
40
+ --_indicator-shape: var(--nav-rail-indicator-shape, var(--shape-corner-full));
41
+ --_indicator-width: var(--nav-rail-indicator-width, 3.5rem); /* 56dp */
42
+ --_indicator-height: var(--nav-rail-indicator-height, 2rem); /* 32dp */
43
+ --_state-color: var(--_inactive-icon-color);
44
+
45
+ /* Focus ring */
46
+ .focus-ring {
47
+ z-index: 3;
48
+ --focus-ring-container-shape-start-start: var(--shape-corner-small);
49
+ --focus-ring-container-shape-start-end: var(--shape-corner-small);
50
+ --focus-ring-container-shape-end-start: var(--shape-corner-small);
51
+ --focus-ring-container-shape-end-end: var(--shape-corner-small);
52
+ }
53
+
54
+ /* Active indicator (pill behind icon) */
55
+ .indicator {
56
+ position: relative;
57
+ display: flex;
58
+ align-items: center;
59
+ justify-content: center;
60
+ width: var(--_indicator-width);
61
+ height: var(--_indicator-height);
62
+ border-radius: var(--_indicator-shape);
63
+ overflow: hidden;
64
+ flex-shrink: 0;
65
+ transition: background-color var(--duration-short4, 200ms) var(--easing-standard, ease);
66
+
67
+ .icon-container {
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ z-index: 1;
72
+ position: relative;
73
+ pointer-events: none;
74
+
75
+ ::slotted(*) {
76
+ --icon-size: 1.5rem; /* 24dp */
77
+ --icon-color: var(--_inactive-icon-color);
78
+ color: var(--_inactive-icon-color);
79
+ display: flex;
80
+ }
81
+ }
82
+ }
83
+
84
+ /* State layer for hover/press */
85
+ .state-layer {
86
+ position: absolute;
87
+ top: 0.25rem;
88
+ left: 50%;
89
+ transform: translateX(-50%);
90
+ width: var(--_indicator-width);
91
+ height: var(--_indicator-height);
92
+ pointer-events: none;
93
+ background-color: var(--_state-color);
94
+ opacity: 0;
95
+ z-index: 0;
96
+ border-radius: var(--_indicator-shape);
97
+ transition: opacity var(--duration-short4, 200ms) var(--easing-standard, ease);
98
+ }
99
+
100
+ .ripple {
101
+ z-index: 1;
102
+ --ripple-pressed-color: var(--_state-color);
103
+ --ripple-state-opacity: 0;
104
+ border-radius: var(--shape-corner-small, 4px);
105
+ }
106
+
107
+ /* Label */
108
+ .label {
109
+ @include mixin.get-typography('label-medium');
110
+ color: var(--_inactive-label-color);
111
+ text-align: center;
112
+ pointer-events: none;
113
+ z-index: 1;
114
+ transition: color var(--duration-short4, 200ms) var(--easing-standard, ease),
115
+ font-weight var(--duration-short4, 200ms) var(--easing-standard, ease);
116
+ }
117
+
118
+ /* Active icon slot: hidden by default */
119
+ .active-icon-slot {
120
+ display: none;
121
+ }
122
+
123
+ .hidden-slot {
124
+ display: none;
125
+ }
126
+
127
+ /* Item content layout */
128
+ .item-content {
129
+ display: flex;
130
+ flex-direction: column;
131
+ align-items: center;
132
+ gap: 0.25rem;
133
+ width: 100%;
134
+ z-index: 1;
135
+ }
136
+
137
+ /* Active state */
138
+ &.active {
139
+ --_state-color: var(--_active-icon-color);
140
+
141
+ .indicator {
142
+ background-color: var(--_indicator-color);
143
+
144
+ .icon-container {
145
+ ::slotted(*) {
146
+ --icon-color: var(--_active-icon-color);
147
+ color: var(--_active-icon-color);
148
+ }
149
+ }
150
+ }
151
+
152
+ .label {
153
+ color: var(--_active-label-color);
154
+ font-weight: var(--typography-label-medium-font-weight-bold, 700);
155
+ }
156
+ }
157
+
158
+ /* Active icon slot: show when active and slot has content */
159
+ &.active.has-active-icon {
160
+ .active-icon-slot {
161
+ display: flex;
162
+ }
163
+
164
+ .icon-slot {
165
+ display: none;
166
+ }
167
+ }
168
+
169
+ /* Hover state */
170
+ &:hover:not(.disabled) {
171
+ .state-layer {
172
+ opacity: 0.08;
173
+ }
174
+ }
175
+
176
+ /* Pressed state */
177
+ &.pressed:not(.disabled) {
178
+ .state-layer {
179
+ opacity: 0.12;
180
+ }
181
+ }
182
+
183
+ /* Disabled state */
184
+ &.disabled {
185
+ cursor: not-allowed;
186
+
187
+ .indicator {
188
+ .icon-container {
189
+ ::slotted(*) {
190
+ --icon-color: var(--color-on-surface);
191
+ color: var(--color-on-surface);
192
+ opacity: 0.38;
193
+ }
194
+ }
195
+ }
196
+
197
+ .label {
198
+ color: var(--color-on-surface);
199
+ opacity: 0.38;
200
+ }
201
+
202
+ .ripple {
203
+ display: none;
204
+ }
205
+ }
206
+ }
207
+
208
+ @media (prefers-reduced-motion: reduce) {
209
+ .item {
210
+ .indicator,
211
+ .state-layer,
212
+ .label {
213
+ transition: none;
214
+ }
215
+ }
216
+ }
@@ -0,0 +1,223 @@
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';
4
+ import { dispatchActivationClick, isActivationClick } from '@/__utils/dispatch-event-utils.js';
5
+ import { observerSlotChangesWithCallback } from '@/__utils/observe-slot-change.js';
6
+ import { throttle } from '@/__utils/throttle.js';
7
+ import styles from './navigation-rail-item.scss';
8
+
9
+ /**
10
+ * @label Navigation Rail Item
11
+ * @tag wc-navigation-rail-item
12
+ * @rawTag navigation-rail-item
13
+ * @parentRawTag navigation-rail
14
+ *
15
+ * @summary An individual item within a navigation rail.
16
+ * @overview
17
+ * <p>Navigation rail items display a destination with an icon and optional label.</p>
18
+ *
19
+ * @example
20
+ * ```html
21
+ * <wc-navigation-rail-item>
22
+ * <wc-icon slot="icon">home</wc-icon>
23
+ * Home
24
+ * </wc-navigation-rail-item>
25
+ * ```
26
+ * @tags navigation
27
+ */
28
+ export class NavigationRailItem extends LitElement {
29
+ #id = crypto.randomUUID();
30
+
31
+ static styles = [styles];
32
+
33
+ /** Whether this item is currently active/selected. */
34
+ @property({ type: Boolean, reflect: true }) active = false;
35
+
36
+ /** Whether this item is disabled. */
37
+ @property({ type: Boolean, reflect: true }) disabled = false;
38
+
39
+ /** Whether the parent rail is in collapsed mode (labels hidden). */
40
+ @property({ type: Boolean, reflect: true }) collapsed = false;
41
+
42
+ /** If provided, the item renders as a link. */
43
+ @property({ reflect: true }) href?: string;
44
+
45
+ /** Link target. */
46
+ @property() target: string = '_self';
47
+
48
+ /** Value used for identification when managing active state externally. */
49
+ @property({ reflect: true }) value?: string;
50
+
51
+ /** Reason the item is disabled (shown to screen readers). */
52
+ @property({ attribute: 'disabled-reason' }) disabledReason: string = '';
53
+
54
+ /** Sets the delay for throttle in milliseconds. Defaults to 200 milliseconds. */
55
+ @property({ type: Number }) throttleDelay = 200;
56
+
57
+ @state() private _isPressed = false;
58
+
59
+ @state() private _hasLabel = false;
60
+
61
+ @state() private _hasActiveIcon = false;
62
+
63
+ @query('.item-element') readonly itemElement!: HTMLElement | null;
64
+
65
+ override focus() {
66
+ this.itemElement?.focus();
67
+ }
68
+
69
+ override blur() {
70
+ this.itemElement?.blur();
71
+ }
72
+
73
+ override firstUpdated() {
74
+ this.__dispatchClickWithThrottle = throttle(
75
+ this.__dispatchClick,
76
+ this.throttleDelay,
77
+ );
78
+
79
+ observerSlotChangesWithCallback(
80
+ this.renderRoot.querySelector('slot:not([name])'),
81
+ hasContent => {
82
+ this._hasLabel = hasContent;
83
+ this.requestUpdate();
84
+ },
85
+ );
86
+
87
+ observerSlotChangesWithCallback(
88
+ this.renderRoot.querySelector('slot[name="active-icon"]'),
89
+ hasContent => {
90
+ this._hasActiveIcon = hasContent;
91
+ this.requestUpdate();
92
+ },
93
+ );
94
+ }
95
+
96
+ __dispatchClickWithThrottle: (event: MouseEvent | KeyboardEvent) => void =
97
+ event => {
98
+ this.__dispatchClick(event);
99
+ };
100
+
101
+ __dispatchClick = (event: MouseEvent | KeyboardEvent) => {
102
+ if (this.disabled && this.href) {
103
+ event.stopImmediatePropagation();
104
+ event.preventDefault();
105
+ return;
106
+ }
107
+
108
+ if (!isActivationClick(event) || !this.itemElement) {
109
+ return;
110
+ }
111
+
112
+ this.focus();
113
+ dispatchActivationClick(this.itemElement);
114
+ };
115
+
116
+ __handlePress = (event: KeyboardEvent | MouseEvent) => {
117
+ if (this.disabled) return;
118
+ if (
119
+ event instanceof KeyboardEvent &&
120
+ event.type === 'keydown' &&
121
+ (event.key === 'Enter' || event.key === ' ')
122
+ ) {
123
+ this._isPressed = true;
124
+ } else if (event.type === 'mousedown') {
125
+ this._isPressed = true;
126
+ } else {
127
+ this._isPressed = false;
128
+ }
129
+ };
130
+
131
+ __isLink() {
132
+ return !!this.href;
133
+ }
134
+
135
+ __getDisabledReasonID() {
136
+ return this.disabled && this.disabledReason
137
+ ? `disabled-reason-${this.#id}`
138
+ : nothing;
139
+ }
140
+
141
+ __renderDisabledReason() {
142
+ const disabledReasonID = this.__getDisabledReasonID();
143
+ if (disabledReasonID)
144
+ return html`<div
145
+ id="disabled-reason-${this.#id}"
146
+ role="tooltip"
147
+ aria-label=${this.disabledReason}
148
+ class="screen-reader-only"
149
+ >
150
+ ${this.disabledReason}
151
+ </div>`;
152
+ return nothing;
153
+ }
154
+
155
+ __renderItemContent() {
156
+ return html`
157
+ <wc-focus-ring class="focus-ring" for='item'></wc-focus-ring>
158
+ <div class="state-layer"></div>
159
+ <wc-ripple class="ripple"></wc-ripple>
160
+
161
+ <div class="item-content">
162
+ <div class="indicator">
163
+ <div class="icon-container">
164
+ <slot name="active-icon" class="active-icon-slot"></slot>
165
+ <slot name="icon" class="icon-slot"></slot>
166
+ </div>
167
+ </div>
168
+ ${this._hasLabel && !this.collapsed
169
+ ? html`<div class="label"><slot></slot></div>`
170
+ : html`<slot class="hidden-slot"></slot>`}
171
+ </div>
172
+
173
+ ${this.__renderDisabledReason()}
174
+ `;
175
+ }
176
+
177
+ render() {
178
+ const isLink = this.__isLink();
179
+
180
+ const cssClasses = {
181
+ item: true,
182
+ 'item-element': true,
183
+ active: this.active,
184
+ disabled: this.disabled,
185
+ pressed: this._isPressed,
186
+ 'has-label': this._hasLabel,
187
+ 'has-active-icon': this._hasActiveIcon,
188
+ };
189
+
190
+ if (!isLink) {
191
+ return html`<button
192
+ id="item"
193
+ class=${classMap(cssClasses)}
194
+ ?disabled=${this.disabled}
195
+ aria-disabled=${`${this.disabled}`}
196
+ aria-current=${this.active ? 'page' : nothing}
197
+ ?aria-describedby=${this.__getDisabledReasonID()}
198
+ @click=${this.__dispatchClickWithThrottle}
199
+ @mousedown=${this.__handlePress}
200
+ @keydown=${this.__handlePress}
201
+ @keyup=${this.__handlePress}
202
+ >
203
+ ${this.__renderItemContent()}
204
+ </button>`;
205
+ }
206
+
207
+ return html`<a
208
+ id="item"
209
+ class=${classMap(cssClasses)}
210
+ href=${this.href}
211
+ target=${this.target}
212
+ aria-current=${this.active ? 'page' : nothing}
213
+ aria-disabled=${`${this.disabled}`}
214
+ ?aria-describedby=${this.__getDisabledReasonID()}
215
+ @click=${this.__dispatchClickWithThrottle}
216
+ @mousedown=${this.__handlePress}
217
+ @keydown=${this.__handlePress}
218
+ @keyup=${this.__handlePress}
219
+ >
220
+ ${this.__renderItemContent()}
221
+ </a>`;
222
+ }
223
+ }