@vuu-ui/vuu-filters 3.5.1 → 3.5.2

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,5 +1,5 @@
1
1
  {
2
- "version": "3.5.1",
2
+ "version": "3.5.2",
3
3
  "main": "./src/index.js",
4
4
  "author": "heswell",
5
5
  "license": "Apache-2.0",
@@ -10,19 +10,19 @@
10
10
  "type-defs": "node ../../scripts/build-type-defs.mjs"
11
11
  },
12
12
  "devDependencies": {
13
- "@vuu-ui/vuu-data-types": "3.5.1",
14
- "@vuu-ui/vuu-protocol-types": "3.5.1",
15
- "@vuu-ui/vuu-table-types": "3.5.1",
16
- "@vuu-ui/vuu-filter-types": "3.5.1"
13
+ "@vuu-ui/vuu-data-types": "3.5.2",
14
+ "@vuu-ui/vuu-protocol-types": "3.5.2",
15
+ "@vuu-ui/vuu-table-types": "3.5.2",
16
+ "@vuu-ui/vuu-filter-types": "3.5.2"
17
17
  },
18
18
  "dependencies": {
19
- "@vuu-ui/vuu-context-menu": "3.5.1",
20
- "@vuu-ui/vuu-data-react": "3.5.1",
21
- "@vuu-ui/vuu-filter-parser": "3.5.1",
22
- "@vuu-ui/vuu-popups": "3.5.1",
23
- "@vuu-ui/vuu-ui-controls": "3.5.1",
24
- "@vuu-ui/vuu-table": "3.5.1",
25
- "@vuu-ui/vuu-utils": "3.5.1",
19
+ "@vuu-ui/vuu-context-menu": "3.5.2",
20
+ "@vuu-ui/vuu-data-react": "3.5.2",
21
+ "@vuu-ui/vuu-filter-parser": "3.5.2",
22
+ "@vuu-ui/vuu-popups": "3.5.2",
23
+ "@vuu-ui/vuu-ui-controls": "3.5.2",
24
+ "@vuu-ui/vuu-table": "3.5.2",
25
+ "@vuu-ui/vuu-utils": "3.5.2",
26
26
  "@salt-ds/core": "1.54.1",
27
27
  "@salt-ds/lab": "1.0.0-alpha.83",
28
28
  "@salt-ds/styles": "0.2.1",
@@ -43,6 +43,10 @@ const css = `
43
43
  --saltButton-padding: var(--salt-spacing-200);
44
44
  }
45
45
 
46
+ .vuuColumnFilter-toggle {
47
+ max-width: none;
48
+ }
49
+
46
50
  .vuuColumnFilter-invalid {
47
51
  border-color: red;
48
52
  }
@@ -39,7 +39,8 @@ const ColumnFilter_ColumnFilter = /*#__PURE__*/ external_react_forwardRef(functi
39
39
  return /*#__PURE__*/ jsxs(SegmentedButtonGroup, {
40
40
  ...buttonGroupProps,
41
41
  className: clsx(classBase, className, {
42
- [`${classBase}-invalid`]: isInvalid
42
+ [`${classBase}-invalid`]: isInvalid,
43
+ [`${classBase}-toggle`]: "toggle" === variant
43
44
  }),
44
45
  ref: forwardRef,
45
46
  children: [
@@ -3,6 +3,14 @@ const css = `
3
3
  & .vuuToggleFilter-onlyAvailableValue:not([aria-checked="true"], :hover) {
4
4
  background-color: var(--vuuToggleFilter-implicitActive-bg, var(--salt-actionable-bold-background));
5
5
  }
6
+
7
+ & .vuuToggleFilter-unavailableValue:not([aria-checked="true"]) {
8
+ background: var(--toggleButton-background);
9
+ border-color: var(--toggleButton-borderColor);
10
+ color: var(--toggleButton-text-color);
11
+ cursor: var(--vuuToggleFilter-unavailableValue-cursor, var(--salt-cursor-disabled));
12
+ opacity: var(--vuuToggleFilter-unavailableValue-opacity, .4);
13
+ }
6
14
  }
7
15
 
8
16
 
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { ToggleButton, ToggleButtonGroup } from "@salt-ds/core";
2
+ import { ToggleButton, ToggleButtonGroup, Tooltip } from "@salt-ds/core";
3
3
  import { useComponentCssInjection } from "@salt-ds/styles";
4
4
  import { useWindow } from "@salt-ds/window";
5
5
  import clsx from "clsx";
@@ -24,6 +24,7 @@ const getValues = (defaultValue, value)=>{
24
24
  ];
25
25
  };
26
26
  const classBase = "vuuToggleFilter";
27
+ const NO_MATCHING_DATA = "No matching data";
27
28
  const ToggleFilter_ToggleFilter = /*#__PURE__*/ forwardRef(function({ className, column, defaultValue: defaultValueProp, labels, onCommit, table, value: valueProp, values, ...ToggleButtonGroupProps }, forwardedRef) {
28
29
  const targetWindow = useWindow();
29
30
  useComponentCssInjection({
@@ -33,7 +34,7 @@ const ToggleFilter_ToggleFilter = /*#__PURE__*/ forwardRef(function({ className,
33
34
  });
34
35
  if (void 0 !== labels && labels.length !== values.length) throw Error("[ToggleFilter] labels must have the same number of items as values");
35
36
  const [defaultValue, value] = getValues(defaultValueProp, valueProp);
36
- const onlyAvailableValue = useToggleFilter({
37
+ const { onlyAvailableValue, unavailableValues } = useToggleFilter({
37
38
  column,
38
39
  table,
39
40
  values
@@ -54,15 +55,23 @@ const ToggleFilter_ToggleFilter = /*#__PURE__*/ forwardRef(function({ className,
54
55
  children: [
55
56
  /*#__PURE__*/ jsx(ToggleButton, {
56
57
  value: "all",
57
- children: "ALL"
58
+ children: "All"
58
59
  }, "all"),
59
- values.map((toggleValue, i)=>/*#__PURE__*/ jsx(ToggleButton, {
60
- className: clsx({
61
- [`${classBase}-onlyAvailableValue`]: onlyAvailableValue === toggleValue
62
- }),
63
- value: toggleValue,
64
- children: labels?.[i] ?? toggleValue
65
- }, toggleValue))
60
+ values.map((toggleValue, i)=>{
61
+ const unavailable = unavailableValues.includes(toggleValue);
62
+ return /*#__PURE__*/ jsx(Tooltip, {
63
+ content: NO_MATCHING_DATA,
64
+ disabled: !unavailable,
65
+ children: /*#__PURE__*/ jsx(ToggleButton, {
66
+ className: clsx({
67
+ [`${classBase}-onlyAvailableValue`]: onlyAvailableValue === toggleValue,
68
+ [`${classBase}-unavailableValue`]: unavailable
69
+ }),
70
+ value: toggleValue,
71
+ children: labels?.[i] ?? toggleValue
72
+ })
73
+ }, toggleValue);
74
+ })
66
75
  ]
67
76
  });
68
77
  });
@@ -1,57 +1,81 @@
1
- import { useSavedFilters } from "../filter-provider/FilterContext.js";
2
1
  import { useTypeaheadSuggestions } from "@vuu-ui/vuu-data-react";
3
- import { useCallback, useMemo, useRef, useState } from "react";
4
- import { filtersAreEqual, getVuuTable } from "@vuu-ui/vuu-utils";
2
+ import { parseFilter } from "@vuu-ui/vuu-filter-parser";
3
+ import { extractFilterForColumn, getVuuTable, useDataSource } from "@vuu-ui/vuu-utils";
4
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5
5
  const assertValid = (values, actualValues)=>{
6
6
  if (actualValues.some((val)=>-1 === values.indexOf(val))) console.warn(`[useToggleFilter] ToggleFilter is configured with values which do not include all values from data source
7
7
  [${values.join()}]
8
8
  [${actualValues.join()}]`);
9
9
  };
10
- const typeaheadRefreshRequired = (f1, f2)=>{
11
- if (null === f1 && null === f2) return false;
12
- if (null === f1 || null === f2) return true;
13
- if (filtersAreEqual(f1, f2)) return false;
14
- return true;
10
+ const hasFilterOnColumn = (filterSpec, column)=>{
11
+ if (void 0 === filterSpec || "" === filterSpec.filter) return false;
12
+ const filter = filterSpec.filterStruct ?? parseFilter(filterSpec.filter);
13
+ return void 0 !== extractFilterForColumn(filter, column);
15
14
  };
16
15
  const useToggleFilter = ({ column, table, values })=>{
17
- const { currentFilter } = useSavedFilters();
18
- const currentFilterRef = useRef(currentFilter.filter);
19
- const [typeaheadValues, setTypeaheadValues] = useState([]);
16
+ const dataSource = useDataSource(false);
17
+ const [typeaheadValues, setTypeaheadValues] = useState(void 0);
20
18
  const getSuggestions = useTypeaheadSuggestions();
21
- const refreshSuggestions = useCallback((table)=>{
22
- const vuuTable = getVuuTable(table);
19
+ const requestIdRef = useRef(0);
20
+ const valuesRef = useRef(values);
21
+ valuesRef.current = values;
22
+ const valuesKey = values.join("\u0000");
23
+ const vuuTable = table ? getVuuTable(table) : void 0;
24
+ const tableModule = vuuTable?.module;
25
+ const tableName = vuuTable?.table;
26
+ const checkAvailability = useCallback(()=>{
27
+ if (void 0 === tableModule || void 0 === tableName || void 0 === dataSource) return;
28
+ if (hasFilterOnColumn(dataSource.filter, column)) return;
29
+ const requestId = ++requestIdRef.current;
23
30
  const params = [
24
- vuuTable,
31
+ {
32
+ module: tableModule,
33
+ table: tableName
34
+ },
25
35
  column
26
36
  ];
27
37
  getSuggestions(params).then((suggestions)=>{
28
- if (false === suggestions) setTypeaheadValues([]);
29
- else {
30
- assertValid(values, suggestions);
31
- setTypeaheadValues(suggestions);
32
- }
38
+ if (requestId !== requestIdRef.current || false === suggestions) return;
39
+ assertValid(valuesRef.current, suggestions);
40
+ setTypeaheadValues(suggestions);
33
41
  });
34
42
  }, [
35
43
  column,
44
+ dataSource,
36
45
  getSuggestions,
37
- values
46
+ tableModule,
47
+ tableName
38
48
  ]);
39
- useMemo(()=>{
40
- if (table) refreshSuggestions(table);
49
+ useEffect(()=>{
50
+ checkAvailability();
41
51
  }, [
42
- refreshSuggestions,
43
- table
52
+ checkAvailability
44
53
  ]);
45
- useMemo(()=>{
46
- const { current: filter } = currentFilterRef;
47
- if (table && typeaheadRefreshRequired(filter, currentFilter.filter)) refreshSuggestions(table);
48
- currentFilterRef.current = currentFilter.filter;
54
+ useEffect(()=>{
55
+ if (dataSource) {
56
+ const handleConfigChange = (_config, _range, _confirmed, configChanges)=>{
57
+ if (configChanges?.filterChanged) checkAvailability();
58
+ };
59
+ dataSource.on("config", handleConfigChange);
60
+ return ()=>{
61
+ dataSource.removeListener("config", handleConfigChange);
62
+ };
63
+ }
49
64
  }, [
50
- currentFilter.filter,
51
- refreshSuggestions,
52
- table
65
+ checkAvailability,
66
+ dataSource
67
+ ]);
68
+ return useMemo(()=>{
69
+ if (void 0 === typeaheadValues) return {
70
+ unavailableValues: []
71
+ };
72
+ return {
73
+ onlyAvailableValue: 1 === typeaheadValues.length ? typeaheadValues[0] : void 0,
74
+ unavailableValues: valuesRef.current.filter((value)=>!typeaheadValues.includes(value))
75
+ };
76
+ }, [
77
+ typeaheadValues,
78
+ valuesKey
53
79
  ]);
54
- const [firstValue] = typeaheadValues;
55
- return 1 === typeaheadValues.length ? firstValue : void 0;
56
80
  };
57
81
  export { useToggleFilter };
@@ -8,4 +8,22 @@ export interface ToggleFilterHookProps {
8
8
  table?: TableSchemaTable;
9
9
  values: string[];
10
10
  }
11
- export declare const useToggleFilter: ({ column, table, values, }: ToggleFilterHookProps) => string | undefined;
11
+ export interface ToggleFilterHookResult {
12
+ /**
13
+ * If only one of the toggle values has matching data, that value.
14
+ */
15
+ onlyAvailableValue?: string;
16
+ /**
17
+ * Toggle values for which there is no matching data.
18
+ */
19
+ unavailableValues: string[];
20
+ }
21
+ /**
22
+ * Determines which toggle values have matching data, using typeahead
23
+ * against the DataSource. Typeahead respects the filter applied to the
24
+ * DataSource, so while a filter on this column is in effect, results
25
+ * would only reflect the filtered value. In that case no check is made
26
+ * and the result of the last check (if any) is retained. If there has
27
+ * been no check, all values are assumed to possibly have data.
28
+ */
29
+ export declare const useToggleFilter: ({ column, table, values, }: ToggleFilterHookProps) => ToggleFilterHookResult;