From 8b256fbaff94d48297b4881a5be5a488c66f4125 Mon Sep 17 00:00:00 2001 From: heswell Date: Sun, 22 Oct 2023 15:34:34 +0100 Subject: [PATCH 1/4] make instrument-picker more generic --- vuu-ui/packages/vuu-datagrid-types/index.d.ts | 1 + .../vuu-table/src/table-next/TableNext.css | 4 ++ .../vuu-table/src/table-next/TableNext.tsx | 1 + .../instrument-picker/InstrumentPicker.tsx | 21 +++++++- .../instrument-picker/useInstrumentPicker.ts | 28 ++++++++--- .../UiControls/InstrumentPicker.examples.tsx | 49 +++++++++++++++++++ .../showcase/src/examples/UiControls/index.ts | 1 + 7 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 vuu-ui/showcase/src/examples/UiControls/InstrumentPicker.examples.tsx diff --git a/vuu-ui/packages/vuu-datagrid-types/index.d.ts b/vuu-ui/packages/vuu-datagrid-types/index.d.ts index 81b58b000..503c026b9 100644 --- a/vuu-ui/packages/vuu-datagrid-types/index.d.ts +++ b/vuu-ui/packages/vuu-datagrid-types/index.d.ts @@ -43,6 +43,7 @@ export interface TableAttributes { columnDefaultWidth?: number; columnFormatHeader?: "capitalize" | "uppercase"; columnSeparators?: boolean; + showHighlightedRow?: boolean; rowSeparators?: boolean; zebraStripes?: boolean; } diff --git a/vuu-ui/packages/vuu-table/src/table-next/TableNext.css b/vuu-ui/packages/vuu-table/src/table-next/TableNext.css index f83992f2b..9b4836589 100644 --- a/vuu-ui/packages/vuu-table/src/table-next/TableNext.css +++ b/vuu-ui/packages/vuu-table/src/table-next/TableNext.css @@ -25,6 +25,10 @@ --row-borderColor: var(--salt-separable-tertiary-borderColor); } +.vuuTableNext-highlight .vuuTableNextRow:hover { + background-color: var(--vuu-color-pink-10-fade-20); +} + .vuuTableNext-scrollbarContainer { --scroll-content-width: 1100px; border-bottom: none !important; diff --git a/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx b/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx index c36ff84f2..b40f2cf57 100644 --- a/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx +++ b/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx @@ -98,6 +98,7 @@ export const TableNext = forwardRef(function TableNext( const className = cx(classBase, classNameProp, { [`${classBase}-colLines`]: tableAttributes.columnSeparators, [`${classBase}-rowLines`]: tableAttributes.rowSeparators, + [`${classBase}-highlight`]: tableAttributes.showHighlightedRow, [`${classBase}-zebra`]: tableAttributes.zebraStripes, // [`${classBase}-loading`]: isDataLoading(tableProps.columns), }); diff --git a/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/InstrumentPicker.tsx b/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/InstrumentPicker.tsx index 9ca343d8f..6d0562db1 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/InstrumentPicker.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/InstrumentPicker.tsx @@ -1,4 +1,5 @@ import { TableSchema } from "@finos/vuu-data"; +import { DataSourceRow } from "@finos/vuu-data-types"; import { useId } from "@finos/vuu-layout"; import { TableNext, TableProps, TableRowSelectHandler } from "@finos/vuu-table"; import { ColumnMap } from "@finos/vuu-utils"; @@ -17,6 +18,14 @@ export interface InstrumentPickerProps TableProps: Pick; columnMap: ColumnMap; disabled?: boolean; + /** + * Used to form the display value to render in input following selection. If + * not provided, default will be the values from rendered columns. + * + * @param row DataSourceRow + * @returns string + */ + itemToString?: (row: DataSourceRow) => string; onSelect: TableRowSelectHandler; schema: TableSchema; searchColumns: string[]; @@ -30,6 +39,7 @@ export const InstrumentPicker = forwardRef(function InstrumentPicker( columnMap, disabled, id: idProp, + itemToString, onSelect, schema, searchColumns, @@ -47,7 +57,16 @@ export const InstrumentPicker = forwardRef(function InstrumentPicker( onOpenChange, tableHandlers, value, - } = useInstrumentPicker({ columnMap, dataSource, onSelect, searchColumns }); + } = useInstrumentPicker({ + columnMap, + columns: TableProps.config.columns, + dataSource, + itemToString, + onSelect, + searchColumns, + }); + + console.log({ value }); const endAdornment = useMemo(() => , []); diff --git a/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useInstrumentPicker.ts b/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useInstrumentPicker.ts index 1acb729a4..ae13cc722 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useInstrumentPicker.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/instrument-picker/useInstrumentPicker.ts @@ -1,23 +1,36 @@ import { DataSource } from "@finos/vuu-data"; +import { DataSourceRow } from "@finos/vuu-data-types"; +import { ColumnDescriptor } from "@finos/vuu-datagrid-types"; import { TableRowSelectHandler } from "@finos/vuu-table"; import { ColumnMap } from "@finos/vuu-utils"; import { ChangeEvent, useCallback, useMemo, useState } from "react"; import { useControlled } from "../common-hooks"; +import { InstrumentPickerProps } from "./InstrumentPicker"; -export interface InstrumentPickerHookProps { - columnMap: ColumnMap; +export interface InstrumentPickerHookProps + extends Pick< + InstrumentPickerProps, + "columnMap" | "itemToString" | "onSelect" | "searchColumns" + > { + columns: ColumnDescriptor[]; dataSource: DataSource; defaultIsOpen?: boolean; isOpen?: boolean; - onSelect: TableRowSelectHandler; - searchColumns: string[]; } +const defaultItemToString = + (columns: ColumnDescriptor[], columnMap: ColumnMap) => + (row: DataSourceRow) => { + return columns.map(({ name }) => row[columnMap[name]]).join(" "); + }; + export const useInstrumentPicker = ({ columnMap, + columns, dataSource, defaultIsOpen, isOpen: isOpenProp, + itemToString = defaultItemToString(columns, columnMap), onSelect, searchColumns, }: InstrumentPickerHookProps) => { @@ -65,13 +78,12 @@ export const useInstrumentPicker = ({ const handleSelectRow = useCallback( (row) => { - const { name } = columnMap; - const { [name]: value } = row; - setValue(value as string); + const value = itemToString(row); + setValue(value); setIsOpen(false); onSelect(row); }, - [columnMap, onSelect, setIsOpen] + [itemToString, onSelect, setIsOpen] ); const inputProps = { diff --git a/vuu-ui/showcase/src/examples/UiControls/InstrumentPicker.examples.tsx b/vuu-ui/showcase/src/examples/UiControls/InstrumentPicker.examples.tsx new file mode 100644 index 000000000..6446a2ea4 --- /dev/null +++ b/vuu-ui/showcase/src/examples/UiControls/InstrumentPicker.examples.tsx @@ -0,0 +1,49 @@ +import { InstrumentPicker } from "@finos/vuu-ui-controls"; +import { getSchema } from "@finos/vuu-data-test"; +import { buildColumnMap, ColumnMap } from "@finos/vuu-utils"; +import { useCallback, useMemo } from "react"; +import { TableProps, TableRowSelectHandler } from "@finos/vuu-table"; +import { createArrayDataSource } from "../utils/createArrayDataSource"; +import { ColumnDescriptor } from "@finos/vuu-datagrid-types"; + +let displaySequence = 0; + +export const DefaultInstrumentPicker = () => { + const schema = getSchema("instruments"); + const [columnMap, searchColumns, tableProps] = useMemo< + [ColumnMap, string[], Pick] + >( + () => [ + buildColumnMap(schema.columns), + ["bbg", "description"], + { + config: { + // TODO need to inject this value + showHighlightedRow: true, + columns: [ + { name: "bbg", serverDataType: "string" }, + { name: "description", serverDataType: "string", width: 280 }, + ] as ColumnDescriptor[], + }, + dataSource: createArrayDataSource({ table: schema.table }), + }, + ], + [schema] + ); + + const handleSelect = useCallback((row) => { + console.log(`row selected ${row.join(",")}`); + }, []); + + return ( + + ); +}; +DefaultInstrumentPicker.displaySequence = displaySequence++; diff --git a/vuu-ui/showcase/src/examples/UiControls/index.ts b/vuu-ui/showcase/src/examples/UiControls/index.ts index 49b3154b1..02e11d8cf 100644 --- a/vuu-ui/showcase/src/examples/UiControls/index.ts +++ b/vuu-ui/showcase/src/examples/UiControls/index.ts @@ -2,6 +2,7 @@ export * as ComboBox from "./Combobox.examples"; export * as DragDrop from "./DragDrop.examples"; export * as Dropdown from "./Dropdown.examples"; export * as EditableLabel from "./EditableLabel.examples"; +export * as InstrumentPicker from "./InstrumentPicker.examples"; export * as InstrumentSearch from "./InstrumentSearch.examples"; export * as List from "./List.examples"; export * as Tabstrip from "./Tabstrip.examples"; From bb499b6b05a880cf8616d7161741e550aefcbe66 Mon Sep 17 00:00:00 2001 From: heswell Date: Mon, 23 Oct 2023 10:03:13 +0100 Subject: [PATCH 2/4] refactor Table navigation, preparing for row highlighting --- .../vuu-table/src/table-next/TableNext.tsx | 2 + .../src/table-next/useKeyboardNavigation.ts | 31 +++++-- .../vuu-table/src/table-next/useTableNext.ts | 3 + .../vuu-table/src/table/dataTableTypes.ts | 7 ++ .../src/common-hooks/navigationTypes.ts | 6 +- .../vuu-ui-controls/src/list/List.css | 5 +- .../vuu-ui-controls/src/list/List.tsx | 2 +- .../common-hooks/useKeyboardNavigation.ts | 83 +++++++++---------- .../vuu-ui-controls/src/list/useList.ts | 3 +- .../src/examples/Table/TableNext.examples.tsx | 30 +++++++ .../src/examples/UiControls/List.examples.tsx | 55 +++++++++++- 11 files changed, 163 insertions(+), 64 deletions(-) diff --git a/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx b/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx index b40f2cf57..f585ad55c 100644 --- a/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx +++ b/vuu-ui/packages/vuu-table/src/table-next/TableNext.tsx @@ -26,6 +26,7 @@ export const TableNext = forwardRef(function TableNext( config, dataSource, id: idProp, + navigationStyle = "cell", onAvailableColumnsChange, onConfigChange, onFeatureEnabled, @@ -69,6 +70,7 @@ export const TableNext = forwardRef(function TableNext( containerRef, dataSource, headerHeight, + navigationStyle, onAvailableColumnsChange, onConfigChange, onFeatureEnabled, diff --git a/vuu-ui/packages/vuu-table/src/table-next/useKeyboardNavigation.ts b/vuu-ui/packages/vuu-table/src/table-next/useKeyboardNavigation.ts index 73e750dae..e1b4ddf24 100644 --- a/vuu-ui/packages/vuu-table/src/table-next/useKeyboardNavigation.ts +++ b/vuu-ui/packages/vuu-table/src/table-next/useKeyboardNavigation.ts @@ -15,20 +15,33 @@ import { getTableCell, headerCellQuery, } from "./table-dom-utils"; +import { TableNavigationStyle } from "../table/dataTableTypes"; -const navigationKeys = new Set([ +const rowNavigationKeys = new Set([ "Home", "End", "PageUp", "PageDown", "ArrowDown", - "ArrowLeft", - "ArrowRight", "ArrowUp", ]); -export const isNavigationKey = (key: string): key is NavigationKey => { - return navigationKeys.has(key as NavigationKey); +const cellNavigationKeys = new Set(rowNavigationKeys); +cellNavigationKeys.add("ArrowLeft"); +cellNavigationKeys.add("ArrowRight"); + +export const isNavigationKey = ( + key: string, + navigationStyle: TableNavigationStyle +): key is NavigationKey => { + switch (navigationStyle) { + case "cell": + return cellNavigationKeys.has(key as NavigationKey); + case "row": + return rowNavigationKeys.has(key as NavigationKey); + default: + return false; + } }; type ArrowKey = "ArrowUp" | "ArrowDown" | "ArrowLeft" | "ArrowRight"; @@ -114,6 +127,7 @@ export interface NavigationHookProps { columnCount?: number; disableHighlightOnFocus?: boolean; label?: string; + navigationStyle: TableNavigationStyle; viewportRange: VuuRange; requestScroll?: ScrollRequestHandler; restoreLastFocus?: boolean; @@ -126,6 +140,7 @@ export const useKeyboardNavigation = ({ columnCount = 0, containerRef, disableHighlightOnFocus, + navigationStyle, requestScroll, rowCount = 0, viewportRowCount, @@ -233,7 +248,6 @@ NavigationHookProps) => { // click handler. const focusedCell = getFocusedCell(document.activeElement); if (focusedCell) { - console.log({ focusedCell }); focusedCellPos.current = getTableCellPos(focusedCell); } } @@ -242,7 +256,6 @@ NavigationHookProps) => { const navigateChildItems = useCallback( async (key: NavigationKey) => { - console.log(`navigate child items ${key}`); const [nextRowIdx, nextColIdx] = isPagingKey(key) ? await nextPageItemIdx(key, activeCellPos.current) : nextCellPos(key, activeCellPos.current, columnCount, rowCount); @@ -258,13 +271,13 @@ NavigationHookProps) => { const handleKeyDown = useCallback( (e: KeyboardEvent) => { - if (rowCount > 0 && isNavigationKey(e.key)) { + if (rowCount > 0 && isNavigationKey(e.key, navigationStyle)) { e.preventDefault(); e.stopPropagation(); void navigateChildItems(e.key); } }, - [rowCount, navigateChildItems] + [rowCount, navigationStyle, navigateChildItems] ); const handleClick = useCallback( diff --git a/vuu-ui/packages/vuu-table/src/table-next/useTableNext.ts b/vuu-ui/packages/vuu-table/src/table-next/useTableNext.ts index d97265299..3400fca92 100644 --- a/vuu-ui/packages/vuu-table/src/table-next/useTableNext.ts +++ b/vuu-ui/packages/vuu-table/src/table-next/useTableNext.ts @@ -67,6 +67,7 @@ export interface TableHookProps | "availableColumns" | "config" | "dataSource" + | "navigationStyle" | "onAvailableColumnsChange" | "onConfigChange" | "onFeatureEnabled" @@ -98,6 +99,7 @@ export const useTable = ({ containerRef, dataSource, headerHeight = 25, + navigationStyle, onAvailableColumnsChange, onConfigChange, onFeatureEnabled, @@ -408,6 +410,7 @@ export const useTable = ({ } = useKeyboardNavigation({ columnCount: columns.filter((c) => c.hidden !== true).length, containerRef, + navigationStyle, requestScroll, rowCount: dataSource?.size, viewportRange: range, diff --git a/vuu-ui/packages/vuu-table/src/table/dataTableTypes.ts b/vuu-ui/packages/vuu-table/src/table/dataTableTypes.ts index 2db9f107e..a196e163f 100644 --- a/vuu-ui/packages/vuu-table/src/table/dataTableTypes.ts +++ b/vuu-ui/packages/vuu-table/src/table/dataTableTypes.ts @@ -20,6 +20,8 @@ export type TableRowClickHandler = (row: VuuDataRow) => void; // 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 extends Omit, "onSelect"> { Row?: FC; @@ -32,6 +34,11 @@ export interface TableProps dataSource: DataSource; headerHeight?: number; height?: number; + /** + * Defined how focus navigation within data cells will be handled by table. + * Default is cell. + */ + navigationStyle?: TableNavigationStyle; /** * required if a fully featured column picker is to be available. * Available columns can be changed by the addition or removal of diff --git a/vuu-ui/packages/vuu-ui-controls/src/common-hooks/navigationTypes.ts b/vuu-ui/packages/vuu-ui-controls/src/common-hooks/navigationTypes.ts index c6b041c06..7a6349a1a 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/common-hooks/navigationTypes.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/common-hooks/navigationTypes.ts @@ -1,14 +1,12 @@ import { FocusEvent, KeyboardEvent, RefObject } from "react"; -import { CollectionItem } from "./collectionTypes"; -export interface NavigationProps { +export interface NavigationProps { cycleFocus?: boolean; defaultHighlightedIndex?: number; disableHighlightOnFocus?: boolean; focusOnHighlight?: boolean; focusVisible?: number; highlightedIndex?: number; - indexPositions: CollectionItem[]; itemCount: number; onHighlight?: (idx: number) => void; onKeyboardNavigation?: (evt: KeyboardEvent, idx: number) => void; @@ -16,7 +14,7 @@ export interface NavigationProps { viewportItemCount: number; } -export interface NavigationHookProps extends NavigationProps { +export interface NavigationHookProps extends NavigationProps { containerRef: RefObject; label?: string; selected?: string[]; diff --git a/vuu-ui/packages/vuu-ui-controls/src/list/List.css b/vuu-ui/packages/vuu-ui-controls/src/list/List.css index 9b9c87477..9a4e0b348 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/list/List.css +++ b/vuu-ui/packages/vuu-ui-controls/src/list/List.css @@ -36,12 +36,13 @@ overflow: auto; } -.vuuListItemHeader { +.vuuListHeader { --saltList-item-background: var(--list-item-header-background); color: var(--list-item-header-color); + font-weight: 600; } -.vuuListItemHeader[data-sticky="true"] { +.vuuListHeader[data-sticky="true"] { --saltList-item-background: var(--list-background); position: sticky; top: 0; diff --git a/vuu-ui/packages/vuu-ui-controls/src/list/List.tsx b/vuu-ui/packages/vuu-ui-controls/src/list/List.tsx index c1e7904f1..8e03994ce 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/list/List.tsx +++ b/vuu-ui/packages/vuu-ui-controls/src/list/List.tsx @@ -203,12 +203,12 @@ export const List = forwardRef(function List< focusVisible: collapsibleHeaders && appliedFocusVisible === idx.value, })} aria-expanded={expanded} - data-idx={collapsibleHeaders ? idx.value : undefined} data-index={collapsibleHeaders ? idx.value : undefined} data-highlighted={idx.value === highlightedIndex || undefined} data-sticky={stickyHeaders} data-selectable={false} id={headerId} + itemHeight={getItemHeight(idx.value)} key={`header-${idx.value}`} label={title} // role="presentation" diff --git a/vuu-ui/packages/vuu-ui-controls/src/list/common-hooks/useKeyboardNavigation.ts b/vuu-ui/packages/vuu-ui-controls/src/list/common-hooks/useKeyboardNavigation.ts index 6474b99c6..17ac6213e 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/list/common-hooks/useKeyboardNavigation.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/list/common-hooks/useKeyboardNavigation.ts @@ -18,13 +18,12 @@ import { PageUp, } from "./keyUtils"; import { - CollectionItem, NavigationHookProps, NavigationHookResult, getFirstSelectedItem, hasSelection, } from "../../common-hooks"; -import { getElementByDataIndex } from "@finos/vuu-utils"; +import { getElementByDataIndex, isValidNumber } from "@finos/vuu-utils"; export const LIST_FOCUS_VISIBLE = -2; @@ -46,18 +45,20 @@ function nextItemIdx(count: number, key: string, idx: number) { } } -const getIndexOfSelectedItem = ( - items: CollectionItem[], - selected?: string[] -) => { +const getIndexOfSelectedItem = (selected?: string[]) => { const selectedItemId = Array.isArray(selected) ? getFirstSelectedItem(selected) : undefined; if (selectedItemId) { - return items.findIndex((item) => item.id === selectedItemId); - } else { - return -1; + const el = document.getElementById(selectedItemId) as HTMLElement; + if (el) { + const index = parseInt(el.dataset.index ?? "-1"); + if (isValidNumber(index)) { + return index; + } + } } + return -1; }; const getStartIdx = ( @@ -137,24 +138,29 @@ const pageUp = async ( } }; -const isLeaf = (item: CollectionItem): boolean => - !item.header && !item.childNodes; -const isFocusable = (item: CollectionItem) => - isLeaf(item) || item.expanded !== undefined; +// const isLeaf = (item: CollectionItem): boolean => +// !item.header && !item.childNodes; +const isLeaf = (element?: HTMLElement) => element !== undefined; +// const isFocusable = (item: CollectionItem) => +// isLeaf(item) || item.expanded !== undefined; +// TODO read dom element and check for leaf item or toggleable group +const isFocusable = (container: HTMLElement, index: number) => { + const targetEl = getElementByDataIndex(container, index); + return isLeaf(targetEl); +}; -export const useKeyboardNavigation = ({ +export const useKeyboardNavigation = ({ containerRef, defaultHighlightedIndex = -1, disableHighlightOnFocus, highlightedIndex: highlightedIndexProp, - indexPositions, itemCount, onHighlight, onKeyboardNavigation, restoreLastFocus, selected, viewportItemCount, -}: NavigationHookProps): NavigationHookResult => { +}: NavigationHookProps): NavigationHookResult => { const lastFocus = useRef(-1); const [, forceRender] = useState({}); const [highlightedIndex, setHighlightedIdx, isControlledHighlighting] = @@ -198,41 +204,43 @@ export const useKeyboardNavigation = ({ const nextFocusableItemIdx = useCallback( (key = ArrowDown, idx: number = key === ArrowDown ? -1 : itemCount) => { + //TODO we don't seem to have selectedhere first time after selection if (itemCount === 0) { return -1; } else { - const indexOfSelectedItem = getIndexOfSelectedItem( - indexPositions, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - selected - ); + const isEnd = key === "End"; + const isHome = key === "Home"; // The start index is generally the highlightedIdx (passed in as idx). // We don't need it for Home and End navigation. // Special case where we have selection, but no highlighting - begin // navigation from selected item. + const indexOfSelectedItem = + isEnd || isHome || idx === -1 ? -1 : getIndexOfSelectedItem(selected); const startIdx = getStartIdx(key, idx, indexOfSelectedItem, itemCount); - let nextIdx = nextItemIdx(itemCount, key, startIdx); + + const { current: container } = containerRef; // Guard against returning zero, when first item is a header or group if ( nextIdx === 0 && key === ArrowUp && - !isFocusable(indexPositions[0]) + container && + !isFocusable(container, 0) ) { return idx; } while ( - (((key === ArrowDown || key === Home) && nextIdx < itemCount) || - ((key === ArrowUp || key === End) && nextIdx > 0)) && - !isFocusable(indexPositions[nextIdx]) + (((key === ArrowDown || isHome) && nextIdx < itemCount) || + ((key === ArrowUp || isEnd) && nextIdx > 0)) && + container && + !isFocusable(container, nextIdx) ) { nextIdx = nextItemIdx(itemCount, key, nextIdx); } return nextIdx; } }, - [indexPositions, itemCount, selected] + [containerRef, itemCount, selected] ); // does this belong here or should it be a method passed in? @@ -247,7 +255,7 @@ export const useKeyboardNavigation = ({ } else { // If mouse wan't used, then keyboard must have been keyboardNavigation.current = true; - if (indexPositions.length === 0) { + if (itemCount === 0) { setHighlightedIndex(LIST_FOCUS_VISIBLE); } else if (highlightedIndex !== -1) { // We need to force a render here. We're not changing the highlightedIdx, but we want to @@ -258,12 +266,7 @@ export const useKeyboardNavigation = ({ if (lastFocus.current !== -1) { setHighlightedIndex(lastFocus.current); } else { - const selectedItemIdx = getIndexOfSelectedItem( - indexPositions, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - selected - ); + const selectedItemIdx = getIndexOfSelectedItem(selected); if (selectedItemIdx !== -1) { setHighlightedIndex(selectedItemIdx); } else { @@ -271,12 +274,7 @@ export const useKeyboardNavigation = ({ } } } else if (hasSelection(selected)) { - const selectedItemIdx = getIndexOfSelectedItem( - indexPositions, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - selected - ); + const selectedItemIdx = getIndexOfSelectedItem(selected); setHighlightedIndex(selectedItemIdx); } else if (disableHighlightOnFocus !== true) { setHighlightedIndex(nextFocusableItemIdx()); @@ -285,7 +283,7 @@ export const useKeyboardNavigation = ({ }, [ disableHighlightOnFocus, highlightedIndex, - indexPositions, + itemCount, nextFocusableItemIdx, restoreLastFocus, selected, @@ -318,7 +316,6 @@ export const useKeyboardNavigation = ({ const handleKeyDown = useCallback( (e: KeyboardEvent) => { - console.log("handleKeyDown"); if (itemCount > 0 && isNavigationKey(e)) { e.preventDefault(); e.stopPropagation(); diff --git a/vuu-ui/packages/vuu-ui-controls/src/list/useList.ts b/vuu-ui/packages/vuu-ui-controls/src/list/useList.ts index e4f7742fe..096153c8d 100644 --- a/vuu-ui/packages/vuu-ui-controls/src/list/useList.ts +++ b/vuu-ui/packages/vuu-ui-controls/src/list/useList.ts @@ -132,12 +132,11 @@ export const useList = ({ }, setHighlightedIndex, ...keyboardHook - } = useKeyboardNavigation({ + } = useKeyboardNavigation({ containerRef: scrollContainer, defaultHighlightedIndex, disableHighlightOnFocus, highlightedIndex: highlightedIndexProp, - indexPositions: dataHook.data, itemCount: dataHook.data.length, label, onHighlight, diff --git a/vuu-ui/showcase/src/examples/Table/TableNext.examples.tsx b/vuu-ui/showcase/src/examples/Table/TableNext.examples.tsx index b9f727918..83bbbe215 100644 --- a/vuu-ui/showcase/src/examples/Table/TableNext.examples.tsx +++ b/vuu-ui/showcase/src/examples/Table/TableNext.examples.tsx @@ -51,6 +51,36 @@ export const DefaultTableNextArrayData = () => { }; DefaultTableNextArrayData.displaySequence = displaySequence++; +export const NavigationStyle = () => { + const { + typeaheadHook: _, + config: configProp, + ...props + } = useTableConfig({ + rangeChangeRowset: "full", + table: { module: "SIMUL", table: "instruments" }, + }); + + const [config, setConfig] = useState(configProp); + + const handleConfigChange = useCallback((config: TableConfig) => { + setConfig(config); + }, []); + + return ( + + ); +}; +NavigationStyle.displaySequence = displaySequence++; + export const EditableTableNextArrayData = () => { const { config, dataSource } = useTableConfig({ columnConfig: { diff --git a/vuu-ui/showcase/src/examples/UiControls/List.examples.tsx b/vuu-ui/showcase/src/examples/UiControls/List.examples.tsx index 69b69c7dc..27ea54be0 100644 --- a/vuu-ui/showcase/src/examples/UiControls/List.examples.tsx +++ b/vuu-ui/showcase/src/examples/UiControls/List.examples.tsx @@ -20,17 +20,17 @@ import { useRef, useState, } from "react"; -import { usa_states } from "./List.data"; +import { usa_states, usa_states_cities } from "./List.data"; let displaySequence = 1; export const DefaultList = () => { const handleSelect = useCallback((evt, selected) => { - console.log(`handleSelect`, { selected }); + console.log(`handleSelect ${selected}`); }, []); const handleSelectionChange = useCallback( (evt, selected) => { - console.log(`handleSelectionChange`, { selected }); + console.log(`handleSelectionChange ${selected}`); }, [] ); @@ -419,3 +419,52 @@ export const DefaultSelectedWithinViewport = () => { ); }; DefaultSelectedWithinViewport.displaySequence = displaySequence++; + +export const GroupedList = () => { + const handleSelect = useCallback((evt, selected) => { + console.log(`handleSelect ${selected}`); + }, []); + const handleSelectionChange = useCallback( + (evt, selected) => { + console.log(`handleSelectionChange ${selected}`); + }, + [] + ); + + return ( + + ); +}; +GroupedList.displaySequence = displaySequence++; + +export const GroupedListCollapsibleHeaders = () => { + const handleSelect = useCallback((evt, selected) => { + console.log(`handleSelect ${selected}`); + }, []); + const handleSelectionChange = useCallback( + (evt, selected) => { + console.log(`handleSelectionChange ${selected}`); + }, + [] + ); + + return ( + + ); +}; +GroupedListCollapsibleHeaders.displaySequence = displaySequence++; From 2486d856e48101738aac1263975b60337535c4fb Mon Sep 17 00:00:00 2001 From: heswell Date: Mon, 23 Oct 2023 10:10:35 +0100 Subject: [PATCH 3/4] fix broken import paths --- vuu-ui/packages/vuu-layout/src/toolbar/useKeyboardNavigation.ts | 2 +- vuu-ui/packages/vuu-layout/src/toolbar/useToolbar.ts | 2 +- .../vuu-table-extras/src/column-settings/ColumnNameLabel.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vuu-ui/packages/vuu-layout/src/toolbar/useKeyboardNavigation.ts b/vuu-ui/packages/vuu-layout/src/toolbar/useKeyboardNavigation.ts index aeb6e2882..ff79ee20b 100644 --- a/vuu-ui/packages/vuu-layout/src/toolbar/useKeyboardNavigation.ts +++ b/vuu-ui/packages/vuu-layout/src/toolbar/useKeyboardNavigation.ts @@ -27,7 +27,7 @@ import { } from "@finos/vuu-utils"; import { getIndexOfEditedItem } from "./toolbar-dom-utils"; import { NavigationOutOfBoundsHandler } from "./Toolbar"; -import { PopupCloseCallback } from "packages/vuu-popups/src"; +import { PopupCloseCallback } from "@finos/vuu-popups"; type directionType = "bwd" | "fwd" | "start" | "end"; type directionMap = { [key: string]: directionType }; diff --git a/vuu-ui/packages/vuu-layout/src/toolbar/useToolbar.ts b/vuu-ui/packages/vuu-layout/src/toolbar/useToolbar.ts index e01729a3e..5a53fcfd1 100644 --- a/vuu-ui/packages/vuu-layout/src/toolbar/useToolbar.ts +++ b/vuu-ui/packages/vuu-layout/src/toolbar/useToolbar.ts @@ -1,6 +1,6 @@ import type { OverflowItem, ToolbarProps } from "@finos/vuu-layout"; import { isValidNumber } from "@finos/vuu-utils"; -import { PopupCloseCallback } from "packages/vuu-popups/src"; +import { PopupCloseCallback } from "@finos/vuu-popups"; import { KeyboardEvent, MouseEvent as ReactMouseEvent, diff --git a/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnNameLabel.tsx b/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnNameLabel.tsx index 1578da446..6dd6259d4 100644 --- a/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnNameLabel.tsx +++ b/vuu-ui/packages/vuu-table-extras/src/column-settings/ColumnNameLabel.tsx @@ -1,4 +1,4 @@ -import { ColumnDescriptor } from "packages/vuu-datagrid-types"; +import { ColumnDescriptor } from "@finos/vuu-datagrid-types"; import cx from "classnames"; import { From d6e3f55e71e003c9f17418619a44aa2d43087a11 Mon Sep 17 00:00:00 2001 From: heswell Date: Mon, 23 Oct 2023 11:56:24 +0100 Subject: [PATCH 4/4] add empty inlined worker as vitext mocj fails otherwise --- vuu-ui/.gitignore | 2 +- vuu-ui/packages/vuu-data/src/inlined-worker.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 vuu-ui/packages/vuu-data/src/inlined-worker.js diff --git a/vuu-ui/.gitignore b/vuu-ui/.gitignore index c4a26c374..c55fe6a5b 100644 --- a/vuu-ui/.gitignore +++ b/vuu-ui/.gitignore @@ -1 +1 @@ -inlined-worker.js \ No newline at end of file +# inlined-worker.js \ No newline at end of file diff --git a/vuu-ui/packages/vuu-data/src/inlined-worker.js b/vuu-ui/packages/vuu-data/src/inlined-worker.js new file mode 100644 index 000000000..e0563efac --- /dev/null +++ b/vuu-ui/packages/vuu-data/src/inlined-worker.js @@ -0,0 +1 @@ +export const workerSourceCode = "";