test(react): pin the copy/paste column-space coupling while grouped - #485
Merged
Conversation
The derived group column sits in paste's target space: `mapPasteToTargets` filters only `ROW_SELECT_COLUMN_ID`, so `__pretable_group__` occupies a slot, takes the block's first value when the anchor lands at column 0, and reports it back as a `not-editable` rejection. That reads like an oversight and isn't. Copy and CSV both emit a field for the same column — the group label on a group row, an empty field on a data row — so the slot is what keeps the two sides counting across the same column space. Dropping it from paste alone shifts every value one column right on the way back in: a whole-row copy of `\tr0a\tr0b\tr0c\tr0d` pasted onto another row writes `a=""` (blanking a real column), `b=r0a`, `c=r0b`, `d=r0c`, and clips `r0d`. Silent and destructive, where today's cost is a cosmetic rejection entry. Nothing pinned that coupling: all 116 existing clipboard tests pass with the group column excluded from `mapPasteToTargets`. This test round-trips a whole grouped row through `serializeRanges` -> `parseTsv` -> `mapPasteToTargets` and asserts every value lands back in the column it came from. It holds under either arrangement — group column in both spaces or in neither — and fails only when the two disagree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
blove
enabled auto-merge (squash)
August 24, 2026 17:36
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
Vercel preview readyPreview: https://pretable-nrr810fiy-cacheplane.vercel.app Updated automatically by the |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What I was asked to fix, and why I didn't
The scoped defect was: the derived group column is not excluded from paste's column space —
mapPasteToTargetsfilters onlyROW_SELECT_COLUMN_ID(packages/react/src/paste.ts:316), so__pretable_group__occupies a slot no consumer column occupies.Both predicted manifestations are real and reachable:
ROW_SELECT_COLUMN_IDis guarded in itsonClick). A plain click focuses it (data-pretable-focused="true"), and a paste there sends block column 0 into__pretable_group__:rejected: ["r1:__pretable_group__=x (not-editable)"],cells: ["r1:name=y"].But the inclusion is load-bearing, not an oversight.
copy.ts:327andcsv.ts:523both deliberately emit a field for the same derived column — the group label on a group row, an empty field on a data row (its definition isvalue: () => ""). Verified directly: a whole grouped row serializes to"\tr0a\tr0b\tr0c\tr0d". That leading empty field is what the paste slot lines up with.Excluding the group column from paste alone therefore breaks the copy-rows → paste-rows round trip, destructively. Measured by mutating
paste.tsexactly as scoped:ais silently blanked with copy's empty group field and every value shifts one column right. Today's cost is a cosmeticrejectedentry naming a column the consumer can recognize (GROUP_COLUMN_IDis public API). Trading a benign rejection for a silent wrong write is the wrong direction, so I did not ship the fix.What this PR does
Nothing pinned that coupling — all 116 existing clipboard tests pass with the group column excluded from
mapPasteToTargets, which is why this was scoped as a one-line fix in the first place. This adds the missing guard.The test round-trips a whole grouped row through
serializeRanges→parseTsv→mapPasteToTargetson the same drawn-column array the surface passes to both, and asserts every value lands back in the column it came from. It is written against the invariant, not the current choice: it passes whether the group column is in both column spaces or neither, and fails only when the two disagree.The real trade, left open
The two sides genuinely conflict and the resolution is a product decision, not a bug fix:
__pretable_group__and the rest shift right.The only arrangement that satisfies both is coherent change on both sides: stop copy/CSV emitting a standalone field for the derived group column (e.g. move the group label into the first data column), then drop the slot from paste. That changes documented copy behavior (
clipboard.mdx:44-47) and would lose group labels from a select-all copy unless the label is rehomed — worth a brainstorm, not a drive-by.Gate
pnpm build,pnpm typecheck,pnpm lint,pnpm format,pnpm test(every package ran; react 1247 passed),pnpm api:check— all exit 0.One snag worth knowing:
pnpm buildfailed twice withTS2307: Cannot find module '@pretable/core'frompackages/renderer-domuntilpnpm installrelinked it — the worktree'spackages/renderer-dom/node_moduleshad no@pretabledirectory at all. Not caused by this branch.🤖 Generated with Claude Code