Fixed the selection and rendering issues of the syncstore
This commit is contained in:
14
src/Gridler/components/BottomBar.tsx
Normal file
14
src/Gridler/components/BottomBar.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { useGridlerStore } from './Store';
|
||||
|
||||
export function BottomBar() {
|
||||
const { _activeTooltip, tooltipBarProps } = useGridlerStore((s) => ({
|
||||
_activeTooltip: s._activeTooltip,
|
||||
tooltipBarProps: s.tooltipBarProps,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div data-tooltip-bar style={{ minHeight: '24px' }} {...tooltipBarProps}>
|
||||
{_activeTooltip}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { type BaseGridColumn, type GridCell, GridCellKind } from '@glideapps/gli
|
||||
import { ActionIcon, Select, Stack, TextInput } from '@mantine/core';
|
||||
import { useDebouncedValue } from '@mantine/hooks';
|
||||
import { IconX } from '@tabler/icons-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { type ReactNode, useEffect, useState } from 'react';
|
||||
|
||||
import type { FilterOption, FilterOptionOperator, GridlerStoreState } from './Store';
|
||||
|
||||
@@ -34,6 +34,7 @@ export interface GridlerColumn extends Partial<BaseGridColumn> {
|
||||
id: string;
|
||||
maxWidth?: number;
|
||||
minWidth?: number;
|
||||
tooltip?: ((buffer: any, row: number, col: number) => ReactNode) | string;
|
||||
width?: number;
|
||||
}
|
||||
|
||||
@@ -84,7 +85,6 @@ export const ColumnFilterInput = (props: ColumnFilterSetProps) => {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return filters;
|
||||
});
|
||||
}, [defferedFilterValue, props.column.id, props.options, props.storeState]);
|
||||
@@ -136,8 +136,6 @@ export const ColumnFilterInputOperator = (props: ColumnFilterSetProps) => {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
return filters;
|
||||
});
|
||||
}, [defferedFilterValue, props.column.id, props.options, props.storeState]);
|
||||
|
||||
@@ -77,48 +77,32 @@ export const Computer = React.memo(() => {
|
||||
rowIndexes.push(idx);
|
||||
}
|
||||
}
|
||||
//console.log('Setting SSS', { key, rowIndex });
|
||||
}
|
||||
//console.log('Setting selection', { rowIndexes, values });
|
||||
|
||||
return rowIndexes;
|
||||
};
|
||||
|
||||
if (values) {
|
||||
searchSelection().then((rowIndexes) => {
|
||||
// const newObj : GridSelection = {
|
||||
// ...cur,
|
||||
let rows = CompactSelection.empty();
|
||||
rowIndexes.forEach((r) => {
|
||||
rows = rows.add(r);
|
||||
});
|
||||
|
||||
// rows: {
|
||||
// items: rowIndexes.map((r) => [r - 1, r]) ?? [],
|
||||
// },
|
||||
// };
|
||||
// console.log('Setting selection', {
|
||||
// rowIndexes,
|
||||
// values,
|
||||
// newObj,
|
||||
// });
|
||||
setStateFN('_gridSelectionRows', () => {
|
||||
let rows = CompactSelection.empty();
|
||||
rowIndexes.forEach((r) => {
|
||||
rows = rows.add(r);
|
||||
});
|
||||
// for (const r of cur ?? CompactSelection.empty()) {
|
||||
// rows = rows.add(r);
|
||||
// }
|
||||
setStateFN('_gridSelection', (c) => ({
|
||||
columns: c?.columns ?? CompactSelection.empty(),
|
||||
...c,
|
||||
rows,
|
||||
}));
|
||||
|
||||
return rows;
|
||||
});
|
||||
|
||||
setStateFN('_gridSelection', (c) => ({
|
||||
columns: c?.columns ?? CompactSelection.empty(),
|
||||
...c,
|
||||
rows,
|
||||
}));
|
||||
});
|
||||
}
|
||||
}, [values]);
|
||||
|
||||
useEffect(() => {
|
||||
//console.log('Gridler:Computer: Selection changed', _gridSelectionRows?.toArray());
|
||||
const onChange = getState('onChange');
|
||||
if (onChange && typeof onChange === 'function') {
|
||||
const page_data = getState('_page_data');
|
||||
@@ -152,7 +136,7 @@ export const Computer = React.memo(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log('Calling onChange with buffers', buffers, _gridSelectionRows?.toArray());
|
||||
|
||||
const _values = getState('values');
|
||||
|
||||
if (JSON.stringify(_values) !== JSON.stringify(buffers)) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
type GridCell,
|
||||
GridCellKind,
|
||||
type GridColumn,
|
||||
type GridMouseEventArgs,
|
||||
type GridSelection,
|
||||
type HeaderClickedEventArgs,
|
||||
type Item,
|
||||
@@ -19,7 +20,7 @@ import { getUUID } from '@warkypublic/artemis-kit';
|
||||
import { getNestedValue } from '@warkypublic/artemis-kit/object';
|
||||
import { createSyncStore } from '@warkypublic/zustandsyncstore';
|
||||
import { produce } from 'immer';
|
||||
import { type PropsWithChildren, useEffect } from 'react';
|
||||
import { type PropsWithChildren, type ReactNode, useEffect } from 'react';
|
||||
|
||||
import { type MantineBetterMenuInstance, useMantineBetterMenus } from '../../MantineBetterMenu';
|
||||
import { type TRequest } from '../utils/types';
|
||||
@@ -78,8 +79,16 @@ export interface GridlerProps extends PropsWithChildren {
|
||||
) => GridCell;
|
||||
request?: TRequest;
|
||||
rowHeight?: number;
|
||||
sections?: {
|
||||
bottom?: React.ReactNode;
|
||||
left?: React.ReactNode;
|
||||
right?: React.ReactNode;
|
||||
top?: React.ReactNode;
|
||||
};
|
||||
selectedRow?: number;
|
||||
selectMode?: 'cell' | 'row';
|
||||
showMenu?: (id: string, options?: Partial<MantineBetterMenuInstance>) => void;
|
||||
tooltipBarProps?: React.HTMLAttributes<HTMLDivElement>;
|
||||
uniqueid: string;
|
||||
useAPIQuery?: (index: number) => Promise<Array<Record<string, any>>>;
|
||||
values?: Array<Record<string, any>>;
|
||||
@@ -87,6 +96,7 @@ export interface GridlerProps extends PropsWithChildren {
|
||||
|
||||
export interface GridlerState {
|
||||
_active_requests?: Array<{ controller: AbortController; page: number }>;
|
||||
_activeTooltip?: ReactNode;
|
||||
_glideref?: DataEditorRef;
|
||||
_gridSelection?: GridSelection;
|
||||
_gridSelectionRows?: GridSelection['rows'];
|
||||
@@ -110,6 +120,7 @@ export interface GridlerState {
|
||||
selection: Rectangle,
|
||||
abortSignal: AbortSignal
|
||||
) => CellArray | GetCellsThunk;
|
||||
getRowBuffer: (row: number) => any;
|
||||
getState: <K extends keyof GridlerStoreState>(key: K) => GridlerStoreState[K];
|
||||
|
||||
hasLocalData: boolean;
|
||||
@@ -127,6 +138,7 @@ export interface GridlerState {
|
||||
onContextClick: (area: string, event: any, col?: number, row?: number) => void;
|
||||
onHeaderClicked: (colIndex: number, event: HeaderClickedEventArgs) => void;
|
||||
onHeaderMenuClick: (col: number, screenPosition: Rectangle) => void;
|
||||
onItemHovered: (args: GridMouseEventArgs) => void;
|
||||
onVisibleRegionChanged: (
|
||||
r: Rectangle,
|
||||
tx: number,
|
||||
@@ -179,28 +191,10 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
|
||||
const state = get();
|
||||
const [col, row] = cell;
|
||||
|
||||
//Handle local data
|
||||
if (state.data && state.data.length > 0) {
|
||||
if (state.data[row] === undefined) {
|
||||
return {
|
||||
allowOverlay: false,
|
||||
kind: GridCellKind.Loading,
|
||||
};
|
||||
}
|
||||
return state.toCell(state.data[row], col);
|
||||
}
|
||||
const buffer = state.getRowBuffer(row);
|
||||
|
||||
//Handle remote paged data
|
||||
const firstPage = Math.max(0, Math.floor(row / state.pageSize));
|
||||
const upperPage = state.pageSize * firstPage;
|
||||
const index = row - upperPage;
|
||||
|
||||
const rowData = state._page_data?.[firstPage]?.[index];
|
||||
//console.log('getCellContent', row, firstPage, upperPage, index, rowData);
|
||||
//This is empty, that is why the grid renders nothing
|
||||
|
||||
if (rowData !== undefined) {
|
||||
return state.toCell(rowData, col);
|
||||
if (buffer !== undefined) {
|
||||
return state.toCell(buffer, col);
|
||||
}
|
||||
return {
|
||||
allowOverlay: false,
|
||||
@@ -233,6 +227,28 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
|
||||
return result as CellArray;
|
||||
};
|
||||
},
|
||||
getRowBuffer: (row: number) => {
|
||||
const state = get();
|
||||
//Handle local data
|
||||
if (state.data && state.data.length > 0) {
|
||||
if (state.data[row] === undefined) {
|
||||
return {
|
||||
allowOverlay: false,
|
||||
kind: GridCellKind.Loading,
|
||||
};
|
||||
}
|
||||
return state.data[row];
|
||||
}
|
||||
|
||||
//Handle remote paged data
|
||||
const firstPage = Math.max(0, Math.floor(row / state.pageSize));
|
||||
const upperPage = state.pageSize * firstPage;
|
||||
const index = row - upperPage;
|
||||
|
||||
const rowData = state._page_data?.[firstPage]?.[index];
|
||||
|
||||
return rowData;
|
||||
},
|
||||
getState: (key) => {
|
||||
return get()[key];
|
||||
},
|
||||
@@ -499,6 +515,20 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
|
||||
y: screenPosition.y,
|
||||
});
|
||||
},
|
||||
onItemHovered: (args: GridMouseEventArgs) => {
|
||||
const s = get();
|
||||
s.setState('_activeTooltip', undefined);
|
||||
if (args.kind === 'cell') {
|
||||
//_activeTooltip
|
||||
const coldef = s.renderColumns?.[args.location[0]];
|
||||
if (coldef?.tooltip && typeof coldef?.tooltip === 'string') {
|
||||
s.setState('_activeTooltip', coldef?.tooltip);
|
||||
} else if (coldef?.tooltip && typeof coldef?.tooltip === 'function') {
|
||||
const buffer = s.getRowBuffer(args.location[1]);
|
||||
s.setState('_activeTooltip', coldef?.tooltip(buffer, args.location[1], args.location[0]));
|
||||
}
|
||||
}
|
||||
},
|
||||
onVisibleRegionChanged: (
|
||||
region: Rectangle,
|
||||
tx: number,
|
||||
|
||||
Reference in New Issue
Block a user