@rabbitio/ui-kit 1.0.0-beta.43 → 1.0.0-beta.45

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 (113) hide show
  1. package/.husky/pre-push +1 -1
  2. package/dist/index.cjs +1389 -102
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.css +23630 -0
  5. package/dist/index.css.map +1 -1
  6. package/dist/index.modern.js +1185 -57
  7. package/dist/index.modern.js.map +1 -1
  8. package/dist/index.module.js +1379 -103
  9. package/dist/index.module.js.map +1 -1
  10. package/dist/index.umd.js +1388 -106
  11. package/dist/index.umd.js.map +1 -1
  12. package/package.json +6 -1
  13. package/src/assets/image/icons/arrow-tosca.svg +3 -0
  14. package/src/assets/image/icons/arrow-white.svg +14 -0
  15. package/src/assets/image/icons/failed-validation-icon.svg +15 -0
  16. package/src/assets/image/icons/successful-validation-icon.svg +10 -0
  17. package/src/components/atoms/BackgroundTitle/BackgroundTitle.jsx +44 -0
  18. package/src/components/atoms/BackgroundTitle/background-title.module.scss +52 -0
  19. package/src/components/atoms/Validation/Validation.jsx +130 -0
  20. package/src/components/atoms/Validation/validation.module.scss +15 -0
  21. package/src/components/atoms/buttons/Close/Close.jsx +64 -0
  22. package/src/components/atoms/buttons/Close/close.module.scss +75 -0
  23. package/src/components/atoms/buttons/LinkButton/LinkButton.jsx +121 -0
  24. package/src/components/atoms/buttons/LinkButton/link-button.module.scss +45 -0
  25. package/src/components/organisms/Dialog/Dialog.jsx +515 -0
  26. package/src/components/organisms/Dialog/DialogButtons/DialogButtons.jsx +122 -0
  27. package/src/components/organisms/Dialog/DialogButtons/dialog-buttons.module.scss +25 -0
  28. package/src/components/organisms/Dialog/DialogStep/DialogStep.jsx +664 -0
  29. package/src/components/organisms/Dialog/DialogStep/dialog-step.module.scss +362 -0
  30. package/src/components/organisms/Dialog/dialog.module.scss +223 -0
  31. package/src/constants/organisms/dialog/DialogStep/dialogStep.js +1 -0
  32. package/src/constants/organisms/dialog/dialog.js +29 -0
  33. package/src/index.js +10 -0
  34. package/stories/stubs/exampleContent.jsx +20 -0
  35. package/styles/fonts/NunitoSans-Bold.ttf +0 -0
  36. package/styles/fonts/NunitoSans-ExtraBold.ttf +0 -0
  37. package/styles/fonts/NunitoSans-Light.ttf +0 -0
  38. package/styles/fonts/NunitoSans-Regular.ttf +0 -0
  39. package/styles/fonts/NunitoSans-SemiBold.ttf +0 -0
  40. package/styles/index.scss +14 -13
  41. package/coverage/base.css +0 -224
  42. package/coverage/block-navigation.js +0 -87
  43. package/coverage/clover.xml +0 -6516
  44. package/coverage/coverage-final.json +0 -43
  45. package/coverage/favicon.png +0 -0
  46. package/coverage/index.html +0 -416
  47. package/coverage/prettify.css +0 -1
  48. package/coverage/prettify.js +0 -2
  49. package/coverage/rabbit-ui-kit/index.html +0 -116
  50. package/coverage/rabbit-ui-kit/index.js.html +0 -88
  51. package/coverage/rabbit-ui-kit/src/common/adapters/axiosAdapter.js.html +0 -190
  52. package/coverage/rabbit-ui-kit/src/common/adapters/index.html +0 -116
  53. package/coverage/rabbit-ui-kit/src/common/amountUtils.js.html +0 -1393
  54. package/coverage/rabbit-ui-kit/src/common/errorUtils.js.html +0 -211
  55. package/coverage/rabbit-ui-kit/src/common/external-apis/apiGroups.js.html +0 -250
  56. package/coverage/rabbit-ui-kit/src/common/external-apis/index.html +0 -131
  57. package/coverage/rabbit-ui-kit/src/common/external-apis/ipAddressProviders.js.html +0 -499
  58. package/coverage/rabbit-ui-kit/src/common/fiatCurrenciesService.js.html +0 -568
  59. package/coverage/rabbit-ui-kit/src/common/index.html +0 -146
  60. package/coverage/rabbit-ui-kit/src/common/models/blockchain.js.html +0 -115
  61. package/coverage/rabbit-ui-kit/src/common/models/coin.js.html +0 -556
  62. package/coverage/rabbit-ui-kit/src/common/models/index.html +0 -146
  63. package/coverage/rabbit-ui-kit/src/common/models/protocol.js.html +0 -100
  64. package/coverage/rabbit-ui-kit/src/common/utils/cache.js.html +0 -889
  65. package/coverage/rabbit-ui-kit/src/common/utils/emailAPI.js.html +0 -139
  66. package/coverage/rabbit-ui-kit/src/common/utils/index.html +0 -161
  67. package/coverage/rabbit-ui-kit/src/common/utils/logging/index.html +0 -131
  68. package/coverage/rabbit-ui-kit/src/common/utils/logging/logger.js.html +0 -229
  69. package/coverage/rabbit-ui-kit/src/common/utils/logging/logsStorage.js.html +0 -268
  70. package/coverage/rabbit-ui-kit/src/common/utils/postponeExecution.js.html +0 -118
  71. package/coverage/rabbit-ui-kit/src/common/utils/safeStringify.js.html +0 -235
  72. package/coverage/rabbit-ui-kit/src/components/atoms/AssetIcon/AssetIcon.jsx.html +0 -250
  73. package/coverage/rabbit-ui-kit/src/components/atoms/AssetIcon/index.html +0 -116
  74. package/coverage/rabbit-ui-kit/src/components/atoms/LoadingDots/LoadingDots.jsx.html +0 -256
  75. package/coverage/rabbit-ui-kit/src/components/atoms/LoadingDots/index.html +0 -116
  76. package/coverage/rabbit-ui-kit/src/components/atoms/SupportChat/SupportChat.jsx.html +0 -229
  77. package/coverage/rabbit-ui-kit/src/components/atoms/SupportChat/index.html +0 -116
  78. package/coverage/rabbit-ui-kit/src/components/atoms/buttons/Button/Button.jsx.html +0 -802
  79. package/coverage/rabbit-ui-kit/src/components/atoms/buttons/Button/index.html +0 -116
  80. package/coverage/rabbit-ui-kit/src/components/hooks/index.html +0 -131
  81. package/coverage/rabbit-ui-kit/src/components/hooks/useCallHandlingErrors.js.html +0 -163
  82. package/coverage/rabbit-ui-kit/src/components/hooks/useReferredState.js.html +0 -157
  83. package/coverage/rabbit-ui-kit/src/components/utils/index.html +0 -146
  84. package/coverage/rabbit-ui-kit/src/components/utils/inputValueProviders.js.html +0 -259
  85. package/coverage/rabbit-ui-kit/src/components/utils/uiUtils.js.html +0 -127
  86. package/coverage/rabbit-ui-kit/src/components/utils/urlQueryUtils.js.html +0 -346
  87. package/coverage/rabbit-ui-kit/src/index.html +0 -116
  88. package/coverage/rabbit-ui-kit/src/index.js.html +0 -250
  89. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/cacheAndConcurrentRequestsResolver.js.html +0 -1762
  90. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/cachedRobustExternalApiCallerService.js.html +0 -649
  91. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/cancelProcessing.js.html +0 -172
  92. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/concurrentCalculationsMetadataHolder.js.html +0 -394
  93. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/externalApiProvider.js.html +0 -553
  94. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/externalServicesStatsCollector.js.html +0 -331
  95. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/index.html +0 -206
  96. package/coverage/rabbit-ui-kit/src/robustExteranlApiCallerService/robustExternalAPICallerService.js.html +0 -1249
  97. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/index.html +0 -131
  98. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/swapProvider.js.html +0 -727
  99. package/coverage/rabbit-ui-kit/src/swaps-lib/external-apis/swapspaceSwapProvider.js.html +0 -2899
  100. package/coverage/rabbit-ui-kit/src/swaps-lib/models/baseSwapCreationInfo.js.html +0 -214
  101. package/coverage/rabbit-ui-kit/src/swaps-lib/models/existingSwap.js.html +0 -304
  102. package/coverage/rabbit-ui-kit/src/swaps-lib/models/existingSwapWithFiatData.js.html +0 -487
  103. package/coverage/rabbit-ui-kit/src/swaps-lib/models/index.html +0 -146
  104. package/coverage/rabbit-ui-kit/src/swaps-lib/services/index.html +0 -116
  105. package/coverage/rabbit-ui-kit/src/swaps-lib/services/publicSwapService.js.html +0 -2191
  106. package/coverage/rabbit-ui-kit/src/swaps-lib/utils/index.html +0 -116
  107. package/coverage/rabbit-ui-kit/src/swaps-lib/utils/swapUtils.js.html +0 -742
  108. package/coverage/rabbit-ui-kit/stories/atoms/LoadingDots.stories.jsx.html +0 -226
  109. package/coverage/rabbit-ui-kit/stories/atoms/buttons/Button.stories.jsx.html +0 -946
  110. package/coverage/rabbit-ui-kit/stories/atoms/buttons/index.html +0 -116
  111. package/coverage/rabbit-ui-kit/stories/atoms/index.html +0 -116
  112. package/coverage/sort-arrow-sprite.png +0 -0
  113. package/coverage/sorter.js +0 -196
@@ -0,0 +1,515 @@
1
+ import React, { useEffect, useRef, useState } from "react";
2
+ import PropTypes from "prop-types";
3
+ import { CSSTransition } from "react-transition-group";
4
+ import AnimateHeight from "react-animate-height";
5
+ import ResizeObserver from "resize-observer-polyfill";
6
+ import {
7
+ disableBodyScroll,
8
+ enableBodyScroll,
9
+ clearAllBodyScrollLocks,
10
+ } from "body-scroll-lock";
11
+ import animateScrollTo from "animated-scroll-to";
12
+
13
+ import { useReferredState } from "../../hooks/useReferredState";
14
+ import { logErrorOrOutputToConsole } from "../../../common/errorUtils";
15
+ import {
16
+ DIALOG_TRANSITION_STEP_DURATION,
17
+ DIALOG_SIZES,
18
+ } from "../../../constants/organisms/dialog/dialog";
19
+
20
+ import s from "./dialog.module.scss";
21
+ import { Close } from "../../atoms/buttons/Close/Close";
22
+ import { DialogButtons } from "./DialogButtons/DialogButtons";
23
+
24
+ /**
25
+ * Flexible modal window component with support for multiple steps. Can be used as an inline component and inserted in regular layouts. Only <DialogStep> components can be passed as children.
26
+ *
27
+ * @component
28
+ * @param {Object} props - Component props.
29
+ * @param {boolean} props.showDialog - Step name, specified on the root dialog level, used as an ID for dialog navigation.
30
+ * @param {string} props.onClose - Handler for when the dialog is closed.
31
+ * @param {string} props.initControls - State-setting function to initialize the dialog-to-step connection.
32
+ * @param {string} props.children - Content of the dialog window, supports only dialog step components.
33
+ * @param {Coin} props.width - Width in pixels, formatted as "1000px" and passed a string. Values should be used from constants.
34
+ * @param {string} props.dispatchDialogOpened - Dispatch upon the dialog closure.
35
+ * @param {string} props.dispatchDialogClosed - Dispatch upon the dialog opening.
36
+ * @param {function} props.inline - If false or not set, dialog will be opened as a modal window above the UI. If true, inline mode will be used, making the dialog a regular block, that can be placed inside a regular layout. Default: false.
37
+ * @returns {JSX.Element} React component
38
+ */
39
+ export const Dialog = ({
40
+ showDialog = false,
41
+ onClose = () => {},
42
+ initControls = null,
43
+ children = [],
44
+ width = "",
45
+ dispatchDialogOpened = () => {},
46
+ dispatchDialogClosed = () => {},
47
+ inline = false,
48
+ }) => {
49
+ const buttonsConfigurationDefault = {
50
+ primaryButtonTitle: null,
51
+ primaryButtonOnClick: null,
52
+ primaryButtonLoader: false,
53
+ primaryButtonTo: null,
54
+ primaryButtonSetClickTrigger: () => {},
55
+ secondaryButtonTitle: null,
56
+ secondaryButtonOnClick: null,
57
+ secondaryButtonTo: null,
58
+ fixedButtonsEnabled: false,
59
+ };
60
+
61
+ const [showDialogProcessed, setShowDialogProcessed] = useState(false);
62
+ const [currentStep, setCurrentStep] = useState(0);
63
+ const [steps, setSteps] = useState(null);
64
+ const [dialogConfiguration, updateDialogConfiguration] = useState({
65
+ cornerBackButtonTitle: "",
66
+ customWidth: width !== "" ? width : DIALOG_SIZES.small.width,
67
+ });
68
+ const [animationConfiguration, updateAnimationConfiguration] = useState({
69
+ animateHeightDelay: DIALOG_TRANSITION_STEP_DURATION * 2,
70
+ animateHeightTransitionSpeed: DIALOG_TRANSITION_STEP_DURATION,
71
+ animateHeightTransitionEnabled: false,
72
+ wrapperWidthAnimationEnabled: false,
73
+ currentStepAnimationEnabled: false,
74
+ cornerBackButtonAnimationEnabled: false,
75
+ triggerAnimationFinishedDispatcher: false,
76
+ dialogContainerOverflowDisabled: false,
77
+ hideMobileBottomButtonSection: false,
78
+ });
79
+ const [stepAnimationFinishedTrigger, setStepAnimationFinishedTrigger] =
80
+ useState(0);
81
+ const [dialogVerticalHeight, setDialogVerticalHeight] = useState(300);
82
+ const [currentStepRef, setCurrentStepRef] = useState({});
83
+ const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
84
+ const [buttonsConfiguration, updateButtonsConfigurationState] = useState(
85
+ buttonsConfigurationDefault
86
+ );
87
+ const [buttonControllingStep, updateButtonControllingStep] =
88
+ useReferredState("");
89
+ const [isMultiStep, setIsMultiStep] = useState(false);
90
+
91
+ const dialogWrapperRef = useRef();
92
+ const dialogRef = useRef();
93
+ const scrollableRef = useRef();
94
+ const resizeObserverRef = useRef(null);
95
+
96
+ const updateButtonsConfiguration = (newConfiguration, stepName) => {
97
+ if (
98
+ buttonControllingStep.current === stepName ||
99
+ buttonControllingStep.current === ""
100
+ )
101
+ updateButtonsConfigurationState(newConfiguration);
102
+ };
103
+
104
+ useEffect(() => {
105
+ if (showDialog) disableAnimation();
106
+ setShowDialogProcessed(showDialog);
107
+ showDialog ? dispatchDialogOpened() : dispatchDialogClosed();
108
+ // eslint-disable-next-line react-hooks/exhaustive-deps
109
+ }, [showDialog]);
110
+
111
+ const showCornerButtonForStep = (stepName, stepButtonShowParam) => {
112
+ if (stepName !== "") {
113
+ let stepNameId = steps.findIndex((step) => step.name === stepName);
114
+ return stepButtonShowParam !== null &&
115
+ typeof stepButtonShowParam === "boolean"
116
+ ? stepButtonShowParam
117
+ : stepNameId > steps.findIndex((step) => step.hidden === false);
118
+ } else {
119
+ return false;
120
+ }
121
+ };
122
+
123
+ const nextStep = (animationControlEnabled = true) => {
124
+ const nextStep = steps.find(
125
+ (step, index) => index > currentStep && step.hidden === false
126
+ );
127
+ if (nextStep) {
128
+ goToStep(nextStep.name, animationControlEnabled);
129
+ return true;
130
+ } else {
131
+ return false;
132
+ }
133
+ };
134
+
135
+ const previousStep = (animationControlEnabled = true) => {
136
+ const prevSteps = steps
137
+ .map((step, index) => {
138
+ return index < currentStep && step.hidden === false
139
+ ? step.name
140
+ : undefined;
141
+ })
142
+ .filter((item) => typeof item !== "undefined");
143
+
144
+ if (prevSteps.length > 0) {
145
+ goToStep(prevSteps[prevSteps.length - 1], animationControlEnabled);
146
+ return true;
147
+ } else {
148
+ return false;
149
+ }
150
+ };
151
+
152
+ const getStepClass = (stepName) => {
153
+ if (steps.length > 1) {
154
+ let stepNameId = steps.findIndex((step) => step.name === stepName);
155
+ let stepClass =
156
+ currentStep > stepNameId
157
+ ? "prev"
158
+ : currentStep === stepNameId
159
+ ? "current"
160
+ : "next";
161
+ return stepClass;
162
+ } else {
163
+ return "current";
164
+ }
165
+ };
166
+
167
+ const isCurrentStep = (stepName) => {
168
+ return steps[currentStep].name === stepName;
169
+ };
170
+
171
+ const toFirstStep = (animationControlEnabled = true) => {
172
+ if (animationControlEnabled) enableAnimation();
173
+ setCurrentStep(steps.findIndex((step) => step.hidden === false));
174
+ };
175
+
176
+ const goToStep = (stepName, animationControlEnabled = true) => {
177
+ if (animationControlEnabled) enableAnimation();
178
+ try {
179
+ let stepNameId = steps.findIndex((step) => step.name === stepName);
180
+ setCurrentStep(stepNameId);
181
+ } catch (e) {
182
+ logErrorOrOutputToConsole(e);
183
+ }
184
+ };
185
+
186
+ const provideCurrentStepRef = (ref) => {
187
+ setCurrentStepRef(ref);
188
+ };
189
+
190
+ const disableAnimation = (dispatch = false) => {
191
+ updateAnimationConfiguration((prev) => {
192
+ return {
193
+ ...prev,
194
+ animateHeightTransitionEnabled: false,
195
+ wrapperWidthAnimationEnabled: false,
196
+ currentStepAnimationEnabled: false,
197
+ cornerBackButtonAnimationEnabled: false,
198
+ dialogContainerOverflowDisabled: false,
199
+ hideMobileBottomButtonSection: false,
200
+ };
201
+ });
202
+ if (dispatch) {
203
+ updateAnimationConfiguration((prev) => {
204
+ return {
205
+ ...prev,
206
+ triggerAnimationFinishedDispatcher: true,
207
+ };
208
+ });
209
+ }
210
+ };
211
+
212
+ useEffect(() => {
213
+ if (animationConfiguration.triggerAnimationFinishedDispatcher) {
214
+ setStepAnimationFinishedTrigger((prev) => prev + 1);
215
+ updateAnimationConfiguration((prev) => {
216
+ return {
217
+ ...prev,
218
+ triggerAnimationFinishedDispatcher: false,
219
+ };
220
+ });
221
+ }
222
+ // eslint-disable-next-line react-hooks/exhaustive-deps
223
+ }, [animationConfiguration]);
224
+
225
+ const enableAnimation = () => {
226
+ updateAnimationConfiguration((prev) => {
227
+ return {
228
+ ...prev,
229
+ animateHeightTransitionEnabled: true,
230
+ wrapperWidthAnimationEnabled: true,
231
+ currentStepAnimationEnabled: true,
232
+ cornerBackButtonAnimationEnabled: true,
233
+ dialogContainerOverflowDisabled: true,
234
+ hideMobileBottomButtonSection: true,
235
+ };
236
+ });
237
+ };
238
+
239
+ const scrollDialogToTop = () => {
240
+ animateScrollTo(0, {
241
+ elementToScroll: dialogRef?.current,
242
+ minDuration: DIALOG_TRANSITION_STEP_DURATION,
243
+ maxDuration: DIALOG_TRANSITION_STEP_DURATION,
244
+ });
245
+ animateScrollTo(0, {
246
+ elementToScroll: scrollableRef?.current,
247
+ minDuration: DIALOG_TRANSITION_STEP_DURATION,
248
+ maxDuration: DIALOG_TRANSITION_STEP_DURATION,
249
+ });
250
+ };
251
+
252
+ const clearButtonsConfiguration = () => {
253
+ updateButtonsConfigurationState(buttonsConfigurationDefault);
254
+ };
255
+
256
+ useEffect(() => {
257
+ initControls &&
258
+ initControls((prev) => {
259
+ return {
260
+ ...prev,
261
+ stepAnimationFinishedTrigger: stepAnimationFinishedTrigger,
262
+ };
263
+ });
264
+ // eslint-disable-next-line react-hooks/exhaustive-deps
265
+ }, [stepAnimationFinishedTrigger]);
266
+
267
+ useEffect(() => {
268
+ initControls &&
269
+ initControls((prev) => {
270
+ return {
271
+ ...prev,
272
+ animationConfiguration: animationConfiguration,
273
+ };
274
+ });
275
+ // eslint-disable-next-line react-hooks/exhaustive-deps
276
+ }, [animationConfiguration]);
277
+
278
+ useEffect(() => {
279
+ if (currentStepRef.current) {
280
+ resizeObserverRef.current = new ResizeObserver((entries = []) => {
281
+ entries.forEach((entry) => {
282
+ const { width, height } = entry.contentRect;
283
+ setDimensions({ width, height });
284
+ });
285
+ });
286
+ if (currentStepRef.current)
287
+ resizeObserverRef.current.observe(currentStepRef.current);
288
+ return () => {
289
+ if (resizeObserverRef.current)
290
+ resizeObserverRef.current.disconnect();
291
+ };
292
+ }
293
+ // eslint-disable-next-line react-hooks/exhaustive-deps
294
+ }, [currentStepRef]);
295
+
296
+ useEffect(() => {
297
+ setDialogVerticalHeight((prev) =>
298
+ prev !== 0 && dimensions.height === 0 ? prev : dimensions.height
299
+ );
300
+ // eslint-disable-next-line react-hooks/exhaustive-deps
301
+ }, [dimensions]);
302
+
303
+ useEffect(() => {
304
+ const childrenFormatted = children.length > 1 ? children : [children];
305
+
306
+ let stepsArr = childrenFormatted.map((child) => {
307
+ return {
308
+ name: child.props.stepName,
309
+ hidden: !!child.props.hidden,
310
+ };
311
+ });
312
+ setSteps(stepsArr);
313
+
314
+ // eslint-disable-next-line react-hooks/exhaustive-deps
315
+ }, []);
316
+
317
+ useEffect(() => {
318
+ setIsMultiStep(typeof initControls === "function");
319
+ // eslint-disable-next-line react-hooks/exhaustive-deps
320
+ }, [initControls]);
321
+
322
+ useEffect(() => {
323
+ if (steps)
324
+ initControls &&
325
+ initControls({
326
+ nextStep: nextStep,
327
+ previousStep: previousStep,
328
+ currentStep: currentStep,
329
+ isCurrentStep: isCurrentStep,
330
+ getStepClass: getStepClass,
331
+ updateDialogConfiguration: updateDialogConfiguration,
332
+ toFirstStep: toFirstStep,
333
+ goToStep: goToStep,
334
+ provideCurrentStepRef: provideCurrentStepRef,
335
+ animationConfiguration: animationConfiguration,
336
+ disableAnimation: disableAnimation,
337
+ enableAnimation: enableAnimation,
338
+ showCornerButtonForStep: showCornerButtonForStep,
339
+ stepAnimationFinishedTrigger: stepAnimationFinishedTrigger,
340
+ scrollDialogToTop: scrollDialogToTop,
341
+ updateButtonsConfiguration: updateButtonsConfiguration,
342
+ clearButtonsConfiguration: clearButtonsConfiguration,
343
+ buttonControllingStep: buttonControllingStep.current,
344
+ updateButtonControllingStep: updateButtonControllingStep,
345
+ updateAnimationConfiguration: updateAnimationConfiguration,
346
+ inline: inline,
347
+ });
348
+ // eslint-disable-next-line react-hooks/exhaustive-deps
349
+ }, [currentStep, steps]);
350
+
351
+ useEffect(() => {
352
+ return () => {
353
+ clearAllBodyScrollLocks();
354
+ updateButtonControllingStep("");
355
+ clearButtonsConfiguration();
356
+ };
357
+ // eslint-disable-next-line react-hooks/exhaustive-deps
358
+ }, []);
359
+
360
+ return (
361
+ <CSSTransition
362
+ in={showDialogProcessed}
363
+ timeout={DIALOG_TRANSITION_STEP_DURATION}
364
+ classNames={
365
+ inline
366
+ ? undefined
367
+ : {
368
+ enter: s["dialog-transition-enter"],
369
+ enterActive: s["dialog-transition-enter-active"],
370
+ exit: s["dialog-transition-exit"],
371
+ exitActive: s["dialog-transition-exit-active"],
372
+ }
373
+ }
374
+ unmountOnExit
375
+ onExited={() => {
376
+ disableAnimation(false);
377
+ clearButtonsConfiguration();
378
+ updateButtonControllingStep("");
379
+ }}
380
+ onExiting={() => {
381
+ if (inline) return;
382
+ enableBodyScroll(scrollableRef.current);
383
+ enableBodyScroll(dialogRef.current);
384
+ }}
385
+ onEntered={() => {
386
+ if (inline) return;
387
+ disableBodyScroll(scrollableRef.current);
388
+ disableBodyScroll(dialogRef.current);
389
+ }}
390
+ >
391
+ <div
392
+ className={
393
+ s["dialog"] +
394
+ " " +
395
+ (dialogVerticalHeight > 1 || !isMultiStep
396
+ ? ""
397
+ : " " + s["hidden"]) +
398
+ (animationConfiguration.dialogContainerOverflowDisabled
399
+ ? " " + s["vertical-overflow-disabled"]
400
+ : "") +
401
+ (inline ? " " + s["inline"] : "")
402
+ }
403
+ ref={dialogRef}
404
+ >
405
+ <div
406
+ className={
407
+ s["scrollable"] + (inline ? " " + s["inline"] : "")
408
+ }
409
+ ref={scrollableRef}
410
+ >
411
+ <div
412
+ className={
413
+ s["dialog-wrapper"] +
414
+ (animationConfiguration.wrapperWidthAnimationEnabled
415
+ ? ""
416
+ : " " + s["animation-disabled"]) +
417
+ (inline ? " " + s["inline"] : "")
418
+ }
419
+ ref={dialogWrapperRef}
420
+ style={
421
+ dialogConfiguration.customWidth !== ""
422
+ ? { maxWidth: dialogConfiguration.customWidth }
423
+ : width !== ""
424
+ ? { maxWidth: width }
425
+ : null
426
+ }
427
+ >
428
+ <AnimateHeight
429
+ duration={
430
+ animationConfiguration.animateHeightTransitionEnabled
431
+ ? animationConfiguration.animateHeightTransitionSpeed
432
+ : 0
433
+ }
434
+ delay={
435
+ animationConfiguration.animateHeightTransitionEnabled
436
+ ? animationConfiguration.animateHeightDelay
437
+ : 0
438
+ }
439
+ height={isMultiStep ? dialogVerticalHeight : "auto"}
440
+ contentClassName={s["dialog-wrapper-rah-content"]}
441
+ >
442
+ {inline ? (
443
+ ""
444
+ ) : (
445
+ <div className={s["dialog-wrapper-close"]}>
446
+ <Close
447
+ color="dark"
448
+ onClick={(e) => onClose()}
449
+ large
450
+ />
451
+ </div>
452
+ )}
453
+ {children}
454
+ </AnimateHeight>
455
+ </div>
456
+ </div>
457
+ {
458
+ <CSSTransition
459
+ in={
460
+ (!!buttonsConfiguration.primaryButtonTitle ||
461
+ !!buttonsConfiguration.secondaryButtonTitle) &&
462
+ !animationConfiguration.hideMobileBottomButtonSection &&
463
+ buttonsConfiguration.fixedButtonsEnabled
464
+ }
465
+ timeout={DIALOG_TRANSITION_STEP_DURATION}
466
+ // classNames={s["fixed-buttons-container"]}
467
+ classNames={{
468
+ enter: s["fixed-buttons-container-enter"],
469
+ enterActive:
470
+ s["fixed-buttons-container-enter-active"],
471
+ enterDone: s["fixed-buttons-container-enter-done"],
472
+ exit: s["fixed-buttons-container-exit"],
473
+ exitActive:
474
+ s["fixed-buttons-container-exit-active"],
475
+ exitDone: s["fixed-buttons-container-exit-done"],
476
+ }}
477
+ unmountOnExit
478
+ >
479
+ <div className={s["fixed-buttons-container"]}>
480
+ <DialogButtons {...buttonsConfiguration} />
481
+ </div>
482
+ </CSSTransition>
483
+ }
484
+ </div>
485
+ </CSSTransition>
486
+ );
487
+ };
488
+
489
+ Dialog.propTypes = {
490
+ showDialog: PropTypes.bool,
491
+ onClose: PropTypes.func.isRequired,
492
+ initControls: PropTypes.func,
493
+ children: PropTypes.node,
494
+ width: PropTypes.oneOf([
495
+ "550px",
496
+ "600px",
497
+ "700px",
498
+ "750px",
499
+ "800px",
500
+ "1000px",
501
+ ]),
502
+ dispatchDialogOpened: PropTypes.func,
503
+ dispatchDialogClosed: PropTypes.func,
504
+ inline: PropTypes.bool,
505
+ };
506
+
507
+ Dialog.defaultProps = {
508
+ showDialog: false,
509
+ onClose: () => {},
510
+ initControls: null,
511
+ children: [],
512
+ dispatchDialogOpened: () => {},
513
+ dispatchDialogClosed: () => {},
514
+ inline: false,
515
+ };
@@ -0,0 +1,122 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+
4
+ import { useCallHandlingErrors } from "../../../hooks/useCallHandlingErrors";
5
+
6
+ import s from "./dialog-buttons.module.scss";
7
+ import { LinkButton } from "../../../atoms/buttons/LinkButton/LinkButton";
8
+ import { Button } from "../../../atoms/buttons/Button/Button";
9
+
10
+ /**
11
+ * Renders a dialog component with configurable primary and secondary buttons.
12
+ * This component allows for a variety of configurations including different button modes,
13
+ * sizes, and actions. It's designed to handle user interactions effectively with error management.
14
+ *
15
+ * @component
16
+ * @param {Object} props - Props for configuring the DialogButtons.
17
+ * @param {string} [props.primaryButtonTitle] - The text to display on the primary button.
18
+ * @param {Function} props.primaryButtonOnClick - Function to call when the primary button is clicked.
19
+ * @param {boolean} [props.primaryButtonLoader=false] - Whether to show a loader on the primary button.
20
+ * @param {string} [props.primaryButtonTo] - The URL or route the primary button should navigate to.
21
+ * @param {Function} [props.primaryButtonSetClickTrigger] - Additional click handling logic for the primary button.
22
+ * @param {string} [props.secondaryButtonTitle] - The text to display on the secondary button.
23
+ * @param {Function} props.secondaryButtonOnClick - Function to call when the secondary button is clicked.
24
+ * @param {string} [props.secondaryButtonTo] - The URL or route the secondary button should navigate to.
25
+ * @param {boolean} [props.secondaryButtonBig=false] - Makes the secondary button larger for visual emphasis.
26
+ * @param {boolean} [props.withBackgroundImage=false] - Indicates if the button should adjust its styling for background images.
27
+ * @param {boolean} [props.hideOnMobiles=false] - Whether to hide the buttons on mobile devices for responsive designs.
28
+ * @returns {React.Element} The rendered component with two buttons based on provided props.
29
+ */
30
+ export const DialogButtons = ({
31
+ primaryButtonTitle,
32
+ primaryButtonOnClick,
33
+ primaryButtonLoader = false,
34
+ primaryButtonTo,
35
+ primaryButtonSetClickTrigger,
36
+ secondaryButtonTitle,
37
+ secondaryButtonOnClick,
38
+ secondaryButtonTo,
39
+ secondaryButtonBig = false,
40
+ withBackgroundImage = false,
41
+ hideOnMobiles = false,
42
+ }) => {
43
+ const callHandlingErrors = useCallHandlingErrors();
44
+
45
+ return (
46
+ <>
47
+ <div
48
+ className={
49
+ s["dialog-buttons"] +
50
+ (hideOnMobiles ? " " + s["hide-on-mobiles"] : "") +
51
+ (secondaryButtonBig ? " " + s["space-between-layout"] : "")
52
+ }
53
+ >
54
+ {secondaryButtonTitle ? (
55
+ secondaryButtonTo ? (
56
+ <Button
57
+ mode="primary-transparent"
58
+ to={secondaryButtonTo}
59
+ size="lg"
60
+ loader={false}
61
+ fullWidthOnMobiles
62
+ content={secondaryButtonTitle}
63
+ onClick={secondaryButtonOnClick}
64
+ handleError={callHandlingErrors}
65
+ />
66
+ ) : secondaryButtonBig ? (
67
+ <Button
68
+ mode="transparent"
69
+ size="lg"
70
+ loader={false}
71
+ fullWidthOnMobiles
72
+ content={secondaryButtonTitle}
73
+ onClick={secondaryButtonOnClick}
74
+ handleError={callHandlingErrors}
75
+ />
76
+ ) : (
77
+ <LinkButton
78
+ onClick={secondaryButtonOnClick}
79
+ content={secondaryButtonTitle}
80
+ isColored={!withBackgroundImage}
81
+ />
82
+ )
83
+ ) : null}
84
+
85
+ {primaryButtonTitle ? (
86
+ <Button
87
+ mode="primary"
88
+ size="lg"
89
+ onClick={primaryButtonOnClick}
90
+ loader={primaryButtonLoader}
91
+ to={primaryButtonTo}
92
+ fullWidthOnMobiles
93
+ content={primaryButtonTitle}
94
+ setClickTrigger={primaryButtonSetClickTrigger}
95
+ handleError={callHandlingErrors}
96
+ />
97
+ ) : null}
98
+ </div>
99
+ </>
100
+ );
101
+ };
102
+
103
+ DialogButtons.propTypes = {
104
+ primaryButtonTitle: PropTypes.string,
105
+ primaryButtonOnClick: PropTypes.func,
106
+ primaryButtonLoader: PropTypes.bool,
107
+ primaryButtonTo: PropTypes.string,
108
+ primaryButtonSetClickTrigger: PropTypes.func,
109
+ secondaryButtonTitle: PropTypes.string,
110
+ secondaryButtonOnClick: PropTypes.func,
111
+ secondaryButtonTo: PropTypes.string,
112
+ secondaryButtonBig: PropTypes.bool,
113
+ withBackgroundImage: PropTypes.bool,
114
+ hideOnMobiles: PropTypes.bool,
115
+ };
116
+
117
+ DialogButtons.defaultProps = {
118
+ primaryButtonLoader: false,
119
+ secondaryButtonBig: false,
120
+ withBackgroundImage: false,
121
+ hideOnMobiles: false,
122
+ };
@@ -0,0 +1,25 @@
1
+ @import "../../../../../styles/index";
2
+
3
+ .dialog-buttons {
4
+ display: flex;
5
+ justify-content: flex-end;
6
+ align-items: center;
7
+ gap: Margin("5");
8
+ width: 100%;
9
+ flex-wrap: wrap-reverse;
10
+
11
+ @media (max-width: $phone-width) {
12
+ flex-direction: column-reverse;
13
+ gap: Margin("5");
14
+ }
15
+
16
+ &.hide-on-mobiles {
17
+ @media (max-width: $tablet-width) {
18
+ display: none;
19
+ }
20
+ }
21
+
22
+ &.space-between-layout {
23
+ justify-content: space-between;
24
+ }
25
+ }