feat(ui): rename filter and search state handlers to onChange
Standardize the naming convention for state change handlers in
FilterState and SearchState interfaces:
- FilterState: `onFilterChange` → `onChange`
- SearchState: `onSearchChange` → `onChange`
This aligns with React conventions and makes spreading props
directly onto form components cleaner (e.g., `{...search}`).
Also adds a runtime check to ensure useTable mode remains stable
for the component lifetime.
Signed-off-by: Johan Persson <johanopersson@gmail.com>
This commit is contained in:
@@ -679,7 +679,7 @@ export interface FieldLabelProps
|
||||
// @public (undocumented)
|
||||
export interface FilterState<TFilter> {
|
||||
// (undocumented)
|
||||
onFilterChange: (filter: TFilter) => void;
|
||||
onChange: (value: TFilter) => void;
|
||||
// (undocumented)
|
||||
value: TFilter | undefined;
|
||||
}
|
||||
@@ -1258,7 +1258,7 @@ export interface SearchFieldProps
|
||||
// @public (undocumented)
|
||||
export interface SearchState {
|
||||
// (undocumented)
|
||||
onSearchChange: (value: string) => void;
|
||||
onChange: (value: string) => void;
|
||||
// (undocumented)
|
||||
value: string;
|
||||
}
|
||||
|
||||
@@ -20,13 +20,13 @@ import type { SortDescriptor, TableItem, TableProps } from '../types';
|
||||
/** @public */
|
||||
export interface FilterState<TFilter> {
|
||||
value: TFilter | undefined;
|
||||
onFilterChange: (filter: TFilter) => void;
|
||||
onChange: (value: TFilter) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export interface SearchState {
|
||||
value: string;
|
||||
onSearchChange: (value: string) => void;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
|
||||
/** @public */
|
||||
|
||||
@@ -98,9 +98,16 @@ export function useTable<T extends TableItem, TFilter = unknown>(
|
||||
): UseTableResult<T, TFilter> {
|
||||
const query = useQueryState<TFilter>(options);
|
||||
|
||||
const initialModeRef = useRef(options.mode);
|
||||
if (initialModeRef.current !== options.mode) {
|
||||
throw new Error(
|
||||
`useTable mode cannot change from '${initialModeRef.current}' to '${options.mode}'. ` +
|
||||
`The mode must remain stable for the lifetime of the component.`,
|
||||
);
|
||||
}
|
||||
|
||||
let pagination: PaginationResult<T> & { reload: () => void };
|
||||
|
||||
// Conditional hooks - mode is stable for lifetime of component
|
||||
if (options.mode === 'complete') {
|
||||
pagination = useCompletePagination(options, query);
|
||||
} else if (options.mode === 'offset') {
|
||||
@@ -125,7 +132,7 @@ export function useTable<T extends TableItem, TFilter = unknown>(
|
||||
return {
|
||||
tableProps,
|
||||
reload: pagination.reload,
|
||||
filter: { value: query.filter, onFilterChange: query.setFilter },
|
||||
search: { value: query.search, onSearchChange: query.setSearch },
|
||||
filter: { value: query.filter, onChange: query.setFilter },
|
||||
search: { value: query.search, onChange: query.setSearch },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@ import {
|
||||
type ColumnConfig,
|
||||
} from '..';
|
||||
import { Button } from '../../Button';
|
||||
import { TextField } from '../../TextField';
|
||||
import { Select } from '../../Select';
|
||||
import { Flex } from '../../Flex';
|
||||
import { data as data1 } from './mocked-data1';
|
||||
import { data as data4 } from './mocked-data4';
|
||||
import { selectionData, selectionColumns, tableStoriesMeta } from './utils';
|
||||
import { SearchField } from '../../SearchField';
|
||||
|
||||
const meta = {
|
||||
title: 'Backstage UI/Table/dev',
|
||||
@@ -186,12 +186,11 @@ export const Search: Story = {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TextField
|
||||
<SearchField
|
||||
aria-label="Search"
|
||||
placeholder="Search..."
|
||||
value={search.value}
|
||||
onChange={value => search.onSearchChange(value)}
|
||||
style={{ marginBottom: '16px' }}
|
||||
{...search}
|
||||
/>
|
||||
<Table
|
||||
columnConfig={columns}
|
||||
@@ -924,20 +923,19 @@ export const ComprehensiveServerSide: Story = {
|
||||
return (
|
||||
<Flex direction="column" gap="4">
|
||||
<Flex gap="4" align="end">
|
||||
<TextField
|
||||
<SearchField
|
||||
aria-label="Search"
|
||||
label="Search"
|
||||
placeholder="Search by name, owner, or description..."
|
||||
value={search.value}
|
||||
onChange={search.onSearchChange}
|
||||
style={{ width: 300 }}
|
||||
{...search}
|
||||
/>
|
||||
<Select
|
||||
label="Type"
|
||||
options={typeOptions}
|
||||
selectedKey={filter.value?.type ?? ''}
|
||||
onSelectionChange={key =>
|
||||
filter.onFilterChange({ type: key === '' ? null : String(key) })
|
||||
value={filter.value?.type ?? ''}
|
||||
onChange={key =>
|
||||
filter.onChange({ type: key === '' ? null : String(key) })
|
||||
}
|
||||
style={{ width: 180 }}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user