@revolist/revogrid 4.23.14 → 4.23.16

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 (81) hide show
  1. package/dist/cjs/{cell-renderer-Dcz022q7.js → cell-renderer-DfUCisis.js} +23 -5
  2. package/dist/cjs/{column.drag.plugin-BGLbi1zS.js → column.drag.plugin-ByDJ7Rk3.js} +35 -6
  3. package/dist/cjs/{column.service-C1Qvcf5l.js → column.service-BNWNiJW3.js} +62 -23
  4. package/dist/cjs/{filter.button-w6LWnyhi.js → filter.button-C4xpvyyE.js} +14 -4
  5. package/dist/cjs/{header-cell-renderer-vVr4IWNV.js → header-cell-renderer-DyjOxArm.js} +1 -1
  6. package/dist/cjs/index.cjs.js +8 -5
  7. package/dist/cjs/loader.cjs.js +1 -1
  8. package/dist/cjs/revo-grid.cjs.entry.js +6 -6
  9. package/dist/cjs/revo-grid.cjs.js +1 -1
  10. package/dist/cjs/revogr-attribution_7.cjs.entry.js +40 -4
  11. package/dist/cjs/revogr-clipboard_3.cjs.entry.js +1 -1
  12. package/dist/cjs/revogr-data_4.cjs.entry.js +14 -6
  13. package/dist/cjs/revogr-filter-panel.cjs.entry.js +177 -48
  14. package/dist/collection/components/clipboard/revogr-clipboard.js +1 -1
  15. package/dist/collection/components/data/column.service.js +62 -23
  16. package/dist/collection/components/data/row-renderer.js +15 -2
  17. package/dist/collection/components/overlay/clipboard.utils.js +26 -0
  18. package/dist/collection/components/overlay/revogr-overlay-selection.js +27 -7
  19. package/dist/collection/components/revoGrid/revo-grid.js +14 -7
  20. package/dist/collection/components/scroll/revogr-viewport-scroll.js +10 -2
  21. package/dist/collection/plugins/filter/filter.button.js +12 -4
  22. package/dist/collection/plugins/filter/filter.panel.js +138 -48
  23. package/dist/collection/plugins/filter/filter.plugin.js +1 -1
  24. package/dist/collection/plugins/filter/filter.reorder.js +44 -0
  25. package/dist/collection/plugins/filter/filter.style.css +96 -6
  26. package/dist/collection/plugins/groupingRow/grouping.row.renderer.js +7 -2
  27. package/dist/collection/plugins/moveColumn/column.drag.plugin.js +30 -2
  28. package/dist/collection/serve/controller.js +1 -0
  29. package/dist/esm/{cell-renderer-BtN-NGCk.js → cell-renderer-CLTRlCa5.js} +23 -5
  30. package/dist/esm/{column.drag.plugin-4Ixr4ijU.js → column.drag.plugin-BZacA8n_.js} +35 -7
  31. package/dist/esm/{column.service-CC_SD8W3.js → column.service-C6hByxPy.js} +62 -23
  32. package/dist/esm/filter.button-B-RBiF67.js +38 -0
  33. package/dist/esm/{header-cell-renderer-B-LX2sgu.js → header-cell-renderer-BMmXRsd_.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 +6 -6
  37. package/dist/esm/revo-grid.js +1 -1
  38. package/dist/esm/revogr-attribution_7.entry.js +40 -4
  39. package/dist/esm/revogr-clipboard_3.entry.js +1 -1
  40. package/dist/esm/revogr-data_4.entry.js +14 -6
  41. package/dist/esm/revogr-filter-panel.entry.js +177 -48
  42. package/dist/revo-grid/{cell-renderer-BtN-NGCk.js → cell-renderer-CLTRlCa5.js} +23 -5
  43. package/dist/revo-grid/{column.drag.plugin-4Ixr4ijU.js → column.drag.plugin-BZacA8n_.js} +35 -7
  44. package/dist/revo-grid/{column.service-CC_SD8W3.js → column.service-C6hByxPy.js} +62 -23
  45. package/dist/revo-grid/filter.button-B-RBiF67.js +38 -0
  46. package/dist/revo-grid/{header-cell-renderer-B-LX2sgu.js → header-cell-renderer-BMmXRsd_.js} +1 -1
  47. package/dist/revo-grid/index.esm.js +6 -6
  48. package/dist/revo-grid/revo-grid.entry.js +6 -6
  49. package/dist/revo-grid/revo-grid.esm.js +1 -1
  50. package/dist/revo-grid/revogr-attribution_7.entry.js +40 -4
  51. package/dist/revo-grid/revogr-clipboard_3.entry.js +1 -1
  52. package/dist/revo-grid/revogr-data_4.entry.js +14 -6
  53. package/dist/revo-grid/revogr-filter-panel.entry.js +177 -48
  54. package/dist/types/components/data/column.service.d.ts +10 -1
  55. package/dist/types/components/data/row-renderer.d.ts +1 -1
  56. package/dist/types/components/overlay/clipboard.utils.d.ts +3 -0
  57. package/dist/types/components/overlay/revogr-overlay-selection.d.ts +4 -3
  58. package/dist/types/components/revoGrid/revo-grid.d.ts +4 -4
  59. package/dist/types/components.d.ts +14 -14
  60. package/dist/types/plugins/filter/filter.button.d.ts +23 -2
  61. package/dist/types/plugins/filter/filter.panel.d.ts +8 -1
  62. package/dist/types/plugins/filter/filter.plugin.d.ts +1 -0
  63. package/dist/types/plugins/filter/filter.reorder.d.ts +4 -0
  64. package/dist/types/plugins/filter/filter.types.d.ts +8 -0
  65. package/dist/types/plugins/moveColumn/column.drag.plugin.d.ts +4 -0
  66. package/dist/types/types/interfaces.d.ts +8 -0
  67. package/hydrate/index.js +358 -90
  68. package/hydrate/index.mjs +358 -90
  69. package/package.json +1 -1
  70. package/readme.md +20 -1
  71. package/standalone/column.service.js +1 -1
  72. package/standalone/filter.button.js +1 -1
  73. package/standalone/index.js +1 -1
  74. package/standalone/revo-grid.js +1 -1
  75. package/standalone/revogr-clipboard2.js +1 -1
  76. package/standalone/revogr-data2.js +1 -1
  77. package/standalone/revogr-filter-panel.js +1 -1
  78. package/standalone/revogr-overlay-selection2.js +1 -1
  79. package/standalone/revogr-viewport-scroll2.js +1 -1
  80. package/dist/esm/filter.button-C8XTWPU2.js +0 -30
  81. package/dist/revo-grid/filter.button-C8XTWPU2.js +0 -30
@@ -64,7 +64,7 @@ export class RevoGridComponent {
64
64
  this.rowSize = 0;
65
65
  /** Indicates default column size. */
66
66
  this.colSize = 100;
67
- /** When true, user can range selection. */
67
+ /** When true, user can select a cell range. Required for range-based clipboard fill. */
68
68
  this.range = false;
69
69
  /** When true, grid in read only mode. */
70
70
  this.readonly = false;
@@ -76,7 +76,7 @@ export class RevoGridComponent {
76
76
  this.noHorizontalScrollTransfer = false;
77
77
  /** When true cell focus appear. */
78
78
  this.canFocus = true;
79
- /** When true enable clipboard. */
79
+ /** When true enable clipboard. Can be boolean or clipboard config. */
80
80
  this.useClipboard = true;
81
81
  /**
82
82
  * Columns - defines an array of grid columns.
@@ -1202,7 +1202,7 @@ export class RevoGridComponent {
1202
1202
  "optional": false,
1203
1203
  "docs": {
1204
1204
  "tags": [],
1205
- "text": "When true, user can range selection."
1205
+ "text": "When true, user can select a cell range. Required for range-based clipboard fill."
1206
1206
  },
1207
1207
  "getter": false,
1208
1208
  "setter": false,
@@ -1294,15 +1294,22 @@ export class RevoGridComponent {
1294
1294
  "type": "boolean",
1295
1295
  "mutable": false,
1296
1296
  "complexType": {
1297
- "original": "boolean",
1298
- "resolved": "boolean",
1299
- "references": {}
1297
+ "original": "boolean | ClipboardConfig",
1298
+ "resolved": "ClipboardConfig | boolean",
1299
+ "references": {
1300
+ "ClipboardConfig": {
1301
+ "location": "import",
1302
+ "path": "@type",
1303
+ "id": "src/types/index.ts::ClipboardConfig",
1304
+ "referenceLocation": "ClipboardConfig"
1305
+ }
1306
+ }
1300
1307
  },
1301
1308
  "required": false,
1302
1309
  "optional": false,
1303
1310
  "docs": {
1304
1311
  "tags": [],
1305
- "text": "When true enable clipboard."
1312
+ "text": "When true enable clipboard. Can be boolean or clipboard config."
1306
1313
  },
1307
1314
  "getter": false,
1308
1315
  "setter": false,
@@ -219,9 +219,17 @@ export class RevogrViewportScroll {
219
219
  }
220
220
  render() {
221
221
  var _a, _b;
222
- const physicalContentHeight = getContentSize(this.contentHeight, (_b = (_a = this.verticalScroll) === null || _a === void 0 ? void 0 : _a.clientHeight) !== null && _b !== void 0 ? _b : 0);
222
+ const clientHeight = (_b = (_a = this.verticalScroll) === null || _a === void 0 ? void 0 : _a.clientHeight) !== null && _b !== void 0 ? _b : 0;
223
+ // When content fits in the viewport (no scroll needed), don't inflate content-wrapper
224
+ // to clientHeight — that would prevent inner-content-table from shrinking and push
225
+ // rowPinEnd (footer) to the bottom instead of letting it follow the data rows.
226
+ // For large/compressed grids (content > clientHeight), physicalContentHeight handles
227
+ // the browser scroll-size compression correctly.
228
+ const physicalContentHeight = this.contentHeight < clientHeight
229
+ ? Math.max(this.contentHeight, 0)
230
+ : getContentSize(this.contentHeight, clientHeight);
223
231
  const physicalContentWidth = getContentSize(this.contentWidth, 0);
224
- return (h(Host, { key: 'ec8d907976c1d50f7aab3c263be3f0249a274df6', onWheel: this.horizontalMouseWheel, onScroll: (e) => this.applyScroll('rgCol', e) }, h("div", { key: 'e35696a7993ac94261426b45c28d488cdc42b7f0', class: "inner-content-table", style: { width: `${physicalContentWidth}px` } }, h("div", { key: 'a6997451e01eacda1d27d4efa1d74e1748626218', class: "header-wrapper", ref: e => (this.header = e) }, h("slot", { key: '1d401e87d32d5b1531c2211723b552bbc894f22c', name: HEADER_SLOT })), h("div", { key: 'ceab6f9e812d6ca9a0aa376afcd2562a17f505e0', class: "vertical-inner", ref: el => (this.verticalScroll = el), onWheel: this.verticalMouseWheel, onScroll: (e) => this.applyScroll('rgRow', e) }, h("div", { key: 'a9556578a23d6efddec2e982e863aec064042154', class: "content-wrapper", style: { height: `${physicalContentHeight}px` } }, h("slot", { key: '0ae01f9736b9740612e75261f6e3abebda533377', name: CONTENT_SLOT }))), h("div", { key: '09c2565d4ed449a43820f92d97b6558fca3758e7', class: "footer-wrapper", ref: e => (this.footer = e) }, h("slot", { key: '1ffb08ff8138a560cc09d82e3fe22a53e502aafe', name: FOOTER_SLOT })))));
232
+ return (h(Host, { key: '3dd9d29cf26743d7aa4995f51180d56008526e54', onWheel: this.horizontalMouseWheel, onScroll: (e) => this.applyScroll('rgCol', e) }, h("div", { key: 'af75428e845044c33eba2fecd1ec04a9177b9b5c', class: "inner-content-table", style: { width: `${physicalContentWidth}px` } }, h("div", { key: 'a0149f597588371e1fafe69efc3bd4411379a017', class: "header-wrapper", ref: e => (this.header = e) }, h("slot", { key: 'e5d2570bf93897cd97ef702141c83bb8c0e13ee2', name: HEADER_SLOT })), h("div", { key: 'd1388ff0d721dd8ce925b934bb2128fddc1ac17b', class: "vertical-inner", ref: el => (this.verticalScroll = el), onWheel: this.verticalMouseWheel, onScroll: (e) => this.applyScroll('rgRow', e) }, h("div", { key: 'a306ff56f62279402e2a881a081e3224341d5bdf', class: "content-wrapper", style: { height: `${physicalContentHeight}px` } }, h("slot", { key: '898bda8e9429da06c9ff2bd41626ac27f3cde3cc', name: CONTENT_SLOT }))), h("div", { key: '5e9eba1edd5fca07a964971054a7900e4dd84099', class: "footer-wrapper", ref: e => (this.footer = e) }, h("slot", { key: 'f233ad1c23b3f692c45e1db235cfef4704a80726', name: FOOTER_SLOT })))));
225
233
  }
226
234
  /**
227
235
  * Extra layer for scroll event monitoring, where MouseWheel event is not passing
@@ -7,17 +7,25 @@ export const FILTER_BUTTON_ACTIVE = 'active';
7
7
  export const FILTER_PROP = 'hasFilter';
8
8
  export const AND_OR_BUTTON = 'and-or-button';
9
9
  export const TRASH_BUTTON = 'trash-button';
10
+ export const REORDER_BUTTON = 'reorder-button';
10
11
  export const FilterButton = ({ column }) => {
11
12
  return (h("span", null, h("button", { class: {
12
13
  [FILTER_BUTTON_CLASS]: true,
13
14
  [FILTER_BUTTON_ACTIVE]: column && !!column[FILTER_PROP],
14
15
  } }, 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" }))))));
15
16
  };
16
- export const TrashButton = () => {
17
- return (h("div", { class: { [TRASH_BUTTON]: true } }, h("svg", { class: "trash-img", viewBox: "0 0 24 24" }, h("path", { fill: "currentColor", d: "M9,3V4H4V6H5V19A2,2 0 0,0 7,21H17A2,2 0 0,0 19,19V6H20V4H15V3H9M7,6H17V19H7V6M9,8V17H11V8H9M13,8V17H15V8H13Z" }))));
17
+ export const TrashButton = ({ ariaLabel, onClick }) => {
18
+ return (h("button", { type: "button", class: { [TRASH_BUTTON]: true }, "aria-label": ariaLabel, onClick: onClick }, h("svg", { class: "trash-img", viewBox: "0 0 24 24" }, h("path", { fill: "currentColor", d: "M9,3V4H4V6H5V19A2,2 0 0,0 7,21H17A2,2 0 0,0 19,19V6H20V4H15V3H9M7,6H17V19H7V6M9,8V17H11V8H9M13,8V17H15V8H13Z" }))));
18
19
  };
19
- export const AndOrButton = ({ text }) => {
20
- return h("button", { class: { [AND_OR_BUTTON]: true, 'light revo-button': true } }, text);
20
+ export const AndOrButton = ({ text, onClick }) => {
21
+ return h("button", { type: "button", class: { [AND_OR_BUTTON]: true, 'light revo-button': true }, onClick: onClick }, text);
22
+ };
23
+ export const ReorderButton = ({ ariaLabel, dragging, dragOver, onDragStart, onDragEnd, onDragOver, onDragLeave, onDrop, onKeyDown, }) => {
24
+ return (h("button", { type: "button", class: {
25
+ [REORDER_BUTTON]: true,
26
+ 'filter-row-dragging': !!dragging,
27
+ 'filter-row-drag-over': !!dragOver,
28
+ }, draggable: true, title: ariaLabel, "aria-label": ariaLabel, onDragStart: onDragStart, onDragEnd: onDragEnd, onDragOver: onDragOver, onDragLeave: onDragLeave, onDrop: onDrop, onKeyDown: onKeyDown }, "::"));
21
29
  };
22
30
  export function isFilterBtn(e) {
23
31
  if (e.classList.contains(FILTER_BUTTON_CLASS)) {
@@ -4,12 +4,14 @@
4
4
  // filter.panel.tsx
5
5
  import { h, Host, } from "@stencil/core";
6
6
  import debounce from "lodash/debounce";
7
- import { AndOrButton, isFilterBtn, TrashButton } from "./filter.button";
7
+ import { AndOrButton, isFilterBtn, ReorderButton, TrashButton } from "./filter.button";
8
8
  import "../../utils/closest.polifill";
9
+ import { getFilterReorderId, moveFilterItem, setFilterReorderData, } from "./filter.reorder";
9
10
  const defaultType = 'none';
10
11
  const FILTER_LIST_CLASS = 'multi-filter-list';
11
12
  const FILTER_LIST_CLASS_ACTION = 'multi-filter-list-action';
12
13
  const FILTER_ID = 'add-filter';
14
+ const VIEWPORT_PADDING = 8;
13
15
  /**
14
16
  * Filter panel for editing filters
15
17
  */
@@ -29,6 +31,9 @@ export class FilterPanel {
29
31
  placeholder: 'Enter value...',
30
32
  and: 'and',
31
33
  or: 'or',
34
+ filterCondition: 'Filter condition',
35
+ removeFilter: 'Remove filter',
36
+ reorderFilter: 'Reorder filter',
32
37
  };
33
38
  this.isFilterIdSet = false;
34
39
  this.filterId = 0;
@@ -102,18 +107,28 @@ export class FilterPanel {
102
107
  if (typeof prop === 'undefined')
103
108
  return '';
104
109
  const propFilters = (_b = this.filterItems[prop]) !== null && _b !== void 0 ? _b : [];
105
- const capts = Object.assign(this.filterCaptionsInternal, this.filterCaptions);
106
- return (h("div", { key: this.filterId }, propFilters.map((filter, index) => {
110
+ const visibleFilterCount = propFilters.filter(filter => !filter.hidden).length;
111
+ const capts = Object.assign(Object.assign({}, this.filterCaptionsInternal), this.filterCaptions);
112
+ return (h("div", { key: this.filterId }, h("ul", { class: "multi-filter-list-container" }, propFilters.map((filter, index) => {
107
113
  let andOrButton;
108
114
  if (filter.hidden) {
109
115
  return;
110
116
  }
111
117
  // hide toggle button if there is only one filter and the last one
112
118
  if (index !== this.filterItems[prop].length - 1) {
113
- andOrButton = (h("div", { onClick: () => this.toggleFilterAndOr(filter.id) }, h(AndOrButton, { text: filter.relation === 'and' ? capts.and : capts.or })));
119
+ andOrButton = (h(AndOrButton, { text: filter.relation === 'and' ? capts.and : capts.or, onClick: () => this.toggleFilterAndOr(filter.id) }));
114
120
  }
115
- return (h("div", { key: filter.id, class: FILTER_LIST_CLASS }, 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)), h("div", { class: FILTER_LIST_CLASS_ACTION }, andOrButton), h("div", { onClick: () => this.onRemoveFilter(filter.id) }, h(TrashButton, null))), h("div", null, this.renderExtra(prop, index))));
116
- }), propFilters.filter(f => !f.hidden).length > 0 ? h("div", { class: "add-filter-divider" }) : ''));
121
+ const extra = this.renderExtra(prop, index);
122
+ const isDragging = this.draggedFilterId === filter.id;
123
+ const isDragOver = this.dragOverFilterId === filter.id && !isDragging;
124
+ const canReorder = visibleFilterCount > 1;
125
+ return (h("li", { key: filter.id, class: FILTER_LIST_CLASS, "aria-label": `${capts.filterCondition} ${index + 1}` }, h("div", { class: {
126
+ 'multi-filter-list-row': true,
127
+ 'filter-row-drop-active': this.draggedFilterId !== undefined && !isDragging,
128
+ 'filter-row-dragging': isDragging,
129
+ 'filter-row-drag-over': isDragOver,
130
+ } }, 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) })))));
131
+ })), propFilters.filter(f => !f.hidden).length > 0 ? h("div", { class: "add-filter-divider" }) : ''));
117
132
  }
118
133
  componentDidRender() {
119
134
  this.syncDialog();
@@ -132,37 +147,35 @@ export class FilterPanel {
132
147
  this.dialog.show();
133
148
  }
134
149
  if (this.changes.autoCorrect !== false) {
150
+ this.autoCorrect(this.dialog);
135
151
  requestAnimationFrame(() => this.autoCorrect(this.dialog));
136
152
  }
137
153
  }
138
154
  autoCorrect(el) {
139
- if (!el) {
155
+ var _a;
156
+ if (!el || !this.changes) {
140
157
  return;
141
158
  }
159
+ el.style.maxHeight = '';
160
+ el.style.left = `${this.changes.x}px`;
161
+ el.style.top = `${this.changes.y}px`;
142
162
  const pos = el.getBoundingClientRect();
143
- const maxLeft = Math.max(0, window.innerWidth - pos.width);
144
- const maxTop = Math.max(0, window.innerHeight - pos.height);
145
- if (pos.left > maxLeft) {
146
- el.style.left = `${maxLeft}px`;
147
- }
148
- if (pos.top > maxTop) {
149
- el.style.top = `${maxTop}px`;
150
- }
151
- }
152
- onDialogMouseDown(e) {
153
- if (!this.closeOnOutsideClick ||
154
- e.target !== this.dialog ||
155
- !this.dialog) {
156
- return;
157
- }
158
- const rect = this.dialog.getBoundingClientRect();
159
- const isInside = e.clientX >= rect.left &&
160
- e.clientX <= rect.right &&
161
- e.clientY >= rect.top &&
162
- e.clientY <= rect.bottom;
163
- if (!isInside) {
164
- this.onCancel();
165
- }
163
+ const anchorTop = (_a = this.changes.anchorY) !== null && _a !== void 0 ? _a : this.changes.y;
164
+ const anchorBottom = this.changes.y;
165
+ const spaceAbove = Math.max(0, anchorTop - VIEWPORT_PADDING);
166
+ const spaceBelow = Math.max(0, window.innerHeight - anchorBottom - VIEWPORT_PADDING);
167
+ const openAbove = pos.height > spaceBelow && spaceAbove > spaceBelow;
168
+ const availableHeight = Math.max(VIEWPORT_PADDING, openAbove ? spaceAbove : spaceBelow);
169
+ el.style.maxHeight = `${availableHeight}px`;
170
+ const adjustedPos = el.getBoundingClientRect();
171
+ const maxLeft = Math.max(VIEWPORT_PADDING, window.innerWidth - adjustedPos.width - VIEWPORT_PADDING);
172
+ const maxTop = Math.max(VIEWPORT_PADDING, window.innerHeight - adjustedPos.height - VIEWPORT_PADDING);
173
+ const left = Math.min(Math.max(VIEWPORT_PADDING, this.changes.x), maxLeft);
174
+ const top = openAbove
175
+ ? Math.min(Math.max(VIEWPORT_PADDING, anchorTop - adjustedPos.height), maxTop)
176
+ : Math.min(Math.max(VIEWPORT_PADDING, anchorBottom), maxTop);
177
+ el.style.left = `${left}px`;
178
+ el.style.top = `${top}px`;
166
179
  }
167
180
  onFilterTypeChange(e, prop, index) {
168
181
  if (!(e.target instanceof HTMLSelectElement)) {
@@ -254,6 +267,80 @@ export class FilterPanel {
254
267
  this.debouncedApplyFilter();
255
268
  }
256
269
  }
270
+ onFilterDragStart(e, id) {
271
+ this.draggedFilterId = id;
272
+ setFilterReorderData(e.dataTransfer, id);
273
+ }
274
+ onFilterDragOver(e, id) {
275
+ if (this.draggedFilterId === undefined || this.draggedFilterId === id) {
276
+ return;
277
+ }
278
+ e.preventDefault();
279
+ if (e.dataTransfer) {
280
+ e.dataTransfer.dropEffect = 'move';
281
+ }
282
+ this.dragOverFilterId = id;
283
+ }
284
+ onFilterDragLeave(id) {
285
+ if (this.dragOverFilterId === id) {
286
+ this.dragOverFilterId = undefined;
287
+ }
288
+ }
289
+ onFilterDrop(e, prop, targetId) {
290
+ var _a;
291
+ e.preventDefault();
292
+ const sourceId = (_a = this.draggedFilterId) !== null && _a !== void 0 ? _a : getFilterReorderId(e.dataTransfer);
293
+ this.onFilterDragEnd();
294
+ if (sourceId === undefined) {
295
+ return;
296
+ }
297
+ const items = this.filterItems[prop];
298
+ if (!items) {
299
+ return;
300
+ }
301
+ if (!moveFilterItem(items, sourceId, targetId)) {
302
+ return;
303
+ }
304
+ this.filterId++;
305
+ if (!this.disableDynamicFiltering) {
306
+ this.debouncedApplyFilter();
307
+ }
308
+ }
309
+ onFilterDragEnd() {
310
+ this.draggedFilterId = undefined;
311
+ this.dragOverFilterId = undefined;
312
+ }
313
+ onFilterReorderKeyDown(e, prop, sourceId) {
314
+ let direction = 0;
315
+ if (e.key === 'ArrowUp') {
316
+ direction = -1;
317
+ }
318
+ else if (e.key === 'ArrowDown') {
319
+ direction = 1;
320
+ }
321
+ else {
322
+ return;
323
+ }
324
+ const items = this.filterItems[prop];
325
+ if (!items) {
326
+ return;
327
+ }
328
+ const visibleItems = items.filter(item => !item.hidden);
329
+ const sourceIndex = visibleItems.findIndex(item => item.id === sourceId);
330
+ if (sourceIndex === -1) {
331
+ return;
332
+ }
333
+ e.preventDefault();
334
+ e.stopPropagation();
335
+ const target = visibleItems[sourceIndex + direction];
336
+ if (!target || !moveFilterItem(items, sourceId, target.id)) {
337
+ return;
338
+ }
339
+ this.filterId++;
340
+ if (!this.disableDynamicFiltering) {
341
+ this.debouncedApplyFilter();
342
+ }
343
+ }
257
344
  toggleFilterAndOr(id) {
258
345
  var _a;
259
346
  this.assertChanges();
@@ -292,7 +379,7 @@ export class FilterPanel {
292
379
  });
293
380
  });
294
381
  if (!isDefaultTypeRemoved) {
295
- const capts = Object.assign(this.filterCaptionsInternal, this.filterCaptions);
382
+ const capts = Object.assign(Object.assign({}, this.filterCaptionsInternal), this.filterCaptions);
296
383
  options.push(h("option", { selected: this.currentFilterType === defaultType, value: defaultType }, prop && this.filterItems[prop] && this.filterItems[prop].length > 0
297
384
  ? capts.add
298
385
  : this.filterNames[defaultType]));
@@ -325,7 +412,7 @@ export class FilterPanel {
325
412
  select.focus();
326
413
  }
327
414
  };
328
- const capts = Object.assign(this.filterCaptionsInternal, this.filterCaptions);
415
+ const capts = Object.assign(Object.assign({}, this.filterCaptionsInternal), this.filterCaptions);
329
416
  const extra = this.filterEntities[currentFilter[index].type].extra;
330
417
  if (typeof extra === 'function') {
331
418
  return extra(h, {
@@ -362,32 +449,33 @@ export class FilterPanel {
362
449
  } }));
363
450
  }
364
451
  render() {
365
- var _a, _b, _c, _d, _e, _f, _g;
452
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
366
453
  const style = {
367
454
  left: `${(_b = (_a = this.changes) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0}px`,
368
455
  top: `${(_d = (_c = this.changes) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : 0}px`,
369
456
  };
370
- const capts = Object.assign(this.filterCaptionsInternal, this.filterCaptions);
371
- return (h(Host, { key: '9fb424017d080876ff7796237917b4f41f617fe0' }, h("dialog", { key: '37b9f870b95f6fe1bd7be359dd7b77ef196e896e', class: "filter-panel-dialog", style: style, ref: el => (this.dialog = el), onCancel: e => {
457
+ const capts = Object.assign(Object.assign({}, this.filterCaptionsInternal), this.filterCaptions);
458
+ return (h(Host, { key: '4e969f8b7033363c885c94b1f7770917786669f2' }, h("dialog", { key: '79b2713724684fa99f56621fe43645a0b0ad54bf', class: "filter-panel-dialog", style: style, ref: el => (this.dialog = el), onCancel: e => {
372
459
  e.preventDefault();
373
460
  this.onCancel();
374
- }, onMouseDown: e => this.onDialogMouseDown(e) }, this.changes && [
375
- h("slot", { key: '76ec505a92d0a7c1ae0bbb5f4cac63555f3416be', slot: "header" }),
461
+ } }, this.changes && [
462
+ h("slot", { key: "header-slot", slot: "header" }),
376
463
  ((_f = (_e = this.changes).extraContent) === null || _f === void 0 ? void 0 : _f.call(_e, this.changes)) || '',
377
464
  ((_g = this.changes) === null || _g === void 0 ? void 0 : _g.hideDefaultFilters) !== true && [
378
- h("label", { key: 'c6fd82c95f6005f286c7bc90de34956128a83246' }, capts.title),
379
- h("div", { key: '5e7dac36ad79ba1b6072a0053b30aa384ade0dde', class: "filter-holder" }, this.getFilterItemsList()),
380
- h("div", { key: 'd9b6103edbd138d4db845745686ee4c847310a66', class: "add-filter" }, h("select", { key: 'c1b321f2d19458f95ab3f9188d83d94bebdb688e', id: FILTER_ID, class: "select-css", onChange: e => this.onAddNewFilter(e) }, this.renderSelectOptions(this.currentFilterType))),
465
+ h("label", { key: "filter-title" }, capts.title),
466
+ h("div", { key: "filter-holder", class: "filter-holder" }, this.getFilterItemsList()),
467
+ h("div", { key: "add-filter", class: "add-filter" }, h("select", { key: 'fc894bdfae1ff35d5c49adc7646dd3182b7bd49e', id: FILTER_ID, class: "select-css", onChange: e => this.onAddNewFilter(e) }, this.renderSelectOptions(this.currentFilterType))),
381
468
  ],
382
- h("slot", { key: '1571dcbc5c57651deb42a4046272ff60fa74f5a7' }),
383
- h("div", { key: '4aa7dee532336b084542df0209291b4c60378b49', class: "filter-actions" }, this.disableDynamicFiltering && [
384
- h("button", { key: '4c1b3054cd1bb7f46877592f00f6634d0f7ecafa', id: "revo-button-save", "aria-label": "save", class: "revo-button green", onClick: () => this.onSave() }, capts.save),
385
- h("button", { key: 'f31a568c89be18b1a854cdd7d4726e01db24e338', id: "revo-button-ok", "aria-label": "ok", class: "revo-button green", onClick: () => this.onCancel() }, capts.cancel),
469
+ h("slot", { key: "default-slot" }),
470
+ ((_j = (_h = this.changes).extraBottomContent) === null || _j === void 0 ? void 0 : _j.call(_h, this.changes)) || '',
471
+ h("div", { key: "filter-actions", class: "filter-actions" }, this.disableDynamicFiltering && [
472
+ h("button", { key: "save", id: "revo-button-save", "aria-label": "save", class: "revo-button green", onClick: () => this.onSave() }, capts.save),
473
+ h("button", { key: "cancel", id: "revo-button-ok", "aria-label": "ok", class: "revo-button green", onClick: () => this.onCancel() }, capts.cancel),
386
474
  ], !this.disableDynamicFiltering && [
387
- h("button", { key: '5d40e8b1f13f94cff4f5a2e2aefeee8861104a9d', id: "revo-button-ok", "aria-label": "ok", class: "revo-button green", onClick: () => this.onCancel() }, capts.ok),
388
- h("button", { key: '67eac3abd16f6f6e2ed7089dcfb0d05524ddb7df', id: "revo-button-reset", "aria-label": "reset", class: "revo-button outline", onClick: () => this.onReset() }, capts.reset),
475
+ h("button", { key: "ok", id: "revo-button-ok", "aria-label": "ok", class: "revo-button green", onClick: () => this.onCancel() }, capts.ok),
476
+ h("button", { key: "reset", id: "revo-button-reset", "aria-label": "reset", class: "revo-button outline", onClick: () => this.onReset() }, capts.reset),
389
477
  ]),
390
- h("slot", { key: 'b27a9bb3ef814e1e09dca14eda3e332ff34c654c', slot: "footer" }),
478
+ h("slot", { key: "footer-slot", slot: "footer" }),
391
479
  ])));
392
480
  }
393
481
  static get is() { return "revogr-filter-panel"; }
@@ -532,7 +620,9 @@ export class FilterPanel {
532
620
  "currentFilterId": {},
533
621
  "currentFilterType": {},
534
622
  "changes": {},
535
- "filterItems": {}
623
+ "filterItems": {},
624
+ "draggedFilterId": {},
625
+ "dragOverFilterId": {}
536
626
  };
537
627
  }
538
628
  static get events() {
@@ -194,7 +194,7 @@ export class FilterPlugin extends BasePlugin {
194
194
  }
195
195
  // filter button clicked, open filter dialog
196
196
  const buttonPos = (filterButton instanceof HTMLElement ? filterButton : el).getBoundingClientRect();
197
- const data = Object.assign(Object.assign(Object.assign({}, e.detail), this.filterCollection[prop]), { x: buttonPos.x, y: buttonPos.y + buttonPos.height, autoCorrect: true, filterTypes: this.getColumnFilter(e.detail.filter), filterItems: this.multiFilterItems, extraContent: this.extraHyperContent });
197
+ const data = Object.assign(Object.assign(Object.assign({}, e.detail), this.filterCollection[prop]), { x: buttonPos.x, y: buttonPos.y + buttonPos.height, anchorY: buttonPos.y, autoCorrect: true, filterTypes: this.getColumnFilter(e.detail.filter), filterItems: this.multiFilterItems, extraContent: this.extraHyperContent, extraBottomContent: this.extraBottomHyperContent });
198
198
  (_b = this.beforeshow) === null || _b === void 0 ? void 0 : _b.call(this, data);
199
199
  this.pop.show(data);
200
200
  }
@@ -0,0 +1,44 @@
1
+ /*!
2
+ * Built by Revolist OU ❤️
3
+ */
4
+ const FILTER_REORDER_MIME = 'text/revogrid-filter-id';
5
+ export function setFilterReorderData(dataTransfer, id) {
6
+ if (!dataTransfer) {
7
+ return;
8
+ }
9
+ dataTransfer.effectAllowed = 'move';
10
+ dataTransfer.setData(FILTER_REORDER_MIME, String(id));
11
+ dataTransfer.setData('text/plain', String(id));
12
+ }
13
+ export function getFilterReorderId(dataTransfer) {
14
+ if (!dataTransfer) {
15
+ return;
16
+ }
17
+ const rawId = dataTransfer.getData(FILTER_REORDER_MIME) || dataTransfer.getData('text/plain');
18
+ const normalizedId = rawId.trim();
19
+ if (!normalizedId) {
20
+ return;
21
+ }
22
+ const id = Number(normalizedId);
23
+ return Number.isFinite(id) ? id : undefined;
24
+ }
25
+ export function moveFilterItem(items, sourceId, targetId) {
26
+ if (sourceId === targetId) {
27
+ return false;
28
+ }
29
+ const sourceIndex = items.findIndex(item => item.id === sourceId);
30
+ const targetIndex = items.findIndex(item => item.id === targetId);
31
+ if (sourceIndex === -1 || targetIndex === -1 || sourceIndex === targetIndex) {
32
+ return false;
33
+ }
34
+ const relationsByPosition = items.map(item => { var _a; return (_a = item.relation) !== null && _a !== void 0 ? _a : 'and'; });
35
+ const [movedItem] = items.splice(sourceIndex, 1);
36
+ items.splice(targetIndex, 0, movedItem);
37
+ items.forEach((item, index) => {
38
+ var _a;
39
+ item.relation = index === items.length - 1
40
+ ? 'and'
41
+ : (_a = relationsByPosition[index]) !== null && _a !== void 0 ? _a : 'and';
42
+ });
43
+ return true;
44
+ }
@@ -52,6 +52,7 @@ revogr-filter-panel .filter-panel-dialog {
52
52
  border: 1px solid var(--revo-grid-filter-panel-border, #cecece);
53
53
  transform-origin: 62px 0px;
54
54
  box-shadow: 0 5px 18px -2px var(--revo-grid-filter-panel-shadow, rgba(0, 0, 0, 0.15));
55
+ box-sizing: border-box;
55
56
  padding: 10px;
56
57
  border-radius: 8px;
57
58
  margin: 0;
@@ -59,9 +60,6 @@ revogr-filter-panel .filter-panel-dialog {
59
60
  text-align: left;
60
61
  animation: revogr-filter-panel-open 140ms cubic-bezier(0.2, 0, 0, 1);
61
62
  }
62
- revogr-filter-panel .filter-panel-dialog::backdrop {
63
- background: transparent;
64
- }
65
63
  revogr-filter-panel .filter-panel-dialog .filter-holder > div {
66
64
  display: flex;
67
65
  flex-direction: column;
@@ -85,8 +83,16 @@ revogr-filter-panel .filter-panel-dialog input[type=text] {
85
83
  width: 100%;
86
84
  }
87
85
  revogr-filter-panel .filter-panel-dialog .filter-actions {
86
+ position: sticky;
87
+ right: 0;
88
+ bottom: -10px;
89
+ left: 0;
90
+ z-index: 1;
88
91
  text-align: right;
89
- margin-right: -5px;
92
+ margin: 10px -10px -10px;
93
+ padding: 0 5px 10px 10px;
94
+ background: var(--revo-grid-filter-panel-bg, #fff);
95
+ border-top: 1px solid var(--revo-grid-filter-panel-divider, #d9d9d9);
90
96
  }
91
97
  revogr-filter-panel .filter-panel-dialog .filter-actions button {
92
98
  margin-top: 10px;
@@ -189,9 +195,44 @@ revogr-filter-panel .filter-panel-dialog .filter-actions button {
189
195
  .multi-filter-list div {
190
196
  white-space: nowrap;
191
197
  }
198
+ .multi-filter-list .multi-filter-list-row {
199
+ display: flex;
200
+ align-items: center;
201
+ gap: 6px;
202
+ position: relative;
203
+ }
204
+ .multi-filter-list .multi-filter-list-row.filter-row-dragging {
205
+ opacity: 0.65;
206
+ }
207
+ .multi-filter-list .multi-filter-list-row.filter-row-drag-over::before {
208
+ content: "";
209
+ position: absolute;
210
+ top: -4px;
211
+ right: 0;
212
+ left: 0;
213
+ z-index: 2;
214
+ height: 2px;
215
+ background: var(--revo-grid-filter-panel-reorder-accent, #007cb2);
216
+ border-radius: 999px;
217
+ box-shadow: 0 0 0 2px var(--revo-grid-filter-panel-bg, #fff);
218
+ }
219
+ .multi-filter-list .multi-filter-list-row.filter-row-drop-active .filter-row-drop-target {
220
+ pointer-events: auto;
221
+ }
222
+ .multi-filter-list .filter-row-drop-target {
223
+ position: absolute;
224
+ inset: 0;
225
+ z-index: 1;
226
+ padding: 0;
227
+ pointer-events: none;
228
+ background: transparent;
229
+ border: 0;
230
+ }
192
231
  .multi-filter-list .multi-filter-list-action {
193
232
  display: flex;
194
- justify-content: space-between;
233
+ align-self: stretch;
234
+ flex: 0 0 auto;
235
+ justify-content: flex-end;
195
236
  align-items: center;
196
237
  }
197
238
  .multi-filter-list .and-or-button {
@@ -201,6 +242,10 @@ revogr-filter-panel .filter-panel-dialog .filter-actions button {
201
242
  }
202
243
  .multi-filter-list .trash-button {
203
244
  margin: 0 0 -2px 6px;
245
+ padding: 0;
246
+ border: 0;
247
+ background: transparent;
248
+ color: inherit;
204
249
  cursor: pointer;
205
250
  width: 22px;
206
251
  height: 100%;
@@ -209,6 +254,31 @@ revogr-filter-panel .filter-panel-dialog .filter-actions button {
209
254
  .multi-filter-list .trash-button .trash-img {
210
255
  width: 1em;
211
256
  }
257
+ .multi-filter-list .reorder-button {
258
+ border: 0;
259
+ background: transparent;
260
+ color: var(--revo-grid-filter-panel-reorder-color, #6b7280);
261
+ cursor: grab;
262
+ font-family: monospace;
263
+ font-size: 12px;
264
+ letter-spacing: 0;
265
+ line-height: 1;
266
+ padding: 6px 2px;
267
+ transform: scaleX(0.8);
268
+ width: 16px;
269
+ }
270
+ .multi-filter-list .reorder-button.filter-row-drag-over {
271
+ color: var(--revo-grid-filter-panel-reorder-accent, #007cb2);
272
+ }
273
+ .multi-filter-list .reorder-button:active {
274
+ cursor: grabbing;
275
+ }
276
+
277
+ .multi-filter-list-container {
278
+ padding: 0;
279
+ margin: 0;
280
+ list-style: none;
281
+ }
212
282
 
213
283
  .add-filter-divider {
214
284
  display: block;
@@ -219,6 +289,26 @@ revogr-filter-panel .filter-panel-dialog .filter-actions button {
219
289
 
220
290
  .select-input {
221
291
  display: flex;
222
- justify-content: space-between;
223
292
  align-items: center;
293
+ flex: 1 1 auto;
294
+ gap: 6px;
295
+ min-width: 0;
296
+ }
297
+ .select-input .select-filter,
298
+ .select-input .filter-extra {
299
+ flex: 1 1 0;
300
+ min-width: 0;
301
+ }
302
+ .select-input .select-filter {
303
+ width: auto;
304
+ }
305
+ .select-input .filter-extra {
306
+ display: flex;
307
+ }
308
+ .select-input .filter-extra > * {
309
+ width: 100%;
310
+ }
311
+ .select-input input[type=text],
312
+ .select-input input[type=date] {
313
+ margin: 0;
224
314
  }
@@ -21,12 +21,17 @@ export const GroupingRowRenderer = (props) => {
21
21
  const name = model[PSEUDO_GROUP_ITEM];
22
22
  const expanded = model[GROUP_EXPANDED];
23
23
  const depth = parseInt(model[GROUP_DEPTH], 10) || 0;
24
+ const groupRowAttrs = {
25
+ rowClass: 'groupingRow',
26
+ depth,
27
+ expanded,
28
+ };
24
29
  if (groupingCustomRenderer) {
25
- return (h(RowRenderer, Object.assign({}, props, { rowClass: "groupingRow", depth: depth }), h("div", { onClick: e => expandEvent(e, model, itemIndex) }, groupingCustomRenderer(h, Object.assign(Object.assign({}, props), { colType: props.providers.colType, name,
30
+ return (h(RowRenderer, Object.assign({}, props, groupRowAttrs), h("div", { onClick: e => expandEvent(e, model, itemIndex) }, groupingCustomRenderer(h, Object.assign(Object.assign({}, props), { colType: props.providers.colType, name,
26
31
  expanded,
27
32
  depth })))));
28
33
  }
29
- return (h(RowRenderer, Object.assign({}, props, { rowClass: "groupingRow", depth: depth }), hasExpand && [
34
+ return (h(RowRenderer, Object.assign({}, props, groupRowAttrs), hasExpand && [
30
35
  h("button", { class: { [GROUP_EXPAND_BTN]: true }, onClick: e => expandEvent(e, model, itemIndex) }, expandSvgIconVNode(expanded)),
31
36
  name,
32
37
  ]));