Skip to content

LayoutEditor, store, history · Browser (client only)

@openseat/editor

Visual layout designer for OpenSeat: tools, inspector, layers, undo/redo, import/export and save with conflict handling.

The OpenSeat visual layout designer: tool palette, canvas, properties inspector, layers panel, undo/redo, JSON import/export and saving with conflict detection.

  • 8 components
  • 3 hooks
  • 85 functions
  • 51 interfaces
  • 23 types
  • 19 constants
  • MIT
npm i @openseat/editor @openseat/core konva react react-dom
first npm release pending

Install commands show the public npm names. The first npm release is pending; the packages are free and MIT licensed.

Stylesheet: import @openseat/editor/styles.css once in your app, or the components render unstyled.

depends on @openseat/core, @openseat/react, @openseat/renderer-konva, @openseat/theme-default, zustand · peers konva, react, react-dom

Import
import {
  LayoutEditor,
  useEditor,
  createEditorStore,
  LayersPanel,
  Inspector,
} from "@openseat/editor";
import "@openseat/editor/styles.css";

Components8

component

Inspector

Right-hand properties panel. Every value comes from the store on each render, so undo, redo and canvas edits show at once.

  • Nothing selected: layout settings, venue, defaults and categories.
  • One object: the panel for its type plus placement.
  • Several seats (seat mode, "Edit seats"): bulk seat editing.
  • Several rows: row tools plus the multi-selection tools.
  • Anything else: multi-selection tools.

Needs its stylesheet: add import "@openseat/editor/styles.css"; once in your app, or it renders unstyled.

function Inspector(): JSX.Element;

@openseat/editor/src/react/Inspector.tsx

component

IssuesPanel

Floating panel listing the layout's issues grouped by kind. Clicking an entry selects its object (entering its section or row) and zooms to it; common problems have one-click fixes. Render it inside .os-canvas.

Needs its stylesheet: add import "@openseat/editor/styles.css"; once in your app, or it renders unstyled.

function IssuesPanel(props: {
  readonly onClose: () => void;
}): JSX.Element;

Props

PropTypeDescription
onClosereadonly() => void

@openseat/editor/src/react/issues.tsx

component

LayersPanel

Layer tree: sections, their rows / tables / GA areas, and their seats. Rows show plain-language names ("Rectangle 1", "Standing area General"). Click selects (entering the section or row it lives in), Shift-click selects the range from the last clicked row, Ctrl/Cmd-click toggles, double-click (or F2) renames (a row's or seat's label, other objects' layer name). Eye and lock buttons set the flag on that object only; children hidden or locked through a parent are greyed (is-inherited-hidden / is-inherited-locked) and keep their own flags. Large trees are windowed.

Needs its stylesheet: add import "@openseat/editor/styles.css"; once in your app, or it renders unstyled.

function LayersPanel(): JSX.Element;

@openseat/editor/src/react/LayersPanel.tsx

component

LayoutEditor

The visual layout designer: tool palette, canvas, inspector and layers, with undo/redo, import/export, presets, a buyer preview and saving. All edits go through the editor store, so every change is one undoable step. The canvas behaviour lives in useCanvasInteractions; this component composes the chrome around it.

Needs its stylesheet: add import "@openseat/editor/styles.css"; once in your app, or it renders unstyled.

function LayoutEditor(props: LayoutEditorProps): JSX.Element;

Props · LayoutEditorProps

PropTypeDescription
storeoptionalEditorStore

Provide a store to control the editor from outside, or initialLayout to let the editor create one.

initialLayoutoptionalLayoutDocument
onSaveoptionalSaveHandler

Persists the layout. Without it, the Save button is disabled.

onChangeoptional(layout: LayoutDocument) => void

Called after every layout change. Only read when the editor creates its own store.

isInventoryInUseoptionalInventoryInUseCheck

Reports which of the given seat IDs or inventory keys have tickets sold or held. A save that removes seats asks first only when some are in use (or when this check is missing or fails). Only read when the editor creates its own store.

themeoptionalTheme
showLayersoptionalboolean

Show the layers panel under the inspector. Default true.

Default true

classNameoptionalstring
styleoptionalCSSProperties
mapRefoptional{ current: SeatMapHandle | null; }

Receives the canvas handle, for host-side zoom controls or screenshots.

categoryPricesoptionalReadonly<Record<string, string>>

Display prices per category ID ("$45"), owned by the host: prices are not part of the layout document. Shown in the buyer preview, the paint legend and (with onCategoryPricesChange) the categories editor.

onCategoryPricesChangeoptional(next: Record<string, string>) => void

Makes prices editable in the categories editor; receives the full new price map.

currencyoptionalCurrencyControl

The currency of the prices, with the choices the host offers: shown as a picker at the top of the Ticket types panel. Hidden when omitted.

previewMapRefoptional{ current: BookingMapHandle | null; }

Receives the buyer preview's BookingMap handle while the preview is open.

wheelModeoptionalWheelMode

What a plain mouse wheel does on the canvas until the user picks otherwise with the top-bar toggle (remembered per browser). Default "zoom".

Default "zoom"

onBeforeDestructiveChangeoptionalDestructiveChangeHook

Asked before a change that can remove sold inventory: replacing the layout with a venue template, rebuilding it from its template, or regenerating a table or booth block so that places disappear. Return false (or a promise of false) to cancel; the editor explains why. Without it, such a change asks the user to type REPLACE whenever inventory would be removed.

Every member is readonly.

Example

OrganiserPage.tsx
import { useState } from "react";
import type { LayoutDocument } from "@openseat/core";
import { createRestAdapter } from "@openseat/adapter-rest";
import { LayoutEditor } from "@openseat/editor";
import "@openseat/editor/styles.css";

const api = createRestAdapter({
  baseUrl: "https://tickets.example.com/api",
  credentials: "include", // staff cookie session
  sendManifest: true, // PUT body: { layout, manifest }
});

export function OrganiserPage({ layout }: { layout: LayoutDocument }) {
  const [prices, setPrices] = useState<Record<string, string>>({ vip: "₹1,499", general: "₹299" });
  return (
    <div style={{ height: "100dvh" }}>
      <LayoutEditor
        initialLayout={layout}
        // Sends If-Match: "<baseRevision>". A 409/412 resolves as { status: "conflict", remote },
        // and the editor offers "Load their version" or "Overwrite with mine" (force: true).
        onSave={(request) => api.saveLayout(request)}
        categoryPrices={prices}
        onCategoryPricesChange={setPrices}
      />
    </div>
  );
}

Recipe: embed the designer

@openseat/editor/src/react/LayoutEditor.tsx

component

PreviewPane

The buyer's view of the layout being edited: the booking map with overview-to-section zoom, the legend (with prices when the host supplies them) and the selection summary; everything is available except what is marked not for sale. A layout with sections opens on the section overview, seats hidden until a section is chosen, as buyers see it. Seat selections are local to the preview and discarded when it closes; the layout is never changed.

Needs its stylesheet: add import "@openseat/editor/styles.css"; once in your app, or it renders unstyled.

function PreviewPane(props: PreviewPaneProps): JSX.Element;

Props · PreviewPaneProps

PropTypeDescription
onExit() => void

Leave the preview and return to editing.

categoryPricesoptionalReadonly<Record<string, string>>

Display prices per category ID, shown in the legend, tooltips and summary.

mapRefoptional{ current: BookingMapHandle | null; }

Receives the BookingMap handle while the preview is open.

Every member is readonly.

@openseat/editor/src/react/PreviewPane.tsx

component

SaveRemovalDialog

Asks before a save that removes seats, in plain language: the seats by name (never IDs) and, when the host's isInventoryInUse told the store, how many of them have tickets. Shown while the store holds a pending save diff; Cancel has the focus, and "Save and remove" saves once.

Needs its stylesheet: add import "@openseat/editor/styles.css"; once in your app, or it renders unstyled.

function SaveRemovalDialog(props: {
  readonly onDone: () => void;
}): JSX.Element | null;

Props

PropTypeDescription
onDonereadonly() => void

@openseat/editor/src/react/SaveRemovalDialog.tsx

component

ScopeBar

Where the user is editing, as a breadcrumb ("Layout › Section 101 › Row C") with a "Back to whole map" button and an Exit button (one level up). Clicking an earlier crumb leaves the scopes after it. In seat mode (the Select seats tool) at the top level it shows only "Selecting single seats" and the back button. With nothing entered and one section selected, a hint says how to edit its seats.

Needs its stylesheet: add import "@openseat/editor/styles.css"; once in your app, or it renders unstyled.

function ScopeBar(): JSX.Element | null;

@openseat/editor/src/react/ScopeBar.tsx

component

TableGridDialog

Needs its stylesheet: add import "@openseat/editor/styles.css"; once in your app, or it renders unstyled.

function TableGridDialog(props: {
  readonly origin: Point;
  readonly onClose: () => void;
}): JSX.Element;

Props

PropTypeDescription
originPoint
onClose() => void

Every member is readonly.

@openseat/editor/src/react/TableGridDialog.tsx

Hooks3

hook

useEditor

Subscribes to part of the editor state. Select plain fields (not new objects or arrays built in the selector), so components re-render only when that field changes.

function useEditor<T>(selector: (state: EditorStoreState) => T): T;

Type parameters

  • T

Parameters

ParameterTypeDescription
selector(state: EditorStoreState) => T

Returns

T

@openseat/editor/src/react/context.ts

hook

useLayoutIssues

The current layout's issues. Computed immediately on mount, then again 150 ms after the layout stops changing.

function useLayoutIssues(): LayoutIssues;

@openseat/editor/src/react/issues.tsx

Functions85

function

amendLast

Replaces fields of the newest entry (no-op on an empty history).

function amendLast(
  history: History,
  patch: Partial<Pick<HistoryEntry, "revision" | "label">>,
): History;

Parameters

ParameterTypeDescription
historyHistory
patchPartial<Pick<HistoryEntry, "revision" | "label">>

Returns

@openseat/editor/src/history.ts

function

amountText

"84 seats", "1,200 places", "60 seats · 300 places", "10 booths"; "0 seats" when nothing uses it. What is held back follows: "33 booths · 3 held back", or "304 seats held back" when nothing of the type is for sale.

function amountText(a: TicketAmount | undefined): string;

Parameters

ParameterTypeDescription
aTicketAmount | undefined

Returns

string

@openseat/editor/src/ticket-types.ts

function

arcSectionFromPoints

An arc (wedge) section from three clicks: the arc center (stage or field centre), first on the front row at the start angle, and second at the end angle, whose distance from the centre sets the back row. The sweep runs clockwise on screen from first to second (at most 360°). Null when the clicks do not describe a usable arc.

function arcSectionFromPoints(
  center: Point,
  first: Point,
  second: Point,
  layout: LayoutDocument,
  d: ArcDrawingSettings,
): { objects: LayoutObject[]; sectionId: string; summary: string } | null;

Parameters

ParameterTypeDescription
centerPoint
firstPoint
secondPoint
layoutLayoutDocument
dArcDrawingSettings

Returns

{ objects: LayoutObject[]; sectionId: string; summary: string; } | null

@openseat/editor/src/tools.ts

function

beginGroup

Opens a gesture group: until endGroup, every recorded entry folds into one undo step, however long the gesture takes. Opening a group with another key closes the open one first; the same key keeps it open.

function beginGroup(history: History, key: string): History;

Parameters

ParameterTypeDescription
historyHistory
keystring

Returns

@openseat/editor/src/history.ts

function

boundsCentre

Centre of a bounds box.

function boundsCentre(b: Bounds): Point;

Parameters

ParameterTypeDescription
bBounds

Returns

@openseat/editor/src/selection.ts

function

clipboardSizeError

Message for clipboard text over MAX_CLIPBOARD_BYTES, or null when it is small enough.

function clipboardSizeError(text: string): string | null;

Parameters

ParameterTypeDescription
textstring

Returns

string | null

@openseat/editor/src/clipboard.ts

function

compareRowLabels

Row labels in front-to-back order: A, B … Z, AA, AB (shorter first), numbers by value.

function compareRowLabels(a: string, b: string): number;

Parameters

ParameterTypeDescription
astring
bstring

Returns

number

@openseat/editor/src/row-range.ts

function

contentBounds

World bounds of the content: every visible object. Null for an empty layout.

function contentBounds(layout: LayoutDocument): Bounds | null;

Parameters

ParameterTypeDescription
layoutLayoutDocument

Returns

Bounds | null

@openseat/editor/src/tools.ts

function

createEditorStore

Creates the editor's state store. Framework-independent (Zustand vanilla); the React components subscribe to it, and hosts can too.

function createEditorStore(
  options: EditorStoreOptions,
): EditorStore;

Parameters

ParameterTypeDescription
optionsEditorStoreOptions

options takes EditorStoreOptions:

Returns

@openseat/editor/src/store.ts

function

createObjectsForTool

Default objects created by a placement tool at point. IDs are unique in layout. Returns null for tools that collect more input (rows, polygon), select (select, selectSeats, pan, paint), or change the document some other way (focal: the UI calls setFocalPoint).

function createObjectsForTool(
  tool: ToolId,
  rawPoint: Point,
  layout: LayoutDocument,
  snap: boolean,
  ctx?: ToolContext,
): LayoutObject[] | null;

Parameters

ParameterTypeDescription
toolToolId
rawPointPoint
layoutLayoutDocument
snapboolean
ctxoptionalToolContext

Default {}

Returns

LayoutObject[] | null

@openseat/editor/src/tools.ts

function

describeObjects

What a set of objects is, in user terms: one object by name ("Table T3"), otherwise counts by kind in document order ("400 seats", "2 tables and 1 booth"). "nothing" for an empty list.

function describeObjects(
  layout: LayoutDocument,
  ids: readonly string[],
): string;

Parameters

ParameterTypeDescription
layoutLayoutDocument
idsreadonly string[]

Returns

string

@openseat/editor/src/human-labels.ts

function

dividerCaptionSize

Caption size for a new floor divider: a fiftieth of the venue's longer side (120 on a 6,000-unit ground, about 15 px at the 12% that shows it whole), or null on a layout under 1,000 units, where the theme's own size reads well.

function dividerCaptionSize(layout: LayoutDocument): number | null;

Parameters

ParameterTypeDescription
layoutLayoutDocument

Returns

number | null

@openseat/editor/src/tools.ts

function

dividerFromPoints

A new floor divider (open path with a caption, not yet added) through points (at least 2).

function dividerFromPoints(
  layout: LayoutDocument,
  points: readonly Point[],
  caption?: string,
): CustomPath;

Parameters

ParameterTypeDescription
layoutLayoutDocument
pointsreadonly Point[]
captionoptionalstring

Default DEFAULT_DIVIDER_CAPTION

Returns

@openseat/editor/src/tools.ts

function

dragShapeFor

The stage, rectangle or booth a drag-to-size tool (isDragSizeTool) creates for a drag over rect: centred on the drag and exactly as large, but at least 10 x 10 (a shorter drag gives the minimum size). Corners snap to the grid when state.snapToGrid is set. Uses the same default names and IDs as a click. Null for other tools.

function dragShapeFor(
  tool: ToolId,
  rect: DragRect,
  state: DragShapeState,
): LayoutObject | null;

Parameters

ParameterTypeDescription
toolToolId
rectDragRect
stateDragShapeState

Returns

@openseat/editor/src/tools.ts

function

drawBlock

A block of rows from a rectangle drag (the Rows tool in block mode). The rectangle runs from the snapped start to end: one seat per seatSpacing across (rounded, at least one) and one row per rowSpacing down. Row 0 (the front row, labelled first) is on the start's side, or, when the layout has a focal point, on the side nearer the focal point; seats are numbered from the start's side, whichever way the drag goes.

Without intoSectionId the result is a new parametric block section with an auto outline, centred on the block. With it, the rows are plain parametric rows of that section, labelled after its existing rows.

function drawBlock(input: DrawBlockInput): DrawnBlock;

Parameters

ParameterTypeDescription
inputDrawBlockInput

input takes DrawBlockInput:

Returns

@openseat/editor/src/row-drawing.ts

function

drawRows

Rows drawn with the pointer: the first row runs from start towards end, with as many seats as fit at seatSpacing. Further rows stack on whichever side of it side lies. Seats are numbered from the start of the drag and rows are labelled A, B, C… (or from firstRowLabel) away from the first row.

Every row is parametric: its rotation is the drawn angle and its layout (spacing, start anchor, radius, tangent seat rotation, labeling) reproduces the seats exactly, so later edits regenerate the row in place.

function drawRows(input: DrawRowsInput): DrawnRows;

Parameters

ParameterTypeDescription
inputDrawRowsInput

input takes DrawRowsInput:

Returns

@openseat/editor/src/row-drawing.ts

function

drawsOwnName

True for the object types whose own fields already draw their name on the map (a booth's or table's label).

function drawsOwnName(type: LayoutObject["type"]): boolean;

Parameters

ParameterTypeDescription
typeLayoutObject["type"]

Returns

boolean

@openseat/editor/src/store.ts

function

endGroup

Closes the open gesture group (no-op without one).

function endGroup(history: History): History;

Parameters

ParameterTypeDescription
historyHistory

history takes History:

Returns

@openseat/editor/src/history.ts

function

footnoteFor

A new note (footnote label, not yet added) made by core createFootnote: centred under the content, NOTE_GAP below its bottom edge (the canvas centre for an empty layout), with text (default DEFAULT_NOTE_TEXT, a prompt to type over).

function footnoteFor(layout: LayoutDocument, text?: string): Label;

Parameters

ParameterTypeDescription
layoutLayoutDocument
textoptionalstring

Default DEFAULT_NOTE_TEXT

Returns

@openseat/editor/src/tools.ts

function

heldBackCount

Seats, places and booths of a type held back from sale.

function heldBackCount(a: TicketAmount | undefined): number;

Parameters

ParameterTypeDescription
aTicketAmount | undefined

Returns

number

@openseat/editor/src/ticket-types.ts

function

isActivationTarget

True when focus is on something Enter, Space or the arrow keys activate or move within: buttons, links, checkboxes and radios, and menu items, options, tabs and the like (by ARIA role). The editor must leave those keys to the element there.

function isActivationTarget(target: EventTarget | null): boolean;

Parameters

ParameterTypeDescription
targetEventTarget | null

Returns

boolean

@openseat/editor/src/shortcuts.ts

function

isDirty

function isDirty(state: EditorState): boolean;

Parameters

ParameterTypeDescription
stateEditorState

state takes EditorState:

Returns

boolean

@openseat/editor/src/store.ts

function

isDragDrawTool

Tools whose primary gesture is a press-drag-release on the canvas (rather than clicks): rows in either mode, and rectangle sections and GA areas. Arc sections are built from clicks.

function isDragDrawTool(
  tool: ToolId,
  options?: ToolOptions,
): boolean;

Parameters

ParameterTypeDescription
toolToolId
optionsoptionalToolOptions

Default DEFAULT_TOOL_OPTIONS

Returns

boolean

@openseat/editor/src/tools.ts

function

isDragSizeTool

Tools that size what they place to a press-drag-release (a click places the default size).

function isDragSizeTool(tool: ToolId): boolean;

Parameters

ParameterTypeDescription
toolToolId

Returns

boolean

@openseat/editor/src/tools.ts

function

isFloorDivider

True for a path drawn as a floor divider: one with a caption.

function isFloorDivider(
  obj: LayoutObject | undefined,
): obj is CustomPath & { readonly caption: string };

Parameters

ParameterTypeDescription
objLayoutObject | undefined

Returns

obj is CustomPath & { readonly caption: string; }

@openseat/editor/src/tools.ts

function

isPlacementTool

Tools that create something where you click.

function isPlacementTool(tool: ToolId): boolean;

Parameters

ParameterTypeDescription
toolToolId

Returns

boolean

@openseat/editor/src/tools.ts

function

isRepeatTool

Tools that stay active after placing, so you can place several in a row (15 tables, 20 booths) without picking the tool again. Escape or another tool ends them. Only the stage-centre (focal) tool is one-shot.

function isRepeatTool(tool: ToolId): boolean;

Parameters

ParameterTypeDescription
toolToolId

Returns

boolean

@openseat/editor/src/tools.ts

function

isSellableObjectType

True for the object types that can be marked Not for sale (seats, rows, sections, tables, booths, zones).

function isSellableObjectType(type: LayoutObject["type"]): boolean;

Parameters

ParameterTypeDescription
typeLayoutObject["type"]

Returns

boolean

@openseat/editor/src/store.ts

function

isTypingTarget

True when keyboard focus is in a text field (a text-like INPUT, a TEXTAREA, a SELECT or contentEditable), where shortcuts must not fire. Checkboxes, sliders, colour pickers and buttons are not typing targets.

function isTypingTarget(target: EventTarget | null): boolean;

Parameters

ParameterTypeDescription
targetEventTarget | null

Returns

boolean

@openseat/editor/src/shortcuts.ts

function

isUntitledName

True for a layout nobody has named yet ("", "Untitled layout").

function isUntitledName(name: string): boolean;

Parameters

ParameterTypeDescription
namestring

Returns

boolean

@openseat/editor/src/layout-names.ts

function

mapNameLabelId

ID of the text label that shows an object's name on the map ("Show name on map").

function mapNameLabelId(objectId: string): string;

Parameters

ParameterTypeDescription
objectIdstring

Returns

string

@openseat/editor/src/store.ts

function

neverSoldCategoryIds

Ticket types that are never sold (metadata.openseat.unsellableCategories) that exist in the layout.

function neverSoldCategoryIds(
  layout: LayoutDocument,
): ReadonlySet<string>;

Parameters

ParameterTypeDescription
layoutLayoutDocument

Returns

ReadonlySet<string>

@openseat/editor/src/ticket-types.ts

function

neverSoldTypesIn

The never-sold ticket types that hold back ids (sections, rows, tables, seats, zones, booths, by their own or their seats' type), with how many seats or places each holds back. Empty when nothing selected is held back by its ticket type.

function neverSoldTypesIn(
  layout: LayoutDocument,
  ids: readonly string[],
  index?: LayoutIndex,
): { readonly id: string; readonly name: string; readonly count: number }[];

Parameters

ParameterTypeDescription
layoutLayoutDocument
idsreadonly string[]
indexoptionalLayoutIndex

Default indexLayout(layout)

Returns

{ readonly id: string; readonly name: string; readonly count: number; }[]

@openseat/editor/src/ticket-types.ts

function

newStage

A new stage labelled "Stage", with no style of its own, so the theme's stage look (soft grey, thin border, letter-spaced title) applies, and the chosen outline shape ("rect" leaves shape out).

function newStage(
  layout: LayoutDocument,
  position: Point,
  width: number,
  height: number,
  shape?: StageShape,
): LayoutObject;

Parameters

ParameterTypeDescription
layoutLayoutDocument
positionPoint
widthnumber
heightnumber
shapeoptionalStageShape

Default "rect"

Returns

@openseat/editor/src/tools.ts

function

nextCategoryColour

The colour for the next ticket type of layout: the first palette colour no category uses yet (compared case-insensitively). When all twelve are taken the palette repeats, by category count.

function nextCategoryColour(
  layout: Pick<LayoutDocument, "categories">,
): string;

Parameters

ParameterTypeDescription
layoutPick<LayoutDocument, "categories">

Returns

string

@openseat/editor/src/category-colours.ts

function

nextZoneLabel

"Zone 1", "Zone 2": the smallest ordinal no zone (GA area) or section label uses yet, so a new zone never repeats a name buyers see.

function nextZoneLabel(layout: LayoutDocument): string;

Parameters

ParameterTypeDescription
layoutLayoutDocument

Returns

string

@openseat/editor/src/tools.ts

function

notForSaleState

Whether the objects ids are Not for sale: each sellable object counts as not for sale when it, or the row, table or section it belongs to, is on the layout's Not for sale list (a booth also when it stands inside a listed section). Objects that sell nothing (shapes, stages, labels) are ignored; with none left the answer is "none".

function notForSaleState(
  layout: LayoutDocument,
  ids: readonly string[],
): NotForSaleState;

Parameters

ParameterTypeDescription
layoutLayoutDocument
idsreadonly string[]

Returns

@openseat/editor/src/store.ts

function

objectLabel

Any object as a person names it: "Section Stalls", "Row C", "Table T3", "Booth B7", "Zone General", "Floor divider GROUND FLOOR", "Rectangle 1", or a seat's seatLabel. "item" for a missing object.

function objectLabel(
  layout: LayoutDocument,
  obj: LayoutObject | undefined,
): string;

Parameters

ParameterTypeDescription
layoutLayoutDocument
objLayoutObject | undefined

Returns

string

@openseat/editor/src/human-labels.ts

function

ownsArrowKeys

True when the arrow keys belong to the focused element: radios, sliders, menu items, options, tabs, tree items, and anything inside a menu, tree, tab list, radio group or list box. Plain buttons, links and checkboxes have no arrow-key action, so the editor may nudge with arrows while they have focus.

function ownsArrowKeys(target: EventTarget | null): boolean;

Parameters

ParameterTypeDescription
targetEventTarget | null

Returns

boolean

@openseat/editor/src/shortcuts.ts

function

ownZoneOf

The zone that has ticket type categoryId to itself: the one standing area or zone section ("Sections only") with that type, when nothing else (no seats elsewhere, no booth, no other area) has it. Its name and the type's name are then two names for one thing ("General standing" and "Silver"), so renaming one offers to rename the other. Null otherwise.

function ownZoneOf(
  layout: LayoutDocument,
  categoryId: string,
): { readonly id: string; readonly label: string } | null;

Parameters

ParameterTypeDescription
layoutLayoutDocument
categoryIdstring

Returns

{ readonly id: string; readonly label: string; } | null

@openseat/editor/src/ticket-types.ts

function

paintSeatNear

The paint tool's seat for a click at point on container (a section, row or table): the nearest drawn seat inside it, within a few seat sizes of the point. "far" when the click is well away from every seat (the section's title, an empty corner); null when the container has no seats to pick from (a zone section, whose seats are hidden, or an empty section), so the caller paints the container itself.

function paintSeatNear(
  index: LayoutIndex,
  container: LayoutObject,
  point: Point,
): string | "far" | null;

Parameters

ParameterTypeDescription
indexLayoutIndex
containerLayoutObject
pointPoint

Returns

string | "far" | null

@openseat/editor/src/store.ts

function

paintTargetsAt

The seats a paint click at point would change at level ("row": the whole row of the nearest seat, "seat": that seat, "section": every seat of its section), or null when no seat is near. The paint tool previews these under the pointer, and a click paints exactly them (the store's assignCategory picks the same nearest seat).

function paintTargetsAt(
  index: LayoutIndex,
  point: Point,
  level: "section" | "row" | "seat",
): { readonly seatId: string; readonly targets: readonly string[] } | null;

Parameters

ParameterTypeDescription
indexLayoutIndex
pointPoint
level"section" | "row" | "seat"

Returns

{ readonly seatId: string; readonly targets: readonly string[]; } | null

@openseat/editor/src/paint-targets.ts

function

parseClipboard

Parses clipboard text made by serializeClipboard. Returns null for anything else: text over MAX_CLIPBOARD_BYTES, more than MAX_PASTE_OBJECTS objects, text that is not JSON, a missing marker, a wrong format or version, an empty or missing object list, or any object (or category) that fails the layout schema. Bounds are recomputed when absent or malformed. Use readClipboardText for the reason.

function parseClipboard(
  text: string,
): EditorClipboardPayload | null;

Parameters

ParameterTypeDescription
textstring

Returns

@openseat/editor/src/clipboard.ts

function

plainErrorMessage

Turns the developer messages core throws ("updateSectionSeating needs valid seating: rows: A section may generate at most 20000 seats; this block has 766000") into sentences an organiser can act on ("That is too many seats for one section: 7,66,000. One section can hold up to 20,000 seats."). Messages that are already plain pass through unchanged.

function plainErrorMessage(message: string): string;

Parameters

ParameterTypeDescription
messagestring

Returns

string

@openseat/editor/src/plain-errors.ts

function

polygonFromPoints

Builds a polygon, section (custom outline) or zone (GA area) from points clicked in layout space. The origin is placed at the points' centre (a zone's at their centroid). Null for fewer than three points.

function polygonFromPoints(
  points: readonly Point[],
  layout: LayoutDocument,
  target?: "polygon" | "section" | "ga",
  opts?: { readonly capacity?: number; readonly zone?: ZoneSettings },
): LayoutObject | null;

Parameters

ParameterTypeDescription
pointsreadonly Point[]
layoutLayoutDocument
targetoptional"polygon" | "section" | "ga"

Default "polygon"

optsoptional{ readonly capacity?: number; readonly zone?: ZoneSettings; }

Default {}

Returns

@openseat/editor/src/tools.ts

function

priceNumber

The number in a price as typed or shown ("₹1,499" → 1499), or null.

function priceNumber(price: string): number | null;

Parameters

ParameterTypeDescription
pricestring

Returns

number | null

@openseat/editor/src/ticket-types.ts

function

readableLabelSize

Label text size that reads at about 16 screen pixels at zoom scale: 16 at 100% or more, 130 at 12%.

function readableLabelSize(scale: number | undefined): number;

Parameters

ParameterTypeDescription
scalenumber | undefined

Returns

number

@openseat/editor/src/tools.ts

function

readClipboardText

Parses clipboard text made by serializeClipboard, checking the size limits first: text over MAX_CLIPBOARD_BYTES and payloads of more than MAX_PASTE_OBJECTS objects are rejected with an error message before any object is validated. Other text (not ours, malformed) gives a null payload without an error.

function readClipboardText(text: string): ClipboardReadResult;

Parameters

ParameterTypeDescription
textstring

Returns

@openseat/editor/src/clipboard.ts

function

record

Adds an entry, clearing redo. Merges into the previous entry when the keys match and the new entry is within the merge window of the previous entry's first change (the window does not slide), and, with requireContinuity, when the new entry starts where the previous one ended.

While a gesture group is open (beginGroup), every entry after the group's first merges into the previous one regardless of keys and the window (continuity is still required when asked for).

function record(
  history: History,
  entry: HistoryEntry,
  options?: HistoryOptions,
): History;

Parameters

ParameterTypeDescription
historyHistory
entryHistoryEntry
optionsoptionalHistoryOptions

Default {}

Returns

@openseat/editor/src/history.ts

function

rectFromDrag

A rectangle section, zone (GA area) or rectangle shape spanning a drag from start to end. Both corners snap to opts.grid (0 disables snapping). Null when the result is smaller than 10 x 10, so a stray click creates nothing. A zone takes the shape (rectangle, rounded or trapezoid), seating and price tier of opts.zone; without it, the editor store applies the Zone tool's settings when the zone is added.

function rectFromDrag(
  kind: "section" | "ga" | "rectangle",
  start: Point,
  end: Point,
  layout: LayoutDocument,
  opts: {
    readonly grid: number;
    readonly capacity?: number;
    readonly zone?: ZoneSettings;
  },
): LayoutObject | null;

Parameters

ParameterTypeDescription
kind"section" | "ga" | "rectangle"
startPoint
endPoint
layoutLayoutDocument
opts{ readonly grid: number; readonly capacity?: number; readonly zone?: ZoneSettings; }

Returns

@openseat/editor/src/tools.ts

function

removeCategoryMovingTo

Removes a ticket type that is in use: what had it gets to (another ticket type) or none. The never-sold list drops it too.

function removeCategoryMovingTo(
  layout: LayoutDocument,
  id: string,
  to: string | null,
): LayoutDocument;

Parameters

ParameterTypeDescription
layoutLayoutDocument
idstring
tostring | null

Returns

@openseat/editor/src/ticket-types.ts

function

renameTypeAndZone

The layout with ticket type categoryId called typeName and area zoneId called zoneName.

function renameTypeAndZone(
  layout: LayoutDocument,
  categoryId: string,
  typeName: string,
  zoneId: string,
  zoneName: string,
): LayoutDocument;

Parameters

ParameterTypeDescription
layoutLayoutDocument
categoryIdstring
typeNamestring
zoneIdstring
zoneNamestring

Returns

@openseat/editor/src/ticket-types.ts

function

resolveShortcut

Maps a key press to an editor command. mac selects Cmd rather than Ctrl as the command modifier. Returns null for keys the editor does not handle, so they reach the browser and host app untouched. Enter finishes the current shape while ctx.drafting, and otherwise enters the selection's scope.

function resolveShortcut(
  e: KeyInput,
  mac: boolean,
  ctx?: ShortcutContext,
): EditorCommand | null;

Parameters

ParameterTypeDescription
eKeyInput
macboolean
ctxoptionalShortcutContext

Default {}

Returns

@openseat/editor/src/shortcuts.ts

function

revenueEstimate

Price × (seats + places + booths) for every sellable ticket type, so booth and stall income counts like seat income. Never-sold types count nothing, and neither do seats, places and booths marked Not for sale (counted in heldBack).

function revenueEstimate(
  layout: LayoutDocument,
  prices: Readonly<Record<string, string>> | undefined,
): RevenueEstimate;

Parameters

ParameterTypeDescription
layoutLayoutDocument
pricesReadonly<Record<string, string>> | undefined

Returns

@openseat/editor/src/ticket-types.ts

function

rowsInRange

The rows of sectionIds whose labels lie from from to to (inclusive, either order).

function rowsInRange(
  layout: LayoutDocument,
  sectionIds: readonly string[],
  from: string,
  to: string,
): string[];

Parameters

ParameterTypeDescription
layoutLayoutDocument
sectionIdsreadonly string[]
fromstring
tostring

Returns

string[]

@openseat/editor/src/row-range.ts

function

rowSpanText

"Rows A–D", "Row C": the range as organisers say it.

function rowSpanText(from: string, to: string): string;

Parameters

ParameterTypeDescription
fromstring
tostring

Returns

string

@openseat/editor/src/row-range.ts

function

sameDocument

True when two documents have the same content. Layout operations reuse unchanged objects, so only objects that differ by reference are compared by value: cheap for the few objects an inspector edit touches.

function sameDocument(
  a: LayoutDocument,
  b: LayoutDocument,
): boolean;

Parameters

ParameterTypeDescription
aLayoutDocument
bLayoutDocument

Returns

boolean

@openseat/editor/src/history.ts

function

samePriceGroups

Sellable ticket types with the same price (by amount, so "250" and "₹250" match) that are both on the map. Free types (price 0) are left out: a free Guests type next to a free Press type is on purpose.

function samePriceGroups(
  layout: LayoutDocument,
  prices: Readonly<Record<string, string>> | undefined,
): SamePriceGroup[];

Parameters

ParameterTypeDescription
layoutLayoutDocument
pricesReadonly<Record<string, string>> | undefined

Returns

@openseat/editor/src/ticket-types.ts

function

saveRemovalMessage

What the save removes, in plain words and without IDs: "Row C, Seat 5 (Stalls) and 3 more will be removed. 2 of them have tickets sold or held; those buyers will need new seats."

function saveRemovalMessage(diff: PendingSaveDiff): string;

Parameters

ParameterTypeDescription
diffPendingSaveDiff

diff takes PendingSaveDiff:

Returns

string

@openseat/editor/src/react/SaveRemovalDialog.tsx

function

seatLabel

A seat as a person names it: "Row A, Seat 10", or "Table T3, Seat 2". When another seat in the layout has the same name, its section follows: "Row A, Seat 10 (Stalls)".

function seatLabel(layout: LayoutDocument, seat: Seat): string;

Parameters

ParameterTypeDescription
layoutLayoutDocument
seatSeat

Returns

string

@openseat/editor/src/human-labels.ts

function

seatNearPoint

The visible seat nearest point (layout space), when it lies within three seat sizes of it; seats of zone sections (not drawn) are skipped. This is the seat a paint click at point means, whichever row's or section's outline the click landed on: with curved rows, the outline of the row above can cover the middle of the row the organiser sees under the pointer.

function seatNearPoint(
  index: LayoutIndex,
  point: Point,
): string | null;

Parameters

ParameterTypeDescription
indexLayoutIndex
pointPoint

Returns

string | null

@openseat/editor/src/store.ts

function

seatRange

The seats from anchorId to id inclusive, in the slot order of the row (or table) that holds both, for Shift-click range selection. The result runs from the anchor towards id. Empty when either is not a seat or the two are not in the same row or table.

function seatRange(
  layout: LayoutDocument,
  anchorId: string,
  id: string,
): string[];

Parameters

ParameterTypeDescription
layoutLayoutDocument
anchorIdstring
idstring

Returns

string[]

@openseat/editor/src/selection.ts

function

seatToolAction

What a seat-tool click at point does. A click near the extrapolated next slot past either end of a row (rows with at least two seats; within tolerance, default 1.5 x the row's seat pitch, and nearer that slot than the row's end seat) extends that row; otherwise a single seat is created at the (grid-snapped) point. Locked and hidden rows are never extended.

function seatToolAction(
  layout: LayoutDocument,
  point: Point,
  opts: {
    readonly grid: number;
    readonly tolerance?: number;
    readonly seatRadius?: number;
  },
): SeatToolAction;

Parameters

ParameterTypeDescription
layoutLayoutDocument
pointPoint
opts{ readonly grid: number; readonly tolerance?: number; readonly seatRadius?: number; }

Returns

@openseat/editor/src/tools.ts

function

sectionRowLabels

The row labels of the given sections, each once, in compareRowLabels order ("A" … "J"), for picking "rows A to D".

function sectionRowLabels(
  layout: LayoutDocument,
  sectionIds: readonly string[],
): string[];

Parameters

ParameterTypeDescription
layoutLayoutDocument
sectionIdsreadonly string[]

Returns

string[]

@openseat/editor/src/row-range.ts

function

selectableUnits

The selectable units of the current scope, in document order, without effectively locked or hidden objects:

  • inside a row or table (scopeGroupId): its seats;
  • seat granularity: every seat (of the scoped section, when there is one);
  • inside a section: its rows, tables, GA areas and loose seats;
  • at the top level: every object that has no parent (sections, rows and tables outside sections, loose seats, stages, labels, ...).
function selectableUnits(
  layout: LayoutDocument,
  ctx: HitContext,
): string[];

Parameters

ParameterTypeDescription
layoutLayoutDocument
ctxHitContext

Returns

string[]

@openseat/editor/src/selection.ts

function

selectionBounds

Bounds of objects together with everything they carry (a table with its chairs, a section with its rows).

function selectionBounds(
  layout: LayoutDocument,
  ids: readonly string[],
): Bounds | null;

Parameters

ParameterTypeDescription
layoutLayoutDocument
idsreadonly string[]

Returns

Bounds | null

@openseat/editor/src/selection.ts

function

setCategoryOnRowRange

Gives the rows labelled from to to (either way round) of each of sectionIds the ticket type (null clears it), as one undo step: "front 4 rows VIP" across four blocks in one go. Locked rows are left alone. Returns false (with a message) when nothing changed.

function setCategoryOnRowRange(
  store: EditorStore,
  sectionIds: readonly string[],
  from: string,
  to: string,
  categoryId: string | null,
): boolean;

Parameters

ParameterTypeDescription
storeEditorStore
sectionIdsreadonly string[]
fromstring
tostring
categoryIdstring | null

Returns

boolean

@openseat/editor/src/row-range.ts

function

shortcutText

The key text for a command on one platform (its first binding there), or null when it has no key. Nudge reads "Arrows"; tools have their own keys (TOOL_KEYS).

function shortcutText(
  id: EditorCommand["type"],
  mac: boolean,
): string | null;

Parameters

ParameterTypeDescription
idEditorCommand["type"]
macboolean

Returns

string | null

@openseat/editor/src/commands.ts

function

snapAngle

A rotation angle in degrees, rounded to 15° steps while Shift is held.

function snapAngle(deg: number, shift: boolean): number;

Parameters

ParameterTypeDescription
degnumber
shiftboolean

Returns

number

@openseat/editor/src/snapping.ts

function

snapMove

Snaps a drag on each axis independently. Alignment to another object's left/centre/right (or top/middle/bottom), or to an extra lines target, wins when within threshold, and produces a guide line; otherwise the anchor snaps to the grid.

Modifiers: Alt returns the raw delta with no guides. Shift first projects the delta onto the nearest 45° direction and keeps it there: horizontal and vertical moves snap only along their axis, diagonal moves snap one axis (alignment preferred) and derive the other.

function snapMove(input: SnapInput): SnapResult;

Parameters

ParameterTypeDescription
inputSnapInput

input takes SnapInput:

Returns

@openseat/editor/src/snapping.ts

function

snapPoint

Snaps a single point (a drawing click or drag corner) on each axis: to the nearest target coordinate within threshold (with a guide), otherwise to the grid. With alt the point is returned unchanged with no guides.

function snapPoint(
  point: Point,
  ctx: SnapPointContext,
): { point: Point; guides: Guide[] };

Parameters

ParameterTypeDescription
pointPoint
ctxSnapPointContext

Returns

{ point: Point; guides: Guide[]; }

@openseat/editor/src/snapping.ts

function

ticketAmounts

Per ticket type: the seats buyers pick, the places of zones and of sections sold as a zone (their capacity, not their hidden seats), and the booths. A zone map's ticket types used to read "0 seats", and booth types "0 seats" and ₹0 revenue. What is held back from sale (Not for sale on the map, or a never-sold type) goes to held, not to the counts: three sponsor booths marked Not for sale are not three booths to sell.

function ticketAmounts(
  layout: LayoutDocument,
): Map<string, TicketAmount>;

Parameters

ParameterTypeDescription
layoutLayoutDocument

Returns

Map<string, TicketAmount>

@openseat/editor/src/ticket-types.ts

function

ticketCount

Tickets of a type: seats + places + booths (a booth is one ticket, bought by an exhibitor). Held-back ones are not tickets.

function ticketCount(a: TicketAmount | undefined): number;

Parameters

ParameterTypeDescription
aTicketAmount | undefined

Returns

number

@openseat/editor/src/ticket-types.ts

function

uniqueRowPrefix

An ID prefix (block1, block2, …) no object in the layout uses yet.

function uniqueRowPrefix(layout: LayoutDocument): string;

Parameters

ParameterTypeDescription
layoutLayoutDocument

Returns

string

@openseat/editor/src/row-drawing.ts

function

unitPivot

The point an object rotates about when its rotation is typed in: a row turns about the centre of its seats' bounds, everything else about its position. Null for unknown IDs.

function unitPivot(
  layout: LayoutDocument,
  id: string,
): Point | null;

Parameters

ParameterTypeDescription
layoutLayoutDocument
idstring

Returns

Point | null

@openseat/editor/src/selection.ts

function

venueSnapLines

The venue outline's left, centre and right x and top, middle and bottom y, as snap lines. Empty without a venue.

function venueSnapLines(venue: Venue | undefined): Guide[];

Parameters

ParameterTypeDescription
venueVenue | undefined

Returns

@openseat/editor/src/snapping.ts

function

withCategorySellable

The layout with ticket type id sold (sellable true: removed from metadata.openseat.unsellableCategories) or never sold (added). The same layout object when nothing changes.

function withCategorySellable(
  layout: LayoutDocument,
  id: string,
  sellable: boolean,
): LayoutDocument;

Parameters

ParameterTypeDescription
layoutLayoutDocument
idstring
sellableboolean

Returns

@openseat/editor/src/ticket-types.ts

function

withStageShape

A stage with another outline shape. "rect" removes shape (and the runway); "thrust" keeps or sets the runway (thrust replaces it, null removes it so the default size applies). Never touches the style, so the theme's stage look applies to stages without one.

function withStageShape(
  stage: Stage,
  shape: StageShape,
  thrust?: StageThrust | null,
): Stage;

Parameters

ParameterTypeDescription
stageStage
shapeStageShape
thrustoptionalStageThrust | null

Returns

@openseat/editor/src/tools.ts

function

zoneDraftRect

The drawn rectangle of a zone made without the tool's settings, or undefined.

function zoneDraftRect(
  obj: LayoutObject,
):
  | {
      readonly x: number;
      readonly y: number;
      readonly width: number;
      readonly height: number;
    }
  | undefined;

Parameters

ParameterTypeDescription
objLayoutObject

Returns

{ readonly x: number; readonly y: number; readonly width: number; readonly height: number; } | undefined

@openseat/editor/src/tools.ts

function

zoneFromRect

A new zone (GA area, not yet added) filling rect, made by core createZone: rectangle, rounded rectangle or trapezoid (a polygon shape here gives a rectangle; use zoneFromPoints for clicked corners), labelled "Zone N", seated by default, with the capacity and price tier of settings.

function zoneFromRect(
  layout: LayoutDocument,
  rect: {
    readonly x: number;
    readonly y: number;
    readonly width: number;
    readonly height: number;
  },
  settings?: ZoneSettings,
): GaArea;

Parameters

ParameterTypeDescription
layoutLayoutDocument
rect{ readonly x: number; readonly y: number; readonly width: number; readonly height: number; }
settingsoptionalZoneSettings

Default {}

Returns

@openseat/editor/src/tools.ts

Interfaces51

interface

AddZoneOptions

A zone to add with EditorActions.addZone. Unset fields come from the Zone tool's settings.

interface AddZoneOptions

Members

MemberTypeDescription
shapeoptionalZoneShape
rectoptional{ readonly x: number; readonly y: number; readonly width: number; readonly height: number; }

World rectangle for rect, rounded and trapezoid zones (top-left corner and size).

pointsoptionalreadonly Point[]

World corners for a polygon zone (at least 3).

labeloptionalstring

Default "Zone N".

Default "Zone N"

capacityoptionalnumber
seatingoptionalGaSeating
categoryIdoptionalstring | null

Price tier (category ID); null for none.

Every member is readonly.

@openseat/editor/src/store.ts

interface

ApplyOptions

interface ApplyOptions

Members

MemberTypeDescription
mergeKeyoptionalstring

Collapse consecutive changes with the same key into one undo step.

selectionoptionalreadonly string[] | ((after: LayoutDocument) => readonly string[])

Selection after the change, or a function of the new layout. Defaults to the current selection, minus anything deleted.

messageoptionalstring | ((after: LayoutDocument) => string)

Status message after the change, or a function of the new layout. Defaults to the label.

Every member is readonly.

@openseat/editor/src/store.ts

interface

ArcDrawingSettings

interface ArcDrawingSettings

Members

MemberTypeDescription
rowSpacingnumber
seatSpacingnumber
seatRadiusnumber
rowLabelingRowLabeling
seatLabelingSeatLabeling

Every member is readonly.

@openseat/editor/src/tools.ts

interface

BlockPanelProps

interface BlockPanelProps

Members

MemberTypeDescription
blockIdreadonlystring

@openseat/editor/src/react/templates/BlockPanel.tsx

interface

ClipboardReadResult

What readClipboardText found: a payload, or null with an error for text that is ours but over a limit.

interface ClipboardReadResult

Members

MemberTypeDescription
payloadEditorClipboardPayload | null
errorstring | null

Set when the text was rejected for its size or object count (shown to the user).

Every member is readonly.

@openseat/editor/src/clipboard.ts

interface

CommandInfo

The editor's command reference: a label, a group and the key binding (if any) of every EditorCommand. Used by the shortcut help overlay, context menus and docs. Key texts come from SHORTCUT_BINDINGS, the table resolveShortcut itself runs on, so they cannot drift.

interface CommandInfo

Members

MemberTypeDescription
idEditorCommand["type"]
labelstring
group"edit" | "arrange" | "view" | "rows" | "sections" | "tools"
keysoptional{ readonly mac: string; readonly other: string; }

Every member is readonly.

@openseat/editor/src/commands.ts

interface

CurrencyChoice

One currency a host offers for ticket prices ("INR", "₹ Indian rupee").

interface CurrencyChoice

Members

MemberTypeDescription
codestring
labelstring

Every member is readonly.

@openseat/editor/src/react/context.ts

interface

CurrencyControl

The host's ticket-price currency, shown as a picker at the top of the Ticket types panel (LayoutEditor's currency). Prices are the host's, so is the currency: the editor only shows the choice and reports a change.

interface CurrencyControl

Members

MemberTypeDescription
codestring

The current currency code ("INR").

optionsreadonly CurrencyChoice[]
onChange(code: string) => void

Every member is readonly.

@openseat/editor/src/react/context.ts

interface

DeletionSummary

What deleting the selection would affect, so the UI can confirm first.

interface DeletionSummary

Members

MemberTypeDescription
sectionsnumber

Selected sections.

seatsInSectionsnumber

Seats inside the selected sections (deleted with them unless withContents is false).

lockednumber

Effectively locked objects that delete would skip.

Every member is readonly.

@openseat/editor/src/store.ts

interface

DestructiveChange

A change that can remove sold inventory: replacing the layout with a venue template, rebuilding a template layout, or regenerating a table or booth block so that places disappear.

interface DestructiveChange

Members

MemberTypeDescription
kind"template-replace" | "template-rerun" | "block-regenerate"
removedInventoryIdsreadonly string[]

Inventory keys (seat IDs, booth and standing-area ticket IDs, whole-table IDs) the change removes.

Every member is readonly.

@openseat/editor/src/react/context.ts

interface

DragRect

A press-drag-release on the canvas, in layout coordinates.

interface DragRect

Members

MemberTypeDescription
startPoint
endPoint

Every member is readonly.

@openseat/editor/src/tools.ts

interface

DragShapeState

What dragShapeFor reads: the editor state, or just the parts it needs.

interface DragShapeState

Members

MemberTypeDescription
layoutLayoutDocument
toolOptionsoptionalToolOptions
snapToGridoptionalboolean

Snap both corners to the layout grid. Default false.

Default false

Every member is readonly.

@openseat/editor/src/tools.ts

interface

DrawBlockInput

interface DrawBlockInput extends RowDrawingSettings

Extends RowDrawingSettings

Members

MemberTypeDescription
startPoint

Press point: the first seat of the first row (snapped to grid).

endPoint

Current pointer: the opposite corner of the block.

curvaturenumber

Block curvature, -100..100; clamped so the back row never collapses.

gridnumber

Grid size to snap the start point to. 0 disables snapping.

layoutLayoutDocument
rowLabelingRowLabeling
seatLabelingSeatLabeling
alignoptional"left" | "center" | "right"

How rows of different length line up. Defaults to "center".

Default "center"

intoSectionIdoptionalstring | null

Add plain rows to this existing section instead of creating a new section.

seatSpacingnumber

Distance between seat centres along a row.

From RowDrawingSettings

rowSpacingnumber

Distance between rows.

From RowDrawingSettings

seatRadiusnumber

From RowDrawingSettings

Every member is readonly.

@openseat/editor/src/row-drawing.ts

interface

DrawingDefaults

Settings used when drawing rows and making sections parametric.

interface DrawingDefaults

Members

MemberTypeDescription
seatSpacingnumber

Distance between neighbouring seat centres.

rowSpacingnumber

Distance between neighbouring rows.

seatRadiusnumber
curvaturenumber

-100..100; 0 is straight.

rowLabelingRowLabeling
seatLabelingSeatLabeling

@openseat/editor/src/store.ts

interface

DrawnBlock

interface DrawnBlock

Members

MemberTypeDescription
objectsLayoutObject[]
sectionIdstring | null

The new section, or null when rows were drawn into an existing one.

rowsnumber
seatsPerRownumber
summarystring

Size as "rows × seats", e.g. "4 × 12".

labelPointPoint

Where to show the floating size hint (the pointer).

Every member is readonly.

@openseat/editor/src/row-drawing.ts

interface

DrawnRows

interface DrawnRows

Members

MemberTypeDescription
objectsLayoutObject[]
seatsPerRownumber
rowCountnumber
anglenumber

Direction of the rows in degrees, screen convention (0 points right, 90 down).

summarystring

Human-readable size, e.g. "3 rows × 12 seats".

Every member is readonly.

@openseat/editor/src/row-drawing.ts

interface

DrawRowsInput

interface DrawRowsInput extends RowDrawingSettings

Extends RowDrawingSettings

Members

MemberTypeDescription
startPoint

Where the drag started: the first seat of the first row.

endPoint

Where the drag is now: the first row runs from start towards this point.

sideoptionalPoint

After the drag, the pointer position: rows are added towards it, one per rowSpacing.

idPrefixstring
gridnumber

Grid size to snap the start point to. 0 disables snapping.

curvatureoptionalnumber

Block curvature, -100..100 (0 straight). Positive bends the rows around a centre on the far side of the first row from the added rows, so further rows are concentric and longer in radius; negative bends the other way.

rowLabelingoptionalRowLabeling

Row label sequence. Defaults to A, B, C… from the first drawn row.

seatLabelingoptionalSeatLabeling

Seat numbering, stored on each row's layout. Defaults to 1, 2, 3… from the start of the drag.

firstRowLabeloptionalstring

Label of the first row ("K", "12", "IV"); further rows follow the labeling from there.

sectionIdoptionalstring

Section the rows (and their seats) belong to.

layoutoptionalLayoutDocument

The document the rows will join. When given (and firstRowLabel is not), row labels skip those already used by rows of the same section, so new rows continue after existing ones.

seatSpacingnumber

Distance between seat centres along a row.

From RowDrawingSettings

rowSpacingnumber

Distance between rows.

From RowDrawingSettings

seatRadiusnumber

From RowDrawingSettings

Every member is readonly.

@openseat/editor/src/row-drawing.ts

interface

EditorActions

interface EditorActions

Members

MemberTypeDescription
applymethod(label: string, update: (layout: LayoutDocument) => LayoutDocument, options?: ApplyOptions) => boolean

Applies a change as one undoable step. Returns false when nothing changed. Auto outlines are refreshed in the same step. A RangeError thrown by update (invalid input to a core operation) is shown as the message and leaves the layout unchanged.

dismissFreeformNoticemethod() => void

Hides the freeform notice.

undomethod() => void
redomethod() => void
beginGesturemethod(key: string) => void

Opens a gesture (a slider drag, a handle drag): every edit until endGesture becomes one undo step, however long it takes. Opening one with another key closes the open one first. Undo closes it.

endGesturemethod() => void

Closes the open gesture, if any.

selectmethod(ids: readonly string[], mode?: "replace" | "add" | "toggle") => void
selectAllmethod() => void

Selects the units of the current scope, without locked and hidden objects.

selectSameTypemethod() => void

Selects every unit of the current scope with the same type as a selected object.

setToolmethod(tool: ToolId) => void
setToolOptionsmethod(patch: { readonly [K in keyof ToolOptions]?: Partial<ToolOptions[K]>; }) => void
setDrawingDefaultsmethod(patch: Partial<DrawingDefaults>) => void
setLastPointermethod(point: Point | null) => void
setDraftTargetmethod(target: DraftTarget) => void
setSnapToGridmethod(enabled: boolean) => void
setAlignToObjectsmethod(enabled: boolean) => void
setMessagemethod(message: string) => void
resolveTargetmethod(hitId: string) => string | null

The object a click on hitId selects in the current scope and granularity, or null.

clickObjectmethod(hitId: string, opts?: { readonly additive?: boolean; readonly range?: boolean; readonly point?: Point; }) => void

Click on an object: select its target; additive toggles it, range selects seats from the last clicked seat. point (layout coordinates) is where the click landed: selecting seats, a click on a section's empty area beside a seat (between curved rows) takes that nearest seat (seatNearPoint).

seatForClickAtmethod(point: Point) => string | null

The seat a seat-granularity click at point means when it hit no seat: the nearest seat within reach that the current scope lets a click select (not locked or hidden), else null.

doubleClickObjectmethod(hitId: string) => void

Double-click: enter a section, row or table (selecting what was hit inside), or edit a shape's outline.

selectMarqueemethod(rawIds: readonly string[], additive: boolean) => void

Selection from a marquee that fully contains rawIds. Locked and hidden objects are skipped.

enterScopemethod(id?: string) => void

Enters a section, row or table (default: the single selected one). Clears the selection.

exitScopemethod() => void

Leaves the row or table scope first, then the section scope, selecting what was left.

exitAllScopesmethod() => void

Back to the whole map in one step: leaves the row, table and section scopes and seat mode (the seat-selection tool), selecting the outermost object that was entered.

addObjectsmethod(label: string, objects: readonly LayoutObject[]) => void
movemethod(ids: readonly string[], delta: Point) => void
transformmethod(id: string, transform: ObjectTransform) => void
setObjectPositionmethod(id: string, position: Point, opts?: { readonly mergeKey?: string; }) => void

Moves an object (with what it carries) so its position is position.

setObjectRotationmethod(id: string, rotation: number, opts?: { readonly mergeKey?: string; }) => void

Rotates an object (with what it carries) to an absolute rotation about its pivot.

transformSelectionmethod(t: SelectionTransform, label?: string) => void
rotateSelectionmethod(deg: number) => void

Rotates the selection by deg degrees about the centre of its bounds.

flipSelectionmethod(axis: "horizontal" | "vertical") => void
deletionSummarymethod() => DeletionSummary
deleteSelectionmethod(opts?: { readonly withContents?: boolean; }) => void

Deletes the selection. A section takes its contents unless withContents is false. Locked objects stay.

duplicateSelectionmethod(opts?: { readonly offset?: Point; }) => void
nudgeSelectionmethod(dx: number, dy: number) => void
alignSelectionmethod(edge: AlignEdge) => void
distributeSelectionmethod(axis: "x" | "y") => void
setVisiblemethod(ids: string | readonly string[], visible: boolean) => void
setLockedmethod(ids: string | readonly string[], locked: boolean) => void
reorderSelectionmethod(direction: ReorderDirection) => void
copySelectionmethod() => EditorClipboardPayload | null
cutSelectionmethod() => void
pastemethod(opts?: { readonly payload?: EditorClipboardPayload; readonly at?: Point; readonly inPlace?: boolean; }) => void

Pastes at at (or the last pointer). A cut payload keeps its IDs when they are free.

updateRowsmethod(rowIds: readonly string[], patch: RowPatch, opts?: { readonly mergeKey?: string; }) => void
insertSeatsmethod(rowId: string, atSlot: number, count?: number) => void
removeSeatsFromRowsmethod(seatIds: readonly string[], mode: "close-gap" | "keep-positions") => void
extendRowmethod(rowId: string, end: "start" | "end", count: number) => void
splitRowmethod(rowId: string, afterIndex: number) => void
mergeSelectedRowsmethod() => void
reverseRowmethod(rowId: string) => void
straightenRowmethod(rowId: string) => void
detachRowLayoutmethod(rowId: string) => void
extractSeatsmethod(seatIds: readonly string[], asRow: boolean) => void
groupSelectionIntoRowmethod(rowLabel?: string) => void
relabelRowsmethod(rowIds: readonly string[], spec: RowLabeling, opts?: { readonly mergeKey?: string; }) => void
relabelSeatsmethod(target: { readonly groupIds?: readonly string[]; readonly seatIds?: readonly string[]; }, spec: SeatLabeling) => void
setRowLabelmethod(rowId: string, label: string, opts?: { readonly mergeKey?: string; }) => void
setSeatLabelmethod(seatObjectId: string, label: string, opts?: { readonly mergeKey?: string; }) => void

Sets a seat's label by hand; relabeling leaves it alone afterwards.

resetSeatLabelmethod(seatId: string) => void

Gives a hand-labelled seat its automatic label back (its row's numbering for its slot) and clears labelLocked.

addSeatsToRowmethod(seatIds: readonly string[], rowId: string) => void

Moves seats into a row (by their position along it). A parametric section holding the row becomes freeform, since regenerating it would drop them.

setSeatIdmethod(seatObjectId: string, seatId: string) => { readonly ok: boolean; readonly error?: string; }

Changes a seat's public ID. Rejects empty and duplicate values.

updateSectionSeatingmethod(sectionId: string, patch: Partial<SectionSeating>, opts?: { readonly mergeKey?: string; }) => void
makeSectionParametricmethod(sectionId: string) => void

Gives a section without seating a fill seating from the drawing defaults.

detachSectionSeatingmethod(sectionId: string) => void

Drops a section's parametric seating; its rows and seats stay as they are.

createSectionFromSelectionmethod(opts?: SectionFromSelectionOptions) => void
dissolveSectionmethod(id: string) => void
convertToSectionmethod(objectId: string) => void
setSectionMembershipmethod(ids: readonly string[], sectionId: string | null) => void
syncSectionMembershipmethod(sectionId: string) => void

Makes the section's members exactly what lies inside its outline.

setVertexEditingmethod(id: string | null) => void
moveVertexmethod(objectId: string, index: number, world: Point, opts?: { readonly mergeKey?: string; }) => boolean

Moves an outline point. False when the edit was rejected (self-intersecting, locked, ...).

insertVertexmethod(objectId: string, edgeIndex: number, world?: Point) => boolean
removeVertexmethod(objectId: string, index: number) => boolean
updateTablemethod(tableId: string, patch: TableEditPatch, opts?: { readonly mergeKey?: string; readonly grow?: boolean; }) => { readonly clamped: boolean; }

Edits a table's shape and seats. grow (default true) enlarges a table too small for its seats.

addCategorymethod(name: string, opts?: { readonly colour?: string; }) => string

Adds a ticket type (category) as one undo step, "Add ticket type". Its ID is a slug of name, made unique; its colour is opts.colour or the next free palette colour (nextCategoryColour). With the paint tool active, the new type becomes the one painted. Returns the new ID, or "" when it could not be added (the reason is the message).

addCategoriesmethod(entries: readonly { readonly name: string; readonly colour?: string; }[]) => string[]

Adds several ticket types (price tiers such as Gold and Silver) as one undo step. Names already used (ignoring case) are skipped. Returns the IDs of the added types.

assignCategorymethod(hitId: string, categoryId: string | null, level: "section" | "row" | "seat", point?: Point) => void

Paints a category on the section, row or seat under hitId (null clears it). With point (where the click landed) and the Row or Seat level, a hit on a whole section (seats too small to hit at this zoom, or the gap between two seats) paints the row or seat nearest the point, not the whole section.

setCategoryOnSelectionmethod(categoryId: string | null) => void

Sets the category of the selection, cascading to the seats of rows, tables and sections.

setNotForSalemethod(ids: readonly string[], notForSale: boolean) => boolean

Marks seats, rows, sections, tables, booths or zones Not for sale (they stay on the map, greyed out, and buyers can't select them), or puts them back on sale, as one undo step. Categories are not changed. Other objects in ids are ignored. Putting an object back on sale releases only that object: when its row or section was held back as a whole, the rest of it stays held back. The message names what changed: "Booth B7 is not for sale.", "4 seats are available again." Returns false when nothing changed.

setObjectNamemethod(id: string, name: string, opts?: { readonly mergeKey?: string; }) => void

Sets an object's name (empty removes it) and the text of its name label on the map, if it has one (setNameOnMap).

setNameOnMapmethod(id: string, show: boolean) => void

Shows or hides the name of a shape, aisle or path on the map, as a text label at its centre (mapNameLabelId). One undo step.

setVenuemethod(venue: Venue | null, opts?: { readonly mergeKey?: string; }) => void
setFocalPointmethod(point: Point | null, opts?: { readonly mergeKey?: string; }) => void
clearLayoutmethod() => void

Removes every object, the venue and the focal point. Categories stay.

addDraftPointmethod(point: Point) => void

Adds a point to the shape being drawn. A click near the first point closes a polygon (three points or more); while drawing a floor divider (the divider tool), a click near the last point finishes it (two points or more).

finishDraftmethod() => void
cancelDraftmethod() => void
setSectionShowSeatsmethod(ids: readonly string[], show: boolean) => void

Switches sections between seats ("Seats", show true) and "Zone only" (sold by quantity, seats kept but not drawn), as one undo step. Seat IDs are never changed, so switching back restores them exactly. Selected rows and seats of a section that becomes a zone give way to the section.

setZoneCapacitymethod(id: string, capacity: number | null, opts?: { readonly mergeKey?: string; }) => void

Sets a zone's capacity: a zone section's (null removes the override, so it follows the seat count) or a drawn zone's. Typing is one undo step.

addZonemethod(opts?: AddZoneOptions) => string | null

Adds a zone (core createZone) with the Zone tool's settings for anything not given. Returns its ID, or null.

addDividermethod(points: readonly Point[], caption?: string) => string | null

Adds a floor divider through points (at least 2) with caption (default "GROUND FLOOR"), selects it and asks the inspector to focus its caption. Returns its ID, or null.

addFootnotemethod(text?: string) => string | null

Adds note text (default "Type your note here") centred under the content, selected with its text box focused. Returns its ID, or null.

setStageShapemethod(id: string, shape: StageShape, thrust?: StageThrust | null, opts?: { readonly mergeKey?: string; }) => void

Changes a stage's outline: rectangle, thrust (T), round or semicircle. thrust sizes a thrust stage's runway (null removes it, so the default size applies). The style is left alone.

clearFocusRequestmethod() => void

Clears focusRequest once the field has focus.

loadmethod(layout: LayoutDocument, options?: { readonly keepHistory?: boolean; }) => void

Replaces the layout outside history, for example after loading from a server.

importJsonmethod(json: string) => ValidationResult

Parses JSON and, when valid, replaces the layout's contents as one undoable step. The document keeps its own ID and base revision, so an imported file can never overwrite another stored layout. JSON over MAX_IMPORT_BYTES is rejected.

exportJsonmethod() => { readonly json: string | null; readonly errors: readonly LayoutIssue[]; }

Serialises the layout when it is valid; otherwise returns the errors.

savemethod(opts?: { readonly confirmRemovals?: boolean; }) => Promise<void>

Saves through the host's handler. When the save would remove seats from the inventory (compared with lastSavedLayout), it stops and sets pendingSaveDiff instead, unless confirmRemovals is set.

cancelPendingSavemethod() => void

Drops a save waiting for confirmation.

requestDialogmethod(kind: EditorDialogRequest) => void

Asks the editor UI to open a dialog (sets requestedDialog).

clearRequestedDialogmethod() => void

Clears requestedDialog, once the UI has opened it.

resolveConflictmethod(choice: "overwrite" | "load-remote" | "cancel") => Promise<void>

After a conflict: overwrite the newer version, or load it (undoable, so local work is not lost).

Every member is readonly.

@openseat/editor/src/store.ts

interface

EditorContextValue

interface EditorContextValue

Members

MemberTypeDescription
storeEditorStore
map{ readonly current: SeatMapHandle | null; }

Imperative access to the canvas, for zoom controls and scrolling to objects.

zoomZoomSource
uiEditorUi

Every member is readonly.

@openseat/editor/src/react/context.ts

interface

EditorScope

Where the user is editing. At the top level a click selects whole sections; inside a section (sectionId) it selects rows, tables and GA areas; inside a row or table (groupId) it selects seats.

interface EditorScope

Members

MemberTypeDescription
sectionIdstring | null
groupIdstring | null

Every member is readonly.

@openseat/editor/src/store.ts

interface

EditorState

interface EditorState

Members

MemberTypeDescription
layoutLayoutDocument
selectionreadonly string[]
toolToolId
historyHistory
baseRevisionnumber

Revision of the stored layout these edits are based on.

savedLayoutLayoutDocument

The layout as last saved or loaded. The editor is dirty when layout !== savedLayout.

lastSavedLayoutLayoutDocument | null

The layout the server holds as far as the editor knows: the initial layout, then the last one loaded, saved or loaded after a conflict. Saves diff the inventory against it.

pendingSaveDiffPendingSaveDiff | null

Set when save() stopped because seats would be removed; save({ confirmRemovals: true }) goes ahead.

saveStatusSaveStatus
snapToGridboolean
alignToObjectsboolean
draftreadonly Point[]

Points of a polygon being drawn.

messagestring

Short message for the status bar and screen readers.

scopeEditorScope

The section, row or table being edited ("entered").

granularitySelectionGranularity

"seats" with the seat-selection tool or inside a row or table.

toolOptionsToolOptions
drawingDefaultsDrawingDefaults
clipboardEditorClipboardPayload | null

Last copied or cut objects.

vertexEditIdstring | null

Object whose outline points are being edited.

draftTargetDraftTarget

What finishDraft creates.

lastPointerPoint | null

Last pointer position in layout coordinates; paste goes there.

freeformNoticestring | null

Set when an edit turned parametric sections freeform (their block, arc or fill settings are gone), e.g. "Section 1 is now freeform." Shown with an Undo button until dismissed, undone, or another kind of edit.

requestedDialogEditorDialogRequest | null

A dialog waiting to be opened by the editor UI (EditorActions.requestDialog).

focusRequeststring | null

The data-testid of an inspector field to focus next, such as "divider-caption" after a floor divider is drawn. The inspector focuses it and calls EditorActions.clearFocusRequest.

Every member is readonly.

@openseat/editor/src/store.ts

interface

EditorStoreOptions

interface EditorStoreOptions

Members

MemberTypeDescription
layoutLayoutDocument
onSaveoptionalSaveHandler
onChangeoptional(layout: LayoutDocument) => void

Called after every change to the layout, including undo, redo and load.

historyoptionalHistoryOptions
defaultsoptionalPartial<DrawingDefaults>

Drawing defaults (seat and row spacing, numbering) for this editor.

nowoptional() => number

Clock, for tests.

isInventoryInUseoptionalInventoryInUseCheck

Which removed seat IDs have tickets sold or held. With it, a save that removes only unsold seats goes ahead without asking, and the confirmation names the sold ones. Without it, every save that removes seats asks first.

Every member is readonly.

@openseat/editor/src/store.ts

interface

EditorUi

Editor-level UI actions for panels rendered inside the editor.

interface EditorUi

Members

MemberTypeDescription
openDialogmethod(kind: EditorDialogKind, origin?: Point) => void

Opens a dialog. origin (layout coordinates) is where the rows dialog and booth grid place their objects; it defaults to the centre of the view.

runCommandmethod(cmd: EditorCommand) => void

Runs an editor command exactly as its keyboard shortcut does, including any confirmation (deleting a section with seats asks first). Toolbar and palette buttons go through here so they behave like the keys.

categoryPricesoptionalReadonly<Record<string, string>>

Host-owned display prices per category ID (LayoutEditor's categoryPrices).

onCategoryPricesChangeoptional(next: Record<string, string>) => void

Present when the host lets the categories editor change prices (LayoutEditor's onCategoryPricesChange).

onBeforeDestructiveChangeoptionalDestructiveChangeHook

The host's guard for changes that remove inventory (LayoutEditor's onBeforeDestructiveChange).

pricingFocusRequestoptionalnumber

Counts requests for the pricing step: each increase asks the layout panel's ticket-type editor to focus its first price field. Undefined in editors that predate it.

requestPricingFocusoptionalmethod() => void

Asks the ticket-type editor to focus its first sellable price field (the pricing step).

currencyoptionalCurrencyControl

The host's price currency and its picker (LayoutEditor's currency).

Every member is readonly.

@openseat/editor/src/react/context.ts

interface

History

interface History

Members

MemberTypeDescription
pastreadonly HistoryEntry[]
futurereadonly HistoryEntry[]
groupoptionalHistoryGroup | null

The open gesture group, if any (see beginGroup).

sealedoptionalboolean

Set by undo and redo: the next entry starts a new step even when its merge key matches, so an edit after undo/redo never folds into the step that was just undone or redone.

Every member is readonly.

@openseat/editor/src/history.ts

interface

HistoryEntry

One undoable change. Entries store before/after document snapshots. Layout operations are immutable and reuse unchanged objects, so a snapshot costs one array of references, not a deep copy: a 2,000-object layout adds about 16 KB per entry.

interface HistoryEntry

Members

MemberTypeDescription
labelstring
beforeLayoutDocument
afterLayoutDocument
selectionBeforereadonly string[]
selectionAfterreadonly string[]
mergeKeyoptionalstring

Consecutive entries with the same key, recorded within the merge window, collapse into one. The inspector uses this so typing "120" in a field is one undo step, not three.

timenumber
startTimeoptionalnumber

Time of the first change folded into this entry. Set on merged entries; the merge window is measured from it, so a continuous stream of edits (dragging a slider for ten seconds) does not keep one entry open forever.

revisionoptional{ readonly before: number; readonly after: number; }

The document's base revision before and after this step, for steps that change it (loading a newer version after a save conflict). Undo restores before, so the next save conflicts again instead of silently overwriting; redo restores after.

Every member is readonly.

@openseat/editor/src/history.ts

interface

HistoryGroup

An open gesture: every entry recorded while it is open folds into one.

interface HistoryGroup

Members

MemberTypeDescription
keystring
recordedboolean

True once an entry was recorded in the group (later ones merge into it).

Every member is readonly.

@openseat/editor/src/history.ts

interface

HistoryOptions

interface HistoryOptions

Members

MemberTypeDescription
limitoptionalnumber

Maximum entries kept. Oldest are dropped first. Default 200.

Default 200

mergeWindowMsoptionalnumber

Milliseconds, measured from the first merged change, within which same-key entries merge. Default 1000.

Default 1000

requireContinuityoptionalboolean

Merge only when the new entry continues from the previous one (last.after === entry.before), so a change made outside history (a load, or an undo followed by other edits) never gets folded into an older step. The editor store always sets this; it is off by default for callers that record synthetic entries.

Every member is readonly.

@openseat/editor/src/history.ts

interface

KeyInput

interface KeyInput

Members

MemberTypeDescription
keystring
ctrlKeyboolean
metaKeyboolean
shiftKeyboolean
altKeyboolean

Every member is readonly.

@openseat/editor/src/shortcuts.ts

interface

LayoutEditorProps

The props of LayoutEditor. Import @openseat/editor/styles.css once, give the editor a height, and pass onSave to save through your backend.

interface LayoutEditorProps

The props of LayoutEditor: every member is listed there.

@openseat/editor/src/react/LayoutEditor.tsx

interface

LayoutIssues

interface LayoutIssues

Members

MemberTypeDescription
errorsreadonly LayoutIssue[]
warningsreadonly LayoutIssue[]
driftreadonly RowDrift[]
objectIdsReadonlySet<string>

Every object named by an issue or a drifting row, for canvas highlights.

totalnumber

errors + warnings + drifting rows.

Every member is readonly.

@openseat/editor/src/react/issues.tsx

interface

LengthUnits

How the inspector shows lengths. With metadata.openseat.unitsPerMetre set (venue templates), lengths read in metres with 2 decimals and areas in m²; values are still stored in layout units. Without it, lengths are shown in layout units as before.

interface LengthUnits

Members

MemberTypeDescription
unitsPerMetrenumber | null

Units per metre, or null when lengths are shown in layout units.

suffixstring

" (m)" for field labels in metres, "" otherwise.

toDisplaymethod(units: number) => number

A stored length as shown: metres rounded to 2 decimals, or the units (3 decimals).

fromDisplaymethod(value: number) => number

A shown length back to layout units (3 decimals).

areaM2method(unitsSquared: number) => number | null

A stored area (units²) in m² rounded to 1 decimal, or null without a scale.

Every member is readonly.

@openseat/editor/src/react/inspector/shared.ts

interface

PendingSaveDiff

What a save would change in the sellable inventory, compared with the last saved (or loaded) layout. Set while a save waits for the user to confirm that seats will be removed.

interface PendingSaveDiff

Members

MemberTypeDescription
removedSeatIdsreadonly string[]

Public seat IDs the save would delete.

addedSeatIdsreadonly string[]
changedSeatIdsreadonly string[]

Seats that moved or were relabelled.

inUseoptionalreadonly string[]

The removed seat IDs that have tickets sold or held, as the host's isInventoryInUse reported them. Absent when the host has no such check (or it failed): then any removed seat might be sold.

describedreadonly string[]

Up to five removed seats by name ("Row C, Seat 5 (Stalls)"), the ones with tickets first. Never IDs.

totalnumber

How many seats the save removes (the length of removedSeatIds).

Every member is readonly.

@openseat/editor/src/store.ts

interface

PreviewPaneProps

interface PreviewPaneProps

The props of PreviewPane: every member is listed there.

@openseat/editor/src/react/PreviewPane.tsx

interface

RevenueEstimate

What a ticket type could earn if every ticket sells: price × tickets, per type and in total.

interface RevenueEstimate

Members

MemberTypeDescription
totalnumber
byCategoryReadonlyMap<string, number>
unpricednumber

Sellable types on the map without a price: the total leaves them out.

heldBacknumber

Seats, places and booths of sellable types held back (Not for sale): the total leaves them out.

Every member is readonly.

@openseat/editor/src/ticket-types.ts

interface

RowDrawingSettings

interface RowDrawingSettings

Members

MemberTypeDescription
seatSpacingnumber

Distance between seat centres along a row.

rowSpacingnumber

Distance between rows.

seatRadiusnumber

Every member is readonly.

@openseat/editor/src/row-drawing.ts

interface

RowPatch

Changes for EditorActions.updateRows. Geometry fields regenerate the rows from their parametric layout; seat IDs of retained seats are kept.

interface RowPatch

Members

MemberTypeDescription
seatCountoptionalnumber

Real seats per row (holes are not counted).

seatSpacingoptionalnumber
curvatureoptionalnumber

-100..100, as on a block; several rows get concentric arcs. Takes precedence over radius.

radiusoptionalnumber | null

Signed arc radius; null straightens.

anchoroptionalRowLayout["anchor"]
gapsoptionalRowLayout["gaps"]
seatRotationoptionalRowLayout["seatRotation"]
labelingoptionalSeatLabeling
labelPositionoptionalRowLabelPosition
rowSpacingoptionalnumber

With several rows: restacks them front to back this far apart.

rotationoptionalnumber

Absolute row rotation in degrees.

@openseat/editor/src/store.ts

interface

SamePriceGroup

Ticket types sharing one price: buyers would see two names for the same ticket.

interface SamePriceGroup

Members

MemberTypeDescription
pricestring

The price as the first type shows it ("₹250").

idsreadonly string[]

Ticket type IDs, in the layout's order; the first one is kept by a merge.

Every member is readonly.

@openseat/editor/src/ticket-types.ts

interface

SaveDiff

Seat IDs that a save would remove, add or change compared with the last saved layout.

interface SaveDiff

Members

MemberTypeDescription
removedSeatIdsreadonly string[]
addedSeatIdsreadonly string[]
changedSeatIdsreadonly string[]

Every member is readonly.

@openseat/editor/src/react/context.ts

interface

SaveRequest

What the editor sends to the host's save handler.

interface SaveRequest

Members

MemberTypeDescription
layoutLayoutDocument

The layout to store. revision is the revision these edits started from.

baseRevisionnumber

Revision the edits are based on. The host must reject the save if its stored revision differs, unless force is set.

forceboolean

True only when the user chose to overwrite a newer version after a conflict.

manifestInventoryManifest

Everything sellable in layout (seats with their section, row and category; GA areas, booths and whole tables), for reconciling inventory on the backend. Diff it against the previous save with diffManifests.

Every member is readonly.

@openseat/editor/src/store.ts

interface

ShortcutBinding

One key binding. resolveShortcut is driven by this table and the command reference (COMMANDS in commands.ts) is generated from it, so the help overlay cannot drift from what the keys actually do.

interface ShortcutBinding

Members

MemberTypeDescription
commandSimpleEditorCommand["type"]
keysreadonly string[]

KeyboardEvent.key values that trigger the binding, lowercased when a single character. Shifted symbols of the same physical key ("}" for Shift+]) are listed too, since browsers report those.

modboolean

Cmd on Mac, Ctrl elsewhere.

shiftoptionalboolean

true: Shift must be held; false: must not be; absent: either.

platformoptional"mac" | "other"

Only on this platform.

whenoptional"drafting" | "idle"

Only when a shape is (or is not) being drafted.

displaystring

Key cap shown in help, e.g. "V", "]", "Delete".

Every member is readonly.

@openseat/editor/src/shortcuts.ts

interface

ShortcutContext

interface ShortcutContext

Members

MemberTypeDescription
draftingoptionalreadonlyboolean

A shape or row sketch is in progress: Enter finishes it instead of entering a scope.

@openseat/editor/src/shortcuts.ts

interface

SnapInput

interface SnapInput

Members

MemberTypeDescription
movingBounds

Bounds of everything being dragged, before the drag.

deltaPoint

Raw drag delta in layout units.

candidatesreadonly Bounds[]

Bounds of objects the selection can align to.

thresholdnumber

Maximum distance, in layout units, at which an edge snaps to another edge.

gridnumber

Grid size for fallback snapping; 0 disables it.

anchorPoint

Origin of the dragged object, which grid snapping aligns to the grid.

alignToObjectsoptionalboolean

Turn alignment-to-objects off and use only the grid.

modifiersoptionalSnapModifiers
linesoptionalreadonly Guide[]

Extra alignment targets, such as the venue's edges and centre (see venueSnapLines).

Every member is readonly.

@openseat/editor/src/snapping.ts

interface

SnapModifiers

Modifier keys held during a drag.

interface SnapModifiers

Members

MemberTypeDescription
altoptionalboolean

Bypass all snapping: the raw delta, no guides.

shiftoptionalboolean

Constrain the movement to the nearest multiple of 45°.

Every member is readonly.

@openseat/editor/src/snapping.ts

interface

SnapPointContext

interface SnapPointContext

Members

MemberTypeDescription
gridnumber

Grid size for fallback snapping; 0 disables it.

thresholdnumber

Maximum distance, in layout units, at which a coordinate snaps to a target.

pointsoptionalreadonly Point[]

Points whose x and y the point can align to (other objects' corners, seats…).

linesoptionalreadonly Guide[]

Lines the point can snap to, such as the venue's edges and centre.

altoptionalboolean

Bypass snapping (Alt held).

Every member is readonly.

@openseat/editor/src/snapping.ts

interface

SnapResult

interface SnapResult

Members

MemberTypeDescription
deltaPoint
guidesGuide[]

Every member is readonly.

@openseat/editor/src/snapping.ts

interface

TemplateGalleryDialogProps

"New layout from template": the venue template gallery. Loaded with React.lazy, and it loads @openseat/core/templates and the generated thumbnails with dynamic imports, so neither is in the editor's main bundle.

Left: category tabs (College events first, remembered). Middle: search, event facet chips and the venue cards. Right, once a venue is open: its setups, the target capacity, size chips, "Seats | Sections only (no seats)" (remembered for the session; a re-run keeps the stamp's choice), the parameter form, a live preview, the summary and the placement fieldset (replace or insert). Create makes exactly one undoable store.apply; replacing layouts with inventory goes through the host's destructive-change hook first.

interface TemplateGalleryDialogProps

Members

MemberTypeDescription
originoptionalPoint

Where the user right-clicked ("Insert venue template here…"): enables "At clicked point".

onClose() => void
onCreatedoptional(toast: string) => void

Receives the toast text after a template was created or inserted.

onOpenArenaoptional() => void

Opens the arena builder (the Sports tab's link card). Hidden without it.

Every member is readonly.

@openseat/editor/src/react/templates/TemplateGalleryDialog.tsx

interface

TicketAmount

What a ticket type sells: seats, places in zones (standing or sold by quantity) and booths.

interface TicketAmount

Members

MemberTypeDescription
seatsnumber

Seats buyers can book (held-back seats are in TicketAmount.held).

placesnumber

Zone and standing places buyers can book.

boothsnumber

Booths exhibitors can book.

heldoptional{ readonly seats: number; readonly places: number; readonly booths: number; }

Seats, places and booths of this type held back from sale: marked Not for sale on the map, or the whole type is never sold. They are not tickets, so counts and revenue leave them out; panels show them separately ("33 booths · 3 held back").

Every member is readonly.

@openseat/editor/src/ticket-types.ts

interface

ToolContext

Optional context for createObjectsForTool.

interface ToolContext

Members

MemberTypeDescription
toolOptionsoptionalToolOptions
seatRadiusoptionalnumber

Radius of new seats (single seats and table chairs). Defaults to 10.

Default 10

viewScaleoptionalnumber

The map's zoom (screen pixels per layout unit) where the object is placed: a new label is sized to read at about 16 px at this zoom, so a label placed on a big ground at 12% is not a speck.

Every member is readonly.

@openseat/editor/src/tools.ts

interface

ToolInfo

interface ToolInfo

Members

MemberTypeDescription
idToolId
labelstring
descriptionstring

Every member is readonly.

@openseat/editor/src/tools.ts

interface

ToolOptions

Per-tool settings chosen in the tool palette.

interface ToolOptions

Members

MemberTypeDescription
rows{ readonly mode: "block" | "line"; }

"block": drag a rectangle to get a section of rows; "line": draw a row, then pull out more rows.

section{ readonly mode: "rect" | "polygon" | "arc"; }

"rect": drag a rectangle; "polygon": click the corners; "arc": click centre, inner edge, then outer corner.

table{ readonly kind: "round" | "rect"; readonly seats: number; readonly bookAsWhole?: boolean; }

Tables placed next. Editing a table's shape, seat count or "book as a whole" in the inspector updates these, so the next table matches it.

booth{ readonly width: number; readonly height: number; }

Size of booths placed next. Resizing a booth updates it, so the next booth matches.

ga{ readonly mode: ZoneShape; readonly capacity: number; readonly seating: GaSeating; readonly categoryId: string | null; }

Zones drawn next (the "ga" tool): the shape, whether buyers are seated or standing, the places sold, and the price tier (category; null for none).

stage{ readonly shape: StageShape; }

Outline of stages placed next.

paint{ readonly categoryId: string | null; readonly level: "section" | "row" | "seat"; }

Category to paint (null clears it) and what a click paints: the whole section, the row or the seat.

Every member is readonly.

@openseat/editor/src/tools.ts

interface

ZoomSource

Current zoom, published separately so panning does not re-render the whole editor.

interface ZoomSource

Members

MemberTypeDescription
getmethod() => number
subscribemethod(listener: () => void) => () => void

Every member is readonly.

@openseat/editor/src/react/context.ts

Types23

type

DestructiveChangeHook

Asked before a DestructiveChange: return false (or resolve to false) to cancel it, for example when some removed seats are sold.

type DestructiveChangeHook = (
  change: DestructiveChange,
) => boolean | Promise<boolean>;

@openseat/editor/src/react/context.ts

type

DraftTarget

What a finished draft becomes: a polygon, a section, a zone, or (an open line) a floor divider.

type DraftTarget = "polygon" | "section" | "ga" | "divider";

@openseat/editor/src/store.ts

type

EditorClipboardPayload

A clipboard payload as the editor keeps it. cut marks objects that were cut rather than copied: pasting them keeps their IDs, seat IDs and inventory IDs when those are still free, so cut and paste moves inventory instead of re-keying it.

type EditorClipboardPayload = ClipboardPayload & {
  readonly cut?: boolean;
};

Members

MemberTypeDescription
format"openseat/objects"
version1
sourceLayoutIdstring
objectsreadonly LayoutObject[]
categoriesreadonly Category[]
boundsBounds

World bounds of the copied objects.

cutoptionalboolean

Every member is readonly.

@openseat/editor/src/clipboard.ts

type

EditorCommand

type EditorCommand =
  | {
      readonly type: "undo";
    }
  | {
      readonly type: "redo";
    }
  | {
      readonly type: "delete";
    }
  | {
      readonly type: "duplicate";
    }
  | {
      readonly type: "selectAll";
    }
  | {
      readonly type: "escape";
    }
  | {
      readonly type: "finishShape";
    }
  | {
      readonly type: "save";
    }
  | {
      readonly type: "zoomIn";
    }
// … 99 more lines (type truncated)

This type is long; its declaration is shortened here.

Variants · 41

DiscriminantTypeDescription
type: "undo"{ readonly type: "undo"; }
type: "redo"{ readonly type: "redo"; }
type: "delete"{ readonly type: "delete"; }
type: "duplicate"{ readonly type: "duplicate"; }
type: "selectAll"{ readonly type: "selectAll"; }
type: "escape"{ readonly type: "escape"; }
type: "finishShape"{ readonly type: "finishShape"; }
type: "save"{ readonly type: "save"; }
type: "zoomIn"{ readonly type: "zoomIn"; }
type: "zoomOut"{ readonly type: "zoomOut"; }
type: "fit"{ readonly type: "fit"; }
type: "copy"{ readonly type: "copy"; }
type: "cut"{ readonly type: "cut"; }
type: "paste"{ readonly type: "paste"; }
type: "pasteInPlace"{ readonly type: "pasteInPlace"; }

Paste at the copied objects' original position.

type: "flipH"{ readonly type: "flipH"; }
type: "flipV"{ readonly type: "flipV"; }
type: "rotate90"{ readonly type: "rotate90"; }

Rotate the selection 90° clockwise about its centre.

type: "bringForward"{ readonly type: "bringForward"; }
type: "sendBackward"{ readonly type: "sendBackward"; }
type: "bringToFront"{ readonly type: "bringToFront"; }
type: "sendToBack"{ readonly type: "sendToBack"; }
type: "help"{ readonly type: "help"; }

Show the keyboard shortcut overview.

type: "enterScope"{ readonly type: "enterScope"; }

Edit the contents of the selected section, row or table.

type: "zoomToSelection"{ readonly type: "zoomToSelection"; }
type: "toggleGrid"{ readonly type: "toggleGrid"; }
type: "selectSameType"{ readonly type: "selectSameType"; }

Select every object of the selected objects' types (in the current scope).

type: "exitScope"{ readonly type: "exitScope"; }
type: "toggleLock"{ readonly type: "toggleLock"; }
type: "toggleVisibility"{ readonly type: "toggleVisibility"; }
type: "groupIntoRow"{ readonly type: "groupIntoRow"; }
type: "mergeRows"{ readonly type: "mergeRows"; }
type: "splitRow"{ readonly type: "splitRow"; }

Split the row at the seat the context menu was opened on.

type: "reverseRow"{ readonly type: "reverseRow"; }
type: "straightenRow"{ readonly type: "straightenRow"; }
type: "extractSeats"{ readonly type: "extractSeats"; }
type: "createSection"{ readonly type: "createSection"; }
type: "convertToSection"{ readonly type: "convertToSection"; }
type: "editOutline"{ readonly type: "editOutline"; }
type: "tool"{ readonly type: "tool"; readonly tool: ToolId; }
type: "nudge"{ readonly type: "nudge"; readonly dx: number; readonly dy: number; }

@openseat/editor/src/shortcuts.ts

type

EditorDialogKind

Dialogs any editor panel can open (the Inspector's "Create rows…", for example). "template" is the venue template gallery; "renumber" renumbers the selected tables and booths; "name-areas" names the selected sections and zones (A, B, C… or Block 1, 2, 3…), even when they hold tables.

type EditorDialogKind =
  | "rows"
  | "import"
  | "export"
  | "arena"
  | "booth-grid"
  | "table-grid"
  | "template"
  | "renumber"
  | "name-areas";

@openseat/editor/src/react/context.ts

type

EditorDialogRequest

A dialog the host or a panel asked the editor to open (the playground's start screen, for example). The editor opens it and clears the request.

type EditorDialogRequest =
  | "template"
  | "rows"
  | "booth-grid"
  | "table-grid"
  | "arena"
  | "import"
  | "export"
  | "help";

@openseat/editor/src/store.ts

type

EditorStore

type EditorStore = StoreApi<EditorStoreState>;

Plus 4 inherited from StoreApi.

@openseat/editor/src/store.ts

type

EditorStoreState

type EditorStoreState = EditorState & EditorActions;

Members

MemberTypeDescription
layoutLayoutDocument
selectionreadonly string[]
toolToolId
historyHistory
baseRevisionnumber

Revision of the stored layout these edits are based on.

savedLayoutLayoutDocument

The layout as last saved or loaded. The editor is dirty when layout !== savedLayout.

lastSavedLayoutLayoutDocument | null

The layout the server holds as far as the editor knows: the initial layout, then the last one loaded, saved or loaded after a conflict. Saves diff the inventory against it.

pendingSaveDiffPendingSaveDiff | null

Set when save() stopped because seats would be removed; save({ confirmRemovals: true }) goes ahead.

saveStatusSaveStatus
snapToGridboolean
alignToObjectsboolean
draftreadonly Point[]

Points of a polygon being drawn.

messagestring

Short message for the status bar and screen readers.

scopeEditorScope

The section, row or table being edited ("entered").

granularitySelectionGranularity

"seats" with the seat-selection tool or inside a row or table.

toolOptionsToolOptions
drawingDefaultsDrawingDefaults
clipboardEditorClipboardPayload | null

Last copied or cut objects.

vertexEditIdstring | null

Object whose outline points are being edited.

draftTargetDraftTarget

What finishDraft creates.

lastPointerPoint | null

Last pointer position in layout coordinates; paste goes there.

freeformNoticestring | null

Set when an edit turned parametric sections freeform (their block, arc or fill settings are gone), e.g. "Section 1 is now freeform." Shown with an Undo button until dismissed, undone, or another kind of edit.

requestedDialogEditorDialogRequest | null

A dialog waiting to be opened by the editor UI (EditorActions.requestDialog).

focusRequeststring | null

The data-testid of an inspector field to focus next, such as "divider-caption" after a floor divider is drawn. The inspector focuses it and calls EditorActions.clearFocusRequest.

applymethod(label: string, update: (layout: LayoutDocument) => LayoutDocument, options?: ApplyOptions) => boolean

Applies a change as one undoable step. Returns false when nothing changed. Auto outlines are refreshed in the same step. A RangeError thrown by update (invalid input to a core operation) is shown as the message and leaves the layout unchanged.

dismissFreeformNoticemethod() => void

Hides the freeform notice.

undomethod() => void
redomethod() => void
beginGesturemethod(key: string) => void

Opens a gesture (a slider drag, a handle drag): every edit until endGesture becomes one undo step, however long it takes. Opening one with another key closes the open one first. Undo closes it.

endGesturemethod() => void

Closes the open gesture, if any.

selectmethod(ids: readonly string[], mode?: "replace" | "add" | "toggle") => void
selectAllmethod() => void

Selects the units of the current scope, without locked and hidden objects.

selectSameTypemethod() => void

Selects every unit of the current scope with the same type as a selected object.

setToolmethod(tool: ToolId) => void
setToolOptionsmethod(patch: { readonly [K in keyof ToolOptions]?: Partial<ToolOptions[K]>; }) => void
setDrawingDefaultsmethod(patch: Partial<DrawingDefaults>) => void
setLastPointermethod(point: Point | null) => void
setDraftTargetmethod(target: DraftTarget) => void
setSnapToGridmethod(enabled: boolean) => void
setAlignToObjectsmethod(enabled: boolean) => void
setMessagemethod(message: string) => void
resolveTargetmethod(hitId: string) => string | null

The object a click on hitId selects in the current scope and granularity, or null.

clickObjectmethod(hitId: string, opts?: { readonly additive?: boolean; readonly range?: boolean; readonly point?: Point; }) => void

Click on an object: select its target; additive toggles it, range selects seats from the last clicked seat. point (layout coordinates) is where the click landed: selecting seats, a click on a section's empty area beside a seat (between curved rows) takes that nearest seat (seatNearPoint).

seatForClickAtmethod(point: Point) => string | null

The seat a seat-granularity click at point means when it hit no seat: the nearest seat within reach that the current scope lets a click select (not locked or hidden), else null.

doubleClickObjectmethod(hitId: string) => void

Double-click: enter a section, row or table (selecting what was hit inside), or edit a shape's outline.

selectMarqueemethod(rawIds: readonly string[], additive: boolean) => void

Selection from a marquee that fully contains rawIds. Locked and hidden objects are skipped.

enterScopemethod(id?: string) => void

Enters a section, row or table (default: the single selected one). Clears the selection.

exitScopemethod() => void

Leaves the row or table scope first, then the section scope, selecting what was left.

exitAllScopesmethod() => void

Back to the whole map in one step: leaves the row, table and section scopes and seat mode (the seat-selection tool), selecting the outermost object that was entered.

addObjectsmethod(label: string, objects: readonly LayoutObject[]) => void
movemethod(ids: readonly string[], delta: Point) => void
transformmethod(id: string, transform: ObjectTransform) => void
setObjectPositionmethod(id: string, position: Point, opts?: { readonly mergeKey?: string; }) => void

Moves an object (with what it carries) so its position is position.

setObjectRotationmethod(id: string, rotation: number, opts?: { readonly mergeKey?: string; }) => void

Rotates an object (with what it carries) to an absolute rotation about its pivot.

transformSelectionmethod(t: SelectionTransform, label?: string) => void
rotateSelectionmethod(deg: number) => void

Rotates the selection by deg degrees about the centre of its bounds.

flipSelectionmethod(axis: "horizontal" | "vertical") => void
deletionSummarymethod() => DeletionSummary
deleteSelectionmethod(opts?: { readonly withContents?: boolean; }) => void

Deletes the selection. A section takes its contents unless withContents is false. Locked objects stay.

duplicateSelectionmethod(opts?: { readonly offset?: Point; }) => void
nudgeSelectionmethod(dx: number, dy: number) => void
alignSelectionmethod(edge: AlignEdge) => void
distributeSelectionmethod(axis: "x" | "y") => void
setVisiblemethod(ids: string | readonly string[], visible: boolean) => void
setLockedmethod(ids: string | readonly string[], locked: boolean) => void
reorderSelectionmethod(direction: ReorderDirection) => void
copySelectionmethod() => EditorClipboardPayload | null
cutSelectionmethod() => void
pastemethod(opts?: { readonly payload?: EditorClipboardPayload; readonly at?: Point; readonly inPlace?: boolean; }) => void

Pastes at at (or the last pointer). A cut payload keeps its IDs when they are free.

updateRowsmethod(rowIds: readonly string[], patch: RowPatch, opts?: { readonly mergeKey?: string; }) => void
insertSeatsmethod(rowId: string, atSlot: number, count?: number) => void
removeSeatsFromRowsmethod(seatIds: readonly string[], mode: "close-gap" | "keep-positions") => void
extendRowmethod(rowId: string, end: "start" | "end", count: number) => void
splitRowmethod(rowId: string, afterIndex: number) => void
mergeSelectedRowsmethod() => void
reverseRowmethod(rowId: string) => void
straightenRowmethod(rowId: string) => void
detachRowLayoutmethod(rowId: string) => void
extractSeatsmethod(seatIds: readonly string[], asRow: boolean) => void
groupSelectionIntoRowmethod(rowLabel?: string) => void
relabelRowsmethod(rowIds: readonly string[], spec: RowLabeling, opts?: { readonly mergeKey?: string; }) => void
relabelSeatsmethod(target: { readonly groupIds?: readonly string[]; readonly seatIds?: readonly string[]; }, spec: SeatLabeling) => void
setRowLabelmethod(rowId: string, label: string, opts?: { readonly mergeKey?: string; }) => void
setSeatLabelmethod(seatObjectId: string, label: string, opts?: { readonly mergeKey?: string; }) => void

Sets a seat's label by hand; relabeling leaves it alone afterwards.

resetSeatLabelmethod(seatId: string) => void

Gives a hand-labelled seat its automatic label back (its row's numbering for its slot) and clears labelLocked.

addSeatsToRowmethod(seatIds: readonly string[], rowId: string) => void

Moves seats into a row (by their position along it). A parametric section holding the row becomes freeform, since regenerating it would drop them.

setSeatIdmethod(seatObjectId: string, seatId: string) => { readonly ok: boolean; readonly error?: string; }

Changes a seat's public ID. Rejects empty and duplicate values.

updateSectionSeatingmethod(sectionId: string, patch: Partial<SectionSeating>, opts?: { readonly mergeKey?: string; }) => void
makeSectionParametricmethod(sectionId: string) => void

Gives a section without seating a fill seating from the drawing defaults.

detachSectionSeatingmethod(sectionId: string) => void

Drops a section's parametric seating; its rows and seats stay as they are.

createSectionFromSelectionmethod(opts?: SectionFromSelectionOptions) => void
dissolveSectionmethod(id: string) => void
convertToSectionmethod(objectId: string) => void
setSectionMembershipmethod(ids: readonly string[], sectionId: string | null) => void
syncSectionMembershipmethod(sectionId: string) => void

Makes the section's members exactly what lies inside its outline.

setVertexEditingmethod(id: string | null) => void
moveVertexmethod(objectId: string, index: number, world: Point, opts?: { readonly mergeKey?: string; }) => boolean

Moves an outline point. False when the edit was rejected (self-intersecting, locked, ...).

insertVertexmethod(objectId: string, edgeIndex: number, world?: Point) => boolean
removeVertexmethod(objectId: string, index: number) => boolean
updateTablemethod(tableId: string, patch: TableEditPatch, opts?: { readonly mergeKey?: string; readonly grow?: boolean; }) => { readonly clamped: boolean; }

Edits a table's shape and seats. grow (default true) enlarges a table too small for its seats.

addCategorymethod(name: string, opts?: { readonly colour?: string; }) => string

Adds a ticket type (category) as one undo step, "Add ticket type". Its ID is a slug of name, made unique; its colour is opts.colour or the next free palette colour (nextCategoryColour). With the paint tool active, the new type becomes the one painted. Returns the new ID, or "" when it could not be added (the reason is the message).

addCategoriesmethod(entries: readonly { readonly name: string; readonly colour?: string; }[]) => string[]

Adds several ticket types (price tiers such as Gold and Silver) as one undo step. Names already used (ignoring case) are skipped. Returns the IDs of the added types.

assignCategorymethod(hitId: string, categoryId: string | null, level: "section" | "row" | "seat", point?: Point) => void

Paints a category on the section, row or seat under hitId (null clears it). With point (where the click landed) and the Row or Seat level, a hit on a whole section (seats too small to hit at this zoom, or the gap between two seats) paints the row or seat nearest the point, not the whole section.

setCategoryOnSelectionmethod(categoryId: string | null) => void

Sets the category of the selection, cascading to the seats of rows, tables and sections.

setNotForSalemethod(ids: readonly string[], notForSale: boolean) => boolean

Marks seats, rows, sections, tables, booths or zones Not for sale (they stay on the map, greyed out, and buyers can't select them), or puts them back on sale, as one undo step. Categories are not changed. Other objects in ids are ignored. Putting an object back on sale releases only that object: when its row or section was held back as a whole, the rest of it stays held back. The message names what changed: "Booth B7 is not for sale.", "4 seats are available again." Returns false when nothing changed.

setObjectNamemethod(id: string, name: string, opts?: { readonly mergeKey?: string; }) => void

Sets an object's name (empty removes it) and the text of its name label on the map, if it has one (setNameOnMap).

setNameOnMapmethod(id: string, show: boolean) => void

Shows or hides the name of a shape, aisle or path on the map, as a text label at its centre (mapNameLabelId). One undo step.

setVenuemethod(venue: Venue | null, opts?: { readonly mergeKey?: string; }) => void
setFocalPointmethod(point: Point | null, opts?: { readonly mergeKey?: string; }) => void
clearLayoutmethod() => void

Removes every object, the venue and the focal point. Categories stay.

addDraftPointmethod(point: Point) => void

Adds a point to the shape being drawn. A click near the first point closes a polygon (three points or more); while drawing a floor divider (the divider tool), a click near the last point finishes it (two points or more).

finishDraftmethod() => void
cancelDraftmethod() => void
setSectionShowSeatsmethod(ids: readonly string[], show: boolean) => void

Switches sections between seats ("Seats", show true) and "Zone only" (sold by quantity, seats kept but not drawn), as one undo step. Seat IDs are never changed, so switching back restores them exactly. Selected rows and seats of a section that becomes a zone give way to the section.

setZoneCapacitymethod(id: string, capacity: number | null, opts?: { readonly mergeKey?: string; }) => void

Sets a zone's capacity: a zone section's (null removes the override, so it follows the seat count) or a drawn zone's. Typing is one undo step.

addZonemethod(opts?: AddZoneOptions) => string | null

Adds a zone (core createZone) with the Zone tool's settings for anything not given. Returns its ID, or null.

addDividermethod(points: readonly Point[], caption?: string) => string | null

Adds a floor divider through points (at least 2) with caption (default "GROUND FLOOR"), selects it and asks the inspector to focus its caption. Returns its ID, or null.

addFootnotemethod(text?: string) => string | null

Adds note text (default "Type your note here") centred under the content, selected with its text box focused. Returns its ID, or null.

setStageShapemethod(id: string, shape: StageShape, thrust?: StageThrust | null, opts?: { readonly mergeKey?: string; }) => void

Changes a stage's outline: rectangle, thrust (T), round or semicircle. thrust sizes a thrust stage's runway (null removes it, so the default size applies). The style is left alone.

clearFocusRequestmethod() => void

Clears focusRequest once the field has focus.

loadmethod(layout: LayoutDocument, options?: { readonly keepHistory?: boolean; }) => void

Replaces the layout outside history, for example after loading from a server.

importJsonmethod(json: string) => ValidationResult

Parses JSON and, when valid, replaces the layout's contents as one undoable step. The document keeps its own ID and base revision, so an imported file can never overwrite another stored layout. JSON over MAX_IMPORT_BYTES is rejected.

exportJsonmethod() => { readonly json: string | null; readonly errors: readonly LayoutIssue[]; }

Serialises the layout when it is valid; otherwise returns the errors.

savemethod(opts?: { readonly confirmRemovals?: boolean; }) => Promise<void>

Saves through the host's handler. When the save would remove seats from the inventory (compared with lastSavedLayout), it stops and sets pendingSaveDiff instead, unless confirmRemovals is set.

cancelPendingSavemethod() => void

Drops a save waiting for confirmation.

requestDialogmethod(kind: EditorDialogRequest) => void

Asks the editor UI to open a dialog (sets requestedDialog).

clearRequestedDialogmethod() => void

Clears requestedDialog, once the UI has opened it.

resolveConflictmethod(choice: "overwrite" | "load-remote" | "cancel") => Promise<void>

After a conflict: overwrite the newer version, or load it (undoable, so local work is not lost).

Every member is readonly.

@openseat/editor/src/store.ts

type

GuardVerdict

What to do before a destructive change:

  • "proceed": nothing sold can be lost, or the host's hook allowed it;
  • "cancelled": the host's hook refused it;
  • "confirm": no hook and inventory would go: the user types CONFIRM_WORD.
type GuardVerdict = "proceed" | "cancelled" | "confirm";

@openseat/editor/src/react/templates/placement.ts

type

InventoryInUseCheck

Asks the host which of these public seat IDs have tickets sold or held. Returns the ones in use (a subset of keys), synchronously or not.

type InventoryInUseCheck = (
  keys: readonly string[],
) => readonly string[] | Promise<readonly string[]>;

@openseat/editor/src/store.ts

type

NotForSaleState

Whether a set of objects is for sale: all held back, none, or some.

type NotForSaleState = "all" | "none" | "mixed";

@openseat/editor/src/store.ts

type

PresetKind

Venue presets offered by the Presets menu.

type PresetKind = "template" | "arena" | "booth-grid" | "table-grid";

@openseat/editor/src/react/bars.tsx

type

SaveHandler

Persists a layout. Resolve with conflict (do not throw) when the stored revision is newer.

type SaveHandler = (request: SaveRequest) => Promise<SaveResult>;

@openseat/editor/src/store.ts

type

SaveResult

What your onSave handler resolves with: saved with the new revision, or conflict with the stored layout, which the editor shows the user with the choice to load it or overwrite it.

type SaveResult =
  | {
      readonly status: "saved";
      readonly revision: number;
      readonly updatedAt?: string;
    }
  | {
      readonly status: "conflict";
      readonly remote: LayoutDocument;
      readonly message?: string;
    };

Variants · 2

DiscriminantTypeDescription
status: "saved"{ readonly status: "saved"; readonly revision: number; readonly updatedAt?: string; }
status: "conflict"{ readonly status: "conflict"; readonly remote: LayoutDocument; readonly message?: string; }

@openseat/editor/src/store.ts

type

SaveStatus

type SaveStatus =
  | {
      readonly state: "idle";
    }
  | {
      readonly state: "saving";
    }
  | {
      readonly state: "saved";
      readonly at: number;
      readonly revision: number;
    }
  | {
      readonly state: "conflict";
      readonly remote: LayoutDocument;
      readonly message?: string;
    }
  | {
      readonly state: "error";
      readonly message: string;
    };

Variants · 5

DiscriminantTypeDescription
state: "idle"{ readonly state: "idle"; }
state: "saving"{ readonly state: "saving"; }
state: "saved"{ readonly state: "saved"; readonly at: number; readonly revision: number; }
state: "conflict"{ readonly state: "conflict"; readonly remote: LayoutDocument; readonly message?: string; }
state: "error"{ readonly state: "error"; readonly message: string; }

@openseat/editor/src/store.ts

type

SeatToolAction

type SeatToolAction =
  | {
      readonly kind: "extend";
      readonly rowId: string;
      readonly end: "start" | "end";
    }
  | {
      readonly kind: "create";
      readonly objects: LayoutObject[];
    };

Variants · 2

DiscriminantTypeDescription
kind: "extend"{ readonly kind: "extend"; readonly rowId: string; readonly end: "start" | "end"; }
kind: "create"{ readonly kind: "create"; readonly objects: LayoutObject[]; }

@openseat/editor/src/tools.ts

type

SelectionGranularity

What a click selects: whole objects (by hierarchy) or individual seats.

type SelectionGranularity = "objects" | "seats";

@openseat/editor/src/store.ts

type

SimpleEditorCommand

Commands that carry no payload, so a key binding can produce them directly.

type SimpleEditorCommand = Exclude<
  EditorCommand,
  | {
      readonly type: "tool";
    }
  | {
      readonly type: "nudge";
    }
>;

Variants · 39

DiscriminantTypeDescription
type: "undo"{ readonly type: "undo"; }
type: "redo"{ readonly type: "redo"; }
type: "delete"{ readonly type: "delete"; }
type: "duplicate"{ readonly type: "duplicate"; }
type: "selectAll"{ readonly type: "selectAll"; }
type: "escape"{ readonly type: "escape"; }
type: "finishShape"{ readonly type: "finishShape"; }
type: "save"{ readonly type: "save"; }
type: "zoomIn"{ readonly type: "zoomIn"; }
type: "zoomOut"{ readonly type: "zoomOut"; }
type: "fit"{ readonly type: "fit"; }
type: "copy"{ readonly type: "copy"; }
type: "cut"{ readonly type: "cut"; }
type: "paste"{ readonly type: "paste"; }
type: "pasteInPlace"{ readonly type: "pasteInPlace"; }
type: "flipH"{ readonly type: "flipH"; }
type: "flipV"{ readonly type: "flipV"; }
type: "rotate90"{ readonly type: "rotate90"; }
type: "bringForward"{ readonly type: "bringForward"; }
type: "sendBackward"{ readonly type: "sendBackward"; }
type: "bringToFront"{ readonly type: "bringToFront"; }
type: "sendToBack"{ readonly type: "sendToBack"; }
type: "help"{ readonly type: "help"; }
type: "enterScope"{ readonly type: "enterScope"; }
type: "zoomToSelection"{ readonly type: "zoomToSelection"; }
type: "toggleGrid"{ readonly type: "toggleGrid"; }
type: "selectSameType"{ readonly type: "selectSameType"; }
type: "exitScope"{ readonly type: "exitScope"; }
type: "toggleLock"{ readonly type: "toggleLock"; }
type: "toggleVisibility"{ readonly type: "toggleVisibility"; }
type: "groupIntoRow"{ readonly type: "groupIntoRow"; }
type: "mergeRows"{ readonly type: "mergeRows"; }
type: "splitRow"{ readonly type: "splitRow"; }
type: "reverseRow"{ readonly type: "reverseRow"; }
type: "straightenRow"{ readonly type: "straightenRow"; }
type: "extractSeats"{ readonly type: "extractSeats"; }
type: "createSection"{ readonly type: "createSection"; }
type: "convertToSection"{ readonly type: "convertToSection"; }
type: "editOutline"{ readonly type: "editOutline"; }

@openseat/editor/src/shortcuts.ts

type

TemplatesModule

The @openseat/core/templates module.

type TemplatesModule = typeof Templates;

Members

MemberTypeDescription
defineSetupSetupDefinition

Declares a setup with params typed from its ParamSpec tuple. Use as const on the params array.

TemplateInputError{ prototype: TemplateInputError; captureStackTrace: (targetObject: object, constructorOpt?: Function | undefined) => void; prepareStackTrace: (err: Error, stackTraces: CallSite[]) => any; stackTraceLimit: number; }

Thrown for out-of-range input that cannot be clamped (unknown setup, limits).

TEMPLATE_LIMITS{ readonly maxSeats: 25000; readonly maxObjects: 40000; readonly previewSeatLimit: 10000; readonly largeLayoutWarn: 10000; readonly maxMetaBytes: 48000; }
isCategoryVocabIdid is CategoryVocabId
vocabEntryCategoryVocabEntry | undefined

The vocab entry for an id, or undefined for ids outside the vocab.

colourToLab{ L: number; a: number; b: number; } | null

CIELAB (D65) of a #rrggbb colour, or null when it is not one.

colourDeltaEnumber

CIE76 colour difference; Infinity when either colour is malformed.

colourChromanumber

CIELAB chroma; 0 for a malformed colour.

sellableColourProblemsstring[]

Problems with a set of sellable category colours: missing, malformed, near-grey, or too close to another sellable colour. Empty when fine.

CATEGORY_VOCAB{ readonly "fan-pit": { readonly name: "Fan pit"; readonly colour: "#e11d48"; readonly sellable: true; readonly suggestedPriceINR: 999; }; readonly vip: { readonly name: "VIP"; readonly colour: "#7e22ce"; readonly sellable: true; readonly suggestedPriceINR: 1499; }; readonly gold: { readonly name: "Gold"; readonly colour: "#f59e0b"; readonly sellable: true; readonly suggestedPriceINR: 799; }; readonly silver: { reado …(shortened)

The category vocabulary: the ONLY category ids template builders may use. The registry and the build matrix enforce it.

Every sellable entry has a colour that is clearly distinct from every other sellable colour (CIE76 ΔE >= SELLABLE_MIN_DELTA_E) and is never near-grey (chroma >= SELLABLE_MIN_CHROMA), so ticket types read apart on the map. Not-for-sale entries use greys on purpose.

suggestedPriceINR values are indicative placeholders only: the editor shows them as input placeholders and never writes them as host prices.

CATEGORY_VOCAB_IDSCategoryVocabId[]

Vocab ids in declaration order.

SELLABLE_MIN_DELTA_E20

Minimum CIE76 ΔE between two sellable colours.

SELLABLE_MIN_CHROMA30

Minimum CIELAB chroma of a sellable colour (below it reads as grey).

TEMPLATE_CATEGORIESreadonly TemplateCategory[]

The ten template categories (the owner's list B main categories), in gallery order.

EVENT_FACETSreadonly EventFacet[]

Event facet chips, in display order.

OWNER_LIST_Areadonly OwnerListAEntry[]

The owner's list A (college event venues), verbatim and in the owner's order. Each entry has exactly one PRIMARY venue (search 120) and optional BOOST venues (search 90). The gallery's "College events" tab lists these.

OWNER_LIST_Breadonly OwnerListBEntry[]

The owner's list B (main category -> venue subtypes), verbatim. 41 subtypes, each mapped to a DISTINCT venue; tests derive the count from this list. Stadium, indoor arena, waterfront and multipurpose hall come from list A only.

VENUE_MANIFESTreadonly VenueManifest[]
MANIFEST_SETUPSreadonly (ManifestSetup & { readonly venueId: string; })[]

Every manifest setup with its venue id, in registry order.

snapParamnumber

Snaps to the spec's step grid, THEN clamps to [min, max]; ints are rounded.

defaultParamsRecord<string, ParamValue>
resolveParamsResolvedParams

Resolves the params of a build: defaults, then the size preset, then input. Numbers are snapped to their step, then clamped; a bad type or enum value falls back to the default with an issue; unknown keys are dropped. Never throws.

fnv1anumber

32-bit FNV-1a hash of a string.

mulberry32() => number

mulberry32 PRNG: deterministic floats in [0, 1).

isHeavySetupboolean

True for setups that get the reduced matrix: flagged heavy, or estimated above 8k seats by default.

paramCombosParamCombo[]

Named param combinations for the build matrix. Every combo is fully resolved and in range; identical combos are dropped (the first name wins).

Light setups: default, small, large, all-min, all-max, maxCapacity, minCapacity, each numeric param alone at min and at max, each enum option, each boolean flipped, and 6 seeded randoms. Heavy setups: default, small, large, maxCapacity, each param extreme with the rest at default, each enum option, and 4 seeded randoms. Randoms use mulberry32 seeded with FNV-1a of the setup id.

paramSweepnumber[]

n evenly spaced on-grid values of an int/number param, min and max included.

findParamParamSpec | undefined

A param spec by key, or undefined.

isCompleteParamsboolean

True when values has an entry for every param of the setup.

HEAVY_SEAT_THRESHOLD8000

Setups with more default seats than this get the reduced (heavy) build matrix.

LIGHT_RANDOM_COMBOS6

Seeded random combos per light setup.

HEAVY_RANDOM_COMBOS4

Seeded random combos per heavy setup.

mergedAliasesstring[]

A venue's aliases with the owner's names merged in centrally: the list-A names it is PRIMARY for and its list-B subtype names. Boost venues do not get the list-A name (search scores them separately).

joinVenueTemplatesVenueTemplate[]

Joins the manifest with the implemented setup definitions. Every venue is returned; setups holds its implemented setups only, in manifest order.

getVenueVenueTemplate | undefined
getSetupVenueSetupTemplate | undefined

An implemented setup by its full id.

getVenueManifestVenueManifest | undefined
getManifestSetup(ManifestSetup & { readonly venueId: string; }) | undefined

A manifest setup (implemented or not) by its full id.

listSetupsVenueSetupTemplate[]

Implemented setups in registry order, optionally of one category.

listVenuesVenueTemplate[]

Venues in registry order. By default venues with no implemented setup are hidden.

checkParamSpecstring[]

Problems with one param spec (and its relation to the others).

valueFitsboolean

True when value is a valid, in-range, on-grid value of spec.

checkSetupDefinitionstring[]

Problems with one setup definition on its own.

checkTemplateRegistrystring[]

Every registry rule. Returns human-readable problems; empty when clean.

SETUP_ID_PATTERNRegExp

Full setup (template) id: <cat>.<venue>.<setup>.

VENUE_ID_PATTERNRegExp

Venue id: <cat>.<venue>.

ID_PREFIX_PATTERNRegExp

Object-id prefix of a setup.

VENUE_TEMPLATESreadonly VenueTemplate[]

Every venue (implemented or not), in registry order, with merged aliases.

stemTokenstring

Light plural stemming: ies -> y, (s|x|z|ch|sh)es -> drop es, s -> drop s.

normaliseTokensstring[]

Normalised, stemmed tokens of a text, stop words dropped.

damerauDistancenumber

Optimal-string-alignment (restricted Damerau-Levenshtein) distance, capped at max + 1.

searchTemplatesTemplateSearchHit[]

Searches venue templates. Pure and deterministic. An empty query lists every venue in registry order (score 0). facet keeps venues with at least one setup of that facet and scores only those setups.

SEARCH_SCORES{ readonly listAPrimary: 120; readonly exact: 100; readonly listABoost: 90; readonly prefix: 70; readonly allTokensBase: 50; readonly allTokensPerToken: 5; readonly eventTagToken: 15; readonly category: 10; readonly fuzzy: 20; }

Template search over the manifest (works before any setup is built).

Normalisation: NFKD, diacritics stripped, lowercase, '&' -> 'and', punctuation and hyphens -> spaces, plural stemming (ies -> y, es, s), stop words dropped. Every phrase is also indexed in joined form (each adjacent token pair concatenated, and the whole phrase compacted), so 'e sports', 'e-sports' and 'esports' all meet, as do 'open mic' and 'openmic'.

Tiered scores (each venue keeps its best; ties go by registry order): list-A phrase on its PRIMARY venue 120; exact name or alias 100; list-A phrase on a BOOST venue 90; name or alias prefix 70; all query tokens in the name, aliases or events 50 + 5 per token; event or tag tokens 15 each; category name 10; fuzzy (Damerau <= 1, tokens of 5+ chars) 20.

summaryMeasurenumber

Reads measure from a build summary.

clearCapacityMemovoid

Clears the build memo (tests).

fitCapacityFitCapacityResult

Finds the driver value whose capacity best matches target, by binary search over the driver's step grid (capacity must be non-decreasing in it). Uses capacity.estimate when present, buildTemplate summaries otherwise (about 8 builds at most, memoised). A target above the max returns the max with a note; below the min returns the min with a note.

ACADEMIC_SETUPSreadonly SetupDefinition<Readonly<Record<string, ParamValue>>>[]
CULTURAL_SETUPSreadonly SetupDefinition<Readonly<Record<string, ParamValue>>>[]
EXHIBITION_SETUPSreadonly SetupDefinition<Readonly<Record<string, ParamValue>>>[]
HOSPITALITY_SETUPSreadonly SetupDefinition<Readonly<Record<string, ParamValue>>>[]
OUTDOOR_SETUPSreadonly SetupDefinition<Readonly<Record<string, ParamValue>>>[]
PERFORMANCE_SETUPSreadonly SetupDefinition<Readonly<Record<string, ParamValue>>>[]
SOCIAL_SETUPSreadonly SetupDefinition<Readonly<Record<string, ParamValue>>>[]
SPECIALISED_SETUPSreadonly SetupDefinition<Readonly<Record<string, ParamValue>>>[]
SPORTS_SETUPSreadonly SetupDefinition<Readonly<Record<string, ParamValue>>>[]
UNCONVENTIONAL_SETUPSreadonly SetupDefinition<Readonly<Record<string, ParamValue>>>[]
GROUP_SETUPSReadonly<Record<TemplateCategoryId, readonly SetupDefinition[]>>

Implemented setup definitions per category group.

SETUP_DEFINITIONSreadonly SetupDefinition[]

Every implemented setup definition, group by group. Joined with the manifest by registry.ts.

round3number

Rounds to 3 decimals, without -0.

mnumber

Metres to layout units, rounded to 1e-3.

toMetresnumber

Layout units to metres, rounded to 1e-3.

ptUPoint

A metre point in layout units.

tidyPointPoint

A point rounded to 1e-3.

TEMPLATE_UNITS_PER_METRE50

Layout units per metre in every template layout.

densityCautionstring

The density caution text. Summaries compute the same text from GA capacities, so the two merge.

SEATS{ readonly chair: { readonly shape: { readonly kind: "circle"; readonly radius: 10; }; readonly seatSpacingM: 0.52; readonly rowSpacingM: 0.9; }; readonly stand: { readonly shape: { readonly kind: "circle"; readonly radius: 9; }; readonly seatSpacingM: 0.5; readonly rowSpacingM: 0.86; }; readonly bleacher: { readonly shape: { readonly kind: "circle"; readonly radius: 9; }; readonly seatSpacingM: 0.5; readonly rowSpac …(shortened)
DENSITY{ readonly pit: 1.6; readonly standing: 1.4; readonly cocktail: 1; readonly mixer: 1; readonly grass: 1; readonly picnic: 1; readonly vipLounge: 1; readonly participants: 0.5; readonly accessible: 0.5; readonly expoVisitors: 0.5; }

Planning densities in persons per m², aligned to the National Building Code of India Part 4. They are planning estimates, never approvals.

NBC_STANDING_MAX1.67

Highest standing density a template allows (persons/m²).

HIGH_DENSITY_MAX2

Highest density with the advanced allowHighDensity override; always cautioned.

DENSITY_CAUTION_ABOVE1.5

Densities above this add a summary caution.

rectPtsPoint[]

Corners of a w x h rectangle centred on the origin, clockwise from the top-left.

rectFromM{ center: Point; width: number; height: number; points: Point[]; }

A rectangle's centre, width, height and corners (clockwise from the top-left). Corners may come in any order.

arcPtsPoint[]

seg + 1 points on a circular arc from a0 to a1 degrees.

ellipseSectorPtsPoint[]

The band between two concentric ellipses from a0 to a1 degrees: the outer arc forwards, then the inner arc back. An inner radius of 0 closes the sector at the centre. A full 360-degree sweep is not supported (it would not be a simple polygon); use two halves.

uPolygonPoint[]

A rectangle with a rectangular notch cut into one of its edges (a U shape), e.g. a standing area wrapped around a front-of-house desk. The notch is clipped to the outer rectangle and cut from the edge it is nearest to. A notch that does not overlap the outer rectangle, or that would split it, leaves the plain rectangle.

areaM2number

Area of a polygon given in metres, in m².

gaCapacityForAreanumber

Planning capacity of a standing area: floor((area − deduct) × density), at least 1. boundaryUnits is in layout units (unitsPerMetre per metre).

catmullRomPoint[]

An open Catmull-Rom spline through pointsM (centripetal-free, uniform), with samples segments between each pair of points. The first and last points are kept.

rdpSimplifyPoint[]

Ramer-Douglas-Peucker simplification of an open polyline; keeps both ends. Iterative.

TemplateKit{ prototype: TemplateKit; }
buildTemplateBuiltTemplate

Builds a template layout:

  1. resolves the params (defaults, size preset, input; snapped and clamped) and, with targetCapacity, fits the capacity driver;
  2. runs the setup's builder on a fresh TemplateKit;
  3. creates the layout with the kit's referenced categories;
  4. moves everything (objects, venue, focal point and block frames) by whole grid cells so the content starts 40 units from the canvas origin, with a plain map over positions (locked surfaces move too and sections keep their seating), sizes the canvas to the venue and objects plus 40 and calls fitCanvasToContent;
  5. writes metadata.openseat (OpenSeatMeta): units, the template stamp, block stamps, not-for-sale categories and IDs and the indicative INR prices of the categories present. Block stamps are dropped, with a note, when the metadata would exceed 48 KB;
  6. with zonesOnly, turns every section into a zone (zoneTemplateLayout);
  7. enforces TEMPLATE_LIMITS (TemplateInputError) and summarises.

Identical input gives a byte-identical serializeLayout; no timestamps are written. setup is a registered setup id or, for tests and fixtures, a definition.

summarizeLayoutTemplateSummary

Counts for the template gallery and the build summary, derived from the objects alone, so they also work on a layout the user has edited:

  • seats: every seat object, table seats included; tableSeats: seats owned by a table.
  • Not for sale: seats, GA places and whole tables in a category listed in metadata.openseat.unsellableCategories (the vocabulary's not-for-sale categories when the layout lists none), or covered by metadata.openseat.notForSale (unsellableInventory). unsellableSeats counts those seats; totalCapacity is the sellable seats plus the sellable GA capacity (booths are not people).
  • Zone sections (showSeats: false) sell their capacity instead of their seats: totalCapacity counts the capacity of each one that is for sale, and unsellableSeats the seats beyond it (all of them when the zone is held back). Seats, tables, accessible places and the per-category seat counts still count the seats kept in the document, so a setup's seat and zone variants report the same figures. zones counts zone sections plus GA areas.
  • accessible: wheelchair seats plus the capacity of GA areas in the "accessible" category.
  • cautions: GA areas planned above 1.5 persons/m² and layouts above TEMPLATE_LIMITS.largeLayoutWarn seats. notes is empty here; buildTemplate adds the kit's clamp notes.
zoneTemplateLayoutLayoutDocument

The zone variant of a built template layout:

  1. core toZoneOnlyLayout: loose rows, tables and seats are wrapped into sections, and every section with seats becomes a zone section;
  2. each zone section sells what its seats sold: its capacity defaults to its seat count, and becomes the number of its sellable seats when some were not for sale; a section with no sellable seat is listed in metadata.openseat.notForSale (unless its category already holds it back), and a section held back only by its category while some of its seats sold takes their most common sellable category instead;
  3. zone sections get rounded corners (ZONE_CORNER_RADIUS_M); the sections core added are rounded to 1e-3 like every template coordinate;
  4. when every zone is seated (no standing GA), the footnote ZONES_SEATED_FOOTNOTE is centred under the content (core createFootnote, sized to the content width), and the canvas grows to fit it;
  5. the template stamp records zonesOnly: true.

Seats themselves are never changed, so the sellable capacity equals the seat variant's. A layout that is already a zone layout is returned as is.

ZONES_SEATED_FOOTNOTE"ALL THE SECTIONS ARE SEATED"

Footnote added under a zone layout whose zones are all seated.

ZONE_CORNER_RADIUS_M0.4

Corner rounding of a template's zone sections, in metres.

athleticsTrack(kit: TemplateKitApi, opts?: AthleticsTrackOptions | undefined) => AthleticsTrackResult
badmintonCourt(kit: TemplateKitApi, opts?: CourtOptions | undefined) => FieldResult
basketballCourt(kit: TemplateKitApi, opts?: CourtOptions | undefined) => FieldResult
cricketGround(kit: TemplateKitApi, opts?: CricketGroundOptions | undefined) => CricketGroundResult
footballPitch(kit: TemplateKitApi, opts?: FootballPitchOptions | undefined) => FieldResult
hockeyPitch(kit: TemplateKitApi, opts?: CourtOptions | undefined) => FieldResult
kabaddiCourt(kit: TemplateKitApi, opts?: KabaddiCourtOptions | undefined) => FieldResult
poolLanes(kit: TemplateKitApi, opts?: PoolLanesOptions | undefined) => PoolLanesResult
tennisCourt(kit: TemplateKitApi, opts?: CourtOptions | undefined) => FieldResult
volleyballCourt(kit: TemplateKitApi, opts?: CourtOptions | undefined) => FieldResult
arcWedges(kit: TemplateKitApi, opts: ArcWedgesOptions) => SeatingResult
fanHouse(kit: TemplateKitApi, opts: FanHouseOptions) => FanHouseResult
standAlong(kit: TemplateKitApi, opts: StandAlongOptions) => SeatingResult
theatreBlocks(kit: TemplateKitApi, opts: TheatreBlocksOptions) => TheatreBlocksResult
banquetRounds(kit: TemplateKitApi, opts: BanquetRoundsOptions) => TableGridResult
cabaretTables(kit: TemplateKitApi, opts: CabaretTablesOptions) => TableGridResult
deskRuns(kit: TemplateKitApi, opts: DeskRunsOptions) => TableGridResult
loungeRow(kit: TemplateKitApi, opts: LoungeRowOptions) => TableGridResult
tableGrid(kit: TemplateKitApi, opts: TableGridOptions) => TableGridResult
teamTables(kit: TemplateKitApi, opts: TeamTablesOptions) => TableGridResult
danceFloor(kit: TemplateKitApi, opts: DanceFloorOptions) => DanceFloorResult
endStageShow(kit: TemplateKitApi, opts: EndStageShowOptions) => EndStageShowResult
boothBand(kit: TemplateKitApi, opts: BoothBandOptions) => BoothBlockResult
boothGrid(kit: TemplateKitApi, opts: BoothGridOptions) => BoothBlockResult
boothRing(kit: TemplateKitApi, opts: BoothRingOptions) => BoothBlockResult
islandGrid(kit: TemplateKitApi, opts: IslandGridOptions) => BoothBlockResult
accessibleZone(kit: TemplateKitApi, opts: AccessibleZoneOptions) => BuilderResult
amenity(kit: TemplateKitApi, opts: AmenityOptions) => BuilderResult
columnGrid(kit: TemplateKitApi, opts: ColumnGridOptions) => ColumnGridResult
gates(kit: TemplateKitApi, opts: GatesOptions) => BuilderResult
battleRing(kit: TemplateKitApi, opts?: BattleRingOptions | undefined) => BattleRingResult
runway(kit: TemplateKitApi, opts?: RunwayOptions | undefined) => RunwayResult
accessibleCount(seats: number) => number
inflateRect(r: RectM, d: number) => RectM
nextRowStart(start: number, rows: number) => number
rectM(cx: number, cy: number, w: number, h: number) => RectM
rectUnion(rects: readonly RectM[]) => RectM
regenerateBlockRegenerateBlockResult

Rebuilds block blockId with params (merged over the stamp's params).

The block is rebuilt in a sub-kit with the stamp's prefix and frame, translated by the drift of the surviving members' centroid (so a block the user moved regenerates where it now is). Per slot:

  • an existing member keeps its object id (the inventory key of a whole-booked table), its booth inventoryId, its seats' object and seat ids (by seat number), their accessibility flags and its label (labels only follow the new numbering when a label param changed and the user had not renamed the member); its category and bookAsWhole follow the new params unless the user had changed them;
  • a member the user deleted is recreated (under its old id when free);
  • a slot that no longer exists is removed with its seats and reported in removedInventoryIds (also when a kept table loses seats). New members get labels that do not clash with kept ones. The stamp (params, frame and slots) and metadata.openseat.notForSale are updated, and vocab categories the new members use are added. An unknown block id returns the layout unchanged.
BLOCK_KINDSReadonly<Record<BlockKind, BlockKindSpec>>
placeTemplatePlaceTemplateResult

Places built into target.

replace: the template's layout under the target's id and revision, with metadata = the target's other metadata plus the template's openseat block; the canvas follows the template FRAME rule (venue and objects plus 40, then fitCanvasToContent). removedInventoryIds lists every target inventory key the template does not have, for the editor's destructive-change guard.

insert (built on core's copyInto):

  • object ids become ${ns}:${id}, ns the first free of t1, t2…;
  • a section label that clashes (case-insensitively) with an existing one gets (2), (3)…, and its seats' public ids are re-derived from it (${label}-${row}-${seat}, the rule seats added later follow);
  • other inventory keys are kept unless they clash, then become ${ns}-${key};
  • categories merge by id (existing ones win); not-for-sale categories, suggested prices, not-for-sale ids and block stamps are merged with their ids remapped; the template stamp is appended to inserts (the last 20 are kept);
  • the content is centred on at, or else placed right of the existing content (the arena preset rule); the target's venue and focal point stay;
  • the canvas grows with fitCanvasToContent.

zonesOnly places the template's zone variant in either mode.

MAX_TEMPLATE_INSERTS20

Most template stamps remembered in metadata.openseat.inserts.

templateSchematicTemplateSchematic

The schematic of layout in a width x height viewBox (default 320 x 200), fitted with a 4-unit margin. roles (BuiltTemplate.roles) tells surfaces, markings, zones and obstacles apart; without it polygon zIndex decides. At most SCHEMATIC_MAX_BYTES serialised.

schematicToSvgstring

The schematic as a standalone SVG string. Presentation attributes only (fill, stroke, stroke-width, fill-opacity): no style attributes or elements, so it renders under a strict Content-Security-Policy.

SCHEMATIC_MAX_BYTES3072

Largest serialised schematic (JSON, bytes).

@openseat/editor/src/react/templates/placement.ts

type

ToolId

type ToolId =
  | "select"
  | "selectSeats"
  | "pan"
  | "seat"
  | "rows"
  | "section"
  | "table"
  | "booth"
  | "stage"
  | "rectangle"
  | "polygon"
  | "label"
  | "ga"
  | "divider"
  | "paint"
  | "focal";

@openseat/editor/src/tools.ts

type

WheelMode

What a plain mouse wheel does on the canvas: zoom about the pointer, or scroll the view.

type WheelMode = "zoom" | "pan";

@openseat/editor/src/react/bars.tsx

type

ZoneSettings

Zone settings: the Zone tool's options, or the parts a caller gives.

type ZoneSettings = Partial<ToolOptions["ga"]>;

Members

MemberTypeDescription
modeoptional"rect" | "polygon" | "rounded" | "trapezoid"
capacityoptionalnumber
seatingoptional"standing" | "seated"
categoryIdoptionalstring | null

Every member is readonly.

@openseat/editor/src/tools.ts

type

ZoneShape

How the Zone tool draws: drag a rectangle (plain, rounded or trapezoid) or click the corners of a polygon.

type ZoneShape = "rect" | "rounded" | "polygon" | "trapezoid";

@openseat/editor/src/tools.ts

Constants19

const

CATEGORY_PALETTE

Default colours for new ticket types (categories): twelve clearly different hues, none of them grey, in the order new ticket types take them. Each one has at least 4.5:1 contrast against white (WCAG AA for text), so white seat labels stay readable on them and they stand out on a light canvas.

const CATEGORY_PALETTE: readonly string[]

@openseat/editor/src/category-colours.ts

const

CLIPBOARD_MARKER

Top-level marker key of serialised clipboard text. Its value is the clipboard text version.

const CLIPBOARD_MARKER = "openseat/clipboard"

@openseat/editor/src/clipboard.ts

const

COMMANDS

Every editor command, grouped (edit, arrange, view, rows, sections, tools) in display order.

const COMMANDS: readonly CommandInfo[]

@openseat/editor/src/commands.ts

const

DEFAULT_DIVIDER_CAPTION

Caption a new floor divider gets.

const DEFAULT_DIVIDER_CAPTION = "GROUND FLOOR"

@openseat/editor/src/tools.ts

const

DEFAULT_DRAWING_DEFAULTS

const DEFAULT_DRAWING_DEFAULTS: DrawingDefaults

@openseat/editor/src/store.ts

const

DEFAULT_NOTE_TEXT

Text a new note gets ("Add note text").

const DEFAULT_NOTE_TEXT = "Type your note here"

@openseat/editor/src/tools.ts

const

DEFAULT_ROW_DRAWING

const DEFAULT_ROW_DRAWING: RowDrawingSettings

@openseat/editor/src/row-drawing.ts

const

DEFAULT_TOOL_OPTIONS

const DEFAULT_TOOL_OPTIONS: ToolOptions

@openseat/editor/src/tools.ts

const

EditorContext

const EditorContext: Context<EditorContextValue | null>

@openseat/editor/src/react/context.ts

const

emptyHistory

const emptyHistory: History

@openseat/editor/src/history.ts

const

MAX_CLIPBOARD_BYTES

Longest clipboard text (in UTF-16 code units) that paste will parse.

const MAX_CLIPBOARD_BYTES = 5000000

@openseat/editor/src/clipboard.ts

const

MAX_IMPORT_BYTES

Longest layout JSON that import will parse.

const MAX_IMPORT_BYTES = 20000000

@openseat/editor/src/clipboard.ts

const

MAX_PASTE_OBJECTS

Most objects one paste may add.

const MAX_PASTE_OBJECTS = 50000

@openseat/editor/src/clipboard.ts

const

NOTE_GAP

Gap between the bottom of the content and a new note's centre.

const NOTE_GAP = 40

@openseat/editor/src/tools.ts

const

SHORTCUT_BINDINGS

Every key binding, in the order help lists them.

const SHORTCUT_BINDINGS: readonly ShortcutBinding[]

@openseat/editor/src/shortcuts.ts

const

STAGE_SHAPE_OPTIONS

Plain names of the stage shapes, for the toolbar and the inspector.

const STAGE_SHAPE_OPTIONS: readonly {
  readonly value: StageShape;
  readonly label: string;
}[]

@openseat/editor/src/tools.ts

const

TOOL_KEYS

Single-key tool shortcuts. Shown in toolbar tooltips.

const TOOL_KEYS: Readonly<Record<ToolId, string>>

@openseat/editor/src/shortcuts.ts

const

TOOLS

Toolbar order.

const TOOLS: readonly ToolInfo[]

@openseat/editor/src/tools.ts

const

ZONE_SHAPE_OPTIONS

Plain names of the zone shapes, for the toolbar.

const ZONE_SHAPE_OPTIONS: readonly {
  readonly value: ZoneShape;
  readonly label: string;
  readonly title: string;
}[]

@openseat/editor/src/tools.ts