Event handlers and Flex changes

This commit is contained in:
Hein 2025-10-22 17:06:31 +02:00
parent af68d6d377
commit f5887b5be6
6 changed files with 82 additions and 14 deletions

View File

@ -3,11 +3,7 @@
1px 0 0 #00000030, 1px 0 0 #00000030,
0 1px 0 #00000030, 0 1px 0 #00000030,
-1px 0 0 #00000030; -1px 0 0 #00000030;
display: flex;
min-height: 40px;
min-width: 40px;
height: 100%;
width: 100%;
&[data-focused='true'] { &[data-focused='true'] {
box-shadow: box-shadow:

View File

@ -6,7 +6,7 @@ import {
type GridColumn, type GridColumn,
} from '@glideapps/glide-data-grid'; } from '@glideapps/glide-data-grid';
import { Group, Stack } from '@mantine/core'; import { Group, Stack } from '@mantine/core';
import { useElementSize, useMergedRef } from '@mantine/hooks'; import { useDebouncedValue, useElementSize, useMergedRef } from '@mantine/hooks';
import React from 'react'; import React from 'react';
import { BottomBar } from './components/BottomBar'; import { BottomBar } from './components/BottomBar';
@ -24,7 +24,19 @@ export const GridlerDataGrid = () => {
const ref = React.useRef<DataEditorRef | null>(null); const ref = React.useRef<DataEditorRef | null>(null);
const refContextActivated = React.useRef<boolean>(false); const refContextActivated = React.useRef<boolean>(false);
const { height, ref: refWrapper, width } = useElementSize(); const { height, ref: refWrapper, width } = useElementSize({ box: 'content-box' });
/*
const [_dimensions, setDimensions] = useState<{ height: number; width: number } | null>(null);
const { height, width } = _dimensions ?? { height: 0, width: 0 };
useLayoutEffect(() => {
// Measure container before rendering grid
if (refWrapper.current) {
const { height, width } = refWrapper.current.getBoundingClientRect();
setDimensions({ height, width });
}
}, []);
*/
const { const {
_gridSelection, _gridSelection,
@ -37,6 +49,7 @@ export const GridlerDataGrid = () => {
headerHeight, headerHeight,
heightProp, heightProp,
mounted, mounted,
onCellClicked,
onCellEdited, onCellEdited,
onColumnMoved, onColumnMoved,
onColumnProposeMove, onColumnProposeMove,
@ -65,6 +78,7 @@ export const GridlerDataGrid = () => {
headerHeight: s.headerHeight, headerHeight: s.headerHeight,
heightProp: s.height, heightProp: s.height,
mounted: s.mounted, mounted: s.mounted,
onCellClicked: s.onCellClicked,
onCellEdited: s.onCellEdited, onCellEdited: s.onCellEdited,
onColumnMoved: s.onColumnMoved, onColumnMoved: s.onColumnMoved,
onColumnProposeMove: s.onColumnProposeMove, onColumnProposeMove: s.onColumnProposeMove,
@ -72,6 +86,7 @@ export const GridlerDataGrid = () => {
onContextClick: s.onContextClick, onContextClick: s.onContextClick,
onHeaderClicked: s.onHeaderClicked, onHeaderClicked: s.onHeaderClicked,
onHeaderMenuClick: s.onHeaderMenuClick, onHeaderMenuClick: s.onHeaderMenuClick,
onItemHovered: s.onItemHovered, onItemHovered: s.onItemHovered,
onVisibleRegionChanged: s.onVisibleRegionChanged, onVisibleRegionChanged: s.onVisibleRegionChanged,
renderColumns: s.renderColumns, renderColumns: s.renderColumns,
@ -122,6 +137,13 @@ export const GridlerDataGrid = () => {
} }
}} }}
ref={refWrapper} ref={refWrapper}
style={{
display: 'flex',
height: '100%',
minHeight: '64px',
minWidth: '32px',
width: '100%',
}}
> >
{sections?.left} {sections?.left}
@ -132,8 +154,14 @@ export const GridlerDataGrid = () => {
columns={(renderColumns as Array<GridColumn>) ?? []} columns={(renderColumns as Array<GridColumn>) ?? []}
columnSelect="none" columnSelect="none"
drawFocusRing drawFocusRing
height={(height ?? 400) - 4} height={height ?? 400}
overscrollX={16}
overscrollY={32}
rangeSelect="multi-rect" rangeSelect="multi-rect"
rightElementProps={{
fill: false,
sticky: true,
}}
rowMarkers={{ rowMarkers={{
checkboxStyle: 'square', checkboxStyle: 'square',
kind: 'both', kind: 'both',
@ -148,6 +176,7 @@ export const GridlerDataGrid = () => {
gridSelection={_gridSelection} gridSelection={_gridSelection}
headerHeight={headerHeight ?? 32} headerHeight={headerHeight ?? 32}
headerIcons={{ sort: SortSprite, sortdown: SortDownSprite, sortup: SortUpSprite }} headerIcons={{ sort: SortSprite, sortdown: SortDownSprite, sortup: SortUpSprite }}
onCellClicked={onCellClicked}
onCellContextMenu={(cell, event) => { onCellContextMenu={(cell, event) => {
event.preventDefault(); event.preventDefault();
glideProps?.onCellContextMenu?.(cell, event); glideProps?.onCellContextMenu?.(cell, event);
@ -229,8 +258,10 @@ export const GridlerDataGrid = () => {
{!hasLocalData && <Pager />} {!hasLocalData && <Pager />}
{sections?.right} {sections?.right}
</div> </div>
<BottomBar /> <div style={{ flexGrow: 0 }}>
{sections?.bottom} <BottomBar />
{sections?.bottom}
</div>
{/* <Portal> */} {/* <Portal> */}
</Stack> </Stack>
); );

View File

@ -18,7 +18,7 @@ export interface GridlerColumn extends Partial<BaseGridColumn> {
colIndx: string, colIndx: string,
value: any, value: any,
storeState: GridlerStoreState storeState: GridlerStoreState
) => GridCellLoose; ) => Partial<GridCellLoose>;
defaultIcon?: string; defaultIcon?: string;
disableFilter?: boolean; disableFilter?: boolean;
disableMove?: boolean; disableMove?: boolean;

View File

@ -181,6 +181,11 @@ export const Computer = React.memo(() => {
})); }));
}).then(() => { }).then(() => {
loadPage(0, 'all'); loadPage(0, 'all');
getState('_events')?.dispatchEvent?.(
new CustomEvent('onColumnSorted', {
detail: { cols: colSort },
})
);
}); });
}, [colSort]); }, [colSort]);
@ -192,6 +197,11 @@ export const Computer = React.memo(() => {
if (JSON.stringify(refLastFilters.current) !== JSON.stringify(colFilters)) { if (JSON.stringify(refLastFilters.current) !== JSON.stringify(colFilters)) {
loadPage(0, 'all'); loadPage(0, 'all');
refLastFilters.current = colFilters; refLastFilters.current = colFilters;
getState('_events')?.dispatchEvent?.(
new CustomEvent('onColumnFiltered', {
detail: { filters: colFilters },
})
);
} }
}, [colFilters]); }, [colFilters]);

View File

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable react/react-in-jsx-scope */
/* eslint-disable react-refresh/only-export-components */ /* eslint-disable react-refresh/only-export-components */
/* eslint-disable @typescript-eslint/no-unused-vars */ /* eslint-disable @typescript-eslint/no-unused-vars */
import { import {
@ -143,6 +143,7 @@ export interface GridlerState {
loadingData?: boolean; loadingData?: boolean;
loadPage: (page: number, clearMode?: 'all' | 'page') => Promise<void>; loadPage: (page: number, clearMode?: 'all' | 'page') => Promise<void>;
mounted: boolean; mounted: boolean;
onCellClicked: (cell: Item, event: CellClickedEventArgs) => void;
onCellEdited: (cell: Item, newVal: EditableGridCell) => void; onCellEdited: (cell: Item, newVal: EditableGridCell) => void;
onColumnMoved: (from: number, to: number) => void; onColumnMoved: (from: number, to: number) => void;
onColumnProposeMove: (startIndex: number, endIndex: number) => boolean; onColumnProposeMove: (startIndex: number, endIndex: number) => boolean;
@ -340,6 +341,16 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
}, },
maxConcurrency: 1, maxConcurrency: 1,
mounted: false, mounted: false,
onCellClicked: (cell: Item, event: CellClickedEventArgs) => {
const state = get();
const [col, row] = cell;
state.glideProps?.onCellClicked?.(cell, event);
state._events.dispatchEvent(
new CustomEvent('onCellClicked', {
detail: { cell, col, row, state },
})
);
},
onCellEdited: (cell: Item, newVal: EditableGridCell) => { onCellEdited: (cell: Item, newVal: EditableGridCell) => {
const state = get(); const state = get();
const [, row] = cell; const [, row] = cell;
@ -351,6 +362,7 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
detail: { cell, newVal, row, state }, detail: { cell, newVal, row, state },
}) })
); );
state.glideProps?.onCellEdited?.(cell, newVal);
}, },
onColumnMoved: (from: number, to: number) => { onColumnMoved: (from: number, to: number) => {
const s = get(); const s = get();
@ -737,7 +749,7 @@ const { Provider, useStore: useGridlerStore } = createSyncStore<GridlerStoreStat
const val = String(ref).includes('.') ? (getNestedValue(ref, row) ?? '') : row?.[ref]; const val = String(ref).includes('.') ? (getNestedValue(ref, row) ?? '') : row?.[ref];
if (coldef?.Cell) { if (coldef?.Cell) {
return coldef?.Cell(row, col, ref, val, s) as GridCell; return { kind: GridCellKind.Text, ...coldef?.Cell(row, col, ref, val, s) } as GridCell;
} }
if (s.RenderCell) { if (s.RenderCell) {
return s.RenderCell(row, col, ref, val, s); return s.RenderCell(row, col, ref, val, s);

View File

@ -18,6 +18,25 @@ export const GridlerGoAPIExampleEventlog = () => {
const [sections, setSections] = useState<Record<string, unknown> | undefined>(undefined); const [sections, setSections] = useState<Record<string, unknown> | undefined>(undefined);
const columns: GridlerColumns = [ const columns: GridlerColumns = [
{ {
Cell: (row, col, colIndx, value, storeState) => {
const process = `${
row?.cql2?.length > 0
? '🔖'
: row?.cql1?.length > 0
? '📕'
: row?.status === 1
? '💡'
: row?.status === 2
? '🔒'
: '⚙️'
} ${String(row?.id_process ?? '0')}`;
return {
data: process,
displayData: process,
status: row?.status,
};
},
id: 'id_process', id: 'id_process',
title: 'RID', title: 'RID',
width: 100, width: 100,
@ -45,7 +64,7 @@ export const GridlerGoAPIExampleEventlog = () => {
]; ];
return ( return (
<Stack h="80vh"> <Stack h="80vh" w="50vw">
<h2>Demo Using Go API Adaptor</h2> <h2>Demo Using Go API Adaptor</h2>
<TextInput label="API Url" onChange={(e) => setApiUrl(e.target.value)} value={apiUrl} /> <TextInput label="API Url" onChange={(e) => setApiUrl(e.target.value)} value={apiUrl} />
<TextInput label="API Key" onChange={(e) => setApiKey(e.target.value)} value={apiKey} /> <TextInput label="API Key" onChange={(e) => setApiKey(e.target.value)} value={apiKey} />