pcm-shared-components 0.0.62 → 0.0.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,8 +3,8 @@ import { Button, Dialog, DialogActions, DialogContent, IconButton, Typography, T
3
3
  import ArrowBackIcon from '@mui/icons-material/ArrowBack';
4
4
  import { ThemeProvider } from '@mui/system';
5
5
  import { createTheme, useTheme } from '@mui/material/styles';
6
- import LoadingBackdrop from '../../Loaders/LoadingBackdrop'; // import GridLoading from 'app/main/components/loading/loading';
7
-
6
+ import LoadingBackdrop from '../../Loaders/LoadingBackdrop';
7
+ import PerfectScrollbar from '../../Tools/PCMScrollbar';
8
8
  import PropTypes from 'prop-types';
9
9
  let debounce;
10
10
  export const GenericDialogWindow = props => {
@@ -80,6 +80,9 @@ export const GenericDialogWindow = props => {
80
80
  onClick: onSave
81
81
  }, save_button_label)))), /*#__PURE__*/React.createElement(DialogContent, {
82
82
  className: "pt-4 pl-0 pr-0 "
83
+ }, /*#__PURE__*/React.createElement(PerfectScrollbar, {
84
+ className: "",
85
+ enable: true
83
86
  }, /*#__PURE__*/React.createElement("div", {
84
87
  className: "w-full h-full "
85
88
  }, component ? /*#__PURE__*/React.cloneElement(component, {
@@ -91,7 +94,7 @@ export const GenericDialogWindow = props => {
91
94
  data: data
92
95
  },
93
96
  ref: childRef
94
- }) : /*#__PURE__*/React.createElement(React.Fragment, null))), /*#__PURE__*/React.createElement(DialogActions, {
97
+ }) : /*#__PURE__*/React.createElement(React.Fragment, null)))), /*#__PURE__*/React.createElement(DialogActions, {
95
98
  className: "justify-between pl-16"
96
99
  }, showSaveButton && /*#__PURE__*/React.createElement(Button, {
97
100
  variant: "contained",
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect } from 'react';
2
2
  import Slider from '@mui/material/Slider';
3
3
  import Typography from '@mui/material/Typography';
4
4
  import { combineDrawing } from '../service/image_tools';
@@ -6,6 +6,7 @@ import imageCompression from 'browser-image-compression';
6
6
  import { ChromePicker } from 'react-color';
7
7
  import Button from '@mui/material/Button';
8
8
  import { OUTPUT_TYPES } from '../constants';
9
+ import { rgbToHex } from '../../../Tools/color';
9
10
  const imageScaleMarks = [{
10
11
  value: 1.5,
11
12
  label: 'Full'
@@ -81,32 +82,15 @@ const Controls = props => {
81
82
  return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
82
83
  className: "flex flex-col"
83
84
  }, /*#__PURE__*/React.createElement("div", {
84
- className: "flex flex-row justify-between "
85
- }, /*#__PURE__*/React.createElement(Button, {
86
- color: "secondary",
87
- onClick: () => {
88
- saveableCanvas.current.eraseAll();
89
- }
90
- }, "Erase"), /*#__PURE__*/React.createElement(Button, {
91
- color: "secondary",
92
- onClick: () => {
93
- saveableCanvas.current.undo();
94
- }
95
- }, "Undo"), /*#__PURE__*/React.createElement(Button, {
96
- variant: "outlined",
97
- onClick: () => {
98
- exportImage(onSave, saveableCanvas, outputFormat, state.imageCompressionOptions);
99
- }
100
- }, "Save")), /*#__PURE__*/React.createElement("div", {
101
85
  className: "m-auto my-12"
102
86
  }, /*#__PURE__*/React.createElement(ChromePicker, {
103
87
  className: "drop-shadow-none",
104
- disableAlpha: true,
88
+ disableAlpha: false,
105
89
  color: state.color,
106
90
  onChange: (color, event) => {
107
91
  setState(previousState => {
108
92
  return { ...previousState,
109
- color: color.hex
93
+ color: rgbToHex(color.rgb)
110
94
  };
111
95
  });
112
96
  }
@@ -173,12 +157,29 @@ const Controls = props => {
173
157
  return { ...previousState,
174
158
  imageScale: Number(event.target.value)
175
159
  };
176
- });
160
+ }); // saveableCanvas.current.eraseAll();
177
161
  },
178
162
  marks: imageScaleMarks,
179
163
  min: 1.5,
180
164
  max: 2.5
181
165
  })))), /*#__PURE__*/React.createElement("div", {
166
+ className: "flex flex-row justify-between mt-12 "
167
+ }, /*#__PURE__*/React.createElement(Button, {
168
+ color: "secondary",
169
+ onClick: () => {
170
+ saveableCanvas.current.eraseAll();
171
+ }
172
+ }, "Erase"), /*#__PURE__*/React.createElement(Button, {
173
+ color: "secondary",
174
+ onClick: () => {
175
+ saveableCanvas.current.undo();
176
+ }
177
+ }, "Undo"), /*#__PURE__*/React.createElement(Button, {
178
+ variant: "outlined",
179
+ onClick: () => {
180
+ exportImage(onSave, saveableCanvas, outputFormat, state.imageCompressionOptions);
181
+ }
182
+ }, "Save")), /*#__PURE__*/React.createElement("div", {
182
183
  className: "flex flex-row justify-center mt-12"
183
184
  }, showDownloadButton && /*#__PURE__*/React.createElement(Button, {
184
185
  variant: "outlined",
@@ -8,6 +8,7 @@ import { getStorage, setStorage } from './service/local_storage';
8
8
  import PropTypes from 'prop-types';
9
9
  import { ThemeProvider } from '@mui/system';
10
10
  import { createTheme, useTheme } from '@mui/material/styles';
11
+ import PCMScrollbar from '../../Tools/PCMScrollbar';
11
12
  /**
12
13
  * Displays an image that can is used to draw on to generate maps with highlighted routes.
13
14
  *
@@ -87,6 +88,18 @@ export const ImageCanvasDraw = props => {
87
88
  useEffect(() => {
88
89
  //Get the scaled down image and width, height
89
90
  setImageSize(state.b64DataUrl);
91
+
92
+ try {
93
+ document.addEventListener('keydown', function (e) {
94
+ console.log('debug e', e);
95
+
96
+ if (e.ctrlKey && e.key.toLowerCase() === 'z') {
97
+ saveableCanvas.current.undo();
98
+ }
99
+ });
100
+ } catch (error) {
101
+ console.error('Error in keydown ImageCanvasDraw Controls', error);
102
+ }
90
103
  }, []);
91
104
  useEffect(() => {
92
105
  if (saveableCanvas && saveableCanvas.current) {
@@ -117,7 +130,7 @@ export const ImageCanvasDraw = props => {
117
130
  return /*#__PURE__*/React.createElement(ThemeProvider, {
118
131
  theme: defaultTheme
119
132
  }, state.width && state.width !== 0 ? /*#__PURE__*/React.createElement("div", {
120
- className: "flex flex-row overflow-hidden"
133
+ className: "flex flex-row overflow-hidden p-6"
121
134
  }, state.drawerOpen ? /*#__PURE__*/React.createElement("div", {
122
135
  className: "flex flex-row",
123
136
  style: {
@@ -132,8 +145,11 @@ export const ImageCanvasDraw = props => {
132
145
  showDownloadButton: showDownloadButton
133
146
  }), /*#__PURE__*/React.createElement(DrawerButtonOpenClose, null, /*#__PURE__*/React.createElement(ChevronLeftIcon, null))) : /*#__PURE__*/React.createElement("div", {
134
147
  className: "flex flex-row justify-end"
135
- }, /*#__PURE__*/React.createElement(DrawerButtonOpenClose, null, /*#__PURE__*/React.createElement(ChevronRightIcon, null))), state.width !== 0 && /*#__PURE__*/React.createElement("div", {
136
- className: "overflow-scroll"
148
+ }, /*#__PURE__*/React.createElement(DrawerButtonOpenClose, null, /*#__PURE__*/React.createElement(ChevronRightIcon, null))), state.width !== 0 && /*#__PURE__*/React.createElement(PCMScrollbar, {
149
+ className: "overflow-scroll",
150
+ style: {
151
+ maxHeight: '90vh'
152
+ }
137
153
  }, /*#__PURE__*/React.createElement(CanvasDraw, {
138
154
  className: "",
139
155
  ref: saveableCanvas,
@@ -12,7 +12,6 @@ export const PcSharedComponentThemeInheritor = props => {
12
12
  children = React.ReactNode
13
13
  } = props;
14
14
  const currentTheme = createTheme(theme ? theme : useTheme());
15
- console.log('debug currentTheme', currentTheme);
16
15
  return /*#__PURE__*/React.createElement(ThemeProvider, {
17
16
  theme: theme
18
17
  }, children);
@@ -0,0 +1,24 @@
1
+ import { height } from '@mui/system';
2
+ import React from 'react';
3
+ import ImageCanvasDraw from '../../Drawing/ImageCanvasDraw';
4
+ import { cedarShade } from '../../Drawing/ImageCanvasDraw/storybook/testMap.test';
5
+
6
+ const ScrollingInnerDiv = () => {
7
+ return /*#__PURE__*/React.createElement("div", {
8
+ style: {
9
+ backgroundColor: 'yellow',
10
+ padding: 24,
11
+ height: 200
12
+ }
13
+ }, /*#__PURE__*/React.createElement("div", {
14
+ style: {
15
+ backgroundColor: 'blue',
16
+ height: '100%',
17
+ overflow: 'scroll'
18
+ }
19
+ }, /*#__PURE__*/React.createElement(ImageCanvasDraw, {
20
+ b64DataUrl: cedarShade
21
+ }), "CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE CONTENT TO HAVE TAKING UP THE ENTIRE PARENT DIV SPACE"));
22
+ };
23
+
24
+ export default ScrollingInnerDiv;
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import PerfectScrollbar from 'react-perfect-scrollbar';
3
+ import "react-perfect-scrollbar/dist/css/styles.css";
4
+ import PropTypes from 'prop-types';
5
+ import MobileDetect from 'mobile-detect';
6
+ import clsx from 'clsx';
7
+ const md = new MobileDetect(window.navigator.userAgent);
8
+ const isMobile = md.mobile();
9
+ export const PCMScrollbar = props => {
10
+ const {
11
+ children,
12
+ className,
13
+ enable,
14
+ style
15
+ } = props;
16
+ return /*#__PURE__*/React.createElement(PerfectScrollbar, {
17
+ key: props.id,
18
+ className: clsx(className),
19
+ style: enable && !isMobile ? {
20
+ position: 'relative',
21
+ overflow: 'hidden',
22
+ ...style
23
+ } : {}
24
+ }, children);
25
+ };
26
+ export default PCMScrollbar;
27
+ PCMScrollbar.propTypes = {
28
+ className: PropTypes.any,
29
+ style: PropTypes.object,
30
+ enable: PropTypes.bool
31
+ };
32
+ PCMScrollbar.defaultProps = {
33
+ className: '',
34
+ style: {},
35
+ enable: true
36
+ };
@@ -0,0 +1,6 @@
1
+ export const rgbToHex = rgb => {
2
+ let alpha = Math.ceil(rgb.a * 255).toString(16);
3
+ alpha = alpha.length > 1 ? alpha : `0${alpha}`;
4
+ const hex = rgb ? (rgb.r | 1 << 8).toString(16).slice(1) + (rgb.g | 1 << 8).toString(16).slice(1) + (rgb.b | 1 << 8).toString(16).slice(1) + alpha : undefined;
5
+ return `#${hex}`;
6
+ };
@@ -1 +1 @@
1
- *,:after,:before{--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2196f380;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.relative{position:relative}.m-auto{margin:auto}.m-12{margin:1.2rem}.mx-6{margin-left:.6rem;margin-right:.6rem}.my-auto{margin-top:auto;margin-bottom:auto}.my-12{margin-top:1.2rem;margin-bottom:1.2rem}.my-6{margin-top:.6rem;margin-bottom:.6rem}.mx-8{margin-left:.8rem;margin-right:.8rem}.mt-6{margin-top:.6rem}.mb-2{margin-bottom:.2rem}.mt-12{margin-top:1.2rem}.mb-6{margin-bottom:.6rem}.ml-6{margin-left:.6rem}.mr-12{margin-right:1.2rem}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.h-full{height:100%}.w-full{width:100%}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.rounded-md{border-radius:.6rem}.border{border-width:1px}.border-transparent{border-color:#0000}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(67 160 71/var(--tw-bg-opacity))}.px-4{padding-left:.4rem;padding-right:.4rem}.py-2{padding-top:.2rem;padding-bottom:.2rem}.px-2{padding-left:.2rem;padding-right:.2rem}.pt-4{padding-top:.4rem}.pl-0{padding-left:0}.pr-0{padding-right:0}.pl-16{padding-left:1.6rem}.text-sm{font-size:1.4rem;line-height:2rem}.text-xl{font-size:2rem;line-height:2.8rem}.text-2xl{font-size:2.4rem;line-height:3.2rem}.font-medium{font-weight:500}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px 0 #0000000f;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px 0 var(--tw-shadow-color)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.drop-shadow-none{--tw-drop-shadow:drop-shadow(0 0 #0000)}.drop-shadow-none,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(56 142 60/var(--tw-bg-opacity))}.hover\:bg-gray-100\/75:hover{background-color:#f5f5f5bf}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-green-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(76 175 80/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}
1
+ *,:after,:before{--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2196f380;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.relative{position:relative}.m-auto{margin:auto}.m-12{margin:1.2rem}.mx-6{margin-left:.6rem;margin-right:.6rem}.my-auto{margin-top:auto;margin-bottom:auto}.my-12{margin-top:1.2rem;margin-bottom:1.2rem}.my-6{margin-top:.6rem;margin-bottom:.6rem}.mx-8{margin-left:.8rem;margin-right:.8rem}.mt-6{margin-top:.6rem}.mb-2{margin-bottom:.2rem}.mt-12{margin-top:1.2rem}.mb-6{margin-bottom:.6rem}.ml-6{margin-left:.6rem}.mr-12{margin-right:1.2rem}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-full{height:100%}.w-full{width:100%}.flex-row{flex-direction:row}.flex-row-reverse{flex-direction:row-reverse}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.rounded-md{border-radius:.6rem}.border{border-width:1px}.border-transparent{border-color:#0000}.bg-green-600{--tw-bg-opacity:1;background-color:rgb(67 160 71/var(--tw-bg-opacity))}.p-6{padding:.6rem}.px-4{padding-left:.4rem;padding-right:.4rem}.py-2{padding-top:.2rem;padding-bottom:.2rem}.px-2{padding-left:.2rem;padding-right:.2rem}.pt-4{padding-top:.4rem}.pl-0{padding-left:0}.pr-0{padding-right:0}.pl-16{padding-left:1.6rem}.text-sm{font-size:1.4rem;line-height:2rem}.text-xl{font-size:2rem;line-height:2.8rem}.text-2xl{font-size:2.4rem;line-height:3.2rem}.font-medium{font-weight:500}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.shadow{--tw-shadow:0 1px 3px 0 #0000001a,0 1px 2px 0 #0000000f;--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px 0 var(--tw-shadow-color)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 #0000000d;--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.drop-shadow-none{--tw-drop-shadow:drop-shadow(0 0 #0000)}.drop-shadow-none,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.hover\:bg-green-700:hover{--tw-bg-opacity:1;background-color:rgb(56 142 60/var(--tw-bg-opacity))}.hover\:bg-gray-100\/75:hover{background-color:#f5f5f5bf}.focus\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-green-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(76 175 80/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pcm-shared-components",
3
- "version": "0.0.62",
3
+ "version": "0.0.65",
4
4
  "private": false,
5
5
  "main": "dist/index.js",
6
6
  "babel": {
@@ -61,11 +61,13 @@
61
61
  "axios": "^0.26.0",
62
62
  "browser-image-compression": "^1.0.17",
63
63
  "clsx": "^1.1.1",
64
+ "mobile-detect": "^1.4.5",
64
65
  "moment": "^2.29.1",
65
66
  "prismjs": "^1.27.0",
66
67
  "react-canvas-draw": "^1.2.1",
67
68
  "react-color": "^2.19.3",
68
69
  "react-markdown": "^8.0.0",
70
+ "react-perfect-scrollbar": "^1.5.8",
69
71
  "tinycolor2": "^1.4.2"
70
72
  }
71
73
  }