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.
Files changed (61) hide show
  1. package/components/appbar/index.scss +1 -1
  2. package/components/badge/README.md +43 -12
  3. package/components/badge/index.scss +15 -21
  4. package/components/bottomsheet/README.md +53 -22
  5. package/components/bottomsheet/index.scss +61 -44
  6. package/components/button/_shared.scss +6 -6
  7. package/components/card/README.md +1 -1
  8. package/components/checkbox/index.scss +10 -10
  9. package/components/datepicker/README.md +184 -59
  10. package/components/datepicker/index.scss +84 -20
  11. package/components/dialog/README.md +151 -56
  12. package/components/dialog/index.scss +50 -62
  13. package/components/iconbutton/index.scss +5 -5
  14. package/components/list/index.scss +6 -6
  15. package/components/menu/index.scss +13 -13
  16. package/components/navigationbar/index.scss +7 -1
  17. package/components/navigationrail/index.scss +27 -22
  18. package/components/radio/index.scss +8 -8
  19. package/components/select/index.scss +3 -3
  20. package/components/sidesheet/README.md +90 -37
  21. package/components/sidesheet/index.scss +51 -41
  22. package/components/slider/README.md +35 -9
  23. package/components/slider/index.scss +182 -153
  24. package/components/snackbar/README.md +43 -25
  25. package/components/snackbar/index.scss +22 -27
  26. package/components/stepper/index.scss +4 -4
  27. package/components/switch/index.scss +13 -13
  28. package/components/timepicker/README.md +131 -55
  29. package/components/timepicker/index.scss +46 -25
  30. package/dist/appbar.css +1 -1
  31. package/dist/badge.css +1 -1
  32. package/dist/bottomsheet.css +1 -1
  33. package/dist/bottomsheet.js +1 -1
  34. package/dist/button.css +1 -1
  35. package/dist/checkbox.css +1 -1
  36. package/dist/chip.css +1 -1
  37. package/dist/datepicker.css +1 -1
  38. package/dist/datepicker.js +1 -1
  39. package/dist/dialog.css +1 -1
  40. package/dist/iconbutton.css +1 -1
  41. package/dist/layout.css +1 -1
  42. package/dist/list.css +1 -1
  43. package/dist/menu.css +1 -1
  44. package/dist/micl.css +1 -1
  45. package/dist/micl.js +1 -1
  46. package/dist/navigationbar.css +1 -1
  47. package/dist/navigationrail.css +1 -1
  48. package/dist/radio.css +1 -1
  49. package/dist/select.css +1 -1
  50. package/dist/sidesheet.css +1 -1
  51. package/dist/slider.css +1 -1
  52. package/dist/slider.js +1 -1
  53. package/dist/snackbar.css +1 -1
  54. package/dist/snackbar.js +1 -1
  55. package/dist/stepper.css +1 -1
  56. package/dist/switch.css +1 -1
  57. package/dist/timepicker.css +1 -1
  58. package/dist/timepicker.js +1 -1
  59. package/foundations/layout/_tokens.scss +55 -0
  60. package/foundations/layout/index.scss +2 -35
  61. package/package.json +1 -1
@@ -1,32 +1,60 @@
1
1
  # Date picker
2
- This component implements the [Material Design 3 Expressive Date picker](https://m3.material.io/components/date-pickers/overview) design. It allows users to select a date using either a text input or a calendar interface.
2
+
3
+ This component implements the [Material Design 3 Expressive Date picker](https://m3.material.io/components/date-pickers/overview) specification. It allows users to select a date using either a text input or a calendar interface.
3
4
 
4
5
  ## Basic Usage
5
6
 
6
7
  ### HTML
7
- The Date Picker component is an extension of the [**Dialog** component](../dialog/README.md). To create a basic date picker, use a `<dialog>` element with both `micl-dialog` and `micl-datepicker` classes.
8
+ The Date picker component is an extension of the [**Dialog** component](../dialog/README.md). To create a basic date picker, use a `<dialog>` element with both the `micl-dialog` and `micl-datepicker` classes.
8
9
 
9
10
  ```HTML
10
- <dialog id="mydatepicker" class="micl-dialog micl-datepicker" closedby="closerequest" aria-labelledby="mytitle">
11
+ <dialog
12
+ id="mydatepicker"
13
+ class="micl-dialog micl-datepicker"
14
+ closedby="closerequest"
15
+ aria-labelledby="mysupport"
16
+ >
11
17
  <form method="dialog">
12
18
  <div class="micl-dialog__headline">
13
- <h2 id="mytitle">Enter date</h2>
14
- <span class="micl-dialog__supporting-text">Select date</span>
15
- <button type="button" id="btn" class="micl-datepicker__inputmode micl-iconbutton-standard-s micl-button--toggle material-symbols-outlined" commandfor="btn" command="--micl-toggle" data-miclicon="edit" data-micliconselected="calendar_today"></button>
19
+ <h2>Enter date</h2>
20
+ <span id="mysupport" class="micl-dialog__supporting-text">Select date</span>
21
+ <button type="button" id="btn"
22
+ class="micl-datepicker__inputmode micl-iconbutton-standard-s micl-button--toggle material-symbols-outlined"
23
+ commandfor="btn"
24
+ command="--micl-toggle"
25
+ aria-pressed="false"
26
+ aria-label="Switch between calendar and text input"
27
+ data-miclicon="edit"
28
+ data-micliconselected="calendar_today"
29
+ ></button>
16
30
  <hr class="micl-divider">
31
+
17
32
  <div class="micl-datepicker__month-selector">
18
- <button type="button" class="micl-datepicker__previous micl-iconbutton-standard-xs material-symbols-outlined" aria-label="Previous month">chevron_left</button>
33
+ <button type="button"
34
+ class="micl-datepicker__previous micl-iconbutton-standard-xs material-symbols-outlined"
35
+ aria-label="Previous month"
36
+ >chevron_backward</button>
19
37
  <button type="button" class="micl-datepicker__month micl-button-text-xs">
20
38
  <span class="micl-button__icon material-symbols-outlined" aria-hidden="true">arrow_drop_down</span>
21
39
  </button>
22
- <button type="button" class="micl-datepicker__next micl-iconbutton-standard-xs material-symbols-outlined" aria-label="Next month">chevron_right</button>
40
+ <button type="button"
41
+ class="micl-datepicker__next micl-iconbutton-standard-xs material-symbols-outlined"
42
+ aria-label="Next month"
43
+ >chevron_forward</button>
23
44
  </div>
45
+
24
46
  <div class="micl-datepicker__year-selector">
25
- <button type="button" class="micl-datepicker__previous micl-iconbutton-standard-xs material-symbols-outlined" aria-label="Previous year">chevron_left</button>
47
+ <button type="button"
48
+ class="micl-datepicker__previous micl-iconbutton-standard-xs material-symbols-outlined"
49
+ aria-label="Previous year"
50
+ >chevron_backward</button>
26
51
  <button type="button" class="micl-datepicker__year micl-button-text-xs">
27
52
  <span class="micl-button__icon material-symbols-outlined" aria-hidden="true">arrow_drop_down</span>
28
53
  </button>
29
- <button type="button" class="micl-datepicker__next micl-iconbutton-standard-xs material-symbols-outlined" aria-label="Next year">chevron_right</button>
54
+ <button type="button"
55
+ class="micl-datepicker__next micl-iconbutton-standard-xs material-symbols-outlined"
56
+ aria-label="Next year"
57
+ >chevron_forward</button>
30
58
  </div>
31
59
  </div>
32
60
 
@@ -37,7 +65,8 @@ The Date Picker component is an extension of the [**Dialog** component](../dialo
37
65
  <div class="micl-datepicker__input micl-textfield-outlined">
38
66
  <label for="mydate">Date</label>
39
67
  <input type="text" id="mydate">
40
- </div>
68
+ <span class="micl-textfield__supporting-text"></span>
69
+ </div>
41
70
  </div>
42
71
 
43
72
  <div class="micl-dialog__actions">
@@ -49,7 +78,8 @@ The Date Picker component is an extension of the [**Dialog** component](../dialo
49
78
  ```
50
79
 
51
80
  ### CSS
52
- Import both the date picker and the dialog styles into your project:
81
+
82
+ Import the required component styles into your project:
53
83
 
54
84
  ```CSS
55
85
  @use "material-inspired-component-library/dist/dialog";
@@ -60,77 +90,118 @@ Import both the date picker and the dialog styles into your project:
60
90
  @use "material-inspired-component-library/dist/datepicker";
61
91
  ```
62
92
 
63
- Or import all MICL styles:
93
+ Alternatively, import all MICL styles at once:
94
+
64
95
  ```CSS
65
96
  @use "material-inspired-component-library/styles";
66
97
  ```
67
98
 
68
99
  ### JavaScript
100
+
69
101
  This component requires JavaScript to function:
70
102
 
71
103
  ```JavaScript
72
104
  import micl from "material-inspired-component-library/dist/micl";
73
105
  ```
74
- When loading individual JavaScript files, also load `dist/textfield` — it wires the input field that opens the picker.
75
106
 
76
- This will initialize any Date picker component, including those that will be added to the DOM later on.
107
+ Importing the script initializes all Date picker components on the page, including those dynamically added to the DOM later.
108
+
109
+ If you are loading individual JavaScript files, be sure to also load `dist/textfield` — it wires the input field that triggers the picker.
77
110
 
78
111
  ### Live Demo
79
- A live example of the [Date picker component](https://henkpb.github.io/micl/datepicker.html) is available to interact with.
80
112
 
81
- ## Variants
82
- Because the Date picker component relies on the Dialog component, it utilizes the same utility classes for content structure. Refer to the [Dialog component documentation](../dialog/README.md) for structural details.
113
+ A live interactive demo of the [Date picker component](https://henkpb.github.io/micl/datepicker.html) is available.
114
+
115
+ ## Anatomy
83
116
 
84
- ### Date Picker Structure
85
117
  For the picker to function, the `micl-dialog__content` area **must** contain the `<div class="micl-datepicker__calendars">` container. This holds the month-based calendars.
86
118
 
87
119
  Additionally, the content area may contain:
88
120
 
89
- - A container for selecting a year: `<div class="micl-datepicker__years">`
121
+ * A container for selecting a year: `<div class="micl-datepicker__years">`
122
+ * A container for selecting a month: `<div class="micl-datepicker__months">`
123
+ * A [Text field component](../textfield/README.md) with the `micl-datepicker__input` class for manual date entry.
90
124
 
91
- - A container for selecting a month: `<div class="micl-datepicker__months">`
125
+ The `micl-dialog__headline` area may contain:
92
126
 
93
- - A [Text field component](../textfield/README.md) with the `micl-datepicker__input` class for manual date entry.
127
+ * **Title**: A heading element (e.g., `<h2>`) displaying the selected date. Because its content is dynamically replaced whenever the selection changes, ensure the dialog's `aria-labelledby` attribute points to the supporting label instead.
128
+ * **Supporting label**: A text element with the class `micl-dialog__supporting-text`.
129
+ * **Month selector**: A container with a [Button component](../button/README.md) flanked by two [Icon button components](../iconbutton/README.md):
130
+ * `micl-datepicker__month`: Opens the month selection container.
131
+ * `micl-datepicker__previous`: Navigates to the previous month.
132
+ * `micl-datepicker__next`: Navigates to the next month.
94
133
 
95
- The `micl-dialog__headline` area may contain:
96
134
 
97
- - **Title**: A heading element (e.g., `<h2>`) to display the selected date.
135
+ * **Year selector**: A container with a [Button component](../button/README.md) flanked by two [Icon button components](../iconbutton/README.md):
136
+ * `micl-datepicker__year`: Opens the year selection container.
137
+ * `micl-datepicker__previous`: Navigates to the previous year.
138
+ * `micl-datepicker__next`: Navigates to the next year.
98
139
 
99
- - **Supporting label**: A text element with the class `micl-dialog__supporting-text`.
140
+ Any structural item not required for your specific implementation may be omitted.
100
141
 
101
- - **Month selector**: A container with three [Icon button components](../iconbutton/README.md):
102
- - `micl-datepicker__month`: Opens the month selection container.
103
- - `micl-datepicker__previous`: Navigates to the previous month.
104
- - `micl-datepicker__next`: Navigates to the next month.
142
+ ## Variants
105
143
 
106
- - **Year selector**: A container with three [Icon button components](../iconbutton/README.md):
107
- - `micl-datepicker__year`: Opens the year selection container.
108
- - `micl-datepicker__previous`: Navigates to the previous year.
109
- - `micl-datepicker__next`: Navigates to the next year.
144
+ Because the Date picker relies on the Dialog component, it utilizes the same utility classes for content structure. Refer to the [Dialog component documentation](../dialog/README.md) for structural details.
110
145
 
111
- Any item not required for your implementation may be omitted.
146
+ ### Selectable Dates
147
+
148
+ The `min` and `max` attributes of the invoking input field limit the selection. Dates outside this range are rendered in a disabled state; they cannot be selected, navigated to, or typed in. Additionally, calendar navigation arrows will stop at the first and last months containing a selectable date.
149
+
150
+ Days from neighbouring months that pad the first and last weeks of the calendar are displayed in the same disabled state. These elements carry the `micl-datepicker__outside` class, allowing you to hide them completely via CSS if preferred.
151
+
152
+ ### Input Mode Switching
112
153
 
113
- #### Input Mode Switching
114
154
  To allow users to toggle between the calendar view and the manual date input, add an icon button to the `micl-dialog__headline` area:
115
155
 
116
- - Class: `micl-datepicker__inputmode`
117
- - Data Attribute: `data-miclicon="edit"` (defines the icon to show).
118
- - Data Attribute: `data-micliconselected="calendar_today"` (defines the icon to show when toggled).
156
+ * Class: `micl-datepicker__inputmode`
157
+ * Data Attribute: `data-miclicon="edit"` (defines the default icon).
158
+ * Data Attribute: `data-micliconselected="calendar_today"` (defines the toggled icon).
159
+
160
+ Since this is an icon-only button, it requires an `aria-label`. You must also include `aria-pressed="false"`. The self-targeting `--micl-toggle` command will automatically keep this attribute in sync with the active mode.
161
+
162
+ The text field accepts dates in the user's localized format and formats the entry while it is typed. Add a `micl-textfield__supporting-text` element, and the component will automatically populate it with the localized format string (e.g., `DD.MM.YYYY`, `MM/DD/YYYY`) to serve as a hint:
163
+
164
+ ```HTML
165
+ <div class="micl-datepicker__input micl-textfield-outlined">
166
+ <label for="mydate">Date</label>
167
+ <input type="text" id="mydate">
168
+ <span class="micl-textfield__supporting-text"></span>
169
+ </div>
170
+ ```
171
+
172
+ An entry that is not a valid date, or one that falls outside the allowed `min` and `max` range, leaves the text field in an error state and does not change the selection. The invalid entry is preserved for correction. If the user confirms anyway, the picker commits the last valid selection.
173
+
174
+ ## Integration
119
175
 
120
- ### Integration
121
176
  You can trigger the Date picker component from standard input fields or buttons.
122
177
 
123
- #### Connecting to an Input Field
178
+ ### Connecting to an Input Field
179
+
124
180
  To replace the browser's native date picker, add the `data-datepicker` attribute to an `<input>` element. The value of this attribute must match the `id` of your Date picker dialog.
125
181
 
126
182
  ```HTML
127
183
  <input type="date" data-datepicker="mydatepicker" value="2025-12-02">
128
184
  ```
129
185
 
130
- - **Behavior**: Clicking the input opens the picker initialized with the input's current value.
131
- - **Reusability**: Multiple input fields can target the same Date picker component ID. The picker will automatically update to reflect the date of the specific input field engaged by the user.
186
+ * **Behavior**: Clicking the input opens the picker, initialized with the input's current value.
187
+ * **Reusability**: Multiple input fields can target the same Date picker component ID. The picker automatically updates to reflect the date of the specific input field currently engaged by the user.
132
188
 
133
- **Docked Positioning** By default, the Date picker opens in the center of the screen. To anchor it to the input field, use the `micl-dialog--docked` class and CSS Anchor positioning.
189
+ When the invoking input is wrapped in a [Text field component](../textfield/README.md), add an empty `micl-textfield__supporting-text` element to spell out the date format below the field. The component fills this element with the locale's date format, matching the one it uses in its own input view:
190
+
191
+ ```HTML
192
+ <div class="micl-textfield-outlined">
193
+ <label for="mytextfield">Start date</label>
194
+ <input type="date" id="mytextfield" data-datepicker="mydatepicker" value="2025-12-02">
195
+ <span class="micl-textfield__supporting-text"></span>
196
+ </div>
197
+
198
+ ```
199
+
200
+ *(Note: If you provide custom text content within this element, the component will not overwrite it.)*
201
+
202
+ #### Docked Positioning
203
+
204
+ By default, the Date picker opens in the center of the screen. To anchor it to the input field, use the `micl-dialog--docked` class and CSS Anchor positioning. A docked date picker still opens as a modal dialog — unlike a standard docked [Dialog](../dialog/README.md), it cannot be a popover (for the reason detailed in the important note below).
134
205
 
135
206
  ```HTML
136
207
  <dialog id="mydatepicker" class="micl-dialog micl-dialog--docked micl-datepicker" style="position-anchor:--myanchor">
@@ -139,47 +210,68 @@ To replace the browser's native date picker, add the `data-datepicker` attribute
139
210
  <label for="mytextfield">Start date</label>
140
211
  <input type="date" id="mytextfield" data-datepicker="mydatepicker">
141
212
  </div>
213
+
142
214
  ```
143
215
 
144
- #### Connecting to a Button
145
- You can trigger the picker from a button using the standard `popovertarget` attribute.
216
+ ### Connecting to a Button
217
+
218
+ You can trigger the picker from a button using the standard `command` attribute.
146
219
 
147
220
  ```HTML
148
- <button type="button" class="micl-button-text-m" popovertarget="mydatepicker" value="2026-01-23">23.01.2026</button>
221
+ <button
222
+ type="button"
223
+ class="micl-button-text-m"
224
+ command="show-modal"
225
+ commandfor="mydatepicker"
226
+ value="2026-01-23"
227
+ >23.01.2026</button>
149
228
  ```
150
229
 
151
- - **Behavior**: The Date picker reads from and writes to the button's value attribute.
152
- - **Formatting**: The component automatically updates the button's text content with the selected date, formatted according to the user's locale.
230
+ * **Behavior**: The Date picker reads from and writes to the button's `value` attribute.
231
+ * **Formatting**: The component automatically updates the button's text content with the selected date, formatted according to the user's locale.
232
+
233
+ > [!IMPORTANT]
234
+ > Because a date picker requires explicit user confirmation, it must function as a modal dialog. Opening it as a popover (`popovertarget`) is **not supported**. A `<dialog popover>` is not closed by `<form method="dialog">` and does not fire the standard `close` event required by the component to write the selected date back to the invoker.
153
235
 
154
236
  ## Date Range Selection
237
+
155
238
  Add the `micl-datepicker--range` class to the dialog to let users select a range of dates instead of a single date:
156
239
 
157
240
  ```HTML
158
- <dialog id="myrangepicker" class="micl-dialog micl-datepicker micl-datepicker--range" closedby="closerequest">
241
+ <dialog class="micl-dialog micl-datepicker micl-datepicker--range" closedby="closerequest">
159
242
  ```
160
243
 
161
- The first selected date becomes the start of the range and the second one its end. Selecting a date before the start moves the start, and any selection after a completed range starts a new one. Confirming before an end date has been chosen commits a single-day range.
244
+ The first selected date becomes the start of the range, and the second selection defines the end. Selecting a date *before* the current start date moves the start, and any selection made after a completed range resets the picker to start a new range. Confirming before an end date is chosen commits a single-day range.
162
245
 
163
246
  ### Connecting a Pair of Input Fields
164
- Connect two date input fields — both referring to the picker in their `data-datepicker` attribute — and identify the field holding the end date in the `data-miclrangeto` attribute of the start field:
247
+
248
+ Connect two date input fields — both referencing the picker in their `data-datepicker` attributes — and identify the end-date field using the `data-miclrangeto` attribute on the start-date field:
165
249
 
166
250
  ```HTML
167
251
  <input type="date" id="from" data-datepicker="myrangepicker" data-miclrangeto="to">
168
252
  <input type="date" id="to" data-datepicker="myrangepicker">
169
253
  ```
170
254
 
171
- - **Behavior**: Clicking either field opens the picker with the range loaded from both fields; reversed values are swapped. Confirming writes both fields and fires their change-events.
172
- - **Limits**: The earliest allowed date is taken from the `min` attribute of the start field, the latest from the `max` attribute of the end field.
255
+ * **Behavior**: Clicking either field opens the picker with the range loaded from both fields. If the start date is after the end date, the values are automatically swapped. Confirming the selection updates both fields and fires their respective `change` events.
256
+ * **Limits**: The earliest allowed date is derived from the `min` attribute of the start field; the latest allowed date is derived from the `max` attribute of the end field.
173
257
 
174
258
  ### Connecting to a Button
175
- A single button invoker holds the range in its value attribute as an ISO 8601 time interval. The component updates the button's text content with the localized range:
259
+
260
+ A single button invoker holds the range in its `value` attribute as an ISO 8601 time interval. The component updates the button's text content with the localized range string:
176
261
 
177
262
  ```HTML
178
- <button type="button" class="micl-button-text-m" popovertarget="myrangepicker" value="2026-01-23/2026-02-06">23.01.2026 – 06.02.2026</button>
263
+ <button
264
+ type="button"
265
+ class="micl-button-text-m"
266
+ command="show-modal"
267
+ commandfor="myrangepicker"
268
+ value="2026-01-23/2026-02-06"
269
+ >23.01.2026 – 06.02.2026</button>
179
270
  ```
180
271
 
181
272
  ### Text Input Mode
182
- In range mode, the manual input area holds two [Text field components](../textfield/README.md) instead of being one itself:
273
+
274
+ In range mode, the manual input area contains two [Text field components](../textfield/README.md) instead of one:
183
275
 
184
276
  ```HTML
185
277
  <div class="micl-datepicker__input">
@@ -194,13 +286,36 @@ In range mode, the manual input area holds two [Text field components](../textfi
194
286
  </div>
195
287
  ```
196
288
 
197
- Entering a start date that lies after the end date swaps the two. The fields cannot be emptied: to discard the end of a range, return to the calendar view and start a new range by selecting any date.
289
+ Entering a start date that occurs after the end date will swap the two inputs. These fields cannot be fully cleared; to discard the end of a range, the user must return to the calendar view and start a new range by clicking any date.
290
+
291
+ ## Accessibility
292
+
293
+ * **Dialog labeling:** Always label the dialog. Point `aria-labelledby` at the supporting label, not at the headline. The headline holds the current selection and is rewritten on every change (the component marks it `aria-live="polite"` so assistive technologies announce new selections).
294
+ * **Grid structure:** The calendar is exposed as a `grid` of `row`s, with the weekday labels acting as `columnheader`s. Every date is a `gridcell` carrying its full, localized date as an `aria-label`. Selected dates are `aria-selected`, today's date is `aria-current="date"`, and dates outside the allowed range are `aria-disabled`.
295
+ * **Keyboard navigation:** The calendar utilizes a single tab stop and moves focus between dates with the arrow keys. Dates from neighboring months and those outside the allowed range are safely skipped.
296
+
297
+ | Key | Action |
298
+ | --- | --- |
299
+ | <kbd>←</kbd> <kbd>→</kbd> | Move to the previous or next day (mirrored in a right-to-left context) |
300
+ | <kbd>↑</kbd> <kbd>↓</kbd> | Move to the same weekday of the previous or next week |
301
+ | <kbd>Home</kbd> <kbd>End</kbd> | Move to the first or last day of the week |
302
+ | <kbd>Enter</kbd> <kbd>Space</kbd> | Select the focused date |
303
+ | <kbd>PageUp</kbd> <kbd>PageDown</kbd> | Show the next or previous month |
304
+ | <kbd>Shift</kbd> + <kbd>PageUp</kbd> / <kbd>PageDown</kbd> | Show the next or previous year |
305
+ | <kbd>Shift</kbd> + <kbd>M</kbd> / <kbd>Y</kbd> | Open the month or year selection |
306
+ | <kbd>Esc</kbd> | Close the picker without changing the invoker |
307
+
308
+ Moving beyond the first or last date of the month smoothly scrolls the calendar to the adjacent month while keeping focus on the active date.
309
+
310
+ * **Icon-only buttons:** The month/year arrows and the input mode toggle carry no text. Ensure each has a descriptive `aria-label`. The input mode toggle communicates the active mode through the `aria-pressed` attribute.
311
+ * **Motion preferences:** The component respects OS-level accessibility settings. The calendar will only slide between months and nudge at limits if the user has *not* enabled reduced motion.
198
312
 
199
313
  ## Theming
200
- Each date picker can be themed with CSS custom properties that follow the Material Design 3 component-token naming convention. The container color, shape and elevation are inherited from the [Dialog component](../dialog/README.md).
314
+
315
+ Each date picker can be themed with CSS custom properties that follow the Material Design 3 component-token naming convention. The container color, shape, and elevation are inherited directly from the [Dialog component](../dialog/README.md).
201
316
 
202
317
  | Custom property | Meaning | Default |
203
- |---|---|---|
318
+ | --- | --- | --- |
204
319
  | `--md-comp-date-picker-modal-container-width` | The width of the modal date picker | `360px` |
205
320
  | `--md-comp-date-input-modal-container-width` | The width of the modal date picker in text input mode | `328px` |
206
321
  | `--md-comp-date-picker-docked-container-width` | The width of the docked date picker | `360px` |
@@ -214,8 +329,18 @@ Each date picker can be themed with CSS custom properties that follow the Materi
214
329
  | `--md-comp-date-picker-selection-year-unselected-label-text-color` | The text color of the selectable years | `--md-sys-color-on-surface-variant` |
215
330
  | `--md-comp-date-picker-selection-year-selected-container-color` | The background color of the selected year | `--md-sys-color-primary` |
216
331
  | `--md-comp-date-picker-selection-year-selected-label-text-color` | The text color of the selected year | `--md-sys-color-on-primary` |
332
+ | `--md-comp-date-picker-selection-month-selected-container-color` | The background color of the selected month | `--md-sys-color-surface-variant` |
333
+ | `--md-comp-date-picker-selection-month-selected-label-text-color` | The text color of the selected month | `--md-sys-color-on-surface` |
334
+ | `--md-comp-date-picker-focus-indicator-color` | The color of the focus indicator around a date, month or year | `--md-sys-color-secondary` |
217
335
  | `--md-comp-date-picker-range-selection-active-indicator-container-color` | The background color of the band connecting the endpoints of a range | `--md-sys-color-secondary-container` |
218
336
  | `--md-comp-date-picker-selection-date-in-range-label-text-color` | The text color of the dates inside a range | `--md-sys-color-on-secondary-container` |
337
+ | `--md-comp-date-picker-motion-spatial` | The easing function of the slide between two months | `--md-sys-motion-expressive-fast-effects` |
338
+ | `--md-comp-date-picker-motion-spatial-duration` | The duration of the slide between two months | `--md-sys-motion-expressive-default-spatial-duration` |
339
+ | `--md-comp-date-picker-motion-duration` | The duration of the fade between the calendar, month, year and input views | `--md-sys-motion-expressive-default-effects-duration` |
340
+ | `--md-comp-date-picker-motion-duration-reverse` | The duration of the fade of the view that is leaving | `--md-sys-motion-expressive-fast-effects-duration` |
341
+ | `--md-comp-date-picker-button-motion-duration` | The duration of the state layer fade of a date or year | `--md-sys-motion-expressive-fast-spatial-duration` |
342
+
343
+ *(Note: All motion is disabled if the user has requested reduced motion at the OS level.)*
219
344
 
220
345
  **Example: Changing the width of the modal date picker**
221
346
 
@@ -31,6 +31,7 @@
31
31
  @include statelayer.token('focus-state-layer-opacity');
32
32
  @include statelayer.token('pressed-state-layer-opacity');
33
33
  @include statelayer.token('disabled-state-layer-opacity');
34
+ @include statelayer.token('focus-indicator-thickness');
34
35
  @include statelayer.property;
35
36
 
36
37
  @include typography.scale('headline-large');
@@ -41,7 +42,7 @@
41
42
  %view-transition-base {
42
43
  block-size: fit-content;
43
44
  opacity: 1;
44
- transition-duration: var(--md-comp-date-picker-motion-spatial-duration);
45
+ transition-duration: var(--_datepicker-motion-spatial-duration);
45
46
 
46
47
  &.micl-datepicker__view-hidden {
47
48
  block-size: 0;
@@ -65,12 +66,12 @@
65
66
  background-repeat: no-repeat;
66
67
  background-size: 100%;
67
68
  background-clip: content-box;
68
- transition: --statelayer-opacity var(--md-comp-date-picker-button-motion-duration) linear;
69
+ transition: --statelayer-opacity var(--_datepicker-button-motion-duration) linear;
69
70
 
70
71
  &:hover {
71
72
  --statelayer-opacity: var(--md-sys-state-hover-state-layer-opacity);
72
73
  }
73
- &:focus-visible {
74
+ &:is(:focus-visible, :has(input:focus-visible)) {
74
75
  --statelayer-opacity: var(--md-sys-state-focus-state-layer-opacity);
75
76
  }
76
77
  &:active {
@@ -78,12 +79,17 @@
78
79
  }
79
80
  }
80
81
 
82
+ %focus-indicator {
83
+ outline: var(--md-sys-state-focus-indicator-thickness, 3px) solid var(--md-comp-date-picker-focus-indicator-color, var(--md-sys-color-secondary));
84
+ outline-offset: -1px;
85
+ }
86
+
81
87
  dialog.micl-dialog.micl-datepicker {
82
- --md-comp-date-picker-motion-spatial: #{motion.$md-sys-motion-expressive-fast-effects};
83
- --md-comp-date-picker-motion-spatial-duration: #{motion.$md-sys-motion-expressive-default-spatial-duration};
84
- --md-comp-date-picker-motion-duration: #{motion.$md-sys-motion-expressive-default-effects-duration};
85
- --md-comp-date-picker-motion-duration-reverse: #{motion.$md-sys-motion-expressive-fast-effects-duration};
86
- --md-comp-date-picker-button-motion-duration: #{motion.$md-sys-motion-expressive-fast-spatial-duration};
88
+ --_datepicker-motion-spatial: var(--md-comp-date-picker-motion-spatial, #{motion.$md-sys-motion-expressive-fast-effects});
89
+ --_datepicker-motion-spatial-duration: var(--md-comp-date-picker-motion-spatial-duration, #{motion.$md-sys-motion-expressive-default-spatial-duration});
90
+ --_datepicker-motion-duration: var(--md-comp-date-picker-motion-duration, #{motion.$md-sys-motion-expressive-default-effects-duration});
91
+ --_datepicker-motion-duration-reverse: var(--md-comp-date-picker-motion-duration-reverse, #{motion.$md-sys-motion-expressive-fast-effects-duration});
92
+ --_datepicker-button-motion-duration: var(--md-comp-date-picker-button-motion-duration, #{motion.$md-sys-motion-expressive-fast-spatial-duration});
87
93
 
88
94
  // Internal alias: the target size is referenced from many descendants.
89
95
  --_target: var(--md-sys-state-target-size, 48px);
@@ -153,7 +159,7 @@ dialog.micl-dialog.micl-datepicker {
153
159
  min-block-size: 330px;
154
160
  padding-inline: 0;
155
161
  overflow: hidden auto;
156
- transition: min-block-size var(--md-comp-date-picker-motion-spatial-duration) var(--md-comp-date-picker-motion-spatial);
162
+ transition: min-block-size var(--_datepicker-motion-spatial-duration) var(--_datepicker-motion-spatial);
157
163
  }
158
164
 
159
165
  .micl-dialog__actions {
@@ -179,6 +185,13 @@ dialog.micl-dialog.micl-datepicker {
179
185
  margin-block: -2px;
180
186
  }
181
187
  }
188
+
189
+ @media (prefers-reduced-motion: reduce) {
190
+ --_datepicker-motion-spatial-duration: 0ms;
191
+ --_datepicker-motion-duration: 0ms;
192
+ --_datepicker-motion-duration-reverse: 0ms;
193
+ --_datepicker-button-motion-duration: 0ms;
194
+ }
182
195
  }
183
196
 
184
197
  .micl-datepicker__inputmode {
@@ -275,10 +288,10 @@ dialog.micl-dialog.micl-datepicker {
275
288
  overflow: hidden;
276
289
  transform: translateX(0);
277
290
  transition:
278
- transform var(--md-comp-date-picker-motion-spatial-duration) var(--md-comp-date-picker-motion-spatial),
279
- opacity var(--md-comp-date-picker-motion-duration-reverse) linear,
280
- block-size var(--md-comp-date-picker-motion-duration-reverse) linear allow-discrete,
281
- display var(--md-comp-date-picker-motion-duration-reverse) linear allow-discrete;
291
+ transform var(--_datepicker-motion-spatial-duration) var(--_datepicker-motion-spatial),
292
+ opacity var(--_datepicker-motion-duration-reverse) linear,
293
+ block-size var(--_datepicker-motion-duration-reverse) linear allow-discrete,
294
+ display var(--_datepicker-motion-duration-reverse) linear allow-discrete;
282
295
 
283
296
  &.micl-datepicker__view-hidden {
284
297
  block-size: 0%;
@@ -293,6 +306,38 @@ dialog.micl-dialog.micl-datepicker {
293
306
  &.micl-moveleft {
294
307
  transform: translateX(-50%);
295
308
  }
309
+ // The flex row is laid out from the inline start, so the off-screen half of
310
+ // the strip sits on the opposite side in a right-to-left context.
311
+ &:dir(rtl) {
312
+ &.micl-startright,
313
+ &.micl-moveleft {
314
+ transform: translateX(50%);
315
+ }
316
+ }
317
+ &.micl-datepicker__nudge-min,
318
+ &.micl-datepicker__nudge-max {
319
+ animation: micl-datepicker-nudge var(--_datepicker-motion-duration) ease-in-out;
320
+ }
321
+ &.micl-datepicker__nudge-min {
322
+ --_nudge: 8px;
323
+ }
324
+ &.micl-datepicker__nudge-max {
325
+ --_nudge: -8px;
326
+ }
327
+ &:dir(rtl) {
328
+ &.micl-datepicker__nudge-min {
329
+ --_nudge: -8px;
330
+ }
331
+ &.micl-datepicker__nudge-max {
332
+ --_nudge: 8px;
333
+ }
334
+ }
335
+ }
336
+
337
+ @keyframes micl-datepicker-nudge {
338
+ 50% {
339
+ translate: var(--_nudge, 0) 0;
340
+ }
296
341
  }
297
342
  .micl-datepicker__calendar {
298
343
  flex-shrink: 0;
@@ -304,12 +349,16 @@ dialog.micl-dialog.micl-datepicker {
304
349
 
305
350
  box-sizing: border-box;
306
351
  display: grid;
307
- grid-template-columns: repeat(7, var(--_target));
308
352
  grid-template-rows: 40px repeat(6, var(--_target));
309
353
  block-size: 100%;
310
354
  inline-size: 100%;
311
355
  padding-inline: 12px;
312
356
 
357
+ > * {
358
+ display: grid;
359
+ grid-template-columns: repeat(7, var(--_target));
360
+ }
361
+
313
362
  span, time {
314
363
  box-sizing: border-box;
315
364
  display: inline-flex;
@@ -368,12 +417,16 @@ dialog.micl-dialog.micl-datepicker {
368
417
  &:is(.micl-datepicker__today, .micl-datepicker__selected):is(:hover, :focus-visible, :active) {
369
418
  --statelayer-color: currentColor;
370
419
  }
371
- &.micl-datepicker__outside {
420
+ &.micl-datepicker__disabled {
372
421
  color: rgb(from var(--md-sys-color-on-surface) r g b / var(--md-sys-state-disabled-state-layer-opacity));
422
+ pointer-events: none;
373
423
  }
374
- &:not(.micl-datepicker__outside) {
424
+ &:not(.micl-datepicker__disabled) {
375
425
  cursor: pointer;
376
426
  }
427
+ &:focus-visible {
428
+ @extend %focus-indicator;
429
+ }
377
430
  }
378
431
  }
379
432
 
@@ -403,15 +456,23 @@ dialog.micl-dialog.micl-datepicker {
403
456
 
404
457
  span {
405
458
  visibility: hidden;
406
- color: var(--md-sys-color-on-surface);
459
+ color: inherit;
407
460
  }
408
461
  &:has(input:checked) {
409
- background-color: var(--md-sys-color-surface-variant);
462
+ color: var(--md-comp-date-picker-selection-month-selected-label-text-color, var(--md-sys-color-on-surface));
463
+ background-color: var(--md-comp-date-picker-selection-month-selected-container-color, var(--md-sys-color-surface-variant));
410
464
 
411
465
  span {
412
466
  visibility: visible;
413
467
  }
414
468
  }
469
+ &:has(input:disabled) {
470
+ color: rgb(from var(--md-sys-color-on-surface) r g b / var(--md-sys-state-disabled-state-layer-opacity));
471
+ pointer-events: none;
472
+ }
473
+ &:has(input:focus-visible) {
474
+ @extend %focus-indicator;
475
+ }
415
476
  }
416
477
  }
417
478
  .micl-datepicker__years {
@@ -444,10 +505,13 @@ dialog.micl-dialog.micl-datepicker {
444
505
  background-color: var(--md-comp-date-picker-selection-year-selected-container-color, var(--md-sys-color-primary));
445
506
 
446
507
  // The state layer of the selected year follows its label color.
447
- &:is(:hover, :focus-visible, :active) {
508
+ &:is(:hover, :active, :has(input:focus-visible)) {
448
509
  --statelayer-color: currentColor;
449
510
  }
450
511
  }
512
+ &:has(input:focus-visible) {
513
+ @extend %focus-indicator;
514
+ }
451
515
  }
452
516
  }
453
517
  :is(.micl-datepicker__months, .micl-datepicker__years) input[type=radio] {
@@ -475,6 +539,6 @@ dialog.micl-dialog.micl-datepicker {
475
539
  }
476
540
  }
477
541
 
478
- .micl-no-transition {
542
+ .micl-datepicker__no-transition {
479
543
  transition: none !important;
480
544
  }