Skip to main content

Package structure

src/
types/
schema.ts -> Template/TemplatePage/Schema (text/table/image/section/chart/kpi) + TableColumnStyle
binding.ts -> TableColumn, Binding (includes "chart": path/labelColumn/valueColumn/filters)
dataSource.ts -> DataSourceOption/DataSourceColumnType, SectionColumnDragPayload
page/ -> the sheet itself: how big it is, how it converts, and which band a field lands in
units.ts -> mm <-> px <-> pt conversions + grid (GRID_SIZE_MM, snapToGrid)
sizes.ts -> page size presets + orientation (portrait/landscape)
zones.ts -> classifies a field into header/footer/margin/body + drag lock
template.ts -> migrateTemplate: the version chain, one step per format version
errors.ts -> every error class + describePdfError, the localizer at the edge (no React)
errorUtils.ts -> normalizes any thrown value into a display-safe error message
fieldWarnings.ts -> "missing binding"/"incomplete filter" warning messages (Fields list, tab icons)
materialIcons.ts -> Material Symbols icon paths + EN/PT-BR search labels (KPI icon picker)
numberFormat.ts -> pt-BR number formatting, shared by the KPI card and the CURRENCY/NUMBER formatters
schemaFactory.ts -> creates a new schema (text/table/image/section/chart/kpi) + next free Y
drag.ts -> the drag-and-drop contract: the external field payload + the internal section-column mime
fields/ -> one folder per field type, holding the pure logic that type owns
table/
columns.ts -> keeps a table's head/content/footer/columnStyles in sync with its array binding
colors.ts -> Excel-style header/body/band color presets (Light/Medium/Dark groups)
layout.ts -> resolveColumnWidthsMm — one source of truth shared by the canvas and render/renderTable.ts
columnFormula.ts -> tokenFor (the single key -> token rule) + columnFormulaFor (the resolver's precedence)
+ parses/builds a calculated column's formula (CURRENCY/NUMBER/DATE/raw)
normalizeColumns.ts -> converts raw-key columns into {label, formula} in a saved template + its bindings
columnResize.ts -> the column-resize drag math (grow one side, shrink+clamp the other)
kpi/
card.ts -> KPI card defaults, corner radius, and per-element (icon/title/value/caption) position/lock
format.ts -> KPI value formatting
chart/
colors.ts -> the chart's fixed categorical palettes + labels
format.ts -> chart number/label formatting
pieGeometry.ts -> pie/donut slice path + label point math, shared by the canvas and render/renderChart.ts
canvas/ -> the canvas's pure math, in .ts files because they export no component
geometry.ts -> PageCanvas.tsx's section hit-test + marquee-selection math (pure, testable)
dragGesture.ts -> shared mousedown -> window mousemove/mouseup drag-loop wiring (KPI drag, column resize)
zoomScale.ts -> the zoom limits/step and clampZoom, shared by the canvas and the zoom context
i18n/
locales/
en.ts, pt-BR.ts -> the Designer's own UI text, one file per language (en is canonical, and `Dict`
is literally `typeof en`)
dictionaries.ts -> the locale -> Dict map + dictFor(locale) — React-free, so /server can import it
context.tsx, contextValue.ts, hooks.ts -> I18nProvider, useT, useLocale (three files because a .tsx
may only export components — see the comment in contextValue.ts)
withInlineCode.tsx -> renders a translated string's `` `code` `` spans as real <code>
bindings/
bindings.ts -> resolves bindings (scalar/array/keyvalue/template/section/chart/kpi)
+ resolveChartItems/aggregateChartItems ("chart" binding)
builders.ts -> pure per-schema-type binding builders used by BindingEditor.tsx, testable without React
columnParsing.ts -> parses the table's free-text "col, Label={FUNCTION(...)}" input
splitDelimited.ts -> splits on a delimiter while respecting quotes/parens (used by the two above)
expressions/ -> the {token}/{FUNCTION(...)} engine, and the seven modules the rest of the package calls
engine/ -> the pipeline itself — nothing outside expressions/ imports these five
tokenize.ts -> chars -> tokens (an operator only counts when surrounded by whitespace)
parse.ts -> tokens -> AST, with operator precedence and real grouping
evaluate.ts -> AST + data -> value (no eval/new Function)
functions.ts -> the SUM/COUNT/AVG/CONCAT/DATE/CURRENCY/NUMBER/IF registry
formatters.ts -> DATE/CURRENCY formatting (UTC-safe, pt-BR numbers)
resolve.ts -> renderTemplate + expressionError: the entry point everything else uses
templateText.ts -> what the editor needs to know about a field's text template ("FAT-{[fatura]}")
schemaExpressions.ts -> collects a whole Template's expression errors and suspicious operators
suggest.ts -> the ƒx editor's autocomplete (functions and word operators only, never field names)
suspicious.ts -> an operator with whitespace on one side only — the lexical rule's blind spot
errors.ts -> ExpressionError/SyntaxError/DepthError + the code -> message table
dataAccess.ts -> path lookup + value comparison, shared with the binding filters
pdf/
generate.ts -> thin orchestrator: asks layout/ where everything goes, then draws it —
no pagination decision of its own
layout/ -> pure math, no pdf-lib
layoutDocument.ts-> THE pagination pass: Template+data -> LayoutDocument (pages of Placements)
layoutTypes.ts -> BodyItem/FlowBounds shapes
bodyLayout.ts -> buildBodyItems (groups schemas into BodyItems by Y) + boundsOf/gapAfter
pageLayout.ts -> normalizePageDefs (single vs. multi-page)
sectionLayout.ts -> section measurement (how many repeats, how tall each one is)
render/
index.ts -> drawFieldOfType, the per-type dispatcher (text/image/table/chart/kpi)
renderTable.ts -> draws a table in pdf-lib across page slices, header/value/footer with color/size
renderSection.ts -> draws a repeated section, one pass per bound array item
renderChart.ts -> draws pie (slices via drawSvgPath) or bar + legend in pdf-lib
renderKpi.ts -> draws the KPI card (background + traced icon + title/value/caption)
renderText.ts, renderImage.ts -> the two simplest field types (renderImage.ts also owns the
image size/count safety limits)
pagination.ts -> splits body content across pages against the header/footer/margin bands
tableMetrics.ts -> table row height + rows-per-slice (no pdf-lib, shared with layout/)
svgShapes.ts -> roundedRectPath (uniform or per-corner radius) shared by render/renderTable.ts/render/renderKpi.ts
textSafety.ts -> control-character sanitisation + missing-glyph error naming the field (see "Failure modes")
textLayout.ts -> alignX/alignY offset math + truncateToWidth, shared by render/renderTable.ts/render/renderText.ts
resolvers.ts, color.ts -> small shared helpers for layout/ and render/
fontUtils.ts -> WOFF/WOFF2 -> real TTF/OTF (pure zlib for v1; v2 needs the
optional peer dep `wawoff2`, lazy-loaded, not installed by default)
pdfWorker.ts -> shared pdf.js worker configuration
backgroundImage.ts -> turns an uploaded PNG/JPEG into the page's background PNG (image only —
see the entry-point boundary in ARCHITECTURE.md)
thirdParty.d.ts -> ambient types for wawoff2/tiny-inflate (no official @types)
css/ -> hand-written CSS, copied verbatim into dist/ by tsup's publicDir
theme.css -> the reset (via @import) + the finished look, all inside @layer json-pdf-designer
reset.css -> the appearance-free subset: what the editor used to inherit from Tailwind's Preflight
designer/
Designer.tsx -> the PRESET: three providers + two parts in a two-column layout (101 lines)
context/ -> DesignerProvider.tsx + the five contexts (contexts.ts), the hooks (hooks.ts),
the pure derivations the selectors call (derived.ts), and the zoom context
(zoom.tsx/zoomContext.ts/useDesignerZoom.ts)
parts/ -> the ten placeable parts, one file each, + useTabGate.ts (the opt-in tab gate)
actions.ts -> every Template/Binding[] mutator, each reading from the updater's `prev`
(which is what keeps the actions context identity-stable)
useTabBar.ts, useSelection.ts, useClipboardAndDelete.ts -> the hooks the provider is built from
helpers.ts -> pure spawn-position/name-dedup/data-source-lookup helpers
components/
PageCanvas.tsx -> the A4 sheet, rulers, zoom (zoom-aware drag/resize), grid, red bands,
marquee selection, drag/resize/inline editing
FieldBox/ -> renders text/table/image/section/chart/kpi on the canvas (one file per type)
FieldList.tsx -> the side field list (select/lock/remove, send-to-back/bring-to-front)
TemplateInspector.tsx -> read-only tree of the current page's fields, grouped by header/body/footer zone
Toolbar.tsx -> the "+ text/table/image/section/chart/kpi" buttons
PropertyPanel/
index.tsx -> thin dispatcher to one PropertyPanel<Type>.tsx per schema type
PropertyPanelText.tsx, PropertyPanelTable.tsx, PropertyPanelImage.tsx, PropertyPanelSection.tsx,
PropertyPanelChart.tsx, PropertyPanelKpi.tsx, PropertyPanelFields.tsx -> per-type Data/Style content
formula/ -> the ƒx expression editor, the one place a formula is typed
FormulaModal.tsx -> the modal: autocomplete, live preview against the sample row, error surfacing
FormulaButton.tsx -> the ƒx button that opens it, with its "this column has a formula" active state
DataTypeFields.tsx -> the field pickers inside the modal, one per data type
BindingEditor.tsx -> the generic binding UI (scalar/template/array/keyvalue/section/chart + calculated columns)
Ruler.tsx -> the mm ruler (SVG)
PdfPreview.tsx -> preview of the generated PDF via pdf.js
PdfPreviewModal.tsx-> a full modal around PdfPreview (exported, see above)
ui/ -> Button, Input, Card, Select, Textarea, Checkbox, Modal, TabPanel, PalettePicker,
CollapsibleSection, ClearFieldButton, icons — exported (see above), used internally
registry.ts -> the 12 slots + defaultUiComponents; UiComponentsProvider.tsx / useUiComponents.ts
cx.ts -> class merge (dedupes exact tokens, returns undefined when empty) + mergeStyle
useDialogA11y.ts -> what makes an overlay a DIALOG: focus in on open, Tab trapped, focus back on
close, Escape to close — shared, because PdfPreviewModal skips the Modal shell
index.ts -> the package's public exports (never reaches pdfjs-dist)
server.ts -> the "/server" entry: the React-free half (generatePdf, migrateTemplate, the errors)
preview.ts -> the "/preview" entry: the ONLY graph allowed to import pdfjs-dist
examples/ (each one on a different point of the styling spectrum)
report-builder/ -> a full app (JSON data sources, field explorer) using the package's ready-made UI
-- theme.css as it ships, no customization
composed-layout/ -> the same editor in a layout the preset cannot do: 8 parts in the DOM at once, no tab bar
-- theme.css rethemed by --jpd-* token only, not one rule rewritten
custom-ui/ -> the same idea, a 100% custom shell (hand-written CSS, no package component)
-- no package CSS at all: 192 .jpd-* selectors from scratch
headless-designer/ -> no <Designer> at all — a hand-built editor over json-pdf-designer/server + PdfPreview
-- reset.css alone, the only example on the appearance-free export
no-preview/ -> generates + downloads with no preview and no pdfjs-dist installed
-- theme.css in dark mode, the only app that exercises dark