API reference
Every function and type @getv.design/embed exports, generated from the declarations the package publishes. How to use them is on Embedding. The package is at 0.x: an API may still change in a minor version.
Entries
Four JavaScript entries, each an ES module, and two stylesheets. The editor and the exact-fonts code are separate files that load only when a page asks for them, so importing an entry costs only what it needs.
@getv.design/embed
const version: string;
The package’s version, as published: 0.1.0, say.
function mount(
el: HTMLElement,
source: Source,
options: MountOptions,
): Promise<ViewHandle | EditHandle | PlayHandle>;
Show a document in el, to view, present or edit.
Types: every type below.
@getv.design/embed/static
function parse(text: string): ParseResult;
Read .vd text. Never throws: what is wrong comes back as problems.
function renderSvg(source: Source, options?: RenderSvgOptions): Promise<string>;
Draw a document, or one of its pages, as a standalone SVG.
function designOf(text: string): string | undefined;
The .vd text in text: itself for a .vd, the design it carries for a .vd.svg, undefined for an SVG that carries none. For copying a design out of an SVG as text.
function outline(text: string): Outline;
A document’s title and pages, each with the line its frame is written on: what an editor needs for an outline, breadcrumbs, and keeping a preview on the page the cursor is in. Never throws.
The line is found by reading the text for the page’s top-level frame line, never by evaluating anything, so it is as cheap as parsing.
function createRenderer(options?: RendererOptions): Promise<Renderer>;
A renderer that draws synchronously once it exists. Exact fonts are fetched here, all of them, because which ones a later document needs is not known yet and the render cannot wait to find out.
function approximateRenderer(): Renderer;
The renderer with no font files, made synchronously: what the Markdown adapters use when a host does not hand them one, because a markdown-it plugin is installed in a synchronous call.
Also version, as above.
Types: Outline, OutlinePage, ParseResult, Problem, Renderer, RendererOptions, RendererRenderOptions, RenderSvgOptions, Source, VdDocument.
@getv.design/embed/view
function view(el: HTMLElement, source: Source, options?: ViewOptions): Promise<ViewHandle>;
Show a document in el. Rejects, leaving el untouched, if the source cannot be read.
Also version, as above.
Types: every type below.
@getv.design/embed/edit
function edit(el: HTMLElement, source: Source, options?: EditOptions): Promise<EditHandle>;
Edit a document in el. Rejects, leaving el untouched, if the source cannot be read.
Also version, as above.
Types: every type below.
@getv.design/embed/markdown
function createFenceIds(prefix?: unknown): () => string;
Ids for one page of HTML: each fence on it gets its own prefix.
function isVdFence(info: string | undefined | null): boolean;
The language a fence must name. vdesign is accepted too, for hosts that know vd as something else.
function parseInfo(info: string): FenceOptions;
The attributes after the language: key=value, key="quoted value", or a bare key for a flag. Unknown keys are ignored, so adding one later breaks no fence written today.
function renderFence(
body: string,
info: string | FenceOptions,
options?: FenceRenderOptions,
): string;
A fence to HTML. info is the whole info string (vd page=1) or options already parsed. Never throws: a fence that cannot be drawn comes back as its code block, with what was wrong.
Also createRenderer, as above.
Types: FenceOptions, FenceRenderOptions, Problem, Renderer.
@getv.design/embed/markdown-it
function vdesignMarkdownIt(md: MarkdownItLike, options?: MarkdownItOptions): void;
md.use(vdesignMarkdownIt, options).
Also createRenderer, as above.
Types: FenceOptions, FenceRenderOptions, MarkdownItOptions, Problem, Renderer.
@getv.design/embed/rehype
function rehypeVdesign(options?: RehypeOptions): void;
.use(rehypeVdesign, options).
Types: FenceOptions, FenceRenderOptions, Problem, RehypeOptions, Renderer.
@getv.design/embed/marked
function vdesignMarked(options?: FenceRenderOptions): {
renderer: { code(this: unknown, token: CodeToken | string, info?: string): string | false };
};
A marked extension. Returning false hands the block back to marked’s own renderer.
Also createRenderer, as above.
Types: FenceOptions, FenceRenderOptions, Problem, Renderer.
@getv.design/embed/auto
function hydrate(root?: ParentNode, options?: HydrateOptions): Promise<ViewHandle[]>;
Every figure.vd-figure[data-vd-mode="view"] under root that is not live yet. Resolves once each has opened or stayed a drawing; never rejects. Safe to call again after the page changes: figures already live are skipped.
Types: HydrateOptions, ViewHandle, ViewOptions.
@getv.design/embed/view.css, @getv.design/embed/edit.css
The styles the view and the editor otherwise insert as a <style> element. Link them under the ids vd-viewer-styles and vd-editor-styles when your content security policy refuses inline styles; see Embedding.
@getv.design/embed/fonts/*
The Inter faces the exact-fonts layout reads, one .woff2 per weight and style, and their licence, OFL.txt. Serve this folder yourself and set fontBase to keep font requests on your own origin.
Types
VdDocument
A parsed document. Opaque: pass it back to any function that takes a Source.
Opaque: it has no members you can read.
Source
What a document can be given as: .vd text, a URL to fetch, a file, or a parsed document.
type Source = string | URL | Blob | VdDocument;
Problem
Something wrong with a document. Reading never throws; it reports these instead.
-
line?: numberThe 1-based line in the
.vdtext, when the problem belongs to one. -
code: stringStable and machine-readable; branch on this, not on
message. -
message: string -
severity: 'error' | 'warning'
ParseResult
document: VdDocumentproblems: Problem[]
RenderSvgOptions
-
page?: string | numberOne page to draw: its id, or its 0-based index among the pages. Omitted, the whole document is drawn.
-
fonts?: 'exact' | 'approximate'How text is measured.
'approximate'(the default) needs no font files and runs anywhere; line breaks can differ slightly from the app’s.'exact'lays text out from the font files the app’s exports use, so lines break where theirs do: in Node they are read from the package’s ownfonts/folder, in a browser fetched fromfontBase. If a face cannot be had, the drawing is approximate andonProblemshears afonts-unavailablewarning; it does not reject. -
fontBase?: string | URLThe folder
'exact'reads the faces from (Inter-Regular.woff2and so on): a URL, or a path resolved against the page. Default: in Node, the package’s ownfonts/; in a browser, the package’sfonts/on jsDelivr. -
onProblems?: (problems: Problem[]) => voidCalled once, before the SVG is returned, with what is wrong: the document’s own problems and, under
'exact', any face that would not load. Empty when nothing is. -
idPrefix?: stringPut in front of every id the SVG defines for itself (clips, shadows, gradients) and of every reference to one. Two SVGs inline in one page otherwise share those names, and the second one’s shapes clip to the first one’s rectangles. The
/markdownentries give each fence its own.
OutlinePage
A page in outline(): what view() calls a page, and where it starts in the text.
-
id: string -
name?: string -
line?: numberThe 1-based line of the page’s
frameline in the text given, which for a.vd.svgcounts the SVG’s own lines. Undefined only if the frame could not be found, which a documentparseaccepted does not do.
Outline
-
title?: string -
pages: OutlinePage[]In play order: top-level frames that are not hidden.
-
problems: Problem[]
RendererOptions
-
fonts?: 'exact' | 'approximate''approximate'(the default) needs no font files.'exact'fetches every bundled face once, beforecreateRendererresolves, so each later render can lay text out from them without waiting. That is all 18 faces, about 2.6 MB: meant for a build step or an editor’s preview, not a web page. -
fontBase?: string | URLAs for
renderSvg.
RendererRenderOptions
page?: string | numberidPrefix?: stringonProblems?: (problems: Problem[]) => void
Renderer
Renders synchronously, for a caller that cannot wait: a markdown-it rule returns a string. Under fonts: 'exact' a document that needs a face that did not load draws approximately and onProblems hears fonts-unavailable.
-
renderSvg(source: string | VdDocument, options?: RendererRenderOptions): string.vdor.vd.svgtext, or a parsed document, to an SVG string. Throws aRangeErrorfor a missing page. -
readonly fonts: 'exact' | 'approximate'What
createRendererwas asked for, and what it got:'approximate'if the faces would not load.
ViewOptions
-
fit?: 'page' | 'content' | 'none'What the camera shows.
'page'(the default) fits the current page to the element;'content'fits everything;'none'leaves the camera at 100%. Applied on mount, byfit(), when the element is resized, and, for'page', bygoTo(); under the other two,goTo()centres the page at the current zoom. -
page?: number | stringThe page to start on: its id, or its 0-based index among the pages. A page is a top-level frame that is not hidden, counted as
renderSvgand the app’s exports count them. -
interactive?: booleanCtrl or ⌘ with the wheel (or a trackpad pinch) zooms; middle-drag or Space-drag pans. A plain wheel is left to the page, so the reader’s scroll is never caught by the view.
falseturns all of it off. Defaulttrue. -
fonts?: 'exact' | 'browser'How text is measured.
'browser'uses the page’s own fonts.'exact', the default, lays text out from the font files the app and its exports use, so lines break where theirs do: the view draws at once with the page’s fonts, fetches only the faces the document uses, then lays the text out again once, when they arrive. If a face cannot be fetched the view stays on the page’s fonts,problemsgains afonts-unavailablewarning, and thefontsevent says'browser'. -
fontBase?: string | URLThe folder
'exact'fetches faces from (Inter-Regular.woff2and so on): a URL, or a path resolved against the page. Default: the package’sfonts/on jsDelivr, which means the reader’s browser asks jsDelivr for them. To keep that request on your own origin, serve the package’sfonts/folder yourself and point this at it. -
surface?: stringThe colour behind the pages.
-
onLink?: (href: string) => voidA click on an
https:ormailto:link in the document. Without it the link opens in a new tab. A#pagelink goes to that page either way.
PageInfo
id: stringname?: string
ViewEvents
ready and problems describe the document on screen, so a listener added late is told the current state at once. One added in the same tick as a load() can therefore hear ready and problems twice: once from that replay and once when the load lands.
-
ready: () => voidA document is drawn: the first, and each one
load()brings. A listener added after that is called once straight away. -
problems: (problems: Problem[]) => voidWhat is wrong with the document on screen, empty when nothing is; again after every
load(). A listener added later is called with the current list straight away. -
page: (page: PageInfo) => voidThe current page changed. Not replayed.
-
fonts: (fonts: 'exact' | 'browser') => voidWhat text is measured with, once that is settled:
'exact'when the font files are in use,'browser'underfonts: 'browser'or when they could not be fetched. Fires when that is settled, and again if a laterload()needs a face that cannot be fetched; a listener added later is told the current answer at once.
PlayOptions
-
page?: number | stringThe page to start on. Default: the one the view is showing.
PlayHandle
-
goTo(page: number | string): void -
destroy(): voidStop presenting. Escape does the same.
ViewHandle
-
load(source: Source): Promise<void>Show another document, or a new version of this one, in place: what is unchanged is not redrawn. The page on screen and the camera stay while that page is still there. Rejects, leaving the view as it was, if the source cannot be read. When loads overlap, the last one called wins: an earlier one that finishes later resolves without drawing.
-
pages(): PageInfo[] -
goTo(page: number | string): voidThrows a
RangeErrorfor a page that is not there. -
fit(): voidApply the
fitoption again, for an element resized without the browser noticing. -
play(options?: PlayOptions): Promise<PlayHandle>Present over the view, one page at a time; Escape comes back.
-
edit(options?: EditOptions): Promise<EditHandle>Edit what is on screen, in place: the editor replaces the view in the same element, where the person was looking, and this handle is destroyed. The editor’s code loads only now.
optionsoverride the view’s own. Rejects, leaving the view as it was (a presentation and aload()in flight included), if the editor cannot open, and rejects a second call made while one is opening. Aload()that lands while the editor opens is dropped once it has: the editor shows the document from whenedit()was called. -
on<E extends keyof ViewEvents>(event: E, callback: ViewEvents[E]): () => voidThrows a
TypeErrorfor an event that is not one of these. -
destroy(): voidTake the view away, leaving the element empty, and release its image URLs.
EditOptions
As for a view, with these differences: a link is followed on ⌘-click (Ctrl elsewhere), since a plain click selects; fit frames the document once, and again on a resize only until the person moves the camera.
extends ViewOptions
-
toolbar?: booleanThe floating toolbar and the context menu. Default
true.
ChangeEvent
-
text(): stringThe whole
.vdfile after the change, asgetText(); composed only when called.
EditHandle
-
getText(): stringThe whole
.vdfile: the design and its images. -
getDocument(): VdDocumentThe document as it stands, to pass to
renderSvg,view()orload(). -
on(event: 'change', callback: (event: ChangeEvent) => void): () => voidOne
changeper undo step: a whole drag is one, on pointerup, and so are an undo and a redo. Throws aTypeErrorfor any other event. -
undo(): void -
redo(): void -
view(): Promise<ViewHandle>Back to a view of the document as edited, in the same element, keeping the camera; this handle is destroyed. Rejects, leaving the editor, if the view cannot open, and rejects a second call made while one is opening. The canvas takes no input meanwhile; a change that still lands (an
undo()) is shown by the view. -
destroy(): voidTake the editor away, leaving the element empty. Safe to call twice.
MountMode
type MountMode = 'view' | 'edit' | 'play';
MountOptions
type MountOptions = { mode: MountMode } & EditOptions;
FenceOptions
What a fence’s info string asks for: ```vd page=pricing mode=view source.
-
page?: string | numberOne page, by id or 0-based index (a number written as digits). Default: the whole document.
-
src?: stringA file to draw instead of the body, resolved by
resolveSrc. -
height?: numberThe live view’s height in CSS pixels. Default: the drawing’s own aspect ratio.
-
mode?: 'static' | 'view''view'hydrates into a live view;'static'stays an SVG. Default: the adapter’smode. -
source?: booleanAlso show the
.vdtext, folded, under the drawing. -
alt?: stringThe drawing’s accessible name. Default: the document’s title.
FenceRenderOptions
-
renderer?: RendererDefault: a renderer with no font files (
approximateRenderer()).createRenderermakes an exact one. -
resolveSrc?: (src: string) => string | undefinedRead a fence’s
src=. Without it, or when it returnsundefined, the fence shows a problem. -
mode?: 'static' | 'view'For fences that do not say. Default
'static'. -
output?: 'inline' | 'img''inline'(the default) puts the SVG in the page: its text can be selected and searched.'img'wraps it in<img src="data:…">: isolated from the page’s CSS, and what a mail client or a CMS that strips<svg>accepts. -
inlineStyles?: booleanfalsefor a page whose content security policy refusesstyle="". A drawing that needs one (a blend mode) is then wrapped as an<img>, which the policy does not reach into. Defaulttrue. -
limits?: { bytes?: number; nodes?: number }The most text and nodes one fence may hold. Past either it stays a code block.
-
idPrefix?: () => stringA fresh prefix for each drawing’s ids. Default:
vd1-,vd2-, … per call ofcreateFenceIds. -
attributes?: readonly (readonly [string, string])[]Extra attributes for the
<figure>, as the host’s own code block would have carried them: VS Code’s preview marks blocksclass="code-line" data-line="12"to keep its scroll in step with the editor.
MarkdownItOptions
extends Omit<FenceRenderOptions, 'resolveSrc'>
-
resolveSrc?: (src: string, env: unknown) => string | undefinedRead a fence’s
src=.envis what the host passed tomd.render(text, env).
RehypeOptions
extends Omit<FenceRenderOptions, 'resolveSrc' | 'renderer'>
-
fonts?: RendererOptions['fonts']Default
'exact'. Ignored whenrendereris given. -
fontBase?: RendererOptions['fontBase'] -
renderer?: Renderer -
resolveSrc?: (src: string, path: string | undefined) => string | undefinedRead a fence’s
src=.pathis the Markdown file’s own path when the pipeline knows it. Default, in Node: the file, relative to the Markdown. -
include?: (path: string | undefined) => booleanWhich Markdown files to draw fences in, by path. Default: all of them. For a site whose reference pages quote DSL to teach it, where the reader came for the code, not the picture.
HydrateOptions
-
fonts?: ViewOptions['fonts']Passed to each view. Default
'exact', fromfontBase. -
fontBase?: ViewOptions['fontBase'] -
surface?: ViewOptions['surface'] -
onLink?: ViewOptions['onLink']