@rabbitio/ui-kit 1.0.0-beta.42 → 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.
- package/.gitlab-ci.yml +29 -0
- package/.husky/commit-msg +8 -0
- package/.husky/pre-push +1 -0
- package/README.md +13 -4
- package/dist/index.cjs +1545 -148
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +23630 -0
- package/dist/index.css.map +1 -1
- package/dist/index.modern.js +1318 -103
- package/dist/index.modern.js.map +1 -1
- package/dist/index.module.js +1534 -149
- package/dist/index.module.js.map +1 -1
- package/dist/index.umd.js +1544 -152
- package/dist/index.umd.js.map +1 -1
- package/package.json +16 -3
- package/src/assets/image/icons/arrow-tosca.svg +3 -0
- package/src/assets/image/icons/arrow-white.svg +14 -0
- package/src/assets/image/icons/failed-validation-icon.svg +15 -0
- package/src/assets/image/icons/successful-validation-icon.svg +10 -0
- package/src/common/amountUtils.js +4 -2
- package/src/common/tests/integration/external-apis/ipAddressProviders/getClientIpAddress.test.js +14 -0
- package/src/common/utils/cache.js +4 -4
- package/src/components/atoms/BackgroundTitle/BackgroundTitle.jsx +44 -0
- package/src/components/atoms/BackgroundTitle/background-title.module.scss +52 -0
- package/src/components/atoms/Validation/Validation.jsx +130 -0
- package/src/components/atoms/Validation/validation.module.scss +15 -0
- package/src/components/atoms/buttons/Close/Close.jsx +64 -0
- package/src/components/atoms/buttons/Close/close.module.scss +75 -0
- package/src/components/atoms/buttons/LinkButton/LinkButton.jsx +121 -0
- package/src/components/atoms/buttons/LinkButton/link-button.module.scss +45 -0
- package/src/components/organisms/Dialog/Dialog.jsx +515 -0
- package/src/components/organisms/Dialog/DialogButtons/DialogButtons.jsx +122 -0
- package/src/components/organisms/Dialog/DialogButtons/dialog-buttons.module.scss +25 -0
- package/src/components/organisms/Dialog/DialogStep/DialogStep.jsx +664 -0
- package/src/components/organisms/Dialog/DialogStep/dialog-step.module.scss +362 -0
- package/src/components/organisms/Dialog/dialog.module.scss +223 -0
- package/src/components/tests/utils/inputValueProviders/provideFormatOfFloatValueByInputString.test.js +139 -0
- package/src/components/tests/utils/urlQueryUtils/getQueryParameterValues.test.js +71 -0
- package/src/components/tests/utils/urlQueryUtils/saveQueryParameterAndValues.test.js +144 -0
- package/src/components/utils/inputValueProviders.js +58 -0
- package/src/constants/organisms/dialog/DialogStep/dialogStep.js +1 -0
- package/src/constants/organisms/dialog/dialog.js +29 -0
- package/src/index.js +11 -0
- package/src/robustExteranlApiCallerService/robustExternalAPICallerService.js +3 -1
- package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/_performCallAttempt.test.js +787 -0
- package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/callExternalAPI/callExternalAPI.test.js +745 -0
- package/src/robustExteranlApiCallerService/tests/robustExternalAPICallerService/robustExternalAPICallerService/constructor.test.js +31 -0
- package/src/swaps-lib/external-apis/swapProvider.js +17 -4
- package/src/swaps-lib/external-apis/swapspaceSwapProvider.js +91 -30
- package/src/swaps-lib/models/baseSwapCreationInfo.js +4 -1
- package/src/swaps-lib/models/existingSwap.js +3 -0
- package/src/swaps-lib/models/existingSwapWithFiatData.js +4 -0
- package/src/swaps-lib/services/publicSwapService.js +32 -4
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/_fetchSupportedCurrenciesIfNeeded.test.js +506 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/createSwap.test.js +1311 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getAllSupportedCurrencies.test.js +76 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getDepositCurrencies.test.js +82 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getSwapInfo.test.js +1892 -0
- package/src/swaps-lib/test/external-apis/swapspaceSwapProvider/getWithdrawalCurrencies.test.js +111 -0
- package/src/swaps-lib/test/utils/swapUtils/safeHandleRequestsLimitExceeding.test.js +88 -0
- package/stories/stubs/exampleContent.jsx +20 -0
- package/styles/fonts/NunitoSans-Bold.ttf +0 -0
- package/styles/fonts/NunitoSans-ExtraBold.ttf +0 -0
- package/styles/fonts/NunitoSans-Light.ttf +0 -0
- package/styles/fonts/NunitoSans-Regular.ttf +0 -0
- package/styles/fonts/NunitoSans-SemiBold.ttf +0 -0
- package/styles/index.scss +14 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rabbitio/ui-kit",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.45",
|
|
4
4
|
"description": "Rabbit.io react.js components kit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -15,10 +15,13 @@
|
|
|
15
15
|
"./index.css": "./dist/index.css"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
|
+
"prepare": "husky",
|
|
18
19
|
"build": "rm -rf dist && microbundle --no-compress --jsx React.createElement --jsxFragment React.Fragment --jsxImportSource react --globals react/jsx-runtime=jsx --visualize",
|
|
19
20
|
"prepublish": "npm run build",
|
|
20
21
|
"storybook": "storybook dev -p 6006",
|
|
21
|
-
"build-storybook": "storybook build"
|
|
22
|
+
"build-storybook": "storybook build",
|
|
23
|
+
"test-watching": "vitest",
|
|
24
|
+
"test": "vitest run --coverage"
|
|
22
25
|
},
|
|
23
26
|
"keywords": [
|
|
24
27
|
"rabbit.io",
|
|
@@ -38,12 +41,17 @@
|
|
|
38
41
|
"react-dom": ">=18.2.0"
|
|
39
42
|
},
|
|
40
43
|
"dependencies": {
|
|
44
|
+
"animated-scroll-to": "2.3.0",
|
|
41
45
|
"axios": "1.6.7",
|
|
42
46
|
"bignumber.js": "9.1.2",
|
|
47
|
+
"body-scroll-lock": "3.1.5",
|
|
43
48
|
"eventbusjs": "0.2.0",
|
|
44
49
|
"jshashes": "1.0.8",
|
|
45
50
|
"react": ">=18.2.0",
|
|
51
|
+
"react-animate-height": "3.2.3",
|
|
46
52
|
"react-dom": ">=18.2.0",
|
|
53
|
+
"react-transition-group": "4.4.5",
|
|
54
|
+
"resize-observer-polyfill": "1.5.1",
|
|
47
55
|
"uuid": "9.0.0"
|
|
48
56
|
},
|
|
49
57
|
"devDependencies": {
|
|
@@ -59,14 +67,19 @@
|
|
|
59
67
|
"@storybook/react": "^7.6.6",
|
|
60
68
|
"@storybook/react-webpack5": "^7.6.6",
|
|
61
69
|
"@storybook/test": "^7.6.6",
|
|
70
|
+
"@vitest/coverage-v8": "^1.5.0",
|
|
71
|
+
"husky": "^9.0.11",
|
|
62
72
|
"microbundle": "^0.15.1",
|
|
63
73
|
"prettier": "^3.1.1",
|
|
64
74
|
"prop-types": "^15.8.1",
|
|
65
75
|
"resolve-url-loader": "^5.0.0",
|
|
66
76
|
"sass": "^1.70.0",
|
|
67
77
|
"sass-loader": "^14.1.0",
|
|
78
|
+
"should": "13.2.3",
|
|
79
|
+
"sinon": "17.0.1",
|
|
68
80
|
"storybook": "^7.6.6",
|
|
69
|
-
"style-loader": "^3.3.3"
|
|
81
|
+
"style-loader": "^3.3.3",
|
|
82
|
+
"vitest": "1.5.0"
|
|
70
83
|
},
|
|
71
84
|
"prettier": {
|
|
72
85
|
"trailingComma": "es5",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<svg
|
|
2
|
+
width="16"
|
|
3
|
+
height="16"
|
|
4
|
+
viewBox="0 0 16 16"
|
|
5
|
+
fill="none"
|
|
6
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
7
|
+
>
|
|
8
|
+
<path
|
|
9
|
+
d="M12.2431 6L8.00045 10.2426L3.75781 6"
|
|
10
|
+
stroke="#fff" stroke-width="2"
|
|
11
|
+
stroke-linecap="round"
|
|
12
|
+
stroke-linejoin="round"
|
|
13
|
+
/>
|
|
14
|
+
</svg>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect opacity="0.8" x="1.5" y="1.5" width="24" height="24" rx="12" fill="#DAF1FE"/>
|
|
3
|
+
<path d="M12.3259 10.5855C12.2575 9.8896 12.8063 9.28745 13.5055 9.29121C14.2008 9.29495 14.7418 9.8964 14.6722 10.5881L14.1937 15.3431C14.1575 15.7026 13.855 15.9762 13.4937 15.9762C13.1319 15.9762 12.829 15.7017 12.7936 15.3415L12.3259 10.5855Z" fill="url(#paint0_linear)"/>
|
|
4
|
+
<path d="M13.514 17.1182C14.1325 17.1182 14.634 17.6196 14.634 18.2382C14.634 18.8567 14.1325 19.3582 13.514 19.3582H13.486C12.8674 19.3582 12.366 18.8567 12.366 18.2382C12.366 17.6196 12.8674 17.1182 13.486 17.1182H13.514Z" fill="url(#paint1_linear)"/>
|
|
5
|
+
<defs>
|
|
6
|
+
<linearGradient id="paint0_linear" x1="17.3456" y1="14.0483" x2="11.6522" y2="12.8896" gradientUnits="userSpaceOnUse">
|
|
7
|
+
<stop stop-color="#55E7D9"/>
|
|
8
|
+
<stop offset="1" stop-color="#54B4FF"/>
|
|
9
|
+
</linearGradient>
|
|
10
|
+
<linearGradient id="paint1_linear" x1="17.3456" y1="14.2383" x2="11.6522" y2="13.0796" gradientUnits="userSpaceOnUse">
|
|
11
|
+
<stop stop-color="#55E7D9"/>
|
|
12
|
+
<stop offset="1" stop-color="#54B4FF"/>
|
|
13
|
+
</linearGradient>
|
|
14
|
+
</defs>
|
|
15
|
+
</svg>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect opacity="0.8" x="1.5" y="1.5" width="24" height="24" rx="12" fill="#DAF1FE"/>
|
|
3
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.8703 15.7837L9.64348 13.5569C9.30357 13.217 8.75246 13.217 8.41255 13.5569C8.07264 13.8968 8.07264 14.4479 8.41255 14.7878L11.2351 17.6104C11.5672 17.9425 12.103 17.9512 12.4457 17.6301L18.4492 12.0049C18.8 11.6762 18.8179 11.1254 18.4892 10.7746C18.1605 10.4238 17.6097 10.4059 17.2589 10.7346L11.8703 15.7837Z" fill="url(#paint0_linear)"/>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="paint0_linear" x1="19.8333" y1="18.9098" x2="15.586" y2="7.2736" gradientUnits="userSpaceOnUse">
|
|
6
|
+
<stop stop-color="#55E7D9"/>
|
|
7
|
+
<stop offset="1" stop-color="#54B4FF"/>
|
|
8
|
+
</linearGradient>
|
|
9
|
+
</defs>
|
|
10
|
+
</svg>
|
|
@@ -273,11 +273,13 @@ export class AmountUtils {
|
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
/**
|
|
276
|
+
* Returns integer part of number as a string.
|
|
277
|
+
*
|
|
276
278
|
* @param amount {BigNumber|number|string|null|undefined} The number value to be trimmed.
|
|
277
279
|
* HEX strings also allowed "0x..." and JS hex numbers
|
|
278
280
|
* @return {string|null}
|
|
279
281
|
*/
|
|
280
|
-
static
|
|
282
|
+
static toIntegerString(amount) {
|
|
281
283
|
return this.trim(amount, 0);
|
|
282
284
|
}
|
|
283
285
|
|
|
@@ -392,7 +394,7 @@ export class AmountUtils {
|
|
|
392
394
|
leftNumber = leftNumber.times(multiplier);
|
|
393
395
|
}
|
|
394
396
|
}
|
|
395
|
-
const leftAmountString = AmountUtils.
|
|
397
|
+
const leftAmountString = AmountUtils.toIntegerString(leftNumber);
|
|
396
398
|
const rightAmountString =
|
|
397
399
|
right != null
|
|
398
400
|
? right.toFixed(
|
package/src/common/tests/integration/external-apis/ipAddressProviders/getClientIpAddress.test.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import should from "should";
|
|
2
|
+
|
|
3
|
+
import { describe, it } from "vitest";
|
|
4
|
+
import { IpAddressProvider } from "../../../../external-apis/ipAddressProviders.js";
|
|
5
|
+
|
|
6
|
+
describe("ipAddressProviders", function () {
|
|
7
|
+
describe("#getClientIpAddress", function () {
|
|
8
|
+
it("Should successfully retrieve IP address", async function () {
|
|
9
|
+
(
|
|
10
|
+
await IpAddressProvider.getClientIpAddress()
|
|
11
|
+
).should.not.be.empty();
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -9,10 +9,10 @@ import { Logger } from "./logging/logger.js";
|
|
|
9
9
|
*/
|
|
10
10
|
export class Cache {
|
|
11
11
|
/**
|
|
12
|
-
* @param eventBus {EventBus} EventBus.js lib instance
|
|
13
|
-
* @param [noSessionEvents=[]] {string[]} array of events that will be treated as "no session"
|
|
12
|
+
* @param [eventBus=null] {EventBus} EventBus.js lib instance if you plan to use Cache with events handling
|
|
13
|
+
* @param [noSessionEvents=[]] {string[]} array of events that will be treated as "no session", you should pass EventBus to make it work
|
|
14
14
|
*/
|
|
15
|
-
constructor(eventBus, noSessionEvents = []) {
|
|
15
|
+
constructor(eventBus = null, noSessionEvents = []) {
|
|
16
16
|
this._cache = new Map();
|
|
17
17
|
this._eventDependentDataKeys = [];
|
|
18
18
|
this._noSessionEvents = noSessionEvents;
|
|
@@ -102,7 +102,7 @@ export class Cache {
|
|
|
102
102
|
);
|
|
103
103
|
if (eventAndKeys) {
|
|
104
104
|
eventAndKeys.push(key);
|
|
105
|
-
} else {
|
|
105
|
+
} else if (this._eventBus) {
|
|
106
106
|
this._eventDependentDataKeys.push([event, key]);
|
|
107
107
|
this._eventBus.addEventListener(event, () => {
|
|
108
108
|
try {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
|
|
4
|
+
import s from "./background-title.module.scss";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Component for displaying a title with a fancy background text, which
|
|
8
|
+
* is semi-visible. This component is designed to work with forms that
|
|
9
|
+
* have a white background, and it allows for a configuration of margins.
|
|
10
|
+
*
|
|
11
|
+
* @param {Object} props - Component props
|
|
12
|
+
* @param {string} props.text - Text to be displayed as the title
|
|
13
|
+
* @param {boolean} [props.smallMargins=false] - Whether to use smaller margins around the title
|
|
14
|
+
*/
|
|
15
|
+
export const BackgroundTitle = ({ text, smallMargins = false }) => {
|
|
16
|
+
return (
|
|
17
|
+
<div className={s["background-title"]}>
|
|
18
|
+
<div
|
|
19
|
+
className={
|
|
20
|
+
s["background-title-wrapper"] +
|
|
21
|
+
(smallMargins ? " " + s["small-margins"] : "")
|
|
22
|
+
}
|
|
23
|
+
>
|
|
24
|
+
<div
|
|
25
|
+
className={
|
|
26
|
+
s["background-title-wrapper-text"] +
|
|
27
|
+
(smallMargins ? " " + s["small-margins"] : "")
|
|
28
|
+
}
|
|
29
|
+
>
|
|
30
|
+
{text}
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
BackgroundTitle.propTypes = {
|
|
38
|
+
text: PropTypes.string.isRequired,
|
|
39
|
+
smallMargins: PropTypes.bool,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
BackgroundTitle.defaultProps = {
|
|
43
|
+
smallMargins: false,
|
|
44
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
@import "../../../../styles/index";
|
|
2
|
+
|
|
3
|
+
.background-title {
|
|
4
|
+
pointer-events: none;
|
|
5
|
+
user-select: none;
|
|
6
|
+
position: relative;
|
|
7
|
+
width: 200%;
|
|
8
|
+
font-family: NunitoSans;
|
|
9
|
+
|
|
10
|
+
&-wrapper {
|
|
11
|
+
position: absolute;
|
|
12
|
+
overflow-x: hidden;
|
|
13
|
+
width: 200%;
|
|
14
|
+
height: 90px;
|
|
15
|
+
top: 0;
|
|
16
|
+
left: 0;
|
|
17
|
+
|
|
18
|
+
@media (max-width: $phone-width) {
|
|
19
|
+
font-size: 30px;
|
|
20
|
+
line-height: 50px;
|
|
21
|
+
letter-spacing: 0.76875px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&.small-margins {
|
|
25
|
+
top: 15px;
|
|
26
|
+
left: 19px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&-text {
|
|
30
|
+
position: absolute;
|
|
31
|
+
top: 0;
|
|
32
|
+
left: 0;
|
|
33
|
+
font-size: 50px;
|
|
34
|
+
line-height: 50px;
|
|
35
|
+
font-weight: $extra-bold;
|
|
36
|
+
letter-spacing: 1.23px;
|
|
37
|
+
color: rgba(#12316b, 0.05);
|
|
38
|
+
|
|
39
|
+
&.small-margins {
|
|
40
|
+
font-size: 30px;
|
|
41
|
+
line-height: 50px;
|
|
42
|
+
letter-spacing: 0.76875px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@media (max-width: $phone-width) {
|
|
46
|
+
font-size: 30px;
|
|
47
|
+
line-height: 40px;
|
|
48
|
+
letter-spacing: 0.76875px;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
|
|
4
|
+
import s from "./validation.module.scss";
|
|
5
|
+
// import successfulValidationIcon from "../../../assets/image/icons/successful-validation-icon.svg";
|
|
6
|
+
// import failedValidationIcon from "../../../assets/image/icons/failed-validation-icon.svg";
|
|
7
|
+
|
|
8
|
+
const SuccessfulValidationIcon = () => (
|
|
9
|
+
<svg
|
|
10
|
+
width="27"
|
|
11
|
+
height="27"
|
|
12
|
+
viewBox="0 0 27 27"
|
|
13
|
+
fill="none"
|
|
14
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
15
|
+
>
|
|
16
|
+
<rect
|
|
17
|
+
opacity="0.8"
|
|
18
|
+
x="1.5"
|
|
19
|
+
y="1.5"
|
|
20
|
+
width="24"
|
|
21
|
+
height="24"
|
|
22
|
+
rx="12"
|
|
23
|
+
fill="#DAF1FE"
|
|
24
|
+
/>
|
|
25
|
+
<path
|
|
26
|
+
fill-rule="evenodd"
|
|
27
|
+
clip-rule="evenodd"
|
|
28
|
+
d="M11.8703 15.7837L9.64348 13.5569C9.30357 13.217 8.75246 13.217 8.41255 13.5569C8.07264 13.8968 8.07264 14.4479 8.41255 14.7878L11.2351 17.6104C11.5672 17.9425 12.103 17.9512 12.4457 17.6301L18.4492 12.0049C18.8 11.6762 18.8179 11.1254 18.4892 10.7746C18.1605 10.4238 17.6097 10.4059 17.2589 10.7346L11.8703 15.7837Z"
|
|
29
|
+
fill="url(#paint0_linear)"
|
|
30
|
+
/>
|
|
31
|
+
<defs>
|
|
32
|
+
<linearGradient
|
|
33
|
+
id="paint0_linear"
|
|
34
|
+
x1="19.8333"
|
|
35
|
+
y1="18.9098"
|
|
36
|
+
x2="15.586"
|
|
37
|
+
y2="7.2736"
|
|
38
|
+
gradientUnits="userSpaceOnUse"
|
|
39
|
+
>
|
|
40
|
+
<stop stop-color="#55E7D9" />
|
|
41
|
+
<stop offset="1" stop-color="#54B4FF" />
|
|
42
|
+
</linearGradient>
|
|
43
|
+
</defs>
|
|
44
|
+
</svg>
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const FailedValidationIcon = () => (
|
|
48
|
+
<svg
|
|
49
|
+
width="27"
|
|
50
|
+
height="27"
|
|
51
|
+
viewBox="0 0 27 27"
|
|
52
|
+
fill="none"
|
|
53
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
54
|
+
>
|
|
55
|
+
<rect
|
|
56
|
+
opacity="0.8"
|
|
57
|
+
x="1.5"
|
|
58
|
+
y="1.5"
|
|
59
|
+
width="24"
|
|
60
|
+
height="24"
|
|
61
|
+
rx="12"
|
|
62
|
+
fill="#DAF1FE"
|
|
63
|
+
/>
|
|
64
|
+
<path
|
|
65
|
+
d="M12.3259 10.5855C12.2575 9.8896 12.8063 9.28745 13.5055 9.29121C14.2008 9.29495 14.7418 9.8964 14.6722 10.5881L14.1937 15.3431C14.1575 15.7026 13.855 15.9762 13.4937 15.9762C13.1319 15.9762 12.829 15.7017 12.7936 15.3415L12.3259 10.5855Z"
|
|
66
|
+
fill="url(#paint0_linear)"
|
|
67
|
+
/>
|
|
68
|
+
<path
|
|
69
|
+
d="M13.514 17.1182C14.1325 17.1182 14.634 17.6196 14.634 18.2382C14.634 18.8567 14.1325 19.3582 13.514 19.3582H13.486C12.8674 19.3582 12.366 18.8567 12.366 18.2382C12.366 17.6196 12.8674 17.1182 13.486 17.1182H13.514Z"
|
|
70
|
+
fill="url(#paint1_linear)"
|
|
71
|
+
/>
|
|
72
|
+
<defs>
|
|
73
|
+
<linearGradient
|
|
74
|
+
id="paint0_linear"
|
|
75
|
+
x1="17.3456"
|
|
76
|
+
y1="14.0483"
|
|
77
|
+
x2="11.6522"
|
|
78
|
+
y2="12.8896"
|
|
79
|
+
gradientUnits="userSpaceOnUse"
|
|
80
|
+
>
|
|
81
|
+
<stop stop-color="#55E7D9" />
|
|
82
|
+
<stop offset="1" stop-color="#54B4FF" />
|
|
83
|
+
</linearGradient>
|
|
84
|
+
<linearGradient
|
|
85
|
+
id="paint1_linear"
|
|
86
|
+
x1="17.3456"
|
|
87
|
+
y1="14.2383"
|
|
88
|
+
x2="11.6522"
|
|
89
|
+
y2="13.0796"
|
|
90
|
+
gradientUnits="userSpaceOnUse"
|
|
91
|
+
>
|
|
92
|
+
<stop stop-color="#55E7D9" />
|
|
93
|
+
<stop offset="1" stop-color="#54B4FF" />
|
|
94
|
+
</linearGradient>
|
|
95
|
+
</defs>
|
|
96
|
+
</svg>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Simple validation message with an icon.
|
|
101
|
+
* It shows either a success or failure icon based on the isSuccessAlert prop.
|
|
102
|
+
*
|
|
103
|
+
* @param {Object} props - The component props.
|
|
104
|
+
* @param {string} props.text - The validation message text to display.
|
|
105
|
+
* @param {boolean} props.isSuccessAlert - Determines if the displayed alert is for a success (true) or failure (false).
|
|
106
|
+
*/
|
|
107
|
+
export const Validation = ({ text = "", isSuccessAlert }) => {
|
|
108
|
+
return (
|
|
109
|
+
<div className={s["validation"]}>
|
|
110
|
+
{isSuccessAlert ? (
|
|
111
|
+
// <img src={successfulValidationIcon} alt="validation icon" />
|
|
112
|
+
<SuccessfulValidationIcon />
|
|
113
|
+
) : (
|
|
114
|
+
// <img src={failedValidationIcon} alt="validation icon" />
|
|
115
|
+
<FailedValidationIcon />
|
|
116
|
+
)}
|
|
117
|
+
<span className={s["validation-text"]}>{text}</span>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
Validation.propTypes = {
|
|
123
|
+
text: PropTypes.string,
|
|
124
|
+
isSuccessAlert: PropTypes.bool.isRequired,
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
Validation.defaultProps = {
|
|
128
|
+
text: "",
|
|
129
|
+
isSuccessAlert: false,
|
|
130
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
@import "../../../../styles/index";
|
|
2
|
+
|
|
3
|
+
.validation {
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
margin-top: Margin("3");
|
|
7
|
+
|
|
8
|
+
&-text {
|
|
9
|
+
text-align: left;
|
|
10
|
+
color: SolidColor("sky");
|
|
11
|
+
@extend .ml-2;
|
|
12
|
+
font-size: 14px;
|
|
13
|
+
@extend %text-semibold;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
|
|
4
|
+
import s from "./close.module.scss";
|
|
5
|
+
|
|
6
|
+
import { useCallHandlingErrors } from "../../../hooks/useCallHandlingErrors";
|
|
7
|
+
|
|
8
|
+
export const CLOSE_COLORS = {
|
|
9
|
+
WHITE: "white",
|
|
10
|
+
DARK: "dark",
|
|
11
|
+
DARK_INVERT: "dark-invert",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A component for rendering a close icon that handles errors on click.
|
|
16
|
+
* This component uses an SVG to render the icon and allows customization
|
|
17
|
+
* through props for color, size, and the click event handling.
|
|
18
|
+
*
|
|
19
|
+
* @param {Object} props - The properties passed to the component.
|
|
20
|
+
* @param {string} props.color - The color theme of the close icon.
|
|
21
|
+
* Should be one of the properties of CLOSE_COLORS.
|
|
22
|
+
* @param {Function} props.onClick - The function to call when the icon is clicked.
|
|
23
|
+
* @param {boolean} props.large - Whether the icon should be displayed in a larger size.
|
|
24
|
+
*/
|
|
25
|
+
export const Close = ({
|
|
26
|
+
color = CLOSE_COLORS.WHITE,
|
|
27
|
+
onClick = () => {},
|
|
28
|
+
large = false,
|
|
29
|
+
}) => {
|
|
30
|
+
const callHandlingErrors = useCallHandlingErrors();
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<svg
|
|
34
|
+
className={
|
|
35
|
+
s["close"] + " " + s[color] + (large ? " " + s["large"] : "")
|
|
36
|
+
}
|
|
37
|
+
onClick={(e) => callHandlingErrors(onClick, e)}
|
|
38
|
+
style={{ cursor: "pointer" }}
|
|
39
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
40
|
+
viewBox={`0 0 50 50`}
|
|
41
|
+
x="0px"
|
|
42
|
+
y="0px"
|
|
43
|
+
>
|
|
44
|
+
<path
|
|
45
|
+
d="M28.228,23.986L47.092,5.122c1.172-1.171,1.172-3.071,0-4.242c-1.172-1.172-3.07-1.172-4.242,0L23.986,19.744L5.121,0.88
|
|
46
|
+
c-1.172-1.172-3.07-1.172-4.242,0c-1.172,1.171-1.172,3.071,0,4.242l18.865,18.864L0.879,42.85c-1.172,1.171-1.172,3.071,0,4.242
|
|
47
|
+
C1.465,47.677,2.233,47.97,3,47.97s1.535-0.293,2.121-0.879l18.865-18.864L42.85,47.091c0.586,0.586,1.354,0.879,2.121,0.879
|
|
48
|
+
s1.535-0.293,2.121-0.879c1.172-1.171,1.172-3.071,0-4.242L28.228,23.986z"
|
|
49
|
+
/>
|
|
50
|
+
</svg>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
Close.propTypes = {
|
|
55
|
+
color: PropTypes.oneOf(Object.values(CLOSE_COLORS)),
|
|
56
|
+
onClick: PropTypes.func,
|
|
57
|
+
large: PropTypes.bool,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
Close.defaultProps = {
|
|
61
|
+
color: CLOSE_COLORS.WHITE,
|
|
62
|
+
onClick: () => {},
|
|
63
|
+
large: false,
|
|
64
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
@import "../../../../../styles/index";
|
|
2
|
+
|
|
3
|
+
.close {
|
|
4
|
+
width: 24px;
|
|
5
|
+
height: 24px;
|
|
6
|
+
padding: 6px;
|
|
7
|
+
border-radius: 100%;
|
|
8
|
+
background-color: LightColor("grey-20");
|
|
9
|
+
opacity: 0.5;
|
|
10
|
+
transition: 0.2s all ease;
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
|
|
14
|
+
&.large {
|
|
15
|
+
width: 48px;
|
|
16
|
+
height: 48px;
|
|
17
|
+
padding: 16px;
|
|
18
|
+
|
|
19
|
+
@media (max-width: $tablet-width) {
|
|
20
|
+
width: 36px;
|
|
21
|
+
height: 36px;
|
|
22
|
+
padding: 12px;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&.white {
|
|
27
|
+
path {
|
|
28
|
+
fill: white;
|
|
29
|
+
background-color: none;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
&.dark-invert {
|
|
34
|
+
opacity: 0.5;
|
|
35
|
+
background-color: SolidColor("grey");
|
|
36
|
+
|
|
37
|
+
@media (hover: hover) {
|
|
38
|
+
&:hover {
|
|
39
|
+
opacity: 1;
|
|
40
|
+
transition: opacity 0.03s ease;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&:active {
|
|
45
|
+
opacity: 1;
|
|
46
|
+
transition: opacity 0.03s ease;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
path {
|
|
50
|
+
fill: SolidColor("lightsmoke");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&.dark {
|
|
55
|
+
box-shadow: $shadowOutlineStatic;
|
|
56
|
+
|
|
57
|
+
@media (hover: hover) {
|
|
58
|
+
&:hover {
|
|
59
|
+
opacity: 1;
|
|
60
|
+
transition: opacity 0.03s ease;
|
|
61
|
+
box-shadow: $shadowOutlineHover;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
&:active {
|
|
66
|
+
opacity: 1;
|
|
67
|
+
transition: opacity 0.03s ease;
|
|
68
|
+
box-shadow: $shadowOutlineHover;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
path {
|
|
72
|
+
fill: SolidColor("darkBlue");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import React, { useEffect, useState } from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
|
|
4
|
+
import { useCallHandlingErrors } from "../../../hooks/useCallHandlingErrors";
|
|
5
|
+
|
|
6
|
+
import s from "./link-button.module.scss";
|
|
7
|
+
import { LoadingDots } from "../../LoadingDots/LoadingDots";
|
|
8
|
+
|
|
9
|
+
export const iconRotateOptions = {
|
|
10
|
+
rotate0: "0deg",
|
|
11
|
+
rotate90: "90deg",
|
|
12
|
+
rotate180: "180deg",
|
|
13
|
+
rotate270: "270deg",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* LinkButton renders a clickable button which can optionally display an icon and loading animation.
|
|
18
|
+
* It can also be styled to be colored or disabled. This button supports rotating the icon according to specified degrees.
|
|
19
|
+
*
|
|
20
|
+
* @component
|
|
21
|
+
* @param {Object} props - Properties passed down to the component.
|
|
22
|
+
* @param {Function} props.onClick - Callback function triggered on button click. It should handle any post-click logic like resetting loading state.
|
|
23
|
+
* @param {boolean} props.isDisabled - If true, the button will be disabled and non-interactable.
|
|
24
|
+
* @param {boolean} props.isLoadable - If true, the button will display a loading indicator upon being clicked.
|
|
25
|
+
* @param {string} props.content - Text content displayed on the button.
|
|
26
|
+
* @param {boolean} props.isColored - If true, applies additional styling to the button.
|
|
27
|
+
* @param {string} props.icon - URL of an icon image to be displayed on the button.
|
|
28
|
+
* @param {string} props.iconRotate - Rotation angle for the icon. Valid values are defined in `iconRotateOptions`.
|
|
29
|
+
* @param {Object} props.IconComponent - Icon component, if SVG is imported directly.
|
|
30
|
+
*
|
|
31
|
+
* @returns {JSX.Element} A React component that renders a clickable and optionally loadable and icon-displaying button.
|
|
32
|
+
*/
|
|
33
|
+
export const LinkButton = ({
|
|
34
|
+
onClick = (resetButtonLoader) => {},
|
|
35
|
+
isDisabled = false,
|
|
36
|
+
isLoadable = false,
|
|
37
|
+
content = "",
|
|
38
|
+
isColored = true,
|
|
39
|
+
icon,
|
|
40
|
+
iconRotate,
|
|
41
|
+
IconComponent,
|
|
42
|
+
}) => {
|
|
43
|
+
const callHandlingErrors = useCallHandlingErrors();
|
|
44
|
+
|
|
45
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
46
|
+
const [processedIconRotation, setProcessedIconRotation] = useState(null);
|
|
47
|
+
|
|
48
|
+
const handleClick = () => {
|
|
49
|
+
callHandlingErrors(() => {
|
|
50
|
+
if (!isDisabled) {
|
|
51
|
+
if (isLoadable) {
|
|
52
|
+
setIsLoading(true);
|
|
53
|
+
}
|
|
54
|
+
// TODO: [bug, moderate] Click can be called when there isLoading=true task_id=a15979a4ca2042b29dfd1d128a16c281
|
|
55
|
+
onClick(() => setIsLoading(false));
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (
|
|
62
|
+
iconRotate &&
|
|
63
|
+
Object.keys(iconRotateOptions).find(
|
|
64
|
+
(key) => iconRotateOptions[key] === iconRotate
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
setProcessedIconRotation(iconRotate);
|
|
68
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
69
|
+
}, [iconRotate]);
|
|
70
|
+
|
|
71
|
+
return isLoading ? (
|
|
72
|
+
<LoadingDots isColored={true} />
|
|
73
|
+
) : (
|
|
74
|
+
<div
|
|
75
|
+
className={
|
|
76
|
+
s["link-button"] +
|
|
77
|
+
` ${
|
|
78
|
+
processedIconRotation &&
|
|
79
|
+
processedIconRotation !== iconRotateOptions.rotate0
|
|
80
|
+
? " " + s["icon-rotate-" + processedIconRotation]
|
|
81
|
+
: ""
|
|
82
|
+
} ${isDisabled ? " " + s["disabled"] : ""}`
|
|
83
|
+
}
|
|
84
|
+
onClick={handleClick}
|
|
85
|
+
>
|
|
86
|
+
{icon ? <img src={icon} alt="link button alt" /> : null}
|
|
87
|
+
{IconComponent ? <IconComponent /> : null}
|
|
88
|
+
<p
|
|
89
|
+
className={
|
|
90
|
+
s["link-button-text"] +
|
|
91
|
+
` ${isColored ? s["colored"] : ""} ${
|
|
92
|
+
isDisabled ? s["disabled"] : ""
|
|
93
|
+
}`
|
|
94
|
+
}
|
|
95
|
+
>
|
|
96
|
+
{content}
|
|
97
|
+
</p>
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
LinkButton.propTypes = {
|
|
103
|
+
onClick: PropTypes.func,
|
|
104
|
+
isDisabled: PropTypes.bool,
|
|
105
|
+
isLoadable: PropTypes.bool,
|
|
106
|
+
content: PropTypes.string,
|
|
107
|
+
icon: PropTypes.string,
|
|
108
|
+
isColored: PropTypes.bool,
|
|
109
|
+
iconRotate: PropTypes.oneOf(Object.values(iconRotateOptions)),
|
|
110
|
+
IconComponent: PropTypes.elementType,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
LinkButton.defaultProps = {
|
|
114
|
+
onClick: (resetButtonLoader) => {},
|
|
115
|
+
isDisabled: false,
|
|
116
|
+
isLoadable: false,
|
|
117
|
+
content: "",
|
|
118
|
+
icon: undefined,
|
|
119
|
+
isColored: true,
|
|
120
|
+
iconRotate: iconRotateOptions.rotate0,
|
|
121
|
+
};
|