mtrl 0.2.5 → 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 +123 -115
- 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 -66
- package/src/components/button/api.ts +5 -0
- package/src/components/button/button.ts +0 -2
- package/src/components/button/config.ts +5 -0
- package/src/components/button/constants.ts +0 -6
- package/src/components/button/index.ts +2 -2
- package/src/components/button/types.ts +7 -7
- package/src/components/card/_styles.scss +67 -25
- package/src/components/card/api.ts +54 -3
- package/src/components/card/card.ts +25 -6
- package/src/components/card/config.ts +189 -22
- package/src/components/card/constants.ts +20 -19
- package/src/components/card/content.ts +299 -2
- package/src/components/card/features.ts +158 -4
- package/src/components/card/index.ts +31 -9
- package/src/components/card/types.ts +166 -15
- package/src/components/checkbox/_styles.scss +0 -2
- package/src/components/chip/chip.ts +1 -9
- package/src/components/chip/constants.ts +0 -10
- package/src/components/chip/index.ts +1 -1
- package/src/components/chip/types.ts +1 -4
- 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/progress/_styles.scss +0 -65
- package/src/components/progress/config.ts +1 -2
- package/src/components/progress/constants.ts +0 -14
- package/src/components/progress/index.ts +1 -1
- package/src/components/progress/progress.ts +1 -4
- package/src/components/progress/types.ts +1 -4
- package/src/components/radios/_styles.scss +0 -45
- package/src/components/radios/api.ts +85 -60
- package/src/components/radios/config.ts +1 -2
- package/src/components/radios/constants.ts +0 -9
- package/src/components/radios/index.ts +1 -1
- package/src/components/radios/radio.ts +34 -11
- package/src/components/radios/radios.ts +2 -1
- package/src/components/radios/types.ts +1 -7
- 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 +221 -168
- package/src/components/slider/accessibility.md +59 -0
- package/src/components/slider/api.ts +41 -120
- package/src/components/slider/config.ts +51 -49
- 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 +141 -184
- package/src/components/slider/features/ui.ts +150 -201
- 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 +346 -154
- package/src/components/tabs/api.ts +178 -400
- package/src/components/tabs/config.ts +46 -52
- package/src/components/tabs/constants.ts +85 -8
- package/src/components/tabs/features.ts +403 -0
- package/src/components/tabs/index.ts +60 -3
- package/src/components/tabs/indicator.ts +285 -0
- package/src/components/tabs/responsive.ts +144 -0
- package/src/components/tabs/scroll-indicators.ts +149 -0
- package/src/components/tabs/state.ts +186 -0
- package/src/components/tabs/tab-api.ts +258 -0
- package/src/components/tabs/tab.ts +255 -0
- package/src/components/tabs/tabs.ts +50 -31
- package/src/components/tabs/types.ts +332 -128
- package/src/components/tabs/utils.ts +107 -0
- package/src/components/textfield/_styles.scss +0 -98
- package/src/components/textfield/config.ts +2 -3
- package/src/components/textfield/constants.ts +0 -14
- package/src/components/textfield/index.ts +2 -2
- package/src/components/textfield/textfield.ts +0 -2
- package/src/components/textfield/types.ts +1 -4
- 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/component.ts +1 -1
- package/src/core/compose/features/badge.ts +79 -0
- package/src/core/compose/features/icon.ts +3 -1
- package/src/core/compose/features/index.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 +115 -3
- 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/card/actions.ts +0 -48
- package/src/components/card/header.ts +0 -88
- package/src/components/card/media.ts +0 -52
- 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 -43
- package/src/components/slider/features/events.ts +0 -164
- package/src/components/slider/features/interactions.ts +0 -261
- package/src/components/slider/features/keyboard.ts +0 -112
- package/src/core/collection/adapters/mongodb.js +0 -232
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// src/components/tabs/utils.ts
|
|
2
|
+
import { TabsComponent, TabComponent } from './types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Gets the active tab from a component
|
|
6
|
+
* @param component - Component with tabs
|
|
7
|
+
* @returns Active tab or null
|
|
8
|
+
*/
|
|
9
|
+
export function getActiveTab(component: any): TabComponent | null {
|
|
10
|
+
// First try the standard method
|
|
11
|
+
if (typeof component.getActiveTab === 'function') {
|
|
12
|
+
return component.getActiveTab();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Fallback: check if component has tabs array
|
|
16
|
+
if (Array.isArray(component.tabs)) {
|
|
17
|
+
return component.tabs.find(tab => tab.isActive && tab.isActive());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// If all else fails, return null
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Updates tab panels based on active tab
|
|
26
|
+
* @param component - Component with tabs
|
|
27
|
+
*/
|
|
28
|
+
export function updateTabPanels(component: any): void {
|
|
29
|
+
// Get active tab using our helper function
|
|
30
|
+
const activeTab = getActiveTab(component);
|
|
31
|
+
if (!activeTab) return;
|
|
32
|
+
|
|
33
|
+
// Make sure getValue exists
|
|
34
|
+
if (typeof activeTab.getValue !== 'function') return;
|
|
35
|
+
|
|
36
|
+
const activeValue = activeTab.getValue();
|
|
37
|
+
|
|
38
|
+
// Find all tab panels in the document
|
|
39
|
+
const tabPanels = document.querySelectorAll(`[role="tabpanel"]`);
|
|
40
|
+
|
|
41
|
+
tabPanels.forEach(panel => {
|
|
42
|
+
// Get the associated tab value
|
|
43
|
+
const forTab = panel.getAttribute('aria-labelledby')?.replace('tab-', '');
|
|
44
|
+
|
|
45
|
+
if (forTab === activeValue) {
|
|
46
|
+
panel.removeAttribute('hidden');
|
|
47
|
+
panel.setAttribute('tabindex', '0');
|
|
48
|
+
} else {
|
|
49
|
+
panel.setAttribute('hidden', 'true');
|
|
50
|
+
panel.setAttribute('tabindex', '-1');
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Sets up keyboard navigation for tabs
|
|
57
|
+
* @param component - Tabs component
|
|
58
|
+
*/
|
|
59
|
+
export function setupKeyboardNavigation(component: any): void {
|
|
60
|
+
// Skip if element is missing
|
|
61
|
+
if (!component.element) return;
|
|
62
|
+
|
|
63
|
+
component.element.addEventListener('keydown', (event: KeyboardEvent) => {
|
|
64
|
+
// Only handle arrow keys when tabs container has focus
|
|
65
|
+
if (event.target !== event.currentTarget) return;
|
|
66
|
+
|
|
67
|
+
// Skip if getTabs or setActiveTab don't exist
|
|
68
|
+
if (typeof component.getTabs !== 'function' ||
|
|
69
|
+
typeof component.setActiveTab !== 'function') return;
|
|
70
|
+
|
|
71
|
+
const tabs = component.getTabs();
|
|
72
|
+
const currentTab = getActiveTab(component);
|
|
73
|
+
const currentIndex = currentTab ? tabs.indexOf(currentTab) : -1;
|
|
74
|
+
|
|
75
|
+
let newIndex = currentIndex;
|
|
76
|
+
|
|
77
|
+
switch (event.key) {
|
|
78
|
+
case 'ArrowRight':
|
|
79
|
+
case 'ArrowDown':
|
|
80
|
+
newIndex = currentIndex < tabs.length - 1 ? currentIndex + 1 : 0;
|
|
81
|
+
break;
|
|
82
|
+
|
|
83
|
+
case 'ArrowLeft':
|
|
84
|
+
case 'ArrowUp':
|
|
85
|
+
newIndex = currentIndex > 0 ? currentIndex - 1 : tabs.length - 1;
|
|
86
|
+
break;
|
|
87
|
+
|
|
88
|
+
case 'Home':
|
|
89
|
+
newIndex = 0;
|
|
90
|
+
break;
|
|
91
|
+
|
|
92
|
+
case 'End':
|
|
93
|
+
newIndex = tabs.length - 1;
|
|
94
|
+
break;
|
|
95
|
+
|
|
96
|
+
default:
|
|
97
|
+
return; // Don't handle other keys
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// If a new tab should be focused
|
|
101
|
+
if (newIndex !== currentIndex && tabs[newIndex]) {
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
tabs[newIndex].element.focus();
|
|
104
|
+
component.setActiveTab(tabs[newIndex]);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
@@ -14,104 +14,6 @@ $component: '#{base.$prefix}-textfield';
|
|
|
14
14
|
display: inline-flex;
|
|
15
15
|
flex-direction: column;
|
|
16
16
|
min-width: 210px;
|
|
17
|
-
|
|
18
|
-
// Size variants
|
|
19
|
-
&--small {
|
|
20
|
-
.#{$component}-input {
|
|
21
|
-
height: 40px;
|
|
22
|
-
font-size: 14px;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.#{$component}-label {
|
|
26
|
-
font-size: 14px;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.#{$component}-helper {
|
|
30
|
-
font-size: 11px;
|
|
31
|
-
margin-top: 2px;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
&.#{$component}--filled {
|
|
35
|
-
.#{$component}-input {
|
|
36
|
-
padding: 16px 12px 6px;
|
|
37
|
-
|
|
38
|
-
&:focus {
|
|
39
|
-
padding-bottom: 5px;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
&:not(.#{$component}--empty) .#{$component}-label,
|
|
44
|
-
&.#{$component}--focused .#{$component}-label {
|
|
45
|
-
transform: translateY(-85%) scale(0.75);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
&.#{$component}--outlined {
|
|
50
|
-
.#{$component}-input {
|
|
51
|
-
padding: 10px 12px 11px;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
&:not(.#{$component}--empty) .#{$component}-label,
|
|
55
|
-
&.#{$component}--focused .#{$component}-label {
|
|
56
|
-
transform: translateY(-130%) scale(0.75);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
&.#{$component}--focused .#{$component}-input {
|
|
60
|
-
height: 38px;
|
|
61
|
-
padding: 9px 11px 10px;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
&--medium {
|
|
67
|
-
// Default size, styles already defined in base
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
&--large {
|
|
71
|
-
.#{$component}-input {
|
|
72
|
-
height: 64px;
|
|
73
|
-
font-size: 16px;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.#{$component}-label {
|
|
77
|
-
font-size: 16px;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.#{$component}-helper {
|
|
81
|
-
font-size: 13px;
|
|
82
|
-
margin-top: 6px;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
&.#{$component}--filled {
|
|
86
|
-
.#{$component}-input {
|
|
87
|
-
padding: 26px 20px 8px;
|
|
88
|
-
|
|
89
|
-
&:focus {
|
|
90
|
-
padding-bottom: 7px;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
&:not(.#{$component}--empty) .#{$component}-label,
|
|
95
|
-
&.#{$component}--focused .#{$component}-label {
|
|
96
|
-
transform: translateY(-110%) scale(0.75);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
&.#{$component}--outlined {
|
|
101
|
-
.#{$component}-input {
|
|
102
|
-
padding: 16px 20px 17px;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
&:not(.#{$component}--empty) .#{$component}-label,
|
|
106
|
-
&.#{$component}--focused .#{$component}-label {
|
|
107
|
-
transform: translateY(-170%) scale(0.75);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
&.#{$component}--focused .#{$component}-input {
|
|
111
|
-
padding: 15px 19px 16px;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
17
|
|
|
116
18
|
// Label
|
|
117
19
|
&-label {
|
|
@@ -5,15 +5,14 @@ import {
|
|
|
5
5
|
BaseComponentConfig
|
|
6
6
|
} from '../../core/config/component-config';
|
|
7
7
|
import { TextfieldConfig, BaseComponent, ApiOptions } from './types';
|
|
8
|
-
import { TEXTFIELD_VARIANTS, TEXTFIELD_TYPES
|
|
8
|
+
import { TEXTFIELD_VARIANTS, TEXTFIELD_TYPES } from './constants';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Default configuration for the Textfield component
|
|
12
12
|
*/
|
|
13
13
|
export const defaultConfig: TextfieldConfig = {
|
|
14
14
|
type: TEXTFIELD_TYPES.TEXT,
|
|
15
|
-
variant: TEXTFIELD_VARIANTS.FILLED
|
|
16
|
-
size: TEXTFIELD_SIZES.MEDIUM
|
|
15
|
+
variant: TEXTFIELD_VARIANTS.FILLED
|
|
17
16
|
};
|
|
18
17
|
|
|
19
18
|
/**
|
|
@@ -8,15 +8,6 @@ export const TEXTFIELD_VARIANTS = {
|
|
|
8
8
|
OUTLINED: 'outlined'
|
|
9
9
|
} as const;
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* Textfield size variants
|
|
13
|
-
*/
|
|
14
|
-
export const TEXTFIELD_SIZES = {
|
|
15
|
-
SMALL: 'small',
|
|
16
|
-
MEDIUM: 'medium',
|
|
17
|
-
LARGE: 'large'
|
|
18
|
-
} as const;
|
|
19
|
-
|
|
20
11
|
/**
|
|
21
12
|
* Textfield input types
|
|
22
13
|
*/
|
|
@@ -45,11 +36,6 @@ export const TEXTFIELD_SCHEMA = {
|
|
|
45
36
|
enum: Object.values(TEXTFIELD_VARIANTS),
|
|
46
37
|
required: false
|
|
47
38
|
},
|
|
48
|
-
size: {
|
|
49
|
-
type: 'string',
|
|
50
|
-
enum: Object.values(TEXTFIELD_SIZES),
|
|
51
|
-
required: false
|
|
52
|
-
},
|
|
53
39
|
name: {
|
|
54
40
|
type: 'string',
|
|
55
41
|
required: false
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// src/components/textfield/index.ts
|
|
2
2
|
export { default } from './textfield'
|
|
3
|
-
export { TEXTFIELD_VARIANTS,
|
|
4
|
-
export { TextfieldConfig, TextfieldComponent } from './types'
|
|
3
|
+
export { TEXTFIELD_VARIANTS, TEXTFIELD_TYPES } from './constants'
|
|
4
|
+
export { TextfieldConfig, TextfieldComponent } from './types'
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
withDisabled,
|
|
7
7
|
withLifecycle,
|
|
8
8
|
withVariant,
|
|
9
|
-
withSize,
|
|
10
9
|
withTextInput,
|
|
11
10
|
withTextLabel
|
|
12
11
|
} from '../../core/compose/features';
|
|
@@ -32,7 +31,6 @@ const createTextfield = (config: TextfieldConfig = {}): TextfieldComponent => {
|
|
|
32
31
|
withEvents(),
|
|
33
32
|
withElement(getElementConfig(baseConfig)),
|
|
34
33
|
withVariant(baseConfig),
|
|
35
|
-
withSize(baseConfig),
|
|
36
34
|
withTextInput(baseConfig),
|
|
37
35
|
withTextLabel(baseConfig),
|
|
38
36
|
withDisabled(baseConfig),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/components/textfield/types.ts
|
|
2
|
-
import { TEXTFIELD_VARIANTS,
|
|
2
|
+
import { TEXTFIELD_VARIANTS, TEXTFIELD_TYPES } from './constants';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Configuration interface for the Textfield component
|
|
@@ -11,9 +11,6 @@ export interface TextfieldConfig {
|
|
|
11
11
|
/** Visual variant (filled, outlined) */
|
|
12
12
|
variant?: keyof typeof TEXTFIELD_VARIANTS | string;
|
|
13
13
|
|
|
14
|
-
/** Size variant (small, medium, large) */
|
|
15
|
-
size?: keyof typeof TEXTFIELD_SIZES | string;
|
|
16
|
-
|
|
17
14
|
/** Input name attribute */
|
|
18
15
|
name?: string;
|
|
19
16
|
|
|
@@ -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
|
+
```
|