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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "feat: autocontrolled `useTable` hook",
"packageName": "@fluentui/react-table",
"email": "lingfangao@hotmail.com",
"dependentChangeType": "patch"
}
58 changes: 29 additions & 29 deletions packages/react-components/react-table/etc/react-table.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,31 +67,9 @@ export interface RowState<TItem> {
rowId: RowId;
}

// @public (undocumented)
export interface SelectionState {
allRowsSelected: boolean;
clearRows: () => void;
deselectRow: (rowId: RowId) => void;
isRowSelected: (rowId: RowId) => boolean;
selectedRows: RowId[];
selectRow: (rowId: RowId) => void;
someRowsSelected: boolean;
toggleAllRows: () => void;
toggleRow: (rowId: RowId) => void;
}

// @public (undocumented)
export type SortDirection = 'ascending' | 'descending';

// @public (undocumented)
export interface SortState {
getSortDirection: (columnId: ColumnId) => SortDirection | undefined;
setColumnSort: (columnId: ColumnId, sortDirection: SortDirection) => void;
sortColumn: ColumnId | undefined;
sortDirection: SortDirection;
toggleColumnSort: (columnId: ColumnId) => void;
}

// @public
export const Table: ForwardRefComponent<TableProps>;

Expand Down Expand Up @@ -240,13 +218,7 @@ export type TablePrimaryCellSlots = {
export type TablePrimaryCellState = ComponentState<TablePrimaryCellSlots>;

// @public
export type TableProps = ComponentProps<TableSlots> & {} & Partial<TableContextValue> & {
onSortColumnChange?: (e: React_2.MouseEvent<HTMLElement> | React_2.KeyboardEvent<HTMLElement>, data: {
sortState: SortState_2;
}) => void;
sortState?: SortState_2;
defaultSortState?: SortState_2;
};
export type TableProps = ComponentProps<TableSlots> & Partial<TableContextValue>;

// @public
export const TableRow: ForwardRefComponent<TableRowProps>;
Expand Down Expand Up @@ -291,11 +263,33 @@ export type TableSelectionCellSlots = {
// @public
export type TableSelectionCellState = ComponentState<TableSelectionCellSlots> & Pick<TableCellState, 'media'> & Pick<Required<TableSelectionCellProps>, 'type' | 'checked'>;

// @public (undocumented)
export interface TableSelectionState {
allRowsSelected: boolean;
clearRows: () => void;
deselectRow: (rowId: RowId) => void;
isRowSelected: (rowId: RowId) => boolean;
selectedRows: RowId[];
selectRow: (rowId: RowId) => void;
someRowsSelected: boolean;
toggleAllRows: () => void;
toggleRow: (rowId: RowId) => void;
}

// @public (undocumented)
export type TableSlots = {
root: Slot<'table', 'div'>;
};

// @public (undocumented)
export interface TableSortState {
getSortDirection: (columnId: ColumnId) => SortDirection | undefined;
setColumnSort: (columnId: ColumnId, sortDirection: SortDirection) => void;
sortColumn: ColumnId | undefined;
sortDirection: SortDirection;
toggleColumnSort: (columnId: ColumnId) => void;
}

// @public
export type TableState = ComponentState<TableSlots> & Pick<Required<TableProps>, 'size' | 'noNativeElements'> & TableContextValue;

Expand Down Expand Up @@ -342,14 +336,20 @@ export const useTableHeaderStyles_unstable: (state: TableHeaderState) => TableHe
export interface UseTableOptions<TItem, TRowState extends RowState<TItem> = RowState<TItem>> {
// (undocumented)
columns: ColumnDefinition<TItem>[];
defaultSelectedRows?: Set<RowId>;
defaultSortState?: SortState;
// (undocumented)
getRowId?: (item: TItem) => RowId;
// (undocumented)
items: TItem[];
onSelectionChange?: OnSelectionChangeCallback;
onSortChange?: OnSortChangeCallback;
// (undocumented)
rowEnhancer?: RowEnhancer<TItem, TRowState>;
selectedRows?: Set<RowId>;
// (undocumented)
selectionMode?: SelectionMode_2;
sortState?: SortState;
}

// @public
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities';
import * as React from 'react';

export type TableSlots = {
root: Slot<'table', 'div'>;
Expand All @@ -14,10 +13,6 @@ export type TableContextValue = {
};

export type SortDirection = 'ascending' | 'descending';
export type SortState = {
sortColumn: string | undefined;
sortDirection: 'ascending' | 'descending';
};

export type TableContextValues = {
table: TableContextValue;
Expand All @@ -26,19 +21,7 @@ export type TableContextValues = {
/**
* Table Props
*/
export type TableProps = ComponentProps<TableSlots> & {} & Partial<TableContextValue> & {
/**
* Called when the sorted column changes
*/
onSortColumnChange?: (
e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,
data: { sortState: SortState },
) => void;

sortState?: SortState;

defaultSortState?: SortState;
};
export type TableProps = ComponentProps<TableSlots> & Partial<TableContextValue>;

/**
* State used in rendering Table
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { SelectionMode } from './types';
type OnSelectionChangeCallback = (selectedItems: Set<SelectionItemId>) => void;

export interface SelectionManager {
toggleItem(id: SelectionItemId): void;
selectItem(id: SelectionItemId): void;
deselectItem(id: SelectionItemId): void;
toggleItem(id: SelectionItemId, selectedItems: Set<SelectionItemId>): void;
selectItem(id: SelectionItemId, selectedItems: Set<SelectionItemId>): void;
deselectItem(id: SelectionItemId, selectedItems: Set<SelectionItemId>): void;
clearItems(): void;
isSelected(id: SelectionItemId): boolean;
toggleAllItems(itemIds: SelectionItemId[]): void;
isSelected(id: SelectionItemId, selectedItems: Set<SelectionItemId>): boolean;
toggleAllItems(itemIds: SelectionItemId[], selectedItems: Set<SelectionItemId>): void;
}

export type SelectionItemId = string | number;
Expand All @@ -23,8 +23,7 @@ export function createSelectionManager(
}

function createMultipleSelectionManager(onSelectionChange: OnSelectionChangeCallback): SelectionManager {
const selectedItems = new Set<SelectionItemId>();
const toggleAllItems = (itemIds: SelectionItemId[]) => {
const toggleAllItems = (itemIds: SelectionItemId[], selectedItems: Set<SelectionItemId>) => {
const allItemsSelected = itemIds.every(itemId => selectedItems.has(itemId));

if (allItemsSelected) {
Expand All @@ -36,7 +35,7 @@ function createMultipleSelectionManager(onSelectionChange: OnSelectionChangeCall
onSelectionChange(new Set(selectedItems));
};

const toggleItem = (itemId: SelectionItemId) => {
const toggleItem = (itemId: SelectionItemId, selectedItems: Set<SelectionItemId>) => {
if (selectedItems.has(itemId)) {
selectedItems.delete(itemId);
} else {
Expand All @@ -46,22 +45,21 @@ function createMultipleSelectionManager(onSelectionChange: OnSelectionChangeCall
onSelectionChange(new Set(selectedItems));
};

const selectItem = (itemId: SelectionItemId) => {
const selectItem = (itemId: SelectionItemId, selectedItems: Set<SelectionItemId>) => {
selectedItems.add(itemId);
onSelectionChange(new Set(selectedItems));
};

const deselectItem = (itemId: SelectionItemId) => {
const deselectItem = (itemId: SelectionItemId, selectedItems: Set<SelectionItemId>) => {
selectedItems.delete(itemId);
onSelectionChange(new Set(selectedItems));
};

const clearItems = () => {
selectedItems.clear();
onSelectionChange(new Set(selectedItems));
onSelectionChange(new Set());
};

const isSelected = (itemId: SelectionItemId) => {
const isSelected = (itemId: SelectionItemId, selectedItems: Set<SelectionItemId>) => {
return selectedItems.has(itemId);
};

Expand All @@ -76,24 +74,20 @@ function createMultipleSelectionManager(onSelectionChange: OnSelectionChangeCall
}

function createSingleSelectionManager(onSelectionChange: OnSelectionChangeCallback): SelectionManager {
let selectedItem: SelectionItemId | undefined = undefined;
const toggleItem = (itemId: SelectionItemId) => {
selectedItem = itemId;
onSelectionChange(new Set([selectedItem]));
onSelectionChange(new Set([itemId]));
};

const clearItems = () => {
selectedItem = undefined;
onSelectionChange(new Set<SelectionItemId>());
};

const isSelected = (itemId: SelectionItemId) => {
return selectedItem === itemId;
const isSelected = (itemId: SelectionItemId, selectedItems: Set<SelectionItemId>) => {
return selectedItems.has(itemId);
};

const selectItem = (itemId: SelectionItemId) => {
selectedItem = itemId;
onSelectionChange(new Set([selectedItem]));
onSelectionChange(new Set([itemId]));
};

return {
Expand Down
45 changes: 38 additions & 7 deletions packages/react-components/react-table/src/hooks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ export type RowId = string | number;
export type ColumnId = string | number;
export type GetRowIdInternal<TItem> = (rowId: TItem, index: number) => RowId;
export type SelectionMode = 'single' | 'multiselect';
export type OnSelectionChangeCallback = (selectedItems: Set<RowId>) => void;
export type OnSortChangeCallback = (state: { sortColumn: ColumnId | undefined; sortDirection: SortDirection }) => void;

export interface SortState {
sortColumn: ColumnId | undefined;
sortDirection: SortDirection;
}

export interface ColumnDefinition<TItem> {
columnId: ColumnId;
Expand All @@ -12,10 +19,10 @@ export interface ColumnDefinition<TItem> {

export type RowEnhancer<TItem, TRowState extends RowState<TItem> = RowState<TItem>> = (
row: RowState<TItem>,
state: { selection: SelectionState; sort: SortState },
state: { selection: TableSelectionState; sort: TableSortState },
) => TRowState;

export interface SortStateInternal<TItem> {
export interface TableSortStateInternal<TItem> {
sortDirection: SortDirection;
sortColumn: ColumnId | undefined;
setColumnSort: (columnId: ColumnId, sortDirection: SortDirection) => void;
Expand All @@ -31,11 +38,35 @@ export interface UseTableOptions<TItem, TRowState extends RowState<TItem> = RowS
columns: ColumnDefinition<TItem>[];
items: TItem[];
selectionMode?: SelectionMode;
/**
* Used in uncontrolled mode to set initial selected rows on mount
*/
defaultSelectedRows?: Set<RowId>;
/**
* Used to control row selection
*/
selectedRows?: Set<RowId>;
/**
* Called when selection changes
*/
onSelectionChange?: OnSelectionChangeCallback;
/**
* Used to control sorting
*/
sortState?: SortState;
/**
* Used in uncontrolled mode to set initial sort column and direction on mount
*/
defaultSortState?: SortState;
/**
* Called when sort changes
*/
onSortChange?: OnSortChangeCallback;
getRowId?: (item: TItem) => RowId;
rowEnhancer?: RowEnhancer<TItem, TRowState>;
}

export interface SelectionStateInternal {
export interface TableSelectionStateInternal {
clearRows: () => void;
deselectRow: (rowId: RowId) => void;
selectRow: (rowId: RowId) => void;
Expand All @@ -47,7 +78,7 @@ export interface SelectionStateInternal {
someRowsSelected: boolean;
}

export interface SortState {
export interface TableSortState {
/**
* Current sort direction
*/
Expand All @@ -71,7 +102,7 @@ export interface SortState {
getSortDirection: (columnId: ColumnId) => SortDirection | undefined;
}

export interface SelectionState {
export interface TableSelectionState {
/**
* Clears all selected rows
*/
Expand Down Expand Up @@ -130,9 +161,9 @@ export interface TableState<TItem, TRowState extends RowState<TItem> = RowState<
/**
* State and actions to manage row selection
*/
selection: SelectionState;
selection: TableSelectionState;
/**
* State and actions to manage row sorting
*/
sort: SortState;
sort: TableSortState;
}
Loading