Init
This commit is contained in:
163
src/Gridler/components/Column.tsx
Normal file
163
src/Gridler/components/Column.tsx
Normal file
@@ -0,0 +1,163 @@
|
||||
/* eslint-disable react-refresh/only-export-components */
|
||||
import { type BaseGridColumn, type GridCell, GridCellKind } from '@glideapps/glide-data-grid';
|
||||
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 { FilterOption, FilterOptionOperator, GridlerStoreState } from './Store';
|
||||
|
||||
export type GridCellLoose = {
|
||||
kind: GridCellKind | string;
|
||||
} & Omit<GridCell, 'allowOverlay' | 'kind'>;
|
||||
|
||||
export interface GridlerColumn extends Partial<BaseGridColumn> {
|
||||
Cell?: (
|
||||
row: any,
|
||||
col: number,
|
||||
colIndx: string,
|
||||
value: any,
|
||||
storeState: GridlerStoreState
|
||||
) => GridCellLoose;
|
||||
defaultIcon?: string;
|
||||
disableFilter?: boolean;
|
||||
disableMove?: boolean;
|
||||
disableResize?: boolean;
|
||||
disableSort?: boolean;
|
||||
getMenuItems?: (
|
||||
id: string,
|
||||
storeState: any,
|
||||
row?: any,
|
||||
col?: GridlerColumn,
|
||||
defaultItems?: Array<any>
|
||||
) => Array<any>;
|
||||
id: string;
|
||||
maxWidth?: number;
|
||||
minWidth?: number;
|
||||
width?: number;
|
||||
}
|
||||
|
||||
export const FilterOperators: Array<{ label: string; value: FilterOptionOperator }> = [
|
||||
{ label: 'Contains', value: 'contains' },
|
||||
{ label: 'Equal', value: 'eq' },
|
||||
{ label: 'Not Equal', value: 'neq' },
|
||||
{ label: 'Greater Than', value: 'gt' },
|
||||
{ label: 'Greater Than or Equal', value: 'gte' },
|
||||
{ label: 'Less Than', value: 'lt' },
|
||||
{ label: 'Less Than or Equal', value: 'lte' },
|
||||
];
|
||||
|
||||
export interface ColumnFilterSetProps {
|
||||
column: GridlerColumn;
|
||||
options?: Partial<FilterOption>;
|
||||
storeState: GridlerStoreState;
|
||||
}
|
||||
|
||||
export type GridlerColumns = Array<GridlerColumn>;
|
||||
|
||||
export const ColumnFilterInput = (props: ColumnFilterSetProps) => {
|
||||
const filterIndex =
|
||||
props.storeState?.colFilters?.findIndex((f) => f.id === props.column.id) ?? -1;
|
||||
const filter = props.storeState?.colFilters?.[filterIndex] ?? { id: props.column.id, value: '' };
|
||||
|
||||
const [filterValue, setFilterValue] = useState<string>(filter?.value ?? '');
|
||||
const [defferedFilterValue] = useDebouncedValue(filterValue, 900);
|
||||
|
||||
useEffect(() => {
|
||||
props.storeState.setStateFN('colFilters', (state) => {
|
||||
const idx = state?.findIndex((f) => f.id === props.column.id) ?? -1;
|
||||
|
||||
const filters = state ?? [];
|
||||
if (idx >= 0) {
|
||||
filters[idx] = {
|
||||
...filters[idx],
|
||||
...props.options,
|
||||
id: props.column.id,
|
||||
value: defferedFilterValue,
|
||||
};
|
||||
} else {
|
||||
filters.push({
|
||||
operator: 'contains',
|
||||
...props.options,
|
||||
id: props.column.id,
|
||||
value: defferedFilterValue,
|
||||
});
|
||||
}
|
||||
|
||||
return filters;
|
||||
});
|
||||
}, [defferedFilterValue]);
|
||||
|
||||
return (
|
||||
<TextInput
|
||||
onChange={(e) => setFilterValue(e.target.value)}
|
||||
rightSection={
|
||||
<ActionIcon color="gray" onClick={() => setFilterValue('')} variant="filled">
|
||||
<IconX color="red" />
|
||||
</ActionIcon>
|
||||
}
|
||||
value={filterValue ?? filter?.value}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const ColumnFilterInputOperator = (props: ColumnFilterSetProps) => {
|
||||
const filterIndex =
|
||||
props.storeState?.colFilters?.findIndex((f) => f.id === props.column.id) ?? -1;
|
||||
const filter = props.storeState?.colFilters?.[filterIndex] ?? {
|
||||
id: props.column.id,
|
||||
operator: 'contains',
|
||||
};
|
||||
|
||||
const [filterValue, setFilterValue] = useState<FilterOptionOperator>(
|
||||
filter?.operator ?? 'contains'
|
||||
);
|
||||
const [defferedFilterValue] = useDebouncedValue(filterValue, 900);
|
||||
|
||||
useEffect(() => {
|
||||
props.storeState.setStateFN('colFilters', (state) => {
|
||||
const idx = state?.findIndex((f) => f.id === props.column.id) ?? -1;
|
||||
|
||||
const filters = state ?? [];
|
||||
if (idx >= 0) {
|
||||
filters[idx] = {
|
||||
...filters[idx],
|
||||
...props.options,
|
||||
id: props.column.id,
|
||||
operator: defferedFilterValue,
|
||||
};
|
||||
} else {
|
||||
filters.push({
|
||||
operator: 'contains',
|
||||
...props.options,
|
||||
id: props.column.id,
|
||||
value: defferedFilterValue,
|
||||
});
|
||||
}
|
||||
|
||||
return filters;
|
||||
});
|
||||
}, [defferedFilterValue]);
|
||||
|
||||
return (
|
||||
<Select
|
||||
comboboxProps={{ withinPortal: false }}
|
||||
data={FilterOperators}
|
||||
maxDropdownHeight={150}
|
||||
onChange={(value) => setFilterValue(value as any)}
|
||||
placeholder="Operator"
|
||||
searchable
|
||||
value={filterValue ?? filter?.operator}
|
||||
withScrollArea
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const ColumnFilterSet = (props: ColumnFilterSetProps) => {
|
||||
return (
|
||||
<Stack onClick={(e) => e.stopPropagation()}>
|
||||
<ColumnFilterInputOperator {...props} />
|
||||
<ColumnFilterInput {...props} />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user