Files
m3e-canvas/web/vendor/lib/host.ts
T
pastilhasandClaude Fable 5 e99b4afbf9 the vendoring machinery: one command reproduces the whole state
scripts/vendor.sh clones upstream, rewrites @/ imports to relative
paths, and applies scripts/apply-host.py. web/host.ts is ours and gets
placed into the vendored tree, because upstream declined it.

a script rather than a .patch, and that is not a preference. between
cfde698 and 5c83ac6 — one day — upstream changed an import line,
re-indented the component from 6 spaces to 8, and added an editAccess
guard. a context diff fails on all three, none of which concern us. so
every anchor matches structure with flexible whitespace and re-indents
to whatever it finds, and a missing anchor stops the run loudly.

all three prompt-export paths are wired, which is what upstream said a
complete version needs. the other two clipboard writes are ShareMenu's
share-link and ask-an-AI blurb, and the reason they are excluded is
written down so the count does not read as the same oversight twice.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-05 12:04:34 +01:00

47 lines
1.7 KiB
TypeScript

"use client";
import { createContext, useContext } from "react";
import type { Doc } from "./tokens";
/**
* Hooks for an application that embeds the editor.
*
* The editor keeps its own state and its own UI; a host only needs to say where the document is kept
* and where the prompt goes. Every field is optional and every default is what the standalone app
* already did — localStorage for the document, the clipboard for the prompt — so an editor rendered
* without a provider behaves exactly as before.
*
* ```tsx
* <HostProvider value={{ loadDoc, saveDoc, onExport: (text) => sendToAgent(text) }}>
* <Canvas />
* </HostProvider>
* ```
*/
export type HostAdapter = {
/** Return the saved document, or null for a fresh one. Omit to read localStorage. */
loadDoc?: () => Partial<Doc> | null;
/** Persist the document. Omit to write localStorage. Called on every change, so debounce if remote. */
saveDoc?: (doc: Partial<Doc>) => void;
/** Editor chrome — panel widths, favourites. Separate from the document because it is not the work. */
loadUi?: () => unknown | null;
saveUi?: (ui: unknown) => void;
/**
* Where the generated prompt goes.
*
* Return `true` to say the host has handled it and the editor should not also write the clipboard;
* anything else and the clipboard write still happens. That default matters — a host that only
* wants to observe the export does not have to reimplement copying.
*/
onExport?: (prompt: string, doc: Doc) => boolean | void;
};
const EMPTY: HostAdapter = {};
export const HostContext = createContext<HostAdapter>(EMPTY);
export const HostProvider = HostContext.Provider;
export const useHost = (): HostAdapter => useContext(HostContext);