From f015dce5eb926d4b84ab3055036ac454a49c69a4 Mon Sep 17 00:00:00 2001 From: Matheus Wichman Date: Thu, 6 May 2021 20:46:47 -0300 Subject: [PATCH 1/3] [Autocomplete] Rename getOptionSelected to isOptionEqualToValue --- docs/pages/api-docs/autocomplete.json | 2 +- .../components/autocomplete/Asynchronous.js | 2 +- .../components/autocomplete/Asynchronous.tsx | 2 +- .../pages/guides/migration-v4/migration-v4.md | 2 ++ .../api-docs/autocomplete/autocomplete.json | 4 ++-- .../src/Autocomplete/Autocomplete.js | 24 +++++++++---------- .../src/Autocomplete/Autocomplete.test.js | 4 ++-- .../src/useAutocomplete/useAutocomplete.d.ts | 6 ++--- .../src/useAutocomplete/useAutocomplete.js | 22 ++++++++--------- 9 files changed, 35 insertions(+), 33 deletions(-) diff --git a/docs/pages/api-docs/autocomplete.json b/docs/pages/api-docs/autocomplete.json index d217be58fe2764..d208edcfcdf407 100644 --- a/docs/pages/api-docs/autocomplete.json +++ b/docs/pages/api-docs/autocomplete.json @@ -40,12 +40,12 @@ "type": { "name": "func" }, "default": "(option) => option.label ?? option" }, - "getOptionSelected": { "type": { "name": "func" } }, "groupBy": { "type": { "name": "func" } }, "handleHomeEndKeys": { "type": { "name": "bool" }, "default": "!props.freeSolo" }, "id": { "type": { "name": "string" } }, "includeInputInList": { "type": { "name": "bool" } }, "inputValue": { "type": { "name": "string" } }, + "isOptionEqualToValue": { "type": { "name": "func" } }, "limitTags": { "type": { "name": "custom", "description": "integer" }, "default": "-1" }, "ListboxComponent": { "type": { "name": "elementType" }, "default": "'ul'" }, "ListboxProps": { "type": { "name": "object" } }, diff --git a/docs/src/pages/components/autocomplete/Asynchronous.js b/docs/src/pages/components/autocomplete/Asynchronous.js index de74b3b847b14b..6d7e775a3d7442 100644 --- a/docs/src/pages/components/autocomplete/Asynchronous.js +++ b/docs/src/pages/components/autocomplete/Asynchronous.js @@ -52,7 +52,7 @@ export default function Asynchronous() { onClose={() => { setOpen(false); }} - getOptionSelected={(option, value) => option.title === value.title} + isOptionEqualToValue={(option, value) => option.title === value.title} getOptionLabel={(option) => option.title} options={options} loading={loading} diff --git a/docs/src/pages/components/autocomplete/Asynchronous.tsx b/docs/src/pages/components/autocomplete/Asynchronous.tsx index e99c328b206bfc..54c51f67ab50d3 100644 --- a/docs/src/pages/components/autocomplete/Asynchronous.tsx +++ b/docs/src/pages/components/autocomplete/Asynchronous.tsx @@ -57,7 +57,7 @@ export default function Asynchronous() { onClose={() => { setOpen(false); }} - getOptionSelected={(option, value) => option.title === value.title} + isOptionEqualToValue={(option, value) => option.title === value.title} getOptionLabel={(option) => option.title} options={options} loading={loading} diff --git a/docs/src/pages/guides/migration-v4/migration-v4.md b/docs/src/pages/guides/migration-v4/migration-v4.md index deb5cdaaf849bb..cc7ac03beeab20 100644 --- a/docs/src/pages/guides/migration-v4/migration-v4.md +++ b/docs/src/pages/guides/migration-v4/migration-v4.md @@ -405,6 +405,8 @@ As the core components use emotion as a styled engine, the props used by emotion + ``` +- Rename `getOptionSelected` to `isOptionEqualToValue` to better describe its purpose. + ### Avatar - Rename `circle` to `circular` for consistency. The possible values should be adjectives, not nouns: diff --git a/docs/translations/api-docs/autocomplete/autocomplete.json b/docs/translations/api-docs/autocomplete/autocomplete.json index e99c73796941ce..6b321a650c3f98 100644 --- a/docs/translations/api-docs/autocomplete/autocomplete.json +++ b/docs/translations/api-docs/autocomplete/autocomplete.json @@ -27,12 +27,12 @@ "getLimitTagsText": "The label to display when the tags are truncated (limitTags).

Signature:
function(more: number) => ReactNode
more: The number of truncated tags.", "getOptionDisabled": "Used to determine the disabled state for a given option.

Signature:
function(option: T) => boolean
option: The option to test.", "getOptionLabel": "Used to determine the string value for a given option. It's used to fill the input (and the list box options if renderOption is not provided).

Signature:
function(option: T) => string
", - "getOptionSelected": "Used to determine if an option is selected, considering the current value(s). Uses strict equality by default. ⚠️ Both arguments need to be handled, an option can only match with one value.

Signature:
function(option: T, value: T) => boolean
option: The option to test.
value: The value to test against.", "groupBy": "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.

Signature:
function(options: T) => string
options: The options to group.", "handleHomeEndKeys": "If true, the component handles the "Home" and "End" keys when the popup is open. It should move focus to the first option and last option, respectively.", "id": "This prop is used to help implement the accessibility logic. If you don't provide an id it will fall back to a randomly generated one.", "includeInputInList": "If true, the highlight can move to the input.", "inputValue": "The input value.", + "isOptionEqualToValue": "Used to determine if the option represents the given value. Uses strict equality by default. ⚠️ Both arguments need to be handled, an option can only match with one value.

Signature:
function(option: T, value: T) => boolean
option: The option to test.
value: The value to test against.", "limitTags": "The maximum number of tags that will be visible when not focused. Set -1 to disable the limit.", "ListboxComponent": "The component used to render the listbox.", "ListboxProps": "Props applied to the Listbox element.", @@ -59,7 +59,7 @@ "selectOnFocus": "If true, the input's text is selected on focus. It helps the user clear the selected value.", "size": "The size of the component.", "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.", - "value": "The value of the autocomplete.
The value must have reference equality with the option in order to be selected. You can customize the equality behavior with the getOptionSelected prop." + "value": "The value of the autocomplete.
The value must have reference equality with the option in order to be selected. You can customize the equality behavior with the isOptionEqualToValue prop." }, "classDescriptions": { "root": { "description": "Styles applied to the root element." }, diff --git a/packages/material-ui/src/Autocomplete/Autocomplete.js b/packages/material-ui/src/Autocomplete/Autocomplete.js index 31bde4c434f58f..7db99d486b5547 100644 --- a/packages/material-ui/src/Autocomplete/Autocomplete.js +++ b/packages/material-ui/src/Autocomplete/Autocomplete.js @@ -436,7 +436,7 @@ const Autocomplete = React.forwardRef(function Autocomplete(inProps, ref) { getLimitTagsText = (more) => `+${more}`, getOptionDisabled, getOptionLabel = (option) => option.label ?? option, - getOptionSelected, + isOptionEqualToValue, groupBy, handleHomeEndKeys = !props.freeSolo, id: idProp, @@ -853,16 +853,6 @@ Autocomplete.propTypes /* remove-proptypes */ = { * @default (option) => option.label ?? option */ getOptionLabel: PropTypes.func, - /** - * Used to determine if an option is selected, considering the current value(s). - * Uses strict equality by default. - * ⚠️ Both arguments need to be handled, an option can only match with one value. - * - * @param {T} option The option to test. - * @param {T} value The value to test against. - * @returns {boolean} - */ - getOptionSelected: PropTypes.func, /** * 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. @@ -891,6 +881,16 @@ Autocomplete.propTypes /* remove-proptypes */ = { * The input value. */ inputValue: PropTypes.string, + /** + * Used to determine if the option represents the given value. + * Uses strict equality by default. + * ⚠️ Both arguments need to be handled, an option can only match with one value. + * + * @param {T} option The option to test. + * @param {T} value The value to test against. + * @returns {boolean} + */ + isOptionEqualToValue: PropTypes.func, /** * The maximum number of tags that will be visible when not focused. * Set `-1` to disable the limit. @@ -1058,7 +1058,7 @@ Autocomplete.propTypes /* remove-proptypes */ = { * The value of the autocomplete. * * The value must have reference equality with the option in order to be selected. - * You can customize the equality behavior with the `getOptionSelected` prop. + * You can customize the equality behavior with the `isOptionEqualToValue` prop. */ value: chainPropTypes(PropTypes.any, (props) => { if (props.multiple && props.value !== undefined && !Array.isArray(props.value)) { diff --git a/packages/material-ui/src/Autocomplete/Autocomplete.test.js b/packages/material-ui/src/Autocomplete/Autocomplete.test.js index 6aed4a0841ddb3..9b85e41ab04239 100644 --- a/packages/material-ui/src/Autocomplete/Autocomplete.test.js +++ b/packages/material-ui/src/Autocomplete/Autocomplete.test.js @@ -1237,7 +1237,7 @@ describe('', () => { expect(handleChange.args[0][1]).to.equal('a'); }); - it('warn if getOptionSelected match multiple values for a given option', () => { + it('warn if isOptionEqualToValue match multiple values for a given option', () => { const value = [ { id: '10', text: 'One' }, { id: '20', text: 'Two' }, @@ -1254,7 +1254,7 @@ describe('', () => { options={options} value={value} getOptionLabel={(option) => option.text} - getOptionSelected={(option) => value.find((v) => v.id === option.id)} + isOptionEqualToValue={(option) => value.find((v) => v.id === option.id)} renderInput={(params) => } />, ); diff --git a/packages/material-ui/src/useAutocomplete/useAutocomplete.d.ts b/packages/material-ui/src/useAutocomplete/useAutocomplete.d.ts index b363af17d78bbb..deb717b0d2132f 100644 --- a/packages/material-ui/src/useAutocomplete/useAutocomplete.d.ts +++ b/packages/material-ui/src/useAutocomplete/useAutocomplete.d.ts @@ -140,7 +140,7 @@ export interface UseAutocompleteProps< */ getOptionLabel?: (option: T) => string; /** - * Used to determine if an option is selected, considering the current value(s). + * Used to determine if the option represents the given value. * Uses strict equality by default. * ⚠️ Both arguments need to be handled, an option can only match with one value. * @@ -148,7 +148,7 @@ export interface UseAutocompleteProps< * @param {T} value The value to test against. * @returns {boolean} */ - getOptionSelected?: (option: T, value: T) => boolean; + isOptionEqualToValue?: (option: T, value: T) => boolean; /** * 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. @@ -244,7 +244,7 @@ export interface UseAutocompleteProps< * The value of the autocomplete. * * The value must have reference equality with the option in order to be selected. - * You can customize the equality behavior with the `getOptionSelected` prop. + * You can customize the equality behavior with the `isOptionEqualToValue` prop. */ value?: Value; /** diff --git a/packages/material-ui/src/useAutocomplete/useAutocomplete.js b/packages/material-ui/src/useAutocomplete/useAutocomplete.js index 01b3f265027e12..861c52cc968a47 100644 --- a/packages/material-ui/src/useAutocomplete/useAutocomplete.js +++ b/packages/material-ui/src/useAutocomplete/useAutocomplete.js @@ -80,7 +80,7 @@ export default function useAutocomplete(props) { freeSolo = false, getOptionDisabled, getOptionLabel: getOptionLabelProp = (option) => option.label ?? option, - getOptionSelected = (option, value) => option === value, + isOptionEqualToValue = (option, value) => option === value, groupBy, handleHomeEndKeys = !props.freeSolo, id: idProp, @@ -190,7 +190,7 @@ export default function useAutocomplete(props) { if ( filterSelectedOptions && (multiple ? value : [value]).some( - (value2) => value2 !== null && getOptionSelected(option, value2), + (value2) => value2 !== null && isOptionEqualToValue(option, value2), ) ) { return false; @@ -211,7 +211,7 @@ export default function useAutocomplete(props) { if (process.env.NODE_ENV !== 'production') { if (value !== null && !freeSolo && options.length > 0) { const missingValue = (multiple ? value : [value]).filter( - (value2) => !options.some((option) => getOptionSelected(option, value2)), + (value2) => !options.some((option) => isOptionEqualToValue(option, value2)), ); if (missingValue.length > 0) { @@ -223,7 +223,7 @@ export default function useAutocomplete(props) { ? JSON.stringify(missingValue) : JSON.stringify(missingValue[0]) }\`.`, - 'You can use the `getOptionSelected` prop to customize the equality test.', + 'You can use the `isOptionEqualToValue` prop to customize the equality test.', ].join('\n'), ); } @@ -443,13 +443,13 @@ export default function useAutocomplete(props) { if ( multiple && currentOption && - findIndex(value, (val) => getOptionSelected(currentOption, val)) !== -1 + findIndex(value, (val) => isOptionEqualToValue(currentOption, val)) !== -1 ) { return; } const itemIndex = findIndex(filteredOptions, (optionItem) => - getOptionSelected(optionItem, valueItem), + isOptionEqualToValue(optionItem, valueItem), ); if (itemIndex === -1) { changeHighlightedIndex({ diff: 'reset' }); @@ -467,7 +467,7 @@ export default function useAutocomplete(props) { // Restore the focus to the previous index. setHighlightedIndex({ index: highlightedIndexRef.current }); - // Ignore filteredOptions (and options, getOptionSelected, getOptionLabel) not to break the scroll position + // Ignore filteredOptions (and options, isOptionEqualToValue, getOptionLabel) not to break the scroll position // eslint-disable-next-line react-hooks/exhaustive-deps }, [ // Only sync the highlighted index when the option switch between empty and not @@ -562,19 +562,19 @@ export default function useAutocomplete(props) { newValue = Array.isArray(value) ? value.slice() : []; if (process.env.NODE_ENV !== 'production') { - const matches = newValue.filter((val) => getOptionSelected(option, val)); + const matches = newValue.filter((val) => isOptionEqualToValue(option, val)); if (matches.length > 1) { console.error( [ - `Material-UI: The \`getOptionSelected\` method of ${componentName} do not handle the arguments correctly.`, + `Material-UI: The \`isOptionEqualToValue\` method of ${componentName} do not handle the arguments correctly.`, `The component expects a single value to match a given option but found ${matches.length} matches.`, ].join('\n'), ); } } - const itemIndex = findIndex(newValue, (valueItem) => getOptionSelected(option, valueItem)); + const itemIndex = findIndex(newValue, (valueItem) => isOptionEqualToValue(option, valueItem)); if (itemIndex === -1) { newValue.push(option); @@ -1018,7 +1018,7 @@ export default function useAutocomplete(props) { }), getOptionProps: ({ index, option }) => { const selected = (multiple ? value : [value]).some( - (value2) => value2 != null && getOptionSelected(option, value2), + (value2) => value2 != null && isOptionEqualToValue(option, value2), ); const disabled = getOptionDisabled ? getOptionDisabled(option) : false; From 9f2ee62515a1e04dfbca89ea423412755932b180 Mon Sep 17 00:00:00 2001 From: Matheus Wichman Date: Wed, 12 May 2021 09:49:07 -0300 Subject: [PATCH 2/3] prettier --- docs/src/pages/guides/migration-v4/migration-v4.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/pages/guides/migration-v4/migration-v4.md b/docs/src/pages/guides/migration-v4/migration-v4.md index 8e611a84de41a3..755908c00cfeb4 100644 --- a/docs/src/pages/guides/migration-v4/migration-v4.md +++ b/docs/src/pages/guides/migration-v4/migration-v4.md @@ -424,6 +424,7 @@ As the core components use emotion as a styled engine, the props used by emotion option.title === value.title} + isOptionEqualToValue={(option, value) => option.title === value.title} + ``` ### Avatar From 9089962d957b45ac60077006e8e63c9cbf47763b Mon Sep 17 00:00:00 2001 From: Matheus Wichman Date: Wed, 12 May 2021 09:59:28 -0300 Subject: [PATCH 3/3] rerun ci