@idonatedev/idonate-sdk 1.2.0-dev14 → 1.2.0-dev16

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 (34) hide show
  1. package/dist/constants.js +1 -1
  2. package/dist/esm/constants.js +1 -1
  3. package/dist/esm/tokenize/CardConnectTokenizer.d.ts +6 -1
  4. package/dist/esm/tokenize/CardConnectTokenizer.js +184 -53
  5. package/dist/esm/tokenize/PayPalTokenizer.d.ts +1 -0
  6. package/dist/esm/tokenize/PayPalTokenizer.js +52 -16
  7. package/dist/esm/tokenize/SpreedlyTokenizer.d.ts +6 -0
  8. package/dist/esm/tokenize/SpreedlyTokenizer.js +113 -63
  9. package/dist/esm/tokenize/Tokenizer.d.ts +6 -2
  10. package/dist/esm/tokenize/Tokenizer.js +13 -3
  11. package/dist/esm/tokenize/gateway-utils.js +3 -2
  12. package/dist/esm/tokenize/index.d.ts +1 -1
  13. package/dist/esm/tokenize/spreedly-secure.js +6 -2
  14. package/dist/esm/tokenize/tokenizer-utils.d.ts +1 -1
  15. package/dist/esm/tokenize/tokenizer-utils.js +25 -4
  16. package/dist/esm/tokenize/types.d.ts +3 -2
  17. package/dist/esm/typeAdapters.js +6 -4
  18. package/dist/tokenize/CardConnectTokenizer.d.ts +6 -1
  19. package/dist/tokenize/CardConnectTokenizer.js +184 -56
  20. package/dist/tokenize/PayPalTokenizer.d.ts +1 -0
  21. package/dist/tokenize/PayPalTokenizer.js +52 -16
  22. package/dist/tokenize/SpreedlyTokenizer.d.ts +6 -0
  23. package/dist/tokenize/SpreedlyTokenizer.js +113 -63
  24. package/dist/tokenize/Tokenizer.d.ts +6 -2
  25. package/dist/tokenize/Tokenizer.js +13 -3
  26. package/dist/tokenize/gateway-utils.js +3 -2
  27. package/dist/tokenize/index.d.ts +1 -1
  28. package/dist/tokenize/spreedly-secure.js +6 -2
  29. package/dist/tokenize/tokenizer-utils.d.ts +1 -1
  30. package/dist/tokenize/tokenizer-utils.js +25 -4
  31. package/dist/tokenize/types.d.ts +3 -2
  32. package/dist/typeAdapters.js +6 -4
  33. package/package.json +1 -1
  34. package/umd/idonate-sdk.js +1 -1
@@ -69,7 +69,7 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
69
69
  }
70
70
  static create(gateway, container, config) {
71
71
  return __awaiter(this, void 0, void 0, function* () {
72
- var _a;
72
+ var _a, _b;
73
73
  if (container.mode !== 'bank_account') {
74
74
  yield SpreedlyTokenizer.ensureSpreedlyLoaded();
75
75
  }
@@ -78,9 +78,9 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
78
78
  environmentKey = config.clientConfig.spreedlyEnvironmentKey;
79
79
  }
80
80
  if (!environmentKey) {
81
- environmentKey = '';
81
+ throw new Error('Spreedly environment key is required. Provide it via gateway.config.environmentKey or client config.');
82
82
  }
83
- const tokenizer = new SpreedlyTokenizer(environmentKey, container.containerId, container.styling, container.mode || 'credit_card', container.bankCountry || 'US', container.enableTestMode || false, container.layout || 'single-line', container.responsiveBreakpoint || tokenizer_constants_1.RESPONSIVE_BREAKPOINT);
83
+ const tokenizer = new SpreedlyTokenizer(environmentKey, container.containerId, container.styling, container.mode || 'credit_card', container.bankCountry || 'US', container.enableTestMode || false, container.layout || 'single-line', (_b = container.responsiveBreakpoint) !== null && _b !== void 0 ? _b : tokenizer_constants_1.RESPONSIVE_BREAKPOINT);
84
84
  tokenizer.organizationId = config.organizationId;
85
85
  tokenizer.embedId = config.embedId;
86
86
  tokenizer.clientConfig = config.clientConfig;
@@ -161,8 +161,29 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
161
161
  this.emit('ready');
162
162
  resolve();
163
163
  });
164
+ this.spreedly.on('paymentMethod', (token, pmData) => {
165
+ const paymentToken = {
166
+ token,
167
+ lastFour: pmData.last_four_digits,
168
+ cardType: this.normalizeCardType(pmData.card_type),
169
+ paymentMethodType: 'credit_card',
170
+ provider: 'spreedly',
171
+ };
172
+ if (this.tokenizationResolve) {
173
+ const resolveTokenization = this.tokenizationResolve;
174
+ this.clearTokenizationState();
175
+ this.emit('tokenReady', paymentToken);
176
+ resolveTokenization(paymentToken);
177
+ }
178
+ });
164
179
  this.spreedly.on('errors', (errors) => {
165
- this.emit('error', new types_1.TokenizationError(errors));
180
+ const error = new types_1.TokenizationError(errors);
181
+ this.emit('error', error);
182
+ if (this.tokenizationReject) {
183
+ const rejectTokenization = this.tokenizationReject;
184
+ this.clearTokenizationState();
185
+ rejectTokenization(error);
186
+ }
166
187
  });
167
188
  this.spreedly.on('fieldEvent', (fieldName, eventType, activeEl, inputProperties) => {
168
189
  this.handleFieldEvent(fieldName, eventType, inputProperties);
@@ -188,6 +209,19 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
188
209
  });
189
210
  }
190
211
  tokenizeCardInternal(cardData) {
212
+ if (this.tokenizationPromise) {
213
+ return this.tokenizationPromise;
214
+ }
215
+ const expiry = this.parseExpiry(this.expiryEl);
216
+ if (!expiry) {
217
+ return Promise.reject(new types_1.TokenizationError('Expiration date is required', 'VALIDATION_ERROR'));
218
+ }
219
+ this.tokenizationPromise = this.executeCardTokenization(cardData, expiry).finally(() => {
220
+ this.tokenizationPromise = undefined;
221
+ });
222
+ return this.tokenizationPromise;
223
+ }
224
+ executeCardTokenization(cardData, expiry) {
191
225
  return __awaiter(this, void 0, void 0, function* () {
192
226
  var _a;
193
227
  let securityFields = {};
@@ -207,42 +241,13 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
207
241
  }
208
242
  return new Promise((resolve, reject) => {
209
243
  var _a, _b, _c, _d, _e, _f;
210
- const timeout = setTimeout(() => {
211
- if (this.spreedly && this.spreedly.removeHandlers) {
212
- this.spreedly.removeHandlers();
213
- }
244
+ this.tokenizationResolve = resolve;
245
+ this.tokenizationReject = reject;
246
+ this.tokenizationTimeout = setTimeout(() => {
247
+ this.clearTokenizationState();
214
248
  reject(new types_1.TokenizationError('Tokenization timeout', 'TIMEOUT'));
215
249
  }, tokenizer_constants_1.TOKENIZE_TIMEOUT);
216
- const cleanup = () => {
217
- clearTimeout(timeout);
218
- if (this.spreedly && this.spreedly.removeHandlers) {
219
- this.spreedly.removeHandlers();
220
- }
221
- };
222
- this.spreedly.on('paymentMethod', (token, pmData) => {
223
- cleanup();
224
- const paymentToken = {
225
- token,
226
- lastFour: pmData.last_four_digits,
227
- cardType: this.normalizeCardType(pmData.card_type),
228
- provider: 'spreedly',
229
- };
230
- this.emit('tokenReady', paymentToken);
231
- resolve(paymentToken);
232
- });
233
- this.spreedly.on('errors', (errors) => {
234
- cleanup();
235
- reject(new types_1.TokenizationError(errors));
236
- });
237
- const expiry = this.parseExpiry(this.expiryEl);
238
- if (!expiry) {
239
- cleanup();
240
- reject(new types_1.TokenizationError('Expiration date is required', 'VALIDATION_ERROR'));
241
- return;
242
- }
243
- const expiryMonth = expiry.month;
244
- const expiryYear = expiry.year;
245
- this.spreedly.tokenizeCreditCard(Object.assign({ first_name: cardData.firstName, last_name: cardData.lastName, month: expiryMonth, year: expiryYear, email: cardData.email, phone_number: cardData.phone, address1: (_a = cardData.address) === null || _a === void 0 ? void 0 : _a.address1, address2: (_b = cardData.address) === null || _b === void 0 ? void 0 : _b.address2, city: (_c = cardData.address) === null || _c === void 0 ? void 0 : _c.city, state: (_d = cardData.address) === null || _d === void 0 ? void 0 : _d.state, zip: (_e = cardData.address) === null || _e === void 0 ? void 0 : _e.zip, country: (_f = cardData.address) === null || _f === void 0 ? void 0 : _f.country }, securityFields));
250
+ this.spreedly.tokenizeCreditCard(Object.assign({ first_name: cardData.firstName, last_name: cardData.lastName, month: expiry.month, year: expiry.year, email: cardData.email, phone_number: cardData.phone, address1: (_a = cardData.address) === null || _a === void 0 ? void 0 : _a.address1, address2: (_b = cardData.address) === null || _b === void 0 ? void 0 : _b.address2, city: (_c = cardData.address) === null || _c === void 0 ? void 0 : _c.city, state: (_d = cardData.address) === null || _d === void 0 ? void 0 : _d.state, zip: (_e = cardData.address) === null || _e === void 0 ? void 0 : _e.zip, country: (_f = cardData.address) === null || _f === void 0 ? void 0 : _f.country }, securityFields));
246
251
  });
247
252
  });
248
253
  }
@@ -435,17 +440,22 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
435
440
  accountHolderType: accountHolderType,
436
441
  },
437
442
  }, this.clientConfig, this.environmentKey);
438
- return {
443
+ const paymentToken = {
439
444
  token: result,
440
445
  lastFour: accountNumber.slice(-4),
441
446
  accountType: accountType,
442
447
  paymentMethodType: 'bank_account',
443
448
  provider: 'spreedly',
444
449
  };
450
+ this.emit('tokenReady', paymentToken);
451
+ return paymentToken;
445
452
  });
446
453
  }
447
454
  validate() {
448
455
  return __awaiter(this, void 0, void 0, function* () {
456
+ if (!this.isReady) {
457
+ throw new Error('Tokenizer not initialized');
458
+ }
449
459
  if (this.mode === 'bank_account') {
450
460
  return this.validateBankAccountInternal();
451
461
  }
@@ -633,13 +643,31 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
633
643
  this.accountNumberEl.value = '';
634
644
  if (this.accountTypeEl)
635
645
  this.accountTypeEl.selectedIndex = 0;
646
+ this.currentValidationState = {
647
+ isValid: false,
648
+ routingNumber: { isValid: false, isEmpty: true },
649
+ accountNumber: { isValid: false, isEmpty: true },
650
+ };
636
651
  }
637
652
  else {
638
653
  this.spreedly.reload();
639
654
  if (this.expiryEl) {
640
655
  this.expiryEl.value = '';
641
656
  }
657
+ this.currentValidationState = {
658
+ isValid: false,
659
+ cardNumber: { isValid: false, isEmpty: true },
660
+ cvv: { isValid: false, isEmpty: true },
661
+ expiry: { isValid: false, isEmpty: true },
662
+ };
663
+ }
664
+ if (this.tokenizationReject) {
665
+ const reject = this.tokenizationReject;
666
+ this.clearTokenizationState();
667
+ reject(new types_1.TokenizationError('Tokenizer cleared', 'CLEARED'));
642
668
  }
669
+ this.clearTokenizationState();
670
+ this.emit('validation', this.currentValidationState);
643
671
  }
644
672
  focus(field) {
645
673
  if (this.mode === 'bank_account') {
@@ -730,14 +758,29 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
730
758
  }
731
759
  }
732
760
  }
761
+ clearTokenizationState() {
762
+ if (this.tokenizationTimeout) {
763
+ clearTimeout(this.tokenizationTimeout);
764
+ this.tokenizationTimeout = undefined;
765
+ }
766
+ this.tokenizationResolve = undefined;
767
+ this.tokenizationReject = undefined;
768
+ }
733
769
  destroy() {
734
770
  var _a;
771
+ this.markDestroyed();
735
772
  (_a = this.resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
773
+ if (this.tokenizationReject) {
774
+ const reject = this.tokenizationReject;
775
+ this.clearTokenizationState();
776
+ reject(new types_1.TokenizationError('Tokenizer destroyed', 'DESTROYED'));
777
+ }
736
778
  if (this.spreedly && this.spreedly.removeHandlers) {
737
779
  this.spreedly.removeHandlers();
738
780
  }
739
781
  this.eventHandlers.clear();
740
- if (this.expiryEl) {
782
+ if (this.containerEl) {
783
+ this.containerEl.innerHTML = '';
741
784
  }
742
785
  }
743
786
  hasToken() {
@@ -784,15 +827,6 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
784
827
  }
785
828
  this.updateOverallValidation();
786
829
  }
787
- if (eventType === 'focus') {
788
- this.emit('focus', { field: fieldName });
789
- }
790
- else if (eventType === 'blur') {
791
- this.emit('blur', { field: fieldName });
792
- }
793
- else if (eventType === 'input') {
794
- this.emit('change', { field: fieldName });
795
- }
796
830
  }
797
831
  createInternalElements() {
798
832
  const container = document.getElementById(this.containerId);
@@ -838,6 +872,10 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
838
872
  };
839
873
  this.updateOverallValidation();
840
874
  });
875
+ this.expiryEl.addEventListener('blur', () => {
876
+ this.validateExpiry();
877
+ this.updateOverallValidation();
878
+ });
841
879
  container.appendChild(this.expiryEl);
842
880
  const cvvDiv = (0, tokenizer_utils_1.createFieldContainer)(this.cvvEl, '1', tokenizer_constants_1.FIELD_FLEX.cvv.minWidth);
843
881
  cvvDiv.style.height = this.mergedStyles.input.height;
@@ -865,6 +903,10 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
865
903
  };
866
904
  this.updateOverallValidation();
867
905
  });
906
+ this.expiryEl.addEventListener('blur', () => {
907
+ this.validateExpiry();
908
+ this.updateOverallValidation();
909
+ });
868
910
  container.appendChild(this.expiryEl);
869
911
  const cvvDiv = (0, tokenizer_utils_1.createFieldContainer)(this.cvvEl, tokenizer_constants_1.FIELD_FLEX.cvv.flex, tokenizer_constants_1.FIELD_FLEX.cvv.minWidth);
870
912
  cvvDiv.style.height = this.mergedStyles.input.height;
@@ -1027,23 +1069,31 @@ class SpreedlyTokenizer extends Tokenizer_1.Tokenizer {
1027
1069
  if (!this.expiryEl)
1028
1070
  return;
1029
1071
  const expiry = this.parseExpiry(this.expiryEl);
1072
+ const isEmpty = !this.expiryEl.value;
1073
+ let isValid = false;
1030
1074
  if (!expiry) {
1031
- this.applyErrorStyles(this.expiryEl);
1032
- return;
1033
- }
1034
- const month = parseInt(expiry.month, 10);
1035
- const year = parseInt(expiry.year, 10);
1036
- if (month < 1 || month > 12) {
1037
- this.applyErrorStyles(this.expiryEl);
1038
- return;
1075
+ if (!isEmpty)
1076
+ this.applyErrorStyles(this.expiryEl);
1039
1077
  }
1040
- const now = new Date();
1041
- const expiryDate = new Date(year, month - 1);
1042
- if (expiryDate < now) {
1043
- this.applyErrorStyles(this.expiryEl);
1044
- return;
1078
+ else {
1079
+ const month = parseInt(expiry.month, 10);
1080
+ const year = parseInt(expiry.year, 10);
1081
+ if (month < 1 || month > 12) {
1082
+ this.applyErrorStyles(this.expiryEl);
1083
+ }
1084
+ else {
1085
+ const now = new Date();
1086
+ const expiryEndDate = new Date(year, month);
1087
+ if (expiryEndDate <= now) {
1088
+ this.applyErrorStyles(this.expiryEl);
1089
+ }
1090
+ else {
1091
+ isValid = true;
1092
+ this.applyInputStyles(this.expiryEl, this.mergedStyles, 'middle');
1093
+ }
1094
+ }
1045
1095
  }
1046
- this.applyInputStyles(this.expiryEl, this.mergedStyles, 'middle');
1096
+ this.currentValidationState.expiry = { isValid, isEmpty };
1047
1097
  }
1048
1098
  applyErrorStyles(element) {
1049
1099
  if (this.mergedStyles.error) {
@@ -2,9 +2,13 @@ import { CardData, BankAccountData, PaymentData, PaymentToken, ValidationResult,
2
2
  import ConfigHandler from '../config-handler';
3
3
  export declare abstract class Tokenizer {
4
4
  protected mode: PaymentMethodMode;
5
- protected eventHandlers: Map<TokenizerEvent, Set<(data?: any) => void>>;
5
+ protected eventHandlers: Map<string, Set<(data?: any) => void>>;
6
+ private focusHandlerElements;
6
7
  private _isReady;
8
+ private _isDestroyed;
7
9
  get isReady(): boolean;
10
+ get isDestroyed(): boolean;
11
+ protected markDestroyed(): void;
8
12
  abstract tokenize(paymentData: PaymentData): Promise<PaymentToken>;
9
13
  abstract validate(): Promise<ValidationResult>;
10
14
  abstract clear(): void;
@@ -16,7 +20,7 @@ export declare abstract class Tokenizer {
16
20
  getMode(): PaymentMethodMode;
17
21
  on(event: TokenizerEvent, handler: (data?: any) => void): void;
18
22
  off(event: TokenizerEvent, handler: (data?: any) => void): void;
19
- protected emit(event: TokenizerEvent, data?: any): void;
23
+ protected emit(event: string, data?: any): void;
20
24
  protected isCardData(data: PaymentData): data is CardData;
21
25
  protected isBankAccountData(data: PaymentData): data is BankAccountData;
22
26
  protected normalizeCardType(providerCardType: string): CardType;
@@ -49,10 +49,18 @@ class Tokenizer {
49
49
  constructor() {
50
50
  this.mode = 'credit_card';
51
51
  this.eventHandlers = new Map();
52
+ this.focusHandlerElements = new WeakSet();
52
53
  this._isReady = false;
54
+ this._isDestroyed = false;
53
55
  }
54
56
  get isReady() {
55
- return this._isReady;
57
+ return this._isReady && !this._isDestroyed;
58
+ }
59
+ get isDestroyed() {
60
+ return this._isDestroyed;
61
+ }
62
+ markDestroyed() {
63
+ this._isDestroyed = true;
56
64
  }
57
65
  getMode() {
58
66
  return this.mode;
@@ -118,7 +126,6 @@ class Tokenizer {
118
126
  expiryEl.addEventListener('input', (e) => {
119
127
  const target = e.target;
120
128
  target.value = (0, tokenizer_utils_1.formatExpiryInput)(target.value);
121
- this.emit('change', { field: 'expiry' });
122
129
  });
123
130
  expiryEl.addEventListener('keypress', (e) => {
124
131
  const char = String.fromCharCode(e.which);
@@ -169,7 +176,10 @@ class Tokenizer {
169
176
  element.style.border = inputStyles.border;
170
177
  element.style.borderRadius = inputStyles.borderRadius;
171
178
  }
172
- (0, tokenizer_utils_1.addFocusHandlers)(element, styles);
179
+ if (!this.focusHandlerElements.has(element)) {
180
+ (0, tokenizer_utils_1.addFocusHandlers)(element, styles, position);
181
+ this.focusHandlerElements.add(element);
182
+ }
173
183
  }
174
184
  generateFieldIds(containerId) {
175
185
  return {
@@ -13,8 +13,9 @@ var __rest = (this && this.__rest) || function (s, e) {
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.normalizeGateway = normalizeGateway;
15
15
  function normalizeGateway(input) {
16
- if (!input)
17
- return input;
16
+ if (!input) {
17
+ throw new Error('Gateway is required but received ' + String(input));
18
+ }
18
19
  if (input.backendName !== undefined)
19
20
  return input;
20
21
  const _a = input.config || {}, { environment_key, base_url, merchant_id } = _a, extraConfigKeys = __rest(_a, ["environment_key", "base_url", "merchant_id"]);
@@ -3,6 +3,6 @@ export { Tokenizer } from './Tokenizer';
3
3
  export { SpreedlyTokenizer } from './SpreedlyTokenizer';
4
4
  export { CardConnectTokenizer } from './CardConnectTokenizer';
5
5
  export { PayPalTokenizer, PayPalCreateOrderData } from './PayPalTokenizer';
6
- export { PaymentMethodType, PaymentGateway, TokenizerContainer, TokenizerStyling, CardData, PaymentData, PaymentToken, CardType, TokenizerEvent, ValidationState, ValidationResult, ValidationError, TokenizationError, } from './types';
6
+ export { PaymentMethodType, PaymentMethodMode, PaymentGateway, TokenizerContainer, TokenizerStyling, CardData, BankAccountData, PaymentData, PaymentToken, CardType, TokenizerEvent, ValidationState, ValidationResult, ValidationError, TokenizationError, } from './types';
7
7
  export { normalizeGateway } from './gateway-utils';
8
8
  export { iats };
@@ -16,6 +16,7 @@ function fetchSpreedlySecurityArgs(config, organizationId, embedId) {
16
16
  throw new Error('Secure tokenization is not enabled');
17
17
  }
18
18
  const makeRequest = () => __awaiter(this, void 0, void 0, function* () {
19
+ var _a;
19
20
  const response = yield fetch(`${config.embedApiBaseUrl}/spreedly/security-args`, {
20
21
  method: 'POST',
21
22
  headers: { 'Content-Type': 'application/json' },
@@ -27,13 +28,16 @@ function fetchSpreedlySecurityArgs(config, organizationId, embedId) {
27
28
  if (!response.ok) {
28
29
  throw new Error(`Security args request failed: ${response.status}`);
29
30
  }
30
- return response.json();
31
+ const data = yield response.json();
32
+ return (_a = data.result) !== null && _a !== void 0 ? _a : data;
31
33
  });
32
34
  try {
33
35
  return yield makeRequest();
34
36
  }
35
37
  catch (error) {
36
- if (error instanceof TypeError && error.message.includes('fetch')) {
38
+ const isNetworkError = error instanceof TypeError && error.message.includes('fetch');
39
+ const isServerError = error instanceof Error && error.message.includes('failed: 5');
40
+ if (isNetworkError || isServerError) {
37
41
  yield new Promise((resolve) => setTimeout(resolve, 1000));
38
42
  return makeRequest();
39
43
  }
@@ -6,7 +6,7 @@ export declare function parseExpiryDate(value: string): {
6
6
  export declare function formatExpiryInput(value: string): string;
7
7
  export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number, errorMessage: string): Promise<T>;
8
8
  export declare function getConnectedBorderRadius(baseRadius: string, position: 'left' | 'middle' | 'right', isConnected: boolean): string;
9
- export declare function addFocusHandlers(element: HTMLElement, styles: TokenizerStylingComplete, onFocus?: () => void, onBlur?: () => void): void;
9
+ export declare function addFocusHandlers(element: HTMLElement, styles: TokenizerStylingComplete, position?: 'left' | 'middle' | 'right', onFocus?: () => void, onBlur?: () => void): void;
10
10
  export declare function createFieldContainer(id: string, flex: string, minWidth?: string, maxWidth?: string): HTMLDivElement;
11
11
  export declare function createInputElement(id: string, type: string, placeholder: string, maxLength?: number): HTMLInputElement;
12
12
  export declare function validateRoutingNumber(routingNumber: string): boolean;
@@ -56,7 +56,7 @@ function getConnectedBorderRadius(baseRadius, position, isConnected) {
56
56
  return baseRadius;
57
57
  }
58
58
  }
59
- function addFocusHandlers(element, styles, onFocus, onBlur) {
59
+ function addFocusHandlers(element, styles, position, onFocus, onBlur) {
60
60
  element.addEventListener('focus', () => {
61
61
  if (styles.focus) {
62
62
  Object.assign(element.style, styles.focus);
@@ -64,9 +64,30 @@ function addFocusHandlers(element, styles, onFocus, onBlur) {
64
64
  onFocus === null || onFocus === void 0 ? void 0 : onFocus();
65
65
  });
66
66
  element.addEventListener('blur', () => {
67
- element.style.border = styles.input.border;
68
- element.style.outline = 'none';
69
- element.style.boxShadow = 'none';
67
+ const isConnected = styles.container.gap === '0';
68
+ if (isConnected && position) {
69
+ element.style.borderTop = styles.input.border;
70
+ element.style.borderBottom = styles.input.border;
71
+ switch (position) {
72
+ case 'left':
73
+ element.style.borderLeft = styles.input.border;
74
+ element.style.borderRight = 'none';
75
+ break;
76
+ case 'middle':
77
+ element.style.borderLeft = styles.input.border;
78
+ element.style.borderRight = 'none';
79
+ break;
80
+ case 'right':
81
+ element.style.borderLeft = styles.input.border;
82
+ element.style.borderRight = styles.input.border;
83
+ break;
84
+ }
85
+ }
86
+ else {
87
+ element.style.border = styles.input.border;
88
+ }
89
+ element.style.outline = '';
90
+ element.style.boxShadow = '';
70
91
  onBlur === null || onBlur === void 0 ? void 0 : onBlur();
71
92
  });
72
93
  }
@@ -1,5 +1,5 @@
1
1
  export type PaymentMethodType = 'credit_card' | 'bank_account' | 'paypal' | 'apple_pay' | 'google_pay';
2
- export type PaymentMethodMode = 'credit_card' | 'bank_account';
2
+ export type PaymentMethodMode = 'credit_card' | 'bank_account' | 'paypal';
3
3
  export interface PaymentGateway {
4
4
  id: string;
5
5
  backendName: string;
@@ -106,9 +106,10 @@ export interface PaymentToken {
106
106
  paymentTransactionId?: string;
107
107
  }
108
108
  export type CardType = 'visa' | 'mastercard' | 'amex' | 'discover' | 'diners' | 'jcb' | 'unknown';
109
- export type TokenizerEvent = 'ready' | 'focus' | 'blur' | 'change' | 'validation' | 'cardTypeChange' | 'error' | 'tokenization' | 'tokenReady';
109
+ export type TokenizerEvent = 'ready' | 'validation' | 'cardTypeChange' | 'error' | 'tokenReady';
110
110
  export interface ValidationState {
111
111
  isValid: boolean;
112
+ hasToken?: boolean;
112
113
  cardNumber?: {
113
114
  isValid: boolean;
114
115
  isEmpty: boolean;
@@ -111,16 +111,18 @@ function buildCashPaymentPayload(organizationId, input) {
111
111
  utmFields.utm_term = input.utm.term;
112
112
  }
113
113
  }
114
+ let remainingMeta = input.customerMeta
115
+ ? Object.assign({}, input.customerMeta) : {};
114
116
  if (input.customerMeta) {
115
117
  [1, 2, 3, 4, 5].forEach((customNoteIndex) => {
116
118
  const key = `custom_note_${customNoteIndex}`;
117
- if (input.customerMeta[key]) {
118
- donationOptions[key] = input.customerMeta[key];
119
- delete input.customerMeta[key];
119
+ if (remainingMeta[key]) {
120
+ donationOptions[key] = remainingMeta[key];
121
+ delete remainingMeta[key];
120
122
  }
121
123
  });
122
124
  }
123
- return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, donationOptions), billingAddress), billingContact), payment), utmFields), { customer_meta: input.customerMeta || {}, recaptcha_token: input.recaptchaToken, recaptcha_type: input.recaptchaType });
125
+ return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, donationOptions), billingAddress), billingContact), payment), utmFields), { customer_meta: remainingMeta, recaptcha_token: input.recaptchaToken, recaptcha_type: input.recaptchaType });
124
126
  }
125
127
  function buildDonationResult(response) {
126
128
  let campaign;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@idonatedev/idonate-sdk",
3
3
  "author": "iDonate",
4
- "version": "1.2.0-dev14",
4
+ "version": "1.2.0-dev16",
5
5
  "sideEffects": false,
6
6
  "description": "iDonate Web SDK",
7
7
  "engines": {