@monolith-forensics/monolith-ui 1.1.57 → 1.1.58

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.
@@ -441,8 +441,48 @@ const DateInput = styled(({ className, defaultValue, format = "YYYY-MM-DD HH:mm:
441
441
  const handlePaste = (e) => __awaiter(void 0, void 0, void 0, function* () {
442
442
  const pastedText = yield window.navigator.clipboard.readText();
443
443
  if (!pastedText)
444
+ return; // do nothing if clipboard is empty
445
+ // check for unix timestamp in seconds
446
+ if (pastedText.match(/^\d{10}$/)) {
447
+ const parsedTimestamp = moment
448
+ .unix(parseInt(pastedText, 10))
449
+ .toISOString();
450
+ setValue(parsedTimestamp);
444
451
  return;
445
- // check if pasted text is a valid timestamp
452
+ }
453
+ // check for unix timestamp in seconds with fractional seconds
454
+ if (pastedText.match(/^\d{10}\.\d{1,6}$/)) {
455
+ const parsedTimestamp = moment
456
+ .unix(parseFloat(pastedText))
457
+ .toISOString();
458
+ setValue(parsedTimestamp);
459
+ return;
460
+ }
461
+ // check for unix timestamp in milliseconds
462
+ if (pastedText.match(/^\d{13}$/)) {
463
+ const parsedTimestamp = moment
464
+ .unix(parseInt(pastedText, 10) / 1000)
465
+ .toISOString();
466
+ setValue(parsedTimestamp);
467
+ return;
468
+ }
469
+ // check for windows ldap or filetime timestamp
470
+ if (pastedText.match(/^\d{18}$/)) {
471
+ const parsedTimestamp = moment
472
+ .unix((parseInt(pastedText, 10) - 116444736000000000) / 10000000)
473
+ .toISOString();
474
+ setValue(parsedTimestamp);
475
+ return;
476
+ }
477
+ // check for YMD ldap timestamp in format YYYYMMDDHHMMSSZ
478
+ if (pastedText.match(/^\d{14}Z$/)) {
479
+ const parsedTimestamp = moment
480
+ .utc(pastedText, "YYYYMMDDHHmmssZ")
481
+ .toISOString();
482
+ setValue(parsedTimestamp);
483
+ return;
484
+ }
485
+ // check if pasted text is any other valid timestamp
446
486
  if (!moment(pastedText).isValid())
447
487
  return;
448
488
  const parsedTimestamp = moment.utc(pastedText).toISOString();
@@ -3,6 +3,7 @@ import { Size, Variant } from "../core";
3
3
  interface SelectBoxProps {
4
4
  className?: string;
5
5
  defaultValue?: Option | string;
6
+ value?: Option | string;
6
7
  data?: Option[] | string[];
7
8
  placeholder?: string;
8
9
  arrow?: boolean;
@@ -41,5 +42,5 @@ type Option = {
41
42
  export declare const StyledInputContainer: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
42
43
  width?: string | number | null;
43
44
  }>> & string;
44
- declare const SelectBox: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<SelectBoxProps, never>> & string & Omit<({ className, data, placeholder, arrow, onChange, onSearch, searchFn, onScroll, loading, defaultValue, onItemAdded, size, variant, width, allowCustomValue, searchable, clearable, label, description, required, error, openOnFocus, renderOption, actionComponent, focused, grouped, TooltipContent, DropDownProps, }: SelectBoxProps) => import("react/jsx-runtime").JSX.Element, keyof import("react").Component<any, {}, any>>;
45
+ declare const SelectBox: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<SelectBoxProps, never>> & string & Omit<({ className, data, placeholder, arrow, onChange, onSearch, searchFn, onScroll, loading, defaultValue, value, onItemAdded, size, variant, width, allowCustomValue, searchable, clearable, label, description, required, error, openOnFocus, renderOption, actionComponent, focused, grouped, TooltipContent, DropDownProps, }: SelectBoxProps) => import("react/jsx-runtime").JSX.Element, keyof import("react").Component<any, {}, any>>;
45
46
  export default SelectBox;
@@ -15,6 +15,7 @@ import { useFloating, flip, offset, FloatingPortal, autoUpdate, } from "@floatin
15
15
  import { useCallback, useEffect, useRef, useState, } from "react";
16
16
  import { Input, FieldLabel, Tooltip } from "..";
17
17
  import { useDebouncedCallback } from "use-debounce";
18
+ import { useUncontrolled } from "@mantine/hooks";
18
19
  import { StyledContent, StyledFloatContainer, ArrowButton, ClearButton, } from "../core";
19
20
  export const StyledInputContainer = styled.div `
20
21
  font-family: ${({ theme }) => theme.typography.fontFamily};
@@ -150,11 +151,15 @@ const StyledItem = styled.div `
150
151
  color: ${(props) => props.theme.palette.text.primary};
151
152
  }
152
153
  `;
153
- const SelectBox = styled(({ className, data = [], placeholder = "Select...", arrow = true, onChange, onSearch, searchFn, onScroll, loading, defaultValue, onItemAdded, size = "sm", variant = "outlined", width = "100%", allowCustomValue = false, searchable = false, clearable = false, label, description, required = false, error, openOnFocus = true, renderOption, actionComponent, focused, grouped, TooltipContent, DropDownProps = {}, }) => {
154
- var _a, _b, _c, _d, _e, _f, _g, _h;
154
+ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arrow = true, onChange, onSearch, searchFn, onScroll, loading, defaultValue, value, onItemAdded, size = "sm", variant = "outlined", width = "100%", allowCustomValue = false, searchable = false, clearable = false, label, description, required = false, error, openOnFocus = true, renderOption, actionComponent, focused, grouped, TooltipContent, DropDownProps = {}, }) => {
155
+ var _a, _b, _c, _d, _e, _f, _g;
155
156
  const isObjectArray = (_a = Object.keys((data === null || data === void 0 ? void 0 : data[0]) || {})) === null || _a === void 0 ? void 0 : _a.includes("label");
157
+ const [_value, handleChange] = useUncontrolled({
158
+ value,
159
+ defaultValue,
160
+ onChange,
161
+ });
156
162
  const [isOpen, setIsOpen] = useState(false);
157
- const [selected, setSelected] = useState(null);
158
163
  const [searchValue, setSearchValue] = useState("");
159
164
  const [customItems, setCustomItems] = useState([]);
160
165
  const [placement, setPlacement] = useState("bottom-start");
@@ -162,9 +167,9 @@ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arr
162
167
  const inputRef = useRef(null);
163
168
  const containerRef = useRef(null);
164
169
  const scrollContainerRef = useRef(null);
165
- const uniqueItems = Array.from(new Map([...data, ...customItems].map(item => [
170
+ const uniqueItems = Array.from(new Map([...data, ...customItems].map((item) => [
166
171
  isObjectArray ? item.value : item,
167
- item
172
+ item,
168
173
  ])).values());
169
174
  const filteredItems = uniqueItems
170
175
  .filter((item) => {
@@ -225,11 +230,9 @@ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arr
225
230
  };
226
231
  const handleClear = (e) => {
227
232
  e.preventDefault();
228
- if (inputRef.current)
229
- inputRef.current.value = "";
233
+ e.stopPropagation();
230
234
  setIsOpen(false);
231
- handleChangeSelection(null);
232
- setSelected(null);
235
+ handleChange(undefined);
233
236
  setSearchValue("");
234
237
  searchFn === null || searchFn === void 0 ? void 0 : searchFn("");
235
238
  update();
@@ -237,13 +240,9 @@ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arr
237
240
  const handleItemClick = (event, item) => {
238
241
  event.preventDefault();
239
242
  event.stopPropagation();
240
- handleChangeSelection(item);
243
+ handleChange(item);
241
244
  setIsOpen(false);
242
245
  };
243
- const handleChangeSelection = useCallback((option) => {
244
- setSelected(option);
245
- onChange === null || onChange === void 0 ? void 0 : onChange((option === null || option === void 0 ? void 0 : option.value) || option, option);
246
- }, [onChange]);
247
246
  const handleAddItem = useCallback((newItem) => {
248
247
  const isNewItem = data.every((item) => item.label.toLowerCase() !==
249
248
  newItem.toLowerCase());
@@ -255,7 +254,7 @@ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arr
255
254
  prev.push(newValue);
256
255
  return prev;
257
256
  });
258
- handleChangeSelection(newValue);
257
+ handleChange(newValue);
259
258
  onItemAdded === null || onItemAdded === void 0 ? void 0 : onItemAdded(newValue);
260
259
  }
261
260
  else {
@@ -264,9 +263,9 @@ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arr
264
263
  ? item.label.toLowerCase() === newItem.toLowerCase()
265
264
  : item.toLowerCase() === newItem.toLowerCase();
266
265
  });
267
- handleChangeSelection(item);
266
+ handleChange(item);
268
267
  }
269
- }, [onItemAdded, isObjectArray, data, handleChangeSelection]);
268
+ }, [onItemAdded, isObjectArray, data, handleChange]);
270
269
  const handleKeyDown = (e) => {
271
270
  var _a, _b;
272
271
  const currentInputValue = (_a = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _a === void 0 ? void 0 : _a.value;
@@ -293,32 +292,26 @@ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arr
293
292
  // Arrow down
294
293
  if (e.key === "ArrowDown") {
295
294
  e.preventDefault();
296
- setSelected((prev) => {
297
- let newItem = filteredItems[0]; // Loop back to the first item
298
- const index = filteredItems.findIndex((item) => isObjectArray
299
- ? item.value === (prev === null || prev === void 0 ? void 0 : prev.value)
300
- : item === prev);
301
- if (index < filteredItems.length - 1) {
302
- newItem = filteredItems[index + 1];
303
- }
304
- onChange === null || onChange === void 0 ? void 0 : onChange((newItem === null || newItem === void 0 ? void 0 : newItem.value) || newItem, newItem);
305
- return newItem;
306
- });
295
+ let newItem = filteredItems[0]; // Loop back to the first item
296
+ const index = filteredItems.findIndex((item) => isObjectArray
297
+ ? item.value === (_value === null || _value === void 0 ? void 0 : _value.value)
298
+ : item === _value);
299
+ if (index < filteredItems.length - 1) {
300
+ newItem = filteredItems[index + 1];
301
+ }
302
+ handleChange === null || handleChange === void 0 ? void 0 : handleChange(newItem, newItem);
307
303
  }
308
304
  // Arrow up
309
305
  if (e.key === "ArrowUp") {
310
306
  e.preventDefault();
311
- setSelected((prev) => {
312
- let newItem = filteredItems[filteredItems.length - 1]; // Loop back to the last item
313
- const index = filteredItems.findIndex((item) => isObjectArray
314
- ? item.value === (prev === null || prev === void 0 ? void 0 : prev.value)
315
- : item === prev);
316
- if (index > 0) {
317
- newItem = filteredItems[index - 1];
318
- }
319
- onChange === null || onChange === void 0 ? void 0 : onChange((newItem === null || newItem === void 0 ? void 0 : newItem.value) || newItem, newItem);
320
- return newItem;
321
- });
307
+ let newItem = filteredItems[filteredItems.length - 1]; // Loop back to the last item
308
+ const index = filteredItems.findIndex((item) => isObjectArray
309
+ ? item.value === (_value === null || _value === void 0 ? void 0 : _value.value)
310
+ : item === _value);
311
+ if (index > 0) {
312
+ newItem = filteredItems[index - 1];
313
+ }
314
+ handleChange === null || handleChange === void 0 ? void 0 : handleChange(newItem, newItem);
322
315
  }
323
316
  // Tab key
324
317
  if (e.key === "Tab") {
@@ -326,7 +319,7 @@ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arr
326
319
  handleAddItem(currentInputValue);
327
320
  setSearchValue("");
328
321
  }
329
- else if (!selected) {
322
+ else if (!_value) {
330
323
  // clear input
331
324
  if (inputRef.current) {
332
325
  inputRef.current.value = "";
@@ -381,31 +374,6 @@ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arr
381
374
  document.addEventListener("click", close);
382
375
  return () => document.removeEventListener("click", close);
383
376
  }, [refs.floating, refs.reference]);
384
- // Handle default value
385
- useEffect(() => {
386
- if (defaultValue) {
387
- const isOption = defaultValue.value !== undefined;
388
- const searchPattern = isOption
389
- ? defaultValue.value
390
- : defaultValue;
391
- setSelected(data.find((item) => isObjectArray
392
- ? item.value === searchPattern
393
- : item === searchPattern) || null);
394
- }
395
- }, [data, defaultValue, isObjectArray]);
396
- // handle input value change
397
- useEffect(() => {
398
- if (inputRef.current) {
399
- if (!selected) {
400
- inputRef.current.value = "";
401
- }
402
- else {
403
- inputRef.current.value = isObjectArray
404
- ? selected.label
405
- : selected;
406
- }
407
- }
408
- }, [selected]);
409
377
  // handle scroll item into view
410
378
  useEffect(() => {
411
379
  var _a, _b;
@@ -413,7 +381,7 @@ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arr
413
381
  if (item) {
414
382
  item.scrollIntoView({ block: "nearest" });
415
383
  }
416
- }, [selected]);
384
+ }, [_value]);
417
385
  // make calls to onSearch callback
418
386
  useEffect(() => {
419
387
  if (searchable) {
@@ -446,7 +414,7 @@ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arr
446
414
  setDropDownHeight(bottomHeight);
447
415
  };
448
416
  }, [topHeight, bottomHeight, isOpen]);
449
- return (_jsxs("div", { className: className, children: [label && (_jsx(FieldLabel, { error: error, asterisk: required, size: size, description: description, children: label })), _jsxs(StyledInputContainer, { ref: refs.setReference, onMouseDown: () => setIsOpen(true), width: width, onKeyDown: handleKeyDown, "data-open": isOpen, children: [_jsx(Input, { ref: inputRef, onChange: debouncedHandleOnChange, onFocus: handleFocus, autoFocus: focused, placeholder: placeholder, size: size, readOnly: !searchable, "data-button-right": arrow || clearable }), clearable && (selected || !!((_h = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _h === void 0 ? void 0 : _h.value)) ? (_jsx(ClearButton, { className: "input-btn", onClick: handleClear, onMouseDown: (e) => {
417
+ return (_jsxs("div", { className: className, children: [label && (_jsx(FieldLabel, { error: error, asterisk: required, size: size, description: description, children: label })), _jsxs(StyledInputContainer, { ref: refs.setReference, onMouseDown: () => setIsOpen(true), width: width, onKeyDown: handleKeyDown, "data-open": isOpen, children: [_jsx(Input, { ref: inputRef, value: isObjectArray ? (_value === null || _value === void 0 ? void 0 : _value.label) || "" : _value || "", onChange: debouncedHandleOnChange, onFocus: handleFocus, autoFocus: focused, placeholder: placeholder, size: size, readOnly: !searchable, "data-button-right": arrow || clearable }), clearable && _value ? (_jsx(ClearButton, { className: "input-btn", onClick: handleClear, onMouseDown: (e) => {
450
418
  e.preventDefault();
451
419
  e.stopPropagation();
452
420
  } })) : arrow ? (_jsx(ArrowButton, { onClick: (e) => {
@@ -468,15 +436,14 @@ const SelectBox = styled(({ className, data = [], placeholder = "Select...", arr
468
436
  }, variant: variant, "data-empty": filteredItems.length === 0 }, DropDownProps, { children: [actionComponent && _jsx(ActionMenu, { children: actionComponent }), _jsxs(StyledInnerItemContainer, { ref: scrollContainerRef, "data-scroll-active": scrollActive, onScroll: onScroll, children: [loading && _jsx("div", { children: "Loading..." }), !loading && grouped
469
437
  ? groups.map((group, index) => (_jsxs("div", { children: [_jsx(GroupTitle, { size: size, children: group.label }), group.items.map((item, index) => {
470
438
  return (_jsx(Tooltip, { content: TooltipContent ? (_jsx(TooltipContent, { data: item.data })) : null, side: "left", children: _jsx(StyledItem, { className: "mfFloatingItem", onClick: (e) => handleItemClick(e, item), "data-selected": isObjectArray
471
- ? (selected === null || selected === void 0 ? void 0 : selected.value) ===
472
- item.value
473
- : selected === item, size: size, children: (renderOption === null || renderOption === void 0 ? void 0 : renderOption(item)) || (_jsx(_Fragment, { children: (item === null || item === void 0 ? void 0 : item.label) || item })) }, index) }, index));
439
+ ? (_value === null || _value === void 0 ? void 0 : _value.value) === item.value
440
+ : _value === item, size: size, children: (renderOption === null || renderOption === void 0 ? void 0 : renderOption(item)) || (_jsx(_Fragment, { children: (item === null || item === void 0 ? void 0 : item.label) || item })) }, index) }, index));
474
441
  })] }, group.label)))
475
442
  : filteredItems.map((item, index) => {
476
443
  return (_jsx(Tooltip, { content: TooltipContent ? (_jsx(TooltipContent, { data: item.data })) : null, side: "left", children: _jsx(StyledItem, { className: "mfFloatingItem", onClick: (e) => handleItemClick(e, item), "data-selected": isObjectArray
477
- ? (selected === null || selected === void 0 ? void 0 : selected.value) ===
444
+ ? (_value === null || _value === void 0 ? void 0 : _value.value) ===
478
445
  (item === null || item === void 0 ? void 0 : item.value)
479
- : selected === item, size: size, children: (renderOption === null || renderOption === void 0 ? void 0 : renderOption(item)) || (_jsx(_Fragment, { children: (item === null || item === void 0 ? void 0 : item.label) || item })) }, index) }, index));
446
+ : _value === item, size: size, children: (renderOption === null || renderOption === void 0 ? void 0 : renderOption(item)) || (_jsx(_Fragment, { children: (item === null || item === void 0 ? void 0 : item.label) || item })) }, index) }, index));
480
447
  })] })] })) }) }))] }));
481
448
  }) `
482
449
  position: relative;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monolith-forensics/monolith-ui",
3
- "version": "1.1.57",
3
+ "version": "1.1.58",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "author": "Matt Danner (Monolith Forensics LLC)",
@@ -22,6 +22,7 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@floating-ui/react": "^0.26.16",
25
+ "@mantine/hooks": "^7.13.0",
25
26
  "@radix-ui/react-switch": "^1.0.7",
26
27
  "@radix-ui/react-tooltip": "^1.0.7",
27
28
  "@tabler/icons-react": "^3.11.0",