Skip to content

Commit

Permalink
fix(MessageItem): no validation when editing
Browse files Browse the repository at this point in the history
  • Loading branch information
mstephen19 committed Jul 31, 2024
1 parent 1944197 commit 466cd0e
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 21 deletions.
6 changes: 1 addition & 5 deletions src/popup/Accordions/MessageSequencer/AddMessageBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,7 @@ export const AddMessageBox = () => {
const content = sanitize(unsanitized);

// If tags are detected in the string (e.g. {spin}{/spin}), runs validation.
const ok = transforms.run(content).ok;

console.log(ok);

if (!ok) {
if (!transforms.run(content).ok) {
setValidationError(`Syntax error!`);
setLoading(false);
return;
Expand Down
60 changes: 44 additions & 16 deletions src/popup/Accordions/MessageSequencer/MessageItem.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IconButton, ListItem, ListItemProps, ListItemText, Tooltip, styled } from '@mui/material';
import { useState, useContext } from 'react';
import { useState, useContext, useRef, useEffect } from 'react';
import DeleteIcon from '@mui/icons-material/Delete';
import EditOffIcon from '@mui/icons-material/EditOff';
import { messageStore } from '../../../storage';
Expand All @@ -8,6 +8,7 @@ import { MessageSequenceContext } from '../../context/MessageSequenceProvider';

import type { Message } from '../../../types';
import { TabDataContext } from '../../context/TabProvider';
import { transforms } from '../../../transforms';

const MessageListItem = styled(ListItem)({
display: 'flex',
Expand All @@ -20,12 +21,22 @@ export const MessageItem = ({ message, ...props }: { message: Message } & ListIt

const messages = useContext(MessageSequenceContext);
const [editing, setEditing] = useState(false);
const [validationError, setValidationError] = useState('');

const [loading, setLoading] = useState(false);

/**
* Optionally pass a replacement {@link Message} to delete & replace.
*/
const handleUpdate = async (updated?: Partial<Message>) => {
const handleUpdate = async (updated?: string) => {
if (updated && !transforms.run(updated).ok) {
setValidationError('Syntax error!');
return;
}

setValidationError('');
setEditing(false);

const index = messages.findIndex(({ id }) => id === message.id);
if (index === -1) return;

Expand All @@ -34,7 +45,7 @@ export const MessageItem = ({ message, ...props }: { message: Message } & ListIt
const clone = [...messages];

// Replace the current message item with the updated one
if (updated) clone.splice(index, 1, { ...clone[index], ...updated });
if (updated) clone.splice(index, 1, { ...clone[index], content: sanitize(updated) });
// Or remove the item entirely
else clone.splice(index, 1);

Expand All @@ -44,35 +55,46 @@ export const MessageItem = ({ message, ...props }: { message: Message } & ListIt
setLoading(false);
};

const contentRef = useRef<HTMLDivElement>(null);

useEffect(() => {
const target = contentRef.current?.querySelector('.MuiListItemText-primary');

if (editing && target && document.activeElement !== target) {
(target as HTMLParagraphElement).focus();
moveCursorToEnd(target);
}
}, [editing]);

return (
<MessageListItem {...props} selected={editing}>
<ListItemText
primary={message.content}
secondary={validationError}
onKeyDown={(e) => {
const editedText = (e.target as HTMLSpanElement).textContent || '';
const editedText = (e.target as HTMLParagraphElement).textContent || '';
if (!editing || !editedText.trim()) return;

// Enter + Shift for new lines
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
setEditing(false);

handleUpdate({ content: sanitize(editedText) });
handleUpdate(editedText);
}
}}
contentEditable={editing}
primaryTypographyProps={{
contentEditable: editing,
}}
secondaryTypographyProps={{
color: 'error',
}}
// Unable to double-click to edit during loading
onDoubleClick={() => {
if (!loading) {
setEditing(true);
}
}}
ref={(elem: HTMLDivElement) => {
if (editing && elem && document.activeElement !== elem) {
elem.focus();
moveCursorToEnd(elem);
}
}}
ref={contentRef}
sx={{
flex: 1,
wordWrap: 'break-word',
Expand All @@ -82,17 +104,23 @@ export const MessageItem = ({ message, ...props }: { message: Message } & ListIt
/>

<Tooltip title={editing ? 'Cancel' : 'Delete'} arrow>
<span>
<span style={{ alignSelf: 'start' }}>
{editing ? (
<IconButton sx={{ alignSelf: 'start' }} onClick={() => setEditing(false)}>
<IconButton
onClick={() => {
setEditing(false);
setValidationError('');

const target = contentRef.current?.querySelector('.MuiListItemText-primary');
if (target) target.textContent = message.content;
}}>
<EditOffIcon />
</IconButton>
) : (
<IconButton
// ? Disallow deleting the last message in the sequence realtime if
// ? it's the last one.
disabled={loading || (running && messages.length === 1)}
sx={{ alignSelf: 'start' }}
onClick={() => handleUpdate()}>
<DeleteIcon />
</IconButton>
Expand Down

0 comments on commit 466cd0e

Please sign in to comment.