From 1ad4c9cd58df10c19c86ce877a5189a060ce9554 Mon Sep 17 00:00:00 2001 From: Brian Love Date: Fri, 5 Jun 2026 16:59:11 -0700 Subject: [PATCH] docs(website): align clipboard page with the @public copy API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The grid clipboard page's onCopy example referenced functions that don't exist (serializeAsTsv / serializeAsHtmlTable) and an arg shape that's wrong (`{ ranges, snapshot }`). The real onCopy signature is `(args: SerializeRangesArgs) => CopyPayload | null` where SerializeRangesArgs is `{ ranges, visibleRows, columns, copyWithHeaders }`, and the return is a CopyPayload (`{ text, html? }`) or null — never a bare string. - Rewrite the onCopy example to use the real `serializeRangesAsTsv` and the correct args shape (a working TSV→CSV override). - Correct the documented return type (CopyPayload | null, not string). - Add a "Building your own serializer" section documenting SerializeRangesArgs's fields and `defaultCoerceForCopy` (both @public, previously undocumented). - Document the `copyToClipboard` prop (also @public). Closes the clipboard-docs-alignment follow-up from the PR 3 @public commitment. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/website/content/docs/grid/clipboard.mdx | 62 ++++++++++++++++---- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/apps/website/content/docs/grid/clipboard.mdx b/apps/website/content/docs/grid/clipboard.mdx index 240d7c22..ad25aae6 100644 --- a/apps/website/content/docs/grid/clipboard.mdx +++ b/apps/website/content/docs/grid/clipboard.mdx @@ -39,28 +39,70 @@ const columns: PretableColumn[] = [ ## Grid-level `onCopy` override -For full control — a custom delimiter, a JSON payload, an HTML clipboard payload alongside the TSV — pass `onCopy` on the surface: +For full control — a custom delimiter, a JSON payload, an HTML clipboard payload alongside the TSV — pass `onCopy` on the surface. It receives the same `SerializeRangesArgs` the default serializer gets and returns a `CopyPayload` (`{ text, html? }`) or `null` to cancel the copy: ```tsx +import { serializeRangesAsTsv } from "@pretable/react"; + row.id} - onCopy={({ ranges, snapshot }) => ({ - text: serializeAsTsv({ ranges, snapshot }), - html: serializeAsHtmlTable({ ranges, snapshot }), - })} -/> + onCopy={(args) => { + // args is SerializeRangesArgs: { ranges, visibleRows, columns, copyWithHeaders } + const tsv = serializeRangesAsTsv(args); + if (!tsv) return null; // empty selection → cancel the copy + // Reuse the built-in TSV, but write CSV instead. + return { text: tsv.text.replace(/\t/g, ",") }; + }} +/>; ``` -`onCopy` returns: +`onCopy` returns a `CopyPayload` or `null`: -- `string` — written to the clipboard as `text/plain`. -- `{ text, html? }` — when `html` is present, the surface writes both `text/plain` and `text/html` via the Clipboard API. Excel and Sheets prefer `text/html` when present. +- `{ text, html? }` — `text` is written as `text/plain`; when `html` is present, the surface also writes `text/html` via the Clipboard API. Excel and Sheets prefer `text/html` when both are present. - `null` — skip the clipboard write entirely (suppress copy in this mode). -The `serializeRangesAsTsv` helper from `@pretable/react` is the same function the default uses; call it directly when you only want to wrap the TSV output. +`serializeRangesAsTsv` is the same helper the default path uses, so calling it inside `onCopy` (as above) keeps the built-in row/column/range handling — including filtering out the synthetic row-select column — and lets you post-process its output. + +## Building your own serializer + +`serializeRangesAsTsv`, `defaultCoerceForCopy`, and the `SerializeRangesArgs` / `CopyPayload` types are exported from `@pretable/react`, so you can build a serializer from the same primitives the default uses. + +`SerializeRangesArgs` is the argument both `onCopy` and `serializeRangesAsTsv` receive: + +| Field | Type | Notes | +| ----------------- | ---------------------------------- | ------------------------------------------------- | +| `ranges` | `readonly PretableCellRange[]` | the selected ranges, in the order they were added | +| `visibleRows` | `readonly PretableVisibleRow[]` | the currently materialized rows | +| `columns` | `readonly PretableColumn[]` | column defs (the row-select column is among them) | +| `copyWithHeaders` | `boolean` | mirror of the `copyWithHeaders` prop | + +`defaultCoerceForCopy(value)` is the fallback value→string coercion (the `null` / `Date` / primitive / object rules listed under [Default TSV format](#default-tsv-format)). Reach for it in a custom serializer so values without a per-column `format` still stringify consistently: + +```tsx +import { defaultCoerceForCopy } from "@pretable/react"; + +const text = column.format + ? column.format({ value, row, column }) + : defaultCoerceForCopy(value); +``` + +## `copyToClipboard` override + +By default the surface writes the `CopyPayload` to the system clipboard via the async Clipboard API. Pass `copyToClipboard` to intercept that write — to route copies through your own clipboard shim, log them, or target a non-DOM environment: + +```tsx + { + await myClipboard.write({ text, html }); + }} + /* ... */ +/> +``` + +It receives the `CopyPayload` produced by the default serializer or your `onCopy`, and may return a promise. ## `copyWithHeaders`