flet-box 0.0.0-stage → 1.0.2
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/LICENSE +21 -0
- package/README.md +190 -2
- package/bin/cli.js +394 -0
- package/bin/commands/buildAndroid.js +200 -0
- package/bin/commands/buildIOS.js +237 -0
- package/bin/commands/create.js +406 -0
- package/bin/commands/createBundle.js +375 -0
- package/bin/commands/createComponent.js +115 -0
- package/bin/commands/createScreen.js +161 -0
- package/bin/commands/killServer.js +107 -0
- package/bin/commands/package.js +131 -0
- package/bin/commands/release.js +189 -0
- package/bin/commands/runBundle.js +62 -0
- package/bin/commands/runCloudflare.js +89 -0
- package/bin/commands/runNative.js +109 -0
- package/bin/commands/runServer.js +390 -0
- package/bin/ota/loader.js +361 -0
- package/bin/utils/bundleConfig.js +178 -0
- package/bin/utils/capacitor.js +137 -0
- package/bin/utils/colors.js +215 -0
- package/bin/utils/helpers.js +80 -0
- package/bin/utils/spinner.js +96 -0
- package/bin/utils/templates.js +1824 -0
- package/bin/utils/version.js +108 -0
- package/package.json +58 -4
- package/src/animations/AnimatedBox.js +607 -0
- package/src/animations/AnimatedText.js +105 -0
- package/src/animations/MatrixRain.js +220 -0
- package/src/animations/ParallaxBox.js +369 -0
- package/src/animations/animate.js +332 -0
- package/src/animations/index.js +25 -0
- package/src/app.js +41 -0
- package/src/assets/icon-1024-maskable.png +0 -0
- package/src/assets/icon-192-maskable.png +0 -0
- package/src/assets/icon-192.png +0 -0
- package/src/assets/icon-512-maskable.png +0 -0
- package/src/assets/icon-512.png +0 -0
- package/src/assets/logo.png +0 -0
- package/src/core/App.js +44 -0
- package/src/core/hmr-client.js +142 -0
- package/src/core/index.js +34 -0
- package/src/core/pwa.js +100 -0
- package/src/core/runApp.js +430 -0
- package/src/create-index.sh +237 -0
- package/src/fonts/MaterialIcons-Regular.woff2 +0 -0
- package/src/fonts/icons.css +23 -0
- package/src/index.d.ts +1930 -0
- package/src/index.js +288 -0
- package/src/navigations/AdaptiveScaffold.js +149 -0
- package/src/navigations/AppBar.js +331 -0
- package/src/navigations/BottomNavigation.js +298 -0
- package/src/navigations/CollapsibleSideBar.js +139 -0
- package/src/navigations/Drawer.js +333 -0
- package/src/navigations/DrawerItem.js +260 -0
- package/src/navigations/Router.js +475 -0
- package/src/navigations/Scaffold.js +537 -0
- package/src/navigations/Tabs.js +384 -0
- package/src/navigations/index.js +57 -0
- package/src/services/RamStore.js +213 -0
- package/src/services/Session.js +310 -0
- package/src/services/Storage.js +309 -0
- package/src/services/http.js +350 -0
- package/src/services/index.js +57 -0
- package/src/tools/animation.js +42 -0
- package/src/tools/array.js +95 -0
- package/src/tools/border.js +28 -0
- package/src/tools/clipboard.js +104 -0
- package/src/tools/color.js +329 -0
- package/src/tools/createList.js +215 -0
- package/src/tools/delay.js +55 -0
- package/src/tools/device.js +138 -0
- package/src/tools/dict.js +297 -0
- package/src/tools/dimensions.js +118 -0
- package/src/tools/filter.js +41 -0
- package/src/tools/flex.js +26 -0
- package/src/tools/gradient.js +34 -0
- package/src/tools/grid.js +57 -0
- package/src/tools/index.js +38 -0
- package/src/tools/mapList.js +107 -0
- package/src/tools/margin.js +93 -0
- package/src/tools/memo.js +60 -0
- package/src/tools/os.js +104 -0
- package/src/tools/padding.js +93 -0
- package/src/tools/print.js +69 -0
- package/src/tools/random.js +299 -0
- package/src/tools/ref.js +70 -0
- package/src/tools/rgba.js +4 -0
- package/src/tools/shadow.js +23 -0
- package/src/tools/string.js +85 -0
- package/src/tools/time.js +674 -0
- package/src/tools/transform.js +68 -0
- package/src/tools/transition.js +48 -0
- package/src/tools/useState.js +268 -0
- package/src/tools/uuid.js +42 -0
- package/src/utils/TextInputValidator.js +256 -0
- package/src/utils/composeUpdate.js +65 -0
- package/src/utils/getWidgetProps.js +35 -0
- package/src/utils/index.js +76 -0
- package/src/utils/markdownParser.js +368 -0
- package/src/utils/mediaTime.js +79 -0
- package/src/utils/navigation.js +263 -0
- package/src/utils/scriptInjector.js +73 -0
- package/src/utils/stackPosition.js +31 -0
- package/src/utils/stopWebRefresh.js +77 -0
- package/src/utils/styleInjector.js +38 -0
- package/src/utils/syntaxHighlight.js +339 -0
- package/src/utils/themes.js +347 -0
- package/src/utils/units.js +87 -0
- package/src/utils/visualEffects.js +169 -0
- package/src/widget-factory/addChildren.js +114 -0
- package/src/widget-factory/assignProps.js +256 -0
- package/src/widget-factory/createWidget.js +28 -0
- package/src/widget-factory/effects.js +132 -0
- package/src/widget-factory/index.js +7 -0
- package/src/widget-factory/lifecycle.js +210 -0
- package/src/widget-factory/makeParentable.js +89 -0
- package/src/widget-factory/pixTool.js +40 -0
- package/src/widget-factory/processProps.js +122 -0
- package/src/widget-factory/reactivity.js +98 -0
- package/src/widget-factory/remTool.js +34 -0
- package/src/widget-factory/stackPosition.js +87 -0
- package/src/widget-factory/stringTool.js +26 -0
- package/src/widget-factory/tools.js +249 -0
- package/src/widget-factory/translateProps.js +1049 -0
- package/src/widget-factory/warnings.js +284 -0
- package/src/widget-factory/widgetFactory.js +200 -0
- package/src/widgets/Accordion.js +562 -0
- package/src/widgets/AdMob.js +315 -0
- package/src/widgets/AdSense.js +268 -0
- package/src/widgets/AlertDialog.js +162 -0
- package/src/widgets/Audio.js +311 -0
- package/src/widgets/Avatar.js +210 -0
- package/src/widgets/Badge.js +189 -0
- package/src/widgets/BottomSheet.js +287 -0
- package/src/widgets/Button.js +247 -0
- package/src/widgets/Card.js +33 -0
- package/src/widgets/Carousel.js +301 -0
- package/src/widgets/Chart.js +632 -0
- package/src/widgets/Checkbox.js +106 -0
- package/src/widgets/Chip.js +153 -0
- package/src/widgets/CircularBar.js +352 -0
- package/src/widgets/CircularChart.js +549 -0
- package/src/widgets/CodeViewer.js +236 -0
- package/src/widgets/Column.js +29 -0
- package/src/widgets/Container.js +31 -0
- package/src/widgets/DataTable.js +257 -0
- package/src/widgets/Divider.js +93 -0
- package/src/widgets/DraggBox.js +115 -0
- package/src/widgets/Dropdown.js +505 -0
- package/src/widgets/DroppBox.js +180 -0
- package/src/widgets/FloatingActionButton.js +91 -0
- package/src/widgets/GridView.js +20 -0
- package/src/widgets/Icon.js +33 -0
- package/src/widgets/Image.js +15 -0
- package/src/widgets/Input.js +565 -0
- package/src/widgets/Inspector.js +254 -0
- package/src/widgets/InstallButton.js +110 -0
- package/src/widgets/ListTile.js +224 -0
- package/src/widgets/ListView.js +503 -0
- package/src/widgets/Markdown.js +1236 -0
- package/src/widgets/Modal.js +496 -0
- package/src/widgets/Pagination.js +195 -0
- package/src/widgets/ProgressBar.js +178 -0
- package/src/widgets/QRCode.js +467 -0
- package/src/widgets/Radio.js +132 -0
- package/src/widgets/Rating.js +261 -0
- package/src/widgets/Row.js +29 -0
- package/src/widgets/Skeleton.js +243 -0
- package/src/widgets/Slider.js +527 -0
- package/src/widgets/SnackBar.js +227 -0
- package/src/widgets/Stack.js +29 -0
- package/src/widgets/Stepper.js +296 -0
- package/src/widgets/Switch.js +102 -0
- package/src/widgets/Text.js +98 -0
- package/src/widgets/Tooltip.js +267 -0
- package/src/widgets/TreeView.js +370 -0
- package/src/widgets/Video.js +92 -0
- package/src/widgets/index.js +52 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Button.js
|
|
3
|
+
* @description Button with size presets, variants, icons and gradient support.
|
|
4
|
+
*/
|
|
5
|
+
import { WidgetFactory } from "../widget-factory/index.js";import { colors } from "../utils/themes.js";
|
|
6
|
+
import { Text } from "./Text.js";
|
|
7
|
+
import { Icon } from "./Icon.js";
|
|
8
|
+
|
|
9
|
+
// ============================================================
|
|
10
|
+
// CONFIGURATION
|
|
11
|
+
// ============================================================
|
|
12
|
+
|
|
13
|
+
const SIZE_PRESETS = {
|
|
14
|
+
small: { padding: [6, 12], fontSize: 12, gap: 6, iconSize: 16 },
|
|
15
|
+
medium: { padding: [10, 20], fontSize: 14, gap: 8, iconSize: 20 },
|
|
16
|
+
large: { padding: [14, 28], fontSize: 16, gap: 10, iconSize: 24 },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const SHADOW_LEVELS = {
|
|
20
|
+
0: "none",
|
|
21
|
+
1: "0 1px 3px rgba(0,0,0,0.12)",
|
|
22
|
+
2: "0 3px 6px rgba(0,0,0,0.16)",
|
|
23
|
+
3: "0 6px 12px rgba(0,0,0,0.2)",
|
|
24
|
+
4: "0 10px 20px rgba(0,0,0,0.25)",
|
|
25
|
+
5: "0 15px 30px rgba(0,0,0,0.3)",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// ============================================================
|
|
29
|
+
// HELPERS
|
|
30
|
+
// ============================================================
|
|
31
|
+
|
|
32
|
+
function normalizeSpacing(value, defaultPair) {
|
|
33
|
+
if (value === undefined) return defaultPair;
|
|
34
|
+
if (typeof value === "number") return [value, value * 2];
|
|
35
|
+
if (Array.isArray(value) && value.length === 2) return value;
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function computeBackground(variant, disabled, bgColor, gradient) {
|
|
40
|
+
if (disabled) return colors.gray100;
|
|
41
|
+
if (variant === "filled") return gradient || bgColor || colors.primary;
|
|
42
|
+
return "transparent";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function computeTextColor(variant, disabled, color, bgColor) {
|
|
46
|
+
if (disabled) return colors.textDisabled;
|
|
47
|
+
if (variant === "filled") return color || "#fff";
|
|
48
|
+
return color || bgColor || colors.primary;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function computeBorder(variant, disabled, color, bgColor) {
|
|
52
|
+
if (disabled) return `1px solid ${colors.gray300}`;
|
|
53
|
+
if (variant === "outlined") {
|
|
54
|
+
const borderColor = color || bgColor || colors.primary;
|
|
55
|
+
return `2px solid ${borderColor}`;
|
|
56
|
+
}
|
|
57
|
+
if (variant === "text") return "none";
|
|
58
|
+
return `1px solid ${colors.border}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function createIcon(name, size, color) {
|
|
62
|
+
if (!name) return null;
|
|
63
|
+
return Icon({ name, size, color, display: "inline-flex" });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function resolveIconNames(props) {
|
|
67
|
+
const { icon, iconPosition, iconTop, iconLeft, iconRight, iconBottom } =
|
|
68
|
+
props;
|
|
69
|
+
return {
|
|
70
|
+
top: iconTop || (icon && iconPosition === "top" ? icon : null),
|
|
71
|
+
left: iconLeft || (icon && iconPosition === "left" ? icon : null),
|
|
72
|
+
right: iconRight || (icon && iconPosition === "right" ? icon : null),
|
|
73
|
+
bottom: iconBottom || (icon && iconPosition === "bottom" ? icon : null),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function buildIconElements(iconNames, size, color) {
|
|
78
|
+
return {
|
|
79
|
+
top: createIcon(iconNames.top, size, color),
|
|
80
|
+
left: createIcon(iconNames.left, size, color),
|
|
81
|
+
right: createIcon(iconNames.right, size, color),
|
|
82
|
+
bottom: createIcon(iconNames.bottom, size, color),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function buildButtonChildren(text, textColor, fontSize, gap, iconElements) {
|
|
87
|
+
const children = [];
|
|
88
|
+
|
|
89
|
+
if (iconElements.top) children.push(iconElements.top);
|
|
90
|
+
|
|
91
|
+
const middleRow = [];
|
|
92
|
+
if (iconElements.left) middleRow.push(iconElements.left);
|
|
93
|
+
if (text) {
|
|
94
|
+
middleRow.push(
|
|
95
|
+
Text({ text, color: textColor, size: fontSize, weight: "bold" }),
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
if (iconElements.right) middleRow.push(iconElements.right);
|
|
99
|
+
|
|
100
|
+
if (middleRow.length > 0) {
|
|
101
|
+
children.push(
|
|
102
|
+
WidgetFactory({
|
|
103
|
+
tag: "div",
|
|
104
|
+
display: "flex",
|
|
105
|
+
flexDirection: "row",
|
|
106
|
+
alignItems: "center",
|
|
107
|
+
justifyContent: "center",
|
|
108
|
+
gap,
|
|
109
|
+
child: middleRow,
|
|
110
|
+
}),
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (iconElements.bottom) children.push(iconElements.bottom);
|
|
115
|
+
|
|
116
|
+
if (children.length === 0 && iconElements.left) {
|
|
117
|
+
children.push(iconElements.left);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return children;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function applySpacingToProps(buttonProps, padding, margin) {
|
|
124
|
+
const normalizedPadding = normalizeSpacing(
|
|
125
|
+
padding,
|
|
126
|
+
SIZE_PRESETS.medium.padding,
|
|
127
|
+
);
|
|
128
|
+
const normalizedMargin = normalizeSpacing(margin, undefined);
|
|
129
|
+
|
|
130
|
+
if (Array.isArray(normalizedPadding)) {
|
|
131
|
+
buttonProps.paddingTop = normalizedPadding[0];
|
|
132
|
+
buttonProps.paddingBottom = normalizedPadding[0];
|
|
133
|
+
buttonProps.paddingLeft = normalizedPadding[1];
|
|
134
|
+
buttonProps.paddingRight = normalizedPadding[1];
|
|
135
|
+
} else if (normalizedPadding !== undefined) {
|
|
136
|
+
buttonProps.padding = normalizedPadding;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (Array.isArray(normalizedMargin)) {
|
|
140
|
+
buttonProps.marginTop = normalizedMargin[0];
|
|
141
|
+
buttonProps.marginBottom = normalizedMargin[0];
|
|
142
|
+
buttonProps.marginLeft = normalizedMargin[1];
|
|
143
|
+
buttonProps.marginRight = normalizedMargin[1];
|
|
144
|
+
} else if (normalizedMargin !== undefined) {
|
|
145
|
+
buttonProps.margin = normalizedMargin;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ============================================================
|
|
150
|
+
// MAIN COMPONENT
|
|
151
|
+
// ============================================================
|
|
152
|
+
|
|
153
|
+
export const Button = (props) => {
|
|
154
|
+
const {
|
|
155
|
+
text,
|
|
156
|
+
iconLeft,
|
|
157
|
+
iconRight,
|
|
158
|
+
iconTop,
|
|
159
|
+
iconBottom,
|
|
160
|
+
icon,
|
|
161
|
+
gradient,
|
|
162
|
+
padding,
|
|
163
|
+
margin,
|
|
164
|
+
onPress,
|
|
165
|
+
iconPosition = "left",
|
|
166
|
+
variant = "filled",
|
|
167
|
+
size = "medium",
|
|
168
|
+
borderRadius = 24,
|
|
169
|
+
elevation = 2,
|
|
170
|
+
disabled = false,
|
|
171
|
+
fullWidth = false,
|
|
172
|
+
bgColor = colors.surface,
|
|
173
|
+
color = colors.text,
|
|
174
|
+
...rest
|
|
175
|
+
} = props;
|
|
176
|
+
|
|
177
|
+
const sizePreset = SIZE_PRESETS[size] || SIZE_PRESETS.medium;
|
|
178
|
+
const shadow = SHADOW_LEVELS[elevation] || SHADOW_LEVELS[0];
|
|
179
|
+
|
|
180
|
+
const background = computeBackground(variant, disabled, bgColor, gradient);
|
|
181
|
+
const textColor = computeTextColor(variant, disabled, color, bgColor);
|
|
182
|
+
const border = computeBorder(variant, disabled, color, bgColor);
|
|
183
|
+
|
|
184
|
+
const iconNames = resolveIconNames({
|
|
185
|
+
icon,
|
|
186
|
+
iconPosition,
|
|
187
|
+
iconTop,
|
|
188
|
+
iconLeft,
|
|
189
|
+
iconRight,
|
|
190
|
+
iconBottom,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const iconElements = buildIconElements(
|
|
194
|
+
iconNames,
|
|
195
|
+
sizePreset.iconSize,
|
|
196
|
+
textColor,
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const children = buildButtonChildren(
|
|
200
|
+
text,
|
|
201
|
+
textColor,
|
|
202
|
+
sizePreset.fontSize,
|
|
203
|
+
sizePreset.gap,
|
|
204
|
+
iconElements,
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
const hasTopOrBottomIcon = !!(iconElements.top || iconElements.bottom);
|
|
208
|
+
const flexDirection = hasTopOrBottomIcon ? "column" : "row";
|
|
209
|
+
|
|
210
|
+
const buttonProps = {
|
|
211
|
+
tag: "button",
|
|
212
|
+
widgetName: "Button",
|
|
213
|
+
display: "inline-flex",
|
|
214
|
+
flexDirection,
|
|
215
|
+
alignItems: "center",
|
|
216
|
+
justifyContent: "center",
|
|
217
|
+
gap: sizePreset.gap,
|
|
218
|
+
borderRadius,
|
|
219
|
+
width: fullWidth ? "100%" : "auto",
|
|
220
|
+
backgroundColor: background,
|
|
221
|
+
border,
|
|
222
|
+
color: textColor,
|
|
223
|
+
boxShadow: shadow,
|
|
224
|
+
cursor: disabled ? "not-allowed" : "pointer",
|
|
225
|
+
opacity: disabled ? 0.6 : 1,
|
|
226
|
+
transition: "all 0.2s ease",
|
|
227
|
+
boxSizing: fullWidth ? "border-box" : undefined,
|
|
228
|
+
flexShrink: fullWidth ? undefined : 0,
|
|
229
|
+
onclick: disabled ? null : onPress,
|
|
230
|
+
child: children.length === 1 ? children[0] : children,
|
|
231
|
+
...rest,
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
applySpacingToProps(buttonProps, padding, margin);
|
|
235
|
+
|
|
236
|
+
if (gradient) {
|
|
237
|
+
buttonProps.background = gradient;
|
|
238
|
+
delete buttonProps.backgroundColor;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const button = WidgetFactory(buttonProps);
|
|
242
|
+
button.setAttribute("type", "button");
|
|
243
|
+
|
|
244
|
+
return button;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
export default Button;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Card.js
|
|
3
|
+
* @description Elevated surface card with optional border, padding and radius.
|
|
4
|
+
*/
|
|
5
|
+
import { WidgetFactory } from "../widget-factory/index.js";
|
|
6
|
+
import { colors } from "../utils/themes.js";
|
|
7
|
+
import { border } from "../tools/index.js";
|
|
8
|
+
|
|
9
|
+
export const Card = (props = {}) => {
|
|
10
|
+
const {
|
|
11
|
+
elevation = 2,
|
|
12
|
+
padding = 16,
|
|
13
|
+
borderRadius = 12,
|
|
14
|
+
bgColor = colors.surface,
|
|
15
|
+
borderColor = colors.border,
|
|
16
|
+
borderWidth = 1,
|
|
17
|
+
borderStyle = "solid",
|
|
18
|
+
showBorder = true,
|
|
19
|
+
...rest
|
|
20
|
+
} = props;
|
|
21
|
+
|
|
22
|
+
return WidgetFactory({
|
|
23
|
+
widgetName: "Card",
|
|
24
|
+
backgroundColor: bgColor,
|
|
25
|
+
borderRadius: borderRadius,
|
|
26
|
+
padding: padding,
|
|
27
|
+
elevation: elevation,
|
|
28
|
+
border: showBorder ? border(borderWidth, borderStyle, borderColor) : "none",
|
|
29
|
+
...rest,
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default Card;
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Carousel.js
|
|
3
|
+
* @description Swipeable carousel of slides with navigation controls.
|
|
4
|
+
*/
|
|
5
|
+
import { WidgetFactory } from "../widget-factory/index.js";
|
|
6
|
+
import { Icon } from "./Icon.js";
|
|
7
|
+
import { colors } from "../utils/themes.js";
|
|
8
|
+
|
|
9
|
+
export const Carousel = (props) => {
|
|
10
|
+
const {
|
|
11
|
+
items = [],
|
|
12
|
+
autoPlay = false,
|
|
13
|
+
interval = 3000,
|
|
14
|
+
showArrows = true,
|
|
15
|
+
showDots = true,
|
|
16
|
+
infinite = true,
|
|
17
|
+
height = 300,
|
|
18
|
+
width = "100%",
|
|
19
|
+
borderRadius = 12,
|
|
20
|
+
onIndexChange,
|
|
21
|
+
onPress,
|
|
22
|
+
|
|
23
|
+
// Dot customization
|
|
24
|
+
dotColor = colors.gray300,
|
|
25
|
+
dotActiveColor = colors.primary,
|
|
26
|
+
dotSize = 8,
|
|
27
|
+
dotActiveSize = 20,
|
|
28
|
+
|
|
29
|
+
// Button customization
|
|
30
|
+
buttonBgColor = colors.surface,
|
|
31
|
+
buttonIconColor = colors.secondary,
|
|
32
|
+
buttonSize = 36,
|
|
33
|
+
buttonIconSize = 24,
|
|
34
|
+
buttonTop = "46%",
|
|
35
|
+
|
|
36
|
+
...rest
|
|
37
|
+
} = props;
|
|
38
|
+
|
|
39
|
+
if (!items.length) return null;
|
|
40
|
+
|
|
41
|
+
let currentIndex = 0;
|
|
42
|
+
let autoPlayInterval = null;
|
|
43
|
+
let isTransitioning = false;
|
|
44
|
+
let trackRef = null;
|
|
45
|
+
let dotsContainerRef = null;
|
|
46
|
+
|
|
47
|
+
const updatePosition = (animate = true) => {
|
|
48
|
+
if (!trackRef) return;
|
|
49
|
+
trackRef.style.transition = animate ? "transform 0.3s ease-in-out" : "none";
|
|
50
|
+
trackRef.style.transform = `translateX(-${currentIndex * (100 / items.length)}%)`;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const updateDots = () => {
|
|
54
|
+
if (!dotsContainerRef) return;
|
|
55
|
+
const dots = dotsContainerRef.children;
|
|
56
|
+
for (let i = 0; i < dots.length; i++) {
|
|
57
|
+
const dot = dots[i];
|
|
58
|
+
if (i === currentIndex) {
|
|
59
|
+
dot.style.backgroundColor = dotActiveColor;
|
|
60
|
+
dot.style.width =
|
|
61
|
+
typeof dotActiveSize === "number"
|
|
62
|
+
? `${dotActiveSize}px`
|
|
63
|
+
: dotActiveSize;
|
|
64
|
+
} else {
|
|
65
|
+
dot.style.backgroundColor = dotColor;
|
|
66
|
+
dot.style.width =
|
|
67
|
+
typeof dotSize === "number" ? `${dotSize}px` : dotSize;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const next = () => {
|
|
73
|
+
if (isTransitioning) return;
|
|
74
|
+
isTransitioning = true;
|
|
75
|
+
|
|
76
|
+
let newIndex = currentIndex + 1;
|
|
77
|
+
if (newIndex >= items.length) {
|
|
78
|
+
if (infinite) newIndex = 0;
|
|
79
|
+
else {
|
|
80
|
+
isTransitioning = false;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
currentIndex = newIndex;
|
|
86
|
+
updatePosition(true);
|
|
87
|
+
updateDots();
|
|
88
|
+
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
isTransitioning = false;
|
|
91
|
+
}, 350);
|
|
92
|
+
const cb = onIndexChange || onPress;
|
|
93
|
+
if (cb) cb(currentIndex);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const prev = () => {
|
|
97
|
+
if (isTransitioning) return;
|
|
98
|
+
isTransitioning = true;
|
|
99
|
+
|
|
100
|
+
let newIndex = currentIndex - 1;
|
|
101
|
+
if (newIndex < 0) {
|
|
102
|
+
if (infinite) newIndex = items.length - 1;
|
|
103
|
+
else {
|
|
104
|
+
isTransitioning = false;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
currentIndex = newIndex;
|
|
110
|
+
updatePosition(true);
|
|
111
|
+
updateDots();
|
|
112
|
+
|
|
113
|
+
setTimeout(() => {
|
|
114
|
+
isTransitioning = false;
|
|
115
|
+
}, 350);
|
|
116
|
+
const cb = onIndexChange || onPress;
|
|
117
|
+
if (cb) cb(currentIndex);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const goTo = (index) => {
|
|
121
|
+
if (isTransitioning) return;
|
|
122
|
+
if (index < 0 || index >= items.length) return;
|
|
123
|
+
isTransitioning = true;
|
|
124
|
+
currentIndex = index;
|
|
125
|
+
updatePosition(true);
|
|
126
|
+
updateDots();
|
|
127
|
+
setTimeout(() => {
|
|
128
|
+
isTransitioning = false;
|
|
129
|
+
}, 350);
|
|
130
|
+
const cb = onIndexChange || onPress;
|
|
131
|
+
if (cb) cb(currentIndex);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const startAutoPlay = () => {
|
|
135
|
+
if (!autoPlay || items.length <= 1) return;
|
|
136
|
+
if (autoPlayInterval) clearInterval(autoPlayInterval);
|
|
137
|
+
autoPlayInterval = setInterval(next, interval);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const stopAutoPlay = () => {
|
|
141
|
+
if (autoPlayInterval) {
|
|
142
|
+
clearInterval(autoPlayInterval);
|
|
143
|
+
autoPlayInterval = null;
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const createArrow = (position, iconName, onClick) => {
|
|
148
|
+
const isLeft = position === "left";
|
|
149
|
+
return WidgetFactory({
|
|
150
|
+
position: "absolute",
|
|
151
|
+
left: isLeft ? "10px" : "auto",
|
|
152
|
+
right: isLeft ? "auto" : "10px",
|
|
153
|
+
top: buttonTop,
|
|
154
|
+
cursor: "pointer",
|
|
155
|
+
backgroundColor: buttonBgColor,
|
|
156
|
+
borderRadius: "50%",
|
|
157
|
+
width: typeof buttonSize === "number" ? `${buttonSize}px` : buttonSize,
|
|
158
|
+
height: typeof buttonSize === "number" ? `${buttonSize}px` : buttonSize,
|
|
159
|
+
display: "flex",
|
|
160
|
+
alignItems: "center",
|
|
161
|
+
justifyContent: "center",
|
|
162
|
+
zIndex: 10,
|
|
163
|
+
child: Icon({
|
|
164
|
+
name: iconName,
|
|
165
|
+
size: buttonIconSize,
|
|
166
|
+
color: buttonIconColor,
|
|
167
|
+
}),
|
|
168
|
+
onclick: onClick,
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Main container
|
|
173
|
+
const container = WidgetFactory({
|
|
174
|
+
widgetName: "Carousel",
|
|
175
|
+
position: "relative",
|
|
176
|
+
width: typeof width === "number" ? `${width}px` : width,
|
|
177
|
+
height: typeof height === "number" ? `${height}px` : height,
|
|
178
|
+
overflow: "hidden",
|
|
179
|
+
borderRadius:
|
|
180
|
+
typeof borderRadius === "number" ? `${borderRadius}px` : borderRadius,
|
|
181
|
+
...rest,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Track container
|
|
185
|
+
const track = WidgetFactory({
|
|
186
|
+
display: "flex",
|
|
187
|
+
transition: "transform 0.3s ease-in-out",
|
|
188
|
+
height: "100%",
|
|
189
|
+
width: `${items.length * 100}%`,
|
|
190
|
+
});
|
|
191
|
+
trackRef = track;
|
|
192
|
+
|
|
193
|
+
// Createste slides
|
|
194
|
+
items.forEach((item) => {
|
|
195
|
+
const slide = WidgetFactory({
|
|
196
|
+
width: `${100 / items.length}%`,
|
|
197
|
+
height: "100%",
|
|
198
|
+
flexShrink: 0,
|
|
199
|
+
display: "flex",
|
|
200
|
+
justifyContent: "center",
|
|
201
|
+
alignItems: "center",
|
|
202
|
+
overflow: "hidden",
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
if (item instanceof HTMLElement) {
|
|
206
|
+
slide.appendChild(item);
|
|
207
|
+
} else if (typeof item === "string") {
|
|
208
|
+
const img = document.createElement("img");
|
|
209
|
+
img.src = item;
|
|
210
|
+
img.style.width = "100%";
|
|
211
|
+
img.style.height = "100%";
|
|
212
|
+
img.style.objectFit = "cover";
|
|
213
|
+
img.onerror = () => {
|
|
214
|
+
console.error("Image not loaded:", item);
|
|
215
|
+
};
|
|
216
|
+
slide.appendChild(img);
|
|
217
|
+
} else if (item && typeof item === "object" && item.src) {
|
|
218
|
+
const img = document.createElement("img");
|
|
219
|
+
img.src = item.src;
|
|
220
|
+
img.alt = item.alt || "";
|
|
221
|
+
img.style.width = "100%";
|
|
222
|
+
img.style.height = "100%";
|
|
223
|
+
img.style.objectFit = "cover";
|
|
224
|
+
slide.appendChild(img);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
track.appendChild(slide);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
container.appendChild(track);
|
|
231
|
+
|
|
232
|
+
// Navigation arrows
|
|
233
|
+
if (showArrows && items.length > 1) {
|
|
234
|
+
const prevArrow = createArrow("left", "chevron_left", prev);
|
|
235
|
+
const nextArrow = createArrow("right", "chevron_right", next);
|
|
236
|
+
container.appendChild(prevArrow);
|
|
237
|
+
container.appendChild(nextArrow);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Dots indicators
|
|
241
|
+
if (showDots && items.length > 1) {
|
|
242
|
+
const dotsContainer = WidgetFactory({
|
|
243
|
+
position: "absolute",
|
|
244
|
+
bottom: "15px",
|
|
245
|
+
left: "50%",
|
|
246
|
+
transform: "translateX(-50%)",
|
|
247
|
+
display: "flex",
|
|
248
|
+
gap: "8px",
|
|
249
|
+
zIndex: 10,
|
|
250
|
+
});
|
|
251
|
+
dotsContainerRef = dotsContainer;
|
|
252
|
+
|
|
253
|
+
items.forEach((_, index) => {
|
|
254
|
+
const dot = WidgetFactory({
|
|
255
|
+
width:
|
|
256
|
+
index === currentIndex
|
|
257
|
+
? typeof dotActiveSize === "number"
|
|
258
|
+
? `${dotActiveSize}px`
|
|
259
|
+
: dotActiveSize
|
|
260
|
+
: typeof dotSize === "number"
|
|
261
|
+
? `${dotSize}px`
|
|
262
|
+
: dotSize,
|
|
263
|
+
height: typeof dotSize === "number" ? `${dotSize}px` : dotSize,
|
|
264
|
+
borderRadius: "4px",
|
|
265
|
+
backgroundColor: index === currentIndex ? dotActiveColor : dotColor,
|
|
266
|
+
cursor: "pointer",
|
|
267
|
+
transition: "all 0.2s",
|
|
268
|
+
onclick: () => goTo(index),
|
|
269
|
+
});
|
|
270
|
+
dotsContainer.appendChild(dot);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
container.appendChild(dotsContainer);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Initialize position
|
|
277
|
+
updatePosition(false);
|
|
278
|
+
updateDots();
|
|
279
|
+
|
|
280
|
+
// Autoplay setup
|
|
281
|
+
if (autoPlay) {
|
|
282
|
+
startAutoPlay();
|
|
283
|
+
container.addEventListener("mouseenter", stopAutoPlay);
|
|
284
|
+
container.addEventListener("mouseleave", startAutoPlay);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Public methods
|
|
288
|
+
container.next = next;
|
|
289
|
+
container.prev = prev;
|
|
290
|
+
container.goTo = goTo;
|
|
291
|
+
container.getCurrentIndex = () => currentIndex;
|
|
292
|
+
|
|
293
|
+
// Cleanup
|
|
294
|
+
container.onUnmount(() => {
|
|
295
|
+
stopAutoPlay();
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
return container;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
export default Carousel;
|