mtrl 0.2.6 → 0.2.7
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.
- package/index.ts +18 -0
- package/package.json +1 -1
- package/src/components/badge/_styles.scss +117 -109
- package/src/components/badge/api.ts +57 -59
- package/src/components/badge/badge.ts +16 -2
- package/src/components/badge/config.ts +65 -11
- package/src/components/badge/constants.ts +22 -12
- package/src/components/badge/features.ts +44 -40
- package/src/components/badge/types.ts +42 -30
- package/src/components/bottom-app-bar/_styles.scss +103 -0
- package/src/components/bottom-app-bar/bottom-app-bar.ts +196 -0
- package/src/components/bottom-app-bar/config.ts +73 -0
- package/src/components/bottom-app-bar/index.ts +11 -0
- package/src/components/bottom-app-bar/types.ts +108 -0
- package/src/components/button/_styles.scss +0 -10
- package/src/components/button/api.ts +5 -0
- package/src/components/button/config.ts +5 -0
- package/src/components/button/types.ts +6 -0
- package/src/components/card/card.ts +13 -25
- package/src/components/card/config.ts +67 -22
- package/src/components/card/features.ts +3 -0
- package/src/components/card/types.ts +28 -0
- package/src/components/checkbox/_styles.scss +0 -2
- package/src/components/datepicker/_styles.scss +358 -0
- package/src/components/datepicker/api.ts +272 -0
- package/src/components/datepicker/config.ts +144 -0
- package/src/components/datepicker/constants.ts +98 -0
- package/src/components/datepicker/datepicker.ts +346 -0
- package/src/components/datepicker/index.ts +9 -0
- package/src/components/datepicker/render.ts +452 -0
- package/src/components/datepicker/types.ts +268 -0
- package/src/components/datepicker/utils.ts +290 -0
- package/src/components/dialog/_styles.scss +174 -128
- package/src/components/dialog/api.ts +48 -13
- package/src/components/dialog/config.ts +9 -5
- package/src/components/dialog/dialog.ts +6 -3
- package/src/components/dialog/features.ts +290 -130
- package/src/components/dialog/types.ts +7 -4
- package/src/components/divider/_styles.scss +57 -0
- package/src/components/divider/config.ts +81 -0
- package/src/components/divider/divider.ts +37 -0
- package/src/components/divider/features.ts +207 -0
- package/src/components/divider/index.ts +5 -0
- package/src/components/divider/types.ts +55 -0
- package/src/components/extended-fab/_styles.scss +267 -0
- package/src/components/extended-fab/api.ts +141 -0
- package/src/components/extended-fab/config.ts +108 -0
- package/src/components/extended-fab/constants.ts +36 -0
- package/src/components/extended-fab/extended-fab.ts +125 -0
- package/src/components/extended-fab/index.ts +4 -0
- package/src/components/extended-fab/types.ts +287 -0
- package/src/components/fab/_styles.scss +225 -0
- package/src/components/fab/api.ts +97 -0
- package/src/components/fab/config.ts +94 -0
- package/src/components/fab/constants.ts +41 -0
- package/src/components/fab/fab.ts +67 -0
- package/src/components/fab/index.ts +4 -0
- package/src/components/fab/types.ts +234 -0
- package/src/components/navigation/_styles.scss +1 -0
- package/src/components/navigation/api.ts +78 -50
- package/src/components/navigation/features/items.ts +280 -0
- package/src/components/navigation/nav-item.ts +72 -23
- package/src/components/navigation/navigation.ts +54 -2
- package/src/components/navigation/types.ts +210 -188
- package/src/components/search/_styles.scss +306 -0
- package/src/components/search/api.ts +203 -0
- package/src/components/search/config.ts +87 -0
- package/src/components/search/constants.ts +21 -0
- package/src/components/search/features/index.ts +4 -0
- package/src/components/search/features/search.ts +718 -0
- package/src/components/search/features/states.ts +165 -0
- package/src/components/search/features/structure.ts +198 -0
- package/src/components/search/index.ts +10 -0
- package/src/components/search/search.ts +52 -0
- package/src/components/search/types.ts +163 -0
- package/src/components/segmented-button/_styles.scss +117 -0
- package/src/components/segmented-button/config.ts +67 -0
- package/src/components/segmented-button/constants.ts +42 -0
- package/src/components/segmented-button/index.ts +4 -0
- package/src/components/segmented-button/segment.ts +155 -0
- package/src/components/segmented-button/segmented-button.ts +250 -0
- package/src/components/segmented-button/types.ts +219 -0
- package/src/components/slider/_styles.scss +83 -24
- package/src/components/slider/accessibility.md +5 -5
- package/src/components/slider/api.ts +41 -120
- package/src/components/slider/config.ts +51 -47
- package/src/components/slider/features/handlers.ts +495 -0
- package/src/components/slider/features/index.ts +1 -2
- package/src/components/slider/features/slider.ts +66 -84
- package/src/components/slider/features/states.ts +195 -0
- package/src/components/slider/features/structure.ts +136 -206
- package/src/components/slider/features/ui.ts +145 -206
- package/src/components/slider/index.ts +2 -11
- package/src/components/slider/slider.ts +9 -12
- package/src/components/slider/types.ts +39 -24
- package/src/components/switch/_styles.scss +0 -2
- package/src/components/tabs/_styles.scss +94 -32
- package/src/components/tabs/features.ts +4 -2
- package/src/components/tabs/indicator.ts +73 -13
- package/src/components/tabs/types.ts +10 -2
- package/src/components/timepicker/README.md +277 -0
- package/src/components/timepicker/_styles.scss +451 -0
- package/src/components/timepicker/api.ts +632 -0
- package/src/components/timepicker/clockdial.ts +482 -0
- package/src/components/timepicker/config.ts +130 -0
- package/src/components/timepicker/constants.ts +138 -0
- package/src/components/timepicker/index.ts +8 -0
- package/src/components/timepicker/render.ts +613 -0
- package/src/components/timepicker/timepicker.ts +117 -0
- package/src/components/timepicker/types.ts +336 -0
- package/src/components/timepicker/utils.ts +241 -0
- package/src/components/top-app-bar/_styles.scss +225 -0
- package/src/components/top-app-bar/config.ts +83 -0
- package/src/components/top-app-bar/index.ts +11 -0
- package/src/components/top-app-bar/top-app-bar.ts +316 -0
- package/src/components/top-app-bar/types.ts +140 -0
- package/src/core/build/_ripple.scss +6 -6
- package/src/core/build/ripple.ts +72 -95
- package/src/core/compose/features/icon.ts +3 -1
- package/src/core/compose/features/ripple.ts +4 -1
- package/src/core/compose/features/textlabel.ts +26 -2
- package/src/core/dom/create.ts +5 -0
- package/src/index.ts +9 -0
- package/src/styles/abstract/_theme.scss +9 -1
- package/src/styles/themes/_autumn.scss +21 -0
- package/src/styles/themes/_base-theme.scss +61 -0
- package/src/styles/themes/_baseline.scss +58 -0
- package/src/styles/themes/_bluekhaki.scss +125 -0
- package/src/styles/themes/_brownbeige.scss +125 -0
- package/src/styles/themes/_browngreen.scss +125 -0
- package/src/styles/themes/_forest.scss +6 -0
- package/src/styles/themes/_greenbeige.scss +125 -0
- package/src/styles/themes/_material.scss +125 -0
- package/src/styles/themes/_ocean.scss +6 -0
- package/src/styles/themes/_sageivory.scss +125 -0
- package/src/styles/themes/_spring.scss +6 -0
- package/src/styles/themes/_summer.scss +5 -0
- package/src/styles/themes/_sunset.scss +5 -0
- package/src/styles/themes/_tealcaramel.scss +125 -0
- package/src/styles/themes/_winter.scss +6 -0
- package/src/components/navigation/features/items.js +0 -192
- package/src/components/slider/features/appearance.ts +0 -94
- package/src/components/slider/features/disabled.ts +0 -68
- package/src/components/slider/features/events.ts +0 -164
- package/src/components/slider/features/interactions.ts +0 -396
- package/src/components/slider/features/keyboard.ts +0 -233
- package/src/core/collection/adapters/mongodb.js +0 -232
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
// src/components/slider/types.ts
|
|
2
2
|
import { SLIDER_COLORS, SLIDER_SIZES, SLIDER_EVENTS } from './constants';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Configuration interface for the Slider component
|
|
6
|
-
*/
|
|
7
4
|
export interface SliderConfig {
|
|
8
5
|
/** Minimum value of the slider */
|
|
9
6
|
min?: number;
|
|
@@ -14,7 +11,7 @@ export interface SliderConfig {
|
|
|
14
11
|
/** Current value of the slider */
|
|
15
12
|
value?: number;
|
|
16
13
|
|
|
17
|
-
/** Secondary value for range slider (when using two
|
|
14
|
+
/** Secondary value for range slider (when using two handles) */
|
|
18
15
|
secondValue?: number;
|
|
19
16
|
|
|
20
17
|
/** Step size for discrete slider */
|
|
@@ -41,9 +38,21 @@ export interface SliderConfig {
|
|
|
41
38
|
/** Whether to snap to steps while dragging (discrete slider) */
|
|
42
39
|
snapToSteps?: boolean;
|
|
43
40
|
|
|
44
|
-
/** Whether the slider is a range slider (two
|
|
41
|
+
/** Whether the slider is a range slider (two handles) */
|
|
45
42
|
range?: boolean;
|
|
46
43
|
|
|
44
|
+
/** Label text for the slider */
|
|
45
|
+
label?: string;
|
|
46
|
+
|
|
47
|
+
/** Position of the label (start or end) - defaults to 'start' */
|
|
48
|
+
labelPosition?: 'start' | 'end';
|
|
49
|
+
|
|
50
|
+
/** Icon to display with the slider */
|
|
51
|
+
icon?: string;
|
|
52
|
+
|
|
53
|
+
/** Position of the icon (start or end) */
|
|
54
|
+
iconPosition?: 'start' | 'end';
|
|
55
|
+
|
|
47
56
|
/** Additional CSS classes */
|
|
48
57
|
class?: string;
|
|
49
58
|
|
|
@@ -53,34 +62,28 @@ export interface SliderConfig {
|
|
|
53
62
|
};
|
|
54
63
|
}
|
|
55
64
|
|
|
56
|
-
/**
|
|
57
|
-
* Slider event object
|
|
58
|
-
*/
|
|
59
65
|
export interface SliderEvent {
|
|
60
|
-
/**
|
|
61
|
-
slider:
|
|
66
|
+
/** The slider component that triggered the event */
|
|
67
|
+
slider: any;
|
|
62
68
|
|
|
63
69
|
/** Current slider value */
|
|
64
70
|
value: number;
|
|
65
71
|
|
|
66
|
-
/** Secondary
|
|
67
|
-
secondValue
|
|
72
|
+
/** Secondary value (for range sliders) */
|
|
73
|
+
secondValue: number | null;
|
|
68
74
|
|
|
69
|
-
/** Original event if
|
|
70
|
-
originalEvent
|
|
75
|
+
/** Original DOM event if available */
|
|
76
|
+
originalEvent: Event | null;
|
|
71
77
|
|
|
72
|
-
/**
|
|
78
|
+
/** Function to prevent default behavior */
|
|
73
79
|
preventDefault: () => void;
|
|
74
80
|
|
|
75
|
-
/** Whether default
|
|
81
|
+
/** Whether default behavior was prevented */
|
|
76
82
|
defaultPrevented: boolean;
|
|
77
83
|
}
|
|
78
84
|
|
|
79
|
-
/**
|
|
80
|
-
* Slider component interface
|
|
81
|
-
*/
|
|
82
85
|
export interface SliderComponent {
|
|
83
|
-
/**
|
|
86
|
+
/** The root element of the slider */
|
|
84
87
|
element: HTMLElement;
|
|
85
88
|
|
|
86
89
|
/** Sets slider value */
|
|
@@ -95,16 +98,16 @@ export interface SliderComponent {
|
|
|
95
98
|
/** Gets secondary slider value */
|
|
96
99
|
getSecondValue: () => number | null;
|
|
97
100
|
|
|
98
|
-
/** Sets slider minimum */
|
|
101
|
+
/** Sets slider minimum value */
|
|
99
102
|
setMin: (min: number) => SliderComponent;
|
|
100
103
|
|
|
101
|
-
/** Gets slider minimum */
|
|
104
|
+
/** Gets slider minimum value */
|
|
102
105
|
getMin: () => number;
|
|
103
106
|
|
|
104
|
-
/** Sets slider maximum */
|
|
107
|
+
/** Sets slider maximum value */
|
|
105
108
|
setMax: (max: number) => SliderComponent;
|
|
106
109
|
|
|
107
|
-
/** Gets slider maximum */
|
|
110
|
+
/** Gets slider maximum value */
|
|
108
111
|
getMax: () => number;
|
|
109
112
|
|
|
110
113
|
/** Sets slider step size */
|
|
@@ -140,6 +143,18 @@ export interface SliderComponent {
|
|
|
140
143
|
/** Shows or hides current value while dragging */
|
|
141
144
|
showCurrentValue: (show: boolean) => SliderComponent;
|
|
142
145
|
|
|
146
|
+
/** Sets label text */
|
|
147
|
+
setLabel: (text: string) => SliderComponent;
|
|
148
|
+
|
|
149
|
+
/** Gets label text */
|
|
150
|
+
getLabel: () => string;
|
|
151
|
+
|
|
152
|
+
/** Sets icon HTML */
|
|
153
|
+
setIcon: (iconHtml: string) => SliderComponent;
|
|
154
|
+
|
|
155
|
+
/** Gets icon HTML */
|
|
156
|
+
getIcon: () => string;
|
|
157
|
+
|
|
143
158
|
/** Adds event listener */
|
|
144
159
|
on: (event: keyof typeof SLIDER_EVENTS | typeof SLIDER_EVENTS[keyof typeof SLIDER_EVENTS], handler: (event: SliderEvent) => void) => SliderComponent;
|
|
145
160
|
|
|
@@ -25,11 +25,18 @@ $container: '#{base.$prefix}-tabs';
|
|
|
25
25
|
&:has(.#{$component}--icon-and-text) {
|
|
26
26
|
min-height: 64px;
|
|
27
27
|
}
|
|
28
|
+
|
|
29
|
+
// Primary indicator specific styling
|
|
30
|
+
.#{$container}-indicator {
|
|
31
|
+
height: 4px;
|
|
32
|
+
border-radius: 3px 3px 0 0;
|
|
33
|
+
background-color: t.color('primary');
|
|
34
|
+
}
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
&--secondary {
|
|
31
38
|
min-height: 48px;
|
|
32
|
-
// Tab indicator styling
|
|
39
|
+
// Tab indicator styling for secondary variant
|
|
33
40
|
.#{$container}-indicator {
|
|
34
41
|
height: 2px;
|
|
35
42
|
border-radius: 0;
|
|
@@ -63,13 +70,10 @@ $container: '#{base.$prefix}-tabs';
|
|
|
63
70
|
background-color: t.color('outline-variant'); // MD3: Outline variant color
|
|
64
71
|
}
|
|
65
72
|
|
|
66
|
-
// Tab indicator styling
|
|
73
|
+
// Tab indicator styling - base styles
|
|
67
74
|
&-indicator {
|
|
68
75
|
position: absolute;
|
|
69
76
|
bottom: 1px;
|
|
70
|
-
height: 4px;
|
|
71
|
-
background-color: t.color('primary');
|
|
72
|
-
border-radius: 3px 3px 0 0;
|
|
73
77
|
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
74
78
|
width 250ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
75
79
|
z-index: 1; // Ensure indicator appears above divider
|
|
@@ -122,12 +126,12 @@ $container: '#{base.$prefix}-tabs';
|
|
|
122
126
|
|
|
123
127
|
&:focus-visible {
|
|
124
128
|
outline: 2px solid t.color('primary');
|
|
125
|
-
outline-offset:
|
|
129
|
+
outline-offset: -2px;
|
|
126
130
|
z-index: 1;
|
|
127
131
|
}
|
|
128
132
|
|
|
129
133
|
// Disabled state
|
|
130
|
-
|
|
134
|
+
&--disabled, &:disabled {
|
|
131
135
|
pointer-events: none;
|
|
132
136
|
opacity: 0.38;
|
|
133
137
|
}
|
|
@@ -189,44 +193,102 @@ $container: '#{base.$prefix}-tabs';
|
|
|
189
193
|
}
|
|
190
194
|
}
|
|
191
195
|
|
|
192
|
-
//
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
196
|
+
// ACTIVE TAB STATES - PRIMARY VARIANT
|
|
197
|
+
.#{$container}--primary & {
|
|
198
|
+
// Active Tab Base State - Apply to primary variant
|
|
199
|
+
&--active {
|
|
200
|
+
color: t.color('primary');
|
|
201
|
+
|
|
202
|
+
.#{$component}-icon {
|
|
203
|
+
color: t.color('primary');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Hover state for active tabs
|
|
207
|
+
&:hover, &.#{$component}--hover {
|
|
208
|
+
background-color: t.alpha('primary', 0.08);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Focused state for active tabs
|
|
212
|
+
&:focus-visible, &.#{$component}--focus {
|
|
213
|
+
background-color: t.alpha('primary', 0.1);
|
|
214
|
+
outline-color: t.color('primary');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Pressed state for active tabs
|
|
218
|
+
&:active, &.#{$component}--pressed {
|
|
219
|
+
background-color: t.alpha('primary', 0.12);
|
|
220
|
+
}
|
|
203
221
|
}
|
|
204
222
|
|
|
205
|
-
//
|
|
206
|
-
&:active:not(
|
|
207
|
-
|
|
223
|
+
// Inactive Tabs - Primary variant
|
|
224
|
+
&:not(.#{$component}--active):not(.#{$component}--disabled):not(:disabled) {
|
|
225
|
+
color: t.color('on-surface-variant');
|
|
226
|
+
|
|
227
|
+
// Hover state for inactive tabs
|
|
228
|
+
&:hover, &.#{$component}--hover {
|
|
229
|
+
background-color: t.alpha('on-surface-variant', 0.08);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Focused state for inactive tabs
|
|
233
|
+
&:focus-visible, &.#{$component}--focus {
|
|
234
|
+
background-color: t.alpha('on-surface-variant', 0.1);
|
|
235
|
+
outline-color: t.color('on-surface-variant');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Pressed state for inactive tabs
|
|
239
|
+
&:active, &.#{$component}--pressed {
|
|
240
|
+
background-color: t.alpha('on-surface-variant', 0.12);
|
|
241
|
+
}
|
|
208
242
|
}
|
|
209
243
|
}
|
|
210
244
|
|
|
211
|
-
//
|
|
245
|
+
// ACTIVE TAB STATES - SECONDARY VARIANT
|
|
212
246
|
.#{$container}--secondary & {
|
|
247
|
+
// Active Tab - Secondary variant
|
|
213
248
|
&--active {
|
|
214
249
|
color: t.color('on-surface');
|
|
215
250
|
|
|
216
251
|
.#{$component}-icon {
|
|
217
252
|
color: t.color('on-surface');
|
|
218
253
|
}
|
|
254
|
+
|
|
255
|
+
// Hover state for active tabs - secondary
|
|
256
|
+
&:hover, &.#{$component}--hover {
|
|
257
|
+
background-color: t.alpha('on-surface', 0.08);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Focused state for active tabs - secondary
|
|
261
|
+
&:focus-visible, &.#{$component}--focus {
|
|
262
|
+
background-color: t.alpha('on-surface', 0.1);
|
|
263
|
+
outline-color: t.color('on-surface');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Pressed state for active tabs - secondary
|
|
267
|
+
&:active, &.#{$component}--pressed {
|
|
268
|
+
background-color: t.alpha('on-surface', 0.12);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Inactive Tabs - Secondary variant
|
|
273
|
+
&:not(.#{$component}--active):not(.#{$component}--disabled):not(:disabled) {
|
|
274
|
+
color: t.color('on-surface-variant');
|
|
275
|
+
|
|
276
|
+
// Hover state for inactive tabs - secondary
|
|
277
|
+
&:hover, &.#{$component}--hover {
|
|
278
|
+
background-color: t.alpha('on-surface-variant', 0.08);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Focused state for inactive tabs - secondary
|
|
282
|
+
&:focus-visible, &.#{$component}--focus {
|
|
283
|
+
background-color: t.alpha('on-surface-variant', 0.1);
|
|
284
|
+
outline-color: t.color('on-surface-variant');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Pressed state for inactive tabs - secondary
|
|
288
|
+
&:active, &.#{$component}--pressed {
|
|
289
|
+
background-color: t.alpha('on-surface-variant', 0.12);
|
|
290
|
+
}
|
|
219
291
|
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Hover state for inactive tabs
|
|
223
|
-
&:hover:not(:disabled):not(&--active):not([disabled]) {
|
|
224
|
-
background-color: t.alpha('on-surface-variant', 0.08);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Pressed state for inactive tabs
|
|
228
|
-
&:active:not(:disabled):not([disabled]):not(&--active) {
|
|
229
|
-
background-color: t.alpha('on-surface-variant', 0.12);
|
|
230
292
|
}
|
|
231
293
|
|
|
232
294
|
// Ripple effect styling
|
|
@@ -282,12 +282,14 @@ export const withIndicator = <T extends IndicatorFeatureConfig>(config: T) =>
|
|
|
282
282
|
const indicator: TabIndicator = createTabIndicator({
|
|
283
283
|
prefix: config.prefix,
|
|
284
284
|
// Support both new and legacy config
|
|
285
|
-
widthStrategy: indicatorConfig.widthStrategy || config.indicatorWidthStrategy || '
|
|
285
|
+
widthStrategy: indicatorConfig.widthStrategy || config.indicatorWidthStrategy || 'auto', // Changed default to 'auto'
|
|
286
286
|
height: indicatorConfig.height || config.indicatorHeight || 3,
|
|
287
287
|
fixedWidth: indicatorConfig.fixedWidth || 40,
|
|
288
288
|
animationDuration: indicatorConfig.animationDuration || 250,
|
|
289
289
|
animationTiming: indicatorConfig.animationTiming || 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
290
|
-
color: indicatorConfig.color
|
|
290
|
+
color: indicatorConfig.color,
|
|
291
|
+
// Pass the tabs variant to the indicator
|
|
292
|
+
variant: config.variant || 'primary'
|
|
291
293
|
});
|
|
292
294
|
|
|
293
295
|
// Find the scroll container and add the indicator to it
|
|
@@ -8,7 +8,7 @@ export interface TabIndicatorConfig {
|
|
|
8
8
|
/** Height of the indicator in pixels */
|
|
9
9
|
height?: number;
|
|
10
10
|
/** Width strategy - fixed size or dynamic based on tab width */
|
|
11
|
-
widthStrategy?: 'fixed' | 'dynamic' | 'content';
|
|
11
|
+
widthStrategy?: 'fixed' | 'dynamic' | 'content' | 'auto';
|
|
12
12
|
/** Fixed width in pixels when using fixed strategy */
|
|
13
13
|
fixedWidth?: number;
|
|
14
14
|
/** Animation duration in milliseconds */
|
|
@@ -21,6 +21,8 @@ export interface TabIndicatorConfig {
|
|
|
21
21
|
prefix?: string;
|
|
22
22
|
/** Custom color for the indicator */
|
|
23
23
|
color?: string;
|
|
24
|
+
/** Tabs variant (primary or secondary) */
|
|
25
|
+
variant?: string;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
/**
|
|
@@ -47,12 +49,13 @@ export interface TabIndicator {
|
|
|
47
49
|
* Default configuration for tab indicator
|
|
48
50
|
*/
|
|
49
51
|
const DEFAULT_CONFIG: TabIndicatorConfig = {
|
|
50
|
-
widthStrategy: '
|
|
52
|
+
widthStrategy: 'auto', // Changed to 'auto' to match variant behavior
|
|
51
53
|
fixedWidth: 40,
|
|
52
54
|
animationDuration: 250,
|
|
53
55
|
animationTiming: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
54
56
|
visible: true,
|
|
55
|
-
prefix: 'mtrl'
|
|
57
|
+
prefix: 'mtrl',
|
|
58
|
+
variant: 'primary'
|
|
56
59
|
};
|
|
57
60
|
|
|
58
61
|
/**
|
|
@@ -81,17 +84,38 @@ export const createTabIndicator = (config: TabIndicatorConfig = {}): TabIndicato
|
|
|
81
84
|
let currentTab: TabComponent | null = null;
|
|
82
85
|
|
|
83
86
|
/**
|
|
84
|
-
* Calculates indicator width based on strategy
|
|
87
|
+
* Calculates indicator width based on strategy and variant
|
|
85
88
|
* @param tab - Target tab
|
|
86
89
|
* @returns Width in pixels
|
|
87
90
|
*/
|
|
88
91
|
const calculateWidth = (tab: TabComponent): number => {
|
|
92
|
+
// Use auto strategy to determine based on variant
|
|
93
|
+
if (mergedConfig.widthStrategy === 'auto') {
|
|
94
|
+
// For secondary tabs, use full tab width
|
|
95
|
+
if (mergedConfig.variant === 'secondary') {
|
|
96
|
+
return tab.element.offsetWidth;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// For primary tabs (default), use text label width
|
|
100
|
+
const textElement = tab.element.querySelector(`.${prefix}-tab-text`) ||
|
|
101
|
+
tab.element.querySelector(`.${prefix}-button-text`);
|
|
102
|
+
|
|
103
|
+
if (textElement) {
|
|
104
|
+
return textElement.clientWidth;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Fallback to dynamic if text element not found
|
|
108
|
+
return Math.max(tab.element.offsetWidth / 2, 30);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Handle other strategies when explicitly set
|
|
89
112
|
switch (mergedConfig.widthStrategy) {
|
|
90
113
|
case 'dynamic':
|
|
91
114
|
return Math.max(tab.element.offsetWidth / 2, 30);
|
|
92
115
|
case 'content':
|
|
93
116
|
// Try to match content width
|
|
94
|
-
const text = tab.element.querySelector(`.${prefix}-button-text`)
|
|
117
|
+
const text = tab.element.querySelector(`.${prefix}-button-text`) ||
|
|
118
|
+
tab.element.querySelector(`.${prefix}-tab-text`);
|
|
95
119
|
if (text) {
|
|
96
120
|
return Math.max(text.clientWidth, 30);
|
|
97
121
|
}
|
|
@@ -126,6 +150,46 @@ export const createTabIndicator = (config: TabIndicatorConfig = {}): TabIndicato
|
|
|
126
150
|
};
|
|
127
151
|
};
|
|
128
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Calculates indicator position based on variant and width
|
|
155
|
+
* @param tab - Target tab
|
|
156
|
+
* @param indicatorWidth - Width of the indicator
|
|
157
|
+
* @returns {Object} Position information
|
|
158
|
+
*/
|
|
159
|
+
const calculatePosition = (tab: TabComponent, indicatorWidth: number): { left: number } => {
|
|
160
|
+
const { left, width: tabWidth } = getTabPosition(tab.element);
|
|
161
|
+
|
|
162
|
+
// For primary tabs with text label width, center under the text
|
|
163
|
+
if (mergedConfig.variant !== 'secondary' &&
|
|
164
|
+
(mergedConfig.widthStrategy === 'auto' || mergedConfig.widthStrategy === 'content')) {
|
|
165
|
+
const textElement = tab.element.querySelector(`.${prefix}-tab-text`) ||
|
|
166
|
+
tab.element.querySelector(`.${prefix}-button-text`);
|
|
167
|
+
|
|
168
|
+
if (textElement) {
|
|
169
|
+
// Get text element position relative to tab
|
|
170
|
+
const textRect = textElement.getBoundingClientRect();
|
|
171
|
+
const tabRect = tab.element.getBoundingClientRect();
|
|
172
|
+
const textLeft = textRect.left - tabRect.left;
|
|
173
|
+
|
|
174
|
+
// Center indicator under text
|
|
175
|
+
return {
|
|
176
|
+
left: left + textLeft
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// For secondary tabs or when no text element found
|
|
182
|
+
// For centered indicators, center in the tab
|
|
183
|
+
if (indicatorWidth < tabWidth) {
|
|
184
|
+
return {
|
|
185
|
+
left: left + ((tabWidth - indicatorWidth) / 2)
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// For full-width indicators
|
|
190
|
+
return { left };
|
|
191
|
+
};
|
|
192
|
+
|
|
129
193
|
/**
|
|
130
194
|
* Moves indicator to specified tab
|
|
131
195
|
* @param tab - Target tab
|
|
@@ -140,15 +204,11 @@ export const createTabIndicator = (config: TabIndicatorConfig = {}): TabIndicato
|
|
|
140
204
|
// Store current tab for later updates
|
|
141
205
|
currentTab = tab;
|
|
142
206
|
|
|
143
|
-
// Calculate indicator width
|
|
207
|
+
// Calculate indicator width based on strategy and variant
|
|
144
208
|
const width = calculateWidth(tab);
|
|
145
209
|
|
|
146
|
-
//
|
|
147
|
-
const { left
|
|
148
|
-
|
|
149
|
-
// Calculate position to center indicator on tab
|
|
150
|
-
const tabCenter = left + (tabWidth / 2);
|
|
151
|
-
const indicatorLeft = tabCenter - (width / 2);
|
|
210
|
+
// Calculate position based on width and variant
|
|
211
|
+
const { left } = calculatePosition(tab, width);
|
|
152
212
|
|
|
153
213
|
// Apply position immediately if requested
|
|
154
214
|
if (immediate) {
|
|
@@ -160,7 +220,7 @@ export const createTabIndicator = (config: TabIndicatorConfig = {}): TabIndicato
|
|
|
160
220
|
|
|
161
221
|
// Update position and width
|
|
162
222
|
element.style.width = `${width}px`;
|
|
163
|
-
element.style.transform = `translateX(${
|
|
223
|
+
element.style.transform = `translateX(${left}px)`;
|
|
164
224
|
|
|
165
225
|
// Restore transition after immediate update
|
|
166
226
|
if (immediate) {
|
|
@@ -10,8 +10,14 @@ import { TabIndicator } from './indicator';
|
|
|
10
10
|
export interface IndicatorConfig {
|
|
11
11
|
/** Height of the indicator in pixels */
|
|
12
12
|
height?: number;
|
|
13
|
-
/**
|
|
14
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Width strategy for the indicator
|
|
15
|
+
* - 'fixed': Uses a fixed width defined by fixedWidth
|
|
16
|
+
* - 'dynamic': Uses half the tab width
|
|
17
|
+
* - 'content': Uses the text content width
|
|
18
|
+
* - 'auto': Adapts based on variant (primary: text width, secondary: full tab width)
|
|
19
|
+
*/
|
|
20
|
+
widthStrategy?: 'fixed' | 'dynamic' | 'content' | 'auto';
|
|
15
21
|
/** Fixed width in pixels (when using fixed strategy) */
|
|
16
22
|
fixedWidth?: number;
|
|
17
23
|
/** Animation duration in milliseconds */
|
|
@@ -20,6 +26,8 @@ export interface IndicatorConfig {
|
|
|
20
26
|
animationTiming?: string;
|
|
21
27
|
/** Custom color for the indicator */
|
|
22
28
|
color?: string;
|
|
29
|
+
/** Tab variant (primary or secondary) */
|
|
30
|
+
variant?: string;
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
/**
|