@redvars/peacock 3.2.10 → 3.3.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 (197) hide show
  1. package/dist/{PeacockComponent-CxJc63xj.js → IndividualComponent-tDnXrOLV.js} +3 -3
  2. package/dist/IndividualComponent-tDnXrOLV.js.map +1 -0
  3. package/dist/{button-DaL4va7Q.js → button-BGFJfbT2.js} +22 -35
  4. package/dist/button-BGFJfbT2.js.map +1 -0
  5. package/dist/button-group.js +8 -8
  6. package/dist/button-group.js.map +1 -1
  7. package/dist/button.js +6 -5
  8. package/dist/button.js.map +1 -1
  9. package/dist/chart-donut.js +307 -0
  10. package/dist/chart-donut.js.map +1 -0
  11. package/dist/chart-doughnut.js +307 -0
  12. package/dist/chart-doughnut.js.map +1 -0
  13. package/dist/chart-pie.js +259 -0
  14. package/dist/chart-pie.js.map +1 -0
  15. package/dist/{class-map-BvQRv7eW.js → class-map-DpeNtqCn.js} +2 -2
  16. package/dist/{class-map-BvQRv7eW.js.map → class-map-DpeNtqCn.js.map} +1 -1
  17. package/dist/clock.js +5 -6
  18. package/dist/clock.js.map +1 -1
  19. package/dist/code-editor.js +37 -24
  20. package/dist/code-editor.js.map +1 -1
  21. package/dist/code-highlighter.js +21 -7
  22. package/dist/code-highlighter.js.map +1 -1
  23. package/dist/custom-elements-jsdocs.json +5377 -3122
  24. package/dist/custom-elements.json +5527 -3940
  25. package/dist/{dispatch-event-utils-vbdiOSeC.js → dispatch-event-utils-B4odODQf.js} +2 -15
  26. package/dist/dispatch-event-utils-B4odODQf.js.map +1 -0
  27. package/dist/index.js +13 -9
  28. package/dist/index.js.map +1 -1
  29. package/dist/number-counter.js +12 -10
  30. package/dist/number-counter.js.map +1 -1
  31. package/dist/{observe-theme-change-NneLARW8.js → observe-theme-change-BISF-Gl5.js} +2 -2
  32. package/dist/{observe-theme-change-NneLARW8.js.map → observe-theme-change-BISF-Gl5.js.map} +1 -1
  33. package/dist/peacock-loader.js +124 -62
  34. package/dist/peacock-loader.js.map +1 -1
  35. package/dist/query-QBcUV-L_.js +15 -0
  36. package/dist/query-QBcUV-L_.js.map +1 -0
  37. package/dist/{image-v3BujlY5.js → slider-Dk9CFWTG.js} +1606 -327
  38. package/dist/slider-Dk9CFWTG.js.map +1 -0
  39. package/dist/src/IndividualComponent.d.ts +1 -0
  40. package/dist/src/accordion/{accordion-item/accordion-item.d.ts → accordion-item.d.ts} +4 -4
  41. package/dist/src/accordion/{accordion/accordion.d.ts → accordion.d.ts} +6 -6
  42. package/dist/src/accordion/{accordion-item/index.d.ts → index.d.ts} +1 -0
  43. package/dist/src/avatar/avatar.d.ts +2 -2
  44. package/dist/src/badge/badge.d.ts +2 -2
  45. package/dist/src/breadcrumb/breadcrumb/breadcrumb.d.ts +7 -8
  46. package/dist/src/breadcrumb/breadcrumb-item/breadcrumb-item.d.ts +3 -3
  47. package/dist/src/button/button/button.d.ts +2 -2
  48. package/dist/src/button/button-group/button-group.d.ts +5 -5
  49. package/dist/src/button/icon-button/icon-button.d.ts +2 -2
  50. package/dist/src/chart-donut/chart-donut.d.ts +53 -0
  51. package/dist/src/chart-donut/index.d.ts +1 -0
  52. package/dist/src/chart-doughnut/chart-doughnut.d.ts +53 -0
  53. package/dist/src/chart-doughnut/index.d.ts +1 -0
  54. package/dist/src/chart-pie/chart-pie.d.ts +50 -0
  55. package/dist/src/chart-pie/index.d.ts +1 -0
  56. package/dist/src/checkbox/checkbox.d.ts +3 -6
  57. package/dist/src/chip/chip/chip.d.ts +4 -4
  58. package/dist/src/chip/tag/tag.d.ts +3 -3
  59. package/dist/src/clock/clock.d.ts +3 -4
  60. package/dist/src/code-editor/code-editor.d.ts +11 -9
  61. package/dist/src/container/container.d.ts +6 -11
  62. package/dist/src/date-picker/date-picker.d.ts +3 -3
  63. package/dist/src/divider/divider.d.ts +2 -2
  64. package/dist/src/elevation/elevation.d.ts +2 -2
  65. package/dist/src/empty-state/empty-state.d.ts +9 -2
  66. package/dist/src/field/field.d.ts +17 -0
  67. package/dist/src/focus-ring/focus-ring.d.ts +1 -1
  68. package/dist/src/icon/icon.d.ts +2 -2
  69. package/dist/src/image/image.d.ts +4 -12
  70. package/dist/src/index.d.ts +5 -1
  71. package/dist/src/input/input.d.ts +2 -2
  72. package/dist/src/link/link.d.ts +4 -5
  73. package/dist/src/menu/menu/menu.d.ts +16 -0
  74. package/dist/src/menu/menu-item/menu-item.d.ts +12 -0
  75. package/dist/src/menu/menu-list/menu-list.d.ts +15 -0
  76. package/dist/src/number-counter/number-counter.d.ts +9 -7
  77. package/dist/src/number-field/number-field.d.ts +1 -1
  78. package/dist/src/popover/index.d.ts +1 -1
  79. package/dist/src/progress/circular-progress/circular-progress.d.ts +3 -3
  80. package/dist/src/progress/linear-progress/linear-progress.d.ts +3 -3
  81. package/dist/src/ripple/ripple.d.ts +60 -4
  82. package/dist/src/skeleton/skeleton.d.ts +6 -5
  83. package/dist/src/slider/index.d.ts +1 -0
  84. package/dist/src/slider/slider.d.ts +52 -0
  85. package/dist/src/spinner/spinner.d.ts +2 -2
  86. package/dist/src/switch/switch.d.ts +2 -2
  87. package/dist/src/tabs/index.d.ts +4 -0
  88. package/dist/src/tabs/tab-group.d.ts +41 -0
  89. package/dist/src/tabs/tab-panel.d.ts +21 -0
  90. package/dist/src/tabs/tab.d.ts +58 -0
  91. package/dist/src/tabs/tabs.d.ts +27 -0
  92. package/dist/src/textarea/textarea.d.ts +3 -3
  93. package/dist/src/time-picker/time-picker.d.ts +3 -3
  94. package/dist/src/{popover/tooltip → tooltip}/tooltip.d.ts +6 -3
  95. package/dist/{state-B09bP3XH.js → state-8v48Exzh.js} +2 -2
  96. package/dist/{state-B09bP3XH.js.map → state-8v48Exzh.js.map} +1 -1
  97. package/dist/{style-map-B8xgVEc9.js → style-map-CfNHEkQp.js} +2 -2
  98. package/dist/{style-map-B8xgVEc9.js.map → style-map-CfNHEkQp.js.map} +1 -1
  99. package/dist/transform-DRuHEvar.js +3312 -0
  100. package/dist/transform-DRuHEvar.js.map +1 -0
  101. package/dist/tsconfig.tsbuildinfo +1 -1
  102. package/dist/{unsafe-html-B-dV3Jps.js → unsafe-html-CV6Je6HL.js} +2 -2
  103. package/dist/{unsafe-html-B-dV3Jps.js.map → unsafe-html-CV6Je6HL.js.map} +1 -1
  104. package/package.json +3 -1
  105. package/readme.md +2 -2
  106. package/src/{PeacockComponent.ts → IndividualComponent.ts} +1 -1
  107. package/src/accordion/{accordion-item/accordion-item.scss → accordion-item.scss} +1 -1
  108. package/src/accordion/{accordion-item/accordion-item.ts → accordion-item.ts} +5 -5
  109. package/src/accordion/{accordion/accordion.scss → accordion.scss} +2 -1
  110. package/src/accordion/{accordion/accordion.ts → accordion.ts} +6 -6
  111. package/src/accordion/{accordion-item/index.ts → index.ts} +2 -0
  112. package/src/avatar/avatar.ts +2 -2
  113. package/src/badge/badge.ts +2 -2
  114. package/src/breadcrumb/breadcrumb/breadcrumb.ts +7 -8
  115. package/src/breadcrumb/breadcrumb-item/breadcrumb-item.ts +3 -3
  116. package/src/button/BaseButton.ts +1 -1
  117. package/src/button/button/button.scss +9 -23
  118. package/src/button/button/button.ts +8 -8
  119. package/src/button/button-group/button-group.ts +7 -7
  120. package/src/button/icon-button/icon-button.ts +8 -8
  121. package/src/chart-donut/chart-donut.scss +37 -0
  122. package/src/chart-donut/chart-donut.ts +287 -0
  123. package/src/chart-donut/demo/index.html +51 -0
  124. package/src/chart-donut/index.ts +1 -0
  125. package/src/chart-doughnut/chart-donut.scss +37 -0
  126. package/src/chart-doughnut/chart-doughnut.ts +287 -0
  127. package/src/chart-doughnut/demo/index.html +51 -0
  128. package/src/chart-doughnut/index.ts +1 -0
  129. package/src/chart-pie/chart-pie.scss +27 -0
  130. package/src/chart-pie/chart-pie.ts +256 -0
  131. package/src/chart-pie/demo/index.html +51 -0
  132. package/src/chart-pie/index.ts +1 -0
  133. package/src/checkbox/checkbox.ts +3 -6
  134. package/src/chip/chip/chip.ts +6 -6
  135. package/src/chip/tag/tag.ts +6 -6
  136. package/src/clock/clock.ts +5 -6
  137. package/src/code-editor/code-editor.scss +3 -5
  138. package/src/code-editor/code-editor.ts +30 -15
  139. package/src/code-highlighter/code-highlighter.ts +19 -4
  140. package/src/container/container.ts +6 -11
  141. package/src/date-picker/date-picker.ts +7 -7
  142. package/src/divider/divider.ts +2 -2
  143. package/src/elevation/elevation.ts +2 -2
  144. package/src/empty-state/empty-state.ts +10 -3
  145. package/src/field/field.scss +4 -4
  146. package/src/field/field.ts +19 -2
  147. package/src/focus-ring/focus-ring.scss +2 -1
  148. package/src/focus-ring/focus-ring.ts +1 -1
  149. package/src/icon/icon.ts +2 -2
  150. package/src/icon/p-icon.ts +1 -1
  151. package/src/image/image.ts +4 -12
  152. package/src/index.ts +6 -2
  153. package/src/input/input.ts +6 -6
  154. package/src/link/link.ts +4 -5
  155. package/src/menu/menu/menu.ts +16 -0
  156. package/src/menu/menu-item/menu-item-colors.scss +2 -2
  157. package/src/menu/menu-item/menu-item.ts +14 -2
  158. package/src/menu/menu-list/menu-list.ts +16 -1
  159. package/src/number-counter/demo/index.html +1 -1
  160. package/src/number-counter/number-counter.ts +11 -9
  161. package/src/number-field/number-field.ts +7 -7
  162. package/src/peacock-loader.ts +71 -44
  163. package/src/popover/index.ts +1 -1
  164. package/src/progress/circular-progress/circular-progress.scss +1 -1
  165. package/src/progress/circular-progress/circular-progress.ts +3 -3
  166. package/src/progress/linear-progress/linear-progress.ts +3 -3
  167. package/src/ripple/ripple.ts +478 -94
  168. package/src/skeleton/skeleton.ts +6 -5
  169. package/src/slider/index.ts +1 -0
  170. package/src/slider/slider.scss +130 -0
  171. package/src/slider/slider.ts +178 -0
  172. package/src/spinner/spinner.ts +2 -2
  173. package/src/switch/switch.ts +4 -4
  174. package/src/tabs/index.ts +4 -0
  175. package/src/tabs/tab-group.scss +10 -0
  176. package/src/tabs/tab-group.ts +137 -0
  177. package/src/tabs/tab-panel.scss +12 -0
  178. package/src/tabs/tab-panel.ts +28 -0
  179. package/src/tabs/tab.scss +157 -0
  180. package/src/tabs/tab.ts +242 -0
  181. package/src/tabs/tabs.scss +18 -0
  182. package/src/tabs/tabs.ts +64 -0
  183. package/src/textarea/textarea.ts +5 -5
  184. package/src/time-picker/time-picker.ts +7 -7
  185. package/src/{popover/tooltip → tooltip}/tooltip.scss +1 -1
  186. package/src/{popover/tooltip → tooltip}/tooltip.ts +10 -6
  187. package/dist/PeacockComponent-CxJc63xj.js.map +0 -1
  188. package/dist/button-DaL4va7Q.js.map +0 -1
  189. package/dist/dispatch-event-utils-vbdiOSeC.js.map +0 -1
  190. package/dist/image-v3BujlY5.js.map +0 -1
  191. package/dist/src/PeacockComponent.d.ts +0 -1
  192. package/dist/src/accordion/accordion/index.d.ts +0 -1
  193. package/dist/src/avatar/p-avatar.d.ts +0 -3
  194. package/dist/src/badge/p-badge.d.ts +0 -3
  195. package/src/accordion/accordion/index.ts +0 -1
  196. package/src/avatar/p-avatar.ts +0 -5
  197. package/src/badge/p-badge.ts +0 -5
@@ -0,0 +1,130 @@
1
+ :host {
2
+ --_track-height: 4px;
3
+ --_thumb-size: 20px;
4
+ --thumb-half: 10px;
5
+ --_active-track-color: var(--color-primary);
6
+ --_inactive-track-color: var(--color-secondary-container);
7
+ --_thumb-color: var(--color-primary);
8
+ --_label-color: var(--color-primary);
9
+ --_label-text-color: var(--color-on-primary);
10
+
11
+ display: inline-block;
12
+ width: 100%;
13
+ min-width: 200px;
14
+ vertical-align: middle;
15
+ touch-action: none; // Prevent scrolling while dragging
16
+ }
17
+
18
+ .slider-container {
19
+ position: relative;
20
+ display: flex;
21
+ align-items: center;
22
+ width: 100%;
23
+ height: 48px; // Touch target size
24
+ cursor: pointer;
25
+
26
+ &.disabled {
27
+ pointer-events: none;
28
+ opacity: 0.38;
29
+ }
30
+ }
31
+
32
+ .track {
33
+ position: absolute;
34
+ width: 100%;
35
+ height: var(--_track-height);
36
+ background-color: var(--_inactive-track-color);
37
+ border-radius: var(--_track-height);
38
+ overflow: hidden;
39
+ pointer-events: none;
40
+
41
+ .track-active {
42
+ position: absolute;
43
+ height: 100%;
44
+ background-color: var(--_active-track-color);
45
+ transition: width 0.1s ease-out;
46
+ will-change: width;
47
+ }
48
+ }
49
+
50
+ .thumb {
51
+ position: absolute;
52
+ top: 50%;
53
+ transform: translateY(-50%);
54
+ width: var(--_thumb-size);
55
+ height: var(--_thumb-size);
56
+ background-color: var(--_thumb-color);
57
+ border-radius: 50%;
58
+ box-shadow: var(--md-sys-elevation-1);
59
+ outline: none;
60
+ cursor: grab;
61
+ transition: left 0.05s cubic-bezier(0.25, 0.46, 0.45, 0.94), box-shadow 0.2s ease;
62
+ will-change: left;
63
+ z-index: 2;
64
+
65
+ display: flex;
66
+ align-items: center;
67
+ justify-content: center;
68
+
69
+ // State Layer (Hover/Focus halo)
70
+ &::before {
71
+ content: '';
72
+ position: absolute;
73
+ top: 50%;
74
+ left: 50%;
75
+ width: 40px;
76
+ height: 40px;
77
+ transform: translate(-50%, -50%);
78
+ border-radius: 50%;
79
+ background-color: var(--_thumb-color);
80
+ opacity: 0;
81
+ transition: opacity 0.2s;
82
+ }
83
+
84
+ &:hover::before { opacity: 0.08; }
85
+ &:focus-visible::before { opacity: 0.12; }
86
+ &:active {
87
+ cursor: grabbing;
88
+ box-shadow: var(--md-sys-elevation-5);
89
+ }
90
+
91
+ // Disable transition while dragging
92
+ &.dragging {
93
+ transition: none;
94
+ }
95
+ }
96
+
97
+ // Value Label (Tooltip)
98
+ .value-label {
99
+ position: absolute;
100
+ bottom: 100%;
101
+ margin-bottom: 8px;
102
+ padding: 4px 8px;
103
+ background-color: var(--_label-color);
104
+ color: var(--_label-text-color);
105
+ border-radius: 4px;
106
+ font-size: 12px;
107
+ white-space: nowrap;
108
+ opacity: 0;
109
+ transform: translateY(4px);
110
+ transition: opacity 0.1s, transform 0.1s;
111
+ pointer-events: none;
112
+
113
+ // Tooltip triangle
114
+ &::after {
115
+ content: '';
116
+ position: absolute;
117
+ top: 100%;
118
+ left: 50%;
119
+ transform: translateX(-50%);
120
+ border: 6px solid transparent;
121
+ border-top-color: var(--_label-color);
122
+ }
123
+ }
124
+
125
+ .slider-container.dragging .value-label,
126
+ .slider-container:active .value-label,
127
+ .thumb:focus-visible .value-label {
128
+ opacity: 1;
129
+ transform: translateY(0);
130
+ }
@@ -0,0 +1,178 @@
1
+ import { LitElement, html } from 'lit';
2
+ import { property, state, query } from 'lit/decorators.js';
3
+ import { styleMap } from 'lit/directives/style-map.js';
4
+ import sliderStyles from './slider.scss';
5
+
6
+ /**
7
+ * @label Slider
8
+ * @tag wc-slider
9
+ * @rawTag slider
10
+ *
11
+ * @summary Sliders allow users to make selections from a range of values.
12
+ *
13
+ * @fires {CustomEvent} input - Dispatched when the slider value changes during interaction.
14
+ * @fires {CustomEvent} change - Dispatched when the slider interaction ends.
15
+ *
16
+ * @example
17
+ * ```html
18
+ * <wc-slider min="0" max="100" value="50"></wc-slider>
19
+ * ```
20
+ */
21
+ export class Slider extends LitElement {
22
+ static styles = [sliderStyles];
23
+
24
+ /**
25
+ * The minimum value of the slider.
26
+ */
27
+ @property({ type: Number }) min = 0;
28
+
29
+ /**
30
+ * The maximum value of the slider.
31
+ */
32
+ @property({ type: Number }) max = 100;
33
+
34
+ /**
35
+ * The current value of the slider.
36
+ */
37
+ @property({ type: Number, reflect: true }) value = 50;
38
+
39
+ /**
40
+ * The step increment for the slider.
41
+ */
42
+ @property({ type: Number }) step = 1;
43
+
44
+ /**
45
+ * Whether the slider is disabled.
46
+ */
47
+ @property({ type: Boolean, reflect: true }) disabled = false;
48
+
49
+ /**
50
+ * Whether to show labels on the slider.
51
+ */
52
+ @property({ type: Boolean }) labeled = true;
53
+
54
+ @state() private isDragging = false;
55
+
56
+ @query('.slider-container') private container!: HTMLElement;
57
+ @query('.thumb') private thumbElement!: HTMLElement;
58
+
59
+ private handleInput(event: MouseEvent | TouchEvent) {
60
+ if (this.disabled) return;
61
+
62
+ const rect = this.container.getBoundingClientRect();
63
+ const clientX = 'touches' in event ? event.touches[0].clientX : (event as MouseEvent).clientX;
64
+
65
+ // Calculate percentage relative to track width
66
+ let percentage = (clientX - rect.left) / rect.width;
67
+ percentage = Math.max(0, Math.min(1, percentage));
68
+
69
+ const rawValue = this.min + percentage * (this.max - this.min);
70
+ const steppedValue = Math.round(rawValue / this.step) * this.step;
71
+
72
+ const oldValue = this.value;
73
+ this.value = Math.max(this.min, Math.min(this.max, steppedValue));
74
+
75
+ if (oldValue !== this.value) {
76
+ this.dispatchEvent(new CustomEvent('input', { detail: { value: this.value }, bubbles: true, composed: true }));
77
+ }
78
+ }
79
+
80
+ private onMouseDown(e: MouseEvent | TouchEvent) {
81
+ if (this.disabled) return;
82
+
83
+ e.preventDefault();
84
+ this.isDragging = true;
85
+
86
+ // Add dragging class for CSS state
87
+ this.container.classList.add('dragging');
88
+ this.thumbElement.classList.add('dragging');
89
+
90
+ this.handleInput(e);
91
+
92
+ window.addEventListener('mousemove', this.onMouseMove);
93
+ window.addEventListener('mouseup', this.onMouseUp);
94
+ window.addEventListener('touchmove', this.onMouseMove, { passive: false });
95
+ window.addEventListener('touchend', this.onMouseUp);
96
+ window.addEventListener('touchcancel', this.onMouseUp);
97
+ }
98
+
99
+ private onMouseMove = (e: MouseEvent | TouchEvent) => {
100
+ if (this.isDragging) {
101
+ e.preventDefault();
102
+ this.handleInput(e);
103
+ }
104
+ };
105
+
106
+ private onMouseUp = () => {
107
+ if (!this.isDragging) return;
108
+
109
+ this.isDragging = false;
110
+ this.container.classList.remove('dragging');
111
+ this.thumbElement.classList.remove('dragging');
112
+
113
+ this.dispatchEvent(new CustomEvent('change', { detail: { value: this.value }, bubbles: true, composed: true }));
114
+
115
+ window.removeEventListener('mousemove', this.onMouseMove);
116
+ window.removeEventListener('mouseup', this.onMouseUp);
117
+ window.removeEventListener('touchmove', this.onMouseMove);
118
+ window.removeEventListener('touchend', this.onMouseUp);
119
+ window.removeEventListener('touchcancel', this.onMouseUp);
120
+ };
121
+
122
+ private handleKeyDown(e: KeyboardEvent) {
123
+ if (this.disabled) return;
124
+
125
+ const increment = e.shiftKey ? this.step * 10 : this.step;
126
+ let newValue = this.value;
127
+
128
+ if (e.key === 'ArrowRight' || e.key === 'ArrowUp') {
129
+ newValue = Math.min(this.max, this.value + increment);
130
+ e.preventDefault();
131
+ } else if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') {
132
+ newValue = Math.max(this.min, this.value - increment);
133
+ e.preventDefault();
134
+ } else if (e.key === 'Home') {
135
+ newValue = this.min;
136
+ e.preventDefault();
137
+ } else if (e.key === 'End') {
138
+ newValue = this.max;
139
+ e.preventDefault();
140
+ }
141
+
142
+ if (newValue !== this.value) {
143
+ this.value = newValue;
144
+ this.dispatchEvent(new CustomEvent('input', { detail: { value: this.value }, bubbles: true, composed: true }));
145
+ this.dispatchEvent(new CustomEvent('change', { detail: { value: this.value }, bubbles: true, composed: true }));
146
+ }
147
+ }
148
+
149
+ render() {
150
+ const percentage = ((this.value - this.min) / (this.max - this.min)) * 100;
151
+
152
+ return html`
153
+ <div
154
+ class="slider-container ${this.disabled ? 'disabled' : ''}"
155
+ @mousedown=${this.onMouseDown}
156
+ @touchstart=${this.onMouseDown}
157
+ >
158
+ <div class="track">
159
+ <div class="track-active" style=${styleMap({ width: `${percentage}%` })}></div>
160
+ </div>
161
+
162
+ <div
163
+ class="thumb"
164
+ role="slider"
165
+ tabindex="${this.disabled ? -1 : 0}"
166
+ aria-valuemin=${this.min}
167
+ aria-valuemax=${this.max}
168
+ aria-valuenow=${this.value}
169
+ aria-disabled=${this.disabled}
170
+ style=${styleMap({ left: `calc(${percentage}% - var(--thumb-half))` })}
171
+ @keydown=${this.handleKeyDown}
172
+ >
173
+ ${this.labeled ? html`<div class="value-label">${this.value}</div>` : ''}
174
+ </div>
175
+ </div>
176
+ `;
177
+ }
178
+ }
@@ -4,7 +4,7 @@ import styles from './spinner.scss';
4
4
 
5
5
  /**
6
6
  * @label Spinner
7
- * @tag base-spinner
7
+ * @tag wc-spinner
8
8
  * @rawTag spinner
9
9
  * @summary A spinner component that animates a circular shape.
10
10
  * @cssprop --spinner-track-color - The color of the track.
@@ -13,7 +13,7 @@ import styles from './spinner.scss';
13
13
  *
14
14
  * @example
15
15
  * ```html
16
- * <base-spinner></base-spinner>
16
+ * <wc-spinner></wc-spinner>
17
17
  * ```
18
18
  */
19
19
  export class Spinner extends LitElement {
@@ -7,7 +7,7 @@ import BaseInput from '../input/BaseInput.js';
7
7
 
8
8
  /**
9
9
  * @label Switch
10
- * @tag base-switch
10
+ * @tag wc-switch
11
11
  * @rawTag switch
12
12
  *
13
13
  * @summary Captures boolean input with an on/off switch interaction.
@@ -27,7 +27,7 @@ import BaseInput from '../input/BaseInput.js';
27
27
  *
28
28
  * @example
29
29
  * ```html
30
- * <base-switch value="true"></base-switch>
30
+ * <wc-switch value="true"></wc-switch>
31
31
  * ```
32
32
  * @tags input, form
33
33
  */
@@ -213,8 +213,8 @@ export class Switch extends BaseInput {
213
213
  __renderIcon() {
214
214
  if (this.withIcon) {
215
215
  if (this.value)
216
- return html`<base-icon name="check" class="icon"></base-icon>`;
217
- return html`<base-icon name="close" class="icon"></base-icon>`;
216
+ return html`<wc-icon name="check" class="icon"></wc-icon>`;
217
+ return html`<wc-icon name="close" class="icon"></wc-icon>`;
218
218
  }
219
219
  return nothing;
220
220
  }
@@ -0,0 +1,4 @@
1
+ export { Tab } from './tab.js';
2
+ export { TabGroup } from './tab-group.js';
3
+ export { TabPanel } from './tab-panel.js';
4
+ export { Tabs } from './tabs.js';
@@ -0,0 +1,10 @@
1
+ @use '../../scss/mixin';
2
+
3
+ @include mixin.base-styles;
4
+
5
+ :host {
6
+ display: flex;
7
+ flex-direction: column;
8
+ height: 100%;
9
+ }
10
+
@@ -0,0 +1,137 @@
1
+ import { html, LitElement } from 'lit';
2
+ import { property } from 'lit/decorators.js';
3
+ import styles from './tab-group.scss';
4
+
5
+ /**
6
+ * @label Tab Group
7
+ * @tag wc-tab-group
8
+ * @rawTag tab-group
9
+ *
10
+ * @summary The tab group component is used to display multiple panels of content in a container.
11
+ * @overview
12
+ * <p>The tab group component allows users to switch between different views or content sections.</p>
13
+ *
14
+ * @example
15
+ * ```html
16
+ * <wc-tab-group>
17
+ *
18
+ * <wc-tabs>
19
+ * <wc-tab selected >Tab 1</wc-tab>
20
+ * <wc-tab>Tab 2</wc-tab>
21
+ * </wc-tabs>
22
+ *
23
+ * <wc-tab-panel>Panel 1</wc-tab-panel>
24
+ * <wc-tab-panel>Panel 2</wc-tab-panel>
25
+ * </wc-tab-group>
26
+ * ```
27
+ * @tags navigation
28
+ */
29
+ export class TabGroup extends LitElement {
30
+ static styles = [styles];
31
+
32
+ @property({ reflect: true })
33
+ variant: 'line' | 'line-secondary' | 'contained' | 'pill' = 'line';
34
+
35
+ private uid = crypto.randomUUID();
36
+
37
+ connectedCallback() {
38
+ super.connectedCallback();
39
+ this.addEventListener('base-tab-click', this.onTabClick as EventListener);
40
+ }
41
+
42
+ disconnectedCallback() {
43
+ this.removeEventListener('base-tab-click', this.onTabClick as EventListener);
44
+ super.disconnectedCallback();
45
+ }
46
+
47
+ firstUpdated() {
48
+ this.initializeTabs();
49
+ }
50
+
51
+ private onTabClick = (event: Event) => {
52
+ const custom = event as CustomEvent;
53
+ event.stopPropagation();
54
+ const targetValue = custom.detail?.target || custom.detail?.value;
55
+ if (targetValue) {
56
+ this.selectTab(targetValue);
57
+ }
58
+ };
59
+
60
+ selectTab(target: string) {
61
+ const tabs = this.getTabs();
62
+ tabs.forEach((tab: HTMLElement) => {
63
+ (tab as any).selected = false;
64
+ tab.classList.remove('previous-tab', 'next-tab');
65
+ });
66
+
67
+ let selectedIndex = -1;
68
+ tabs.forEach((tab: HTMLElement, index: number) => {
69
+ const t = tab.getAttribute('target') || tab.getAttribute('value');
70
+ if (t === target) {
71
+ selectedIndex = index;
72
+ }
73
+ });
74
+
75
+ if (selectedIndex >= 0) {
76
+ const selectedTab = tabs[selectedIndex];
77
+ (selectedTab as any).selected = true;
78
+ if (tabs[selectedIndex - 1]) {
79
+ tabs[selectedIndex - 1].classList.add('previous-tab');
80
+ }
81
+ if (tabs[selectedIndex + 1]) {
82
+ tabs[selectedIndex + 1].classList.add('next-tab');
83
+ }
84
+ }
85
+
86
+ const panels = this.getTabPanels();
87
+ panels.forEach(panel => {
88
+ const panelValue = panel.getAttribute('value');
89
+ (panel as any).active = panelValue === target;
90
+ });
91
+ }
92
+
93
+ private getTabs(): NodeListOf<HTMLElement> {
94
+ return this.querySelectorAll(':scope > tabs-list base-tab');
95
+ }
96
+
97
+ private getTabPanels(): NodeListOf<HTMLElement> {
98
+ return this.querySelectorAll(':scope > base-tab-panel');
99
+ }
100
+
101
+ private getTabList(): HTMLElement | null {
102
+ return this.querySelector(':scope > tabs-list');
103
+ }
104
+
105
+ private tabsHaveTarget(): boolean {
106
+ return !!this.querySelector(':scope > tabs-list base-tab[target]');
107
+ }
108
+
109
+ private initializeTabs() {
110
+ const tabs = Array.from(this.getTabs());
111
+ if (!this.tabsHaveTarget()) {
112
+
113
+ this.getTabPanels().forEach((panel, index) => {
114
+ if (!panel.getAttribute('value')) {
115
+ panel.setAttribute('value', `tab-${this.uid}-${index}`);
116
+ }
117
+ });
118
+
119
+ if (tabs.length > 0) {
120
+ const firstTarget = tabs[0].getAttribute('target');
121
+ if (firstTarget) {
122
+ this.selectTab(firstTarget);
123
+ }
124
+ }
125
+ } else {
126
+ const selectedTab = this.querySelector(':scope > tabs-list base-tab[selected]') as HTMLElement;
127
+ if (selectedTab) {
128
+ const selectedTarget = selectedTab.getAttribute('target');
129
+ if (selectedTarget) this.selectTab(selectedTarget);
130
+ }
131
+ }
132
+ }
133
+
134
+ render() {
135
+ return html`<slot></slot>`;
136
+ }
137
+ }
@@ -0,0 +1,12 @@
1
+ @use '../../scss/mixin';
2
+
3
+ @include mixin.base-styles;
4
+
5
+ :host {
6
+ display: block;
7
+ flex: 1;
8
+ }
9
+
10
+ :host([hidden]) {
11
+ display: none;
12
+ }
@@ -0,0 +1,28 @@
1
+ import { html, LitElement } from 'lit';
2
+ import { property } from 'lit/decorators.js';
3
+ import styles from './tab-panel.scss';
4
+
5
+ /**
6
+ * @label Tab Panel
7
+ * @tag wc-tab-panel
8
+ * @rawTag tab-panel
9
+ *
10
+ * @summary Content panel for tabs.
11
+ * @overview
12
+ * <p>TabPanel contains the content associated with a tab.</p>
13
+ *
14
+ * @example
15
+ * ```html
16
+ * <wc-tab-panel>Content for this tab</wc-tab-panel>
17
+ * ```
18
+ * @tags navigation
19
+ */
20
+ export class TabPanel extends LitElement {
21
+ static styles = [styles];
22
+
23
+ @property({ reflect: true }) value?: string;
24
+
25
+ render() {
26
+ return html`<slot></slot>`;
27
+ }
28
+ }
@@ -0,0 +1,157 @@
1
+ @use '../../scss/mixin';
2
+
3
+ @include mixin.base-styles;
4
+
5
+ :host {
6
+ display: inline-block;
7
+ height: 100%;
8
+ --tab-outline-color: var(--color-primary);
9
+ }
10
+
11
+ .tab-element {
12
+ background: transparent;
13
+ border: none;
14
+ appearance: none;
15
+ margin: 0;
16
+ outline: none;
17
+ text-decoration: none;
18
+ }
19
+
20
+ .tab {
21
+ position: relative;
22
+ display: flex;
23
+ flex-direction: column;
24
+ align-items: center;
25
+ justify-content: center;
26
+ height: var(--_tab-height);
27
+ padding: 0 var(--_container-padding);
28
+ width: 100%;
29
+ cursor: pointer;
30
+
31
+ .tab-content {
32
+ position: relative;
33
+ @include mixin.get-typography('title-small');
34
+ display: flex;
35
+ align-items: center;
36
+ justify-content: center;
37
+ gap: var(--_tab-icon-label-spacing);
38
+ width: 100%;
39
+ height: 100%;
40
+ z-index: 0;
41
+
42
+ color: var(--_label-text-color);
43
+ opacity: var(--_label-text-opacity, 1);
44
+ --icon-size: var(--tab-icon-size, var(--_tab-icon-size));
45
+ --icon-color: var(--_label-text-color);
46
+
47
+ .slot-container {
48
+ display: none;
49
+ }
50
+ }
51
+
52
+ .indicator {
53
+ position: absolute;
54
+ pointer-events: none;
55
+ z-index: 1;
56
+ opacity: 0;
57
+ background: var(--_active-indicator-color);
58
+ border-radius: var(--_active-indicator-shape);
59
+ transform-origin: left bottom;
60
+ height: var(--_active-indicator-height);
61
+ inset: auto 0px 0px;
62
+ opacity: 0;
63
+ }
64
+
65
+ &.has-content {
66
+ .slot-container {
67
+ display: flex;
68
+ flex: none;
69
+ justify-content: center;
70
+ }
71
+ }
72
+
73
+ &.disabled {
74
+ cursor: not-allowed;
75
+ }
76
+
77
+ /*
78
+ Background layers
79
+ */
80
+ .focus-ring {
81
+ z-index: 2;
82
+ --focus-ring-container-shape-start-start: var(--_container-shape-start-start);
83
+ --focus-ring-container-shape-start-end: var(--_container-shape-start-end);
84
+ --focus-ring-container-shape-end-start: var(--_container-shape-end-start);
85
+ --focus-ring-container-shape-end-end: var(--_container-shape-end-end);
86
+ --focus-ring-container-shape-variant: var(--_container-corner-shape-variant);
87
+ }
88
+
89
+ .ripple {
90
+ corner-shape: var(--_container-corner-shape-variant);
91
+ --ripple-state-opacity: var(--_container-state-opacity, 0);
92
+ --ripple-pressed-color: var(--_container-state-color);
93
+ }
94
+
95
+ .outline {
96
+ z-index: 1;
97
+ display: none;
98
+ position: absolute;
99
+ width: 100%;
100
+ height: 100%;
101
+ pointer-events: none;
102
+ border: var(--_outline-width) solid var(--_outline-color);
103
+ border-start-start-radius: var(--_container-shape-start-start);
104
+ border-start-end-radius: var(--_container-shape-start-end);
105
+ border-end-start-radius: var(--_container-shape-end-start);
106
+ border-end-end-radius: var(--_container-shape-end-end);
107
+ }
108
+ }
109
+
110
+
111
+
112
+ :host-context([variant='line']) .tab {
113
+ --_tab-height: 100%;
114
+ --_container-padding: 1rem;
115
+
116
+ --_label-text-color: var(--color-on-surface);
117
+ --_container-state-color: var(--_label-text-color);
118
+ --_container-shape-start-start: var(--shape-corner-small);
119
+ --_container-shape-start-end: var(--shape-corner-small);
120
+ --_container-shape-end-start: var(--shape-corner-small);
121
+ --_container-shape-end-end: var(--shape-corner-small);
122
+ --_active-indicator-color: var(--color-primary);
123
+ --_active-indicator-shape: 3px 3px 0 0;
124
+ --_active-indicator-height: 2px;
125
+
126
+ .focus-ring {
127
+ inset: 3px 3px 4px 3px;
128
+ }
129
+
130
+ &.active {
131
+
132
+ .tab-content .indicator {
133
+ opacity: 1;
134
+ }
135
+
136
+ .focus-ring {
137
+ inset: 3px 3px calc(4px + var(--_active-indicator-height)) 3px;
138
+ }
139
+ }
140
+
141
+ &:hover:not(:where(.disabled)) {
142
+ --_container-state-opacity: 0.08;
143
+ }
144
+
145
+ &.pressed:not(:where(.disabled)) {
146
+ --_container-state-opacity: 0.12;
147
+ }
148
+
149
+ &.disabled {
150
+ --_label-text-color: var(--color-on-surface);
151
+ --_label-text-opacity: 0.38;
152
+
153
+ .ripple {
154
+ display: none;
155
+ }
156
+ }
157
+ }