Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Table): scroll handlers and menu handlers, fix double scroll #2564

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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