import React, { useMemo, useRef, useState } from 'react';
import { useAsync, useForkRef, useIsomorphicLayoutEffect, useResize } from '@react-devui/hooks';
import { getClassName, isSimpleArrayEqual } from '@react-devui/utils';
import { registerComponentMate } from '../../utils';
import { useComponentConfig, usePrefixConfig } from '../root';
import { DTableEmpty } from './TableEmpty';
import { DTableExpand } from './TableExpand';
import { DTableFilter } from './TableFilter';
import { DTableSearch } from './TableSearch';
import { DTableTd } from './TableTd';
import { DTableTh } from './TableTh';
import { DTableThAction } from './TableThAction';
export interface DTableContextData {
gFixed: ('left' | 'right')[];
gEllipsis: boolean;
}
export const DTableContext = React.createContext<DTableContextData | null>(null);
export interface DTableProps extends React.HTMLAttributes<HTMLDivElement> {
dBorder?: boolean;
dEllipsis?: boolean;
}
const { COMPONENT_NAME } = registerComponentMate({ COMPONENT_NAME: 'DTable' as const });
function Table(props: DTableProps, ref: React.ForwardedRef<HTMLDivElement>): JSX.Element | null {
const {
children,
dBorder = false,
dEllipsis = false,
...restProps
} = useComponentConfig(COMPONENT_NAME, props);
const dPrefix = usePrefixConfig();
const elRef = useRef<HTMLDivElement>(null);
const combineElRef = useForkRef(elRef, ref);
const dataRef = useRef<{
clearTid?: () => void;
}>({});
const async = useAsync();
const [fixed, setFixed] = useState<('left' | 'right')[]>([]);
const getFixed = (el: HTMLDivElement) => {
const scrollLeft = el.scrollLeft;
const maxScrollLeft = el.scrollWidth - el.clientWidth;
let newFixed: ('left' | 'right')[] = [];
if (maxScrollLeft === 0) {
newFixed = [];
} else if (scrollLeft === 0) {
newFixed = ['right'];
} else if (Math.ceil(scrollLeft) >= maxScrollLeft) {
newFixed = ['left'];
} else {
newFixed = ['left', 'right'];
}
if (!isSimpleArrayEqual(newFixed, fixed)) {
setFixed(newFixed);
}
};
useIsomorphicLayoutEffect(() => {
if (elRef.current) {
getFixed(elRef.current);
}
}, []);
useResize(elRef, () => {
dataRef.current.clearTid?.();
dataRef.current.clearTid = async.setTimeout(() => {
dataRef.current.clearTid = undefined;
if (elRef.current) {
getFixed(elRef.current);
}
}, 100);
});
const contextValue = useMemo<DTableContextData>(
() => ({
gFixed: fixed,
gEllipsis: dEllipsis,
}),
[dEllipsis, fixed]
);
return (
<DTableContext.Provider value={contextValue}>
<div
{...restProps}
ref={combineElRef}
className={getClassName(restProps.className, `${dPrefix}table`, {
[`${dPrefix}table--border`]: dBorder,
})}
onScroll={(e) => {
restProps.onScroll?.(e);
getFixed(e.currentTarget);
}}
>
{children}
</div>
</DTableContext.Provider>
);
}
export const DTable: {
(props: DTableProps & React.RefAttributes<HTMLDivElement>): ReturnType<typeof Table>;
Th: typeof DTableTh;
ThAction: typeof DTableThAction;
Td: typeof DTableTd;
Empty: typeof DTableEmpty;
Filter: typeof DTableFilter;
Search: typeof DTableSearch;
Expand: typeof DTableExpand;
} = React.forwardRef(Table) as any;
DTable.Th = DTableTh;
DTable.ThAction = DTableThAction;
DTable.Td = DTableTd;
DTable.Empty = DTableEmpty;
DTable.Filter = DTableFilter;
DTable.Search = DTableSearch;
DTable.Expand = DTableExpand;