Skip to content

feat(xlsx): inline hyperlinks in data rows (#325)#326

Merged
productdevbook merged 1 commit into
mainfrom
feat/inline-hyperlinks-data-325
May 28, 2026
Merged

feat(xlsx): inline hyperlinks in data rows (#325)#326
productdevbook merged 1 commit into
mainfrom
feat/inline-hyperlinks-data-325

Conversation

@productdevbook
Copy link
Copy Markdown
Owner

@productdevbook productdevbook commented May 28, 2026

Closes #325.

Problem

writeXlsx's columns + data API only accepted scalar CellValue for row values. Hyperlinks with separate display text could only be expressed via the parallel cells: Map<"row,col", …> API — meaning three sources of truth for one logical "Link" column (schema in columns, value in cells, coordinate in a hand-computed "row,col" string). Reordering or inserting columns broke the index math.

Solution

Allow rich values inline in data rows — an ExcelJS-compatible { text, hyperlink, tooltip? } shape, keyed by the column's key. The cells map path is fully preserved for backward compatibility.

import { writeXlsx, link } from "hucre/xlsx"

await writeXlsx({
  sheets: [{
    name: "Summary",
    columns: [{ header: "Link", key: "link" }, { header: "ID", key: "id" }],
    data: [
      { link: link("Open", "https://example.com/items/abc-123"), id: "abc-123" },
      { link: { text: "Open", hyperlink: "https://example.com/items/def-456" }, id: "def-456" },
    ],
  }],
})

Changes

  • HyperlinkValue type + widened data type. CellValue union is left untouched, so CSV/ODS/formula serialization paths are unaffected.
  • link(text, hyperlink, tooltip?) helper exported from both hucre and hucre/xlsx. A plain object is also accepted (stays JSON-serializable).
  • #-prefixed targets become internal references (location), e.g. "#Sheet2!A1".
  • collectHyperlinks now reads the resolved grid, so links from both inline data rows and the cells map are collected from a single source (this also closes the existing gap where a cells-map hyperlink was never carried onto the ResolvedCell).
  • Non-XLSX consumers (ODS writer, pivot source rows) unwrap rich values to scalar text.

Design note

Surveyed competing libraries (ExcelJS, SheetJS, write-excel-file). { text, hyperlink, tooltip } is the most familiar shape in the ecosystem (ExcelJS) and maps almost 1:1 to hucre's internal Hyperlink type. Issue Option A (inline) was chosen as the core solution; Option B (column-level getter) was left out of scope.

Testing

  • pnpm test: 7472 tests pass (including lint + typecheck).
  • 6 new tests: raw object, link() helper, tooltip round-trip, #-internal ref, scalar values left untouched, mixed data + cells on the same sheet.
  • README updated with an inline data + link() example.

🤖 Generated with Claude Code

Allow rich hyperlink values directly inside `writeXlsx` `data` row objects,
keyed by a column's `key`, instead of a parallel `cells: Map<"row,col", …>`.

- New `HyperlinkValue` ({ text, hyperlink, tooltip? }) — ExcelJS-compatible shape
- `link(text, hyperlink, tooltip?)` helper exported from hucre and hucre/xlsx
- `#`-prefixed targets become internal references (location)
- `collectHyperlinks` now reads the resolved grid, so links from both `data`
  rows and the `cells` map are collected from a single source
- Non-XLSX consumers (ODS writer, pivot source rows) unwrap to scalar text

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@productdevbook productdevbook merged commit a41c9a8 into main May 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: hyperlinks in data rows (or column-driven link generation)

1 participant