@krizaka/ui 3.0.0 → 3.2.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 (310) hide show
  1. package/README.md +1 -1
  2. package/dist/achievement.js +1 -1
  3. package/dist/action-bar.js +1 -1
  4. package/dist/app-shell.js +1 -1
  5. package/dist/argument-card.js +2 -2
  6. package/dist/card-grid.js +1 -1
  7. package/dist/card.js +1 -1
  8. package/dist/choice-grid.js +1 -1
  9. package/dist/{chunk-OGJI5X4W.js → chunk-2PUDI7JS.js} +2 -2
  10. package/dist/chunk-4LOMIQVX.js +21 -0
  11. package/dist/chunk-4LOMIQVX.js.map +1 -0
  12. package/dist/{chunk-K3SWZXYT.js → chunk-DGQMDJXK.js} +2 -2
  13. package/dist/chunk-G3ETON2A.js +22 -0
  14. package/dist/chunk-G3ETON2A.js.map +1 -0
  15. package/dist/chunk-I5RVM5CW.js +27 -0
  16. package/dist/chunk-I5RVM5CW.js.map +1 -0
  17. package/dist/chunk-IZ7MV6HM.js +26 -0
  18. package/dist/chunk-IZ7MV6HM.js.map +1 -0
  19. package/dist/chunk-ZNMFG62E.js +20 -0
  20. package/dist/chunk-ZNMFG62E.js.map +1 -0
  21. package/dist/cn.d.ts +9 -1
  22. package/dist/cn.js +5 -3
  23. package/dist/code-block.js +1 -1
  24. package/dist/command.js +1 -1
  25. package/dist/confirm-button.js +1 -1
  26. package/dist/continue-prompt.js +1 -1
  27. package/dist/cta-panel.js +1 -1
  28. package/dist/data-table.js +2 -2
  29. package/dist/date-picker.d.ts +650 -61
  30. package/dist/date-picker.js +918 -122
  31. package/dist/date-picker.js.map +1 -1
  32. package/dist/decision-list.js +1 -1
  33. package/dist/dropdown-menu.js +1 -1
  34. package/dist/error-page.js +1 -1
  35. package/dist/field.js +1 -1
  36. package/dist/filter-bar.js +2 -2
  37. package/dist/form/server.d.ts +96 -0
  38. package/dist/form/server.js +82 -0
  39. package/dist/form/server.js.map +1 -0
  40. package/dist/form.d.ts +503 -0
  41. package/dist/form.js +760 -0
  42. package/dist/form.js.map +1 -0
  43. package/dist/gallery-page.js +1 -1
  44. package/dist/glow-card.js +1 -1
  45. package/dist/goal-gauge.js +1 -1
  46. package/dist/how-it-works-page.js +1 -1
  47. package/dist/landscape.js +1 -1
  48. package/dist/link-card.js +1 -1
  49. package/dist/longform-page.js +1 -1
  50. package/dist/marquee.js +1 -1
  51. package/dist/mascot-quote.js +1 -1
  52. package/dist/motion.css +18 -1
  53. package/dist/native/form.d.ts +376 -0
  54. package/dist/native/form.js +650 -0
  55. package/dist/native/form.js.map +1 -0
  56. package/dist/native.d.ts +351 -3
  57. package/dist/native.js +1205 -399
  58. package/dist/native.js.map +1 -1
  59. package/dist/nav-bar.js +1 -1
  60. package/dist/page-hero.js +2 -2
  61. package/dist/page.js +2 -2
  62. package/dist/popover.js +1 -1
  63. package/dist/pricing-page.js +1 -1
  64. package/dist/product-page.js +1 -1
  65. package/dist/profile-card.js +1 -1
  66. package/dist/promise-card.js +1 -1
  67. package/dist/scroll-stage.js +1 -1
  68. package/dist/stage-banner.js +1 -1
  69. package/dist/terminal-replay.js +1 -1
  70. package/dist/toast.js +1 -1
  71. package/dist/toc.js +1 -1
  72. package/dist/tooltip.js +1 -1
  73. package/package.json +50 -7
  74. package/registry/achievement.json +1 -1
  75. package/registry/action-bar.json +1 -1
  76. package/registry/alert.json +1 -1
  77. package/registry/app-shell.json +1 -1
  78. package/registry/argument-card.json +1 -1
  79. package/registry/audio-player.json +1 -1
  80. package/registry/auth-layout.json +1 -1
  81. package/registry/avatar.json +1 -1
  82. package/registry/badge.json +1 -1
  83. package/registry/button.json +1 -1
  84. package/registry/card-grid.json +1 -1
  85. package/registry/card.json +1 -1
  86. package/registry/catalogue-page.json +1 -1
  87. package/registry/changelog-page.json +1 -1
  88. package/registry/checkbox.json +89 -4
  89. package/registry/chip-link.json +1 -1
  90. package/registry/chip.json +1 -1
  91. package/registry/choice-grid.json +1 -1
  92. package/registry/cn.json +1 -1
  93. package/registry/code-block.json +1 -1
  94. package/registry/combobox.json +1 -1
  95. package/registry/command.json +1 -1
  96. package/registry/component-page.json +1 -1
  97. package/registry/confirm-button.json +1 -1
  98. package/registry/contact-page.json +1 -1
  99. package/registry/continue-prompt.json +1 -1
  100. package/registry/countdown.json +1 -1
  101. package/registry/cta-panel.json +1 -1
  102. package/registry/dashboard-layout.json +1 -1
  103. package/registry/data-table.json +1 -1
  104. package/registry/date-picker.json +1811 -236
  105. package/registry/decision-list.json +1 -1
  106. package/registry/detail-layout.json +1 -1
  107. package/registry/dialog.json +1 -1
  108. package/registry/docs-article-page.json +1 -1
  109. package/registry/docs-hub-page.json +1 -1
  110. package/registry/docs-layout.json +1 -1
  111. package/registry/dropdown-menu.json +1 -1
  112. package/registry/empty-state.json +1 -1
  113. package/registry/error-page.json +1 -1
  114. package/registry/examples/checkbox/native/terms.d.ts +4 -0
  115. package/registry/examples/checkbox/native/terms.dark.png +0 -0
  116. package/registry/examples/checkbox/native/terms.js +26 -0
  117. package/registry/examples/checkbox/native/terms.light.png +0 -0
  118. package/registry/examples/checkbox/native/terms.tsx +28 -0
  119. package/registry/examples/date-picker/birth-date-wheel.d.ts +4 -0
  120. package/registry/examples/date-picker/birth-date-wheel.js +13 -0
  121. package/registry/examples/date-picker/birth-date-wheel.tsx +11 -0
  122. package/registry/examples/date-picker/birth-date.d.ts +4 -0
  123. package/registry/examples/date-picker/birth-date.js +25 -0
  124. package/registry/examples/date-picker/birth-date.tsx +21 -0
  125. package/registry/examples/date-picker/calendar.js +1 -1
  126. package/registry/examples/date-picker/calendar.tsx +2 -6
  127. package/registry/examples/date-picker/day-strip.d.ts +4 -0
  128. package/registry/examples/date-picker/day-strip.js +28 -0
  129. package/registry/examples/date-picker/day-strip.tsx +27 -0
  130. package/registry/examples/date-picker/month-year.d.ts +4 -0
  131. package/registry/examples/date-picker/month-year.js +13 -0
  132. package/registry/examples/date-picker/month-year.tsx +10 -0
  133. package/registry/examples/date-picker/native/birth-date-wheel.d.ts +4 -0
  134. package/registry/examples/date-picker/native/birth-date-wheel.dark.png +0 -0
  135. package/registry/examples/date-picker/native/birth-date-wheel.js +13 -0
  136. package/registry/examples/date-picker/native/birth-date-wheel.light.png +0 -0
  137. package/registry/examples/date-picker/native/birth-date-wheel.tsx +9 -0
  138. package/registry/examples/date-picker/native/birth-date.d.ts +4 -0
  139. package/registry/examples/date-picker/native/birth-date.dark.png +0 -0
  140. package/registry/examples/date-picker/native/birth-date.js +30 -0
  141. package/registry/examples/date-picker/native/birth-date.light.png +0 -0
  142. package/registry/examples/date-picker/native/birth-date.tsx +27 -0
  143. package/registry/examples/date-picker/native/calendar.d.ts +4 -0
  144. package/registry/examples/date-picker/native/calendar.dark.png +0 -0
  145. package/registry/examples/date-picker/native/calendar.js +13 -0
  146. package/registry/examples/date-picker/native/calendar.light.png +0 -0
  147. package/registry/examples/date-picker/native/calendar.tsx +8 -0
  148. package/registry/examples/date-picker/native/day-strip.d.ts +4 -0
  149. package/registry/examples/date-picker/native/day-strip.dark.png +0 -0
  150. package/registry/examples/date-picker/native/day-strip.js +29 -0
  151. package/registry/examples/date-picker/native/day-strip.light.png +0 -0
  152. package/registry/examples/date-picker/native/day-strip.tsx +26 -0
  153. package/registry/examples/date-picker/native/month-year.d.ts +4 -0
  154. package/registry/examples/date-picker/native/month-year.dark.png +0 -0
  155. package/registry/examples/date-picker/native/month-year.js +13 -0
  156. package/registry/examples/date-picker/native/month-year.light.png +0 -0
  157. package/registry/examples/date-picker/native/month-year.tsx +8 -0
  158. package/registry/examples/date-picker/native/time-slots.d.ts +4 -0
  159. package/registry/examples/date-picker/native/time-slots.dark.png +0 -0
  160. package/registry/examples/date-picker/native/time-slots.js +15 -0
  161. package/registry/examples/date-picker/native/time-slots.light.png +0 -0
  162. package/registry/examples/date-picker/native/time-slots.tsx +15 -0
  163. package/registry/examples/date-picker/native/time-wheel.d.ts +4 -0
  164. package/registry/examples/date-picker/native/time-wheel.dark.png +0 -0
  165. package/registry/examples/date-picker/native/time-wheel.js +13 -0
  166. package/registry/examples/date-picker/native/time-wheel.light.png +0 -0
  167. package/registry/examples/date-picker/native/time-wheel.tsx +8 -0
  168. package/registry/examples/date-picker/time-slots.d.ts +4 -0
  169. package/registry/examples/date-picker/time-slots.js +26 -0
  170. package/registry/examples/date-picker/time-slots.tsx +25 -0
  171. package/registry/examples/date-picker/time-wheel.d.ts +4 -0
  172. package/registry/examples/date-picker/time-wheel.js +13 -0
  173. package/registry/examples/date-picker/time-wheel.tsx +10 -0
  174. package/registry/examples/date-picker/wheel.d.ts +4 -0
  175. package/registry/examples/date-picker/wheel.js +14 -0
  176. package/registry/examples/date-picker/wheel.tsx +16 -0
  177. package/registry/examples/field/native/default.d.ts +4 -0
  178. package/registry/examples/field/native/default.dark.png +0 -0
  179. package/registry/examples/field/native/default.js +29 -0
  180. package/registry/examples/field/native/default.light.png +0 -0
  181. package/registry/examples/field/native/default.tsx +23 -0
  182. package/registry/examples/form/amount.d.ts +4 -0
  183. package/registry/examples/form/amount.js +30 -0
  184. package/registry/examples/form/amount.tsx +36 -0
  185. package/registry/examples/form/audience.d.ts +4 -0
  186. package/registry/examples/form/audience.js +29 -0
  187. package/registry/examples/form/audience.tsx +31 -0
  188. package/registry/examples/form/native/amount.d.ts +4 -0
  189. package/registry/examples/form/native/amount.dark.png +0 -0
  190. package/registry/examples/form/native/amount.js +26 -0
  191. package/registry/examples/form/native/amount.light.png +0 -0
  192. package/registry/examples/form/native/amount.tsx +30 -0
  193. package/registry/examples/form/native/audience.d.ts +4 -0
  194. package/registry/examples/form/native/audience.dark.png +0 -0
  195. package/registry/examples/form/native/audience.js +24 -0
  196. package/registry/examples/form/native/audience.light.png +0 -0
  197. package/registry/examples/form/native/audience.tsx +24 -0
  198. package/registry/examples/form/native/profile.d.ts +4 -0
  199. package/registry/examples/form/native/profile.dark.png +0 -0
  200. package/registry/examples/form/native/profile.js +33 -0
  201. package/registry/examples/form/native/profile.light.png +0 -0
  202. package/registry/examples/form/native/profile.tsx +36 -0
  203. package/registry/examples/form/native/settings.d.ts +4 -0
  204. package/registry/examples/form/native/settings.dark.png +0 -0
  205. package/registry/examples/form/native/settings.js +25 -0
  206. package/registry/examples/form/native/settings.light.png +0 -0
  207. package/registry/examples/form/native/settings.tsx +23 -0
  208. package/registry/examples/form/native/sign-up.d.ts +4 -0
  209. package/registry/examples/form/native/sign-up.dark.png +0 -0
  210. package/registry/examples/form/native/sign-up.js +38 -0
  211. package/registry/examples/form/native/sign-up.light.png +0 -0
  212. package/registry/examples/form/native/sign-up.tsx +34 -0
  213. package/registry/examples/form/native/upload.d.ts +4 -0
  214. package/registry/examples/form/native/upload.dark.png +0 -0
  215. package/registry/examples/form/native/upload.js +23 -0
  216. package/registry/examples/form/native/upload.light.png +0 -0
  217. package/registry/examples/form/native/upload.tsx +22 -0
  218. package/registry/examples/form/profile.d.ts +4 -0
  219. package/registry/examples/form/profile.js +35 -0
  220. package/registry/examples/form/profile.tsx +40 -0
  221. package/registry/examples/form/report.d.ts +4 -0
  222. package/registry/examples/form/report.js +30 -0
  223. package/registry/examples/form/report.tsx +30 -0
  224. package/registry/examples/form/settings.d.ts +4 -0
  225. package/registry/examples/form/settings.js +30 -0
  226. package/registry/examples/form/settings.tsx +31 -0
  227. package/registry/examples/form/sign-up.d.ts +4 -0
  228. package/registry/examples/form/sign-up.js +38 -0
  229. package/registry/examples/form/sign-up.tsx +37 -0
  230. package/registry/examples/form/upload.d.ts +4 -0
  231. package/registry/examples/form/upload.js +32 -0
  232. package/registry/examples/form/upload.tsx +32 -0
  233. package/registry/field.json +104 -4
  234. package/registry/file-upload.json +1 -1
  235. package/registry/filter-bar.json +1 -1
  236. package/registry/form.json +2940 -0
  237. package/registry/gallery-page.json +1 -1
  238. package/registry/glow-card.json +1 -1
  239. package/registry/goal-gauge.json +1 -1
  240. package/registry/how-it-works-page.json +1 -1
  241. package/registry/image-cropper.json +1 -1
  242. package/registry/index.json +43 -10
  243. package/registry/iso.json +1 -1
  244. package/registry/kbd.json +1 -1
  245. package/registry/landing-page.json +1 -1
  246. package/registry/landscape.json +1 -1
  247. package/registry/legal-page.json +1 -1
  248. package/registry/link-card.json +1 -1
  249. package/registry/loader.json +1 -1
  250. package/registry/longform-page.json +1 -1
  251. package/registry/marketing-layout.json +1 -1
  252. package/registry/marquee.json +1 -1
  253. package/registry/mascot-quote.json +1 -1
  254. package/registry/mascot-state.json +2 -2
  255. package/registry/mascots.json +2 -2
  256. package/registry/media-capture.json +1 -1
  257. package/registry/meter.json +1 -1
  258. package/registry/nav-bar.json +1 -1
  259. package/registry/number-ticker.json +1 -1
  260. package/registry/page-header.json +1 -1
  261. package/registry/page-hero.json +1 -1
  262. package/registry/page.json +1 -1
  263. package/registry/pagination.json +1 -1
  264. package/registry/pointer-light.json +1 -1
  265. package/registry/popover.json +1 -1
  266. package/registry/pricing-page.json +1 -1
  267. package/registry/product-page.json +1 -1
  268. package/registry/profile-card.json +1 -1
  269. package/registry/progress.json +1 -1
  270. package/registry/promise-card.json +1 -1
  271. package/registry/radio-group.json +1 -1
  272. package/registry/scroll-stage.json +1 -1
  273. package/registry/search-field.json +1 -1
  274. package/registry/section-backdrop.json +1 -1
  275. package/registry/separator.json +1 -1
  276. package/registry/settings-layout.json +1 -1
  277. package/registry/skeleton.json +1 -1
  278. package/registry/slider.json +1 -1
  279. package/registry/slot.json +1 -1
  280. package/registry/spinner.json +1 -1
  281. package/registry/split-view.json +1 -1
  282. package/registry/stage-banner.json +1 -1
  283. package/registry/stat.json +1 -1
  284. package/registry/status-page.json +1 -1
  285. package/registry/stepper.json +1 -1
  286. package/registry/switch.json +1 -1
  287. package/registry/tabs.json +1 -1
  288. package/registry/tag-input.json +1 -1
  289. package/registry/terminal-replay.json +1 -1
  290. package/registry/theme.json +8 -1
  291. package/registry/toast.json +1 -1
  292. package/registry/toc.json +1 -1
  293. package/registry/tooltip.json +1 -1
  294. package/registry/video-player.json +1 -1
  295. package/registry/video-trimmer.json +1 -1
  296. package/registry/virtual.json +1 -1
  297. package/skills/date-picker/SKILL.md +43 -0
  298. package/skills/form/SKILL.md +44 -0
  299. package/dist/chunk-2USC2YT6.js +0 -17
  300. package/dist/chunk-2USC2YT6.js.map +0 -1
  301. package/dist/chunk-5AXLA4LK.js +0 -13
  302. package/dist/chunk-5AXLA4LK.js.map +0 -1
  303. package/dist/chunk-FJDSLNXK.js +0 -11
  304. package/dist/chunk-FJDSLNXK.js.map +0 -1
  305. package/dist/chunk-KNBYZGSQ.js +0 -11
  306. package/dist/chunk-KNBYZGSQ.js.map +0 -1
  307. package/dist/chunk-VCAAHCHL.js +0 -17
  308. package/dist/chunk-VCAAHCHL.js.map +0 -1
  309. /package/dist/{chunk-OGJI5X4W.js.map → chunk-2PUDI7JS.js.map} +0 -0
  310. /package/dist/{chunk-K3SWZXYT.js.map → chunk-DGQMDJXK.js.map} +0 -0
@@ -0,0 +1,650 @@
1
+ // src/native/form.tsx
2
+ import { Button, Checkbox as CheckboxControl, Chip, DateField as DateFieldControl, ProductMark, Spinner, TextField as TextFieldControl, Txt, useTheme } from "@krizaka/ui/native";
3
+ import * as React2 from "react";
4
+ import { AccessibilityInfo, KeyboardAvoidingView, Platform, Pressable, ScrollView, StyleSheet, Switch as SwitchControl, View } from "react-native";
5
+
6
+ // src/form/core.tsx
7
+ import { useField, useForm, useStore } from "@tanstack/react-form";
8
+ import * as React from "react";
9
+
10
+ // src/form/errors.ts
11
+ var formMessages = {
12
+ required: "This field is required.",
13
+ tooShort: "Use at least {minimum} characters.",
14
+ tooLong: "Use at most {maximum} characters.",
15
+ tooSmall: "Enter {minimum} or more.",
16
+ tooBig: "Enter {maximum} or less.",
17
+ tooFew: "Choose at least {minimum}.",
18
+ tooMany: "Choose at most {maximum}.",
19
+ invalidEmail: "Enter an e-mail address, like name@example.com.",
20
+ invalidUrl: "Enter a web address, like https://example.com.",
21
+ invalidDate: "Enter a real date.",
22
+ invalidNumber: "Enter a number.",
23
+ invalidFormat: "Check the format of this field.",
24
+ invalidChoice: "Choose one of the options.",
25
+ invalid: "Check this field.",
26
+ // The whole form (a server's answer without fields): the codes of @krizaka/query's KrizakaApiError.
27
+ network: "No connection. Check your network and try again.",
28
+ "rate-limited": "Too many tries. Wait a moment and try again.",
29
+ unauthorized: "Your session has ended. Sign in again.",
30
+ forbidden: "You are not allowed to do this.",
31
+ conflict: "This was changed meanwhile. Reload and try again.",
32
+ "validation-failed": "Some fields need your attention.",
33
+ unavailable: "The service is unavailable for a moment. Try again shortly.",
34
+ server: "Something went wrong on our side. Try again."
35
+ };
36
+ var KEY = /^[\w-]+(\.[\w-]+)+$/;
37
+ var fill = (text, values) => values ? text.replace(/\{(\w+)\}/g, (all, name) => values[name] === void 0 ? all : String(values[name])) : text;
38
+ function formMessage(error, i18n = {}) {
39
+ const e = typeof error === "string" ? { key: error } : error;
40
+ const translated = i18n.t?.(e.key, e.values);
41
+ if (translated && translated !== e.key) return translated;
42
+ const code = e.key.slice(e.key.lastIndexOf(".") + 1);
43
+ const fallback = formMessages[code];
44
+ if (e.message && (code === "invalid" || !fallback)) return e.message;
45
+ if (fallback && (e.key.startsWith(`${i18n.prefix ?? "form.errors"}.`) || e.key.startsWith(`${i18n.apiPrefix ?? "apiErrors"}.`))) return fill(fallback, e.values);
46
+ return e.message ?? (KEY.test(e.key) ? fill(fallback ?? formMessages.invalid, e.values) : e.key);
47
+ }
48
+ function pathName(path) {
49
+ let name = "";
50
+ for (const part of path ?? []) {
51
+ const key = typeof part === "object" && part !== null ? part.key : part;
52
+ if (typeof key === "number") name += `[${key}]`;
53
+ else name += name ? `.${String(key)}` : String(key);
54
+ }
55
+ return name;
56
+ }
57
+ var num = (value) => value === void 0 ? void 0 : Number(value);
58
+ function issueError(issue, prefix = "form.errors") {
59
+ if (KEY.test(issue.message)) return { key: issue.message };
60
+ const key = (code, values) => ({ key: `${prefix}.${code}`, ...values ? { values } : {} });
61
+ const collection = issue.origin === "array" || issue.origin === "set";
62
+ switch (issue.code) {
63
+ case "invalid_type":
64
+ return issue.input === void 0 || issue.input === null || issue.input === "" ? key("required") : issue.expected === "number" ? key("invalidNumber") : issue.expected === "date" ? key("invalidDate") : key("invalid");
65
+ case "too_small": {
66
+ const minimum = num(issue.minimum);
67
+ if (issue.origin === "string") return minimum <= 1 ? key("required") : key("tooShort", { minimum });
68
+ if (collection) return minimum <= 1 ? key("required") : key("tooFew", { minimum });
69
+ return key("tooSmall", { minimum });
70
+ }
71
+ case "too_big": {
72
+ const maximum = num(issue.maximum);
73
+ return issue.origin === "string" ? key("tooLong", { maximum }) : collection ? key("tooMany", { maximum }) : key("tooBig", { maximum });
74
+ }
75
+ case "invalid_format":
76
+ if (issue.format === "email") return key("invalidEmail");
77
+ if (issue.format === "url") return key("invalidUrl");
78
+ if (issue.format === "date" || issue.format === "datetime") return key("invalidDate");
79
+ return key("invalidFormat");
80
+ case "invalid_value":
81
+ return issue.input === false || issue.input === void 0 ? key("required") : key("invalidChoice");
82
+ case "invalid_union":
83
+ case "invalid_key":
84
+ case "invalid_element":
85
+ return key("invalidChoice");
86
+ default:
87
+ return key("invalid");
88
+ }
89
+ }
90
+ function issuesToFields(issues, prefix) {
91
+ const fields2 = {};
92
+ for (const issue of issues) {
93
+ const name = pathName(issue.path);
94
+ if (!(name in fields2)) fields2[name] = { ...issueError(issue, prefix), source: "schema" };
95
+ }
96
+ return fields2;
97
+ }
98
+ function isFormProblem(value) {
99
+ return typeof value === "object" && value !== null && ("fields" in value || "code" in value || "status" in value);
100
+ }
101
+ function problemToErrors(problem, i18n = {}, known, codeFields = {}) {
102
+ const prefix = i18n.prefix ?? "form.errors";
103
+ const fields2 = {};
104
+ let unplaced = false;
105
+ const owner = problem.code ? codeFields[problem.code] : void 0;
106
+ if (owner && (!known || known(owner)) && !problem.fields?.[owner]) {
107
+ fields2[owner] = { key: `${prefix}.${problem.code}`, ...problem.detail ? { message: problem.detail } : {}, source: "server" };
108
+ if (!problem.fields || Object.keys(problem.fields).length === 0) return { fields: fields2, form: null };
109
+ }
110
+ for (const [name, refusal] of Object.entries(problem.fields ?? {})) {
111
+ if (known && !known(name)) {
112
+ unplaced = true;
113
+ continue;
114
+ }
115
+ const error = typeof refusal === "string" ? { key: refusal } : "key" in refusal ? refusal : { key: refusal.code ? KEY.test(refusal.code) ? refusal.code : `${prefix}.${refusal.code}` : `${prefix}.invalid`, message: refusal.message };
116
+ fields2[name] = { ...error, source: "server" };
117
+ }
118
+ const placed = Object.keys(fields2).length > 0;
119
+ if (placed && !unplaced) return { fields: fields2, form: null };
120
+ const code = problem.code ?? (problem.status === 0 ? "network" : problem.status && problem.status >= 500 ? "server" : "invalid");
121
+ const retryIn = problem.retryAt ? Math.max(1, Math.ceil((problem.retryAt - Date.now()) / 1e3)) : void 0;
122
+ return {
123
+ fields: fields2,
124
+ form: { key: KEY.test(code) ? code : `${i18n.apiPrefix ?? "apiErrors"}.${code}`, ...problem.detail ? { message: problem.detail } : {}, ...retryIn ? { values: { seconds: retryIn } } : {}, source: "server" }
125
+ };
126
+ }
127
+
128
+ // src/form/core.tsx
129
+ import { jsx } from "react/jsx-runtime";
130
+ var FormContext = React.createContext(null);
131
+ function useFormContext() {
132
+ const ctx = React.useContext(FormContext);
133
+ if (!ctx) throw new Error("A Krizaka form field must be inside its form's `form.Form`.");
134
+ return ctx;
135
+ }
136
+ var run = (schema, value) => schema["~standard"].validate(value);
137
+ function useKrizakaFormCore(definition, options = {}) {
138
+ const i18n = { ...definition.i18n, ...options.i18n };
139
+ const latest = React.useRef({ options, i18n });
140
+ React.useLayoutEffect(() => {
141
+ latest.current = { options, i18n };
142
+ });
143
+ const [error, setError] = React.useState(null);
144
+ const refused = React.useRef(false);
145
+ const api = useForm({
146
+ defaultValues: options.defaultValues ?? definition.defaultValues,
147
+ validators: {
148
+ // Every change: the schema, synchronously (an async refinement waits for the submit). Errors are computed for
149
+ // every field; each field shows its own once the person left it or tried to send.
150
+ onChange: ({ value }) => {
151
+ const result = run(definition.schema, value);
152
+ if (result instanceof Promise || !result.issues?.length) return void 0;
153
+ const fields2 = issuesToFields(result.issues, latest.current.i18n.prefix);
154
+ delete fields2[""];
155
+ return { fields: fields2 };
156
+ }
157
+ },
158
+ onSubmit: async ({ value }) => {
159
+ const parsed = await run(definition.schema, value);
160
+ if (parsed.issues?.length) {
161
+ apply({ fields: issuesToFields(parsed.issues, latest.current.i18n.prefix) });
162
+ return;
163
+ }
164
+ let result;
165
+ try {
166
+ result = await latest.current.options.onSubmit?.(parsed.value);
167
+ } catch (thrown) {
168
+ apply(isFormProblem(thrown) ? thrown : { code: "server" });
169
+ return;
170
+ }
171
+ if (result && typeof result === "object" && "ok" in result && result.ok === false) {
172
+ apply(result.problem);
173
+ return;
174
+ }
175
+ const data = result && typeof result === "object" && "ok" in result ? result.data : result;
176
+ latest.current.options.onSuccess?.(data);
177
+ }
178
+ });
179
+ const known = (name) => name in api.fieldInfo;
180
+ function apply(problem) {
181
+ refused.current = true;
182
+ const { fields: fields2, form } = problemToErrors(problem, latest.current.i18n, known, latest.current.options.codeFields);
183
+ for (const [name, fieldError] of Object.entries(fields2)) {
184
+ api.setFieldMeta(name, (meta) => ({ ...meta, isBlurred: true, errorMap: { ...meta.errorMap, onServer: fieldError } }));
185
+ }
186
+ setError(form);
187
+ }
188
+ const submit = React.useCallback(async () => {
189
+ setError(null);
190
+ refused.current = false;
191
+ for (const name of Object.keys(api.fieldInfo)) {
192
+ if (api.getFieldMeta(name)?.errorMap?.onServer) api.setFieldMeta(name, (meta) => ({ ...meta, errorMap: { ...meta.errorMap, onServer: void 0 } }));
193
+ }
194
+ await api.handleSubmit();
195
+ const state = api.state;
196
+ return !refused.current && state.isSubmitSuccessful && state.isValid && !Object.values(state.fieldMeta).some((meta) => meta?.errorMap?.onServer);
197
+ }, [api]);
198
+ return React.useMemo(() => ({ api, i18n, error, submit }), [api, error, submit, i18n.t, i18n.prefix, i18n.apiPrefix, i18n.locale]);
199
+ }
200
+ var UNCHECKED = /* @__PURE__ */ Symbol("unchecked");
201
+ function useKrizakaField(name, options = {}) {
202
+ const ctx = useFormContext();
203
+ const id = React.useId();
204
+ const [checked, setChecked] = React.useState(UNCHECKED);
205
+ const check = options.validateAsync;
206
+ const field = useField({
207
+ form: ctx.api,
208
+ name,
209
+ ...check ? {
210
+ asyncDebounceMs: options.asyncDebounceMs ?? 350,
211
+ validators: {
212
+ onChangeAsyncDebounceMs: options.asyncDebounceMs ?? 350,
213
+ onChangeAsync: async ({ value: value2, signal }) => {
214
+ const answer = await check(value2, signal);
215
+ if (signal.aborted) return void 0;
216
+ if (!answer) {
217
+ setChecked(value2);
218
+ return void 0;
219
+ }
220
+ setChecked(UNCHECKED);
221
+ const error = typeof answer === "string" ? { key: answer } : answer;
222
+ return { ...error, immediate: true, source: "check" };
223
+ }
224
+ }
225
+ } : {}
226
+ });
227
+ const attempts = useStore(ctx.api.store, (state) => state.submissionAttempts);
228
+ const meta = field.state.meta;
229
+ const map = meta.errorMap;
230
+ const all = [map.onServer, map.onChange, map.onBlur, map.onSubmit, map.onMount].filter(Boolean);
231
+ const first = all[0];
232
+ const detail = typeof first === "string" ? { key: first } : first;
233
+ const visible = detail && (detail.immediate || detail.source === "server" || meta.isBlurred || attempts > 0) ? detail : void 0;
234
+ const value = field.state.value;
235
+ return {
236
+ id,
237
+ name,
238
+ value,
239
+ setValue: (next) => {
240
+ if (map.onServer) ctx.api.setFieldMeta(name, (m) => ({ ...m, errorMap: { ...m.errorMap, onServer: void 0 } }));
241
+ field.handleChange(next);
242
+ },
243
+ onBlur: () => field.handleBlur(),
244
+ error: visible ? formMessage(visible, ctx.i18n) : void 0,
245
+ errorDetail: visible,
246
+ validating: Boolean(meta.isValidating),
247
+ available: Boolean(check) && checked !== UNCHECKED && Object.is(checked, value) && !meta.isValidating && all.length === 0,
248
+ hintId: `${id}-hint`,
249
+ errorId: `${id}-error`,
250
+ locale: ctx.i18n.locale ?? "en",
251
+ api: field
252
+ };
253
+ }
254
+ function useKrizakaFieldArray(name) {
255
+ const ctx = useFormContext();
256
+ const field = useField({ form: ctx.api, name, mode: "array" });
257
+ const attempts = useStore(ctx.api.store, (state) => state.submissionAttempts);
258
+ const map = field.state.meta.errorMap;
259
+ const first = map.onServer ?? map.onChange ?? map.onSubmit;
260
+ return {
261
+ name,
262
+ items: field.state.value ?? [],
263
+ push: (item) => field.pushValue(item),
264
+ remove: (index) => void field.removeValue(index),
265
+ move: (from, to) => field.moveValue(from, to),
266
+ fieldName: (index, key) => `${name}[${index}]${key ? `.${key}` : ""}`,
267
+ error: first && (attempts > 0 || first.source === "server" || field.state.meta.isDirty) ? formMessage(first, ctx.i18n) : void 0
268
+ };
269
+ }
270
+ function useFormValue(name) {
271
+ const ctx = useFormContext();
272
+ return useStore(ctx.api.store, (state) => getPath(state.values, name));
273
+ }
274
+ function useFormStatus() {
275
+ const ctx = useFormContext();
276
+ const submitting = useStore(ctx.api.store, (s) => s.isSubmitting);
277
+ const succeeded = useStore(ctx.api.store, (s) => s.isSubmitSuccessful);
278
+ const attempts = useStore(ctx.api.store, (s) => s.submissionAttempts);
279
+ return { submitting, succeeded: succeeded && !ctx.error, attempts };
280
+ }
281
+ function getPath(source, path) {
282
+ let current = source;
283
+ for (const part of path.replace(/\[(\d+)\]/g, ".$1").split(".")) {
284
+ if (current === null || typeof current !== "object") return void 0;
285
+ current = current[part];
286
+ }
287
+ return current;
288
+ }
289
+ function firstVisibleError(ctx) {
290
+ if (ctx.error) return formMessage(ctx.error, ctx.i18n);
291
+ for (const meta of Object.values(ctx.api.state.fieldMeta)) {
292
+ const error = meta?.errorMap && Object.values(meta.errorMap).find(Boolean);
293
+ if (error) return formMessage(error, ctx.i18n);
294
+ }
295
+ return void 0;
296
+ }
297
+ function makeCreateKrizakaForm(components, Root) {
298
+ return function createKrizakaForm2(definition) {
299
+ function useForm2(options) {
300
+ const ctx = useKrizakaFormCore(definition, options);
301
+ const [store] = React.useState(() => createStore(ctx));
302
+ React.useLayoutEffect(() => store.set(ctx), [store, ctx]);
303
+ const Form = React.useCallback((props) => /* @__PURE__ */ jsx(Bound, { store, Root, props }), [store]);
304
+ return React.useMemo(
305
+ () => ({
306
+ ...components,
307
+ Form,
308
+ submit: ctx.submit,
309
+ reset: (values) => ctx.api.reset(values),
310
+ setValue: (name, value) => ctx.api.setFieldValue(name, value),
311
+ getValues: () => ctx.api.state.values,
312
+ error: ctx.error,
313
+ api: ctx.api
314
+ }),
315
+ [ctx, Form]
316
+ );
317
+ }
318
+ return {
319
+ schema: definition.schema,
320
+ defaultValues: definition.defaultValues,
321
+ useForm: useForm2,
322
+ useFormWithAction: (action, options) => useForm2({ ...options, onSubmit: action })
323
+ };
324
+ };
325
+ }
326
+ function createStore(initial) {
327
+ let value = initial;
328
+ const listeners = /* @__PURE__ */ new Set();
329
+ return {
330
+ get: () => value,
331
+ set: (next) => {
332
+ if (Object.is(next, value)) return;
333
+ value = next;
334
+ listeners.forEach((listener) => listener());
335
+ },
336
+ subscribe: (listener) => {
337
+ listeners.add(listener);
338
+ return () => listeners.delete(listener);
339
+ }
340
+ };
341
+ }
342
+ function Bound({ store, Root, props }) {
343
+ const value = React.useSyncExternalStore(store.subscribe, store.get, store.get);
344
+ return /* @__PURE__ */ jsx(Root, { ...props, value });
345
+ }
346
+
347
+ // src/form/money.ts
348
+ import { currencyDigits } from "@krizaka/intl";
349
+ function decimalSeparator(locale) {
350
+ return new Intl.NumberFormat(locale).formatToParts(1.5).find((p) => p.type === "decimal")?.value ?? ".";
351
+ }
352
+ function currencySymbol(currency, locale) {
353
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).formatToParts(0).find((p) => p.type === "currency")?.value ?? currency;
354
+ }
355
+ function parseMoney(text, currency, locale = "en") {
356
+ const digits = currencyDigits(currency);
357
+ const t = text.replace(/[\s\u00a0\u202f']/g, "");
358
+ if (!t) return void 0;
359
+ const negative = t.startsWith("-");
360
+ const body = negative ? t.slice(1) : t;
361
+ if (!/^[\d.,]+$/.test(body)) return null;
362
+ let int = body;
363
+ let frac = "";
364
+ const last = Math.max(body.lastIndexOf("."), body.lastIndexOf(","));
365
+ if (last >= 0) {
366
+ const tail = body.slice(last + 1);
367
+ if (body[last] === decimalSeparator(locale) || tail.length !== 3) {
368
+ if (tail.length > digits || !/^\d*$/.test(tail)) return null;
369
+ int = body.slice(0, last);
370
+ frac = tail;
371
+ }
372
+ }
373
+ if (!/^(\d*|\d{1,3}([.,]\d{3})+)$/.test(int)) return null;
374
+ int = int.replace(/[.,]/g, "");
375
+ if (!int && !frac) return null;
376
+ const units = BigInt(int || "0") * 10n ** BigInt(digits) + BigInt((frac || "").padEnd(digits, "0") || "0");
377
+ const value = Number(negative ? -units : units);
378
+ return Number.isSafeInteger(value) ? value : null;
379
+ }
380
+ function moneyInputText(minorUnits, currency, locale = "en") {
381
+ if (minorUnits === null || minorUnits === void 0 || !Number.isFinite(minorUnits)) return "";
382
+ const digits = currencyDigits(currency);
383
+ const sign = minorUnits < 0 ? "-" : "";
384
+ const abs = String(Math.abs(Math.trunc(minorUnits))).padStart(digits + 1, "0");
385
+ return digits === 0 ? sign + abs : `${sign}${abs.slice(0, -digits)}${decimalSeparator(locale)}${abs.slice(-digits)}`;
386
+ }
387
+
388
+ // src/date-picker/parts.ts
389
+ function isRealDate(value) {
390
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) return false;
391
+ const date = /* @__PURE__ */ new Date(`${value}T00:00:00Z`);
392
+ return !Number.isNaN(date.getTime()) && date.toISOString().slice(0, 10) === value;
393
+ }
394
+ function latestBirthDate(age, today = /* @__PURE__ */ new Date()) {
395
+ return new Date(Date.UTC(today.getFullYear() - age, today.getMonth(), today.getDate())).toISOString().slice(0, 10);
396
+ }
397
+
398
+ // src/native/form.tsx
399
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
400
+ var ChainContext = React2.createContext(null);
401
+ function useChain(ctx) {
402
+ const entries = React2.useRef([]);
403
+ return React2.useMemo(() => {
404
+ const mark = () => entries.current.forEach((e, i) => e.setLast(i === entries.current.length - 1));
405
+ return {
406
+ register: (entry) => {
407
+ entries.current = [...entries.current.filter((e) => e.key !== entry.key), entry];
408
+ mark();
409
+ return () => {
410
+ entries.current = entries.current.filter((e) => e.key !== entry.key);
411
+ mark();
412
+ };
413
+ },
414
+ next: (key) => {
415
+ const i = entries.current.findIndex((e) => e.key === key);
416
+ const following = entries.current[i + 1];
417
+ if (following) following.focus();
418
+ else void submitAndAnnounce(ctx);
419
+ }
420
+ };
421
+ }, [ctx]);
422
+ }
423
+ function useChained(override) {
424
+ const chain = React2.useContext(ChainContext);
425
+ const key = React2.useId();
426
+ const ref = React2.useRef(null);
427
+ const [last, setLast] = React2.useState(false);
428
+ React2.useLayoutEffect(() => chain?.register({ key, focus: () => ref.current?.focus(), setLast }), [chain, key]);
429
+ if (!chain || override.returnKeyType !== void 0 || override.onSubmitEditing !== void 0) return { inputRef: ref };
430
+ return {
431
+ inputRef: ref,
432
+ returnKeyType: last ? "go" : "next",
433
+ submitBehavior: last ? "blurAndSubmit" : "submit",
434
+ onSubmitEditing: () => chain.next(key)
435
+ };
436
+ }
437
+ async function submitAndAnnounce(ctx) {
438
+ if (await ctx.submit()) return;
439
+ const message = firstVisibleError(ctx);
440
+ if (message) AccessibilityInfo.announceForAccessibility(message);
441
+ }
442
+ function FormRoot({ value, children, style, scroll, "aria-label": label }) {
443
+ const chain = useChain(value);
444
+ const body = scroll ? /* @__PURE__ */ jsx2(KeyboardAvoidingView, { behavior: Platform.OS === "ios" ? "padding" : void 0, style: styles.screen, children: /* @__PURE__ */ jsx2(ScrollView, { role: "form", "aria-label": label, keyboardShouldPersistTaps: "handled", automaticallyAdjustKeyboardInsets: true, keyboardDismissMode: "interactive", contentContainerStyle: [styles.form, style], children }) }) : /* @__PURE__ */ jsx2(View, { role: "form", "aria-label": label, style: [styles.form, style], children });
445
+ return /* @__PURE__ */ jsx2(FormContext.Provider, { value, children: /* @__PURE__ */ jsx2(ChainContext.Provider, { value: chain, children: body }) });
446
+ }
447
+ function Suggestion({ field }) {
448
+ const suggestion = field.errorDetail?.suggestion;
449
+ if (!field.error || !suggestion) return null;
450
+ return /* @__PURE__ */ jsx2(Pressable, { role: "button", onPress: () => field.setValue(suggestion.value), hitSlop: 8, style: styles.suggestion, children: /* @__PURE__ */ jsx2(Txt, { variant: "label", tone: "accent", children: suggestion.label }) });
451
+ }
452
+ function Submit({ label, variant = "primary", brand, style }) {
453
+ const ctx = useFormContext();
454
+ const { submitting } = useFormStatus();
455
+ const mark = submitting && brand ? /* @__PURE__ */ jsx2(ProductMark, { id: brand, size: 18, animated: true }) : void 0;
456
+ return /* @__PURE__ */ jsx2(Button, { label, variant, loading: submitting && !brand, disabled: submitting, "aria-busy": submitting, icon: mark, style, onPress: () => void submitAndAnnounce(ctx) });
457
+ }
458
+ function FormError({ title, style }) {
459
+ const ctx = useFormContext();
460
+ const { theme, radius } = useTheme();
461
+ if (!ctx.error) return null;
462
+ return /* @__PURE__ */ jsxs(View, { role: "alert", "aria-live": "assertive", style: [styles.alert, { borderRadius: radius.lg, borderColor: theme.danger, backgroundColor: theme.dangerSoft }, style], children: [
463
+ title ? /* @__PURE__ */ jsx2(Txt, { variant: "label", children: title }) : null,
464
+ /* @__PURE__ */ jsx2(Txt, { tone: "secondary", children: formMessage(ctx.error, ctx.i18n) })
465
+ ] });
466
+ }
467
+ function TextField({ name, label, hint, disabled, style, transform, validateAsync, asyncDebounceMs, availableHint, checkingLabel = "Checking", ...input }) {
468
+ const f = useKrizakaField(name, { validateAsync, asyncDebounceMs });
469
+ const chained = useChained(input);
470
+ const { theme } = useTheme();
471
+ const end = f.validating ? /* @__PURE__ */ jsx2(Spinner, { size: "sm", label: checkingLabel }) : f.available ? /* @__PURE__ */ jsx2(Txt, { "aria-hidden": true, style: { color: theme.successText }, children: "\u2713" }) : null;
472
+ return /* @__PURE__ */ jsxs(View, { style: [styles.field, style], children: [
473
+ /* @__PURE__ */ jsx2(
474
+ TextFieldControl,
475
+ {
476
+ label,
477
+ hint: f.available && availableHint ? hint ? `${availableHint} \xB7 ${hint}` : availableHint : hint,
478
+ error: f.error,
479
+ disabled,
480
+ value: f.value ?? "",
481
+ onValueChange: (text) => f.setValue(transform ? transform(text) : text),
482
+ onBlur: f.onBlur,
483
+ end,
484
+ ...chained,
485
+ ...input
486
+ }
487
+ ),
488
+ /* @__PURE__ */ jsx2(Suggestion, { field: f })
489
+ ] });
490
+ }
491
+ function TextArea({ name, label, hint, disabled, style, ...input }) {
492
+ const f = useKrizakaField(name);
493
+ return /* @__PURE__ */ jsx2(TextFieldControl, { multiline: true, label, hint, error: f.error, disabled, value: f.value ?? "", onValueChange: (t) => f.setValue(t), onBlur: f.onBlur, style, ...input });
494
+ }
495
+ function Checkbox({ name, label, accessibleLabel, disabled, style }) {
496
+ const f = useKrizakaField(name);
497
+ return /* @__PURE__ */ jsx2(
498
+ CheckboxControl,
499
+ {
500
+ label: accessibleLabel,
501
+ checked: f.value === true,
502
+ onCheckedChange: (c) => {
503
+ f.setValue(c);
504
+ f.onBlur();
505
+ },
506
+ error: f.error,
507
+ disabled,
508
+ style,
509
+ children: label
510
+ }
511
+ );
512
+ }
513
+ function Switch({ name, label, hint, disabled, style }) {
514
+ const f = useKrizakaField(name);
515
+ const { theme } = useTheme();
516
+ return /* @__PURE__ */ jsxs(View, { style: [styles.switchRow, style], children: [
517
+ /* @__PURE__ */ jsxs(View, { style: styles.switchText, children: [
518
+ /* @__PURE__ */ jsx2(Txt, { variant: "label", children: label }),
519
+ f.error ? /* @__PURE__ */ jsx2(Txt, { variant: "caption", tone: "danger", role: "alert", children: f.error }) : hint ? /* @__PURE__ */ jsx2(Txt, { variant: "caption", tone: "secondary", children: hint }) : null
520
+ ] }),
521
+ /* @__PURE__ */ jsx2(
522
+ SwitchControl,
523
+ {
524
+ "aria-label": label,
525
+ accessibilityHint: f.error ?? hint,
526
+ value: f.value === true,
527
+ disabled,
528
+ onValueChange: (on) => {
529
+ f.setValue(on);
530
+ f.onBlur();
531
+ },
532
+ trackColor: { false: theme.surface3, true: theme.accent },
533
+ thumbColor: theme.textOnMedia,
534
+ ...{ activeThumbColor: theme.textOnMedia },
535
+ ios_backgroundColor: theme.surface3
536
+ }
537
+ )
538
+ ] });
539
+ }
540
+ function RadioGroup({ name, label, hint, disabled, style, options, scrollable }) {
541
+ const f = useKrizakaField(name);
542
+ return /* @__PURE__ */ jsxs(View, { style: [styles.field, style], children: [
543
+ /* @__PURE__ */ jsx2(Txt, { variant: "caption", tone: "secondary", style: styles.groupLabel, children: label }),
544
+ /* @__PURE__ */ jsx2(
545
+ Chip.Group,
546
+ {
547
+ type: "single",
548
+ "aria-label": label,
549
+ value: f.value ?? "",
550
+ disabled,
551
+ scrollable,
552
+ onValueChange: (v) => {
553
+ f.setValue(v);
554
+ f.onBlur();
555
+ },
556
+ children: options.map((o) => /* @__PURE__ */ jsx2(Chip, { value: o.value, disabled: o.disabled, children: o.label }, o.value))
557
+ }
558
+ ),
559
+ f.error ? /* @__PURE__ */ jsx2(Txt, { variant: "caption", tone: "danger", role: "alert", children: f.error }) : hint ? /* @__PURE__ */ jsx2(Txt, { variant: "caption", tone: "secondary", children: hint }) : null
560
+ ] });
561
+ }
562
+ function Select(props) {
563
+ return /* @__PURE__ */ jsx2(RadioGroup, { scrollable: props.options.length > 4, ...props });
564
+ }
565
+ function DateField({ name, label, hint, disabled, style, labels, autoComplete }) {
566
+ const f = useKrizakaField(name);
567
+ const chained = useChained({});
568
+ return /* @__PURE__ */ jsx2(DateFieldControl, { ...chained, returnKeyType: chained.returnKeyType, label, hint, error: f.error, disabled, style, labels, autoComplete, locale: f.locale, value: f.value ?? "", onValueChange: (v) => f.setValue(v), onBlur: f.onBlur });
569
+ }
570
+ function Money({ name, label, hint, disabled, style, currency, placeholder }) {
571
+ const f = useKrizakaField(name);
572
+ const [text, setText] = React2.useState(() => moneyInputText(f.value, currency, f.locale));
573
+ const [editing, setEditing] = React2.useState(false);
574
+ const chained = useChained({});
575
+ return /* @__PURE__ */ jsx2(
576
+ TextFieldControl,
577
+ {
578
+ ...chained,
579
+ label,
580
+ hint,
581
+ error: f.error,
582
+ disabled,
583
+ style,
584
+ placeholder,
585
+ keyboardType: "decimal-pad",
586
+ value: editing ? text : moneyInputText(f.value, currency, f.locale),
587
+ end: /* @__PURE__ */ jsx2(Txt, { tone: "secondary", children: currencySymbol(currency, f.locale) }),
588
+ onFocus: () => {
589
+ setText(moneyInputText(f.value, currency, f.locale));
590
+ setEditing(true);
591
+ },
592
+ onValueChange: (next) => {
593
+ setText(next);
594
+ const units = parseMoney(next, currency, f.locale);
595
+ f.setValue(units === void 0 ? null : units === null ? Number.NaN : units);
596
+ },
597
+ onBlur: () => {
598
+ setEditing(false);
599
+ f.onBlur();
600
+ }
601
+ }
602
+ );
603
+ }
604
+ function FormField({ name, validateAsync, asyncDebounceMs, children }) {
605
+ return /* @__PURE__ */ jsx2(Fragment, { children: children(useKrizakaField(name, { validateAsync, asyncDebounceMs })) });
606
+ }
607
+ function FieldArray({ name, children }) {
608
+ return /* @__PURE__ */ jsx2(Fragment, { children: children(useKrizakaFieldArray(name)) });
609
+ }
610
+ function Watch({ name, children }) {
611
+ return /* @__PURE__ */ jsx2(Fragment, { children: children(useFormValue(name)) });
612
+ }
613
+ var fields = { TextField, TextArea, Checkbox, Switch, RadioGroup, Select, DateField, Money, Field: FormField, FieldArray, Watch, Submit, FormError };
614
+ var createKrizakaForm = makeCreateKrizakaForm(fields, FormRoot);
615
+ var styles = StyleSheet.create({
616
+ form: { gap: 16, alignSelf: "stretch" },
617
+ screen: { flex: 1, alignSelf: "stretch" },
618
+ field: { gap: 6, alignSelf: "stretch" },
619
+ suggestion: { alignSelf: "flex-start", minHeight: 32, justifyContent: "center" },
620
+ alert: { borderWidth: 1, padding: 12, gap: 4 },
621
+ switchRow: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", gap: 16, minHeight: 44 },
622
+ switchText: { flex: 1, gap: 2 },
623
+ groupLabel: { fontWeight: "600" }
624
+ });
625
+ export {
626
+ Checkbox,
627
+ DateField,
628
+ FieldArray,
629
+ FormError,
630
+ FormField,
631
+ Money,
632
+ RadioGroup,
633
+ Select,
634
+ Submit,
635
+ Switch,
636
+ TextArea,
637
+ TextField,
638
+ Watch,
639
+ createKrizakaForm,
640
+ formMessage,
641
+ formMessages,
642
+ isRealDate,
643
+ latestBirthDate,
644
+ useFormContext,
645
+ useFormStatus,
646
+ useFormValue,
647
+ useKrizakaField,
648
+ useKrizakaFieldArray
649
+ };
650
+ //# sourceMappingURL=form.js.map