material-inspired-component-library 9.1.0 → 9.1.2
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/README.md +2 -1
- package/components/appbar/index.scss +1 -1
- package/components/badge/README.md +43 -12
- package/components/badge/index.scss +15 -21
- package/components/bottomsheet/README.md +53 -22
- package/components/bottomsheet/index.scss +62 -45
- package/components/button/_shared.scss +9 -9
- package/components/card/README.md +55 -25
- package/components/card/index.scss +57 -38
- package/components/checkbox/README.md +97 -28
- package/components/checkbox/index.scss +39 -29
- package/components/chip/index.scss +6 -6
- package/components/datepicker/README.md +184 -59
- package/components/datepicker/index.scss +85 -21
- package/components/dialog/README.md +151 -56
- package/components/dialog/index.scss +50 -62
- package/components/iconbutton/index.scss +8 -8
- package/components/list/index.scss +15 -11
- package/components/menu/index.scss +13 -13
- package/components/navigationbar/index.scss +7 -1
- package/components/navigationrail/index.scss +27 -22
- package/components/radio/README.md +52 -12
- package/components/radio/index.scss +59 -41
- package/components/select/index.scss +3 -3
- package/components/sidesheet/README.md +90 -37
- package/components/sidesheet/index.scss +51 -41
- package/components/slider/README.md +35 -9
- package/components/slider/index.scss +182 -153
- package/components/snackbar/README.md +43 -25
- package/components/snackbar/index.scss +22 -27
- package/components/stepper/index.scss +5 -5
- package/components/switch/README.md +32 -4
- package/components/switch/index.scss +57 -52
- package/components/timepicker/README.md +131 -55
- package/components/timepicker/index.scss +47 -26
- package/dist/appbar.css +1 -1
- package/dist/badge.css +1 -1
- package/dist/bottomsheet.css +1 -1
- package/dist/bottomsheet.js +1 -1
- package/dist/button.css +1 -1
- package/dist/card.css +1 -1
- package/dist/checkbox.css +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/chip.css +1 -1
- package/dist/components/checkbox/index.d.ts +1 -0
- package/dist/datepicker.css +1 -1
- package/dist/datepicker.js +1 -1
- package/dist/dialog.css +1 -1
- package/dist/foundations/form/index.js +1 -1
- package/dist/iconbutton.css +1 -1
- package/dist/layout.css +1 -1
- package/dist/list.css +1 -1
- package/dist/menu.css +1 -1
- package/dist/micl.css +1 -1
- package/dist/micl.js +1 -1
- package/dist/navigationbar.css +1 -1
- package/dist/navigationrail.css +1 -1
- package/dist/radio.css +1 -1
- package/dist/select.css +1 -1
- package/dist/sidesheet.css +1 -1
- package/dist/slider.css +1 -1
- package/dist/slider.js +1 -1
- package/dist/snackbar.css +1 -1
- package/dist/snackbar.js +1 -1
- package/dist/stepper.css +1 -1
- package/dist/stepper.js +1 -1
- package/dist/switch.css +1 -1
- package/dist/timepicker.css +1 -1
- package/dist/timepicker.js +1 -1
- package/foundations/layout/_tokens.scss +55 -0
- package/foundations/layout/index.scss +5 -35
- package/package.json +2 -2
- package/{components/checkbox/_label.scss → styles/togglelabel.scss} +11 -3
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
@use '../../styles/motion';
|
|
23
23
|
@use '../../styles/shape';
|
|
24
24
|
@use '../../styles/statelayer';
|
|
25
|
-
@use '
|
|
25
|
+
@use '../../styles/togglelabel';
|
|
26
26
|
|
|
27
27
|
@include shape.corner('full');
|
|
28
28
|
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
@include statelayer.token('pressed-state-layer-opacity');
|
|
33
33
|
@include statelayer.token('disabled-state-layer-opacity');
|
|
34
34
|
@include statelayer.token('focus-indicator-thickness');
|
|
35
|
+
@include statelayer.token('focus-indicator-outer-offset');
|
|
35
36
|
@include statelayer.token('ripple-opacity-factor');
|
|
36
37
|
@include statelayer.token('ripple-duration');
|
|
37
38
|
@include statelayer.property;
|
|
@@ -40,32 +41,37 @@
|
|
|
40
41
|
$radio: 'input[type=radio].micl-radio';
|
|
41
42
|
|
|
42
43
|
#{$radio} {
|
|
43
|
-
--md-comp-radio-button-motion-effects
|
|
44
|
-
--md-comp-radio-button-motion-duration
|
|
45
|
-
--md-comp-radio-button-motion-duration-reverse
|
|
44
|
+
--_motion-effects: var(--md-comp-radio-button-motion-effects, #{motion.$md-sys-motion-expressive-slow-effects});
|
|
45
|
+
--_motion-duration: var(--md-comp-radio-button-motion-duration, #{motion.$md-sys-motion-expressive-slow-effects-duration});
|
|
46
|
+
--_motion-duration-reverse: var(--md-comp-radio-button-motion-duration-reverse, #{motion.$md-sys-motion-expressive-default-effects-duration});
|
|
46
47
|
|
|
47
48
|
--_size: var(--md-comp-radio-button-icon-size, 20px);
|
|
48
49
|
--_outline-width: var(--md-comp-radio-button-outline-width, 2px);
|
|
50
|
+
--_layer: max(var(--md-sys-state-layer-size, 40px), calc(var(--_size) + 20px));
|
|
51
|
+
--_target: max(var(--md-sys-state-target-size, 48px), calc(var(--_layer) + 8px));
|
|
52
|
+
--statelayer-color: var(--md-sys-color-on-surface);
|
|
49
53
|
|
|
50
54
|
appearance: none;
|
|
51
55
|
box-sizing: border-box;
|
|
52
56
|
position: relative;
|
|
53
|
-
inline-size: var(--
|
|
54
|
-
min-inline-size: var(--
|
|
55
|
-
block-size: var(--
|
|
56
|
-
min-block-size: var(--
|
|
57
|
+
inline-size: var(--_target);
|
|
58
|
+
min-inline-size: var(--_target);
|
|
59
|
+
block-size: var(--_target);
|
|
60
|
+
min-block-size: var(--_target);
|
|
57
61
|
margin: 0;
|
|
58
|
-
border: calc((var(--
|
|
62
|
+
border: calc((var(--_target) - var(--_layer)) / 2) solid transparent;
|
|
59
63
|
background-clip: content-box;
|
|
60
64
|
background-color: transparent;
|
|
61
65
|
-webkit-tap-highlight-color: transparent;
|
|
62
66
|
border-radius: var(--md-sys-shape-corner-full);
|
|
63
|
-
outline-offset:
|
|
67
|
+
outline-offset: calc(
|
|
68
|
+
var(--md-sys-state-focus-indicator-outer-offset, 2px)
|
|
69
|
+
- ((var(--_target) - var(--_layer)) / 2)
|
|
70
|
+
);
|
|
64
71
|
|
|
65
|
-
// The ring and the dot in one box: the dot is the primary background clipped to the
|
|
66
|
-
// content box, hidden while the padding fills the ring, revealed when the checked
|
|
67
|
-
// padding shrinks to reveal a dot of half the icon size.
|
|
68
72
|
&::after {
|
|
73
|
+
--_outline-color: var(--md-comp-radio-button-unselected-icon-color, var(--md-sys-color-on-surface-variant));
|
|
74
|
+
|
|
69
75
|
content: "";
|
|
70
76
|
box-sizing: border-box;
|
|
71
77
|
position: absolute;
|
|
@@ -74,20 +80,25 @@ $radio: 'input[type=radio].micl-radio';
|
|
|
74
80
|
inset: 0;
|
|
75
81
|
margin: auto;
|
|
76
82
|
padding: calc((var(--_size) / 2) - var(--_outline-width));
|
|
77
|
-
border: var(--_outline-width) solid var(--
|
|
83
|
+
border: var(--_outline-width) solid var(--_outline-color);
|
|
78
84
|
background-color: var(--md-comp-radio-button-selected-icon-color, var(--md-sys-color-primary));
|
|
79
85
|
background-clip: content-box;
|
|
80
86
|
border-radius: var(--md-sys-shape-corner-full);
|
|
81
87
|
transition:
|
|
82
|
-
padding var(--
|
|
83
|
-
border-color var(--
|
|
88
|
+
padding var(--_motion-duration-reverse) var(--_motion-effects),
|
|
89
|
+
border-color var(--_motion-duration-reverse) motion.$md-sys-motion-easing-emphasized;
|
|
84
90
|
}
|
|
85
|
-
&:checked
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
&:checked {
|
|
92
|
+
--statelayer-color: var(--md-sys-color-primary);
|
|
93
|
+
|
|
94
|
+
&::after {
|
|
95
|
+
--_outline-color: var(--md-comp-radio-button-selected-icon-color, var(--md-sys-color-primary));
|
|
96
|
+
|
|
97
|
+
padding: calc((var(--_size) / 4) - var(--_outline-width));
|
|
98
|
+
transition:
|
|
99
|
+
padding var(--_motion-duration) var(--_motion-effects),
|
|
100
|
+
border-color var(--_motion-duration) motion.$md-sys-motion-easing-emphasized;
|
|
101
|
+
}
|
|
91
102
|
}
|
|
92
103
|
&:not(:disabled) {
|
|
93
104
|
--micl-ripple: 1;
|
|
@@ -106,33 +117,35 @@ $radio: 'input[type=radio].micl-radio';
|
|
|
106
117
|
cursor: pointer;
|
|
107
118
|
transition:
|
|
108
119
|
background-size 0ms,
|
|
109
|
-
--statelayer-opacity var(--
|
|
120
|
+
--statelayer-opacity var(--_motion-duration) linear;
|
|
110
121
|
|
|
111
|
-
&:hover,
|
|
112
|
-
&:focus-visible,
|
|
113
|
-
&:active {
|
|
114
|
-
--statelayer-color: var(--md-sys-color-on-surface);
|
|
115
|
-
|
|
116
|
-
&:checked {
|
|
117
|
-
--statelayer-color: var(--md-sys-color-primary);
|
|
118
|
-
}
|
|
119
|
-
&::after {
|
|
120
|
-
border-color: var(--md-sys-color-on-surface);
|
|
121
|
-
}
|
|
122
|
-
&:checked::after {
|
|
123
|
-
border-color: var(--md-comp-radio-button-selected-icon-color, var(--md-sys-color-primary));
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
122
|
&:hover {
|
|
127
123
|
--statelayer-opacity: var(--md-sys-state-hover-state-layer-opacity, 8%);
|
|
124
|
+
|
|
125
|
+
&:not(:checked)::after {
|
|
126
|
+
--_outline-color: var(--md-sys-color-on-surface);
|
|
127
|
+
}
|
|
128
128
|
}
|
|
129
129
|
&:focus-visible {
|
|
130
130
|
--statelayer-opacity: var(--md-sys-state-focus-state-layer-opacity, 10%);
|
|
131
131
|
|
|
132
132
|
outline: var(--md-sys-state-focus-indicator-thickness, 3px) solid var(--md-sys-color-secondary);
|
|
133
|
+
|
|
134
|
+
&:not(:checked)::after {
|
|
135
|
+
--_outline-color: var(--md-sys-color-on-surface);
|
|
136
|
+
}
|
|
133
137
|
}
|
|
134
138
|
&:active {
|
|
139
|
+
--statelayer-color: var(--md-sys-color-on-surface);
|
|
135
140
|
--statelayer-opacity: var(--md-sys-state-pressed-state-layer-opacity, 10%);
|
|
141
|
+
|
|
142
|
+
&:not(:checked) {
|
|
143
|
+
--statelayer-color: var(--md-sys-color-primary);
|
|
144
|
+
|
|
145
|
+
&::after {
|
|
146
|
+
--_outline-color: var(--md-sys-color-on-surface);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
136
149
|
}
|
|
137
150
|
&.micl-rippling {
|
|
138
151
|
animation: micl-ripple var(--md-sys-state-ripple-duration);
|
|
@@ -142,7 +155,7 @@ $radio: 'input[type=radio].micl-radio';
|
|
|
142
155
|
opacity: var(--md-sys-state-disabled-state-layer-opacity, 38%);
|
|
143
156
|
|
|
144
157
|
&::after {
|
|
145
|
-
|
|
158
|
+
--_outline-color: var(--md-sys-color-on-surface);
|
|
146
159
|
}
|
|
147
160
|
&:checked::after {
|
|
148
161
|
background-color: var(--md-sys-color-on-surface);
|
|
@@ -151,14 +164,19 @@ $radio: 'input[type=radio].micl-radio';
|
|
|
151
164
|
}
|
|
152
165
|
|
|
153
166
|
#{$radio}:not(:disabled) + label,
|
|
154
|
-
label:has(+ #{$radio}:not(:disabled))
|
|
167
|
+
label:has(+ #{$radio}:not(:disabled)),
|
|
168
|
+
label:has(#{$radio}:not(:disabled)) {
|
|
155
169
|
@extend %micl-toggle-label-pointer;
|
|
156
170
|
}
|
|
157
171
|
#{$radio} + label,
|
|
158
|
-
label:has(+ #{$radio})
|
|
172
|
+
label:has(+ #{$radio}),
|
|
173
|
+
label:has(#{$radio}) {
|
|
159
174
|
@extend %micl-toggle-label;
|
|
160
175
|
}
|
|
161
176
|
#{$radio}:disabled + label,
|
|
162
177
|
label:has(+ #{$radio}:disabled) {
|
|
163
178
|
@extend %micl-toggle-label-disabled;
|
|
164
179
|
}
|
|
180
|
+
label:has(#{$radio}:disabled) {
|
|
181
|
+
@extend %micl-toggle-label-disabled-text;
|
|
182
|
+
}
|
|
@@ -41,8 +41,8 @@ $selects: ':is(.micl-textfield-filled, .micl-textfield-outlined) > select';
|
|
|
41
41
|
--_line-height: var(--md-comp-text-field-container-height, 56px);
|
|
42
42
|
}
|
|
43
43
|
#{$selects} {
|
|
44
|
-
--md-comp-list-motion-effects
|
|
45
|
-
--md-comp-list-motion-duration
|
|
44
|
+
--_list-motion-effects: var(--md-comp-list-motion-effects, #{motion.$md-sys-motion-expressive-fast-spatial});
|
|
45
|
+
--_list-motion-duration: var(--md-comp-list-motion-duration, #{motion.$md-sys-motion-expressive-default-effects-duration});
|
|
46
46
|
|
|
47
47
|
appearance: base-select;
|
|
48
48
|
line-height: var(--_line-height);
|
|
@@ -168,7 +168,7 @@ $selects: ':is(.micl-textfield-filled, .micl-textfield-outlined) > select';
|
|
|
168
168
|
// the list transition is repeated here without it.
|
|
169
169
|
transition:
|
|
170
170
|
background-size 0ms,
|
|
171
|
-
--statelayer-opacity var(--
|
|
171
|
+
--statelayer-opacity var(--_list-motion-duration) linear;
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# Side sheet
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
This component implements the [Material Design 3 Expressive Side sheet](https://m3.material.io/components/side-sheets/overview) specification. Side sheets display optional content and actions without interrupting the user's workflow in the main content area.
|
|
3
4
|
|
|
4
5
|
## Basic Usage
|
|
5
6
|
|
|
@@ -14,6 +15,7 @@ To create a standard side sheet, use the `<dialog>` element with the `popover` a
|
|
|
14
15
|
type="button"
|
|
15
16
|
class="micl-iconbutton-standard-s material-symbols-outlined"
|
|
16
17
|
popovertarget="mysidesheet"
|
|
18
|
+
aria-label="Close"
|
|
17
19
|
>close</button>
|
|
18
20
|
</div>
|
|
19
21
|
<div class="micl-sidesheet__content">
|
|
@@ -32,7 +34,7 @@ Import the side sheet styles into your project:
|
|
|
32
34
|
@use "material-inspired-component-library/dist/sidesheet";
|
|
33
35
|
```
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
Alternatively, import all MICL styles at once:
|
|
36
38
|
```CSS
|
|
37
39
|
@use "material-inspired-component-library/styles";
|
|
38
40
|
```
|
|
@@ -41,25 +43,67 @@ Or import all MICL styles:
|
|
|
41
43
|
No custom JavaScript is required for the core functionality of the side sheet component.
|
|
42
44
|
|
|
43
45
|
### Live Demo
|
|
44
|
-
A live
|
|
46
|
+
A live interactive demo of the [Side sheet component](https://henkpb.github.io/micl/sidesheet.html) is available.
|
|
47
|
+
|
|
48
|
+
## Anatomy
|
|
49
|
+
A **standard** side sheet allows the rest of the page to remain usable by dynamically narrowing the main content area to make room for itself. Its headline and actions container are both optional; a side sheet may consist of nothing but content.
|
|
50
|
+
|
|
51
|
+
| Element | Meaning |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| `dialog.micl-sidesheet` | The container. Add the `popover` attribute for a standard side sheet; omit it for a modal one. |
|
|
54
|
+
| `.micl-sidesheet__headline` | The header row: holds an optional back button, a heading, and an optional close button. |
|
|
55
|
+
| `.micl-sidesheet__content` | The scrollable body of the side sheet. |
|
|
56
|
+
| `.micl-sidesheet__actions` | An optional row of buttons pinned to the bottom, usually preceded by an `<hr class="micl-divider">`. |
|
|
57
|
+
|
|
58
|
+
A side sheet is **docked**, meaning it spans the full height of the viewport and sits flush against the trailing edge.
|
|
59
|
+
|
|
60
|
+
> [!WARNING]
|
|
61
|
+
> The **standard** side sheet component dynamically applies CSS rules to the `<body>` element to properly resize the main content area when the sheet is open. Overriding these rules may cause unexpected layout behavior. The applied rules are:
|
|
62
|
+
> ```CSS
|
|
63
|
+
> box-sizing: border-box;
|
|
64
|
+
> margin: 0;
|
|
65
|
+
> max-inline-size: /* varies dynamically based on side sheet state */
|
|
66
|
+
> transition: /* handles max-inline-size animation */
|
|
67
|
+
> ```
|
|
68
|
+
>
|
|
69
|
+
> These rules only take effect on medium window size classes (600px) and wider. On compact screens lacking horizontal space, the main content area is left untouched and the side sheet simply overlays it.
|
|
45
70
|
|
|
46
71
|
## Variants
|
|
47
|
-
|
|
72
|
+
Using a plain `popover` attribute makes the side sheet an *auto* popover: it closes automatically when the user presses <kbd>Esc</kbd> or clicks anywhere outside of it. This behavior is ideal for temporary panels like settings menus.
|
|
48
73
|
|
|
49
|
-
|
|
74
|
+
### Co-Existing Side Sheet
|
|
75
|
+
For a side sheet that should remain open while the user interacts with the main content, use `popover="manual"` instead. A manual popover is only dismissed by its own close button:
|
|
50
76
|
|
|
77
|
+
```HTML
|
|
78
|
+
<dialog id="mysidesheet" class="micl-sidesheet" popover="manual" aria-labelledby="mytitle">
|
|
79
|
+
...
|
|
80
|
+
</dialog>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
To open a **standard** side sheet, link a trigger button to the sheet's ID using `popovertarget`:
|
|
84
|
+
```HTML
|
|
85
|
+
<button type="button" popovertarget="mysidesheet">Open Side Sheet</button>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Modal Side Sheet
|
|
89
|
+
A **modal** side sheet blocks access to the rest of the page and requires the user to explicitly dismiss it. This variant is suitable for critical tasks or information requiring full attention.
|
|
90
|
+
|
|
91
|
+
To create a modal side sheet, use the `<dialog>` element *without* the `popover` attribute. Because it isn't a popover, `popovertarget` has no effect. Instead, you must provide a button (or another control) using `command="close"` to dismiss it. A modal side sheet is inherently not dismissed by outside clicks; explicitly setting `closedby="closerequest"` enforces this behavior while keeping the <kbd>Esc</kbd> key functional. (If you *do* want outside clicks to close it, use `closedby="any"` instead).
|
|
51
92
|
```HTML
|
|
52
93
|
<dialog id="mysidesheet" class="micl-sidesheet" closedby="closerequest" aria-labelledby="mytitle">
|
|
53
94
|
<div class="micl-sidesheet__headline">
|
|
54
95
|
<button
|
|
55
96
|
type="button"
|
|
56
97
|
class="micl-iconbutton-standard-s material-symbols-outlined"
|
|
98
|
+
aria-label="Back"
|
|
57
99
|
>arrow_back</button>
|
|
58
100
|
<h2 id="mytitle">Title</h2>
|
|
59
101
|
<button
|
|
60
102
|
type="button"
|
|
61
103
|
class="micl-iconbutton-standard-s material-symbols-outlined"
|
|
62
|
-
|
|
104
|
+
command="close"
|
|
105
|
+
commandfor="mysidesheet"
|
|
106
|
+
aria-label="Close"
|
|
63
107
|
>close</button>
|
|
64
108
|
</div>
|
|
65
109
|
<div class="micl-sidesheet__content">
|
|
@@ -72,54 +116,63 @@ To create a modal side sheet, use the `<dialog>` element without the `popover` a
|
|
|
72
116
|
</dialog>
|
|
73
117
|
```
|
|
74
118
|
|
|
75
|
-
To open a
|
|
119
|
+
To open a **modal** side sheet, use the `show-modal` command instead:
|
|
76
120
|
```HTML
|
|
77
|
-
<button type="button"
|
|
121
|
+
<button type="button" command="show-modal" commandfor="mysidesheet">Open Side Sheet</button>
|
|
78
122
|
```
|
|
79
123
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
> [!WARNING]
|
|
88
|
-
> The **standard** side sheet component adds CSS rules to the `<body>` element to properly resize the main content area when the side sheet is open. Overriding these rules may cause the component to behave unexpectedly. The rules that are applied are:
|
|
89
|
-
> ```CSS
|
|
90
|
-
> box-sizing: border-box;
|
|
91
|
-
> margin: 0;
|
|
92
|
-
> max-inline-size: ...varies depending on if the side sheet is opened...
|
|
93
|
-
> transition: ...transition on max-inline-size...
|
|
94
|
-
> ```
|
|
124
|
+
## Accessibility
|
|
125
|
+
* **Name the side sheet:** A `<dialog>` is exposed to assistive technologies as a dialog. Always provide an accessible name by pointing `aria-labelledby` to the headline's heading `id`.
|
|
126
|
+
* **Name the icon buttons:** Always provide a descriptive `aria-label` for icon buttons, like the back and close buttons.
|
|
127
|
+
* **Manage initial focus:** A standard side sheet relies on the Popover API, which automatically moves focus into the side sheet when the user tabs away from the trigger button, and returns focus upon closing. A modal side sheet natively focuses its first focusable descendant. This is rarely the desired behavior if the first element is a "Back" button. Add the `autofocus` attribute to the control that should legitimately receive focus first. *(Note: placing `autofocus` directly on the `<dialog>` element is ignored).*
|
|
128
|
+
* **Scrolling by keyboard:** When the content container overflows, modern browsers make it a distinct tab stop (often with a visible focus ring) so it can be scrolled via arrow keys. This is a deliberate accessibility feature; do not suppress the focus ring.
|
|
129
|
+
* **Dismissal constraints:** A side sheet opened with `popover` or `showModal()` is dismissed via the <kbd>Esc</kbd> key. A `popover="manual"` side sheet is not, meaning a visible close button is strictly required.
|
|
130
|
+
* **Respect motion preferences:** All motion is automatically disabled if the user has requested reduced motion at the OS level. The side sheet (and the main content resizing) will toggle instantly.
|
|
95
131
|
|
|
96
132
|
## Theming
|
|
97
|
-
Each side sheet
|
|
133
|
+
Each side sheet can be themed using CSS custom properties formatted to match the Material Design 3 component-token naming convention.
|
|
98
134
|
|
|
99
135
|
| Custom property | Meaning | Default |
|
|
100
|
-
|
|
101
|
-
| `--md-comp-sidesheet-container-width` | The
|
|
102
|
-
| `--md-comp-sidesheet-container-max-width` | The
|
|
103
|
-
| `--md-comp-sidesheet-padding` | The
|
|
136
|
+
| --- | --- | --- |
|
|
137
|
+
| `--md-comp-sidesheet-container-width` | The width of the side sheet | `256px` |
|
|
138
|
+
| `--md-comp-sidesheet-container-max-width` | The maximum allowed width of the side sheet; any larger `--md-comp-sidesheet-container-width` is clamped to this | `400px` |
|
|
139
|
+
| `--md-comp-sidesheet-padding` | The padding between the vertical edges and the content | `--md-sys-layout-window-margin` |
|
|
140
|
+
| `--md-comp-sidesheet-headline-height` | The minimum height of the headline row; increase this if using icon buttons larger than `micl-iconbutton-standard-s` | `40px` |
|
|
104
141
|
| `--md-comp-sidesheet-container-shape` | The corner rounding of the standard side sheet | `--md-sys-shape-corner-none` |
|
|
142
|
+
| `--md-comp-sidesheet-content-color` | The text color inside the side sheet | `--md-sys-color-on-surface` |
|
|
105
143
|
| `--md-comp-sidesheet-standard-container-color` | The background color of the standard side sheet | `--md-sys-color-surface` |
|
|
106
|
-
| `--md-comp-sidesheet-divider-thickness` | The thickness of the
|
|
107
|
-
| `--md-comp-sidesheet-divider-color` | The color of the
|
|
108
|
-
| `--md-comp-sidesheet-standard-container-elevation` | The shadow (elevation) of the standard side sheet | `--md-sys-elevation-level0` |
|
|
144
|
+
| `--md-comp-sidesheet-divider-thickness` | The thickness of the standard side sheet's vertical divider | `1px` |
|
|
145
|
+
| `--md-comp-sidesheet-divider-color` | The color of the standard side sheet's vertical divider | `--md-sys-color-outline-variant` |
|
|
146
|
+
| `--md-comp-sidesheet-standard-container-elevation` | The shadow depth (elevation) of the standard side sheet | `--md-sys-elevation-level0` |
|
|
109
147
|
| `--md-comp-sidesheet-modal-container-color` | The background color of the modal side sheet | `--md-sys-color-surface-container-low` |
|
|
110
|
-
| `--md-comp-sidesheet-modal-container-elevation` | The shadow (elevation) of the modal side sheet | `--md-sys-elevation-level1` |
|
|
111
|
-
| `--md-comp-sidesheet-modal-container-shape` | The corner rounding of the modal side sheet
|
|
148
|
+
| `--md-comp-sidesheet-modal-container-elevation` | The shadow depth (elevation) of the modal side sheet | `--md-sys-elevation-level1` |
|
|
149
|
+
| `--md-comp-sidesheet-modal-container-shape` | The corner rounding of the modal side sheet (applied to the two corners facing the main content) | `--md-sys-shape-corner-large` |
|
|
150
|
+
| `--md-comp-sidesheet-motion-spatial` | The easing function for sliding the side sheet (uses a spring animation that slightly overshoots before settling) | `--md-sys-motion-expressive-slow-spatial` |
|
|
151
|
+
| `--md-comp-sidesheet-motion-duration` | Animation duration for opening | `650ms` |
|
|
152
|
+
| `--md-comp-sidesheet-motion-duration-reverse` | Animation duration for closing | `500ms` |
|
|
112
153
|
|
|
113
|
-
|
|
114
|
-
**Example: Changing the width of the sidesheet**
|
|
154
|
+
**Example: Changing the width of the side sheet**
|
|
115
155
|
|
|
116
156
|
```HTML
|
|
117
|
-
<body style="--md-comp-sidesheet-container-width:320px">
|
|
157
|
+
<body style="--md-comp-sidesheet-container-width: 320px;">
|
|
118
158
|
<dialog id="mysidesheet" class="micl-sidesheet" popover>
|
|
119
159
|
...
|
|
120
160
|
</dialog>
|
|
121
161
|
</body>
|
|
122
162
|
```
|
|
123
163
|
|
|
164
|
+
To remove the vertical divider of a standard side sheet, set the following CSS variable to zero:
|
|
165
|
+
```CSS
|
|
166
|
+
#mysidesheet {
|
|
167
|
+
--md-comp-sidesheet-divider-thickness: 0;
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
> [!NOTE]
|
|
172
|
+
> For a **standard** side sheet, define the `--md-comp-sidesheet-container-width` custom property on the `<body>` (or `:root`) element rather than on the side sheet itself. The CSS rule responsible for shrinking the main content area reads this variable from the body. Setting it only on the `<dialog>` would cause the side sheet and the main content area to fall out of sync.
|
|
173
|
+
|
|
124
174
|
## Compatibility
|
|
125
|
-
|
|
175
|
+
|
|
176
|
+
The standard side sheet relies on the Popover API. Please review [browser compatibility for the Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) if you are targeting older browsers.
|
|
177
|
+
|
|
178
|
+
The modal side sheet is opened and closed using the `command` and `commandfor` attributes. Review [browser compatibility for the Invoker Commands API](https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API). If these attributes are not supported in your target environments, calling `showModal()` and `close()` via JavaScript serves as an effective fallback.
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
20
|
// SOFTWARE.
|
|
21
21
|
|
|
22
|
-
@use '../../foundations/layout';
|
|
22
|
+
@use '../../foundations/layout/tokens';
|
|
23
23
|
@use '../../styles/elevation';
|
|
24
24
|
@use '../../styles/motion';
|
|
25
25
|
@use '../../styles/shape';
|
|
@@ -36,33 +36,32 @@
|
|
|
36
36
|
|
|
37
37
|
@include typography.scale('title-large');
|
|
38
38
|
|
|
39
|
-
:
|
|
40
|
-
|
|
41
|
-
--md-comp-sidesheet-container-max-width: 400px;
|
|
42
|
-
--md-comp-sidesheet-padding: var(--md-sys-layout-window-margin, 24px);
|
|
43
|
-
}
|
|
44
|
-
body {
|
|
45
|
-
--md-comp-sidesheet-motion-spatial: #{motion.$md-sys-motion-expressive-slow-spatial};
|
|
46
|
-
--md-comp-sidesheet-motion-duration: #{motion.$md-sys-motion-expressive-slow-spatial-duration};
|
|
47
|
-
--md-comp-sidesheet-motion-duration-reverse: #{motion.$md-sys-motion-expressive-default-spatial-duration};
|
|
48
|
-
}
|
|
39
|
+
$container-width: 256px;
|
|
40
|
+
$container-max-width: 400px;
|
|
49
41
|
|
|
50
42
|
dialog.micl-sidesheet {
|
|
43
|
+
--_width: min(var(--md-comp-sidesheet-container-width, #{$container-width}), var(--md-comp-sidesheet-container-max-width, #{$container-max-width}));
|
|
44
|
+
--_padding: var(--md-comp-sidesheet-padding, var(--md-sys-layout-window-margin, 24px));
|
|
45
|
+
--_motion-spatial: var(--md-comp-sidesheet-motion-spatial, #{motion.$md-sys-motion-expressive-slow-spatial});
|
|
46
|
+
--_motion-duration: var(--md-comp-sidesheet-motion-duration, #{motion.$md-sys-motion-expressive-slow-spatial-duration});
|
|
47
|
+
--_motion-duration-reverse: var(--md-comp-sidesheet-motion-duration-reverse, #{motion.$md-sys-motion-expressive-default-spatial-duration});
|
|
48
|
+
|
|
51
49
|
--micl-spring-buffer: 40px;
|
|
52
|
-
--micl-duration: var(--
|
|
50
|
+
--micl-duration: var(--_motion-duration-reverse);
|
|
53
51
|
|
|
54
52
|
box-sizing: border-box;
|
|
55
53
|
display: none;
|
|
56
54
|
flex-direction: column;
|
|
57
|
-
|
|
58
|
-
max-inline-size:
|
|
59
|
-
block-size:
|
|
60
|
-
|
|
55
|
+
inline-size: calc(var(--_width) + var(--micl-spring-buffer));
|
|
56
|
+
max-inline-size: none;
|
|
57
|
+
block-size: 100dvb;
|
|
58
|
+
max-block-size: none;
|
|
61
59
|
margin-block: 0;
|
|
62
60
|
margin-inline-start: auto;
|
|
63
|
-
margin-inline-end: calc(-1 * (var(--
|
|
64
|
-
padding-block: var(--
|
|
61
|
+
margin-inline-end: calc(-1 * (var(--_width) + var(--micl-spring-buffer)));
|
|
62
|
+
padding-block: var(--_padding) 0;
|
|
65
63
|
padding-inline: 0 var(--micl-spring-buffer);
|
|
64
|
+
color: var(--md-comp-sidesheet-content-color, var(--md-sys-color-on-surface));
|
|
66
65
|
background-color: var(--md-comp-sidesheet-standard-container-color, var(--md-sys-color-surface));
|
|
67
66
|
border: none;
|
|
68
67
|
border-radius: var(--md-comp-sidesheet-container-shape, var(--md-sys-shape-corner-none));
|
|
@@ -71,15 +70,15 @@ dialog.micl-sidesheet {
|
|
|
71
70
|
overflow: hidden;
|
|
72
71
|
transition:
|
|
73
72
|
opacity var(--micl-duration) linear,
|
|
74
|
-
margin-inline-end var(--micl-duration) var(--
|
|
73
|
+
margin-inline-end var(--micl-duration) var(--_motion-spatial),
|
|
75
74
|
overlay var(--micl-duration) linear allow-discrete,
|
|
76
75
|
display var(--micl-duration) linear allow-discrete;
|
|
77
76
|
|
|
78
77
|
.micl-sidesheet__headline {
|
|
79
78
|
display: flex;
|
|
80
79
|
align-items: center;
|
|
81
|
-
block-size: var(--md-
|
|
82
|
-
padding-inline: var(--
|
|
80
|
+
min-block-size: var(--md-comp-sidesheet-headline-height, 40px);
|
|
81
|
+
padding-inline: var(--_padding);
|
|
83
82
|
margin-block-end: 16px;
|
|
84
83
|
column-gap: 12px;
|
|
85
84
|
color: var(--md-sys-color-on-surface-variant);
|
|
@@ -92,19 +91,16 @@ dialog.micl-sidesheet {
|
|
|
92
91
|
overflow: hidden;
|
|
93
92
|
text-overflow: ellipsis;
|
|
94
93
|
white-space: nowrap;
|
|
95
|
-
user-select: none;
|
|
96
94
|
}
|
|
97
95
|
button {
|
|
98
|
-
margin-inline: -
|
|
99
|
-
}
|
|
100
|
-
button:first-child {
|
|
101
|
-
margin-inline-start: -16px;
|
|
96
|
+
margin-inline: -8px;
|
|
102
97
|
}
|
|
103
98
|
}
|
|
104
99
|
.micl-sidesheet__content {
|
|
105
100
|
box-sizing: border-box;
|
|
106
101
|
flex: 1 1 auto;
|
|
107
|
-
padding-
|
|
102
|
+
padding-block-end: var(--_padding);
|
|
103
|
+
padding-inline: var(--_padding);
|
|
108
104
|
overflow: hidden auto;
|
|
109
105
|
}
|
|
110
106
|
.micl-sidesheet__actions {
|
|
@@ -113,8 +109,8 @@ dialog.micl-sidesheet {
|
|
|
113
109
|
flex-shrink: 0;
|
|
114
110
|
align-items: center;
|
|
115
111
|
justify-content: start;
|
|
116
|
-
padding-block: 16px var(--
|
|
117
|
-
padding-inline: var(--
|
|
112
|
+
padding-block: 16px var(--_padding);
|
|
113
|
+
padding-inline: var(--_padding);
|
|
118
114
|
column-gap: 8px;
|
|
119
115
|
overflow: hidden;
|
|
120
116
|
}
|
|
@@ -126,18 +122,18 @@ dialog.micl-sidesheet {
|
|
|
126
122
|
box-shadow: var(--md-comp-sidesheet-modal-container-elevation, var(--md-sys-elevation-level1));
|
|
127
123
|
}
|
|
128
124
|
&:popover-open {
|
|
129
|
-
border-inline-start: var(--md-comp-sidesheet-divider-thickness, 1px) solid var(--md-comp-sidesheet-divider-color, var(--md-sys-color-outline, gray));
|
|
125
|
+
border-inline-start: var(--md-comp-sidesheet-divider-thickness, 1px) solid var(--md-comp-sidesheet-divider-color, var(--md-sys-color-outline-variant, gray));
|
|
130
126
|
}
|
|
131
127
|
&:popover-open,
|
|
132
128
|
&[open] {
|
|
133
|
-
--micl-duration: var(--
|
|
129
|
+
--micl-duration: var(--_motion-duration);
|
|
134
130
|
|
|
135
131
|
display: flex;
|
|
136
132
|
margin-inline-end: calc(-1 * var(--micl-spring-buffer));
|
|
137
133
|
opacity: 100%;
|
|
138
134
|
|
|
139
135
|
@starting-style {
|
|
140
|
-
margin-inline-end: calc(-1 * (var(--
|
|
136
|
+
margin-inline-end: calc(-1 * (var(--_width) + var(--micl-spring-buffer)));
|
|
141
137
|
opacity: 0;
|
|
142
138
|
}
|
|
143
139
|
}
|
|
@@ -152,15 +148,29 @@ dialog.micl-sidesheet {
|
|
|
152
148
|
background-color: rgba(0, 0, 0, 0);
|
|
153
149
|
}
|
|
154
150
|
}
|
|
155
|
-
}
|
|
156
151
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
transition: max-inline-size var(--md-comp-sidesheet-motion-duration-reverse);
|
|
152
|
+
@media (prefers-reduced-motion: reduce) {
|
|
153
|
+
--_motion-duration: 0ms;
|
|
154
|
+
--_motion-duration-reverse: 0ms;
|
|
155
|
+
}
|
|
162
156
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
157
|
+
|
|
158
|
+
@media (min-width: tokens.$md-sys-breakpoint-medium-min) {
|
|
159
|
+
body:has(dialog.micl-sidesheet[popover]) {
|
|
160
|
+
box-sizing: border-box;
|
|
161
|
+
max-inline-size: 100%;
|
|
162
|
+
margin: 0;
|
|
163
|
+
transition: max-inline-size var(--md-comp-sidesheet-motion-duration-reverse, #{motion.$md-sys-motion-expressive-default-spatial-duration});
|
|
164
|
+
}
|
|
165
|
+
body:has(dialog.micl-sidesheet:popover-open) {
|
|
166
|
+
max-inline-size: calc(100% - min(var(--md-comp-sidesheet-container-width, #{$container-width}), var(--md-comp-sidesheet-container-max-width, #{$container-max-width})));
|
|
167
|
+
transition: max-inline-size var(--md-comp-sidesheet-motion-duration, #{motion.$md-sys-motion-expressive-slow-spatial-duration}) var(--md-comp-sidesheet-motion-spatial, #{motion.$md-sys-motion-expressive-slow-spatial});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
@media (prefers-reduced-motion: reduce) {
|
|
171
|
+
body:has(dialog.micl-sidesheet[popover]),
|
|
172
|
+
body:has(dialog.micl-sidesheet:popover-open) {
|
|
173
|
+
transition-duration: 0s;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
166
176
|
}
|