Files
llink/js/desktop/src/features/particles/text-edit-overlay.tsx
T
Arjun PatelandGitHub a8a0b7db1b infra: add linting and formatting for js projects (#230)
* wip

* wip

* wip

* format

* wip(mobile): lint and format

* cleanup

* nits

* nits

* idiomatic react

* nit

* format all root files
2026-06-02 07:44:24 -07:00

79 lines
2.2 KiB
TypeScript

import { useCallback, useState } from 'react';
import { createPortal } from 'react-dom';
import { toast } from 'sonner';
import type { Particle } from '@/api/types';
import {
particlePath,
parseParticlePath,
toFirestoreDocPath,
type ParticlePath,
} from '@/lib/particle-path';
import { editTextParticleContent } from '@/lib/firestore-particles';
import { TextEditor } from '@/features/compose/text-editor';
import { useSuspendPlayback } from '@/hooks/use-suspend-playback';
type TextParticle = Extract<Particle, { type: 'text' }>;
interface TextEditOverlayProps {
particle: TextParticle;
streamPath: ParticlePath;
onClose: () => void;
}
export function TextEditOverlay({
particle,
streamPath,
onClose,
}: TextEditOverlayProps) {
useSuspendPlayback(true, 'text-edit');
const [textContent, setTextContent] = useState(particle.properties.content);
const [saving, setSaving] = useState(false);
const handleSubmit = useCallback(async () => {
if (saving) return;
const trimmed = textContent.trim();
if (!trimmed) return;
if (trimmed === particle.properties.content) {
onClose();
return;
}
setSaving(true);
try {
const { networkId, segments } = parseParticlePath(streamPath);
const docPath = toFirestoreDocPath(
particlePath(networkId, [...segments, particle.id]),
);
await editTextParticleContent(docPath, trimmed);
onClose();
} catch (err) {
toast.error(err instanceof Error ? err.message : 'Failed to save');
setSaving(false);
}
}, [
saving,
textContent,
particle.properties.content,
particle.id,
streamPath,
onClose,
]);
return createPortal(
// React synthetic events bubble through the React tree (not the DOM tree),
// so clicks here would reach stream-view's click-to-navigate handler even
// though we're portaled to document.body. Stop propagation at the root.
<div className="fixed inset-0 z-[100]" onClick={(e) => e.stopPropagation()}>
<TextEditor
textContent={textContent}
onTextChange={setTextContent}
onSubmit={handleSubmit}
onCancel={onClose}
submitHint="save"
/>
</div>,
document.body,
);
}