@idonatedev/idonate-sdk 1.2.0-dev18 → 1.2.0-dev19

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.
@@ -32,17 +32,30 @@ export const DEFAULT_UNIFIED_STYLES = {
32
32
  fontSize: '',
33
33
  textAlign: '',
34
34
  },
35
+ label: {
36
+ show: false,
37
+ fontSize: '0.875rem',
38
+ fontWeight: 'bold',
39
+ fontFamily: '',
40
+ color: '#333',
41
+ marginBottom: '0.25rem',
42
+ },
35
43
  };
36
44
  export function mergeStyles(defaults, userStyles) {
37
45
  if (!userStyles)
38
46
  return defaults;
39
- return {
47
+ const merged = {
40
48
  input: Object.assign(Object.assign({}, defaults.input), userStyles.input),
41
49
  focus: Object.assign(Object.assign({}, defaults.focus), userStyles.focus),
42
50
  error: Object.assign(Object.assign({}, defaults.error), userStyles.error),
43
51
  container: Object.assign(Object.assign({}, defaults.container), userStyles.container),
44
52
  twoLine: Object.assign(Object.assign({}, defaults.twoLine), userStyles.twoLine),
53
+ label: Object.assign(Object.assign({}, defaults.label), userStyles.label),
45
54
  };
55
+ if (!merged.label.fontFamily) {
56
+ merged.label.fontFamily = merged.input.fontFamily;
57
+ }
58
+ return merged;
46
59
  }
47
60
  export function getContainerStylesForLayout(baseStyles, layout = 'single-line') {
48
61
  if (layout === 'two-line') {
@@ -7,6 +7,8 @@ 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
9
  export declare function addFocusHandlers(element: HTMLElement, styles: TokenizerStylingComplete, position?: 'left' | 'middle' | 'right', onFocus?: () => void, onBlur?: () => void): void;
10
+ export declare function createFieldLabel(text: string, forId: string, styles: TokenizerStylingComplete): HTMLLabelElement;
11
+ export declare function wrapFieldWithLabel(field: HTMLElement, labelText: string, styles: TokenizerStylingComplete): HTMLElement;
10
12
  export declare function createFieldContainer(id: string, flex: string, minWidth?: string, maxWidth?: string): HTMLDivElement;
11
13
  export declare function createInputElement(id: string, type: string, placeholder: string, maxLength?: number): HTMLInputElement;
12
14
  export declare function validateRoutingNumber(routingNumber: string): boolean;
@@ -17,3 +19,4 @@ export declare function validateInstitutionNumber(institutionNumber: string): bo
17
19
  export declare function validateTransitNumber(transitNumber: string): boolean;
18
20
  export declare function validateCanadianAccountNumber(accountNumber: string): boolean;
19
21
  export declare function formatCanadianRoutingNumber(institutionNumber: string, transitNumber: string): string;
22
+ export declare function cssLengthToPixels(value: string): number;
@@ -74,6 +74,43 @@ export function addFocusHandlers(element, styles, position, onFocus, onBlur) {
74
74
  onBlur === null || onBlur === void 0 ? void 0 : onBlur();
75
75
  });
76
76
  }
77
+ export function createFieldLabel(text, forId, styles) {
78
+ const label = document.createElement('label');
79
+ label.htmlFor = forId;
80
+ label.textContent = text;
81
+ label.style.display = styles.label.show ? 'block' : 'none';
82
+ label.style.fontSize = styles.label.fontSize;
83
+ label.style.fontWeight = styles.label.fontWeight;
84
+ label.style.fontFamily = styles.label.fontFamily;
85
+ label.style.color = styles.label.color;
86
+ label.style.marginBottom = styles.label.marginBottom;
87
+ return label;
88
+ }
89
+ export function wrapFieldWithLabel(field, labelText, styles) {
90
+ if (!styles.label.show)
91
+ return field;
92
+ const wrapper = document.createElement('div');
93
+ wrapper.style.display = 'flex';
94
+ wrapper.style.flexDirection = 'column';
95
+ if (field.style.flex) {
96
+ wrapper.style.flex = field.style.flex;
97
+ field.style.flex = '';
98
+ }
99
+ if (field.style.minWidth) {
100
+ wrapper.style.minWidth = field.style.minWidth;
101
+ }
102
+ if (field.style.maxWidth) {
103
+ wrapper.style.maxWidth = field.style.maxWidth;
104
+ }
105
+ if (field.style.flexBasis) {
106
+ wrapper.style.flexBasis = field.style.flexBasis;
107
+ field.style.flexBasis = '';
108
+ }
109
+ const label = createFieldLabel(labelText, field.id, styles);
110
+ wrapper.appendChild(label);
111
+ wrapper.appendChild(field);
112
+ return wrapper;
113
+ }
77
114
  export function createFieldContainer(id, flex, minWidth, maxWidth) {
78
115
  const div = document.createElement('div');
79
116
  div.id = id;
@@ -158,3 +195,19 @@ export function formatCanadianRoutingNumber(institutionNumber, transitNumber) {
158
195
  const transit = transitNumber.replace(/\D/g, '').padStart(5, '0');
159
196
  return '0' + institution + transit;
160
197
  }
198
+ export function cssLengthToPixels(value) {
199
+ const num = parseFloat(value);
200
+ if (isNaN(num)) {
201
+ console.warn(`[cssLengthToPixels] Cannot parse "${value}", defaulting to 14px`);
202
+ return 14;
203
+ }
204
+ if (value.endsWith('rem'))
205
+ return num * 16;
206
+ if (value.endsWith('pt'))
207
+ return num * 1.333;
208
+ if (value.endsWith('px') || !value.match(/[a-z%]/i))
209
+ return num;
210
+ console.warn(`[cssLengthToPixels] Unsupported unit in "${value}". ` +
211
+ `Only px, rem, and pt are supported. Using ${num}px as approximation.`);
212
+ return num;
213
+ }
@@ -21,6 +21,15 @@ export interface TokenizerContainer {
21
21
  enableTestMode?: boolean;
22
22
  layout?: 'single-line' | 'two-line' | 'responsive';
23
23
  responsiveBreakpoint?: number;
24
+ placeholders?: {
25
+ cardNumber?: string;
26
+ expiry?: string;
27
+ expiryMonth?: string;
28
+ expiryYear?: string;
29
+ cvv?: string;
30
+ routingNumber?: string;
31
+ accountNumber?: string;
32
+ };
24
33
  }
25
34
  export interface TokenizerStylingComplete {
26
35
  input: {
@@ -59,6 +68,14 @@ export interface TokenizerStylingComplete {
59
68
  fontSize: string;
60
69
  textAlign: string;
61
70
  };
71
+ label: {
72
+ show: boolean;
73
+ fontSize: string;
74
+ fontWeight: string;
75
+ fontFamily: string;
76
+ color: string;
77
+ marginBottom: string;
78
+ };
62
79
  }
63
80
  type DeepPartial<T> = T extends object ? {
64
81
  [P in keyof T]?: DeepPartial<T[P]>;
@@ -6,6 +6,7 @@ export declare class CardConnectTokenizer extends Tokenizer {
6
6
  private iframeUrl;
7
7
  private containerId;
8
8
  private layout;
9
+ private customPlaceholders?;
9
10
  private iframe;
10
11
  private messageHandler?;
11
12
  private expectedOrigin;
@@ -49,6 +50,7 @@ export declare class CardConnectTokenizer extends Tokenizer {
49
50
  get tokenizationMode(): 'auto' | 'manual';
50
51
  private handleMessage;
51
52
  private handleValidationMessage;
53
+ private static measureCvvLabelMarginLeft;
52
54
  private static generateIframeUrl;
53
55
  private static createIframe;
54
56
  private static generateCardConnectCss;
@@ -16,11 +16,12 @@ const styles_1 = require("./styles");
16
16
  const tokenizer_constants_1 = require("./tokenizer-constants");
17
17
  const tokenizer_utils_1 = require("./tokenizer-utils");
18
18
  class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
19
- constructor(iframe, iframeUrl, containerId, mode = 'credit_card', enableTestMode = false, layout = 'single-line') {
19
+ constructor(iframe, iframeUrl, containerId, mode = 'credit_card', enableTestMode = false, layout = 'single-line', customPlaceholders) {
20
20
  super();
21
21
  this.iframeUrl = iframeUrl;
22
22
  this.containerId = containerId;
23
23
  this.layout = layout;
24
+ this.customPlaceholders = customPlaceholders;
24
25
  this.enableTestMode = false;
25
26
  this.acceptAutoToken = true;
26
27
  this.mode = mode;
@@ -57,7 +58,7 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
57
58
  const mergedStyles = (0, styles_1.mergeStyles)(styles_1.DEFAULT_UNIFIED_STYLES, container.styling);
58
59
  const iframeUrl = CardConnectTokenizer.generateIframeUrl(baseUrl, resolvedContainer);
59
60
  const iframe = CardConnectTokenizer.createIframe(iframeUrl, mergedStyles);
60
- const tokenizer = new CardConnectTokenizer(iframe, iframeUrl, container.containerId, container.mode || 'credit_card', container.enableTestMode || false, effectiveLayout);
61
+ const tokenizer = new CardConnectTokenizer(iframe, iframeUrl, container.containerId, container.mode || 'credit_card', container.enableTestMode || false, effectiveLayout, container.placeholders);
61
62
  tokenizer.createInternalElements(resolvedContainer);
62
63
  yield tokenizer.init();
63
64
  return tokenizer;
@@ -80,19 +81,32 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
80
81
  }
81
82
  }
82
83
  createCreditCardFields(containerEl, mergedStyles) {
84
+ var _a;
83
85
  this.iframe.style.width = '100%';
86
+ const hasLabels = ((_a = mergedStyles.label) === null || _a === void 0 ? void 0 : _a.show) &&
87
+ (this.layout === 'two-line' || this.layout === 'responsive');
88
+ const inputHeight = mergedStyles.input.height || '40px';
84
89
  if (this.layout === 'two-line' || this.layout === 'responsive') {
85
- const inputHeight = mergedStyles.input.height || '40px';
86
- this.iframe.style.height = `calc((${inputHeight}) * 2 + 10px)`;
90
+ if (hasLabels) {
91
+ const labelFontPx = (0, tokenizer_utils_1.cssLengthToPixels)(mergedStyles.label.fontSize);
92
+ const labelMarginPx = parseFloat(mergedStyles.label.marginBottom) || 0;
93
+ const labelRowHeight = Math.ceil(labelFontPx * 1.2) + labelMarginPx;
94
+ const extraHeight = Math.ceil(labelRowHeight * 2) + 34;
95
+ this.iframe.style.height = `calc(${inputHeight} * 2 + ${extraHeight}px)`;
96
+ }
97
+ else {
98
+ this.iframe.style.height = `calc((${inputHeight}) * 2 + 10px)`;
99
+ }
87
100
  }
88
101
  else {
89
- this.iframe.style.height = mergedStyles.input.height || '40px';
102
+ this.iframe.style.height = inputHeight;
90
103
  }
91
104
  this.iframe.style.border = 'none';
92
105
  this.iframe.style.display = 'block';
93
106
  containerEl.appendChild(this.iframe);
94
107
  }
95
108
  createBankAccountFields(containerEl, mergedStyles) {
109
+ var _a, _b, _c, _d;
96
110
  this.iframe.style.display = 'none';
97
111
  if (this.layout === 'two-line') {
98
112
  this.accountTypeEl = (0, tokenizer_utils_1.createAccountTypeSelect)(`${this.containerId}-account-type`);
@@ -101,45 +115,45 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
101
115
  minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.minWidth,
102
116
  });
103
117
  this.applyInputStyles(this.accountTypeEl, mergedStyles, 'left');
104
- containerEl.appendChild(this.accountTypeEl);
105
- this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', 'Routing *', 9);
118
+ containerEl.appendChild((0, tokenizer_utils_1.wrapFieldWithLabel)(this.accountTypeEl, 'Account Type', mergedStyles));
119
+ this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', ((_a = this.customPlaceholders) === null || _a === void 0 ? void 0 : _a.routingNumber) || 'Routing *', 9);
106
120
  Object.assign(this.routingNumberEl.style, {
107
121
  flex: '1',
108
122
  minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.minWidth,
109
123
  });
110
124
  this.applyInputStyles(this.routingNumberEl, mergedStyles, 'right');
111
- containerEl.appendChild(this.routingNumberEl);
112
- this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', 'Account Number *', 17);
125
+ containerEl.appendChild((0, tokenizer_utils_1.wrapFieldWithLabel)(this.routingNumberEl, 'Routing Number', mergedStyles));
126
+ this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', ((_b = this.customPlaceholders) === null || _b === void 0 ? void 0 : _b.accountNumber) || 'Account Number *', 17);
113
127
  Object.assign(this.accountNumberEl.style, {
114
128
  flex: '1',
115
129
  flexBasis: '100%',
116
130
  minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.minWidth,
117
131
  });
118
132
  this.applyInputStyles(this.accountNumberEl, mergedStyles);
119
- containerEl.appendChild(this.accountNumberEl);
133
+ containerEl.appendChild((0, tokenizer_utils_1.wrapFieldWithLabel)(this.accountNumberEl, 'Account Number', mergedStyles));
120
134
  }
121
135
  else {
122
- this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', 'Routing *', 9);
136
+ this.routingNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-routing`, 'text', ((_c = this.customPlaceholders) === null || _c === void 0 ? void 0 : _c.routingNumber) || 'Routing *', 9);
123
137
  Object.assign(this.routingNumberEl.style, {
124
138
  flex: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.flex,
125
139
  minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.routingNumber.minWidth,
126
140
  });
127
141
  this.applyInputStyles(this.routingNumberEl, mergedStyles, 'left');
128
- containerEl.appendChild(this.routingNumberEl);
129
- this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', 'Account Number *', 17);
142
+ containerEl.appendChild((0, tokenizer_utils_1.wrapFieldWithLabel)(this.routingNumberEl, 'Routing Number', mergedStyles));
143
+ this.accountNumberEl = (0, tokenizer_utils_1.createInputElement)(`${this.containerId}-account`, 'text', ((_d = this.customPlaceholders) === null || _d === void 0 ? void 0 : _d.accountNumber) || 'Account Number *', 17);
130
144
  Object.assign(this.accountNumberEl.style, {
131
145
  flex: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.flex,
132
146
  minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountNumber.minWidth,
133
147
  });
134
148
  this.applyInputStyles(this.accountNumberEl, mergedStyles, 'middle');
135
- containerEl.appendChild(this.accountNumberEl);
149
+ containerEl.appendChild((0, tokenizer_utils_1.wrapFieldWithLabel)(this.accountNumberEl, 'Account Number', mergedStyles));
136
150
  this.accountTypeEl = (0, tokenizer_utils_1.createAccountTypeSelect)(`${this.containerId}-account-type`);
137
151
  Object.assign(this.accountTypeEl.style, {
138
152
  flex: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.flex,
139
153
  minWidth: tokenizer_constants_1.BANK_FIELD_FLEX.accountType.minWidth,
140
154
  });
141
155
  this.applyInputStyles(this.accountTypeEl, mergedStyles, 'right');
142
- containerEl.appendChild(this.accountTypeEl);
156
+ containerEl.appendChild((0, tokenizer_utils_1.wrapFieldWithLabel)(this.accountTypeEl, 'Account Type', mergedStyles));
143
157
  }
144
158
  this.mergedStyles = mergedStyles;
145
159
  this.currentValidationState = {
@@ -237,8 +251,6 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
237
251
  window.addEventListener('message', this.messageHandler);
238
252
  this.iframe.onload = () => {
239
253
  clearTimeout(timeout);
240
- if (this.enableTestMode && this.mode === 'credit_card') {
241
- }
242
254
  this.emit('ready');
243
255
  resolve();
244
256
  };
@@ -684,7 +696,34 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
684
696
  this.emit('validation', this.currentValidationState);
685
697
  }
686
698
  }
699
+ static measureCvvLabelMarginLeft(monthWidth, yearWidth, cvvMarginLeft) {
700
+ var _a;
701
+ const targetCvvX = monthWidth + 4 + 4 + yearWidth + 12 + cvvMarginLeft;
702
+ const host = document.createElement('div');
703
+ host.style.cssText =
704
+ 'position:absolute;visibility:hidden;left:0;top:0;width:9999px;height:0;overflow:hidden;';
705
+ document.body.appendChild(host);
706
+ const shadow = host.attachShadow({ mode: 'open' });
707
+ shadow.innerHTML = [
708
+ '<input type="text" size="2" style="margin-right:4px">',
709
+ '<label>/</label>',
710
+ '<input type="text" size="4" style="margin-left:4px;margin-right:12px">',
711
+ '<input type="tel" size="5">',
712
+ ].join('');
713
+ const inputs = shadow.querySelectorAll('input');
714
+ const hostX = host.getBoundingClientRect().x;
715
+ const cvvRect = (_a = inputs[2]) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
716
+ const defaultCvvX = cvvRect ? cvvRect.x - hostX : -1;
717
+ document.body.removeChild(host);
718
+ if (defaultCvvX <= 0 || defaultCvvX > 500) {
719
+ console.warn('[CardConnect] CVV measurement out of range, using fallback margin-left:100px');
720
+ return 100;
721
+ }
722
+ const predictedLabelLeft = defaultCvvX + 8;
723
+ return Math.round(targetCvvX - predictedLabelLeft);
724
+ }
687
725
  static generateIframeUrl(baseUrl, container) {
726
+ var _a, _b, _c, _d, _e, _f, _g, _h;
688
727
  const params = new URLSearchParams({
689
728
  invalidinputevent: 'true',
690
729
  enhancedresponse: 'true',
@@ -693,30 +732,46 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
693
732
  formatinput: 'true',
694
733
  unique: 'true',
695
734
  norsa: 'true',
696
- placeholder: 'Card Number *',
697
- placeholdercvv: 'CVV',
735
+ placeholder: ((_a = container.placeholders) === null || _a === void 0 ? void 0 : _a.cardNumber) || 'Card Number *',
736
+ placeholdercvv: ((_b = container.placeholders) === null || _b === void 0 ? void 0 : _b.cvv) || 'CVV',
698
737
  invalidcreditcardevent: 'true',
699
738
  invalidexpiry: 'true',
700
739
  invalidcvv: 'true',
701
740
  });
741
+ const mergedStyles = (0, styles_1.mergeStyles)(styles_1.DEFAULT_UNIFIED_STYLES, container.styling);
742
+ const showLabelsInUrl = ((_c = mergedStyles.label) === null || _c === void 0 ? void 0 : _c.show) && container.layout === 'two-line';
743
+ if (showLabelsInUrl) {
744
+ params.set('cardlabel', 'Card Number');
745
+ params.set('expirylabel', 'Expiration');
746
+ params.set('cvvlabel', 'CVV');
747
+ }
748
+ else {
749
+ params.set('cardlabel', '');
750
+ params.set('expirylabel', '');
751
+ params.set('cvvlabel', '');
752
+ }
702
753
  if (container.layout === 'two-line') {
703
754
  params.set('useexpiryfield', 'true');
704
755
  params.set('orientation', 'horizontal');
705
- params.set('placeholdermonth', 'MM');
706
- params.set('placeholderyear', 'YYYY');
756
+ params.set('placeholdermonth', ((_d = container.placeholders) === null || _d === void 0 ? void 0 : _d.expiryMonth) || 'MM');
757
+ params.set('placeholderyear', ((_e = container.placeholders) === null || _e === void 0 ? void 0 : _e.expiryYear) || 'YYYY');
707
758
  }
708
759
  else {
709
760
  params.set('orientation', 'horizontal');
710
- params.set('placeholdermonth', 'MM');
711
- params.set('placeholderyear', 'YYYY');
761
+ params.set('placeholdermonth', ((_f = container.placeholders) === null || _f === void 0 ? void 0 : _f.expiryMonth) || 'MM');
762
+ params.set('placeholderyear', ((_g = container.placeholders) === null || _g === void 0 ? void 0 : _g.expiryYear) || 'YYYY');
712
763
  }
713
- const mergedStyles = (0, styles_1.mergeStyles)(styles_1.DEFAULT_UNIFIED_STYLES, container.styling);
714
764
  const isDesktopSafari = typeof navigator !== 'undefined' &&
715
765
  /Safari/.test(navigator.userAgent) &&
716
766
  /Apple Computer/.test(navigator.vendor) &&
717
767
  !/Chrome/.test(navigator.userAgent) &&
718
768
  !/Mobile/.test(navigator.userAgent);
719
- const cssString = CardConnectTokenizer.generateCardConnectCss(mergedStyles, (container.layout || 'single-line'), isDesktopSafari);
769
+ const showLabels = ((_h = mergedStyles.label) === null || _h === void 0 ? void 0 : _h.show) && container.layout === 'two-line';
770
+ let cvvLabelMarginLeft;
771
+ if (showLabels && typeof document !== 'undefined') {
772
+ cvvLabelMarginLeft = CardConnectTokenizer.measureCvvLabelMarginLeft(60, 80, 40);
773
+ }
774
+ const cssString = CardConnectTokenizer.generateCardConnectCss(mergedStyles, (container.layout || 'single-line'), isDesktopSafari, cvvLabelMarginLeft);
720
775
  const queryPairs = [];
721
776
  params.forEach((value, key) => {
722
777
  queryPairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
@@ -731,7 +786,7 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
731
786
  iframe.style.width = '100%';
732
787
  iframe.style.height = styles.input.height;
733
788
  iframe.style.border = 'none';
734
- iframe.style.overflow = 'hidden';
789
+ iframe.style.overflow = '';
735
790
  iframe.style.display = 'block';
736
791
  iframe.style.minWidth = '0';
737
792
  if (styles.container) {
@@ -749,18 +804,30 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
749
804
  iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms');
750
805
  return iframe;
751
806
  }
752
- static generateCardConnectCss(styles, layout = 'single-line', isDesktopSafari = false) {
753
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
807
+ static generateCardConnectCss(styles, layout = 'single-line', isDesktopSafari = false, cvvLabelMarginLeft) {
808
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
754
809
  const css = [];
755
- if (layout === 'two-line') {
756
- css.push('html,form,body{margin:0;padding:0;}');
810
+ const showLabelsInIframe = ((_a = styles.label) === null || _a === void 0 ? void 0 : _a.show) && layout === 'two-line';
811
+ if (showLabelsInIframe) {
812
+ const labelCss = `font-size:${styles.label.fontSize};font-weight:${styles.label.fontWeight};font-family:${styles.label.fontFamily};color:${styles.label.color};margin-bottom:${styles.label.marginBottom}`;
813
+ css.push(`label{${labelCss};}`);
814
+ css.push(`label[for="ccexpiryfieldyear"]{display:none;}`);
815
+ css.push(`br{line-height:0;font-size:0;margin:0;}`);
816
+ css.push(`input,select{margin-top:0;margin-bottom:0;}`);
817
+ }
818
+ else {
757
819
  css.push('label{display:none;}');
758
- css.push('br{display:none;}');
820
+ }
821
+ if (layout === 'two-line') {
822
+ css.push('html,body{margin:0;padding:0;overflow:hidden;}');
823
+ css.push('form{margin:0;padding:0;width:100%;box-sizing:border-box;}');
824
+ if (!showLabelsInIframe) {
825
+ css.push('br{display:none;}');
826
+ }
759
827
  }
760
828
  else {
761
829
  css.push('body{margin:0;padding:0;display:flex;align-items:center;}');
762
830
  css.push('form{margin:0;padding:0;display:flex;width:100%;align-items:center;}');
763
- css.push('label{display:none;}');
764
831
  css.push('br{display:none;}');
765
832
  }
766
833
  const isConnected = styles.container.gap === '0';
@@ -793,13 +860,22 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
793
860
  }
794
861
  if (layout === 'two-line') {
795
862
  css.push('input#ccnumfield{width:100%;display:block;margin-bottom:8px;}');
796
- const twoLinePadding = ((_a = styles.twoLine) === null || _a === void 0 ? void 0 : _a.padding) || ((_b = styles.input) === null || _b === void 0 ? void 0 : _b.padding) || '10px';
797
- const twoLineFontSize = ((_c = styles.twoLine) === null || _c === void 0 ? void 0 : _c.fontSize) || ((_d = styles.input) === null || _d === void 0 ? void 0 : _d.fontSize) || '14px';
798
- const twoLineTextAlign = ((_e = styles.twoLine) === null || _e === void 0 ? void 0 : _e.textAlign) || 'left';
799
- css.push(`input#ccexpiryfieldmonth{width:25%;padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};}`);
800
- css.push(`input#ccexpiryfieldyear{width:35%;padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};}`);
801
- css.push(`input#cccvvfield{width:calc(40% - 16px);padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};margin-left:-4px;}`);
802
- if ((_f = styles.input) === null || _f === void 0 ? void 0 : _f.borderRadius) {
863
+ const twoLinePadding = ((_b = styles.twoLine) === null || _b === void 0 ? void 0 : _b.padding) || ((_c = styles.input) === null || _c === void 0 ? void 0 : _c.padding) || '10px';
864
+ const twoLineFontSize = ((_d = styles.twoLine) === null || _d === void 0 ? void 0 : _d.fontSize) || ((_e = styles.input) === null || _e === void 0 ? void 0 : _e.fontSize) || '14px';
865
+ const twoLineTextAlign = ((_f = styles.twoLine) === null || _f === void 0 ? void 0 : _f.textAlign) || 'left';
866
+ if (showLabelsInIframe) {
867
+ css.push(`input#ccexpiryfieldmonth{width:60px;padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};}`);
868
+ css.push(`input#ccexpiryfieldyear{width:80px;padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};}`);
869
+ css.push(`input#cccvvfield{width:80px;margin-left:40px;padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};}`);
870
+ const labelMargin = cvvLabelMarginLeft !== null && cvvLabelMarginLeft !== void 0 ? cvvLabelMarginLeft : 100;
871
+ css.push(`label#cccvvlabel{margin-left:${labelMargin}px;}`);
872
+ }
873
+ else {
874
+ css.push(`input#ccexpiryfieldmonth{min-width:4em;padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};}`);
875
+ css.push(`input#ccexpiryfieldyear{min-width:4em;padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};}`);
876
+ css.push(`input#cccvvfield{min-width:4em;padding:${twoLinePadding};font-size:${twoLineFontSize};text-align:${twoLineTextAlign};}`);
877
+ }
878
+ if ((_g = styles.input) === null || _g === void 0 ? void 0 : _g.borderRadius) {
803
879
  css.push(`input{border-radius:${styles.input.borderRadius};}`);
804
880
  }
805
881
  }
@@ -808,7 +884,7 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
808
884
  css.push('select#ccexpirymonth{width:16%;margin:0;margin-right:-12px;}');
809
885
  css.push('select#ccexpiryyear{width:20%;}');
810
886
  css.push('input#cccvvfield{width:20%;margin:0;margin-left:-12px;}');
811
- if ((_g = styles.input) === null || _g === void 0 ? void 0 : _g.borderRadius) {
887
+ if ((_h = styles.input) === null || _h === void 0 ? void 0 : _h.borderRadius) {
812
888
  css.push(`input#ccnumfield{border-radius:${styles.input.borderRadius} 0 0 ${styles.input.borderRadius};border-right:none;}`);
813
889
  css.push('select#ccexpirymonth{border-radius:0;border-right:none;}');
814
890
  css.push('select#ccexpiryyear{border-radius:0;border-right:none;}');
@@ -826,7 +902,7 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
826
902
  css.push(`select#ccexpirymonth{width:15%;margin-right:${marginRight};}`);
827
903
  css.push(`select#ccexpiryyear{width:20%;margin-right:${marginRight};}`);
828
904
  css.push('input#cccvvfield{width:15%;}');
829
- if ((_h = styles.input) === null || _h === void 0 ? void 0 : _h.borderRadius) {
905
+ if ((_j = styles.input) === null || _j === void 0 ? void 0 : _j.borderRadius) {
830
906
  css.push(`input,select{border-radius:${styles.input.borderRadius};}`);
831
907
  }
832
908
  }
@@ -842,7 +918,7 @@ class CardConnectTokenizer extends Tokenizer_1.Tokenizer {
842
918
  if (focusStyles.length > 0) {
843
919
  css.push(`input:focus{${focusStyles.join(';')};}`);
844
920
  css.push(`select:focus{${focusStyles.join(';')};}`);
845
- if (isConnected && ((_j = styles.input) === null || _j === void 0 ? void 0 : _j.border)) {
921
+ if (isConnected && ((_k = styles.input) === null || _k === void 0 ? void 0 : _k.border)) {
846
922
  css.push(`input#ccnumfield:focus{border:${styles.input.border};${focusStyles.join(';')};}`);
847
923
  css.push(`select#ccexpirymonth:focus{border:${styles.input.border};${focusStyles.join(';')};}`);
848
924
  css.push(`select#ccexpiryyear:focus{border:${styles.input.border};${focusStyles.join(';')};}`);
@@ -6,6 +6,7 @@ export declare class SpreedlyTokenizer extends Tokenizer {
6
6
  private environmentKey;
7
7
  private containerId;
8
8
  private layout;
9
+ private customPlaceholders?;
9
10
  private spreedly;
10
11
  private currentValidationState;
11
12
  private mergedStyles;
@@ -63,6 +64,7 @@ export declare class SpreedlyTokenizer extends Tokenizer {
63
64
  private updateOverallValidation;
64
65
  private handleFieldEvent;
65
66
  private createInternalElements;
67
+ private appendField;
66
68
  private createCreditCardFields;
67
69
  private createBankAccountFields;
68
70
  private createUSBankAccountFields;