Skip to content

Commit

Permalink
fix: grid hotkeys (#653)
Browse files Browse the repository at this point in the history
* fix: the rendering of the loading when switching grid views

* fix: the shortcut key for quick search triggers twice

* fix: the hotkey conflicts in the grid view
  • Loading branch information
Sky-FE committed Jun 6, 2024
1 parent b24f97a commit 402b9a6
Show file tree
Hide file tree
Showing 13 changed files with 59 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ export const GridViewBase = () => {
const router = useRouter();
const isHydrated = useIsHydrated();
const groupPoints = useGroupPoint();
const prepare = isHydrated && view;
const gridRef = useRef<IGridRef>(null);
const container = useRef<HTMLDivElement>(null);
const expandRecordRef = useRef<IExpandRecordContainerRef>(null);
Expand All @@ -76,6 +75,7 @@ export const GridViewBase = () => {
const hiddenFields = useHiddenFields();
const customIcons = useGridIcons();

const prepare = isHydrated && view && columns.length;
const { filter, sort, group } = view ?? {};
const realRowCount = rowCount ?? ssrRecords?.length ?? 0;

Expand Down Expand Up @@ -242,9 +242,9 @@ export const GridViewBase = () => {
) : (
<div className="flex w-full items-center space-x-4">
<div className="w-full space-y-3 px-2">
<Skeleton className="h-6 w-full" />
<Skeleton className="h-6 w-full" />
<Skeleton className="h-6 w-full" />
<Skeleton className="h-7 w-full" />
<Skeleton className="h-7 w-full" />
<Skeleton className="h-7 w-full" />
</div>
</div>
)}
Expand Down
22 changes: 17 additions & 5 deletions apps/nextjs-app/src/features/app/blocks/view/grid/GridViewBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import { isEqual, keyBy, uniqueId, groupBy } from 'lodash';
import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { usePrevious, useMount, useClickAway } from 'react-use';
import { ExpandRecordContainer } from '@/features/app/components/ExpandRecordContainer';
import type { IExpandRecordContainerRef } from '@/features/app/components/ExpandRecordContainer/types';
Expand Down Expand Up @@ -108,7 +109,7 @@ export const GridViewBase: React.FC<IGridViewProps> = (props: IGridViewProps) =>
const group = view?.group;
const isAutoSort = sort && !sort?.manualSort;
const frozenColumnCount = isTouchDevice ? 0 : view?.options?.frozenColumnCount ?? 1;
const isLoading = !view;
const isLoading = !view || !columns.length;
const permission = useTablePermission();
const { toast } = useToast();
const realRowCount = rowCount ?? ssrRecords?.length ?? 0;
Expand Down Expand Up @@ -301,7 +302,8 @@ export const GridViewBase: React.FC<IGridViewProps> = (props: IGridViewProps) =>
const selectColumns = extract(start, end, columns);
const indexedColumns = keyBy(selectColumns, 'id');
const selectFields = fields.filter((field) => indexedColumns[field.id]);
openHeaderMenu({ position, fields: selectFields });
const onSelectionClear = () => gridRef.current?.setSelection(emptySelection);
openHeaderMenu({ position, fields: selectFields, onSelectionClear });
}
},
[
Expand Down Expand Up @@ -614,6 +616,16 @@ export const GridViewBase: React.FC<IGridViewProps> = (props: IGridViewProps) =>

useScrollFrameRate(gridRef.current?.scrollBy);

useHotkeys(
['mod+f', 'mod+k'],
() => {
gridRef.current?.setSelection(emptySelection);
},
{
enableOnFormTags: ['input', 'select', 'textarea'],
}
);

return (
<div ref={containerRef} className="relative size-full overflow-hidden">
{isReadyToRender && !isLoading ? (
Expand Down Expand Up @@ -697,9 +709,9 @@ export const GridViewBase: React.FC<IGridViewProps> = (props: IGridViewProps) =>
) : (
<div className="flex w-full items-center space-x-4">
<div className="w-full space-y-3 px-2">
<Skeleton className="h-6 w-full" />
<Skeleton className="h-6 w-full" />
<Skeleton className="h-6 w-full" />
<Skeleton className="h-7 w-full" />
<Skeleton className="h-7 w-full" />
<Skeleton className="h-7 w-full" />
</div>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const FieldMenu = () => {
const { t } = useTranslation(tableConfig.i18nNamespaces);
const allFields = useFields({ withHidden: true, withDenied: true });
const fieldSettingRef = useRef<HTMLDivElement>(null);
const fields = headerMenu?.fields;
const { fields, onSelectionClear } = headerMenu ?? {};

const menuFieldPermission = useMemo(() => {
if (!fields?.length || !fieldsPermission) {
Expand Down Expand Up @@ -210,6 +210,7 @@ export const FieldMenu = () => {
return;
}
await onClick();
onSelectionClear?.();
closeHeaderMenu();
}}
>
Expand Down Expand Up @@ -249,6 +250,7 @@ export const FieldMenu = () => {
return;
}
await onClick();
onSelectionClear?.();
closeHeaderMenu();
}}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { IFieldInstance, Record } from '@teable/sdk/model';
export interface IHeaderMenu {
fields: IFieldInstance[];
position: IPosition;
onSelectionClear?: () => void;
}

export interface IRecordMenu {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const Sidebar: FC<PropsWithChildren<ISidebarProps>> = (props) => {
>
<div className="flex size-full flex-col overflow-hidden bg-popover">
<SidebarHeader headerLeft={headerLeft} onExpand={() => setLeftVisible(!leftVisible)} />
{children}
{leftVisible && children}
</div>
</div>
)}
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk/src/components/editor/long-text/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const LongTextEditorBase: ForwardRefRenderFunction<IEditorRef<string>, ITextEdit
props,
ref
) => {
const { value, onChange, className, readonly } = props;
const { value, onChange, className, readonly, saveOnBlur = true } = props;
const [text, setText] = useState<string>(value || '');
const inputRef = useRef<HTMLTextAreaElement | null>(null);

Expand Down Expand Up @@ -39,7 +39,7 @@ const LongTextEditorBase: ForwardRefRenderFunction<IEditorRef<string>, ITextEdit
minRows={2}
maxRows={10}
readOnly={readonly}
onBlur={saveValue}
onBlur={() => saveOnBlur && saveValue()}
onChange={onChangeInner}
/>
);
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk/src/components/editor/number/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const NumberEditorBase: ForwardRefRenderFunction<IEditorRef<number>, INum
props,
ref
) => {
const { value, options, onChange, className, readonly, style } = props;
const { value, options, onChange, className, readonly, style, saveOnBlur = true } = props;
const { formatting } = options;
const inputRef = useRef<HTMLInputElement | null>(null);
const [formatStr, setFormatStr] = useState<string | null>(
Expand Down Expand Up @@ -47,7 +47,7 @@ export const NumberEditorBase: ForwardRefRenderFunction<IEditorRef<number>, INum
className={cn('h-10 sm:h-8', className)}
value={formatStr || ''}
onChange={onChangeInner}
onBlur={saveValue}
onBlur={() => saveOnBlur && saveValue()}
disabled={readonly}
/>
);
Expand Down
4 changes: 2 additions & 2 deletions packages/sdk/src/components/editor/text/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface ITextEditor extends ICellEditor<string | null> {
}

const TextEditorBase: ForwardRefRenderFunction<IEditorRef<string>, ITextEditor> = (props, ref) => {
const { value, options, onChange, className, readonly, style } = props;
const { value, options, onChange, className, readonly, style, saveOnBlur = true } = props;
const [text, setText] = useState<string>(value || '');
const inputRef = useRef<HTMLInputElement | null>(null);
const showAs = options.showAs;
Expand Down Expand Up @@ -56,7 +56,7 @@ const TextEditorBase: ForwardRefRenderFunction<IEditorRef<string>, ITextEditor>
className={cn('h-10 sm:h-8', className)}
value={text}
onChange={onChangeInner}
onBlur={saveValue}
onBlur={() => saveOnBlur && saveValue()}
disabled={readonly}
/>
{showAs && (
Expand Down
3 changes: 2 additions & 1 deletion packages/sdk/src/components/editor/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ export interface ICellEditor<T> {
className?: string;
style?: React.CSSProperties;
value?: T;
onChange?: (value?: T) => void;
readonly?: boolean;
saveOnBlur?: boolean;
context?: ICellEditorContext;
onChange?: (value?: T) => void;
}

export interface IEditorRef<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const GridNumberEditorBase: ForwardRefRenderFunction<
style={{ border: `2px solid ${cellLineColorActived}`, ...style, ...attachStyle }}
options={options}
onChange={saveValue}
saveOnBlur={false}
/>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const GridSelectEditorBase: ForwardRefRenderFunction<
IEditorRef<string | string[] | undefined>,
IWrapperEditorProps & IEditorProps
> = (props, ref) => {
const { field, record, rect, style, isEditing } = props;
const { field, record, rect, style, isEditing, setEditing } = props;
const tableId = useTableId();
const defaultFocusRef = useRef<HTMLInputElement | null>(null);
const editorRef = useRef<IEditorRef<string | string[] | undefined>>(null);
Expand Down Expand Up @@ -59,6 +59,7 @@ const GridSelectEditorBase: ForwardRefRenderFunction<

const onChange = (value?: string[] | string) => {
record.updateCell(fieldId, isMultiple && value?.length === 0 ? null : value);
if (!isMultiple) setEditing?.(false);
};

const onOptionAdd = useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
import { clamp } from 'lodash';
import type { CSSProperties, ForwardRefRenderFunction } from 'react';
import { useEffect, useRef, useMemo, useImperativeHandle, forwardRef } from 'react';
import { HotkeysProvider } from 'react-hotkeys-hook';
import type { IGridTheme } from '../../configs';
import { GRID_HOTKEY_SCOPE, useKeyboardSelection } from '../../hooks';
import { useKeyboardSelection } from '../../hooks';
import type { IInteractionLayerProps } from '../../InteractionLayer';
import type { IActiveCellBound, ICellItem, IRectangle, IScrollState } from '../../interface';
import type { CombinedSelection } from '../../managers';
Expand Down Expand Up @@ -117,9 +116,14 @@ export const EditorContainerBase: ForwardRefRenderFunction<
if ((cellContent as ICell).type === CellType.Loading) return;
if (!activeCell || isEditing) return;
editorRef.current?.setValue?.(cellContent.data);
requestAnimationFrame(() => (editorRef.current || defaultFocusRef.current)?.focus?.());
}, [cellContent, activeCell, isEditing]);

useEffect(() => {
if ((cellType as CellType) === CellType.Loading) return;
if (!activeCell) return;
requestAnimationFrame(() => (editorRef.current || defaultFocusRef.current)?.focus?.());
}, [cellType, activeCell, isEditing]);

useKeyboardSelection({
editorRef,
isEditing,
Expand Down Expand Up @@ -271,24 +275,22 @@ export const EditorContainerBase: ForwardRefRenderFunction<
};

return (
<HotkeysProvider initiallyActiveScopes={[GRID_HOTKEY_SCOPE]}>
<div className="click-outside-ignore pointer-events-none absolute left-0 top-0 w-full">
<div
className="absolute z-10"
style={{
top: rect.y,
left: rect.x,
minWidth: width,
minHeight: height,
}}
onKeyDown={onKeyDown}
onPaste={onPasteInner}
>
{EditorRenderer}
<input className="opacity-0" ref={defaultFocusRef} />
</div>
<div className="click-outside-ignore pointer-events-none absolute left-0 top-0 w-full">
<div
className="absolute z-10"
style={{
top: rect.y,
left: rect.x,
minWidth: width,
minHeight: height,
}}
onKeyDown={onKeyDown}
onPaste={onPasteInner}
>
{EditorRenderer}
<input className="opacity-0" ref={defaultFocusRef} />
</div>
</HotkeysProvider>
</div>
);
};

Expand Down
10 changes: 0 additions & 10 deletions packages/sdk/src/components/grid/hooks/useKeyboardSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ interface ISelectionKeyboardProps
editorRef: React.MutableRefObject<IEditorRef | null>;
}

export const GRID_HOTKEY_SCOPE = 'grid-hotkey-scope';

export const useKeyboardSelection = (props: ISelectionKeyboardProps) => {
const {
isEditing,
Expand All @@ -44,7 +42,6 @@ export const useKeyboardSelection = (props: ISelectionKeyboardProps) => {
},
{
enabled: !isEditing && selection.type !== SelectionRegionType.None,
scopes: GRID_HOTKEY_SCOPE,
enableOnFormTags: ['input', 'select', 'textarea'],
}
);
Expand Down Expand Up @@ -105,7 +102,6 @@ export const useKeyboardSelection = (props: ISelectionKeyboardProps) => {
},
{
enabled: Boolean(activeCell && !isEditing),
scopes: GRID_HOTKEY_SCOPE,
enableOnFormTags: ['input', 'select', 'textarea'],
}
);
Expand All @@ -126,7 +122,6 @@ export const useKeyboardSelection = (props: ISelectionKeyboardProps) => {
},
{
enabled: Boolean(activeCell),
scopes: GRID_HOTKEY_SCOPE,
enableOnFormTags: ['input', 'select', 'textarea'],
}
);
Expand All @@ -142,7 +137,6 @@ export const useKeyboardSelection = (props: ISelectionKeyboardProps) => {
},
{
enabled: Boolean(activeCell && !isEditing),
scopes: GRID_HOTKEY_SCOPE,
enableOnFormTags: ['input', 'select', 'textarea'],
}
);
Expand All @@ -159,7 +153,6 @@ export const useKeyboardSelection = (props: ISelectionKeyboardProps) => {
},
{
enabled: Boolean(activeCell && !isEditing),
scopes: GRID_HOTKEY_SCOPE,
enableOnFormTags: ['input', 'select', 'textarea'],
}
);
Expand Down Expand Up @@ -192,7 +185,6 @@ export const useKeyboardSelection = (props: ISelectionKeyboardProps) => {
},
{
enabled: Boolean(activeCell),
scopes: GRID_HOTKEY_SCOPE,
enableOnFormTags: ['input', 'select', 'textarea'],
}
);
Expand All @@ -204,7 +196,6 @@ export const useKeyboardSelection = (props: ISelectionKeyboardProps) => {
},
{
enabled: Boolean(activeCell),
scopes: GRID_HOTKEY_SCOPE,
enableOnFormTags: ['input', 'select', 'textarea'],
}
);
Expand All @@ -217,7 +208,6 @@ export const useKeyboardSelection = (props: ISelectionKeyboardProps) => {
},
{
enabled: Boolean(activeCell && !isEditing),
scopes: GRID_HOTKEY_SCOPE,
enableOnFormTags: ['input', 'select', 'textarea'],
}
);
Expand Down

0 comments on commit 402b9a6

Please sign in to comment.