@redvars/peacock 3.5.1 → 3.6.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 (198) hide show
  1. package/dist/{BaseButton-DuASuVth.js → BaseButton-BNFAYn-S.js} +2 -2
  2. package/dist/{BaseButton-DuASuVth.js.map → BaseButton-BNFAYn-S.js.map} +1 -1
  3. package/dist/BaseInput-14YmcfK7.js +27 -0
  4. package/dist/BaseInput-14YmcfK7.js.map +1 -0
  5. package/dist/banner.js +2 -3
  6. package/dist/banner.js.map +1 -1
  7. package/dist/{button-DouvOfEU.js → button-colors-Ccys3hvS.js} +5 -294
  8. package/dist/button-colors-Ccys3hvS.js.map +1 -0
  9. package/dist/button-group.js +226 -6
  10. package/dist/button-group.js.map +1 -1
  11. package/dist/button.js +294 -8
  12. package/dist/button.js.map +1 -1
  13. package/dist/calendar-column-view.js +634 -0
  14. package/dist/calendar-column-view.js.map +1 -0
  15. package/dist/calendar-event-BrQ_SEKD.js +199 -0
  16. package/dist/calendar-event-BrQ_SEKD.js.map +1 -0
  17. package/dist/calendar-month-view.js +376 -0
  18. package/dist/calendar-month-view.js.map +1 -0
  19. package/dist/calendar.js +339 -0
  20. package/dist/calendar.js.map +1 -0
  21. package/dist/canvas.js +361 -0
  22. package/dist/canvas.js.map +1 -0
  23. package/dist/cb-compound-expression.js +125 -0
  24. package/dist/cb-compound-expression.js.map +1 -0
  25. package/dist/cb-divider.js +150 -0
  26. package/dist/cb-divider.js.map +1 -0
  27. package/dist/cb-expression.js +75 -0
  28. package/dist/cb-expression.js.map +1 -0
  29. package/dist/cb-predicate.js +137 -0
  30. package/dist/cb-predicate.js.map +1 -0
  31. package/dist/code-editor.js +2 -1
  32. package/dist/code-editor.js.map +1 -1
  33. package/dist/condition-builder.js +58 -0
  34. package/dist/condition-builder.js.map +1 -0
  35. package/dist/custom-elements-jsdocs.json +7976 -4294
  36. package/dist/custom-elements.json +14358 -7589
  37. package/dist/dropdown-button.js +216 -0
  38. package/dist/dropdown-button.js.map +1 -0
  39. package/dist/event-manager-D-QCmUgR.js +113 -0
  40. package/dist/event-manager-D-QCmUgR.js.map +1 -0
  41. package/dist/fab.js +1 -1
  42. package/dist/flow-designer-dZnLJOQT.js +1656 -0
  43. package/dist/flow-designer-dZnLJOQT.js.map +1 -0
  44. package/dist/flow-designer-node-XMe-jlKg.js +548 -0
  45. package/dist/flow-designer-node-XMe-jlKg.js.map +1 -0
  46. package/dist/flow-designer-node.js +4 -0
  47. package/dist/flow-designer-node.js.map +1 -0
  48. package/dist/flow-designer.js +16 -0
  49. package/dist/flow-designer.js.map +1 -0
  50. package/dist/html-editor.js +358 -0
  51. package/dist/html-editor.js.map +1 -0
  52. package/dist/icon-button-CK1ZuE-2.js +247 -0
  53. package/dist/icon-button-CK1ZuE-2.js.map +1 -0
  54. package/dist/index.js +29 -6
  55. package/dist/index.js.map +1 -1
  56. package/dist/{is-dark-mode-DicqGkCJ.js → is-dark-mode-DOcaw4Yq.js} +2 -27
  57. package/dist/is-dark-mode-DOcaw4Yq.js.map +1 -0
  58. package/dist/modal.js +418 -0
  59. package/dist/modal.js.map +1 -0
  60. package/dist/{navigation-rail-Lxetd5-Z.js → navigation-rail-DyO0oAZU.js} +306 -2197
  61. package/dist/navigation-rail-DyO0oAZU.js.map +1 -0
  62. package/dist/notification-manager.js +268 -0
  63. package/dist/notification-manager.js.map +1 -0
  64. package/dist/peacock-loader.js +84 -8
  65. package/dist/peacock-loader.js.map +1 -1
  66. package/dist/popover-NC7b1lTq.js +1971 -0
  67. package/dist/popover-NC7b1lTq.js.map +1 -0
  68. package/dist/popover-content.js +125 -0
  69. package/dist/popover-content.js.map +1 -0
  70. package/dist/popover.js +4 -0
  71. package/dist/popover.js.map +1 -0
  72. package/dist/split-button.js +388 -0
  73. package/dist/split-button.js.map +1 -0
  74. package/dist/src/__controllers/floating-controller.d.ts +35 -0
  75. package/dist/src/calendar/base-event.d.ts +10 -0
  76. package/dist/src/calendar/calendar-column-view.d.ts +41 -0
  77. package/dist/src/calendar/calendar-event.d.ts +7 -0
  78. package/dist/src/calendar/calendar-month-view.d.ts +31 -0
  79. package/dist/src/calendar/calendar.d.ts +65 -0
  80. package/dist/src/calendar/event-manager.d.ts +17 -0
  81. package/dist/src/calendar/index.d.ts +4 -0
  82. package/dist/src/calendar/types.d.ts +13 -0
  83. package/dist/src/calendar/utils.d.ts +31 -0
  84. package/dist/src/canvas/canvas.d.ts +92 -0
  85. package/dist/src/canvas/index.d.ts +2 -0
  86. package/dist/src/condition-builder/cb-compound-expression.d.ts +31 -0
  87. package/dist/src/condition-builder/cb-divider.d.ts +26 -0
  88. package/dist/src/condition-builder/cb-expression.d.ts +31 -0
  89. package/dist/src/condition-builder/cb-predicate.d.ts +30 -0
  90. package/dist/src/condition-builder/condition-builder.d.ts +27 -0
  91. package/dist/src/condition-builder/index.d.ts +5 -0
  92. package/dist/src/dropdown-button/dropdown-button.d.ts +68 -0
  93. package/dist/src/dropdown-button/index.d.ts +1 -0
  94. package/dist/src/flow-designer/commands.d.ts +66 -0
  95. package/dist/src/flow-designer/flow-designer-node.d.ts +46 -0
  96. package/dist/src/flow-designer/flow-designer.d.ts +133 -0
  97. package/dist/src/flow-designer/index.d.ts +7 -0
  98. package/dist/src/flow-designer/layout.d.ts +30 -0
  99. package/dist/src/flow-designer/types.d.ts +142 -0
  100. package/dist/src/flow-designer/validation.d.ts +43 -0
  101. package/dist/src/flow-designer/workflow-utils.d.ts +40 -0
  102. package/dist/src/html-editor/html-editor.d.ts +56 -0
  103. package/dist/src/html-editor/index.d.ts +2 -0
  104. package/dist/src/index.d.ts +13 -0
  105. package/dist/src/menu/menu/menu.d.ts +5 -7
  106. package/dist/src/menu/menu-item/menu-item.d.ts +14 -13
  107. package/dist/src/modal/index.d.ts +1 -0
  108. package/dist/src/modal/modal.d.ts +63 -0
  109. package/dist/src/notification-manager/index.d.ts +1 -0
  110. package/dist/src/notification-manager/notification-manager.d.ts +44 -0
  111. package/dist/src/popover/index.d.ts +2 -0
  112. package/dist/src/popover/popover-content.d.ts +29 -0
  113. package/dist/src/popover/popover.d.ts +62 -0
  114. package/dist/src/split-button/index.d.ts +1 -0
  115. package/dist/src/split-button/split-button.d.ts +72 -0
  116. package/dist/src/tooltip/tooltip.d.ts +2 -15
  117. package/dist/test/flow-designer.test.d.ts +1 -0
  118. package/dist/tsconfig.tsbuildinfo +1 -1
  119. package/package.json +4 -2
  120. package/readme.md +2 -2
  121. package/src/__controllers/floating-controller.ts +237 -0
  122. package/src/banner/banner.scss +2 -3
  123. package/src/button/button/button.ts +1 -0
  124. package/src/calendar/base-event.ts +49 -0
  125. package/src/calendar/calendar-column-view.scss +326 -0
  126. package/src/calendar/calendar-column-view.ts +392 -0
  127. package/src/calendar/calendar-event.ts +20 -0
  128. package/src/calendar/calendar-month-view.scss +192 -0
  129. package/src/calendar/calendar-month-view.ts +244 -0
  130. package/src/calendar/calendar.scss +71 -0
  131. package/src/calendar/calendar.ts +298 -0
  132. package/src/calendar/event-manager.ts +117 -0
  133. package/src/calendar/index.ts +4 -0
  134. package/src/calendar/types.ts +14 -0
  135. package/src/calendar/utils.ts +180 -0
  136. package/src/canvas/canvas.scss +60 -0
  137. package/src/canvas/canvas.ts +391 -0
  138. package/src/canvas/index.ts +2 -0
  139. package/src/condition-builder/cb-compound-expression.scss +37 -0
  140. package/src/condition-builder/cb-compound-expression.ts +80 -0
  141. package/src/condition-builder/cb-divider.scss +93 -0
  142. package/src/condition-builder/cb-divider.ts +56 -0
  143. package/src/condition-builder/cb-expression.scss +14 -0
  144. package/src/condition-builder/cb-expression.ts +49 -0
  145. package/src/condition-builder/cb-predicate.scss +35 -0
  146. package/src/condition-builder/cb-predicate.ts +102 -0
  147. package/src/condition-builder/condition-builder.scss +13 -0
  148. package/src/condition-builder/condition-builder.ts +38 -0
  149. package/src/condition-builder/index.ts +5 -0
  150. package/src/dropdown-button/demo/index.html +110 -0
  151. package/src/dropdown-button/dropdown-button.scss +22 -0
  152. package/src/dropdown-button/dropdown-button.ts +206 -0
  153. package/src/dropdown-button/index.ts +1 -0
  154. package/src/flow-designer/DEMO.md +239 -0
  155. package/src/flow-designer/commands.ts +278 -0
  156. package/src/flow-designer/flow-designer-node.ts +172 -0
  157. package/src/flow-designer/flow-designer.scss +457 -0
  158. package/src/flow-designer/flow-designer.ts +611 -0
  159. package/src/flow-designer/index.ts +41 -0
  160. package/src/flow-designer/layout.ts +357 -0
  161. package/src/flow-designer/types.ts +166 -0
  162. package/src/flow-designer/validation.ts +284 -0
  163. package/src/flow-designer/workflow-utils.ts +282 -0
  164. package/src/html-editor/html-editor.scss +146 -0
  165. package/src/html-editor/html-editor.ts +276 -0
  166. package/src/html-editor/index.ts +3 -0
  167. package/src/index.ts +25 -0
  168. package/src/menu/menu/menu.scss +2 -2
  169. package/src/menu/menu/menu.ts +91 -101
  170. package/src/menu/menu-item/menu-item.scss +4 -0
  171. package/src/menu/menu-item/menu-item.ts +82 -78
  172. package/src/modal/index.ts +1 -0
  173. package/src/modal/modal.scss +206 -0
  174. package/src/modal/modal.ts +201 -0
  175. package/src/notification-manager/index.ts +1 -0
  176. package/src/notification-manager/notification-manager.scss +113 -0
  177. package/src/notification-manager/notification-manager.ts +199 -0
  178. package/src/peacock-loader.ts +71 -0
  179. package/src/popover/index.ts +2 -0
  180. package/src/popover/popover-content.scss +69 -0
  181. package/src/popover/popover-content.ts +51 -0
  182. package/src/popover/popover.scss +7 -0
  183. package/src/popover/popover.ts +170 -0
  184. package/src/split-button/index.ts +1 -0
  185. package/src/split-button/split-button-colors.scss +56 -0
  186. package/src/split-button/split-button-sizes.scss +28 -0
  187. package/src/split-button/split-button.scss +79 -0
  188. package/src/split-button/split-button.ts +236 -0
  189. package/src/table/table.ts +2 -2
  190. package/src/tooltip/tooltip.scss +4 -3
  191. package/src/tooltip/tooltip.ts +46 -104
  192. package/dist/button-DouvOfEU.js.map +0 -1
  193. package/dist/button-group-CEdMwvJJ.js +0 -464
  194. package/dist/button-group-CEdMwvJJ.js.map +0 -1
  195. package/dist/is-dark-mode-DicqGkCJ.js.map +0 -1
  196. package/dist/navigation-rail-Lxetd5-Z.js.map +0 -1
  197. package/dist/src/menu/menu/MenuSurfaceController.d.ts +0 -18
  198. package/src/menu/menu/MenuSurfaceController.ts +0 -61
@@ -0,0 +1,170 @@
1
+ import { html, LitElement } from 'lit';
2
+ import { property } from 'lit/decorators.js';
3
+ import type { Placement } from '@floating-ui/dom';
4
+ import IndividualComponent from '@/IndividualComponent.js';
5
+ import { FloatingController } from '../__controllers/floating-controller.js';
6
+ import styles from './popover.scss';
7
+ import type { PopoverContent } from './popover-content.js';
8
+
9
+ /**
10
+ * @label Popover
11
+ * @tag wc-popover
12
+ * @rawTag popover
13
+ * @summary Displays additional information in a floating panel anchored to a trigger element.
14
+ * @overview
15
+ * <p>The Popover component wraps a trigger element and a <code>wc-popover-content</code> child. It uses
16
+ * floating-ui to compute position, keeping the panel visible inside the viewport even on scroll.</p>
17
+ * @tags display
18
+ *
19
+ * @fires {CustomEvent} wc-popover--open - Fired when the popover opens.
20
+ * @fires {CustomEvent} wc-popover--close - Fired when the popover closes.
21
+ *
22
+ * @example
23
+ * ```html
24
+ * <wc-popover trigger="click">
25
+ * <wc-button>Open popover</wc-button>
26
+ * <wc-popover-content>
27
+ * <p>Popover body text goes here.</p>
28
+ * </wc-popover-content>
29
+ * </wc-popover>
30
+ * ```
31
+ */
32
+ @IndividualComponent
33
+ export class Popover extends LitElement {
34
+ static styles = [styles];
35
+
36
+ /**
37
+ * Determines how the popover is triggered.
38
+ * Possible values are `"click"`, `"hover"`, `"manual"`.
39
+ */
40
+ @property({ reflect: true }) trigger: 'click' | 'hover' | 'manual' = 'click';
41
+
42
+ /**
43
+ * Preferred placement of the popover relative to the trigger element.
44
+ * Accepts any floating-ui `Placement` string such as `"bottom"`, `"top-start"`, `"right"`, etc.
45
+ */
46
+ @property({ reflect: true }) placement: Placement = 'bottom';
47
+
48
+ /**
49
+ * Whether the popover is open.
50
+ */
51
+ @property({ type: Boolean, reflect: true }) open = false;
52
+
53
+ /**
54
+ * Distance in pixels between the trigger element and the popover panel.
55
+ */
56
+ @property({ type: Number }) offset = 8;
57
+
58
+ private _floating: FloatingController | null = null;
59
+
60
+ private _contentEl: PopoverContent | null = null;
61
+
62
+ private _triggerEl: HTMLElement | null = null;
63
+
64
+ private _setupFloating() {
65
+ // Tear down any existing controller
66
+ if (this._floating) {
67
+ this._floating = null;
68
+ }
69
+
70
+ // Resolve the content element
71
+ this._contentEl = this.querySelector<PopoverContent>('wc-popover-content');
72
+
73
+ // Resolve the trigger element: first light-DOM child that is NOT wc-popover-content
74
+ this._triggerEl =
75
+ (Array.from(this.children).find(
76
+ (c) => c.tagName.toLowerCase() !== 'wc-popover-content',
77
+ ) as HTMLElement) ?? null;
78
+
79
+ if (!this._triggerEl || !this._contentEl) return;
80
+
81
+ const triggerMode =
82
+ this.trigger === 'manual'
83
+ ? 'manual'
84
+ : (this.trigger as 'click' | 'hover');
85
+
86
+ this._floating = new FloatingController(this, {
87
+ placement: this.placement,
88
+ strategy: 'fixed',
89
+ offset: this.offset,
90
+ trigger: triggerMode,
91
+ closeOnClickOutside: true,
92
+ onOpenChange: (isOpen) => {
93
+ this.open = isOpen;
94
+ if (this._contentEl) {
95
+ this._contentEl.open = isOpen;
96
+ }
97
+ this.dispatchEvent(
98
+ new CustomEvent(isOpen ? 'wc-popover--open' : 'wc-popover--close', {
99
+ bubbles: true,
100
+ composed: true,
101
+ }),
102
+ );
103
+ },
104
+ });
105
+
106
+ this._floating.setElements(
107
+ this._triggerEl,
108
+ this._contentEl as unknown as HTMLElement,
109
+ );
110
+
111
+ if (this.open) {
112
+ this._floating.open();
113
+ this._contentEl.open = true;
114
+ }
115
+ }
116
+
117
+ connectedCallback() {
118
+ super.connectedCallback();
119
+ }
120
+
121
+ firstUpdated() {
122
+ this._setupFloating();
123
+ }
124
+
125
+ updated(changedProps: Map<string, unknown>) {
126
+ if (
127
+ changedProps.has('trigger') ||
128
+ changedProps.has('placement') ||
129
+ changedProps.has('offset')
130
+ ) {
131
+ this._setupFloating();
132
+ }
133
+
134
+ if (changedProps.has('open') && this._floating) {
135
+ if (this.open && !this._floating.isOpen) {
136
+ this._floating.open();
137
+ if (this._contentEl) this._contentEl.open = true;
138
+ } else if (!this.open && this._floating.isOpen) {
139
+ this._floating.close();
140
+ if (this._contentEl) this._contentEl.open = false;
141
+ }
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Programmatically opens the popover.
147
+ */
148
+ show() {
149
+ if (this._floating && !this._floating.isOpen) {
150
+ this._floating.open();
151
+ } else if (!this._floating) {
152
+ this.open = true;
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Programmatically closes the popover.
158
+ */
159
+ hide() {
160
+ if (this._floating && this._floating.isOpen) {
161
+ this._floating.close();
162
+ } else if (!this._floating) {
163
+ this.open = false;
164
+ }
165
+ }
166
+
167
+ render() {
168
+ return html`<slot></slot>`;
169
+ }
170
+ }
@@ -0,0 +1 @@
1
+ export { SplitButton } from './split-button.js';
@@ -0,0 +1,56 @@
1
+ @mixin _split-button-color($color) {
2
+ --filled-split-button-container-color: var(--color-#{$color});
3
+ --filled-split-button-label-text-color: var(--color-on-#{$color});
4
+
5
+ --tonal-split-button-container-color: var(--color-#{$color}-container);
6
+ --tonal-split-button-label-text-color: var(--color-on-#{$color}-container);
7
+
8
+ --outlined-split-button-outline-color: var(--color-#{$color});
9
+ --outlined-split-button-label-text-color: var(--color-#{$color});
10
+ }
11
+
12
+ :host([color=primary]) {
13
+ @include _split-button-color(primary);
14
+ }
15
+
16
+ :host([color=secondary]) {
17
+ @include _split-button-color(secondary);
18
+ }
19
+
20
+ :host([color=tertiary]) {
21
+ @include _split-button-color(tertiary);
22
+ }
23
+
24
+ :host([color=success]) {
25
+ @include _split-button-color(success);
26
+ }
27
+
28
+ :host([color=danger]) {
29
+ @include _split-button-color(error);
30
+ }
31
+
32
+ :host([color=warning]) {
33
+ @include _split-button-color(warning);
34
+ }
35
+
36
+ :host([color=on-surface]) {
37
+ --filled-split-button-container-color: var(--color-on-surface);
38
+ --filled-split-button-label-text-color: var(--color-surface);
39
+
40
+ --tonal-split-button-container-color: var(--color-on-surface-container);
41
+ --tonal-split-button-label-text-color: var(--color-surface-container-high);
42
+
43
+ --outlined-split-button-outline-color: var(--color-on-surface);
44
+ --outlined-split-button-label-text-color: var(--color-on-surface);
45
+ }
46
+
47
+ :host([color=surface]) {
48
+ --filled-split-button-container-color: var(--color-surface-container-high);
49
+ --filled-split-button-label-text-color: var(--color-on-surface);
50
+
51
+ --tonal-split-button-container-color: var(--color-surface-container-high);
52
+ --tonal-split-button-label-text-color: var(--color-on-surface-container);
53
+
54
+ --outlined-split-button-outline-color: var(--color-on-surface);
55
+ --outlined-split-button-label-text-color: var(--color-on-surface);
56
+ }
@@ -0,0 +1,28 @@
1
+ :host([size='xs']),
2
+ :host([size='extra-small']) {
3
+ --split-button-icon-size: 1rem;
4
+ }
5
+
6
+
7
+ :host([size='sm']),
8
+ :host([size='small']) {
9
+ --split-button-icon-size: 1.125rem;
10
+ }
11
+
12
+
13
+ :host([size='md']),
14
+ :host([size='medium']) {
15
+ --split-button-icon-size: 1.25rem;
16
+ }
17
+
18
+
19
+ :host([size='lg']),
20
+ :host([size='large']) {
21
+ --split-button-icon-size: 1.5rem;
22
+ }
23
+
24
+
25
+ :host([size='xl']),
26
+ :host([size='extra-large']) {
27
+ --split-button-icon-size: 2rem;
28
+ }
@@ -0,0 +1,79 @@
1
+ @use '../../scss/mixin';
2
+
3
+ @include mixin.base-styles;
4
+
5
+ :host {
6
+ display: inline-flex;
7
+ position: relative;
8
+
9
+ --split-button-container-shape: var(--shape-corner-medium);
10
+ --split-button-gap: 0.125rem;
11
+ --split-button-icon-size: 1.125rem;
12
+ }
13
+
14
+ .split-button {
15
+ display: inline-flex;
16
+ align-items: center;
17
+ gap: var(--split-button-gap);
18
+ }
19
+
20
+ .action-button {
21
+ --button-container-shape: var(--split-button-container-shape);
22
+ }
23
+
24
+ .dropdown-trigger {
25
+ --button-container-shape: var(--split-button-container-shape);
26
+ --button-icon-size: var(--split-button-icon-size);
27
+ }
28
+
29
+ .dropdown-icon {
30
+ transition: transform 200ms ease;
31
+ }
32
+
33
+ .dropdown-trigger.active .dropdown-icon {
34
+ transform: rotate(180deg);
35
+ }
36
+
37
+ /* ── Variant: Filled ────────────────────────────────────── */
38
+
39
+ .split-button.variant-filled {
40
+ .action-button,
41
+ .dropdown-trigger {
42
+ --filled-button-container-color: var(--filled-split-button-container-color);
43
+ --filled-button-label-text-color: var(--filled-split-button-label-text-color);
44
+ }
45
+ }
46
+
47
+
48
+ /* ── Variant: Tonal ─────────────────────────────────────── */
49
+
50
+ .split-button.variant-tonal {
51
+ .action-button,
52
+ .dropdown-trigger {
53
+ --tonal-button-container-color: var(--tonal-split-button-container-color);
54
+ --tonal-button-label-text-color: var(--tonal-split-button-label-text-color);
55
+ }
56
+ }
57
+
58
+
59
+ /* ── Variant: Outlined ──────────────────────────────────── */
60
+
61
+ .split-button.variant-outlined {
62
+ .action-button,
63
+ .dropdown-trigger {
64
+ --outlined-button-outline-color: var(--outlined-split-button-outline-color, var(--color-outline));
65
+ --outlined-button-label-text-color: var(--outlined-split-button-label-text-color);
66
+ }
67
+ }
68
+
69
+ :host([block]) {
70
+ width: 100%;
71
+
72
+ .split-button {
73
+ width: 100%;
74
+ }
75
+
76
+ .action-button {
77
+ flex: 1;
78
+ }
79
+ }
@@ -0,0 +1,236 @@
1
+ import { html, LitElement } from 'lit';
2
+ import { property, query, state } from 'lit/decorators.js';
3
+ import { classMap } from 'lit/directives/class-map.js';
4
+ import IndividualComponent from '@/IndividualComponent.js';
5
+ import styles from './split-button.scss';
6
+ import colorStyles from './split-button-colors.scss';
7
+ import sizeStyles from './split-button-sizes.scss';
8
+
9
+ /**
10
+ * @label Split Button
11
+ * @tag wc-split-button
12
+ * @rawTag split-button
13
+ *
14
+ * @summary A split button lets users perform a default action or choose from a set of related actions via a dropdown menu.
15
+ * @overview
16
+ * <p>A split button combines a primary action button with a dropdown arrow that opens a menu. Following M3 Material Design, the split button provides a default action alongside a set of secondary options, reducing clutter while keeping alternative actions accessible.</p>
17
+ *
18
+ * @cssprop --split-button-container-shape: Defines the border radius of the split button container shape.
19
+ *
20
+ * @cssprop --filled-split-button-container-color: Color of the filled split button container.
21
+ * @cssprop --filled-split-button-label-text-color: Text color of the filled split button label.
22
+ *
23
+ * @cssprop --outlined-split-button-container-color: Color of the outlined split button container.
24
+ * @cssprop --outlined-split-button-label-text-color: Text color of the outlined split button label.
25
+ *
26
+ * @cssprop --tonal-split-button-container-color: Color of the tonal split button container.
27
+ * @cssprop --tonal-split-button-label-text-color: Text color of the tonal split button label.
28
+ *
29
+ * @fires {MouseEvent} click - Dispatched when the primary action button is clicked.
30
+ * @fires {CustomEvent} toggle-menu - Dispatched when the dropdown menu is opened or closed.
31
+ *
32
+ * @example
33
+ * ```html
34
+ * <wc-split-button>
35
+ * Save
36
+ * <wc-menu-item slot="menu">Save as draft</wc-menu-item>
37
+ * <wc-menu-item slot="menu">Save and publish</wc-menu-item>
38
+ * </wc-split-button>
39
+ * ```
40
+ * @tags controls
41
+ */
42
+ @IndividualComponent
43
+ export class SplitButton extends LitElement {
44
+ static override styles = [styles, colorStyles, sizeStyles];
45
+
46
+ /**
47
+ * Button size.
48
+ * Possible values are `"xs"`, `"sm"`, `"md"`, `"lg"`, `"xl"`. Defaults to `"sm"`.
49
+ */
50
+ @property({ reflect: true }) size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = 'sm';
51
+
52
+ /**
53
+ * The visual style of the split button.
54
+ *
55
+ * Possible variant values:
56
+ * `"filled"` is a filled button.
57
+ * `"outlined"` is an outlined button.
58
+ * `"tonal"` is a light color button.
59
+ */
60
+ @property({ reflect: true }) variant: 'filled' | 'tonal' | 'outlined' =
61
+ 'filled';
62
+
63
+ /**
64
+ * Defines the primary color of the split button.
65
+ */
66
+ @property({ reflect: true }) color:
67
+ | 'primary'
68
+ | 'secondary'
69
+ | 'tertiary'
70
+ | 'success'
71
+ | 'danger'
72
+ | 'warning'
73
+ | 'surface'
74
+ | 'on-surface' = 'primary';
75
+
76
+ /**
77
+ * Whether the split button is disabled.
78
+ */
79
+ @property({ type: Boolean, reflect: true }) disabled = false;
80
+
81
+ @state() private _menuOpen = false;
82
+
83
+ @query('.dropdown-trigger') private readonly _dropdownButton!: HTMLElement;
84
+
85
+ @query('wc-menu') private readonly _menu!: HTMLElement & {
86
+ open: boolean;
87
+ anchorElement: HTMLElement | null;
88
+ show: () => void;
89
+ close: () => void;
90
+ };
91
+
92
+ private _menuId = `split-menu-${Math.random().toString(36).slice(2, 9)}`;
93
+
94
+ override focus() {
95
+ const btn =
96
+ this.shadowRoot?.querySelector<HTMLElement>('.action-button');
97
+ btn?.focus();
98
+ }
99
+
100
+ private _onActionClick(event: MouseEvent) {
101
+ if (this.disabled) {
102
+ event.stopImmediatePropagation();
103
+ event.preventDefault();
104
+ return;
105
+ }
106
+
107
+ // Close menu if open
108
+ if (this._menuOpen) {
109
+ this._menu?.close();
110
+ }
111
+ }
112
+
113
+ private _onDropdownClick(event: MouseEvent) {
114
+ event.stopPropagation();
115
+ if (this.disabled) return;
116
+
117
+ if (this._menuOpen) {
118
+ this._menu?.close();
119
+ } else {
120
+ this._menu.anchorElement = this;
121
+ this._menu?.show();
122
+ }
123
+ }
124
+
125
+ private _onMenuOpened = () => {
126
+ this._menuOpen = true;
127
+ this.dispatchEvent(
128
+ new CustomEvent('toggle-menu', {
129
+ detail: { open: true },
130
+ bubbles: true,
131
+ composed: true,
132
+ }),
133
+ );
134
+ };
135
+
136
+ private _onMenuClosed = () => {
137
+ this._menuOpen = false;
138
+ this.dispatchEvent(
139
+ new CustomEvent('toggle-menu', {
140
+ detail: { open: false },
141
+ bubbles: true,
142
+ composed: true,
143
+ }),
144
+ );
145
+ };
146
+
147
+ private _onKeyDown = (event: KeyboardEvent) => {
148
+ if (this.disabled) return;
149
+
150
+ if (
151
+ event.key === 'ArrowDown' &&
152
+ event.target === this._dropdownButton
153
+ ) {
154
+ event.preventDefault();
155
+ if (!this._menuOpen) {
156
+ this._menu.anchorElement = this;
157
+ this._menu?.show();
158
+ }
159
+ // Focus the menu so keyboard nav works
160
+ requestAnimationFrame(() => this._menu?.focus());
161
+ }
162
+
163
+ if (event.key === 'Escape' && this._menuOpen) {
164
+ this._menu?.close();
165
+ this._dropdownButton?.focus();
166
+ }
167
+ };
168
+
169
+ override connectedCallback() {
170
+ super.connectedCallback();
171
+ this.addEventListener('keydown', this._onKeyDown);
172
+ }
173
+
174
+ override disconnectedCallback() {
175
+ this.removeEventListener('keydown', this._onKeyDown);
176
+ super.disconnectedCallback();
177
+ }
178
+
179
+ override render() {
180
+ const actionClasses = {
181
+ 'action-button': true,
182
+ disabled: this.disabled,
183
+ };
184
+
185
+ const dropdownClasses = {
186
+ 'dropdown-trigger': true,
187
+ active: this._menuOpen,
188
+ disabled: this.disabled,
189
+ };
190
+
191
+ const containerClasses = {
192
+ 'split-button': true,
193
+ [`variant-${this.variant}`]: true,
194
+ disabled: this.disabled,
195
+ };
196
+
197
+ return html`
198
+ <div class=${classMap(containerClasses)}>
199
+ <wc-button
200
+ class=${classMap(actionClasses)}
201
+ size=${this.size}
202
+ variant=${this.variant}
203
+ ?disabled=${this.disabled}
204
+ @click=${this._onActionClick}
205
+ >
206
+ <slot></slot>
207
+ </wc-button>
208
+
209
+ <wc-icon-button
210
+ class=${classMap(dropdownClasses)}
211
+ size=${this.size}
212
+ variant=${this.variant}
213
+ ?disabled=${this.disabled}
214
+ .configAria=${{
215
+ 'aria-haspopup': 'menu',
216
+ 'aria-expanded': String(this._menuOpen),
217
+ 'aria-controls': this._menuId,
218
+ 'aria-label': 'Open split button menu',
219
+ }}
220
+ @click=${this._onDropdownClick}
221
+ >
222
+ <wc-icon class="dropdown-icon" name="arrow_drop_down" aria-hidden="true"></wc-icon>
223
+ </wc-icon-button>
224
+ </div>
225
+
226
+ <wc-menu
227
+ id=${this._menuId}
228
+ placement="bottom-end"
229
+ @opened=${this._onMenuOpened}
230
+ @closed=${this._onMenuClosed}
231
+ >
232
+ <slot name="menu"></slot>
233
+ </wc-menu>
234
+ `;
235
+ }
236
+ }
@@ -218,7 +218,7 @@ export class Table extends LitElement {
218
218
  }
219
219
 
220
220
  private getTotalItems(): number {
221
- if (this.paginate && !this.managed) return this.data.length;
221
+ if (this.paginate && !this.managed && this.data) return this.data.length;
222
222
  return this.totalItems ?? 0;
223
223
  }
224
224
 
@@ -468,7 +468,7 @@ export class Table extends LitElement {
468
468
  <div class=${classMap(tableClasses)}>
469
469
  <div class="table-scroll-container" @scroll=${this.onScrollContainer}>
470
470
  ${this.renderHeader()}
471
- ${this.data.length ? this.renderBody() : this.renderEmptyState()}
471
+ ${this.data && this.data.length ? this.renderBody() : this.renderEmptyState()}
472
472
  </div>
473
473
  <div class="table-footer">${this.renderPagination()}</div>
474
474
  </div>
@@ -5,13 +5,14 @@
5
5
 
6
6
 
7
7
  :host(:not([preview])) {
8
+ position: absolute;
9
+ top: 0;
10
+ left: 0;
11
+
8
12
  .tooltip {
9
13
  pointer-events: none;
10
14
  transition: transform var(--duration-short2) ease-in-out, opacity var(--duration-short2) ease-in-out;
11
15
  transform: scale(0);
12
- position: absolute;
13
- top: 0;
14
- left: 0;
15
16
  opacity: 0;
16
17
  }
17
18