Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#638 Table Fixes and features #690

Merged
merged 5 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion browser/data-browser/src/components/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface PopoverProps {
onOpenChange: (open: boolean) => void;
className?: string;
noArrow?: boolean;
noLock?: boolean;
}

export function Popover({
Expand All @@ -20,6 +21,7 @@ export function Popover({
open,
defaultOpen,
noArrow,
noLock,
onOpenChange,
Trigger,
}: React.PropsWithChildren<PopoverProps>): JSX.Element {
Expand All @@ -28,7 +30,7 @@ export function Popover({

const container = containerRef.current ?? undefined;

useControlLock(!!open);
useControlLock(!noLock && !!open);

const handleOpenChange = useCallback(
(changedToOpen: boolean) => {
Expand Down
57 changes: 48 additions & 9 deletions browser/data-browser/src/components/TableEditor/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from './TableEditorContext';
import { FaExpandAlt } from 'react-icons/fa';
import { IconButton } from '../IconButton/IconButton';
import { KeyboardInteraction } from './helpers/keyboardHandlers';

export enum CellAlign {
Start = 'flex-start',
Expand All @@ -23,6 +24,7 @@ export interface CellProps {
role?: string;
onClearCell?: () => void;
onEnterEditModeWithCharacter?: (key: string) => void;
onEditNextRow?: () => void;
}

interface IndexCellProps extends CellProps {
Expand All @@ -38,10 +40,12 @@ export function Cell({
align,
role,
onEnterEditModeWithCharacter = () => undefined,
onEditNextRow,
}: React.PropsWithChildren<CellProps>): JSX.Element {
const ref = useRef<HTMLDivElement>(null);

const {
mouseDown,
selectedRow,
selectedColumn,
multiSelectCornerRow,
Expand All @@ -53,15 +57,30 @@ export function Cell({
multiSelectCornerCellRef,
setCursorMode,
registerEventListener,
disabledKeyboardInteractions,
setMouseDown,
} = useTableEditorContext();

const isActive = rowIndex === selectedRow && columnIndex === selectedColumn;
const isActiveCorner =
rowIndex === multiSelectCornerRow &&
columnIndex === multiSelectCornerColumn;

const handleClick = useCallback(
const handleMouseUp = useCallback(() => {
setMouseDown(false);
}, []);

const handleMouseEnter = useCallback(() => {
if (mouseDown) {
setMultiSelectCorner(rowIndex, columnIndex);
setCursorMode(CursorMode.MultiSelect);
}
}, [mouseDown, rowIndex, columnIndex]);

const handleMouseDown = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
setMouseDown(true);

// When Shift is pressed, enter multi-select mode
if (e.shiftKey) {
e.stopPropagation();
Expand All @@ -86,13 +105,19 @@ export function Cell({

if (isActive && columnIndex !== 0) {
// Enter edit mode when clicking on a higlighted cell, except when it's the index column.
setMultiSelectCorner(undefined, undefined);

return setCursorMode(CursorMode.Edit);
}

if (disabledKeyboardInteractions.has(KeyboardInteraction.ExitEditMode)) {
return;
}

setCursorMode(CursorMode.Visual);
setActiveCell(rowIndex, columnIndex);
},
[setActiveCell, isActive, columnIndex],
[setActiveCell, isActive, columnIndex, disabledKeyboardInteractions],
);

useLayoutEffect(() => {
Expand All @@ -117,16 +142,28 @@ export function Cell({

activeCellRef.current = ref.current;

const unregister = registerEventListener(
TableEvent.EnterEditModeWithCharacter,
onEnterEditModeWithCharacter,
);
const unregisters = [
registerEventListener(
TableEvent.EnterEditModeWithCharacter,
onEnterEditModeWithCharacter,
),
registerEventListener(TableEvent.InteractionsFired, interactions => {
if (
interactions.includes(KeyboardInteraction.EditNextRow) &&
isActive
) {
onEditNextRow?.();
}
}),
];

return () => {
unregister();
for (const unregister of unregisters) {
unregister();
}
};
}
}, [isActive, onEnterEditModeWithCharacter]);
}, [isActive, onEnterEditModeWithCharacter, onEditNextRow]);

return (
<CellWrapper
Expand All @@ -135,10 +172,12 @@ export function Cell({
disabled={disabled}
role={role ?? 'gridcell'}
className={className}
onClick={handleClick}
allowUserSelect={cursorMode === CursorMode.Edit}
align={align}
tabIndex={isActive ? 0 : -1}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
onMouseEnter={handleMouseEnter}
>
{children}
</CellWrapper>
Expand Down
13 changes: 10 additions & 3 deletions browser/data-browser/src/components/TableEditor/TableEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { usePasteCommand } from './hooks/usePasteCommand';
import { DndWrapper } from './DndWrapper';
import { VisuallyHidden } from '../VisuallyHidden';
import { useClickAwayListener } from '../../hooks/useClickAwayListener';
import { KeyboardInteraction } from './helpers/keyboardHandlers';

const ARIA_TABLE_USAGE =
'Use the arrow keys to navigate the table. Press enter to edit a cell. Press escape to exit edit mode.';
Expand Down Expand Up @@ -99,8 +100,8 @@ function FancyTableInner<T>({
const scrollerRef = useRef<HTMLDivElement>(null);
const headerRef = useRef<HTMLDivElement>(null);

const { listRef, tableRef, setCursorMode } = useTableEditorContext();

const { listRef, tableRef, setCursorMode, disabledKeyboardInteractions } =
useTableEditorContext();
const [onScroll, setOnScroll] = useState<OnScroll>(() => undefined);

const { templateColumns, contentRowWidth, resizeCell } = useCellSizes(
Expand All @@ -110,8 +111,12 @@ function FancyTableInner<T>({
);

const handleClickOutside = useCallback(() => {
if (disabledKeyboardInteractions.has(KeyboardInteraction.ExitEditMode)) {
return;
}

setCursorMode(CursorMode.Visual);
}, []);
}, [disabledKeyboardInteractions]);

useClickAwayListener([tableRef], handleClickOutside, true);

Expand Down Expand Up @@ -182,6 +187,7 @@ function FancyTableInner<T>({
<VisuallyHidden id={ariaUsageId}>
<p>{ARIA_TABLE_USAGE}</p>
</VisuallyHidden>
{/* @ts-ignore */}
<Table
aria-labelledby={labelledBy}
aria-rowcount={itemCount}
Expand Down Expand Up @@ -229,6 +235,7 @@ interface TableProps {
totalContentHeight: number;
}

// @ts-ignore
const Table = styled.div.attrs<TableProps>(p => ({
style: {
'--table-template-columns': p.gridTemplateColumns,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ export enum TableEvent {
EnterEditModeWithCharacter = 'enterEditModeWithCharacter',
ClearCell = 'clearCell',
ClearRow = 'clearRow',
InteractionsFired = 'interactionsFired',
}

export type TableEventHandlers = {
enterEditModeWithCharacter: (key: string) => void;
clearCell: () => void;
clearRow: (index: number) => void;
interactionsFired: (interactions: KeyboardInteraction[]) => void;
};

export enum CursorMode {
Expand All @@ -26,6 +28,8 @@ function emptySetState<T>(_: T | ((__: T) => T)): undefined {
}

export interface TableEditorContext {
mouseDown: boolean;
setMouseDown: React.Dispatch<React.SetStateAction<boolean>>;
tableRef: React.MutableRefObject<HTMLDivElement | null>;
disabledKeyboardInteractions: Set<KeyboardInteraction>;
setDisabledKeyboardInteractions: React.Dispatch<
Expand Down Expand Up @@ -55,10 +59,13 @@ export interface TableEditorContext {
registerEventListener<T extends TableEvent>(
event: T,
cb: TableEventHandlers[T],
);
): () => void;
emitInteractionsFired(interactions: KeyboardInteraction[]): void;
}

const initial = {
mouseDown: false,
setMouseDown: emptySetState,
tableRef: { current: null },
disabledKeyboardInteractions: new Set<KeyboardInteraction>(),
setDisabledKeyboardInteractions: emptySetState,
Expand All @@ -80,14 +87,16 @@ const initial = {
clearCell: () => undefined,
clearRow: (_: number) => undefined,
enterEditModeWithCharacter: (_: string) => undefined,
registerEventListener: () => undefined,
registerEventListener: () => () => undefined,
emitInteractionsFired: () => undefined,
};

const TableEditorContext = React.createContext<TableEditorContext>(initial);

export function TableEditorContextProvider({
children,
}: React.PropsWithChildren<unknown>): JSX.Element {
const [mouseDown, setMouseDown] = useState(false);
const tableRef = useRef<HTMLDivElement | null>(null);
const listRef = useRef<FixedSizeList>(null);
const [eventManager] = useState(
Expand Down Expand Up @@ -146,8 +155,17 @@ export function TableEditorContextProvider({
[eventManager],
);

const emitInteractionsFired = useCallback(
(interactions: KeyboardInteraction[]) => {
eventManager.emit(TableEvent.InteractionsFired, interactions);
},
[eventManager],
);

const context = useMemo(
() => ({
mouseDown,
setMouseDown,
tableRef,
disabledKeyboardInteractions,
setDisabledKeyboardInteractions,
Expand All @@ -170,6 +188,7 @@ export function TableEditorContextProvider({
clearCell,
clearRow,
enterEditModeWithCharacter,
emitInteractionsFired,
}),
[
disabledKeyboardInteractions,
Expand All @@ -182,6 +201,8 @@ export function TableEditorContextProvider({
setMultiSelectCorner,
isDragging,
cursorMode,
emitInteractionsFired,
mouseDown,
],
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,14 @@ export function useTableEditorKeyboardNavigation(
multiSelectCornerColumn,
setActiveCell,
listRef,
emitInteractionsFired,
} = tableContext;

const hasControlLock = useHasControlLock();

const handleKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLDivElement>) => {
if (hasControlLock || tableHeaderHasFocus(headerRef)) {
console.warn('Control lock enabled, can not use keyboard.');

return;
}

Expand Down Expand Up @@ -102,6 +101,8 @@ export function useTableEditorKeyboardNavigation(

handler.handler(context);
}

emitInteractionsFired(handlers.map(h => h.id));
},
[
disabledKeyboardInteractions,
Expand All @@ -114,6 +115,7 @@ export function useTableEditorKeyboardNavigation(
commands.undo,
commands.expand,
hasControlLock,
emitInteractionsFired,
],
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function AtomicSelectInput({
};

return (
<InputWrapper>
<StyledInputWrapper>
<SelectWrapper disabled={!!props.disabled}>
<Select {...props} onChange={handleChange} value={value as string}>
{options.map(option => (
Expand All @@ -40,10 +40,14 @@ export function AtomicSelectInput({
))}
</Select>
</SelectWrapper>
</InputWrapper>
</StyledInputWrapper>
);
}

const StyledInputWrapper = styled(InputWrapper)`
min-width: 15ch;
`;

const SelectWrapper = styled.span<{ disabled: boolean }>`
width: 100%;
padding-inline: 0.2rem;
Expand Down
6 changes: 6 additions & 0 deletions browser/data-browser/src/views/OntologyPage/OntologyPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ const FullPageWrapper = styled.div<{ edit: boolean }>`
--ontology-graph-ratio: 16/9;
}

@container (max-width: 600px) {
grid-template-areas: ${p =>
p.edit ? `'title' 'list' 'list'` : `'title' 'graph' 'list'`};
grid-template-columns: 100%;
}

padding-bottom: 3rem;
`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export function PropertyLineWrite({

return (
<ListItem>
<Row center>
<Row center wrapItems>
<InputSwitcher
commit
required
Expand Down
Loading