diff --git a/docs/data/joy/components/autocomplete/AutocompleteVariables.js b/docs/data/joy/components/autocomplete/AutocompleteVariables.js new file mode 100644 index 00000000000000..cb2764f8bad6f7 --- /dev/null +++ b/docs/data/joy/components/autocomplete/AutocompleteVariables.js @@ -0,0 +1,185 @@ +import * as React from 'react'; +import JoyVariablesDemo from 'docs/src/modules/components/JoyVariablesDemo'; +import Autocomplete from '@mui/joy/Autocomplete'; +import Stack from '@mui/joy/Stack'; +import LiveTv from '@mui/icons-material/LiveTv'; + +export default function ButtonVariables() { + return ( + ( + + } + placeholder="Decorators" + options={top100Films} + sx={sx} + /> + } + placeholder="Decorators" + options={top100Films} + defaultValue={[top100Films[1]]} + sx={sx} + /> + + )} + /> + ); +} + +// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top +const top100Films = [ + { label: 'The Shawshank Redemption', year: 1994 }, + { label: 'The Godfather', year: 1972 }, + { label: 'The Godfather: Part II', year: 1974 }, + { label: 'The Dark Knight', year: 2008 }, + { label: '12 Angry Men', year: 1957 }, + { label: "Schindler's List", year: 1993 }, + { label: 'Pulp Fiction', year: 1994 }, + { + label: 'The Lord of the Rings: The Return of the King', + year: 2003, + }, + { label: 'The Good, the Bad and the Ugly', year: 1966 }, + { label: 'Fight Club', year: 1999 }, + { + label: 'The Lord of the Rings: The Fellowship of the Ring', + year: 2001, + }, + { + label: 'Star Wars: Episode V - The Empire Strikes Back', + year: 1980, + }, + { label: 'Forrest Gump', year: 1994 }, + { label: 'Inception', year: 2010 }, + { + label: 'The Lord of the Rings: The Two Towers', + year: 2002, + }, + { label: "One Flew Over the Cuckoo's Nest", year: 1975 }, + { label: 'Goodfellas', year: 1990 }, + { label: 'The Matrix', year: 1999 }, + { label: 'Seven Samurai', year: 1954 }, + { + label: 'Star Wars: Episode IV - A New Hope', + year: 1977, + }, + { label: 'City of God', year: 2002 }, + { label: 'Se7en', year: 1995 }, + { label: 'The Silence of the Lambs', year: 1991 }, + { label: "It's a Wonderful Life", year: 1946 }, + { label: 'Life Is Beautiful', year: 1997 }, + { label: 'The Usual Suspects', year: 1995 }, + { label: 'Léon: The Professional', year: 1994 }, + { label: 'Spirited Away', year: 2001 }, + { label: 'Saving Private Ryan', year: 1998 }, + { label: 'Once Upon a Time in the West', year: 1968 }, + { label: 'American History X', year: 1998 }, + { label: 'Interstellar', year: 2014 }, + { label: 'Casablanca', year: 1942 }, + { label: 'City Lights', year: 1931 }, + { label: 'Psycho', year: 1960 }, + { label: 'The Green Mile', year: 1999 }, + { label: 'The Intouchables', year: 2011 }, + { label: 'Modern Times', year: 1936 }, + { label: 'Raiders of the Lost Ark', year: 1981 }, + { label: 'Rear Window', year: 1954 }, + { label: 'The Pianist', year: 2002 }, + { label: 'The Departed', year: 2006 }, + { label: 'Terminator 2: Judgment Day', year: 1991 }, + { label: 'Back to the Future', year: 1985 }, + { label: 'Whiplash', year: 2014 }, + { label: 'Gladiator', year: 2000 }, + { label: 'Memento', year: 2000 }, + { label: 'The Prestige', year: 2006 }, + { label: 'The Lion King', year: 1994 }, + { label: 'Apocalypse Now', year: 1979 }, + { label: 'Alien', year: 1979 }, + { label: 'Sunset Boulevard', year: 1950 }, + { + label: 'Dr. Strangelove or: How I Learned to Stop Worrying and Love the Bomb', + year: 1964, + }, + { label: 'The Great Dictator', year: 1940 }, + { label: 'Cinema Paradiso', year: 1988 }, + { label: 'The Lives of Others', year: 2006 }, + { label: 'Grave of the Fireflies', year: 1988 }, + { label: 'Paths of Glory', year: 1957 }, + { label: 'Django Unchained', year: 2012 }, + { label: 'The Shining', year: 1980 }, + { label: 'WALL·E', year: 2008 }, + { label: 'American Beauty', year: 1999 }, + { label: 'The Dark Knight Rises', year: 2012 }, + { label: 'Princess Mononoke', year: 1997 }, + { label: 'Aliens', year: 1986 }, + { label: 'Oldboy', year: 2003 }, + { label: 'Once Upon a Time in America', year: 1984 }, + { label: 'Witness for the Prosecution', year: 1957 }, + { label: 'Das Boot', year: 1981 }, + { label: 'Citizen Kane', year: 1941 }, + { label: 'North by Northwest', year: 1959 }, + { label: 'Vertigo', year: 1958 }, + { + label: 'Star Wars: Episode VI - Return of the Jedi', + year: 1983, + }, + { label: 'Reservoir Dogs', year: 1992 }, + { label: 'Braveheart', year: 1995 }, + { label: 'M', year: 1931 }, + { label: 'Requiem for a Dream', year: 2000 }, + { label: 'Amélie', year: 2001 }, + { label: 'A Clockwork Orange', year: 1971 }, + { label: 'Like Stars on Earth', year: 2007 }, + { label: 'Taxi Driver', year: 1976 }, + { label: 'Lawrence of Arabia', year: 1962 }, + { label: 'Double Indemnity', year: 1944 }, + { + label: 'Eternal Sunshine of the Spotless Mind', + year: 2004, + }, + { label: 'Amadeus', year: 1984 }, + { label: 'To Kill a Mockingbird', year: 1962 }, + { label: 'Toy Story 3', year: 2010 }, + { label: 'Logan', year: 2017 }, + { label: 'Full Metal Jacket', year: 1987 }, + { label: 'Dangal', year: 2016 }, + { label: 'The Sting', year: 1973 }, + { label: '2001: A Space Odyssey', year: 1968 }, + { label: "Singin' in the Rain", year: 1952 }, + { label: 'Toy Story', year: 1995 }, + { label: 'Bicycle Thieves', year: 1948 }, + { label: 'The Kid', year: 1921 }, + { label: 'Inglourious Basterds', year: 2009 }, + { label: 'Snatch', year: 2000 }, + { label: '3 Idiots', year: 2009 }, + { label: 'Monty Python and the Holy Grail', year: 1975 }, +]; diff --git a/docs/data/joy/components/autocomplete/autocomplete.md b/docs/data/joy/components/autocomplete/autocomplete.md index ee2b46ca25c6ff..64190131960026 100644 --- a/docs/data/joy/components/autocomplete/autocomplete.md +++ b/docs/data/joy/components/autocomplete/autocomplete.md @@ -360,6 +360,12 @@ If you would like to prevent the default key handler behavior, you can set the e /> ``` +## CSS Variables + +The Autocomplete component reuses CSS variables from the Input component: + +{{"demo": "AutocompleteVariables.js", "hideToolbar": true}} + ## Limitations ### autocomplete/autofill diff --git a/packages/mui-joy/src/Autocomplete/Autocomplete.tsx b/packages/mui-joy/src/Autocomplete/Autocomplete.tsx index 4379cb46d969c1..6f2f71af46fcdd 100644 --- a/packages/mui-joy/src/Autocomplete/Autocomplete.tsx +++ b/packages/mui-joy/src/Autocomplete/Autocomplete.tsx @@ -70,7 +70,8 @@ const defaultModifiers = [ ]; const useUtilityClasses = (ownerState: OwnerState) => { - const { focused, hasClearIcon, hasPopupIcon, popupOpen, variant, color, size } = ownerState; + const { focused, hasClearIcon, hasPopupIcon, popupOpen, variant, color, size, multiple } = + ownerState; const slots = { root: [ @@ -82,7 +83,7 @@ const useUtilityClasses = (ownerState: OwnerState) => { color && `color${capitalize(color)}`, size && `size${capitalize(size)}`, ], - wrapper: ['wrapper'], + wrapper: ['wrapper', multiple && 'multiple'], input: ['input'], startDecorator: ['startDecorator'], endDecorator: ['endDecorator'], @@ -124,28 +125,30 @@ const AutocompleteWrapper = styled('div', { slot: 'Wrapper', overridesResolver: (props, styles) => styles.wrapper, })<{ ownerState: OwnerState }>(({ ownerState }) => ({ + '--Chip-minHeight': 'var(--Input-decorator-childHeight)', // For Autocomplete multiple selection because it uses Chip for showing selected items. flex: 1, // stretch to fill the root slot minWidth: 0, // won't push end decorator out of the autocomplete display: 'flex', alignItems: 'center', flexWrap: 'wrap', - ...(ownerState.multiple && { + [`&.${autocompleteClasses.multiple}`]: { paddingInlineStart: 0, paddingBlockEnd: 'var(--_Input-paddingBlock)', - [`& .${chipClasses.root}`]: { - // TODO: use flexbox `gap` on the root slot later. - marginInlineStart: 'var(--_Input-paddingBlock)', - marginBlockStart: 'var(--_Input-paddingBlock)', - }, // TODO: use [CSS :has](https://caniuse.com/?search=%3Ahas) later ...(ownerState.startDecorator && + Array.isArray(ownerState.value) && (ownerState.value as Array).length > 0 && { marginInlineStart: 'calc(-1 * var(--_Input-paddingBlock))', [`& .${autocompleteClasses.input}`]: { - marginInlineStart: 'var(--Input-paddingInline)', + marginInlineStart: 'var(--Input-gap)', }, }), - }), + }, + [`& .${chipClasses.root}`]: { + // TODO: use flexbox `gap` later. + marginInlineStart: 'var(--_Input-paddingBlock)', + marginBlockStart: 'var(--_Input-paddingBlock)', + }, })); const AutocompleteInput = styled(StyledInputHtml, { diff --git a/packages/mui-joy/src/Autocomplete/autocompleteClasses.ts b/packages/mui-joy/src/Autocomplete/autocompleteClasses.ts index 089f5b9952a109..e48385d4651176 100644 --- a/packages/mui-joy/src/Autocomplete/autocompleteClasses.ts +++ b/packages/mui-joy/src/Autocomplete/autocompleteClasses.ts @@ -19,6 +19,8 @@ export interface AutocompleteClasses { disabled: string; /** State class applied to the root element if `error={true}`. */ error: string; + /** Styles applied to the wrapper element if `multiple={true}`. */ + multiple: string; /** Styles applied to the limitTag element. */ limitTag: string; /** Styles applied when the popup icon is rendered. */ @@ -83,6 +85,7 @@ const autocompleteClasses: AutocompleteClasses = generateUtilityClasses('JoyAuto 'focused', 'disabled', 'error', + 'multiple', 'limitTag', 'hasPopupIcon', 'hasClearIcon', diff --git a/packages/mui-joy/src/Input/Input.tsx b/packages/mui-joy/src/Input/Input.tsx index 9bc60990cfd22a..06353aa3f932ae 100644 --- a/packages/mui-joy/src/Input/Input.tsx +++ b/packages/mui-joy/src/Input/Input.tsx @@ -164,7 +164,6 @@ export const StyledInputStartDecorator = styled('span')<{ ownerState: InputOwner '--Button-margin': '0 0 0 calc(var(--Input-decorator-childOffset) * -1)', '--IconButton-margin': '0 0 0 calc(var(--Input-decorator-childOffset) * -1)', '--Icon-margin': '0 0 0 calc(var(--Input-paddingInline) / -4)', - '--Chip-minHeight': 'var(--Input-decorator-childHeight)', // For Autocomplete multiple selection because it uses Chip for showing selected items. display: 'inherit', alignItems: 'center', paddingBlock: 'var(--unstable_Input-paddingBlock)', // for wrapping Autocomplete's tags