@vuu-ui/vuu-filters 0.8.27-debug → 0.8.28-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 (40) hide show
  1. package/cjs/index.js +1553 -1089
  2. package/cjs/index.js.map +4 -4
  3. package/esm/index.js +1540 -1059
  4. package/esm/index.js.map +4 -4
  5. package/index.css +48 -81
  6. package/index.css.map +3 -3
  7. package/package.json +9 -9
  8. package/types/FilterModel.d.ts +43 -0
  9. package/types/filter-bar/FilterBar.d.ts +3 -4
  10. package/types/filter-bar/filterBarFocusManagement.d.ts +1 -0
  11. package/types/filter-bar/useFilterBar.d.ts +16 -21
  12. package/types/filter-bar/useFilterState.d.ts +1 -1
  13. package/types/filter-clause/FilterClause.d.ts +18 -0
  14. package/types/filter-clause/FilterMenu.d.ts +0 -1
  15. package/types/filter-clause/filterClauseFocusManagement.d.ts +16 -0
  16. package/types/filter-clause/filterClauseTypes.d.ts +3 -2
  17. package/types/filter-clause/index.d.ts +2 -2
  18. package/types/filter-clause/useFilterClause.d.ts +24 -0
  19. package/types/filter-clause/value-editors/FilterClauseValueEditor.d.ts +13 -0
  20. package/types/filter-clause/value-editors/FilterClauseValueEditorDate.d.ts +10 -0
  21. package/types/filter-clause/value-editors/FilterClauseValueEditorNumber.d.ts +10 -0
  22. package/types/filter-clause/value-editors/FilterClauseValueEditorText.d.ts +11 -0
  23. package/types/filter-editor/FilterClauseCombinator.d.ts +10 -0
  24. package/types/filter-editor/FilterEditor.d.ts +17 -0
  25. package/types/filter-editor/index.d.ts +1 -0
  26. package/types/filter-editor/useFilterEditor.d.ts +31 -0
  27. package/types/filter-pill/FilterPill.d.ts +8 -5
  28. package/types/filter-pill/FilterPillMenuOptions.d.ts +12 -0
  29. package/types/filter-pill/getFilterTooltipText.d.ts +2 -0
  30. package/types/filter-pill-menu/FilterPillMenu.d.ts +1 -1
  31. package/types/filter-utils.d.ts +0 -1
  32. package/types/index.d.ts +2 -1
  33. package/types/filter-builder-menu/FilterBuilderMenu.d.ts +0 -10
  34. package/types/filter-builder-menu/index.d.ts +0 -1
  35. package/types/filter-clause/DateInput.d.ts +0 -9
  36. package/types/filter-clause/FilterClauseEditor.d.ts +0 -17
  37. package/types/filter-clause/FilterClauseTextValueEditor.d.ts +0 -11
  38. package/types/filter-clause/FilterClauseValueEditor.d.ts +0 -9
  39. package/types/filter-clause/NumericInput.d.ts +0 -9
  40. package/types/filter-clause/useFilterClauseEditor.d.ts +0 -32
package/cjs/index.js CHANGED
@@ -43,10 +43,12 @@ __export(src_exports, {
43
43
  EQUALS: () => EQUALS,
44
44
  ExpandoCombobox: () => ExpandoCombobox,
45
45
  FilterBar: () => FilterBar,
46
- FilterBuilderMenu: () => FilterBuilderMenu,
47
- FilterClauseEditor: () => FilterClauseEditor,
48
- FilterClauseTextValueEditor: () => FilterClauseTextValueEditor,
46
+ FilterClause: () => FilterClause,
47
+ FilterClauseModel: () => FilterClauseModel,
48
+ FilterClauseValueEditorText: () => FilterClauseValueEditorText,
49
+ FilterEditor: () => FilterEditor,
49
50
  FilterInput: () => FilterInput,
51
+ FilterModel: () => FilterModel,
50
52
  FilterPill: () => FilterPill,
51
53
  GREATER_THAN: () => GREATER_THAN,
52
54
  IN: () => IN,
@@ -65,7 +67,6 @@ __export(src_exports, {
65
67
  overrideColName: () => overrideColName,
66
68
  removeFilter: () => removeFilter,
67
69
  removeLastClause: () => removeLastClause,
68
- replaceClause: () => replaceClause,
69
70
  saveLocalEntity: () => saveLocalEntity,
70
71
  splitFilterOnColumn: () => splitFilterOnColumn,
71
72
  updateFilter: () => updateFilter,
@@ -74,10 +75,220 @@ __export(src_exports, {
74
75
  });
75
76
  module.exports = __toCommonJS(src_exports);
76
77
 
78
+ // src/FilterModel.ts
79
+ var import_vuu_utils = require("@vuu-ui/vuu-utils");
80
+ var hasValues = ({ values }) => Array.isArray(values) && values.length > 0;
81
+ var isValidFilterClause = (filterClause) => {
82
+ if (filterClause.op === void 0 || filterClause.column === void 0) {
83
+ return false;
84
+ } else if ((0, import_vuu_utils.isMultiValueFilter)(filterClause)) {
85
+ return hasValues(filterClause);
86
+ } else if ((0, import_vuu_utils.isSingleValueFilter)(filterClause)) {
87
+ return filterClause.value !== void 0 && filterClause.value !== "";
88
+ }
89
+ throw Error("isValidFilterClause should never reach this far");
90
+ };
91
+ var isValidFilter = (filter) => {
92
+ if (filter === void 0) {
93
+ return false;
94
+ } else if ((0, import_vuu_utils.isMultiClauseFilter)(filter)) {
95
+ return filter.filters.every(isValidFilter);
96
+ } else {
97
+ return isValidFilterClause(filter);
98
+ }
99
+ };
100
+ var isValidFilterModel = (filterModel) => {
101
+ if (filterModel.isMultiClauseFilter) {
102
+ return filterModel.filterClauses.every((f) => f.isValid);
103
+ } else {
104
+ return filterModel.filterClauses.length === 1 && filterModel.filterClauses[0].isValid;
105
+ }
106
+ };
107
+ var _filterClause, _isValid;
108
+ var FilterClauseModel = class extends import_vuu_utils.EventEmitter {
109
+ constructor(filterClause) {
110
+ super();
111
+ __privateAdd(this, _filterClause, void 0);
112
+ __privateAdd(this, _isValid, void 0);
113
+ __privateSet(this, _filterClause, filterClause);
114
+ __privateSet(this, _isValid, isValidFilterClause(filterClause));
115
+ }
116
+ get isValid() {
117
+ return __privateGet(this, _isValid);
118
+ }
119
+ setIsValid(isValid) {
120
+ __privateSet(this, _isValid, isValid);
121
+ this.emit("isValid", isValid);
122
+ }
123
+ get column() {
124
+ return __privateGet(this, _filterClause).column;
125
+ }
126
+ set column(column) {
127
+ __privateSet(this, _filterClause, {
128
+ column
129
+ });
130
+ const isValid = isValidFilterClause(__privateGet(this, _filterClause));
131
+ this.emit("filterClause", __privateGet(this, _filterClause), isValid);
132
+ if (isValid !== __privateGet(this, _isValid)) {
133
+ this.setIsValid(isValid);
134
+ }
135
+ }
136
+ get op() {
137
+ return __privateGet(this, _filterClause).op;
138
+ }
139
+ setOp(op) {
140
+ __privateSet(this, _filterClause, {
141
+ ...__privateGet(this, _filterClause),
142
+ op
143
+ });
144
+ const isValid = isValidFilterClause(__privateGet(this, _filterClause));
145
+ this.emit("filterClause", __privateGet(this, _filterClause), isValid);
146
+ if (isValid !== __privateGet(this, _isValid)) {
147
+ this.setIsValid(isValid);
148
+ }
149
+ }
150
+ setValue(value, isFinal = true) {
151
+ console.log(`setValue ${value} isFinal(${isFinal})`);
152
+ if ((0, import_vuu_utils.isSingleValueFilter)(__privateGet(this, _filterClause))) {
153
+ __privateSet(this, _filterClause, {
154
+ ...__privateGet(this, _filterClause),
155
+ value
156
+ });
157
+ } else if (Array.isArray(value)) {
158
+ __privateSet(this, _filterClause, {
159
+ ...__privateGet(this, _filterClause),
160
+ values: value
161
+ });
162
+ }
163
+ const isValid = isValidFilterClause(__privateGet(this, _filterClause));
164
+ if (isValid !== __privateGet(this, _isValid)) {
165
+ this.setIsValid(isValid);
166
+ }
167
+ if (isFinal) {
168
+ this.emit("filterClause", __privateGet(this, _filterClause), isValid);
169
+ }
170
+ }
171
+ asFilter(throwIfInvalid = true) {
172
+ if (throwIfInvalid && !__privateGet(this, _isValid)) {
173
+ throw Error("Invalid filter model cannot be returned as Filter");
174
+ }
175
+ return __privateGet(this, _filterClause);
176
+ }
177
+ };
178
+ _filterClause = new WeakMap();
179
+ _isValid = new WeakMap();
180
+ var _children, _isValid2, _op;
181
+ var FilterModel = class extends import_vuu_utils.EventEmitter {
182
+ constructor(filter) {
183
+ super();
184
+ __privateAdd(this, _children, []);
185
+ __privateAdd(this, _isValid2, void 0);
186
+ __privateAdd(this, _op, void 0);
187
+ this.onFilterClauseChange = () => {
188
+ this.emit("filter", this.asFilter(false), __privateGet(this, _isValid2));
189
+ };
190
+ this.onFilterClauseStatusChange = (isValid) => {
191
+ if (!isValid && __privateGet(this, _isValid2)) {
192
+ this.setIsValid(false);
193
+ } else {
194
+ this.checkValidStatus();
195
+ }
196
+ };
197
+ if ((0, import_vuu_utils.isMultiClauseFilter)(filter)) {
198
+ __privateSet(this, _op, filter.op);
199
+ filter.filters.forEach((f) => this.addFilterClause(f));
200
+ } else if (filter) {
201
+ this.addFilterClause(filter);
202
+ } else {
203
+ this.addNewFilterClause();
204
+ }
205
+ __privateSet(this, _isValid2, isValidFilter(filter));
206
+ }
207
+ get isValid() {
208
+ return __privateGet(this, _isValid2);
209
+ }
210
+ setIsValid(isValid) {
211
+ __privateSet(this, _isValid2, isValid);
212
+ this.emit("isValid", isValid);
213
+ }
214
+ addNewFilterClause(operator) {
215
+ const count = __privateGet(this, _children).length;
216
+ if (!operator && !__privateGet(this, _op) && count === 1) {
217
+ __privateSet(this, _op, "and");
218
+ } else if (operator && !__privateGet(this, _op) && count === 1) {
219
+ __privateSet(this, _op, operator);
220
+ } else if (operator && __privateGet(this, _op) && operator !== __privateGet(this, _op)) {
221
+ throw Error(
222
+ "FilterModel: use setOp to change the Filter combinator operator"
223
+ );
224
+ }
225
+ const filterClauseModel = new FilterClauseModel({});
226
+ filterClauseModel.on("isValid", this.onFilterClauseStatusChange);
227
+ filterClauseModel.on("filterClause", this.onFilterClauseChange);
228
+ __privateGet(this, _children).push(filterClauseModel);
229
+ this.setIsValid(false);
230
+ }
231
+ addFilterClause(filterClause = {}) {
232
+ const filterClauseModel = new FilterClauseModel(filterClause);
233
+ filterClauseModel.on("isValid", this.onFilterClauseStatusChange);
234
+ filterClauseModel.on("filterClause", this.onFilterClauseChange);
235
+ __privateGet(this, _children).push(filterClauseModel);
236
+ }
237
+ removeFilterClause(filterClause) {
238
+ if (this.isMultiClauseFilter) {
239
+ const doomedFilter = this.filterClauses.indexOf(filterClause);
240
+ if (doomedFilter !== -1) {
241
+ this.filterClauses.splice(doomedFilter, 1);
242
+ if (this.filterClauses.length === 1) {
243
+ __privateSet(this, _op, void 0);
244
+ }
245
+ this.checkValidStatus();
246
+ }
247
+ }
248
+ }
249
+ checkValidStatus() {
250
+ const nowValid = isValidFilterModel(this);
251
+ if (nowValid !== __privateGet(this, _isValid2)) {
252
+ this.setIsValid(nowValid);
253
+ }
254
+ }
255
+ getFilterClause(index) {
256
+ return __privateGet(this, _children)[index];
257
+ }
258
+ get op() {
259
+ return __privateGet(this, _op);
260
+ }
261
+ setOp(op) {
262
+ __privateSet(this, _op, op);
263
+ this.emit("filter", this.asFilter(false), __privateGet(this, _isValid2));
264
+ }
265
+ get filterClauses() {
266
+ return __privateGet(this, _children);
267
+ }
268
+ get isMultiClauseFilter() {
269
+ return __privateGet(this, _op) === "and" || __privateGet(this, _op) === "or";
270
+ }
271
+ asFilter(throwIfInvalid = true) {
272
+ if (throwIfInvalid && !__privateGet(this, _isValid2)) {
273
+ throw Error("Invalid filter model cannot be returned as Filter");
274
+ }
275
+ if (__privateGet(this, _op) === "and" || __privateGet(this, _op) === "or") {
276
+ return {
277
+ op: __privateGet(this, _op),
278
+ filters: __privateGet(this, _children).map((f) => f.asFilter(throwIfInvalid))
279
+ };
280
+ } else {
281
+ return __privateGet(this, _children)[0].asFilter(throwIfInvalid);
282
+ }
283
+ }
284
+ };
285
+ _children = new WeakMap();
286
+ _isValid2 = new WeakMap();
287
+ _op = new WeakMap();
288
+
77
289
  // src/filter-bar/FilterBar.tsx
78
- var import_vuu_popups5 = require("@vuu-ui/vuu-popups");
79
- var import_vuu_ui_controls8 = require("@vuu-ui/vuu-ui-controls");
80
- var import_core2 = require("@salt-ds/core");
290
+ var import_vuu_popups3 = require("@vuu-ui/vuu-popups");
291
+ var import_vuu_ui_controls10 = require("@vuu-ui/vuu-ui-controls");
81
292
 
82
293
  // ../../node_modules/clsx/dist/clsx.mjs
83
294
  function r(e) {
@@ -101,66 +312,22 @@ function clsx() {
101
312
  var clsx_default = clsx;
102
313
 
103
314
  // src/filter-bar/FilterBar.tsx
104
- var import_react13 = require("react");
315
+ var import_react14 = require("react");
105
316
 
106
- // src/filter-builder-menu/FilterBuilderMenu.tsx
107
- var import_react = require("react");
108
- var import_vuu_popups = require("@vuu-ui/vuu-popups");
109
- var import_vuu_ui_controls = require("@vuu-ui/vuu-ui-controls");
110
- var import_jsx_runtime = require("react/jsx-runtime");
111
- var classBase = "vuuFilterBuilderMenu";
112
- var FilterBuilderMenu = ({
113
- ListProps: ListProps2,
114
- onMenuAction
115
- }) => {
116
- const ref = (0, import_react.useRef)(null);
117
- const listRef = (0, import_react.useCallback)((el) => {
118
- if (el) {
119
- requestAnimationFrame(() => {
120
- el.focus();
121
- });
122
- }
123
- }, []);
124
- const handleSelect = (0, import_react.useCallback)(
125
- (evt, selected) => {
126
- const {
127
- props: { "data-action": action }
128
- } = selected;
129
- onMenuAction({ type: "menu-action", menuId: action, options: {} });
130
- },
131
- [onMenuAction]
132
- );
133
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
134
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: `${classBase}-trigger`, ref }),
135
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_vuu_popups.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_vuu_popups.PopupComponent, { anchorElement: ref, placement: "right", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
136
- import_vuu_ui_controls.List,
137
- {
138
- ...ListProps2,
139
- className: `${classBase}List`,
140
- defaultHighlightedIndex: 0,
141
- itemHeight: 22,
142
- ref: listRef,
143
- onSelect: handleSelect,
144
- style: { position: "relative" },
145
- width: 100,
146
- children: [
147
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_vuu_ui_controls.ListItem, { "data-action": "apply-save", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "vuuMenuButton", children: "APPLY AND SAVE" }) }),
148
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_vuu_ui_controls.ListItem, { "data-action": "and-clause", children: "AND" }),
149
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_vuu_ui_controls.ListItem, { "data-action": "or-clause", children: "OR" })
150
- ]
151
- }
152
- ) }) })
153
- ] });
154
- };
317
+ // src/filter-editor/FilterEditor.tsx
318
+ var import_vuu_ui_controls6 = require("@vuu-ui/vuu-ui-controls");
319
+
320
+ // src/filter-clause/FilterClause.tsx
321
+ var import_react6 = require("react");
155
322
 
156
323
  // src/filter-clause/ExpandoCombobox.tsx
157
- var import_vuu_utils = require("@vuu-ui/vuu-utils");
158
- var import_vuu_ui_controls2 = require("@vuu-ui/vuu-ui-controls");
159
- var import_react2 = require("react");
160
- var import_jsx_runtime2 = require("react/jsx-runtime");
161
- var classBase2 = "vuuExpandoCombobox";
324
+ var import_vuu_utils2 = require("@vuu-ui/vuu-utils");
325
+ var import_vuu_ui_controls = require("@vuu-ui/vuu-ui-controls");
326
+ var import_react = require("react");
327
+ var import_jsx_runtime = require("react/jsx-runtime");
328
+ var classBase = "vuuExpandoCombobox";
162
329
  var NO_INPUT_PROPS = {};
163
- var ExpandoCombobox = (0, import_react2.forwardRef)(function ExpandoCombobox2({
330
+ var ExpandoCombobox = (0, import_react.forwardRef)(function ExpandoCombobox2({
164
331
  className: classNameProp,
165
332
  InputProps: InputPropsProp = NO_INPUT_PROPS,
166
333
  ListProps: ListPropsProp,
@@ -173,10 +340,10 @@ var ExpandoCombobox = (0, import_react2.forwardRef)(function ExpandoCombobox2({
173
340
  value = "",
174
341
  ...props
175
342
  }, forwardedRef) {
176
- const [text, setText] = (0, import_react2.useState)(value);
177
- const { itemToString = import_vuu_utils.itemToString } = props;
178
- const initialValue = (0, import_react2.useRef)(value);
179
- const itemsToString = (0, import_react2.useCallback)(
343
+ const [text, setText] = (0, import_react.useState)(value);
344
+ const { itemToString = import_vuu_utils2.itemToString } = props;
345
+ const initialValue = (0, import_react.useRef)(value);
346
+ const itemsToString = (0, import_react.useCallback)(
180
347
  (items) => {
181
348
  const [first, ...rest] = items;
182
349
  if (rest.length) {
@@ -187,7 +354,7 @@ var ExpandoCombobox = (0, import_react2.forwardRef)(function ExpandoCombobox2({
187
354
  },
188
355
  [itemToString]
189
356
  );
190
- const handleInputChange = (0, import_react2.useCallback)(
357
+ const handleInputChange = (0, import_react.useCallback)(
191
358
  (evt) => {
192
359
  const { value: value2 } = evt.target;
193
360
  setText(value2);
@@ -195,15 +362,15 @@ var ExpandoCombobox = (0, import_react2.forwardRef)(function ExpandoCombobox2({
195
362
  },
196
363
  [onInputChange]
197
364
  );
198
- const handleSetSelectedText = (0, import_react2.useCallback)((text2) => {
365
+ const handleSetSelectedText = (0, import_react.useCallback)((text2) => {
199
366
  setText(text2);
200
367
  }, []);
201
- const [InputProps, ListProps2] = (0, import_react2.useMemo)(() => {
368
+ const [InputProps, ListProps] = (0, import_react.useMemo)(() => {
202
369
  const { inputProps, ...restInputProps } = InputPropsProp;
203
370
  return [
204
371
  {
205
372
  ...restInputProps,
206
- className: `${classBase2}-Input`,
373
+ className: `${classBase}-Input`,
207
374
  endAdornment: null,
208
375
  inputProps: {
209
376
  ...inputProps,
@@ -225,7 +392,7 @@ var ExpandoCombobox = (0, import_react2.forwardRef)(function ExpandoCombobox2({
225
392
  }
226
393
  ];
227
394
  }, [InputPropsProp, handleInputChange, ListPropsProp]);
228
- const handleSelectionChange = (0, import_react2.useCallback)(
395
+ const handleSelectionChange = (0, import_react.useCallback)(
229
396
  (_, selected) => {
230
397
  if (Array.isArray(selected)) {
231
398
  onSelectionChange == null ? void 0 : onSelectionChange(
@@ -242,7 +409,7 @@ var ExpandoCombobox = (0, import_react2.forwardRef)(function ExpandoCombobox2({
242
409
  },
243
410
  [itemToString, onSelectionChange]
244
411
  );
245
- const getDefaultSelected = () => {
412
+ const getSelected = () => {
246
413
  if (initialValue.current === void 0) {
247
414
  return void 0;
248
415
  } else if (Array.isArray(initialValue.current)) {
@@ -258,23 +425,23 @@ var ExpandoCombobox = (0, import_react2.forwardRef)(function ExpandoCombobox2({
258
425
  const popupProps = {
259
426
  minWidth: "fit-content"
260
427
  };
261
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
428
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
262
429
  "div",
263
430
  {
264
- className: clsx_default(classBase2, classNameProp),
431
+ className: clsx_default(classBase, classNameProp),
265
432
  "data-text": text,
266
433
  ref: forwardedRef,
267
434
  style,
268
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
269
- import_vuu_ui_controls2.ComboBox,
435
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
436
+ import_vuu_ui_controls.ComboBox,
270
437
  {
271
438
  ...props,
272
439
  PopupProps: popupProps,
273
- allowEnterCommitsText: true,
274
- defaultSelected: getDefaultSelected(),
440
+ className: "vuuEmbedded",
441
+ defaultSelected: getSelected(),
275
442
  defaultValue: Array.isArray(initialValue.current) ? itemsToString(initialValue.current) : initialValue.current,
276
443
  fullWidth: true,
277
- ListProps: ListProps2,
444
+ ListProps,
278
445
  InputProps,
279
446
  itemsToString,
280
447
  onSelectionChange: handleSelectionChange,
@@ -287,76 +454,62 @@ var ExpandoCombobox = (0, import_react2.forwardRef)(function ExpandoCombobox2({
287
454
  );
288
455
  });
289
456
 
290
- // src/filter-clause/FilterClauseEditor.tsx
291
- var import_core = require("@salt-ds/core");
292
- var import_react7 = require("react");
293
-
294
- // src/filter-clause/operator-utils.ts
295
- var import_vuu_utils2 = require("@vuu-ui/vuu-utils");
296
- var textOperators = ["=", "in", "!=", "starts", "ends"];
297
- var numericperators = ["=", "!=", ">", ">=", "<", "<="];
298
- var getOperators = (column) => {
299
- if ((0, import_vuu_utils2.isTextColumn)(column)) {
300
- return textOperators;
301
- } else if ((0, import_vuu_utils2.isNumericColumn)(column)) {
302
- return numericperators;
303
- } else {
304
- throw Error("getOperators only supports text and numeric columns");
305
- }
306
- };
307
-
308
- // src/filter-clause/NumericInput.tsx
309
- var import_react3 = require("react");
310
- var import_vuu_ui_controls3 = require("@vuu-ui/vuu-ui-controls");
457
+ // src/filter-clause/value-editors/FilterClauseValueEditorNumber.tsx
458
+ var import_react2 = require("react");
459
+ var import_vuu_ui_controls2 = require("@vuu-ui/vuu-ui-controls");
311
460
  var import_vuu_utils3 = require("@vuu-ui/vuu-utils");
312
- var import_jsx_runtime3 = require("react/jsx-runtime");
313
- var NumericInput = (0, import_react3.forwardRef)(function NumericInput2({
314
- InputProps,
315
- className,
316
- onInputComplete,
317
- value: valueProp
318
- }, forwardedRef) {
319
- const [value, setValue] = (0, import_react3.useState)(
320
- (0, import_vuu_utils3.isValidNumber)(valueProp) ? valueProp.toString() : ""
321
- );
322
- const handleChange = (0, import_react3.useCallback)((evt) => {
323
- const { value: value2 } = evt.target;
324
- const numericValue = parseFloat(value2);
325
- if ((0, import_vuu_utils3.isValidNumber)(numericValue)) {
326
- console.log("its valid");
327
- }
328
- setValue(value2);
329
- }, []);
330
- const handleKeyDown = (0, import_react3.useCallback)(
331
- (evt) => {
332
- if (evt.key === "Enter") {
333
- const { value: value2 } = evt.target;
334
- const numericValue = parseFloat(value2);
335
- if ((0, import_vuu_utils3.isValidNumber)(numericValue)) {
336
- onInputComplete(numericValue);
461
+ var import_jsx_runtime2 = require("react/jsx-runtime");
462
+ var FilterClauseValueEditorNumber = (0, import_react2.forwardRef)(
463
+ function FilterClauseNumericValueEditor({
464
+ InputProps,
465
+ className,
466
+ "data-field": dataField,
467
+ onChangeValue,
468
+ value: valueProp
469
+ }, forwardedRef) {
470
+ const [value, setValue] = (0, import_react2.useState)(
471
+ (0, import_vuu_utils3.isValidNumber)(valueProp) ? valueProp.toString() : ""
472
+ );
473
+ const handleChange = (0, import_react2.useCallback)((evt) => {
474
+ const { value: value2 } = evt.target;
475
+ const numericValue = parseFloat(value2);
476
+ if ((0, import_vuu_utils3.isValidNumber)(numericValue)) {
477
+ console.log("its valid");
478
+ }
479
+ setValue(value2);
480
+ }, []);
481
+ const handleKeyDown = (0, import_react2.useCallback)(
482
+ (evt) => {
483
+ if (evt.key === "Enter" || evt.key === "Tab") {
484
+ const { value: value2 } = evt.target;
485
+ const numericValue = parseFloat(value2);
486
+ if ((0, import_vuu_utils3.isValidNumber)(numericValue)) {
487
+ onChangeValue(numericValue);
488
+ }
337
489
  }
490
+ },
491
+ [onChangeValue]
492
+ );
493
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
494
+ import_vuu_ui_controls2.ExpandoInput,
495
+ {
496
+ ...InputProps,
497
+ className,
498
+ "data-field": dataField,
499
+ onChange: handleChange,
500
+ onKeyDown: handleKeyDown,
501
+ ref: forwardedRef,
502
+ value
338
503
  }
339
- },
340
- [onInputComplete]
341
- );
342
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
343
- import_vuu_ui_controls3.ExpandoInput,
344
- {
345
- ...InputProps,
346
- className,
347
- value,
348
- ref: forwardedRef,
349
- onChange: handleChange,
350
- onKeyDown: handleKeyDown
351
- }
352
- );
353
- });
504
+ );
505
+ }
506
+ );
354
507
 
355
- // src/filter-clause/FilterClauseTextValueEditor.tsx
356
- var import_react4 = require("react");
508
+ // src/filter-clause/value-editors/FilterClauseValueEditorText.tsx
509
+ var import_react3 = require("react");
357
510
  var import_vuu_data_react = require("@vuu-ui/vuu-data-react");
358
- var import_vuu_ui_controls4 = require("@vuu-ui/vuu-ui-controls");
359
- var import_jsx_runtime4 = require("react/jsx-runtime");
511
+ var import_vuu_ui_controls3 = require("@vuu-ui/vuu-ui-controls");
512
+ var import_jsx_runtime3 = require("react/jsx-runtime");
360
513
  var selectionKeys = ["Enter", " "];
361
514
  var getVuuTable = (schemaTable) => {
362
515
  if (schemaTable.session) {
@@ -367,170 +520,186 @@ var getVuuTable = (schemaTable) => {
367
520
  }
368
521
  };
369
522
  var NO_DATA_MATCH = ["No matching data"];
370
- var FilterClauseTextValueEditor = (0, import_react4.forwardRef)(function TextInput({
371
- InputProps: InputPropsProp = {},
372
- className,
373
- column,
374
- "data-field": dataField,
375
- onDeselect,
376
- onInputComplete,
377
- operator,
378
- suggestionProvider = import_vuu_data_react.useTypeaheadSuggestions,
379
- table,
380
- value
381
- }, forwardedRef) {
382
- var _a;
383
- const isMultiValue = operator === "in";
384
- const [valueInputValue, setValueInputValue] = (0, import_react4.useState)(
385
- (_a = value == null ? void 0 : value.toString()) != null ? _a : ""
386
- );
387
- const [typeaheadValues, setTypeaheadValues] = (0, import_react4.useState)([]);
388
- const getSuggestions = suggestionProvider();
389
- const handleSingleValueSelectionChange = (0, import_react4.useCallback)(
390
- (_, value2) => onInputComplete(value2),
391
- [onInputComplete]
392
- );
393
- const handleMultiValueSelectionChange = (0, import_react4.useCallback)(
394
- (_, values) => onInputComplete(values),
395
- [onInputComplete]
396
- );
397
- (0, import_react4.useEffect)(() => {
398
- if (table) {
399
- const vuuTable = getVuuTable(table);
400
- const params = valueInputValue && !isMultiValue ? [vuuTable, column.name, valueInputValue] : [vuuTable, column.name];
401
- getSuggestions(params).then((suggestions) => {
402
- if (suggestions.length === 0 && valueInputValue) {
403
- setTypeaheadValues(NO_DATA_MATCH);
523
+ var FilterClauseValueEditorText = (0, import_react3.forwardRef)(
524
+ function FilterClauseTextValueEditor({
525
+ InputProps: InputPropsProp = {},
526
+ className,
527
+ column,
528
+ "data-field": dataField,
529
+ onDeselect,
530
+ onChangeValue,
531
+ operator,
532
+ suggestionProvider = import_vuu_data_react.useTypeaheadSuggestions,
533
+ table,
534
+ value
535
+ }, forwardedRef) {
536
+ var _a;
537
+ const isMultiValue = operator === "in";
538
+ const [valueInputValue, setValueInputValue] = (0, import_react3.useState)(
539
+ (_a = value == null ? void 0 : value.toString()) != null ? _a : ""
540
+ );
541
+ const [typeaheadValues, setTypeaheadValues] = (0, import_react3.useState)([]);
542
+ const getSuggestions = suggestionProvider();
543
+ const handleSingleValueSelectionChange = (0, import_react3.useCallback)(
544
+ (_, value2) => onChangeValue(value2),
545
+ [onChangeValue]
546
+ );
547
+ const handleMultiValueSelectionChange = (0, import_react3.useCallback)(
548
+ (_, values) => onChangeValue(values),
549
+ [onChangeValue]
550
+ );
551
+ (0, import_react3.useEffect)(() => {
552
+ if (table) {
553
+ const vuuTable = getVuuTable(table);
554
+ const params = valueInputValue && !isMultiValue ? [vuuTable, column.name, valueInputValue] : [vuuTable, column.name];
555
+ getSuggestions(params).then((suggestions) => {
556
+ if (suggestions.length === 0 && valueInputValue) {
557
+ setTypeaheadValues(NO_DATA_MATCH);
558
+ } else {
559
+ setTypeaheadValues(suggestions);
560
+ }
561
+ }).catch((err) => {
562
+ console.error("Error getting suggestions", err);
563
+ });
564
+ }
565
+ }, [table, column, valueInputValue, getSuggestions, isMultiValue]);
566
+ const handleInputChange = (0, import_react3.useCallback)(
567
+ (evt) => {
568
+ const { value: value2 } = evt.target;
569
+ console.log(`handleInputChange "${value2}"`);
570
+ setValueInputValue(value2);
571
+ if (operator === "starts" || operator === "ends") {
572
+ onChangeValue(value2, false);
573
+ }
574
+ },
575
+ [onChangeValue, operator]
576
+ );
577
+ const handleKeyDownFreeTextInput = (0, import_react3.useCallback)(
578
+ (evt) => {
579
+ var _a2, _b;
580
+ console.log(`handleKeyDownFreeTextInput ${valueInputValue}`);
581
+ if ((evt.key === "Enter" || evt.key === "Tab") && valueInputValue !== "") {
582
+ evt.stopPropagation();
583
+ evt.preventDefault();
584
+ console.log(`call onInputComplete ${valueInputValue}`);
585
+ onChangeValue(valueInputValue);
404
586
  } else {
405
- setTypeaheadValues(suggestions);
587
+ (_b = (_a2 = InputPropsProp == null ? void 0 : InputPropsProp.inputProps) == null ? void 0 : _a2.onKeyDown) == null ? void 0 : _b.call(_a2, evt);
406
588
  }
407
- }).catch((err) => {
408
- console.error("Error getting suggestions", err);
409
- });
410
- }
411
- }, [table, column, valueInputValue, getSuggestions, isMultiValue]);
412
- const handleInputChange = (0, import_react4.useCallback)((evt) => {
413
- const { value: value2 } = evt.target;
414
- setValueInputValue(value2);
415
- }, []);
416
- const InputProps = (0, import_react4.useMemo)(() => {
417
- if (operator !== "in") {
418
- const { inputProps, ...restInputProps } = InputPropsProp;
419
- return {
420
- ...restInputProps,
421
- inputProps: {
422
- ...inputProps,
423
- onKeyDown: (evt) => {
424
- var _a2;
425
- if (evt.key === "Enter" && valueInputValue !== "") {
426
- evt.stopPropagation();
427
- evt.preventDefault();
428
- onInputComplete(valueInputValue);
429
- } else {
430
- (_a2 = inputProps == null ? void 0 : inputProps.onKeyDown) == null ? void 0 : _a2.call(inputProps, evt);
431
- }
589
+ },
590
+ [InputPropsProp, onChangeValue, valueInputValue]
591
+ );
592
+ const InputProps = (0, import_react3.useMemo)(() => {
593
+ if (operator === "starts" || operator === "ends") {
594
+ const { inputProps, ...restInputProps } = InputPropsProp;
595
+ return {
596
+ ...restInputProps,
597
+ inputProps: {
598
+ ...inputProps,
599
+ onKeyDown: handleKeyDownFreeTextInput
432
600
  }
601
+ };
602
+ } else {
603
+ return InputPropsProp;
604
+ }
605
+ }, [InputPropsProp, handleKeyDownFreeTextInput, operator]);
606
+ const getValueInputField = (0, import_react3.useCallback)(() => {
607
+ switch (operator) {
608
+ case "in":
609
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
610
+ ExpandoCombobox,
611
+ {
612
+ InputProps,
613
+ className,
614
+ "data-field": dataField,
615
+ initialHighlightedIndex: 0,
616
+ source: typeaheadValues,
617
+ onInputChange: handleInputChange,
618
+ onSelectionChange: handleMultiValueSelectionChange,
619
+ ref: forwardedRef,
620
+ selectionStrategy: "multiple",
621
+ selectionKeys,
622
+ value
623
+ }
624
+ );
625
+ case "starts": {
626
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
627
+ ExpandoCombobox,
628
+ {
629
+ InputProps,
630
+ ListProps: {
631
+ className: "vuuIllustrationsOnly",
632
+ disabled: true
633
+ },
634
+ allowEnterCommitsText: true,
635
+ allowFreeText: true,
636
+ className,
637
+ "data-field": dataField,
638
+ initialHighlightedIndex: 0,
639
+ disableFilter: typeaheadValues === NO_DATA_MATCH && (valueInputValue == null ? void 0 : valueInputValue.length) > 0,
640
+ source: typeaheadValues,
641
+ onInputChange: handleInputChange,
642
+ onSelectionChange: handleSingleValueSelectionChange,
643
+ ref: forwardedRef,
644
+ value
645
+ }
646
+ );
433
647
  }
434
- };
435
- } else {
436
- return InputPropsProp;
437
- }
438
- }, [InputPropsProp, onInputComplete, operator, valueInputValue]);
439
- const getValueInputField = (0, import_react4.useCallback)(() => {
440
- switch (operator) {
441
- case "in":
442
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
443
- ExpandoCombobox,
444
- {
445
- InputProps,
446
- className,
447
- "data-field": dataField,
448
- initialHighlightedIndex: 0,
449
- source: typeaheadValues,
450
- onInputChange: handleInputChange,
451
- onSelectionChange: handleMultiValueSelectionChange,
452
- ref: forwardedRef,
453
- selectionStrategy: "multiple",
454
- selectionKeys,
455
- value
456
- }
457
- );
458
- case "starts": {
459
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
460
- ExpandoCombobox,
461
- {
462
- InputProps,
463
- ListProps: {
464
- className: "vuuIllustrationsOnly",
465
- disabled: true
466
- },
467
- allowFreeText: true,
468
- className,
469
- "data-field": dataField,
470
- initialHighlightedIndex: 0,
471
- disableFilter: typeaheadValues === NO_DATA_MATCH && (valueInputValue == null ? void 0 : valueInputValue.length) > 0,
472
- source: typeaheadValues,
473
- onInputChange: handleInputChange,
474
- onSelectionChange: handleSingleValueSelectionChange,
475
- ref: forwardedRef,
476
- value
477
- }
478
- );
648
+ case "ends":
649
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
650
+ import_vuu_ui_controls3.ExpandoInput,
651
+ {
652
+ ...InputProps,
653
+ className,
654
+ "data-field": dataField,
655
+ value: valueInputValue,
656
+ ref: forwardedRef,
657
+ onChange: handleInputChange
658
+ }
659
+ );
660
+ default:
661
+ return typeaheadValues.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
662
+ ExpandoCombobox,
663
+ {
664
+ InputProps,
665
+ allowBackspaceClearsSelection: true,
666
+ allowFreeText: true,
667
+ className,
668
+ "data-field": dataField,
669
+ initialHighlightedIndex: 0,
670
+ source: typeaheadValues,
671
+ title: "value",
672
+ onInputChange: handleInputChange,
673
+ onDeselect,
674
+ onSelectionChange: handleSingleValueSelectionChange,
675
+ ref: forwardedRef,
676
+ value
677
+ }
678
+ ) : null;
479
679
  }
480
- case "ends":
481
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
482
- import_vuu_ui_controls4.ExpandoInput,
483
- {
484
- ...InputProps,
485
- className,
486
- "data-field": dataField,
487
- value: valueInputValue,
488
- ref: forwardedRef,
489
- onChange: handleInputChange
490
- }
491
- );
492
- default:
493
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
494
- ExpandoCombobox,
495
- {
496
- InputProps,
497
- allowBackspaceClearsSelection: true,
498
- allowFreeText: true,
499
- className,
500
- "data-field": dataField,
501
- initialHighlightedIndex: 0,
502
- source: typeaheadValues,
503
- title: "value",
504
- onInputChange: handleInputChange,
505
- onDeselect,
506
- onSelectionChange: handleSingleValueSelectionChange,
507
- ref: forwardedRef,
508
- value
509
- }
510
- );
511
- }
512
- }, [
513
- InputProps,
514
- operator,
515
- className,
516
- dataField,
517
- typeaheadValues,
518
- handleInputChange,
519
- handleMultiValueSelectionChange,
520
- forwardedRef,
521
- value,
522
- valueInputValue,
523
- onDeselect,
524
- handleSingleValueSelectionChange
525
- ]);
526
- return getValueInputField();
527
- });
680
+ }, [
681
+ InputProps,
682
+ operator,
683
+ className,
684
+ dataField,
685
+ typeaheadValues,
686
+ handleInputChange,
687
+ handleMultiValueSelectionChange,
688
+ forwardedRef,
689
+ value,
690
+ valueInputValue,
691
+ onDeselect,
692
+ handleSingleValueSelectionChange
693
+ ]);
694
+ return getValueInputField();
695
+ }
696
+ );
528
697
 
529
- // src/filter-clause/FilterClauseValueEditor.tsx
698
+ // src/filter-clause/value-editors/FilterClauseValueEditor.tsx
530
699
  var import_vuu_utils5 = require("@vuu-ui/vuu-utils");
531
700
 
532
- // src/filter-clause/DateInput.tsx
533
- var import_react5 = require("react");
701
+ // src/filter-clause/value-editors/FilterClauseValueEditorDate.tsx
702
+ var import_react4 = require("react");
534
703
 
535
704
  // ../../node_modules/@internationalized/date/dist/import.mjs
536
705
  var $14e0f24ef4ac5c92$var$localTimeZone = null;
@@ -557,31 +726,52 @@ var $7c5f6fbf42389787$var$MONTH_DAYS = 29;
557
726
  var $7c5f6fbf42389787$var$MONTH_FRACT = 12 * $7c5f6fbf42389787$var$HOUR_PARTS + 793;
558
727
  var $7c5f6fbf42389787$var$MONTH_PARTS = $7c5f6fbf42389787$var$MONTH_DAYS * $7c5f6fbf42389787$var$DAY_PARTS + $7c5f6fbf42389787$var$MONTH_FRACT;
559
728
 
560
- // src/filter-clause/DateInput.tsx
561
- var import_vuu_ui_controls5 = require("@vuu-ui/vuu-ui-controls");
729
+ // src/filter-clause/value-editors/FilterClauseValueEditorDate.tsx
730
+ var import_vuu_ui_controls4 = require("@vuu-ui/vuu-ui-controls");
562
731
  var import_vuu_utils4 = require("@vuu-ui/vuu-utils");
563
- var import_jsx_runtime5 = require("react/jsx-runtime");
564
- var DateInput = (props) => {
565
- const { value, onInputComplete, operator } = props;
732
+ var import_jsx_runtime4 = require("react/jsx-runtime");
733
+ var FilterClauseValueEditorDate = (props) => {
734
+ const { InputProps, className, onChangeValue, operator, value } = props;
566
735
  const toEpochMilliS = getEpochMillisConverter(operator);
567
- const [date, setDate] = (0, import_react5.useState)(
736
+ const [date, setDate] = (0, import_react4.useState)(
568
737
  () => getInitialState(value)
569
738
  );
570
- const onSelectedDateChange = (0, import_react5.useCallback)((d) => {
571
- setDate(d);
572
- }, []);
573
- const onBlur = (0, import_react5.useCallback)(() => {
574
- date && onInputComplete(toEpochMilliS(date));
575
- }, [date, onInputComplete, toEpochMilliS]);
576
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
577
- import_vuu_ui_controls5.DatePicker,
578
- {
579
- className: "vuuFilterClause-DatePicker",
580
- selectedDate: date,
739
+ const onSelectedDateChange = (0, import_react4.useCallback)(
740
+ (d, source) => {
741
+ setDate(d);
742
+ if (d && source === "calendar") {
743
+ onChangeValue(toEpochMilliS(d));
744
+ }
745
+ },
746
+ [onChangeValue, toEpochMilliS]
747
+ );
748
+ const onBlur = (0, import_react4.useCallback)(() => {
749
+ date && onChangeValue(toEpochMilliS(date));
750
+ }, [date, onChangeValue, toEpochMilliS]);
751
+ const handleKeyDown = (0, import_react4.useCallback)(
752
+ (evt) => {
753
+ if (evt.key === "Enter") {
754
+ if (date) {
755
+ const popup = (0, import_vuu_utils4.queryClosest)(evt.target, ".vuuDatePopup");
756
+ if (popup === null) {
757
+ onChangeValue(toEpochMilliS(date));
758
+ }
759
+ }
760
+ } else if (evt.key === "Tab") {
761
+ console.log("better handle tab");
762
+ }
763
+ },
764
+ [date, onChangeValue, toEpochMilliS]
765
+ );
766
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
767
+ import_vuu_ui_controls4.DateInput,
768
+ {
769
+ inputProps: InputProps == null ? void 0 : InputProps.inputProps,
770
+ className: clsx_default("vuuFilterClause-DatePicker", className),
771
+ selectedDate: date,
581
772
  onBlur,
582
- onSelectedDateChange,
583
- closeOnSelection: true,
584
- hideOutOfRangeDates: true
773
+ onChange: onSelectedDateChange,
774
+ onKeyDown: handleKeyDown
585
775
  }
586
776
  );
587
777
  };
@@ -604,9 +794,9 @@ var getEpochMillisConverter = (op) => (date, timezone = $14e0f24ef4ac5c92$export
604
794
  }
605
795
  };
606
796
 
607
- // src/filter-clause/FilterClauseValueEditor.tsx
608
- var import_jsx_runtime6 = require("react/jsx-runtime");
609
- var classBase3 = "vuuFilterClause";
797
+ // src/filter-clause/value-editors/FilterClauseValueEditor.tsx
798
+ var import_jsx_runtime5 = require("react/jsx-runtime");
799
+ var classBase2 = "vuuFilterClause";
610
800
  var FilterClauseValueEditor = ({
611
801
  selectedColumn,
612
802
  operator,
@@ -621,27 +811,31 @@ var FilterClauseValueEditor = ({
621
811
  return null;
622
812
  }
623
813
  if ((0, import_vuu_utils5.isDateTimeColumn)(selectedColumn)) {
624
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
625
- DateInput,
814
+ console.log(`return DateInput`);
815
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
816
+ FilterClauseValueEditorDate,
626
817
  {
818
+ InputProps,
819
+ className: clsx_default(`${classBase2}Field`, `${classBase2}Value`),
820
+ "data-field": "value",
627
821
  value,
628
822
  operator,
629
- onInputComplete: onChangeValue
823
+ onChangeValue
630
824
  }
631
825
  );
632
826
  }
633
827
  switch (selectedColumn.serverDataType) {
634
828
  case "string":
635
829
  case "char":
636
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
637
- FilterClauseTextValueEditor,
830
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
831
+ FilterClauseValueEditorText,
638
832
  {
639
833
  InputProps,
640
- className: clsx_default(`${classBase3}Field`, `${classBase3}Value`),
834
+ className: clsx_default(`${classBase2}Field`, `${classBase2}Value`),
641
835
  column: selectedColumn,
642
836
  "data-field": "value",
643
837
  onDeselect: onDeselectValue,
644
- onInputComplete: onChangeValue,
838
+ onChangeValue,
645
839
  operator,
646
840
  suggestionProvider,
647
841
  table,
@@ -651,13 +845,14 @@ var FilterClauseValueEditor = ({
651
845
  case "int":
652
846
  case "long":
653
847
  case "double":
654
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
655
- NumericInput,
848
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
849
+ FilterClauseValueEditorNumber,
656
850
  {
657
851
  InputProps,
658
- className: clsx_default(`${classBase3}Field`, `${classBase3}Value`),
852
+ className: clsx_default(`${classBase2}Field`, `${classBase2}Value`),
659
853
  column: selectedColumn,
660
- onInputComplete: onChangeValue,
854
+ "data-field": "value",
855
+ onChangeValue,
661
856
  operator
662
857
  }
663
858
  );
@@ -667,24 +862,87 @@ var FilterClauseValueEditor = ({
667
862
  }
668
863
  };
669
864
 
670
- // src/filter-clause/useFilterClauseEditor.ts
865
+ // src/filter-clause/operator-utils.ts
671
866
  var import_vuu_utils6 = require("@vuu-ui/vuu-utils");
672
- var import_react6 = require("react");
673
- var cursorAtTextStart = (input) => input.selectionStart === 0;
674
- var cursorAtTextEnd = (input) => input.selectionStart === input.value.length;
675
- var getFieldName = (field) => (field == null ? void 0 : field.classList.contains("vuuFilterClauseColumn")) ? "column" : (field == null ? void 0 : field.classList.contains("vuuFilterClauseOperator")) ? "operator" : "value";
676
- var getFocusedField = () => {
677
- const activeElement = document.activeElement;
678
- if (activeElement == null ? void 0 : activeElement.classList.contains("vuuFilterClause-clearButton")) {
679
- return activeElement;
867
+ var textOperators = ["=", "in", "!=", "starts", "ends"];
868
+ var numericperators = ["=", "!=", ">", ">=", "<", "<="];
869
+ var getOperators = (column) => {
870
+ if ((0, import_vuu_utils6.isTextColumn)(column)) {
871
+ return textOperators;
872
+ } else if ((0, import_vuu_utils6.isNumericColumn)(column)) {
873
+ return numericperators;
874
+ } else {
875
+ throw Error("getOperators only supports text and numeric columns");
876
+ }
877
+ };
878
+
879
+ // src/filter-clause/useFilterClause.ts
880
+ var import_vuu_utils8 = require("@vuu-ui/vuu-utils");
881
+ var import_react5 = require("react");
882
+
883
+ // src/filter-clause/filterClauseFocusManagement.ts
884
+ var import_vuu_utils7 = require("@vuu-ui/vuu-utils");
885
+ var getFilterClauseElement = (possiblyDescendant) => possiblyDescendant == null ? void 0 : possiblyDescendant.closest(".vuuFilterClause");
886
+ var getFilterClauseFieldElement = (possiblyDescendant) => possiblyDescendant == null ? void 0 : possiblyDescendant.closest(".vuuFilterClauseField");
887
+ var mapFilterFieldToClassName = {
888
+ column: "vuuFilterClauseColumn",
889
+ operator: "vuuFilterClauseOperator",
890
+ value: "vuuFilterClauseValue"
891
+ };
892
+ var getFilterClauseDetails = ({ classList }) => {
893
+ if (classList.contains("vuuFilterClauseColumn")) {
894
+ return "column";
895
+ } else if (classList.contains("vuuFilterClauseOperator")) {
896
+ return "operator";
897
+ } else if (classList.contains("vuuFilterClauseValue")) {
898
+ return "value";
899
+ } else {
900
+ throw Error(
901
+ "getFilterClauseField, filterClauseElemnent is missing required class name"
902
+ );
903
+ }
904
+ };
905
+ var getFocusedFieldDetails = () => {
906
+ const el = document.activeElement;
907
+ const field = (0, import_vuu_utils7.queryClosest)(el, ".vuuFilterClauseField");
908
+ const filterClause = (0, import_vuu_utils7.queryClosest)(field, ".vuuFilterClause");
909
+ if (filterClause && field) {
910
+ return [(0, import_vuu_utils7.getElementDataIndex)(filterClause), getFilterClauseDetails(field)];
680
911
  } else {
681
- return activeElement == null ? void 0 : activeElement.closest(".vuuFilterClauseField");
912
+ return [];
682
913
  }
683
914
  };
915
+ var focusField = (fieldOrClause) => {
916
+ const input = fieldOrClause == null ? void 0 : fieldOrClause.querySelector("input");
917
+ if (input) {
918
+ input.focus();
919
+ requestAnimationFrame(() => {
920
+ input == null ? void 0 : input.select();
921
+ });
922
+ }
923
+ };
924
+ var elementIsFilterCombinator = (element) => element !== null && element.classList.contains("vuuFilterClauseCombinator");
925
+ var elementIsFilterClause = (element) => element !== null && element.classList.contains("vuuFilterClause");
926
+ var focusFilterClauseField = (filterEditor, filterClauseIndex, fieldName = "value") => {
927
+ if (filterEditor) {
928
+ const fieldClassName = mapFilterFieldToClassName[fieldName];
929
+ const field = filterEditor.querySelector(
930
+ `.vuuFilterClause[data-index="${filterClauseIndex}"] .${fieldClassName}`
931
+ );
932
+ focusField(field);
933
+ }
934
+ };
935
+ var focusLastClauseValue = (filterEditor) => {
936
+ console.log("focusLastClauseValue");
937
+ const field = Array.from(
938
+ filterEditor == null ? void 0 : filterEditor.querySelectorAll(".vuuFilterClauseField")
939
+ ).at(-1);
940
+ focusField(field);
941
+ };
684
942
  var focusNextFocusableElement = (direction = "fwd") => {
685
943
  var _a;
686
944
  const activeField = getFocusedField();
687
- const filterClause = activeField == null ? void 0 : activeField.closest(".vuuFilterClause");
945
+ const filterClause = getFilterClauseElement(activeField);
688
946
  if (direction === "fwd" && (filterClause == null ? void 0 : filterClause.lastChild) === activeField) {
689
947
  requestAnimationFrame(() => {
690
948
  focusNextFocusableElement();
@@ -694,20 +952,17 @@ var focusNextFocusableElement = (direction = "fwd") => {
694
952
  (_a = nextField == null ? void 0 : nextField.querySelector("input")) == null ? void 0 : _a.focus();
695
953
  }
696
954
  };
697
- var clauseIsNotFirst = (el) => {
698
- var _a;
699
- const clause = el.closest("[data-index]");
700
- if (clause) {
701
- const index = clause.dataset.index;
702
- const previousClause = (_a = clause == null ? void 0 : clause.parentElement) == null ? void 0 : _a.querySelector(
703
- `[data-index]:has(.vuuFilterClause):has(+[data-index="${index}"])`
704
- );
705
- return previousClause !== null;
955
+ var getFocusedField = () => {
956
+ const activeElement = document.activeElement;
957
+ if (activeElement == null ? void 0 : activeElement.classList.contains("vuuFilterClause-clearButton")) {
958
+ return activeElement;
959
+ } else {
960
+ return getFilterClauseFieldElement(activeElement);
706
961
  }
707
962
  };
708
963
  var focusNextElement = () => {
709
964
  const filterClauseField = getFocusedField();
710
- const filterClause = filterClauseField == null ? void 0 : filterClauseField.closest(".vuuFilterClause");
965
+ const filterClause = getFilterClauseElement(filterClauseField);
711
966
  if (filterClause && filterClauseField) {
712
967
  if (filterClauseField.classList.contains("vuuFilterClauseValue")) {
713
968
  const clearButton = filterClause.querySelector(
@@ -719,119 +974,170 @@ var focusNextElement = () => {
719
974
  }
720
975
  }
721
976
  };
722
- var navigateToNextInputIfAtBoundary = (evt) => {
977
+ var cursorAtTextStart = (input) => input.selectionStart === 0;
978
+ var cursorAtTextEnd = (input) => input.selectionStart === input.value.length;
979
+ var getFieldName = (field) => (field == null ? void 0 : field.classList.contains("vuuFilterClauseColumn")) ? "column" : (field == null ? void 0 : field.classList.contains("vuuFilterClauseOperator")) ? "operator" : "value";
980
+ var clauseIsNotFirst = (el) => {
981
+ const clause = getFilterClauseElement(el);
982
+ if (clause) {
983
+ const index = (0, import_vuu_utils7.getElementDataIndex)(clause);
984
+ return index > 0;
985
+ }
986
+ };
987
+ var clauseIsNotLast = (el) => {
988
+ const clause = getFilterClauseElement(el);
989
+ const nextClause = clause == null ? void 0 : clause.nextElementSibling;
990
+ return nextClause == null ? void 0 : nextClause.classList.contains("vuuFilterClauseCombinator");
991
+ };
992
+ var tabToPreviousFilterCombinator = (currentElement) => {
993
+ const filterClause = getFilterClauseElement(currentElement);
994
+ const nextItem = filterClause.previousSibling;
995
+ console.log(`tab to previous combinator`);
996
+ nextItem == null ? void 0 : nextItem.focus();
997
+ };
998
+ var navigateToNextFilterClause = (currentElement, direction = "fwd") => {
999
+ if (direction === "bwd") {
1000
+ if (elementIsFilterCombinator(currentElement)) {
1001
+ const nextClause = currentElement.previousElementSibling;
1002
+ if (elementIsFilterClause(nextClause)) {
1003
+ const nextField = nextClause.querySelector(
1004
+ ".vuuFilterClauseValue"
1005
+ );
1006
+ console.log(`focus field Value ${nextField == null ? void 0 : nextField.classList}`);
1007
+ focusField(nextField);
1008
+ }
1009
+ } else {
1010
+ const filterClause = getFilterClauseElement(currentElement);
1011
+ const nextClause = filterClause.previousSibling;
1012
+ const nextField = nextClause.querySelector(
1013
+ ".vuuFilterClauseValue"
1014
+ );
1015
+ focusField(nextField);
1016
+ }
1017
+ } else {
1018
+ const nextClause = currentElement.nextSibling;
1019
+ focusField(nextClause);
1020
+ }
1021
+ };
1022
+ var navigateToNextItemIfAtBoundary = (evt) => {
723
1023
  const input = evt.target;
724
- const cursorAtStart = cursorAtTextStart(input);
725
- const cursorAtEnd = cursorAtTextEnd(input);
726
- const field = input.closest(".vuuFilterClauseField");
1024
+ const field = getFilterClauseFieldElement(input);
727
1025
  if (evt.key === "ArrowLeft") {
728
- if (cursorAtStart) {
1026
+ if (cursorAtTextStart(input)) {
729
1027
  const fieldName = getFieldName(field);
730
1028
  if (fieldName === "column") {
731
- return;
1029
+ if (clauseIsNotFirst(input)) {
1030
+ const filterClause = getFilterClauseElement(field);
1031
+ const combinator = filterClause.previousElementSibling;
1032
+ combinator == null ? void 0 : combinator.focus();
1033
+ }
732
1034
  } else {
733
- const nextField = field.previousSibling;
734
- const nextInput = nextField == null ? void 0 : nextField.querySelector("input");
735
1035
  evt.preventDefault();
736
- nextInput == null ? void 0 : nextInput.focus();
737
- requestAnimationFrame(() => {
738
- nextInput == null ? void 0 : nextInput.select();
739
- });
1036
+ focusField(field.previousSibling);
740
1037
  }
741
1038
  }
742
1039
  evt.stopPropagation();
743
1040
  } else if (evt.key === "ArrowRight") {
744
- if (cursorAtEnd) {
1041
+ if (cursorAtTextEnd(input)) {
745
1042
  const fieldName = getFieldName(field);
746
1043
  if (fieldName === "value") {
1044
+ if (clauseIsNotLast(input)) {
1045
+ const filterClause = getFilterClauseElement(field);
1046
+ const combinator = filterClause.nextElementSibling;
1047
+ combinator == null ? void 0 : combinator.focus();
1048
+ }
747
1049
  return;
748
1050
  } else {
749
- const nextField = field.nextSibling;
750
- const nextInput = nextField == null ? void 0 : nextField.querySelector("input");
751
1051
  evt.preventDefault();
752
- nextInput == null ? void 0 : nextInput.focus();
753
- requestAnimationFrame(() => {
754
- nextInput == null ? void 0 : nextInput.select();
755
- });
1052
+ focusField(field.nextSibling);
756
1053
  }
757
1054
  }
758
1055
  evt.stopPropagation();
759
1056
  }
760
1057
  };
761
- var getFilterClauseValue = (filterClause) => {
762
- if ((0, import_vuu_utils6.isMultiValueFilter)(filterClause)) {
763
- return filterClause.values;
764
- } else if ((0, import_vuu_utils6.isSingleValueFilter)(filterClause)) {
765
- return filterClause.value;
766
- } else {
767
- return void 0;
1058
+ var focusFirstClauseIfAllClausesValid = (filterEditor) => {
1059
+ const columInput = Array.from(
1060
+ filterEditor.querySelectorAll(".vuuFilterClauseColumn input")
1061
+ );
1062
+ if (columInput.every((input) => input.value.length > 0)) {
1063
+ setTimeout(() => {
1064
+ const input = columInput.at(0);
1065
+ input == null ? void 0 : input.select();
1066
+ input == null ? void 0 : input.focus();
1067
+ }, 100);
768
1068
  }
769
1069
  };
770
- var useFilterClauseEditor = ({
771
- filterClause,
1070
+
1071
+ // src/filter-clause/useFilterClause.ts
1072
+ var useFilterClause = ({
1073
+ filterClauseModel,
772
1074
  onCancel,
773
- onChange,
774
1075
  columnsByName
775
1076
  }) => {
776
- const columnRef = (0, import_react6.useRef)(null);
777
- const operatorRef = (0, import_react6.useRef)(null);
778
- const [selectedColumn, setSelectedColumn] = (0, import_react6.useState)(filterClause.column ? columnsByName[filterClause.column] : void 0);
779
- const [operator, _setOperator] = (0, import_react6.useState)(
780
- filterClause.op
781
- );
782
- const setOperator = (0, import_react6.useCallback)((op) => {
783
- _setOperator(op);
784
- }, []);
785
- const [value, setValue] = (0, import_react6.useState)(
786
- getFilterClauseValue(filterClause)
787
- );
788
- const handleColumnSelect = (0, import_react6.useCallback)(
789
- (_, column) => {
790
- setSelectedColumn(column != null ? column : void 0);
791
- setOperator(void 0);
792
- setValue(void 0);
793
- setTimeout(() => {
794
- focusNextElement();
795
- }, 100);
796
- },
797
- [setOperator]
1077
+ var _a;
1078
+ const [filterClause, setFilterClause] = (0, import_react5.useState)(
1079
+ filterClauseModel.isValid ? filterClauseModel.asFilter() : {}
798
1080
  );
799
- const removeAndNavigateToNextInputIfAtBoundary = (0, import_react6.useCallback)(
1081
+ (0, import_react5.useMemo)(() => {
1082
+ filterClauseModel.on("filterClause", (filterClause2) => {
1083
+ setFilterClause(filterClause2);
1084
+ });
1085
+ }, [filterClauseModel]);
1086
+ const columnRef = (0, import_react5.useRef)(null);
1087
+ const operatorRef = (0, import_react5.useRef)(null);
1088
+ const removeAndNavigateToNextInputIfAtBoundary = (0, import_react5.useCallback)(
800
1089
  (evt) => {
801
- var _a;
1090
+ var _a2;
802
1091
  const input = evt.target;
803
1092
  if (input.value === "") {
804
- const field = input.closest(
805
- ".vuuFilterClauseField,[data-field]"
806
- );
807
- switch ((_a = field == null ? void 0 : field.dataset) == null ? void 0 : _a.field) {
1093
+ const field = input.closest("[data-field]");
1094
+ switch ((_a2 = field == null ? void 0 : field.dataset) == null ? void 0 : _a2.field) {
808
1095
  case "operator": {
809
- setOperator(void 0);
810
- setSelectedColumn(void 0);
1096
+ filterClauseModel.column = void 0;
811
1097
  focusNextFocusableElement("bwd");
812
1098
  break;
813
1099
  }
814
1100
  case "value": {
815
- setOperator(void 0);
1101
+ filterClauseModel.setOp(void 0);
816
1102
  focusNextFocusableElement("bwd");
817
1103
  break;
818
1104
  }
819
1105
  case "column": {
820
1106
  if (clauseIsNotFirst(input)) {
821
- console.log("This is NOT the first clause");
822
- onCancel == null ? void 0 : onCancel("Backspace");
1107
+ evt.preventDefault();
1108
+ onCancel == null ? void 0 : onCancel(filterClauseModel, "Backspace");
823
1109
  }
824
1110
  }
825
1111
  }
826
1112
  }
827
1113
  },
828
- [onCancel, setOperator]
1114
+ [filterClauseModel, onCancel]
1115
+ );
1116
+ const handleColumnSelect = (0, import_react5.useCallback)(
1117
+ (evt, column) => {
1118
+ var _a2;
1119
+ if ((evt == null ? void 0 : evt.type) === "keydown") {
1120
+ const { key } = evt;
1121
+ if (key === "Tab") {
1122
+ if (filterClauseModel.column === column.name) {
1123
+ return;
1124
+ } else {
1125
+ evt.preventDefault();
1126
+ }
1127
+ }
1128
+ }
1129
+ filterClauseModel.column = (_a2 = column == null ? void 0 : column.name) != null ? _a2 : void 0;
1130
+ setTimeout(() => {
1131
+ focusNextElement();
1132
+ }, 100);
1133
+ },
1134
+ [filterClauseModel]
829
1135
  );
830
- const handleOperatorSelect = (0, import_react6.useCallback)(
1136
+ const handleOperatorSelect = (0, import_react5.useCallback)(
831
1137
  (_, selected) => {
832
1138
  const op = selected;
833
- if (op === void 0 || (0, import_vuu_utils6.isValidFilterClauseOp)(op)) {
834
- setOperator(op);
1139
+ if (op === void 0 || (0, import_vuu_utils8.isValidFilterClauseOp)(op)) {
1140
+ filterClauseModel.setOp(op);
835
1141
  focusNextElement();
836
1142
  } else {
837
1143
  throw Error(
@@ -839,198 +1145,504 @@ var useFilterClauseEditor = ({
839
1145
  );
840
1146
  }
841
1147
  },
842
- [setOperator]
1148
+ [filterClauseModel]
843
1149
  );
844
- const handleChangeValue = (0, import_react6.useCallback)(
845
- (value2) => {
846
- setValue(value2);
847
- if (value2 !== null && value2 !== "") {
848
- if (Array.isArray(value2)) {
849
- onChange({
850
- column: selectedColumn == null ? void 0 : selectedColumn.name,
851
- op: operator,
852
- values: value2
853
- });
854
- } else {
855
- onChange({
856
- column: selectedColumn == null ? void 0 : selectedColumn.name,
857
- op: operator,
858
- value: value2
859
- });
860
- }
861
- }
862
- },
863
- [onChange, operator, selectedColumn == null ? void 0 : selectedColumn.name]
1150
+ const handleChangeValue = (0, import_react5.useCallback)(
1151
+ (value, isFinal) => filterClauseModel.setValue(value, isFinal),
1152
+ [filterClauseModel]
864
1153
  );
865
- const handleDeselectValue = (0, import_react6.useCallback)(() => {
866
- setValue(void 0);
867
- }, []);
868
- const handleKeyDownCaptureInput = (0, import_react6.useCallback)(
1154
+ const handleDeselectValue = (0, import_react5.useCallback)(
1155
+ () => filterClauseModel.setValue(void 0),
1156
+ [filterClauseModel]
1157
+ );
1158
+ const handleKeyDownCaptureNavigation = (0, import_react5.useCallback)(
869
1159
  (evt) => {
870
1160
  if (["ArrowLeft", "ArrowRight"].includes(evt.key)) {
871
- navigateToNextInputIfAtBoundary(evt);
1161
+ navigateToNextItemIfAtBoundary(evt);
872
1162
  } else if (evt.key === "Backspace") {
873
1163
  removeAndNavigateToNextInputIfAtBoundary(evt);
1164
+ } else if (evt.key === "Escape") {
1165
+ onCancel == null ? void 0 : onCancel(filterClauseModel, "Escape");
1166
+ } else if (evt.key === "Tab" && evt.shiftKey) {
1167
+ evt.preventDefault();
1168
+ tabToPreviousFilterCombinator(evt.target);
874
1169
  }
875
1170
  },
876
- [removeAndNavigateToNextInputIfAtBoundary]
877
- );
878
- const handleClear = (0, import_react6.useCallback)(
879
- (e) => {
880
- var _a;
881
- const button = e.target;
882
- const firstInput = (_a = button.closest(".vuuFilterClause")) == null ? void 0 : _a.querySelector("input");
883
- setSelectedColumn(void 0);
884
- setOperator(void 0);
885
- setValue(void 0);
886
- setTimeout(() => {
887
- firstInput.select();
888
- firstInput == null ? void 0 : firstInput.focus();
889
- }, 100);
890
- },
891
- [setOperator]
1171
+ [filterClauseModel, onCancel, removeAndNavigateToNextInputIfAtBoundary]
892
1172
  );
893
- const handleClearKeyDown = (0, import_react6.useCallback)((e) => {
894
- e.stopPropagation();
895
- if (e.key === "Backspace") {
896
- focusNextFocusableElement("bwd");
1173
+ const handleFocus = (0, import_react5.useCallback)((evt) => {
1174
+ if (elementIsFilterClause(evt.target)) {
1175
+ focusField(evt.target);
897
1176
  }
898
1177
  }, []);
899
- const InputProps = (0, import_react6.useMemo)(
1178
+ const InputProps = (0, import_react5.useMemo)(
900
1179
  () => ({
901
1180
  inputProps: {
902
- onKeyDownCapture: handleKeyDownCaptureInput
1181
+ onKeyDownCapture: handleKeyDownCaptureNavigation,
1182
+ tabIndex: -1
903
1183
  }
904
1184
  }),
905
- [handleKeyDownCaptureInput]
1185
+ [handleKeyDownCaptureNavigation]
906
1186
  );
907
- (0, import_react6.useEffect)(() => {
908
- var _a;
909
- const columnInput = (_a = columnRef.current) == null ? void 0 : _a.querySelector("input");
910
- columnInput == null ? void 0 : columnInput.focus();
911
- }, []);
1187
+ (0, import_react5.useEffect)(() => {
1188
+ if (filterClauseModel.column === void 0) {
1189
+ requestAnimationFrame(() => {
1190
+ var _a2;
1191
+ const columnInput = (_a2 = columnRef == null ? void 0 : columnRef.current) == null ? void 0 : _a2.querySelector("input");
1192
+ columnInput == null ? void 0 : columnInput.focus();
1193
+ });
1194
+ }
1195
+ }, [filterClauseModel]);
912
1196
  return {
913
1197
  InputProps,
914
1198
  columnRef,
1199
+ filterClause,
915
1200
  onChangeValue: handleChangeValue,
916
- onClear: handleClear,
917
- onClearKeyDown: handleClearKeyDown,
918
1201
  onDeselectValue: handleDeselectValue,
919
1202
  onColumnSelect: handleColumnSelect,
1203
+ onFocus: handleFocus,
920
1204
  onOperatorSelect: handleOperatorSelect,
921
- operator,
922
1205
  operatorRef,
923
- selectedColumn,
924
- value
1206
+ selectedColumn: columnsByName[(_a = filterClause.column) != null ? _a : ""]
925
1207
  };
926
1208
  };
927
1209
 
928
- // src/filter-clause/FilterClauseEditor.tsx
929
- var import_jsx_runtime7 = require("react/jsx-runtime");
930
- var classBase4 = "vuuFilterClause";
931
- var FilterClauseEditor = ({
1210
+ // src/filter-clause/FilterClause.tsx
1211
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1212
+ var classBase3 = "vuuFilterClause";
1213
+ var FilterClause = ({
932
1214
  className,
933
1215
  columnsByName,
934
1216
  onCancel,
935
- onChange,
936
1217
  onDropdownClose,
937
1218
  onDropdownOpen,
938
- filterClause,
1219
+ filterClauseModel,
939
1220
  suggestionProvider,
940
1221
  tableSchema,
941
1222
  ...htmlAttributes
942
1223
  }) => {
943
- var _a;
1224
+ var _a, _b;
944
1225
  const {
945
1226
  InputProps,
946
1227
  columnRef,
1228
+ filterClause,
947
1229
  onChangeValue,
948
- onClear,
949
- onClearKeyDown,
950
- onDeselectValue,
951
1230
  onColumnSelect,
1231
+ onFocus,
1232
+ onDeselectValue,
952
1233
  onOperatorSelect,
953
- operator,
954
1234
  operatorRef,
955
- selectedColumn,
956
- value
957
- } = useFilterClauseEditor({
958
- filterClause,
1235
+ selectedColumn
1236
+ } = useFilterClause({
1237
+ filterClauseModel,
959
1238
  onCancel,
960
- onChange,
961
1239
  columnsByName
962
1240
  });
963
- const columns = (0, import_react7.useMemo)(() => Object.values(columnsByName), [columnsByName]);
964
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: clsx_default(classBase4, className), ...htmlAttributes, tabIndex: 0, children: [
965
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
966
- ExpandoCombobox,
967
- {
968
- InputProps,
969
- allowBackspaceClearsSelection: true,
970
- className: clsx_default(`${classBase4}Field`, `${classBase4}Column`),
971
- "data-field": "column",
972
- initialHighlightedIndex: 0,
973
- itemToString: (column) => column.name,
974
- onListItemSelect: onColumnSelect,
975
- ref: columnRef,
976
- source: columns,
977
- title: "column",
978
- value: (_a = selectedColumn == null ? void 0 : selectedColumn.name) != null ? _a : ""
1241
+ const columns = (0, import_react6.useMemo)(() => Object.values(columnsByName), [columnsByName]);
1242
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1243
+ "div",
1244
+ {
1245
+ className: clsx_default(classBase3, className),
1246
+ ...htmlAttributes,
1247
+ onFocus,
1248
+ tabIndex: 0,
1249
+ children: [
1250
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1251
+ ExpandoCombobox,
1252
+ {
1253
+ InputProps,
1254
+ allowBackspaceClearsSelection: true,
1255
+ className: clsx_default(`${classBase3}Field`, `${classBase3}Column`),
1256
+ "data-field": "column",
1257
+ initialHighlightedIndex: 0,
1258
+ itemToString: (column) => column.name,
1259
+ onListItemSelect: onColumnSelect,
1260
+ ref: columnRef,
1261
+ source: columns,
1262
+ title: "column",
1263
+ value: filterClause.column
1264
+ },
1265
+ "column-field"
1266
+ ),
1267
+ (selectedColumn == null ? void 0 : selectedColumn.name) ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1268
+ ExpandoCombobox,
1269
+ {
1270
+ InputProps,
1271
+ allowBackspaceClearsSelection: true,
1272
+ className: clsx_default(`${classBase3}Field`, `${classBase3}Operator`, {
1273
+ [`${classBase3}Operator-hidden`]: selectedColumn === null
1274
+ }),
1275
+ "data-field": "operator",
1276
+ initialHighlightedIndex: 0,
1277
+ onListItemSelect: onOperatorSelect,
1278
+ ref: operatorRef,
1279
+ source: getOperators(selectedColumn),
1280
+ title: "operator",
1281
+ value: (_a = filterClause.op) != null ? _a : ""
1282
+ },
1283
+ "operator-field"
1284
+ ) : null,
1285
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1286
+ FilterClauseValueEditor,
1287
+ {
1288
+ InputProps,
1289
+ onChangeValue,
1290
+ onDeselectValue,
1291
+ operator: filterClause.op,
1292
+ selectedColumn,
1293
+ suggestionProvider,
1294
+ table: tableSchema.table,
1295
+ value: (_b = filterClause == null ? void 0 : filterClause.values) != null ? _b : filterClause == null ? void 0 : filterClause.value
1296
+ },
1297
+ "value-field"
1298
+ )
1299
+ ]
1300
+ }
1301
+ );
1302
+ };
1303
+
1304
+ // src/filter-editor/FilterClauseCombinator.tsx
1305
+ var import_vuu_ui_controls5 = require("@vuu-ui/vuu-ui-controls");
1306
+ var import_react7 = require("react");
1307
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1308
+ var classBase4 = "vuuFilterClauseCombinator";
1309
+ var FilterClauseCombinator = ({
1310
+ onChange,
1311
+ onKeyDown,
1312
+ operator
1313
+ }) => {
1314
+ const handleChange = (0, import_react7.useCallback)(
1315
+ (value) => {
1316
+ onChange(value);
1317
+ },
1318
+ [onChange]
1319
+ );
1320
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1321
+ import_vuu_ui_controls5.CycleStateButton,
1322
+ {
1323
+ className: classBase4,
1324
+ onChange: handleChange,
1325
+ onKeyDown,
1326
+ value: operator,
1327
+ values: ["and", "or"],
1328
+ variant: "primary"
1329
+ }
1330
+ );
1331
+ };
1332
+
1333
+ // src/filter-editor/useFilterEditor.ts
1334
+ var import_react8 = require("react");
1335
+ var useFilterEditor = ({
1336
+ columnDescriptors,
1337
+ filter,
1338
+ onCancel,
1339
+ onSave
1340
+ }) => {
1341
+ const filterModel = (0, import_react8.useMemo)(() => {
1342
+ return new FilterModel(filter);
1343
+ }, [filter]);
1344
+ const [_, forceRefresh] = (0, import_react8.useState)({});
1345
+ const [isValid, setIsValid] = (0, import_react8.useState)(filterModel.isValid);
1346
+ const clauseCombinatorRef = (0, import_react8.useRef)(void 0);
1347
+ const saveButtonRef = (0, import_react8.useRef)(null);
1348
+ const containerRef = (0, import_react8.useRef)(null);
1349
+ const setContainer = (0, import_react8.useCallback)((el) => {
1350
+ containerRef.current = el;
1351
+ if (el) {
1352
+ focusFirstClauseIfAllClausesValid(el);
1353
+ }
1354
+ }, []);
1355
+ const saveButtonMenuBuilder = (0, import_react8.useCallback)((_2, options) => {
1356
+ switch (clauseCombinatorRef.current) {
1357
+ case "and":
1358
+ return [{ action: "and-clause", label: "AND", options }];
1359
+ case "or":
1360
+ return [{ action: "or-clause", label: "OR", options }];
1361
+ default:
1362
+ return [
1363
+ { action: "and-clause", label: "AND", options },
1364
+ { action: "or-clause", label: "OR", options }
1365
+ ];
1366
+ }
1367
+ }, []);
1368
+ const columnsByName = (0, import_react8.useMemo)(
1369
+ () => columnDescriptorsByName(columnDescriptors),
1370
+ [columnDescriptors]
1371
+ );
1372
+ const isLastFilterClause = (0, import_react8.useCallback)(
1373
+ (index) => index !== void 0 && filterModel.filterClauses.length === index + 1,
1374
+ [filterModel]
1375
+ );
1376
+ (0, import_react8.useMemo)(() => {
1377
+ const setValid = (isValid2) => {
1378
+ setIsValid(isValid2);
1379
+ };
1380
+ const valueChanged = (_filter2, isValid2) => {
1381
+ if (isValid2) {
1382
+ const [filterClauseIndex, fieldName] = getFocusedFieldDetails();
1383
+ if (fieldName === "value" && isLastFilterClause(filterClauseIndex)) {
1384
+ requestAnimationFrame(() => {
1385
+ var _a;
1386
+ (_a = saveButtonRef.current) == null ? void 0 : _a.focus();
1387
+ });
1388
+ }
979
1389
  }
980
- ),
981
- (selectedColumn == null ? void 0 : selectedColumn.name) ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
982
- ExpandoCombobox,
983
- {
984
- InputProps,
985
- allowBackspaceClearsSelection: true,
986
- className: clsx_default(`${classBase4}Field`, `${classBase4}Operator`, {
987
- [`${classBase4}Operator-hidden`]: selectedColumn === null
988
- }),
989
- "data-field": "operator",
990
- initialHighlightedIndex: 0,
991
- onListItemSelect: onOperatorSelect,
992
- ref: operatorRef,
993
- source: getOperators(selectedColumn),
994
- title: "operator",
995
- value: operator != null ? operator : ""
1390
+ };
1391
+ filterModel.on("isValid", setValid);
1392
+ filterModel.on("filter", valueChanged);
1393
+ }, [filterModel, isLastFilterClause]);
1394
+ const handleCancelFilterClause = (0, import_react8.useCallback)(
1395
+ (filterClause, reason) => {
1396
+ if (reason === "Backspace") {
1397
+ const indexOfFilterClause = filterModel.filterClauses.indexOf(filterClause);
1398
+ filterModel.removeFilterClause(filterClause);
1399
+ forceRefresh({});
1400
+ if (reason === "Backspace" && containerRef.current) {
1401
+ if (indexOfFilterClause > 0) {
1402
+ focusFilterClauseField(
1403
+ containerRef.current,
1404
+ indexOfFilterClause - 1
1405
+ );
1406
+ }
1407
+ }
1408
+ } else {
1409
+ console.log(
1410
+ `cancel because of Escape valid clause ${filterClause.isValid}`
1411
+ );
1412
+ onCancel(filter);
996
1413
  }
997
- ) : null,
998
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
999
- FilterClauseValueEditor,
1000
- {
1001
- InputProps,
1002
- onChangeValue,
1003
- onDeselectValue,
1004
- operator,
1005
- selectedColumn,
1006
- suggestionProvider,
1007
- table: tableSchema == null ? void 0 : tableSchema.table,
1008
- value
1414
+ },
1415
+ [filter, filterModel, onCancel]
1416
+ );
1417
+ const invokeMenuAction = (0, import_react8.useCallback)(
1418
+ ({ menuId }) => {
1419
+ switch (menuId) {
1420
+ case "save": {
1421
+ const savedFilter = filterModel.asFilter();
1422
+ const newOrUpdatedFilter = (filter == null ? void 0 : filter.name) ? {
1423
+ ...savedFilter,
1424
+ name: filter.name
1425
+ } : savedFilter;
1426
+ onSave(newOrUpdatedFilter);
1427
+ return true;
1428
+ }
1429
+ case "and-clause": {
1430
+ clauseCombinatorRef.current = "and";
1431
+ filterModel.addNewFilterClause("and");
1432
+ return true;
1433
+ }
1434
+ case "or-clause":
1435
+ clauseCombinatorRef.current = "or";
1436
+ filterModel.addNewFilterClause("or");
1437
+ return true;
1438
+ default:
1439
+ return false;
1009
1440
  }
1010
- ),
1011
- value !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1012
- import_core.Button,
1013
- {
1014
- className: `${classBase4}-clearButton`,
1015
- onClick: onClear,
1016
- onKeyDown: onClearKeyDown,
1017
- "data-icon": "close"
1441
+ },
1442
+ [filter == null ? void 0 : filter.name, filterModel, onSave]
1443
+ );
1444
+ const handleKeyDownSaveButton = (0, import_react8.useCallback)(
1445
+ (evt) => {
1446
+ if (evt.key === "Tab" && evt.shiftKey) {
1447
+ evt.preventDefault();
1448
+ const target = evt.target;
1449
+ const filterEditor = target.closest(".vuuFilterEditor");
1450
+ focusLastClauseValue(filterEditor);
1451
+ } else if (evt.key === "Escape") {
1452
+ onCancel(filter);
1018
1453
  }
1019
- ) : null
1454
+ },
1455
+ [filter, onCancel]
1456
+ );
1457
+ const handleKeyDownNavigationFromCombinator = (0, import_react8.useCallback)((evt) => {
1458
+ const { target, key, shiftKey } = evt;
1459
+ if (key === "ArrowLeft") {
1460
+ evt.preventDefault();
1461
+ navigateToNextFilterClause(target, "bwd");
1462
+ } else if (key === "ArrowRight") {
1463
+ evt.preventDefault();
1464
+ navigateToNextFilterClause(target, "fwd");
1465
+ } else if (key === "Tab" && shiftKey) {
1466
+ evt.preventDefault();
1467
+ navigateToNextFilterClause(target, "bwd");
1468
+ }
1469
+ }, []);
1470
+ const handleClickSaveButton = (0, import_react8.useMemo)(
1471
+ () => () => invokeMenuAction({
1472
+ menuId: "save",
1473
+ options: {},
1474
+ type: "menu-action"
1475
+ }),
1476
+ [invokeMenuAction]
1477
+ );
1478
+ const saveButtonProps = {
1479
+ PopupMenuProps: {
1480
+ icon: "more-vert",
1481
+ menuBuilder: saveButtonMenuBuilder,
1482
+ menuActionHandler: invokeMenuAction,
1483
+ menuLocation: "filter-save-menu"
1484
+ },
1485
+ onClick: handleClickSaveButton,
1486
+ onKeyDown: handleKeyDownSaveButton
1487
+ };
1488
+ const onChangeFilterCombinator = (0, import_react8.useCallback)(
1489
+ (op) => {
1490
+ filterModel.setOp(op);
1491
+ clauseCombinatorRef.current = op;
1492
+ forceRefresh({});
1493
+ },
1494
+ [filterModel]
1495
+ );
1496
+ const handleCancelFilterEdit = (0, import_react8.useCallback)(() => {
1497
+ onCancel(filter);
1498
+ }, [filter, onCancel]);
1499
+ return {
1500
+ columnsByName,
1501
+ filterModel,
1502
+ isValid,
1503
+ onCancelFilterClause: handleCancelFilterClause,
1504
+ onCancelFilterEdit: handleCancelFilterEdit,
1505
+ onChangeFilterCombinator,
1506
+ onKeyDownCombinator: handleKeyDownNavigationFromCombinator,
1507
+ saveButtonProps,
1508
+ saveButtonRef,
1509
+ setContainer
1510
+ };
1511
+ };
1512
+ function columnDescriptorsByName(columns) {
1513
+ return columns.reduce((m, col) => ({ ...m, [col.name]: col }), {});
1514
+ }
1515
+
1516
+ // src/filter-editor/FilterEditor.tsx
1517
+ var import_core = require("@salt-ds/core");
1518
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1519
+ var import_react9 = require("react");
1520
+ var classBase5 = "vuuFilterEditor";
1521
+ var FilterEditor = ({
1522
+ FilterClauseEditorProps,
1523
+ columnDescriptors,
1524
+ filter,
1525
+ onCancel,
1526
+ onSave,
1527
+ tableSchema,
1528
+ ...htmlAttributes
1529
+ }) => {
1530
+ const {
1531
+ columnsByName,
1532
+ filterModel,
1533
+ setContainer,
1534
+ onCancelFilterClause,
1535
+ onCancelFilterEdit,
1536
+ onChangeFilterCombinator,
1537
+ onKeyDownCombinator,
1538
+ saveButtonRef,
1539
+ saveButtonProps
1540
+ } = useFilterEditor({
1541
+ columnDescriptors,
1542
+ filter,
1543
+ onCancel,
1544
+ onSave
1545
+ });
1546
+ const getContents = () => {
1547
+ const { op } = filterModel;
1548
+ const content = [];
1549
+ filterModel.filterClauses.forEach((filterClauseModel, i) => {
1550
+ if (i > 0 && op) {
1551
+ content.push(
1552
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1553
+ FilterClauseCombinator,
1554
+ {
1555
+ onChange: onChangeFilterCombinator,
1556
+ onKeyDown: onKeyDownCombinator,
1557
+ operator: op
1558
+ },
1559
+ `filter-operator-${i}`
1560
+ )
1561
+ );
1562
+ }
1563
+ content.push(
1564
+ /* @__PURE__ */ (0, import_react9.createElement)(
1565
+ FilterClause,
1566
+ {
1567
+ ...FilterClauseEditorProps,
1568
+ columnsByName,
1569
+ "data-index": i,
1570
+ filterClauseModel,
1571
+ key: `editor-${i}`,
1572
+ onCancel: onCancelFilterClause,
1573
+ tableSchema
1574
+ }
1575
+ )
1576
+ );
1577
+ });
1578
+ return content;
1579
+ };
1580
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { ...htmlAttributes, className: classBase5, ref: setContainer, children: [
1581
+ getContents(),
1582
+ /* @__PURE__ */ (0, import_react9.createElement)(
1583
+ import_vuu_ui_controls6.SplitButton,
1584
+ {
1585
+ ...saveButtonProps,
1586
+ disabled: !filterModel.isValid,
1587
+ key: "save-button",
1588
+ ref: saveButtonRef
1589
+ },
1590
+ "Save"
1591
+ ),
1592
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core.Button, { onClick: onCancelFilterEdit, variant: "secondary", children: "Cancel" })
1020
1593
  ] });
1021
1594
  };
1022
1595
 
1023
1596
  // src/filter-pill/FilterPill.tsx
1024
- var import_vuu_popups3 = require("@vuu-ui/vuu-popups");
1025
- var import_vuu_ui_controls6 = require("@vuu-ui/vuu-ui-controls");
1597
+ var import_vuu_popups = require("@vuu-ui/vuu-popups");
1598
+ var import_vuu_ui_controls7 = require("@vuu-ui/vuu-ui-controls");
1599
+ var import_vuu_utils13 = require("@vuu-ui/vuu-utils");
1600
+ var import_react10 = require("react");
1601
+
1602
+ // src/filter-pill/filterAsReactNode.tsx
1026
1603
  var import_vuu_utils10 = require("@vuu-ui/vuu-utils");
1027
- var import_react9 = require("react");
1028
1604
 
1029
- // src/filter-pill-menu/FilterPillMenu.tsx
1030
- var import_vuu_popups2 = require("@vuu-ui/vuu-popups");
1031
- var import_react8 = require("react");
1605
+ // src/filter-pill/getFilterLabel.ts
1606
+ var import_vuu_utils9 = require("@vuu-ui/vuu-utils");
1607
+ var getColumnLabel = (filter, columnsByName) => {
1608
+ var _a;
1609
+ const column = columnsByName == null ? void 0 : columnsByName[filter.column];
1610
+ if (column) {
1611
+ return (_a = column.label) != null ? _a : column.name;
1612
+ } else {
1613
+ return filter.column;
1614
+ }
1615
+ };
1616
+ var getFilterLabel = (columnsByName) => (filter) => {
1617
+ if ((0, import_vuu_utils9.isMultiClauseFilter)(filter)) {
1618
+ return filter.filters.map((f) => getFilterLabel(columnsByName)(f)).join(", ");
1619
+ } else {
1620
+ return getColumnLabel(filter, columnsByName);
1621
+ }
1622
+ };
1623
+
1624
+ // src/filter-pill/filterAsReactNode.tsx
1625
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1626
+ var filterAsReactNode = (f, getLabel = getFilterLabel()) => {
1627
+ if ((0, import_vuu_utils10.isMultiClauseFilter)(f)) {
1628
+ const heading = f.op === "and" ? "Match all ..." : "Match any ...";
1629
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("ul", { children: [
1630
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: heading }),
1631
+ f.filters.map((f2, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", { children: filterAsReactNode(f2, getLabel) }, i))
1632
+ ] });
1633
+ } else if ((0, import_vuu_utils10.isMultiValueFilter)(f)) {
1634
+ if (f.values.length > 3) {
1635
+ const values = f.values.slice(0, 3);
1636
+ return `${getLabel({ ...f, values }).slice(0, -1)},...]`;
1637
+ } else {
1638
+ return getLabel(f);
1639
+ }
1640
+ } else {
1641
+ return getLabel(f);
1642
+ }
1643
+ };
1032
1644
 
1033
- // src/filter-pill-menu/FilterPillMenuOptions.ts
1645
+ // src/filter-pill/FilterPillMenuOptions.ts
1034
1646
  var closeCommand = (options) => ({
1035
1647
  label: `Close`,
1036
1648
  location: "filter",
@@ -1049,72 +1661,18 @@ var renameCommand = (options) => ({
1049
1661
  action: `rename-filter`,
1050
1662
  options
1051
1663
  });
1052
- var editCommand = (options) => ({
1053
- label: `Edit`,
1054
- location: "filter",
1055
- action: "edit-filter",
1056
- options
1057
- });
1058
-
1059
- // src/filter-pill-menu/FilterPillMenu.tsx
1060
- var import_jsx_runtime8 = require("react/jsx-runtime");
1061
- var classBase5 = "vuuFilterPillMenu";
1062
- var FilterPillMenu = ({
1063
- allowClose = true,
1064
- allowDelete = true,
1065
- allowEdit = true,
1066
- allowRename = true,
1067
- filter,
1068
- location,
1069
- onMenuAction,
1070
- onMenuClose
1071
- }) => {
1072
- const [menuBuilder, menuOptions] = (0, import_react8.useMemo)(
1073
- () => [
1074
- (_location, options) => {
1075
- const menuItems = [];
1076
- if (allowRename) {
1077
- menuItems.push(renameCommand(options));
1078
- }
1079
- if (allowEdit) {
1080
- menuItems.push(editCommand(options));
1081
- }
1082
- if (allowClose) {
1083
- menuItems.push(closeCommand(options));
1084
- }
1085
- if (allowDelete) {
1086
- menuItems.push(deleteCommand(options));
1087
- }
1088
- return menuItems;
1089
- },
1090
- {
1091
- filter
1092
- }
1093
- ],
1094
- [allowClose, allowDelete, allowEdit, allowRename, filter]
1095
- );
1096
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1097
- import_vuu_popups2.PopupMenu,
1098
- {
1099
- className: classBase5,
1100
- menuBuilder,
1101
- menuActionHandler: onMenuAction,
1102
- menuLocation: clsx_default("filter", location),
1103
- menuOptions,
1104
- onMenuClose,
1105
- tabIndex: -1
1106
- }
1107
- );
1108
- };
1109
-
1110
- // src/filter-pill/filterAsReactNode.tsx
1111
- var import_vuu_utils9 = require("@vuu-ui/vuu-utils");
1664
+ var editCommand = (options) => ({
1665
+ label: `Edit`,
1666
+ location: "filter",
1667
+ action: "edit-filter",
1668
+ options
1669
+ });
1112
1670
 
1113
- // src/filter-pill/getFilterLabel.ts
1114
- var import_vuu_utils8 = require("@vuu-ui/vuu-utils");
1671
+ // src/filter-pill/getFilterTooltipText.ts
1672
+ var import_vuu_utils12 = require("@vuu-ui/vuu-utils");
1115
1673
 
1116
1674
  // src/filter-utils.ts
1117
- var import_vuu_utils7 = require("@vuu-ui/vuu-utils");
1675
+ var import_vuu_utils11 = require("@vuu-ui/vuu-utils");
1118
1676
  var AND = "and";
1119
1677
  var EQUALS = "=";
1120
1678
  var GREATER_THAN = ">";
@@ -1125,7 +1683,7 @@ var ENDS_WITH = "ends";
1125
1683
  var IN = "in";
1126
1684
  var filterClauses = (filter, clauses = []) => {
1127
1685
  if (filter) {
1128
- if ((0, import_vuu_utils7.isMultiClauseFilter)(filter)) {
1686
+ if ((0, import_vuu_utils11.isMultiClauseFilter)(filter)) {
1129
1687
  filter.filters.forEach((f) => clauses.push(...filterClauses(f)));
1130
1688
  } else {
1131
1689
  clauses.push(filter);
@@ -1148,7 +1706,7 @@ var removeLastClause = (filter) => {
1148
1706
  }
1149
1707
  };
1150
1708
  var addClause = (existingFilter, clause, { combineWith = AND } = DEFAULT_ADD_FILTER_OPTS) => {
1151
- if ((0, import_vuu_utils7.isMultiClauseFilter)(existingFilter) && existingFilter.op === combineWith) {
1709
+ if ((0, import_vuu_utils11.isMultiClauseFilter)(existingFilter) && existingFilter.op === combineWith) {
1152
1710
  return {
1153
1711
  ...existingFilter,
1154
1712
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -1162,41 +1720,17 @@ var addClause = (existingFilter, clause, { combineWith = AND } = DEFAULT_ADD_FIL
1162
1720
  };
1163
1721
  }
1164
1722
  };
1165
- var replaceClause = (existingFilter, clause, idx) => {
1166
- if (existingFilter === void 0)
1167
- return clause;
1168
- return findAndReplaceClauseAtGivenIndex(existingFilter, clause, idx).filter;
1169
- };
1170
- function findAndReplaceClauseAtGivenIndex(existingFilter, clause, idx, currIdx = 0) {
1171
- if ((0, import_vuu_utils7.isMultiClauseFilter)(existingFilter)) {
1172
- let i = currIdx;
1173
- const filters = existingFilter.filters.map((f) => {
1174
- const res = findAndReplaceClauseAtGivenIndex(f, clause, idx, i);
1175
- i = res.nextIdx;
1176
- return res.filter;
1177
- });
1178
- return { filter: { ...existingFilter, filters }, nextIdx: i };
1179
- } else if (idx !== currIdx) {
1180
- return { filter: existingFilter, nextIdx: currIdx + 1 };
1181
- } else {
1182
- const { name } = existingFilter;
1183
- return {
1184
- filter: { ...(0, import_vuu_utils7.isNotNullOrUndefined)(name) ? { name } : {}, ...clause },
1185
- nextIdx: currIdx + 1
1186
- };
1187
- }
1188
- }
1189
1723
  var addFilter = (existingFilter, filter, { combineWith = AND } = DEFAULT_ADD_FILTER_OPTS) => {
1190
1724
  var _a;
1191
1725
  if (includesNoValues(filter)) {
1192
- if ((0, import_vuu_utils7.isMultiClauseFilter)(filter)) {
1726
+ if ((0, import_vuu_utils11.isMultiClauseFilter)(filter)) {
1193
1727
  } else {
1194
1728
  existingFilter = removeFilterForColumn(existingFilter, {
1195
1729
  name: filter.column
1196
1730
  });
1197
1731
  }
1198
1732
  } else if (includesAllValues(filter)) {
1199
- if ((0, import_vuu_utils7.isMultiClauseFilter)(filter)) {
1733
+ if ((0, import_vuu_utils11.isMultiClauseFilter)(filter)) {
1200
1734
  }
1201
1735
  return removeFilterForColumn(existingFilter, { name: (_a = filter.column) != null ? _a : "" });
1202
1736
  }
@@ -1231,10 +1765,10 @@ var includesNoValues = (filter) => {
1231
1765
  if (!filter) {
1232
1766
  return false;
1233
1767
  }
1234
- if ((0, import_vuu_utils7.isInFilter)(filter) && filter.values.length === 0) {
1768
+ if ((0, import_vuu_utils11.isInFilter)(filter) && filter.values.length === 0) {
1235
1769
  return true;
1236
1770
  }
1237
- return (0, import_vuu_utils7.isAndFilter)(filter) && filter.filters.some((f) => includesNoValues(f));
1771
+ return (0, import_vuu_utils11.isAndFilter)(filter) && filter.filters.some((f) => includesNoValues(f));
1238
1772
  };
1239
1773
  var includesAllValues = (filter) => {
1240
1774
  if (!filter) {
@@ -1252,7 +1786,7 @@ var merge = (f1, f2) => {
1252
1786
  if (includesNoValues(f2)) {
1253
1787
  return f2;
1254
1788
  }
1255
- if ((0, import_vuu_utils7.isInFilter)(f1) && (0, import_vuu_utils7.isInFilter)(f2)) {
1789
+ if ((0, import_vuu_utils11.isInFilter)(f1) && (0, import_vuu_utils11.isInFilter)(f2)) {
1256
1790
  return {
1257
1791
  ...f1,
1258
1792
  values: [
@@ -1262,7 +1796,7 @@ var merge = (f1, f2) => {
1262
1796
  )
1263
1797
  ]
1264
1798
  };
1265
- } else if ((0, import_vuu_utils7.isInFilter)(f1) && f2.op === EQUALS) {
1799
+ } else if ((0, import_vuu_utils11.isInFilter)(f1) && f2.op === EQUALS) {
1266
1800
  return {
1267
1801
  ...f1,
1268
1802
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -1318,14 +1852,14 @@ var splitFilterOnColumn = (columnName, filter) => {
1318
1852
  if (filter.op !== AND) {
1319
1853
  return [void 0, filter];
1320
1854
  }
1321
- const [[columnFilter = void 0], filters] = (0, import_vuu_utils7.partition)(
1855
+ const [[columnFilter = void 0], filters] = (0, import_vuu_utils11.partition)(
1322
1856
  filter.filters,
1323
1857
  (f) => f.column === columnName
1324
1858
  );
1325
1859
  return filters.length === 1 ? [columnFilter, filters[0]] : [columnFilter, { op: AND, filters }];
1326
1860
  };
1327
1861
  var overrideColName = (filter, column) => {
1328
- if ((0, import_vuu_utils7.isMultiClauseFilter)(filter)) {
1862
+ if ((0, import_vuu_utils11.isMultiClauseFilter)(filter)) {
1329
1863
  return {
1330
1864
  op: filter.op,
1331
1865
  filters: filter.filters.map((f) => overrideColName(f, column))
@@ -1354,7 +1888,7 @@ var removeFilterForColumn = (sourceFilter, column) => {
1354
1888
  if (sourceFilter.column === colName) {
1355
1889
  return void 0;
1356
1890
  }
1357
- if ((0, import_vuu_utils7.isAndFilter)(sourceFilter) || (0, import_vuu_utils7.isOrFilter)(sourceFilter)) {
1891
+ if ((0, import_vuu_utils11.isAndFilter)(sourceFilter) || (0, import_vuu_utils11.isOrFilter)(sourceFilter)) {
1358
1892
  const { op } = sourceFilter;
1359
1893
  const filters = sourceFilter.filters;
1360
1894
  const otherColFilters = filters.filter((f) => f.column !== colName);
@@ -1386,7 +1920,7 @@ var filterEquals = (f1, f2, strict = false) => {
1386
1920
  return true;
1387
1921
  }
1388
1922
  if (f1 && f2 && canMerge(f1, f2)) {
1389
- return f1.op === f2.op && ((0, import_vuu_utils7.isSingleValueFilter)(f1) && (0, import_vuu_utils7.isSingleValueFilter)(f2) && f1.value === f2.value || (0, import_vuu_utils7.isMultiValueFilter)(f1) && (0, import_vuu_utils7.isMultiValueFilter)(f2) && sameValues(f1.values, f2.values));
1923
+ return f1.op === f2.op && ((0, import_vuu_utils11.isSingleValueFilter)(f1) && (0, import_vuu_utils11.isSingleValueFilter)(f2) && f1.value === f2.value || (0, import_vuu_utils11.isMultiValueFilter)(f1) && (0, import_vuu_utils11.isMultiValueFilter)(f2) && sameValues(f1.values, f2.values));
1390
1924
  }
1391
1925
  return false;
1392
1926
  };
@@ -1403,7 +1937,7 @@ var updateFilter = (filter, newFilter, mode) => {
1403
1937
  }
1404
1938
  const { column: columnName } = newFilter;
1405
1939
  if (columnName) {
1406
- const existingClause = newFilter.column ? (0, import_vuu_utils7.extractFilterForColumn)(filter, columnName) : void 0;
1940
+ const existingClause = newFilter.column ? (0, import_vuu_utils11.extractFilterForColumn)(filter, columnName) : void 0;
1407
1941
  if (existingClause && columnName) {
1408
1942
  const result = removeFilterForColumn(filter, { name: columnName });
1409
1943
  return updateFilter(result, newFilter, "add");
@@ -1445,7 +1979,7 @@ var getNumericFilter = (column, op, value) => {
1445
1979
  return { column, op, value };
1446
1980
  };
1447
1981
 
1448
- // src/filter-pill/getFilterLabel.ts
1982
+ // src/filter-pill/getFilterTooltipText.ts
1449
1983
  function applyFormatter(filter, formatter) {
1450
1984
  if ("value" in filter) {
1451
1985
  return { ...filter, value: formatter(filter.value) };
@@ -1455,11 +1989,11 @@ function applyFormatter(filter, formatter) {
1455
1989
  }
1456
1990
  function formatFilterValue(filter, columnsByName) {
1457
1991
  const column = columnsByName == null ? void 0 : columnsByName[filter.column];
1458
- if (column && (0, import_vuu_utils8.isDateTimeColumn)(column)) {
1459
- const pattern = (0, import_vuu_utils8.dateTimePattern)(column.type);
1992
+ if (column && (0, import_vuu_utils12.isDateTimeColumn)(column)) {
1993
+ const pattern = (0, import_vuu_utils12.dateTimePattern)(column.type);
1460
1994
  const formatter = (n) => {
1461
1995
  var _a;
1462
- return (0, import_vuu_utils8.formatDate)({ date: (_a = pattern.date) != null ? _a : import_vuu_utils8.defaultPatternsByType.date })(
1996
+ return (0, import_vuu_utils12.formatDate)({ date: (_a = pattern.date) != null ? _a : import_vuu_utils12.defaultPatternsByType.date })(
1463
1997
  new Date(n)
1464
1998
  );
1465
1999
  };
@@ -1470,37 +2004,16 @@ function formatFilterValue(filter, columnsByName) {
1470
2004
  }
1471
2005
  return filter;
1472
2006
  }
1473
- var getFilterLabel = (columnsByName) => (filter) => {
1474
- if ((0, import_vuu_utils8.isMultiClauseFilter)(filter)) {
2007
+ var getFilterTooltipText = (columnsByName) => (filter) => {
2008
+ if ((0, import_vuu_utils12.isMultiClauseFilter)(filter)) {
1475
2009
  const [firstClause] = filterClauses(filter);
1476
2010
  const formattedFilter = formatFilterValue(
1477
2011
  firstClause,
1478
2012
  columnsByName
1479
2013
  );
1480
- return `${(0, import_vuu_utils8.filterAsQuery)(formattedFilter)} ${filter.op} ...`;
1481
- } else {
1482
- return (0, import_vuu_utils8.filterAsQuery)(formatFilterValue(filter, columnsByName));
1483
- }
1484
- };
1485
-
1486
- // src/filter-pill/filterAsReactNode.tsx
1487
- var import_jsx_runtime9 = require("react/jsx-runtime");
1488
- var filterAsReactNode = (f, getLabel = getFilterLabel()) => {
1489
- if ((0, import_vuu_utils9.isMultiClauseFilter)(f)) {
1490
- const heading = f.op === "and" ? "Match all ..." : "Match any ...";
1491
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("ul", { children: [
1492
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: heading }),
1493
- f.filters.map((f2, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", { children: filterAsReactNode(f2, getLabel) }, i))
1494
- ] });
1495
- } else if ((0, import_vuu_utils9.isMultiValueFilter)(f)) {
1496
- if (f.values.length > 3) {
1497
- const values = f.values.slice(0, 3);
1498
- return `${getLabel({ ...f, values }).slice(0, -1)},...]`;
1499
- } else {
1500
- return getLabel(f);
1501
- }
2014
+ return `${(0, import_vuu_utils12.filterAsQuery)(formattedFilter)} ${filter.op} ...`;
1502
2015
  } else {
1503
- return getLabel(f);
2016
+ return (0, import_vuu_utils12.filterAsQuery)(formatFilterValue(filter, columnsByName));
1504
2017
  }
1505
2018
  };
1506
2019
 
@@ -1508,31 +2021,37 @@ var filterAsReactNode = (f, getLabel = getFilterLabel()) => {
1508
2021
  var import_jsx_runtime10 = require("react/jsx-runtime");
1509
2022
  var classBase6 = "vuuFilterPill";
1510
2023
  var FilterPill = ({
2024
+ allowClose = true,
2025
+ allowDelete = true,
2026
+ allowEdit = true,
2027
+ allowRename = true,
1511
2028
  className: classNameProp,
1512
2029
  columnsByName,
1513
2030
  editable = true,
2031
+ editing = false,
2032
+ editLabelApiRef,
1514
2033
  filter,
1515
2034
  id: idProp,
1516
2035
  onBeginEdit,
1517
2036
  onExitEditMode,
1518
2037
  onMenuAction,
1519
- showMenu = true,
1520
2038
  ...htmlAttributes
1521
2039
  }) => {
1522
- const rootRef = (0, import_react9.useRef)(null);
1523
- const handleEnterEditMode = (0, import_react9.useCallback)(() => {
2040
+ const rootRef = (0, import_react10.useRef)(null);
2041
+ const handleEnterEditMode = (0, import_react10.useCallback)(() => {
1524
2042
  onBeginEdit == null ? void 0 : onBeginEdit(filter);
1525
2043
  }, [filter, onBeginEdit]);
1526
2044
  const getLabel = getFilterLabel(columnsByName);
1527
- const label = (0, import_react9.useMemo)(
2045
+ const label = (0, import_react10.useMemo)(
1528
2046
  () => {
1529
2047
  var _a;
1530
2048
  return (_a = filter.name) != null ? _a : getLabel(filter);
1531
2049
  },
1532
2050
  [getLabel, filter]
1533
2051
  );
1534
- const id = (0, import_vuu_utils10.useId)(idProp);
1535
- const handleMenuClose = (0, import_react9.useCallback)((reason) => {
2052
+ const getTooltipTextl = getFilterTooltipText(columnsByName);
2053
+ const id = (0, import_vuu_utils13.useId)(idProp);
2054
+ const handleMenuClose = (0, import_react10.useCallback)((reason) => {
1536
2055
  if ((reason == null ? void 0 : reason.type) === "escape") {
1537
2056
  requestAnimationFrame(() => {
1538
2057
  if (rootRef.current) {
@@ -1541,58 +2060,124 @@ var FilterPill = ({
1541
2060
  });
1542
2061
  }
1543
2062
  }, []);
1544
- const { anchorProps, tooltipProps } = (0, import_vuu_popups3.useTooltip)({
2063
+ const popupMenuProps = (0, import_react10.useMemo)(
2064
+ () => ({
2065
+ icon: "more-vert",
2066
+ menuBuilder: (_location, options) => {
2067
+ const menuItems = [];
2068
+ if (allowRename) {
2069
+ menuItems.push(renameCommand(options));
2070
+ }
2071
+ if (allowEdit) {
2072
+ menuItems.push(editCommand(options));
2073
+ }
2074
+ if (allowClose) {
2075
+ menuItems.push(closeCommand(options));
2076
+ }
2077
+ if (allowDelete) {
2078
+ menuItems.push(deleteCommand(options));
2079
+ }
2080
+ return menuItems;
2081
+ },
2082
+ menuActionHandler: onMenuAction,
2083
+ menuLocation: "filter-pill-menu",
2084
+ menuOptions: {
2085
+ filter
2086
+ },
2087
+ onMenuClose: handleMenuClose
2088
+ }),
2089
+ [
2090
+ allowClose,
2091
+ allowDelete,
2092
+ allowEdit,
2093
+ allowRename,
2094
+ filter,
2095
+ handleMenuClose,
2096
+ onMenuAction
2097
+ ]
2098
+ );
2099
+ const handleExitEditMode = (0, import_react10.useCallback)(
2100
+ (originalValue, newValue) => {
2101
+ onExitEditMode == null ? void 0 : onExitEditMode(originalValue, newValue);
2102
+ requestAnimationFrame(() => {
2103
+ var _a, _b;
2104
+ (_b = (_a = rootRef.current) == null ? void 0 : _a.querySelector("button")) == null ? void 0 : _b.focus();
2105
+ });
2106
+ },
2107
+ [onExitEditMode]
2108
+ );
2109
+ const { anchorProps, hideTooltip, showTooltip, tooltipProps } = (0, import_vuu_popups.useTooltip)({
2110
+ anchorQuery: ".vuuFilterPill",
1545
2111
  id,
1546
- placement: "below",
1547
- tooltipContent: filterAsReactNode(filter, getLabel)
2112
+ placement: ["above", "below"],
2113
+ tooltipContent: filterAsReactNode(filter, getTooltipTextl)
1548
2114
  });
2115
+ const buttonProps = {
2116
+ onBlur: hideTooltip,
2117
+ onFocus: (0, import_react10.useCallback)(() => {
2118
+ showTooltip(rootRef);
2119
+ }, [showTooltip])
2120
+ };
1549
2121
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1550
- "div",
2122
+ import_vuu_ui_controls7.SplitStateButton,
1551
2123
  {
1552
2124
  ...anchorProps,
1553
2125
  ...htmlAttributes,
2126
+ ButtonProps: buttonProps,
2127
+ PopupMenuProps: popupMenuProps,
1554
2128
  className: clsx_default(classBase6, classNameProp),
1555
2129
  "data-text": label,
1556
2130
  ref: rootRef,
1557
2131
  children: [
1558
2132
  editable && onExitEditMode ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1559
- import_vuu_ui_controls6.EditableLabel,
2133
+ import_vuu_ui_controls7.EditableLabel,
1560
2134
  {
1561
2135
  defaultValue: label,
2136
+ editing,
2137
+ editLabelApiRef,
1562
2138
  onEnterEditMode: handleEnterEditMode,
1563
- onExitEditMode
2139
+ onExitEditMode: handleExitEditMode
1564
2140
  },
1565
2141
  label
1566
- ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: `${classBase6}-label`, children: label }),
1567
- showMenu && onMenuAction ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1568
- FilterPillMenu,
1569
- {
1570
- filter,
1571
- onMenuAction,
1572
- onMenuClose: handleMenuClose
1573
- }
1574
- ) : null,
1575
- tooltipProps && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_vuu_popups3.Tooltip, { ...tooltipProps })
2142
+ ) : label,
2143
+ tooltipProps && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_vuu_popups.Tooltip, { className: `${classBase6}-tooltip`, ...tooltipProps })
1576
2144
  ]
1577
2145
  }
1578
2146
  );
1579
2147
  };
1580
2148
 
1581
2149
  // src/filter-bar/FilterBarMenu.tsx
1582
- var import_vuu_popups4 = require("@vuu-ui/vuu-popups");
2150
+ var import_vuu_popups2 = require("@vuu-ui/vuu-popups");
1583
2151
  var import_jsx_runtime11 = require("react/jsx-runtime");
1584
2152
  var FilterBarMenu = () => {
1585
2153
  const classBase9 = "vuuFilterBarMenu";
1586
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: classBase9, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_vuu_popups4.PopupMenu, { icon: "tune", menuLocation: "filter-bar-menu", tabIndex: -1 }) });
2154
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: classBase9, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_vuu_popups2.PopupMenu, { icon: "tune", menuLocation: "filter-bar-menu", tabIndex: -1 }) });
1587
2155
  };
1588
2156
 
1589
2157
  // src/filter-bar/useFilterBar.ts
1590
- var import_vuu_utils12 = require("@vuu-ui/vuu-utils");
1591
- var import_react12 = require("react");
2158
+ var import_vuu_ui_controls9 = require("@vuu-ui/vuu-ui-controls");
2159
+ var import_vuu_utils16 = require("@vuu-ui/vuu-utils");
2160
+ var import_react13 = require("react");
1592
2161
 
1593
2162
  // src/filter-bar/useFilterState.ts
1594
- var import_react10 = require("react");
1595
- var import_vuu_ui_controls7 = require("@vuu-ui/vuu-ui-controls");
2163
+ var import_react11 = require("react");
2164
+ var import_vuu_ui_controls8 = require("@vuu-ui/vuu-ui-controls");
2165
+ var getActiveIndices = (indices, toggledIndex, preserveExisting) => {
2166
+ const isActive = indices.includes(toggledIndex);
2167
+ if (isActive) {
2168
+ if (preserveExisting) {
2169
+ return indices.filter((i) => i !== toggledIndex);
2170
+ } else {
2171
+ return [];
2172
+ }
2173
+ } else {
2174
+ if (preserveExisting) {
2175
+ return indices.concat(toggledIndex);
2176
+ } else {
2177
+ return [toggledIndex];
2178
+ }
2179
+ }
2180
+ };
1596
2181
  var useFilterState = ({
1597
2182
  defaultFilterState,
1598
2183
  onFilterDeleted,
@@ -1600,20 +2185,20 @@ var useFilterState = ({
1600
2185
  onFilterStateChanged,
1601
2186
  filterState: filterStateProp
1602
2187
  }) => {
1603
- const [filterState, setFilterState] = (0, import_vuu_ui_controls7.useControlled)({
2188
+ const [filterState, setFilterState] = (0, import_vuu_ui_controls8.useControlled)({
1604
2189
  controlled: filterStateProp,
1605
2190
  default: defaultFilterState != null ? defaultFilterState : { filters: [], activeIndices: [] },
1606
2191
  name: "useFilterState",
1607
2192
  state: "FilterState"
1608
2193
  });
1609
- const handleFilterStateChange = (0, import_react10.useCallback)(
2194
+ const handleFilterStateChange = (0, import_react11.useCallback)(
1610
2195
  (s) => {
1611
2196
  setFilterState(s);
1612
2197
  onFilterStateChanged == null ? void 0 : onFilterStateChanged(s);
1613
2198
  },
1614
2199
  [onFilterStateChanged, setFilterState]
1615
2200
  );
1616
- const handleAddFilter = (0, import_react10.useCallback)(
2201
+ const handleAddFilter = (0, import_react11.useCallback)(
1617
2202
  (filter) => {
1618
2203
  const index = filterState.filters.length;
1619
2204
  const newFilters = filterState.filters.concat(filter);
@@ -1626,7 +2211,7 @@ var useFilterState = ({
1626
2211
  },
1627
2212
  [filterState, handleFilterStateChange]
1628
2213
  );
1629
- const handleDeleteFilter = (0, import_react10.useCallback)(
2214
+ const handleDeleteFilter = (0, import_react11.useCallback)(
1630
2215
  (filter) => {
1631
2216
  let index = -1;
1632
2217
  const newFilters = filterState.filters.filter((f, i) => {
@@ -1655,7 +2240,7 @@ var useFilterState = ({
1655
2240
  onFilterDeleted
1656
2241
  ]
1657
2242
  );
1658
- const handleRenameFilter = (0, import_react10.useCallback)(
2243
+ const handleRenameFilter = (0, import_react11.useCallback)(
1659
2244
  (filter, name) => {
1660
2245
  let index = -1;
1661
2246
  const newFilters = filterState.filters.map((f, i) => {
@@ -1672,7 +2257,7 @@ var useFilterState = ({
1672
2257
  },
1673
2258
  [filterState, handleFilterStateChange, onFilterRenamed]
1674
2259
  );
1675
- const handleChangeFilter = (0, import_react10.useCallback)(
2260
+ const handleChangeFilter = (0, import_react11.useCallback)(
1676
2261
  (oldFilter, newFilter) => {
1677
2262
  let index = -1;
1678
2263
  const newFilters = filterState.filters.map((f, i) => {
@@ -1688,14 +2273,23 @@ var useFilterState = ({
1688
2273
  },
1689
2274
  [filterState, handleFilterStateChange]
1690
2275
  );
1691
- const handleActiveIndicesChange = (0, import_react10.useCallback)(
1692
- (indices) => handleFilterStateChange({ ...filterState, activeIndices: indices }),
2276
+ const handleToggleFilterActive = (0, import_react11.useCallback)(
2277
+ (filterIndex, preserveRemainingFilters = false) => {
2278
+ handleFilterStateChange({
2279
+ ...filterState,
2280
+ activeIndices: getActiveIndices(
2281
+ filterState.activeIndices,
2282
+ filterIndex,
2283
+ preserveRemainingFilters
2284
+ )
2285
+ });
2286
+ },
1693
2287
  [filterState, handleFilterStateChange]
1694
2288
  );
1695
2289
  return {
1696
2290
  activeFilterIndex: filterState.activeIndices,
1697
2291
  filters: filterState.filters,
1698
- onChangeActiveFilterIndex: handleActiveIndicesChange,
2292
+ onToggleFilterActive: handleToggleFilterActive,
1699
2293
  onAddFilter: handleAddFilter,
1700
2294
  onChangeFilter: handleChangeFilter,
1701
2295
  onDeleteFilter: handleDeleteFilter,
@@ -1712,22 +2306,22 @@ var removeIndexAndDecrementLarger = (indices, idxToRemove) => {
1712
2306
  };
1713
2307
 
1714
2308
  // src/filter-bar/useApplyFilterOnChange.ts
1715
- var import_react11 = require("react");
1716
- var import_vuu_utils11 = require("@vuu-ui/vuu-utils");
2309
+ var import_react12 = require("react");
2310
+ var import_vuu_utils14 = require("@vuu-ui/vuu-utils");
1717
2311
  function useApplyFilterOnChange({
1718
2312
  activeFilterIndex,
1719
2313
  columnsByName,
1720
2314
  filters,
1721
2315
  onApplyFilter
1722
2316
  }) {
1723
- const applyFilter = (0, import_react11.useCallback)(
2317
+ const applyFilter = (0, import_react12.useCallback)(
1724
2318
  (filter) => {
1725
- const query = filter ? (0, import_vuu_utils11.filterAsQuery)(filter, { columnsByName }) : "";
2319
+ const query = filter ? (0, import_vuu_utils14.filterAsQuery)(filter, { columnsByName }) : "";
1726
2320
  onApplyFilter({ filter: query, filterStruct: filter });
1727
2321
  },
1728
2322
  [columnsByName, onApplyFilter]
1729
2323
  );
1730
- (0, import_react11.useEffect)(() => {
2324
+ (0, import_react12.useEffect)(() => {
1731
2325
  const activeFilters = activeFilterIndex.map((i) => filters[i]);
1732
2326
  if (activeFilters.length === 0) {
1733
2327
  applyFilter();
@@ -1740,8 +2334,38 @@ function useApplyFilterOnChange({
1740
2334
  }, [activeFilterIndex, applyFilter, filters]);
1741
2335
  }
1742
2336
 
2337
+ // src/filter-bar/filterBarFocusManagement.ts
2338
+ var import_vuu_utils15 = require("@vuu-ui/vuu-utils");
2339
+ var navigateToNextItem = (el, direction = "fwd") => {
2340
+ const pill = (0, import_vuu_utils15.queryClosest)(el, ".vuuFilterPill");
2341
+ if (pill) {
2342
+ const index = (0, import_vuu_utils15.getElementDataIndex)(pill);
2343
+ if (typeof index === "number") {
2344
+ const target = direction === "fwd" ? (0, import_vuu_utils15.getElementByDataIndex)(pill.parentElement, index + 1) : (0, import_vuu_utils15.getElementByDataIndex)(pill.parentElement, index - 1);
2345
+ if (target) {
2346
+ target.focus();
2347
+ } else if (direction === "fwd") {
2348
+ console.log("to the button");
2349
+ const filterBar = (0, import_vuu_utils15.queryClosest)(el, ".vuuFilterBar");
2350
+ const addButton = filterBar == null ? void 0 : filterBar.querySelector(
2351
+ ".vuuFilterBar-add"
2352
+ );
2353
+ addButton == null ? void 0 : addButton.focus();
2354
+ }
2355
+ }
2356
+ } else {
2357
+ const button = (0, import_vuu_utils15.queryClosest)(el, ".vuuFilterBar-add");
2358
+ if (button) {
2359
+ const filterBar = (0, import_vuu_utils15.queryClosest)(el, ".vuuFilterBar");
2360
+ const target = filterBar == null ? void 0 : filterBar.querySelector(
2361
+ ".vuuFilterPill:last-child"
2362
+ );
2363
+ target == null ? void 0 : target.focus();
2364
+ }
2365
+ }
2366
+ };
2367
+
1743
2368
  // src/filter-bar/useFilterBar.ts
1744
- var EMPTY_FILTER_CLAUSE = {};
1745
2369
  var useFilterBar = ({
1746
2370
  columnDescriptors,
1747
2371
  containerRef,
@@ -1750,16 +2374,14 @@ var useFilterBar = ({
1750
2374
  onApplyFilter,
1751
2375
  onFilterDeleted,
1752
2376
  onFilterRenamed,
1753
- onFilterStateChanged,
1754
- showMenu: showMenuProp
2377
+ onFilterStateChanged
1755
2378
  }) => {
1756
- const addButtonRef = (0, import_react12.useRef)(null);
1757
- const editingFilter = (0, import_react12.useRef)();
1758
- const [showMenu, setShowMenu] = (0, import_react12.useState)(showMenuProp);
1759
- const [editFilter, setEditFilter] = (0, import_react12.useState)();
1760
- const [promptProps, setPromptProps] = (0, import_react12.useState)(null);
1761
- const columnsByName = (0, import_react12.useMemo)(
1762
- () => columnDescriptorsByName(columnDescriptors),
2379
+ const addButtonRef = (0, import_react13.useRef)(null);
2380
+ const [interactedFilterState, setInteractedFilterState] = (0, import_react13.useState)();
2381
+ const [promptProps, setPromptProps] = (0, import_react13.useState)(null);
2382
+ const editPillLabelAPI = (0, import_react13.useRef)(import_vuu_ui_controls9.NullEditAPI);
2383
+ const columnsByName = (0, import_react13.useMemo)(
2384
+ () => columnDescriptorsByName2(columnDescriptors),
1763
2385
  [columnDescriptors]
1764
2386
  );
1765
2387
  const {
@@ -1769,7 +2391,7 @@ var useFilterBar = ({
1769
2391
  onChangeFilter,
1770
2392
  onDeleteFilter,
1771
2393
  onRenameFilter,
1772
- onChangeActiveFilterIndex
2394
+ onToggleFilterActive
1773
2395
  } = useFilterState({
1774
2396
  defaultFilterState,
1775
2397
  filterState,
@@ -1783,47 +2405,21 @@ var useFilterBar = ({
1783
2405
  filters,
1784
2406
  onApplyFilter
1785
2407
  });
1786
- const editPillLabel = (0, import_react12.useCallback)(
1787
- (index) => {
1788
- requestAnimationFrame(() => {
1789
- var _a;
1790
- const pills = (_a = containerRef.current) == null ? void 0 : _a.querySelectorAll(
1791
- ".vuuFilterPill"
1792
- );
1793
- if (pills == null ? void 0 : pills[index]) {
1794
- const editableLabel = pills[index].querySelector(
1795
- ".vuuEditableLabel"
1796
- );
1797
- if (editableLabel) {
1798
- (0, import_vuu_utils12.dispatchMouseEvent)(editableLabel, "dblclick");
1799
- }
1800
- }
2408
+ const editPillLabel = (0, import_react13.useCallback)((index, filter) => {
2409
+ setTimeout(() => {
2410
+ setInteractedFilterState({
2411
+ filter,
2412
+ index,
2413
+ state: "rename"
1801
2414
  });
1802
- },
1803
- [containerRef]
1804
- );
1805
- const focusFilterClause = (0, import_react12.useCallback)(
1806
- (_ = 0) => {
2415
+ }, 100);
2416
+ }, []);
2417
+ const focusFilterPill = (0, import_react13.useCallback)(
2418
+ (index = 0) => {
1807
2419
  requestAnimationFrame(() => {
1808
2420
  var _a;
1809
- const input = (_a = containerRef.current) == null ? void 0 : _a.querySelector(
1810
- ".vuuFilterClause .saltInput-input"
1811
- );
1812
- if (input) {
1813
- input.focus();
1814
- }
1815
- });
1816
- },
1817
- [containerRef]
1818
- );
1819
- const focusFilterPill = (0, import_react12.useCallback)(
1820
- (index) => {
1821
- requestAnimationFrame(() => {
1822
- var _a, _b;
1823
- const target = typeof index === "number" ? (_a = containerRef.current) == null ? void 0 : _a.querySelector(
1824
- `.vuuOverflowContainer-item[data-index="${index}"] .vuuFilterPill`
1825
- ) : (_b = containerRef.current) == null ? void 0 : _b.querySelector(
1826
- ".vuuFilterPill[tabindex]"
2421
+ const target = (_a = containerRef.current) == null ? void 0 : _a.querySelector(
2422
+ `.vuuFilterPill[data-index="${index}"] button`
1827
2423
  );
1828
2424
  if (target) {
1829
2425
  target.focus();
@@ -1832,7 +2428,7 @@ var useFilterBar = ({
1832
2428
  },
1833
2429
  [containerRef]
1834
2430
  );
1835
- const deleteConfirmed = (0, import_react12.useCallback)(
2431
+ const deleteConfirmed = (0, import_react13.useCallback)(
1836
2432
  (filter) => {
1837
2433
  onDeleteFilter(filter);
1838
2434
  requestAnimationFrame(() => {
@@ -1843,7 +2439,7 @@ var useFilterBar = ({
1843
2439
  },
1844
2440
  [filters.length, focusFilterPill, onDeleteFilter]
1845
2441
  );
1846
- const getDeletePrompt = (0, import_react12.useMemo)(
2442
+ const getDeletePrompt = (0, import_react13.useMemo)(
1847
2443
  () => (filter) => {
1848
2444
  const close = () => {
1849
2445
  setPromptProps(null);
@@ -1865,7 +2461,7 @@ var useFilterBar = ({
1865
2461
  },
1866
2462
  [deleteConfirmed, focusFilterPill]
1867
2463
  );
1868
- const deleteFilter = (0, import_react12.useCallback)(
2464
+ const deleteFilter = (0, import_react13.useCallback)(
1869
2465
  (filter, withPrompt) => {
1870
2466
  if (withPrompt) {
1871
2467
  setPromptProps(getDeletePrompt(filter));
@@ -1875,23 +2471,19 @@ var useFilterBar = ({
1875
2471
  },
1876
2472
  [deleteConfirmed, getDeletePrompt]
1877
2473
  );
1878
- const handleBeginEditFilterName = (0, import_react12.useCallback)((filter) => {
1879
- editingFilter.current = filter;
1880
- }, []);
1881
- const handleExitEditFilterName = (0, import_react12.useCallback)(
2474
+ const handleExitEditFilterName = (0, import_react13.useCallback)(
1882
2475
  (_, editedValue = "") => {
1883
- if (editingFilter.current) {
1884
- const indexOfEditedFilter = onRenameFilter(
1885
- editingFilter.current,
1886
- editedValue
1887
- );
1888
- editingFilter.current = void 0;
2476
+ if ((interactedFilterState == null ? void 0 : interactedFilterState.state) === "rename" && interactedFilterState.filter) {
2477
+ const { filter } = interactedFilterState;
2478
+ const indexOfEditedFilter = onRenameFilter(filter, editedValue);
2479
+ setInteractedFilterState(void 0);
1889
2480
  focusFilterPill(indexOfEditedFilter);
1890
2481
  }
2482
+ setInteractedFilterState(void 0);
1891
2483
  },
1892
- [focusFilterPill, onRenameFilter]
2484
+ [focusFilterPill, interactedFilterState, onRenameFilter]
1893
2485
  );
1894
- const handlePillMenuAction = (0, import_react12.useCallback)(
2486
+ const handlePillMenuAction = (0, import_react13.useCallback)(
1895
2487
  ({ menuId, options }) => {
1896
2488
  switch (menuId) {
1897
2489
  case "delete-filter": {
@@ -1902,201 +2494,125 @@ var useFilterBar = ({
1902
2494
  case "rename-filter": {
1903
2495
  const { filter } = options;
1904
2496
  const index = filters.indexOf(filter);
1905
- editPillLabel(index);
2497
+ editPillLabel(index, filter);
1906
2498
  return true;
1907
2499
  }
1908
2500
  case "edit-filter": {
1909
2501
  const { filter } = options;
1910
- editingFilter.current = filter;
1911
- setEditFilter(filter);
1912
- focusFilterClause();
2502
+ setInteractedFilterState({
2503
+ filter,
2504
+ index: filters.indexOf(filter),
2505
+ state: "edit"
2506
+ });
1913
2507
  return true;
1914
2508
  }
1915
2509
  default:
1916
2510
  return false;
1917
2511
  }
1918
2512
  },
1919
- [deleteFilter, editPillLabel, filters, focusFilterClause]
2513
+ [deleteFilter, editPillLabel, filters]
1920
2514
  );
1921
- const addIfNewElseUpdate = (0, import_react12.useCallback)(
1922
- (edited, existing) => {
2515
+ const handlePillKeyDown = (0, import_react13.useCallback)((e) => {
2516
+ if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
2517
+ navigateToNextItem(e.target, e.key === "ArrowLeft" ? "bwd" : "fwd");
2518
+ }
2519
+ }, []);
2520
+ const addIfNewElseUpdate = (0, import_react13.useCallback)(
2521
+ (newOrUpdatedFilter, existing) => {
1923
2522
  if (existing === void 0) {
1924
- const idx = onAddFilter(edited);
1925
- editPillLabel(idx);
2523
+ const idx = onAddFilter(newOrUpdatedFilter);
2524
+ focusFilterPill(idx);
2525
+ editPillLabel(idx, newOrUpdatedFilter);
1926
2526
  } else {
1927
- onChangeFilter(existing, edited);
2527
+ const idx = onChangeFilter(existing, newOrUpdatedFilter);
2528
+ focusFilterPill(idx);
1928
2529
  }
1929
2530
  },
1930
- [editPillLabel, onAddFilter, onChangeFilter]
2531
+ [editPillLabel, focusFilterPill, onAddFilter, onChangeFilter]
1931
2532
  );
1932
- const handleMenuAction = (0, import_react12.useCallback)(
1933
- ({ menuId }) => {
1934
- switch (menuId) {
1935
- case "apply-save": {
1936
- const editedFilter = editFilter;
1937
- addIfNewElseUpdate(editedFilter, editingFilter.current);
1938
- setEditFilter(void 0);
1939
- editingFilter.current = void 0;
1940
- setShowMenu(false);
1941
- return true;
1942
- }
1943
- case "and-clause": {
1944
- const newFilter = addClause(
1945
- editFilter,
1946
- EMPTY_FILTER_CLAUSE
1947
- );
1948
- setEditFilter(newFilter);
1949
- setShowMenu(false);
1950
- return true;
2533
+ const filterSaveHandler = (0, import_react13.useCallback)(
2534
+ (filter) => {
2535
+ if (interactedFilterState) {
2536
+ const { filter: existingFilter } = interactedFilterState;
2537
+ setInteractedFilterState(void 0);
2538
+ addIfNewElseUpdate(filter, existingFilter);
2539
+ }
2540
+ },
2541
+ [addIfNewElseUpdate, interactedFilterState]
2542
+ );
2543
+ const handlePillClick = (0, import_react13.useCallback)(
2544
+ (e) => {
2545
+ const isEditing = e.target.querySelector(
2546
+ ".vuuEditableLabel-editing"
2547
+ );
2548
+ if (!isEditing) {
2549
+ const pill = (0, import_vuu_utils16.queryClosest)(e.target, ".vuuFilterPill");
2550
+ if (pill) {
2551
+ const index = (0, import_vuu_utils16.getElementDataIndex)(pill);
2552
+ onToggleFilterActive(index, e.shiftKey);
1951
2553
  }
1952
- case "or-clause":
1953
- setEditFilter(
1954
- (filter) => addClause(filter, EMPTY_FILTER_CLAUSE, {
1955
- combineWith: "or"
1956
- })
1957
- );
1958
- setShowMenu(false);
1959
- return true;
1960
- default:
1961
- return false;
1962
2554
  }
1963
2555
  },
1964
- [editFilter, addIfNewElseUpdate]
2556
+ [onToggleFilterActive]
1965
2557
  );
1966
- const handleClickAddFilter = (0, import_react12.useCallback)(() => {
1967
- setEditFilter({});
1968
- }, [setEditFilter]);
1969
- const handleClickRemoveFilter = (0, import_react12.useCallback)(() => {
1970
- setEditFilter(void 0);
1971
- }, []);
1972
2558
  const pillProps = {
1973
- onBeginEdit: handleBeginEditFilterName,
2559
+ editLabelApiRef: editPillLabelAPI,
2560
+ // onBeginEdit: handleBeginEditFilterName,
2561
+ onClick: handlePillClick,
2562
+ onKeyDown: handlePillKeyDown,
1974
2563
  onMenuAction: handlePillMenuAction,
1975
2564
  onExitEditMode: handleExitEditFilterName
1976
2565
  };
1977
- const handleChangeFilterClause = (0, import_react12.useCallback)(
1978
- (idx) => (filterClause) => {
1979
- if (filterClause !== void 0) {
1980
- setEditFilter((ef) => replaceClause(ef, filterClause, idx));
1981
- setShowMenu(true);
1982
- }
1983
- },
1984
- []
1985
- );
1986
- const handleCancelFilterClause = (0, import_react12.useCallback)(
1987
- (reason) => {
1988
- if (reason === "Backspace" && (0, import_vuu_utils12.isMultiClauseFilter)(editFilter)) {
1989
- setEditFilter(removeLastClause(editFilter));
1990
- }
1991
- },
1992
- [editFilter]
1993
- );
1994
- const handleBlurFilterClause = (0, import_react12.useCallback)((e) => {
1995
- const target = e.target;
1996
- const relatedTarget = e.relatedTarget;
1997
- const filterClause = target.closest(".vuuFilterClause");
1998
- if (filterClause == null ? void 0 : filterClause.contains(relatedTarget)) {
1999
- } else {
2000
- const dropdownId = target.getAttribute("aria-owns");
2001
- const dropDown = dropdownId ? document.getElementById(dropdownId) : null;
2002
- if (dropDown == null ? void 0 : dropDown.contains(relatedTarget)) {
2003
- } else {
2004
- setShowMenu(true);
2005
- }
2006
- }
2007
- }, []);
2008
- const handleFocusFilterClause = (0, import_react12.useCallback)(() => {
2009
- setShowMenu(false);
2566
+ const handleClickAddButton = (0, import_react13.useCallback)(() => {
2567
+ setInteractedFilterState({
2568
+ index: -1,
2569
+ state: "create"
2570
+ });
2010
2571
  }, []);
2011
- const handleKeyDownFilterbar = (0, import_react12.useCallback)(
2012
- (evt) => {
2013
- if (evt.key === "Escape" && editFilter !== void 0) {
2014
- setEditFilter(void 0);
2015
- requestAnimationFrame(() => {
2016
- });
2017
- }
2018
- },
2019
- [editFilter]
2020
- );
2021
- const handleKeyDownMenu = (0, import_react12.useCallback)(
2022
- (evt) => {
2023
- var _a;
2024
- const { current: container } = containerRef;
2025
- if (evt.key === "Backspace" && container) {
2026
- evt.preventDefault();
2027
- const fields = Array.from(
2028
- container.querySelectorAll(".vuuFilterClauseField")
2029
- );
2030
- if (fields.length > 0) {
2031
- const field = fields.at(-1);
2032
- (_a = field == null ? void 0 : field.querySelector("input")) == null ? void 0 : _a.focus();
2033
- }
2034
- setShowMenu(false);
2035
- } else if (evt.key === "Tab") {
2036
- if (evt.shiftKey && container) {
2037
- const clearButtons = Array.from(
2038
- container.querySelectorAll(".vuuFilterClause-clearButton")
2039
- );
2040
- if (clearButtons.length > 0) {
2041
- const clearButton = clearButtons.at(-1);
2042
- setTimeout(() => {
2043
- clearButton.focus();
2044
- }, 100);
2045
- }
2046
- } else {
2047
- console.log("apply current selection");
2048
- }
2049
- }
2050
- },
2051
- [containerRef]
2052
- );
2053
- const handleAddButtonKeyDown = (0, import_react12.useCallback)((evt) => {
2572
+ const handleKeyDownAddButton = (0, import_react13.useCallback)((evt) => {
2054
2573
  if (evt.key === "ArrowLeft") {
2055
- console.log("navgiate to the Toolbar");
2574
+ navigateToNextItem(evt.target, "bwd");
2056
2575
  }
2057
2576
  }, []);
2058
- const handlePillNavigationOutOfBounds = (0, import_react12.useCallback)((direction) => {
2577
+ const handleCancelEdit = (0, import_react13.useCallback)(() => {
2059
2578
  var _a;
2060
- if (direction === "end") {
2061
- (_a = addButtonRef.current) == null ? void 0 : _a.focus();
2579
+ if (interactedFilterState) {
2580
+ const { index } = interactedFilterState;
2581
+ if (index === -1) {
2582
+ (_a = addButtonRef.current) == null ? void 0 : _a.focus();
2583
+ } else {
2584
+ focusFilterPill(index);
2585
+ }
2586
+ setInteractedFilterState(void 0);
2062
2587
  }
2063
- }, []);
2588
+ }, [focusFilterPill, interactedFilterState]);
2064
2589
  const addButtonProps = {
2065
2590
  ref: addButtonRef,
2066
- onKeyDown: handleAddButtonKeyDown
2591
+ onClick: handleClickAddButton,
2592
+ onKeyDown: handleKeyDownAddButton
2067
2593
  };
2068
2594
  return {
2069
2595
  activeFilterIndex,
2070
2596
  addButtonProps,
2071
2597
  columnsByName,
2072
- editFilter,
2073
2598
  filters,
2074
- onBlurFilterClause: handleBlurFilterClause,
2075
- onCancelFilterClause: handleCancelFilterClause,
2076
- onChangeActiveFilterIndex,
2077
- onClickAddFilter: handleClickAddFilter,
2078
- onClickRemoveFilter: handleClickRemoveFilter,
2079
- onChangeFilterClause: handleChangeFilterClause,
2080
- onFocusFilterClause: handleFocusFilterClause,
2081
- onKeyDownFilterbar: handleKeyDownFilterbar,
2082
- onKeyDownMenu: handleKeyDownMenu,
2083
- onMenuAction: handleMenuAction,
2084
- onNavigateOutOfBounds: handlePillNavigationOutOfBounds,
2599
+ interactedFilterState,
2600
+ onCancelEdit: handleCancelEdit,
2601
+ onSave: filterSaveHandler,
2085
2602
  pillProps,
2086
- promptProps,
2087
- showMenu
2603
+ promptProps
2088
2604
  };
2089
2605
  };
2090
- function columnDescriptorsByName(columns) {
2606
+ function columnDescriptorsByName2(columns) {
2091
2607
  return columns.reduce((m, col) => ({ ...m, [col.name]: col }), {});
2092
2608
  }
2093
2609
 
2094
2610
  // src/filter-bar/FilterBar.tsx
2095
2611
  var import_jsx_runtime12 = require("react/jsx-runtime");
2096
- var import_react14 = require("react");
2612
+ var import_react15 = require("react");
2097
2613
  var classBase7 = "vuuFilterBar";
2098
2614
  var FilterBar = ({
2099
- FilterClauseEditorProps: FilterClauseEditorProps2,
2615
+ FilterClauseEditorProps,
2100
2616
  className: classNameProp,
2101
2617
  columnDescriptors,
2102
2618
  defaultFilterState,
@@ -2105,31 +2621,20 @@ var FilterBar = ({
2105
2621
  onFilterDeleted,
2106
2622
  onFilterRenamed,
2107
2623
  onFilterStateChanged,
2108
- showMenu: showMenuProp = false,
2109
2624
  tableSchema,
2110
2625
  ...htmlAttributes
2111
2626
  }) => {
2112
- const rootRef = (0, import_react13.useRef)(null);
2627
+ const rootRef = (0, import_react14.useRef)(null);
2113
2628
  const {
2114
2629
  activeFilterIndex,
2115
2630
  addButtonProps,
2116
2631
  columnsByName,
2117
- editFilter,
2118
2632
  filters,
2119
- onBlurFilterClause,
2120
- onCancelFilterClause,
2121
- onClickAddFilter,
2122
- onClickRemoveFilter,
2123
- onChangeFilterClause,
2124
- onChangeActiveFilterIndex,
2125
- onFocusFilterClause,
2126
- onNavigateOutOfBounds,
2127
- onKeyDownFilterbar,
2128
- onKeyDownMenu,
2129
- onMenuAction,
2633
+ interactedFilterState,
2634
+ onCancelEdit,
2635
+ onSave,
2130
2636
  pillProps,
2131
- promptProps,
2132
- showMenu
2637
+ promptProps
2133
2638
  } = useFilterBar({
2134
2639
  containerRef: rootRef,
2135
2640
  columnDescriptors,
@@ -2138,126 +2643,85 @@ var FilterBar = ({
2138
2643
  onApplyFilter,
2139
2644
  onFilterStateChanged,
2140
2645
  onFilterDeleted,
2141
- onFilterRenamed,
2142
- showMenu: showMenuProp
2143
- });
2144
- const className = clsx_default(classBase7, classNameProp, {
2145
- [`${classBase7}-display`]: editFilter === void 0,
2146
- [`${classBase7}-edit`]: editFilter !== void 0
2646
+ onFilterRenamed
2147
2647
  });
2648
+ const className = clsx_default(classBase7, classNameProp);
2649
+ const indexOfFilterBeingRenamed = (interactedFilterState == null ? void 0 : interactedFilterState.state) === "rename" ? interactedFilterState.index : -1;
2650
+ const filterModel = (interactedFilterState == null ? void 0 : interactedFilterState.state) === "edit" || (interactedFilterState == null ? void 0 : interactedFilterState.state) === "create" ? new FilterModel(interactedFilterState.filter) : void 0;
2148
2651
  const getChildren2 = () => {
2149
2652
  const items = [];
2150
- if (editFilter === void 0) {
2151
- filters.forEach((filter, i) => {
2152
- items.push(
2153
- /* @__PURE__ */ (0, import_react14.createElement)(
2154
- FilterPill,
2155
- {
2156
- ...pillProps,
2157
- columnsByName,
2158
- filter,
2159
- key: `filter-${i}`
2160
- }
2161
- )
2162
- );
2163
- });
2164
- return items;
2165
- } else if (editFilter) {
2166
- const filterClauses2 = filterClauses(editFilter);
2653
+ filters.forEach((filter, i) => {
2167
2654
  items.push(
2168
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: `${classBase7}-Editor`, children: filterClauses2.map((f, i) => /* @__PURE__ */ (0, import_react14.createElement)(
2169
- FilterClauseEditor,
2655
+ /* @__PURE__ */ (0, import_react15.createElement)(
2656
+ FilterPill,
2170
2657
  {
2171
- ...FilterClauseEditorProps2,
2658
+ ...pillProps,
2659
+ editing: indexOfFilterBeingRenamed === i,
2172
2660
  columnsByName,
2173
- filterClause: f,
2174
- key: `editor-${i}`,
2175
- onCancel: onCancelFilterClause,
2176
- onChange: onChangeFilterClause(i),
2177
- onBlur: onBlurFilterClause,
2178
- onFocus: onFocusFilterClause,
2179
- tableSchema
2661
+ "data-index": i,
2662
+ filter,
2663
+ key: `filter-${i}`,
2664
+ selected: activeFilterIndex.includes(i)
2180
2665
  }
2181
- )) }, `editor`)
2182
- );
2183
- if (showMenu) {
2184
- items.push(
2185
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2186
- FilterBuilderMenu,
2187
- {
2188
- onMenuAction,
2189
- ListProps: { onKeyDownCapture: onKeyDownMenu }
2190
- },
2191
- "menu"
2192
- )
2193
- );
2194
- }
2195
- items.push(
2196
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2197
- import_core2.Button,
2198
- {
2199
- className: `${classBase7}-remove`,
2200
- "data-align": "right",
2201
- "data-icon": "cross",
2202
- onClick: onClickRemoveFilter,
2203
- variant: "primary"
2204
- },
2205
- "filter-remove"
2206
2666
  )
2207
2667
  );
2208
- return items;
2209
- }
2668
+ });
2669
+ return items;
2210
2670
  };
2211
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2212
- "div",
2213
- {
2214
- ...htmlAttributes,
2215
- className,
2216
- onKeyDown: onKeyDownFilterbar,
2217
- ref: rootRef,
2218
- children: [
2219
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FilterBarMenu, {}),
2220
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2221
- import_vuu_ui_controls8.Toolbar,
2222
- {
2223
- activeItemIndex: activeFilterIndex,
2224
- onActiveChange: onChangeActiveFilterIndex,
2225
- onNavigateOutOfBounds,
2226
- selectionStrategy: "multiple-special-key",
2227
- children: getChildren2()
2228
- }
2229
- ),
2230
- editFilter === void 0 ? /* @__PURE__ */ (0, import_react14.createElement)(
2231
- import_core2.Button,
2232
- {
2233
- ...addButtonProps,
2234
- className: `${classBase7}-add`,
2235
- "data-icon": "plus",
2236
- "data-selectable": false,
2237
- key: "filter-add",
2238
- onClick: onClickAddFilter,
2239
- tabIndex: 0,
2240
- variant: "primary"
2241
- }
2242
- ) : null,
2243
- promptProps ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2244
- import_vuu_popups5.Prompt,
2671
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { ...htmlAttributes, className, ref: rootRef, children: [
2672
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(FilterBarMenu, {}),
2673
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
2674
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: `${classBase7}-filters`, children: getChildren2() }),
2675
+ /* @__PURE__ */ (0, import_react15.createElement)(
2676
+ import_vuu_ui_controls10.IconButton,
2677
+ {
2678
+ ...addButtonProps,
2679
+ className: clsx_default("vuuIconButton", `${classBase7}-add`),
2680
+ "data-selectable": false,
2681
+ icon: "plus",
2682
+ key: "filter-add",
2683
+ tabIndex: 0,
2684
+ variant: "primary"
2685
+ }
2686
+ )
2687
+ ] }),
2688
+ filterModel && tableSchema && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_vuu_popups3.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2689
+ import_vuu_popups3.PopupComponent,
2690
+ {
2691
+ anchorElement: rootRef,
2692
+ offsetTop: -10,
2693
+ offsetLeft: 20,
2694
+ placement: "below",
2695
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2696
+ FilterEditor,
2245
2697
  {
2246
- ...promptProps,
2247
- PopupProps: {
2248
- anchorElement: rootRef,
2249
- offsetTop: 16,
2250
- placement: "below-center"
2251
- }
2252
- }
2253
- ) : null
2254
- ]
2255
- }
2256
- );
2698
+ FilterClauseEditorProps,
2699
+ columnDescriptors,
2700
+ onCancel: onCancelEdit,
2701
+ onSave,
2702
+ filter: interactedFilterState == null ? void 0 : interactedFilterState.filter,
2703
+ tableSchema
2704
+ },
2705
+ "filter-editor"
2706
+ )
2707
+ }
2708
+ ) }),
2709
+ promptProps ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2710
+ import_vuu_popups3.Prompt,
2711
+ {
2712
+ ...promptProps,
2713
+ PopupProps: {
2714
+ anchorElement: rootRef,
2715
+ offsetTop: 16,
2716
+ placement: "below-center"
2717
+ }
2718
+ }
2719
+ ) : null
2720
+ ] });
2257
2721
  };
2258
2722
 
2259
2723
  // src/filter-input/FilterInput.tsx
2260
- var import_core3 = require("@salt-ds/core");
2724
+ var import_core2 = require("@salt-ds/core");
2261
2725
 
2262
2726
  // src/filter-input/useCodeMirrorEditor.ts
2263
2727
  var import_vuu_codemirror5 = require("@vuu-ui/vuu-codemirror");
@@ -5247,14 +5711,14 @@ var parser = LRParser.deserialize({
5247
5711
  });
5248
5712
 
5249
5713
  // ../vuu-filter-parser/src/FilterTreeWalker.ts
5250
- var import_vuu_utils13 = require("@vuu-ui/vuu-utils");
5714
+ var import_vuu_utils17 = require("@vuu-ui/vuu-utils");
5251
5715
  var _filter;
5252
5716
  var FilterExpression = class {
5253
5717
  constructor() {
5254
5718
  __privateAdd(this, _filter, void 0);
5255
5719
  }
5256
5720
  setFilterCombinatorOp(op, filter = __privateGet(this, _filter)) {
5257
- if ((0, import_vuu_utils13.isMultiClauseFilter)(filter) && filter.op === op) {
5721
+ if ((0, import_vuu_utils17.isMultiClauseFilter)(filter) && filter.op === op) {
5258
5722
  return;
5259
5723
  } else {
5260
5724
  __privateSet(this, _filter, {
@@ -5266,14 +5730,14 @@ var FilterExpression = class {
5266
5730
  add(filter) {
5267
5731
  if (__privateGet(this, _filter) === void 0) {
5268
5732
  __privateSet(this, _filter, filter);
5269
- } else if ((0, import_vuu_utils13.isMultiClauseFilter)(__privateGet(this, _filter))) {
5733
+ } else if ((0, import_vuu_utils17.isMultiClauseFilter)(__privateGet(this, _filter))) {
5270
5734
  __privateGet(this, _filter).filters.push(filter);
5271
5735
  } else {
5272
5736
  throw Error(`Invalid filter passed to FilterExpression`);
5273
5737
  }
5274
5738
  }
5275
5739
  setColumn(column, filter = __privateGet(this, _filter)) {
5276
- if ((0, import_vuu_utils13.isMultiClauseFilter)(filter)) {
5740
+ if ((0, import_vuu_utils17.isMultiClauseFilter)(filter)) {
5277
5741
  const target = filter.filters.at(-1);
5278
5742
  if (target) {
5279
5743
  this.setColumn(column, target);
@@ -5283,7 +5747,7 @@ var FilterExpression = class {
5283
5747
  }
5284
5748
  }
5285
5749
  setOp(value, filter = __privateGet(this, _filter)) {
5286
- if ((0, import_vuu_utils13.isMultiClauseFilter)(filter)) {
5750
+ if ((0, import_vuu_utils17.isMultiClauseFilter)(filter)) {
5287
5751
  const target = filter.filters.at(-1);
5288
5752
  if (target) {
5289
5753
  this.setOp(value, target);
@@ -5294,15 +5758,15 @@ var FilterExpression = class {
5294
5758
  }
5295
5759
  setValue(value, filter = __privateGet(this, _filter)) {
5296
5760
  var _a;
5297
- if ((0, import_vuu_utils13.isMultiClauseFilter)(filter)) {
5761
+ if ((0, import_vuu_utils17.isMultiClauseFilter)(filter)) {
5298
5762
  const target = filter.filters.at(-1);
5299
5763
  if (target) {
5300
5764
  this.setValue(value, target);
5301
5765
  }
5302
- } else if ((0, import_vuu_utils13.isMultiValueFilter)(filter)) {
5766
+ } else if ((0, import_vuu_utils17.isMultiValueFilter)(filter)) {
5303
5767
  (_a = filter.values) != null ? _a : filter.values = [];
5304
5768
  filter.values.push(value);
5305
- } else if ((0, import_vuu_utils13.isSingleValueFilter)(filter)) {
5769
+ } else if ((0, import_vuu_utils17.isSingleValueFilter)(filter)) {
5306
5770
  filter.value = value;
5307
5771
  }
5308
5772
  }
@@ -5365,7 +5829,7 @@ var walkTree = (tree, source) => {
5365
5829
  var strictParser = parser.configure({ strict: true });
5366
5830
 
5367
5831
  // src/filter-input/useCodeMirrorEditor.ts
5368
- var import_react16 = require("react");
5832
+ var import_react17 = require("react");
5369
5833
 
5370
5834
  // src/filter-input/FilterLanguage.ts
5371
5835
  var import_vuu_codemirror = require("@vuu-ui/vuu-codemirror");
@@ -5471,7 +5935,7 @@ var vuuTheme = import_vuu_codemirror3.EditorView.theme(
5471
5935
 
5472
5936
  // src/filter-input/useFilterAutoComplete.ts
5473
5937
  var import_vuu_codemirror4 = require("@vuu-ui/vuu-codemirror");
5474
- var import_react15 = require("react");
5938
+ var import_react16 = require("react");
5475
5939
  var getOperator = (node, state) => {
5476
5940
  let maybeColumnNode = node.prevSibling || node.parent;
5477
5941
  while (maybeColumnNode && !["Column", "Operator", "In"].includes(maybeColumnNode.name)) {
@@ -5541,7 +6005,7 @@ var getSetValues = (node, state) => {
5541
6005
  return values;
5542
6006
  };
5543
6007
  var useAutoComplete = (suggestionProvider, onSubmit, existingFilter) => {
5544
- const makeSuggestions = (0, import_react15.useCallback)(
6008
+ const makeSuggestions = (0, import_react16.useCallback)(
5545
6009
  async (context, suggestionType, optionalArgs = {}) => {
5546
6010
  const { startsWith = "" } = optionalArgs;
5547
6011
  const options = await suggestionProvider.getSuggestions(
@@ -5552,7 +6016,7 @@ var useAutoComplete = (suggestionProvider, onSubmit, existingFilter) => {
5552
6016
  },
5553
6017
  [suggestionProvider]
5554
6018
  );
5555
- return (0, import_react15.useCallback)(
6019
+ return (0, import_react16.useCallback)(
5556
6020
  async (context) => {
5557
6021
  var _a, _b;
5558
6022
  const { state, pos } = context;
@@ -5736,15 +6200,15 @@ var useCodeMirrorEditor = ({
5736
6200
  onSubmitFilter,
5737
6201
  suggestionProvider
5738
6202
  }) => {
5739
- const editorRef = (0, import_react16.useRef)(null);
5740
- const onSubmit = (0, import_react16.useRef)(noop);
5741
- const viewRef = (0, import_react16.useRef)();
6203
+ const editorRef = (0, import_react17.useRef)(null);
6204
+ const onSubmit = (0, import_react17.useRef)(noop);
6205
+ const viewRef = (0, import_react17.useRef)();
5742
6206
  const completionFn = useAutoComplete(
5743
6207
  suggestionProvider,
5744
6208
  onSubmit,
5745
6209
  existingFilter
5746
6210
  );
5747
- const [createState, clearInput] = (0, import_react16.useMemo)(() => {
6211
+ const [createState, clearInput] = (0, import_react17.useMemo)(() => {
5748
6212
  const parseFilter2 = () => {
5749
6213
  const view = getView(viewRef);
5750
6214
  const source = view.state.doc.toString();
@@ -5819,7 +6283,7 @@ var useCodeMirrorEditor = ({
5819
6283
  };
5820
6284
  return [createState2, clearInput2];
5821
6285
  }, [completionFn, onSubmitFilter]);
5822
- (0, import_react16.useEffect)(() => {
6286
+ (0, import_react17.useEffect)(() => {
5823
6287
  if (!editorRef.current) {
5824
6288
  throw Error("editor not in dom");
5825
6289
  }
@@ -5853,7 +6317,7 @@ var FilterInput = ({
5853
6317
  });
5854
6318
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { ...props, className: classBase8, children: [
5855
6319
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5856
- import_core3.Button,
6320
+ import_core2.Button,
5857
6321
  {
5858
6322
  className: `${classBase8}-FilterButton`,
5859
6323
  "data-icon": iconName,
@@ -5862,7 +6326,7 @@ var FilterInput = ({
5862
6326
  ),
5863
6327
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: `${classBase8}-Editor`, ref: editorRef }),
5864
6328
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
5865
- import_core3.Button,
6329
+ import_core2.Button,
5866
6330
  {
5867
6331
  className: `${classBase8}-ClearButton`,
5868
6332
  "data-icon": "close-circle",
@@ -5875,16 +6339,16 @@ var FilterInput = ({
5875
6339
  // src/filter-input/useFilterSuggestionProvider.ts
5876
6340
  var import_vuu_codemirror6 = require("@vuu-ui/vuu-codemirror");
5877
6341
  var import_vuu_data_react2 = require("@vuu-ui/vuu-data-react");
5878
- var import_react17 = require("react");
6342
+ var import_react18 = require("react");
5879
6343
 
5880
6344
  // src/filter-input/filterInfo.ts
5881
- var import_vuu_utils14 = require("@vuu-ui/vuu-utils");
6345
+ var import_vuu_utils18 = require("@vuu-ui/vuu-utils");
5882
6346
  var filterInfo = (filterName, filterQuery) => {
5883
- const rootElement = (0, import_vuu_utils14.createEl)("div", "vuuFunctionDoc");
5884
- const headingElement = (0, import_vuu_utils14.createEl)("div", "function-heading");
5885
- const nameElement = (0, import_vuu_utils14.createEl)("span", "function-name", filterName);
6347
+ const rootElement = (0, import_vuu_utils18.createEl)("div", "vuuFunctionDoc");
6348
+ const headingElement = (0, import_vuu_utils18.createEl)("div", "function-heading");
6349
+ const nameElement = (0, import_vuu_utils18.createEl)("span", "function-name", filterName);
5886
6350
  headingElement.appendChild(nameElement);
5887
- const child2 = (0, import_vuu_utils14.createEl)("p", void 0, filterQuery);
6351
+ const child2 = (0, import_vuu_utils18.createEl)("p", void 0, filterQuery);
5888
6352
  rootElement.appendChild(headingElement);
5889
6353
  rootElement.appendChild(child2);
5890
6354
  return rootElement;
@@ -5971,9 +6435,9 @@ var useFilterSuggestionProvider = ({
5971
6435
  table,
5972
6436
  typeaheadHook: useTypeahead = import_vuu_data_react2.useTypeaheadSuggestions
5973
6437
  }) => {
5974
- const latestSuggestionsRef = (0, import_react17.useRef)();
6438
+ const latestSuggestionsRef = (0, import_react18.useRef)();
5975
6439
  const getTypeaheadSuggestions = useTypeahead();
5976
- const getSuggestions = (0, import_react17.useCallback)(
6440
+ const getSuggestions = (0, import_react18.useCallback)(
5977
6441
  async (suggestionType, options = NONE) => {
5978
6442
  const {
5979
6443
  columnName,
@@ -6063,7 +6527,7 @@ var useFilterSuggestionProvider = ({
6063
6527
  },
6064
6528
  [columns, getTypeaheadSuggestions, namedFilters, saveOptions, table]
6065
6529
  );
6066
- const isPartialMatch = (0, import_react17.useCallback)(
6530
+ const isPartialMatch = (0, import_react18.useCallback)(
6067
6531
  async (valueType, columnName, pattern) => {
6068
6532
  const suggestions = (
6069
6533
  // latestSuggestions && latestSuggestions.length > 0