@monolith-forensics/monolith-ui 1.0.0

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.
@@ -0,0 +1,89 @@
1
+ import { useTheme } from "@mui/material";
2
+ import { useState } from "react";
3
+ import TaskButton from "../../../Cases/CaseTasks/components/TaskButton";
4
+ import Menu, { MenuItem } from "./Menu";
5
+
6
+ const OptionButton = ({ value, type, data = [], dataField, displayField }) => {
7
+ const theme = useTheme();
8
+ const [currentValue, setCurrentValue] = useState(value);
9
+ const [anchorEl, setAnchorEl] = useState(null);
10
+ const open = Boolean(anchorEl);
11
+
12
+ const handleClick = (event) => {
13
+ event.preventDefault();
14
+ event.stopPropagation();
15
+ setAnchorEl(event.currentTarget);
16
+ // onClick();
17
+ };
18
+
19
+ const handleSelect = (event) => {
20
+ console.log(data);
21
+ console.log(event);
22
+ setAnchorEl(null);
23
+ setCurrentValue(displayField ? event[displayField] : event);
24
+ };
25
+
26
+ const handleClose = () => {
27
+ setAnchorEl(null);
28
+ // onClose();
29
+ };
30
+ return (
31
+ <div>
32
+ <TaskButton
33
+ onClick={handleClick}
34
+ style={{
35
+ fontSize: 12,
36
+ color: theme.palette.text.primary,
37
+ padding: 5,
38
+ }}
39
+ >
40
+ {type === "textBox" ? (
41
+ <input
42
+ type="text"
43
+ value={currentValue}
44
+ onChange={(e) => setCurrentValue(e.target.value)}
45
+ style={{
46
+ fontSize: 12,
47
+ color: theme.palette.text.primary,
48
+ padding: 0,
49
+ border: "none",
50
+ outline: "none",
51
+ backgroundColor: "transparent",
52
+ }}
53
+ />
54
+ ) : (
55
+ <>{currentValue}</>
56
+ )}
57
+ </TaskButton>
58
+ {type === "dropDown" && (
59
+ <Menu
60
+ anchorEl={anchorEl}
61
+ open={open}
62
+ onClose={handleClose}
63
+ onItemSelect={handleSelect}
64
+ // anchorOrigin={{
65
+ // vertical: "top",
66
+ // horizontal: "left",
67
+ // }}
68
+ // transformOrigin={{
69
+ // vertical: "top",
70
+ // horizontal: "right",
71
+ // }}
72
+ // MenuListProps={{
73
+ // style: {
74
+ // maxHeight: "250px",
75
+ // },
76
+ // }}
77
+ >
78
+ {data.map((item) => (
79
+ <MenuItem key={item.id} onClick={handleClose} data={item}>
80
+ {displayField ? item[displayField] : item}
81
+ </MenuItem>
82
+ ))}
83
+ </Menu>
84
+ )}
85
+ </div>
86
+ );
87
+ };
88
+
89
+ export default OptionButton;
@@ -0,0 +1,252 @@
1
+ import { useState } from "react";
2
+ import { useEffect } from "react";
3
+ import { useRef } from "react";
4
+ import styled from "@emotion/styled";
5
+ import Input, { InputLabel } from "./Input";
6
+ import { CSSTransition } from "react-transition-group";
7
+ import ArrowDropDownOutlinedIcon from "@mui/icons-material/ArrowDropDownOutlined";
8
+ import { cloneElement } from "react";
9
+ import { useMemo } from "react";
10
+
11
+ export const SelectBox = styled(
12
+ ({
13
+ className,
14
+ children,
15
+ style = {},
16
+ dropDownStyle = {},
17
+ fieldName = Date.now(),
18
+ displayField = null,
19
+ valueField = null,
20
+ defaultValue = null,
21
+ inputStyle = {},
22
+ labelStyle = {},
23
+ placeholder = "",
24
+ allowTextInput = false,
25
+ labelName = "",
26
+ closeOnSelect = true,
27
+ selectBoxRef = useRef({}),
28
+ onChange = () => {},
29
+ }) => {
30
+ const mainRef = useRef(null);
31
+ const listBoxRef = useRef(null);
32
+ const inputRef = useRef(null);
33
+ const [open, setOpen] = useState(false);
34
+ const [currentItem, setCurrentItem] = useState(defaultValue);
35
+
36
+ const handleOpen = () => {
37
+ setOpen(true);
38
+ };
39
+
40
+ const handleClose = () => {
41
+ setOpen(false);
42
+ };
43
+
44
+ const handleArrowClick = () => {
45
+ open ? handleClose() : handleOpen();
46
+ };
47
+
48
+ const onItemSelect = (itemData) => {
49
+ setCurrentItem(displayField ? itemData[displayField] : itemData);
50
+ onChange({
51
+ fieldName: fieldName,
52
+ newValue: !!itemData
53
+ ? !!valueField
54
+ ? itemData[valueField]
55
+ : itemData
56
+ : null,
57
+ previousValue: currentItem,
58
+ });
59
+ handleClose();
60
+ };
61
+
62
+ const handleInputChange = ({ fieldName, newValue, previousValue }) => {
63
+ onChange({
64
+ fieldName: fieldName,
65
+ newValue: newValue,
66
+ previousValue: currentItem,
67
+ });
68
+ setCurrentItem(newValue);
69
+ };
70
+
71
+ // Close dropdown when tab is pressed
72
+ // used instead of onBlur, because oBlur function caused race condition with the onClick event of the dropdown items
73
+ const handleTabPress = (e) => {
74
+ if (e.key === "Tab") {
75
+ setOpen(false);
76
+ }
77
+ };
78
+
79
+ // Close dropdown when clicked outside of the dropdown
80
+ useEffect(() => {
81
+ function handleClickOutside(event) {
82
+ if (mainRef.current && !mainRef.current.contains(event.target)) {
83
+ setOpen(false);
84
+ }
85
+ }
86
+ // Bind the event listener
87
+ document.addEventListener("mousedown", handleClickOutside);
88
+ return () => {
89
+ // Unbind the event listener on clean up
90
+ document.removeEventListener("mousedown", handleClickOutside);
91
+ };
92
+ }, []);
93
+
94
+ // Set internal functions to be used by the parent component
95
+ useEffect(() => {
96
+ selectBoxRef.current = {};
97
+ selectBoxRef.current.close = handleClose;
98
+ selectBoxRef.current.open = handleOpen;
99
+ selectBoxRef.current.setValue = setCurrentItem;
100
+ }, []);
101
+
102
+ return (
103
+ <div
104
+ ref={mainRef}
105
+ className={`${className} ${open ? "opened" : ""}`}
106
+ style={{ ...style }}
107
+ >
108
+ {labelName && (
109
+ <InputLabel
110
+ labelName={labelName}
111
+ style={{ ...labelStyle }}
112
+ ></InputLabel>
113
+ )}
114
+ <div className="select-box">
115
+ <Input
116
+ className="select-box-input"
117
+ inputRef={inputRef}
118
+ defaultValue={currentItem}
119
+ readOnly={!allowTextInput}
120
+ placeholder={placeholder}
121
+ inputStyle={{ cursor: "pointer" }}
122
+ labelStyle={{ ...labelStyle }}
123
+ fieldName={fieldName}
124
+ onFocus={handleOpen}
125
+ onChange={handleInputChange}
126
+ onKeyDown={handleTabPress}
127
+ ></Input>
128
+ <div className="select-box-arrow" onClick={handleArrowClick}>
129
+ <ArrowDropDownOutlinedIcon />
130
+ </div>
131
+ <CSSTransition
132
+ in={open}
133
+ nodeRef={listBoxRef}
134
+ timeout={300}
135
+ classNames="select-box-options"
136
+ unmountOnExit
137
+ // onEnter={() => setShowButton(false)}
138
+ // onExited={() => setShowButton(true)}
139
+ >
140
+ {useMemo(() => {
141
+ return (
142
+ <div
143
+ ref={listBoxRef}
144
+ className="select-box-options"
145
+ style={{ ...dropDownStyle }}
146
+ >
147
+ {children.length
148
+ ? children.map((child) =>
149
+ cloneElement(child, {
150
+ key: child.props.key,
151
+ onItemSelect: onItemSelect,
152
+ })
153
+ )
154
+ : cloneElement(children, {
155
+ // key: children.props.key,
156
+ onItemSelect: onItemSelect,
157
+ })}
158
+ </div>
159
+ );
160
+ }, [children, onItemSelect, open])}
161
+ </CSSTransition>
162
+ </div>
163
+ </div>
164
+ );
165
+ }
166
+ )`
167
+ &.opened input {
168
+ border: 1px solid ${(props) => props.theme.palette.primary.main};
169
+ }
170
+ .select-box {
171
+ position: relative;
172
+ }
173
+ .select-box-input {
174
+ width: 100%;
175
+ }
176
+ .select-box-arrow {
177
+ position: absolute;
178
+ right: 0;
179
+ top: 0;
180
+ bottom: 0;
181
+ display: flex;
182
+ align-items: center;
183
+ justify-content: center;
184
+ padding: 0 8px;
185
+ color: ${(props) => props.theme.palette.text.secondary};
186
+ cursor: pointer;
187
+ }
188
+ .select-box-options {
189
+ position: absolute;
190
+ top: 100%;
191
+ left: 0;
192
+ width: 100%;
193
+ min-height: 100px;
194
+ max-height: 300px;
195
+ overflow-y: auto;
196
+ // background-color: ${(props) => props.theme.palette.background.default};
197
+ background-color: ${(props) => props.theme.palette.input.background};
198
+ border: 1px solid ${(props) => props.theme.palette.divider};
199
+ border-radius: 5px;
200
+ z-index: 1;
201
+ margin-top: 6px;
202
+ padding: 8px;
203
+ box-shadow: 2px 3px 10px 0px rgba(0, 0, 0, 0.2);
204
+ }
205
+ .select-box-options-enter {
206
+ opacity: 0;
207
+ transform: scale(0.9);
208
+ }
209
+ .select-box-options-enter-active {
210
+ opacity: 1;
211
+ transform: translateY(0);
212
+ transition: opacity 100ms, transform 100ms;
213
+ }
214
+ .select-box-options-exit {
215
+ opacity: 1;
216
+ }
217
+ .select-box-options-exit-active {
218
+ opacity: 0;
219
+ transform: scale(0.9);
220
+ transition: opacity 100ms, transform 100ms;
221
+ }
222
+ `;
223
+
224
+ SelectBox.displayName = "SelectBox";
225
+
226
+ export const SelectBoxItem = styled(
227
+ ({ className, children, data = null, onItemSelect = () => {} }) => {
228
+ return (
229
+ <div
230
+ className={`${className} select-box-item`}
231
+ onClick={() => {
232
+ console.log("SelectBoxItem Clicked");
233
+ onItemSelect(data);
234
+ }}
235
+ >
236
+ {children}
237
+ </div>
238
+ );
239
+ }
240
+ )`
241
+ border-radius: 5px;
242
+ cursor: pointer;
243
+ user-select: none;
244
+ padding: 7px;
245
+ &:hover {
246
+ background-color: ${(props) => props.theme.palette.action.hover};
247
+ }
248
+ `;
249
+
250
+ SelectBoxItem.displayName = "SelectBoxItem";
251
+
252
+ export default SelectBox;
@@ -0,0 +1,75 @@
1
+ import { useState } from "react";
2
+ import { useRef } from "react";
3
+ import styled from "@emotion/styled";
4
+ import { InputLabel } from "../Input";
5
+ import {
6
+ Tag,
7
+ TagBoxContainer,
8
+ TagBoxInner,
9
+ TagBoxInput,
10
+ TagKillButton,
11
+ TagsContainer,
12
+ TagText,
13
+ } from "./TagBoxStyles";
14
+
15
+ const TestTags = [
16
+ "STG-1200",
17
+ "Archive Drive 1",
18
+ "NAS 1",
19
+ "Riker",
20
+ "Azure",
21
+ "Tag 6",
22
+ ];
23
+
24
+ const TagBox = styled(({ labelName, labelStyle = {}, data = [] }) => {
25
+ const [tags, setTags] = useState(TestTags);
26
+ const tagBoxContainerRef = useRef(null);
27
+ const tagBoxInputRef = useRef(null);
28
+ const tagBoxInnerRef = useRef(null);
29
+
30
+ const onClick = (e) => {
31
+ tagBoxInputRef.current.focus();
32
+ };
33
+
34
+ const onBlur = (e) => {
35
+ tagBoxInnerRef.current.scrollLeft = -99999;
36
+ };
37
+
38
+ const removeTag = ({ event, clickedTag }) => {
39
+ event.stopPropagation();
40
+ event.preventDefault();
41
+ setTags(tags.filter((tag) => tag !== clickedTag));
42
+ };
43
+
44
+ return (
45
+ <TagBoxContainer ref={tagBoxContainerRef} onClick={onClick} onBlur={onBlur}>
46
+ {labelName && (
47
+ <InputLabel
48
+ labelName={labelName}
49
+ style={{ ...labelStyle }}
50
+ ></InputLabel>
51
+ )}
52
+ <TagBoxInner ref={tagBoxInnerRef}>
53
+ <TagsContainer>
54
+ {tags.map((tag, index) => {
55
+ return (
56
+ <Tag key={index} value={tag}>
57
+ <TagText>{tag}</TagText>
58
+ <TagKillButton
59
+ onClick={(e) => {
60
+ removeTag({ event: e, clickedTag: tag });
61
+ }}
62
+ ></TagKillButton>
63
+ </Tag>
64
+ );
65
+ })}
66
+ </TagsContainer>
67
+ <TagBoxInput ref={tagBoxInputRef}></TagBoxInput>
68
+ </TagBoxInner>
69
+ </TagBoxContainer>
70
+ );
71
+ })``;
72
+
73
+ TagBox.displayName = "TagBox";
74
+
75
+ export default TagBox;
@@ -0,0 +1,122 @@
1
+ import styled from "@emotion/styled";
2
+ import CloseIcon from "@mui/icons-material/Close";
3
+
4
+ export const TagBoxContainer = styled.div`
5
+ width: 100%;
6
+ `;
7
+
8
+ export const TagBoxInner = styled.div`
9
+ height: 33px;
10
+ display: flex;
11
+ border: 1px solid ${(props) => props.theme.palette.input.border};
12
+ color: ${(props) => props.theme.palette.text.primary};
13
+ outline: none;
14
+ padding: 8px 8px;
15
+ width: 100%;
16
+ background-color: ${(props) => props.theme.palette.input.background};
17
+ border-radius: 5px;
18
+ transition: border 0.1s ease-in-out;
19
+ overflow-x: hidden;
20
+ &:focus {
21
+ border: 1px solid ${(props) => props.theme.palette.primary.main};
22
+ }
23
+ `;
24
+
25
+ export const TagsContainer = styled.div`
26
+ // min-height: 34px;
27
+ display: flex;
28
+ -webkit-box-align: center;
29
+ align-items: center;
30
+ flex-wrap: nowrap;
31
+ margin-left: calc(-5px);
32
+ box-sizing: border-box;
33
+ `;
34
+
35
+ export const TagBoxInput = styled.input`
36
+ border: none;
37
+ outline: none;
38
+ width: 100%;
39
+ min-width: 50px;
40
+ background-color: transparent;
41
+ color: ${(props) => props.theme.palette.text.primary};
42
+ &:focus {
43
+ border: none;
44
+ outline: none;
45
+ }
46
+ `;
47
+
48
+ export const Tag = styled.div`
49
+ display: flex;
50
+ -webkit-box-align: center;
51
+ align-items: center;
52
+ background-color: rgb(26, 27, 30);
53
+ color: rgb(193, 194, 197);
54
+ height: 22px;
55
+ padding-left: 10px;
56
+ padding-right: 0px;
57
+ font-weight: 500;
58
+ font-size: 12px;
59
+ border-radius: 4px;
60
+ cursor: default;
61
+ user-select: none;
62
+ max-width: 120px;
63
+ margin: calc(3px) calc(5px);
64
+ `;
65
+
66
+ export const TagText = styled.div`
67
+ display: flex;
68
+ -webkit-box-align: center;
69
+ align-items: center;
70
+ background-color: rgb(26, 27, 30);
71
+ color: rgb(193, 194, 197);
72
+ height: 22px;
73
+ // padding-left: 12px;
74
+ padding-right: 0px;
75
+ font-weight: 500;
76
+ font-size: 12px;
77
+ border-radius: 4px;
78
+ cursor: default;
79
+ user-select: none;
80
+ max-width: 75px;
81
+ // margin: calc(3px) calc(5px);
82
+ white-space: nowrap;
83
+ overflow: hidden;
84
+ text-overflow: ellipsis;
85
+ `;
86
+
87
+ export const TagKillButton = styled(CloseIcon)`
88
+ -webkit-tap-highlight-color: transparent;
89
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
90
+ Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
91
+ cursor: pointer;
92
+ appearance: none;
93
+ // font-size: 18px;
94
+ text-align: left;
95
+ text-decoration: none;
96
+ box-sizing: border-box;
97
+ border: 1px solid transparent;
98
+ background-color: transparent;
99
+ position: relative;
100
+ height: 19px;
101
+ min-height: 19px;
102
+ width: 22px;
103
+ min-width: 19px;
104
+ border-radius: 2px;
105
+ line-height: 1;
106
+ display: flex;
107
+ -webkit-box-align: center;
108
+ align-items: center;
109
+ -webkit-box-pack: center;
110
+ justify-content: center;
111
+ color: rgb(193, 194, 197);
112
+ // margin-left: 4px;
113
+ // margin-right: 4px;
114
+ padding: 0px 3px;
115
+ &:hover {
116
+ color: rgb(255, 255, 255);
117
+ }
118
+ `;
119
+
120
+ export const TagBoxOptions = styled.div``;
121
+
122
+ export const TagBoxOption = styled.div``;
@@ -0,0 +1,85 @@
1
+ import { useRef } from "react";
2
+ import { useEffect, useState } from "react";
3
+ import styled from "@emotion/styled";
4
+ import { InputLabel } from "./Input";
5
+
6
+ const TextArea = styled(
7
+ ({
8
+ className,
9
+ style = {},
10
+ inputStyle = {},
11
+ labelStyle = {},
12
+ placeholder = "",
13
+ labelName = null,
14
+ readOnly = false,
15
+ value = "",
16
+ inputRef = useRef(null),
17
+ rows = 1,
18
+ onChange = () => {},
19
+ onFocus = () => {},
20
+ onBlur = () => {},
21
+ }) => {
22
+ const [inputValue, setInputValue] = useState(value || "");
23
+
24
+ const handleChange = (e) => {
25
+ onChange({
26
+ event: e,
27
+ newValue: e.target.value,
28
+ previousValue: inputValue,
29
+ });
30
+ setInputValue(e.target.value);
31
+ };
32
+
33
+ useEffect(() => {
34
+ setInputValue(value);
35
+ }, [value]);
36
+
37
+ return (
38
+ <div className={className} style={{ ...style }}>
39
+ {labelName && (
40
+ <InputLabel
41
+ labelName={labelName}
42
+ style={{ ...labelStyle }}
43
+ ></InputLabel>
44
+ )}
45
+ <textarea
46
+ ref={inputRef}
47
+ onChange={handleChange}
48
+ onFocus={onFocus}
49
+ onBlur={onBlur}
50
+ readOnly={readOnly}
51
+ placeholder={placeholder}
52
+ rows={rows}
53
+ value={inputValue}
54
+ style={{ ...inputStyle }}
55
+ />
56
+ </div>
57
+ );
58
+ }
59
+ )`
60
+ // width: fit-content;
61
+ width: 100%;
62
+ textarea {
63
+ // border-top: none;
64
+ // border-left: none;
65
+ // border-right: none;
66
+ border: 1px solid ${(props) => props.theme.palette.textArea.border};
67
+ color: ${(props) => props.theme.palette.text.primary};
68
+ outline: none;
69
+ padding: 8px 8px;
70
+ // width: 150px;
71
+ width: 100%;
72
+ height: 100%;
73
+ // background-color: transparent;
74
+ background-color: ${(props) => props.theme.palette.input.background};
75
+ border-radius: 5px;
76
+ transition: border 0.1s ease-in-out;
77
+ resize: none;
78
+ font-family: "Roboto", "Helvetica", "Arial", sans-serif;
79
+ &:focus {
80
+ border: 1px solid ${(props) => props.theme.palette.primary.main};
81
+ }
82
+ }
83
+ `;
84
+
85
+ export default TextArea;
@@ -0,0 +1,43 @@
1
+ import styled from "@emotion/styled";
2
+ import TextArea from "./TextArea";
3
+
4
+ const TextAreaBox = styled(
5
+ ({
6
+ className,
7
+ style = {},
8
+ textAreaStyle = {},
9
+ colSpan = 1,
10
+ height = null,
11
+ labelName = null,
12
+ fieldName = null,
13
+ onChange = () => {},
14
+ }) => {
15
+ const handleChange = ({ newValue, previousValue }) => {
16
+ onChange({
17
+ fieldName: fieldName,
18
+ newValue: newValue,
19
+ previousValue: previousValue,
20
+ });
21
+ };
22
+
23
+ return (
24
+ <div
25
+ className={className}
26
+ style={{
27
+ gridColumn: `span ${colSpan}`,
28
+ ...style,
29
+ }}
30
+ >
31
+ <TextArea
32
+ labelName={labelName}
33
+ onChange={handleChange}
34
+ style={{ height: height, ...textAreaStyle }}
35
+ ></TextArea>
36
+ </div>
37
+ );
38
+ }
39
+ )``;
40
+
41
+ TextAreaBox.displayName = "TextAreaBox";
42
+
43
+ export default TextAreaBox;
package/src/TextBox.js ADDED
@@ -0,0 +1,10 @@
1
+ import styled from "@emotion/styled";
2
+ import Input from "./Input";
3
+
4
+ const TextBox = styled(() => {
5
+ return (
6
+ <div>
7
+ <Input></Input>
8
+ </div>
9
+ );
10
+ })``;
package/src/TimeBox.js ADDED
File without changes