Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add List view for apps as default #690

Merged
merged 25 commits into from
Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
823794f
Make inputProps controllable
bharatkashyap Jul 25, 2022
0a667bf
Use only `TextField` for better abstraction
bharatkashyap Jul 29, 2022
d7b96fd
Add Tabs and ToggleButtonGroup
bharatkashyap Jul 29, 2022
1c632b8
Toggle ToggleButton colour
bharatkashyap Jul 29, 2022
bff3b48
Add apps list table
bharatkashyap Jul 29, 2022
5fbabc3
Merge branch 'app-card-rename' into home-ui
bharatkashyap Jul 29, 2022
b45f0c0
Use EditableText for apps list, disableTooltip
bharatkashyap Jul 29, 2022
315d949
Further purify EditableText
bharatkashyap Jul 30, 2022
6c1180f
Reuse components for list, grid
bharatkashyap Jul 30, 2022
9032375
Fix hydration issues due to TableRow not rendering
bharatkashyap Jul 31, 2022
44fa3cd
Merge branch 'master' of github.com:mui/mui-toolpad into app-card-rename
bharatkashyap Jul 31, 2022
42700d3
Modify smoke test
bharatkashyap Jul 31, 2022
f7f00df
Smoke tests, remove typo in duration text
bharatkashyap Jul 31, 2022
af88666
Pass `inputProps` to underlying input
bharatkashyap Jul 31, 2022
420ece5
Disallow click to edit for App name
bharatkashyap Jul 31, 2022
bdd5959
modify smoke tests for list view
bharatkashyap Jul 31, 2022
f37f824
Make comment more explanatory
bharatkashyap Aug 1, 2022
c969b93
Leaner interface for EditableText
bharatkashyap Aug 1, 2022
43b136e
Smoke tests closer to original
bharatkashyap Aug 1, 2022
5f063cc
Abstract disabling styles
bharatkashyap Aug 2, 2022
2c28c6d
Use standard adjective form for state prop
bharatkashyap Aug 3, 2022
2278014
Use `TabContext`, create common `AppView` component
bharatkashyap Aug 5, 2022
9970d94
Fix naming
bharatkashyap Aug 5, 2022
4f14e24
Remove Tabs from the scope of this PR
bharatkashyap Aug 8, 2022
5ceff71
Merge branch 'master' into app-card-rename
Janpot Aug 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 136 additions & 25 deletions packages/toolpad-app/src/components/EditableText.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,150 @@
import * as React from 'react';
import { Skeleton, TextField, Typography, TypographyVariant, Tooltip } from '@mui/material';
import { TextField, Theme, TypographyVariant, SxProps } from '@mui/material';

interface EditableTextProps {
defaultValue?: string;
loading: boolean;
editing: boolean;
isError: boolean;
errorText?: string;
onKeyUp: (event: React.KeyboardEvent<HTMLInputElement>) => void;
onBlur: (event: React.FocusEvent<HTMLInputElement>) => void;
variant?: TypographyVariant;
disabled?: boolean;
editable?: boolean;
helperText?: React.ReactNode;
error?: boolean;
onChange?: (newValue: string) => void;
onSave?: (newValue: string) => void;
onClose?: () => void;
size?: 'small' | 'medium';
sx?: SxProps;
value?: string;
variant?: TypographyVariant;
}

const EditableText = React.forwardRef<HTMLInputElement, EditableTextProps>(
({ defaultValue, onKeyUp, onBlur, variant, size, editing, loading, isError, errorText }, ref) => {
return editing ? (
(
{
defaultValue,
disabled,
editable,
helperText,
error,
onChange,
onClose,
onSave,
size,
sx,
value,
variant: typographyVariant = 'body1',
},
ref,
) => {
const appTitleInput = React.useRef<HTMLInputElement | null>(null);

React.useEffect(() => {
let inputElement: HTMLInputElement | null = appTitleInput.current;
if (ref) {
inputElement = (ref as React.MutableRefObject<HTMLInputElement>).current;
}
if (inputElement) {
if (editable) {
inputElement.focus();
inputElement.select();
} else {
inputElement.blur();
}
}
}, [ref, editable]);

const handleBlur = React.useCallback(
(event: React.FocusEvent<HTMLInputElement>) => {
// This is only triggered on a click away
if (onClose) {
onClose();
}
if (onSave && event.target) {
onSave(event.target.value);
}
},
[onClose, onSave],
);

const handleChange = React.useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
if (onChange) {
onChange(event.target.value);
}
},
[onChange],
);

const handleInput = React.useCallback(
(event: React.KeyboardEvent<HTMLInputElement>) => {
let inputElement: HTMLInputElement | null = appTitleInput.current;
if (ref) {
inputElement = (ref as React.MutableRefObject<HTMLInputElement>).current;
}
if (inputElement) {
if (event.key === 'Escape') {
if (defaultValue) {
if (onChange) {
onChange(defaultValue);
}
}
if (onClose) {
onClose();
}
return;
}
if (event.key === 'Enter') {
if (onClose) {
onClose();
}
if (onSave) {
onSave((event.target as HTMLInputElement).value);
}
}
}
},
[defaultValue, onChange, onSave, onClose, ref],
);

return (
<TextField
variant={'standard'}
// `disabled` prop overrides `editable` prop
disabled={disabled || !editable}
error={error}
helperText={helperText}
inputRef={ref ?? appTitleInput}
inputProps={{
tabIndex: editable ? 0 : -1,
'aria-readonly': !editable,
sx: (theme: Theme) => ({
// Handle overflow
textOverflow: 'ellipsis',
overflow: 'hidden',
whiteSpace: 'nowrap',
fontSize: theme.typography[typographyVariant].fontSize,
height: theme.typography[typographyVariant].fontSize,
}),
}}
onKeyUp={handleInput}
onBlur={handleBlur}
onChange={handleChange}
size={size ?? 'small'}
inputRef={ref}
sx={{ paddingBottom: '4px' }}
InputProps={{ sx: { fontSize: '1.5rem', height: '1.5em' } }}
onKeyUp={onKeyUp ?? (() => {})}
onBlur={onBlur ?? (() => {})}
defaultValue={defaultValue}
error={isError}
helperText={isError ? errorText : ''}
sx={{
...sx,
'& .MuiInputBase-root.MuiInput-root:before, .MuiInput-root.MuiInputBase-root:not(.Mui-disabled):hover::before':
{
borderBottom: editable ? `initial` : 'none',
},
// TextField must not appear disabled if disabled state is controlled by `editable` prop
'& .MuiInput-root.MuiInputBase-root.Mui-disabled, .MuiInput-input.MuiInputBase-input.Mui-disabled, .MuiInput-root.MuiFormHelperText-root.Mui-disabled':
disabled
? null
: {
WebkitTextFillColor: 'unset',
color: 'unset',
},
}}
value={value}
variant={'standard'}
/>
) : (
<Tooltip title={defaultValue || ''} enterDelay={500}>
<Typography gutterBottom variant={variant ?? 'body1'} component="div" noWrap>
{loading ? <Skeleton /> : defaultValue}
</Typography>
</Tooltip>
);
},
);
Expand Down
Loading