Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .changeset/quiet-cell-errors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
"@tailor-platform/app-shell": minor
---

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”.

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.

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.

For example, reject negative quantities with a user-facing message. Invalid drafts remain editable; successful confirmation updates the consumer-owned rows:

```tsx
import { useState } from "react";
import {
CellEditError,
DataTable,
createColumnHelper,
useDataTable,
} from "@tailor-platform/app-shell";

type Item = { id: string; quantity: number | null };
const { column } = createColumnHelper<Item>();

function EditableItems() {
const [rows, setRows] = useState<Item[]>([{ id: "item-1", quantity: 5 }]);
const columns = [
column({
id: "quantity",
label: "Quantity",
type: "number",
edit: {
onValueCommitted: (row, value) => {
if (value !== null && value < 0) {
throw new CellEditError("Quantity must be zero or greater");
}
setRows((current) =>
current.map((item) => (item.id === row.id ? { ...item, quantity: value } : item)),
);
},
},
}),
];
const table = useDataTable({ columns, data: { rows } });

return (
<DataTable.Root value={table}>
<DataTable.Table />
</DataTable.Root>
);
}
```

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:

```tsx
error: {
render: ({ row, error }) => (
<div>
<p>Could not update item {row.id}</p>
<p>{error instanceof CellEditError ? error.message : "Please try again later"}</p>
</div>
),
},
```

If the callback handles its own failures and feedback instead, set `edit.error: false` to disable callback interception and retain eager edit completion.
9 changes: 5 additions & 4 deletions docs-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@
"symbols": [
"BadgeCellEditOptions",
"BuildQueryVariables",
"CellEditError",
"CellEditState",
"CollectionControl",
"CollectionControlProvider",
Expand Down Expand Up @@ -471,10 +472,10 @@
"withURLCollectionState"
],
"hashes": {
"typeSurface": "05cbf8a4bdb7a863",
"outline": "93a2a1e3c380f5b9",
"typeSurface": "33eb2bdd6be1c774",
"outline": "8ca624c7ec761939",
"snapshot": "a97e067c66e46ef6",
"outputMd": "94d4e9340fdb20f3",
"outputMd": "b1ee3ccb6cb4a1f4",
"examples": "10abd548e6affb9d"
}
},
Expand Down Expand Up @@ -1786,7 +1787,7 @@
"packages/core/skills/app-shell-patterns/references/components/combobox.md": "dfb775c7c4307409",
"packages/core/skills/app-shell-patterns/references/components/command-palette.md": "7e5bc675a593791a",
"packages/core/skills/app-shell-patterns/references/components/csv-importer.md": "53d3c795ca21b9dc",
"packages/core/skills/app-shell-patterns/references/components/data-table.md": "94d4e9340fdb20f3",
"packages/core/skills/app-shell-patterns/references/components/data-table.md": "b1ee3ccb6cb4a1f4",
"packages/core/skills/app-shell-patterns/references/components/date-picker.md": "bc69f14829004f9d",
"packages/core/skills/app-shell-patterns/references/components/default-header.md": "375e55f4b12fa2be",
"packages/core/skills/app-shell-patterns/references/components/default-sidebar.md": "3422388a0cc78571",
Expand Down
Loading
Loading