DataTable

並べ替え・行の選択・列の表示切り替えができる表。状態はすべて外から渡す

インポート

ts
import { DataTable, type DataTableSort } from '@k8ordo/ui';

使い方

状態はすべて呼び出し側が持つ(制御型)。並べ替えの状態を受けても DataTable は並べ替えず、渡された順に描くので、サーバーで並べ替えるときも同じ部品で済む。機能は、その変化を受け取る関数を渡したときだけ現れる。

Role
AokiDesigner3
InoueEngineer8
UedaEngineer5
tsx
const [sort, setSort] = useState<DataTableSort | null>(null);
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const [hiddenColumnIds, setHiddenColumnIds] = useState<string[]>([]);

<DataTable
  columns={[
    { id: 'name', header: 'Name', cell: (m) => m.name, sortable: true },
    { id: 'role', header: 'Role', cell: (m) => <Badge label={m.role} /> },
    {
      id: 'projects',
      header: 'Projects',
      cell: (m) => m.projects,
      align: 'right',
      sortable: true,
    },
  ]}
  getRowId={(m) => m.id}
  hiddenColumnIds={hiddenColumnIds}
  label="Members"
  onHiddenColumnIdsChange={setHiddenColumnIds}
  onSelectedIdsChange={setSelectedIds}
  onSortChange={setSort}
  rows={sortMembers(members, sort)}
  selectedIds={selectedIds}
  sort={sort}
/>

並べ替えとページを URL に持つ

@k8ordo/state の url スロットに並べ替えとページを置く例。並べ替えるとアドレスバーが変わり、リンクを渡した相手にも同じ並びの同じページが見え、戻るで前の並びに戻る。

Role
AokiDesigner3
InoueEngineer8
UedaEngineer5
tsx
// members-state.ts
export const membersState = definePageState('members', {
  url: z.object({
    sort: z._default(z.enum(['', 'name', 'projects']), ''),
    dir: z._default(z.enum(['ascending', 'descending']), 'ascending'),
    page: z._default(z.coerce.number().check(z.int(), z.gte(1)), 1),
  }),
});

// members-table.tsx
const [{ sort, dir, page }, update] = useAppState(membersState);
const current = sort === '' ? null : { columnId: sort, direction: dir };
const rows = sortMembers(members, current);

<DataTable
  columns={columns}
  getRowId={(m) => m.id}
  label="Members"
  onSortChange={(next) => {
    update(
      next === null
        ? { sort: '', dir: 'ascending', page: 1 }
        : { sort: next.columnId, dir: next.direction, page: 1 },
      { history: 'push' },
    );
  }}
  rows={rows.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE)}
  sort={current}
/>
<Pagination
  currentPage={page}
  onChange={(next) => update({ page: next }, { history: 'push' })}
  totalPages={Math.ceil(rows.length / PAGE_SIZE)}
/>

行が無いとき

rows が空のときは、emptyState を列をまたぐ行に描く。EmptyState を渡す。

NameRoleProjects

No members yet

tsx
<DataTable
  columns={columns}
  emptyState={<EmptyState title="No members yet" />}
  getRowId={(m) => m.id}
  label="Members"
  rows={[]}
/>

Props

columns
Type: ReadonlyArray<DataTableColumn<Row>>
Default: -
getRowId
Type: (row: Row) => string
Default: -
label
Type: string
Default: -
rows
Type: readonly Row[]
Default: -
emptyState?
Type: ReactNode
Default: -
hiddenColumnIds?
Type: readonly string[]
Default: NONE
onHiddenColumnIdsChange?
Type: (ids: string[]) => void
Default: -
onSelectedIdsChange?
Type: (ids: string[]) => void
Default: -
onSortChange?
Type: (sort: DataTableSort | null) => void
Default: -
selectedIds?
Type: readonly string[]
Default: NONE
sort?
Type: DataTableSort|null
Default: null

このコンポーネントが描画する文言(ラベルやプレースホルダーなど)は、propsで指定しないとき文言辞書から解決されます。差し替え方は次を参照してください: i18n