Skip to content

Commit c2e4c32

Browse files
author
k.golikov
committed
Add js event tester
1 parent 20ecef7 commit c2e4c32

File tree

7 files changed

+139
-4
lines changed

7 files changed

+139
-4
lines changed

src/constants/router/menuItems.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ const menuItems: MenuItem[] = [
7474
{
7575
route: routes.counter
7676
},
77+
{
78+
route: routes.jsEventTester
79+
},
7780
{
7881
route: routes.jsonToYaml,
7982
title: 'JSON to YAML converter',

src/constants/router/routes.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import JsonToYamlPage from '../../pages/jsonToYamlPage/JsonToYamlPage';
3333
import CounterPage from '../../pages/counterPage/CounterPage';
3434
import RooksDemoPage from '../../pages/rooksDemoPage/RooksDemoPage';
3535
import MarkdownCheatSheetPage from '../../pages/markdownCheatSheetPage/MarkdownCheatSheetPage';
36+
import JsEventTesterPage from '../../pages/jsEventTesterPage/JsEventTesterPage';
3637

3738
export interface AppRoute extends Omit<RouteProps, 'element'> {
3839
path: string;
@@ -69,6 +70,7 @@ type AppRoutesMap = Readonly<{
6970
dataUrlView: AppRoute;
7071
counter: AppRoute;
7172
rooksDemo: AppRoute;
73+
jsEventTester: AppRoute;
7274
markdownCheatSheet: AppRoute;
7375
settings: AppRoute;
7476
about: AppRoute;
@@ -206,6 +208,11 @@ export const routes: AppRoutesMap = {
206208
component: CounterPage,
207209
title: 'Counter'
208210
},
211+
jsEventTester: {
212+
path: '/tools/js-event-tester',
213+
component: JsEventTesterPage,
214+
title: 'JS Event Tester'
215+
},
209216
rooksDemo: {
210217
path: '/other/rooks-demo',
211218
component: RooksDemoPage,

src/layouts/appLayout/components/appHeader/components/appHeaderSearch/AppHeaderSearch.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const AppHeaderSearch: FunctionComponent<Props> = ({ className, inputClassName,
9494
[selectOption, query]
9595
);
9696

97-
useKey(['/'], (event) => {
97+
useKey(['Slash'], (event) => {
9898
const activeTag = document.activeElement?.tagName;
9999
if (activeTag && ['input', 'textarea'].includes(activeTag)) {
100100
return;

src/layouts/pages/pageContainer/PageContainer.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { FunctionComponent, ReactNode, useMemo } from 'react';
1+
import React, { ReactNode, useMemo } from 'react';
22
import styles from './PageContainer.module.scss';
33
import { Space, SpaceProps, Tag } from 'antd';
44
import Paragraph from 'antd/lib/typography/Paragraph';
@@ -35,7 +35,7 @@ const getTagNodes = (key: number | string): Readonly<Record<PageTag, ReactNode>>
3535

3636
const renderTag = (tag: PageTag, index: number) => getTagNodes(index)[tag];
3737

38-
const PageContainer: FunctionComponent<PageContainerProps> = (props) => {
38+
const PageContainer = React.forwardRef<HTMLDivElement, PageContainerProps>((props, ref) => {
3939
const {
4040
title,
4141
description,
@@ -53,6 +53,7 @@ const PageContainer: FunctionComponent<PageContainerProps> = (props) => {
5353

5454
return (
5555
<div
56+
ref={ref}
5657
className={classNames(
5758
styles.container,
5859
{
@@ -75,6 +76,6 @@ const PageContainer: FunctionComponent<PageContainerProps> = (props) => {
7576
<div className={classNames(styles.contentContainer, contentClassName)}>{children}</div>
7677
</div>
7778
);
78-
};
79+
});
7980

8081
export default PageContainer;

src/pages/jsEventTesterPage/JsEventTesterPage.module.scss

Whitespace-only changes.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import React, { FunctionComponent, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2+
import PageContainer from '../../layouts/pages/pageContainer/PageContainer';
3+
import Flex from '../../components/flex/Flex';
4+
import { Tabs } from 'antd';
5+
import Text from 'antd/lib/typography/Text';
6+
import joinObjects from '../../utils/joinObjects';
7+
8+
const JsEventTesterPage: FunctionComponent = () => {
9+
const [lastKeyDownEvent, setLastKeyDownEvent] = useState<KeyboardEvent>();
10+
11+
const containerRef = useRef<HTMLDivElement>(null);
12+
13+
const pressedModifiers = useMemo<ReactNode[]>(() => {
14+
if (!lastKeyDownEvent) {
15+
return [];
16+
}
17+
18+
return [
19+
lastKeyDownEvent.ctrlKey && (
20+
<Text keyboard key="modifier-ctrl">
21+
Ctrl
22+
</Text>
23+
),
24+
lastKeyDownEvent.altKey && (
25+
<Text keyboard key="modifier-alt">
26+
Alt
27+
</Text>
28+
),
29+
lastKeyDownEvent.shiftKey && (
30+
<Text keyboard key="modifier-shift">
31+
Shift
32+
</Text>
33+
),
34+
lastKeyDownEvent.metaKey && (
35+
<Text keyboard key="modifier-meta">
36+
Win
37+
</Text>
38+
)
39+
].filter(Boolean);
40+
}, [lastKeyDownEvent]);
41+
42+
const pressedShortcut = useMemo<ReactNode[]>(() => {
43+
if (!lastKeyDownEvent) {
44+
return [];
45+
}
46+
47+
return [
48+
...pressedModifiers,
49+
lastKeyDownEvent.location !== 1 && lastKeyDownEvent.location !== 2 && (
50+
<Text keyboard key="pressed-key">
51+
{lastKeyDownEvent.key.toUpperCase()}
52+
</Text>
53+
)
54+
].filter(Boolean);
55+
}, [pressedModifiers, lastKeyDownEvent]);
56+
57+
const handleKeyDown = useCallback((event: KeyboardEvent) => {
58+
event.stopImmediatePropagation();
59+
60+
console.log('keydown', event);
61+
setLastKeyDownEvent(event);
62+
}, []);
63+
64+
useEffect(() => {
65+
window.addEventListener('keydown', handleKeyDown);
66+
67+
return () => {
68+
window.removeEventListener('keydown', handleKeyDown);
69+
};
70+
}, [handleKeyDown]);
71+
72+
return (
73+
<PageContainer ref={containerRef} title="JavaScript Event Tester" tabIndex={-1}>
74+
<Flex column maxWidth="800px">
75+
<Tabs>
76+
<Tabs.TabPane tab="keydown">
77+
<Flex column>
78+
{lastKeyDownEvent ? (
79+
<Text className="fs-6">
80+
<Flex column gap={5}>
81+
<Text strong className="fs-5">
82+
{joinObjects(pressedShortcut, <>+</>)}
83+
</Text>
84+
<div>
85+
<Text code>event.key</Text>: <Text keyboard>{lastKeyDownEvent.key}</Text>
86+
</div>
87+
<div>
88+
<Text code>event.code</Text>: <Text keyboard>{lastKeyDownEvent.code}</Text>
89+
</div>
90+
<div>
91+
<Text code>event.which</Text>:{' '}
92+
<Text keyboard>{lastKeyDownEvent.which}</Text>
93+
</div>
94+
<div>
95+
<Text code>modifiers</Text>: {pressedModifiers}
96+
</div>
97+
</Flex>
98+
</Text>
99+
) : (
100+
<Flex column gap={8}>
101+
<Text strong>Press any key</Text>
102+
</Flex>
103+
)}
104+
</Flex>
105+
</Tabs.TabPane>
106+
</Tabs>
107+
</Flex>
108+
</PageContainer>
109+
);
110+
};
111+
112+
export default JsEventTesterPage;

src/utils/joinObjects.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const joinObjects = <T, S>(items: T[], separator: S): Array<T | S> => {
2+
return items.reduce<Array<T | S>>((result, value, index) => {
3+
if (index !== 0) {
4+
result.push(separator);
5+
}
6+
7+
result.push(value);
8+
return result;
9+
}, []);
10+
};
11+
12+
export default joinObjects;

0 commit comments

Comments
 (0)