@wise/dynamic-flow-client 5.2.0 → 5.4.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 (36) hide show
  1. package/build/main.css +16 -2
  2. package/build/main.js +816 -440
  3. package/build/main.mjs +821 -445
  4. package/build/types/domain/components/FormattedValueComponent.d.ts +16 -0
  5. package/build/types/domain/components/RootDomainComponent.d.ts +11 -3
  6. package/build/types/domain/components/SelectInputComponent.d.ts +1 -2
  7. package/build/types/domain/components/SubflowDomainComponent.d.ts +16 -0
  8. package/build/types/domain/components/step/StepDomainComponent.d.ts +3 -3
  9. package/build/types/domain/features/eventNames.d.ts +1 -0
  10. package/build/types/domain/features/events.d.ts +2 -1
  11. package/build/types/domain/mappers/mapStepToComponent.d.ts +2 -0
  12. package/build/types/domain/mappers/schema/objectSchemaToComponent/objectSchemaToFormattedValueComponent.d.ts +7 -0
  13. package/build/types/domain/mappers/schema/oneOfSchemaToComponent/oneOfSchemaToComponent.d.ts +25 -0
  14. package/build/types/domain/mappers/schema/persistAsyncSchemaToComponent.d.ts +25 -0
  15. package/build/types/domain/prefetching/request-cache.d.ts +7 -7
  16. package/build/types/domain/types.d.ts +18 -3
  17. package/build/types/flow/executeRequest.d.ts +39 -0
  18. package/build/types/flow/executeSubmission.d.ts +6 -33
  19. package/build/types/flow/getResponseType.d.ts +1 -1
  20. package/build/types/flow/getSafeHttpClient.d.ts +1 -0
  21. package/build/types/flow/handleErrorResponse.d.ts +3 -0
  22. package/build/types/flow/response-utils.d.ts +2 -1
  23. package/build/types/getSubflowCallbacks.d.ts +14 -0
  24. package/build/types/index.d.ts +7 -3
  25. package/build/types/renderers/mappers/formattedValueComponentToProps.d.ts +4 -0
  26. package/build/types/renderers/mappers/subflowComponentToRendererProps.d.ts +4 -0
  27. package/build/types/test-utils/DynamicFlowWiseModal.d.ts +12 -0
  28. package/build/types/test-utils/getMergedTestRenderers.d.ts +2 -0
  29. package/build/types/types.d.ts +3 -11
  30. package/build/types/useDynamicFlow.d.ts +12 -0
  31. package/build/types/{useDynamicFlowCore.d.ts → useDynamicFlowController.d.ts} +3 -2
  32. package/build/types/useDynamicFlowModal.d.ts +16 -0
  33. package/build/types/utils/{scrollToTop.d.ts → getScrollToTop.d.ts} +1 -1
  34. package/package.json +22 -22
  35. package/build/types/DynamicFormCore.d.ts +0 -11
  36. package/build/types/flow/makeSubmissionRequest.d.ts +0 -3
package/build/main.mjs CHANGED
@@ -751,7 +751,84 @@ var translations = {
751
751
  };
752
752
  var i18n_default = translations;
753
753
 
754
- // src/DynamicFlowCore.tsx
754
+ // src/utils/type-validators.ts
755
+ var isString = (value) => typeof value === "string";
756
+ var isNumber = (value) => typeof value === "number" && !Number.isNaN(value);
757
+ var isInteger = (value) => isNumber(value) && Math.floor(value) === value;
758
+ var isBoolean = (value) => typeof value === "boolean";
759
+ var isObject = (value) => !isNullish(value) && (value == null ? void 0 : value.constructor) === Object;
760
+ var isArray = (value) => Array.isArray(value);
761
+ var isNull = (value) => value === null;
762
+ var isUndefined = (value) => typeof value === "undefined";
763
+ var isNullish = (v) => isNull(v) || isUndefined(v);
764
+ var isFile = (value) => value instanceof File;
765
+ var isValidDate = (value) => isString(value) && /^\d{4}-\d{2}-\d{2}$/.test(value);
766
+
767
+ // src/renderers/utils.ts
768
+ function findRendererPropsByType(root, type, predicate = () => true) {
769
+ if (isArray(root)) {
770
+ return root.flatMap((child) => findRendererPropsByType(child, type, predicate));
771
+ }
772
+ return [
773
+ ...isType(root, type) && predicate(root) ? [root] : [],
774
+ ...getChildren(root).flatMap((child) => findRendererPropsByType(child, type, predicate))
775
+ ];
776
+ }
777
+ var isType = (node, type) => node.type === type;
778
+ var getChildren = (node) => {
779
+ switch (node.type) {
780
+ case "root":
781
+ case "box":
782
+ case "container":
783
+ case "form":
784
+ case "form-section":
785
+ case "step":
786
+ case "modal":
787
+ case "section":
788
+ return node.childrenProps;
789
+ case "columns":
790
+ return [...node.startChildrenProps, ...node.endChildrenProps];
791
+ case "modal-layout":
792
+ return node.content.childrenProps;
793
+ case "repeatable":
794
+ return node.editableItemProps ? [node.editableItemProps] : [];
795
+ case "input-select":
796
+ return node.childrenProps ? [node.childrenProps] : [];
797
+ case "tabs":
798
+ return node.tabs.flatMap((c) => c.childrenProps);
799
+ case "alert":
800
+ case "button":
801
+ case "input-checkbox":
802
+ case "input-date":
803
+ case "decision":
804
+ case "divider":
805
+ case "formatted-value":
806
+ case "heading":
807
+ case "hidden":
808
+ case "image":
809
+ case "instructions":
810
+ case "input-integer":
811
+ case "list":
812
+ case "loading-indicator":
813
+ case "markdown":
814
+ case "input-multi-select":
815
+ case "input-upload-multi":
816
+ case "input-number":
817
+ case "money-input":
818
+ case "paragraph":
819
+ case "progress":
820
+ case "review":
821
+ case "search":
822
+ case "status-list":
823
+ case "input-text":
824
+ case "input-upload":
825
+ case "external-confirmation":
826
+ case "subflow":
827
+ return [];
828
+ }
829
+ };
830
+
831
+ // src/useDynamicFlow.tsx
755
832
  import { useMemo as useMemo2 } from "react";
756
833
 
757
834
  // src/common/errorBoundary/ErrorBoundary.tsx
@@ -855,93 +932,24 @@ var CoreContainerRenderer = {
855
932
  render: ({ children }) => /* @__PURE__ */ jsx3(Fragment2, { children })
856
933
  };
857
934
 
858
- // src/utils/type-validators.ts
859
- var isString = (value) => typeof value === "string";
860
- var isNumber = (value) => typeof value === "number" && !Number.isNaN(value);
861
- var isInteger = (value) => isNumber(value) && Math.floor(value) === value;
862
- var isBoolean = (value) => typeof value === "boolean";
863
- var isObject = (value) => !isNullish(value) && (value == null ? void 0 : value.constructor) === Object;
864
- var isArray = (value) => Array.isArray(value);
865
- var isNull = (value) => value === null;
866
- var isUndefined = (value) => typeof value === "undefined";
867
- var isNullish = (v) => isNull(v) || isUndefined(v);
868
- var isFile = (value) => value instanceof File;
869
- var isValidDate = (value) => isString(value) && /^\d{4}-\d{2}-\d{2}$/.test(value);
870
-
871
- // src/renderers/utils.ts
872
- function findRendererPropsByType(root, type, predicate = () => true) {
873
- if (isArray(root)) {
874
- return root.flatMap((child) => findRendererPropsByType(child, type, predicate));
875
- }
876
- return [
877
- ...isType(root, type) && predicate(root) ? [root] : [],
878
- ...getChildren(root).flatMap((child) => findRendererPropsByType(child, type, predicate))
879
- ];
880
- }
881
- var isType = (node, type) => node.type === type;
882
- var getChildren = (node) => {
883
- switch (node.type) {
884
- case "root":
885
- case "box":
886
- case "container":
887
- case "form":
888
- case "form-section":
889
- case "step":
890
- case "modal":
891
- case "section":
892
- return node.childrenProps;
893
- case "columns":
894
- return [...node.startChildrenProps, ...node.endChildrenProps];
895
- case "modal-layout":
896
- return node.content.childrenProps;
897
- case "repeatable":
898
- return node.editableItemProps ? [node.editableItemProps] : [];
899
- case "input-select":
900
- return node.childrenProps ? [node.childrenProps] : [];
901
- case "tabs":
902
- return node.tabs.flatMap((c) => c.childrenProps);
903
- case "alert":
904
- case "button":
905
- case "input-checkbox":
906
- case "input-date":
907
- case "decision":
908
- case "divider":
909
- case "heading":
910
- case "hidden":
911
- case "image":
912
- case "instructions":
913
- case "input-integer":
914
- case "list":
915
- case "loading-indicator":
916
- case "markdown":
917
- case "input-multi-select":
918
- case "input-upload-multi":
919
- case "input-number":
920
- case "money-input":
921
- case "paragraph":
922
- case "progress":
923
- case "review":
924
- case "search":
925
- case "status-list":
926
- case "input-text":
927
- case "input-upload":
928
- case "external-confirmation":
929
- return [];
930
- }
931
- };
932
-
933
935
  // src/renderers/CoreRootRenderer.tsx
934
- import { jsx as jsx4 } from "react/jsx-runtime";
936
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
935
937
  var CoreRootRenderer = {
936
938
  canRenderType: "root",
937
- render: ({ children, childrenProps }) => {
939
+ render: ({ children, childrenProps, subflow }) => {
940
+ if ((subflow == null ? void 0 : subflow.presentation.type) === "push") {
941
+ return /* @__PURE__ */ jsx4(Fragment3, { children: subflow.children });
942
+ }
938
943
  const [stepProps] = findRendererPropsByType(childrenProps, "step");
939
- return /* @__PURE__ */ jsx4("div", { id: stepProps == null ? void 0 : stepProps.id, className: "dynamic-flow-step", children });
944
+ return /* @__PURE__ */ jsxs2("div", { id: stepProps == null ? void 0 : stepProps.id, className: "dynamic-flow-step", children: [
945
+ children,
946
+ (subflow == null ? void 0 : subflow.presentation.type) === "modal" ? subflow.children : void 0
947
+ ] });
940
948
  }
941
949
  };
942
950
 
943
951
  // src/renderers/getRenderFunction.tsx
944
- import { Fragment as Fragment3, jsx as jsx5 } from "react/jsx-runtime";
952
+ import { Fragment as Fragment4, jsx as jsx5 } from "react/jsx-runtime";
945
953
  var getRenderFunction = (renderers) => {
946
954
  function ComponentRenderer(props) {
947
955
  const { type } = props;
@@ -961,7 +969,7 @@ var getRenderFunction = (renderers) => {
961
969
  }
962
970
  const render = (props) => {
963
971
  if (!props) {
964
- return /* @__PURE__ */ jsx5(Fragment3, {});
972
+ return /* @__PURE__ */ jsx5(Fragment4, {});
965
973
  }
966
974
  return /* @__PURE__ */ jsx5(ComponentRenderer, __spreadValues({}, props), props.uid);
967
975
  };
@@ -1249,6 +1257,29 @@ var externalComponentToProps = (component, rendererMapperProps) => {
1249
1257
  }, rendererMapperProps);
1250
1258
  };
1251
1259
 
1260
+ // src/renderers/mappers/formattedValueComponentToProps.ts
1261
+ var formattedValueComponentToProps = (component, rendererMapperProps) => {
1262
+ return __spreadValues(__spreadProps(__spreadValues({
1263
+ type: "formatted-value"
1264
+ }, pick(
1265
+ component,
1266
+ "format",
1267
+ "uid",
1268
+ "analyticsId",
1269
+ "control",
1270
+ "description",
1271
+ "help",
1272
+ "media",
1273
+ "tags",
1274
+ "title"
1275
+ // for now, we don't want to pass `value` down to the renderer to avoid the "WhateverComponent".
1276
+ // 'value',
1277
+ )), {
1278
+ validationState: getValidationState(component.errors, void 0),
1279
+ onChange: component.onChange.bind(component)
1280
+ }), rendererMapperProps);
1281
+ };
1282
+
1252
1283
  // src/renderers/mappers/formComponentToProps.ts
1253
1284
  var formComponentToProps = (component, rendererMapperProps) => {
1254
1285
  const childrenProps = component.getChildren().map((c) => componentToRendererProps(c, rendererMapperProps));
@@ -1661,11 +1692,18 @@ var rootComponentToProps = (rootComponent, rendererMapperProps) => {
1661
1692
  }
1662
1693
  return componentToRendererProps(child, rendererMapperProps);
1663
1694
  });
1695
+ const subflow = rootComponent.subflow ? {
1696
+ presentation: rootComponent.subflow.presentation,
1697
+ children: rendererMapperProps.render(
1698
+ componentToRendererProps(rootComponent.subflow, rendererMapperProps)
1699
+ )
1700
+ } : void 0;
1664
1701
  return __spreadValues({
1665
1702
  type: "root",
1666
1703
  uid: rootComponent.uid,
1667
1704
  children: childrenProps.map(rendererMapperProps.render),
1668
- childrenProps
1705
+ childrenProps,
1706
+ subflow
1669
1707
  }, rendererMapperProps);
1670
1708
  };
1671
1709
 
@@ -1856,6 +1894,19 @@ var uploadInputComponentToProps = (component, rendererMapperProps) => {
1856
1894
  });
1857
1895
  };
1858
1896
 
1897
+ // src/renderers/mappers/subflowComponentToRendererProps.ts
1898
+ var subflowComponentToRendererProps = (component, rendererMapperProps) => {
1899
+ return __spreadValues(__spreadProps(__spreadValues({
1900
+ uid: "subflow",
1901
+ type: "subflow"
1902
+ }, pick(component, "requestCache", "presentation", "initialRequest")), {
1903
+ onCancellation: component.onCancellation.bind(component),
1904
+ onCompletion: component.onCompletion.bind(component),
1905
+ onError: component.onError.bind(component),
1906
+ onEvent: component.onEvent.bind(component)
1907
+ }), rendererMapperProps);
1908
+ };
1909
+
1859
1910
  // src/renderers/mappers/componentToRendererProps.ts
1860
1911
  var componentToRendererProps = (component, mapperProps) => {
1861
1912
  if (isHiddenComponent(component)) {
@@ -1904,6 +1955,8 @@ var getComponentProps = (component, rendererMapperProps) => {
1904
1955
  return dividerComponentToProps(component, rendererMapperProps);
1905
1956
  case "external-confirmation":
1906
1957
  return externalComponentToProps(component, rendererMapperProps);
1958
+ case "formatted-value":
1959
+ return formattedValueComponentToProps(component, rendererMapperProps);
1907
1960
  case "form":
1908
1961
  return formComponentToProps(component, rendererMapperProps);
1909
1962
  case "heading":
@@ -1952,6 +2005,8 @@ var getComponentProps = (component, rendererMapperProps) => {
1952
2005
  return selectInputComponentToProps(component, rendererMapperProps);
1953
2006
  case "status-list":
1954
2007
  return statusListComponentToProps(component, rendererMapperProps);
2008
+ case "subflow":
2009
+ return subflowComponentToRendererProps(component, rendererMapperProps);
1955
2010
  case "tabs":
1956
2011
  return tabsComponentToProps(component, rendererMapperProps);
1957
2012
  case "text":
@@ -1976,7 +2031,7 @@ var getComponentAlertProps = (component, rendererMapperProps) => "alert" in comp
1976
2031
  markdown: component.alert.content
1977
2032
  }, rendererMapperProps) : null;
1978
2033
 
1979
- // src/useDynamicFlowCore.tsx
2034
+ // src/useDynamicFlowController.tsx
1980
2035
  import { useCallback as useCallback2, useEffect, useMemo, useRef as useRef2, useState } from "react";
1981
2036
  import { useIntl as useIntl2 } from "react-intl";
1982
2037
 
@@ -1989,16 +2044,17 @@ var getInputUpdateFunction = (updateComponent) => {
1989
2044
  };
1990
2045
 
1991
2046
  // src/domain/components/RootDomainComponent.ts
1992
- var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2047
+ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig, requestCache) => {
1993
2048
  const update = getInputUpdateFunction(updateComponent);
1994
2049
  const rootComponent = {
1995
2050
  type: "root",
1996
2051
  kind: "step",
1997
2052
  uid: "root",
1998
2053
  stepComponent: null,
2054
+ subflow: null,
1999
2055
  stepStack: [],
2000
- isNativeBackEnabled: backConfig.isNativeBackEnabled,
2001
- isFlowCancellable: backConfig.isFlowCancellable,
2056
+ backConfig,
2057
+ requestCache,
2002
2058
  _update(updateFn) {
2003
2059
  update(this, updateFn);
2004
2060
  },
@@ -2061,6 +2117,16 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2061
2117
  var _a;
2062
2118
  return (_a = this.stepStack[this.stepStack.length - 1]) != null ? _a : null;
2063
2119
  },
2120
+ addSubflow(subflow) {
2121
+ this._update((draft) => {
2122
+ draft.subflow = subflow;
2123
+ });
2124
+ },
2125
+ closeSubflow() {
2126
+ this._update((draft) => {
2127
+ draft.subflow = null;
2128
+ });
2129
+ },
2064
2130
  start() {
2065
2131
  var _a;
2066
2132
  (_a = this.getStep()) == null ? void 0 : _a.start();
@@ -2071,6 +2137,7 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2071
2137
  },
2072
2138
  updateStep(stepComponent) {
2073
2139
  var _a;
2140
+ this.closeSubflow();
2074
2141
  const shouldScroll = shouldScrollOnStepUpdate(stepComponent, this.getStep());
2075
2142
  this._update((draft) => {
2076
2143
  draft.stepStack = draft.stepStack.slice(0, -1);
@@ -2082,10 +2149,11 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2082
2149
  (_a = this.getStep()) == null ? void 0 : _a.start();
2083
2150
  },
2084
2151
  pushStep(stepComponent) {
2152
+ var _a;
2153
+ this.closeSubflow();
2085
2154
  const previousStep = this.getStep();
2086
2155
  const previousStepHasPolling = previousStep == null ? void 0 : previousStep.step.polling;
2087
2156
  this._update((draft) => {
2088
- var _a;
2089
2157
  switch (stepComponent.stackBehavior) {
2090
2158
  case "remove-previous":
2091
2159
  case "replace-current":
@@ -2100,9 +2168,9 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2100
2168
  }
2101
2169
  draft.stepStack.push(stepComponent);
2102
2170
  }
2103
- (_a = this.getStep()) == null ? void 0 : _a.start();
2104
2171
  });
2105
2172
  if (previousStep != null) {
2173
+ (_a = this.getStep()) == null ? void 0 : _a.start();
2106
2174
  scrollToTop == null ? void 0 : scrollToTop("instant");
2107
2175
  }
2108
2176
  },
@@ -2120,6 +2188,7 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2120
2188
  },
2121
2189
  navigateBack() {
2122
2190
  var _a;
2191
+ this.closeSubflow();
2123
2192
  if (this.stepStack.length === 1) {
2124
2193
  return;
2125
2194
  }
@@ -2132,7 +2201,7 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2132
2201
  var _a, _b;
2133
2202
  const navigation = (_a = this.getStep()) == null ? void 0 : _a.step.navigation;
2134
2203
  const stepHasBehavior = Boolean((_b = navigation == null ? void 0 : navigation.back) != null ? _b : navigation == null ? void 0 : navigation.backButton);
2135
- return this.isFlowCancellable || this.stepStack.length > 1 && this.isNativeBackEnabled || stepHasBehavior;
2204
+ return this.backConfig.isFlowCancellable || this.stepStack.length > 1 && this.backConfig.isNativeBackEnabled || stepHasBehavior;
2136
2205
  }
2137
2206
  };
2138
2207
  return rootComponent;
@@ -2144,6 +2213,24 @@ var shouldScrollOnStepUpdate = (newStep, currentStep) => {
2144
2213
  return newStep.error != null && newStep.error !== currentStep.error;
2145
2214
  };
2146
2215
 
2216
+ // src/domain/components/utils/getRandomId.ts
2217
+ var getRandomId = () => Math.random().toString(36).substring(2);
2218
+
2219
+ // src/domain/components/SubflowDomainComponent.ts
2220
+ var createSubflowDomainComponent = (subflowProps, updateComponent) => {
2221
+ const update = getInputUpdateFunction(updateComponent);
2222
+ const subflowComponent = __spreadProps(__spreadValues({
2223
+ uid: `subflow-${getRandomId()}`,
2224
+ type: "subflow",
2225
+ kind: "layout"
2226
+ }, subflowProps), {
2227
+ _update(updateFn) {
2228
+ update(this, updateFn);
2229
+ }
2230
+ });
2231
+ return subflowComponent;
2232
+ };
2233
+
2147
2234
  // src/domain/components/ModalComponent.ts
2148
2235
  var createModalContentComponent = (modalProps, updateComponent) => {
2149
2236
  const update = getInputUpdateFunction(updateComponent);
@@ -2167,9 +2254,6 @@ var createModalContentComponent = (modalProps, updateComponent) => {
2167
2254
  return modalContentComponent;
2168
2255
  };
2169
2256
 
2170
- // src/domain/components/utils/getRandomId.ts
2171
- var getRandomId = () => Math.random().toString(36).substring(2);
2172
-
2173
2257
  // src/domain/components/AlertComponent.ts
2174
2258
  var createAlertComponent = (alertProps) => __spreadValues({
2175
2259
  type: "alert",
@@ -2192,6 +2276,12 @@ var getDomainLayerBehavior = ({ action, behavior: specBehavior }, stepActions, r
2192
2276
  };
2193
2277
  var normaliseBehavior = (behavior, stepActions) => {
2194
2278
  if ("type" in behavior) {
2279
+ if (behavior.type === "subflow") {
2280
+ return __spreadProps(__spreadValues({}, behavior), {
2281
+ onCompletion: behavior.onCompletion ? normaliseBehavior(behavior.onCompletion, stepActions) : void 0,
2282
+ onError: behavior.onError ? normaliseBehavior(behavior.onError, stepActions) : void 0
2283
+ });
2284
+ }
2195
2285
  return behavior;
2196
2286
  }
2197
2287
  if ("action" in behavior && behavior.action) {
@@ -3313,6 +3403,35 @@ var modalToComponent = (uid, { content, title }, mapperProps, schemaComponents)
3313
3403
  mapperProps.updateComponent
3314
3404
  );
3315
3405
 
3406
+ // src/domain/components/step/ExternalConfirmationComponent.ts
3407
+ var createExternalConfirmation = (uid, url, updateComponent) => {
3408
+ const update = getInputUpdateFunction(updateComponent);
3409
+ return {
3410
+ type: "external-confirmation",
3411
+ kind: "layout",
3412
+ uid,
3413
+ url,
3414
+ status: "initial",
3415
+ onSuccess() {
3416
+ update(this, (draft) => {
3417
+ draft.status = "success";
3418
+ });
3419
+ },
3420
+ onFailure() {
3421
+ if (this.status === "initial") {
3422
+ update(this, (draft) => {
3423
+ draft.status = "failure";
3424
+ });
3425
+ }
3426
+ },
3427
+ onCancel() {
3428
+ update(this, (draft) => {
3429
+ draft.status = "dismissed";
3430
+ });
3431
+ }
3432
+ };
3433
+ };
3434
+
3316
3435
  // src/utils/recursiveMerge.ts
3317
3436
  function recursiveMerge(valueA, valueB) {
3318
3437
  if (valueA === null) {
@@ -3352,67 +3471,16 @@ function mergeArrays(valueA, valueB) {
3352
3471
  );
3353
3472
  }
3354
3473
 
3355
- // src/flow/makeSubmissionRequest.ts
3356
- var makeSubmissionRequest = (action, model) => {
3357
- var _a, _b;
3358
- return [
3359
- (_a = action.url) != null ? _a : "",
3360
- {
3361
- method: (_b = action.method) != null ? _b : "POST",
3362
- body: makeRequestBody(action, model),
3363
- headers: { "Content-Type": "application/json" }
3364
- }
3365
- ];
3366
- };
3367
- var makeRequestBody = (action, model) => {
3368
- var _a, _b;
3369
- const method = (_a = action.method) != null ? _a : "POST";
3370
- if (method === "GET") {
3371
- return void 0;
3372
- }
3373
- const payload = recursiveMerge(model, (_b = action.data) != null ? _b : null);
3374
- return payload !== null ? JSON.stringify(payload) : null;
3375
- };
3474
+ // src/utils/component-utils.ts
3475
+ var getSubmittableData = async (components) => Promise.all(components.map(async (component) => component.getSubmittableValue())).then(
3476
+ (values) => values.reduce((acc, value) => recursiveMerge(acc, value), null)
3477
+ );
3478
+ var getSubmittableDataSync = (components) => components.map((component) => component.getSubmittableValueSync()).reduce((acc, value) => recursiveMerge(acc, value), null);
3479
+ var getLocalValues = (components) => components.map((component) => component.getLocalValue()).reduce((acc, value) => recursiveMerge(acc, value), null);
3376
3480
 
3377
- // src/domain/components/step/ExternalConfirmationComponent.ts
3378
- var createExternalConfirmation = (uid, url, updateComponent) => {
3379
- const update = getInputUpdateFunction(updateComponent);
3380
- return {
3381
- type: "external-confirmation",
3382
- kind: "layout",
3383
- uid,
3384
- url,
3385
- status: "initial",
3386
- onSuccess() {
3387
- update(this, (draft) => {
3388
- draft.status = "success";
3389
- });
3390
- },
3391
- onFailure() {
3392
- if (this.status === "initial") {
3393
- update(this, (draft) => {
3394
- draft.status = "failure";
3395
- });
3396
- }
3397
- },
3398
- onCancel() {
3399
- update(this, (draft) => {
3400
- draft.status = "dismissed";
3401
- });
3402
- }
3403
- };
3404
- };
3405
-
3406
- // src/utils/component-utils.ts
3407
- var getSubmittableData = async (components) => Promise.all(components.map(async (component) => component.getSubmittableValue())).then(
3408
- (values) => values.reduce((acc, value) => recursiveMerge(acc, value), null)
3409
- );
3410
- var getSubmittableDataSync = (components) => components.map((component) => component.getSubmittableValueSync()).reduce((acc, value) => recursiveMerge(acc, value), null);
3411
- var getLocalValues = (components) => components.map((component) => component.getLocalValue()).reduce((acc, value) => recursiveMerge(acc, value), null);
3412
-
3413
- // src/domain/components/step/StepDomainComponent.ts
3414
- var createStepComponent = (stepProps) => {
3415
- const _a = stepProps, { uid, stepPolling, stepRefreshAfter, updateComponent } = _a, rest = __objRest(_a, ["uid", "stepPolling", "stepRefreshAfter", "updateComponent"]);
3481
+ // src/domain/components/step/StepDomainComponent.ts
3482
+ var createStepComponent = (stepProps) => {
3483
+ const _a = stepProps, { uid, stepPolling, stepRefreshAfter, updateComponent } = _a, rest = __objRest(_a, ["uid", "stepPolling", "stepRefreshAfter", "updateComponent"]);
3416
3484
  const update = getInputUpdateFunction(updateComponent);
3417
3485
  const component = __spreadProps(__spreadValues({
3418
3486
  uid
@@ -3557,27 +3625,42 @@ var getStepRefreshAfter = ({
3557
3625
  };
3558
3626
 
3559
3627
  // src/domain/prefetching/request-cache.ts
3560
- var makeRequestCache = () => {
3561
- const cache = /* @__PURE__ */ new Map();
3562
- return {
3563
- has: (...requestParams) => {
3564
- return cache.has(makeKey(...requestParams));
3565
- },
3566
- get: (...requestParams) => {
3567
- return cache.get(makeKey(...requestParams));
3568
- },
3569
- delete: (...requestParams) => {
3570
- return cache.delete(makeKey(...requestParams));
3571
- },
3572
- set: (...[input, init, response]) => {
3573
- return cache.set(makeKey(input, init), response);
3628
+ var makeRequestCacheWithParent = (parent) => {
3629
+ const map = /* @__PURE__ */ new Map();
3630
+ const cache = {
3631
+ get: (requestParams) => {
3632
+ var _a;
3633
+ const key = makeKey(requestParams);
3634
+ const promise = (_a = map.get(key)) != null ? _a : parent == null ? void 0 : parent.get(requestParams);
3635
+ map.delete(key);
3636
+ return promise;
3574
3637
  },
3575
- clear: () => {
3576
- cache.clear();
3638
+ set: (requestParams, responsePromise) => {
3639
+ return map.set(makeKey(requestParams), responsePromise);
3577
3640
  }
3578
3641
  };
3642
+ return cache;
3579
3643
  };
3580
- var makeKey = (...requestParams) => {
3644
+ var makeRequestCache = (initialValues = []) => {
3645
+ const cache = makeRequestCacheWithParent(void 0);
3646
+ initialValues.forEach(([requestParams, responsePromise]) => {
3647
+ cache.set(requestParams, responsePromise);
3648
+ });
3649
+ return cache;
3650
+ };
3651
+ var normaliseRequestCache = (cache) => {
3652
+ if (cache === void 0) {
3653
+ return makeRequestCache();
3654
+ }
3655
+ if (isRequestCacheInstance(cache)) {
3656
+ return cache;
3657
+ }
3658
+ return makeRequestCache(cache);
3659
+ };
3660
+ var isRequestCacheInstance = (cache) => {
3661
+ return !cache || !Array.isArray(cache);
3662
+ };
3663
+ var makeKey = (requestParams) => {
3581
3664
  var _a, _b;
3582
3665
  const [input, init] = requestParams;
3583
3666
  const url = typeof input === "string" || input instanceof URL ? input.toString() : input.url;
@@ -4069,7 +4152,7 @@ var getInitialValidationAsyncState = () => ({
4069
4152
  });
4070
4153
 
4071
4154
  // src/flow/response-utils.ts
4072
- import { validateActionResponse } from "@wise/dynamic-flow-types/spec";
4155
+ import { validateActionResponse, validateSubflowResponse } from "@wise/dynamic-flow-types/spec";
4073
4156
  var assertResponseIsValid = (response) => {
4074
4157
  if (!isResponse(response)) {
4075
4158
  throw new Error("Incorrect type of response from fetch. Expected object of type Response.");
@@ -4115,6 +4198,13 @@ function assertModalResponseBody(body) {
4115
4198
  "Incorrect response body in modal response. Expected an object satisfying the type { title?: string, components: Layout[] }."
4116
4199
  );
4117
4200
  }
4201
+ function assertSubflowResponseBody(body) {
4202
+ const { valid } = validateSubflowResponse(body);
4203
+ if (valid) {
4204
+ return;
4205
+ }
4206
+ throw new Error("Incorrect response body in subflow response.");
4207
+ }
4118
4208
  function isErrorResponseBody(body) {
4119
4209
  return Boolean(
4120
4210
  isObject(body) && (body.refreshFormUrl || body.refreshUrl || body.validation || body.error || body.analytics)
@@ -5573,6 +5663,83 @@ var integerSchemaToComponent = (schemaMapperProps, mapperProps) => {
5573
5663
  );
5574
5664
  };
5575
5665
 
5666
+ // src/domain/components/FormattedValueComponent.ts
5667
+ var createFormattedValueComponent = (props, updateComponent) => {
5668
+ const {
5669
+ uid,
5670
+ schemaId,
5671
+ analyticsId,
5672
+ alert,
5673
+ control,
5674
+ description,
5675
+ errors,
5676
+ format,
5677
+ help,
5678
+ hidden,
5679
+ media,
5680
+ summariser,
5681
+ title,
5682
+ tags,
5683
+ value,
5684
+ schemaOnChange
5685
+ } = props;
5686
+ const update = getInputUpdateFunction(updateComponent);
5687
+ return {
5688
+ type: "formatted-value",
5689
+ kind: "input",
5690
+ uid,
5691
+ schemaId,
5692
+ analyticsId,
5693
+ alert,
5694
+ control,
5695
+ description,
5696
+ errors,
5697
+ format,
5698
+ help,
5699
+ hidden,
5700
+ media,
5701
+ title,
5702
+ tags,
5703
+ value,
5704
+ async getSubmittableValue() {
5705
+ return this.getSubmittableValueSync();
5706
+ },
5707
+ getSubmittableValueSync() {
5708
+ return this.getLocalValue();
5709
+ },
5710
+ getSummary() {
5711
+ return summariser(this.getLocalValue());
5712
+ },
5713
+ getLocalValue() {
5714
+ return this.value;
5715
+ },
5716
+ validate() {
5717
+ return true;
5718
+ },
5719
+ onChange(newValue) {
5720
+ update(this, (draft) => {
5721
+ draft.value = newValue;
5722
+ });
5723
+ void (schemaOnChange == null ? void 0 : schemaOnChange());
5724
+ }
5725
+ };
5726
+ };
5727
+
5728
+ // src/domain/mappers/schema/objectSchemaToComponent/objectSchemaToFormattedValueComponent.ts
5729
+ var objectSchemaToFormattedValueComponent = (schemaMapperProps, mapperProps) => {
5730
+ const { onBehavior } = mapperProps;
5731
+ const { schema } = schemaMapperProps;
5732
+ const { format } = schema;
5733
+ return createFormattedValueComponent(
5734
+ __spreadProps(__spreadValues({}, mapCommonSchemaProps(schemaMapperProps)), {
5735
+ format,
5736
+ value: schemaMapperProps.model,
5737
+ schemaOnChange: getSchemaOnChange(schema, onBehavior)
5738
+ }),
5739
+ mapperProps.updateComponent
5740
+ );
5741
+ };
5742
+
5576
5743
  // src/domain/components/MoneyInputComponent.ts
5577
5744
  var createMoneyInputComponent = (moneyInputProps, updateComponent) => {
5578
5745
  const _a = moneyInputProps, {
@@ -5986,11 +6153,17 @@ var createSelectInputComponent = (selectProps, updateComponent) => {
5986
6153
  if (updatedIndex === this.selectedIndex) {
5987
6154
  return;
5988
6155
  }
5989
- if (updatedIndex !== null && this.analyticsId) {
5990
- selectProps.trackEvent("OneOf Selected", {
5991
- oneOfId: this.analyticsId,
5992
- schemaId: this.children[updatedIndex].analyticsId
6156
+ if (updatedIndex !== null) {
6157
+ selectProps.trackEvent("OneOf Option Selected", {
6158
+ schema: this.analyticsId,
6159
+ selectedOption: this.children[updatedIndex].analyticsId
5993
6160
  });
6161
+ if (this.analyticsId) {
6162
+ selectProps.trackEvent("OneOf Selected", {
6163
+ oneOfId: this.analyticsId,
6164
+ schemaId: this.children[updatedIndex].analyticsId
6165
+ });
6166
+ }
5994
6167
  }
5995
6168
  this._update((draft) => {
5996
6169
  draft.errors = [];
@@ -6595,9 +6768,16 @@ var mapSchemaToComponent = (schemaMapperProps, mapperProps) => {
6595
6768
  return booleanSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
6596
6769
  }
6597
6770
  if (isObjectSchema(schema)) {
6598
- if (schema.format === "money") {
6771
+ const { format } = schema;
6772
+ if (format === "money") {
6599
6773
  return objectSchemaToMoneyInputComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
6600
6774
  }
6775
+ if (format != null && Object.keys(schema.properties).length === 0) {
6776
+ return objectSchemaToFormattedValueComponent(
6777
+ __spreadProps(__spreadValues({}, schemaMapperProps), { schema: __spreadProps(__spreadValues({}, schema), { format }) }),
6778
+ mapperProps
6779
+ );
6780
+ }
6601
6781
  return objectSchemaToObjectComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
6602
6782
  }
6603
6783
  if (isIntegerSchema(schema)) {
@@ -6720,6 +6900,227 @@ var groupLayout = (acc, layout) => {
6720
6900
  var hasChildren = (component) => "components" in component;
6721
6901
  var hasColumns = (component) => "right" in component && "left" in component;
6722
6902
 
6903
+ // src/flow/handleErrorResponse.ts
6904
+ var handleErrorResponse = async (response, actionId, trackEvent) => {
6905
+ const body = await parseResponseBodyAsJsonElement(response.clone());
6906
+ if (isErrorResponseBody(body)) {
6907
+ const refreshUrl = body.refreshUrl || body.refreshFormUrl;
6908
+ const { error, validation, analytics } = body;
6909
+ trackEvent("Action Failed", __spreadProps(__spreadValues({}, analytics), { actionId, statusCode: response.status }));
6910
+ const errors = { error, validation };
6911
+ return refreshUrl ? { type: "refresh", body: { refreshUrl, errors } } : {
6912
+ type: "error",
6913
+ body: { errors, analytics },
6914
+ httpError: { statusCode: response.status }
6915
+ };
6916
+ }
6917
+ trackEvent("Action Failed", { actionId, statusCode: response.status });
6918
+ const errorMessage = await parseResponseBodyAsText(response);
6919
+ return {
6920
+ type: "error",
6921
+ httpError: {
6922
+ message: errorMessage || void 0,
6923
+ statusCode: response.status
6924
+ }
6925
+ };
6926
+ };
6927
+
6928
+ // src/flow/getResponseType.ts
6929
+ var responseTypes = ["step", "action", "exit", "modal", "subflow"];
6930
+ var getResponseType = async (response) => {
6931
+ assertResponseIsValid(response);
6932
+ const headerResponseType = getResponseTypeFromHeader(response);
6933
+ if (headerResponseType) {
6934
+ return headerResponseType;
6935
+ }
6936
+ const jsonBody = await parseResponseBodyAsJsonElement(response.clone());
6937
+ if (isObject(jsonBody) && jsonBody.action) {
6938
+ return "action";
6939
+ }
6940
+ return "step";
6941
+ };
6942
+ var getResponseTypeFromHeader = (response) => {
6943
+ var _a, _b;
6944
+ if ((_a = response.headers) == null ? void 0 : _a.has("X-Df-Response-Type")) {
6945
+ const type = response.headers.get("X-Df-Response-Type");
6946
+ assertDFResponseType(type);
6947
+ return type;
6948
+ }
6949
+ if ((_b = response.headers) == null ? void 0 : _b.has("X-Df-Exit")) {
6950
+ return "exit";
6951
+ }
6952
+ return void 0;
6953
+ };
6954
+ function assertDFResponseType(type) {
6955
+ if (!responseTypes.includes(type)) {
6956
+ throw new Error(
6957
+ "Unsupported X-Df-Response-Type. Allowed values are 'step', 'action', 'exit', 'error', 'modal', 'subflow'."
6958
+ );
6959
+ }
6960
+ }
6961
+
6962
+ // src/flow/makeSafeHttpClient.ts
6963
+ var makeSafeHttpClient = (httpClient) => async (...props) => {
6964
+ try {
6965
+ return await httpClient(...props);
6966
+ } catch (e) {
6967
+ return null;
6968
+ }
6969
+ };
6970
+
6971
+ // src/flow/executeRequest.ts
6972
+ var executeRequest = async (props) => {
6973
+ const { exit, request, requestCache, httpClient, trackEvent, logEvent } = props;
6974
+ const { url, method, body } = request;
6975
+ const response = await getCachedOrFetch(
6976
+ [
6977
+ url,
6978
+ {
6979
+ method,
6980
+ body: body ? JSON.stringify(body) : void 0,
6981
+ headers: { "Content-Type": "application/json" }
6982
+ }
6983
+ ],
6984
+ requestCache,
6985
+ httpClient
6986
+ );
6987
+ if (!response) {
6988
+ const extra = { errorMessage: "Network Error" };
6989
+ trackEvent("Request Failed", extra);
6990
+ logEvent("error", "Dynamic Flow - Request Failed Unexpectedly", extra);
6991
+ return { type: "error" };
6992
+ }
6993
+ if (!response.ok) {
6994
+ return handleErrorResponse(response, void 0, trackEvent);
6995
+ }
6996
+ const responseType = await getResponseType(response);
6997
+ const responseBody = await parseResponseBodyAsJsonElement(response.clone());
6998
+ if (exit) {
6999
+ return { type: "complete", result: responseBody };
7000
+ }
7001
+ switch (responseType) {
7002
+ case "step": {
7003
+ const etag = response.headers.get("etag") || null;
7004
+ assertStepResponseBody(responseBody);
7005
+ return { type: "replace-step", step: responseBody, etag };
7006
+ }
7007
+ case "exit": {
7008
+ return { type: "complete", result: responseBody };
7009
+ }
7010
+ case "action": {
7011
+ assertActionResponseBody(responseBody);
7012
+ return {
7013
+ type: "behavior",
7014
+ behavior: {
7015
+ type: "action",
7016
+ action: responseBody.action
7017
+ }
7018
+ };
7019
+ }
7020
+ case "subflow": {
7021
+ assertSubflowResponseBody(responseBody);
7022
+ return {
7023
+ type: "behavior",
7024
+ behavior: __spreadProps(__spreadValues({}, responseBody), {
7025
+ type: "subflow",
7026
+ onCompletion: responseBody.onCompletion ? normaliseBehavior(responseBody.onCompletion, []) : void 0,
7027
+ onError: responseBody.onError ? normaliseBehavior(responseBody.onError, []) : void 0
7028
+ })
7029
+ };
7030
+ }
7031
+ case "modal": {
7032
+ assertModalResponseBody(responseBody);
7033
+ return { type: "behavior", behavior: __spreadProps(__spreadValues({}, responseBody), { type: "modal" }) };
7034
+ }
7035
+ default: {
7036
+ throw new Error(`Unsupported response type: ${String(responseType)}`);
7037
+ }
7038
+ }
7039
+ };
7040
+ var getCachedOrFetch = async (requestParams, requestCache, httpClient) => {
7041
+ const cachedPromise = requestCache.get(requestParams);
7042
+ if (cachedPromise) {
7043
+ const cachedResponse = await cachedPromise;
7044
+ if (cachedResponse == null ? void 0 : cachedResponse.ok) {
7045
+ return cachedResponse;
7046
+ }
7047
+ }
7048
+ return makeSafeHttpClient(httpClient)(...requestParams);
7049
+ };
7050
+
7051
+ // src/flow/executeSubmission.ts
7052
+ var executeSubmission = async (props) => {
7053
+ const { httpClient, requestCache, trackEvent, logEvent } = props;
7054
+ const triggerAction = async (action, model, isInitial) => {
7055
+ var _a, _b;
7056
+ const { exit, url, result = null, id: actionId } = action;
7057
+ const trackSubmissionEvent = !isInitial ? trackEvent : () => {
7058
+ };
7059
+ trackSubmissionEvent("Action Triggered", { actionId });
7060
+ if (exit && !url) {
7061
+ trackSubmissionEvent("Action Succeeded", { actionId });
7062
+ return { type: "complete", result };
7063
+ }
7064
+ try {
7065
+ const command = await executeRequest({
7066
+ exit,
7067
+ request: createRequestFromAction(action, model),
7068
+ requestCache,
7069
+ httpClient,
7070
+ trackEvent: (name, properties) => {
7071
+ trackSubmissionEvent(name, __spreadProps(__spreadValues({}, properties), { actionId }));
7072
+ },
7073
+ logEvent
7074
+ });
7075
+ switch (command.type) {
7076
+ case "error": {
7077
+ trackSubmissionEvent("Action Failed", __spreadValues({
7078
+ actionId,
7079
+ statusCode: (_a = command.httpError) == null ? void 0 : _a.statusCode
7080
+ }, (_b = command.body) == null ? void 0 : _b.analytics));
7081
+ return command;
7082
+ }
7083
+ case "behavior": {
7084
+ if (command.behavior.type === "action") {
7085
+ trackSubmissionEvent("Action Succeeded", { actionId });
7086
+ return await executeRequest({
7087
+ request: createRequestFromAction(command.behavior.action, null),
7088
+ requestCache,
7089
+ httpClient,
7090
+ trackEvent,
7091
+ logEvent
7092
+ });
7093
+ }
7094
+ trackSubmissionEvent("Action Succeeded", { actionId });
7095
+ return command;
7096
+ }
7097
+ case "complete": {
7098
+ trackSubmissionEvent("Action Succeeded", { actionId });
7099
+ return __spreadProps(__spreadValues({}, command), { result: recursiveMerge(command.result, result) });
7100
+ }
7101
+ default: {
7102
+ trackSubmissionEvent("Action Succeeded", { actionId });
7103
+ return command;
7104
+ }
7105
+ }
7106
+ } catch (error) {
7107
+ const errorMessage = getErrorMessage(error);
7108
+ trackSubmissionEvent("Action Failed", { actionId, errorMessage });
7109
+ logEvent("error", "Dynamic Flow - Action Failed Unexpectedly", { actionId, errorMessage });
7110
+ throw error;
7111
+ }
7112
+ };
7113
+ return triggerAction(props.action, props.model, props.isInitial);
7114
+ };
7115
+ var createRequestFromAction = (action, model) => {
7116
+ var _a, _b, _c;
7117
+ return __spreadProps(__spreadValues({}, action), {
7118
+ url: (_a = action.url) != null ? _a : "",
7119
+ method: (_b = action.method) != null ? _b : "POST",
7120
+ body: action.method === "GET" ? void 0 : recursiveMerge(model, (_c = action.data) != null ? _c : null)
7121
+ });
7122
+ };
7123
+
6723
7124
  // src/domain/mappers/mapStepToComponent.ts
6724
7125
  var mapStepToComponent = (_a) => {
6725
7126
  var _b = _a, {
@@ -6738,7 +7139,7 @@ var mapStepToComponent = (_a) => {
6738
7139
  "onBehavior"
6739
7140
  ]);
6740
7141
  var _a2;
6741
- const { etag, step, stepLocalValue, logEvent, updateComponent } = restProps;
7142
+ const { etag, step, stepLocalValue, flowRequestCache, logEvent, updateComponent } = restProps;
6742
7143
  const {
6743
7144
  id,
6744
7145
  control,
@@ -6753,12 +7154,15 @@ var mapStepToComponent = (_a) => {
6753
7154
  title,
6754
7155
  tags
6755
7156
  } = step;
6756
- const submissionRequestsCache = makeRequestCache();
7157
+ const requestCache = makeRequestCacheWithParent(flowRequestCache);
6757
7158
  const submissionBehaviors = [];
6758
7159
  const registerSubmissionBehavior = (behavior) => {
6759
7160
  if (behavior.type === "action" && behavior.action.prefetch) {
6760
7161
  submissionBehaviors.push(behavior);
6761
7162
  }
7163
+ if (behavior.type === "subflow" && behavior.launchConfig.type === "dynamic" && behavior.launchConfig.request.prefetch) {
7164
+ submissionBehaviors.push(behavior);
7165
+ }
6762
7166
  };
6763
7167
  const back = mapBackNavigation(navigation, onBehavior, features.isEnabled("nativeBack"));
6764
7168
  const stepId = id || key;
@@ -6819,7 +7223,7 @@ var mapStepToComponent = (_a) => {
6819
7223
  title,
6820
7224
  tags,
6821
7225
  stackBehavior: (_a2 = navigation == null ? void 0 : navigation.stackBehavior) != null ? _a2 : "default",
6822
- submissionRequestsCache,
7226
+ requestCache,
6823
7227
  step,
6824
7228
  updateComponent,
6825
7229
  trackEvent,
@@ -6829,7 +7233,7 @@ var mapStepToComponent = (_a) => {
6829
7233
  httpClient: mapperProps.httpClient,
6830
7234
  model: stepComponent.getSubmittableValueSync(),
6831
7235
  behaviors: submissionBehaviors,
6832
- requestsCache: submissionRequestsCache
7236
+ requestCache
6833
7237
  });
6834
7238
  return stepComponent;
6835
7239
  };
@@ -6852,56 +7256,25 @@ var mapBackNavigation = (navigation, onBehavior, isNativeBackEnabled) => {
6852
7256
  } : void 0;
6853
7257
  };
6854
7258
  var executePrefetch = (props) => {
6855
- const {
6856
- httpClient,
6857
- behaviors: submissionBehaviors,
6858
- model,
6859
- requestsCache: submissionRequestsCache
6860
- } = props;
7259
+ const { httpClient, behaviors: submissionBehaviors, model, requestCache } = props;
6861
7260
  submissionBehaviors.forEach((behavior) => {
6862
- const requestParams = makeSubmissionRequest(behavior.action, model);
7261
+ const request = behavior.type === "action" ? createRequestFromAction(behavior.action, model) : behavior.launchConfig.request;
7262
+ const requestParams = [
7263
+ request.url,
7264
+ {
7265
+ body: JSON.stringify(request.body),
7266
+ method: request.method,
7267
+ headers: { "Content-Type": "application/json" }
7268
+ }
7269
+ ];
6863
7270
  try {
6864
7271
  const responsePromise = httpClient(...requestParams).catch(() => null);
6865
- submissionRequestsCache.set(...requestParams, responsePromise);
7272
+ requestCache.set(requestParams, responsePromise);
6866
7273
  } catch (e) {
6867
7274
  }
6868
7275
  });
6869
7276
  };
6870
7277
 
6871
- // src/flow/getResponseType.ts
6872
- var responseTypes = ["step", "action", "exit", "modal"];
6873
- var getResponseType = async (response) => {
6874
- assertResponseIsValid(response);
6875
- const headerResponseType = getResponseTypeFromHeader(response);
6876
- if (headerResponseType) {
6877
- return headerResponseType;
6878
- }
6879
- const jsonBody = await parseResponseBodyAsJsonElement(response.clone());
6880
- if (isObject(jsonBody) && jsonBody.action) {
6881
- return "action";
6882
- }
6883
- return "step";
6884
- };
6885
- var getResponseTypeFromHeader = (response) => {
6886
- var _a, _b;
6887
- if ((_a = response.headers) == null ? void 0 : _a.has("X-Df-Response-Type")) {
6888
- const type = response.headers.get("X-Df-Response-Type");
6889
- assertDFResponseType(type);
6890
- return type;
6891
- }
6892
- if ((_b = response.headers) == null ? void 0 : _b.has("X-Df-Exit")) {
6893
- return "exit";
6894
- }
6895
- return void 0;
6896
- };
6897
- function assertDFResponseType(type) {
6898
- if (!responseTypes.includes(type)) {
6899
- throw new Error(
6900
- "Unsupported X-Df-Response-Type. Allowed values are 'step', 'action', 'exit', 'error', 'modal'."
6901
- );
6902
- }
6903
- }
6904
-
6905
7278
  // src/flow/executePoll.ts
6906
7279
  var executePoll = async (props) => {
6907
7280
  const { errorBehavior, signal, url, httpClient, trackEvent } = props;
@@ -6995,113 +7368,62 @@ var executeRefresh = async (props) => {
6995
7368
  }
6996
7369
  };
6997
7370
 
6998
- // src/flow/makeSafeHttpClient.ts
6999
- var makeSafeHttpClient = (httpClient) => async (...props) => {
7000
- try {
7001
- return await httpClient(...props);
7002
- } catch (e) {
7003
- return null;
7004
- }
7005
- };
7006
-
7007
- // src/flow/executeSubmission.ts
7008
- var executeSubmission = async (props) => {
7009
- const { httpClient, requestCache, trackEvent, logEvent } = props;
7010
- const triggerAction = async (action, model, isInitial) => {
7011
- const { exit, url, result = null, id: actionId } = action;
7012
- const trackSubmissionEvent = !isInitial ? trackEvent : () => {
7013
- };
7014
- trackSubmissionEvent("Action Triggered", { actionId });
7015
- if (exit && !url) {
7016
- trackSubmissionEvent("Action Succeeded", { actionId });
7017
- return { type: "complete", result };
7018
- }
7019
- const requestParams = makeSubmissionRequest(action, model);
7020
- const response = await getCachedOrFetch(requestParams, requestCache, httpClient);
7021
- if (!response) {
7022
- const extra = { actionId, errorMessage: "Network Error" };
7023
- trackEvent("Action Failed", extra);
7024
- logEvent("error", "Dynamic Flow - Action Failed Unexpectedly", extra);
7025
- return { type: "error" };
7026
- }
7027
- if (!response.ok) {
7028
- return handleErrorResponse(response, actionId);
7029
- }
7030
- try {
7031
- const responseType = await getResponseType(response);
7032
- const body = await parseResponseBodyAsJsonElement(response);
7033
- if (exit) {
7034
- return { type: "complete", result: recursiveMerge(body, result) };
7035
- }
7036
- switch (responseType) {
7037
- case "step": {
7038
- const etag = response.headers.get("etag") || null;
7039
- assertStepResponseBody(body);
7040
- trackSubmissionEvent("Action Succeeded", { actionId });
7041
- return { type: "replace-step", step: body, etag };
7042
- }
7043
- case "exit": {
7044
- trackSubmissionEvent("Action Succeeded", { actionId });
7045
- return { type: "complete", result: recursiveMerge(body, result) };
7046
- }
7047
- case "action": {
7048
- assertActionResponseBody(body);
7049
- trackSubmissionEvent("Action Succeeded", { actionId });
7050
- return await triggerAction(body.action, null, false);
7051
- }
7052
- case "modal": {
7053
- assertModalResponseBody(body);
7054
- trackSubmissionEvent("Action Succeeded", { actionId });
7055
- return { type: "behavior", behavior: __spreadProps(__spreadValues({}, body), { type: "modal" }) };
7056
- }
7057
- default: {
7058
- throw new Error(`Unsupported response type: ${String(responseType)}`);
7059
- }
7371
+ // src/getSubflowCallbacks.ts
7372
+ var getSubflowCallbacks = ({
7373
+ behavior,
7374
+ close,
7375
+ restart,
7376
+ onBehavior,
7377
+ onError,
7378
+ onEvent
7379
+ }) => {
7380
+ const {
7381
+ onCompletion: onCompletionBehavior,
7382
+ onError: onErrorBehavior,
7383
+ referrerId,
7384
+ resultKey
7385
+ } = behavior;
7386
+ return {
7387
+ onCompletion: (result) => {
7388
+ var _a;
7389
+ restart();
7390
+ if (!onCompletionBehavior) {
7391
+ close();
7392
+ return;
7060
7393
  }
7061
- } catch (error) {
7062
- const errorMessage = getErrorMessage(error);
7063
- trackSubmissionEvent("Action Failed", { actionId, errorMessage });
7064
- logEvent("error", "Dynamic Flow - Action Failed Unexpectedly", { actionId, errorMessage });
7065
- throw error;
7066
- }
7067
- };
7068
- const handleErrorResponse = async (response, actionId) => {
7069
- const body = await parseResponseBodyAsJsonElement(response.clone());
7070
- if (isErrorResponseBody(body)) {
7071
- const refreshUrl = body.refreshUrl || body.refreshFormUrl;
7072
- const { error, validation, analytics } = body;
7073
- trackEvent("Action Failed", __spreadProps(__spreadValues({}, analytics), { actionId, statusCode: response.status }));
7074
- const errors = { error, validation };
7075
- return refreshUrl ? { type: "refresh", body: { refreshUrl, errors } } : {
7076
- type: "error",
7077
- body: { errors, analytics },
7078
- httpError: { statusCode: response.status }
7079
- };
7080
- }
7081
- trackEvent("Action Failed", { actionId, statusCode: response.status });
7082
- const errorMessage = await parseResponseBodyAsText(response);
7083
- return {
7084
- type: "error",
7085
- httpError: {
7086
- message: errorMessage || void 0,
7087
- statusCode: response.status
7394
+ if (onCompletionBehavior.type === "action") {
7395
+ const newActionData = recursiveMerge(
7396
+ (_a = onCompletionBehavior.action.data) != null ? _a : null,
7397
+ resultKey ? { [resultKey]: result } : result
7398
+ );
7399
+ void onBehavior(__spreadProps(__spreadValues({}, onCompletionBehavior), {
7400
+ action: __spreadProps(__spreadValues({}, onCompletionBehavior.action), { data: newActionData })
7401
+ }));
7402
+ return;
7088
7403
  }
7089
- };
7090
- };
7091
- return triggerAction(props.action, props.model, props.isInitial);
7092
- };
7093
- var getCachedOrFetch = async (requestParams, requestCache, httpClient) => {
7094
- if (requestCache == null ? void 0 : requestCache.has(...requestParams)) {
7095
- const cachedPromise = requestCache.get(...requestParams);
7096
- requestCache.delete(...requestParams);
7097
- if (cachedPromise) {
7098
- const cachedResponse = await cachedPromise;
7099
- if (cachedResponse == null ? void 0 : cachedResponse.ok) {
7100
- return cachedResponse;
7404
+ void onBehavior(onCompletionBehavior);
7405
+ close();
7406
+ },
7407
+ onError: (error, status) => {
7408
+ if (!onErrorBehavior) {
7409
+ onError(error, {}, status);
7410
+ close();
7411
+ return;
7101
7412
  }
7413
+ restart();
7414
+ void onBehavior(onErrorBehavior);
7415
+ close();
7416
+ },
7417
+ onEvent: (name, properties) => {
7418
+ onEvent(name, __spreadValues({
7419
+ referrerId
7420
+ }, properties));
7421
+ },
7422
+ onCancellation: () => {
7423
+ restart();
7424
+ close();
7102
7425
  }
7103
- }
7104
- return makeSafeHttpClient(httpClient)(...requestParams);
7426
+ };
7105
7427
  };
7106
7428
 
7107
7429
  // src/renderers/getSchemaErrorMessageFunction.ts
@@ -7331,19 +7653,18 @@ function useStableCallback(handler) {
7331
7653
  return useCallback((...args) => ref.current ? ref.current(...args) : null, []);
7332
7654
  }
7333
7655
 
7334
- // src/useDynamicFlowCore.tsx
7335
- function useDynamicFlowCore(props) {
7336
- const _a = props, { flowId, initialAction, initialStep, features } = _a, rest = __objRest(_a, ["flowId", "initialAction", "initialStep", "features"]);
7656
+ // src/useDynamicFlowController.tsx
7657
+ function useDynamicFlowController(props) {
7658
+ const _a = props, { flowId, initialAction, initialStep, features, scrollToTop } = _a, rest = __objRest(_a, ["flowId", "initialAction", "initialStep", "features", "scrollToTop"]);
7337
7659
  const httpClient = useStableCallback(rest.httpClient);
7338
7660
  const onCancellation = useStableCallback(rest.onCancellation);
7339
7661
  const onCompletion = useStableCallback(rest.onCompletion);
7340
- const onCopy = useStableCallback(props.onCopy);
7341
- const onValueChange = useStableCallback(props.onValueChange);
7342
- const onLink = useStableCallback(props.onLink);
7662
+ const onCopy = useStableCallback(rest.onCopy);
7663
+ const onLink = useStableCallback(rest.onLink);
7343
7664
  const onError = useStableCallback(rest.onError);
7344
7665
  const onEvent = useStableCallback(rest.onEvent);
7345
7666
  const onLog = useStableCallback(rest.onLog);
7346
- const scrollToTop = useStableCallback(props.scrollToTop);
7667
+ const onValueChange = useStableCallback(rest.onValueChange);
7347
7668
  const { formatMessage, locale } = useIntl2();
7348
7669
  const getErrorMessageFunctions = useMemo(
7349
7670
  () => getSchemaErrorMessageFunction(formatMessage, locale),
@@ -7351,10 +7672,15 @@ function useDynamicFlowCore(props) {
7351
7672
  );
7352
7673
  const rerender = useRerender();
7353
7674
  const rootComponentRef = useRef2(
7354
- createRootDomainComponent(rerender, scrollToTop, {
7355
- isNativeBackEnabled: features.isEnabled("nativeBack"),
7356
- isFlowCancellable: Boolean(rest.onCancellation)
7357
- })
7675
+ createRootDomainComponent(
7676
+ rerender,
7677
+ scrollToTop,
7678
+ {
7679
+ isNativeBackEnabled: features.isEnabled("nativeBack"),
7680
+ isFlowCancellable: Boolean(rest.onCancellation)
7681
+ },
7682
+ normaliseRequestCache(rest.requestCache)
7683
+ )
7358
7684
  );
7359
7685
  const stepCount = useRef2(0);
7360
7686
  const abortControllerRef = useRef2(new AbortController());
@@ -7363,12 +7689,15 @@ function useDynamicFlowCore(props) {
7363
7689
  abortControllerRef.current = new AbortController();
7364
7690
  return abortControllerRef.current.signal;
7365
7691
  };
7692
+ const hasTriggeredInitialAction = useRef2(false);
7366
7693
  useEffect(() => {
7367
7694
  trackCoreEvent("Initiated");
7368
- if (!initialStep && initialAction) {
7695
+ if (!hasTriggeredInitialAction.current && !initialStep && initialAction) {
7369
7696
  rootComponentRef.current.setLoadingState("submitting");
7697
+ hasTriggeredInitialAction.current = true;
7370
7698
  void onAction(__spreadValues({ method: "GET" }, initialAction), null);
7371
7699
  }
7700
+ rootComponentRef.current.start();
7372
7701
  return () => {
7373
7702
  rootComponentRef.current.stop();
7374
7703
  };
@@ -7381,6 +7710,7 @@ function useDynamicFlowCore(props) {
7381
7710
  const component = createStepComponent2(newStep, etag, null);
7382
7711
  if (component) {
7383
7712
  rootComponentRef.current.pushStep(component);
7713
+ rootComponentRef.current.setLoadingState("idle");
7384
7714
  }
7385
7715
  },
7386
7716
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -7395,12 +7725,14 @@ function useDynamicFlowCore(props) {
7395
7725
  );
7396
7726
  if (component) {
7397
7727
  rootComponentRef.current.updateStep(component);
7728
+ rootComponentRef.current.setLoadingState("idle");
7398
7729
  }
7399
7730
  }, []);
7400
7731
  const getMapperProps = () => ({
7401
7732
  uid: `${rootComponentRef.current.uid}:${stepCount.current}`,
7402
7733
  loadingState: "idle",
7403
7734
  updateComponent: () => rerender(),
7735
+ flowRequestCache: rootComponentRef.current.requestCache,
7404
7736
  getErrorMessageFunctions,
7405
7737
  trackEvent,
7406
7738
  logEvent,
@@ -7439,7 +7771,8 @@ function useDynamicFlowCore(props) {
7439
7771
  const stepId = (_b = (_a2 = step == null ? void 0 : step.id) != null ? _a2 : step == null ? void 0 : step.key) != null ? _b : null;
7440
7772
  const analytics = step == null ? void 0 : step.analytics;
7441
7773
  const metadata = __spreadValues(__spreadValues(__spreadValues(__spreadValues({
7442
- flowId
7774
+ flowId,
7775
+ integrationId: flowId
7443
7776
  }, step ? { stepCount: stepCount.current } : {}), stepId !== null ? { stepId } : {}), analytics), properties);
7444
7777
  try {
7445
7778
  onEvent == null ? void 0 : onEvent(`Dynamic Flow - ${eventName}`, __spreadValues({}, metadata));
@@ -7480,7 +7813,7 @@ function useDynamicFlowCore(props) {
7480
7813
  onCancellation();
7481
7814
  }, []);
7482
7815
  const onBehavior = useCallback2(async (behavior) => {
7483
- var _a2;
7816
+ var _a2, _b, _c;
7484
7817
  switch (behavior.type) {
7485
7818
  case "back": {
7486
7819
  if (behavior.action) {
@@ -7571,6 +7904,33 @@ function useDynamicFlowCore(props) {
7571
7904
  case "dismiss":
7572
7905
  rootComponentRef.current.dismissModal();
7573
7906
  break;
7907
+ case "subflow": {
7908
+ rootComponentRef.current.setLoadingState("submitting");
7909
+ const { launchConfig } = behavior;
7910
+ const { request, presentation } = launchConfig;
7911
+ const callbacks = getSubflowCallbacks({
7912
+ behavior,
7913
+ close: () => rootComponentRef.current.closeSubflow(),
7914
+ onBehavior,
7915
+ onError: closeWithError,
7916
+ onEvent,
7917
+ restart: () => {
7918
+ rootComponentRef.current.setLoadingState("idle");
7919
+ rootComponentRef.current.start();
7920
+ }
7921
+ });
7922
+ const component = createSubflowDomainComponent(
7923
+ __spreadProps(__spreadValues({}, callbacks), {
7924
+ initialRequest: request,
7925
+ requestCache: (_c = (_b = rootComponentRef.current.getStep()) == null ? void 0 : _b.requestCache) != null ? _c : rootComponentRef.current.requestCache,
7926
+ presentation
7927
+ }),
7928
+ rerender
7929
+ );
7930
+ rootComponentRef.current.stop();
7931
+ rootComponentRef.current.addSubflow(component);
7932
+ break;
7933
+ }
7574
7934
  case "none":
7575
7935
  break;
7576
7936
  }
@@ -7579,16 +7939,16 @@ function useDynamicFlowCore(props) {
7579
7939
  }, []);
7580
7940
  const onAction = useCallback2(
7581
7941
  async (action, model) => {
7582
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
7942
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
7583
7943
  try {
7584
7944
  rootComponentRef.current.setLoadingState("submitting");
7585
7945
  const command = await executeSubmission({
7586
7946
  action,
7587
7947
  model,
7588
7948
  isInitial: !rootComponentRef.current.hasStep(),
7589
- requestCache: (_a2 = rootComponentRef.current.getStep()) == null ? void 0 : _a2.submissionRequestsCache,
7949
+ requestCache: (_b = (_a2 = rootComponentRef.current.getStep()) == null ? void 0 : _a2.requestCache) != null ? _b : rootComponentRef.current.requestCache,
7590
7950
  httpClient,
7591
- trackEvent: trackCoreEvent,
7951
+ trackEvent,
7592
7952
  logEvent
7593
7953
  });
7594
7954
  switch (command.type) {
@@ -7600,6 +7960,7 @@ function useDynamicFlowCore(props) {
7600
7960
  }
7601
7961
  case "replace-step": {
7602
7962
  const isFirstStep = !rootComponentRef.current.hasStep();
7963
+ rootComponentRef.current.closeSubflow();
7603
7964
  createStep(command.step, command.etag);
7604
7965
  trackCoreEvent("Step Shown", { isFirstStep });
7605
7966
  break;
@@ -7607,7 +7968,7 @@ function useDynamicFlowCore(props) {
7607
7968
  case "error": {
7608
7969
  rootComponentRef.current.setLoadingState("idle");
7609
7970
  const genericErrorMessage = getErrorMessageFunctions().genericErrorWithRetry();
7610
- const errors = (_c = (_b = command.body) == null ? void 0 : _b.errors) != null ? _c : { error: genericErrorMessage };
7971
+ const errors = (_d = (_c = command.body) == null ? void 0 : _c.errors) != null ? _d : { error: genericErrorMessage };
7611
7972
  const currentStep = rootComponentRef.current.getStep();
7612
7973
  if (currentStep) {
7613
7974
  updateStep(
@@ -7621,16 +7982,16 @@ function useDynamicFlowCore(props) {
7621
7982
  external: void 0
7622
7983
  // and no external, to avoid retriggering it
7623
7984
  }),
7624
- (_e = (_d = rootComponentRef.current.getStep()) == null ? void 0 : _d.etag) != null ? _e : null
7985
+ (_f = (_e = rootComponentRef.current.getStep()) == null ? void 0 : _e.etag) != null ? _f : null
7625
7986
  );
7626
7987
  } else {
7627
- const errorMessage = ((_g = (_f = command.body) == null ? void 0 : _f.errors) == null ? void 0 : _g.error) || ((_h = command.httpError) == null ? void 0 : _h.message) || "Initial request failed";
7988
+ const errorMessage = ((_h = (_g = command.body) == null ? void 0 : _g.errors) == null ? void 0 : _h.error) || ((_i = command.httpError) == null ? void 0 : _i.message) || "Initial request failed";
7628
7989
  closeWithError(
7629
7990
  new Error(errorMessage, {
7630
7991
  cause: `method: ${action.method}, url: ${action.url}`
7631
7992
  }),
7632
7993
  {},
7633
- (_i = command.httpError) == null ? void 0 : _i.statusCode
7994
+ (_j = command.httpError) == null ? void 0 : _j.statusCode
7634
7995
  );
7635
7996
  }
7636
7997
  break;
@@ -7726,25 +8087,25 @@ function useDynamicFlowCore(props) {
7726
8087
  []
7727
8088
  );
7728
8089
  const hasMappedInitialStep = useRef2(false);
7729
- if (!hasMappedInitialStep.current && initialStep && !initialAction) {
8090
+ if (!hasMappedInitialStep.current && initialStep) {
7730
8091
  createStep(initialStep, null);
7731
8092
  trackCoreEvent("Step Shown", { isFirstStep: true });
7732
8093
  hasMappedInitialStep.current = true;
7733
8094
  }
7734
- return { rootComponent: rootComponentRef.current };
8095
+ return {
8096
+ rootComponent: rootComponentRef.current,
8097
+ cancel: closeWithCancellation
8098
+ };
7735
8099
  }
7736
8100
  var useRerender = () => {
7737
8101
  const [, setState] = useState({});
7738
8102
  return useCallback2(() => setState({}), []);
7739
8103
  };
7740
8104
 
7741
- // src/utils/normalise-flow-id.ts
7742
- var normaliseFlowId = (flowId) => flowId.toLowerCase().replace(/[^a-z-]/g, "-");
7743
-
7744
- // src/utils/scrollToTop.ts
7745
- var getScrollToTop = (normalisedFlowId, className3) => (behavior) => {
8105
+ // src/utils/getScrollToTop.ts
8106
+ var getScrollToTop = (normalisedFlowId, className2) => (behavior) => {
7746
8107
  var _a;
7747
- const element = document.querySelector(`div#${normalisedFlowId}.${className3}`);
8108
+ const element = document.querySelector(`div#${normalisedFlowId}.${className2}`);
7748
8109
  if (!element || !window) {
7749
8110
  return;
7750
8111
  }
@@ -7755,10 +8116,13 @@ var getScrollToTop = (normalisedFlowId, className3) => (behavior) => {
7755
8116
  }
7756
8117
  };
7757
8118
 
7758
- // src/DynamicFlowCore.tsx
8119
+ // src/utils/normalise-flow-id.ts
8120
+ var normaliseFlowId = (flowId) => flowId.toLowerCase().replace(/[^a-z-]/g, "-");
8121
+
8122
+ // src/useDynamicFlow.tsx
7759
8123
  import { jsx as jsx6 } from "react/jsx-runtime";
7760
8124
  var className = "dynamic-flow";
7761
- function DynamicFlowCore(props) {
8125
+ function useDynamicFlow(props) {
7762
8126
  var _a;
7763
8127
  const { flowId, renderers, httpClient, onEvent, onError, onLog } = props;
7764
8128
  const normalisedFlowId = normaliseFlowId(flowId);
@@ -7770,7 +8134,10 @@ function DynamicFlowCore(props) {
7770
8134
  var _a2;
7771
8135
  return new FeatureFlags((_a2 = props.features) != null ? _a2 : {});
7772
8136
  }, []);
7773
- const { rootComponent } = useDynamicFlowCore(__spreadProps(__spreadValues({}, props), { features, scrollToTop }));
8137
+ const { rootComponent, cancel } = useDynamicFlowController(__spreadProps(__spreadValues({}, props), {
8138
+ features,
8139
+ scrollToTop
8140
+ }));
7774
8141
  const render = useMemo2(
7775
8142
  () => getRenderFunction([CoreRootRenderer, CoreContainerRenderer, ...renderers]),
7776
8143
  [renderers]
@@ -7783,102 +8150,111 @@ function DynamicFlowCore(props) {
7783
8150
  }),
7784
8151
  stepLoadingState: rootComponent.getLoadingState()
7785
8152
  });
7786
- return /* @__PURE__ */ jsx6(
7787
- ErrorBoundary_default,
7788
- {
7789
- onError: (error) => {
7790
- onEvent == null ? void 0 : onEvent("Dynamic Flow - Failed", { error });
7791
- onError == null ? void 0 : onError(error);
7792
- onLog == null ? void 0 : onLog("error", "Dynamic Flow - ErrorBoundary", { errorMessage: getErrorMessage(error) });
7793
- },
7794
- children: /* @__PURE__ */ jsx6("div", { id: normalisedFlowId, className, children: render(tree) })
7795
- }
7796
- );
8153
+ return {
8154
+ controller: {
8155
+ getSubmittableValue: async () => rootComponent.getSubmittableValue(),
8156
+ validate: () => rootComponent.validate(),
8157
+ cancel
8158
+ },
8159
+ view: /* @__PURE__ */ jsx6(
8160
+ ErrorBoundary_default,
8161
+ {
8162
+ onError: (error) => {
8163
+ onEvent == null ? void 0 : onEvent("Dynamic Flow - Failed", { error });
8164
+ onError == null ? void 0 : onError(error);
8165
+ onLog == null ? void 0 : onLog("error", "Dynamic Flow - ErrorBoundary", {
8166
+ errorMessage: getErrorMessage(error)
8167
+ });
8168
+ },
8169
+ children: /* @__PURE__ */ jsx6("div", { id: normalisedFlowId, className, children: render(tree) })
8170
+ }
8171
+ )
8172
+ };
7797
8173
  }
7798
8174
 
7799
- // src/DynamicFormCore.tsx
7800
- import { forwardRef, useImperativeHandle, useMemo as useMemo3 } from "react";
7801
-
7802
- // src/utils/openLinkInNewTab.tsx
7803
- var openLinkInNewTab = (url) => {
7804
- var _a;
7805
- try {
7806
- const w = (_a = window == null ? void 0 : window.open) == null ? void 0 : _a.call(window, url, "_blank");
7807
- return Boolean(w);
7808
- } catch (e) {
7809
- return false;
7810
- }
7811
- };
7812
-
7813
- // src/DynamicFormCore.tsx
7814
- import { jsx as jsx7 } from "react/jsx-runtime";
7815
- var className2 = "dynamic-flow";
7816
- var DynamicFormCore = forwardRef(function DynamicFormCore2(props, ref) {
7817
- var _a;
7818
- const {
7819
- onCompletion = () => {
8175
+ // src/useDynamicFlowModal.tsx
8176
+ import { useState as useState2 } from "react";
8177
+ var useDynamicFlowModal = (props) => {
8178
+ const _a = props, { renderers, onCompletion, onError, onCancellation, onEvent, onLink } = _a, rest = __objRest(_a, ["renderers", "onCompletion", "onError", "onCancellation", "onEvent", "onLink"]);
8179
+ const [state, setState] = useState2({ type: "initial" });
8180
+ const df = useDynamicFlow(__spreadProps(__spreadValues({}, rest), {
8181
+ onCompletion: (result) => {
8182
+ setState({ type: "completed", result });
8183
+ },
8184
+ onError: (error, status) => {
8185
+ setState({ type: "error", error, status });
8186
+ },
8187
+ onEvent: (name, properties) => {
8188
+ if (name === "Dynamic Flow - Step Shown") {
8189
+ setState({ type: "in-progress" });
8190
+ }
8191
+ onEvent == null ? void 0 : onEvent(name, properties);
7820
8192
  },
7821
- httpClient,
7822
- onEvent,
7823
- onError,
7824
- onLink = openLinkInNewTab,
7825
- renderers
7826
- } = props;
7827
- const normalisedFlowId = normaliseFlowId(props.flowId);
7828
- const scrollToTop = useMemo3(
7829
- () => getScrollToTop(normalisedFlowId, className2),
7830
- [normalisedFlowId]
7831
- );
7832
- const features = useMemo3(() => {
7833
- var _a2;
7834
- return new FeatureFlags((_a2 = props.features) != null ? _a2 : {});
7835
- }, []);
7836
- const { rootComponent } = useDynamicFlowCore(__spreadProps(__spreadValues({
7837
- onCompletion
7838
- }, props), {
7839
- features,
7840
- scrollToTop,
7841
- onLink
8193
+ renderers,
8194
+ onLink: onLink != null ? onLink : (() => true)
7842
8195
  }));
7843
- useImperativeHandle(
7844
- ref,
7845
- () => ({
7846
- getValue: async () => {
7847
- var _a2;
7848
- return (_a2 = await rootComponent.getSubmittableValue()) != null ? _a2 : null;
7849
- },
7850
- validate: () => rootComponent.validate()
7851
- }),
7852
- // eslint-disable-next-line react-hooks/exhaustive-deps
7853
- []
7854
- );
7855
- const render = useMemo3(
7856
- () => getRenderFunction([CoreRootRenderer, CoreContainerRenderer, ...renderers]),
7857
- [renderers]
7858
- );
7859
- const tree = componentToRendererProps(rootComponent, {
7860
- features,
7861
- render,
7862
- httpClient,
7863
- trackEvent: (_a = rootComponent.getTrackEvent()) != null ? _a : (() => {
7864
- }),
7865
- stepLoadingState: rootComponent.getLoadingState()
7866
- });
7867
- return /* @__PURE__ */ jsx7(
7868
- ErrorBoundary_default,
7869
- {
7870
- onError: (error) => {
7871
- onEvent == null ? void 0 : onEvent("Dynamic Flow - Failed");
7872
- onError(error);
7873
- },
7874
- children: /* @__PURE__ */ jsx7("div", { id: normalisedFlowId, className: className2, children: render(tree) })
8196
+ const onUnmount = () => {
8197
+ switch (state.type) {
8198
+ case "completed":
8199
+ onCompletion(state.result);
8200
+ break;
8201
+ case "error":
8202
+ onError(state.error, state.status);
8203
+ break;
8204
+ case "initial":
8205
+ case "in-progress":
8206
+ case "cancelled": {
8207
+ df.controller.cancel();
8208
+ onCancellation == null ? void 0 : onCancellation();
8209
+ }
7875
8210
  }
7876
- );
7877
- });
8211
+ };
8212
+ const onClose = () => {
8213
+ setState({ type: "cancelled" });
8214
+ };
8215
+ return __spreadProps(__spreadValues({}, df), {
8216
+ modal: { body: df.view, open: state.type === "in-progress", onClose, onUnmount }
8217
+ });
8218
+ };
8219
+
8220
+ // src/DynamicFlowCore.tsx
8221
+ function DynamicFlowCore(props) {
8222
+ const df = useDynamicFlow(props);
8223
+ return df.view;
8224
+ }
8225
+
8226
+ // src/domain/features/eventNames.ts
8227
+ var eventNames = [
8228
+ "Initiated",
8229
+ "Succeeded",
8230
+ "Failed",
8231
+ "Cancelled",
8232
+ "Step Shown",
8233
+ "Action Triggered",
8234
+ "Action Succeeded",
8235
+ "Action Aborted",
8236
+ "Action Failed",
8237
+ "Refresh Triggered",
8238
+ "Refresh Succeeded",
8239
+ "Refresh Aborted",
8240
+ "Refresh Failed",
8241
+ "OneOf Selected",
8242
+ "OneOf Option Selected",
8243
+ "PersistAsync Triggered",
8244
+ "PersistAsync Succeeded",
8245
+ "PersistAsync Failed",
8246
+ "Polling Failed",
8247
+ "ValidationAsync Triggered",
8248
+ "ValidationAsync Succeeded",
8249
+ "ValidationAsync Failed"
8250
+ ];
7878
8251
  export {
7879
8252
  DynamicFlowCore as DynamicFlow,
7880
- DynamicFormCore as DynamicForm,
8253
+ eventNames,
7881
8254
  findRendererPropsByType,
7882
8255
  makeHttpClient,
7883
- i18n_default as translations
8256
+ makeRequestCache,
8257
+ i18n_default as translations,
8258
+ useDynamicFlow,
8259
+ useDynamicFlowModal
7884
8260
  };