@uniweb/press 0.4.18 → 1.1.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/README.md CHANGED
@@ -87,13 +87,16 @@ For a fuller walkthrough, see the [quick start](./docs/quick-start.md).
87
87
 
88
88
  ## What's shipped
89
89
 
90
- Press ships three format adapters today:
90
+ Press ships six format adapters today:
91
91
 
92
92
  - **docx** — Word documents via the [`docx`](https://docx.js.org) library. Paragraphs, headings, text runs, tables, lists, images, hyperlinks, headers/footers, page numbering. The flagship format.
93
93
  - **typst** — Typeset PDFs via the [Typst](https://typst.app) compiler. Same-source preview from `/typst` builders; whole-book compile via `compileSubtree`; `sources` mode (pure frontend, user compiles locally) and `server` mode (via a companion endpoint — see [deployment.md](./docs/architecture/deployment.md)).
94
94
  - **xlsx** — Spreadsheets via `exceljs`. Plain `{ title, headers, data }` objects, multi-sheet, preview and compiled output independent (because spreadsheets aren't typography).
95
+ - **latex** — A LaTeX source bundle (`main.tex` and its parts, zipped) that you compile with `latexmk` or another TeX engine. Its builders at `/latex` are the `/typst` builders, so the same JSX can be registered for both.
96
+ - **pagedjs** — Browser-paginated HTML: [Paged.js](https://pagedjs.org) lays out the pages in a browser tab, and the reader prints to PDF. It reads the fragments a foundation registers under `'html'`.
97
+ - **epub** — Reflowable EPUB3 e-books, from the same `'html'` registrations as pagedjs.
95
98
 
96
- For what's next (Paged.js for browser-paginated PDFs, EPUB, slides, and a handful of speculative formats) see the [format roadmap](./docs/architecture/format-roadmap.md). For writing a custom adapter against an unsupported format, see the [custom adapter guide](./docs/guides/custom-adapter.md).
99
+ For what's next, see the [format roadmap](./docs/design/format-roadmap.md). For writing a custom adapter against an unsupported format, see the [custom adapter guide](./docs/guides/custom-adapter.md).
97
100
 
98
101
  ## Three ways to use Press
99
102
 
@@ -152,7 +155,7 @@ Format adapters themselves (`compileDocx`, `compileTypst`, `compileXlsx`, and th
152
155
  - [Overview](./docs/architecture/overview.md) — how Press is put together under the hood, for contributors orienting to the codebase.
153
156
  - [Adding a format](./docs/architecture/adding-a-format.md) — worked examples (LaTeX, Paged.js) and the general checklist.
154
157
  - [Deployment](./docs/architecture/deployment.md) — wire protocol, reference implementations, and operational concerns for formats that need a backend.
155
- - [Format roadmap](./docs/architecture/format-roadmap.md) — what's shipped, what's next, what's speculative.
158
+ - [Format roadmap](./docs/design/format-roadmap.md) — what's shipped, what's next, what's speculative.
156
159
 
157
160
  **Runnable example:**
158
161
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/press",
3
- "version": "0.4.18",
3
+ "version": "1.1.0",
4
4
  "description": "Press your React components into downloadable files — Word, Excel, PDF. Registration-based pattern with lazy-loaded format adapters.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -37,10 +37,10 @@
37
37
  "url": "https://github.com/uniweb/press/issues"
38
38
  },
39
39
  "engines": {
40
- "node": ">=20.19"
40
+ "node": ">=22.12"
41
41
  },
42
42
  "dependencies": {
43
- "docx": "^9.0.0",
43
+ "docx": "^9.9.0",
44
44
  "exceljs": "^4.4.0",
45
45
  "jszip": "^3.10.0",
46
46
  "parse5": "^7.2.0"
@@ -18,7 +18,7 @@
18
18
  * consumes — the store key foundations register fragments under. May
19
19
  * differ from the output format name. Paged.js compiles
20
20
  * 'pagedjs' output but reads fragments registered under
21
- * 'html'; future EPUB will do the same. (See principle 6's
21
+ * 'html'; EPUB does the same. (See principle 6's
22
22
  * "When the generalization is already earned" carve-out in
23
23
  * docs/architecture/principles.md — this split was introduced
24
24
  * with the first HTML-string adapter rather than deferred.)
@@ -801,29 +801,25 @@ function toWidthType(v) {
801
801
  }
802
802
 
803
803
  /**
804
- * Build a TableCell `width` option from an IR width node.
804
+ * Build a TableCell (or Table) `width` option from an IR width node.
805
805
  *
806
806
  * OOXML ECMA-376 expects `w:w` to be in fiftieths of a percent when
807
- * `w:type="pct"` (so 50% = 2500). The docx library, when given a
808
- * number size with `WidthType.PERCENTAGE`, serialises it as `${n}%`
809
- * (e.g. `w:w="18%"`) which Word flags as a validation error and
810
- * auto-repairs on open. To get a plain-number output we multiply by
811
- * 50 and pass the value as a string — that takes the library's
812
- * universal-measure branch, which emits the value verbatim as a
813
- * plain integer while keeping `w:type="pct"`.
807
+ * `w:type="pct"` (so 50% = 2500). docx ≥ 9.9 writes a number size with
808
+ * `WidthType.PERCENTAGE` that way (50 → `w:w="2500"`), and its table
809
+ * column-width resolver reads the same number as a percent — so a
810
+ * percentage is passed as the plain number of percent.
811
+ *
812
+ * ⛔ Before 9.9 the library wrote that number as `${n}%` (`w:w="18%"`),
813
+ * which Word flags and repairs on open, so this passed `String(n * 50)`
814
+ * through the library's universal-measure branch instead. docx 9.9
815
+ * resolves every cell width when it builds a table and throws on that
816
+ * string ("Invalid universal measure '2500'"), which is why
817
+ * package.json requires docx ^9.9.0.
814
818
  */
815
819
  function toTableCellWidth(width) {
816
- const rawSize = toInt(width.size) ?? 0
817
- const t = width.type
818
- if (t === 'pct' || t === 'percentage') {
819
- return {
820
- size: String(rawSize * 50),
821
- type: WidthType.PERCENTAGE,
822
- }
823
- }
824
820
  return {
825
- size: rawSize,
826
- type: toWidthType(t),
821
+ size: toInt(width.size) ?? 0,
822
+ type: toWidthType(width.type),
827
823
  }
828
824
  }
829
825
 
@@ -13,8 +13,8 @@
13
13
  * Intended consumers:
14
14
  * - Whole-book Download buttons (foundation aggregates every page's
15
15
  * blocks into a single tree, passes it here).
16
- * - Build-time compile (uniweb build --book): same aggregation run at
17
- * build time rather than on click.
16
+ * - Headless hosts that compile a whole site with no browser (unipress):
17
+ * `compileDocument` gathers the blocks and comes through here.
18
18
  * - Headless export pipelines (Mode 4 from the Press concepts doc).
19
19
  *
20
20
  * This function is sync in, async out — renderToStaticMarkup is sync,
@@ -51,9 +51,13 @@ import { runCompile, getAdapterDescriptor } from './adapters/dispatch.js'
51
51
  * 'typst',
52
52
  * { basePath: website.basePath },
53
53
  * )
54
- * // hand `compiled` to the typst adapter:
55
- * const { compileTypst } = await import('@uniweb/press/adapters/typst')
56
- * const blob = await compileTypst(compiled, { mode: 'sources', ... })
54
+ * // `compiled` is the input the typst adapter reads. The adapters are not
55
+ * // exported (they stay lazy-loaded), so for the Blob call compileSubtree,
56
+ * // which runs this step and the adapter:
57
+ * const blob = await compileSubtree(<ChildBlocks blocks={blocks} />, 'typst', {
58
+ * basePath: website.basePath,
59
+ * adapterOptions: { mode: 'sources' },
60
+ * })
57
61
  */
58
62
  export function compileRegistrations(elements, format, options = {}) {
59
63
  const { basePath, theme } = options
package/src/ir/compile.js CHANGED
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * consumes — the store key whose fragments feed this adapter.
9
9
  * Foundations register under this key. Multiple adapters can
10
- * share the same key (e.g. pagedjs and future EPUB both read
10
+ * share the same key (e.g. pagedjs and EPUB both read
11
11
  * 'html'), so a foundation writes one registration and gets
12
12
  * both formats.
13
13
  * ir — whether fragments are walked to IR (true: docx/typst) or
@@ -26,7 +26,7 @@ import { runCompile, getAdapterDescriptor } from './adapters/dispatch.js'
26
26
  // useDocumentCompile call in a page. Same behaviour as the off-screen
27
27
  // compileSubtree pathway — keyed on the adapter's `consumes` input shape,
28
28
  // not the output format, so a missed 'html' registration warns once total
29
- // even across multiple output formats (pagedjs + future epub) that share it.
29
+ // even across multiple output formats (pagedjs + epub) that share it.
30
30
  const _emptyKeyWarned = new Set()
31
31
  function warnIfEmptyRegistrations(store, format) {
32
32
  const desc = getAdapterDescriptor(format)