material-inspired-component-library 1.2.2 → 1.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.
Files changed (48) hide show
  1. package/README.md +10 -0
  2. package/components/button/README.md +1 -1
  3. package/components/button/index.scss +52 -79
  4. package/components/card/index.scss +28 -29
  5. package/components/checkbox/index.scss +0 -5
  6. package/components/dialog/index.scss +11 -7
  7. package/components/iconbutton/README.md +1 -1
  8. package/components/iconbutton/index.scss +46 -80
  9. package/components/list/index.scss +39 -30
  10. package/components/list/index.ts +10 -9
  11. package/components/menu/README.md +67 -4
  12. package/components/menu/index.scss +29 -29
  13. package/components/menu/index.ts +47 -16
  14. package/components/navigationrail/README.md +99 -0
  15. package/components/navigationrail/index.scss +157 -0
  16. package/components/radio/index.scss +21 -11
  17. package/components/select/index.scss +5 -11
  18. package/components/textfield/index.scss +8 -2
  19. package/dist/bottomsheet.css +1 -1
  20. package/dist/button.css +1 -1
  21. package/dist/card.css +1 -1
  22. package/dist/checkbox.css +1 -1
  23. package/dist/components/menu/index.d.ts +0 -11
  24. package/dist/dialog.css +1 -1
  25. package/dist/iconbutton.css +1 -1
  26. package/dist/list.css +1 -1
  27. package/dist/menu.css +1 -1
  28. package/dist/micl.css +1 -1
  29. package/dist/micl.js +1 -1
  30. package/dist/navigationrail.css +1 -0
  31. package/dist/navigationrail.js +1 -0
  32. package/dist/radio.css +1 -1
  33. package/dist/select.css +1 -1
  34. package/dist/slider.css +1 -1
  35. package/dist/switch.css +1 -1
  36. package/dist/textfield.css +1 -1
  37. package/docs/docs.js +2 -2
  38. package/docs/index.html +3 -1
  39. package/docs/menu.html +183 -3
  40. package/docs/micl.css +1 -1
  41. package/docs/micl.js +1 -1
  42. package/docs/navigationrail.html +75 -0
  43. package/micl.ts +10 -8
  44. package/package.json +7 -7
  45. package/styles/statelayer.scss +14 -0
  46. package/styles.scss +1 -1
  47. package/webpack.config.js +37 -0
  48. package/styles/ripple.scss +0 -50
@@ -21,7 +21,6 @@
21
21
 
22
22
  @use '../../styles/elevation';
23
23
  @use '../../styles/motion';
24
- @use '../../styles/ripple';
25
24
  @use '../../styles/shapes';
26
25
  @use '../../styles/statelayer';
27
26
 
@@ -48,17 +47,25 @@ button.micl-iconbutton-outlined-xl {
48
47
  --md-sys-iconbutton-motion-effects: #{motion.$md-sys-motion-expressive-fast-spatial};
49
48
  --md-sys-iconbutton-motion-duration: #{motion.$md-sys-motion-expressive-fast-spatial-duration};
50
49
  --md-sys-iconbutton-motion-duration-reverse: #{motion.$md-sys-motion-expressive-fast-spatial-duration};
50
+ --miclripple: 1;
51
51
 
52
52
  padding: 0;
53
53
  border: none;
54
54
  border-radius: var(--md-sys-shape-corner-full);
55
55
  background-color: transparent;
56
+ background-image:
57
+ radial-gradient(circle at var(--x, center) var(--y, center), transparent 0%, rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)) 10%, transparent 10%),
58
+ linear-gradient(rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)));
59
+ background-repeat: no-repeat;
60
+ background-size: 10000%, 100%;
56
61
  color: var(--md-sys-color-on-surface-variant);
57
62
  cursor: pointer;
58
63
  font-variation-settings: 'FILL' 0;
59
64
  transition:
60
65
  border-radius var(--md-sys-iconbutton-motion-duration) var(--md-sys-iconbutton-motion-effects),
61
- font-variation-settings var(--md-sys-iconbutton-motion-duration) linear;
66
+ font-variation-settings var(--md-sys-iconbutton-motion-duration) linear,
67
+ background-size 3000ms,
68
+ --statelayer-opacity var(--md-sys-iconbutton-motion-duration) linear;
62
69
 
63
70
  &:disabled {
64
71
  background-color: rgb(from var(--md-sys-color-on-surface) r g b / 10%);
@@ -66,9 +73,15 @@ button.micl-iconbutton-outlined-xl {
66
73
  box-shadow: var(--md-sys-elevation-level0);
67
74
  cursor: default;
68
75
  }
69
- &:not(:disabled):focus-visible {
70
- outline: var(--md-sys-state-focus-indicator-thickness) solid var(--md-sys-color-secondary);
71
- outline-offset: 3px;
76
+ &:not(:disabled) {
77
+ &:focus-visible {
78
+ outline: var(--md-sys-state-focus-indicator-thickness) solid var(--md-sys-color-secondary);
79
+ outline-offset: 3px;
80
+ }
81
+ &:active {
82
+ background-size: 0%, 100%;
83
+ transition: background-size 0ms;
84
+ }
72
85
  }
73
86
  &:hover:not(:disabled),
74
87
  &.micl-button--toggle.micl-button--selected {
@@ -92,9 +105,6 @@ button.micl-iconbutton-outlined-xs {
92
105
  border-radius: var(--md-sys-shape-corner-large);
93
106
  }
94
107
  &:not(:disabled) {
95
- --miclripple: 1;
96
- @include ripple.effect;
97
-
98
108
  &:active {
99
109
  // border-radius: var(--md-sys-shape-corner-small);
100
110
  border-radius: var(--md-sys-shape-corner-medium);
@@ -146,9 +156,6 @@ button.micl-iconbutton-outlined-s {
146
156
  border-radius: var(--md-sys-shape-corner-large);
147
157
  }
148
158
  &:not(:disabled) {
149
- --miclripple: 1;
150
- @include ripple.effect;
151
-
152
159
  &:active {
153
160
  // border-radius: var(--md-sys-shape-corner-small);
154
161
  border-radius: var(--md-sys-shape-corner-medium);
@@ -197,9 +204,6 @@ button.micl-iconbutton-outlined-m {
197
204
  border-radius: var(--md-sys-shape-corner-large);
198
205
  }
199
206
  &:not(:disabled) {
200
- --miclripple: 1;
201
- @include ripple.effect;
202
-
203
207
  &:active {
204
208
  // border-radius: var(--md-sys-shape-corner-small);
205
209
  border-radius: var(--md-sys-shape-corner-medium);
@@ -237,9 +241,6 @@ button.micl-iconbutton-outlined-l {
237
241
  border-radius: var(--md-sys-shape-corner-extra-large);
238
242
  }
239
243
  &:not(:disabled) {
240
- --miclripple: 1;
241
- @include ripple.effect;
242
-
243
244
  &:active {
244
245
  border-radius: var(--md-sys-shape-corner-large);
245
246
  }
@@ -276,9 +277,6 @@ button.micl-iconbutton-outlined-xl {
276
277
  border-radius: var(--md-sys-shape-corner-extra-large);
277
278
  }
278
279
  &:not(:disabled) {
279
- --miclripple: 1;
280
- @include ripple.effect;
281
-
282
280
  &:active {
283
281
  border-radius: var(--md-sys-shape-corner-large);
284
282
  }
@@ -307,30 +305,22 @@ button.micl-iconbutton-standard-s,
307
305
  button.micl-iconbutton-standard-m,
308
306
  button.micl-iconbutton-standard-l,
309
307
  button.micl-iconbutton-standard-xl {
308
+ --statelayer-color: var(--md-sys-color-on-surface-variant);
309
+
310
310
  &:not(:disabled) {
311
311
  &.micl-button--toggle.micl-button--selected {
312
+ --statelayer-color: var(--md-sys-color-primary);
313
+
312
314
  color: var(--md-sys-color-primary);
313
315
  }
314
316
  &:hover {
315
- background-color: rgb(from var(--md-sys-color-on-surface-variant) r g b / var(--md-sys-state-hover-state-layer-opacity));
316
-
317
- &.micl-button--toggle.micl-button--selected {
318
- background-color: rgb(from var(--md-sys-color-primary) r g b / var(--md-sys-state-hover-state-layer-opacity));
319
- }
317
+ --statelayer-opacity: var(--md-sys-state-hover-state-layer-opacity);
320
318
  }
321
319
  &:focus-visible {
322
- background-color: rgb(from var(--md-sys-color-on-surface-variant) r g b / var(--md-sys-state-focus-state-layer-opacity));
323
-
324
- &.micl-button--toggle.micl-button--selected {
325
- background-color: rgb(from var(--md-sys-color-primary) r g b / var(--md-sys-state-focus-state-layer-opacity));
326
- }
320
+ --statelayer-opacity: var(--md-sys-state-focus-state-layer-opacity);
327
321
  }
328
322
  &:active {
329
- background-color: rgb(from var(--md-sys-color-on-surface-variant) r g b / var(--md-sys-state-pressed-state-layer-opacity));
330
-
331
- &.micl-button--toggle.micl-button--selected {
332
- background-color: rgb(from var(--md-sys-color-primary) r g b / var(--md-sys-state-pressed-state-layer-opacity));
333
- }
323
+ --statelayer-opacity: var(--md-sys-state-pressed-state-layer-opacity);
334
324
  }
335
325
  }
336
326
  }
@@ -341,34 +331,26 @@ button.micl-iconbutton-filled-s,
341
331
  button.micl-iconbutton-filled-m,
342
332
  button.micl-iconbutton-filled-l,
343
333
  button.micl-iconbutton-filled-xl {
334
+ --statelayer-color: var(--md-sys-color-on-primary);
335
+
344
336
  background-color: var(--md-sys-color-primary);
345
337
  color: var(--md-sys-color-on-primary);
346
338
 
347
339
  &:not(:disabled) {
348
340
  &.micl-button--toggle:not(.micl-button--selected) {
341
+ --statelayer-color: var(--md-sys-color-on-surface-variant);
342
+
349
343
  background-color: var(--md-sys-color-surface-container);
350
344
  color: var(--md-sys-color-on-surface-variant);
351
345
  }
352
346
  &:hover {
353
- background-color: color-mix(in srgb, var(--md-sys-color-primary), var(--md-sys-color-on-primary) var(--md-sys-state-hover-state-layer-opacity));
354
-
355
- &.micl-button--toggle:not(.micl-button--selected) {
356
- background-color: color-mix(in srgb, var(--md-sys-color-surface-container), var(--md-sys-color-on-surface-variant) var(--md-sys-state-hover-state-layer-opacity));
357
- }
347
+ --statelayer-opacity: var(--md-sys-state-hover-state-layer-opacity);
358
348
  }
359
349
  &:focus-visible {
360
- background-color: color-mix(in srgb, var(--md-sys-color-primary), var(--md-sys-color-on-primary) var(--md-sys-state-focus-state-layer-opacity));
361
-
362
- &.micl-button--toggle:not(.micl-button--selected) {
363
- background-color: color-mix(in srgb, var(--md-sys-color-surface-container), var(--md-sys-color-on-surface-variant) var(--md-sys-state-focus-state-layer-opacity));
364
- }
350
+ --statelayer-opacity: var(--md-sys-state-focus-state-layer-opacity);
365
351
  }
366
352
  &:active {
367
- background-color: color-mix(in srgb, var(--md-sys-color-primary), var(--md-sys-color-on-primary) var(--md-sys-state-pressed-state-layer-opacity));
368
-
369
- &.micl-button--toggle:not(.micl-button--selected) {
370
- background-color: color-mix(in srgb, var(--md-sys-color-surface-container), var(--md-sys-color-on-surface-variant) var(--md-sys-state-pressed-state-layer-opacity));
371
- }
353
+ --statelayer-opacity: var(--md-sys-state-pressed-state-layer-opacity);
372
354
  }
373
355
  }
374
356
  }
@@ -378,34 +360,26 @@ button.micl-iconbutton-tonal-s,
378
360
  button.micl-iconbutton-tonal-m,
379
361
  button.micl-iconbutton-tonal-l,
380
362
  button.micl-iconbutton-tonal-xl {
363
+ --statelayer-color: var(--md-sys-color-on-secondary-container);
364
+
381
365
  background-color: var(--md-sys-color-secondary-container);
382
366
  color: var(--md-sys-color-on-secondary-container);
383
367
 
384
368
  &:not(:disabled) {
385
369
  &.micl-button--toggle.micl-button--selected {
370
+ --statelayer-color: var(--md-sys-color-on-secondary);
371
+
386
372
  background-color: var(--md-sys-color-secondary);
387
373
  color: var(--md-sys-color-on-secondary);
388
374
  }
389
375
  &:hover {
390
- background-color: color-mix(in srgb, var(--md-sys-color-secondary-container), var(--md-sys-color-on-secondary-container) var(--md-sys-state-hover-state-layer-opacity));
391
-
392
- &.micl-button--toggle.micl-button--selected {
393
- background-color: color-mix(in srgb, var(--md-sys-color-secondary), var(--md-sys-color-on-secondary) var(--md-sys-state-hover-state-layer-opacity));
394
- }
376
+ --statelayer-opacity: var(--md-sys-state-hover-state-layer-opacity);
395
377
  }
396
378
  &:focus-visible {
397
- background-color: color-mix(in srgb, var(--md-sys-color-secondary-container), var(--md-sys-color-on-secondary-container) var(--md-sys-state-focus-state-layer-opacity));
398
-
399
- &.micl-button--toggle.micl-button--selected {
400
- background-color: color-mix(in srgb, var(--md-sys-color-secondary), var(--md-sys-color-on-secondary) var(--md-sys-state-focus-state-layer-opacity));
401
- }
379
+ --statelayer-opacity: var(--md-sys-state-focus-state-layer-opacity);
402
380
  }
403
381
  &:active {
404
- background-color: color-mix(in srgb, var(--md-sys-color-secondary-container), var(--md-sys-color-on-secondary-container) var(--md-sys-state-pressed-state-layer-opacity));
405
-
406
- &.micl-button--toggle.micl-button--selected {
407
- background-color: color-mix(in srgb, var(--md-sys-color-secondary), var(--md-sys-color-on-secondary) var(--md-sys-state-pressed-state-layer-opacity));
408
- }
382
+ --statelayer-opacity: var(--md-sys-state-pressed-state-layer-opacity);
409
383
  }
410
384
  }
411
385
  }
@@ -415,6 +389,8 @@ button.micl-iconbutton-outlined-s,
415
389
  button.micl-iconbutton-outlined-m,
416
390
  button.micl-iconbutton-outlined-l,
417
391
  button.micl-iconbutton-outlined-xl {
392
+ --statelayer-color: var(--md-sys-color-on-surface-variant);
393
+
418
394
  background-color: transparent;
419
395
  color: var(--md-sys-color-on-surface-variant);
420
396
 
@@ -440,29 +416,19 @@ button.micl-iconbutton-outlined-xl {
440
416
  }
441
417
  &:not(:disabled) {
442
418
  &.micl-button--toggle.micl-button--selected {
419
+ --statelayer-color: var(--md-sys-color-inverse-on-surface);
420
+
443
421
  background-color: var(--md-sys-color-inverse-surface);
444
422
  color: var(--md-sys-color-inverse-on-surface);
445
423
  }
446
424
  &:hover {
447
- background-color: rgb(from var(--md-sys-color-on-surface-variant) r g b / var(--md-sys-state-hover-state-layer-opacity));
448
-
449
- &.micl-button--toggle.micl-button--selected {
450
- background-color: color-mix(in srgb, var(--md-sys-color-inverse-surface), var(--md-sys-color-inverse-on-surface) var(--md-sys-state-hover-state-layer-opacity));
451
- }
425
+ --statelayer-opacity: var(--md-sys-state-hover-state-layer-opacity);
452
426
  }
453
427
  &:focus-visible {
454
- background-color: rgb(from var(--md-sys-color-on-surface-variant) r g b / var(--md-sys-state-focus-state-layer-opacity));
455
-
456
- &.micl-button--toggle.micl-button--selected {
457
- background-color: color-mix(in srgb, var(--md-sys-color-inverse-surface), var(--md-sys-color-inverse-on-surface) var(--md-sys-state-focus-state-layer-opacity));
458
- }
428
+ --statelayer-opacity: var(--md-sys-state-focus-state-layer-opacity);
459
429
  }
460
430
  &:active {
461
- background-color: rgb(from var(--md-sys-color-on-surface-variant) r g b / var(--md-sys-state-pressed-state-layer-opacity));
462
-
463
- &.micl-button--toggle.micl-button--selected {
464
- background-color: color-mix(in srgb, var(--md-sys-color-inverse-surface), var(--md-sys-color-inverse-on-surface) var(--md-sys-state-pressed-state-layer-opacity));
465
- }
431
+ --statelayer-opacity: var(--md-sys-state-pressed-state-layer-opacity);
466
432
  }
467
433
  }
468
434
  }
@@ -20,12 +20,12 @@
20
20
  // SOFTWARE.
21
21
 
22
22
  @use '../../styles/motion';
23
- @use '../../styles/ripple';
24
23
  @use '../../styles/shapes';
25
24
  @use '../../styles/statelayer';
26
25
  @use '../../styles/typography';
27
26
 
28
27
  :root {
28
+ --md-sys-list-padding: 8px;
29
29
  --md-sys-list-item-one-height: 56px;
30
30
  --md-sys-list-item-two-height: 72px;
31
31
  --md-sys-list-item-three-height: 88px;
@@ -43,7 +43,7 @@
43
43
  --md-sys-accordion-motion-duration: #{motion.$md-sys-motion-expressive-default-spatial-duration};
44
44
 
45
45
  margin: 0;
46
- padding: 8px 0;
46
+ padding: var(--md-sys-list-padding) 0;
47
47
  interpolate-size: allow-keywords;
48
48
  list-style-type: none;
49
49
 
@@ -71,9 +71,6 @@
71
71
  pointer-events: none;
72
72
  }
73
73
  &:not(.micl-list-item--disabled) {
74
- @include ripple.effect;
75
- --miclripple: 1;
76
-
77
74
  cursor: pointer;
78
75
  }
79
76
  }
@@ -98,6 +95,7 @@
98
95
  .micl-list-item-one,
99
96
  .micl-list-item-two,
100
97
  .micl-list-item-three {
98
+ --statelayer-color: var(--md-sys-color-on-surface);
101
99
  --md-sys-list-item-thumbnail-aspect-ratio: 1.778;
102
100
 
103
101
  box-sizing: border-box;
@@ -105,24 +103,39 @@
105
103
  align-items: center;
106
104
  column-gap: var(--md-sys-list-item-space);
107
105
  padding-inline: var(--md-sys-list-item-space);
106
+ border: none;
108
107
  border-radius: var(--md-sys-shape-corner-none);
109
108
  background-color: var(--md-sys-list-item-container-color);
109
+ background-image:
110
+ radial-gradient(circle at var(--x, center) var(--y, center), transparent 0%, rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)) 10%, transparent 10%),
111
+ linear-gradient(rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)));
112
+ background-repeat: no-repeat;
113
+ background-size: 10000%, 100%;
110
114
  list-style: none;
111
- transition: background-color var(--md-sys-list-motion-duration) linear;
115
+ transition:
116
+ background-size 3000ms,
117
+ --statelayer-opacity var(--md-sys-list-motion-duration) linear;
112
118
 
119
+ &:not(:has(> button)) {
120
+ --miclripple: 1;
121
+ }
113
122
  &> a,
123
+ &> button,
114
124
  &> label {
125
+ box-sizing: border-box;
115
126
  display: inherit;
116
127
  align-items: inherit;
117
128
  column-gap: inherit;
118
- border-radius: inherit;
119
- background-color: inherit;
129
+ min-height: inherit;
120
130
  inline-size: 100%;
121
131
  padding-inline: var(--md-sys-list-item-space);
132
+ border: none;
133
+ border-radius: inherit;
134
+ background-color: transparent;
122
135
  text-decoration: none;
123
136
  cursor: pointer;
124
137
  }
125
- &:has(> a,> label) {
138
+ &:has(> a,> button,> label) {
126
139
  padding-inline: 0;
127
140
  }
128
141
  &:disabled,
@@ -139,14 +152,14 @@
139
152
  .micl-list-item__thumbnail {
140
153
  opacity: 38%;
141
154
  }
142
- a, label {
155
+ a, button, label {
143
156
  pointer-events: none;
144
157
  cursor: auto;
145
158
  }
146
159
  }
147
160
  &:not(:disabled):not(.micl-list-item--disabled) {
148
161
  &:hover {
149
- background-color: color-mix(in srgb, var(--md-sys-list-item-container-color), var(--md-sys-color-on-surface) var(--md-sys-state-hover-state-layer-opacity));
162
+ --statelayer-opacity: var(--md-sys-state-hover-state-layer-opacity);
150
163
 
151
164
  &:has(input[type=checkbox]) {
152
165
  cursor: pointer;
@@ -156,26 +169,25 @@
156
169
  }
157
170
  }
158
171
  &:focus-visible {
172
+ --statelayer-opacity: var(--md-sys-state-focus-state-layer-opacity);
173
+
159
174
  outline: var(--md-sys-state-focus-indicator-thickness) solid var(--md-sys-color-secondary);
160
- outline-offset: calc(-1 * var(--md-sys-state-focus-indicator-thickness));
161
- background-color: color-mix(in srgb, var(--md-sys-list-item-container-color), var(--md-sys-color-on-surface) var(--md-sys-state-focus-state-layer-opacity));
175
+ outline-offset: var(--md-sys-state-focus-indicator-inner-offset);
162
176
 
163
177
  .micl-list-item__icon {
164
178
  font-variation-settings: 'FILL' 1;
165
179
  }
166
180
  }
167
181
  &:active {
168
- background-color: color-mix(in srgb, var(--md-sys-list-item-container-color), var(--md-sys-color-on-surface) var(--md-sys-state-pressed-state-layer-opacity));
182
+ --statelayer-opacity: var(--md-sys-state-pressed-state-layer-opacity);
183
+
184
+ background-size: 0%, 100%;
185
+ transition: background-size 0ms;
169
186
 
170
187
  .micl-list-item__icon {
171
188
  font-variation-settings: 'FILL' 1;
172
189
  }
173
190
  }
174
- &:has(input[type=checkbox]) {
175
- @include ripple.effect;
176
- --miclripple: 1;
177
- --md-sys-ripple-background-color: var(--md-sys-color-primary);
178
- }
179
191
  &:has(input[type=checkbox]:checked) {
180
192
  background-color: var(--md-sys-color-secondary-container);
181
193
 
@@ -187,18 +199,11 @@
187
199
  .micl-list-item__trailing-text {
188
200
  color: var(--md-sys-color-on-surface);
189
201
  }
190
- &:focus-visible {
191
- background-color: color-mix(in srgb, var(--md-sys-color-secondary-container), var(--md-sys-color-on-surface) var(--md-sys-state-focus-state-layer-opacity));
192
- }
193
- &:active {
194
- background-color: color-mix(in srgb, var(--md-sys-color-secondary-container), var(--md-sys-color-on-surface) var(--md-sys-state-pressed-state-layer-opacity));
195
- }
196
202
  }
197
203
  input[type=checkbox]:not(:disabled):hover,
198
204
  input[type=checkbox]:not(:disabled):active {
199
205
  --checkbox-state-layer-color: initial;
200
206
  --checkbox-outline-color: initial;
201
- --md-sys-ripple-background-color: transparent;
202
207
  }
203
208
  }
204
209
  }
@@ -206,7 +211,7 @@
206
211
  .micl-list-item-one {
207
212
  min-height: var(--md-sys-list-item-one-height);
208
213
 
209
- &:not(:has(> a,> label)) {
214
+ &:not(:has(> a,> button,> label)) {
210
215
  padding-block-start: var(--md-sys-list-item-one-padding);
211
216
  padding-block-end: var(--md-sys-list-item-one-padding);
212
217
 
@@ -217,6 +222,7 @@
217
222
  }
218
223
  }
219
224
  &> a,
225
+ &> button,
220
226
  &> label {
221
227
  padding-block-start: var(--md-sys-list-item-one-padding);
222
228
  padding-block-end: var(--md-sys-list-item-one-padding);
@@ -231,7 +237,7 @@
231
237
  .micl-list-item-two {
232
238
  min-height: var(--md-sys-list-item-two-height);
233
239
 
234
- &:not(:has(> a, > label)) {
240
+ &:not(:has(> a,> button,> label)) {
235
241
  padding-block-start: var(--md-sys-list-item-two-padding);
236
242
  padding-block-end: var(--md-sys-list-item-two-padding);
237
243
 
@@ -242,6 +248,7 @@
242
248
  }
243
249
  }
244
250
  &> a,
251
+ &> button,
245
252
  &> label {
246
253
  padding-block-start: var(--md-sys-list-item-two-padding);
247
254
  padding-block-end: var(--md-sys-list-item-two-padding);
@@ -261,7 +268,7 @@
261
268
  .micl-list-item-three {
262
269
  min-height: var(--md-sys-list-item-three-height);
263
270
 
264
- &:not(:has(> a, > label)) {
271
+ &:not(:has(> a,> button,> label)) {
265
272
  padding-block-start: var(--md-sys-list-item-three-padding);
266
273
  padding-block-end: var(--md-sys-list-item-three-padding);
267
274
 
@@ -272,6 +279,7 @@
272
279
  }
273
280
  }
274
281
  &> a,
282
+ &> button,
275
283
  &> label {
276
284
  padding-block-start: var(--md-sys-list-item-three-padding);
277
285
  padding-block-end: var(--md-sys-list-item-three-padding);
@@ -300,9 +308,10 @@
300
308
  }
301
309
 
302
310
  .micl-list-item__icon {
303
- color: var(--md-sys-color-on-surface-variant);
311
+ min-width: 24px;
304
312
  font-size: 24px;
305
313
  font-variation-settings: 'FILL' 0;
314
+ color: var(--md-sys-color-on-surface-variant);
306
315
  transition: font-variation-settings var(--md-sys-list-motion-duration) linear;
307
316
  }
308
317
  .micl-list-item__avatar {
@@ -58,14 +58,9 @@ export default (() =>
58
58
  return;
59
59
  }
60
60
 
61
- let currentIndex = items.findIndex(item => isSelected(item));
62
- if (currentIndex === -1) {
63
- currentIndex = items.findIndex(item => item.tabIndex === 0);
64
- }
65
- if (currentIndex === -1) {
66
- currentIndex = 0;
67
- }
68
- let nextIndex = currentIndex;
61
+ let selectedIndex = items.findIndex(item => isSelected(item)),
62
+ currentIndex = items.findIndex(item => item.tabIndex === 0),
63
+ nextIndex = currentIndex;
69
64
 
70
65
  switch (event.key) {
71
66
  case 'ArrowDown':
@@ -77,7 +72,6 @@ export default (() =>
77
72
  event.preventDefault();
78
73
  break;
79
74
  case 'Tab':
80
- let selectedIndex = items.findIndex(item => isSelected(item));
81
75
  if (selectedIndex === -1) {
82
76
  if (currentIndex !== 0) {
83
77
  items[currentIndex].tabIndex = -1;
@@ -102,6 +96,13 @@ export default (() =>
102
96
  items[currentIndex].tabIndex = -1;
103
97
  items[nextIndex].tabIndex = 0;
104
98
  items[nextIndex].focus();
99
+
100
+ const btn = items[nextIndex].querySelector(':scope > button');
101
+ btn?.dispatchEvent(new MouseEvent('mouseenter', {
102
+ bubbles : true,
103
+ cancelable: true,
104
+ view : window
105
+ }));
105
106
  }
106
107
  }
107
108
  };
@@ -4,7 +4,7 @@ This component implements the [Material Design 3 Expressive Menu](https://m3.mat
4
4
  ## Basic Usage
5
5
 
6
6
  ### HTML
7
- The Menu component is an extension of the [List component](../list/README.md). It consists of a `<nav>` element with the `micl-menu` class, which acts as the container for a `<ul>` with the `micl-list` class. The menu can be opened and closed using a control element with the `popovertarget` attribute.
7
+ The Menu component is an extension of the [List component](../list/README.md). It consists of a `<nav>` element with the `micl-menu` class, which acts as the container for a `<ul>` with the `micl-list` class. The menu can be opened and closed using a control element with the `popovertarget` attribute, where the value of the attribute matches the `id` of the menu's `<nav>` element.
8
8
 
9
9
  ```HTML
10
10
  <nav id="mymenu" class="micl-menu" popover>
@@ -17,7 +17,7 @@ The Menu component is an extension of the [List component](../list/README.md). I
17
17
  </ul>
18
18
  </nav>
19
19
 
20
- <button type="button" popovertarget="mymenu">Open Basic Menu</button>
20
+ <button type="button" popovertarget="mymenu">Open Menu</button>
21
21
  ```
22
22
 
23
23
  ### CSS
@@ -68,17 +68,18 @@ Since the Menu component is based on the **List component**, all of its list ite
68
68
  ```
69
69
 
70
70
  **Example: A menu with a link**
71
+
71
72
  To make a menu item function as a link, wrap its content in an `<a>` tag and set the `tabindex` to `-1`. This ensures the link is clickable but does not interfere with menu navigation.
72
73
 
73
74
  ```HTML
74
75
  <nav id="mymenu" class="micl-menu" popover>
75
76
  <ul class="micl-list">
76
- <li class="micl-list-item-two micl-list-item__divider">
77
+ <li class="micl-list-item-two" tabindex="0">
77
78
  <a href="https://www.nytimes.com" tabindex="-1">
78
79
  <span class="micl-list-item__icon material-symbols-outlined" aria-hidden="true">newspaper</span>
79
80
  <span class="micl-list-item__text">
80
81
  <span class="micl-list-item__headline">The New York Times</span>
81
- <span class="micl-list-item__supporting-text">Clicking this item opens the front page of The New York Times</span>
82
+ <span class="micl-list-item__supporting-text">Open the front page of The New York Times</span>
82
83
  </span>
83
84
  </a>
84
85
  </li>
@@ -86,9 +87,71 @@ To make a menu item function as a link, wrap its content in an `<a>` tag and set
86
87
  </nav>
87
88
  ```
88
89
 
90
+ **Example: A menu with a submenu**
91
+
92
+ A menu item may trigger opening a submenu when invoked by a button. Wrap the menu item content in a `<button>` tag, set its `tabindex` to `-1` and add the `popovertarget` attribute that points to the submenu. The button acts then as the control element for the submenu.
93
+
94
+ ```HTML
95
+ <nav id="mymenu" class="micl-menu" popover>
96
+ <ul class="micl-list">
97
+ <li class="micl-list-item-one" tabindex="0">
98
+ <button popovertarget="mysubmenu" tabindex="-1">
99
+ <span class="micl-list-item__text">
100
+ <span class="micl-list-item__headline">Item 1</span>
101
+ </span>
102
+ <span class="micl-list-item__icon material-symbols-outlined">arrow_right</span>
103
+ </button>
104
+ <nav id="mysubmenu" class="micl-menu" popover>
105
+ <ul class="micl-list">
106
+ <li class="micl-list-item-one" tabindex="0">
107
+ <span class="micl-list-item__text">
108
+ <span class="micl-list-item__headline">Item 1-1</span>
109
+ </span>
110
+ </li>
111
+ <li class="micl-list-item-one" tabindex="0">
112
+ <span class="micl-list-item__text">
113
+ <span class="micl-list-item__headline">Item 1-2</span>
114
+ </span>
115
+ </li>
116
+ </ul>
117
+ </nav>
118
+ </li>
119
+ <li class="micl-list-item-one" tabindex="0">
120
+ <span class="micl-list-item__text">
121
+ <span class="micl-list-item__headline">Item 2</span>
122
+ </span>
123
+ </li>
124
+ </ul>
125
+ </nav>
126
+ ```
127
+
89
128
  Adding the `micl-list-item--disabled` class to a menu item causes the item to be displayed in a disabled state.
90
129
 
91
130
  Add the `micl-list-item__divider` class to a menu item to create a divider between the item and the previous menu item.
92
131
 
132
+ ## Customizations
133
+ You can customize the appearance of the Menu component by overriding its global CSS variables. These variables are declared on the `:root` pseudo-class and can be changed on any appropriate parent element to affect its child menus.
134
+
135
+ | Variable name | Default Value | Description |
136
+ | ------------- | ----- | ----------- |
137
+ | --md-sys-menu-width-max | 280px | The maximum width allowed for a menu |
138
+ | --md-sys-menu-width-min | 112px | The minimum allowed width for a menu |
139
+
140
+ **Example: Changing the maximum width**
141
+
142
+ ```HTML
143
+ <div style="--md-sys-menu-width-max:320px">
144
+ <nav id="mymenu" class="micl-menu" popover>
145
+ <ul class="micl-list">
146
+ <li class="micl-list-item-one" tabindex="0">
147
+ <span class="micl-list-item__text">
148
+ <span class="micl-list-item__headline">Menu item</span>
149
+ </span>
150
+ </li>
151
+ </ul>
152
+ </nav>
153
+ </div>
154
+ ```
155
+
93
156
  ## Compatibility
94
157
  This component uses **popover anchor positioning** to place the menu next to its invoker. This is a modern CSS feature that may not be fully supported in all browsers. To ensure the menu works in browsers that do not support anchor positioning, wrap the menu and its invoker in a `<div>` element with `position:relative`. Please check [Browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/anchor#browser_compatibility) for details.