import { computed, Default, handler, NAME, pattern, type PerSession, type PerSpace, type PerUser, Stream, UI, type VNode, Writable, } from "commonfabric"; /** * A chat whose names and messages are typed into draft cells and committed by * separate events — fixture for the multi-runtime tests of drafts * (`cellset-lww.test.ts`, `drafted-chat-chained-event-gate-multi-runtime.test.ts`, * `drafted-chat-scopes-multi-runtime.test.ts`). * * A draft is written by one event and read by the event that commits it, so * the pair races across streams. The profile save writes the trimmed name back * into its draft, a handler echo standing on the document the next typed name * is written to. A send reads its draft, skips an empty one, and clears it. * `sessionDraft` is the one draft scoped to a session rather than a user. */ type DraftCell = Writable>; export interface ChatMessage { body: string; } type MessagesCell = Writable>; export interface DraftedChatInput { profileDraft?: PerUser; profileName?: PerUser; messageDraft?: PerUser; sessionDraft?: PerSession; messages?: PerSpace; } export interface DraftedChatOutput { [NAME]: string; [UI]: VNode; profileDraft: PerUser; messageDraft: PerUser; sessionDraft: PerSession; messages: PerSpace; currentProfileName: string; setProfileDraft: Stream; setMessageDraft: Stream; setSessionDraft: Stream; saveProfile: Stream; sendMessage: Stream; } const writeDraft = handler( (text, { draft }) => { draft.set(text); }, ); const saveProfile = handler((_, { profileDraft, profileName }) => { const name = (profileDraft.get() ?? "").trim(); if (!name) return; profileName.set(name); profileDraft.set(name); }); const sendMessage = handler((_, { messageDraft, messages }) => { const body = (messageDraft.get() ?? "").trim(); if (!body) return; messages.push({ body }); messageDraft.set(""); }); export default pattern( ({ profileDraft, profileName, messageDraft, sessionDraft, messages }) => { const profileDraftCell: DraftCell = profileDraft!; const profileNameCell: DraftCell = profileName!; const messageDraftCell: DraftCell = messageDraft!; const sessionDraftCell: DraftCell = sessionDraft!; const messagesCell: MessagesCell = messages!; return { [NAME]: "drafted chat fixture", [UI]: (
drafted chat fixture
), profileDraft: profileDraftCell as PerUser, messageDraft: messageDraftCell as PerUser, sessionDraft: sessionDraftCell as PerSession, messages: messagesCell as PerSpace, currentProfileName: computed(() => profileNameCell.get() ?? ""), setProfileDraft: writeDraft({ draft: profileDraftCell }), setMessageDraft: writeDraft({ draft: messageDraftCell }), setSessionDraft: writeDraft({ draft: sessionDraftCell }), saveProfile: saveProfile({ profileDraft: profileDraftCell, profileName: profileNameCell, }), sendMessage: sendMessage({ messageDraft: messageDraftCell, messages: messagesCell, }), }; }, );