@uurtech/jdf 0.2.2 → 0.2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uurtech/jdf",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Render JDF (JSON Document Format) documents in the browser. Drop-in replacement for embedding PDFs — point at a .jdf file and it appears on the page, fully styled, searchable, with a clickable TOC.",
5
5
  "license": "MIT",
6
6
  "author": "Ugur Kazdal <ugur@uurtech.com>",
@@ -103,6 +103,7 @@ function textTag(h: TextElement["heading"]): keyof HTMLElementTagNameMap {
103
103
  // ── richtext ────────────────────────────────────────────────────────────────
104
104
  function renderRichText(el: RichTextElement, ctx: RenderContext): HTMLElement {
105
105
  const p = document.createElement("p");
106
+ p.style.whiteSpace = "pre-wrap"; // keep "\n" line breaks (folded paragraphs) — same as the reader
106
107
  p.className = "jdfjs-richtext";
107
108
  p.style.margin = "0";
108
109
  applyStyle(p, resolveStyle(el.style, ctx.styles));
@@ -294,7 +295,13 @@ function colWidthCss(w: string | number | undefined): string | undefined {
294
295
  function renderTable(el: TableElement, ctx: RenderContext): HTMLElement {
295
296
  const wrap = document.createElement("div");
296
297
  wrap.className = "jdfjs-table-wrap";
297
- applyStyle(wrap, resolveStyle(el.style, ctx.styles));
298
+ // `style.fontSize` / `lineHeight` size the cells and `style.padding` is the
299
+ // cell padding (the PDF importer writes compact values so a converted
300
+ // statement occupies the same box as the source rows). Same rules as the
301
+ // reader's TableElement — keep them identical.
302
+ const tableCss = resolveStyle(el.style, ctx.styles);
303
+ const { padding: cellPad = "8px 12px", ...wrapCss } = tableCss;
304
+ applyStyle(wrap, wrapCss);
298
305
  wrap.style.overflowX = "auto";
299
306
 
300
307
  const headerCss = (() => {
@@ -335,7 +342,8 @@ function renderTable(el: TableElement, ctx: RenderContext): HTMLElement {
335
342
  table.style.width = "100%";
336
343
  table.style.borderCollapse = "collapse";
337
344
  table.style.tableLayout = el.columns?.some((c) => c.width != null) ? "fixed" : "auto";
338
- table.style.fontSize = "14px";
345
+ table.style.fontSize = tableCss["font-size"] || "14px";
346
+ if (tableCss["line-height"]) table.style.lineHeight = tableCss["line-height"];
339
347
  if (borders.outer) table.style.border = `${borders.width || 1}px solid ${borders.color || "#e2e8f0"}`;
340
348
 
341
349
  // Column widths — honour columns[].width via a <colgroup> so both header
@@ -358,9 +366,11 @@ function renderTable(el: TableElement, ctx: RenderContext): HTMLElement {
358
366
  headers.forEach((h, i) => {
359
367
  const th = document.createElement("th");
360
368
  th.textContent = h;
361
- th.style.padding = "8px 12px";
369
+ th.style.padding = cellPad;
362
370
  th.style.fontWeight = "600";
363
- th.style.background = "#f8fafc";
371
+ // Designed tables get the light header band; a table that brings its own
372
+ // headerStyle (the PDF importer, hand-authored docs) shows exactly that.
373
+ if (!el.headerStyle) th.style.background = "#f8fafc";
364
374
  th.style.textAlign = colAlign(i) || "left";
365
375
  if (borders.inner) th.style.border = `${borders.width || 1}px solid ${borders.color || "#e2e8f0"}`;
366
376
  tr.appendChild(th);
@@ -381,13 +391,17 @@ function renderTable(el: TableElement, ctx: RenderContext): HTMLElement {
381
391
  const tr = document.createElement("tr");
382
392
  applyStyle(tr, rowCss as any);
383
393
  if (ri % 2 === 1) applyStyle(tr, altRowCss as any);
394
+ // A spacer row (every cell empty — the PDF importer keeps a statement's
395
+ // blank separator lines) must still be one line tall, so it gets a
396
+ // non-breaking space; an empty cell in a filled row stays empty.
397
+ const blankRow = row.every((c) => cellText(c) === "");
384
398
  row.forEach((cell, ci) => {
385
399
  const td = document.createElement("td");
386
- td.textContent = cellText(cell);
400
+ td.textContent = blankRow ? "\u00a0" : cellText(cell);
387
401
  const attrs = cellAttrs(cell);
388
402
  if (attrs.colspan) td.colSpan = attrs.colspan;
389
403
  if (attrs.rowspan) td.rowSpan = attrs.rowspan;
390
- td.style.padding = "8px 12px";
404
+ td.style.padding = cellPad;
391
405
  td.style.verticalAlign = "top";
392
406
  // Cell-level align wins over the column default.
393
407
  td.style.textAlign = cellAlign(cell) || colAlign(ci) || "left";
@@ -1,3 +1,4 @@
1
+ import { unitToPx } from "@jdf/core";
1
2
  import type { Style, StyleRef } from "@jdf/core";
2
3
 
3
4
  function paddingToCss(p: NonNullable<Style["padding"]>): string {
@@ -16,6 +17,8 @@ export function styleToCss(style: Style): Record<string, string> {
16
17
  if (style.color) css["color"] = style.color;
17
18
  if (style.backgroundColor) css["background-color"] = style.backgroundColor;
18
19
  if (style.textAlign) css["text-align"] = style.textAlign;
20
+ if (style.lineHeight) css["line-height"] = String(style.lineHeight); // unitless, same as the reader
21
+ if (style.textIndent) css["text-indent"] = `${unitToPx(style.textIndent)}px`;
19
22
  if (style.textDecoration) {
20
23
  const td = style.textDecoration === "strikethrough" ? "line-through" : style.textDecoration;
21
24
  css["text-decoration"] = td;