@bambamboole/pdf-ua-template-builder 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +119 -17
  2. package/dist/builder/Builder.d.ts +7 -0
  3. package/dist/builder/TemplateBuilder.d.ts +10 -13
  4. package/dist/builder/blocks/Palette.d.ts +7 -0
  5. package/dist/builder/canvas/BlockDataPreview.d.ts +7 -0
  6. package/dist/builder/canvas/BuilderCanvas.d.ts +8 -4
  7. package/dist/builder/canvas/Canvas.d.ts +4 -0
  8. package/dist/builder/canvas/ColumnResizer.d.ts +2 -1
  9. package/dist/builder/canvas/PageSheet.d.ts +3 -1
  10. package/dist/builder/canvas/SortableBlock.d.ts +7 -5
  11. package/dist/builder/canvas/columns.d.ts +9 -0
  12. package/dist/builder/context/BuilderContext.d.ts +66 -0
  13. package/dist/builder/controls/AlignSelect.d.ts +7 -0
  14. package/dist/builder/controls/BuilderField.d.ts +74 -0
  15. package/dist/builder/controls/Field.d.ts +6 -0
  16. package/dist/builder/controls/fieldConverters.d.ts +4 -0
  17. package/dist/builder/controls/index.d.ts +7 -0
  18. package/dist/builder/controls/inputs.d.ts +5 -0
  19. package/dist/builder/hooks/useBuilderDragDrop.d.ts +25 -0
  20. package/dist/builder/inspector/BlockContentControls.d.ts +9 -0
  21. package/dist/builder/inspector/BlockInspector.d.ts +14 -0
  22. package/dist/builder/inspector/BlockLayoutControls.d.ts +7 -0
  23. package/dist/builder/inspector/DocumentSettings.d.ts +18 -0
  24. package/dist/builder/inspector/Inspector.d.ts +1 -0
  25. package/dist/builder/inspector/InspectorShell.d.ts +19 -0
  26. package/dist/builder/inspector/PageSettings.d.ts +4 -0
  27. package/dist/builder/inspector/SpacingControls.d.ts +15 -0
  28. package/dist/builder/inspector/TypographyControls.d.ts +19 -0
  29. package/dist/builder/inspector/alignOptions.d.ts +10 -0
  30. package/dist/builder/inspector/editors/ImageBlockEditor.d.ts +3 -0
  31. package/dist/builder/inspector/editors/KeyValueBlockEditor.d.ts +11 -0
  32. package/dist/builder/inspector/editors/SortableList.d.ts +7 -0
  33. package/dist/builder/inspector/editors/SortableRow.d.ts +10 -0
  34. package/dist/builder/inspector/editors/TableBlockEditor.d.ts +20 -0
  35. package/dist/builder/inspector/editors/blockEditors.d.ts +7 -0
  36. package/dist/builder/lib/records.d.ts +4 -0
  37. package/dist/builder/lib/sensors.d.ts +1 -0
  38. package/dist/builder/primitives/Button.d.ts +10 -0
  39. package/dist/builder/primitives/Chip.d.ts +7 -0
  40. package/dist/builder/schema/schemaAdapter.d.ts +2 -5
  41. package/dist/builder/state/configUpdates.d.ts +23 -0
  42. package/dist/builder/state/dragDrop.d.ts +17 -0
  43. package/dist/builder/state/editorModel.d.ts +5 -0
  44. package/dist/builder/state/editorReducer.d.ts +71 -0
  45. package/dist/editor/CodeEditor.d.ts +4 -0
  46. package/dist/editor/TemplateEditor.d.ts +23 -0
  47. package/dist/editor/TemplateEditorContext.d.ts +20 -0
  48. package/dist/editor/editorTheme.d.ts +1 -0
  49. package/dist/editor/parseTemplate.d.ts +6 -0
  50. package/dist/editor/templateSchema.d.ts +1 -0
  51. package/dist/index.d.ts +12 -0
  52. package/dist/index.js +3906 -5260
  53. package/dist/index.js.map +1 -1
  54. package/dist/render/PdfPane.d.ts +14 -0
  55. package/dist/render/Preview.d.ts +4 -0
  56. package/dist/render/RenderContext.d.ts +17 -0
  57. package/dist/render/usePdfUaApi.d.ts +19 -0
  58. package/dist/style.css +3 -1
  59. package/dist/types/template.d.ts +5 -1
  60. package/package.json +25 -9
  61. package/dist/builder/forms/InlineBlockForm.d.ts +0 -9
  62. package/dist/builder/pdf/PdfPane.d.ts +0 -11
  63. package/dist/builder/topbar/BuilderTopbar.d.ts +0 -17
package/README.md CHANGED
@@ -1,13 +1,16 @@
1
1
  # @bambamboole/pdf-ua-template-builder
2
2
 
3
- An embeddable React template builder for the
4
- [pdf-ua-api](https://github.com/bambamboole/pdf-ua-api) PDF/UA renderer.
3
+ Embeddable React components for authoring
4
+ [pdf-ua-api](https://github.com/bambamboole/pdf-ua-api) PDF/UA templates — a
5
+ visual drag-and-drop **builder** and a schema-validated **JSON editor**, each
6
+ with a live rendered-PDF preview.
5
7
 
6
- - Hybrid block cards that expand inline for editing
8
+ - **Visual builder** — hybrid block cards that expand inline for editing
9
+ - **JSON editor** — CodeMirror with schema-aware autocomplete, validation, and hover
7
10
  - Page-format aware canvas (A3/A4/A5/A6/Letter/Legal/Tabloid + orientation)
8
11
  - Repeated footer area and page-number controls
9
12
  - Animated drag-and-drop with full keyboard accessibility (powered by dnd-kit)
10
- - Lightweight neutral UI built around CSS custom properties
13
+ - Light/dark theming and composable provider + parts, built on CSS custom properties
11
14
 
12
15
  ## Install
13
16
 
@@ -27,14 +30,11 @@ npm install react react-dom
27
30
  import { TemplateBuilder, createInvoiceExample } from "@bambamboole/pdf-ua-template-builder";
28
31
  import "@bambamboole/pdf-ua-template-builder/style.css";
29
32
 
30
- const example = createInvoiceExample();
31
-
32
33
  export default function App() {
33
34
  return (
34
35
  <TemplateBuilder
35
36
  apiUrl="http://localhost:8080"
36
- initialTemplate={example.template}
37
- initialData={example.data}
37
+ examples={{ Invoice: createInvoiceExample() }}
38
38
  onChange={(template, data) => console.log("changed", template, data)}
39
39
  onRendered={(pdf) => console.log("rendered pdf blob", pdf)}
40
40
  />
@@ -44,14 +44,116 @@ export default function App() {
44
44
 
45
45
  ## Props
46
46
 
47
- | Prop | Type | Description |
48
- | ----------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
49
- | `apiUrl` | `string` | Base URL of a running `pdf-ua-api`. Defaults to `""` (relative URL / proxy). |
50
- | `initialTemplate` | `Template` | Template loaded on first render. |
51
- | `initialData` | `Record<string, unknown>` | Runtime data keyed by block id (table rows, dynamic key-value overrides). |
52
- | `onChange` | `(template: Template, data: Record<string, unknown>) => void` | Fires on every edit. |
53
- | `onRendered` | `(pdf: Blob) => void` | Fires after a successful render. |
54
- | `className` | `string` | Class appended to the root element. |
47
+ | Prop | Type | Description |
48
+ | ----------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------- |
49
+ | `apiUrl` | `string` | Base URL of a running `pdf-ua-api`. Defaults to `""` (relative URL / proxy). |
50
+ | `initialTemplate` | `Template` | Template loaded on first render. |
51
+ | `initialData` | `Record<string, unknown>` | Runtime data keyed by block id (table rows, dynamic key-value overrides). |
52
+ | `examples` | `Record<string, { template: Template; data?: TemplateData }>` | Loadable examples keyed by display name. The palette's Load control only appears when this is non-empty. |
53
+ | `onChange` | `(template: Template, data: Record<string, unknown>) => void` | Fires on every edit. |
54
+ | `onRendered` | `(pdf: Blob) => void` | Fires after a successful render. |
55
+ | `className` | `string` | Class appended to the root element. |
56
+
57
+ ## Composable layout
58
+
59
+ `<TemplateBuilder />` is a preset that places a `Builder` and a `Preview`
60
+ side-by-side. When you need a different arrangement — for example the PDF
61
+ preview **below** the builder inside a docs page — compose the parts yourself.
62
+ `TemplateBuilderProvider` owns the shared state and drag-and-drop context; place
63
+ `Builder` and `Preview` inside it however you like. Both accept a `className` for
64
+ positioning and sizing:
65
+
66
+ ```tsx
67
+ import {
68
+ TemplateBuilderProvider,
69
+ Builder,
70
+ Preview,
71
+ createInvoiceExample,
72
+ } from "@bambamboole/pdf-ua-template-builder";
73
+ import "@bambamboole/pdf-ua-template-builder/style.css";
74
+
75
+ export default function StackedBuilder() {
76
+ return (
77
+ <TemplateBuilderProvider apiUrl="http://localhost:8080">
78
+ <div className="flex flex-col gap-3">
79
+ <Builder examples={{ Invoice: createInvoiceExample() }} className="h-[36rem]" />
80
+ <Preview className="h-[40rem]" />
81
+ </div>
82
+ </TemplateBuilderProvider>
83
+ );
84
+ }
85
+ ```
86
+
87
+ `Builder` groups the palette, canvas, and inspector; `Preview` shows the rendered
88
+ PDF and the Render button. `TemplateBuilderProvider` accepts the same props as
89
+ `<TemplateBuilder />` except `examples` and `className` (`apiUrl`,
90
+ `initialTemplate`, `initialData`, `onChange`, `onRendered`). Because the provider
91
+ does not impose a height, give `Builder` and `Preview` explicit sizes when you
92
+ are not filling the viewport. For fully custom parts, the `useTemplateBuilder()`
93
+ hook exposes the underlying state and actions.
94
+
95
+ ## JSON editor
96
+
97
+ Prefer raw JSON? `TemplateEditor` is a drop-in alternative to `TemplateBuilder`:
98
+ a CodeMirror editor with schema-aware autocomplete, validation, and hover (driven
99
+ by the bundled template JSON Schema), paired with the same rendered-PDF preview.
100
+
101
+ ```tsx
102
+ import { TemplateEditor, createInvoiceExample } from "@bambamboole/pdf-ua-template-builder";
103
+ import "@bambamboole/pdf-ua-template-builder/style.css";
104
+
105
+ const example = createInvoiceExample();
106
+
107
+ export default function App() {
108
+ return (
109
+ <TemplateEditor
110
+ apiUrl="http://localhost:8080"
111
+ initialTemplate={example.template}
112
+ data={example.data}
113
+ onChange={(template, text) => console.log("edited", template, text)}
114
+ onRendered={(pdf) => console.log("rendered pdf blob", pdf)}
115
+ />
116
+ );
117
+ }
118
+ ```
119
+
120
+ The editor owns the JSON text; `data` is passed straight through to render.
121
+ `onChange(template, text)` fires on every edit — `template` is `null` while the
122
+ JSON is invalid, and Render is disabled until it parses. Schema problems surface
123
+ as inline editor diagnostics.
124
+
125
+ It composes exactly like the builder, and shares the same `Preview`:
126
+
127
+ ```tsx
128
+ import { TemplateEditorProvider, CodeEditor, Preview } from "@bambamboole/pdf-ua-template-builder";
129
+
130
+ <TemplateEditorProvider apiUrl="http://localhost:8080" initialTemplate={example.template}>
131
+ <div className="flex flex-col gap-3">
132
+ <CodeEditor className="h-[36rem]" />
133
+ <Preview className="h-[40rem]" />
134
+ </div>
135
+ </TemplateEditorProvider>
136
+ ```
137
+
138
+ `useTemplateEditor()` exposes the text and parsed state (`{ text, setText,
139
+ template, error, data }`) for custom UIs.
140
+
141
+ ## Dark mode
142
+
143
+ The builder and editor ship a dark theme built from the same semantic tokens. It
144
+ turns on automatically when the OS prefers dark (`prefers-color-scheme: dark`) and
145
+ whenever an ancestor element carries `data-theme="dark"` (or a `.dark` class) — so
146
+ it syncs with hosts like Starlight out of the box. Force a mode explicitly with
147
+ `data-theme="light"` or `data-theme="dark"` on a wrapper element:
148
+
149
+ ```tsx
150
+ <div data-theme="dark">
151
+ <TemplateBuilder apiUrl="http://localhost:8080" />
152
+ </div>
153
+ ```
154
+
155
+ The on-canvas page and the rendered-PDF preview stay light ("paper") in both
156
+ themes, matching the white PDF the backend produces.
55
157
 
56
158
  ## Backend
57
159
 
@@ -93,7 +195,7 @@ npm run lint # oxlint
93
195
  ```
94
196
 
95
197
  `npm run dev` proxies `/schema` and `/render/*` to a local `pdf-ua-api`
96
- (default: `http://localhost:8080`, override with `PDF_UA_API_PROXY_URL`).
198
+ (default: `http://localhost:9999`, override with `PDF_UA_API_PROXY_URL`).
97
199
 
98
200
  ## License
99
201
 
@@ -0,0 +1,7 @@
1
+ import { TemplateExample } from './context/BuilderContext';
2
+ export interface BuilderProps {
3
+ className?: string;
4
+ /** Loadable examples surfaced in the palette, keyed by display name. */
5
+ examples?: Record<string, TemplateExample>;
6
+ }
7
+ export declare function Builder({ className, examples }?: BuilderProps): import("react/jsx-runtime").JSX.Element;
@@ -1,7 +1,6 @@
1
- import { UniqueIdentifier } from '@dnd-kit/core';
2
1
  import { Template } from '../types/generated/template';
3
2
  import { TemplateData } from '../types/template';
4
- import { EditorArea, EditorModel } from './state/editorModel';
3
+ import { TemplateExample } from './context/BuilderContext';
5
4
  export interface TemplateBuilderProps {
6
5
  /** Base URL of a running pdf-ua-api instance. Defaults to "" (relative URLs / proxy). */
7
6
  apiUrl?: string;
@@ -9,6 +8,8 @@ export interface TemplateBuilderProps {
9
8
  initialTemplate?: Template;
10
9
  /** Runtime data keyed by block id (table rows, dynamic key-value overrides). */
11
10
  initialData?: TemplateData;
11
+ /** Loadable examples surfaced in the palette, keyed by display name. */
12
+ examples?: Record<string, TemplateExample>;
12
13
  /** Fires whenever the user edits the template or its runtime data. */
13
14
  onChange?: (template: Template, data: TemplateData) => void;
14
15
  /** Fires after a successful render with the produced PDF blob. */
@@ -16,14 +17,10 @@ export interface TemplateBuilderProps {
16
17
  /** Optional className appended to the root element. */
17
18
  className?: string;
18
19
  }
19
- interface DragData {
20
- source?: string;
21
- type?: string;
22
- rowUid?: string;
23
- blockUid?: string;
24
- area?: EditorArea;
25
- }
26
- export declare function TemplateBuilder({ apiUrl: initialApiUrlProp, initialTemplate, initialData, onChange, onRendered, className, }?: TemplateBuilderProps): import("react/jsx-runtime").JSX.Element;
27
- export declare function getRowIndex(model: EditorModel, overId: UniqueIdentifier | undefined, overData: DragData): number | null;
28
- export declare function createNextBlockId(model: EditorModel, blockType: string): string;
29
- export {};
20
+ /**
21
+ * All-in-one preset: a provider wrapping a Builder and a Preview side by side.
22
+ *
23
+ * For custom layouts (e.g. preview below the builder), compose the parts
24
+ * directly with `TemplateBuilderProvider`, `Builder`, and `Preview`.
25
+ */
26
+ export declare function TemplateBuilder({ apiUrl, initialTemplate, initialData, examples, onChange, onRendered, className, }?: TemplateBuilderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { TemplateExample } from '../context/BuilderContext';
2
+ export interface PaletteProps {
3
+ className?: string;
4
+ /** Loadable examples keyed by display name. The Load control only renders when non-empty. */
5
+ examples?: Record<string, TemplateExample>;
6
+ }
7
+ export declare function Palette({ className, examples }?: PaletteProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { Block } from '../../types/generated/template';
2
+ export interface BlockDataPreviewProps {
3
+ block: Block;
4
+ rowData?: unknown;
5
+ onChange?: (block: Block) => void;
6
+ }
7
+ export declare function BlockDataPreview({ block, rowData, onChange }: BlockDataPreviewProps): import("react/jsx-runtime").JSX.Element | null;
@@ -1,17 +1,21 @@
1
1
  import { Block, Orientation, PageFormat } from '../../types/generated/template';
2
- import { TemplateSchemaResponse } from '../../types/template';
2
+ import { TemplateData } from '../../types/template';
3
3
  import { EditorModel, PageNumbersValue } from '../state/editorModel';
4
4
  export interface BuilderCanvasProps {
5
- schema: TemplateSchemaResponse;
6
5
  model: EditorModel;
6
+ data: TemplateData;
7
7
  format: PageFormat;
8
8
  orientation: Orientation;
9
9
  footerRepeat: boolean;
10
10
  pageNumbers: PageNumbersValue;
11
- onChangeBlock: (blockUid: string, block: Block) => void;
11
+ selectedBlockUid: string | null;
12
12
  onRemoveBlock: (blockUid: string) => void;
13
+ onSelectBlock: (blockUid: string) => void;
14
+ onChangeBlock: (blockUid: string, block: Block) => void;
15
+ onDeselect: () => void;
13
16
  onSetRowWidths: (rowUid: string, widths: string[]) => void;
14
17
  onToggleFooterRepeat: (repeat: boolean) => void;
15
18
  onChangePageNumbers: (value: PageNumbersValue) => void;
19
+ className?: string;
16
20
  }
17
- export declare function BuilderCanvas({ schema, model, format, orientation, footerRepeat, pageNumbers, onChangeBlock, onRemoveBlock, onSetRowWidths, onToggleFooterRepeat, onChangePageNumbers, }: BuilderCanvasProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function BuilderCanvas({ model, data, format, orientation, footerRepeat, pageNumbers, selectedBlockUid, onRemoveBlock, onSelectBlock, onChangeBlock, onDeselect, onSetRowWidths, onToggleFooterRepeat, onChangePageNumbers, className, }: BuilderCanvasProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ export interface CanvasProps {
2
+ className?: string;
3
+ }
4
+ export declare function Canvas({ className }?: CanvasProps): import("react/jsx-runtime").JSX.Element;
@@ -5,5 +5,6 @@ export interface ColumnResizerProps {
5
5
  leftIndex: number;
6
6
  containerRef: RefObject<HTMLElement | null>;
7
7
  onResize: (widths: string[]) => void;
8
+ label?: string;
8
9
  }
9
- export declare function ColumnResizer({ widths, count, leftIndex, containerRef, onResize, }: ColumnResizerProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function ColumnResizer({ widths, count, leftIndex, containerRef, onResize, label, }: ColumnResizerProps): import("react/jsx-runtime").JSX.Element;
@@ -4,5 +4,7 @@ export interface PageSheetProps {
4
4
  format: PageFormat;
5
5
  orientation: Orientation;
6
6
  children: ReactNode;
7
+ /** Show the "{format} · {orientation} / {width}mm" caption. Off for the footer sheet. */
8
+ showMeta?: boolean;
7
9
  }
8
- export declare function PageSheet({ format, orientation, children }: PageSheetProps): import("react/jsx-runtime").JSX.Element;
10
+ export declare function PageSheet({ format, orientation, children, showMeta }: PageSheetProps): import("react/jsx-runtime").JSX.Element;
@@ -1,14 +1,16 @@
1
1
  import { CSSProperties } from 'react';
2
- import { EditorArea, EditorBlock } from '../state/editorModel';
3
2
  import { Block } from '../../types/generated/template';
4
- import { TemplateSchemaResponse } from '../../types/template';
3
+ import { EditorArea, EditorBlock } from '../state/editorModel';
4
+ import { TemplateData } from '../../types/template';
5
5
  export interface SortableBlockProps {
6
6
  rowUid: string;
7
7
  area: EditorArea;
8
8
  editorBlock: EditorBlock;
9
- schema: TemplateSchemaResponse;
10
- onChangeBlock: (blockUid: string, block: Block) => void;
9
+ data: TemplateData;
10
+ selected: boolean;
11
11
  onRemoveBlock: (blockUid: string) => void;
12
+ onSelect: (blockUid: string) => void;
13
+ onChangeBlock: (blockUid: string, block: Block) => void;
12
14
  style?: CSSProperties;
13
15
  }
14
- export declare function SortableBlock({ rowUid, area, editorBlock, schema, onChangeBlock, onRemoveBlock, style: layoutStyle, }: SortableBlockProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare function SortableBlock({ rowUid, area, editorBlock, data, selected, onRemoveBlock, onSelect, onChangeBlock, style: layoutStyle, }: SortableBlockProps): import("react/jsx-runtime").JSX.Element;
@@ -2,3 +2,12 @@ export declare function parseWidths(widths: readonly (number | string)[] | null
2
2
  export declare function formatWidths(widths: readonly number[]): string[];
3
3
  export declare function gridTemplateForWidths(widths: readonly string[] | null | undefined, count: number): string | null;
4
4
  export declare function setBoundary(widths: readonly number[], leftIndex: number, leftPercent: number): number[];
5
+ export declare function labelWidthPercent(width: string | null | undefined, fallback?: number): number;
6
+ export declare const NUMBER_COLUMN_RESERVE = 5;
7
+ export interface TableColumnTracks {
8
+ tracks: number[];
9
+ data: number[];
10
+ }
11
+ export declare function percentWidth(width: string | number | null | undefined): number | null;
12
+ export declare function distribute(count: number, total: number): number[];
13
+ export declare function tableColumnTracks(widths: readonly (string | null | undefined)[], numberRows: boolean): TableColumnTracks;
@@ -0,0 +1,66 @@
1
+ import { ReactNode } from 'react';
2
+ import { Block, Orientation, PageFormat, Template } from '../../types/generated/template';
3
+ import { TemplateData, TemplateSchemaResponse } from '../../types/template';
4
+ import { EditorBlock, EditorModel, PageNumbersValue, ResolvedPageSize } from '../state/editorModel';
5
+ import { getBlockTypes } from '../schema/schemaAdapter';
6
+ /** A loadable example: a template plus its optional runtime data. */
7
+ export interface TemplateExample {
8
+ template: Template;
9
+ data?: TemplateData;
10
+ }
11
+ export interface TemplateBuilderProviderProps {
12
+ /** Base URL of a running pdf-ua-api instance. Defaults to "" (relative URLs / proxy). */
13
+ apiUrl?: string;
14
+ /** Template loaded into the editor on first render. */
15
+ initialTemplate?: Template;
16
+ /** Runtime data keyed by block id (table rows, dynamic key-value overrides). */
17
+ initialData?: TemplateData;
18
+ /** Fires whenever the user edits the template or its runtime data. */
19
+ onChange?: (template: Template, data: TemplateData) => void;
20
+ /** Fires after a successful render with the produced PDF blob. */
21
+ onRendered?: (pdf: Blob) => void;
22
+ /** Pane slots to arrange. They share this provider's state and DnD context. */
23
+ children: ReactNode;
24
+ }
25
+ /** Editor state and derived values. Changes as the user edits. */
26
+ export interface BuilderState {
27
+ schema: TemplateSchemaResponse | null;
28
+ schemaLoading: boolean;
29
+ model: EditorModel;
30
+ data: TemplateData;
31
+ serializedTemplate: Template;
32
+ selectedBlockUid: string | null;
33
+ selectedBlock: EditorBlock | null;
34
+ blockTypes: ReturnType<typeof getBlockTypes>;
35
+ pageSize: ResolvedPageSize;
36
+ footerRepeat: boolean;
37
+ pageNumbers: PageNumbersValue;
38
+ pdfUrl: string | null;
39
+ pdfLoading: boolean;
40
+ error: string | null;
41
+ }
42
+ /** Stable editor actions. Identity never changes for the provider's lifetime. */
43
+ export interface BuilderActions {
44
+ renderPdf: () => void;
45
+ loadExample: (example: TemplateExample) => void;
46
+ addBlock: (type: string) => void;
47
+ changeBlock: (blockUid: string, block: Block) => void;
48
+ changeTemplateSettings: (template: Template) => void;
49
+ removeBlock: (blockUid: string) => void;
50
+ selectBlock: (blockUid: string) => void;
51
+ deselect: () => void;
52
+ setRowWidths: (rowUid: string, widths: string[]) => void;
53
+ changeData: (data: TemplateData) => void;
54
+ changeFormat: (format: PageFormat) => void;
55
+ changeOrientation: (orientation: Orientation) => void;
56
+ toggleFooterRepeat: (repeat: boolean) => void;
57
+ changePageNumbers: (value: PageNumbersValue) => void;
58
+ }
59
+ export type BuilderContextValue = BuilderState & BuilderActions;
60
+ /** Subscribe to editor state. Re-renders on edits. */
61
+ export declare function useBuilderState(): BuilderState;
62
+ /** Read the stable editor actions. Does not re-render on edits. */
63
+ export declare function useBuilderActions(): BuilderActions;
64
+ /** Headless escape hatch returning both state and actions. */
65
+ export declare function useTemplateBuilder(): BuilderContextValue;
66
+ export declare function TemplateBuilderProvider({ apiUrl: apiUrlProp, initialTemplate, initialData, onChange, onRendered, children, }: TemplateBuilderProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ export interface AlignSelectProps {
2
+ name: string;
3
+ value: string;
4
+ label?: string;
5
+ onChange: (value: string) => void;
6
+ }
7
+ export declare function AlignSelect({ name, value, label, onChange }: AlignSelectProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,74 @@
1
+ import { ReactNode } from 'react';
2
+ export type EmptyTextValue = "empty-string" | "undefined";
3
+ export interface BuilderControlProps {
4
+ name: string;
5
+ label: string;
6
+ help?: ReactNode;
7
+ error?: ReactNode;
8
+ id?: string;
9
+ className?: string;
10
+ disabled?: boolean;
11
+ }
12
+ export interface TextFieldProps extends BuilderControlProps {
13
+ value?: string;
14
+ placeholder?: string;
15
+ emptyValue?: EmptyTextValue;
16
+ autoComplete?: string;
17
+ onChange: (value: string | undefined) => void;
18
+ }
19
+ export interface TextAreaFieldProps extends BuilderControlProps {
20
+ value?: string;
21
+ placeholder?: string;
22
+ emptyValue?: EmptyTextValue;
23
+ rows?: number;
24
+ onChange: (value: string | undefined) => void;
25
+ }
26
+ export interface NumberFieldProps extends BuilderControlProps {
27
+ value?: number;
28
+ min?: number;
29
+ max?: number;
30
+ step?: number | "any";
31
+ placeholder?: string;
32
+ onChange: (value: number | undefined) => void;
33
+ }
34
+ export interface SelectFieldOption<Value extends string> {
35
+ value: Value;
36
+ label: string;
37
+ disabled?: boolean;
38
+ }
39
+ export interface SelectFieldProps<Value extends string> extends BuilderControlProps {
40
+ value?: Value;
41
+ options: readonly SelectFieldOption<Value>[];
42
+ optional?: boolean;
43
+ emptyLabel?: string;
44
+ onChange: (value: Value | undefined) => void;
45
+ }
46
+ export interface CheckboxFieldProps extends BuilderControlProps {
47
+ checked: boolean;
48
+ onChange: (checked: boolean) => void;
49
+ }
50
+ export interface ColorFieldProps extends BuilderControlProps {
51
+ value?: string;
52
+ fallbackValue?: string;
53
+ onChange: (value: string | undefined) => void;
54
+ }
55
+ export interface UnitFieldProps extends BuilderControlProps {
56
+ value?: string;
57
+ placeholder?: string;
58
+ emptyValue?: EmptyTextValue;
59
+ readOnly?: boolean;
60
+ onChange?: (value: string | undefined) => void;
61
+ }
62
+ interface FieldLayoutProps extends BuilderControlProps {
63
+ children: ReactNode;
64
+ }
65
+ export declare function TextField({ value, placeholder, emptyValue, autoComplete, onChange, ...fieldProps }: TextFieldProps): ReactNode;
66
+ export declare function TextAreaField({ value, placeholder, emptyValue, rows, onChange, ...fieldProps }: TextAreaFieldProps): ReactNode;
67
+ export declare function NumberField({ value, min, max, step, placeholder, onChange, ...fieldProps }: NumberFieldProps): ReactNode;
68
+ export declare function SelectField<Value extends string>({ value, options, optional, emptyLabel, onChange, ...fieldProps }: SelectFieldProps<Value>): ReactNode;
69
+ export declare function CheckboxField({ checked, onChange, ...fieldProps }: CheckboxFieldProps): ReactNode;
70
+ export declare function ColorField({ value, fallbackValue, onChange, ...fieldProps }: ColorFieldProps): ReactNode;
71
+ export declare function UnitField({ value, placeholder, emptyValue, readOnly, onChange, ...fieldProps }: UnitFieldProps): ReactNode;
72
+ export declare function BuilderField({ name, label, help, error, id, className, children, }: FieldLayoutProps): ReactNode;
73
+ export declare function createFieldId(name: string): string;
74
+ export {};
@@ -0,0 +1,6 @@
1
+ import { ReactNode } from 'react';
2
+ export interface FieldProps {
3
+ label: ReactNode;
4
+ children: ReactNode;
5
+ }
6
+ export declare function Field({ label, children }: FieldProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { EmptyTextValue, SelectFieldOption } from './BuilderField';
2
+ export declare function textValue(value: string, emptyValue: EmptyTextValue): string | undefined;
3
+ export declare function numberValue(value: string, valueAsNumber: number): number | undefined;
4
+ export declare function selectValue<Value extends string>(value: string, options: readonly SelectFieldOption<Value>[]): Value | undefined;
@@ -0,0 +1,7 @@
1
+ export { BuilderField, CheckboxField, ColorField, createFieldId, NumberField, SelectField, TextAreaField, TextField, UnitField, } from './BuilderField';
2
+ export { AlignSelect } from './AlignSelect';
3
+ export type { AlignSelectProps } from './AlignSelect';
4
+ export { Field } from './Field';
5
+ export type { FieldProps } from './Field';
6
+ export { Checkbox, Input, Select, Textarea } from './inputs';
7
+ export type { BuilderControlProps, CheckboxFieldProps, ColorFieldProps, EmptyTextValue, NumberFieldProps, SelectFieldOption, SelectFieldProps, TextAreaFieldProps, TextFieldProps, UnitFieldProps, } from './BuilderField';
@@ -0,0 +1,5 @@
1
+ import { InputHTMLAttributes, SelectHTMLAttributes, TextareaHTMLAttributes } from 'react';
2
+ export declare function Input({ className, ...rest }: InputHTMLAttributes<HTMLInputElement>): import("react/jsx-runtime").JSX.Element;
3
+ export declare function Textarea({ className, ...rest }: TextareaHTMLAttributes<HTMLTextAreaElement>): import("react/jsx-runtime").JSX.Element;
4
+ export declare function Select({ className, ...rest }: SelectHTMLAttributes<HTMLSelectElement>): import("react/jsx-runtime").JSX.Element;
5
+ export declare function Checkbox({ className, ...rest }: InputHTMLAttributes<HTMLInputElement>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,25 @@
1
+ import { DragEndEvent, DragStartEvent } from '@dnd-kit/core';
2
+ import { Dispatch, RefObject } from 'react';
3
+ import { Block } from '../../types/generated/template';
4
+ import { JsonSchemaObject } from '../../types/template';
5
+ import { useBuilderSensors } from '../lib/sensors';
6
+ import { EditorModel } from '../state/editorModel';
7
+ import { EditorAction } from '../state/editorReducer';
8
+ export type ActiveDrag = {
9
+ kind: "palette";
10
+ type: string;
11
+ } | {
12
+ kind: "block";
13
+ block: Block;
14
+ } | {
15
+ kind: "row";
16
+ } | null;
17
+ interface BuilderDragDrop {
18
+ activeDrag: ActiveDrag;
19
+ sensors: ReturnType<typeof useBuilderSensors>;
20
+ onDragStart: (event: DragStartEvent) => void;
21
+ onDragEnd: (event: DragEndEvent) => void;
22
+ onDragCancel: () => void;
23
+ }
24
+ export declare function useBuilderDragDrop(schema: JsonSchemaObject | null, dispatch: Dispatch<EditorAction>, modelRef: RefObject<EditorModel>): BuilderDragDrop;
25
+ export {};
@@ -0,0 +1,9 @@
1
+ import { ReactNode } from 'react';
2
+ import { Block } from '../../types/generated/template';
3
+ export interface BlockContentControlsProps {
4
+ block: Block;
5
+ rowData?: unknown;
6
+ onChangeBlock: (block: Block) => void;
7
+ onChangeRowData?: (data: unknown) => void;
8
+ }
9
+ export declare function BlockContentControls(props: BlockContentControlsProps): ReactNode;
@@ -0,0 +1,14 @@
1
+ import { Block } from '../../types/generated/template';
2
+ import { TemplateData, TemplateSchemaResponse } from '../../types/template';
3
+ import { EditorBlock } from '../state/editorModel';
4
+ export interface BlockInspectorProps {
5
+ block: EditorBlock | null;
6
+ schema: TemplateSchemaResponse;
7
+ data: TemplateData;
8
+ onChangeBlock: (blockUid: string, block: Block) => void;
9
+ onChangeData?: (data: TemplateData) => void;
10
+ onRemoveBlock: (blockUid: string) => void;
11
+ onClose: () => void;
12
+ className?: string;
13
+ }
14
+ export declare function BlockInspector({ block, schema, data, onChangeBlock, onChangeData, onRemoveBlock, onClose, className, }: BlockInspectorProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { ReactNode } from 'react';
2
+ import { Block } from '../../types/generated/template';
3
+ export interface BlockLayoutControlsProps {
4
+ block: Block;
5
+ onChangeBlock: (block: Block) => void;
6
+ }
7
+ export declare function BlockLayoutControls({ block, onChangeBlock }: BlockLayoutControlsProps): ReactNode;
@@ -0,0 +1,18 @@
1
+ import { ReactNode } from 'react';
2
+ import { Orientation, PageFormat, Template } from '../../types/generated/template';
3
+ import { TemplateSchemaMetadata } from '../../types/template';
4
+ export interface DocumentSettingsProps {
5
+ template: Template;
6
+ metadata?: Pick<TemplateSchemaMetadata, "bundledFonts">;
7
+ format: PageFormat;
8
+ orientation: Orientation;
9
+ onChangeTemplate: (template: Template) => void;
10
+ onChangeFormat: (format: PageFormat) => void;
11
+ onChangeOrientation: (orientation: Orientation) => void;
12
+ className?: string;
13
+ }
14
+ /**
15
+ * Document-wide settings, laid out as a horizontal bar above the block palette.
16
+ * Each group wraps to its own column on narrow widths.
17
+ */
18
+ export declare function DocumentSettings({ template, metadata, format, orientation, onChangeTemplate, onChangeFormat, onChangeOrientation, className, }: DocumentSettingsProps): ReactNode;
@@ -0,0 +1 @@
1
+ export declare function Inspector(): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,19 @@
1
+ import { KeyboardEvent, ReactNode } from 'react';
2
+ export interface InspectorShellProps {
3
+ ariaLabel: string;
4
+ className?: string;
5
+ onKeyDown?: (event: KeyboardEvent<HTMLElement>) => void;
6
+ children: ReactNode;
7
+ }
8
+ export declare const InspectorShell: import('react').ForwardRefExoticComponent<InspectorShellProps & import('react').RefAttributes<HTMLElement>>;
9
+ export interface InspectorHeaderProps {
10
+ title: string;
11
+ chip?: ReactNode;
12
+ subtitle?: string;
13
+ action?: ReactNode;
14
+ }
15
+ export declare function InspectorHeader({ title, chip, subtitle, action }: InspectorHeaderProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare function InspectorSection({ title, children }: {
17
+ title: string;
18
+ children: ReactNode;
19
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ export interface PageSettingsProps {
2
+ className?: string;
3
+ }
4
+ export declare function PageSettings({ className }?: PageSettingsProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,15 @@
1
+ import { ReactNode } from 'react';
2
+ import { Block, Template } from '../../types/generated/template';
3
+ interface BlockSpacingControlsProps {
4
+ scope: "block";
5
+ block: Block;
6
+ onChangeBlock: (block: Block) => void;
7
+ }
8
+ interface PageMarginControlsProps {
9
+ scope: "page";
10
+ template: Template;
11
+ onChangeTemplate: (template: Template) => void;
12
+ }
13
+ export type SpacingControlsProps = BlockSpacingControlsProps | PageMarginControlsProps;
14
+ export declare function SpacingControls(props: SpacingControlsProps): ReactNode;
15
+ export {};