diff --git a/package-lock.json b/package-lock.json
index 7555d4f4..ee3405e5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@dassana-io/web-components",
- "version": "0.3.0",
+ "version": "0.3.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -6402,6 +6402,14 @@
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz",
"integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA=="
},
+ "add-dom-event-listener": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz",
+ "integrity": "sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw==",
+ "requires": {
+ "object-assign": "4.x"
+ }
+ },
"address": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz",
@@ -6616,9 +6624,9 @@
}
},
"antd": {
- "version": "4.6.3",
- "resolved": "https://registry.npmjs.org/antd/-/antd-4.6.3.tgz",
- "integrity": "sha512-3wYzzXK5juew1OO2BKQVesgEWkWhf2P1xjNtyjDJqxACmtUGr7kL3v/6DCAqMDt8P5gLzDvZgsSMpes1sSfS8A==",
+ "version": "4.6.5",
+ "resolved": "https://registry.npmjs.org/antd/-/antd-4.6.5.tgz",
+ "integrity": "sha512-heB8TuArpJEtSPOIz1tfY+LOpJnPweKWtQHwcjbW4zWQ+hmFJfKTaYkNWOfeb7w/8YELP+nZ1wVyEPkmM10SEg==",
"requires": {
"@ant-design/colors": "^4.0.5",
"@ant-design/css-animation": "^1.7.2",
@@ -6633,36 +6641,36 @@
"omit.js": "^2.0.2",
"raf": "^3.4.1",
"rc-animate": "~3.1.0",
- "rc-cascader": "~1.3.0",
+ "rc-cascader": "~1.4.0",
"rc-checkbox": "~2.3.0",
"rc-collapse": "~2.0.0",
"rc-dialog": "~8.2.1",
"rc-drawer": "~4.1.0",
- "rc-dropdown": "~3.1.2",
+ "rc-dropdown": "~3.2.0",
"rc-field-form": "~1.10.0",
- "rc-image": "~3.0.2",
+ "rc-image": "~3.0.6",
"rc-input-number": "~6.0.0",
- "rc-mentions": "~1.4.0",
- "rc-menu": "~8.5.2",
- "rc-motion": "^1.1.1",
+ "rc-mentions": "~1.5.0",
+ "rc-menu": "~8.7.1",
+ "rc-motion": "^2.0.0",
"rc-notification": "~4.4.0",
"rc-pagination": "~3.0.3",
- "rc-picker": "~2.0.6",
+ "rc-picker": "~2.1.0",
"rc-progress": "~3.1.0",
"rc-rate": "~2.8.2",
"rc-resize-observer": "^0.2.3",
- "rc-select": "~11.2.0",
- "rc-slider": "~9.3.0",
+ "rc-select": "~11.3.2",
+ "rc-slider": "~9.4.1",
"rc-steps": "~4.1.0",
"rc-switch": "~3.2.0",
"rc-table": "~7.9.2",
"rc-tabs": "~11.6.0",
"rc-textarea": "~0.3.0",
- "rc-tooltip": "~4.2.0",
- "rc-tree": "~3.9.0",
+ "rc-tooltip": "~5.0.0",
+ "rc-tree": "~3.10.0",
"rc-tree-select": "~4.1.1",
- "rc-trigger": "~4.4.0",
- "rc-upload": "~3.3.0",
+ "rc-trigger": "~5.0.3",
+ "rc-upload": "~3.3.1",
"rc-util": "^5.1.0",
"scroll-into-view-if-needed": "^2.2.25",
"warning": "^4.0.3"
@@ -6685,9 +6693,9 @@
}
},
"rc-util": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.2.1.tgz",
- "integrity": "sha512-OnIKp4DsYZpT3St9LwiGARXyMR38wNbk7C4jXS6NGAGHZEQWck7W6qfiJwj+MUmhJiUisAknU6BUs65exbhFTw==",
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.3.4.tgz",
+ "integrity": "sha512-3Nj2cy7GM+f7f4wMVGvt3aGejt7ChBZWy+Jse56DzbJzP3NGhg3SO/QqStaVsOSDFo1NdXlSCVK94Cm4z6sFUw==",
"requires": {
"react-is": "^16.12.0",
"shallowequal": "^1.1.0"
@@ -11338,9 +11346,9 @@
"dev": true
},
"dayjs": {
- "version": "1.8.35",
- "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.35.tgz",
- "integrity": "sha512-isAbIEenO4ilm6f8cpqvgjZCsuerDAz2Kb7ri201AiNn58aqXuaLJEnCtfIMdCvERZHNGRY5lDMTr/jdAnKSWQ=="
+ "version": "1.8.36",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz",
+ "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw=="
},
"debug": {
"version": "4.1.1",
@@ -19944,35 +19952,60 @@
}
},
"rc-align": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.3.tgz",
- "integrity": "sha512-TpI0t1tvAo/wYdoZbZlkCK+MkQBqNuPyRZesfsji4tMlqoqQ0q0MhnC9JD5KGPitMvmSB+KWgFpaN2uTz4hw6Q==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.8.tgz",
+ "integrity": "sha512-2sRUkmB8z4UEXzaS+lDHzXMoR8HrtKH9nn2yHlHVNyUTnaucjMFbdEoCk+hO1g7cpIgW0MphG8i0EH2scSesfw==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"dom-align": "^1.7.0",
- "rc-util": "^5.0.1",
+ "rc-util": "^5.3.0",
"resize-observer-polyfill": "^1.5.1"
+ },
+ "dependencies": {
+ "rc-util": {
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.3.4.tgz",
+ "integrity": "sha512-3Nj2cy7GM+f7f4wMVGvt3aGejt7ChBZWy+Jse56DzbJzP3NGhg3SO/QqStaVsOSDFo1NdXlSCVK94Cm4z6sFUw==",
+ "requires": {
+ "react-is": "^16.12.0",
+ "shallowequal": "^1.1.0"
+ }
+ }
}
},
"rc-animate": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.1.0.tgz",
- "integrity": "sha512-8FsM+3B1H+0AyTyGggY6JyVldHTs1CyYT8CfTmG/nGHHXlecvSLeICJhcKgRLjUiQlctNnRtB1rwz79cvBVmrw==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.1.1.tgz",
+ "integrity": "sha512-8wg2Zg3EETy0k/9kYuis30NJNQg1D6/WSQwnCiz6SvyxQXNet/rVraRz3bPngwY6rcU2nlRvoShiYOorXyF7Sg==",
"requires": {
"@ant-design/css-animation": "^1.7.2",
"classnames": "^2.2.6",
"raf": "^3.4.0",
- "rc-util": "^5.0.1"
+ "rc-util": "^4.15.3"
+ },
+ "dependencies": {
+ "rc-util": {
+ "version": "4.21.1",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-4.21.1.tgz",
+ "integrity": "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg==",
+ "requires": {
+ "add-dom-event-listener": "^1.1.0",
+ "prop-types": "^15.5.10",
+ "react-is": "^16.12.0",
+ "react-lifecycles-compat": "^3.0.4",
+ "shallowequal": "^1.1.0"
+ }
+ }
}
},
"rc-cascader": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-1.3.0.tgz",
- "integrity": "sha512-wayuMo/dSZixvdpiRFZB4Q6A3omKRXQcJ3CxN02+PNiTEcRnK2KDqKUzrx7GwgMsyH5tz90lUZ91lLaEPNFv0A==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-1.4.0.tgz",
+ "integrity": "sha512-6kgQljDQEKjVAVRkZtvvoi+2qv4u42M6oLuvt4ZDBa16r3X9ZN8TAq3atVyC840ivbGKlHT50OcdVx/iwiHc1w==",
"requires": {
"array-tree-filter": "^2.1.0",
- "rc-trigger": "^4.0.0",
+ "rc-trigger": "^5.0.4",
"rc-util": "^5.0.1",
"warning": "^4.0.1"
}
@@ -19987,15 +20020,26 @@
}
},
"rc-collapse": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-2.0.0.tgz",
- "integrity": "sha512-R5+Ge1uzwK9G1wZPRPhqQsed4FXTDmU0BKzsqfNBtZdk/wd+yey8ZutmJmSozYc5hQwjPkCvJHV7gOIRZKIlJg==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-2.0.1.tgz",
+ "integrity": "sha512-sRNqwQovzQoptTh7dCwj3kfxrdor2oNXrGSBz+QJxSFS7N3Ujgf8X/KlN2ElCkwBKf7nNv36t9dwH0HEku4wJg==",
"requires": {
"@ant-design/css-animation": "^1.7.2",
"classnames": "2.x",
"rc-animate": "3.x",
- "react-is": "^16.7.0",
+ "rc-util": "^5.2.1",
"shallowequal": "^1.1.0"
+ },
+ "dependencies": {
+ "rc-util": {
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.3.4.tgz",
+ "integrity": "sha512-3Nj2cy7GM+f7f4wMVGvt3aGejt7ChBZWy+Jse56DzbJzP3NGhg3SO/QqStaVsOSDFo1NdXlSCVK94Cm4z6sFUw==",
+ "requires": {
+ "react-is": "^16.12.0",
+ "shallowequal": "^1.1.0"
+ }
+ }
}
},
"rc-dialog": {
@@ -20019,13 +20063,13 @@
}
},
"rc-dropdown": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-3.1.2.tgz",
- "integrity": "sha512-s2W5jqvjTid5DxotGO5FlTBaQWeB+Bu7McQgjB8Ot3Wbl72AIKwLf11+lgbV4mA2vWC1H8DKyn6SW9TKLTi0xg==",
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-3.2.0.tgz",
+ "integrity": "sha512-j1HSw+/QqlhxyTEF6BArVZnTmezw2LnSmRk6I9W7BCqNCKaRwleRmMMs1PHbuaG8dKHVqP6e21RQ7vPBLVnnNw==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.6",
- "rc-trigger": "^4.0.0"
+ "rc-trigger": "^5.0.4"
}
},
"rc-field-form": {
@@ -20061,9 +20105,9 @@
}
},
"rc-input-number": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-6.0.0.tgz",
- "integrity": "sha512-vbe+g7HvR/joknSnvLkBTi9N9I+LsV4kljfuog8WNiS7OAF3aEN0QcHSOQ4+xk6+Hx9P1tU63z2+TyEx8W/j2Q==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-6.0.1.tgz",
+ "integrity": "sha512-cS1k6IB/V84VUQd5qWzGFrLHvZjWGHGmYbrvR0QP/C1Ju1SlBqlhqhOBTc6w+dpPs84PCH5caZtNzsHeWZ1zYA==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
@@ -20071,43 +20115,42 @@
}
},
"rc-mentions": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.4.2.tgz",
- "integrity": "sha512-wSmHRF9kFwrbj59mR+u4yVr0KtcrfPw53PYOVizYxYeDfmwaCcSgk29F8OjlDy5jVqUaMhHX5nIiYCePu5Aytg==",
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-1.5.1.tgz",
+ "integrity": "sha512-J5q4o4zFeHfoKg4Q3W7O0xTL7SM4z21hqPPHV2TmuYxZHJLV0mHzTKS8A15qJoyfI28+4b6dZa8JR2V+WlNkaA==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.6",
"rc-menu": "^8.0.1",
"rc-textarea": "^0.3.0",
- "rc-trigger": "^4.3.0",
+ "rc-trigger": "^5.0.4",
"rc-util": "^5.0.1"
}
},
"rc-menu": {
- "version": "8.5.3",
- "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-8.5.3.tgz",
- "integrity": "sha512-OLdN+jwhabgyRZDvWYjYpO7RP7wLybhNuAulgGqx1oUPBJrtgVlG/X4HtPb7nypRx/n+eicj6H8CtbCs0L4m/Q==",
+ "version": "8.7.1",
+ "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-8.7.1.tgz",
+ "integrity": "sha512-CuuJ9oS1oPAfenqAMa3CZZE7RrPcPTHV3310cf6RO2uJgE9ztqasRFMEBwtruH16OexTr0igTCXySm+e2/TBQg==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"mini-store": "^3.0.1",
"omit.js": "^2.0.0",
- "rc-motion": "^1.0.1",
- "rc-trigger": "^4.4.0",
+ "rc-motion": "^2.0.1",
+ "rc-trigger": "^5.0.4",
"rc-util": "^5.0.1",
"resize-observer-polyfill": "^1.5.0",
"shallowequal": "^1.1.0"
}
},
"rc-motion": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-1.1.2.tgz",
- "integrity": "sha512-YC/E7SSWKBFakYg4PENhSRWD4ZLDqkI7FKmutJcrMewZ91/ZIWfoZSDvPaBdKO0hsFrrzWepFhXQIq0FNnCMWA==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.0.1.tgz",
+ "integrity": "sha512-spiBod/mQhbAt4ynq0P7TYa8OXAgg/nEloU0jrTO2X4wVkVTI8ynadyjgq7Tr55pegTsuCbYlysEsIdsSrcU0g==",
"requires": {
"@babel/runtime": "^7.11.1",
"classnames": "^2.2.1",
- "raf": "^3.4.1",
- "rc-util": "^5.0.6"
+ "rc-util": "^5.2.1"
},
"dependencies": {
"@babel/runtime": {
@@ -20117,6 +20160,15 @@
"requires": {
"regenerator-runtime": "^0.13.4"
}
+ },
+ "rc-util": {
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.3.4.tgz",
+ "integrity": "sha512-3Nj2cy7GM+f7f4wMVGvt3aGejt7ChBZWy+Jse56DzbJzP3NGhg3SO/QqStaVsOSDFo1NdXlSCVK94Cm4z6sFUw==",
+ "requires": {
+ "react-is": "^16.12.0",
+ "shallowequal": "^1.1.0"
+ }
}
}
},
@@ -20141,16 +20193,16 @@
}
},
"rc-picker": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.0.11.tgz",
- "integrity": "sha512-pUEne2fikHvzqmOjWNLa1P/ss4/1J9lpHrtSU1IrueRiEbUPLIgXmnzoUeVt3syOZGBnWok6nNDu1FvIQfVMCw==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-2.1.0.tgz",
+ "integrity": "sha512-Tu8+yR0qnBVND4v+eta8GRkLu4OvTUaxlk7ZHDAkVFm1RHLAl1GzA6Foni9vcpkMnFMFD6EzpaOlkArI0ryuDA==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1",
"date-fns": "^2.15.0",
"dayjs": "^1.8.30",
"moment": "^2.24.0",
- "rc-trigger": "^4.0.0",
+ "rc-trigger": "^5.0.4",
"rc-util": "^5.0.1",
"shallowequal": "^1.1.0"
},
@@ -20193,27 +20245,27 @@
}
},
"rc-select": {
- "version": "11.2.0",
- "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-11.2.0.tgz",
- "integrity": "sha512-rw9XH2ALt/lpXDM/gULWiPDkEh5UndLDMqZo5FRiZji7MYLg+CbmcFpvJ6iYN5KpKosyLsCWrwvzeWZOCL6q0Q==",
+ "version": "11.3.3",
+ "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-11.3.3.tgz",
+ "integrity": "sha512-YMsGVEZxXctj15nIZKlFCkiOxMe0PNBeACN6nHqDozDYKR/aqP8J3XZqZ5Gw/fcgS4bI50zPVMieJKlY8/6Wfw==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
- "rc-motion": "^1.0.1",
- "rc-trigger": "^4.3.0",
+ "rc-motion": "^2.0.1",
+ "rc-trigger": "^5.0.4",
"rc-util": "^5.0.1",
"rc-virtual-list": "^3.0.3",
"warning": "^4.0.3"
}
},
"rc-slider": {
- "version": "9.3.1",
- "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-9.3.1.tgz",
- "integrity": "sha512-c52PWPyrfJWh28K6dixAm0906L3/4MUIxqrNQA4TLnC/Z+cBNycWJUZoJerpwSOE1HdM3XDwixCsmtFc/7aWlQ==",
+ "version": "9.4.1",
+ "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-9.4.1.tgz",
+ "integrity": "sha512-MTynuHuqsT1Gc4arFaEOt4w7JJU/BJTqnuMETp5XyCgJnF6EmMAIH8xp1j3HzlqEhT+OsP+Pxvu5yEeuk71D6A==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
- "rc-tooltip": "^4.0.0",
+ "rc-tooltip": "^5.0.1",
"rc-util": "^5.0.0",
"shallowequal": "^1.1.0"
}
@@ -20239,9 +20291,9 @@
}
},
"rc-table": {
- "version": "7.9.7",
- "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.9.7.tgz",
- "integrity": "sha512-S/46pdU7fKBoL7N8JDu+KpkGSB3fJkiGoxvMCLBrR4p7/BJEYr1X4MFKb5BpkE7ZpEK4n44ILiVZZT7I7EiGVA==",
+ "version": "7.9.10",
+ "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.9.10.tgz",
+ "integrity": "sha512-WtPBxYsBU/a5MIglilbMlVkiXkPKXpUM/CPCFaqA2veh1b7J40mbTGQmU8VT6S0FClkI5jm0QBtSp6LstPkOMQ==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
@@ -20252,18 +20304,27 @@
}
},
"rc-tabs": {
- "version": "11.6.1",
- "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-11.6.1.tgz",
- "integrity": "sha512-fJZUOmwBo2E4WTbucCSZO/N1ZK+d9K/QchgDeycTIqxl5D/xtX0Dw/vC2DFi140OFjAy2JL7H0EmsSeOFfCgzw==",
+ "version": "11.6.2",
+ "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-11.6.2.tgz",
+ "integrity": "sha512-7Z5Lg+nP/H4V7dIlewrOC0+aogRVH3ASjTy4VIletYOeStGPWYSfwBnUTBdcCXcUuWuyyKnNkYrUD0yaRqUCIA==",
"requires": {
- "@babel/runtime": "^7.10.1",
+ "@babel/runtime": "^7.11.2",
"classnames": "2.x",
"raf": "^3.4.1",
- "rc-dropdown": "^3.1.0",
- "rc-menu": "^8.2.1",
+ "rc-dropdown": "^3.1.3",
+ "rc-menu": "^8.6.1",
"rc-resize-observer": "^0.2.1",
- "rc-trigger": "^4.2.1",
"rc-util": "^5.0.0"
+ },
+ "dependencies": {
+ "@babel/runtime": {
+ "version": "7.11.2",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz",
+ "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ }
}
},
"rc-textarea": {
@@ -20278,21 +20339,32 @@
}
},
"rc-tooltip": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-4.2.2.tgz",
- "integrity": "sha512-mAs+gAngUyHVA6HdFXsELoJOHgfjAACLLc8SGtnVhovJdyqs5ZGSL9p5i+ApNaVpwjswqShw7L4DRtMl7cXCQg==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.0.1.tgz",
+ "integrity": "sha512-3AnxhUS0j74xAV3khrKw8o6rg+Ima3nw09DJBezMPnX3ImQUAnayWsPSlN1mEnihjA43rcFkGM1emiKE+CXyMQ==",
"requires": {
- "rc-trigger": "^4.2.1"
+ "@babel/runtime": "^7.11.2",
+ "rc-trigger": "^5.0.0"
+ },
+ "dependencies": {
+ "@babel/runtime": {
+ "version": "7.11.2",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz",
+ "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ }
}
},
"rc-tree": {
- "version": "3.9.5",
- "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-3.9.5.tgz",
- "integrity": "sha512-ZGVl1o83hZoz971pzY9Y7yZM+f9qcia1Gym+QNyc3zMGQVshbr6CX2WZ8xUK18tTkdRSqbTXmZFnvYf1lfqT8A==",
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-3.10.0.tgz",
+ "integrity": "sha512-kf7J/f2E2T8Kfta3/1BIg65AzTmXOgOjn0KOpvD3KI/gqkfKMRKUS1ybkxW39JUPpKwdeOHFnYH+nFFMq7tkfg==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
- "rc-motion": "^1.0.0",
+ "rc-motion": "^2.0.1",
"rc-util": "^5.0.0",
"rc-virtual-list": "^3.0.1"
}
@@ -20310,16 +20382,34 @@
}
},
"rc-trigger": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-4.4.2.tgz",
- "integrity": "sha512-uw2/s7j1b/RXyixa4omPuxZWv/3ln+H+p0v3trIUBxseolbdj8TTFpXYjXMZdGtMpAEAIbN1yo/K+r7wRB+xtQ==",
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.0.6.tgz",
+ "integrity": "sha512-L/xIX5OO7a/bdTH0yYT9mwAsV6oM1inAqAbLjoUzpcIW+UUE3jjVOjm5VaKDfHd41rzDzOfN05URmhet5QzXKQ==",
"requires": {
- "@babel/runtime": "^7.10.1",
+ "@babel/runtime": "^7.11.2",
"classnames": "^2.2.6",
- "raf": "^3.4.1",
"rc-align": "^4.0.0",
- "rc-motion": "^1.0.0",
- "rc-util": "^5.0.1"
+ "rc-motion": "^2.0.0",
+ "rc-util": "^5.3.4"
+ },
+ "dependencies": {
+ "@babel/runtime": {
+ "version": "7.11.2",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz",
+ "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
+ "rc-util": {
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.3.4.tgz",
+ "integrity": "sha512-3Nj2cy7GM+f7f4wMVGvt3aGejt7ChBZWy+Jse56DzbJzP3NGhg3SO/QqStaVsOSDFo1NdXlSCVK94Cm4z6sFUw==",
+ "requires": {
+ "react-is": "^16.12.0",
+ "shallowequal": "^1.1.0"
+ }
+ }
}
},
"rc-upload": {
@@ -20333,9 +20423,9 @@
},
"dependencies": {
"rc-util": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.2.1.tgz",
- "integrity": "sha512-OnIKp4DsYZpT3St9LwiGARXyMR38wNbk7C4jXS6NGAGHZEQWck7W6qfiJwj+MUmhJiUisAknU6BUs65exbhFTw==",
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.3.4.tgz",
+ "integrity": "sha512-3Nj2cy7GM+f7f4wMVGvt3aGejt7ChBZWy+Jse56DzbJzP3NGhg3SO/QqStaVsOSDFo1NdXlSCVK94Cm4z6sFUw==",
"requires": {
"react-is": "^16.12.0",
"shallowequal": "^1.1.0"
@@ -20353,9 +20443,9 @@
}
},
"rc-virtual-list": {
- "version": "3.0.14",
- "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.0.14.tgz",
- "integrity": "sha512-sbiPmSaDmO+2IY91eHyFYVHH8mJH0QYS1t4I5EKbqeVFgY/RZIHkwezKX/nvxULQlZHdTU6l/wh7yBxfp4QUyg==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.1.0.tgz",
+ "integrity": "sha512-DYU3wOjVuQo4hzYvmmpnoNtxrd8OIcutazA90x374ZFGGm4xYoSjCdh6UhBLi47IJI2BRry4l583nuoi7+06GA==",
"requires": {
"classnames": "^2.2.6",
"rc-resize-observer": "^0.2.3",
@@ -20363,9 +20453,9 @@
},
"dependencies": {
"rc-util": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.2.1.tgz",
- "integrity": "sha512-OnIKp4DsYZpT3St9LwiGARXyMR38wNbk7C4jXS6NGAGHZEQWck7W6qfiJwj+MUmhJiUisAknU6BUs65exbhFTw==",
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.3.4.tgz",
+ "integrity": "sha512-3Nj2cy7GM+f7f4wMVGvt3aGejt7ChBZWy+Jse56DzbJzP3NGhg3SO/QqStaVsOSDFo1NdXlSCVK94Cm4z6sFUw==",
"requires": {
"react-is": "^16.12.0",
"shallowequal": "^1.1.0"
@@ -20852,8 +20942,7 @@
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
- "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
- "dev": true
+ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-popper": {
"version": "1.3.7",
diff --git a/package.json b/package.json
index d865f3e7..bd25ea88 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@dassana-io/web-components",
- "version": "0.3.1",
+ "version": "0.4.0",
"publishConfig": {
"registry": "https://npm.pkg.github.com/dassana-io"
},
@@ -18,7 +18,7 @@
"@types/node": "^12.12.53",
"@types/react": "^16.9.44",
"@types/react-dom": "^16.9.8",
- "antd": "^4.6.3",
+ "antd": "^4.6.5",
"bytes": "^3.1.0",
"classnames": "^2.2.6",
"fuse.js": "^6.4.1",
diff --git a/src/__snapshots__/storybook.test.ts.snap b/src/__snapshots__/storybook.test.ts.snap
index 0b423db0..0760c9b0 100644
--- a/src/__snapshots__/storybook.test.ts.snap
+++ b/src/__snapshots__/storybook.test.ts.snap
@@ -149,183 +149,6 @@ exports[`Storyshots Button Primary Disabled 1`] = `
`;
-exports[`Storyshots Form Default 1`] = `
-
-`;
-
exports[`Storyshots Icon Custom 1`] = `
@@ -507,12 +330,226 @@ exports[`Storyshots Notifications Warning 1`] = `
`;
+exports[`Storyshots Popover Default 1`] = `
+
+
+
+
+
+`;
+
+exports[`Storyshots Popover Title 1`] = `
+
+
+
+
+
+`;
+
+exports[`Storyshots Radio Group Default 1`] = `
+
+
+
+
+
+`;
+
+exports[`Storyshots Radio Group Partially Disabled 1`] = `
+
+
+
+
+
+`;
+
exports[`Storyshots Select Default 1`] = `
Lorem
@@ -696,10 +735,10 @@ exports[`Storyshots Select Full Width 1`] = `
exports[`Storyshots Select Icon 1`] = `
@@ -892,7 +933,7 @@ exports[`Storyshots Select Search 1`] = `
exports[`Storyshots Skeleton Circle 1`] = `
@@ -901,27 +942,27 @@ exports[`Storyshots Skeleton Circle 1`] = `
exports[`Storyshots Skeleton Count 1`] = `
Array [
,
,
,
,
,
@@ -930,7 +971,7 @@ Array [
exports[`Storyshots Skeleton Default 1`] = `
@@ -1052,3 +1093,98 @@ exports[`Storyshots Toggle Small 1`] = `
/>
`;
+
+exports[`Storyshots Tooltip Default 1`] = `
+
+
+
+
+
+`;
+
+exports[`Storyshots Tree Default 1`] = `
+
+`;
diff --git a/src/components/Form/FieldLabel/index.tsx b/src/components/Form/FieldLabel/index.tsx
index 68cb2e3a..2f146f62 100644
--- a/src/components/Form/FieldLabel/index.tsx
+++ b/src/components/Form/FieldLabel/index.tsx
@@ -1,6 +1,6 @@
import cn from 'classnames'
import { createUseStyles } from 'react-jss'
-import { fontSizeRegular } from '../../assets/styleguide'
+import { fontSizeRegular } from '../../assets/styles/styleguide'
import Skeleton from '../../Skeleton'
import React, { FC } from 'react'
diff --git a/src/components/Form/Form.stories.tsx b/src/components/Form/Form.stories.tsx
index b0202ec7..542fc5b5 100644
--- a/src/components/Form/Form.stories.tsx
+++ b/src/components/Form/Form.stories.tsx
@@ -1,5 +1,7 @@
+import { basicOptions } from '../RadioGroup/fixtures/sample_options'
import { iconOptions } from '../Select/fixtures/sample_options'
import React from 'react'
+import treeData from '../Tree/fixtures/0_sample_data'
import Form, { FormProps } from './index'
import { Meta, Story } from '@storybook/react/types-6-0'
@@ -9,6 +11,10 @@ export default {
onSubmit: { control: { disable: true } }
},
component: Form,
+ parameters: {
+ // disabled because shallow rendering gives warning, but FormTree only works with shallow render
+ storyshots: { disable: true }
+ },
title: 'Form'
} as Meta
@@ -20,7 +26,11 @@ interface UserModel {
const Template: Story
> = (args: FormProps) => (
@@ -29,6 +39,17 @@ const Template: Story> = (args: FormProps) => (
name='cloudType'
options={iconOptions}
/>
+
+
Submit
)
diff --git a/src/components/Form/FormRadioGroup/FormRadioGroup.test.tsx b/src/components/Form/FormRadioGroup/FormRadioGroup.test.tsx
new file mode 100644
index 00000000..1fe181d0
--- /dev/null
+++ b/src/components/Form/FormRadioGroup/FormRadioGroup.test.tsx
@@ -0,0 +1,89 @@
+import { basicOptions } from '../../RadioGroup/fixtures/sample_options'
+import { Controller } from 'react-hook-form'
+import FieldContext from '../FieldContext'
+import FieldLabel from '../FieldLabel'
+import RadioGroup from '../../RadioGroup'
+import React from 'react'
+import FormRadioGroup, { FormRadioGroupProps } from './index'
+import { mount, ReactWrapper } from 'enzyme'
+
+jest.mock('react-hook-form', () => ({
+ ...jest.requireActual('react-hook-form'),
+ Controller: () => ,
+ useFormContext: () => ({
+ control: jest.fn(),
+ errors: () => ({})
+ })
+}))
+
+let wrapper: ReactWrapper
+
+const mockChangeEvent = {
+ onChange: jest.fn(),
+ value: 'abc'
+} as jest.Mocked
+const mockOnSubmit = jest.fn()
+
+const getRenderedCmp = (wrapper: ReactWrapper) =>
+ wrapper.find(Controller).invoke('render')!(mockChangeEvent)
+
+beforeEach(() => {
+ wrapper = mount(
+
+
+
+ )
+})
+
+afterEach(() => {
+ jest.resetAllMocks()
+})
+
+describe('FormRadioGroup', () => {
+ it('renders', () => {
+ expect(wrapper).toHaveLength(1)
+ })
+
+ it('correctly passes a default value from initial values if it exists', () => {
+ expect(wrapper.find(Controller).props().defaultValue).toEqual('bar')
+ })
+
+ it('should render a Radio Group component', () => {
+ const radioGroup = getRenderedCmp(wrapper)
+
+ expect(radioGroup.type).toBe(RadioGroup)
+ })
+
+ it('should call onChange with the target value extracted from the event', () => {
+ const radioGroup = getRenderedCmp(wrapper)
+
+ radioGroup.props.onChange({ target: { value: 'foo' } })
+
+ expect(mockChangeEvent.onChange).toHaveBeenCalledWith('foo')
+ })
+
+ it('renders a label if one is passed in', () => {
+ wrapper = mount(
+
+
+
+ )
+ expect(wrapper.find(FieldLabel)).toHaveLength(1)
+ })
+})
diff --git a/src/components/Form/FormRadioGroup/index.tsx b/src/components/Form/FormRadioGroup/index.tsx
new file mode 100644
index 00000000..26a991b7
--- /dev/null
+++ b/src/components/Form/FormRadioGroup/index.tsx
@@ -0,0 +1,63 @@
+import { BaseFieldProps } from '../types'
+import FieldLabel from '../FieldLabel'
+import { getFormFieldDataTag } from '../utils'
+import { Controller, useFormContext } from 'react-hook-form'
+import FieldContext, { FieldContextProps } from '../FieldContext'
+import RadioGroup, { RadioGroupProps } from '../../RadioGroup'
+import React, { FC, useContext } from 'react'
+
+export interface FormRadioGroupProps
+ extends BaseFieldProps,
+ Omit {}
+
+const FormRadioGroup: FC = ({
+ defaultValue,
+ label,
+ labelSkeletonWidth,
+ name,
+ required,
+ rules = {},
+ ...rest
+}: FormRadioGroupProps) => {
+ const { control } = useFormContext()
+ const { initialValues, loading } = useContext(
+ FieldContext
+ )
+
+ rules.required = true
+
+ const initialValue = (initialValues[name] as string) || defaultValue || ''
+
+ return (
+
+ {label && (
+
+ )}
+ (
+
+ ) => onChange(event.target.value)}
+ value={value}
+ {...rest}
+ />
+ )}
+ rules={rules}
+ />
+
+ )
+}
+
+export default FormRadioGroup
diff --git a/src/components/Form/FormTree/FormTree.test.tsx b/src/components/Form/FormTree/FormTree.test.tsx
new file mode 100644
index 00000000..de63021c
--- /dev/null
+++ b/src/components/Form/FormTree/FormTree.test.tsx
@@ -0,0 +1,117 @@
+import { Controller } from 'react-hook-form'
+import FieldLabel from '../FieldLabel'
+import { FieldValues } from 'react-hook-form/dist/types/form'
+import React from 'react'
+import treeData from '../../Tree/fixtures/0_sample_data'
+import FieldContext, { FieldContextProps } from '../FieldContext'
+import FormTree, { FormTreeProps } from '.'
+import { mount, ReactWrapper } from 'enzyme'
+import Tree, { TreeId } from '../../Tree'
+
+/* Helper functions */
+interface MountWrapperArgsType {
+ initialValues: FieldValues
+ name: string
+ defaultChecked?: TreeId[]
+}
+
+const mountWrapper = ({
+ initialValues,
+ name,
+ defaultChecked
+}: MountWrapperArgsType) => {
+ const defaultValue: FieldContextProps = {
+ initialValues,
+ loading: true,
+ onSubmit: mockOnSubmit
+ }
+ const formTreeProps: FormTreeProps = {
+ name,
+ treeData
+ }
+
+ if (defaultChecked) formTreeProps.defaultChecked = defaultChecked
+
+ wrapper = mount(
+
+
+
+ )
+}
+/* --------------------------------------- */
+
+jest.mock('react-hook-form', () => ({
+ ...jest.requireActual('react-hook-form'),
+ Controller: () => ,
+ useFormContext: () => ({
+ control: jest.fn(),
+ errors: () => ({})
+ })
+}))
+
+let wrapper: ReactWrapper
+
+const mockOnSubmit = jest.fn()
+
+beforeEach(() => {
+ mountWrapper({ initialValues: { foo: [0] }, name: 'foo' })
+})
+
+afterEach(() => {
+ jest.resetAllMocks()
+})
+
+describe('FormTree', () => {
+ it('renders', () => {
+ expect(wrapper).toHaveLength(1)
+ })
+
+ it('correctly passes a default value from initial values if it exists', () => {
+ expect(wrapper.find(Controller).props().defaultValue).toMatchObject([0])
+ })
+
+ it('correctly passes default checked as default value if initial values do not exist', () => {
+ mountWrapper({ defaultChecked: [1], initialValues: {}, name: 'foo' })
+ expect(wrapper.find(Controller).props().defaultValue).toMatchObject([1])
+ })
+
+ it('correctly passes an empty array as default value if initial values and default checked do not exist', () => {
+ mountWrapper({ initialValues: {}, name: 'foo' })
+ expect(wrapper.find(Controller).props().defaultValue).toMatchObject([])
+ })
+
+ it('correctly passes default values if both default checked and initial values exist', () => {
+ mountWrapper({
+ defaultChecked: [1],
+ initialValues: { foo: [0] },
+ name: 'foo'
+ })
+ expect(wrapper.find(Controller).props().defaultValue).toMatchObject([0])
+ })
+
+ it('should render a Tree component', () => {
+ const test = {
+ onChange: jest.fn()
+ } as jest.Mocked
+
+ const tree = wrapper.find(Controller).invoke('render')!(test)
+
+ expect(tree.type).toBe(Tree)
+ })
+
+ it('renders a label if one is passed in', () => {
+ wrapper = mount(
+
+
+
+ )
+
+ expect(wrapper.find(FieldLabel)).toHaveLength(1)
+ })
+})
diff --git a/src/components/Form/FormTree/index.tsx b/src/components/Form/FormTree/index.tsx
new file mode 100644
index 00000000..19d55a4b
--- /dev/null
+++ b/src/components/Form/FormTree/index.tsx
@@ -0,0 +1,58 @@
+import { BaseFieldProps } from '../types'
+import FieldLabel from '../FieldLabel'
+import { getFormFieldDataTag } from '../utils'
+import { Controller, useFormContext } from 'react-hook-form'
+import FieldContext, { FieldContextProps } from '../FieldContext'
+import React, { FC, useContext } from 'react'
+import Tree, { TreeId, TreeProps } from '../../Tree'
+
+export interface FormTreeProps
+ extends BaseFieldProps,
+ Omit {}
+
+const FormTree: FC = ({
+ defaultChecked,
+ label,
+ labelSkeletonWidth,
+ name,
+ required,
+ rules = {},
+ ...rest
+}: FormTreeProps) => {
+ const { control } = useFormContext()
+ const { initialValues, loading } = useContext(
+ FieldContext
+ )
+ const defaultValue =
+ (initialValues[name] as TreeId[]) || defaultChecked || []
+
+ return (
+
+ {label && (
+
+ )}
+ (
+
+ )}
+ rules={rules}
+ />
+
+ )
+}
+
+export default FormTree
diff --git a/src/components/Form/index.tsx b/src/components/Form/index.tsx
index 753f62df..d13224f2 100644
--- a/src/components/Form/index.tsx
+++ b/src/components/Form/index.tsx
@@ -2,8 +2,10 @@ import { createUseStyles } from 'react-jss'
import FieldContext from './FieldContext'
import { FieldValues } from 'react-hook-form/dist/types/form'
import FormInput from './FormInput'
+import FormRadioGroup from './FormRadioGroup'
import FormSelect from './FormSelect'
import FormSubmitButton from './FormSubmitButton'
+import FormTree from './FormTree'
import { FormProvider, SubmitHandler, useForm } from 'react-hook-form'
import React, { ReactNode, useEffect } from 'react'
@@ -52,7 +54,9 @@ function Form({
Form.SubmitButton = FormSubmitButton
Form.Input = FormInput
+Form.RadioGroup = FormRadioGroup
Form.Select = FormSelect
+Form.Tree = FormTree
export * from './types'
export default Form
diff --git a/src/components/Input/index.tsx b/src/components/Input/index.tsx
index 5cab0941..134e774b 100644
--- a/src/components/Input/index.tsx
+++ b/src/components/Input/index.tsx
@@ -5,7 +5,10 @@ import cn from 'classnames'
import { createUseStyles } from 'react-jss'
import { getDataTestAttributeProp } from '../utils'
import Skeleton from '../Skeleton'
-import { defaultFieldWidth, fieldErrorStyles } from '../assets/styleguide'
+import {
+ defaultFieldWidth,
+ fieldErrorStyles
+} from '../assets/styles/styleguide'
import React, { FC } from 'react'
const useStyles = createUseStyles({
diff --git a/src/components/Link/index.tsx b/src/components/Link/index.tsx
index c8febf14..ddd23933 100644
--- a/src/components/Link/index.tsx
+++ b/src/components/Link/index.tsx
@@ -2,7 +2,7 @@ import 'antd/lib/typography/style/index.css'
import { CommonComponentProps } from '../types'
import { createUseStyles } from 'react-jss'
import { getDataTestAttributeProp } from '../utils'
-import { linkColor } from '../assets/styleguide'
+import { linkColor } from '../assets/styles/styleguide'
import { Typography } from 'antd'
import React, { FC, ReactNode } from 'react'
diff --git a/src/components/Popover/Popover.stories.tsx b/src/components/Popover/Popover.stories.tsx
new file mode 100644
index 00000000..ed70ec23
--- /dev/null
+++ b/src/components/Popover/Popover.stories.tsx
@@ -0,0 +1,48 @@
+import { action } from '@storybook/addon-actions'
+import Button from '../Button'
+import Icon from '../Icon'
+import { placementOptions } from '../utils'
+import React from 'react'
+import { Meta, Story } from '@storybook/react/types-6-0'
+import Popover, { PopoverProps } from './index'
+
+export default {
+ argTypes: {
+ children: { control: { disable: true } },
+ content: {
+ control: { disable: true },
+ defaultValue: (
+
+ )
+ },
+ placement: {
+ control: {
+ options: placementOptions,
+ type: 'select'
+ }
+ },
+ title: { control: { type: 'text' } }
+ },
+ component: Popover,
+ decorators: [
+ (PopoverStory: Story) => (
+
+ )
+ ],
+ title: 'Popover'
+} as Meta
+
+const Template: Story = args => (
+
+
+
+)
+
+export const Default = Template.bind({})
+
+export const Title = Template.bind({})
+Title.args = {
+ title: 'Account Info'
+}
diff --git a/src/components/Popover/Popover.test.tsx b/src/components/Popover/Popover.test.tsx
new file mode 100644
index 00000000..caaa85b3
--- /dev/null
+++ b/src/components/Popover/Popover.test.tsx
@@ -0,0 +1,46 @@
+import { Popover as AntDPopover } from 'antd'
+import React from 'react'
+import Popover, { PopoverProps } from './index'
+import { shallow, ShallowWrapper } from 'enzyme'
+
+let wrapper: ShallowWrapper
+
+const mockContent = DASSANA
+const mockTitle = 'foo'
+
+const getWrapper = (
+ additionalProps?: Omit
+): ShallowWrapper =>
+ shallow(
+
+ Hello World
+
+ )
+
+beforeEach(() => {
+ wrapper = getWrapper()
+})
+
+describe('Popover', () => {
+ it('renders', () => {
+ expect(wrapper).toHaveLength(1)
+ })
+
+ it('correctly passes the content prop', () => {
+ expect(wrapper.find(AntDPopover).props().content).toEqual(mockContent)
+ })
+
+ it('correctly passes the title prop if one is provided', () => {
+ wrapper = getWrapper({ title: mockTitle })
+ expect(wrapper.find(AntDPopover).props().title).toEqual(mockTitle)
+ })
+
+ it('correctly passes the placement prop if one is provided', () => {
+ wrapper = getWrapper({ placement: 'top' })
+ expect(wrapper.find(AntDPopover).props().placement).toEqual('top')
+ })
+
+ it('has a default placement of bottom', () => {
+ expect(wrapper.find(AntDPopover).props().placement).toBe('bottom')
+ })
+})
diff --git a/src/components/Popover/index.tsx b/src/components/Popover/index.tsx
new file mode 100644
index 00000000..f73cda68
--- /dev/null
+++ b/src/components/Popover/index.tsx
@@ -0,0 +1,56 @@
+import '../assets/styles/antdAnimations.css'
+import 'antd/lib/popover/style/index.css'
+import { Popover as AntDPopover } from 'antd'
+import cn from 'classnames'
+import { CommonComponentProps } from '../types'
+import { getDataTestAttributeProp } from '../utils'
+import { TooltipPlacement } from 'antd/es/tooltip'
+import React, { FC, ReactNode } from 'react'
+
+export type PopoverContent = string | ReactNode
+
+export interface PopoverProps extends CommonComponentProps {
+ /**
+ * Element popover should be anchored to
+ */
+ children: ReactNode
+ /**
+ * Array of classes to pass to element
+ * @default []
+ */
+ classes?: string[]
+ /**
+ * Content rendered inside of popover
+ */
+ content: PopoverContent
+ /**
+ * Position of popover relative to the target
+ */
+ placement?: TooltipPlacement
+ /**
+ * Title of popover
+ */
+ title?: PopoverContent
+}
+
+const Popover: FC = ({
+ children,
+ classes = [],
+ content,
+ dataTag,
+ placement = 'bottom',
+ title
+}: PopoverProps) => (
+
+
+ {children}
+
+
+)
+
+export default Popover
diff --git a/src/components/RadioGroup/RadioGroup.stories.tsx b/src/components/RadioGroup/RadioGroup.stories.tsx
new file mode 100644
index 00000000..ca675971
--- /dev/null
+++ b/src/components/RadioGroup/RadioGroup.stories.tsx
@@ -0,0 +1,30 @@
+import React from 'react'
+import { basicOptions, basicOptionsDisabled } from './fixtures/sample_options'
+import { Meta, Story } from '@storybook/react/types-6-0'
+import RadioGroup, { RadioGroupProps } from './index'
+
+export default {
+ argTypes: {
+ value: { control: { disable: true } }
+ },
+ component: RadioGroup,
+ title: 'Radio Group'
+} as Meta
+
+const commonStoryProps = {
+ /**
+ * Storybook automatically passes an onChange but not a value to RadioGroup, so the component won't work
+ * properly in the story. Passing undefined here ensures that RadioGroup is uncontrolled.
+ */
+ onChange: undefined
+}
+
+const Template: Story = args => (
+
+)
+
+export const Default = Template.bind({})
+Default.args = { options: basicOptions }
+
+export const PartiallyDisabled = Template.bind({})
+PartiallyDisabled.args = { options: basicOptionsDisabled }
diff --git a/src/components/RadioGroup/RadioGroup.test.tsx b/src/components/RadioGroup/RadioGroup.test.tsx
new file mode 100644
index 00000000..1fd247bb
--- /dev/null
+++ b/src/components/RadioGroup/RadioGroup.test.tsx
@@ -0,0 +1,60 @@
+import { Radio as AntDRadio } from 'antd'
+import { basicOptions } from './fixtures/sample_options'
+import RadioGroup from './index'
+import React from 'react'
+import Skeleton from '../Skeleton'
+import { mount, ReactWrapper } from 'enzyme'
+
+let wrapper: ReactWrapper
+
+beforeEach(() => {
+ wrapper = mount()
+})
+
+describe('RadioGroup', () => {
+ it('renders', () => {
+ expect(wrapper.find(RadioGroup)).toHaveLength(1)
+ })
+
+ it('should pass onChange and value to the input component if the props exist', () => {
+ const mockOnChange = jest.fn()
+ wrapper = mount(
+
+ )
+
+ expect(wrapper.find(AntDRadio.Group).props().onChange).toEqual(
+ mockOnChange
+ )
+ expect(wrapper.find(AntDRadio.Group).props().value).toEqual('low')
+ })
+
+ it('should have a default value of the first option if none is passed in', () => {
+ expect(wrapper.find(AntDRadio.Group).props().defaultValue).toEqual(
+ basicOptions[0].value
+ )
+ })
+
+ it('correctly passes the disabled prop', () => {
+ wrapper = mount()
+
+ expect(wrapper.find(AntDRadio.Group).props().disabled).toBeTruthy()
+ })
+
+ it('correctly passes the options prop', () => {
+ expect(wrapper.find(AntDRadio.Group).props().options).toMatchObject(
+ basicOptions
+ )
+ })
+
+ describe('loading', () => {
+ it('renders a loading skeleton', () => {
+ wrapper = mount()
+
+ expect(wrapper.find(Skeleton)).toHaveLength(basicOptions.length)
+ })
+ })
+})
diff --git a/src/components/RadioGroup/fixtures/sample_options.ts b/src/components/RadioGroup/fixtures/sample_options.ts
new file mode 100644
index 00000000..aba714da
--- /dev/null
+++ b/src/components/RadioGroup/fixtures/sample_options.ts
@@ -0,0 +1,13 @@
+import { RadioGroupOptions } from '../.'
+
+export const basicOptions: RadioGroupOptions[] = [
+ { label: 'High', value: 'high' },
+ { label: 'Medium', value: 'medium' },
+ { label: 'Low', value: 'low' }
+]
+
+export const basicOptionsDisabled: RadioGroupOptions[] = [
+ { label: 'High', value: 'high' },
+ { label: 'Medium', value: 'medium' },
+ { disabled: true, label: 'Low', value: 'low' }
+]
diff --git a/src/components/RadioGroup/index.tsx b/src/components/RadioGroup/index.tsx
new file mode 100644
index 00000000..48190dc8
--- /dev/null
+++ b/src/components/RadioGroup/index.tsx
@@ -0,0 +1,114 @@
+import 'antd/lib/radio/style/index.css'
+import { Radio as AntDRadio } from 'antd'
+import { CommonComponentProps } from '../types'
+import { createUseStyles } from 'react-jss'
+import Skeleton from '../Skeleton'
+import { skeletonButtonBorderColor } from '../assets/styles/styleguide'
+import times from 'lodash/times'
+import { getDataTestAttributeProp, TAG } from '../utils'
+import React, { ChangeEventHandler, FC } from 'react'
+
+const useStyles = createUseStyles({
+ button: {
+ border: `1px solid ${skeletonButtonBorderColor}`,
+ display: 'flex'
+ },
+ container: {
+ display: 'flex'
+ },
+ skeleton: {
+ borderRadius: 'unset'
+ }
+})
+
+const RadioGroupSkeleton: FC = ({
+ options
+}: RadioGroupProps) => {
+ const classes = useStyles()
+
+ return (
+
+ {times(options.length, i => (
+
+
+
+ ))}
+
+ )
+}
+
+export interface RadioGroupOptions {
+ disabled?: boolean
+ label: string
+ value: string
+}
+
+export interface RadioGroupProps extends CommonComponentProps {
+ /**
+ * Default value for radio group. Without this, the first option will be defaulted
+ */
+ defaultValue?: string
+ /**
+ * Adds the disabled attribute and styles (opacity, gray scale filter, no pointer events)
+ * @default false
+ */
+ disabled?: boolean
+ /**
+ * Whether or not to show skeleton loader
+ * @default false
+ */
+ loading?: boolean
+ /**
+ * Callback that runs when element is updated
+ */
+ onChange?: ChangeEventHandler
+ /**
+ * Array of options to be rendered in the form of buttons
+ */
+ options: RadioGroupOptions[]
+ /**
+ * Element content value for controlled input elements. Requires an onChange to be passed
+ */
+ value?: string
+}
+
+const RadioGroup: FC = (props: RadioGroupProps) => {
+ const {
+ defaultValue,
+ dataTag,
+ disabled = false,
+ loading = false,
+ onChange,
+ options,
+ value
+ } = props
+
+ let controlledCmpProps = {}
+
+ if (onChange) {
+ controlledCmpProps = {
+ onChange,
+ value
+ }
+ }
+
+ return loading ? (
+
+ ) : (
+
+ )
+}
+
+export default RadioGroup
diff --git a/src/components/Select/index.tsx b/src/components/Select/index.tsx
index f52ba4a0..fe14a7f2 100644
--- a/src/components/Select/index.tsx
+++ b/src/components/Select/index.tsx
@@ -1,4 +1,4 @@
-import '../assets/antdAnimations.css'
+import '../assets/styles/antdAnimations.css'
import 'antd/lib/select/style/index.css'
import { Select as AntDSelect } from 'antd'
import { BaseFormElementProps } from '../types'
@@ -6,7 +6,10 @@ import cn from 'classnames'
import { createUseStyles } from 'react-jss'
import { getDataTestAttributeProp } from '../utils'
import Skeleton from '../Skeleton'
-import { defaultFieldWidth, fieldErrorStyles } from '../assets/styleguide'
+import {
+ defaultFieldWidth,
+ fieldErrorStyles
+} from '../assets/styles/styleguide'
import Icon, { IconName, SharedIconProps } from '../Icon'
import React, { FC } from 'react'
diff --git a/src/components/Tooltip/Tooltip.stories.tsx b/src/components/Tooltip/Tooltip.stories.tsx
new file mode 100644
index 00000000..e16ddf27
--- /dev/null
+++ b/src/components/Tooltip/Tooltip.stories.tsx
@@ -0,0 +1,38 @@
+import Icon from '../Icon'
+import { placementOptions } from '../utils'
+import React from 'react'
+import { Meta, Story } from '@storybook/react/types-6-0'
+import Tooltip, { TooltipProps } from './index'
+
+export default {
+ argTypes: {
+ children: { control: { disable: true } },
+ placement: {
+ control: {
+ options: placementOptions,
+ type: 'select'
+ }
+ },
+ title: { control: { type: 'text' } }
+ },
+ component: Tooltip,
+ decorators: [
+ (PopoverStory: Story) => (
+
+ )
+ ],
+ title: 'Tooltip'
+} as Meta
+
+const Template: Story = args => (
+
+
+
+)
+
+export const Default = Template.bind({})
+Default.args = {
+ title: 'Dassana'
+}
diff --git a/src/components/Tooltip/Tooltip.test.tsx b/src/components/Tooltip/Tooltip.test.tsx
new file mode 100644
index 00000000..809a510a
--- /dev/null
+++ b/src/components/Tooltip/Tooltip.test.tsx
@@ -0,0 +1,40 @@
+import { Tooltip as AntDTooltip } from 'antd'
+import React from 'react'
+import { shallow, ShallowWrapper } from 'enzyme'
+import Tooltip, { TooltipProps } from './index'
+
+let wrapper: ShallowWrapper
+
+const mockTitle = 'foo'
+
+const getWrapper = (
+ additionalProps?: Omit
+): ShallowWrapper =>
+ shallow(
+
+ Hello World
+
+ )
+
+beforeEach(() => {
+ wrapper = getWrapper()
+})
+
+describe('Tooltip', () => {
+ it('renders', () => {
+ expect(wrapper).toHaveLength(1)
+ })
+
+ it('correctly passes the title prop', () => {
+ expect(wrapper.find(AntDTooltip).props().title).toEqual(mockTitle)
+ })
+
+ it('correctly passes the placement prop if one is provided', () => {
+ wrapper = getWrapper({ placement: 'top' })
+ expect(wrapper.find(AntDTooltip).props().placement).toEqual('top')
+ })
+
+ it('has a default placement of right', () => {
+ expect(wrapper.find(AntDTooltip).props().placement).toBe('right')
+ })
+})
diff --git a/src/components/Tooltip/index.tsx b/src/components/Tooltip/index.tsx
new file mode 100644
index 00000000..372d0f4f
--- /dev/null
+++ b/src/components/Tooltip/index.tsx
@@ -0,0 +1,51 @@
+import '../assets/styles/antdAnimations.css'
+import 'antd/lib/tooltip/style/index.css'
+import { Tooltip as AntDTooltip } from 'antd'
+import cn from 'classnames'
+import { CommonComponentProps } from '../types'
+import { getDataTestAttributeProp } from '../utils'
+import { TooltipPlacement } from 'antd/es/tooltip'
+import React, { FC, ReactNode } from 'react'
+
+export type TooltipTitle = string | ReactNode
+
+export interface TooltipProps extends CommonComponentProps {
+ /**
+ * Element tooltip should be anchored to
+ */
+ children: ReactNode
+ /**
+ * Array of classes to pass to element
+ * @default []
+ */
+ classes?: string[]
+ /**
+ * Position of tooltip relative to the target
+ */
+ placement?: TooltipPlacement
+ /**
+ * Text shown in the tooltip
+ */
+ title: TooltipTitle
+}
+
+const Tooltip: FC = ({
+ children,
+ classes = [],
+ dataTag,
+ placement = 'right',
+ title
+}: TooltipProps) => (
+
+
+ {children}
+
+
+)
+
+export default Tooltip
diff --git a/src/components/Tree/Tree.stories.tsx b/src/components/Tree/Tree.stories.tsx
new file mode 100644
index 00000000..b431dd28
--- /dev/null
+++ b/src/components/Tree/Tree.stories.tsx
@@ -0,0 +1,36 @@
+import { action } from '@storybook/addon-actions'
+import React from 'react'
+import treeData0 from './fixtures/0_sample_data'
+import { Meta, Story } from '@storybook/react/types-6-0'
+import Tree, { TreeProps } from './index'
+
+export default {
+ argTypes: {
+ onChange: {
+ control: { disable: true },
+ defaultValue: action('onChange')
+ },
+ treeData: {
+ table: {
+ type: {
+ detail: `interface TreeNodeType {
+ id: string | number
+ name: string
+ children?: TreeNodeType[]
+}
+ `
+ }
+ }
+ }
+ },
+ component: Tree,
+ title: 'Tree'
+} as Meta
+
+const Template: Story = args =>
+
+export const Default = Template.bind({})
+
+Default.args = {
+ treeData: treeData0
+}
diff --git a/src/components/Tree/TreeSkeleton.tsx b/src/components/Tree/TreeSkeleton.tsx
new file mode 100644
index 00000000..2366f8df
--- /dev/null
+++ b/src/components/Tree/TreeSkeleton.tsx
@@ -0,0 +1,72 @@
+import { createUseStyles } from 'react-jss'
+import random from 'lodash/random'
+import Skeleton from '../Skeleton'
+import times from 'lodash/times'
+import React, { FC, Fragment, Key } from 'react'
+
+const useStyles = createUseStyles({
+ skeletonLabel: {
+ marginLeft: 5
+ },
+ treeNodeSkeleton: {
+ alignItems: 'center',
+ display: 'flex',
+ marginLeft: props => (props.nestLevel ? props.nestLevel * 20 : 0),
+ paddingBottom: 10
+ }
+})
+
+interface TreeNodeSkeletonProps {
+ nestLevel?: number
+}
+
+export const TreeNodeSkeleton: FC = (
+ props: TreeNodeSkeletonProps
+) => {
+ const classes = useStyles(props)
+
+ return (
+
+
+
+
+ )
+}
+
+const generateTreeNodeSkeletons = (count: number, treeNodeCount?: number) => (
+ <>
+ {times(count, (j: number) => {
+ return (
+
+ )
+ })}
+ >
+)
+
+const generateTreeBlock = (i: Key, treeNodeCount: number) => (
+
+ {generateTreeNodeSkeletons(treeNodeCount - 1)}
+ {generateTreeNodeSkeletons(random(1, 3), treeNodeCount)}
+
+)
+
+interface TreeSkeletonProps {
+ blockCount: number
+ treeNodeCount: number
+}
+
+const TreeSkeleton: FC = ({
+ blockCount,
+ treeNodeCount
+}: TreeSkeletonProps) => (
+ {times(blockCount, i => generateTreeBlock(i, treeNodeCount))}
+)
+
+export default TreeSkeleton
diff --git a/src/components/Tree/__tests__/Tree.test.tsx b/src/components/Tree/__tests__/Tree.test.tsx
new file mode 100644
index 00000000..d8e462af
--- /dev/null
+++ b/src/components/Tree/__tests__/Tree.test.tsx
@@ -0,0 +1,94 @@
+import { Tree as AntDTree } from 'antd'
+import React from 'react'
+import Tree from '../index'
+import treeData0 from '../fixtures/0_sample_data'
+import TreeSkeleton from '../TreeSkeleton'
+import { mount, ReactWrapper, shallow, ShallowWrapper } from 'enzyme'
+
+/* Helper functions */
+function getTreeNode(wrapper: ReactWrapper) {
+ return wrapper
+ .find('.ant-tree-treenode')
+ .find('.ant-tree-node-content-wrapper')
+ .at(0)
+}
+/* --------------------------------------- */
+
+const mockOnChange = jest.fn()
+
+let wrapper: ReactWrapper
+
+beforeEach(() => {
+ wrapper = mount()
+})
+
+describe('Tree', () => {
+ it('renders', () => {
+ const tree = wrapper.find(Tree)
+
+ expect(tree).toHaveLength(1)
+ })
+
+ describe('props', () => {
+ it('correctly passes treeData and onChange props if the props exist', () => {
+ const treeProps = wrapper.find(Tree).props()
+
+ expect(treeProps.treeData).toMatchObject(treeData0)
+ expect(treeProps.onChange).toEqual(mockOnChange)
+ })
+
+ it('throws an error if passed skeletonBlockCount prop is less than 1', () => {
+ expect(() =>
+ shallow()
+ ).toThrow()
+ })
+
+ it('throws an error if passed skeletonTreeNodeCount prop is less than 1', () => {
+ expect(() =>
+ shallow()
+ ).toThrow()
+ })
+ })
+
+ describe('onChange', () => {
+ it('calls onChange handler when a tree node is clicked', () => {
+ const treeNode = getTreeNode(wrapper)
+
+ expect(treeNode).toHaveLength(1)
+
+ treeNode.simulate('click')
+
+ expect(mockOnChange).toHaveBeenCalledTimes(1)
+ })
+
+ it('calls onChange handler with correct arguments when a tree node is clicked', () => {
+ const mockArgs = [3, 4, 5, 6, 7]
+ const treeNode = getTreeNode(wrapper)
+
+ expect(treeNode).toHaveLength(1)
+
+ treeNode.simulate('click')
+
+ expect(mockOnChange).toHaveBeenCalledWith(mockArgs)
+ })
+
+ it('does not pass an onCheck prop if onChange prop does not exist', () => {
+ wrapper = mount()
+ const treeNode = getTreeNode(wrapper)
+
+ expect(treeNode).toHaveLength(1)
+
+ expect(wrapper.find(AntDTree).props().onCheck).toBeUndefined()
+ })
+ })
+
+ describe('loading', () => {
+ it('renders a TreeSkeleton if loading prop is passed as true', () => {
+ const wrapper: ShallowWrapper = shallow(
+
+ )
+
+ expect(wrapper.find(TreeSkeleton)).toHaveLength(1)
+ })
+ })
+})
diff --git a/src/components/Tree/__tests__/TreeSkeleton.test.tsx b/src/components/Tree/__tests__/TreeSkeleton.test.tsx
new file mode 100644
index 00000000..eca427fc
--- /dev/null
+++ b/src/components/Tree/__tests__/TreeSkeleton.test.tsx
@@ -0,0 +1,54 @@
+import React from 'react'
+import { mount, ReactWrapper } from 'enzyme'
+import TreeSkeleton, { TreeNodeSkeleton } from '../TreeSkeleton'
+
+declare global {
+ // eslint-disable-next-line @typescript-eslint/no-namespace
+ namespace jest {
+ interface Matchers {
+ toBeWithinRange(a: number, b: number): R
+ }
+ }
+}
+
+expect.extend({
+ toBeWithinRange(received, floor, ceiling) {
+ const pass = received >= floor && received <= ceiling
+ if (pass) {
+ return {
+ message: () =>
+ `expected ${received} not to be within range ${floor} - ${ceiling}`,
+ pass: true
+ }
+ } else {
+ return {
+ message: () =>
+ `expected ${received} to be within range ${floor} - ${ceiling}`,
+ pass: false
+ }
+ }
+ }
+})
+
+let wrapper: ReactWrapper
+
+beforeEach(() => {
+ wrapper = mount()
+})
+
+describe('TreeSkeleton', () => {
+ it('renders', () => {
+ expect(wrapper.find(TreeSkeleton)).toHaveLength(1)
+ })
+
+ it('correctly passes blockCount and treeNodeCount props', () => {
+ const skeletonProps = wrapper.find(TreeSkeleton).props()
+
+ expect(skeletonProps.blockCount).toEqual(3)
+ expect(skeletonProps.treeNodeCount).toEqual(3)
+ })
+
+ it('renders correct number of SkeletonTreeNodes within range', () => {
+ expect(wrapper.find(TreeNodeSkeleton).length).toBeWithinRange(9, 15)
+ })
+})
diff --git a/src/components/Tree/__tests__/utils.test.ts b/src/components/Tree/__tests__/utils.test.ts
new file mode 100644
index 00000000..a7732138
--- /dev/null
+++ b/src/components/Tree/__tests__/utils.test.ts
@@ -0,0 +1,38 @@
+import { processTreeData } from '../utils'
+import treeData0 from '../fixtures/0_sample_data'
+
+describe('processTreeData', () => {
+ it('returns an object containing correctly formatted tree data and an object mapping keys to tree nodes', () => {
+ const processedData = [
+ {
+ children: [
+ {
+ children: [
+ { key: 3, title: 'Prod Account' },
+ { key: 4, title: 'Dev Account' }
+ ],
+ key: 1,
+ title: 'Security'
+ },
+ {
+ children: [
+ { key: 5, title: 'Prod Account' },
+ { key: 6, title: 'Dev Account' },
+ { key: 7, title: 'Test Account' }
+ ],
+ key: 2,
+ title: 'Infrastructure'
+ }
+ ],
+ key: 0,
+ title: 'AWS'
+ }
+ ]
+
+ expect(processTreeData(treeData0)).toMatchObject(processedData)
+ })
+
+ it('returns an empty array if tree data is empty', () => {
+ expect(processTreeData([])).toMatchObject([])
+ })
+})
diff --git a/src/components/Tree/fixtures/0_sample_data.ts b/src/components/Tree/fixtures/0_sample_data.ts
new file mode 100644
index 00000000..e5c2f9a7
--- /dev/null
+++ b/src/components/Tree/fixtures/0_sample_data.ts
@@ -0,0 +1,44 @@
+import { TreeNodeType } from '../'
+
+const treeData: TreeNodeType[] = [
+ {
+ children: [
+ {
+ children: [
+ {
+ id: 3,
+ name: 'Prod Account'
+ },
+ {
+ id: 4,
+ name: 'Dev Account'
+ }
+ ],
+ id: 1,
+ name: 'Security'
+ },
+ {
+ children: [
+ {
+ id: 5,
+ name: 'Prod Account'
+ },
+ {
+ id: 6,
+ name: 'Dev Account'
+ },
+ {
+ id: 7,
+ name: 'Test Account'
+ }
+ ],
+ id: 2,
+ name: 'Infrastructure'
+ }
+ ],
+ id: 0,
+ name: 'AWS'
+ }
+]
+
+export default treeData
diff --git a/src/components/Tree/index.tsx b/src/components/Tree/index.tsx
new file mode 100644
index 00000000..df77854c
--- /dev/null
+++ b/src/components/Tree/index.tsx
@@ -0,0 +1,111 @@
+import 'antd/lib/tree/style/index.css'
+import '../assets/styles/antdBaseStyles.css'
+import { Tree as AntDTree } from 'antd'
+import cn from 'classnames'
+import { CommonComponentProps } from '../types'
+import { getDataTestAttributeProp } from '../utils'
+import TreeSkeleton from './TreeSkeleton'
+import { getLeafNodeIds, processTreeData } from './utils'
+import React, { FC } from 'react'
+
+export type TreeId = string | number
+
+export interface TreeNodeType {
+ id: TreeId
+ name: string
+ children?: TreeNodeType[]
+}
+
+export interface OnChangeHandler {
+ (checkedKeys: TreeId[]): void
+}
+
+export interface TreeProps extends CommonComponentProps {
+ /**
+ * Array of nested objects of type - TreeNodeType to be passed to Tree
+ */
+ treeData: TreeNodeType[]
+ /**
+ * Array of classes to pass to element
+ */
+ classes?: string[]
+ /**
+ * Array of tree nodes that are initially default checked
+ */
+ defaultChecked?: TreeId[]
+ /**
+ * Adds the disabled attribute and styles (opacity, gray scale filter, no pointer events)
+ */
+ disabled?: boolean
+ /**
+ * Whether or not to show skeleton loader
+ */
+ loading?: boolean
+ /**
+ * Callback that runs when element is checked
+ */
+ onChange?: OnChangeHandler
+ /**
+ * Number of blocks of skeleton blocks to show if loading is true. Each block will have between 3-5 skeleton tree nodes of variable width
+ */
+ skeletonBlockCount?: number
+ /**
+ * Number of skeleton tree nodes inside a skeleton block to show if loading is true. This also determines how many levels the skeleton tree nodes will be nested
+ */
+ skeletonTreeNodeCount?: number
+}
+
+export type TreeNodesHash = Record
+
+const Tree: FC = ({
+ classes = [],
+ dataTag,
+ defaultChecked = [],
+ disabled = false,
+ loading = false,
+ onChange,
+ skeletonBlockCount = 3,
+ skeletonTreeNodeCount = 3,
+ treeData
+}: TreeProps) => {
+ const mappedTreeData = processTreeData(treeData)
+
+ let controlledCmpProps = {}
+
+ const treeClasses = cn(classes)
+
+ if (onChange) {
+ controlledCmpProps = {
+ onCheck: (_: TreeId[], info: Record) =>
+ getLeafNodeIds(info, onChange)
+ }
+ }
+
+ if (skeletonBlockCount < 1)
+ throw new Error('skeletonBlockCount must be a positive integer')
+
+ if (skeletonTreeNodeCount < 1)
+ throw new Error('skeletonTreeNodeCount must be a positive integer')
+
+ return loading ? (
+
+ ) : (
+
+ )
+}
+
+export default Tree
diff --git a/src/components/Tree/utils.ts b/src/components/Tree/utils.ts
new file mode 100644
index 00000000..b9698a6c
--- /dev/null
+++ b/src/components/Tree/utils.ts
@@ -0,0 +1,41 @@
+import { DataNode } from 'antd/es/tree'
+import { OnChangeHandler, TreeId, TreeNodeType } from '.'
+
+/**
+ * Recursive function to process TreeData. It takes an array of nested TreeNodes and returns array of nested DataNodes formatted to satisfy antD requirements.
+ */
+export const processTreeData = (nodes: TreeNodeType[] | undefined) => {
+ if (!nodes) return []
+
+ const mappedNodes = []
+
+ for (const node of nodes) {
+ // Note: To update when we know what BE will be sending
+ const mappedNode: DataNode = { key: node.id, title: node.name }
+
+ const mappedChildren = processTreeData(node.children)
+
+ if (mappedChildren.length) mappedNode.children = mappedChildren
+
+ mappedNodes.push(mappedNode)
+ }
+
+ return mappedNodes
+}
+
+/**
+ * Helper function to filter checked leaf node keys from array of all checked nodes given by antd.
+ * @param info {checkedNodes: DataNode[], ...} antd's onCheck callback param
+ * @param onChange onChange handler passed as prop to Tree
+ */
+export const getLeafNodeIds = (
+ info: Record,
+ onChange: OnChangeHandler
+) =>
+ onChange(
+ info.checkedNodes.reduce((acc: TreeId[], cur: Record) => {
+ if (!cur.children) acc.push(cur.key)
+
+ return acc
+ }, [])
+ )
diff --git a/src/components/assets/antdAnimations.css b/src/components/assets/antdAnimations.css
deleted file mode 100644
index ce6aa886..00000000
--- a/src/components/assets/antdAnimations.css
+++ /dev/null
@@ -1,438 +0,0 @@
-[class^='ant-'],
-[class*='ant-'],
-[class^='ant-'] *,
-[class*='ant-'] *,
-[class^='ant-'] *::before,
-[class*='ant-'] *::before,
-[class^='ant-'] *::after,
-[class*='ant-'] *::after {
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
-}
-*,
-*::before,
-*::after {
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-.slide-up-enter,
-.slide-up-appear {
- -webkit-animation-duration: 0.2s;
- animation-duration: 0.2s;
- -webkit-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-play-state: paused;
- animation-play-state: paused;
-}
-.slide-up-leave {
- -webkit-animation-duration: 0.2s;
- animation-duration: 0.2s;
- -webkit-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-play-state: paused;
- animation-play-state: paused;
-}
-.slide-up-enter.slide-up-enter-active,
-.slide-up-appear.slide-up-appear-active {
- -webkit-animation-name: antSlideUpIn;
- animation-name: antSlideUpIn;
- -webkit-animation-play-state: running;
- animation-play-state: running;
-}
-.slide-up-leave.slide-up-leave-active {
- -webkit-animation-name: antSlideUpOut;
- animation-name: antSlideUpOut;
- -webkit-animation-play-state: running;
- animation-play-state: running;
- pointer-events: none;
-}
-.slide-up-enter,
-.slide-up-appear {
- opacity: 0;
- -webkit-animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
- animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
-}
-.slide-up-leave {
- -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
- animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
-}
-.slide-down-enter,
-.slide-down-appear {
- -webkit-animation-duration: 0.2s;
- animation-duration: 0.2s;
- -webkit-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-play-state: paused;
- animation-play-state: paused;
-}
-.slide-down-leave {
- -webkit-animation-duration: 0.2s;
- animation-duration: 0.2s;
- -webkit-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-play-state: paused;
- animation-play-state: paused;
-}
-.slide-down-enter.slide-down-enter-active,
-.slide-down-appear.slide-down-appear-active {
- -webkit-animation-name: antSlideDownIn;
- animation-name: antSlideDownIn;
- -webkit-animation-play-state: running;
- animation-play-state: running;
-}
-.slide-down-leave.slide-down-leave-active {
- -webkit-animation-name: antSlideDownOut;
- animation-name: antSlideDownOut;
- -webkit-animation-play-state: running;
- animation-play-state: running;
- pointer-events: none;
-}
-.slide-down-enter,
-.slide-down-appear {
- opacity: 0;
- -webkit-animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
- animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
-}
-.slide-down-leave {
- -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
- animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
-}
-.slide-left-enter,
-.slide-left-appear {
- -webkit-animation-duration: 0.2s;
- animation-duration: 0.2s;
- -webkit-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-play-state: paused;
- animation-play-state: paused;
-}
-.slide-left-leave {
- -webkit-animation-duration: 0.2s;
- animation-duration: 0.2s;
- -webkit-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-play-state: paused;
- animation-play-state: paused;
-}
-.slide-left-enter.slide-left-enter-active,
-.slide-left-appear.slide-left-appear-active {
- -webkit-animation-name: antSlideLeftIn;
- animation-name: antSlideLeftIn;
- -webkit-animation-play-state: running;
- animation-play-state: running;
-}
-.slide-left-leave.slide-left-leave-active {
- -webkit-animation-name: antSlideLeftOut;
- animation-name: antSlideLeftOut;
- -webkit-animation-play-state: running;
- animation-play-state: running;
- pointer-events: none;
-}
-.slide-left-enter,
-.slide-left-appear {
- opacity: 0;
- -webkit-animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
- animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
-}
-.slide-left-leave {
- -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
- animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
-}
-.slide-right-enter,
-.slide-right-appear {
- -webkit-animation-duration: 0.2s;
- animation-duration: 0.2s;
- -webkit-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-play-state: paused;
- animation-play-state: paused;
-}
-.slide-right-leave {
- -webkit-animation-duration: 0.2s;
- animation-duration: 0.2s;
- -webkit-animation-fill-mode: both;
- animation-fill-mode: both;
- -webkit-animation-play-state: paused;
- animation-play-state: paused;
-}
-.slide-right-enter.slide-right-enter-active,
-.slide-right-appear.slide-right-appear-active {
- -webkit-animation-name: antSlideRightIn;
- animation-name: antSlideRightIn;
- -webkit-animation-play-state: running;
- animation-play-state: running;
-}
-.slide-right-leave.slide-right-leave-active {
- -webkit-animation-name: antSlideRightOut;
- animation-name: antSlideRightOut;
- -webkit-animation-play-state: running;
- animation-play-state: running;
- pointer-events: none;
-}
-.slide-right-enter,
-.slide-right-appear {
- opacity: 0;
- -webkit-animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
- animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
-}
-.slide-right-leave {
- -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
- animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
-}
-@-webkit-keyframes antSlideUpIn {
- 0% {
- -webkit-transform: scaleY(0.8);
- transform: scaleY(0.8);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 0;
- }
- 100% {
- -webkit-transform: scaleY(1);
- transform: scaleY(1);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 1;
- }
-}
-@keyframes antSlideUpIn {
- 0% {
- -webkit-transform: scaleY(0.8);
- transform: scaleY(0.8);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 0;
- }
- 100% {
- -webkit-transform: scaleY(1);
- transform: scaleY(1);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 1;
- }
-}
-@-webkit-keyframes antSlideUpOut {
- 0% {
- -webkit-transform: scaleY(1);
- transform: scaleY(1);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 1;
- }
- 100% {
- -webkit-transform: scaleY(0.8);
- transform: scaleY(0.8);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 0;
- }
-}
-@keyframes antSlideUpOut {
- 0% {
- -webkit-transform: scaleY(1);
- transform: scaleY(1);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 1;
- }
- 100% {
- -webkit-transform: scaleY(0.8);
- transform: scaleY(0.8);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 0;
- }
-}
-@-webkit-keyframes antSlideDownIn {
- 0% {
- -webkit-transform: scaleY(0.8);
- transform: scaleY(0.8);
- -webkit-transform-origin: 100% 100%;
- transform-origin: 100% 100%;
- opacity: 0;
- }
- 100% {
- -webkit-transform: scaleY(1);
- transform: scaleY(1);
- -webkit-transform-origin: 100% 100%;
- transform-origin: 100% 100%;
- opacity: 1;
- }
-}
-@keyframes antSlideDownIn {
- 0% {
- -webkit-transform: scaleY(0.8);
- transform: scaleY(0.8);
- -webkit-transform-origin: 100% 100%;
- transform-origin: 100% 100%;
- opacity: 0;
- }
- 100% {
- -webkit-transform: scaleY(1);
- transform: scaleY(1);
- -webkit-transform-origin: 100% 100%;
- transform-origin: 100% 100%;
- opacity: 1;
- }
-}
-@-webkit-keyframes antSlideDownOut {
- 0% {
- -webkit-transform: scaleY(1);
- transform: scaleY(1);
- -webkit-transform-origin: 100% 100%;
- transform-origin: 100% 100%;
- opacity: 1;
- }
- 100% {
- -webkit-transform: scaleY(0.8);
- transform: scaleY(0.8);
- -webkit-transform-origin: 100% 100%;
- transform-origin: 100% 100%;
- opacity: 0;
- }
-}
-@keyframes antSlideDownOut {
- 0% {
- -webkit-transform: scaleY(1);
- transform: scaleY(1);
- -webkit-transform-origin: 100% 100%;
- transform-origin: 100% 100%;
- opacity: 1;
- }
- 100% {
- -webkit-transform: scaleY(0.8);
- transform: scaleY(0.8);
- -webkit-transform-origin: 100% 100%;
- transform-origin: 100% 100%;
- opacity: 0;
- }
-}
-@-webkit-keyframes antSlideLeftIn {
- 0% {
- -webkit-transform: scaleX(0.8);
- transform: scaleX(0.8);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 0;
- }
- 100% {
- -webkit-transform: scaleX(1);
- transform: scaleX(1);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 1;
- }
-}
-@keyframes antSlideLeftIn {
- 0% {
- -webkit-transform: scaleX(0.8);
- transform: scaleX(0.8);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 0;
- }
- 100% {
- -webkit-transform: scaleX(1);
- transform: scaleX(1);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 1;
- }
-}
-@-webkit-keyframes antSlideLeftOut {
- 0% {
- -webkit-transform: scaleX(1);
- transform: scaleX(1);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 1;
- }
- 100% {
- -webkit-transform: scaleX(0.8);
- transform: scaleX(0.8);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 0;
- }
-}
-@keyframes antSlideLeftOut {
- 0% {
- -webkit-transform: scaleX(1);
- transform: scaleX(1);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 1;
- }
- 100% {
- -webkit-transform: scaleX(0.8);
- transform: scaleX(0.8);
- -webkit-transform-origin: 0% 0%;
- transform-origin: 0% 0%;
- opacity: 0;
- }
-}
-@-webkit-keyframes antSlideRightIn {
- 0% {
- -webkit-transform: scaleX(0.8);
- transform: scaleX(0.8);
- -webkit-transform-origin: 100% 0%;
- transform-origin: 100% 0%;
- opacity: 0;
- }
- 100% {
- -webkit-transform: scaleX(1);
- transform: scaleX(1);
- -webkit-transform-origin: 100% 0%;
- transform-origin: 100% 0%;
- opacity: 1;
- }
-}
-@keyframes antSlideRightIn {
- 0% {
- -webkit-transform: scaleX(0.8);
- transform: scaleX(0.8);
- -webkit-transform-origin: 100% 0%;
- transform-origin: 100% 0%;
- opacity: 0;
- }
- 100% {
- -webkit-transform: scaleX(1);
- transform: scaleX(1);
- -webkit-transform-origin: 100% 0%;
- transform-origin: 100% 0%;
- opacity: 1;
- }
-}
-@-webkit-keyframes antSlideRightOut {
- 0% {
- -webkit-transform: scaleX(1);
- transform: scaleX(1);
- -webkit-transform-origin: 100% 0%;
- transform-origin: 100% 0%;
- opacity: 1;
- }
- 100% {
- -webkit-transform: scaleX(0.8);
- transform: scaleX(0.8);
- -webkit-transform-origin: 100% 0%;
- transform-origin: 100% 0%;
- opacity: 0;
- }
-}
-@keyframes antSlideRightOut {
- 0% {
- -webkit-transform: scaleX(1);
- transform: scaleX(1);
- -webkit-transform-origin: 100% 0%;
- transform-origin: 100% 0%;
- opacity: 1;
- }
- 100% {
- -webkit-transform: scaleX(0.8);
- transform: scaleX(0.8);
- -webkit-transform-origin: 100% 0%;
- transform-origin: 100% 0%;
- opacity: 0;
- }
-}
diff --git a/src/components/assets/styles/antdAnimations.css b/src/components/assets/styles/antdAnimations.css
new file mode 100644
index 00000000..61e55b15
--- /dev/null
+++ b/src/components/assets/styles/antdAnimations.css
@@ -0,0 +1,1636 @@
+@import './antdBaseStyles.css';
+
+.fade-enter,
+.fade-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.fade-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.fade-enter.fade-enter-active,
+.fade-appear.fade-appear-active {
+ -webkit-animation-name: antFadeIn;
+ animation-name: antFadeIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.fade-leave.fade-leave-active {
+ -webkit-animation-name: antFadeOut;
+ animation-name: antFadeOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.fade-enter,
+.fade-appear {
+ opacity: 0;
+ -webkit-animation-timing-function: linear;
+ animation-timing-function: linear;
+}
+.fade-leave {
+ -webkit-animation-timing-function: linear;
+ animation-timing-function: linear;
+}
+@-webkit-keyframes antFadeIn {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+@keyframes antFadeIn {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+@-webkit-keyframes antFadeOut {
+ 0% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0;
+ }
+}
+@keyframes antFadeOut {
+ 0% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0;
+ }
+}
+.move-up-enter,
+.move-up-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.move-up-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.move-up-enter.move-up-enter-active,
+.move-up-appear.move-up-appear-active {
+ -webkit-animation-name: antMoveUpIn;
+ animation-name: antMoveUpIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.move-up-leave.move-up-leave-active {
+ -webkit-animation-name: antMoveUpOut;
+ animation-name: antMoveUpOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.move-up-enter,
+.move-up-appear {
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+}
+.move-up-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
+ animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
+}
+.move-down-enter,
+.move-down-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.move-down-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.move-down-enter.move-down-enter-active,
+.move-down-appear.move-down-appear-active {
+ -webkit-animation-name: antMoveDownIn;
+ animation-name: antMoveDownIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.move-down-leave.move-down-leave-active {
+ -webkit-animation-name: antMoveDownOut;
+ animation-name: antMoveDownOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.move-down-enter,
+.move-down-appear {
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+}
+.move-down-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
+ animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
+}
+.move-left-enter,
+.move-left-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.move-left-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.move-left-enter.move-left-enter-active,
+.move-left-appear.move-left-appear-active {
+ -webkit-animation-name: antMoveLeftIn;
+ animation-name: antMoveLeftIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.move-left-leave.move-left-leave-active {
+ -webkit-animation-name: antMoveLeftOut;
+ animation-name: antMoveLeftOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.move-left-enter,
+.move-left-appear {
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+}
+.move-left-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
+ animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
+}
+.move-right-enter,
+.move-right-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.move-right-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.move-right-enter.move-right-enter-active,
+.move-right-appear.move-right-appear-active {
+ -webkit-animation-name: antMoveRightIn;
+ animation-name: antMoveRightIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.move-right-leave.move-right-leave-active {
+ -webkit-animation-name: antMoveRightOut;
+ animation-name: antMoveRightOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.move-right-enter,
+.move-right-appear {
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+}
+.move-right-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
+ animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
+}
+@-webkit-keyframes antMoveDownIn {
+ 0% {
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: translateY(0%);
+ transform: translateY(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+}
+@keyframes antMoveDownIn {
+ 0% {
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: translateY(0%);
+ transform: translateY(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+}
+@-webkit-keyframes antMoveDownOut {
+ 0% {
+ -webkit-transform: translateY(0%);
+ transform: translateY(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+}
+@keyframes antMoveDownOut {
+ 0% {
+ -webkit-transform: translateY(0%);
+ transform: translateY(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+}
+@-webkit-keyframes antMoveLeftIn {
+ 0% {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: translateX(0%);
+ transform: translateX(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+}
+@keyframes antMoveLeftIn {
+ 0% {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: translateX(0%);
+ transform: translateX(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+}
+@-webkit-keyframes antMoveLeftOut {
+ 0% {
+ -webkit-transform: translateX(0%);
+ transform: translateX(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+}
+@keyframes antMoveLeftOut {
+ 0% {
+ -webkit-transform: translateX(0%);
+ transform: translateX(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+}
+@-webkit-keyframes antMoveRightIn {
+ 0% {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: translateX(0%);
+ transform: translateX(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+}
+@keyframes antMoveRightIn {
+ 0% {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: translateX(0%);
+ transform: translateX(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+}
+@-webkit-keyframes antMoveRightOut {
+ 0% {
+ -webkit-transform: translateX(0%);
+ transform: translateX(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+}
+@keyframes antMoveRightOut {
+ 0% {
+ -webkit-transform: translateX(0%);
+ transform: translateX(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+}
+@-webkit-keyframes antMoveUpIn {
+ 0% {
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: translateY(0%);
+ transform: translateY(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+}
+@keyframes antMoveUpIn {
+ 0% {
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: translateY(0%);
+ transform: translateY(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+}
+@-webkit-keyframes antMoveUpOut {
+ 0% {
+ -webkit-transform: translateY(0%);
+ transform: translateY(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+}
+@keyframes antMoveUpOut {
+ 0% {
+ -webkit-transform: translateY(0%);
+ transform: translateY(0%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ -webkit-transform-origin: 0 0;
+ transform-origin: 0 0;
+ opacity: 0;
+ }
+}
+html {
+ --antd-wave-shadow-color: #1890ff;
+ --scroll-bar: 0;
+}
+[ant-click-animating-without-extra-node='true']::after,
+.ant-click-animating-node {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ display: block;
+ border-radius: inherit;
+ -webkit-box-shadow: 0 0 0 0 #1890ff;
+ box-shadow: 0 0 0 0 #1890ff;
+ -webkit-box-shadow: 0 0 0 0 var(--antd-wave-shadow-color);
+ box-shadow: 0 0 0 0 var(--antd-wave-shadow-color);
+ opacity: 0.2;
+ -webkit-animation: fadeEffect 2s cubic-bezier(0.08, 0.82, 0.17, 1),
+ waveEffect 0.4s cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation: fadeEffect 2s cubic-bezier(0.08, 0.82, 0.17, 1),
+ waveEffect 0.4s cubic-bezier(0.08, 0.82, 0.17, 1);
+ -webkit-animation-fill-mode: forwards;
+ animation-fill-mode: forwards;
+ content: '';
+ pointer-events: none;
+}
+@-webkit-keyframes waveEffect {
+ 100% {
+ -webkit-box-shadow: 0 0 0 #1890ff;
+ box-shadow: 0 0 0 #1890ff;
+ -webkit-box-shadow: 0 0 0 6px var(--antd-wave-shadow-color);
+ box-shadow: 0 0 0 6px var(--antd-wave-shadow-color);
+ }
+}
+@keyframes waveEffect {
+ 100% {
+ -webkit-box-shadow: 0 0 0 #1890ff;
+ box-shadow: 0 0 0 #1890ff;
+ -webkit-box-shadow: 0 0 0 6px var(--antd-wave-shadow-color);
+ box-shadow: 0 0 0 6px var(--antd-wave-shadow-color);
+ }
+}
+@-webkit-keyframes fadeEffect {
+ 100% {
+ opacity: 0;
+ }
+}
+@keyframes fadeEffect {
+ 100% {
+ opacity: 0;
+ }
+}
+.slide-up-enter,
+.slide-up-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.slide-up-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.slide-up-enter.slide-up-enter-active,
+.slide-up-appear.slide-up-appear-active {
+ -webkit-animation-name: antSlideUpIn;
+ animation-name: antSlideUpIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.slide-up-leave.slide-up-leave-active {
+ -webkit-animation-name: antSlideUpOut;
+ animation-name: antSlideUpOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.slide-up-enter,
+.slide-up-appear {
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
+ animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
+}
+.slide-up-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+ animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+}
+.slide-down-enter,
+.slide-down-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.slide-down-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.slide-down-enter.slide-down-enter-active,
+.slide-down-appear.slide-down-appear-active {
+ -webkit-animation-name: antSlideDownIn;
+ animation-name: antSlideDownIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.slide-down-leave.slide-down-leave-active {
+ -webkit-animation-name: antSlideDownOut;
+ animation-name: antSlideDownOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.slide-down-enter,
+.slide-down-appear {
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
+ animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
+}
+.slide-down-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+ animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+}
+.slide-left-enter,
+.slide-left-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.slide-left-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.slide-left-enter.slide-left-enter-active,
+.slide-left-appear.slide-left-appear-active {
+ -webkit-animation-name: antSlideLeftIn;
+ animation-name: antSlideLeftIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.slide-left-leave.slide-left-leave-active {
+ -webkit-animation-name: antSlideLeftOut;
+ animation-name: antSlideLeftOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.slide-left-enter,
+.slide-left-appear {
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
+ animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
+}
+.slide-left-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+ animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+}
+.slide-right-enter,
+.slide-right-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.slide-right-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.slide-right-enter.slide-right-enter-active,
+.slide-right-appear.slide-right-appear-active {
+ -webkit-animation-name: antSlideRightIn;
+ animation-name: antSlideRightIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.slide-right-leave.slide-right-leave-active {
+ -webkit-animation-name: antSlideRightOut;
+ animation-name: antSlideRightOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.slide-right-enter,
+.slide-right-appear {
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
+ animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
+}
+.slide-right-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+ animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
+}
+@-webkit-keyframes antSlideUpIn {
+ 0% {
+ -webkit-transform: scaleY(0.8);
+ transform: scaleY(0.8);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scaleY(1);
+ transform: scaleY(1);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 1;
+ }
+}
+@keyframes antSlideUpIn {
+ 0% {
+ -webkit-transform: scaleY(0.8);
+ transform: scaleY(0.8);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scaleY(1);
+ transform: scaleY(1);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 1;
+ }
+}
+@-webkit-keyframes antSlideUpOut {
+ 0% {
+ -webkit-transform: scaleY(1);
+ transform: scaleY(1);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: scaleY(0.8);
+ transform: scaleY(0.8);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 0;
+ }
+}
+@keyframes antSlideUpOut {
+ 0% {
+ -webkit-transform: scaleY(1);
+ transform: scaleY(1);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: scaleY(0.8);
+ transform: scaleY(0.8);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 0;
+ }
+}
+@-webkit-keyframes antSlideDownIn {
+ 0% {
+ -webkit-transform: scaleY(0.8);
+ transform: scaleY(0.8);
+ -webkit-transform-origin: 100% 100%;
+ transform-origin: 100% 100%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scaleY(1);
+ transform: scaleY(1);
+ -webkit-transform-origin: 100% 100%;
+ transform-origin: 100% 100%;
+ opacity: 1;
+ }
+}
+@keyframes antSlideDownIn {
+ 0% {
+ -webkit-transform: scaleY(0.8);
+ transform: scaleY(0.8);
+ -webkit-transform-origin: 100% 100%;
+ transform-origin: 100% 100%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scaleY(1);
+ transform: scaleY(1);
+ -webkit-transform-origin: 100% 100%;
+ transform-origin: 100% 100%;
+ opacity: 1;
+ }
+}
+@-webkit-keyframes antSlideDownOut {
+ 0% {
+ -webkit-transform: scaleY(1);
+ transform: scaleY(1);
+ -webkit-transform-origin: 100% 100%;
+ transform-origin: 100% 100%;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: scaleY(0.8);
+ transform: scaleY(0.8);
+ -webkit-transform-origin: 100% 100%;
+ transform-origin: 100% 100%;
+ opacity: 0;
+ }
+}
+@keyframes antSlideDownOut {
+ 0% {
+ -webkit-transform: scaleY(1);
+ transform: scaleY(1);
+ -webkit-transform-origin: 100% 100%;
+ transform-origin: 100% 100%;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: scaleY(0.8);
+ transform: scaleY(0.8);
+ -webkit-transform-origin: 100% 100%;
+ transform-origin: 100% 100%;
+ opacity: 0;
+ }
+}
+@-webkit-keyframes antSlideLeftIn {
+ 0% {
+ -webkit-transform: scaleX(0.8);
+ transform: scaleX(0.8);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 1;
+ }
+}
+@keyframes antSlideLeftIn {
+ 0% {
+ -webkit-transform: scaleX(0.8);
+ transform: scaleX(0.8);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 1;
+ }
+}
+@-webkit-keyframes antSlideLeftOut {
+ 0% {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: scaleX(0.8);
+ transform: scaleX(0.8);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 0;
+ }
+}
+@keyframes antSlideLeftOut {
+ 0% {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: scaleX(0.8);
+ transform: scaleX(0.8);
+ -webkit-transform-origin: 0% 0%;
+ transform-origin: 0% 0%;
+ opacity: 0;
+ }
+}
+@-webkit-keyframes antSlideRightIn {
+ 0% {
+ -webkit-transform: scaleX(0.8);
+ transform: scaleX(0.8);
+ -webkit-transform-origin: 100% 0%;
+ transform-origin: 100% 0%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ -webkit-transform-origin: 100% 0%;
+ transform-origin: 100% 0%;
+ opacity: 1;
+ }
+}
+@keyframes antSlideRightIn {
+ 0% {
+ -webkit-transform: scaleX(0.8);
+ transform: scaleX(0.8);
+ -webkit-transform-origin: 100% 0%;
+ transform-origin: 100% 0%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ -webkit-transform-origin: 100% 0%;
+ transform-origin: 100% 0%;
+ opacity: 1;
+ }
+}
+@-webkit-keyframes antSlideRightOut {
+ 0% {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ -webkit-transform-origin: 100% 0%;
+ transform-origin: 100% 0%;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: scaleX(0.8);
+ transform: scaleX(0.8);
+ -webkit-transform-origin: 100% 0%;
+ transform-origin: 100% 0%;
+ opacity: 0;
+ }
+}
+@keyframes antSlideRightOut {
+ 0% {
+ -webkit-transform: scaleX(1);
+ transform: scaleX(1);
+ -webkit-transform-origin: 100% 0%;
+ transform-origin: 100% 0%;
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: scaleX(0.8);
+ transform: scaleX(0.8);
+ -webkit-transform-origin: 100% 0%;
+ transform-origin: 100% 0%;
+ opacity: 0;
+ }
+}
+.zoom-enter,
+.zoom-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-enter.zoom-enter-active,
+.zoom-appear.zoom-appear-active {
+ -webkit-animation-name: antZoomIn;
+ animation-name: antZoomIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.zoom-leave.zoom-leave-active {
+ -webkit-animation-name: antZoomOut;
+ animation-name: antZoomOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.zoom-enter,
+.zoom-appear {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+}
+.zoom-enter-prepare,
+.zoom-appear-prepare {
+ -webkit-transform: none;
+ transform: none;
+}
+.zoom-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+ animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+}
+.zoom-big-enter,
+.zoom-big-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-big-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-big-enter.zoom-big-enter-active,
+.zoom-big-appear.zoom-big-appear-active {
+ -webkit-animation-name: antZoomBigIn;
+ animation-name: antZoomBigIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.zoom-big-leave.zoom-big-leave-active {
+ -webkit-animation-name: antZoomBigOut;
+ animation-name: antZoomBigOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.zoom-big-enter,
+.zoom-big-appear {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+}
+.zoom-big-enter-prepare,
+.zoom-big-appear-prepare {
+ -webkit-transform: none;
+ transform: none;
+}
+.zoom-big-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+ animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+}
+.zoom-big-fast-enter,
+.zoom-big-fast-appear {
+ -webkit-animation-duration: 0.1s;
+ animation-duration: 0.1s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-big-fast-leave {
+ -webkit-animation-duration: 0.1s;
+ animation-duration: 0.1s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-big-fast-enter.zoom-big-fast-enter-active,
+.zoom-big-fast-appear.zoom-big-fast-appear-active {
+ -webkit-animation-name: antZoomBigIn;
+ animation-name: antZoomBigIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.zoom-big-fast-leave.zoom-big-fast-leave-active {
+ -webkit-animation-name: antZoomBigOut;
+ animation-name: antZoomBigOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.zoom-big-fast-enter,
+.zoom-big-fast-appear {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+}
+.zoom-big-fast-enter-prepare,
+.zoom-big-fast-appear-prepare {
+ -webkit-transform: none;
+ transform: none;
+}
+.zoom-big-fast-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+ animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+}
+.zoom-up-enter,
+.zoom-up-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-up-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-up-enter.zoom-up-enter-active,
+.zoom-up-appear.zoom-up-appear-active {
+ -webkit-animation-name: antZoomUpIn;
+ animation-name: antZoomUpIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.zoom-up-leave.zoom-up-leave-active {
+ -webkit-animation-name: antZoomUpOut;
+ animation-name: antZoomUpOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.zoom-up-enter,
+.zoom-up-appear {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+}
+.zoom-up-enter-prepare,
+.zoom-up-appear-prepare {
+ -webkit-transform: none;
+ transform: none;
+}
+.zoom-up-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+ animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+}
+.zoom-down-enter,
+.zoom-down-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-down-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-down-enter.zoom-down-enter-active,
+.zoom-down-appear.zoom-down-appear-active {
+ -webkit-animation-name: antZoomDownIn;
+ animation-name: antZoomDownIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.zoom-down-leave.zoom-down-leave-active {
+ -webkit-animation-name: antZoomDownOut;
+ animation-name: antZoomDownOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.zoom-down-enter,
+.zoom-down-appear {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+}
+.zoom-down-enter-prepare,
+.zoom-down-appear-prepare {
+ -webkit-transform: none;
+ transform: none;
+}
+.zoom-down-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+ animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+}
+.zoom-left-enter,
+.zoom-left-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-left-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-left-enter.zoom-left-enter-active,
+.zoom-left-appear.zoom-left-appear-active {
+ -webkit-animation-name: antZoomLeftIn;
+ animation-name: antZoomLeftIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.zoom-left-leave.zoom-left-leave-active {
+ -webkit-animation-name: antZoomLeftOut;
+ animation-name: antZoomLeftOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.zoom-left-enter,
+.zoom-left-appear {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+}
+.zoom-left-enter-prepare,
+.zoom-left-appear-prepare {
+ -webkit-transform: none;
+ transform: none;
+}
+.zoom-left-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+ animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+}
+.zoom-right-enter,
+.zoom-right-appear {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-right-leave {
+ -webkit-animation-duration: 0.2s;
+ animation-duration: 0.2s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation-play-state: paused;
+ animation-play-state: paused;
+}
+.zoom-right-enter.zoom-right-enter-active,
+.zoom-right-appear.zoom-right-appear-active {
+ -webkit-animation-name: antZoomRightIn;
+ animation-name: antZoomRightIn;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+}
+.zoom-right-leave.zoom-right-leave-active {
+ -webkit-animation-name: antZoomRightOut;
+ animation-name: antZoomRightOut;
+ -webkit-animation-play-state: running;
+ animation-play-state: running;
+ pointer-events: none;
+}
+.zoom-right-enter,
+.zoom-right-appear {
+ -webkit-transform: scale(0);
+ transform: scale(0);
+ opacity: 0;
+ -webkit-animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+ animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
+}
+.zoom-right-enter-prepare,
+.zoom-right-appear-prepare {
+ -webkit-transform: none;
+ transform: none;
+}
+.zoom-right-leave {
+ -webkit-animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+ animation-timing-function: cubic-bezier(0.78, 0.14, 0.15, 0.86);
+}
+@-webkit-keyframes antZoomIn {
+ 0% {
+ -webkit-transform: scale(0.2);
+ transform: scale(0.2);
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+@keyframes antZoomIn {
+ 0% {
+ -webkit-transform: scale(0.2);
+ transform: scale(0.2);
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+@-webkit-keyframes antZoomOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ }
+ 100% {
+ -webkit-transform: scale(0.2);
+ transform: scale(0.2);
+ opacity: 0;
+ }
+}
+@keyframes antZoomOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ }
+ 100% {
+ -webkit-transform: scale(0.2);
+ transform: scale(0.2);
+ opacity: 0;
+ }
+}
+@-webkit-keyframes antZoomBigIn {
+ 0% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+@keyframes antZoomBigIn {
+ 0% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+@-webkit-keyframes antZoomBigOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ }
+ 100% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ opacity: 0;
+ }
+}
+@keyframes antZoomBigOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ }
+ 100% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ opacity: 0;
+ }
+}
+@-webkit-keyframes antZoomUpIn {
+ 0% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 50% 0%;
+ transform-origin: 50% 0%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 50% 0%;
+ transform-origin: 50% 0%;
+ }
+}
+@keyframes antZoomUpIn {
+ 0% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 50% 0%;
+ transform-origin: 50% 0%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 50% 0%;
+ transform-origin: 50% 0%;
+ }
+}
+@-webkit-keyframes antZoomUpOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 50% 0%;
+ transform-origin: 50% 0%;
+ }
+ 100% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 50% 0%;
+ transform-origin: 50% 0%;
+ opacity: 0;
+ }
+}
+@keyframes antZoomUpOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 50% 0%;
+ transform-origin: 50% 0%;
+ }
+ 100% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 50% 0%;
+ transform-origin: 50% 0%;
+ opacity: 0;
+ }
+}
+@-webkit-keyframes antZoomLeftIn {
+ 0% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 0% 50%;
+ transform-origin: 0% 50%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 0% 50%;
+ transform-origin: 0% 50%;
+ }
+}
+@keyframes antZoomLeftIn {
+ 0% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 0% 50%;
+ transform-origin: 0% 50%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 0% 50%;
+ transform-origin: 0% 50%;
+ }
+}
+@-webkit-keyframes antZoomLeftOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 0% 50%;
+ transform-origin: 0% 50%;
+ }
+ 100% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 0% 50%;
+ transform-origin: 0% 50%;
+ opacity: 0;
+ }
+}
+@keyframes antZoomLeftOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 0% 50%;
+ transform-origin: 0% 50%;
+ }
+ 100% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 0% 50%;
+ transform-origin: 0% 50%;
+ opacity: 0;
+ }
+}
+@-webkit-keyframes antZoomRightIn {
+ 0% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 100% 50%;
+ transform-origin: 100% 50%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 100% 50%;
+ transform-origin: 100% 50%;
+ }
+}
+@keyframes antZoomRightIn {
+ 0% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 100% 50%;
+ transform-origin: 100% 50%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 100% 50%;
+ transform-origin: 100% 50%;
+ }
+}
+@-webkit-keyframes antZoomRightOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 100% 50%;
+ transform-origin: 100% 50%;
+ }
+ 100% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 100% 50%;
+ transform-origin: 100% 50%;
+ opacity: 0;
+ }
+}
+@keyframes antZoomRightOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 100% 50%;
+ transform-origin: 100% 50%;
+ }
+ 100% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 100% 50%;
+ transform-origin: 100% 50%;
+ opacity: 0;
+ }
+}
+@-webkit-keyframes antZoomDownIn {
+ 0% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 50% 100%;
+ transform-origin: 50% 100%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 50% 100%;
+ transform-origin: 50% 100%;
+ }
+}
+@keyframes antZoomDownIn {
+ 0% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 50% 100%;
+ transform-origin: 50% 100%;
+ opacity: 0;
+ }
+ 100% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 50% 100%;
+ transform-origin: 50% 100%;
+ }
+}
+@-webkit-keyframes antZoomDownOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 50% 100%;
+ transform-origin: 50% 100%;
+ }
+ 100% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 50% 100%;
+ transform-origin: 50% 100%;
+ opacity: 0;
+ }
+}
+@keyframes antZoomDownOut {
+ 0% {
+ -webkit-transform: scale(1);
+ transform: scale(1);
+ -webkit-transform-origin: 50% 100%;
+ transform-origin: 50% 100%;
+ }
+ 100% {
+ -webkit-transform: scale(0.8);
+ transform: scale(0.8);
+ -webkit-transform-origin: 50% 100%;
+ transform-origin: 50% 100%;
+ opacity: 0;
+ }
+}
diff --git a/src/components/assets/styles/antdBaseStyles.css b/src/components/assets/styles/antdBaseStyles.css
new file mode 100644
index 00000000..90ba8e70
--- /dev/null
+++ b/src/components/assets/styles/antdBaseStyles.css
@@ -0,0 +1,22 @@
+[class^='ant-'],
+[class*='ant-'],
+[class^='ant-'] *,
+[class*='ant-'] *,
+[class^='ant-'] *::before,
+[class*='ant-'] *::before,
+[class^='ant-'] *::after,
+[class*='ant-'] *::after {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+*,
+*::before,
+*::after {
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+img {
+ vertical-align: middle;
+ border-style: none;
+}
diff --git a/src/components/assets/styleguide.ts b/src/components/assets/styles/styleguide.ts
similarity index 88%
rename from src/components/assets/styleguide.ts
rename to src/components/assets/styles/styleguide.ts
index d4d555b3..12f44ef3 100644
--- a/src/components/assets/styleguide.ts
+++ b/src/components/assets/styles/styleguide.ts
@@ -14,3 +14,4 @@ export const fieldErrorStyles = {
}
export const fontSizeRegular = '14px'
export const linkColor = '#1EA7FD'
+export const skeletonButtonBorderColor = '#DFDFDF'
diff --git a/src/components/index.ts b/src/components/index.ts
index 5653d4e5..92ccd1e3 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -4,9 +4,13 @@ export { default as Input } from './Input'
export { default as Icon } from './Icon'
export { default as Link } from './Link'
export * from './Notification'
+export { default as Popover } from './Popover'
+export { default as RadioGroup } from './RadioGroup'
export { default as Select } from './Select'
export { default as Skeleton } from './Skeleton'
export { default as Table } from './Table'
export { default as Tag } from './Tag'
export { default as Toggle } from './Toggle'
+export { default as Tooltip } from './Tooltip'
+export { default as Tree } from './Tree'
export * from './types'
diff --git a/src/components/utils.ts b/src/components/utils.ts
index 10059e47..fb355f80 100644
--- a/src/components/utils.ts
+++ b/src/components/utils.ts
@@ -1,3 +1,5 @@
+import { TooltipPlacement } from 'antd/es/tooltip'
+
export const TAG = 'data-test'
export const getDataTestAttributeProp = (
@@ -6,3 +8,18 @@ export const getDataTestAttributeProp = (
): { [TAG]: string } => ({
[TAG]: dataTag ? `${cmpName}-${dataTag}` : cmpName
})
+
+export const placementOptions: TooltipPlacement[] = [
+ 'bottom',
+ 'bottomLeft',
+ 'bottomRight',
+ 'left',
+ 'leftBottom',
+ 'leftTop',
+ 'right',
+ 'rightBottom',
+ 'rightTop',
+ 'top',
+ 'topLeft',
+ 'topRight'
+]
diff --git a/src/storybook.test.ts b/src/storybook.test.ts
index 750317cf..792636d3 100644
--- a/src/storybook.test.ts
+++ b/src/storybook.test.ts
@@ -1,2 +1,13 @@
-import initStoryshots from '@storybook/addon-storyshots'
-initStoryshots()
+import initStoryshots, {
+ shallowSnapshot,
+ snapshot
+} from '@storybook/addon-storyshots'
+
+const componentsToShallowRender = ['Tree']
+
+initStoryshots({
+ test: data =>
+ componentsToShallowRender.includes(data.context.kind)
+ ? shallowSnapshot(data)
+ : snapshot(data)
+})