Skip to content

Commit

Permalink
Merge pull request #75 from walkframe/fix/fixed-with-transform
Browse files Browse the repository at this point in the history
Fix/fixed with transform
  • Loading branch information
righ authored Nov 12, 2024
2 parents b7f60b7 + b620469 commit 717838d
Show file tree
Hide file tree
Showing 16 changed files with 145 additions and 84 deletions.
1 change: 1 addition & 0 deletions .storybook/examples/basic/size.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const Sheet = ({ numRows, numCols, defaultWidth, initialCells }: Props) => {
raw: (n) => String(n),
},
sheetResize: "both",
editingOnEnter: true,
}}
initialCells={constructInitialCells({
cells: {
Expand Down
4 changes: 2 additions & 2 deletions .storybook/examples/basic/style.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default {

export const Style = () => {
return (
<>
<div style={{transform: 'translate(50px, 50px)'}}>
<GridSheet
initialCells={constructInitialCells({
matrices: {
Expand Down Expand Up @@ -89,6 +89,6 @@ export const Style = () => {
})}
options={{}}
/>
</>
</div>
);
};
20 changes: 20 additions & 0 deletions e2e/event.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,23 @@ test('escape key should cancel the editing', async ({ page }) => {
expect(await histories.count()).toBe(0);
expect(await b2.locator('.gs-cell-rendered').textContent()).toBe('7');
});

test('edit on enter', async ({ page }) => {
await page.goto('http://localhost:5233/iframe.html?id=basic--small&viewMode=story');
const address = page.locator('.gs-selecting-address');
const editor = page.locator('.gs-editor');
const b2 = page.locator("[data-address='B2']");
await b2.click();

expect(await address.textContent()).toBe('B2');
expect(await editor.getAttribute('class')).not.toContain('gs-editing');
await page.keyboard.press('Enter');
expect(await address.textContent()).toBe('B2');
expect(await editor.getAttribute('class')).toContain('gs-editing');
await page.keyboard.press('Enter');
expect(await address.textContent()).toBe('B3');
expect(await editor.getAttribute('class')).not.toContain('gs-editing');
await page.keyboard.press('Enter');
expect(await address.textContent()).toBe('B3');
expect(await editor.getAttribute('class')).toContain('gs-editing');
});
20 changes: 10 additions & 10 deletions e2e/formula.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ test('render', async ({ page }) => {
const a12 = sheet2.locator("[data-address='A1']");
await a12.click();
await page.keyboard.type('500');
await editor2.blur();
await page.keyboard.press('Enter');
expect(await a11.locator('.gs-cell-rendered').textContent()).toBe('600');

// update sheet3
Expand All @@ -32,7 +32,7 @@ test('render', async ({ page }) => {
const a13 = sheet3.locator("[data-address='A1']");
await a13.click();
await page.keyboard.type('777');
await editor3.blur();
await page.keyboard.press('Enter');
expect(await a31.locator('.gs-cell-rendered').textContent()).toBe('1777');

const input3 = page.locator('#input3');
Expand Down Expand Up @@ -110,16 +110,16 @@ test('insert ref by selection', async ({ page }) => {
await page.keyboard.press('ArrowLeft');
await page.keyboard.press('=');
await b2.click();
await editor.press('Enter');
await page.keyboard.press('Enter');

await b1.click();
await page.keyboard.type('=sum(');
await page.locator("[data-address='B2']").hover();
await page.mouse.down();
await page.locator("[data-address='C3']").hover();
await page.mouse.up();
await editor.press(')');
await editor.press('Enter');
await page.keyboard.type(')');
await page.keyboard.press('Enter');

await c1.click();
await page.keyboard.type('=sum()');
Expand All @@ -139,21 +139,21 @@ test('insert ref by selection in multiple sheets', async ({ page }) => {
const sheet1 = page.locator('[data-sheet-name="criteria"]');
const sheet2 = page.locator('[data-sheet-name="grades"]');
const sheet3 = page.locator('[data-sheet-name="other"]');
const editor3 = sheet3.locator('.gs-editor textarea');
const editor3 = page.locator('.gs-editor[data-sheet-id="3"] textarea');
const largeEditor3 = sheet3.locator('.gs-formula-bar textarea');

const b3 = sheet3.locator("[data-address='B3']");
await b3.click();
await largeEditor3.fill('=sum(');
await page.keyboard.type('=sum(');
await sheet1.locator("[data-address='E1']").hover();
await page.mouse.down();
await sheet1.locator("[data-address='F1']").hover();
await page.mouse.up();
// Confirm that the contents of largeEditor is copied to editor
expect(await editor3.inputValue()).toBe('=sum(criteria!E1:F1');
expect(await largeEditor3.inputValue()).toBe('=sum(criteria!E1:F1');
await largeEditor3.press(')');
await largeEditor3.press('Enter');
await page.keyboard.type(')');
await page.keyboard.press('Enter');
expect(await b3.locator('.gs-cell-rendered').textContent()).toBe('185');

const b5 = sheet3.locator("[data-address='B5']");
Expand All @@ -177,7 +177,7 @@ test('insert cols range and rows range by selection in multiple sheets', async (

const sheet1 = page.locator('[data-sheet-name="criteria"]');
const sheet2 = page.locator('[data-sheet-name="grades"]');
const editor2 = sheet2.locator('.gs-editor textarea');
const editor2 = page.locator('.gs-editor[data-sheet-id="2"] textarea');
const largeEditor2 = sheet2.locator('.gs-formula-bar textarea');

const d3 = sheet2.locator("[data-address='D3']");
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"@storybook/react": "^6.5.12",
"@types/date-fns": "^2.6.0",
"@types/jest": "^29.4.0",
"@types/react": "^16.9.49",
"@types/react": "^16.9.24",
"@types/react-dom": "^16.9.24",
"@types/storybook__react": "^5.2.1",
"@typescript-eslint/parser": "^4.14.2",
"babel-loader": "^8.2.2",
Expand Down
23 changes: 19 additions & 4 deletions src/components/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const Cell: React.FC<Props> = React.memo(({ y, x, operationStyle }) => {
selectingZone,
verticalHeaderSelecting,
horizontalheaderSelecting,
gridOuterRef,
editorRef,
showAddress,
autofillDraggingTo,
Expand All @@ -61,11 +62,19 @@ export const Cell: React.FC<Props> = React.memo(({ y, x, operationStyle }) => {
const pointed = choosing.y === y && choosing.x === x;
const _setEditorRect = React.useCallback(() => {
const rect = cellRef.current?.getBoundingClientRect();
if (rect) {
const outerRect = gridOuterRef.current?.getBoundingClientRect();
if (
rect &&
outerRect &&
rect.top < outerRect.bottom &&
rect.bottom > outerRect.top &&
rect.left < outerRect.right &&
rect.right > outerRect.left
) {
dispatch(
setEditorRect({
y: rect.top,
x: rect.left,
y: rect.y,
x: rect.x,
height: rect.height,
width: rect.width,
}),
Expand All @@ -74,12 +83,17 @@ export const Cell: React.FC<Props> = React.memo(({ y, x, operationStyle }) => {
}, []);

React.useEffect(() => {
let timeoutId: number;
if (pointed) {
_setEditorRect();
// Delay to account for coordinate shifts caused by unintentional redrawing due to virtualization.
timeoutId = window.setTimeout(_setEditorRect, 300);
if (!editing) {
dispatch(setInputting(table.stringify({ y, x })));
}
}
return () => {
window.clearTimeout(timeoutId);
};
}, [pointed, editing]);
const cell = table.getByPoint({ y, x });
const writeCell = (value: string) => {
Expand Down Expand Up @@ -151,6 +165,7 @@ export const Cell: React.FC<Props> = React.memo(({ y, x, operationStyle }) => {
} else {
dispatch(choose({ y, x }));
dispatch(select({ startY: y, startX: x, endY: -1, endX: -1 }));
_setEditorRect();
}
const valueString = table.stringify({ y, x });
dispatch(setInputting(valueString));
Expand Down
43 changes: 29 additions & 14 deletions src/components/Editor.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { createPortal } from 'react-dom';
import { x2c, y2r } from '../lib/converters';
import { clip } from '../lib/clipboard';
import {
Expand Down Expand Up @@ -28,8 +29,13 @@ import { expandInput, insertTextAtCursor } from '../lib/input';
import { useSheetContext } from './SheetProvider';
import { Lexer } from '../formula/evaluator';
import { REF_PALETTE } from '../lib/palette';
import { Mode } from '../types';

export const Editor: React.FC = () => {
type Props = {
mode?: Mode;
};

export const Editor: React.FC<Props> = ({ mode }: Props) => {
const { store, dispatch } = React.useContext(Context);

const {
Expand All @@ -46,6 +52,7 @@ export const Editor: React.FC = () => {
editingOnEnter,
onSave,
table,
sheetId,
} = store;

const [, sheetContext] = useSheetContext();
Expand Down Expand Up @@ -128,6 +135,7 @@ export const Editor: React.FC = () => {
}),
);
dispatch(setEditingCell(''));
resetSize(e.currentTarget);
return false;
// eslint-disable-next-line no-fallthrough
case 'Enter': // ENTER
Expand All @@ -144,7 +152,8 @@ export const Editor: React.FC = () => {
writeCell(input.value);
dispatch(setEditingCell(''));
}
} else if (editingOnEnter && selectingZone.startY === -1) {
resetSize(e.currentTarget);
} else if (editingOnEnter && selectingZone.endY === -1) {
const dblclick = document.createEvent('MouseEvents');
dblclick.initEvent('dblclick', true, true);
input.dispatchEvent(dblclick);
Expand Down Expand Up @@ -377,16 +386,15 @@ export const Editor: React.FC = () => {
return false;
};

return (
<div className={`gs-editor ${editing ? 'gs-editing' : ''}`} style={editing ? { top, left, height } : {}}>
return createPortal(
<div
className={`gs-editor ${editing ? 'gs-editing' : ''}`}
data-mode={mode || 'light'}
data-sheet-id={sheetId}
style={editing ? { top, left, height } : {}}
>
{showAddress && <div className="gs-cell-label">{address}</div>}
<div
className="gs-editor-inner"
style={{
minWidth: width,
width: editorRef.current?.scrollWidth ?? 0,
}}
>
<div className="gs-editor-inner" style={{ width }}>
<pre
className="gs-editor-hl"
style={{
Expand All @@ -406,17 +414,17 @@ export const Editor: React.FC = () => {
dispatch(setLastFocusedRef(editorRef));
sheetContext?.setLastFocusedRef?.(editorRef);
}}
style={{ minWidth: width }}
onDoubleClick={(e) => {
if (prevention.isPrevented(cell?.prevention, prevention.Write)) {
console.warn('This cell is protected from writing.');
return;
}
const input = e.currentTarget;
resetSize(input);
if (!editing) {
dispatch(setInputting(valueString));
dispatch(setEditingCell(address));
input.style.width = `${width}px`;
input.style.height = `${height}px`;
window.setTimeout(() => {
input.style.width = `${input.scrollWidth}px`;
input.style.height = `${input.scrollHeight}px`;
Expand All @@ -434,6 +442,7 @@ export const Editor: React.FC = () => {
writeCell(e.target.value);
}
}
resetSize(e.target);
}}
value={inputting}
onChange={(e) => {
Expand All @@ -444,7 +453,8 @@ export const Editor: React.FC = () => {
onKeyDown={handleKeyDown}
/>
</div>
</div>
</div>,
document.body,
);
};

Expand Down Expand Up @@ -488,3 +498,8 @@ export const editorStyle = (text: string) => {
</>
);
};

const resetSize = (input: HTMLTextAreaElement) => {
input.style.width = '0px';
input.style.height = '0px';
};
8 changes: 3 additions & 5 deletions src/components/FormulaBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,12 @@ export const FormulaBar: React.FC = () => {
return;
}
hlRef.current.style.height = `${largeEditorRef.current.clientHeight}px`;
hlRef.current.scrollLeft = largeEditorRef.current!.scrollLeft;
hlRef.current.scrollTop = largeEditorRef.current!.scrollTop;
hlRef.current.scrollLeft = largeEditorRef.current.scrollLeft;
hlRef.current.scrollTop = largeEditorRef.current.scrollTop;
};

return (
<label
className="gs-formula-bar"
>
<label className="gs-formula-bar">
<div className="gs-selecting-address">{address}</div>
<div className="gs-fx">Fx</div>
<div className="gs-formula-bar-editor-inner">
Expand Down
4 changes: 3 additions & 1 deletion src/components/GridSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { functions } from '../formula/mapping';
import { Context } from '../store';
import { reducer as defaultReducer } from '../store/actions';

import { Editor } from './Editor';
import { StoreInitializer } from './StoreInitializer';
import { Resizer } from './Resizer';
import { Emitter } from './Emitter';
Expand Down Expand Up @@ -171,7 +172,7 @@ export function GridSheet({
const { onChange, onSelect, mode } = options;
return (
<Context.Provider value={{ store, dispatch }}>
<div className={`gs-root1`} data-sheet-name={sheetName} data-theme={mode || 'light'}>
<div className={`gs-root1`} data-sheet-name={sheetName} data-mode={mode || 'light'}>
{showFormulaBar && <FormulaBar />}
<div
className={`gs-main ${className || ''}`}
Expand All @@ -183,6 +184,7 @@ export function GridSheet({
resize: sheetResize,
}}
>
<Editor mode={mode} />
<Tabular tableRef={tableRef} />
<StoreInitializer
initialCells={initialData}
Expand Down
3 changes: 1 addition & 2 deletions src/components/Tabular.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Editor } from './Editor';

import { Cell } from './Cell';
import { HeaderCellTop } from './HeaderCellTop';
import { HeaderCellLeft } from './HeaderCellLeft';
Expand Down Expand Up @@ -100,7 +100,6 @@ export const Tabular = ({ tableRef }: Props) => {

return (
<>
<Editor />
<SearchBox />
<div
className="gs-tabular"
Expand Down
Loading

0 comments on commit 717838d

Please sign in to comment.