11import classNames from "classnames" ;
2- import {
3- DragEvent ,
4- DragEventHandler ,
5- HTMLAttributes ,
6- KeyboardEvent ,
7- MouseEvent ,
8- ReactElement ,
9- ReactNode ,
10- useMemo
11- } from "react" ;
12- import { FaArrowsAltV } from "./icons/FaArrowsAltV" ;
13- import { FaLongArrowAltDown } from "./icons/FaLongArrowAltDown" ;
14- import { FaLongArrowAltUp } from "./icons/FaLongArrowAltUp" ;
15-
16- import ColumnHeader from "./ColumnHeader" ;
17-
18- import { useColumn , useColumnsStore , useDatagridConfig , useHeaderDragDrop } from "../model/hooks/injection-hooks" ;
19- import { GridColumn } from "../typings/GridColumn" ;
2+ import { ReactElement } from "react" ;
3+ import { ColumnHeader } from "./ColumnHeader" ;
4+ import { useColumn , useColumnsStore , useDatagridConfig , useColumnHeaderVM } from "../model/hooks/injection-hooks" ;
205import { ColumnResizerProps } from "./ColumnResizer" ;
21- import { ColumnHeaderViewModel } from "../features/column/ColumnHeader.viewModel" ;
226import { observer } from "mobx-react-lite" ;
237
248export interface ColumnContainerProps {
259 isLast ?: boolean ;
2610 resizer : ReactElement < ColumnResizerProps > ;
2711}
28- interface DragHandleProps {
29- draggable : boolean ;
30- onDragStart ?: DragEventHandler < HTMLSpanElement > ;
31- onDragEnd ?: DragEventHandler < HTMLSpanElement > ;
32- }
3312
3413export const ColumnContainer = observer ( function ColumnContainer ( props : ColumnContainerProps ) : ReactElement {
3514 const { columnsFilterable, id : gridId } = useDatagridConfig ( ) ;
36- const columnsStore = useColumnsStore ( ) ;
37- const column = useColumn ( ) ;
38- const { canDrag , canSort } = column ;
15+ const { columnFilters } = useColumnsStore ( ) ;
16+ const { canSort , columnId , setHeaderElementRef , columnIndex , canResize , sortDir , header } = useColumn ( ) ;
17+ const { draggableProps , dropTarget , dragging } = useColumnHeaderVM ( ) ;
3918
40- const headerDragDropStore = useHeaderDragDrop ( ) ;
41- const columnHeaderVM = useMemo (
42- ( ) =>
43- new ColumnHeaderViewModel ( {
44- dndStore : headerDragDropStore ,
45- columnsStore,
46- columnsDraggable : canDrag
47- } ) ,
48- [ headerDragDropStore , columnsStore , canDrag ]
49- ) ;
50- const draggableProps = columnHeaderVM . draggableProps ;
51- const dropTarget = columnHeaderVM . dropTarget ;
52- const isDragging = columnHeaderVM . dragging ;
53-
54- const sortProps = canSort ? getSortProps ( column ) : null ;
55- const caption = column . header . trim ( ) ;
19+ const caption = header . trim ( ) ;
5620
5721 return (
5822 < div
59- aria-sort = { getAriaSort ( canSort , column ) }
23+ aria-sort = { getAriaSort ( canSort , sortDir ) }
6024 className = { classNames ( "th" , {
61- [ `drop-${ dropTarget ?. [ 1 ] } ` ] : column . columnId === dropTarget ?. [ 0 ] ,
62- dragging : column . columnId === isDragging ?. [ 1 ] ,
63- "dragging-over-self" : column . columnId === isDragging ?. [ 1 ] && ! dropTarget
25+ [ `drop-${ dropTarget ?. [ 1 ] } ` ] : columnId === dropTarget ?. [ 0 ] ,
26+ dragging : columnId === dragging ?. [ 1 ] ,
27+ "dragging-over-self" : columnId === dragging ?. [ 1 ] && ! dropTarget
6428 } ) }
6529 role = "columnheader"
6630 style = { ! canSort ? { cursor : "unset" } : undefined }
6731 title = { caption }
68- ref = { ref => column . setHeaderElementRef ( ref ) }
69- data-column-id = { column . columnId }
32+ ref = { ref => setHeaderElementRef ( ref ) }
33+ data-column-id = { columnId }
7034 onDrop = { draggableProps . onDrop }
7135 onDragEnter = { draggableProps . onDragEnter }
7236 onDragOver = { draggableProps . onDragOver }
7337 >
74- < div className = { classNames ( "column-container" ) } id = { `${ gridId } -column${ column . columnId } ` } >
75- < ColumnHeader
76- sortProps = { sortProps }
77- canSort = { canSort }
78- caption = { caption }
79- isDragging = { isDragging }
80- columnAlignment = { column . alignment }
81- >
82- { draggableProps . draggable && (
83- < DragHandle
84- draggable = { draggableProps . draggable }
85- onDragStart = { draggableProps . onDragStart }
86- onDragEnd = { draggableProps . onDragEnd }
87- />
88- ) }
89- < span style = { draggableProps . draggable ? { paddingInlineStart : "4px" } : undefined } >
90- { caption . length > 0 ? caption : "\u00a0" }
91- </ span >
92- { canSort ? < SortIcon /> : null }
93- </ ColumnHeader >
38+ < div className = { classNames ( "column-container" ) } id = { `${ gridId } -column${ columnId } ` } >
39+ < ColumnHeader />
9440 { columnsFilterable && (
95- < div className = "filter" style = { { pointerEvents : isDragging ? "none" : undefined } } >
96- { columnsStore . columnFilters [ column . columnIndex ] ?. renderFilterWidgets ( ) }
41+ < div className = "filter" style = { { pointerEvents : dragging ? "none" : undefined } } >
42+ { columnFilters [ columnIndex ] ?. renderFilterWidgets ( ) }
9743 </ div >
9844 ) }
9945 </ div >
100- { column . canResize ? props . resizer : null }
46+ { canResize ? props . resizer : null }
10147 </ div >
10248 ) ;
10349} ) ;
10450
105- function DragHandle ( { draggable, onDragStart, onDragEnd } : DragHandleProps ) : ReactElement {
106- const handleMouseDown = ( e : MouseEvent < HTMLSpanElement > ) : void => {
107- // Only stop propagation, don't prevent default - we need default for drag to work
108- e . stopPropagation ( ) ;
109- } ;
110-
111- const handleClick = ( e : MouseEvent < HTMLSpanElement > ) : void => {
112- // Stop click events from bubbling to prevent sorting
113- e . stopPropagation ( ) ;
114- e . preventDefault ( ) ;
115- } ;
116-
117- const handleDragStart = ( e : DragEvent < HTMLSpanElement > ) : void => {
118- // Don't stop propagation here - let the drag start properly
119- if ( onDragStart ) {
120- onDragStart ( e ) ;
121- }
122- } ;
123-
124- const handleDragEnd = ( e : DragEvent < HTMLSpanElement > ) : void => {
125- if ( onDragEnd ) {
126- onDragEnd ( e ) ;
127- }
128- } ;
129-
130- return (
131- < span
132- className = "drag-handle"
133- draggable = { draggable }
134- onDragStart = { handleDragStart }
135- onDragEnd = { handleDragEnd }
136- onMouseDown = { handleMouseDown }
137- onClick = { handleClick }
138- >
139- ⠿
140- </ span >
141- ) ;
142- }
143-
144- function SortIcon ( ) : ReactNode {
145- const column = useColumn ( ) ;
146- switch ( column . sortDir ) {
147- case "asc" :
148- return < FaLongArrowAltUp /> ;
149- case "desc" :
150- return < FaLongArrowAltDown /> ;
151- default :
152- return < FaArrowsAltV /> ;
153- }
154- }
155-
156- function getAriaSort ( canSort : boolean , column : GridColumn ) : "ascending" | "descending" | "none" | undefined {
51+ function getAriaSort ( canSort : boolean , sortDir : string | undefined ) : "ascending" | "descending" | "none" | undefined {
15752 if ( ! canSort ) {
15853 return undefined ;
15954 }
16055
161- switch ( column . sortDir ) {
56+ switch ( sortDir ) {
16257 case "asc" :
16358 return "ascending" ;
16459 case "desc" :
@@ -167,19 +62,3 @@ function getAriaSort(canSort: boolean, column: GridColumn): "ascending" | "desce
16762 return "none" ;
16863 }
16964}
170-
171- function getSortProps ( column : GridColumn ) : HTMLAttributes < HTMLDivElement > {
172- return {
173- onClick : ( ) => {
174- column . toggleSort ( ) ;
175- } ,
176- onKeyDown : ( e : KeyboardEvent < HTMLDivElement > ) => {
177- if ( e . key === "Enter" || e . key === " " ) {
178- e . preventDefault ( ) ;
179- column . toggleSort ( ) ;
180- }
181- } ,
182- role : "button" ,
183- tabIndex : 0
184- } ;
185- }
0 commit comments