Skip to content

Commit

Permalink
feat(MessageItem): better editing experience (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
mstephen19 authored Jul 30, 2024
2 parents 46d8901 + fab9ba6 commit ed070d9
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 19 deletions.
6 changes: 4 additions & 2 deletions src/popup/Accordions/MessageSequencer/AddMessageBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,13 @@ export const AddMessageBox = () => {
label='Message Content'
placeholder='Hello, how are you?'
onKeyDown={(e) => {
if (!appData.addMessageText.trim()) return;

// Allow pressing Enter + Shift to create new lines.
if (!loading && e.key === 'Enter' && !e.shiftKey && appData.addMessageText.trim()) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();

handleAddMessage(appData.addMessageText);
if (!loading) handleAddMessage(appData.addMessageText);
}
}}
value={inputText}
Expand Down
53 changes: 37 additions & 16 deletions src/popup/Accordions/MessageSequencer/MessageItem.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IconButton, List, ListItem, ListItemProps, ListItemText, TextField, Tooltip, styled } from '@mui/material';
import React, { useEffect, useState, useContext, createContext } from 'react';
import { IconButton, ListItem, ListItemProps, ListItemText, Tooltip, styled } from '@mui/material';
import { useState, useContext } from 'react';
import DeleteIcon from '@mui/icons-material/Delete';
import EditOffIcon from '@mui/icons-material/EditOff';
import { messageStore } from '../../../storage';
import { sanitize } from '../../../utils';
import { MessageSequenceContext } from '../../context/MessageSequenceProvider';
Expand All @@ -24,55 +25,75 @@ export const MessageItem = ({ message, ...props }: { message: Message } & ListIt
/**
* Optionally pass a replacement {@link Message} to delete & replace.
*/
const handleDelete = async (updated?: Partial<Message>) => {
const handleUpdate = async (updated?: Partial<Message>) => {
const index = messages.findIndex(({ id }) => id === message.id);
if (index === -1) return;

setLoading(true);

const clone = [...messages];

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

// Rewrite the entire message list
await messageStore.write(clone);

setLoading(false);
};

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

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

handleDelete({ content: sanitize(editedText) });
handleUpdate({ content: sanitize(editedText) });
}
}}
contentEditable={editing}
// Unable to double-click to edit during loading
onDoubleClick={() => !loading && setEditing(true)}
onDoubleClick={() => {
if (!loading) {
setEditing(true);
}
}}
ref={(elem) => {
if (editing) (elem as HTMLDivElement)?.focus();
}}
sx={{
flex: 1,
wordWrap: 'break-word',
userSelect: 'none',
whiteSpace: 'pre-wrap',
}}
/>

<Tooltip title='Remove' arrow>
<Tooltip title={editing ? 'Cancel' : 'Delete'} arrow>
<span>
<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={() => handleDelete()}>
<DeleteIcon />
</IconButton>
{editing ? (
<IconButton sx={{ alignSelf: 'start' }} onClick={() => setEditing(false)}>
<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>
)}
</span>
</Tooltip>
</MessageListItem>
Expand Down
2 changes: 1 addition & 1 deletion src/popup/Accordions/MessageSequencer/MessageList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const MessageList = () => {

handleRearrange(+e.dataTransfer.getData('text/plain'), +e.currentTarget.dataset.index!);
}}
draggable={!loading}
draggable={!loading && messages.length > 1}
key={`message-${message.id}`}
message={message}
// Display divider only for the final item
Expand Down

0 comments on commit ed070d9

Please sign in to comment.