@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.js CHANGED
@@ -57,10 +57,13 @@ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "
57
57
  var index_exports = {};
58
58
  __export(index_exports, {
59
59
  DynamicFlow: () => DynamicFlowCore,
60
- DynamicForm: () => DynamicFormCore,
60
+ eventNames: () => eventNames,
61
61
  findRendererPropsByType: () => findRendererPropsByType,
62
62
  makeHttpClient: () => makeHttpClient,
63
- translations: () => i18n_default
63
+ makeRequestCache: () => makeRequestCache,
64
+ translations: () => i18n_default,
65
+ useDynamicFlow: () => useDynamicFlow,
66
+ useDynamicFlowModal: () => useDynamicFlowModal
64
67
  });
65
68
  module.exports = __toCommonJS(index_exports);
66
69
 
@@ -778,7 +781,84 @@ var translations = {
778
781
  };
779
782
  var i18n_default = translations;
780
783
 
781
- // src/DynamicFlowCore.tsx
784
+ // src/utils/type-validators.ts
785
+ var isString = (value) => typeof value === "string";
786
+ var isNumber = (value) => typeof value === "number" && !Number.isNaN(value);
787
+ var isInteger = (value) => isNumber(value) && Math.floor(value) === value;
788
+ var isBoolean = (value) => typeof value === "boolean";
789
+ var isObject = (value) => !isNullish(value) && (value == null ? void 0 : value.constructor) === Object;
790
+ var isArray = (value) => Array.isArray(value);
791
+ var isNull = (value) => value === null;
792
+ var isUndefined = (value) => typeof value === "undefined";
793
+ var isNullish = (v) => isNull(v) || isUndefined(v);
794
+ var isFile = (value) => value instanceof File;
795
+ var isValidDate = (value) => isString(value) && /^\d{4}-\d{2}-\d{2}$/.test(value);
796
+
797
+ // src/renderers/utils.ts
798
+ function findRendererPropsByType(root, type, predicate = () => true) {
799
+ if (isArray(root)) {
800
+ return root.flatMap((child) => findRendererPropsByType(child, type, predicate));
801
+ }
802
+ return [
803
+ ...isType(root, type) && predicate(root) ? [root] : [],
804
+ ...getChildren(root).flatMap((child) => findRendererPropsByType(child, type, predicate))
805
+ ];
806
+ }
807
+ var isType = (node, type) => node.type === type;
808
+ var getChildren = (node) => {
809
+ switch (node.type) {
810
+ case "root":
811
+ case "box":
812
+ case "container":
813
+ case "form":
814
+ case "form-section":
815
+ case "step":
816
+ case "modal":
817
+ case "section":
818
+ return node.childrenProps;
819
+ case "columns":
820
+ return [...node.startChildrenProps, ...node.endChildrenProps];
821
+ case "modal-layout":
822
+ return node.content.childrenProps;
823
+ case "repeatable":
824
+ return node.editableItemProps ? [node.editableItemProps] : [];
825
+ case "input-select":
826
+ return node.childrenProps ? [node.childrenProps] : [];
827
+ case "tabs":
828
+ return node.tabs.flatMap((c) => c.childrenProps);
829
+ case "alert":
830
+ case "button":
831
+ case "input-checkbox":
832
+ case "input-date":
833
+ case "decision":
834
+ case "divider":
835
+ case "formatted-value":
836
+ case "heading":
837
+ case "hidden":
838
+ case "image":
839
+ case "instructions":
840
+ case "input-integer":
841
+ case "list":
842
+ case "loading-indicator":
843
+ case "markdown":
844
+ case "input-multi-select":
845
+ case "input-upload-multi":
846
+ case "input-number":
847
+ case "money-input":
848
+ case "paragraph":
849
+ case "progress":
850
+ case "review":
851
+ case "search":
852
+ case "status-list":
853
+ case "input-text":
854
+ case "input-upload":
855
+ case "external-confirmation":
856
+ case "subflow":
857
+ return [];
858
+ }
859
+ };
860
+
861
+ // src/useDynamicFlow.tsx
782
862
  var import_react4 = require("react");
783
863
 
784
864
  // src/common/errorBoundary/ErrorBoundary.tsx
@@ -882,88 +962,19 @@ var CoreContainerRenderer = {
882
962
  render: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children })
883
963
  };
884
964
 
885
- // src/utils/type-validators.ts
886
- var isString = (value) => typeof value === "string";
887
- var isNumber = (value) => typeof value === "number" && !Number.isNaN(value);
888
- var isInteger = (value) => isNumber(value) && Math.floor(value) === value;
889
- var isBoolean = (value) => typeof value === "boolean";
890
- var isObject = (value) => !isNullish(value) && (value == null ? void 0 : value.constructor) === Object;
891
- var isArray = (value) => Array.isArray(value);
892
- var isNull = (value) => value === null;
893
- var isUndefined = (value) => typeof value === "undefined";
894
- var isNullish = (v) => isNull(v) || isUndefined(v);
895
- var isFile = (value) => value instanceof File;
896
- var isValidDate = (value) => isString(value) && /^\d{4}-\d{2}-\d{2}$/.test(value);
897
-
898
- // src/renderers/utils.ts
899
- function findRendererPropsByType(root, type, predicate = () => true) {
900
- if (isArray(root)) {
901
- return root.flatMap((child) => findRendererPropsByType(child, type, predicate));
902
- }
903
- return [
904
- ...isType(root, type) && predicate(root) ? [root] : [],
905
- ...getChildren(root).flatMap((child) => findRendererPropsByType(child, type, predicate))
906
- ];
907
- }
908
- var isType = (node, type) => node.type === type;
909
- var getChildren = (node) => {
910
- switch (node.type) {
911
- case "root":
912
- case "box":
913
- case "container":
914
- case "form":
915
- case "form-section":
916
- case "step":
917
- case "modal":
918
- case "section":
919
- return node.childrenProps;
920
- case "columns":
921
- return [...node.startChildrenProps, ...node.endChildrenProps];
922
- case "modal-layout":
923
- return node.content.childrenProps;
924
- case "repeatable":
925
- return node.editableItemProps ? [node.editableItemProps] : [];
926
- case "input-select":
927
- return node.childrenProps ? [node.childrenProps] : [];
928
- case "tabs":
929
- return node.tabs.flatMap((c) => c.childrenProps);
930
- case "alert":
931
- case "button":
932
- case "input-checkbox":
933
- case "input-date":
934
- case "decision":
935
- case "divider":
936
- case "heading":
937
- case "hidden":
938
- case "image":
939
- case "instructions":
940
- case "input-integer":
941
- case "list":
942
- case "loading-indicator":
943
- case "markdown":
944
- case "input-multi-select":
945
- case "input-upload-multi":
946
- case "input-number":
947
- case "money-input":
948
- case "paragraph":
949
- case "progress":
950
- case "review":
951
- case "search":
952
- case "status-list":
953
- case "input-text":
954
- case "input-upload":
955
- case "external-confirmation":
956
- return [];
957
- }
958
- };
959
-
960
965
  // src/renderers/CoreRootRenderer.tsx
961
966
  var import_jsx_runtime4 = require("react/jsx-runtime");
962
967
  var CoreRootRenderer = {
963
968
  canRenderType: "root",
964
- render: ({ children, childrenProps }) => {
969
+ render: ({ children, childrenProps, subflow }) => {
970
+ if ((subflow == null ? void 0 : subflow.presentation.type) === "push") {
971
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: subflow.children });
972
+ }
965
973
  const [stepProps] = findRendererPropsByType(childrenProps, "step");
966
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { id: stepProps == null ? void 0 : stepProps.id, className: "dynamic-flow-step", children });
974
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { id: stepProps == null ? void 0 : stepProps.id, className: "dynamic-flow-step", children: [
975
+ children,
976
+ (subflow == null ? void 0 : subflow.presentation.type) === "modal" ? subflow.children : void 0
977
+ ] });
967
978
  }
968
979
  };
969
980
 
@@ -1276,6 +1287,29 @@ var externalComponentToProps = (component, rendererMapperProps) => {
1276
1287
  }, rendererMapperProps);
1277
1288
  };
1278
1289
 
1290
+ // src/renderers/mappers/formattedValueComponentToProps.ts
1291
+ var formattedValueComponentToProps = (component, rendererMapperProps) => {
1292
+ return __spreadValues(__spreadProps(__spreadValues({
1293
+ type: "formatted-value"
1294
+ }, pick(
1295
+ component,
1296
+ "format",
1297
+ "uid",
1298
+ "analyticsId",
1299
+ "control",
1300
+ "description",
1301
+ "help",
1302
+ "media",
1303
+ "tags",
1304
+ "title"
1305
+ // for now, we don't want to pass `value` down to the renderer to avoid the "WhateverComponent".
1306
+ // 'value',
1307
+ )), {
1308
+ validationState: getValidationState(component.errors, void 0),
1309
+ onChange: component.onChange.bind(component)
1310
+ }), rendererMapperProps);
1311
+ };
1312
+
1279
1313
  // src/renderers/mappers/formComponentToProps.ts
1280
1314
  var formComponentToProps = (component, rendererMapperProps) => {
1281
1315
  const childrenProps = component.getChildren().map((c) => componentToRendererProps(c, rendererMapperProps));
@@ -1688,11 +1722,18 @@ var rootComponentToProps = (rootComponent, rendererMapperProps) => {
1688
1722
  }
1689
1723
  return componentToRendererProps(child, rendererMapperProps);
1690
1724
  });
1725
+ const subflow = rootComponent.subflow ? {
1726
+ presentation: rootComponent.subflow.presentation,
1727
+ children: rendererMapperProps.render(
1728
+ componentToRendererProps(rootComponent.subflow, rendererMapperProps)
1729
+ )
1730
+ } : void 0;
1691
1731
  return __spreadValues({
1692
1732
  type: "root",
1693
1733
  uid: rootComponent.uid,
1694
1734
  children: childrenProps.map(rendererMapperProps.render),
1695
- childrenProps
1735
+ childrenProps,
1736
+ subflow
1696
1737
  }, rendererMapperProps);
1697
1738
  };
1698
1739
 
@@ -1883,6 +1924,19 @@ var uploadInputComponentToProps = (component, rendererMapperProps) => {
1883
1924
  });
1884
1925
  };
1885
1926
 
1927
+ // src/renderers/mappers/subflowComponentToRendererProps.ts
1928
+ var subflowComponentToRendererProps = (component, rendererMapperProps) => {
1929
+ return __spreadValues(__spreadProps(__spreadValues({
1930
+ uid: "subflow",
1931
+ type: "subflow"
1932
+ }, pick(component, "requestCache", "presentation", "initialRequest")), {
1933
+ onCancellation: component.onCancellation.bind(component),
1934
+ onCompletion: component.onCompletion.bind(component),
1935
+ onError: component.onError.bind(component),
1936
+ onEvent: component.onEvent.bind(component)
1937
+ }), rendererMapperProps);
1938
+ };
1939
+
1886
1940
  // src/renderers/mappers/componentToRendererProps.ts
1887
1941
  var componentToRendererProps = (component, mapperProps) => {
1888
1942
  if (isHiddenComponent(component)) {
@@ -1931,6 +1985,8 @@ var getComponentProps = (component, rendererMapperProps) => {
1931
1985
  return dividerComponentToProps(component, rendererMapperProps);
1932
1986
  case "external-confirmation":
1933
1987
  return externalComponentToProps(component, rendererMapperProps);
1988
+ case "formatted-value":
1989
+ return formattedValueComponentToProps(component, rendererMapperProps);
1934
1990
  case "form":
1935
1991
  return formComponentToProps(component, rendererMapperProps);
1936
1992
  case "heading":
@@ -1979,6 +2035,8 @@ var getComponentProps = (component, rendererMapperProps) => {
1979
2035
  return selectInputComponentToProps(component, rendererMapperProps);
1980
2036
  case "status-list":
1981
2037
  return statusListComponentToProps(component, rendererMapperProps);
2038
+ case "subflow":
2039
+ return subflowComponentToRendererProps(component, rendererMapperProps);
1982
2040
  case "tabs":
1983
2041
  return tabsComponentToProps(component, rendererMapperProps);
1984
2042
  case "text":
@@ -2003,7 +2061,7 @@ var getComponentAlertProps = (component, rendererMapperProps) => "alert" in comp
2003
2061
  markdown: component.alert.content
2004
2062
  }, rendererMapperProps) : null;
2005
2063
 
2006
- // src/useDynamicFlowCore.tsx
2064
+ // src/useDynamicFlowController.tsx
2007
2065
  var import_react3 = require("react");
2008
2066
  var import_react_intl7 = require("react-intl");
2009
2067
 
@@ -2016,16 +2074,17 @@ var getInputUpdateFunction = (updateComponent) => {
2016
2074
  };
2017
2075
 
2018
2076
  // src/domain/components/RootDomainComponent.ts
2019
- var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2077
+ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig, requestCache) => {
2020
2078
  const update = getInputUpdateFunction(updateComponent);
2021
2079
  const rootComponent = {
2022
2080
  type: "root",
2023
2081
  kind: "step",
2024
2082
  uid: "root",
2025
2083
  stepComponent: null,
2084
+ subflow: null,
2026
2085
  stepStack: [],
2027
- isNativeBackEnabled: backConfig.isNativeBackEnabled,
2028
- isFlowCancellable: backConfig.isFlowCancellable,
2086
+ backConfig,
2087
+ requestCache,
2029
2088
  _update(updateFn) {
2030
2089
  update(this, updateFn);
2031
2090
  },
@@ -2088,6 +2147,16 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2088
2147
  var _a;
2089
2148
  return (_a = this.stepStack[this.stepStack.length - 1]) != null ? _a : null;
2090
2149
  },
2150
+ addSubflow(subflow) {
2151
+ this._update((draft) => {
2152
+ draft.subflow = subflow;
2153
+ });
2154
+ },
2155
+ closeSubflow() {
2156
+ this._update((draft) => {
2157
+ draft.subflow = null;
2158
+ });
2159
+ },
2091
2160
  start() {
2092
2161
  var _a;
2093
2162
  (_a = this.getStep()) == null ? void 0 : _a.start();
@@ -2098,6 +2167,7 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2098
2167
  },
2099
2168
  updateStep(stepComponent) {
2100
2169
  var _a;
2170
+ this.closeSubflow();
2101
2171
  const shouldScroll = shouldScrollOnStepUpdate(stepComponent, this.getStep());
2102
2172
  this._update((draft) => {
2103
2173
  draft.stepStack = draft.stepStack.slice(0, -1);
@@ -2109,10 +2179,11 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2109
2179
  (_a = this.getStep()) == null ? void 0 : _a.start();
2110
2180
  },
2111
2181
  pushStep(stepComponent) {
2182
+ var _a;
2183
+ this.closeSubflow();
2112
2184
  const previousStep = this.getStep();
2113
2185
  const previousStepHasPolling = previousStep == null ? void 0 : previousStep.step.polling;
2114
2186
  this._update((draft) => {
2115
- var _a;
2116
2187
  switch (stepComponent.stackBehavior) {
2117
2188
  case "remove-previous":
2118
2189
  case "replace-current":
@@ -2127,9 +2198,9 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2127
2198
  }
2128
2199
  draft.stepStack.push(stepComponent);
2129
2200
  }
2130
- (_a = this.getStep()) == null ? void 0 : _a.start();
2131
2201
  });
2132
2202
  if (previousStep != null) {
2203
+ (_a = this.getStep()) == null ? void 0 : _a.start();
2133
2204
  scrollToTop == null ? void 0 : scrollToTop("instant");
2134
2205
  }
2135
2206
  },
@@ -2147,6 +2218,7 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2147
2218
  },
2148
2219
  navigateBack() {
2149
2220
  var _a;
2221
+ this.closeSubflow();
2150
2222
  if (this.stepStack.length === 1) {
2151
2223
  return;
2152
2224
  }
@@ -2159,7 +2231,7 @@ var createRootDomainComponent = (updateComponent, scrollToTop, backConfig) => {
2159
2231
  var _a, _b;
2160
2232
  const navigation = (_a = this.getStep()) == null ? void 0 : _a.step.navigation;
2161
2233
  const stepHasBehavior = Boolean((_b = navigation == null ? void 0 : navigation.back) != null ? _b : navigation == null ? void 0 : navigation.backButton);
2162
- return this.isFlowCancellable || this.stepStack.length > 1 && this.isNativeBackEnabled || stepHasBehavior;
2234
+ return this.backConfig.isFlowCancellable || this.stepStack.length > 1 && this.backConfig.isNativeBackEnabled || stepHasBehavior;
2163
2235
  }
2164
2236
  };
2165
2237
  return rootComponent;
@@ -2171,6 +2243,24 @@ var shouldScrollOnStepUpdate = (newStep, currentStep) => {
2171
2243
  return newStep.error != null && newStep.error !== currentStep.error;
2172
2244
  };
2173
2245
 
2246
+ // src/domain/components/utils/getRandomId.ts
2247
+ var getRandomId = () => Math.random().toString(36).substring(2);
2248
+
2249
+ // src/domain/components/SubflowDomainComponent.ts
2250
+ var createSubflowDomainComponent = (subflowProps, updateComponent) => {
2251
+ const update = getInputUpdateFunction(updateComponent);
2252
+ const subflowComponent = __spreadProps(__spreadValues({
2253
+ uid: `subflow-${getRandomId()}`,
2254
+ type: "subflow",
2255
+ kind: "layout"
2256
+ }, subflowProps), {
2257
+ _update(updateFn) {
2258
+ update(this, updateFn);
2259
+ }
2260
+ });
2261
+ return subflowComponent;
2262
+ };
2263
+
2174
2264
  // src/domain/components/ModalComponent.ts
2175
2265
  var createModalContentComponent = (modalProps, updateComponent) => {
2176
2266
  const update = getInputUpdateFunction(updateComponent);
@@ -2194,9 +2284,6 @@ var createModalContentComponent = (modalProps, updateComponent) => {
2194
2284
  return modalContentComponent;
2195
2285
  };
2196
2286
 
2197
- // src/domain/components/utils/getRandomId.ts
2198
- var getRandomId = () => Math.random().toString(36).substring(2);
2199
-
2200
2287
  // src/domain/components/AlertComponent.ts
2201
2288
  var createAlertComponent = (alertProps) => __spreadValues({
2202
2289
  type: "alert",
@@ -2219,6 +2306,12 @@ var getDomainLayerBehavior = ({ action, behavior: specBehavior }, stepActions, r
2219
2306
  };
2220
2307
  var normaliseBehavior = (behavior, stepActions) => {
2221
2308
  if ("type" in behavior) {
2309
+ if (behavior.type === "subflow") {
2310
+ return __spreadProps(__spreadValues({}, behavior), {
2311
+ onCompletion: behavior.onCompletion ? normaliseBehavior(behavior.onCompletion, stepActions) : void 0,
2312
+ onError: behavior.onError ? normaliseBehavior(behavior.onError, stepActions) : void 0
2313
+ });
2314
+ }
2222
2315
  return behavior;
2223
2316
  }
2224
2317
  if ("action" in behavior && behavior.action) {
@@ -3340,6 +3433,35 @@ var modalToComponent = (uid, { content, title }, mapperProps, schemaComponents)
3340
3433
  mapperProps.updateComponent
3341
3434
  );
3342
3435
 
3436
+ // src/domain/components/step/ExternalConfirmationComponent.ts
3437
+ var createExternalConfirmation = (uid, url, updateComponent) => {
3438
+ const update = getInputUpdateFunction(updateComponent);
3439
+ return {
3440
+ type: "external-confirmation",
3441
+ kind: "layout",
3442
+ uid,
3443
+ url,
3444
+ status: "initial",
3445
+ onSuccess() {
3446
+ update(this, (draft) => {
3447
+ draft.status = "success";
3448
+ });
3449
+ },
3450
+ onFailure() {
3451
+ if (this.status === "initial") {
3452
+ update(this, (draft) => {
3453
+ draft.status = "failure";
3454
+ });
3455
+ }
3456
+ },
3457
+ onCancel() {
3458
+ update(this, (draft) => {
3459
+ draft.status = "dismissed";
3460
+ });
3461
+ }
3462
+ };
3463
+ };
3464
+
3343
3465
  // src/utils/recursiveMerge.ts
3344
3466
  function recursiveMerge(valueA, valueB) {
3345
3467
  if (valueA === null) {
@@ -3379,67 +3501,16 @@ function mergeArrays(valueA, valueB) {
3379
3501
  );
3380
3502
  }
3381
3503
 
3382
- // src/flow/makeSubmissionRequest.ts
3383
- var makeSubmissionRequest = (action, model) => {
3384
- var _a, _b;
3385
- return [
3386
- (_a = action.url) != null ? _a : "",
3387
- {
3388
- method: (_b = action.method) != null ? _b : "POST",
3389
- body: makeRequestBody(action, model),
3390
- headers: { "Content-Type": "application/json" }
3391
- }
3392
- ];
3393
- };
3394
- var makeRequestBody = (action, model) => {
3395
- var _a, _b;
3396
- const method = (_a = action.method) != null ? _a : "POST";
3397
- if (method === "GET") {
3398
- return void 0;
3399
- }
3400
- const payload = recursiveMerge(model, (_b = action.data) != null ? _b : null);
3401
- return payload !== null ? JSON.stringify(payload) : null;
3402
- };
3504
+ // src/utils/component-utils.ts
3505
+ var getSubmittableData = async (components) => Promise.all(components.map(async (component) => component.getSubmittableValue())).then(
3506
+ (values) => values.reduce((acc, value) => recursiveMerge(acc, value), null)
3507
+ );
3508
+ var getSubmittableDataSync = (components) => components.map((component) => component.getSubmittableValueSync()).reduce((acc, value) => recursiveMerge(acc, value), null);
3509
+ var getLocalValues = (components) => components.map((component) => component.getLocalValue()).reduce((acc, value) => recursiveMerge(acc, value), null);
3403
3510
 
3404
- // src/domain/components/step/ExternalConfirmationComponent.ts
3405
- var createExternalConfirmation = (uid, url, updateComponent) => {
3406
- const update = getInputUpdateFunction(updateComponent);
3407
- return {
3408
- type: "external-confirmation",
3409
- kind: "layout",
3410
- uid,
3411
- url,
3412
- status: "initial",
3413
- onSuccess() {
3414
- update(this, (draft) => {
3415
- draft.status = "success";
3416
- });
3417
- },
3418
- onFailure() {
3419
- if (this.status === "initial") {
3420
- update(this, (draft) => {
3421
- draft.status = "failure";
3422
- });
3423
- }
3424
- },
3425
- onCancel() {
3426
- update(this, (draft) => {
3427
- draft.status = "dismissed";
3428
- });
3429
- }
3430
- };
3431
- };
3432
-
3433
- // src/utils/component-utils.ts
3434
- var getSubmittableData = async (components) => Promise.all(components.map(async (component) => component.getSubmittableValue())).then(
3435
- (values) => values.reduce((acc, value) => recursiveMerge(acc, value), null)
3436
- );
3437
- var getSubmittableDataSync = (components) => components.map((component) => component.getSubmittableValueSync()).reduce((acc, value) => recursiveMerge(acc, value), null);
3438
- var getLocalValues = (components) => components.map((component) => component.getLocalValue()).reduce((acc, value) => recursiveMerge(acc, value), null);
3439
-
3440
- // src/domain/components/step/StepDomainComponent.ts
3441
- var createStepComponent = (stepProps) => {
3442
- const _a = stepProps, { uid, stepPolling, stepRefreshAfter, updateComponent } = _a, rest = __objRest(_a, ["uid", "stepPolling", "stepRefreshAfter", "updateComponent"]);
3511
+ // src/domain/components/step/StepDomainComponent.ts
3512
+ var createStepComponent = (stepProps) => {
3513
+ const _a = stepProps, { uid, stepPolling, stepRefreshAfter, updateComponent } = _a, rest = __objRest(_a, ["uid", "stepPolling", "stepRefreshAfter", "updateComponent"]);
3443
3514
  const update = getInputUpdateFunction(updateComponent);
3444
3515
  const component = __spreadProps(__spreadValues({
3445
3516
  uid
@@ -3584,27 +3655,42 @@ var getStepRefreshAfter = ({
3584
3655
  };
3585
3656
 
3586
3657
  // src/domain/prefetching/request-cache.ts
3587
- var makeRequestCache = () => {
3588
- const cache = /* @__PURE__ */ new Map();
3589
- return {
3590
- has: (...requestParams) => {
3591
- return cache.has(makeKey(...requestParams));
3592
- },
3593
- get: (...requestParams) => {
3594
- return cache.get(makeKey(...requestParams));
3595
- },
3596
- delete: (...requestParams) => {
3597
- return cache.delete(makeKey(...requestParams));
3598
- },
3599
- set: (...[input, init, response]) => {
3600
- return cache.set(makeKey(input, init), response);
3658
+ var makeRequestCacheWithParent = (parent) => {
3659
+ const map = /* @__PURE__ */ new Map();
3660
+ const cache = {
3661
+ get: (requestParams) => {
3662
+ var _a;
3663
+ const key = makeKey(requestParams);
3664
+ const promise = (_a = map.get(key)) != null ? _a : parent == null ? void 0 : parent.get(requestParams);
3665
+ map.delete(key);
3666
+ return promise;
3601
3667
  },
3602
- clear: () => {
3603
- cache.clear();
3668
+ set: (requestParams, responsePromise) => {
3669
+ return map.set(makeKey(requestParams), responsePromise);
3604
3670
  }
3605
3671
  };
3672
+ return cache;
3606
3673
  };
3607
- var makeKey = (...requestParams) => {
3674
+ var makeRequestCache = (initialValues = []) => {
3675
+ const cache = makeRequestCacheWithParent(void 0);
3676
+ initialValues.forEach(([requestParams, responsePromise]) => {
3677
+ cache.set(requestParams, responsePromise);
3678
+ });
3679
+ return cache;
3680
+ };
3681
+ var normaliseRequestCache = (cache) => {
3682
+ if (cache === void 0) {
3683
+ return makeRequestCache();
3684
+ }
3685
+ if (isRequestCacheInstance(cache)) {
3686
+ return cache;
3687
+ }
3688
+ return makeRequestCache(cache);
3689
+ };
3690
+ var isRequestCacheInstance = (cache) => {
3691
+ return !cache || !Array.isArray(cache);
3692
+ };
3693
+ var makeKey = (requestParams) => {
3608
3694
  var _a, _b;
3609
3695
  const [input, init] = requestParams;
3610
3696
  const url = typeof input === "string" || input instanceof URL ? input.toString() : input.url;
@@ -4142,6 +4228,13 @@ function assertModalResponseBody(body) {
4142
4228
  "Incorrect response body in modal response. Expected an object satisfying the type { title?: string, components: Layout[] }."
4143
4229
  );
4144
4230
  }
4231
+ function assertSubflowResponseBody(body) {
4232
+ const { valid } = (0, import_spec.validateSubflowResponse)(body);
4233
+ if (valid) {
4234
+ return;
4235
+ }
4236
+ throw new Error("Incorrect response body in subflow response.");
4237
+ }
4145
4238
  function isErrorResponseBody(body) {
4146
4239
  return Boolean(
4147
4240
  isObject(body) && (body.refreshFormUrl || body.refreshUrl || body.validation || body.error || body.analytics)
@@ -5600,6 +5693,83 @@ var integerSchemaToComponent = (schemaMapperProps, mapperProps) => {
5600
5693
  );
5601
5694
  };
5602
5695
 
5696
+ // src/domain/components/FormattedValueComponent.ts
5697
+ var createFormattedValueComponent = (props, updateComponent) => {
5698
+ const {
5699
+ uid,
5700
+ schemaId,
5701
+ analyticsId,
5702
+ alert,
5703
+ control,
5704
+ description,
5705
+ errors,
5706
+ format,
5707
+ help,
5708
+ hidden,
5709
+ media,
5710
+ summariser,
5711
+ title,
5712
+ tags,
5713
+ value,
5714
+ schemaOnChange
5715
+ } = props;
5716
+ const update = getInputUpdateFunction(updateComponent);
5717
+ return {
5718
+ type: "formatted-value",
5719
+ kind: "input",
5720
+ uid,
5721
+ schemaId,
5722
+ analyticsId,
5723
+ alert,
5724
+ control,
5725
+ description,
5726
+ errors,
5727
+ format,
5728
+ help,
5729
+ hidden,
5730
+ media,
5731
+ title,
5732
+ tags,
5733
+ value,
5734
+ async getSubmittableValue() {
5735
+ return this.getSubmittableValueSync();
5736
+ },
5737
+ getSubmittableValueSync() {
5738
+ return this.getLocalValue();
5739
+ },
5740
+ getSummary() {
5741
+ return summariser(this.getLocalValue());
5742
+ },
5743
+ getLocalValue() {
5744
+ return this.value;
5745
+ },
5746
+ validate() {
5747
+ return true;
5748
+ },
5749
+ onChange(newValue) {
5750
+ update(this, (draft) => {
5751
+ draft.value = newValue;
5752
+ });
5753
+ void (schemaOnChange == null ? void 0 : schemaOnChange());
5754
+ }
5755
+ };
5756
+ };
5757
+
5758
+ // src/domain/mappers/schema/objectSchemaToComponent/objectSchemaToFormattedValueComponent.ts
5759
+ var objectSchemaToFormattedValueComponent = (schemaMapperProps, mapperProps) => {
5760
+ const { onBehavior } = mapperProps;
5761
+ const { schema } = schemaMapperProps;
5762
+ const { format } = schema;
5763
+ return createFormattedValueComponent(
5764
+ __spreadProps(__spreadValues({}, mapCommonSchemaProps(schemaMapperProps)), {
5765
+ format,
5766
+ value: schemaMapperProps.model,
5767
+ schemaOnChange: getSchemaOnChange(schema, onBehavior)
5768
+ }),
5769
+ mapperProps.updateComponent
5770
+ );
5771
+ };
5772
+
5603
5773
  // src/domain/components/MoneyInputComponent.ts
5604
5774
  var createMoneyInputComponent = (moneyInputProps, updateComponent) => {
5605
5775
  const _a = moneyInputProps, {
@@ -6013,11 +6183,17 @@ var createSelectInputComponent = (selectProps, updateComponent) => {
6013
6183
  if (updatedIndex === this.selectedIndex) {
6014
6184
  return;
6015
6185
  }
6016
- if (updatedIndex !== null && this.analyticsId) {
6017
- selectProps.trackEvent("OneOf Selected", {
6018
- oneOfId: this.analyticsId,
6019
- schemaId: this.children[updatedIndex].analyticsId
6186
+ if (updatedIndex !== null) {
6187
+ selectProps.trackEvent("OneOf Option Selected", {
6188
+ schema: this.analyticsId,
6189
+ selectedOption: this.children[updatedIndex].analyticsId
6020
6190
  });
6191
+ if (this.analyticsId) {
6192
+ selectProps.trackEvent("OneOf Selected", {
6193
+ oneOfId: this.analyticsId,
6194
+ schemaId: this.children[updatedIndex].analyticsId
6195
+ });
6196
+ }
6021
6197
  }
6022
6198
  this._update((draft) => {
6023
6199
  draft.errors = [];
@@ -6622,9 +6798,16 @@ var mapSchemaToComponent = (schemaMapperProps, mapperProps) => {
6622
6798
  return booleanSchemaToComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
6623
6799
  }
6624
6800
  if (isObjectSchema(schema)) {
6625
- if (schema.format === "money") {
6801
+ const { format } = schema;
6802
+ if (format === "money") {
6626
6803
  return objectSchemaToMoneyInputComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
6627
6804
  }
6805
+ if (format != null && Object.keys(schema.properties).length === 0) {
6806
+ return objectSchemaToFormattedValueComponent(
6807
+ __spreadProps(__spreadValues({}, schemaMapperProps), { schema: __spreadProps(__spreadValues({}, schema), { format }) }),
6808
+ mapperProps
6809
+ );
6810
+ }
6628
6811
  return objectSchemaToObjectComponent(__spreadProps(__spreadValues({}, schemaMapperProps), { schema }), mapperProps);
6629
6812
  }
6630
6813
  if (isIntegerSchema(schema)) {
@@ -6747,6 +6930,227 @@ var groupLayout = (acc, layout) => {
6747
6930
  var hasChildren = (component) => "components" in component;
6748
6931
  var hasColumns = (component) => "right" in component && "left" in component;
6749
6932
 
6933
+ // src/flow/handleErrorResponse.ts
6934
+ var handleErrorResponse = async (response, actionId, trackEvent) => {
6935
+ const body = await parseResponseBodyAsJsonElement(response.clone());
6936
+ if (isErrorResponseBody(body)) {
6937
+ const refreshUrl = body.refreshUrl || body.refreshFormUrl;
6938
+ const { error, validation, analytics } = body;
6939
+ trackEvent("Action Failed", __spreadProps(__spreadValues({}, analytics), { actionId, statusCode: response.status }));
6940
+ const errors = { error, validation };
6941
+ return refreshUrl ? { type: "refresh", body: { refreshUrl, errors } } : {
6942
+ type: "error",
6943
+ body: { errors, analytics },
6944
+ httpError: { statusCode: response.status }
6945
+ };
6946
+ }
6947
+ trackEvent("Action Failed", { actionId, statusCode: response.status });
6948
+ const errorMessage = await parseResponseBodyAsText(response);
6949
+ return {
6950
+ type: "error",
6951
+ httpError: {
6952
+ message: errorMessage || void 0,
6953
+ statusCode: response.status
6954
+ }
6955
+ };
6956
+ };
6957
+
6958
+ // src/flow/getResponseType.ts
6959
+ var responseTypes = ["step", "action", "exit", "modal", "subflow"];
6960
+ var getResponseType = async (response) => {
6961
+ assertResponseIsValid(response);
6962
+ const headerResponseType = getResponseTypeFromHeader(response);
6963
+ if (headerResponseType) {
6964
+ return headerResponseType;
6965
+ }
6966
+ const jsonBody = await parseResponseBodyAsJsonElement(response.clone());
6967
+ if (isObject(jsonBody) && jsonBody.action) {
6968
+ return "action";
6969
+ }
6970
+ return "step";
6971
+ };
6972
+ var getResponseTypeFromHeader = (response) => {
6973
+ var _a, _b;
6974
+ if ((_a = response.headers) == null ? void 0 : _a.has("X-Df-Response-Type")) {
6975
+ const type = response.headers.get("X-Df-Response-Type");
6976
+ assertDFResponseType(type);
6977
+ return type;
6978
+ }
6979
+ if ((_b = response.headers) == null ? void 0 : _b.has("X-Df-Exit")) {
6980
+ return "exit";
6981
+ }
6982
+ return void 0;
6983
+ };
6984
+ function assertDFResponseType(type) {
6985
+ if (!responseTypes.includes(type)) {
6986
+ throw new Error(
6987
+ "Unsupported X-Df-Response-Type. Allowed values are 'step', 'action', 'exit', 'error', 'modal', 'subflow'."
6988
+ );
6989
+ }
6990
+ }
6991
+
6992
+ // src/flow/makeSafeHttpClient.ts
6993
+ var makeSafeHttpClient = (httpClient) => async (...props) => {
6994
+ try {
6995
+ return await httpClient(...props);
6996
+ } catch (e) {
6997
+ return null;
6998
+ }
6999
+ };
7000
+
7001
+ // src/flow/executeRequest.ts
7002
+ var executeRequest = async (props) => {
7003
+ const { exit, request, requestCache, httpClient, trackEvent, logEvent } = props;
7004
+ const { url, method, body } = request;
7005
+ const response = await getCachedOrFetch(
7006
+ [
7007
+ url,
7008
+ {
7009
+ method,
7010
+ body: body ? JSON.stringify(body) : void 0,
7011
+ headers: { "Content-Type": "application/json" }
7012
+ }
7013
+ ],
7014
+ requestCache,
7015
+ httpClient
7016
+ );
7017
+ if (!response) {
7018
+ const extra = { errorMessage: "Network Error" };
7019
+ trackEvent("Request Failed", extra);
7020
+ logEvent("error", "Dynamic Flow - Request Failed Unexpectedly", extra);
7021
+ return { type: "error" };
7022
+ }
7023
+ if (!response.ok) {
7024
+ return handleErrorResponse(response, void 0, trackEvent);
7025
+ }
7026
+ const responseType = await getResponseType(response);
7027
+ const responseBody = await parseResponseBodyAsJsonElement(response.clone());
7028
+ if (exit) {
7029
+ return { type: "complete", result: responseBody };
7030
+ }
7031
+ switch (responseType) {
7032
+ case "step": {
7033
+ const etag = response.headers.get("etag") || null;
7034
+ assertStepResponseBody(responseBody);
7035
+ return { type: "replace-step", step: responseBody, etag };
7036
+ }
7037
+ case "exit": {
7038
+ return { type: "complete", result: responseBody };
7039
+ }
7040
+ case "action": {
7041
+ assertActionResponseBody(responseBody);
7042
+ return {
7043
+ type: "behavior",
7044
+ behavior: {
7045
+ type: "action",
7046
+ action: responseBody.action
7047
+ }
7048
+ };
7049
+ }
7050
+ case "subflow": {
7051
+ assertSubflowResponseBody(responseBody);
7052
+ return {
7053
+ type: "behavior",
7054
+ behavior: __spreadProps(__spreadValues({}, responseBody), {
7055
+ type: "subflow",
7056
+ onCompletion: responseBody.onCompletion ? normaliseBehavior(responseBody.onCompletion, []) : void 0,
7057
+ onError: responseBody.onError ? normaliseBehavior(responseBody.onError, []) : void 0
7058
+ })
7059
+ };
7060
+ }
7061
+ case "modal": {
7062
+ assertModalResponseBody(responseBody);
7063
+ return { type: "behavior", behavior: __spreadProps(__spreadValues({}, responseBody), { type: "modal" }) };
7064
+ }
7065
+ default: {
7066
+ throw new Error(`Unsupported response type: ${String(responseType)}`);
7067
+ }
7068
+ }
7069
+ };
7070
+ var getCachedOrFetch = async (requestParams, requestCache, httpClient) => {
7071
+ const cachedPromise = requestCache.get(requestParams);
7072
+ if (cachedPromise) {
7073
+ const cachedResponse = await cachedPromise;
7074
+ if (cachedResponse == null ? void 0 : cachedResponse.ok) {
7075
+ return cachedResponse;
7076
+ }
7077
+ }
7078
+ return makeSafeHttpClient(httpClient)(...requestParams);
7079
+ };
7080
+
7081
+ // src/flow/executeSubmission.ts
7082
+ var executeSubmission = async (props) => {
7083
+ const { httpClient, requestCache, trackEvent, logEvent } = props;
7084
+ const triggerAction = async (action, model, isInitial) => {
7085
+ var _a, _b;
7086
+ const { exit, url, result = null, id: actionId } = action;
7087
+ const trackSubmissionEvent = !isInitial ? trackEvent : () => {
7088
+ };
7089
+ trackSubmissionEvent("Action Triggered", { actionId });
7090
+ if (exit && !url) {
7091
+ trackSubmissionEvent("Action Succeeded", { actionId });
7092
+ return { type: "complete", result };
7093
+ }
7094
+ try {
7095
+ const command = await executeRequest({
7096
+ exit,
7097
+ request: createRequestFromAction(action, model),
7098
+ requestCache,
7099
+ httpClient,
7100
+ trackEvent: (name, properties) => {
7101
+ trackSubmissionEvent(name, __spreadProps(__spreadValues({}, properties), { actionId }));
7102
+ },
7103
+ logEvent
7104
+ });
7105
+ switch (command.type) {
7106
+ case "error": {
7107
+ trackSubmissionEvent("Action Failed", __spreadValues({
7108
+ actionId,
7109
+ statusCode: (_a = command.httpError) == null ? void 0 : _a.statusCode
7110
+ }, (_b = command.body) == null ? void 0 : _b.analytics));
7111
+ return command;
7112
+ }
7113
+ case "behavior": {
7114
+ if (command.behavior.type === "action") {
7115
+ trackSubmissionEvent("Action Succeeded", { actionId });
7116
+ return await executeRequest({
7117
+ request: createRequestFromAction(command.behavior.action, null),
7118
+ requestCache,
7119
+ httpClient,
7120
+ trackEvent,
7121
+ logEvent
7122
+ });
7123
+ }
7124
+ trackSubmissionEvent("Action Succeeded", { actionId });
7125
+ return command;
7126
+ }
7127
+ case "complete": {
7128
+ trackSubmissionEvent("Action Succeeded", { actionId });
7129
+ return __spreadProps(__spreadValues({}, command), { result: recursiveMerge(command.result, result) });
7130
+ }
7131
+ default: {
7132
+ trackSubmissionEvent("Action Succeeded", { actionId });
7133
+ return command;
7134
+ }
7135
+ }
7136
+ } catch (error) {
7137
+ const errorMessage = getErrorMessage(error);
7138
+ trackSubmissionEvent("Action Failed", { actionId, errorMessage });
7139
+ logEvent("error", "Dynamic Flow - Action Failed Unexpectedly", { actionId, errorMessage });
7140
+ throw error;
7141
+ }
7142
+ };
7143
+ return triggerAction(props.action, props.model, props.isInitial);
7144
+ };
7145
+ var createRequestFromAction = (action, model) => {
7146
+ var _a, _b, _c;
7147
+ return __spreadProps(__spreadValues({}, action), {
7148
+ url: (_a = action.url) != null ? _a : "",
7149
+ method: (_b = action.method) != null ? _b : "POST",
7150
+ body: action.method === "GET" ? void 0 : recursiveMerge(model, (_c = action.data) != null ? _c : null)
7151
+ });
7152
+ };
7153
+
6750
7154
  // src/domain/mappers/mapStepToComponent.ts
6751
7155
  var mapStepToComponent = (_a) => {
6752
7156
  var _b = _a, {
@@ -6765,7 +7169,7 @@ var mapStepToComponent = (_a) => {
6765
7169
  "onBehavior"
6766
7170
  ]);
6767
7171
  var _a2;
6768
- const { etag, step, stepLocalValue, logEvent, updateComponent } = restProps;
7172
+ const { etag, step, stepLocalValue, flowRequestCache, logEvent, updateComponent } = restProps;
6769
7173
  const {
6770
7174
  id,
6771
7175
  control,
@@ -6780,12 +7184,15 @@ var mapStepToComponent = (_a) => {
6780
7184
  title,
6781
7185
  tags
6782
7186
  } = step;
6783
- const submissionRequestsCache = makeRequestCache();
7187
+ const requestCache = makeRequestCacheWithParent(flowRequestCache);
6784
7188
  const submissionBehaviors = [];
6785
7189
  const registerSubmissionBehavior = (behavior) => {
6786
7190
  if (behavior.type === "action" && behavior.action.prefetch) {
6787
7191
  submissionBehaviors.push(behavior);
6788
7192
  }
7193
+ if (behavior.type === "subflow" && behavior.launchConfig.type === "dynamic" && behavior.launchConfig.request.prefetch) {
7194
+ submissionBehaviors.push(behavior);
7195
+ }
6789
7196
  };
6790
7197
  const back = mapBackNavigation(navigation, onBehavior, features.isEnabled("nativeBack"));
6791
7198
  const stepId = id || key;
@@ -6846,7 +7253,7 @@ var mapStepToComponent = (_a) => {
6846
7253
  title,
6847
7254
  tags,
6848
7255
  stackBehavior: (_a2 = navigation == null ? void 0 : navigation.stackBehavior) != null ? _a2 : "default",
6849
- submissionRequestsCache,
7256
+ requestCache,
6850
7257
  step,
6851
7258
  updateComponent,
6852
7259
  trackEvent,
@@ -6856,7 +7263,7 @@ var mapStepToComponent = (_a) => {
6856
7263
  httpClient: mapperProps.httpClient,
6857
7264
  model: stepComponent.getSubmittableValueSync(),
6858
7265
  behaviors: submissionBehaviors,
6859
- requestsCache: submissionRequestsCache
7266
+ requestCache
6860
7267
  });
6861
7268
  return stepComponent;
6862
7269
  };
@@ -6879,56 +7286,25 @@ var mapBackNavigation = (navigation, onBehavior, isNativeBackEnabled) => {
6879
7286
  } : void 0;
6880
7287
  };
6881
7288
  var executePrefetch = (props) => {
6882
- const {
6883
- httpClient,
6884
- behaviors: submissionBehaviors,
6885
- model,
6886
- requestsCache: submissionRequestsCache
6887
- } = props;
7289
+ const { httpClient, behaviors: submissionBehaviors, model, requestCache } = props;
6888
7290
  submissionBehaviors.forEach((behavior) => {
6889
- const requestParams = makeSubmissionRequest(behavior.action, model);
7291
+ const request = behavior.type === "action" ? createRequestFromAction(behavior.action, model) : behavior.launchConfig.request;
7292
+ const requestParams = [
7293
+ request.url,
7294
+ {
7295
+ body: JSON.stringify(request.body),
7296
+ method: request.method,
7297
+ headers: { "Content-Type": "application/json" }
7298
+ }
7299
+ ];
6890
7300
  try {
6891
7301
  const responsePromise = httpClient(...requestParams).catch(() => null);
6892
- submissionRequestsCache.set(...requestParams, responsePromise);
7302
+ requestCache.set(requestParams, responsePromise);
6893
7303
  } catch (e) {
6894
7304
  }
6895
7305
  });
6896
7306
  };
6897
7307
 
6898
- // src/flow/getResponseType.ts
6899
- var responseTypes = ["step", "action", "exit", "modal"];
6900
- var getResponseType = async (response) => {
6901
- assertResponseIsValid(response);
6902
- const headerResponseType = getResponseTypeFromHeader(response);
6903
- if (headerResponseType) {
6904
- return headerResponseType;
6905
- }
6906
- const jsonBody = await parseResponseBodyAsJsonElement(response.clone());
6907
- if (isObject(jsonBody) && jsonBody.action) {
6908
- return "action";
6909
- }
6910
- return "step";
6911
- };
6912
- var getResponseTypeFromHeader = (response) => {
6913
- var _a, _b;
6914
- if ((_a = response.headers) == null ? void 0 : _a.has("X-Df-Response-Type")) {
6915
- const type = response.headers.get("X-Df-Response-Type");
6916
- assertDFResponseType(type);
6917
- return type;
6918
- }
6919
- if ((_b = response.headers) == null ? void 0 : _b.has("X-Df-Exit")) {
6920
- return "exit";
6921
- }
6922
- return void 0;
6923
- };
6924
- function assertDFResponseType(type) {
6925
- if (!responseTypes.includes(type)) {
6926
- throw new Error(
6927
- "Unsupported X-Df-Response-Type. Allowed values are 'step', 'action', 'exit', 'error', 'modal'."
6928
- );
6929
- }
6930
- }
6931
-
6932
7308
  // src/flow/executePoll.ts
6933
7309
  var executePoll = async (props) => {
6934
7310
  const { errorBehavior, signal, url, httpClient, trackEvent } = props;
@@ -7022,113 +7398,62 @@ var executeRefresh = async (props) => {
7022
7398
  }
7023
7399
  };
7024
7400
 
7025
- // src/flow/makeSafeHttpClient.ts
7026
- var makeSafeHttpClient = (httpClient) => async (...props) => {
7027
- try {
7028
- return await httpClient(...props);
7029
- } catch (e) {
7030
- return null;
7031
- }
7032
- };
7033
-
7034
- // src/flow/executeSubmission.ts
7035
- var executeSubmission = async (props) => {
7036
- const { httpClient, requestCache, trackEvent, logEvent } = props;
7037
- const triggerAction = async (action, model, isInitial) => {
7038
- const { exit, url, result = null, id: actionId } = action;
7039
- const trackSubmissionEvent = !isInitial ? trackEvent : () => {
7040
- };
7041
- trackSubmissionEvent("Action Triggered", { actionId });
7042
- if (exit && !url) {
7043
- trackSubmissionEvent("Action Succeeded", { actionId });
7044
- return { type: "complete", result };
7045
- }
7046
- const requestParams = makeSubmissionRequest(action, model);
7047
- const response = await getCachedOrFetch(requestParams, requestCache, httpClient);
7048
- if (!response) {
7049
- const extra = { actionId, errorMessage: "Network Error" };
7050
- trackEvent("Action Failed", extra);
7051
- logEvent("error", "Dynamic Flow - Action Failed Unexpectedly", extra);
7052
- return { type: "error" };
7053
- }
7054
- if (!response.ok) {
7055
- return handleErrorResponse(response, actionId);
7056
- }
7057
- try {
7058
- const responseType = await getResponseType(response);
7059
- const body = await parseResponseBodyAsJsonElement(response);
7060
- if (exit) {
7061
- return { type: "complete", result: recursiveMerge(body, result) };
7062
- }
7063
- switch (responseType) {
7064
- case "step": {
7065
- const etag = response.headers.get("etag") || null;
7066
- assertStepResponseBody(body);
7067
- trackSubmissionEvent("Action Succeeded", { actionId });
7068
- return { type: "replace-step", step: body, etag };
7069
- }
7070
- case "exit": {
7071
- trackSubmissionEvent("Action Succeeded", { actionId });
7072
- return { type: "complete", result: recursiveMerge(body, result) };
7073
- }
7074
- case "action": {
7075
- assertActionResponseBody(body);
7076
- trackSubmissionEvent("Action Succeeded", { actionId });
7077
- return await triggerAction(body.action, null, false);
7078
- }
7079
- case "modal": {
7080
- assertModalResponseBody(body);
7081
- trackSubmissionEvent("Action Succeeded", { actionId });
7082
- return { type: "behavior", behavior: __spreadProps(__spreadValues({}, body), { type: "modal" }) };
7083
- }
7084
- default: {
7085
- throw new Error(`Unsupported response type: ${String(responseType)}`);
7086
- }
7401
+ // src/getSubflowCallbacks.ts
7402
+ var getSubflowCallbacks = ({
7403
+ behavior,
7404
+ close,
7405
+ restart,
7406
+ onBehavior,
7407
+ onError,
7408
+ onEvent
7409
+ }) => {
7410
+ const {
7411
+ onCompletion: onCompletionBehavior,
7412
+ onError: onErrorBehavior,
7413
+ referrerId,
7414
+ resultKey
7415
+ } = behavior;
7416
+ return {
7417
+ onCompletion: (result) => {
7418
+ var _a;
7419
+ restart();
7420
+ if (!onCompletionBehavior) {
7421
+ close();
7422
+ return;
7087
7423
  }
7088
- } catch (error) {
7089
- const errorMessage = getErrorMessage(error);
7090
- trackSubmissionEvent("Action Failed", { actionId, errorMessage });
7091
- logEvent("error", "Dynamic Flow - Action Failed Unexpectedly", { actionId, errorMessage });
7092
- throw error;
7093
- }
7094
- };
7095
- const handleErrorResponse = async (response, actionId) => {
7096
- const body = await parseResponseBodyAsJsonElement(response.clone());
7097
- if (isErrorResponseBody(body)) {
7098
- const refreshUrl = body.refreshUrl || body.refreshFormUrl;
7099
- const { error, validation, analytics } = body;
7100
- trackEvent("Action Failed", __spreadProps(__spreadValues({}, analytics), { actionId, statusCode: response.status }));
7101
- const errors = { error, validation };
7102
- return refreshUrl ? { type: "refresh", body: { refreshUrl, errors } } : {
7103
- type: "error",
7104
- body: { errors, analytics },
7105
- httpError: { statusCode: response.status }
7106
- };
7107
- }
7108
- trackEvent("Action Failed", { actionId, statusCode: response.status });
7109
- const errorMessage = await parseResponseBodyAsText(response);
7110
- return {
7111
- type: "error",
7112
- httpError: {
7113
- message: errorMessage || void 0,
7114
- statusCode: response.status
7424
+ if (onCompletionBehavior.type === "action") {
7425
+ const newActionData = recursiveMerge(
7426
+ (_a = onCompletionBehavior.action.data) != null ? _a : null,
7427
+ resultKey ? { [resultKey]: result } : result
7428
+ );
7429
+ void onBehavior(__spreadProps(__spreadValues({}, onCompletionBehavior), {
7430
+ action: __spreadProps(__spreadValues({}, onCompletionBehavior.action), { data: newActionData })
7431
+ }));
7432
+ return;
7115
7433
  }
7116
- };
7117
- };
7118
- return triggerAction(props.action, props.model, props.isInitial);
7119
- };
7120
- var getCachedOrFetch = async (requestParams, requestCache, httpClient) => {
7121
- if (requestCache == null ? void 0 : requestCache.has(...requestParams)) {
7122
- const cachedPromise = requestCache.get(...requestParams);
7123
- requestCache.delete(...requestParams);
7124
- if (cachedPromise) {
7125
- const cachedResponse = await cachedPromise;
7126
- if (cachedResponse == null ? void 0 : cachedResponse.ok) {
7127
- return cachedResponse;
7434
+ void onBehavior(onCompletionBehavior);
7435
+ close();
7436
+ },
7437
+ onError: (error, status) => {
7438
+ if (!onErrorBehavior) {
7439
+ onError(error, {}, status);
7440
+ close();
7441
+ return;
7128
7442
  }
7443
+ restart();
7444
+ void onBehavior(onErrorBehavior);
7445
+ close();
7446
+ },
7447
+ onEvent: (name, properties) => {
7448
+ onEvent(name, __spreadValues({
7449
+ referrerId
7450
+ }, properties));
7451
+ },
7452
+ onCancellation: () => {
7453
+ restart();
7454
+ close();
7129
7455
  }
7130
- }
7131
- return makeSafeHttpClient(httpClient)(...requestParams);
7456
+ };
7132
7457
  };
7133
7458
 
7134
7459
  // src/renderers/getSchemaErrorMessageFunction.ts
@@ -7358,19 +7683,18 @@ function useStableCallback(handler) {
7358
7683
  return (0, import_react2.useCallback)((...args) => ref.current ? ref.current(...args) : null, []);
7359
7684
  }
7360
7685
 
7361
- // src/useDynamicFlowCore.tsx
7362
- function useDynamicFlowCore(props) {
7363
- const _a = props, { flowId, initialAction, initialStep, features } = _a, rest = __objRest(_a, ["flowId", "initialAction", "initialStep", "features"]);
7686
+ // src/useDynamicFlowController.tsx
7687
+ function useDynamicFlowController(props) {
7688
+ const _a = props, { flowId, initialAction, initialStep, features, scrollToTop } = _a, rest = __objRest(_a, ["flowId", "initialAction", "initialStep", "features", "scrollToTop"]);
7364
7689
  const httpClient = useStableCallback(rest.httpClient);
7365
7690
  const onCancellation = useStableCallback(rest.onCancellation);
7366
7691
  const onCompletion = useStableCallback(rest.onCompletion);
7367
- const onCopy = useStableCallback(props.onCopy);
7368
- const onValueChange = useStableCallback(props.onValueChange);
7369
- const onLink = useStableCallback(props.onLink);
7692
+ const onCopy = useStableCallback(rest.onCopy);
7693
+ const onLink = useStableCallback(rest.onLink);
7370
7694
  const onError = useStableCallback(rest.onError);
7371
7695
  const onEvent = useStableCallback(rest.onEvent);
7372
7696
  const onLog = useStableCallback(rest.onLog);
7373
- const scrollToTop = useStableCallback(props.scrollToTop);
7697
+ const onValueChange = useStableCallback(rest.onValueChange);
7374
7698
  const { formatMessage, locale } = (0, import_react_intl7.useIntl)();
7375
7699
  const getErrorMessageFunctions = (0, import_react3.useMemo)(
7376
7700
  () => getSchemaErrorMessageFunction(formatMessage, locale),
@@ -7378,10 +7702,15 @@ function useDynamicFlowCore(props) {
7378
7702
  );
7379
7703
  const rerender = useRerender();
7380
7704
  const rootComponentRef = (0, import_react3.useRef)(
7381
- createRootDomainComponent(rerender, scrollToTop, {
7382
- isNativeBackEnabled: features.isEnabled("nativeBack"),
7383
- isFlowCancellable: Boolean(rest.onCancellation)
7384
- })
7705
+ createRootDomainComponent(
7706
+ rerender,
7707
+ scrollToTop,
7708
+ {
7709
+ isNativeBackEnabled: features.isEnabled("nativeBack"),
7710
+ isFlowCancellable: Boolean(rest.onCancellation)
7711
+ },
7712
+ normaliseRequestCache(rest.requestCache)
7713
+ )
7385
7714
  );
7386
7715
  const stepCount = (0, import_react3.useRef)(0);
7387
7716
  const abortControllerRef = (0, import_react3.useRef)(new AbortController());
@@ -7390,12 +7719,15 @@ function useDynamicFlowCore(props) {
7390
7719
  abortControllerRef.current = new AbortController();
7391
7720
  return abortControllerRef.current.signal;
7392
7721
  };
7722
+ const hasTriggeredInitialAction = (0, import_react3.useRef)(false);
7393
7723
  (0, import_react3.useEffect)(() => {
7394
7724
  trackCoreEvent("Initiated");
7395
- if (!initialStep && initialAction) {
7725
+ if (!hasTriggeredInitialAction.current && !initialStep && initialAction) {
7396
7726
  rootComponentRef.current.setLoadingState("submitting");
7727
+ hasTriggeredInitialAction.current = true;
7397
7728
  void onAction(__spreadValues({ method: "GET" }, initialAction), null);
7398
7729
  }
7730
+ rootComponentRef.current.start();
7399
7731
  return () => {
7400
7732
  rootComponentRef.current.stop();
7401
7733
  };
@@ -7408,6 +7740,7 @@ function useDynamicFlowCore(props) {
7408
7740
  const component = createStepComponent2(newStep, etag, null);
7409
7741
  if (component) {
7410
7742
  rootComponentRef.current.pushStep(component);
7743
+ rootComponentRef.current.setLoadingState("idle");
7411
7744
  }
7412
7745
  },
7413
7746
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -7422,12 +7755,14 @@ function useDynamicFlowCore(props) {
7422
7755
  );
7423
7756
  if (component) {
7424
7757
  rootComponentRef.current.updateStep(component);
7758
+ rootComponentRef.current.setLoadingState("idle");
7425
7759
  }
7426
7760
  }, []);
7427
7761
  const getMapperProps = () => ({
7428
7762
  uid: `${rootComponentRef.current.uid}:${stepCount.current}`,
7429
7763
  loadingState: "idle",
7430
7764
  updateComponent: () => rerender(),
7765
+ flowRequestCache: rootComponentRef.current.requestCache,
7431
7766
  getErrorMessageFunctions,
7432
7767
  trackEvent,
7433
7768
  logEvent,
@@ -7466,7 +7801,8 @@ function useDynamicFlowCore(props) {
7466
7801
  const stepId = (_b = (_a2 = step == null ? void 0 : step.id) != null ? _a2 : step == null ? void 0 : step.key) != null ? _b : null;
7467
7802
  const analytics = step == null ? void 0 : step.analytics;
7468
7803
  const metadata = __spreadValues(__spreadValues(__spreadValues(__spreadValues({
7469
- flowId
7804
+ flowId,
7805
+ integrationId: flowId
7470
7806
  }, step ? { stepCount: stepCount.current } : {}), stepId !== null ? { stepId } : {}), analytics), properties);
7471
7807
  try {
7472
7808
  onEvent == null ? void 0 : onEvent(`Dynamic Flow - ${eventName}`, __spreadValues({}, metadata));
@@ -7507,7 +7843,7 @@ function useDynamicFlowCore(props) {
7507
7843
  onCancellation();
7508
7844
  }, []);
7509
7845
  const onBehavior = (0, import_react3.useCallback)(async (behavior) => {
7510
- var _a2;
7846
+ var _a2, _b, _c;
7511
7847
  switch (behavior.type) {
7512
7848
  case "back": {
7513
7849
  if (behavior.action) {
@@ -7598,6 +7934,33 @@ function useDynamicFlowCore(props) {
7598
7934
  case "dismiss":
7599
7935
  rootComponentRef.current.dismissModal();
7600
7936
  break;
7937
+ case "subflow": {
7938
+ rootComponentRef.current.setLoadingState("submitting");
7939
+ const { launchConfig } = behavior;
7940
+ const { request, presentation } = launchConfig;
7941
+ const callbacks = getSubflowCallbacks({
7942
+ behavior,
7943
+ close: () => rootComponentRef.current.closeSubflow(),
7944
+ onBehavior,
7945
+ onError: closeWithError,
7946
+ onEvent,
7947
+ restart: () => {
7948
+ rootComponentRef.current.setLoadingState("idle");
7949
+ rootComponentRef.current.start();
7950
+ }
7951
+ });
7952
+ const component = createSubflowDomainComponent(
7953
+ __spreadProps(__spreadValues({}, callbacks), {
7954
+ initialRequest: request,
7955
+ requestCache: (_c = (_b = rootComponentRef.current.getStep()) == null ? void 0 : _b.requestCache) != null ? _c : rootComponentRef.current.requestCache,
7956
+ presentation
7957
+ }),
7958
+ rerender
7959
+ );
7960
+ rootComponentRef.current.stop();
7961
+ rootComponentRef.current.addSubflow(component);
7962
+ break;
7963
+ }
7601
7964
  case "none":
7602
7965
  break;
7603
7966
  }
@@ -7606,16 +7969,16 @@ function useDynamicFlowCore(props) {
7606
7969
  }, []);
7607
7970
  const onAction = (0, import_react3.useCallback)(
7608
7971
  async (action, model) => {
7609
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i;
7972
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
7610
7973
  try {
7611
7974
  rootComponentRef.current.setLoadingState("submitting");
7612
7975
  const command = await executeSubmission({
7613
7976
  action,
7614
7977
  model,
7615
7978
  isInitial: !rootComponentRef.current.hasStep(),
7616
- requestCache: (_a2 = rootComponentRef.current.getStep()) == null ? void 0 : _a2.submissionRequestsCache,
7979
+ requestCache: (_b = (_a2 = rootComponentRef.current.getStep()) == null ? void 0 : _a2.requestCache) != null ? _b : rootComponentRef.current.requestCache,
7617
7980
  httpClient,
7618
- trackEvent: trackCoreEvent,
7981
+ trackEvent,
7619
7982
  logEvent
7620
7983
  });
7621
7984
  switch (command.type) {
@@ -7627,6 +7990,7 @@ function useDynamicFlowCore(props) {
7627
7990
  }
7628
7991
  case "replace-step": {
7629
7992
  const isFirstStep = !rootComponentRef.current.hasStep();
7993
+ rootComponentRef.current.closeSubflow();
7630
7994
  createStep(command.step, command.etag);
7631
7995
  trackCoreEvent("Step Shown", { isFirstStep });
7632
7996
  break;
@@ -7634,7 +7998,7 @@ function useDynamicFlowCore(props) {
7634
7998
  case "error": {
7635
7999
  rootComponentRef.current.setLoadingState("idle");
7636
8000
  const genericErrorMessage = getErrorMessageFunctions().genericErrorWithRetry();
7637
- const errors = (_c = (_b = command.body) == null ? void 0 : _b.errors) != null ? _c : { error: genericErrorMessage };
8001
+ const errors = (_d = (_c = command.body) == null ? void 0 : _c.errors) != null ? _d : { error: genericErrorMessage };
7638
8002
  const currentStep = rootComponentRef.current.getStep();
7639
8003
  if (currentStep) {
7640
8004
  updateStep(
@@ -7648,16 +8012,16 @@ function useDynamicFlowCore(props) {
7648
8012
  external: void 0
7649
8013
  // and no external, to avoid retriggering it
7650
8014
  }),
7651
- (_e = (_d = rootComponentRef.current.getStep()) == null ? void 0 : _d.etag) != null ? _e : null
8015
+ (_f = (_e = rootComponentRef.current.getStep()) == null ? void 0 : _e.etag) != null ? _f : null
7652
8016
  );
7653
8017
  } else {
7654
- 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";
8018
+ 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";
7655
8019
  closeWithError(
7656
8020
  new Error(errorMessage, {
7657
8021
  cause: `method: ${action.method}, url: ${action.url}`
7658
8022
  }),
7659
8023
  {},
7660
- (_i = command.httpError) == null ? void 0 : _i.statusCode
8024
+ (_j = command.httpError) == null ? void 0 : _j.statusCode
7661
8025
  );
7662
8026
  }
7663
8027
  break;
@@ -7753,25 +8117,25 @@ function useDynamicFlowCore(props) {
7753
8117
  []
7754
8118
  );
7755
8119
  const hasMappedInitialStep = (0, import_react3.useRef)(false);
7756
- if (!hasMappedInitialStep.current && initialStep && !initialAction) {
8120
+ if (!hasMappedInitialStep.current && initialStep) {
7757
8121
  createStep(initialStep, null);
7758
8122
  trackCoreEvent("Step Shown", { isFirstStep: true });
7759
8123
  hasMappedInitialStep.current = true;
7760
8124
  }
7761
- return { rootComponent: rootComponentRef.current };
8125
+ return {
8126
+ rootComponent: rootComponentRef.current,
8127
+ cancel: closeWithCancellation
8128
+ };
7762
8129
  }
7763
8130
  var useRerender = () => {
7764
8131
  const [, setState] = (0, import_react3.useState)({});
7765
8132
  return (0, import_react3.useCallback)(() => setState({}), []);
7766
8133
  };
7767
8134
 
7768
- // src/utils/normalise-flow-id.ts
7769
- var normaliseFlowId = (flowId) => flowId.toLowerCase().replace(/[^a-z-]/g, "-");
7770
-
7771
- // src/utils/scrollToTop.ts
7772
- var getScrollToTop = (normalisedFlowId, className3) => (behavior) => {
8135
+ // src/utils/getScrollToTop.ts
8136
+ var getScrollToTop = (normalisedFlowId, className2) => (behavior) => {
7773
8137
  var _a;
7774
- const element = document.querySelector(`div#${normalisedFlowId}.${className3}`);
8138
+ const element = document.querySelector(`div#${normalisedFlowId}.${className2}`);
7775
8139
  if (!element || !window) {
7776
8140
  return;
7777
8141
  }
@@ -7782,10 +8146,13 @@ var getScrollToTop = (normalisedFlowId, className3) => (behavior) => {
7782
8146
  }
7783
8147
  };
7784
8148
 
7785
- // src/DynamicFlowCore.tsx
8149
+ // src/utils/normalise-flow-id.ts
8150
+ var normaliseFlowId = (flowId) => flowId.toLowerCase().replace(/[^a-z-]/g, "-");
8151
+
8152
+ // src/useDynamicFlow.tsx
7786
8153
  var import_jsx_runtime6 = require("react/jsx-runtime");
7787
8154
  var className = "dynamic-flow";
7788
- function DynamicFlowCore(props) {
8155
+ function useDynamicFlow(props) {
7789
8156
  var _a;
7790
8157
  const { flowId, renderers, httpClient, onEvent, onError, onLog } = props;
7791
8158
  const normalisedFlowId = normaliseFlowId(flowId);
@@ -7797,7 +8164,10 @@ function DynamicFlowCore(props) {
7797
8164
  var _a2;
7798
8165
  return new FeatureFlags((_a2 = props.features) != null ? _a2 : {});
7799
8166
  }, []);
7800
- const { rootComponent } = useDynamicFlowCore(__spreadProps(__spreadValues({}, props), { features, scrollToTop }));
8167
+ const { rootComponent, cancel } = useDynamicFlowController(__spreadProps(__spreadValues({}, props), {
8168
+ features,
8169
+ scrollToTop
8170
+ }));
7801
8171
  const render = (0, import_react4.useMemo)(
7802
8172
  () => getRenderFunction([CoreRootRenderer, CoreContainerRenderer, ...renderers]),
7803
8173
  [renderers]
@@ -7810,95 +8180,101 @@ function DynamicFlowCore(props) {
7810
8180
  }),
7811
8181
  stepLoadingState: rootComponent.getLoadingState()
7812
8182
  });
7813
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
7814
- ErrorBoundary_default,
7815
- {
7816
- onError: (error) => {
7817
- onEvent == null ? void 0 : onEvent("Dynamic Flow - Failed", { error });
7818
- onError == null ? void 0 : onError(error);
7819
- onLog == null ? void 0 : onLog("error", "Dynamic Flow - ErrorBoundary", { errorMessage: getErrorMessage(error) });
7820
- },
7821
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { id: normalisedFlowId, className, children: render(tree) })
7822
- }
7823
- );
8183
+ return {
8184
+ controller: {
8185
+ getSubmittableValue: async () => rootComponent.getSubmittableValue(),
8186
+ validate: () => rootComponent.validate(),
8187
+ cancel
8188
+ },
8189
+ view: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
8190
+ ErrorBoundary_default,
8191
+ {
8192
+ onError: (error) => {
8193
+ onEvent == null ? void 0 : onEvent("Dynamic Flow - Failed", { error });
8194
+ onError == null ? void 0 : onError(error);
8195
+ onLog == null ? void 0 : onLog("error", "Dynamic Flow - ErrorBoundary", {
8196
+ errorMessage: getErrorMessage(error)
8197
+ });
8198
+ },
8199
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { id: normalisedFlowId, className, children: render(tree) })
8200
+ }
8201
+ )
8202
+ };
7824
8203
  }
7825
8204
 
7826
- // src/DynamicFormCore.tsx
8205
+ // src/useDynamicFlowModal.tsx
7827
8206
  var import_react5 = require("react");
7828
-
7829
- // src/utils/openLinkInNewTab.tsx
7830
- var openLinkInNewTab = (url) => {
7831
- var _a;
7832
- try {
7833
- const w = (_a = window == null ? void 0 : window.open) == null ? void 0 : _a.call(window, url, "_blank");
7834
- return Boolean(w);
7835
- } catch (e) {
7836
- return false;
7837
- }
7838
- };
7839
-
7840
- // src/DynamicFormCore.tsx
7841
- var import_jsx_runtime7 = require("react/jsx-runtime");
7842
- var className2 = "dynamic-flow";
7843
- var DynamicFormCore = (0, import_react5.forwardRef)(function DynamicFormCore2(props, ref) {
7844
- var _a;
7845
- const {
7846
- onCompletion = () => {
8207
+ var useDynamicFlowModal = (props) => {
8208
+ const _a = props, { renderers, onCompletion, onError, onCancellation, onEvent, onLink } = _a, rest = __objRest(_a, ["renderers", "onCompletion", "onError", "onCancellation", "onEvent", "onLink"]);
8209
+ const [state, setState] = (0, import_react5.useState)({ type: "initial" });
8210
+ const df = useDynamicFlow(__spreadProps(__spreadValues({}, rest), {
8211
+ onCompletion: (result) => {
8212
+ setState({ type: "completed", result });
8213
+ },
8214
+ onError: (error, status) => {
8215
+ setState({ type: "error", error, status });
8216
+ },
8217
+ onEvent: (name, properties) => {
8218
+ if (name === "Dynamic Flow - Step Shown") {
8219
+ setState({ type: "in-progress" });
8220
+ }
8221
+ onEvent == null ? void 0 : onEvent(name, properties);
7847
8222
  },
7848
- httpClient,
7849
- onEvent,
7850
- onError,
7851
- onLink = openLinkInNewTab,
7852
- renderers
7853
- } = props;
7854
- const normalisedFlowId = normaliseFlowId(props.flowId);
7855
- const scrollToTop = (0, import_react5.useMemo)(
7856
- () => getScrollToTop(normalisedFlowId, className2),
7857
- [normalisedFlowId]
7858
- );
7859
- const features = (0, import_react5.useMemo)(() => {
7860
- var _a2;
7861
- return new FeatureFlags((_a2 = props.features) != null ? _a2 : {});
7862
- }, []);
7863
- const { rootComponent } = useDynamicFlowCore(__spreadProps(__spreadValues({
7864
- onCompletion
7865
- }, props), {
7866
- features,
7867
- scrollToTop,
7868
- onLink
8223
+ renderers,
8224
+ onLink: onLink != null ? onLink : (() => true)
7869
8225
  }));
7870
- (0, import_react5.useImperativeHandle)(
7871
- ref,
7872
- () => ({
7873
- getValue: async () => {
7874
- var _a2;
7875
- return (_a2 = await rootComponent.getSubmittableValue()) != null ? _a2 : null;
7876
- },
7877
- validate: () => rootComponent.validate()
7878
- }),
7879
- // eslint-disable-next-line react-hooks/exhaustive-deps
7880
- []
7881
- );
7882
- const render = (0, import_react5.useMemo)(
7883
- () => getRenderFunction([CoreRootRenderer, CoreContainerRenderer, ...renderers]),
7884
- [renderers]
7885
- );
7886
- const tree = componentToRendererProps(rootComponent, {
7887
- features,
7888
- render,
7889
- httpClient,
7890
- trackEvent: (_a = rootComponent.getTrackEvent()) != null ? _a : (() => {
7891
- }),
7892
- stepLoadingState: rootComponent.getLoadingState()
7893
- });
7894
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
7895
- ErrorBoundary_default,
7896
- {
7897
- onError: (error) => {
7898
- onEvent == null ? void 0 : onEvent("Dynamic Flow - Failed");
7899
- onError(error);
7900
- },
7901
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { id: normalisedFlowId, className: className2, children: render(tree) })
8226
+ const onUnmount = () => {
8227
+ switch (state.type) {
8228
+ case "completed":
8229
+ onCompletion(state.result);
8230
+ break;
8231
+ case "error":
8232
+ onError(state.error, state.status);
8233
+ break;
8234
+ case "initial":
8235
+ case "in-progress":
8236
+ case "cancelled": {
8237
+ df.controller.cancel();
8238
+ onCancellation == null ? void 0 : onCancellation();
8239
+ }
7902
8240
  }
7903
- );
7904
- });
8241
+ };
8242
+ const onClose = () => {
8243
+ setState({ type: "cancelled" });
8244
+ };
8245
+ return __spreadProps(__spreadValues({}, df), {
8246
+ modal: { body: df.view, open: state.type === "in-progress", onClose, onUnmount }
8247
+ });
8248
+ };
8249
+
8250
+ // src/DynamicFlowCore.tsx
8251
+ function DynamicFlowCore(props) {
8252
+ const df = useDynamicFlow(props);
8253
+ return df.view;
8254
+ }
8255
+
8256
+ // src/domain/features/eventNames.ts
8257
+ var eventNames = [
8258
+ "Initiated",
8259
+ "Succeeded",
8260
+ "Failed",
8261
+ "Cancelled",
8262
+ "Step Shown",
8263
+ "Action Triggered",
8264
+ "Action Succeeded",
8265
+ "Action Aborted",
8266
+ "Action Failed",
8267
+ "Refresh Triggered",
8268
+ "Refresh Succeeded",
8269
+ "Refresh Aborted",
8270
+ "Refresh Failed",
8271
+ "OneOf Selected",
8272
+ "OneOf Option Selected",
8273
+ "PersistAsync Triggered",
8274
+ "PersistAsync Succeeded",
8275
+ "PersistAsync Failed",
8276
+ "Polling Failed",
8277
+ "ValidationAsync Triggered",
8278
+ "ValidationAsync Succeeded",
8279
+ "ValidationAsync Failed"
8280
+ ];