Skip to content

Commit 365a6e5

Browse files
committed
feat: scroll to top on page switch
1 parent cadea7a commit 365a6e5

File tree

7 files changed

+104
-60
lines changed

7 files changed

+104
-60
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtron-labs/devtron-fe-common-lib",
3-
"version": "1.10.1",
3+
"version": "1.10.1-beta-1",
44
"description": "Supporting common component library",
55
"type": "module",
66
"main": "dist/index.js",

src/Shared/Components/Table/BulkSelectionActionWidget.tsx

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import { ReactComponent as ICClose } from '@Icons/ic-close.svg'
66
import { DraggableButton, DraggablePositionVariant, DraggableWrapper } from '@Common/DraggableWrapper'
77
import { ComponentSizeType } from '@Shared/constants'
8+
import { useRegisterShortcut } from '@Common/Hooks'
9+
import { useEffect } from 'react'
810
import { BulkSelectionActionWidgetProps } from './types'
911
import { Button, ButtonComponentType, ButtonStyleType, ButtonVariantType } from '../Button'
1012

@@ -13,38 +15,50 @@ const BulkSelectionActionWidget = ({
1315
handleClearBulkSelection,
1416
parentRef,
1517
BulkActionsComponent,
16-
}: BulkSelectionActionWidgetProps) => (
17-
<DraggableWrapper
18-
dragSelector=".drag-selector"
19-
positionVariant={DraggablePositionVariant.PARENT_BOTTOM_CENTER}
20-
zIndex="calc(var(--modal-index) - 1)"
21-
parentRef={parentRef}
22-
>
23-
<div className="dc__separated-flexbox dc__separated-flexbox--gap-8 pt-12 pb-12 pr-12 pl-12 bulk-selection-widget br-8">
24-
<div className="flexbox dc__gap-8">
25-
<DraggableButton dragClassName="drag-selector" />
26-
27-
<div className="fs-13 lh-20 fw-6 flex dc__gap-12">
28-
<span className="flex dc__gap-2 bcb-5 cn-0 br-4 pr-6 pl-6">{count}</span>
29-
<span className="cn-9">Selected</span>
18+
}: BulkSelectionActionWidgetProps) => {
19+
const { registerShortcut, unregisterShortcut } = useRegisterShortcut()
20+
21+
useEffect(() => {
22+
registerShortcut({ keys: ['Escape'], callback: handleClearBulkSelection })
23+
24+
return () => {
25+
unregisterShortcut(['Escape'])
26+
}
27+
}, [])
28+
29+
return (
30+
<DraggableWrapper
31+
dragSelector=".drag-selector"
32+
positionVariant={DraggablePositionVariant.PARENT_BOTTOM_CENTER}
33+
zIndex="calc(var(--modal-index) - 1)"
34+
parentRef={parentRef}
35+
>
36+
<div className="dc__separated-flexbox dc__separated-flexbox--gap-8 pt-12 pb-12 pr-12 pl-12 bulk-selection-widget br-8">
37+
<div className="flexbox dc__gap-8">
38+
<DraggableButton dragClassName="drag-selector" />
39+
40+
<div className="fs-13 lh-20 fw-6 flex dc__gap-12">
41+
<span className="flex dc__gap-2 bcb-5 cn-0 br-4 pr-6 pl-6">{count}</span>
42+
<span className="cn-9">Selected</span>
43+
</div>
3044
</div>
31-
</div>
3245

33-
<BulkActionsComponent />
34-
35-
<Button
36-
icon={<ICClose />}
37-
dataTestId="table__action-widget--close"
38-
component={ButtonComponentType.button}
39-
style={ButtonStyleType.negativeGrey}
40-
variant={ButtonVariantType.borderLess}
41-
ariaLabel="Clear selection(s)"
42-
size={ComponentSizeType.small}
43-
onClick={handleClearBulkSelection}
44-
showAriaLabelInTippy
45-
/>
46-
</div>
47-
</DraggableWrapper>
48-
)
46+
<BulkActionsComponent />
47+
48+
<Button
49+
icon={<ICClose />}
50+
dataTestId="table__action-widget--close"
51+
component={ButtonComponentType.button}
52+
style={ButtonStyleType.negativeGrey}
53+
variant={ButtonVariantType.borderLess}
54+
ariaLabel="Clear selection(s)"
55+
size={ComponentSizeType.small}
56+
onClick={handleClearBulkSelection}
57+
showAriaLabelInTippy
58+
/>
59+
</div>
60+
</DraggableWrapper>
61+
)
62+
}
4963

5064
export default BulkSelectionActionWidget

src/Shared/Components/Table/InternalTable.tsx

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1+
import { useRef, useEffect, useMemo, Fragment } from 'react'
12
import { Checkbox } from '@Common/Checkbox'
23
import { DEFAULT_BASE_PAGE_SIZE } from '@Common/Constants'
34
import ErrorScreenManager from '@Common/ErrorScreenManager'
4-
import { useAsync, showError, CHECKBOX_VALUE, GenericFilterEmptyState, GenericEmptyState } from '@Common/index'
5+
import {
6+
useAsync,
7+
showError,
8+
CHECKBOX_VALUE,
9+
GenericFilterEmptyState,
10+
GenericEmptyState,
11+
useEffectAfterMount,
12+
} from '@Common/index'
513
import { Pagination } from '@Common/Pagination'
614
import { SortableTableHeaderCell } from '@Common/SortableTableHeaderCell'
7-
import { useRef, useEffect, useMemo, Fragment } from 'react'
15+
816
import { BulkSelection } from '../BulkSelection'
917
import BulkSelectionActionWidget from './BulkSelectionActionWidget'
1018
import { SEARCH_SORT_CHANGE_DEBOUNCE_TIME, BULK_ACTION_GUTTER_LABEL, EVENT_TARGET } from './constants'
@@ -56,14 +64,6 @@ const InternalTable = ({
5664
isFilterApplied,
5765
} = filterData ?? {}
5866

59-
useEffect(() => {
60-
rowsContainerRef.current.scrollTo({
61-
top: 0,
62-
left: 0,
63-
behavior: 'smooth',
64-
})
65-
}, [offset])
66-
6767
const isBulkSelectionConfigured = !!bulkSelectionConfig
6868

6969
const {
@@ -161,11 +161,21 @@ const InternalTable = ({
161161
return paginatedRows
162162
}, [paginationVariant, offset, pageSize, filteredRows])
163163

164-
const { activeRowIndex } = useTableWithKeyboardShortcuts(
164+
const { activeRowIndex, setActiveRowIndex } = useTableWithKeyboardShortcuts(
165165
{ bulkSelectionConfig, bulkSelectionReturnValue, handleToggleBulkSelectionOnRow },
166166
visibleRows,
167167
)
168168

169+
useEffectAfterMount(() => {
170+
rowsContainerRef.current.scrollTo({
171+
top: 0,
172+
left: 0,
173+
behavior: 'smooth',
174+
})
175+
176+
setActiveRowIndex(0)
177+
}, [offset])
178+
169179
useEffect(() => {
170180
setIdentifiers?.(
171181
visibleRows.reduce((acc, row) => {
@@ -187,7 +197,7 @@ const InternalTable = ({
187197
return
188198
}
189199

190-
node.scrollIntoView({ behavior: 'instant', block: 'nearest' })
200+
node.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
191201
}
192202

193203
const showPagination =
@@ -238,15 +248,18 @@ const InternalTable = ({
238248
return visibleRows.map((row, visibleRowIndex) => {
239249
const rowIndex = rowToIndexMap?.get(row)
240250
const isRowActive = activeRowIndex === visibleRowIndex
251+
const isRowBulkSelected = !!bulkSelectionState[row.id] || isBulkSelectionApplied
241252

242253
return (
243254
<div
244255
ref={scrollIntoViewActiveRowRefCallback}
245-
className={`dc__grid px-20 ${
256+
className={`dc__grid px-20 form__checkbox-parent ${
246257
showSeparatorBetweenRows ? 'dc__border-bottom-n1' : ''
247258
} fs-13 fw-4 lh-20 cn-9 generic-table__row dc__gap-16 ${
248-
isRowActive ? 'generic-table__row--active' : ''
249-
} ${RowActionsOnHoverComponent ? 'dc__position-rel dc__opacity-hover dc__opacity-hover--parent' : ''}`}
259+
isRowActive ? 'generic-table__row--active form__checkbox-parent--active' : ''
260+
} ${RowActionsOnHoverComponent ? 'dc__position-rel dc__opacity-hover dc__opacity-hover--parent' : ''} ${
261+
isRowBulkSelected ? 'generic-table__row--bulk-selected' : ''
262+
}`}
250263
style={{
251264
gridTemplateColumns,
252265
}}
@@ -257,7 +270,7 @@ const InternalTable = ({
257270
if (field === BULK_ACTION_GUTTER_LABEL) {
258271
return (
259272
<Checkbox
260-
isChecked={!!bulkSelectionState[row.id] || isBulkSelectionApplied}
273+
isChecked={isRowBulkSelected}
261274
onChange={() => handleToggleBulkSelectionOnRow(row)}
262275
rootClassName="mb-0"
263276
value={CHECKBOX_VALUE.CHECKED}
@@ -271,8 +284,9 @@ const InternalTable = ({
271284
field={field}
272285
value={row.data[field]}
273286
signals={EVENT_TARGET as SignalsType}
274-
data={row.data}
287+
row={row}
275288
filterData={filterData}
289+
isRowActive={isRowActive}
276290
{...additionalProps}
277291
/>
278292
)
@@ -306,8 +320,8 @@ const InternalTable = ({
306320

307321
return (
308322
<div className="generic-table flexbox-col dc__overflow-hidden flex-grow-1">
309-
<div className="flexbox-col flex-grow-1 w-100 dc__overflow-auto">
310-
<div className="bg__primary dc__min-width-fit-content px-20 dc__border-bottom-n1" ref={parentRef}>
323+
<div className="flexbox-col flex-grow-1 w-100 dc__overflow-auto" ref={parentRef}>
324+
<div className="bg__primary dc__min-width-fit-content px-20 dc__border-bottom-n1">
311325
{loading && !visibleColumns.length ? (
312326
<div className="flexbox py-12 dc__gap-16">
313327
{Array(3)
@@ -334,10 +348,10 @@ const InternalTable = ({
334348
<SortableTableHeaderCell
335349
key={label}
336350
title={label}
337-
isSortable={isSortable}
351+
isSortable={!!isSortable}
338352
sortOrder={sortOrder}
339-
isSorted={sortBy === label}
340-
triggerSorting={getTriggerSortingHandler(label)}
353+
isSorted={sortBy === field}
354+
triggerSorting={getTriggerSortingHandler(field)}
341355
showTippyOnTruncate={showTippyOnTruncate}
342356
disabled={areFilteredRowsLoading}
343357
{...(isResizable

src/Shared/Components/Table/styles.scss

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,16 @@
55
&__row--active > * {
66
background-color: var(--bg-hover-opaque);
77
}
8+
9+
&__row--bulk-selected,
10+
&__row--bulk-selected > * {
11+
background-color: var(--B50);
12+
}
13+
14+
&__row--bulk-selected:hover,
15+
&__row--bulk-selected:hover > *,
16+
&__row--bulk-selected.generic-table__row--active,
17+
&__row--bulk-selected.generic-table__row--active > * {
18+
background-color: var(--B100);
19+
}
820
}

src/Shared/Components/Table/types.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,19 @@ interface AdditionalProps {
7474
[key: string]: unknown
7575
}
7676

77-
export type RowsType = {
77+
type RowType = {
7878
id: string
7979
data: Record<string, unknown>
80-
}[]
80+
}
81+
82+
export type RowsType = RowType[]
8183

8284
export interface CellComponentProps extends Pick<BaseColumnType, 'field'>, AdditionalProps {
8385
signals: SignalsType
8486
value: unknown
85-
data: RowsType[number]['data']
87+
row: RowType
8688
filterData: UseFiltersReturnType
89+
isRowActive: boolean
8790
}
8891

8992
export type Column = Pick<SortableTableHeaderCellProps, 'showTippyOnTruncate'> &

src/Shared/Components/Table/useTableWithKeyboardShortcuts.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useRegisterShortcut } from '@Common/Hooks'
22
import { useState, useRef, useCallback, useEffect } from 'react'
3-
import { noop } from 'rxjs'
3+
import { noop } from '@Common/Helper'
44
import { BulkSelectionEvents } from '../BulkSelection'
55
import { InternalTablePropsWithWrappers, RowsType, SignalEnum } from './types'
66
import { EVENT_TARGET } from './constants'
@@ -202,6 +202,7 @@ const useTableWithKeyboardShortcuts = (
202202

203203
return {
204204
activeRowIndex,
205+
setActiveRowIndex,
205206
}
206207
}
207208

0 commit comments

Comments
 (0)