@ornery/ui-grid-react 0.1.4 → 0.1.6
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/UiGrid.d.ts +11 -0
- package/dist/UiGrid.d.ts.map +1 -0
- package/dist/gridStateMath.d.ts +8 -0
- package/dist/gridStateMath.d.ts.map +1 -0
- package/dist/index.d.ts +13 -133
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1248 -1202
- package/dist/index.mjs +1198 -1131
- package/dist/mountUiGrid.d.ts +4 -0
- package/dist/mountUiGrid.d.ts.map +1 -0
- package/dist/rustWasmGridEngine.d.ts +8 -0
- package/dist/rustWasmGridEngine.d.ts.map +1 -0
- package/dist/{index.d.mts → useGridState.d.ts} +14 -37
- package/dist/useGridState.d.ts.map +1 -0
- package/dist/useVirtualScroll.d.ts +20 -0
- package/dist/useVirtualScroll.d.ts.map +1 -0
- package/dist/virtualScrollMath.d.ts +17 -0
- package/dist/virtualScrollMath.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/UiGrid.test.tsx +2 -1
- package/src/UiGrid.tsx +330 -74
- package/src/gridStateMath.test.ts +49 -0
- package/src/gridStateMath.ts +32 -0
- package/src/index.ts +3 -0
- package/src/mountUiGrid.tsx +10 -0
- package/src/rustWasmGridEngine.test.ts +56 -0
- package/src/rustWasmGridEngine.ts +23 -0
- package/src/ui-grid.css +161 -1
- package/src/useGridState.ts +664 -343
- package/src/useVirtualScroll.ts +13 -10
- package/src/virtualScrollMath.test.ts +44 -0
- package/src/virtualScrollMath.ts +36 -0
- package/tsconfig.build.json +6 -0
- package/tsconfig.dts.json +15 -0
- package/CLAUDE.md +0 -283
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { createRoot, type Root } from 'react-dom/client';
|
|
3
|
+
|
|
4
|
+
import { UiGrid, type UiGridProps } from './UiGrid';
|
|
5
|
+
|
|
6
|
+
export function mountUiGrid(container: Element | DocumentFragment, props: UiGridProps): Root {
|
|
7
|
+
const root = createRoot(container);
|
|
8
|
+
root.render(React.createElement(UiGrid, props));
|
|
9
|
+
return root;
|
|
10
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
activeGridEngineBackend,
|
|
4
|
+
clearRustWasmGridEngine,
|
|
5
|
+
defaultGridEngine,
|
|
6
|
+
} from '@ornery/ui-grid';
|
|
7
|
+
import { registerReactUiGridWasmEngineFromModule } from './rustWasmGridEngine';
|
|
8
|
+
import { SORT_DIRECTIONS } from '@ornery/ui-grid';
|
|
9
|
+
import type { BuildGridPipelineContext, PipelineResult } from '@ornery/ui-grid';
|
|
10
|
+
|
|
11
|
+
function createContext(): BuildGridPipelineContext {
|
|
12
|
+
return {
|
|
13
|
+
options: {
|
|
14
|
+
id: 'react-engine-spec',
|
|
15
|
+
data: [
|
|
16
|
+
{ id: 'row-1', owner: 'Alice' },
|
|
17
|
+
{ id: 'row-2', owner: 'Bob' },
|
|
18
|
+
],
|
|
19
|
+
columnDefs: [{ name: 'owner' }],
|
|
20
|
+
},
|
|
21
|
+
columns: [{ name: 'owner' }],
|
|
22
|
+
activeFilters: {},
|
|
23
|
+
sortState: { columnName: null, direction: SORT_DIRECTIONS.none },
|
|
24
|
+
groupByColumns: [],
|
|
25
|
+
collapsedGroups: {},
|
|
26
|
+
hiddenRowReasons: {},
|
|
27
|
+
expandedRows: {},
|
|
28
|
+
expandedTreeRows: {},
|
|
29
|
+
currentPage: 1,
|
|
30
|
+
pageSize: 0,
|
|
31
|
+
rowSize: 44,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe('rustWasmGridEngine', () => {
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
clearRustWasmGridEngine();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('registers the real module shape into the shared engine seam', () => {
|
|
41
|
+
const sentinel: PipelineResult = {
|
|
42
|
+
visibleRows: [],
|
|
43
|
+
displayItems: [],
|
|
44
|
+
virtualizationEnabled: true,
|
|
45
|
+
pipelineMs: 0,
|
|
46
|
+
totalItems: 77,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
registerReactUiGridWasmEngineFromModule({
|
|
50
|
+
build_pipeline_js: () => sentinel,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(defaultGridEngine.buildPipeline(createContext())).toBe(sentinel);
|
|
54
|
+
expect(activeGridEngineBackend()).toBe('rust-wasm');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { BuildGridPipelineContext, PipelineResult } from '@ornery/ui-grid';
|
|
2
|
+
import { registerRustWasmGridEngine } from '@ornery/ui-grid';
|
|
3
|
+
|
|
4
|
+
const uiGridWasmModulePath = '../../../dist/ui-grid-wasm-web/ui_grid_wasm.js';
|
|
5
|
+
const uiGridWasmBinaryPath = '/dist/ui-grid-wasm-web/ui_grid_wasm_bg.wasm';
|
|
6
|
+
|
|
7
|
+
type UiGridWasmModule = {
|
|
8
|
+
build_pipeline_js(context: unknown): PipelineResult;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function registerReactUiGridWasmEngineFromModule(module: UiGridWasmModule): void {
|
|
12
|
+
registerRustWasmGridEngine({
|
|
13
|
+
buildPipeline(context: BuildGridPipelineContext): PipelineResult {
|
|
14
|
+
return module.build_pipeline_js(context);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function enableReactUiGridWasmEngine(): Promise<void> {
|
|
20
|
+
const module = await import(/* @vite-ignore */ uiGridWasmModulePath);
|
|
21
|
+
await module.default(uiGridWasmBinaryPath);
|
|
22
|
+
registerReactUiGridWasmEngineFromModule(module);
|
|
23
|
+
}
|
package/src/ui-grid.css
CHANGED
|
@@ -20,6 +20,17 @@
|
|
|
20
20
|
--ui-grid-status-enterprise-color: var(--app-ui-grid-status-enterprise-color, #115e59);
|
|
21
21
|
--ui-grid-status-pilot-bg: var(--app-ui-grid-status-pilot-bg, rgba(234, 88, 12, 0.14));
|
|
22
22
|
--ui-grid-status-pilot-color: var(--app-ui-grid-status-pilot-color, #c2410c);
|
|
23
|
+
--ui-grid-pin-menu-open-z-index: var(--app-ui-grid-pin-menu-open-z-index, 8);
|
|
24
|
+
--ui-grid-pin-menu-z-index: var(--app-ui-grid-pin-menu-z-index, 20);
|
|
25
|
+
--ui-grid-pin-menu-gap: var(--app-ui-grid-pin-menu-gap, 0.25rem);
|
|
26
|
+
--ui-grid-pin-menu-padding: var(--app-ui-grid-pin-menu-padding, 0.25rem);
|
|
27
|
+
--ui-grid-pin-menu-radius: var(--app-ui-grid-pin-menu-radius, 999px);
|
|
28
|
+
--ui-grid-pin-menu-shadow: var(--app-ui-grid-pin-menu-shadow, 0 10px 24px color-mix(in srgb, var(--ui-grid-cell-color) 10%, transparent));
|
|
29
|
+
--ui-grid-pin-menu-action-size: var(--app-ui-grid-pin-menu-action-size, 1.75rem);
|
|
30
|
+
--ui-grid-pin-control-collapsed-size: var(--app-ui-grid-pin-control-collapsed-size, 1px);
|
|
31
|
+
--ui-grid-pin-control-transition-duration: var(--app-ui-grid-pin-control-transition-duration, 160ms);
|
|
32
|
+
--ui-grid-pin-control-transition-easing: var(--app-ui-grid-pin-control-transition-easing, cubic-bezier(0.22, 1, 0.36, 1));
|
|
33
|
+
--ui-grid-pin-menu-scale-closed: var(--app-ui-grid-pin-menu-scale-closed, 0.72);
|
|
23
34
|
display: block;
|
|
24
35
|
color: var(--ui-grid-cell-color);
|
|
25
36
|
}
|
|
@@ -39,12 +50,18 @@
|
|
|
39
50
|
.grid-hero {
|
|
40
51
|
display: flex;
|
|
41
52
|
justify-content: space-between;
|
|
53
|
+
flex-wrap: wrap;
|
|
42
54
|
gap: 1.5rem;
|
|
43
|
-
align-items:
|
|
55
|
+
align-items: flex-start;
|
|
44
56
|
padding: 1rem 0;
|
|
45
57
|
color: var(--ui-grid-cell-color);
|
|
46
58
|
}
|
|
47
59
|
|
|
60
|
+
.grid-hero > :first-child {
|
|
61
|
+
flex: 1 1 28rem;
|
|
62
|
+
min-width: min(100%, 20rem);
|
|
63
|
+
}
|
|
64
|
+
|
|
48
65
|
.ui-grid-host .eyebrow {
|
|
49
66
|
margin: 0 0 0.5rem;
|
|
50
67
|
text-transform: uppercase;
|
|
@@ -70,6 +87,9 @@
|
|
|
70
87
|
gap: 1rem;
|
|
71
88
|
align-items: center;
|
|
72
89
|
flex-wrap: wrap;
|
|
90
|
+
flex: 0 1 auto;
|
|
91
|
+
margin-left: auto;
|
|
92
|
+
justify-content: flex-end;
|
|
73
93
|
}
|
|
74
94
|
|
|
75
95
|
.action {
|
|
@@ -168,6 +188,22 @@
|
|
|
168
188
|
.filter-grid,
|
|
169
189
|
.body-grid {
|
|
170
190
|
display: grid;
|
|
191
|
+
width: max-content;
|
|
192
|
+
min-width: 100%;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.header-grid,
|
|
196
|
+
.filter-grid {
|
|
197
|
+
position: sticky;
|
|
198
|
+
z-index: 3;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.header-grid {
|
|
202
|
+
top: 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.filter-grid {
|
|
206
|
+
top: var(--ui-grid-header-sticky-top, 0px);
|
|
171
207
|
}
|
|
172
208
|
|
|
173
209
|
.header-cell,
|
|
@@ -192,8 +228,18 @@
|
|
|
192
228
|
background: color-mix(in srgb, var(--ui-grid-accent) 8%, var(--ui-grid-header-background));
|
|
193
229
|
}
|
|
194
230
|
|
|
231
|
+
.header-cell.is-pin-menu-open {
|
|
232
|
+
z-index: var(--ui-grid-pin-menu-open-z-index);
|
|
233
|
+
}
|
|
234
|
+
|
|
195
235
|
.header-label {
|
|
196
236
|
min-width: 0;
|
|
237
|
+
display: block;
|
|
238
|
+
line-height: 1.25;
|
|
239
|
+
white-space: nowrap;
|
|
240
|
+
overflow: hidden;
|
|
241
|
+
text-overflow: clip;
|
|
242
|
+
hyphens: none;
|
|
197
243
|
}
|
|
198
244
|
|
|
199
245
|
.header-actions {
|
|
@@ -201,6 +247,8 @@
|
|
|
201
247
|
align-items: center;
|
|
202
248
|
gap: 0.4rem;
|
|
203
249
|
justify-self: end;
|
|
250
|
+
flex-wrap: nowrap;
|
|
251
|
+
flex-shrink: 0;
|
|
204
252
|
}
|
|
205
253
|
|
|
206
254
|
.header-action,
|
|
@@ -250,14 +298,115 @@
|
|
|
250
298
|
color: var(--ui-grid-accent);
|
|
251
299
|
}
|
|
252
300
|
|
|
301
|
+
.pin-control {
|
|
302
|
+
position: relative;
|
|
303
|
+
display: inline-grid;
|
|
304
|
+
place-items: center;
|
|
305
|
+
justify-items: center;
|
|
306
|
+
min-width: 2rem;
|
|
307
|
+
overflow: hidden;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.pin-trigger {
|
|
311
|
+
grid-area: 1 / 1;
|
|
312
|
+
transform-origin: center;
|
|
313
|
+
transition:
|
|
314
|
+
width var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing),
|
|
315
|
+
height var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing),
|
|
316
|
+
opacity var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing),
|
|
317
|
+
transform var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing),
|
|
318
|
+
border-color var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing),
|
|
319
|
+
background-color var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing),
|
|
320
|
+
color var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.pin-menu {
|
|
324
|
+
grid-area: 1 / 1;
|
|
325
|
+
z-index: var(--ui-grid-pin-menu-z-index);
|
|
326
|
+
display: grid;
|
|
327
|
+
grid-auto-rows: var(--ui-grid-pin-menu-action-size);
|
|
328
|
+
gap: var(--ui-grid-pin-menu-gap);
|
|
329
|
+
padding: var(--ui-grid-pin-menu-padding);
|
|
330
|
+
border: 1px solid var(--ui-grid-border-color);
|
|
331
|
+
border-radius: var(--ui-grid-pin-menu-radius);
|
|
332
|
+
background: var(--ui-grid-surface);
|
|
333
|
+
box-shadow: var(--ui-grid-pin-menu-shadow);
|
|
334
|
+
justify-items: center;
|
|
335
|
+
align-items: center;
|
|
336
|
+
width: 2rem;
|
|
337
|
+
max-height: var(--ui-grid-pin-control-collapsed-size);
|
|
338
|
+
opacity: 0;
|
|
339
|
+
pointer-events: none;
|
|
340
|
+
transform: scale(var(--ui-grid-pin-menu-scale-closed));
|
|
341
|
+
transform-origin: center;
|
|
342
|
+
transition:
|
|
343
|
+
max-height var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing),
|
|
344
|
+
opacity var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing),
|
|
345
|
+
transform var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing),
|
|
346
|
+
padding var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing),
|
|
347
|
+
border-color var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing),
|
|
348
|
+
box-shadow var(--ui-grid-pin-control-transition-duration) var(--ui-grid-pin-control-transition-easing);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.pin-control-open {
|
|
352
|
+
align-items: start;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.pin-control-open .pin-trigger {
|
|
356
|
+
width: var(--ui-grid-pin-control-collapsed-size);
|
|
357
|
+
height: var(--ui-grid-pin-control-collapsed-size);
|
|
358
|
+
opacity: 0;
|
|
359
|
+
transform: scale(0.72);
|
|
360
|
+
pointer-events: none;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
.pin-control-open .pin-menu {
|
|
364
|
+
max-height: calc((var(--ui-grid-pin-menu-action-size) * 2) + var(--ui-grid-pin-menu-gap) + (var(--ui-grid-pin-menu-padding) * 2));
|
|
365
|
+
opacity: 1;
|
|
366
|
+
pointer-events: auto;
|
|
367
|
+
transform: scale(1);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.pin-menu-action {
|
|
371
|
+
display: inline-flex;
|
|
372
|
+
align-items: center;
|
|
373
|
+
justify-content: center;
|
|
374
|
+
width: var(--ui-grid-pin-menu-action-size);
|
|
375
|
+
height: var(--ui-grid-pin-menu-action-size);
|
|
376
|
+
border: 0;
|
|
377
|
+
border-radius: 999px;
|
|
378
|
+
background: transparent;
|
|
379
|
+
color: var(--ui-grid-cell-color);
|
|
380
|
+
cursor: pointer;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.pin-menu-action:hover,
|
|
384
|
+
.pin-menu-action:focus-visible {
|
|
385
|
+
outline: 0;
|
|
386
|
+
background: color-mix(in srgb, var(--ui-grid-accent) 12%, var(--ui-grid-surface));
|
|
387
|
+
color: var(--ui-grid-accent);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.pin-menu-action svg {
|
|
391
|
+
width: 1rem;
|
|
392
|
+
height: 1rem;
|
|
393
|
+
fill: currentColor;
|
|
394
|
+
}
|
|
395
|
+
|
|
253
396
|
.filter-cell {
|
|
254
397
|
padding: 0.75rem 1rem 1rem;
|
|
255
398
|
border-bottom: 1px solid var(--ui-grid-border-color);
|
|
256
399
|
background: var(--ui-grid-header-background);
|
|
400
|
+
overflow: hidden;
|
|
257
401
|
}
|
|
258
402
|
|
|
259
403
|
.filter-cell input {
|
|
404
|
+
display: block;
|
|
260
405
|
width: 100%;
|
|
406
|
+
min-width: 0;
|
|
407
|
+
max-width: 100%;
|
|
408
|
+
min-inline-size: 0;
|
|
409
|
+
max-inline-size: 100%;
|
|
261
410
|
border: 1px solid var(--ui-grid-border-color);
|
|
262
411
|
border-radius: var(--ui-grid-radius);
|
|
263
412
|
background: var(--ui-grid-surface);
|
|
@@ -390,6 +539,17 @@
|
|
|
390
539
|
width: 100%;
|
|
391
540
|
}
|
|
392
541
|
|
|
542
|
+
.grid-virtual-spacer {
|
|
543
|
+
position: relative;
|
|
544
|
+
width: max-content;
|
|
545
|
+
min-width: 100%;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.grid-virtual-body {
|
|
549
|
+
position: absolute;
|
|
550
|
+
left: 0;
|
|
551
|
+
}
|
|
552
|
+
|
|
393
553
|
.body-cell.align-center {
|
|
394
554
|
text-align: center;
|
|
395
555
|
}
|