@uurtech/jdf 0.1.22 → 0.1.23

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.1.22",
3
+ "version": "0.1.23",
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>",
@@ -182,22 +182,30 @@ function renderImage(el: ImageElement, ctx: RenderContext): HTMLElement {
182
182
 
183
183
  // ── table ───────────────────────────────────────────────────────────────────
184
184
  function cellText(c: TableCellValue): string {
185
- return typeof c === "string" ? c : c.content;
185
+ // Tolerate malformed cells (null, numbers, missing content) instead of
186
+ // throwing — a single bad cell must never abort the whole render. The reader
187
+ // (SolidJS <For>) is naturally lenient here; the web embed's .forEach used to
188
+ // throw on `null.content`, killing the table and every element after it on
189
+ // the page. Coerce anything non-stringy to a best-effort string.
190
+ if (c == null) return "";
191
+ if (typeof c === "string") return c;
192
+ if (typeof c === "object") return c.content == null ? "" : String(c.content);
193
+ return String(c);
186
194
  }
187
195
  function cellAttrs(c: TableCellValue): { colspan?: number; rowspan?: number } {
188
- if (typeof c === "string") return {};
196
+ if (c == null || typeof c !== "object") return {};
189
197
  return { colspan: c.colspan, rowspan: c.rowspan };
190
198
  }
191
199
  /** Per-cell style object → CSS map (string ref / array / inline Style). */
192
200
  function cellCss(c: TableCellValue, styles: Record<string, Style>): Record<string, string> {
193
- if (typeof c === "string" || !c.style) return {};
201
+ if (c == null || typeof c !== "object" || !c.style) return {};
194
202
  const s = c.style;
195
203
  if (typeof s === "string") return styleToCss(styles[s] || {});
196
204
  if (Array.isArray(s)) { let m = {}; for (const k of s) m = { ...m, ...styleToCss(styles[k] || {}) }; return m; }
197
205
  return styleToCss(s);
198
206
  }
199
207
  function cellAlign(c: TableCellValue): TextAlign | undefined {
200
- return typeof c === "string" ? undefined : c.align;
208
+ return c == null || typeof c !== "object" ? undefined : c.align;
201
209
  }
202
210
  /** Normalise a column width (number → px, string passed through, e.g. "30%"). */
203
211
  function colWidthCss(w: string | number | undefined): string | undefined {
@@ -284,7 +292,14 @@ function renderTable(el: TableElement, ctx: RenderContext): HTMLElement {
284
292
  }
285
293
 
286
294
  const tbody = document.createElement("tbody");
287
- el.rows.forEach((row, ri) => {
295
+ // Normalise rows/cells defensively: a row that isn't an array (object, null,
296
+ // stray string) or a table whose `rows` isn't an array must not throw and
297
+ // abort the page render. Non-array rows are skipped (like the reader's <For>),
298
+ // matching desktop behaviour so a partly-malformed table still shows its
299
+ // well-formed rows on the web instead of vanishing.
300
+ const rows: TableCellValue[][] = Array.isArray(el.rows) ? el.rows : [];
301
+ rows.forEach((row, ri) => {
302
+ if (!Array.isArray(row)) return;
288
303
  const tr = document.createElement("tr");
289
304
  applyStyle(tr, rowCss as any);
290
305
  if (ri % 2 === 1) applyStyle(tr, altRowCss as any);