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,141 @@
|
|
|
1
|
+
// src/components/extended-fab/api.ts
|
|
2
|
+
import { ExtendedFabComponent } from './types';
|
|
3
|
+
|
|
4
|
+
interface ApiOptions {
|
|
5
|
+
disabled: {
|
|
6
|
+
enable: () => void;
|
|
7
|
+
disable: () => void;
|
|
8
|
+
};
|
|
9
|
+
lifecycle: {
|
|
10
|
+
destroy: () => void;
|
|
11
|
+
};
|
|
12
|
+
text: {
|
|
13
|
+
setText: (text: string) => any;
|
|
14
|
+
getText: () => string;
|
|
15
|
+
};
|
|
16
|
+
className: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ComponentWithElements {
|
|
20
|
+
element: HTMLElement;
|
|
21
|
+
icon: {
|
|
22
|
+
setIcon: (html: string) => any;
|
|
23
|
+
getIcon: () => string;
|
|
24
|
+
getElement: () => HTMLElement | null;
|
|
25
|
+
};
|
|
26
|
+
text: {
|
|
27
|
+
setText: (text: string) => any;
|
|
28
|
+
getText: () => string;
|
|
29
|
+
getElement: () => HTMLElement | null;
|
|
30
|
+
};
|
|
31
|
+
getClass: (name: string) => string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Enhances an Extended FAB component with API methods
|
|
36
|
+
* @param {ApiOptions} options - API configuration options
|
|
37
|
+
* @returns {Function} Higher-order function that adds API methods to component
|
|
38
|
+
* @internal This is an internal utility for the Extended FAB component
|
|
39
|
+
*/
|
|
40
|
+
export const withAPI = ({ disabled, lifecycle, text, className }: ApiOptions) =>
|
|
41
|
+
(component: ComponentWithElements): ExtendedFabComponent => ({
|
|
42
|
+
...component as any,
|
|
43
|
+
element: component.element as HTMLButtonElement,
|
|
44
|
+
|
|
45
|
+
getValue: () => component.element.value,
|
|
46
|
+
|
|
47
|
+
setValue(value: string) {
|
|
48
|
+
component.element.value = value;
|
|
49
|
+
return this;
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
enable() {
|
|
53
|
+
disabled.enable();
|
|
54
|
+
return this;
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
disable() {
|
|
58
|
+
disabled.disable();
|
|
59
|
+
return this;
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
setIcon(icon: string) {
|
|
63
|
+
component.icon.setIcon(icon);
|
|
64
|
+
return this;
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
getIcon() {
|
|
68
|
+
return component.icon.getIcon();
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
setText(newText: string) {
|
|
72
|
+
text.setText(newText);
|
|
73
|
+
return this;
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
getText() {
|
|
77
|
+
return text.getText();
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
setPosition(position: string) {
|
|
81
|
+
// First remove any existing position classes
|
|
82
|
+
const positions = ['top-right', 'top-left', 'bottom-right', 'bottom-left'];
|
|
83
|
+
positions.forEach(pos => {
|
|
84
|
+
component.element.classList.remove(`${className}--${pos}`);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Add new position class
|
|
88
|
+
component.element.classList.add(`${className}--${position}`);
|
|
89
|
+
return this;
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
getPosition() {
|
|
93
|
+
const positions = ['top-right', 'top-left', 'bottom-right', 'bottom-left'];
|
|
94
|
+
for (const pos of positions) {
|
|
95
|
+
if (component.element.classList.contains(`${className}--${pos}`)) {
|
|
96
|
+
return pos;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
lower() {
|
|
103
|
+
component.element.classList.add(`${className}--lowered`);
|
|
104
|
+
return this;
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
raise() {
|
|
108
|
+
component.element.classList.remove(`${className}--lowered`);
|
|
109
|
+
return this;
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
collapse() {
|
|
113
|
+
component.element.classList.add(`${className}--collapsed`);
|
|
114
|
+
|
|
115
|
+
// Emit a custom event that can be listened to
|
|
116
|
+
const event = new CustomEvent('collapse', {
|
|
117
|
+
bubbles: true,
|
|
118
|
+
cancelable: true
|
|
119
|
+
});
|
|
120
|
+
component.element.dispatchEvent(event);
|
|
121
|
+
|
|
122
|
+
return this;
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
expand() {
|
|
126
|
+
component.element.classList.remove(`${className}--collapsed`);
|
|
127
|
+
|
|
128
|
+
// Emit a custom event that can be listened to
|
|
129
|
+
const event = new CustomEvent('expand', {
|
|
130
|
+
bubbles: true,
|
|
131
|
+
cancelable: true
|
|
132
|
+
});
|
|
133
|
+
component.element.dispatchEvent(event);
|
|
134
|
+
|
|
135
|
+
return this;
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
destroy() {
|
|
139
|
+
lifecycle.destroy();
|
|
140
|
+
}
|
|
141
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// src/components/extended-fab/config.ts
|
|
2
|
+
import {
|
|
3
|
+
createComponentConfig,
|
|
4
|
+
createElementConfig,
|
|
5
|
+
BaseComponentConfig
|
|
6
|
+
} from '../../core/config/component-config';
|
|
7
|
+
import { ExtendedFabConfig } from './types';
|
|
8
|
+
import { FAB_VARIANTS, EXTENDED_FAB_WIDTH } from './constants';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Default configuration for the Extended FAB component
|
|
12
|
+
*/
|
|
13
|
+
export const defaultConfig: ExtendedFabConfig = {
|
|
14
|
+
variant: FAB_VARIANTS.PRIMARY,
|
|
15
|
+
type: 'button',
|
|
16
|
+
ripple: true,
|
|
17
|
+
iconPosition: 'start',
|
|
18
|
+
width: 'fixed'
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates the base configuration for Extended FAB component
|
|
23
|
+
* @param {ExtendedFabConfig} config - User provided configuration
|
|
24
|
+
* @returns {ExtendedFabConfig} Complete configuration with defaults applied
|
|
25
|
+
*/
|
|
26
|
+
export const createBaseConfig = (config: ExtendedFabConfig = {}): ExtendedFabConfig =>
|
|
27
|
+
createComponentConfig(defaultConfig, config, 'extended-fab') as ExtendedFabConfig;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Generates element configuration for the Extended FAB component
|
|
31
|
+
* @param {ExtendedFabConfig} config - Extended FAB configuration
|
|
32
|
+
* @returns {Object} Element configuration object for withElement
|
|
33
|
+
*/
|
|
34
|
+
export const getElementConfig = (config: ExtendedFabConfig) => {
|
|
35
|
+
// Create the attributes object
|
|
36
|
+
const attrs: Record<string, any> = {
|
|
37
|
+
type: config.type || 'button',
|
|
38
|
+
'aria-label': config.ariaLabel || config.text || (config.icon ? 'action' : undefined)
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Build class list
|
|
42
|
+
let classNames = [`${config.prefix}-extended-fab`];
|
|
43
|
+
|
|
44
|
+
// Add width class
|
|
45
|
+
if (config.width) {
|
|
46
|
+
classNames.push(`${config.prefix}-extended-fab--${config.width}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Add animation class if specified
|
|
50
|
+
if (config.animate) {
|
|
51
|
+
classNames.push(`${config.prefix}-extended-fab--animate-enter`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Add position class if specified
|
|
55
|
+
if (config.position) {
|
|
56
|
+
classNames.push(`${config.prefix}-extended-fab--${config.position}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Add collapse-on-scroll class if specified
|
|
60
|
+
if (config.collapseOnScroll) {
|
|
61
|
+
classNames.push(`${config.prefix}-extended-fab--collapsible`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Add user classes
|
|
65
|
+
if (config.class) {
|
|
66
|
+
classNames.push(config.class);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Only add disabled attribute if it's explicitly true
|
|
70
|
+
if (config.disabled === true) {
|
|
71
|
+
attrs.disabled = true;
|
|
72
|
+
classNames.push(`${config.prefix}-extended-fab--disabled`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return createElementConfig(config, {
|
|
76
|
+
tag: 'button',
|
|
77
|
+
attrs,
|
|
78
|
+
className: classNames,
|
|
79
|
+
forwardEvents: {
|
|
80
|
+
click: (component) => !component.element.disabled,
|
|
81
|
+
focus: true,
|
|
82
|
+
blur: true
|
|
83
|
+
},
|
|
84
|
+
interactive: true
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Creates API configuration for the Extended FAB component
|
|
90
|
+
* @param {Object} comp - Component with disabled and lifecycle features
|
|
91
|
+
* @returns {Object} API configuration object
|
|
92
|
+
*/
|
|
93
|
+
export const getApiConfig = (comp: any) => ({
|
|
94
|
+
disabled: {
|
|
95
|
+
enable: () => comp.disabled.enable(),
|
|
96
|
+
disable: () => comp.disabled.disable()
|
|
97
|
+
},
|
|
98
|
+
lifecycle: {
|
|
99
|
+
destroy: () => comp.lifecycle.destroy()
|
|
100
|
+
},
|
|
101
|
+
className: comp.getClass('extended-fab'),
|
|
102
|
+
text: {
|
|
103
|
+
setText: (text: string) => comp.text.setText(text),
|
|
104
|
+
getText: () => comp.text.getText()
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
export default defaultConfig;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/components/extended-fab/constants.ts
|
|
2
|
+
import { FAB_VARIANTS, FAB_POSITIONS } from '../fab/constants'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Re-export FAB variants for styling
|
|
6
|
+
*/
|
|
7
|
+
export { FAB_VARIANTS }
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Re-export FAB positions for fixed positioning
|
|
11
|
+
*/
|
|
12
|
+
export { FAB_POSITIONS }
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Extended FAB width behavior options
|
|
16
|
+
*/
|
|
17
|
+
export const EXTENDED_FAB_WIDTH = {
|
|
18
|
+
/** Fixed width based on content */
|
|
19
|
+
FIXED: 'fixed',
|
|
20
|
+
/** Fluid width that can adapt to container */
|
|
21
|
+
FLUID: 'fluid'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Extended FAB dimensions
|
|
26
|
+
*/
|
|
27
|
+
export const EXTENDED_FAB_DIMENSIONS = {
|
|
28
|
+
/** Standard height - 56dp */
|
|
29
|
+
HEIGHT: 56,
|
|
30
|
+
/** Minimum width - 80dp */
|
|
31
|
+
MIN_WIDTH: 80,
|
|
32
|
+
/** Padding - 16dp */
|
|
33
|
+
PADDING: 16,
|
|
34
|
+
/** Icon size - 24dp */
|
|
35
|
+
ICON_SIZE: 24
|
|
36
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// src/components/extended-fab/extended-fab.ts
|
|
2
|
+
import { pipe } from '../../core/compose';
|
|
3
|
+
import { createBase, withElement } from '../../core/compose/component';
|
|
4
|
+
import {
|
|
5
|
+
withEvents,
|
|
6
|
+
withIcon,
|
|
7
|
+
withVariant,
|
|
8
|
+
withRipple,
|
|
9
|
+
withDisabled,
|
|
10
|
+
withLifecycle,
|
|
11
|
+
withText
|
|
12
|
+
} from '../../core/compose/features';
|
|
13
|
+
import { withAPI } from './api';
|
|
14
|
+
import { ExtendedFabConfig, ExtendedFabComponent } from './types';
|
|
15
|
+
import { createBaseConfig, getElementConfig, getApiConfig } from './config';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new Extended Floating Action Button (Extended FAB) component
|
|
19
|
+
*
|
|
20
|
+
* @param {ExtendedFabConfig} config - Extended FAB configuration object
|
|
21
|
+
* @returns {ExtendedFabComponent} Extended FAB component instance
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* // Create a basic Extended FAB with icon and text
|
|
26
|
+
* const extendedFab = createExtendedFab({
|
|
27
|
+
* icon: '<svg>...</svg>',
|
|
28
|
+
* text: 'Create',
|
|
29
|
+
* ariaLabel: 'Create new item'
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Create a tertiary Extended FAB with a custom position
|
|
33
|
+
* const customExtendedFab = createExtendedFab({
|
|
34
|
+
* text: 'Add to cart',
|
|
35
|
+
* icon: '<svg>...</svg>',
|
|
36
|
+
* variant: 'tertiary',
|
|
37
|
+
* position: 'bottom-right',
|
|
38
|
+
* collapseOnScroll: true
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* // Add click handler
|
|
42
|
+
* extendedFab.on('click', () => {
|
|
43
|
+
* console.log('Extended FAB clicked');
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
const createExtendedFab = (config: ExtendedFabConfig = {}): ExtendedFabComponent => {
|
|
48
|
+
const fabConfig = createBaseConfig(config);
|
|
49
|
+
|
|
50
|
+
// Set up scroll collapse handler if needed
|
|
51
|
+
const setupScrollCollapse = (component: ExtendedFabComponent): void => {
|
|
52
|
+
if (fabConfig.collapseOnScroll) {
|
|
53
|
+
let lastScrollY = window.scrollY;
|
|
54
|
+
let ticking = false;
|
|
55
|
+
const scrollThreshold = 10; // Minimum scroll amount to trigger collapse/expand
|
|
56
|
+
|
|
57
|
+
const handleScroll = () => {
|
|
58
|
+
if (!ticking) {
|
|
59
|
+
window.requestAnimationFrame(() => {
|
|
60
|
+
const currentScrollY = window.scrollY;
|
|
61
|
+
const scrollDelta = currentScrollY - lastScrollY;
|
|
62
|
+
|
|
63
|
+
// If scrolling down beyond threshold, collapse
|
|
64
|
+
if (scrollDelta > scrollThreshold) {
|
|
65
|
+
component.collapse();
|
|
66
|
+
}
|
|
67
|
+
// If scrolling up beyond threshold, expand
|
|
68
|
+
else if (scrollDelta < -scrollThreshold) {
|
|
69
|
+
component.expand();
|
|
70
|
+
}
|
|
71
|
+
// If at the top of the page, ensure expanded
|
|
72
|
+
if (currentScrollY <= 0) {
|
|
73
|
+
component.expand();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
lastScrollY = currentScrollY;
|
|
77
|
+
ticking = false;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
ticking = true;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Add scroll listener
|
|
85
|
+
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
86
|
+
|
|
87
|
+
// Ensure it's expanded by default
|
|
88
|
+
requestAnimationFrame(() => {
|
|
89
|
+
component.expand();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Clean up on destroy
|
|
93
|
+
const originalDestroy = component.destroy;
|
|
94
|
+
component.destroy = () => {
|
|
95
|
+
window.removeEventListener('scroll', handleScroll);
|
|
96
|
+
originalDestroy.call(component);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const extendedFab = pipe(
|
|
103
|
+
createBase,
|
|
104
|
+
withEvents(),
|
|
105
|
+
withElement(getElementConfig(fabConfig)),
|
|
106
|
+
withVariant(fabConfig),
|
|
107
|
+
withIcon(fabConfig),
|
|
108
|
+
withText(fabConfig),
|
|
109
|
+
withDisabled(fabConfig),
|
|
110
|
+
withRipple(fabConfig),
|
|
111
|
+
withLifecycle(),
|
|
112
|
+
comp => withAPI(getApiConfig(comp))(comp)
|
|
113
|
+
)(fabConfig);
|
|
114
|
+
|
|
115
|
+
// Set up scroll collapse after component is created
|
|
116
|
+
setupScrollCollapse(extendedFab);
|
|
117
|
+
|
|
118
|
+
return extendedFab;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error('Extended FAB creation error:', error);
|
|
121
|
+
throw new Error(`Failed to create Extended FAB: ${(error as Error).message}`);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
export default createExtendedFab;
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
// src/components/extended-fab/types.ts
|
|
2
|
+
import { FAB_VARIANTS } from '../fab/constants';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Configuration interface for the Extended FAB component
|
|
6
|
+
* @category Components
|
|
7
|
+
*/
|
|
8
|
+
export interface ExtendedFabConfig {
|
|
9
|
+
/**
|
|
10
|
+
* Extended FAB variant that determines visual styling
|
|
11
|
+
* @default 'primary'
|
|
12
|
+
*/
|
|
13
|
+
variant?: keyof typeof FAB_VARIANTS | string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Whether the Extended FAB is initially disabled
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Extended FAB icon HTML content
|
|
23
|
+
* @example '<svg>...</svg>'
|
|
24
|
+
*/
|
|
25
|
+
icon?: string;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Icon size in pixels or other CSS units
|
|
29
|
+
* @example '24px'
|
|
30
|
+
*/
|
|
31
|
+
iconSize?: string;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Position of the icon relative to the text
|
|
35
|
+
* @default 'start'
|
|
36
|
+
*/
|
|
37
|
+
iconPosition?: 'start' | 'end';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Text label for the Extended FAB
|
|
41
|
+
* @example 'Create'
|
|
42
|
+
*/
|
|
43
|
+
text?: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Additional CSS classes to add to the Extended FAB
|
|
47
|
+
* @example 'home-fab bottom-right'
|
|
48
|
+
*/
|
|
49
|
+
class?: string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Button value attribute
|
|
53
|
+
*/
|
|
54
|
+
value?: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Position of the Extended FAB on the screen
|
|
58
|
+
* @example 'bottom-right'
|
|
59
|
+
*/
|
|
60
|
+
position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Button type attribute
|
|
64
|
+
* @default 'button'
|
|
65
|
+
*/
|
|
66
|
+
type?: 'button' | 'submit' | 'reset';
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Accessible label for screen readers
|
|
70
|
+
*/
|
|
71
|
+
ariaLabel?: string;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Whether to enable ripple effect
|
|
75
|
+
* @default true
|
|
76
|
+
*/
|
|
77
|
+
ripple?: boolean;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Component prefix for class names
|
|
81
|
+
* @default 'mtrl'
|
|
82
|
+
*/
|
|
83
|
+
prefix?: string;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Component name used in class generation
|
|
87
|
+
*/
|
|
88
|
+
componentName?: string;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Ripple effect configuration
|
|
92
|
+
*/
|
|
93
|
+
rippleConfig?: {
|
|
94
|
+
/** Duration of the ripple animation in milliseconds */
|
|
95
|
+
duration?: number;
|
|
96
|
+
/** Timing function for the ripple animation */
|
|
97
|
+
timing?: string;
|
|
98
|
+
/** Opacity values for ripple start and end [start, end] */
|
|
99
|
+
opacity?: [string, string];
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Whether to show the Extended FAB with an entrance animation
|
|
104
|
+
* @default false
|
|
105
|
+
*/
|
|
106
|
+
animate?: boolean;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Width behavior of the Extended FAB
|
|
110
|
+
* @default 'fixed'
|
|
111
|
+
*/
|
|
112
|
+
width?: 'fixed' | 'fluid';
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Whether the Extended FAB should collapse to a standard FAB on scroll
|
|
116
|
+
* @default false
|
|
117
|
+
*/
|
|
118
|
+
collapseOnScroll?: boolean;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Extended FAB component interface
|
|
123
|
+
* @category Components
|
|
124
|
+
*/
|
|
125
|
+
export interface ExtendedFabComponent {
|
|
126
|
+
/** The Extended FAB's DOM element */
|
|
127
|
+
element: HTMLButtonElement;
|
|
128
|
+
|
|
129
|
+
/** API for managing Extended FAB icons */
|
|
130
|
+
icon: {
|
|
131
|
+
/** Sets the icon HTML content */
|
|
132
|
+
setIcon: (html: string) => any;
|
|
133
|
+
/** Gets the current icon HTML content */
|
|
134
|
+
getIcon: () => string;
|
|
135
|
+
/** Gets the icon DOM element */
|
|
136
|
+
getElement: () => HTMLElement | null;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/** API for managing text content */
|
|
140
|
+
text: {
|
|
141
|
+
/** Sets the text content */
|
|
142
|
+
setText: (text: string) => any;
|
|
143
|
+
/** Gets the current text content */
|
|
144
|
+
getText: () => string;
|
|
145
|
+
/** Gets the text DOM element */
|
|
146
|
+
getElement: () => HTMLElement | null;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/** API for managing disabled state */
|
|
150
|
+
disabled: {
|
|
151
|
+
/** Enables the Extended FAB */
|
|
152
|
+
enable: () => void;
|
|
153
|
+
/** Disables the Extended FAB */
|
|
154
|
+
disable: () => void;
|
|
155
|
+
/** Checks if the Extended FAB is disabled */
|
|
156
|
+
isDisabled: () => boolean;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/** API for managing component lifecycle */
|
|
160
|
+
lifecycle: {
|
|
161
|
+
/** Destroys the component and cleans up resources */
|
|
162
|
+
destroy: () => void;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Gets a class name with the component's prefix
|
|
167
|
+
* @param name - Base class name
|
|
168
|
+
* @returns Prefixed class name
|
|
169
|
+
*/
|
|
170
|
+
getClass: (name: string) => string;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Gets the Extended FAB's value attribute
|
|
174
|
+
* @returns Extended FAB value
|
|
175
|
+
*/
|
|
176
|
+
getValue: () => string;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Sets the Extended FAB's value attribute
|
|
180
|
+
* @param value - New value
|
|
181
|
+
* @returns The Extended FAB component for chaining
|
|
182
|
+
*/
|
|
183
|
+
setValue: (value: string) => ExtendedFabComponent;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Enables the Extended FAB (removes disabled attribute)
|
|
187
|
+
* @returns The Extended FAB component for chaining
|
|
188
|
+
*/
|
|
189
|
+
enable: () => ExtendedFabComponent;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Disables the Extended FAB (adds disabled attribute)
|
|
193
|
+
* @returns The Extended FAB component for chaining
|
|
194
|
+
*/
|
|
195
|
+
disable: () => ExtendedFabComponent;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Sets the Extended FAB's icon
|
|
199
|
+
* @param icon - Icon HTML content
|
|
200
|
+
* @returns The Extended FAB component for chaining
|
|
201
|
+
*/
|
|
202
|
+
setIcon: (icon: string) => ExtendedFabComponent;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Gets the Extended FAB's icon HTML content
|
|
206
|
+
* @returns Icon HTML
|
|
207
|
+
*/
|
|
208
|
+
getIcon: () => string;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Sets the Extended FAB's text content
|
|
212
|
+
* @param text - Text content
|
|
213
|
+
* @returns The Extended FAB component for chaining
|
|
214
|
+
*/
|
|
215
|
+
setText: (text: string) => ExtendedFabComponent;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Gets the Extended FAB's text content
|
|
219
|
+
* @returns Text content
|
|
220
|
+
*/
|
|
221
|
+
getText: () => string;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Sets the Extended FAB's position
|
|
225
|
+
* @param position - Position value ('top-right', 'bottom-left', etc.)
|
|
226
|
+
* @returns The Extended FAB component for chaining
|
|
227
|
+
*/
|
|
228
|
+
setPosition: (position: string) => ExtendedFabComponent;
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Gets the current position of the Extended FAB
|
|
232
|
+
* @returns Current position
|
|
233
|
+
*/
|
|
234
|
+
getPosition: () => string | null;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Lowers the Extended FAB (useful for pressed state)
|
|
238
|
+
* @returns The Extended FAB component for chaining
|
|
239
|
+
*/
|
|
240
|
+
lower: () => ExtendedFabComponent;
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Raises the Extended FAB back to its default elevation
|
|
244
|
+
* @returns The Extended FAB component for chaining
|
|
245
|
+
*/
|
|
246
|
+
raise: () => ExtendedFabComponent;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Collapses the Extended FAB into a standard FAB
|
|
250
|
+
* @returns The Extended FAB component for chaining
|
|
251
|
+
*/
|
|
252
|
+
collapse: () => ExtendedFabComponent;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Expands a collapsed Extended FAB back to its full size
|
|
256
|
+
* @returns The Extended FAB component for chaining
|
|
257
|
+
*/
|
|
258
|
+
expand: () => ExtendedFabComponent;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Destroys the Extended FAB component and cleans up resources
|
|
262
|
+
*/
|
|
263
|
+
destroy: () => void;
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Adds an event listener to the Extended FAB
|
|
267
|
+
* @param event - Event name ('click', 'focus', etc.)
|
|
268
|
+
* @param handler - Event handler function
|
|
269
|
+
* @returns The Extended FAB component for chaining
|
|
270
|
+
*/
|
|
271
|
+
on: (event: string, handler: Function) => ExtendedFabComponent;
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Removes an event listener from the Extended FAB
|
|
275
|
+
* @param event - Event name
|
|
276
|
+
* @param handler - Event handler function
|
|
277
|
+
* @returns The Extended FAB component for chaining
|
|
278
|
+
*/
|
|
279
|
+
off: (event: string, handler: Function) => ExtendedFabComponent;
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Adds CSS classes to the Extended FAB element
|
|
283
|
+
* @param classes - One or more class names to add
|
|
284
|
+
* @returns The Extended FAB component for chaining
|
|
285
|
+
*/
|
|
286
|
+
addClass: (...classes: string[]) => ExtendedFabComponent;
|
|
287
|
+
}
|