@xsolla/xui-input-payment 0.64.0-pr56.1768440195

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.
@@ -0,0 +1,944 @@
1
+ // src/InputPayment.tsx
2
+ import React4, { useState, forwardRef as forwardRef3, useRef, useEffect } from "react";
3
+
4
+ // ../primitives-native/src/Box.tsx
5
+ import {
6
+ View,
7
+ Pressable,
8
+ Image
9
+ } from "react-native";
10
+ import { jsx } from "react/jsx-runtime";
11
+ var Box = ({
12
+ children,
13
+ onPress,
14
+ onLayout,
15
+ onMoveShouldSetResponder,
16
+ onResponderGrant,
17
+ onResponderMove,
18
+ onResponderRelease,
19
+ onResponderTerminate,
20
+ backgroundColor,
21
+ borderColor,
22
+ borderWidth,
23
+ borderBottomWidth,
24
+ borderBottomColor,
25
+ borderTopWidth,
26
+ borderTopColor,
27
+ borderLeftWidth,
28
+ borderLeftColor,
29
+ borderRightWidth,
30
+ borderRightColor,
31
+ borderRadius,
32
+ borderStyle,
33
+ height,
34
+ padding,
35
+ paddingHorizontal,
36
+ paddingVertical,
37
+ margin,
38
+ marginTop,
39
+ marginBottom,
40
+ marginLeft,
41
+ marginRight,
42
+ flexDirection,
43
+ alignItems,
44
+ justifyContent,
45
+ position,
46
+ top,
47
+ bottom,
48
+ left,
49
+ right,
50
+ width,
51
+ flex,
52
+ overflow,
53
+ zIndex,
54
+ hoverStyle,
55
+ pressStyle,
56
+ style,
57
+ "data-testid": dataTestId,
58
+ testID,
59
+ as,
60
+ src,
61
+ alt,
62
+ ...rest
63
+ }) => {
64
+ const getContainerStyle = (pressed) => ({
65
+ backgroundColor: pressed && pressStyle?.backgroundColor ? pressStyle.backgroundColor : backgroundColor,
66
+ borderColor,
67
+ borderWidth,
68
+ borderBottomWidth,
69
+ borderBottomColor,
70
+ borderTopWidth,
71
+ borderTopColor,
72
+ borderLeftWidth,
73
+ borderLeftColor,
74
+ borderRightWidth,
75
+ borderRightColor,
76
+ borderRadius,
77
+ borderStyle,
78
+ overflow,
79
+ zIndex,
80
+ height,
81
+ width,
82
+ padding,
83
+ paddingHorizontal,
84
+ paddingVertical,
85
+ margin,
86
+ marginTop,
87
+ marginBottom,
88
+ marginLeft,
89
+ marginRight,
90
+ flexDirection,
91
+ alignItems,
92
+ justifyContent,
93
+ position,
94
+ top,
95
+ bottom,
96
+ left,
97
+ right,
98
+ flex,
99
+ ...style
100
+ });
101
+ const finalTestID = dataTestId || testID;
102
+ const {
103
+ role,
104
+ tabIndex,
105
+ onKeyDown,
106
+ onKeyUp,
107
+ "aria-label": _ariaLabel,
108
+ "aria-labelledby": _ariaLabelledBy,
109
+ "aria-current": _ariaCurrent,
110
+ "aria-disabled": _ariaDisabled,
111
+ "aria-live": _ariaLive,
112
+ className,
113
+ "data-testid": _dataTestId,
114
+ ...nativeRest
115
+ } = rest;
116
+ if (as === "img" && src) {
117
+ const imageStyle = {
118
+ width,
119
+ height,
120
+ borderRadius,
121
+ position,
122
+ top,
123
+ bottom,
124
+ left,
125
+ right,
126
+ ...style
127
+ };
128
+ return /* @__PURE__ */ jsx(
129
+ Image,
130
+ {
131
+ source: { uri: src },
132
+ style: imageStyle,
133
+ testID: finalTestID,
134
+ resizeMode: "cover",
135
+ ...nativeRest
136
+ }
137
+ );
138
+ }
139
+ if (onPress) {
140
+ return /* @__PURE__ */ jsx(
141
+ Pressable,
142
+ {
143
+ onPress,
144
+ onLayout,
145
+ onMoveShouldSetResponder,
146
+ onResponderGrant,
147
+ onResponderMove,
148
+ onResponderRelease,
149
+ onResponderTerminate,
150
+ style: ({ pressed }) => getContainerStyle(pressed),
151
+ testID: finalTestID,
152
+ ...nativeRest,
153
+ children
154
+ }
155
+ );
156
+ }
157
+ return /* @__PURE__ */ jsx(
158
+ View,
159
+ {
160
+ style: getContainerStyle(),
161
+ testID: finalTestID,
162
+ onLayout,
163
+ onMoveShouldSetResponder,
164
+ onResponderGrant,
165
+ onResponderMove,
166
+ onResponderRelease,
167
+ onResponderTerminate,
168
+ ...nativeRest,
169
+ children
170
+ }
171
+ );
172
+ };
173
+
174
+ // ../primitives-native/src/Text.tsx
175
+ import { Text as RNText } from "react-native";
176
+ import { jsx as jsx2 } from "react/jsx-runtime";
177
+ var roleMap = {
178
+ alert: "alert",
179
+ heading: "header",
180
+ button: "button",
181
+ link: "link",
182
+ text: "text"
183
+ };
184
+ var Text = ({
185
+ children,
186
+ color,
187
+ fontSize,
188
+ fontWeight,
189
+ fontFamily,
190
+ id,
191
+ role,
192
+ ...props
193
+ }) => {
194
+ let resolvedFontFamily = fontFamily ? fontFamily.split(",")[0].replace(/['"]/g, "").trim() : void 0;
195
+ if (resolvedFontFamily === "Pilat Wide Bold") {
196
+ resolvedFontFamily = void 0;
197
+ }
198
+ const style = {
199
+ color,
200
+ fontSize: typeof fontSize === "number" ? fontSize : void 0,
201
+ fontWeight,
202
+ fontFamily: resolvedFontFamily,
203
+ textDecorationLine: props.textDecoration
204
+ };
205
+ const accessibilityRole = role ? roleMap[role] : void 0;
206
+ return /* @__PURE__ */ jsx2(RNText, { style, testID: id, accessibilityRole, children });
207
+ };
208
+
209
+ // ../primitives-native/src/Spinner.tsx
210
+ import { ActivityIndicator, View as View2 } from "react-native";
211
+ import { jsx as jsx3 } from "react/jsx-runtime";
212
+ var Spinner = ({
213
+ color,
214
+ size,
215
+ role,
216
+ "aria-label": ariaLabel,
217
+ "aria-live": ariaLive,
218
+ "aria-describedby": ariaDescribedBy,
219
+ testID
220
+ }) => {
221
+ return /* @__PURE__ */ jsx3(
222
+ View2,
223
+ {
224
+ accessible: true,
225
+ accessibilityRole: role === "status" ? "none" : void 0,
226
+ accessibilityLabel: ariaLabel,
227
+ accessibilityLiveRegion: ariaLive === "polite" ? "polite" : ariaLive === "assertive" ? "assertive" : "none",
228
+ testID,
229
+ children: /* @__PURE__ */ jsx3(
230
+ ActivityIndicator,
231
+ {
232
+ color,
233
+ size: typeof size === "number" ? size : "small"
234
+ }
235
+ )
236
+ }
237
+ );
238
+ };
239
+ Spinner.displayName = "Spinner";
240
+
241
+ // ../primitives-native/src/Icon.tsx
242
+ import React from "react";
243
+ import { View as View3 } from "react-native";
244
+ import { jsx as jsx4 } from "react/jsx-runtime";
245
+
246
+ // ../primitives-native/src/Divider.tsx
247
+ import { View as View4 } from "react-native";
248
+ import { jsx as jsx5 } from "react/jsx-runtime";
249
+
250
+ // ../primitives-native/src/Input.tsx
251
+ import { forwardRef } from "react";
252
+ import { TextInput as RNTextInput } from "react-native";
253
+ import { jsx as jsx6 } from "react/jsx-runtime";
254
+ var keyboardTypeMap = {
255
+ text: "default",
256
+ number: "numeric",
257
+ email: "email-address",
258
+ tel: "phone-pad",
259
+ url: "url",
260
+ decimal: "decimal-pad"
261
+ };
262
+ var inputModeToKeyboardType = {
263
+ none: "default",
264
+ text: "default",
265
+ decimal: "decimal-pad",
266
+ numeric: "number-pad",
267
+ tel: "phone-pad",
268
+ search: "default",
269
+ email: "email-address",
270
+ url: "url"
271
+ };
272
+ var autoCompleteToTextContentType = {
273
+ "one-time-code": "oneTimeCode",
274
+ email: "emailAddress",
275
+ username: "username",
276
+ password: "password",
277
+ "new-password": "newPassword",
278
+ tel: "telephoneNumber",
279
+ "postal-code": "postalCode",
280
+ name: "name"
281
+ };
282
+ var InputPrimitive = forwardRef(
283
+ ({
284
+ value,
285
+ placeholder,
286
+ onChange,
287
+ onChangeText,
288
+ onFocus,
289
+ onBlur,
290
+ onKeyDown,
291
+ disabled,
292
+ secureTextEntry,
293
+ style,
294
+ color,
295
+ fontSize,
296
+ placeholderTextColor,
297
+ maxLength,
298
+ name,
299
+ type,
300
+ inputMode,
301
+ autoComplete,
302
+ id,
303
+ "aria-invalid": ariaInvalid,
304
+ "aria-describedby": ariaDescribedBy,
305
+ "aria-labelledby": ariaLabelledBy,
306
+ "aria-label": ariaLabel,
307
+ "aria-disabled": ariaDisabled,
308
+ "data-testid": dataTestId
309
+ }, ref) => {
310
+ const handleChangeText = (text) => {
311
+ onChangeText?.(text);
312
+ if (onChange) {
313
+ const syntheticEvent = {
314
+ target: { value: text },
315
+ currentTarget: { value: text },
316
+ type: "change",
317
+ nativeEvent: { text },
318
+ preventDefault: () => {
319
+ },
320
+ stopPropagation: () => {
321
+ },
322
+ isTrusted: false
323
+ };
324
+ onChange(syntheticEvent);
325
+ }
326
+ };
327
+ const keyboardType = inputMode ? inputModeToKeyboardType[inputMode] || "default" : type ? keyboardTypeMap[type] || "default" : "default";
328
+ const textContentType = autoComplete ? autoCompleteToTextContentType[autoComplete] : void 0;
329
+ return /* @__PURE__ */ jsx6(
330
+ RNTextInput,
331
+ {
332
+ ref,
333
+ value,
334
+ placeholder,
335
+ onChangeText: handleChangeText,
336
+ onFocus,
337
+ onBlur,
338
+ onKeyPress: (e) => {
339
+ if (onKeyDown) {
340
+ onKeyDown({
341
+ key: e.nativeEvent.key,
342
+ preventDefault: () => {
343
+ }
344
+ });
345
+ }
346
+ },
347
+ editable: !disabled,
348
+ secureTextEntry: secureTextEntry || type === "password",
349
+ keyboardType,
350
+ textContentType,
351
+ style: [
352
+ {
353
+ color,
354
+ fontSize: typeof fontSize === "number" ? fontSize : void 0,
355
+ flex: 1,
356
+ padding: 0,
357
+ textAlign: style?.textAlign || "left"
358
+ },
359
+ style
360
+ ],
361
+ placeholderTextColor,
362
+ maxLength,
363
+ testID: dataTestId || id,
364
+ accessibilityLabel: ariaLabel,
365
+ accessibilityHint: ariaDescribedBy,
366
+ accessibilityState: {
367
+ disabled: disabled || ariaDisabled
368
+ },
369
+ accessible: true
370
+ }
371
+ );
372
+ }
373
+ );
374
+ InputPrimitive.displayName = "InputPrimitive";
375
+
376
+ // ../primitives-native/src/TextArea.tsx
377
+ import { forwardRef as forwardRef2 } from "react";
378
+ import { TextInput as RNTextInput2 } from "react-native";
379
+ import { jsx as jsx7 } from "react/jsx-runtime";
380
+ var TextAreaPrimitive = forwardRef2(
381
+ ({
382
+ value,
383
+ placeholder,
384
+ onChange,
385
+ onChangeText,
386
+ onFocus,
387
+ onBlur,
388
+ onKeyDown,
389
+ disabled,
390
+ style,
391
+ color,
392
+ fontSize,
393
+ placeholderTextColor,
394
+ maxLength,
395
+ rows,
396
+ id,
397
+ "aria-invalid": ariaInvalid,
398
+ "aria-describedby": ariaDescribedBy,
399
+ "aria-labelledby": ariaLabelledBy,
400
+ "aria-label": ariaLabel,
401
+ "aria-disabled": ariaDisabled,
402
+ "data-testid": dataTestId
403
+ }, ref) => {
404
+ const handleChangeText = (text) => {
405
+ onChangeText?.(text);
406
+ if (onChange) {
407
+ const syntheticEvent = {
408
+ target: { value: text },
409
+ currentTarget: { value: text },
410
+ type: "change",
411
+ nativeEvent: { text },
412
+ preventDefault: () => {
413
+ },
414
+ stopPropagation: () => {
415
+ },
416
+ isTrusted: false
417
+ };
418
+ onChange(syntheticEvent);
419
+ }
420
+ };
421
+ return /* @__PURE__ */ jsx7(
422
+ RNTextInput2,
423
+ {
424
+ ref,
425
+ value,
426
+ placeholder,
427
+ onChangeText: handleChangeText,
428
+ onFocus,
429
+ onBlur,
430
+ onKeyPress: (e) => {
431
+ if (onKeyDown) {
432
+ onKeyDown({
433
+ key: e.nativeEvent.key,
434
+ preventDefault: () => {
435
+ }
436
+ });
437
+ }
438
+ },
439
+ editable: !disabled,
440
+ multiline: true,
441
+ numberOfLines: rows || 4,
442
+ style: [
443
+ {
444
+ color,
445
+ fontSize: typeof fontSize === "number" ? fontSize : void 0,
446
+ flex: 1,
447
+ padding: 0,
448
+ textAlignVertical: "top",
449
+ textAlign: style?.textAlign || "left"
450
+ },
451
+ style
452
+ ],
453
+ placeholderTextColor,
454
+ maxLength,
455
+ testID: dataTestId || id,
456
+ accessibilityLabel: ariaLabel,
457
+ accessibilityHint: ariaDescribedBy,
458
+ accessibilityState: {
459
+ disabled: disabled || ariaDisabled
460
+ },
461
+ accessible: true
462
+ }
463
+ );
464
+ }
465
+ );
466
+ TextAreaPrimitive.displayName = "TextAreaPrimitive";
467
+
468
+ // src/InputPayment.tsx
469
+ import { useDesignSystem, useId, isWeb } from "@xsolla/xui-core";
470
+ import {
471
+ Visa,
472
+ Mastercard,
473
+ Maestro,
474
+ AmericanExpress,
475
+ Dinersclub,
476
+ Discover,
477
+ Jcb,
478
+ Unionpay,
479
+ Aura,
480
+ CartesBancaires,
481
+ Cirrus,
482
+ Dankort,
483
+ Elo,
484
+ Hipercard,
485
+ Mir,
486
+ Naranja,
487
+ Paypal,
488
+ Sodexo,
489
+ Uatp
490
+ } from "@xsolla/xui-icons-payment";
491
+ import { jsx as jsx8, jsxs } from "react/jsx-runtime";
492
+ var DEFAULT_POSSIBLE_PAYMENTS = [
493
+ "mastercard",
494
+ "visa",
495
+ "maestro",
496
+ "diners",
497
+ "amex",
498
+ "discover",
499
+ "jcb",
500
+ "unionpay"
501
+ ];
502
+ var paymentIconComponents = {
503
+ visa: Visa,
504
+ mastercard: Mastercard,
505
+ maestro: Maestro,
506
+ amex: AmericanExpress,
507
+ diners: Dinersclub,
508
+ discover: Discover,
509
+ jcb: Jcb,
510
+ unionpay: Unionpay,
511
+ aura: Aura,
512
+ cartesbancaires: CartesBancaires,
513
+ cirrus: Cirrus,
514
+ dankort: Dankort,
515
+ elo: Elo,
516
+ hipercard: Hipercard,
517
+ mir: Mir,
518
+ naranja: Naranja,
519
+ paypal: Paypal,
520
+ sodexo: Sodexo,
521
+ uatp: Uatp
522
+ };
523
+ var detectPaymentSystem = (cardNumber) => {
524
+ const cleanNumber = cardNumber.replace(/\s/g, "");
525
+ if (!cleanNumber) return null;
526
+ if (/^1/.test(cleanNumber)) return "uatp";
527
+ if (/^220[0-4]/.test(cleanNumber)) return "mir";
528
+ if (/^3[47]/.test(cleanNumber)) return "amex";
529
+ if (/^3(?:0[0-5]|[68])/.test(cleanNumber)) return "diners";
530
+ if (/^35(?:2[89]|[3-8])/.test(cleanNumber)) return "jcb";
531
+ if (/^(401178|401179|431274|438935|451416|457393|457631|457632|504175|506699|5067[0-9]{2}|509[0-9]{3}|627780|636297|636368|650[0-9]{3}|651[0-9]{3}|655[0-9]{3})/.test(
532
+ cleanNumber
533
+ ))
534
+ return "elo";
535
+ if (/^4/.test(cleanNumber)) return "visa";
536
+ if (/^(606282|637095|637568|637599|637609|637612)/.test(cleanNumber))
537
+ return "hipercard";
538
+ if (/^507860/.test(cleanNumber)) return "aura";
539
+ if (/^5019/.test(cleanNumber)) return "dankort";
540
+ if (/^589562/.test(cleanNumber)) return "naranja";
541
+ if (/^5[1-5]/.test(cleanNumber)) return "mastercard";
542
+ if (cleanNumber.length >= 4 && /^(?:222[1-9]|22[3-9]\d|2[3-6]\d{2}|27[01]\d|2720)/.test(cleanNumber))
543
+ return "mastercard";
544
+ if (/^(?:6011|65|64[4-9])/.test(cleanNumber)) return "discover";
545
+ if (cleanNumber.length >= 6 && /^(?:6221(?:2[6-9]|[3-9]\d)|622[2-8]\d{2}|6229(?:[01]\d|2[0-5]))/.test(cleanNumber))
546
+ return "discover";
547
+ if (/^62/.test(cleanNumber)) return "unionpay";
548
+ if (/^(?:5[06-9]|6)/.test(cleanNumber)) return "maestro";
549
+ return null;
550
+ };
551
+ var CARD_GAP = 4;
552
+ var PaymentIcons = ({ possiblePayments, maxVisible, recognizedPayment, iconHeight }) => {
553
+ const [cyclingIndex, setCyclingIndex] = useState(0);
554
+ const [isTransitioning, setIsTransitioning] = useState(false);
555
+ const [isRecognized, setIsRecognized] = useState(false);
556
+ const scaledCardHeight = iconHeight;
557
+ const scaledCardWidth = Math.round(iconHeight * (4 / 3));
558
+ const scaledGap = CARD_GAP;
559
+ const constantCards = possiblePayments.slice(0, maxVisible - 1);
560
+ const cyclingCards = possiblePayments.slice(maxVisible - 1);
561
+ useEffect(() => {
562
+ if (recognizedPayment) {
563
+ setIsRecognized(true);
564
+ } else {
565
+ const timeout = setTimeout(() => {
566
+ setIsRecognized(false);
567
+ }, 50);
568
+ return () => clearTimeout(timeout);
569
+ }
570
+ }, [recognizedPayment]);
571
+ useEffect(() => {
572
+ if (cyclingCards.length <= 1 || recognizedPayment) return;
573
+ const interval = setInterval(() => {
574
+ setIsTransitioning(true);
575
+ setTimeout(() => {
576
+ setCyclingIndex((prev) => (prev + 1) % cyclingCards.length);
577
+ setIsTransitioning(false);
578
+ }, 150);
579
+ }, 2e3);
580
+ return () => clearInterval(interval);
581
+ }, [cyclingCards.length, recognizedPayment]);
582
+ const paymentLabels = {
583
+ mastercard: "Mastercard",
584
+ visa: "Visa",
585
+ maestro: "Maestro",
586
+ diners: "Diners Club",
587
+ amex: "American Express",
588
+ discover: "Discover",
589
+ jcb: "JCB",
590
+ unionpay: "UnionPay",
591
+ aura: "Aura",
592
+ cartesbancaires: "Cartes Bancaires",
593
+ cirrus: "Cirrus",
594
+ dankort: "Dankort",
595
+ elo: "Elo",
596
+ hipercard: "Hipercard",
597
+ mir: "Mir",
598
+ naranja: "Naranja",
599
+ paypal: "PayPal",
600
+ sodexo: "Sodexo",
601
+ uatp: "UATP"
602
+ };
603
+ const getAriaLabel = () => {
604
+ if (recognizedPayment) {
605
+ return `Recognized payment: ${paymentLabels[recognizedPayment]}`;
606
+ }
607
+ return `Accepted payment cards: ${possiblePayments.map((key) => paymentLabels[key]).join(", ")}`;
608
+ };
609
+ const totalVisibleCards = Math.min(possiblePayments.length, maxVisible);
610
+ const containerWidth = totalVisibleCards * scaledCardWidth + (totalVisibleCards - 1) * scaledGap;
611
+ return /* @__PURE__ */ jsxs(
612
+ Box,
613
+ {
614
+ flexDirection: "row",
615
+ alignItems: "center",
616
+ role: "img",
617
+ "aria-label": getAriaLabel(),
618
+ position: "relative",
619
+ width: containerWidth,
620
+ height: scaledCardHeight,
621
+ style: { overflow: "hidden" },
622
+ children: [
623
+ constantCards.map((key, index) => {
624
+ const IconComponent = paymentIconComponents[key];
625
+ const isRecognizedCard = recognizedPayment === key;
626
+ let translateX = 0;
627
+ let opacity = 1;
628
+ if (isRecognized && recognizedPayment) {
629
+ if (isRecognizedCard) {
630
+ const targetPosition = (totalVisibleCards - 1) * (scaledCardWidth + scaledGap);
631
+ const currentPosition = index * (scaledCardWidth + scaledGap);
632
+ translateX = targetPosition - currentPosition;
633
+ opacity = 1;
634
+ } else {
635
+ translateX = containerWidth;
636
+ opacity = 0;
637
+ }
638
+ }
639
+ return /* @__PURE__ */ jsx8(
640
+ Box,
641
+ {
642
+ position: "absolute",
643
+ left: index * (scaledCardWidth + scaledGap),
644
+ style: {
645
+ transform: isWeb ? `translateX(${translateX}px)` : void 0,
646
+ opacity,
647
+ ...isWeb && { transition: "transform 300ms ease-out, opacity 300ms ease-out" }
648
+ },
649
+ children: /* @__PURE__ */ jsx8(IconComponent, { size: scaledCardHeight })
650
+ },
651
+ key
652
+ );
653
+ }),
654
+ cyclingCards.length > 0 && /* @__PURE__ */ jsx8(
655
+ Box,
656
+ {
657
+ position: "absolute",
658
+ left: (maxVisible - 1) * (scaledCardWidth + scaledGap),
659
+ width: scaledCardWidth,
660
+ height: scaledCardHeight,
661
+ children: cyclingCards.map((key, index) => {
662
+ const IconComponent = paymentIconComponents[key];
663
+ const isCurrentCycling = index === cyclingIndex;
664
+ const isRecognizedCard = recognizedPayment === key;
665
+ let translateX = 0;
666
+ let opacity = isCurrentCycling && !isTransitioning ? 1 : 0;
667
+ if (isRecognized && recognizedPayment) {
668
+ if (isRecognizedCard) {
669
+ opacity = 1;
670
+ } else {
671
+ translateX = containerWidth;
672
+ opacity = 0;
673
+ }
674
+ }
675
+ return /* @__PURE__ */ jsx8(
676
+ Box,
677
+ {
678
+ position: "absolute",
679
+ top: 0,
680
+ left: 0,
681
+ style: {
682
+ transform: isWeb ? `translateX(${translateX}px)` : void 0,
683
+ opacity,
684
+ ...isWeb && {
685
+ transition: isRecognized ? "transform 300ms ease-out, opacity 300ms ease-out" : "opacity 150ms ease-in-out"
686
+ }
687
+ },
688
+ children: /* @__PURE__ */ jsx8(IconComponent, { size: scaledCardHeight })
689
+ },
690
+ key
691
+ );
692
+ })
693
+ }
694
+ )
695
+ ]
696
+ }
697
+ );
698
+ };
699
+ var InputPayment = forwardRef3(
700
+ ({
701
+ value,
702
+ icon,
703
+ placeholder = "Card number",
704
+ onChange,
705
+ onChangeText,
706
+ onKeyDown,
707
+ size = "m",
708
+ name,
709
+ disabled = false,
710
+ errorMessage,
711
+ error,
712
+ possiblePayments = DEFAULT_POSSIBLE_PAYMENTS,
713
+ maxVisiblePossiblePayments = 5,
714
+ recognizedPayment: controlledRecognizedPayment,
715
+ onRecognizedPaymentChange,
716
+ autoDetect = true,
717
+ id: providedId,
718
+ "aria-label": ariaLabel,
719
+ testID,
720
+ ...rest
721
+ }, ref) => {
722
+ const { theme } = useDesignSystem();
723
+ const [internalState, setInternalState] = useState(
724
+ "default"
725
+ );
726
+ const [passValue, setPassValue] = useState(value ?? "");
727
+ const [detectedPayment, setDetectedPayment] = useState(null);
728
+ const inputRef = useRef(null);
729
+ const rawId = useId();
730
+ const safeId = rawId.replace(/:/g, "");
731
+ const inputId = providedId || `input-payment-${safeId}`;
732
+ const errorId = `${inputId}-error`;
733
+ React4.useImperativeHandle(
734
+ ref,
735
+ () => inputRef.current,
736
+ []
737
+ );
738
+ useEffect(() => {
739
+ if (value !== void 0) {
740
+ setPassValue(value);
741
+ }
742
+ }, [value]);
743
+ useEffect(() => {
744
+ if (autoDetect && passValue) {
745
+ const detected = detectPaymentSystem(passValue);
746
+ const validDetected = detected && possiblePayments.includes(detected) ? detected : null;
747
+ setDetectedPayment(validDetected);
748
+ onRecognizedPaymentChange?.(validDetected);
749
+ } else if (!passValue) {
750
+ setDetectedPayment(null);
751
+ if (autoDetect) {
752
+ onRecognizedPaymentChange?.(null);
753
+ }
754
+ }
755
+ }, [passValue, autoDetect, onRecognizedPaymentChange, possiblePayments]);
756
+ const isDisable = disabled;
757
+ const isError = !!(errorMessage || error);
758
+ const isFocus = internalState === "focus";
759
+ const displayRecognizedPayment = controlledRecognizedPayment ?? detectedPayment;
760
+ const sizeStyles = theme.sizing.input(size);
761
+ const inputColors = theme.colors.control.input;
762
+ const handleFocus = () => {
763
+ if (!isDisable) {
764
+ setInternalState("focus");
765
+ }
766
+ };
767
+ const handleBlur = () => {
768
+ if (!isDisable) {
769
+ setInternalState("default");
770
+ }
771
+ };
772
+ const handleChange = (e) => {
773
+ const newValue = e.target.value;
774
+ if (onChange) {
775
+ onChange(e);
776
+ }
777
+ if (onChangeText) {
778
+ onChangeText(newValue);
779
+ }
780
+ setPassValue(newValue);
781
+ };
782
+ const handleKeyDown = (e) => {
783
+ if (e.key === "Escape") {
784
+ e.currentTarget.blur();
785
+ }
786
+ if (onKeyDown) {
787
+ onKeyDown(e);
788
+ }
789
+ };
790
+ let backgroundColor = inputColors.bg;
791
+ let borderColor = inputColors.border;
792
+ let outlineColor;
793
+ if (isDisable) {
794
+ backgroundColor = inputColors.bgDisable;
795
+ borderColor = inputColors.borderDisable;
796
+ } else if (isError) {
797
+ outlineColor = theme.colors.border.alert;
798
+ if (isFocus) {
799
+ backgroundColor = theme.colors.control.focus.bg;
800
+ }
801
+ } else if (isFocus) {
802
+ backgroundColor = theme.colors.control.focus.bg;
803
+ outlineColor = theme.colors.border.brand;
804
+ }
805
+ const textColor = isDisable ? inputColors.textDisable : inputColors.text;
806
+ const placeholderColor = inputColors.placeholder;
807
+ const iconColor = inputColors.placeholder;
808
+ const paddingConfig = {
809
+ xl: { vertical: 12, horizontal: 12 },
810
+ l: { vertical: 14, horizontal: 12 },
811
+ m: { vertical: 11, horizontal: 12 },
812
+ s: { vertical: 7, horizontal: 10 },
813
+ xs: { vertical: 7, horizontal: 10 }
814
+ };
815
+ const borderRadiusConfig = {
816
+ xl: 4,
817
+ l: 4,
818
+ m: 2,
819
+ s: 2,
820
+ xs: 2
821
+ };
822
+ const iconSizeConfig = {
823
+ xl: 18,
824
+ l: 18,
825
+ m: 18,
826
+ s: 16,
827
+ xs: 16
828
+ };
829
+ const focusOutlineConfig = {
830
+ xl: { width: 2, offset: -2 },
831
+ l: { width: 2, offset: -2 },
832
+ m: { width: 1, offset: -1 },
833
+ s: { width: 1, offset: -1 },
834
+ xs: { width: 1, offset: -1 }
835
+ };
836
+ const padding = paddingConfig[size];
837
+ const borderRadius = borderRadiusConfig[size];
838
+ const iconSize = iconSizeConfig[size];
839
+ const focusOutline = focusOutlineConfig[size];
840
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", gap: 8, width: "100%", testID, children: [
841
+ /* @__PURE__ */ jsxs(
842
+ Box,
843
+ {
844
+ backgroundColor,
845
+ borderColor,
846
+ borderWidth: borderColor !== "transparent" ? 1 : 0,
847
+ borderRadius,
848
+ height: sizeStyles.height,
849
+ paddingVertical: padding.vertical,
850
+ paddingHorizontal: padding.horizontal,
851
+ flexDirection: "row",
852
+ alignItems: "center",
853
+ gap: 10,
854
+ position: "relative",
855
+ style: {
856
+ ...outlineColor ? {
857
+ outline: `${focusOutline.width}px solid ${outlineColor}`,
858
+ outlineOffset: `${focusOutline.offset}px`
859
+ } : {}
860
+ },
861
+ hoverStyle: !isDisable && !isFocus && !isError ? {
862
+ backgroundColor: inputColors.bgHover,
863
+ borderColor: inputColors.borderHover
864
+ } : void 0,
865
+ children: [
866
+ icon && /* @__PURE__ */ jsx8(
867
+ Box,
868
+ {
869
+ alignItems: "center",
870
+ justifyContent: "center",
871
+ role: "img",
872
+ "aria-hidden": "true",
873
+ children: React4.isValidElement(icon) ? React4.cloneElement(icon, {
874
+ size: iconSize,
875
+ color: iconColor
876
+ }) : icon
877
+ }
878
+ ),
879
+ /* @__PURE__ */ jsx8(Box, { flex: 1, height: "100%", justifyContent: "center", children: /* @__PURE__ */ jsx8(
880
+ InputPrimitive,
881
+ {
882
+ ref: inputRef,
883
+ id: inputId,
884
+ value: passValue,
885
+ name,
886
+ placeholder,
887
+ onChange: handleChange,
888
+ onFocus: handleFocus,
889
+ onBlur: handleBlur,
890
+ onKeyDown: handleKeyDown,
891
+ disabled: isDisable,
892
+ type: "text",
893
+ inputMode: "numeric",
894
+ autoComplete: "off",
895
+ color: textColor,
896
+ fontSize: sizeStyles.fontSize,
897
+ placeholderTextColor: placeholderColor,
898
+ "aria-invalid": isError || void 0,
899
+ "aria-describedby": errorMessage ? errorId : void 0,
900
+ "aria-label": ariaLabel || "Card number",
901
+ "aria-disabled": isDisable || void 0,
902
+ "data-testid": "input-payment__field",
903
+ ...rest
904
+ }
905
+ ) }),
906
+ possiblePayments.length > 0 && /* @__PURE__ */ jsx8(
907
+ Box,
908
+ {
909
+ alignItems: "center",
910
+ justifyContent: "center",
911
+ "data-testid": "input-payment__card-icons",
912
+ style: { overflow: "hidden" },
913
+ children: /* @__PURE__ */ jsx8(
914
+ PaymentIcons,
915
+ {
916
+ possiblePayments,
917
+ maxVisible: maxVisiblePossiblePayments,
918
+ recognizedPayment: displayRecognizedPayment,
919
+ iconHeight: iconSize
920
+ }
921
+ )
922
+ }
923
+ )
924
+ ]
925
+ }
926
+ ),
927
+ errorMessage && /* @__PURE__ */ jsx8(
928
+ Text,
929
+ {
930
+ id: errorId,
931
+ role: "alert",
932
+ color: theme.colors.content.alert.primary,
933
+ fontSize: sizeStyles.fontSize - 2,
934
+ children: errorMessage
935
+ }
936
+ )
937
+ ] });
938
+ }
939
+ );
940
+ InputPayment.displayName = "InputPayment";
941
+ export {
942
+ InputPayment
943
+ };
944
+ //# sourceMappingURL=index.mjs.map