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

Commit c678dd9

Browse files
authored
Merge pull request #25 from ZeroarcSoftware/feature/candid-issue-784
Issue #784 - POC of double scrollbars to enhance UX (DRAFT)
2 parents 837a67e + b7882b7 commit c678dd9

2 files changed

Lines changed: 49 additions & 7 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tabletable",
3-
"version": "4.7.0",
3+
"version": "4.8.0",
44
"description": "A simple and extremely flexible table component written in React.",
55
"main": "dist/Container.js",
66
"types": "dist/Container.d.ts",

src/Container.tsx

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// Tabletable - Copyright 2020 Zeroarc Software, LLC
22
'use strict';
33

4-
import React, { useState, ReactElement, SyntheticEvent, FunctionComponent, useEffect } from 'react';
4+
import React, { useState, ReactElement, SyntheticEvent, FunctionComponent, useEffect, useRef, useCallback } from 'react';
55
import Immutable from 'immutable';
66
import ClassNames from 'classnames';
77
// Fonts
88
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
99
import { library } from '@fortawesome/fontawesome-svg-core';
10-
import { faSort} from '@fortawesome/free-solid-svg-icons/faSort';
10+
import { faSort } from '@fortawesome/free-solid-svg-icons/faSort';
1111
import { faTimes } from '@fortawesome/free-solid-svg-icons/faTimes';
1212
import { faSearch } from '@fortawesome/free-solid-svg-icons/faSearch';
1313
import { faSortDown } from '@fortawesome/free-solid-svg-icons/faSortDown';
@@ -87,9 +87,21 @@ const TabletableContainer: FunctionComponent<Props> = ({
8787
}) => {
8888

8989
const [formFilterValue, setFilterValue] = useState(filterValue);
90+
const [tableWidth, setTableWidth] = useState(0);
91+
92+
const responsiveTableRef = useRef<HTMLDivElement | null>(null);
93+
const scrollerRef = useRef<HTMLDivElement | null>(null);
94+
const scrollLock = useRef(false);
95+
96+
const callbackTableRef = useCallback(node => {
97+
if (node !== null) {
98+
responsiveTableRef.current = node;
99+
setTableWidth(node.scrollWidth + 5);
100+
}
101+
}, []);
90102

91103
// Track filterValue changes and reset the state to the passed in value
92-
// if it changes
104+
// if it changes.
93105
useEffect(() => {
94106
setFilterValue(filterValue);
95107
}, [filterValue]);
@@ -139,6 +151,28 @@ const TabletableContainer: FunctionComponent<Props> = ({
139151
}
140152
};
141153

154+
// Keep top scroll controller and master table scrollbar on bottom in sync.
155+
const handleScrollControlScroll = (e: React.UIEvent<HTMLElement>): void => {
156+
if (responsive && !scrollLock.current && responsiveTableRef?.current) {
157+
scrollLock.current = true;
158+
responsiveTableRef.current.scrollLeft = e.currentTarget.scrollLeft;
159+
160+
setTimeout(() => {
161+
scrollLock.current = false;
162+
}, 1);
163+
}
164+
}
165+
const handleTableScroll = (e: React.UIEvent<HTMLElement>): void => {
166+
if (responsive && !scrollLock.current && scrollerRef?.current) {
167+
scrollLock.current = true;
168+
scrollerRef.current.scrollLeft = e.currentTarget.scrollLeft;
169+
170+
setTimeout(() => {
171+
scrollLock.current = false;
172+
}, 10);
173+
}
174+
}
175+
142176
//#endregion
143177

144178
if (!Immutable.isImmutable(data)) {
@@ -260,7 +294,6 @@ const TabletableContainer: FunctionComponent<Props> = ({
260294
});
261295

262296
let createRow: JSX.Element | null = null;
263-
let createActionsRow: JSX.Element | null = null;
264297
let errorMsg: JSX.Element | null = null;
265298

266299
if (mode === 'create') {
@@ -411,6 +444,12 @@ const TabletableContainer: FunctionComponent<Props> = ({
411444
)
412445
: '';
413446

447+
const scrollControl = (
448+
<div className="scroll-control mb-3" onScroll={handleScrollControlScroll} ref={scrollerRef}>
449+
<div id="scroller" style={{ width: tableWidth }}></div>
450+
</div>
451+
);
452+
414453
return (
415454
<div className={containerCssClass}>
416455
<div className='row'>
@@ -423,7 +462,9 @@ const TabletableContainer: FunctionComponent<Props> = ({
423462
{showSpinner ? (
424463
spinner
425464
) : (
426-
<div className={responsive ? 'table-responsive' : ''}>
465+
<>
466+
{responsive ? scrollControl : null}
467+
<div className={responsive ? 'table-responsive' : ''} ref={callbackTableRef} onScroll={handleTableScroll}>
427468
<table className={tableCssClass}>
428469
<thead>
429470
<tr>
@@ -436,7 +477,8 @@ const TabletableContainer: FunctionComponent<Props> = ({
436477
</tbody>
437478
</table>
438479
</div>
439-
)
480+
</>
481+
)
440482
}
441483
{pager}
442484
</div>

0 commit comments

Comments
 (0)