nexus-shared 1.1.20 → 2.0.0

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 (332) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +903 -0
  3. package/dist/Client.Index.d.ts +44 -0
  4. package/dist/Client.Index.js +49 -0
  5. package/dist/Components/Documents/Button.d.ts +29 -0
  6. package/dist/Components/Documents/Button.js +11 -0
  7. package/dist/Components/Documents/Menu.d.ts +102 -0
  8. package/dist/Components/Documents/Menu.js +238 -0
  9. package/dist/Components/Documents/SplitButton.d.ts +64 -0
  10. package/dist/Components/Documents/SplitButton.js +127 -0
  11. package/dist/Components/Documents/TabButtons.d.ts +62 -0
  12. package/dist/Components/Documents/TabButtons.js +19 -0
  13. package/dist/Components/Forms/ApiForm.d.ts +21 -0
  14. package/dist/Components/Forms/ApiForm.js +99 -0
  15. package/dist/Components/Forms/Crud.d.ts +17 -0
  16. package/dist/Components/Forms/Crud.js +556 -0
  17. package/dist/Components/Forms/CrudParts.d.ts +15 -0
  18. package/dist/Components/Forms/CrudParts.js +36 -0
  19. package/dist/Components/Forms/Form.d.ts +52 -0
  20. package/dist/Components/Forms/Form.js +319 -0
  21. package/dist/Components/Forms/SubmitForm.d.ts +65 -0
  22. package/dist/Components/Forms/SubmitForm.js +198 -0
  23. package/dist/Components/Inputs/Calendar.d.ts +69 -0
  24. package/dist/Components/Inputs/Calendar.js +258 -0
  25. package/dist/Components/Inputs/CheckBox.d.ts +53 -0
  26. package/dist/Components/Inputs/CheckBox.js +87 -0
  27. package/dist/Components/Inputs/CheckBoxGroup.d.ts +20 -0
  28. package/dist/Components/Inputs/CheckBoxGroup.js +80 -0
  29. package/dist/Components/Inputs/ChoiceField.d.ts +122 -0
  30. package/dist/Components/Inputs/ChoiceField.js +169 -0
  31. package/dist/Components/Inputs/DatePicker.d.ts +54 -0
  32. package/dist/Components/Inputs/DatePicker.js +246 -0
  33. package/dist/Components/Inputs/DateRangePicker.d.ts +62 -0
  34. package/dist/Components/Inputs/DateRangePicker.js +283 -0
  35. package/dist/Components/Inputs/DateTimePicker.d.ts +75 -0
  36. package/dist/Components/Inputs/DateTimePicker.js +399 -0
  37. package/dist/Components/Inputs/Dropdown.d.ts +117 -0
  38. package/dist/Components/Inputs/Dropdown.js +839 -0
  39. package/dist/Components/Inputs/DropdownParts.d.ts +84 -0
  40. package/dist/Components/Inputs/DropdownParts.js +102 -0
  41. package/dist/Components/Inputs/EditorShell.d.ts +45 -0
  42. package/dist/Components/Inputs/EditorShell.js +214 -0
  43. package/dist/Components/Inputs/Field.d.ts +53 -0
  44. package/dist/Components/Inputs/Field.js +16 -0
  45. package/dist/Components/Inputs/GroupForm.d.ts +20 -0
  46. package/dist/Components/Inputs/GroupForm.js +170 -0
  47. package/dist/Components/Inputs/InputField.d.ts +59 -0
  48. package/dist/Components/Inputs/InputField.js +169 -0
  49. package/dist/Components/Inputs/InputRenderer.d.ts +35 -0
  50. package/dist/Components/Inputs/InputRenderer.js +99 -0
  51. package/dist/Components/Inputs/MarkdownEditor.d.ts +67 -0
  52. package/dist/Components/Inputs/MarkdownEditor.js +289 -0
  53. package/dist/Components/Inputs/NumberBox.d.ts +53 -0
  54. package/dist/Components/Inputs/NumberBox.js +228 -0
  55. package/dist/Components/Inputs/RadioGroup.d.ts +20 -0
  56. package/dist/Components/Inputs/RadioGroup.js +43 -0
  57. package/dist/Components/Inputs/ReadOnlyNotice.d.ts +36 -0
  58. package/dist/Components/Inputs/ReadOnlyNotice.js +116 -0
  59. package/dist/Components/Inputs/RichTextEditor.d.ts +103 -0
  60. package/dist/Components/Inputs/RichTextEditor.js +1170 -0
  61. package/dist/Components/Inputs/RichTextParts.d.ts +63 -0
  62. package/dist/Components/Inputs/RichTextParts.js +157 -0
  63. package/dist/Components/Inputs/RowsInput.d.ts +104 -0
  64. package/dist/Components/Inputs/RowsInput.js +259 -0
  65. package/dist/Components/Inputs/Slider.d.ts +87 -0
  66. package/dist/Components/Inputs/Slider.js +216 -0
  67. package/dist/Components/Inputs/TabularForm.d.ts +23 -0
  68. package/dist/Components/Inputs/TabularForm.js +283 -0
  69. package/dist/Components/Inputs/TextArea.d.ts +43 -0
  70. package/dist/Components/Inputs/TextArea.js +31 -0
  71. package/dist/Components/Inputs/TextBox.d.ts +52 -0
  72. package/dist/Components/Inputs/TextBox.js +58 -0
  73. package/dist/Components/Inputs/TextField.d.ts +31 -0
  74. package/dist/Components/Inputs/TextField.js +35 -0
  75. package/dist/Components/Inputs/TimePanel.d.ts +34 -0
  76. package/dist/Components/Inputs/TimePanel.js +288 -0
  77. package/dist/Components/Inputs/TimePicker.d.ts +54 -0
  78. package/dist/Components/Inputs/TimePicker.js +239 -0
  79. package/dist/Components/Inputs/TreeView.d.ts +160 -0
  80. package/dist/Components/Inputs/TreeView.js +947 -0
  81. package/dist/Components/Layouts/MessageBox.d.ts +71 -0
  82. package/dist/Components/Layouts/MessageBox.js +104 -0
  83. package/dist/Components/Layouts/Popup.d.ts +92 -0
  84. package/dist/Components/Layouts/Popup.js +376 -0
  85. package/dist/Components/Layouts/PopupContext.d.ts +2 -0
  86. package/dist/Components/Layouts/PopupContext.js +4 -0
  87. package/dist/Components/Layouts/PopupDock.d.ts +22 -0
  88. package/dist/Components/Layouts/PopupDock.js +121 -0
  89. package/dist/Components/Layouts/PopupHost.d.ts +56 -0
  90. package/dist/Components/Layouts/PopupHost.js +163 -0
  91. package/dist/Components/Layouts/PopupRules.d.ts +30 -0
  92. package/dist/Components/Layouts/PopupRules.js +63 -0
  93. package/dist/Components/Layouts/ThemePicker.d.ts +13 -0
  94. package/dist/Components/Layouts/ThemePicker.js +22 -0
  95. package/dist/Components/Layouts/ThemeScript.d.ts +14 -0
  96. package/dist/Components/Layouts/ThemeScript.js +13 -0
  97. package/dist/Components/Layouts/ThemeSwitcher.d.ts +13 -0
  98. package/dist/Components/Layouts/ThemeSwitcher.js +29 -0
  99. package/dist/Components/Layouts/Toaster.d.ts +76 -0
  100. package/dist/Components/Layouts/Toaster.js +172 -0
  101. package/dist/Components/Viewers/DataTable.d.ts +25 -0
  102. package/dist/Components/Viewers/DataTable.js +542 -0
  103. package/dist/Components/Viewers/DataTableParts.d.ts +134 -0
  104. package/dist/Components/Viewers/DataTableParts.js +145 -0
  105. package/dist/Components/Viewers/MarkdownView.d.ts +26 -0
  106. package/dist/Components/Viewers/MarkdownView.js +79 -0
  107. package/dist/Components/Viewers/RichTextView.d.ts +18 -0
  108. package/dist/Components/Viewers/RichTextView.js +17 -0
  109. package/dist/Helpers/AnimationHelpers.d.ts +6 -0
  110. package/dist/Helpers/AnimationHelpers.js +35 -0
  111. package/dist/Helpers/ApiClient.d.ts +74 -0
  112. package/dist/Helpers/ApiClient.js +197 -0
  113. package/dist/Helpers/ApiFormHelpers.d.ts +26 -0
  114. package/dist/Helpers/ApiFormHelpers.js +56 -0
  115. package/dist/Helpers/ApiModules.d.ts +135 -0
  116. package/dist/Helpers/ApiModules.js +194 -0
  117. package/dist/Helpers/ApiResponses.d.ts +41 -0
  118. package/dist/Helpers/ApiResponses.js +159 -0
  119. package/dist/Helpers/ApiRoutes.d.ts +150 -0
  120. package/dist/Helpers/ApiRoutes.js +191 -0
  121. package/dist/Helpers/ApiToasts.d.ts +21 -0
  122. package/dist/Helpers/ApiToasts.js +22 -0
  123. package/dist/Helpers/ClassHelpers.d.ts +3 -0
  124. package/dist/Helpers/ClassHelpers.js +4 -0
  125. package/dist/Helpers/CrudBackend.d.ts +56 -0
  126. package/dist/Helpers/CrudBackend.js +119 -0
  127. package/dist/Helpers/CrudHelpers.d.ts +76 -0
  128. package/dist/Helpers/CrudHelpers.js +202 -0
  129. package/dist/Helpers/DateHelpers.d.ts +88 -0
  130. package/dist/Helpers/DateHelpers.js +363 -0
  131. package/dist/Helpers/DatePreferences.d.ts +14 -0
  132. package/dist/Helpers/DatePreferences.js +94 -0
  133. package/dist/Helpers/DateTimeHelpers.d.ts +87 -0
  134. package/dist/Helpers/DateTimeHelpers.js +286 -0
  135. package/dist/Helpers/DragHelpers.d.ts +129 -0
  136. package/dist/Helpers/DragHelpers.js +281 -0
  137. package/dist/Helpers/DropdownHelpers.d.ts +56 -0
  138. package/dist/Helpers/DropdownHelpers.js +180 -0
  139. package/dist/Helpers/FormDrafts.d.ts +18 -0
  140. package/dist/Helpers/FormDrafts.js +76 -0
  141. package/dist/Helpers/FormStore.d.ts +231 -0
  142. package/dist/Helpers/FormStore.js +734 -0
  143. package/dist/Helpers/InputParamsHelpers.d.ts +79 -0
  144. package/dist/Helpers/InputParamsHelpers.js +388 -0
  145. package/dist/Helpers/MarkdownEditing.d.ts +27 -0
  146. package/dist/Helpers/MarkdownEditing.js +250 -0
  147. package/dist/Helpers/MarkdownHelpers.d.ts +82 -0
  148. package/dist/Helpers/MarkdownHelpers.js +775 -0
  149. package/dist/Helpers/MessageBuilder.d.ts +74 -0
  150. package/dist/Helpers/MessageBuilder.js +254 -0
  151. package/dist/Helpers/NepaliCalendar.d.ts +25 -0
  152. package/dist/Helpers/NepaliCalendar.js +107 -0
  153. package/dist/Helpers/NumberHelpers.d.ts +71 -0
  154. package/dist/Helpers/NumberHelpers.js +202 -0
  155. package/dist/Helpers/Permissions.d.ts +62 -0
  156. package/dist/Helpers/Permissions.js +133 -0
  157. package/dist/Helpers/PopoverHelpers.d.ts +43 -0
  158. package/dist/Helpers/PopoverHelpers.js +91 -0
  159. package/dist/Helpers/RichTextHelpers.d.ts +77 -0
  160. package/dist/Helpers/RichTextHelpers.js +1072 -0
  161. package/dist/Helpers/RowsStore.d.ts +160 -0
  162. package/dist/Helpers/RowsStore.js +584 -0
  163. package/dist/Helpers/TableColumns.d.ts +40 -0
  164. package/dist/Helpers/TableColumns.js +254 -0
  165. package/dist/Helpers/TableExport.d.ts +30 -0
  166. package/dist/Helpers/TableExport.js +97 -0
  167. package/dist/Helpers/TableHelpers.d.ts +102 -0
  168. package/dist/Helpers/TableHelpers.js +281 -0
  169. package/dist/Helpers/TableStore.d.ts +142 -0
  170. package/dist/Helpers/TableStore.js +530 -0
  171. package/dist/Helpers/ThemeHelpers.d.ts +15 -0
  172. package/dist/Helpers/ThemeHelpers.js +16 -0
  173. package/dist/Helpers/TimeHelpers.d.ts +73 -0
  174. package/dist/Helpers/TimeHelpers.js +253 -0
  175. package/dist/Helpers/TreeStore.d.ts +188 -0
  176. package/dist/Helpers/TreeStore.js +577 -0
  177. package/dist/Helpers/ValidationHelpers.d.ts +124 -0
  178. package/dist/Helpers/ValidationHelpers.js +301 -0
  179. package/dist/Interfaces/ApiInterfaces.d.ts +149 -0
  180. package/dist/Interfaces/ApiInterfaces.js +24 -0
  181. package/dist/Interfaces/CrudInterfaces.d.ts +171 -0
  182. package/{src/sso-client.tsx → dist/Interfaces/CrudInterfaces.js} +1 -1
  183. package/dist/Interfaces/DateInterfaces.d.ts +154 -0
  184. package/dist/Interfaces/DateInterfaces.js +29 -0
  185. package/dist/Interfaces/FormInterfaces.d.ts +352 -0
  186. package/dist/Interfaces/FormInterfaces.js +1 -0
  187. package/dist/Interfaces/InputInterfaces.d.ts +141 -0
  188. package/dist/Interfaces/InputInterfaces.js +1 -0
  189. package/dist/Interfaces/MessageInterfaces.d.ts +111 -0
  190. package/dist/Interfaces/MessageInterfaces.js +5 -0
  191. package/dist/Interfaces/TableInterfaces.d.ts +291 -0
  192. package/dist/Interfaces/TableInterfaces.js +1 -0
  193. package/dist/Interfaces/ThemeInterfaces.d.ts +17 -0
  194. package/dist/Interfaces/ThemeInterfaces.js +17 -0
  195. package/dist/Interfaces/TypeInterfaces.d.ts +4 -0
  196. package/dist/Interfaces/TypeInterfaces.js +1 -0
  197. package/dist/Server.Index.d.ts +2 -0
  198. package/dist/Server.Index.js +5 -0
  199. package/dist/Services/ApiProxy.d.ts +32 -0
  200. package/dist/Services/ApiProxy.js +111 -0
  201. package/dist/Services/BrowserApi.d.ts +78 -0
  202. package/dist/Services/BrowserApi.js +111 -0
  203. package/dist/Services/ServerApi.d.ts +49 -0
  204. package/dist/Services/ServerApi.js +75 -0
  205. package/dist/Services/ThemeService.d.ts +17 -0
  206. package/dist/Services/ThemeService.js +83 -0
  207. package/dist/Shared.Index.d.ts +43 -0
  208. package/dist/Shared.Index.js +47 -0
  209. package/package.json +82 -33
  210. package/src/Styles/Nexus.Base.css +70 -0
  211. package/src/Styles/Nexus.Button.css +151 -0
  212. package/src/Styles/Nexus.Calendar.css +275 -0
  213. package/src/Styles/Nexus.Choice.css +345 -0
  214. package/src/Styles/Nexus.Crud.css +84 -0
  215. package/src/Styles/Nexus.DateTime.css +81 -0
  216. package/src/Styles/Nexus.Dropdown.css +774 -0
  217. package/src/Styles/Nexus.Editor.css +297 -0
  218. package/src/Styles/Nexus.Form.css +298 -0
  219. package/src/Styles/Nexus.Index.css +34 -0
  220. package/src/Styles/Nexus.Input.css +637 -0
  221. package/src/Styles/Nexus.Markdown.css +265 -0
  222. package/src/Styles/Nexus.Menu.css +249 -0
  223. package/src/Styles/Nexus.Popup.css +731 -0
  224. package/src/Styles/Nexus.RichText.css +463 -0
  225. package/src/Styles/Nexus.Rows.css +566 -0
  226. package/src/Styles/Nexus.Slider.css +278 -0
  227. package/src/Styles/Nexus.Tab.Buttons.css +364 -0
  228. package/src/Styles/Nexus.Table.css +1014 -0
  229. package/src/Styles/Nexus.Theme.Picker.css +159 -0
  230. package/src/Styles/Nexus.Themes.css +194 -0
  231. package/src/Styles/Nexus.Time.css +147 -0
  232. package/src/Styles/Nexus.Toast.css +265 -0
  233. package/src/Styles/Nexus.Tokens.css +72 -0
  234. package/src/Styles/Nexus.Tree.css +435 -0
  235. package/src/api-services/authentication-service.tsx +0 -23
  236. package/src/api-services/preference-service.tsx +0 -5
  237. package/src/api-services/system-service.tsx +0 -34
  238. package/src/client.ts +0 -31
  239. package/src/components/documents/button.tsx +0 -142
  240. package/src/components/documents/icon-box.tsx +0 -93
  241. package/src/components/documents/page-title.tsx +0 -7
  242. package/src/components/documents/tab-button.tsx +0 -172
  243. package/src/components/documents/tag.tsx +0 -30
  244. package/src/components/index.js +0 -0
  245. package/src/components/inputs/checkbox-input.tsx +0 -66
  246. package/src/components/inputs/input-box.tsx +0 -48
  247. package/src/components/inputs/input-element.tsx +0 -65
  248. package/src/components/inputs/input-form.tsx +0 -164
  249. package/src/components/inputs/input.tsx +0 -181
  250. package/src/components/inputs/number-input.tsx +0 -108
  251. package/src/components/inputs/radiobox-input.tsx +0 -53
  252. package/src/components/inputs/textarea-input.tsx +0 -47
  253. package/src/components/inputs/textbox-input.tsx +0 -45
  254. package/src/components/layouts/global-dialogbox.tsx +0 -431
  255. package/src/components/layouts/global-layout.tsx +0 -59
  256. package/src/components/layouts/layout-helpers.tsx +0 -20
  257. package/src/components/layouts/panels/user-panel.tsx +0 -112
  258. package/src/components/layouts/utility-menu.tsx +0 -49
  259. package/src/components/panels/theme-panel.tsx +0 -46
  260. package/src/helpers/bitwise-helpers.tsx +0 -11
  261. package/src/helpers/browser-helpers.tsx +0 -156
  262. package/src/helpers/datasource-helpers.tsx +0 -99
  263. package/src/helpers/element-helpers.tsx +0 -57
  264. package/src/helpers/input-helpers.tsx +0 -74
  265. package/src/helpers/string-helpers.tsx +0 -28
  266. package/src/helpers/utility-helpers.tsx +0 -45
  267. package/src/helpers/validation-helpers.tsx +0 -302
  268. package/src/index.ts +0 -26
  269. package/src/interface.ts +0 -19
  270. package/src/interfaces/auth-token-interfaces.tsx +0 -6
  271. package/src/interfaces/browser-interfaces.tsx +0 -36
  272. package/src/interfaces/button-interfaces.tsx +0 -63
  273. package/src/interfaces/datasource-interfaces.tsx +0 -22
  274. package/src/interfaces/datatable-interfaces.tsx +0 -25
  275. package/src/interfaces/dialogbox-interfaces.tsx +0 -5
  276. package/src/interfaces/exception-interfaces.tsx +0 -99
  277. package/src/interfaces/http-interfaces.tsx +0 -129
  278. package/src/interfaces/icon-interfaces.tsx +0 -129
  279. package/src/interfaces/input-interfaces.tsx +0 -410
  280. package/src/interfaces/layout-interfaces.tsx +0 -191
  281. package/src/interfaces/menu-interfaces.tsx +0 -49
  282. package/src/interfaces/message-interfaces.tsx +0 -32
  283. package/src/interfaces/permission-interfaces.tsx +0 -9
  284. package/src/interfaces/storage-interfaces.tsx +0 -5
  285. package/src/interfaces/system-interfaces.tsx +0 -22
  286. package/src/interfaces/theme-interfaces.tsx +0 -123
  287. package/src/interfaces/type-interfaces.tsx +0 -28
  288. package/src/interfaces/user-interfaces.tsx +0 -47
  289. package/src/nexus-client.tsx +0 -21
  290. package/src/nexus.environments.tsx +0 -66
  291. package/src/proxy-api/proxy-backend.tsx +0 -60
  292. package/src/proxy-api/proxy-constants.tsx +0 -28
  293. package/src/proxy-api/proxy-helpers.tsx +0 -91
  294. package/src/proxy-api-client.tsx +0 -1
  295. package/src/proxy-api-server.tsx +0 -2
  296. package/src/services/http-client-services.tsx +0 -75
  297. package/src/services/http-services.tsx +0 -158
  298. package/src/services/loader-service.tsx +0 -185
  299. package/src/services/localstorage-service.tsx +0 -119
  300. package/src/services/message-services.tsx +0 -383
  301. package/src/services/theme-service.tsx +0 -161
  302. package/src/services/user-services.tsx +0 -10
  303. package/src/sso-config/auth-token-validation.ts +0 -16
  304. package/src/sso-config/callback-route.tsx +0 -35
  305. package/src/sso-config/cookie-encryption.ts +0 -51
  306. package/src/sso-config/cookie-helpers.tsx +0 -102
  307. package/src/sso-config/forgot-password-route.tsx +0 -36
  308. package/src/sso-config/oauth-callback-state.ts +0 -61
  309. package/src/sso-config/pkce-helpers.ts +0 -9
  310. package/src/sso-config/provider-complete-route.tsx +0 -18
  311. package/src/sso-config/redirect-context-actions.tsx +0 -45
  312. package/src/sso-config/redirect-context-helpers.tsx +0 -159
  313. package/src/sso-config/redirect-context-persist.tsx +0 -18
  314. package/src/sso-config/redirect-context-route.tsx +0 -45
  315. package/src/sso-config/refresh-route.tsx +0 -23
  316. package/src/sso-config/sign-in-route.tsx +0 -74
  317. package/src/sso-config/sign-out-route.tsx +0 -57
  318. package/src/sso-config/sign-up-route.tsx +0 -57
  319. package/src/sso-config/sso-backend-flow.ts +0 -38
  320. package/src/sso-config/sso-complete-route.tsx +0 -50
  321. package/src/sso-config/sso-config.ts +0 -59
  322. package/src/sso-config/sso-interfaces.tsx +0 -99
  323. package/src/sso-config/sso-response-helpers.tsx +0 -20
  324. package/src/sso-server.tsx +0 -21
  325. package/src/styles/nexus.animation.css +0 -269
  326. package/src/styles/nexus.core.css +0 -119
  327. package/src/styles/nexus.dialog.css +0 -144
  328. package/src/styles/nexus.icon.css +0 -51
  329. package/src/styles/nexus.input.css +0 -207
  330. package/src/styles/nexus.loader.css +0 -11
  331. package/src/styles/nexus.logic.css +0 -47
  332. package/src/styles/nexus.utility.css +0 -347
@@ -0,0 +1,286 @@
1
+ import { DEFAULT_DATE_PREFERENCES } from "../Interfaces/DateInterfaces.js";
2
+ import { dayNumberToIsoDate, daysFromCivil, formatDate, isIsoDate, isoDateToDayNumber, parseDateText, partsToIsoDate, toLatinDigits, usesDevanagari } from "./DateHelpers.js";
3
+ import { formatTime, parseTimeText, secondsToIsoTime, timeToSeconds, toIsoTime } from "./TimeHelpers.js";
4
+ /*
5
+ * Pure date-time helpers. A date-time value is a moment, held as a UTC ISO string in the shape `toISOString` writes:
6
+ * "2026-09-17T08:45:00.000Z". It is the same moment on every machine, so a time saved in Kathmandu is still that
7
+ * moment when it is opened in London, and values of this one shape sort as text. People see and pick it as a date and
8
+ * a time of day in a time zone: the browser's by default, or one named by its IANA id ("Asia/Kathmandu",
9
+ * "America/New_York", "UTC"). Intl supplies each zone's offsets and daylight saving rules; the date and the time are
10
+ * then written and read like `formatDate` and `formatTime`.
11
+ */
12
+ const MS_PER_SECOND = 1000;
13
+ const MS_PER_MINUTE = 60_000;
14
+ const MS_PER_DAY = 86_400_000;
15
+ const pad = (value) => String(value).padStart(2, "0");
16
+ /** A UTC date-time as `toISOString` writes it: "2026-09-17T08:45:00.000Z". */
17
+ export const UTC_DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}T([01]\d|2[0-3]):[0-5]\d:[0-5]\d\.\d{3}Z$/;
18
+ /** Whether text is a date-time value in the shape the components give, "2026-09-17T08:45:00.000Z", on a day that exists. */
19
+ export function isUtcDateTime(text) {
20
+ return typeof text === "string" && UTC_DATE_TIME_PATTERN.test(text) && isIsoDate(text.slice(0, 10));
21
+ }
22
+ /** The value of milliseconds since 1970, or `null` outside years 1 to 9999, where ISO strings have four-digit years. */
23
+ function msToUtcDateTime(ms) {
24
+ if (!Number.isFinite(ms))
25
+ return null;
26
+ const date = new Date(ms);
27
+ const year = date.getUTCFullYear();
28
+ return Number.isNaN(date.getTime()) || year < 1 || year > 9999 ? null : date.toISOString();
29
+ }
30
+ /** A wall-clock date and time counted as if it were UTC: the side of a zone's offset that people read. */
31
+ const wallMs = (date, seconds) => isoDateToDayNumber(date) * MS_PER_DAY + seconds * MS_PER_SECOND;
32
+ // Time zones
33
+ const zoneFormatters = new Map();
34
+ const knownZones = new Map();
35
+ let browserZone = null;
36
+ function zoneFormatter(timeZone) {
37
+ let formatter = zoneFormatters.get(timeZone);
38
+ if (!formatter) {
39
+ formatter = new Intl.DateTimeFormat("en-US", { timeZone, hourCycle: "h23", year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric" });
40
+ zoneFormatters.set(timeZone, formatter);
41
+ }
42
+ return formatter;
43
+ }
44
+ /** Milliseconds a zone's clocks are ahead of UTC at a moment: 20,700,000 (+05:45) in Kathmandu. Whole seconds. */
45
+ function zoneOffsetMs(ms, timeZone) {
46
+ const whole = Math.floor(ms / MS_PER_SECOND) * MS_PER_SECOND;
47
+ const parts = {};
48
+ for (const part of zoneFormatter(timeZone).formatToParts(whole))
49
+ parts[part.type] = Number(part.value);
50
+ const { year = 1970, month = 1, day = 1, hour = 0, minute = 0, second = 0 } = parts;
51
+ return daysFromCivil(year, month, day) * MS_PER_DAY + (hour * 3600 + minute * 60 + second) * MS_PER_SECOND - whole;
52
+ }
53
+ // Intl (through CLDR) still names some zones by their old spellings; people read the current IANA ids. Intl accepts both.
54
+ const CURRENT_ZONE_IDS = {
55
+ "Africa/Asmera": "Africa/Asmara",
56
+ "America/Buenos_Aires": "America/Argentina/Buenos_Aires",
57
+ "America/Catamarca": "America/Argentina/Catamarca",
58
+ "America/Coral_Harbour": "America/Atikokan",
59
+ "America/Cordoba": "America/Argentina/Cordoba",
60
+ "America/Godthab": "America/Nuuk",
61
+ "America/Indianapolis": "America/Indiana/Indianapolis",
62
+ "America/Jujuy": "America/Argentina/Jujuy",
63
+ "America/Louisville": "America/Kentucky/Louisville",
64
+ "America/Mendoza": "America/Argentina/Mendoza",
65
+ "Asia/Calcutta": "Asia/Kolkata",
66
+ "Asia/Katmandu": "Asia/Kathmandu",
67
+ "Asia/Rangoon": "Asia/Yangon",
68
+ "Asia/Saigon": "Asia/Ho_Chi_Minh",
69
+ "Atlantic/Faeroe": "Atlantic/Faroe",
70
+ "Europe/Kiev": "Europe/Kyiv",
71
+ "Pacific/Enderbury": "Pacific/Kanton",
72
+ "Pacific/Ponape": "Pacific/Pohnpei",
73
+ "Pacific/Truk": "Pacific/Chuuk",
74
+ };
75
+ const currentZoneId = (id) => CURRENT_ZONE_IDS[id] ?? id;
76
+ /** The browser's time zone as an IANA id, such as "Asia/Kathmandu"; "UTC" where Intl does not tell. Read once. */
77
+ export function getBrowserTimeZone() {
78
+ if (browserZone === null) {
79
+ try {
80
+ browserZone = currentZoneId(new Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC");
81
+ }
82
+ catch {
83
+ browserZone = "UTC";
84
+ }
85
+ }
86
+ return browserZone;
87
+ }
88
+ /** A zone's current IANA id ("asia/katmandu" gives "Asia/Kathmandu"), or `null` for a zone Intl does not know. */
89
+ export function toTimeZone(timeZone) {
90
+ if (!timeZone)
91
+ return null;
92
+ let id = knownZones.get(timeZone);
93
+ if (id === undefined) {
94
+ try {
95
+ id = currentZoneId(new Intl.DateTimeFormat("en-US", { timeZone }).resolvedOptions().timeZone);
96
+ }
97
+ catch {
98
+ id = null;
99
+ }
100
+ knownZones.set(timeZone, id);
101
+ }
102
+ return id;
103
+ }
104
+ /** The zone to show moments in: `timeZone` when Intl knows it, otherwise the browser's. */
105
+ export const resolveTimeZone = (timeZone) => toTimeZone(timeZone) ?? getBrowserTimeZone();
106
+ /** An offset in minutes as "UTC+05:45", "UTC-04:00", or "UTC+00:00". */
107
+ export function formatUtcOffset(minutes) {
108
+ const whole = Math.round(minutes);
109
+ const size = Math.abs(whole);
110
+ return `UTC${whole < 0 ? "-" : "+"}${pad(Math.floor(size / 60))}:${pad(size % 60)}`;
111
+ }
112
+ /** Minutes a zone's clocks are ahead of UTC at a moment (now by default): 345 in Kathmandu, -240 in New York in summer. */
113
+ export function getTimeZoneOffset(timeZone, at = Date.now()) {
114
+ const zone = resolveTimeZone(timeZone);
115
+ return Math.round(zoneOffsetMs(instantMs(at, zone) ?? Date.now(), zone) / MS_PER_MINUTE);
116
+ }
117
+ /** Names a zone (the browser's by default) at a moment (now by default): its id, a city, its offset, and its long name. */
118
+ export function describeTimeZone(timeZone, at = Date.now()) {
119
+ const id = resolveTimeZone(timeZone);
120
+ const ms = instantMs(at, id) ?? Date.now();
121
+ const city = id.slice(id.lastIndexOf("/") + 1).replaceAll("_", " ");
122
+ let name = id;
123
+ try {
124
+ name = new Intl.DateTimeFormat("en-US", { timeZone: id, timeZoneName: "long" }).formatToParts(ms).find(part => part.type === "timeZoneName")?.value ?? id;
125
+ }
126
+ catch {
127
+ // Keeps the id.
128
+ }
129
+ return { id, city, offset: formatUtcOffset(zoneOffsetMs(ms, id) / MS_PER_MINUTE), name };
130
+ }
131
+ // Moments and wall clocks
132
+ /**
133
+ * The moment a wall-clock date and time name in a zone. A time that happens twice, when clocks go back, is the one at
134
+ * `preferredOffset` when that is one of the two, otherwise the first; a time that is skipped, when clocks go forward,
135
+ * moves forward by the gap, so 02:30 on that night is 03:30. `Date` and Temporal resolve both the same way.
136
+ */
137
+ function localToMs(date, seconds, timeZone, preferredOffset = null) {
138
+ const wall = wallMs(date, seconds);
139
+ // The offsets a day before and a day after are the zone's offsets on either side of any change of clocks near this time.
140
+ const before = zoneOffsetMs(wall - MS_PER_DAY, timeZone);
141
+ const after = zoneOffsetMs(wall + MS_PER_DAY, timeZone);
142
+ const early = wall - before;
143
+ if (before === after)
144
+ return early;
145
+ const matches = [early, wall - after].filter(ms => zoneOffsetMs(ms, timeZone) === wall - ms);
146
+ if (preferredOffset !== null && matches.includes(wall - preferredOffset))
147
+ return wall - preferredOffset;
148
+ // Skipped: the offset from before the change carries the time forward, past the gap.
149
+ return matches.length > 0 ? Math.min(...matches) : early;
150
+ }
151
+ // "2026-09-17", "2026-09-17T14:30", "2026-09-17 14:30:15.250", each with an optional "Z" or offset: +05:45, +0545, +05.
152
+ const DATE_TIME_TEXT = /^(\d{4})-(\d{1,2})-(\d{1,2})(?:[T ](\d{1,2}):(\d{2})(?::(\d{2})(?:[.,](\d+))?)?\s*(Z|[+-]\d{2}(?::?\d{2})?)?)?$/i;
153
+ /** Milliseconds since 1970 of anything a moment can arrive as (see `DateTimeInput`), or `null`. */
154
+ function instantMs(input, timeZone) {
155
+ if (input === null || input === undefined || input === "")
156
+ return null;
157
+ if (input instanceof Date)
158
+ return Number.isNaN(input.getTime()) ? null : input.getTime();
159
+ if (typeof input === "number")
160
+ return Number.isFinite(input) ? input : null;
161
+ if (typeof input !== "string")
162
+ return null;
163
+ const match = DATE_TIME_TEXT.exec(input.trim());
164
+ if (!match)
165
+ return null;
166
+ const date = partsToIsoDate({ year: Number(match[1]), month: Number(match[2]), day: Number(match[3]) });
167
+ if (!isIsoDate(date))
168
+ return null;
169
+ // A day alone: its first moment in the zone.
170
+ if (match[4] === undefined)
171
+ return localToMs(date, 0, timeZone);
172
+ const hour = Number(match[4]);
173
+ const minute = Number(match[5]);
174
+ const second = Number(match[6] ?? 0);
175
+ if (hour > 23 || minute > 59 || second > 59)
176
+ return null;
177
+ const wall = wallMs(date, hour * 3600 + minute * 60 + second) + Number((match[7] ?? "").slice(0, 3).padEnd(3, "0"));
178
+ const zone = match[8];
179
+ // No zone: UTC, the way a .NET DateTime saved as UTC often comes back without its "Z".
180
+ if (!zone || zone.toUpperCase() === "Z")
181
+ return wall;
182
+ const digits = zone.slice(1).replace(":", "");
183
+ const offsetHours = Number(digits.slice(0, 2));
184
+ const offsetMinutes = Number(digits.slice(2) || 0);
185
+ if (offsetHours > 23 || offsetMinutes > 59)
186
+ return null;
187
+ return wall - (zone[0] === "-" ? -1 : 1) * (offsetHours * 60 + offsetMinutes) * MS_PER_MINUTE;
188
+ }
189
+ /**
190
+ * Turns anything a moment can arrive as into the value the components hold, a UTC ISO string, or `null`:
191
+ * - "2026-09-17T08:45:00Z" or "2026-09-17T14:30:00+05:45" is that moment: "2026-09-17T08:45:00.000Z";
192
+ * - "2026-09-17T08:45:00", without a zone, is read as UTC (see `DateTimeInput`);
193
+ * - "2026-09-17" is the first moment of that day in `timeZone` (the browser's by default);
194
+ * - a `Date` or milliseconds since 1970 is that moment.
195
+ * Text that is not a date-time, a day that does not exist, or a year past 9999 gives `null`.
196
+ */
197
+ export function toUtcDateTime(input, timeZone) {
198
+ const ms = instantMs(input, resolveTimeZone(timeZone));
199
+ return ms === null ? null : msToUtcDateTime(ms);
200
+ }
201
+ /** Now, as a UTC ISO string. */
202
+ export function nowUtcDateTime() {
203
+ return new Date().toISOString();
204
+ }
205
+ /**
206
+ * The date and the time of day a moment shows in a zone (the browser's by default): "2026-09-17T08:45:00Z" is
207
+ * `{ date: "2026-09-17", time: "14:30:00" }` in Kathmandu. Milliseconds are dropped. `null` for an input that is not a moment.
208
+ */
209
+ export function toLocalDateTime(input, timeZone) {
210
+ const zone = resolveTimeZone(timeZone);
211
+ const ms = instantMs(input, zone);
212
+ if (ms === null || msToUtcDateTime(ms) === null)
213
+ return null;
214
+ const wall = Math.floor(ms / MS_PER_SECOND) * MS_PER_SECOND + zoneOffsetMs(ms, zone);
215
+ const dayNumber = Math.floor(wall / MS_PER_DAY);
216
+ return { date: dayNumberToIsoDate(dayNumber), time: secondsToIsoTime((wall - dayNumber * MS_PER_DAY) / MS_PER_SECOND, true) };
217
+ }
218
+ /**
219
+ * The moment a date and a time of day name in a zone (the browser's by default), as a UTC ISO string:
220
+ * `fromLocalDateTime("2026-09-17", "14:30", "Asia/Kathmandu")` is "2026-09-17T08:45:00.000Z". When clocks go back, a
221
+ * time that happens twice is the first of the two, or, with `reference` (the moment being changed), the one at the
222
+ * reference's offset, so an edit near the second 01:30 stays in the second hour. When clocks go forward, a skipped time
223
+ * moves forward by the gap. `null` when the date or the time is not valid.
224
+ */
225
+ export function fromLocalDateTime(date, time, timeZone, reference) {
226
+ const iso = toIsoTime(time, true);
227
+ if (!isIsoDate(date) || !iso)
228
+ return null;
229
+ const zone = resolveTimeZone(timeZone);
230
+ const referenceMs = instantMs(reference, zone);
231
+ return msToUtcDateTime(localToMs(date, timeToSeconds(iso), zone, referenceMs === null ? null : zoneOffsetMs(referenceMs, zone)));
232
+ }
233
+ /** Today's date in a zone (the browser's by default). */
234
+ export function todayIsoDateIn(timeZone) {
235
+ return toLocalDateTime(Date.now(), timeZone).date;
236
+ }
237
+ /** The script of a date-time's time: Devanagari digits when its date is Nepali in Devanagari, as `DatePicker` and `TimePicker` agree. */
238
+ export const timeScriptOf = (options) => usesDevanagari(options.calendar ?? DEFAULT_DATE_PREFERENCES.calendar, options.script) ? "devanagari" : "latin";
239
+ /**
240
+ * Writes a moment as the date and the time it shows in a zone, in the date and time formats: "2026-09-17 02:30 PM"
241
+ * for "2026-09-17T08:45:00Z" in Kathmandu with the default settings, "२०८३-०६-०१ ०२:३० अपराह्न" in the Nepali calendar
242
+ * in Devanagari. Returns "" for an empty or invalid input.
243
+ */
244
+ export function formatDateTime(input, options = {}) {
245
+ const local = toLocalDateTime(input, options.timeZone);
246
+ if (!local)
247
+ return "";
248
+ return `${formatDate(local.date, options)} ${formatTime(local.time, { format: options.timeFormat, script: timeScriptOf(options), seconds: options.seconds })}`;
249
+ }
250
+ // Words that may stand between a typed date and its time: "Sep 17, 2026 at 2:30 PM".
251
+ const DATE_TIME_JOINER = /(?:[\s,]+(?:at|@))?[\s,]*$/i;
252
+ /**
253
+ * Reads a date and time the user typed as the wall clock they name: the date as `parseDateText` reads it in the
254
+ * calendar and format, then a time of day as `parseTimeText` reads it, on either clock. "17/09/2026 2:30 pm",
255
+ * "2026-09-17T14:30", "Sep 17, 2026 at 14:30", and "२०८३-०६-०१ ०२:३० अपराह्न" all work. The time has seconds
256
+ * ("14:30:00"); a date typed without a time gives `time: null`. Returns `null` for text that is not a date.
257
+ */
258
+ export function parseLocalDateTimeText(text, options = {}) {
259
+ const clean = toLatinDigits(text).trim().replace(/(\d)T(\d)/i, "$1 $2");
260
+ if (!clean)
261
+ return null;
262
+ const words = clean.split(/\s+/);
263
+ // The time is the last word or two ("14:30", "2:30 pm"); the date is what stands before it.
264
+ for (let cut = words.length - 1; cut >= Math.max(1, words.length - 2); cut--) {
265
+ const time = parseTimeText(words.slice(cut).join(" "), { seconds: true });
266
+ if (!time)
267
+ continue;
268
+ const date = parseDateText(words.slice(0, cut).join(" ").replace(DATE_TIME_JOINER, ""), options);
269
+ if (date)
270
+ return { date, time };
271
+ }
272
+ const date = parseDateText(clean, options);
273
+ return date ? { date, time: null } : null;
274
+ }
275
+ /**
276
+ * Reads a date and time the user typed (see `parseLocalDateTimeText`) as the moment it names in `options.timeZone`,
277
+ * a UTC ISO string. With `seconds: false`, typed seconds are dropped. A date typed without a time takes
278
+ * `defaultTime`, when there is one. Returns `null` for text that is not a date and time.
279
+ */
280
+ export function parseDateTimeText(text, options = {}) {
281
+ const local = parseLocalDateTimeText(text, options);
282
+ const time = local?.time ?? toIsoTime(options.defaultTime, true);
283
+ if (!local || !time)
284
+ return null;
285
+ return fromLocalDateTime(local.date, options.seconds === false ? time.slice(0, 5) : time, options.timeZone);
286
+ }
@@ -0,0 +1,129 @@
1
+ import { type RefObject } from "react";
2
+ /** A box in viewport pixels. */
3
+ export interface BoundsRect {
4
+ left: number;
5
+ top: number;
6
+ width: number;
7
+ height: number;
8
+ }
9
+ /** A point, or an offset, in pixels. */
10
+ export interface DragPoint {
11
+ x: number;
12
+ y: number;
13
+ }
14
+ /**
15
+ * Where a dragged element may go: `viewport` (the browser window), `parent` (inside the borders of the element its
16
+ * position is measured from, else its parent), an element (inside its borders), a fixed box, a function returning a
17
+ * box when the drag starts, or `null` for anywhere.
18
+ */
19
+ export type DragBounds = "viewport" | "parent" | Element | BoundsRect | (() => BoundsRect | null) | null;
20
+ export interface ClampOptions {
21
+ /** Space kept from the edges of the bounds, in pixels. Default 0. */
22
+ margin?: number;
23
+ /**
24
+ * How many pixels of the box must stay inside. Leave it out to keep the whole box inside; a box larger than the bounds
25
+ * then lines up with their top and left edges, so a window's title bar stays reachable.
26
+ */
27
+ keepVisible?: number;
28
+ }
29
+ /** Reads and writes a target's position: an offset in pixels from where the layout puts it. */
30
+ export interface DragPosition {
31
+ get: () => DragPoint;
32
+ set: (point: DragPoint) => void;
33
+ }
34
+ /** What a drag callback receives. */
35
+ export interface DragState {
36
+ /** The target being moved. */
37
+ target: HTMLElement;
38
+ /** The pointer where the press started, in viewport pixels. */
39
+ start: DragPoint;
40
+ /** The pointer now, in viewport pixels. */
41
+ pointer: DragPoint;
42
+ /** The target's position: an offset from its place in the layout. */
43
+ position: DragPoint;
44
+ /** How far the target has moved since the drag started, after the bounds. */
45
+ delta: DragPoint;
46
+ }
47
+ export interface DragOptions extends ClampOptions {
48
+ /** Where the target may go. Default `viewport`; `null` lets it go anywhere. */
49
+ bounds?: DragBounds;
50
+ /** Move along one axis only. Default `both`. */
51
+ axis?: "x" | "y" | "both";
52
+ /** How far the pointer must travel before the target moves, in pixels, so a click or a double-click stays one. Default 3. */
53
+ threshold?: number;
54
+ /** Reads and writes the position. Default: the target's CSS `translate` property (`translatePosition`). */
55
+ position?: DragPosition;
56
+ /**
57
+ * When the pointer has passed the threshold, before the target moves. Return `false` to cancel the drag. It may change
58
+ * the target first (restore a maximized window, for example); the position and the bounds are read after it.
59
+ */
60
+ onStart?: (state: DragState) => void | false;
61
+ /** On every move, after the position is written. */
62
+ onMove?: (state: DragState) => void;
63
+ /** When the drag ends; `cancelled` is true when Esc put the target back where it started. */
64
+ onEnd?: (state: DragState, cancelled: boolean) => void;
65
+ }
66
+ export interface StartDragOptions extends DragOptions {
67
+ /** The element that moves. */
68
+ target: HTMLElement;
69
+ /** The element pressed, which keeps the pointer while dragging. Default: the event's current target, else the target. In React, pass `event.currentTarget`. */
70
+ handle?: Element;
71
+ }
72
+ export interface DraggableOptions extends DragOptions {
73
+ /** The element that moves. Default: the handle itself. `null` (a ref not set yet) starts no drag. */
74
+ target?: HTMLElement | null | (() => HTMLElement | null);
75
+ /** A press on an element matching this selector, inside the handle, does not start a drag. Default: buttons, links, and form controls. */
76
+ cancel?: string;
77
+ /** Whether a press may start a drag now. */
78
+ enabled?: () => boolean;
79
+ }
80
+ /** Controls inside a handle keep their own clicks and text selection. */
81
+ export declare const DRAG_CANCEL_SELECTOR = "button, a[href], input, select, textarea, label, summary, [contenteditable]:not([contenteditable=\"false\"]), [data-nx-no-drag]";
82
+ /** The browser window, without its scrollbars. */
83
+ export declare function viewportBounds(): BoundsRect;
84
+ /** The inside of an element's borders (its padding box), without a scrollbar, in viewport pixels. */
85
+ export declare function elementBounds(element: Element): BoundsRect;
86
+ /** Turns a `DragBounds` into a box, for an element being moved. */
87
+ export declare function resolveBounds(bounds: DragBounds | undefined, element: HTMLElement): BoundsRect | null;
88
+ /**
89
+ * The top-left corner a box must move to, the least distance, to stay inside bounds.
90
+ *
91
+ * @example clampToBounds({ left: -20, top: 40, width: 300, height: 200 }, viewportBounds()) // { x: 0, y: 40 }
92
+ */
93
+ export declare function clampToBounds(box: BoundsRect, bounds: BoundsRect, options?: ClampOptions): DragPoint;
94
+ /** The default position: the element's inline CSS `translate`, in pixels. */
95
+ export declare function translatePosition(element: HTMLElement): DragPosition;
96
+ /** A position kept in two CSS variables on the element, for a stylesheet that places it with them (and can ignore them, e.g. when maximized). */
97
+ export declare function cssVariablePosition(element: HTMLElement, xVariable: string, yVariable: string): DragPosition;
98
+ /**
99
+ * Moves an element by an offset, kept inside bounds, and returns its new position. With no offset it pulls an element
100
+ * back inside, e.g. after the window got smaller or the element grew. Also the way to move an element from the keyboard.
101
+ */
102
+ export declare function moveWithin(element: HTMLElement, by: DragPoint, options?: Omit<DragOptions, "threshold" | "onStart" | "onMove" | "onEnd">): DragPoint;
103
+ /**
104
+ * Starts dragging `target` from a `pointerdown` event, e.g. in a React `onPointerDown` on a title bar. The target
105
+ * follows the pointer once it has moved past the threshold, stays inside the bounds, and goes back where it started on
106
+ * Esc. The handle needs `touch-action: none` in its CSS, or a touch pans the page instead. Returns a function that ends
107
+ * the drag early.
108
+ */
109
+ export declare function startDrag(event: PointerEvent, options: StartDragOptions): () => void;
110
+ /**
111
+ * Makes `handle` drag `options.target` (or itself), and returns a function that stops it. Options can be a function,
112
+ * read at every press, so a component can pass its latest props.
113
+ *
114
+ * @example
115
+ * const stop = makeDraggable(card.querySelector(".title"), { target: card, bounds: "parent" });
116
+ */
117
+ export declare function makeDraggable(handle: HTMLElement, options?: DraggableOptions | (() => DraggableOptions)): () => void;
118
+ /**
119
+ * React: the element in `handleRef` drags the target (or itself). The options may change on every render; the latest
120
+ * are used at each press.
121
+ *
122
+ * @example
123
+ * const card = useRef<HTMLDivElement>(null);
124
+ * const title = useRef<HTMLDivElement>(null);
125
+ * useDraggable(title, { target: () => card.current, bounds: "parent" });
126
+ */
127
+ export declare function useDraggable(handleRef: RefObject<HTMLElement | null>, options?: DraggableOptions & {
128
+ disabled?: boolean;
129
+ }): void;