Skip to content

Commit bb54644

Browse files
IzumiSyitspradeclaudeCopilot
authored
feat(data-table): add declarative cell-editing errors (#635)
* feat(data-table): add declarative cell-editing errors * fix(data-table): remove built-in cell error reset action * feat(data-table): refine the cell-error popover UI (#638) * feat(data-table): give the default cell-error popover an error look and undo hint The standard popover body showed only the message, so it read like a neutral tooltip. It now leads with a destructive alert icon, shows the message in medium weight, and adds the existing "Press Esc to undo" hint. Custom error.render content is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(data-table): tighten the cell-error popover Drop the undo hint and the popup border, reduce padding and cap the width at max-w-xs so long messages wrap. The lab's Draft note column now throws a longer message on "?" to show wrapping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(data-table): refine cell-error popover placement and tint - 1px error ring on the cell, including while focused - popup opens directly under the cell, aligned to its left edge - light red tint (Alert's danger-surface) layered over the opaque popover colour so table lines don't show through; softer shadow-sm - icon centred on the first text line, at 70% of the text colour - lab: "!!" in Draft note throws a long message to show wrapping Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(data-table): 1.5px error outline, heavier error icons - cell error ring is 1.5px (resting and focused) - error icons in the cell and popover use strokeWidth 2.5 - drop the focus ring on the in-cell error trigger; it drew a second box around the icon when focus returned to it on popover close Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * fix(data-table): refine editing error handling and examples * docs(changeset): add cell editing error usage examples * docs(changeset): clarify cell editing error summary * fix(data-table): clarify edit confirmation failure feedback * fix(data-table): preserve errors and dismiss details on Tab --------- Co-authored-by: pradeep <6978383+itsprade@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: IzumiSy <982850+IzumiSy@users.noreply.github.com>
1 parent 2413432 commit bb54644

17 files changed

Lines changed: 2488 additions & 216 deletions

File tree

‎.changeset/quiet-cell-errors.md‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
"@tailor-platform/app-shell": minor
3+
---
4+
5+
Add built-in error popovers to DataTable inline editing. When `onValueChange` or `onValueCommitted` throws or returns a rejected Promise, the affected cell shows an error. Throw the exported `CellEditError` with a translated, user-facing message to display that text; other failures display the localized message “Could not confirm this change”.
6+
7+
Alongside this feedback, the editor now retains pending and failed drafts for correction or retry. Confirmation waits for any pending `onValueChange` check to succeed, and the draft clears only after confirmation succeeds. Drafts remain editable without trapping cell navigation. For direct inputs, Tab and Shift+Tab retain an already failed commit without retrying it; press Enter to retry. Data adoption, persistence, and rollback remain consumer-owned.
8+
9+
Each new failure automatically opens its popover without moving focus. Closing the details retains the draft and error, which can be inspected again with the error icon or Alt+ArrowDown. Tab or Shift+Tab to another cell or out of the table dismisses the details without trapping focus; Tab within interactive error content remains available. Esc closes open details first; a subsequent Esc discards the draft and error together. The standard popover adds no reset action.
10+
11+
For example, reject negative quantities with a user-facing message. Invalid drafts remain editable; successful confirmation updates the consumer-owned rows:
12+
13+
```tsx
14+
import { useState } from "react";
15+
import {
16+
CellEditError,
17+
DataTable,
18+
createColumnHelper,
19+
useDataTable,
20+
} from "@tailor-platform/app-shell";
21+
22+
type Item = { id: string; quantity: number | null };
23+
const { column } = createColumnHelper<Item>();
24+
25+
function EditableItems() {
26+
const [rows, setRows] = useState<Item[]>([{ id: "item-1", quantity: 5 }]);
27+
const columns = [
28+
column({
29+
id: "quantity",
30+
label: "Quantity",
31+
type: "number",
32+
edit: {
33+
onValueCommitted: (row, value) => {
34+
if (value !== null && value < 0) {
35+
throw new CellEditError("Quantity must be zero or greater");
36+
}
37+
setRows((current) =>
38+
current.map((item) => (item.id === row.id ? { ...item, quantity: value } : item)),
39+
);
40+
},
41+
},
42+
}),
43+
];
44+
const table = useDataTable({ columns, data: { rows } });
45+
46+
return (
47+
<DataTable.Root value={table}>
48+
<DataTable.Table />
49+
</DataTable.Root>
50+
);
51+
}
52+
```
53+
54+
The standard error popover needs no configuration. To customize its body or include consumer-owned actions, add `error.render` to the column's `edit` config. The renderer receives the current row and the original thrown value:
55+
56+
```tsx
57+
error: {
58+
render: ({ row, error }) => (
59+
<div>
60+
<p>Could not update item {row.id}</p>
61+
<p>{error instanceof CellEditError ? error.message : "Please try again later"}</p>
62+
</div>
63+
),
64+
},
65+
```
66+
67+
If the callback handles its own failures and feedback instead, set `edit.error: false` to disable callback interception and retain eager edit completion.

‎docs-manifest.json‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@
412412
"symbols": [
413413
"BadgeCellEditOptions",
414414
"BuildQueryVariables",
415+
"CellEditError",
415416
"CellEditState",
416417
"CollectionControl",
417418
"CollectionControlProvider",
@@ -471,10 +472,10 @@
471472
"withURLCollectionState"
472473
],
473474
"hashes": {
474-
"typeSurface": "05cbf8a4bdb7a863",
475-
"outline": "93a2a1e3c380f5b9",
475+
"typeSurface": "33eb2bdd6be1c774",
476+
"outline": "8ca624c7ec761939",
476477
"snapshot": "a97e067c66e46ef6",
477-
"outputMd": "94d4e9340fdb20f3",
478+
"outputMd": "b1ee3ccb6cb4a1f4",
478479
"examples": "10abd548e6affb9d"
479480
}
480481
},
@@ -1786,7 +1787,7 @@
17861787
"packages/core/skills/app-shell-patterns/references/components/combobox.md": "dfb775c7c4307409",
17871788
"packages/core/skills/app-shell-patterns/references/components/command-palette.md": "7e5bc675a593791a",
17881789
"packages/core/skills/app-shell-patterns/references/components/csv-importer.md": "53d3c795ca21b9dc",
1789-
"packages/core/skills/app-shell-patterns/references/components/data-table.md": "94d4e9340fdb20f3",
1790+
"packages/core/skills/app-shell-patterns/references/components/data-table.md": "b1ee3ccb6cb4a1f4",
17901791
"packages/core/skills/app-shell-patterns/references/components/date-picker.md": "bc69f14829004f9d",
17911792
"packages/core/skills/app-shell-patterns/references/components/default-header.md": "375e55f4b12fa2be",
17921793
"packages/core/skills/app-shell-patterns/references/components/default-sidebar.md": "3422388a0cc78571",

0 commit comments

Comments
 (0)