@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.
- package/README.md +119 -17
- package/dist/builder/Builder.d.ts +7 -0
- package/dist/builder/TemplateBuilder.d.ts +10 -13
- package/dist/builder/blocks/Palette.d.ts +7 -0
- package/dist/builder/canvas/BlockDataPreview.d.ts +7 -0
- package/dist/builder/canvas/BuilderCanvas.d.ts +8 -4
- package/dist/builder/canvas/Canvas.d.ts +4 -0
- package/dist/builder/canvas/ColumnResizer.d.ts +2 -1
- package/dist/builder/canvas/PageSheet.d.ts +3 -1
- package/dist/builder/canvas/SortableBlock.d.ts +7 -5
- package/dist/builder/canvas/columns.d.ts +9 -0
- package/dist/builder/context/BuilderContext.d.ts +66 -0
- package/dist/builder/controls/AlignSelect.d.ts +7 -0
- package/dist/builder/controls/BuilderField.d.ts +74 -0
- package/dist/builder/controls/Field.d.ts +6 -0
- package/dist/builder/controls/fieldConverters.d.ts +4 -0
- package/dist/builder/controls/index.d.ts +7 -0
- package/dist/builder/controls/inputs.d.ts +5 -0
- package/dist/builder/hooks/useBuilderDragDrop.d.ts +25 -0
- package/dist/builder/inspector/BlockContentControls.d.ts +9 -0
- package/dist/builder/inspector/BlockInspector.d.ts +14 -0
- package/dist/builder/inspector/BlockLayoutControls.d.ts +7 -0
- package/dist/builder/inspector/DocumentSettings.d.ts +18 -0
- package/dist/builder/inspector/Inspector.d.ts +1 -0
- package/dist/builder/inspector/InspectorShell.d.ts +19 -0
- package/dist/builder/inspector/PageSettings.d.ts +4 -0
- package/dist/builder/inspector/SpacingControls.d.ts +15 -0
- package/dist/builder/inspector/TypographyControls.d.ts +19 -0
- package/dist/builder/inspector/alignOptions.d.ts +10 -0
- package/dist/builder/inspector/editors/ImageBlockEditor.d.ts +3 -0
- package/dist/builder/inspector/editors/KeyValueBlockEditor.d.ts +11 -0
- package/dist/builder/inspector/editors/SortableList.d.ts +7 -0
- package/dist/builder/inspector/editors/SortableRow.d.ts +10 -0
- package/dist/builder/inspector/editors/TableBlockEditor.d.ts +20 -0
- package/dist/builder/inspector/editors/blockEditors.d.ts +7 -0
- package/dist/builder/lib/records.d.ts +4 -0
- package/dist/builder/lib/sensors.d.ts +1 -0
- package/dist/builder/primitives/Button.d.ts +10 -0
- package/dist/builder/primitives/Chip.d.ts +7 -0
- package/dist/builder/schema/schemaAdapter.d.ts +2 -5
- package/dist/builder/state/configUpdates.d.ts +23 -0
- package/dist/builder/state/dragDrop.d.ts +17 -0
- package/dist/builder/state/editorModel.d.ts +5 -0
- package/dist/builder/state/editorReducer.d.ts +71 -0
- package/dist/editor/CodeEditor.d.ts +4 -0
- package/dist/editor/TemplateEditor.d.ts +23 -0
- package/dist/editor/TemplateEditorContext.d.ts +20 -0
- package/dist/editor/editorTheme.d.ts +1 -0
- package/dist/editor/parseTemplate.d.ts +6 -0
- package/dist/editor/templateSchema.d.ts +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +3906 -5260
- package/dist/index.js.map +1 -1
- package/dist/render/PdfPane.d.ts +14 -0
- package/dist/render/Preview.d.ts +4 -0
- package/dist/render/RenderContext.d.ts +17 -0
- package/dist/render/usePdfUaApi.d.ts +19 -0
- package/dist/style.css +3 -1
- package/dist/types/template.d.ts +5 -1
- package/package.json +25 -9
- package/dist/builder/forms/InlineBlockForm.d.ts +0 -9
- package/dist/builder/pdf/PdfPane.d.ts +0 -11
- 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
|
-
|
|
4
|
-
[pdf-ua-api](https://github.com/bambamboole/pdf-ua-api) PDF/UA
|
|
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
|
-
-
|
|
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
|
-
-
|
|
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
|
-
|
|
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
|
|
48
|
-
| ----------------- |
|
|
49
|
-
| `apiUrl` | `string`
|
|
50
|
-
| `initialTemplate` | `Template`
|
|
51
|
-
| `initialData` | `Record<string, unknown>`
|
|
52
|
-
| `
|
|
53
|
-
| `
|
|
54
|
-
| `
|
|
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:
|
|
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 {
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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 {
|
|
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
|
-
|
|
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({
|
|
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;
|
|
@@ -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 {
|
|
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
|
-
|
|
10
|
-
|
|
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,
|
|
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,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,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,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 {};
|