Skip to content

Commit 43aefc8

Browse files
committed
readOnly support in tables #1115
1 parent 397c5e6 commit 43aefc8

File tree

12 files changed

+123
-40
lines changed

12 files changed

+123
-40
lines changed

browser/data-browser/src/components/Dialog/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useHotkeys } from 'react-hotkeys-hook';
44
import { FaTimes } from 'react-icons/fa';
55
import { styled, keyframes } from 'styled-components';
66
import * as CSS from 'csstype';
7-
import { effectTimeout } from '../../helpers/effectTimeout';
87
import { Button } from '../Button';
98
import { DropdownContainer } from '../Dropdown/DropdownContainer';
109
import { PopoverContainer } from '../Popover';
@@ -18,6 +17,7 @@ import { useControlLock } from '../../hooks/useControlLock';
1817
import { useDialogGlobalContext } from './DialogGlobalContextProvider';
1918
import { DIALOG_CONTENT_CONTAINER } from '../../helpers/containers';
2019
import { CurrentBackgroundColor } from '../../globalCssVars';
20+
import { timeoutEffect } from '@helpers/timeoutEffect';
2121

2222
export interface InternalDialogProps {
2323
show: boolean;
@@ -145,7 +145,7 @@ const InnerDialog: React.FC<React.PropsWithChildren<InternalDialogProps>> = ({
145145

146146
if (dialogRef.current.hasAttribute('data-closing')) {
147147
// TODO: Use getAnimations() api to wait for the animations to complete instead of a timeout.
148-
return effectTimeout(() => {
148+
return timeoutEffect(() => {
149149
// @ts-ignore
150150
dialogRef.current.close();
151151
dialogRef.current?.removeAttribute('data-closing');

browser/data-browser/src/components/TableEditor/Cell.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export function Cell({
5454
const [markEnterEditMode, setMarkEnterEditMode] = useState(false);
5555

5656
const {
57+
readOnly,
5758
mouseDown,
5859
selectedRow,
5960
selectedColumn,
@@ -77,14 +78,14 @@ export function Cell({
7778

7879
const handleMouseUp = useCallback(() => {
7980
setMouseDown(false);
80-
}, []);
81+
}, [setMouseDown]);
8182

8283
const handleMouseEnter = useCallback(() => {
8384
if (mouseDown) {
8485
setMultiSelectCorner(rowIndex, columnIndex);
8586
setCursorMode(CursorMode.MultiSelect);
8687
}
87-
}, [mouseDown, rowIndex, columnIndex]);
88+
}, [mouseDown, rowIndex, columnIndex, setMultiSelectCorner, setCursorMode]);
8889

8990
const shouldEnterEditMode = useCallback(
9091
(e: React.MouseEvent<HTMLDivElement>) => {
@@ -124,7 +125,7 @@ export function Cell({
124125
return;
125126
}
126127

127-
if (shouldEnterEditMode(e)) {
128+
if (!readOnly && shouldEnterEditMode(e)) {
128129
setMarkEnterEditMode(true);
129130

130131
return;
@@ -138,12 +139,17 @@ export function Cell({
138139
setActiveCell(rowIndex, columnIndex);
139140
},
140141
[
142+
readOnly,
141143
setActiveCell,
142144
columnIndex,
143145
shouldEnterEditMode,
144146
cursorMode,
145147
isActive,
146148
disabledKeyboardInteractions,
149+
setCursorMode,
150+
setMouseDown,
151+
setMultiSelectCorner,
152+
rowIndex,
147153
],
148154
);
149155

@@ -159,7 +165,13 @@ export function Cell({
159165
setCursorMode(CursorMode.Edit);
160166
setMarkEnterEditMode(false);
161167
}
162-
}, [markEnterEditMode, disabledKeyboardInteractions]);
168+
}, [
169+
markEnterEditMode,
170+
disabledKeyboardInteractions,
171+
setMultiSelectCorner,
172+
setMouseDown,
173+
setCursorMode,
174+
]);
163175

164176
useLayoutEffect(() => {
165177
if (!ref.current) {
@@ -169,7 +181,7 @@ export function Cell({
169181
if (isActiveCorner) {
170182
updateMultiSelectCornerCellRef(ref.current);
171183
}
172-
}, [isActiveCorner]);
184+
}, [isActiveCorner, updateMultiSelectCornerCellRef]);
173185

174186
useEffect(() => {
175187
if (!ref.current) {
@@ -209,6 +221,7 @@ export function Cell({
209221
onEnterEditModeWithCharacter,
210222
onEditNextRow,
211223
updateActiveCellRef,
224+
registerEventListener,
212225
]);
213226

214227
return (

browser/data-browser/src/components/TableEditor/TableEditor.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const ARIA_TABLE_USAGE =
4040
'Use the arrow keys to navigate the table. Press enter to edit a cell. Press escape to exit edit mode.';
4141

4242
interface FancyTableProps<T> {
43+
readOnly?: boolean;
4344
columns: T[];
4445
itemCount: number;
4546
columnSizes?: number[];
@@ -68,10 +69,11 @@ type OnScroll = (props: ListOnScrollProps) => unknown;
6869

6970
export function FancyTable<T>({
7071
rowHeight = 40,
72+
readOnly = false,
7173
...props
7274
}: FancyTableProps<T>): JSX.Element {
7375
return (
74-
<TableEditorContextProvider>
76+
<TableEditorContextProvider readOnly={readOnly}>
7577
<FancyTableInner rowHeight={rowHeight} {...props} />
7678
</TableEditorContextProvider>
7779
);
@@ -100,8 +102,13 @@ function FancyTableInner<T>({
100102
const scrollerRef = useRef<HTMLDivElement>(null);
101103
const headerRef = useRef<HTMLDivElement>(null);
102104

103-
const { listRef, tableRef, setCursorMode, disabledKeyboardInteractions } =
104-
useTableEditorContext();
105+
const {
106+
listRef,
107+
tableRef,
108+
setCursorMode,
109+
disabledKeyboardInteractions,
110+
readOnly,
111+
} = useTableEditorContext();
105112
const [onScroll, setOnScroll] = useState<OnScroll>(() => undefined);
106113

107114
const { templateColumns, contentRowWidth, resizeCell } = useCellSizes(
@@ -116,7 +123,7 @@ function FancyTableInner<T>({
116123
}
117124

118125
setCursorMode(CursorMode.Visual);
119-
}, [disabledKeyboardInteractions]);
126+
}, [disabledKeyboardInteractions, setCursorMode]);
120127

121128
useClickAwayListener([tableRef], handleClickOutside, true);
122129

@@ -154,7 +161,7 @@ function FancyTableInner<T>({
154161
</TableRow>
155162
);
156163
},
157-
[itemCount, children],
164+
[children, onRowExpand],
158165
);
159166

160167
const List = useCallback(
@@ -175,12 +182,16 @@ function FancyTableInner<T>({
175182
);
176183

177184
useEffect(() => {
185+
if (readOnly) {
186+
return;
187+
}
188+
178189
document.addEventListener('paste', triggerPasteCommand);
179190

180191
return () => {
181192
document.removeEventListener('paste', triggerPasteCommand);
182193
};
183-
}, [triggerPasteCommand]);
194+
}, [triggerPasteCommand, readOnly]);
184195

185196
return (
186197
<DndWrapper>

browser/data-browser/src/components/TableEditor/TableEditorContext.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ function emptySetState<T>(_: T | ((__: T) => T)): undefined {
3737
}
3838

3939
export interface TableEditorContext {
40+
readOnly: boolean;
4041
mouseDown: boolean;
4142
setMouseDown: React.Dispatch<React.SetStateAction<boolean>>;
4243
tableRef: React.RefObject<HTMLDivElement | null>;
@@ -77,6 +78,7 @@ export interface TableEditorContext {
7778
}
7879

7980
const initial: TableEditorContext = {
81+
readOnly: false,
8082
mouseDown: false,
8183
setMouseDown: emptySetState,
8284
tableRef: { current: null },
@@ -110,9 +112,14 @@ const initial: TableEditorContext = {
110112

111113
const TableEditorContext = createContext<TableEditorContext>(initial);
112114

115+
interface TableEditorContextProviderProps {
116+
readOnly: boolean;
117+
}
118+
113119
export function TableEditorContextProvider({
114120
children,
115-
}: React.PropsWithChildren<unknown>): JSX.Element {
121+
readOnly,
122+
}: React.PropsWithChildren<TableEditorContextProviderProps>): JSX.Element {
116123
const [mouseDown, setMouseDown] = useState(false);
117124
const tableRef = useRef<HTMLDivElement | null>(null);
118125
const listRef = useRef<FixedSizeList>(null);
@@ -197,6 +204,7 @@ export function TableEditorContextProvider({
197204

198205
const context = useMemo(
199206
() => ({
207+
readOnly,
200208
mouseDown,
201209
setMouseDown,
202210
tableRef,
@@ -228,6 +236,10 @@ export function TableEditorContextProvider({
228236
setMarkings,
229237
}),
230238
[
239+
clearCell,
240+
clearRow,
241+
enterEditModeWithCharacter,
242+
eventManager,
231243
disabledKeyboardInteractions,
232244
selectedRow,
233245
selectedColumn,
@@ -241,6 +253,7 @@ export function TableEditorContextProvider({
241253
isDragging,
242254
cursorMode,
243255
emitInteractionsFired,
256+
readOnly,
244257
mouseDown,
245258
markings,
246259
],

browser/data-browser/src/components/TableEditor/helpers/keyboardHandlers.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export interface KeyboardHandler {
4444
keys: Set<string>;
4545
cursorMode: Set<CursorMode>;
4646
preventDefault?: boolean;
47+
disabledInReadOnly?: boolean;
4748
shift?: boolean;
4849
mod?: boolean;
4950
condition?: (context: HandlerContext) => boolean;
@@ -119,6 +120,7 @@ const editNextRow: KeyboardHandler = {
119120
keys: new Set(['Enter']),
120121
shift: false,
121122
cursorMode: new Set([CursorMode.Edit]),
123+
disabledInReadOnly: true,
122124
preventDefault: true,
123125
handler: ({ translateCursor }) => {
124126
translateCursor(1, 0);
@@ -130,6 +132,7 @@ const editNextCell: KeyboardHandler = {
130132
keys: new Set(['Tab']),
131133
shift: false,
132134
cursorMode: new Set([CursorMode.Edit]),
135+
disabledInReadOnly: true,
133136
preventDefault: true,
134137
handler: ({ translateCursor }) => {
135138
translateCursor(0, 1);
@@ -141,6 +144,7 @@ const editPreviousCell: KeyboardHandler = {
141144
keys: new Set(['Tab']),
142145
shift: true,
143146
cursorMode: new Set([CursorMode.Edit]),
147+
disabledInReadOnly: true,
144148
preventDefault: true,
145149
handler: ({ translateCursor }) => {
146150
translateCursor(0, -1);
@@ -167,6 +171,7 @@ const undoCommand: KeyboardHandler = {
167171
keys: new Set(['z']),
168172
mod: true,
169173
cursorMode: new Set([CursorMode.Visual, CursorMode.MultiSelect]),
174+
disabledInReadOnly: true,
170175
condition: () => document.activeElement?.tagName !== 'INPUT',
171176
handler: ({ undo }) => {
172177
undo?.();
@@ -177,6 +182,7 @@ const deleteCell: KeyboardHandler = {
177182
id: KeyboardInteraction.DeleteCell,
178183
keys: new Set(['Delete', 'Backspace']),
179184
cursorMode: new Set([CursorMode.Visual, CursorMode.MultiSelect]),
185+
disabledInReadOnly: true,
180186
condition: ({ tableContext }) =>
181187
tableContext.selectedColumn !== 0 &&
182188
tableContext.selectedColumn !== undefined &&
@@ -191,6 +197,7 @@ const deleteRow: KeyboardHandler = {
191197
id: KeyboardInteraction.DeleteRow,
192198
keys: new Set(['Delete', 'Backspace']),
193199
cursorMode: new Set([CursorMode.Visual]),
200+
disabledInReadOnly: true,
194201
condition: ({ tableContext }) =>
195202
tableContext.selectedColumn === 0 &&
196203
tableContext.selectedColumn !== undefined &&
@@ -245,6 +252,7 @@ const enterEditModeWithEnter: KeyboardHandler = {
245252
id: KeyboardInteraction.EnterEditModeWithEnter,
246253
keys: new Set(['Enter']),
247254
cursorMode: new Set([CursorMode.Visual]),
255+
disabledInReadOnly: true,
248256
condition: ({ tableContext }) =>
249257
tableContext.selectedColumn !== undefined &&
250258
tableContext.selectedColumn !== 0 &&
@@ -269,6 +277,7 @@ const enterEditModeByTyping: KeyboardHandler = {
269277
id: KeyboardInteraction.EnterEditModeByTyping,
270278
keys: new Set(triggerCharacters.split('')),
271279
cursorMode: new Set([CursorMode.Visual]),
280+
disabledInReadOnly: true,
272281
mod: false,
273282
condition: ({ tableContext }) =>
274283
tableContext.selectedColumn !== undefined &&

browser/data-browser/src/components/TableEditor/hooks/useTableEditorKeyboardNavigation.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,10 @@ export function useTableEditorKeyboardNavigation(
3737
) {
3838
const tableContext = useTableEditorContext();
3939
const {
40+
readOnly,
4041
disabledKeyboardInteractions,
4142
selectedRow,
4243
selectedColumn,
43-
multiSelectCornerRow,
44-
multiSelectCornerColumn,
4544
setActiveCell,
4645
listRef,
4746
emitInteractionsFired,
@@ -90,6 +89,7 @@ export function useTableEditorKeyboardNavigation(
9089
!disabledKeyboardInteractions.has(h.id) &&
9190
h.keys.has(e.key) &&
9291
h.cursorMode.has(tableContext.cursorMode) &&
92+
(readOnly ? !h.disabledInReadOnly : true) &&
9393
matchShift(h, e) &&
9494
matchModifier(h, e) &&
9595
matchCondition(h, context),
@@ -106,15 +106,18 @@ export function useTableEditorKeyboardNavigation(
106106
emitInteractionsFired(handlers.map(h => h.id));
107107
},
108108
[
109+
commands,
110+
listRef,
111+
setActiveCell,
112+
columnCount,
113+
rowCount,
114+
tableRef,
115+
headerRef,
116+
readOnly,
109117
disabledKeyboardInteractions,
110118
selectedRow,
111119
selectedColumn,
112-
multiSelectCornerRow,
113-
multiSelectCornerColumn,
114120
tableContext,
115-
commands.copy,
116-
commands.undo,
117-
commands.expand,
118121
hasControlLock,
119122
emitInteractionsFired,
120123
],

browser/data-browser/src/components/forms/RangeInput.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,15 @@ export function RangeInput({
6060
const num = toOptionalNum(e.target.value, round);
6161
onChange(num, maxValue);
6262
},
63-
[onChange, maxValue],
63+
[onChange, maxValue, round],
6464
);
6565

6666
const handleMaxChange = useCallback(
6767
(e: React.ChangeEvent<HTMLInputElement>) => {
6868
const num = toOptionalNum(e.target.value, round);
6969
onChange(minValue, num);
7070
},
71-
[onChange, minValue],
71+
[onChange, minValue, round],
7272
);
7373

7474
return (

browser/data-browser/src/helpers/effectTimeout.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

0 commit comments

Comments
 (0)