@monolith-forensics/monolith-ui 2.1.0 → 2.1.1-dev.4
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.
- package/dist/DropDownMenu/DropDownMenu.js +9 -6
- package/dist/DropDownMenu/components/MenuItem.js +5 -1
- package/dist/DropDownMenu/components/MenuItemList.d.ts +3 -2
- package/dist/DropDownMenu/components/MenuItemList.js +37 -63
- package/dist/DropDownMenu/types.d.ts +1 -10
- package/dist/FileViewer/FileViewer.d.ts +1 -0
- package/dist/FileViewer/FileViewer.js +2 -2
- package/dist/QueryFilter/QueryFilter.types.d.ts +18 -2
- package/dist/QueryFilter/components/MultiSelectEditor.js +164 -7
- package/dist/core/controlSizes.js +1 -1
- package/package.json +1 -3
- package/dist/QueryFilter/DefaultOperators.d.ts +0 -76
- package/dist/QueryFilter/DefaultOperators.js +0 -21
- package/dist/QueryFilter/types.d.ts +0 -66
- package/dist/QueryFilter/types.js +0 -1
- package/dist/RichTextEditor/Extensions/BubbleMenuExtension.d.ts +0 -7
- package/dist/RichTextEditor/Extensions/BubbleMenuExtension.js +0 -157
- package/dist/Table/Utils/resizeHandler.d.ts +0 -3
- package/dist/Table/Utils/resizeHandler.js +0 -84
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { Menu, MenuItemList, StyledInnerItemContainer } from "./components";
|
|
4
4
|
import { DEFAULT_DROPDOWN_MAX_HEIGHT } from "./constants";
|
|
@@ -10,10 +10,13 @@ const getNumericCssLength = (value) => {
|
|
|
10
10
|
const pixelMatch = value.trim().match(/^(\d+(?:\.\d+)?)px$/);
|
|
11
11
|
return pixelMatch ? Number(pixelMatch[1]) : undefined;
|
|
12
12
|
};
|
|
13
|
-
export const DropDownMenu = ({ data, children, defaultValue, value, variant, arrow, size, searchable, grouped, onAddNew, loading, onScroll, onScrollToTop, onScrollToBottom, onSearch, manualSearch, multiselect, enableSelectAll, enableSelectedOptionStyling, renderOption, dynamicOptionHeight, onItemSelect, onChange, buttonProps, TooltipContent, dropDownProps,
|
|
14
|
-
var _a, _b, _c, _d, _e
|
|
15
|
-
const isObjectArray =
|
|
16
|
-
|
|
13
|
+
export const DropDownMenu = ({ data, children, defaultValue, value, variant, arrow, size, searchable, grouped, onAddNew, loading, loadingMore, onScroll, onScrollToTop, onScrollToBottom, onSearch, manualSearch, multiselect, enableSelectAll, enableSelectedOptionStyling, renderOption, dynamicOptionHeight, onItemSelect, onChange, buttonProps, TooltipContent, dropDownProps, disabled, }) => {
|
|
14
|
+
var _a, _b, _c, _d, _e;
|
|
15
|
+
const isObjectArray = [
|
|
16
|
+
...(data || []),
|
|
17
|
+
...(value || defaultValue || []),
|
|
18
|
+
].some((item) => { var _a; return (_a = Object.keys(item || {})) === null || _a === void 0 ? void 0 : _a.includes("label"); });
|
|
19
|
+
const maxDropdownHeight = (_e = (_d = (_b = getNumericCssLength((_a = dropDownProps === null || dropDownProps === void 0 ? void 0 : dropDownProps.style) === null || _a === void 0 ? void 0 : _a.height)) !== null && _b !== void 0 ? _b : getNumericCssLength((_c = dropDownProps === null || dropDownProps === void 0 ? void 0 : dropDownProps.style) === null || _c === void 0 ? void 0 : _c.maxHeight)) !== null && _d !== void 0 ? _d : getNumericCssLength(dropDownProps === null || dropDownProps === void 0 ? void 0 : dropDownProps.maxDropdownHeight)) !== null && _e !== void 0 ? _e : DEFAULT_DROPDOWN_MAX_HEIGHT;
|
|
17
20
|
const [internalSelected, setInternalSelected] = useState(defaultValue || []);
|
|
18
21
|
const isControlled = value !== undefined;
|
|
19
22
|
const selected = isControlled ? value || [] : internalSelected;
|
|
@@ -45,5 +48,5 @@ export const DropDownMenu = ({ data, children, defaultValue, value, variant, arr
|
|
|
45
48
|
const handleScrollToBottom = (e) => {
|
|
46
49
|
onScrollToBottom === null || onScrollToBottom === void 0 ? void 0 : onScrollToBottom(e);
|
|
47
50
|
};
|
|
48
|
-
return (_jsx(Menu, { label: children, disabled: disabled, arrow: arrow, buttonSize: size, variant: variant, multiselect: multiselect, buttonProps: buttonProps, onMenuClose: handleMenuClose, dropDownProps: dropDownProps, children:
|
|
51
|
+
return (_jsx(Menu, { label: children, disabled: disabled, arrow: arrow, buttonSize: size, variant: variant, multiselect: multiselect, buttonProps: buttonProps, onMenuClose: handleMenuClose, dropDownProps: dropDownProps, children: _jsx(StyledInnerItemContainer, { children: _jsx(MenuItemList, { menuItems: data, searchable: searchable, grouped: grouped, onAddNew: onAddNew, onSearch: onSearch, manualSearch: manualSearch, dynamicOptionHeight: dynamicOptionHeight, maxDropdownHeight: maxDropdownHeight, selected: selected, TooltipContent: TooltipContent, multiselect: multiselect, enableSelectAll: enableSelectAll, enableSelectedOptionStyling: enableSelectedOptionStyling, size: size, loading: loading, loadingMore: loadingMore, handleAddItem: handleAddItem, handleRemoveItem: handleRemoveItem, handleSetSelected: handleSetSelected, onItemSelect: onItemSelect, renderOption: renderOption, onScroll: onScroll, onScrollToTop: onScrollToTop, onScrollToBottom: handleScrollToBottom }) }) }));
|
|
49
52
|
};
|
|
@@ -26,7 +26,7 @@ export const MenuItem = styled(forwardRef((_a, forwardedRef) => {
|
|
|
26
26
|
return (_jsx(Tooltip, { content: TooltipContent ? _jsx(TooltipContent, { data: itemData }) : null, side: "left", children: _jsx(Button, Object.assign({}, props, { ref: useMergeRefs([
|
|
27
27
|
item.ref,
|
|
28
28
|
forwardedRef,
|
|
29
|
-
]), type: "button", role: "menuitem", tabIndex: isActive ? 0 : -1, disabled: disabled, justify: "start", color: props.color, selected: false }, menu.getItemProps({
|
|
29
|
+
]), type: "button", role: "menuitem", tabIndex: isActive ? 0 : -1, "data-multiselect": multiselect, disabled: disabled, justify: "start", color: props.color, selected: false }, menu.getItemProps({
|
|
30
30
|
onClick(event) {
|
|
31
31
|
var _a;
|
|
32
32
|
(_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, event);
|
|
@@ -104,5 +104,9 @@ export const MenuItem = styled(forwardRef((_a, forwardedRef) => {
|
|
|
104
104
|
white-space: ${({ $dynamicHeight }) => $dynamicHeight ? "normal" : "nowrap"};
|
|
105
105
|
text-overflow: ${({ $dynamicHeight }) => $dynamicHeight ? "clip" : "ellipsis"};
|
|
106
106
|
}
|
|
107
|
+
|
|
108
|
+
&[data-multiselect="true"] [data-position="left"] {
|
|
109
|
+
padding-inline-end: ${({ size = "sm" }) => `${getControlSizeTokens(size).iconGap}px`};
|
|
110
|
+
}
|
|
107
111
|
}
|
|
108
112
|
`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComponentType } from "react";
|
|
2
2
|
import { Size } from "../../core";
|
|
3
|
-
import { DropDownItem
|
|
3
|
+
import { DropDownItem } from "../types";
|
|
4
4
|
export declare const MenuItemList: React.FC<{
|
|
5
5
|
menuItems: DropDownItem[];
|
|
6
6
|
searchable?: boolean;
|
|
@@ -25,5 +25,6 @@ export declare const MenuItemList: React.FC<{
|
|
|
25
25
|
onScrollToTop?: (e: Event) => void;
|
|
26
26
|
onScrollToBottom?: (e: Event) => void;
|
|
27
27
|
maxDropdownHeight?: number;
|
|
28
|
-
|
|
28
|
+
loading?: boolean;
|
|
29
|
+
loadingMore?: boolean;
|
|
29
30
|
}>;
|
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
-
var t = {};
|
|
3
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
-
t[p] = s[p];
|
|
5
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
-
t[p[i]] = s[p[i]];
|
|
9
|
-
}
|
|
10
|
-
return t;
|
|
11
|
-
};
|
|
12
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
13
2
|
import { useCallback, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
14
3
|
import styled from "styled-components";
|
|
@@ -18,7 +7,6 @@ import CheckBox from "../../CheckBox";
|
|
|
18
7
|
import { getControlSizeTokens } from "../../core";
|
|
19
8
|
import { DropDownMenu } from "../DropDownMenu";
|
|
20
9
|
import { MenuItem } from "./MenuItem";
|
|
21
|
-
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
22
10
|
import { useDebouncedCallback } from "use-debounce";
|
|
23
11
|
import { SearchInput } from "./SearchInput";
|
|
24
12
|
import Loader from "../../Loader";
|
|
@@ -108,6 +96,17 @@ const GroupHeader = styled.div `
|
|
|
108
96
|
min-width: fit-content;
|
|
109
97
|
}
|
|
110
98
|
`;
|
|
99
|
+
const LoadingMoreRow = styled.div `
|
|
100
|
+
display: flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
justify-content: center;
|
|
103
|
+
gap: 8px;
|
|
104
|
+
color: ${(props) => props.theme.palette.text.secondary};
|
|
105
|
+
min-height: ${({ $size = "sm" }) => `${getControlSizeTokens($size).menuRowHeight}px`};
|
|
106
|
+
padding: ${({ $size = "sm" }) => `0px ${getControlSizeTokens($size).menuItemPaddingX}px`};
|
|
107
|
+
font-size: ${({ $size = "sm" }) => `${getControlSizeTokens($size).supportingFontSize}px`};
|
|
108
|
+
box-sizing: border-box;
|
|
109
|
+
`;
|
|
111
110
|
const MeasuredRow = ({ children, index, setItemSize, style }) => {
|
|
112
111
|
const rowRef = useRef(null);
|
|
113
112
|
useLayoutEffect(() => {
|
|
@@ -129,29 +128,14 @@ const MeasuredRow = ({ children, index, setItemSize, style }) => {
|
|
|
129
128
|
}, [children, index, setItemSize]);
|
|
130
129
|
return (_jsx("div", { style: Object.assign(Object.assign({}, style), { overflow: "visible" }), children: _jsx("div", { ref: rowRef, children: children }) }));
|
|
131
130
|
};
|
|
132
|
-
export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dynamicOptionHeight, selected, TooltipContent, multiselect, enableSelectAll, enableSelectedOptionStyling, grouped, onAddNew, size, handleAddItem, handleRemoveItem, handleSetSelected, onItemSelect, renderOption, onScroll, onScrollToTop, onScrollToBottom, maxDropdownHeight = DEFAULT_DROPDOWN_MAX_HEIGHT,
|
|
131
|
+
export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dynamicOptionHeight, selected, TooltipContent, multiselect, enableSelectAll, enableSelectedOptionStyling, grouped, onAddNew, size, handleAddItem, handleRemoveItem, handleSetSelected, onItemSelect, renderOption, onScroll, onScrollToTop, onScrollToBottom, maxDropdownHeight = DEFAULT_DROPDOWN_MAX_HEIGHT, loading, loadingMore, }) => {
|
|
133
132
|
const [searchValue, setSearchValue] = useState("");
|
|
134
|
-
const _a = query !== null && query !== void 0 ? query : {}, { queryKey, queryFn, getNextPageParam, initialPageParam } = _a, rest = __rest(_a, ["queryKey", "queryFn", "getNextPageParam", "initialPageParam"]);
|
|
135
|
-
const targetElm = useRef(null);
|
|
136
133
|
const listElm = useRef(null);
|
|
137
134
|
const fixedListRef = useRef(null);
|
|
138
135
|
const variableListRef = useRef(null);
|
|
139
136
|
const hasHandledInitialSelectedScroll = useRef(false);
|
|
140
137
|
const itemSizeMap = useRef({});
|
|
141
|
-
const [viewPortDimensions, setViewPortDimensions] = useState({
|
|
142
|
-
width: 0,
|
|
143
|
-
height: 0,
|
|
144
|
-
});
|
|
145
138
|
const [, setMeasurementRevision] = useState(0);
|
|
146
|
-
const { data: infiniteQueryResult, isLoading: isLoadingInfiniteQuery, fetchNextPage, } = useInfiniteQuery(Object.assign({ queryKey: (queryKey === null || queryKey === void 0 ? void 0 : queryKey({ search: searchValue })) || [], queryFn: queryFn, getNextPageParam: (query === null || query === void 0 ? void 0 : query.getNextPageParam) || (() => undefined), initialPageParam: (query === null || query === void 0 ? void 0 : query.initialPageParam) || 1, enabled: !!query }, rest));
|
|
147
|
-
const infinteOptionsData = infiniteQueryResult;
|
|
148
|
-
const infiniteSelectOptions = infinteOptionsData || [];
|
|
149
|
-
const _options = !!query ? infiniteSelectOptions : menuItems;
|
|
150
|
-
const debouncedFetchNextPage = useDebouncedCallback(() => {
|
|
151
|
-
if (!isLoading && !!query) {
|
|
152
|
-
fetchNextPage();
|
|
153
|
-
}
|
|
154
|
-
}, 50);
|
|
155
139
|
const handleSearch = useDebouncedCallback((e) => {
|
|
156
140
|
setSearchValue(e.target.value);
|
|
157
141
|
}, 150);
|
|
@@ -166,7 +150,7 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
|
|
|
166
150
|
onItemSelect === null || onItemSelect === void 0 ? void 0 : onItemSelect(item);
|
|
167
151
|
(_a = item === null || item === void 0 ? void 0 : item.onClick) === null || _a === void 0 ? void 0 : _a.call(item, item);
|
|
168
152
|
};
|
|
169
|
-
const visibleItems =
|
|
153
|
+
const visibleItems = menuItems.filter((item) => item.visible !== false);
|
|
170
154
|
const filteredItems = searchable
|
|
171
155
|
? filterMenuItems(visibleItems, searchValue)
|
|
172
156
|
: visibleItems;
|
|
@@ -191,12 +175,23 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
|
|
|
191
175
|
},
|
|
192
176
|
];
|
|
193
177
|
}
|
|
178
|
+
if (loadingMore) {
|
|
179
|
+
items = [
|
|
180
|
+
...items,
|
|
181
|
+
{
|
|
182
|
+
_isLoadingMore: true,
|
|
183
|
+
label: "Loading more...",
|
|
184
|
+
value: "__loading_more__",
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
}
|
|
194
188
|
return items;
|
|
195
189
|
})();
|
|
196
190
|
const selectedKeys = useMemo(() => new Set((selected || []).map(getItemKey)), [selected]);
|
|
197
191
|
const isItemSelected = (item) => selectedKeys.has(getItemKey(item));
|
|
198
192
|
const selectableItems = useMemo(() => displayItems.filter((item) => !item._isGroupHeader &&
|
|
199
193
|
!item._isAddNew &&
|
|
194
|
+
!item._isLoadingMore &&
|
|
200
195
|
!item.disabled &&
|
|
201
196
|
!item.items), [displayItems]);
|
|
202
197
|
const selectableKeys = useMemo(() => new Set(selectableItems.map(getItemKey)), [selectableItems]);
|
|
@@ -205,12 +200,13 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
|
|
|
205
200
|
selectedSelectableItems.length === selectableItems.length;
|
|
206
201
|
const someSelectableItemsSelected = selectedSelectableItems.length > 0 && !allSelectableItemsSelected;
|
|
207
202
|
const selectedDisplayIndex = displayItems.findIndex((item) => {
|
|
208
|
-
if (item._isGroupHeader || item._isAddNew)
|
|
203
|
+
if (item._isGroupHeader || item._isAddNew || item._isLoadingMore) {
|
|
209
204
|
return false;
|
|
205
|
+
}
|
|
210
206
|
return isItemSelected(item);
|
|
211
207
|
});
|
|
212
208
|
const selectedDisplayKey = selected === null || selected === void 0 ? void 0 : selected.map(getItemKey).join("|");
|
|
213
|
-
const isLoading =
|
|
209
|
+
const isLoading = loading;
|
|
214
210
|
const handleOnScroll = useCallback((event) => {
|
|
215
211
|
const scrollTolerance = 15;
|
|
216
212
|
onScroll === null || onScroll === void 0 ? void 0 : onScroll(event);
|
|
@@ -220,9 +216,8 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
|
|
|
220
216
|
}
|
|
221
217
|
if (scrollHeight - scrollTop <= clientHeight + scrollTolerance) {
|
|
222
218
|
onScrollToBottom === null || onScrollToBottom === void 0 ? void 0 : onScrollToBottom(event);
|
|
223
|
-
debouncedFetchNextPage();
|
|
224
219
|
}
|
|
225
|
-
}, [
|
|
220
|
+
}, [onScroll, onScrollToBottom, onScrollToTop]);
|
|
226
221
|
const handleToggleSelectAll = () => {
|
|
227
222
|
if (selectableItems.length === 0)
|
|
228
223
|
return;
|
|
@@ -249,12 +244,12 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
|
|
|
249
244
|
const estimatedDynamicItemHeight = itemHeight + 16;
|
|
250
245
|
const itemCount = (displayItems === null || displayItems === void 0 ? void 0 : displayItems.length) || 0;
|
|
251
246
|
const displayItemsKey = displayItems
|
|
252
|
-
.map((item) => `${item.value}:${item.label}:${item._isGroupHeader ? "g" : "i"}`)
|
|
247
|
+
.map((item) => `${item.value}:${item.label}:${item._isGroupHeader ? "g" : item._isLoadingMore ? "l" : "i"}`)
|
|
253
248
|
.join("|");
|
|
254
249
|
const getDynamicItemSize = (index) => {
|
|
255
|
-
var _a;
|
|
250
|
+
var _a, _b;
|
|
256
251
|
return itemSizeMap.current[index] ||
|
|
257
|
-
(((_a = displayItems[index]) === null || _a === void 0 ? void 0 : _a._isGroupHeader)
|
|
252
|
+
(((_a = displayItems[index]) === null || _a === void 0 ? void 0 : _a._isGroupHeader) || ((_b = displayItems[index]) === null || _b === void 0 ? void 0 : _b._isLoadingMore)
|
|
258
253
|
? itemHeight
|
|
259
254
|
: estimatedDynamicItemHeight);
|
|
260
255
|
};
|
|
@@ -271,32 +266,8 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
|
|
|
271
266
|
DROPDOWN_CONTENT_VERTICAL_PADDING -
|
|
272
267
|
searchHeight -
|
|
273
268
|
selectAllHeight);
|
|
274
|
-
const
|
|
275
|
-
const height = Math.min(estimatedHeight, availableHeight, maxListHeight);
|
|
269
|
+
const height = Math.min(estimatedHeight, maxListHeight);
|
|
276
270
|
const width = "100%";
|
|
277
|
-
useLayoutEffect(() => {
|
|
278
|
-
const target = targetElm.current;
|
|
279
|
-
if (!target)
|
|
280
|
-
return;
|
|
281
|
-
const updateDimensions = () => {
|
|
282
|
-
const nextDimensions = target.getBoundingClientRect();
|
|
283
|
-
setViewPortDimensions((currentDimensions) => {
|
|
284
|
-
const width = Math.ceil(nextDimensions.width);
|
|
285
|
-
const height = Math.floor(nextDimensions.height);
|
|
286
|
-
if (currentDimensions.width === width &&
|
|
287
|
-
currentDimensions.height === height) {
|
|
288
|
-
return currentDimensions;
|
|
289
|
-
}
|
|
290
|
-
return { width, height };
|
|
291
|
-
});
|
|
292
|
-
};
|
|
293
|
-
updateDimensions();
|
|
294
|
-
if (typeof ResizeObserver === "undefined")
|
|
295
|
-
return;
|
|
296
|
-
const observer = new ResizeObserver(updateDimensions);
|
|
297
|
-
observer.observe(target);
|
|
298
|
-
return () => observer.disconnect();
|
|
299
|
-
}, [displayItemsKey, isLoading]);
|
|
300
271
|
const setItemSize = useCallback((index, measuredSize) => {
|
|
301
272
|
var _a;
|
|
302
273
|
if (itemSizeMap.current[index] === measuredSize)
|
|
@@ -342,6 +313,9 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
|
|
|
342
313
|
if (item._isGroupHeader) {
|
|
343
314
|
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));
|
|
344
315
|
}
|
|
316
|
+
if (item._isLoadingMore) {
|
|
317
|
+
return (_jsxs(LoadingMoreRow, { "$size": size, style: style, children: [_jsx(Loader, { size: 14 }), _jsx("span", { children: "Loading more..." })] }, "__loading_more__"));
|
|
318
|
+
}
|
|
345
319
|
if (item._isAddNew) {
|
|
346
320
|
return (_jsx(MenuItem, { className: "MenuItem", size: size, leftSection: _jsx(Plus, { size: 14 }), onClick: (e) => {
|
|
347
321
|
e.preventDefault();
|
|
@@ -370,7 +344,7 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
|
|
|
370
344
|
handleSearch(e);
|
|
371
345
|
}
|
|
372
346
|
onSearch === null || onSearch === void 0 ? void 0 : onSearch(e.target.value);
|
|
373
|
-
} })), multiselect && enableSelectAll && selectableItems.length > 0 && (_jsx(MenuItem, { className: "MenuItem", size: size, leftSection: _jsx(CheckBox, { value: allSelectableItemsSelected, partialCheck: someSelectableItemsSelected, size: size, onChange: handleToggleSelectAll }), onClick: (e) => {
|
|
347
|
+
} })), multiselect && enableSelectAll && selectableItems.length > 0 && (_jsx(MenuItem, { className: "MenuItem", size: size, multiselect: true, leftSection: _jsx(CheckBox, { value: allSelectableItemsSelected, partialCheck: someSelectableItemsSelected, size: size, onChange: handleToggleSelectAll }), onClick: (e) => {
|
|
374
348
|
e.preventDefault();
|
|
375
349
|
e.stopPropagation();
|
|
376
350
|
handleToggleSelectAll();
|
|
@@ -382,7 +356,7 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
|
|
|
382
356
|
alignItems: "center",
|
|
383
357
|
height: "100%",
|
|
384
358
|
padding: "10px 0",
|
|
385
|
-
}, children: [_jsx("div", { style: { fontSize: `${sizeTokens.supportingFontSize}px` }, children: "Loading..." }), _jsx(Loader, {})] })), !isLoading && (_jsx(ListViewPort, {
|
|
359
|
+
}, children: [_jsx("div", { style: { fontSize: `${sizeTokens.supportingFontSize}px` }, children: "Loading..." }), _jsx(Loader, {})] })), !isLoading && (_jsx(ListViewPort, { children: dynamicListEnabled ? (_jsx(VariableSizeList, { ref: variableListRef, itemData: displayItems, overscanCount: overscanCount, height: height, width: width, itemCount: itemCount, itemSize: getDynamicItemSize, outerElementType: ListScroller, outerRef: listElm, children: ({ data, index, style }) => {
|
|
386
360
|
const item = data === null || data === void 0 ? void 0 : data[index];
|
|
387
361
|
if (!item)
|
|
388
362
|
return null;
|
|
@@ -3,7 +3,6 @@ import { Size, Variant } from "../core";
|
|
|
3
3
|
import Input from "../Input";
|
|
4
4
|
import { ButtonProps } from "../Button";
|
|
5
5
|
import { StyledContent } from "./components";
|
|
6
|
-
import { InfiniteData, UseInfiniteQueryOptions } from "@tanstack/react-query";
|
|
7
6
|
export type DropDownItem = {
|
|
8
7
|
toLowerCase?: () => string;
|
|
9
8
|
label: string;
|
|
@@ -49,20 +48,12 @@ export type DropDownMenuProps = {
|
|
|
49
48
|
dynamicOptionHeight?: boolean;
|
|
50
49
|
onAddNew?: (value: string) => void;
|
|
51
50
|
loading?: boolean;
|
|
51
|
+
loadingMore?: boolean;
|
|
52
52
|
arrow?: boolean;
|
|
53
53
|
dropDownProps?: ComponentPropsWithoutRef<typeof StyledContent>;
|
|
54
54
|
buttonRender?: (props: any) => ReactElement;
|
|
55
55
|
buttonProps?: ButtonProps;
|
|
56
56
|
disabled?: boolean;
|
|
57
|
-
query?: Omit<UseInfiniteQueryOptions, "select" | "queryKey" | "queryFn" | "getNextPageParam" | "initialPageParam"> & {
|
|
58
|
-
select: (data: InfiniteData<unknown>) => DropDownItem[];
|
|
59
|
-
queryKey: (args: {
|
|
60
|
-
search?: string;
|
|
61
|
-
}) => UseInfiniteQueryOptions["queryKey"];
|
|
62
|
-
queryFn: UseInfiniteQueryOptions["queryFn"];
|
|
63
|
-
getNextPageParam: UseInfiniteQueryOptions["getNextPageParam"];
|
|
64
|
-
initialPageParam: UseInfiniteQueryOptions["initialPageParam"];
|
|
65
|
-
};
|
|
66
57
|
};
|
|
67
58
|
export type MenuProps = {
|
|
68
59
|
label?: any;
|
|
@@ -171,7 +171,7 @@ const resolveViewerType = (file) => {
|
|
|
171
171
|
}
|
|
172
172
|
return ViewerTypes.Code;
|
|
173
173
|
};
|
|
174
|
-
export const FileViewer = ({ file, open, isPending, onClose }) => {
|
|
174
|
+
export const FileViewer = ({ file, open, isPending, onClose, onDownload }) => {
|
|
175
175
|
const [zoomFactor, setZoomFactor] = useState(1);
|
|
176
176
|
const [rotation, setRotation] = useState(0);
|
|
177
177
|
useEffect(() => {
|
|
@@ -194,7 +194,7 @@ export const FileViewer = ({ file, open, isPending, onClose }) => {
|
|
|
194
194
|
return (_jsx(FloatingPortal, { preserveTabOrder: true, children: _jsxs(StyledContainer, { className: "mfui-FileViewer", children: [_jsxs(StyledMenu, { className: "FileViewer-menu", children: [_jsx(Button, { variant: "text", onClick: () => {
|
|
195
195
|
onClose === null || onClose === void 0 ? void 0 : onClose();
|
|
196
196
|
resetViewerState();
|
|
197
|
-
}, children: _jsx(XIcon, { size: 18 }) }), _jsx("div", { children: file.name }), _jsxs(StyledActionsMenu, { children: [ZoomableViewerTypes.includes(viewerType) && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "text", disabled: !file.url, "aria-label": "Zoom in", title: "Zoom in", onClick: () => setZoomFactor((prev) => prev * 1.1), children: _jsx(ZoomInIcon, { size: 18 }) }), _jsx(Button, { variant: "text", disabled: !file.url, "aria-label": "Zoom out", title: "Zoom out", onClick: () => setZoomFactor((prev) => prev * 0.9), children: _jsx(ZoomOutIcon, { size: 18 }) })] })), RotatableViewerTypes.includes(viewerType) && (_jsx(Button, { variant: "text", disabled: !file.url, "aria-label": "Rotate image", title: "Rotate image", onClick: () => setRotation((prev) => (prev + 90) % 360), children: _jsx(RotateCwIcon, { size: 18 }) })), _jsx("a", { href: file.url, download: file.name, style: { pointerEvents: !file.url ? "none" : "auto" }, children: _jsx(Button, { variant: "text", disabled: !file.url, children: _jsx(DownloadIcon, { size: 18 }) }) })] })] }), file.url ? (_jsxs(StyledInnerContainer, { onClick: handleBackgroundClick, "data-type": viewerType, children: [viewerType === ViewerTypes.PDF && (_jsx(PdfViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Image && (_jsx(ImageViewer, { file: file, zoomFactor: zoomFactor, rotation: rotation, isPending: isPending })), viewerType === ViewerTypes.Video && (_jsx(VideoViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Audio && (_jsx(VideoViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Office && (_jsx(OfficeViewer, { file: file, isPending: isPending })), viewerType === ViewerTypes.Text && (_jsx(CodeViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Code && (_jsx(CodeViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending }))] })) : (_jsx(StyledInnerContainer, { children: _jsxs("div", { style: {
|
|
197
|
+
}, children: _jsx(XIcon, { size: 18 }) }), _jsx("div", { children: file.name }), _jsxs(StyledActionsMenu, { children: [ZoomableViewerTypes.includes(viewerType) && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "text", disabled: !file.url, "aria-label": "Zoom in", title: "Zoom in", onClick: () => setZoomFactor((prev) => prev * 1.1), children: _jsx(ZoomInIcon, { size: 18 }) }), _jsx(Button, { variant: "text", disabled: !file.url, "aria-label": "Zoom out", title: "Zoom out", onClick: () => setZoomFactor((prev) => prev * 0.9), children: _jsx(ZoomOutIcon, { size: 18 }) })] })), RotatableViewerTypes.includes(viewerType) && (_jsx(Button, { variant: "text", disabled: !file.url, "aria-label": "Rotate image", title: "Rotate image", onClick: () => setRotation((prev) => (prev + 90) % 360), children: _jsx(RotateCwIcon, { size: 18 }) })), _jsx("a", { href: file.url, download: file.name, style: { pointerEvents: !file.url ? "none" : "auto" }, onClick: () => onDownload === null || onDownload === void 0 ? void 0 : onDownload(file), children: _jsx(Button, { variant: "text", disabled: !file.url, children: _jsx(DownloadIcon, { size: 18 }) }) })] })] }), file.url ? (_jsxs(StyledInnerContainer, { onClick: handleBackgroundClick, "data-type": viewerType, children: [viewerType === ViewerTypes.PDF && (_jsx(PdfViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Image && (_jsx(ImageViewer, { file: file, zoomFactor: zoomFactor, rotation: rotation, isPending: isPending })), viewerType === ViewerTypes.Video && (_jsx(VideoViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Audio && (_jsx(VideoViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Office && (_jsx(OfficeViewer, { file: file, isPending: isPending })), viewerType === ViewerTypes.Text && (_jsx(CodeViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Code && (_jsx(CodeViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending }))] })) : (_jsx(StyledInnerContainer, { children: _jsxs("div", { style: {
|
|
198
198
|
margin: "auto",
|
|
199
199
|
display: "flex",
|
|
200
200
|
gap: "10px",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DropDownItem
|
|
1
|
+
import type { DropDownItem } from "../DropDownMenu";
|
|
2
2
|
import type { SuperDatePickerProps } from "../SuperDatePicker";
|
|
3
3
|
export interface UseQueryFilterProps {
|
|
4
4
|
value?: Query | null;
|
|
@@ -28,6 +28,22 @@ export type Operator = {
|
|
|
28
28
|
};
|
|
29
29
|
export type InputType = "text" | "number" | "date" | "datetime" | "multiselect";
|
|
30
30
|
export type BetweenEditor = "inputs" | "superDatePicker";
|
|
31
|
+
export type FilterOptionsQueryResult = {
|
|
32
|
+
items: DropDownItem[];
|
|
33
|
+
nextPageParam?: unknown;
|
|
34
|
+
};
|
|
35
|
+
export type FilterOptionsQuery = {
|
|
36
|
+
cacheKey: string | ((args: {
|
|
37
|
+
search?: string;
|
|
38
|
+
}) => string);
|
|
39
|
+
initialPageParam?: unknown;
|
|
40
|
+
staleTime?: number;
|
|
41
|
+
loadPage: (args: {
|
|
42
|
+
search?: string;
|
|
43
|
+
pageParam: unknown;
|
|
44
|
+
signal: AbortSignal;
|
|
45
|
+
}) => Promise<FilterOptionsQueryResult>;
|
|
46
|
+
};
|
|
31
47
|
export interface FilterDefinition {
|
|
32
48
|
dataField: string;
|
|
33
49
|
label: string;
|
|
@@ -43,7 +59,7 @@ export interface FilterDefinition {
|
|
|
43
59
|
dropDownOptions?: {
|
|
44
60
|
style?: React.CSSProperties;
|
|
45
61
|
};
|
|
46
|
-
query?:
|
|
62
|
+
query?: FilterOptionsQuery;
|
|
47
63
|
}
|
|
48
64
|
export interface Rule {
|
|
49
65
|
id?: string;
|
|
@@ -1,17 +1,172 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
3
|
import { useTheme } from "styled-components";
|
|
4
|
+
import { useDebouncedCallback } from "use-debounce";
|
|
3
5
|
import { DropDownMenu } from "../../DropDownMenu";
|
|
4
|
-
import { QUERY_FILTER_SELECT_VALUE_LABEL
|
|
6
|
+
import { QUERY_FILTER_SELECT_VALUE_LABEL } from "../QueryFilter.constants";
|
|
7
|
+
const DEFAULT_FILTER_OPTIONS_STALE_TIME = 5 * 60 * 1000;
|
|
8
|
+
const DEFAULT_INITIAL_PAGE_PARAM = 1;
|
|
9
|
+
const filterOptionsCache = new Map();
|
|
10
|
+
const filterOptionsRequestCache = new Map();
|
|
11
|
+
const getItemKey = (item) => item && typeof item === "object" && "value" in item ? item.value : item;
|
|
12
|
+
const mergeDropDownItems = (...itemLists) => {
|
|
13
|
+
const seen = new Set();
|
|
14
|
+
const merged = [];
|
|
15
|
+
for (const item of itemLists.flat()) {
|
|
16
|
+
const key = getItemKey(item);
|
|
17
|
+
if (seen.has(key))
|
|
18
|
+
continue;
|
|
19
|
+
seen.add(key);
|
|
20
|
+
merged.push(item);
|
|
21
|
+
}
|
|
22
|
+
return merged;
|
|
23
|
+
};
|
|
24
|
+
const getCacheKey = (query, search) => {
|
|
25
|
+
if (typeof query.cacheKey === "function") {
|
|
26
|
+
return query.cacheKey({ search });
|
|
27
|
+
}
|
|
28
|
+
return `${query.cacheKey}:${search || ""}`;
|
|
29
|
+
};
|
|
30
|
+
const hasNextPageParam = (pageParam) => pageParam !== undefined && pageParam !== null;
|
|
31
|
+
const getPageRequestKey = (cacheKey, pageParam) => {
|
|
32
|
+
try {
|
|
33
|
+
return `${cacheKey}:${JSON.stringify(pageParam)}`;
|
|
34
|
+
}
|
|
35
|
+
catch (_a) {
|
|
36
|
+
return `${cacheKey}:${String(pageParam)}`;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const loadFilterOptionsPage = (query, search, pageParam) => {
|
|
40
|
+
const cacheKey = getCacheKey(query, search);
|
|
41
|
+
const requestKey = getPageRequestKey(cacheKey, pageParam);
|
|
42
|
+
const pendingRequest = filterOptionsRequestCache.get(requestKey);
|
|
43
|
+
if (pendingRequest) {
|
|
44
|
+
return pendingRequest;
|
|
45
|
+
}
|
|
46
|
+
const abortController = new AbortController();
|
|
47
|
+
const request = query
|
|
48
|
+
.loadPage({
|
|
49
|
+
search,
|
|
50
|
+
pageParam,
|
|
51
|
+
signal: abortController.signal,
|
|
52
|
+
})
|
|
53
|
+
.finally(() => {
|
|
54
|
+
filterOptionsRequestCache.delete(requestKey);
|
|
55
|
+
});
|
|
56
|
+
filterOptionsRequestCache.set(requestKey, request);
|
|
57
|
+
return request;
|
|
58
|
+
};
|
|
59
|
+
const useFilterOptionsQuery = (query) => {
|
|
60
|
+
const [search, setSearch] = useState("");
|
|
61
|
+
const [items, setItems] = useState([]);
|
|
62
|
+
const [nextPageParam, setNextPageParam] = useState();
|
|
63
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
64
|
+
const [isFetchingNextPage, setIsFetchingNextPage] = useState(false);
|
|
65
|
+
const initialRequestRef = useRef(0);
|
|
66
|
+
const nextPageRequestRef = useRef(0);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
var _a, _b;
|
|
69
|
+
if (!query) {
|
|
70
|
+
setItems([]);
|
|
71
|
+
setNextPageParam(undefined);
|
|
72
|
+
setIsLoading(false);
|
|
73
|
+
setIsFetchingNextPage(false);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
let isCurrent = true;
|
|
77
|
+
const requestId = initialRequestRef.current + 1;
|
|
78
|
+
initialRequestRef.current = requestId;
|
|
79
|
+
const cacheKey = getCacheKey(query, search);
|
|
80
|
+
const staleTime = (_a = query.staleTime) !== null && _a !== void 0 ? _a : DEFAULT_FILTER_OPTIONS_STALE_TIME;
|
|
81
|
+
const cached = filterOptionsCache.get(cacheKey);
|
|
82
|
+
if (cached && Date.now() - cached.timestamp < staleTime) {
|
|
83
|
+
setItems(cached.items);
|
|
84
|
+
setNextPageParam(cached.nextPageParam);
|
|
85
|
+
setIsLoading(false);
|
|
86
|
+
setIsFetchingNextPage(false);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
setIsLoading(true);
|
|
90
|
+
setIsFetchingNextPage(false);
|
|
91
|
+
setItems([]);
|
|
92
|
+
setNextPageParam(undefined);
|
|
93
|
+
loadFilterOptionsPage(query, search, (_b = query.initialPageParam) !== null && _b !== void 0 ? _b : DEFAULT_INITIAL_PAGE_PARAM)
|
|
94
|
+
.then((result) => {
|
|
95
|
+
if (!isCurrent || initialRequestRef.current !== requestId)
|
|
96
|
+
return;
|
|
97
|
+
setItems(result.items);
|
|
98
|
+
setNextPageParam(result.nextPageParam);
|
|
99
|
+
filterOptionsCache.set(cacheKey, Object.assign(Object.assign({}, result), { timestamp: Date.now() }));
|
|
100
|
+
})
|
|
101
|
+
.catch((error) => {
|
|
102
|
+
if (!isCurrent || initialRequestRef.current !== requestId)
|
|
103
|
+
return;
|
|
104
|
+
console.error("Failed to load filter options", error);
|
|
105
|
+
})
|
|
106
|
+
.finally(() => {
|
|
107
|
+
if (!isCurrent || initialRequestRef.current !== requestId)
|
|
108
|
+
return;
|
|
109
|
+
setIsLoading(false);
|
|
110
|
+
});
|
|
111
|
+
return () => {
|
|
112
|
+
isCurrent = false;
|
|
113
|
+
};
|
|
114
|
+
}, [query, search]);
|
|
115
|
+
const loadNextPage = useCallback(() => {
|
|
116
|
+
if (!query || isLoading || isFetchingNextPage)
|
|
117
|
+
return;
|
|
118
|
+
if (!hasNextPageParam(nextPageParam))
|
|
119
|
+
return;
|
|
120
|
+
const requestId = nextPageRequestRef.current + 1;
|
|
121
|
+
nextPageRequestRef.current = requestId;
|
|
122
|
+
const cacheKey = getCacheKey(query, search);
|
|
123
|
+
setIsFetchingNextPage(true);
|
|
124
|
+
loadFilterOptionsPage(query, search, nextPageParam)
|
|
125
|
+
.then((result) => {
|
|
126
|
+
if (nextPageRequestRef.current !== requestId)
|
|
127
|
+
return;
|
|
128
|
+
setItems((currentItems) => {
|
|
129
|
+
const nextItems = mergeDropDownItems(currentItems, result.items);
|
|
130
|
+
filterOptionsCache.set(cacheKey, {
|
|
131
|
+
items: nextItems,
|
|
132
|
+
nextPageParam: result.nextPageParam,
|
|
133
|
+
timestamp: Date.now(),
|
|
134
|
+
});
|
|
135
|
+
return nextItems;
|
|
136
|
+
});
|
|
137
|
+
setNextPageParam(result.nextPageParam);
|
|
138
|
+
})
|
|
139
|
+
.catch((error) => {
|
|
140
|
+
if (nextPageRequestRef.current !== requestId)
|
|
141
|
+
return;
|
|
142
|
+
console.error("Failed to load more filter options", error);
|
|
143
|
+
})
|
|
144
|
+
.finally(() => {
|
|
145
|
+
if (nextPageRequestRef.current !== requestId)
|
|
146
|
+
return;
|
|
147
|
+
setIsFetchingNextPage(false);
|
|
148
|
+
});
|
|
149
|
+
}, [isFetchingNextPage, isLoading, nextPageParam, query, search]);
|
|
150
|
+
return {
|
|
151
|
+
items,
|
|
152
|
+
isLoading,
|
|
153
|
+
isFetchingNextPage,
|
|
154
|
+
loadNextPage,
|
|
155
|
+
setSearch,
|
|
156
|
+
};
|
|
157
|
+
};
|
|
5
158
|
export const MultiSelectEditor = ({ rule, filterDef, onChange }) => {
|
|
6
159
|
var _a, _b;
|
|
7
160
|
const theme = useTheme();
|
|
161
|
+
const optionsQuery = useFilterOptionsQuery(filterDef === null || filterDef === void 0 ? void 0 : filterDef.query);
|
|
162
|
+
const handleAsyncSearch = useDebouncedCallback((value) => {
|
|
163
|
+
optionsQuery.setSearch(value);
|
|
164
|
+
}, 150);
|
|
8
165
|
const handleChange = (selected, diff) => {
|
|
9
166
|
onChange === null || onChange === void 0 ? void 0 : onChange(selected, diff);
|
|
10
167
|
};
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
...(rule.options || []),
|
|
14
|
-
];
|
|
168
|
+
const dropDownOptions = useMemo(() => mergeDropDownItems((filterDef === null || filterDef === void 0 ? void 0 : filterDef.selectOptions) || [], optionsQuery.items || []), [filterDef === null || filterDef === void 0 ? void 0 : filterDef.selectOptions, optionsQuery.items]);
|
|
169
|
+
const options = useMemo(() => mergeDropDownItems(dropDownOptions, rule.options || []), [dropDownOptions, rule.options]);
|
|
15
170
|
const selected = ((_a = rule.value) === null || _a === void 0 ? void 0 : _a.map((value) => {
|
|
16
171
|
const option = options.find((o) => o.value == value);
|
|
17
172
|
return option || { label: value, value };
|
|
@@ -20,7 +175,7 @@ export const MultiSelectEditor = ({ rule, filterDef, onChange }) => {
|
|
|
20
175
|
if (Array.isArray(rule.value) && rule.value.length > 1) {
|
|
21
176
|
display = `${rule.value.length} ${(filterDef === null || filterDef === void 0 ? void 0 : filterDef.pluralLabel) || "Values"}`;
|
|
22
177
|
}
|
|
23
|
-
return (_jsx(DropDownMenu, { data:
|
|
178
|
+
return (_jsx(DropDownMenu, { data: dropDownOptions, variant: "outlined", multiselect: true, searchable: true, size: "xs", buttonProps: {
|
|
24
179
|
title: QUERY_FILTER_SELECT_VALUE_LABEL,
|
|
25
180
|
variant: "contained",
|
|
26
181
|
size: "xxs",
|
|
@@ -40,5 +195,7 @@ export const MultiSelectEditor = ({ rule, filterDef, onChange }) => {
|
|
|
40
195
|
},
|
|
41
196
|
}, dropDownProps: {
|
|
42
197
|
style: Object.assign({ width: 200, maxWidth: 400 }, (_b = filterDef === null || filterDef === void 0 ? void 0 : filterDef.dropDownOptions) === null || _b === void 0 ? void 0 : _b.style),
|
|
43
|
-
}, value: selected, onChange: handleChange,
|
|
198
|
+
}, loading: optionsQuery.isLoading && dropDownOptions.length === 0, loadingMore: optionsQuery.isFetchingNextPage, value: selected, onChange: handleChange, manualSearch: !!(filterDef === null || filterDef === void 0 ? void 0 : filterDef.query), onSearch: (filterDef === null || filterDef === void 0 ? void 0 : filterDef.query)
|
|
199
|
+
? (value) => handleAsyncSearch(value)
|
|
200
|
+
: undefined, onScrollToBottom: (filterDef === null || filterDef === void 0 ? void 0 : filterDef.query) ? optionsQuery.loadNextPage : undefined, children: display }));
|
|
44
201
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monolith-forensics/monolith-ui",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1-dev.4",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"author": "Matt Danner (Monolith Forensics LLC)",
|
|
@@ -85,12 +85,10 @@
|
|
|
85
85
|
"use-debounce": "^10.0.0"
|
|
86
86
|
},
|
|
87
87
|
"peerDependencies": {
|
|
88
|
-
"@tanstack/react-query": "^5.59.16",
|
|
89
88
|
"react": "^18.3.1",
|
|
90
89
|
"react-dom": "^18.3.1"
|
|
91
90
|
},
|
|
92
91
|
"devDependencies": {
|
|
93
|
-
"@tanstack/react-query": "5.59.16",
|
|
94
92
|
"@types/d3-scale": "^4.0.9",
|
|
95
93
|
"@types/d3-shape": "^3.1.8",
|
|
96
94
|
"@types/overlayscrollbars": "^1.12.5",
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { Operator } from "./types";
|
|
2
|
-
export declare const Operators: {
|
|
3
|
-
Equals: {
|
|
4
|
-
value: string;
|
|
5
|
-
label: string;
|
|
6
|
-
};
|
|
7
|
-
NotEquals: {
|
|
8
|
-
value: string;
|
|
9
|
-
label: string;
|
|
10
|
-
};
|
|
11
|
-
LessThan: {
|
|
12
|
-
value: string;
|
|
13
|
-
label: string;
|
|
14
|
-
};
|
|
15
|
-
GreaterThan: {
|
|
16
|
-
value: string;
|
|
17
|
-
label: string;
|
|
18
|
-
};
|
|
19
|
-
LessThanOrEqual: {
|
|
20
|
-
value: string;
|
|
21
|
-
label: string;
|
|
22
|
-
};
|
|
23
|
-
GreaterThanOrEqual: {
|
|
24
|
-
value: string;
|
|
25
|
-
label: string;
|
|
26
|
-
};
|
|
27
|
-
Contains: {
|
|
28
|
-
value: string;
|
|
29
|
-
label: string;
|
|
30
|
-
};
|
|
31
|
-
BeginsWith: {
|
|
32
|
-
value: string;
|
|
33
|
-
label: string;
|
|
34
|
-
};
|
|
35
|
-
EndsWith: {
|
|
36
|
-
value: string;
|
|
37
|
-
label: string;
|
|
38
|
-
};
|
|
39
|
-
DoesNotContain: {
|
|
40
|
-
value: string;
|
|
41
|
-
label: string;
|
|
42
|
-
};
|
|
43
|
-
DoesNotBeginWith: {
|
|
44
|
-
value: string;
|
|
45
|
-
label: string;
|
|
46
|
-
};
|
|
47
|
-
DoesNotEndWith: {
|
|
48
|
-
value: string;
|
|
49
|
-
label: string;
|
|
50
|
-
};
|
|
51
|
-
IsEmpty: {
|
|
52
|
-
value: string;
|
|
53
|
-
label: string;
|
|
54
|
-
};
|
|
55
|
-
IsNotEmpty: {
|
|
56
|
-
value: string;
|
|
57
|
-
label: string;
|
|
58
|
-
};
|
|
59
|
-
In: {
|
|
60
|
-
value: string;
|
|
61
|
-
label: string;
|
|
62
|
-
};
|
|
63
|
-
NIn: {
|
|
64
|
-
value: string;
|
|
65
|
-
label: string;
|
|
66
|
-
};
|
|
67
|
-
Between: {
|
|
68
|
-
value: string;
|
|
69
|
-
label: string;
|
|
70
|
-
};
|
|
71
|
-
NotBetween: {
|
|
72
|
-
value: string;
|
|
73
|
-
label: string;
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
export declare const DefaultOperators: Operator[];
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export const Operators = {
|
|
2
|
-
Equals: { value: "=", label: "is" },
|
|
3
|
-
NotEquals: { value: "!=", label: "is not" },
|
|
4
|
-
LessThan: { value: "<", label: "less than" },
|
|
5
|
-
GreaterThan: { value: ">", label: "greater than" },
|
|
6
|
-
LessThanOrEqual: { value: "<=", label: "less than or equal" },
|
|
7
|
-
GreaterThanOrEqual: { value: ">=", label: "greater than or equal" },
|
|
8
|
-
Contains: { value: "contains", label: "contains" },
|
|
9
|
-
BeginsWith: { value: "beginsWith", label: "begins with" },
|
|
10
|
-
EndsWith: { value: "endsWith", label: "ends with" },
|
|
11
|
-
DoesNotContain: { value: "doesNotContain", label: "does not contain" },
|
|
12
|
-
DoesNotBeginWith: { value: "doesNotBeginWith", label: "does not begin with" },
|
|
13
|
-
DoesNotEndWith: { value: "doesNotEndWith", label: "does not end with" },
|
|
14
|
-
IsEmpty: { value: "isEmpty", label: "is empty" },
|
|
15
|
-
IsNotEmpty: { value: "isNotEmpty", label: "is not empty" },
|
|
16
|
-
In: { value: "in", label: "is any of" },
|
|
17
|
-
NIn: { value: "nin", label: "is none of" },
|
|
18
|
-
Between: { value: "between", label: "between" },
|
|
19
|
-
NotBetween: { value: "notBetween", label: "not between" },
|
|
20
|
-
};
|
|
21
|
-
export const DefaultOperators = Object.values(Operators);
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { DropDownItem, DropDownMenuProps } from "../DropDownMenu";
|
|
2
|
-
export interface UseQueryFilterProps {
|
|
3
|
-
defaultFilter?: Query | null;
|
|
4
|
-
/**
|
|
5
|
-
* Filter definitions for the available fields. Pass `undefined` while the
|
|
6
|
-
* definitions are still loading (e.g. async fetch in flight) — any rules
|
|
7
|
-
* already in state will render nothing until definitions resolve. An empty
|
|
8
|
-
* array means "loaded, no definitions": every rule will render as an
|
|
9
|
-
* orphan chip and `onUnknownField` will fire for each.
|
|
10
|
-
*/
|
|
11
|
-
filterDefinitions: FilterDefinition[] | undefined;
|
|
12
|
-
showCombinator?: boolean;
|
|
13
|
-
onFilterChange?: (filter: any) => void;
|
|
14
|
-
onUnknownField?: (rule: Rule) => void;
|
|
15
|
-
}
|
|
16
|
-
export type QueryFilterType = {
|
|
17
|
-
filter: Query;
|
|
18
|
-
filterDefinitions: FilterDefinition[] | undefined;
|
|
19
|
-
showCombinator?: boolean;
|
|
20
|
-
addRule: (rule: Rule) => void;
|
|
21
|
-
/**
|
|
22
|
-
* Remove a rule by `id` (preferred) or by passing the `Rule` object. The
|
|
23
|
-
* object form falls back to reference equality when `rule.id` is missing,
|
|
24
|
-
* so chips for un-normalized orphan rules can still delete themselves.
|
|
25
|
-
*/
|
|
26
|
-
removeRule: (target: string | Rule) => void;
|
|
27
|
-
updateRule: (rule: Rule) => void;
|
|
28
|
-
updateRootCombinator: (combinator: Combinator) => void;
|
|
29
|
-
onUnknownField?: (rule: Rule) => void;
|
|
30
|
-
};
|
|
31
|
-
export type UseQueryFilter = (args: UseQueryFilterProps) => QueryFilterType;
|
|
32
|
-
export type Combinator = "and" | "or";
|
|
33
|
-
export type Operator = {
|
|
34
|
-
label: string;
|
|
35
|
-
value: string;
|
|
36
|
-
};
|
|
37
|
-
export type InputType = "text" | "number" | "date" | "datetime" | "multiselect";
|
|
38
|
-
export interface FilterDefinition {
|
|
39
|
-
dataField: string;
|
|
40
|
-
label: string;
|
|
41
|
-
pluralLabel?: string;
|
|
42
|
-
operators?: Operator[];
|
|
43
|
-
inputType?: InputType;
|
|
44
|
-
resolution?: "day" | "second" | "millisecond";
|
|
45
|
-
isoString?: boolean;
|
|
46
|
-
placeholder?: string;
|
|
47
|
-
selectOptions?: DropDownItem[];
|
|
48
|
-
dropDownOptions?: {
|
|
49
|
-
style?: React.CSSProperties;
|
|
50
|
-
};
|
|
51
|
-
query?: DropDownMenuProps["query"];
|
|
52
|
-
}
|
|
53
|
-
export interface Rule {
|
|
54
|
-
id?: string;
|
|
55
|
-
dataField: string;
|
|
56
|
-
value?: string[];
|
|
57
|
-
options?: DropDownItem[];
|
|
58
|
-
operator: Operator;
|
|
59
|
-
label: string;
|
|
60
|
-
}
|
|
61
|
-
export interface RuleGroup {
|
|
62
|
-
rules: Rule[];
|
|
63
|
-
combinator: Combinator;
|
|
64
|
-
}
|
|
65
|
-
export interface Query extends RuleGroup {
|
|
66
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { Extension, isNodeSelection, isTextSelection, posToDOMRect, } from "@tiptap/core";
|
|
2
|
-
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
3
|
-
import { ReactRenderer } from "@tiptap/react";
|
|
4
|
-
import BubbleMenuComponent from "../Components/BubbleMenu";
|
|
5
|
-
class Menu {
|
|
6
|
-
constructor({ view, editor, customMenuItems, }) {
|
|
7
|
-
this.mousedownHandler = (event) => {
|
|
8
|
-
this.preventShow = true;
|
|
9
|
-
};
|
|
10
|
-
this.mouseUpHandler = (event) => {
|
|
11
|
-
this.preventShow = false;
|
|
12
|
-
this.update(this.editor.view);
|
|
13
|
-
};
|
|
14
|
-
this.focusHandler = () => {
|
|
15
|
-
// this.editor.commands.setTextSelection({ from: 0, to: 0 });
|
|
16
|
-
// we use `setTimeout` to make sure `selection` is already updated
|
|
17
|
-
setTimeout(() => this.update(this.editor.view));
|
|
18
|
-
};
|
|
19
|
-
this.blurHandler = ({ event }) => {
|
|
20
|
-
var _a;
|
|
21
|
-
if (this.preventShow) {
|
|
22
|
-
this.preventShow = false;
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
if ((event === null || event === void 0 ? void 0 : event.relatedTarget) &&
|
|
26
|
-
((_a = this.floating) === null || _a === void 0 ? void 0 : _a.contains(event === null || event === void 0 ? void 0 : event.relatedTarget))) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
// clear text selection
|
|
30
|
-
// this.editor.commands.setTextSelection({ from: 0, to: 0 });
|
|
31
|
-
this.hide();
|
|
32
|
-
};
|
|
33
|
-
this.editor = editor;
|
|
34
|
-
this.view = view;
|
|
35
|
-
this.rect = null;
|
|
36
|
-
this.preventShow = false;
|
|
37
|
-
this.floating = null;
|
|
38
|
-
this.isOpen = false;
|
|
39
|
-
// create and mount react component
|
|
40
|
-
if (!this.component) {
|
|
41
|
-
this.component = new ReactRenderer(BubbleMenuComponent, {
|
|
42
|
-
props: {
|
|
43
|
-
editor: this.editor,
|
|
44
|
-
open: false,
|
|
45
|
-
onOpen: (ref) => {
|
|
46
|
-
this.floating = ref;
|
|
47
|
-
},
|
|
48
|
-
customMenuItems,
|
|
49
|
-
},
|
|
50
|
-
editor: this.editor,
|
|
51
|
-
});
|
|
52
|
-
document.body.appendChild(this.component.element);
|
|
53
|
-
}
|
|
54
|
-
// don't show the bubble during selection of text
|
|
55
|
-
this.view.dom.addEventListener("mousedown", this.mousedownHandler, {
|
|
56
|
-
capture: true,
|
|
57
|
-
});
|
|
58
|
-
this.view.dom.addEventListener("mouseup", this.mouseUpHandler);
|
|
59
|
-
this.editor.on("blur", this.blurHandler);
|
|
60
|
-
this.editor.on("focus", this.focusHandler);
|
|
61
|
-
}
|
|
62
|
-
update(view, oldState) {
|
|
63
|
-
var _a;
|
|
64
|
-
const { state, composing } = view;
|
|
65
|
-
const { doc, selection } = state;
|
|
66
|
-
const { empty, ranges } = selection;
|
|
67
|
-
const from = Math.min(...ranges.map((range) => range.$from.pos));
|
|
68
|
-
const to = Math.max(...ranges.map((range) => range.$to.pos));
|
|
69
|
-
const selectionChanged = !(oldState === null || oldState === void 0 ? void 0 : oldState.selection.eq(view.state.selection));
|
|
70
|
-
const docChanged = !(oldState === null || oldState === void 0 ? void 0 : oldState.doc.eq(view.state.doc));
|
|
71
|
-
const isSame = !selectionChanged && !docChanged;
|
|
72
|
-
if (composing || isSame) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
// Sometime check for `empty` is not enough.
|
|
76
|
-
// Doubleclick an empty paragraph returns a node size of 2.
|
|
77
|
-
// So we check also for an empty text size.
|
|
78
|
-
const isEmptyTextBlock = !doc.textBetween(from, to).length && isTextSelection(state.selection);
|
|
79
|
-
// When clicking on a element inside the bubble menu the editor "blur" event
|
|
80
|
-
// is called and the bubble menu item is focussed. In this case we should
|
|
81
|
-
// consider the menu as part of the editor and keep showing the menu
|
|
82
|
-
const isChildOfMenu = (_a = this === null || this === void 0 ? void 0 : this.floating) === null || _a === void 0 ? void 0 : _a.contains(document.activeElement);
|
|
83
|
-
const hasEditorFocus = view.hasFocus() || isChildOfMenu;
|
|
84
|
-
if (!hasEditorFocus ||
|
|
85
|
-
empty ||
|
|
86
|
-
isEmptyTextBlock ||
|
|
87
|
-
!this.editor.isEditable ||
|
|
88
|
-
this.preventShow) {
|
|
89
|
-
this.hide();
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
// only set position when it is not already open
|
|
93
|
-
// otherwise the menu will jump around when the selection changes or text formatting is applied
|
|
94
|
-
if (!this.isOpen) {
|
|
95
|
-
if (isNodeSelection(state.selection)) {
|
|
96
|
-
let node = view.nodeDOM(from);
|
|
97
|
-
const nodeViewWrapper = node.dataset.nodeViewWrapper
|
|
98
|
-
? node
|
|
99
|
-
: node.querySelector("[data-node-view-wrapper]");
|
|
100
|
-
if (nodeViewWrapper) {
|
|
101
|
-
node = nodeViewWrapper.firstChild;
|
|
102
|
-
}
|
|
103
|
-
if (node) {
|
|
104
|
-
this.rect = node.getBoundingClientRect();
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
this.rect = posToDOMRect(view, from, to);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
this.show();
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
show() {
|
|
115
|
-
if (this.component) {
|
|
116
|
-
this.component.updateProps({ open: true, rect: this.rect });
|
|
117
|
-
this.isOpen = true;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
hide() {
|
|
121
|
-
if (this.component) {
|
|
122
|
-
this.component.updateProps({ open: false, rect: null });
|
|
123
|
-
this.isOpen = false;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
destroy() {
|
|
127
|
-
if (this.component) {
|
|
128
|
-
this.view.dom.removeEventListener("mousedown", this.mousedownHandler);
|
|
129
|
-
this.view.dom.removeEventListener("mouseup", this.mouseUpHandler);
|
|
130
|
-
this.component.destroy();
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
const BubbleMenu = Extension.create({
|
|
135
|
-
name: "bubbleMenu",
|
|
136
|
-
addOptions() {
|
|
137
|
-
return {
|
|
138
|
-
bubbleMenuOptions: {},
|
|
139
|
-
};
|
|
140
|
-
},
|
|
141
|
-
addProseMirrorPlugins() {
|
|
142
|
-
return [
|
|
143
|
-
new Plugin({
|
|
144
|
-
key: new PluginKey("bubbleMenu"),
|
|
145
|
-
view: (view) => {
|
|
146
|
-
var _a;
|
|
147
|
-
return new Menu({
|
|
148
|
-
view,
|
|
149
|
-
editor: this.editor,
|
|
150
|
-
customMenuItems: ((_a = this === null || this === void 0 ? void 0 : this.options) === null || _a === void 0 ? void 0 : _a.customMenuItems) || [],
|
|
151
|
-
});
|
|
152
|
-
},
|
|
153
|
-
}),
|
|
154
|
-
];
|
|
155
|
-
},
|
|
156
|
-
});
|
|
157
|
-
export default BubbleMenu;
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import TableDefaults from "../TableDefaults";
|
|
2
|
-
const enableResizeClass = (dataField) => {
|
|
3
|
-
if (dataField === undefined) {
|
|
4
|
-
return;
|
|
5
|
-
}
|
|
6
|
-
document.querySelectorAll(`.resizer.col-${dataField}`).forEach((resizer) => {
|
|
7
|
-
resizer.classList.add("isResizing");
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
const disableResizeClass = (dataField) => {
|
|
11
|
-
if (dataField === undefined) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
document.querySelectorAll(`.resizer.col-${dataField}`).forEach((resizer) => {
|
|
15
|
-
resizer.classList.remove("isResizing");
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
const resizeHandler = ({ event, columnId, columnProps, onResize, onResizeFinished, }) => {
|
|
19
|
-
let col = event.target
|
|
20
|
-
.parentElement;
|
|
21
|
-
let newColumns = [];
|
|
22
|
-
let x = 0;
|
|
23
|
-
let w = 0;
|
|
24
|
-
const mouseMoveHandler = function (e) {
|
|
25
|
-
const selectedColumn = document.querySelectorAll(`.column-${columnId}`);
|
|
26
|
-
const columnHeaders = document.querySelectorAll(`.mfui-th.column-${columnId}`);
|
|
27
|
-
const dx = e.clientX - x;
|
|
28
|
-
let newWidth = w + dx;
|
|
29
|
-
// Calculate what the minimum width should be
|
|
30
|
-
// min width should be the defined column width or the default min width
|
|
31
|
-
if (columnProps.minWidth === undefined) {
|
|
32
|
-
if (newWidth < TableDefaults.td.minWidth)
|
|
33
|
-
newWidth = TableDefaults.td.minWidth;
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
if (newWidth < columnProps.minWidth)
|
|
37
|
-
newWidth = columnProps.minWidth;
|
|
38
|
-
}
|
|
39
|
-
selectedColumn.forEach((col) => {
|
|
40
|
-
var _a;
|
|
41
|
-
col.style.width = `${newWidth}px`;
|
|
42
|
-
col.style.flex = "0 0 auto";
|
|
43
|
-
// col.style.maxWidth = `${newWidth}px`;
|
|
44
|
-
// col.style.minWidth = `${newWidth}px`;
|
|
45
|
-
newColumns.push({
|
|
46
|
-
dataField: ((_a = col === null || col === void 0 ? void 0 : col.dataset) === null || _a === void 0 ? void 0 : _a.field) || "",
|
|
47
|
-
width: newWidth,
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
newColumns = Array.from(columnHeaders).map((col) => {
|
|
51
|
-
var _a;
|
|
52
|
-
return {
|
|
53
|
-
dataField: ((_a = col === null || col === void 0 ? void 0 : col.dataset) === null || _a === void 0 ? void 0 : _a.field) || "",
|
|
54
|
-
width: newWidth,
|
|
55
|
-
};
|
|
56
|
-
});
|
|
57
|
-
onResize({
|
|
58
|
-
columns: newColumns,
|
|
59
|
-
});
|
|
60
|
-
};
|
|
61
|
-
const mouseUpHandler = function () {
|
|
62
|
-
var _a, _b, _c;
|
|
63
|
-
let newWidth = ((_c = (_b = (_a = document === null || document === void 0 ? void 0 : document.querySelector) === null || _a === void 0 ? void 0 : _a.call(document, `.column-${columnId}`)) === null || _b === void 0 ? void 0 : _b.style) === null || _c === void 0 ? void 0 : _c.width) || null;
|
|
64
|
-
if (newWidth) {
|
|
65
|
-
newWidth = newWidth.replace("px", "");
|
|
66
|
-
}
|
|
67
|
-
disableResizeClass(columnId);
|
|
68
|
-
document.removeEventListener("mousemove", mouseMoveHandler);
|
|
69
|
-
document.removeEventListener("mouseup", mouseUpHandler);
|
|
70
|
-
onResizeFinished === null || onResizeFinished === void 0 ? void 0 : onResizeFinished({
|
|
71
|
-
column: columnProps,
|
|
72
|
-
columnId: columnId,
|
|
73
|
-
targetColumn: document.querySelector(`.column-${columnId}`),
|
|
74
|
-
newWidth,
|
|
75
|
-
});
|
|
76
|
-
};
|
|
77
|
-
x = event.clientX;
|
|
78
|
-
const styles = window.getComputedStyle(col);
|
|
79
|
-
w = parseInt(styles.width, 10);
|
|
80
|
-
document.addEventListener("mousemove", mouseMoveHandler);
|
|
81
|
-
document.addEventListener("mouseup", mouseUpHandler);
|
|
82
|
-
enableResizeClass(columnId);
|
|
83
|
-
};
|
|
84
|
-
export default resizeHandler;
|