diff --git a/docs/pages/api/autocomplete.md b/docs/pages/api/autocomplete.md index 5084808b95ec06..1ffa03c5ef1e6a 100644 --- a/docs/pages/api/autocomplete.md +++ b/docs/pages/api/autocomplete.md @@ -73,7 +73,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi | renderInput * | func | | Render the input.

**Signature:**
`function(params: object) => ReactNode`
*params:* null | | renderOption | func | | Render the option, use `getOptionLabel` by default.

**Signature:**
`function(option: T, state: object) => ReactNode`
*option:* The option to render.
*state:* The state of the component. | | renderTags | func | | Render the selected value.

**Signature:**
`function(value: undefined, getTagProps: function) => ReactNode`
*value:* The `value` provided to the component.
*getTagProps:* A tag props getter. | -| selectOnFocus | bool | !props.freeSolo | If `true`, the input's text will be selected on focus. | +| selectOnFocus | bool | !props.freeSolo | If `true`, the input's text will be selected on focus. It helps the user clearning the selected value. | | size | 'medium'
| 'small'
| 'medium' | The size of the autocomplete. | | value | any
| array
| | 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. | diff --git a/docs/src/pages/components/autocomplete/CustomizedHook.js b/docs/src/pages/components/autocomplete/CustomizedHook.js index 219b9456a328dd..bd5dbaf1da4043 100644 --- a/docs/src/pages/components/autocomplete/CustomizedHook.js +++ b/docs/src/pages/components/autocomplete/CustomizedHook.js @@ -1,6 +1,7 @@ /* eslint-disable no-use-before-define */ import React from 'react'; import useAutocomplete from '@material-ui/lab/useAutocomplete'; +import NoSsr from '@material-ui/core/NoSsr'; import CheckIcon from '@material-ui/icons/Check'; import CloseIcon from '@material-ui/icons/Close'; import styled from 'styled-components'; @@ -146,28 +147,30 @@ export default function CustomizedHook() { }); return ( -
-
- - - {value.map((option, index) => ( - - ))} + +
+
+ + + {value.map((option, index) => ( + + ))} - - + + +
+ {groupedOptions.length > 0 ? ( + + {groupedOptions.map((option, index) => ( +
  • + {option.title} + +
  • + ))} +
    + ) : null}
    - {groupedOptions.length > 0 ? ( - - {groupedOptions.map((option, index) => ( -
  • - {option.title} - -
  • - ))} -
    - ) : null} -
    + ); } diff --git a/docs/src/pages/components/autocomplete/CustomizedHook.tsx b/docs/src/pages/components/autocomplete/CustomizedHook.tsx index c2d4db38691799..c19c9d8411dbae 100644 --- a/docs/src/pages/components/autocomplete/CustomizedHook.tsx +++ b/docs/src/pages/components/autocomplete/CustomizedHook.tsx @@ -1,6 +1,7 @@ /* eslint-disable no-use-before-define */ import React from 'react'; import useAutocomplete from '@material-ui/lab/useAutocomplete'; +import NoSsr from '@material-ui/core/NoSsr'; import CheckIcon from '@material-ui/icons/Check'; import CloseIcon from '@material-ui/icons/Close'; import styled from 'styled-components'; @@ -146,27 +147,29 @@ export default function CustomizedHook() { }); return ( -
    -
    - - - {value.map((option: FilmOptionType, index: number) => ( - - ))} - - + +
    +
    + + + {value.map((option: FilmOptionType, index: number) => ( + + ))} + + +
    + {groupedOptions.length > 0 ? ( + + {groupedOptions.map((option, index) => ( +
  • + {option.title} + +
  • + ))} +
    + ) : null}
    - {groupedOptions.length > 0 ? ( - - {groupedOptions.map((option, index) => ( -
  • - {option.title} - -
  • - ))} -
    - ) : null} -
    + ); } diff --git a/docs/src/pages/components/autocomplete/FreeSoloCreateOption.js b/docs/src/pages/components/autocomplete/FreeSoloCreateOption.js new file mode 100644 index 00000000000000..3aa9a6b2bfa1c1 --- /dev/null +++ b/docs/src/pages/components/autocomplete/FreeSoloCreateOption.js @@ -0,0 +1,164 @@ +/* eslint-disable no-use-before-define */ +import React from 'react'; +import TextField from '@material-ui/core/TextField'; +import Autocomplete, { createFilterOptions } from '@material-ui/lab/Autocomplete'; + +const filter = createFilterOptions(); + +export default function FreeSoloCreateOption() { + const [value, setValue] = React.useState(null); + + return ( + { + if (newValue && newValue.inputValue) { + setValue({ + title: newValue.inputValue, + }); + + return; + } + + setValue(newValue); + }} + filterOptions={(options, params) => { + const filtered = filter(options, params); + + if (params.inputValue !== '') { + filtered.push({ + inputValue: params.inputValue, + title: `Add "${params.inputValue}"`, + }); + } + + return filtered; + }} + id="free-solo-with-text-demo" + options={top100Films} + getOptionLabel={option => { + // e.g value selected with enter, right from the input + if (typeof option === 'string') { + return option; + } + if (option.inputValue) { + return option.inputValue; + } + return option.title; + }} + renderOption={option => option.title} + style={{ width: 300 }} + freeSolo + renderInput={params => ( + + )} + /> + ); +} + +// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top +const top100Films = [ + { title: 'The Shawshank Redemption', year: 1994 }, + { title: 'The Godfather', year: 1972 }, + { title: 'The Godfather: Part II', year: 1974 }, + { title: 'The Dark Knight', year: 2008 }, + { title: '12 Angry Men', year: 1957 }, + { title: "Schindler's List", year: 1993 }, + { title: 'Pulp Fiction', year: 1994 }, + { title: 'The Lord of the Rings: The Return of the King', year: 2003 }, + { title: 'The Good, the Bad and the Ugly', year: 1966 }, + { title: 'Fight Club', year: 1999 }, + { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 }, + { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 }, + { title: 'Forrest Gump', year: 1994 }, + { title: 'Inception', year: 2010 }, + { title: 'The Lord of the Rings: The Two Towers', year: 2002 }, + { title: "One Flew Over the Cuckoo's Nest", year: 1975 }, + { title: 'Goodfellas', year: 1990 }, + { title: 'The Matrix', year: 1999 }, + { title: 'Seven Samurai', year: 1954 }, + { title: 'Star Wars: Episode IV - A New Hope', year: 1977 }, + { title: 'City of God', year: 2002 }, + { title: 'Se7en', year: 1995 }, + { title: 'The Silence of the Lambs', year: 1991 }, + { title: "It's a Wonderful Life", year: 1946 }, + { title: 'Life Is Beautiful', year: 1997 }, + { title: 'The Usual Suspects', year: 1995 }, + { title: 'Léon: The Professional', year: 1994 }, + { title: 'Spirited Away', year: 2001 }, + { title: 'Saving Private Ryan', year: 1998 }, + { title: 'Once Upon a Time in the West', year: 1968 }, + { title: 'American History X', year: 1998 }, + { title: 'Interstellar', year: 2014 }, + { title: 'Casablanca', year: 1942 }, + { title: 'City Lights', year: 1931 }, + { title: 'Psycho', year: 1960 }, + { title: 'The Green Mile', year: 1999 }, + { title: 'The Intouchables', year: 2011 }, + { title: 'Modern Times', year: 1936 }, + { title: 'Raiders of the Lost Ark', year: 1981 }, + { title: 'Rear Window', year: 1954 }, + { title: 'The Pianist', year: 2002 }, + { title: 'The Departed', year: 2006 }, + { title: 'Terminator 2: Judgment Day', year: 1991 }, + { title: 'Back to the Future', year: 1985 }, + { title: 'Whiplash', year: 2014 }, + { title: 'Gladiator', year: 2000 }, + { title: 'Memento', year: 2000 }, + { title: 'The Prestige', year: 2006 }, + { title: 'The Lion King', year: 1994 }, + { title: 'Apocalypse Now', year: 1979 }, + { title: 'Alien', year: 1979 }, + { title: 'Sunset Boulevard', year: 1950 }, + { + title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', + year: 1964, + }, + { title: 'The Great Dictator', year: 1940 }, + { title: 'Cinema Paradiso', year: 1988 }, + { title: 'The Lives of Others', year: 2006 }, + { title: 'Grave of the Fireflies', year: 1988 }, + { title: 'Paths of Glory', year: 1957 }, + { title: 'Django Unchained', year: 2012 }, + { title: 'The Shining', year: 1980 }, + { title: 'WALL·E', year: 2008 }, + { title: 'American Beauty', year: 1999 }, + { title: 'The Dark Knight Rises', year: 2012 }, + { title: 'Princess Mononoke', year: 1997 }, + { title: 'Aliens', year: 1986 }, + { title: 'Oldboy', year: 2003 }, + { title: 'Once Upon a Time in America', year: 1984 }, + { title: 'Witness for the Prosecution', year: 1957 }, + { title: 'Das Boot', year: 1981 }, + { title: 'Citizen Kane', year: 1941 }, + { title: 'North by Northwest', year: 1959 }, + { title: 'Vertigo', year: 1958 }, + { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 }, + { title: 'Reservoir Dogs', year: 1992 }, + { title: 'Braveheart', year: 1995 }, + { title: 'M', year: 1931 }, + { title: 'Requiem for a Dream', year: 2000 }, + { title: 'Amélie', year: 2001 }, + { title: 'A Clockwork Orange', year: 1971 }, + { title: 'Like Stars on Earth', year: 2007 }, + { title: 'Taxi Driver', year: 1976 }, + { title: 'Lawrence of Arabia', year: 1962 }, + { title: 'Double Indemnity', year: 1944 }, + { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 }, + { title: 'Amadeus', year: 1984 }, + { title: 'To Kill a Mockingbird', year: 1962 }, + { title: 'Toy Story 3', year: 2010 }, + { title: 'Logan', year: 2017 }, + { title: 'Full Metal Jacket', year: 1987 }, + { title: 'Dangal', year: 2016 }, + { title: 'The Sting', year: 1973 }, + { title: '2001: A Space Odyssey', year: 1968 }, + { title: "Singin' in the Rain", year: 1952 }, + { title: 'Toy Story', year: 1995 }, + { title: 'Bicycle Thieves', year: 1948 }, + { title: 'The Kid', year: 1921 }, + { title: 'Inglourious Basterds', year: 2009 }, + { title: 'Snatch', year: 2000 }, + { title: '3 Idiots', year: 2009 }, + { title: 'Monty Python and the Holy Grail', year: 1975 }, +]; diff --git a/docs/src/pages/components/autocomplete/FreeSoloCreateOption.tsx b/docs/src/pages/components/autocomplete/FreeSoloCreateOption.tsx new file mode 100644 index 00000000000000..0323feffd3559d --- /dev/null +++ b/docs/src/pages/components/autocomplete/FreeSoloCreateOption.tsx @@ -0,0 +1,169 @@ +/* eslint-disable no-use-before-define */ +import React from 'react'; +import TextField from '@material-ui/core/TextField'; +import Autocomplete, { createFilterOptions } from '@material-ui/lab/Autocomplete'; + +const filter = createFilterOptions(); + +export default function FreeSoloCreateOption() { + const [value, setValue] = React.useState(null); + + return ( + { + if (newValue && newValue.inputValue) { + setValue({ + title: newValue.inputValue, + }); + return; + } + + setValue(newValue); + }} + filterOptions={(options, params) => { + const filtered = filter(options, params) as FilmOptionType[]; + + if (params.inputValue !== '') { + filtered.push({ + inputValue: params.inputValue, + title: `Add "${params.inputValue}"`, + }); + } + + return filtered; + }} + id="free-solo-with-text-demo" + options={top100Films as FilmOptionType[]} + getOptionLabel={option => { + // e.g value selected with enter, right from the input + if (typeof option === 'string') { + return option; + } + if (option.inputValue) { + return option.inputValue; + } + return option.title; + }} + renderOption={option => option.title} + style={{ width: 300 }} + freeSolo + renderInput={params => ( + + )} + /> + ); +} + +interface FilmOptionType { + inputValue?: string; + title: string; + year?: number; +} + +// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top +const top100Films = [ + { title: 'The Shawshank Redemption', year: 1994 }, + { title: 'The Godfather', year: 1972 }, + { title: 'The Godfather: Part II', year: 1974 }, + { title: 'The Dark Knight', year: 2008 }, + { title: '12 Angry Men', year: 1957 }, + { title: "Schindler's List", year: 1993 }, + { title: 'Pulp Fiction', year: 1994 }, + { title: 'The Lord of the Rings: The Return of the King', year: 2003 }, + { title: 'The Good, the Bad and the Ugly', year: 1966 }, + { title: 'Fight Club', year: 1999 }, + { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 }, + { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 }, + { title: 'Forrest Gump', year: 1994 }, + { title: 'Inception', year: 2010 }, + { title: 'The Lord of the Rings: The Two Towers', year: 2002 }, + { title: "One Flew Over the Cuckoo's Nest", year: 1975 }, + { title: 'Goodfellas', year: 1990 }, + { title: 'The Matrix', year: 1999 }, + { title: 'Seven Samurai', year: 1954 }, + { title: 'Star Wars: Episode IV - A New Hope', year: 1977 }, + { title: 'City of God', year: 2002 }, + { title: 'Se7en', year: 1995 }, + { title: 'The Silence of the Lambs', year: 1991 }, + { title: "It's a Wonderful Life", year: 1946 }, + { title: 'Life Is Beautiful', year: 1997 }, + { title: 'The Usual Suspects', year: 1995 }, + { title: 'Léon: The Professional', year: 1994 }, + { title: 'Spirited Away', year: 2001 }, + { title: 'Saving Private Ryan', year: 1998 }, + { title: 'Once Upon a Time in the West', year: 1968 }, + { title: 'American History X', year: 1998 }, + { title: 'Interstellar', year: 2014 }, + { title: 'Casablanca', year: 1942 }, + { title: 'City Lights', year: 1931 }, + { title: 'Psycho', year: 1960 }, + { title: 'The Green Mile', year: 1999 }, + { title: 'The Intouchables', year: 2011 }, + { title: 'Modern Times', year: 1936 }, + { title: 'Raiders of the Lost Ark', year: 1981 }, + { title: 'Rear Window', year: 1954 }, + { title: 'The Pianist', year: 2002 }, + { title: 'The Departed', year: 2006 }, + { title: 'Terminator 2: Judgment Day', year: 1991 }, + { title: 'Back to the Future', year: 1985 }, + { title: 'Whiplash', year: 2014 }, + { title: 'Gladiator', year: 2000 }, + { title: 'Memento', year: 2000 }, + { title: 'The Prestige', year: 2006 }, + { title: 'The Lion King', year: 1994 }, + { title: 'Apocalypse Now', year: 1979 }, + { title: 'Alien', year: 1979 }, + { title: 'Sunset Boulevard', year: 1950 }, + { + title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', + year: 1964, + }, + { title: 'The Great Dictator', year: 1940 }, + { title: 'Cinema Paradiso', year: 1988 }, + { title: 'The Lives of Others', year: 2006 }, + { title: 'Grave of the Fireflies', year: 1988 }, + { title: 'Paths of Glory', year: 1957 }, + { title: 'Django Unchained', year: 2012 }, + { title: 'The Shining', year: 1980 }, + { title: 'WALL·E', year: 2008 }, + { title: 'American Beauty', year: 1999 }, + { title: 'The Dark Knight Rises', year: 2012 }, + { title: 'Princess Mononoke', year: 1997 }, + { title: 'Aliens', year: 1986 }, + { title: 'Oldboy', year: 2003 }, + { title: 'Once Upon a Time in America', year: 1984 }, + { title: 'Witness for the Prosecution', year: 1957 }, + { title: 'Das Boot', year: 1981 }, + { title: 'Citizen Kane', year: 1941 }, + { title: 'North by Northwest', year: 1959 }, + { title: 'Vertigo', year: 1958 }, + { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 }, + { title: 'Reservoir Dogs', year: 1992 }, + { title: 'Braveheart', year: 1995 }, + { title: 'M', year: 1931 }, + { title: 'Requiem for a Dream', year: 2000 }, + { title: 'Amélie', year: 2001 }, + { title: 'A Clockwork Orange', year: 1971 }, + { title: 'Like Stars on Earth', year: 2007 }, + { title: 'Taxi Driver', year: 1976 }, + { title: 'Lawrence of Arabia', year: 1962 }, + { title: 'Double Indemnity', year: 1944 }, + { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 }, + { title: 'Amadeus', year: 1984 }, + { title: 'To Kill a Mockingbird', year: 1962 }, + { title: 'Toy Story 3', year: 2010 }, + { title: 'Logan', year: 2017 }, + { title: 'Full Metal Jacket', year: 1987 }, + { title: 'Dangal', year: 2016 }, + { title: 'The Sting', year: 1973 }, + { title: '2001: A Space Odyssey', year: 1968 }, + { title: "Singin' in the Rain", year: 1952 }, + { title: 'Toy Story', year: 1995 }, + { title: 'Bicycle Thieves', year: 1948 }, + { title: 'The Kid', year: 1921 }, + { title: 'Inglourious Basterds', year: 2009 }, + { title: 'Snatch', year: 2000 }, + { title: '3 Idiots', year: 2009 }, + { title: 'Monty Python and the Holy Grail', year: 1975 }, +]; diff --git a/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.js b/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.js new file mode 100644 index 00000000000000..bc1586c2bb865d --- /dev/null +++ b/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.js @@ -0,0 +1,248 @@ +/* eslint-disable no-use-before-define */ +import React from 'react'; +import TextField from '@material-ui/core/TextField'; +import Dialog from '@material-ui/core/Dialog'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogActions from '@material-ui/core/DialogActions'; +import Button from '@material-ui/core/Button'; +import Autocomplete, { createFilterOptions } from '@material-ui/lab/Autocomplete'; + +const filter = createFilterOptions(); + +export default function FreeSoloCreateOptionDialog() { + const [value, setValue] = React.useState(null); + const [open, toggleOpen] = React.useState(false); + + const handleClose = () => { + setDialogValue({ + title: '', + year: '', + }); + + toggleOpen(false); + }; + + const [dialogValue, setDialogValue] = React.useState({ + title: '', + year: '', + }); + + const handleSubmit = event => { + event.preventDefault(); + setValue({ + title: dialogValue.title, + year: parseInt(dialogValue.year, 10), + }); + + handleClose(); + }; + + return ( + + { + if (typeof newValue === 'string') { + // timeout to avoid instant validation of the dialog's form. + setTimeout(() => { + toggleOpen(true); + setDialogValue({ + title: newValue, + year: '', + }); + }); + return; + } + + if (newValue && newValue.inputValue) { + toggleOpen(true); + setDialogValue({ + title: newValue.inputValue, + year: '', + }); + + return; + } + + setValue(newValue); + }} + filterOptions={(options, params) => { + const filtered = filter(options, params); + + if (params.inputValue !== '') { + filtered.push({ + inputValue: params.inputValue, + title: `Add "${params.inputValue}"`, + }); + } + + return filtered; + }} + id="free-solo-dialog-demo" + options={top100Films} + getOptionLabel={option => { + // e.g value selected with enter, right from the input + if (typeof option === 'string') { + return option; + } + if (option.inputValue) { + return option.inputValue; + } + return option.title; + }} + renderOption={option => option.title} + style={{ width: 300 }} + freeSolo + renderInput={params => ( + + )} + /> + +
    + Add a new film + + + Did you miss any film in our list? Please, add it! + + setDialogValue({ ...dialogValue, title: event.target.value })} + label="title" + type="text" + fullWidth + /> + setDialogValue({ ...dialogValue, year: event.target.value })} + label="year" + type="number" + fullWidth + /> + + + + + +
    +
    +
    + ); +} + +// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top +const top100Films = [ + { title: 'The Shawshank Redemption', year: 1994 }, + { title: 'The Godfather', year: 1972 }, + { title: 'The Godfather: Part II', year: 1974 }, + { title: 'The Dark Knight', year: 2008 }, + { title: '12 Angry Men', year: 1957 }, + { title: "Schindler's List", year: 1993 }, + { title: 'Pulp Fiction', year: 1994 }, + { title: 'The Lord of the Rings: The Return of the King', year: 2003 }, + { title: 'The Good, the Bad and the Ugly', year: 1966 }, + { title: 'Fight Club', year: 1999 }, + { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 }, + { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 }, + { title: 'Forrest Gump', year: 1994 }, + { title: 'Inception', year: 2010 }, + { title: 'The Lord of the Rings: The Two Towers', year: 2002 }, + { title: "One Flew Over the Cuckoo's Nest", year: 1975 }, + { title: 'Goodfellas', year: 1990 }, + { title: 'The Matrix', year: 1999 }, + { title: 'Seven Samurai', year: 1954 }, + { title: 'Star Wars: Episode IV - A New Hope', year: 1977 }, + { title: 'City of God', year: 2002 }, + { title: 'Se7en', year: 1995 }, + { title: 'The Silence of the Lambs', year: 1991 }, + { title: "It's a Wonderful Life", year: 1946 }, + { title: 'Life Is Beautiful', year: 1997 }, + { title: 'The Usual Suspects', year: 1995 }, + { title: 'Léon: The Professional', year: 1994 }, + { title: 'Spirited Away', year: 2001 }, + { title: 'Saving Private Ryan', year: 1998 }, + { title: 'Once Upon a Time in the West', year: 1968 }, + { title: 'American History X', year: 1998 }, + { title: 'Interstellar', year: 2014 }, + { title: 'Casablanca', year: 1942 }, + { title: 'City Lights', year: 1931 }, + { title: 'Psycho', year: 1960 }, + { title: 'The Green Mile', year: 1999 }, + { title: 'The Intouchables', year: 2011 }, + { title: 'Modern Times', year: 1936 }, + { title: 'Raiders of the Lost Ark', year: 1981 }, + { title: 'Rear Window', year: 1954 }, + { title: 'The Pianist', year: 2002 }, + { title: 'The Departed', year: 2006 }, + { title: 'Terminator 2: Judgment Day', year: 1991 }, + { title: 'Back to the Future', year: 1985 }, + { title: 'Whiplash', year: 2014 }, + { title: 'Gladiator', year: 2000 }, + { title: 'Memento', year: 2000 }, + { title: 'The Prestige', year: 2006 }, + { title: 'The Lion King', year: 1994 }, + { title: 'Apocalypse Now', year: 1979 }, + { title: 'Alien', year: 1979 }, + { title: 'Sunset Boulevard', year: 1950 }, + { + title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', + year: 1964, + }, + { title: 'The Great Dictator', year: 1940 }, + { title: 'Cinema Paradiso', year: 1988 }, + { title: 'The Lives of Others', year: 2006 }, + { title: 'Grave of the Fireflies', year: 1988 }, + { title: 'Paths of Glory', year: 1957 }, + { title: 'Django Unchained', year: 2012 }, + { title: 'The Shining', year: 1980 }, + { title: 'WALL·E', year: 2008 }, + { title: 'American Beauty', year: 1999 }, + { title: 'The Dark Knight Rises', year: 2012 }, + { title: 'Princess Mononoke', year: 1997 }, + { title: 'Aliens', year: 1986 }, + { title: 'Oldboy', year: 2003 }, + { title: 'Once Upon a Time in America', year: 1984 }, + { title: 'Witness for the Prosecution', year: 1957 }, + { title: 'Das Boot', year: 1981 }, + { title: 'Citizen Kane', year: 1941 }, + { title: 'North by Northwest', year: 1959 }, + { title: 'Vertigo', year: 1958 }, + { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 }, + { title: 'Reservoir Dogs', year: 1992 }, + { title: 'Braveheart', year: 1995 }, + { title: 'M', year: 1931 }, + { title: 'Requiem for a Dream', year: 2000 }, + { title: 'Amélie', year: 2001 }, + { title: 'A Clockwork Orange', year: 1971 }, + { title: 'Like Stars on Earth', year: 2007 }, + { title: 'Taxi Driver', year: 1976 }, + { title: 'Lawrence of Arabia', year: 1962 }, + { title: 'Double Indemnity', year: 1944 }, + { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 }, + { title: 'Amadeus', year: 1984 }, + { title: 'To Kill a Mockingbird', year: 1962 }, + { title: 'Toy Story 3', year: 2010 }, + { title: 'Logan', year: 2017 }, + { title: 'Full Metal Jacket', year: 1987 }, + { title: 'Dangal', year: 2016 }, + { title: 'The Sting', year: 1973 }, + { title: '2001: A Space Odyssey', year: 1968 }, + { title: "Singin' in the Rain", year: 1952 }, + { title: 'Toy Story', year: 1995 }, + { title: 'Bicycle Thieves', year: 1948 }, + { title: 'The Kid', year: 1921 }, + { title: 'Inglourious Basterds', year: 2009 }, + { title: 'Snatch', year: 2000 }, + { title: '3 Idiots', year: 2009 }, + { title: 'Monty Python and the Holy Grail', year: 1975 }, +]; diff --git a/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.tsx b/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.tsx new file mode 100644 index 00000000000000..caa7b3f415097a --- /dev/null +++ b/docs/src/pages/components/autocomplete/FreeSoloCreateOptionDialog.tsx @@ -0,0 +1,251 @@ +/* eslint-disable no-use-before-define */ +import React from 'react'; +import TextField from '@material-ui/core/TextField'; +import Dialog from '@material-ui/core/Dialog'; +import DialogTitle from '@material-ui/core/DialogTitle'; +import DialogContent from '@material-ui/core/DialogContent'; +import DialogContentText from '@material-ui/core/DialogContentText'; +import DialogActions from '@material-ui/core/DialogActions'; +import Button from '@material-ui/core/Button'; +import Autocomplete, { createFilterOptions } from '@material-ui/lab/Autocomplete'; + +const filter = createFilterOptions(); + +export default function FreeSoloCreateOptionDialog() { + const [value, setValue] = React.useState(null); + const [open, toggleOpen] = React.useState(false); + + const handleClose = () => { + setDialogValue({ + title: '', + year: '', + }); + toggleOpen(false); + }; + + const [dialogValue, setDialogValue] = React.useState({ + title: '', + year: '', + }); + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + setValue({ + title: dialogValue.title, + year: parseInt(dialogValue.year, 10), + }); + handleClose(); + }; + + return ( + + { + if (typeof newValue === 'string') { + // timeout to avoid instant validation of the dialog's form. + setTimeout(() => { + toggleOpen(true); + setDialogValue({ + title: newValue, + year: '', + }); + }); + return; + } + + if (newValue && newValue.inputValue) { + toggleOpen(true); + setDialogValue({ + title: newValue.inputValue, + year: '', + }); + return; + } + + setValue(newValue); + }} + filterOptions={(options, params) => { + const filtered = filter(options, params) as FilmOptionType[]; + + if (params.inputValue !== '') { + filtered.push({ + inputValue: params.inputValue, + title: `Add "${params.inputValue}"`, + }); + } + + return filtered; + }} + id="free-solo-dialog-demo" + options={top100Films} + getOptionLabel={option => { + // e.g value selected with enter, right from the input + if (typeof option === 'string') { + return option; + } + if (option.inputValue) { + return option.inputValue; + } + return option.title; + }} + renderOption={option => option.title} + style={{ width: 300 }} + freeSolo + renderInput={params => ( + + )} + /> + +
    + Add a new film + + + Did you miss any film in our list? Please, add it! + + setDialogValue({ ...dialogValue, title: event.target.value })} + label="title" + type="text" + fullWidth + /> + setDialogValue({ ...dialogValue, year: event.target.value })} + label="year" + type="number" + fullWidth + /> + + + + + +
    +
    +
    + ); +} + +interface FilmOptionType { + inputValue?: string; + title: string; + year?: number; +} + +// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top +const top100Films = [ + { title: 'The Shawshank Redemption', year: 1994 }, + { title: 'The Godfather', year: 1972 }, + { title: 'The Godfather: Part II', year: 1974 }, + { title: 'The Dark Knight', year: 2008 }, + { title: '12 Angry Men', year: 1957 }, + { title: "Schindler's List", year: 1993 }, + { title: 'Pulp Fiction', year: 1994 }, + { title: 'The Lord of the Rings: The Return of the King', year: 2003 }, + { title: 'The Good, the Bad and the Ugly', year: 1966 }, + { title: 'Fight Club', year: 1999 }, + { title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 }, + { title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 }, + { title: 'Forrest Gump', year: 1994 }, + { title: 'Inception', year: 2010 }, + { title: 'The Lord of the Rings: The Two Towers', year: 2002 }, + { title: "One Flew Over the Cuckoo's Nest", year: 1975 }, + { title: 'Goodfellas', year: 1990 }, + { title: 'The Matrix', year: 1999 }, + { title: 'Seven Samurai', year: 1954 }, + { title: 'Star Wars: Episode IV - A New Hope', year: 1977 }, + { title: 'City of God', year: 2002 }, + { title: 'Se7en', year: 1995 }, + { title: 'The Silence of the Lambs', year: 1991 }, + { title: "It's a Wonderful Life", year: 1946 }, + { title: 'Life Is Beautiful', year: 1997 }, + { title: 'The Usual Suspects', year: 1995 }, + { title: 'Léon: The Professional', year: 1994 }, + { title: 'Spirited Away', year: 2001 }, + { title: 'Saving Private Ryan', year: 1998 }, + { title: 'Once Upon a Time in the West', year: 1968 }, + { title: 'American History X', year: 1998 }, + { title: 'Interstellar', year: 2014 }, + { title: 'Casablanca', year: 1942 }, + { title: 'City Lights', year: 1931 }, + { title: 'Psycho', year: 1960 }, + { title: 'The Green Mile', year: 1999 }, + { title: 'The Intouchables', year: 2011 }, + { title: 'Modern Times', year: 1936 }, + { title: 'Raiders of the Lost Ark', year: 1981 }, + { title: 'Rear Window', year: 1954 }, + { title: 'The Pianist', year: 2002 }, + { title: 'The Departed', year: 2006 }, + { title: 'Terminator 2: Judgment Day', year: 1991 }, + { title: 'Back to the Future', year: 1985 }, + { title: 'Whiplash', year: 2014 }, + { title: 'Gladiator', year: 2000 }, + { title: 'Memento', year: 2000 }, + { title: 'The Prestige', year: 2006 }, + { title: 'The Lion King', year: 1994 }, + { title: 'Apocalypse Now', year: 1979 }, + { title: 'Alien', year: 1979 }, + { title: 'Sunset Boulevard', year: 1950 }, + { + title: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', + year: 1964, + }, + { title: 'The Great Dictator', year: 1940 }, + { title: 'Cinema Paradiso', year: 1988 }, + { title: 'The Lives of Others', year: 2006 }, + { title: 'Grave of the Fireflies', year: 1988 }, + { title: 'Paths of Glory', year: 1957 }, + { title: 'Django Unchained', year: 2012 }, + { title: 'The Shining', year: 1980 }, + { title: 'WALL·E', year: 2008 }, + { title: 'American Beauty', year: 1999 }, + { title: 'The Dark Knight Rises', year: 2012 }, + { title: 'Princess Mononoke', year: 1997 }, + { title: 'Aliens', year: 1986 }, + { title: 'Oldboy', year: 2003 }, + { title: 'Once Upon a Time in America', year: 1984 }, + { title: 'Witness for the Prosecution', year: 1957 }, + { title: 'Das Boot', year: 1981 }, + { title: 'Citizen Kane', year: 1941 }, + { title: 'North by Northwest', year: 1959 }, + { title: 'Vertigo', year: 1958 }, + { title: 'Star Wars: Episode VI - Return of the Jedi', year: 1983 }, + { title: 'Reservoir Dogs', year: 1992 }, + { title: 'Braveheart', year: 1995 }, + { title: 'M', year: 1931 }, + { title: 'Requiem for a Dream', year: 2000 }, + { title: 'Amélie', year: 2001 }, + { title: 'A Clockwork Orange', year: 1971 }, + { title: 'Like Stars on Earth', year: 2007 }, + { title: 'Taxi Driver', year: 1976 }, + { title: 'Lawrence of Arabia', year: 1962 }, + { title: 'Double Indemnity', year: 1944 }, + { title: 'Eternal Sunshine of the Spotless Mind', year: 2004 }, + { title: 'Amadeus', year: 1984 }, + { title: 'To Kill a Mockingbird', year: 1962 }, + { title: 'Toy Story 3', year: 2010 }, + { title: 'Logan', year: 2017 }, + { title: 'Full Metal Jacket', year: 1987 }, + { title: 'Dangal', year: 2016 }, + { title: 'The Sting', year: 1973 }, + { title: '2001: A Space Odyssey', year: 1968 }, + { title: "Singin' in the Rain", year: 1952 }, + { title: 'Toy Story', year: 1995 }, + { title: 'Bicycle Thieves', year: 1948 }, + { title: 'The Kid', year: 1921 }, + { title: 'Inglourious Basterds', year: 2009 }, + { title: 'Snatch', year: 2000 }, + { title: '3 Idiots', year: 2009 }, + { title: 'Monty Python and the Holy Grail', year: 1975 }, +]; diff --git a/docs/src/pages/components/autocomplete/autocomplete.md b/docs/src/pages/components/autocomplete/autocomplete.md index 907e13b4985028..05a790f5dfabf0 100644 --- a/docs/src/pages/components/autocomplete/autocomplete.md +++ b/docs/src/pages/components/autocomplete/autocomplete.md @@ -34,10 +34,21 @@ Choose one country between 248. Set `freeSolo` to true so the textbox can contain any arbitrary value. The prop is designed to cover the primary use case of a search box with suggestions, e.g. Google search. -However, if you intend to use it for a [combo box](#combo-box) like experience (an enhanced version of a select element) we recommend setting `selectOnFocus`. +However, if you intend to use it for a [combo box](#combo-box) like experience (an enhanced version of a select element) we recommend setting `selectOnFocus` (it helps the user clearning the selected value). {{"demo": "pages/components/autocomplete/FreeSolo.js"}} +### Helper message + +Sometimes you want to make explicit to the user that he/she can add whatever value he/she wants. +The following demo adds a last option: `Add "YOUR SEARCH"`. + +{{"demo": "pages/components/autocomplete/FreeSoloCreateOption.js"}} + +You could also display a dialog when the user wants to add a new value. + +{{"demo": "pages/components/autocomplete/FreeSoloCreateOptionDialog.js"}} + ## Grouped {{"demo": "pages/components/autocomplete/Grouped.js"}} diff --git a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js index 5e7cb5d9accdb9..ebfbd5226fffca 100644 --- a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js +++ b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js @@ -745,6 +745,7 @@ Autocomplete.propTypes = { renderTags: PropTypes.func, /** * If `true`, the input's text will be selected on focus. + * It helps the user clearning the selected value. */ selectOnFocus: PropTypes.bool, /** diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts index 86de086256f888..d25398ed1ba4d2 100644 --- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts +++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts @@ -160,6 +160,7 @@ export interface UseAutocompleteCommonProps { options: T[]; /** * If `true`, the input's text will be selected on focus. + * It helps the user clearning the selected value. */ selectOnFocus?: boolean; }