Skip to content

Commit b402e9a

Browse files
committed
Add stickyFirstColumn prop
1 parent a205c5d commit b402e9a

6 files changed

Lines changed: 85 additions & 8 deletions

File tree

src/components/Cell.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import cx from 'classnames'
44
export const Cell: FC<{
55
gutter: boolean
66
stickyRight: boolean
7+
stickyFirstColumn?: boolean
78
disabled?: boolean
89
className?: string
910
active?: boolean
@@ -14,6 +15,7 @@ export const Cell: FC<{
1415
children,
1516
gutter,
1617
stickyRight,
18+
stickyFirstColumn,
1719
active,
1820
disabled,
1921
className,
@@ -28,6 +30,7 @@ export const Cell: FC<{
2830
disabled && 'dsg-cell-disabled',
2931
gutter && active && 'dsg-cell-gutter-active',
3032
stickyRight && 'dsg-cell-sticky-right',
33+
stickyFirstColumn && 'dsg-cell-sticky-first',
3134
className
3235
)}
3336
style={{

src/components/DataSheetGrid.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export const DataSheetGrid = React.memo(
7070
headerRowHeight = typeof rowHeight === 'number' ? rowHeight : 40,
7171
gutterColumn,
7272
stickyRightColumn,
73+
stickyFirstColumn,
7374
rowKey,
7475
addRowsComponent: AddRowsComponent = AddRows,
7576
createRow = DEFAULT_CREATE_ROW as () => T,
@@ -251,6 +252,13 @@ export const DataSheetGrid = React.memo(
251252
x = 0
252253
}
253254

255+
if (
256+
stickyFirstColumn &&
257+
event.clientX - outerBoundingClientRect.left <= columnRights[1]
258+
) {
259+
x = event.clientX - outerBoundingClientRect.left
260+
}
261+
254262
if (
255263
hasStickyRightColumn &&
256264
outerBoundingClientRect.right - event.clientX <=
@@ -276,6 +284,7 @@ export const DataSheetGrid = React.memo(
276284
getOuterBoundingClientRect,
277285
headerRowHeight,
278286
hasStickyRightColumn,
287+
stickyFirstColumn,
279288
getRowIndex,
280289
]
281290
)
@@ -1779,6 +1788,7 @@ export const DataSheetGrid = React.memo(
17791788
outerRef={outerRef}
17801789
columnWidths={columnWidths}
17811790
hasStickyRightColumn={hasStickyRightColumn}
1791+
stickyFirstColumn={stickyFirstColumn}
17821792
displayHeight={displayHeight}
17831793
data={data}
17841794
fullWidth={fullWidth}
@@ -1807,6 +1817,7 @@ export const DataSheetGrid = React.memo(
18071817
headerRowHeight={headerRowHeight}
18081818
rowHeight={getRowSize}
18091819
hasStickyRightColumn={hasStickyRightColumn}
1820+
stickyFirstColumn={stickyFirstColumn}
18101821
dataLength={data.length}
18111822
viewHeight={height}
18121823
viewWidth={width}

src/components/Grid.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const Grid = <T extends any>({
1818
innerRef,
1919
columnWidths,
2020
hasStickyRightColumn,
21+
stickyFirstColumn,
2122
displayHeight,
2223
headerRowHeight,
2324
rowHeight,
@@ -43,6 +44,7 @@ export const Grid = <T extends any>({
4344
innerRef: RefObject<HTMLDivElement>
4445
columnWidths?: number[]
4546
hasStickyRightColumn: boolean
47+
stickyFirstColumn?: boolean
4648
displayHeight: number
4749
headerRowHeight: number
4850
rowHeight: (index: number) => { height: number }
@@ -97,9 +99,15 @@ export const Grid = <T extends any>({
9799
overscan: 1,
98100
rangeExtractor: (range) => {
99101
const result = defaultRangeExtractor(range)
102+
100103
if (result[0] !== 0) {
101104
result.unshift(0)
102105
}
106+
107+
if (stickyFirstColumn && result[1] !== 1) {
108+
result.splice(1, 0, 1)
109+
}
110+
103111
if (
104112
hasStickyRightColumn &&
105113
result[result.length - 1] !== columns.length - 1
@@ -150,6 +158,7 @@ export const Grid = <T extends any>({
150158
<CellComponent
151159
key={col.key}
152160
gutter={col.index === 0}
161+
stickyFirstColumn={stickyFirstColumn && col.index === 1}
153162
stickyRight={
154163
hasStickyRightColumn && col.index === columns.length - 1
155164
}
@@ -215,6 +224,7 @@ export const Grid = <T extends any>({
215224
<CellComponent
216225
key={col.key}
217226
gutter={col.index === 0}
227+
stickyFirstColumn={stickyFirstColumn && col.index === 1}
218228
stickyRight={
219229
hasStickyRightColumn && col.index === columns.length - 1
220230
}

src/components/SelectionRect.tsx

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export const SelectionRect = React.memo<SelectionContextType>(
4848
rowHeight,
4949
activeCell,
5050
hasStickyRightColumn,
51+
stickyFirstColumn,
5152
dataLength,
5253
viewWidth,
5354
viewHeight,
@@ -170,20 +171,22 @@ export const SelectionRect = React.memo<SelectionContextType>(
170171
})}
171172
style={{
172173
top: headerRowHeight,
173-
left: columnWidths[0],
174+
left: columnWidths[0] + (stickyFirstColumn ? columnWidths[1] : 0),
174175
height: viewHeight ? viewHeight - headerRowHeight : 0,
175176
width:
176177
contentWidth && viewWidth
177178
? viewWidth -
178179
columnWidths[0] -
179180
(hasStickyRightColumn
180181
? columnWidths[columnWidths.length - 1]
181-
: 0)
182+
: 0) -
183+
(stickyFirstColumn ? columnWidths[1] : 0)
182184
: `calc(100% - ${
183185
columnWidths[0] +
184186
(hasStickyRightColumn
185187
? columnWidths[columnWidths.length - 1]
186-
: 0)
188+
: 0) +
189+
(stickyFirstColumn ? columnWidths[1] : 0)
187190
}px)`,
188191
}}
189192
/>
@@ -232,6 +235,8 @@ export const SelectionRect = React.memo<SelectionContextType>(
232235
className={cx('dsg-active-cell', {
233236
'dsg-active-cell-focus': editing,
234237
'dsg-active-cell-disabled': activeCellIsDisabled,
238+
'dsg-active-cell-sticky-first':
239+
stickyFirstColumn && activeCell.col === 0,
235240
})}
236241
style={activeCellRect}
237242
/>
@@ -253,18 +258,30 @@ export const SelectionRect = React.memo<SelectionContextType>(
253258
}}
254259
/>
255260
)}
256-
{expandRowsRect && (
257-
<div className={cx('dsg-expand-rows-rect')} style={expandRowsRect} />
258-
)}
259261
{expandRowsIndicator && (
260262
<div
261263
className={cx(
262264
'dsg-expand-rows-indicator',
263-
selectionIsDisabled && 'dsg-expand-rows-indicator-disabled'
265+
selectionIsDisabled && 'dsg-expand-rows-indicator-disabled',
266+
stickyFirstColumn &&
267+
((!selection && activeCell?.col === 0) ||
268+
selection?.max.col === 0) &&
269+
'dsg-expand-rows-indicator-sticky-first'
264270
)}
265271
style={expandRowsIndicator}
266272
/>
267273
)}
274+
{expandRowsRect && (
275+
<div
276+
className={cx(
277+
'dsg-expand-rows-rect',
278+
stickyFirstColumn &&
279+
activeCell?.col === 0 &&
280+
'dsg-expand-rows-rect-sticky-first'
281+
)}
282+
style={expandRowsRect}
283+
/>
284+
)}
268285
</>
269286
)
270287
}

src/style.css

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@
8181
transform: translateY(-100%);
8282
}
8383

84+
.dsg-cell-sticky-first {
85+
position: sticky;
86+
top: 0;
87+
z-index: 20;
88+
margin-right: auto;
89+
transform: translateY(-100%);
90+
}
91+
8492
.dsg-cell-disabled {
8593
background: var(--dsg-cell-disabled-background-color);
8694
}
@@ -101,6 +109,10 @@
101109
box-shadow: 1px 0 var(--dsg-border-color), 0 1px var(--dsg-border-color);
102110
}
103111

112+
.dsg-cell-header.dsg-cell-sticky-first {
113+
box-shadow: 1px 0 var(--dsg-border-color), 0 1px var(--dsg-border-color);
114+
}
115+
104116
.dsg-cell-header.dsg-cell-sticky-right {
105117
box-shadow: 0 1px var(--dsg-border-color);
106118
}
@@ -140,6 +152,11 @@
140152
border-color: var(--dsg-selection-disabled-border-color);
141153
}
142154

155+
.dsg-active-cell-sticky-first {
156+
position: sticky;
157+
z-index: 40;
158+
}
159+
143160
.dsg-selection-rect {
144161
background: var(--dsg-selection-background-color);
145162
}
@@ -405,6 +422,7 @@
405422
.dsg-selection-col-marker-container {
406423
position: absolute;
407424
top: 0;
425+
z-index: 20;
408426
}
409427

410428
.dsg-selection-col-marker {
@@ -570,10 +588,20 @@
570588
border: solid 1px var(--dsg-selection-disabled-border-color);
571589
}
572590

591+
.dsg-expand-rows-indicator-sticky-first {
592+
position: sticky;
593+
z-index: 40;
594+
}
595+
573596
.dsg-expand-rows-rect {
574597
position: absolute;
575598
box-sizing: border-box;
576599
transition: all var(--dsg-transition-duration);
577600
pointer-events: none;
578601
background: rgba(0, 0, 0, 0.03);
579602
}
603+
604+
.dsg-expand-rows-rect-sticky-first{
605+
position: sticky;
606+
z-index: 40;
607+
}

src/types.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export type SelectionContextType = {
6262
selection: Selection | null
6363
dataLength: number
6464
rowHeight: (index: number) => { height: number; top: number }
65+
stickyFirstColumn?: boolean
6566
hasStickyRightColumn: boolean
6667
editing: boolean
6768
isCellDisabled: (cell: Cell) => boolean
@@ -93,7 +94,13 @@ export type AddRowsComponentProps = {
9394

9495
export type ContextMenuItem =
9596
| {
96-
type: 'INSERT_ROW_BELLOW' | 'DELETE_ROW' | 'DUPLICATE_ROW' | 'COPY' | 'CUT' | 'PASTE'
97+
type:
98+
| 'INSERT_ROW_BELLOW'
99+
| 'DELETE_ROW'
100+
| 'DUPLICATE_ROW'
101+
| 'COPY'
102+
| 'CUT'
103+
| 'PASTE'
97104
action: () => void
98105
}
99106
| {
@@ -135,6 +142,7 @@ export type DataSheetGridProps<T> = {
135142
columns?: Partial<Column<T, any, any>>[]
136143
gutterColumn?: SimpleColumn<T, any> | false
137144
stickyRightColumn?: SimpleColumn<T, any>
145+
stickyFirstColumn?: boolean
138146
rowKey?: string | ((opts: { rowData: T; rowIndex: number }) => string)
139147
height?: number
140148
rowHeight?: number | ((opt: { rowData: T; rowIndex: number }) => number)

0 commit comments

Comments
 (0)