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.
- package/README.md +4 -0
- package/components/accordion/README.md +20 -0
- package/components/alert/README.md +19 -7
- package/components/button/README.md +1 -1
- package/components/button/index.scss +24 -20
- package/components/dialog/README.md +14 -12
- package/components/dialog/index.scss +63 -52
- package/components/divider/index.scss +7 -1
- package/components/iconbutton/README.md +1 -1
- package/components/iconbutton/index.scss +20 -17
- package/components/list/index.scss +2 -5
- package/components/textfield/index.ts +26 -0
- package/components/timepicker/README.md +135 -0
- package/components/timepicker/index.scss +390 -0
- package/components/timepicker/index.ts +416 -0
- package/dist/button.css +1 -1
- package/dist/components/timepicker/index.d.ts +5 -0
- package/dist/dialog.css +1 -1
- package/dist/divider.css +1 -1
- package/dist/iconbutton.css +1 -1
- package/dist/list.css +1 -1
- package/dist/micl.css +1 -1
- package/dist/micl.js +1 -1
- package/dist/switch.css +1 -1
- package/dist/timepicker.css +1 -0
- package/dist/timepicker.js +1 -0
- package/docs/accordion.html +1 -1
- package/docs/bottomsheet.html +1 -1
- package/docs/button.html +42 -15
- package/docs/dialog.html +12 -12
- package/docs/iconbutton.html +258 -164
- package/docs/index.html +31 -7
- package/docs/micl.css +1 -1
- package/docs/micl.js +1 -1
- package/docs/timepicker.html +150 -0
- package/micl.ts +3 -1
- package/package.json +16 -15
- package/styles.scss +1 -0
|
@@ -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:
|
|
116
|
-
|
|
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-
|
|
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:
|
|
163
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
+
}
|