Back to start

For developers

API reference

Everything a host can reach: the four elements, their attributes, properties and methods, the events they dispatch and what the packages export. The names here are the ones in the package's frozen surface — a name that changes is a breaking change and is in the changelog. How to get started is on the installation page.

<guide-preview> — the viewer

The element a visitor's page loads. It runs a guide, one step or one page at a time, keeping the answers when the visitor goes back.

active-locale attribute
active-locale="sv"

The language to show the guide in, as a locale code. Setting the attribute goes through the activeLocale property, so both the rendered text and the engine switch; removing it falls back to the default source locale. It is also read when the graph loads, so the first paint is already in the right language.

Values: "sv" | "en"

answer-display attribute
answer-display="trail"

Shows the visitor's earlier answers above the current step. "trail" lists each question with the answer as displayed (unit included); "history" is a plainer list of the question and the chosen option's label. Absent or any other value: no list.

Values: "trail" | "history"

example-files attribute
example-files

Boolean. When present, a file field whose step carries an example photo gets a button beside the file picker that fetches the example and attaches it. Without it no such button is drawn, even if the guide has an example photo. Meant for demo and try-it pages.

proving attribute
proving

Boolean. Marks a trial run inside the editor: file fields and map questions get stand-ins (a sample picture, a drawn map) instead of the real picker, hidden conditional fields stay hidden, and no guide-progress event is fired. Set by the editor; a host should not normally set it on a published page.

activeLocale property
activeLocale: string (write-only)

Sets the language the guide is shown in and tells the engine, so answers and templates follow; re-renders at once. Same effect as the active-locale attribute, which routes through this property. It has no getter, so reading it returns undefined.

clear method
clear(message?: string): void

Removes the guide from the viewer and shows an empty state with the given message. The default text is "Ingen guide har valts." (Swedish, not localised). Set graph again to show a guide.

getAnswers method
getAnswers(): Answers

The visitor's answers so far, as an object keyed by variable name. Only answers on the path the visitor actually took are included. Returns an empty object when no guide is loaded. Files are not in it; use getFiles().

getCurrentNodeId method
getCurrentNodeId(): string | null

The id of the step the visitor is on, or null when no guide is loaded. Save it alongside getAnswers() and hand both back through given to let the visitor resume later.

getFiles method
getFiles(): { fieldId: string; variableName: string; file: File }[]

The files the visitor has chosen in the guide's file fields, with each field's id and variable name. The viewer sends them nowhere; the host collects them when it is time to submit. Stand-ins from a trial run are never included.

getFormData method
getFormData(): FormData

Every answer and file encoded the way a browser encodes a form, ready to post with fetch as multipart. A file variable appears once, as the file; answers from a repeating page become name[index].field; a file with no variable name goes under file-<field id>.

getOutput method
getOutput(): EmailResultOutput | null

If the current step produces output (today the email result), returns the recipient, subject and body, both as the template and with answers filled in, plus any variables that were missing. Otherwise null.

getStepNumber method
getStepNumber(): number

Which step in sequence the visitor is on, as counted by the engine. Returns 1 when no guide is loaded. Mainly for the editor's second mirror of the same run; the viewer already shows the step number itself.

getTraversedConnectionIds method
getTraversedConnectionIds(): string[]

The ids of the guide's connections the run has passed through, in order. Empty when no guide is loaded. Mainly used by the editor to highlight the route on the canvas.

given property
given: GivenAnswers | null   // { answers: Answers; nodeId?: string | null }

Answers the host already knows, such as a name from a login or a saved run. They fill the fields but nothing is locked: the visitor can change them and they are validated as if typed. nodeId opens the guide on that step at load; can be set before or after graph and survives a restart.

graph property
graph: GraphData | null

The guide to show, in the standard format. Older formats are migrated on load; a guide from a newer version is refused and the viewer says so instead of drawing a broken page. Reading returns a copy, or null when nothing is loaded.

mirror method
mirror(source: GuidePreview | null): void

Makes this viewer draw the same run as another one, sharing its engine rather than a copy, so Next in one is Next in the other. null detaches it. Internal wiring for the editor's canvas; a host rarely needs it.

previous method
previous(): void

Goes back one step, as the visitor's Back button does, and fires preview-node-changed. Does nothing if there is no step to go back to.

refresh method
refresh(): void

Re-renders from the engine and drops any shown draft. For a mirrored viewer whose engine someone else moved; internal wiring for the editor.

restart method
restart(): void

Starts the guide over from the first step as a new case. The host's given answers are filled in again, but the step in given is not reused. Fires preview-node-changed and guide-progress with "restart".

reviewDeclarationEnabled property
reviewDeclarationEnabled: boolean

Whether the review step shows the declaration of what the decision rests on beneath the visitor's answers. Defaults to true; set false on pages where there is no decision to account for, such as an expression of interest.

routeAnalysisEnabled property
routeAnalysisEnabled: boolean

Whether the viewer shows the routes: where a step leads on cards such as rules and service calls, and which paths reach a result in compact mode. Defaults to true. These are cards a visitor seldom stops on; in practice the editor sets it from its capabilities.

setTheme method
setTheme(theme: "light" | "dark" | null): void

Sets the viewer's theme, same as the theme property. null hands the choice back to the operating system setting.

showDraft method
showDraft(values: Answers): void

Shows unsaved values in the page's fields, namely what the other mirrored viewer is typing, without storing them. Internal wiring for the editor's mirroring; a host rarely needs it.

showNode method
showNode(nodeId: string): boolean

Jumps straight to a step and draws it. If the id is a field on a page, the page is shown with that field highlighted. Returns true if the step could be shown. Used by the editor to show the selected node; fires no event.

shownAnswers property
shownAnswers: Answers (write-only)

Seeds answers so an already-answered step can be drawn with them, such as a picture on the editor's canvas. Decides nothing in the run. Internal wiring for the editor; it has no getter.

theme property
theme: "light" | "dark" | null

Light or dark theme for the viewer; null follows the operating system. Written as data-fw-theme on the element, not the document, so the host's page around it is not recoloured.

Values: "light" | "dark" | null

unmatchedGiven method
unmatchedGiven(): string[]

The names in given that no node in the guide declares as a variable. Those values are kept anyway, but the list explains why a field stayed empty. The same names are also logged with console.info.

variableInspectorEnabled property
variableInspectorEnabled: boolean

Whether the viewer shows a collapsible list of the variables' current values below the guide. Defaults to true; a host would normally turn it off on a published page.

<guide-editor> — the editor

The element the person editing builds the guide in. The host decides what it offers, stores what it hands over and listens to its events.

active-locale attribute
active-locale="<language code>"

Which of the guide's languages editing starts in. It only applies if the guide offers that language; otherwise a translator lands in the first non-source language and everyone else in the source language. It is a view and is never stored in the guide; read the current language with contentLocale.

Values: "sv" | "en"

editor-locale attribute
editor-locale="sv" | "en"

The language of the tool itself: palette, panel, menus and messages. It is separate from the guide's content language (active-locale). The editor ships strings in Swedish and English.

Values: "sv" | "en"

feature-level attribute
feature-level="basic" | "advanced" | "service"

How much of the editor the person editing gets: which node types and features are offered. Ignored while the modules attribute is set. Mirrored by the featureLevel property.

Values: "basic" | "advanced" | "service"

get-started-href attribute
get-started-href="<url>"

Address of the host's own getting-started page. With it, Help offers a Getting started item that leads there; without it the item is not shown.

mode attribute
mode="administrator" | "edit" | "translator" | "readonly"

What the person editing may change. Without the attribute, or with an unknown value, the editor is locked read-only: the host has to grant capability explicitly. The mode is a view, not protection — permissions are the host's job. Sets the mode property.

Values: "administrator" | "edit" | "translator" | "readonly"

mode-notice attribute
mode-notice="off"

With "off", the panel's box explaining why fields are locked is hidden. For a host that says so itself, for example in its own bar above the editor. The mode is unaffected.

Values: "off"

modules attribute
modules="<module ids, space- or comma-separated>"

Builds the editor's capabilities from modules instead of a level: the core (multiple choice, rules, variables, import/export) is always on and each module adds more. An empty attribute gives just the core; with no attribute, feature-level decides. The menu only lists modules backed by a registered node type, so submission appears only once PRO is loaded.

Values: "logic" | "content" | "fields" | "host-services" | "pages" | "submission"

palette-open attribute
palette-open (boolean)

Whether the full node palette is expanded. The host sets it before first paint and hears palette-open-changed with { open } when the person editing changes it; the library stores nothing. Mirrored by the paletteOpen property.

palette-search attribute
palette-search="off"

With "off", the node palette has no search field (Search node). The host's choice when setting the editor up.

Values: "off"

panel-open attribute
panel-open (boolean)

Whether the side panel (Properties/Preview) is open over the canvas. The person editing opening or folding it is announced with panel-open-changed and { open }; the host decides whether to remember it and sets it before first paint. Mirrored by the panelOpen property.

panel-width attribute
panel-width="<px>"

The side panel's width in pixels. When the person editing drags its edge, panel-width-changed fires with { width } (null after a reset), and the host can store the value and hand it back here. Mirrored by the panelWidth property.

theme attribute
theme="light" | "dark"

Light or dark theme for the editor. It is applied to the element, not the document, so the host page around it is unaffected. Sets the theme property.

Values: "light" | "dark"

addCustomNodeType method
addCustomNodeType(spec: NodeTemplate): void

Adds a node template to the library, or replaces it if the key (spec.type) already exists. The palette refreshes, a confirmation toast is shown, and node-templates-changed fires with the whole list so the host can save it. The library is shared by every editor on the page.

buildId property
readonly buildId: string

Which build of the editor is running: commit, whether there were uncommitted changes, and time. Meant for troubleshooting, such as a host's support page showing what a device is actually running.

capabilities property
capabilities: EditorCapabilities  (setter takes Partial<EditorCapabilities>)

Reads the capabilities actually in effect (a copy). Setting it layers individual on/off overrides on top of what feature-level or modules give; each assignment replaces the previous overrides.

contentLocale property
readonly contentLocale: string

The language of the guide's content currently being edited, for example after the person editing switched language in the toolbar. Its starting value comes from active-locale and the mode.

featureLevel property
featureLevel: "basic" | "advanced" | "service"

Same as the feature-level attribute: setting the property writes the attribute. Reads the level that is set, even when modules is in control instead.

Values: "basic" | "advanced" | "service"

getData method
getData(): GraphData

The guide as it stands, in the standard format and ready to store: nodes and connections from the canvas, the guide's settings, the node templates it uses, and the format version stamped on. This is what the host should save.

graph property
graph: GraphData

Setting graph opens a guide: it is migrated to the current format, the undo history and selection are reset, and a guide in an unsupported format is refused with an error message in the editor. Reading it returns the same as getData().

mode property
mode: "administrator" | "edit" | "translator" | "readonly"

What the person editing may change; same values as the mode attribute, which sets this property. The property does not write the attribute back, and it does not validate the value — use one of the four.

Values: "administrator" | "edit" | "translator" | "readonly"

modules property
modules: string[] | null

Same as the modules attribute: a list is written as a space-separated attribute, null removes the attribute. Reads the valid module ids after parsing (aliases resolved, unknown ones dropped), or null.

Values: null

nodeTemplates property
nodeTemplates: NodeTemplate[]  (setter accepts unknown)

The host's node templates. Setting the list replaces all non-built-in templates; invalid entries are skipped and the built-ins stay. Reading returns the editor-made templates without the built-ins. The library stores nothing — changes made in the editor are announced with node-templates-changed.

paletteOpen property
paletteOpen: boolean

Whether the full node palette is expanded; setting it toggles the palette-open attribute.

panelOpen property
panelOpen: boolean

Whether the side panel is open; setting it toggles the panel-open attribute. It is a view, not a change to the guide and not an undo step.

panelWidth property
panelWidth: number | null

The side panel's requested width in pixels; setting it writes the panel-width attribute, and null removes it for the default width. Reads the requested value, not the width actually drawn within the bounds.

redo method
redo(): void

Redoes the last undone step, if there is one. Same as the person editing choosing Redo.

refreshGraph method
refreshGraph(value: GraphData): void

Loads a newer version of the same guide without moving the view: whoever is watching keeps their pan and zoom. Meant for e.g. a read-only window following a colleague's work. Otherwise like setting graph, so the undo history is reset.

removeCustomNodeType method
removeCustomNodeType(type: string): void

Removes a node template from the library (built-in templates cannot be removed). Nodes created from it keep working but carry the base type's name. Fires node-templates-changed.

replaceGraph method
replaceGraph(value: GraphData, reason: GraphChangedDetail["reason"]): void

Replaces the guide as an undoable step, unlike setting graph. The guide is migrated first, then graph-changed fires with { graph, reason }. The editor itself uses it for import and reset.

Values: "node-moved" | "node-nudged" | "node-created" | "node-removed" | "start-node-changed" | "node-updated" | "node-template-changed" | "guide-updated" | "graph-imported" | "form-skeleton-added" | "graph-reset" | "connection-created" | "connection-removed" | "connection-recolored"

revealNode method
revealNode(nodeId: string, fieldId?: string): void

Selects the node and centres it in view. With fieldId, the side panel also opens on Properties and focus moves to that field. For a host that lists problems, such as what blocks publishing, and wants to take the person editing there.

setTheme method
setTheme(theme: ThemeChoice | null): void

Sets the editor's theme; the same as assigning the theme property. The editor has no theme button of its own — the host builds the control in its interface and calls this.

Values: "light" | "dark" | null

showToast method
showToast(options: ToastOptions): void  // { message: string; type: "success" | "error" | "info"; duration?: number }

Shows a short message in the editor's own toast, for example that the guide was saved. The host supplies the text; it is not translated.

startTour method
startTour(): void

Starts the editor's step-by-step tour pointing out its parts. The same tour the person editing can start themselves.

theme property
theme: "light" | "dark" | null

The editor's theme, applied to the element so the host page is unaffected. The theme attribute sets the property, but the property does not write the attribute back. The library does not store the choice, and the editor fires no event when the property is set.

Values: "light" | "dark" | null

undo method
undo(): void

Undoes the last step, if there is one. Typing in progress is recorded as a step first. Same as the person editing choosing Undo.

unsupportedNodeTypes method
unsupportedNodeTypes(graph?: GraphData): string[]

Which node types in a guide the editor's current capabilities do not offer, as type names. Without an argument it checks the open guide; with one the host can ask before importing, for example to raise the level first.

updateCustomNodeType method
updateCustomNodeType(type: string, changes: { label: string; icon?: string }): void

Renames a node template in the library and sets its icon. The change shows everywhere the template is used, and node-templates-changed fires. Omitting icon removes it.

<guide-versions> — the version list

The list of a guide's versions. It shows and asks; storing, publishing and deleting are the host's, when the list sends its intent events.

editor-locale attribute
editor-locale="sv"

The language of the list's own buttons, headings and dates. Without it the source language is used.

order attribute
order="saved" | "label" | "custom"

How the rows are shown. saved and label sort a copy and change nothing on the host's side; custom shows the array exactly as the host handed it. Other values are ignored.

theme attribute
theme="light" | "dark"

Light or dark theme for this element only, in the same words as <guide-editor>. It never recolours the page around it, and the library does not remember the choice.

actions property
actions: VersionAction[] | null  // "open" | "restore" | "activate" | "save" | "discard" | "duplicate" | "rename" | "note" | "delete"

Which actions the host's storage can actually carry out; only those buttons are shown. null (the default) shows all of them except restore, which appears only when listed explicitly. Opening a row by clicking it is not governed by actions.

editorLocale property
readonly editorLocale: string | undefined

Reads the editor-locale attribute. There is no setter; set the language through the attribute.

order property
order: "saved" | "label" | "custom"

The same as the order attribute, as a property. When the person editing drags a row, the element switches itself to custom.

setTheme method
setTheme(theme: "light" | "dark" | null): void

Sets the theme; null hands the decision back to the operating system. The same as setting the theme property.

theme property
theme: "light" | "dark" | null

The theme as a property. It is written to data-fw-theme on the element, not on the document.

versions property
versions: GuideVersion[]  // { id, number?, label?, note?, savedAt?, by?: { subject?, name?, me? }, reason?: "conflict", current?, open?, draft?, missing? }

The versions to show, as the host describes them. Setting the property redraws the list; it is the only way to change it. The list never counts on its own: number is the host's.

<prompt-dialog> — the prompt dialog

The dialog the editor and the version list ask with. A host can use the same dialog for its own questions.

ask method
ask(options: { title: string; label: string; message?: string; value?: string; placeholder?: string; confirmLabel: string; cancelLabel?: string }): Promise<string | null>

Opens a modal dialog with a text field and resolves with what was typed, trimmed. Cancel, Escape or an empty field resolves null. Asking again while one is open cancels the earlier question.

choose method
choose(options: { title: string; message?: string; choices: Array<{ id: string; label: string }>; cancelLabel?: string }): Promise<string | null>

The same dialog with one button per choice instead of a field. Resolves with the chosen id, or null if the person backs out.

editorLocale property
set editorLocale(value: string)

The tool's language. It only affects the default text of the Cancel button; every other text is passed in by the host through ask() and choose(). Setter only, no attribute.

Events

What the elements tell the host. All are CustomEvents; the detail is described per event.

graph-changed event
CustomEvent<{ graph: GraphData; reason: "node-moved" | "node-nudged" | "node-created" | "node-removed" | "start-node-changed" | "node-updated" | "node-template-changed" | "guide-updated" | "graph-imported" | "form-skeleton-added" | "graph-reset" | "connection-created" | "connection-removed" | "connection-recolored" }>  // bubbles, composed

The guide changed; detail.graph is the whole guide in the standard format and reason says why. It fires on every keystroke in a field (reason node-updated), so a host that saves should debounce its writes. This is the event init() listens to for onSave.

Dispatched by: <guide-editor>

graph-reset-request event
CustomEvent<null>  // no detail; bubbles, composed

The person editing chose to start over and confirmed it in the editor's warning dialog. The editor changes nothing itself: the host decides what an empty or original guide is and hands it over with replaceGraph(graph, "graph-reset").

Dispatched by: <guide-editor>

guide-progress event
CustomEvent<{ kind: "start" | "next" | "back" | "result" | "restart" | "submitted" | "validation-stopped"; nodeId: string | null; nodeType: string | null; step: number }>  // bubbles, composed

The visitor's way through the guide, for analytics: start, next, back, reached a result, restarted, stopped by validation and (in PRO) submitted. It never carries answers. Silent in the editor's preview and test runs (the editor-view and proving attributes).

Dispatched by: <guide-preview>

node-templates-changed event
CustomEvent<{ templates: NodeTemplate[] }>  // bubbles, composed

The node template library changed, and detail.templates is the whole list. The library stores nothing; the host decides whether to save it and hands it back through nodeTemplates next time. init() wires it to onTemplatesChange.

Dispatched by: <guide-editor>

palette-open-changed event
CustomEvent<{ open: boolean }>  // bubbles, composed

The node palette was opened or folded. A view, not a change to the guide. The host may remember it and set paletteOpen before the editor is next drawn.

Dispatched by: <guide-editor (raised by its inner <node-palette>, or by the editor itself when it folds the palette to make room)>

panel-open-changed event
CustomEvent<{ open: boolean }>  // bubbles, composed

The side panel was opened or folded, by the person editing or by the editor. The library does not remember it; the host may store it and set panelOpen before the editor is next drawn.

Dispatched by: <guide-editor>

panel-width-changed event
CustomEvent<{ width: number | null }>  // bubbles, composed

The person editing finished dragging or stepping the side panel's edge; width is the requested width in px, null after a reset. The host may store it and hand it back through panelWidth.

Dispatched by: <guide-editor>

preview-draft-changed event
CustomEvent<{ values: Answers }>  // bubbles, composed

What is currently typed on a page that has not been submitted yet, per keystroke. Mainly internal: the editor uses it to show the same half-filled page in both previews. Only raised on steps of type page.

Dispatched by: <guide-preview>

preview-node-changed event
CustomEvent<{ nodeId: string; answers: Answers }>  // bubbles, composed

The visitor moved to a new step, forwards or back; detail holds the step's id and all answers so far. A guide has no submit of its own, so this is where the host sees that a result was reached. Also raised in the editor's previews.

Dispatched by: <guide-preview>

save-request event
CustomEvent<null>  // no detail; bubbles, composed, cancelable

The person editing asked to save (Ctrl+S or File → Save). A host that saves calls preventDefault() and reads the guide with getData(). If nobody does, the editor shows a notice that the page handles saving on its own.

Dispatched by: <guide-editor>

theme-change event
CustomEvent<{ theme: "light" | "dark" }>  // bubbles, composed

Announces that the theme was switched, so the host can remember the choice. The library stores no theme itself. Listen on document.

Dispatched by: <none of the shipped elements; raised by whoever toggles the theme via announceThemeChange (in this repo: the example site's <theme-toggle>)>

version-activate-intent event
CustomEvent<{ version: GuideVersion }>  // bubbles, composed

The person editing wants this version to be the one visitors see (the row's button, on rows that are not current, missing or a draft). The list changes nothing; the host makes it live and then sends a new versions array.

Dispatched by: <guide-versions>

version-delete-intent event
CustomEvent<{ version: GuideVersion }>  // bubbles, composed

The person editing wants to remove the version. The list does not confirm, because only the host knows whether it can be undone; ask yourself if needed. The button is on every row but raises nothing on the current version while it still exists.

Dispatched by: <guide-versions>

version-discard-intent event
CustomEvent<{ version: GuideVersion }>  // bubbles, composed

The person editing wants to throw away unsaved changes. Shown only on a row with draft: true. The host drops the draft and gives the version's content back to the editor.

Dispatched by: <guide-versions>

version-duplicate-intent event
CustomEvent<{ version: GuideVersion }>  // bubbles, composed

The person editing wants a copy of the version. It is the row's main button on the current version and a menu item elsewhere. The host makes the copy and sends a new list.

Dispatched by: <guide-versions>

version-note-intent event
CustomEvent<{ version: GuideVersion }>  // bubbles, composed

The person editing wants to say what this version is. The event carries no text; the host asks itself, for example with <prompt-dialog>.ask(), stores the note and sends a new list.

Dispatched by: <guide-versions>

version-open-intent event
CustomEvent<{ version: GuideVersion }>  // bubbles, composed

The person editing wants to look at this version: a click on the row or its name. Opening moves and changes nothing; the host loads the version into the editor. Not governed by actions, and not raised for a missing version.

Dispatched by: <guide-versions>

version-rename-intent event
CustomEvent<{ version: GuideVersion }>  // bubbles, composed

The person editing wants to rename the version. The event carries no new name; the host asks for it itself, stores it and sends a new list.

Dispatched by: <guide-versions>

version-reorder-intent event
CustomEvent<{ order: string[] }>  // version ids in the new order; bubbles, composed

The person editing dragged a row (the grip, or Alt+arrow) into an order of their own. The element switches itself to order custom; the host stores the order if it wants and sends the list back in that order.

Dispatched by: <guide-versions>

version-restore-intent event
CustomEvent<{ version: GuideVersion }>  // bubbles, composed

The person editing wants to carry on from an older version. The button appears only when the host explicitly lists "restore" in actions, and never on the current or a missing version. The host puts that version's content into the editor as new work.

Dispatched by: <guide-versions>

version-save-intent event
CustomEvent<{ version: GuideVersion }>  // bubbles, composed

The person editing wants to save unsaved work into this version. It is the row's main button, only on a row with draft: true. The host writes the editor's content (getData()) into the version and sends a new list.

Dispatched by: <guide-versions>

What the package exports — the viewer

The functions and types in flowweaver-viewer (and so in every bundle): setup, languages, code lists, maps, palettes and the answers.

AnswerFields type
type AnswerFields = Record<string, string>

The parts of an answer that has parts, e.g. the label the visitor saw and the code behind it.

AnswerValue type
type AnswerValue = string | AnswerFields | string[] | AnswerRecord[]

One answer: a value, a value with parts, several values, or several records with parts. Read it with answerText, answerList or answerField rather than String().

Contract: docs/INLAMNING-KONTRAKT.md

Answers type
type Answers = Record<string, AnswerValue>

Every answer in a guide, keyed by variable name.

answerText function
answerText(value: AnswerValue | undefined): string

Turns an answer into one line of text for a result, a letter or a receipt. Several values are joined with ", ", an answer with parts shows its label, and a missing answer gives "".

Contract: docs/INLAMNING-KONTRAKT.md

answerList function
answerList(value: AnswerValue | undefined): string[]

Turns an answer into a list of comparable strings, for when the host checks whether the answer contains something. Objects are read by their label, empty entries are dropped, and an older newline-separated string is split.

Contract: docs/INLAMNING-KONTRAKT.md

answerField function
answerField(value: AnswerValue | undefined, field: string): string[]

Picks one part out of each object in an answer, e.g. the code ("value") of every chosen country. Returns an empty list for an answer without parts; objects lacking the part are skipped.

Contract: docs/INLAMNING-KONTRAKT.md

isAnswerEmpty function
isAnswerEmpty(value: AnswerValue | undefined): boolean

True when the answer is missing, an empty or blank string, an empty list, or an object without a label.

type * from ../viewer/types/graph type
export type * from "../viewer/types/graph"  // GraphData, FlowNodeData, Connection, GuideSettings, GuideMeta, …

The types of the guide's file format: GraphData (start node, nodes, connections, settings, meta) and everything it is made of. This is the shape the host stores and sets as graph on the element.

Contract: docs/JSON-KONTRAKT.md

SubmissionSchemaProperty type
interface SubmissionSchemaProperty { type: "string" | "number" | "boolean" | "object" | "array"; label?; format?; pattern?; enum?; options?; kind?; properties?; items?; minItems?; maxItems?; optional? }

One field in the submission schema: JSON Schema keywords where they exist, plus our own (label, options, kind, optional).

Contract: docs/INLAMNING-KONTRAKT.md

SubmissionSchema type
interface SubmissionSchema { $guide?: LocalizedTextMap; $serviceId?: string; exportedAt?: string; properties: Record<string, SubmissionSchemaProperty> }

The shape of what a guide submits, stamped by the editor into meta.submissionSchema on export, so a receiver can build against it before the first submission arrives.

Contract: docs/INLAMNING-KONTRAKT.md

GuidePreview class
class GuidePreview extends HTMLElement  // <guide-preview>

The class behind <guide-preview>, the element that runs a finished guide for the visitor. The element is registered when the viewer bundle loads; the export is for typing or instanceof.

Contract: docs/VARDSYSTEM-KONTRAKT.md

LanguagePack type
interface LanguagePack { viewer?: Record<string, string>; editor?: Record<string, string> }

The texts for one language passed to init, split into what the visitor reads (viewer) and what the person editing reads (editor).

LanguageSetup type
interface LanguageSetup { offer?: readonly string[]; source?: string; content?: string; tool?: string }

The language part of init: which languages a guide may be offered in, which a new guide is written in, which content language is shown, and the tool's own language.

HostSetup type
interface HostSetup { graph?; mode?; languages?; packs?; templates?; versions?; theme?; onSave?; onTemplatesChange? }

Everything the host passes to init: the guide, the permission mode, languages, language packs, node templates, versions, theme and the save callbacks.

Contract: docs/VARDSYSTEM-KONTRAKT.md

Wiring type
interface Wiring { coverage: Record<string, LocaleCoverage>; disconnect: () => void }

What init returns: the coverage of each registered language pack and a function that stops listening.

init function
init(element: HTMLElement, setup?: HostSetup): Wiring

Wires an element into the host in one call: registers language packs first, declares the languages, sets mode, editor-locale, active-locale, theme, versions and templates, listens for changes to call onSave/onTemplatesChange, and sets the guide last. Returns the packs' coverage and disconnect(). Built for <guide-editor>; on <guide-preview> the languages, theme and guide apply, while onSave never fires because the viewer does not emit graph-changed.

Contract: docs/VARDSYSTEM-KONTRAKT.md

SetupSeverity type
type SetupSeverity = "error" | "warning"

How serious a checkSetup finding is.

SetupFinding type
interface SetupFinding { id: string; severity: SetupSeverity; what: string; consequence: string }

One checkSetup finding: a stable id to filter on, severity, what was observed and what it leads to (in English).

SetupReport type
interface SetupReport { ok: boolean; findings: SetupFinding[] }

The answer from checkSetup; ok is true only when nothing was found.

CheckableElement type
interface CheckableElement extends HTMLElement { graph?: GraphData }

The element checkSetup inspects: <guide-preview> or <guide-editor>.

checkSetup function
checkSetup(element: CheckableElement): SetupReport

Inspects a mounted element's setup and reports in English: tokens that do not resolve, a <guide-editor> without mode, and languages the guide offers that lack viewer texts or fall outside declareLocales. It says nothing about storage or listeners, so ok: true means only that none of these was found. Call it after mounting, once the guide is set.

Contract: docs/VARDSYSTEM-KONTRAKT.md

LocaleStrings type
type LocaleStrings = Readonly<Record<string, string>>

A language pack: text keys mapped to texts.

registerLocale function
registerLocale(locale: string, strings: LocaleStrings): LocaleCoverage

Registers the viewer's texts for one language, e.g. Arabic buttons or the host's own Swedish wording. Calling again for the same language replaces the pack. Returns how much the pack covers. Call it at startup, before the elements render.

Contract: docs/VARDSYSTEM-KONTRAKT.md

unregisterLocale function
unregisterLocale(locale: string): void

Removes a registered language pack.

localeStrings function
localeStrings(locale: string): Record<string, string>

Returns every text for one language as a flat template to translate from: the package's own, overridden by the host's registered texts.

builtInLocales function
builtInLocales(): string[]

The language codes the package ships its own texts for, sorted.

availableLocales function
availableLocales(): string[]

The language codes the viewer can be shown in: the package's own plus those the host registered, sorted.

AudienceCoverage type
interface AudienceCoverage { filled: number; total: number; missing: string[] }

How many keys a language covers for one audience, and which are missing.

LocaleCoverage type
interface LocaleCoverage { locale: string; viewer: AudienceCoverage; editor: AudienceCoverage }

A language's coverage, separately for the viewer's and the editor's texts.

coverageOf function
coverageOf(locale: string): LocaleCoverage

Reports how much of the viewer's and the editor's texts a language covers, counting registered and built-in texts. With only the viewer loaded the editor side reads 0 of 0.

LocaleDeclaration type
interface LocaleDeclaration { default?: string }

The option to declareLocales: which language is the default.

declareLocales function
declareLocales(locales: readonly string[], options?: LocaleDeclaration): void

Declares which languages a guide may be offered in and which is the default (otherwise the first). Calling again replaces the declaration. Nothing is written into the guide.

Contract: docs/VARDSYSTEM-KONTRAKT.md

clearDeclaredLocales function
clearDeclaredLocales(): void

Clears the language declaration, so declaredLocales returns null again.

declaredLocales function
declaredLocales(): readonly string[] | null

The declared languages, or null when the host has declared none.

declaredDefaultLocale function
declaredDefaultLocale(): string | null

The declared default language, or null.

CodeListItem type
interface CodeListItem { value: string; label: LocalizedTextMap; synonyms?: LocalizedTextMap[]; sourceLabel?: string; exclusive?: boolean }

One entry in a code list: the stored code, its label per language, synonyms to search by, and whether it excludes every other entry.

CodeStandard type
type CodeStandard = "iso-3166-1-alpha-2" | "iso-3166-1-alpha-3" | "iso-3166-1-numeric" | "custom"

Which standard a code list's codes follow.

CodeList type
interface CodeList { id; standard: CodeStandard; label; version; published; source; sourceUrl?; labelSources?; items: CodeListItem[] }

A code list the host registers, with its standard, source and version.

registerCodeList function
registerCodeList(list: CodeList): void

Makes a code list (e.g. countries or municipalities) available to fields and rules. The lists ship as JSON beside the bundles and none is built in. The same id replaces the earlier list; a malformed list is refused with a TypeError saying what is wrong.

Contract: docs/VARDSYSTEM-KONTRAKT.md

codeListFault function
codeListFault(list: unknown): string | null

Checks a code list without registering it: returns a description of the fault (in Swedish), or null when the list is valid.

unregisterCodeList function
unregisterCodeList(id: string): void

Removes a registered code list.

getCodeList function
getCodeList(id: string): CodeList | null

Returns a registered code list, or null.

getCodeLists function
getCodeLists(): CodeList[]

Every registered code list.

MapKind type
type MapKind = "point" | "points" | "area"

What kind of geometry a map question asks for; per the code, points and area are reserved for v2.

Contract: docs/KART-KONTRAKT.md

MapPickResult type
interface MapPickResult { geometry: { type: string; coordinates: unknown }; label: string; zoom?: number }

The answer from the host's map: GeoJSON in WGS84 ([longitude, latitude]), a readable label and optionally the zoom level.

Contract: docs/KART-KONTRAKT.md

MapProvider type
interface MapProvider { kinds: readonly MapKind[]; pick(options): Promise<MapPickResult | null>; snapshot?(geometry, options?): Promise<string> }

The host's map: which kinds it supports, pick which lets the visitor point out geometry (null on cancel), and an optional still image.

Contract: docs/KART-KONTRAKT.md

registerMapProvider function
registerMapProvider(next: MapProvider): void

Registers the host's map provider, which map questions then call; FlowWeaver draws no map itself. There is one provider at a time and a new call replaces it.

Contract: docs/KART-KONTRAKT.md

unregisterMapProvider function
unregisterMapProvider(): void

Removes the registered map provider.

Contract: docs/KART-KONTRAKT.md

registerLookupOrigins function
registerLookupOrigins(origins: readonly string[]): void

Sets which origins (e.g. https://api.example.se) a lookup field may send the visitor's text to, besides the page's own. With no list, lookups go to the page's own origin only; an address outside the list is never called and the field says the lookup could not be reached. A new call replaces the list, and an entry that is not a bare origin is refused with an error.

Contract: docs/UPPSLAG-KONTRAKT.md

unregisterLookupOrigins function
unregisterLookupOrigins(): void

Removes the list, so lookups again go to the page's own origin only.

Contract: docs/UPPSLAG-KONTRAKT.md

Palette type
interface Palette { id: string; label: string; light: Record<string, string>; dark: Record<string, string> }

A finished colour scale: token values for light and dark mode.

palettes constant
const palettes: { hav: Palette; skog: Palette; skiffer: Palette; tegel: Palette }

The four built-in colour scales (hav, skog, skiffer, tegel), to pass to applyPalette.

applyPalette function
applyPalette(palette: Palette | null): void

Recolours FlowWeaver's elements in one step by adding a <style> to <head> with the scale's whole primary family and node colours, for light and dark mode. null removes it and restores the default colour. It also sets the --fw-* tokens on :root.

What the editor adds

What flowweaver-editor exports on top of the viewer.

GuideEditor class
class GuideEditor extends HTMLElement  // <guide-editor>
  attributes: feature-level, modules, mode, mode-notice, editor-locale, active-locale, theme, get-started-href, panel-width, panel-open, palette-open, palette-search
  graph: GraphData; getData(): GraphData; replaceGraph(value, reason); undo(); redo(); setTheme(theme: ThemeChoice | null)
  events: graph-changed, save-request, locale-change, panel-width-changed, panel-open-changed, palette-open-changed

The <guide-editor> element, registered when the editor bundle loads. The host sets graph, reads the guide back with getData() (stamped with its format version) and listens for graph-changed and save-request to store it itself; the editor stores nothing.

GuideVersion type
interface GuideVersion {
  id: string; number?: number; label?: string; note?: string; savedAt?: number;
  by?: { subject?: string; name?: string; me?: boolean };
  reason?: "conflict"; current?: boolean; open?: boolean; draft?: boolean; missing?: boolean;
}

One row in <guide-versions>, as the host describes it from its own storage. number, by and reason are the host's to set and are never computed by the list; current is the version visitors see, open the one the person editing is working from.

Contract: docs/LAGRING-KONTRAKT.md

GuideVersions class
class GuideVersions extends HTMLElement  // <guide-versions>
  attributes: editor-locale, order, theme
  versions: GuideVersion[]; order: VersionOrder; actions: VersionAction[] | null; theme: ThemeChoice | null
  events: version-{open|restore|activate|save|discard|duplicate|rename|note|delete}-intent { detail: { version } },
          version-reorder-intent { detail: { order: string[] } }

The <guide-versions> element: the list of a guide's versions. It decides nothing — it renders rows and raises version-*-intent events; reading, writing, naming and removing stay with the host. With actions the host says which actions its storage supports, so the menu shows only those.

Contract: docs/LAGRING-KONTRAKT.md

LinkPickContext type
interface LinkPickContext {
  locale: string;        // language of the text being edited
  selectedText: string;  // "" when nothing was selected
}

What the host's link picker receives when the person editing presses the link button: the language of the text being edited and the selected text.

LinkPickResult type
interface LinkPickResult {
  url: string;     // the address the viewer renders; relative is fine
  label?: string;  // link text when nothing was selected
  ref?: string;    // the host's own reference for the page
}

The host's link picker's answer. With ref the link is written [text](address "ref"); the viewer renders only the address, and the editor can later ask resolve whether the page has moved.

LinkPicker type
interface LinkPicker {
  pick(context: LinkPickContext): Promise<LinkPickResult | null>;
  resolve?(ref: string): Promise<{ url: string } | null>;
}

The host's link picker. pick opens the host's own dialog and resolves to null when the person editing cancels. The optional resolve is asked about every reference when a guide is opened in the editor: a changed address is rewritten, null (page gone) becomes a health warning, and a thrown error counts as no answer.

PromptDialog class
class PromptDialog extends HTMLElement  // <prompt-dialog>
  editorLocale: string (setter)
  ask(options: PromptOptions): Promise<string | null>
  choose(options: { title: string; message?: string; choices: Array<{ id: string; label: string }>; cancelLabel?: string }): Promise<string | null>

The <prompt-dialog> element, a modal dialog that asks for a word — for example what a copy should be called when <guide-versions> raises version-rename-intent. ask resolves to the text, or null on cancel or an empty answer; choose offers fixed choices instead of a field.

PromptOptions type
interface PromptOptions {
  title: string; label: string; message?: string; value?: string;
  placeholder?: string; confirmLabel: string; cancelLabel?: string;
}

What the host passes to PromptDialog.ask: title, a label above the field, an optional explanatory message, an initial value and button texts. Without cancelLabel the editor's own Cancel text is used.

ThemeChoice type
type ThemeChoice = "light" | "dark";

Light or dark theme for theme on <guide-editor> and <guide-versions>; null means the operating system's setting applies. The theme is set on the element, not on the host's page, and the library does not store the choice — remembering it is the host's job.

VersionOrder type
type VersionOrder = "saved" | "label" | "custom";

How <guide-versions> orders its rows: by date, by name, or in the order the host handed them (custom). Date and name are only a view; when the person editing drags a row, the list switches to custom and asks the host for the new order with version-reorder-intent.

registerLinkPicker function
function registerLinkPicker(value: LinkPicker): void

Registers the host's link picker, so the editor's link button opens the host's dialog instead of writing [text](https://). A new registration replaces the previous one and forgets earlier resolve answers.

unregisterLinkPicker function
function unregisterLinkPicker(): void

Removes the host's link picker; the link button then writes [text](https://) as it does without one.

FlowWeaver PRO — submitting PRO

What the PRO bundles add: the receiver contract the host registers, and the schema of what a guide sends in.

registerSubmissionReceiver function
function registerSubmissionReceiver(value: SubmissionReceiver): void

Registers the host's submission receiver. The guide hands the answers to submit and shows the reference that comes back; with no receiver registered, sending fails and the visitor is told so. A new registration replaces the previous one and resets the retry guarantee read so far (retryWindowHours).

unregisterSubmissionReceiver function
function unregisterSubmissionReceiver(): void

Removes the host's receiver and the retry guarantee read from it. After that, sending fails and the recipient list is empty.

listSubmissionRecipients function
function listSubmissionRecipients(): Promise<SubmissionRecipient[]>

Asks the registered receiver for its catalog and returns the rows trimmed to exactly {id, label} — any extra fields the host included are dropped. An empty list without a receiver. It also reads retryWindowHours when the catalog answered in that form.

VISITOR_RECIPIENT_ID constant
const VISITOR_RECIPIENT_ID = "@visitor";

The recipient picker's one address exception: the visitor's own address from an answer — the visitor's data to the visitor. @ cannot start a sensible catalog id, so the value does not collide with the host's ids.

SubmissionCatalog type
interface SubmissionCatalog {
  recipients: readonly SubmissionRecipient[];
  retryWindowHours?: number;
}

The catalog reply's other form: the rows plus the host's stated guarantee of how many hours a submissionId is recognised. It is the receiver's GET /recipients response, so the host can pass it on as-is. Only a finite number above zero counts as a guarantee; omitted means none.

SubmissionPayload type
interface SubmissionPayload {
  recipientId: string; recipientIds: string[]; copyRecipientIds: string[];
  submissionId?: string; serviceId?: string; serviceVersion?: string; caseType?: string;
  locale: string; answers: Answers; records: SubmissionRecord[];
  row: SubmissionRowCell[]; emailCopy: boolean; visitorEmail?: string;
  protection: { honeypot: string; elapsedMs: number };
}

What the guide hands to submit: recipient ids from the host's catalog (never addresses — the host resolves those), the answers by variable name, a readable summary, a submissionId that stays the same across retries, and the raw bot-protection data for the receiver to judge. recipientId is the first recipient, kept for older receivers; prefer recipientIds.

SubmissionReceipt type
interface SubmissionReceipt {
  reference: string;
}

What submit resolves to: the case reference, which the host owns and numbers. The guide shows it to the visitor; a thrown error gives an honest failure message and never an invented number.

SubmissionReceiver type
interface SubmissionReceiver {
  recipients(): readonly SubmissionRecipient[] | SubmissionCatalog
    | Promise<readonly SubmissionRecipient[] | SubmissionCatalog>;
  submit(payload: SubmissionPayload): Promise<SubmissionReceipt>;
}

What the host registers. recipients supplies the visible part of the catalog for the editor's recipient picker, synchronously or asynchronously; submit turns the answers into a case and rejects by throwing. The addresses themselves stay in the host's backend.

SubmissionRecipient type
interface SubmissionRecipient {
  id: string;
  label: string;
}

One row in the editor's recipient picker, and never more. The guide stores only the id; the address is not in the type and so never reaches the client.

SubmissionRecord type
interface SubmissionRecord {
  question: string;
  answer: AnswerValue;
  variable: string | null;
}

One line of the submission's readable summary (records): the question's heading as the visitor read it, the answer and the variable name — the same lines the review step shows.

submissionSchema function
function submissionSchema(graph: GraphData): SubmissionSchema

Derives the submission schema from a guide: the keys are the editor's variable names, the type follows the field type and the label is the question per language. For a host that already has the graph and wants to build or validate its receiver against it; the same schema is stamped into meta.submissionSchema on export.

pro-bundles about
flowweaver-pro-viewer  ← src/entries/pro-viewer.ts  (global FlowWeaverProViewer)
flowweaver-pro-editor  ← src/entries/pro-editor.ts  (global FlowWeaverProEditor)
// each: export * from the open entry, plus the submission exports above

FlowWeaver PRO is built as two bundles of its own that export everything the open ones do plus the submission exports here. The PRO viewer sends: the submission and e-mail result nodes hand the answers to the host's receiver. The open viewer draws a sending step as a plain result and sends nothing; the PRO editor adds the sending node types, the recipient picker, the health rules and the schema stamped on export. The file format is the same, so one guide works in both.

Contract: docs/INLAMNING-KONTRAKT.md (ships with FlowWeaver PRO)