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,674 @@
|
|
|
1
|
+
// tools/time.js - COMPLETE VERSION
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ============================================================
|
|
5
|
+
* TIME HELPERS - Complete Natural English
|
|
6
|
+
* ============================================================
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// ========== TIME UNITS ==========
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Converts seconds to milliseconds.
|
|
13
|
+
* @param {number} n - Number of seconds.
|
|
14
|
+
* @returns {number} Equivalent milliseconds.
|
|
15
|
+
*/
|
|
16
|
+
export const seconds = (n) => n * 1000;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Converts minutes to milliseconds.
|
|
20
|
+
* @param {number} n - Number of minutes.
|
|
21
|
+
* @returns {number} Equivalent milliseconds.
|
|
22
|
+
*/
|
|
23
|
+
export const minutes = (n) => n * 60 * 1000;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Converts hours to milliseconds.
|
|
27
|
+
* @param {number} n - Number of hours.
|
|
28
|
+
* @returns {number} Equivalent milliseconds.
|
|
29
|
+
*/
|
|
30
|
+
export const hours = (n) => n * 60 * 60 * 1000;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Converts days to milliseconds.
|
|
34
|
+
* @param {number} n - Number of days.
|
|
35
|
+
* @returns {number} Equivalent milliseconds.
|
|
36
|
+
*/
|
|
37
|
+
export const days = (n) => n * 24 * 60 * 60 * 1000;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Converts weeks to milliseconds.
|
|
41
|
+
* @param {number} n - Number of weeks.
|
|
42
|
+
* @returns {number} Equivalent milliseconds.
|
|
43
|
+
*/
|
|
44
|
+
export const weeks = (n) => n * 7 * 24 * 60 * 60 * 1000;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Converts months (approximated as 30 days) to milliseconds.
|
|
48
|
+
* @param {number} n - Number of months.
|
|
49
|
+
* @returns {number} Equivalent milliseconds.
|
|
50
|
+
*/
|
|
51
|
+
export const months = (n) => n * 30 * days(1);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Converts years (approximated as 365 days) to milliseconds.
|
|
55
|
+
* @param {number} n - Number of years.
|
|
56
|
+
* @returns {number} Equivalent milliseconds.
|
|
57
|
+
*/
|
|
58
|
+
export const years = (n) => n * 365 * days(1);
|
|
59
|
+
|
|
60
|
+
// ========== CURRENT ==========
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Returns the current Unix timestamp in milliseconds.
|
|
64
|
+
* @returns {number} Current time as a Unix epoch in ms.
|
|
65
|
+
*/
|
|
66
|
+
export const now = () => Date.now();
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Returns today's date formatted as `YYYY-MM-DD`.
|
|
70
|
+
* @returns {string} Today's date string.
|
|
71
|
+
*/
|
|
72
|
+
export const today = () => formatDate(now(), "YYYY-MM-DD");
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Returns yesterday's date formatted as `YYYY-MM-DD`.
|
|
76
|
+
* @returns {string} Yesterday's date string.
|
|
77
|
+
*/
|
|
78
|
+
export const yesterday = () => formatDate(now() - days(1), "YYYY-MM-DD");
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Returns tomorrow's date formatted as `YYYY-MM-DD`.
|
|
82
|
+
* @returns {string} Tomorrow's date string.
|
|
83
|
+
*/
|
|
84
|
+
export const tomorrow = () => formatDate(now() + days(1), "YYYY-MM-DD");
|
|
85
|
+
|
|
86
|
+
// ========== DATE INFO ==========
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Returns the full English name of the day of the week for a given date.
|
|
90
|
+
* @param {Date|number|string} date - Any value accepted by `new Date()`.
|
|
91
|
+
* @returns {string} Day name, e.g. `"Monday"`.
|
|
92
|
+
*/
|
|
93
|
+
export const dayOfWeek = (date) => {
|
|
94
|
+
const days = [
|
|
95
|
+
"Sunday",
|
|
96
|
+
"Monday",
|
|
97
|
+
"Tuesday",
|
|
98
|
+
"Wednesday",
|
|
99
|
+
"Thursday",
|
|
100
|
+
"Friday",
|
|
101
|
+
"Saturday",
|
|
102
|
+
];
|
|
103
|
+
return days[new Date(date).getDay()];
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Returns the full English name of the month for a given date.
|
|
108
|
+
* @param {Date|number|string} date - Any value accepted by `new Date()`.
|
|
109
|
+
* @returns {string} Month name, e.g. `"January"`.
|
|
110
|
+
*/
|
|
111
|
+
export const monthName = (date) => {
|
|
112
|
+
const months = [
|
|
113
|
+
"January",
|
|
114
|
+
"February",
|
|
115
|
+
"March",
|
|
116
|
+
"April",
|
|
117
|
+
"May",
|
|
118
|
+
"June",
|
|
119
|
+
"July",
|
|
120
|
+
"August",
|
|
121
|
+
"September",
|
|
122
|
+
"October",
|
|
123
|
+
"November",
|
|
124
|
+
"December",
|
|
125
|
+
];
|
|
126
|
+
return months[new Date(date).getMonth()];
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Returns `true` if the given date falls on today.
|
|
131
|
+
* @param {Date|number|string} date - Date to check.
|
|
132
|
+
* @returns {boolean}
|
|
133
|
+
*/
|
|
134
|
+
export const isToday = (date) => formatDate(date) === today();
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Returns `true` if the given date falls on yesterday.
|
|
138
|
+
* @param {Date|number|string} date - Date to check.
|
|
139
|
+
* @returns {boolean}
|
|
140
|
+
*/
|
|
141
|
+
export const isYesterday = (date) => formatDate(date) === yesterday();
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Returns `true` if the given date falls on tomorrow.
|
|
145
|
+
* @param {Date|number|string} date - Date to check.
|
|
146
|
+
* @returns {boolean}
|
|
147
|
+
*/
|
|
148
|
+
export const isTomorrow = (date) => formatDate(date) === tomorrow();
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Returns `true` if the given date falls on a Saturday or Sunday.
|
|
152
|
+
* @param {Date|number|string} date - Date to check.
|
|
153
|
+
* @returns {boolean}
|
|
154
|
+
*/
|
|
155
|
+
export const isWeekend = (date) => [0, 6].includes(new Date(date).getDay());
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Returns `true` if the given year is a leap year.
|
|
159
|
+
* @param {number} year - Four-digit year.
|
|
160
|
+
* @returns {boolean}
|
|
161
|
+
*/
|
|
162
|
+
export const isLeapYear = (year) => {
|
|
163
|
+
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// ========== FORMAT ==========
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Formats a date according to a token-based format string.
|
|
170
|
+
*
|
|
171
|
+
* Supported tokens: `YYYY` (year), `MM` (month), `DD` (day),
|
|
172
|
+
* `HH` (hours, 24h), `mm` (minutes), `ss` (seconds).
|
|
173
|
+
*
|
|
174
|
+
* @param {Date|number|string} date - Date to format.
|
|
175
|
+
* @param {string} [format="YYYY-MM-DD"] - Output format string.
|
|
176
|
+
* @returns {string} Formatted date string.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* formatDate(new Date(), "YYYY-MM-DD HH:mm:ss") // "2024-01-15 09:30:00"
|
|
180
|
+
*/
|
|
181
|
+
export const formatDate = (date, format = "YYYY-MM-DD") => {
|
|
182
|
+
const d = new Date(date);
|
|
183
|
+
const year = d.getFullYear();
|
|
184
|
+
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
185
|
+
const day = String(d.getDate()).padStart(2, "0");
|
|
186
|
+
const hours = String(d.getHours()).padStart(2, "0");
|
|
187
|
+
const minutes = String(d.getMinutes()).padStart(2, "0");
|
|
188
|
+
const seconds = String(d.getSeconds()).padStart(2, "0");
|
|
189
|
+
|
|
190
|
+
return format
|
|
191
|
+
.replace("YYYY", year)
|
|
192
|
+
.replace("MM", month)
|
|
193
|
+
.replace("DD", day)
|
|
194
|
+
.replace("HH", hours)
|
|
195
|
+
.replace("mm", minutes)
|
|
196
|
+
.replace("ss", seconds);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Formats a date as a long human-readable string using the Intl API.
|
|
201
|
+
*
|
|
202
|
+
* @param {Date|number|string} date - Date to format.
|
|
203
|
+
* @param {string} [locale="en-US"] - BCP 47 locale string.
|
|
204
|
+
* @returns {string} Long date string, e.g. `"Monday, January 15, 2024"`.
|
|
205
|
+
*/
|
|
206
|
+
export const formatDateLong = (date, locale = "en-US") => {
|
|
207
|
+
return new Date(date).toLocaleDateString(locale, {
|
|
208
|
+
weekday: "long",
|
|
209
|
+
year: "numeric",
|
|
210
|
+
month: "long",
|
|
211
|
+
day: "numeric",
|
|
212
|
+
});
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Formats a date as a short human-readable string using the Intl API.
|
|
217
|
+
*
|
|
218
|
+
* @param {Date|number|string} date - Date to format.
|
|
219
|
+
* @param {string} [locale="en-US"] - BCP 47 locale string.
|
|
220
|
+
* @returns {string} Short date string, e.g. `"Jan 15, 2024"`.
|
|
221
|
+
*/
|
|
222
|
+
export const formatDateShort = (date, locale = "en-US") => {
|
|
223
|
+
return new Date(date).toLocaleDateString(locale, {
|
|
224
|
+
year: "numeric",
|
|
225
|
+
month: "short",
|
|
226
|
+
day: "numeric",
|
|
227
|
+
});
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Formats a date as a 24-hour time string `HH:mm:ss`.
|
|
232
|
+
* @param {Date|number|string} date - Date to format.
|
|
233
|
+
* @returns {string} Time string, e.g. `"14:05:30"`.
|
|
234
|
+
*/
|
|
235
|
+
export const formatTime = (date) => formatDate(date, "HH:mm:ss");
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Formats a date as a 12-hour time string with AM/PM suffix.
|
|
239
|
+
* @param {Date|number|string} date - Date to format.
|
|
240
|
+
* @returns {string} Time string, e.g. `"02:05:30 PM"`.
|
|
241
|
+
*/
|
|
242
|
+
export const formatTimeAmPm = (date) => {
|
|
243
|
+
const d = new Date(date);
|
|
244
|
+
let hours = d.getHours();
|
|
245
|
+
const ampm = hours >= 12 ? "PM" : "AM";
|
|
246
|
+
hours = hours % 12 || 12;
|
|
247
|
+
const minutes = String(d.getMinutes()).padStart(2, "0");
|
|
248
|
+
const seconds = String(d.getSeconds()).padStart(2, "0");
|
|
249
|
+
return `${String(hours).padStart(2, "0")}:${minutes}:${seconds} ${ampm}`;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// ========== PARSE ==========
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Parses a date string into a `Date` object using a simple token-based format.
|
|
256
|
+
*
|
|
257
|
+
* Supported tokens: `YYYY`, `MM`, `DD`, `HH`, `mm`, `ss`.
|
|
258
|
+
* Separators can be `-`, `/`, `:`, or a space.
|
|
259
|
+
*
|
|
260
|
+
* @param {string} str - Date string to parse.
|
|
261
|
+
* @param {string} [format="YYYY-MM-DD"] - Format string describing the input.
|
|
262
|
+
* @returns {Date} Parsed `Date` object.
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* parseDate("2024-01-15", "YYYY-MM-DD")
|
|
266
|
+
* parseDate("15/01/2024", "DD/MM/YYYY")
|
|
267
|
+
*/
|
|
268
|
+
export const parseDate = (str, format = "YYYY-MM-DD") => {
|
|
269
|
+
// Simple parser for common formats
|
|
270
|
+
const parts = str.split(/[-/:\s]/);
|
|
271
|
+
const fmt = format.split(/[-/:\s]/);
|
|
272
|
+
|
|
273
|
+
let year = new Date().getFullYear();
|
|
274
|
+
let month = 0;
|
|
275
|
+
let day = 1;
|
|
276
|
+
let hours = 0;
|
|
277
|
+
let minutes = 0;
|
|
278
|
+
let seconds = 0;
|
|
279
|
+
|
|
280
|
+
fmt.forEach((f, i) => {
|
|
281
|
+
const val = parseInt(parts[i]);
|
|
282
|
+
if (f === "YYYY") year = val;
|
|
283
|
+
else if (f === "MM") month = val - 1;
|
|
284
|
+
else if (f === "DD") day = val;
|
|
285
|
+
else if (f === "HH") hours = val;
|
|
286
|
+
else if (f === "mm") minutes = val;
|
|
287
|
+
else if (f === "ss") seconds = val;
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return new Date(year, month, day, hours, minutes, seconds);
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
// ========== DIFF ==========
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Returns the absolute difference between two dates in the specified unit.
|
|
297
|
+
*
|
|
298
|
+
* @param {Date|number|string} date1 - First date.
|
|
299
|
+
* @param {Date|number|string} date2 - Second date.
|
|
300
|
+
* @param {"milliseconds"|"seconds"|"minutes"|"hours"|"days"|"weeks"|"months"|"years"} [unit="days"] - Output unit.
|
|
301
|
+
* @returns {number} Absolute difference in the requested unit.
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* dateDiff("2024-01-01", "2024-01-15", "days") // 14
|
|
305
|
+
*/
|
|
306
|
+
export const dateDiff = (date1, date2, unit = "days") => {
|
|
307
|
+
const diff = Math.abs(new Date(date1) - new Date(date2));
|
|
308
|
+
const units = {
|
|
309
|
+
milliseconds: 1,
|
|
310
|
+
seconds: 1000,
|
|
311
|
+
minutes: 1000 * 60,
|
|
312
|
+
hours: 1000 * 60 * 60,
|
|
313
|
+
days: 1000 * 60 * 60 * 24,
|
|
314
|
+
weeks: 1000 * 60 * 60 * 24 * 7,
|
|
315
|
+
months: 1000 * 60 * 60 * 24 * 30,
|
|
316
|
+
years: 1000 * 60 * 60 * 24 * 365,
|
|
317
|
+
};
|
|
318
|
+
return diff / units[unit];
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// ========== MANIPULATE ==========
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Adds `n` days to a date and returns a new `Date`.
|
|
325
|
+
* @param {Date|number|string} date - Base date.
|
|
326
|
+
* @param {number} n - Number of days to add (negative to subtract).
|
|
327
|
+
* @returns {Date}
|
|
328
|
+
*/
|
|
329
|
+
export const addDays = (date, n) =>
|
|
330
|
+
new Date(new Date(date).getTime() + days(n));
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Adds `n` hours to a date and returns a new `Date`.
|
|
334
|
+
* @param {Date|number|string} date - Base date.
|
|
335
|
+
* @param {number} n - Number of hours to add (negative to subtract).
|
|
336
|
+
* @returns {Date}
|
|
337
|
+
*/
|
|
338
|
+
export const addHours = (date, n) =>
|
|
339
|
+
new Date(new Date(date).getTime() + hours(n));
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Adds `n` minutes to a date and returns a new `Date`.
|
|
343
|
+
* @param {Date|number|string} date - Base date.
|
|
344
|
+
* @param {number} n - Number of minutes to add (negative to subtract).
|
|
345
|
+
* @returns {Date}
|
|
346
|
+
*/
|
|
347
|
+
export const addMinutes = (date, n) =>
|
|
348
|
+
new Date(new Date(date).getTime() + minutes(n));
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Adds `n` seconds to a date and returns a new `Date`.
|
|
352
|
+
* @param {Date|number|string} date - Base date.
|
|
353
|
+
* @param {number} n - Number of seconds to add (negative to subtract).
|
|
354
|
+
* @returns {Date}
|
|
355
|
+
*/
|
|
356
|
+
export const addSeconds = (date, n) =>
|
|
357
|
+
new Date(new Date(date).getTime() + seconds(n));
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Subtracts `n` days from a date and returns a new `Date`.
|
|
361
|
+
* @param {Date|number|string} date - Base date.
|
|
362
|
+
* @param {number} n - Number of days to subtract.
|
|
363
|
+
* @returns {Date}
|
|
364
|
+
*/
|
|
365
|
+
export const subtractDays = (date, n) => addDays(date, -n);
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Subtracts `n` hours from a date and returns a new `Date`.
|
|
369
|
+
* @param {Date|number|string} date - Base date.
|
|
370
|
+
* @param {number} n - Number of hours to subtract.
|
|
371
|
+
* @returns {Date}
|
|
372
|
+
*/
|
|
373
|
+
export const subtractHours = (date, n) => addHours(date, -n);
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Subtracts `n` minutes from a date and returns a new `Date`.
|
|
377
|
+
* @param {Date|number|string} date - Base date.
|
|
378
|
+
* @param {number} n - Number of minutes to subtract.
|
|
379
|
+
* @returns {Date}
|
|
380
|
+
*/
|
|
381
|
+
export const subtractMinutes = (date, n) => addMinutes(date, -n);
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Subtracts `n` seconds from a date and returns a new `Date`.
|
|
385
|
+
* @param {Date|number|string} date - Base date.
|
|
386
|
+
* @param {number} n - Number of seconds to subtract.
|
|
387
|
+
* @returns {Date}
|
|
388
|
+
*/
|
|
389
|
+
export const subtractSeconds = (date, n) => addSeconds(date, -n);
|
|
390
|
+
|
|
391
|
+
// ========== RELATIVE ==========
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Returns a human-readable relative time string in English, e.g. `"3 days ago"`.
|
|
395
|
+
* Returns `"just now"` for differences under 1 second.
|
|
396
|
+
*
|
|
397
|
+
* @param {Date|number|string} date - The past date to compare against now.
|
|
398
|
+
* @returns {string} Relative time string.
|
|
399
|
+
*
|
|
400
|
+
* @example
|
|
401
|
+
* timeAgo(Date.now() - 5 * 60 * 1000) // "5 minutes ago"
|
|
402
|
+
*/
|
|
403
|
+
export const timeAgo = (date) => {
|
|
404
|
+
const now = new Date();
|
|
405
|
+
const d = new Date(date);
|
|
406
|
+
const diff = Math.floor((now - d) / 1000);
|
|
407
|
+
|
|
408
|
+
const intervals = [
|
|
409
|
+
{ label: "year", seconds: 31536000 },
|
|
410
|
+
{ label: "month", seconds: 2592000 },
|
|
411
|
+
{ label: "week", seconds: 604800 },
|
|
412
|
+
{ label: "day", seconds: 86400 },
|
|
413
|
+
{ label: "hour", seconds: 3600 },
|
|
414
|
+
{ label: "minute", seconds: 60 },
|
|
415
|
+
{ label: "second", seconds: 1 },
|
|
416
|
+
];
|
|
417
|
+
|
|
418
|
+
for (const interval of intervals) {
|
|
419
|
+
const count = Math.floor(diff / interval.seconds);
|
|
420
|
+
if (count >= 1) {
|
|
421
|
+
return `${count} ${interval.label}${count > 1 ? "s" : ""} ago`;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return "just now";
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
/** Alias for {@link timeAgo}. */
|
|
428
|
+
export const relativeTime = timeAgo;
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Returns a human-readable relative time string in the specified locale.
|
|
432
|
+
* Supports `"en"` (English) and `"es"` (Spanish); falls back to English.
|
|
433
|
+
*
|
|
434
|
+
* @param {Date|number|string} date - The past date to compare against now.
|
|
435
|
+
* @param {"en"|"es"} [locale="en"] - Output locale.
|
|
436
|
+
* @returns {string} Locale-aware relative time string.
|
|
437
|
+
*
|
|
438
|
+
* @example
|
|
439
|
+
* timeAgoLocale(Date.now() - 3600000, "es") // "hace 1 hora"
|
|
440
|
+
*/
|
|
441
|
+
export const timeAgoLocale = (date, locale = "en") => {
|
|
442
|
+
const d = new Date(date);
|
|
443
|
+
const now = new Date();
|
|
444
|
+
const diff = Math.floor((now - d) / 1000);
|
|
445
|
+
|
|
446
|
+
const intervals = {
|
|
447
|
+
en: [
|
|
448
|
+
{ label: "year", seconds: 31536000, plural: "years" },
|
|
449
|
+
{ label: "month", seconds: 2592000, plural: "months" },
|
|
450
|
+
{ label: "week", seconds: 604800, plural: "weeks" },
|
|
451
|
+
{ label: "day", seconds: 86400, plural: "days" },
|
|
452
|
+
{ label: "hour", seconds: 3600, plural: "hours" },
|
|
453
|
+
{ label: "minute", seconds: 60, plural: "minutes" },
|
|
454
|
+
{ label: "second", seconds: 1, plural: "seconds" },
|
|
455
|
+
],
|
|
456
|
+
es: [
|
|
457
|
+
{ label: "año", seconds: 31536000, plural: "años" },
|
|
458
|
+
{ label: "mes", seconds: 2592000, plural: "meses" },
|
|
459
|
+
{ label: "semana", seconds: 604800, plural: "semanas" },
|
|
460
|
+
{ label: "día", seconds: 86400, plural: "días" },
|
|
461
|
+
{ label: "hora", seconds: 3600, plural: "horas" },
|
|
462
|
+
{ label: "minuto", seconds: 60, plural: "minutos" },
|
|
463
|
+
{ label: "segundo", seconds: 1, plural: "segundos" },
|
|
464
|
+
],
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
const lang = intervals[locale] || intervals.en;
|
|
468
|
+
for (const interval of lang) {
|
|
469
|
+
const count = Math.floor(diff / interval.seconds);
|
|
470
|
+
if (count >= 1) {
|
|
471
|
+
const label = count > 1 ? interval.plural : interval.label;
|
|
472
|
+
if (locale === "es") return `hace ${count} ${label}`;
|
|
473
|
+
return `${count} ${label} ago`;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return locale === "es" ? "ahora mismo" : "just now";
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
// ========== WAIT ==========
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Returns a promise that resolves after `ms` milliseconds.
|
|
483
|
+
* @param {number} ms - Milliseconds to wait.
|
|
484
|
+
* @returns {Promise<void>}
|
|
485
|
+
*/
|
|
486
|
+
export const waitFor = (ms) =>
|
|
487
|
+
new Promise((resolve) => setTimeout(resolve, ms));
|
|
488
|
+
|
|
489
|
+
/** Alias for {@link waitFor}. */
|
|
490
|
+
export const wait = waitFor;
|
|
491
|
+
|
|
492
|
+
/** Alias for {@link waitFor}. */
|
|
493
|
+
export const sleep = waitFor;
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Polls `condition` every `interval` ms until it returns truthy or `timeout` ms elapse.
|
|
497
|
+
*
|
|
498
|
+
* @param {Function} condition - Zero-argument predicate to evaluate each interval.
|
|
499
|
+
* @param {number} [timeout] - Maximum wait time in ms (default: 30 seconds).
|
|
500
|
+
* @param {number} [interval] - Polling interval in ms (default: 1 second).
|
|
501
|
+
* @returns {Promise<true>} Resolves `true` when the condition is met.
|
|
502
|
+
* @throws {Error} Throws if the timeout is reached before the condition is satisfied.
|
|
503
|
+
*/
|
|
504
|
+
export const waitUntil = async (
|
|
505
|
+
condition,
|
|
506
|
+
timeout = seconds(30),
|
|
507
|
+
interval = seconds(1),
|
|
508
|
+
) => {
|
|
509
|
+
const startTime = now();
|
|
510
|
+
while (now() - startTime < timeout) {
|
|
511
|
+
if (condition()) return true;
|
|
512
|
+
await waitFor(interval);
|
|
513
|
+
}
|
|
514
|
+
throw new Error(`Timeout waiting for condition after ${timeout}ms`);
|
|
515
|
+
};
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Polls the DOM for a CSS selector until the element appears or the timeout elapses.
|
|
519
|
+
*
|
|
520
|
+
* @param {string} selector - CSS selector to look for.
|
|
521
|
+
* @param {number} [timeout] - Maximum wait time in ms (default: 10 seconds).
|
|
522
|
+
* @param {number} [interval] - Polling interval in ms (default: 0.5 seconds).
|
|
523
|
+
* @returns {Promise<Element>} Resolves with the found DOM element.
|
|
524
|
+
* @throws {Error} Throws if the element is not found within the timeout.
|
|
525
|
+
*/
|
|
526
|
+
export const waitForElement = async (
|
|
527
|
+
selector,
|
|
528
|
+
timeout = seconds(10),
|
|
529
|
+
interval = seconds(0.5),
|
|
530
|
+
) => {
|
|
531
|
+
const startTime = now();
|
|
532
|
+
while (now() - startTime < timeout) {
|
|
533
|
+
const element = document.querySelector(selector);
|
|
534
|
+
if (element) return element;
|
|
535
|
+
await waitFor(interval);
|
|
536
|
+
}
|
|
537
|
+
throw new Error(`Element not found: ${selector}`);
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
// ========== TIMER ==========
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Creates a named performance timer. Call `stop()` to log and retrieve the elapsed time,
|
|
544
|
+
* or `elapsed()` to read it without logging.
|
|
545
|
+
*
|
|
546
|
+
* @param {string} label - Label printed with the elapsed time when `stop()` is called.
|
|
547
|
+
* @returns {{ stop: Function, elapsed: Function }}
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* const t = timer("fetchUsers");
|
|
551
|
+
* await fetchUsers();
|
|
552
|
+
* t.stop(); // logs "⏱️ fetchUsers: 142ms"
|
|
553
|
+
*/
|
|
554
|
+
export const timer = (label) => {
|
|
555
|
+
const start = now();
|
|
556
|
+
return {
|
|
557
|
+
stop: () => {
|
|
558
|
+
const elapsed = now() - start;
|
|
559
|
+
console.log(`⏱️ ${label}: ${elapsed}ms`);
|
|
560
|
+
return elapsed;
|
|
561
|
+
},
|
|
562
|
+
elapsed: () => now() - start,
|
|
563
|
+
};
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
// ========== INTERVAL ==========
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Calls `callback` repeatedly every `ms` milliseconds.
|
|
570
|
+
* Returns the interval ID so it can be cancelled with `clearInterval`.
|
|
571
|
+
*
|
|
572
|
+
* @param {number} ms - Interval duration in milliseconds.
|
|
573
|
+
* @param {Function} callback - Function to call on each tick.
|
|
574
|
+
* @returns {number} Interval ID.
|
|
575
|
+
*/
|
|
576
|
+
export const every = (ms, callback) => setInterval(callback, ms);
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Calls `callback` once per second.
|
|
580
|
+
* @param {Function} callback - Function to call each second.
|
|
581
|
+
* @returns {number} Interval ID.
|
|
582
|
+
*/
|
|
583
|
+
export const everySecond = (callback) => every(seconds(1), callback);
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Calls `callback` once per minute.
|
|
587
|
+
* @param {Function} callback - Function to call each minute.
|
|
588
|
+
* @returns {number} Interval ID.
|
|
589
|
+
*/
|
|
590
|
+
export const everyMinute = (callback) => every(minutes(1), callback);
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Calls `callback` once per hour.
|
|
594
|
+
* @param {Function} callback - Function to call each hour.
|
|
595
|
+
* @returns {number} Interval ID.
|
|
596
|
+
*/
|
|
597
|
+
export const everyHour = (callback) => every(hours(1), callback);
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Calls `callback` once per day.
|
|
601
|
+
* @param {Function} callback - Function to call each day.
|
|
602
|
+
* @returns {number} Interval ID.
|
|
603
|
+
*/
|
|
604
|
+
export const everyDay = (callback) => every(days(1), callback);
|
|
605
|
+
|
|
606
|
+
// ========== EXPORT ==========
|
|
607
|
+
export default {
|
|
608
|
+
// Units
|
|
609
|
+
seconds,
|
|
610
|
+
minutes,
|
|
611
|
+
hours,
|
|
612
|
+
days,
|
|
613
|
+
weeks,
|
|
614
|
+
months,
|
|
615
|
+
years,
|
|
616
|
+
|
|
617
|
+
// Current
|
|
618
|
+
now,
|
|
619
|
+
today,
|
|
620
|
+
yesterday,
|
|
621
|
+
tomorrow,
|
|
622
|
+
|
|
623
|
+
// Info
|
|
624
|
+
dayOfWeek,
|
|
625
|
+
monthName,
|
|
626
|
+
isToday,
|
|
627
|
+
isYesterday,
|
|
628
|
+
isTomorrow,
|
|
629
|
+
isWeekend,
|
|
630
|
+
isLeapYear,
|
|
631
|
+
|
|
632
|
+
// Format
|
|
633
|
+
formatDate,
|
|
634
|
+
formatDateLong,
|
|
635
|
+
formatDateShort,
|
|
636
|
+
formatTime,
|
|
637
|
+
formatTimeAmPm,
|
|
638
|
+
|
|
639
|
+
// Parse
|
|
640
|
+
parseDate,
|
|
641
|
+
|
|
642
|
+
// Diff
|
|
643
|
+
dateDiff,
|
|
644
|
+
|
|
645
|
+
// Manipulate
|
|
646
|
+
addDays,
|
|
647
|
+
addHours,
|
|
648
|
+
addMinutes,
|
|
649
|
+
addSeconds,
|
|
650
|
+
subtractDays,
|
|
651
|
+
subtractHours,
|
|
652
|
+
subtractMinutes,
|
|
653
|
+
subtractSeconds,
|
|
654
|
+
|
|
655
|
+
// Relative
|
|
656
|
+
timeAgo,
|
|
657
|
+
relativeTime,
|
|
658
|
+
timeAgoLocale,
|
|
659
|
+
|
|
660
|
+
// Wait
|
|
661
|
+
waitFor,
|
|
662
|
+
wait,
|
|
663
|
+
sleep,
|
|
664
|
+
waitUntil,
|
|
665
|
+
waitForElement,
|
|
666
|
+
|
|
667
|
+
// Timer & Interval
|
|
668
|
+
timer,
|
|
669
|
+
every,
|
|
670
|
+
everySecond,
|
|
671
|
+
everyMinute,
|
|
672
|
+
everyHour,
|
|
673
|
+
everyDay,
|
|
674
|
+
};
|