mtrl 0.0.3 → 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.
- package/package.json +1 -1
- package/src/components/button/styles.scss +198 -161
- package/src/components/checkbox/checkbox.js +3 -2
- package/src/components/checkbox/styles.scss +105 -55
- package/src/components/container/styles.scss +65 -58
- package/src/components/list/constants.js +0 -5
- package/src/components/list/list-item.js +12 -4
- package/src/components/list/list.js +11 -19
- package/src/components/list/styles.scss +240 -11
- package/src/components/menu/styles.scss +37 -30
- package/src/components/navigation/styles.scss +406 -6
- package/src/components/snackbar/styles.scss +46 -17
- package/src/components/switch/styles.scss +93 -46
- package/src/components/textfield/styles.scss +351 -5
- package/src/core/build/_ripple.scss +79 -0
- package/src/core/dom/create.js +0 -1
- package/src/styles/abstract/_mixins.scss +9 -7
- package/src/styles/abstract/_theme.scss +157 -0
- package/src/styles/abstract/_variables.scss +72 -6
- package/src/styles/base/_reset.scss +86 -0
- package/src/styles/base/_typography.scss +155 -0
- package/src/styles/main.scss +104 -57
- package/src/styles/themes/_base-theme.scss +2 -27
- package/src/styles/themes/_baseline.scss +64 -39
- package/src/styles/utilities/_color.scss +154 -0
- package/src/styles/utilities/_flexbox.scss +194 -0
- package/src/styles/utilities/_spacing.scss +139 -0
- package/src/styles/utilities/_typography.scss +178 -0
- package/src/styles/utilities/_visibility.scss +142 -0
- package/src/components/list/styles/_list-item.scss +0 -142
- package/src/components/list/styles/_list.scss +0 -89
- package/src/components/list/styles/_variables.scss +0 -13
- package/src/components/navigation/styles/_bar.scss +0 -51
- package/src/components/navigation/styles/_base.scss +0 -129
- package/src/components/navigation/styles/_drawer.scss +0 -169
- package/src/components/navigation/styles/_rail.scss +0 -65
- package/src/components/textfield/styles/base.scss +0 -107
- package/src/components/textfield/styles/filled.scss +0 -58
- package/src/components/textfield/styles/outlined.scss +0 -66
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
// src/components/checkbox/
|
|
2
|
-
@use '
|
|
3
|
-
@use '../../styles/abstract/
|
|
1
|
+
// src/components/checkbox/_checkbox.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;
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
$component: '#{base.$prefix}-checkbox';
|
|
9
|
+
|
|
10
|
+
.#{$component} {
|
|
11
|
+
// Base styles
|
|
6
12
|
display: inline-flex;
|
|
7
13
|
align-items: center;
|
|
8
14
|
position: relative;
|
|
@@ -10,6 +16,7 @@
|
|
|
10
16
|
padding: 4px 0;
|
|
11
17
|
user-select: none;
|
|
12
18
|
|
|
19
|
+
// Input (visually hidden but accessible)
|
|
13
20
|
&-input {
|
|
14
21
|
position: absolute;
|
|
15
22
|
opacity: 0;
|
|
@@ -23,22 +30,24 @@
|
|
|
23
30
|
cursor: not-allowed;
|
|
24
31
|
}
|
|
25
32
|
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
// Focus indicator
|
|
34
|
+
&:focus-visible ~ .#{$component}-icon {
|
|
35
|
+
outline: 2px solid t.color('primary');
|
|
28
36
|
outline-offset: 2px;
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
39
|
|
|
40
|
+
// Checkbox visual element
|
|
32
41
|
&-icon {
|
|
33
42
|
position: relative;
|
|
34
43
|
width: 18px;
|
|
35
44
|
height: 18px;
|
|
36
|
-
border-radius:
|
|
37
|
-
background-color:
|
|
38
|
-
border: 2px solid
|
|
39
|
-
|
|
40
|
-
border-color map.get(c.$motion, 'duration-short4') map.get(c.$motion, 'easing-standard');
|
|
45
|
+
border-radius: f.get-shape('tiny');
|
|
46
|
+
background-color: t.color('surface-container-highest');
|
|
47
|
+
border: 2px solid t.color('outline');
|
|
48
|
+
@include m.motion-transition(background-color, border-color);
|
|
41
49
|
|
|
50
|
+
// Check mark icon
|
|
42
51
|
svg {
|
|
43
52
|
position: absolute;
|
|
44
53
|
top: 50%;
|
|
@@ -47,22 +56,23 @@
|
|
|
47
56
|
height: 18px;
|
|
48
57
|
transform: translate(-50%, -50%) scale(0);
|
|
49
58
|
fill: currentColor;
|
|
50
|
-
color:
|
|
51
|
-
transition: transform
|
|
59
|
+
color: t.color('on-primary');
|
|
60
|
+
transition: transform v.motion('duration-short4') v.motion('easing-emphasized');
|
|
52
61
|
}
|
|
53
62
|
}
|
|
54
63
|
|
|
64
|
+
// Label styling
|
|
55
65
|
&-label {
|
|
56
|
-
@include
|
|
66
|
+
@include m.typography('body-large');
|
|
57
67
|
margin-left: 12px;
|
|
58
|
-
color:
|
|
68
|
+
color: t.color('on-surface');
|
|
59
69
|
}
|
|
60
70
|
|
|
61
71
|
// Label position variants
|
|
62
72
|
&--label-start {
|
|
63
73
|
flex-direction: row-reverse;
|
|
64
74
|
|
|
65
|
-
.#{
|
|
75
|
+
.#{$component}-label {
|
|
66
76
|
margin-left: 0;
|
|
67
77
|
margin-right: 12px;
|
|
68
78
|
}
|
|
@@ -71,42 +81,44 @@
|
|
|
71
81
|
&--label-end {
|
|
72
82
|
flex-direction: row;
|
|
73
83
|
|
|
74
|
-
.#{
|
|
84
|
+
.#{$component}-label {
|
|
75
85
|
margin-left: 12px;
|
|
76
86
|
margin-right: 0;
|
|
77
87
|
}
|
|
78
88
|
}
|
|
79
89
|
|
|
80
|
-
|
|
90
|
+
// RTL support
|
|
91
|
+
@include m.rtl {
|
|
81
92
|
&--label-start {
|
|
82
|
-
.#{
|
|
93
|
+
.#{$component}-label {
|
|
83
94
|
margin-left: 12px;
|
|
84
95
|
margin-right: 0;
|
|
85
96
|
}
|
|
86
97
|
}
|
|
87
98
|
|
|
88
99
|
&--label-end {
|
|
89
|
-
.#{
|
|
100
|
+
.#{$component}-label {
|
|
90
101
|
margin-left: 0;
|
|
91
102
|
margin-right: 12px;
|
|
92
103
|
}
|
|
93
104
|
}
|
|
94
105
|
}
|
|
95
106
|
|
|
96
|
-
//
|
|
97
|
-
.#{
|
|
98
|
-
background-color:
|
|
99
|
-
border-color:
|
|
107
|
+
// Checked state
|
|
108
|
+
.#{$component}-input:checked ~ .#{$component}-icon {
|
|
109
|
+
background-color: t.color('primary');
|
|
110
|
+
border-color: t.color('primary');
|
|
100
111
|
|
|
101
112
|
svg {
|
|
102
113
|
transform: translate(-50%, -50%) scale(1);
|
|
103
114
|
}
|
|
104
115
|
}
|
|
105
116
|
|
|
117
|
+
// Indeterminate state
|
|
106
118
|
&--indeterminate {
|
|
107
|
-
.#{
|
|
108
|
-
background-color:
|
|
109
|
-
border-color:
|
|
119
|
+
.#{$component}-icon {
|
|
120
|
+
background-color: t.color('primary');
|
|
121
|
+
border-color: t.color('primary');
|
|
110
122
|
|
|
111
123
|
&::after {
|
|
112
124
|
content: '';
|
|
@@ -116,7 +128,7 @@
|
|
|
116
128
|
transform: translate(-50%, -50%);
|
|
117
129
|
width: 10px;
|
|
118
130
|
height: 2px;
|
|
119
|
-
background-color:
|
|
131
|
+
background-color: t.color('on-primary');
|
|
120
132
|
}
|
|
121
133
|
|
|
122
134
|
svg {
|
|
@@ -125,59 +137,97 @@
|
|
|
125
137
|
}
|
|
126
138
|
}
|
|
127
139
|
|
|
140
|
+
// Disabled state
|
|
128
141
|
&--disabled {
|
|
129
|
-
opacity: .
|
|
142
|
+
opacity: 0.38;
|
|
143
|
+
|
|
144
|
+
.#{$component}-input {
|
|
145
|
+
cursor: not-allowed;
|
|
146
|
+
}
|
|
130
147
|
}
|
|
131
148
|
|
|
132
|
-
//
|
|
149
|
+
// Outlined variant
|
|
133
150
|
&--outlined {
|
|
134
|
-
.#{
|
|
151
|
+
.#{$component}-icon {
|
|
135
152
|
background-color: transparent;
|
|
136
153
|
}
|
|
137
154
|
|
|
138
|
-
.#{
|
|
155
|
+
.#{$component}-input:checked ~ .#{$component}-icon {
|
|
139
156
|
background-color: transparent;
|
|
140
|
-
border-color:
|
|
157
|
+
border-color: t.color('primary');
|
|
141
158
|
|
|
142
159
|
svg {
|
|
143
|
-
color:
|
|
160
|
+
color: t.color('primary');
|
|
144
161
|
}
|
|
145
162
|
}
|
|
146
163
|
|
|
147
|
-
&.#{
|
|
148
|
-
.#{
|
|
149
|
-
background-color:
|
|
164
|
+
&.#{$component}--indeterminate {
|
|
165
|
+
.#{$component}-icon::after {
|
|
166
|
+
background-color: t.color('primary');
|
|
150
167
|
}
|
|
151
168
|
}
|
|
152
169
|
}
|
|
153
170
|
|
|
154
|
-
//
|
|
171
|
+
// State layer effects
|
|
155
172
|
&:not(&--disabled) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
173
|
+
// Common state layer structure
|
|
174
|
+
.#{$component}-input:hover ~ .#{$component}-icon::before,
|
|
175
|
+
.#{$component}-input:active ~ .#{$component}-icon::before {
|
|
176
|
+
content: '';
|
|
177
|
+
position: absolute;
|
|
178
|
+
top: -12px;
|
|
179
|
+
left: -12px;
|
|
180
|
+
right: -12px;
|
|
181
|
+
bottom: -12px;
|
|
182
|
+
border-radius: 50%;
|
|
183
|
+
background-color: t.color('on-surface');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Hover state
|
|
187
|
+
.#{$component}-input:hover ~ .#{$component}-icon::before {
|
|
188
|
+
opacity: v.state('hover-state-layer-opacity');
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Hover checked state
|
|
193
|
+
.#{$component}-input:checked:hover ~ .#{$component}-icon::before {
|
|
194
|
+
opacity: v.state('pressed-state-layer-opacity');
|
|
195
|
+
background-color: t.color('primary');
|
|
196
|
+
}
|
|
197
|
+
// Active/pressed state
|
|
198
|
+
.#{$component}-input:active ~ .#{$component}-icon::before {
|
|
199
|
+
opacity: v.state('pressed-state-layer-opacity');
|
|
200
|
+
background-color: t.color('on-surface');
|
|
168
201
|
}
|
|
169
202
|
}
|
|
170
203
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
.#{
|
|
204
|
+
// Accessibility
|
|
205
|
+
@include m.reduced-motion {
|
|
206
|
+
.#{$component}-icon,
|
|
207
|
+
.#{$component}-icon svg {
|
|
174
208
|
transition: none;
|
|
175
209
|
}
|
|
176
210
|
}
|
|
177
211
|
|
|
178
|
-
@include
|
|
179
|
-
.#{
|
|
212
|
+
@include m.high-contrast {
|
|
213
|
+
.#{$component}-icon {
|
|
180
214
|
border-width: 2px;
|
|
181
215
|
}
|
|
182
216
|
}
|
|
217
|
+
|
|
218
|
+
// Touch target
|
|
219
|
+
// @include m.touch-target;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Checkbox group layout
|
|
223
|
+
.#{$component}-group {
|
|
224
|
+
display: flex;
|
|
225
|
+
flex-direction: column;
|
|
226
|
+
gap: 8px;
|
|
227
|
+
|
|
228
|
+
&--horizontal {
|
|
229
|
+
flex-direction: row;
|
|
230
|
+
gap: 16px;
|
|
231
|
+
flex-wrap: wrap;
|
|
232
|
+
}
|
|
183
233
|
}
|
|
@@ -1,59 +1,66 @@
|
|
|
1
|
-
// src/components/container/
|
|
2
|
-
@use '
|
|
3
|
-
@use '../../styles/abstract/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
1
|
+
// src/components/container/_container.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}-container';
|
|
9
|
+
|
|
10
|
+
.#{$component} {
|
|
11
|
+
@include m.shape('medium');
|
|
12
|
+
@include m.motion-transition(
|
|
13
|
+
background-color,
|
|
14
|
+
box-shadow
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
padding: 16px;
|
|
18
|
+
background-color: t.color('surface-container');
|
|
19
|
+
|
|
20
|
+
// Surface container variants
|
|
21
|
+
&--low {
|
|
22
|
+
background-color: t.color('surface-container-low');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&--lowest {
|
|
26
|
+
background-color: t.color('surface-container-lowest');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&--high {
|
|
30
|
+
background-color: t.color('surface-container-high');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&--highest {
|
|
34
|
+
background-color: t.color('surface-container-highest');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Elevation variants
|
|
38
|
+
&--elevation-0 {
|
|
39
|
+
@include m.elevation(0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&--elevation-1 {
|
|
43
|
+
@include m.elevation(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
&--elevation-2 {
|
|
47
|
+
@include m.elevation(2);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&--elevation-3 {
|
|
51
|
+
@include m.elevation(3);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&--elevation-4 {
|
|
55
|
+
@include m.elevation(4);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Accessibility
|
|
59
|
+
@include m.reduced-motion {
|
|
60
|
+
transition: none;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@include m.high-contrast {
|
|
64
|
+
border: 1px solid currentColor;
|
|
65
|
+
}
|
|
59
66
|
}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
// src/components/list/list-item.js
|
|
2
|
+
|
|
2
3
|
import { PREFIX } from '../../core/config'
|
|
3
4
|
import { pipe } from '../../core/compose'
|
|
4
5
|
import { createBase, withElement } from '../../core/compose/component'
|
|
5
6
|
import { withEvents, withDisabled } from '../../core/compose/features'
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Supported list item layouts
|
|
10
|
+
*/
|
|
11
|
+
export const LIST_ITEM_LAYOUTS = {
|
|
12
|
+
HORIZONTAL: 'horizontal', // Default horizontal layout
|
|
13
|
+
VERTICAL: 'vertical' // Stacked layout with vertical alignment
|
|
14
|
+
}
|
|
7
15
|
|
|
8
16
|
/**
|
|
9
17
|
* Creates a DOM element with optional class and content
|
|
@@ -48,7 +56,8 @@ const createListItem = (config = {}) => {
|
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
const createContent = (component) => {
|
|
51
|
-
const { element
|
|
59
|
+
const { element } = component
|
|
60
|
+
const { prefix } = baseConfig
|
|
52
61
|
const isVertical = config.layout === LIST_ITEM_LAYOUTS.VERTICAL
|
|
53
62
|
|
|
54
63
|
// Create content container
|
|
@@ -128,8 +137,7 @@ const createListItem = (config = {}) => {
|
|
|
128
137
|
tag: 'div',
|
|
129
138
|
role: config.role || 'listitem',
|
|
130
139
|
componentName: 'list-item',
|
|
131
|
-
|
|
132
|
-
className: `${baseConfig.prefix}-list-item ${config.layout === LIST_ITEM_LAYOUTS.VERTICAL ? 'vertical' : ''} ${config.class || ''}`.trim()
|
|
140
|
+
className: `${config.layout === LIST_ITEM_LAYOUTS.VERTICAL ? 'vertical' : ''} ${config.class || ''}`
|
|
133
141
|
}),
|
|
134
142
|
withDisabled(),
|
|
135
143
|
createContent
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// src/components/list/list.js
|
|
2
|
+
|
|
1
3
|
import { PREFIX } from '../../core/config'
|
|
2
4
|
import { pipe } from '../../core/compose'
|
|
3
5
|
import { createBase, withElement } from '../../core/compose/component'
|
|
@@ -54,29 +56,29 @@ const createList = (config = {}) => {
|
|
|
54
56
|
const focusedItem = document.activeElement
|
|
55
57
|
if (!focusedItem?.classList.contains(`${prefix}-list-item`)) return
|
|
56
58
|
|
|
57
|
-
const
|
|
58
|
-
const currentIndex =
|
|
59
|
+
const items = Array.from(element.querySelectorAll(`.${prefix}-list-item`))
|
|
60
|
+
const currentIndex = items.indexOf(focusedItem)
|
|
59
61
|
|
|
60
62
|
switch (event.key) {
|
|
61
63
|
case 'ArrowDown':
|
|
62
64
|
case 'ArrowRight':
|
|
63
65
|
event.preventDefault()
|
|
64
|
-
const nextItem =
|
|
66
|
+
const nextItem = items[currentIndex + 1]
|
|
65
67
|
if (nextItem) nextItem.focus()
|
|
66
68
|
break
|
|
67
69
|
case 'ArrowUp':
|
|
68
70
|
case 'ArrowLeft':
|
|
69
71
|
event.preventDefault()
|
|
70
|
-
const prevItem =
|
|
72
|
+
const prevItem = items[currentIndex - 1]
|
|
71
73
|
if (prevItem) prevItem.focus()
|
|
72
74
|
break
|
|
73
75
|
case 'Home':
|
|
74
76
|
event.preventDefault()
|
|
75
|
-
|
|
77
|
+
items[0]?.focus()
|
|
76
78
|
break
|
|
77
79
|
case 'End':
|
|
78
80
|
event.preventDefault()
|
|
79
|
-
|
|
81
|
+
items[items.length - 1]?.focus()
|
|
80
82
|
break
|
|
81
83
|
case ' ':
|
|
82
84
|
case 'Enter':
|
|
@@ -185,7 +187,7 @@ const createList = (config = {}) => {
|
|
|
185
187
|
|
|
186
188
|
element.addEventListener('keydown', handleKeyDown)
|
|
187
189
|
|
|
188
|
-
// Clean up
|
|
190
|
+
// Clean up
|
|
189
191
|
if (component.lifecycle) {
|
|
190
192
|
const originalDestroy = component.lifecycle.destroy
|
|
191
193
|
component.lifecycle.destroy = () => {
|
|
@@ -246,14 +248,12 @@ const createList = (config = {}) => {
|
|
|
246
248
|
}
|
|
247
249
|
}
|
|
248
250
|
|
|
249
|
-
|
|
251
|
+
return pipe(
|
|
250
252
|
createBase,
|
|
251
253
|
withEvents(),
|
|
252
254
|
withElement({
|
|
253
255
|
tag: 'div',
|
|
254
|
-
|
|
255
|
-
// and "listbox" for interactive, selectable types.
|
|
256
|
-
role: (!config.type || config.type === LIST_TYPES.DEFAULT) ? 'list' : 'listbox',
|
|
256
|
+
role: config.type === LIST_TYPES.DEFAULT ? 'list' : 'listbox',
|
|
257
257
|
'aria-multiselectable': config.type === LIST_TYPES.MULTI_SELECT ? 'true' : undefined,
|
|
258
258
|
componentName: LIST_CLASSES.ROOT,
|
|
259
259
|
className: config.class
|
|
@@ -262,14 +262,6 @@ const createList = (config = {}) => {
|
|
|
262
262
|
withLifecycle(),
|
|
263
263
|
createContent
|
|
264
264
|
)(baseConfig)
|
|
265
|
-
|
|
266
|
-
// Ensure that for default lists, the role is correctly "list"
|
|
267
|
-
if (!config.type || config.type === LIST_TYPES.DEFAULT) {
|
|
268
|
-
list.element.setAttribute('role', 'list')
|
|
269
|
-
}
|
|
270
|
-
// Expose the prefix on the returned component for testing purposes.
|
|
271
|
-
list.prefix = baseConfig.prefix
|
|
272
|
-
return list
|
|
273
265
|
}
|
|
274
266
|
|
|
275
267
|
export default createList
|