@vuu-ui/vuu-filters 0.8.14-debug → 0.8.15-debug

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.
Files changed (64) hide show
  1. package/cjs/index.js +521 -127
  2. package/cjs/index.js.map +4 -4
  3. package/esm/index.js +514 -109
  4. package/esm/index.js.map +4 -4
  5. package/index.css +16 -18
  6. package/index.css.map +2 -2
  7. package/package.json +10 -10
  8. package/types/vuu-data/src/array-data-source/aggregate-utils.d.ts +8 -0
  9. package/types/vuu-data/src/array-data-source/array-data-source.d.ts +84 -0
  10. package/types/vuu-data/src/array-data-source/array-data-utils.d.ts +5 -0
  11. package/types/vuu-data/src/array-data-source/group-utils.d.ts +10 -0
  12. package/types/vuu-data/src/array-data-source/sort-utils.d.ts +4 -0
  13. package/types/vuu-data/src/authenticate.d.ts +1 -0
  14. package/types/vuu-data/src/connection-manager.d.ts +50 -0
  15. package/types/vuu-data/src/connectionTypes.d.ts +5 -0
  16. package/types/vuu-data/src/constants.d.ts +41 -0
  17. package/types/vuu-data/src/data-source.d.ts +237 -0
  18. package/types/vuu-data/src/index.d.ts +10 -0
  19. package/types/vuu-data/src/inlined-worker.d.ts +1 -0
  20. package/types/vuu-data/src/json-data-source.d.ts +56 -0
  21. package/types/vuu-data/src/message-utils.d.ts +28 -0
  22. package/types/vuu-data/src/remote-data-source.d.ts +65 -0
  23. package/types/vuu-data/src/server-proxy/messages.d.ts +38 -0
  24. package/types/vuu-data/src/vuuUIMessageTypes.d.ts +228 -0
  25. package/types/vuu-data/src/websocket-connection.d.ts +25 -0
  26. package/types/vuu-filters/src/filter-bar/FilterBarMenu.d.ts +2 -0
  27. package/types/{filter-bar → vuu-filters/src/filter-bar}/useFilterBar.d.ts +10 -5
  28. package/types/vuu-filters/src/filter-bar/useFilterBarMenu.d.ts +5 -0
  29. package/types/{filter-bar → vuu-filters/src/filter-bar}/useFilters.d.ts +3 -1
  30. package/types/{filter-builder-menu → vuu-filters/src/filter-builder-menu}/FilterBuilderMenu.d.ts +3 -1
  31. package/types/{filter-clause → vuu-filters/src/filter-clause}/FilterClauseEditor.d.ts +6 -2
  32. package/types/{filter-clause → vuu-filters/src/filter-clause}/TextInput.d.ts +1 -0
  33. package/types/{filter-clause → vuu-filters/src/filter-clause}/filterClauseTypes.d.ts +4 -1
  34. package/types/{filter-clause → vuu-filters/src/filter-clause}/useFilterClauseEditor.d.ts +9 -3
  35. package/types/{filter-pill → vuu-filters/src/filter-pill}/FilterPill.d.ts +1 -1
  36. package/types/vuu-filters/src/filter-pill/filterAsReactNode.d.ts +3 -0
  37. package/types/{filter-utils.d.ts → vuu-filters/src/filter-utils.d.ts} +2 -1
  38. /package/types/{column-filter → vuu-filters/src/column-filter}/utils.d.ts +0 -0
  39. /package/types/{filter-bar → vuu-filters/src/filter-bar}/FilterBar.d.ts +0 -0
  40. /package/types/{filter-bar → vuu-filters/src/filter-bar}/index.d.ts +0 -0
  41. /package/types/{filter-builder-menu → vuu-filters/src/filter-builder-menu}/index.d.ts +0 -0
  42. /package/types/{filter-clause → vuu-filters/src/filter-clause}/ExpandoCombobox.d.ts +0 -0
  43. /package/types/{filter-clause → vuu-filters/src/filter-clause}/FilterMenu.d.ts +0 -0
  44. /package/types/{filter-clause → vuu-filters/src/filter-clause}/FilterMenuOptions.d.ts +0 -0
  45. /package/types/{filter-clause → vuu-filters/src/filter-clause}/NumericInput.d.ts +0 -0
  46. /package/types/{filter-clause → vuu-filters/src/filter-clause}/index.d.ts +0 -0
  47. /package/types/{filter-clause → vuu-filters/src/filter-clause}/operator-utils.d.ts +0 -0
  48. /package/types/{filter-input → vuu-filters/src/filter-input}/FilterInput.d.ts +0 -0
  49. /package/types/{filter-input → vuu-filters/src/filter-input}/FilterLanguage.d.ts +0 -0
  50. /package/types/{filter-input → vuu-filters/src/filter-input}/filterInfo.d.ts +0 -0
  51. /package/types/{filter-input → vuu-filters/src/filter-input}/highlighting.d.ts +0 -0
  52. /package/types/{filter-input → vuu-filters/src/filter-input}/index.d.ts +0 -0
  53. /package/types/{filter-input → vuu-filters/src/filter-input}/theme.d.ts +0 -0
  54. /package/types/{filter-input → vuu-filters/src/filter-input}/useCodeMirrorEditor.d.ts +0 -0
  55. /package/types/{filter-input → vuu-filters/src/filter-input}/useFilterAutoComplete.d.ts +0 -0
  56. /package/types/{filter-input → vuu-filters/src/filter-input}/useFilterSuggestionProvider.d.ts +0 -0
  57. /package/types/{filter-pill → vuu-filters/src/filter-pill}/index.d.ts +0 -0
  58. /package/types/{filter-pill-menu → vuu-filters/src/filter-pill-menu}/FilterPillMenu.d.ts +0 -0
  59. /package/types/{filter-pill-menu → vuu-filters/src/filter-pill-menu}/FilterPillMenuOptions.d.ts +0 -0
  60. /package/types/{filter-pill-menu → vuu-filters/src/filter-pill-menu}/index.d.ts +0 -0
  61. /package/types/{index.d.ts → vuu-filters/src/index.d.ts} +0 -0
  62. /package/types/{local-config.d.ts → vuu-filters/src/local-config.d.ts} +0 -0
  63. /package/types/{use-filter-config.d.ts → vuu-filters/src/use-filter-config.d.ts} +0 -0
  64. /package/types/{use-rest-config.d.ts → vuu-filters/src/use-rest-config.d.ts} +0 -0
package/esm/index.js CHANGED
@@ -1897,7 +1897,7 @@ var useViewActionDispatcher = (id, root, viewPath, dropTargets) => {
1897
1897
 
1898
1898
  // ../vuu-layout/src/layout-view/View.tsx
1899
1899
  var import_classnames9 = __toESM(require_classnames());
1900
- import { useForkRef as useForkRef3, useIdMemo as useId2 } from "@salt-ds/core";
1900
+ import { useForkRef as useForkRef3 } from "@salt-ds/core";
1901
1901
  import React14, {
1902
1902
  forwardRef as forwardRef5,
1903
1903
  useCallback as useCallback14,
@@ -2076,7 +2076,7 @@ var View = forwardRef5(function View2(props, forwardedRef) {
2076
2076
  title: titleProp,
2077
2077
  ...restProps
2078
2078
  } = props;
2079
- const id = useId2(idProp);
2079
+ const id = useId(idProp);
2080
2080
  const rootRef = useRef10(null);
2081
2081
  const mainRef = useRef10(null);
2082
2082
  const [componentProps, _setComponentProps] = useState7();
@@ -2347,7 +2347,7 @@ var LocalLayoutPersistenceManager = class {
2347
2347
  const newMetadata = {
2348
2348
  ...metadata,
2349
2349
  id,
2350
- created: formatDate(/* @__PURE__ */ new Date(), "dd.mm.yyyy")
2350
+ created: formatDate("dd.mm.yyyy")(/* @__PURE__ */ new Date())
2351
2351
  };
2352
2352
  this.saveLayoutsWithMetadata(
2353
2353
  [...existingLayouts, { id, json: layout }],
@@ -2624,6 +2624,7 @@ import React18, {
2624
2624
  import { NotificationLevel, useNotifications } from "@vuu-ui/vuu-popups";
2625
2625
  import { jsx as jsx26 } from "react/jsx-runtime";
2626
2626
  var LayoutManagementContext = React18.createContext({
2627
+ getApplicationSettings: () => void 0,
2627
2628
  layoutMetadata: [],
2628
2629
  saveLayout: () => void 0,
2629
2630
  // The default Application JSON will be served if no LayoutManagementProvider
@@ -2632,6 +2633,7 @@ var LayoutManagementContext = React18.createContext({
2632
2633
  saveApplicationSettings: () => void 0,
2633
2634
  loadLayoutById: () => void 0
2634
2635
  });
2636
+ var useLayoutManager = () => useContext3(LayoutManagementContext);
2635
2637
 
2636
2638
  // ../vuu-shell/src/layout-management/LayoutList.tsx
2637
2639
  import { Fragment as Fragment5, jsx as jsx27, jsxs as jsxs11 } from "react/jsx-runtime";
@@ -3755,7 +3757,7 @@ var PaletteItem = memo2(
3755
3757
  );
3756
3758
  PaletteItem.displayName = "PaletteItem";
3757
3759
  var Palette = ({
3758
- ListProps: ListProps2,
3760
+ ListProps: ListProps3,
3759
3761
  ViewProps: ViewProps4,
3760
3762
  children,
3761
3763
  className,
@@ -3814,7 +3816,7 @@ var Palette = ({
3814
3816
  return /* @__PURE__ */ jsx43(
3815
3817
  List2,
3816
3818
  {
3817
- ...ListProps2,
3819
+ ...ListProps3,
3818
3820
  ...props,
3819
3821
  className: (0, import_classnames24.default)(classBase21, className, `${classBase21}-${orientation}`),
3820
3822
  itemHeight,
@@ -3839,7 +3841,7 @@ import React21, {
3839
3841
  useRef as useRef20
3840
3842
  } from "react";
3841
3843
  import { jsx as jsx44, jsxs as jsxs22 } from "react/jsx-runtime";
3842
- var classBase12 = "Tabs";
3844
+ var classBase12 = "vuuTabs";
3843
3845
  var getDefaultTabIcon = () => void 0;
3844
3846
  var getChildElements = (children) => {
3845
3847
  const elements = [];
@@ -3969,7 +3971,7 @@ var Stack = forwardRef8(function Stack2({
3969
3971
  Stack.displayName = "Stack";
3970
3972
 
3971
3973
  // ../vuu-layout/src/stack/StackLayout.tsx
3972
- import { useIdMemo as useId3 } from "@salt-ds/core";
3974
+ import { useIdMemo as useId2 } from "@salt-ds/core";
3973
3975
  import React22, { useCallback as useCallback30, useRef as useRef21 } from "react";
3974
3976
  import { jsx as jsx45 } from "react/jsx-runtime";
3975
3977
  var defaultCreateNewChild = () => /* @__PURE__ */ jsx45(
@@ -3992,7 +3994,7 @@ var StackLayout = (props) => {
3992
3994
  ...restProps
3993
3995
  } = props;
3994
3996
  const { children } = props;
3995
- const id = useId3(idProp);
3997
+ const id = useId2(idProp);
3996
3998
  const [dispatchViewAction] = useViewActionDispatcher(id, ref, path);
3997
3999
  const createNewChildFromContext = useLayoutCreateNewChild();
3998
4000
  const createNewChild = (_a = createNewChildProp != null ? createNewChildProp : createNewChildFromContext) != null ? _a : defaultCreateNewChild;
@@ -4716,7 +4718,10 @@ import { PopupComponent as Popup, Portal } from "@vuu-ui/vuu-popups";
4716
4718
  import { List as List3, ListItem as ListItem2 } from "@vuu-ui/vuu-ui-controls";
4717
4719
  import { Fragment as Fragment6, jsx as jsx50, jsxs as jsxs25 } from "react/jsx-runtime";
4718
4720
  var classBase14 = "vuuFilterBuilderMenu";
4719
- var FilterBuilderMenu = ({ onMenuAction }) => {
4721
+ var FilterBuilderMenu = ({
4722
+ ListProps: ListProps3,
4723
+ onMenuAction
4724
+ }) => {
4720
4725
  const ref = useRef25(null);
4721
4726
  const listRef = useCallback34((el) => {
4722
4727
  if (el) {
@@ -4739,15 +4744,16 @@ var FilterBuilderMenu = ({ onMenuAction }) => {
4739
4744
  /* @__PURE__ */ jsx50(Portal, { children: /* @__PURE__ */ jsx50(Popup, { anchorElement: ref, placement: "right", children: /* @__PURE__ */ jsxs25(
4740
4745
  List3,
4741
4746
  {
4747
+ ...ListProps3,
4742
4748
  className: `${classBase14}List`,
4743
- defaultHighlightedIndex: 1,
4749
+ defaultHighlightedIndex: 0,
4744
4750
  itemHeight: 22,
4745
4751
  ref: listRef,
4746
4752
  onSelect: handleSelect,
4747
4753
  style: { position: "relative" },
4748
4754
  width: 100,
4749
4755
  children: [
4750
- /* @__PURE__ */ jsx50(ListItem2, { "data-action": "apply-save", className: "vuuMenuButton", children: "APPLY AND SAVE" }),
4756
+ /* @__PURE__ */ jsx50(ListItem2, { "data-action": "apply-save", children: /* @__PURE__ */ jsx50("span", { className: "vuuMenuButton", children: "APPLY AND SAVE" }) }),
4751
4757
  /* @__PURE__ */ jsx50(ListItem2, { "data-action": "and-clause", children: "AND" }),
4752
4758
  /* @__PURE__ */ jsx50(ListItem2, { "data-action": "or-clause", children: "OR" })
4753
4759
  ]
@@ -4783,7 +4789,6 @@ var ExpandoCombobox = forwardRef9(function ExpandoCombobox2({
4783
4789
  value = "",
4784
4790
  ...props
4785
4791
  }, forwardedRef) {
4786
- var _a;
4787
4792
  const [text, setText] = useState20(value);
4788
4793
  const { itemToString = defaultToString } = props;
4789
4794
  const initialValue = useRef26(value);
@@ -4801,7 +4806,6 @@ var ExpandoCombobox = forwardRef9(function ExpandoCombobox2({
4801
4806
  const handleInputChange = useCallback35(
4802
4807
  (evt) => {
4803
4808
  const { value: value2 } = evt.target;
4804
- console.log(`onInputChange ${value2}`);
4805
4809
  setText(value2);
4806
4810
  onInputChange == null ? void 0 : onInputChange(evt);
4807
4811
  },
@@ -4810,7 +4814,7 @@ var ExpandoCombobox = forwardRef9(function ExpandoCombobox2({
4810
4814
  const handleSetSelectedText = useCallback35((text2) => {
4811
4815
  setText(text2);
4812
4816
  }, []);
4813
- const [InputProps, ListProps2] = useMemo16(() => {
4817
+ const [InputProps, ListProps3] = useMemo16(() => {
4814
4818
  const { inputProps, ...restInputProps } = InputPropsProp;
4815
4819
  return [
4816
4820
  {
@@ -4857,7 +4861,7 @@ var ExpandoCombobox = forwardRef9(function ExpandoCombobox2({
4857
4861
  const popupProps = {
4858
4862
  minWidth: "fit-content"
4859
4863
  };
4860
- return ((_a = props.source) == null ? void 0 : _a.length) === 0 ? null : /* @__PURE__ */ jsx51(
4864
+ return /* @__PURE__ */ jsx51(
4861
4865
  "div",
4862
4866
  {
4863
4867
  className: (0, import_classnames28.default)(classBase15, classNameProp),
@@ -4871,7 +4875,7 @@ var ExpandoCombobox = forwardRef9(function ExpandoCombobox2({
4871
4875
  PopupProps: popupProps,
4872
4876
  defaultValue: initialValue.current,
4873
4877
  fullWidth: true,
4874
- ListProps: ListProps2,
4878
+ ListProps: ListProps3,
4875
4879
  InputProps,
4876
4880
  itemsToString,
4877
4881
  onSelectionChange: handleSelectionChange,
@@ -4970,10 +4974,14 @@ import {
4970
4974
  ExpandoInput as ExpandoInput2
4971
4975
  } from "@vuu-ui/vuu-ui-controls";
4972
4976
  import { jsx as jsx53 } from "react/jsx-runtime";
4977
+ var selectionKeys = ["Enter", " "];
4978
+ var NO_DATA_MATCH = ["No matching data"];
4973
4979
  var TextInput = forwardRef11(function TextInput2({
4974
4980
  InputProps: InputPropsProp = {},
4975
4981
  className,
4976
4982
  column,
4983
+ "data-field": dataField,
4984
+ onDeselect,
4977
4985
  onInputComplete,
4978
4986
  operator,
4979
4987
  suggestionProvider = useTypeaheadSuggestions,
@@ -5003,7 +5011,11 @@ var TextInput = forwardRef11(function TextInput2({
5003
5011
  if (table) {
5004
5012
  const params = valueInputValue ? [table, column.name, valueInputValue] : [table, column.name];
5005
5013
  getSuggestions(params).then((suggestions) => {
5006
- setTypeaheadValues(suggestions);
5014
+ if (suggestions.length === 0 && valueInputValue) {
5015
+ setTypeaheadValues(NO_DATA_MATCH);
5016
+ } else {
5017
+ setTypeaheadValues(suggestions);
5018
+ }
5007
5019
  }).catch((err) => {
5008
5020
  console.error("Error getting suggestions", err);
5009
5021
  });
@@ -5037,6 +5049,9 @@ var TextInput = forwardRef11(function TextInput2({
5037
5049
  }
5038
5050
  }, [InputPropsProp, onInputComplete, operator, valueInputValue]);
5039
5051
  const getValueInputField = useCallback37(() => {
5052
+ if (typeaheadValues.length === 0) {
5053
+ return null;
5054
+ }
5040
5055
  switch (operator) {
5041
5056
  case "in":
5042
5057
  return /* @__PURE__ */ jsx53(
@@ -5044,16 +5059,18 @@ var TextInput = forwardRef11(function TextInput2({
5044
5059
  {
5045
5060
  InputProps,
5046
5061
  className,
5062
+ "data-field": dataField,
5047
5063
  initialHighlightedIndex: 0,
5048
5064
  source: typeaheadValues,
5049
5065
  onInputChange: handleInputChange,
5050
5066
  onSelectionChange: handleMultiValueSelectionChange,
5051
5067
  ref: forwardedRef,
5052
5068
  selectionStrategy: "multiple",
5069
+ selectionKeys,
5053
5070
  value
5054
5071
  }
5055
5072
  );
5056
- case "starts":
5073
+ case "starts": {
5057
5074
  return /* @__PURE__ */ jsx53(
5058
5075
  ExpandoCombobox,
5059
5076
  {
@@ -5064,7 +5081,9 @@ var TextInput = forwardRef11(function TextInput2({
5064
5081
  },
5065
5082
  allowFreeText: true,
5066
5083
  className,
5084
+ "data-field": dataField,
5067
5085
  initialHighlightedIndex: 0,
5086
+ disableFilter: typeaheadValues === NO_DATA_MATCH && (valueInputValue == null ? void 0 : valueInputValue.length) > 0,
5068
5087
  source: typeaheadValues,
5069
5088
  onInputChange: handleInputChange,
5070
5089
  onSelectionChange: handleSingleValueSelectionChange,
@@ -5072,12 +5091,14 @@ var TextInput = forwardRef11(function TextInput2({
5072
5091
  value
5073
5092
  }
5074
5093
  );
5094
+ }
5075
5095
  case "ends":
5076
5096
  return /* @__PURE__ */ jsx53(
5077
5097
  ExpandoInput2,
5078
5098
  {
5079
5099
  ...InputProps,
5080
5100
  className,
5101
+ "data-field": dataField,
5081
5102
  value: valueInputValue,
5082
5103
  ref: forwardedRef,
5083
5104
  onChange: handleInputChange
@@ -5088,11 +5109,14 @@ var TextInput = forwardRef11(function TextInput2({
5088
5109
  ExpandoCombobox,
5089
5110
  {
5090
5111
  InputProps,
5112
+ allowBackspaceClearsSelection: true,
5091
5113
  className,
5114
+ "data-field": dataField,
5092
5115
  initialHighlightedIndex: 0,
5093
5116
  source: typeaheadValues,
5094
5117
  title: "value",
5095
5118
  onInputChange: handleInputChange,
5119
+ onDeselect,
5096
5120
  onSelectionChange: handleSingleValueSelectionChange,
5097
5121
  ref: forwardedRef,
5098
5122
  value
@@ -5103,13 +5127,15 @@ var TextInput = forwardRef11(function TextInput2({
5103
5127
  operator,
5104
5128
  InputProps,
5105
5129
  className,
5130
+ dataField,
5106
5131
  typeaheadValues,
5107
5132
  handleInputChange,
5108
5133
  handleMultiValueSelectionChange,
5109
5134
  forwardedRef,
5110
5135
  value,
5111
- handleSingleValueSelectionChange,
5112
- valueInputValue
5136
+ valueInputValue,
5137
+ onDeselect,
5138
+ handleSingleValueSelectionChange
5113
5139
  ]);
5114
5140
  return getValueInputField();
5115
5141
  });
@@ -5132,29 +5158,44 @@ var cursorAtTextStart = (input) => input.selectionStart === 0;
5132
5158
  var cursorAtTextEnd = (input) => input.selectionStart === input.value.length;
5133
5159
  var getFieldName = (field) => (field == null ? void 0 : field.classList.contains("vuuFilterClauseColumn")) ? "column" : (field == null ? void 0 : field.classList.contains("vuuFilterClauseOperator")) ? "operator" : "value";
5134
5160
  var getFocusedField = () => {
5135
- var _a;
5136
- return (_a = document.activeElement) == null ? void 0 : _a.closest(".vuuFilterClauseField");
5161
+ const activeElement = document.activeElement;
5162
+ if (activeElement == null ? void 0 : activeElement.classList.contains("vuuFilterClause-clearButton")) {
5163
+ return activeElement;
5164
+ } else {
5165
+ return activeElement == null ? void 0 : activeElement.closest(".vuuFilterClauseField");
5166
+ }
5137
5167
  };
5138
5168
  var focusNextFocusableElement = (direction = "fwd") => {
5139
5169
  var _a;
5140
5170
  const activeField = getFocusedField();
5141
5171
  const filterClause = activeField == null ? void 0 : activeField.closest(".vuuFilterClause");
5142
- if ((filterClause == null ? void 0 : filterClause.lastChild) === activeField) {
5172
+ if (direction === "fwd" && (filterClause == null ? void 0 : filterClause.lastChild) === activeField) {
5143
5173
  requestAnimationFrame(() => {
5144
5174
  focusNextFocusableElement();
5145
5175
  });
5146
5176
  } else {
5147
- const nextField = direction === "fwd" ? activeField.nextElementSibling : activeField.previousElementSibling;
5177
+ const nextField = direction === "fwd" ? activeField == null ? void 0 : activeField.nextElementSibling : activeField == null ? void 0 : activeField.previousElementSibling;
5148
5178
  (_a = nextField == null ? void 0 : nextField.querySelector("input")) == null ? void 0 : _a.focus();
5149
5179
  }
5150
5180
  };
5181
+ var clauseIsNotFirst = (el) => {
5182
+ var _a;
5183
+ const clause = el.closest("[data-index]");
5184
+ if (clause) {
5185
+ const index = clause.dataset.index;
5186
+ const previousClause = (_a = clause == null ? void 0 : clause.parentElement) == null ? void 0 : _a.querySelector(
5187
+ `[data-index]:has(.vuuFilterClause):has(+[data-index="${index}"])`
5188
+ );
5189
+ return previousClause !== null;
5190
+ }
5191
+ };
5151
5192
  var focusNextElement = () => {
5152
5193
  const filterClauseField = getFocusedField();
5153
5194
  const filterClause = filterClauseField == null ? void 0 : filterClauseField.closest(".vuuFilterClause");
5154
5195
  if (filterClause && filterClauseField) {
5155
5196
  if (filterClauseField.classList.contains("vuuFilterClauseValue")) {
5156
5197
  const clearButton = filterClause.querySelector(
5157
- ".vuuFilterClause-closeButton"
5198
+ ".vuuFilterClause-clearButton"
5158
5199
  );
5159
5200
  clearButton == null ? void 0 : clearButton.focus();
5160
5201
  } else {
@@ -5213,6 +5254,7 @@ var getFilterClauseValue = (filterClause) => {
5213
5254
  };
5214
5255
  var useFilterClauseEditor = ({
5215
5256
  filterClause,
5257
+ onCancel,
5216
5258
  onChange,
5217
5259
  tableSchema
5218
5260
  }) => {
@@ -5223,6 +5265,10 @@ var useFilterClauseEditor = ({
5223
5265
  const [operator, _setOperator] = useState23(
5224
5266
  filterClause.op
5225
5267
  );
5268
+ const findColumn = useCallback38(
5269
+ (columnName) => tableSchema.columns.find((col) => col.name === columnName),
5270
+ [tableSchema.columns]
5271
+ );
5226
5272
  const setOperator = useCallback38((op) => {
5227
5273
  _setOperator(op);
5228
5274
  }, []);
@@ -5234,10 +5280,43 @@ var useFilterClauseEditor = ({
5234
5280
  setSelectedColumn(column != null ? column : void 0);
5235
5281
  setOperator(void 0);
5236
5282
  setValue(void 0);
5237
- focusNextElement();
5283
+ setTimeout(() => {
5284
+ focusNextElement();
5285
+ }, 100);
5238
5286
  },
5239
5287
  [setOperator]
5240
5288
  );
5289
+ const removeAndNavigateToNextInputIfAtBoundary = useCallback38(
5290
+ (evt) => {
5291
+ var _a;
5292
+ const input = evt.target;
5293
+ if (input.value === "") {
5294
+ const field = input.closest(
5295
+ ".vuuFilterClauseField,[data-field]"
5296
+ );
5297
+ switch ((_a = field == null ? void 0 : field.dataset) == null ? void 0 : _a.field) {
5298
+ case "operator": {
5299
+ setOperator(void 0);
5300
+ setSelectedColumn(void 0);
5301
+ focusNextFocusableElement("bwd");
5302
+ break;
5303
+ }
5304
+ case "value": {
5305
+ setOperator(void 0);
5306
+ focusNextFocusableElement("bwd");
5307
+ break;
5308
+ }
5309
+ case "column": {
5310
+ if (clauseIsNotFirst(input)) {
5311
+ console.log("This is NOT the first clause");
5312
+ onCancel == null ? void 0 : onCancel("Backspace");
5313
+ }
5314
+ }
5315
+ }
5316
+ }
5317
+ },
5318
+ [onCancel, setOperator]
5319
+ );
5241
5320
  const handleSelectionChangeOperator = useCallback38(
5242
5321
  (evt, selected) => {
5243
5322
  const op = selected;
@@ -5269,27 +5348,75 @@ var useFilterClauseEditor = ({
5269
5348
  value: value2
5270
5349
  });
5271
5350
  }
5272
- requestAnimationFrame(() => {
5273
- focusNextElement();
5274
- });
5275
5351
  }
5276
5352
  },
5277
5353
  [onChange, operator, selectedColumn == null ? void 0 : selectedColumn.name]
5278
5354
  );
5355
+ const handleDeselectValue = useCallback38(() => {
5356
+ setValue(void 0);
5357
+ }, []);
5279
5358
  const handleKeyDownInput = useCallback38(
5280
5359
  (evt) => {
5281
5360
  if (["ArrowLeft", "ArrowRight"].includes(evt.key)) {
5282
5361
  navigateToNextInputIfAtBoundary(evt);
5283
- } else if (operator && evt.key === "Enter" && ["starts", "ends"].includes(operator)) {
5284
- console.log("enter");
5362
+ } else if (evt.key === "Backspace") {
5363
+ removeAndNavigateToNextInputIfAtBoundary(evt);
5364
+ } else if (evt.key === "Enter") {
5365
+ const input = evt.target;
5366
+ const field = input.closest("[data-field]");
5367
+ if (field.dataset.field === "column") {
5368
+ const column = findColumn(input.value);
5369
+ if (column) {
5370
+ setSelectedColumn(column);
5371
+ focusNextElement();
5372
+ }
5373
+ } else if (field.dataset.field === "value") {
5374
+ if (operator === "starts") {
5375
+ evt.stopPropagation();
5376
+ const newValue = input.value;
5377
+ setValue(newValue);
5378
+ onChange({
5379
+ column: selectedColumn == null ? void 0 : selectedColumn.name,
5380
+ op: operator,
5381
+ value: newValue
5382
+ });
5383
+ }
5384
+ }
5285
5385
  }
5286
5386
  },
5287
- [operator]
5387
+ [
5388
+ findColumn,
5389
+ onChange,
5390
+ operator,
5391
+ removeAndNavigateToNextInputIfAtBoundary,
5392
+ selectedColumn == null ? void 0 : selectedColumn.name
5393
+ ]
5288
5394
  );
5395
+ const handleClear = useCallback38(
5396
+ (e) => {
5397
+ var _a;
5398
+ const button = e.target;
5399
+ const firstInput = (_a = button.closest(".vuuFilterClause")) == null ? void 0 : _a.querySelector("input");
5400
+ setSelectedColumn(void 0);
5401
+ setOperator(void 0);
5402
+ setValue(void 0);
5403
+ setTimeout(() => {
5404
+ firstInput.select();
5405
+ firstInput == null ? void 0 : firstInput.focus();
5406
+ }, 100);
5407
+ },
5408
+ [setOperator]
5409
+ );
5410
+ const handleClearKeyDown = useCallback38((e) => {
5411
+ e.stopPropagation();
5412
+ if (e.key === "Backspace") {
5413
+ focusNextFocusableElement("bwd");
5414
+ }
5415
+ }, []);
5289
5416
  const InputProps = useMemo18(
5290
5417
  () => ({
5291
5418
  inputProps: {
5292
- onKeyDown: handleKeyDownInput
5419
+ onKeyDownCapture: handleKeyDownInput
5293
5420
  }
5294
5421
  }),
5295
5422
  [handleKeyDownInput]
@@ -5303,6 +5430,9 @@ var useFilterClauseEditor = ({
5303
5430
  InputProps,
5304
5431
  columnRef,
5305
5432
  onChangeValue: handleChangeValue,
5433
+ onClear: handleClear,
5434
+ onClearKeyDown: handleClearKeyDown,
5435
+ onDeselectValue: handleDeselectValue,
5306
5436
  onSelectionChangeColumn: handleSelectionChangeColumn,
5307
5437
  onSelectionChangeOperator: handleSelectionChangeOperator,
5308
5438
  operator,
@@ -5319,8 +5449,10 @@ import { jsx as jsx54, jsxs as jsxs26 } from "react/jsx-runtime";
5319
5449
  var classBase16 = "vuuFilterClause";
5320
5450
  var FilterClauseEditor = ({
5321
5451
  className,
5452
+ onCancel,
5322
5453
  onChange,
5323
- onClose,
5454
+ onDropdownClose,
5455
+ onDropdownOpen,
5324
5456
  filterClause,
5325
5457
  suggestionProvider,
5326
5458
  tableSchema,
@@ -5332,6 +5464,9 @@ var FilterClauseEditor = ({
5332
5464
  InputProps,
5333
5465
  columnRef,
5334
5466
  onChangeValue,
5467
+ onClear,
5468
+ onClearKeyDown,
5469
+ onDeselectValue,
5335
5470
  onSelectionChangeColumn,
5336
5471
  onSelectionChangeOperator,
5337
5472
  operator,
@@ -5341,6 +5476,7 @@ var FilterClauseEditor = ({
5341
5476
  valueRef
5342
5477
  } = useFilterClauseEditor({
5343
5478
  filterClause,
5479
+ onCancel,
5344
5480
  onChange,
5345
5481
  tableSchema
5346
5482
  });
@@ -5357,7 +5493,9 @@ var FilterClauseEditor = ({
5357
5493
  InputProps,
5358
5494
  className: (0, import_classnames29.default)(`${classBase16}Field`, `${classBase16}Value`),
5359
5495
  column: selectedColumn,
5496
+ "data-field": "value",
5360
5497
  filterClause,
5498
+ onDeselect: onDeselectValue,
5361
5499
  onInputComplete: onChangeValue,
5362
5500
  operator,
5363
5501
  ref: valueRef,
@@ -5403,29 +5541,33 @@ var FilterClauseEditor = ({
5403
5541
  /* @__PURE__ */ jsx54(
5404
5542
  ExpandoCombobox,
5405
5543
  {
5406
- title: "column",
5407
5544
  InputProps,
5545
+ allowBackspaceClearsSelection: true,
5408
5546
  className: (0, import_classnames29.default)(`${classBase16}Field`, `${classBase16}Column`),
5547
+ "data-field": "column",
5409
5548
  initialHighlightedIndex: 0,
5410
5549
  itemToString: (column) => column.name,
5550
+ onSelectionChange: onSelectionChangeColumn,
5411
5551
  ref: columnRef,
5412
5552
  source: columns,
5413
- onSelectionChange: onSelectionChangeColumn,
5553
+ title: "column",
5414
5554
  value: (_a = selectedColumn == null ? void 0 : selectedColumn.name) != null ? _a : ""
5415
5555
  }
5416
5556
  ),
5417
5557
  (selectedColumn == null ? void 0 : selectedColumn.name) ? /* @__PURE__ */ jsx54(
5418
5558
  ExpandoCombobox,
5419
5559
  {
5420
- title: "operator",
5421
5560
  InputProps,
5561
+ allowBackspaceClearsSelection: true,
5422
5562
  className: (0, import_classnames29.default)(`${classBase16}Field`, `${classBase16}Operator`, {
5423
5563
  [`${classBase16}Operator-hidden`]: selectedColumn === null
5424
5564
  }),
5565
+ "data-field": "operator",
5425
5566
  initialHighlightedIndex: 0,
5567
+ onSelectionChange: onSelectionChangeOperator,
5426
5568
  ref: operatorRef,
5427
5569
  source: getOperators(selectedColumn),
5428
- onSelectionChange: onSelectionChangeOperator,
5570
+ title: "operator",
5429
5571
  value: operator != null ? operator : ""
5430
5572
  }
5431
5573
  ) : null,
@@ -5433,8 +5575,9 @@ var FilterClauseEditor = ({
5433
5575
  value !== void 0 ? /* @__PURE__ */ jsx54(
5434
5576
  Button9,
5435
5577
  {
5436
- className: `${classBase16}-closeButton`,
5437
- onClick: onClose,
5578
+ className: `${classBase16}-clearButton`,
5579
+ onClick: onClear,
5580
+ onKeyDown: onClearKeyDown,
5438
5581
  "data-icon": "close"
5439
5582
  }
5440
5583
  ) : null
@@ -5443,8 +5586,12 @@ var FilterClauseEditor = ({
5443
5586
 
5444
5587
  // src/filter-pill/FilterPill.tsx
5445
5588
  var import_classnames31 = __toESM(require_classnames(), 1);
5589
+ import {
5590
+ Tooltip,
5591
+ useTooltip
5592
+ } from "@vuu-ui/vuu-popups/src";
5446
5593
  import { EditableLabel as EditableLabel2 } from "@vuu-ui/vuu-ui-controls";
5447
- import { filterAsQuery, isMultiClauseFilter as isMultiClauseFilter2 } from "@vuu-ui/vuu-utils";
5594
+ import { filterAsQuery, isMultiClauseFilter as isMultiClauseFilter3 } from "@vuu-ui/vuu-utils";
5448
5595
  import { useCallback as useCallback40, useRef as useRef28 } from "react";
5449
5596
 
5450
5597
  // src/filter-pill-menu/FilterPillMenu.tsx
@@ -5533,7 +5680,6 @@ var FilterPillMenu = ({
5533
5680
  import {
5534
5681
  extractFilterForColumn,
5535
5682
  isAndFilter,
5536
- isCompleteFilter,
5537
5683
  isInFilter,
5538
5684
  isMultiClauseFilter,
5539
5685
  isMultiValueFilter as isMultiValueFilter2,
@@ -5562,18 +5708,25 @@ var filterClauses = (filter, clauses = []) => {
5562
5708
  var DEFAULT_ADD_FILTER_OPTS = {
5563
5709
  combineWith: "and"
5564
5710
  };
5711
+ var removeLastClause = (filter) => {
5712
+ const { filters } = filter;
5713
+ if (filters.length > 2) {
5714
+ return {
5715
+ ...filter,
5716
+ filters: filter.filters.slice(0, -1)
5717
+ };
5718
+ } else {
5719
+ return filter.filters[0];
5720
+ }
5721
+ };
5565
5722
  var addClause = (existingFilter, clause, { combineWith = AND } = DEFAULT_ADD_FILTER_OPTS) => {
5566
5723
  if (isMultiClauseFilter(existingFilter) && existingFilter.op === combineWith) {
5567
- if (isCompleteFilter(clause)) {
5568
- return {
5569
- ...existingFilter,
5570
- filters: existingFilter.filters.concat(clause)
5571
- };
5572
- } else {
5573
- throw Error(
5574
- "filter-utils, replaceFilter, only a valid clause can be added to a filter"
5575
- );
5576
- }
5724
+ return {
5725
+ ...existingFilter,
5726
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
5727
+ // @ts-ignore
5728
+ filters: existingFilter.filters.concat(clause)
5729
+ };
5577
5730
  } else {
5578
5731
  return {
5579
5732
  op: combineWith,
@@ -5852,13 +6005,38 @@ var getNumericFilter = (column, op, value) => {
5852
6005
  return { column, op, value };
5853
6006
  };
5854
6007
 
5855
- // src/filter-pill/FilterPill.tsx
6008
+ // src/filter-pill/filterAsReactNode.tsx
6009
+ import {
6010
+ filterValue,
6011
+ isMultiClauseFilter as isMultiClauseFilter2,
6012
+ isMultiValueFilter as isMultiValueFilter3,
6013
+ quotedStrings
6014
+ } from "@vuu-ui/vuu-utils";
5856
6015
  import { jsx as jsx56, jsxs as jsxs27 } from "react/jsx-runtime";
6016
+ var filterAsReactNode = (f) => {
6017
+ if (isMultiClauseFilter2(f)) {
6018
+ return /* @__PURE__ */ jsxs27("div", { children: [
6019
+ /* @__PURE__ */ jsx56("span", { children: "Match all ..." }),
6020
+ f.filters.map((f2, i) => /* @__PURE__ */ jsx56("div", { children: filterAsReactNode(f2) }, i))
6021
+ ] });
6022
+ } else if (isMultiValueFilter3(f)) {
6023
+ if (f.values.length > 3) {
6024
+ return `${f.column} ${f.op} [${f.values.slice(0, 3).map(quotedStrings).join(",")} ...]`;
6025
+ } else {
6026
+ return `${f.column} ${f.op} [${f.values.map(quotedStrings).join(",")}]`;
6027
+ }
6028
+ } else {
6029
+ return `${f.column} ${f.op} ${filterValue(f.value)}`;
6030
+ }
6031
+ };
6032
+
6033
+ // src/filter-pill/FilterPill.tsx
6034
+ import { jsx as jsx57, jsxs as jsxs28 } from "react/jsx-runtime";
5857
6035
  var classBase18 = "vuuFilterPill";
5858
6036
  var getFilterLabel = (filter) => {
5859
6037
  if (filter.name) {
5860
6038
  return filter.name;
5861
- } else if (isMultiClauseFilter2(filter)) {
6039
+ } else if (isMultiClauseFilter3(filter)) {
5862
6040
  const [firstClause] = filterClauses(filter);
5863
6041
  return `${filterAsQuery(firstClause)} ${filter.op} ...`;
5864
6042
  } else {
@@ -5866,9 +6044,10 @@ var getFilterLabel = (filter) => {
5866
6044
  }
5867
6045
  };
5868
6046
  var FilterPill = ({
6047
+ className: classNameProp,
5869
6048
  editable = true,
5870
6049
  filter,
5871
- className: classNameProp,
6050
+ id: idProp,
5872
6051
  onBeginEdit,
5873
6052
  onExitEditMode,
5874
6053
  onMenuAction,
@@ -5880,6 +6059,7 @@ var FilterPill = ({
5880
6059
  onBeginEdit == null ? void 0 : onBeginEdit(filter);
5881
6060
  }, [filter, onBeginEdit]);
5882
6061
  const label = getFilterLabel(filter);
6062
+ const id = useId(idProp);
5883
6063
  const handleMenuClose = useCallback40((reason) => {
5884
6064
  if ((reason == null ? void 0 : reason.type) === "escape") {
5885
6065
  requestAnimationFrame(() => {
@@ -5889,15 +6069,21 @@ var FilterPill = ({
5889
6069
  });
5890
6070
  }
5891
6071
  }, []);
5892
- return /* @__PURE__ */ jsxs27(
6072
+ const { anchorProps, tooltipProps } = useTooltip({
6073
+ id,
6074
+ placement: "below",
6075
+ tooltipContent: filterAsReactNode(filter)
6076
+ });
6077
+ return /* @__PURE__ */ jsxs28(
5893
6078
  "div",
5894
6079
  {
6080
+ ...anchorProps,
5895
6081
  ...htmlAttributes,
5896
6082
  className: (0, import_classnames31.default)(classBase18, classNameProp),
5897
6083
  "data-text": label,
5898
6084
  ref: rootRef,
5899
6085
  children: [
5900
- editable && onExitEditMode ? /* @__PURE__ */ jsx56(
6086
+ editable && onExitEditMode ? /* @__PURE__ */ jsx57(
5901
6087
  EditableLabel2,
5902
6088
  {
5903
6089
  defaultValue: label,
@@ -5905,14 +6091,20 @@ var FilterPill = ({
5905
6091
  onExitEditMode
5906
6092
  },
5907
6093
  label
5908
- ) : /* @__PURE__ */ jsx56("span", { className: `${classBase18}-label`, children: label }),
5909
- showMenu && onMenuAction ? /* @__PURE__ */ jsx56(
6094
+ ) : /* @__PURE__ */ jsx57("span", { className: `${classBase18}-label`, children: label }),
6095
+ showMenu && onMenuAction ? /* @__PURE__ */ jsx57(
5910
6096
  FilterPillMenu,
5911
6097
  {
5912
6098
  filter,
5913
6099
  onMenuAction,
5914
6100
  onMenuClose: handleMenuClose
5915
6101
  }
6102
+ ) : null,
6103
+ tooltipProps ? /* @__PURE__ */ jsx57(
6104
+ Tooltip,
6105
+ {
6106
+ ...tooltipProps
6107
+ }
5916
6108
  ) : null
5917
6109
  ]
5918
6110
  }
@@ -5920,7 +6112,11 @@ var FilterPill = ({
5920
6112
  };
5921
6113
 
5922
6114
  // src/filter-bar/useFilterBar.ts
5923
- import { dispatchMouseEvent as dispatchMouseEvent2, filterAsQuery as filterAsQuery2 } from "@vuu-ui/vuu-utils";
6115
+ import {
6116
+ dispatchMouseEvent as dispatchMouseEvent2,
6117
+ filterAsQuery as filterAsQuery2,
6118
+ isMultiClauseFilter as isMultiClauseFilter4
6119
+ } from "@vuu-ui/vuu-utils";
5924
6120
  import {
5925
6121
  useCallback as useCallback42,
5926
6122
  useEffect as useEffect14,
@@ -5935,7 +6131,8 @@ import { useCallback as useCallback41 } from "react";
5935
6131
  var useFilters = ({
5936
6132
  defaultFilters,
5937
6133
  filters: filtersProp,
5938
- onFiltersChanged
6134
+ onFiltersChanged,
6135
+ tableSchema
5939
6136
  }) => {
5940
6137
  const [filters, setFilters] = useControlled5({
5941
6138
  controlled: filtersProp,
@@ -5943,6 +6140,77 @@ var useFilters = ({
5943
6140
  name: "useFilters",
5944
6141
  state: "Filters"
5945
6142
  });
6143
+ const { getApplicationSettings, saveApplicationSettings } = useLayoutManager();
6144
+ const hasFilter = (filters2, name) => filters2.findIndex((f) => f.name === name) !== -1;
6145
+ const saveFilterToSettings = useCallback41(
6146
+ (filter, name) => {
6147
+ if (tableSchema && name) {
6148
+ const savedFilters = getApplicationSettings(
6149
+ "filters"
6150
+ );
6151
+ let newFilters = savedFilters;
6152
+ const { module, table } = tableSchema.table;
6153
+ const key = `${module}:${table}`;
6154
+ if (savedFilters) {
6155
+ if (savedFilters[key]) {
6156
+ if (hasFilter(savedFilters[key], name)) {
6157
+ newFilters = {
6158
+ ...savedFilters,
6159
+ [key]: savedFilters[key].map(
6160
+ (f) => f.name === name ? { ...filter, name } : f
6161
+ )
6162
+ };
6163
+ } else if ((filter == null ? void 0 : filter.name) && (filter == null ? void 0 : filter.name) !== name && hasFilter(savedFilters[key], filter.name)) {
6164
+ newFilters = {
6165
+ ...savedFilters,
6166
+ [key]: savedFilters[key].map(
6167
+ (f) => f.name === filter.name ? { ...filter, name } : f
6168
+ )
6169
+ };
6170
+ } else {
6171
+ newFilters = {
6172
+ ...savedFilters,
6173
+ [key]: savedFilters[key].concat({ ...filter, name })
6174
+ };
6175
+ }
6176
+ } else {
6177
+ newFilters = {
6178
+ ...savedFilters,
6179
+ [key]: [{ ...filter, name }]
6180
+ };
6181
+ }
6182
+ } else {
6183
+ newFilters = {
6184
+ [key]: [{ ...filter, name }]
6185
+ };
6186
+ }
6187
+ if (newFilters !== savedFilters) {
6188
+ saveApplicationSettings(newFilters, "filters");
6189
+ }
6190
+ }
6191
+ },
6192
+ [getApplicationSettings, saveApplicationSettings, tableSchema]
6193
+ );
6194
+ const removeFilterFromSettings = useCallback41(
6195
+ (filter) => {
6196
+ var _a;
6197
+ if (tableSchema && filter.name) {
6198
+ const savedFilters = getApplicationSettings(
6199
+ "filters"
6200
+ );
6201
+ const { module, table } = tableSchema.table;
6202
+ const key = `${module}:${table}`;
6203
+ if (((_a = savedFilters[key]) == null ? void 0 : _a.findIndex((f) => f.name === filter.name)) !== -1) {
6204
+ const newSavedFilters = {
6205
+ ...savedFilters,
6206
+ [key]: savedFilters[key].filter((f) => f.name !== filter.name)
6207
+ };
6208
+ saveApplicationSettings(newSavedFilters, "filters");
6209
+ }
6210
+ }
6211
+ },
6212
+ [getApplicationSettings, saveApplicationSettings, tableSchema]
6213
+ );
5946
6214
  const handleAddFilter = useCallback41(
5947
6215
  (filter) => {
5948
6216
  const index = filters.length;
@@ -5955,6 +6223,9 @@ var useFilters = ({
5955
6223
  );
5956
6224
  const handleDeleteFilter = useCallback41(
5957
6225
  (filter) => {
6226
+ console.log(`handleDeleteFilter`, {
6227
+ filter
6228
+ });
5958
6229
  let index = -1;
5959
6230
  const newFilters = filters.filter((f, i) => {
5960
6231
  if (f !== filter) {
@@ -5966,9 +6237,10 @@ var useFilters = ({
5966
6237
  });
5967
6238
  setFilters(newFilters);
5968
6239
  onFiltersChanged == null ? void 0 : onFiltersChanged(newFilters);
6240
+ removeFilterFromSettings(filter);
5969
6241
  return index;
5970
6242
  },
5971
- [filters, onFiltersChanged, setFilters]
6243
+ [filters, onFiltersChanged, removeFilterFromSettings, setFilters]
5972
6244
  );
5973
6245
  const handleRenameFilter = useCallback41(
5974
6246
  (filter, name) => {
@@ -5983,9 +6255,10 @@ var useFilters = ({
5983
6255
  });
5984
6256
  setFilters(newFilters);
5985
6257
  onFiltersChanged == null ? void 0 : onFiltersChanged(newFilters);
6258
+ saveFilterToSettings(filter, name);
5986
6259
  return index;
5987
6260
  },
5988
- [filters, onFiltersChanged, setFilters]
6261
+ [filters, onFiltersChanged, saveFilterToSettings, setFilters]
5989
6262
  );
5990
6263
  const handleChangeFilter = useCallback41(
5991
6264
  (filter) => {
@@ -6022,7 +6295,8 @@ var useFilterBar = ({
6022
6295
  onApplyFilter,
6023
6296
  onChangeActiveFilterIndex: onChangeActiveFilterIndexProp,
6024
6297
  onFiltersChanged,
6025
- showMenu: showMenuProp
6298
+ showMenu: showMenuProp,
6299
+ tableSchema
6026
6300
  }) => {
6027
6301
  const addButtonRef = useRef29(null);
6028
6302
  const editingFilter = useRef29();
@@ -6038,7 +6312,8 @@ var useFilterBar = ({
6038
6312
  onRenameFilter
6039
6313
  } = useFilters({
6040
6314
  filters: filtersProp,
6041
- onFiltersChanged
6315
+ onFiltersChanged,
6316
+ tableSchema
6042
6317
  });
6043
6318
  const editPillLabel = useCallback42(
6044
6319
  (index) => {
@@ -6214,12 +6489,16 @@ var useFilterBar = ({
6214
6489
  setShowMenu(false);
6215
6490
  return true;
6216
6491
  }
6217
- case "and-clause":
6218
- setEditFilter(
6219
- (filter) => addClause(filter, EMPTY_FILTER_CLAUSE)
6492
+ case "and-clause": {
6493
+ const newFilter = addClause(
6494
+ editFilter,
6495
+ EMPTY_FILTER_CLAUSE
6220
6496
  );
6497
+ console.log({ newFilter });
6498
+ setEditFilter(newFilter);
6221
6499
  setShowMenu(false);
6222
6500
  return true;
6501
+ }
6223
6502
  case "or-clause":
6224
6503
  setEditFilter(
6225
6504
  (filter) => addClause(filter, {}, { combineWith: "or" })
@@ -6259,7 +6538,7 @@ var useFilterBar = ({
6259
6538
  );
6260
6539
  const handleClickAddFilter = useCallback42(() => {
6261
6540
  setEditFilter({});
6262
- }, []);
6541
+ }, [setEditFilter]);
6263
6542
  const handleClickRemoveFilter = useCallback42(() => {
6264
6543
  setEditFilter(void 0);
6265
6544
  }, []);
@@ -6268,13 +6547,43 @@ var useFilterBar = ({
6268
6547
  onMenuAction: handlePillMenuAction,
6269
6548
  onExitEditMode: handleExitEditFilterName
6270
6549
  };
6271
- const handleChangeFilterClause = (filterClause) => {
6272
- if (filterClause !== void 0) {
6273
- setEditFilter((filter) => replaceClause(filter, filterClause));
6274
- setShowMenu(true);
6550
+ const handleChangeFilterClause = useCallback42(
6551
+ (filterClause) => {
6552
+ console.log(`handleCHangeFilterClause ${JSON.stringify(filterClause)}`);
6553
+ if (filterClause !== void 0) {
6554
+ const newFilter = replaceClause(editFilter, filterClause);
6555
+ setEditFilter(newFilter);
6556
+ setShowMenu(true);
6557
+ }
6558
+ },
6559
+ [editFilter]
6560
+ );
6561
+ const handleCancelFilterClause = useCallback42(
6562
+ (reason) => {
6563
+ if (reason === "Backspace" && isMultiClauseFilter4(editFilter)) {
6564
+ setEditFilter(removeLastClause(editFilter));
6565
+ }
6566
+ },
6567
+ [editFilter]
6568
+ );
6569
+ const handleBlurFilterClause = useCallback42((e) => {
6570
+ const target = e.target;
6571
+ const relatedTarget = e.relatedTarget;
6572
+ const filterClause = target.closest(".vuuFilterClause");
6573
+ if (filterClause == null ? void 0 : filterClause.contains(relatedTarget)) {
6574
+ } else {
6575
+ const dropdownId = target.getAttribute("aria-owns");
6576
+ const dropDown = dropdownId ? document.getElementById(dropdownId) : null;
6577
+ if (dropDown == null ? void 0 : dropDown.contains(relatedTarget)) {
6578
+ } else {
6579
+ setShowMenu(true);
6580
+ }
6275
6581
  }
6276
- };
6277
- const onKeyDown = useCallback42(
6582
+ }, []);
6583
+ const handleFocusFilterClause = useCallback42(() => {
6584
+ setShowMenu(false);
6585
+ }, []);
6586
+ const handleKeyDownFilterbar = useCallback42(
6278
6587
  (evt) => {
6279
6588
  if (evt.key === "Escape" && editFilter !== void 0) {
6280
6589
  setEditFilter(void 0);
@@ -6284,6 +6593,39 @@ var useFilterBar = ({
6284
6593
  },
6285
6594
  [editFilter]
6286
6595
  );
6596
+ const handleKeyDownMenu = useCallback42(
6597
+ (evt) => {
6598
+ var _a;
6599
+ console.log(`keydown from List ${evt.key}`);
6600
+ const { current: container } = containerRef;
6601
+ if (evt.key === "Backspace" && container) {
6602
+ evt.preventDefault();
6603
+ const fields = Array.from(
6604
+ container.querySelectorAll(".vuuFilterClauseField")
6605
+ );
6606
+ if (fields.length > 0) {
6607
+ const field = fields.at(-1);
6608
+ (_a = field == null ? void 0 : field.querySelector("input")) == null ? void 0 : _a.focus();
6609
+ }
6610
+ setShowMenu(false);
6611
+ } else if (evt.key === "Tab") {
6612
+ if (evt.shiftKey && container) {
6613
+ const clearButtons = Array.from(
6614
+ container.querySelectorAll(".vuuFilterClause-clearButton")
6615
+ );
6616
+ if (clearButtons.length > 0) {
6617
+ const clearButton = clearButtons.at(-1);
6618
+ setTimeout(() => {
6619
+ clearButton.focus();
6620
+ }, 100);
6621
+ }
6622
+ } else {
6623
+ console.log("apply current selection");
6624
+ }
6625
+ }
6626
+ },
6627
+ [containerRef]
6628
+ );
6287
6629
  const handleAddButtonKeyDown = useCallback42((evt) => {
6288
6630
  if (evt.key === "ArrowLeft") {
6289
6631
  console.log("navgiate to the Toolbar");
@@ -6304,11 +6646,15 @@ var useFilterBar = ({
6304
6646
  addButtonProps,
6305
6647
  editFilter,
6306
6648
  filters,
6649
+ onBlurFilterClause: handleBlurFilterClause,
6650
+ onCancelFilterClause: handleCancelFilterClause,
6307
6651
  onChangeActiveFilterIndex: handleChangeActiveFilterIndex,
6308
6652
  onClickAddFilter: handleClickAddFilter,
6309
6653
  onClickRemoveFilter: handleClickRemoveFilter,
6310
6654
  onChangeFilterClause: handleChangeFilterClause,
6311
- onKeyDown,
6655
+ onFocusFilterClause: handleFocusFilterClause,
6656
+ onKeyDownFilterbar: handleKeyDownFilterbar,
6657
+ onKeyDownMenu: handleKeyDownMenu,
6312
6658
  onMenuAction: handleMenuAction,
6313
6659
  onNavigateOutOfBounds: handlePillNavigationOutOfBounds,
6314
6660
  pillProps,
@@ -6317,8 +6663,53 @@ var useFilterBar = ({
6317
6663
  };
6318
6664
  };
6319
6665
 
6666
+ // src/filter-bar/FilterBarMenu.tsx
6667
+ import { PopupMenu as PopupMenu3 } from "@vuu-ui/vuu-popups";
6668
+
6669
+ // src/filter-bar/useFilterBarMenu.ts
6670
+ import { useCallback as useCallback43, useMemo as useMemo21 } from "react";
6671
+ var useFilterBarMenu = () => {
6672
+ const menuBuilder = useCallback43(() => {
6673
+ return [
6674
+ {
6675
+ label: `You have no saved filters for this table`,
6676
+ action: `no-action`
6677
+ }
6678
+ ];
6679
+ }, []);
6680
+ const menuActionHandler = useMemo21(
6681
+ () => (action) => {
6682
+ console.log(`invoke menuId `, {
6683
+ action
6684
+ });
6685
+ return false;
6686
+ },
6687
+ []
6688
+ );
6689
+ return {
6690
+ menuBuilder,
6691
+ menuActionHandler
6692
+ };
6693
+ };
6694
+
6695
+ // src/filter-bar/FilterBarMenu.tsx
6696
+ import { jsx as jsx58 } from "react/jsx-runtime";
6697
+ var FilterBarMenu = () => {
6698
+ const classBase21 = "vuuFilterBarMenu";
6699
+ const { menuBuilder, menuActionHandler } = useFilterBarMenu();
6700
+ return /* @__PURE__ */ jsx58("div", { className: classBase21, children: /* @__PURE__ */ jsx58(
6701
+ PopupMenu3,
6702
+ {
6703
+ icon: "tune",
6704
+ menuBuilder,
6705
+ menuActionHandler,
6706
+ tabIndex: -1
6707
+ }
6708
+ ) });
6709
+ };
6710
+
6320
6711
  // src/filter-bar/FilterBar.tsx
6321
- import { jsx as jsx57, jsxs as jsxs28 } from "react/jsx-runtime";
6712
+ import { jsx as jsx59, jsxs as jsxs29 } from "react/jsx-runtime";
6322
6713
  import { createElement } from "react";
6323
6714
  var classBase19 = "vuuFilterBar";
6324
6715
  var FilterBar = ({
@@ -6339,12 +6730,16 @@ var FilterBar = ({
6339
6730
  addButtonProps,
6340
6731
  editFilter,
6341
6732
  filters,
6733
+ onBlurFilterClause,
6734
+ onCancelFilterClause,
6342
6735
  onClickAddFilter,
6343
6736
  onClickRemoveFilter,
6344
6737
  onChangeFilterClause,
6345
6738
  onChangeActiveFilterIndex,
6739
+ onFocusFilterClause,
6346
6740
  onNavigateOutOfBounds,
6347
- onKeyDown,
6741
+ onKeyDownFilterbar,
6742
+ onKeyDownMenu,
6348
6743
  onMenuAction,
6349
6744
  pillProps,
6350
6745
  promptProps,
@@ -6356,13 +6751,13 @@ var FilterBar = ({
6356
6751
  onApplyFilter,
6357
6752
  onChangeActiveFilterIndex: onChangeActiveFilterIndexProp,
6358
6753
  onFiltersChanged,
6359
- showMenu: showMenuProp
6754
+ showMenu: showMenuProp,
6755
+ tableSchema
6360
6756
  });
6361
6757
  const className = (0, import_classnames32.default)(classBase19, classNameProp, {
6362
6758
  [`${classBase19}-display`]: editFilter === void 0,
6363
6759
  [`${classBase19}-edit`]: editFilter !== void 0
6364
6760
  });
6365
- const onClose = () => console.log("Closing filter component");
6366
6761
  const getChildren2 = () => {
6367
6762
  const items = [];
6368
6763
  if (editFilter === void 0) {
@@ -6382,8 +6777,10 @@ var FilterBar = ({
6382
6777
  ...FilterClauseEditorProps2,
6383
6778
  filterClause,
6384
6779
  key: `editor-${i}`,
6780
+ onCancel: onCancelFilterClause,
6385
6781
  onChange: onChangeFilterClause,
6386
- onClose,
6782
+ onBlur: onBlurFilterClause,
6783
+ onFocus: onFocusFilterClause,
6387
6784
  tableSchema
6388
6785
  }
6389
6786
  )
@@ -6391,11 +6788,18 @@ var FilterBar = ({
6391
6788
  });
6392
6789
  if (showMenu) {
6393
6790
  items.push(
6394
- /* @__PURE__ */ jsx57(FilterBuilderMenu, { onMenuAction }, "menu")
6791
+ /* @__PURE__ */ jsx59(
6792
+ FilterBuilderMenu,
6793
+ {
6794
+ onMenuAction,
6795
+ ListProps: { onKeyDownCapture: onKeyDownMenu }
6796
+ },
6797
+ "menu"
6798
+ )
6395
6799
  );
6396
6800
  }
6397
6801
  items.push(
6398
- /* @__PURE__ */ jsx57(
6802
+ /* @__PURE__ */ jsx59(
6399
6803
  Button10,
6400
6804
  {
6401
6805
  className: `${classBase19}-remove`,
@@ -6410,16 +6814,16 @@ var FilterBar = ({
6410
6814
  return items;
6411
6815
  }
6412
6816
  };
6413
- return /* @__PURE__ */ jsxs28(
6817
+ return /* @__PURE__ */ jsxs29(
6414
6818
  "div",
6415
6819
  {
6416
6820
  ...htmlAttributes,
6417
6821
  className,
6418
- onKeyDown,
6822
+ onKeyDown: onKeyDownFilterbar,
6419
6823
  ref: rootRef,
6420
6824
  children: [
6421
- /* @__PURE__ */ jsx57("span", { className: `${classBase19}-icon`, "data-icon": "tune" }),
6422
- /* @__PURE__ */ jsx57(
6825
+ /* @__PURE__ */ jsx59(FilterBarMenu, {}),
6826
+ /* @__PURE__ */ jsx59(
6423
6827
  Toolbar,
6424
6828
  {
6425
6829
  activeItemIndex: activeFilterIndex,
@@ -6443,7 +6847,7 @@ var FilterBar = ({
6443
6847
  variant: "primary"
6444
6848
  }
6445
6849
  ) : null,
6446
- promptProps ? /* @__PURE__ */ jsx57(
6850
+ promptProps ? /* @__PURE__ */ jsx59(
6447
6851
  Prompt,
6448
6852
  {
6449
6853
  ...promptProps,
@@ -9460,8 +9864,8 @@ var parser = LRParser.deserialize({
9460
9864
 
9461
9865
  // ../vuu-filter-parser/src/FilterTreeWalker.ts
9462
9866
  import {
9463
- isMultiClauseFilter as isMultiClauseFilter3,
9464
- isMultiValueFilter as isMultiValueFilter3,
9867
+ isMultiClauseFilter as isMultiClauseFilter5,
9868
+ isMultiValueFilter as isMultiValueFilter4,
9465
9869
  isSingleValueFilter as isSingleValueFilter3
9466
9870
  } from "@vuu-ui/vuu-utils";
9467
9871
  var _filter;
@@ -9470,7 +9874,7 @@ var FilterExpression = class {
9470
9874
  __privateAdd(this, _filter, void 0);
9471
9875
  }
9472
9876
  setFilterCombinatorOp(op, filter = __privateGet(this, _filter)) {
9473
- if (isMultiClauseFilter3(filter) && filter.op === op) {
9877
+ if (isMultiClauseFilter5(filter) && filter.op === op) {
9474
9878
  return;
9475
9879
  } else {
9476
9880
  __privateSet(this, _filter, {
@@ -9482,14 +9886,14 @@ var FilterExpression = class {
9482
9886
  add(filter) {
9483
9887
  if (__privateGet(this, _filter) === void 0) {
9484
9888
  __privateSet(this, _filter, filter);
9485
- } else if (isMultiClauseFilter3(__privateGet(this, _filter))) {
9889
+ } else if (isMultiClauseFilter5(__privateGet(this, _filter))) {
9486
9890
  __privateGet(this, _filter).filters.push(filter);
9487
9891
  } else {
9488
9892
  throw Error(`Invalid filter passed to FilterExpression`);
9489
9893
  }
9490
9894
  }
9491
9895
  setColumn(column, filter = __privateGet(this, _filter)) {
9492
- if (isMultiClauseFilter3(filter)) {
9896
+ if (isMultiClauseFilter5(filter)) {
9493
9897
  const target = filter.filters.at(-1);
9494
9898
  if (target) {
9495
9899
  this.setColumn(column, target);
@@ -9499,7 +9903,7 @@ var FilterExpression = class {
9499
9903
  }
9500
9904
  }
9501
9905
  setOp(value, filter = __privateGet(this, _filter)) {
9502
- if (isMultiClauseFilter3(filter)) {
9906
+ if (isMultiClauseFilter5(filter)) {
9503
9907
  const target = filter.filters.at(-1);
9504
9908
  if (target) {
9505
9909
  this.setOp(value, target);
@@ -9510,12 +9914,12 @@ var FilterExpression = class {
9510
9914
  }
9511
9915
  setValue(value, filter = __privateGet(this, _filter)) {
9512
9916
  var _a;
9513
- if (isMultiClauseFilter3(filter)) {
9917
+ if (isMultiClauseFilter5(filter)) {
9514
9918
  const target = filter.filters.at(-1);
9515
9919
  if (target) {
9516
9920
  this.setValue(value, target);
9517
9921
  }
9518
- } else if (isMultiValueFilter3(filter)) {
9922
+ } else if (isMultiValueFilter4(filter)) {
9519
9923
  (_a = filter.values) != null ? _a : filter.values = [];
9520
9924
  filter.values.push(value);
9521
9925
  } else if (isSingleValueFilter3(filter)) {
@@ -9582,7 +9986,7 @@ var strictParser = parser.configure({ strict: true });
9582
9986
 
9583
9987
  // src/filter-input/useCodeMirrorEditor.ts
9584
9988
  var import_classnames33 = __toESM(require_classnames(), 1);
9585
- import { useEffect as useEffect15, useMemo as useMemo21, useRef as useRef31 } from "react";
9989
+ import { useEffect as useEffect15, useMemo as useMemo22, useRef as useRef31 } from "react";
9586
9990
 
9587
9991
  // src/filter-input/FilterLanguage.ts
9588
9992
  import {
@@ -9701,7 +10105,7 @@ import {
9701
10105
  getValue,
9702
10106
  syntaxTree
9703
10107
  } from "@vuu-ui/vuu-codemirror";
9704
- import { useCallback as useCallback43 } from "react";
10108
+ import { useCallback as useCallback44 } from "react";
9705
10109
  var getOperator = (node, state) => {
9706
10110
  let maybeColumnNode = node.prevSibling || node.parent;
9707
10111
  while (maybeColumnNode && !["Column", "Operator", "In"].includes(maybeColumnNode.name)) {
@@ -9771,7 +10175,7 @@ var getSetValues = (node, state) => {
9771
10175
  return values;
9772
10176
  };
9773
10177
  var useAutoComplete = (suggestionProvider, onSubmit, existingFilter) => {
9774
- const makeSuggestions = useCallback43(
10178
+ const makeSuggestions = useCallback44(
9775
10179
  async (context, suggestionType, optionalArgs = {}) => {
9776
10180
  const { startsWith = "" } = optionalArgs;
9777
10181
  const options = await suggestionProvider.getSuggestions(
@@ -9782,7 +10186,7 @@ var useAutoComplete = (suggestionProvider, onSubmit, existingFilter) => {
9782
10186
  },
9783
10187
  [suggestionProvider]
9784
10188
  );
9785
- return useCallback43(
10189
+ return useCallback44(
9786
10190
  async (context) => {
9787
10191
  var _a, _b;
9788
10192
  const { state, pos } = context;
@@ -9974,7 +10378,7 @@ var useCodeMirrorEditor = ({
9974
10378
  onSubmit,
9975
10379
  existingFilter
9976
10380
  );
9977
- const [createState, clearInput] = useMemo21(() => {
10381
+ const [createState, clearInput] = useMemo22(() => {
9978
10382
  const parseFilter2 = () => {
9979
10383
  const view = getView(viewRef);
9980
10384
  const source = view.state.doc.toString();
@@ -10066,7 +10470,7 @@ var useCodeMirrorEditor = ({
10066
10470
  };
10067
10471
 
10068
10472
  // src/filter-input/FilterInput.tsx
10069
- import { jsx as jsx58, jsxs as jsxs29 } from "react/jsx-runtime";
10473
+ import { jsx as jsx60, jsxs as jsxs30 } from "react/jsx-runtime";
10070
10474
  var classBase20 = "vuuFilterInput";
10071
10475
  var FilterInput = ({
10072
10476
  existingFilter,
@@ -10081,8 +10485,8 @@ var FilterInput = ({
10081
10485
  onSubmitFilter,
10082
10486
  suggestionProvider
10083
10487
  });
10084
- return /* @__PURE__ */ jsxs29("div", { ...props, className: classBase20, children: [
10085
- /* @__PURE__ */ jsx58(
10488
+ return /* @__PURE__ */ jsxs30("div", { ...props, className: classBase20, children: [
10489
+ /* @__PURE__ */ jsx60(
10086
10490
  Button11,
10087
10491
  {
10088
10492
  className: `${classBase20}-FilterButton`,
@@ -10090,8 +10494,8 @@ var FilterInput = ({
10090
10494
  tabIndex: -1
10091
10495
  }
10092
10496
  ),
10093
- /* @__PURE__ */ jsx58("div", { className: `${classBase20}-Editor`, ref: editorRef }),
10094
- /* @__PURE__ */ jsx58(
10497
+ /* @__PURE__ */ jsx60("div", { className: `${classBase20}-Editor`, ref: editorRef }),
10498
+ /* @__PURE__ */ jsx60(
10095
10499
  Button11,
10096
10500
  {
10097
10501
  className: `${classBase20}-ClearButton`,
@@ -10115,7 +10519,7 @@ import {
10115
10519
  getTypeaheadParams,
10116
10520
  useTypeaheadSuggestions as useTypeaheadSuggestions2
10117
10521
  } from "@vuu-ui/vuu-data-react";
10118
- import { useCallback as useCallback44, useRef as useRef32 } from "react";
10522
+ import { useCallback as useCallback45, useRef as useRef32 } from "react";
10119
10523
 
10120
10524
  // src/filter-input/filterInfo.ts
10121
10525
  import { createEl } from "@vuu-ui/vuu-utils";
@@ -10213,7 +10617,7 @@ var useFilterSuggestionProvider = ({
10213
10617
  }) => {
10214
10618
  const latestSuggestionsRef = useRef32();
10215
10619
  const getTypeaheadSuggestions = useTypeahead();
10216
- const getSuggestions = useCallback44(
10620
+ const getSuggestions = useCallback45(
10217
10621
  async (suggestionType, options = NONE) => {
10218
10622
  const {
10219
10623
  columnName,
@@ -10303,7 +10707,7 @@ var useFilterSuggestionProvider = ({
10303
10707
  },
10304
10708
  [columns, getTypeaheadSuggestions, namedFilters, saveOptions, table]
10305
10709
  );
10306
- const isPartialMatch = useCallback44(
10710
+ const isPartialMatch = useCallback45(
10307
10711
  async (valueType, columnName, pattern) => {
10308
10712
  const suggestions = (
10309
10713
  // latestSuggestions && latestSuggestions.length > 0
@@ -10370,6 +10774,7 @@ export {
10370
10774
  getTypeaheadFilter,
10371
10775
  overrideColName,
10372
10776
  removeFilter,
10777
+ removeLastClause,
10373
10778
  replaceClause,
10374
10779
  saveLocalEntity,
10375
10780
  splitFilterOnColumn,