/** * An app URL in a document reads as the chip of what it names — SPEC §13.3, * "A reference's card", and §7.7. * * The URL stays the URL: the chip is the `reference` node with `href` set (a * URL chip, `ReferenceNode`), which a document writes back as the URL it was, * plain text with no card and a `link` mark with one. Never a `nostr:` * reference in its place: the URL is how a person addresses the object. * * What a URL names is the app's to say — its manifests and its relay — so the * app hands this extension two functions: `referenceOf`, what it has resolved * so far, and `ask`, to look up the URLs it has not. A URL that names nothing, * or whose answer has not come back, stays text; when `ask` settles the * document is looked at again. * * The URL being typed stays text while the caret is in it or at its end, so a * half-typed address never turns into a chip under the person's fingers. A * pasted URL is whole, so it is asked about and made a chip at once, the caret * still at its end — where `ReferenceMenu` opens its menu. * * why: https://github.com/estiva-app/estiva-docs/blob/main/decisions/a-link-is-stored-as-the-url-a-person-wrote.md */ import { Extension, type Editor } from '@tiptap/core'; import type { Node as PmNode } from '@tiptap/pm/model'; import { type Selection } from '@tiptap/pm/state'; export interface LinkChipsOptions { /** * The `nostr:` reference an app URL names, from what the app has resolved * (§7.7) — protocol's `referenceOfLink(url, resolveLink)`. Undefined while it * names nothing, or its answer has not come back. */ referenceOf: ((url: string) => string | undefined) | null; /** Look up what these URLs name. When it settles, the document is looked at again. */ ask: ((urls: string[]) => Promise | void) | null; /** * How many URLs one editor asks about in its life, the first ones; the rest * stay text. An app's answer can cost a relay query, and a document pasted * full of links must not spend the writer's quota. Default 24. */ limit: number; } /** The meta on the transaction that made chips: `{ pasted }`. */ export declare const CHIPS_MADE = "linkChipsMade"; interface Found { /** Text URLs that name something: made chips. */ chips: { from: number; to: number; url: string; uri: string; marks: string[]; pasted: boolean; }[]; /** URL chips whose URL is answered now: given their reference. */ fills: { pos: number; uri: string; }[]; /** Every URL still waiting for an answer, or naming nothing. */ open: string[]; } /** Where something was pasted: a URL wholly inside one was not typed, so the caret at its end does not hold it as text. */ export interface PastedRange { from: number; to: number; } /** * What to change in a document, and what to ask. `selection` null treats no * URL as being typed; a URL inside one of `pasted` is never being typed. */ export declare function findLinkChips(doc: PmNode, selection: Selection | null, referenceOf: LinkChipsOptions['referenceOf'], pasted?: readonly PastedRange[]): Found; /** * Look at the document again — after the app learned what more URLs name some * other way. Dispatches only when there is a chip to make: an empty * transaction would wake every other plugin (a trailing paragraph appears). */ export declare function refreshLinkChips(editor: Editor): void; /** * Turns the app URLs in a document into URL chips. Pair it with `ReferenceNode`; * `ReferenceCards` then draws a card a URL chip asks for. */ export declare const LinkChips: Extension; export {}; //# sourceMappingURL=LinkChips.d.ts.map