material-inspired-component-library 9.1.1 → 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/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 +61 -44
- package/components/button/_shared.scss +6 -6
- package/components/card/README.md +1 -1
- package/components/checkbox/index.scss +10 -10
- package/components/datepicker/README.md +184 -59
- package/components/datepicker/index.scss +84 -20
- package/components/dialog/README.md +151 -56
- package/components/dialog/index.scss +50 -62
- package/components/iconbutton/index.scss +5 -5
- package/components/list/index.scss +6 -6
- package/components/menu/index.scss +13 -13
- package/components/navigationbar/index.scss +7 -1
- package/components/navigationrail/index.scss +27 -22
- package/components/radio/index.scss +8 -8
- 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 +4 -4
- package/components/switch/index.scss +13 -13
- package/components/timepicker/README.md +131 -55
- package/components/timepicker/index.scss +46 -25
- 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/checkbox.css +1 -1
- package/dist/chip.css +1 -1
- package/dist/datepicker.css +1 -1
- package/dist/datepicker.js +1 -1
- package/dist/dialog.css +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/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 +2 -35
- package/package.json +1 -1
|
@@ -1,102 +1,170 @@
|
|
|
1
1
|
# Dialog
|
|
2
|
-
This component implements the [Material Design 3 Expressive Dialog](https://m3.material.io/components/dialogs/overview) design. A dialog is a small window that prompts the user to make a decision or enter additional information.
|
|
2
|
+
This component implements the [Material Design 3 Expressive Dialog](https://m3.material.io/components/dialogs/overview) design. A dialog is a small, focused window that prompts the user to make a decision or enter additional information.
|
|
3
3
|
|
|
4
4
|
## Basic Usage
|
|
5
5
|
|
|
6
6
|
### HTML
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
To create a dialog, use the `<dialog>` element with the `micl-dialog` class and open it from a control element, such as a button.
|
|
8
9
|
|
|
9
10
|
```HTML
|
|
10
|
-
<dialog id="mydialog" class="micl-dialog"
|
|
11
|
+
<dialog id="mydialog" class="micl-dialog" closedby="closerequest" aria-labelledby="mytitle" aria-describedby="mydesc">
|
|
11
12
|
<div class="micl-dialog__headline">
|
|
12
13
|
<h2 id="mytitle">Basic dialog</h2>
|
|
13
14
|
<span id="mydesc" class="micl-dialog__supporting-text">An example of a basic dialog</span>
|
|
14
15
|
</div>
|
|
16
|
+
<form method="dialog" class="micl-dialog__actions">
|
|
17
|
+
<button class="micl-button-text-s" value="" autofocus>Cancel</button>
|
|
18
|
+
<button class="micl-button-text-s" value="ok">OK</button>
|
|
19
|
+
</form>
|
|
15
20
|
</dialog>
|
|
16
21
|
|
|
17
|
-
<button type="button"
|
|
18
|
-
```
|
|
22
|
+
<button type="button" class="micl-button-filled-m" command="show-modal" commandfor="mydialog">Open Basic Dialog</button>
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
```
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
* `command="show-modal"` combined with `commandfor` opens the dialog as a **modal**: the browser moves it to the top layer, traps keyboard focus inside it, and makes the rest of the page inert. This is the Material Design default and the recommended approach for most use cases.
|
|
27
|
+
* `closedby="closerequest"` is the default for a modal dialog and allows the <kbd>Esc</kbd> key to close it. Using `closedby="any"` will additionally close the dialog when the user clicks outside of it. Avoid `closedby="none"`, as it removes the <kbd>Esc</kbd> key escape route.
|
|
28
|
+
* `aria-labelledby` points to the heading and `aria-describedby` to the supporting text, ensuring assistive technologies announce both when the dialog opens.
|
|
29
|
+
* Buttons inside a `<form method="dialog">` close the dialog when activated, and the activating button's `value` is passed to `dialog.returnValue`. Give a canceling button an explicit `value=""`—a button without a `value` attribute leaves `returnValue` unchanged from its previous state. An empty `returnValue` is the conventional way to signal a cancellation.
|
|
30
|
+
* `autofocus` designates the control that receives focus when the dialog opens. Place this on the least destructive action.
|
|
23
31
|
|
|
24
32
|
### CSS
|
|
33
|
+
|
|
25
34
|
Import the dialog styles into your project:
|
|
26
35
|
|
|
27
36
|
```CSS
|
|
28
37
|
@use "material-inspired-component-library/dist/button";
|
|
29
38
|
@use "material-inspired-component-library/dist/iconbutton";
|
|
30
39
|
@use "material-inspired-component-library/dist/dialog";
|
|
40
|
+
|
|
31
41
|
```
|
|
32
42
|
|
|
33
43
|
Or import all MICL styles:
|
|
44
|
+
|
|
34
45
|
```CSS
|
|
35
46
|
@use "material-inspired-component-library/styles";
|
|
47
|
+
|
|
36
48
|
```
|
|
37
49
|
|
|
38
50
|
### JavaScript
|
|
39
|
-
|
|
51
|
+
|
|
52
|
+
No custom JavaScript is required for the core functionality of this component. The native `command` and `popover` attributes handle the open and close behaviors entirely.
|
|
40
53
|
|
|
41
54
|
### Live Demo
|
|
42
|
-
A live example of the [Dialog component](https://henkpb.github.io/micl/dialog.html) is available to interact with.
|
|
43
55
|
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
A live example of the [Dialog component](https://henkpb.github.io/micl/dialog.html) is available for interaction.
|
|
57
|
+
|
|
58
|
+
## Anatomy
|
|
59
|
+
|
|
60
|
+
A dialog consists of up to three sections:
|
|
61
|
+
|
|
62
|
+
* `micl-dialog__headline`: The header of the dialog. It usually contains:
|
|
63
|
+
* A heading element (`<h1>`-`<h6>`).
|
|
64
|
+
* An optional icon (`micl-dialog__icon`). When present, the icon, heading, and supporting text are centered.
|
|
65
|
+
* An optional sub-header (`micl-dialog__subhead`). Text that exceeds one line is truncated with an ellipsis.
|
|
66
|
+
* An optional `micl-dialog__supporting-text` element describing the dialog's purpose.
|
|
46
67
|
|
|
47
|
-
|
|
68
|
+
|
|
69
|
+
* `micl-dialog__content`: The optional main content area where additional information is placed. This section scrolls if the content exceeds the dialog's maximum height.
|
|
70
|
+
* `micl-dialog__actions`: A container for action buttons. In a modal dialog, these must be placed inside a `<form method="dialog">`.
|
|
48
71
|
|
|
49
72
|
```HTML
|
|
50
|
-
<dialog id="mydialog" class="micl-dialog" closedby="closerequest"
|
|
73
|
+
<dialog id="mydialog" class="micl-dialog" closedby="closerequest" aria-labelledby="mytitle" aria-describedby="mydesc">
|
|
51
74
|
<div class="micl-dialog__headline">
|
|
52
75
|
<span class="micl-dialog__icon material-symbols-outlined" aria-hidden="true">info</span>
|
|
53
|
-
<h2 id="mytitle">
|
|
54
|
-
<span
|
|
76
|
+
<h2 id="mytitle">Headline</h2>
|
|
77
|
+
<span class="micl-dialog__subhead">Sub-header</span>
|
|
78
|
+
<span id="mydesc" class="micl-dialog__supporting-text">Supporting text</span>
|
|
55
79
|
</div>
|
|
56
|
-
<div class="micl-
|
|
57
|
-
|
|
58
|
-
<button class="micl-button-text-s" autofocus>Cancel</button>
|
|
59
|
-
<button class="micl-button-text-s" value="save">Save</button>
|
|
60
|
-
</form>
|
|
80
|
+
<div class="micl-dialog__content">
|
|
81
|
+
…
|
|
61
82
|
</div>
|
|
83
|
+
<form method="dialog" class="micl-dialog__actions">
|
|
84
|
+
<button class="micl-button-text-s" value="" autofocus>Cancel</button>
|
|
85
|
+
<button class="micl-button-text-s" value="ok">OK</button>
|
|
86
|
+
</form>
|
|
62
87
|
</dialog>
|
|
63
88
|
|
|
64
|
-
<button type="button" command="show-modal" commandfor="mydialog">Open Modal Dialog</button>
|
|
65
89
|
```
|
|
66
90
|
|
|
67
|
-
|
|
91
|
+
## Variants
|
|
92
|
+
|
|
93
|
+
### Alert dialog
|
|
68
94
|
|
|
69
|
-
|
|
95
|
+
A dialog that interrupts the user with an urgent message must use `role="alertdialog"` to ensure assistive technologies announce it appropriately. Keep the content concise and provide at least one confirming and one dismissive action.
|
|
70
96
|
|
|
71
97
|
```HTML
|
|
72
|
-
<dialog id="mydialog" class="micl-dialog
|
|
98
|
+
<dialog id="mydialog" class="micl-dialog" closedby="closerequest" role="alertdialog" aria-labelledby="mytitle" aria-describedby="mydesc">
|
|
99
|
+
<div class="micl-dialog__headline">
|
|
100
|
+
<span class="micl-dialog__icon material-symbols-outlined" aria-hidden="true">delete</span>
|
|
101
|
+
<h2 id="mytitle">Delete selected images?</h2>
|
|
102
|
+
<span id="mydesc" class="micl-dialog__supporting-text">Images will be permanently removed from all synchronized devices.</span>
|
|
103
|
+
</div>
|
|
104
|
+
<form method="dialog" class="micl-dialog__actions">
|
|
105
|
+
<button class="micl-button-text-s" value="" autofocus>Cancel</button>
|
|
106
|
+
<button class="micl-button-text-s" value="dodelete">Delete</button>
|
|
107
|
+
</form>
|
|
73
108
|
</dialog>
|
|
74
109
|
|
|
75
|
-
<button type="button"
|
|
110
|
+
<button type="button" class="micl-button-outlined-m" command="show-modal" commandfor="mydialog">Delete images</button>
|
|
111
|
+
|
|
76
112
|
```
|
|
77
113
|
|
|
78
|
-
###
|
|
79
|
-
A dialog typically consists of three main sections to organize its content:
|
|
114
|
+
### Light-dismiss dialog
|
|
80
115
|
|
|
81
|
-
|
|
116
|
+
Adding the `popover` attribute renders the dialog as a popover instead of a modal. It animates outward from the opening control element and closes automatically when the user clicks outside of it or presses <kbd>Esc</kbd>.
|
|
82
117
|
|
|
83
|
-
|
|
118
|
+
```HTML
|
|
119
|
+
<dialog id="mydialog" class="micl-dialog" popover aria-labelledby="mytitle" aria-describedby="mydesc">
|
|
120
|
+
<div class="micl-dialog__headline">
|
|
121
|
+
<h2 id="mytitle">Light-dismiss dialog</h2>
|
|
122
|
+
<span id="mydesc" class="micl-dialog__supporting-text">An example of a dialog that closes when you click outside it</span>
|
|
123
|
+
</div>
|
|
124
|
+
<div class="micl-dialog__actions">
|
|
125
|
+
<button type="button" class="micl-button-text-s" popovertarget="mydialog" popovertargetaction="hide" autofocus>OK</button>
|
|
126
|
+
</div>
|
|
127
|
+
</dialog>
|
|
128
|
+
|
|
129
|
+
<button type="button" class="micl-button-outlined-m" popovertarget="mydialog">Open Dialog</button>
|
|
84
130
|
|
|
85
|
-
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
> [!IMPORTANT]
|
|
134
|
+
> A popover is not a modal. The browser does not trap focus inside it nor does it make the rest of the page inert. Review the Accessibility guidelines before choosing this variant.
|
|
86
135
|
|
|
87
|
-
|
|
136
|
+
Because a popover is governed by the Popover API rather than standard dialog behavior, two modal attributes have no effect here:
|
|
88
137
|
|
|
89
|
-
|
|
138
|
+
* `closedby` is ignored. Light dismissal and <kbd>Esc</kbd> key support are handled natively by the `popover` attribute.
|
|
139
|
+
* `<form method="dialog">` will not close a popover. You must close it using a button with `popovertarget` and `popovertargetaction="hide"`, as shown above.
|
|
90
140
|
|
|
91
|
-
|
|
141
|
+
### Docked dialog
|
|
92
142
|
|
|
93
|
-
|
|
143
|
+
A docked dialog opens adjacent to the control element rather than centering on the screen. Add the `micl-dialog--docked` class, assign an `anchor-name` to the control element, and link the dialog using `position-anchor`:
|
|
144
|
+
|
|
145
|
+
```HTML
|
|
146
|
+
<dialog id="mydialog" class="micl-dialog micl-dialog--docked" style="position-anchor:--myanchor" popover aria-labelledby="mytitle">
|
|
147
|
+
<div class="micl-dialog__headline">
|
|
148
|
+
<h2 id="mytitle">Docked dialog</h2>
|
|
149
|
+
</div>
|
|
150
|
+
<div class="micl-dialog__actions">
|
|
151
|
+
<button type="button" class="micl-button-text-s" popovertarget="mydialog" popovertargetaction="hide">Close</button>
|
|
152
|
+
</div>
|
|
153
|
+
</dialog>
|
|
154
|
+
|
|
155
|
+
<button type="button" class="micl-button-outlined-m" popovertarget="mydialog" style="anchor-name:--myanchor">Open Docked Dialog</button>
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
* The dialog places itself below the control element and flips above it if there is insufficient vertical space.
|
|
160
|
+
* A docked dialog fades in and out in place, rather than scaling out from the control element.
|
|
94
161
|
|
|
95
162
|
### Full-screen dialog
|
|
96
|
-
|
|
163
|
+
|
|
164
|
+
A full-screen dialog covers the entire viewport on compact windows (599px and narrower). On wider windows, it behaves like a basic dialog. Use the `micl-dialog--fullscreen` modifier class:
|
|
97
165
|
|
|
98
166
|
```HTML
|
|
99
|
-
<dialog id="mydialog" class="micl-dialog micl-dialog--fullscreen" closedby="
|
|
167
|
+
<dialog id="mydialog" class="micl-dialog micl-dialog--fullscreen" closedby="closerequest" aria-labelledby="mytitle" aria-describedby="mydesc">
|
|
100
168
|
<form method="dialog" class="micl-dialog__headline">
|
|
101
169
|
<button class="micl-dialog__fullscreen micl-iconbutton-standard-s material-symbols-outlined" aria-label="Close">close</button>
|
|
102
170
|
<span class="micl-dialog__icon material-symbols-outlined" aria-hidden="true">person</span>
|
|
@@ -107,44 +175,71 @@ A full-screen dialog covers the entire viewport, primarily on smaller screens. O
|
|
|
107
175
|
<span id="mydesc" class="micl-dialog__supporting-text">This dialog covers the whole screen.</span>
|
|
108
176
|
</div>
|
|
109
177
|
<form method="dialog" class="micl-dialog__actions">
|
|
110
|
-
<button class="micl-button-text-s" autofocus>Cancel</button>
|
|
178
|
+
<button class="micl-button-text-s" value="" autofocus>Cancel</button>
|
|
111
179
|
<button class="micl-button-text-s" value="dosave">Save</button>
|
|
112
180
|
</form>
|
|
113
181
|
</dialog>
|
|
114
182
|
|
|
115
|
-
<button type="button" command="show-modal" commandfor="mydialog">Open Full-Screen Dialog</button>
|
|
183
|
+
<button type="button" class="micl-button-outlined-m" command="show-modal" commandfor="mydialog">Open Full-Screen Dialog</button>
|
|
184
|
+
|
|
116
185
|
```
|
|
117
186
|
|
|
118
|
-
|
|
187
|
+
* In full-screen mode, `micl-dialog__fullscreen` buttons placed directly within the `micl-dialog__headline` become visible. The `micl-dialog__icon` and the standard `micl-dialog__actions` at the bottom are hidden.
|
|
188
|
+
* On wider screens, the layout reverts: `micl-dialog__fullscreen` buttons are hidden, and the standard bottom actions (`micl-dialog__actions`) are displayed.
|
|
189
|
+
* Scrolling within `micl-dialog__content` applies elevation to the header. This effect relies on scroll-driven animations.
|
|
190
|
+
|
|
191
|
+
## Accessibility
|
|
119
192
|
|
|
120
|
-
|
|
193
|
+
* **Prefer a modal dialog.** A dialog opened via `command="show-modal"` (or `dialog.showModal()`) correctly utilizes the top layer, traps focus, and hides background content from screen readers. A `popover` dialog does none of this. Reserve the light-dismiss variant strictly for short, non-critical context.
|
|
194
|
+
* **Always label the dialog.** Point `aria-labelledby` to the primary heading element. If supporting text is present, link it using `aria-describedby`.
|
|
195
|
+
* **Use `role="alertdialog"` exclusively** for dialogs that interrupt the user with urgent messages requiring immediate response.
|
|
196
|
+
* **Maintain keyboard navigation.** `closedby="closerequest"` is the default for a reason. Using `closedby="none"` removes the <kbd>Esc</kbd> key escape route and should only be used when a user *must not* abandon the process (and even then, an explicit close button must remain).
|
|
197
|
+
* **Assign `autofocus`** to the control that should receive focus upon opening, prioritizing the dismissive action over destructive ones. Without it, browsers will focus the dialog container itself.
|
|
198
|
+
* **Provide context for icons.** Give icon-only buttons an `aria-label`, and mark decorative glyphs (like `micl-dialog__icon`) with `aria-hidden="true"`.
|
|
199
|
+
* **Respect motion preferences.** Motion is disabled if the user has requested reduced motion at the OS level; the dialog will appear and disappear instantly.
|
|
121
200
|
|
|
122
201
|
## Theming
|
|
123
|
-
|
|
202
|
+
|
|
203
|
+
Dialogs can be themed using CSS custom properties following the Material Design 3 component-token naming convention. Apply them to a parent element to style its child dialogs.
|
|
124
204
|
|
|
125
205
|
| Custom property | Meaning | Default |
|
|
126
|
-
|
|
127
|
-
| `--md-comp-dialog-min-width` |
|
|
128
|
-
| `--md-comp-dialog-max-width` |
|
|
129
|
-
| `--md-comp-dialog-
|
|
130
|
-
| `--md-comp-dialog-
|
|
131
|
-
| `--md-comp-dialog-
|
|
132
|
-
| `--md-comp-dialog-container-
|
|
133
|
-
| `--md-comp-dialog-container-
|
|
134
|
-
| `--md-comp-dialog-
|
|
135
|
-
| `--md-comp-dialog-
|
|
136
|
-
| `--md-comp-dialog-
|
|
137
|
-
| `--md-comp-dialog-
|
|
138
|
-
| `--md-comp-
|
|
206
|
+
| --- | --- | --- |
|
|
207
|
+
| `--md-comp-dialog-min-width` | Minimum width of a dialog | `280px` |
|
|
208
|
+
| `--md-comp-dialog-max-width` | Maximum width of a dialog | `560px` |
|
|
209
|
+
| `--md-comp-dialog-margin` | Minimum padding between the dialog and the viewport edge | `48px` |
|
|
210
|
+
| `--md-comp-dialog-padding` | Inner padding between the dialog edge and its content | `24px` |
|
|
211
|
+
| `--md-comp-dialog-headline-space` | Vertical spacing between header elements | `16px` |
|
|
212
|
+
| `--md-comp-dialog-container-color` | Dialog background color | `--md-sys-color-surface-container-high` |
|
|
213
|
+
| `--md-comp-dialog-container-shape` | Dialog border radius (corner rounding) | `--md-sys-shape-corner-extra-large` |
|
|
214
|
+
| `--md-comp-dialog-container-elevation` | Dialog shadow depth (elevation) | `--md-sys-elevation-level3` |
|
|
215
|
+
| `--md-comp-dialog-content-color` | Text color for the main content area | `--md-sys-color-on-surface` |
|
|
216
|
+
| `--md-comp-dialog-headline-color` | Text color for the headline | `--md-sys-color-on-surface` |
|
|
217
|
+
| `--md-comp-dialog-subhead-color` | Text color for the sub-header | `--md-sys-color-on-surface` |
|
|
218
|
+
| `--md-comp-dialog-supporting-text-color` | Text color for supporting text | `--md-sys-color-on-surface-variant` |
|
|
219
|
+
| `--md-comp-dialog-icon-color` | Color of the header icon | `--md-sys-color-secondary` |
|
|
220
|
+
| `--md-comp-dialog-icon-size` | Size of the header icon | `--md-sys-icon-size` |
|
|
221
|
+
| `--md-comp-dialog-motion-spatial` | The easing function used when the dialog opens. Uses a spring animation that slightly overshoots the final size before settling | `--md-sys-motion-expressive-fast-spatial` |
|
|
222
|
+
| `--md-comp-dialog-motion-duration` | Animation duration for opening | `650ms` |
|
|
223
|
+
| `--md-comp-dialog-motion-duration-reverse` | Animation duration for closing | `350ms` |
|
|
224
|
+
| `--md-comp-full-screen-dialog-container-color` | Background color of a full-screen dialog | `--md-sys-color-surface` |
|
|
139
225
|
|
|
140
226
|
**Example: Changing the dialog padding**
|
|
141
227
|
|
|
142
228
|
```HTML
|
|
143
|
-
<div style="--md-comp-dialog-padding:16px">
|
|
229
|
+
<div style="--md-comp-dialog-padding: 16px;">
|
|
144
230
|
<dialog class="micl-dialog">
|
|
145
231
|
</dialog>
|
|
146
232
|
</div>
|
|
233
|
+
|
|
147
234
|
```
|
|
148
235
|
|
|
149
236
|
## Compatibility
|
|
150
|
-
|
|
237
|
+
|
|
238
|
+
This component utilizes modern web platform features. Review [Browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/anchor#browser_compatibility) before deploying it in production environments.
|
|
239
|
+
|
|
240
|
+
* **Open/Close Mechanisms:** Relies on [Invoker commands](https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API) (`command` / `commandfor`) and the [Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API). To support legacy browsers, you must implement manual `showModal()` JavaScript calls.
|
|
241
|
+
* **Positioning:** [CSS anchor positioning](https://developer.mozilla.org/en-US/docs/Web/CSS/anchor) dynamically places docked dialogs. In unsupported browsers, light-dismiss dialogs will appear centered rather than scaling out from the control element, and docked dialogs will fall back to the center of the screen.
|
|
242
|
+
* **Animations:** Uses [`@starting-style`](https://developer.mozilla.org/en-US/docs/Web/CSS/@starting-style) and [`transition-behavior: allow-discrete`](https://developer.mozilla.org/en-US/docs/Web/CSS/transition-behavior) for open/close transitions. Without these, the dialog appears instantly.
|
|
243
|
+
* **Dynamic Sizing:** [`interpolate-size`](https://developer.mozilla.org/en-US/docs/Web/CSS/interpolate-size) allows the dialog to animate smoothly to its calculated width. In browsers that do not yet support this (e.g., Firefox 156), the dialog still fades and travels, but assumes its final dimensions immediately.
|
|
244
|
+
* **Advanced Styling:** Utilizes [`:has()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:has), [`:dir()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:dir), and [relative color syntax](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_colors/Relative_colors) for icon layout, right-to-left placement, and backdrop rendering.
|
|
245
|
+
* **Header Elevation:** Uses [Scroll-driven animations](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline/scroll) to elevate the header when content scrolls. Where unsupported, the header remains flat—a purely cosmetic fallback.
|
|
@@ -19,6 +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/tokens' as layout;
|
|
22
23
|
@use '../../styles/elevation';
|
|
23
24
|
@use '../../styles/motion';
|
|
24
25
|
@use '../../styles/shape';
|
|
@@ -32,31 +33,25 @@
|
|
|
32
33
|
@include shape.corner('none');
|
|
33
34
|
@include shape.corner('extra-large');
|
|
34
35
|
|
|
35
|
-
@include statelayer.token('hover-state-layer-opacity');
|
|
36
36
|
@include statelayer.token('backdrop-opacity');
|
|
37
|
-
@include statelayer.property;
|
|
38
37
|
|
|
39
38
|
@include typography.scale('headline-small');
|
|
40
39
|
@include typography.scale('title-large');
|
|
41
40
|
@include typography.scale('title-medium');
|
|
42
41
|
@include typography.scale('body-medium');
|
|
43
42
|
|
|
44
|
-
:root {
|
|
45
|
-
--_dialog-dir-factor: 1;
|
|
46
|
-
}
|
|
47
|
-
:dir(rtl) {
|
|
48
|
-
--_dialog-dir-factor: -1;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
43
|
dialog.micl-dialog {
|
|
52
|
-
--
|
|
53
|
-
--md-comp-dialog-motion-duration
|
|
54
|
-
--md-comp-dialog-motion-duration-reverse
|
|
44
|
+
--_motion-spatial: var(--md-comp-dialog-motion-spatial, #{motion.$md-sys-motion-expressive-fast-spatial});
|
|
45
|
+
--_motion-duration: var(--md-comp-dialog-motion-duration, #{motion.$md-sys-motion-expressive-slow-spatial-duration});
|
|
46
|
+
--_motion-duration-reverse: var(--md-comp-dialog-motion-duration-reverse, #{motion.$md-sys-motion-expressive-fast-spatial-duration});
|
|
55
47
|
|
|
56
|
-
--micl-duration: var(--
|
|
57
|
-
--micl-
|
|
48
|
+
--micl-duration: var(--_motion-duration-reverse);
|
|
49
|
+
--micl-spatial: #{motion.$md-sys-motion-easing-emphasized-accelerate};
|
|
50
|
+
--micl-easing: #{motion.$md-sys-motion-easing-emphasized-accelerate};
|
|
58
51
|
|
|
52
|
+
--_dialog-dir-factor: 1;
|
|
59
53
|
--_dialog-background-color: var(--md-comp-dialog-container-color, var(--md-sys-color-surface-container-high));
|
|
54
|
+
--_margin: var(--md-comp-dialog-margin, 48px);
|
|
60
55
|
--_padding: var(--md-comp-dialog-padding, 24px);
|
|
61
56
|
--_translate: translate(calc(var(--_dialog-dir-factor, 1) * -50%), -50%);
|
|
62
57
|
|
|
@@ -64,48 +59,46 @@ dialog.micl-dialog {
|
|
|
64
59
|
display: none;
|
|
65
60
|
flex-direction: column;
|
|
66
61
|
min-inline-size: var(--md-comp-dialog-min-width, 280px);
|
|
67
|
-
max-inline-size: var(--md-comp-dialog-max-width, 560px);
|
|
68
|
-
max-block-size:
|
|
62
|
+
max-inline-size: min(var(--md-comp-dialog-max-width, 560px), calc(100% - var(--_margin)));
|
|
63
|
+
max-block-size: calc(100dvb - var(--_margin));
|
|
69
64
|
position-anchor: auto;
|
|
70
|
-
inset-block
|
|
71
|
-
inset-inline
|
|
65
|
+
inset-block: anchor(start) auto;
|
|
66
|
+
inset-inline: anchor(start) auto;
|
|
72
67
|
transform: var(--_translate) scale(50%);
|
|
73
68
|
padding: 0;
|
|
74
69
|
margin: 0;
|
|
75
70
|
outline: none;
|
|
76
71
|
border: none;
|
|
77
72
|
border-radius: var(--md-comp-dialog-container-shape, var(--md-sys-shape-corner-extra-large));
|
|
73
|
+
color: var(--md-comp-dialog-content-color, var(--md-sys-color-on-surface));
|
|
78
74
|
background-color: var(--_dialog-background-color);
|
|
79
|
-
background-image: linear-gradient(rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)));
|
|
80
|
-
background-repeat: no-repeat;
|
|
81
75
|
box-shadow: var(--md-comp-dialog-container-elevation, var(--md-sys-elevation-level3));
|
|
82
76
|
opacity: 0;
|
|
83
77
|
overflow: hidden;
|
|
84
78
|
interpolate-size: allow-keywords;
|
|
85
79
|
transition:
|
|
86
|
-
inset-block-start var(--micl-duration)
|
|
87
|
-
inset-inline-start var(--micl-duration)
|
|
88
|
-
inline-size var(--micl-duration)
|
|
89
|
-
block-size var(--micl-duration)
|
|
90
|
-
transform var(--micl-duration)
|
|
91
|
-
opacity var(--micl-duration)
|
|
80
|
+
inset-block-start var(--micl-duration) var(--micl-easing),
|
|
81
|
+
inset-inline-start var(--micl-duration) var(--micl-easing),
|
|
82
|
+
inline-size var(--micl-duration) var(--micl-spatial),
|
|
83
|
+
block-size var(--micl-duration) var(--micl-spatial),
|
|
84
|
+
transform var(--micl-duration) var(--micl-spatial),
|
|
85
|
+
opacity var(--micl-duration) linear,
|
|
92
86
|
overlay var(--micl-duration) linear allow-discrete,
|
|
93
|
-
display var(--micl-duration) linear allow-discrete
|
|
94
|
-
--statelayer-opacity var(--md-comp-dialog-motion-duration) linear;
|
|
87
|
+
display var(--micl-duration) linear allow-discrete;
|
|
95
88
|
|
|
96
89
|
@starting-style {
|
|
97
90
|
block-size: fit-content;
|
|
98
91
|
inline-size: fit-content;
|
|
99
|
-
inset-block-start: anchor(start);
|
|
100
|
-
inset-inline-start: anchor(start);
|
|
101
|
-
opacity: 0;
|
|
102
|
-
transform: var(--_translate) scale(50%);
|
|
103
92
|
}
|
|
104
93
|
|
|
94
|
+
&:dir(rtl) {
|
|
95
|
+
--_dialog-dir-factor: -1;
|
|
96
|
+
}
|
|
105
97
|
&:popover-open,
|
|
106
98
|
&[open] {
|
|
107
|
-
--micl-duration: var(--
|
|
108
|
-
--micl-
|
|
99
|
+
--micl-duration: var(--_motion-duration);
|
|
100
|
+
--micl-spatial: var(--_motion-spatial);
|
|
101
|
+
--micl-easing: #{motion.$md-sys-motion-easing-emphasized};
|
|
109
102
|
|
|
110
103
|
display: flex;
|
|
111
104
|
inset-block-start: 50%;
|
|
@@ -128,22 +121,14 @@ dialog.micl-dialog {
|
|
|
128
121
|
inset-block-start: 50%;
|
|
129
122
|
inset-inline-start: 50%;
|
|
130
123
|
}
|
|
131
|
-
|
|
132
|
-
&:popover-open,
|
|
133
|
-
&[open] {
|
|
134
|
-
@starting-style {
|
|
135
|
-
inset-block-start: 50%;
|
|
136
|
-
inset-inline-start: 50%;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
124
|
}
|
|
140
125
|
|
|
141
126
|
&::backdrop {
|
|
142
127
|
background-color: rgba(0, 0, 0, 0);
|
|
143
128
|
transition:
|
|
144
|
-
background-color var(--
|
|
145
|
-
overlay var(--
|
|
146
|
-
display var(--
|
|
129
|
+
background-color var(--micl-duration) linear,
|
|
130
|
+
overlay var(--micl-duration) linear allow-discrete,
|
|
131
|
+
display var(--micl-duration) linear allow-discrete;
|
|
147
132
|
}
|
|
148
133
|
&[open]::backdrop {
|
|
149
134
|
background-color: rgba(0, 0, 0, var(--md-sys-state-backdrop-opacity, 32%));
|
|
@@ -157,7 +142,10 @@ dialog.micl-dialog {
|
|
|
157
142
|
inset-block: anchor(end) auto;
|
|
158
143
|
inset-inline: anchor(start) auto;
|
|
159
144
|
transform: none;
|
|
160
|
-
transition:
|
|
145
|
+
transition:
|
|
146
|
+
opacity var(--micl-duration) linear,
|
|
147
|
+
overlay var(--micl-duration) linear allow-discrete,
|
|
148
|
+
display var(--micl-duration) linear allow-discrete;
|
|
161
149
|
position-try-fallbacks: flip-block;
|
|
162
150
|
}
|
|
163
151
|
|
|
@@ -173,6 +161,7 @@ dialog.micl-dialog {
|
|
|
173
161
|
|
|
174
162
|
&:has(> .micl-dialog__icon) {
|
|
175
163
|
align-items: center;
|
|
164
|
+
text-align: center;
|
|
176
165
|
}
|
|
177
166
|
.micl-dialog__icon {
|
|
178
167
|
--_icon-size: var(--md-comp-dialog-icon-size, var(--md-sys-icon-size, 24px));
|
|
@@ -192,11 +181,10 @@ dialog.micl-dialog {
|
|
|
192
181
|
.micl-dialog__subhead {
|
|
193
182
|
@include typography.title-medium;
|
|
194
183
|
|
|
195
|
-
padding-inline: var(--_padding);
|
|
196
184
|
overflow: hidden;
|
|
197
185
|
text-overflow: ellipsis;
|
|
198
186
|
white-space: nowrap;
|
|
199
|
-
color: var(--md-sys-color-on-surface)
|
|
187
|
+
color: var(--md-comp-dialog-subhead-color, var(--md-sys-color-on-surface));
|
|
200
188
|
}
|
|
201
189
|
&:has(+ .micl-dialog__actions) {
|
|
202
190
|
padding-block-end: 0;
|
|
@@ -218,21 +206,22 @@ dialog.micl-dialog {
|
|
|
218
206
|
justify-content: flex-end;
|
|
219
207
|
column-gap: 8px;
|
|
220
208
|
padding: var(--_padding);
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@media (prefers-reduced-motion: reduce) {
|
|
212
|
+
--_motion-duration: 0ms;
|
|
213
|
+
--_motion-duration-reverse: 0ms;
|
|
226
214
|
}
|
|
227
215
|
}
|
|
228
216
|
|
|
229
217
|
dialog.micl-dialog.micl-dialog--fullscreen {
|
|
230
|
-
@media (max-width:
|
|
218
|
+
@media (max-width: layout.$md-sys-breakpoint-compact-max) {
|
|
231
219
|
--_dialog-background-color: var(--md-comp-full-screen-dialog-container-color, var(--md-sys-color-surface));
|
|
232
220
|
|
|
233
|
-
inline-size:
|
|
234
|
-
block-size:
|
|
235
|
-
max-inline-size:
|
|
221
|
+
inline-size: 100%;
|
|
222
|
+
block-size: 100dvb;
|
|
223
|
+
max-inline-size: 100%;
|
|
224
|
+
max-block-size: 100dvb;
|
|
236
225
|
border-radius: var(--md-sys-shape-corner-none, 0px);
|
|
237
226
|
box-shadow: var(--md-sys-elevation-level0);
|
|
238
227
|
timeline-scope: --headlineTimeline;
|
|
@@ -243,6 +232,7 @@ dialog.micl-dialog.micl-dialog--fullscreen {
|
|
|
243
232
|
block-size: 56px;
|
|
244
233
|
flex-direction: row;
|
|
245
234
|
align-items: center;
|
|
235
|
+
text-align: start;
|
|
246
236
|
gap: 8px;
|
|
247
237
|
padding-block: 4px;
|
|
248
238
|
padding-inline: 8px 16px;
|
|
@@ -262,26 +252,24 @@ dialog.micl-dialog.micl-dialog--fullscreen {
|
|
|
262
252
|
white-space: nowrap;
|
|
263
253
|
}
|
|
264
254
|
.micl-dialog__icon {
|
|
265
|
-
display:none;
|
|
255
|
+
display: none;
|
|
266
256
|
}
|
|
267
257
|
}
|
|
268
258
|
.micl-dialog__content {
|
|
269
259
|
scroll-timeline: --headlineTimeline block;
|
|
270
|
-
scroll-timeline: --headlineTimeline vertical;
|
|
271
260
|
}
|
|
272
261
|
.micl-dialog__actions {
|
|
273
262
|
display: none;
|
|
274
|
-
opacity: 0;
|
|
275
263
|
}
|
|
276
264
|
}
|
|
277
|
-
@media (min-width:
|
|
265
|
+
@media (min-width: layout.$md-sys-breakpoint-medium-min) {
|
|
278
266
|
.micl-dialog__fullscreen {
|
|
279
267
|
display: none;
|
|
280
268
|
}
|
|
281
269
|
}
|
|
282
270
|
}
|
|
283
271
|
|
|
284
|
-
@media (max-width:
|
|
272
|
+
@media (max-width: layout.$md-sys-breakpoint-compact-max) {
|
|
285
273
|
body:has(dialog.micl-dialog.micl-dialog--fullscreen:popover-open) {
|
|
286
274
|
overflow-y: hidden;
|
|
287
275
|
}
|
|
@@ -65,8 +65,8 @@ $iconbuttons: ':is([class*="micl-iconbutton-standard-"], [class*="micl-iconbutto
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
#{$iconbuttons} {
|
|
68
|
-
--md-comp-icon-button-motion-effects
|
|
69
|
-
--md-comp-icon-button-motion-duration
|
|
68
|
+
--_motion-effects: var(--md-comp-icon-button-motion-effects, #{motion.$md-sys-motion-expressive-fast-spatial});
|
|
69
|
+
--_motion-duration: var(--md-comp-icon-button-motion-duration, #{motion.$md-sys-motion-expressive-fast-spatial-duration});
|
|
70
70
|
--micl-ripple: 1;
|
|
71
71
|
|
|
72
72
|
box-sizing: border-box;
|
|
@@ -96,10 +96,10 @@ $iconbuttons: ':is([class*="micl-iconbutton-standard-"], [class*="micl-iconbutto
|
|
|
96
96
|
font-variation-settings: 'FILL' 0;
|
|
97
97
|
cursor: pointer;
|
|
98
98
|
transition:
|
|
99
|
-
border-radius var(--
|
|
100
|
-
font-variation-settings var(--
|
|
99
|
+
border-radius var(--_motion-duration) var(--_motion-effects),
|
|
100
|
+
font-variation-settings var(--_motion-duration) linear,
|
|
101
101
|
background-size 0ms,
|
|
102
|
-
--statelayer-opacity var(--
|
|
102
|
+
--statelayer-opacity var(--_motion-duration) linear;
|
|
103
103
|
|
|
104
104
|
&:disabled {
|
|
105
105
|
box-shadow: var(--md-sys-elevation-level0);
|
|
@@ -165,8 +165,8 @@ $unselected: ':not(:checked, :has(input[type=checkbox]:checked), #{$open-accordi
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
.micl-list {
|
|
168
|
-
--md-comp-list-motion-effects
|
|
169
|
-
--md-comp-list-motion-duration
|
|
168
|
+
--_list-motion-effects: var(--md-comp-list-motion-effects, #{motion.$md-sys-motion-expressive-fast-spatial});
|
|
169
|
+
--_list-motion-duration: var(--md-comp-list-motion-duration, #{motion.$md-sys-motion-expressive-default-effects-duration});
|
|
170
170
|
--md-comp-accordion-motion-spatial: #{motion.$md-sys-motion-expressive-default-spatial};
|
|
171
171
|
--md-comp-accordion-motion-duration: #{motion.$md-sys-motion-expressive-default-spatial-duration};
|
|
172
172
|
--md-comp-divider-space: 0.5px;
|
|
@@ -269,9 +269,9 @@ $unselected: ':not(:checked, :has(input[type=checkbox]:checked), #{$open-accordi
|
|
|
269
269
|
background-size: 0%, 100%;
|
|
270
270
|
list-style: none;
|
|
271
271
|
transition:
|
|
272
|
-
border-radius var(--
|
|
272
|
+
border-radius var(--_list-motion-duration) var(--_list-motion-effects),
|
|
273
273
|
background-size 0ms,
|
|
274
|
-
--statelayer-opacity var(--
|
|
274
|
+
--statelayer-opacity var(--_list-motion-duration) linear;
|
|
275
275
|
-webkit-tap-highlight-color: transparent;
|
|
276
276
|
|
|
277
277
|
&:first-of-type {
|
|
@@ -407,11 +407,11 @@ $unselected: ':not(:checked, :has(input[type=checkbox]:checked), #{$open-accordi
|
|
|
407
407
|
font-size: var(--md-comp-list-item-leading-icon-expressive-size, 20px);
|
|
408
408
|
font-variation-settings: 'FILL' 0;
|
|
409
409
|
color: var(--_leading-icon-color);
|
|
410
|
-
transition: font-variation-settings var(--
|
|
410
|
+
transition: font-variation-settings var(--_list-motion-duration) linear;
|
|
411
411
|
|
|
412
412
|
&.micl-list-item__icon--expander {
|
|
413
413
|
transform: rotate(0deg);
|
|
414
|
-
transition: transform var(--
|
|
414
|
+
transition: transform var(--_list-motion-duration) linear;
|
|
415
415
|
}
|
|
416
416
|
}
|
|
417
417
|
.micl-list-item__text ~ .micl-list-item__icon {
|