cloudmr-ux 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +30 -0
  2. package/dist/index.css +17 -0
  3. package/dist/index.js +174 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/index.modern.js +167 -0
  6. package/dist/index.modern.js.map +1 -0
  7. package/package.json +99 -0
  8. package/src/.eslintrc +5 -0
  9. package/src/common/components/Cmr-components/avatar/Avatar.scss +0 -0
  10. package/src/common/components/Cmr-components/avatar/Avatar.tsx +25 -0
  11. package/src/common/components/Cmr-components/button/Button.scss +0 -0
  12. package/src/common/components/Cmr-components/button/Button.tsx +14 -0
  13. package/src/common/components/Cmr-components/checkbox/Checkbox.scss +11 -0
  14. package/src/common/components/Cmr-components/checkbox/Checkbox.tsx +29 -0
  15. package/src/common/components/Cmr-components/collapse/Collapse.scss +3 -0
  16. package/src/common/components/Cmr-components/collapse/Collapse.tsx +75 -0
  17. package/src/common/components/Cmr-components/dialogue/Confirmation.tsx +48 -0
  18. package/src/common/components/Cmr-components/dialogue/DeletionDialog.tsx +61 -0
  19. package/src/common/components/Cmr-components/dialogue/EditConfirmation.tsx +72 -0
  20. package/src/common/components/Cmr-components/double-slider/DualSlider.tsx +198 -0
  21. package/src/common/components/Cmr-components/double-slider/InvertibleDualSlider.tsx +224 -0
  22. package/src/common/components/Cmr-components/dropdown/Dropdown.scss +36 -0
  23. package/src/common/components/Cmr-components/dropdown/Dropdown.tsx +83 -0
  24. package/src/common/components/Cmr-components/gui-slider/ControlledSlider.tsx +139 -0
  25. package/src/common/components/Cmr-components/gui-slider/Slider.tsx +170 -0
  26. package/src/common/components/Cmr-components/header/Header.scss +20 -0
  27. package/src/common/components/Cmr-components/header/Header.tsx +101 -0
  28. package/src/common/components/Cmr-components/input/Input.scss +0 -0
  29. package/src/common/components/Cmr-components/input/Input.tsx +39 -0
  30. package/src/common/components/Cmr-components/input-number/InputNumber.scss +0 -0
  31. package/src/common/components/Cmr-components/input-number/InputNumber.tsx +29 -0
  32. package/src/common/components/Cmr-components/label/Label.scss +13 -0
  33. package/src/common/components/Cmr-components/label/Label.tsx +20 -0
  34. package/src/common/components/Cmr-components/option/Option.scss +0 -0
  35. package/src/common/components/Cmr-components/option/Option.tsx +24 -0
  36. package/src/common/components/Cmr-components/panel/Panel.scss +0 -0
  37. package/src/common/components/Cmr-components/panel/Panel.tsx +54 -0
  38. package/src/common/components/Cmr-components/progress/Progress.scss +0 -0
  39. package/src/common/components/Cmr-components/progress/Progress.tsx +38 -0
  40. package/src/common/components/Cmr-components/radio/Radio.scss +0 -0
  41. package/src/common/components/Cmr-components/radio/Radio.tsx +23 -0
  42. package/src/common/components/Cmr-components/radio-group/RadioGroup.scss +0 -0
  43. package/src/common/components/Cmr-components/radio-group/RadioGroup.tsx +32 -0
  44. package/src/common/components/Cmr-components/rename/edit.tsx +94 -0
  45. package/src/common/components/Cmr-components/select/Select.scss +3 -0
  46. package/src/common/components/Cmr-components/select/Select.tsx +33 -0
  47. package/src/common/components/Cmr-components/select-upload/SelectUpload.scss +0 -0
  48. package/src/common/components/Cmr-components/select-upload/SelectUpload.tsx +133 -0
  49. package/src/common/components/Cmr-components/slider/Slider.scss +0 -0
  50. package/src/common/components/Cmr-components/slider/Slider.tsx +66 -0
  51. package/src/common/components/Cmr-components/spin/Spin.scss +0 -0
  52. package/src/common/components/Cmr-components/spin/Spin.tsx +31 -0
  53. package/src/common/components/Cmr-components/tooltip/Tooltip.scss +0 -0
  54. package/src/common/components/Cmr-components/tooltip/Tooltip.tsx +50 -0
  55. package/src/common/components/Cmr-components/upload/Upload.scss +5 -0
  56. package/src/common/components/Cmr-components/upload/Upload.tsx +188 -0
  57. package/src/common/components/Cmr-components/upload/UploadWindow.tsx +355 -0
  58. package/src/index.js +8 -0
  59. package/src/index.test.js +7 -0
  60. package/src/styles.module.css +9 -0
@@ -0,0 +1,224 @@
1
+ import {Box} from "@mui/material";
2
+ import {useEffect, useRef, useState} from "react";
3
+
4
+ /**
5
+ * This dual slider (lil-gui styled) allows users to control the max and min of an interval simultaneously.
6
+ * The rendered interval (and number control) can be masked by a transformation - inverse pair.
7
+ * @param name
8
+ * @param min
9
+ * @param max
10
+ * @param setMin
11
+ * @param setMax
12
+ * @param reverse
13
+ * @param transform transform and inverse are a pair that masks the rendered values and rendered inputs by a transformation
14
+ * @param inverse transform and inverse are a pair that masks the rendered values and rendered inputs by a transformation
15
+ * @constructor
16
+ */
17
+ export const InvertibleDualSlider = ({name,min,max,setMin,setMax, reverse=false,
18
+ transform=x=>x,inverse=x=>x,onFinalize}:
19
+ {name:string,min:number,max:number, setMin?:(min:number)=>void,
20
+ setMax?:(max:number)=>void,reverse?:boolean,transform?:(x:number)=>number,
21
+ inverse?:(x:number)=>number,onFinalize?: ()=>void} )=>{
22
+ const [leftSliderPosition, setLeftSliderPosition] = useState(0); // Initial percentage for the left slider
23
+ const [rightSliderPosition, setRightSliderPosition] = useState(100); // Initial percentage for the right slider
24
+ useEffect(() => {//Initialize parent min/max values upon initialization
25
+ setMin&&setMin(min);
26
+ setMax&&setMax(max);
27
+ setLeftSliderPosition(0);
28
+ setRightSliderPosition(100);
29
+ }, [min,max]);
30
+ const [isHovering, setIsHovering] = useState(false);
31
+ const [leftEditing, setLeftEditing] = useState(false);
32
+
33
+ const [minOverride, setMinOverride] = useState<any>(undefined);
34
+ const [maxOverride, setMaxOverride] = useState<any>(undefined);
35
+
36
+ if(minOverride)
37
+ min = minOverride;
38
+ if(maxOverride)
39
+ max = maxOverride;
40
+
41
+ const a = transform((max-min)*leftSliderPosition/100+min);
42
+ const b = transform((max-min)*rightSliderPosition/100+min);
43
+ const left = Math.min(a,b);
44
+ const right = Math.max(a,b);
45
+
46
+ const sliderRef = useRef(null); // Ref for the parent box
47
+
48
+ const handleDragStart = (e:any, slider:string) => {
49
+ // Prevent default behavior
50
+ e.preventDefault();
51
+ setLeftEditing(false);
52
+ setLeftIsNaN(false)
53
+ leftRef.current.blur();
54
+
55
+ setRightEditing(false);
56
+ setRightIsNaN(false);
57
+ rightRef.current.blur();
58
+
59
+ // Calculate initial positions
60
+ const startX = e.clientX;
61
+ // @ts-ignore
62
+ const sliderWidth = sliderRef.current.offsetWidth;
63
+
64
+ const handleMouseMove = (e:any) => {
65
+ const moveX = e.clientX - startX;
66
+ const newPosition = ((moveX / sliderWidth) * 100) + (slider === 'left' ? leftSliderPosition : rightSliderPosition);
67
+
68
+
69
+ // Prevent the slider from going outside the parent box
70
+ const clampedPosition = Math.min(100, Math.max(0, newPosition));
71
+ // Update the position of the slider
72
+ if (slider === 'left') {
73
+ setLeftSliderPosition(clampedPosition);
74
+ const a = (max-min)*clampedPosition/100+min;
75
+ const b = (max-min)*rightSliderPosition/100+min;
76
+ setMin&&setMin(Math.min(a,b));
77
+ setMax&&setMax(Math.max(a,b));
78
+
79
+ } else if (slider === 'right') {
80
+ setRightSliderPosition(clampedPosition);
81
+ const a = (max-min)*leftSliderPosition/100+min;
82
+ const b = (max-min)*clampedPosition/100+min;
83
+ setMin&&setMin(Math.min(a,b));
84
+ setMax&&setMax(Math.max(a,b));
85
+ }
86
+
87
+ };
88
+
89
+ const handleMouseUp = () => {
90
+ // Remove event listeners once dragging is complete
91
+ document.removeEventListener('mousemove', handleMouseMove);
92
+ document.removeEventListener('mouseup', handleMouseUp);
93
+ onFinalize&&onFinalize();
94
+ };
95
+
96
+ // Add mouse move and mouse up listeners to document to handle drag
97
+ document.addEventListener('mousemove', handleMouseMove);
98
+ document.addEventListener('mouseup', handleMouseUp);
99
+ };
100
+
101
+ const leftText = Math.abs(left)<0.01&&left!=0?Number(left).toExponential(3).toUpperCase():Number(left).toFixed(3);
102
+ const [leftEditedText,setLeftEditedText] = useState('');
103
+ const [leftIsNaN, setLeftIsNaN] = useState(false);
104
+ const leftRef = useRef<any>(null);
105
+
106
+ const [rightEditing, setRightEditing] = useState(false);
107
+ const [rightEditedText, setRightEditedText] = useState('');
108
+ const [rightIsNaN, setRightIsNaN] = useState(false);
109
+ const rightRef = useRef<any>(null);
110
+
111
+ // Logic to handle right value box editing...
112
+ const rightText = Math.abs(right) < 0.01 && right != 0 ? Number(right).toExponential(3).toUpperCase() : Number(right).toFixed(3);
113
+
114
+ return <Box sx={{display:'flex',flexDirection:'row', paddingLeft:'4px',paddingRight:'4px'}} height={27}>
115
+ {name!=''&&<Box fontSize={16} marginRight={'5pt'} color={'white'} alignItems={'center'} display={'flex'} marginBottom={'1pt'}
116
+ fontFamily={'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif'}>
117
+ {name}
118
+ </Box>}
119
+ <Box sx={{display:'flex',flexDirection:'row'}} flex={1}>
120
+ <input ref={leftRef} style={{backgroundColor:'#ffffff',width:'45px', borderRadius:'2px', outline:"none",borderStyle:'none',paddingLeft:'3px',paddingRight:'3px', lineHeight:'20px',
121
+ whiteSpace:'nowrap',fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif',fontSize:'11px',color:leftIsNaN?'red':'black'}} value={
122
+ (leftEditing)?leftEditedText:leftText
123
+ } onKeyDown={(e) => {
124
+ if (e.key === 'Enter'&&!leftIsNaN) {
125
+ //@ts-ignore
126
+ e.target.blur(); // This will cause the input to lose focus
127
+ }
128
+ }} onFocus={(e)=>{
129
+ setLeftEditedText(e.target.value);
130
+ setLeftEditing(true);
131
+ }} onChange={(event)=>{
132
+ setLeftIsNaN(isNaN(Number(event.target.value)));
133
+ setLeftEditedText(event.target.value);
134
+ }} onBlur={(e)=>{
135
+ let val = inverse(Number(leftEditedText));
136
+ if(isNaN(val)) {
137
+ return e.preventDefault();
138
+ }
139
+ setLeftEditing(false);
140
+ setMin&&setMin(val);
141
+ let newMin = min;
142
+ if(val<min) {
143
+ setMinOverride(val);
144
+ newMin = val;
145
+ }
146
+ let leftPosition = (val-newMin)/(max-newMin)*100;
147
+ setLeftSliderPosition(leftPosition);
148
+ onFinalize&&onFinalize();
149
+ }}/>
150
+
151
+ <Box sx={{ backgroundColor: '#ffffff', flex: 1, marginLeft: '4px', marginRight: '4px', borderRadius: '2px', position: 'relative',
152
+ overflow:'hidden'
153
+ }} ref={sliderRef}
154
+ onMouseEnter={() => setIsHovering(true)} onMouseLeave={() => setIsHovering(false)}>
155
+ {/* Central gray block with two vertical black components */}
156
+
157
+
158
+ {!reverse&&<Box sx={{backgroundColor:isHovering?'#b9deff':'#8ec7ff',
159
+ height:'100%',position:'absolute',
160
+ left:`calc(${Math.min(leftSliderPosition,rightSliderPosition+3)*0.97}%)`,
161
+ right:`calc(${(100 - Math.max(leftSliderPosition-3,rightSliderPosition))*0.97}%)`,
162
+ zIndex:1}}/>}
163
+ {reverse&&<Box sx={{backgroundColor:isHovering?'#b9deff':'#8ec7ff',
164
+ height:'100%',position:'absolute',
165
+ left:`calc(${Math.max(leftSliderPosition,rightSliderPosition+3)*0.97}%)`,
166
+ right:`0`,
167
+ zIndex:1}}/>}
168
+ {reverse&&<Box sx={{backgroundColor:isHovering?'#b9deff':'#8ec7ff',
169
+ height:'100%',position:'absolute',
170
+ left:`0`,
171
+ right:`calc(${(100 - Math.min(leftSliderPosition-3,rightSliderPosition))*0.97}%)`,
172
+ zIndex:1}}/>}
173
+ <Box sx={{ position: 'absolute', left: `calc(${leftSliderPosition*0.97}% - 10px)`, width: '20px', height: '100%', cursor: 'ew-resize', zIndex: 1 }}
174
+ onMouseDown={(e) => handleDragStart(e, 'left')}>
175
+ {/* Visual representation of the slider */}
176
+ <Box sx={{ position: 'absolute', left: '10px', width: '2px', height: '100%', backgroundColor: '#2e9eff' }} />
177
+ </Box>
178
+
179
+ {/* Transparent hitbox for the right slider */}
180
+ <Box sx={{ position: 'absolute', right: `calc(${(100 - rightSliderPosition)*0.97}% - 10px)`, width: '20px', height: '100%', cursor: 'ew-resize', zIndex: 1 }}
181
+ onMouseDown={(e) => handleDragStart(e, 'right')}>
182
+ {/* Visual representation of the slider */}
183
+ <Box sx={{ position: 'absolute', right: '10px', width: '2px', height: '100%', backgroundColor: '#2e9eff' }} />
184
+ </Box>
185
+ </Box>
186
+
187
+ <input style={{backgroundColor: '#ffffff', width: '45px', borderRadius: '2px', outline: "none", borderStyle: 'none', paddingLeft: '3px', paddingRight: '3px', lineHeight: '20px',
188
+ whiteSpace: 'nowrap', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif', fontSize: '11px', color: rightIsNaN ? 'red' : 'black'}}
189
+ value={(rightEditing) ? rightEditedText : rightText}
190
+ ref={rightRef}
191
+ onKeyDown={(e) => {
192
+ if (e.key === 'Enter' && !rightIsNaN) {
193
+ //@ts-ignore
194
+ e.target.blur(); // This will cause the input to lose focus
195
+ }
196
+ }}
197
+ onFocus={(e) => {
198
+ setRightEditedText(e.target.value);
199
+ setRightEditing(true);
200
+ }}
201
+ onChange={(event) => {
202
+ setRightIsNaN(isNaN(Number(event.target.value)));
203
+ setRightEditedText(event.target.value);
204
+ }}
205
+ onBlur={(e) => {
206
+ let val = inverse(Number(rightEditedText));
207
+ if (isNaN(val)) {
208
+ return e.preventDefault();
209
+ }
210
+ setRightEditing(false);
211
+ setMax && setMax(val);
212
+ let newMax = max;
213
+ if (val > max) {
214
+ setMaxOverride(val);
215
+ newMax = val;
216
+ }
217
+ let rightPosition = (val - min) / (newMax - min) * 100;
218
+ setRightSliderPosition(rightPosition);
219
+ onFinalize&&onFinalize();
220
+ }}
221
+ />
222
+ </Box>
223
+ </Box>
224
+ }
@@ -0,0 +1,36 @@
1
+ .select-box {
2
+ position: relative;
3
+ outline: none;
4
+ }
5
+
6
+ .select-box .ant-select {
7
+ color: #888080;
8
+ width: 205px;
9
+ background: #ffffff;
10
+ box-sizing: border-box;
11
+ border-radius: 4px;
12
+ -webkit-appearance: none;
13
+ appearance: none;
14
+ -webkit-outline: none;
15
+ outline: none;
16
+ }
17
+
18
+ .select-box > .ant-select > .ant-select-selector {
19
+ border: 1px solid #e5e5e5;
20
+ }
21
+
22
+ .select-box
23
+ > .ant-select
24
+ > .ant-select-selector
25
+ > .ant-select-selection-placeholder,
26
+ .ant-select-selection-item {
27
+ font-size: 12px;
28
+ line-height: 30px;
29
+ color: #999999;
30
+ font-weight: normal;
31
+ letter-spacing: 0.1px;
32
+ }
33
+
34
+ .select-box > .ant-select > .ant-select-arrow {
35
+ top: 65%;
36
+ }
@@ -0,0 +1,83 @@
1
+ import React, { useState } from 'react';
2
+ import { Select } from 'antd';
3
+ import './DropDown.scss';
4
+
5
+ const { Option } = Select;
6
+
7
+ const CmrDropDown = (props: any) => {
8
+ const [DropdownCaret, setDropdownCaret] = useState(false);
9
+ const onCaretChange = () => {
10
+ setDropdownCaret(!DropdownCaret);
11
+ };
12
+
13
+ return (
14
+ <div className="select-box">
15
+ <Select
16
+ onFocus={onCaretChange}
17
+ onBlur={onCaretChange}
18
+ suffixIcon={
19
+ <>
20
+ <svg
21
+ style={{ display: DropdownCaret ? 'none' : 'block' }}
22
+ width="6"
23
+ height="3"
24
+ viewBox="0 0 6 3"
25
+ fill="none"
26
+ xmlns="http://www.w3.org/2000/svg"
27
+ >
28
+ <path
29
+ d="M5.79875 0H0.20125C0.0333594 0 -0.0603867 0.147179 0.0435863 0.247656L2.84234 2.94215C2.92245 3.01928 3.0767 3.01928 3.15766 2.94215L5.95641 0.247656C6.06039 0.147179 5.96664 0 5.79875 0Z"
30
+ fill="#999999"
31
+ />
32
+ </svg>
33
+ <svg
34
+ style={{ display: DropdownCaret ? 'block' : 'none' }}
35
+ width="6"
36
+ height="3"
37
+ viewBox="0 0 6 3"
38
+ fill="none"
39
+ xmlns="http://www.w3.org/2000/svg"
40
+ >
41
+ <path
42
+ d="M5.79875 3H0.20125C0.0333594 3 -0.0603867 2.85282 0.0435863 2.75234L2.84234 0.0578451C2.92245 -0.0192819 3.0767 -0.0192819 3.15766 0.0578451L5.95641 2.75234C6.06039 2.85282 5.96664 3 5.79875 3Z"
43
+ fill="#999999"
44
+ />
45
+ </svg>
46
+ </>
47
+ }
48
+ id=""
49
+ disabled={props.disabled}
50
+ className={props.className}
51
+ placeholder={props.placeholder}
52
+ value={props.value}
53
+ onChange={props.onChange}
54
+ dropdownClassName={props.dropdownClassName}
55
+ dropdownStyle={props.dropdownStyle}
56
+ defaultValue={props.defaultValue}
57
+ onSelect={props.onSelect}
58
+ showSearch={props.showSearch}
59
+ onSearch={props.onSearch}
60
+ dropdownAlign={{
61
+ offset: [0, 0],
62
+ overflow: {
63
+ adjustY: 0,
64
+ },
65
+ }}
66
+ >
67
+ {props.isOptionsObj
68
+ ? props.options.map((obj: any, i: any) => (
69
+ <Option key={i} value={obj.value}>
70
+ {obj.label}
71
+ </Option>
72
+ ))
73
+ : props.options.map((opt: any, ind: any) => (
74
+ <Option key={ind} value={props.options[ind]}>
75
+ {props.options[ind]}
76
+ </Option>
77
+ ))}
78
+ </Select>
79
+ </div>
80
+ );
81
+ };
82
+
83
+ export default CmrDropDown;
@@ -0,0 +1,139 @@
1
+ import { Box } from "@mui/material";
2
+ import { useRef, useState } from "react";
3
+
4
+ export const ControlledSlider = ({
5
+ name,
6
+ min,
7
+ max,
8
+ setValue,
9
+ transform = x => x,
10
+ inverse = x => x,
11
+ value
12
+ }: {
13
+ name: string,
14
+ min: number,
15
+ max: number,
16
+ setValue?: (value: number) => void,
17
+ transform?: (x: number) => number,
18
+ inverse?: (x: number) => number,
19
+ value: number
20
+ }) => {
21
+ const sliderPosition = (value - min) / (max - min) * 100;
22
+ const sliderRef = useRef(null);
23
+ const [isEditing, setIsEditing] = useState(false);
24
+ const [editedValue, setEditedValue] = useState('');
25
+ const [textIsNaN, setIsNaN] = useState(false);
26
+
27
+ const handleDragStart = (e: any) => {
28
+ e.preventDefault();
29
+
30
+ const startX = e.clientX;
31
+ //@ts-ignore
32
+ const sliderWidth = sliderRef.current.offsetWidth;
33
+
34
+ const handleMouseMove = (e: any) => {
35
+ const moveX = e.clientX - startX;
36
+ const newPosition = ((moveX / sliderWidth) * 100) + sliderPosition;
37
+ const clampedPosition = Math.min(100, Math.max(0, newPosition));
38
+ const newValue = (max - min) * clampedPosition / 100 + min;
39
+ setValue && setValue(newValue);
40
+ };
41
+
42
+ const handleMouseUp = () => {
43
+ document.removeEventListener('mousemove', handleMouseMove);
44
+ document.removeEventListener('mouseup', handleMouseUp);
45
+ };
46
+
47
+ document.addEventListener('mousemove', handleMouseMove);
48
+ document.addEventListener('mouseup', handleMouseUp);
49
+ };
50
+
51
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
52
+ setIsNaN(isNaN(Number(e.target.value)));
53
+ setEditedValue(e.target.value);
54
+ };
55
+
56
+ const handleInputBlur = (e:any) => {
57
+ let val = inverse(Number(editedValue));
58
+ if (isNaN(val)) {
59
+ return e.preventDefault();
60
+ }
61
+ setIsEditing(false);
62
+ setValue&&setValue(val)
63
+ };
64
+
65
+ const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
66
+ if (e.key === 'Enter'&&!textIsNaN) {
67
+ e.currentTarget.blur();
68
+ }
69
+ };
70
+
71
+ const formatText=(value:number)=>{
72
+ return Math.abs(value)<0.01&&value!=0?
73
+ Number(value).toExponential(3).toUpperCase():
74
+ Number(value).toFixed(3);
75
+ }
76
+
77
+ const displayValue = isEditing ? editedValue : formatText(value);
78
+
79
+ return (
80
+ <Box sx={{ display: 'flex', flexDirection: 'row', paddingLeft: '4px', paddingRight: '4px' }} height={20}>
81
+ <Box flex={0.77} fontSize={16} color={'#3D3D3D'} alignItems={'center'} display={'flex'} marginBottom={'1pt'}
82
+ fontFamily={'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif'}>
83
+ {name}
84
+ </Box>
85
+ <Box sx={{ display: 'flex', flexDirection: 'row' }} flex={1}>
86
+ <Box
87
+ sx={{
88
+ backgroundColor: '#f0f0f0',
89
+ flex: 1,
90
+ marginLeft: '4px',
91
+ marginRight: '4px',
92
+ borderRadius: '2px',
93
+ position: 'relative',
94
+ overflow: 'hidden'
95
+ }}
96
+ ref={sliderRef}
97
+ onMouseDown={handleDragStart}
98
+ >
99
+ <Box
100
+ sx={{
101
+ position: 'absolute',
102
+ left: `calc(${sliderPosition * 0.98}% - 10px)`,
103
+ width: '20px',
104
+ height: '100%',
105
+ cursor: 'ew-resize',
106
+ zIndex: 1
107
+ }}
108
+ >
109
+ <Box sx={{ position: 'absolute', left: '10px', width: '2px', height: '100%', backgroundColor: 'black' }} />
110
+ </Box>
111
+ </Box>
112
+ <input
113
+ style={{
114
+ backgroundColor: '#f0f0f0',
115
+ width: '45px',
116
+ borderRadius: '2px',
117
+ outline: "none",
118
+ borderStyle: 'none',
119
+ paddingLeft: '3px',
120
+ paddingRight: '3px',
121
+ lineHeight: '20px',
122
+ whiteSpace: 'nowrap',
123
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif',
124
+ fontSize: '11px',
125
+ color: textIsNaN?'red':'black'
126
+ }}
127
+ value={displayValue}
128
+ onChange={handleInputChange}
129
+ onBlur={handleInputBlur}
130
+ onKeyDown={handleInputKeyDown}
131
+ onFocus={(e) => {
132
+ setEditedValue(e.target.value);
133
+ setIsEditing(true)
134
+ }}
135
+ />
136
+ </Box>
137
+ </Box>
138
+ );
139
+ };
@@ -0,0 +1,170 @@
1
+ import { Box } from "@mui/material";
2
+ import {useEffect, useRef, useState} from "react";
3
+
4
+ /**
5
+ * This slider allows users to control a single value within a given range.
6
+ * The rendered value can be masked by a transformation.
7
+ * @param name
8
+ * @param min
9
+ * @param max
10
+ * @param setValue
11
+ * @param transform transform is used to mask the rendered value by a transformation
12
+ * @param inverse transform is used to unmask the value to its original form
13
+ * @constructor
14
+ */
15
+ export const Slider = ({
16
+ name,
17
+ min,
18
+ max,
19
+ setValue,
20
+ transform = x => x,
21
+ inverse = x => x,
22
+ value
23
+ }: {
24
+ name: string,
25
+ min: number,
26
+ max: number,
27
+ setValue?: (value: number) => void,
28
+ transform?: (x: number) => number,
29
+ inverse?: (x: number) => number,
30
+ value?:number
31
+ }) => {
32
+ useEffect(() => {
33
+ if(value!=undefined){
34
+ setSliderPosition((value-min)/(max-min)*100);
35
+ }
36
+ }, [value]);
37
+ const [sliderPosition, setSliderPosition] = useState(50); // Initial percentage for the slider
38
+
39
+ const sliderRef = useRef(null); // Ref for the parent box
40
+
41
+ const handleDragStart = (e: any) => {
42
+ // Prevent default behavior
43
+ e.preventDefault();
44
+
45
+ // Calculate initial positions
46
+ const startX = e.clientX;
47
+ // @ts-ignore
48
+ const sliderWidth = sliderRef.current.offsetWidth;
49
+
50
+ const handleMouseMove = (e: any) => {
51
+ const moveX = e.clientX - startX;
52
+ const newPosition = ((moveX / sliderWidth) * 100)+sliderPosition;
53
+
54
+ // Prevent the slider from going outside the parent box
55
+ const clampedPosition = Math.min(100, Math.max(0, newPosition));
56
+
57
+ // Update the position of the slider
58
+ setSliderPosition(clampedPosition);
59
+ const value = transform((max - min) * clampedPosition / 100 + min);
60
+ setValue && setValue(value);
61
+ };
62
+
63
+ const handleMouseUp = () => {
64
+ // Remove event listeners once dragging is complete
65
+ document.removeEventListener('mousemove', handleMouseMove);
66
+ document.removeEventListener('mouseup', handleMouseUp);
67
+ };
68
+
69
+ // Add mouse move and mouse up listeners to document to handle drag
70
+ document.addEventListener('mousemove', handleMouseMove);
71
+ document.addEventListener('mouseup', handleMouseUp);
72
+ };
73
+
74
+
75
+ const [isEditing, setIsEditing] = useState(false);
76
+ const [editedValue, setEditedValue] = useState('');
77
+ const [textIsNaN, setIsNaN] = useState(false);
78
+
79
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
80
+ setIsNaN(isNaN(Number(e.target.value)));
81
+ setEditedValue(e.target.value);
82
+ };
83
+
84
+ const handleInputBlur = (e:any) => {
85
+ let val = inverse(Number(editedValue));
86
+ if (isNaN(val)) {
87
+ return e.preventDefault();
88
+ }
89
+ setIsEditing(false);
90
+ setValue&&setValue(val)
91
+ };
92
+
93
+ const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
94
+ if (e.key === 'Enter'&&!textIsNaN) {
95
+ e.currentTarget.blur();
96
+ }
97
+ };
98
+
99
+ const formatText=(value:number)=>{
100
+ return Math.abs(value)<0.01&&value!=0?
101
+ Number(value).toExponential(3).toUpperCase():
102
+ Number(value).toFixed(3);
103
+ }
104
+
105
+ const val = transform((max - min) * sliderPosition / 100 + min);
106
+ const displayValue = isEditing ? editedValue : formatText(val);
107
+
108
+ return <Box sx={{display: 'flex', flexDirection: 'row', paddingLeft: '4px', paddingRight: '4px',marginBottom:'4px'
109
+ }} height={20}>
110
+ <Box flex={0.77} fontSize={16} color={'#3D3D3D'} alignItems={'center'} display={'flex'} marginBottom={'1pt'}
111
+ fontFamily={'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif'}>
112
+ {name}
113
+ </Box>
114
+ <Box sx={{display: 'flex', flexDirection: 'row'}} flex={1}>
115
+ <Box sx={{
116
+ backgroundColor: '#f0f0f0',
117
+ flex: 1,
118
+ marginLeft: '4px',
119
+ marginRight: '4px',
120
+ borderRadius: '2px',
121
+ position: 'relative',
122
+ overflow: 'hidden'
123
+ }} ref={sliderRef}
124
+ onMouseDown={handleDragStart}>
125
+ {/* Visual representation of the slider */}
126
+ <Box sx={{
127
+ position: 'absolute',
128
+ left: `calc(${sliderPosition*0.98}% - 10px)`,
129
+ width: '20px',
130
+ height: '100%',
131
+ cursor: 'ew-resize',
132
+ zIndex: 1
133
+ }}>
134
+ <Box sx={{
135
+ position: 'absolute',
136
+ left: '10px',
137
+ width: '2px',
138
+ height: '100%',
139
+ backgroundColor: 'black'
140
+ }}/>
141
+ </Box>
142
+ </Box>
143
+
144
+ <input
145
+ style={{
146
+ backgroundColor: '#f0f0f0',
147
+ width: '45px',
148
+ borderRadius: '2px',
149
+ outline: "none",
150
+ borderStyle: 'none',
151
+ paddingLeft: '3px',
152
+ paddingRight: '3px',
153
+ lineHeight: '20px',
154
+ whiteSpace: 'nowrap',
155
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif',
156
+ fontSize: '11px',
157
+ color: textIsNaN?'red':'black'
158
+ }}
159
+ value={displayValue}
160
+ onChange={handleInputChange}
161
+ onBlur={handleInputBlur}
162
+ onKeyDown={handleInputKeyDown}
163
+ onFocus={(e) => {
164
+ setEditedValue(e.target.value);
165
+ setIsEditing(true)
166
+ }}
167
+ />
168
+ </Box>
169
+ </Box>;
170
+ }
@@ -0,0 +1,20 @@
1
+ @import url(https://fonts.googleapis.com/css?family=Nunito);
2
+
3
+ :root {
4
+ --bs-dark-rgb: 0, 0, 0; /* change these values to your preferred RGB color */
5
+ }
6
+
7
+ .small-margin{
8
+ margin-left: 25pt;
9
+ margin-right: 25pt;
10
+ }
11
+
12
+ .navbar-nav > .active > a {
13
+ color: white;
14
+ font-weight: 500;
15
+ }
16
+
17
+ .navbar-brand {
18
+ font-family: 'Nunito', sans-serif;
19
+
20
+ }