@revolist/revogrid 4.27.0 → 4.27.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/cjs/{cell-renderer-C7rdgaov.js → cell-renderer-BDIx0xys.js} +1 -1
  2. package/dist/cjs/{column.service-Bbml5C2j.js → column.service-D-ENzqyb.js} +2 -0
  3. package/dist/cjs/{filter.button-F2Bw3UAd.js → filter.button-C6ixuMmr.js} +3 -2
  4. package/dist/cjs/{header-cell-renderer-BljFI6wj.js → header-cell-renderer-B5Y4fdZC.js} +1 -1
  5. package/dist/cjs/index.cjs.js +7 -5
  6. package/dist/cjs/loader.cjs.js +1 -1
  7. package/dist/cjs/revo-grid.cjs.entry.js +63 -43
  8. package/dist/cjs/revo-grid.cjs.js +1 -1
  9. package/dist/cjs/revogr-attribution_7.cjs.entry.js +1 -1
  10. package/dist/cjs/revogr-data_4.cjs.entry.js +12 -11
  11. package/dist/cjs/revogr-filter-panel.cjs.entry.js +139 -33
  12. package/dist/cjs/{row-resize.plugin-BRQy_qNn.js → row-resize.plugin-C4YOF1lN.js} +353 -185
  13. package/dist/collection/components/header/header-renderer.js +7 -6
  14. package/dist/collection/components/header/revogr-header-style.css +8 -3
  15. package/dist/collection/components/revoGrid/revo-grid-style.css +12 -2
  16. package/dist/collection/components/revoGrid/revo-grid.js +37 -21
  17. package/dist/collection/plugins/filter/filter.button.js +3 -2
  18. package/dist/collection/plugins/filter/filter.indexed.js +5 -0
  19. package/dist/collection/plugins/filter/filter.panel.js +138 -31
  20. package/dist/collection/plugins/filter/filter.plugin.js +48 -5
  21. package/dist/collection/plugins/filter/filter.style.css +25 -3
  22. package/dist/collection/plugins/groupingRow/grouping.const.js +1 -0
  23. package/dist/collection/plugins/groupingRow/grouping.row.plugin.js +84 -54
  24. package/dist/collection/plugins/groupingRow/grouping.sorting.service.js +58 -0
  25. package/dist/collection/plugins/groupingRow/grouping.trimmed.service.js +5 -3
  26. package/dist/collection/plugins/row-resize/row-resize.plugin.js +144 -113
  27. package/dist/collection/plugins/sorting/sorting.plugin.js +16 -13
  28. package/dist/collection/plugins/wcag/index.js +5 -4
  29. package/dist/collection/services/dimension.provider.js +17 -1
  30. package/dist/esm/{cell-renderer-BFpmdV8H.js → cell-renderer-D9ze8OJw.js} +1 -1
  31. package/dist/esm/{column.service-CM-wgGs8.js → column.service-pu_fdQ0S.js} +2 -1
  32. package/dist/esm/{filter.button-DMhpuAiw.js → filter.button-CEPUxLUo.js} +3 -2
  33. package/dist/{revo-grid/header-cell-renderer-Bqh1PrgH.js → esm/header-cell-renderer-YCiVIQ2E.js} +1 -1
  34. package/dist/esm/index.js +6 -6
  35. package/dist/esm/loader.js +1 -1
  36. package/dist/esm/revo-grid.entry.js +63 -43
  37. package/dist/esm/revo-grid.js +1 -1
  38. package/dist/esm/revogr-attribution_7.entry.js +1 -1
  39. package/dist/esm/revogr-data_4.entry.js +12 -11
  40. package/dist/esm/revogr-filter-panel.entry.js +139 -33
  41. package/dist/esm/{row-resize.plugin-BRiaHlHA.js → row-resize.plugin-Beu0pMds.js} +354 -187
  42. package/dist/revo-grid/{cell-renderer-BFpmdV8H.js → cell-renderer-D9ze8OJw.js} +1 -1
  43. package/dist/revo-grid/{column.service-CM-wgGs8.js → column.service-pu_fdQ0S.js} +2 -1
  44. package/dist/revo-grid/{filter.button-DMhpuAiw.js → filter.button-CEPUxLUo.js} +3 -2
  45. package/dist/{esm/header-cell-renderer-Bqh1PrgH.js → revo-grid/header-cell-renderer-YCiVIQ2E.js} +1 -1
  46. package/dist/revo-grid/index.esm.js +6 -6
  47. package/dist/revo-grid/revo-grid.entry.js +63 -43
  48. package/dist/revo-grid/revo-grid.esm.js +1 -1
  49. package/dist/revo-grid/revogr-attribution_7.entry.js +1 -1
  50. package/dist/revo-grid/revogr-data_4.entry.js +12 -11
  51. package/dist/revo-grid/revogr-filter-panel.entry.js +139 -33
  52. package/dist/revo-grid/{row-resize.plugin-BRiaHlHA.js → row-resize.plugin-Beu0pMds.js} +354 -187
  53. package/dist/types/components/revoGrid/revo-grid.d.ts +2 -0
  54. package/dist/types/plugins/filter/filter.indexed.d.ts +2 -0
  55. package/dist/types/plugins/filter/filter.panel.d.ts +9 -2
  56. package/dist/types/plugins/filter/filter.plugin.d.ts +8 -1
  57. package/dist/types/plugins/filter/filter.types.d.ts +8 -0
  58. package/dist/types/plugins/groupingRow/grouping.const.d.ts +1 -0
  59. package/dist/types/plugins/groupingRow/grouping.row.plugin.d.ts +5 -7
  60. package/dist/types/plugins/groupingRow/grouping.sorting.service.d.ts +7 -0
  61. package/dist/types/plugins/groupingRow/grouping.trimmed.service.d.ts +9 -0
  62. package/dist/types/plugins/row-resize/row-resize.plugin.d.ts +14 -12
  63. package/dist/types/plugins/sorting/sorting.plugin.d.ts +5 -0
  64. package/dist/types/services/dimension.provider.d.ts +7 -1
  65. package/dist/types/types/interfaces.d.ts +13 -1
  66. package/hydrate/index.js +561 -264
  67. package/hydrate/index.mjs +561 -264
  68. package/package.json +1 -1
  69. package/standalone/column.service.js +1 -1
  70. package/standalone/filter.button.js +1 -1
  71. package/standalone/index.js +1 -1
  72. package/standalone/revo-grid.js +1 -1
  73. package/standalone/revogr-data2.js +1 -1
  74. package/standalone/revogr-filter-panel.js +1 -1
  75. package/standalone/revogr-header2.js +1 -1
  76. package/standalone/revogr-overlay-selection2.js +1 -1
@@ -11,19 +11,20 @@ const HeaderRenderer = (p) => {
11
11
  const hasSortingSign = !!(((_a = p.data) === null || _a === void 0 ? void 0 : _a.sortable) ||
12
12
  ((_b = p.data) === null || _b === void 0 ? void 0 : _b.order) ||
13
13
  ((_c = p.data) === null || _c === void 0 ? void 0 : _c.sortIndex));
14
+ const hasFilterButton = !!(p.canFilter && ((_d = p.data) === null || _d === void 0 ? void 0 : _d.filter) !== false);
14
15
  const cellClass = {
15
16
  [HEADER_CLASS]: true,
16
- [HEADER_SORTABLE_CLASS]: !!((_d = p.data) === null || _d === void 0 ? void 0 : _d.sortable),
17
+ [HEADER_SORTABLE_CLASS]: !!((_e = p.data) === null || _e === void 0 ? void 0 : _e.sortable),
17
18
  };
18
- if ((_e = p.data) === null || _e === void 0 ? void 0 : _e.order) {
19
+ if ((_f = p.data) === null || _f === void 0 ? void 0 : _f.order) {
19
20
  cellClass[p.data.order] = true;
20
21
  }
21
22
  const dataProps = {
22
- key: String((_g = (_f = p.data) === null || _f === void 0 ? void 0 : _f.prop) !== null && _g !== void 0 ? _g : p.column.itemIndex),
23
+ key: String((_h = (_g = p.data) === null || _g === void 0 ? void 0 : _g.prop) !== null && _h !== void 0 ? _h : p.column.itemIndex),
23
24
  [DATA_COL]: p.column.itemIndex,
24
25
  canResize: p.canResize,
25
- minWidth: ((_h = p.data) === null || _h === void 0 ? void 0 : _h.minSize) || MIN_COL_SIZE,
26
- maxWidth: (_j = p.data) === null || _j === void 0 ? void 0 : _j.maxSize,
26
+ minWidth: ((_j = p.data) === null || _j === void 0 ? void 0 : _j.minSize) || MIN_COL_SIZE,
27
+ maxWidth: (_k = p.data) === null || _k === void 0 ? void 0 : _k.maxSize,
27
28
  active: p.active || ['r'],
28
29
  class: cellClass,
29
30
  style: {
@@ -59,6 +60,6 @@ const HeaderRenderer = (p) => {
59
60
  }
60
61
  }
61
62
  }
62
- return (h(HeaderCellRenderer, { data: p.data, props: dataProps, additionalData: p.additionalData }, hasSortingSign ? h(SortingSign, { column: p.data }) : null, p.canFilter && ((_k = p.data) === null || _k === void 0 ? void 0 : _k.filter) !== false ? (h(FilterButton, { column: p.data })) : ('')));
63
+ return (h(HeaderCellRenderer, { data: p.data, props: dataProps, additionalData: p.additionalData }, hasSortingSign || hasFilterButton ? (h("span", { class: "header-controls" }, hasSortingSign ? h(SortingSign, { column: p.data }) : null, hasFilterButton ? h(FilterButton, { column: p.data }) : null)) : null));
63
64
  };
64
65
  export default HeaderRenderer;
@@ -71,10 +71,15 @@ revogr-header .rgHeaderCell .header-content {
71
71
  white-space: nowrap;
72
72
  flex-grow: 1;
73
73
  }
74
- revogr-header .rgHeaderCell > span:first-of-type {
75
- position: relative;
74
+ revogr-header .rgHeaderCell .header-controls {
75
+ position: absolute;
76
+ top: 0;
77
+ right: 1px;
78
+ bottom: 1px;
79
+ min-width: 15px;
76
80
  z-index: 1;
77
- margin-left: auto;
81
+ display: flex;
82
+ align-items: center;
78
83
  }
79
84
  revogr-header .rgHeaderCell .resizable {
80
85
  display: block;
@@ -175,9 +175,16 @@ revo-grid[theme]:not([theme=default],
175
175
  [theme=dark],
176
176
  [theme=compact],
177
177
  [theme=darkCompact]) revogr-header .rgHeaderCell {
178
- padding: var(--rg-theme-header-padding);
178
+ padding: 0;
179
179
  text-overflow: ellipsis;
180
180
  }
181
+ revo-grid:is([theme=material], [theme=darkMaterial]) revogr-header .rgHeaderCell .header-content,
182
+ revo-grid[theme]:not([theme=default],
183
+ [theme=dark],
184
+ [theme=compact],
185
+ [theme=darkCompact]) revogr-header .rgHeaderCell .header-content {
186
+ padding: var(--rg-theme-header-padding);
187
+ }
181
188
  revo-grid:is([theme=material], [theme=darkMaterial]) revogr-header .header-rgRow,
182
189
  revo-grid[theme]:not([theme=default],
183
190
  [theme=dark],
@@ -264,9 +271,12 @@ revo-grid:is([theme=compact], [theme=darkCompact]) revogr-header {
264
271
  text-align: var(--rg-theme-header-text-align);
265
272
  }
266
273
  revo-grid:is([theme=compact], [theme=darkCompact]) revogr-header .rgHeaderCell {
267
- padding: var(--rg-theme-header-padding);
274
+ padding: 0;
268
275
  text-overflow: ellipsis;
269
276
  }
277
+ revo-grid:is([theme=compact], [theme=darkCompact]) revogr-header .rgHeaderCell .header-content {
278
+ padding: var(--rg-theme-header-padding);
279
+ }
270
280
  revo-grid:is([theme=compact], [theme=darkCompact]) revogr-header .header-rgRow {
271
281
  height: var(--rg-theme-header-height);
272
282
  }
@@ -21,7 +21,7 @@ import GridScrollingService from "./viewport.scrolling.service";
21
21
  import { SelectionStoreConnector } from "../../services/selection.store.connector";
22
22
  import OrderRenderer from "../order/order-renderer";
23
23
  import { StretchColumn, isStretchPlugin, } from "../../plugins/column.stretch.plugin";
24
- import { rowDefinitionByType, rowDefinitionRemoveByType } from "./grid.helpers";
24
+ import { rowDefinitionByType } from "./grid.helpers";
25
25
  import { ColumnMovePlugin } from "../../plugins/moveColumn/column.drag.plugin";
26
26
  import { getPropertyFromEvent } from "../../utils/events";
27
27
  import { isMobileDevice } from "../../utils/mobile";
@@ -857,29 +857,31 @@ export class RevoGridComponent {
857
857
  vals: after,
858
858
  oldVals: before,
859
859
  });
860
- // apply new values
860
+ this.dimensionProvider.syncRowDefinitions(newVal);
861
861
  const newRows = rowDefinitionByType(newVal);
862
- // clear current defs
863
- if (oldVal) {
864
- const remove = rowDefinitionRemoveByType(oldVal);
865
- // clear all old data and drop sizes
866
- for (const t in remove) {
867
- if (remove.hasOwnProperty(t)) {
868
- const type = t;
869
- const store = this.dataProvider.stores[type];
870
- const sourceLength = store.store.get('source').length;
871
- this.dimensionProvider.clearSize(type, sourceLength);
872
- }
873
- }
874
- }
875
- // set new sizes
862
+ const oldRows = rowDefinitionByType(oldVal);
863
+ const dataProvider = this.dataProvider;
864
+ const dimensionProvider = this.dimensionProvider;
876
865
  rowTypes.forEach((t) => {
877
- var _a;
878
866
  const newSizes = newRows[t];
879
- // apply new sizes or force update
880
- if (newSizes || forceUpdate) {
881
- (_a = this.dimensionProvider) === null || _a === void 0 ? void 0 : _a.setCustomSizes(t, (newSizes === null || newSizes === void 0 ? void 0 : newSizes.sizes) || {});
867
+ const oldSizes = oldRows[t];
868
+ if (!newSizes && !oldSizes && !forceUpdate) {
869
+ return;
882
870
  }
871
+ const sizes = Object.assign({}, dimensionProvider.stores[t].store.get('sizes'));
872
+ const definitionSizes = (newSizes === null || newSizes === void 0 ? void 0 : newSizes.sizes) || {};
873
+ const previousDefinitionSizes = (oldSizes === null || oldSizes === void 0 ? void 0 : oldSizes.sizes) || {};
874
+ const items = dataProvider.stores[t].store.get('items');
875
+ items.forEach((physicalIndex, virtualIndex) => {
876
+ if (Object.hasOwn(previousDefinitionSizes, physicalIndex) &&
877
+ sizes[virtualIndex] === previousDefinitionSizes[physicalIndex]) {
878
+ delete sizes[virtualIndex];
879
+ }
880
+ if (Object.hasOwn(definitionSizes, physicalIndex)) {
881
+ sizes[virtualIndex] = definitionSizes[physicalIndex];
882
+ }
883
+ });
884
+ dimensionProvider.setCustomSizes(t, sizes);
883
885
  });
884
886
  }
885
887
  trimmedRowsChanged(newVal = {}) {
@@ -928,6 +930,9 @@ export class RevoGridComponent {
928
930
  rowHeadersChange(rowHeaders) {
929
931
  this.rowheaderschanged.emit(rowHeaders);
930
932
  }
933
+ resizeRowChanged() {
934
+ this.syncRowResizeConfig();
935
+ }
931
936
  /**
932
937
  * Register external VNodes
933
938
  */
@@ -950,6 +955,7 @@ export class RevoGridComponent {
950
955
  */
951
956
  pluginsChanged(plugins = [], prevPlugins) {
952
957
  this.pluginService.addUserPluginsAndCreate(this.element, plugins, prevPlugins, this.getPluginData());
958
+ this.syncRowResizeConfig();
953
959
  }
954
960
  // #endregion
955
961
  // #region Plugins
@@ -990,11 +996,15 @@ export class RevoGridComponent {
990
996
  this.pluginService.add(new SortingPlugin(this.element, pluginData));
991
997
  // register grouping plugin
992
998
  this.pluginService.add(new GroupingRowPlugin(this.element, pluginData));
993
- this.pluginService.add(RowResizePlugin.fromGridProperty(this.element, pluginData));
999
+ this.pluginService.add(new RowResizePlugin(this.element, pluginData));
994
1000
  if (this.canMoveColumns) {
995
1001
  this.pluginService.add(new ColumnMovePlugin(this.element, pluginData));
996
1002
  }
997
1003
  }
1004
+ syncRowResizeConfig() {
1005
+ const plugin = this.pluginService.getByClass(RowResizePlugin);
1006
+ plugin === null || plugin === void 0 ? void 0 : plugin.syncGridConfig();
1007
+ }
998
1008
  getPluginData() {
999
1009
  if (!this.dimensionProvider || !this.dataProvider || !this.columnProvider || !this.viewportProvider || !this.selectionStoreConnector) {
1000
1010
  return;
@@ -1037,6 +1047,9 @@ export class RevoGridComponent {
1037
1047
  this.themeService.setDefinitions(this.themeDefinitions);
1038
1048
  this.dimensionProvider = new DimensionProvider(this.viewportProvider, {
1039
1049
  realSizeChanged: (k) => this.contentsizechanged.emit(k),
1050
+ rowDefinitionsChanged: definitions => {
1051
+ this.rowDefinitions = definitions;
1052
+ },
1040
1053
  });
1041
1054
  this.dimensionProvider.setSettings({ originItemSize: getColumnSize(this.colSize) }, 'rgCol');
1042
1055
  this.columnProvider = new ColumnDataProvider();
@@ -3873,6 +3886,9 @@ export class RevoGridComponent {
3873
3886
  }, {
3874
3887
  "propName": "rowHeaders",
3875
3888
  "methodName": "rowHeadersChange"
3889
+ }, {
3890
+ "propName": "resizeRow",
3891
+ "methodName": "resizeRowChanged"
3876
3892
  }, {
3877
3893
  "propName": "registerVNode",
3878
3894
  "methodName": "registerOutsideVNodes"
@@ -9,9 +9,10 @@ export const AND_OR_BUTTON = 'and-or-button';
9
9
  export const TRASH_BUTTON = 'trash-button';
10
10
  export const REORDER_BUTTON = 'reorder-button';
11
11
  export const FilterButton = ({ column }) => {
12
- return (h("span", null, h("button", { class: {
12
+ const active = !!(column === null || column === void 0 ? void 0 : column[FILTER_PROP]);
13
+ return (h("span", { class: "filter-button-wrapper" }, h("button", { class: {
13
14
  [FILTER_BUTTON_CLASS]: true,
14
- [FILTER_BUTTON_ACTIVE]: column && !!column[FILTER_PROP],
15
+ [FILTER_BUTTON_ACTIVE]: active,
15
16
  } }, h("svg", { class: "filter-img", viewBox: "0 0 64 64" }, h("g", { stroke: "none", "stroke-width": "1", fill: "none", "fill-rule": "evenodd" }, h("path", { d: "M43,48 L43,56 L21,56 L21,48 L43,48 Z M53,28 L53,36 L12,36 L12,28 L53,28 Z M64,8 L64,16 L0,16 L0,8 L64,8 Z", fill: "currentColor" }))))));
16
17
  };
17
18
  export const TrashButton = ({ ariaLabel, onClick }) => {
@@ -32,6 +32,11 @@ export const filterTypes = {
32
32
  boolean: ['notEmpty', 'empty'],
33
33
  array: ['notEmpty', 'empty'],
34
34
  };
35
+ /** Preferred initial operator for built-in filter families. */
36
+ export const filterTypeDefaults = {
37
+ string: 'contains',
38
+ number: 'eqN',
39
+ };
35
40
  export const filterNames = {
36
41
  none: 'None',
37
42
  empty: 'Is blank',
@@ -20,6 +20,7 @@ const VIEWPORT_PADDING = 8;
20
20
  */
21
21
  export class FilterPanel {
22
22
  constructor() {
23
+ this.hasChanges = false;
23
24
  this.filterCaptionsInternal = {
24
25
  title: 'Filter by',
25
26
  ok: 'Close',
@@ -55,7 +56,7 @@ export class FilterPanel {
55
56
  */
56
57
  this.allowDuplicateOperators = true;
57
58
  this.debouncedApplyFilter = debounce(() => {
58
- this.filterChange.emit(this.filterItems);
59
+ this.emitFilterChange();
59
60
  }, 400);
60
61
  }
61
62
  onMouseDown(e) {
@@ -85,10 +86,25 @@ export class FilterPanel {
85
86
  }
86
87
  }
87
88
  async show(newEntity) {
89
+ this.hasChanges = false;
88
90
  this.changes = newEntity;
89
- this.filterItems = (newEntity === null || newEntity === void 0 ? void 0 : newEntity.filterItems) || {};
91
+ this.filterItems = this.cloneFilterItems((newEntity === null || newEntity === void 0 ? void 0 : newEntity.filterItems) || {});
92
+ this.draftFilter = undefined;
90
93
  if (this.changes) {
91
94
  this.changes.type = this.changes.type || defaultType;
95
+ const prop = this.changes.prop;
96
+ const propFilters = prop === undefined ? undefined : this.filterItems[prop];
97
+ if (!(propFilters === null || propFilters === void 0 ? void 0 : propFilters.length) && this.changes.showDefaultFilter !== false) {
98
+ const type = this.resolveDraftFilterType(this.changes.defaultFilterType);
99
+ if (type) {
100
+ this.draftFilter = {
101
+ id: ++this.filterId,
102
+ type,
103
+ value: '',
104
+ relation: 'and',
105
+ };
106
+ }
107
+ }
92
108
  }
93
109
  }
94
110
  async getChanges() {
@@ -109,29 +125,42 @@ export class FilterPanel {
109
125
  const prop = (_a = this.changes) === null || _a === void 0 ? void 0 : _a.prop;
110
126
  if (prop === undefined)
111
127
  return '';
112
- const propFilters = (_b = this.filterItems[prop]) !== null && _b !== void 0 ? _b : [];
113
- const visibleFilterCount = propFilters.filter(filter => !filter.hidden).length;
128
+ const propFilters = ((_b = this.filterItems[prop]) !== null && _b !== void 0 ? _b : []).map((filter, index) => ({
129
+ filter,
130
+ index,
131
+ isDraft: false,
132
+ }));
133
+ if (this.draftFilter) {
134
+ propFilters.push({
135
+ filter: this.draftFilter,
136
+ index: propFilters.length,
137
+ isDraft: true,
138
+ });
139
+ }
140
+ const visibleFilters = propFilters.filter(({ filter }) => !filter.hidden);
141
+ const visibleFilterCount = visibleFilters.length;
114
142
  const capts = Object.assign(Object.assign({}, this.filterCaptionsInternal), this.filterCaptions);
115
- return (h("div", { key: this.filterId }, h("ul", { class: "multi-filter-list-container" }, propFilters.map((filter, index) => {
143
+ return (h("div", { key: this.filterId }, h("ul", { class: "multi-filter-list-container" }, propFilters.map(({ filter, index, isDraft }) => {
144
+ var _a;
116
145
  let andOrButton;
117
146
  if (filter.hidden) {
118
147
  return;
119
148
  }
120
149
  // hide toggle button if there is only one filter and the last one
121
- if (index !== this.filterItems[prop].length - 1) {
150
+ if (((_a = visibleFilters[visibleFilterCount - 1]) === null || _a === void 0 ? void 0 : _a.filter.id) !== filter.id) {
122
151
  andOrButton = (h(AndOrButton, { text: filter.relation === 'and' ? capts.and : capts.or, onClick: () => this.toggleFilterAndOr(filter.id) }));
123
152
  }
124
- const extra = this.renderExtra(prop, index);
153
+ const extra = this.renderExtra(prop, index, isDraft);
125
154
  const isDragging = this.draggedFilterId === filter.id;
126
155
  const isDragOver = this.dragOverFilterId === filter.id && !isDragging;
127
- const canReorder = visibleFilterCount > 1;
156
+ const canReorder = visibleFilterCount > 1 && !isDraft;
128
157
  return (h("li", { key: filter.id, class: FILTER_LIST_CLASS, "aria-label": `${capts.filterCondition} ${index + 1}` }, h("div", { class: {
129
158
  'multi-filter-list-row': true,
130
159
  'filter-row-drop-active': this.draggedFilterId !== undefined && !isDragging,
131
160
  'filter-row-dragging': isDragging,
132
161
  'filter-row-drag-over': isDragOver,
133
- } }, canReorder ? (h("button", { type: "button", class: "filter-row-drop-target", tabIndex: -1, "aria-label": `${capts.filterCondition} ${index + 1}`, onDragOver: e => this.onFilterDragOver(e, filter.id), onDragLeave: () => this.onFilterDragLeave(filter.id), onDrop: e => this.onFilterDrop(e, prop, filter.id) })) : '', canReorder ? (h(ReorderButton, { ariaLabel: capts.reorderFilter, dragging: isDragging, dragOver: isDragOver, onDragStart: e => this.onFilterDragStart(e, filter.id), onDragEnd: () => this.onFilterDragEnd(), onKeyDown: e => this.onFilterReorderKeyDown(e, prop, filter.id) })) : '', h("div", { class: { 'select-input': true } }, h("select", { class: "select-css select-filter", onChange: e => this.onFilterTypeChange(e, prop, index) }, this.renderSelectOptions(this.filterItems[prop][index].type, true)), extra ? h("div", { class: "filter-extra" }, extra) : ''), h("div", { class: FILTER_LIST_CLASS_ACTION }, andOrButton, h(TrashButton, { ariaLabel: capts.removeFilter, onClick: () => this.onRemoveFilter(filter.id) })))));
134
- })), propFilters.some(f => !f.hidden) ? h("div", { class: "add-filter-divider" }) : ''));
162
+ } }, canReorder ? (h("button", { type: "button", class: "filter-row-drop-target", tabIndex: -1, "aria-label": `${capts.filterCondition} ${index + 1}`, onDragOver: e => this.onFilterDragOver(e, filter.id), onDragLeave: () => this.onFilterDragLeave(filter.id), onDrop: e => this.onFilterDrop(e, prop, filter.id) })) : '', canReorder ? (h(ReorderButton, { ariaLabel: capts.reorderFilter, dragging: isDragging, dragOver: isDragOver, onDragStart: e => this.onFilterDragStart(e, filter.id), onDragEnd: () => this.onFilterDragEnd(), onKeyDown: e => this.onFilterReorderKeyDown(e, prop, filter.id) })) : '', h("div", { class: { 'select-input': true } }, h("select", { class: "select-css select-filter", onChange: e => this.onFilterTypeChange(e, prop, index, isDraft) }, this.renderSelectOptions(filter.type, true)), extra ? h("div", { class: "filter-extra" }, extra) : ''), h("div", { class: FILTER_LIST_CLASS_ACTION }, andOrButton, h(TrashButton, { ariaLabel: capts.removeFilter, onClick: () => this.onRemoveFilter(filter.id) })))));
163
+ })), visibleFilterCount ? h("div", { class: "add-filter-divider" }) : ''));
135
164
  }
136
165
  componentDidRender() {
137
166
  this.syncDialog();
@@ -180,16 +209,24 @@ export class FilterPanel {
180
209
  el.style.left = `${left}px`;
181
210
  el.style.top = `${top}px`;
182
211
  }
183
- onFilterTypeChange(e, prop, index) {
212
+ onFilterTypeChange(e, prop, index, isDraft = false) {
184
213
  if (!(e.target instanceof HTMLSelectElement)) {
185
214
  return;
186
215
  }
187
- this.filterItems[prop][index].type = e.target.value;
216
+ const type = e.target.value;
217
+ const filter = isDraft
218
+ ? this.promoteDraft(prop, type)
219
+ : this.filterItems[prop][index];
220
+ if (!filter) {
221
+ return;
222
+ }
223
+ filter.type = type;
224
+ this.hasChanges = true;
188
225
  // this re-renders the input to know if we need extra input
189
226
  this.filterId++;
190
227
  // adding setTimeout will wait for the next tick DOM update then focus on input
191
228
  setTimeout(() => {
192
- const input = document.getElementById('filter-input-' + this.filterItems[prop][index].id);
229
+ const input = document.getElementById('filter-input-' + filter.id);
193
230
  if (input instanceof HTMLInputElement) {
194
231
  input.focus();
195
232
  }
@@ -224,12 +261,20 @@ export class FilterPanel {
224
261
  return;
225
262
  this.filterId++;
226
263
  this.currentFilterId = this.filterId;
227
- this.filterItems[prop].push({
228
- id: this.currentFilterId,
229
- type: this.currentFilterType,
230
- value: '',
231
- relation: 'and',
232
- });
264
+ if (this.draftFilter) {
265
+ this.draftFilter.id = this.currentFilterId;
266
+ this.draftFilter.type = this.currentFilterType;
267
+ this.promoteDraft(prop);
268
+ }
269
+ else {
270
+ this.filterItems[prop].push({
271
+ id: this.currentFilterId,
272
+ type: this.currentFilterType,
273
+ value: '',
274
+ relation: 'and',
275
+ });
276
+ this.hasChanges = true;
277
+ }
233
278
  // adding setTimeout will wait for the next tick DOM update then focus on input
234
279
  setTimeout(() => {
235
280
  const input = document.getElementById('filter-input-' + this.currentFilterId);
@@ -238,7 +283,9 @@ export class FilterPanel {
238
283
  }, 0);
239
284
  }
240
285
  onSave() {
241
- this.filterChange.emit(this.filterItems);
286
+ if (this.hasChanges) {
287
+ this.emitFilterChange();
288
+ }
242
289
  }
243
290
  onCancel() {
244
291
  this.changes = undefined;
@@ -246,16 +293,25 @@ export class FilterPanel {
246
293
  onReset() {
247
294
  var _a;
248
295
  this.assertChanges();
249
- this.resetChange.emit((_a = this.changes) === null || _a === void 0 ? void 0 : _a.prop);
296
+ this.draftFilter = undefined;
297
+ const prop = (_a = this.changes) === null || _a === void 0 ? void 0 : _a.prop;
298
+ if (prop !== undefined) {
299
+ delete this.filterItems[prop];
300
+ }
301
+ this.resetChange.emit(prop);
250
302
  // this updates the DOM which is used by getFilterItemsList() key
251
303
  this.filterId++;
252
304
  }
253
305
  onRemoveFilter(id) {
254
- var _a;
306
+ var _a, _b;
255
307
  this.assertChanges();
256
308
  // this is for reactivity issues for getFilterItemsList()
257
309
  this.filterId++;
258
310
  const prop = (_a = this.changes) === null || _a === void 0 ? void 0 : _a.prop;
311
+ if (((_b = this.draftFilter) === null || _b === void 0 ? void 0 : _b.id) === id) {
312
+ this.draftFilter = undefined;
313
+ return;
314
+ }
259
315
  const items = this.filterItems[prop !== null && prop !== void 0 ? prop : ''];
260
316
  if (!items)
261
317
  return;
@@ -263,6 +319,7 @@ export class FilterPanel {
263
319
  if (index === -1)
264
320
  return;
265
321
  items.splice(index, 1);
322
+ this.hasChanges = true;
266
323
  // let's remove the prop if no more filters so the filter icon will be removed
267
324
  if (items.length === 0)
268
325
  delete this.filterItems[prop !== null && prop !== void 0 ? prop : ''];
@@ -304,6 +361,7 @@ export class FilterPanel {
304
361
  if (!moveFilterItem(items, sourceId, targetId)) {
305
362
  return;
306
363
  }
364
+ this.hasChanges = true;
307
365
  this.filterId++;
308
366
  if (!this.disableDynamicFiltering) {
309
367
  this.debouncedApplyFilter();
@@ -339,6 +397,7 @@ export class FilterPanel {
339
397
  if (!target || !moveFilterItem(items, sourceId, target.id)) {
340
398
  return;
341
399
  }
400
+ this.hasChanges = true;
342
401
  this.filterId++;
343
402
  if (!this.disableDynamicFiltering) {
344
403
  this.debouncedApplyFilter();
@@ -357,6 +416,7 @@ export class FilterPanel {
357
416
  if (index === -1)
358
417
  return;
359
418
  items[index].relation = items[index].relation === 'and' ? 'or' : 'and';
419
+ this.hasChanges = true;
360
420
  if (!this.disableDynamicFiltering) {
361
421
  this.debouncedApplyFilter();
362
422
  }
@@ -405,12 +465,22 @@ export class FilterPanel {
405
465
  }
406
466
  return options;
407
467
  }
408
- renderExtra(prop, index) {
409
- const currentFilter = this.filterItems[prop];
468
+ renderExtra(prop, index, isDraft = false) {
469
+ var _a, _b;
470
+ const currentFilter = isDraft
471
+ ? this.draftFilter
472
+ : (_a = this.filterItems[prop]) === null || _a === void 0 ? void 0 : _a[index];
410
473
  if (!currentFilter)
411
474
  return '';
412
475
  const applyFilter = (value) => {
413
- this.filterItems[prop][index].value = value;
476
+ currentFilter.value = value;
477
+ if (isDraft && !this.isMeaningfulDraftValue(value)) {
478
+ return;
479
+ }
480
+ if (isDraft && !this.promoteDraft(prop)) {
481
+ return;
482
+ }
483
+ this.hasChanges = true;
414
484
  if (!this.disableDynamicFiltering) {
415
485
  this.debouncedApplyFilter();
416
486
  }
@@ -425,11 +495,11 @@ export class FilterPanel {
425
495
  }
426
496
  };
427
497
  const capts = Object.assign(Object.assign({}, this.filterCaptionsInternal), this.filterCaptions);
428
- const extra = this.filterEntities[currentFilter[index].type].extra;
498
+ const extra = (_b = this.filterEntities[currentFilter.type]) === null || _b === void 0 ? void 0 : _b.extra;
429
499
  if (typeof extra === 'function') {
430
500
  return extra(h, {
431
- value: currentFilter[index].value,
432
- filter: currentFilter[index],
501
+ value: currentFilter.value,
502
+ filter: currentFilter,
433
503
  prop,
434
504
  index,
435
505
  placeholder: capts.placeholder,
@@ -444,7 +514,7 @@ export class FilterPanel {
444
514
  if (extra !== 'input' && extra !== 'datepicker') {
445
515
  return '';
446
516
  }
447
- return (h("input", { id: `filter-input-${currentFilter[index].id}`, placeholder: capts.placeholder, type: extra === 'datepicker' ? 'date' : 'text', value: currentFilter[index].value, onInput: (e) => {
517
+ return (h("input", { id: `filter-input-${currentFilter.id}`, placeholder: capts.placeholder, type: extra === 'datepicker' ? 'date' : 'text', value: currentFilter.value, onInput: (e) => {
448
518
  if (e.target instanceof HTMLInputElement) {
449
519
  applyFilter(e.target.value);
450
520
  }
@@ -460,6 +530,42 @@ export class FilterPanel {
460
530
  e.stopPropagation();
461
531
  } }));
462
532
  }
533
+ resolveDraftFilterType(preferred) {
534
+ var _a, _b;
535
+ const available = Object.values((_b = (_a = this.changes) === null || _a === void 0 ? void 0 : _a.filterTypes) !== null && _b !== void 0 ? _b : {}).flat();
536
+ const type = preferred && available.includes(preferred)
537
+ ? preferred
538
+ : available[0];
539
+ return type;
540
+ }
541
+ promoteDraft(prop, type) {
542
+ if (!this.draftFilter) {
543
+ return;
544
+ }
545
+ if (!this.filterItems[prop]) {
546
+ this.filterItems[prop] = [];
547
+ }
548
+ if (type) {
549
+ this.draftFilter.type = type;
550
+ }
551
+ const filter = this.draftFilter;
552
+ this.filterItems[prop].push(filter);
553
+ this.draftFilter = undefined;
554
+ this.hasChanges = true;
555
+ return filter;
556
+ }
557
+ isMeaningfulDraftValue(value) {
558
+ return value !== '' && value !== undefined && value !== null;
559
+ }
560
+ emitFilterChange() {
561
+ this.filterChange.emit(this.cloneFilterItems(this.filterItems));
562
+ }
563
+ cloneFilterItems(filterItems) {
564
+ return Object.fromEntries(Object.entries(filterItems).map(([prop, filters]) => [
565
+ prop,
566
+ filters.map(filter => (Object.assign({}, filter))),
567
+ ]));
568
+ }
463
569
  getAddFilterSelect() {
464
570
  return this.element.querySelector(`#${FILTER_ID}`);
465
571
  }
@@ -492,7 +598,7 @@ export class FilterPanel {
492
598
  top: `${(_d = (_c = this.changes) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0}px`,
493
599
  };
494
600
  const capts = Object.assign(Object.assign({}, this.filterCaptionsInternal), this.filterCaptions);
495
- return (h(Host, { key: 'd0e4ebb408750b11b3965da6a25e581733c968e3' }, h("dialog", { key: '3df36777c931ec1063e8574169ca880a99dbfe41', class: "filter-panel-dialog", style: style, ref: el => (this.dialog = el), onCancel: e => {
601
+ return (h(Host, { key: '0bb6ac39407141e989b6a2f54063ee5ed789e40e' }, h("dialog", { key: '28a919ca4184018e8f00bbd31d373e153306d163', class: "filter-panel-dialog", style: style, ref: el => (this.dialog = el), onCancel: e => {
496
602
  e.preventDefault();
497
603
  this.onCancel();
498
604
  } }, this.changes && [
@@ -501,7 +607,7 @@ export class FilterPanel {
501
607
  ((_g = this.changes) === null || _g === void 0 ? void 0 : _g.hideDefaultFilters) !== true && [
502
608
  h("label", { key: "filter-title" }, capts.title),
503
609
  h("div", { key: "filter-holder", class: "filter-holder" }, this.getFilterItemsList()),
504
- h("div", { key: "add-filter", class: "add-filter" }, h("select", { key: 'e2a8bd29f2090d3e6c933795427b71ca190b82aa', id: FILTER_ID, class: "select-css", onChange: e => this.onAddNewFilter(e) }, this.renderSelectOptions(this.currentFilterType))),
610
+ h("div", { key: "add-filter", class: "add-filter" }, h("select", { key: 'c5816b6699d8608bd8ec2621bbbd4c70daf52a1e', id: FILTER_ID, class: "select-css", onChange: e => this.onAddNewFilter(e) }, this.renderSelectOptions(this.currentFilterType))),
505
611
  ],
506
612
  h("slot", { key: "default-slot" }),
507
613
  ((_j = (_h = this.changes).extraBottomContent) === null || _j === void 0 ? void 0 : _j.call(_h, this.changes)) || '',
@@ -678,6 +784,7 @@ export class FilterPanel {
678
784
  "currentFilterType": {},
679
785
  "changes": {},
680
786
  "filterItems": {},
787
+ "draftFilter": {},
681
788
  "draggedFilterId": {},
682
789
  "dragOverFilterId": {}
683
790
  };