Skip to content

Commit

Permalink
Merge pull request #1972 from quadratichq/ayush/1961
Browse files Browse the repository at this point in the history
fix: inline editor arrow key interactions (edit & enter states)
  • Loading branch information
davidkircos authored Nov 21, 2024
2 parents 51156b2 + 5378d8b commit 322dfbc
Show file tree
Hide file tree
Showing 17 changed files with 290 additions and 78 deletions.
1 change: 1 addition & 0 deletions quadratic-client/src/app/actions/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export enum Action {
MoveCursorRightWithSelection = 'move_cursor_right_with_selection',
MoveCursorLeftWithSelection = 'move_cursor_left_with_selection',
EditCell = 'edit_cell',
ToggleArrowMode = 'toggle_arrow_mode',
DeleteCell = 'delete_cell',
ShowCellTypeMenu = 'show_cell_type_menu',
CloseInlineEditor = 'close_inline_editor',
Expand Down
50 changes: 42 additions & 8 deletions quadratic-client/src/app/actions/editActionsSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from '@/app/grid/actions/clipboard/clipboard';
import { sheets } from '@/app/grid/controller/Sheets';
import { inlineEditorHandler } from '@/app/gridGL/HTMLGrid/inlineEditor/inlineEditorHandler';
import { CursorMode } from '@/app/gridGL/HTMLGrid/inlineEditor/inlineEditorKeyboard';
import { doubleClickCell } from '@/app/gridGL/interaction/pointer/doubleClickCell';
import { pixiAppSettings } from '@/app/gridGL/pixiApp/PixiAppSettings';
import { downloadFile } from '@/app/helpers/downloadFileInBrowser';
Expand Down Expand Up @@ -42,6 +43,7 @@ type EditActionSpec = Pick<
| Action.FillRight
| Action.FillDown
| Action.EditCell
| Action.ToggleArrowMode
| Action.DeleteCell
| Action.CloseInlineEditor
| Action.SaveInlineEditor
Expand Down Expand Up @@ -162,19 +164,51 @@ export const editActionsSpec: EditActionSpec = {
label: 'Edit cell',
run: () => {
if (!inlineEditorHandler.isEditingFormula()) {
const cursor = sheets.sheet.cursor;
const cursorPosition = cursor.cursorPosition;
const column = cursorPosition.x;
const row = cursorPosition.y;
quadraticCore.getCodeCell(sheets.sheet.id, column, row).then((code) => {
const { x, y } = sheets.sheet.cursor.cursorPosition;
quadraticCore.getCodeCell(sheets.sheet.id, x, y).then((code) => {
if (code) {
doubleClickCell({ column: Number(code.x), row: Number(code.y), language: code.language, cell: '' });
doubleClickCell({
column: Number(code.x),
row: Number(code.y),
language: code.language,
cell: '',
});
} else {
quadraticCore.getEditCell(sheets.sheet.id, x, y).then((cell) => {
doubleClickCell({
column: x,
row: y,
cell,
cursorMode: cell ? CursorMode.Edit : CursorMode.Enter,
});
});
}
});
return true;
}
},
},
[Action.ToggleArrowMode]: {
label: 'Toggle arrow mode',
run: () => {
if (!inlineEditorHandler.isEditingFormula()) {
const { x, y } = sheets.sheet.cursor.cursorPosition;
quadraticCore.getCodeCell(sheets.sheet.id, x, y).then((code) => {
if (code) {
doubleClickCell({
column: Number(code.x),
row: Number(code.y),
language: code.language,
cell: '',
cursorMode: CursorMode.Edit,
});
} else {
quadraticCore.getEditCell(sheets.sheet.id, column, row).then((cell) => {
doubleClickCell({ column, row, cell });
quadraticCore.getEditCell(sheets.sheet.id, x, y).then((cell) => {
doubleClickCell({ column: x, row: y, cell, cursorMode: CursorMode.Edit });
});
}
});
return true;
}
},
},
Expand Down
11 changes: 9 additions & 2 deletions quadratic-client/src/app/atoms/inlineEditorAtom.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import { CursorMode, inlineEditorKeyboard } from '@/app/gridGL/HTMLGrid/inlineEditor/inlineEditorKeyboard';
import { inlineEditorMonaco } from '@/app/gridGL/HTMLGrid/inlineEditor/inlineEditorMonaco';
import { pixiApp } from '@/app/gridGL/pixiApp/PixiApp';
import { LINE_HEIGHT } from '@/app/web-workers/renderWebWorker/worker/cellsLabel/CellLabel';
import { atom } from 'recoil';

export interface InlineEditorState {
visible: boolean;
formula: boolean;
left: number;
top: number;
lineHeight: number;
height: number;
editMode: boolean;
}

export const defaultInlineEditor: InlineEditorState = {
visible: false,
formula: false,
left: 0,
top: 0,
lineHeight: 19,
height: LINE_HEIGHT,
editMode: false,
};

export const inlineEditorAtom = atom({
Expand All @@ -26,6 +31,8 @@ export const inlineEditorAtom = atom({
if (newValue.visible) {
inlineEditorMonaco.focus();
}
inlineEditorKeyboard.cursorMode = newValue.editMode ? CursorMode.Edit : CursorMode.Enter;
pixiApp.cursor.dirty = true;
});
},
],
Expand Down
3 changes: 2 additions & 1 deletion quadratic-client/src/app/events/events.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ErrorValidation } from '@/app/gridGL/cells/CellsSheet';
import { EditingCell } from '@/app/gridGL/HTMLGrid/hoverCell/HoverCell';
import { CursorMode } from '@/app/gridGL/HTMLGrid/inlineEditor/inlineEditorKeyboard';
import { CodeCell } from '@/app/gridGL/types/codeCell';
import { SheetPosTS } from '@/app/gridGL/types/size';
import {
Expand Down Expand Up @@ -51,7 +52,7 @@ interface EventTypes {
setCursor: (cursor?: string, selection?: Selection) => void;
cursorPosition: () => void;
generateThumbnail: () => void;
changeInput: (input: boolean, initialValue?: string) => void;
changeInput: (input: boolean, initialValue?: string, cursorMode?: CursorMode) => void;
headingSize: (width: number, height: number) => void;
gridSettings: () => void;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
//! in inlineEditorHandler.ts.

import { inlineEditorAtom } from '@/app/atoms/inlineEditorAtom';
import { sheets } from '@/app/grid/controller/Sheets';
import { inlineEditorHandler } from '@/app/gridGL/HTMLGrid/inlineEditor/inlineEditorHandler';
import { CURSOR_THICKNESS } from '@/app/gridGL/UI/Cursor';
import { colors } from '@/app/theme/colors';
import { DockToLeftIcon } from '@/shared/components/Icons';
import { Button } from '@/shared/shadcn/ui/button';
import { SubtitlesOutlined } from '@mui/icons-material';
import { Tooltip } from '@mui/material';
import { TooltipPopover } from '@/shared/shadcn/ui/tooltip';
import { useCallback } from 'react';
import { useRecoilValue } from 'recoil';
import './inlineEditorStyles.scss';
Expand All @@ -21,12 +23,12 @@ export const InlineEditor = () => {
}
}, []);

// Note: I switched to using material's Tooltip because radix-ui's Tooltip did
// not keep position during viewport changes. Even forcing a remount did not
// fix its positioning problem. There's probably a workaround, but it was too
// much work.

const { visible, formula, left, top } = useRecoilValue(inlineEditorAtom);
let { visible, formula, left, top, height } = useRecoilValue(inlineEditorAtom);
height += CURSOR_THICKNESS * 1.5;
const inlineShowing = inlineEditorHandler.getShowing();
if (inlineShowing) {
height = Math.max(height, sheets.sheet.getCellOffsets(inlineShowing.x, inlineShowing.y).height);
}

return (
<div
Expand All @@ -44,26 +46,28 @@ export const InlineEditor = () => {
<div id="cell-edit"></div>

{visible && formula ? (
<Tooltip title="Open Formula in multi-line code editor">
<TooltipPopover label="Open Formula in multi-line code editor">
<Button
variant="ghost"
style={{
boxSizing: 'content-box',
position: 'absolute',
display: 'flex',
alignItems: 'center',
alignItems: 'flex-start',
borderRadius: '0',
padding: '0',
marginTop: '-0.23px',
width: '23px',
height: '23.23px',
height: `${height}px`,
right: '-24px',
backgroundColor: colors.languageFormula,
}}
onClick={(e) => inlineEditorHandler.openCodeEditor(e)}
onClick={(e) => {
e.stopPropagation();
inlineEditorHandler.openCodeEditor();
}}
>
<SubtitlesOutlined sx={{ width: '18px', height: '18px', color: 'white' }} />
<DockToLeftIcon style={{ color: 'white', width: '20px', height: '20px' }} />
</Button>
</Tooltip>
</TooltipPopover>
) : null}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ class InlineEditorFormula {
// or by keyboard input) or whether they want to switch to a different cell.
wantsCellRef() {
const lastCharacter = inlineEditorMonaco.getNonWhitespaceCharBeforeCursor();
return ['', ',', '+', '-', '*', '/', '%', '=', '<', '>', '&', '.', '(', '{'].includes(lastCharacter);
return (
!!lastCharacter &&
['', ',', '+', '-', '*', '/', '%', '=', '<', '>', '&', '.', '(', '{', ':', '!'].includes(lastCharacter)
);
}

// Returns whether we are editing a formula only if it is valid (used for
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { events } from '@/app/events/events';
import { sheets } from '@/app/grid/controller/Sheets';
import { inlineEditorFormula } from '@/app/gridGL/HTMLGrid/inlineEditor/inlineEditorFormula';
import { inlineEditorKeyboard } from '@/app/gridGL/HTMLGrid/inlineEditor/inlineEditorKeyboard';
import { CursorMode, inlineEditorKeyboard } from '@/app/gridGL/HTMLGrid/inlineEditor/inlineEditorKeyboard';
import { inlineEditorMonaco, PADDING_FOR_INLINE_EDITOR } from '@/app/gridGL/HTMLGrid/inlineEditor/inlineEditorMonaco';
import { pixiApp } from '@/app/gridGL/pixiApp/PixiApp';
import { pixiAppSettings } from '@/app/gridGL/pixiApp/PixiAppSettings';
Expand Down Expand Up @@ -171,7 +171,7 @@ class InlineEditorHandler {
};

// Handler for the changeInput event.
private changeInput = async (input: boolean, initialValue?: string) => {
private changeInput = async (input: boolean, initialValue?: string, cursorMode?: CursorMode) => {
if (!input && !this.open) return;

if (initialValue) {
Expand All @@ -197,16 +197,30 @@ class InlineEditorHandler {
let changeToFormula = false;
if (initialValue) {
value = initialValue;
this.changeToFormula(value[0] === '=');
changeToFormula = value[0] === '=';
} else {
const formula = await quadraticCore.getCodeCell(this.location.sheetId, this.location.x, this.location.y);
if (formula?.language === 'Formula') {
value = '=' + formula.code_string;
changeToFormula = true;
} else {
value = (await quadraticCore.getEditCell(this.location.sheetId, this.location.x, this.location.y)) || '';
changeToFormula = false;
}
}

if (cursorMode === undefined) {
if (changeToFormula) {
cursorMode = value.length > 1 ? CursorMode.Edit : CursorMode.Enter;
} else {
cursorMode = value ? CursorMode.Edit : CursorMode.Enter;
}
}
pixiAppSettings.setInlineEditorState?.((prev) => ({
...prev,
editMode: cursorMode === CursorMode.Edit,
}));

this.formatSummary = await quadraticCore.getCellFormatSummary(
this.location.sheetId,
this.location.x,
Expand Down Expand Up @@ -358,8 +372,8 @@ class InlineEditorHandler {
pixiAppSettings.setInlineEditorState((prev) => ({
...prev,
left: this.x,
top: this.y + OPEN_SANS_FIX.y / 3,
lineHeight: this.height,
top: this.y,
height: this.height,
}));

pixiApp.cursor.dirty = true;
Expand Down Expand Up @@ -502,8 +516,7 @@ class InlineEditorHandler {
};

// Handler for the click for the expand code editor button.
openCodeEditor = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
e.stopPropagation();
openCodeEditor = () => {
if (!pixiAppSettings.setCodeEditorState) {
throw new Error('Expected setCodeEditorState to be defined in openCodeEditor');
}
Expand Down
Loading

0 comments on commit 322dfbc

Please sign in to comment.