@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
|
@@ -28,7 +28,7 @@ describe('gridStateMath', () => {
|
|
|
28
28
|
it('builds grid template columns deterministically', () => {
|
|
29
29
|
expect(
|
|
30
30
|
buildGridTemplateColumns(orderVisibleColumns(columns, ['status', 'revenue', 'customer'])),
|
|
31
|
-
).toBe('2fr 120px minmax(11rem,
|
|
31
|
+
).toBe('2fr 120px minmax(11rem, 1fr)');
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
it('resolves benchmark iterations with a minimum of one', () => {
|
|
@@ -43,9 +43,9 @@ describe('gridStateMath', () => {
|
|
|
43
43
|
});
|
|
44
44
|
|
|
45
45
|
it('computes viewport height and viewport rows', () => {
|
|
46
|
-
expect(computeViewportHeightPx(undefined, undefined)).toBe('
|
|
46
|
+
expect(computeViewportHeightPx(undefined, undefined)).toBe('440px');
|
|
47
47
|
expect(computeViewportHeightPx(620, 480)).toBe('620px');
|
|
48
|
-
expect(computeViewportRows(undefined, undefined)).toBe(
|
|
48
|
+
expect(computeViewportRows(undefined, undefined)).toBe(10);
|
|
49
49
|
expect(computeViewportRows(220, 44)).toBe(5);
|
|
50
50
|
});
|
|
51
51
|
});
|
package/src/gridStateMath.ts
CHANGED
|
@@ -34,12 +34,15 @@ export function formatPaginationSummary(
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
export function computeViewportHeightPx(
|
|
37
|
-
viewportHeight?: number,
|
|
38
37
|
autoViewportHeight?: number | null,
|
|
38
|
+
minRowsToShow?: number,
|
|
39
|
+
rowHeight?: number,
|
|
39
40
|
): string {
|
|
40
|
-
|
|
41
|
+
const fallback = (minRowsToShow ?? 10) * (rowHeight ?? 44);
|
|
42
|
+
return `${autoViewportHeight ?? fallback}px`;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
|
-
export function computeViewportRows(
|
|
44
|
-
|
|
45
|
+
export function computeViewportRows(autoViewportHeight?: number | null, rowHeight?: number, minRowsToShow?: number): number {
|
|
46
|
+
const height = autoViewportHeight ?? (minRowsToShow ?? 10) * (rowHeight ?? 44);
|
|
47
|
+
return Math.max(1, Math.ceil(height / (rowHeight ?? 44)));
|
|
45
48
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,27 +1,11 @@
|
|
|
1
1
|
export { UiGrid } from './UiGrid';
|
|
2
|
-
export type { UiGridProps } from './UiGrid';
|
|
3
|
-
export { mountUiGrid, updateUiGrid, styledCell } from './mountUiGrid';
|
|
2
|
+
export type { UiGridProps, UiGridCellRenderers } from './UiGrid';
|
|
3
|
+
export { mountUiGrid, updateUiGrid, styledCell, datePickerCell } from './mountUiGrid';
|
|
4
4
|
export {
|
|
5
5
|
mountUiGridCustomElement,
|
|
6
6
|
type MountUiGridCustomElementOptions,
|
|
7
7
|
type MountedUiGridCustomElement,
|
|
8
8
|
} from './vanillaAdapter';
|
|
9
|
-
export { useGridState } from './useGridState';
|
|
10
|
-
export type { UseGridStateResult } from './useGridState';
|
|
11
|
-
export { useVirtualScroll } from './useVirtualScroll';
|
|
12
|
-
export type { UseVirtualScrollOptions, UseVirtualScrollResult } from './useVirtualScroll';
|
|
13
|
-
export {
|
|
14
|
-
orderVisibleColumns,
|
|
15
|
-
buildGridTemplateColumns,
|
|
16
|
-
resolveBenchmarkIterations,
|
|
17
|
-
formatPaginationSummary,
|
|
18
|
-
computeViewportHeightPx,
|
|
19
|
-
computeViewportRows,
|
|
20
|
-
} from './gridStateMath';
|
|
21
|
-
export {
|
|
22
|
-
enableReactUiGridWasmEngine,
|
|
23
|
-
registerReactUiGridWasmEngineFromModule,
|
|
24
|
-
} from './rustWasmGridEngine';
|
|
25
9
|
|
|
26
10
|
export type {
|
|
27
11
|
GridOptions,
|
package/src/mountUiGrid.tsx
CHANGED
|
@@ -25,4 +25,30 @@ export function styledCell(
|
|
|
25
25
|
{ style: { color, fontVariantNumeric: 'tabular-nums', ...extraStyle } },
|
|
26
26
|
text,
|
|
27
27
|
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Create a date <input> React node — usable from non-TSX contexts. */
|
|
31
|
+
export function datePickerCell(
|
|
32
|
+
value: string,
|
|
33
|
+
onChange?: (newValue: string) => void,
|
|
34
|
+
extraStyle?: React.CSSProperties,
|
|
35
|
+
): React.ReactNode {
|
|
36
|
+
return React.createElement('input', {
|
|
37
|
+
type: 'date',
|
|
38
|
+
value: value || '',
|
|
39
|
+
onChange: onChange
|
|
40
|
+
? (e: React.ChangeEvent<HTMLInputElement>) => onChange(e.target.value)
|
|
41
|
+
: undefined,
|
|
42
|
+
style: {
|
|
43
|
+
font: 'inherit',
|
|
44
|
+
fontSize: '0.85rem',
|
|
45
|
+
border: '1px solid color-mix(in srgb, currentColor 20%, transparent)',
|
|
46
|
+
borderRadius: '6px',
|
|
47
|
+
padding: '0.2rem 0.4rem',
|
|
48
|
+
background: 'var(--ui-grid-surface, white)',
|
|
49
|
+
color: 'inherit',
|
|
50
|
+
cursor: 'pointer',
|
|
51
|
+
...extraStyle,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
28
54
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
if (typeof ShadowRoot !== 'undefined') {
|
|
2
|
+
const proto = ShadowRoot.prototype as unknown as Record<string, unknown>;
|
|
3
|
+
if (!('adoptedStyleSheets' in proto)) {
|
|
4
|
+
Object.defineProperty(proto, 'adoptedStyleSheets', {
|
|
5
|
+
get() {
|
|
6
|
+
return (this as unknown as Record<string, unknown>)['_adoptedStyleSheets'] ?? [];
|
|
7
|
+
},
|
|
8
|
+
set(sheets: CSSStyleSheet[]) {
|
|
9
|
+
(this as unknown as Record<string, unknown>)['_adoptedStyleSheets'] = sheets;
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
package/src/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,
|
package/src/useGridState.ts
CHANGED
|
@@ -1183,9 +1183,9 @@ export function useGridState(
|
|
|
1183
1183
|
|
|
1184
1184
|
// --- Auto resize effect ---
|
|
1185
1185
|
|
|
1186
|
-
// Auto-resize is on by default so the grid fills its container.
|
|
1187
|
-
//
|
|
1188
|
-
//
|
|
1186
|
+
// Auto-resize is on by default so the grid fills its container. The
|
|
1187
|
+
// ResizeObserver measures the host element and writes `autoViewportHeight`
|
|
1188
|
+
// so the grid always fills available space (matching the old ui-grid).
|
|
1189
1189
|
useEffect(() => {
|
|
1190
1190
|
if (!FEATURE_AUTO_RESIZE) return;
|
|
1191
1191
|
|
|
@@ -1206,14 +1206,14 @@ export function useGridState(
|
|
|
1206
1206
|
lastGridHeightRef.current = nextHeight;
|
|
1207
1207
|
lastGridWidthRef.current = nextWidth;
|
|
1208
1208
|
|
|
1209
|
-
if (
|
|
1209
|
+
if (nextHeight > 0) {
|
|
1210
1210
|
setAutoViewportHeight(nextHeight);
|
|
1211
1211
|
}
|
|
1212
1212
|
});
|
|
1213
1213
|
|
|
1214
1214
|
if (!observer) return;
|
|
1215
1215
|
return () => observer.disconnect();
|
|
1216
|
-
}, [options.enableAutoResize,
|
|
1216
|
+
}, [options.enableAutoResize, gridApi]);
|
|
1217
1217
|
|
|
1218
1218
|
// --- Computed values ---
|
|
1219
1219
|
|
|
@@ -1225,7 +1225,7 @@ export function useGridState(
|
|
|
1225
1225
|
const paginationCurrentPage = getCurrentPageValueFn();
|
|
1226
1226
|
const paginationTotalPages = getTotalPagesValueFn();
|
|
1227
1227
|
const paginationSelectedPageSize = effectivePageSizeFn(pipeline.totalItems);
|
|
1228
|
-
const viewportHeightPx = computeViewportHeightPx(options.
|
|
1228
|
+
const viewportHeightPx = computeViewportHeightPx(autoViewportHeight, options.minRowsToShow, options.rowHeight);
|
|
1229
1229
|
|
|
1230
1230
|
// --- Display helper functions ---
|
|
1231
1231
|
|
|
@@ -1770,8 +1770,9 @@ export function useGridState(
|
|
|
1770
1770
|
startIndex,
|
|
1771
1771
|
visibleRows: pipelineRef.current.visibleRows.length,
|
|
1772
1772
|
viewportRows: computeViewportRows(
|
|
1773
|
-
|
|
1773
|
+
autoViewportHeight,
|
|
1774
1774
|
optionsRef.current.rowHeight,
|
|
1775
|
+
optionsRef.current.minRowsToShow,
|
|
1775
1776
|
),
|
|
1776
1777
|
threshold: optionsRef.current.infiniteScrollRowsFromEnd ?? 20,
|
|
1777
1778
|
setState: (state) => setInfiniteScrollState(state),
|
package/tsconfig.dts.json
CHANGED
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
"outDir": "./dist",
|
|
8
8
|
"rootDir": "./src",
|
|
9
9
|
"paths": {
|
|
10
|
-
"@ornery/ui-grid-core": ["../ui-grid-core/dist/index.d.ts"]
|
|
10
|
+
"@ornery/ui-grid-core": ["../ui-grid-core/dist/index.d.ts"],
|
|
11
|
+
"@ornery/ui-grid-vanilla": ["../ui-grid-vanilla/dist/index.d.ts"]
|
|
11
12
|
}
|
|
12
13
|
},
|
|
13
14
|
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
|
14
|
-
"exclude": ["src/**/*.test.ts", "src/**/*.test.tsx"]
|
|
15
|
+
"exclude": ["src/**/*.test.ts", "src/**/*.test.tsx", "src/test-setup.ts"]
|
|
15
16
|
}
|
package/tsconfig.json
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
"declarationMap": true,
|
|
8
8
|
"baseUrl": ".",
|
|
9
9
|
"paths": {
|
|
10
|
-
"@ornery/ui-grid-core": ["../ui-grid-core/src/index.ts"]
|
|
10
|
+
"@ornery/ui-grid-core": ["../ui-grid-core/src/index.ts"],
|
|
11
|
+
"@ornery/ui-grid-vanilla": ["../ui-grid-vanilla/src/index.ts"]
|
|
11
12
|
}
|
|
12
13
|
},
|
|
13
14
|
"include": ["src"]
|
package/vitest.config.ts
CHANGED
|
@@ -5,10 +5,12 @@ export default defineConfig({
|
|
|
5
5
|
resolve: {
|
|
6
6
|
alias: {
|
|
7
7
|
'@ornery/ui-grid-core': path.resolve(__dirname, '../ui-grid-core/src/index.ts'),
|
|
8
|
+
'@ornery/ui-grid-vanilla': path.resolve(__dirname, '../ui-grid-vanilla/src/index.ts'),
|
|
8
9
|
},
|
|
9
10
|
},
|
|
10
11
|
test: {
|
|
11
12
|
environment: 'jsdom',
|
|
12
13
|
globals: true,
|
|
14
|
+
setupFiles: ['./src/test-setup.ts'],
|
|
13
15
|
},
|
|
14
16
|
});
|