Skip to content

Commit

Permalink
implement keyboard shortcuts prop
Browse files Browse the repository at this point in the history
  • Loading branch information
radubrehar committed May 20, 2024
1 parent dd3a41d commit 0265347
Show file tree
Hide file tree
Showing 19 changed files with 879 additions and 19 deletions.
47 changes: 47 additions & 0 deletions examples/src/pages/tests/hotkey/default.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
eventToKeyDescriptor,
keyboardShortcutBinding,
} from '@src/components/utils/hotkey';
import * as React from 'react';

(globalThis as any).combinations = {};

const fn = (e: React.KeyboardEvent) => {
const key = eventToKeyDescriptor(e);
console.log(e.key);
(globalThis as any).combinations[key] =
(globalThis as any).combinations[key] || 0;
(globalThis as any).combinations[key]++;
};
function App() {
React.useEffect(() => {
const callback = keyboardShortcutBinding(
[
'ctrl+shift+i',
'a',
'b',
'c',
'd',
'cmd+t',
'cmd+e',
'alt+shift+x',
'shift+alt+y',
'alt+*',
'alt+shift+*',
'escape',
'*',
],
fn,
);
//@ts-ignore
document.documentElement.addEventListener('keydown', callback);
}, []);

return (
<>
<input type="text" defaultValue="x" />
</>
);
}

export default App;
37 changes: 37 additions & 0 deletions examples/src/pages/tests/hotkey/default.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { test, expect } from '@testing';

export default test.describe('Keyboard shortcuts', () => {
test('should work', async ({ page }) => {
await page.load();
const getCombinations = async () => {
return await page.evaluate(() => (globalThis as any).combinations);
};

await page.keyboard.press('Control+Shift+i');
await page.keyboard.press('a');
await page.keyboard.press('b');
await page.keyboard.press('Meta+b');
await page.keyboard.press('Meta+t');
await page.keyboard.press('t');
await page.keyboard.press('Alt+Shift+x');
await page.keyboard.press('Alt+Shift+y');
await page.keyboard.press('Meta+e');
await page.keyboard.press('e');
await page.keyboard.press('Escape');

expect(await getCombinations()).toEqual({
'ctrl+shift+i': 1,
a: 1,
b: 1,
'cmd+t': 1,
alt: 2,
t: 1,
'alt+shift': 2,
'alt+shift+x': 1,
'alt+shift+y': 1,
'cmd+e': 1,
e: 1,
escape: 1,
});
});
});
128 changes: 128 additions & 0 deletions examples/src/pages/tests/table/props/data/edit-with-delay.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import * as React from 'react';

import {
InfiniteTable,
InfiniteTablePropColumns,
} from '@infinite-table/infinite-react';
import { DataSource } from '@infinite-table/infinite-react';

type Developer = {
id: number;

firstName: string;
lastName: string;

currency: string;
preferredLanguage: string;
stack: string;
canDesign: 'yes' | 'no';
salary: string;

age: number;
};

const data: Developer[] = [
{
id: 1,
firstName: 'John',
lastName: 'Bob',
age: 20,
canDesign: 'yes',
currency: 'USD',
preferredLanguage: 'JavaScript',
stack: 'frontend',
salary: '$ 1000',
},
{
id: 2,
firstName: 'Marry',
lastName: 'Bob',
age: 25,
canDesign: 'yes',
currency: 'USD',
preferredLanguage: 'JavaScript',
stack: 'frontend',
salary: '$ 11000',
},
{
id: 3,
firstName: 'Bill',
lastName: 'Bobson',
age: 30,
canDesign: 'no',
currency: 'CAD',
preferredLanguage: 'TypeScript',
stack: 'frontend',
salary: '$ 12000',
},
{
id: 4,
firstName: 'Mark',
lastName: 'Twain',
age: 31,
canDesign: 'yes',
currency: 'CAD',
preferredLanguage: 'Rust',
stack: 'backend',
salary: '£ 21000',
},
{
id: 5,
firstName: 'Matthew',
lastName: 'Hilson',
age: 29,
canDesign: 'yes',
currency: 'CAD',
preferredLanguage: 'Go',
stack: 'backend',
salary: '£ 9000',
},
];

const columns: InfiniteTablePropColumns<Developer> = {
id: {
field: 'id',
},
firstName: {
field: 'firstName',
defaultEditable: (params) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(params.rawValue !== 'John');
}, 1000);
});
},
},
age: {
field: 'age',
type: 'number',
},
salary: {
field: 'salary',
},

stack: { field: 'stack', renderMenuIcon: false },
currency: { field: 'currency' },
};

export default () => {
return (
<>
<React.StrictMode>
<DataSource<Developer> data={data} primaryKey="id">
<InfiniteTable<Developer>
domProps={{
style: {
height: '100%',
},
}}
keyboardNavigation="cell"
columnDefaultEditable
columnDefaultWidth={150}
columns={columns}
/>
</DataSource>
</React.StrictMode>
</>
);
};
42 changes: 42 additions & 0 deletions examples/src/pages/tests/table/props/data/edit-with-delay.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { test, expect } from '@testing';

export default test.describe
.parallel('Immediate edit works on lazy editable columns', () => {
test('on string column', async ({ page, rowModel }) => {
await page.waitForInfinite();
const editor = page.locator('input');
const cell = {
colId: 'firstName',
rowIndex: 0,
};
await rowModel.clickCell(cell);
await page.keyboard.press('Enter');

await page.waitForTimeout(1100);
// expect the edit to not be open
expect(await editor.count()).toBe(0);

const cell2 = {
colId: 'firstName',
rowIndex: 1,
};
await rowModel.clickCell(cell2);
const initialText = await rowModel.getTextForCell(cell2);
await page.keyboard.press('Enter');

await editor.waitFor({
state: 'visible',
});

await page.keyboard.type('atest');
await page.keyboard.press('Enter');
await page.waitForTimeout(50);
const text = await rowModel.getTextForCell(cell2);
expect(text).toEqual(`${initialText}atest`);
expect(await editor.count()).toBe(0);

// just wait a bit more to make sure the editor is not showing again
await page.waitForTimeout(1150);
expect(await editor.count()).toBe(0);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import * as React from 'react';

import {
InfiniteTable,
InfiniteTablePropColumns,
keyboardShortcuts,
} from '@infinite-table/infinite-react';
import { DataSource } from '@infinite-table/infinite-react';

type Developer = {
id: number;

firstName: string;
lastName: string;

currency: string;
preferredLanguage: string;
stack: string;
canDesign: 'yes' | 'no';
salary: string;

age: number;
};

const data: Developer[] = [
{
id: 1,
firstName: 'John',
lastName: 'Bob',
age: 20,
canDesign: 'yes',
currency: 'USD',
preferredLanguage: 'JavaScript',
stack: 'frontend',
salary: '$ 1000',
},
{
id: 2,
firstName: 'Marry',
lastName: 'Bob',
age: 25,
canDesign: 'yes',
currency: 'USD',
preferredLanguage: 'JavaScript',
stack: 'frontend',
salary: '$ 11000',
},
{
id: 3,
firstName: 'Bill',
lastName: 'Bobson',
age: 30,
canDesign: 'no',
currency: 'CAD',
preferredLanguage: 'TypeScript',
stack: 'frontend',
salary: '$ 12000',
},
{
id: 4,
firstName: 'Mark',
lastName: 'Twain',
age: 31,
canDesign: 'yes',
currency: 'CAD',
preferredLanguage: 'Rust',
stack: 'backend',
salary: '£ 21000',
},
{
id: 5,
firstName: 'Matthew',
lastName: 'Hilson',
age: 29,
canDesign: 'yes',
currency: 'CAD',
preferredLanguage: 'Go',
stack: 'backend',
salary: '£ 9000',
},
];

const columns: InfiniteTablePropColumns<Developer> = {
id: {
field: 'id',
},
firstName: {
field: 'firstName',
defaultEditable: (params) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(params.rawValue !== 'John');
}, 100);
});
},
},
age: {
field: 'age',
type: 'number',
},
salary: {
field: 'salary',
},

stack: { field: 'stack', renderMenuIcon: false },
currency: { field: 'currency' },
};

export default () => {
return (
<>
<React.StrictMode>
<DataSource<Developer> data={data} primaryKey="id">
<InfiniteTable<Developer>
domProps={{
style: {
height: '100%',
},
}}
keyboardShortcuts={[keyboardShortcuts.instantEdit]}
keyboardNavigation="cell"
columnDefaultEditable
columnDefaultWidth={150}
columns={columns}
/>
</DataSource>
</React.StrictMode>
</>
);
};
Loading

0 comments on commit 0265347

Please sign in to comment.