Skip to content

Commit

Permalink
Experiment/table select api (#1271)
Browse files Browse the repository at this point in the history
* first cut table selection API

* update all types for table selection
  • Loading branch information
heswell authored Mar 17, 2024
1 parent 99e35ee commit 64f7d22
Show file tree
Hide file tree
Showing 18 changed files with 181 additions and 101 deletions.
8 changes: 8 additions & 0 deletions vuu-ui/packages/vuu-data-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ export type DataSourceRow = [
...VuuRowDataItemType[]
];

export type DataSourceRowObject = {
index: number;
key: string;
isGroupRow: boolean;
isSelected: boolean;
data: VuuDataRowDto;
};

export type DataSourceRowPredicate = (row: DataSourceRow) => boolean;

export interface ContextMenuItemBase {
Expand Down
17 changes: 13 additions & 4 deletions vuu-ui/packages/vuu-table-types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import type {
VuuSortType,
VuuTable,
} from "@finos/vuu-protocol-types";
import type { VuuDataRow } from "@finos/vuu-protocol-types";
import type { ClientSideValidationChecker } from "@finos/vuu-ui-controls";
import type { DateTimePattern } from "@finos/vuu-utils";
import { DataSourceRow } from "@finos/vuu-data-types";
import { DataSourceRow, DataSourceRowObject } from "@finos/vuu-data-types";
import type { FunctionComponent, MouseEvent } from "react";
import type { HTMLAttributes } from "react";

Expand Down Expand Up @@ -45,9 +44,19 @@ export type DataItemCommitHandler<
T extends VuuRowDataItemType = VuuRowDataItemType
> = (value: T) => CommitResponse;

export type TableRowClickHandler = (row: VuuDataRow) => void;
export type TableRowSelectHandler = (row: DataSourceRowObject | null) => void;
export type TableRowSelectHandlerInternal = (row: DataSourceRow | null) => void;

export type RowClickHandler = (
/**
* Fired when user clicks a row, returning the row object (DataSourceRowObject)
*/
export type TableRowClickHandler = (
evt: MouseEvent<HTMLDivElement>,
row: DataSourceRowObject
) => void;

export type TableRowClickHandlerInternal = (
evt: MouseEvent<HTMLDivElement>,
row: DataSourceRow,
rangeSelect: boolean,
keepExistingSelection: boolean
Expand Down
6 changes: 3 additions & 3 deletions vuu-ui/packages/vuu-table/src/Row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { DataSourceRow } from "@finos/vuu-data-types";
import {
DataCellEditHandler,
RuntimeColumnDescriptor,
RowClickHandler,
TableRowClickHandlerInternal,
} from "@finos/vuu-table-types";
import {
ColumnMap,
Expand Down Expand Up @@ -34,7 +34,7 @@ export interface RowProps {
highlighted?: boolean;
row: DataSourceRow;
offset: number;
onClick?: RowClickHandler;
onClick?: TableRowClickHandlerInternal;
onDataEdited?: DataCellEditHandler;
onToggleGroup?: (row: DataSourceRow, column: RuntimeColumnDescriptor) => void;
style?: CSSProperties;
Expand Down Expand Up @@ -89,7 +89,7 @@ export const Row = memo(
(evt: MouseEvent<HTMLDivElement>) => {
const rangeSelect = evt.shiftKey;
const keepExistingSelection = evt.ctrlKey || evt.metaKey; /* mac only */
onClick?.(row, rangeSelect, keepExistingSelection);
onClick?.(evt, row, rangeSelect, keepExistingSelection);
},
[onClick, row]
);
Expand Down
4 changes: 1 addition & 3 deletions vuu-ui/packages/vuu-table/src/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {
DataSource,
DataSourceRow,
SchemaColumn,
SelectionChangeHandler,
VuuFeatureInvocationMessage,
Expand All @@ -10,6 +9,7 @@ import {
TableConfig,
TableConfigChangeHandler,
TableRowClickHandler,
TableRowSelectHandler,
TableSelectionModel,
} from "@finos/vuu-table-types";
import {
Expand Down Expand Up @@ -44,8 +44,6 @@ const classBase = "vuuTable";

const { IDX, RENDER_IDX } = metadataKeys;

// TODO implement a Model object to represent a row data for better API
export type TableRowSelectHandler = (row: DataSourceRow) => void;
export type TableNavigationStyle = "none" | "cell" | "row";

export interface TableProps
Expand Down
18 changes: 9 additions & 9 deletions vuu-ui/packages/vuu-table/src/useSelection.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { RowClickHandler, TableSelectionModel } from "@finos/vuu-table-types";
import {
TableRowClickHandlerInternal,
TableRowSelectHandlerInternal,
TableSelectionModel,
} from "@finos/vuu-table-types";
import {
deselectItem,
dispatchMouseEvent,
isRowSelected,
metadataKeys,
selectItem,
} from "@finos/vuu-utils";
import {
DataSourceRow,
Selection,
SelectionChangeHandler,
} from "@finos/vuu-data-types";
import { Selection, SelectionChangeHandler } from "@finos/vuu-data-types";
import {
KeyboardEvent,
KeyboardEventHandler,
Expand All @@ -29,7 +29,7 @@ export interface SelectionHookProps {
highlightedIndexRef: MutableRefObject<number | undefined>;
selectionKeys?: string[];
selectionModel: TableSelectionModel;
onSelect?: (row: DataSourceRow) => void;
onSelect?: TableRowSelectHandlerInternal;
onSelectionChange: SelectionChangeHandler;
}

Expand All @@ -49,8 +49,8 @@ export const useSelection = ({
[selectionKeys]
);

const handleRowClick = useCallback<RowClickHandler>(
(row, rangeSelect, keepExistingSelection) => {
const handleRowClick = useCallback<TableRowClickHandlerInternal>(
(evt, row, rangeSelect, keepExistingSelection) => {
const { [IDX]: idx } = row;
const { current: active } = lastActiveRef;
const { current: selected } = selectedRef;
Expand Down
31 changes: 21 additions & 10 deletions vuu-ui/packages/vuu-table/src/useTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import {
import {
ColumnDescriptor,
DataCellEditHandler,
RowClickHandler,
TableRowClickHandlerInternal,
RuntimeColumnDescriptor,
TableColumnResizeHandler,
TableConfig,
TableSelectionModel,
TableRowSelectHandlerInternal,
} from "@finos/vuu-table-types";
import { VuuRange, VuuSortType } from "@finos/vuu-protocol-types";
import {
Expand All @@ -22,6 +23,7 @@ import {
} from "@finos/vuu-ui-controls";
import {
applySort,
asDataSourceRowObject,
buildColumnMap,
getIndexFromRowElement,
isGroupColumn,
Expand Down Expand Up @@ -557,16 +559,33 @@ export const useTable = ({
[dataSource, onSelectionChange]
);

const handleSelect = useCallback<TableRowSelectHandlerInternal>(
(row) => {
if (onSelect) {
onSelect(row === null ? null : asDataSourceRowObject(row, columnMap));
}
},
[columnMap, onSelect]
);

const {
onKeyDown: selectionHookKeyDown,
onRowClick: selectionHookOnRowClick,
} = useSelection({
highlightedIndexRef,
onSelect,
onSelect: handleSelect,
onSelectionChange: handleSelectionChange,
selectionModel,
});

const handleRowClick = useCallback<TableRowClickHandlerInternal>(
(evt, row, rangeSelect, keepExistingSelection) => {
selectionHookOnRowClick(evt, row, rangeSelect, keepExistingSelection);
onRowClickProp?.(evt, asDataSourceRowObject(row, columnMap));
},
[columnMap, onRowClickProp, selectionHookOnRowClick]
);

const handleKeyDown = useCallback(
(e: KeyboardEvent<HTMLElement>) => {
navigationKeyDown(e);
Expand All @@ -580,14 +599,6 @@ export const useTable = ({
[navigationKeyDown, editingKeyDown, selectionHookKeyDown]
);

const handleRowClick = useCallback<RowClickHandler>(
(row, rangeSelect, keepExistingSelection) => {
selectionHookOnRowClick(row, rangeSelect, keepExistingSelection);
onRowClickProp?.(row);
},
[onRowClickProp, selectionHookOnRowClick]
);

const onMoveColumn = useCallback(
(columns: ColumnDescriptor[]) => {
const newTableConfig = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DataSourceRow, TableSchema } from "@finos/vuu-data-types";
import { Table, TableProps, TableRowSelectHandler } from "@finos/vuu-table";
import { DataSourceRowObject, TableSchema } from "@finos/vuu-data-types";
import { Table, TableProps } from "@finos/vuu-table";
import { ColumnMap, useId } from "@finos/vuu-utils";
import { Input } from "@salt-ds/core";
import { ForwardedRef, forwardRef, HTMLAttributes, useMemo } from "react";
Expand All @@ -16,7 +16,8 @@ if (typeof SearchCell !== "function") {
}

export interface InstrumentPickerProps
extends Omit<HTMLAttributes<HTMLElement>, "onSelect"> {
extends Omit<HTMLAttributes<HTMLElement>, "onSelect">,
Pick<TableProps, "onSelect"> {
TableProps: Pick<TableProps, "config" | "dataSource">;
columnMap: ColumnMap;
disabled?: boolean;
Expand All @@ -27,10 +28,9 @@ export interface InstrumentPickerProps
* @param row DataSourceRow
* @returns string
*/
itemToString?: (row: DataSourceRow) => string;
itemToString?: (row: DataSourceRowObject) => string;
onClose?: () => void;
onOpenChange?: OpenChangeHandler;
onSelect: TableRowSelectHandler;
schema: TableSchema;
searchColumns: string[];
width?: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { DataSource, DataSourceRow } from "@finos/vuu-data-types";
import { ColumnDescriptor } from "@finos/vuu-table-types";
import { DataSource, DataSourceRowObject } from "@finos/vuu-data-types";
import {
ColumnDescriptor,
TableRowSelectHandler,
useControlledTableNavigation,
} from "@finos/vuu-table";
import { ColumnMap } from "@finos/vuu-utils";
} from "@finos/vuu-table-types";
import { useControlledTableNavigation } from "@finos/vuu-table";
import { ChangeEvent, useCallback, useMemo, useState } from "react";
import { useControlled } from "../common-hooks";
import { OpenChangeHandler } from "../dropdown";
Expand All @@ -21,19 +20,14 @@ export interface InstrumentPickerHookProps
isOpen?: boolean;
}

const defaultItemToString =
(columns: ColumnDescriptor[], columnMap: ColumnMap) =>
(row: DataSourceRow) => {
return columns.map(({ name }) => row[columnMap[name]]).join(" ");
};
const defaultItemToString = (row: DataSourceRowObject) =>
Object.values(row.data).join(" ");

export const useInstrumentPicker = ({
columnMap,
columns,
dataSource,
defaultIsOpen,
isOpen: isOpenProp,
itemToString = defaultItemToString(columns, columnMap),
itemToString = defaultItemToString,
onOpenChange,
onSelect,
searchColumns,
Expand Down Expand Up @@ -85,9 +79,9 @@ export const useInstrumentPicker = ({

const handleSelectRow = useCallback<TableRowSelectHandler>(
(row) => {
const value = itemToString(row);
const value = row === null ? "" : itemToString(row);
setValue(value);
onSelect(row);
onSelect?.(row);
handleOpenChange?.(false, "select");
},
[handleOpenChange, itemToString, onSelect]
Expand Down
33 changes: 30 additions & 3 deletions vuu-ui/packages/vuu-utils/src/row-utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//TODO this all probably belongs in vuu-table
import type { DataSourceRow } from "@finos/vuu-data-types";
import type { DataSourceRow, DataSourceRowObject } from "@finos/vuu-data-types";
import type { MutableRefObject } from "react";
import { metadataKeys } from "./column-utils";
import { ColumnMap, metadataKeys } from "./column-utils";

const { IDX } = metadataKeys;
const { IS_LEAF, KEY, IDX, SELECTED } = metadataKeys;

export type RowOffsetFunc = (
row: DataSourceRow,
Expand Down Expand Up @@ -90,3 +90,30 @@ export const getIndexFromRowElement = (rowElement: HTMLElement) => {
);
}
};

export const asDataSourceRowObject = (
row: DataSourceRow,
columnMap: ColumnMap
): DataSourceRowObject => {
console.log({ columnMap });
const {
[IS_LEAF]: isLeaf,
[KEY]: key,
[IDX]: index,
[SELECTED]: selected,
} = row;

const rowObject: DataSourceRowObject = {
key,
index,
isGroupRow: !isLeaf,
isSelected: selected > 0,
data: {},
};

for (const [colName, colIdx] of Object.entries(columnMap)) {
rowObject.data[colName] = row[colIdx];
}

return rowObject;
};
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const BasketSelectorRow = ({
(evt: MouseEvent<HTMLDivElement>) => {
const rangeSelect = evt.shiftKey;
const keepExistingSelection = evt.ctrlKey || evt.metaKey; /* mac only */
onClick?.(row, rangeSelect, keepExistingSelection);
onClick?.(evt, row, rangeSelect, keepExistingSelection);
},
[onClick, row]
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { TableRowClickHandler } from "@finos/vuu-table-types";
import { TableProps } from "@finos/vuu-table";
import { OpenChangeHandler, useControlled } from "@finos/vuu-ui-controls";
import { buildColumnMap } from "@finos/vuu-utils";
import { useCallback, useMemo, useRef } from "react";
import { BasketSelectorProps } from "./BasketSelector";
import { BasketSelectorRow } from "./BasketSelectorRow";
Expand Down Expand Up @@ -33,11 +32,6 @@ export const useBasketSelector = ({
name: "useDropdownList",
});

const columnMap = useMemo(
() => buildColumnMap(dataSourceBasketTradingSearch.columns),
[dataSourceBasketTradingSearch.columns]
);

const handleOpenChange = useCallback<OpenChangeHandler>(
(open, closeReason) => {
setIsOpen(open);
Expand All @@ -55,12 +49,12 @@ export const useBasketSelector = ({
);

const handleRowClick = useCallback<TableRowClickHandler>(
(row) => {
const instanceId = row[columnMap.instanceId] as string;
(_evt, row) => {
const instanceId = row.data.instanceId as string;
handleOpenChange(false, "select");
onSelectBasket?.(instanceId);
},
[columnMap.instanceId, handleOpenChange, onSelectBasket]
[handleOpenChange, onSelectBasket]
);

const handleClickAddBasket = useCallback(() => {
Expand Down
Loading

0 comments on commit 64f7d22

Please sign in to comment.