mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
dbeaver/pro#6018 fix: context menu disappears on cells with an intera… (#3538)
* dbeaver/pro#6018 fix: context menu disappears on cells with an interactive formatter add menu visibility handling to cell formatters * dbeaver/pro#6018 refactor: rename handleStateSwitch to handleCellMenuStateSwitch for clarity * dbeaver/pro#6018 refactor: rename menu visibility properties for clarity --------- Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
This commit is contained in:
@@ -4,11 +4,12 @@ import { Checkbox, clsx, Focusable } from '@dbeaver/ui-kit';
|
||||
interface Props {
|
||||
value: boolean | null;
|
||||
className?: string;
|
||||
focusable?: boolean;
|
||||
onClick?: React.MouseEventHandler<HTMLElement>;
|
||||
onKeyDown?: React.KeyboardEventHandler<HTMLElement>;
|
||||
}
|
||||
|
||||
export function BooleanFormatter({ value, className, onClick, onKeyDown }: Props) {
|
||||
export function BooleanFormatter({ value, className, onClick, onKeyDown, focusable }: Props) {
|
||||
const handleKeyDown = (event: React.KeyboardEvent<HTMLElement>) => {
|
||||
if (event.code === 'Enter' || event.code === 'Space') {
|
||||
event.preventDefault();
|
||||
@@ -17,6 +18,7 @@ export function BooleanFormatter({ value, className, onClick, onKeyDown }: Props
|
||||
};
|
||||
return (
|
||||
<Focusable
|
||||
focusable={focusable}
|
||||
className={clsx('tw:flex tw:items-center tw:outline-none tw:hover:cursor-pointer', className)}
|
||||
onKeyDown={handleKeyDown}
|
||||
onClick={onClick}
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,6 +20,8 @@ export interface ICellContext {
|
||||
cell: IResultSetElementKey | undefined;
|
||||
position: ICellPosition;
|
||||
editionState: DatabaseEditChangeType | null;
|
||||
isMenuVisible: boolean;
|
||||
setMenuVisibility(visible: boolean): void;
|
||||
}
|
||||
|
||||
export const CellContext = createContext<ICellContext>(undefined as any);
|
||||
|
||||
+7
-1
@@ -5,7 +5,7 @@
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { computed, observable } from 'mobx';
|
||||
import { computed, observable, action } from 'mobx';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useContext, type HTMLAttributes } from 'react';
|
||||
|
||||
@@ -35,6 +35,7 @@ export const CellRenderer = observer<Props>(function CellRenderer({ rowIdx, colI
|
||||
const cellContext = useObservableRef(
|
||||
() => ({
|
||||
isHovered: false,
|
||||
isMenuVisible: false,
|
||||
get position(): ICellPosition {
|
||||
return { colIdx: this.colIdx, rowIdx: this.rowIdx };
|
||||
},
|
||||
@@ -70,9 +71,14 @@ export const CellRenderer = observer<Props>(function CellRenderer({ rowIdx, colI
|
||||
|
||||
return this.tableDataContext.getEditionState(this.cell);
|
||||
},
|
||||
setMenuVisibility(visibility: boolean): void {
|
||||
this.isMenuVisible = visibility;
|
||||
},
|
||||
}),
|
||||
{
|
||||
isHovered: observable.ref,
|
||||
isMenuVisible: observable.ref,
|
||||
setMenuVisibility: action,
|
||||
colIdx: observable.ref,
|
||||
rowIdx: observable.ref,
|
||||
row: computed,
|
||||
|
||||
+11
-7
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { use, useContext, useDeferredValue, useState } from 'react';
|
||||
import { use, useContext } from 'react';
|
||||
import { DataGridCellInnerContext } from '@cloudbeaver/plugin-data-grid';
|
||||
|
||||
import { getComputed, s, useObjectRef, useS } from '@cloudbeaver/core-blocks';
|
||||
@@ -29,11 +29,11 @@ export const CellFormatter = observer<Props>(function CellFormatter({ rowIdx, co
|
||||
const tableDataContext = useContext(TableDataContext);
|
||||
const innerCellContext = use(DataGridCellInnerContext);
|
||||
const cellContext = useContext(CellContext);
|
||||
const [menuVisible, setMenuVisible] = useState(false);
|
||||
|
||||
const cell = cellContext.cell;
|
||||
const showCellMenu = getComputed(() => !!cell && (innerCellContext?.isFocused || cellContext.isFocused || cellContext.isHovered || menuVisible));
|
||||
const showCellMenuDeferred = useDeferredValue(showCellMenu, showCellMenu);
|
||||
const showCellMenu = getComputed(
|
||||
() => !!cell && (innerCellContext?.isFocused || cellContext.isFocused || cellContext.isHovered || cellContext.isMenuVisible),
|
||||
);
|
||||
const styles = useS(style);
|
||||
|
||||
const spreadsheetActions = useObjectRef<IDataPresentationActions<IResultSetElementKey>>({
|
||||
@@ -47,12 +47,16 @@ export const CellFormatter = observer<Props>(function CellFormatter({ rowIdx, co
|
||||
},
|
||||
});
|
||||
|
||||
function handleCellMenuStateSwitch(visible: boolean): void {
|
||||
cellContext.setMenuVisibility(visible);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={s(styles, { wrapper: true })}>
|
||||
<div className={s(styles, { container: true })}>
|
||||
<CellFormatterFactory rowIdx={rowIdx} colIdx={colIdx} />
|
||||
</div>
|
||||
{showCellMenuDeferred && (
|
||||
{showCellMenu && (
|
||||
<div className={s(styles, { menuContainer: true })}>
|
||||
<CellMenu
|
||||
cellKey={cell!}
|
||||
@@ -61,7 +65,7 @@ export const CellFormatter = observer<Props>(function CellFormatter({ rowIdx, co
|
||||
spreadsheetActions={spreadsheetActions}
|
||||
resultIndex={context.resultIndex}
|
||||
simple={context.simple}
|
||||
onStateSwitch={setMenuVisible}
|
||||
onStateSwitch={handleCellMenuStateSwitch}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
+7
-1
@@ -53,6 +53,12 @@ export const BooleanFormatter = observer<ICellFormatterProps>(function BooleanFo
|
||||
}
|
||||
|
||||
return (
|
||||
<GridBooleanFormatter className={s(style, { formatter: true })} value={value as boolean | null} onClick={toggleValue} onKeyDown={toggleValue} />
|
||||
<GridBooleanFormatter
|
||||
focusable={!cellContext.isMenuVisible}
|
||||
className={s(style, { formatter: true })}
|
||||
value={value as boolean | null}
|
||||
onClick={toggleValue}
|
||||
onKeyDown={toggleValue}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user