@monolith-forensics/monolith-ui 1.4.2 → 1.4.3

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.
@@ -1,4 +1,5 @@
1
1
  import moment from "moment";
2
+ import { ReactNode } from "react";
2
3
  import { Size, Variant } from "../core";
3
4
  type DateInputProps = {
4
5
  className?: string;
@@ -7,7 +8,7 @@ type DateInputProps = {
7
8
  value?: string | null | undefined;
8
9
  format?: FormatOptions;
9
10
  label?: string;
10
- description?: string;
11
+ description?: ReactNode;
11
12
  arrow?: boolean;
12
13
  size?: Size;
13
14
  variant?: Variant;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
3
  import { Menu, MenuItemList, StyledInnerItemContainer } from "./components";
4
- export const DropDownMenu = ({ data, children, defaultValue, variant, arrow, size, searchable, grouped, onAddNew, loading, onScroll, onScrollToTop, onScrollToBottom, onSearch, manualSearch, multiselect, renderOption, onItemSelect, onChange, buttonProps, TooltipContent, dropDownProps, query, disabled, }) => {
4
+ export const DropDownMenu = ({ data, children, defaultValue, variant, arrow, size, searchable, loading, onScroll, onScrollToTop, onScrollToBottom, onSearch, manualSearch, multiselect, renderOption, onItemSelect, onChange, buttonProps, TooltipContent, dropDownProps, query, disabled, }) => {
5
5
  var _a;
6
6
  const isObjectArray = (_a = Object.keys((data === null || data === void 0 ? void 0 : data[0]) || {})) === null || _a === void 0 ? void 0 : _a.includes("label");
7
7
  const [selected, setSelected] = useState(defaultValue || []);
@@ -25,5 +25,5 @@ export const DropDownMenu = ({ data, children, defaultValue, variant, arrow, siz
25
25
  const handleScrollToBottom = (e) => {
26
26
  onScrollToBottom === null || onScrollToBottom === void 0 ? void 0 : onScrollToBottom(e);
27
27
  };
28
- return (_jsx(Menu, { label: children, disabled: disabled, arrow: arrow, buttonSize: size, variant: variant, multiselect: multiselect, buttonProps: buttonProps, onMenuClose: handleMenuClose, dropDownProps: dropDownProps, children: _jsxs(StyledInnerItemContainer, { children: [loading && _jsx("div", { children: "Loading..." }), !loading && (_jsx(MenuItemList, { menuItems: data, searchable: searchable, grouped: grouped, onAddNew: onAddNew, onSearch: onSearch, manualSearch: manualSearch, selected: selected, TooltipContent: TooltipContent, multiselect: multiselect, size: size, handleAddItem: handleAddItem, handleRemoveItem: handleRemoveItem, onItemSelect: onItemSelect, renderOption: renderOption, onScroll: onScroll, onScrollToTop: onScrollToTop, onScrollToBottom: handleScrollToBottom, query: query }))] }) }));
28
+ return (_jsx(Menu, { label: children, disabled: disabled, arrow: arrow, buttonSize: size, variant: variant, multiselect: multiselect, buttonProps: buttonProps, onMenuClose: handleMenuClose, dropDownProps: dropDownProps, children: _jsxs(StyledInnerItemContainer, { children: [loading && _jsx("div", { children: "Loading..." }), !loading && (_jsx(MenuItemList, { menuItems: data, searchable: searchable, onSearch: onSearch, manualSearch: manualSearch, selected: selected, TooltipContent: TooltipContent, multiselect: multiselect, size: size, handleAddItem: handleAddItem, handleRemoveItem: handleRemoveItem, onItemSelect: onItemSelect, renderOption: renderOption, onScroll: onScroll, onScrollToTop: onScrollToTop, onScrollToBottom: handleScrollToBottom, query: query }))] }) }));
29
29
  };
@@ -10,8 +10,6 @@ export declare const MenuItemList: React.FC<{
10
10
  selected?: DropDownItem[];
11
11
  TooltipContent?: ComponentType<any>;
12
12
  multiselect?: boolean;
13
- grouped?: boolean;
14
- onAddNew?: (value: string) => void;
15
13
  size?: Size;
16
14
  handleAddItem: (item: DropDownItem) => void;
17
15
  handleRemoveItem: (item: DropDownItem) => void;
@@ -13,7 +13,6 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
13
13
  import { useLayoutEffect, useRef, useState } from "react";
14
14
  import styled from "styled-components";
15
15
  import { FixedSizeList } from "react-window";
16
- import { Plus } from "lucide-react";
17
16
  import CheckBox from "../../CheckBox";
18
17
  import { DropDownMenu } from "../DropDownMenu";
19
18
  import { MenuItem } from "./MenuItem";
@@ -31,71 +30,11 @@ const filterMenuItems = (menuItems, searchValue) => {
31
30
  return (_c = item.toLowerCase) === null || _c === void 0 ? void 0 : _c.call(item).includes(searchValue.toLowerCase());
32
31
  });
33
32
  };
34
- const buildGroupedDisplayList = (items) => {
35
- const groups = {};
36
- for (const item of items) {
37
- const key = item.group || "Other";
38
- if (!groups[key])
39
- groups[key] = [];
40
- groups[key].push(item);
41
- }
42
- const sortedKeys = Object.keys(groups).sort((a, b) => a.localeCompare(b));
43
- const result = [];
44
- for (const key of sortedKeys) {
45
- result.push({
46
- _isGroupHeader: true,
47
- label: key,
48
- value: `__group__${key}`,
49
- });
50
- result.push(...groups[key]);
51
- }
52
- return result;
53
- };
54
33
  const ListViewPort = styled.div.attrs({ className: "ListViewPort" }) `
55
34
  display: flex;
56
35
  flex-direction: column;
57
36
  `;
58
- const GroupHeader = styled.div `
59
- display: flex;
60
- align-items: center;
61
- gap: 8px;
62
- color: ${(props) => props.theme.palette.text.secondary};
63
- font-weight: 500;
64
- user-select: none;
65
- padding: ${({ $size }) => $size === "xs"
66
- ? "2px 8px"
67
- : $size === "sm"
68
- ? "4px 10px"
69
- : $size === "md"
70
- ? "4px 12px"
71
- : $size === "lg"
72
- ? "5px 14px"
73
- : $size === "xl"
74
- ? "6px 16px"
75
- : "2px 8px"};
76
- font-size: ${({ $size }) => $size === "xs"
77
- ? "10px"
78
- : $size === "sm"
79
- ? "11px"
80
- : $size === "md"
81
- ? "13px"
82
- : $size === "lg"
83
- ? "15px"
84
- : $size === "xl"
85
- ? "17px"
86
- : "10px"};
87
-
88
- .group-line {
89
- border-top: 1px solid ${(props) => props.theme.palette.divider};
90
- flex: 1;
91
- }
92
-
93
- .group-label {
94
- white-space: nowrap;
95
- min-width: fit-content;
96
- }
97
- `;
98
- export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, selected, TooltipContent, multiselect, grouped, onAddNew, size, handleAddItem, handleRemoveItem, onItemSelect, renderOption, onScroll, onScrollToTop, onScrollToBottom, query, }) => {
37
+ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, selected, TooltipContent, multiselect, size, handleAddItem, handleRemoveItem, onItemSelect, renderOption, onScroll, onScrollToTop, onScrollToBottom, query, }) => {
99
38
  var _a;
100
39
  const [searchValue, setSearchValue] = useState("");
101
40
  const _b = query !== null && query !== void 0 ? query : {}, { queryKey, queryFn, getNextPageParam, initialPageParam } = _b, rest = __rest(_b, ["queryKey", "queryFn", "getNextPageParam", "initialPageParam"]);
@@ -130,29 +69,6 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, se
130
69
  const filteredItems = searchable
131
70
  ? filterMenuItems(visibleItems, searchValue)
132
71
  : visibleItems;
133
- const hasExactMatch = searchValue.trim() !== "" &&
134
- filteredItems.some((item) => {
135
- var _a, _b;
136
- return ((_a = item === null || item === void 0 ? void 0 : item.label) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === searchValue.trim().toLowerCase() ||
137
- ((_b = item === null || item === void 0 ? void 0 : item.value) === null || _b === void 0 ? void 0 : _b.toString().toLowerCase()) ===
138
- searchValue.trim().toLowerCase();
139
- });
140
- const displayItems = (() => {
141
- let items = grouped
142
- ? buildGroupedDisplayList(filteredItems)
143
- : filteredItems;
144
- if (onAddNew && searchValue.trim() && !hasExactMatch) {
145
- items = [
146
- ...items,
147
- {
148
- _isAddNew: true,
149
- label: `Add "${searchValue.trim()}"`,
150
- value: searchValue.trim(),
151
- },
152
- ];
153
- }
154
- return items;
155
- })();
156
72
  const isObjectArray = (_a = Object.keys((visibleItems === null || visibleItems === void 0 ? void 0 : visibleItems[0]) || {})) === null || _a === void 0 ? void 0 : _a.includes("label");
157
73
  const isLoading = isLoadingInfiniteQuery;
158
74
  const handleOnScroll = (event) => {
@@ -198,7 +114,7 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, se
198
114
  }, [targetElm.current, isLoading]);
199
115
  const overscanCount = 10;
200
116
  const itemHeight = 25;
201
- const itemCount = (displayItems === null || displayItems === void 0 ? void 0 : displayItems.length) || 0;
117
+ const itemCount = (filteredItems === null || filteredItems === void 0 ? void 0 : filteredItems.length) || 0;
202
118
  const height = viewPortDimensions.height
203
119
  ? viewPortDimensions.height
204
120
  : itemCount * itemHeight < 200
@@ -218,20 +134,8 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, se
218
134
  alignItems: "center",
219
135
  height: "100%",
220
136
  padding: "10px 0",
221
- }, children: [_jsx("div", { style: { fontSize: "12px" }, children: "Loading..." }), _jsx(Loader, {})] })), !isLoading && (_jsx(ListViewPort, { ref: targetElm, children: _jsx(FixedSizeList, { itemData: displayItems, overscanCount: overscanCount, height: height, width: width, itemCount: itemCount, itemSize: itemHeight, outerRef: listElm, children: ({ data, index, style }) => {
222
- const item = data === null || data === void 0 ? void 0 : data[index];
223
- if (!item)
224
- return null;
225
- if (item._isGroupHeader) {
226
- return (_jsxs(GroupHeader, { "$size": size, style: style, children: [_jsx("span", { className: "group-line" }), _jsx("span", { className: "group-label", children: item.label }), _jsx("span", { className: "group-line" })] }, item.value));
227
- }
228
- if (item._isAddNew) {
229
- return (_jsx(MenuItem, { className: "MenuItem", size: size, leftSection: _jsx(Plus, { size: 14 }), onClick: (e) => {
230
- e.preventDefault();
231
- e.stopPropagation();
232
- onAddNew === null || onAddNew === void 0 ? void 0 : onAddNew(item.value);
233
- }, style: style, children: item.label }, "__add_new__"));
234
- }
137
+ }, children: [_jsx("div", { style: { fontSize: "12px" }, children: "Loading..." }), _jsx(Loader, {})] })), !isLoading && (_jsx(ListViewPort, { ref: targetElm, children: _jsx(FixedSizeList, { itemData: filteredItems, overscanCount: overscanCount, height: height, width: width, itemCount: itemCount, itemSize: itemHeight, outerRef: listElm, children: ({ data, index, style }) => {
138
+ const item = (data === null || data === void 0 ? void 0 : data[index]) || {};
235
139
  const isSelected = !!(selected === null || selected === void 0 ? void 0 : selected.find((s) => {
236
140
  return isObjectArray ? (s === null || s === void 0 ? void 0 : s.value) === (item === null || item === void 0 ? void 0 : item.value) : s === item;
237
141
  }));
@@ -15,7 +15,6 @@ export type DropDownItem = {
15
15
  rightSection?: React.ReactNode;
16
16
  disabled?: boolean;
17
17
  visible?: boolean;
18
- group?: string;
19
18
  };
20
19
  export type SearchInputProps = React.ComponentPropsWithoutRef<typeof Input>;
21
20
  export type StyledContentProps = {
@@ -43,8 +42,6 @@ export type DropDownMenuProps = {
43
42
  onSearch?: (value: string) => void;
44
43
  searchable?: boolean;
45
44
  manualSearch?: boolean;
46
- grouped?: boolean;
47
- onAddNew?: (value: string) => void;
48
45
  loading?: boolean;
49
46
  arrow?: boolean;
50
47
  dropDownProps?: ComponentPropsWithoutRef<typeof StyledContent>;
@@ -3,7 +3,7 @@ import { Size } from "../core";
3
3
  interface InfoComponentProps {
4
4
  className?: string;
5
5
  children?: ReactNode;
6
- description?: string;
6
+ description?: ReactNode;
7
7
  label?: string | ReactNode;
8
8
  }
9
9
  export declare const InfoComponent: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<InfoComponentProps, never>> & string & Omit<({ className, children, description, label }: InfoComponentProps) => string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined, keyof import("react").Component<any, {}, any>>;
@@ -11,7 +11,7 @@ export interface FieldLabelProps {
11
11
  className?: string;
12
12
  children?: ReactNode;
13
13
  error?: string;
14
- description?: string;
14
+ description?: ReactNode;
15
15
  size?: Size;
16
16
  asterisk?: boolean;
17
17
  style?: React.CSSProperties;
@@ -1,3 +1,4 @@
1
+ import { ReactNode } from "react";
1
2
  import { Size, Variant } from "../core";
2
3
  export type Option = {
3
4
  label: string;
@@ -23,7 +24,7 @@ export type SelectBoxProps = {
23
24
  searchable?: boolean;
24
25
  clearable?: boolean;
25
26
  label?: string;
26
- description?: string;
27
+ description?: ReactNode;
27
28
  required?: boolean;
28
29
  error?: string;
29
30
  openOnFocus?: boolean;
@@ -1,4 +1,4 @@
1
- import { CSSProperties } from "react";
1
+ import { CSSProperties, ReactNode } from "react";
2
2
  import { Size } from "../core";
3
3
  export type SwitchProps = {
4
4
  className?: string;
@@ -6,7 +6,7 @@ export type SwitchProps = {
6
6
  size?: Exclude<Size, "xxs">;
7
7
  label?: string;
8
8
  labelPosition?: "left" | "right";
9
- description?: string;
9
+ description?: ReactNode;
10
10
  error?: string;
11
11
  required?: boolean;
12
12
  disabled?: boolean;
@@ -1,3 +1,4 @@
1
+ import { ReactNode } from "react";
1
2
  import { Size, Variant } from "../core";
2
3
  export type Option = {
3
4
  label: string;
@@ -22,7 +23,7 @@ export interface TagBoxProps {
22
23
  searchable?: boolean;
23
24
  clearable?: boolean;
24
25
  label?: string;
25
- description?: string;
26
+ description?: ReactNode;
26
27
  required?: boolean;
27
28
  error?: string;
28
29
  openOnFocus?: boolean;
@@ -1,10 +1,9 @@
1
- import React from "react";
1
+ import React, { ReactNode } from "react";
2
2
  import { Size } from "../core";
3
- import { DropDownMenuProps } from "../DropDownMenu/types";
3
+ import { DropDownItem } from "..";
4
4
  export type InsertableItem = {
5
5
  label: string;
6
6
  value: string;
7
- group?: string;
8
7
  };
9
8
  export interface TextAreaInputProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
10
9
  variant?: "contained" | "filled" | "outlined" | "text";
@@ -13,28 +12,21 @@ export interface TextAreaInputProps extends React.TextareaHTMLAttributes<HTMLTex
13
12
  required?: boolean;
14
13
  colSpan?: number;
15
14
  size?: Size;
16
- description?: string;
15
+ description?: ReactNode;
17
16
  maxRows?: number;
18
17
  minRows?: number;
19
18
  cacheMeasurements?: boolean;
20
19
  onHeightChange?: (height: number, meta: {
21
20
  rowHeight: number;
22
21
  }) => void;
22
+ showActionMenu?: boolean;
23
+ actionMenuOptions?: Array<{
24
+ value: string;
25
+ label: string;
26
+ }>;
27
+ onActionMenuSelect?: (item: DropDownItem) => void;
23
28
  insertableItems?: InsertableItem[];
24
29
  onInsertItem?: (item: InsertableItem) => void;
25
- groupInsertableItems?: boolean;
26
- /** Callback when the user creates a new item by typing a value in the search box that doesn't match any existing option. */
27
- onAddNewItem?: (value: string) => void;
28
- /**
29
- * Visual style of the insert menu trigger.
30
- * - `"ellipsis"` renders a minimal `...` icon button.
31
- * - `"dropdown"` renders an outlined button with a label and arrow (default).
32
- */
33
- insertMenuVariant?: "ellipsis" | "dropdown";
34
- /** Label for the insert dropdown trigger button. Only used when `insertMenuVariant` is `"dropdown"`. Defaults to "Insert". */
35
- insertMenuLabel?: string;
36
- /** Additional props forwarded to the DropDownMenu component. */
37
- insertMenuProps?: Partial<DropDownMenuProps>;
38
30
  }
39
31
  declare const TextAreaInput: React.ForwardRefExoticComponent<TextAreaInputProps & React.RefAttributes<HTMLTextAreaElement>>;
40
32
  export default TextAreaInput;
@@ -11,9 +11,34 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  };
12
12
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  import styled from "styled-components";
14
- import { forwardRef, useRef, useMemo } from "react";
15
- import { TextArea, FieldLabel, DropDownMenu } from "..";
14
+ import { forwardRef, useState, useRef, useEffect } from "react";
15
+ import { TextArea, FieldLabel, DropDownMenu, SelectBox, } from "..";
16
16
  import { MoreHorizontal } from "lucide-react";
17
+ const DEFAULT_ACTIONS = [
18
+ { value: "clear", label: "Clear Text" },
19
+ { value: "insert", label: "Insert Item" },
20
+ ];
21
+ const TextAreaWrapper = styled.div `
22
+ position: relative;
23
+ `;
24
+ const InsertMenuOverlay = styled.div `
25
+ position: absolute;
26
+ top: 0;
27
+ left: 0;
28
+ right: 0;
29
+ z-index: 10;
30
+ opacity: ${({ $visible }) => ($visible ? 1 : 0)};
31
+ pointer-events: ${({ $visible }) => ($visible ? "auto" : "none")};
32
+ transform: ${({ $visible }) => $visible ? "translateY(0)" : "translateY(-4px)"};
33
+ transition:
34
+ opacity 0.2s ease,
35
+ transform 0.2s ease;
36
+ `;
37
+ const StyledInsertSelectBox = styled(SelectBox) `
38
+ width: 100%;
39
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
40
+ border: 1px solid ${({ theme }) => theme.palette.primary.main};
41
+ `;
17
42
  const StyledMoreHorizontal = styled(MoreHorizontal) `
18
43
  color: ${({ theme }) => theme.palette.text.secondary};
19
44
  &:hover {
@@ -21,8 +46,21 @@ const StyledMoreHorizontal = styled(MoreHorizontal) `
21
46
  }
22
47
  `;
23
48
  const TextAreaInput = forwardRef((props, ref) => {
24
- const { label, error, required, colSpan = 1, size = "sm", description, maxRows = 6, minRows = 3, onHeightChange, cacheMeasurements, insertableItems, onInsertItem, groupInsertableItems, onAddNewItem, insertMenuVariant = "dropdown", insertMenuLabel = "Insert", insertMenuProps } = props, rest = __rest(props, ["label", "error", "required", "colSpan", "size", "description", "maxRows", "minRows", "onHeightChange", "cacheMeasurements", "insertableItems", "onInsertItem", "groupInsertableItems", "onAddNewItem", "insertMenuVariant", "insertMenuLabel", "insertMenuProps"]);
49
+ const {
50
+ // UI
51
+ label, error, required, colSpan = 1, size = "sm", description, maxRows = 6, minRows = 3, onHeightChange, cacheMeasurements,
52
+ // Action menu
53
+ showActionMenu = false, actionMenuOptions = DEFAULT_ACTIONS, onActionMenuSelect,
54
+ // Insertable items
55
+ insertableItems, onInsertItem } = props,
56
+ // Rest of props for TextArea
57
+ rest = __rest(props, ["label", "error", "required", "colSpan", "size", "description", "maxRows", "minRows", "onHeightChange", "cacheMeasurements", "showActionMenu", "actionMenuOptions", "onActionMenuSelect", "insertableItems", "onInsertItem"]);
58
+ // State for insert menu visibility
59
+ const [showInsertMenu, setShowInsertMenu] = useState(false);
60
+ const [triggerSelectBoxOpen, setTriggerSelectBoxOpen] = useState(false);
25
61
  const textareaRef = useRef(null);
62
+ const insertMenuRef = useRef(null);
63
+ // Merge refs
26
64
  const mergedRef = (node) => {
27
65
  textareaRef.current = node;
28
66
  if (typeof ref === "function") {
@@ -32,50 +70,79 @@ const TextAreaInput = forwardRef((props, ref) => {
32
70
  ref.current = node;
33
71
  }
34
72
  };
35
- const dropdownData = useMemo(() => (insertableItems || []).map((item) => ({
36
- label: item.label,
37
- value: item.value,
38
- group: item.group,
39
- })), [insertableItems]);
40
- const insertAtCursor = (text) => {
41
- var _a;
42
- const textarea = textareaRef.current;
43
- if (!textarea)
73
+ // Handle click outside to close insert menu
74
+ useEffect(() => {
75
+ if (!showInsertMenu)
44
76
  return;
45
- const start = textarea.selectionStart;
46
- const end = textarea.selectionEnd;
47
- const currentValue = textarea.value;
48
- const newValue = currentValue.slice(0, start) + text + currentValue.slice(end);
49
- const nativeSet = (_a = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value")) === null || _a === void 0 ? void 0 : _a.set;
50
- nativeSet === null || nativeSet === void 0 ? void 0 : nativeSet.call(textarea, newValue);
51
- textarea.dispatchEvent(new Event("input", { bubbles: true }));
52
- textarea.focus();
53
- textarea.setSelectionRange(start + text.length, start + text.length);
54
- };
55
- const handleItemSelect = (item) => {
56
- const insertable = {
57
- label: item.label,
58
- value: String(item.value),
59
- group: item.group,
77
+ const handleClickOutside = (event) => {
78
+ if (insertMenuRef.current &&
79
+ !insertMenuRef.current.contains(event.target)) {
80
+ setShowInsertMenu(false);
81
+ }
60
82
  };
61
- if (onInsertItem) {
62
- onInsertItem(insertable);
83
+ document.addEventListener("mousedown", handleClickOutside);
84
+ return () => {
85
+ document.removeEventListener("mousedown", handleClickOutside);
86
+ };
87
+ }, [showInsertMenu]);
88
+ const handleActionSelect = (item) => {
89
+ if (item.value === "insert" && (insertableItems === null || insertableItems === void 0 ? void 0 : insertableItems.length)) {
90
+ setShowInsertMenu(true);
91
+ // Trigger SelectBox to open using the new enhanced props
92
+ setTriggerSelectBoxOpen(true);
93
+ }
94
+ else if (item.value === "clear") {
95
+ // Built-in clear functionality
96
+ const textarea = textareaRef.current;
97
+ if (textarea) {
98
+ textarea.value = "";
99
+ textarea.focus();
100
+ // Trigger change event so controlled components update
101
+ const event = new Event("input", { bubbles: true });
102
+ textarea.dispatchEvent(event);
103
+ }
104
+ onActionMenuSelect === null || onActionMenuSelect === void 0 ? void 0 : onActionMenuSelect(item);
63
105
  }
64
106
  else {
65
- insertAtCursor(insertable.value);
107
+ onActionMenuSelect === null || onActionMenuSelect === void 0 ? void 0 : onActionMenuSelect(item);
66
108
  }
67
109
  };
68
- const handleAddNew = (value) => {
69
- if (onAddNewItem) {
70
- onAddNewItem(value);
110
+ const handleSelectBoxOpened = () => {
111
+ // Reset the trigger after SelectBox has opened
112
+ setTriggerSelectBoxOpen(false);
113
+ };
114
+ const handleInsertSelect = (value, option) => {
115
+ console.log("Selected value:", value, "Selected option:", option); // Debug log
116
+ // SelectBox passes (value, option) - we want the full option object
117
+ const item = option;
118
+ if (!item || !item.value) {
119
+ console.warn("Invalid item selected:", item);
120
+ setShowInsertMenu(false);
121
+ return;
122
+ }
123
+ if (onInsertItem) {
124
+ onInsertItem(item);
71
125
  }
72
126
  else {
73
- insertAtCursor(value);
127
+ // Default behavior: insert at current cursor position
128
+ const textarea = textareaRef.current;
129
+ if (textarea) {
130
+ const start = textarea.selectionStart;
131
+ const end = textarea.selectionEnd;
132
+ const currentValue = textarea.value;
133
+ const newValue = currentValue.slice(0, start) + item.value + currentValue.slice(end);
134
+ textarea.value = newValue;
135
+ textarea.focus();
136
+ textarea.setSelectionRange(start + item.value.length, start + item.value.length);
137
+ // Trigger change event
138
+ const event = new Event("input", { bubbles: true });
139
+ textarea.dispatchEvent(event);
140
+ }
74
141
  }
142
+ setShowInsertMenu(false);
75
143
  };
76
- const hasInsertableItems = !!dropdownData.length;
77
- return (_jsxs("div", { style: { gridColumn: `span ${colSpan}`, height: "fit-content" }, children: [label && (_jsx(FieldLabel, { asterisk: required, error: error, description: description, size: size, actionComponent: hasInsertableItems ? (insertMenuVariant === "ellipsis" ? (_jsx(DropDownMenu, Object.assign({ data: dropdownData, variant: "text", size: "xs", arrow: false, searchable: true, grouped: groupInsertableItems, onAddNew: handleAddNew, onItemSelect: handleItemSelect, buttonProps: {
78
- "aria-label": "Insert item",
144
+ return (_jsxs("div", { style: { gridColumn: `span ${colSpan}`, height: "fit-content" }, children: [label && (_jsx(FieldLabel, { asterisk: required, error: error, description: description, size: size, actionComponent: showActionMenu ? (_jsx(DropDownMenu, { data: actionMenuOptions, variant: "text", size: "xs", arrow: false, onItemSelect: handleActionSelect, buttonProps: {
145
+ "aria-label": "Open actions",
79
146
  style: {
80
147
  minWidth: "auto",
81
148
  border: "none",
@@ -85,14 +152,7 @@ const TextAreaInput = forwardRef((props, ref) => {
85
152
  height: 16,
86
153
  width: 16,
87
154
  },
88
- }, dropDownProps: {
89
- style: { width: 200, maxWidth: 400 },
90
- } }, insertMenuProps, { children: _jsx(StyledMoreHorizontal, { size: 16 }) }))) : (_jsx(DropDownMenu, Object.assign({ data: dropdownData, variant: "outlined", size: "xs", arrow: true, searchable: true, grouped: groupInsertableItems, onAddNew: handleAddNew, onItemSelect: handleItemSelect, buttonProps: {
91
- title: insertMenuLabel,
92
- size: "xxs",
93
- }, dropDownProps: {
94
- style: { width: 200, maxWidth: 400 },
95
- } }, insertMenuProps, { children: insertMenuLabel })))) : null, children: label })), _jsx(TextArea, Object.assign({ ref: mergedRef, size: size, maxRows: maxRows, minRows: minRows, onHeightChange: onHeightChange, cacheMeasurements: cacheMeasurements }, rest))] }));
155
+ }, children: _jsx(StyledMoreHorizontal, { size: 16 }) })) : null, children: label })), _jsxs(TextAreaWrapper, { children: [_jsx(TextArea, Object.assign({ ref: mergedRef, size: size, maxRows: maxRows, minRows: minRows, onHeightChange: onHeightChange, cacheMeasurements: cacheMeasurements }, rest)), showInsertMenu && (insertableItems === null || insertableItems === void 0 ? void 0 : insertableItems.length) && (_jsx(InsertMenuOverlay, { ref: insertMenuRef, "$visible": showInsertMenu, children: _jsx(StyledInsertSelectBox, { data: insertableItems, placeholder: "Select item to insert...", searchable: true, clearable: false, arrow: false, focused: showInsertMenu, openOnFocus: true, triggerOpen: triggerSelectBoxOpen, onOpened: handleSelectBoxOpened, onChange: handleInsertSelect, size: size }) }))] })] }));
96
156
  });
97
157
  TextAreaInput.displayName = "TextAreaInput";
98
158
  export default TextAreaInput;
@@ -1,5 +1,6 @@
1
1
  import { InputProps } from "../Input/Input";
2
2
  import { Size } from "../core";
3
+ import { ReactNode } from "react";
3
4
  export type TextInputProps = InputProps & {
4
5
  className?: string;
5
6
  label?: string;
@@ -7,7 +8,7 @@ export type TextInputProps = InputProps & {
7
8
  required?: boolean;
8
9
  size?: Size;
9
10
  colSpan?: number;
10
- description?: string;
11
+ description?: ReactNode;
11
12
  inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
12
13
  style?: React.CSSProperties;
13
14
  password?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monolith-forensics/monolith-ui",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "author": "Matt Danner (Monolith Forensics LLC)",