themed-table-2
Use ThemedTable2<T> in a layrz Flutter widget. Apply when displaying a list of domain objects in a table with sort, search, multiselect, and row actions.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use ThemedTable2<T> in a layrz Flutter widget. Apply when displaying a list of domain objects in a table with sort, search, multiselect, and row actions.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use ThemedTabView and ThemedTab in a layrz Flutter widget. Apply when adding horizontal tab navigation with Material 3 styling.
Use ThemedButton in a layrz Flutter widget. Apply when rendering any tappable action — primary/secondary CTAs, icon-only FABs, destructive actions, cooldown buttons, or the six semantic factories (.save, .cancel, .info, .show, .edit, .delete).
Use ThemedSearchInput in a layrz Flutter widget. Apply when adding a search bar — either a compact icon button that expands into an overlay, or a full-width inline field.
Use when migrating ThemedTable<T> (v1) to ThemedTable2<T> (v2) in a layrz Flutter widget. Apply when a widget uses the old ThemedTable API with onShow/onEdit/onDelete/onMultiDelete/ThemedColumn and needs to be updated.
Use ResponsiveCol in a layrz Flutter widget. Apply when defining a column's width at different breakpoints inside a ResponsiveRow.
Use ResponsiveRow in a layrz Flutter widget. Apply when wrapping ResponsiveCol children in a responsive 12-column grid container.
| name | themed-table-2 |
| description | Use ThemedTable2<T> in a layrz Flutter widget. Apply when displaying a list of domain objects in a table with sort, search, multiselect, and row actions. |
Dart syntax: This library requires Dart ≥ 3.10. Use dot shorthand for all enum values — never write the fully-qualified form.
Full constructor and property reference: read
references/api.mdin this skill's directory.
ThemedColumn2<T> to define columns alongside ThemedTable2<T>ThemedTable2<Asset>(
items: store.assets,
actionsCount: 0,
hasMultiselect: false,
columns: [
ThemedColumn2<Asset>(
headerText: 'Name',
valueBuilder: (item) => item.name,
),
ThemedColumn2<Asset>(
headerText: 'Plate',
valueBuilder: (item) => item.plate ?? 'N/A',
),
],
)
Always wrap in Expanded or give a fixed height — ThemedTable2 requires bounded height.
ListView.builder + fixed itemExtent — only visible rows are rendered.compute() — valueBuilder and customSort must be isolate-safe (no BuildContext, no i18n, no Flutter objects).actionsCount must equal the number of buttons actionsBuilder actually returns — assert enforced.hasMultiselect: true requires at least one entry in multiselectActions — assert enforced.onTapDefaultBehavior defaults to .copyToClipboard; set to .none to disable.onFilteredCountChanged fires after every _filterAndSort cycle (initial load, search, sort, items update) with the visible row count. Fires with 0 for an empty dataset. Optional — null by default, no overhead when omitted.valueBuilder and customSort run inside a background isolate. They cannot capture Flutter objects (BuildContext, i18n, State, Streams, widgets). Doing so causes a runtime crash:
Invalid argument(s): Illegal argument in isolate message: object is unsendable
Wrong:
// ❌ CRASH — i18n captures BuildContext
valueBuilder: (item) => i18n.t('status.${item.status}'),
Right:
// ✅ SAFE — precompute a plain Map before the ThemedTable2 call
final Map<String, String> statusLabels = {
'active': i18n.t('status.active'),
'inactive': i18n.t('status.inactive'),
};
valueBuilder: (item) => statusLabels[item.status] ?? item.status ?? 'N/A',
// With search + actions
ThemedTable2<Asset>(
items: _items,
canSearch: true,
actionsCount: 2,
hasMultiselect: false,
columns: [
ThemedColumn2<Asset>(
headerText: i18n.t('asset.name'),
valueBuilder: (item) => item.name,
),
ThemedColumn2<Asset>(
headerText: i18n.t('asset.plate'),
width: 150,
valueBuilder: (item) => item.plate ?? 'N/A',
),
],
actionsBuilder: (item) => [
ThemedActionButton.edit(
labelText: i18n.t('actions.edit'),
onTap: () => _onEdit(item),
),
ThemedActionButton.delete(
labelText: i18n.t('actions.delete'),
onTap: () => _onDelete(item),
),
],
)
// With multiselect
final ValueNotifier<List<Asset>> _selected = ValueNotifier([]);
ThemedTable2<Asset>(
items: _items,
hasMultiselect: true,
actionsCount: 0,
multiselectValue: _selected,
multiselectActions: [
ThemedActionButton(
icon: LayrzIcons.solarOutlineTrashBin,
labelText: i18n.t('actions.deleteSelected'),
color: Colors.red,
onTap: () => _onDeleteSelected(_selected.value),
),
],
columns: [ /* ... */ ],
)
// With filtered count callback
ThemedTable2<Asset>(
items: _items,
canSearch: true,
actionsCount: 0,
hasMultiselect: false,
onFilteredCountChanged: (count) {
setState(() => _visibleCount = count);
},
columns: [ /* ... */ ],
)
// With programmatic controller
final _controller = ThemedTable2Controller<Asset>();
// In dispose():
_controller.dispose();
ThemedTable2<Asset>(
items: _items,
controller: _controller,
columns: [ /* ... */ ],
actionsCount: 0,
hasMultiselect: false,
)
// Trigger sort programmatically
_controller.sort(columnIndex: 0, ascending: true);
_controller.refresh();