@redvars/peacock 3.3.2 → 3.4.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 (160) 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/bottom-sheet.js +238 -0
  6. package/dist/bottom-sheet.js.map +1 -0
  7. package/dist/{button-ClzS8JLq.js → button-COYCtuA8.js} +306 -149
  8. package/dist/button-COYCtuA8.js.map +1 -0
  9. package/dist/button-group-DsXquZQn.js +440 -0
  10. package/dist/button-group-DsXquZQn.js.map +1 -0
  11. package/dist/button-group.js +6 -4
  12. package/dist/button-group.js.map +1 -1
  13. package/dist/button.js +5 -3
  14. package/dist/button.js.map +1 -1
  15. package/dist/card-content.js +29 -0
  16. package/dist/card-content.js.map +1 -0
  17. package/dist/card.js +418 -44
  18. package/dist/card.js.map +1 -1
  19. package/dist/{chart-bar-DbnXQgvS.js → chart-bar-cn6rrna-.js} +2 -2
  20. package/dist/{chart-bar-DbnXQgvS.js.map → chart-bar-cn6rrna-.js.map} +1 -1
  21. package/dist/chart-bar.js +4 -3
  22. package/dist/chart-bar.js.map +1 -1
  23. package/dist/chart-doughnut.js +2 -1
  24. package/dist/chart-doughnut.js.map +1 -1
  25. package/dist/chart-pie.js +2 -1
  26. package/dist/chart-pie.js.map +1 -1
  27. package/dist/chart-stacked-bar.js +4 -3
  28. package/dist/chart-stacked-bar.js.map +1 -1
  29. package/dist/{class-map-59YGWLnx.js → class-map-3TAnCMAX.js} +3 -9
  30. package/dist/class-map-3TAnCMAX.js.map +1 -0
  31. package/dist/clock.js +2 -1
  32. package/dist/clock.js.map +1 -1
  33. package/dist/code-editor.js +6 -4
  34. package/dist/code-editor.js.map +1 -1
  35. package/dist/code-highlighter.js +5 -3
  36. package/dist/code-highlighter.js.map +1 -1
  37. package/dist/custom-elements-jsdocs.json +2458 -2753
  38. package/dist/custom-elements.json +3185 -777
  39. package/dist/dispatch-event-utils-B4odODQf.js.map +1 -1
  40. package/dist/index.js +14 -10
  41. package/dist/index.js.map +1 -1
  42. package/dist/number-counter.js +3 -2
  43. package/dist/number-counter.js.map +1 -1
  44. package/dist/{observe-theme-change-pALI5fmV.js → observe-theme-change-DKAIv5BB.js} +3 -2
  45. package/dist/observe-theme-change-DKAIv5BB.js.map +1 -0
  46. package/dist/peacock-loader.js +37 -8
  47. package/dist/peacock-loader.js.map +1 -1
  48. package/dist/property-1psGvXOq.js +10 -0
  49. package/dist/property-1psGvXOq.js.map +1 -0
  50. package/dist/{snackbar-74YCdMPL.js → select-C3XAzenC.js} +2158 -191
  51. package/dist/select-C3XAzenC.js.map +1 -0
  52. package/dist/side-sheet.js +186 -0
  53. package/dist/side-sheet.js.map +1 -0
  54. package/dist/src/bottom-sheet/bottom-sheet.d.ts +42 -0
  55. package/dist/src/bottom-sheet/index.d.ts +1 -0
  56. package/dist/src/button/BaseButton.d.ts +4 -3
  57. package/dist/src/button/button/button.d.ts +4 -0
  58. package/dist/src/button/button-group/button-group.d.ts +32 -3
  59. package/dist/src/button/icon-button/icon-button.d.ts +4 -0
  60. package/dist/src/card/card-content.d.ts +15 -0
  61. package/dist/src/card/card.d.ts +37 -3
  62. package/dist/src/card/index.d.ts +1 -0
  63. package/dist/src/container/container.d.ts +1 -1
  64. package/dist/src/empty-state/empty-state.d.ts +1 -1
  65. package/dist/src/focus-ring/focus-ring.d.ts +4 -1
  66. package/dist/src/index.d.ts +7 -1
  67. package/dist/src/menu/menu/menu.d.ts +1 -0
  68. package/dist/src/menu/menu-item/menu-item.d.ts +0 -1
  69. package/dist/src/radio/index.d.ts +1 -0
  70. package/dist/src/radio/radio.d.ts +73 -0
  71. package/dist/src/ripple/ripple.d.ts +19 -3
  72. package/dist/src/segmented-button/index.d.ts +2 -0
  73. package/dist/src/segmented-button/segmented-button-group.d.ts +46 -0
  74. package/dist/src/segmented-button/segmented-button.d.ts +65 -0
  75. package/dist/src/select/index.d.ts +3 -0
  76. package/dist/src/select/option.d.ts +55 -0
  77. package/dist/src/select/select.d.ts +116 -0
  78. package/dist/src/side-sheet/index.d.ts +1 -0
  79. package/dist/src/side-sheet/side-sheet.d.ts +41 -0
  80. package/dist/src/tabs/tab-group.d.ts +0 -1
  81. package/dist/src/tabs/tab.d.ts +8 -2
  82. package/dist/src/tabs/tabs.d.ts +13 -1
  83. package/dist/state-DwbEjqVk.js +10 -0
  84. package/dist/state-DwbEjqVk.js.map +1 -0
  85. package/dist/{style-map-DcB52w-l.js → style-map-CRFEoCEg.js} +2 -2
  86. package/dist/{style-map-DcB52w-l.js.map → style-map-CRFEoCEg.js.map} +1 -1
  87. package/dist/tsconfig.tsbuildinfo +1 -1
  88. package/dist/{unsafe-html-C2r3PyzF.js → unsafe-html-D3GHRaGQ.js} +2 -2
  89. package/dist/{unsafe-html-C2r3PyzF.js.map → unsafe-html-D3GHRaGQ.js.map} +1 -1
  90. package/package.json +1 -1
  91. package/readme.md +2 -2
  92. package/src/bottom-sheet/bottom-sheet.scss +88 -0
  93. package/src/bottom-sheet/bottom-sheet.ts +135 -0
  94. package/src/bottom-sheet/index.ts +1 -0
  95. package/src/button/BaseButton.ts +16 -7
  96. package/src/button/button/button-colors.scss +76 -5
  97. package/src/button/button/button-sizes.scss +39 -19
  98. package/src/button/button/button.scss +117 -116
  99. package/src/button/button/button.ts +23 -1
  100. package/src/button/button-group/button-group.scss +25 -22
  101. package/src/button/button-group/button-group.ts +121 -4
  102. package/src/button/icon-button/icon-button-sizes.scss +35 -15
  103. package/src/button/icon-button/icon-button.ts +21 -1
  104. package/src/card/card-colors.scss +10 -0
  105. package/src/card/card-content.ts +26 -0
  106. package/src/card/card.scss +221 -41
  107. package/src/card/card.ts +240 -7
  108. package/src/card/index.ts +1 -0
  109. package/src/code-editor/code-editor.ts +1 -1
  110. package/src/container/container.ts +1 -1
  111. package/src/empty-state/empty-state.scss +8 -0
  112. package/src/empty-state/empty-state.ts +2 -2
  113. package/src/focus-ring/focus-ring.ts +37 -19
  114. package/src/index.ts +8 -1
  115. package/src/menu/menu/menu.scss +24 -3
  116. package/src/menu/menu/menu.ts +23 -2
  117. package/src/menu/menu-item/menu-item.scss +1 -0
  118. package/src/menu/menu-item/menu-item.ts +1 -9
  119. package/src/peacock-loader.ts +32 -0
  120. package/src/radio/index.ts +1 -0
  121. package/src/radio/radio.scss +181 -0
  122. package/src/radio/radio.ts +362 -0
  123. package/src/ripple/ripple.ts +19 -3
  124. package/src/segmented-button/index.ts +2 -0
  125. package/src/segmented-button/segmented-button-group.scss +21 -0
  126. package/src/segmented-button/segmented-button-group.ts +110 -0
  127. package/src/segmented-button/segmented-button.scss +115 -0
  128. package/src/segmented-button/segmented-button.ts +175 -0
  129. package/src/select/index.ts +3 -0
  130. package/src/select/option.ts +109 -0
  131. package/src/select/select.scss +120 -0
  132. package/src/select/select.ts +486 -0
  133. package/src/side-sheet/index.ts +1 -0
  134. package/src/side-sheet/side-sheet.scss +79 -0
  135. package/src/side-sheet/side-sheet.ts +100 -0
  136. package/src/slider/slider.scss +0 -1
  137. package/src/tabs/demo/index.html +90 -0
  138. package/src/tabs/tab-group.ts +0 -3
  139. package/src/tabs/tab.scss +237 -25
  140. package/src/tabs/tab.ts +86 -12
  141. package/src/tabs/tabs.scss +37 -3
  142. package/src/tabs/tabs.ts +118 -2
  143. package/src/utils/dispatch-event-utils.ts +1 -0
  144. package/dist/IndividualComponent-Dt5xirYG.js +0 -73
  145. package/dist/IndividualComponent-Dt5xirYG.js.map +0 -1
  146. package/dist/button-ClzS8JLq.js.map +0 -1
  147. package/dist/button-group-BMS5WvaF.js +0 -292
  148. package/dist/button-group-BMS5WvaF.js.map +0 -1
  149. package/dist/chart-donut.js +0 -309
  150. package/dist/chart-donut.js.map +0 -1
  151. package/dist/class-map-59YGWLnx.js.map +0 -1
  152. package/dist/observe-theme-change-pALI5fmV.js.map +0 -1
  153. package/dist/snackbar-74YCdMPL.js.map +0 -1
  154. package/dist/src/chart-donut/chart-donut.d.ts +0 -53
  155. package/dist/src/chart-donut/index.d.ts +0 -1
  156. package/dist/test/card.test.d.ts +0 -1
  157. package/src/chart-donut/chart-donut.scss +0 -37
  158. package/src/chart-donut/chart-donut.ts +0 -287
  159. package/src/chart-donut/demo/index.html +0 -51
  160. package/src/chart-donut/index.ts +0 -1
package/src/card/card.ts CHANGED
@@ -1,10 +1,14 @@
1
- import { LitElement, html } from 'lit';
2
- import { property } from 'lit/decorators.js';
1
+ import { LitElement, html, nothing, PropertyValues } 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, throttle } from '../utils.js';
3
6
  import IndividualComponent from '../IndividualComponent.js';
4
7
  import styles from './card.scss';
8
+ import colorStyles from './card-colors.scss';
5
9
 
6
10
  type CardVariant = 'elevated' | 'filled' | 'outlined';
7
- type CardElevation = 0 | 1 | 2 | 3 | 4 | 5;
11
+
8
12
  /**
9
13
  * @label Card
10
14
  * @tag wc-card
@@ -24,15 +28,244 @@ type CardElevation = 0 | 1 | 2 | 3 | 4 | 5;
24
28
  */
25
29
  @IndividualComponent
26
30
  export class Card extends LitElement {
27
- static styles = [styles];
31
+ static styles = [styles, colorStyles];
28
32
 
33
+ #id = crypto.randomUUID();
34
+
29
35
  @property({ type: String, reflect: true })
30
36
  variant: CardVariant = 'elevated';
31
37
 
32
- @property({ type: Number, reflect: true })
33
- elevation: CardElevation = 1;
38
+ @property({type: Boolean, reflect: true})
39
+ disabled: boolean = false;
40
+
41
+ @property({ type: Boolean, reflect: true })
42
+ actionable: boolean = false;
43
+
44
+ /**
45
+ * If button is disabled, the reason why it is disabled.
46
+ */
47
+ @property({ attribute: 'disabled-reason' })
48
+ disabledReason: string = '';
49
+
50
+ /**
51
+ * Hyperlink to navigate to on click.
52
+ */
53
+ @property({ reflect: true }) href?: string;
54
+
55
+ /**
56
+ * Sets or retrieves the window or frame at which to target content.
57
+ */
58
+ @property() target: string = '_self';
59
+
60
+
61
+ /**
62
+ * Sets the delay for throttle in milliseconds. Defaults to 200 milliseconds.
63
+ */
64
+ @property() throttleDelay = 200;
65
+
66
+ /**
67
+ * States
68
+ */
69
+ @state()
70
+ isPressed = false;
71
+
72
+ @state()
73
+ private slotHasContent = false;
74
+
75
+
76
+ @query('.card') readonly cardElement!: HTMLElement | null;
77
+
78
+ @query('slot') readonly contentSlot!: HTMLSlotElement | null;
79
+
80
+ #tabindex?: number = 0;
81
+
82
+ #slottedTabIndexMap = new WeakMap<HTMLElement, string | null>();
83
+
84
+ override firstUpdated() {
85
+ this.__dispatchClickWithThrottle = throttle(
86
+ this.__dispatchClick,
87
+ this.throttleDelay,
88
+ );
89
+ observerSlotChangesWithCallback(
90
+ this.renderRoot.querySelector('slot'),
91
+ hasContent => {
92
+ this.slotHasContent = hasContent;
93
+ this.__syncSlottedChildrenTabIndex();
94
+ this.requestUpdate();
95
+ },
96
+ );
97
+ this.__syncSlottedChildrenTabIndex();
98
+ }
99
+
100
+ override updated(changedProperties: PropertyValues<this>) {
101
+ if (changedProperties.has('actionable') || changedProperties.has('href')) {
102
+ this.__syncSlottedChildrenTabIndex();
103
+ }
104
+ }
105
+
106
+ __syncSlottedChildrenTabIndex() {
107
+ if (!this.contentSlot) return;
108
+
109
+ const shouldDisableTabbing = this.actionable || this.__isLink();
110
+ const assignedChildren = this.contentSlot.assignedElements({ flatten: true });
111
+
112
+ assignedChildren.forEach(node => {
113
+ if (!(node instanceof HTMLElement)) return;
114
+
115
+ if (shouldDisableTabbing) {
116
+ if (!this.#slottedTabIndexMap.has(node)) {
117
+ this.#slottedTabIndexMap.set(node, node.getAttribute('tabindex'));
118
+ }
119
+
120
+ if (node.getAttribute('tabindex') !== '-1') {
121
+ node.setAttribute('tabindex', '-1');
122
+ }
123
+ return;
124
+ }
125
+
126
+ const originalTabIndex = this.#slottedTabIndexMap.get(node);
127
+ if (originalTabIndex === null) {
128
+ if (node.hasAttribute('tabindex')) {
129
+ node.removeAttribute('tabindex');
130
+ }
131
+ } else if (originalTabIndex !== undefined) {
132
+ if (node.getAttribute('tabindex') !== originalTabIndex) {
133
+ node.setAttribute('tabindex', originalTabIndex);
134
+ }
135
+ }
136
+
137
+ this.#slottedTabIndexMap.delete(node);
138
+ });
139
+ }
140
+
141
+ __dispatchClickWithThrottle: (event: MouseEvent | KeyboardEvent) => void =
142
+ event => {
143
+ this.__dispatchClick(event);
144
+ };
145
+
146
+ __dispatchClick = (event: MouseEvent | KeyboardEvent) => {
147
+ // If the button is soft-disabled or a disabled link, we need to explicitly
148
+ // prevent the click from propagating to other event listeners as well as
149
+ // prevent the default action.
150
+ if (this.disabled && this.href) {
151
+ event.stopImmediatePropagation();
152
+ event.preventDefault();
153
+ return;
154
+ }
155
+
156
+ if (!isActivationClick(event) || !this.cardElement) {
157
+ return;
158
+ }
159
+
160
+ this.focus();
161
+ dispatchActivationClick(this.cardElement);
162
+ };
163
+
164
+ __isLink() {
165
+ return !!this.href;
166
+ }
167
+
168
+ __getDisabledReasonID() {
169
+ return this.disabled && this.disabledReason
170
+ ? `disabled-reason-${this.#id}`
171
+ : nothing;
172
+ }
173
+
174
+ __renderDisabledReason() {
175
+ const disabledReasonID = this.__getDisabledReasonID();
176
+ if (disabledReasonID)
177
+ return html`<div
178
+ id="disabled-reason-${this.#id}"
179
+ role="tooltip"
180
+ aria-label=${this.disabledReason}
181
+ class="screen-reader-only"
182
+ >
183
+ ${this.disabledReason}
184
+ </div>`;
185
+ return nothing;
186
+ }
187
+
188
+ __handlePress = (event: KeyboardEvent | MouseEvent) => {
189
+ if (this.disabled) return;
190
+ if (
191
+ event instanceof KeyboardEvent &&
192
+ event.type === 'keydown' &&
193
+ (event.key === 'Enter' || event.key === ' ')
194
+ ) {
195
+ this.isPressed = true;
196
+ } else if (event.type === 'mousedown') {
197
+ this.isPressed = true;
198
+ } else {
199
+ this.isPressed = false;
200
+ }
201
+ };
202
+
203
+
204
+
34
205
 
35
206
  render() {
36
- return html`<div class="card"><slot></slot></div>`;
207
+
208
+ const isLink = this.__isLink();
209
+
210
+ const cssClasses = {
211
+ card: true,
212
+ 'card-element': true,
213
+ [`variant-${this.variant}`]: true,
214
+ actionable: (this.actionable && !this.disabled) || isLink,
215
+ disabled: this.disabled,
216
+ pressed: this.isPressed,
217
+ 'has-content': this.slotHasContent,
218
+ };
219
+
220
+ if (!isLink) {
221
+ return html`<button
222
+ class=${classMap(cssClasses)}
223
+ id="button"
224
+ tabindex=${this.#tabindex}
225
+ @click=${this.__dispatchClickWithThrottle}
226
+ @mousedown=${this.__handlePress}
227
+ @keydown=${this.__handlePress}
228
+ @keyup=${this.__handlePress}
229
+ ?aria-describedby=${this.__getDisabledReasonID()}
230
+ aria-disabled=${`${this.disabled}`}
231
+ ?disabled=${this.disabled}
232
+ >
233
+ ${this.renderCardContent()}
234
+ </button>`;
235
+ }
236
+ return html`<a
237
+ class=${classMap(cssClasses)}
238
+ id="button"
239
+ tabindex=${this.#tabindex}
240
+ href=${this.href}
241
+ target=${this.target}
242
+ @click=${this.__dispatchClickWithThrottle}
243
+ @mousedown=${this.__handlePress}
244
+ @keydown=${this.__handlePress}
245
+ @keyup=${this.__handlePress}
246
+ role="button"
247
+ ?aria-describedby=${this.__getDisabledReasonID()}
248
+ aria-disabled=${`${this.disabled}`}
249
+ >
250
+ ${this.renderCardContent()}
251
+ </a>`;
252
+ }
253
+
254
+ renderCardContent() {
255
+ return html`
256
+ <wc-focus-ring class="focus-ring" .control=${this} .forElement=${this.cardElement}></wc-focus-ring>
257
+ <wc-elevation class="elevation"></wc-elevation>
258
+ <div class="background"></div>
259
+ <div class="outline"></div>
260
+ <wc-ripple class="ripple"></wc-ripple>
261
+
262
+ <div class="card-content">
263
+
264
+ <div class="slot-container">
265
+ <slot @slotchange=${this.__syncSlottedChildrenTabIndex}></slot>
266
+ </div>
267
+
268
+ </div>
269
+ `;
37
270
  }
38
271
  }
package/src/card/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { Card } from './card.js';
2
+ export { CardContent } from './card-content.js';
@@ -21,7 +21,7 @@ import styles from './code-editor.scss';
21
21
  *
22
22
  * @example
23
23
  * ```html
24
- * <wc-code-editor language="javascript"></wc-code-editor>
24
+ * <wc-code-editor language="javascript" style="width: 80%;--code-editor-height: 9rem;height: 9rem;" ></wc-code-editor>
25
25
  * ```
26
26
  */
27
27
 
@@ -16,7 +16,7 @@ type ContainerSize = 'max' | 'xl' | 'lg' | 'md' | 'sm' | 'full';
16
16
  *
17
17
  * @example
18
18
  * ```html
19
- * <wc-container size="lg">Content</wc-container>
19
+ * <wc-container style="width: 80%; border: 1px dotted black;" size="md">Content</wc-container>
20
20
  * ```
21
21
  */
22
22
  export class Container extends LitElement {
@@ -64,6 +64,10 @@
64
64
  .content {
65
65
  width: 50%;
66
66
  }
67
+
68
+ .headline {
69
+ @include mixin.get-typography(title-medium);
70
+ }
67
71
  }
68
72
  }
69
73
 
@@ -79,6 +83,10 @@
79
83
  justify-content: center;
80
84
  }
81
85
  }
86
+
87
+ .headline {
88
+ @include mixin.get-typography(title-small);
89
+ }
82
90
  }
83
91
  }
84
92
 
@@ -12,7 +12,7 @@ import styles from './empty-state.scss';
12
12
  *
13
13
  * @example
14
14
  * ```html
15
- * <wc-empty-state headline="No items found"></wc-empty-state>
15
+ * <wc-empty-state width="80%" headline="No items found"></wc-empty-state>
16
16
  * ```
17
17
  */
18
18
  export class EmptyState extends LitElement {
@@ -52,7 +52,7 @@ export class EmptyState extends LitElement {
52
52
 
53
53
  __renderTitle() {
54
54
  if (!this.headline) return nothing;
55
- return html`<div class="title">${this.headline}</div>`;
55
+ return html`<div class="headline">${this.headline}</div>`;
56
56
  }
57
57
 
58
58
  __renderDescription() {
@@ -18,7 +18,7 @@ export class FocusRing extends LitElement {
18
18
 
19
19
  @property({ type: Boolean, reflect: true }) visible: boolean = false;
20
20
 
21
- @property({ type: String}) element = '';
21
+ @property({ type: String }) for = '';
22
22
 
23
23
 
24
24
  render() {
@@ -27,6 +27,8 @@ export class FocusRing extends LitElement {
27
27
 
28
28
  _control?: HTMLElement;
29
29
 
30
+ _focusTarget?: HTMLElement;
31
+
30
32
  get control() {
31
33
  return this._control || null;
32
34
  }
@@ -39,6 +41,15 @@ export class FocusRing extends LitElement {
39
41
  }
40
42
  }
41
43
 
44
+ set forElement(value: HTMLElement | null) {
45
+ if (value) {
46
+ this._focusTarget = value;
47
+ this.attach();
48
+ } else {
49
+ this.detach();
50
+ }
51
+ }
52
+
42
53
  connectedCallback() {
43
54
  super.connectedCallback();
44
55
  this.attach();
@@ -50,8 +61,8 @@ export class FocusRing extends LitElement {
50
61
  }
51
62
 
52
63
  __focusin() {
53
- // @ts-ignore
54
- this.visible = this._control[this.element].matches(':focus-visible') ?? false;
64
+ const focusTarget = this.__getFocusTarget();
65
+ this.visible = focusTarget?.matches(':focus-visible') ?? false;
55
66
  }
56
67
 
57
68
  __focusout() {
@@ -62,27 +73,34 @@ export class FocusRing extends LitElement {
62
73
  this.visible = false;
63
74
  }
64
75
 
76
+ __getFocusTarget(): HTMLElement | undefined {
77
+
78
+ if (this._focusTarget) {
79
+ return this._focusTarget;
80
+ }
81
+
82
+ const focusTarget = document.getElementById(this.for);
83
+ if (focusTarget) {
84
+ return focusTarget
85
+ }
86
+ return undefined;
87
+ }
88
+
65
89
  attach() {
66
- // @ts-ignore
67
- if (this._control && this._control[this.element]) {
68
- // @ts-ignore
69
- this._control[this.element].addEventListener('focusin', this.__focusin.bind(this));
70
- // @ts-ignore
71
- this._control[this.element].addEventListener('focusout', this.__focusin.bind(this));
72
- // @ts-ignore
73
- this._control[this.element].addEventListener('pointerdown', this.__focusin.bind(this));
90
+ const focusTarget = this.__getFocusTarget();
91
+ if (focusTarget) {
92
+ focusTarget.addEventListener('focusin', this.__focusin.bind(this));
93
+ focusTarget.addEventListener('focusout', this.__focusout.bind(this));
94
+ focusTarget.addEventListener('pointerdown', this.__pointerdown.bind(this));
74
95
  }
75
96
  }
76
97
 
77
98
  detach() {
78
- // @ts-ignore
79
- if (this._control && this._control[this.element]) {
80
- // @ts-ignore
81
- this._control[this.element].removeEventListener('focusin', this.__focusin);
82
- // @ts-ignore
83
- this._control[this.element].removeEventListener('focusout', this.__focusout);
84
- // @ts-ignore
85
- this._control[this.element].removeEventListener('pointerdown', this.__pointerdown);
99
+ const focusTarget = this.__getFocusTarget();
100
+ if (focusTarget) {
101
+ focusTarget.removeEventListener('focusin', this.__focusin.bind(this));
102
+ focusTarget.removeEventListener('focusout', this.__focusout.bind(this));
103
+ focusTarget.removeEventListener('pointerdown', this.__pointerdown.bind(this));
86
104
  }
87
105
  this._control = undefined;
88
106
  }
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 { SegmentedButton, SegmentedButtonGroup } from './segmented-button/index.js';
8
9
 
9
10
  export { FocusRing } from './focus-ring/index.js';
10
11
  export { Ripple } from './ripple/index.js';
@@ -37,7 +38,6 @@ export { CodeEditor } from './code-editor/index.js';
37
38
  export { Image } from './image/index.js';
38
39
  export { Tab, TabGroup, TabPanel, Tabs } from './tabs/index.js';
39
40
  export { Slider } from './slider/index.js';
40
- export { ChartDonut } from './chart-donut/index.js';
41
41
  export { ChartDoughnut } from './chart-doughnut/index.js';
42
42
  export { ChartPie } from './chart-pie/index.js';
43
43
  export { ChartBar, ChartStackedBar } from './chart-bar/index.js';
@@ -46,3 +46,10 @@ export { Pagination } from './pagination/index.js';
46
46
  export { TreeView, TreeNode } from './tree-view/index.js';
47
47
  export { Card } from './card/index.js';
48
48
  export { Snackbar } from './snackbar/index.js';
49
+ export { Radio } from './radio/index.js';
50
+ export { BottomSheet } from './bottom-sheet/index.js';
51
+ export { SideSheet } from './side-sheet/index.js';
52
+ export { Select } from './select/index.js';
53
+ export type { SelectOption } from './select/index.js';
54
+ export { SelectOptionElement } from './select/index.js';
55
+
@@ -4,23 +4,37 @@
4
4
 
5
5
  .menu {
6
6
  display: flex;
7
- position: relative;
7
+ position: fixed;
8
8
  z-index: var(--menu-z-index, 1000);
9
9
  min-width: 112px;
10
10
  padding-block: var(--spacing-050);
11
+ transform-origin: top center;
12
+
13
+ --_menu-enter-duration: var(--duration-medium1, 250ms);
14
+ --_menu-exit-duration: var(--duration-short4, 200ms);
15
+ --_menu-enter-easing: cubic-bezier(0.05, 0.7, 0.1, 1);
16
+ --_menu-exit-easing: cubic-bezier(0.3, 0, 0.8, 0.15);
17
+
18
+ transition-property: opacity, transform, visibility;
19
+ transition-duration: var(--_menu-exit-duration), var(--_menu-exit-duration), 0ms;
20
+ transition-delay: 0ms, 0ms, var(--_menu-exit-duration);
21
+ transition-timing-function: var(--_menu-exit-easing), var(--_menu-exit-easing), linear;
11
22
 
12
23
  &.closed {
13
- display: none;
14
24
  opacity: 0;
15
25
  visibility: hidden;
16
26
  pointer-events: none;
27
+ transform: translateY(-4px) scale(0.97);
17
28
  }
18
29
 
19
30
  &.open {
20
- display: flex;
21
31
  opacity: 1;
22
32
  visibility: visible;
23
33
  pointer-events: auto;
34
+ transform: translateY(0) scale(1);
35
+ transition-duration: var(--_menu-enter-duration), var(--_menu-enter-duration), 0ms;
36
+ transition-delay: 0ms, 0ms, 0ms;
37
+ transition-timing-function: var(--_menu-enter-easing), var(--_menu-enter-easing), linear;
24
38
  }
25
39
 
26
40
  .menu-content {
@@ -73,6 +87,13 @@
73
87
  }
74
88
  }
75
89
 
90
+ @media (prefers-reduced-motion: reduce) {
91
+ .menu {
92
+ transition: none;
93
+ transform: none;
94
+ }
95
+ }
96
+
76
97
  .menu {
77
98
  --_container-shape-start-start: var(--shape-corner-large);
78
99
  --_container-shape-start-end: var(--shape-corner-large);
@@ -181,7 +181,6 @@ export class Menu extends LitElement {
181
181
  for (let index = 0; index < enabledItems.length; index += 1) {
182
182
  const currentItem = enabledItems[index];
183
183
  currentItem.tabIndex = index === this.activeIndex ? 0 : -1;
184
- currentItem.selected = index === this.activeIndex;
185
184
  }
186
185
  }
187
186
 
@@ -226,10 +225,23 @@ export class Menu extends LitElement {
226
225
  return this._enabledItems()[0] ?? null;
227
226
  }
228
227
 
228
+ private _ownsKeyboardEvent(event: KeyboardEvent) {
229
+ const path = event.composedPath();
230
+ const ownedItems = this.items;
231
+
232
+ return path.some(target => target instanceof MenuItem && ownedItems.includes(target));
233
+ }
234
+
229
235
  private _onItemActivate = (event: Event) => {
230
236
  const customEvent = event as CustomEvent<{ item: MenuItem }>;
237
+ const { item } = customEvent.detail;
238
+ const ownedItems = this.items;
239
+ if (!ownedItems.includes(item)) {
240
+ return;
241
+ }
242
+
231
243
  const enabledItems = this._enabledItems();
232
- const nextIndex = enabledItems.indexOf(customEvent.detail.item);
244
+ const nextIndex = enabledItems.indexOf(item);
233
245
  if (nextIndex >= 0) {
234
246
  this.activeIndex = nextIndex;
235
247
  this._syncRovingTabIndex();
@@ -238,10 +250,15 @@ export class Menu extends LitElement {
238
250
 
239
251
  private _onItemRequestClose = (event: Event) => {
240
252
  const customEvent = event as CustomEvent<{
253
+ item: MenuItem;
241
254
  reason: 'click-selection' | 'keydown';
242
255
  key?: string;
243
256
  }>;
244
257
 
258
+ if (!this.items.includes(customEvent.detail.item)) {
259
+ return;
260
+ }
261
+
245
262
  if (customEvent.defaultPrevented) {
246
263
  return;
247
264
  }
@@ -259,6 +276,10 @@ export class Menu extends LitElement {
259
276
  return;
260
277
  }
261
278
 
279
+ if (!this._ownsKeyboardEvent(event)) {
280
+ return;
281
+ }
282
+
262
283
  switch (event.key) {
263
284
  case 'ArrowDown':
264
285
  event.preventDefault();
@@ -4,6 +4,7 @@
4
4
 
5
5
  :host {
6
6
  padding-inline: var(--spacing-050);
7
+ outline: none;
7
8
  }
8
9
 
9
10
  .menu-item {
@@ -138,10 +138,6 @@ export class MenuItem extends LitElement {
138
138
  return !!this.href;
139
139
  }
140
140
 
141
- get focusTarget() {
142
- return this;
143
- }
144
-
145
141
  render() {
146
142
  const isLink = this.__isLink();
147
143
 
@@ -180,11 +176,7 @@ export class MenuItem extends LitElement {
180
176
 
181
177
  renderContent() {
182
178
  return html`
183
- <wc-focus-ring
184
- class="focus-ring"
185
- .control=${this}
186
- element="focusTarget"
187
- ></wc-focus-ring>
179
+ <wc-focus-ring class="focus-ring" .control=${this} .forElement=${this}></wc-focus-ring>
188
180
  <div class="background"></div>
189
181
  <wc-ripple class="ripple"></wc-ripple>
190
182
 
@@ -11,6 +11,8 @@ import { Divider } from './divider/divider.js';
11
11
  import { Button } from './button/button/button.js';
12
12
  import { ButtonGroup } from './button/button-group/button-group.js';
13
13
  import { IconButton } from './button/icon-button/icon-button.js';
14
+ import { SegmentedButton } from './segmented-button/segmented-button.js';
15
+ import { SegmentedButtonGroup } from './segmented-button/segmented-button-group.js';
14
16
  import { Input } from './input/input.js';
15
17
  import { Field } from './field/field.js';
16
18
  import { NumberField } from './number-field/number-field.js';
@@ -19,6 +21,7 @@ import { TimePicker } from './time-picker/time-picker.js';
19
21
  import { Textarea } from './textarea/textarea.js';
20
22
  import { Switch } from './switch/switch.js';
21
23
  import { Checkbox } from './checkbox/checkbox.js';
24
+ import { Radio } from './radio/radio.js';
22
25
 
23
26
  import { Menu } from './menu/menu/menu.js';
24
27
  import { MenuItem } from './menu/menu-item/menu-item.js';
@@ -52,7 +55,12 @@ import { Table } from './table/table.js';
52
55
  import { Pagination } from './pagination/pagination.js';
53
56
  import { TreeView } from './tree-view/tree-view.js';
54
57
  import { Card } from './card/card.js';
58
+ import { CardContent } from './card/card-content.js';
55
59
  import { Snackbar } from './snackbar/snackbar.js';
60
+ import { BottomSheet } from './bottom-sheet/bottom-sheet.js';
61
+ import { SideSheet } from './side-sheet/side-sheet.js';
62
+ import { Select } from './select/select.js';
63
+ import { SelectOptionElement } from './select/option.js';
56
64
 
57
65
  const distDirectory = `${import.meta.url}/..`;
58
66
  await loadCSS(`${distDirectory}/assets/styles.css`);
@@ -101,6 +109,12 @@ const loaderConfig: LoaderConfig = {
101
109
  'wc-button-group': {
102
110
  CustomElementClass: ButtonGroup,
103
111
  },
112
+ 'wc-segmented-button': {
113
+ CustomElementClass: SegmentedButton,
114
+ },
115
+ 'wc-segmented-button-group': {
116
+ CustomElementClass: SegmentedButtonGroup,
117
+ },
104
118
  'wc-divider': {
105
119
  CustomElementClass: Divider,
106
120
  },
@@ -140,6 +154,9 @@ const loaderConfig: LoaderConfig = {
140
154
  'wc-card': {
141
155
  CustomElementClass: Card,
142
156
  },
157
+ 'wc-card-content': {
158
+ CustomElementClass: CardContent,
159
+ },
143
160
  'wc-tag': {
144
161
  CustomElementClass: Tag,
145
162
  },
@@ -195,6 +212,9 @@ const loaderConfig: LoaderConfig = {
195
212
  'wc-checkbox': {
196
213
  CustomElementClass: Checkbox,
197
214
  },
215
+ 'wc-radio': {
216
+ CustomElementClass: Radio,
217
+ },
198
218
  'wc-spinner': {
199
219
  CustomElementClass: Spinner,
200
220
  },
@@ -234,6 +254,18 @@ const loaderConfig: LoaderConfig = {
234
254
  'wc-snackbar': {
235
255
  CustomElementClass: Snackbar,
236
256
  },
257
+ 'wc-bottom-sheet': {
258
+ CustomElementClass: BottomSheet,
259
+ },
260
+ 'wc-side-sheet': {
261
+ CustomElementClass: SideSheet,
262
+ },
263
+ 'wc-select': {
264
+ CustomElementClass: Select,
265
+ },
266
+ 'wc-option': {
267
+ CustomElementClass: SelectOptionElement,
268
+ },
237
269
  'wc-chart-doughnut': {
238
270
  importPath: `${distDirectory}/chart-doughnut.js`,
239
271
  },
@@ -0,0 +1 @@
1
+ export { Radio } from './radio.js';