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.
Files changed (147) hide show
  1. package/index.ts +18 -0
  2. package/package.json +1 -1
  3. package/src/components/badge/_styles.scss +117 -109
  4. package/src/components/badge/api.ts +57 -59
  5. package/src/components/badge/badge.ts +16 -2
  6. package/src/components/badge/config.ts +65 -11
  7. package/src/components/badge/constants.ts +22 -12
  8. package/src/components/badge/features.ts +44 -40
  9. package/src/components/badge/types.ts +42 -30
  10. package/src/components/bottom-app-bar/_styles.scss +103 -0
  11. package/src/components/bottom-app-bar/bottom-app-bar.ts +196 -0
  12. package/src/components/bottom-app-bar/config.ts +73 -0
  13. package/src/components/bottom-app-bar/index.ts +11 -0
  14. package/src/components/bottom-app-bar/types.ts +108 -0
  15. package/src/components/button/_styles.scss +0 -10
  16. package/src/components/button/api.ts +5 -0
  17. package/src/components/button/config.ts +5 -0
  18. package/src/components/button/types.ts +6 -0
  19. package/src/components/card/card.ts +13 -25
  20. package/src/components/card/config.ts +67 -22
  21. package/src/components/card/features.ts +3 -0
  22. package/src/components/card/types.ts +28 -0
  23. package/src/components/checkbox/_styles.scss +0 -2
  24. package/src/components/datepicker/_styles.scss +358 -0
  25. package/src/components/datepicker/api.ts +272 -0
  26. package/src/components/datepicker/config.ts +144 -0
  27. package/src/components/datepicker/constants.ts +98 -0
  28. package/src/components/datepicker/datepicker.ts +346 -0
  29. package/src/components/datepicker/index.ts +9 -0
  30. package/src/components/datepicker/render.ts +452 -0
  31. package/src/components/datepicker/types.ts +268 -0
  32. package/src/components/datepicker/utils.ts +290 -0
  33. package/src/components/dialog/_styles.scss +174 -128
  34. package/src/components/dialog/api.ts +48 -13
  35. package/src/components/dialog/config.ts +9 -5
  36. package/src/components/dialog/dialog.ts +6 -3
  37. package/src/components/dialog/features.ts +290 -130
  38. package/src/components/dialog/types.ts +7 -4
  39. package/src/components/divider/_styles.scss +57 -0
  40. package/src/components/divider/config.ts +81 -0
  41. package/src/components/divider/divider.ts +37 -0
  42. package/src/components/divider/features.ts +207 -0
  43. package/src/components/divider/index.ts +5 -0
  44. package/src/components/divider/types.ts +55 -0
  45. package/src/components/extended-fab/_styles.scss +267 -0
  46. package/src/components/extended-fab/api.ts +141 -0
  47. package/src/components/extended-fab/config.ts +108 -0
  48. package/src/components/extended-fab/constants.ts +36 -0
  49. package/src/components/extended-fab/extended-fab.ts +125 -0
  50. package/src/components/extended-fab/index.ts +4 -0
  51. package/src/components/extended-fab/types.ts +287 -0
  52. package/src/components/fab/_styles.scss +225 -0
  53. package/src/components/fab/api.ts +97 -0
  54. package/src/components/fab/config.ts +94 -0
  55. package/src/components/fab/constants.ts +41 -0
  56. package/src/components/fab/fab.ts +67 -0
  57. package/src/components/fab/index.ts +4 -0
  58. package/src/components/fab/types.ts +234 -0
  59. package/src/components/navigation/_styles.scss +1 -0
  60. package/src/components/navigation/api.ts +78 -50
  61. package/src/components/navigation/features/items.ts +280 -0
  62. package/src/components/navigation/nav-item.ts +72 -23
  63. package/src/components/navigation/navigation.ts +54 -2
  64. package/src/components/navigation/types.ts +210 -188
  65. package/src/components/search/_styles.scss +306 -0
  66. package/src/components/search/api.ts +203 -0
  67. package/src/components/search/config.ts +87 -0
  68. package/src/components/search/constants.ts +21 -0
  69. package/src/components/search/features/index.ts +4 -0
  70. package/src/components/search/features/search.ts +718 -0
  71. package/src/components/search/features/states.ts +165 -0
  72. package/src/components/search/features/structure.ts +198 -0
  73. package/src/components/search/index.ts +10 -0
  74. package/src/components/search/search.ts +52 -0
  75. package/src/components/search/types.ts +163 -0
  76. package/src/components/segmented-button/_styles.scss +117 -0
  77. package/src/components/segmented-button/config.ts +67 -0
  78. package/src/components/segmented-button/constants.ts +42 -0
  79. package/src/components/segmented-button/index.ts +4 -0
  80. package/src/components/segmented-button/segment.ts +155 -0
  81. package/src/components/segmented-button/segmented-button.ts +250 -0
  82. package/src/components/segmented-button/types.ts +219 -0
  83. package/src/components/slider/_styles.scss +83 -24
  84. package/src/components/slider/accessibility.md +5 -5
  85. package/src/components/slider/api.ts +41 -120
  86. package/src/components/slider/config.ts +51 -47
  87. package/src/components/slider/features/handlers.ts +495 -0
  88. package/src/components/slider/features/index.ts +1 -2
  89. package/src/components/slider/features/slider.ts +66 -84
  90. package/src/components/slider/features/states.ts +195 -0
  91. package/src/components/slider/features/structure.ts +136 -206
  92. package/src/components/slider/features/ui.ts +145 -206
  93. package/src/components/slider/index.ts +2 -11
  94. package/src/components/slider/slider.ts +9 -12
  95. package/src/components/slider/types.ts +39 -24
  96. package/src/components/switch/_styles.scss +0 -2
  97. package/src/components/tabs/_styles.scss +94 -32
  98. package/src/components/tabs/features.ts +4 -2
  99. package/src/components/tabs/indicator.ts +73 -13
  100. package/src/components/tabs/types.ts +10 -2
  101. package/src/components/timepicker/README.md +277 -0
  102. package/src/components/timepicker/_styles.scss +451 -0
  103. package/src/components/timepicker/api.ts +632 -0
  104. package/src/components/timepicker/clockdial.ts +482 -0
  105. package/src/components/timepicker/config.ts +130 -0
  106. package/src/components/timepicker/constants.ts +138 -0
  107. package/src/components/timepicker/index.ts +8 -0
  108. package/src/components/timepicker/render.ts +613 -0
  109. package/src/components/timepicker/timepicker.ts +117 -0
  110. package/src/components/timepicker/types.ts +336 -0
  111. package/src/components/timepicker/utils.ts +241 -0
  112. package/src/components/top-app-bar/_styles.scss +225 -0
  113. package/src/components/top-app-bar/config.ts +83 -0
  114. package/src/components/top-app-bar/index.ts +11 -0
  115. package/src/components/top-app-bar/top-app-bar.ts +316 -0
  116. package/src/components/top-app-bar/types.ts +140 -0
  117. package/src/core/build/_ripple.scss +6 -6
  118. package/src/core/build/ripple.ts +72 -95
  119. package/src/core/compose/features/icon.ts +3 -1
  120. package/src/core/compose/features/ripple.ts +4 -1
  121. package/src/core/compose/features/textlabel.ts +26 -2
  122. package/src/core/dom/create.ts +5 -0
  123. package/src/index.ts +9 -0
  124. package/src/styles/abstract/_theme.scss +9 -1
  125. package/src/styles/themes/_autumn.scss +21 -0
  126. package/src/styles/themes/_base-theme.scss +61 -0
  127. package/src/styles/themes/_baseline.scss +58 -0
  128. package/src/styles/themes/_bluekhaki.scss +125 -0
  129. package/src/styles/themes/_brownbeige.scss +125 -0
  130. package/src/styles/themes/_browngreen.scss +125 -0
  131. package/src/styles/themes/_forest.scss +6 -0
  132. package/src/styles/themes/_greenbeige.scss +125 -0
  133. package/src/styles/themes/_material.scss +125 -0
  134. package/src/styles/themes/_ocean.scss +6 -0
  135. package/src/styles/themes/_sageivory.scss +125 -0
  136. package/src/styles/themes/_spring.scss +6 -0
  137. package/src/styles/themes/_summer.scss +5 -0
  138. package/src/styles/themes/_sunset.scss +5 -0
  139. package/src/styles/themes/_tealcaramel.scss +125 -0
  140. package/src/styles/themes/_winter.scss +6 -0
  141. package/src/components/navigation/features/items.js +0 -192
  142. package/src/components/slider/features/appearance.ts +0 -94
  143. package/src/components/slider/features/disabled.ts +0 -68
  144. package/src/components/slider/features/events.ts +0 -164
  145. package/src/components/slider/features/interactions.ts +0 -396
  146. package/src/components/slider/features/keyboard.ts +0 -233
  147. 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
+ }