@wise/dynamic-flow-client-internal 5.30.1-experimental-1e1196b → 5.31.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.
- package/build/dynamicFlow/DynamicFlow.js +11 -0
- package/build/dynamicFlow/DynamicFlowModal.js +21 -0
- package/build/dynamicFlow/DynamicFlowWiseProps.js +1 -0
- package/build/dynamicFlow/DynamicFlowWithRef.js +19 -0
- package/build/dynamicFlow/context-menu/useContextMenu.js +33 -0
- package/build/dynamicFlow/context-menu/useDFContextMenu.js +135 -0
- package/build/dynamicFlow/context-menu/useDFContextMenu.test.js +101 -0
- package/build/dynamicFlow/getMergedRenderers.js +36 -0
- package/build/dynamicFlow/messages.js +13 -0
- package/build/dynamicFlow/renderers.js +10 -0
- package/build/dynamicFlow/telemetry/app-version.js +4 -0
- package/build/dynamicFlow/telemetry/dispatchAnalyticsEvent.js +8 -0
- package/build/dynamicFlow/telemetry/getLogEvent.js +22 -0
- package/build/dynamicFlow/telemetry/getTrackEvent.js +39 -0
- package/build/dynamicFlow/telemetry/index.js +2 -0
- package/build/dynamicFlow/useCreateSnackBar.js +9 -0
- package/build/dynamicFlow/useOnCopy.js +16 -0
- package/build/dynamicFlow/useWiseHttpClient.js +24 -0
- package/build/dynamicFlow/useWiseToCoreProps.js +42 -0
- package/build/i18n/en.json +0 -2
- package/build/i18n/index.js +43 -0
- package/build/index.js +6 -0
- package/build/main.css +0 -25
- package/build/main.js +22 -248
- package/build/main.mjs +14 -240
- package/build/stories/ButtonLoader.story.js +109 -0
- package/build/stories/ContainerQueries.story.js +74 -0
- package/build/stories/DynamicFlow.story.js +37 -0
- package/build/stories/DynamicFlowWithRef.story.js +72 -0
- package/build/stories/Editable.story.js +58 -0
- package/build/stories/Initialisation.story.js +33 -0
- package/build/stories/PinnedButtons.story.js +94 -0
- package/build/stories/SCAIntegration.story.js +67 -0
- package/build/stories/utils/fixtureHttpClient.js +59 -0
- package/build/test-utils/NeptuneProviders.js +11 -0
- package/build/test-utils/index.js +4 -0
- package/build/test-utils/respond-with.js +6 -0
- package/build/test-utils/rtl-utils.js +7 -0
- package/build/test-utils/wait.js +3 -0
- package/build/tests/DynamicFlow.test.js +177 -0
- package/build/tests/HideStepTitle.test.js +58 -0
- package/build/tests/RequestCache.test.js +34 -0
- package/build/tests/SCARejectionHandling.test.js +71 -0
- package/build/tests/Subflow.Wise.test.js +650 -0
- package/build/tests/events.test.js +124 -0
- package/build/tests/logging.test.js +12 -0
- package/build/tests/onNotification.test.js +96 -0
- package/build/tests/renderers/ControlAndTags.test.js +225 -0
- package/build/tests/renderers/ImageRenderer.test.js +129 -0
- package/build/tests/renderers/RadioInputRendererComponent.test.js +89 -0
- package/build/tests/renderers/ReviewRenderer.test.js +41 -0
- package/build/tests/renderers/TextInputRenderer.test.js +44 -0
- package/build/tests/renderers/TimeZoneHeader.test.js +19 -0
- package/build/tests/renderers/UploadInputRenderer.maxSize.test.js +22 -0
- package/build/tests/renderers/value-utils.test.js +24 -0
- package/build/tsconfig.types.tsbuildinfo +1 -1
- package/package.json +4 -4
package/build/main.mjs
CHANGED
|
@@ -127,7 +127,7 @@ import { useDynamicFlow } from "@wise/dynamic-flow-client";
|
|
|
127
127
|
// src/dynamicFlow/telemetry/app-version.ts
|
|
128
128
|
var appVersion = (
|
|
129
129
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
130
|
-
typeof process !== "undefined" ? "5.
|
|
130
|
+
typeof process !== "undefined" ? "5.31.0" : "0.0.0"
|
|
131
131
|
);
|
|
132
132
|
|
|
133
133
|
// src/dynamicFlow/context-menu/useContextMenu.tsx
|
|
@@ -6777,98 +6777,7 @@ import {
|
|
|
6777
6777
|
TextArea,
|
|
6778
6778
|
TextareaWithDisplayFormat
|
|
6779
6779
|
} from "@transferwise/components";
|
|
6780
|
-
import {
|
|
6781
|
-
import { useIntl as useIntl21 } from "react-intl";
|
|
6782
|
-
import { useLayoutEffect as useLayoutEffect3, useRef as useRef5, useState as useState20 } from "react";
|
|
6783
|
-
|
|
6784
|
-
// ../renderers/src/messages/ssn-input.messages.ts
|
|
6785
|
-
import { defineMessages as defineMessages15 } from "react-intl";
|
|
6786
|
-
var ssn_input_messages_default = defineMessages15({
|
|
6787
|
-
showValue: {
|
|
6788
|
-
id: "df.wise.ssnInput.showValue",
|
|
6789
|
-
defaultMessage: "Show value",
|
|
6790
|
-
description: "Accessible label for showing a masked SSN or SIN value"
|
|
6791
|
-
},
|
|
6792
|
-
hideValue: {
|
|
6793
|
-
id: "df.wise.ssnInput.hideValue",
|
|
6794
|
-
defaultMessage: "Hide value",
|
|
6795
|
-
description: "Accessible label for hiding an SSN or SIN value"
|
|
6796
|
-
}
|
|
6797
|
-
});
|
|
6798
|
-
|
|
6799
|
-
// ../renderers/src/components/ssnInputUtils.ts
|
|
6800
|
-
function formatSsnValue(rawValue, displayFormat, isVisible) {
|
|
6801
|
-
if (!displayFormat) {
|
|
6802
|
-
return isVisible ? rawValue : "\u2022".repeat(rawValue.length);
|
|
6803
|
-
}
|
|
6804
|
-
return displayFormat.split("").reduce(
|
|
6805
|
-
({ display, digitsUsed }, character) => {
|
|
6806
|
-
if (character === "*") {
|
|
6807
|
-
return digitsUsed < rawValue.length ? {
|
|
6808
|
-
display: `${display}${isVisible ? rawValue[digitsUsed] : "\u2022"}`,
|
|
6809
|
-
digitsUsed: digitsUsed + 1
|
|
6810
|
-
} : { display, digitsUsed };
|
|
6811
|
-
}
|
|
6812
|
-
return digitsUsed > 0 && digitsUsed < rawValue.length ? { display: `${display}${character}`, digitsUsed } : { display, digitsUsed };
|
|
6813
|
-
},
|
|
6814
|
-
{ display: "", digitsUsed: 0 }
|
|
6815
|
-
).display;
|
|
6816
|
-
}
|
|
6817
|
-
function getRawOffset(displayValue, displayOffset, rawValueLength) {
|
|
6818
|
-
return Math.min(
|
|
6819
|
-
displayValue.slice(0, displayOffset).split("").filter((character) => character === "\u2022" || /\d/.test(character)).length,
|
|
6820
|
-
rawValueLength
|
|
6821
|
-
);
|
|
6822
|
-
}
|
|
6823
|
-
function replaceSsnSelection(rawValue, displayValue, insertedValue, start, end, maxDigits) {
|
|
6824
|
-
const startOffset = getRawOffset(displayValue, start, rawValue.length);
|
|
6825
|
-
const endOffset = getRawOffset(displayValue, end, rawValue.length);
|
|
6826
|
-
const selectedLength = endOffset - startOffset;
|
|
6827
|
-
const availableCapacity = Math.max(0, maxDigits - (rawValue.length - selectedLength));
|
|
6828
|
-
const acceptedInsertedValue = insertedValue.slice(0, availableCapacity);
|
|
6829
|
-
if (!acceptedInsertedValue) {
|
|
6830
|
-
return void 0;
|
|
6831
|
-
}
|
|
6832
|
-
return {
|
|
6833
|
-
value: `${rawValue.slice(0, startOffset)}${acceptedInsertedValue}${rawValue.slice(endOffset)}`,
|
|
6834
|
-
caret: startOffset + acceptedInsertedValue.length
|
|
6835
|
-
};
|
|
6836
|
-
}
|
|
6837
|
-
function deleteSsnSelection(rawValue, displayValue, start, end, backward) {
|
|
6838
|
-
let startOffset = getRawOffset(displayValue, start, rawValue.length);
|
|
6839
|
-
let endOffset = getRawOffset(displayValue, end, rawValue.length);
|
|
6840
|
-
if (startOffset === endOffset) {
|
|
6841
|
-
if (backward) {
|
|
6842
|
-
startOffset = Math.max(0, startOffset - 1);
|
|
6843
|
-
} else {
|
|
6844
|
-
endOffset = Math.min(rawValue.length, endOffset + 1);
|
|
6845
|
-
}
|
|
6846
|
-
}
|
|
6847
|
-
return {
|
|
6848
|
-
value: `${rawValue.slice(0, startOffset)}${rawValue.slice(endOffset)}`,
|
|
6849
|
-
caret: startOffset
|
|
6850
|
-
};
|
|
6851
|
-
}
|
|
6852
|
-
function getDisplayOffset(displayValue, rawOffset) {
|
|
6853
|
-
if (rawOffset === 0) {
|
|
6854
|
-
return 0;
|
|
6855
|
-
}
|
|
6856
|
-
let displayOffset = 0;
|
|
6857
|
-
let digitsSeen = 0;
|
|
6858
|
-
for (const character of displayValue) {
|
|
6859
|
-
if (character === "\u2022" || /\d/.test(character)) {
|
|
6860
|
-
digitsSeen += 1;
|
|
6861
|
-
if (digitsSeen === rawOffset) {
|
|
6862
|
-
return displayOffset + 1;
|
|
6863
|
-
}
|
|
6864
|
-
}
|
|
6865
|
-
displayOffset += 1;
|
|
6866
|
-
}
|
|
6867
|
-
return displayOffset;
|
|
6868
|
-
}
|
|
6869
|
-
|
|
6870
|
-
// ../renderers/src/components/VariableTextInput.tsx
|
|
6871
|
-
import { jsx as jsx100, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
6780
|
+
import { jsx as jsx100 } from "react/jsx-runtime";
|
|
6872
6781
|
var commonKeys = [
|
|
6873
6782
|
"autoComplete",
|
|
6874
6783
|
"autoCapitalize",
|
|
@@ -6885,9 +6794,6 @@ var commonKeys = [
|
|
|
6885
6794
|
function VariableTextInput(inputProps) {
|
|
6886
6795
|
const { id, value, control, onChange } = inputProps;
|
|
6887
6796
|
const commonProps = __spreadProps(__spreadValues({}, pick(inputProps, ...commonKeys)), { name: id });
|
|
6888
|
-
if (control === "ssn-input") {
|
|
6889
|
-
return /* @__PURE__ */ jsx100(SsnInput, __spreadProps(__spreadValues({}, commonProps), { maxLength: inputProps.maxLength, onChange }));
|
|
6890
|
-
}
|
|
6891
6797
|
switch (control) {
|
|
6892
6798
|
case "email":
|
|
6893
6799
|
return /* @__PURE__ */ jsx100(TextInput, __spreadProps(__spreadValues({}, commonProps), { type: "email", onChange }));
|
|
@@ -6913,142 +6819,10 @@ function VariableTextInput(inputProps) {
|
|
|
6913
6819
|
}
|
|
6914
6820
|
}
|
|
6915
6821
|
function TextInput(props) {
|
|
6916
|
-
const _a = props, { control, displayFormat, onChange
|
|
6822
|
+
const _a = props, { control, displayFormat, onChange } = _a, commonProps = __objRest(_a, ["control", "displayFormat", "onChange"]);
|
|
6917
6823
|
const InputWithPattern = control === "textarea" ? TextareaWithDisplayFormat : InputWithDisplayFormat;
|
|
6918
6824
|
const InputWithoutPattern = control === "textarea" ? TextArea : Input6;
|
|
6919
|
-
return displayFormat ? /* @__PURE__ */ jsx100(InputWithPattern, __spreadProps(__spreadValues({ displayPattern: displayFormat }, commonProps), { onChange })) : /* @__PURE__ */ jsx100(InputWithoutPattern, __spreadProps(__spreadValues({}, commonProps), {
|
|
6920
|
-
}
|
|
6921
|
-
function SsnInput(props) {
|
|
6922
|
-
const _a = props, {
|
|
6923
|
-
displayFormat = "",
|
|
6924
|
-
maxLength,
|
|
6925
|
-
onChange,
|
|
6926
|
-
type: _type,
|
|
6927
|
-
value = ""
|
|
6928
|
-
} = _a, commonProps = __objRest(_a, [
|
|
6929
|
-
"displayFormat",
|
|
6930
|
-
"maxLength",
|
|
6931
|
-
"onChange",
|
|
6932
|
-
"type",
|
|
6933
|
-
"value"
|
|
6934
|
-
]);
|
|
6935
|
-
const { formatMessage } = useIntl21();
|
|
6936
|
-
const [isVisible, setIsVisible] = useState20(false);
|
|
6937
|
-
const [editVersion, setEditVersion] = useState20(0);
|
|
6938
|
-
const inputRef = useRef5(null);
|
|
6939
|
-
const selection = useRef5({ start: 0, end: 0 });
|
|
6940
|
-
const pendingCaret = useRef5(null);
|
|
6941
|
-
const maxDigits = displayFormat.split("").filter((character) => character === "*").length || maxLength || Infinity;
|
|
6942
|
-
const rawValue = value.replace(/\D/g, "");
|
|
6943
|
-
const formattedValue = formatSsnValue(rawValue, displayFormat, isVisible);
|
|
6944
|
-
const scheduleCaret = (rawOffset) => {
|
|
6945
|
-
pendingCaret.current = rawOffset;
|
|
6946
|
-
setEditVersion((version) => version + 1);
|
|
6947
|
-
};
|
|
6948
|
-
const replaceSelection = (insertedValue, start, end) => {
|
|
6949
|
-
const result = replaceSsnSelection(
|
|
6950
|
-
rawValue,
|
|
6951
|
-
formattedValue,
|
|
6952
|
-
insertedValue,
|
|
6953
|
-
start,
|
|
6954
|
-
end,
|
|
6955
|
-
maxDigits
|
|
6956
|
-
);
|
|
6957
|
-
if (!result) {
|
|
6958
|
-
return;
|
|
6959
|
-
}
|
|
6960
|
-
scheduleCaret(result.caret);
|
|
6961
|
-
onChange(result.value);
|
|
6962
|
-
};
|
|
6963
|
-
const deleteSelection = (start, end, backward) => {
|
|
6964
|
-
const result = deleteSsnSelection(rawValue, formattedValue, start, end, backward);
|
|
6965
|
-
scheduleCaret(result.caret);
|
|
6966
|
-
onChange(result.value);
|
|
6967
|
-
};
|
|
6968
|
-
useLayoutEffect3(() => {
|
|
6969
|
-
if (pendingCaret.current === null || !inputRef.current) {
|
|
6970
|
-
return;
|
|
6971
|
-
}
|
|
6972
|
-
inputRef.current.setSelectionRange(
|
|
6973
|
-
getDisplayOffset(formattedValue, pendingCaret.current),
|
|
6974
|
-
getDisplayOffset(formattedValue, pendingCaret.current)
|
|
6975
|
-
);
|
|
6976
|
-
pendingCaret.current = null;
|
|
6977
|
-
}, [editVersion, formattedValue, rawValue]);
|
|
6978
|
-
return /* @__PURE__ */ jsxs40("div", { className: "df-ssn-input-wrapper", children: [
|
|
6979
|
-
/* @__PURE__ */ jsx100(
|
|
6980
|
-
"input",
|
|
6981
|
-
__spreadProps(__spreadValues({
|
|
6982
|
-
ref: inputRef
|
|
6983
|
-
}, commonProps), {
|
|
6984
|
-
className: "form-control np-form-control np-input np-input--shape-rectangle df-ssn-input",
|
|
6985
|
-
type: "text",
|
|
6986
|
-
inputMode: "numeric",
|
|
6987
|
-
maxLength: displayFormat.length || maxLength,
|
|
6988
|
-
value: formattedValue,
|
|
6989
|
-
onChange: (event) => {
|
|
6990
|
-
const nextValue = event.currentTarget.value;
|
|
6991
|
-
const inputType = event.nativeEvent.inputType;
|
|
6992
|
-
const start = selection.current.start;
|
|
6993
|
-
const end = selection.current.end;
|
|
6994
|
-
if (isVisible || /^\d+$/.test(nextValue)) {
|
|
6995
|
-
const nextRawValue = nextValue.replace(/\D/g, "").slice(0, maxDigits);
|
|
6996
|
-
scheduleCaret(nextRawValue.length);
|
|
6997
|
-
onChange(nextRawValue);
|
|
6998
|
-
} else if ((inputType == null ? void 0 : inputType.startsWith("delete")) || nextValue.length < formattedValue.length) {
|
|
6999
|
-
deleteSelection(start, end, inputType === "deleteContentBackward");
|
|
7000
|
-
} else {
|
|
7001
|
-
replaceSelection(nextValue.replace(/\D/g, ""), start, end);
|
|
7002
|
-
}
|
|
7003
|
-
},
|
|
7004
|
-
onSelect: (event) => {
|
|
7005
|
-
var _a2, _b;
|
|
7006
|
-
selection.current = {
|
|
7007
|
-
start: (_a2 = event.currentTarget.selectionStart) != null ? _a2 : 0,
|
|
7008
|
-
end: (_b = event.currentTarget.selectionEnd) != null ? _b : 0
|
|
7009
|
-
};
|
|
7010
|
-
},
|
|
7011
|
-
onKeyDown: (event) => {
|
|
7012
|
-
var _a2, _b;
|
|
7013
|
-
selection.current = {
|
|
7014
|
-
start: (_a2 = event.currentTarget.selectionStart) != null ? _a2 : 0,
|
|
7015
|
-
end: (_b = event.currentTarget.selectionEnd) != null ? _b : 0
|
|
7016
|
-
};
|
|
7017
|
-
if (/^\d$/.test(event.key)) {
|
|
7018
|
-
event.preventDefault();
|
|
7019
|
-
replaceSelection(event.key, selection.current.start, selection.current.end);
|
|
7020
|
-
} else if (event.key === "Backspace") {
|
|
7021
|
-
event.preventDefault();
|
|
7022
|
-
deleteSelection(selection.current.start, selection.current.end, true);
|
|
7023
|
-
} else if (event.key === "Delete") {
|
|
7024
|
-
event.preventDefault();
|
|
7025
|
-
deleteSelection(selection.current.start, selection.current.end, false);
|
|
7026
|
-
}
|
|
7027
|
-
},
|
|
7028
|
-
onPaste: (event) => {
|
|
7029
|
-
var _a2, _b;
|
|
7030
|
-
event.preventDefault();
|
|
7031
|
-
selection.current = {
|
|
7032
|
-
start: (_a2 = event.currentTarget.selectionStart) != null ? _a2 : 0,
|
|
7033
|
-
end: (_b = event.currentTarget.selectionEnd) != null ? _b : 0
|
|
7034
|
-
};
|
|
7035
|
-
const pastedValue = event.clipboardData.getData("text").replace(/\D/g, "");
|
|
7036
|
-
replaceSelection(pastedValue, selection.current.start, selection.current.end);
|
|
7037
|
-
}
|
|
7038
|
-
})
|
|
7039
|
-
),
|
|
7040
|
-
/* @__PURE__ */ jsx100(
|
|
7041
|
-
"button",
|
|
7042
|
-
{
|
|
7043
|
-
type: "button",
|
|
7044
|
-
className: "df-ssn-input-toggle",
|
|
7045
|
-
"aria-label": formatMessage(isVisible ? ssn_input_messages_default.hideValue : ssn_input_messages_default.showValue),
|
|
7046
|
-
"aria-pressed": isVisible,
|
|
7047
|
-
onClick: () => setIsVisible((visible) => !visible),
|
|
7048
|
-
children: isVisible ? /* @__PURE__ */ jsx100(EyeShut, { size: 24 }) : /* @__PURE__ */ jsx100(Eye, { size: 24 })
|
|
7049
|
-
}
|
|
7050
|
-
)
|
|
7051
|
-
] });
|
|
6825
|
+
return displayFormat ? /* @__PURE__ */ jsx100(InputWithPattern, __spreadProps(__spreadValues({ displayPattern: displayFormat }, commonProps), { onChange })) : /* @__PURE__ */ jsx100(InputWithoutPattern, __spreadProps(__spreadValues({}, commonProps), { onChange: (e) => onChange(e.target.value) }));
|
|
7052
6826
|
}
|
|
7053
6827
|
|
|
7054
6828
|
// ../renderers/src/TextInputRenderer.tsx
|
|
@@ -7260,7 +7034,7 @@ var LargeUploadRenderer = {
|
|
|
7260
7034
|
// ../renderers/src/UpsellRenderer.tsx
|
|
7261
7035
|
var import_classnames35 = __toESM(require_classnames());
|
|
7262
7036
|
import { Nudge } from "@transferwise/components";
|
|
7263
|
-
import { useState as
|
|
7037
|
+
import { useState as useState20 } from "react";
|
|
7264
7038
|
import { jsx as jsx104 } from "react/jsx-runtime";
|
|
7265
7039
|
var UpsellRenderer = {
|
|
7266
7040
|
canRenderType: "upsell",
|
|
@@ -7268,7 +7042,7 @@ var UpsellRenderer = {
|
|
|
7268
7042
|
};
|
|
7269
7043
|
function UpsellRendererComponent(props) {
|
|
7270
7044
|
const { text, callToAction, media, margin, onDismiss, control, tags } = props;
|
|
7271
|
-
const [isVisible, setIsVisible] =
|
|
7045
|
+
const [isVisible, setIsVisible] = useState20(true);
|
|
7272
7046
|
return isVisible ? /* @__PURE__ */ jsx104(
|
|
7273
7047
|
Nudge,
|
|
7274
7048
|
{
|
|
@@ -7498,11 +7272,11 @@ var customEventsToAnalytics = {
|
|
|
7498
7272
|
|
|
7499
7273
|
// src/dynamicFlow/useOnCopy.tsx
|
|
7500
7274
|
import { useCallback as useCallback2 } from "react";
|
|
7501
|
-
import { useIntl as
|
|
7275
|
+
import { useIntl as useIntl21 } from "react-intl";
|
|
7502
7276
|
|
|
7503
7277
|
// src/dynamicFlow/messages.ts
|
|
7504
|
-
import { defineMessages as
|
|
7505
|
-
var messages_default =
|
|
7278
|
+
import { defineMessages as defineMessages15 } from "react-intl";
|
|
7279
|
+
var messages_default = defineMessages15({
|
|
7506
7280
|
copied: {
|
|
7507
7281
|
id: "df.wise.CopyFeedback.copy",
|
|
7508
7282
|
defaultMessage: "Copied to clipboard",
|
|
@@ -7517,7 +7291,7 @@ var messages_default = defineMessages16({
|
|
|
7517
7291
|
|
|
7518
7292
|
// src/dynamicFlow/useOnCopy.tsx
|
|
7519
7293
|
var useOnCopy = () => {
|
|
7520
|
-
const { formatMessage } =
|
|
7294
|
+
const { formatMessage } = useIntl21();
|
|
7521
7295
|
const createSnackBar = useSnackBarIfAvailable();
|
|
7522
7296
|
return useCallback2(
|
|
7523
7297
|
(copiedContent) => {
|
|
@@ -7533,9 +7307,9 @@ var useOnCopy = () => {
|
|
|
7533
7307
|
|
|
7534
7308
|
// src/dynamicFlow/useWiseHttpClient.tsx
|
|
7535
7309
|
import { useCallback as useCallback3 } from "react";
|
|
7536
|
-
import { useIntl as
|
|
7310
|
+
import { useIntl as useIntl22 } from "react-intl";
|
|
7537
7311
|
var useWiseHttpClient = (httpClient) => {
|
|
7538
|
-
const { locale } =
|
|
7312
|
+
const { locale } = useIntl22();
|
|
7539
7313
|
return useCallback3(
|
|
7540
7314
|
async (input, init = {}) => {
|
|
7541
7315
|
const headers = new Headers(init.headers);
|
|
@@ -7615,13 +7389,13 @@ var openLinkInNewTab = (url) => {
|
|
|
7615
7389
|
};
|
|
7616
7390
|
|
|
7617
7391
|
// src/dynamicFlow/DynamicFlow.tsx
|
|
7618
|
-
import { jsxs as
|
|
7392
|
+
import { jsxs as jsxs40 } from "react/jsx-runtime";
|
|
7619
7393
|
function DynamicFlow(props) {
|
|
7620
7394
|
const { className = "" } = props;
|
|
7621
7395
|
const dfProps = useWiseToCoreProps(props);
|
|
7622
7396
|
const df = useDynamicFlow(dfProps);
|
|
7623
7397
|
const { onContextMenu, contextMenu } = useDFContextMenu(df.controller);
|
|
7624
|
-
return /* @__PURE__ */
|
|
7398
|
+
return /* @__PURE__ */ jsxs40("div", { className, onContextMenu, children: [
|
|
7625
7399
|
df.view,
|
|
7626
7400
|
contextMenu
|
|
7627
7401
|
] });
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
import { DynamicFlow } from '../dynamicFlow/DynamicFlow';
|
|
4
|
+
import { fixtureHttpClient } from './utils/fixtureHttpClient';
|
|
5
|
+
export default {
|
|
6
|
+
title: 'Initialisation',
|
|
7
|
+
component: DynamicFlow,
|
|
8
|
+
};
|
|
9
|
+
const onCompletion = action('onCompletion');
|
|
10
|
+
const onError = action('onError');
|
|
11
|
+
const onEvent = action('onEvent');
|
|
12
|
+
const onLog = action('onLog');
|
|
13
|
+
export const ButtonLoader = {
|
|
14
|
+
render: () => (_jsx(DynamicFlow, { flowId: "initialisation-telemetry", customFetch: fixtureHttpClient, initialStep: step, onCompletion: onCompletion, onError: onError, onEvent: onEvent, onLog: onLog })),
|
|
15
|
+
};
|
|
16
|
+
const step = {
|
|
17
|
+
id: 'convert-review',
|
|
18
|
+
title: 'Does everything look right?',
|
|
19
|
+
schemas: [
|
|
20
|
+
{
|
|
21
|
+
properties: {
|
|
22
|
+
quoteId: {
|
|
23
|
+
const: '123',
|
|
24
|
+
},
|
|
25
|
+
profileId: {
|
|
26
|
+
const: 6666,
|
|
27
|
+
},
|
|
28
|
+
context: {
|
|
29
|
+
const: 'CONVERT',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
displayOrder: ['quoteId', 'profileId', 'context'],
|
|
33
|
+
required: ['quoteId', 'profileId', 'context'],
|
|
34
|
+
hidden: true,
|
|
35
|
+
type: 'object',
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
layout: [
|
|
39
|
+
{
|
|
40
|
+
components: [
|
|
41
|
+
{
|
|
42
|
+
fields: [
|
|
43
|
+
{
|
|
44
|
+
label: "You're converting",
|
|
45
|
+
value: '123 EUR',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
label: 'To',
|
|
49
|
+
value: '101.61 GBP',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
label: 'Our fee',
|
|
53
|
+
value: '6.15 EUR',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
label: 'Rate',
|
|
57
|
+
value: '1 EUR = 0.8696 GBP',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
title: 'Conversion details',
|
|
61
|
+
callToAction: {
|
|
62
|
+
title: 'Edit',
|
|
63
|
+
behavior: {
|
|
64
|
+
action: {
|
|
65
|
+
exit: true,
|
|
66
|
+
result: {
|
|
67
|
+
action: 'EDIT',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
type: 'action',
|
|
71
|
+
},
|
|
72
|
+
action: {
|
|
73
|
+
exit: true,
|
|
74
|
+
result: {
|
|
75
|
+
action: 'EDIT',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
control: 'horizontal',
|
|
80
|
+
type: 'review',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
title: 'Convert',
|
|
84
|
+
behavior: {
|
|
85
|
+
action: {
|
|
86
|
+
exit: true,
|
|
87
|
+
result: {
|
|
88
|
+
action: 'CONVERT',
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
type: 'action',
|
|
92
|
+
},
|
|
93
|
+
control: 'primary',
|
|
94
|
+
margin: 'xs',
|
|
95
|
+
type: 'button',
|
|
96
|
+
action: {
|
|
97
|
+
exit: true,
|
|
98
|
+
result: {
|
|
99
|
+
action: 'CONVERT',
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
control: 'bordered',
|
|
105
|
+
type: 'box',
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
refreshUrl: '/v1/convert/review?refresh=true',
|
|
109
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
import { DynamicFlow } from '../dynamicFlow/DynamicFlow';
|
|
4
|
+
import { Fragment } from 'react/jsx-runtime';
|
|
5
|
+
export default {
|
|
6
|
+
component: ImageLayoutWithSize,
|
|
7
|
+
title: 'Dev Tools/Container Queries',
|
|
8
|
+
argTypes: {
|
|
9
|
+
width: {
|
|
10
|
+
options: ['100%', '900px', '600px', '575px', '400px'],
|
|
11
|
+
control: { type: 'select' },
|
|
12
|
+
description: 'Width of the div containing the DynamicFlow component',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
args: {
|
|
16
|
+
width: '575px',
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
export function ImageLayoutWithSize({ width }) {
|
|
20
|
+
return _jsx(Fragment, { children: renderWithStep(imageLayoutStep, width) }, width);
|
|
21
|
+
}
|
|
22
|
+
function renderWithStep(step, width) {
|
|
23
|
+
const getDF = () => (_jsx(DynamicFlow, { flowId: "new-df-flow-id", className: "df-prefer-container-queries", customFetch: async (input, init) => {
|
|
24
|
+
action('httpClient')(input, init === null || init === void 0 ? void 0 : init.body);
|
|
25
|
+
return fetch(input, init);
|
|
26
|
+
}, initialStep: Object.assign(Object.assign({}, step), { title: `Dynamic Flow Step - ${width}`, description: `This is a DynamicFlow component inside a ${width}-wide <div> container. You can change the width in the Storybook controls.` }), onCompletion: action('onCompletion'), onEvent: action('onEvent'), onLog: action('onLog'), onError: (error) => {
|
|
27
|
+
action('onError');
|
|
28
|
+
console.error(error);
|
|
29
|
+
} }));
|
|
30
|
+
return (_jsxs("div", { className: "d-flex", children: [_jsx("div", { style: { flexGrow: 1, backgroundColor: '#EEE', textAlign: 'center' }, children: " NOT-DF " }), _jsx("div", { style: { width, backgroundColor: 'white' }, children: getDF() }), _jsx("div", { style: { flexGrow: 1, backgroundColor: '#EEE', textAlign: 'center' }, children: " NOT-DF " })] }));
|
|
31
|
+
}
|
|
32
|
+
const imageLayoutStep = {
|
|
33
|
+
id: 'step-id',
|
|
34
|
+
title: 'Dynamic Flow Step',
|
|
35
|
+
description: 'This is a step in the dynamic flow.',
|
|
36
|
+
schemas: [],
|
|
37
|
+
layout: [
|
|
38
|
+
{
|
|
39
|
+
type: 'image',
|
|
40
|
+
size: 'xs',
|
|
41
|
+
content: {
|
|
42
|
+
uri: 'https://placehold.co/600x600?text=Cat',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: 'image',
|
|
47
|
+
size: 'sm',
|
|
48
|
+
content: {
|
|
49
|
+
uri: 'https://placehold.co/600x600?text=Cat',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: 'image',
|
|
54
|
+
size: 'md',
|
|
55
|
+
content: {
|
|
56
|
+
uri: 'https://placehold.co/600x600?text=Cat',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
type: 'image',
|
|
61
|
+
size: 'lg',
|
|
62
|
+
content: {
|
|
63
|
+
uri: 'https://placehold.co/600x600?text=Cat',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: 'image',
|
|
68
|
+
size: 'xl',
|
|
69
|
+
content: {
|
|
70
|
+
uri: 'https://placehold.co/600x600?text=Cat',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
import { layouts, schemas, misc, step } from '@wise/dynamic-flow-fixtures';
|
|
4
|
+
import { DynamicFlow } from '../index';
|
|
5
|
+
import { fixtureHttpClient } from './utils/fixtureHttpClient';
|
|
6
|
+
const fixtures = Object.assign(Object.assign(Object.assign(Object.assign({}, schemas), layouts), misc), step);
|
|
7
|
+
function DynamicFlowRenderer({ initialStepName = '', }) {
|
|
8
|
+
const selectedStep = fixtures[initialStepName] || {};
|
|
9
|
+
const parsedStep = typeof selectedStep === 'string' ? JSON.parse(selectedStep) : selectedStep;
|
|
10
|
+
const props = {
|
|
11
|
+
flowId: 'storybook',
|
|
12
|
+
customFetch: fixtureHttpClient,
|
|
13
|
+
onCompletion: action('onCompletion'),
|
|
14
|
+
onError: action('onError'),
|
|
15
|
+
onEvent: action('onEvent'),
|
|
16
|
+
onLog: action('onLog'),
|
|
17
|
+
};
|
|
18
|
+
return (_jsx(DynamicFlow, Object.assign({}, props, { initialAction: { method: 'GET', url: `/steps/${initialStepName}` } }), parsedStep.id));
|
|
19
|
+
}
|
|
20
|
+
const meta = {
|
|
21
|
+
title: 'Multi-fixture',
|
|
22
|
+
component: DynamicFlowRenderer,
|
|
23
|
+
};
|
|
24
|
+
export const AllFixtures = {
|
|
25
|
+
argTypes: {
|
|
26
|
+
initialStepName: {
|
|
27
|
+
label: 'Initial Step',
|
|
28
|
+
control: 'select',
|
|
29
|
+
options: Object.keys(fixtures),
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
args: { initialStepName: Object.keys(fixtures)[1], revampEnabled: false },
|
|
33
|
+
parameters: {
|
|
34
|
+
chromatic: { disableSnapshot: true },
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
export default meta;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
import { Button } from '@transferwise/components';
|
|
4
|
+
import { useRef, useState } from 'react';
|
|
5
|
+
import { DynamicFlowWithRef } from '..';
|
|
6
|
+
import { fixtureHttpClient } from './utils/fixtureHttpClient';
|
|
7
|
+
const step = {
|
|
8
|
+
id: 'dynamic-form-story',
|
|
9
|
+
title: 'Dynamic Form',
|
|
10
|
+
schemas: [
|
|
11
|
+
{
|
|
12
|
+
$id: '#form',
|
|
13
|
+
type: 'object',
|
|
14
|
+
displayOrder: ['name', 'city'],
|
|
15
|
+
required: ['name'],
|
|
16
|
+
properties: {
|
|
17
|
+
name: { type: 'string', title: 'Name', minLength: 2 },
|
|
18
|
+
city: {
|
|
19
|
+
title: 'City',
|
|
20
|
+
oneOf: [
|
|
21
|
+
{ title: 'London', const: 'London', icon: { name: 'flag-gb' } },
|
|
22
|
+
{ title: 'Paris', const: 'Paris', icon: { name: 'flag-fr' } },
|
|
23
|
+
{ title: 'New York', const: 'New York', icon: { name: 'flag-us' } },
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
layout: [
|
|
30
|
+
{
|
|
31
|
+
type: 'form',
|
|
32
|
+
schemaId: '#form',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
function DynamicFlowWithRefStory() {
|
|
37
|
+
const ref = useRef(null);
|
|
38
|
+
const props = {
|
|
39
|
+
flowId: 'storybook',
|
|
40
|
+
analyticsId: 'storybook',
|
|
41
|
+
customFetch: fixtureHttpClient,
|
|
42
|
+
onValueChange: action('onValueChange'),
|
|
43
|
+
onError: action('onError'),
|
|
44
|
+
onEvent: action('onEvent'),
|
|
45
|
+
onLog: action('onLog'),
|
|
46
|
+
};
|
|
47
|
+
const [currentValue, setCurrentValue] = useState('');
|
|
48
|
+
const [isValid, setValid] = useState(null);
|
|
49
|
+
const backgroundColor = isValid === null ? '#eeeeee' : isValid ? '#eeffee' : '#ffeeee';
|
|
50
|
+
const validityText = isValid === null ? '' : isValid ? '✅ valid\n\n' : '❌ invalid\n\n';
|
|
51
|
+
return (_jsxs(_Fragment, { children: [_jsx(DynamicFlowWithRef, Object.assign({ ref: ref }, props, { initialStep: step, onValueChange: async () => {
|
|
52
|
+
var _a;
|
|
53
|
+
var _b;
|
|
54
|
+
const newValue = (_b = (_a = ref.current) === null || _a === void 0 ? void 0 : _a.getValue()) !== null && _b !== void 0 ? _b : null;
|
|
55
|
+
setCurrentValue(JSON.stringify(newValue, null, 2));
|
|
56
|
+
}, onCompletion: () => { } }), JSON.stringify(step)), _jsx(Button, { onClick: async () => {
|
|
57
|
+
var _a;
|
|
58
|
+
var _b;
|
|
59
|
+
const ok = (_b = (_a = ref.current) === null || _a === void 0 ? void 0 : _a.validate()) !== null && _b !== void 0 ? _b : false;
|
|
60
|
+
setValid(ok);
|
|
61
|
+
}, children: "validate()" }), _jsx("hr", {}), _jsxs("pre", { style: { backgroundColor }, children: [validityText, currentValue] })] }));
|
|
62
|
+
}
|
|
63
|
+
const meta = {
|
|
64
|
+
title: 'Dynamic Form',
|
|
65
|
+
component: DynamicFlowWithRefStory,
|
|
66
|
+
};
|
|
67
|
+
export const AllFixtures = {
|
|
68
|
+
parameters: {
|
|
69
|
+
chromatic: { disableSnapshot: true },
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
export default meta;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { action } from 'storybook/actions';
|
|
3
|
+
import { layouts, schemas } from '@wise/dynamic-flow-fixtures';
|
|
4
|
+
import { useMemo, useState } from 'react';
|
|
5
|
+
import { DynamicFlow } from '../dynamicFlow/DynamicFlow';
|
|
6
|
+
const fixtures = Object.assign(Object.assign({}, schemas), layouts);
|
|
7
|
+
export function Editable({ initialStepName = '' }) {
|
|
8
|
+
const selectedStep = fixtures[initialStepName] || {};
|
|
9
|
+
const selectedInitialStep = JSON.stringify(selectedStep, null, 2);
|
|
10
|
+
return _jsx(InteractiveDemo, { selectedInitialStep: selectedInitialStep }, selectedInitialStep);
|
|
11
|
+
}
|
|
12
|
+
function InteractiveDemo({ selectedInitialStep }) {
|
|
13
|
+
const [initialStatusCode, setInitialStatusCode] = useState(200);
|
|
14
|
+
const [initialStep, setInitialStep] = useState(selectedInitialStep);
|
|
15
|
+
const onTextAreaChange = (event) => {
|
|
16
|
+
setInitialStep(event.target.value);
|
|
17
|
+
};
|
|
18
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { children: [_jsx("h3", { children: "Editable Demo" }), _jsx("p", { children: "You can specify a response status code and body, and DF will load your step below." }), _jsxs("fieldset", { children: [_jsx("label", { htmlFor: "status-code", children: "Response Status code: " }), _jsx(StatusCodeSelect, { id: "status-code", state: [initialStatusCode, setInitialStatusCode] })] }), _jsxs("fieldset", { children: [_jsx("label", { htmlFor: "textarea", children: "Response Body:" }), _jsx(InvalidJsonWarning, { initialStep: initialStep }), _jsx("textarea", { id: "textarea", wrap: "off", rows: 40, style: {
|
|
19
|
+
fontFamily: 'monospace',
|
|
20
|
+
fontSize: '0.9em',
|
|
21
|
+
width: '100%',
|
|
22
|
+
maxHeight: '200px',
|
|
23
|
+
}, value: initialStep, onChange: onTextAreaChange })] })] }), isValidJson(initialStep) ? (_jsx(DynamicFlow, { flowId: "storybook", customFetch: fetch, initialStep: JSON.parse(initialStep), onCompletion: action('onCompletion'), onError: (error) => {
|
|
24
|
+
action('onError')(error);
|
|
25
|
+
console.error(error);
|
|
26
|
+
} }, `${initialStep}-${initialStatusCode}`)) : null] }));
|
|
27
|
+
}
|
|
28
|
+
function InvalidJsonWarning({ initialStep }) {
|
|
29
|
+
const validJson = useMemo(() => isValidJson(initialStep), [initialStep]);
|
|
30
|
+
return !validJson ? (_jsx("p", { children: "\u274C Invalid syntax or missing elements are preventing the JSON code you entered from being parsed." })) : null;
|
|
31
|
+
}
|
|
32
|
+
const isValidJson = (value) => {
|
|
33
|
+
try {
|
|
34
|
+
JSON.parse(value);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
catch (_a) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
function StatusCodeSelect({ id, state: [value, setValue], }) {
|
|
42
|
+
return (_jsxs("select", { id: id, value: value, onChange: (event) => setValue(Number.parseInt(event.target.value, 10)), children: [_jsx("option", { children: "200" }), _jsx("option", { children: "400" }), _jsx("option", { children: "500" })] }));
|
|
43
|
+
}
|
|
44
|
+
export default {
|
|
45
|
+
component: Editable,
|
|
46
|
+
title: 'Multi-fixture',
|
|
47
|
+
parameters: {
|
|
48
|
+
chromatic: { disableSnapshot: true },
|
|
49
|
+
},
|
|
50
|
+
argTypes: {
|
|
51
|
+
initialStepName: {
|
|
52
|
+
label: 'Initial Step',
|
|
53
|
+
control: 'select',
|
|
54
|
+
options: Object.keys(fixtures),
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
args: { initialStepName: Object.keys(fixtures)[0] },
|
|
58
|
+
};
|