@adaptabletools/adaptable 23.0.17 → 23.0.18
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/package.json
CHANGED
|
@@ -25,7 +25,7 @@ export type MultiComboboxProps<T extends ComboboxItemType> = Omit<AdaptableCombo
|
|
|
25
25
|
/**
|
|
26
26
|
* Optional override for the Select All checkbox change handler.
|
|
27
27
|
* When provided, replaces the default behaviour of selecting / deselecting
|
|
28
|
-
*
|
|
28
|
+
* the currently filtered items via `onValueChange`.
|
|
29
29
|
*/
|
|
30
30
|
onSelectAllCheckboxChange?: (checked: boolean) => void;
|
|
31
31
|
renderInputValues?: (items: T[]) => React.ReactNode;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxClear, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxPrimitive, ComboboxSeparator, ComboboxTrigger, ComboboxValue, useComboboxAnchor, RESIZABLE_VIRTUALIZED_LIST_CLASS, } from '../ui/combobox';
|
|
3
|
+
import { Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxClear, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxPrimitive, ComboboxSeparator, ComboboxTrigger, ComboboxValue, useComboboxAnchor, useFilteredItems, RESIZABLE_VIRTUALIZED_LIST_CLASS, } from '../ui/combobox';
|
|
4
4
|
import { cn } from '../../lib/utils';
|
|
5
5
|
import { ChevronDownIcon, Loader2Icon, PlusIcon } from 'lucide-react';
|
|
6
6
|
import { useMemo } from 'react';
|
|
@@ -9,6 +9,55 @@ import { getItemTextLabel, toStringValue, toStringValues, valueToItem, valueToIt
|
|
|
9
9
|
import { VirtualizedList } from './VirtualizedList';
|
|
10
10
|
import { CheckBox } from '../CheckBox';
|
|
11
11
|
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip';
|
|
12
|
+
function getSelectAllCheckboxState(selectedItems, filteredItems) {
|
|
13
|
+
if (filteredItems.length === 0) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
if (selectedItems.length === 0) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
const selectedValues = new Set(selectedItems.map((item) => item.value));
|
|
20
|
+
let selectedVisibleCount = 0;
|
|
21
|
+
let unselectedVisibleCount = 0;
|
|
22
|
+
for (const item of filteredItems) {
|
|
23
|
+
if (selectedValues.has(item.value)) {
|
|
24
|
+
selectedVisibleCount += 1;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
unselectedVisibleCount += 1;
|
|
28
|
+
}
|
|
29
|
+
if (selectedVisibleCount > 0 && unselectedVisibleCount > 0) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (selectedVisibleCount === 0) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
function applySelectAllToSelection(options) {
|
|
39
|
+
const { checked, filteredItems, currentValues, itemByValue } = options;
|
|
40
|
+
const currentSet = new Set(currentValues);
|
|
41
|
+
if (!checked) {
|
|
42
|
+
for (const item of filteredItems) {
|
|
43
|
+
currentSet.delete(item.value);
|
|
44
|
+
}
|
|
45
|
+
const values = currentValues.filter((value) => currentSet.has(value));
|
|
46
|
+
return { values, items: valueToItems(values, itemByValue) ?? [] };
|
|
47
|
+
}
|
|
48
|
+
const visibleSelected = new Set();
|
|
49
|
+
for (const item of filteredItems) {
|
|
50
|
+
if (currentSet.has(item.value)) {
|
|
51
|
+
visibleSelected.add(item.value);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const hiddenValues = currentValues.filter((value) => !visibleSelected.has(value));
|
|
55
|
+
const hiddenItems = valueToItems(hiddenValues, itemByValue) ?? [];
|
|
56
|
+
return {
|
|
57
|
+
values: [...hiddenItems.map((item) => item.value), ...filteredItems.map((item) => item.value)],
|
|
58
|
+
items: [...hiddenItems, ...filteredItems],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
12
61
|
const getContentStyle = ({ maxLabelLength }) => {
|
|
13
62
|
const labelWidth = `${maxLabelLength + 6}ch`;
|
|
14
63
|
return {
|
|
@@ -25,6 +74,7 @@ const getEmptyText = (props) => {
|
|
|
25
74
|
const AdaptableComboboxList = (props) => {
|
|
26
75
|
const virtualizerRef = React.useRef(null);
|
|
27
76
|
const loadingClassName = props.isLoading ? 'twa:opacity-50' : undefined;
|
|
77
|
+
const filteredItems = useFilteredItems();
|
|
28
78
|
const renderItem = (item) => {
|
|
29
79
|
const isUncreatedCreatable = item.creatable && !item.created;
|
|
30
80
|
const label = isUncreatedCreatable ? `Create "${item.label}"` : item.label;
|
|
@@ -42,16 +92,12 @@ const AdaptableComboboxList = (props) => {
|
|
|
42
92
|
return (_jsxs(_Fragment, { children: [props.showSelectAllCheckbox && (_jsx(ComboboxValue, { children: (selectedItems) => {
|
|
43
93
|
const allChecked = props.selectAllCheckboxValue !== undefined
|
|
44
94
|
? props.selectAllCheckboxValue
|
|
45
|
-
: selectedItems
|
|
46
|
-
? true
|
|
47
|
-
: selectedItems.length >= 1
|
|
48
|
-
? null
|
|
49
|
-
: false;
|
|
95
|
+
: getSelectAllCheckboxState(selectedItems, filteredItems);
|
|
50
96
|
return (_jsx(CheckBox, { checked: allChecked, onChange: (checked) => {
|
|
51
|
-
props.onCheckAllChange?.(checked);
|
|
97
|
+
props.onCheckAllChange?.(checked, filteredItems);
|
|
52
98
|
}, onKeyDown: (e) => {
|
|
53
99
|
if (e.key === 'Enter') {
|
|
54
|
-
props.onCheckAllChange?.(
|
|
100
|
+
props.onCheckAllChange?.(allChecked !== true, filteredItems);
|
|
55
101
|
}
|
|
56
102
|
}, onMouseDown: (e) => {
|
|
57
103
|
e.preventDefault();
|
|
@@ -373,15 +419,20 @@ const MultiCombobox_SimpleSearchable = (props) => {
|
|
|
373
419
|
const showClear = props.showClear ?? true;
|
|
374
420
|
const isDisabled = props.disabled;
|
|
375
421
|
const { allItems, itemByValue, maxLabelLength, inputValue, onInputValueChange, onValueChange, value, } = useGetAllItems(props);
|
|
376
|
-
const onCheckAllChange = props.onSelectAllCheckboxChange
|
|
377
|
-
(
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
422
|
+
const onCheckAllChange = props.onSelectAllCheckboxChange != null
|
|
423
|
+
? (checked) => {
|
|
424
|
+
props.onSelectAllCheckboxChange(checked);
|
|
425
|
+
}
|
|
426
|
+
: (checked, filteredItems) => {
|
|
427
|
+
const currentValues = (value ?? []);
|
|
428
|
+
const next = applySelectAllToSelection({
|
|
429
|
+
checked,
|
|
430
|
+
filteredItems,
|
|
431
|
+
currentValues,
|
|
432
|
+
itemByValue,
|
|
433
|
+
});
|
|
434
|
+
onValueChange?.(next.values, next.items);
|
|
435
|
+
};
|
|
385
436
|
const [menuOpen, setMenuOpen] = React.useState(false);
|
|
386
437
|
const onOpenChange = (open) => {
|
|
387
438
|
setMenuOpen(open);
|
|
@@ -401,7 +452,7 @@ const MultiCombobox_SimpleSearchable = (props) => {
|
|
|
401
452
|
: 'twa:flex-1' }), props.searchable === false && selectedItems.length > 0 ? (_jsx("div", { className: "twa:flex-1" })) : null, _jsx("div", { "data-slot": "input-group", role: "group", className: "twa:group/input-group twa:z-10", children: _jsxs(InputGroupAddon, { align: "inline-end", className: "twa:p-0 px twa:gap-0.5", children: [props.isLoading && (_jsx(Loader2Icon, { className: "twa:size-4 twa:text-muted-foreground twa:animate-spin" })), props.showTrigger !== false ? (_jsx(InputGroupButton, { size: "icon-xs", variant: "ghost", render: _jsx(ComboboxTrigger, { className: "twa:min-h-auto!" }), "data-slot": "combobox-toggle", className: cn(`twa:data-pressed:bg-transparent`, shouldKeepTrigger
|
|
402
453
|
? ''
|
|
403
454
|
: 'twa:group-has-data-[slot=combobox-clear]/input-group:hidden'), disabled: isDisabled })) : null, showClear && _jsx(ComboboxClear, { disabled: isDisabled })] }) })] })) : null] }));
|
|
404
|
-
} }) }), _jsx(ComboboxContent, { anchor: anchor, style: getContentStyle({ maxLabelLength }), resizable: props.resizable, children: _jsx(AdaptableComboboxList, { searchable: props.searchable, emptyText: emptyText, renderItemLabel: props.renderItemLabel, showSelectAllCheckbox: props.showSelectAllCheckbox, renderCheckboxIndicator: props.renderCheckboxIndicator ?? true, onCheckAllChange: onCheckAllChange,
|
|
455
|
+
} }) }), _jsx(ComboboxContent, { anchor: anchor, style: getContentStyle({ maxLabelLength }), resizable: props.resizable, children: _jsx(AdaptableComboboxList, { searchable: props.searchable, emptyText: emptyText, renderItemLabel: props.renderItemLabel, showSelectAllCheckbox: props.showSelectAllCheckbox, selectAllCheckboxValue: props.selectAllCheckboxValue, renderCheckboxIndicator: props.renderCheckboxIndicator ?? true, onCheckAllChange: onCheckAllChange, groups: props.groups, virtualized: !!props.virtualized, showItemTooltip: !!props.showItemTooltip, open: props.open, isLoading: props.isLoading }) })] }));
|
|
405
456
|
};
|
|
406
457
|
const MultiComboboxChips = (props) => {
|
|
407
458
|
return (_jsx(_Fragment, { children: props.selectedItems.map((item) => (_jsx(ComboboxChip, { showRemove: props.showClear, onMouseDown: (e) => {
|
|
@@ -421,15 +472,20 @@ const MultiCombobox_MenuListSearchable = (props) => {
|
|
|
421
472
|
contentElRef.current = el;
|
|
422
473
|
}, []);
|
|
423
474
|
const { allItems, itemByValue, maxLabelLength, inputValue, onInputValueChange, onValueChange, value, } = useGetAllItems(props);
|
|
424
|
-
const onCheckAllChange = props.onSelectAllCheckboxChange
|
|
425
|
-
(
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
475
|
+
const onCheckAllChange = props.onSelectAllCheckboxChange != null
|
|
476
|
+
? (checked) => {
|
|
477
|
+
props.onSelectAllCheckboxChange(checked);
|
|
478
|
+
}
|
|
479
|
+
: (checked, filteredItems) => {
|
|
480
|
+
const currentValues = (value ?? []);
|
|
481
|
+
const next = applySelectAllToSelection({
|
|
482
|
+
checked,
|
|
483
|
+
filteredItems,
|
|
484
|
+
currentValues,
|
|
485
|
+
itemByValue,
|
|
486
|
+
});
|
|
487
|
+
onValueChange?.(next.values, next.items);
|
|
488
|
+
};
|
|
433
489
|
const hasFocusRef = React.useRef(false);
|
|
434
490
|
const containerElRef = React.useRef(null);
|
|
435
491
|
const isInternalFocusTarget = (target) => {
|
|
@@ -488,7 +544,7 @@ const MultiCombobox_MenuListSearchable = (props) => {
|
|
|
488
544
|
};
|
|
489
545
|
return (_jsxs(AdaptableCombobox_Root, { ...props, value: value, multiple: true, allItems: allItems, itemByValue: itemByValue, inputValue: inputValue, onInputValueChange: onInputValueChange, onValueChange: onValueChange, onOpenChange: onOpenChange, children: [props.renderInput === false ? (_jsx(ComboboxTrigger, { nativeButton: false, render: renderChips, icon: props.showTrigger !== false ? undefined : null })) : (renderChips(undefined)), _jsxs(ComboboxContent, { anchor: anchor, style: getContentStyle({ maxLabelLength }), resizable: props.resizable, contentRef: contentRefCallback, children: [_jsx(ComboboxInput, { placeholder: 'Filter...', showClear: false, ref: searchInputRef, showTrigger: false, disabled: isDisabled, onFocus: handleFocus, onBlur: handleBlur, role: "searchbox", className: 'twa:min-h-input', children: typeof props.renderSearchInputTrailing === 'function'
|
|
490
546
|
? props.renderSearchInputTrailing()
|
|
491
|
-
: undefined }), _jsx(AdaptableComboboxList, { renderItemLabel: props.renderItemLabel, emptyText: emptyText, searchable: props.searchable, showSelectAllCheckbox: props.showSelectAllCheckbox, selectAllCheckboxValue: props.selectAllCheckboxValue, renderCheckboxIndicator: props.renderCheckboxIndicator ?? true, onCheckAllChange: onCheckAllChange,
|
|
547
|
+
: undefined }), _jsx(AdaptableComboboxList, { renderItemLabel: props.renderItemLabel, emptyText: emptyText, searchable: props.searchable, showSelectAllCheckbox: props.showSelectAllCheckbox, selectAllCheckboxValue: props.selectAllCheckboxValue, renderCheckboxIndicator: props.renderCheckboxIndicator ?? true, onCheckAllChange: onCheckAllChange, groups: props.groups, virtualized: !!props.virtualized, showItemTooltip: !!props.showItemTooltip, open: props.open, isLoading: props.isLoading })] })] }));
|
|
492
548
|
};
|
|
493
549
|
export const MultiCombobox = (props) => {
|
|
494
550
|
const searchable = props.searchable === false ? false : props.searchable === 'menulist' ? 'menulist' : 'inline';
|
|
@@ -299,12 +299,27 @@ export function TreeDropdown(props) {
|
|
|
299
299
|
}) }));
|
|
300
300
|
}, [renderSelectedValues, selectedLeafPaths, chipLabelForPath, showRemoveChip, deselectLeafPath]);
|
|
301
301
|
const allLeafPaths = useMemo(() => allNodes.filter((n) => !n.hasChildren).map((n) => n.path), [allNodes]);
|
|
302
|
+
const selectAllLeafPaths = useMemo(() => {
|
|
303
|
+
if (!searchQuery) {
|
|
304
|
+
return allLeafPaths;
|
|
305
|
+
}
|
|
306
|
+
const q = searchQuery.toLowerCase();
|
|
307
|
+
return allLeafPaths.filter((path) => {
|
|
308
|
+
for (let i = 1; i <= path.length; i++) {
|
|
309
|
+
const anc = nodeByKey.get(encodePath(path.slice(0, i)));
|
|
310
|
+
if (anc && anc.label && anc.label.toLowerCase().includes(q)) {
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return false;
|
|
315
|
+
});
|
|
316
|
+
}, [allLeafPaths, searchQuery, nodeByKey]);
|
|
302
317
|
const selectAllChecked = useMemo(() => {
|
|
303
|
-
if (
|
|
318
|
+
if (selectAllLeafPaths.length === 0) {
|
|
304
319
|
return false;
|
|
305
320
|
}
|
|
306
321
|
let selected = 0;
|
|
307
|
-
for (const p of
|
|
322
|
+
for (const p of selectAllLeafPaths) {
|
|
308
323
|
if (selectionState.isNodeSelected(p) === true) {
|
|
309
324
|
selected++;
|
|
310
325
|
}
|
|
@@ -312,25 +327,32 @@ export function TreeDropdown(props) {
|
|
|
312
327
|
if (selected === 0) {
|
|
313
328
|
return false;
|
|
314
329
|
}
|
|
315
|
-
if (selected ===
|
|
330
|
+
if (selected === selectAllLeafPaths.length) {
|
|
316
331
|
return true;
|
|
317
332
|
}
|
|
318
333
|
return null;
|
|
319
|
-
}, [
|
|
334
|
+
}, [selectAllLeafPaths, selectionState]);
|
|
320
335
|
const onSelectAllChange = useCallback((checked) => {
|
|
321
336
|
const next = new TreeSelectionState(internalSelection, {
|
|
322
337
|
treePaths,
|
|
323
338
|
strictCheckPaths: false,
|
|
324
339
|
});
|
|
325
|
-
if (
|
|
326
|
-
|
|
340
|
+
if (!searchQuery) {
|
|
341
|
+
if (checked) {
|
|
342
|
+
next.selectAll();
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
next.deselectAll();
|
|
346
|
+
}
|
|
327
347
|
}
|
|
328
348
|
else {
|
|
329
|
-
|
|
349
|
+
for (const path of selectAllLeafPaths) {
|
|
350
|
+
next.setNodeSelection(path, checked);
|
|
351
|
+
}
|
|
330
352
|
}
|
|
331
353
|
setInternalSelection(next.getState());
|
|
332
354
|
onValueChangeFromProps?.(next.getSelectedLeafNodePaths());
|
|
333
|
-
}, [internalSelection, treePaths, onValueChangeFromProps]);
|
|
355
|
+
}, [internalSelection, treePaths, onValueChangeFromProps, searchQuery, selectAllLeafPaths]);
|
|
334
356
|
const renderSearchInputTrailing = useCallback(() => {
|
|
335
357
|
if (branchNodes.length === 0) {
|
|
336
358
|
return null;
|
|
@@ -31,7 +31,7 @@ declare const ComboboxGroup: React.ForwardRefExoticComponent<Omit<import("@base-
|
|
|
31
31
|
declare const ComboboxLabel: React.ForwardRefExoticComponent<Omit<import("@base-ui/react").AutocompleteGroupLabelProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
32
32
|
declare function ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props): React.JSX.Element;
|
|
33
33
|
declare const ComboboxEmpty: React.ForwardRefExoticComponent<Omit<import("@base-ui/react").AutocompleteEmptyProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
34
|
-
declare const ComboboxSeparator: React.ForwardRefExoticComponent<Omit<import("@base-ui/react").
|
|
34
|
+
declare const ComboboxSeparator: React.ForwardRefExoticComponent<Omit<import("@base-ui/react").ComboboxSeparatorProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
35
35
|
declare const ComboboxChips: React.ForwardRefExoticComponent<Omit<import("@base-ui/react").ComboboxChipsProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
36
36
|
declare const ComboboxChip: React.ForwardRefExoticComponent<Omit<import("@base-ui/react").ComboboxChipProps & {
|
|
37
37
|
showRemove?: boolean;
|
package/src/env.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
NEXT_PUBLIC_INFINITE_TABLE_LICENSE_KEY: "StartDate=2021-06-29|EndDate=2030-01-01|Owner=Adaptable|Type=distribution|TS=1624971462479|C=137829811,1004007071,2756196225,1839832928,3994409405,636616862" || '',
|
|
3
|
-
PUBLISH_TIMESTAMP:
|
|
4
|
-
VERSION: "23.0.
|
|
3
|
+
PUBLISH_TIMESTAMP: 1785941951293 || Date.now(),
|
|
4
|
+
VERSION: "23.0.18" || '--current-version--',
|
|
5
5
|
};
|