docs(changeset): Eslint, fixes on container rendering

This commit is contained in:
Hein
2025-10-22 13:17:42 +02:00
parent 2f0db1f0e3
commit 0f7cf52432
15 changed files with 314 additions and 257 deletions

View File

@@ -6,7 +6,7 @@ import {
type GridColumn,
} from '@glideapps/glide-data-grid';
import { Group, Stack } from '@mantine/core';
import { useMergedRef } from '@mantine/hooks';
import { useElementSize, useMergedRef } from '@mantine/hooks';
import React from 'react';
import { BottomBar } from './components/BottomBar';
@@ -24,6 +24,8 @@ export const GridlerDataGrid = () => {
const ref = React.useRef<DataEditorRef | null>(null);
const refContextActivated = React.useRef<boolean>(false);
const { height, ref: refWrapper, width } = useElementSize();
const {
_gridSelection,
focused,
@@ -86,18 +88,16 @@ export const GridlerDataGrid = () => {
setStateFN('_glideref', () => {
return r ?? undefined;
});
const ready = getState('ready');
const newReady = !!(r && mounted);
if (ready !== newReady) {
setState('ready', newReady);
}
});
const theme = useGridTheme();
if (!mounted) {
return (
<>
Loading...
<Computer />
</>
);
}
return (
<Stack
align="stretch"
@@ -115,7 +115,7 @@ export const GridlerDataGrid = () => {
//Yes this is a litle hacky, but it works to prevent double context menu
if (!refContextActivated.current) {
refContextActivated.current = true;
onContextClick('other', e);
onContextClick('other', e as any);
setTimeout(() => {
refContextActivated.current = false;
}, 100);
@@ -123,100 +123,112 @@ export const GridlerDataGrid = () => {
}}
>
{sections?.left}
<DataEditor
cellActivationBehavior="double-click"
//getCelrefMergedlContent={getCellContent}
columns={(renderColumns as Array<GridColumn>) ?? []}
columnSelect="none"
drawFocusRing
getCellContent={getCellContent}
getCellsForSelection={getCellsForSelection}
getRowThemeOverride={theme.getRowThemeOverride}
gridSelection={_gridSelection}
headerHeight={headerHeight ?? 32}
headerIcons={{ sort: SortSprite, sortdown: SortDownSprite, sortup: SortUpSprite }}
onCellContextMenu={(cell, event) => {
event.preventDefault();
if (!refContextActivated.current) {
refContextActivated.current = true;
onContextClick('cell', event, cell[0], cell[1]);
setTimeout(() => {
refContextActivated.current = false;
}, 100);
}
<div
ref={refWrapper}
style={{
flexGrow: 2,
height: '100%',
minHeight: '80px',
width: '100%',
}}
onCellEdited={onCellEdited}
onColumnMoved={onColumnMoved}
onColumnProposeMove={onColumnProposeMove}
onColumnResize={onColumnResize}
onGridSelectionChange={(selection) => {
let rows = CompactSelection.empty();
const currentSelection = getState('_gridSelection');
for (const r of selection.rows) {
rows = rows.hasIndex(r) ? rows : rows.add(r);
}
if (selectMode === 'row' && selection.current?.range) {
for (
let y = selection.current.range.y;
y < selection.current.range.y + selection.current.range.height;
y++
) {
rows = rows.hasIndex(y) ? rows : rows.add(y);
>
{width && width > 0 && height && height > 0 && (
<DataEditor
cellActivationBehavior="double-click"
//getCelrefMergedlContent={getCellContent}
columns={(renderColumns as Array<GridColumn>) ?? []}
columnSelect="none"
drawFocusRing
getCellContent={getCellContent}
getCellsForSelection={getCellsForSelection}
getRowThemeOverride={theme.getRowThemeOverride}
gridSelection={_gridSelection}
headerHeight={headerHeight ?? 32}
headerIcons={{ sort: SortSprite, sortdown: SortDownSprite, sortup: SortUpSprite }}
height={(height ?? 400) - 4}
onCellContextMenu={(cell, event) => {
event.preventDefault();
if (!refContextActivated.current) {
refContextActivated.current = true;
onContextClick('cell', event, cell[0], cell[1]);
setTimeout(() => {
refContextActivated.current = false;
}, 100);
}
}}
onCellEdited={onCellEdited}
onColumnMoved={onColumnMoved}
onColumnProposeMove={onColumnProposeMove}
onColumnResize={onColumnResize}
onGridSelectionChange={(selection) => {
let rows = CompactSelection.empty();
const currentSelection = getState('_gridSelection');
for (const r of selection.rows) {
rows = rows.hasIndex(r) ? rows : rows.add(r);
}
if (selectMode === 'row' && selection.current?.range) {
for (
let y = selection.current.range.y;
y < selection.current.range.y + selection.current.range.height;
y++
) {
rows = rows.hasIndex(y) ? rows : rows.add(y);
}
}
if (
JSON.stringify(currentSelection?.columns) !== JSON.stringify(selection.columns) ||
JSON.stringify(currentSelection?.rows) !== JSON.stringify(rows) ||
JSON.stringify(currentSelection?.current) !== JSON.stringify(selection.current)
) {
setState('_gridSelection', { ...selection, rows });
if (JSON.stringify(currentSelection?.rows) !== JSON.stringify(rows)) {
setState('_gridSelectionRows', rows);
}
}
//console.log('Selection', selection);
}}
onHeaderClicked={onHeaderClicked}
onHeaderContextMenu={(col, event) => {
event.preventDefault();
if (!refContextActivated.current) {
refContextActivated.current = true;
onContextClick('header', event as any, col);
setTimeout(() => {
refContextActivated.current = false;
}, 100);
}
}}
onHeaderMenuClick={onHeaderMenuClick}
onItemHovered={onItemHovered}
onVisibleRegionChanged={onVisibleRegionChanged}
rangeSelect="multi-rect"
ref={refMerged as React.Ref<DataEditorRef>}
rightElement={
<Group>
{sections?.rightElementStart}
<RightMenuIcon />
{sections?.rightElementEnd}
</Group>
}
}
if (
JSON.stringify(currentSelection?.columns) !== JSON.stringify(selection.columns) ||
JSON.stringify(currentSelection?.rows) !== JSON.stringify(rows) ||
JSON.stringify(currentSelection?.current) !== JSON.stringify(selection.current)
) {
setState('_gridSelection', { ...selection, rows });
if (JSON.stringify(currentSelection?.rows) !== JSON.stringify(rows)) {
setState('_gridSelectionRows', rows);
}
}
//console.log('Selection', selection);
}}
onHeaderClicked={onHeaderClicked}
onHeaderContextMenu={(col, event) => {
event.preventDefault();
if (!refContextActivated.current) {
refContextActivated.current = true;
onContextClick('header', event, col);
setTimeout(() => {
refContextActivated.current = false;
}, 100);
}
}}
onHeaderMenuClick={onHeaderMenuClick}
onItemHovered={onItemHovered}
onVisibleRegionChanged={onVisibleRegionChanged}
rangeSelect="multi-rect"
ref={refMerged as any}
rightElement={
<Group>
{sections?.rightElementStart}
<RightMenuIcon />
{sections?.rightElementEnd}
</Group>
}
rowHeight={rowHeight ?? 22}
//rowMarkersCheckboxStyle='square'
//rowMarkersKind='both'
rowMarkers={{
checkboxStyle: 'square',
kind: 'both',
}}
rows={total_rows ?? 0}
rowSelect="multi"
rowSelectionMode="auto"
spanRangeBehavior="default"
theme={theme.gridTheme}
width="100%"
{...glideProps}
/>
rowHeight={rowHeight ?? 22}
//rowMarkersCheckboxStyle='square'
//rowMarkersKind='both'
rowMarkers={{
checkboxStyle: 'square',
kind: 'both',
}}
rows={total_rows ?? 0}
rowSelect="multi"
rowSelectionMode="auto"
spanRangeBehavior="default"
theme={theme.gridTheme}
width={width ?? 200}
{...glideProps}
/>
)}
</div>
{/* </Portal> */}
<Computer />
{!hasLocalData && <Pager />}

View File

@@ -1,3 +1,4 @@
/* eslint-disable react/react-in-jsx-scope */
import { useGridlerStore } from './GridlerStore';
export function BottomBar() {

View File

@@ -1,4 +1,3 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { CompactSelection } from '@glideapps/glide-data-grid';
import React, { useEffect, useRef } from 'react';
@@ -7,7 +6,7 @@ import { useGridlerStore } from './GridlerStore';
//The computer component does not need to be recalculated on every render, so we use React.memo to prevent unnecessary re-renders.
export const Computer = React.memo(() => {
const refFirstRun = useRef(0);
const refLastFilters = useRef<any>(null);
const refLastFilters = useRef<unknown>(null);
const {
_glideref,
_gridSelectionRows,
@@ -19,6 +18,7 @@ export const Computer = React.memo(() => {
columns,
getState,
loadPage,
ready,
setState,
setStateFN,
@@ -34,6 +34,7 @@ export const Computer = React.memo(() => {
columns: s.columns,
getState: s.getState,
loadPage: s.loadPage,
ready: s.ready,
setState: s.setState,
setStateFN: s.setStateFN,
@@ -47,7 +48,7 @@ export const Computer = React.memo(() => {
const pageSize = getState('pageSize');
const keyField = getState('keyField') ?? 'id';
const rowIndexes = [];
for (const vi in values as Array<any>) {
for (const vi in values as Array<Record<string, unknown>>) {
let rowIndex = -1;
const key = String(
typeof values?.[vi] === 'object'
@@ -232,7 +233,7 @@ export const Computer = React.memo(() => {
}
refFirstRun.current = 1;
loadPage(0);
}, [_glideref]);
}, [ready, loadPage]);
// console.log('Gridler:Debug:Computer', {
// colFilters,
@@ -245,3 +246,5 @@ export const Computer = React.memo(() => {
return <></>;
});
Computer.displayName = 'Gridler-Computer';

View File

@@ -1,7 +1,10 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable react/react-in-jsx-scope */
/* eslint-disable react-refresh/only-export-components */
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
type CellArray,
type CellClickedEventArgs,
CompactSelection,
type DataEditorProps,
type DataEditorRef,
@@ -133,7 +136,7 @@ export interface GridlerState {
selection: Rectangle,
abortSignal: AbortSignal
) => CellArray | GetCellsThunk;
getRowBuffer: (row: number) => any;
getRowBuffer: (row: number) => Record<string, any>;
getState: <K extends keyof GridlerStoreState>(key: K) => GridlerStoreState[K];
hasLocalData: boolean;
@@ -149,7 +152,7 @@ export interface GridlerState {
colIndex: number,
newSizeWithGrow: number
) => void;
onContextClick: (area: string, event: any, col?: number, row?: number) => void;
onContextClick: (area: string, event: CellClickedEventArgs, col?: number, row?: number) => void;
onHeaderClicked: (colIndex: number, event: HeaderClickedEventArgs) => void;
onHeaderMenuClick: (col: number, screenPosition: Rectangle) => void;
onItemHovered: (args: GridMouseEventArgs) => void;
@@ -166,6 +169,7 @@ export interface GridlerState {
) => void;
pageSize: number;
ready: boolean;
reload?: () => Promise<void>;
renderColumns?: GridlerColumns;
setState: <K extends keyof GridlerStoreState>(
@@ -190,7 +194,7 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
_page_data: {},
_visibleArea: { height: 10000, width: 1000, x: 0, y: 0 },
_visiblePages: { height: 0, width: 0, x: 0, y: 0 },
addError: (err: string, ...args: Array<any>) => {
addError: (err: string, ...args: Array<unknown>) => {
const s = get();
console.log('Gridler Error', s.uniqueid, err, args);
set(
@@ -205,7 +209,7 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
const state = get();
const [col, row] = cell;
const buffer = state.getRowBuffer(row);
const buffer = state.getRowBuffer(row) as Record<string, string> | undefined;
if (buffer !== undefined) {
return state.toCell(buffer, col);
@@ -404,7 +408,7 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
}
},
onContextClick: (area: string, event: any, col?: number, row?: number) => {
onContextClick: (area: string, event: CellClickedEventArgs, col?: number, row?: number) => {
const s = get();
const coldef = s.renderColumns?.[col ?? -1];
@@ -490,7 +494,9 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
) ??
s.getMenuItems?.(area, s, col && row ? s.getRowBuffer(row) : undefined, coldef, items) ??
items,
//@ts-expect-error Check bounds
x: event.clientX ?? event.bounds?.x,
//@ts-expect-error Check bounds
y: event.clientY ?? event.bounds?.y,
});
},
@@ -681,8 +687,8 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
}, 100)
);
},
pageSize: 50,
ready: false,
setState: (key, value) => {
set(
produce((state) => {
@@ -695,7 +701,7 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
set(
produce((state) => {
if (typeof value === 'function') {
state[key] = (value as (value: any) => any)(state[key]);
state[key] = (value as (value: unknown) => unknown)(state[key]);
} else {
reject(new Error(`Not a function ${value}`));
throw Error(`Not a function ${value}`);
@@ -799,12 +805,13 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
/// logic to apply the selected row.
useEffect(() => {
const ready = getState('ready');
const ref = getState('_glideref');
const keyField = getState('keyField') ?? 'id';
const selectedRow = getState('selectedRow') ?? props.selectedRow;
const askAPIRowNumber = getState('askAPIRowNumber');
let rowIndex = -1;
if (selectedRow && ref) {
if (selectedRow && ref && ready) {
const page_data = getState('_page_data');
const pageSize = getState('pageSize');
for (const p in page_data) {

View File

@@ -63,3 +63,5 @@ export const Pager = React.memo(() => {
return <></>;
});
Pager.displayName = 'Gridler-Pager';

View File

@@ -14,7 +14,7 @@ export function RightMenuIcon() {
loading={loadingData}
mr="xs"
mt="2px"
onClick={(e) => onContextClick('menu', e)}
onClick={(e) => onContextClick('menu', e as any)}
variant="subtle"
>
<IconMenu2 />

View File

@@ -143,3 +143,5 @@ export const GlidlerAPIAdaptorForGoLangv2 = React.memo((props: APIOptions) => {
return <></>;
});
GlidlerAPIAdaptorForGoLangv2.displayName = 'Gridler-GlidlerAPIAdaptorForGoLangv2';

View File

@@ -27,3 +27,5 @@ export const GlidlerLocalDataAdaptor = React.memo((props: GlidlerLocalDataAdapto
return <></>;
});
GlidlerLocalDataAdaptor.displayName = 'Gridler-GlidlerLocalDataAdaptor';

View File

@@ -45,7 +45,7 @@ export const GridlerGoAPIExampleEventlog = () => {
];
return (
<Stack h="60vh">
<Stack h="80vh">
<h2>Demo Using Go API Adaptor</h2>
<TextInput label="API Url" onChange={(e) => setApiUrl(e.target.value)} value={apiUrl} />
<TextInput label="API Key" onChange={(e) => setApiKey(e.target.value)} value={apiKey} />

View File

@@ -6,7 +6,12 @@ import { fn } from 'storybook/test';
import { GridlerLocaldataExampleEventlog } from './Examples.localdata';
const Renderable = (props: any) => {
return <Box h="100%" mih="400px" miw="400px" w='100%' > <GridlerLocaldataExampleEventlog {...props} /></Box>;
return (
<Box h="100%" mih="400px" miw="400px" w="100%">
{' '}
<GridlerLocaldataExampleEventlog {...props} />
</Box>
);
};
const meta = {