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,225 @@
|
|
|
1
|
+
// src/components/fab/_styles.scss
|
|
2
|
+
@use '../../styles/abstract/base' as base;
|
|
3
|
+
@use '../../styles/abstract/variables' as v;
|
|
4
|
+
@use '../../styles/abstract/functions' as f;
|
|
5
|
+
@use '../../styles/abstract/mixins' as m;
|
|
6
|
+
@use '../../styles/abstract/theme' as t;
|
|
7
|
+
|
|
8
|
+
$component: '#{base.$prefix}-fab';
|
|
9
|
+
|
|
10
|
+
.#{$component} {
|
|
11
|
+
// Base styles
|
|
12
|
+
position: relative;
|
|
13
|
+
display: inline-flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
border: none;
|
|
17
|
+
background-color: t.color('primary-container');
|
|
18
|
+
color: t.color('on-primary-container');
|
|
19
|
+
font: inherit;
|
|
20
|
+
text-decoration: none;
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
user-select: none;
|
|
23
|
+
vertical-align: middle;
|
|
24
|
+
appearance: none;
|
|
25
|
+
overflow: hidden;
|
|
26
|
+
|
|
27
|
+
// FAB uses elevation in all variants
|
|
28
|
+
@include m.elevation(3);
|
|
29
|
+
|
|
30
|
+
// Transitions
|
|
31
|
+
@include m.motion-transition(
|
|
32
|
+
transform,
|
|
33
|
+
box-shadow,
|
|
34
|
+
background-color,
|
|
35
|
+
color
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Focus styles
|
|
39
|
+
&:focus {
|
|
40
|
+
outline: none;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&:focus-visible {
|
|
44
|
+
outline: 2px solid t.color('outline');
|
|
45
|
+
outline-offset: 2px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Default FAB size (56dp)
|
|
49
|
+
width: 56px;
|
|
50
|
+
height: 56px;
|
|
51
|
+
border-radius: f.get-shape('large');
|
|
52
|
+
|
|
53
|
+
// Icon sizing
|
|
54
|
+
&-icon {
|
|
55
|
+
display: inline-flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
width: 24px;
|
|
59
|
+
height: 24px;
|
|
60
|
+
|
|
61
|
+
svg {
|
|
62
|
+
width: 24px;
|
|
63
|
+
height: 24px;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Size variants
|
|
68
|
+
&--small {
|
|
69
|
+
width: 40px;
|
|
70
|
+
height: 40px;
|
|
71
|
+
border-radius: f.get-shape('medium');
|
|
72
|
+
|
|
73
|
+
.#{$component}-icon {
|
|
74
|
+
width: 24px;
|
|
75
|
+
height: 24px;
|
|
76
|
+
|
|
77
|
+
svg {
|
|
78
|
+
width: 24px;
|
|
79
|
+
height: 24px;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
&--default {
|
|
85
|
+
// Default is already defined in base styles
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
&--large {
|
|
89
|
+
width: 96px;
|
|
90
|
+
height: 96px;
|
|
91
|
+
border-radius: f.get-shape('extra-large');
|
|
92
|
+
|
|
93
|
+
.#{$component}-icon {
|
|
94
|
+
width: 36px;
|
|
95
|
+
height: 36px;
|
|
96
|
+
|
|
97
|
+
svg {
|
|
98
|
+
width: 36px;
|
|
99
|
+
height: 36px;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Color variants - primary is the default
|
|
105
|
+
|
|
106
|
+
// Primary variant (default)
|
|
107
|
+
&--primary {
|
|
108
|
+
background-color: t.color('primary-container');
|
|
109
|
+
color: t.color('on-primary-container');
|
|
110
|
+
|
|
111
|
+
&:hover {
|
|
112
|
+
@include m.state-layer(t.color('on-primary-container'), 'hover');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
&:active {
|
|
116
|
+
@include m.state-layer(t.color('on-primary-container'), 'pressed');
|
|
117
|
+
@include m.elevation(1);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Secondary variant
|
|
122
|
+
&--secondary {
|
|
123
|
+
background-color: t.color('secondary-container');
|
|
124
|
+
color: t.color('on-secondary-container');
|
|
125
|
+
|
|
126
|
+
&:hover {
|
|
127
|
+
@include m.state-layer(t.color('on-secondary-container'), 'hover');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
&:active {
|
|
131
|
+
@include m.state-layer(t.color('on-secondary-container'), 'pressed');
|
|
132
|
+
@include m.elevation(1);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Tertiary variant
|
|
137
|
+
&--tertiary {
|
|
138
|
+
background-color: t.color('tertiary-container');
|
|
139
|
+
color: t.color('on-tertiary-container');
|
|
140
|
+
|
|
141
|
+
&:hover {
|
|
142
|
+
@include m.state-layer(t.color('on-tertiary-container'), 'hover');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
&:active {
|
|
146
|
+
@include m.state-layer(t.color('on-tertiary-container'), 'pressed');
|
|
147
|
+
@include m.elevation(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Surface variant
|
|
152
|
+
&--surface {
|
|
153
|
+
background-color: t.color('surface');
|
|
154
|
+
color: t.color('primary');
|
|
155
|
+
|
|
156
|
+
&:hover {
|
|
157
|
+
@include m.state-layer(t.color('primary'), 'hover');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
&:active {
|
|
161
|
+
@include m.state-layer(t.color('primary'), 'pressed');
|
|
162
|
+
@include m.elevation(1);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Lowered state (when pressed)
|
|
167
|
+
&--lowered {
|
|
168
|
+
@include m.elevation(1);
|
|
169
|
+
transform: translateY(1px);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Disabled state
|
|
173
|
+
&--disabled,
|
|
174
|
+
&:disabled {
|
|
175
|
+
pointer-events: none;
|
|
176
|
+
@include m.elevation(0);
|
|
177
|
+
background-color: t.alpha('on-surface', 0.12);
|
|
178
|
+
color: t.alpha('on-surface', 0.38);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Positioning utilities
|
|
182
|
+
&--top-right {
|
|
183
|
+
position: fixed;
|
|
184
|
+
top: 16px;
|
|
185
|
+
right: 16px;
|
|
186
|
+
z-index: v.z-index('dropdown');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
&--top-left {
|
|
190
|
+
position: fixed;
|
|
191
|
+
top: 16px;
|
|
192
|
+
left: 16px;
|
|
193
|
+
z-index: v.z-index('dropdown');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
&--bottom-right {
|
|
197
|
+
position: fixed;
|
|
198
|
+
bottom: 16px;
|
|
199
|
+
right: 16px;
|
|
200
|
+
z-index: v.z-index('dropdown');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
&--bottom-left {
|
|
204
|
+
position: fixed;
|
|
205
|
+
bottom: 16px;
|
|
206
|
+
left: 16px;
|
|
207
|
+
z-index: v.z-index('dropdown');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Optional animations
|
|
211
|
+
@keyframes fab-enter {
|
|
212
|
+
from {
|
|
213
|
+
transform: scale(0);
|
|
214
|
+
opacity: 0;
|
|
215
|
+
}
|
|
216
|
+
to {
|
|
217
|
+
transform: scale(1);
|
|
218
|
+
opacity: 1;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
&--animate-enter {
|
|
223
|
+
animation: fab-enter 0.3s f.get-motion-easing('emphasized-decelerate') forwards;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// src/components/fab/api.ts
|
|
2
|
+
import { FabComponent } from './types';
|
|
3
|
+
|
|
4
|
+
interface ApiOptions {
|
|
5
|
+
disabled: {
|
|
6
|
+
enable: () => void;
|
|
7
|
+
disable: () => void;
|
|
8
|
+
};
|
|
9
|
+
lifecycle: {
|
|
10
|
+
destroy: () => void;
|
|
11
|
+
};
|
|
12
|
+
className: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface ComponentWithElements {
|
|
16
|
+
element: HTMLElement;
|
|
17
|
+
icon: {
|
|
18
|
+
setIcon: (html: string) => any;
|
|
19
|
+
getIcon: () => string;
|
|
20
|
+
getElement: () => HTMLElement | null;
|
|
21
|
+
};
|
|
22
|
+
getClass: (name: string) => string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Enhances a FAB component with API methods
|
|
27
|
+
* @param {ApiOptions} options - API configuration options
|
|
28
|
+
* @returns {Function} Higher-order function that adds API methods to component
|
|
29
|
+
* @internal This is an internal utility for the FAB component
|
|
30
|
+
*/
|
|
31
|
+
export const withAPI = ({ disabled, lifecycle, className }: ApiOptions) =>
|
|
32
|
+
(component: ComponentWithElements): FabComponent => ({
|
|
33
|
+
...component as any,
|
|
34
|
+
element: component.element as HTMLButtonElement,
|
|
35
|
+
|
|
36
|
+
getValue: () => component.element.value,
|
|
37
|
+
|
|
38
|
+
setValue(value: string) {
|
|
39
|
+
component.element.value = value;
|
|
40
|
+
return this;
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
enable() {
|
|
44
|
+
disabled.enable();
|
|
45
|
+
return this;
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
disable() {
|
|
49
|
+
disabled.disable();
|
|
50
|
+
return this;
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
setIcon(icon: string) {
|
|
54
|
+
component.icon.setIcon(icon);
|
|
55
|
+
return this;
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
getIcon() {
|
|
59
|
+
return component.icon.getIcon();
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
setPosition(position: string) {
|
|
63
|
+
// First remove any existing position classes
|
|
64
|
+
const positions = ['top-right', 'top-left', 'bottom-right', 'bottom-left'];
|
|
65
|
+
positions.forEach(pos => {
|
|
66
|
+
component.element.classList.remove(`${className}--${pos}`);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Add new position class
|
|
70
|
+
component.element.classList.add(`${className}--${position}`);
|
|
71
|
+
return this;
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
getPosition() {
|
|
75
|
+
const positions = ['top-right', 'top-left', 'bottom-right', 'bottom-left'];
|
|
76
|
+
for (const pos of positions) {
|
|
77
|
+
if (component.element.classList.contains(`${className}--${pos}`)) {
|
|
78
|
+
return pos;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
lower() {
|
|
85
|
+
component.element.classList.add(`${className}--lowered`);
|
|
86
|
+
return this;
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
raise() {
|
|
90
|
+
component.element.classList.remove(`${className}--lowered`);
|
|
91
|
+
return this;
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
destroy() {
|
|
95
|
+
lifecycle.destroy();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// src/components/fab/config.ts
|
|
2
|
+
import {
|
|
3
|
+
createComponentConfig,
|
|
4
|
+
createElementConfig,
|
|
5
|
+
BaseComponentConfig
|
|
6
|
+
} from '../../core/config/component-config';
|
|
7
|
+
import { FabConfig } from './types';
|
|
8
|
+
import { FAB_VARIANTS, FAB_SIZES } from './constants';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Default configuration for the FAB component
|
|
12
|
+
*/
|
|
13
|
+
export const defaultConfig: FabConfig = {
|
|
14
|
+
variant: FAB_VARIANTS.PRIMARY,
|
|
15
|
+
size: FAB_SIZES.DEFAULT,
|
|
16
|
+
type: 'button',
|
|
17
|
+
ripple: true
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates the base configuration for FAB component
|
|
22
|
+
* @param {FabConfig} config - User provided configuration
|
|
23
|
+
* @returns {FabConfig} Complete configuration with defaults applied
|
|
24
|
+
*/
|
|
25
|
+
export const createBaseConfig = (config: FabConfig = {}): FabConfig =>
|
|
26
|
+
createComponentConfig(defaultConfig, config, 'fab') as FabConfig;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Generates element configuration for the FAB component
|
|
30
|
+
* @param {FabConfig} config - FAB configuration
|
|
31
|
+
* @returns {Object} Element configuration object for withElement
|
|
32
|
+
*/
|
|
33
|
+
export const getElementConfig = (config: FabConfig) => {
|
|
34
|
+
// Create the attributes object
|
|
35
|
+
const attrs: Record<string, any> = {
|
|
36
|
+
type: config.type || 'button',
|
|
37
|
+
'aria-label': config.ariaLabel || (config.icon ? 'action' : undefined)
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Add size class
|
|
41
|
+
const fabSizeClass = `${config.prefix}-fab--${config.size || FAB_SIZES.DEFAULT}`;
|
|
42
|
+
let classNames = [fabSizeClass];
|
|
43
|
+
|
|
44
|
+
// Add animation class if specified
|
|
45
|
+
if (config.animate) {
|
|
46
|
+
classNames.push(`${config.prefix}-fab--animate-enter`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Add position class if specified
|
|
50
|
+
if (config.position) {
|
|
51
|
+
classNames.push(`${config.prefix}-fab--${config.position}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Add user classes
|
|
55
|
+
if (config.class) {
|
|
56
|
+
classNames.push(config.class);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Only add disabled attribute if it's explicitly true
|
|
60
|
+
if (config.disabled === true) {
|
|
61
|
+
attrs.disabled = true;
|
|
62
|
+
classNames.push(`${config.prefix}-fab--disabled`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return createElementConfig(config, {
|
|
66
|
+
tag: 'button',
|
|
67
|
+
attrs,
|
|
68
|
+
className: classNames,
|
|
69
|
+
forwardEvents: {
|
|
70
|
+
click: (component) => !component.element.disabled,
|
|
71
|
+
focus: true,
|
|
72
|
+
blur: true
|
|
73
|
+
},
|
|
74
|
+
interactive: true
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Creates API configuration for the FAB component
|
|
80
|
+
* @param {Object} comp - Component with disabled and lifecycle features
|
|
81
|
+
* @returns {Object} API configuration object
|
|
82
|
+
*/
|
|
83
|
+
export const getApiConfig = (comp: any) => ({
|
|
84
|
+
disabled: {
|
|
85
|
+
enable: () => comp.disabled.enable(),
|
|
86
|
+
disable: () => comp.disabled.disable()
|
|
87
|
+
},
|
|
88
|
+
lifecycle: {
|
|
89
|
+
destroy: () => comp.lifecycle.destroy()
|
|
90
|
+
},
|
|
91
|
+
className: comp.getClass('fab')
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
export default defaultConfig;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// src/components/fab/constants.ts
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* FAB variants for styling
|
|
5
|
+
*/
|
|
6
|
+
export const FAB_VARIANTS = {
|
|
7
|
+
/** Primary container color with on-primary-container icons */
|
|
8
|
+
PRIMARY: 'primary',
|
|
9
|
+
/** Secondary container color with on-secondary-container icons */
|
|
10
|
+
SECONDARY: 'secondary',
|
|
11
|
+
/** Tertiary container color with on-tertiary-container icons */
|
|
12
|
+
TERTIARY: 'tertiary',
|
|
13
|
+
/** Surface color with primary color icons */
|
|
14
|
+
SURFACE: 'surface'
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* FAB size variants
|
|
19
|
+
*/
|
|
20
|
+
export const FAB_SIZES = {
|
|
21
|
+
/** Standard FAB size (56dp) */
|
|
22
|
+
DEFAULT: 'default',
|
|
23
|
+
/** Small FAB size (40dp) */
|
|
24
|
+
SMALL: 'small',
|
|
25
|
+
/** Large FAB size (96dp) */
|
|
26
|
+
LARGE: 'large'
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* FAB positions for fixed positioning
|
|
31
|
+
*/
|
|
32
|
+
export const FAB_POSITIONS = {
|
|
33
|
+
/** Top right corner */
|
|
34
|
+
TOP_RIGHT: 'top-right',
|
|
35
|
+
/** Top left corner */
|
|
36
|
+
TOP_LEFT: 'top-left',
|
|
37
|
+
/** Bottom right corner */
|
|
38
|
+
BOTTOM_RIGHT: 'bottom-right',
|
|
39
|
+
/** Bottom left corner */
|
|
40
|
+
BOTTOM_LEFT: 'bottom-left'
|
|
41
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// src/components/fab/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
|
+
} from '../../core/compose/features';
|
|
12
|
+
import { withAPI } from './api';
|
|
13
|
+
import { FabConfig, FabComponent } from './types';
|
|
14
|
+
import { createBaseConfig, getElementConfig, getApiConfig } from './config';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new Floating Action Button (FAB) component
|
|
18
|
+
*
|
|
19
|
+
* @param {FabConfig} config - FAB configuration object
|
|
20
|
+
* @returns {FabComponent} FAB component instance
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // Create a default FAB with a plus icon
|
|
25
|
+
* const fab = createFab({
|
|
26
|
+
* icon: '<svg>...</svg>',
|
|
27
|
+
* ariaLabel: 'Add new item'
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* // Create a small FAB with a custom position
|
|
31
|
+
* const smallFab = createFab({
|
|
32
|
+
* size: FAB_SIZES.SMALL,
|
|
33
|
+
* icon: '<svg>...</svg>',
|
|
34
|
+
* variant: 'secondary',
|
|
35
|
+
* position: 'bottom-right'
|
|
36
|
+
* });
|
|
37
|
+
*
|
|
38
|
+
* // Add click handler
|
|
39
|
+
* fab.on('click', () => {
|
|
40
|
+
* console.log('FAB clicked');
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
const createFab = (config: FabConfig = {}): FabComponent => {
|
|
45
|
+
const fabConfig = createBaseConfig(config);
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const fab = pipe(
|
|
49
|
+
createBase,
|
|
50
|
+
withEvents(),
|
|
51
|
+
withElement(getElementConfig(fabConfig)),
|
|
52
|
+
withVariant(fabConfig),
|
|
53
|
+
withIcon(fabConfig),
|
|
54
|
+
withDisabled(fabConfig),
|
|
55
|
+
withRipple(fabConfig),
|
|
56
|
+
withLifecycle(),
|
|
57
|
+
comp => withAPI(getApiConfig(comp))(comp)
|
|
58
|
+
)(fabConfig);
|
|
59
|
+
|
|
60
|
+
return fab;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error('FAB creation error:', error);
|
|
63
|
+
throw new Error(`Failed to create FAB: ${(error as Error).message}`);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default createFab;
|