@redvars/peacock 3.3.3 → 3.5.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 (280) hide show
  1. package/dist/IndividualComponent-DUINtMGK.js +67 -0
  2. package/dist/IndividualComponent-DUINtMGK.js.map +1 -0
  3. package/dist/assets/images/empty-state/no-document.svg +11 -12
  4. package/dist/assets/images/empty-state/page.svg +15 -9
  5. package/dist/assets/styles.css +1 -1
  6. package/dist/assets/styles.css.map +1 -1
  7. package/dist/banner.js +202 -0
  8. package/dist/banner.js.map +1 -0
  9. package/dist/bottom-sheet.js +238 -0
  10. package/dist/bottom-sheet.js.map +1 -0
  11. package/dist/{button-ClzS8JLq.js → button-DMN1dPAg.js} +358 -218
  12. package/dist/button-DMN1dPAg.js.map +1 -0
  13. package/dist/button-group-CX9CUUXk.js +435 -0
  14. package/dist/button-group-CX9CUUXk.js.map +1 -0
  15. package/dist/button-group.js +11 -6
  16. package/dist/button-group.js.map +1 -1
  17. package/dist/button.js +10 -5
  18. package/dist/button.js.map +1 -1
  19. package/dist/card-content.js +29 -0
  20. package/dist/card-content.js.map +1 -0
  21. package/dist/card.js +428 -44
  22. package/dist/card.js.map +1 -1
  23. package/dist/{chart-bar-DbnXQgvS.js → chart-bar-cn6rrna-.js} +2 -2
  24. package/dist/{chart-bar-DbnXQgvS.js.map → chart-bar-cn6rrna-.js.map} +1 -1
  25. package/dist/chart-bar.js +5 -4
  26. package/dist/chart-bar.js.map +1 -1
  27. package/dist/chart-doughnut.js +2 -1
  28. package/dist/chart-doughnut.js.map +1 -1
  29. package/dist/chart-pie.js +2 -1
  30. package/dist/chart-pie.js.map +1 -1
  31. package/dist/chart-stacked-bar.js +5 -4
  32. package/dist/chart-stacked-bar.js.map +1 -1
  33. package/dist/{class-map-59YGWLnx.js → class-map-YU7g0o3B.js} +4 -10
  34. package/dist/class-map-YU7g0o3B.js.map +1 -0
  35. package/dist/clock.js +2 -1
  36. package/dist/clock.js.map +1 -1
  37. package/dist/code-editor.js +8 -6
  38. package/dist/code-editor.js.map +1 -1
  39. package/dist/code-highlighter.js +6 -4
  40. package/dist/code-highlighter.js.map +1 -1
  41. package/dist/custom-elements-jsdocs.json +6270 -5026
  42. package/dist/custom-elements.json +5763 -2049
  43. package/dist/directive-ZPhl09Yt.js +9 -0
  44. package/dist/directive-ZPhl09Yt.js.map +1 -0
  45. package/dist/dispatch-event-utils-CuEqjlPT.js +127 -0
  46. package/dist/dispatch-event-utils-CuEqjlPT.js.map +1 -0
  47. package/dist/fab-C5Nzxk0E.js +497 -0
  48. package/dist/fab-C5Nzxk0E.js.map +1 -0
  49. package/dist/fab.js +11 -0
  50. package/dist/fab.js.map +1 -0
  51. package/dist/index.js +24 -12
  52. package/dist/index.js.map +1 -1
  53. package/dist/{observe-theme-change-pALI5fmV.js → is-dark-mode-DicqGkCJ.js} +8 -3
  54. package/dist/is-dark-mode-DicqGkCJ.js.map +1 -0
  55. package/dist/notification.js +417 -0
  56. package/dist/notification.js.map +1 -0
  57. package/dist/number-counter.js +4 -3
  58. package/dist/number-counter.js.map +1 -1
  59. package/dist/observe-slot-change-BGJfgg2E.js +31 -0
  60. package/dist/observe-slot-change-BGJfgg2E.js.map +1 -0
  61. package/dist/peacock-loader.js +59 -10
  62. package/dist/peacock-loader.js.map +1 -1
  63. package/dist/property-1psGvXOq.js +10 -0
  64. package/dist/property-1psGvXOq.js.map +1 -0
  65. package/dist/search.js +452 -0
  66. package/dist/search.js.map +1 -0
  67. package/dist/{radio-b70_Ie9n.js → select-4pl4XBj7.js} +2439 -521
  68. package/dist/select-4pl4XBj7.js.map +1 -0
  69. package/dist/side-sheet.js +186 -0
  70. package/dist/side-sheet.js.map +1 -0
  71. package/dist/spread-B5cgadZl.js +32 -0
  72. package/dist/spread-B5cgadZl.js.map +1 -0
  73. package/dist/src/__base_element/BaseHyperlink.d.ts +20 -0
  74. package/dist/src/__utils/cache-fetch.d.ts +1 -0
  75. package/dist/src/__utils/is-dark-mode.d.ts +1 -0
  76. package/dist/src/__utils/is-in-viewport.d.ts +1 -0
  77. package/dist/src/__utils/observe-slot-change.d.ts +1 -0
  78. package/dist/src/__utils/sanitize-svg.d.ts +1 -0
  79. package/dist/src/__utils/throttle.d.ts +4 -0
  80. package/dist/src/accordion/accordion-item.d.ts +33 -9
  81. package/dist/src/accordion/accordion.d.ts +21 -5
  82. package/dist/src/banner/banner.d.ts +47 -0
  83. package/dist/src/banner/index.d.ts +1 -0
  84. package/dist/src/bottom-sheet/bottom-sheet.d.ts +42 -0
  85. package/dist/src/bottom-sheet/index.d.ts +1 -0
  86. package/dist/src/button/BaseButton.d.ts +7 -13
  87. package/dist/src/button/button/button.d.ts +4 -0
  88. package/dist/src/button/button-group/button-group.d.ts +32 -3
  89. package/dist/src/button/icon-button/icon-button.d.ts +4 -0
  90. package/dist/src/card/card-content.d.ts +15 -0
  91. package/dist/src/card/card.d.ts +37 -3
  92. package/dist/src/card/index.d.ts +1 -0
  93. package/dist/src/container/container.d.ts +1 -1
  94. package/dist/src/empty-state/empty-state.d.ts +1 -1
  95. package/dist/src/fab/fab.d.ts +111 -0
  96. package/dist/src/fab/index.d.ts +1 -0
  97. package/dist/src/focus-ring/focus-ring.d.ts +4 -1
  98. package/dist/src/index.d.ts +11 -1
  99. package/dist/src/link/link.d.ts +3 -10
  100. package/dist/src/menu/menu/menu.d.ts +4 -2
  101. package/dist/src/menu/menu-item/menu-item.d.ts +0 -1
  102. package/dist/src/menu/sub-menu/sub-menu.d.ts +1 -0
  103. package/dist/src/notification/index.d.ts +1 -0
  104. package/dist/src/notification/notification.d.ts +69 -0
  105. package/dist/src/pagination/pagination.d.ts +8 -1
  106. package/dist/src/ripple/ripple.d.ts +19 -3
  107. package/dist/src/search/index.d.ts +1 -0
  108. package/dist/src/search/search.d.ts +76 -0
  109. package/dist/src/segmented-button/index.d.ts +2 -0
  110. package/dist/src/segmented-button/segmented-button-group.d.ts +46 -0
  111. package/dist/src/segmented-button/segmented-button.d.ts +65 -0
  112. package/dist/src/select/index.d.ts +3 -0
  113. package/dist/src/select/option.d.ts +55 -0
  114. package/dist/src/select/select.d.ts +114 -0
  115. package/dist/src/side-sheet/index.d.ts +1 -0
  116. package/dist/src/side-sheet/side-sheet.d.ts +41 -0
  117. package/dist/src/slider/slider.d.ts +4 -0
  118. package/dist/src/snackbar/snackbar.d.ts +14 -1
  119. package/dist/src/tabs/tab-group.d.ts +0 -1
  120. package/dist/src/tabs/tab.d.ts +8 -2
  121. package/dist/src/tabs/tabs.d.ts +13 -1
  122. package/dist/src/toolbar/index.d.ts +1 -0
  123. package/dist/src/toolbar/toolbar.d.ts +86 -0
  124. package/dist/state-DwbEjqVk.js +10 -0
  125. package/dist/state-DwbEjqVk.js.map +1 -0
  126. package/dist/{style-map-DcB52w-l.js → style-map-DVmWOuYy.js} +3 -3
  127. package/dist/{style-map-DcB52w-l.js.map → style-map-DVmWOuYy.js.map} +1 -1
  128. package/dist/test/search.test.d.ts +1 -0
  129. package/dist/test/toolbar.test.d.ts +1 -0
  130. package/dist/throttle-C7ZAPqtu.js +24 -0
  131. package/dist/throttle-C7ZAPqtu.js.map +1 -0
  132. package/dist/toolbar.js +306 -0
  133. package/dist/toolbar.js.map +1 -0
  134. package/dist/tsconfig.tsbuildinfo +1 -1
  135. package/dist/{unsafe-html-C2r3PyzF.js → unsafe-html-BsGUjx94.js} +3 -3
  136. package/dist/{unsafe-html-C2r3PyzF.js.map → unsafe-html-BsGUjx94.js.map} +1 -1
  137. package/package.json +1 -1
  138. package/readme.md +2 -2
  139. package/scss/styles.scss +4 -0
  140. package/src/__base_element/BaseHyperlink.ts +42 -0
  141. package/src/__base_element/README.md +19 -0
  142. package/src/__utils/cache-fetch.ts +65 -0
  143. package/src/{utils → __utils}/dispatch-event-utils.ts +1 -0
  144. package/src/__utils/is-dark-mode.ts +3 -0
  145. package/src/__utils/is-in-viewport.ts +6 -0
  146. package/src/__utils/observe-slot-change.ts +38 -0
  147. package/src/__utils/sanitize-svg.ts +27 -0
  148. package/src/__utils/throttle.ts +27 -0
  149. package/src/accordion/accordion-item.scss +136 -65
  150. package/src/accordion/accordion-item.ts +117 -44
  151. package/src/accordion/accordion.scss +24 -5
  152. package/src/accordion/accordion.ts +29 -23
  153. package/src/accordion/demo/index.html +74 -35
  154. package/src/banner/banner.scss +87 -0
  155. package/src/banner/banner.ts +107 -0
  156. package/src/banner/index.ts +1 -0
  157. package/src/bottom-sheet/bottom-sheet.scss +88 -0
  158. package/src/bottom-sheet/bottom-sheet.ts +135 -0
  159. package/src/bottom-sheet/index.ts +1 -0
  160. package/src/button/BaseButton.ts +26 -30
  161. package/src/button/button/button-colors.scss +90 -19
  162. package/src/button/button/button-sizes.scss +39 -19
  163. package/src/button/button/button.scss +117 -116
  164. package/src/button/button/button.ts +29 -6
  165. package/src/button/button-group/button-group.scss +25 -22
  166. package/src/button/button-group/button-group.ts +122 -5
  167. package/src/button/icon-button/icon-button-sizes.scss +35 -15
  168. package/src/button/icon-button/icon-button.ts +25 -12
  169. package/src/card/card-colors.scss +10 -0
  170. package/src/card/card-content.ts +26 -0
  171. package/src/card/card.scss +221 -41
  172. package/src/card/card.ts +251 -8
  173. package/src/card/index.ts +1 -0
  174. package/src/chart-bar/chart-bar.ts +1 -1
  175. package/src/chart-bar/chart-stacked-bar.ts +3 -1
  176. package/src/chart-doughnut/chart-doughnut.ts +1 -1
  177. package/src/chart-pie/chart-pie.ts +1 -1
  178. package/src/checkbox/checkbox.ts +1 -1
  179. package/src/clock/clock.ts +1 -1
  180. package/src/code-editor/code-editor.ts +5 -5
  181. package/src/code-highlighter/code-highlighter.ts +2 -2
  182. package/src/container/container.ts +1 -1
  183. package/src/date-picker/date-picker.ts +5 -2
  184. package/src/divider/divider.ts +3 -1
  185. package/src/empty-state/empty-state.scss +9 -3
  186. package/src/empty-state/empty-state.ts +2 -2
  187. package/src/fab/fab-colors.scss +49 -0
  188. package/src/fab/fab-sizes.scss +47 -0
  189. package/src/fab/fab.scss +137 -0
  190. package/src/fab/fab.ts +285 -0
  191. package/src/fab/index.ts +1 -0
  192. package/src/field/field.ts +3 -1
  193. package/src/focus-ring/focus-ring.ts +37 -19
  194. package/src/icon/datasource.ts +1 -1
  195. package/src/icon/icon.ts +3 -1
  196. package/src/image/image.ts +3 -2
  197. package/src/index.ts +12 -1
  198. package/src/input/input.ts +5 -2
  199. package/src/link/link.ts +2 -15
  200. package/src/menu/menu/menu.scss +31 -3
  201. package/src/menu/menu/menu.ts +30 -6
  202. package/src/menu/menu-item/menu-item.scss +1 -0
  203. package/src/menu/menu-item/menu-item.ts +1 -9
  204. package/src/menu/sub-menu/sub-menu.ts +1 -0
  205. package/src/notification/index.ts +1 -0
  206. package/src/notification/notification.scss +201 -0
  207. package/src/notification/notification.ts +206 -0
  208. package/src/number-counter/number-counter.ts +3 -1
  209. package/src/number-field/number-field.ts +4 -2
  210. package/src/pagination/pagination.scss +33 -24
  211. package/src/pagination/pagination.ts +113 -60
  212. package/src/peacock-loader.ts +48 -0
  213. package/src/radio/radio.ts +3 -1
  214. package/src/ripple/ripple.ts +19 -3
  215. package/src/search/index.ts +1 -0
  216. package/src/search/search-colors.scss +14 -0
  217. package/src/search/search.scss +204 -0
  218. package/src/search/search.ts +240 -0
  219. package/src/segmented-button/index.ts +2 -0
  220. package/src/segmented-button/segmented-button-group.scss +21 -0
  221. package/src/segmented-button/segmented-button-group.ts +110 -0
  222. package/src/segmented-button/segmented-button.scss +115 -0
  223. package/src/segmented-button/segmented-button.ts +175 -0
  224. package/src/select/index.ts +3 -0
  225. package/src/select/option.ts +109 -0
  226. package/src/select/select.scss +125 -0
  227. package/src/select/select.ts +520 -0
  228. package/src/side-sheet/index.ts +1 -0
  229. package/src/side-sheet/side-sheet.scss +79 -0
  230. package/src/side-sheet/side-sheet.ts +100 -0
  231. package/src/slider/slider.scss +19 -1
  232. package/src/slider/slider.ts +30 -19
  233. package/src/snackbar/snackbar.scss +62 -31
  234. package/src/snackbar/snackbar.ts +92 -12
  235. package/src/switch/switch.ts +3 -1
  236. package/src/table/table.ts +3 -1
  237. package/src/tabs/demo/index.html +90 -0
  238. package/src/tabs/tab-group.ts +0 -3
  239. package/src/tabs/tab.scss +237 -25
  240. package/src/tabs/tab.ts +91 -14
  241. package/src/tabs/tabs.scss +37 -3
  242. package/src/tabs/tabs.ts +118 -2
  243. package/src/textarea/textarea.ts +4 -2
  244. package/src/time-picker/time-picker.ts +4 -2
  245. package/src/toolbar/index.ts +1 -0
  246. package/src/toolbar/toolbar-colors.scss +16 -0
  247. package/src/toolbar/toolbar.scss +165 -0
  248. package/src/toolbar/toolbar.ts +137 -0
  249. package/dist/IndividualComponent-Dt5xirYG.js +0 -73
  250. package/dist/IndividualComponent-Dt5xirYG.js.map +0 -1
  251. package/dist/button-ClzS8JLq.js.map +0 -1
  252. package/dist/button-group-BMS5WvaF.js +0 -292
  253. package/dist/button-group-BMS5WvaF.js.map +0 -1
  254. package/dist/chart-donut.js +0 -309
  255. package/dist/chart-donut.js.map +0 -1
  256. package/dist/class-map-59YGWLnx.js.map +0 -1
  257. package/dist/directive-Cuw6h7YA.js +0 -9
  258. package/dist/directive-Cuw6h7YA.js.map +0 -1
  259. package/dist/dispatch-event-utils-B4odODQf.js +0 -277
  260. package/dist/dispatch-event-utils-B4odODQf.js.map +0 -1
  261. package/dist/observe-theme-change-pALI5fmV.js.map +0 -1
  262. package/dist/radio-b70_Ie9n.js.map +0 -1
  263. package/dist/src/chart-donut/chart-donut.d.ts +0 -53
  264. package/dist/src/chart-donut/index.d.ts +0 -1
  265. package/dist/src/styleMixins.css.d.ts +0 -9
  266. package/dist/src/utils.d.ts +0 -9
  267. package/src/chart-donut/chart-donut.scss +0 -37
  268. package/src/chart-donut/chart-donut.ts +0 -287
  269. package/src/chart-donut/demo/index.html +0 -51
  270. package/src/chart-donut/index.ts +0 -1
  271. package/src/styleMixins.css.ts +0 -55
  272. package/src/utils.ts +0 -193
  273. /package/dist/src/{spread.d.ts → __directive/spread.d.ts} +0 -0
  274. /package/dist/src/{utils → __utils}/copy-to-clipboard.d.ts +0 -0
  275. /package/dist/src/{utils → __utils}/dispatch-event-utils.d.ts +0 -0
  276. /package/dist/src/{utils → __utils}/observe-theme-change.d.ts +0 -0
  277. /package/dist/test/{card.test.d.ts → banner.test.d.ts} +0 -0
  278. /package/src/{spread.ts → __directive/spread.ts} +0 -0
  279. /package/src/{utils → __utils}/copy-to-clipboard.ts +0 -0
  280. /package/src/{utils → __utils}/observe-theme-change.ts +0 -0
@@ -1,5 +1,5 @@
1
- import { html, LitElement } from 'lit';
2
- import { property, query } from 'lit/decorators.js';
1
+ import { html, LitElement, nothing } from 'lit';
2
+ import { property, query, state } from 'lit/decorators.js';
3
3
  import { classMap } from 'lit/directives/class-map.js';
4
4
  import styles from './accordion-item.scss';
5
5
 
@@ -7,13 +7,27 @@ import styles from './accordion-item.scss';
7
7
  * @label Accordion Item
8
8
  * @tag wc-accordion-item
9
9
  * @rawTag accordion-item
10
- * @summary An accordion item is single item in an accordion list. It contains a header and a content section that can be expanded or collapsed by the user.
10
+ * @summary An expansion panel with a header that reveals or hides associated content. Follows Material Design 3 expansion panel guidelines.
11
11
  * @parentRawTag accordion
12
- *
12
+ *
13
+ * @slot - The body content revealed when the panel is expanded.
14
+ * @slot heading - The panel title. Renders as `body-large` text.
15
+ * @slot description - Optional subtitle rendered below the title. Renders as `body-small` text.
16
+ * @slot header-actions - Actions (e.g. icon buttons) placed at the trailing end of the header, before the toggle icon.
17
+ *
18
+ * @part header - The header `<button>` element.
19
+ * @part title - The title text container.
20
+ * @part description - The description text container.
21
+ * @part content - The expandable content region wrapper.
22
+ *
23
+ * @fires {CustomEvent<{ open: boolean }>} accordion-item:toggle - Fired when the panel is expanded or collapsed.
24
+ *
13
25
  * @example
14
26
  * ```html
15
27
  * <wc-accordion-item>
16
- * Testing
28
+ * <span slot="heading">Personal information</span>
29
+ * <span slot="description">Fill in your details</span>
30
+ * <p>Content goes here.</p>
17
31
  * </wc-accordion-item>
18
32
  * ```
19
33
  * @tags display
@@ -24,24 +38,38 @@ export class AccordionItem extends LitElement {
24
38
  #id = crypto.randomUUID();
25
39
 
26
40
  /**
27
- * The menu item value.
28
- */
29
- @property({ type: String, reflect: true })
30
- heading: string = '';
31
-
32
- /**
33
- * If true, the user cannot interact with the button. Defaults to `false`.
41
+ * Whether the user cannot interact with the panel.
34
42
  */
35
43
  @property({ type: Boolean, reflect: true })
36
44
  disabled: boolean = false;
37
45
 
38
46
  /**
39
- * Menu item selection state.
47
+ * Whether the panel is expanded.
40
48
  */
41
49
  @property({ type: Boolean, reflect: true })
42
50
  open: boolean = false;
43
51
 
44
- @query('.accordion-heading')
52
+ /**
53
+ * Whether to hide the expand/collapse toggle indicator icon.
54
+ */
55
+ @property({ type: Boolean, reflect: true, attribute: 'hide-toggle' })
56
+ hideToggle: boolean = false;
57
+
58
+ /**
59
+ * Position of the toggle icon relative to the panel title.
60
+ * `'after'` places it at the trailing end (default, matches M3).
61
+ * `'before'` places it at the leading start.
62
+ */
63
+ @property({ type: String, reflect: true, attribute: 'toggle-position' })
64
+ togglePosition: 'before' | 'after' = 'after';
65
+
66
+ @state()
67
+ private _hasDescriptionSlot = false;
68
+
69
+ @state()
70
+ private _hasHeadingSlot = false;
71
+
72
+ @query('.header-button')
45
73
  private readonly buttonElement!: HTMLElement | null;
46
74
 
47
75
  override focus() {
@@ -52,48 +80,93 @@ export class AccordionItem extends LitElement {
52
80
  this.buttonElement?.blur();
53
81
  }
54
82
 
55
- private __handleToggle() {
83
+ private _handleToggle() {
56
84
  if (this.disabled) return;
57
85
  this.open = !this.open;
58
86
  this.dispatchEvent(
59
- new CustomEvent('accordion-item--toggle', {
87
+ new CustomEvent('accordion-item:toggle', {
60
88
  bubbles: true,
61
89
  composed: true,
62
- detail: { open: this.open, id: this.#id },
90
+ detail: { open: this.open },
63
91
  }),
64
92
  );
65
93
  }
66
94
 
95
+ private static _onSlotChange(e: Event, setter: (v: boolean) => void) {
96
+ const slot = e.target as HTMLSlotElement;
97
+ const nodes = slot.assignedNodes({ flatten: true });
98
+ setter(
99
+ nodes.some(n =>
100
+ n.nodeType === Node.TEXT_NODE
101
+ ? (n.textContent?.trim() ?? '') !== ''
102
+ : true,
103
+ ),
104
+ );
105
+ }
106
+
107
+ private _renderToggleIcon() {
108
+ if (this.hideToggle) return nothing;
109
+ return html`<wc-icon
110
+ class="toggle-icon"
111
+ name="keyboard_arrow_down"
112
+ aria-hidden="true"
113
+ ></wc-icon>`;
114
+ }
115
+
67
116
  render() {
68
- return html`<div
69
- class=${classMap({
70
- 'accordion-item': true,
71
- open: this.open,
72
- disabled: this.disabled,
73
- })}
74
- >
75
- <button
76
- id=${`accordion-heading-${this.#id}`}
77
- tabindex="0"
78
- aria-controls=${`accordion-control-${this.#id}`}
79
- class="accordion-heading"
80
- aria-disabled=${this.disabled}
81
- @click=${this.__handleToggle}
82
- aria-expanded=${this.open}
83
- >
84
- <wc-icon class="accordion-icon" name="keyboard_arrow_down"></wc-icon>
85
- <div part="title" class="accordion-title">
86
- <slot name="heading">${this.heading}</slot>
87
- </div>
88
- </button>
117
+ return html`
89
118
  <div
90
- class="item-section slot-main"
91
- id=${`accordion-control-${this.#id}`}
92
- aria-labelledby=${`accordion-heading-${this.#id}`}
93
- role="region"
119
+ class=${classMap({
120
+ 'expansion-panel': true,
121
+ open: this.open,
122
+ disabled: this.disabled,
123
+ })}
94
124
  >
95
- <slot></slot>
125
+ <button
126
+ id=${`panel-header-${this.#id}`}
127
+ part="header"
128
+ class="header-button"
129
+ tabindex=${this.disabled ? '-1' : '0'}
130
+ aria-controls=${`panel-content-${this.#id}`}
131
+ aria-disabled=${this.disabled}
132
+ aria-expanded=${this.open}
133
+ ?disabled=${this.disabled}
134
+ @click=${this._handleToggle}
135
+ >
136
+ ${this.togglePosition === 'before' ? this._renderToggleIcon() : nothing}
137
+ <span class="header-label">
138
+ <span part="title" class="panel-title">
139
+ <slot
140
+ name="heading"
141
+ @slotchange=${(e: Event) => AccordionItem._onSlotChange(e, v => { this._hasHeadingSlot = v; })}
142
+ ></slot>
143
+ </span>
144
+ <span
145
+ part="description"
146
+ class="panel-description"
147
+ ?hidden=${!this._hasDescriptionSlot}
148
+ >
149
+ <slot
150
+ name="description"
151
+ @slotchange=${(e: Event) => AccordionItem._onSlotChange(e, v => { this._hasDescriptionSlot = v; })}
152
+ ></slot>
153
+ </span>
154
+ </span>
155
+ <slot name="header-actions" class="header-actions"></slot>
156
+ ${this.togglePosition === 'after' ? this._renderToggleIcon() : nothing}
157
+ </button>
158
+ <div
159
+ id=${`panel-content-${this.#id}`}
160
+ part="content"
161
+ class="panel-content"
162
+ role="region"
163
+ aria-labelledby=${`panel-header-${this.#id}`}
164
+ >
165
+ <div class="content-inner">
166
+ <slot></slot>
167
+ </div>
168
+ </div>
96
169
  </div>
97
- </div>`;
170
+ `;
98
171
  }
99
172
  }
@@ -2,15 +2,34 @@
2
2
 
3
3
  @include mixin.base-styles;
4
4
 
5
+ // ─── Host ────────────────────────────────────────────────────────────────────
6
+
5
7
  :host {
6
8
  display: block;
7
9
  }
8
10
 
9
- slot::slotted(:not(:last-child)) {
10
- border-block-start: 1px solid var(--color-outline);
11
+ // ─── Default display mode ────────────────────────────────────────────────────
12
+ // Each item is a fully-bordered rounded container (M3 expansion panel shape).
13
+ // Items are stacked with a gap; no shared dividers.
14
+
15
+ .accordion {
16
+ display: flex;
17
+ flex-direction: column;
18
+ gap: var(--spacing-100); // 8dp gap between panels
11
19
  }
12
20
 
13
- slot::slotted(:last-child) {
14
- border-block-start: 1px solid var(--color-outline);
15
- border-block-end: 1px solid var(--color-outline);
21
+ // ─── Flat display mode ───────────────────────────────────────────────────────
22
+ // Removes the gap and the per-item border/background for use inside cards.
23
+
24
+ :host([display-mode='flat']) {
25
+ .accordion {
26
+ gap: 0;
27
+ }
28
+
29
+ // Push overrides into each item via inherited CSS custom properties.
30
+ // wc-accordion-item reads --_accordion-item-border / --_accordion-item-background.
31
+ slot::slotted(wc-accordion-item) {
32
+ --_accordion-item-border: none;
33
+ --_accordion-item-background: transparent;
34
+ }
16
35
  }
@@ -7,14 +7,20 @@ import { AccordionItem } from './accordion-item.js';
7
7
  * @label Accordion
8
8
  * @tag wc-accordion
9
9
  * @rawTag accordion
10
- * @summary An accordion is a vertically stacked list of headers that reveal or hide associated sections of content.
10
+ * @summary A vertically stacked set of expansion panels. Follows Material Design 3 expansion panel guidelines.
11
11
  *
12
12
  * @example
13
13
  * ```html
14
14
  * <wc-accordion>
15
- * <wc-accordion-item heading="Accordion">
16
- * Content
17
- * </wc-accordion-item>
15
+ * <wc-accordion-item>
16
+ * <span slot="heading">Panel 1</span>
17
+ * <span slot="description">Summary text</span>
18
+ * Content
19
+ * </wc-accordion-item>
20
+ * <wc-accordion-item>
21
+ * <span slot="heading">Panel 2</span>
22
+ * Content
23
+ * </wc-accordion-item>
18
24
  * </wc-accordion>
19
25
  * ```
20
26
  * @tags display
@@ -22,10 +28,22 @@ import { AccordionItem } from './accordion-item.js';
22
28
  export class Accordion extends LitElement {
23
29
  static styles = [styles];
24
30
 
25
- @property({ type: Boolean, attribute: 'allow-multiple' })
26
- allowMultiple = false;
31
+ /**
32
+ * Whether multiple panels can be expanded simultaneously.
33
+ * When `false` (default), expanding one panel collapses all others.
34
+ */
35
+ @property({ type: Boolean, reflect: true })
36
+ multi = false;
27
37
 
28
- @queryAssignedElements({ selector: 'p-accordion-item' })
38
+ /**
39
+ * Display mode for the accordion.
40
+ * `'default'` renders panels with a subtle background on expand and dividers between items.
41
+ * `'flat'` renders panels without borders or background changes — suitable for use inside cards.
42
+ */
43
+ @property({ type: String, reflect: true, attribute: 'display-mode' })
44
+ displayMode: 'default' | 'flat' = 'default';
45
+
46
+ @queryAssignedElements({ selector: 'wc-accordion-item' })
29
47
  items!: Array<AccordionItem>;
30
48
 
31
49
  connectedCallback() {
@@ -39,7 +57,6 @@ export class Accordion extends LitElement {
39
57
  disconnectedCallback() {
40
58
  super.disconnectedCallback();
41
59
  // @ts-ignore
42
- // eslint-disable-next-line no-undef
43
60
  this.removeEventListener('accordion-item:toggle', this._onItemToggle);
44
61
  this.removeEventListener('keydown', this._onKeyDown);
45
62
  }
@@ -47,11 +64,10 @@ export class Accordion extends LitElement {
47
64
  private _onItemToggle(e: CustomEvent) {
48
65
  const targetItem = e.target as AccordionItem;
49
66
 
50
- // Stop event bubbling if it came from a nested accordion
51
- // We check if the target item is a direct child of *this* accordion
67
+ // Ignore events from nested accordions only handle direct children
52
68
  if (targetItem.parentElement !== this) return;
53
69
 
54
- if (!this.allowMultiple && targetItem.open) {
70
+ if (!this.multi && targetItem.open) {
55
71
  this.items.forEach(item => {
56
72
  if (item !== targetItem && item.open) {
57
73
  // eslint-disable-next-line no-param-reassign
@@ -62,17 +78,11 @@ export class Accordion extends LitElement {
62
78
  }
63
79
 
64
80
  private _onKeyDown(e: KeyboardEvent) {
65
- // 1. Find which item currently has its HEADER focused.
66
- // We check the shadowRoot of each item to see if the internal <button> is the active element.
67
81
  const focusedItemIndex = this.items.findIndex(item => {
68
- // Access the Shadow DOM of the item
69
82
  const root = item.shadowRoot;
70
- // Check if the focused element inside that shadow DOM is the toggle button
71
- return root?.activeElement?.classList.contains('accordion-heading');
83
+ return root?.activeElement?.classList.contains('header-button');
72
84
  });
73
85
 
74
- // 2. If no header is focused (e.g., focus is on body content or outside), do nothing.
75
- // This prevents stealing focus when the user is typing in a form inside the accordion.
76
86
  if (focusedItemIndex === -1) return;
77
87
 
78
88
  let nextIndex = -1;
@@ -81,12 +91,10 @@ export class Accordion extends LitElement {
81
91
  switch (e.key) {
82
92
  case 'ArrowDown':
83
93
  e.preventDefault();
84
- // Cycle next
85
94
  nextIndex = (focusedItemIndex + 1) % this.items.length;
86
95
  break;
87
96
  case 'ArrowUp':
88
97
  e.preventDefault();
89
- // Cycle previous
90
98
  nextIndex =
91
99
  (focusedItemIndex - 1 + this.items.length) % this.items.length;
92
100
  break;
@@ -100,12 +108,10 @@ export class Accordion extends LitElement {
100
108
  break;
101
109
  }
102
110
 
103
- // 3. Apply Focus
104
111
  if (nextIndex !== -1) {
105
112
  const itemToFocus = this.items[nextIndex];
106
- // Select the button inside the Shadow DOM of the target item
107
113
  const button = itemToFocus.shadowRoot?.querySelector(
108
- '.accordion-heading',
114
+ '.header-button',
109
115
  ) as HTMLElement;
110
116
  button?.focus();
111
117
  }
@@ -9,50 +9,89 @@
9
9
  <style>
10
10
  body {
11
11
  background: #fafafa;
12
+ padding: 2rem;
13
+ max-width: 640px;
14
+ margin: 0 auto;
12
15
  }
13
- .text-body {
14
- padding: 0;
15
- margin: 0 !important;
16
+ h3 {
17
+ margin: 1.5rem 0 0.5rem;
18
+ font-family: sans-serif;
19
+ font-size: 0.875rem;
20
+ color: #666;
16
21
  }
17
22
  </style>
18
23
  </head>
19
24
  <body>
20
25
 
21
- <p-accordion>
22
- <p-accordion-item heading="Title 1">
23
- <p class='text-body'>
24
- The accordion component delivers large amounts of content in a small space through progressive
25
- disclosure.
26
- The user gets key details about the underlying content and can choose to expand that content
27
- within the
28
- constraints of the accordion.
29
- Accordions work especially well on mobile interfaces or whenever vertical space is at a premium.
30
- </p>
31
- </p-accordion-item>
26
+ <h3>Default</h3>
27
+ <wc-accordion>
28
+ <wc-accordion-item>
29
+ <span slot="heading">Personal information</span>
30
+ <span slot="description">Fill in your personal details</span>
31
+ <p>Type in your name and address below.</p>
32
+ </wc-accordion-item>
33
+ <wc-accordion-item>
34
+ <span slot="heading">Shipping address</span>
35
+ <span slot="description">Where should we send your order?</span>
36
+ <p>Add your shipping address to continue.</p>
37
+ </wc-accordion-item>
38
+ <wc-accordion-item disabled>
39
+ <span slot="heading">Billing address</span>
40
+ <p>This section is unavailable.</p>
41
+ </wc-accordion-item>
42
+ </wc-accordion>
32
43
 
33
- <p-accordion-item heading="Title 1">
34
- <p class='text-body'>
35
- The accordion component delivers large amounts of content in a small space through progressive
36
- disclosure.
37
- The user gets key details about the underlying content and can choose to expand that content
38
- within the
39
- constraints of the accordion.
40
- Accordions work especially well on mobile interfaces or whenever vertical space is at a premium.
41
- </p>
42
- </p-accordion-item>
44
+ <h3>Multi (allow multiple panels open)</h3>
45
+ <wc-accordion multi>
46
+ <wc-accordion-item>
47
+ <span slot="heading">Panel A</span>
48
+ <p>Content for panel A.</p>
49
+ </wc-accordion-item>
50
+ <wc-accordion-item open>
51
+ <span slot="heading">Panel B</span>
52
+ <p>Content for panel B (initially open).</p>
53
+ </wc-accordion-item>
54
+ <wc-accordion-item>
55
+ <span slot="heading">Panel C</span>
56
+ <p>Content for panel C.</p>
57
+ </wc-accordion-item>
58
+ </wc-accordion>
43
59
 
44
- <p-accordion-item heading="Title 1" disabled>
45
- <p class='text-body'>
46
- The accordion component delivers large amounts of content in a small space through progressive
47
- disclosure.
48
- The user gets key details about the underlying content and can choose to expand that content
49
- within the
50
- constraints of the accordion.
51
- Accordions work especially well on mobile interfaces or whenever vertical space is at a premium.
52
- </p>
53
- </p-accordion-item>
54
- </p-accordion>
60
+ <h3>Toggle position: before</h3>
61
+ <wc-accordion>
62
+ <wc-accordion-item toggle-position="before">
63
+ <span slot="heading">Panel 1</span>
64
+ <p>Icon appears at the leading start.</p>
65
+ </wc-accordion-item>
66
+ <wc-accordion-item toggle-position="before">
67
+ <span slot="heading">Panel 2</span>
68
+ <p>Icon appears at the leading start.</p>
69
+ </wc-accordion-item>
70
+ </wc-accordion>
55
71
 
72
+ <h3>Hide toggle</h3>
73
+ <wc-accordion>
74
+ <wc-accordion-item hide-toggle>
75
+ <span slot="heading">No toggle icon</span>
76
+ <p>The expand indicator is hidden.</p>
77
+ </wc-accordion-item>
78
+ <wc-accordion-item hide-toggle>
79
+ <span slot="heading">Another panel</span>
80
+ <p>Click the header to toggle.</p>
81
+ </wc-accordion-item>
82
+ </wc-accordion>
83
+
84
+ <h3>Flat display mode</h3>
85
+ <wc-accordion display-mode="flat">
86
+ <wc-accordion-item>
87
+ <span slot="heading">Flat Panel 1</span>
88
+ <p>No borders between panels. Suitable inside cards.</p>
89
+ </wc-accordion-item>
90
+ <wc-accordion-item>
91
+ <span slot="heading">Flat Panel 2</span>
92
+ <p>Content here.</p>
93
+ </wc-accordion-item>
94
+ </wc-accordion>
56
95
 
57
96
  <script type='module' src='/dist/peacock-loader.js'></script>
58
97
  </body>
@@ -0,0 +1,87 @@
1
+ @use '../../scss/mixin';
2
+
3
+ @include mixin.base-styles;
4
+
5
+ :host {
6
+ display: block;
7
+
8
+ --banner-container-color: var(--color-tertiary-container);
9
+ --banner-label-text-color: var(--color-on-tertiary-container);
10
+ --banner-description-text-color: var(--color-on-tertiary-container);
11
+ --banner-icon-color: var(--color-on-tertiary-container);
12
+ --banner-border-radius: var(--shape-corner-small);
13
+ }
14
+
15
+ .banner {
16
+ align-items: flex-start;
17
+ background: var(--banner-container-color);
18
+ border-radius: var(--banner-border-radius);
19
+ display: grid;
20
+ gap: var(--spacing-200);
21
+ grid-template-columns: auto 1fr;
22
+ padding: var(--spacing-200);
23
+ }
24
+
25
+ .banner-icon {
26
+ align-items: center;
27
+ color: var(--banner-icon-color);
28
+ display: inline-flex;
29
+ justify-content: center;
30
+ min-width: 1.5rem;
31
+ padding-top: 0.1rem;
32
+ }
33
+
34
+ .banner-content {
35
+ display: flex;
36
+ flex-direction: column;
37
+ gap: var(--spacing-050);
38
+ }
39
+
40
+ .banner-label {
41
+ @include mixin.get-typography(label-large);
42
+ color: var(--banner-label-text-color);
43
+ }
44
+
45
+ .banner-description {
46
+ @include mixin.get-typography(body-medium);
47
+ color: var(--banner-description-text-color);
48
+ }
49
+
50
+ .banner-content.inline {
51
+ flex-direction: row;
52
+ align-items: baseline;
53
+ flex-wrap: wrap;
54
+ gap: 0.25em;
55
+ }
56
+
57
+ .banner.info,
58
+ .banner-content.info {
59
+ --banner-container-color: var(--color-primary-container);
60
+ --banner-label-text-color: var(--color-on-primary-container);
61
+ --banner-description-text-color: var(--color-on-primary-container);
62
+ --banner-icon-color: var(--color-on-primary-container);
63
+ }
64
+
65
+ .banner.success,
66
+ .banner-content.success {
67
+ --banner-container-color: var(--color-success-container);
68
+ --banner-label-text-color: var(--color-on-success-container);
69
+ --banner-description-text-color: var(--color-on-success-container);
70
+ --banner-icon-color: var(--color-on-success-container);
71
+ }
72
+
73
+ .banner.warning,
74
+ .banner-content.warning {
75
+ --banner-container-color: var(--color-warning-container);
76
+ --banner-label-text-color: var(--color-on-warning-container);
77
+ --banner-description-text-color: var(--color-on-warning-container);
78
+ --banner-icon-color: var(--color-on-warning-container);
79
+ }
80
+
81
+ .banner.error,
82
+ .banner-content.error {
83
+ --banner-container-color: var(--color-error-container);
84
+ --banner-label-text-color: var(--color-on-error-container);
85
+ --banner-description-text-color: var(--color-on-error-container);
86
+ --banner-icon-color: var(--color-on-error-container);
87
+ }