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,38 @@
1
+ // src/tools/index.js
2
+ export { animation } from "./animation.js";
3
+ export { shuffle, reverse, sort, unique, chunk } from "./array.js";
4
+ export { border } from "./border.js";
5
+ export { clipboard } from "./clipboard.js";
6
+ export { color } from "./color.js";
7
+ export { createList } from "./createList.js";
8
+ export { delay, withMinDelay, retry } from "./delay.js";
9
+ export { device } from "./device.js";
10
+ export { dimensions, width, height } from "./dimensions.js";
11
+ export { filter } from "./filter.js";
12
+ export { flex } from "./flex.js";
13
+ export { default as gradient } from "./gradient.js";
14
+ export { grid } from "./grid.js";
15
+ export { default as margin } from "./margin.js";
16
+ export { mapList, repeat, range } from "./mapList.js";
17
+ export { memo, memoWithKey, clearMemo } from "./memo.js";
18
+ export { os } from "./os.js";
19
+ export { default as padding } from "./padding.js";
20
+ export { print } from "./print.js";
21
+ export { random } from "./random.js";
22
+ export { default as rgba } from "./rgba.js";
23
+ export { default as shadow } from "./shadow.js";
24
+ export {
25
+ capitalize,
26
+ capitalizeWords,
27
+ lowerCase,
28
+ upperCase,
29
+ reverseString,
30
+ truncate,
31
+ } from "./string.js";
32
+ export { formatDate, relativeTime, sleep, now } from "./time.js";
33
+ export { transform } from "./transform.js";
34
+ export { transition } from "./transition.js";
35
+ export { useState, useWatchState } from "./useState.js";
36
+ export { uuid, shortId, numericId, timestampId } from "./uuid.js";
37
+ export { dict, emptyDict, fromJSON, fromEntries, Dict } from "./dict.js";
38
+ export { ref } from "./ref.js";
@@ -0,0 +1,107 @@
1
+ // tools/mapList.js
2
+
3
+ /**
4
+ * Maps an array, a numeric length, or a plain object to an array of widgets or
5
+ * any other value produced by the mapping function.
6
+ *
7
+ * - **Array**: iterates with `(item, index)`.
8
+ * - **Number**: treats the value as an array length and iterates with `(null, index)`.
9
+ * - **Object**: iterates over `Object.entries` with `(value, key, index)`.
10
+ *
11
+ * @param {Array|number|Object} list - Source collection.
12
+ * @param {Function} fn - Mapping function. Signature depends on source type:
13
+ * - Array: `(item, index) => widget`
14
+ * - Number: `(null, index) => widget`
15
+ * - Object: `(value, key, index) => widget`
16
+ * @returns {Array} Array of mapped values.
17
+ *
18
+ * @example
19
+ * // Map array to widgets
20
+ * mapList(users, (user, i) => Text({ text: user.name }))
21
+ *
22
+ * @example
23
+ * // Generateste N widgets from a number
24
+ * mapList(5, (_, i) => Skeleton({ variant: 'text' }))
25
+ *
26
+ * @example
27
+ * // Map object values
28
+ * mapList({ a: 1, b: 2, c: 3 }, (value, key) => Text({ text: `${key}: ${value}` }))
29
+ */
30
+ export const mapList = (list, fn) => {
31
+ // Handle number — create a virtual array of that length
32
+ if (typeof list === "number") {
33
+ const arr = [];
34
+ for (let i = 0; i < list; i++) {
35
+ arr.push(fn(null, i));
36
+ }
37
+ return arr;
38
+ }
39
+
40
+ // Handle array
41
+ if (Array.isArray(list)) {
42
+ return list.map((item, index) => fn(item, index));
43
+ }
44
+
45
+ // Handle plain object — iterate over its entries
46
+ if (typeof list === "object" && list !== null) {
47
+ return Object.entries(list).map(([key, value], index) =>
48
+ fn(value, key, index),
49
+ );
50
+ }
51
+
52
+ return [];
53
+ };
54
+
55
+ /**
56
+ * Repeats a widget (or calls a factory function) `count` times and returns the
57
+ * resulting array.
58
+ *
59
+ * @param {number} count - Number of repetitions.
60
+ * @param {Function|*} widget - Widget instance to repeat, or a `(index) => widget`
61
+ * factory function called on each iteration.
62
+ * @returns {Array} Array of widgets.
63
+ *
64
+ * @example
65
+ * repeat(3, Button({ text: 'Click' }))
66
+ * repeat(5, (i) => Text({ text: `Item ${i}` }))
67
+ */
68
+ export const repeat = (count, widget) => {
69
+ const result = [];
70
+ for (let i = 0; i < count; i++) {
71
+ if (typeof widget === "function") {
72
+ result.push(widget(i));
73
+ } else {
74
+ result.push(widget);
75
+ }
76
+ }
77
+ return result;
78
+ };
79
+
80
+ /**
81
+ * Generates an array of numbers in the half-open interval `[start, end)` with
82
+ * a configurable step. Mirrors Python's `range()`.
83
+ *
84
+ * When called with a single argument, the range starts at `0`.
85
+ *
86
+ * @param {number} start - Start value (inclusive), or the exclusive end when `end` is omitted.
87
+ * @param {number} [end] - End value (exclusive). If omitted, `start` becomes the end and `0` is used as start.
88
+ * @param {number} [step=1] - Increment between values.
89
+ * @returns {number[]} Array of numbers.
90
+ *
91
+ * @example
92
+ * range(5) // [0, 1, 2, 3, 4]
93
+ * range(1, 5) // [1, 2, 3, 4]
94
+ * range(0, 10, 2) // [0, 2, 4, 6, 8]
95
+ */
96
+ export const range = (start, end, step = 1) => {
97
+ const result = [];
98
+ const actualStart = end === undefined ? 0 : start;
99
+ const actualEnd = end === undefined ? start : end;
100
+
101
+ for (let i = actualStart; i < actualEnd; i += step) {
102
+ result.push(i);
103
+ }
104
+ return result;
105
+ };
106
+
107
+ export default { mapList, repeat, range };
@@ -0,0 +1,93 @@
1
+ // tools/margin.js
2
+
3
+ /**
4
+ * Generates a CSS `margin` shorthand string from a number, a plain CSS string,
5
+ * or a configuration object.
6
+ *
7
+ * When all resolved sides are equal the output is a single value (e.g. `"20px"`).
8
+ * When only top/bottom differ from left/right the two-value shorthand is used
9
+ * (e.g. `"10px 20px"`). Otherwise the full four-value form is returned.
10
+ *
11
+ * Object option keys (all optional, resolved in priority order per side):
12
+ * - `all` — applies to every side.
13
+ * - `horizontal` — applies to `left` and `right`.
14
+ * - `vertical` — applies to `top` and `bottom`.
15
+ * - `top`, `right`, `bottom`, `left` — individual side overrides.
16
+ *
17
+ * @param {number|string|Object} value
18
+ * A number (converted to `px`), a raw CSS string, or an options object.
19
+ * @returns {string} CSS margin value.
20
+ *
21
+ * @example
22
+ * margin(20) // "20px"
23
+ * margin({ all: 20 }) // "20px"
24
+ * margin({ horizontal: 20, vertical: 10 }) // "10px 20px"
25
+ * margin({ top: 10, right: 20, bottom: 10, left: 20 }) // "10px 20px"
26
+ * margin({ left: 20, right: 20 }) // "0px 20px"
27
+ * margin({ top: 10, bottom: 10 }) // "10px 0px"
28
+ */
29
+ export const margin = (value) => {
30
+ // A number or raw CSS string applies uniformly to all sides
31
+ if (typeof value === "number" || typeof value === "string") {
32
+ const px = typeof value === "number" ? `${value}px` : value;
33
+ return px;
34
+ }
35
+
36
+ // Object form — resolve each side independently
37
+ if (typeof value === "object") {
38
+ const top =
39
+ value.top !== undefined
40
+ ? value.top
41
+ : value.vertical !== undefined
42
+ ? value.vertical
43
+ : value.all !== undefined
44
+ ? value.all
45
+ : 0;
46
+ const right =
47
+ value.right !== undefined
48
+ ? value.right
49
+ : value.horizontal !== undefined
50
+ ? value.horizontal
51
+ : value.all !== undefined
52
+ ? value.all
53
+ : 0;
54
+ const bottom =
55
+ value.bottom !== undefined
56
+ ? value.bottom
57
+ : value.vertical !== undefined
58
+ ? value.vertical
59
+ : value.all !== undefined
60
+ ? value.all
61
+ : 0;
62
+ const left =
63
+ value.left !== undefined
64
+ ? value.left
65
+ : value.horizontal !== undefined
66
+ ? value.horizontal
67
+ : value.all !== undefined
68
+ ? value.all
69
+ : 0;
70
+
71
+ const topPx = typeof top === "number" ? `${top}px` : top;
72
+ const rightPx = typeof right === "number" ? `${right}px` : right;
73
+ const bottomPx = typeof bottom === "number" ? `${bottom}px` : bottom;
74
+ const leftPx = typeof left === "number" ? `${left}px` : left;
75
+
76
+ // All sides equal — return a single value
77
+ if (topPx === rightPx && rightPx === bottomPx && bottomPx === leftPx) {
78
+ return topPx;
79
+ }
80
+
81
+ // Only horizontal and vertical differ — use two-value shorthand
82
+ if (topPx === bottomPx && rightPx === leftPx) {
83
+ return `${topPx} ${rightPx}`;
84
+ }
85
+
86
+ // Full four-value form
87
+ return `${topPx} ${rightPx} ${bottomPx} ${leftPx}`;
88
+ }
89
+
90
+ return "0px";
91
+ };
92
+
93
+ export default margin;
@@ -0,0 +1,60 @@
1
+ // tools/memo.js
2
+
3
+ /**
4
+ * Memoize a function (cache results)
5
+ * @param {Function} fn - Function to memoize
6
+ * @returns {Function} Memoized function
7
+ * @example
8
+ * const expensiveFn = memo((n) => { ... })
9
+ */
10
+ export const memo = (fn) => {
11
+ const cache = new Map();
12
+
13
+ const memoized = (...args) => {
14
+ const key = JSON.stringify(args);
15
+ if (cache.has(key)) {
16
+ return cache.get(key);
17
+ }
18
+ const result = fn(...args);
19
+ cache.set(key, result);
20
+ return result;
21
+ };
22
+
23
+ memoized.cache = cache;
24
+ return memoized;
25
+ };
26
+
27
+ /**
28
+ * Memoize with custom key generator
29
+ * @param {Function} fn - Function to memoize
30
+ * @param {Function} keyFn - Key generator function
31
+ * @returns {Function} Memoized function
32
+ */
33
+ export const memoWithKey = (fn, keyFn) => {
34
+ const cache = new Map();
35
+
36
+ const memoized = (...args) => {
37
+ const key = keyFn(...args);
38
+ if (cache.has(key)) {
39
+ return cache.get(key);
40
+ }
41
+ const result = fn(...args);
42
+ cache.set(key, result);
43
+ return result;
44
+ };
45
+
46
+ memoized.cache = cache;
47
+ return memoized;
48
+ };
49
+
50
+ /**
51
+ * Clear memo cache
52
+ * @param {Function} memoizedFn - Memoized function
53
+ */
54
+ export const clearMemo = (memoizedFn) => {
55
+ if (memoizedFn.cache) {
56
+ memoizedFn.cache.clear();
57
+ }
58
+ };
59
+
60
+ export default { memo, memoWithKey, clearMemo };
@@ -0,0 +1,104 @@
1
+ // tools/os.js
2
+
3
+ /**
4
+ * Operating system detection utilities.
5
+ *
6
+ * Parses `navigator.userAgent` to identify the host OS and its version.
7
+ * All methods are synchronous reads — no side effects, no caching.
8
+ *
9
+ * Note: UA-string detection is a best-effort heuristic. Browsers, WebViews,
10
+ * and some privacy settings can spoof or omit UA data. Use these results for
11
+ * progressive enhancement, not security decisions.
12
+ *
13
+ * @namespace os
14
+ */
15
+ export const os = {
16
+ /**
17
+ * Get the name of the host operating system.
18
+ *
19
+ * Detection order matters: Android is checked before Linux because Android
20
+ * UAs also contain "Linux". ChromeOS (CrOS) is checked last as a subset
21
+ * of Linux-like UAs.
22
+ *
23
+ * @returns {"Windows"|"macOS"|"Android"|"iOS"|"Linux"|"ChromeOS"|"Unknown"}
24
+ * Normalized OS name, or `"Unknown"` when no known pattern matches
25
+ *
26
+ * @example
27
+ * os.name() // "macOS" on a Mac, "Android" on an Android phone
28
+ */
29
+ name: () => {
30
+ const ua = navigator.userAgent;
31
+
32
+ if (/Windows/i.test(ua)) return "Windows";
33
+ if (/Mac OS|MacIntel|MacPPC|Mac68K/i.test(ua)) return "macOS";
34
+ if (/Android/i.test(ua)) return "Android";
35
+ if (/iOS|iPhone|iPad|iPod/i.test(ua)) return "iOS";
36
+ if (/Linux/i.test(ua)) return "Linux";
37
+ if (/CrOS/i.test(ua)) return "ChromeOS";
38
+
39
+ return "Unknown";
40
+ },
41
+
42
+ /**
43
+ * Get the version string of the host operating system.
44
+ *
45
+ * Extracts the version from the UA string using OS-specific regex patterns.
46
+ * On macOS, underscore separators in the UA are normalized to dots
47
+ * (e.g. `"10_15_7"` → `"10.15.7"`).
48
+ *
49
+ * @returns {string} Version string (e.g. `"10.0"`, `"14_2"` normalized to `"14.2"`)
50
+ * or `"Unknown"` when the pattern does not match
51
+ *
52
+ * @example
53
+ * os.version() // "14.1" on macOS Sonoma, "13.0" on Windows 11
54
+ */
55
+ version: () => {
56
+ const ua = navigator.userAgent;
57
+ const osName = os.name();
58
+
59
+ if (osName === "Windows") {
60
+ const match = ua.match(/Windows NT (\d+\.\d+)/);
61
+ if (match) return match[1];
62
+ }
63
+ if (osName === "macOS") {
64
+ const match = ua.match(/Mac OS X (\d+[._]\d+[._]\d+)/);
65
+ if (match) return match[1].replace(/_/g, ".");
66
+ }
67
+ if (osName === "Android") {
68
+ const match = ua.match(/Android (\d+\.\d+)/);
69
+ if (match) return match[1];
70
+ }
71
+ if (osName === "iOS") {
72
+ const match = ua.match(/OS (\d+[._]\d+[._]?\d*)/);
73
+ if (match) return match[1].replace(/_/g, ".");
74
+ }
75
+
76
+ return "Unknown";
77
+ },
78
+
79
+ /**
80
+ * Detect whether the host OS is a mobile operating system.
81
+ *
82
+ * Returns `true` for Android and iOS. Use this when you need OS-level
83
+ * behavior differences rather than viewport-size differences (prefer
84
+ * `device.isMobile()` for viewport-based branching).
85
+ *
86
+ * @returns {boolean} `true` if the OS is Android or iOS
87
+ */
88
+ isMobile: () => {
89
+ return os.name() === "Android" || os.name() === "iOS";
90
+ },
91
+
92
+ /**
93
+ * Detect whether the host OS is a desktop operating system.
94
+ *
95
+ * The inverse of `os.isMobile()`.
96
+ *
97
+ * @returns {boolean} `true` if the OS is not Android or iOS
98
+ */
99
+ isDesktop: () => {
100
+ return !os.isMobile();
101
+ },
102
+ };
103
+
104
+ export default os;
@@ -0,0 +1,93 @@
1
+ // tools/padding.js
2
+
3
+ /**
4
+ * Generates a CSS `padding` shorthand string from a number, a plain CSS string,
5
+ * or a configuration object.
6
+ *
7
+ * When all resolved sides are equal the output is a single value (e.g. `"20px"`).
8
+ * When only top/bottom differ from left/right the two-value shorthand is used
9
+ * (e.g. `"10px 20px"`). Otherwise the full four-value form is returned.
10
+ *
11
+ * Object option keys (all optional, resolved in priority order per side):
12
+ * - `all` — applies to every side.
13
+ * - `horizontal` — applies to `left` and `right`.
14
+ * - `vertical` — applies to `top` and `bottom`.
15
+ * - `top`, `right`, `bottom`, `left` — individual side overrides.
16
+ *
17
+ * @param {number|string|Object} value
18
+ * A number (converted to `px`), a raw CSS string, or an options object.
19
+ * @returns {string} CSS padding value.
20
+ *
21
+ * @example
22
+ * padding(20) // "20px"
23
+ * padding({ all: 20 }) // "20px"
24
+ * padding({ horizontal: 20, vertical: 10 }) // "10px 20px"
25
+ * padding({ top: 10, right: 20, bottom: 10, left: 20 }) // "10px 20px"
26
+ * padding({ left: 20, right: 20 }) // "0px 20px"
27
+ * padding({ top: 10, bottom: 10 }) // "10px 0px"
28
+ */
29
+ export const padding = (value) => {
30
+ // A number or raw CSS string applies uniformly to all sides
31
+ if (typeof value === "number" || typeof value === "string") {
32
+ const px = typeof value === "number" ? `${value}px` : value;
33
+ return px;
34
+ }
35
+
36
+ // Object form — resolve each side independently
37
+ if (typeof value === "object") {
38
+ const top =
39
+ value.top !== undefined
40
+ ? value.top
41
+ : value.vertical !== undefined
42
+ ? value.vertical
43
+ : value.all !== undefined
44
+ ? value.all
45
+ : 0;
46
+ const right =
47
+ value.right !== undefined
48
+ ? value.right
49
+ : value.horizontal !== undefined
50
+ ? value.horizontal
51
+ : value.all !== undefined
52
+ ? value.all
53
+ : 0;
54
+ const bottom =
55
+ value.bottom !== undefined
56
+ ? value.bottom
57
+ : value.vertical !== undefined
58
+ ? value.vertical
59
+ : value.all !== undefined
60
+ ? value.all
61
+ : 0;
62
+ const left =
63
+ value.left !== undefined
64
+ ? value.left
65
+ : value.horizontal !== undefined
66
+ ? value.horizontal
67
+ : value.all !== undefined
68
+ ? value.all
69
+ : 0;
70
+
71
+ const topPx = typeof top === "number" ? `${top}px` : top;
72
+ const rightPx = typeof right === "number" ? `${right}px` : right;
73
+ const bottomPx = typeof bottom === "number" ? `${bottom}px` : bottom;
74
+ const leftPx = typeof left === "number" ? `${left}px` : left;
75
+
76
+ // All sides equal — return a single value
77
+ if (topPx === rightPx && rightPx === bottomPx && bottomPx === leftPx) {
78
+ return topPx;
79
+ }
80
+
81
+ // Only horizontal and vertical differ — use two-value shorthand
82
+ if (topPx === bottomPx && rightPx === leftPx) {
83
+ return `${topPx} ${rightPx}`;
84
+ }
85
+
86
+ // Full four-value form
87
+ return `${topPx} ${rightPx} ${bottomPx} ${leftPx}`;
88
+ }
89
+
90
+ return "0px";
91
+ };
92
+
93
+ export default padding;
@@ -0,0 +1,69 @@
1
+ // tools/print.js
2
+ // Simple and clean logging system
3
+
4
+ /**
5
+ * A thin wrapper around `console` that adds icons, optional timestamps, and
6
+ * optional labels to log output. Objects are serialized to pretty-printed JSON.
7
+ *
8
+ * @param {*} message - Value to log. Objects are serialized with `JSON.stringify`.
9
+ * @param {"log"|"warn"|"error"|"info"|"success"|"debug"} [type="log"] - Log level.
10
+ * Can also be passed as an options object for backwards compatibility.
11
+ * @param {Object} [options={}] - Additional formatting options.
12
+ * @param {boolean} [options.timestamp=false] - Prepend the current time.
13
+ * @param {string} [options.label=""] - Bracket-wrapped label inserted before the message.
14
+ * @param {boolean} [options.prefix=true] - Whether to prepend the level icon.
15
+ * @returns {void}
16
+ *
17
+ * @example
18
+ * print('Hello world')
19
+ * print('User logged in', 'success')
20
+ * print('Something went wrong', 'error')
21
+ * print('Loading...', 'info', { timestamp: true })
22
+ */
23
+ export const print = (message, type = "log", options = {}) => {
24
+ // Allow the second argument to be an options object for backwards compatibility
25
+ if (typeof type === "object") {
26
+ options = type;
27
+ type = "log";
28
+ }
29
+
30
+ const { timestamp = false, label = "", prefix = true } = options;
31
+
32
+ const styles = {
33
+ log: { color: "#94a3b8", icon: "📝", method: "log" },
34
+ warn: { color: "#fbbf24", icon: "⚠️", method: "warn" },
35
+ error: { color: "#f87171", icon: "❌", method: "error" },
36
+ info: { color: "#60a5fa", icon: "ℹ️", method: "info" },
37
+ success: { color: "#34d399", icon: "✅", method: "log" },
38
+ debug: { color: "#c084fc", icon: "🐛", method: "debug" },
39
+ };
40
+
41
+ const config = styles[type] || styles.log;
42
+
43
+ // Serialize objects to readable JSON
44
+ let formattedMessage = message;
45
+ if (typeof message === "object" && message !== null) {
46
+ formattedMessage = JSON.stringify(message, null, 2);
47
+ }
48
+
49
+ const parts = [];
50
+ if (timestamp) parts.push(`[${new Date().toLocaleTimeString()}]`);
51
+ if (prefix) parts.push(config.icon);
52
+ if (label) parts.push(`[${label}]`);
53
+ parts.push(formattedMessage);
54
+
55
+ const finalMessage = parts.join(" ");
56
+
57
+ // Dispatch to the appropriate console method for the log level
58
+ console[config.method](finalMessage);
59
+ };
60
+
61
+ // Shorthand aliases (uncomment to enable individual exports):
62
+ // export const log = (msg) => print(msg, "log");
63
+ // export const warn = (msg) => print(msg, "warn");
64
+ // export const error = (msg) => print(msg, "error");
65
+ // export const info = (msg) => print(msg, "info");
66
+ // export const success = (msg) => print(msg, "success");
67
+ // export const debug = (msg) => print(msg, "debug");
68
+
69
+ export default print;