xiod-ui 1.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 (224) hide show
  1. package/LICENSE +73 -0
  2. package/README.md +167 -0
  3. package/dist/components/accordion.d.ts +9 -0
  4. package/dist/components/accordion.js +46 -0
  5. package/dist/components/agent-steps.d.ts +47 -0
  6. package/dist/components/agent-steps.js +223 -0
  7. package/dist/components/alert-dialog.d.ts +21 -0
  8. package/dist/components/alert-dialog.js +74 -0
  9. package/dist/components/alert.d.ts +12 -0
  10. package/dist/components/alert.js +45 -0
  11. package/dist/components/aspect-ratio.d.ts +9 -0
  12. package/dist/components/aspect-ratio.js +22 -0
  13. package/dist/components/autocomplete.d.ts +35 -0
  14. package/dist/components/autocomplete.js +160 -0
  15. package/dist/components/avatar.d.ts +17 -0
  16. package/dist/components/avatar.js +65 -0
  17. package/dist/components/badge.d.ts +15 -0
  18. package/dist/components/badge.js +46 -0
  19. package/dist/components/breadcrumb.d.ts +12 -0
  20. package/dist/components/breadcrumb.js +75 -0
  21. package/dist/components/button-group.d.ts +14 -0
  22. package/dist/components/button-group.js +45 -0
  23. package/dist/components/button-split.d.ts +19 -0
  24. package/dist/components/button-split.js +73 -0
  25. package/dist/components/button.d.ts +15 -0
  26. package/dist/components/button.js +54 -0
  27. package/dist/components/calendar.d.ts +63 -0
  28. package/dist/components/calendar.js +425 -0
  29. package/dist/components/card.d.ts +17 -0
  30. package/dist/components/card.js +139 -0
  31. package/dist/components/carousel.d.ts +59 -0
  32. package/dist/components/carousel.js +503 -0
  33. package/dist/components/checkbox.d.ts +16 -0
  34. package/dist/components/checkbox.js +86 -0
  35. package/dist/components/circular-progress.d.ts +28 -0
  36. package/dist/components/circular-progress.js +127 -0
  37. package/dist/components/collapsible.d.ts +8 -0
  38. package/dist/components/collapsible.js +27 -0
  39. package/dist/components/color-picker.d.ts +159 -0
  40. package/dist/components/color-picker.js +1589 -0
  41. package/dist/components/combobox.d.ts +46 -0
  42. package/dist/components/combobox.js +237 -0
  43. package/dist/components/command.d.ts +22 -0
  44. package/dist/components/command.js +129 -0
  45. package/dist/components/context-menu.d.ts +38 -0
  46. package/dist/components/context-menu.js +164 -0
  47. package/dist/components/copy-to-clipboard.d.ts +32 -0
  48. package/dist/components/copy-to-clipboard.js +83 -0
  49. package/dist/components/corner-badge.d.ts +22 -0
  50. package/dist/components/corner-badge.js +84 -0
  51. package/dist/components/dashboard-grid.d.ts +83 -0
  52. package/dist/components/dashboard-grid.js +486 -0
  53. package/dist/components/date-picker.d.ts +29 -0
  54. package/dist/components/date-picker.js +261 -0
  55. package/dist/components/dialog.d.ts +26 -0
  56. package/dist/components/dialog.js +97 -0
  57. package/dist/components/dot-matrix.d.ts +32 -0
  58. package/dist/components/dot-matrix.js +707 -0
  59. package/dist/components/draggable.d.ts +42 -0
  60. package/dist/components/draggable.js +346 -0
  61. package/dist/components/drawer.d.ts +66 -0
  62. package/dist/components/drawer.js +304 -0
  63. package/dist/components/empty.d.ts +14 -0
  64. package/dist/components/empty.js +75 -0
  65. package/dist/components/field.d.ts +12 -0
  66. package/dist/components/field.js +44 -0
  67. package/dist/components/fieldset.d.ts +7 -0
  68. package/dist/components/fieldset.js +21 -0
  69. package/dist/components/file-upload.d.ts +61 -0
  70. package/dist/components/file-upload.js +482 -0
  71. package/dist/components/form.d.ts +6 -0
  72. package/dist/components/form.js +14 -0
  73. package/dist/components/frame.d.ts +10 -0
  74. package/dist/components/frame.js +47 -0
  75. package/dist/components/gauge.d.ts +27 -0
  76. package/dist/components/gauge.js +74 -0
  77. package/dist/components/grid.d.ts +26 -0
  78. package/dist/components/grid.js +204 -0
  79. package/dist/components/group.d.ts +19 -0
  80. package/dist/components/group.js +45 -0
  81. package/dist/components/input-group.d.ts +15 -0
  82. package/dist/components/input-group.js +61 -0
  83. package/dist/components/input-otp.d.ts +24 -0
  84. package/dist/components/input-otp.js +50 -0
  85. package/dist/components/input-payment.d.ts +131 -0
  86. package/dist/components/input-payment.js +1140 -0
  87. package/dist/components/input-phone.d.ts +70 -0
  88. package/dist/components/input-phone.js +657 -0
  89. package/dist/components/input-sensitive.d.ts +12 -0
  90. package/dist/components/input-sensitive.js +169 -0
  91. package/dist/components/input.d.ts +13 -0
  92. package/dist/components/input.js +26 -0
  93. package/dist/components/kbd.d.ts +6 -0
  94. package/dist/components/kbd.js +19 -0
  95. package/dist/components/kinetic-click.d.ts +48 -0
  96. package/dist/components/kinetic-click.js +1184 -0
  97. package/dist/components/label.d.ts +6 -0
  98. package/dist/components/label.js +18 -0
  99. package/dist/components/list-box.d.ts +20 -0
  100. package/dist/components/list-box.js +148 -0
  101. package/dist/components/loader.d.ts +13 -0
  102. package/dist/components/loader.js +430 -0
  103. package/dist/components/marker.d.ts +15 -0
  104. package/dist/components/marker.js +59 -0
  105. package/dist/components/menu.d.ts +42 -0
  106. package/dist/components/menu.js +186 -0
  107. package/dist/components/menubar.d.ts +40 -0
  108. package/dist/components/menubar.js +107 -0
  109. package/dist/components/message.d.ts +33 -0
  110. package/dist/components/message.js +112 -0
  111. package/dist/components/meter.d.ts +10 -0
  112. package/dist/components/meter.js +42 -0
  113. package/dist/components/morphic-toast.d.ts +61 -0
  114. package/dist/components/morphic-toast.js +916 -0
  115. package/dist/components/navigation-menu.d.ts +26 -0
  116. package/dist/components/navigation-menu.js +116 -0
  117. package/dist/components/number-field.d.ts +15 -0
  118. package/dist/components/number-field.js +86 -0
  119. package/dist/components/option-picker.d.ts +18 -0
  120. package/dist/components/option-picker.js +89 -0
  121. package/dist/components/orb.d.ts +38 -0
  122. package/dist/components/orb.js +1413 -0
  123. package/dist/components/pagination.d.ts +25 -0
  124. package/dist/components/pagination.js +147 -0
  125. package/dist/components/popover.d.ts +22 -0
  126. package/dist/components/popover.js +79 -0
  127. package/dist/components/preview-card.d.ts +16 -0
  128. package/dist/components/preview-card.js +60 -0
  129. package/dist/components/progress.d.ts +21 -0
  130. package/dist/components/progress.js +139 -0
  131. package/dist/components/radio.d.ts +16 -0
  132. package/dist/components/radio.js +68 -0
  133. package/dist/components/resizable.d.ts +58 -0
  134. package/dist/components/resizable.js +964 -0
  135. package/dist/components/ruler-picker.d.ts +27 -0
  136. package/dist/components/ruler-picker.js +253 -0
  137. package/dist/components/scroll-area.d.ts +13 -0
  138. package/dist/components/scroll-area.js +34 -0
  139. package/dist/components/scroll-bar.d.ts +13 -0
  140. package/dist/components/scroll-bar.js +47 -0
  141. package/dist/components/select.d.ts +29 -0
  142. package/dist/components/select.js +140 -0
  143. package/dist/components/separator.d.ts +6 -0
  144. package/dist/components/separator.js +15 -0
  145. package/dist/components/sidebar.d.ts +65 -0
  146. package/dist/components/sidebar.js +408 -0
  147. package/dist/components/skeleton.d.ts +5 -0
  148. package/dist/components/skeleton.js +12 -0
  149. package/dist/components/slider.d.ts +12 -0
  150. package/dist/components/slider.js +96 -0
  151. package/dist/components/sortable.d.ts +44 -0
  152. package/dist/components/sortable.js +327 -0
  153. package/dist/components/switch.d.ts +15 -0
  154. package/dist/components/switch.js +63 -0
  155. package/dist/components/table.d.ts +12 -0
  156. package/dist/components/table.js +65 -0
  157. package/dist/components/tabs.d.ts +12 -0
  158. package/dist/components/tabs.js +39 -0
  159. package/dist/components/text.d.ts +14 -0
  160. package/dist/components/text.js +69 -0
  161. package/dist/components/textarea.d.ts +9 -0
  162. package/dist/components/textarea.js +20 -0
  163. package/dist/components/theme-provider.d.ts +52 -0
  164. package/dist/components/theme-provider.js +148 -0
  165. package/dist/components/timeline.d.ts +34 -0
  166. package/dist/components/timeline.js +147 -0
  167. package/dist/components/toast.d.ts +17 -0
  168. package/dist/components/toast.js +161 -0
  169. package/dist/components/toggle-group.d.ts +14 -0
  170. package/dist/components/toggle-group.js +53 -0
  171. package/dist/components/toggle.d.ts +11 -0
  172. package/dist/components/toggle.js +36 -0
  173. package/dist/components/toolbar.d.ts +11 -0
  174. package/dist/components/toolbar.js +49 -0
  175. package/dist/components/tooltip.d.ts +17 -0
  176. package/dist/components/tooltip.js +56 -0
  177. package/dist/components/waveform.d.ts +61 -0
  178. package/dist/components/waveform.js +500 -0
  179. package/dist/components/wheel-picker.d.ts +44 -0
  180. package/dist/components/wheel-picker.js +771 -0
  181. package/dist/hooks/use-copy-to-clipboard.d.ts +9 -0
  182. package/dist/hooks/use-copy-to-clipboard.js +36 -0
  183. package/dist/hooks/use-media-query.d.ts +21 -0
  184. package/dist/hooks/use-media-query.js +58 -0
  185. package/dist/styles.css +202 -0
  186. package/dist/themes/afterglow.css +89 -0
  187. package/dist/themes/afterglow.scoped.css +90 -0
  188. package/dist/themes/blacklight.css +89 -0
  189. package/dist/themes/blacklight.scoped.css +90 -0
  190. package/dist/themes/cathode.css +89 -0
  191. package/dist/themes/cathode.scoped.css +90 -0
  192. package/dist/themes/cel.css +89 -0
  193. package/dist/themes/cel.scoped.css +90 -0
  194. package/dist/themes/cinder.css +89 -0
  195. package/dist/themes/cinder.scoped.css +90 -0
  196. package/dist/themes/clay.css +89 -0
  197. package/dist/themes/clay.scoped.css +90 -0
  198. package/dist/themes/cobalt.css +89 -0
  199. package/dist/themes/cobalt.scoped.css +90 -0
  200. package/dist/themes/crimson.css +89 -0
  201. package/dist/themes/crimson.scoped.css +90 -0
  202. package/dist/themes/ion.css +89 -0
  203. package/dist/themes/ion.scoped.css +90 -0
  204. package/dist/themes/iris.css +89 -0
  205. package/dist/themes/iris.scoped.css +90 -0
  206. package/dist/themes/lagoon.css +89 -0
  207. package/dist/themes/lagoon.scoped.css +90 -0
  208. package/dist/themes/mochi.css +89 -0
  209. package/dist/themes/mochi.scoped.css +90 -0
  210. package/dist/themes/riso.css +89 -0
  211. package/dist/themes/riso.scoped.css +90 -0
  212. package/dist/themes/roast.css +89 -0
  213. package/dist/themes/roast.scoped.css +90 -0
  214. package/dist/themes/sage.css +89 -0
  215. package/dist/themes/sage.scoped.css +90 -0
  216. package/dist/themes/sepia.css +89 -0
  217. package/dist/themes/sepia.scoped.css +90 -0
  218. package/dist/themes/sorbet.css +89 -0
  219. package/dist/themes/sorbet.scoped.css +90 -0
  220. package/dist/themes/taffy.css +89 -0
  221. package/dist/themes/taffy.scoped.css +90 -0
  222. package/dist/themes/toxin.css +89 -0
  223. package/dist/themes/toxin.scoped.css +90 -0
  224. package/package.json +140 -0
@@ -0,0 +1,657 @@
1
+ "use client";
2
+ import { ScrollArea } from "./scroll-area.js";
3
+ import { Popover, PopoverContent as PopoverPopup, PopoverTrigger } from "./popover.js";
4
+ import { InputGroup, InputGroupAddon, InputGroupInput } from "./input-group.js";
5
+ import { cn } from "cn";
6
+ import { ChevronDown } from "xiod-icons/icons/ChevronDown";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { cva } from "class-variance-authority";
9
+ import * as React$1 from "react";
10
+ import { Cancel } from "xiod-icons/icons/Cancel";
11
+ import { Check } from "xiod-icons/icons/Check";
12
+ import { Search } from "xiod-icons/icons/Search";
13
+ import { mergeProps } from "@base-ui/react/merge-props";
14
+ import { useRender } from "@base-ui/react/use-render";
15
+ //#region src/components/input-phone.tsx
16
+ const COUNTRIES = [
17
+ {
18
+ code: "US",
19
+ name: "United States",
20
+ dialCode: "+1",
21
+ flag: "🇺🇸",
22
+ mask: "(###) ###-####"
23
+ },
24
+ {
25
+ code: "GB",
26
+ name: "United Kingdom",
27
+ dialCode: "+44",
28
+ flag: "🇬🇧",
29
+ mask: "##### ######"
30
+ },
31
+ {
32
+ code: "IN",
33
+ name: "India",
34
+ dialCode: "+91",
35
+ flag: "🇮🇳",
36
+ mask: "##### #####"
37
+ },
38
+ {
39
+ code: "CA",
40
+ name: "Canada",
41
+ dialCode: "+1",
42
+ flag: "🇨🇦",
43
+ mask: "(###) ###-####"
44
+ },
45
+ {
46
+ code: "AU",
47
+ name: "Australia",
48
+ dialCode: "+61",
49
+ flag: "🇦🇺",
50
+ mask: "#### ### ###"
51
+ },
52
+ {
53
+ code: "DE",
54
+ name: "Germany",
55
+ dialCode: "+49",
56
+ flag: "🇩🇪",
57
+ mask: "#### ########"
58
+ },
59
+ {
60
+ code: "FR",
61
+ name: "France",
62
+ dialCode: "+33",
63
+ flag: "🇫🇷",
64
+ mask: "# ## ## ## ##"
65
+ },
66
+ {
67
+ code: "JP",
68
+ name: "Japan",
69
+ dialCode: "+81",
70
+ flag: "🇯🇵",
71
+ mask: "## #### ####"
72
+ },
73
+ {
74
+ code: "BR",
75
+ name: "Brazil",
76
+ dialCode: "+55",
77
+ flag: "🇧🇷",
78
+ mask: "(##) #####-####"
79
+ },
80
+ {
81
+ code: "CN",
82
+ name: "China",
83
+ dialCode: "+86",
84
+ flag: "🇨🇳",
85
+ mask: "### #### ####"
86
+ },
87
+ {
88
+ code: "ES",
89
+ name: "Spain",
90
+ dialCode: "+34",
91
+ flag: "🇪🇸",
92
+ mask: "### ## ## ##"
93
+ },
94
+ {
95
+ code: "IT",
96
+ name: "Italy",
97
+ dialCode: "+39",
98
+ flag: "🇮🇹",
99
+ mask: "### #######"
100
+ },
101
+ {
102
+ code: "MX",
103
+ name: "Mexico",
104
+ dialCode: "+52",
105
+ flag: "🇲🇽",
106
+ mask: "### ### ####"
107
+ },
108
+ {
109
+ code: "NL",
110
+ name: "Netherlands",
111
+ dialCode: "+31",
112
+ flag: "🇳🇱",
113
+ mask: "# ########"
114
+ },
115
+ {
116
+ code: "SG",
117
+ name: "Singapore",
118
+ dialCode: "+65",
119
+ flag: "🇸🇬",
120
+ mask: "#### ####"
121
+ },
122
+ {
123
+ code: "KR",
124
+ name: "South Korea",
125
+ dialCode: "+82",
126
+ flag: "🇰🇷",
127
+ mask: "## #### ####"
128
+ },
129
+ {
130
+ code: "ZA",
131
+ name: "South Africa",
132
+ dialCode: "+27",
133
+ flag: "🇿🇦",
134
+ mask: "## ### ####"
135
+ },
136
+ {
137
+ code: "AE",
138
+ name: "United Arab Emirates",
139
+ dialCode: "+971",
140
+ flag: "🇦🇪",
141
+ mask: "## ### ####"
142
+ },
143
+ {
144
+ code: "AR",
145
+ name: "Argentina",
146
+ dialCode: "+54",
147
+ flag: "🇦🇷",
148
+ mask: "### ###-####"
149
+ },
150
+ {
151
+ code: "CH",
152
+ name: "Switzerland",
153
+ dialCode: "+41",
154
+ flag: "🇨🇭",
155
+ mask: "## ### ## ##"
156
+ },
157
+ {
158
+ code: "SE",
159
+ name: "Sweden",
160
+ dialCode: "+46",
161
+ flag: "🇸🇪",
162
+ mask: "##-### ## ##"
163
+ },
164
+ {
165
+ code: "NO",
166
+ name: "Norway",
167
+ dialCode: "+47",
168
+ flag: "🇳🇴",
169
+ mask: "### ## ###"
170
+ },
171
+ {
172
+ code: "DK",
173
+ name: "Denmark",
174
+ dialCode: "+45",
175
+ flag: "🇩🇰",
176
+ mask: "## ## ## ##"
177
+ },
178
+ {
179
+ code: "FI",
180
+ name: "Finland",
181
+ dialCode: "+358",
182
+ flag: "🇫🇮",
183
+ mask: "## ### ## ##"
184
+ },
185
+ {
186
+ code: "NZ",
187
+ name: "New Zealand",
188
+ dialCode: "+64",
189
+ flag: "🇳🇿",
190
+ mask: "## ### ####"
191
+ },
192
+ {
193
+ code: "PL",
194
+ name: "Poland",
195
+ dialCode: "+48",
196
+ flag: "🇵🇱",
197
+ mask: "### ### ###"
198
+ },
199
+ {
200
+ code: "PT",
201
+ name: "Portugal",
202
+ dialCode: "+351",
203
+ flag: "🇵🇹",
204
+ mask: "### ### ###"
205
+ },
206
+ {
207
+ code: "IE",
208
+ name: "Ireland",
209
+ dialCode: "+353",
210
+ flag: "🇮🇪",
211
+ mask: "## ### ####"
212
+ },
213
+ {
214
+ code: "BE",
215
+ name: "Belgium",
216
+ dialCode: "+32",
217
+ flag: "🇧🇪",
218
+ mask: "### ## ## ##"
219
+ },
220
+ {
221
+ code: "AT",
222
+ name: "Austria",
223
+ dialCode: "+43",
224
+ flag: "🇦🇹",
225
+ mask: "#### ######"
226
+ },
227
+ {
228
+ code: "IL",
229
+ name: "Israel",
230
+ dialCode: "+972",
231
+ flag: "🇮🇱",
232
+ mask: "##-###-####"
233
+ },
234
+ {
235
+ code: "SA",
236
+ name: "Saudi Arabia",
237
+ dialCode: "+966",
238
+ flag: "🇸🇦",
239
+ mask: "## ### ####"
240
+ },
241
+ {
242
+ code: "TH",
243
+ name: "Thailand",
244
+ dialCode: "+66",
245
+ flag: "🇹🇭",
246
+ mask: "## #### ####"
247
+ },
248
+ {
249
+ code: "MY",
250
+ name: "Malaysia",
251
+ dialCode: "+60",
252
+ flag: "🇲🇾",
253
+ mask: "##-### ####"
254
+ },
255
+ {
256
+ code: "ID",
257
+ name: "Indonesia",
258
+ dialCode: "+62",
259
+ flag: "🇮🇩",
260
+ mask: "###-####-####"
261
+ },
262
+ {
263
+ code: "PH",
264
+ name: "Philippines",
265
+ dialCode: "+63",
266
+ flag: "🇵🇭",
267
+ mask: "### ### ####"
268
+ },
269
+ {
270
+ code: "VN",
271
+ name: "Vietnam",
272
+ dialCode: "+84",
273
+ flag: "🇻🇳",
274
+ mask: "### ### ####"
275
+ },
276
+ {
277
+ code: "GR",
278
+ name: "Greece",
279
+ dialCode: "+30",
280
+ flag: "🇬🇷",
281
+ mask: "### #######"
282
+ },
283
+ {
284
+ code: "TR",
285
+ name: "Turkey",
286
+ dialCode: "+90",
287
+ flag: "🇹🇷",
288
+ mask: "### ### ## ##"
289
+ },
290
+ {
291
+ code: "UA",
292
+ name: "Ukraine",
293
+ dialCode: "+380",
294
+ flag: "🇺🇦",
295
+ mask: "## ### ## ##"
296
+ },
297
+ {
298
+ code: "CZ",
299
+ name: "Czech Republic",
300
+ dialCode: "+420",
301
+ flag: "🇨🇿",
302
+ mask: "### ### ###"
303
+ },
304
+ {
305
+ code: "HU",
306
+ name: "Hungary",
307
+ dialCode: "+36",
308
+ flag: "🇭🇺",
309
+ mask: "## ### ####"
310
+ },
311
+ {
312
+ code: "RO",
313
+ name: "Romania",
314
+ dialCode: "+40",
315
+ flag: "🇷🇴",
316
+ mask: "### ### ###"
317
+ },
318
+ {
319
+ code: "CL",
320
+ name: "Chile",
321
+ dialCode: "+56",
322
+ flag: "🇨🇱",
323
+ mask: "# #### ####"
324
+ },
325
+ {
326
+ code: "CO",
327
+ name: "Colombia",
328
+ dialCode: "+57",
329
+ flag: "🇨🇴",
330
+ mask: "### ### ####"
331
+ },
332
+ {
333
+ code: "PE",
334
+ name: "Peru",
335
+ dialCode: "+51",
336
+ flag: "🇵🇪",
337
+ mask: "### ### ###"
338
+ },
339
+ {
340
+ code: "EG",
341
+ name: "Egypt",
342
+ dialCode: "+20",
343
+ flag: "🇪🇬",
344
+ mask: "## #### ####"
345
+ },
346
+ {
347
+ code: "NG",
348
+ name: "Nigeria",
349
+ dialCode: "+234",
350
+ flag: "🇳🇬",
351
+ mask: "### ### ####"
352
+ },
353
+ {
354
+ code: "KE",
355
+ name: "Kenya",
356
+ dialCode: "+254",
357
+ flag: "🇰🇪",
358
+ mask: "### ######"
359
+ }
360
+ ];
361
+ function formatPhoneNumber(digits, mask) {
362
+ const clean = digits.replace(/\D/g, "");
363
+ if (!mask) return clean;
364
+ let formatted = "";
365
+ let digitIndex = 0;
366
+ for (let i = 0; i < mask.length && digitIndex < clean.length; i++) if (mask[i] === "#") {
367
+ formatted += clean[digitIndex];
368
+ digitIndex++;
369
+ } else formatted += mask[i];
370
+ if (digitIndex < clean.length) formatted += clean.slice(digitIndex);
371
+ return formatted;
372
+ }
373
+ function parseE164Number(e164, countries = COUNTRIES) {
374
+ if (!e164.startsWith("+")) return null;
375
+ const sortedCountries = countries.toSorted((a, b) => b.dialCode.length - a.dialCode.length);
376
+ for (const country of sortedCountries) if (e164.startsWith(country.dialCode)) return {
377
+ country,
378
+ nationalNumber: e164.slice(country.dialCode.length).replace(/\D/g, "")
379
+ };
380
+ return null;
381
+ }
382
+ const inputPhoneVariants = cva("w-full max-w-[15.5rem] sm:max-w-[15rem] [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
383
+ variants: {
384
+ variant: {
385
+ default: "",
386
+ filled: "bg-muted/40 border-transparent focus-within:bg-background",
387
+ ghost: "border-transparent bg-transparent shadow-none ring-0 focus-within:border-border"
388
+ },
389
+ size: {
390
+ default: "max-w-[15.5rem] sm:max-w-[15rem]",
391
+ sm: "max-w-[14.5rem] sm:max-w-[14rem]",
392
+ lg: "max-w-[17rem] sm:max-w-[16.5rem]"
393
+ }
394
+ },
395
+ defaultVariants: {
396
+ variant: "default",
397
+ size: "default"
398
+ }
399
+ });
400
+ const InputPhoneContext = React$1.createContext(null);
401
+ function useInputPhone() {
402
+ const context = React$1.useContext(InputPhoneContext);
403
+ if (!context) throw new Error("useInputPhone must be used within an <InputPhone /> container.");
404
+ return context;
405
+ }
406
+ const usePhoneInput = useInputPhone;
407
+ function InputPhone({ className, variant, size, defaultValue = "", value: valueProp, defaultCountry = "US", countries = COUNTRIES, disabled, readOnly, onChange, children, ...props }) {
408
+ const containerRef = React$1.useRef(null);
409
+ const initialCountry = React$1.useMemo(() => {
410
+ if (defaultValue) {
411
+ const parsed = parseE164Number(defaultValue, countries);
412
+ if (parsed) return parsed.country;
413
+ }
414
+ return countries.find((c) => c.code.toUpperCase() === defaultCountry.toUpperCase()) || countries[0];
415
+ }, [
416
+ defaultValue,
417
+ defaultCountry,
418
+ countries
419
+ ]);
420
+ const initialNational = React$1.useMemo(() => {
421
+ if (defaultValue) {
422
+ const parsed = parseE164Number(defaultValue, countries);
423
+ if (parsed) return parsed.nationalNumber;
424
+ }
425
+ return "";
426
+ }, [defaultValue, countries]);
427
+ const [selectedCountry, setSelectedCountryState] = React$1.useState(initialCountry);
428
+ const [nationalNumber, setNationalNumberState] = React$1.useState(initialNational);
429
+ React$1.useEffect(() => {
430
+ if (valueProp !== void 0) {
431
+ const parsed = parseE164Number(valueProp, countries);
432
+ if (parsed) {
433
+ setSelectedCountryState(parsed.country);
434
+ setNationalNumberState(parsed.nationalNumber);
435
+ } else setNationalNumberState(valueProp.replace(/\D/g, ""));
436
+ }
437
+ }, [valueProp, countries]);
438
+ const e164Value = React$1.useMemo(() => {
439
+ const cleanDigits = nationalNumber.replace(/\D/g, "");
440
+ if (!cleanDigits) return "";
441
+ return `${selectedCountry.dialCode}${cleanDigits}`;
442
+ }, [selectedCountry, nationalNumber]);
443
+ const handleCountryChange = React$1.useCallback((newCountry) => {
444
+ setSelectedCountryState(newCountry);
445
+ const newE164 = nationalNumber.replace(/\D/g, "") ? `${newCountry.dialCode}${nationalNumber.replace(/\D/g, "")}` : "";
446
+ onChange?.(newE164, newCountry, nationalNumber);
447
+ }, [nationalNumber, onChange]);
448
+ const handleNationalNumberChange = React$1.useCallback((newNational) => {
449
+ if (newNational.trim().startsWith("+")) {
450
+ const parsed = parseE164Number(newNational.trim(), countries);
451
+ if (parsed) {
452
+ setSelectedCountryState(parsed.country);
453
+ setNationalNumberState(parsed.nationalNumber);
454
+ const newE164 = `${parsed.country.dialCode}${parsed.nationalNumber}`;
455
+ onChange?.(newE164, parsed.country, parsed.nationalNumber);
456
+ return;
457
+ }
458
+ }
459
+ const cleanDigits = newNational.replace(/\D/g, "");
460
+ setNationalNumberState(cleanDigits);
461
+ const newE164 = cleanDigits ? `${selectedCountry.dialCode}${cleanDigits}` : "";
462
+ onChange?.(newE164, selectedCountry, cleanDigits);
463
+ }, [
464
+ selectedCountry,
465
+ countries,
466
+ onChange
467
+ ]);
468
+ const contextValue = React$1.useMemo(() => ({
469
+ containerRef,
470
+ selectedCountry,
471
+ setSelectedCountry: handleCountryChange,
472
+ nationalNumber,
473
+ setNationalNumber: handleNationalNumberChange,
474
+ e164Value,
475
+ disabled,
476
+ readOnly,
477
+ countries,
478
+ onChange
479
+ }), [
480
+ selectedCountry,
481
+ handleCountryChange,
482
+ nationalNumber,
483
+ handleNationalNumberChange,
484
+ e164Value,
485
+ disabled,
486
+ readOnly,
487
+ countries,
488
+ onChange
489
+ ]);
490
+ return /* @__PURE__ */ jsx(InputGroup, {
491
+ ref: containerRef,
492
+ className: cn(inputPhoneVariants({
493
+ variant,
494
+ size
495
+ }), className),
496
+ "data-slot": "input-phone",
497
+ ...props,
498
+ children: /* @__PURE__ */ jsx(InputPhoneContext.Provider, {
499
+ value: contextValue,
500
+ children: children || /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(InputPhoneCountrySelect, {}), /* @__PURE__ */ jsx(InputPhoneInput, {})] })
501
+ })
502
+ });
503
+ }
504
+ function InputPhoneCountrySelect({ className, render, ...props }) {
505
+ const { containerRef, selectedCountry, setSelectedCountry, disabled, readOnly, countries } = useInputPhone();
506
+ const [open, setOpen] = React$1.useState(false);
507
+ const [search, setSearch] = React$1.useState("");
508
+ const filteredCountries = React$1.useMemo(() => {
509
+ if (!search.trim()) return countries;
510
+ const query = search.toLowerCase().trim();
511
+ return countries.filter((c) => c.name.toLowerCase().includes(query) || c.code.toLowerCase().includes(query) || c.dialCode.includes(query));
512
+ }, [search, countries]);
513
+ const defaultTriggerProps = {
514
+ type: "button",
515
+ disabled: disabled || readOnly,
516
+ "aria-label": `Select country, current ${selectedCountry.name} (${selectedCountry.dialCode})`,
517
+ className: cn("inline-flex items-center gap-1.5 pe-2.5 ps-1 py-1 text-sm font-medium text-foreground hover:bg-muted/40 transition-colors select-none focus-visible:outline-none disabled:pointer-events-none disabled:opacity-64 pointer-coarse:after:absolute pointer-coarse:after:min-h-11 shrink-0 border-r border-input/40", className),
518
+ "data-slot": "input-phone-country",
519
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
520
+ /* @__PURE__ */ jsx("span", {
521
+ className: "text-base leading-none select-none",
522
+ "data-slot": "input-phone-flag",
523
+ children: selectedCountry.flag
524
+ }),
525
+ /* @__PURE__ */ jsx("span", {
526
+ className: "text-xs font-semibold text-muted-foreground",
527
+ children: selectedCountry.dialCode
528
+ }),
529
+ /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5 opacity-60 shrink-0" })
530
+ ] })
531
+ };
532
+ return /* @__PURE__ */ jsx(InputGroupAddon, {
533
+ align: "inline-start",
534
+ className: "pe-0",
535
+ children: /* @__PURE__ */ jsxs(Popover, {
536
+ open,
537
+ onOpenChange: setOpen,
538
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, { render: useRender({
539
+ defaultTagName: "button",
540
+ props: mergeProps(defaultTriggerProps, props),
541
+ render
542
+ }) }), /* @__PURE__ */ jsxs(PopoverPopup, {
543
+ anchor: containerRef,
544
+ align: "start",
545
+ side: "bottom",
546
+ sideOffset: 4,
547
+ hideArrow: true,
548
+ collisionAvoidance: { fallbackAxisSide: "none" },
549
+ className: "w-(--anchor-width) **:data-[slot=popover-viewport]:p-2 **:data-[slot=popover-viewport]:[--viewport-inline-padding:--spacing(2)] z-50",
550
+ "data-slot": "input-phone-country-content",
551
+ children: [/* @__PURE__ */ jsxs("div", {
552
+ className: "relative mb-1 flex items-center gap-1.5 px-2 py-1 border-b border-border/40 pb-1.5",
553
+ children: [
554
+ /* @__PURE__ */ jsx(Search, { className: "size-3.5 text-muted-foreground shrink-0" }),
555
+ /* @__PURE__ */ jsx("input", {
556
+ type: "text",
557
+ "aria-label": "Search countries",
558
+ placeholder: "Search country or code...",
559
+ value: search,
560
+ onChange: (e) => setSearch(e.target.value),
561
+ className: "w-full bg-transparent text-xs text-foreground placeholder:text-muted-foreground/60 outline-none border-0 p-0"
562
+ }),
563
+ search && /* @__PURE__ */ jsx("button", {
564
+ type: "button",
565
+ "aria-label": "Clear country search",
566
+ onClick: () => setSearch(""),
567
+ className: "p-0.5 rounded text-muted-foreground hover:text-foreground",
568
+ children: /* @__PURE__ */ jsx(Cancel, { className: "size-3" })
569
+ })
570
+ ]
571
+ }), /* @__PURE__ */ jsx(ScrollArea, {
572
+ className: "max-h-[min(11rem,calc(var(--available-height,11rem)-3.5rem))] flex flex-col gap-0.5 text-xs",
573
+ children: filteredCountries.length === 0 ? /* @__PURE__ */ jsx("div", {
574
+ className: "p-2 text-center text-muted-foreground text-xs",
575
+ children: "No country found"
576
+ }) : filteredCountries.map((c, index) => {
577
+ const isSelected = c.code === selectedCountry.code;
578
+ return /* @__PURE__ */ jsxs("button", {
579
+ type: "button",
580
+ "aria-pressed": isSelected,
581
+ onClick: () => {
582
+ setSelectedCountry(c);
583
+ setOpen(false);
584
+ setSearch("");
585
+ },
586
+ className: cn("flex items-center justify-between gap-2 px-2 py-1 rounded-md text-left transition-colors w-full", isSelected ? "bg-accent text-accent-foreground font-medium" : "hover:bg-muted/60 text-foreground"),
587
+ children: [/* @__PURE__ */ jsxs("div", {
588
+ className: "flex items-center gap-1.5 truncate",
589
+ children: [/* @__PURE__ */ jsx("span", {
590
+ className: "text-xs leading-none",
591
+ children: c.flag
592
+ }), /* @__PURE__ */ jsx("span", {
593
+ className: "truncate text-xs",
594
+ children: c.name
595
+ })]
596
+ }), /* @__PURE__ */ jsxs("div", {
597
+ className: "flex items-center gap-1 shrink-0 font-mono text-[11px] text-muted-foreground",
598
+ children: [/* @__PURE__ */ jsx("span", { children: c.dialCode }), isSelected && /* @__PURE__ */ jsx(Check, { className: "size-3.5 text-primary" })]
599
+ })]
600
+ }, `${c.code}-${index}`);
601
+ })
602
+ })]
603
+ })]
604
+ })
605
+ });
606
+ }
607
+ function InputPhoneInput({ className, ...props }) {
608
+ const { selectedCountry, nationalNumber, setNationalNumber, disabled, readOnly } = useInputPhone();
609
+ const formattedDisplay = React$1.useMemo(() => {
610
+ return formatPhoneNumber(nationalNumber, selectedCountry.mask);
611
+ }, [nationalNumber, selectedCountry.mask]);
612
+ const handleChange = (e) => {
613
+ setNationalNumber(e.target.value);
614
+ };
615
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(InputGroupInput, {
616
+ type: "tel",
617
+ value: formattedDisplay,
618
+ onChange: handleChange,
619
+ disabled,
620
+ readOnly,
621
+ placeholder: selectedCountry.mask || "Phone number",
622
+ "aria-label": "Phone number",
623
+ className: cn("w-full bg-transparent px-[calc(--spacing(3)-1px)] py-1.5 text-foreground placeholder:text-muted-foreground/60 font-mono border-0 shadow-none ring-0", className),
624
+ "data-slot": "input-phone-number",
625
+ ...props
626
+ }), nationalNumber && !disabled && !readOnly && /* @__PURE__ */ jsx(InputGroupAddon, {
627
+ align: "inline-end",
628
+ children: /* @__PURE__ */ jsx("button", {
629
+ type: "button",
630
+ onClick: () => setNationalNumber(""),
631
+ className: "p-1 rounded-full text-muted-foreground/60 hover:text-foreground hover:bg-muted/40 transition-colors pointer-coarse:after:absolute pointer-coarse:after:size-8",
632
+ "aria-label": "Clear Phone Number",
633
+ children: /* @__PURE__ */ jsx(Cancel, { className: "size-3.5" })
634
+ })
635
+ })] });
636
+ }
637
+ function InputPhoneFlag({ className, code, render, children, ...props }) {
638
+ const context = React$1.useContext(InputPhoneContext);
639
+ const targetCountry = code ? COUNTRIES.find((c) => c.code.toUpperCase() === code.toUpperCase()) : context?.selectedCountry;
640
+ const defaultProps = {
641
+ className: cn("inline-flex items-center justify-center text-base leading-none select-none", className),
642
+ "data-slot": "input-phone-flag",
643
+ children: children || targetCountry?.flag || "🌐"
644
+ };
645
+ return useRender({
646
+ defaultTagName: "span",
647
+ props: mergeProps(defaultProps, props),
648
+ render
649
+ });
650
+ }
651
+ const PhoneInput = InputPhone;
652
+ const PhoneInputCountrySelect = InputPhoneCountrySelect;
653
+ const PhoneInputFlag = InputPhoneFlag;
654
+ const PhoneInputInput = InputPhoneInput;
655
+ const phoneInputVariants = inputPhoneVariants;
656
+ //#endregion
657
+ export { COUNTRIES, InputPhone, InputPhoneCountrySelect, InputPhoneFlag, InputPhoneInput, PhoneInput, PhoneInputCountrySelect, PhoneInputFlag, PhoneInputInput, formatPhoneNumber, inputPhoneVariants, parseE164Number, phoneInputVariants, useInputPhone, usePhoneInput };
@@ -0,0 +1,12 @@
1
+ import * as React$1 from "react";
2
+ import { Input } from "@base-ui/react/input";
3
+ //#region src/components/input-sensitive.d.ts
4
+ type InputSensitiveProps = Omit<Input.Props, "size" | "className" | "style" | "type"> & {
5
+ size?: "sm" | "default" | "lg" | number;
6
+ className?: string;
7
+ style?: React$1.CSSProperties;
8
+ onCopy?: () => void;
9
+ };
10
+ declare function InputSensitive({ className, size, onCopy, onChange, onBlur, onKeyDown, disabled, readOnly, ...props }: InputSensitiveProps): React$1.JSX.Element;
11
+ //#endregion
12
+ export { InputSensitive, type InputSensitiveProps };