@genesislcap/grid-pro 15.72.0 → 15.73.0-FUI-2628.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.
- package/dist/custom-elements.json +145 -0
- package/dist/dts/context-menu/context-menu.d.ts +69 -0
- package/dist/dts/context-menu/context-menu.d.ts.map +1 -0
- package/dist/dts/context-menu/index.d.ts +2 -0
- package/dist/dts/context-menu/index.d.ts.map +1 -0
- package/dist/dts/grid-pro.d.ts +39 -2
- package/dist/dts/grid-pro.d.ts.map +1 -1
- package/dist/dts/index.d.ts +1 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/esm/context-menu/context-menu.js +379 -0
- package/dist/esm/context-menu/index.js +1 -0
- package/dist/esm/grid-pro.js +81 -3
- package/dist/esm/index.js +1 -0
- package/dist/grid-pro.api.json +401 -1
- package/dist/grid-pro.d.ts +80 -3
- package/package.json +12 -12
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { css, DOM } from '@microsoft/fast-element';
|
|
2
|
+
import { logger } from '../utils/logger';
|
|
3
|
+
/**
|
|
4
|
+
* Same surface as the vertical actions menu: AG Grid's context-menu variables, with design-system
|
|
5
|
+
* tokens when those variables are not set. The menu is drawn in the top layer, outside the themed
|
|
6
|
+
* grid element, so the values are copied from the cell that was clicked.
|
|
7
|
+
*/
|
|
8
|
+
const contextMenuStyles = css `
|
|
9
|
+
:host {
|
|
10
|
+
display: block;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
:host > .grid-context-menu,
|
|
14
|
+
.grid-context-menu-item > .grid-context-menu {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: var(--ag-spacing, 4px) 0;
|
|
20
|
+
max-width: 368px;
|
|
21
|
+
min-width: 64px;
|
|
22
|
+
background-color: var(--ag-menu-background-color, var(--fill-color));
|
|
23
|
+
border: var(
|
|
24
|
+
--ag-menu-border,
|
|
25
|
+
calc(var(--stroke-width, 1) * 1px) solid var(--neutral-stroke-rest, transparent)
|
|
26
|
+
);
|
|
27
|
+
border-radius: var(--ag-border-radius, calc(var(--control-corner-radius, 2) * 1px));
|
|
28
|
+
box-shadow: var(--ag-menu-shadow, var(--ag-popup-shadow, 0 2px 8px rgb(0 0 0 / 30%)));
|
|
29
|
+
color: var(--ag-menu-text-color, var(--neutral-foreground-rest));
|
|
30
|
+
font-family: var(--ag-font-family, var(--body-font));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.grid-context-menu > .grid-context-menu-item {
|
|
34
|
+
display: flex;
|
|
35
|
+
box-sizing: border-box;
|
|
36
|
+
align-items: center;
|
|
37
|
+
height: calc(var(--ag-icon-size, 16px) + (var(--ag-spacing, 4px) + 2px) * 2);
|
|
38
|
+
margin: 0;
|
|
39
|
+
background: transparent;
|
|
40
|
+
border: none;
|
|
41
|
+
border-radius: 0;
|
|
42
|
+
color: inherit;
|
|
43
|
+
font-family: inherit;
|
|
44
|
+
font-size: var(--ag-font-size, var(--type-ramp-base-font-size));
|
|
45
|
+
font-weight: 500;
|
|
46
|
+
user-select: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.grid-context-menu > .grid-context-menu-separator {
|
|
50
|
+
margin: var(--ag-spacing, 4px) 0;
|
|
51
|
+
border-top: var(
|
|
52
|
+
--ag-menu-border,
|
|
53
|
+
calc(var(--stroke-width, 1) * 1px) solid var(--neutral-stroke-rest, currentColor)
|
|
54
|
+
);
|
|
55
|
+
opacity: 50%;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.grid-context-menu > .grid-context-menu-item:hover,
|
|
59
|
+
.grid-context-menu > .grid-context-menu-item:focus {
|
|
60
|
+
background: var(--ag-row-hover-color, var(--neutral-fill-stealth-hover));
|
|
61
|
+
border: none;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.grid-context-menu > .grid-context-menu-item[disabled] {
|
|
65
|
+
background: transparent;
|
|
66
|
+
cursor: default;
|
|
67
|
+
opacity: 50%;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.grid-context-menu > .grid-context-menu-item::part(content) {
|
|
71
|
+
flex: 1;
|
|
72
|
+
margin-inline: 0;
|
|
73
|
+
padding-inline: calc(var(--ag-spacing, 4px) * 2) calc(var(--ag-spacing, 4px) * 4);
|
|
74
|
+
line-height: var(--ag-icon-size, 16px);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* A plain item in a menu with checkboxes lines its text up with theirs. */
|
|
78
|
+
.grid-context-menu
|
|
79
|
+
> .grid-context-menu-item.indent-1:not([role='menuitemcheckbox'])::part(content) {
|
|
80
|
+
padding-inline-start: calc(var(--ag-spacing, 4px) * 4 + var(--ag-icon-size, 16px));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.grid-context-menu > .grid-context-menu-item::part(end) {
|
|
84
|
+
padding-inline-end: calc(var(--ag-spacing, 4px) * 2);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.grid-context-menu > .grid-context-menu-item [slot='end'] {
|
|
88
|
+
white-space: nowrap;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* The menu item's own boxed, accent-filled checkbox and wide chevron, reduced to AG Grid's
|
|
92
|
+
icon column: a bare tick and a small arrow at the grid's icon size. */
|
|
93
|
+
.grid-context-menu > .grid-context-menu-item::part(input-container) {
|
|
94
|
+
margin: 0;
|
|
95
|
+
padding-inline-start: calc(var(--ag-spacing, 4px) * 2);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.grid-context-menu > .grid-context-menu-item::part(checkbox),
|
|
99
|
+
.grid-context-menu > .grid-context-menu-item[aria-checked='true']::part(checkbox) {
|
|
100
|
+
width: var(--ag-icon-size, 16px);
|
|
101
|
+
height: var(--ag-icon-size, 16px);
|
|
102
|
+
margin: 0;
|
|
103
|
+
background: transparent;
|
|
104
|
+
border: none;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.grid-context-menu > .grid-context-menu-item::part(expand-collapse-glyph-container) {
|
|
108
|
+
margin: 0;
|
|
109
|
+
padding-inline-end: calc(var(--ag-spacing, 4px) * 2);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.grid-context-menu > .grid-context-menu-item::part(expand-collapse) {
|
|
113
|
+
width: var(--ag-icon-size, 16px);
|
|
114
|
+
height: var(--ag-icon-size, 16px);
|
|
115
|
+
margin: 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.grid-context-menu-icon {
|
|
119
|
+
display: inline-flex;
|
|
120
|
+
align-items: center;
|
|
121
|
+
justify-content: center;
|
|
122
|
+
width: var(--ag-icon-size, 16px);
|
|
123
|
+
height: var(--ag-icon-size, 16px);
|
|
124
|
+
font-size: var(--ag-icon-size, 16px);
|
|
125
|
+
color: inherit;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* Font Awesome's chevron fills its box; the check does not, so the arrow is drawn smaller. */
|
|
129
|
+
.grid-context-menu-icon.chevron {
|
|
130
|
+
font-size: calc(var(--ag-icon-size, 16px) * 0.75);
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
133
|
+
/** The design-system icon (`${prefix}-icon`), which draws Font Awesome. */
|
|
134
|
+
function menuIcon(prefix, slot, name, variant) {
|
|
135
|
+
const icon = document.createElement(`${prefix}-icon`);
|
|
136
|
+
icon.slot = slot;
|
|
137
|
+
icon.classList.add('grid-context-menu-icon');
|
|
138
|
+
if (variant) {
|
|
139
|
+
icon.classList.add(variant);
|
|
140
|
+
}
|
|
141
|
+
icon.setAttribute('name', name);
|
|
142
|
+
icon.setAttribute('size', '1x');
|
|
143
|
+
icon.setAttribute('aria-hidden', 'true');
|
|
144
|
+
return icon;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Custom properties the menu reads. AG Grid sets its theme on its wrapper element, which is not an
|
|
148
|
+
* ancestor of the menu, so they are copied from the clicked cell.
|
|
149
|
+
*/
|
|
150
|
+
const MENU_THEME_PROPERTIES = [
|
|
151
|
+
'--ag-spacing',
|
|
152
|
+
'--ag-icon-size',
|
|
153
|
+
'--ag-font-size',
|
|
154
|
+
'--ag-font-family',
|
|
155
|
+
'--ag-menu-background-color',
|
|
156
|
+
'--ag-menu-border',
|
|
157
|
+
'--ag-menu-text-color',
|
|
158
|
+
'--ag-menu-shadow',
|
|
159
|
+
'--ag-popup-shadow',
|
|
160
|
+
'--ag-border-radius',
|
|
161
|
+
'--ag-row-hover-color',
|
|
162
|
+
'--fill-color',
|
|
163
|
+
'--neutral-stroke-rest',
|
|
164
|
+
'--neutral-foreground-rest',
|
|
165
|
+
'--neutral-fill-stealth-hover',
|
|
166
|
+
'--body-font',
|
|
167
|
+
'--type-ramp-base-font-size',
|
|
168
|
+
'--stroke-width',
|
|
169
|
+
'--control-corner-radius',
|
|
170
|
+
];
|
|
171
|
+
function applyMenuTheme(host, source) {
|
|
172
|
+
if (!source) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const computed = getComputedStyle(source);
|
|
176
|
+
for (const name of MENU_THEME_PROPERTIES) {
|
|
177
|
+
const value = computed.getPropertyValue(name).trim();
|
|
178
|
+
if (value) {
|
|
179
|
+
host.style.setProperty(name, value);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* A CSV Export item, using AG Grid's community CSV export. Assign it to `contextMenuItems` as the
|
|
185
|
+
* whole menu, or spread its result into a menu of your own. Empty when the grid sets
|
|
186
|
+
* `suppressCsvExport`.
|
|
187
|
+
*
|
|
188
|
+
* @public
|
|
189
|
+
*/
|
|
190
|
+
export function defaultGridContextMenuItems(event) {
|
|
191
|
+
var _a;
|
|
192
|
+
if ((_a = event.api) === null || _a === void 0 ? void 0 : _a.getGridOption('suppressCsvExport')) {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
return [
|
|
196
|
+
{
|
|
197
|
+
name: 'CSV Export',
|
|
198
|
+
action: () => { var _a; return (_a = event.api) === null || _a === void 0 ? void 0 : _a.exportDataAsCsv(); },
|
|
199
|
+
},
|
|
200
|
+
];
|
|
201
|
+
}
|
|
202
|
+
/** Each prefix is reported once, not on every right-click. */
|
|
203
|
+
const prefixesReportedMissing = new Set();
|
|
204
|
+
function menuComponentsRegistered(prefix) {
|
|
205
|
+
if (customElements.get(`${prefix}-menu`) && customElements.get(`${prefix}-menu-item`)) {
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
if (!prefixesReportedMissing.has(prefix)) {
|
|
209
|
+
prefixesReportedMissing.add(prefix);
|
|
210
|
+
logger.warn(`Grid Pro: the right-click menu needs <${prefix}-menu> and <${prefix}-menu-item> registered ` +
|
|
211
|
+
'in the design system. The browser menu is shown instead.');
|
|
212
|
+
}
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Opens a design-system menu at the pointer and returns a function that removes it, or
|
|
217
|
+
* `undefined` when the design system has not registered the menu components.
|
|
218
|
+
*
|
|
219
|
+
* A pointer press outside, a scroll outside, a window resize, Escape or Tab closes it. Choosing an item runs its
|
|
220
|
+
* action and closes it; an item with a submenu opens the submenu instead.
|
|
221
|
+
*
|
|
222
|
+
* @internal
|
|
223
|
+
*/
|
|
224
|
+
export function openGridContextMenu(options) {
|
|
225
|
+
var _a, _b;
|
|
226
|
+
const { prefix, x, y, items, themeSource } = options;
|
|
227
|
+
if (!menuComponentsRegistered(prefix)) {
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
const host = document.createElement('div');
|
|
231
|
+
host.classList.add('grid-context-menu-host');
|
|
232
|
+
host.style.cssText = MENU_HOST_STYLE;
|
|
233
|
+
applyMenuTheme(host, themeSource);
|
|
234
|
+
host.addEventListener('mousedown', (event) => event.stopPropagation());
|
|
235
|
+
const shadow = host.attachShadow({ mode: 'open' });
|
|
236
|
+
contextMenuStyles.addStylesTo(shadow);
|
|
237
|
+
const container = (_a = options.container) !== null && _a !== void 0 ? _a : document.body;
|
|
238
|
+
const containerRoot = container.getRootNode();
|
|
239
|
+
const returnFocusTo = (_b = themeSource === null || themeSource === void 0 ? void 0 : themeSource.closest('.ag-cell')) !== null && _b !== void 0 ? _b : null;
|
|
240
|
+
let closed = false;
|
|
241
|
+
const close = (restoreFocus = false) => {
|
|
242
|
+
if (closed) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
closed = true;
|
|
246
|
+
const focusWasInMenu = host.matches(':focus-within');
|
|
247
|
+
host.remove();
|
|
248
|
+
window.removeEventListener('mousedown', onPointerDownOutside);
|
|
249
|
+
window.removeEventListener('resize', onResize);
|
|
250
|
+
window.removeEventListener('scroll', onScroll, true);
|
|
251
|
+
if (containerRoot instanceof ShadowRoot) {
|
|
252
|
+
containerRoot.removeEventListener('scroll', onScroll, true);
|
|
253
|
+
}
|
|
254
|
+
window.removeEventListener('keydown', onKeyDown, true);
|
|
255
|
+
if (restoreFocus && focusWasInMenu) {
|
|
256
|
+
returnFocusTo === null || returnFocusTo === void 0 ? void 0 : returnFocusTo.focus({ preventScroll: true });
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
const onPointerDownOutside = () => close();
|
|
260
|
+
const onResize = () => close();
|
|
261
|
+
// Scroll does not cross shadow roots, so a grid in a shadow root is watched there as well.
|
|
262
|
+
const onScroll = (event) => {
|
|
263
|
+
if (!event.composedPath().includes(host)) {
|
|
264
|
+
close();
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
const onKeyDown = (event) => {
|
|
268
|
+
if (event.key === 'Escape' || event.key === 'Tab') {
|
|
269
|
+
event.preventDefault();
|
|
270
|
+
event.stopPropagation();
|
|
271
|
+
close(true);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
const menu = document.createElement(`${prefix}-menu`);
|
|
275
|
+
menu.classList.add('grid-context-menu');
|
|
276
|
+
appendMenuItems(prefix, menu, items, () => close(true));
|
|
277
|
+
shadow.append(menu);
|
|
278
|
+
container.appendChild(host);
|
|
279
|
+
showInTopLayer(host);
|
|
280
|
+
placeWithinViewport(host, x, y);
|
|
281
|
+
window.addEventListener('mousedown', onPointerDownOutside);
|
|
282
|
+
window.addEventListener('resize', onResize);
|
|
283
|
+
window.addEventListener('scroll', onScroll, true);
|
|
284
|
+
if (containerRoot instanceof ShadowRoot) {
|
|
285
|
+
containerRoot.addEventListener('scroll', onScroll, true);
|
|
286
|
+
}
|
|
287
|
+
window.addEventListener('keydown', onKeyDown, true);
|
|
288
|
+
// The menu collects its items on the next update; focusing it before then does nothing.
|
|
289
|
+
DOM.queueUpdate(() => {
|
|
290
|
+
if (!closed) {
|
|
291
|
+
menu.focus();
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
return () => close();
|
|
295
|
+
}
|
|
296
|
+
/** Overrides the user-agent popover box; `z-index` only matters where popovers are unsupported. */
|
|
297
|
+
const MENU_HOST_STYLE = 'position: fixed; inset: auto; margin: 0; padding: 0; border: 0; overflow: visible; ' +
|
|
298
|
+
'background: transparent; color: inherit; z-index: 10000;';
|
|
299
|
+
/**
|
|
300
|
+
* The top layer keeps the menu above dialogs and clear of transformed or clipping ancestors.
|
|
301
|
+
* Browsers without popovers fall back to the fixed, high z-index of {@link MENU_HOST_STYLE}.
|
|
302
|
+
*/
|
|
303
|
+
function showInTopLayer(host) {
|
|
304
|
+
if (typeof host.showPopover === 'function') {
|
|
305
|
+
host.popover = 'manual';
|
|
306
|
+
host.showPopover();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/** Opens at the pointer, flipping left or up where the menu would leave the viewport. */
|
|
310
|
+
function placeWithinViewport(host, x, y) {
|
|
311
|
+
host.style.left = `${x}px`;
|
|
312
|
+
host.style.top = `${y}px`;
|
|
313
|
+
const { width, height } = host.getBoundingClientRect();
|
|
314
|
+
if (x + width > window.innerWidth) {
|
|
315
|
+
host.style.left = `${Math.max(0, x - width)}px`;
|
|
316
|
+
}
|
|
317
|
+
if (y + height > window.innerHeight) {
|
|
318
|
+
host.style.top = `${Math.max(0, y - height)}px`;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function appendMenuItems(prefix, menu, items, close) {
|
|
322
|
+
var _a;
|
|
323
|
+
// Separators only go between items, so an empty spread does not leave a stray line.
|
|
324
|
+
const entries = items.filter((item, index) => item !== 'separator' || (index > 0 && items[index - 1] !== 'separator'));
|
|
325
|
+
while (entries[0] === 'separator')
|
|
326
|
+
entries.shift();
|
|
327
|
+
while (entries.at(-1) === 'separator')
|
|
328
|
+
entries.pop();
|
|
329
|
+
for (const item of entries) {
|
|
330
|
+
if (item === 'separator') {
|
|
331
|
+
const separator = document.createElement('div');
|
|
332
|
+
separator.setAttribute('role', 'separator');
|
|
333
|
+
separator.classList.add('grid-context-menu-separator');
|
|
334
|
+
menu.append(separator);
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
const menuItem = document.createElement(`${prefix}-menu-item`);
|
|
338
|
+
menuItem.classList.add('grid-context-menu-item');
|
|
339
|
+
menuItem.textContent = item.name;
|
|
340
|
+
if (item.tooltip) {
|
|
341
|
+
menuItem.title = item.tooltip;
|
|
342
|
+
}
|
|
343
|
+
if (item.checked !== undefined) {
|
|
344
|
+
menuItem.setAttribute('role', 'menuitemcheckbox');
|
|
345
|
+
if (item.checked) {
|
|
346
|
+
menuItem.setAttribute('checked', '');
|
|
347
|
+
// Neither design system draws a checkbox glyph of its own.
|
|
348
|
+
menuItem.append(menuIcon(prefix, 'checkbox-indicator', 'check'));
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (item.shortcut) {
|
|
352
|
+
const shortcut = document.createElement('span');
|
|
353
|
+
shortcut.slot = 'end';
|
|
354
|
+
shortcut.textContent = item.shortcut;
|
|
355
|
+
menuItem.append(shortcut);
|
|
356
|
+
}
|
|
357
|
+
if (item.disabled) {
|
|
358
|
+
menuItem.setAttribute('disabled', '');
|
|
359
|
+
}
|
|
360
|
+
const hasSubMenu = !!((_a = item.subMenu) === null || _a === void 0 ? void 0 : _a.length);
|
|
361
|
+
if (hasSubMenu) {
|
|
362
|
+
const subMenu = document.createElement(`${prefix}-menu`);
|
|
363
|
+
subMenu.slot = 'submenu';
|
|
364
|
+
subMenu.classList.add('grid-context-menu');
|
|
365
|
+
appendMenuItems(prefix, subMenu, item.subMenu, close);
|
|
366
|
+
menuItem.append(menuIcon(prefix, 'expand-collapse-indicator', 'chevron-right', 'chevron'), subMenu);
|
|
367
|
+
}
|
|
368
|
+
// `change` is what the menu item emits for a click, Enter or Space alike.
|
|
369
|
+
menuItem.addEventListener('change', (event) => {
|
|
370
|
+
var _a;
|
|
371
|
+
if (event.target !== menuItem || hasSubMenu || item.disabled) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
(_a = item.action) === null || _a === void 0 ? void 0 : _a.call(item);
|
|
375
|
+
close();
|
|
376
|
+
});
|
|
377
|
+
menu.append(menuItem);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { defaultGridContextMenuItems, } from './context-menu';
|
package/dist/esm/grid-pro.js
CHANGED
|
@@ -13,6 +13,7 @@ import { GridProColumn, resolveVisibleColumnFields } from './column';
|
|
|
13
13
|
import { EnumColumnFilter, EnumColumnFloatingFilter, GridProFilterTypes } from './column-filters';
|
|
14
14
|
import { ColumnSelection, gridProColumnSelectionHostStyles } from './column-selection';
|
|
15
15
|
import { GRID_PRO_COLUMN_DRAG_BRIDGE_CONTEXT_KEY, gridProColumnDragBridgeModule, } from './column-selection/grid-pro-column-drag-bridge';
|
|
16
|
+
import { openGridContextMenu } from './context-menu/context-menu';
|
|
16
17
|
import { GridProClientSideDatasource, GridProInfiniteDatasource, GridProServerSideDatasource, } from './datasource';
|
|
17
18
|
import { baseDatasourceEventNames } from './datasource/base.types';
|
|
18
19
|
import { errorHandlerDialogStyles } from './datasource/error-handler.dialog';
|
|
@@ -159,6 +160,9 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
|
|
|
159
160
|
}
|
|
160
161
|
return undefined;
|
|
161
162
|
}
|
|
163
|
+
contextMenuItemsChanged() {
|
|
164
|
+
this.syncContextMenuSuppression();
|
|
165
|
+
}
|
|
162
166
|
enableColumnSelectionChanged() {
|
|
163
167
|
this.syncColumnSelectionHostLayout();
|
|
164
168
|
}
|
|
@@ -234,6 +238,8 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
|
|
|
234
238
|
this.statusPanelState = {};
|
|
235
239
|
this.warnedUnregisteredStatusBar = false;
|
|
236
240
|
this.warnedGridOptionsStatusBar = false;
|
|
241
|
+
/** Whether the AG grid instance was created with its own context menu suppressed. */
|
|
242
|
+
this.gridCreatedWithMenuSuppressed = false;
|
|
237
243
|
/**
|
|
238
244
|
* Shows a Columns side panel on the trailing edge of the grid.
|
|
239
245
|
* @public
|
|
@@ -247,6 +253,15 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
|
|
|
247
253
|
this.registeredGridEvents = new Set();
|
|
248
254
|
this.gridEventListeners = new Map();
|
|
249
255
|
this.boundGlobalEventListener = this.globalEventListener.bind(this);
|
|
256
|
+
/**
|
|
257
|
+
* `globalListener` runs on a timeout, which is too late to cancel the browser menu.
|
|
258
|
+
* This one runs inside the right-click event.
|
|
259
|
+
*/
|
|
260
|
+
this.boundContextMenuListener = (eventType, event) => {
|
|
261
|
+
if (eventType === 'cellContextMenu') {
|
|
262
|
+
this.showContextMenu(event);
|
|
263
|
+
}
|
|
264
|
+
};
|
|
250
265
|
this._filterConfig = undefined;
|
|
251
266
|
this.handleLuminanceChange = (record) => {
|
|
252
267
|
const luminance = baseLayerLuminance.getValueFor(record.target);
|
|
@@ -414,11 +429,13 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
|
|
|
414
429
|
this.toggleDatasourceEventListeners(true);
|
|
415
430
|
}
|
|
416
431
|
disconnectedCallback() {
|
|
417
|
-
var _a;
|
|
432
|
+
var _a, _b;
|
|
433
|
+
(_a = this.closeContextMenu) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
434
|
+
this.closeContextMenu = undefined;
|
|
418
435
|
this.disposed = true;
|
|
419
436
|
this.debouncedSaveColumnState.cancel();
|
|
420
437
|
this.debouncedSaveFilterModel.cancel();
|
|
421
|
-
const luminanceTarget = (
|
|
438
|
+
const luminanceTarget = (_b = this.provider) !== null && _b !== void 0 ? _b : this;
|
|
422
439
|
baseLayerLuminance.unsubscribe(this.luminanceObserver, luminanceTarget);
|
|
423
440
|
if (this.luminanceSubscription) {
|
|
424
441
|
this.luminanceSubscription.unsubscribe();
|
|
@@ -1171,6 +1188,7 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
|
|
|
1171
1188
|
get gridParams() {
|
|
1172
1189
|
return {
|
|
1173
1190
|
globalListener: this.boundGlobalEventListener,
|
|
1191
|
+
globalSyncListener: this.boundContextMenuListener,
|
|
1174
1192
|
modules: [gridProColumnDragBridgeModule, ColumnMoveModule, DragAndDropModule],
|
|
1175
1193
|
};
|
|
1176
1194
|
}
|
|
@@ -1238,6 +1256,9 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
|
|
|
1238
1256
|
const derivedOptions = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, this.gridOptionsConfig), { defaultColDef: Object.assign({ enableCellChangeFlash: this.enableCellFlashing, filter: true, resizable: true, sortable: true }, defaultColDef), components: this.combineAllGridComponents(components), headerHeight: this.headerHeight, rowHeight: this.rowHeight, animateRows: false, suppressDragLeaveHidesColumns: true }), this.eventsAndCallbacks), { onGridReady: (event) => __awaiter(this, void 0, void 0, function* () {
|
|
1239
1257
|
var _a, _b, _c;
|
|
1240
1258
|
this.gridApi = event.api;
|
|
1259
|
+
if (!!this.contextMenuItems !== this.gridCreatedWithMenuSuppressed) {
|
|
1260
|
+
this.syncContextMenuSuppression();
|
|
1261
|
+
}
|
|
1241
1262
|
this.applyStatusBarMode();
|
|
1242
1263
|
if (this.gridEventsQueue.length) {
|
|
1243
1264
|
this.gridEventsQueue.forEach((type) => {
|
|
@@ -1374,7 +1395,9 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
|
|
|
1374
1395
|
this.gridSlot.removeChild(this.gridSlot.firstChild);
|
|
1375
1396
|
}
|
|
1376
1397
|
}
|
|
1377
|
-
this.
|
|
1398
|
+
this.gridCreatedWithMenuSuppressed = !!this.contextMenuItems;
|
|
1399
|
+
this.agGrid = createGrid(this.gridSlot, this.gridCreatedWithMenuSuppressed
|
|
1400
|
+
? Object.assign(Object.assign({}, this.agGridOptions), { suppressContextMenu: true }) : this.agGridOptions, this.gridParams);
|
|
1378
1401
|
this.initialised = true;
|
|
1379
1402
|
});
|
|
1380
1403
|
}
|
|
@@ -1508,9 +1531,61 @@ export class GridPro extends LifecycleMixin(FoundationElement) {
|
|
|
1508
1531
|
if (this.initialised) {
|
|
1509
1532
|
// for subsequent (post gridOptions) changes - use setGridOption API for v35
|
|
1510
1533
|
(_a = this.gridApi) === null || _a === void 0 ? void 0 : _a.setGridOption(gridPropertyName, newValue);
|
|
1534
|
+
if (gridPropertyName === 'suppressContextMenu' && this.contextMenuItems) {
|
|
1535
|
+
this.syncContextMenuSuppression();
|
|
1536
|
+
}
|
|
1511
1537
|
}
|
|
1512
1538
|
}
|
|
1513
1539
|
}
|
|
1540
|
+
/**
|
|
1541
|
+
* AG Grid draws its own menu when `ContextMenu` is registered, so it is suppressed while
|
|
1542
|
+
* `contextMenuItems` is set and the app's own `suppressContextMenu` restored when it is cleared.
|
|
1543
|
+
* The suppression goes to AG Grid only, never into `agGridOptions`: that object is what the
|
|
1544
|
+
* `gridOptions` getter returns, and an app re-applying it would otherwise adopt the setting.
|
|
1545
|
+
* @internal
|
|
1546
|
+
*/
|
|
1547
|
+
syncContextMenuSuppression() {
|
|
1548
|
+
var _a, _b, _c, _d;
|
|
1549
|
+
const appSetting = (_c = (_a = this.agAttributes.suppressContextMenu) !== null && _a !== void 0 ? _a : (_b = this.agGridOptions) === null || _b === void 0 ? void 0 : _b.suppressContextMenu) !== null && _c !== void 0 ? _c : false;
|
|
1550
|
+
(_d = this.gridApi) === null || _d === void 0 ? void 0 : _d.setGridOption('suppressContextMenu', this.contextMenuItems ? true : appSetting);
|
|
1551
|
+
}
|
|
1552
|
+
/**
|
|
1553
|
+
* Opens the grid's right-click menu for a cell. Called from the synchronous grid listener so
|
|
1554
|
+
* `preventDefault` still cancels the browser menu.
|
|
1555
|
+
* @internal
|
|
1556
|
+
*/
|
|
1557
|
+
showContextMenu(event) {
|
|
1558
|
+
var _a, _b, _c, _d, _e;
|
|
1559
|
+
const items = (_a = this.contextMenuItems) === null || _a === void 0 ? void 0 : _a.call(this, event);
|
|
1560
|
+
if (!(items === null || items === void 0 ? void 0 : items.length)) {
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
const mouse = event.event instanceof MouseEvent ? event.event : null;
|
|
1564
|
+
const pathTarget = mouse === null || mouse === void 0 ? void 0 : mouse.composedPath()[0];
|
|
1565
|
+
const target = pathTarget instanceof Element ? pathTarget : null;
|
|
1566
|
+
let x = (_b = mouse === null || mouse === void 0 ? void 0 : mouse.clientX) !== null && _b !== void 0 ? _b : 0;
|
|
1567
|
+
let y = (_c = mouse === null || mouse === void 0 ? void 0 : mouse.clientY) !== null && _c !== void 0 ? _c : 0;
|
|
1568
|
+
// A menu opened from the keyboard can arrive without a pointer position.
|
|
1569
|
+
const cell = target === null || target === void 0 ? void 0 : target.closest('.ag-cell');
|
|
1570
|
+
if (x === 0 && y === 0 && cell) {
|
|
1571
|
+
const rect = cell.getBoundingClientRect();
|
|
1572
|
+
x = rect.left;
|
|
1573
|
+
y = rect.bottom;
|
|
1574
|
+
}
|
|
1575
|
+
(_d = this.closeContextMenu) === null || _d === void 0 ? void 0 : _d.call(this);
|
|
1576
|
+
const [prefix = 'foundation'] = this.tagName.toLowerCase().split('-');
|
|
1577
|
+
this.closeContextMenu = openGridContextMenu({
|
|
1578
|
+
prefix,
|
|
1579
|
+
x,
|
|
1580
|
+
y,
|
|
1581
|
+
items,
|
|
1582
|
+
container: (_e = this.shadowRoot) !== null && _e !== void 0 ? _e : undefined,
|
|
1583
|
+
themeSource: target,
|
|
1584
|
+
});
|
|
1585
|
+
if (this.closeContextMenu && (mouse === null || mouse === void 0 ? void 0 : mouse.cancelable)) {
|
|
1586
|
+
mouse.preventDefault();
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1514
1589
|
globalEventListener(eventType, event) {
|
|
1515
1590
|
const eventLowerCase = eventType.toLowerCase();
|
|
1516
1591
|
const browserEvent = new Event(eventLowerCase);
|
|
@@ -1597,6 +1672,9 @@ __decorate([
|
|
|
1597
1672
|
__decorate([
|
|
1598
1673
|
observable
|
|
1599
1674
|
], GridPro.prototype, "statusBarMode", void 0);
|
|
1675
|
+
__decorate([
|
|
1676
|
+
observable
|
|
1677
|
+
], GridPro.prototype, "contextMenuItems", void 0);
|
|
1600
1678
|
__decorate([
|
|
1601
1679
|
attr({ mode: 'boolean', attribute: 'enable-column-selection' })
|
|
1602
1680
|
], GridPro.prototype, "enableColumnSelection", void 0);
|
package/dist/esm/index.js
CHANGED