mtrl 0.2.6 → 0.2.7
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/index.ts +18 -0
- package/package.json +1 -1
- package/src/components/badge/_styles.scss +117 -109
- package/src/components/badge/api.ts +57 -59
- package/src/components/badge/badge.ts +16 -2
- package/src/components/badge/config.ts +65 -11
- package/src/components/badge/constants.ts +22 -12
- package/src/components/badge/features.ts +44 -40
- package/src/components/badge/types.ts +42 -30
- package/src/components/bottom-app-bar/_styles.scss +103 -0
- package/src/components/bottom-app-bar/bottom-app-bar.ts +196 -0
- package/src/components/bottom-app-bar/config.ts +73 -0
- package/src/components/bottom-app-bar/index.ts +11 -0
- package/src/components/bottom-app-bar/types.ts +108 -0
- package/src/components/button/_styles.scss +0 -10
- package/src/components/button/api.ts +5 -0
- package/src/components/button/config.ts +5 -0
- package/src/components/button/types.ts +6 -0
- package/src/components/card/card.ts +13 -25
- package/src/components/card/config.ts +67 -22
- package/src/components/card/features.ts +3 -0
- package/src/components/card/types.ts +28 -0
- package/src/components/checkbox/_styles.scss +0 -2
- package/src/components/datepicker/_styles.scss +358 -0
- package/src/components/datepicker/api.ts +272 -0
- package/src/components/datepicker/config.ts +144 -0
- package/src/components/datepicker/constants.ts +98 -0
- package/src/components/datepicker/datepicker.ts +346 -0
- package/src/components/datepicker/index.ts +9 -0
- package/src/components/datepicker/render.ts +452 -0
- package/src/components/datepicker/types.ts +268 -0
- package/src/components/datepicker/utils.ts +290 -0
- package/src/components/dialog/_styles.scss +174 -128
- package/src/components/dialog/api.ts +48 -13
- package/src/components/dialog/config.ts +9 -5
- package/src/components/dialog/dialog.ts +6 -3
- package/src/components/dialog/features.ts +290 -130
- package/src/components/dialog/types.ts +7 -4
- package/src/components/divider/_styles.scss +57 -0
- package/src/components/divider/config.ts +81 -0
- package/src/components/divider/divider.ts +37 -0
- package/src/components/divider/features.ts +207 -0
- package/src/components/divider/index.ts +5 -0
- package/src/components/divider/types.ts +55 -0
- package/src/components/extended-fab/_styles.scss +267 -0
- package/src/components/extended-fab/api.ts +141 -0
- package/src/components/extended-fab/config.ts +108 -0
- package/src/components/extended-fab/constants.ts +36 -0
- package/src/components/extended-fab/extended-fab.ts +125 -0
- package/src/components/extended-fab/index.ts +4 -0
- package/src/components/extended-fab/types.ts +287 -0
- package/src/components/fab/_styles.scss +225 -0
- package/src/components/fab/api.ts +97 -0
- package/src/components/fab/config.ts +94 -0
- package/src/components/fab/constants.ts +41 -0
- package/src/components/fab/fab.ts +67 -0
- package/src/components/fab/index.ts +4 -0
- package/src/components/fab/types.ts +234 -0
- package/src/components/navigation/_styles.scss +1 -0
- package/src/components/navigation/api.ts +78 -50
- package/src/components/navigation/features/items.ts +280 -0
- package/src/components/navigation/nav-item.ts +72 -23
- package/src/components/navigation/navigation.ts +54 -2
- package/src/components/navigation/types.ts +210 -188
- package/src/components/search/_styles.scss +306 -0
- package/src/components/search/api.ts +203 -0
- package/src/components/search/config.ts +87 -0
- package/src/components/search/constants.ts +21 -0
- package/src/components/search/features/index.ts +4 -0
- package/src/components/search/features/search.ts +718 -0
- package/src/components/search/features/states.ts +165 -0
- package/src/components/search/features/structure.ts +198 -0
- package/src/components/search/index.ts +10 -0
- package/src/components/search/search.ts +52 -0
- package/src/components/search/types.ts +163 -0
- package/src/components/segmented-button/_styles.scss +117 -0
- package/src/components/segmented-button/config.ts +67 -0
- package/src/components/segmented-button/constants.ts +42 -0
- package/src/components/segmented-button/index.ts +4 -0
- package/src/components/segmented-button/segment.ts +155 -0
- package/src/components/segmented-button/segmented-button.ts +250 -0
- package/src/components/segmented-button/types.ts +219 -0
- package/src/components/slider/_styles.scss +83 -24
- package/src/components/slider/accessibility.md +5 -5
- package/src/components/slider/api.ts +41 -120
- package/src/components/slider/config.ts +51 -47
- package/src/components/slider/features/handlers.ts +495 -0
- package/src/components/slider/features/index.ts +1 -2
- package/src/components/slider/features/slider.ts +66 -84
- package/src/components/slider/features/states.ts +195 -0
- package/src/components/slider/features/structure.ts +136 -206
- package/src/components/slider/features/ui.ts +145 -206
- package/src/components/slider/index.ts +2 -11
- package/src/components/slider/slider.ts +9 -12
- package/src/components/slider/types.ts +39 -24
- package/src/components/switch/_styles.scss +0 -2
- package/src/components/tabs/_styles.scss +94 -32
- package/src/components/tabs/features.ts +4 -2
- package/src/components/tabs/indicator.ts +73 -13
- package/src/components/tabs/types.ts +10 -2
- package/src/components/timepicker/README.md +277 -0
- package/src/components/timepicker/_styles.scss +451 -0
- package/src/components/timepicker/api.ts +632 -0
- package/src/components/timepicker/clockdial.ts +482 -0
- package/src/components/timepicker/config.ts +130 -0
- package/src/components/timepicker/constants.ts +138 -0
- package/src/components/timepicker/index.ts +8 -0
- package/src/components/timepicker/render.ts +613 -0
- package/src/components/timepicker/timepicker.ts +117 -0
- package/src/components/timepicker/types.ts +336 -0
- package/src/components/timepicker/utils.ts +241 -0
- package/src/components/top-app-bar/_styles.scss +225 -0
- package/src/components/top-app-bar/config.ts +83 -0
- package/src/components/top-app-bar/index.ts +11 -0
- package/src/components/top-app-bar/top-app-bar.ts +316 -0
- package/src/components/top-app-bar/types.ts +140 -0
- package/src/core/build/_ripple.scss +6 -6
- package/src/core/build/ripple.ts +72 -95
- package/src/core/compose/features/icon.ts +3 -1
- package/src/core/compose/features/ripple.ts +4 -1
- package/src/core/compose/features/textlabel.ts +26 -2
- package/src/core/dom/create.ts +5 -0
- package/src/index.ts +9 -0
- package/src/styles/abstract/_theme.scss +9 -1
- package/src/styles/themes/_autumn.scss +21 -0
- package/src/styles/themes/_base-theme.scss +61 -0
- package/src/styles/themes/_baseline.scss +58 -0
- package/src/styles/themes/_bluekhaki.scss +125 -0
- package/src/styles/themes/_brownbeige.scss +125 -0
- package/src/styles/themes/_browngreen.scss +125 -0
- package/src/styles/themes/_forest.scss +6 -0
- package/src/styles/themes/_greenbeige.scss +125 -0
- package/src/styles/themes/_material.scss +125 -0
- package/src/styles/themes/_ocean.scss +6 -0
- package/src/styles/themes/_sageivory.scss +125 -0
- package/src/styles/themes/_spring.scss +6 -0
- package/src/styles/themes/_summer.scss +5 -0
- package/src/styles/themes/_sunset.scss +5 -0
- package/src/styles/themes/_tealcaramel.scss +125 -0
- package/src/styles/themes/_winter.scss +6 -0
- package/src/components/navigation/features/items.js +0 -192
- package/src/components/slider/features/appearance.ts +0 -94
- package/src/components/slider/features/disabled.ts +0 -68
- package/src/components/slider/features/events.ts +0 -164
- package/src/components/slider/features/interactions.ts +0 -396
- package/src/components/slider/features/keyboard.ts +0 -233
- package/src/core/collection/adapters/mongodb.js +0 -232
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# TimePicker Component
|
|
2
|
+
|
|
3
|
+
The `TimePicker` component provides a user-friendly interface for selecting a time. It supports both dial-based
|
|
4
|
+
and keyboard input selection methods, 12-hour and 24-hour formats, and customizable settings.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- **Two Selection Methods**: Choose between a dial interface or keyboard input
|
|
9
|
+
- **Time Format Support**: 12-hour (AM/PM) or 24-hour format
|
|
10
|
+
- **Flexible Configuration**: Customize title, action buttons, and constraints
|
|
11
|
+
- **Responsive Layout**: Adapts between vertical and horizontal layouts based on device orientation
|
|
12
|
+
- **Accessibility**: Keyboard navigation and screen reader support
|
|
13
|
+
- **Full TypeScript Support**: Comprehensive type definitions for better development experience
|
|
14
|
+
|
|
15
|
+
## Basic Usage
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import { createTimePicker } from 'mtrl';
|
|
19
|
+
|
|
20
|
+
// Create a basic time picker
|
|
21
|
+
const timePicker = createTimePicker({
|
|
22
|
+
title: 'Select time',
|
|
23
|
+
value: '14:30', // Initial time (2:30 PM)
|
|
24
|
+
onConfirm: (time) => {
|
|
25
|
+
console.log('Selected time:', time);
|
|
26
|
+
// Update UI with selected time
|
|
27
|
+
document.getElementById('time-input').value = time;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Create an input to trigger the time picker
|
|
32
|
+
const timeInput = document.createElement('input');
|
|
33
|
+
timeInput.id = 'time-input';
|
|
34
|
+
timeInput.type = 'text';
|
|
35
|
+
timeInput.readOnly = true;
|
|
36
|
+
timeInput.value = '14:30';
|
|
37
|
+
timeInput.addEventListener('click', () => {
|
|
38
|
+
timePicker.open();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Add input to the DOM
|
|
42
|
+
document.body.appendChild(timeInput);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Configuration Options
|
|
46
|
+
|
|
47
|
+
The `createTimePicker` function accepts a configuration object with the following properties:
|
|
48
|
+
|
|
49
|
+
| Property | Type | Default | Description |
|
|
50
|
+
|----------|------|---------|-------------|
|
|
51
|
+
| `value` | `string` | Current time | Initial time value in 24-hour format (HH:MM or HH:MM:SS) |
|
|
52
|
+
| `type` | `TIME_PICKER_TYPE` | `DIAL` | Type of time picker to display (DIAL or INPUT) |
|
|
53
|
+
| `format` | `TIME_FORMAT` | `AMPM` | Time format to use (AMPM for 12-hour or MILITARY for 24-hour) |
|
|
54
|
+
| `orientation` | `TIME_PICKER_ORIENTATION` | `VERTICAL` | Layout orientation (VERTICAL or HORIZONTAL) |
|
|
55
|
+
| `title` | `string` | `undefined` | Title text for the time picker |
|
|
56
|
+
| `showSeconds` | `boolean` | `false` | Whether to show seconds selector |
|
|
57
|
+
| `class` | `string` | `undefined` | Additional CSS classes to add to the time picker |
|
|
58
|
+
| `closeOnSelect` | `boolean` | `true` | Whether to close the picker when time is selected |
|
|
59
|
+
| `minTime` | `string` | `undefined` | Minimum selectable time in 24-hour format (HH:MM) |
|
|
60
|
+
| `maxTime` | `string` | `undefined` | Maximum selectable time in 24-hour format (HH:MM) |
|
|
61
|
+
| `minuteStep` | `number` | `1` | Step interval for minute selection |
|
|
62
|
+
| `secondStep` | `number` | `1` | Step interval for second selection |
|
|
63
|
+
| `cancelText` | `string` | `'Cancel'` | Custom text for cancel button |
|
|
64
|
+
| `confirmText` | `string` | `'OK'` | Custom text for confirm button |
|
|
65
|
+
| `isOpen` | `boolean` | `false` | Whether the time picker is initially visible |
|
|
66
|
+
| `container` | `string \| HTMLElement` | `document.body` | CSS selector or element to append the time picker to |
|
|
67
|
+
| `clockIcon` | `string` | Default SVG | Custom icon for the clock button |
|
|
68
|
+
| `keyboardIcon` | `string` | Default SVG | Custom icon for the keyboard button |
|
|
69
|
+
| `onChange` | `function` | `undefined` | Callback when time is changed |
|
|
70
|
+
| `onOpen` | `function` | `undefined` | Callback when time picker is opened |
|
|
71
|
+
| `onClose` | `function` | `undefined` | Callback when time picker is closed |
|
|
72
|
+
| `onConfirm` | `function` | `undefined` | Callback when time is confirmed |
|
|
73
|
+
| `onCancel` | `function` | `undefined` | Callback when time picker is canceled |
|
|
74
|
+
|
|
75
|
+
## API Methods
|
|
76
|
+
|
|
77
|
+
Once created, the TimePicker instance provides the following methods:
|
|
78
|
+
|
|
79
|
+
### Open, Close, and Toggle
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
// Open the time picker
|
|
83
|
+
timePicker.open();
|
|
84
|
+
|
|
85
|
+
// Close the time picker
|
|
86
|
+
timePicker.close();
|
|
87
|
+
|
|
88
|
+
// Toggle the time picker open/closed state
|
|
89
|
+
timePicker.toggle();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Get and Set Value
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
// Get the current time value as a string (HH:MM or HH:MM:SS)
|
|
96
|
+
const timeString = timePicker.getValue();
|
|
97
|
+
|
|
98
|
+
// Get the current time as an object with hours, minutes, seconds, and period
|
|
99
|
+
const timeObject = timePicker.getTimeObject();
|
|
100
|
+
|
|
101
|
+
// Set the time value
|
|
102
|
+
timePicker.setValue('15:45');
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Change Configuration
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
// Switch between dial and input types
|
|
109
|
+
timePicker.setType(TIME_PICKER_TYPE.INPUT);
|
|
110
|
+
|
|
111
|
+
// Switch between 12-hour and 24-hour formats
|
|
112
|
+
timePicker.setFormat(TIME_FORMAT.MILITARY);
|
|
113
|
+
|
|
114
|
+
// Change the orientation
|
|
115
|
+
timePicker.setOrientation(TIME_PICKER_ORIENTATION.HORIZONTAL);
|
|
116
|
+
|
|
117
|
+
// Update the title
|
|
118
|
+
timePicker.setTitle('Choose departure time');
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Event Handling
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
// Listen for time changes
|
|
125
|
+
timePicker.on('change', (time) => {
|
|
126
|
+
console.log('Time changed:', time);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Listen for time picker opening
|
|
130
|
+
timePicker.on('open', () => {
|
|
131
|
+
console.log('Time picker opened');
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Remove an event listener
|
|
135
|
+
timePicker.off('change', myHandler);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Cleanup
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
// Destroy the time picker and clean up resources
|
|
142
|
+
timePicker.destroy();
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Advanced Examples
|
|
146
|
+
|
|
147
|
+
### 24-Hour Time Picker with Seconds
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
import { createTimePicker, TIME_FORMAT } from 'mtrl';
|
|
151
|
+
|
|
152
|
+
const timePicker = createTimePicker({
|
|
153
|
+
title: 'Select time',
|
|
154
|
+
value: '18:30:45',
|
|
155
|
+
format: TIME_FORMAT.MILITARY,
|
|
156
|
+
showSeconds: true,
|
|
157
|
+
onConfirm: (time) => {
|
|
158
|
+
console.log('Selected time with seconds:', time);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Time Range Selection
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
import { createTimePicker } from 'mtrl';
|
|
167
|
+
|
|
168
|
+
// Start time picker
|
|
169
|
+
const startTimePicker = createTimePicker({
|
|
170
|
+
title: 'Select start time',
|
|
171
|
+
value: '09:00',
|
|
172
|
+
minTime: '08:00',
|
|
173
|
+
maxTime: '16:00',
|
|
174
|
+
onConfirm: (time) => {
|
|
175
|
+
startTimeInput.value = time;
|
|
176
|
+
|
|
177
|
+
// Update end time constraints
|
|
178
|
+
const [hours, minutes] = time.split(':');
|
|
179
|
+
const startDate = new Date();
|
|
180
|
+
startDate.setHours(parseInt(hours, 10), parseInt(minutes, 10));
|
|
181
|
+
|
|
182
|
+
// Add minimum 30 minutes to start time
|
|
183
|
+
const minEndDate = new Date(startDate);
|
|
184
|
+
minEndDate.setMinutes(minEndDate.getMinutes() + 30);
|
|
185
|
+
|
|
186
|
+
endTimePicker.minTime = `${minEndDate.getHours()}:${minEndDate.getMinutes()}`;
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// End time picker
|
|
191
|
+
const endTimePicker = createTimePicker({
|
|
192
|
+
title: 'Select end time',
|
|
193
|
+
value: '17:00',
|
|
194
|
+
minTime: '09:30', // Initial minimum (30 min after default start)
|
|
195
|
+
onConfirm: (time) => {
|
|
196
|
+
endTimeInput.value = time;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Accessibility
|
|
202
|
+
|
|
203
|
+
The TimePicker component is designed with accessibility in mind:
|
|
204
|
+
|
|
205
|
+
- Keyboard navigation for all controls
|
|
206
|
+
- ARIA attributes for screen reader support
|
|
207
|
+
- Large touch targets for better mobile accessibility
|
|
208
|
+
- High contrast colors and clear visual indicators
|
|
209
|
+
- Support for reducing motion based on user preferences
|
|
210
|
+
|
|
211
|
+
## Customization
|
|
212
|
+
|
|
213
|
+
### Custom Styling
|
|
214
|
+
|
|
215
|
+
You can customize the appearance of the TimePicker by overriding the CSS variables and classes:
|
|
216
|
+
|
|
217
|
+
```css
|
|
218
|
+
/* Custom time picker styling */
|
|
219
|
+
.mtrl-time-picker-dialog {
|
|
220
|
+
--mtrl-primary: #6200ee;
|
|
221
|
+
--mtrl-on-primary: #ffffff;
|
|
222
|
+
--mtrl-surface-container-high: #f5f5f5;
|
|
223
|
+
--mtrl-on-surface: #1d1d1d;
|
|
224
|
+
|
|
225
|
+
/* Add custom shadows */
|
|
226
|
+
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* Custom dial styling */
|
|
230
|
+
.mtrl-time-picker-dial-face {
|
|
231
|
+
background-color: rgba(98, 0, 238, 0.05);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* Custom buttons */
|
|
235
|
+
.mtrl-time-picker-confirm {
|
|
236
|
+
font-weight: bold;
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Custom Icons
|
|
241
|
+
|
|
242
|
+
You can also provide custom icons for the clock and keyboard buttons:
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
const timePicker = createTimePicker({
|
|
246
|
+
// Other configuration...
|
|
247
|
+
clockIcon: '<svg>...</svg>', // Custom clock icon
|
|
248
|
+
keyboardIcon: '<svg>...</svg>' // Custom keyboard icon
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Browser Support
|
|
253
|
+
|
|
254
|
+
The TimePicker component supports all modern browsers:
|
|
255
|
+
|
|
256
|
+
- Chrome (latest)
|
|
257
|
+
- Firefox (latest)
|
|
258
|
+
- Safari (latest)
|
|
259
|
+
- Edge (latest)
|
|
260
|
+
|
|
261
|
+
## TypeScript Support
|
|
262
|
+
|
|
263
|
+
The `TimePicker` component includes comprehensive TypeScript definitions:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
import { createTimePicker, TIME_PICKER_TYPE, TIME_FORMAT, TimePickerConfig } from 'mtrl';
|
|
267
|
+
|
|
268
|
+
// Configuration with TypeScript
|
|
269
|
+
const config: TimePickerConfig = {
|
|
270
|
+
title: 'Select time',
|
|
271
|
+
value: '14:30',
|
|
272
|
+
type: TIME_PICKER_TYPE.DIAL,
|
|
273
|
+
format: TIME_FORMAT.AMPM
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
const timePicker = createTimePicker(config);
|
|
277
|
+
```
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
// src/components/timepicker/_styles.scss
|
|
2
|
+
@use 'sass:map';
|
|
3
|
+
@use '../../styles/abstract/base' as base;
|
|
4
|
+
@use '../../styles/abstract/variables' as v;
|
|
5
|
+
@use '../../styles/abstract/functions' as f;
|
|
6
|
+
@use '../../styles/abstract/mixins' as m;
|
|
7
|
+
@use '../../styles/abstract/theme' as t;
|
|
8
|
+
|
|
9
|
+
$component: '#{base.$prefix}-time-picker';
|
|
10
|
+
|
|
11
|
+
.#{$component} {
|
|
12
|
+
// Base styles
|
|
13
|
+
position: relative;
|
|
14
|
+
display: inline-block;
|
|
15
|
+
|
|
16
|
+
&-modal {
|
|
17
|
+
position: fixed;
|
|
18
|
+
top: 0;
|
|
19
|
+
left: 0;
|
|
20
|
+
width: 100%;
|
|
21
|
+
height: 100%;
|
|
22
|
+
background-color: rgba(0, 0, 0, 0.4);
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
justify-content: center;
|
|
26
|
+
z-index: map.get(v.$z-index, 'modal');
|
|
27
|
+
opacity: 0;
|
|
28
|
+
transition: opacity 0.25s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
29
|
+
|
|
30
|
+
&.active {
|
|
31
|
+
opacity: 1;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&-dialog {
|
|
36
|
+
position: relative;
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
min-width: 280px;
|
|
40
|
+
max-width: 328px;
|
|
41
|
+
max-height: 520px;
|
|
42
|
+
background-color: t.color('surface-container-high');
|
|
43
|
+
color: t.color('on-surface');
|
|
44
|
+
border-radius: f.get-shape('extra-large');
|
|
45
|
+
@include m.elevation(3);
|
|
46
|
+
transform: translateY(20px) scale(0.9);
|
|
47
|
+
opacity: 0;
|
|
48
|
+
transition: transform 0.25s cubic-bezier(0.4, 0.0, 0.2, 1), opacity 0.25s cubic-bezier(0.4, 0.0, 0.2, 1);
|
|
49
|
+
|
|
50
|
+
&.active {
|
|
51
|
+
transform: translateY(0) scale(1);
|
|
52
|
+
opacity: 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// State layer for elevations
|
|
56
|
+
&::before {
|
|
57
|
+
content: '';
|
|
58
|
+
position: absolute;
|
|
59
|
+
top: 0;
|
|
60
|
+
left: 0;
|
|
61
|
+
width: 100%;
|
|
62
|
+
height: 100%;
|
|
63
|
+
border-radius: inherit;
|
|
64
|
+
background-color: t.color('surface-tint');
|
|
65
|
+
opacity: 0.05;
|
|
66
|
+
pointer-events: none;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Orientations
|
|
70
|
+
&--vertical {
|
|
71
|
+
// min-height: 460px;
|
|
72
|
+
|
|
73
|
+
.#{$component}-input-container {
|
|
74
|
+
flex-direction: row;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.#{$component}-period {
|
|
78
|
+
flex-direction: column;
|
|
79
|
+
width: 52px;
|
|
80
|
+
height: 80px;
|
|
81
|
+
margin-left: 12px;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
&--horizontal {
|
|
86
|
+
min-width: 520px;
|
|
87
|
+
min-height: 360px;
|
|
88
|
+
|
|
89
|
+
.#{$component}-content {
|
|
90
|
+
flex-direction: row;
|
|
91
|
+
align-items: center;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.#{$component}-input-container {
|
|
95
|
+
flex-direction: row;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.#{$component}-period {
|
|
99
|
+
flex-direction: column;
|
|
100
|
+
width: 52px;
|
|
101
|
+
height: 80px;
|
|
102
|
+
margin-left: 12px;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.#{$component}-dial {
|
|
106
|
+
margin-left: 24px;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Time formats
|
|
111
|
+
&--24h {
|
|
112
|
+
.#{$component}-period {
|
|
113
|
+
display: none;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Title
|
|
119
|
+
&-title {
|
|
120
|
+
padding: 24px 24px 16px;
|
|
121
|
+
@include m.typography('title-small');
|
|
122
|
+
color: t.color('on-surface-variant');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Content container
|
|
126
|
+
&-content {
|
|
127
|
+
flex: 1;
|
|
128
|
+
padding: 0 24px;
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
display: flex;
|
|
131
|
+
flex-direction: column;
|
|
132
|
+
align-items: center;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Input container for both modes
|
|
136
|
+
&-input-container {
|
|
137
|
+
display: flex;
|
|
138
|
+
align-items: center;
|
|
139
|
+
justify-content: center;
|
|
140
|
+
margin: 0 0 24px 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Input field containers
|
|
144
|
+
&-time-input-field {
|
|
145
|
+
position: relative;
|
|
146
|
+
display: flex;
|
|
147
|
+
flex-direction: column;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Time input styles - shared for both modes
|
|
151
|
+
&-hours,
|
|
152
|
+
&-minutes,
|
|
153
|
+
&-seconds {
|
|
154
|
+
display: flex;
|
|
155
|
+
align-items: center;
|
|
156
|
+
justify-content: center;
|
|
157
|
+
width: 96px;
|
|
158
|
+
height: 80px;
|
|
159
|
+
font-size: 3.5rem;
|
|
160
|
+
font-weight: 400;
|
|
161
|
+
border: none;
|
|
162
|
+
background: transparent;
|
|
163
|
+
cursor: pointer;
|
|
164
|
+
|
|
165
|
+
&[data-active="true"] {
|
|
166
|
+
color: t.color('primary');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Style for HTML input elements
|
|
170
|
+
&[type="number"] {
|
|
171
|
+
font-size: 3.5rem;
|
|
172
|
+
font-weight: 400;
|
|
173
|
+
width: 96px;
|
|
174
|
+
height: 76px;
|
|
175
|
+
text-align: center;
|
|
176
|
+
border: none;
|
|
177
|
+
background-color: t.color('surface-container-highest');
|
|
178
|
+
border-radius: f.get-shape('small');
|
|
179
|
+
padding: 0;
|
|
180
|
+
margin: 0;
|
|
181
|
+
color: t.color('on-surface');
|
|
182
|
+
|
|
183
|
+
&:focus {
|
|
184
|
+
outline: none;
|
|
185
|
+
box-shadow: 0 0 0 2px t.color('primary');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Remove spinner arrows
|
|
189
|
+
-moz-appearance: textfield;
|
|
190
|
+
&::-webkit-outer-spin-button,
|
|
191
|
+
&::-webkit-inner-spin-button {
|
|
192
|
+
-webkit-appearance: none;
|
|
193
|
+
margin: 0;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// When in dial mode, add highlighting for active element
|
|
198
|
+
&:not([type="number"]) {
|
|
199
|
+
&[data-active="true"] {
|
|
200
|
+
color: t.color('primary');
|
|
201
|
+
background-color: t.alpha('primary', 0.1);
|
|
202
|
+
border-radius: f.get-shape('small');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
&:hover {
|
|
206
|
+
background-color: t.alpha('on-surface', 0.04);
|
|
207
|
+
border-radius: f.get-shape('small');
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Separator between hours, minutes, seconds
|
|
213
|
+
&-separator {
|
|
214
|
+
font-size: 3.5rem;
|
|
215
|
+
font-weight: 400;
|
|
216
|
+
margin: 0 4px;
|
|
217
|
+
color: t.color('on-surface-variant');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Period selector (AM/PM)
|
|
221
|
+
&-period {
|
|
222
|
+
display: flex;
|
|
223
|
+
flex-direction: column;
|
|
224
|
+
justify-content: space-between;
|
|
225
|
+
background-color: t.color('surface-container-highest');
|
|
226
|
+
border-radius: f.get-shape('small');
|
|
227
|
+
overflow: hidden;
|
|
228
|
+
border: 1px solid t.color('outline-variant');
|
|
229
|
+
margin-left: 16px;
|
|
230
|
+
|
|
231
|
+
&-am,
|
|
232
|
+
&-pm {
|
|
233
|
+
display: flex;
|
|
234
|
+
align-items: center;
|
|
235
|
+
justify-content: center;
|
|
236
|
+
width: 100%;
|
|
237
|
+
height: 50%;
|
|
238
|
+
padding: 8px;
|
|
239
|
+
cursor: pointer;
|
|
240
|
+
@include m.typography('title-medium');
|
|
241
|
+
|
|
242
|
+
// Improve touch target sizes on mobile
|
|
243
|
+
@media (max-width: 599px) {
|
|
244
|
+
min-height: 48px;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Improve focus styles for keyboard navigation
|
|
248
|
+
&:focus-visible {
|
|
249
|
+
outline: 2px solid t.color('primary');
|
|
250
|
+
outline-offset: 2px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
&:hover {
|
|
254
|
+
background-color: t.alpha('on-surface', 0.08);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
&:active {
|
|
258
|
+
background-color: t.alpha('on-surface', 0.12);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
&--selected {
|
|
263
|
+
background-color: t.color('primary-container');
|
|
264
|
+
color: t.color('on-primary-container');
|
|
265
|
+
|
|
266
|
+
&:hover {
|
|
267
|
+
background-color: t.color('primary-container');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Clock dial
|
|
273
|
+
&-dial {
|
|
274
|
+
display: flex;
|
|
275
|
+
align-items: center;
|
|
276
|
+
justify-content: center;
|
|
277
|
+
position: relative;
|
|
278
|
+
margin: 0 auto 24px;
|
|
279
|
+
width: 256px;
|
|
280
|
+
height: 256px;
|
|
281
|
+
|
|
282
|
+
&-canvas {
|
|
283
|
+
display: block;
|
|
284
|
+
width: 100%;
|
|
285
|
+
height: 100%;
|
|
286
|
+
border-radius: 50%;
|
|
287
|
+
cursor: pointer;
|
|
288
|
+
touch-action: none; // Prevent scrolling when touching the canvas
|
|
289
|
+
-webkit-tap-highlight-color: transparent; // Remove highlight on tap (mobile)
|
|
290
|
+
|
|
291
|
+
// Add transition for smooth animations
|
|
292
|
+
transition: transform 0.2s ease;
|
|
293
|
+
|
|
294
|
+
&:focus {
|
|
295
|
+
outline: none;
|
|
296
|
+
box-shadow: 0 0 0 2px t.color('primary');
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Actions footer
|
|
302
|
+
&-actions {
|
|
303
|
+
display: flex;
|
|
304
|
+
align-items: center;
|
|
305
|
+
justify-content: space-between;
|
|
306
|
+
padding: 16px 24px 24px;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
&-toggle-type {
|
|
310
|
+
background: transparent;
|
|
311
|
+
border: none;
|
|
312
|
+
padding: 8px;
|
|
313
|
+
border-radius: 50%;
|
|
314
|
+
cursor: pointer;
|
|
315
|
+
color: t.color('on-surface-variant');
|
|
316
|
+
|
|
317
|
+
// Improve touch target sizes on mobile
|
|
318
|
+
@media (max-width: 599px) {
|
|
319
|
+
min-height: 48px;
|
|
320
|
+
min-width: 48px;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Improve focus styles for keyboard navigation
|
|
324
|
+
&:focus-visible {
|
|
325
|
+
outline: 2px solid t.color('primary');
|
|
326
|
+
outline-offset: 2px;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
&:hover {
|
|
330
|
+
background-color: t.alpha('on-surface', 0.08);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
&:active {
|
|
334
|
+
background-color: t.alpha('on-surface', 0.12);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
svg {
|
|
338
|
+
width: 24px;
|
|
339
|
+
height: 24px;
|
|
340
|
+
display: block;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
&-action-buttons {
|
|
345
|
+
display: flex;
|
|
346
|
+
gap: 8px;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
&-cancel,
|
|
350
|
+
&-confirm {
|
|
351
|
+
padding: 10px 12px;
|
|
352
|
+
border: none;
|
|
353
|
+
background: transparent;
|
|
354
|
+
border-radius: f.get-shape('small');
|
|
355
|
+
cursor: pointer;
|
|
356
|
+
@include m.typography('label-large');
|
|
357
|
+
color: t.color('primary');
|
|
358
|
+
|
|
359
|
+
// Improve touch target sizes on mobile
|
|
360
|
+
@media (max-width: 599px) {
|
|
361
|
+
min-height: 48px;
|
|
362
|
+
padding: 12px 16px;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Improve focus styles for keyboard navigation
|
|
366
|
+
&:focus-visible {
|
|
367
|
+
outline: 2px solid t.color('primary');
|
|
368
|
+
outline-offset: 2px;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
&:hover {
|
|
372
|
+
background-color: t.alpha('primary', 0.08);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
&:active {
|
|
376
|
+
background-color: t.alpha('primary', 0.12);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Responsive adjustments
|
|
381
|
+
@media (max-width: 599px) {
|
|
382
|
+
&-dialog {
|
|
383
|
+
width: 100%;
|
|
384
|
+
max-width: 100%;
|
|
385
|
+
min-height: 460px;
|
|
386
|
+
border-radius: 0;
|
|
387
|
+
margin: 0;
|
|
388
|
+
|
|
389
|
+
&--horizontal {
|
|
390
|
+
flex-direction: column;
|
|
391
|
+
|
|
392
|
+
.#{$component}-content {
|
|
393
|
+
flex-direction: column;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.#{$component}-dial {
|
|
397
|
+
margin-left: 0;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
&-input-container {
|
|
403
|
+
margin: 16px 0;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Smaller inputs on mobile
|
|
407
|
+
&-hours,
|
|
408
|
+
&-minutes,
|
|
409
|
+
&-seconds {
|
|
410
|
+
width: 80px;
|
|
411
|
+
height: 76px;
|
|
412
|
+
font-size: 3rem;
|
|
413
|
+
|
|
414
|
+
&[type="number"] {
|
|
415
|
+
width: 80px;
|
|
416
|
+
height: 76px;
|
|
417
|
+
font-size: 3rem;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Dark mode adjustments
|
|
423
|
+
@media (prefers-color-scheme: dark) {
|
|
424
|
+
&-dialog {
|
|
425
|
+
&::before {
|
|
426
|
+
opacity: 0.08;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
&-hours,
|
|
431
|
+
&-minutes,
|
|
432
|
+
&-seconds {
|
|
433
|
+
&[type="number"] {
|
|
434
|
+
background-color: t.alpha('on-surface', 0.05);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Accessibility
|
|
440
|
+
&-sr-only {
|
|
441
|
+
position: absolute;
|
|
442
|
+
width: 1px;
|
|
443
|
+
height: 1px;
|
|
444
|
+
padding: 0;
|
|
445
|
+
margin: -1px;
|
|
446
|
+
overflow: hidden;
|
|
447
|
+
clip: rect(0, 0, 0, 0);
|
|
448
|
+
white-space: nowrap;
|
|
449
|
+
border: 0;
|
|
450
|
+
}
|
|
451
|
+
}
|