Skip to content

Commit 436b247

Browse files
authored
Rename sandbox: Handle keyboard interactions + focus for editing (codesandbox#4024)
1 parent c104ea6 commit 436b247

File tree

3 files changed

+45
-21
lines changed

3 files changed

+45
-21
lines changed

packages/app/src/app/pages/NewDashboard/Components/SandboxCard/Menu.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Menu } from '@codesandbox/components';
44
import { sandboxUrl } from '@codesandbox/common/lib/utils/url-generator';
55
import { useHistory } from 'react-router-dom';
66

7-
export const MenuOptions = ({ sandbox, isTemplate, setEdit }) => {
7+
export const MenuOptions = ({ sandbox, isTemplate, onRename }) => {
88
const { effects, actions } = useOvermind();
99
const history = useHistory();
1010
const url = sandboxUrl({
@@ -68,7 +68,7 @@ export const MenuOptions = ({ sandbox, isTemplate, setEdit }) => {
6868
>
6969
Export {isTemplate ? 'template' : 'sandbox'}
7070
</Menu.Item>
71-
<Menu.Item onSelect={() => setEdit(true)}>Rename sandbox</Menu.Item>
71+
<Menu.Item onSelect={() => onRename()}>Rename sandbox</Menu.Item>
7272
{isTemplate ? (
7373
<Menu.Item
7474
onSelect={() => {

packages/app/src/app/pages/NewDashboard/Components/SandboxCard/index.tsx

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import React, { useState } from 'react';
1+
import React, { useState, KeyboardEvent, ChangeEvent, FormEvent } from 'react';
22
import { useHistory } from 'react-router-dom';
33
import { useOvermind } from 'app/overmind';
44
import { sandboxUrl } from '@codesandbox/common/lib/utils/url-generator';
5+
import { ESC } from '@codesandbox/common/lib/utils/keycodes';
56
import {
67
Stack,
78
Element,
@@ -26,8 +27,19 @@ export const SandboxCard = ({ sandbox, isTemplate = false, ...props }) => {
2627
alias: sandbox.alias,
2728
});
2829

29-
const editSandboxTitle = async e => {
30-
e.preventDefault();
30+
const onChange = (event: ChangeEvent<HTMLInputElement>) => {
31+
setNewName(event.target.value);
32+
};
33+
const onKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
34+
if (event.keyCode === ESC) {
35+
// Reset value and exit without saving
36+
setNewName(sandboxTitle);
37+
setEdit(false);
38+
}
39+
};
40+
41+
const onSubmit = async (event?: FormEvent<HTMLFormElement>) => {
42+
if (event) event.preventDefault();
3143
await actions.dashboard.renameSandbox({
3244
id: sandbox.id,
3345
title: newName,
@@ -36,6 +48,20 @@ export const SandboxCard = ({ sandbox, isTemplate = false, ...props }) => {
3648
setEdit(false);
3749
};
3850

51+
const onBlur = () => {
52+
// save value when you click outside or tab away
53+
onSubmit();
54+
};
55+
56+
const inputRef = React.useRef(null);
57+
const enterEditing = () => {
58+
setEdit(true);
59+
// Menu defaults to sending focus back to Menu Button
60+
// Send focus to input in the next tick
61+
// after menu is done closing.
62+
setTimeout(() => inputRef.current.focus());
63+
};
64+
3965
return (
4066
<Stack
4167
direction="vertical"
@@ -50,13 +76,13 @@ export const SandboxCard = ({ sandbox, isTemplate = false, ...props }) => {
5076
transition: 'all ease-in-out',
5177
transitionDuration: theme => theme.speeds[4],
5278
':hover, :focus, :focus-within': {
53-
cursor: 'pointer',
79+
cursor: edit ? 'normal' : 'pointer',
5480
transform: 'scale(0.98)',
5581
},
5682
})}
5783
{...props}
5884
onClick={event => {
59-
if (isMenuClicked(event)) return;
85+
if (edit || isMenuClicked(event)) return;
6086
history.push(url);
6187
}}
6288
>
@@ -73,8 +99,14 @@ export const SandboxCard = ({ sandbox, isTemplate = false, ...props }) => {
7399
/>
74100
<Stack justify="space-between" align="center" marginLeft={4}>
75101
{edit ? (
76-
<form onSubmit={editSandboxTitle}>
77-
<Input value={newName} onChange={e => setNewName(e.target.value)} />
102+
<form onSubmit={onSubmit}>
103+
<Input
104+
value={newName}
105+
ref={inputRef}
106+
onChange={onChange}
107+
onKeyDown={onKeyDown}
108+
onBlur={onBlur}
109+
/>
78110
</form>
79111
) : (
80112
<Text size={3} weight="medium">
@@ -84,7 +116,7 @@ export const SandboxCard = ({ sandbox, isTemplate = false, ...props }) => {
84116
<MenuOptions
85117
sandbox={sandbox}
86118
isTemplate={isTemplate}
87-
setEdit={setEdit}
119+
onRename={enterEditing}
88120
/>
89121
</Stack>
90122
<Stack marginX={4}>

packages/app/src/app/pages/NewDashboard/Content/routes/Search/index.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ import { useOvermind } from 'app/overmind';
44
import { sandboxesTypes } from 'app/overmind/namespaces/dashboard/state';
55
import { Loading } from 'app/pages/NewDashboard/Components/Loading';
66
import { Header } from 'app/pages/NewDashboard/Components/Header';
7-
import { Grid } from '@codesandbox/components';
7+
import { SandboxGrid } from 'app/pages/NewDashboard/Components/SandboxGrid';
88
import { Sandbox } from 'app/pages/NewDashboard/Components/Sandbox';
9-
import css from '@styled-system/css';
109
import { getPossibleTemplates } from '../../utils';
1110

1211
export const SearchComponent = ({ location }) => {
@@ -35,18 +34,11 @@ export const SearchComponent = ({ location }) => {
3534
/>
3635
<section style={{ position: 'relative' }}>
3736
{sandboxes.SEARCH ? (
38-
<Grid
39-
rowGap={6}
40-
columnGap={6}
41-
marginBottom={8}
42-
css={css({
43-
gridTemplateColumns: 'repeat(auto-fit,minmax(220px,0.2fr))',
44-
})}
45-
>
37+
<SandboxGrid>
4638
{sandboxes.SEARCH.map(sandbox => (
4739
<Sandbox key={sandbox.id} template sandbox={sandbox} />
4840
))}
49-
</Grid>
41+
</SandboxGrid>
5042
) : (
5143
<Loading />
5244
)}

0 commit comments

Comments
 (0)