@ornery/ui-grid-react 0.1.10 → 1.0.1
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/AGENTS.md +67 -0
- package/dist/UiGrid.d.ts +6 -5
- package/dist/UiGrid.d.ts.map +1 -1
- package/dist/gridStateMath.d.ts +2 -2
- package/dist/gridStateMath.d.ts.map +1 -1
- package/dist/index.d.ts +2 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +159 -2142
- package/dist/index.mjs +153 -2229
- package/dist/mountUiGrid.d.ts +2 -0
- package/dist/mountUiGrid.d.ts.map +1 -1
- package/dist/ui-grid.css +48 -15
- package/dist/useGridState.d.ts.map +1 -1
- package/package.json +5 -3
- package/src/UiGrid.test.tsx +64 -235
- package/src/UiGrid.tsx +178 -699
- package/src/gridStateMath.test.ts +3 -3
- package/src/gridStateMath.ts +7 -4
- package/src/index.ts +2 -18
- package/src/mountUiGrid.tsx +26 -0
- package/src/test-setup.ts +13 -0
- package/src/ui-grid.css +48 -15
- package/src/useGridState.ts +8 -7
- package/tsconfig.dts.json +3 -2
- package/tsconfig.json +2 -1
- package/vitest.config.ts +2 -0
package/dist/mountUiGrid.d.ts
CHANGED
|
@@ -6,4 +6,6 @@ export declare function mountUiGrid(container: Element | DocumentFragment, props
|
|
|
6
6
|
export declare function updateUiGrid(root: Root, props: UiGridProps): void;
|
|
7
7
|
/** Create a styled <span> React node — usable from non-TSX contexts (e.g. Angular). */
|
|
8
8
|
export declare function styledCell(text: string, color: string, extraStyle?: React.CSSProperties): React.ReactNode;
|
|
9
|
+
/** Create a date <input> React node — usable from non-TSX contexts. */
|
|
10
|
+
export declare function datePickerCell(value: string, onChange?: (newValue: string) => void, extraStyle?: React.CSSProperties): React.ReactNode;
|
|
9
11
|
//# sourceMappingURL=mountUiGrid.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mountUiGrid.d.ts","sourceRoot":"","sources":["../src/mountUiGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAEpD,wBAAgB,WAAW,CAAC,SAAS,EAAE,OAAO,GAAG,gBAAgB,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAI3F;AAED,uFAAuF;AACvF,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAEjE;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,GAC/B,KAAK,CAAC,SAAS,CAMjB"}
|
|
1
|
+
{"version":3,"file":"mountUiGrid.d.ts","sourceRoot":"","sources":["../src/mountUiGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAEpD,wBAAgB,WAAW,CAAC,SAAS,EAAE,OAAO,GAAG,gBAAgB,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAI3F;AAED,uFAAuF;AACvF,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,CAEjE;AAED,uFAAuF;AACvF,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,GAC/B,KAAK,CAAC,SAAS,CAMjB;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,EACrC,UAAU,CAAC,EAAE,KAAK,CAAC,aAAa,GAC/B,KAAK,CAAC,SAAS,CAmBjB"}
|
package/dist/ui-grid.css
CHANGED
|
@@ -279,37 +279,70 @@
|
|
|
279
279
|
color: var(--ui-grid-muted-color);
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
+
/*
|
|
283
|
+
* Grid table layout. Header + filter rows live in their own
|
|
284
|
+
* non-user-scrollable strips (real scroll containers so `position: sticky`
|
|
285
|
+
* on pinned cells anchors correctly); the body has its own viewport with
|
|
286
|
+
* visible scrollbars. Horizontal scroll on the body is mirrored onto the
|
|
287
|
+
* strips imperatively via React's onScroll/onWheel handlers so the columns
|
|
288
|
+
* always stay aligned.
|
|
289
|
+
*/
|
|
282
290
|
.grid-table {
|
|
283
|
-
|
|
291
|
+
position: relative;
|
|
292
|
+
display: flex;
|
|
293
|
+
flex-direction: column;
|
|
284
294
|
min-height: 0;
|
|
285
295
|
width: 100%;
|
|
286
296
|
min-width: 0;
|
|
287
|
-
overflow-
|
|
288
|
-
overflow-y: hidden;
|
|
297
|
+
overflow-anchor: none;
|
|
289
298
|
}
|
|
290
299
|
|
|
291
|
-
.header-
|
|
292
|
-
.filter-
|
|
293
|
-
|
|
294
|
-
display: grid;
|
|
295
|
-
width: max-content;
|
|
296
|
-
min-width: 100%;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
.header-grid,
|
|
300
|
-
.filter-grid {
|
|
300
|
+
.grid-header-strip,
|
|
301
|
+
.grid-filter-strip {
|
|
302
|
+
flex: 0 0 auto;
|
|
301
303
|
position: sticky;
|
|
302
304
|
z-index: 3;
|
|
305
|
+
background: var(--ui-grid-surface);
|
|
306
|
+
/* Real scroll container so pinned sticky cells anchor to something,
|
|
307
|
+
* but we don't want the user scrolling it directly. JS drives the
|
|
308
|
+
* scrollLeft, the wheel handler forwards gestures to the body, and
|
|
309
|
+
* the scrollbar is hidden. */
|
|
310
|
+
overflow-x: scroll;
|
|
311
|
+
overflow-y: hidden;
|
|
312
|
+
scrollbar-width: none;
|
|
313
|
+
touch-action: pan-y;
|
|
314
|
+
overscroll-behavior-x: none;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.grid-header-strip::-webkit-scrollbar,
|
|
318
|
+
.grid-filter-strip::-webkit-scrollbar {
|
|
319
|
+
display: none;
|
|
303
320
|
}
|
|
304
321
|
|
|
305
|
-
.header-
|
|
322
|
+
.grid-header-strip {
|
|
306
323
|
top: 0;
|
|
307
324
|
}
|
|
308
325
|
|
|
309
|
-
.filter-
|
|
326
|
+
.grid-filter-strip {
|
|
310
327
|
top: var(--ui-grid-header-sticky-top, 0px);
|
|
311
328
|
}
|
|
312
329
|
|
|
330
|
+
.grid-body-viewport {
|
|
331
|
+
flex: 1 1 auto;
|
|
332
|
+
min-height: 0;
|
|
333
|
+
overflow-x: auto;
|
|
334
|
+
overflow-anchor: none;
|
|
335
|
+
overscroll-behavior-x: none;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.header-grid,
|
|
339
|
+
.filter-grid,
|
|
340
|
+
.body-grid {
|
|
341
|
+
display: grid;
|
|
342
|
+
width: max-content;
|
|
343
|
+
min-width: 100%;
|
|
344
|
+
}
|
|
345
|
+
|
|
313
346
|
.header-cell,
|
|
314
347
|
.filter-cell,
|
|
315
348
|
.body-cell,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useGridState.d.ts","sourceRoot":"","sources":["../src/useGridState.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"useGridState.d.ts","sourceRoot":"","sources":["../src/useGridState.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ornery/ui-grid-react",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "React wrapper for @ornery/ui-grid-core",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -14,12 +14,14 @@
|
|
|
14
14
|
"./styles": "./dist/ui-grid.css"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"@ornery/ui-grid-core": "0.
|
|
17
|
+
"@ornery/ui-grid-core": "1.0.0",
|
|
18
|
+
"@ornery/ui-grid-vanilla": "1.0.0",
|
|
18
19
|
"react": "^18.0.0 || ^19.0.0",
|
|
19
20
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
20
21
|
},
|
|
21
22
|
"devDependencies": {
|
|
22
23
|
"@ornery/ui-grid-core": "file:../ui-grid-core",
|
|
24
|
+
"@ornery/ui-grid-vanilla": "file:../ui-grid-vanilla",
|
|
23
25
|
"@testing-library/react": "^16.0.0",
|
|
24
26
|
"@types/react": "^19.0.0",
|
|
25
27
|
"@types/react-dom": "^19.0.0",
|
|
@@ -34,7 +36,7 @@
|
|
|
34
36
|
},
|
|
35
37
|
"scripts": {
|
|
36
38
|
"start": "vite serve demo --config demo/vite.config.ts",
|
|
37
|
-
"build": "npm run build --prefix ../ui-grid-core && tsup src/index.ts --format esm,cjs --tsconfig tsconfig.build.json --external react --external react-dom --external @ornery/ui-grid-core && tsc -p tsconfig.dts.json && node -e \"require('fs').copyFileSync('src/ui-grid.css','dist/ui-grid.css')\"",
|
|
39
|
+
"build": "npm run build --prefix ../ui-grid-core && npm run build --prefix ../ui-grid-vanilla && tsup src/index.ts --format esm,cjs --tsconfig tsconfig.build.json --external react --external react-dom --external @ornery/ui-grid-core --external @ornery/ui-grid-vanilla && tsc -p tsconfig.dts.json && node -e \"require('fs').copyFileSync('src/ui-grid.css','dist/ui-grid.css')\"",
|
|
38
40
|
"test": "vitest run",
|
|
39
41
|
"test:watch": "vitest"
|
|
40
42
|
}
|
package/src/UiGrid.test.tsx
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { render,
|
|
3
|
-
import { describe, it, expect, vi,
|
|
2
|
+
import { render, act, waitFor } from '@testing-library/react';
|
|
3
|
+
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
4
4
|
import { UiGrid } from './UiGrid';
|
|
5
5
|
import type { UiGridProps } from './UiGrid';
|
|
6
6
|
import type {
|
|
7
|
-
GridHeaderTemplateContext,
|
|
8
7
|
GridOptions,
|
|
9
8
|
UiGridApi,
|
|
10
|
-
GridExpandableTemplateContext,
|
|
11
9
|
} from '@ornery/ui-grid-core';
|
|
12
10
|
import { SORT_DIRECTIONS, FILTER_CONDITIONS } from '@ornery/ui-grid-core';
|
|
13
11
|
|
|
@@ -75,21 +73,33 @@ function createOptions(
|
|
|
75
73
|
};
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
function
|
|
76
|
+
function getShadowRoot(container: HTMLElement): ShadowRoot {
|
|
77
|
+
const el = container.querySelector('ui-grid-element');
|
|
78
|
+
if (!el?.shadowRoot) throw new Error('Shadow root not found');
|
|
79
|
+
return el.shadowRoot;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function renderGrid(
|
|
79
83
|
overrides: Partial<GridOptions> = {},
|
|
80
84
|
props: Partial<Omit<UiGridProps, 'options'>> = {},
|
|
81
|
-
): { container: HTMLElement; gridApi: UiGridApi } {
|
|
85
|
+
): Promise<{ container: HTMLElement; gridApi: UiGridApi; shadowRoot: ShadowRoot }> {
|
|
82
86
|
let gridApi!: UiGridApi;
|
|
87
|
+
let resolveApi: () => void;
|
|
88
|
+
const apiReady = new Promise<void>((r) => { resolveApi = r; });
|
|
83
89
|
const options = createOptions(overrides, (api) => {
|
|
84
90
|
gridApi = api;
|
|
85
91
|
props.onRegisterApi?.(api);
|
|
92
|
+
resolveApi();
|
|
86
93
|
});
|
|
87
94
|
|
|
88
95
|
const { container } = render(
|
|
89
96
|
<UiGrid options={options} onRegisterApi={options.onRegisterApi as any} {...props} />,
|
|
90
97
|
);
|
|
91
98
|
|
|
92
|
-
|
|
99
|
+
await act(async () => { await apiReady; });
|
|
100
|
+
|
|
101
|
+
const shadowRoot = getShadowRoot(container);
|
|
102
|
+
return { container, gridApi, shadowRoot };
|
|
93
103
|
}
|
|
94
104
|
|
|
95
105
|
describe('UiGrid React component', () => {
|
|
@@ -98,13 +108,13 @@ describe('UiGrid React component', () => {
|
|
|
98
108
|
vi.useRealTimers();
|
|
99
109
|
});
|
|
100
110
|
|
|
101
|
-
it('registers the API and renders headers and rows', () => {
|
|
102
|
-
const {
|
|
111
|
+
it('registers the API and renders headers and rows', async () => {
|
|
112
|
+
const { shadowRoot, gridApi } = await renderGrid();
|
|
103
113
|
|
|
104
|
-
const headers = Array.from(
|
|
114
|
+
const headers = Array.from(shadowRoot.querySelectorAll('.header-label')).map((el) =>
|
|
105
115
|
el.textContent?.trim(),
|
|
106
116
|
);
|
|
107
|
-
const bodyCells = Array.from(
|
|
117
|
+
const bodyCells = Array.from(shadowRoot.querySelectorAll('.body-cell')).map((el) =>
|
|
108
118
|
el.textContent?.trim(),
|
|
109
119
|
);
|
|
110
120
|
|
|
@@ -114,11 +124,10 @@ describe('UiGrid React component', () => {
|
|
|
114
124
|
expect(bodyCells).toContain('$300');
|
|
115
125
|
expect(bodyCells).toContain('Mina Patel');
|
|
116
126
|
expect(bodyCells).toContain('Gamma-badge');
|
|
117
|
-
expect(container.querySelector('.grid-viewport')).toBeNull();
|
|
118
127
|
});
|
|
119
128
|
|
|
120
|
-
it('filters rows
|
|
121
|
-
const {
|
|
129
|
+
it('filters rows via the API', async () => {
|
|
130
|
+
const { gridApi } = await renderGrid();
|
|
122
131
|
|
|
123
132
|
const filterChanged = vi.fn();
|
|
124
133
|
gridApi.core.on.filterChanged(filterChanged);
|
|
@@ -134,50 +143,11 @@ describe('UiGrid React component', () => {
|
|
|
134
143
|
act(() => {
|
|
135
144
|
gridApi.core.setFilter('status', 'Missing');
|
|
136
145
|
});
|
|
137
|
-
|
|
138
146
|
expect(gridApi.core.getVisibleRows()).toEqual([]);
|
|
139
|
-
expect(container.querySelector('.empty-state strong')?.textContent).toContain(
|
|
140
|
-
'Nothing to show',
|
|
141
|
-
);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('renders custom header content from the React headerRenderer prop', () => {
|
|
145
|
-
const headerRenderer = ({ value, column }: GridHeaderTemplateContext) => (
|
|
146
|
-
<span>{`${value}:${column.name}`}</span>
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
const { container } = renderGrid({}, { headerRenderer });
|
|
150
|
-
|
|
151
|
-
const headers = Array.from(container.querySelectorAll('.header-label')).map((el) =>
|
|
152
|
-
el.textContent?.trim(),
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
expect(headers).toEqual([
|
|
156
|
-
'Customer:name',
|
|
157
|
-
'Status:status',
|
|
158
|
-
'Revenue:revenue',
|
|
159
|
-
'Owner:owner',
|
|
160
|
-
'Badge:badge',
|
|
161
|
-
]);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('renders custom header content from column headerRenderer when no React headerRenderer is provided', () => {
|
|
165
|
-
const { container } = renderGrid({
|
|
166
|
-
columnDefs: [
|
|
167
|
-
{ name: 'name', displayName: 'Customer', headerRenderer: ({ value }) => `[${value}]` },
|
|
168
|
-
{ name: 'status' },
|
|
169
|
-
],
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
const headers = Array.from(container.querySelectorAll('.header-label')).map((el) =>
|
|
173
|
-
el.textContent?.trim(),
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
expect(headers).toEqual(['[Customer]', 'Status']);
|
|
177
147
|
});
|
|
178
148
|
|
|
179
|
-
it('sorts rows
|
|
180
|
-
const {
|
|
149
|
+
it('sorts rows via the API', async () => {
|
|
150
|
+
const { gridApi } = await renderGrid();
|
|
181
151
|
|
|
182
152
|
const sortChanged = vi.fn();
|
|
183
153
|
gridApi.core.on.sortChanged(sortChanged);
|
|
@@ -191,62 +161,10 @@ describe('UiGrid React component', () => {
|
|
|
191
161
|
'Gamma',
|
|
192
162
|
]);
|
|
193
163
|
expect(sortChanged).toHaveBeenLastCalledWith('name', SORT_DIRECTIONS.asc);
|
|
194
|
-
|
|
195
|
-
const headerButton = container.querySelector('.header-action') as HTMLButtonElement;
|
|
196
|
-
act(() => {
|
|
197
|
-
headerButton.click();
|
|
198
|
-
});
|
|
199
|
-
expect(sortChanged).toHaveBeenLastCalledWith('name', SORT_DIRECTIONS.desc);
|
|
200
|
-
expect(gridApi.core.getVisibleRows().map((row) => row.entity['name'])).toEqual([
|
|
201
|
-
'Gamma',
|
|
202
|
-
'Beta',
|
|
203
|
-
'alpha',
|
|
204
|
-
]);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
it('reorders visible columns by header drag and drop without shifting hidden columns', () => {
|
|
208
|
-
const { container } = renderGrid({
|
|
209
|
-
columnDefs: [
|
|
210
|
-
{ name: 'id', visible: false },
|
|
211
|
-
{ name: 'name', displayName: 'Customer' },
|
|
212
|
-
{ name: 'status' },
|
|
213
|
-
{ name: 'revenue' },
|
|
214
|
-
{ name: 'owner', field: 'account.owner' },
|
|
215
|
-
{ name: 'badge' },
|
|
216
|
-
],
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
const dataTransfer = {
|
|
220
|
-
effectAllowed: 'all',
|
|
221
|
-
dropEffect: 'none',
|
|
222
|
-
store: new Map<string, string>(),
|
|
223
|
-
setData(type: string, value: string) {
|
|
224
|
-
this.store.set(type, value);
|
|
225
|
-
},
|
|
226
|
-
getData(type: string) {
|
|
227
|
-
return this.store.get(type) ?? '';
|
|
228
|
-
},
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
const sourceHeader = container.querySelectorAll('.header-cell')[4] as HTMLElement;
|
|
232
|
-
const targetHeader = container.querySelectorAll('.header-cell')[1] as HTMLElement;
|
|
233
|
-
|
|
234
|
-
act(() => {
|
|
235
|
-
fireEvent.dragStart(sourceHeader, { dataTransfer });
|
|
236
|
-
fireEvent.dragOver(targetHeader, { dataTransfer });
|
|
237
|
-
fireEvent.drop(targetHeader, { dataTransfer });
|
|
238
|
-
fireEvent.dragEnd(sourceHeader, { dataTransfer });
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
const headers = Array.from(container.querySelectorAll('.header-label')).map((el) =>
|
|
242
|
-
el.textContent?.trim(),
|
|
243
|
-
);
|
|
244
|
-
|
|
245
|
-
expect(headers).toEqual(['Customer', 'Badge', 'Status', 'Revenue', 'Owner']);
|
|
246
164
|
});
|
|
247
165
|
|
|
248
|
-
it('groups rows
|
|
249
|
-
const {
|
|
166
|
+
it('groups rows via the API', async () => {
|
|
167
|
+
const { shadowRoot, gridApi } = await renderGrid();
|
|
250
168
|
|
|
251
169
|
const groupingChanged = vi.fn();
|
|
252
170
|
gridApi.core.on.groupingChanged(groupingChanged);
|
|
@@ -255,31 +173,20 @@ describe('UiGrid React component', () => {
|
|
|
255
173
|
gridApi.core.groupByColumn('status');
|
|
256
174
|
});
|
|
257
175
|
|
|
258
|
-
const
|
|
176
|
+
const groups = shadowRoot.querySelectorAll('.group-row');
|
|
259
177
|
expect(groupingChanged).toHaveBeenLastCalledWith(['status']);
|
|
260
|
-
expect(
|
|
261
|
-
expect(container.querySelectorAll('.body-cell')).toHaveLength(15);
|
|
262
|
-
|
|
263
|
-
const activeGroup = Array.from(initialGroups).find((node) =>
|
|
264
|
-
node.textContent?.includes('status: Active'),
|
|
265
|
-
);
|
|
266
|
-
expect(activeGroup).toBeTruthy();
|
|
267
|
-
|
|
268
|
-
act(() => {
|
|
269
|
-
(activeGroup as HTMLButtonElement).click();
|
|
270
|
-
});
|
|
271
|
-
expect(container.querySelectorAll('.body-cell')).toHaveLength(5);
|
|
178
|
+
expect(groups).toHaveLength(2);
|
|
272
179
|
});
|
|
273
180
|
|
|
274
181
|
it('exports visible rows as CSV', async () => {
|
|
275
|
-
const { gridApi } = renderGrid();
|
|
182
|
+
const { gridApi } = await renderGrid();
|
|
276
183
|
|
|
277
184
|
const anchor = document.createElement('a');
|
|
278
185
|
const originalCreateElement = document.createElement.bind(document);
|
|
279
186
|
const clickSpy = vi.spyOn(anchor, 'click').mockImplementation(() => {});
|
|
280
187
|
vi.spyOn(document, 'createElement').mockImplementation(((tagName: string) =>
|
|
281
188
|
tagName === 'a' ? anchor : originalCreateElement(tagName)) as typeof document.createElement);
|
|
282
|
-
|
|
189
|
+
vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:spec-grid');
|
|
283
190
|
vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => {});
|
|
284
191
|
|
|
285
192
|
act(() => {
|
|
@@ -287,37 +194,11 @@ describe('UiGrid React component', () => {
|
|
|
287
194
|
});
|
|
288
195
|
|
|
289
196
|
expect(clickSpy).toHaveBeenCalledTimes(1);
|
|
290
|
-
expect(anchor.download).
|
|
291
|
-
|
|
292
|
-
const blob = createObjectUrlSpy.mock.calls[0][0] as Blob;
|
|
293
|
-
const csv = await new Promise<string>((resolve) => {
|
|
294
|
-
const reader = new FileReader();
|
|
295
|
-
reader.onload = () => resolve(reader.result as string);
|
|
296
|
-
reader.readAsText(blob);
|
|
297
|
-
});
|
|
298
|
-
expect(csv).toContain('Customer,Status,Revenue,Owner,Badge');
|
|
299
|
-
expect(csv).toContain('Gamma,Pilot,$300,Mina Patel,Gamma-badge');
|
|
197
|
+
expect(anchor.download).toMatch(/\.csv$/);
|
|
300
198
|
});
|
|
301
199
|
|
|
302
|
-
it('
|
|
303
|
-
const {
|
|
304
|
-
virtualizationThreshold: 1,
|
|
305
|
-
data: Array.from({ length: 5 }, (_, index) => ({
|
|
306
|
-
id: `virtual-${index}`,
|
|
307
|
-
name: `Row ${index}`,
|
|
308
|
-
status: index % 2 === 0 ? 'Active' : 'Pilot',
|
|
309
|
-
revenue: index * 100,
|
|
310
|
-
account: { owner: `Owner ${index}` },
|
|
311
|
-
})),
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
expect(gridApi.core.getVisibleRows()).toHaveLength(5);
|
|
315
|
-
expect(container.querySelector('.grid-virtual-spacer')).not.toBeNull();
|
|
316
|
-
expect(container.querySelector('.grid-virtual-body')).not.toBeNull();
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
it('paginates rows', () => {
|
|
320
|
-
const { container, gridApi } = renderGrid({
|
|
200
|
+
it('paginates rows via the API', async () => {
|
|
201
|
+
const { gridApi } = await renderGrid({
|
|
321
202
|
enablePagination: true,
|
|
322
203
|
enablePaginationControls: true,
|
|
323
204
|
paginationPageSizes: [1, 2],
|
|
@@ -341,90 +222,44 @@ describe('UiGrid React component', () => {
|
|
|
341
222
|
gridApi.pagination.setPageSize(2);
|
|
342
223
|
});
|
|
343
224
|
expect(gridApi.core.getVisibleRows().map((row) => row.id)).toEqual(['row-1', 'row-2']);
|
|
344
|
-
|
|
345
|
-
expect(container.querySelector('.pagination-bar')?.textContent).toContain('1-2 of 3');
|
|
346
225
|
});
|
|
347
226
|
|
|
348
|
-
it('
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const beginCellEdit = vi.fn();
|
|
360
|
-
const afterCellEdit = vi.fn();
|
|
361
|
-
const cancelCellEdit = vi.fn();
|
|
362
|
-
gridApi.edit.on.beginCellEdit(beginCellEdit);
|
|
363
|
-
gridApi.edit.on.afterCellEdit(afterCellEdit);
|
|
364
|
-
gridApi.edit.on.cancelCellEdit(cancelCellEdit);
|
|
365
|
-
|
|
366
|
-
const firstNameCell = container.querySelector(
|
|
367
|
-
'.body-cell[data-row-id="row-1"][data-col-name="name"]',
|
|
368
|
-
) as HTMLElement;
|
|
369
|
-
|
|
370
|
-
await act(async () => {
|
|
371
|
-
firstNameCell.focus();
|
|
372
|
-
fireEvent.keyDown(firstNameCell, { key: 'Z' });
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
let editor = container.querySelector(
|
|
376
|
-
'.cell-editor[data-row-id="row-1"][data-col-name="name"]',
|
|
377
|
-
) as HTMLInputElement;
|
|
378
|
-
expect(editor).toBeTruthy();
|
|
379
|
-
expect(beginCellEdit).toHaveBeenCalled();
|
|
380
|
-
|
|
381
|
-
await act(async () => {
|
|
382
|
-
fireEvent.keyDown(editor, { key: 'Tab' });
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
expect(gridApi.core.getVisibleRows()[0]?.entity['name']).toBe('Z');
|
|
386
|
-
expect(afterCellEdit).toHaveBeenCalled();
|
|
387
|
-
|
|
388
|
-
const ownerCell = container.querySelector(
|
|
389
|
-
'.body-cell[data-row-id="row-1"][data-col-name="owner"]',
|
|
390
|
-
) as HTMLElement;
|
|
391
|
-
|
|
392
|
-
await act(async () => {
|
|
393
|
-
ownerCell.focus();
|
|
394
|
-
fireEvent.keyDown(ownerCell, { key: 'F2' });
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
editor = container.querySelector(
|
|
398
|
-
'.cell-editor[data-row-id="row-1"][data-col-name="owner"]',
|
|
399
|
-
) as HTMLInputElement;
|
|
400
|
-
expect(editor).toBeTruthy();
|
|
227
|
+
it('renders cell renderers via portals', async () => {
|
|
228
|
+
const statusRenderer = vi.fn((ctx) => `pill-${ctx.value}`);
|
|
229
|
+
const { container } = await renderGrid(
|
|
230
|
+
{
|
|
231
|
+
columnDefs: [
|
|
232
|
+
{ name: 'name', displayName: 'Customer' },
|
|
233
|
+
{ name: 'status' },
|
|
234
|
+
],
|
|
235
|
+
},
|
|
236
|
+
{ cellRenderers: { status: statusRenderer } },
|
|
237
|
+
);
|
|
401
238
|
|
|
239
|
+
// The vanilla element's framework slot flush may not fire in jsdom.
|
|
240
|
+
// Manually dispatch a cellSlotsChanged event to exercise the portal path.
|
|
241
|
+
const el = container.querySelector('ui-grid-element')!;
|
|
402
242
|
await act(async () => {
|
|
403
|
-
|
|
404
|
-
|
|
243
|
+
el.dispatchEvent(new CustomEvent('cellSlotsChanged', {
|
|
244
|
+
detail: {
|
|
245
|
+
added: [{
|
|
246
|
+
slotName: 'cell--status--row-1',
|
|
247
|
+
columnName: 'status',
|
|
248
|
+
rowId: 'row-1',
|
|
249
|
+
context: { $implicit: 'Pilot', value: 'Pilot', row: baseData[0], column: { name: 'status' }, rowIndex: 0 },
|
|
250
|
+
}],
|
|
251
|
+
removed: [],
|
|
252
|
+
},
|
|
253
|
+
}));
|
|
405
254
|
});
|
|
406
255
|
|
|
407
|
-
expect(
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
expect(cancelCellEdit).toHaveBeenCalled();
|
|
256
|
+
expect(statusRenderer).toHaveBeenCalled();
|
|
257
|
+
const portalContent = container.querySelectorAll('[slot]');
|
|
258
|
+
expect(portalContent.length).toBeGreaterThan(0);
|
|
411
259
|
});
|
|
412
260
|
|
|
413
|
-
it('
|
|
414
|
-
const {
|
|
415
|
-
labels: {
|
|
416
|
-
sortDefault: 'Trier',
|
|
417
|
-
sortAsc: 'Tri croissant',
|
|
418
|
-
paginationNext: 'Suivant',
|
|
419
|
-
},
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
const sortButton = container.querySelector('.header-action') as HTMLButtonElement;
|
|
423
|
-
expect(sortButton.getAttribute('aria-label')).toBe('Trier');
|
|
424
|
-
});
|
|
425
|
-
|
|
426
|
-
it('feature flags disable unused template sections', () => {
|
|
427
|
-
const { container, gridApi } = renderGrid({
|
|
261
|
+
it('feature flags disable columns via visible:false', async () => {
|
|
262
|
+
const { gridApi } = await renderGrid({
|
|
428
263
|
enableSorting: false,
|
|
429
264
|
enableFiltering: false,
|
|
430
265
|
enableGrouping: false,
|
|
@@ -437,12 +272,6 @@ describe('UiGrid React component', () => {
|
|
|
437
272
|
],
|
|
438
273
|
});
|
|
439
274
|
|
|
440
|
-
const headers = Array.from(container.querySelectorAll('.header-label')).map((el) =>
|
|
441
|
-
el.textContent?.trim(),
|
|
442
|
-
);
|
|
443
|
-
expect(headers).toEqual(['Status', 'Owner']);
|
|
444
|
-
expect(container.querySelector('.filter-grid')).toBeNull();
|
|
445
|
-
expect(container.querySelector('.chip-action')).toBeNull();
|
|
446
275
|
expect(gridApi.core.getVisibleRows()).toHaveLength(3);
|
|
447
276
|
});
|
|
448
277
|
});
|