mtrl 0.5.4 → 0.5.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mtrl",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "A functional TypeScript/JavaScript component library with composable architecture based on Material Design 3",
5
5
  "author": "floor",
6
6
  "license": "MIT License",
@@ -1,245 +1,251 @@
1
1
  // src/styles/components/_menu.scss
2
- @use '../../styles/abstract/base' as base;
3
- @use '../../styles/abstract/variables' as v;
4
- @use '../../styles/abstract/mixins' as m;
5
- @use '../../styles/abstract/functions' as f;
6
- @use '../../styles/abstract/theme' as t;
2
+ @use "../../styles/abstract/base" as base;
3
+ @use "../../styles/abstract/variables" as v;
4
+ @use "../../styles/abstract/mixins" as m;
5
+ @use "../../styles/abstract/functions" as f;
6
+ @use "../../styles/abstract/theme" as t;
7
7
 
8
8
  $prefix: base.$prefix;
9
9
 
10
- $component: '#{$prefix}-menu';
10
+ $component: "#{$prefix}-menu";
11
11
 
12
12
  .#{$component} {
13
- // Base styles
14
- @include m.typography('body-medium');
15
- @include m.shape('extra-small');
16
-
17
- position: fixed;
18
- z-index: f.get-z-index('menu');
19
- min-width: 112px;
20
- max-width: 280px;
21
- padding: 8px 0; // Keep padding consistent
22
- background-color: t.color('surface-container');
23
- color: t.color('on-surface');
24
- @include m.elevation(2);
25
- overflow: hidden;
26
-
27
- // Initial state - hidden with proper transform origin
28
- display: block;
29
- opacity: 0;
30
- transform-origin: top center; // Default transform origin
31
- transform: scaleY(0);
32
- pointer-events: none;
33
-
34
- // Material Design 3 standard animation curve for menus
35
- transition:
36
- transform v.motion('duration-medium1') v.motion('easing-emphasized'),
37
- opacity v.motion('duration-medium1') v.motion('easing-emphasized');
38
-
39
- // Visible state
40
- &--visible {
41
- opacity: 1;
42
- transform: scaleY(1);
43
- pointer-events: auto;
44
- }
45
-
46
- // Position variations with appropriate transform origins
47
- &--position-top,
48
- &--position-top-start,
49
- &--position-top-end {
50
- transform-origin: bottom center;
51
- }
52
-
53
- // Submenu styling
54
- &--submenu {
55
- position: absolute;
56
- z-index: f.get-z-index('menu') + 1;
57
- }
58
-
59
- // List container
60
- &-list {
61
- margin: 0;
62
- padding: 0;
63
- list-style: none;
64
- overflow-y: auto;
65
- max-height: calc(100vh - 96px);
66
- @include m.scrollbar;
67
- width: 100%;
68
- }
69
-
70
- // Menu items
71
- &-item {
72
- @include m.typography('body-large');
73
- @include m.flex-row;
74
-
75
- position: relative;
76
- min-height: 48px;
77
- padding: 12px 16px;
78
- padding-right: 42px;
79
- cursor: pointer;
80
- user-select: none;
81
- color: t.color('on-surface');
82
- white-space: nowrap;
83
- text-overflow: ellipsis;
13
+ // Base styles
14
+ @include m.typography("body-medium");
15
+ @include m.shape("extra-small");
16
+
17
+ position: fixed;
18
+ z-index: f.get-z-index("menu");
19
+ min-width: 112px;
20
+ max-width: 280px;
21
+ padding: 8px 0; // Keep padding consistent
22
+ background-color: t.color("surface-container");
23
+ color: t.color("on-surface");
24
+ @include m.elevation(2);
84
25
  overflow: hidden;
85
- width: 100%;
86
- box-sizing: border-box;
87
-
88
- // State layer effects
89
- &:hover {
90
- @include m.state-layer(t.color('on-surface'), 'hover');
91
- }
92
-
93
- &:focus {
94
- @include m.state-layer(t.color('on-surface'), 'focus');
95
- outline: none;
26
+
27
+ // Initial state - hidden with proper transform origin
28
+ display: flex;
29
+ flex-direction: column;
30
+ opacity: 0;
31
+ transform-origin: top center; // Default transform origin
32
+ transform: scaleY(0);
33
+ pointer-events: none;
34
+
35
+ // Material Design 3 standard animation curve for menus
36
+ transition:
37
+ transform v.motion("duration-medium1") v.motion("easing-emphasized"),
38
+ opacity v.motion("duration-medium1") v.motion("easing-emphasized");
39
+
40
+ // Visible state
41
+ &--visible {
42
+ opacity: 1;
43
+ transform: scaleY(1);
44
+ pointer-events: auto;
96
45
  }
97
-
98
- &:active {
99
- @include m.state-layer(t.color('on-surface'), 'pressed');
46
+
47
+ // Position variations with appropriate transform origins
48
+ &--position-top,
49
+ &--position-top-start,
50
+ &--position-top-end {
51
+ transform-origin: bottom center;
100
52
  }
101
53
 
102
- // Submenu indicator
54
+ // Submenu styling
103
55
  &--submenu {
104
- padding-right: 48px;
105
-
106
- &::after {
107
- content: '';
108
56
  position: absolute;
109
- right: 12px;
110
- top: 50%;
111
- transform: translateY(-50%);
112
- width: 24px;
113
- height: 24px;
114
- mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 17l5-5-5-5v10z'/%3E%3C/svg%3E") center / contain no-repeat;
115
- -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 17l5-5-5-5v10z'/%3E%3C/svg%3E") center / contain no-repeat;
116
- background-color: currentColor;
117
- opacity: 0.87;
118
- }
119
-
120
- &[aria-expanded="true"] {
121
- @include m.state-layer(t.color('on-surface'), 'hover');
122
-
123
- &::after {
124
- opacity: 1;
125
- }
126
- }
57
+ z-index: f.get-z-index("menu") + 1;
127
58
  }
128
59
 
129
- // Disabled state
130
- &--disabled {
131
- pointer-events: none;
132
- color: t.alpha('on-surface', 0.38);
133
- }
134
-
135
- // Selected state for select component
136
- &--selected {
137
- color: t.color('primary');
138
-
139
- &::after {
140
- content: "";
141
- position: absolute;
142
- right: 12px;
143
- top: 50%;
144
- transform: translateY(-50%);
145
- width: 18px;
146
- height: 18px;
147
- mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpolyline points='20 6 9 17 4 12' stroke='white' stroke-width='2' fill='none'/%3E%3C/svg%3E") center / contain no-repeat;
148
- -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpolyline points='20 6 9 17 4 12' stroke='white' stroke-width='2' fill='none'/%3E%3C/svg%3E") center / contain no-repeat;
149
- background-color: currentColor;
150
- }
151
- }
152
-
153
- // Content containers inside menu items
154
- &-content {
155
- display: flex;
156
- align-items: center;
157
- width: 100%;
158
- overflow: hidden;
159
- }
160
-
161
- &-icon {
162
- margin-right: 12px;
163
- display: flex;
164
- align-items: center;
165
- justify-content: center;
166
- flex-shrink: 0;
167
-
168
- svg {
169
- width: 20px;
170
- height: 20px;
171
- }
172
- }
173
-
174
- &-text {
175
- flex: 1;
176
- white-space: nowrap;
177
- overflow: hidden;
178
- text-overflow: ellipsis;
60
+ // List container
61
+ &-list {
62
+ margin: 0;
63
+ padding: 0;
64
+ list-style: none;
65
+ overflow-y: auto;
66
+ flex: 1 1 auto;
67
+ min-height: 0; // Required for flex children with overflow
68
+ @include m.scrollbar;
69
+ width: 100%;
179
70
  }
180
-
181
- &-shortcut {
182
- margin-left: 12px;
183
- color: t.color('on-surface-variant');
184
- flex-shrink: 0;
185
- }
186
- }
187
-
188
- // Divider
189
- &-divider {
190
- height: 1px;
191
- margin: 8px 0;
192
- background-color: t.color('outline-variant');
193
- }
194
-
195
- // Accessibility
196
- @include m.focus-ring('.#{$component}-item:focus-visible');
197
-
198
- // Reduced motion preference support
199
- @include m.reduced-motion {
200
- transition: opacity 0.1s linear;
201
- transform: none !important;
202
-
203
- &--visible {
204
- transform: none !important;
71
+
72
+ // Menu items
73
+ &-item {
74
+ @include m.typography("body-large");
75
+ @include m.flex-row;
76
+
77
+ position: relative;
78
+ min-height: 48px;
79
+ padding: 12px 16px;
80
+ padding-right: 42px;
81
+ cursor: pointer;
82
+ user-select: none;
83
+ color: t.color("on-surface");
84
+ white-space: nowrap;
85
+ text-overflow: ellipsis;
86
+ overflow: hidden;
87
+ width: 100%;
88
+ box-sizing: border-box;
89
+
90
+ // State layer effects
91
+ &:hover {
92
+ @include m.state-layer(t.color("on-surface"), "hover");
93
+ }
94
+
95
+ &:focus {
96
+ @include m.state-layer(t.color("on-surface"), "focus");
97
+ outline: none;
98
+ }
99
+
100
+ &:active {
101
+ @include m.state-layer(t.color("on-surface"), "pressed");
102
+ }
103
+
104
+ // Submenu indicator
105
+ &--submenu {
106
+ padding-right: 48px;
107
+
108
+ &::after {
109
+ content: "";
110
+ position: absolute;
111
+ right: 12px;
112
+ top: 50%;
113
+ transform: translateY(-50%);
114
+ width: 24px;
115
+ height: 24px;
116
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 17l5-5-5-5v10z'/%3E%3C/svg%3E")
117
+ center / contain no-repeat;
118
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 17l5-5-5-5v10z'/%3E%3C/svg%3E")
119
+ center / contain no-repeat;
120
+ background-color: currentColor;
121
+ opacity: 0.87;
122
+ }
123
+
124
+ &[aria-expanded="true"] {
125
+ @include m.state-layer(t.color("on-surface"), "hover");
126
+
127
+ &::after {
128
+ opacity: 1;
129
+ }
130
+ }
131
+ }
132
+
133
+ // Disabled state
134
+ &--disabled {
135
+ pointer-events: none;
136
+ color: t.alpha("on-surface", 0.38);
137
+ }
138
+
139
+ // Selected state for select component
140
+ &--selected {
141
+ color: t.color("primary");
142
+
143
+ &::after {
144
+ content: "";
145
+ position: absolute;
146
+ right: 12px;
147
+ top: 50%;
148
+ transform: translateY(-50%);
149
+ width: 18px;
150
+ height: 18px;
151
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpolyline points='20 6 9 17 4 12' stroke='white' stroke-width='2' fill='none'/%3E%3C/svg%3E")
152
+ center / contain no-repeat;
153
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpolyline points='20 6 9 17 4 12' stroke='white' stroke-width='2' fill='none'/%3E%3C/svg%3E")
154
+ center / contain no-repeat;
155
+ background-color: currentColor;
156
+ }
157
+ }
158
+
159
+ // Content containers inside menu items
160
+ &-content {
161
+ display: flex;
162
+ align-items: center;
163
+ width: 100%;
164
+ overflow: hidden;
165
+ }
166
+
167
+ &-icon {
168
+ margin-right: 12px;
169
+ display: flex;
170
+ align-items: center;
171
+ justify-content: center;
172
+ flex-shrink: 0;
173
+
174
+ svg {
175
+ width: 20px;
176
+ height: 20px;
177
+ }
178
+ }
179
+
180
+ &-text {
181
+ flex: 1;
182
+ white-space: nowrap;
183
+ overflow: hidden;
184
+ text-overflow: ellipsis;
185
+ }
186
+
187
+ &-shortcut {
188
+ margin-left: 12px;
189
+ color: t.color("on-surface-variant");
190
+ flex-shrink: 0;
191
+ }
205
192
  }
206
- }
207
-
208
- // High contrast mode
209
- @include m.high-contrast {
210
- border: 1px solid CurrentColor;
211
-
212
- .#{$component}-divider {
213
- background-color: CurrentColor;
193
+
194
+ // Divider
195
+ &-divider {
196
+ height: 1px;
197
+ margin: 8px 0;
198
+ background-color: t.color("outline-variant");
214
199
  }
215
-
216
- .#{$component}-item--disabled {
217
- opacity: 1;
218
- color: GrayText;
200
+
201
+ // Accessibility
202
+ @include m.focus-ring(".#{$component}-item:focus-visible");
203
+
204
+ // Reduced motion preference support
205
+ @include m.reduced-motion {
206
+ transition: opacity 0.1s linear;
207
+ transform: none !important;
208
+
209
+ &--visible {
210
+ transform: none !important;
211
+ }
219
212
  }
220
- }
221
213
 
222
- // RTL Support
223
- @include m.rtl {
224
- transform-origin: top right;
225
-
226
- &--position-top,
227
- &--position-top-start,
228
- &--position-top-end {
229
- transform-origin: bottom right;
214
+ // High contrast mode
215
+ @include m.high-contrast {
216
+ border: 1px solid CurrentColor;
217
+
218
+ .#{$component}-divider {
219
+ background-color: CurrentColor;
220
+ }
221
+
222
+ .#{$component}-item--disabled {
223
+ opacity: 1;
224
+ color: GrayText;
225
+ }
230
226
  }
231
-
232
- .#{$component}-item {
233
- &--submenu {
234
- padding-right: 16px;
235
- padding-left: 48px;
236
-
237
- &::after {
238
- right: auto;
239
- left: 16px;
240
- transform: translateY(-50%) rotate(180deg);
227
+
228
+ // RTL Support
229
+ @include m.rtl {
230
+ transform-origin: top right;
231
+
232
+ &--position-top,
233
+ &--position-top-start,
234
+ &--position-top-end {
235
+ transform-origin: bottom right;
236
+ }
237
+
238
+ .#{$component}-item {
239
+ &--submenu {
240
+ padding-right: 16px;
241
+ padding-left: 48px;
242
+
243
+ &::after {
244
+ right: auto;
245
+ left: 16px;
246
+ transform: translateY(-50%) rotate(180deg);
247
+ }
248
+ }
241
249
  }
242
- }
243
250
  }
244
- }
245
- }
251
+ }