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,196 @@
|
|
|
1
|
+
// src/components/bottom-app-bar/bottom-app-bar.ts
|
|
2
|
+
/**
|
|
3
|
+
* @module components/bottom-app-bar
|
|
4
|
+
* @description Bottom app bar implementation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
createBase,
|
|
9
|
+
withElement,
|
|
10
|
+
withEvents,
|
|
11
|
+
withLifecycle,
|
|
12
|
+
ElementComponent,
|
|
13
|
+
BaseComponent
|
|
14
|
+
} from '../../core/compose';
|
|
15
|
+
|
|
16
|
+
import { createConfig, BottomAppBarConfig } from './config';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Bottom app bar component interface
|
|
20
|
+
*/
|
|
21
|
+
export interface BottomAppBar extends ElementComponent {
|
|
22
|
+
/**
|
|
23
|
+
* Adds an action button to the bottom bar
|
|
24
|
+
* @param {HTMLElement} button - Button element to add
|
|
25
|
+
* @returns {BottomAppBar} BottomAppBar instance for chaining
|
|
26
|
+
*/
|
|
27
|
+
addAction: (button: HTMLElement) => BottomAppBar;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Adds a floating action button to the bottom bar
|
|
31
|
+
* @param {HTMLElement} fab - FAB element to add
|
|
32
|
+
* @returns {BottomAppBar} BottomAppBar instance for chaining
|
|
33
|
+
*/
|
|
34
|
+
addFab: (fab: HTMLElement) => BottomAppBar;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Shows the bottom bar
|
|
38
|
+
* @returns {BottomAppBar} BottomAppBar instance for chaining
|
|
39
|
+
*/
|
|
40
|
+
show: () => BottomAppBar;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Hides the bottom bar
|
|
44
|
+
* @returns {BottomAppBar} BottomAppBar instance for chaining
|
|
45
|
+
*/
|
|
46
|
+
hide: () => BottomAppBar;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Checks if the bottom bar is visible
|
|
50
|
+
* @returns {boolean} Whether the bottom bar is visible
|
|
51
|
+
*/
|
|
52
|
+
isVisible: () => boolean;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Get the actions container element
|
|
56
|
+
* @returns {HTMLElement} Actions container element
|
|
57
|
+
*/
|
|
58
|
+
getActionsContainer: () => HTMLElement;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Creates a bottom app bar component
|
|
63
|
+
*
|
|
64
|
+
* @param {BottomAppBarConfig} config - Configuration options
|
|
65
|
+
* @returns {BottomAppBar} Bottom app bar component instance
|
|
66
|
+
*/
|
|
67
|
+
export const createBottomAppBar = (config: BottomAppBarConfig = {}): BottomAppBar => {
|
|
68
|
+
// Process configuration with defaults
|
|
69
|
+
const componentConfig = createConfig(config);
|
|
70
|
+
|
|
71
|
+
// Create base component
|
|
72
|
+
const component = createBase(componentConfig);
|
|
73
|
+
|
|
74
|
+
// Create actions container
|
|
75
|
+
const actionsContainer = document.createElement('div');
|
|
76
|
+
actionsContainer.className = `${component.getClass('bottom-app-bar')}-actions`;
|
|
77
|
+
|
|
78
|
+
// FAB container for proper positioning
|
|
79
|
+
const fabContainer = document.createElement('div');
|
|
80
|
+
fabContainer.className = `${component.getClass('bottom-app-bar')}-fab-container`;
|
|
81
|
+
|
|
82
|
+
// Apply Element enhancer
|
|
83
|
+
const enhancedComponent = withElement({
|
|
84
|
+
tag: componentConfig.tag,
|
|
85
|
+
componentName: 'bottom-app-bar',
|
|
86
|
+
className: [
|
|
87
|
+
componentConfig.hasFab ? `${component.getClass('bottom-app-bar')}--with-fab` : '',
|
|
88
|
+
componentConfig.fabPosition === 'center' ? `${component.getClass('bottom-app-bar')}--fab-center` : '',
|
|
89
|
+
componentConfig.class
|
|
90
|
+
],
|
|
91
|
+
attrs: {
|
|
92
|
+
role: 'toolbar',
|
|
93
|
+
'aria-label': 'Bottom app bar'
|
|
94
|
+
},
|
|
95
|
+
interactive: true
|
|
96
|
+
})(component);
|
|
97
|
+
|
|
98
|
+
// Apply events enhancer for component events
|
|
99
|
+
const withEventsComponent = withEvents()(enhancedComponent);
|
|
100
|
+
|
|
101
|
+
// Apply lifecycle enhancer for cleanup
|
|
102
|
+
const withLifecycleComponent = withLifecycle()(withEventsComponent);
|
|
103
|
+
|
|
104
|
+
// Append actions and FAB containers to the main element
|
|
105
|
+
withLifecycleComponent.element.appendChild(actionsContainer);
|
|
106
|
+
withLifecycleComponent.element.appendChild(fabContainer);
|
|
107
|
+
|
|
108
|
+
// Flag to track visibility
|
|
109
|
+
let isVisible = true;
|
|
110
|
+
|
|
111
|
+
// Previous scroll position for determining scroll direction
|
|
112
|
+
let prevScrollY = window.scrollY;
|
|
113
|
+
|
|
114
|
+
// Handle scrolling behavior if autoHide is enabled
|
|
115
|
+
if (componentConfig.autoHide) {
|
|
116
|
+
const handleScroll = () => {
|
|
117
|
+
const currentScrollY = window.scrollY;
|
|
118
|
+
|
|
119
|
+
// Determine scroll direction
|
|
120
|
+
if (currentScrollY > prevScrollY + 10) {
|
|
121
|
+
// Scrolling down - hide the bottom bar
|
|
122
|
+
if (isVisible) {
|
|
123
|
+
bottomBar.hide();
|
|
124
|
+
componentConfig.onVisibilityChange?.(false);
|
|
125
|
+
}
|
|
126
|
+
} else if (currentScrollY < prevScrollY - 10) {
|
|
127
|
+
// Scrolling up - show the bottom bar
|
|
128
|
+
if (!isVisible) {
|
|
129
|
+
bottomBar.show();
|
|
130
|
+
componentConfig.onVisibilityChange?.(true);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
prevScrollY = currentScrollY;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// Add scroll event listener
|
|
138
|
+
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
139
|
+
|
|
140
|
+
// Clean up event listener on destroy
|
|
141
|
+
const originalDestroy = withLifecycleComponent.lifecycle.destroy;
|
|
142
|
+
withLifecycleComponent.lifecycle.destroy = () => {
|
|
143
|
+
window.removeEventListener('scroll', handleScroll);
|
|
144
|
+
originalDestroy();
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const bottomBar: BottomAppBar = {
|
|
149
|
+
...withLifecycleComponent,
|
|
150
|
+
|
|
151
|
+
addAction(button: HTMLElement) {
|
|
152
|
+
actionsContainer.appendChild(button);
|
|
153
|
+
return this;
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
addFab(fab: HTMLElement) {
|
|
157
|
+
// Clear existing FAB if any
|
|
158
|
+
fabContainer.innerHTML = '';
|
|
159
|
+
|
|
160
|
+
// Add the new FAB
|
|
161
|
+
fabContainer.appendChild(fab);
|
|
162
|
+
|
|
163
|
+
// Update component class to indicate it has a FAB
|
|
164
|
+
this.element.classList.add(`${component.getClass('bottom-app-bar')}--with-fab`);
|
|
165
|
+
|
|
166
|
+
return this;
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
show() {
|
|
170
|
+
this.element.classList.remove(`${component.getClass('bottom-app-bar')}--hidden`);
|
|
171
|
+
isVisible = true;
|
|
172
|
+
return this;
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
hide() {
|
|
176
|
+
this.element.classList.add(`${component.getClass('bottom-app-bar')}--hidden`);
|
|
177
|
+
isVisible = false;
|
|
178
|
+
return this;
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
isVisible() {
|
|
182
|
+
return isVisible;
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
getActionsContainer() {
|
|
186
|
+
return actionsContainer;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// Set the appropriate styles for transitions if needed
|
|
191
|
+
if (componentConfig.autoHide && componentConfig.transitionDuration) {
|
|
192
|
+
bottomBar.element.style.transition = `transform ${componentConfig.transitionDuration}ms ease-in-out`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return bottomBar;
|
|
196
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/components/bottom-app-bar/config.ts
|
|
2
|
+
/**
|
|
3
|
+
* @module components/bottom-app-bar
|
|
4
|
+
* @description Configuration for bottom app bar component
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createComponentConfig, BaseComponentConfig } from '../../core/config/component-config';
|
|
8
|
+
import { PREFIX } from '../../core/config';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Configuration options for bottom app bar
|
|
12
|
+
*/
|
|
13
|
+
export interface BottomAppBarConfig extends BaseComponentConfig {
|
|
14
|
+
/**
|
|
15
|
+
* Element to use for the container
|
|
16
|
+
* @default 'div'
|
|
17
|
+
*/
|
|
18
|
+
tag?: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Whether to show FAB in the bottom bar
|
|
22
|
+
* @default false
|
|
23
|
+
*/
|
|
24
|
+
hasFab?: boolean;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* FAB position in bottom bar
|
|
28
|
+
* @default 'end'
|
|
29
|
+
*/
|
|
30
|
+
fabPosition?: 'center' | 'end';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Additional CSS classes to apply
|
|
34
|
+
*/
|
|
35
|
+
class?: string;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Whether to enable auto-hide on scroll
|
|
39
|
+
* @default false
|
|
40
|
+
*/
|
|
41
|
+
autoHide?: boolean;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Transition duration for show/hide in ms
|
|
45
|
+
* @default 300
|
|
46
|
+
*/
|
|
47
|
+
transitionDuration?: number;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Optional callback when scrolling shows/hides the bar
|
|
51
|
+
*/
|
|
52
|
+
onVisibilityChange?: (visible: boolean) => void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Default configuration for bottom app bar
|
|
57
|
+
*/
|
|
58
|
+
export const defaultConfig: Partial<BottomAppBarConfig> = {
|
|
59
|
+
tag: 'div',
|
|
60
|
+
hasFab: false,
|
|
61
|
+
fabPosition: 'end',
|
|
62
|
+
autoHide: false,
|
|
63
|
+
transitionDuration: 300
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Creates the configuration for a bottom app bar component
|
|
68
|
+
*
|
|
69
|
+
* @param {BottomAppBarConfig} config - User provided configuration
|
|
70
|
+
* @returns {BottomAppBarConfig} Complete configuration with defaults applied
|
|
71
|
+
*/
|
|
72
|
+
export const createConfig = (config: BottomAppBarConfig = {} as BottomAppBarConfig): BottomAppBarConfig =>
|
|
73
|
+
createComponentConfig(defaultConfig, config, 'bottom-app-bar') as BottomAppBarConfig;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/components/bottom-app-bar/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* @module components/bottom-app-bar
|
|
4
|
+
* @description Bottom app bar component for mobile interfaces
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createBottomAppBar } from './bottom-app-bar';
|
|
8
|
+
|
|
9
|
+
export default createBottomAppBar;
|
|
10
|
+
export { createBottomAppBar };
|
|
11
|
+
export type { BottomAppBarConfig } from './config';
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// src/components/bottom-app-bar/types.ts
|
|
2
|
+
/**
|
|
3
|
+
* @module components/bottom-app-bar
|
|
4
|
+
* @description Type definitions for Bottom App Bar component
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ElementComponent } from '../../core/compose';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Configuration options for Bottom App Bar component
|
|
11
|
+
* @category Components
|
|
12
|
+
*/
|
|
13
|
+
export interface BottomAppBarConfig {
|
|
14
|
+
/**
|
|
15
|
+
* Element to use for the container
|
|
16
|
+
* @default 'div'
|
|
17
|
+
*/
|
|
18
|
+
tag?: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Whether to show FAB in the bottom bar
|
|
22
|
+
* @default false
|
|
23
|
+
*/
|
|
24
|
+
hasFab?: boolean;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* FAB position in bottom bar
|
|
28
|
+
* @default 'end'
|
|
29
|
+
*/
|
|
30
|
+
fabPosition?: 'center' | 'end';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Additional CSS classes to apply
|
|
34
|
+
*/
|
|
35
|
+
class?: string;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Whether to enable auto-hide on scroll
|
|
39
|
+
* @default false
|
|
40
|
+
*/
|
|
41
|
+
autoHide?: boolean;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Transition duration for show/hide in ms
|
|
45
|
+
* @default 300
|
|
46
|
+
*/
|
|
47
|
+
transitionDuration?: number;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Optional callback when scrolling shows/hides the bar
|
|
51
|
+
*/
|
|
52
|
+
onVisibilityChange?: (visible: boolean) => void;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Component prefix for class names
|
|
56
|
+
* @default 'mtrl'
|
|
57
|
+
*/
|
|
58
|
+
prefix?: string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Component name for class generation
|
|
62
|
+
*/
|
|
63
|
+
componentName?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Bottom App Bar component interface
|
|
68
|
+
* @category Components
|
|
69
|
+
*/
|
|
70
|
+
export interface BottomAppBar extends ElementComponent {
|
|
71
|
+
/**
|
|
72
|
+
* Adds an action button to the bottom bar
|
|
73
|
+
* @param {HTMLElement} button - Button element to add
|
|
74
|
+
* @returns {BottomAppBar} BottomAppBar instance for chaining
|
|
75
|
+
*/
|
|
76
|
+
addAction: (button: HTMLElement) => BottomAppBar;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Adds a floating action button to the bottom bar
|
|
80
|
+
* @param {HTMLElement} fab - FAB element to add
|
|
81
|
+
* @returns {BottomAppBar} BottomAppBar instance for chaining
|
|
82
|
+
*/
|
|
83
|
+
addFab: (fab: HTMLElement) => BottomAppBar;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Shows the bottom bar
|
|
87
|
+
* @returns {BottomAppBar} BottomAppBar instance for chaining
|
|
88
|
+
*/
|
|
89
|
+
show: () => BottomAppBar;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Hides the bottom bar
|
|
93
|
+
* @returns {BottomAppBar} BottomAppBar instance for chaining
|
|
94
|
+
*/
|
|
95
|
+
hide: () => BottomAppBar;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Checks if the bottom bar is visible
|
|
99
|
+
* @returns {boolean} Whether the bottom bar is visible
|
|
100
|
+
*/
|
|
101
|
+
isVisible: () => boolean;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Get the actions container element
|
|
105
|
+
* @returns {HTMLElement} Actions container element
|
|
106
|
+
*/
|
|
107
|
+
getActionsContainer: () => HTMLElement;
|
|
108
|
+
}
|
|
@@ -96,16 +96,6 @@ $component: '#{base.$prefix}-button';
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
// Ripple container
|
|
100
|
-
.ripple {
|
|
101
|
-
position: absolute;
|
|
102
|
-
border-radius: 50%;
|
|
103
|
-
transform: scale(0);
|
|
104
|
-
pointer-events: none;
|
|
105
|
-
background-color: currentColor;
|
|
106
|
-
opacity: 0.12;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
99
|
&--disabled {
|
|
110
100
|
opacity: 0.38
|
|
111
101
|
}
|
|
@@ -73,6 +73,11 @@ export const withAPI = ({ disabled, lifecycle }: ApiOptions) =>
|
|
|
73
73
|
getIcon() {
|
|
74
74
|
return component.icon.getIcon();
|
|
75
75
|
},
|
|
76
|
+
|
|
77
|
+
setAriaLabel(label: string) {
|
|
78
|
+
component.element.setAttribute('aria-label', label);
|
|
79
|
+
return this;
|
|
80
|
+
},
|
|
76
81
|
|
|
77
82
|
destroy() {
|
|
78
83
|
lifecycle.destroy();
|
|
@@ -45,6 +45,11 @@ export const getElementConfig = (config: ButtonConfig) => {
|
|
|
45
45
|
attrs.value = config.value;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
// Add aria-label attribute for accessibility
|
|
49
|
+
if (config.ariaLabel) {
|
|
50
|
+
attrs['aria-label'] = config.ariaLabel;
|
|
51
|
+
}
|
|
52
|
+
|
|
48
53
|
return createElementConfig(config, {
|
|
49
54
|
tag: 'button',
|
|
50
55
|
attrs,
|
|
@@ -81,6 +81,12 @@ export interface ButtonConfig {
|
|
|
81
81
|
/** Opacity values for ripple start and end [start, end] */
|
|
82
82
|
opacity?: [string, string];
|
|
83
83
|
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Accessible name for the button (aria-label)
|
|
87
|
+
* Required for icon-only buttons without text
|
|
88
|
+
*/
|
|
89
|
+
ariaLabel?: string;
|
|
84
90
|
}
|
|
85
91
|
|
|
86
92
|
/**
|
|
@@ -13,7 +13,9 @@ import {
|
|
|
13
13
|
createBaseConfig,
|
|
14
14
|
getElementConfig,
|
|
15
15
|
getApiConfig,
|
|
16
|
-
withInteractiveBehavior
|
|
16
|
+
withInteractiveBehavior,
|
|
17
|
+
processInlineConfig,
|
|
18
|
+
applyInlineConfiguration
|
|
17
19
|
} from './config';
|
|
18
20
|
import { withElevation } from './features';
|
|
19
21
|
|
|
@@ -25,44 +27,30 @@ import { withElevation } from './features';
|
|
|
25
27
|
*
|
|
26
28
|
* @param {CardSchema} config - Card configuration object
|
|
27
29
|
* @returns {CardComponent} Card component instance
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```typescript
|
|
31
|
-
* // Create a basic elevated card
|
|
32
|
-
* const card = createCard();
|
|
33
|
-
*
|
|
34
|
-
* // Create a filled card with content
|
|
35
|
-
* const filledCard = createCard({
|
|
36
|
-
* variant: CardVariant.FILLED,
|
|
37
|
-
* contentConfig: { text: 'Card content' }
|
|
38
|
-
* });
|
|
39
|
-
*
|
|
40
|
-
* // Create an interactive outlined card
|
|
41
|
-
* const interactiveCard = createCard({
|
|
42
|
-
* variant: CardVariant.OUTLINED,
|
|
43
|
-
* interactive: true,
|
|
44
|
-
* clickable: true,
|
|
45
|
-
* aria: { label: 'Click to view details' }
|
|
46
|
-
* });
|
|
47
|
-
* ```
|
|
48
30
|
*/
|
|
49
31
|
const createCard = (config: CardSchema = {}): CardComponent => {
|
|
50
|
-
|
|
32
|
+
// Process inline configuration (map shorthand properties)
|
|
33
|
+
const processedConfig = processInlineConfig(config);
|
|
34
|
+
const baseConfig = createBaseConfig(processedConfig);
|
|
51
35
|
|
|
52
36
|
try {
|
|
37
|
+
// Create the core card component
|
|
53
38
|
const card = pipe(
|
|
54
39
|
createBase,
|
|
55
40
|
withEvents(),
|
|
56
41
|
withElement(getElementConfig(baseConfig)),
|
|
57
42
|
withVariant(baseConfig),
|
|
58
|
-
|
|
43
|
+
baseConfig.clickable ? withRipple(baseConfig) : (c: BaseComponent) => c,
|
|
59
44
|
withLifecycle(),
|
|
60
45
|
withInteractiveBehavior,
|
|
61
46
|
withElevation,
|
|
62
47
|
comp => withAPI(getApiConfig(comp))(comp)
|
|
63
|
-
)(baseConfig);
|
|
48
|
+
)(baseConfig) as CardComponent;
|
|
49
|
+
|
|
50
|
+
// Apply any inline configuration
|
|
51
|
+
applyInlineConfiguration(card, processedConfig);
|
|
64
52
|
|
|
65
|
-
return card
|
|
53
|
+
return card;
|
|
66
54
|
} catch (error) {
|
|
67
55
|
console.error('Card creation error:', error instanceof Error ? error.message : String(error));
|
|
68
56
|
throw new Error(`Failed to create card: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
// src/components/card/config.ts
|
|
2
|
+
|
|
2
3
|
import {
|
|
3
4
|
createComponentConfig,
|
|
4
5
|
createElementConfig
|
|
5
6
|
} from '../../core/config/component-config';
|
|
6
|
-
import { BaseComponent, CardSchema } from './types';
|
|
7
7
|
import { CARD_VARIANTS, CARD_ELEVATIONS } from './constants';
|
|
8
|
+
import {
|
|
9
|
+
createCardHeader,
|
|
10
|
+
createCardContent,
|
|
11
|
+
createCardMedia,
|
|
12
|
+
createCardActions
|
|
13
|
+
} from './content';
|
|
14
|
+
import { CardComponent, CardSchema, ButtonConfig, BaseComponent } from './types';
|
|
8
15
|
|
|
9
16
|
/**
|
|
10
17
|
* Default configuration for the Card component
|
|
@@ -19,57 +26,95 @@ export const defaultConfig: CardSchema = {
|
|
|
19
26
|
};
|
|
20
27
|
|
|
21
28
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* Creates and adds all configured elements to the card in the following order:
|
|
25
|
-
* 1. Top media elements (position='top')
|
|
26
|
-
* 2. Header element
|
|
27
|
-
* 3. Content elements
|
|
28
|
-
* 4. Bottom media elements (position='bottom')
|
|
29
|
-
* 5. Actions elements
|
|
29
|
+
* Processes inline configuration options into standard config format
|
|
30
|
+
* Maps shorthand properties to their proper config counterparts
|
|
30
31
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
32
|
+
* @param {CardSchema} config - Raw card configuration
|
|
33
|
+
* @returns {CardSchema} Processed configuration
|
|
34
|
+
*/
|
|
35
|
+
export const processInlineConfig = (config: CardSchema): CardSchema => {
|
|
36
|
+
const processedConfig: CardSchema = { ...config };
|
|
37
|
+
|
|
38
|
+
// Map inline properties to their *Config counterparts
|
|
39
|
+
if (config.header) {
|
|
40
|
+
processedConfig.headerConfig = config.header;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (config.content) {
|
|
44
|
+
processedConfig.contentConfig = config.content;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (config.media) {
|
|
48
|
+
processedConfig.mediaConfig = config.media;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (config.actions) {
|
|
52
|
+
processedConfig.actionsConfig = config.actions;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return processedConfig;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Applies inline configuration to a card component
|
|
60
|
+
* Adds configured elements to the card in the correct order
|
|
33
61
|
*
|
|
34
|
-
* @param {CardComponent} card - Card component to
|
|
35
|
-
* @param {CardSchema} config -
|
|
36
|
-
* @returns {CardComponent} Initialized card component
|
|
37
|
-
* @internal This is an internal utility for the Card component
|
|
62
|
+
* @param {CardComponent} card - Card component to configure
|
|
63
|
+
* @param {CardSchema} config - Processed configuration
|
|
38
64
|
*/
|
|
39
|
-
export const
|
|
40
|
-
//
|
|
65
|
+
export const applyInlineConfiguration = (card: CardComponent, config: CardSchema): void => {
|
|
66
|
+
// Add media (top position) if configured
|
|
41
67
|
if (config.mediaConfig && (!config.mediaConfig.position || config.mediaConfig.position === 'top')) {
|
|
42
68
|
const { position, ...mediaConfigWithoutPosition } = config.mediaConfig;
|
|
43
69
|
const mediaElement = createCardMedia(mediaConfigWithoutPosition);
|
|
44
70
|
card.addMedia(mediaElement, 'top');
|
|
45
71
|
}
|
|
46
72
|
|
|
47
|
-
//
|
|
73
|
+
// Add header if configured
|
|
48
74
|
if (config.headerConfig) {
|
|
49
75
|
const headerElement = createCardHeader(config.headerConfig);
|
|
50
76
|
card.setHeader(headerElement);
|
|
51
77
|
}
|
|
52
78
|
|
|
53
|
-
//
|
|
79
|
+
// Add content if configured
|
|
54
80
|
if (config.contentConfig) {
|
|
55
81
|
const contentElement = createCardContent(config.contentConfig);
|
|
56
82
|
card.addContent(contentElement);
|
|
57
83
|
}
|
|
58
84
|
|
|
59
|
-
//
|
|
85
|
+
// Add media (bottom position) if configured
|
|
60
86
|
if (config.mediaConfig && config.mediaConfig.position === 'bottom') {
|
|
61
87
|
const { position, ...mediaConfigWithoutPosition } = config.mediaConfig;
|
|
62
88
|
const mediaElement = createCardMedia(mediaConfigWithoutPosition);
|
|
63
89
|
card.addMedia(mediaElement, 'bottom');
|
|
64
90
|
}
|
|
65
91
|
|
|
66
|
-
//
|
|
92
|
+
// Add actions if configured
|
|
67
93
|
if (config.actionsConfig) {
|
|
68
94
|
const actionsElement = createCardActions(config.actionsConfig);
|
|
69
95
|
card.setActions(actionsElement);
|
|
70
96
|
}
|
|
71
97
|
|
|
72
|
-
|
|
98
|
+
// Process buttons if provided (asynchronously)
|
|
99
|
+
if (Array.isArray(config.buttons) && config.buttons.length > 0) {
|
|
100
|
+
import('../button').then(({ default: createButton }) => {
|
|
101
|
+
// Create buttons from configuration
|
|
102
|
+
const actionButtons = config.buttons!.map(buttonConfig =>
|
|
103
|
+
createButton(buttonConfig).element
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
// Create actions container
|
|
107
|
+
const actionsElement = createCardActions({
|
|
108
|
+
actions: actionButtons,
|
|
109
|
+
align: config.actionsConfig?.align || 'end'
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Add the actions to the card
|
|
113
|
+
card.setActions(actionsElement);
|
|
114
|
+
}).catch(error => {
|
|
115
|
+
console.error('Error processing buttons:', error);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
73
118
|
};
|
|
74
119
|
|
|
75
120
|
/**
|
|
@@ -3,6 +3,9 @@ import { PREFIX } from '../../core/config';
|
|
|
3
3
|
import { createElement } from '../../core/dom/create';
|
|
4
4
|
import { BaseComponent, CardComponent, LoadingFeature, ExpandableFeature, SwipeableFeature } from './types';
|
|
5
5
|
|
|
6
|
+
import { createCardHeader, createCardContent, createCardMedia, createCardActions } from './content';
|
|
7
|
+
import { BaseComponent, CardComponent, CardHeaderConfig, CardContentConfig, CardMediaConfig, CardActionsConfig, CardSchema, ButtonConfig } from './types';
|
|
8
|
+
|
|
6
9
|
interface LoadingConfig {
|
|
7
10
|
initialState?: boolean;
|
|
8
11
|
}
|