mirror of https://github.com/buster-so/buster.git
additional context provider logic
This commit is contained in:
parent
f9b41bc6de
commit
16fadc1b5c
|
@ -6,16 +6,18 @@ import { cn } from '@/lib/classMerge';
|
||||||
import { CaretDown, CaretUp } from '../../../icons/NucleoIconFilled';
|
import { CaretDown, CaretUp } from '../../../icons/NucleoIconFilled';
|
||||||
import { HEADER_HEIGHT } from './constants';
|
import { HEADER_HEIGHT } from './constants';
|
||||||
import { useSortColumnContext } from './SortColumnWrapper';
|
import { useSortColumnContext } from './SortColumnWrapper';
|
||||||
|
import { Virtualizer } from '@tanstack/react-virtual';
|
||||||
|
import { useMount } from '@/hooks';
|
||||||
|
|
||||||
interface DraggableHeaderProps {
|
interface DraggableHeaderProps {
|
||||||
header: Header<Record<string, string | number | Date | null>, unknown>;
|
header: Header<Record<string, string | number | Date | null>, unknown>;
|
||||||
resizable: boolean;
|
resizable: boolean;
|
||||||
sortable: boolean;
|
sortable: boolean;
|
||||||
overTargetId: string | null;
|
isOverTarget: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DraggableHeader: React.FC<DraggableHeaderProps> = React.memo(
|
const DraggableHeader: React.FC<DraggableHeaderProps> = React.memo(
|
||||||
({ header, sortable, resizable, overTargetId }) => {
|
({ header, sortable, resizable, isOverTarget }) => {
|
||||||
// Set up dnd-kit's useDraggable for this header cell
|
// Set up dnd-kit's useDraggable for this header cell
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
|
@ -35,8 +37,6 @@ const DraggableHeader: React.FC<DraggableHeaderProps> = React.memo(
|
||||||
id: `droppable-${header.id}`
|
id: `droppable-${header.id}`
|
||||||
});
|
});
|
||||||
|
|
||||||
const isOverTarget = overTargetId === header.id;
|
|
||||||
|
|
||||||
const style: CSSProperties = {
|
const style: CSSProperties = {
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
|
@ -53,8 +53,7 @@ const DraggableHeader: React.FC<DraggableHeaderProps> = React.memo(
|
||||||
className={cn(
|
className={cn(
|
||||||
'group bg-background relative border-r select-none last:border-r-0',
|
'group bg-background relative border-r select-none last:border-r-0',
|
||||||
header.column.getIsResizing() ? 'bg-primary/8' : 'hover:bg-item-hover',
|
header.column.getIsResizing() ? 'bg-primary/8' : 'hover:bg-item-hover',
|
||||||
isOverTarget &&
|
isOverTarget && 'bg-primary/10 border-primary inset border border-r border-dashed'
|
||||||
'bg-primary/10 border-primary inset rounded-sm border border-r border-dashed'
|
|
||||||
)}
|
)}
|
||||||
// onClick toggles sorting if enabled
|
// onClick toggles sorting if enabled
|
||||||
onClick={header.column.getCanSort() ? header.column.getToggleSortingHandler() : undefined}>
|
onClick={header.column.getCanSort() ? header.column.getToggleSortingHandler() : undefined}>
|
||||||
|
@ -101,41 +100,31 @@ const DraggableHeader: React.FC<DraggableHeaderProps> = React.memo(
|
||||||
|
|
||||||
DraggableHeader.displayName = 'DraggableHeader';
|
DraggableHeader.displayName = 'DraggableHeader';
|
||||||
|
|
||||||
// Header content component to use in the DragOverlay
|
|
||||||
const HeaderDragOverlay = ({
|
|
||||||
header
|
|
||||||
}: {
|
|
||||||
header: Header<Record<string, string | number | Date | null>, unknown>;
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="flex items-center rounded-sm border bg-white p-2 shadow-lg"
|
|
||||||
style={{
|
|
||||||
width: header.column.getSize(),
|
|
||||||
height: `${HEADER_HEIGHT}px`,
|
|
||||||
opacity: 0.85,
|
|
||||||
transform: 'translate3d(0, 0, 0)', // Ensure no unexpected transforms are applied
|
|
||||||
pointerEvents: 'none' // Prevent the overlay from intercepting pointer events
|
|
||||||
}}>
|
|
||||||
{flexRender(header.column.columnDef.header, header.getContext())}
|
|
||||||
{header.column.getIsSorted() === 'asc' && <span> 🔼</span>}
|
|
||||||
{header.column.getIsSorted() === 'desc' && <span> 🔽</span>}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface DataGridHeaderProps {
|
interface DataGridHeaderProps {
|
||||||
table: Table<Record<string, string | number | Date | null>>;
|
table: Table<Record<string, string | number | Date | null>>;
|
||||||
sortable: boolean;
|
sortable: boolean;
|
||||||
resizable: boolean;
|
resizable: boolean;
|
||||||
|
rowVirtualizer: Virtualizer<HTMLDivElement, Element>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DataGridHeader: React.FC<DataGridHeaderProps> = ({ table, sortable, resizable }) => {
|
export const DataGridHeader: React.FC<DataGridHeaderProps> = ({
|
||||||
const { activeId, overTargetId, activeHeader } = useSortColumnContext((x) => x);
|
rowVirtualizer,
|
||||||
|
table,
|
||||||
|
sortable,
|
||||||
|
resizable
|
||||||
|
}) => {
|
||||||
|
const overTargetId = useSortColumnContext((x) => x.overTargetId);
|
||||||
|
|
||||||
|
const showScrollShadow = (rowVirtualizer?.scrollOffset || 0) > 10;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<thead className="bg-background sticky top-0 z-10 w-full" suppressHydrationWarning>
|
<thead className="bg-background sticky top-0 z-10 w-full" suppressHydrationWarning>
|
||||||
<tr className="flex border-b shadow">
|
<tr
|
||||||
|
className={cn(
|
||||||
|
'flex border-b transition-all duration-200',
|
||||||
|
showScrollShadow && 'shadow-sm'
|
||||||
|
)}>
|
||||||
{table
|
{table
|
||||||
.getHeaderGroups()[0]
|
.getHeaderGroups()[0]
|
||||||
?.headers.map(
|
?.headers.map(
|
||||||
|
@ -145,21 +134,13 @@ export const DataGridHeader: React.FC<DataGridHeaderProps> = ({ table, sortable,
|
||||||
header={header}
|
header={header}
|
||||||
sortable={sortable}
|
sortable={sortable}
|
||||||
resizable={resizable}
|
resizable={resizable}
|
||||||
overTargetId={overTargetId}
|
isOverTarget={overTargetId === header.id}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{/* Drag Overlay */}
|
|
||||||
<DragOverlay
|
|
||||||
wrapperElement="span"
|
|
||||||
adjustScale={false}
|
|
||||||
dropAnimation={null} // Using null to completely disable animation
|
|
||||||
zIndex={1000}>
|
|
||||||
{activeId && activeHeader && <HeaderDragOverlay header={activeHeader} />}
|
|
||||||
</DragOverlay>
|
|
||||||
</thead>
|
</thead>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,13 +9,15 @@ import {
|
||||||
DragOverEvent,
|
DragOverEvent,
|
||||||
DragEndEvent,
|
DragEndEvent,
|
||||||
DndContext,
|
DndContext,
|
||||||
pointerWithin
|
pointerWithin,
|
||||||
|
DragOverlay
|
||||||
} from '@dnd-kit/core';
|
} from '@dnd-kit/core';
|
||||||
import { restrictToHorizontalAxis } from '@dnd-kit/modifiers';
|
import { restrictToHorizontalAxis } from '@dnd-kit/modifiers';
|
||||||
import { arrayMove } from '@dnd-kit/sortable';
|
import { arrayMove } from '@dnd-kit/sortable';
|
||||||
import { Header, Table } from '@tanstack/react-table';
|
import { flexRender, Header, Table } from '@tanstack/react-table';
|
||||||
import { useState, useRef, useMemo, useEffect } from 'react';
|
import { useState, useRef, useMemo, useEffect } from 'react';
|
||||||
import { useContextSelector, createContext } from 'use-context-selector';
|
import { useContextSelector, createContext } from 'use-context-selector';
|
||||||
|
import { HEADER_HEIGHT } from './constants';
|
||||||
|
|
||||||
export const SortColumnWrapper: React.FC<{
|
export const SortColumnWrapper: React.FC<{
|
||||||
table: Table<Record<string, string | number | Date | null>>;
|
table: Table<Record<string, string | number | Date | null>>;
|
||||||
|
@ -136,24 +138,51 @@ export const SortColumnWrapper: React.FC<{
|
||||||
onDragStart={onDragStart}
|
onDragStart={onDragStart}
|
||||||
onDragOver={onDragOver}
|
onDragOver={onDragOver}
|
||||||
onDragEnd={onDragEnd}>
|
onDragEnd={onDragEnd}>
|
||||||
<SortColumnContext.Provider value={{ activeId, overTargetId, activeHeader }}>
|
<SortColumnContext.Provider value={{ overTargetId }}>
|
||||||
{children}
|
{children}
|
||||||
|
|
||||||
|
<DragOverlay
|
||||||
|
wrapperElement="span"
|
||||||
|
adjustScale={false}
|
||||||
|
dropAnimation={null} // Using null to completely disable animation
|
||||||
|
zIndex={1000}>
|
||||||
|
{activeId && activeHeader && <HeaderDragOverlay header={activeHeader} />}
|
||||||
|
</DragOverlay>
|
||||||
</SortColumnContext.Provider>
|
</SortColumnContext.Provider>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
type SortColumnContextType = {
|
type SortColumnContextType = {
|
||||||
activeId: string | null;
|
|
||||||
overTargetId: string | null;
|
overTargetId: string | null;
|
||||||
activeHeader: Header<Record<string, string | number | Date | null>, unknown> | null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SortColumnContext = createContext<SortColumnContextType>({
|
export const SortColumnContext = createContext<SortColumnContextType>({
|
||||||
activeId: null,
|
overTargetId: null
|
||||||
overTargetId: null,
|
|
||||||
activeHeader: null
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const useSortColumnContext = <T,>(selector: (ctx: SortColumnContextType) => T) =>
|
export const useSortColumnContext = <T,>(selector: (ctx: SortColumnContextType) => T) =>
|
||||||
useContextSelector(SortColumnContext, selector);
|
useContextSelector(SortColumnContext, selector);
|
||||||
|
|
||||||
|
// Header content component to use in the DragOverlay
|
||||||
|
const HeaderDragOverlay = ({
|
||||||
|
header
|
||||||
|
}: {
|
||||||
|
header: Header<Record<string, string | number | Date | null>, unknown>;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex items-center rounded-sm border bg-white p-2 shadow-lg"
|
||||||
|
style={{
|
||||||
|
width: header.column.getSize(),
|
||||||
|
height: `${HEADER_HEIGHT}px`,
|
||||||
|
opacity: 0.85,
|
||||||
|
transform: 'translate3d(0, 0, 0)', // Ensure no unexpected transforms are applied
|
||||||
|
pointerEvents: 'none' // Prevent the overlay from intercepting pointer events
|
||||||
|
}}>
|
||||||
|
{flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
|
{header.column.getIsSorted() === 'asc' && <span> 🔼</span>}
|
||||||
|
{header.column.getIsSorted() === 'desc' && <span> 🔽</span>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -126,7 +126,12 @@ export const TanStackDataGrid: React.FC<TanStackDataGridProps> = React.memo(
|
||||||
setColOrder={setColOrder}
|
setColOrder={setColOrder}
|
||||||
onReorderColumns={onReorderColumns}>
|
onReorderColumns={onReorderColumns}>
|
||||||
<table className="bg-background w-full">
|
<table className="bg-background w-full">
|
||||||
<DataGridHeader table={table} sortable={sortable} resizable={resizable} />
|
<DataGridHeader
|
||||||
|
table={table}
|
||||||
|
sortable={sortable}
|
||||||
|
resizable={resizable}
|
||||||
|
rowVirtualizer={rowVirtualizer}
|
||||||
|
/>
|
||||||
|
|
||||||
<tbody
|
<tbody
|
||||||
className="relative"
|
className="relative"
|
||||||
|
|
Loading…
Reference in New Issue