Skip to content

PDF Generation Template Editor

Open-source visual PDF generation engine with customizable templates and developer-friendly APIs.

View on GitHub

State Management ​

UI state is managed by Pinia, split across two stores. This guide describes the store architecture, the key state each holds, and how the apis/ layer interacts with them.

Store setup ​

packages/webview/src/stores/index.js creates a single Pinia instance and exports setupStore(app) to install it. The stores follow a strict two-store separation (documented in stores/AGENTS.md):

  • Viewer store — "how to look at the document" (UI / view state).
  • Document store — "what's in the document & how to draw on it" (data + tool styles).

Both stores are referenced by ~102 files across components/ and apis/.

Viewer store — modules/viewer.js (useViewerStore, ~1770 lines) ​

Holds UI / view state. Highlights:

CategoryFields
View / navigationcurrentPage, scale, oldScale, newScale, zoomLevel (preset array), scrollMode, pageMode, pageLabels.
Theme / displaytheme ('light'/'dark'), fullScreen, language, languages[].
Tool modetoolMode ('view' default), activeHand, activeStickNote, activeActiveMeasure.
Elements open/closeactiveElements{} (boolean map keyed by DataElements.*), activeElementsTab{}, panelSpace{left,right}, openedPanelsNum{left,right}.
Disabled elementsdisabledElements{} — { disabled, style } per element.
Toolbar definitionheaders{} (per group), rightHeaders[], toolItems{}, documentEditorHeaders, toolbarGroup, activeHeaderGroup.
Signature configsignatureDialogTabs, signatureDialogProperties{}, enableSignatureTemplates, digitalSignature{}, selectedSignatureField, disableSignatureTool, electronicSignaturesList[], digitalSignaturesList[].
StampscustomStamps[], stampPanelTabs[], importStamps[].
ComparecompareStatus, compareMode, showCompareTip.
PopupstextPopup[], cropPagePopup[], contentEditorPopup[], annotationPopup[], showAnnotationPopup, popoverChanged.
Form boardformBoardFold, formBoardPosition{}, enableFillForm, skipNoRequired, consecutiveType.
Misc flagslicense, verified, readOnly, userAdmin, isDisabledHeader, downloading, upload, uploadLoading, customLoading, documentEditorSaveStatus, documentEditorSaveAsStatus, webviewerMode.
FontscustomFonts[], fontSizes[].
Panels configgenericPanels[], customModals[].
Annotation flagsannotation{isAnnotationExport, isAnnotationImport}.

Key actions ​

  • openElement(dataElement, capability?) — sets activeElements[de]=true; closes sibling panels on the same side; on LEFT_PANEL toggles core.toggleSidebar(); on SEARCH_PANEL also opens LEFT_PANEL and switches its tab.
  • closeElement / openElements / closeElements / toggleElement / resetPanels — variants. Closing LEFT_PANEL also calls core.webViewerPageMode('none') and closes SEARCH_PANEL.
  • setActiveElementTab(dataElement, tab) — maps ThumbnailsButton → core.webViewerPageMode('thumbs'), OutlinesButton → 'outline'.
  • setActiveToolMode(mode) — guards readOnly and mobile (blocks separation/measurement); closes context panels; calls core.setToolMode(mode).
  • setToolbarGroup(value) — mobile guard for Separation/Measurement.
  • disableElement / enableElement / disableElements / enableElements(de, key?) — toggle disabled flags.
  • Stamp/signature list mutators persist to localStorage.
  • dispatch(action) / getState(key) — explicitly the API-access channel; expose store actions/state to apis/.

Document store — modules/document.js (useDocumentStore, ~600 lines) ​

Holds document data + tool configuration. Highlights:

CategoryFields
Document metatotalPages, loadingProgress, annotationsCount, info, currentPdfData{}, fileHasPwd, pwd.
Annotationsannotations (shallowReactive), selected{}, selectedAnnotation, outlines[], activeOutlineId, searchResults[], activeSearchResult, layers[], selectedLayer.
Current toolactiveTool, markupTool (default HIGHLIGHT), shapeTool (default SQUARE).
Tool style presetsper-tool { color, opacity?, stroke? } (highlight, underline, squiggly, strikeout, square, arc, polygon, polyline, circle, arrow, line, ink, freetext, text, form fields, redaction, remove).
Property panelpropertyPanel{} — form-field/editor property model.
ComparecompareFiles{}, compareSettings{}, compareResult.
Signaturessignatures[], selectedSignature, trustedCertificateLists[], pkcs12, author, annotator, highlightLink, highlightForm, autoJumpNextSign, disableDigitalSignature, disableElectronicSignature.
Measuremeasure{scale, precision}.
Document editordocumentEditor{operationList[], pageList[], selectedPageList[]}.
Undo/redocanUndo{content, annotation}, canRedo{content, annotation}.

Key actions ​

  • setActiveToolColor(color) — writes this[activeTool].color and calls core.setTool(activeTool).
  • setToolState(tool) — toggles off if same; otherwise looks up map[tool], calls core.setTool(mapTool.tool, mapTool.toolName), sets activeTool, and for form tools calls core.setInitProperty().
  • setActiveToolColor / setPropertyPanel / setCurrentUser / setHighlightLink / setHighlightForm / setAutoJumpNextSign — push the value into core in addition to storing it.
  • initAnnotations / setAnnotations(annotation, type) — manage the annotation array by page index.
  • dispatch(action) / getState(key) — API access.

How apis/ interacts with the stores ​

Each apis/*.js module is a factory (stores...) => (...args) => result. Two access patterns:

  • Via getters for reads: getActiveTool.js → store.getActiveTool.
  • Via dispatch for actions: closeElement.js → store.dispatch('closeElement')(dataElement).

Some APIs (openElement, closeElements, enableElements, disableElements, addPanel, getPanels, isElementOpen, getPassword) use dispatch/getState; others call getters directly. api_helpers/createEncapsulatedStore.js builds the encapsulated viewerStore / documentStore wrappers (exposing only dispatch/getState) used by the popup APIs, getPassword, and getPanels.

Persistence ​

  • localStorage['language'] — selected language.
  • localStorage['customStamps'], ['electronicSignatures'], ['digitalSignatures'] — stamp/signature lists.