material-inspired-component-library 4.0.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -111,9 +111,10 @@ button.micl-iconbutton-outlined-xs {
111
111
  &::before {
112
112
  content: "";
113
113
  position: absolute;
114
- block-size: var(--md-sys-target-size);
115
- inline-size: var(--md-sys-target-size);
116
- inset: calc((var(--micl-height) - var(--md-sys-target-size)) / 2) 0 0 calc((var(--micl-width) - var(--md-sys-target-size)) / 2);
114
+ block-size: var(--md-sys-target-size, 48px);
115
+ inline-size: 100%;
116
+ min-inline-size: var(--md-sys-target-size, 48px);
117
+ inset: calc((var(--micl-height) - var(--md-sys-target-size, 48px)) / 2) 0 0 calc((min(100%, var(--md-sys-target-size, 48px)) - var(--md-sys-target-size, 48px)) / 2);
117
118
  background-color: transparent;
118
119
  }
119
120
  &.micl-button--toggle.micl-button--selected {
@@ -125,7 +126,7 @@ button.micl-iconbutton-outlined-xs {
125
126
  }
126
127
  &.micl-iconbutton--wide {
127
128
  --micl-width: 40px;
128
- border-radius: calc(var(--micl-width) / 2);
129
+ border-radius: calc(var(--micl-height) / 2);
129
130
  }
130
131
  &.micl-button--square {
131
132
  border-radius: var(--md-sys-shape-corner-medium);
@@ -158,9 +159,10 @@ button.micl-iconbutton-outlined-s {
158
159
  &::before {
159
160
  content: "";
160
161
  position: absolute;
161
- block-size: var(--md-sys-target-size);
162
- inline-size: var(--md-sys-target-size);
163
- inset: calc((var(--micl-height) - var(--md-sys-target-size)) / 2) 0 0 calc((var(--micl-width) - var(--md-sys-target-size)) / 2);
162
+ block-size: var(--md-sys-target-size, 48px);
163
+ inline-size: 100%;
164
+ min-inline-size: var(--md-sys-target-size, 48px);
165
+ inset: calc((var(--micl-height) - var(--md-sys-target-size, 48px)) / 2) 0 0 calc((min(100%, var(--md-sys-target-size, 48px)) - var(--md-sys-target-size, 48px)) / 2);
164
166
  background-color: transparent;
165
167
  }
166
168
  &.micl-button--toggle.micl-button--selected {
@@ -172,12 +174,7 @@ button.micl-iconbutton-outlined-s {
172
174
  }
173
175
  &.micl-iconbutton--wide {
174
176
  --micl-width: 52px;
175
- border-radius: calc(var(--micl-width) / 2);
176
-
177
- &::before {
178
- inline-size: var(--micl-width);
179
- inset: calc((40px - var(--md-sys-target-size)) / 2) 0 0 0;
180
- }
177
+ border-radius: calc(var(--micl-height) / 2);
181
178
  }
182
179
  &.micl-button--square {
183
180
  border-radius: var(--md-sys-shape-corner-medium);
@@ -215,7 +212,7 @@ button.micl-iconbutton-outlined-m {
215
212
  }
216
213
  &.micl-iconbutton--wide {
217
214
  --micl-width: 72px;
218
- border-radius: calc(var(--micl-width) / 2);
215
+ border-radius: calc(var(--micl-height) / 2);
219
216
  }
220
217
  &.micl-button--square {
221
218
  border-radius: var(--md-sys-shape-corner-large);
@@ -226,7 +223,7 @@ button.micl-iconbutton-outlined-m {
226
223
  }
227
224
  &:not(:disabled) {
228
225
  &:active {
229
- border-radius: var(--md-sys-shape-corner-small);
226
+ border-radius: var(--md-sys-shape-corner-medium);
230
227
  }
231
228
  }
232
229
  }
@@ -252,7 +249,7 @@ button.micl-iconbutton-outlined-l {
252
249
  }
253
250
  &.micl-iconbutton--wide {
254
251
  --micl-width: 128px;
255
- border-radius: calc(var(--micl-width) / 2);
252
+ border-radius: calc(var(--micl-height) / 2);
256
253
  }
257
254
  &.micl-button--square {
258
255
  border-radius: var(--md-sys-shape-corner-extra-large);
@@ -289,7 +286,7 @@ button.micl-iconbutton-outlined-xl {
289
286
  }
290
287
  &.micl-iconbutton--wide {
291
288
  --micl-width: 184px;
292
- border-radius: calc(var(--micl-width) / 2);
289
+ border-radius: calc(var(--micl-height) / 2);
293
290
  }
294
291
  &.micl-button--square {
295
292
  border-radius: var(--md-sys-shape-corner-extra-large);
@@ -315,6 +312,9 @@ button.micl-iconbutton-standard-l,
315
312
  button.micl-iconbutton-standard-xl {
316
313
  --statelayer-color: var(--md-sys-color-on-surface-variant);
317
314
 
315
+ &:disabled {
316
+ background-color: transparent;
317
+ }
318
318
  &:not(:disabled) {
319
319
  &.micl-button--toggle.micl-button--selected {
320
320
  --statelayer-color: var(--md-sys-color-primary);
@@ -416,6 +416,9 @@ button.micl-iconbutton-outlined-xl {
416
416
  // border: 3px solid var(--md-sys-color-outline);
417
417
  border: 3px solid var(--md-sys-color-outline-variant);
418
418
  }
419
+ &:disabled {
420
+ background-color: transparent;
421
+ }
419
422
  &:not(:disabled) {
420
423
  &.micl-button--toggle.micl-button--selected {
421
424
  --statelayer-color: var(--md-sys-color-inverse-on-surface);
@@ -35,6 +35,7 @@
35
35
  --md-sys-list-item-three-padding: 12px;
36
36
  --md-sys-list-item-space: 16px;
37
37
  --md-sys-list-item-padding-inline: 16px;
38
+ --md-sys-accordion-item-space: 0px;
38
39
  }
39
40
 
40
41
  .micl-list {
@@ -60,6 +61,7 @@
60
61
  }
61
62
  &[open]::details-content {
62
63
  block-size: auto;
64
+ margin-block-end: var(--md-sys-accordion-item-space, 0px);
63
65
  }
64
66
  &[open] .micl-list-item__icon--expander {
65
67
  transform: rotate(180deg);
@@ -88,11 +90,6 @@
88
90
  overflow: hidden;
89
91
  }
90
92
  }
91
-
92
- li.micl-divider {
93
- box-shadow: 0 -4px 0 3px var(--md-sys-list-item-container-color),
94
- 0 4px 0 4px var(--md-sys-list-item-container-color);
95
- }
96
93
  }
97
94
 
98
95
  .micl-list:has(.micl-list-item-one[tabindex], .micl-list-item-two[tabindex], .micl-list-item-three[tabindex]),
@@ -70,6 +70,32 @@ export default (() =>
70
70
  });
71
71
  }
72
72
 
73
+ if (input.matches('input[type=time][data-timepicker]')) {
74
+ const timePicker = !input.dataset.timepicker ? null :
75
+ document.getElementById(input.dataset.timepicker);
76
+ if (timePicker instanceof HTMLDialogElement) {
77
+ input.addEventListener('click', (event: Event) =>
78
+ {
79
+ event.preventDefault();
80
+ timePicker.showModal();
81
+ });
82
+ input.addEventListener('keydown', (event: Event) =>
83
+ {
84
+ if (!(event instanceof KeyboardEvent)) {
85
+ return;
86
+ }
87
+ switch (event.key) {
88
+ case 'Enter':
89
+ case ' ':
90
+ event.preventDefault();
91
+ timePicker.showModal();
92
+ break;
93
+ default:
94
+ }
95
+ });
96
+ }
97
+ }
98
+
73
99
  setCounter(input);
74
100
  },
75
101
 
@@ -0,0 +1,135 @@
1
+ # Time picker
2
+ This component implements the [Material Design 3 Expressive Time picker](https://m3.material.io/components/time-pickers/overview) design. It allows users to select a specific time of day using either a text input or an analog dial interface.
3
+
4
+ ## Basic Usage
5
+
6
+ ### HTML
7
+ The Time picker component is an extension of the [**Dialog** component](../dialog/README.md). To create a basic time picker, use a `<dialog>` element with both `micl-dialog` and `micl-timepicker` classes.
8
+
9
+ ```HTML
10
+ <dialog id="mytimepicker" class="micl-dialog micl-timepicker" closedby="closerequest" aria-labelledby="mytitle">
11
+ <form method="dialog">
12
+ <div class="micl-dialog__headline">
13
+ <h2 id="mytitle">Enter time</h2>
14
+ </div>
15
+
16
+ <div class="micl-dialog__content">
17
+ <input type="number" name="hour" value="00" aria-labelledby="myhour">
18
+ <span class="micl-timepicker__separator">:</span>
19
+ <input type="number" name="minute" value="00" aria-labelledby="myminute">
20
+ <div class="micl-timepicker__period"></div>
21
+ <span id="myhour" class="micl-timepicker__supporting-text-hour">Hour</span>
22
+ <span id="myminute" class="micl-timepicker__supporting-text-minute">Minute</span>
23
+ <div class="micl-timepicker__dial"></div>
24
+ </div>
25
+
26
+ <div class="micl-dialog__actions">
27
+ <button
28
+ type="button"
29
+ class="micl-timepicker__inputmode micl-iconbutton-standard-s material-symbols-outlined"
30
+ data-alticon="schedule"
31
+ aria-label="Switch input mode"
32
+ >keyboard</button>
33
+ <div>
34
+ <button class="micl-button-text-s" value="">Cancel</button>
35
+ <button class="micl-button-text-s" value="OK">OK</button>
36
+ </div>
37
+ </div>
38
+ </form>
39
+ </dialog>
40
+ ```
41
+
42
+ ### CSS
43
+ Import both the time picker and the dialog styles into your project:
44
+
45
+ ```CSS
46
+ @use "material-inspired-component-library/dist/dialog";
47
+ @use "material-inspired-component-library/dist/timepicker";
48
+ ```
49
+
50
+ Or import all MICL styles:
51
+ ```CSS
52
+ @use "material-inspired-component-library/styles";
53
+ ```
54
+
55
+ ### JavaScript
56
+ This component requires JavaScript to function:
57
+
58
+ ```JavaScript
59
+ import micl from "material-inspired-component-library/dist/micl";
60
+ ```
61
+
62
+ This will initialize any Time picker component, including those that will be added to the DOM later on.
63
+
64
+ ### Live Demo
65
+ A live example of the [Time picker component](https://henkpb.github.io/micl/timepicker.html) is available to interact with.
66
+
67
+ ## Variants
68
+ Because the Time 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.
69
+
70
+ ### Time Picker Structure
71
+ For the picker to function correctly, the `micl-dialog__content` area must contain:
72
+
73
+ - Hour input: `<input type="number" name="hour">`
74
+ - Minute input: `<input type="number" name="minute">`
75
+ - Separator: A text element with class `micl-timepicker__separator` (e.g., a colon).
76
+ - AM/PM Container: An empty `<div>` with class `micl-timepicker__period`. The component logic will populate this selector if the user's locale uses a 12-hour format.
77
+ - Dial Container: An optional empty `<div>` with class `micl-timepicker__dial` for the analog clock interface.
78
+ - Optional elements for "Hour" and "Minute" supporting text.
79
+
80
+ By default, the layout is **vertical**. To switch to a **horizontal** layout (side-by-side inputs and dial), add the modifier class `micl-timepicker--horizontal` to the `<dialog>`.
81
+
82
+ #### Input Mode Switching
83
+ To allow users to toggle between the text inputs and the analog dial, add a button to the `micl-dialog__actions` container:
84
+
85
+ - Class: `micl-timepicker__inputmode`
86
+ - Data Attribute: `data-alticon="schedule"` (defines the icon to show when toggled).
87
+
88
+ ### Integration
89
+ You can trigger the Time picker component from standard input fields or buttons.
90
+
91
+ #### Connecting to an Input Field
92
+ To replace the browser's native time picker, add the `data-timepicker` attribute to an `<input>` element. The value of this attribute must match the `id` of your Time picker dialog.
93
+
94
+ ```HTML
95
+ <input type="time" data-timepicker="mytimepicker" value="09:41">
96
+ ```
97
+
98
+ - **Behavior**: When the input is clicked, the picker opens with the input's current value.
99
+ - **Reusability**: Multiple input fields can target the same Time picker component ID.
100
+
101
+ You may use the same time picker component for different time-input fields. When the user engages with the input field, the time picker is opened showing the time specified in the `value`-attribute.
102
+
103
+ #### Connecting to a Button
104
+ You can use a button to trigger the picker using the standard `popovertarget` attribute.
105
+
106
+ ```HTML
107
+ <button type="button" class="micl-button-text-m" popovertarget="mytimepicker">09:41</button>
108
+ ```
109
+
110
+ - **Behavior**: The Time picker treats the button's text content as the time value to read from and write to.
111
+
112
+ ## Customizations
113
+ You can customize the appearance of the Time picker component by overriding its global CSS variables. These variables are declared on the `:root` pseudo-class and can be changed on any appropriate parent element to affect its child time pickers.
114
+
115
+ | Variable name | Default Value | Description |
116
+ | ------------- | ------------- | ----------- |
117
+ | --md-sys-timepicker-input-height | 72px | Height of the hour a minute input boxes |
118
+ | --md-sys-timepicker-input-width | 96px | Width of the input boxes in 12-hour mode |
119
+ | --md-sys-timepicker-input-width-24h | 114px | Width of the input boxes in 24-hour mode |
120
+ | --md-sys-timepicker-separator-width | 24px | Width of the space containing the colon separator |
121
+ | --md-sys-timepicker-period-height | 72px | Total height of the AM/PM selector toggle |
122
+ | --md-sys-timepicker-period-width | 52px | Width of the AM/PM selector toggle |
123
+ | --md-sys-timepicker-dial-size | 256px | Diameter of the analog clock face |
124
+ | --md-sys-timepicker-dial-center-size | 8px | Diameter of the center dot in the analog dial |
125
+ | --md-sys-timepicker-dial-track-width | 2px | Thickness of the circular track line on the dial |
126
+
127
+ **Example: Changing the width of the dial track**
128
+
129
+ ```HTML
130
+ <div style="--md-sys-timepicker-dial-track-width:3px">
131
+ <dialog class="micl-dialog micl-timepicker" closedby="closerequest">
132
+ ...
133
+ </dialog>
134
+ </div>
135
+ ```
@@ -0,0 +1,390 @@
1
+ //
2
+ // Copyright © 2025 Hermana AS
3
+ //
4
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ // of this software and associated documentation files (the "Software"), to deal
6
+ // in the Software without restriction, including without limitation the rights
7
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ // copies of the Software, and to permit persons to whom the Software is
9
+ // furnished to do so, subject to the following conditions:
10
+ //
11
+ // The above copyright notice and this permission notice shall be included in all
12
+ // copies or substantial portions of the Software.
13
+ //
14
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ // SOFTWARE.
21
+
22
+ @use '../../styles/motion';
23
+ @use '../../styles/shapes';
24
+ @use '../../styles/statelayer';
25
+ @use '../../styles/typography';
26
+
27
+ :root {
28
+ --md-sys-timepicker-input-height: 72px;
29
+ --md-sys-timepicker-input-width: 96px;
30
+ --md-sys-timepicker-input-width-24h: 114px;
31
+ --md-sys-timepicker-separator-width: 24px;
32
+ --md-sys-timepicker-period-height: 72px;
33
+ --md-sys-timepicker-period-width: 52px;
34
+ --md-sys-timepicker-dial-size: 256px;
35
+ --md-sys-timepicker-dial-center-size: 8px;
36
+ --md-sys-timepicker-dial-track-width: 2px;
37
+ }
38
+
39
+ dialog.micl-dialog.micl-timepicker {
40
+ --md-sys-timepicker-motion-duration: #{motion.$md-sys-motion-expressive-fast-spatial-duration};
41
+
42
+ .micl-dialog__headline {
43
+ padding-block-end: 20px;
44
+
45
+ h2 {
46
+ @include typography.label-medium;
47
+
48
+ color: var(--md-sys-color-on-surface-variant);
49
+ }
50
+ }
51
+ .micl-dialog__content {
52
+ display: grid;
53
+ padding-block-start: 1px;
54
+ grid-template-areas:
55
+ "timepicker-hour timepicker-separator timepicker-minute timepicker-period"
56
+ "timepicker-hour-supporting timepicker-hour-supporting timepicker-minute-supporting timepicker-minute-supporting"
57
+ "timepicker-dial timepicker-dial timepicker-dial timepicker-dial";
58
+ grid-template-columns: auto var(--md-sys-timepicker-separator-width) var(--md-sys-timepicker-input-width) auto;
59
+ }
60
+ .micl-dialog__actions {
61
+ &:has(.micl-timepicker__inputmode) {
62
+ justify-content: space-between;
63
+ }
64
+
65
+ .micl-timepicker__inputmode {
66
+ margin-inline-start: -8px;
67
+ }
68
+ }
69
+
70
+ &:has(.micl-timepicker__dial:not(.micl-hidden)) {
71
+ --md-sys-timepicker-input-height: 80px;
72
+ --md-sys-timepicker-period-height: 80px;
73
+
74
+ &.micl-timepicker--horizontal {
75
+ --md-sys-timepicker-period-height: 38px;
76
+
77
+ .micl-dialog__headline {
78
+ padding-block-end: 0;
79
+ }
80
+ .micl-dialog__content {
81
+ grid-template-areas:
82
+ "timepicker-dummy timepicker-dummy timepicker-dummy timepicker-dial"
83
+ "timepicker-hour timepicker-separator timepicker-minute timepicker-dial"
84
+ "timepicker-period timepicker-period timepicker-period timepicker-dial";
85
+ grid-template-rows: 72px var(--md-sys-timepicker-input-height) auto;
86
+
87
+ .micl-timepicker__period {
88
+ --md-sys-timepicker-ampm-height: var(--md-sys-timepicker-period-height);
89
+ --md-sys-timepicker-period-width: calc(2 * var(--md-sys-timepicker-input-width) + var(--md-sys-timepicker-separator-width));
90
+
91
+ display: flex;
92
+ align-self: flex-start;
93
+ margin-inline: 0;
94
+ margin-block: 16px 0;
95
+
96
+ .micl-timepicker__am {
97
+ border-start-end-radius: 0;
98
+ border-end-start-radius: var(--md-sys-shape-corner-small);
99
+ }
100
+ .micl-timepicker__pm {
101
+ border-block-start-width: 1px;
102
+ border-inline-start-width: 0px;
103
+ border-start-end-radius: var(--md-sys-shape-corner-small);
104
+ border-end-start-radius: 0;
105
+ }
106
+ }
107
+ .micl-timepicker__dial {
108
+ margin-block: 0;
109
+ margin-inline: 40px 0;
110
+ }
111
+ }
112
+ }
113
+ .micl-timepicker__supporting-text-hour,
114
+ .micl-timepicker__supporting-text-minute {
115
+ display: none;
116
+ }
117
+ }
118
+ }
119
+
120
+ .micl-timepicker {
121
+ input[name=hour],
122
+ input[name=minute] {
123
+ --statelayer-color: var(--md-sys-color-on-surface);
124
+
125
+ @include typography.display-medium;
126
+
127
+ box-sizing: border-box;
128
+ inline-size: var(--md-sys-timepicker-input-width);
129
+ block-size: var(--md-sys-timepicker-input-height);
130
+ margin: 0;
131
+ padding: 0;
132
+ border: none;
133
+ outline: none;
134
+ border-radius: var(--md-sys-shape-corner-small);
135
+ background-color: var(--md-sys-color-surface-container-highest);
136
+ background-image: linear-gradient(rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)));
137
+ background-repeat: no-repeat;
138
+ background-size: 100%;
139
+ color: var(--md-sys-color-on-surface);
140
+ text-align: center;
141
+ user-select: none;
142
+ -webkit-tap-highlight-color: transparent;
143
+ -moz-appearance: textfield;
144
+ transition: --statelayer-opacity var(--md-sys-timepicker-motion-duration) linear;
145
+
146
+ &::-webkit-inner-spin-button,
147
+ &::-webkit-outer-spin-button {
148
+ -webkit-appearance: none;
149
+ }
150
+ &::selection {
151
+ background-color: transparent;
152
+ }
153
+ &.micl-timepicker--selected {
154
+ --statelayer-color: var(--md-sys-color-on-primary-container);
155
+
156
+ background-color: var(--md-sys-color-primary-container);
157
+ color: var(--md-sys-color-on-primary-container);
158
+ border: 2px solid var(--md-sys-color-primary);
159
+ }
160
+ &:hover {
161
+ --statelayer-opacity: var(--md-sys-state-hover-state-layer-opacity);
162
+ }
163
+ &:focus-visible {
164
+ --statelayer-opacity: var(--md-sys-state-focus-state-layer-opacity);
165
+ }
166
+ &:active {
167
+ --statelayer-opacity: var(--md-sys-state-pressed-state-layer-opacity);
168
+ }
169
+ }
170
+ input[name=hour] {
171
+ grid-area: timepicker-hour;
172
+ justify-self: flex-end;
173
+ }
174
+ input[name=minute] {
175
+ grid-area: timepicker-minute;
176
+ }
177
+ &:has(.micl-timepicker__dial:not(.micl-hidden)) {
178
+ input[name=hour],
179
+ input[name=minute] {
180
+ @include typography.display-large;
181
+
182
+ border: none;
183
+ cursor: pointer;
184
+ }
185
+ }
186
+ &:not(:has(.micl-timepicker__am)):not(:has(.micl-timepicker__dial:not(.micl-hidden))) {
187
+ --md-sys-timepicker-input-width: var(--md-sys-timepicker-input-width-24h);
188
+ }
189
+ }
190
+ .micl-timepicker__separator {
191
+ @include typography.display-large;
192
+
193
+ grid-area: timepicker-separator;
194
+ block-size: var(--md-sys-timepicker-input-height);
195
+ line-height: var(--md-sys-timepicker-input-height);
196
+ inline-size: var(--md-sys-timepicker-separator-width);
197
+ text-align: center;
198
+ color: var(--md-sys-color-on-surface);
199
+ }
200
+ .micl-timepicker__period {
201
+ --md-sys-timepicker-ampm-height: calc(var(--md-sys-timepicker-period-height) / 2);
202
+
203
+ grid-area: timepicker-period;
204
+ block-size: var(--md-sys-timepicker-period-height);
205
+ inline-size: 0;
206
+
207
+ &:has(.micl-timepicker__am) {
208
+ inline-size: var(--md-sys-timepicker-period-width);
209
+ margin-inline: 12px 0;
210
+ }
211
+ .micl-timepicker__am,
212
+ .micl-timepicker__pm {
213
+ --statelayer-color: var(--md-sys-color-on-surface-variant);
214
+
215
+ @include typography.title-medium;
216
+
217
+ appearance: none;
218
+ box-sizing: border-box;
219
+ position: relative;
220
+ display: flex;
221
+ align-items: center;
222
+ inline-size: var(--md-sys-timepicker-period-width);
223
+ block-size: var(--md-sys-timepicker-ampm-height);
224
+ min-block-size: var(--md-sys-timepicker-ampm-height);
225
+ margin: 0;
226
+ border: 1px solid var(--md-sys-color-outline);
227
+ outline: none;
228
+ color: var(--md-sys-color-on-surface-variant);
229
+ background-color: transparent;
230
+ background-image: linear-gradient(rgb(from var(--statelayer-color) r g b / var(--statelayer-opacity)));
231
+ background-repeat: no-repeat;
232
+ background-size: 100%;
233
+ cursor: pointer;
234
+ -webkit-tap-highlight-color: transparent;
235
+ transition: --statelayer-opacity var(--md-sys-timepicker-motion-duration) linear;
236
+
237
+ &::before {
238
+ content: "AM";
239
+ position: absolute;
240
+ inline-size: 100%;
241
+ text-align: center;
242
+ }
243
+ &:checked {
244
+ color: var(--md-sys-color-on-tertiary-container);
245
+ background-color: var(--md-sys-color-tertiary-container);
246
+ }
247
+ &:hover,
248
+ &:focus-visible,
249
+ &:active {
250
+ &:checked {
251
+ --statelayer-color: var(--md-sys-color-on-tertiary-container);
252
+ }
253
+ &::after {
254
+ border-color: var(--md-sys-color-on-surface);
255
+ }
256
+ &:checked::after {
257
+ border-color: var(--md-sys-color-primary);
258
+ }
259
+ }
260
+ &:hover {
261
+ --statelayer-opacity: var(--md-sys-state-hover-state-layer-opacity);
262
+ }
263
+ &:focus-visible {
264
+ --statelayer-opacity: var(--md-sys-state-focus-state-layer-opacity);
265
+
266
+ outline: var(--md-sys-state-focus-indicator-thickness) solid var(--md-sys-color-secondary);
267
+ outline-offset: -2px;
268
+ }
269
+ &:active {
270
+ --statelayer-opacity: var(--md-sys-state-pressed-state-layer-opacity);
271
+ }
272
+ }
273
+ .micl-timepicker__am {
274
+ border-start-start-radius: var(--md-sys-shape-corner-small);
275
+ border-start-end-radius: var(--md-sys-shape-corner-small);
276
+ }
277
+ .micl-timepicker__pm {
278
+ border-block-start-width: 0px;
279
+ border-end-start-radius: var(--md-sys-shape-corner-small);
280
+ border-end-end-radius: var(--md-sys-shape-corner-small);
281
+
282
+ &::before {
283
+ content: "PM";
284
+ }
285
+ }
286
+ }
287
+
288
+ .micl-timepicker__supporting-text-hour,
289
+ .micl-timepicker__supporting-text-minute {
290
+ @include typography.body-small;
291
+
292
+ grid-area: timepicker-hour-supporting;
293
+ padding-block: 4px 0;
294
+ color: var(--md-sys-color-on-surface-variant);
295
+ }
296
+ .micl-timepicker__supporting-text-minute {
297
+ grid-area: timepicker-minute-supporting;
298
+ }
299
+
300
+ .micl-timepicker .micl-timepicker__dial {
301
+ --micl-dial-radius: calc((var(--md-sys-timepicker-dial-size, 256px) - var(--md-sys-target-size, 48px)) / 2);
302
+ --micl-hour-radius: var(--micl-dial-radius);
303
+ --micl-angle: 0deg;
304
+
305
+ position: relative;
306
+ grid-area: timepicker-dial;
307
+ justify-self: center;
308
+ block-size: var(--md-sys-timepicker-dial-size, 256px);
309
+ inline-size: var(--md-sys-timepicker-dial-size, 256px);
310
+ margin-block: 36px 0;
311
+ margin-inline: 0;
312
+ outline: none;
313
+ border-radius: var(--md-sys-shape-corner-full);
314
+ background-color: var(--md-sys-color-surface-container-highest);
315
+ list-style-type: none;
316
+ touch-action: none;
317
+
318
+ data.micl-timepicker__dial-inner {
319
+ --micl-hour-radius: calc(var(--micl-dial-radius) - var(--md-sys-target-size) + 12px);
320
+
321
+ z-index: 2;
322
+ &::before {
323
+ z-index: 2;
324
+ }
325
+ }
326
+ data {
327
+ --micl-a: calc(var(--micl-dial-radius) + (var(--micl-hour-radius) * cos(var(--micl-angle))));
328
+ --micl-b: calc(var(--micl-dial-radius) + (var(--micl-hour-radius) * sin(var(--micl-angle))));
329
+
330
+ @include typography.body-large;
331
+
332
+ position: absolute;
333
+ display: grid;
334
+ place-content: center;
335
+ block-size: var(--md-sys-target-size, 48px);
336
+ inline-size: var(--md-sys-target-size, 48px);
337
+ inset-inline-start: var(--micl-a);
338
+ inset-block-start: var(--micl-b);
339
+ outline: none;
340
+ border-radius: var(--md-sys-shape-corner-full);
341
+ color: var(--md-sys-color-on-surface);
342
+ cursor: pointer;
343
+ z-index: 1;
344
+ user-select: none;
345
+ -webkit-tap-highlight-color: transparent;
346
+
347
+ &.micl-timepicker__time--selected {
348
+ color: var(--md-sys-color-on-primary);
349
+ background-color: var(--md-sys-color-primary);
350
+ }
351
+ &::before {
352
+ content: "";
353
+ position: absolute;
354
+ block-size: var(--md-sys-target-size, 48px);
355
+ inline-size: calc(2 * var(--md-sys-target-size, 48px));
356
+ inset-inline-start: 0;
357
+ inset-block-end: 0;
358
+ transform: rotate(var(--micl-angle)) translate(calc(-1 * var(--md-sys-target-size, 48px)));
359
+ transform-origin: calc(var(--md-sys-target-size, 48px) / 2) center;
360
+ z-index: 1;
361
+ }
362
+ }
363
+
364
+ .micl-timepicker__track {
365
+ --micl-track-length: 92px;
366
+
367
+ position: relative;
368
+ display: block;
369
+ inline-size: var(--md-sys-timepicker-dial-track-width, 2px);
370
+ block-size: var(--micl-track-length);
371
+ inset-inline-start: calc((var(--md-sys-timepicker-dial-size, 256px) - var(--md-sys-timepicker-dial-track-width, 2px)) / 2);
372
+ inset-block-start: calc((var(--md-sys-timepicker-dial-size, 256px) / 2) - var(--micl-track-length));
373
+ border-radius: calc(var(--md-sys-timepicker-dial-track-width, 2px) * 2);
374
+ background-color: var(--md-sys-color-primary);
375
+ transform: rotate(calc(90deg + var(--micl-angle)));
376
+ transform-origin: bottom;
377
+
378
+ &::before {
379
+ content: "";
380
+ position: absolute;
381
+ display: block;
382
+ block-size: var(--md-sys-timepicker-dial-center-size, 8px);
383
+ inline-size: var(--md-sys-timepicker-dial-center-size, 8px);
384
+ inset-block-end: -3px;
385
+ inset-inline-start: -3px;
386
+ border-radius: var(--md-sys-shape-corner-full);
387
+ background-color: var(--md-sys-color-primary);
388
+ }
389
+ }
390
+ }