@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptabletools/adaptable",
3
- "version": "23.0.17",
3
+ "version": "23.0.18",
4
4
  "description": "Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements",
5
5
  "keywords": [
6
6
  "web-components",
@@ -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
- * every item.
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.length === props.totalCount
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?.(!allChecked);
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
- ((checked) => {
378
- if (checked) {
379
- onValueChange?.(allItems.map((item) => item.value), allItems);
380
- }
381
- else {
382
- onValueChange?.([], []);
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, totalCount: allItems.length, groups: props.groups, virtualized: !!props.virtualized, showItemTooltip: !!props.showItemTooltip, open: props.open, isLoading: props.isLoading }) })] }));
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
- ((checked) => {
426
- if (checked) {
427
- onValueChange?.(allItems.map((item) => item.value), allItems);
428
- }
429
- else {
430
- onValueChange?.([], []);
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, totalCount: allItems.length, groups: props.groups, virtualized: !!props.virtualized, showItemTooltip: !!props.showItemTooltip, open: props.open, isLoading: props.isLoading })] })] }));
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 (allLeafPaths.length === 0) {
318
+ if (selectAllLeafPaths.length === 0) {
304
319
  return false;
305
320
  }
306
321
  let selected = 0;
307
- for (const p of allLeafPaths) {
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 === allLeafPaths.length) {
330
+ if (selected === selectAllLeafPaths.length) {
316
331
  return true;
317
332
  }
318
333
  return null;
319
- }, [allLeafPaths, selectionState]);
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 (checked) {
326
- next.selectAll();
340
+ if (!searchQuery) {
341
+ if (checked) {
342
+ next.selectAll();
343
+ }
344
+ else {
345
+ next.deselectAll();
346
+ }
327
347
  }
328
348
  else {
329
- next.deselectAll();
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").SeparatorProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
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: 1785768338368 || Date.now(),
4
- VERSION: "23.0.17" || '--current-version--',
3
+ PUBLISH_TIMESTAMP: 1785941951293 || Date.now(),
4
+ VERSION: "23.0.18" || '--current-version--',
5
5
  };