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,138 @@
|
|
|
1
|
+
// tools/device.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Device detection and responsive utilities.
|
|
5
|
+
*
|
|
6
|
+
* Uses `navigator.userAgent` and window geometry — not media queries — so results
|
|
7
|
+
* are synchronous and available before the DOM is ready. All methods are pure reads
|
|
8
|
+
* and never mutate global state; the listener helpers return cleanup functions so
|
|
9
|
+
* callers can unsubscribe easily.
|
|
10
|
+
*
|
|
11
|
+
* @namespace device
|
|
12
|
+
*/
|
|
13
|
+
export const device = {
|
|
14
|
+
/**
|
|
15
|
+
* Detect whether the current device is a mobile phone.
|
|
16
|
+
*
|
|
17
|
+
* Matches common mobile UA strings including Android phones, iOS devices,
|
|
18
|
+
* BlackBerry, Windows Phone (IEMobile), and Opera Mini.
|
|
19
|
+
*
|
|
20
|
+
* @returns {boolean} `true` if the UA string looks like a mobile phone
|
|
21
|
+
*/
|
|
22
|
+
isMobile: () => {
|
|
23
|
+
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
|
24
|
+
navigator.userAgent,
|
|
25
|
+
);
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Detect whether the current device is a tablet.
|
|
30
|
+
*
|
|
31
|
+
* Identifies iPads and Android tablets (Android UA without "Mobile" in the string).
|
|
32
|
+
*
|
|
33
|
+
* @returns {boolean} `true` if the UA string looks like a tablet
|
|
34
|
+
*/
|
|
35
|
+
isTablet: () => {
|
|
36
|
+
return /iPad|Android(?!.*Mobile)/i.test(navigator.userAgent);
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Detect whether the current device is a desktop/laptop.
|
|
41
|
+
*
|
|
42
|
+
* Returns `true` when neither `isMobile()` nor `isTablet()` match —
|
|
43
|
+
* i.e. the catch-all for any device that is not a phone or tablet.
|
|
44
|
+
*
|
|
45
|
+
* @returns {boolean} `true` if the device is not mobile and not a tablet
|
|
46
|
+
*/
|
|
47
|
+
isDesktop: () => {
|
|
48
|
+
return !device.isMobile() && !device.isTablet();
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get the current screen orientation.
|
|
53
|
+
*
|
|
54
|
+
* Compares `window.innerHeight` vs `window.innerWidth` rather than relying on
|
|
55
|
+
* `screen.orientation`, which is less widely supported and may be locked by the OS.
|
|
56
|
+
*
|
|
57
|
+
* @returns {"portrait"|"landscape"} Current orientation string
|
|
58
|
+
*/
|
|
59
|
+
orientation: () => {
|
|
60
|
+
return window.innerHeight > window.innerWidth ? "portrait" : "landscape";
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Detect whether the device supports touch input.
|
|
65
|
+
*
|
|
66
|
+
* Checks both the `ontouchstart` event property and the `maxTouchPoints` API,
|
|
67
|
+
* so it works across older and newer browsers consistently.
|
|
68
|
+
*
|
|
69
|
+
* @returns {boolean} `true` if the device supports touch events
|
|
70
|
+
*/
|
|
71
|
+
isTouch: () => {
|
|
72
|
+
return "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Detect whether the device supports multi-touch gestures (e.g. pinch-to-zoom).
|
|
77
|
+
*
|
|
78
|
+
* The `gesturestart` event is a non-standard WebKit extension primarily present
|
|
79
|
+
* on iOS Safari. Use this to conditionally enable gesture-based interactions.
|
|
80
|
+
*
|
|
81
|
+
* @returns {boolean} `true` if gesture events are supported
|
|
82
|
+
*/
|
|
83
|
+
hasGesture: () => {
|
|
84
|
+
return "ongesturestart" in window;
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Subscribe to device orientation changes.
|
|
89
|
+
*
|
|
90
|
+
* Fires `callback` with the new orientation string (`"portrait"` or `"landscape"`)
|
|
91
|
+
* whenever the device is rotated. Returns a cleanup function — call it to remove
|
|
92
|
+
* the listener and avoid memory leaks.
|
|
93
|
+
*
|
|
94
|
+
* @param {function(orientation: "portrait"|"landscape"): void} callback - Called on each orientation change
|
|
95
|
+
* @returns {function(): void} Cleanup function that removes the event listener
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* const unsub = device.onOrientationChange((o) => console.log('Now:', o));
|
|
99
|
+
* // Later, when the component unmounts:
|
|
100
|
+
* unsub();
|
|
101
|
+
*/
|
|
102
|
+
onOrientationChange: (callback) => {
|
|
103
|
+
const handler = () => callback(device.orientation());
|
|
104
|
+
window.addEventListener("orientationchange", handler);
|
|
105
|
+
return () => window.removeEventListener("orientationchange", handler);
|
|
106
|
+
},
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Subscribe to window resize events.
|
|
110
|
+
*
|
|
111
|
+
* Fires `callback` with the updated viewport dimensions and orientation on every
|
|
112
|
+
* resize. Returns a cleanup function to unsubscribe. Prefer this over reading
|
|
113
|
+
* `window.innerWidth` inline to avoid layout thrashing in tight loops.
|
|
114
|
+
*
|
|
115
|
+
* @param {function({ width: number, height: number, orientation: "portrait"|"landscape" }): void} callback
|
|
116
|
+
* Called with the new dimensions and orientation on each resize event
|
|
117
|
+
* @returns {function(): void} Cleanup function that removes the event listener
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* const unsub = device.onResize(({ width, height, orientation }) => {
|
|
121
|
+
* console.log(`Viewport: ${width}×${height} (${orientation})`);
|
|
122
|
+
* });
|
|
123
|
+
* // Later:
|
|
124
|
+
* unsub();
|
|
125
|
+
*/
|
|
126
|
+
onResize: (callback) => {
|
|
127
|
+
const handler = () =>
|
|
128
|
+
callback({
|
|
129
|
+
width: window.innerWidth,
|
|
130
|
+
height: window.innerHeight,
|
|
131
|
+
orientation: device.orientation(),
|
|
132
|
+
});
|
|
133
|
+
window.addEventListener("resize", handler);
|
|
134
|
+
return () => window.removeEventListener("resize", handler);
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export default device;
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
// src/tools/dict.js
|
|
2
|
+
// Python-like dictionary utilities
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A wrapper around a plain JavaScript object that exposes a Python-inspired
|
|
6
|
+
* dictionary API (`.get()`, `.keys()`, `.values()`, `.items()`, etc.).
|
|
7
|
+
*/
|
|
8
|
+
export class Dict {
|
|
9
|
+
/**
|
|
10
|
+
* @param {Object} [obj={}] - Initial key-value pairs.
|
|
11
|
+
*/
|
|
12
|
+
constructor(obj = {}) {
|
|
13
|
+
this._data = { ...obj };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Returns the value for `key`, or `defaultValue` if the key is absent.
|
|
18
|
+
* Mirrors Python's `dict.get(key, default)`.
|
|
19
|
+
*
|
|
20
|
+
* @param {string} key - Key to look up.
|
|
21
|
+
* @param {*} [defaultValue=null] - Fallback value when the key is missing.
|
|
22
|
+
* @returns {*} The stored value or `defaultValue`.
|
|
23
|
+
*/
|
|
24
|
+
get(key, defaultValue = null) {
|
|
25
|
+
return this._data[key] !== undefined ? this._data[key] : defaultValue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Sets a key to a value and returns `this` for chaining.
|
|
30
|
+
* Mirrors Python's assignment `d[key] = value`.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} key - Key to set.
|
|
33
|
+
* @param {*} value - Value to store.
|
|
34
|
+
* @returns {Dict} This instance.
|
|
35
|
+
*/
|
|
36
|
+
set(key, value) {
|
|
37
|
+
this._data[key] = value;
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Returns `true` if `key` exists in the dictionary.
|
|
43
|
+
* Mirrors Python's `key in d`.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} key - Key to check.
|
|
46
|
+
* @returns {boolean}
|
|
47
|
+
*/
|
|
48
|
+
has(key) {
|
|
49
|
+
return key in this._data;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Returns an array of all keys in the dictionary.
|
|
54
|
+
* Mirrors Python's `dict.keys()`.
|
|
55
|
+
*
|
|
56
|
+
* @returns {string[]}
|
|
57
|
+
*/
|
|
58
|
+
keys() {
|
|
59
|
+
return Object.keys(this._data);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Returns an array of all values in the dictionary.
|
|
64
|
+
* Mirrors Python's `dict.values()`.
|
|
65
|
+
*
|
|
66
|
+
* @returns {*[]}
|
|
67
|
+
*/
|
|
68
|
+
values() {
|
|
69
|
+
return Object.values(this._data);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Returns an array of `[key, value]` pairs.
|
|
74
|
+
* Mirrors Python's `dict.items()`.
|
|
75
|
+
*
|
|
76
|
+
* @returns {Array<[string, *]>}
|
|
77
|
+
*/
|
|
78
|
+
items() {
|
|
79
|
+
return Object.entries(this._data);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Deletes a key from the dictionary and returns `this` for chaining.
|
|
84
|
+
* Mirrors Python's `del d[key]`.
|
|
85
|
+
*
|
|
86
|
+
* @param {string} key - Key to remove.
|
|
87
|
+
* @returns {Dict} This instance.
|
|
88
|
+
*/
|
|
89
|
+
delete(key) {
|
|
90
|
+
delete this._data[key];
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The number of entries in the dictionary.
|
|
96
|
+
* Mirrors Python's `len(d)`.
|
|
97
|
+
*
|
|
98
|
+
* @type {number}
|
|
99
|
+
*/
|
|
100
|
+
get size() {
|
|
101
|
+
return Object.keys(this._data).length;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Removes all entries and returns `this` for chaining.
|
|
106
|
+
* Mirrors Python's `dict.clear()`.
|
|
107
|
+
*
|
|
108
|
+
* @returns {Dict} This instance.
|
|
109
|
+
*/
|
|
110
|
+
clear() {
|
|
111
|
+
this._data = {};
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Returns a shallow copy of this dictionary as a new `Dict` instance.
|
|
117
|
+
* Mirrors Python's `dict.copy()`.
|
|
118
|
+
*
|
|
119
|
+
* @returns {Dict} A new `Dict` with the same entries.
|
|
120
|
+
*/
|
|
121
|
+
copy() {
|
|
122
|
+
return new Dict({ ...this._data });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Merges another object or `Dict` into this dictionary, overwriting existing keys.
|
|
127
|
+
* Mirrors Python's `dict.update(other)`.
|
|
128
|
+
*
|
|
129
|
+
* @param {Object|Dict} other - Source of additional key-value pairs.
|
|
130
|
+
* @returns {Dict} This instance.
|
|
131
|
+
*/
|
|
132
|
+
update(other) {
|
|
133
|
+
Object.assign(this._data, other instanceof Dict ? other._data : other);
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Returns the internal data as a plain JavaScript object.
|
|
139
|
+
*
|
|
140
|
+
* @returns {Object}
|
|
141
|
+
*/
|
|
142
|
+
toObject() {
|
|
143
|
+
return { ...this._data };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Serializes the dictionary to a JSON string.
|
|
148
|
+
*
|
|
149
|
+
* @returns {string}
|
|
150
|
+
*/
|
|
151
|
+
toJSON() {
|
|
152
|
+
return JSON.stringify(this._data);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Returns a debug-friendly string representation.
|
|
157
|
+
* Mirrors Python's `__str__`.
|
|
158
|
+
*
|
|
159
|
+
* @returns {string} e.g. `Dict({"key":"value"})`
|
|
160
|
+
*/
|
|
161
|
+
toString() {
|
|
162
|
+
return `Dict(${JSON.stringify(this._data)})`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Reads a nested value using dot-notation path, returning `defaultValue` if any
|
|
167
|
+
* segment along the path is absent.
|
|
168
|
+
*
|
|
169
|
+
* @param {string} path - Dot-separated key path, e.g. `"user.address.city"`.
|
|
170
|
+
* @param {*} [defaultValue=null] - Fallback when the path does not exist.
|
|
171
|
+
* @returns {*} The nested value or `defaultValue`.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* dict.getNested("user.address.city", "Unknown")
|
|
175
|
+
*/
|
|
176
|
+
getNested(path, defaultValue = null) {
|
|
177
|
+
const keys = path.split(".");
|
|
178
|
+
let result = this._data;
|
|
179
|
+
for (const key of keys) {
|
|
180
|
+
if (result?.[key] === undefined) return defaultValue;
|
|
181
|
+
result = result[key];
|
|
182
|
+
}
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Sets a nested value at the given dot-notation path, creating intermediate
|
|
188
|
+
* objects as needed. Returns `this` for chaining.
|
|
189
|
+
*
|
|
190
|
+
* @param {string} path - Dot-separated key path, e.g. `"user.address.city"`.
|
|
191
|
+
* @param {*} value - Value to set at the path.
|
|
192
|
+
* @returns {Dict} This instance.
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* dict.setNested("user.address.city", "New York")
|
|
196
|
+
*/
|
|
197
|
+
setNested(path, value) {
|
|
198
|
+
const keys = path.split(".");
|
|
199
|
+
const lastKey = keys.pop();
|
|
200
|
+
let target = this._data;
|
|
201
|
+
for (const key of keys) {
|
|
202
|
+
if (target[key] === undefined) target[key] = {};
|
|
203
|
+
target = target[key];
|
|
204
|
+
}
|
|
205
|
+
target[lastKey] = value;
|
|
206
|
+
return this;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Iterates over all entries, calling `callback(value, key)` for each.
|
|
211
|
+
*
|
|
212
|
+
* @param {Function} callback - Called with `(value, key)` for each entry.
|
|
213
|
+
* @returns {void}
|
|
214
|
+
*/
|
|
215
|
+
forEach(callback) {
|
|
216
|
+
Object.entries(this._data).forEach(([key, value]) => callback(value, key));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Maps over all entries and returns an array of the results.
|
|
221
|
+
*
|
|
222
|
+
* @param {Function} callback - Called with `(value, key)` for each entry; return the mapped value.
|
|
223
|
+
* @returns {Array<*>}
|
|
224
|
+
*/
|
|
225
|
+
map(callback) {
|
|
226
|
+
return Object.entries(this._data).map(([key, value]) =>
|
|
227
|
+
callback(value, key),
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Returns a new `Dict` containing only entries for which `callback` returns truthy.
|
|
233
|
+
*
|
|
234
|
+
* @param {Function} callback - Predicate called with `(value, key)`.
|
|
235
|
+
* @returns {Dict} Filtered dictionary.
|
|
236
|
+
*/
|
|
237
|
+
filter(callback) {
|
|
238
|
+
const result = {};
|
|
239
|
+
Object.entries(this._data).forEach(([key, value]) => {
|
|
240
|
+
if (callback(value, key)) result[key] = value;
|
|
241
|
+
});
|
|
242
|
+
return new Dict(result);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Factory function — creates a new `Dict` instance from a plain object.
|
|
248
|
+
* Mirrors Python's `dict()` constructor.
|
|
249
|
+
*
|
|
250
|
+
* @param {Object} [obj={}] - Initial key-value pairs.
|
|
251
|
+
* @returns {Dict}
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* const d = dict({ name: "Alice", age: 30 });
|
|
255
|
+
* d.get("name"); // "Alice"
|
|
256
|
+
*/
|
|
257
|
+
export const dict = (obj = {}) => {
|
|
258
|
+
return new Dict(obj);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Creates and returns an empty `Dict`.
|
|
263
|
+
*
|
|
264
|
+
* @returns {Dict}
|
|
265
|
+
*/
|
|
266
|
+
export const emptyDict = () => new Dict({});
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Parses a JSON string and wraps the result in a `Dict`.
|
|
270
|
+
* Returns an empty `Dict` on parse failure.
|
|
271
|
+
*
|
|
272
|
+
* @param {string} jsonStr - JSON-encoded object string.
|
|
273
|
+
* @returns {Dict}
|
|
274
|
+
*/
|
|
275
|
+
export const fromJSON = (jsonStr) => {
|
|
276
|
+
try {
|
|
277
|
+
return new Dict(JSON.parse(jsonStr));
|
|
278
|
+
} catch {
|
|
279
|
+
return new Dict({});
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Creates a `Dict` from an array of `[key, value]` pairs.
|
|
285
|
+
* Mirrors Python's `dict([(key, value), ...])`.
|
|
286
|
+
*
|
|
287
|
+
* @param {Array<[string, *]>} entries - Array of key-value pairs.
|
|
288
|
+
* @returns {Dict}
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* fromEntries([["a", 1], ["b", 2]]) // Dict { a: 1, b: 2 }
|
|
292
|
+
*/
|
|
293
|
+
export const fromEntries = (entries) => {
|
|
294
|
+
return new Dict(Object.fromEntries(entries));
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
export default dict;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// src/modules/FletBox/core/dimensions.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dimensions - Provides the current window dimensions and a resize listener API.
|
|
5
|
+
* Similar in spirit to React Native's `Dimensions` module.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { width, height } from './core/dimensions.js';
|
|
9
|
+
* console.log(`Screen: ${width} x ${height}`);
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* import { dimensions } from './core/dimensions.js';
|
|
13
|
+
* const remove = dimensions.addListener(({ width, height }) => {
|
|
14
|
+
* console.log(`Window resized: ${width} x ${height}`);
|
|
15
|
+
* });
|
|
16
|
+
* // Call remove() to stop listening.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
let windowWidth = window.innerWidth;
|
|
20
|
+
let windowHeight = window.innerHeight;
|
|
21
|
+
|
|
22
|
+
// Live named exports — is-module live bindings: importers of { width, height }
|
|
23
|
+
// always read the current value, kept in sync on resize.
|
|
24
|
+
export let width = windowWidth;
|
|
25
|
+
export let height = windowHeight;
|
|
26
|
+
|
|
27
|
+
// Internal list of resize listener callbacks
|
|
28
|
+
const listeners = [];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Internal resize handler. Syncs the cached dimensions and notifies all
|
|
32
|
+
* registered listeners whenever the browser window is resized.
|
|
33
|
+
*
|
|
34
|
+
* @returns {void}
|
|
35
|
+
*/
|
|
36
|
+
const handleResize = () => {
|
|
37
|
+
windowWidth = window.innerWidth;
|
|
38
|
+
windowHeight = window.innerHeight;
|
|
39
|
+
width = windowWidth;
|
|
40
|
+
height = windowHeight;
|
|
41
|
+
|
|
42
|
+
// Notify all registered listeners with the updated dimensions
|
|
43
|
+
listeners.forEach((listener) => {
|
|
44
|
+
listener({ width: windowWidth, height: windowHeight });
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
window.addEventListener("resize", handleResize);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Dimensions object — provides getter properties and listener management.
|
|
52
|
+
* Prefer the named `width` / `height` exports for simple reads; use this
|
|
53
|
+
* object when you need the full API.
|
|
54
|
+
*/
|
|
55
|
+
export const dimensions = {
|
|
56
|
+
/** Current window width in pixels. @type {number} */
|
|
57
|
+
get width() {
|
|
58
|
+
return windowWidth;
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/** Current window height in pixels. @type {number} */
|
|
62
|
+
get height() {
|
|
63
|
+
return windowHeight;
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Returns the current window dimensions as an object.
|
|
68
|
+
*
|
|
69
|
+
* @returns {{ width: number, height: number }}
|
|
70
|
+
*/
|
|
71
|
+
get: () => ({ width: windowWidth, height: windowHeight }),
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Returns the current window width in pixels.
|
|
75
|
+
*
|
|
76
|
+
* @returns {number}
|
|
77
|
+
*/
|
|
78
|
+
getWidth: () => windowWidth,
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Returns the current window height in pixels.
|
|
82
|
+
*
|
|
83
|
+
* @returns {number}
|
|
84
|
+
*/
|
|
85
|
+
getHeight: () => windowHeight,
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Registers a callback that is called whenever the window is resized.
|
|
89
|
+
*
|
|
90
|
+
* @param {Function} callback - Receives `{ width: number, height: number }` on each resize.
|
|
91
|
+
* @returns {Function} A cleanup function that removes this listener when called.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* const remove = dimensions.addListener(({ width }) => console.log(width));
|
|
95
|
+
* // Later:
|
|
96
|
+
* remove();
|
|
97
|
+
*/
|
|
98
|
+
addListener: (callback) => {
|
|
99
|
+
listeners.push(callback);
|
|
100
|
+
return () => {
|
|
101
|
+
const index = listeners.indexOf(callback);
|
|
102
|
+
if (index > -1) listeners.splice(index, 1);
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Removes a previously registered resize listener.
|
|
108
|
+
*
|
|
109
|
+
* @param {Function} callback - The same function reference passed to `addListener`.
|
|
110
|
+
* @returns {void}
|
|
111
|
+
*/
|
|
112
|
+
removeListener: (callback) => {
|
|
113
|
+
const index = listeners.indexOf(callback);
|
|
114
|
+
if (index > -1) listeners.splice(index, 1);
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export default dimensions;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// tools/filter.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate CSS filter string
|
|
5
|
+
* @param {Object} options - Filter options
|
|
6
|
+
* @returns {string} CSS filter value
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* filter({ blur: 5, brightness: 0.8, contrast: 1.2 })
|
|
10
|
+
* // "blur(5px) brightness(0.8) contrast(1.2)"
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* filter({ grayscale: 1, sepia: 0.5, hueRotate: 90 })
|
|
14
|
+
* // "grayscale(1) sepia(0.5) hue-rotate(90deg)"
|
|
15
|
+
*/
|
|
16
|
+
export const filter = (options = {}) => {
|
|
17
|
+
const parts = [];
|
|
18
|
+
|
|
19
|
+
if (options.blur)
|
|
20
|
+
parts.push(
|
|
21
|
+
`blur(${typeof options.blur === "number" ? options.blur + "px" : options.blur})`,
|
|
22
|
+
);
|
|
23
|
+
if (options.brightness) parts.push(`brightness(${options.brightness})`);
|
|
24
|
+
if (options.contrast) parts.push(`contrast(${options.contrast})`);
|
|
25
|
+
if (options.dropShadow) {
|
|
26
|
+
const [x, y, blur, color] = options.dropShadow;
|
|
27
|
+
parts.push(`drop-shadow(${x}px ${y}px ${blur}px ${color})`);
|
|
28
|
+
}
|
|
29
|
+
if (options.grayscale) parts.push(`grayscale(${options.grayscale})`);
|
|
30
|
+
if (options.hueRotate) parts.push(`hue-rotate(${options.hueRotate}deg)`);
|
|
31
|
+
if (options.invert) parts.push(`invert(${options.invert})`);
|
|
32
|
+
if (options.opacity) parts.push(`opacity(${options.opacity})`);
|
|
33
|
+
if (options.saturate) parts.push(`saturate(${options.saturate})`);
|
|
34
|
+
if (options.sepia) parts.push(`sepia(${options.sepia})`);
|
|
35
|
+
if (options.backdrop)
|
|
36
|
+
parts.push(`backdrop-filter(${filter(options.backdrop)})`);
|
|
37
|
+
|
|
38
|
+
return parts.join(" ");
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export default filter;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// tools/flex.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate CSS flex string (shorthand)
|
|
5
|
+
* @param {number|Object} grow - Flex grow value or options object
|
|
6
|
+
* @param {number} shrink - Flex shrink value
|
|
7
|
+
* @param {string} basis - Flex basis value
|
|
8
|
+
* @returns {string} CSS flex value
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* flex(1) // "1 1 0%"
|
|
12
|
+
* flex(1, 0, 'auto') // "1 0 auto"
|
|
13
|
+
* flex({ grow: 1, shrink: 0, basis: '200px' })
|
|
14
|
+
* // "1 0 200px"
|
|
15
|
+
*/
|
|
16
|
+
export const flex = (grow, shrink = 1, basis = "0%") => {
|
|
17
|
+
if (typeof grow === "object") {
|
|
18
|
+
const g = grow.grow ?? 1;
|
|
19
|
+
const s = grow.shrink ?? 1;
|
|
20
|
+
const b = grow.basis ?? "0%";
|
|
21
|
+
return `${g} ${s} ${b}`;
|
|
22
|
+
}
|
|
23
|
+
return `${grow} ${shrink} ${basis}`;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default flex;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a CSS gradient string.
|
|
3
|
+
*
|
|
4
|
+
* Supports linear, radial (circle), and conic gradient types.
|
|
5
|
+
* Use the returned string as a CSS `background` value on any element.
|
|
6
|
+
*
|
|
7
|
+
* @param {"linear"|"circle"|"conic"} type - Gradient type:
|
|
8
|
+
* - `"linear"` → `linear-gradient(angleDeg, ...stops)`
|
|
9
|
+
* - `"circle"` → `radial-gradient(circle, ...stops)`
|
|
10
|
+
* - `"conic"` → `conic-gradient(from angleDeg, ...stops)`
|
|
11
|
+
* @param {string[]} colors - Array of color stop values (any valid CSS color)
|
|
12
|
+
* @param {number} [angle=135] - Angle in degrees (used for linear and conic gradients)
|
|
13
|
+
* @returns {string} CSS gradient value
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Use in a Container's background prop:
|
|
17
|
+
* gradient('linear', ['red', 'blue'])
|
|
18
|
+
* // "linear-gradient(135deg, red, blue)"
|
|
19
|
+
*
|
|
20
|
+
* gradient('circle', ['white', 'black'])
|
|
21
|
+
* // "radial-gradient(circle, white, black)"
|
|
22
|
+
*
|
|
23
|
+
* gradient('conic', ['red', 'yellow', 'blue'])
|
|
24
|
+
* // "conic-gradient(from 135deg, red, yellow, blue)"
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const gradient = (type, colors, angle = 135) => {
|
|
28
|
+
const stops = colors.join(", ");
|
|
29
|
+
if (type === "linear") return `linear-gradient(${angle}deg, ${stops})`;
|
|
30
|
+
if (type === "circle") return `radial-gradient(circle, ${stops})`;
|
|
31
|
+
return `conic-gradient(from ${angle}deg, ${stops})`;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default gradient;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// tools/grid.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate CSS grid template string
|
|
5
|
+
* @param {Object} options - Grid options
|
|
6
|
+
* @returns {string} CSS grid value
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* grid({ columns: 3, gap: 16 })
|
|
10
|
+
* // "repeat(3, 1fr) / auto"
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* grid({ columns: '200px 1fr', rows: 'auto 100px', gap: { row: 16, column: 8 } })
|
|
14
|
+
* // "200px 1fr / auto 100px"
|
|
15
|
+
*/
|
|
16
|
+
export const grid = (options = {}) => {
|
|
17
|
+
let columns = "";
|
|
18
|
+
let rows = "";
|
|
19
|
+
|
|
20
|
+
// Handle columns
|
|
21
|
+
if (options.columns) {
|
|
22
|
+
if (typeof options.columns === "number") {
|
|
23
|
+
columns = `repeat(${options.columns}, 1fr)`;
|
|
24
|
+
} else {
|
|
25
|
+
columns = options.columns;
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
columns = "1fr";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Handle rows
|
|
32
|
+
if (options.rows) {
|
|
33
|
+
if (typeof options.rows === "number") {
|
|
34
|
+
rows = `repeat(${options.rows}, auto)`;
|
|
35
|
+
} else {
|
|
36
|
+
rows = options.rows;
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
rows = "auto";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Handle gap
|
|
43
|
+
let gap = "";
|
|
44
|
+
if (options.gap) {
|
|
45
|
+
if (typeof options.gap === "number") {
|
|
46
|
+
gap = ` ${options.gap}px`;
|
|
47
|
+
} else if (typeof options.gap === "object") {
|
|
48
|
+
gap = ` ${options.gap.row || 0}px ${options.gap.column || 0}px`;
|
|
49
|
+
} else {
|
|
50
|
+
gap = ` ${options.gap}`;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return `${columns} / ${rows}${gap}`;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export default grid;
|