@wise/dynamic-flow-client 5.10.0 → 5.11.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 (29) hide show
  1. package/build/controller/FlowController.js +1 -0
  2. package/build/domain/components/step/ExternalConfirmationComponent.js +5 -9
  3. package/build/domain/mappers/mapStepToComponent.js +1 -1
  4. package/build/domain/mappers/schema/blobSchemaToComponent.js +2 -2
  5. package/build/domain/mappers/schema/tests/test-utils.js +1 -1
  6. package/build/i18n/fr.json +1 -1
  7. package/build/main.css +4 -0
  8. package/build/main.js +17 -16
  9. package/build/main.mjs +17 -16
  10. package/build/renderers/mappers/externalComponentToProps.js +1 -1
  11. package/build/stories/spec/step/ScrollToBottom.story.js +103 -0
  12. package/build/test-utils/DynamicFlowWise.js +1 -1
  13. package/build/test-utils/DynamicFlowWiseModal.js +1 -1
  14. package/build/test-utils/openLinkInNewTab.js +15 -0
  15. package/build/tests/ScrollToBottom.test.js +122 -0
  16. package/build/tests/SingleFileUpload.test.js +81 -1
  17. package/build/types/controller/FlowController.d.ts +0 -1
  18. package/build/types/controller/FlowController.d.ts.map +1 -1
  19. package/build/types/domain/components/step/ExternalConfirmationComponent.d.ts +2 -3
  20. package/build/types/domain/components/step/ExternalConfirmationComponent.d.ts.map +1 -1
  21. package/build/types/domain/mappers/mapStepToComponent.d.ts.map +1 -1
  22. package/build/types/domain/mappers/schema/types.d.ts +1 -0
  23. package/build/types/domain/mappers/schema/types.d.ts.map +1 -1
  24. package/build/types/renderers/mappers/externalComponentToProps.d.ts.map +1 -1
  25. package/build/types/test-utils/openLinkInNewTab.d.ts.map +1 -0
  26. package/package.json +7 -7
  27. package/build/types/utils/openLinkInNewTab.d.ts.map +0 -1
  28. package/build/utils/openLinkInNewTab.js +0 -10
  29. /package/build/types/{utils → test-utils}/openLinkInNewTab.d.ts +0 -0
@@ -58,6 +58,7 @@ export const createFlowController = (props) => {
58
58
  features,
59
59
  httpClient,
60
60
  onBehavior,
61
+ onLink,
61
62
  onPoll,
62
63
  onValueChange,
63
64
  });
@@ -1,5 +1,5 @@
1
1
  import { getInputUpdateFunction } from '../utils/component-utils';
2
- export const createExternalConfirmation = (uid, url, onComponentUpdate) => {
2
+ export const createExternalConfirmation = (uid, url, onLink, onComponentUpdate) => {
3
3
  const update = getInputUpdateFunction(onComponentUpdate);
4
4
  return {
5
5
  type: 'external-confirmation',
@@ -7,15 +7,11 @@ export const createExternalConfirmation = (uid, url, onComponentUpdate) => {
7
7
  uid,
8
8
  url,
9
9
  status: 'initial',
10
- onSuccess() {
11
- update(this, (draft) => {
12
- draft.status = 'success';
13
- });
14
- },
15
- onFailure() {
16
- if (this.status === 'initial') {
10
+ open() {
11
+ if (this.status === 'initial' || this.status === 'failure') {
12
+ const success = onLink(this.url);
17
13
  update(this, (draft) => {
18
- draft.status = 'failure';
14
+ draft.status = success ? 'success' : 'failure';
19
15
  });
20
16
  }
21
17
  },
@@ -57,7 +57,7 @@ export const mapStepToComponent = (_a) => {
57
57
  : undefined;
58
58
  const stepPrefetch = getStepPrefetch(restProps.httpClient, flowRequestCache, submissionBehaviors);
59
59
  const externalConfirmation = (external === null || external === void 0 ? void 0 : external.url)
60
- ? createExternalConfirmation(`${uid}-external-confirmation`, external === null || external === void 0 ? void 0 : external.url, onComponentUpdate)
60
+ ? createExternalConfirmation(`${uid}-external-confirmation`, external === null || external === void 0 ? void 0 : external.url, restProps.onLink, onComponentUpdate)
61
61
  : undefined;
62
62
  const mapperProps = Object.assign(Object.assign({}, restProps), { features,
63
63
  trackEvent,
@@ -3,12 +3,12 @@ import { createUploadInputComponent } from '../../components/UploadInputComponen
3
3
  import { getRequiredCheck } from '../../features/validation/value-checks';
4
4
  import { mapCommonSchemaProps } from './utils/mapCommonSchemaProps';
5
5
  export const blobSchemaToComponent = (schemaMapperProps, mapperProps) => {
6
- const { schema, localValue, required = false, onPersistAsync } = schemaMapperProps;
6
+ const { schema, localValue, model, required = false, onPersistAsync } = schemaMapperProps;
7
7
  const { accepts, cameraConfig, maxSize, source, validationMessages } = schema;
8
8
  const { getErrorMessageFunctions, onComponentUpdate, onValueChange } = mapperProps;
9
9
  const errorMessageFunctions = getErrorMessageFunctions(validationMessages);
10
10
  const validLocalValue = isFile(localValue) ? localValue : null;
11
- const value = onPersistAsync ? validLocalValue : null;
11
+ const value = onPersistAsync && model !== null ? validLocalValue : null;
12
12
  return createUploadInputComponent(Object.assign(Object.assign({}, mapCommonSchemaProps(schemaMapperProps)), { accepts, autoComplete: 'off', cameraConfig, format: 'blob', maxSize,
13
13
  source,
14
14
  value, checks: schema.hidden ? [] : [getRequiredCheck(required, errorMessageFunctions)], schemaOnChange: undefined, onValueChange }), onComponentUpdate);
@@ -4,7 +4,7 @@ import { mockErrorMessageFunctions } from '../../../features/validation/spec-uti
4
4
  import { FeatureFlags } from '../../utils/FeatureFlags';
5
5
  import { makeRequestCache } from '../../../features/prefetch/request-cache';
6
6
  export const getStepMapperProps = () => (Object.assign(Object.assign({}, getMockMapperProps()), { uid: 'root', flowRequestCache: makeRequestCache(), etag: null, loadingState: 'idle', trackEvent: vi.fn(), onPoll: vi.fn() }));
7
- export const getMockMapperProps = (mapperProps = {}) => (Object.assign({ step: {}, stepLocalValue: null, features: new FeatureFlags({}), onComponentUpdate: vi.fn(), onBehavior: vi.fn(), onValueChange: vi.fn(), getErrorMessageFunctions: vi.fn().mockReturnValue(mockErrorMessageFunctions), trackEvent: vi.fn(), logEvent: vi.fn(), httpClient: vi.fn(), registerSubmissionBehavior: vi.fn() }, mapperProps));
7
+ export const getMockMapperProps = (mapperProps = {}) => (Object.assign({ step: {}, stepLocalValue: null, features: new FeatureFlags({}), onComponentUpdate: vi.fn(), onBehavior: vi.fn(), onLink: vi.fn(), onValueChange: vi.fn(), getErrorMessageFunctions: vi.fn().mockReturnValue(mockErrorMessageFunctions), trackEvent: vi.fn(), logEvent: vi.fn(), httpClient: vi.fn(), registerSubmissionBehavior: vi.fn() }, mapperProps));
8
8
  export const getMockSchemaMapperProps = (schemaMapperProps) => (Object.assign({ uid: getRandomId(), localValue: null, model: null, required: false, validationErrors: null }, schemaMapperProps));
9
9
  export const getMockRendererMapperProps = () => ({
10
10
  render: vi.fn(),
@@ -24,7 +24,7 @@
24
24
  "dynamicFlows.ExternalConfirmation.open": "Ouvrir dans un nouvel onglet",
25
25
  "dynamicFlows.ExternalConfirmation.title": "Veuillez confirmer",
26
26
  "dynamicFlows.FileUploadSchema.maxFileSizeError": "Nous sommes désolés, ce fichier est trop volumineux. Veuillez télécharger un fichier plus petit.",
27
- "dynamicFlows.FileUploadSchema.wrongFileTypeError": "Nous sommes désolés, ce format de fichier n'est pas pris en charge. Veuillez en télécharger un autre.",
27
+ "dynamicFlows.FileUploadSchema.wrongFileTypeError": "Désolé, ce format de fichier n'est pas pris en charge. Veuillez en importer un autre.",
28
28
  "dynamicFlows.Help.ariaLabel": "Cliquez ici pour plus d'informations.",
29
29
  "dynamicFlows.MultiSelect.summary": "{first} et {count} de plus",
30
30
  "dynamicFlows.MultipleFileUploadSchema.maxFileSizeError": "Nous sommes désolés, ce fichier est trop volumineux. Veuillez télécharger un fichier plus petit.",
package/build/main.css CHANGED
@@ -212,6 +212,10 @@
212
212
  display: block !important;
213
213
  /* left-aligned by default */
214
214
  }
215
+ .df-button.circular {
216
+ display: flex;
217
+ justify-content: center;
218
+ }
215
219
  .df-button.small.align-center {
216
220
  display: block !important;
217
221
  margin-left: auto;
package/build/main.js CHANGED
@@ -266,7 +266,7 @@ var fr_default = {
266
266
  "dynamicFlows.ExternalConfirmation.open": "Ouvrir dans un nouvel onglet",
267
267
  "dynamicFlows.ExternalConfirmation.title": "Veuillez confirmer",
268
268
  "dynamicFlows.FileUploadSchema.maxFileSizeError": "Nous sommes d\xE9sol\xE9s, ce fichier est trop volumineux. Veuillez t\xE9l\xE9charger un fichier plus petit.",
269
- "dynamicFlows.FileUploadSchema.wrongFileTypeError": "Nous sommes d\xE9sol\xE9s, ce format de fichier n'est pas pris en charge. Veuillez en t\xE9l\xE9charger un autre.",
269
+ "dynamicFlows.FileUploadSchema.wrongFileTypeError": "D\xE9sol\xE9, ce format de fichier n'est pas pris en charge. Veuillez en importer un autre.",
270
270
  "dynamicFlows.Help.ariaLabel": "Cliquez ici pour plus d'informations.",
271
271
  "dynamicFlows.MultiSelect.summary": "{first} et {count} de plus",
272
272
  "dynamicFlows.MultipleFileUploadSchema.maxFileSizeError": "Nous sommes d\xE9sol\xE9s, ce fichier est trop volumineux. Veuillez t\xE9l\xE9charger un fichier plus petit.",
@@ -2496,7 +2496,7 @@ var modalToComponent = (uid, { content, title }, mapperProps, schemaComponents)
2496
2496
  );
2497
2497
 
2498
2498
  // src/domain/components/step/ExternalConfirmationComponent.ts
2499
- var createExternalConfirmation = (uid, url, onComponentUpdate) => {
2499
+ var createExternalConfirmation = (uid, url, onLink, onComponentUpdate) => {
2500
2500
  const update = getInputUpdateFunction(onComponentUpdate);
2501
2501
  return {
2502
2502
  type: "external-confirmation",
@@ -2504,15 +2504,11 @@ var createExternalConfirmation = (uid, url, onComponentUpdate) => {
2504
2504
  uid,
2505
2505
  url,
2506
2506
  status: "initial",
2507
- onSuccess() {
2508
- update(this, (draft) => {
2509
- draft.status = "success";
2510
- });
2511
- },
2512
- onFailure() {
2513
- if (this.status === "initial") {
2507
+ open() {
2508
+ if (this.status === "initial" || this.status === "failure") {
2509
+ const success = onLink(this.url);
2514
2510
  update(this, (draft) => {
2515
- draft.status = "failure";
2511
+ draft.status = success ? "success" : "failure";
2516
2512
  });
2517
2513
  }
2518
2514
  },
@@ -4445,12 +4441,12 @@ var initialiseBase64Value = async (uploadComponent) => {
4445
4441
 
4446
4442
  // src/domain/mappers/schema/blobSchemaToComponent.ts
4447
4443
  var blobSchemaToComponent = (schemaMapperProps, mapperProps) => {
4448
- const { schema, localValue, required = false, onPersistAsync } = schemaMapperProps;
4444
+ const { schema, localValue, model, required = false, onPersistAsync } = schemaMapperProps;
4449
4445
  const { accepts, cameraConfig, maxSize, source, validationMessages } = schema;
4450
4446
  const { getErrorMessageFunctions, onComponentUpdate, onValueChange } = mapperProps;
4451
4447
  const errorMessageFunctions = getErrorMessageFunctions(validationMessages);
4452
4448
  const validLocalValue = isFile(localValue) ? localValue : null;
4453
- const value = onPersistAsync ? validLocalValue : null;
4449
+ const value = onPersistAsync && model !== null ? validLocalValue : null;
4454
4450
  return createUploadInputComponent(
4455
4451
  __spreadProps(__spreadValues({}, mapCommonSchemaProps(schemaMapperProps)), {
4456
4452
  accepts,
@@ -6295,7 +6291,12 @@ var mapStepToComponent = (_a) => {
6295
6291
  }) : void 0;
6296
6292
  const stepRefreshAfter = refreshAfter ? getStepRefreshAfter({ refreshAfter, logEvent, onBehavior }) : void 0;
6297
6293
  const stepPrefetch = getStepPrefetch(restProps.httpClient, flowRequestCache, submissionBehaviors);
6298
- const externalConfirmation = (external == null ? void 0 : external.url) ? createExternalConfirmation(`${uid}-external-confirmation`, external == null ? void 0 : external.url, onComponentUpdate) : void 0;
6294
+ const externalConfirmation = (external == null ? void 0 : external.url) ? createExternalConfirmation(
6295
+ `${uid}-external-confirmation`,
6296
+ external == null ? void 0 : external.url,
6297
+ restProps.onLink,
6298
+ onComponentUpdate
6299
+ ) : void 0;
6299
6300
  const mapperProps = __spreadProps(__spreadValues({}, restProps), {
6300
6301
  features,
6301
6302
  trackEvent,
@@ -6649,6 +6650,7 @@ var createFlowController = (props) => {
6649
6650
  features,
6650
6651
  httpClient,
6651
6652
  onBehavior,
6653
+ onLink,
6652
6654
  onPoll,
6653
6655
  onValueChange
6654
6656
  });
@@ -7527,9 +7529,8 @@ var externalComponentToProps = (component, rendererMapperProps) => {
7527
7529
  type: "external-confirmation",
7528
7530
  uid: component.uid,
7529
7531
  url: component.url,
7530
- status: component.status,
7531
- onSuccess: component.onSuccess.bind(component),
7532
- onFailure: component.onFailure.bind(component),
7532
+ visible: component.status === "failure",
7533
+ open: component.open.bind(component),
7533
7534
  onCancel: component.onCancel.bind(component)
7534
7535
  }, rendererMapperProps);
7535
7536
  };
package/build/main.mjs CHANGED
@@ -236,7 +236,7 @@ var fr_default = {
236
236
  "dynamicFlows.ExternalConfirmation.open": "Ouvrir dans un nouvel onglet",
237
237
  "dynamicFlows.ExternalConfirmation.title": "Veuillez confirmer",
238
238
  "dynamicFlows.FileUploadSchema.maxFileSizeError": "Nous sommes d\xE9sol\xE9s, ce fichier est trop volumineux. Veuillez t\xE9l\xE9charger un fichier plus petit.",
239
- "dynamicFlows.FileUploadSchema.wrongFileTypeError": "Nous sommes d\xE9sol\xE9s, ce format de fichier n'est pas pris en charge. Veuillez en t\xE9l\xE9charger un autre.",
239
+ "dynamicFlows.FileUploadSchema.wrongFileTypeError": "D\xE9sol\xE9, ce format de fichier n'est pas pris en charge. Veuillez en importer un autre.",
240
240
  "dynamicFlows.Help.ariaLabel": "Cliquez ici pour plus d'informations.",
241
241
  "dynamicFlows.MultiSelect.summary": "{first} et {count} de plus",
242
242
  "dynamicFlows.MultipleFileUploadSchema.maxFileSizeError": "Nous sommes d\xE9sol\xE9s, ce fichier est trop volumineux. Veuillez t\xE9l\xE9charger un fichier plus petit.",
@@ -2466,7 +2466,7 @@ var modalToComponent = (uid, { content, title }, mapperProps, schemaComponents)
2466
2466
  );
2467
2467
 
2468
2468
  // src/domain/components/step/ExternalConfirmationComponent.ts
2469
- var createExternalConfirmation = (uid, url, onComponentUpdate) => {
2469
+ var createExternalConfirmation = (uid, url, onLink, onComponentUpdate) => {
2470
2470
  const update = getInputUpdateFunction(onComponentUpdate);
2471
2471
  return {
2472
2472
  type: "external-confirmation",
@@ -2474,15 +2474,11 @@ var createExternalConfirmation = (uid, url, onComponentUpdate) => {
2474
2474
  uid,
2475
2475
  url,
2476
2476
  status: "initial",
2477
- onSuccess() {
2478
- update(this, (draft) => {
2479
- draft.status = "success";
2480
- });
2481
- },
2482
- onFailure() {
2483
- if (this.status === "initial") {
2477
+ open() {
2478
+ if (this.status === "initial" || this.status === "failure") {
2479
+ const success = onLink(this.url);
2484
2480
  update(this, (draft) => {
2485
- draft.status = "failure";
2481
+ draft.status = success ? "success" : "failure";
2486
2482
  });
2487
2483
  }
2488
2484
  },
@@ -4415,12 +4411,12 @@ var initialiseBase64Value = async (uploadComponent) => {
4415
4411
 
4416
4412
  // src/domain/mappers/schema/blobSchemaToComponent.ts
4417
4413
  var blobSchemaToComponent = (schemaMapperProps, mapperProps) => {
4418
- const { schema, localValue, required = false, onPersistAsync } = schemaMapperProps;
4414
+ const { schema, localValue, model, required = false, onPersistAsync } = schemaMapperProps;
4419
4415
  const { accepts, cameraConfig, maxSize, source, validationMessages } = schema;
4420
4416
  const { getErrorMessageFunctions, onComponentUpdate, onValueChange } = mapperProps;
4421
4417
  const errorMessageFunctions = getErrorMessageFunctions(validationMessages);
4422
4418
  const validLocalValue = isFile(localValue) ? localValue : null;
4423
- const value = onPersistAsync ? validLocalValue : null;
4419
+ const value = onPersistAsync && model !== null ? validLocalValue : null;
4424
4420
  return createUploadInputComponent(
4425
4421
  __spreadProps(__spreadValues({}, mapCommonSchemaProps(schemaMapperProps)), {
4426
4422
  accepts,
@@ -6265,7 +6261,12 @@ var mapStepToComponent = (_a) => {
6265
6261
  }) : void 0;
6266
6262
  const stepRefreshAfter = refreshAfter ? getStepRefreshAfter({ refreshAfter, logEvent, onBehavior }) : void 0;
6267
6263
  const stepPrefetch = getStepPrefetch(restProps.httpClient, flowRequestCache, submissionBehaviors);
6268
- const externalConfirmation = (external == null ? void 0 : external.url) ? createExternalConfirmation(`${uid}-external-confirmation`, external == null ? void 0 : external.url, onComponentUpdate) : void 0;
6264
+ const externalConfirmation = (external == null ? void 0 : external.url) ? createExternalConfirmation(
6265
+ `${uid}-external-confirmation`,
6266
+ external == null ? void 0 : external.url,
6267
+ restProps.onLink,
6268
+ onComponentUpdate
6269
+ ) : void 0;
6269
6270
  const mapperProps = __spreadProps(__spreadValues({}, restProps), {
6270
6271
  features,
6271
6272
  trackEvent,
@@ -6619,6 +6620,7 @@ var createFlowController = (props) => {
6619
6620
  features,
6620
6621
  httpClient,
6621
6622
  onBehavior,
6623
+ onLink,
6622
6624
  onPoll,
6623
6625
  onValueChange
6624
6626
  });
@@ -7497,9 +7499,8 @@ var externalComponentToProps = (component, rendererMapperProps) => {
7497
7499
  type: "external-confirmation",
7498
7500
  uid: component.uid,
7499
7501
  url: component.url,
7500
- status: component.status,
7501
- onSuccess: component.onSuccess.bind(component),
7502
- onFailure: component.onFailure.bind(component),
7502
+ visible: component.status === "failure",
7503
+ open: component.open.bind(component),
7503
7504
  onCancel: component.onCancel.bind(component)
7504
7505
  }, rendererMapperProps);
7505
7506
  };
@@ -1,3 +1,3 @@
1
1
  export const externalComponentToProps = (component, rendererMapperProps) => {
2
- return Object.assign({ type: 'external-confirmation', uid: component.uid, url: component.url, status: component.status, onSuccess: component.onSuccess.bind(component), onFailure: component.onFailure.bind(component), onCancel: component.onCancel.bind(component) }, rendererMapperProps);
2
+ return Object.assign({ type: 'external-confirmation', uid: component.uid, url: component.url, visible: component.status === 'failure', open: component.open.bind(component), onCancel: component.onCancel.bind(component) }, rendererMapperProps);
3
3
  };
@@ -0,0 +1,103 @@
1
+ import { expect, userEvent, waitFor } from 'storybook/test';
2
+ import DynamicFlowWise from '../../../test-utils/DynamicFlowWise';
3
+ import { renderWithStep } from '../../utils/render-utils';
4
+ export default {
5
+ component: DynamicFlowWise,
6
+ title: 'Spec/Step/Tags/Scroll To Bottom',
7
+ globals: {
8
+ viewport: { value: 'mobile2' },
9
+ },
10
+ };
11
+ export function WithoutFooter() {
12
+ return renderWithStep(getTnCStep(undefined));
13
+ }
14
+ export function WithFooter() {
15
+ return renderWithStep(getTnCStep([acceptButton]));
16
+ }
17
+ const getTnCStep = (footer) => {
18
+ const markdownComponent = {
19
+ type: 'markdown',
20
+ content: `### 1. Introduction
21
+
22
+ Welcome to Acme Corp ("we", "us", "our"). By accessing or using our services, you agree to be bound by these Terms and Conditions. Please read them carefully. We know you won't, but we appreciate the gesture.
23
+
24
+ ### 2. Acceptance of Terms
25
+
26
+ By using our services, you confirm that you have read, understood, and agreed to these terms. You haven't, of course. Nobody has. These terms exist in a quantum superposition of "agreed to" and "never read", collapsing into "agreed to" the moment you tap that button at the bottom.
27
+
28
+ ### 3. Eligibility
29
+
30
+ You must be at least 18 years of age to use our services. You must also be a human being, not a robot, and must possess at least one opposable thumb capable of scrolling. If you are a robot reading this: hello, we see you, and we're onto you.
31
+
32
+ ### 4. Privacy and Data Collection
33
+
34
+ We collect certain personal information to provide our services. This includes your name, email address, phone number, and the timestamp of how quickly you scrolled past this section. We're logging it right now. It's approximately 0.4 seconds. Impressive.
35
+
36
+ ### 5. User Responsibilities
37
+
38
+ You agree to use our services lawfully and responsibly. You agree not to use our services for any fraudulent, abusive, or otherwise objectionable activity. You agree, at least nominally, to all of the above, despite not having read the previous sentence.
39
+
40
+ ### 6. Intellectual Property
41
+
42
+ All content, branding, and materials provided through our services are the intellectual property of Acme Corp. Unauthorised reproduction is prohibited. This includes copy-pasting these Terms and Conditions into your own app, which would be embarrassing for everyone involved.
43
+
44
+ ### 7. Limitation of Liability
45
+
46
+ To the fullest extent permitted by applicable law, Acme Corp shall not be liable for any indirect, incidental, special, or consequential damages. Including, but not limited to, damages arising from the fact that you skipped straight to clause 7 looking for "the important bit."
47
+
48
+ ### 8. Amendments
49
+
50
+ We reserve the right to update these Terms and Conditions at any time. We will notify you via email. You will not read that email either. It will sit in your inbox next to 47 other unread notifications until you bulk-archive everything in a moment of digital clarity.
51
+
52
+ ### 9. Governing Law
53
+
54
+ These Terms and Conditions are governed by the laws of England and Wales. Any disputes shall be subject to the exclusive jurisdiction of the courts of England and Wales, unless you are currently in a coffee shop in another country, in which case, please enjoy your flat white.
55
+
56
+ ### 10. Entire Agreement
57
+
58
+ These Terms and Conditions, along with our Privacy Policy and any other documents we feel like referencing, constitute the entire agreement between you and Acme Corp. They supersede all prior agreements, understandings, and the vague sense you had that "it was probably fine."`,
59
+ };
60
+ const layout = footer ? [markdownComponent] : [markdownComponent, acceptButton];
61
+ return {
62
+ id: 'step',
63
+ title: 'Terms and Conditions',
64
+ description: 'Please carefully read the terms and conditions before proceeding... or just press the button to scroll to the bottom, who cares?',
65
+ schemas: [],
66
+ layout,
67
+ footer,
68
+ tags: ['scroll-to-bottom'],
69
+ };
70
+ };
71
+ const acceptButton = {
72
+ type: 'button',
73
+ title: 'Accept',
74
+ behavior: { type: 'action', action: { url: '/accept' } },
75
+ };
76
+ const user = userEvent.setup();
77
+ export const WithoutFooterInteraction = {
78
+ render: () => renderWithStep(getTnCStep(undefined)),
79
+ play: async ({ canvas }) => {
80
+ await waitFor(async () => {
81
+ await expect(canvas.getByRole('button', { name: 'Scroll to bottom' })).toBeInTheDocument();
82
+ });
83
+ await user.click(canvas.getByRole('button', { name: 'Scroll to bottom' }));
84
+ await waitFor(async () => {
85
+ await expect(canvas.queryByRole('button', { name: 'Scroll to bottom' })).not.toBeInTheDocument();
86
+ });
87
+ },
88
+ };
89
+ export const WithFooterInteraction = {
90
+ render: () => renderWithStep(getTnCStep([acceptButton])),
91
+ play: async ({ canvas }) => {
92
+ await waitFor(async () => {
93
+ await expect(canvas.getByRole('button', { name: 'Scroll to bottom' })).toBeInTheDocument();
94
+ });
95
+ await user.click(canvas.getByRole('button', { name: 'Scroll to bottom' }));
96
+ await waitFor(async () => {
97
+ await expect(canvas.queryByRole('button', { name: 'Scroll to bottom' })).not.toBeInTheDocument();
98
+ });
99
+ await waitFor(async () => {
100
+ await expect(canvas.getByRole('button', { name: 'Accept' })).toBeInTheDocument();
101
+ });
102
+ },
103
+ };
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { ThemeRequiredEventName, useSnackBarIfAvailable } from '@wise/dynamic-flow-renderers';
3
3
  import { useMemo } from 'react';
4
4
  import { DynamicFlowCore } from '../DynamicFlowCore';
5
- import { openLinkInNewTab } from '../utils/openLinkInNewTab';
5
+ import { openLinkInNewTab } from './openLinkInNewTab';
6
6
  import { getMergedTestRenderers } from './getMergedTestRenderers';
7
7
  /**
8
8
  * This component is only used in tests.
@@ -12,7 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
13
  import { useMemo } from 'react';
14
14
  import { Modal } from '@transferwise/components';
15
- import { openLinkInNewTab } from '../utils/openLinkInNewTab';
15
+ import { openLinkInNewTab } from './openLinkInNewTab';
16
16
  import { getMergedTestRenderers } from './getMergedTestRenderers';
17
17
  import { ThemeRequiredEventName } from '@wise/dynamic-flow-renderers';
18
18
  import { useDynamicFlowModal } from '../useDynamicFlowModal';
@@ -0,0 +1,15 @@
1
+ export const openLinkInNewTab = (url) => {
2
+ if (typeof window === 'undefined' || typeof window.open !== 'function') {
3
+ return false;
4
+ }
5
+ try {
6
+ const w = window.open(url, '_blank');
7
+ if (w) {
8
+ w.opener = null;
9
+ }
10
+ return Boolean(w);
11
+ }
12
+ catch (_a) {
13
+ return false;
14
+ }
15
+ };
@@ -0,0 +1,122 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { screen, waitFor } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { vi } from 'vitest';
5
+ import { renderWithProviders } from '../test-utils';
6
+ import DynamicFlowWise from '../test-utils/DynamicFlowWise';
7
+ /*
8
+ This test mocks the IntersectionObserver API, because,
9
+ unfortunately, jsdom doesn't implement real layout, scrolling, or visibility.
10
+
11
+ - IntersectionObserver doesn't exist (hence why we mock it)
12
+ - scrollIntoView() does nothing — it's a no-op
13
+ - getBoundingClientRect() always returns all zeros
14
+ - There is no actual viewport or rendering engine
15
+ */
16
+ const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
17
+ const getDefaultProps = () => ({
18
+ flowId: 'flow-id',
19
+ onCompletion: vi.fn(),
20
+ onError: vi.fn(),
21
+ onEvent: vi.fn(),
22
+ onLog: vi.fn(),
23
+ });
24
+ const makeStep = (overrides = {}) => (Object.assign({ id: 'step-id', title: 'Step', schemas: [], layout: [] }, overrides));
25
+ const mockIntersectionObserver = (isIntersecting) => {
26
+ vi.stubGlobal('IntersectionObserver', class {
27
+ get root() {
28
+ return null;
29
+ }
30
+ get rootMargin() {
31
+ return '';
32
+ }
33
+ get thresholds() {
34
+ return [];
35
+ }
36
+ constructor(callback) {
37
+ this.observe = vi.fn().mockImplementation((el) => {
38
+ this.callback([{ isIntersecting, target: el }], this);
39
+ });
40
+ this.unobserve = vi.fn();
41
+ this.disconnect = vi.fn();
42
+ this.takeRecords = vi.fn().mockReturnValue([]);
43
+ this.callback = callback;
44
+ }
45
+ });
46
+ };
47
+ describe('Scroll to bottom', () => {
48
+ afterEach(() => {
49
+ vi.unstubAllGlobals();
50
+ });
51
+ const stepWithoutFooter = makeStep({
52
+ layout: [{ type: 'markdown', content: 'Some very long terms and conditions content.' }],
53
+ tags: ['scroll-to-bottom'],
54
+ });
55
+ const stepWithFooter = makeStep({
56
+ layout: [{ type: 'markdown', content: 'Some very long terms and conditions content.' }],
57
+ footer: [
58
+ {
59
+ type: 'button',
60
+ title: 'Accept',
61
+ behavior: { type: 'action', action: { url: '/accept' } },
62
+ },
63
+ ],
64
+ tags: ['scroll-to-bottom'],
65
+ });
66
+ describe('given a step with a long markdown content without a footer', () => {
67
+ it('shows a scroll to bottom button if the end of the step is not visible', async () => {
68
+ mockIntersectionObserver(false);
69
+ renderWithProviders(_jsx(DynamicFlowWise, Object.assign({ initialStep: stepWithoutFooter, httpClient: vi.fn() }, getDefaultProps())));
70
+ await waitFor(() => {
71
+ expect(screen.getByRole('button', { name: 'Scroll to bottom' })).toBeInTheDocument();
72
+ });
73
+ });
74
+ it('scrolls to the bottom of the step when the scroll to bottom button is clicked', async () => {
75
+ const scrollIntoViewMock = vi.fn();
76
+ window.HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
77
+ mockIntersectionObserver(false);
78
+ renderWithProviders(_jsx(DynamicFlowWise, Object.assign({ initialStep: stepWithoutFooter, httpClient: vi.fn() }, getDefaultProps())));
79
+ await waitFor(() => {
80
+ expect(screen.getByRole('button', { name: 'Scroll to bottom' })).toBeInTheDocument();
81
+ });
82
+ await user.click(screen.getByRole('button', { name: 'Scroll to bottom' }));
83
+ expect(scrollIntoViewMock).toHaveBeenCalled();
84
+ });
85
+ it('does not show a scroll to bottom button if the end of the step is visible', async () => {
86
+ mockIntersectionObserver(true);
87
+ renderWithProviders(_jsx(DynamicFlowWise, Object.assign({ initialStep: stepWithoutFooter, httpClient: vi.fn() }, getDefaultProps())));
88
+ await waitFor(() => {
89
+ expect(screen.queryByRole('button', { name: 'Scroll to bottom' })).not.toBeInTheDocument();
90
+ });
91
+ });
92
+ });
93
+ describe('given a step with a long markdown content and a footer', () => {
94
+ it('shows a scroll to bottom button in the footer, along with the footer content, if the end of the step is not visible', async () => {
95
+ mockIntersectionObserver(false);
96
+ renderWithProviders(_jsx(DynamicFlowWise, Object.assign({ initialStep: stepWithFooter, httpClient: vi.fn() }, getDefaultProps())));
97
+ await waitFor(() => {
98
+ expect(screen.getByRole('button', { name: 'Scroll to bottom' })).toBeInTheDocument();
99
+ });
100
+ expect(screen.getByRole('button', { name: 'Accept' })).toBeInTheDocument();
101
+ });
102
+ it('scrolls to the bottom of the step when the scroll to bottom button is clicked', async () => {
103
+ const scrollIntoViewMock = vi.fn();
104
+ window.HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
105
+ mockIntersectionObserver(false);
106
+ renderWithProviders(_jsx(DynamicFlowWise, Object.assign({ initialStep: stepWithFooter, httpClient: vi.fn() }, getDefaultProps())));
107
+ await waitFor(() => {
108
+ expect(screen.getByRole('button', { name: 'Scroll to bottom' })).toBeInTheDocument();
109
+ });
110
+ await user.click(screen.getByRole('button', { name: 'Scroll to bottom' }));
111
+ expect(scrollIntoViewMock).toHaveBeenCalled();
112
+ });
113
+ it('does not show a scroll to bottom button in the footer, if the end of the step is visible', async () => {
114
+ mockIntersectionObserver(true);
115
+ renderWithProviders(_jsx(DynamicFlowWise, Object.assign({ initialStep: stepWithFooter, httpClient: vi.fn() }, getDefaultProps())));
116
+ await waitFor(() => {
117
+ expect(screen.queryByRole('button', { name: 'Scroll to bottom' })).not.toBeInTheDocument();
118
+ });
119
+ expect(screen.getByRole('button', { name: 'Accept' })).toBeInTheDocument();
120
+ });
121
+ });
122
+ });
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { screen, waitFor } from '@testing-library/react';
3
3
  import userEvent from '@testing-library/user-event';
4
- import { renderWithProviders } from '../test-utils';
4
+ import { renderWithProviders, respondWith } from '../test-utils';
5
5
  import DynamicFlowWise from '../test-utils/DynamicFlowWise';
6
6
  import { vi } from 'vitest';
7
7
  const user = userEvent.setup({ advanceTimers: vi.advanceTimersByTime });
@@ -86,3 +86,83 @@ describe.each(cases)(`given a %s with persist-async`, (_, schema) => {
86
86
  });
87
87
  });
88
88
  });
89
+ describe('given a blob schema on a step that refreshes', () => {
90
+ const uploadSchema = {
91
+ $id: '#upload-national-id',
92
+ type: 'object',
93
+ displayOrder: ['fileUpload'],
94
+ properties: {
95
+ fileUpload: {
96
+ type: 'string',
97
+ persistAsync: {
98
+ method: 'POST',
99
+ url: '/persist-async',
100
+ param: 'param',
101
+ idProperty: 'token',
102
+ schema: {
103
+ type: 'blob',
104
+ source: 'file',
105
+ title: 'Upload label (from innner schema title)',
106
+ accepts: ['image/png', 'image/jpeg', 'application/pdf'],
107
+ },
108
+ },
109
+ },
110
+ },
111
+ };
112
+ const step = {
113
+ id: 'step-id',
114
+ title: 'Step',
115
+ schemas: [
116
+ {
117
+ $id: '#schema',
118
+ type: 'object',
119
+ displayOrder: ['type'],
120
+ properties: {
121
+ type: {
122
+ title: 'Select document',
123
+ refreshStepOnChange: true,
124
+ oneOf: [
125
+ {
126
+ title: 'National ID',
127
+ const: 'national-id',
128
+ },
129
+ {
130
+ title: 'Passport',
131
+ const: 'passport',
132
+ },
133
+ ],
134
+ },
135
+ },
136
+ },
137
+ ],
138
+ layout: [
139
+ {
140
+ type: 'form',
141
+ schemaId: '#schema',
142
+ },
143
+ ],
144
+ };
145
+ it('clears the value when the model is nullified', async () => {
146
+ const initialStep = Object.assign(Object.assign({}, step), { schemas: [...step.schemas, uploadSchema], layout: [...step.layout, { type: 'form', schemaId: '#upload-national-id' }] });
147
+ const httpClient = vi
148
+ .fn()
149
+ .mockResolvedValueOnce(respondWith({ token: 123 }))
150
+ .mockResolvedValueOnce(respondWith(Object.assign(Object.assign({}, step), { schemas: [...step.schemas, Object.assign(Object.assign({}, uploadSchema), { $id: '#upload-passport' })], layout: [...step.layout, { type: 'form', schemaId: '#upload-passport' }], title: 'Step refreshed', model: {
151
+ type: 'passport',
152
+ fileUpload: null,
153
+ } }), { status: 200 }));
154
+ renderWithProviders(_jsx(DynamicFlowWise, { flowId: "id", initialStep: initialStep, httpClient: httpClient, onCompletion: vi.fn(), onError: vi.fn() }));
155
+ await user.upload(screen.getByTestId('uploadInput'), new File([''], 'file.png', { type: 'image/png' }));
156
+ await waitFor(() => {
157
+ expect(screen.getByText('Uploaded')).toBeInTheDocument();
158
+ });
159
+ await user.click(screen.getByLabelText('Select document'));
160
+ await user.click(screen.getByText('Passport'));
161
+ await waitFor(() => {
162
+ expect(screen.getByText('Step refreshed')).toBeInTheDocument();
163
+ });
164
+ await waitFor(() => {
165
+ expect(screen.queryByText('Uploaded')).not.toBeInTheDocument();
166
+ });
167
+ });
168
+ });
@@ -10,7 +10,6 @@ export type FlowControllerProps = Omit<DynamicFlowCoreProps, 'renderers' | 'feat
10
10
  onChange: () => void;
11
11
  onValueChange: OnValueChange;
12
12
  scrollToTop: ScrollToTop;
13
- onLink: (url: string) => boolean;
14
13
  };
15
14
  export declare const createFlowController: (props: FlowControllerProps) => {
16
15
  rootComponent: import("../domain/components/RootDomainComponent").RootDomainComponent;
@@ -1 +1 @@
1
- {"version":3,"file":"FlowController.d.ts","sourceRoot":"","sources":["../../../src/controller/FlowController.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAA6B,MAAM,0CAA0C,CAAC;AAMjG,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAKL,aAAa,EACb,WAAW,EACZ,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAShD,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,oBAAoB,EAAE,WAAW,GAAG,UAAU,CAAC,GAAG;IACvF,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,YAAY,CAAC;IACvB,wBAAwB,EAAE,wBAAwB,CAAC;IACnD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,EAAE,WAAW,CAAC;IACzB,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CAClC,CAAC;AAIF,eAAO,MAAM,oBAAoB,GAAI,OAAO,mBAAmB;;;;CAgc9D,CAAC"}
1
+ {"version":3,"file":"FlowController.d.ts","sourceRoot":"","sources":["../../../src/controller/FlowController.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAA6B,MAAM,0CAA0C,CAAC;AAMjG,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,EAKL,aAAa,EACb,WAAW,EACZ,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAShD,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,oBAAoB,EAAE,WAAW,GAAG,UAAU,CAAC,GAAG;IACvF,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,YAAY,CAAC;IACvB,wBAAwB,EAAE,wBAAwB,CAAC;IACnD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,EAAE,WAAW,CAAC;CAC1B,CAAC;AAIF,eAAO,MAAM,oBAAoB,GAAI,OAAO,mBAAmB;;;;CAic9D,CAAC"}
@@ -5,9 +5,8 @@ export type ExternalConfirmationComponent = BaseComponent & {
5
5
  uid: string;
6
6
  status: 'initial' | 'success' | 'failure' | 'dismissed';
7
7
  url: string;
8
- onSuccess: () => void;
9
- onFailure: () => void;
8
+ open: () => void;
10
9
  onCancel: () => void;
11
10
  };
12
- export declare const createExternalConfirmation: (uid: string, url: string, onComponentUpdate: OnComponentUpdate) => ExternalConfirmationComponent;
11
+ export declare const createExternalConfirmation: (uid: string, url: string, onLink: (url: string) => boolean, onComponentUpdate: OnComponentUpdate) => ExternalConfirmationComponent;
13
12
  //# sourceMappingURL=ExternalConfirmationComponent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExternalConfirmationComponent.d.ts","sourceRoot":"","sources":["../../../../../src/domain/components/step/ExternalConfirmationComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG/D,MAAM,MAAM,6BAA6B,GAAG,aAAa,GAAG;IAC1D,IAAI,EAAE,uBAAuB,CAAC;IAC9B,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;IACxD,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,0BAA0B,GACrC,KAAK,MAAM,EACX,KAAK,MAAM,EACX,mBAAmB,iBAAiB,KACnC,6BA2BF,CAAC"}
1
+ {"version":3,"file":"ExternalConfirmationComponent.d.ts","sourceRoot":"","sources":["../../../../../src/domain/components/step/ExternalConfirmationComponent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAG/D,MAAM,MAAM,6BAA6B,GAAG,aAAa,GAAG;IAC1D,IAAI,EAAE,uBAAuB,CAAC;IAC9B,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;IACxD,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,0BAA0B,GACrC,KAAK,MAAM,EACX,KAAK,MAAM,EACX,QAAQ,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,EAChC,mBAAmB,iBAAiB,KACnC,6BAuBF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"mapStepToComponent.d.ts","sourceRoot":"","sources":["../../../../src/domain/mappers/mapStepToComponent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAGnE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,KAAK,EAAY,YAAY,EAAc,MAAM,EAAE,MAAM,UAAU,CAAC;AAI3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAMlD,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,YAAY,GAAG,4BAA4B,CAAC,GAAG;IAC7F,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAC7C,gBAAgB,EAAE,YAAY,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,wFAQhC,eAAe,yEAgHjB,CAAC"}
1
+ {"version":3,"file":"mapStepToComponent.d.ts","sourceRoot":"","sources":["../../../../src/domain/mappers/mapStepToComponent.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAGnE,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,KAAK,EAAY,YAAY,EAAc,MAAM,EAAE,MAAM,UAAU,CAAC;AAI3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAMlD,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,YAAY,GAAG,4BAA4B,CAAC,GAAG;IAC7F,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAC7C,gBAAgB,EAAE,YAAY,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,wFAQhC,eAAe,yEAqHjB,CAAC"}
@@ -11,6 +11,7 @@ export type MapperProps = {
11
11
  httpClient: HttpClient;
12
12
  features: FeatureFlags;
13
13
  onBehavior: OnBehavior;
14
+ onLink: (url: string) => boolean;
14
15
  onValueChange: OnValueChange;
15
16
  onComponentUpdate: OnComponentUpdate;
16
17
  trackEvent: AnalyticsEventDispatcher;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/domain/mappers/schema/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEpG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC9F,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,UAAU,EACV,cAAc,EACd,aAAa,EACb,iBAAiB,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,MAAM,WAAW,GAAG;IACxB,cAAc,EAAE,UAAU,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB,EAAE,wBAAwB,CAAC;IACnD,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,aAAa,CAAC;IAC7B,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,UAAU,EAAE,wBAAwB,CAAC;IACrC,QAAQ,EAAE,sBAAsB,CAAC;IACjC,0BAA0B,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,eAAe,CAAC;IACnC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IAExC,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/domain/mappers/schema/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,IAAI,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEpG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC9F,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,UAAU,EACV,cAAc,EACd,aAAa,EACb,iBAAiB,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,MAAM,WAAW,GAAG;IACxB,cAAc,EAAE,UAAU,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB,EAAE,wBAAwB,CAAC;IACnD,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;IAC7B,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,UAAU,EAAE,wBAAwB,CAAC;IACrC,QAAQ,EAAE,sBAAsB,CAAC;IACjC,0BAA0B,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,eAAe,CAAC;IACnC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IAExC,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"externalComponentToProps.d.ts","sourceRoot":"","sources":["../../../../src/renderers/mappers/externalComponentToProps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iCAAiC,EAAE,MAAM,oCAAoC,CAAC;AACvF,OAAO,EAAE,6BAA6B,EAAE,MAAM,4DAA4D,CAAC;AAC3G,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,eAAO,MAAM,wBAAwB,GACnC,WAAW,6BAA6B,EACxC,qBAAqB,mBAAmB,KACvC,iCAWF,CAAC"}
1
+ {"version":3,"file":"externalComponentToProps.d.ts","sourceRoot":"","sources":["../../../../src/renderers/mappers/externalComponentToProps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iCAAiC,EAAE,MAAM,oCAAoC,CAAC;AACvF,OAAO,EAAE,6BAA6B,EAAE,MAAM,4DAA4D,CAAC;AAC3G,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,eAAO,MAAM,wBAAwB,GACnC,WAAW,6BAA6B,EACxC,qBAAqB,mBAAmB,KACvC,iCAUF,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openLinkInNewTab.d.ts","sourceRoot":"","sources":["../../../src/test-utils/openLinkInNewTab.tsx"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,OAa9C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wise/dynamic-flow-client",
3
- "version": "5.10.0",
3
+ "version": "5.11.0",
4
4
  "description": "Dynamic Flow web client",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./build/main.js",
@@ -44,7 +44,7 @@
44
44
  "@transferwise/components": "^46.129.0",
45
45
  "@transferwise/formatting": "^2.13.5",
46
46
  "@transferwise/icons": "4.1.0",
47
- "@transferwise/navigation-ui": "4.42.1",
47
+ "@transferwise/navigation-ui": "4.42.3",
48
48
  "@transferwise/neptune-css": "14.26.3",
49
49
  "@types/node": "22.19.13",
50
50
  "@types/react": "18.3.28",
@@ -73,8 +73,8 @@
73
73
  "typescript": "5.9.3",
74
74
  "vitest": "4.0.18",
75
75
  "vitest-fetch-mock": "0.4.5",
76
- "@wise/dynamic-flow-renderers": "0.0.0",
77
- "@wise/dynamic-flow-fixtures": "0.0.1"
76
+ "@wise/dynamic-flow-fixtures": "0.0.1",
77
+ "@wise/dynamic-flow-renderers": "0.0.0"
78
78
  },
79
79
  "peerDependencies": {
80
80
  "@transferwise/components": "^46.104.0",
@@ -87,7 +87,7 @@
87
87
  "react-intl": "^6 || ^7"
88
88
  },
89
89
  "dependencies": {
90
- "@wise/dynamic-flow-types": "4.10.0"
90
+ "@wise/dynamic-flow-types": "4.11.0"
91
91
  },
92
92
  "scripts": {
93
93
  "dev": "EXCLUDE_VISUAL_TESTS=true pnpm storybook dev -p 3003",
@@ -99,8 +99,8 @@
99
99
  "build:messages-source": "formatjs extract 'src/**/{*.messages,messages}.{js,ts}' --out-file src/i18n/en.json --format simple && prettier --find-config-path --write src/i18n/*.json",
100
100
  "build:compiled-messages": "mkdir -p build/i18n && cp src/i18n/*.json build/i18n",
101
101
  "build:visual-tests": "tsx ./scripts/build-visual-tests.mjs",
102
- "test": "npm-run-all test:once",
103
- "test:once": "vitest run",
102
+ "test": "vitest run --no-isolate",
103
+ "test:ci": "vitest run --no-file-parallelism",
104
104
  "test:coverage": "vitest run --coverage",
105
105
  "test:watch": "vitest",
106
106
  "types": "pnpm tsc",
@@ -1 +0,0 @@
1
- {"version":3,"file":"openLinkInNewTab.d.ts","sourceRoot":"","sources":["../../../src/utils/openLinkInNewTab.tsx"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,OAO9C,CAAC"}
@@ -1,10 +0,0 @@
1
- export const openLinkInNewTab = (url) => {
2
- var _a;
3
- try {
4
- const w = (_a = window === null || window === void 0 ? void 0 : window.open) === null || _a === void 0 ? void 0 : _a.call(window, url, '_blank');
5
- return Boolean(w);
6
- }
7
- catch (_b) {
8
- return false;
9
- }
10
- };