@alaarab/ogrid-js 2.1.2 → 2.1.4

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 (35) hide show
  1. package/dist/esm/index.js +6343 -32
  2. package/package.json +7 -5
  3. package/dist/esm/OGrid.js +0 -578
  4. package/dist/esm/OGridEventWiring.js +0 -178
  5. package/dist/esm/OGridRendering.js +0 -269
  6. package/dist/esm/components/ColumnChooser.js +0 -91
  7. package/dist/esm/components/ContextMenu.js +0 -125
  8. package/dist/esm/components/HeaderFilter.js +0 -281
  9. package/dist/esm/components/InlineCellEditor.js +0 -434
  10. package/dist/esm/components/MarchingAntsOverlay.js +0 -156
  11. package/dist/esm/components/PaginationControls.js +0 -85
  12. package/dist/esm/components/SideBar.js +0 -353
  13. package/dist/esm/components/StatusBar.js +0 -34
  14. package/dist/esm/renderer/TableRenderer.js +0 -846
  15. package/dist/esm/state/ClipboardState.js +0 -111
  16. package/dist/esm/state/ColumnPinningState.js +0 -82
  17. package/dist/esm/state/ColumnReorderState.js +0 -135
  18. package/dist/esm/state/ColumnResizeState.js +0 -55
  19. package/dist/esm/state/EventEmitter.js +0 -28
  20. package/dist/esm/state/FillHandleState.js +0 -206
  21. package/dist/esm/state/GridState.js +0 -324
  22. package/dist/esm/state/HeaderFilterState.js +0 -213
  23. package/dist/esm/state/KeyboardNavState.js +0 -216
  24. package/dist/esm/state/RowSelectionState.js +0 -72
  25. package/dist/esm/state/SelectionState.js +0 -109
  26. package/dist/esm/state/SideBarState.js +0 -41
  27. package/dist/esm/state/TableLayoutState.js +0 -97
  28. package/dist/esm/state/UndoRedoState.js +0 -71
  29. package/dist/esm/state/VirtualScrollState.js +0 -128
  30. package/dist/esm/types/columnTypes.js +0 -1
  31. package/dist/esm/types/gridTypes.js +0 -1
  32. package/dist/esm/types/index.js +0 -2
  33. package/dist/esm/utils/debounce.js +0 -2
  34. package/dist/esm/utils/getCellCoordinates.js +0 -15
  35. package/dist/esm/utils/index.js +0 -2
@@ -1,281 +0,0 @@
1
- /**
2
- * Renders header filter popover (dropdown) in DOM.
3
- * Instantiated by OGrid, reads state from HeaderFilterState.
4
- */
5
- export class HeaderFilter {
6
- constructor(state) {
7
- this.popoverEl = null;
8
- this.state = state;
9
- }
10
- /**
11
- * Render the popover for the currently open filter.
12
- * Call this whenever HeaderFilterState changes.
13
- */
14
- render(config) {
15
- this.cleanup();
16
- if (!config || !this.state.openColumnId || !this.state.popoverPosition)
17
- return;
18
- const pos = this.state.popoverPosition;
19
- this.popoverEl = document.createElement('div');
20
- this.popoverEl.className = 'ogrid-header-filter-popover';
21
- this.popoverEl.style.position = 'fixed';
22
- this.popoverEl.style.top = `${pos.top}px`;
23
- this.popoverEl.style.left = `${pos.left}px`;
24
- this.popoverEl.style.zIndex = '9999';
25
- this.popoverEl.style.background = 'var(--ogrid-bg, #fff)';
26
- this.popoverEl.style.color = 'var(--ogrid-fg, #242424)';
27
- this.popoverEl.style.border = '1px solid var(--ogrid-border, #e0e0e0)';
28
- this.popoverEl.style.borderRadius = '4px';
29
- this.popoverEl.style.boxShadow = 'var(--ogrid-shadow, 0 2px 8px rgba(0,0,0,0.15))';
30
- this.popoverEl.style.padding = '8px';
31
- this.popoverEl.style.minWidth = '200px';
32
- this.popoverEl.style.maxHeight = '320px';
33
- this.popoverEl.style.overflowY = 'auto';
34
- // Stop clicks within popover from propagating
35
- this.popoverEl.addEventListener('click', (e) => e.stopPropagation());
36
- this.popoverEl.addEventListener('mousedown', (e) => e.stopPropagation());
37
- if (config.filterType === 'text') {
38
- this.renderTextFilter(config);
39
- }
40
- else if (config.filterType === 'multiSelect') {
41
- this.renderMultiSelectFilter(config);
42
- }
43
- else if (config.filterType === 'date') {
44
- this.renderDateFilter(config);
45
- }
46
- document.body.appendChild(this.popoverEl);
47
- }
48
- renderTextFilter(config) {
49
- if (!this.popoverEl)
50
- return;
51
- const input = document.createElement('input');
52
- input.type = 'text';
53
- input.value = this.state.tempTextValue;
54
- input.placeholder = 'Filter...';
55
- input.setAttribute('aria-label', 'Text filter');
56
- input.className = 'ogrid-filter-text-input';
57
- this.applyInputStyle(input);
58
- input.style.marginBottom = '8px';
59
- input.addEventListener('input', () => {
60
- this.state.setTempTextValue(input.value);
61
- });
62
- input.addEventListener('keydown', (e) => {
63
- if (e.key === 'Enter') {
64
- this.state.applyTextFilter(config.filterField);
65
- }
66
- e.stopPropagation();
67
- });
68
- this.popoverEl.appendChild(input);
69
- // Buttons
70
- const btnRow = document.createElement('div');
71
- btnRow.style.display = 'flex';
72
- btnRow.style.gap = '8px';
73
- const applyBtn = document.createElement('button');
74
- applyBtn.textContent = 'Apply';
75
- applyBtn.className = 'ogrid-filter-apply-btn';
76
- this.applyButtonStyle(applyBtn);
77
- applyBtn.addEventListener('click', () => this.state.applyTextFilter(config.filterField));
78
- btnRow.appendChild(applyBtn);
79
- const clearBtn = document.createElement('button');
80
- clearBtn.textContent = 'Clear';
81
- clearBtn.className = 'ogrid-filter-clear-btn';
82
- this.applyButtonStyle(clearBtn);
83
- clearBtn.addEventListener('click', () => this.state.clearTextFilter(config.filterField));
84
- btnRow.appendChild(clearBtn);
85
- this.popoverEl.appendChild(btnRow);
86
- // Focus input
87
- setTimeout(() => input.focus(), 0);
88
- }
89
- renderMultiSelectFilter(config) {
90
- if (!this.popoverEl)
91
- return;
92
- // Search box
93
- const searchInput = document.createElement('input');
94
- searchInput.type = 'text';
95
- searchInput.value = this.state.searchText;
96
- searchInput.placeholder = 'Search...';
97
- searchInput.setAttribute('aria-label', 'Search filter options');
98
- searchInput.className = 'ogrid-filter-search-input';
99
- this.applyInputStyle(searchInput);
100
- searchInput.style.marginBottom = '8px';
101
- searchInput.addEventListener('input', () => {
102
- this.state.setSearchText(searchInput.value);
103
- this.updateCheckboxList(config, checkboxContainer);
104
- });
105
- searchInput.addEventListener('keydown', (e) => e.stopPropagation());
106
- this.popoverEl.appendChild(searchInput);
107
- // Select all / Clear all buttons
108
- const actionRow = document.createElement('div');
109
- actionRow.style.display = 'flex';
110
- actionRow.style.gap = '8px';
111
- actionRow.style.marginBottom = '8px';
112
- const selectAllBtn = document.createElement('button');
113
- selectAllBtn.textContent = 'Select All';
114
- selectAllBtn.className = 'ogrid-filter-select-all-btn';
115
- this.applySmallButtonStyle(selectAllBtn);
116
- selectAllBtn.addEventListener('click', () => {
117
- this.state.handleSelectAll(config.filterField);
118
- this.updateCheckboxList(config, checkboxContainer);
119
- });
120
- actionRow.appendChild(selectAllBtn);
121
- const clearSelBtn = document.createElement('button');
122
- clearSelBtn.textContent = 'Clear';
123
- clearSelBtn.className = 'ogrid-filter-clear-sel-btn';
124
- this.applySmallButtonStyle(clearSelBtn);
125
- clearSelBtn.addEventListener('click', () => {
126
- this.state.handleClearSelection();
127
- this.updateCheckboxList(config, checkboxContainer);
128
- });
129
- actionRow.appendChild(clearSelBtn);
130
- this.popoverEl.appendChild(actionRow);
131
- // Checkbox list container
132
- const checkboxContainer = document.createElement('div');
133
- checkboxContainer.className = 'ogrid-filter-checkbox-list';
134
- checkboxContainer.style.maxHeight = '160px';
135
- checkboxContainer.style.overflowY = 'auto';
136
- checkboxContainer.style.marginBottom = '8px';
137
- checkboxContainer.setAttribute('role', 'group');
138
- checkboxContainer.setAttribute('aria-label', 'Filter options');
139
- this.updateCheckboxList(config, checkboxContainer);
140
- this.popoverEl.appendChild(checkboxContainer);
141
- // Apply button
142
- const applyBtn = document.createElement('button');
143
- applyBtn.textContent = 'Apply';
144
- applyBtn.className = 'ogrid-filter-apply-btn';
145
- this.applyButtonStyle(applyBtn);
146
- applyBtn.addEventListener('click', () => this.state.applyMultiSelectFilter(config.filterField));
147
- this.popoverEl.appendChild(applyBtn);
148
- }
149
- updateCheckboxList(config, container) {
150
- container.innerHTML = '';
151
- const options = this.state.getFilteredOptions(config.filterField);
152
- const selected = this.state.tempSelected;
153
- for (const opt of options) {
154
- const label = document.createElement('label');
155
- label.style.display = 'flex';
156
- label.style.alignItems = 'center';
157
- label.style.gap = '4px';
158
- label.style.padding = '2px 0';
159
- label.style.cursor = 'pointer';
160
- label.style.fontSize = '13px';
161
- const checkbox = document.createElement('input');
162
- checkbox.type = 'checkbox';
163
- checkbox.checked = selected.has(opt);
164
- checkbox.addEventListener('change', () => {
165
- this.state.handleCheckboxChange(opt, checkbox.checked);
166
- });
167
- const text = document.createElement('span');
168
- text.textContent = opt;
169
- label.appendChild(checkbox);
170
- label.appendChild(text);
171
- container.appendChild(label);
172
- }
173
- if (options.length === 0) {
174
- const empty = document.createElement('div');
175
- empty.style.color = 'var(--ogrid-muted, #999)';
176
- empty.style.fontStyle = 'italic';
177
- empty.style.padding = '4px 0';
178
- empty.textContent = 'No options';
179
- container.appendChild(empty);
180
- }
181
- }
182
- renderDateFilter(config) {
183
- if (!this.popoverEl)
184
- return;
185
- const container = document.createElement('div');
186
- container.style.display = 'flex';
187
- container.style.flexDirection = 'column';
188
- container.style.gap = '8px';
189
- // From date
190
- const fromLabel = document.createElement('label');
191
- fromLabel.style.display = 'flex';
192
- fromLabel.style.alignItems = 'center';
193
- fromLabel.style.gap = '4px';
194
- fromLabel.style.fontSize = '13px';
195
- fromLabel.textContent = 'From: ';
196
- const fromInput = document.createElement('input');
197
- fromInput.type = 'date';
198
- fromInput.value = this.state.tempDateFrom;
199
- fromInput.setAttribute('aria-label', 'From date');
200
- this.applyInputStyle(fromInput);
201
- fromInput.addEventListener('change', () => {
202
- this.state.setTempDateFrom(fromInput.value);
203
- });
204
- fromInput.addEventListener('keydown', (e) => e.stopPropagation());
205
- fromLabel.appendChild(fromInput);
206
- container.appendChild(fromLabel);
207
- // To date
208
- const toLabel = document.createElement('label');
209
- toLabel.style.display = 'flex';
210
- toLabel.style.alignItems = 'center';
211
- toLabel.style.gap = '4px';
212
- toLabel.style.fontSize = '13px';
213
- toLabel.textContent = 'To: ';
214
- const toInput = document.createElement('input');
215
- toInput.type = 'date';
216
- toInput.value = this.state.tempDateTo;
217
- toInput.setAttribute('aria-label', 'To date');
218
- this.applyInputStyle(toInput);
219
- toInput.addEventListener('change', () => {
220
- this.state.setTempDateTo(toInput.value);
221
- });
222
- toInput.addEventListener('keydown', (e) => e.stopPropagation());
223
- toLabel.appendChild(toInput);
224
- container.appendChild(toLabel);
225
- this.popoverEl.appendChild(container);
226
- // Buttons
227
- const btnRow = document.createElement('div');
228
- btnRow.style.display = 'flex';
229
- btnRow.style.gap = '8px';
230
- btnRow.style.marginTop = '8px';
231
- const applyBtn = document.createElement('button');
232
- applyBtn.textContent = 'Apply';
233
- applyBtn.className = 'ogrid-filter-apply-btn';
234
- this.applyButtonStyle(applyBtn);
235
- applyBtn.addEventListener('click', () => this.state.applyDateFilter(config.filterField));
236
- btnRow.appendChild(applyBtn);
237
- const clearBtn = document.createElement('button');
238
- clearBtn.textContent = 'Clear';
239
- clearBtn.className = 'ogrid-filter-clear-btn';
240
- this.applyButtonStyle(clearBtn);
241
- clearBtn.addEventListener('click', () => this.state.clearDateFilter(config.filterField));
242
- btnRow.appendChild(clearBtn);
243
- this.popoverEl.appendChild(btnRow);
244
- }
245
- applyInputStyle(input) {
246
- input.style.width = '100%';
247
- input.style.boxSizing = 'border-box';
248
- input.style.padding = '4px 6px';
249
- input.style.background = 'var(--ogrid-bg, #fff)';
250
- input.style.color = 'var(--ogrid-fg, #242424)';
251
- input.style.border = '1px solid var(--ogrid-border, #e0e0e0)';
252
- input.style.borderRadius = '4px';
253
- }
254
- applyButtonStyle(btn) {
255
- btn.style.flex = '1';
256
- btn.style.cursor = 'pointer';
257
- btn.style.padding = '6px 12px';
258
- btn.style.background = 'var(--ogrid-bg-subtle, #f3f2f1)';
259
- btn.style.color = 'var(--ogrid-fg, #242424)';
260
- btn.style.border = '1px solid var(--ogrid-border, #e0e0e0)';
261
- btn.style.borderRadius = '4px';
262
- }
263
- applySmallButtonStyle(btn) {
264
- btn.style.cursor = 'pointer';
265
- btn.style.padding = '2px 8px';
266
- btn.style.fontSize = '12px';
267
- btn.style.background = 'transparent';
268
- btn.style.color = 'var(--ogrid-fg, #242424)';
269
- btn.style.border = '1px solid var(--ogrid-border, #e0e0e0)';
270
- btn.style.borderRadius = '4px';
271
- }
272
- cleanup() {
273
- if (this.popoverEl) {
274
- this.popoverEl.remove();
275
- this.popoverEl = null;
276
- }
277
- }
278
- destroy() {
279
- this.cleanup();
280
- }
281
- }