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.
Files changed (178) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +190 -2
  3. package/bin/cli.js +394 -0
  4. package/bin/commands/buildAndroid.js +200 -0
  5. package/bin/commands/buildIOS.js +237 -0
  6. package/bin/commands/create.js +406 -0
  7. package/bin/commands/createBundle.js +375 -0
  8. package/bin/commands/createComponent.js +115 -0
  9. package/bin/commands/createScreen.js +161 -0
  10. package/bin/commands/killServer.js +107 -0
  11. package/bin/commands/package.js +131 -0
  12. package/bin/commands/release.js +189 -0
  13. package/bin/commands/runBundle.js +62 -0
  14. package/bin/commands/runCloudflare.js +89 -0
  15. package/bin/commands/runNative.js +109 -0
  16. package/bin/commands/runServer.js +390 -0
  17. package/bin/ota/loader.js +361 -0
  18. package/bin/utils/bundleConfig.js +178 -0
  19. package/bin/utils/capacitor.js +137 -0
  20. package/bin/utils/colors.js +215 -0
  21. package/bin/utils/helpers.js +80 -0
  22. package/bin/utils/spinner.js +96 -0
  23. package/bin/utils/templates.js +1824 -0
  24. package/bin/utils/version.js +108 -0
  25. package/package.json +58 -4
  26. package/src/animations/AnimatedBox.js +607 -0
  27. package/src/animations/AnimatedText.js +105 -0
  28. package/src/animations/MatrixRain.js +220 -0
  29. package/src/animations/ParallaxBox.js +369 -0
  30. package/src/animations/animate.js +332 -0
  31. package/src/animations/index.js +25 -0
  32. package/src/app.js +41 -0
  33. package/src/assets/icon-1024-maskable.png +0 -0
  34. package/src/assets/icon-192-maskable.png +0 -0
  35. package/src/assets/icon-192.png +0 -0
  36. package/src/assets/icon-512-maskable.png +0 -0
  37. package/src/assets/icon-512.png +0 -0
  38. package/src/assets/logo.png +0 -0
  39. package/src/core/App.js +44 -0
  40. package/src/core/hmr-client.js +142 -0
  41. package/src/core/index.js +34 -0
  42. package/src/core/pwa.js +100 -0
  43. package/src/core/runApp.js +430 -0
  44. package/src/create-index.sh +237 -0
  45. package/src/fonts/MaterialIcons-Regular.woff2 +0 -0
  46. package/src/fonts/icons.css +23 -0
  47. package/src/index.d.ts +1930 -0
  48. package/src/index.js +288 -0
  49. package/src/navigations/AdaptiveScaffold.js +149 -0
  50. package/src/navigations/AppBar.js +331 -0
  51. package/src/navigations/BottomNavigation.js +298 -0
  52. package/src/navigations/CollapsibleSideBar.js +139 -0
  53. package/src/navigations/Drawer.js +333 -0
  54. package/src/navigations/DrawerItem.js +260 -0
  55. package/src/navigations/Router.js +475 -0
  56. package/src/navigations/Scaffold.js +537 -0
  57. package/src/navigations/Tabs.js +384 -0
  58. package/src/navigations/index.js +57 -0
  59. package/src/services/RamStore.js +213 -0
  60. package/src/services/Session.js +310 -0
  61. package/src/services/Storage.js +309 -0
  62. package/src/services/http.js +350 -0
  63. package/src/services/index.js +57 -0
  64. package/src/tools/animation.js +42 -0
  65. package/src/tools/array.js +95 -0
  66. package/src/tools/border.js +28 -0
  67. package/src/tools/clipboard.js +104 -0
  68. package/src/tools/color.js +329 -0
  69. package/src/tools/createList.js +215 -0
  70. package/src/tools/delay.js +55 -0
  71. package/src/tools/device.js +138 -0
  72. package/src/tools/dict.js +297 -0
  73. package/src/tools/dimensions.js +118 -0
  74. package/src/tools/filter.js +41 -0
  75. package/src/tools/flex.js +26 -0
  76. package/src/tools/gradient.js +34 -0
  77. package/src/tools/grid.js +57 -0
  78. package/src/tools/index.js +38 -0
  79. package/src/tools/mapList.js +107 -0
  80. package/src/tools/margin.js +93 -0
  81. package/src/tools/memo.js +60 -0
  82. package/src/tools/os.js +104 -0
  83. package/src/tools/padding.js +93 -0
  84. package/src/tools/print.js +69 -0
  85. package/src/tools/random.js +299 -0
  86. package/src/tools/ref.js +70 -0
  87. package/src/tools/rgba.js +4 -0
  88. package/src/tools/shadow.js +23 -0
  89. package/src/tools/string.js +85 -0
  90. package/src/tools/time.js +674 -0
  91. package/src/tools/transform.js +68 -0
  92. package/src/tools/transition.js +48 -0
  93. package/src/tools/useState.js +268 -0
  94. package/src/tools/uuid.js +42 -0
  95. package/src/utils/TextInputValidator.js +256 -0
  96. package/src/utils/composeUpdate.js +65 -0
  97. package/src/utils/getWidgetProps.js +35 -0
  98. package/src/utils/index.js +76 -0
  99. package/src/utils/markdownParser.js +368 -0
  100. package/src/utils/mediaTime.js +79 -0
  101. package/src/utils/navigation.js +263 -0
  102. package/src/utils/scriptInjector.js +73 -0
  103. package/src/utils/stackPosition.js +31 -0
  104. package/src/utils/stopWebRefresh.js +77 -0
  105. package/src/utils/styleInjector.js +38 -0
  106. package/src/utils/syntaxHighlight.js +339 -0
  107. package/src/utils/themes.js +347 -0
  108. package/src/utils/units.js +87 -0
  109. package/src/utils/visualEffects.js +169 -0
  110. package/src/widget-factory/addChildren.js +114 -0
  111. package/src/widget-factory/assignProps.js +256 -0
  112. package/src/widget-factory/createWidget.js +28 -0
  113. package/src/widget-factory/effects.js +132 -0
  114. package/src/widget-factory/index.js +7 -0
  115. package/src/widget-factory/lifecycle.js +210 -0
  116. package/src/widget-factory/makeParentable.js +89 -0
  117. package/src/widget-factory/pixTool.js +40 -0
  118. package/src/widget-factory/processProps.js +122 -0
  119. package/src/widget-factory/reactivity.js +98 -0
  120. package/src/widget-factory/remTool.js +34 -0
  121. package/src/widget-factory/stackPosition.js +87 -0
  122. package/src/widget-factory/stringTool.js +26 -0
  123. package/src/widget-factory/tools.js +249 -0
  124. package/src/widget-factory/translateProps.js +1049 -0
  125. package/src/widget-factory/warnings.js +284 -0
  126. package/src/widget-factory/widgetFactory.js +200 -0
  127. package/src/widgets/Accordion.js +562 -0
  128. package/src/widgets/AdMob.js +315 -0
  129. package/src/widgets/AdSense.js +268 -0
  130. package/src/widgets/AlertDialog.js +162 -0
  131. package/src/widgets/Audio.js +311 -0
  132. package/src/widgets/Avatar.js +210 -0
  133. package/src/widgets/Badge.js +189 -0
  134. package/src/widgets/BottomSheet.js +287 -0
  135. package/src/widgets/Button.js +247 -0
  136. package/src/widgets/Card.js +33 -0
  137. package/src/widgets/Carousel.js +301 -0
  138. package/src/widgets/Chart.js +632 -0
  139. package/src/widgets/Checkbox.js +106 -0
  140. package/src/widgets/Chip.js +153 -0
  141. package/src/widgets/CircularBar.js +352 -0
  142. package/src/widgets/CircularChart.js +549 -0
  143. package/src/widgets/CodeViewer.js +236 -0
  144. package/src/widgets/Column.js +29 -0
  145. package/src/widgets/Container.js +31 -0
  146. package/src/widgets/DataTable.js +257 -0
  147. package/src/widgets/Divider.js +93 -0
  148. package/src/widgets/DraggBox.js +115 -0
  149. package/src/widgets/Dropdown.js +505 -0
  150. package/src/widgets/DroppBox.js +180 -0
  151. package/src/widgets/FloatingActionButton.js +91 -0
  152. package/src/widgets/GridView.js +20 -0
  153. package/src/widgets/Icon.js +33 -0
  154. package/src/widgets/Image.js +15 -0
  155. package/src/widgets/Input.js +565 -0
  156. package/src/widgets/Inspector.js +254 -0
  157. package/src/widgets/InstallButton.js +110 -0
  158. package/src/widgets/ListTile.js +224 -0
  159. package/src/widgets/ListView.js +503 -0
  160. package/src/widgets/Markdown.js +1236 -0
  161. package/src/widgets/Modal.js +496 -0
  162. package/src/widgets/Pagination.js +195 -0
  163. package/src/widgets/ProgressBar.js +178 -0
  164. package/src/widgets/QRCode.js +467 -0
  165. package/src/widgets/Radio.js +132 -0
  166. package/src/widgets/Rating.js +261 -0
  167. package/src/widgets/Row.js +29 -0
  168. package/src/widgets/Skeleton.js +243 -0
  169. package/src/widgets/Slider.js +527 -0
  170. package/src/widgets/SnackBar.js +227 -0
  171. package/src/widgets/Stack.js +29 -0
  172. package/src/widgets/Stepper.js +296 -0
  173. package/src/widgets/Switch.js +102 -0
  174. package/src/widgets/Text.js +98 -0
  175. package/src/widgets/Tooltip.js +267 -0
  176. package/src/widgets/TreeView.js +370 -0
  177. package/src/widgets/Video.js +92 -0
  178. package/src/widgets/index.js +52 -0
@@ -0,0 +1,227 @@
1
+ /**
2
+ * @file SnackBar.js
3
+ * @description Transient toast controller returned to callers (`show`/`close`).
4
+ */
5
+ import { WidgetFactory } from "../widget-factory/index.js";
6
+ import { border } from "../tools/index.js";
7
+ import { colors } from "../utils/themes.js";
8
+
9
+ // Fallback colors (if the theme is not initialized yet)
10
+ const FALLBACK = {
11
+ gray800: "#1e293b",
12
+ primary: "#6366f1",
13
+ success: "#10b981",
14
+ danger: "#ef4444",
15
+ warning: "#f59e0b",
16
+ info: "#3b82f6",
17
+ gray900: "#0f172a",
18
+ white: "#ffffff",
19
+ };
20
+
21
+ // Safe function to get theme color
22
+ const getThemeColor = (name, fallback) => {
23
+ try {
24
+ return (colors && colors[name]) || fallback;
25
+ } catch {
26
+ return fallback;
27
+ }
28
+ };
29
+
30
+ /**
31
+ * SnackBar - Notificación temporal
32
+ * @param {Object} options
33
+ * @returns {Object} { close, show, getElement }
34
+ */
35
+ export function SnackBar(options) {
36
+ const {
37
+ message,
38
+ action,
39
+ onAction,
40
+ duration = 3000,
41
+ type = "normal", // 'normal', 'success', 'error', 'warning', 'info'
42
+ position = "bottom", // 'bottom', 'top'
43
+ backgroundColor: customBg,
44
+ textColor: customText,
45
+ actionColor: customAction,
46
+ dismissible = false,
47
+ borderRadius = 16,
48
+ padding = "12px 16px",
49
+ margin = 16,
50
+ elevation = 2,
51
+ animationDuration = 300,
52
+ zIndex = 10000,
53
+ onShow,
54
+ onClose,
55
+ } = options;
56
+
57
+ // Presets using theme colors (with fallback)
58
+ const presets = {
59
+ normal: {
60
+ bg: colors.surface,
61
+ text: colors.text,
62
+ action: colors.primary,
63
+ },
64
+ success: {
65
+ bg: colors.success,
66
+ text: colors.text,
67
+ action: colors.primary,
68
+ },
69
+ error: {
70
+ bg: colors.danger,
71
+ text: colors.text,
72
+ action: colors.primary,
73
+ },
74
+ warning: {
75
+ bg: colors.warning,
76
+ text: colors.text,
77
+ action: getThemeColor("gray900", FALLBACK.gray900),
78
+ },
79
+ info: {
80
+ bg: colors.info,
81
+ text: colors.text,
82
+ action: FALLBACK.white,
83
+ },
84
+ };
85
+
86
+ const preset = presets[type] || presets.normal;
87
+ const finalBg = customBg || preset.bg;
88
+ const finalText = customText || preset.text;
89
+ const finalAction = customAction || preset.action;
90
+
91
+ // Createste main container
92
+ const snackbar = WidgetFactory({
93
+ tag: "div",
94
+ position: "fixed",
95
+ left: `${margin}px`,
96
+ // borderRadius: borderRadius,
97
+ right: `${margin}px`,
98
+ [position]: `${margin}px`,
99
+ backgroundColor: finalBg,
100
+ borderRadius:
101
+ typeof borderRadius === "number" ? `${borderRadius}px` : borderRadius,
102
+ padding: padding,
103
+ border: border(1, "solid", colors.gray100),
104
+ zIndex: zIndex,
105
+ boxShadow:
106
+ elevation === 0
107
+ ? "none"
108
+ : `0 ${elevation}px ${elevation * 2}px rgba(0,0,0,0.15)`,
109
+ opacity: 0,
110
+ transform:
111
+ position === "bottom"
112
+ ? `translateY(calc(100% + ${margin}px))`
113
+ : `translateY(calc(-100% - ${margin}px))`,
114
+ transition: `opacity ${animationDuration}ms ease, transform ${animationDuration}ms ease`,
115
+ display: "flex",
116
+ alignItems: "center",
117
+ justifyContent: "space-between",
118
+ gap: 16,
119
+ fontSize: 14,
120
+ lineHeight: "1.4",
121
+ color: finalText,
122
+ fontFamily: "system-ui, -apple-system, sans-serif",
123
+ flexWrap: "wrap",
124
+ });
125
+
126
+ let timeoutId = null;
127
+
128
+ const show = () => {
129
+ requestAnimationFrame(() => {
130
+ snackbar.style.opacity = "1";
131
+ snackbar.style.transform = "translateY(0)";
132
+ });
133
+ if (onShow) onShow();
134
+ };
135
+
136
+ const close = () => {
137
+ if (timeoutId) clearTimeout(timeoutId);
138
+ snackbar.style.opacity = "0";
139
+ snackbar.style.transform =
140
+ position === "bottom"
141
+ ? `translateY(calc(100% + ${margin}px))`
142
+ : `translateY(calc(-100% - ${margin}px))`;
143
+ setTimeout(() => {
144
+ if (snackbar.parentNode) snackbar.parentNode.removeChild(snackbar);
145
+ if (onClose) onClose();
146
+ }, animationDuration);
147
+ };
148
+
149
+ // Message
150
+ const messageEl = WidgetFactory({
151
+ tag: "span",
152
+ flex: 1,
153
+ text: message,
154
+ wordBreak: "break-word",
155
+ });
156
+ snackbar.appendChild(messageEl);
157
+
158
+ // Action button
159
+ let actionBtn = null;
160
+ if (action) {
161
+ actionBtn = WidgetFactory({
162
+ tag: "button",
163
+ backgroundColor: "transparent",
164
+ border: "none",
165
+ color: finalAction,
166
+ fontSize: 14,
167
+ fontWeight: 500,
168
+ cursor: "pointer",
169
+ padding: "4px 8px",
170
+ margin: "-4px -8px -4px 0",
171
+ borderRadius: 4,
172
+ transition: "opacity 0.2s ease",
173
+ textContent: action,
174
+ onclick: () => {
175
+ if (onAction) onAction();
176
+ close();
177
+ },
178
+ });
179
+ actionBtn.addEventListener("mouseenter", () => {
180
+ actionBtn.style.opacity = "0.8";
181
+ });
182
+ actionBtn.addEventListener("mouseleave", () => {
183
+ actionBtn.style.opacity = "1";
184
+ });
185
+ snackbar.appendChild(actionBtn);
186
+ }
187
+
188
+ // Close button (if dismissible and no action)
189
+ let closeBtn = null;
190
+ if (dismissible && !action) {
191
+ closeBtn = WidgetFactory({
192
+ tag: "button",
193
+ backgroundColor: "transparent",
194
+ border: "none",
195
+ color: finalText,
196
+ fontSize: "18px",
197
+ cursor: "pointer",
198
+ padding: "0 4px",
199
+ margin: "-4px 0 -4px 8px",
200
+ opacity: 0.7,
201
+ transition: "opacity 0.2s ease",
202
+ textContent: "✕",
203
+ onclick: close,
204
+ });
205
+ closeBtn.addEventListener("mouseenter", () => {
206
+ closeBtn.style.opacity = "1";
207
+ });
208
+ closeBtn.addEventListener("mouseleave", () => {
209
+ closeBtn.style.opacity = "0.7";
210
+ });
211
+ snackbar.appendChild(closeBtn);
212
+ }
213
+
214
+ // Add to DOM
215
+ document.body.appendChild(snackbar);
216
+ // Force reflow
217
+ snackbar.offsetHeight;
218
+
219
+ show();
220
+ if (duration > 0) {
221
+ timeoutId = setTimeout(close, duration);
222
+ }
223
+
224
+ return { close, show, getElement: () => snackbar };
225
+ }
226
+
227
+ export default SnackBar;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @file Stack.js
3
+ * @description Positioning container for overlaying children (relative by default,
4
+ * use `position: "stack"` for absolute centering).
5
+ */
6
+ import { WidgetFactory } from "../widget-factory/index.js";
7
+
8
+ export const Stack = (props = {}) => {
9
+ const {
10
+ // Default layout
11
+ position = "relative",
12
+ display = "block",
13
+ boxSizing = "border-box",
14
+
15
+ // Everything else
16
+ ...rest
17
+ } = props;
18
+
19
+ return WidgetFactory({
20
+ tag: "div",
21
+ widgetName: "Stack",
22
+ position: position,
23
+ display: display,
24
+ boxSizing: boxSizing,
25
+ ...rest,
26
+ });
27
+ };
28
+
29
+ export default Stack;
@@ -0,0 +1,296 @@
1
+ /**
2
+ * @file Stepper.js
3
+ * @description Multi-step progress indicator with a horizontally scrollable track.
4
+ */
5
+ import { WidgetFactory } from "../widget-factory/index.js";
6
+ import { Container } from "./Container.js";
7
+ import { Row } from "./Row.js";
8
+ import { Column } from "./Column.js";
9
+ import { Text } from "./Text.js";
10
+ import { Icon } from "./Icon.js";
11
+ import { Button } from "./Button.js";
12
+ import { colors } from "../utils/themes.js";
13
+
14
+ export const Stepper = (props) => {
15
+ const {
16
+ steps = [],
17
+ activeStep = 0,
18
+ onStepChange,
19
+ orientation = "horizontal",
20
+ variant = "circles",
21
+ showLabels = true,
22
+ showNavigation = true,
23
+ nextLabel = "Next",
24
+ backLabel = "Back",
25
+ finishLabel = "Finish",
26
+ onFinish,
27
+
28
+ // Styling props
29
+ bgColor = colors.surface,
30
+ borderRadius = 16,
31
+ border,
32
+ borderColor = colors.border,
33
+ borderWidth = 1,
34
+ shadow,
35
+ padding = 20,
36
+ margin = 0,
37
+ width = "100%",
38
+ ...rest
39
+ } = props;
40
+
41
+ let currentStep = Math.min(Math.max(activeStep, 0), steps.length - 1);
42
+ let stepsContainer = null;
43
+ let contentContainer = null;
44
+ let navContainer = null;
45
+
46
+ const goToStep = (index) => {
47
+ if (index < 0 || index >= steps.length) return;
48
+ currentStep = index;
49
+ if (onStepChange) onStepChange(currentStep);
50
+ updateUI();
51
+ };
52
+
53
+ const next = () => goToStep(currentStep + 1);
54
+ const back = () => goToStep(currentStep - 1);
55
+ const finish = () => onFinish?.();
56
+
57
+ const updateUI = () => {
58
+ if (!stepsContainer) return;
59
+
60
+ // Clear steps container
61
+ while (stepsContainer.firstChild) {
62
+ stepsContainer.removeChild(stepsContainer.firstChild);
63
+ }
64
+
65
+ // Calculatesteste if we need to wrap or scroll
66
+ const stepWidth = 80;
67
+ const totalSteps = steps.length;
68
+ const availableWidth = stepsContainer.parentElement?.offsetWidth || 800;
69
+ const needsWrap =
70
+ orientation === "horizontal" && totalSteps * stepWidth > availableWidth;
71
+
72
+ // Draw each step
73
+ steps.forEach((step, idx) => {
74
+ const isActive = idx === currentStep;
75
+ const isCompleted = idx < currentStep;
76
+ const isLast = idx === steps.length - 1;
77
+
78
+ // Step indicator
79
+ let indicator;
80
+ if (variant === "circles") {
81
+ indicator = Container({
82
+ width: 32,
83
+ height: 32,
84
+ borderRadius: 16,
85
+ bgColor: isActive
86
+ ? colors.primary
87
+ : isCompleted
88
+ ? colors.success
89
+ : colors.gray300,
90
+ justifyContent: "center",
91
+ alignItems: "center",
92
+ child: isCompleted
93
+ ? Icon({ name: "check", size: 18, color: "#fff" })
94
+ : Text({
95
+ text: String(idx + 1),
96
+ size: 14,
97
+ weight: "bold",
98
+ color: isActive ? "#fff" : colors.textSecondary,
99
+ }),
100
+ });
101
+ } else if (variant === "numbers") {
102
+ indicator = Text({
103
+ text: String(idx + 1),
104
+ size: 16,
105
+ weight: "bold",
106
+ color: isActive ? colors.primary : colors.textSecondary,
107
+ });
108
+ } else {
109
+ indicator = Icon({
110
+ name: step.icon || "circle",
111
+ size: 24,
112
+ color: isActive ? colors.primary : colors.gray300,
113
+ });
114
+ }
115
+
116
+ // Label
117
+ const label = showLabels
118
+ ? Text({
119
+ text: step.label,
120
+ size: 12,
121
+ color: isActive ? colors.primary : colors.textSecondary,
122
+ marginTop: 4,
123
+ align: "center",
124
+ })
125
+ : null;
126
+
127
+ const stepColumn = Column({
128
+ alignItems: "center",
129
+ flex: needsWrap ? "auto" : 1,
130
+ minWidth: needsWrap ? "80px" : "0",
131
+ cursor: "pointer",
132
+ onclick: () => goToStep(idx),
133
+ children: [indicator, label].filter(Boolean),
134
+ });
135
+
136
+ if (orientation === "horizontal") {
137
+ stepsContainer.appendChild(stepColumn);
138
+ if (!isLast && !needsWrap) {
139
+ const connector = Container({
140
+ flex: 1,
141
+ height: "2px",
142
+ minWidth: "10px",
143
+ backgroundColor:
144
+ idx < currentStep ? colors.success : colors.gray300,
145
+ });
146
+ stepsContainer.appendChild(connector);
147
+ } else if (!isLast && needsWrap) {
148
+ const spacer = Container({ width: 8 });
149
+ stepsContainer.appendChild(spacer);
150
+ }
151
+ } else {
152
+ const verticalStep = Row({
153
+ gap: 12,
154
+ alignItems: "center",
155
+ children: [stepColumn, Text({ text: step.label, size: 14 })],
156
+ });
157
+ stepsContainer.appendChild(verticalStep);
158
+ }
159
+ });
160
+
161
+ // Update content
162
+ if (contentContainer) {
163
+ while (contentContainer.firstChild) {
164
+ contentContainer.removeChild(contentContainer.firstChild);
165
+ }
166
+ const stepContent = steps[currentStep]?.content;
167
+ if (stepContent) {
168
+ contentContainer.appendChild(stepContent);
169
+ }
170
+ }
171
+
172
+ // Update navigation buttons
173
+ if (navContainer) {
174
+ while (navContainer.firstChild) {
175
+ navContainer.removeChild(navContainer.firstChild);
176
+ }
177
+
178
+ const buttons = [];
179
+ if (currentStep > 0) {
180
+ buttons.push(
181
+ Button({
182
+ text: backLabel,
183
+ variant: "outlined",
184
+ onPress: back,
185
+ }),
186
+ );
187
+ }
188
+ if (currentStep === steps.length - 1) {
189
+ buttons.push(
190
+ Button({
191
+ text: finishLabel,
192
+ variant: "filled",
193
+ bgColor: colors.success,
194
+ onPress: finish,
195
+ }),
196
+ );
197
+ } else {
198
+ buttons.push(
199
+ Button({
200
+ text: nextLabel,
201
+ variant: "filled",
202
+ onPress: next,
203
+ }),
204
+ );
205
+ }
206
+
207
+ const navRow = Row({
208
+ justifyContent: "flex-end",
209
+ gap: 12,
210
+ children: buttons,
211
+ });
212
+ navContainer.appendChild(navRow);
213
+ }
214
+ };
215
+
216
+ // Build style for main container using WidgetFactory
217
+ let style = {
218
+ width: typeof width === "number" ? `${width}px` : width,
219
+ backgroundColor: bgColor,
220
+ borderRadius:
221
+ typeof borderRadius === "number" ? `${borderRadius}px` : borderRadius,
222
+ padding: typeof padding === "number" ? `${padding}px` : padding,
223
+ margin: typeof margin === "number" ? `${margin}px` : margin,
224
+ display: "flex",
225
+ flexDirection: "column",
226
+ gap: "24px",
227
+ boxSizing: "border-box",
228
+ overflow: "hidden",
229
+ };
230
+
231
+ if (border) {
232
+ style.border = border;
233
+ } else if (borderWidth !== undefined) {
234
+ style.borderWidth = `${borderWidth}px`;
235
+ style.borderStyle = "solid";
236
+ style.borderColor = borderColor;
237
+ }
238
+
239
+ if (shadow) {
240
+ style.boxShadow = shadow;
241
+ }
242
+
243
+ const container = WidgetFactory({
244
+ widgetName: "Stepper",
245
+ ...style,
246
+ ...rest,
247
+ });
248
+
249
+ // Steps wrapper with horizontal scroll
250
+ const stepsWrapper = WidgetFactory({
251
+ tag: "div",
252
+ overflowX: "auto",
253
+ overflowY: "visible",
254
+ width: "100%",
255
+ });
256
+
257
+ stepsContainer =
258
+ orientation === "horizontal"
259
+ ? Row({
260
+ alignItems: "center",
261
+ display: "flex",
262
+ flexDirection: "row",
263
+ minWidth: "min-content",
264
+ width: "100%",
265
+ })
266
+ : Column({ gap: 16 });
267
+
268
+ stepsWrapper.appendChild(stepsContainer);
269
+
270
+ // Content container
271
+ contentContainer = Container({
272
+ child: steps[currentStep]?.content || null,
273
+ width: "100%",
274
+ overflow: "auto",
275
+ });
276
+
277
+ // Navigation container
278
+ navContainer = Container({ width: "100%" });
279
+
280
+ container.appendChild(stepsWrapper);
281
+ container.appendChild(contentContainer);
282
+ container.appendChild(navContainer);
283
+
284
+ // Initial render
285
+ updateUI();
286
+
287
+ // Public methods
288
+ container.goTo = goToStep;
289
+ container.next = next;
290
+ container.back = back;
291
+ container.getActiveStep = () => currentStep;
292
+
293
+ return container;
294
+ };
295
+
296
+ export default Stepper;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * @file Switch.js
3
+ * @description iOS-style toggle switch with controlled/uncontrolled state.
4
+ */
5
+ import { WidgetFactory } from "../widget-factory/index.js";
6
+ import { colors } from "../utils/themes.js";
7
+
8
+ export const Switch = (props) => {
9
+ const {
10
+ value = false,
11
+ onToggle,
12
+ onPress: onPressProp,
13
+ disabled = false,
14
+ size = "medium",
15
+ ...rest
16
+ } = props;
17
+
18
+ /** @deprecated Use onPress instead */
19
+ // onToggle kept as alias for backward compatibility
20
+ const onPress = onPressProp || onToggle;
21
+
22
+ // Sizes
23
+ const sizes = {
24
+ small: { width: 40, height: 24, knob: 20 },
25
+ medium: { width: 51, height: 31, knob: 27 },
26
+ large: { width: 60, height: 36, knob: 32 },
27
+ };
28
+ const sz = sizes[size] || sizes.medium;
29
+
30
+ let internalValue = value;
31
+ let switchRef = null;
32
+ let knobRef = null;
33
+
34
+ const updateUI = (newValue) => {
35
+ if (switchRef) {
36
+ switchRef.style.backgroundColor = newValue
37
+ ? colors.success
38
+ : colors.gray300;
39
+ }
40
+ if (knobRef) {
41
+ knobRef.style.transform = newValue
42
+ ? `translateX(${sz.width - sz.knob - 4}px)`
43
+ : "translateX(0)";
44
+ }
45
+ };
46
+
47
+ // Createste knob
48
+ const knob = WidgetFactory({
49
+ width: sz.knob,
50
+ height: sz.knob,
51
+ backgroundColor: "#ffffff",
52
+ borderRadius: "50%",
53
+ transform: internalValue
54
+ ? `translateX(${sz.width - sz.knob - 4}px)`
55
+ : "translateX(0)",
56
+ transition: "transform 0.2s ease",
57
+ boxShadow: "0 1px 3px rgba(0,0,0,0.2)",
58
+ });
59
+ knobRef = knob;
60
+
61
+ // Createste main switch container
62
+ const switchContainer = WidgetFactory({
63
+ widgetName: "Switch",
64
+ width: sz.width,
65
+ height: sz.height,
66
+ backgroundColor: internalValue ? colors.success : colors.gray300,
67
+ borderRadius: sz.height / 2,
68
+ display: "flex",
69
+ alignItems: "center",
70
+ padding: "2px",
71
+ transition: "all 0.2s ease",
72
+ cursor: disabled ? "not-allowed" : "pointer",
73
+ opacity: disabled ? 0.5 : 1,
74
+ boxSizing: "border-box",
75
+ child: knob,
76
+ ...rest,
77
+ });
78
+ switchRef = switchContainer;
79
+
80
+ // Handle click
81
+ if (!disabled) {
82
+ switchContainer.onclick = (e) => {
83
+ e.stopPropagation();
84
+ const newValue = !internalValue;
85
+ internalValue = newValue;
86
+ updateUI(newValue);
87
+ if (onPress) onPress(newValue);
88
+ };
89
+ }
90
+
91
+ // Public methods
92
+ switchContainer.updateValue = (newValue) => {
93
+ internalValue = newValue;
94
+ updateUI(newValue);
95
+ };
96
+
97
+ switchContainer.getValue = () => internalValue;
98
+
99
+ return switchContainer;
100
+ };
101
+
102
+ export default Switch;