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,329 @@
1
+ // tools/color.js
2
+
3
+ /**
4
+ * Fluent color manipulation utility.
5
+ *
6
+ * Parses any common CSS color format (hex, rgb/rgba, hsl/hsla, or a small set of
7
+ * named colors), stores the result as normalized RGBA components, and exposes a
8
+ * chainable API for common transformations.
9
+ *
10
+ * Usage pattern: `color(value)` returns a `Color` instance. Chain methods as needed,
11
+ * then call `.hex()`, `.rgb()`, or `.rgba()` to get a CSS string.
12
+ *
13
+ * @example
14
+ * color('#3498db').lighten(20).rgba()
15
+ * // "rgba(91, 174, 226, 1)"
16
+ *
17
+ * color('hsl(200, 60%, 50%)').darken(10).hex()
18
+ * // "#2980b9" (approximately)
19
+ */
20
+
21
+ /**
22
+ * @class Color
23
+ * @description Internal color model. Prefer the `color()` factory export over
24
+ * instantiating this class directly.
25
+ */
26
+ class Color {
27
+ /**
28
+ * @param {string} color - Any CSS color string: hex (`#rgb`, `#rrggbb`),
29
+ * `rgb(r,g,b)`, `rgba(r,g,b,a)`, `hsl(h,s%,l%)`, `hsla(h,s%,l%,a)`,
30
+ * or a named color (see `parseNamed`).
31
+ */
32
+ constructor(color) {
33
+ this.r = 0;
34
+ this.g = 0;
35
+ this.b = 0;
36
+ this.a = 1;
37
+ this.parse(color);
38
+ }
39
+
40
+ /**
41
+ * Detect the format of `color` and dispatch to the appropriate parser.
42
+ *
43
+ * @param {string} color - CSS color string
44
+ * @returns {Color} `this` for chaining
45
+ */
46
+ parse(color) {
47
+ if (color.startsWith("#")) {
48
+ this.parseHex(color);
49
+ } else if (color.startsWith("rgb")) {
50
+ this.parseRgb(color);
51
+ } else if (color.startsWith("hsl")) {
52
+ this.parseHsl(color);
53
+ } else {
54
+ this.parseNamed(color);
55
+ }
56
+ return this;
57
+ }
58
+
59
+ /**
60
+ * Parse a hex color string into RGB components.
61
+ *
62
+ * Handles both shorthand (`#rgb`) and full (`#rrggbb`) formats.
63
+ * Alpha channel is not parsed from hex (use rgba/hsla for that).
64
+ *
65
+ * @param {string} hex - Hex color string including the leading `#`
66
+ */
67
+ parseHex(hex) {
68
+ hex = hex.slice(1);
69
+ if (hex.length === 3) {
70
+ // Expand shorthand: #abc → #aabbcc
71
+ this.r = parseInt(hex[0] + hex[0], 16);
72
+ this.g = parseInt(hex[1] + hex[1], 16);
73
+ this.b = parseInt(hex[2] + hex[2], 16);
74
+ } else {
75
+ this.r = parseInt(hex.slice(0, 2), 16);
76
+ this.g = parseInt(hex.slice(2, 4), 16);
77
+ this.b = parseInt(hex.slice(4, 6), 16);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Parse an `rgb()` or `rgba()` CSS color string.
83
+ *
84
+ * @param {string} rgb - e.g. `"rgb(255, 128, 0)"` or `"rgba(255, 128, 0, 0.5)"`
85
+ */
86
+ parseRgb(rgb) {
87
+ const match = rgb.match(
88
+ /rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/,
89
+ );
90
+ if (match) {
91
+ this.r = parseInt(match[1]);
92
+ this.g = parseInt(match[2]);
93
+ this.b = parseInt(match[3]);
94
+ this.a = match[4] ? parseFloat(match[4]) : 1;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Parse an `hsl()` or `hsla()` CSS color string, converting to RGB.
100
+ *
101
+ * Uses the standard hue-to-RGB algorithm. Hue is normalized to [0, 1],
102
+ * saturation and lightness to [0, 1].
103
+ *
104
+ * @param {string} hsl - e.g. `"hsl(200, 60%, 40%)"` or `"hsla(200, 60%, 40%, 0.8)"`
105
+ */
106
+ parseHsl(hsl) {
107
+ const match = hsl.match(
108
+ /hsla?\((\d+),\s*(\d+)%,\s*(\d+)%(?:,\s*([\d.]+))?\)/,
109
+ );
110
+ if (match) {
111
+ const h = parseInt(match[1]) / 360;
112
+ const s = parseInt(match[2]) / 100;
113
+ const l = parseInt(match[3]) / 100;
114
+ this.a = match[4] ? parseFloat(match[4]) : 1;
115
+
116
+ let r, g, b;
117
+ if (s === 0) {
118
+ // Achromatic: all channels are equal to lightness
119
+ r = g = b = l;
120
+ } else {
121
+ const hue2rgb = (p, q, t) => {
122
+ if (t < 0) t += 1;
123
+ if (t > 1) t -= 1;
124
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
125
+ if (t < 1 / 2) return q;
126
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
127
+ return p;
128
+ };
129
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
130
+ const p = 2 * l - q;
131
+ r = hue2rgb(p, q, h + 1 / 3);
132
+ g = hue2rgb(p, q, h);
133
+ b = hue2rgb(p, q, h - 1 / 3);
134
+ }
135
+ this.r = Math.round(r * 255);
136
+ this.g = Math.round(g * 255);
137
+ this.b = Math.round(b * 255);
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Parse a named CSS color by mapping it to its hex equivalent.
143
+ *
144
+ * Only a small subset of common names is supported. Unknown names are silently
145
+ * ignored (the instance keeps its previous RGB values).
146
+ *
147
+ * @param {string} name - Lowercase color name (e.g. `"red"`, `"white"`, `"gray"`)
148
+ */
149
+ parseNamed(name) {
150
+ const colors = {
151
+ black: "#000000",
152
+ white: "#ffffff",
153
+ red: "#ff0000",
154
+ green: "#00ff00",
155
+ blue: "#0000ff",
156
+ yellow: "#ffff00",
157
+ cyan: "#00ffff",
158
+ magenta: "#ff00ff",
159
+ gray: "#808080",
160
+ darkgray: "#a9a9a9",
161
+ lightgray: "#d3d3d3",
162
+ };
163
+ if (colors[name]) {
164
+ this.parseHex(colors[name]);
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Serialize the color as a hex string.
170
+ *
171
+ * Alpha is not included — use `.rgba()` when you need transparency.
172
+ *
173
+ * @returns {string} Lowercase hex color (e.g. `"#3498db"`)
174
+ */
175
+ hex() {
176
+ const toHex = (n) => {
177
+ const hex = n.toString(16);
178
+ return hex.length === 1 ? "0" + hex : hex;
179
+ };
180
+ return `#${toHex(this.r)}${toHex(this.g)}${toHex(this.b)}`;
181
+ }
182
+
183
+ /**
184
+ * Serialize the color as an `rgb()` CSS string.
185
+ *
186
+ * Alpha is not included. Use `.rgba()` for translucent colors.
187
+ *
188
+ * @returns {string} e.g. `"rgb(52, 152, 219)"`
189
+ */
190
+ rgb() {
191
+ return `rgb(${this.r}, ${this.g}, ${this.b})`;
192
+ }
193
+
194
+ /**
195
+ * Serialize the color as an `rgba()` CSS string including the alpha channel.
196
+ *
197
+ * @returns {string} e.g. `"rgba(52, 152, 219, 1)"`
198
+ */
199
+ rgba() {
200
+ return `rgba(${this.r}, ${this.g}, ${this.b}, ${this.a})`;
201
+ }
202
+
203
+ /**
204
+ * Lighten the color by blending it toward white.
205
+ *
206
+ * Each channel is moved toward 255 by `percent`% of the remaining distance.
207
+ * Mutates this instance and returns `this` for chaining.
208
+ *
209
+ * @param {number} percent - Lightening amount as a percentage (0–100)
210
+ * @returns {Color} `this` for chaining
211
+ * @example color('#336699').lighten(30).hex() // lighter blue
212
+ */
213
+ lighten(percent) {
214
+ const amount = percent / 100;
215
+ this.r = Math.min(255, Math.round(this.r + (255 - this.r) * amount));
216
+ this.g = Math.min(255, Math.round(this.g + (255 - this.g) * amount));
217
+ this.b = Math.min(255, Math.round(this.b + (255 - this.b) * amount));
218
+ return this;
219
+ }
220
+
221
+ /**
222
+ * Darken the color by scaling each channel toward zero.
223
+ *
224
+ * Each channel is multiplied by `(1 - percent/100)`.
225
+ * Mutates this instance and returns `this` for chaining.
226
+ *
227
+ * @param {number} percent - Darkening amount as a percentage (0–100)
228
+ * @returns {Color} `this` for chaining
229
+ * @example color('#3498db').darken(20).hex() // darker blue
230
+ */
231
+ darken(percent) {
232
+ const amount = percent / 100;
233
+ this.r = Math.max(0, Math.round(this.r * (1 - amount)));
234
+ this.g = Math.max(0, Math.round(this.g * (1 - amount)));
235
+ this.b = Math.max(0, Math.round(this.b * (1 - amount)));
236
+ return this;
237
+ }
238
+
239
+ /**
240
+ * Set the alpha (opacity) channel.
241
+ *
242
+ * Clamps `value` to the [0, 1] range.
243
+ * Mutates this instance and returns `this` for chaining.
244
+ *
245
+ * @param {number} value - Alpha value between 0 (fully transparent) and 1 (fully opaque)
246
+ * @returns {Color} `this` for chaining
247
+ * @example color('#000').alpha(0.5).rgba() // "rgba(0, 0, 0, 0.5)"
248
+ */
249
+ alpha(value) {
250
+ this.a = Math.min(1, Math.max(0, value));
251
+ return this;
252
+ }
253
+
254
+ /**
255
+ * Determine whether the color is perceptually dark.
256
+ *
257
+ * Uses the ITU-R BT.601 luma formula (weighted RGB) which is a standard
258
+ * way to approximate human-perceived brightness. A brightness below 128
259
+ * is considered dark.
260
+ *
261
+ * @returns {boolean} `true` if the color is perceptually dark
262
+ */
263
+ isDark() {
264
+ const brightness = (this.r * 299 + this.g * 587 + this.b * 114) / 1000;
265
+ return brightness < 128;
266
+ }
267
+
268
+ /**
269
+ * Determine whether the color is perceptually light.
270
+ *
271
+ * The inverse of `isDark()`.
272
+ *
273
+ * @returns {boolean} `true` if the color is perceptually light
274
+ */
275
+ isLight() {
276
+ return !this.isDark();
277
+ }
278
+
279
+ /**
280
+ * Get a high-contrast text color suitable for overlay on this background.
281
+ *
282
+ * Returns black on light backgrounds and white on dark backgrounds — useful
283
+ * for automatically picking readable label colors.
284
+ *
285
+ * @returns {"#ffffff"|"#000000"} High-contrast color string
286
+ * @example
287
+ * const bg = color('#3498db');
288
+ * element.style.color = bg.contrast(); // "#ffffff" (white on this mid-blue)
289
+ */
290
+ contrast() {
291
+ return this.isDark() ? "#ffffff" : "#000000";
292
+ }
293
+
294
+ /**
295
+ * Invert the color by complementing each RGB channel.
296
+ *
297
+ * Each channel is replaced with `255 - channel`. The alpha value is unchanged.
298
+ * Mutates this instance and returns `this` for chaining.
299
+ *
300
+ * @returns {Color} `this` for chaining
301
+ * @example color('#ff0000').complement().hex() // "#00ffff" (cyan)
302
+ */
303
+ complement() {
304
+ this.r = 255 - this.r;
305
+ this.g = 255 - this.g;
306
+ this.b = 255 - this.b;
307
+ return this;
308
+ }
309
+ }
310
+
311
+ /**
312
+ * Create a new `Color` instance from any CSS color string.
313
+ *
314
+ * This is the primary entry point for the color API. The returned object
315
+ * exposes a fluent, chainable interface for parsing, transforming, and
316
+ * serializing colors.
317
+ *
318
+ * @param {string} value - Any CSS color: hex, rgb/rgba, hsl/hsla, or a named color
319
+ * @returns {Color} Chainable color instance
320
+ *
321
+ * @example
322
+ * color('#e74c3c').darken(10).alpha(0.9).rgba()
323
+ * // "rgba(195, 58, 44, 0.9)"
324
+ *
325
+ * color('hsl(200, 60%, 50%)').complement().hex()
326
+ */
327
+ export const color = (value) => new Color(value);
328
+
329
+ export default color;
@@ -0,0 +1,215 @@
1
+ // src/components/flet-box/tools/createList.js
2
+
3
+ import { random } from "./random.js";
4
+
5
+ /**
6
+ * Creates a list of items with generated data
7
+ * @module tools/createList
8
+ */
9
+
10
+ /**
11
+ * Create a list of items from a schema
12
+ * @param {Object} schema - Data schema { field: value or function(item, index) }
13
+ * @param {number} count - Number of items to generate (default: 10)
14
+ * @returns {Array} Generated list
15
+ *
16
+ * @example
17
+ * // Basic usage
18
+ * const users = createList({
19
+ * id: () => random.id(),
20
+ * name: random.fullName(),
21
+ * age: () => random.number(18, 65),
22
+ * active: random.boolean()
23
+ * }, 100);
24
+ *
25
+ * @example
26
+ * // With field dependencies
27
+ * const users = createList({
28
+ * name: random.fullName(),
29
+ * email: (item) => random.email(item.name),
30
+ * age: () => random.number(18, 65)
31
+ * }, 50);
32
+ */
33
+ export const createList = (schema, count = 10) => {
34
+ const items = [];
35
+
36
+ for (let i = 0; i < count; i++) {
37
+ const item = {};
38
+
39
+ for (const [key, value] of Object.entries(schema)) {
40
+ if (typeof value === "function") {
41
+ // Pass the partially built item and index to the function
42
+ item[key] = value(item, i);
43
+ } else {
44
+ item[key] = value;
45
+ }
46
+ }
47
+
48
+ // Auto-add id if not present in schema
49
+ if (!item.hasOwnProperty("id") && !schema.id) {
50
+ item.id = i;
51
+ }
52
+
53
+ items.push(item);
54
+ }
55
+
56
+ return items;
57
+ };
58
+
59
+ /**
60
+ * Create a list from existing data with transformation
61
+ * @param {Array} data - Source data
62
+ * @param {Object} mapper - Mapping functions { targetField: (sourceItem, index) => value }
63
+ * @returns {Array} Transformed list
64
+ *
65
+ * @example
66
+ * const apiUsers = await fetchUsers();
67
+ * const users = createList.fromData(apiUsers, {
68
+ * id: (user) => user.userId,
69
+ * name: (user) => `${user.firstName} ${user.lastName}`,
70
+ * email: (user) => user.emailAddress
71
+ * });
72
+ */
73
+ createList.fromData = (data, mapper) => {
74
+ return data.map((item, index) => {
75
+ const result = {};
76
+ for (const [key, transform] of Object.entries(mapper)) {
77
+ result[key] =
78
+ typeof transform === "function" ? transform(item, index) : transform;
79
+ }
80
+ return result;
81
+ });
82
+ };
83
+
84
+ /**
85
+ * Create a sequential list of numbers
86
+ * @param {number} start - Start value (inclusive)
87
+ * @param {number} end - End value (inclusive)
88
+ * @param {Function} mapper - Optional mapping function (receives value, index)
89
+ * @returns {Array} Sequential list
90
+ *
91
+ * @example
92
+ * createList.range(1, 10) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
93
+ * createList.range(0, 5, (i) => `Item ${i}`) // ['Item 0', 'Item 1', ...]
94
+ */
95
+ createList.range = (start, end, mapper = null) => {
96
+ const items = [];
97
+ for (let i = start; i <= end; i++) {
98
+ items.push(mapper ? mapper(i, i - start) : i);
99
+ }
100
+ return items;
101
+ };
102
+
103
+ /**
104
+ * Create a list with repeated value
105
+ * @param {any} value - Value to repeat
106
+ * @param {number} count - Number of repetitions
107
+ * @returns {Array} Repeated list
108
+ *
109
+ * @example
110
+ * createList.repeat({ active: true }, 10) // 10 objects with { active: true }
111
+ */
112
+ createList.repeat = (value, count) => {
113
+ return Array(count).fill(value);
114
+ };
115
+
116
+ /**
117
+ * Paginate a list
118
+ * @param {Array} list - Source list
119
+ * @param {number} page - Page number (1-indexed, default: 1)
120
+ * @param {number} pageSize - Items per page (default: 20)
121
+ * @returns {Object} Paginated result with metadata
122
+ *
123
+ * @example
124
+ * const { data, totalPages, hasNext } = createList.paginate(users, 2, 50);
125
+ */
126
+ createList.paginate = (list, page = 1, pageSize = 20) => {
127
+ const start = (page - 1) * pageSize;
128
+ const end = start + pageSize;
129
+ return {
130
+ data: list.slice(start, end),
131
+ page,
132
+ pageSize,
133
+ total: list.length,
134
+ totalPages: Math.ceil(list.length / pageSize),
135
+ hasNext: end < list.length,
136
+ hasPrev: page > 1,
137
+ startIndex: start,
138
+ endIndex: Math.min(end, list.length),
139
+ };
140
+ };
141
+
142
+ /**
143
+ * Search/filter a list
144
+ * @param {Array} list - Source list
145
+ * @param {string|Function} query - Search string or filter function
146
+ * @param {string[]} fields - Fields to search (if query is string)
147
+ * @returns {Array} Filtered list
148
+ *
149
+ * @example
150
+ * createList.search(users, 'Ana', ['name', 'email'])
151
+ * createList.search(users, (user) => user.age > 30)
152
+ */
153
+ createList.search = (list, query, fields = null) => {
154
+ if (typeof query === "function") {
155
+ return list.filter(query);
156
+ }
157
+
158
+ const searchTerm = query.toLowerCase();
159
+ return list.filter((item) => {
160
+ const searchableFields = fields || Object.keys(item);
161
+ return searchableFields.some((field) => {
162
+ const value = item[field];
163
+ return value && String(value).toLowerCase().includes(searchTerm);
164
+ });
165
+ });
166
+ };
167
+
168
+ /**
169
+ * Sort a list
170
+ * @param {Array} list - Source list
171
+ * @param {string} field - Field to sort by
172
+ * @param {string} order - 'asc' or 'desc' (default: 'asc')
173
+ * @returns {Array} Sorted list
174
+ */
175
+ createList.sort = (list, field, order = "asc") => {
176
+ const sorted = [...list];
177
+ sorted.sort((a, b) => {
178
+ const aVal = a[field];
179
+ const bVal = b[field];
180
+
181
+ if (typeof aVal === "number" && typeof bVal === "number") {
182
+ return order === "asc" ? aVal - bVal : bVal - aVal;
183
+ }
184
+
185
+ const aStr = String(aVal).toLowerCase();
186
+ const bStr = String(bVal).toLowerCase();
187
+
188
+ if (order === "asc") {
189
+ return aStr.localeCompare(bStr);
190
+ } else {
191
+ return bStr.localeCompare(aStr);
192
+ }
193
+ });
194
+ return sorted;
195
+ };
196
+
197
+ /**
198
+ * Group a list by a field
199
+ * @param {Array} list - Source list
200
+ * @param {string} field - Field to group by
201
+ * @returns {Object} Grouped object
202
+ *
203
+ * @example
204
+ * const byStatus = createList.groupBy(users, 'status')
205
+ */
206
+ createList.groupBy = (list, field) => {
207
+ return list.reduce((groups, item) => {
208
+ const key = item[field];
209
+ if (!groups[key]) groups[key] = [];
210
+ groups[key].push(item);
211
+ return groups;
212
+ }, {});
213
+ };
214
+
215
+ export default createList;
@@ -0,0 +1,55 @@
1
+ // src/components/flet-box/tools/delay.js
2
+
3
+ /**
4
+ * Delay execution for a specified number of milliseconds.
5
+ *
6
+ * @param {number} ms - Number of milliseconds to wait.
7
+ * @returns {Promise<void>} A promise that resolves after the delay.
8
+ *
9
+ * @example
10
+ * await delay(1000);
11
+ * console.log('After 1 second');
12
+ */
13
+ export const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
14
+
15
+ /**
16
+ * Ensures a promise takes at least `minMs` milliseconds to resolve.
17
+ * Useful for preventing UI flicker when async operations complete too quickly.
18
+ *
19
+ * @param {Promise<*>} promise - The promise to execute.
20
+ * @param {number} [minMs=500] - Minimum display time in milliseconds.
21
+ * @returns {Promise<*>} Resolves with the promise result after at least `minMs` ms.
22
+ *
23
+ * @example
24
+ * const data = await withMinDelay(fetchData(), 800);
25
+ */
26
+ export const withMinDelay = async (promise, minMs = 500) => {
27
+ const [result] = await Promise.all([promise, delay(minMs)]);
28
+ return result;
29
+ };
30
+
31
+ /**
32
+ * Retries an async operation up to `retries` times with a delay between attempts.
33
+ * Throws the last encountered error if all retries are exhausted.
34
+ *
35
+ * @param {Function} fn - Async function to attempt.
36
+ * @param {number} [retries=3] - Maximum number of retry attempts.
37
+ * @param {number} [delayMs=1000] - Milliseconds to wait between retries.
38
+ * @returns {Promise<*>} Resolves with the function's result on success.
39
+ * @throws {Error} Re-throws the last error when all retries are exhausted.
40
+ *
41
+ * @example
42
+ * const data = await retry(() => fetchData(), 3, 1000);
43
+ */
44
+ export const retry = async (fn, retries = 3, delayMs = 1000) => {
45
+ try {
46
+ return await fn();
47
+ } catch (error) {
48
+ if (retries === 0) throw error;
49
+ await delay(delayMs);
50
+ return retry(fn, retries - 1, delayMs);
51
+ }
52
+ };
53
+
54
+ // Default export for importing everything at once
55
+ export default { delay, withMinDelay, retry };