@catalystsoftware/ui 1.0.4 → 1.0.5

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 (157) hide show
  1. package/data/tailwind.config.js +261 -3821
  2. package/dist/components/catalyst-ui/buttons/burger.tsx +207 -0
  3. package/dist/components/catalyst-ui/core/data-display/timeline.tsx +210 -0
  4. package/dist/components/catalyst-ui/core/feedback/alert.tsx +491 -0
  5. package/dist/components/catalyst-ui/core/feedback/spinner-1.tsx +65 -0
  6. package/dist/components/catalyst-ui/core/feedback/toast.tsx +1857 -0
  7. package/dist/components/catalyst-ui/core/navigation/menu.tsx +164 -0
  8. package/dist/components/catalyst-ui/forms/toggle-class.tsx +176 -0
  9. package/dist/components/catalyst-ui/hooks/use-copy-to-clipboard.tsx +419 -0
  10. package/dist/components/catalyst-ui/hooks/use-counter.tsx +13 -0
  11. package/dist/components/catalyst-ui/hooks/use-event-listener.tsx +23 -0
  12. package/dist/components/catalyst-ui/hooks/use-export-markdown.tsx +47 -0
  13. package/dist/components/catalyst-ui/hooks/use-focus.tsx +17 -0
  14. package/dist/components/catalyst-ui/hooks/use-interval.tsx +23 -0
  15. package/dist/components/catalyst-ui/hooks/use-is-client.tsx +16 -0
  16. package/dist/components/catalyst-ui/hooks/use-media-query.tsx +19 -0
  17. package/dist/components/catalyst-ui/hooks/use-mobile.tsx +19 -0
  18. package/dist/components/catalyst-ui/hooks/use-resize-observer.tsx +81 -0
  19. package/dist/components/catalyst-ui/hooks/use-timeout.tsx +21 -0
  20. package/dist/components/catalyst-ui/hooks/use-timer.tsx +209 -0
  21. package/dist/components/catalyst-ui/hooks/use-toggle.tsx +12 -0
  22. package/dist/components/catalyst-ui/media/image.tsx +13 -0
  23. package/dist/components/catalyst-ui/overlays/dual-sidebar.tsx +4142 -0
  24. package/dist/components/catalyst-ui/overlays/sidebar-original.tsx +726 -0
  25. package/dist/components/catalyst-ui/primitives/accordion.tsx +250 -0
  26. package/dist/components/catalyst-ui/primitives/alert-dialog.tsx +126 -0
  27. package/dist/components/catalyst-ui/primitives/aspect-ratio.tsx +9 -0
  28. package/dist/components/catalyst-ui/primitives/avatar.tsx +296 -0
  29. package/dist/components/catalyst-ui/primitives/badge.tsx +57 -0
  30. package/dist/components/catalyst-ui/primitives/breadcrumb.tsx +101 -0
  31. package/dist/components/catalyst-ui/primitives/button.tsx +265 -0
  32. package/dist/components/catalyst-ui/primitives/calendar-v4.tsx +208 -0
  33. package/dist/components/catalyst-ui/primitives/calendar.tsx +295 -0
  34. package/dist/components/catalyst-ui/primitives/card.tsx +618 -0
  35. package/dist/components/catalyst-ui/primitives/carousel.tsx +238 -0
  36. package/dist/components/catalyst-ui/primitives/chart.tsx +347 -0
  37. package/dist/components/catalyst-ui/primitives/checkbox.tsx +225 -0
  38. package/dist/components/catalyst-ui/primitives/collapsible.tsx +212 -0
  39. package/dist/components/catalyst-ui/primitives/command.tsx +393 -0
  40. package/dist/components/catalyst-ui/primitives/context-menu.tsx +236 -0
  41. package/dist/components/catalyst-ui/primitives/dialog.tsx +471 -0
  42. package/dist/components/catalyst-ui/primitives/drawer.tsx +761 -0
  43. package/dist/components/catalyst-ui/primitives/dropdown-menu.tsx +290 -0
  44. package/dist/components/catalyst-ui/primitives/empty.tsx +104 -0
  45. package/dist/components/catalyst-ui/primitives/field.tsx +244 -0
  46. package/dist/components/catalyst-ui/primitives/hover-card.tsx +124 -0
  47. package/dist/components/catalyst-ui/primitives/input-otp.tsx +76 -0
  48. package/dist/components/catalyst-ui/primitives/input.tsx +64 -0
  49. package/dist/components/catalyst-ui/primitives/item.tsx +196 -0
  50. package/dist/components/catalyst-ui/primitives/kbd.tsx +75 -0
  51. package/dist/components/catalyst-ui/primitives/label.tsx +24 -0
  52. package/dist/components/catalyst-ui/primitives/navigation-menu.tsx +150 -0
  53. package/dist/components/catalyst-ui/primitives/pagination.tsx +198 -0
  54. package/dist/components/catalyst-ui/primitives/popover.tsx +232 -0
  55. package/dist/components/catalyst-ui/primitives/progress.tsx +34 -0
  56. package/dist/components/catalyst-ui/primitives/radio-group.tsx +43 -0
  57. package/dist/components/catalyst-ui/primitives/resizable.tsx +56 -0
  58. package/dist/components/catalyst-ui/primitives/select.tsx +155 -0
  59. package/dist/components/catalyst-ui/primitives/separator.tsx +74 -0
  60. package/dist/components/catalyst-ui/primitives/sheet.tsx +126 -0
  61. package/dist/components/catalyst-ui/primitives/skeleton.tsx +15 -0
  62. package/dist/components/catalyst-ui/primitives/slider.tsx +27 -0
  63. package/dist/components/catalyst-ui/primitives/switch.tsx +187 -0
  64. package/dist/components/catalyst-ui/primitives/tabs.tsx +335 -0
  65. package/dist/components/catalyst-ui/primitives/textarea.tsx +24 -0
  66. package/dist/components/catalyst-ui/primitives/toggle-group.tsx +55 -0
  67. package/dist/components/catalyst-ui/primitives/toggle.tsx +42 -0
  68. package/dist/components/catalyst-ui/primitives/tooltip.tsx +116 -0
  69. package/dist/components/catalyst-ui/utils/basic-auth.tsx +40 -0
  70. package/dist/components/catalyst-ui/utils/context-storage.tsx +19 -0
  71. package/dist/components/catalyst-ui/utils/cors-middleware.tsx +71 -0
  72. package/dist/components/catalyst-ui/utils/deferred-content.tsx +595 -0
  73. package/dist/components/catalyst-ui/utils/honeypot-middleware.tsx +38 -0
  74. package/dist/components/catalyst-ui/utils/incId.tsx +75 -0
  75. package/dist/components/catalyst-ui/utils/jwk-auth.tsx +36 -0
  76. package/dist/components/catalyst-ui/utils/request-id.tsx +14 -0
  77. package/dist/components/catalyst-ui/utils/secure-headers.tsx +37 -0
  78. package/dist/components/catalyst-ui/utils/server-timing.tsx +23 -0
  79. package/dist/components/catalyst-ui/utils/utils.ts +43 -0
  80. package/dist/components/catalyst-ui/utils/with-cookie.tsx +43 -0
  81. package/dist/components/catalyst-ui/x/accordian-x.tsx +428 -0
  82. package/dist/components/catalyst-ui/x/alert-x.tsx +413 -0
  83. package/dist/components/catalyst-ui/x/animated-text-x.tsx +2242 -0
  84. package/dist/components/catalyst-ui/x/avatar-x.tsx +515 -0
  85. package/dist/components/catalyst-ui/x/badge-x.tsx +670 -0
  86. package/dist/components/catalyst-ui/x/button-X.tsx +2857 -0
  87. package/dist/components/catalyst-ui/x/button-group-x.tsx +847 -0
  88. package/dist/components/catalyst-ui/x/calendar-x.tsx +1910 -0
  89. package/dist/components/catalyst-ui/x/card-x.tsx +2597 -0
  90. package/dist/components/catalyst-ui/x/checkbox-x.tsx +656 -0
  91. package/dist/components/catalyst-ui/x/collapsible-x.tsx +1360 -0
  92. package/dist/components/catalyst-ui/x/combobox-x.tsx +911 -0
  93. package/dist/components/catalyst-ui/x/data-table-x.tsx +1753 -0
  94. package/dist/components/catalyst-ui/x/date-picker-x.tsx +648 -0
  95. package/dist/components/catalyst-ui/x/dialog-x.tsx +659 -0
  96. package/dist/components/catalyst-ui/x/dropdown-menu-x.tsx +612 -0
  97. package/dist/components/catalyst-ui/x/hover-card-x.tsx +375 -0
  98. package/dist/components/catalyst-ui/x/icon-x.tsx +840 -0
  99. package/dist/components/catalyst-ui/x/input-mask-x.tsx +981 -0
  100. package/dist/components/catalyst-ui/x/input-otp-x.tsx +659 -0
  101. package/dist/components/catalyst-ui/x/loader-x.tsx +1757 -0
  102. package/dist/components/catalyst-ui/x/pagination-x.tsx +622 -0
  103. package/dist/components/catalyst-ui/x/popover-x.tsx +744 -0
  104. package/dist/components/catalyst-ui/x/radio-group-x.tsx +499 -0
  105. package/dist/components/catalyst-ui/x/select-x.tsx +1127 -0
  106. package/dist/components/catalyst-ui/x/sheet-x.tsx +668 -0
  107. package/dist/components/catalyst-ui/x/switch-x.tsx +681 -0
  108. package/dist/components/catalyst-ui/x/table-x.tsx +574 -0
  109. package/dist/components/catalyst-ui/x/tabs-x.tsx +839 -0
  110. package/dist/components/catalyst-ui/x/textarea-x.tsx +1263 -0
  111. package/dist/components/catalyst-ui/x/tooltip-x.tsx +396 -0
  112. package/dist/components/catalyst-ui/x/tracker-x.tsx +560 -0
  113. package/dist/data/bg-data.tsx +901 -0
  114. package/dist/data/buttons-data.tsx +2327 -0
  115. package/dist/data/charts-data.tsx +102 -0
  116. package/dist/data/chat-data.tsx +83 -0
  117. package/dist/data/code-data.tsx +1040 -0
  118. package/dist/data/comboboxes-data.tsx +1843 -0
  119. package/dist/data/command-data.tsx +1381 -0
  120. package/dist/data/core-data.tsx +15953 -0
  121. package/dist/data/crm-data.tsx +47 -0
  122. package/dist/data/data.tsx +159 -0
  123. package/dist/data/date-and-time-data.tsx +554 -0
  124. package/dist/data/dependencies.tsx +7 -0
  125. package/dist/data/ecommerce-data.tsx +1387 -0
  126. package/dist/data/forms-data.tsx +7890 -0
  127. package/dist/data/hooks-data.tsx +5487 -0
  128. package/dist/data/index.ts +34 -0
  129. package/dist/data/inputs-data.tsx +557 -0
  130. package/dist/data/interactive-data.tsx +5394 -0
  131. package/dist/data/lofi-data.tsx +18295 -0
  132. package/dist/data/marketing-data.tsx +2546 -0
  133. package/dist/data/media-data.tsx +1510 -0
  134. package/dist/data/motion-data.tsx +5801 -0
  135. package/dist/data/overlay-data.tsx +4136 -0
  136. package/dist/data/pdf-data.tsx +124 -0
  137. package/dist/data/pos-data.tsx +213 -0
  138. package/dist/data/postcss.config.js +6 -0
  139. package/dist/data/primitive-data.tsx +5170 -0
  140. package/dist/data/prompt-data.tsx +1226 -0
  141. package/dist/data/requiredLibs.ts +4 -0
  142. package/dist/data/sandbox-data.tsx +1 -0
  143. package/dist/data/sidebars-data.tsx +5421 -0
  144. package/dist/data/stacks-data.tsx +32 -0
  145. package/dist/data/table-data.tsx +706 -0
  146. package/dist/data/tailwind.config.js +270 -0
  147. package/dist/data/tailwind.config.ngin.js +3830 -0
  148. package/dist/data/tailwind.css +431 -0
  149. package/dist/data/tools-data.tsx +6910 -0
  150. package/dist/data/typography-data.tsx +2050 -0
  151. package/dist/data/utils-data.tsx +6500 -0
  152. package/dist/data/x-data.tsx +1171 -0
  153. package/dist/data.tsx +159 -0
  154. package/package.json +1 -1
  155. package/dist/index.d.ts +0 -3
  156. package/dist/index.d.ts.map +0 -1
  157. package/dist/index.js.map +0 -362
@@ -0,0 +1,981 @@
1
+ 'use client'
2
+
3
+ import React, { useId } from 'react'
4
+ import { withMask } from 'use-mask-input'
5
+ import { cva } from 'class-variance-authority'
6
+ import { CreditCard } from 'lucide-react'
7
+ import { cn } from '~/components/catalyst-ui'
8
+ import { Input, useValidateCreditCard } from '~/components/catalyst-ui'
9
+ import { Field, FieldLabel, FieldDescription, FieldError } from '~/components/catalyst-ui'
10
+
11
+ /**
12
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ InputMaskX Component ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
13
+ * ★ ━━━━ ☆ ━━━━ ━━━━ ☆ ━━━━ ★
14
+ * InputMaskX: A collection of input components with various masking patterns for structured data entry
15
+ *
16
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Basic Input Mask ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
17
+ * ```jsx
18
+ * // Default input
19
+ * <InputMaskX label="Default Input" placeholder="Enter text" />
20
+ *
21
+ * // Custom mask pattern
22
+ * <InputMaskX
23
+ * inputMask="WithMask"
24
+ * label="License Plate"
25
+ * mask="AA99 AAA"
26
+ * placeholder="AB12 CDE"
27
+ * />
28
+ *
29
+ * // Time input with mask
30
+ * <InputMaskX
31
+ * inputMask="Time"
32
+ * label="Time"
33
+ * placeholder="HH:MM:SS"
34
+ * />
35
+ * ```
36
+ *
37
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Credit Card Inputs ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
38
+ * ```jsx
39
+ * // Card number with auto-detection
40
+ * <InputMaskX
41
+ * inputMask="CardNumber"
42
+ * label="Credit Card Number"
43
+ * placeholder="1234 5678 9012 3456"
44
+ * />
45
+ *
46
+ * // Expiry date
47
+ * <InputMaskX
48
+ * inputMask="ExpiryDate"
49
+ * label="Expiration Date"
50
+ * placeholder="MM/YY"
51
+ * />
52
+ *
53
+ * // CVC code
54
+ * <InputMaskX
55
+ * inputMask="CVCCode"
56
+ * label="CVC"
57
+ * placeholder="123"
58
+ * />
59
+ *
60
+ * // Complete card form
61
+ * <InputMaskX
62
+ * inputMask="CardDetails"
63
+ * label="Card Information"
64
+ * />
65
+ * ```
66
+ *
67
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Custom Mask Patterns ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
68
+ * ```jsx
69
+ * // Phone number
70
+ * <InputMaskX
71
+ * inputMask="WithMask"
72
+ * label="Phone Number"
73
+ * mask="(999) 999-9999"
74
+ * placeholder="(123) 456-7890"
75
+ * />
76
+ *
77
+ * // Social Security Number
78
+ * <InputMaskX
79
+ * inputMask="WithMask"
80
+ * label="SSN"
81
+ * mask="999-99-9999"
82
+ * placeholder="123-45-6789"
83
+ * />
84
+ *
85
+ * // Postal/ZIP Code
86
+ * <InputMaskX
87
+ * inputMask="WithMask"
88
+ * label="ZIP Code"
89
+ * mask="99999-9999"
90
+ * placeholder="12345-6789"
91
+ * />
92
+ *
93
+ * // Date
94
+ * <InputMaskX
95
+ * inputMask="WithMask"
96
+ * label="Date"
97
+ * mask="99/99/9999"
98
+ * placeholder="MM/DD/YYYY"
99
+ * />
100
+ * ```
101
+ *
102
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Custom Styling Variations ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
103
+ * ```jsx
104
+ * // Filled variant
105
+ * <InputMaskX
106
+ * inputMask="CardNumber"
107
+ * variant="filled"
108
+ * label="Card Number"
109
+ * />
110
+ *
111
+ * // Small size
112
+ * <InputMaskX
113
+ * inputMask="CVCCode"
114
+ * size="sm"
115
+ * label="CVC"
116
+ * />
117
+ *
118
+ * // Large size
119
+ * <InputMaskX
120
+ * inputMask="ExpiryDate"
121
+ * size="lg"
122
+ * label="Expiry"
123
+ * />
124
+ *
125
+ * // Error state
126
+ * <InputMaskX
127
+ * inputMask="CardNumber"
128
+ * state="error"
129
+ * label="Invalid Card"
130
+ * error="Please enter a valid card number"
131
+ * />
132
+ *
133
+ * // Success state
134
+ * <InputMaskX
135
+ * inputMask="CardNumber"
136
+ * state="success"
137
+ * label="Valid Card"
138
+ * />
139
+ *
140
+ * // Rounded variants
141
+ * <InputMaskX
142
+ * inputMask="WithMask"
143
+ * rounded="lg"
144
+ * label="Rounded Input"
145
+ * mask="AAA-999"
146
+ * />
147
+ * ```
148
+ *
149
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ With Icons and Visuals ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
150
+ * ```jsx
151
+ * // Card number with icon
152
+ * <InputMaskX
153
+ * inputMask="CardNumber"
154
+ * label="Card Number"
155
+ * // Shows card type icon (Visa, Mastercard, etc.) automatically
156
+ * />
157
+ *
158
+ * // Custom icon placement
159
+ * <div className="relative">
160
+ * <InputMaskX
161
+ * inputMask="WithMask"
162
+ * label="Phone"
163
+ * mask="(999) 999-9999"
164
+ * className="pl-10" // Space for icon
165
+ * />
166
+ * <Phone className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2" />
167
+ * </div>
168
+ * ```
169
+ *
170
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Complete Payment Form ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
171
+ * ```jsx
172
+ * function PaymentForm() {
173
+ * const [cardNumber, setCardNumber] = useState('')
174
+ * const [expiry, setExpiry] = useState('')
175
+ * const [cvc, setCVC] = useState('')
176
+ *
177
+ * return (
178
+ * <div className="space-y-4 max-w-md">
179
+ * <InputMaskX
180
+ * inputMask="CardNumber"
181
+ * label="Card Number"
182
+ * value={cardNumber}
183
+ * onChange={(e) => setCardNumber(e.target.value)}
184
+ * />
185
+ *
186
+ * <div className="grid grid-cols-2 gap-4">
187
+ * <InputMaskX
188
+ * inputMask="ExpiryDate"
189
+ * label="Expiry Date"
190
+ * value={expiry}
191
+ * onChange={(e) => setExpiry(e.target.value)}
192
+ * />
193
+ * <InputMaskX
194
+ * inputMask="CVCCode"
195
+ * label="CVC"
196
+ * value={cvc}
197
+ * onChange={(e) => setCVC(e.target.value)}
198
+ * />
199
+ * </div>
200
+ *
201
+ * <button className="w-full bg-blue-600 text-white py-2 rounded">
202
+ * Pay Now
203
+ * </button>
204
+ * </div>
205
+ * )
206
+ * }
207
+ * ```
208
+ *
209
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Available Input Mask Types ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
210
+ * 1. **default** - Regular input without mask
211
+ * 2. **WithMask** - Custom mask pattern
212
+ * 3. **Time** - Time input (HH:MM:SS format)
213
+ * 4. **CardNumber** - Credit card number with validation
214
+ * 5. **ExpiryDate** - Card expiry date (MM/YY)
215
+ * 6. **CVCCode** - Card security code
216
+ * 7. **CardDetails** - Combined card form (number + expiry + CVC)
217
+ *
218
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Mask Pattern Syntax ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
219
+ * ```jsx
220
+ * // Common mask patterns
221
+ * <InputMaskX
222
+ * inputMask="WithMask"
223
+ * mask="999-999-9999" // Numbers only
224
+ * />
225
+ *
226
+ * <InputMaskX
227
+ * inputMask="WithMask"
228
+ * mask="AAA-999" // Letters then numbers
229
+ * />
230
+ *
231
+ * <InputMaskX
232
+ * inputMask="WithMask"
233
+ * mask="**** **** **** 9999" // Fixed characters with numbers
234
+ * />
235
+ *
236
+ * // Date/time patterns
237
+ * <InputMaskX
238
+ * inputMask="Time"
239
+ * // Automatically uses HH:MM:SS format
240
+ * />
241
+ *
242
+ * // Custom datetime
243
+ * <InputMaskX
244
+ * inputMask="WithMask"
245
+ * mask="datetime"
246
+ * // Additional props: inputFormat, outputFormat
247
+ * />
248
+ * ```
249
+ *
250
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Props Reference ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
251
+ * - **Common Props**:
252
+ * - `inputMask`: string - Type of mask to apply
253
+ * - `label`: string - Input field label
254
+ * - `description`: string - Helper text
255
+ * - `error`: string - Error message
256
+ * - `placeholder`: string - Placeholder text
257
+ * - `value`: string - Controlled value
258
+ * - `onChange`: (e: React.ChangeEvent) => void - Change handler
259
+ *
260
+ * - **WithMask Specific Props**:
261
+ * - `mask`: string - Mask pattern (e.g., "999-999-9999")
262
+ * - `showMaskOnHover`: boolean - Show mask on hover
263
+ *
264
+ * - **Time Specific Props**:
265
+ * - `inputFormat`: string - Input format (default: "HH:MM:ss")
266
+ * - `outputFormat`: string - Output format (default: "HH:MM:ss")
267
+ *
268
+ * - **Styling Props** (via inputMaskVariants):
269
+ * - `variant`: 'default' | 'filled' | 'ghost'
270
+ * - `size`: 'sm' | 'default' | 'lg'
271
+ * - `rounded`: 'sm' | 'default' | 'lg' | 'full' | 'none'
272
+ * - `state`: 'default' | 'error' | 'success'
273
+ * - `className`: string - Additional CSS classes
274
+ *
275
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Validation Features ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
276
+ * ```jsx
277
+ * // Card number validation
278
+ * <InputMaskX
279
+ * inputMask="CardNumber"
280
+ * label="Card Number"
281
+ * // Automatically validates: Luhn algorithm, card type detection
282
+ * />
283
+ *
284
+ * // Expiry date validation
285
+ * <InputMaskX
286
+ * inputMask="ExpiryDate"
287
+ * label="Expiry"
288
+ * // Validates: Not expired, valid month/year format
289
+ * />
290
+ *
291
+ * // Custom validation
292
+ * function CustomValidationExample() {
293
+ * const [value, setValue] = useState('')
294
+ * const [error, setError] = useState('')
295
+ *
296
+ * const validate = (input: string) => {
297
+ * if (!input.match(/^AB\d{2} CDE$/)) {
298
+ * setError('Invalid format')
299
+ * } else {
300
+ * setError('')
301
+ * }
302
+ * }
303
+ *
304
+ * return (
305
+ * <InputMaskX
306
+ * inputMask="WithMask"
307
+ * label="Custom Pattern"
308
+ * mask="AB99 CDE"
309
+ * value={value}
310
+ * onChange={(e) => {
311
+ * setValue(e.target.value)
312
+ * validate(e.target.value)
313
+ * }}
314
+ * error={error}
315
+ * />
316
+ * )
317
+ * }
318
+ * ```
319
+ *
320
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Accessibility Features ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
321
+ * - **Auto IDs**: Automatic ID generation for label association
322
+ * - **Screen Reader**: All labels and descriptions accessible
323
+ * - **Keyboard Navigation**: Full keyboard support
324
+ * - **Focus Management**: Clear focus indicators
325
+ * - **ARIA Attributes**: Proper role and state attributes
326
+ *
327
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Usage Examples ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
328
+ * ```jsx
329
+ * // Registration form
330
+ * function RegistrationForm() {
331
+ * return (
332
+ * <div className="space-y-4">
333
+ * <InputMaskX label="Full Name" placeholder="John Doe" />
334
+ * <InputMaskX
335
+ * inputMask="WithMask"
336
+ * label="Phone"
337
+ * mask="(999) 999-9999"
338
+ * placeholder="(123) 456-7890"
339
+ * />
340
+ * <InputMaskX
341
+ * inputMask="WithMask"
342
+ * label="SSN"
343
+ * mask="999-99-9999"
344
+ * placeholder="123-45-6789"
345
+ * />
346
+ * </div>
347
+ * )
348
+ * }
349
+ *
350
+ * // Booking system
351
+ * function BookingForm() {
352
+ * return (
353
+ * <div className="space-y-4">
354
+ * <InputMaskX
355
+ * inputMask="WithMask"
356
+ * label="Booking Reference"
357
+ * mask="AAA-9999"
358
+ * placeholder="ABC-1234"
359
+ * />
360
+ * <InputMaskX
361
+ * inputMask="Time"
362
+ * label="Check-in Time"
363
+ * placeholder="14:00:00"
364
+ * />
365
+ * <InputMaskX
366
+ * inputMask="CardDetails"
367
+ * label="Payment Information"
368
+ * />
369
+ * </div>
370
+ * )
371
+ * }
372
+ *
373
+ * // Settings form
374
+ * function SettingsForm() {
375
+ * return (
376
+ * <div className="space-y-4">
377
+ * <InputMaskX
378
+ * inputMask="WithMask"
379
+ * label="API Key"
380
+ * mask="****-****-****-****"
381
+ * placeholder="••••-••••-••••-••••"
382
+ * />
383
+ * <InputMaskX
384
+ * inputMask="Time"
385
+ * label="Schedule Time"
386
+ * placeholder="09:00:00"
387
+ * />
388
+ * <InputMaskX
389
+ * variant="filled"
390
+ * size="sm"
391
+ * label="Short Code"
392
+ * placeholder="ABC123"
393
+ * />
394
+ * </div>
395
+ * )
396
+ * }
397
+ * ```
398
+ *
399
+ * ★ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━ Integration with Form Libraries ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ☆ ━━━━━━━━━━━━━━ ★
400
+ * ```jsx
401
+ * // With React Hook Form
402
+ * import { useForm } from 'react-hook-form'
403
+ *
404
+ * function HookFormExample() {
405
+ * const { register, handleSubmit } = useForm()
406
+ *
407
+ * return (
408
+ * <form onSubmit={handleSubmit(data => console.log(data))}>
409
+ * <InputMaskX
410
+ * inputMask="CardNumber"
411
+ * label="Card Number"
412
+ * {...register('cardNumber', { required: true })}
413
+ * />
414
+ * <InputMaskX
415
+ * inputMask="ExpiryDate"
416
+ * label="Expiry"
417
+ * {...register('expiry', { required: true })}
418
+ * />
419
+ * <button type="submit">Submit</button>
420
+ * </form>
421
+ * )
422
+ * }
423
+ *
424
+ * // With Formik
425
+ * import { useField } from 'formik'
426
+ *
427
+ * function FormikField({ label, ...props }) {
428
+ * const [field, meta] = useField(props)
429
+ *
430
+ * return (
431
+ * <InputMaskX
432
+ * label={label}
433
+ * {...field}
434
+ * error={meta.touched && meta.error ? meta.error : ''}
435
+ * {...props}
436
+ * />
437
+ * )
438
+ * }
439
+ * ```
440
+ *
441
+ */
442
+
443
+ // #region CVA VARIANTS
444
+ export const inputMaskVariants = cva(
445
+ 'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
446
+ {
447
+ variants: {
448
+ variant: {
449
+ default: '',
450
+ filled: 'bg-muted border-transparent shadow-none',
451
+ ghost: 'border-transparent shadow-none',
452
+ },
453
+ size: {
454
+ sm: 'h-8 text-xs',
455
+ default: 'h-10',
456
+ lg: 'h-12 text-base',
457
+ },
458
+ rounded: {
459
+ default: 'rounded-md',
460
+ sm: 'rounded-sm',
461
+ lg: 'rounded-lg',
462
+ full: 'rounded-full',
463
+ none: 'rounded-none',
464
+ },
465
+ state: {
466
+ default: '',
467
+ error: 'border-destructive focus-visible:ring-destructive',
468
+ success: 'border-green-500 focus-visible:ring-green-500',
469
+ },
470
+ },
471
+ defaultVariants: {
472
+ variant: 'default',
473
+ size: 'default',
474
+ rounded: 'default',
475
+ state: 'default',
476
+ },
477
+ }
478
+ )
479
+ // #endregion
480
+
481
+ // #region PARENT FUNCTION
482
+ export function InputMaskX({ inputMask = 'default', ...props }: any) {
483
+ switch (inputMask) {
484
+ case 'WithMask':
485
+ return <WithMask {...props} />
486
+ case 'Time':
487
+ return <Time {...props} />
488
+ case 'CardNumber':
489
+ return <CardNumber {...props} />
490
+ case 'ExpiryDate':
491
+ return <ExpiryDate {...props} />
492
+ case 'CVCCode':
493
+ return <CVCCode {...props} />
494
+ case 'CardDetails':
495
+ return <CardDetails {...props} />
496
+ default:
497
+ return <DefaultInputMask {...props} />
498
+ }
499
+ }
500
+ // #endregion
501
+
502
+ // #region SUPPORTING FUNCTIONS
503
+ const DefaultInputMask = ({ label, description, error, variant, size, rounded, state, className, ...props }: any) => {
504
+ const id = useId()
505
+ return (
506
+ <Field className='w-full max-w-xs space-y-2'>
507
+ {label && <FieldLabel htmlFor={id}>{label}</FieldLabel>}
508
+ <Input
509
+ id={id}
510
+ className={cn(inputMaskVariants({ variant, size, rounded, state }), className)}
511
+ {...props}
512
+ />
513
+ {description && <FieldDescription>{description}</FieldDescription>}
514
+ {error && <FieldError>{error}</FieldError>}
515
+ </Field>
516
+ )
517
+ }
518
+
519
+ const WithMask = ({ label = 'Input with mask', description, error, variant, size, rounded, state, className, mask = 'AA99 AAA', placeholder = 'AB12 CDE', ...props }: any) => {
520
+ const id = useId()
521
+ return (
522
+ <Field className='w-full max-w-xs space-y-2'>
523
+ <FieldLabel htmlFor={id}>{label}</FieldLabel>
524
+ <Input
525
+ id={id}
526
+ type='text'
527
+ placeholder={placeholder}
528
+ ref={withMask(mask, {
529
+ placeholder: '_',
530
+ showMaskOnHover: false
531
+ })}
532
+ className={cn(inputMaskVariants({ variant, size, rounded, state }), className)}
533
+ {...props}
534
+ />
535
+ {description && <FieldDescription>{description}</FieldDescription>}
536
+ {error && <FieldError>{error}</FieldError>}
537
+ <p className='text-muted-foreground text-xs'>
538
+ Built with{' '}
539
+ <a
540
+ className='hover:text-foreground underline'
541
+ href='https://github.com/eduardoborges/use-mask-input'
542
+ target='_blank'
543
+ rel='noopener noreferrer'
544
+ >
545
+ use-mask-input
546
+ </a>
547
+ </p>
548
+ </Field>
549
+ )
550
+ }
551
+
552
+ const Time = ({ label = 'Input time', description, error, variant, size, rounded, state, className, placeholder = '00:00:00', ...props }: any) => {
553
+ const id = useId()
554
+ return (
555
+ <Field className='w-full max-w-xs space-y-2'>
556
+ <FieldLabel htmlFor={id}>{label}</FieldLabel>
557
+ <Input
558
+ id={id}
559
+ type='text'
560
+ placeholder={placeholder}
561
+ ref={withMask('datetime', {
562
+ placeholder: '_',
563
+ inputFormat: 'HH:MM:ss',
564
+ outputFormat: 'HH:MM:ss',
565
+ showMaskOnHover: false
566
+ })}
567
+ className={cn(inputMaskVariants({ variant, size, rounded, state }), className)}
568
+ {...props}
569
+ />
570
+ {description && <FieldDescription>{description}</FieldDescription>}
571
+ {error && <FieldError>{error}</FieldError>}
572
+ <p className='text-muted-foreground text-xs'>
573
+ Built with{' '}
574
+ <a
575
+ className='hover:text-foreground underline'
576
+ href='https://github.com/eduardoborges/use-mask-input'
577
+ target='_blank'
578
+ rel='noopener noreferrer'
579
+ >
580
+ use-mask-input
581
+ </a>
582
+ </p>
583
+ </Field>
584
+ )
585
+ }
586
+
587
+ const CardNumber = ({ label = 'Card number', description, error, variant, size, rounded, state, className, ...props }: any) => {
588
+ const id = useId()
589
+ const { getCardNumberProps, getCardIcon } = useValidateCreditCard()
590
+ const CardIcon = getCardIcon()
591
+
592
+ return (
593
+ <Field className='w-full max-w-xs space-y-2'>
594
+ <FieldLabel htmlFor={id}>{label}</FieldLabel>
595
+ <div className='relative'>
596
+ <Input
597
+ {...getCardNumberProps()}
598
+ id={id}
599
+ className={cn(inputMaskVariants({ variant, size, rounded, state }), 'peer pr-11', className)}
600
+ {...props}
601
+ />
602
+ <div className='text-muted-foreground pointer-events-none absolute inset-y-0 right-0 flex items-center justify-center pr-3 peer-disabled:opacity-50'>
603
+ <CardIcon className='size-6' />
604
+ <span className='sr-only'>Card Provider</span>
605
+ </div>
606
+ </div>
607
+ {description && <FieldDescription>{description}</FieldDescription>}
608
+ {error && <FieldError>{error}</FieldError>}
609
+ <p className='text-muted-foreground text-xs'>
610
+ Built with custom validation
611
+ </p>
612
+ </Field>
613
+ )
614
+ }
615
+
616
+ const ExpiryDate = ({ label = 'Expiry date', description, error, variant, size, rounded, state, className, placeholder = 'MM/YY', ...props }: any) => {
617
+ const id = useId()
618
+ return (
619
+ <Field className='w-full max-w-xs space-y-2'>
620
+ <FieldLabel htmlFor={id}>{label}</FieldLabel>
621
+ <Input
622
+ id={id}
623
+ type='text'
624
+ placeholder={placeholder}
625
+ ref={withMask('99/99', {
626
+ placeholder: '_',
627
+ showMaskOnHover: false
628
+ })}
629
+ className={cn(inputMaskVariants({ variant, size, rounded, state }), className)}
630
+ {...props}
631
+ />
632
+ {description && <FieldDescription>{description}</FieldDescription>}
633
+ {error && <FieldError>{error}</FieldError>}
634
+ </Field>
635
+ )
636
+ }
637
+
638
+ const CVCCode = ({ label = 'CVC code', description, error, variant, size, rounded, state, className, placeholder = '123', ...props }: any) => {
639
+ const id = useId()
640
+ return (
641
+ <Field className='w-full max-w-xs space-y-2'>
642
+ <FieldLabel htmlFor={id}>{label}</FieldLabel>
643
+ <Input
644
+ id={id}
645
+ type='text'
646
+ placeholder={placeholder}
647
+ ref={withMask('999', {
648
+ placeholder: '_',
649
+ showMaskOnHover: false
650
+ })}
651
+ className={cn(inputMaskVariants({ variant, size, rounded, state }), className)}
652
+ {...props}
653
+ />
654
+ {description && <FieldDescription>{description}</FieldDescription>}
655
+ {error && <FieldError>{error}</FieldError>}
656
+ </Field>
657
+ )
658
+ }
659
+
660
+ const CardDetails = ({ label = 'Card details', description, error, variant, size, rounded, state, className, ...props }: any) => {
661
+ const id = useId()
662
+ const { getCardNumberProps, getCardIcon } = useValidateCreditCard()
663
+ const CardIcon = getCardIcon()
664
+
665
+ return (
666
+ <Field className='w-full max-w-xs space-y-2'>
667
+ <FieldLabel>{label}</FieldLabel>
668
+ <div>
669
+ <div className='relative focus-within:z-1'>
670
+ <Input
671
+ {...getCardNumberProps()}
672
+ id={`number-${id}`}
673
+ className={cn(inputMaskVariants({ variant, size, rounded, state }), 'peer rounded-b-none pr-9 shadow-none', className)}
674
+ {...props}
675
+ />
676
+ <div className='text-muted-foreground pointer-events-none absolute inset-y-0 right-0 flex items-center justify-center pr-3 peer-disabled:opacity-50'>
677
+ <CardIcon className='size-6' />
678
+ <span className='sr-only'>Card Provider</span>
679
+ </div>
680
+ </div>
681
+ <div className='-mt-px flex'>
682
+ <div className='min-w-0 flex-1 focus-within:z-1'>
683
+ <Input
684
+ type='text'
685
+ placeholder='MM/YY'
686
+ ref={withMask('99/99', {
687
+ placeholder: '_',
688
+ showMaskOnHover: false
689
+ })}
690
+ id={`expiry-${id}`}
691
+ className={cn(inputMaskVariants({ variant, size, rounded, state }), 'rounded-t-none rounded-r-none shadow-none')}
692
+ />
693
+ </div>
694
+ <div className='-ms-px min-w-0 flex-1 focus-within:z-1'>
695
+ <Input
696
+ type='text'
697
+ placeholder='123'
698
+ ref={withMask('999', {
699
+ placeholder: '_',
700
+ showMaskOnHover: false
701
+ })}
702
+ id={`cvc-${id}`}
703
+ className={cn(inputMaskVariants({ variant, size, rounded, state }), 'rounded-t-none rounded-l-none shadow-none')}
704
+ />
705
+ </div>
706
+ </div>
707
+ </div>
708
+ {description && <FieldDescription>{description}</FieldDescription>}
709
+ {error && <FieldError>{error}</FieldError>}
710
+ <p className='text-muted-foreground text-xs'>
711
+ Built with custom validation
712
+ </p>
713
+ </Field>
714
+ )
715
+ }
716
+ // #endregion
717
+
718
+ // #region DEMO
719
+ export function InputMaskXDemo() {
720
+ return (
721
+ <div className='space-y-12 p-6 max-w-3xl mx-auto'>
722
+ <div>
723
+ <h3 className='text-lg font-semibold mb-4'>Default</h3>
724
+ <InputMaskX label='Default Input' placeholder='Enter text' />
725
+ </div>
726
+
727
+ <div>
728
+ <h3 className='text-lg font-semibold mb-4'>With Mask</h3>
729
+ <InputMaskX inputMask='WithMask' />
730
+ </div>
731
+
732
+ <div>
733
+ <h3 className='text-lg font-semibold mb-4'>Time Input</h3>
734
+ <InputMaskX inputMask='Time' />
735
+ </div>
736
+
737
+ <div>
738
+ <h3 className='text-lg font-semibold mb-4'>Card Number</h3>
739
+ <InputMaskX inputMask='CardNumber' />
740
+ </div>
741
+
742
+ <div>
743
+ <h3 className='text-lg font-semibold mb-4'>Expiry Date</h3>
744
+ <InputMaskX inputMask='ExpiryDate' />
745
+ </div>
746
+
747
+ <div>
748
+ <h3 className='text-lg font-semibold mb-4'>CVC Code</h3>
749
+ <InputMaskX inputMask='CVCCode' />
750
+ </div>
751
+
752
+ <div>
753
+ <h3 className='text-lg font-semibold mb-4'>Card Details (Combined)</h3>
754
+ <InputMaskX inputMask='CardDetails' />
755
+ </div>
756
+ </div>
757
+ )
758
+ }
759
+ // #endregion
760
+
761
+
762
+ /**
763
+
764
+
765
+
766
+
767
+
768
+
769
+ export function InputMaskX({ inputMask = 'default', children, ...props }: any) {
770
+ switch (inputMask) {
771
+ case 'Closable':
772
+ break
773
+ default:
774
+ break;
775
+ }
776
+ }
777
+
778
+ const InputWithMaskDemo = () => {
779
+ const id = useId()
780
+
781
+ return (
782
+ <div className='w-full max-w-xs space-y-2'>
783
+ <Label htmlFor={id}>Input with mask</Label>
784
+ <Input
785
+ id={id}
786
+ type='text'
787
+ placeholder='AB12 CDE'
788
+ ref={withMask('AA99 AAA', {
789
+ placeholder: '_',
790
+ showMaskOnHover: false
791
+ })}
792
+ />
793
+ <p className='text-muted-foreground text-xs'>
794
+ Built with{' '}
795
+ <a
796
+ className='hover:text-foreground underline'
797
+ href='https://github.com/eduardoborges/use-mask-input'
798
+ target='_blank'
799
+ rel='noopener noreferrer'
800
+ >
801
+ use-mask-input
802
+ </a>
803
+ </p>
804
+ </div>
805
+ )
806
+ }
807
+
808
+ const InputTimeDemo = () => {
809
+ const id = useId()
810
+
811
+ return (
812
+ <div className='w-full max-w-xs space-y-2'>
813
+ <Label htmlFor={id}>Input time</Label>
814
+ <Input
815
+ id={id}
816
+ type='text'
817
+ placeholder='00:00:00'
818
+ ref={withMask('datetime', {
819
+ placeholder: '_',
820
+ inputFormat: 'HH:MM:ss',
821
+ outputFormat: 'HH:MM:ss',
822
+ showMaskOnHover: false
823
+ })}
824
+ />
825
+ <p className='text-muted-foreground text-xs'>
826
+ Built with{' '}
827
+ <a
828
+ className='hover:text-foreground underline'
829
+ href='https://github.com/eduardoborges/use-mask-input'
830
+ target='_blank'
831
+ rel='noopener noreferrer'
832
+ >
833
+ use-mask-input
834
+ </a>
835
+ </p>
836
+ </div>
837
+ )
838
+ }
839
+
840
+ const InputCardNumberDemo = () => {
841
+ const id = useId()
842
+ const { meta, getCardNumberProps, getCardImageProps } = usePaymentInputs()
843
+
844
+ return (
845
+ <div className='w-full max-w-xs space-y-2'>
846
+ <Label htmlFor={id}>Card number</Label>
847
+ <div className='relative'>
848
+ <Input {...getCardNumberProps()} id={id} className='peer pr-11' />
849
+ <div className='text-muted-foreground pointer-events-none absolute inset-y-0 right-0 flex items-center justify-center pr-3 peer-disabled:opacity-50'>
850
+ {meta.cardType ? (
851
+ <svg
852
+ className='w-6 overflow-hidden'
853
+ {...getCardImageProps({
854
+ images: images as unknown as CardImages
855
+ })}
856
+ />
857
+ ) : (
858
+ <CreditCardIcon className='size-4' />
859
+ )}
860
+ <span className='sr-only'>Card Provider</span>
861
+ </div>
862
+ </div>
863
+ <p className='text-muted-foreground text-xs'>
864
+ Built with{' '}
865
+ <a
866
+ className='hover:text-foreground underline'
867
+ href='https://github.com/medipass/react-payment-inputs'
868
+ target='_blank'
869
+ rel='noopener noreferrer'
870
+ >
871
+ React Payment Inputs
872
+ </a>
873
+ </p>
874
+ </div>
875
+ )
876
+ }
877
+
878
+ const InputExpiryDateDemo = () => {
879
+ const id = useId()
880
+ const { getExpiryDateProps } = usePaymentInputs()
881
+
882
+ return (
883
+ <div className='w-full max-w-xs space-y-2'>
884
+ <Label htmlFor={id}>Expiry date</Label>
885
+ <Input {...getExpiryDateProps()} id={id} />
886
+ <p className='text-muted-foreground text-xs'>
887
+ Built with{' '}
888
+ <a
889
+ className='hover:text-foreground underline'
890
+ href='https://github.com/medipass/react-payment-inputs'
891
+ target='_blank'
892
+ rel='noopener noreferrer'
893
+ >
894
+ React Payment Inputs
895
+ </a>
896
+ </p>
897
+ </div>
898
+ )
899
+ }
900
+
901
+ const InputCVCCodeDemo = () => {
902
+ const id = useId()
903
+ const { getCVCProps } = usePaymentInputs()
904
+
905
+ return (
906
+ <div className='w-full max-w-xs space-y-2'>
907
+ <Label htmlFor={id}>CVC code</Label>
908
+ <Input {...getCVCProps()} id={id} />
909
+ <p className='text-muted-foreground text-xs'>
910
+ Built with{' '}
911
+ <a
912
+ className='hover:text-foreground underline'
913
+ href='https://github.com/medipass/react-payment-inputs'
914
+ target='_blank'
915
+ rel='noopener noreferrer'
916
+ >
917
+ React Payment Inputs
918
+ </a>
919
+ </p>
920
+ </div>
921
+ )
922
+ }
923
+
924
+ const InputCardDetailsDemo = () => {
925
+ const id = useId()
926
+ const { meta, getCardNumberProps, getExpiryDateProps, getCVCProps, getCardImageProps } = usePaymentInputs()
927
+
928
+ return (
929
+ <div className='w-full max-w-xs space-y-2'>
930
+ <Label>Card details</Label>
931
+ <div>
932
+ <div className='relative focus-within:z-1'>
933
+ <Input {...getCardNumberProps()} id={`number-${id}`} className='peer rounded-b-none pr-9 shadow-none' />
934
+ <div className='text-muted-foreground pointer-events-none absolute inset-y-0 right-0 flex items-center justify-center pr-3 peer-disabled:opacity-50'>
935
+ {meta.cardType ? (
936
+ <svg
937
+ className='w-6 overflow-hidden'
938
+ {...getCardImageProps({
939
+ images: images as unknown as CardImages
940
+ })}
941
+ />
942
+ ) : (
943
+ <CreditCardIcon className='size-4' />
944
+ )}
945
+ <span className='sr-only'>Card Provider</span>
946
+ </div>
947
+ </div>
948
+ <div className='-mt-px flex'>
949
+ <div className='min-w-0 flex-1 focus-within:z-1'>
950
+ <Input
951
+ {...getExpiryDateProps()}
952
+ id={`expiry-${id}`}
953
+ className='rounded-t-none rounded-r-none shadow-none'
954
+ />
955
+ </div>
956
+ <div className='-ms-px min-w-0 flex-1 focus-within:z-1'>
957
+ <Input {...getCVCProps()} id={`cvc-${id}`} className='rounded-t-none rounded-l-none shadow-none' />
958
+ </div>
959
+ </div>
960
+ </div>
961
+ <p className='text-muted-foreground text-xs'>
962
+ Built with{' '}
963
+ <a
964
+ className='hover:text-foreground underline'
965
+ href='https://github.com/medipass/react-payment-inputs'
966
+ target='_blank'
967
+ rel='noopener noreferrer'
968
+ >
969
+ React Payment Inputs
970
+ </a>
971
+ </p>
972
+ </div>
973
+ )
974
+ } */
975
+
976
+
977
+
978
+
979
+
980
+
981
+