Skip to content

Commit

Permalink
fix(Table): scroll handlers and menu handlers, fix double scroll (#2564)
Browse files Browse the repository at this point in the history
  • Loading branch information
YossiSaadi authored Oct 30, 2024
1 parent bd382b7 commit 214350b
Show file tree
Hide file tree
Showing 16 changed files with 194 additions and 199 deletions.
8 changes: 8 additions & 0 deletions packages/core/src/components/Table/Table/Table.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,12 @@
}
}
}

&.virtualized {
overflow: hidden;
}

&.hasScroll {
--sticky-cell-box-shadow: 3px 0 4px rgba(0, 0, 0, 0.1);
}
}
88 changes: 80 additions & 8 deletions packages/core/src/components/Table/Table/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { forwardRef, ReactElement } from "react";
import React, { forwardRef, ReactElement, UIEventHandler, useCallback, useMemo, useRef, useState } from "react";
import cx from "classnames";
import { SubIcon, VibeComponent, VibeComponentProps, withStaticProps } from "../../../types";
import { ITableHeaderProps } from "../TableHeader/TableHeader";
Expand All @@ -10,7 +10,9 @@ import { RowHeights, RowSizes } from "./TableConsts";
import styles from "./Table.module.scss";
import { TableProvider } from "../context/TableContext/TableContext";
import { TableRowMenuProvider } from "../context/TableRowMenuContext/TableRowMenuContext";
import TableRoot from "./TableRoot";
import useMergeRef from "../../../hooks/useMergeRef";
import { TableProviderValue } from "../context/TableContext/TableContext.types";
import { TableRowMenuProviderValue } from "../context/TableRowMenuContext/TableRowMenuContext.types";

export type TableLoadingStateType = "long-text" | "medium-text" | "circle" | "rectangle";

Expand Down Expand Up @@ -61,7 +63,35 @@ const Table: VibeComponent<ITableProps, HTMLDivElement> & {
},
ref
) => {
const classNames = cx(styles.table, { [styles.border]: !withoutBorder }, className);
const tableRootRef = useRef<HTMLDivElement>(null);
const mergedRef = useMergeRef(ref, tableRootRef);

const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
const [hoveredRowRef, setHoveredRowRef] = useState<React.RefObject<HTMLDivElement>>(null);

const resetHoveredRow = useCallback(() => {
setIsMenuOpen(false);
setHoveredRowRef(null);
}, []);

const [isVirtualized, setIsVirtualized] = useState<boolean>(false);
const markTableAsVirtualized = useCallback(() => {
setIsVirtualized(true);
}, []);

const [scrollLeft, setScrollLeft] = useState<number>(0);

const onScroll = useCallback<UIEventHandler<HTMLDivElement>>(
e => {
resetHoveredRow();
if (!isVirtualized) {
const newLeft = (e.target as HTMLDivElement).scrollLeft;
setScrollLeft(newLeft);
}
},
[resetHoveredRow, isVirtualized]
);

const { gridTemplateColumns } = getTableRowLayoutStyles(columns);

/**
Expand All @@ -74,14 +104,56 @@ const Table: VibeComponent<ITableProps, HTMLDivElement> & {
...style
} as React.CSSProperties;

const testId = dataTestId || getTestId(ComponentDefaultTestId.TABLE, id);
const tableProviderValue = useMemo<TableProviderValue>(
() => ({
columns,
dataState,
emptyState,
errorState,
size,
tableRootRef,
isVirtualized,
markTableAsVirtualized,
scrollLeft,
setScrollLeft: (scrollAmount: number) => setScrollLeft(scrollAmount)
}),
[columns, dataState, emptyState, errorState, isVirtualized, markTableAsVirtualized, scrollLeft, size]
);

const tableRowMenuProviderValue = useMemo<TableRowMenuProviderValue>(
() => ({
tableRootRef,
hoveredRowRef,
isMenuOpen,
resetHoveredRow,
setHoveredRowRef: (rowRef: React.RefObject<HTMLDivElement>) => setHoveredRowRef(rowRef),
setIsMenuOpen: (isOpen: boolean) => setIsMenuOpen(isOpen)
}),
[hoveredRowRef, isMenuOpen, resetHoveredRow, setHoveredRowRef]
);

return (
<TableProvider value={{ columns, dataState, emptyState, errorState, size }}>
<TableRowMenuProvider>
<TableRoot ref={ref} id={id} className={classNames} style={calculatedStyle} data-testid={testId}>
<TableProvider value={tableProviderValue}>
<TableRowMenuProvider value={tableRowMenuProviderValue}>
<div
ref={mergedRef}
id={id}
className={cx(
styles.table,
{
[styles.border]: !withoutBorder,
[styles.virtualized]: isVirtualized,
[styles.hasScroll]: scrollLeft > 0
},
className
)}
data-testid={dataTestId || getTestId(ComponentDefaultTestId.TABLE, id)}
role="table"
style={calculatedStyle}
onScroll={onScroll}
>
{children}
</TableRoot>
</div>
</TableRowMenuProvider>
</TableProvider>
);
Expand Down

This file was deleted.

44 changes: 0 additions & 44 deletions packages/core/src/components/Table/Table/TableRoot.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ export function mockUseTable() {
errorState: <div />,
size: RowSizes.MEDIUM,
tableRootRef: { current: null },
isVirtualized: false,
markTableAsVirtualized: jest.fn(),
scrollLeft: 0,
onTableRootScroll: jest.fn(),
setScrollLeft: jest.fn(),
headRef: { current: null },
onHeadScroll: jest.fn(),
virtualizedListRef: { current: null },
onVirtualizedListScroll: jest.fn(),
isVirtualized: false,
markTableAsVirtualized: jest.fn()
onVirtualizedListScroll: jest.fn()
} satisfies ITableContext)
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
import React from "react";
import React, { forwardRef, useRef } from "react";
import { TableContainerProvider } from "../context/TableContainerContext/TableContainerContext";
import TableContainerRoot from "./TableContainerRoot";
import { TableContainerProps } from "./TableContainer.types";
import { getTestId } from "../../../tests/test-ids-utils";
import { ComponentDefaultTestId } from "../../../tests/constants";
import cx from "classnames";
import styles from "./TableContainer.module.scss";

const TableContainer = ({ id, className, "data-testid": dataTestId, style, children }: TableContainerProps) => {
return (
<TableContainerProvider>
<TableContainerRoot
id={id}
className={className}
data-testid={dataTestId || getTestId(ComponentDefaultTestId.TABLE_CONTAINER, id)}
style={style}
>
{children}
</TableContainerRoot>
</TableContainerProvider>
);
};
const TableContainer = forwardRef(
(
{ id, className, "data-testid": dataTestId, style, children }: TableContainerProps,
ref: React.ForwardedRef<HTMLDivElement>
) => {
const menuContainerRef = useRef<HTMLDivElement>(null);

return (
<TableContainerProvider value={{ menuContainerRef }}>
<div
ref={ref}
id={id}
className={cx(styles.tableContainer, className)}
data-testid={dataTestId || getTestId(ComponentDefaultTestId.TABLE_CONTAINER, id)}
style={style}
>
<div ref={menuContainerRef} className={styles.menuContainer} />
{children}
</div>
</TableContainerProvider>
);
}
);

export default TableContainer;

This file was deleted.

4 changes: 2 additions & 2 deletions packages/core/src/components/Table/TableRow/TableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const TableRow: VibeComponent<ITableRowProps, HTMLDivElement> = forwardRef(
const mergedRef = useMergeRef(componentRef, ref);
const { onMouseOverRow, onMouseLeaveRow } = useTableRowMenu();

const onMouseOver = useCallback(() => {
const onMouseEnter = useCallback(() => {
onMouseOverRow(componentRef);
}, [onMouseOverRow]);

Expand All @@ -36,7 +36,7 @@ const TableRow: VibeComponent<ITableRowProps, HTMLDivElement> = forwardRef(
aria-selected={highlighted || false}
className={cx(styles.tableRow, className)}
style={style}
onMouseOver={onMouseOver}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeaveRow}
tabIndex={-1}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const TableRowMenu = forwardRef(
<div
className={cx(styles.rowMenuContainer, getStyle(styles, size))}
style={{ top: menuButtonPosition }}
onMouseOver={onMouseOverRowMenu}
onMouseEnter={onMouseOverRowMenu}
onMouseLeave={onMouseLeaveRowMenu}
>
<MenuButton
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import React, { createContext, useContext, useMemo, useRef } from "react";
import React, { createContext, useContext } from "react";
import { ITableContainerContext, ITableContainerProviderProps } from "./TableContainerContext.types";

const TableContainerContext = createContext<ITableContainerContext | undefined>(undefined);

export const TableContainerProvider = ({ children }: ITableContainerProviderProps) => {
const menuContainerRef = useRef<HTMLDivElement>(null);
const contextValue = useMemo<ITableContainerContext>(() => ({ menuContainerRef }), [menuContainerRef]);
return <TableContainerContext.Provider value={contextValue}>{children}</TableContainerContext.Provider>;
export const TableContainerProvider = ({ value, children }: ITableContainerProviderProps) => {
return <TableContainerContext.Provider value={value}>{children}</TableContainerContext.Provider>;
};

export const useTableContainer = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React from "react";

export interface ITableContainerContext {
menuContainerRef: React.MutableRefObject<HTMLDivElement>;
export type ITableContainerContext = TableContainerProviderValue;

export interface TableContainerProviderValue {
menuContainerRef: React.RefObject<HTMLDivElement>;
}

export interface ITableContainerProviderProps {
value: TableContainerProviderValue;
children: React.ReactNode;
}
Loading

0 comments on commit 214350b

Please sign in to comment.