mtrl 0.0.2 → 0.1.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 (52) hide show
  1. package/package.json +2 -2
  2. package/src/components/button/styles.scss +198 -161
  3. package/src/components/checkbox/checkbox.js +4 -3
  4. package/src/components/checkbox/styles.scss +105 -55
  5. package/src/components/container/styles.scss +65 -58
  6. package/src/components/list/styles.scss +240 -11
  7. package/src/components/menu/features/items-manager.js +5 -1
  8. package/src/components/menu/styles.scss +37 -30
  9. package/src/components/navigation/constants.js +19 -54
  10. package/src/components/navigation/styles.scss +406 -6
  11. package/src/components/snackbar/styles.scss +46 -17
  12. package/src/components/switch/styles.scss +104 -40
  13. package/src/components/switch/switch.js +1 -1
  14. package/src/components/textfield/styles.scss +351 -5
  15. package/src/core/build/_ripple.scss +79 -0
  16. package/src/core/compose/features/disabled.js +27 -7
  17. package/src/core/compose/features/input.js +9 -1
  18. package/src/core/compose/features/textinput.js +16 -20
  19. package/src/core/dom/create.js +0 -1
  20. package/src/styles/abstract/_mixins.scss +9 -7
  21. package/src/styles/abstract/_theme.scss +157 -0
  22. package/src/styles/abstract/_variables.scss +72 -6
  23. package/src/styles/base/_reset.scss +86 -0
  24. package/src/styles/base/_typography.scss +155 -0
  25. package/src/styles/main.scss +104 -57
  26. package/src/styles/themes/_base-theme.scss +2 -27
  27. package/src/styles/themes/_baseline.scss +64 -39
  28. package/src/styles/utilities/_color.scss +154 -0
  29. package/src/styles/utilities/_flexbox.scss +194 -0
  30. package/src/styles/utilities/_spacing.scss +139 -0
  31. package/src/styles/utilities/_typography.scss +178 -0
  32. package/src/styles/utilities/_visibility.scss +142 -0
  33. package/test/components/button.test.js +46 -34
  34. package/test/components/checkbox.test.js +238 -0
  35. package/test/components/list.test.js +105 -0
  36. package/test/components/menu.test.js +385 -0
  37. package/test/components/navigation.test.js +227 -0
  38. package/test/components/snackbar.test.js +234 -0
  39. package/test/components/switch.test.js +186 -0
  40. package/test/components/textfield.test.js +314 -0
  41. package/test/core/ripple.test.js +21 -120
  42. package/test/setup.js +152 -239
  43. package/src/components/list/styles/_list-item.scss +0 -142
  44. package/src/components/list/styles/_list.scss +0 -89
  45. package/src/components/list/styles/_variables.scss +0 -13
  46. package/src/components/navigation/styles/_bar.scss +0 -51
  47. package/src/components/navigation/styles/_base.scss +0 -129
  48. package/src/components/navigation/styles/_drawer.scss +0 -169
  49. package/src/components/navigation/styles/_rail.scss +0 -65
  50. package/src/components/textfield/styles/base.scss +0 -107
  51. package/src/components/textfield/styles/filled.scss +0 -58
  52. package/src/components/textfield/styles/outlined.scss +0 -66
@@ -1,30 +1,33 @@
1
- // src/components/menu/styles.scss
2
- @use 'sass:map';
3
- @use '../../styles/abstract/config' as c;
4
- @use '../../styles/abstract/mixins' as m;
1
+ // src/components/menu/_menu.scss
2
+ @use '../../styles/abstract/base' as base;
5
3
  @use '../../styles/abstract/variables' as v;
4
+ @use '../../styles/abstract/functions' as f;
5
+ @use '../../styles/abstract/mixins' as m;
6
+ @use '../../styles/abstract/theme' as t;
7
+
8
+ $component: '#{base.$prefix}-menu';
6
9
 
7
- .#{c.$prefix}-menu {
10
+ .#{$component} {
8
11
  // Base styles
9
- @include c.typography('body-medium');
10
- @include c.shape('small');
12
+ @include m.typography('body-medium');
13
+ @include m.shape('extra-small');
11
14
 
12
15
  position: fixed;
13
- z-index: map.get(v.$z-index, 'menu');
16
+ z-index: f.get-z-index('menu');
14
17
  min-width: 112px;
15
18
  max-width: 280px;
16
19
  padding: 8px 0;
17
- background-color: var(--mtrl-sys-color-surface-container);
18
- color: var(--mtrl-sys-color-on-surface);
19
- @include c.elevation(2);
20
+ background-color: t.color('surface-container');
21
+ color: t.color('on-surface');
22
+ @include m.elevation(2);
20
23
 
21
24
  display: none;
22
25
  opacity: 0;
23
26
  transform: scale(0.8);
24
27
  transform-origin: top left;
25
28
  pointer-events: none;
26
- transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1),
27
- transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
29
+ transition: opacity v.motion('duration-short2') v.motion('easing-standard'),
30
+ transform v.motion('duration-short2') v.motion('easing-standard');
28
31
 
29
32
  &--visible {
30
33
  display: block;
@@ -35,7 +38,7 @@
35
38
 
36
39
  &--submenu {
37
40
  position: absolute;
38
- z-index: map.get(v.$z-index, 'menu') + 1;
41
+ z-index: f.get-z-index('menu') + 1;
39
42
  }
40
43
 
41
44
  // List container
@@ -50,7 +53,7 @@
50
53
 
51
54
  // Menu items
52
55
  &-item {
53
- @include c.typography('body-large');
56
+ @include m.typography('body-large');
54
57
  @include m.flex-row;
55
58
 
56
59
  position: relative;
@@ -58,20 +61,20 @@
58
61
  padding: 12px 16px;
59
62
  cursor: pointer;
60
63
  user-select: none;
61
- color: var(--mtrl-sys-color-on-surface);
62
- transition: background-color 150ms cubic-bezier(0.4, 0, 0.2, 1);
64
+ color: t.color('on-surface');
65
+ @include m.motion-transition(background-color);
63
66
 
64
67
  &:hover {
65
- @include c.state-layer(var(--mtrl-sys-color-on-surface), 'hover');
68
+ @include m.state-layer(t.color('on-surface'), 'hover');
66
69
  }
67
70
 
68
71
  &:focus {
69
- @include c.state-layer(var(--mtrl-sys-color-on-surface), 'focus');
72
+ @include m.state-layer(t.color('on-surface'), 'focus');
70
73
  outline: none;
71
74
  }
72
75
 
73
76
  &:active {
74
- @include c.state-layer(var(--mtrl-sys-color-on-surface), 'pressed');
77
+ @include m.state-layer(t.color('on-surface'), 'pressed');
75
78
  }
76
79
 
77
80
  // Submenu indicator
@@ -88,7 +91,7 @@
88
91
  }
89
92
 
90
93
  &[aria-expanded="true"] {
91
- @include c.state-layer(var(--mtrl-sys-color-on-surface), 'hover');
94
+ @include m.state-layer(t.color('on-surface'), 'hover');
92
95
 
93
96
  &::after {
94
97
  opacity: 1;
@@ -99,7 +102,7 @@
99
102
  // Disabled state
100
103
  &--disabled {
101
104
  pointer-events: none;
102
- color: rgba(var(--mtrl-sys-color-on-surface-rgb), 0.38);
105
+ color: t.alpha('on-surface', 0.38);
103
106
  }
104
107
  }
105
108
 
@@ -107,34 +110,38 @@
107
110
  &-divider {
108
111
  height: 1px;
109
112
  margin: 8px 0;
110
- background-color: var(--mtrl-sys-color-outline-variant);
113
+ background-color: t.color('outline-variant');
111
114
  }
112
115
 
113
116
  // Accessibility
114
- @include c.focus-ring('.#{c.$prefix}-menu-item:focus-visible');
117
+ @include m.focus-ring('.#{$component}-item:focus-visible');
115
118
 
116
- @include c.reduced-motion {
119
+ @include m.reduced-motion {
117
120
  transition: none;
121
+
122
+ .#{$component}-item {
123
+ transition: none;
124
+ }
118
125
  }
119
126
 
120
- @include c.high-contrast {
127
+ @include m.high-contrast {
121
128
  border: 1px solid CurrentColor;
122
129
 
123
- .#{c.$prefix}-menu-divider {
130
+ .#{$component}-divider {
124
131
  background-color: CurrentColor;
125
132
  }
126
133
 
127
- .#{c.$prefix}-menu-item--disabled {
134
+ .#{$component}-item--disabled {
128
135
  opacity: 1;
129
136
  color: GrayText;
130
137
  }
131
138
  }
132
139
 
133
140
  // RTL Support
134
- @include c.rtl {
141
+ @include m.rtl {
135
142
  transform-origin: top right;
136
143
 
137
- .#{c.$prefix}-menu-item {
144
+ .#{$component}-item {
138
145
  &--submenu {
139
146
  padding-right: 16px;
140
147
  padding-left: 48px;
@@ -121,8 +121,17 @@ export const NAV_SCHEMA = {
121
121
  }
122
122
  }
123
123
 
124
+ /**
125
+ * Navigation item states
126
+ */
127
+ export const NAV_ITEM_STATES = {
128
+ EXPANDED: 'expanded',
129
+ COLLAPSED: 'collapsed'
130
+ }
131
+
124
132
  /**
125
133
  * Navigation item schema
134
+ * Enhanced with support for nested items
126
135
  */
127
136
  export const NAV_ITEM_SCHEMA = {
128
137
  type: 'object',
@@ -154,82 +163,38 @@ export const NAV_ITEM_SCHEMA = {
154
163
  groupId: {
155
164
  type: 'string',
156
165
  optional: true
157
- }
158
- }
159
- }
160
-
161
- /**
162
- * Navigation group schema
163
- */
164
- export const NAV_GROUP_SCHEMA = {
165
- type: 'object',
166
- properties: {
167
- id: {
168
- type: 'string',
169
- required: true
170
166
  },
171
- title: {
172
- type: 'string',
173
- required: true
167
+ items: {
168
+ type: 'array',
169
+ optional: true,
170
+ description: 'Nested navigation items'
174
171
  },
175
172
  expanded: {
176
173
  type: 'boolean',
177
174
  optional: true,
178
- default: true
175
+ default: false
179
176
  }
180
177
  }
181
178
  }
182
179
 
183
180
  /**
184
- * Navigation item states
181
+ * Navigation group schema
185
182
  */
186
- export const NAV_ITEM_STATES = {
187
- EXPANDED: 'expanded',
188
- COLLAPSED: 'collapsed'
189
- }
190
-
191
-
192
- // Update NAV_ITEM_SCHEMA to support nested items
193
- export const NAV_ITEM_SCHEMA = {
183
+ export const NAV_GROUP_SCHEMA = {
194
184
  type: 'object',
195
185
  properties: {
196
186
  id: {
197
187
  type: 'string',
198
188
  required: true
199
189
  },
200
- icon: {
201
- type: 'string',
202
- required: true
203
- },
204
- label: {
190
+ title: {
205
191
  type: 'string',
206
192
  required: true
207
193
  },
208
- badge: {
209
- type: 'string',
210
- optional: true
211
- },
212
- disabled: {
213
- type: 'boolean',
214
- optional: true
215
- },
216
- subtitle: {
217
- type: 'string',
218
- optional: true
219
- },
220
- groupId: {
221
- type: 'string',
222
- optional: true
223
- },
224
- items: {
225
- type: 'array',
226
- optional: true,
227
- description: 'Nested navigation items'
228
- },
229
194
  expanded: {
230
195
  type: 'boolean',
231
196
  optional: true,
232
- default: false
197
+ default: true
233
198
  }
234
199
  }
235
- }
200
+ }
@@ -1,6 +1,406 @@
1
- // src/components/navigation/styles.scss
2
- @use '../../styles/abstract/config' as c;
3
- @use 'styles/base';
4
- @use 'styles/rail';
5
- @use 'styles/drawer';
6
- @use 'styles/bar';
1
+ // src/components/navigation/_navigation.scss
2
+ @use '../../styles/abstract/base' as base;
3
+ @use '../../styles/abstract/variables' as v;
4
+ @use '../../styles/abstract/functions' as f;
5
+ @use '../../styles/abstract/mixins' as m;
6
+ @use '../../styles/abstract/theme' as t;
7
+
8
+ $component: '#{base.$prefix}-nav';
9
+
10
+ // BASE STYLES
11
+ .#{$component} {
12
+ display: flex;
13
+ position: relative;
14
+ background-color: t.color('surface-container');
15
+
16
+ // Base nav item styles
17
+ &-item {
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: center;
21
+ position: relative;
22
+ border: none;
23
+ background: none;
24
+ cursor: pointer;
25
+ padding: 12px;
26
+ gap: 12px;
27
+ color: t.color('on-surface-variant');
28
+ @include m.motion-transition(all);
29
+
30
+ &-icon {
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: center;
34
+ width: 24px;
35
+ height: 24px;
36
+ color: inherit;
37
+ border-radius: 50%;
38
+ padding: 8px;
39
+
40
+ svg {
41
+ width: 24px;
42
+ height: 24px;
43
+ fill: currentColor;
44
+ }
45
+ }
46
+
47
+ &--active {
48
+ color: t.color('primary');
49
+ }
50
+
51
+ &-label {
52
+ @include m.typography('label-large');
53
+ @include m.motion-transition(opacity);
54
+ }
55
+
56
+ &-badge {
57
+ position: absolute;
58
+ top: 8px;
59
+ right: 8px;
60
+ min-width: 16px;
61
+ height: 16px;
62
+ padding: 0 4px;
63
+ border-radius: 8px;
64
+ background-color: t.color('error');
65
+ color: t.color('on-error');
66
+ @include m.typography('label-small');
67
+ display: flex;
68
+ align-items: center;
69
+ justify-content: center;
70
+ }
71
+ }
72
+
73
+ // Navigation positions
74
+ &--left {
75
+ left: 0;
76
+ }
77
+
78
+ &--right {
79
+ right: 0;
80
+ }
81
+
82
+ &--top {
83
+ top: 0;
84
+ }
85
+
86
+ &--bottom {
87
+ bottom: 0;
88
+ }
89
+
90
+ // States
91
+ &--disabled {
92
+ opacity: 0.38;
93
+ pointer-events: none;
94
+ }
95
+
96
+ // RTL Support
97
+ @include m.rtl {
98
+ &--left {
99
+ right: 0;
100
+ left: auto;
101
+ }
102
+
103
+ &--right {
104
+ left: 0;
105
+ right: auto;
106
+ }
107
+
108
+ .#{$component}-item {
109
+ &-badge {
110
+ right: auto;
111
+ left: 8px;
112
+ }
113
+ }
114
+ }
115
+
116
+ // Motion
117
+ @include m.reduced-motion {
118
+ &-item,
119
+ &-item-label {
120
+ transition: none;
121
+ }
122
+ }
123
+
124
+ // High contrast
125
+ @include m.high-contrast {
126
+ border: 1px solid currentColor;
127
+
128
+ &-item {
129
+ &--active {
130
+ outline: 2px solid currentColor;
131
+ outline-offset: -2px;
132
+ }
133
+ }
134
+ }
135
+
136
+ // BAR NAVIGATION
137
+ &--bar {
138
+ flex-direction: row;
139
+ width: 100%;
140
+ height: 80px;
141
+ padding: 0 12px;
142
+ justify-content: space-around;
143
+
144
+ .#{$component}-item {
145
+ flex: 1;
146
+ flex-direction: column;
147
+ height: 100%;
148
+ max-width: 168px;
149
+ gap: 4px;
150
+
151
+ &:hover {
152
+ .#{$component}-item-icon {
153
+ @include m.state-layer(t.color('on-surface'), 'hover');
154
+ }
155
+ }
156
+
157
+ &--active {
158
+ .#{$component}-item-icon {
159
+ background-color: t.color('secondary-container');
160
+ }
161
+ }
162
+
163
+ &-icon {
164
+ margin-bottom: 4px;
165
+ padding: 16px;
166
+ @include m.motion-transition(background-color);
167
+ }
168
+
169
+ &-label {
170
+ @include m.typography('label-medium');
171
+ text-align: center;
172
+ }
173
+
174
+ &-badge {
175
+ top: 4px;
176
+ right: 50%;
177
+ transform: translateX(12px);
178
+ }
179
+ }
180
+ }
181
+
182
+ // RAIL NAVIGATION
183
+ &--rail {
184
+ flex-direction: column;
185
+ width: 80px;
186
+ height: 100%;
187
+ padding: 12px 0;
188
+
189
+ .#{$component}-item {
190
+ flex-direction: column;
191
+ width: 100%;
192
+ min-height: 56px;
193
+ padding: 2px;
194
+ margin: -2px auto 14px;
195
+ gap: 0;
196
+
197
+ &:hover {
198
+ .#{$component}-item-icon {
199
+ @include m.state-layer(t.color('on-surface'), 'hover');
200
+ }
201
+ }
202
+
203
+ &--active {
204
+ .#{$component}-item-icon {
205
+ background-color: t.color('secondary-container');
206
+ }
207
+ }
208
+
209
+ &-icon {
210
+ margin-bottom: 4px;
211
+ padding: 8px;
212
+ width: 56px;
213
+ height: 32px;
214
+ display: flex;
215
+ align-items: center;
216
+ justify-content: center;
217
+ border-radius: 16px;
218
+ @include m.motion-transition(background-color);
219
+
220
+ svg {
221
+ width: 24px;
222
+ height: 24px;
223
+ fill: currentColor;
224
+ }
225
+ }
226
+
227
+ &-label {
228
+ @include m.typography('label-small');
229
+ text-align: center;
230
+ color: inherit;
231
+ font-size: 12px;
232
+ line-height: 16px;
233
+ }
234
+
235
+ &-badge {
236
+ top: 4px;
237
+ right: 16px;
238
+ }
239
+ }
240
+ }
241
+
242
+ // DRAWER NAVIGATION STYLES (BOTH MODAL AND STANDARD)
243
+ &--drawer,
244
+ &--drawer-modal,
245
+ &--drawer-standard {
246
+ flex-direction: column;
247
+ width: 256px;
248
+ height: 100%;
249
+ padding: 12px 0;
250
+ transition: transform v.motion('duration-short2') v.motion('easing-standard');
251
+ transform: translateX(0);
252
+
253
+ // Hidden state
254
+ &.#{$component}--hidden {
255
+ transform: translateX(-100%);
256
+
257
+ @include m.rtl {
258
+ transform: translateX(100%);
259
+ }
260
+ }
261
+
262
+ // Item container for nesting
263
+ .#{$component}-item-container {
264
+ width: 100%;
265
+ display: flex;
266
+ flex-direction: column;
267
+ }
268
+
269
+ // Base nav item styles
270
+ .#{$component}-item {
271
+ padding: 12px 16px;
272
+ align-items: center;
273
+ justify-content: flex-start;
274
+ border-radius: 28px;
275
+ margin: 0 12px;
276
+ width: calc(100% - 24px);
277
+
278
+ &:hover {
279
+ @include m.state-layer(t.color('on-surface'), 'hover');
280
+ }
281
+
282
+ &--active {
283
+ background-color: t.color('secondary-container');
284
+ color: t.color('on-secondary-container');
285
+
286
+ &:hover {
287
+ background-color: t.color('secondary-container');
288
+ }
289
+ }
290
+
291
+ &-icon {
292
+ margin-right: 12px;
293
+ flex-shrink: 0;
294
+ }
295
+
296
+ &-label {
297
+ @include m.typography('label-large');
298
+ flex-grow: 1;
299
+ text-align: left;
300
+ }
301
+
302
+ &-badge {
303
+ position: static;
304
+ margin-left: auto;
305
+ margin-right: 8px;
306
+ }
307
+ }
308
+
309
+ // Nested navigation styles
310
+ .#{$component}-nested-container {
311
+ display: flex;
312
+ flex-direction: column;
313
+ width: 100%;
314
+ margin-left: 28px;
315
+ padding-right: 12px;
316
+
317
+ &[hidden] {
318
+ display: none;
319
+ }
320
+
321
+ // Adjust nested items styles
322
+ .#{$component}-item {
323
+ margin: 0;
324
+ padding: 8px 16px;
325
+ font-size: 14px;
326
+
327
+ &-icon {
328
+ width: 20px;
329
+ height: 20px;
330
+ padding: 6px;
331
+
332
+ svg {
333
+ width: 20px;
334
+ height: 20px;
335
+ }
336
+ }
337
+ }
338
+ }
339
+
340
+ // Expand icon styles
341
+ .#{$component}-expand-icon {
342
+ display: flex;
343
+ align-items: center;
344
+ justify-content: center;
345
+ width: 20px;
346
+ height: 20px;
347
+ margin-left: auto;
348
+ color: inherit;
349
+ @include m.motion-transition(transform);
350
+
351
+ svg {
352
+ width: 20px;
353
+ height: 20px;
354
+ fill: none;
355
+ stroke: currentColor;
356
+ stroke-width: 2px;
357
+ }
358
+ }
359
+
360
+ // RTL support
361
+ @include m.rtl {
362
+ .#{$component}-item {
363
+ &-icon {
364
+ margin-right: 0;
365
+ margin-left: 12px;
366
+ }
367
+
368
+ &-label {
369
+ text-align: right;
370
+ }
371
+
372
+ &-badge {
373
+ margin-left: 8px;
374
+ margin-right: auto;
375
+ }
376
+ }
377
+
378
+ .#{$component}-nested-container {
379
+ margin-left: 0;
380
+ margin-right: 28px;
381
+ padding-right: 0;
382
+ padding-left: 12px;
383
+ }
384
+
385
+ .#{$component}-expand-icon {
386
+ margin-left: 0;
387
+ margin-right: auto;
388
+ transform: scaleX(-1);
389
+ }
390
+ }
391
+ }
392
+
393
+ // Specific drawer variants
394
+ &--drawer-modal {
395
+ @include m.elevation(2);
396
+ }
397
+
398
+ &--drawer-standard {
399
+ border-right: 1px solid t.color('outline-variant');
400
+
401
+ @include m.rtl {
402
+ border-right: none;
403
+ border-left: 1px solid t.color('outline-variant');
404
+ }
405
+ }
406
+ }