Skip to content
This repository was archived by the owner on Mar 25, 2025. It is now read-only.

Commit d6de26f

Browse files
AAntonSBTigge
authored andcommitted
feat(table): double-click resizes adjacent columns
Double clicking a divider resizes the two adjacent columns. Created a data-col field to be able to look up the columns from the ColumnResizerRow component. Then inside columnResizerRow there is a double-click function on the dividers that resizes the adjecent columns to the fit the size of their content.
1 parent 8fab4b7 commit d6de26f

File tree

6 files changed

+108
-5
lines changed

6 files changed

+108
-5
lines changed

packages/core/src/Table/ColumnResizerRow.tsx

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,73 @@ const ResizeMarker = styled.div<{
9797
`
9898

9999
/**
100+
* widthLookup
101+
*
102+
* This lookup returns the size a column would need to
103+
* accommodate it's largest element without overflow.
104+
*/
105+
const widthLookup = (
106+
tableRef: React.RefObject<HTMLDivElement>,
107+
separator: number
108+
): readonly [number, number] => {
109+
const column1Elements = tableRef.current?.querySelectorAll(
110+
`[data-col="${separator}"]`
111+
)
112+
let maxColumn1Width = 0
113+
for (const el of column1Elements ?? []) {
114+
maxColumn1Width = Math.max(
115+
maxColumn1Width,
116+
el.children[0].getBoundingClientRect().width
117+
)
118+
}
119+
120+
const column2Elements = tableRef.current?.querySelectorAll(
121+
`[data-col="${separator + 1}"]`
122+
)
123+
let maxColumn2Width = 0
124+
for (const el of column2Elements ?? []) {
125+
maxColumn2Width = Math.max(
126+
maxColumn2Width,
127+
el.children[0].getBoundingClientRect().width
128+
)
129+
}
130+
131+
return [
132+
maxColumn1Width + TABLE_DIMENSIONS.PADDING_LEFT,
133+
maxColumn2Width + TABLE_DIMENSIONS.PADDING_LEFT,
134+
]
135+
}
136+
137+
interface UpdateWidthsArgs {
138+
readonly tableRef: React.RefObject<HTMLDivElement>
139+
readonly separator: number
140+
readonly currentSizes: ReadonlyArray<number>
141+
readonly minColumnWidth: number
142+
}
143+
144+
const updateWidths = ({
145+
tableRef,
146+
separator,
147+
currentSizes,
148+
minColumnWidth,
149+
}: UpdateWidthsArgs) => {
150+
const [col1, col2] = widthLookup(tableRef, separator)
151+
const prevCol1 = currentSizes[separator]
152+
const prevCol2 = currentSizes[separator + 1]
153+
154+
const newCol1 = Math.min(Math.max(col1, minColumnWidth), prevCol1)
155+
const newCol2 = Math.min(Math.max(col2, minColumnWidth), prevCol2)
156+
157+
const scaleFactor = (prevCol1 + prevCol2) / (newCol1 + newCol2)
158+
159+
const newWidths = [...currentSizes]
160+
newWidths[separator] = newCol1 * scaleFactor
161+
newWidths[separator + 1] = newCol2 * scaleFactor
162+
163+
return newWidths
164+
}
165+
166+
/*
100167
* ColumnResizer
101168
*
102169
* A draggable resize handle that will dispatch a new
@@ -108,14 +175,17 @@ interface ColumnResizerProps {
108175
readonly divider: ColumnDivider
109176
readonly setDragging: (dragging: boolean) => void
110177
readonly onDragEnd: (t: readonly [number, number]) => void
178+
readonly index: number
111179
}
112180

113181
const ColumnResizer: React.FunctionComponent<ColumnResizerProps> = ({
114182
divider,
115183
setDragging,
116184
onDragEnd,
185+
index,
117186
}) => {
118-
const { minColumnWidth } = useContext(TableContext)
187+
const { minColumnWidth, dispatchWidthsAction, columnWidths, tableRef } =
188+
useContext(TableContext)
119189

120190
const [[tx], onDragStart, dragging] = useDraggable(onDragEnd)
121191
const txClipped = clipTranslation(tx, divider, minColumnWidth)
@@ -130,8 +200,25 @@ const ColumnResizer: React.FunctionComponent<ColumnResizerProps> = ({
130200
}
131201
}, [dragging, setDragging])
132202

203+
const optimizeColWidths = useCallback(() => {
204+
if (tableRef === undefined) return
205+
206+
dispatchWidthsAction({
207+
type: WidthActionType.UPDATE_WIDTHS,
208+
widths: updateWidths({
209+
tableRef,
210+
separator: index,
211+
currentSizes: columnWidths,
212+
minColumnWidth,
213+
}),
214+
})
215+
}, [tableRef, minColumnWidth, index, columnWidths, dispatchWidthsAction])
216+
133217
return (
134-
<ResizeContainer left={divider.offset + txClipped}>
218+
<ResizeContainer
219+
onDoubleClick={optimizeColWidths}
220+
left={divider.offset + txClipped}
221+
>
135222
<ResizeHandle onPointerDown={onDragStart} />
136223
<ResizeMarker dragging={dragging} />
137224
</ResizeContainer>
@@ -215,6 +302,7 @@ export const ColumnResizerRow: React.FunctionComponent<ColumnResizerRowProps> =
215302
<ColumnResizer
216303
setDragging={setDragging}
217304
key={`${i}:${divider.offset}`}
305+
index={i}
218306
divider={divider}
219307
onDragEnd={dragEndHandlers[i]}
220308
/>

packages/core/src/Table/Table.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import React, {
88
useState,
99
} from 'react'
1010
import styled from 'styled-components'
11-
1211
import { spacing } from '../designparams'
1312

1413
import { ColumnResizerRow } from './ColumnResizerRow'
@@ -168,6 +167,7 @@ const reduceWidths = (state: WidthsState, action: WidthAction): WidthsState => {
168167
* Example:
169168
* [34, 78]
170169
*/
170+
171171
export const useGridTemplateColumns = () => {
172172
const { columnWidths, selectWidth, menuWidth } = useContext(TableContext)
173173

@@ -274,6 +274,8 @@ export interface TableProps extends Omit<BaseProps, 'onSelect'> {
274274
* Control if columns should be resizeable or not. If true, resize
275275
* handles will be available to change column width.
276276
*
277+
* For doubleclick functionality to work properly, when you have multiple elements in one cell, wrap them inside a <div>.
278+
*
277279
* @default false
278280
*/
279281
readonly resizableColumns?: boolean
@@ -409,6 +411,7 @@ export const Table: React.FunctionComponent<TableProps> = React.memo(
409411
onSelect,
410412
hasMenu,
411413
onWidthsChange,
414+
tableRef,
412415
}}
413416
>
414417
<TableHeaderContainer>{header}</TableHeaderContainer>

packages/core/src/Table/TableHeader.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,11 @@ export const TableHeader: React.FC<TableHeaderProps> = ({
9595
<OverlayContainer>{overlay}</OverlayContainer>
9696
) : (
9797
React.Children.map(children, (cell, i) => {
98-
return <TableHeaderCellContent key={i}>{cell}</TableHeaderCellContent>
98+
return (
99+
<TableHeaderCellContent data-col={i} key={i}>
100+
{cell}
101+
</TableHeaderCellContent>
102+
)
99103
})
100104
)}
101105
{overlay === undefined && hasMenu ? (

packages/core/src/Table/TableRow.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,11 @@ export const TableRow: React.FC<TableRowProps> = React.memo(
162162

163163
const tableCellContent = useMemo(() => {
164164
return React.Children.map(children, (cell, cellId) => {
165-
return <TableCellContent key={cellId}>{cell}</TableCellContent>
165+
return (
166+
<TableCellContent data-col={cellId} key={cellId}>
167+
{cell}
168+
</TableCellContent>
169+
)
166170
})
167171
}, [children])
168172

packages/core/src/Table/__snapshots__/index.test.tsx.snap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ exports[`Tables Table (minimal) 1`] = `
453453
>
454454
<div
455455
className="c5 c6 c7"
456+
data-col={0}
456457
>
457458
<p
458459
className="c8 c9"
@@ -462,6 +463,7 @@ exports[`Tables Table (minimal) 1`] = `
462463
</div>
463464
<div
464465
className="c5 c6 c7"
466+
data-col={1}
465467
>
466468
<p
467469
className="c8 c9"
@@ -471,6 +473,7 @@ exports[`Tables Table (minimal) 1`] = `
471473
</div>
472474
<div
473475
className="c5 c6 c7"
476+
data-col={2}
474477
>
475478
<p
476479
className="c8 c9"

packages/core/src/Table/context.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export const TableContext = createContext<{
5252
readonly onSelect?: (selected: boolean, id?: string) => void
5353
readonly hasMenu: boolean
5454
readonly onWidthsChange?: (widths: ReadonlyArray<number>) => void
55+
readonly tableRef?: React.RefObject<HTMLDivElement>
5556
}>({
5657
minColumnWidth: 0,
5758
columnWidths: [],

0 commit comments

Comments
 (0)