@rebilly/instruments 4.5.0 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/.babelrc +24 -26
  2. package/CHANGELOG.md +14 -0
  3. package/dist/index.js +8 -8
  4. package/dist/index.min.js +8 -8
  5. package/package.json +14 -3
  6. package/project.json +9 -0
  7. package/rollup.config.mjs +21 -26
  8. package/src/data/options-schema/index.js +94 -78
  9. package/src/data/options-schema/schemas/options-schema.js +419 -411
  10. package/src/events/base-event.js +34 -34
  11. package/src/events/events.spec.js +6 -6
  12. package/src/events/index.js +5 -5
  13. package/src/functions/destroy.js +19 -19
  14. package/src/functions/destroy.spec.js +41 -41
  15. package/src/functions/mount/fetch-data.js +200 -193
  16. package/src/functions/mount/fetch-data.spec.js +287 -285
  17. package/src/functions/mount/get-lead-source-data.js +31 -31
  18. package/src/functions/mount/get-lead-source-data.spec.js +19 -19
  19. package/src/functions/mount/index.js +73 -65
  20. package/src/functions/mount/mount.spec.js +77 -66
  21. package/src/functions/mount/setup-element.js +23 -23
  22. package/src/functions/mount/setup-framepay-theme.js +86 -68
  23. package/src/functions/mount/setup-framepay.js +9 -5
  24. package/src/functions/mount/setup-i18n.js +15 -15
  25. package/src/functions/mount/setup-options.js +74 -74
  26. package/src/functions/mount/setup-options.spec.js +323 -287
  27. package/src/functions/mount/setup-storefront.js +15 -20
  28. package/src/functions/mount/setup-styles-vars.js +19 -22
  29. package/src/functions/mount/setup-user-flow.js +51 -47
  30. package/src/functions/on.js +5 -5
  31. package/src/functions/on.spec.js +60 -51
  32. package/src/functions/purchase.js +151 -146
  33. package/src/functions/purchase.spec.js +59 -56
  34. package/src/functions/setup.js +53 -53
  35. package/src/functions/setup.spec.js +88 -75
  36. package/src/functions/show.js +13 -14
  37. package/src/functions/show.spec.js +53 -53
  38. package/src/functions/update.js +30 -28
  39. package/src/functions/update.spec.js +94 -93
  40. package/src/i18n/en.json +32 -32
  41. package/src/i18n/es.json +29 -29
  42. package/src/i18n/i18n.spec.js +18 -18
  43. package/src/i18n/index.js +48 -48
  44. package/src/instance.js +36 -36
  45. package/src/instance.spec.js +29 -27
  46. package/src/loader/index.js +95 -70
  47. package/src/loader/loader.spec.js +63 -63
  48. package/src/state/iframes.js +21 -21
  49. package/src/state/index.js +56 -54
  50. package/src/storefront/account-and-website.js +10 -8
  51. package/src/storefront/account-and-website.spec.js +55 -55
  52. package/src/storefront/deposit-requests.js +6 -6
  53. package/src/storefront/fetch-plans-from-addons-bumpOffer.js +21 -19
  54. package/src/storefront/fetch-products-from-plans.js +52 -51
  55. package/src/storefront/fetch-products-from-plans.spec.js +90 -87
  56. package/src/storefront/index.js +56 -49
  57. package/src/storefront/invoices.js +15 -15
  58. package/src/storefront/invoices.spec.js +69 -65
  59. package/src/storefront/models/account-model.js +29 -32
  60. package/src/storefront/models/base-model.js +6 -9
  61. package/src/storefront/models/deposit-request-model.js +22 -13
  62. package/src/storefront/models/invoice-model.js +16 -16
  63. package/src/storefront/models/payment-metadata.js +4 -4
  64. package/src/storefront/models/plan-model.js +73 -64
  65. package/src/storefront/models/ready-to-pay-model.js +59 -59
  66. package/src/storefront/models/summary-model.js +43 -46
  67. package/src/storefront/models/transaction-model.js +11 -14
  68. package/src/storefront/payment-instruments.js +38 -35
  69. package/src/storefront/payment-instruments.spec.js +81 -62
  70. package/src/storefront/purchase.js +50 -44
  71. package/src/storefront/purchase.spec.js +40 -40
  72. package/src/storefront/ready-to-pay.js +75 -77
  73. package/src/storefront/ready-to-pay.spec.js +59 -54
  74. package/src/storefront/storefront.spec.js +9 -9
  75. package/src/storefront/summary.js +93 -67
  76. package/src/storefront/summary.spec.js +108 -106
  77. package/src/storefront/transactions.js +6 -6
  78. package/src/style/base/default-theme.js +928 -923
  79. package/src/style/base/theme.js +21 -21
  80. package/src/style/base/theme.spec.js +13 -13
  81. package/src/style/index.js +3 -3
  82. package/src/style/utils/border.js +40 -27
  83. package/src/style/utils/color-values.js +18 -18
  84. package/src/style/utils/minifyCss.js +6 -6
  85. package/src/utils/add-dom-element.js +14 -14
  86. package/src/utils/format-currency.js +6 -5
  87. package/src/utils/has-valid-css-selector.js +2 -2
  88. package/src/utils/index.js +6 -6
  89. package/src/utils/is-dom-element.js +1 -1
  90. package/src/utils/process-property-as-dom-element.js +22 -22
  91. package/src/utils/quantity.js +26 -28
  92. package/src/utils/sleep.js +3 -1
  93. package/src/views/amount-selector.js +37 -36
  94. package/src/views/common/iframe/base-iframe.js +53 -52
  95. package/src/views/common/iframe/events/change-iframe-src-handler.js +5 -5
  96. package/src/views/common/iframe/events/dispatch-event-handler.js +4 -4
  97. package/src/views/common/iframe/events/resize-component-handler.js +8 -8
  98. package/src/views/common/iframe/events/show-error-handler.js +2 -2
  99. package/src/views/common/iframe/events/stop-loader-handler.js +8 -8
  100. package/src/views/common/iframe/events/update-addons-handler.js +20 -13
  101. package/src/views/common/iframe/events/update-coupons-handler.js +9 -9
  102. package/src/views/common/iframe/events/update-items-handler.js +26 -22
  103. package/src/views/common/iframe/modal-iframe.js +67 -56
  104. package/src/views/common/iframe/view-iframe.js +11 -11
  105. package/src/views/common/render-utilities.js +2 -2
  106. package/src/views/confirmation.js +33 -30
  107. package/src/views/errors.js +89 -79
  108. package/src/views/form.js +41 -37
  109. package/src/views/method-selector/express-methods.js +46 -46
  110. package/src/views/method-selector/generate-digital-wallet.js +46 -45
  111. package/src/views/method-selector/generate-digital-wallet.spec.js +104 -102
  112. package/src/views/method-selector/generate-framepay-config.js +53 -51
  113. package/src/views/method-selector/generate-framepay-config.spec.js +197 -173
  114. package/src/views/method-selector/get-method-data.js +5 -6
  115. package/src/views/method-selector/get-payment-methods.js +18 -16
  116. package/src/views/method-selector/get-payment-methods.spec.js +29 -27
  117. package/src/views/method-selector/index.js +154 -139
  118. package/src/views/method-selector/method-selector.spec.js +13 -13
  119. package/src/views/method-selector/mount-bump-offer.js +65 -49
  120. package/src/views/method-selector/mount-express-methods.js +89 -85
  121. package/src/views/modal.js +74 -67
  122. package/src/views/result.js +14 -14
  123. package/src/views/summary.js +25 -26
  124. package/tests/async-utilities.js +13 -13
  125. package/tests/mocks/framepay-mock.js +9 -8
  126. package/tests/mocks/rebilly-api-mock.js +5 -3
  127. package/tests/mocks/rebilly-instruments-mock.js +121 -117
  128. package/tests/mocks/storefront-api-mock.js +55 -48
  129. package/tests/mocks/storefront-mock.js +10 -14
  130. package/tests/msw/server.js +6 -6
  131. package/tests/setup-test.js +14 -16
  132. package/vitest.config.js +14 -14
  133. package/.eslintrc.js +0 -34
  134. package/.prettierrc.js +0 -11
@@ -1,32 +1,32 @@
1
1
  import { getLeadSourceData } from './get-lead-source-data';
2
2
 
3
3
  export const mockLocation = (url) => {
4
- const location = new URL(url);
5
- delete window.location;
6
- window.location = location;
4
+ const location = new URL(url);
5
+ delete window.location;
6
+ window.location = location;
7
7
  };
8
8
 
9
9
  describe('getLeadSourceData', () => {
10
- it('should return an object with a path property that matches the current URL', () => {
11
- const result = getLeadSourceData();
12
- expect(result.path).toBe(window.location.href);
13
- });
10
+ it('should return an object with a path property that matches the current URL', () => {
11
+ const result = getLeadSourceData();
12
+ expect(result.path).toBe(window.location.href);
13
+ });
14
14
 
15
- it('should return the path without the query if the query is longer than 255 characters', () => {
16
- const query = Array(300).fill('a').join('');
15
+ it('should return the path without the query if the query is longer than 255 characters', () => {
16
+ const query = Array(300).fill('a').join('');
17
17
 
18
- const pathWithoutQuery = 'http://www.example.com/path';
19
- mockLocation(`${pathWithoutQuery}?${query}`);
18
+ const pathWithoutQuery = 'http://www.example.com/path';
19
+ mockLocation(`${pathWithoutQuery}?${query}`);
20
20
 
21
- const result = getLeadSourceData();
22
- expect(result.path).toBe(pathWithoutQuery);
23
- });
21
+ const result = getLeadSourceData();
22
+ expect(result.path).toBe(pathWithoutQuery);
23
+ });
24
24
 
25
- it('should add the query parameters to the returned object', () => {
26
- const query = 'utm_source=google&utm_medium=cpc&utm_campaign=example';
27
- mockLocation(`http://www.example.com/path?${query}`);
25
+ it('should add the query parameters to the returned object', () => {
26
+ const query = 'utm_source=google&utm_medium=cpc&utm_campaign=example';
27
+ mockLocation(`http://www.example.com/path?${query}`);
28
28
 
29
- expect(getLeadSourceData()).toMatchInlineSnapshot(`
29
+ expect(getLeadSourceData()).toMatchInlineSnapshot(`
30
30
  {
31
31
  "campaign": "example",
32
32
  "medium": "cpc",
@@ -34,5 +34,5 @@ describe('getLeadSourceData', () => {
34
34
  "source": "google",
35
35
  }
36
36
  `);
37
- });
37
+ });
38
38
  });
@@ -16,82 +16,90 @@ import { showError } from '../../views/errors';
16
16
 
17
17
  /** See src/data/options-schema for options structure */
18
18
  export async function mount({
19
- setupFramepay = setupFramepayInstance,
20
- ...options
19
+ setupFramepay = setupFramepayInstance,
20
+ ...options
21
21
  } = {}) {
22
- try {
23
- state.data = {};
24
- state.options = {};
22
+ try {
23
+ state.data = {};
24
+ state.options = {};
25
25
 
26
- // Setup options
27
- state.options = setupOptions({ options });
26
+ // Setup options
27
+ state.options = setupOptions({ options });
28
28
 
29
- // Setup DOM
30
- state.form = setupElement({ element: 'form' });
31
- state.summary = setupElement({ element: 'summary' });
32
- // hardcode max-width to not break UX
33
- // PayPal button cannot exceed 750px;
34
- state.form.style.maxWidth = '750px';
35
- if (state.summary) {
36
- state.summary.style.maxWidth = '750px';
37
- }
29
+ // Setup DOM
30
+ state.form = setupElement({ element: 'form' });
31
+ state.summary = setupElement({ element: 'summary' });
32
+ // hardcode max-width to not break UX
33
+ // PayPal button cannot exceed 750px;
34
+ state.form.style.maxWidth = '750px';
35
+ if (state.summary) {
36
+ state.summary.style.maxWidth = '750px';
37
+ }
38
38
 
39
- // Setup state
40
- state.storefront = setupStorefront();
41
- state.mainStyleVars = setupStylesVars();
42
- state.options.themeFramepay = setupFramepayTheme();
39
+ // Setup state
40
+ state.storefront = setupStorefront();
41
+ state.mainStyleVars = setupStylesVars();
42
+ state.options.themeFramepay = setupFramepayTheme();
43
43
 
44
- // Setup loader
45
- state.loader.addDOMElement({ el: state.form });
46
- state.loader.addDOMElement({ section: 'summary', el: state.summary });
47
- state.loader.startLoading({ section: 'summary', id: 'rebilly-instruments-summary' });
48
- state.loader.startLoading({ id: 'rebilly-instruments-form' });
44
+ // Setup loader
45
+ state.loader.addDOMElement({ el: state.form });
46
+ state.loader.addDOMElement({ section: 'summary', el: state.summary });
47
+ state.loader.startLoading({
48
+ section: 'summary',
49
+ id: 'rebilly-instruments-summary',
50
+ });
51
+ state.loader.startLoading({ id: 'rebilly-instruments-form' });
49
52
 
50
- const [data] = await Promise.all([
51
- fetchData(),
52
- setupFramepay()
53
- ]);
54
- state.data = data;
55
- Events.dataReady.dispatch(state.data);
53
+ const [data] = await Promise.all([fetchData(), setupFramepay()]);
54
+ state.data = data;
55
+ Events.dataReady.dispatch(state.data);
56
56
 
57
- state.i18n = setupI18n();
57
+ state.i18n = setupI18n();
58
58
 
59
- // Update state options from data
60
- if ((!state.options.websiteId) && state.data.transaction?.websiteId) {
61
- state.options.websiteId = state.data.transaction.websiteId;
62
- } else if ((!state.options.websiteId) && state.data.invoice?.websiteId) {
63
- state.options.websiteId = state.data.invoice.websiteId;
64
- }
65
- if (state.data.transaction && state.data.transaction?.type === 'setup') {
66
- state.options.transactionType = 'setup';
67
- }
59
+ // Update state options from data
60
+ if (!state.options.websiteId && state.data.transaction?.websiteId) {
61
+ state.options.websiteId = state.data.transaction.websiteId;
62
+ } else if (!state.options.websiteId && state.data.invoice?.websiteId) {
63
+ state.options.websiteId = state.data.invoice.websiteId;
64
+ }
65
+ if (
66
+ state.data.transaction &&
67
+ state.data.transaction?.type === 'setup'
68
+ ) {
69
+ state.options.transactionType = 'setup';
70
+ }
68
71
 
69
- // Mount content
70
- if (state.form) {
71
- mountForm()
72
- .then(() => determineFirstView());
73
- }
74
- if (state.summary) {
75
- mountSummary();
76
- }
77
- state.i18n({state});
78
- state.hasMounted = true;
72
+ // Mount content
73
+ if (state.form) {
74
+ mountForm().then(() => determineFirstView());
75
+ }
76
+ if (state.summary) {
77
+ mountSummary();
78
+ }
79
+ state.i18n({ state });
80
+ state.hasMounted = true;
79
81
 
80
- const invoiceId = state.options?.invoiceId || state.data?.transaction?.invoiceId;
81
- if(invoiceId && state.data.invoice.isPaid) {
82
- state.loader.stopLoading({id: 'rebilly-instruments-form'});
83
- removeForm();
84
- showError(state.translate.getTranslation('form.error.invoiceIsPaid'), false);
85
- }
82
+ const invoiceId =
83
+ state.options?.invoiceId || state.data?.transaction?.invoiceId;
84
+ if (invoiceId && state.data.invoice.isPaid) {
85
+ state.loader.stopLoading({ id: 'rebilly-instruments-form' });
86
+ removeForm();
87
+ showError(
88
+ state.translate.getTranslation('form.error.invoiceIsPaid'),
89
+ false,
90
+ );
91
+ }
86
92
 
87
- if (!data.readyToPay?.length) {
88
- state.loader.stopLoading({id: 'rebilly-instruments-form'});
89
- showError(state.translate.getTranslation('form.error.noPaymentMethods'))
93
+ if (!data.readyToPay?.length) {
94
+ state.loader.stopLoading({ id: 'rebilly-instruments-form' });
95
+ showError(
96
+ state.translate.getTranslation('form.error.noPaymentMethods'),
97
+ );
98
+ }
99
+ } catch (error) {
100
+ showError(error);
101
+ throw error;
90
102
  }
91
- } catch (error) {
92
- showError(error);
93
- throw error;
94
- }
95
103
 
96
- setupUserFlow({state});
104
+ setupUserFlow({ state });
97
105
  }
@@ -1,85 +1,96 @@
1
- import {RenderMockRebillyInstruments} from 'tests/mocks/rebilly-instruments-mock';
1
+ import { RenderMockRebillyInstruments } from 'tests/mocks/rebilly-instruments-mock';
2
2
  import { sleep } from '@/utils';
3
3
 
4
4
  describe('RebillyInstruments instance', () => {
5
- it('should inject HTML to the merchant\'s website', async () => {
6
- const framePayScriptUrl = 'https://framepay.rebilly.com/rebilly.js';
7
- const framePayStyleUrl = 'https://framepay.rebilly.com/rebilly.css';
5
+ it("should inject HTML to the merchant's website", async () => {
6
+ const framePayScriptUrl = 'https://framepay.rebilly.com/rebilly.js';
7
+ const framePayStyleUrl = 'https://framepay.rebilly.com/rebilly.css';
8
8
 
9
- const options = {
10
- form: '.form-selector',
11
- summary: '.summary-selector',
12
- locale: 'auto',
13
- items: [
14
- {
15
- planId: 'test-plan-id-1',
16
- quantity: 1
17
- }
18
- ],
19
- theme: {
20
- colorBackground: '#000'
21
- },
22
- css: `
9
+ const options = {
10
+ form: '.form-selector',
11
+ summary: '.summary-selector',
12
+ locale: 'auto',
13
+ items: [
14
+ {
15
+ planId: 'test-plan-id-1',
16
+ quantity: 1,
17
+ },
18
+ ],
19
+ theme: {
20
+ colorBackground: '#000',
21
+ },
22
+ css: `
23
23
  .rebilly-instruments-summary-line-item-synopsis-title {
24
24
  color: rgb(0, 68, 212);
25
25
  }
26
26
  `,
27
- _dev: {
28
- framePayStyleLink: framePayStyleUrl
29
- },
30
- };
31
- await RenderMockRebillyInstruments(options);
32
-
33
- const sleepMilliseconds = 1000;
34
- await sleep(sleepMilliseconds);
27
+ _dev: {
28
+ framePayStyleLink: framePayStyleUrl,
29
+ },
30
+ };
31
+ await RenderMockRebillyInstruments(options);
35
32
 
36
- // Mounts form and summary
37
- const summarySelector = document.querySelector('.summary-selector');
38
- const iframe = summarySelector.querySelector('iframe');
39
- expect(iframe.getAttribute('name')).toEqual('rebilly-instruments-summary');
40
- expect(iframe.getAttribute('class')).toEqual('rebilly-instruments-iframe');
41
- expect(iframe.getAttribute('loading')).toEqual('lazy');
42
- expect(iframe.getAttribute('allow')).toEqual('payment');
43
- expect(iframe.getAttribute('src')).toEqual('https://forms.test.rebilly.dev?name=rebilly-instruments-summary');
33
+ const sleepMilliseconds = 1000;
34
+ await sleep(sleepMilliseconds);
44
35
 
45
- // Theme config overrides initial styles
46
- const STYLE_VARS = document.querySelectorAll('style[type="text/css"]')[0];
36
+ // Mounts form and summary
37
+ const summarySelector = document.querySelector('.summary-selector');
38
+ const iframe = summarySelector.querySelector('iframe');
39
+ expect(iframe.getAttribute('name')).toEqual(
40
+ 'rebilly-instruments-summary',
41
+ );
42
+ expect(iframe.getAttribute('class')).toEqual(
43
+ 'rebilly-instruments-iframe',
44
+ );
45
+ expect(iframe.getAttribute('loading')).toEqual('lazy');
46
+ expect(iframe.getAttribute('allow')).toEqual('payment');
47
+ expect(iframe.getAttribute('src')).toEqual(
48
+ 'https://forms.test.rebilly.dev?name=rebilly-instruments-summary',
49
+ );
47
50
 
48
- expect(STYLE_VARS.innerHTML).toMatch(
49
- '--rebilly-colorBackground: #000;'
50
- );
51
+ // Theme config overrides initial styles
52
+ const STYLE_VARS = document.querySelectorAll(
53
+ 'style[type="text/css"]',
54
+ )[0];
51
55
 
52
- // Mounts default FramePay script
53
- const SCRIPTS = [...document.querySelectorAll('head script')];
54
- const FRAMEPAY_SCRIPT = SCRIPTS.find(
55
- (script) => script.src === framePayScriptUrl
56
- );
57
- expect(FRAMEPAY_SCRIPT.src).toEqual(framePayScriptUrl);
56
+ expect(STYLE_VARS.innerHTML).toMatch(
57
+ '--rebilly-colorBackground: #000;',
58
+ );
58
59
 
59
- // Mounts _dev FramePay style
60
- const STYLE_LINKS = [...document.querySelectorAll('head link')];
61
- const FRAMEPAY_STYLE = STYLE_LINKS.find(script => script.href === framePayStyleUrl);
60
+ // Mounts default FramePay script
61
+ const SCRIPTS = [...document.querySelectorAll('head script')];
62
+ const FRAMEPAY_SCRIPT = SCRIPTS.find(
63
+ (script) => script.src === framePayScriptUrl,
64
+ );
65
+ expect(FRAMEPAY_SCRIPT.src).toEqual(framePayScriptUrl);
62
66
 
63
- expect(FRAMEPAY_STYLE.href).toEqual(framePayStyleUrl);
64
- });
67
+ // Mounts _dev FramePay style
68
+ const STYLE_LINKS = [...document.querySelectorAll('head link')];
69
+ const FRAMEPAY_STYLE = STYLE_LINKS.find(
70
+ (script) => script.href === framePayStyleUrl,
71
+ );
65
72
 
66
- it('should mount with JWT pruchase data', async () => {
67
- // Use https://www.jwt.io to help encode and decode JWT
68
- const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkMGYzNWEzYy03N2M0LTQ0NDItOWFhNC03ODA5NDA2NzBjN2IiLCJleHAiOjE2NzM2NDk0ODcsImlhdCI6MTY0MjExMDczOS4zMjYyNDQsImFjbCI6W3sic2NvcGUiOnsib3JnYW5pemF0aW9uSWQiOlsidGVzdC1vcmdhbml6YXRpb24tZCJdLCJ0cmFuc2FjdGlvbklkIjpbInRlc3QtdHJhbnNhY3Rpb24taWQiXX0sInBlcm1pc3Npb25zIjpbMV19XSwiY2xhaW1zIjp7InRyYW5zYWN0aW9uSWQiOiJ0ZXN0LXRyYW5zYWN0aW9uLWlkIn0sIm1lcmNoYW50IjoidGVzdC1vcmdhbml6YXRpb24taWQiLCJjdXN0b21lciI6eyJpZCI6InRlc3QtY3VzdG9tZXItaWQiLCJuYW1lIjoiVGVzdGVyIFRlc3RlcnNvbiIsImNyZWF0ZWRUaW1lIjoiMjAyMi0wMS0xNFQwMDowMDowMCswMDowMCJ9fQ.h4voW-UvXzXRm1JlxkN8cNHhQ_IIPSWWN9BANfBWEHQ';
73
+ expect(FRAMEPAY_STYLE.href).toEqual(framePayStyleUrl);
74
+ });
69
75
 
70
- const options = {
71
- form: '.form-selector',
72
- summary: '.summary-selector',
73
- jwt,
74
- };
76
+ it('should mount with JWT pruchase data', async () => {
77
+ // Use https://www.jwt.io to help encode and decode JWT
78
+ const jwt =
79
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkMGYzNWEzYy03N2M0LTQ0NDItOWFhNC03ODA5NDA2NzBjN2IiLCJleHAiOjE2NzM2NDk0ODcsImlhdCI6MTY0MjExMDczOS4zMjYyNDQsImFjbCI6W3sic2NvcGUiOnsib3JnYW5pemF0aW9uSWQiOlsidGVzdC1vcmdhbml6YXRpb24tZCJdLCJ0cmFuc2FjdGlvbklkIjpbInRlc3QtdHJhbnNhY3Rpb24taWQiXX0sInBlcm1pc3Npb25zIjpbMV19XSwiY2xhaW1zIjp7InRyYW5zYWN0aW9uSWQiOiJ0ZXN0LXRyYW5zYWN0aW9uLWlkIn0sIm1lcmNoYW50IjoidGVzdC1vcmdhbml6YXRpb24taWQiLCJjdXN0b21lciI6eyJpZCI6InRlc3QtY3VzdG9tZXItaWQiLCJuYW1lIjoiVGVzdGVyIFRlc3RlcnNvbiIsImNyZWF0ZWRUaW1lIjoiMjAyMi0wMS0xNFQwMDowMDowMCswMDowMCJ9fQ.h4voW-UvXzXRm1JlxkN8cNHhQ_IIPSWWN9BANfBWEHQ';
75
80
 
76
- const instance = await RenderMockRebillyInstruments(options);
81
+ const options = {
82
+ form: '.form-selector',
83
+ summary: '.summary-selector',
84
+ jwt,
85
+ };
77
86
 
78
- expect(instance.state.options).toEqual(
79
- expect.objectContaining({
80
- transactionId: 'test-transaction-id',
81
- organizationId: 'test-organization-id'
82
- })
83
- );
84
- });
87
+ const instance = await RenderMockRebillyInstruments(options);
88
+
89
+ expect(instance.state.options).toEqual(
90
+ expect.objectContaining({
91
+ transactionId: 'test-transaction-id',
92
+ organizationId: 'test-organization-id',
93
+ }),
94
+ );
95
+ });
85
96
  });
@@ -1,29 +1,29 @@
1
1
  import { processPropertyAsDOMElement } from '../../utils';
2
2
  import state from '../../state';
3
3
 
4
- export default ({element = ''}) => {
5
- const {options} = state;
6
-
7
- if (element !== 'form' && element !== 'summary') {
8
- throw new Error('element must be "form" or "summary"');
9
- }
4
+ export default ({ element = '' }) => {
5
+ const { options } = state;
10
6
 
11
- const getProp = () => {
12
- if (options[element]) {
13
- return options[element]
7
+ if (element !== 'form' && element !== 'summary') {
8
+ throw new Error('element must be "form" or "summary"');
14
9
  }
15
- switch(element) {
16
- case 'summary':
17
- return '.rebilly-instruments-summary'
18
- case 'form':
19
- default:
20
- return '.rebilly-instruments'
21
- }
22
- }
23
10
 
24
- return processPropertyAsDOMElement({
25
- prop: getProp(),
26
- propName: element,
27
- isRequired: ['form'].includes(element)
28
- });
29
- }
11
+ const getProp = () => {
12
+ if (options[element]) {
13
+ return options[element];
14
+ }
15
+ switch (element) {
16
+ case 'summary':
17
+ return '.rebilly-instruments-summary';
18
+ case 'form':
19
+ default:
20
+ return '.rebilly-instruments';
21
+ }
22
+ };
23
+
24
+ return processPropertyAsDOMElement({
25
+ prop: getProp(),
26
+ propName: element,
27
+ isRequired: ['form'].includes(element),
28
+ });
29
+ };
@@ -1,86 +1,104 @@
1
1
  import state from '../../state';
2
2
 
3
3
  function processCSS(rawCss) {
4
- const cssMap = {};
5
- [...rawCss.matchAll(/(--rebilly.*(?=:))[:\s](.*(?=;))/g)]
6
- .forEach(item => {
7
- cssMap[item[1]] = item[2].trim();
8
- });
9
-
10
- function parseValue(value) {
11
- const cssVariables = value.match(/var\((.+?)\)/g);
12
- if(cssVariables) {
13
- let cssValue = value;
14
- cssVariables.forEach(variable => {
15
- const cssVarName = variable.match(/\((.*)\)/i)[1];
16
- cssValue = value.replace(variable, cssMap[cssVarName]);
17
- });
18
- return parseValue(cssValue);
19
- }
20
- return value
21
- }
4
+ const cssMap = {};
5
+ [...rawCss.matchAll(/(--rebilly.*(?=:))[:\s](.*(?=;))/g)].forEach(
6
+ (item) => {
7
+ cssMap[item[1]] = item[2].trim();
8
+ },
9
+ );
22
10
 
23
- return Object.entries(cssMap)
24
- .map(([key, value]) => [key, parseValue(value)]);
11
+ function parseValue(value) {
12
+ const cssVariables = value.match(/var\((.+?)\)/g);
13
+ if (cssVariables) {
14
+ let cssValue = value;
15
+ cssVariables.forEach((variable) => {
16
+ const cssVarName = variable.match(/\((.*)\)/i)[1];
17
+ cssValue = value.replace(variable, cssMap[cssVarName]);
18
+ });
19
+ return parseValue(cssValue);
20
+ }
21
+ return value;
22
+ }
23
+
24
+ return Object.entries(cssMap).map(([key, value]) => [
25
+ key,
26
+ parseValue(value),
27
+ ]);
25
28
  }
26
29
 
27
30
  function replaceCssVars(rawCss) {
28
- const CssVarsObj = {}
29
- processCSS(rawCss).forEach(([key, value]) => {
30
- CssVarsObj[key] = value;
31
- });
32
- return CssVarsObj;
31
+ const CssVarsObj = {};
32
+ processCSS(rawCss).forEach(([key, value]) => {
33
+ CssVarsObj[key] = value;
34
+ });
35
+ return CssVarsObj;
33
36
  }
34
37
 
35
38
  const getStyleProps = (obj, particle = '') => {
36
- const output = {
37
- color: obj[`--rebilly-${particle}ColorText`],
38
- fontFamily: obj[`--rebilly-${particle}FontFamily`],
39
- fontSize: obj[`--rebilly-${particle}FontSize`],
40
- fontWeight: obj[`--rebilly-${particle}FontWeight`],
41
- lineHeight: obj[`--rebilly-${particle}FontLineHeight`],
42
- background: obj[`--rebilly-${particle}ColorBackground`],
43
- boxShadow: obj[`--rebilly-${particle}BoxShadow`],
44
- }
45
- return output;
46
- }
39
+ const output = {
40
+ color: obj[`--rebilly-${particle}ColorText`],
41
+ fontFamily: obj[`--rebilly-${particle}FontFamily`],
42
+ fontSize: obj[`--rebilly-${particle}FontSize`],
43
+ fontWeight: obj[`--rebilly-${particle}FontWeight`],
44
+ lineHeight: obj[`--rebilly-${particle}FontLineHeight`],
45
+ background: obj[`--rebilly-${particle}ColorBackground`],
46
+ boxShadow: obj[`--rebilly-${particle}BoxShadow`],
47
+ };
48
+ return output;
49
+ };
47
50
 
48
51
  export default () => {
49
- const fullCss = `
52
+ const fullCss = `
50
53
  ${state.mainStyleVars}
51
54
  ${state.options?.css || ''}
52
55
  `;
53
56
 
54
- const resolvedCssVarsObj = replaceCssVars(fullCss);
57
+ const resolvedCssVarsObj = replaceCssVars(fullCss);
55
58
 
56
- const framepayStyle = {
57
- base: {
58
- ...getStyleProps(resolvedCssVarsObj, 'input'),
59
- ':hover': getStyleProps(resolvedCssVarsObj, 'inputHover'),
60
- ':focus': getStyleProps(resolvedCssVarsObj, 'inputFocus'),
61
- '::placeholder': getStyleProps(resolvedCssVarsObj, 'inputPlaceholder'),
62
- '::selection': getStyleProps(resolvedCssVarsObj, 'inputSelection'),
63
- },
64
- invalid: {
65
- ...getStyleProps(resolvedCssVarsObj, 'inputError'),
66
- ':hover': getStyleProps(resolvedCssVarsObj, 'inputErrorHover'),
67
- ':focus': getStyleProps(resolvedCssVarsObj, 'inputErrorFocus'),
68
- '::placeholder': getStyleProps(resolvedCssVarsObj, 'inputErrorPlaceholder'),
69
- '::selection': getStyleProps(resolvedCssVarsObj, 'inputErrorSelection'),
70
- },
71
- buttons: {
72
- base: {
73
- ...getStyleProps(resolvedCssVarsObj, 'buttonSecondary'),
74
- ':hover': getStyleProps(resolvedCssVarsObj, 'buttonSecondaryHover'),
75
- ':focus': getStyleProps(resolvedCssVarsObj, 'buttonSecondaryActive'),
76
- },
77
- active: {
78
- ...getStyleProps(resolvedCssVarsObj, 'button'),
79
- ':hover': getStyleProps(resolvedCssVarsObj, 'buttonHover'),
80
- ':focus': getStyleProps(resolvedCssVarsObj, 'buttonActive'),
81
- }
82
- }
83
- }
59
+ const framepayStyle = {
60
+ base: {
61
+ ...getStyleProps(resolvedCssVarsObj, 'input'),
62
+ ':hover': getStyleProps(resolvedCssVarsObj, 'inputHover'),
63
+ ':focus': getStyleProps(resolvedCssVarsObj, 'inputFocus'),
64
+ '::placeholder': getStyleProps(
65
+ resolvedCssVarsObj,
66
+ 'inputPlaceholder',
67
+ ),
68
+ '::selection': getStyleProps(resolvedCssVarsObj, 'inputSelection'),
69
+ },
70
+ invalid: {
71
+ ...getStyleProps(resolvedCssVarsObj, 'inputError'),
72
+ ':hover': getStyleProps(resolvedCssVarsObj, 'inputErrorHover'),
73
+ ':focus': getStyleProps(resolvedCssVarsObj, 'inputErrorFocus'),
74
+ '::placeholder': getStyleProps(
75
+ resolvedCssVarsObj,
76
+ 'inputErrorPlaceholder',
77
+ ),
78
+ '::selection': getStyleProps(
79
+ resolvedCssVarsObj,
80
+ 'inputErrorSelection',
81
+ ),
82
+ },
83
+ buttons: {
84
+ base: {
85
+ ...getStyleProps(resolvedCssVarsObj, 'buttonSecondary'),
86
+ ':hover': getStyleProps(
87
+ resolvedCssVarsObj,
88
+ 'buttonSecondaryHover',
89
+ ),
90
+ ':focus': getStyleProps(
91
+ resolvedCssVarsObj,
92
+ 'buttonSecondaryActive',
93
+ ),
94
+ },
95
+ active: {
96
+ ...getStyleProps(resolvedCssVarsObj, 'button'),
97
+ ':hover': getStyleProps(resolvedCssVarsObj, 'buttonHover'),
98
+ ':focus': getStyleProps(resolvedCssVarsObj, 'buttonActive'),
99
+ },
100
+ },
101
+ };
84
102
 
85
- return framepayStyle;
86
- }
103
+ return framepayStyle;
104
+ };
@@ -1,10 +1,14 @@
1
1
  import state from '../../state';
2
2
 
3
- export default async function setupFramepay () {
4
- const {_dev} = state.options || {};
3
+ export default async function setupFramepay() {
4
+ const { _dev } = state.options || {};
5
5
  const urls = {
6
- script: _dev?.framePayScriptLink || 'https://framepay.rebilly.com/rebilly.js',
7
- style: _dev?.framePayStyleLink || 'https://framepay.rebilly.com/rebilly.css',
6
+ script:
7
+ _dev?.framePayScriptLink ||
8
+ 'https://framepay.rebilly.com/rebilly.js',
9
+ style:
10
+ _dev?.framePayStyleLink ||
11
+ 'https://framepay.rebilly.com/rebilly.css',
8
12
  };
9
13
 
10
14
  return new Promise((resolve) => {
@@ -15,7 +19,7 @@ export default async function setupFramepay () {
15
19
 
16
20
  const framepayScript = document.createElement('script');
17
21
  framepayScript.setAttribute('src', urls.script);
18
-
22
+
19
23
  framepayScript.onload = () => resolve();
20
24
  document.head.append(framepayScript);
21
25
  });