@lpdfio/lpdf 0.7.0 → 0.10.0

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/LICENSE CHANGED
@@ -10,13 +10,21 @@ License inquiries: license@lpdf.io
10
10
 
11
11
  Lpdf is available under three license tiers: a free Community License for individuals and qualifying organizations, a Professional License for mid-size commercial use, and an Enterprise License for larger organizations. All license tiers receive the complete feature set — no capabilities are gated behind paid plans.
12
12
 
13
+ ### Definitions
14
+
15
+ "Production environment" means any environment in which the Software processes real user data or supports live business operations, including staging environments accessible by end users.
16
+
17
+ "Production Context" means a distinct, independently operated system, application, or automated workflow that uses the Software in a production environment, where "independently operated" means it serves a separate and identifiable purpose, user base, or business function. For the avoidance of doubt: multiple delivery channels (web, mobile, desktop, API) of the same system serving the same purpose and user base constitute a single Production Context; all internal business operations of an organization where the organization's own personnel are the sole end users constitute a single Production Context regardless of the number of internal systems or services involved; a service or component that operates exclusively as part of a larger system and has no independent production deployment is not a separate Production Context.
18
+
13
19
  ### Equal Features Across All Tiers
14
20
 
15
21
  Every user of Lpdf, regardless of license tier, has access to the same library, the same layout engine, the same adapters, and the same output quality. Licensing determines the terms of use, not the features available.
16
22
 
17
23
  ### Transitive Dependency
18
24
 
19
- If Lpdf is pulled in as an indirect dependency of another library or framework rather than used directly in your project, the Community License applies automatically, regardless of your organization's revenue.
25
+ If Lpdf is pulled in as an indirect dependency of another library or framework rather than used directly in your project, the Community License terms apply automatically with respect to revenue thresholds — no upgrade to a Professional or Enterprise License is required solely on account of the indirect dependency.
26
+
27
+ The author of the wrapping library or framework is responsible for obtaining a valid license key; end users of that library or framework are not required to obtain a separate Lpdf license key for their indirect use.
20
28
 
21
29
  This exemption does not apply if the dependency was introduced, created, or controlled by the licensee's organization for the purpose of circumventing license requirements.
22
30
 
@@ -36,13 +44,11 @@ Organizations whose revenue crosses the 1,000,000 USD threshold have a **90-day
36
44
 
37
45
  ### Mid-Size Businesses
38
46
 
39
- Companies and organizations whose total annual gross revenue exceeded **1,000,000 USD** but did not exceed **10,000,000 USD** in the most recent 12-month fiscal year must obtain a Professional License to use Lpdf in production environments.
40
-
41
- "Production environment" means any environment in which the Software processes real user data or supports live business operations, including staging environments accessible by end users.
47
+ Companies and organizations whose total annual gross revenue exceeded **1,000,000 USD** but did not exceed **10,000,000 USD** in the most recent 12-month fiscal year must obtain a Professional License for each Production Context in which they use the Software.
42
48
 
43
49
  ### Larger Businesses
44
50
 
45
- Companies and organizations whose total annual gross revenue exceeded **10,000,000 USD** in the most recent 12-month fiscal year must obtain an Enterprise License to use Lpdf in production environments.
51
+ Companies and organizations whose total annual gross revenue exceeded **10,000,000 USD** in the most recent 12-month fiscal year must obtain an Enterprise License for each Production Context in which they use the Software.
46
52
 
47
53
  Organizations whose revenue crosses the 10,000,000 USD threshold have a **90-day grace period** following the close of their fiscal year to obtain an Enterprise license. During this grace period, continued use under a Professional License is permitted. The licensee remains subject to the terms of their existing Professional License and does not gain Enterprise rights until an Enterprise License is obtained.
48
54
 
@@ -52,6 +58,18 @@ Paid licenses directly fund the continued development, maintenance, and improvem
52
58
 
53
59
  ---
54
60
 
61
+ ## Unregistered Use
62
+
63
+ Use of the Software without a valid license key ("Unregistered Use") is permitted solely for evaluation and local testing. It does not constitute a license for use in a production environment, commercial deployment, or distribution.
64
+
65
+ Unregistered Use is subject to the following restriction:
66
+
67
+ **Attribution.** Each document rendered shall include an attribution notice in the form specified in the Software documentation. This notice may not be suppressed, removed, or obscured.
68
+
69
+ This restriction is lifted upon obtaining a valid license key. Community keys are available at no cost at lpdf.io.
70
+
71
+ ---
72
+
55
73
  ## Lpdf Community License
56
74
 
57
75
  *Applies to: individuals, open-source projects, non-profit organizations, and companies with annual gross revenue under 1,000,000 USD.*
@@ -60,9 +78,17 @@ Permission is hereby granted, free of charge, to any person or qualifying organi
60
78
 
61
79
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. Any redistribution of the Software must be made under the terms of this Community License and may not be sublicensed under different terms.
62
80
 
81
+ ### License Key
82
+
83
+ A license key issued under this license may be used by you, your employees, and contractors working on your behalf on your projects. You may not share, distribute, or otherwise make your license key available to individuals or organizations outside your own. Any person or organization outside your own that wishes to use Lpdf must obtain their own license key at lpdf.io.
84
+
63
85
  All modifications to the Software made by the licensee remain the intellectual property of the licensee. Codesense LLC claims no ownership over modifications unless they are voluntarily submitted as contributions to the Lpdf project under a separate Contributor License Agreement.
64
86
 
65
- If your organization's annual gross revenue exceeds 1,000,000 USD, your rights under this Community License are automatically terminated upon expiration of the 90-day grace period described above, and you must obtain a Professional or Enterprise license before continuing to use Lpdf in production.
87
+ If your organization's annual gross revenue exceeds 1,000,000 USD, your rights under this Community License to use the Software in commercial Production Contexts are automatically terminated upon expiration of the 90-day grace period described above, and you must obtain a Professional or Enterprise license for each such Production Context. Use under this Community License by individuals, open-source projects, and non-profit organizations is not subject to revenue thresholds and is unaffected by this provision.
88
+
89
+ ### License Key Expiration
90
+
91
+ License keys issued under this license are valid for one year from the date of issuance. Before expiry, a new key must be generated from the portal and deployed in place of the expiring key. A key may be renewed at no cost provided the licensee continues to qualify under this Community License. Use of an expired key is treated as Unregistered Use — documents rendered without a valid key will include an attribution notice as described above.
66
92
 
67
93
  ### Governing Law
68
94
 
@@ -76,28 +102,36 @@ THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
76
102
 
77
103
  ## Lpdf Professional License
78
104
 
79
- *Applies to: companies and organizations with annual gross revenue exceeding 1,000,000 USD and not exceeding 10,000,000 USD.*
105
+ *Minimum required for companies and organizations with annual gross revenue exceeding 1,000,000 USD and not exceeding 10,000,000 USD.*
80
106
 
81
107
  ### Conduct
82
108
 
83
109
  Licensees agree not to make false statements of fact about Lpdf, Codesense LLC, or its contributors that are intended to cause material harm to the reputation of the project or the company. This clause does not restrict good-faith criticism, bug reports, public discussion of software deficiencies, or reviews based on the licensee's genuine experience.
84
110
 
85
- License rights may not be rented, leased, or transferred to any third party.
111
+ License rights may not be rented, leased, or transferred to any third party. A license key issued under this license may be used by the licensee's employees and contractors working on the licensee's behalf; the licensee may not share or distribute a license key to individuals or organizations outside their own, who must obtain their own license key.
86
112
 
87
113
  ### License Grant
88
114
 
89
- Subject to payment of the applicable license fee, Codesense LLC grants the licensee a non-exclusive, worldwide, royalty-free license to:
115
+ Subject to payment of the applicable license fee per Production Context, Codesense LLC grants the licensee a non-exclusive, worldwide, royalty-free license to use the Software within a single licensed Production Context:
90
116
 
91
- - Use, copy, modify, and integrate the Software into unlimited applications and projects
92
- - Distribute the Software as part of compiled or packaged commercial products
93
- - Deploy the Software across unlimited servers, environments, and infrastructure
117
+ - Use, copy, modify, and integrate the Software into the licensed Production Context
118
+ - Deploy the Software across any number of servers, environments, and infrastructure serving that Production Context
119
+ - Distribute the Software as a component of the licensed Production Context
120
+
121
+ A separate license is required for each additional Production Context in which the licensee uses the Software in a production environment.
122
+
123
+ **Tier compliance.** Licensee is responsible for ensuring their use of the Software complies with the applicable license tier at all times. If the licensee's annual gross revenue crosses 10,000,000 USD, the licensee must obtain an Enterprise License for each affected Production Context within 90 days of the close of the fiscal year in which the threshold was crossed. Use of a Professional License key while qualifying for the Enterprise tier is a material breach of this Agreement.
94
124
 
95
125
  ### License Fees and Evaluation
96
126
 
97
- A license fee is required for use of Lpdf in production environments (as defined above). Evaluation and testing in non-production environments is permitted without a license for a period not exceeding 30 days.
127
+ A license fee is required per Production Context for use of the Software in a production environment (as defined above). Evaluation and testing in non-production environments is permitted without a license for a period not exceeding 30 days.
98
128
 
99
129
  Upon payment, the licensee receives a perpetual license for the version of Lpdf current at the time of purchase, plus one year of updates, new features, and security patches. Continued access to new versions after the first year requires annual renewal. Cancellation of renewal does not affect the perpetual license for the version already held.
100
130
 
131
+ License keys issued under this license are valid for one year and are renewed automatically upon annual payment. An expired key reverts to Unregistered Use behavior — documents rendered without a valid key will include an attribution notice. A valid key is required to exercise the license grant in any production environment.
132
+
133
+ **Active subscription required.** The license grant is contingent on an active subscription in good standing. A technically valid key does not authorize use of the Software after the subscription has expired or been cancelled. Use of any key following subscription lapse — including keys that remain technically valid — constitutes unauthorized use and a material breach of this Agreement.
134
+
101
135
  ### Support
102
136
 
103
137
  Professional License holders receive email support from Codesense LLC with a target response time of 3 business days for standard inquiries. Support terms are further detailed at lpdf.io/support.
@@ -140,28 +174,37 @@ Notwithstanding the foregoing, either party may seek injunctive or other equitab
140
174
 
141
175
  ## Lpdf Enterprise License
142
176
 
143
- *Applies to: companies and organizations with annual gross revenue exceeding 10,000,000 USD.*
177
+ *Required for companies and organizations with annual gross revenue exceeding 10,000,000 USD. Available to any organization that prefers Enterprise license terms.*
144
178
 
145
179
  ### Conduct
146
180
 
147
181
  Licensees agree not to make false statements of fact about Lpdf, Codesense LLC, or its contributors that are intended to cause material harm to the reputation of the project or the company. This clause does not restrict good-faith criticism, bug reports, public discussion of software deficiencies, or reviews based on the licensee's genuine experience.
148
182
 
149
- License rights may not be rented, leased, or transferred to any third party, except as expressly permitted under the subsidiary grant below.
183
+ License rights may not be rented, leased, or transferred to any third party. A license key issued under this license may be used by the licensee's employees, contractors, and personnel of Controlled Entities (as defined in the License Grant below) working on Production Contexts licensed by the licensee. The licensee may not share or distribute a license key for use in Production Contexts not licensed by the licensee; any Production Context operated independently by a Controlled Entity requires its own license obtained by that entity.
150
184
 
151
185
  ### License Grant
152
186
 
153
- Subject to payment of the applicable license fee, Codesense LLC grants the licensee a non-exclusive, worldwide, royalty-free license for an unlimited number of developers within the licensee's organization to:
187
+ Subject to payment of the applicable license fee per Production Context, Codesense LLC grants the licensee a non-exclusive, worldwide, royalty-free license for an unlimited number of developers within the licensee's organization to use the Software within a single licensed Production Context:
188
+
189
+ - Use, copy, modify, and integrate the Software into the licensed Production Context
190
+ - Deploy the Software across any number of servers, environments, and infrastructure serving that Production Context
191
+ - Distribute the Software as a component of the licensed Production Context
192
+
193
+ A separate license is required for each additional Production Context in which the licensee uses the Software in a production environment.
194
+
195
+ **Controlled Entities.** "Controlled Entities" means wholly owned subsidiaries and entities in which the licensee holds more than 50% ownership or voting control. Personnel of Controlled Entities may use license keys issued under this license solely for Production Contexts licensed by the licensee. This does not extend the license to Production Contexts operated independently by a Controlled Entity; each such Production Context requires its own license obtained by the Controlled Entity at the tier applicable to that entity's annual gross revenue.
154
196
 
155
- - Use, copy, modify, and integrate the Software into unlimited applications and projects
156
- - Distribute the Software as part of compiled or packaged commercial products
157
- - Deploy the Software across unlimited servers, environments, and infrastructure
158
- - Extend license rights to wholly owned subsidiaries and entities in which the licensee holds more than 50% ownership or voting control ("Controlled Entities"), provided such Controlled Entities are identified to Codesense LLC upon request and remain subject to the terms of this license
197
+ **Tier compliance.** Licensee is responsible for ensuring their use of the Software complies with the applicable license tier at all times. Each Controlled Entity using the Software must qualify for the tier under which they operate. If a Controlled Entity's annual gross revenue would independently qualify that entity for a different tier, that entity must obtain its own license at the applicable tier for any Production Context it independently operates.
159
198
 
160
199
  ### License Fees and Evaluation
161
200
 
162
- A license fee is required for use of Lpdf in production environments (as defined above). Evaluation and testing in non-production environments is permitted without a license for a period not exceeding 30 days.
201
+ A license fee is required per Production Context for use of the Software in a production environment (as defined above). Evaluation and testing in non-production environments is permitted without a license for a period not exceeding 30 days.
163
202
 
164
- Upon payment, the licensee receives a perpetual license for the version of Lpdf current at the time of purchase, plus one year of updates, new features, and security patches. Continued access to new versions after the first year requires annual renewal. Cancellation of renewal does not affect the perpetual license for the version already held.
203
+ Upon payment, the licensee receives a perpetual license for the major version of Lpdf current at the time of purchase, plus access to updates, new features, and security patches within that major version for the duration of the active subscription. Cancellation of renewal does not affect the perpetual license for the major version already held.
204
+
205
+ **License keys.** License keys issued under this license are locked to the major version of Lpdf current at the time of generation and carry no date expiry. While the subscription is active and in good standing, the licensee may generate new keys for the current major version from the portal at any time. When a new major version of Lpdf is released, a new key must be generated from the portal to use that version; keys generated for a prior major version continue to function with that version only. The right to generate new keys requires an active subscription; key generation rights terminate upon subscription lapse.
206
+
207
+ **Active subscription required.** The license grant is contingent on an active subscription in good standing. A technically valid key does not authorize use of the Software after the subscription has expired or been cancelled. Use of any key following subscription lapse — including keys that carry no date expiry and remain technically valid — constitutes unauthorized use and a material breach of this Agreement.
165
208
 
166
209
  ### Support
167
210
 
@@ -173,7 +216,7 @@ Enterprise licensees may request a Master Service Agreement (MSA) in place of th
173
216
 
174
217
  ### Audit
175
218
 
176
- Codesense LLC may, upon 30 days' written notice and no more than once per calendar year, request a written certification from the licensee confirming their applicable license tier and annual gross revenue for the most recent fiscal year, and may request a list of Controlled Entities covered under the subsidiary grant. The licensee agrees to provide such certification within 15 business days of the request. For Enterprise licensees under an MSA, audit rights may be further defined therein.
219
+ Codesense LLC may, upon 30 days' written notice and no more than once per calendar year, request a written certification from the licensee confirming their applicable license tier and annual gross revenue for the most recent fiscal year, and may request a list of Controlled Entities whose personnel have been granted access to the licensee's license keys. The licensee agrees to provide such certification within 15 business days of the request. For Enterprise licensees under an MSA, audit rights may be further defined therein.
177
220
 
178
221
  ### Ownership and Modifications
179
222
 
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- <p align="center"><img src="lpdf-light.png" height="48" alt="Lpdf"></p>
1
+ <img src="lpdf-mark.svg" height="48" alt="Lpdf - PDF as Code" />
2
2
 
3
3
  # @lpdfio/lpdf
4
4
 
@@ -1,4 +1,4 @@
1
- import type { PdfDocument } from './kit';
1
+ import type { LpdfTokens, PdfDocument } from './kit';
2
2
  import { PdfEngine } from './engine';
3
3
  /** Pass as `attrs` when a node has no attributes. Equivalent to `null`. */
4
4
  export declare const NoAttr: null;
@@ -33,6 +33,7 @@ export declare const L: Readonly<{
33
33
  section: (attrs: import("./kit").SectionAttr | null, nodes: (import("./kit").LpdfLayoutBlock | import("./kit").LpdfCanvasBlock)[]) => import("./kit").LpdfSectionNode;
34
34
  layout: (_attrs: null, nodes: import("./layout").LpdfNode[]) => import("./kit").LpdfLayoutBlock;
35
35
  canvas: (_attrs: null, layers: import("./canvas").LpdfCanvasLayerNode[]) => import("./kit").LpdfCanvasBlock;
36
+ tokens: (attrs: LpdfTokens) => LpdfTokens;
36
37
  stack: (attrs: import("./layout").StackAttr | null, nodes: import("./layout").LpdfNode[]) => import("./layout").LpdfContainerNode;
37
38
  flank: (attrs: import("./layout").FlankAttr | null, nodes: import("./layout").LpdfNode[]) => import("./layout").LpdfContainerNode;
38
39
  split: (attrs: import("./layout").SplitAttr | null, nodes: import("./layout").LpdfNode[]) => import("./layout").LpdfContainerNode;
@@ -50,6 +51,7 @@ export declare const L: Readonly<{
50
51
  img: (attrs: import("./layout").ImgAttr) => import("./layout").LpdfImgNode;
51
52
  barcode: (attrs: import("./layout").BarcodeAttr) => import("./layout").LpdfBarcodeNode;
52
53
  region: (attrs: import("./layout").RegionAttr, nodes: import("./layout").LpdfNode[]) => import("./layout").LpdfRegionNode;
54
+ field: (type: string, name: string, attrs?: import("./layout").FieldAttr | null) => import("./layout").LpdfFieldNode;
53
55
  layer: (attrs: import("./canvas").LayerAttr | null, nodes: import("./canvas").LpdfCanvasPrimitiveNode[]) => import("./canvas").LpdfCanvasLayerNode;
54
56
  rect: (x: number, y: number, w: number, h: number, style?: import("./canvas").CanvasRectStyle) => import("./canvas").LpdfCanvasRectNode;
55
57
  line: (x1: number, y1: number, x2: number, y2: number, style?: import("./canvas").CanvasLineStyle) => import("./canvas").LpdfCanvasLineNode;
@@ -57,5 +59,5 @@ export declare const L: Readonly<{
57
59
  circle: (cx: number, cy: number, r: number, style?: import("./canvas").CanvasEllipseStyle) => import("./canvas").LpdfCanvasCircleNode;
58
60
  path: (d: string, style?: import("./canvas").CanvasPathStyle) => import("./canvas").LpdfCanvasPathNode;
59
61
  textAt: (x: number, y: number, content: string, style?: import("./canvas").CanvasTextStyle, runs?: import("./canvas").CanvasRun[]) => import("./canvas").LpdfCanvasTextNode;
60
- imgAt: (x: number, y: number, w: number, h: number, name: string) => import("./canvas").LpdfCanvasImgNode;
62
+ imgAt: (x: number, y: number, w: number, h: number, name: string, anchor?: string) => import("./canvas").LpdfCanvasImgNode;
61
63
  }>;
@@ -40,6 +40,7 @@ exports.L = Object.freeze({
40
40
  section: kit_1.LpdfKit.section,
41
41
  layout: kit_1.LpdfKit.layout,
42
42
  canvas: kit_1.LpdfKit.canvas,
43
+ tokens: (attrs) => attrs,
43
44
  // ── Layout ────────────────────────────────────────────────────────────────
44
45
  stack: layout_1.LpdfLayout.stack,
45
46
  flank: layout_1.LpdfLayout.flank,
@@ -58,6 +59,7 @@ exports.L = Object.freeze({
58
59
  img: layout_1.LpdfLayout.img,
59
60
  barcode: layout_1.LpdfLayout.barcode,
60
61
  region: layout_1.LpdfLayout.region,
62
+ field: layout_1.LpdfLayout.field,
61
63
  // ── Canvas ────────────────────────────────────────────────────────────────
62
64
  layer: canvas_1.LpdfCanvas.layer,
63
65
  rect: canvas_1.LpdfCanvas.rect,
package/dist/canvas.d.ts CHANGED
@@ -8,6 +8,8 @@ export interface CanvasRectStyle {
8
8
  strokeWidth?: number;
9
9
  strokeDash?: number[];
10
10
  borderRadius?: number;
11
+ opacity?: number;
12
+ anchor?: string;
11
13
  }
12
14
  export interface CanvasLineStyle {
13
15
  stroke?: string;
@@ -21,6 +23,8 @@ export interface CanvasEllipseStyle {
21
23
  stroke?: string;
22
24
  strokeWidth?: number;
23
25
  strokeDash?: number[];
26
+ opacity?: number;
27
+ anchor?: string;
24
28
  }
25
29
  export interface CanvasPathStyle {
26
30
  fill?: string;
@@ -30,6 +34,7 @@ export interface CanvasPathStyle {
30
34
  fillRuleEvenodd?: boolean;
31
35
  lineCap?: LineCap;
32
36
  lineJoin?: LineJoin;
37
+ opacity?: number;
33
38
  }
34
39
  export interface CanvasTextStyle {
35
40
  font?: string;
@@ -38,6 +43,8 @@ export interface CanvasTextStyle {
38
43
  align?: TextAlign;
39
44
  lineHeight?: number;
40
45
  width?: number;
46
+ opacity?: number;
47
+ anchor?: string;
41
48
  }
42
49
  export interface CanvasRun {
43
50
  text: string;
@@ -118,7 +125,7 @@ declare function ellipse(cx: number, cy: number, rx: number, ry: number, style?:
118
125
  declare function circle(cx: number, cy: number, r: number, style?: CanvasEllipseStyle): LpdfCanvasCircleNode;
119
126
  declare function path(d: string, style?: CanvasPathStyle): LpdfCanvasPathNode;
120
127
  declare function textAt(x: number, y: number, content: string, style?: CanvasTextStyle, runs?: CanvasRun[]): LpdfCanvasTextNode;
121
- declare function imgAt(x: number, y: number, w: number, h: number, name: string): LpdfCanvasImgNode;
128
+ declare function imgAt(x: number, y: number, w: number, h: number, name: string, anchor?: string): LpdfCanvasImgNode;
122
129
  declare function layer(attrs: LayerAttr | null, nodes: LpdfCanvasPrimitiveNode[]): LpdfCanvasLayerNode;
123
130
  export declare const LpdfCanvas: Readonly<{
124
131
  rect: typeof rect;
package/dist/canvas.js CHANGED
@@ -60,6 +60,10 @@ function rect(x, y, w, h, style) {
60
60
  attrs['stroke-dash'] = style.strokeDash.join(' ');
61
61
  if (style?.borderRadius !== undefined)
62
62
  attrs['radius'] = String(style.borderRadius);
63
+ if (style?.opacity !== undefined)
64
+ attrs['opacity'] = String(style.opacity);
65
+ if (style?.anchor !== undefined)
66
+ attrs['anchor'] = style.anchor;
63
67
  return { type: 'canvas-rect', attrs };
64
68
  }
65
69
  function line(x1, y1, x2, y2, style) {
@@ -90,6 +94,10 @@ function ellipse(cx, cy, rx, ry, style) {
90
94
  attrs['stroke-width'] = String(style.strokeWidth);
91
95
  if (style?.strokeDash !== undefined)
92
96
  attrs['stroke-dash'] = style.strokeDash.join(' ');
97
+ if (style?.opacity !== undefined)
98
+ attrs['opacity'] = String(style.opacity);
99
+ if (style?.anchor !== undefined)
100
+ attrs['anchor'] = style.anchor;
93
101
  return { type: 'canvas-ellipse', attrs };
94
102
  }
95
103
  function circle(cx, cy, r, style) {
@@ -104,6 +112,10 @@ function circle(cx, cy, r, style) {
104
112
  attrs['stroke-width'] = String(style.strokeWidth);
105
113
  if (style?.strokeDash !== undefined)
106
114
  attrs['stroke-dash'] = style.strokeDash.join(' ');
115
+ if (style?.opacity !== undefined)
116
+ attrs['opacity'] = String(style.opacity);
117
+ if (style?.anchor !== undefined)
118
+ attrs['anchor'] = style.anchor;
107
119
  return { type: 'canvas-circle', attrs };
108
120
  }
109
121
  function path(d, style) {
@@ -122,6 +134,8 @@ function path(d, style) {
122
134
  attrs['line-cap'] = style.lineCap;
123
135
  if (style?.lineJoin !== undefined)
124
136
  attrs['line-join'] = style.lineJoin;
137
+ if (style?.opacity !== undefined)
138
+ attrs['opacity'] = String(style.opacity);
125
139
  return { type: 'canvas-path', attrs };
126
140
  }
127
141
  function textAt(x, y, content, style, runs) {
@@ -138,6 +152,10 @@ function textAt(x, y, content, style, runs) {
138
152
  attrs['line-height'] = String(style.lineHeight);
139
153
  if (style?.width !== undefined)
140
154
  attrs['w'] = String(style.width);
155
+ if (style?.opacity !== undefined)
156
+ attrs['opacity'] = String(style.opacity);
157
+ if (style?.anchor !== undefined)
158
+ attrs['anchor'] = style.anchor;
141
159
  const node = { type: 'canvas-text', text: content, attrs };
142
160
  if (runs && runs.length > 0) {
143
161
  node.runs = runs.map(r => {
@@ -153,11 +171,11 @@ function textAt(x, y, content, style, runs) {
153
171
  }
154
172
  return node;
155
173
  }
156
- function imgAt(x, y, w, h, name) {
157
- return {
158
- type: 'canvas-img',
159
- attrs: { x: String(x), y: String(y), w: String(w), h: String(h), name },
160
- };
174
+ function imgAt(x, y, w, h, name, anchor) {
175
+ const attrs = { x: String(x), y: String(y), w: String(w), h: String(h), name };
176
+ if (anchor !== undefined)
177
+ attrs['anchor'] = anchor;
178
+ return { type: 'canvas-img', attrs };
161
179
  }
162
180
  function layer(attrs, nodes) {
163
181
  const a = {};
package/dist/index.d.ts CHANGED
@@ -2,8 +2,8 @@ export { PdfEngine, LpdfRenderError } from './engine';
2
2
  export type { EncryptPermissions, EncryptOptions } from './engine';
3
3
  export type { RenderOptions, EngineOptions, PageScope } from './_shared';
4
4
  export type { PdfDocument, LpdfSectionNode, LpdfLayoutBlock, LpdfCanvasBlock, LpdfTokens, LpdfFontDef, LpdfMeta, SectionAttr, DocumentAttr, } from './kit';
5
- export type { StackAttr, FlankAttr, SplitAttr, ClusterAttr, GridAttr, FrameAttr, LinkAttr, TableAttr, TheadAttr, TrAttr, TdAttr, TextAttr, SpanAttr, DividerAttr, ImgAttr, BarcodeAttr, RegionAttr, } from './layout';
6
- export type { LpdfNode, LpdfContainerNode, LpdfTextNode, LpdfSpanNode, LpdfDividerNode, LpdfImgNode, LpdfBarcodeNode, LpdfTableNode, LpdfTheadNode, LpdfTrNode, LpdfTdNode, LpdfRegionNode, } from './layout';
5
+ export type { StackAttr, FlankAttr, SplitAttr, ClusterAttr, GridAttr, FrameAttr, LinkAttr, TableAttr, TheadAttr, TrAttr, TdAttr, TextAttr, SpanAttr, DividerAttr, ImgAttr, BarcodeAttr, RegionAttr, FieldAttr, } from './layout';
6
+ export type { LpdfNode, LpdfContainerNode, LpdfTextNode, LpdfSpanNode, LpdfDividerNode, LpdfImgNode, LpdfBarcodeNode, LpdfTableNode, LpdfTheadNode, LpdfTrNode, LpdfTdNode, LpdfRegionNode, LpdfFieldNode, } from './layout';
7
7
  export { CanvasTransform } from './canvas';
8
8
  export type { LineCap, LineJoin, TextAlign, LayerAttr, CanvasRun, CanvasRectStyle, CanvasLineStyle, CanvasEllipseStyle, CanvasPathStyle, CanvasTextStyle, LpdfCanvasLayerNode, LpdfCanvasPrimitiveNode, LpdfCanvasRectNode, LpdfCanvasLineNode, LpdfCanvasEllipseNode, LpdfCanvasCircleNode, LpdfCanvasPathNode, LpdfCanvasTextNode, LpdfCanvasImgNode, } from './canvas';
9
- export { L, NoAttr } from './pdf';
9
+ export { L, NoAttr } from './L';
package/dist/index.js CHANGED
@@ -9,6 +9,6 @@ Object.defineProperty(exports, "LpdfRenderError", { enumerable: true, get: funct
9
9
  var canvas_1 = require("./canvas");
10
10
  Object.defineProperty(exports, "CanvasTransform", { enumerable: true, get: function () { return canvas_1.CanvasTransform; } });
11
11
  // ── Facade ────────────────────────────────────────────────────────────────────
12
- var pdf_1 = require("./pdf");
13
- Object.defineProperty(exports, "L", { enumerable: true, get: function () { return pdf_1.L; } });
14
- Object.defineProperty(exports, "NoAttr", { enumerable: true, get: function () { return pdf_1.NoAttr; } });
12
+ var L_1 = require("./L");
13
+ Object.defineProperty(exports, "L", { enumerable: true, get: function () { return L_1.L; } });
14
+ Object.defineProperty(exports, "NoAttr", { enumerable: true, get: function () { return L_1.NoAttr; } });
package/dist/kit.d.ts CHANGED
@@ -32,7 +32,7 @@ export interface LpdfTokens {
32
32
  border?: Record<string, string>;
33
33
  radius?: Record<string, string>;
34
34
  width?: Record<string, string>;
35
- text?: Record<string, string>;
35
+ textSize?: Record<string, string>;
36
36
  fonts?: Record<string, LpdfFontDef>;
37
37
  }
38
38
  export type LpdfFontDef = {
package/dist/kit.js CHANGED
@@ -58,8 +58,10 @@ function document(attrs, nodes) {
58
58
  const attrsObj = {
59
59
  ...buildAttrs(restOpts),
60
60
  };
61
- if (tokens !== undefined)
62
- attrsObj['tokens'] = tokens;
61
+ if (tokens !== undefined) {
62
+ const { textSize, ...rest } = tokens;
63
+ attrsObj['tokens'] = textSize !== undefined ? { 'text-size': textSize, ...rest } : rest;
64
+ }
63
65
  if (meta !== undefined)
64
66
  attrsObj['meta'] = meta;
65
67
  return {
package/dist/layout.d.ts CHANGED
@@ -73,6 +73,7 @@ export interface FrameAttr {
73
73
  }
74
74
  export interface LinkAttr {
75
75
  url?: string;
76
+ gap?: string;
76
77
  width?: string;
77
78
  height?: string;
78
79
  debug?: string;
@@ -163,6 +164,20 @@ export interface BarcodeAttr {
163
164
  repeat?: string;
164
165
  debug?: string;
165
166
  }
167
+ export interface FieldAttr {
168
+ label?: string;
169
+ value?: string;
170
+ options?: string;
171
+ group?: string;
172
+ checked?: string;
173
+ required?: string;
174
+ readonly?: string;
175
+ maxLen?: string;
176
+ actionUrl?: string;
177
+ width?: string;
178
+ height?: string;
179
+ debug?: string;
180
+ }
166
181
  export interface RegionAttr {
167
182
  pin: string;
168
183
  page?: PageScope | string;
@@ -221,7 +236,11 @@ export interface LpdfRegionNode {
221
236
  attrs: Record<string, string>;
222
237
  nodes: LpdfNode[];
223
238
  }
224
- export type LpdfNode = LpdfContainerNode | LpdfTextNode | LpdfDividerNode | LpdfTableNode | LpdfImgNode | LpdfBarcodeNode | LpdfRegionNode;
239
+ export interface LpdfFieldNode {
240
+ type: 'field';
241
+ attrs: Record<string, string>;
242
+ }
243
+ export type LpdfNode = LpdfContainerNode | LpdfTextNode | LpdfDividerNode | LpdfTableNode | LpdfImgNode | LpdfBarcodeNode | LpdfRegionNode | LpdfFieldNode;
225
244
  declare function stack(attrs: StackAttr | null, nodes: LpdfNode[]): LpdfContainerNode;
226
245
  declare function flank(attrs: FlankAttr | null, nodes: LpdfNode[]): LpdfContainerNode;
227
246
  declare function split(attrs: SplitAttr | null, nodes: LpdfNode[]): LpdfContainerNode;
@@ -239,6 +258,7 @@ declare function divider(attrs: DividerAttr | null): LpdfDividerNode;
239
258
  declare function img(attrs: ImgAttr): LpdfImgNode;
240
259
  declare function barcode(attrs: BarcodeAttr): LpdfBarcodeNode;
241
260
  declare function region(attrs: RegionAttr, nodes: LpdfNode[]): LpdfRegionNode;
261
+ declare function field(type: string, name: string, attrs?: FieldAttr | null): LpdfFieldNode;
242
262
  export declare const LpdfLayout: Readonly<{
243
263
  stack: typeof stack;
244
264
  flank: typeof flank;
@@ -257,5 +277,6 @@ export declare const LpdfLayout: Readonly<{
257
277
  tr: typeof tr;
258
278
  td: typeof td;
259
279
  region: typeof region;
280
+ field: typeof field;
260
281
  }>;
261
282
  export {};
package/dist/layout.js CHANGED
@@ -110,6 +110,12 @@ function region(attrs, nodes) {
110
110
  a['debug'] = attrs.debug;
111
111
  return { type: 'layout-region', attrs: a, nodes };
112
112
  }
113
+ function field(type, name, attrs) {
114
+ const a = { type, name };
115
+ if (attrs)
116
+ Object.assign(a, buildAttrs(attrs));
117
+ return { type: 'field', attrs: a };
118
+ }
113
119
  exports.LpdfLayout = Object.freeze({
114
120
  stack,
115
121
  flank,
@@ -128,4 +134,5 @@ exports.LpdfLayout = Object.freeze({
128
134
  tr,
129
135
  td,
130
136
  region,
137
+ field,
131
138
  });
@@ -205,6 +205,79 @@ export class LpdfEngine {
205
205
  }
206
206
  if (Symbol.dispose) LpdfEngine.prototype[Symbol.dispose] = LpdfEngine.prototype.free;
207
207
 
208
+ /**
209
+ * Generate SDK source code from one or more bare Lpdf XML elements (a fragment).
210
+ *
211
+ * Unlike `codegen_wasm`, this accepts a snippet without the `<lpdf>` wrapper and
212
+ * returns just the node expression(s) — no imports, no engine setup, no boilerplate.
213
+ * Ideal for documentation code examples where the same XML snippet should be shown
214
+ * in multiple target languages.
215
+ *
216
+ * `options_json` accepts the same shape as `codegen_wasm`:
217
+ * - `target`: `"js"`, `"dotnet"`, `"php"`, or `"python"` (required)
218
+ * - `indent`: `2` or `4` (optional, default `4`)
219
+ * @param {string} xml
220
+ * @param {string} options_json
221
+ * @returns {string}
222
+ */
223
+ export function codegen_fragment_wasm(xml, options_json) {
224
+ let deferred4_0;
225
+ let deferred4_1;
226
+ try {
227
+ const ptr0 = passStringToWasm0(xml, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
228
+ const len0 = WASM_VECTOR_LEN;
229
+ const ptr1 = passStringToWasm0(options_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
230
+ const len1 = WASM_VECTOR_LEN;
231
+ const ret = wasm.codegen_fragment_wasm(ptr0, len0, ptr1, len1);
232
+ var ptr3 = ret[0];
233
+ var len3 = ret[1];
234
+ if (ret[3]) {
235
+ ptr3 = 0; len3 = 0;
236
+ throw takeFromExternrefTable0(ret[2]);
237
+ }
238
+ deferred4_0 = ptr3;
239
+ deferred4_1 = len3;
240
+ return getStringFromWasm0(ptr3, len3);
241
+ } finally {
242
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Generate SDK source code from an Lpdf XML string.
248
+ *
249
+ * `options_json` is a JSON object with:
250
+ * - `target`: `"js"` (required)
251
+ * - `indent`: `2` or `4` (optional, default `4`)
252
+ *
253
+ * Returns the generated source code as a string.
254
+ * @param {string} xml
255
+ * @param {string} options_json
256
+ * @returns {string}
257
+ */
258
+ export function codegen_wasm(xml, options_json) {
259
+ let deferred4_0;
260
+ let deferred4_1;
261
+ try {
262
+ const ptr0 = passStringToWasm0(xml, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
263
+ const len0 = WASM_VECTOR_LEN;
264
+ const ptr1 = passStringToWasm0(options_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
265
+ const len1 = WASM_VECTOR_LEN;
266
+ const ret = wasm.codegen_wasm(ptr0, len0, ptr1, len1);
267
+ var ptr3 = ret[0];
268
+ var len3 = ret[1];
269
+ if (ret[3]) {
270
+ ptr3 = 0; len3 = 0;
271
+ throw takeFromExternrefTable0(ret[2]);
272
+ }
273
+ deferred4_0 = ptr3;
274
+ deferred4_1 = len3;
275
+ return getStringFromWasm0(ptr3, len3);
276
+ } finally {
277
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
278
+ }
279
+ }
280
+
208
281
  /**
209
282
  * Convert a JSON kit-tree (produced by `LpdfKit` in any adapter) to an lpdf
210
283
  * XML string.
package/dist/wasm/lpdf.js CHANGED
@@ -206,6 +206,81 @@ class LpdfEngine {
206
206
  if (Symbol.dispose) LpdfEngine.prototype[Symbol.dispose] = LpdfEngine.prototype.free;
207
207
  exports.LpdfEngine = LpdfEngine;
208
208
 
209
+ /**
210
+ * Generate SDK source code from one or more bare Lpdf XML elements (a fragment).
211
+ *
212
+ * Unlike `codegen_wasm`, this accepts a snippet without the `<lpdf>` wrapper and
213
+ * returns just the node expression(s) — no imports, no engine setup, no boilerplate.
214
+ * Ideal for documentation code examples where the same XML snippet should be shown
215
+ * in multiple target languages.
216
+ *
217
+ * `options_json` accepts the same shape as `codegen_wasm`:
218
+ * - `target`: `"js"`, `"dotnet"`, `"php"`, or `"python"` (required)
219
+ * - `indent`: `2` or `4` (optional, default `4`)
220
+ * @param {string} xml
221
+ * @param {string} options_json
222
+ * @returns {string}
223
+ */
224
+ function codegen_fragment_wasm(xml, options_json) {
225
+ let deferred4_0;
226
+ let deferred4_1;
227
+ try {
228
+ const ptr0 = passStringToWasm0(xml, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
229
+ const len0 = WASM_VECTOR_LEN;
230
+ const ptr1 = passStringToWasm0(options_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
231
+ const len1 = WASM_VECTOR_LEN;
232
+ const ret = wasm.codegen_fragment_wasm(ptr0, len0, ptr1, len1);
233
+ var ptr3 = ret[0];
234
+ var len3 = ret[1];
235
+ if (ret[3]) {
236
+ ptr3 = 0; len3 = 0;
237
+ throw takeFromExternrefTable0(ret[2]);
238
+ }
239
+ deferred4_0 = ptr3;
240
+ deferred4_1 = len3;
241
+ return getStringFromWasm0(ptr3, len3);
242
+ } finally {
243
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
244
+ }
245
+ }
246
+ exports.codegen_fragment_wasm = codegen_fragment_wasm;
247
+
248
+ /**
249
+ * Generate SDK source code from an Lpdf XML string.
250
+ *
251
+ * `options_json` is a JSON object with:
252
+ * - `target`: `"js"` (required)
253
+ * - `indent`: `2` or `4` (optional, default `4`)
254
+ *
255
+ * Returns the generated source code as a string.
256
+ * @param {string} xml
257
+ * @param {string} options_json
258
+ * @returns {string}
259
+ */
260
+ function codegen_wasm(xml, options_json) {
261
+ let deferred4_0;
262
+ let deferred4_1;
263
+ try {
264
+ const ptr0 = passStringToWasm0(xml, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
265
+ const len0 = WASM_VECTOR_LEN;
266
+ const ptr1 = passStringToWasm0(options_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
267
+ const len1 = WASM_VECTOR_LEN;
268
+ const ret = wasm.codegen_wasm(ptr0, len0, ptr1, len1);
269
+ var ptr3 = ret[0];
270
+ var len3 = ret[1];
271
+ if (ret[3]) {
272
+ ptr3 = 0; len3 = 0;
273
+ throw takeFromExternrefTable0(ret[2]);
274
+ }
275
+ deferred4_0 = ptr3;
276
+ deferred4_1 = len3;
277
+ return getStringFromWasm0(ptr3, len3);
278
+ } finally {
279
+ wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
280
+ }
281
+ }
282
+ exports.codegen_wasm = codegen_wasm;
283
+
209
284
  /**
210
285
  * Convert a JSON kit-tree (produced by `LpdfKit` in any adapter) to an lpdf
211
286
  * XML string.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lpdfio/lpdf",
3
- "version": "0.7.0",
3
+ "version": "0.10.0",
4
4
  "description": "Node.js SDK for Lpdf — PDF as Code on every platform. You describe a document as code or XML. Lpdf renders a compact, pixel-perfect PDF — identical across platforms.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",