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
20 changes: 20 additions & 0 deletions .changeset/bright-tools-align.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
"@tailor-platform/app-shell": minor
---

Add a full-width `Toolbar` with composable rows, grouped controls, separators, and optional edge-to-edge row layout.

```tsx
<Toolbar.Root>
<Toolbar.Row justify="between" aria-label="List actions">
<Toolbar.Group>
<DataTable.Filters />
</Toolbar.Group>
<Toolbar.Group>
<DataTable.ColumnSettings />
</Toolbar.Group>
</Toolbar.Row>
</Toolbar.Root>
```

AppShell Buttons, inputs, selects, comboboxes, and tabs automatically participate in toolbar keyboard navigation.
61 changes: 61 additions & 0 deletions decisions/generic-toolbar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Decision: generic `Toolbar` for action-bar layout

> Status: **Decided — introduce a generic `Toolbar` for layout and compose feature controls inside it. Implemented by PR #559.**
> Scope: toolbar layout, DataTable composition, and the migration direction for `DataTable.Toolbar`. This does not deprecate or remove `DataTable.Toolbar`.

## Context

`DataTable.Toolbar` combines two concerns:

- layout of a full-width action bar; and
- DataTable-specific controls and their placement.

That fixed composition does not serve other list presentations or the planned ActionBar use case. A second DataTable-specific layout API would duplicate the composition model: consumers would need to decide when to use the wrapper and when to use a general-purpose toolbar.

A generic toolbar also requires consumers to choose leading/trailing placement explicitly with `justify="between"`. That choice can be missed, producing inconsistent layouts, so the component needs a canonical DataTable scaffold in its documentation and examples.

## Decision

### A single generic layout primitive

Expose `Toolbar` as a layout component with four parts:

- `Toolbar.Root` stacks rows;
- `Toolbar.Row` is a horizontal action row and supports `justify="start" | "between"`;
- `Toolbar.Group` keeps related controls together; and
- `Toolbar.Separator` separates groups visually.

`Toolbar` does not own DataTable controls or any other feature-specific controls. It standardizes the layout details that otherwise drift between screens: padding, gaps, wrapping, borders, and row-level keyboard navigation.

### Feature controls compose directly

`DataTable.Filters` and `DataTable.ColumnSettings` are controls that can be placed in a generic toolbar alongside buttons, inputs, tabs, and controls from other features.

```tsx
<DataTable.Root value={table}>
<Toolbar.Root>
<Toolbar.Row justify="between" aria-label="Table controls">
<Toolbar.Group>
<DataTable.Filters />
</Toolbar.Group>
<Toolbar.Group>
<DataTable.ColumnSettings />
</Toolbar.Group>
</Toolbar.Row>
</Toolbar.Root>
<DataTable.Table />
</DataTable.Root>
```

When a generic toolbar is a direct child of `DataTable.Root`, DataTable owns the outer frame while the toolbar supplies the divider below its rows.

### Keep the existing DataTable wrapper during migration

`DataTable.Toolbar` remains supported for its existing fixed layout. New custom layouts should use `Toolbar` directly. Deprecating `DataTable.Toolbar` is a separate compatibility and release decision, not part of this change.

## Consequences

- DataTable and non-DataTable screens use the same composition model for action-bar layout.
- `justify="between"` remains explicit rather than becoming a DataTable-only placement convention; the documentation and example page provide the canonical leading/trailing layout.
- AppShell buttons, inputs, selects, comboboxes, and tabs participate automatically in a toolbar row's Arrow/Home/End navigation. Composite controls retain their own directional-key behavior.
- There is no new `DataTable.Toolbar` layout API or named wrapper around the generic toolbar. Add one only if a stable, opinionated DataTable layout proves necessary across consumers.
28 changes: 23 additions & 5 deletions docs-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -443,10 +443,10 @@
"withURLCollectionState"
],
"hashes": {
"typeSurface": "199f1cb9d06e3c15",
"outline": "2458512deac6c312",
"typeSurface": "014a9036a3b9b0af",
"outline": "f1bea006bdeb43a4",
"snapshot": null,
"outputMd": "d4212ff859cfb879",
"outputMd": "dd2da884d7550daf",
"examples": null
}
},
Expand Down Expand Up @@ -1307,6 +1307,23 @@
"examples": null
}
},
"toolbar": {
"slug": "toolbar",
"kind": "code-backed",
"outline": "docs-src/components/toolbar.docs.outline.md",
"output": "docs/components/toolbar.md",
"examples": null,
"sources": ["packages/core/src/components/toolbar/**"],
"claims": [],
"symbols": ["Toolbar", "ToolbarProps"],
"hashes": {
"typeSurface": "2d88f0306efcaa77",
"outline": "1257a84ccd91d5c3",
"snapshot": "3b402cab18147ef9",
"outputMd": "91d70b140c7bb747",
"examples": null
}
},
"tooltip": {
"slug": "tooltip",
"kind": "code-backed",
Expand Down Expand Up @@ -1588,7 +1605,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": "d4212ff859cfb879",
"packages/core/skills/app-shell-patterns/references/components/data-table.md": "dd2da884d7550daf",
"packages/core/skills/app-shell-patterns/references/components/date-picker.md": "33902be121ff69db",
"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 All @@ -1612,6 +1629,7 @@
"packages/core/skills/app-shell-patterns/references/components/tabs.md": "30bb32e57fc78bd9",
"packages/core/skills/app-shell-patterns/references/components/textarea.md": "c940bc01cd573334",
"packages/core/skills/app-shell-patterns/references/components/timeline.md": "699249c9452485ab",
"packages/core/skills/app-shell-patterns/references/components/toolbar.md": "91d70b140c7bb747",
"packages/core/skills/app-shell-patterns/references/components/tooltip.md": "113c95b2995917ed",
"packages/core/skills/app-shell-patterns/references/components/with-guard.md": "d79aaf40cb97073f",
"packages/core/skills/app-shell-patterns/references/api/create-ai-gateway-client.md": "7eaff97521a14ab0",
Expand Down Expand Up @@ -1650,6 +1668,6 @@
"packages/core/skills/app-shell-patterns/references/patterns/list-dense-scan.md": "8062ea0df9403fbb",
"packages/core/skills/app-shell-patterns/references/pages/document-detail.md": "c3fb2588a0699c26",
"packages/core/skills/app-shell-patterns/references/migrations.md": "799fd5010635b2c2",
"packages/core/skills/app-shell-patterns/SKILL.md": "165761adda4fbfc0"
"packages/core/skills/app-shell-patterns/SKILL.md": "814325f4ea06ffae"
}
}
Loading
Loading