@quario/pdf 0.6.0 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,23 +1,51 @@
1
- # Changelog
1
+ # @quario/pdf
2
2
 
3
- All notable changes to @quario/pdf are documented in this file.
3
+ ## 0.8.0
4
4
 
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5
+ ### Minor Changes
7
6
 
8
- ## [Unreleased]
7
+ - **An image's box is now as wide as the container it sits in.** A
8
+ `background` or `border*` on an image item hugged the picture and now spans
9
+ the content width, or the slot's share inside a split; the picture itself
10
+ does not move. See the `@quario/layout` changelog for the rule and for what
11
+ it costs a report that relied on a border hugging a logo.
9
12
 
10
- ## [0.6.0] - 2026-09-07
13
+ ### Patch Changes
11
14
 
12
- ### Added
15
+ - **Every published README says where the documentation is.** Each package now
16
+ carries a Documentation section pointing at the reference, at the report schema
17
+ that normatively specifies what a report may declare, and at the package's own
18
+ API. The paragraphs that used to end on an unstated contract — the event
19
+ stream's field semantics, the style vocabulary, page columns, the Content
20
+ Security Policy a fragment with images needs, the formula mangling, and each
21
+ target's own contract — link the page that states it. Every link is an absolute
22
+ URL, so it resolves from the npm package page as readily as from an installed
23
+ copy.
24
+ - Updated dependencies
25
+ - @quario/layout@0.5.0
26
+ - quario@0.8.0
27
+
28
+ ## 0.7.0
29
+
30
+ ### Minor Changes
31
+
32
+ - **Styled runs reach the page.** A cell value written as a list of styled runs
33
+ draws each run in its own face, size and colour, underlines and strikes
34
+ through per run rather than across the line, and paints a run's `background`
35
+ as a highlight behind its text.
36
+ - **A `format` inside a sentence now presents where the engine says it does.** A
37
+ cell mixing literal text and one interpolation under a `format` draws the
38
+ value plainly, as the spreadsheet and CSV targets already did; splitting the
39
+ value into styled runs is how a value inside a sentence is formatted.
40
+
41
+ ## 0.6.0
42
+
43
+ ### Minor Changes
13
44
 
14
45
  - **A cell's own `currency` code is honoured**, ahead of the instance's
15
46
  default, so a listing whose rows arrive in different currencies presents each
16
47
  in its own. A code the engine could not accept leaves the cell as plain
17
48
  display text rather than presenting it in the instance's currency.
18
-
19
- ### Changed
20
-
21
49
  - **Numbers presented through `format` now show a fixed two fraction digits,
22
50
  matching every other target.** `format: "number"` on `1000` renders
23
51
  `1,000.00` where it rendered `1,000`, and `0.12345` renders `0.12` where it
@@ -26,9 +54,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
26
54
  so a JPY amount loses the two decimals it never had. `date` is unchanged, as
27
55
  are grouping separators and symbol placement. The digits come from the
28
56
  engine, so a cell reads the same here as it does in a workbook.
29
-
30
- ### Fixed
31
-
32
57
  - **An image these bytes cannot embed now fails with the item's name on it.**
33
58
  A PNG whose pixel data is corrupt past the size in its header used to reject
34
59
  the render with `Invalid typed array length: 0` — the PDF writer's own words,
@@ -38,9 +63,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
38
63
  account after it and on `cause`. A JPEG is unchanged: its header is read but
39
64
  its pixel data never is, so a corrupt one still embeds without complaint.
40
65
 
41
- ## [0.5.0] - 2026-09-05
66
+ ## 0.5.0
42
67
 
43
- ### Added
68
+ ### Minor Changes
44
69
 
45
70
  - **A spanning cell draws as one box** across the columns it covers, through
46
71
  `@quario/layout`. It takes no part in measuring them, and a spanning row that
@@ -48,16 +73,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
48
73
  each slice lands in.
49
74
  - **`valign`** on table cells and split slots, through `@quario/layout`: middle
50
75
  and bottom place the content in the height its row or split leaves over it.
51
-
52
- ### Changed
53
-
54
76
  - **A row's box is drawn by the row's cells**, through `@quario/layout`. A box
55
77
  declared on a table row used to be one rect across the columns; each covered
56
78
  cell now draws its own. A row's `borderBottom` still reads as one continuous
57
79
  edge, a row's `borderLeft` becomes an edge on every cell rather than one at
58
80
  the row's outer left, and a bordered row is taller by its border's width,
59
81
  since a border occupies height as a cell's always has.
60
-
61
82
  - **Embedding TrueType fonts now needs `fontkit`, not `@pdf-lib/fontkit`.**
62
83
  Install `fontkit` instead; nothing else about `options.fonts` changes. The
63
84
  old package's bundle crashed with a bare `ReferenceError` on any OpenType
@@ -65,28 +86,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
65
86
  Tamil, Khmer or Myanmar webfont in practice, and some fifty further scripts
66
87
  besides. Those faces now measure, embed and draw. Which scripts a face
67
88
  supports remains the font's and the parser's to answer, not this package's.
68
-
69
89
  - **`pdf-lib` is now `@cantoo/pdf-lib`.** A maintained fork, and what
70
90
  `fontkit`'s subsetting requires. Rendered documents are unchanged in what
71
91
  they draw: every drawn string is identical and every filled area lands in
72
92
  the same place, but the file's bytes differ, so a host comparing digests
73
93
  against stored output will see them move once.
74
94
 
75
- ## [0.4.0] - 2026-09-03
95
+ ## 0.4.0
76
96
 
77
- ### Changed
97
+ ### Minor Changes
78
98
 
79
99
  - **A split slot's box now fills the split's height.** A slot's background and
80
100
  border stopped at that slot's own content and now take the split's height,
81
101
  the way a table cell's take their row's. See the `@quario/layout` changelog
82
102
  for the rule and for what it costs a report that relied on the short box.
83
-
84
103
  - **A date string under `format: "date"` now presents as a date.** The
85
104
  drawn text comes from the engine's `format()` helper, which revives the two
86
105
  read forms. See the `quario` changelog for the forms and the timezone rule.
87
-
88
- ### Changed
89
-
90
106
  - **The layout moved to `@quario/layout`; this target paints its list.**
91
107
  Measurement, wrapping, pagination, page furniture, the marking's geometry
92
108
  and the page-size table now live in the layout package, which this target
@@ -96,16 +112,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
96
112
  options are the layout's own, so the same object configures `pdf()`, the
97
113
  viewer and the editor. The font mapping's shape is now refused at the
98
114
  factory call rather than at render.
99
-
100
- ### Fixed
101
-
102
115
  - **A nested group's footer keeps the page columns.** Inside a page-column
103
116
  region, the first footer of a group nested in it ended the region: the
104
117
  strips collapsed and every band after it was laid out across the page, as
105
118
  if `columns` were absent. Only the node that declared `columns` closes its
106
119
  own region now — a nested group's header and footer are region content,
107
120
  laid out in the strips.
108
-
109
121
  - **A padded or bordered item or row that breaks across a page keeps its
110
122
  box.** Content too tall for one page is drawn as slices, and a slice now
111
123
  carries the box sides the break left it — the top on the first, the bottom
@@ -117,60 +129,48 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
117
129
  the horizontal padding they were wrapped for, rather than flush to the
118
130
  column. **This changes output** for reports where such content breaks.
119
131
 
120
- ## [0.3.0] - 2026-09-02
132
+ ## 0.3.0
121
133
 
122
- ### Added
134
+ ### Minor Changes
123
135
 
124
136
  - **`format` stringifies at the edge from the instance locale.** A PDF
125
137
  without a host locale still uses `en-US` / UTC, so the bytes stay
126
138
  reproducible.
127
-
128
139
  - **A height-declared report header pins from the page top.** Leftover sits
129
140
  under the items; the next band starts at the pin. The half-line group gap
130
141
  drops after it. `page.margin` on the document is the inset when the host
131
142
  omits it; both is a render error.
132
-
133
143
  - **`spaceBefore` / `spaceAfter` skip the cursor.** Adjacent gaps add.
134
144
  `spaceBefore` drops at a fresh body page or strip top; page-band items
135
145
  keep it.
136
-
137
146
  - **The box is honoured in layout.** Padding and border inset wrap width; a
138
147
  named padding `0` beats the cell omakase (`PADX` 6 / `PADY` 2) on that
139
148
  side. Incomplete sides draw nothing.
140
-
141
- ### Changed
142
-
143
149
  - **The last data row keeps the whole emitted total block.** A stack taller
144
150
  than a page degrades like a tall row.
145
-
146
151
  - **An unstyled table has no rules.** This target used to draw two 0.5 pt
147
152
  rules, under the header and above the total, that no declaration could
148
153
  ask for or refuse. Those strokes are gone. The strokes an author wants
149
154
  are the box they declared. Cell padding omakase stays on undeclared cell
150
155
  sides.
151
-
152
156
  - **A visible text item occupies a line at its own `size`, empty or not.** An
153
157
  empty or whitespace-only value used to sit at the report's base leading
154
158
  (~14 pt at the 10 pt baseline). It now occupies `1.4 ×` the item's size, the
155
159
  same as a glyph line. A literal newline is a line break; the blank line
156
160
  among `"a\n\nb"` is that size too. A table cell that is empty or only
157
161
  horizontal whitespace still has no content height.
158
-
159
- ### Fixed
160
-
161
162
  - **A missing TrueType glyph draws as `?`, not `.notdef`.** Characters
162
163
  outside WinAnsi already substituted `?`; an embedded face's cmap holes
163
164
  drew a box instead, and text extraction hid it. Same rule for every
164
165
  face: a character the face cannot draw becomes `?`.
165
-
166
166
  - **CR, LF, and CRLF are one hard line break.** Cell text already broke
167
167
  on LF; a CRLF left a CR on the previous line, and a lone CR did not
168
168
  break. All three are now one break, matching `SCHEMA.md` Cell values.
169
169
  Wrapping still applies within each line.
170
170
 
171
- ## [0.2.0] - 2026-09-01
171
+ ## 0.2.0
172
172
 
173
- ### Added
173
+ ### Minor Changes
174
174
 
175
175
  - **The report default sets the document's face and base size.** A report's
176
176
  top-level `style` replaces this target's own baseline, so its `size` scales
@@ -178,12 +178,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
178
178
  nothing is set in. It is the layer _under_ the band-role defaults: a report
179
179
  declaring `size: 12` still renders its report header at 14, and an item's own
180
180
  style wins over both.
181
-
182
181
  - **`uppercase` draws capitals.** With no text-transform to defer to, this
183
182
  target capitalises the string before measuring it, so wrapping and column
184
183
  widths are those of the text actually drawn. The mapping is Unicode default
185
184
  case, never the host's locale, so output stays byte-reproducible.
186
-
187
185
  - **Splits lay out across the content width.** Each slot is measured and
188
186
  wrapped inside its own share, all slots draw from a common top, and the
189
187
  split takes the height of its tallest slot so the band below clears them
@@ -192,27 +190,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
192
190
  any page renders in full past the bottom margin. The split's own style is
193
191
  the layer under each slot's, and its `background` fills the whole split
194
192
  behind them.
195
-
196
- ### Changed
197
-
198
193
  - **A bare `Date` draws as ISO 8601 UTC, the same on every machine.** Cell
199
194
  text and outline bookmark titles for `Date` values used `String(date)`,
200
195
  which bakes the host's timezone and locale into the document — at odds with
201
196
  this target's byte-reproducibility guarantee. Both now render through the
202
197
  engine's shared display rule, so a `Date` group key titles its bookmark
203
198
  with the same ISO text its cells draw.
204
-
205
- ### Removed
206
-
207
199
  - **`options.baseSize`.** A document's type size is the document's own, so it
208
200
  is the report's `style.size` — portable, travelling with the definition to
209
201
  every target — rather than a host option one target honoured. Text with
210
202
  nothing declared still renders at 10 points. Replace `pdf({ baseSize: 11 })`
211
203
  with `"style": { "size": 11 }` on the report.
212
204
 
213
- ## [0.1.0] - 2026-08-27
205
+ ## 0.1.0
214
206
 
215
- ### Added
207
+ ### Minor Changes
216
208
 
217
209
  - **Paginated PDFs from the same compiled report.** The band flow places
218
210
  headers, groups, and tables; pdf-lib writes the file. Page furniture and an
package/README.md CHANGED
@@ -198,6 +198,17 @@ per-page presence is normative; exact geometry is best-effort. A licensed render
198
198
  Paper size and fonts are options, not schema; the margin is an option a document may declare in
199
199
  its stead. Authored watermarks and finer break control stay out of scope. Keep-together and continuation headers are by construction, above.
200
200
 
201
+ The full contract is [The PDF target](https://getquario.com/docs/diving-deeper/pdf-target/),
202
+ with each declaration's fate in the
203
+ [support matrix](https://getquario.com/docs/reference/support-matrix/).
204
+
205
+ ## Documentation
206
+
207
+ [The quario documentation](https://getquario.com/docs/) is the reference.
208
+ The [report schema](https://getquario.com/docs/reference/report-schema/) is the normative
209
+ specification of what a report may declare, and
210
+ [`@quario/pdf`](https://getquario.com/docs/reference/pdf/) is this package's own API.
211
+
201
212
  ## License
202
213
 
203
214
  Commercial software with readable source. Free, unlimited, watermarked evaluation; per-developer
package/lib/painter.js CHANGED
@@ -80,6 +80,7 @@ let paintLine = ({ page, height }, op) =>
80
80
  });
81
81
 
82
82
  /** @type {(painter: Painter, op: any) => void} */
83
+ // fallow-ignore-next-line code-duplication -- one operator path, so a face is embedded once per page; ink, baseline, rotation and opacity all differ, and the marking's draw stays its own
83
84
  let paintText = ({ page, height, fonts, faceKey }, op) => {
84
85
  let font = fontFor(fonts, op.font);
85
86
  page.pushOperators(
@@ -100,6 +101,7 @@ let paintText = ({ page, height, fonts, faceKey }, op) => {
100
101
  // face reuses the page's `faceKey` resource instead of growing the dictionary
101
102
  // per draw.
102
103
  /** @type {(painter: Painter, op: any) => void} */
104
+ // fallow-ignore-next-line code-duplication -- one operator path, so a face is embedded once per page; ink, baseline, rotation and opacity all differ, and the marking's draw stays its own
103
105
  let paintMark = ({ page, height, fonts, faceKey }, op) => {
104
106
  let font = fontFor(fonts, op.font);
105
107
  page.pushOperators(
@@ -126,7 +128,7 @@ let paintMark = ({ page, height, fonts, faceKey }, op) => {
126
128
  // The embedders parse the bytes, and what they throw when those bytes are bad
127
129
  // says nothing an author could act on: a corrupt PNG used to reach a host as a
128
130
  // bare `RangeError: Invalid typed array length: 0`, naming no image and no
129
- // item (quario-e0bz). The engine vouched for the magic numbers and the layout
131
+ // item (quario-e0bz). The engine vouched for the magic numbers and
130
132
  // read the size out of the header, so a file corrupt past that point arrives
131
133
  // here looking like any other and this is the first place that knows. The
132
134
  // embedder's own class and words survive behind the path, which is the shape
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quario/pdf",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "The browserless, paginated PDF render target for quario — in the makings, not yet released",
5
5
  "homepage": "https://getquario.com",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -37,20 +37,20 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@cantoo/pdf-lib": "^2.9.1",
40
- "@quario/layout": "^0.3.0"
40
+ "@quario/layout": "^0.5.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@arethetypeswrong/cli": "^0.18.3",
44
44
  "@size-limit/preset-small-lib": "^13.0.3",
45
45
  "@types/fontkit": "^2.0.9",
46
46
  "fontkit": "^2.0.4",
47
- "quario": "^0.6.0",
47
+ "quario": "^0.8.0",
48
48
  "size-limit": "^13.0.3",
49
49
  "typescript": "^7.0.2"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "fontkit": "^2.0.4",
53
- "quario": "^0.6.0"
53
+ "quario": "^0.8.0"
54
54
  },
55
55
  "peerDependenciesMeta": {
56
56
  "fontkit": {