@coffer-org/web-ui 4.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 (387) hide show
  1. package/README.md +87 -0
  2. package/dist/Markdown.d.ts +4 -0
  3. package/dist/Markdown.js +13 -0
  4. package/dist/MarkdownEditor.d.ts +6 -0
  5. package/dist/MarkdownEditor.js +83 -0
  6. package/dist/actions/ActionButton.d.ts +7 -0
  7. package/dist/actions/ActionButton.js +54 -0
  8. package/dist/actions/PopupBody.d.ts +4 -0
  9. package/dist/actions/PopupBody.js +8 -0
  10. package/dist/actions/TemplateHost.d.ts +4 -0
  11. package/dist/actions/TemplateHost.js +36 -0
  12. package/dist/actions/registry.d.ts +20 -0
  13. package/dist/actions/registry.js +9 -0
  14. package/dist/components/ExtendReasonInfo.d.ts +6 -0
  15. package/dist/components/ExtendReasonInfo.js +12 -0
  16. package/dist/components/FavoriteButton.d.ts +8 -0
  17. package/dist/components/FavoriteButton.js +7 -0
  18. package/dist/components/Icon.d.ts +6 -0
  19. package/dist/components/Icon.js +12 -0
  20. package/dist/components/PageBody.d.ts +4 -0
  21. package/dist/components/PageBody.js +4 -0
  22. package/dist/components/RecordInline.d.ts +8 -0
  23. package/dist/components/RecordInline.js +29 -0
  24. package/dist/components/SaveStatus.d.ts +1 -0
  25. package/dist/components/SaveStatus.js +11 -0
  26. package/dist/components/Toolbar.d.ts +5 -0
  27. package/dist/components/Toolbar.js +4 -0
  28. package/dist/components/icons/color.d.ts +2 -0
  29. package/dist/components/icons/color.js +10 -0
  30. package/dist/components/icons/flag.d.ts +2 -0
  31. package/dist/components/icons/flag.js +6 -0
  32. package/dist/components/icons/lucide.d.ts +2 -0
  33. package/dist/components/icons/lucide.js +111 -0
  34. package/dist/components/icons/registry.d.ts +4 -0
  35. package/dist/components/icons/registry.js +22 -0
  36. package/dist/components/icons/simple.d.ts +2 -0
  37. package/dist/components/icons/simple.js +15 -0
  38. package/dist/components/icons/tabler.d.ts +2 -0
  39. package/dist/components/icons/tabler.js +11 -0
  40. package/dist/components/ui/FieldLabel.d.ts +9 -0
  41. package/dist/components/ui/FieldLabel.js +4 -0
  42. package/dist/components/ui/badge.d.ts +9 -0
  43. package/dist/components/ui/badge.js +19 -0
  44. package/dist/components/ui/button.d.ts +11 -0
  45. package/dist/components/ui/button.js +33 -0
  46. package/dist/components/ui/calendar.d.ts +8 -0
  47. package/dist/components/ui/calendar.js +72 -0
  48. package/dist/components/ui/card.d.ts +8 -0
  49. package/dist/components/ui/card.js +16 -0
  50. package/dist/components/ui/checkbox.d.ts +4 -0
  51. package/dist/components/ui/checkbox.js +8 -0
  52. package/dist/components/ui/chip-cls.d.ts +1 -0
  53. package/dist/components/ui/chip-cls.js +1 -0
  54. package/dist/components/ui/combobox.d.ts +24 -0
  55. package/dist/components/ui/combobox.js +58 -0
  56. package/dist/components/ui/confirm.d.ts +10 -0
  57. package/dist/components/ui/confirm.js +37 -0
  58. package/dist/components/ui/date-picker.d.ts +5 -0
  59. package/dist/components/ui/date-picker.js +16 -0
  60. package/dist/components/ui/dialog.d.ts +16 -0
  61. package/dist/components/ui/dialog.js +27 -0
  62. package/dist/components/ui/dropdown-menu.d.ts +15 -0
  63. package/dist/components/ui/dropdown-menu.js +18 -0
  64. package/dist/components/ui/input-group.d.ts +16 -0
  65. package/dist/components/ui/input-group.js +56 -0
  66. package/dist/components/ui/input.d.ts +3 -0
  67. package/dist/components/ui/input.js +6 -0
  68. package/dist/components/ui/label.d.ts +4 -0
  69. package/dist/components/ui/label.js +7 -0
  70. package/dist/components/ui/mask-input.d.ts +61 -0
  71. package/dist/components/ui/mask-input.js +1052 -0
  72. package/dist/components/ui/month-year-picker.d.ts +10 -0
  73. package/dist/components/ui/month-year-picker.js +46 -0
  74. package/dist/components/ui/option-icon.d.ts +15 -0
  75. package/dist/components/ui/option-icon.js +19 -0
  76. package/dist/components/ui/phone-input.d.ts +13 -0
  77. package/dist/components/ui/phone-input.js +53 -0
  78. package/dist/components/ui/popover.d.ts +11 -0
  79. package/dist/components/ui/popover.js +28 -0
  80. package/dist/components/ui/rating.d.ts +44 -0
  81. package/dist/components/ui/rating.js +501 -0
  82. package/dist/components/ui/scroll-area.d.ts +5 -0
  83. package/dist/components/ui/scroll-area.js +11 -0
  84. package/dist/components/ui/select-combobox.d.ts +25 -0
  85. package/dist/components/ui/select-combobox.js +36 -0
  86. package/dist/components/ui/select.d.ts +13 -0
  87. package/dist/components/ui/select.js +24 -0
  88. package/dist/components/ui/separator.d.ts +4 -0
  89. package/dist/components/ui/separator.js +7 -0
  90. package/dist/components/ui/switch.d.ts +4 -0
  91. package/dist/components/ui/switch.js +7 -0
  92. package/dist/components/ui/textarea.d.ts +3 -0
  93. package/dist/components/ui/textarea.js +6 -0
  94. package/dist/components/ui/time-picker.d.ts +84 -0
  95. package/dist/components/ui/time-picker.js +1258 -0
  96. package/dist/components/visually-hidden-input.d.ts +10 -0
  97. package/dist/components/visually-hidden-input.js +96 -0
  98. package/dist/hooks/use-as-ref.d.ts +3 -0
  99. package/dist/hooks/use-as-ref.js +10 -0
  100. package/dist/hooks/use-isomorphic-layout-effect.d.ts +3 -0
  101. package/dist/hooks/use-isomorphic-layout-effect.js +3 -0
  102. package/dist/hooks/use-lazy-ref.d.ts +3 -0
  103. package/dist/hooks/use-lazy-ref.js +9 -0
  104. package/dist/hooks/use-media-query.d.ts +3 -0
  105. package/dist/hooks/use-media-query.js +26 -0
  106. package/dist/host-services.d.ts +47 -0
  107. package/dist/host-services.js +35 -0
  108. package/dist/index.d.ts +70 -0
  109. package/dist/index.js +69 -0
  110. package/dist/layout.d.ts +29 -0
  111. package/dist/layout.js +323 -0
  112. package/dist/lib/cat-color.d.ts +1 -0
  113. package/dist/lib/cat-color.js +7 -0
  114. package/dist/lib/compose-refs.d.ts +5 -0
  115. package/dist/lib/compose-refs.js +38 -0
  116. package/dist/lib/date-format.d.ts +9 -0
  117. package/dist/lib/date-format.js +31 -0
  118. package/dist/lib/format.d.ts +14 -0
  119. package/dist/lib/format.js +34 -0
  120. package/dist/lib/json.d.ts +1 -0
  121. package/dist/lib/json.js +12 -0
  122. package/dist/lib/multi-value.d.ts +3 -0
  123. package/dist/lib/multi-value.js +22 -0
  124. package/dist/lib/record-option.d.ts +7 -0
  125. package/dist/lib/record-option.js +52 -0
  126. package/dist/lib/use-record-labels.d.ts +14 -0
  127. package/dist/lib/use-record-labels.js +130 -0
  128. package/dist/lib/utils.d.ts +2 -0
  129. package/dist/lib/utils.js +5 -0
  130. package/dist/list-view.d.ts +26 -0
  131. package/dist/list-view.js +11 -0
  132. package/dist/markdown/blocks.d.ts +10 -0
  133. package/dist/markdown/blocks.js +57 -0
  134. package/dist/markdown/extensions.d.ts +6 -0
  135. package/dist/markdown/extensions.js +25 -0
  136. package/dist/markdown/slash.d.ts +23 -0
  137. package/dist/markdown/slash.js +27 -0
  138. package/dist/markdown/toolbar.d.ts +13 -0
  139. package/dist/markdown/toolbar.js +119 -0
  140. package/dist/plugin-ui.d.ts +43 -0
  141. package/dist/plugin-ui.js +37 -0
  142. package/dist/registry.d.ts +26 -0
  143. package/dist/registry.js +169 -0
  144. package/dist/render/blocks/accordion.d.ts +1 -0
  145. package/dist/render/blocks/accordion.js +15 -0
  146. package/dist/render/blocks/aside.d.ts +1 -0
  147. package/dist/render/blocks/aside.js +14 -0
  148. package/dist/render/blocks/balance.d.ts +1 -0
  149. package/dist/render/blocks/balance.js +14 -0
  150. package/dist/render/blocks/bento.d.ts +1 -0
  151. package/dist/render/blocks/bento.js +24 -0
  152. package/dist/render/blocks/block-shell.d.ts +15 -0
  153. package/dist/render/blocks/block-shell.js +20 -0
  154. package/dist/render/blocks/calendar.d.ts +1 -0
  155. package/dist/render/blocks/calendar.js +142 -0
  156. package/dist/render/blocks/callout.d.ts +1 -0
  157. package/dist/render/blocks/callout.js +21 -0
  158. package/dist/render/blocks/chart.d.ts +1 -0
  159. package/dist/render/blocks/chart.js +46 -0
  160. package/dist/render/blocks/compare.d.ts +1 -0
  161. package/dist/render/blocks/compare.js +16 -0
  162. package/dist/render/blocks/countdown.d.ts +1 -0
  163. package/dist/render/blocks/countdown.js +36 -0
  164. package/dist/render/blocks/deck.d.ts +1 -0
  165. package/dist/render/blocks/deck.js +29 -0
  166. package/dist/render/blocks/epigraph.d.ts +1 -0
  167. package/dist/render/blocks/epigraph.js +13 -0
  168. package/dist/render/blocks/facets.d.ts +1 -0
  169. package/dist/render/blocks/facets.js +23 -0
  170. package/dist/render/blocks/figure.d.ts +1 -0
  171. package/dist/render/blocks/figure.js +13 -0
  172. package/dist/render/blocks/grid.d.ts +1 -0
  173. package/dist/render/blocks/grid.js +21 -0
  174. package/dist/render/blocks/heatmap.d.ts +1 -0
  175. package/dist/render/blocks/heatmap.js +135 -0
  176. package/dist/render/blocks/idcard.d.ts +1 -0
  177. package/dist/render/blocks/idcard.js +30 -0
  178. package/dist/render/blocks/identity.d.ts +1 -0
  179. package/dist/render/blocks/identity.js +46 -0
  180. package/dist/render/blocks/index.d.ts +40 -0
  181. package/dist/render/blocks/index.js +40 -0
  182. package/dist/render/blocks/journal.d.ts +1 -0
  183. package/dist/render/blocks/journal.js +50 -0
  184. package/dist/render/blocks/ledger.d.ts +1 -0
  185. package/dist/render/blocks/ledger.js +23 -0
  186. package/dist/render/blocks/manifest.d.ts +1 -0
  187. package/dist/render/blocks/manifest.js +50 -0
  188. package/dist/render/blocks/masthead.d.ts +1 -0
  189. package/dist/render/blocks/masthead.js +15 -0
  190. package/dist/render/blocks/meter.d.ts +1 -0
  191. package/dist/render/blocks/meter.js +32 -0
  192. package/dist/render/blocks/nutrition.d.ts +1 -0
  193. package/dist/render/blocks/nutrition.js +27 -0
  194. package/dist/render/blocks/people.d.ts +1 -0
  195. package/dist/render/blocks/people.js +35 -0
  196. package/dist/render/blocks/plaque.d.ts +1 -0
  197. package/dist/render/blocks/plaque.js +15 -0
  198. package/dist/render/blocks/properties.d.ts +1 -0
  199. package/dist/render/blocks/properties.js +22 -0
  200. package/dist/render/blocks/prose.d.ts +1 -0
  201. package/dist/render/blocks/prose.js +17 -0
  202. package/dist/render/blocks/receipt.d.ts +1 -0
  203. package/dist/render/blocks/receipt.js +23 -0
  204. package/dist/render/blocks/registry.d.ts +16 -0
  205. package/dist/render/blocks/registry.js +7 -0
  206. package/dist/render/blocks/relation-source.d.ts +2 -0
  207. package/dist/render/blocks/relation-source.js +6 -0
  208. package/dist/render/blocks/route.d.ts +1 -0
  209. package/dist/render/blocks/route.js +23 -0
  210. package/dist/render/blocks/score.d.ts +1 -0
  211. package/dist/render/blocks/score.js +15 -0
  212. package/dist/render/blocks/series.d.ts +23 -0
  213. package/dist/render/blocks/series.js +57 -0
  214. package/dist/render/blocks/specimen.d.ts +1 -0
  215. package/dist/render/blocks/specimen.js +19 -0
  216. package/dist/render/blocks/split.d.ts +1 -0
  217. package/dist/render/blocks/split.js +15 -0
  218. package/dist/render/blocks/spread.d.ts +1 -0
  219. package/dist/render/blocks/spread.js +15 -0
  220. package/dist/render/blocks/stack.d.ts +1 -0
  221. package/dist/render/blocks/stack.js +15 -0
  222. package/dist/render/blocks/stats.d.ts +1 -0
  223. package/dist/render/blocks/stats.js +23 -0
  224. package/dist/render/blocks/status.d.ts +1 -0
  225. package/dist/render/blocks/status.js +18 -0
  226. package/dist/render/blocks/table.d.ts +11 -0
  227. package/dist/render/blocks/table.js +136 -0
  228. package/dist/render/blocks/tabs.d.ts +1 -0
  229. package/dist/render/blocks/tabs.js +17 -0
  230. package/dist/render/blocks/terminal.d.ts +1 -0
  231. package/dist/render/blocks/terminal.js +18 -0
  232. package/dist/render/blocks/timeline.d.ts +1 -0
  233. package/dist/render/blocks/timeline.js +31 -0
  234. package/dist/render/box.d.ts +5 -0
  235. package/dist/render/box.js +23 -0
  236. package/dist/render/chrome.d.ts +64 -0
  237. package/dist/render/chrome.js +92 -0
  238. package/dist/render/core/amount.d.ts +1 -0
  239. package/dist/render/core/amount.js +19 -0
  240. package/dist/render/core/attachment.d.ts +29 -0
  241. package/dist/render/core/attachment.js +102 -0
  242. package/dist/render/core/choice.d.ts +1 -0
  243. package/dist/render/core/choice.js +40 -0
  244. package/dist/render/core/composite.d.ts +1 -0
  245. package/dist/render/core/composite.js +132 -0
  246. package/dist/render/core/datetime.d.ts +2 -0
  247. package/dist/render/core/datetime.js +215 -0
  248. package/dist/render/core/dimensions.d.ts +1 -0
  249. package/dist/render/core/dimensions.js +44 -0
  250. package/dist/render/core/embed.d.ts +11 -0
  251. package/dist/render/core/embed.js +99 -0
  252. package/dist/render/core/file.d.ts +12 -0
  253. package/dist/render/core/file.js +238 -0
  254. package/dist/render/core/illustrated.d.ts +39 -0
  255. package/dist/render/core/illustrated.js +113 -0
  256. package/dist/render/core/index.d.ts +23 -0
  257. package/dist/render/core/index.js +23 -0
  258. package/dist/render/core/layout-elements.d.ts +1 -0
  259. package/dist/render/core/layout-elements.js +78 -0
  260. package/dist/render/core/localpath.d.ts +6 -0
  261. package/dist/render/core/localpath.js +73 -0
  262. package/dist/render/core/money.d.ts +1 -0
  263. package/dist/render/core/money.js +39 -0
  264. package/dist/render/core/number.d.ts +17 -0
  265. package/dist/render/core/number.js +104 -0
  266. package/dist/render/core/period.d.ts +1 -0
  267. package/dist/render/core/period.js +60 -0
  268. package/dist/render/core/range.d.ts +1 -0
  269. package/dist/render/core/range.js +55 -0
  270. package/dist/render/core/reminder.d.ts +2 -0
  271. package/dist/render/core/reminder.js +56 -0
  272. package/dist/render/core/source.d.ts +3 -0
  273. package/dist/render/core/source.js +65 -0
  274. package/dist/render/core/stepper.d.ts +1 -0
  275. package/dist/render/core/stepper.js +81 -0
  276. package/dist/render/core/storage-group.d.ts +1 -0
  277. package/dist/render/core/storage-group.js +30 -0
  278. package/dist/render/core/text.d.ts +15 -0
  279. package/dist/render/core/text.js +370 -0
  280. package/dist/render/core/tristate.d.ts +1 -0
  281. package/dist/render/core/tristate.js +42 -0
  282. package/dist/render/core/weight.d.ts +4 -0
  283. package/dist/render/core/weight.js +38 -0
  284. package/dist/render/dispatch.d.ts +12 -0
  285. package/dist/render/dispatch.js +53 -0
  286. package/dist/render/display-override.d.ts +25 -0
  287. package/dist/render/display-override.js +23 -0
  288. package/dist/render/editor-mode.d.ts +4 -0
  289. package/dist/render/editor-mode.js +11 -0
  290. package/dist/render/field-address.d.ts +14 -0
  291. package/dist/render/field-address.js +10 -0
  292. package/dist/render/field-errors.d.ts +8 -0
  293. package/dist/render/field-errors.js +25 -0
  294. package/dist/render/field-frame.d.ts +20 -0
  295. package/dist/render/field-frame.js +78 -0
  296. package/dist/render/field-scope.d.ts +8 -0
  297. package/dist/render/field-scope.js +25 -0
  298. package/dist/render/field-width.d.ts +7 -0
  299. package/dist/render/field-width.js +12 -0
  300. package/dist/render/form-types.d.ts +12 -0
  301. package/dist/render/form-types.js +1 -0
  302. package/dist/render/hybrid-scope.d.ts +5 -0
  303. package/dist/render/hybrid-scope.js +9 -0
  304. package/dist/render/image.d.ts +64 -0
  305. package/dist/render/image.js +322 -0
  306. package/dist/render/live-kind.d.ts +7 -0
  307. package/dist/render/live-kind.js +104 -0
  308. package/dist/render/markdown-view.d.ts +5 -0
  309. package/dist/render/markdown-view.js +17 -0
  310. package/dist/render/multi.d.ts +10 -0
  311. package/dist/render/multi.js +26 -0
  312. package/dist/render/multiple-chips.d.ts +24 -0
  313. package/dist/render/multiple-chips.js +18 -0
  314. package/dist/render/option-list.d.ts +15 -0
  315. package/dist/render/option-list.js +47 -0
  316. package/dist/render/option-value.d.ts +20 -0
  317. package/dist/render/option-value.js +41 -0
  318. package/dist/render/picker-scrim.d.ts +7 -0
  319. package/dist/render/picker-scrim.js +32 -0
  320. package/dist/render/picker-surface.d.ts +5 -0
  321. package/dist/render/picker-surface.js +9 -0
  322. package/dist/render/popover-field.d.ts +16 -0
  323. package/dist/render/popover-field.js +153 -0
  324. package/dist/render/record-save-ctx.d.ts +11 -0
  325. package/dist/render/record-save-ctx.js +41 -0
  326. package/dist/render/shared.d.ts +92 -0
  327. package/dist/render/shared.js +182 -0
  328. package/dist/render/slot.d.ts +45 -0
  329. package/dist/render/slot.js +194 -0
  330. package/dist/render/sort-rows.d.ts +3 -0
  331. package/dist/render/sort-rows.js +38 -0
  332. package/dist/render/use-collection-rows.d.ts +10 -0
  333. package/dist/render/use-collection-rows.js +11 -0
  334. package/dist/render/use-field-edit.d.ts +28 -0
  335. package/dist/render/use-field-edit.js +50 -0
  336. package/dist/render/use-file-upload.d.ts +10 -0
  337. package/dist/render/use-file-upload.js +35 -0
  338. package/dist/render/use-form-bridge.d.ts +21 -0
  339. package/dist/render/use-form-bridge.js +53 -0
  340. package/dist/render/use-hybrid.d.ts +2 -0
  341. package/dist/render/use-hybrid.js +5 -0
  342. package/dist/render/widgets/attachment-group.d.ts +1 -0
  343. package/dist/render/widgets/attachment-group.js +35 -0
  344. package/dist/render/widgets/checklist-content.d.ts +15 -0
  345. package/dist/render/widgets/checklist-content.js +12 -0
  346. package/dist/render/widgets/checklist-group.d.ts +11 -0
  347. package/dist/render/widgets/checklist-group.js +47 -0
  348. package/dist/render/widgets/checklist-row.d.ts +14 -0
  349. package/dist/render/widgets/checklist-row.js +14 -0
  350. package/dist/render/widgets/display.d.ts +33 -0
  351. package/dist/render/widgets/display.js +97 -0
  352. package/dist/render/widgets/edit.d.ts +63 -0
  353. package/dist/render/widgets/edit.js +283 -0
  354. package/dist/render/widgets/fixed-collection.d.ts +11 -0
  355. package/dist/render/widgets/fixed-collection.js +34 -0
  356. package/dist/render/widgets/flow-row.d.ts +14 -0
  357. package/dist/render/widgets/flow-row.js +27 -0
  358. package/dist/render/widgets/group-edit.d.ts +9 -0
  359. package/dist/render/widgets/group-edit.js +23 -0
  360. package/dist/render/widgets/group-field.d.ts +9 -0
  361. package/dist/render/widgets/group-field.js +42 -0
  362. package/dist/render/widgets/group-widgets.d.ts +2 -0
  363. package/dist/render/widgets/group-widgets.js +41 -0
  364. package/dist/render/widgets/group.d.ts +26 -0
  365. package/dist/render/widgets/group.js +139 -0
  366. package/dist/render/widgets/illustrated-group.d.ts +1 -0
  367. package/dist/render/widgets/illustrated-group.js +41 -0
  368. package/dist/render/widgets/table-group.d.ts +11 -0
  369. package/dist/render/widgets/table-group.js +58 -0
  370. package/dist/render/widgets/two-cell-group.d.ts +21 -0
  371. package/dist/render/widgets/two-cell-group.js +42 -0
  372. package/dist/render/widgets/url-widget.d.ts +7 -0
  373. package/dist/render/widgets/url-widget.js +15 -0
  374. package/dist/render/widgets/weekday-grid.d.ts +13 -0
  375. package/dist/render/widgets/weekday-grid.js +47 -0
  376. package/dist/render/write.d.ts +5 -0
  377. package/dist/render/write.js +14 -0
  378. package/dist/schema-registry.d.ts +6 -0
  379. package/dist/schema-registry.js +25 -0
  380. package/dist/site-links.d.ts +13 -0
  381. package/dist/site-links.js +18 -0
  382. package/dist/strip-markdown.d.ts +1 -0
  383. package/dist/strip-markdown.js +11 -0
  384. package/dist/theme.css +189 -0
  385. package/dist/types.d.ts +84 -0
  386. package/dist/types.js +1 -0
  387. package/package.json +85 -0
@@ -0,0 +1,1052 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import * as SlotPrimitive from '@radix-ui/react-slot';
4
+ import * as React from 'react';
5
+ import { useComposedRefs } from "../../lib/compose-refs.js";
6
+ import { cn } from "../../lib/utils.js";
7
+ const PAST_YEARS_LIMIT = 120;
8
+ const FUTURE_YEARS_LIMIT = 10;
9
+ const DEFAULT_CURRENCY = 'USD';
10
+ const DEFAULT_LOCALE = 'en-US';
11
+ const NUMERIC_MASK_PATTERNS = /^(phone|zipCode|zipCodeExtended|ssn|ein|time|date|creditCard|creditCardExpiry)$/;
12
+ const CURRENCY_PERCENTAGE_SYMBOLS = /[€$%]/;
13
+ const formattersCache = new Map();
14
+ const currencyAtEndCache = new Map();
15
+ const currencySymbolsCache = new Map();
16
+ const daysInMonthCache = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
17
+ const REGEX_CACHE = {
18
+ digitsOnly: /^\d+$/,
19
+ nonDigits: /\D/g,
20
+ nonAlphaNumeric: /[^A-Z0-9]/gi,
21
+ nonNumericDot: /[^0-9.]/g,
22
+ nonCurrencyChars: /[^\d.,]/g,
23
+ hashPattern: /#/g,
24
+ currencyAtEnd: /\d\s*[^\d\s]+$/,
25
+ percentageChars: /[^\d.]/g,
26
+ phone: /^\d{10}$/,
27
+ ssn: /^\d{9}$/,
28
+ zipCode: /^\d{5}$/,
29
+ zipCodeExtended: /^\d{9}$/,
30
+ isbn: /^\d{13}$/,
31
+ ein: /^\d{9}$/,
32
+ time: /^\d{4}$/,
33
+ creditCard: /^\d{13,19}$/,
34
+ creditCardExpiry: /^\d{4}$/,
35
+ licensePlate: /^[A-Z0-9]{6}$/,
36
+ macAddress: /^[A-F0-9]{12}$/,
37
+ currencyValidation: /^\d+(\.\d{1,2})?$/,
38
+ ipv4Segment: /^\d{1,3}$/,
39
+ };
40
+ function getCachedFormatter(locale, opts) {
41
+ const { currency, minimumFractionDigits = 0, maximumFractionDigits = 2 } = opts;
42
+ const key = `${locale}|${currency}|${minimumFractionDigits}|${maximumFractionDigits}`;
43
+ if (!formattersCache.has(key)) {
44
+ try {
45
+ formattersCache.set(key, new Intl.NumberFormat(locale, {
46
+ style: 'currency',
47
+ currency,
48
+ ...opts,
49
+ }));
50
+ }
51
+ catch {
52
+ formattersCache.set(key, new Intl.NumberFormat(DEFAULT_LOCALE, {
53
+ style: 'currency',
54
+ currency: DEFAULT_CURRENCY,
55
+ ...opts,
56
+ }));
57
+ }
58
+ }
59
+ const formatter = formattersCache.get(key);
60
+ if (!formatter) {
61
+ throw new Error(`Failed to create formatter for ${key}`);
62
+ }
63
+ return formatter;
64
+ }
65
+ function getCachedCurrencySymbols(opts) {
66
+ const { locale, currency } = opts;
67
+ const key = `${locale}|${currency}`;
68
+ const cached = currencySymbolsCache.get(key);
69
+ if (cached) {
70
+ return cached;
71
+ }
72
+ let currencySymbol = '$';
73
+ let decimalSeparator = '.';
74
+ let groupSeparator = ',';
75
+ try {
76
+ const formatter = getCachedFormatter(locale, {
77
+ currency,
78
+ minimumFractionDigits: 0,
79
+ maximumFractionDigits: 2,
80
+ });
81
+ const parts = formatter.formatToParts(1234.5);
82
+ const currencyPart = parts.find((part) => part.type === 'currency');
83
+ const decimalPart = parts.find((part) => part.type === 'decimal');
84
+ const groupPart = parts.find((part) => part.type === 'group');
85
+ if (currencyPart)
86
+ currencySymbol = currencyPart.value;
87
+ if (decimalPart)
88
+ decimalSeparator = decimalPart.value;
89
+ if (groupPart)
90
+ groupSeparator = groupPart.value;
91
+ }
92
+ catch {
93
+ }
94
+ const symbols = {
95
+ currency: currencySymbol,
96
+ decimal: decimalSeparator,
97
+ group: groupSeparator,
98
+ };
99
+ currencySymbolsCache.set(key, symbols);
100
+ return symbols;
101
+ }
102
+ function isCurrencyAtEnd(opts) {
103
+ const { locale, currency } = opts;
104
+ const key = `${locale}|${currency}`;
105
+ const cached = currencyAtEndCache.get(key);
106
+ if (cached !== undefined) {
107
+ return cached;
108
+ }
109
+ try {
110
+ const formatter = getCachedFormatter(locale, {
111
+ currency,
112
+ minimumFractionDigits: 0,
113
+ maximumFractionDigits: 0,
114
+ });
115
+ const sample = formatter.format(123);
116
+ const result = REGEX_CACHE.currencyAtEnd.test(sample);
117
+ currencyAtEndCache.set(key, result);
118
+ return result;
119
+ }
120
+ catch {
121
+ currencyAtEndCache.set(key, false);
122
+ return false;
123
+ }
124
+ }
125
+ function isCurrencyMask(opts) {
126
+ const { mask, pattern } = opts;
127
+ return mask === 'currency' || Boolean(pattern && (pattern.includes('$') || pattern.includes('€')));
128
+ }
129
+ const MASK_PATTERNS = {
130
+ phone: {
131
+ pattern: '(###) ###-####',
132
+ transform: (value) => value.replace(REGEX_CACHE.nonDigits, ''),
133
+ validate: (value) => REGEX_CACHE.phone.test(value.replace(REGEX_CACHE.nonDigits, '')),
134
+ },
135
+ ssn: {
136
+ pattern: '###-##-####',
137
+ transform: (value) => value.replace(REGEX_CACHE.nonDigits, ''),
138
+ validate: (value) => REGEX_CACHE.ssn.test(value.replace(REGEX_CACHE.nonDigits, '')),
139
+ },
140
+ date: {
141
+ pattern: '##/##/####',
142
+ transform: (value) => value.replace(REGEX_CACHE.nonDigits, ''),
143
+ validate: (value) => {
144
+ const cleaned = value.replace(REGEX_CACHE.nonDigits, '');
145
+ if (cleaned.length !== 8)
146
+ return false;
147
+ const month = parseInt(cleaned.substring(0, 2), 10);
148
+ const day = parseInt(cleaned.substring(2, 4), 10);
149
+ const year = parseInt(cleaned.substring(4, 8), 10);
150
+ const currentYear = new Date().getFullYear();
151
+ const minYear = currentYear - PAST_YEARS_LIMIT;
152
+ const maxYear = currentYear + FUTURE_YEARS_LIMIT;
153
+ if (month < 1 || month > 12 || day < 1 || year < minYear || year > maxYear)
154
+ return false;
155
+ const maxDays = month === 2 && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0)
156
+ ? 29
157
+ : (daysInMonthCache[month - 1] ?? 31);
158
+ return day <= maxDays;
159
+ },
160
+ },
161
+ time: {
162
+ pattern: '##:##',
163
+ transform: (value) => value.replace(REGEX_CACHE.nonDigits, ''),
164
+ validate: (value) => {
165
+ const cleaned = value.replace(REGEX_CACHE.nonDigits, '');
166
+ if (!REGEX_CACHE.time.test(cleaned))
167
+ return false;
168
+ const hours = parseInt(cleaned.substring(0, 2), 10);
169
+ const minutes = parseInt(cleaned.substring(2, 4), 10);
170
+ return hours <= 23 && minutes <= 59;
171
+ },
172
+ },
173
+ creditCard: {
174
+ pattern: '#### #### #### ####',
175
+ transform: (value) => value.replace(REGEX_CACHE.nonDigits, ''),
176
+ validate: (value) => {
177
+ const cleaned = value.replace(REGEX_CACHE.nonDigits, '');
178
+ if (!REGEX_CACHE.creditCard.test(cleaned))
179
+ return false;
180
+ let sum = 0;
181
+ let isEven = false;
182
+ for (let i = cleaned.length - 1; i >= 0; i--) {
183
+ const digitChar = cleaned[i];
184
+ if (!digitChar)
185
+ continue;
186
+ let digit = parseInt(digitChar, 10);
187
+ if (isEven) {
188
+ digit *= 2;
189
+ if (digit > 9) {
190
+ digit -= 9;
191
+ }
192
+ }
193
+ sum += digit;
194
+ isEven = !isEven;
195
+ }
196
+ return sum % 10 === 0;
197
+ },
198
+ },
199
+ creditCardExpiry: {
200
+ pattern: '##/##',
201
+ transform: (value) => value.replace(REGEX_CACHE.nonDigits, ''),
202
+ validate: (value) => {
203
+ const cleaned = value.replace(REGEX_CACHE.nonDigits, '');
204
+ if (!REGEX_CACHE.creditCardExpiry.test(cleaned))
205
+ return false;
206
+ const month = parseInt(cleaned.substring(0, 2), 10);
207
+ const year = parseInt(cleaned.substring(2, 4), 10);
208
+ if (month < 1 || month > 12)
209
+ return false;
210
+ const now = new Date();
211
+ const currentYear = now.getFullYear();
212
+ const currentMonth = now.getMonth() + 1;
213
+ const fullYear = year <= 75 ? 2000 + year : 1900 + year;
214
+ if (fullYear < currentYear || (fullYear === currentYear && month < currentMonth)) {
215
+ return false;
216
+ }
217
+ const maxYear = currentYear + 50;
218
+ if (fullYear > maxYear) {
219
+ return false;
220
+ }
221
+ return true;
222
+ },
223
+ },
224
+ zipCode: {
225
+ pattern: '#####',
226
+ transform: (value) => value.replace(REGEX_CACHE.nonDigits, ''),
227
+ validate: (value) => REGEX_CACHE.zipCode.test(value.replace(REGEX_CACHE.nonDigits, '')),
228
+ },
229
+ zipCodeExtended: {
230
+ pattern: '#####-####',
231
+ transform: (value) => value.replace(REGEX_CACHE.nonDigits, ''),
232
+ validate: (value) => REGEX_CACHE.zipCodeExtended.test(value.replace(REGEX_CACHE.nonDigits, '')),
233
+ },
234
+ currency: {
235
+ pattern: '$###,###.##',
236
+ transform: (value, { currency = DEFAULT_CURRENCY, locale = DEFAULT_LOCALE } = {}) => {
237
+ let localeDecimalSeparator = '.';
238
+ try {
239
+ const formatter = getCachedFormatter(locale, {
240
+ currency,
241
+ minimumFractionDigits: 0,
242
+ maximumFractionDigits: 2,
243
+ });
244
+ const parts = formatter.formatToParts(1234.5);
245
+ const decimalPart = parts.find((part) => part.type === 'decimal');
246
+ if (decimalPart)
247
+ localeDecimalSeparator = decimalPart.value;
248
+ }
249
+ catch {
250
+ }
251
+ const cleaned = value.replace(REGEX_CACHE.nonCurrencyChars, '');
252
+ const dotIndex = cleaned.indexOf('.');
253
+ const commaIndex = cleaned.indexOf(',');
254
+ let hasDecimalSeparator = false;
255
+ let decimalIndex = -1;
256
+ if (localeDecimalSeparator === ',') {
257
+ const lastCommaIndex = cleaned.lastIndexOf(',');
258
+ if (lastCommaIndex !== -1) {
259
+ const afterComma = cleaned.substring(lastCommaIndex + 1);
260
+ if (afterComma.length <= 2 && /^\d*$/.test(afterComma)) {
261
+ hasDecimalSeparator = true;
262
+ decimalIndex = lastCommaIndex;
263
+ }
264
+ }
265
+ if (!hasDecimalSeparator && dotIndex !== -1) {
266
+ const afterDot = cleaned.substring(dotIndex + 1);
267
+ if (afterDot.length <= 2 && /^\d*$/.test(afterDot)) {
268
+ hasDecimalSeparator = true;
269
+ decimalIndex = dotIndex;
270
+ }
271
+ }
272
+ if (!hasDecimalSeparator && cleaned.length >= 4) {
273
+ const match = cleaned.match(/^(\d+)\.(\d{3})(\d{1,2})$/);
274
+ if (match) {
275
+ const [, beforeDot, thousandsPart, decimalPart] = match;
276
+ const integerPart = (beforeDot ?? '') + (thousandsPart ?? '');
277
+ const result = `${integerPart}.${decimalPart}`;
278
+ return result;
279
+ }
280
+ }
281
+ }
282
+ else {
283
+ const lastDotIndex = cleaned.lastIndexOf('.');
284
+ if (lastDotIndex !== -1) {
285
+ const afterDot = cleaned.substring(lastDotIndex + 1);
286
+ if (afterDot.length <= 2 && /^\d*$/.test(afterDot)) {
287
+ hasDecimalSeparator = true;
288
+ decimalIndex = lastDotIndex;
289
+ }
290
+ }
291
+ if (!hasDecimalSeparator && commaIndex !== -1) {
292
+ const afterComma = cleaned.substring(commaIndex + 1);
293
+ const looksLikeThousands = commaIndex <= 3 && afterComma.length >= 3;
294
+ if (!looksLikeThousands && afterComma.length <= 2 && /^\d*$/.test(afterComma)) {
295
+ hasDecimalSeparator = true;
296
+ decimalIndex = commaIndex;
297
+ }
298
+ }
299
+ }
300
+ if (hasDecimalSeparator && decimalIndex !== -1) {
301
+ const beforeDecimal = cleaned.substring(0, decimalIndex).replace(/[.,]/g, '');
302
+ const afterDecimal = cleaned.substring(decimalIndex + 1).replace(/[.,]/g, '');
303
+ if (afterDecimal === '') {
304
+ const result = `${beforeDecimal}.`;
305
+ return result;
306
+ }
307
+ const result = `${beforeDecimal}.${afterDecimal.substring(0, 2)}`;
308
+ return result;
309
+ }
310
+ const digitsOnly = cleaned.replace(/[.,]/g, '');
311
+ return digitsOnly;
312
+ },
313
+ validate: (value) => {
314
+ if (!REGEX_CACHE.currencyValidation.test(value))
315
+ return false;
316
+ const num = parseFloat(value);
317
+ return !Number.isNaN(num) && num >= 0;
318
+ },
319
+ },
320
+ percentage: {
321
+ pattern: '##.##%',
322
+ transform: (value) => {
323
+ const cleaned = value.replace(REGEX_CACHE.percentageChars, '');
324
+ const parts = cleaned.split('.');
325
+ if (parts.length > 2) {
326
+ return `${parts[0]}.${parts.slice(1).join('')}`;
327
+ }
328
+ if (parts[1] && parts[1].length > 2) {
329
+ return `${parts[0]}.${parts[1].substring(0, 2)}`;
330
+ }
331
+ return cleaned;
332
+ },
333
+ validate: (value, opts = {}) => {
334
+ const num = parseFloat(value);
335
+ const min = opts.min ?? 0;
336
+ const max = opts.max ?? 100;
337
+ return !Number.isNaN(num) && num >= min && num <= max;
338
+ },
339
+ },
340
+ licensePlate: {
341
+ pattern: '###-###',
342
+ transform: (value) => value.replace(REGEX_CACHE.nonAlphaNumeric, '').toUpperCase(),
343
+ validate: (value) => REGEX_CACHE.licensePlate.test(value),
344
+ },
345
+ ipv4: {
346
+ pattern: '###.###.###.###',
347
+ transform: (value) => value.replace(REGEX_CACHE.nonNumericDot, ''),
348
+ validate: (value) => {
349
+ if (value.includes('.')) {
350
+ const segments = value.split('.');
351
+ if (segments.length > 4)
352
+ return false;
353
+ return segments.every((segment) => {
354
+ if (segment === '')
355
+ return true;
356
+ if (!REGEX_CACHE.ipv4Segment.test(segment))
357
+ return false;
358
+ const num = parseInt(segment, 10);
359
+ return num <= 255;
360
+ });
361
+ }
362
+ else {
363
+ if (!REGEX_CACHE.digitsOnly.test(value))
364
+ return false;
365
+ if (value.length > 12)
366
+ return false;
367
+ const chunks = [];
368
+ for (let i = 0; i < value.length; i += 3) {
369
+ chunks.push(value.substring(i, i + 3));
370
+ }
371
+ if (chunks.length > 4)
372
+ return false;
373
+ return chunks.every((chunk) => {
374
+ const num = parseInt(chunk, 10);
375
+ return num >= 0 && num <= 255;
376
+ });
377
+ }
378
+ },
379
+ },
380
+ macAddress: {
381
+ pattern: '##:##:##:##:##:##',
382
+ transform: (value) => value.replace(REGEX_CACHE.nonAlphaNumeric, '').toUpperCase(),
383
+ validate: (value) => REGEX_CACHE.macAddress.test(value),
384
+ },
385
+ isbn: {
386
+ pattern: '###-#-###-#####-#',
387
+ transform: (value) => value.replace(REGEX_CACHE.nonDigits, ''),
388
+ validate: (value) => REGEX_CACHE.isbn.test(value.replace(REGEX_CACHE.nonDigits, '')),
389
+ },
390
+ ein: {
391
+ pattern: '##-#######',
392
+ transform: (value) => value.replace(REGEX_CACHE.nonDigits, ''),
393
+ validate: (value) => REGEX_CACHE.ein.test(value.replace(REGEX_CACHE.nonDigits, '')),
394
+ },
395
+ };
396
+ function applyMask(opts) {
397
+ const { value, pattern, currency, locale, mask } = opts;
398
+ const cleanValue = value;
399
+ if (pattern.includes('$') || pattern.includes('€') || mask === 'currency') {
400
+ return applyCurrencyMask({
401
+ value: cleanValue,
402
+ currency: currency ?? DEFAULT_CURRENCY,
403
+ locale: locale ?? DEFAULT_LOCALE,
404
+ });
405
+ }
406
+ if (pattern.includes('%')) {
407
+ return applyPercentageMask(cleanValue);
408
+ }
409
+ if (mask === 'ipv4') {
410
+ return cleanValue;
411
+ }
412
+ const maskedChars = [];
413
+ let valueIndex = 0;
414
+ for (let i = 0; i < pattern.length && valueIndex < cleanValue.length; i++) {
415
+ const patternChar = pattern[i];
416
+ const valueChar = cleanValue[valueIndex];
417
+ if (patternChar === '#' && valueChar) {
418
+ maskedChars.push(valueChar);
419
+ valueIndex++;
420
+ }
421
+ else if (patternChar) {
422
+ maskedChars.push(patternChar);
423
+ }
424
+ }
425
+ return maskedChars.join('');
426
+ }
427
+ function applyCurrencyMask(opts) {
428
+ const { value, currency = DEFAULT_CURRENCY, locale = DEFAULT_LOCALE } = opts;
429
+ if (!value)
430
+ return '';
431
+ const { currency: currencySymbol, decimal: decimalSeparator, group: groupSeparator, } = getCachedCurrencySymbols({ locale, currency });
432
+ const normalizedValue = value
433
+ .replace(new RegExp(`\\${groupSeparator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`, 'g'), '')
434
+ .replace(decimalSeparator, '.');
435
+ const parts = normalizedValue.split('.');
436
+ const integerPart = parts[0] ?? '';
437
+ const fractionalPart = parts[1] ?? '';
438
+ if (!integerPart && !fractionalPart)
439
+ return '';
440
+ const intValue = integerPart ?? '0';
441
+ const fracValue = fractionalPart.slice(0, 2);
442
+ const num = Number(`${intValue}.${fracValue ?? ''}`);
443
+ if (Number.isNaN(num)) {
444
+ const cleanedDigits = value.replace(/[^\d]/g, '');
445
+ if (!cleanedDigits)
446
+ return '';
447
+ return `${currencySymbol}${cleanedDigits}`;
448
+ }
449
+ const hasExplicitDecimal = value.includes('.') || value.includes(decimalSeparator);
450
+ try {
451
+ const formatter = getCachedFormatter(locale, {
452
+ currency,
453
+ minimumFractionDigits: fracValue ? fracValue.length : 0,
454
+ maximumFractionDigits: 2,
455
+ });
456
+ const result = formatter.format(num);
457
+ if (hasExplicitDecimal && !fracValue) {
458
+ if (result.match(/^[^\d\s]+/)) {
459
+ const finalResult = result.replace(/(\d)$/, `$1${decimalSeparator}`);
460
+ return finalResult;
461
+ }
462
+ else {
463
+ const finalResult = result.replace(/(\d)(\s*)([^\d\s]+)$/, `$1${decimalSeparator}$2$3`);
464
+ return finalResult;
465
+ }
466
+ }
467
+ return result;
468
+ }
469
+ catch {
470
+ const formattedInt = intValue.replace(/\B(?=(\d{3})+(?!\d))/g, groupSeparator);
471
+ let result = `${currencySymbol}${formattedInt}`;
472
+ if (hasExplicitDecimal) {
473
+ result += `${decimalSeparator}${fracValue}`;
474
+ }
475
+ return result;
476
+ }
477
+ }
478
+ function applyPercentageMask(value) {
479
+ if (!value)
480
+ return '';
481
+ const parts = value.split('.');
482
+ let result = parts[0] ?? '0';
483
+ if (value.includes('.')) {
484
+ result += `.${(parts[1] ?? '').substring(0, 2)}`;
485
+ }
486
+ return `${result}%`;
487
+ }
488
+ function getUnmaskedValue(opts) {
489
+ const { value, transform, currency, locale } = opts;
490
+ return transform ? transform(value, { currency, locale }) : value.replace(REGEX_CACHE.nonDigits, '');
491
+ }
492
+ function toUnmaskedIndex(opts) {
493
+ const { masked, pattern, caret } = opts;
494
+ let idx = 0;
495
+ for (let i = 0; i < caret && i < masked.length && i < pattern.length; i++) {
496
+ if (pattern[i] === '#') {
497
+ idx++;
498
+ }
499
+ }
500
+ return idx;
501
+ }
502
+ function fromUnmaskedIndex(opts) {
503
+ const { masked, pattern, unmaskedIndex } = opts;
504
+ let seen = 0;
505
+ for (let i = 0; i < masked.length && i < pattern.length; i++) {
506
+ if (pattern[i] === '#') {
507
+ seen++;
508
+ if (seen === unmaskedIndex) {
509
+ return i + 1;
510
+ }
511
+ }
512
+ }
513
+ return masked.length;
514
+ }
515
+ function getCurrencyCaretPosition(opts) {
516
+ const { newValue, mask, transformOpts, oldCursorPosition, oldValue, previousUnmasked } = opts;
517
+ if (oldCursorPosition !== undefined && oldValue && previousUnmasked !== undefined) {
518
+ if (oldCursorPosition < oldValue.length) {
519
+ const digitsBeforeCursor = oldValue.substring(0, oldCursorPosition).replace(/\D/g, '').length;
520
+ let digitCount = 0;
521
+ for (let i = 0; i < newValue.length; i++) {
522
+ if (/\d/.test(newValue[i] ?? '')) {
523
+ digitCount++;
524
+ if (digitCount === digitsBeforeCursor) {
525
+ return i + 1;
526
+ }
527
+ }
528
+ }
529
+ }
530
+ }
531
+ if (mask === 'currency') {
532
+ const currencyAtEnd = isCurrencyAtEnd(transformOpts);
533
+ if (currencyAtEnd) {
534
+ const match = newValue.match(/(\d)\s*([^\d\s]+)$/);
535
+ if (match?.[1]) {
536
+ return newValue.lastIndexOf(match[1]) + 1;
537
+ }
538
+ else {
539
+ return newValue.length;
540
+ }
541
+ }
542
+ else {
543
+ return newValue.length;
544
+ }
545
+ }
546
+ else {
547
+ return newValue.length;
548
+ }
549
+ }
550
+ function getPatternCaretPosition(opts) {
551
+ const { newValue, maskPattern, currentUnmasked, oldCursorPosition, oldValue, previousUnmasked } = opts;
552
+ let position = 0;
553
+ let unmaskedCount = 0;
554
+ if (oldCursorPosition !== undefined && oldValue && previousUnmasked !== undefined) {
555
+ const oldUnmaskedIndex = toUnmaskedIndex({
556
+ masked: oldValue,
557
+ pattern: maskPattern.pattern,
558
+ caret: oldCursorPosition,
559
+ });
560
+ if (oldCursorPosition < oldValue.length) {
561
+ const targetUnmaskedIndex = Math.min(oldUnmaskedIndex, currentUnmasked.length);
562
+ for (let i = 0; i < maskPattern.pattern.length && i < newValue.length; i++) {
563
+ if (maskPattern.pattern[i] === '#') {
564
+ unmaskedCount++;
565
+ if (unmaskedCount <= targetUnmaskedIndex) {
566
+ position = i + 1;
567
+ }
568
+ }
569
+ }
570
+ return position;
571
+ }
572
+ }
573
+ for (let i = 0; i < maskPattern.pattern.length && i < newValue.length; i++) {
574
+ if (maskPattern.pattern[i] === '#') {
575
+ unmaskedCount++;
576
+ if (unmaskedCount <= currentUnmasked.length) {
577
+ position = i + 1;
578
+ }
579
+ }
580
+ }
581
+ return position;
582
+ }
583
+ function MaskInput(props) {
584
+ const { value: valueProp, defaultValue, onValueChange: onValueChangeProp, onValidate, onBlur: onBlurProp, onFocus: onFocusProp, onKeyDown: onKeyDownProp, onPaste: onPasteProp, onCompositionStart: onCompositionStartProp, onCompositionEnd: onCompositionEndProp, validationMode = 'onChange', mask, maskPlaceholder, currency = DEFAULT_CURRENCY, locale = DEFAULT_LOCALE, placeholder, inputMode, min, max, maxLength, asChild = false, disabled = false, invalid = false, readOnly = false, required = false, withoutMask = false, className, ref, ...inputProps } = props;
585
+ const [internalValue, setInternalValue] = React.useState(defaultValue ?? '');
586
+ const [focused, setFocused] = React.useState(false);
587
+ const [composing, setComposing] = React.useState(false);
588
+ const [touched, setTouched] = React.useState(false);
589
+ const inputRef = React.useRef(null);
590
+ const composedRef = useComposedRefs(ref, inputRef);
591
+ const isControlled = valueProp !== undefined;
592
+ const value = isControlled ? valueProp : internalValue;
593
+ const maskPattern = React.useMemo(() => {
594
+ if (typeof mask === 'string') {
595
+ return MASK_PATTERNS[mask];
596
+ }
597
+ return mask;
598
+ }, [mask]);
599
+ const transformOpts = React.useMemo(() => ({
600
+ currency,
601
+ locale,
602
+ }), [currency, locale]);
603
+ const placeholderValue = React.useMemo(() => {
604
+ if (withoutMask)
605
+ return placeholder;
606
+ if (placeholder && maskPlaceholder) {
607
+ return focused ? maskPlaceholder : placeholder;
608
+ }
609
+ if (maskPlaceholder) {
610
+ return focused ? maskPlaceholder : undefined;
611
+ }
612
+ return placeholder;
613
+ }, [placeholder, maskPlaceholder, focused, withoutMask]);
614
+ const displayValue = React.useMemo(() => {
615
+ if (withoutMask || !maskPattern || !value)
616
+ return value ?? '';
617
+ const unmasked = getUnmaskedValue({
618
+ value,
619
+ transform: maskPattern.transform,
620
+ ...transformOpts,
621
+ });
622
+ return applyMask({
623
+ value: unmasked,
624
+ pattern: maskPattern.pattern,
625
+ ...transformOpts,
626
+ mask,
627
+ });
628
+ }, [value, maskPattern, withoutMask, transformOpts, mask]);
629
+ const tokenCount = React.useMemo(() => {
630
+ if (!maskPattern || CURRENCY_PERCENTAGE_SYMBOLS.test(maskPattern.pattern))
631
+ return undefined;
632
+ return maskPattern.pattern.match(REGEX_CACHE.hashPattern)?.length ?? 0;
633
+ }, [maskPattern]);
634
+ const calculatedMaxLength = tokenCount ? maskPattern?.pattern.length : maxLength;
635
+ const calculatedInputMode = React.useMemo(() => {
636
+ if (inputMode)
637
+ return inputMode;
638
+ if (!maskPattern)
639
+ return undefined;
640
+ if (mask === 'currency' || mask === 'percentage' || mask === 'ipv4') {
641
+ return 'decimal';
642
+ }
643
+ if (typeof mask === 'string' && NUMERIC_MASK_PATTERNS.test(mask)) {
644
+ return 'numeric';
645
+ }
646
+ return undefined;
647
+ }, [maskPattern, mask, inputMode]);
648
+ const shouldValidate = React.useCallback((trigger) => {
649
+ if (!onValidate || !maskPattern?.validate)
650
+ return false;
651
+ switch (validationMode) {
652
+ case 'onChange':
653
+ return trigger === 'change';
654
+ case 'onBlur':
655
+ return trigger === 'blur';
656
+ case 'onSubmit':
657
+ return false;
658
+ case 'onTouched':
659
+ return touched ? trigger === 'change' : trigger === 'blur';
660
+ case 'all':
661
+ return true;
662
+ default:
663
+ return trigger === 'change';
664
+ }
665
+ }, [onValidate, maskPattern, validationMode, touched]);
666
+ const validationOpts = React.useMemo(() => ({
667
+ min: typeof min === 'string' ? parseFloat(min) : min,
668
+ max: typeof max === 'string' ? parseFloat(max) : max,
669
+ }), [min, max]);
670
+ const onInputValidate = React.useCallback((unmaskedValue) => {
671
+ if (onValidate && maskPattern?.validate) {
672
+ const isValid = maskPattern.validate(unmaskedValue, validationOpts);
673
+ onValidate(isValid, unmaskedValue);
674
+ }
675
+ }, [onValidate, maskPattern?.validate, validationOpts]);
676
+ const onValueChange = React.useCallback((event) => {
677
+ const inputValue = event.target.value;
678
+ let newValue = inputValue;
679
+ let unmaskedValue = inputValue;
680
+ if (composing) {
681
+ if (!isControlled)
682
+ setInternalValue(inputValue);
683
+ return;
684
+ }
685
+ if (withoutMask || !maskPattern) {
686
+ if (!isControlled)
687
+ setInternalValue(inputValue);
688
+ if (shouldValidate('change'))
689
+ onValidate?.(true, inputValue);
690
+ onValueChangeProp?.(inputValue, inputValue);
691
+ return;
692
+ }
693
+ if (maskPattern) {
694
+ unmaskedValue = getUnmaskedValue({
695
+ value: inputValue,
696
+ transform: maskPattern.transform,
697
+ ...transformOpts,
698
+ });
699
+ newValue = applyMask({
700
+ value: unmaskedValue,
701
+ pattern: maskPattern.pattern,
702
+ ...transformOpts,
703
+ mask,
704
+ });
705
+ if (inputRef.current && newValue !== inputValue) {
706
+ const inputElement = inputRef.current;
707
+ if (!(inputElement instanceof HTMLInputElement))
708
+ return;
709
+ const oldCursorPosition = inputElement.selectionStart ?? 0;
710
+ inputElement.value = newValue;
711
+ const currentUnmasked = getUnmaskedValue({
712
+ value: newValue,
713
+ transform: maskPattern.transform,
714
+ ...transformOpts,
715
+ });
716
+ let newCursorPosition;
717
+ const previousUnmasked = getUnmaskedValue({
718
+ value,
719
+ transform: maskPattern.transform,
720
+ ...transformOpts,
721
+ });
722
+ if (CURRENCY_PERCENTAGE_SYMBOLS.test(maskPattern.pattern)) {
723
+ newCursorPosition = getCurrencyCaretPosition({
724
+ newValue,
725
+ mask,
726
+ transformOpts,
727
+ oldCursorPosition,
728
+ oldValue: inputValue,
729
+ previousUnmasked,
730
+ });
731
+ }
732
+ else {
733
+ newCursorPosition = getPatternCaretPosition({
734
+ newValue,
735
+ maskPattern,
736
+ currentUnmasked,
737
+ oldCursorPosition,
738
+ oldValue: inputValue,
739
+ previousUnmasked,
740
+ });
741
+ }
742
+ if (isCurrencyMask({ mask, pattern: maskPattern.pattern })) {
743
+ if (mask === 'currency') {
744
+ const currencyAtEnd = isCurrencyAtEnd(transformOpts);
745
+ if (!currencyAtEnd) {
746
+ newCursorPosition = Math.max(1, newCursorPosition);
747
+ }
748
+ }
749
+ else {
750
+ newCursorPosition = Math.max(1, newCursorPosition);
751
+ }
752
+ }
753
+ else if (maskPattern.pattern.includes('%')) {
754
+ newCursorPosition = Math.min(newValue.length - 1, newCursorPosition);
755
+ }
756
+ newCursorPosition = Math.min(newCursorPosition, newValue.length);
757
+ inputElement.setSelectionRange(newCursorPosition, newCursorPosition);
758
+ }
759
+ }
760
+ if (!isControlled) {
761
+ setInternalValue(newValue);
762
+ }
763
+ if (shouldValidate('change')) {
764
+ onInputValidate(unmaskedValue);
765
+ }
766
+ onValueChangeProp?.(newValue, unmaskedValue);
767
+ }, [
768
+ maskPattern,
769
+ isControlled,
770
+ onValueChangeProp,
771
+ onValidate,
772
+ onInputValidate,
773
+ composing,
774
+ shouldValidate,
775
+ withoutMask,
776
+ transformOpts,
777
+ mask,
778
+ value,
779
+ ]);
780
+ const onFocus = React.useCallback((event) => {
781
+ onFocusProp?.(event);
782
+ if (event.defaultPrevented)
783
+ return;
784
+ setFocused(true);
785
+ }, [onFocusProp]);
786
+ const onBlur = React.useCallback((event) => {
787
+ onBlurProp?.(event);
788
+ if (event.defaultPrevented)
789
+ return;
790
+ setFocused(false);
791
+ if (!touched) {
792
+ setTouched(true);
793
+ }
794
+ if (shouldValidate('blur')) {
795
+ const currentValue = event.target.value;
796
+ const unmaskedValue = maskPattern
797
+ ? getUnmaskedValue({
798
+ value: currentValue,
799
+ transform: maskPattern.transform,
800
+ ...transformOpts,
801
+ })
802
+ : currentValue;
803
+ onInputValidate(unmaskedValue);
804
+ }
805
+ }, [onBlurProp, touched, shouldValidate, onInputValidate, maskPattern, transformOpts]);
806
+ const onCompositionStart = React.useCallback((event) => {
807
+ onCompositionStartProp?.(event);
808
+ if (event.defaultPrevented)
809
+ return;
810
+ setComposing(true);
811
+ }, [onCompositionStartProp]);
812
+ const onCompositionEnd = React.useCallback((event) => {
813
+ onCompositionEndProp?.(event);
814
+ if (event.defaultPrevented)
815
+ return;
816
+ setComposing(false);
817
+ const inputElement = inputRef.current;
818
+ if (!inputElement)
819
+ return;
820
+ if (!(inputElement instanceof HTMLInputElement))
821
+ return;
822
+ const inputValue = inputElement.value;
823
+ if (!maskPattern || withoutMask) {
824
+ if (!isControlled)
825
+ setInternalValue(inputValue);
826
+ if (shouldValidate('change'))
827
+ onValidate?.(true, inputValue);
828
+ onValueChangeProp?.(inputValue, inputValue);
829
+ return;
830
+ }
831
+ const unmasked = getUnmaskedValue({
832
+ value: inputValue,
833
+ transform: maskPattern.transform,
834
+ ...transformOpts,
835
+ });
836
+ const masked = applyMask({
837
+ value: unmasked,
838
+ pattern: maskPattern.pattern,
839
+ ...transformOpts,
840
+ mask,
841
+ });
842
+ if (!isControlled)
843
+ setInternalValue(masked);
844
+ if (shouldValidate('change'))
845
+ onInputValidate(unmasked);
846
+ onValueChangeProp?.(masked, unmasked);
847
+ }, [
848
+ onCompositionEndProp,
849
+ maskPattern,
850
+ withoutMask,
851
+ isControlled,
852
+ shouldValidate,
853
+ onValidate,
854
+ onValueChangeProp,
855
+ transformOpts,
856
+ mask,
857
+ onInputValidate,
858
+ ]);
859
+ const onPaste = React.useCallback((event) => {
860
+ onPasteProp?.(event);
861
+ if (event.defaultPrevented)
862
+ return;
863
+ if (withoutMask || !maskPattern)
864
+ return;
865
+ if (mask === 'ipv4')
866
+ return;
867
+ const target = event.target;
868
+ if (!(target instanceof HTMLInputElement))
869
+ return;
870
+ const pastedData = event.clipboardData.getData('text');
871
+ if (!pastedData)
872
+ return;
873
+ event.preventDefault();
874
+ const currentValue = target.value;
875
+ const selectionStart = target.selectionStart ?? 0;
876
+ const selectionEnd = target.selectionEnd ?? 0;
877
+ const beforeSelection = currentValue.slice(0, selectionStart);
878
+ const afterSelection = currentValue.slice(selectionEnd);
879
+ const newInputValue = beforeSelection + pastedData + afterSelection;
880
+ const unmasked = getUnmaskedValue({
881
+ value: newInputValue,
882
+ transform: maskPattern.transform,
883
+ ...transformOpts,
884
+ });
885
+ const newMaskedValue = applyMask({
886
+ value: unmasked,
887
+ pattern: maskPattern.pattern,
888
+ ...transformOpts,
889
+ mask,
890
+ });
891
+ target.value = newMaskedValue;
892
+ if (isCurrencyMask({ mask, pattern: maskPattern.pattern })) {
893
+ const currencyAtEnd = isCurrencyAtEnd(transformOpts);
894
+ const caret = currencyAtEnd ? newMaskedValue.search(/\s*[^\d\s]+$/) : newMaskedValue.length;
895
+ target.setSelectionRange(caret, caret);
896
+ return;
897
+ }
898
+ if (maskPattern.pattern.includes('%')) {
899
+ target.setSelectionRange(newMaskedValue.length - 1, newMaskedValue.length - 1);
900
+ return;
901
+ }
902
+ let newCursorPosition = newMaskedValue.length;
903
+ try {
904
+ const unmaskedCount = unmasked.length;
905
+ let position = 0;
906
+ let count = 0;
907
+ for (let i = 0; i < maskPattern.pattern.length && i < newMaskedValue.length; i++) {
908
+ if (maskPattern.pattern[i] === '#') {
909
+ count++;
910
+ if (count <= unmaskedCount) {
911
+ position = i + 1;
912
+ }
913
+ }
914
+ }
915
+ newCursorPosition = position;
916
+ }
917
+ catch {
918
+ }
919
+ target.setSelectionRange(newCursorPosition, newCursorPosition);
920
+ if (!isControlled)
921
+ setInternalValue(newMaskedValue);
922
+ if (shouldValidate('change'))
923
+ onInputValidate(unmasked);
924
+ onValueChangeProp?.(newMaskedValue, unmasked);
925
+ }, [
926
+ onPasteProp,
927
+ withoutMask,
928
+ maskPattern,
929
+ mask,
930
+ transformOpts,
931
+ isControlled,
932
+ shouldValidate,
933
+ onInputValidate,
934
+ onValueChangeProp,
935
+ ]);
936
+ const onKeyDown = React.useCallback((event) => {
937
+ onKeyDownProp?.(event);
938
+ if (event.defaultPrevented)
939
+ return;
940
+ if (withoutMask || !maskPattern)
941
+ return;
942
+ if (mask === 'ipv4')
943
+ return;
944
+ if (event.key === 'Backspace') {
945
+ const target = event.target;
946
+ if (!(target instanceof HTMLInputElement))
947
+ return;
948
+ const cursorPosition = target.selectionStart ?? 0;
949
+ const selectionEnd = target.selectionEnd ?? 0;
950
+ const currentValue = target.value;
951
+ if (mask === 'currency' ||
952
+ mask === 'percentage' ||
953
+ maskPattern.pattern.includes('$') ||
954
+ maskPattern.pattern.includes('€') ||
955
+ maskPattern.pattern.includes('%')) {
956
+ return;
957
+ }
958
+ if (cursorPosition !== selectionEnd) {
959
+ return;
960
+ }
961
+ if (cursorPosition > 0) {
962
+ const charBeforeCursor = currentValue[cursorPosition - 1];
963
+ if (charBeforeCursor) {
964
+ event.preventDefault();
965
+ const unmaskedIndex = toUnmaskedIndex({
966
+ masked: currentValue,
967
+ pattern: maskPattern.pattern,
968
+ caret: cursorPosition,
969
+ });
970
+ if (unmaskedIndex > 0) {
971
+ const currentUnmasked = getUnmaskedValue({
972
+ value: currentValue,
973
+ transform: maskPattern.transform,
974
+ ...transformOpts,
975
+ });
976
+ const nextUnmasked = currentUnmasked.slice(0, unmaskedIndex - 1) + currentUnmasked.slice(unmaskedIndex);
977
+ const nextMasked = applyMask({
978
+ value: nextUnmasked,
979
+ pattern: maskPattern.pattern,
980
+ ...transformOpts,
981
+ mask,
982
+ });
983
+ target.value = nextMasked;
984
+ const nextCaret = fromUnmaskedIndex({
985
+ masked: nextMasked,
986
+ pattern: maskPattern.pattern,
987
+ unmaskedIndex: unmaskedIndex - 1,
988
+ });
989
+ target.setSelectionRange(nextCaret, nextCaret);
990
+ onValueChangeProp?.(nextMasked, nextUnmasked);
991
+ }
992
+ return;
993
+ }
994
+ }
995
+ }
996
+ if (event.key === 'Delete') {
997
+ const target = event.target;
998
+ if (!(target instanceof HTMLInputElement))
999
+ return;
1000
+ const cursorPosition = target.selectionStart ?? 0;
1001
+ const selectionEnd = target.selectionEnd ?? 0;
1002
+ const currentValue = target.value;
1003
+ if (mask === 'currency' ||
1004
+ mask === 'percentage' ||
1005
+ maskPattern.pattern.includes('$') ||
1006
+ maskPattern.pattern.includes('€') ||
1007
+ maskPattern.pattern.includes('%')) {
1008
+ return;
1009
+ }
1010
+ if (cursorPosition !== selectionEnd) {
1011
+ return;
1012
+ }
1013
+ if (cursorPosition < currentValue.length) {
1014
+ const charAtCursor = currentValue[cursorPosition];
1015
+ if (charAtCursor) {
1016
+ event.preventDefault();
1017
+ const unmaskedIndex = toUnmaskedIndex({
1018
+ masked: currentValue,
1019
+ pattern: maskPattern.pattern,
1020
+ caret: cursorPosition,
1021
+ });
1022
+ const currentUnmasked = getUnmaskedValue({
1023
+ value: currentValue,
1024
+ transform: maskPattern.transform,
1025
+ ...transformOpts,
1026
+ });
1027
+ if (unmaskedIndex < currentUnmasked.length) {
1028
+ const nextUnmasked = currentUnmasked.slice(0, unmaskedIndex) + currentUnmasked.slice(unmaskedIndex + 1);
1029
+ const nextMasked = applyMask({
1030
+ value: nextUnmasked,
1031
+ pattern: maskPattern.pattern,
1032
+ ...transformOpts,
1033
+ mask,
1034
+ });
1035
+ target.value = nextMasked;
1036
+ const nextCaret = fromUnmaskedIndex({
1037
+ masked: nextMasked,
1038
+ pattern: maskPattern.pattern,
1039
+ unmaskedIndex: unmaskedIndex,
1040
+ });
1041
+ target.setSelectionRange(nextCaret, nextCaret);
1042
+ onValueChangeProp?.(nextMasked, nextUnmasked);
1043
+ }
1044
+ return;
1045
+ }
1046
+ }
1047
+ }
1048
+ }, [maskPattern, onKeyDownProp, onValueChangeProp, transformOpts, mask, withoutMask]);
1049
+ const InputPrimitive = asChild ? SlotPrimitive.Slot : 'input';
1050
+ return (_jsx(InputPrimitive, { "aria-invalid": invalid, "data-disabled": disabled ? '' : undefined, "data-invalid": invalid ? '' : undefined, "data-readonly": readOnly ? '' : undefined, "data-required": required ? '' : undefined, "data-slot": "mask-input", ...inputProps, className: cn('flex h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs outline-none transition-[color,box-shadow] selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:font-medium file:text-foreground file:text-sm placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30', 'focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50', 'aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40', className), placeholder: placeholderValue, ref: composedRef, value: displayValue, disabled: disabled, maxLength: calculatedMaxLength, readOnly: readOnly, required: required, inputMode: calculatedInputMode, min: min, max: max, onFocus: onFocus, onBlur: onBlur, onKeyDown: onKeyDown, onPaste: onPaste, onChange: onValueChange, onCompositionStart: onCompositionStart, onCompositionEnd: onCompositionEnd }));
1051
+ }
1052
+ export { applyCurrencyMask, applyMask, applyPercentageMask, fromUnmaskedIndex, getUnmaskedValue, MASK_PATTERNS, MaskInput, toUnmaskedIndex, };