Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[useAutocomplete] Improve TS typing of groupedOptions prop #44657

Merged
merged 16 commits into from
Dec 18, 2024
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
@@ -1,6 +1,6 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { useAutocomplete } from '@mui/base/useAutocomplete';
import useAutocomplete from '@mui/material/useAutocomplete';
import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close';
import { styled } from '@mui/material/styles';
Expand Down
6 changes: 4 additions & 2 deletions docs/data/material/components/autocomplete/CustomizedHook.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as React from 'react';
import { useAutocomplete, AutocompleteGetTagProps } from '@mui/base/useAutocomplete';
import useAutocomplete, {
AutocompleteGetTagProps,
} from '@mui/material/useAutocomplete';
import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close';
import { styled } from '@mui/material/styles';
Expand Down Expand Up @@ -188,7 +190,7 @@ export default function CustomizedHook() {
</div>
{groupedOptions.length > 0 ? (
<Listbox {...getListboxProps()}>
{(groupedOptions as typeof top100Films).map((option, index) => {
{groupedOptions.map((option, index) => {
const { key, ...optionProps } = getOptionProps({ option, index });
return (
<li key={key} {...optionProps}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { useAutocomplete } from '@mui/base/useAutocomplete';
import useAutocomplete from '@mui/material/useAutocomplete';
import { styled } from '@mui/system';

const Label = styled('label')({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { useAutocomplete } from '@mui/base/useAutocomplete';
import useAutocomplete from '@mui/material/useAutocomplete';
import { styled } from '@mui/system';

const Label = styled('label')({
Expand Down Expand Up @@ -63,7 +63,7 @@ export default function UseAutocomplete() {
</div>
{groupedOptions.length > 0 ? (
<Listbox {...getListboxProps()}>
{(groupedOptions as typeof top100Films).map((option, index) => {
{groupedOptions.map((option, index) => {
const { key, ...optionProps } = getOptionProps({ option, index });
return (
<li key={key} {...optionProps}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</div>
{groupedOptions.length > 0 ? (
<Listbox {...getListboxProps()}>
{(groupedOptions as typeof top100Films).map((option, index) => {
{groupedOptions.map((option, index) => {
const { key, ...optionProps } = getOptionProps({ option, index });
return (
<li key={key} {...optionProps}>
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/material-ui/api/autocomplete.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
},
"groupBy": {
"type": { "name": "func" },
"signature": { "type": "function(options: Value) => string", "describedArgs": ["options"] }
"signature": { "type": "function(option: Value) => string", "describedArgs": ["option"] }
},
"handleHomeEndKeys": { "type": { "name": "bool" }, "default": "!props.freeSolo" },
"id": { "type": { "name": "string" } },
Expand Down
2 changes: 1 addition & 1 deletion docs/translations/api-docs/autocomplete/autocomplete.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
},
"groupBy": {
"description": "If provided, the options will be grouped under the returned string. The groupBy value is also used as the text for group headings when <code>renderGroup</code> is not provided.",
"typeDescriptions": { "options": "The options to group." }
"typeDescriptions": { "option": "The Autocomplete option." }
},
"handleHomeEndKeys": {
"description": "If <code>true</code>, the component handles the &quot;Home&quot; and &quot;End&quot; keys when the popup is open. It should move focus to the first option and last option, respectively."
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-material/src/Autocomplete/Autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,7 @@ Autocomplete.propTypes /* remove-proptypes */ = {
* If provided, the options will be grouped under the returned string.
* The groupBy value is also used as the text for group headings when `renderGroup` is not provided.
*
* @param {Value} options The options to group.
* @param {Value} option The Autocomplete option.
* @returns {string}
*/
groupBy: PropTypes.func,
Expand Down
25 changes: 20 additions & 5 deletions packages/mui-material/src/useAutocomplete/useAutocomplete.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import { PartiallyRequired } from '@mui/types';

export interface CreateFilterOptionsConfig<Value> {
ignoreAccents?: boolean;
Expand Down Expand Up @@ -178,7 +179,7 @@ export interface UseAutocompleteProps<
* If provided, the options will be grouped under the returned string.
* The groupBy value is also used as the text for group headings when `renderGroup` is not provided.
*
* @param {Value} options The options to group.
* @param {Value} option The Autocomplete option.
* @returns {string}
*/
groupBy?: (option: Value) => string;
Expand Down Expand Up @@ -359,8 +360,19 @@ export function useAutocomplete<
DisableClearable extends boolean | undefined = false,
FreeSolo extends boolean | undefined = false,
>(
props: UseAutocompleteProps<Value, Multiple, DisableClearable, FreeSolo>,
): UseAutocompleteReturnValue<Value, Multiple, DisableClearable, FreeSolo>;
props: PartiallyRequired<
UseAutocompleteProps<Value, Multiple, DisableClearable, FreeSolo>,
'groupBy'
>,
): UseAutocompleteReturnValue<Value, Multiple, DisableClearable, FreeSolo, true>;
export function useAutocomplete<
Value,
Multiple extends boolean | undefined = false,
DisableClearable extends boolean | undefined = false,
FreeSolo extends boolean | undefined = false,
>(
props: Omit<UseAutocompleteProps<Value, Multiple, DisableClearable, FreeSolo>, 'groupBy'>,
): UseAutocompleteReturnValue<Value, Multiple, DisableClearable, FreeSolo, false>;

export interface UseAutocompleteRenderedOption<Value> {
option: Value;
Expand All @@ -372,6 +384,7 @@ export interface UseAutocompleteReturnValue<
Multiple extends boolean | undefined = false,
DisableClearable extends boolean | undefined = false,
FreeSolo extends boolean | undefined = false,
HasGroupBy extends boolean = false,
> {
/**
* Resolver for the root slot's props.
Expand Down Expand Up @@ -460,9 +473,11 @@ export interface UseAutocompleteReturnValue<
*/
focusedTag: number;
/**
* The options to render. It's either `Value[]` or `AutocompleteGroupedOption<Value>[]` if the groupBy prop is provided.
* The options to render.
* - If `groupBy` is provided, the options are grouped and represented as `AutocompleteGroupedOption<Value>[]`.
* - Otherwise, the options are represented as a flat array of `Value[]`.
*/
groupedOptions: Value[] | Array<AutocompleteGroupedOption<Value>>;
groupedOptions: HasGroupBy extends true ? AutocompleteGroupedOption<Value>[] : Value[];
}

export default useAutocomplete;
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { expectType } from '@mui/types';
import { useAutocomplete, FilterOptionsState } from '@mui/material/useAutocomplete';
import {
useAutocomplete,
FilterOptionsState,
AutocompleteGroupedOption,
} from '@mui/material/useAutocomplete';

interface Person {
id: string;
Expand Down Expand Up @@ -181,4 +185,17 @@ function Component() {
},
freeSolo: true,
});

const ungroupedAutocomplete = useAutocomplete({ options: persons });
expectType<Person[], typeof ungroupedAutocomplete.groupedOptions>(
ungroupedAutocomplete.groupedOptions,
);

const groupedAutocomplete = useAutocomplete({
options: persons,
groupBy: ({ id }) => id,
});
expectType<AutocompleteGroupedOption<Person>[], typeof groupedAutocomplete.groupedOptions>(
groupedAutocomplete.groupedOptions,
);
}
Loading