mtrl 0.2.9 → 0.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.
- package/index.ts +2 -0
- package/package.json +1 -1
- package/src/components/button/button.ts +34 -5
- package/src/components/navigation/system/core.ts +302 -0
- package/src/components/navigation/system/events.ts +240 -0
- package/src/components/navigation/system/index.ts +184 -0
- package/src/components/navigation/system/mobile.ts +278 -0
- package/src/components/navigation/system/state.ts +77 -0
- package/src/components/navigation/system/types.ts +364 -0
- package/src/components/slider/config.ts +2 -2
- package/src/components/slider/features/controller.ts +1 -25
- package/src/components/slider/features/handlers.ts +0 -1
- package/src/components/slider/features/range.ts +7 -7
- package/src/components/slider/{structure.ts → schema.ts} +2 -13
- package/src/components/slider/slider.ts +3 -2
- package/src/components/switch/api.ts +16 -0
- package/src/components/switch/config.ts +1 -18
- package/src/components/switch/features.ts +198 -0
- package/src/components/switch/index.ts +1 -0
- package/src/components/switch/switch.ts +3 -3
- package/src/components/switch/types.ts +14 -2
- package/src/core/composition/features/dom.ts +26 -14
- package/src/core/composition/features/icon.ts +18 -18
- package/src/core/composition/features/index.ts +3 -2
- package/src/core/composition/features/label.ts +16 -17
- package/src/core/composition/features/layout.ts +47 -0
- package/src/core/composition/index.ts +4 -4
- package/src/core/layout/README.md +350 -0
- package/src/core/layout/array.ts +181 -0
- package/src/core/layout/create.ts +55 -0
- package/src/core/layout/index.ts +26 -0
- package/src/core/layout/object.ts +124 -0
- package/src/core/layout/processor.ts +58 -0
- package/src/core/layout/result.ts +85 -0
- package/src/core/layout/types.ts +125 -0
- package/src/core/layout/utils.ts +136 -0
- package/src/styles/abstract/_variables.scss +28 -0
- package/src/styles/components/_switch.scss +133 -69
- package/src/styles/components/_textfield.scss +9 -16
- package/src/components/navigation/system-types.ts +0 -124
- package/src/components/navigation/system.ts +0 -776
- package/src/core/composition/features/structure.ts +0 -22
- package/src/core/layout/index.js +0 -95
- package/src/core/structure.ts +0 -288
|
@@ -10,12 +10,36 @@ $component: '#{base.$prefix}-switch';
|
|
|
10
10
|
.#{$component} {
|
|
11
11
|
// Base styles
|
|
12
12
|
display: inline-flex;
|
|
13
|
-
|
|
13
|
+
flex-direction: column;
|
|
14
14
|
position: relative;
|
|
15
|
-
|
|
15
|
+
width: 100%;
|
|
16
16
|
padding: 4px 0;
|
|
17
17
|
user-select: none;
|
|
18
18
|
|
|
19
|
+
// Container for switch and label
|
|
20
|
+
&-container {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: row;
|
|
23
|
+
justify-content: space-between;
|
|
24
|
+
align-items: center;
|
|
25
|
+
min-height: 48px;
|
|
26
|
+
width: 100%;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Content wrapper
|
|
30
|
+
&-content {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
flex-grow: 1;
|
|
34
|
+
margin-right: 12px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Label
|
|
38
|
+
&-label {
|
|
39
|
+
@include m.typography('title-medium');
|
|
40
|
+
color: t.color('on-surface');
|
|
41
|
+
}
|
|
42
|
+
|
|
19
43
|
// Input (visually hidden but accessible)
|
|
20
44
|
&-input {
|
|
21
45
|
position: absolute;
|
|
@@ -46,6 +70,24 @@ $component: '#{base.$prefix}-switch';
|
|
|
46
70
|
background-color: t.color('surface-container-highest');
|
|
47
71
|
border: 2px solid t.color('outline');
|
|
48
72
|
@include m.motion-transition(background-color, border-color, outline);
|
|
73
|
+
|
|
74
|
+
// Ripple effect (consistent size for both hover and press)
|
|
75
|
+
&::after {
|
|
76
|
+
content: '';
|
|
77
|
+
position: absolute;
|
|
78
|
+
width: 40px;
|
|
79
|
+
height: 40px;
|
|
80
|
+
top: -6px;
|
|
81
|
+
background-color: transparent;
|
|
82
|
+
opacity: 0;
|
|
83
|
+
border-radius: 50%;
|
|
84
|
+
z-index: 0;
|
|
85
|
+
transform: translateX(-6px);
|
|
86
|
+
transition: opacity v.motion('duration-medium1') v.motion('easing-emphasized'),
|
|
87
|
+
background-color v.motion('duration-medium1') v.motion('easing-emphasized'),
|
|
88
|
+
transform v.motion('duration-medium1') cubic-bezier(0.2, 1.4, 0.35, 1);
|
|
89
|
+
pointer-events: none;
|
|
90
|
+
}
|
|
49
91
|
}
|
|
50
92
|
|
|
51
93
|
// Switch thumb (slider)
|
|
@@ -58,10 +100,17 @@ $component: '#{base.$prefix}-switch';
|
|
|
58
100
|
border-radius: 50%;
|
|
59
101
|
background-color: t.color('outline');
|
|
60
102
|
transform: translateX(0);
|
|
61
|
-
transition:
|
|
103
|
+
transition: transform v.motion('duration-medium1') cubic-bezier(0.2, 1.4, 0.35, 1),
|
|
104
|
+
background-color v.motion('duration-medium1') v.motion('easing-emphasized'),
|
|
105
|
+
width v.motion('duration-medium1') v.motion('easing-emphasized'),
|
|
106
|
+
height v.motion('duration-medium1') v.motion('easing-emphasized'),
|
|
107
|
+
top v.motion('duration-medium1') v.motion('easing-emphasized'),
|
|
108
|
+
left v.motion('duration-medium1') v.motion('easing-emphasized');
|
|
62
109
|
display: flex;
|
|
63
110
|
align-items: center;
|
|
64
111
|
justify-content: center;
|
|
112
|
+
z-index: 1; /* Ensure thumb is above ripple */
|
|
113
|
+
pointer-events: none;
|
|
65
114
|
|
|
66
115
|
// Icon inside thumb
|
|
67
116
|
&-icon {
|
|
@@ -80,44 +129,25 @@ $component: '#{base.$prefix}-switch';
|
|
|
80
129
|
}
|
|
81
130
|
}
|
|
82
131
|
|
|
83
|
-
//
|
|
84
|
-
&-
|
|
85
|
-
@include m.typography('body-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
// Label position variants
|
|
91
|
-
&--label-start {
|
|
92
|
-
.#{$component}-label {
|
|
93
|
-
margin-left: 0;
|
|
94
|
-
margin-right: 12px;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
&--label-end {
|
|
99
|
-
flex-direction: row;
|
|
100
|
-
|
|
101
|
-
.#{$component}-label {
|
|
102
|
-
margin-left: 12px;
|
|
103
|
-
margin-right: 0;
|
|
132
|
+
// Supporting text
|
|
133
|
+
&-helper {
|
|
134
|
+
@include m.typography('body-medium');
|
|
135
|
+
color: t.color('on-surface-variant');
|
|
136
|
+
|
|
137
|
+
&--error {
|
|
138
|
+
color: t.color('error');
|
|
104
139
|
}
|
|
105
140
|
}
|
|
106
141
|
|
|
107
142
|
// RTL support
|
|
108
143
|
@include m.rtl {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
margin-left: 12px;
|
|
112
|
-
margin-right: 0;
|
|
113
|
-
}
|
|
144
|
+
&-container {
|
|
145
|
+
flex-direction: row;
|
|
114
146
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
margin-right: 12px;
|
|
120
|
-
}
|
|
147
|
+
|
|
148
|
+
&-content {
|
|
149
|
+
margin-left: 12px;
|
|
150
|
+
margin-right: 0;
|
|
121
151
|
}
|
|
122
152
|
|
|
123
153
|
// Adjust thumb movement for RTL layout
|
|
@@ -131,6 +161,10 @@ $component: '#{base.$prefix}-switch';
|
|
|
131
161
|
.#{$component}-track {
|
|
132
162
|
background-color: t.color('primary');
|
|
133
163
|
border-color: t.color('primary');
|
|
164
|
+
|
|
165
|
+
&::after {
|
|
166
|
+
transform: translateX(14px);
|
|
167
|
+
}
|
|
134
168
|
}
|
|
135
169
|
|
|
136
170
|
.#{$component}-thumb {
|
|
@@ -148,9 +182,22 @@ $component: '#{base.$prefix}-switch';
|
|
|
148
182
|
}
|
|
149
183
|
}
|
|
150
184
|
|
|
185
|
+
// Error state
|
|
186
|
+
&--error {
|
|
187
|
+
.#{$component}-track {
|
|
188
|
+
border-color: t.color('error');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
151
192
|
// Disabled state
|
|
152
193
|
&--disabled {
|
|
153
|
-
|
|
194
|
+
.#{$component}-track {
|
|
195
|
+
opacity: 0.38;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.#{$component}-label {
|
|
199
|
+
opacity: 0.38;
|
|
200
|
+
}
|
|
154
201
|
|
|
155
202
|
// Specific styles for disabled + checked
|
|
156
203
|
&.#{$component}--checked {
|
|
@@ -161,53 +208,70 @@ $component: '#{base.$prefix}-switch';
|
|
|
161
208
|
}
|
|
162
209
|
|
|
163
210
|
.#{$component}-thumb {
|
|
164
|
-
background-color: t.color('
|
|
165
|
-
opacity:
|
|
211
|
+
background-color: t.color('surface-dim');
|
|
212
|
+
opacity: 0.38;
|
|
166
213
|
&-icon {
|
|
167
|
-
color: t.color('
|
|
214
|
+
color: t.color('on-surface');
|
|
168
215
|
}
|
|
169
216
|
}
|
|
170
217
|
}
|
|
171
218
|
}
|
|
172
219
|
|
|
173
|
-
//
|
|
174
|
-
&:not(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
top: -8px;
|
|
180
|
-
left: -8px;
|
|
181
|
-
right: -8px;
|
|
182
|
-
bottom: -8px;
|
|
183
|
-
background-color: t.color('on-surface');
|
|
184
|
-
opacity: v.state('hover-state-layer-opacity');
|
|
185
|
-
border-radius: 20px;
|
|
186
|
-
}
|
|
220
|
+
// Interactive states for enabled switches
|
|
221
|
+
&:not(.#{$component}--disabled) {
|
|
222
|
+
// Remove track hover effects
|
|
223
|
+
.#{$component}-input:hover + .#{$component}-track::before,
|
|
224
|
+
.#{$component}-input:active + .#{$component}-track::before {
|
|
225
|
+
display: none;
|
|
187
226
|
}
|
|
188
|
-
|
|
189
|
-
//
|
|
190
|
-
.#{$component}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
227
|
+
|
|
228
|
+
// Handle hover and active states for both unchecked
|
|
229
|
+
&:not(.#{$component}--checked) {
|
|
230
|
+
.#{$component}-input:hover ~ .#{$component}-track,
|
|
231
|
+
.#{$component}-input:active ~ .#{$component}-track {
|
|
232
|
+
.#{$component}-thumb {
|
|
233
|
+
background-color: t.color('on-surface-variant');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
&::after {
|
|
237
|
+
background-color: t.color('on-surface');
|
|
238
|
+
opacity: v.state('hover-state-layer-opacity');
|
|
239
|
+
transform: translateX(-6px);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.#{$component}-input:active ~ .#{$component}-track::after {
|
|
199
244
|
opacity: v.state('pressed-state-layer-opacity');
|
|
200
|
-
border-radius: 20px;
|
|
201
245
|
}
|
|
202
246
|
}
|
|
203
247
|
|
|
204
|
-
// Hover/active states
|
|
248
|
+
// Hover/active states for checked
|
|
205
249
|
&.#{$component}--checked {
|
|
206
|
-
.#{$component}-input:hover
|
|
207
|
-
.#{$component}-input:active
|
|
208
|
-
|
|
250
|
+
.#{$component}-input:hover ~ .#{$component}-track,
|
|
251
|
+
.#{$component}-input:active ~ .#{$component}-track {
|
|
252
|
+
&::after {
|
|
253
|
+
background-color: t.color('primary');
|
|
254
|
+
opacity: v.state('hover-state-layer-opacity');
|
|
255
|
+
transform: translateX(14px);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.#{$component}-input:active ~ .#{$component}-track::after {
|
|
260
|
+
opacity: v.state('pressed-state-layer-opacity');
|
|
209
261
|
}
|
|
210
262
|
}
|
|
263
|
+
|
|
264
|
+
// Expand thumb on press for both checked and unchecked
|
|
265
|
+
.#{$component}-input:active ~ .#{$component}-track .#{$component}-thumb {
|
|
266
|
+
width: 28px;
|
|
267
|
+
height: 28px;
|
|
268
|
+
top: 0;
|
|
269
|
+
left: 0;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
&.#{$component}--checked .#{$component}-input:active ~ .#{$component}-track .#{$component}-thumb {
|
|
273
|
+
left: 0;
|
|
274
|
+
}
|
|
211
275
|
}
|
|
212
276
|
|
|
213
277
|
// Accessibility
|
|
@@ -286,12 +286,12 @@ $component: '#{base.$prefix}-textfield';
|
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
// Hover state
|
|
290
|
-
&:hover {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
289
|
+
// // Hover state
|
|
290
|
+
// &:hover {
|
|
291
|
+
// .#{$component}-label {
|
|
292
|
+
// color: t.color('primary');
|
|
293
|
+
// }
|
|
294
|
+
// }
|
|
295
295
|
|
|
296
296
|
// Error state
|
|
297
297
|
&.#{$component}--error {
|
|
@@ -382,6 +382,7 @@ $component: '#{base.$prefix}-textfield';
|
|
|
382
382
|
|
|
383
383
|
// ===== OUTLINED VARIANT =====
|
|
384
384
|
&--outlined {
|
|
385
|
+
background-color: inherit;
|
|
385
386
|
border-radius: f.get-shape('extra-small');
|
|
386
387
|
@include m.motion-transition(border-color);
|
|
387
388
|
|
|
@@ -410,6 +411,7 @@ $component: '#{base.$prefix}-textfield';
|
|
|
410
411
|
}
|
|
411
412
|
|
|
412
413
|
.#{$component}-label {
|
|
414
|
+
background-color: inherit;
|
|
413
415
|
padding: 0 4px;
|
|
414
416
|
left: 12px;
|
|
415
417
|
top: 49%;
|
|
@@ -431,7 +433,6 @@ $component: '#{base.$prefix}-textfield';
|
|
|
431
433
|
&:not(.#{$component}--empty) .#{$component}-label,
|
|
432
434
|
&.#{$component}--focused .#{$component}-label {
|
|
433
435
|
padding: 0 4px;
|
|
434
|
-
background-color: t.color('surface');
|
|
435
436
|
transform: translateY(-147%) scale(0.75);
|
|
436
437
|
}
|
|
437
438
|
|
|
@@ -445,18 +446,10 @@ $component: '#{base.$prefix}-textfield';
|
|
|
445
446
|
border-width: 2px;
|
|
446
447
|
}
|
|
447
448
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
// Hover state
|
|
451
|
-
&:hover {
|
|
449
|
+
|
|
452
450
|
.#{$component}-label {
|
|
453
451
|
color: t.color('primary');
|
|
454
452
|
}
|
|
455
|
-
|
|
456
|
-
&::before {
|
|
457
|
-
opacity: 1;
|
|
458
|
-
border: 1px solid t.color('primary');
|
|
459
|
-
}
|
|
460
453
|
}
|
|
461
454
|
|
|
462
455
|
// Error state
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
// src/components/navigation/system-types.ts
|
|
2
|
-
|
|
3
|
-
import { NavigationComponent, NavItemConfig } from './types';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Structure for navigation section with its items
|
|
7
|
-
*/
|
|
8
|
-
export interface NavigationSection {
|
|
9
|
-
/** Section label */
|
|
10
|
-
label: string;
|
|
11
|
-
|
|
12
|
-
/** Section icon HTML */
|
|
13
|
-
icon?: string;
|
|
14
|
-
|
|
15
|
-
/** Navigation items within this section */
|
|
16
|
-
items: NavItemConfig[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Configuration for the navigation system
|
|
21
|
-
*/
|
|
22
|
-
export interface NavigationSystemConfig {
|
|
23
|
-
/** Item structure by section ID */
|
|
24
|
-
items: Record<string, NavigationSection>;
|
|
25
|
-
|
|
26
|
-
/** Initial active section */
|
|
27
|
-
activeSection?: string;
|
|
28
|
-
|
|
29
|
-
/** Initial active subsection */
|
|
30
|
-
activeSubsection?: string;
|
|
31
|
-
|
|
32
|
-
/** Whether to animate drawer opening/closing */
|
|
33
|
-
animateDrawer?: boolean;
|
|
34
|
-
|
|
35
|
-
/** Whether to show labels on rail */
|
|
36
|
-
showLabelsOnRail?: boolean;
|
|
37
|
-
|
|
38
|
-
/** Whether to hide drawer when an item is clicked */
|
|
39
|
-
hideDrawerOnClick?: boolean;
|
|
40
|
-
|
|
41
|
-
/** Delay before showing drawer on hover (ms) */
|
|
42
|
-
hoverDelay?: number;
|
|
43
|
-
|
|
44
|
-
/** Delay before hiding drawer on mouse leave (ms) */
|
|
45
|
-
closeDelay?: number;
|
|
46
|
-
|
|
47
|
-
/** Configuration options passed to rail component */
|
|
48
|
-
railOptions?: Record<string, any>;
|
|
49
|
-
|
|
50
|
-
/** Configuration options passed to drawer component */
|
|
51
|
-
drawerOptions?: Record<string, any>;
|
|
52
|
-
|
|
53
|
-
/** Enable debug logging */
|
|
54
|
-
debug?: boolean;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Event data for section change events
|
|
59
|
-
*/
|
|
60
|
-
export interface SectionChangeEvent {
|
|
61
|
-
/** ID of the selected section */
|
|
62
|
-
section: string;
|
|
63
|
-
|
|
64
|
-
/** Section data */
|
|
65
|
-
sectionData: NavigationSection;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Event data for item selection events
|
|
70
|
-
*/
|
|
71
|
-
export interface ItemSelectEvent {
|
|
72
|
-
/** ID of the parent section */
|
|
73
|
-
section: string;
|
|
74
|
-
|
|
75
|
-
/** ID of the selected subsection */
|
|
76
|
-
subsection: string;
|
|
77
|
-
|
|
78
|
-
/** Selected item data */
|
|
79
|
-
item: any;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Navigation system API
|
|
84
|
-
*/
|
|
85
|
-
export interface NavigationSystem {
|
|
86
|
-
/** Initialize the navigation system */
|
|
87
|
-
initialize(): NavigationSystem;
|
|
88
|
-
|
|
89
|
-
/** Clean up resources */
|
|
90
|
-
cleanup(): void;
|
|
91
|
-
|
|
92
|
-
/** Navigate to a specific section and subsection */
|
|
93
|
-
navigateTo(section: string, subsection?: string): void;
|
|
94
|
-
|
|
95
|
-
/** Get the rail component */
|
|
96
|
-
getRail(): NavigationComponent | null;
|
|
97
|
-
|
|
98
|
-
/** Get the drawer component */
|
|
99
|
-
getDrawer(): NavigationComponent | null;
|
|
100
|
-
|
|
101
|
-
/** Get the active section */
|
|
102
|
-
getActiveSection(): string | null;
|
|
103
|
-
|
|
104
|
-
/** Get the active subsection */
|
|
105
|
-
getActiveSubsection(): string | null;
|
|
106
|
-
|
|
107
|
-
/** Show the drawer */
|
|
108
|
-
showDrawer(): void;
|
|
109
|
-
|
|
110
|
-
/** Hide the drawer */
|
|
111
|
-
hideDrawer(): void;
|
|
112
|
-
|
|
113
|
-
/** Check if drawer is visible */
|
|
114
|
-
isDrawerVisible(): boolean;
|
|
115
|
-
|
|
116
|
-
/** Configure the navigation system */
|
|
117
|
-
configure(config: Partial<NavigationSystemConfig>): NavigationSystem;
|
|
118
|
-
|
|
119
|
-
/** Event handler for section changes */
|
|
120
|
-
onSectionChange: ((section: string, subsection?: string) => void) | null;
|
|
121
|
-
|
|
122
|
-
/** Event handler for item selection */
|
|
123
|
-
onItemSelect: ((event: ItemSelectEvent) => void) | null;
|
|
124
|
-
}
|