@pixldocs/canvas-renderer 0.3.3 → 0.3.4

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 (2) hide show
  1. package/README.md +110 -67
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @pixldocs/canvas-renderer
2
2
 
3
- React component + imperative API for rendering Pixldocs templates client-side. No server needed.
3
+ Client-side template renderer for Pixldocs render templates in any web app with 1:1 visual parity with the Pixldocs editor. No server round-trip needed for previews.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,57 +8,92 @@ React component + imperative API for rendering Pixldocs templates client-side. N
8
8
  npm install @pixldocs/canvas-renderer fabric react react-dom
9
9
  ```
10
10
 
11
- ## Quick Start React Component
11
+ > **Private package**: Add `//registry.npmjs.org/:_authToken=${NPM_TOKEN}` to your `.npmrc` and configure `NPM_TOKEN` as a build secret.
12
12
 
13
- ### Mode 1: Pre-resolved config
13
+ ---
14
+
15
+ ## Two Rendering Approaches
16
+
17
+ ### Approach A: Live Canvas (interactive)
18
+
19
+ Renders a visible `<canvas>` element in your page. Best for editors, interactive tools, or when you need real-time canvas manipulation.
14
20
 
15
21
  ```tsx
16
22
  import { PixldocsPreview } from '@pixldocs/canvas-renderer';
17
23
 
18
- function App() {
19
- return (
20
- <PixldocsPreview
21
- config={templateConfig}
22
- pageIndex={0}
23
- imageProxyUrl="https://your-project.supabase.co/functions/v1/image-proxy"
24
- onReady={() => console.log('Rendered!')}
25
- />
26
- );
27
- }
24
+ <PixldocsPreview
25
+ templateId="your-template-id"
26
+ formSchemaId="your-schema-id"
27
+ sectionState={sectionState}
28
+ supabaseUrl="https://xxx.supabase.co"
29
+ supabaseAnonKey="eyJ..."
30
+ pageIndex={0}
31
+ onReady={() => console.log('Canvas ready')}
32
+ />
28
33
  ```
29
34
 
30
- ### Mode 2: Auto-resolve from database (recommended)
35
+ **Pros**: Real-time updates, no re-render flicker
36
+ **Cons**: Heavier DOM footprint, canvas stays in memory
37
+
38
+ ### Approach B: Hidden Canvas → Image (recommended for previews)
31
39
 
32
- Pass the same data you'd send to the server API the component fetches
33
- the template, resolves repeatable sections, applies themes, and renders.
40
+ Renders off-screen using a hidden canvas, captures the result as a data URL, and displays it as a lightweight `<img>`. Best for preview panels, template pickers, and multi-page views.
34
41
 
35
42
  ```tsx
36
- import { PixldocsPreview } from '@pixldocs/canvas-renderer';
43
+ import { useState, useEffect } from 'react';
44
+ import { PixldocsRenderer } from '@pixldocs/canvas-renderer';
37
45
 
38
- function App() {
39
- const sectionState = {
40
- section_abc123: { full_name: 'John Doe', photo: 'https://...' },
41
- section_def456: [
42
- { label: 'Date of Birth', value: '1995-08-15' },
43
- { label: 'Religion', value: 'Hindu' },
44
- ],
45
- };
46
+ const renderer = new PixldocsRenderer({
47
+ supabaseUrl: 'https://xxx.supabase.co',
48
+ supabaseAnonKey: 'eyJ...',
49
+ });
50
+
51
+ function TemplatePreview({ templateId, formSchemaId, sectionState, themeId }) {
52
+ const [pages, setPages] = useState([]);
53
+ const [loading, setLoading] = useState(false);
54
+
55
+ useEffect(() => {
56
+ let cancelled = false;
57
+ async function render() {
58
+ setLoading(true);
59
+ try {
60
+ const results = await renderer.renderFromForm({
61
+ templateId,
62
+ formSchemaId,
63
+ sectionState,
64
+ themeId,
65
+ });
66
+ if (!cancelled) setPages(results);
67
+ } catch (err) {
68
+ console.error('Render failed:', err);
69
+ } finally {
70
+ if (!cancelled) setLoading(false);
71
+ }
72
+ }
73
+ render();
74
+ return () => { cancelled = true; };
75
+ }, [templateId, formSchemaId, sectionState, themeId]);
76
+
77
+ if (loading) return <div>Generating preview...</div>;
46
78
 
47
79
  return (
48
- <PixldocsPreview
49
- templateId="dc3fbb17-b671-47cb-a4cf-643a10251fb2"
50
- formSchemaId="b04cd362-a0ef-438d-a7a3-0e8560a709ce"
51
- sectionState={sectionState}
52
- supabaseUrl="https://xxx.supabase.co"
53
- supabaseAnonKey="eyJ..."
54
- onReady={() => console.log('Rendered!')}
55
- onError={(err) => console.error(err)}
56
- />
80
+ <div>
81
+ {pages.map((page, i) => (
82
+ <img key={i} src={page.dataUrl} width={page.width} height={page.height} alt={`Page ${i + 1}`} />
83
+ ))}
84
+ </div>
57
85
  );
58
86
  }
59
87
  ```
60
88
 
61
- ### Props
89
+ **Pros**: Lightweight DOM (just `<img>` tags), canvas is disposed after capture, fast for multi-page
90
+ **Cons**: Not interactive, requires re-render to update
91
+
92
+ ---
93
+
94
+ ## API Reference
95
+
96
+ ### `PixldocsPreview` (React Component)
62
97
 
63
98
  | Prop | Type | Default | Description |
64
99
  |------|------|---------|-------------|
@@ -66,67 +101,69 @@ function App() {
66
101
  | `templateId` | `string` | — | Template UUID (Mode 2) |
67
102
  | `formSchemaId` | `string` | — | Form schema UUID (Mode 2) |
68
103
  | `sectionState` | `SectionFormState` | — | V2 section state data (Mode 2) |
69
- | `themeId` | `string` | `'default'` | Theme variant ID (Mode 2) |
104
+ | `themeId` | `string` | `'default'` | Theme variant ID |
70
105
  | `supabaseUrl` | `string` | — | Supabase URL (Mode 2) |
71
106
  | `supabaseAnonKey` | `string` | — | Supabase anon key (Mode 2) |
72
107
  | `pageIndex` | `number` | `0` | Page index to render |
73
108
  | `zoom` | `number` | auto-fit | Zoom/scale factor |
74
- | `absoluteZoom` | `boolean` | `false` | Use zoom as-is without auto-fit |
75
109
  | `imageProxyUrl` | `string` | — | CORS proxy URL for external images |
76
- | `className` | `string` | — | CSS class for outer container |
77
110
  | `onReady` | `() => void` | — | Called when rendering completes |
78
111
  | `onError` | `(error: Error) => void` | — | Called on error |
79
112
 
80
- ## Imperative API
81
-
82
- ### Render from V2 sectionState (primary use case)
83
-
84
- Same payload format as the Pixldocs server API (`/render-from-form`):
113
+ ### `PixldocsRenderer` (Imperative API)
85
114
 
86
115
  ```ts
87
- import { PixldocsRenderer } from '@pixldocs/canvas-renderer';
88
-
89
116
  const renderer = new PixldocsRenderer({
90
- supabaseUrl: 'https://xxx.supabase.co',
91
- supabaseAnonKey: 'eyJ...',
117
+ supabaseUrl: string,
118
+ supabaseAnonKey: string,
119
+ imageProxyUrl?: string, // CORS proxy for external images
120
+ pixelRatio?: number, // default: 2
92
121
  });
122
+ ```
93
123
 
124
+ #### `renderer.renderFromForm(options)`
125
+
126
+ Renders all pages from a V2 sectionState payload (same format as the server `/render-from-form` API).
127
+
128
+ ```ts
94
129
  const results = await renderer.renderFromForm({
95
- templateId: 'dc3fbb17-b671-47cb-a4cf-643a10251fb2',
96
- formSchemaId: 'b04cd362-a0ef-438d-a7a3-0e8560a709ce',
97
- sectionState: {
98
- section_abc: { full_name: 'John' },
99
- section_def: [{ label: 'DOB', value: '1995-08-15' }],
100
- },
101
- themeId: 'default',
130
+ templateId: 'uuid',
131
+ formSchemaId: 'uuid',
132
+ sectionState: { section_abc: { name: 'John' }, section_def: [...] },
133
+ themeId: 'default', // optional
134
+ format: 'png', // 'png' | 'jpeg' | 'webp'
135
+ quality: 0.92, // for jpeg/webp
136
+ scale: 1, // scale multiplier
102
137
  });
103
-
104
- // results is an array of { dataUrl, width, height } for each page
105
- for (const page of results) {
106
- console.log(page.dataUrl); // data:image/png;base64,...
107
- }
138
+ // Returns: RenderResult[] — one per page
139
+ // Each: { dataUrl, width, height, pixelWidth, pixelHeight }
108
140
  ```
109
141
 
110
- ### Render a pre-resolved config
142
+ #### `renderer.render(config, options?)`
143
+
144
+ Renders a single page from a pre-resolved template config.
111
145
 
112
146
  ```ts
113
- const { dataUrl } = await renderer.render(templateConfig);
114
- const allPages = await renderer.renderAllPages(templateConfig);
147
+ const { dataUrl, width, height } = await renderer.render(templateConfig, { pageIndex: 0 });
115
148
  ```
116
149
 
117
- ### Render by template ID (simple flat data)
150
+ #### `renderer.renderAllPages(config, options?)`
151
+
152
+ Renders all pages from a pre-resolved config.
118
153
 
119
154
  ```ts
120
- const result = await renderer.renderById('template-uuid', { name: 'John' });
155
+ const pages = await renderer.renderAllPages(templateConfig);
121
156
  ```
122
157
 
123
- ## Data Resolution Utilities
158
+ ### Data Resolution Utilities
159
+
160
+ Resolve template data without rendering — useful for inspecting configs or building custom pipelines.
124
161
 
125
162
  ```ts
126
163
  import { resolveFromForm, resolveTemplateData } from '@pixldocs/canvas-renderer';
127
164
 
128
- // V2: resolve from sectionState (same as server API)
129
- const { config } = await resolveFromForm({
165
+ // V2: resolve from sectionState
166
+ const { config, totalPages } = await resolveFromForm({
130
167
  templateId: 'uuid',
131
168
  formSchemaId: 'uuid',
132
169
  sectionState: { ... },
@@ -141,8 +178,14 @@ const { config } = await resolveTemplateData({
141
178
  });
142
179
  ```
143
180
 
181
+ ---
182
+
144
183
  ## Peer Dependencies
145
184
 
146
185
  - `fabric` ^6.0.0
147
186
  - `react` ^18.0.0 || ^19.0.0
148
187
  - `react-dom` ^18.0.0 || ^19.0.0
188
+
189
+ ## License
190
+
191
+ UNLICENSED — Private package for Pixldocs ecosystem only.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixldocs/canvas-renderer",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "Client-side template renderer for Pixldocs — React component + imperative API for rendering templates in any web app",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",