diff --git a/docs/data/material/components/autocomplete/GitHubLabel.js b/docs/data/material/components/autocomplete/GitHubLabel.js
index 23baefb03e2edc..41e56b35af5b43 100644
--- a/docs/data/material/components/autocomplete/GitHubLabel.js
+++ b/docs/data/material/components/autocomplete/GitHubLabel.js
@@ -19,13 +19,19 @@ const StyledAutocompletePopper = styled('div')(({ theme }) => ({
fontSize: 13,
},
[`& .${autocompleteClasses.listbox}`]: {
- backgroundColor: '#fff',
padding: 0,
+ backgroundColor: '#fff',
+ ...theme.applyStyles('dark', {
+ backgroundColor: '#1c2128',
+ }),
[`& .${autocompleteClasses.option}`]: {
minHeight: 'auto',
alignItems: 'flex-start',
padding: 8,
- borderBottom: `1px solid ${' #eaecef'}`,
+ borderBottom: '1px solid #eaecef',
+ ...theme.applyStyles('dark', {
+ borderBottom: '1px solid #30363d',
+ }),
'&[aria-selected="true"]': {
backgroundColor: 'transparent',
},
@@ -33,13 +39,7 @@ const StyledAutocompletePopper = styled('div')(({ theme }) => ({
{
backgroundColor: theme.palette.action.hover,
},
- ...theme.applyStyles('dark', {
- borderBottom: `1px solid ${'#30363d'}`,
- }),
},
- ...theme.applyStyles('dark', {
- backgroundColor: '#1c2128',
- }),
},
[`&.${autocompleteClasses.popperDisablePortal}`]: {
position: 'relative',
@@ -58,7 +58,7 @@ PopperComponent.propTypes = {
};
const StyledPopper = styled(Popper)(({ theme }) => ({
- border: `1px solid ${'#e1e4e8'}`,
+ border: '1px solid #e1e4e8',
boxShadow: `0 8px 24px ${'rgba(149, 157, 165, 0.2)'}`,
color: '#24292e',
backgroundColor: '#fff',
@@ -67,8 +67,8 @@ const StyledPopper = styled(Popper)(({ theme }) => ({
zIndex: theme.zIndex.modal,
fontSize: 13,
...theme.applyStyles('dark', {
- border: `1px solid ${'#30363d'}`,
- boxShadow: `0 8px 24px ${'rgb(1, 4, 9)'}`,
+ border: '1px solid #30363d',
+ boxShadow: '0 8px 24px rgb(1, 4, 9)',
color: '#c9d1d9',
backgroundColor: '#1c2128',
}),
@@ -77,30 +77,30 @@ const StyledPopper = styled(Popper)(({ theme }) => ({
const StyledInput = styled(InputBase)(({ theme }) => ({
padding: 10,
width: '100%',
- borderBottom: `1px solid ${'#30363d'}`,
+ borderBottom: '1px solid #eaecef',
+ ...theme.applyStyles('dark', {
+ borderBottom: '1px solid #30363d',
+ }),
'& input': {
borderRadius: 4,
- backgroundColor: '#fff',
- border: `1px solid ${'#30363d'}`,
padding: 8,
transition: theme.transitions.create(['border-color', 'box-shadow']),
fontSize: 14,
+ backgroundColor: '#fff',
+ border: '1px solid #30363d',
+ ...theme.applyStyles('dark', {
+ backgroundColor: '#0d1117',
+ border: '1px solid #eaecef',
+ }),
'&:focus': {
- boxShadow: `0px 0px 0px 3px ${'rgba(3, 102, 214, 0.3)'}`,
+ boxShadow: '0px 0px 0px 3px rgba(3, 102, 214, 0.3)',
borderColor: '#0366d6',
...theme.applyStyles('dark', {
- boxShadow: `0px 0px 0px 3px ${'rgb(12, 45, 107)'}`,
+ boxShadow: '0px 0px 0px 3px rgb(12, 45, 107)',
borderColor: '#388bfd',
}),
},
- ...theme.applyStyles('dark', {
- backgroundColor: '#0d1117',
- border: `1px solid ${'#eaecef'}`,
- }),
},
- ...theme.applyStyles('dark', {
- borderBottom: `1px solid ${'#eaecef'}`,
- }),
}));
const Button = styled(ButtonBase)(({ theme }) => ({
@@ -108,8 +108,11 @@ const Button = styled(ButtonBase)(({ theme }) => ({
width: '100%',
textAlign: 'left',
paddingBottom: 8,
- color: '#586069',
fontWeight: 600,
+ color: '#586069',
+ ...theme.applyStyles('dark', {
+ color: '#8b949e',
+ }),
'&:hover,&:focus': {
color: '#0366d6',
...theme.applyStyles('dark', {
@@ -123,9 +126,6 @@ const Button = styled(ButtonBase)(({ theme }) => ({
width: 16,
height: 16,
},
- ...theme.applyStyles('dark', {
- color: '#8b949e',
- }),
}));
export default function GitHubLabel() {
@@ -182,11 +182,11 @@ export default function GitHubLabel() {
({
- borderBottom: `1px solid ${'#30363d'}`,
+ borderBottom: '1px solid #30363d',
padding: '8px 10px',
fontWeight: 600,
...t.applyStyles('light', {
- borderBottom: `1px solid ${'#eaecef'}`,
+ borderBottom: '1px solid #eaecef',
}),
})}
>
diff --git a/docs/data/material/components/autocomplete/GitHubLabel.tsx b/docs/data/material/components/autocomplete/GitHubLabel.tsx
index d454737b623a12..f95d7fe1d1d396 100644
--- a/docs/data/material/components/autocomplete/GitHubLabel.tsx
+++ b/docs/data/material/components/autocomplete/GitHubLabel.tsx
@@ -27,15 +27,19 @@ const StyledAutocompletePopper = styled('div')(({ theme }) => ({
fontSize: 13,
},
[`& .${autocompleteClasses.listbox}`]: {
- backgroundColor: '#fff',
-
padding: 0,
+ backgroundColor: '#fff',
+ ...theme.applyStyles('dark', {
+ backgroundColor: '#1c2128',
+ }),
[`& .${autocompleteClasses.option}`]: {
minHeight: 'auto',
alignItems: 'flex-start',
padding: 8,
- borderBottom: `1px solid ${' #eaecef'}`,
-
+ borderBottom: '1px solid #eaecef',
+ ...theme.applyStyles('dark', {
+ borderBottom: '1px solid #30363d',
+ }),
'&[aria-selected="true"]': {
backgroundColor: 'transparent',
},
@@ -43,13 +47,7 @@ const StyledAutocompletePopper = styled('div')(({ theme }) => ({
{
backgroundColor: theme.palette.action.hover,
},
- ...theme.applyStyles('dark', {
- borderBottom: `1px solid ${'#30363d'}`,
- }),
},
- ...theme.applyStyles('dark', {
- backgroundColor: '#1c2128',
- }),
},
[`&.${autocompleteClasses.popperDisablePortal}`]: {
position: 'relative',
@@ -62,7 +60,7 @@ function PopperComponent(props: PopperComponentProps) {
}
const StyledPopper = styled(Popper)(({ theme }) => ({
- border: `1px solid ${'#e1e4e8'}`,
+ border: '1px solid #e1e4e8',
boxShadow: `0 8px 24px ${'rgba(149, 157, 165, 0.2)'}`,
color: '#24292e',
backgroundColor: '#fff',
@@ -71,8 +69,8 @@ const StyledPopper = styled(Popper)(({ theme }) => ({
zIndex: theme.zIndex.modal,
fontSize: 13,
...theme.applyStyles('dark', {
- border: `1px solid ${'#30363d'}`,
- boxShadow: `0 8px 24px ${'rgb(1, 4, 9)'}`,
+ border: '1px solid #30363d',
+ boxShadow: '0 8px 24px rgb(1, 4, 9)',
color: '#c9d1d9',
backgroundColor: '#1c2128',
}),
@@ -81,30 +79,30 @@ const StyledPopper = styled(Popper)(({ theme }) => ({
const StyledInput = styled(InputBase)(({ theme }) => ({
padding: 10,
width: '100%',
- borderBottom: `1px solid ${'#30363d'}`,
+ borderBottom: '1px solid #eaecef',
+ ...theme.applyStyles('dark', {
+ borderBottom: '1px solid #30363d',
+ }),
'& input': {
borderRadius: 4,
- backgroundColor: '#fff',
- border: `1px solid ${'#30363d'}`,
padding: 8,
transition: theme.transitions.create(['border-color', 'box-shadow']),
fontSize: 14,
+ backgroundColor: '#fff',
+ border: '1px solid #30363d',
+ ...theme.applyStyles('dark', {
+ backgroundColor: '#0d1117',
+ border: '1px solid #eaecef',
+ }),
'&:focus': {
- boxShadow: `0px 0px 0px 3px ${'rgba(3, 102, 214, 0.3)'}`,
+ boxShadow: '0px 0px 0px 3px rgba(3, 102, 214, 0.3)',
borderColor: '#0366d6',
...theme.applyStyles('dark', {
- boxShadow: `0px 0px 0px 3px ${'rgb(12, 45, 107)'}`,
+ boxShadow: '0px 0px 0px 3px rgb(12, 45, 107)',
borderColor: '#388bfd',
}),
},
- ...theme.applyStyles('dark', {
- backgroundColor: '#0d1117',
- border: `1px solid ${'#eaecef'}`,
- }),
},
- ...theme.applyStyles('dark', {
- borderBottom: `1px solid ${'#eaecef'}`,
- }),
}));
const Button = styled(ButtonBase)(({ theme }) => ({
@@ -112,8 +110,11 @@ const Button = styled(ButtonBase)(({ theme }) => ({
width: '100%',
textAlign: 'left',
paddingBottom: 8,
- color: '#586069',
fontWeight: 600,
+ color: '#586069',
+ ...theme.applyStyles('dark', {
+ color: '#8b949e',
+ }),
'&:hover,&:focus': {
color: '#0366d6',
...theme.applyStyles('dark', {
@@ -127,9 +128,6 @@ const Button = styled(ButtonBase)(({ theme }) => ({
width: 16,
height: 16,
},
- ...theme.applyStyles('dark', {
- color: '#8b949e',
- }),
}));
export default function GitHubLabel() {
@@ -186,11 +184,11 @@ export default function GitHubLabel() {
({
- borderBottom: `1px solid ${'#30363d'}`,
+ borderBottom: '1px solid #30363d',
padding: '8px 10px',
fontWeight: 600,
...t.applyStyles('light', {
- borderBottom: `1px solid ${'#eaecef'}`,
+ borderBottom: '1px solid #eaecef',
}),
})}
>
diff --git a/docs/data/material/components/autocomplete/GoogleMaps.js b/docs/data/material/components/autocomplete/GoogleMaps.js
index 7dd26015ac2c89..944fe71bda7f93 100644
--- a/docs/data/material/components/autocomplete/GoogleMaps.js
+++ b/docs/data/material/components/autocomplete/GoogleMaps.js
@@ -1,12 +1,18 @@
import * as React from 'react';
+import PropTypes from 'prop-types';
import Box from '@mui/material/Box';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';
+import Paper from '@mui/material/Paper';
import LocationOnIcon from '@mui/icons-material/LocationOn';
import Grid2 from '@mui/material/Grid2';
import Typography from '@mui/material/Typography';
+import { useTheme } from '@mui/material/styles';
import parse from 'autosuggest-highlight/parse';
-import throttle from 'lodash/throttle';
+// For the sake of this demo, we have to use debounce to reduce Google Maps Places API quote use
+// But prefer to use throttle in practice
+// import throttle from 'lodash/throttle';
+import { debounce } from '@mui/material/utils';
// This key was created specifically for the demo in mui.com.
// You need to create a new one for your application.
@@ -23,31 +29,79 @@ function loadScript(src, position) {
return script;
}
-const fetch = throttle(async (request, callback) => {
- const { suggestions } =
- await window.google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(
- request,
- );
+function CustomPaper(props) {
+ const theme = useTheme();
- callback(
- suggestions.map((suggestion) => {
- const place = suggestion.placePrediction;
- // Map to the old AutocompleteService.getPlacePredictions format
- // https://developers.google.com/maps/documentation/javascript/places-migration-autocomplete
- return {
- description: place.text.text,
- structured_formatting: {
- main_text: place.mainText.text,
- main_text_matched_substrings: place.mainText.matches.map((match) => ({
- offset: match.startOffset,
- length: match.endOffset - match.startOffset,
- })),
- secondary_text: place.secondaryText?.text,
- },
- };
- }),
+ return (
+
+ {props.children}
+ {/* Legal requirment https://developers.google.com/maps/documentation/javascript/policies#logo */}
+ ({
+ display: 'flex',
+ justifyContent: 'flex-end',
+ p: 1,
+ pt: '1px',
+ ...staticTheme.applyStyles('dark', {
+ opacity: 0.8,
+ }),
+ })}
+ >
+
+
+
);
-}, 300);
+}
+
+CustomPaper.propTypes = {
+ /**
+ * The content of the component.
+ */
+ children: PropTypes.node,
+};
+
+const fetch = debounce(async (request, callback) => {
+ try {
+ const { suggestions } =
+ await window.google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(
+ request,
+ );
+
+ callback(
+ suggestions.map((suggestion) => {
+ const place = suggestion.placePrediction;
+ // Map to the old AutocompleteService.getPlacePredictions format
+ // https://developers.google.com/maps/documentation/javascript/places-migration-autocomplete
+ return {
+ description: place.text.text,
+ structured_formatting: {
+ main_text: place.mainText.text,
+ main_text_matched_substrings: place.mainText.matches.map((match) => ({
+ offset: match.startOffset,
+ length: match.endOffset - match.startOffset,
+ })),
+ secondary_text: place.secondaryText?.text,
+ },
+ };
+ }),
+ );
+ } catch (err) {
+ if (err.message === 'Quota exceeded for quota') {
+ callback(request.input.length === 1 ? fakeAnswer.p : fakeAnswer.paris);
+ }
+
+ throw err;
+ }
+}, 400);
const emptyOptions = [];
let sessionToken;
@@ -129,6 +183,9 @@ export default function GoogleMaps() {
typeof option === 'string' ? option : option.description
}
filterOptions={(x) => x}
+ slots={{
+ paper: CustomPaper,
+ }}
options={options}
autoComplete
includeInputInList
@@ -186,3 +243,87 @@ export default function GoogleMaps() {
/>
);
}
+
+// Fake data in case Google Map Places API returns a rate limit.
+const fakeAnswer = {
+ p: [
+ {
+ description: 'Portugal',
+ structured_formatting: {
+ main_text: 'Portugal',
+ main_text_matched_substrings: [{ offset: 0, length: 1 }],
+ },
+ },
+ {
+ description: 'Puerto Rico',
+ structured_formatting: {
+ main_text: 'Puerto Rico',
+ main_text_matched_substrings: [{ offset: 0, length: 1 }],
+ },
+ },
+ {
+ description: 'Pakistan',
+ structured_formatting: {
+ main_text: 'Pakistan',
+ main_text_matched_substrings: [{ offset: 0, length: 1 }],
+ },
+ },
+ {
+ description: 'Philippines',
+ structured_formatting: {
+ main_text: 'Philippines',
+ main_text_matched_substrings: [{ offset: 0, length: 1 }],
+ },
+ },
+ {
+ description: 'Paris, France',
+ structured_formatting: {
+ main_text: 'Paris',
+ main_text_matched_substrings: [{ offset: 0, length: 1 }],
+ secondary_text: 'France',
+ },
+ },
+ ],
+ paris: [
+ {
+ description: 'Paris, France',
+ structured_formatting: {
+ main_text: 'Paris',
+ main_text_matched_substrings: [{ offset: 0, length: 5 }],
+ secondary_text: 'France',
+ },
+ },
+ {
+ description: 'Paris, TX, USA',
+ structured_formatting: {
+ main_text: 'Paris',
+ main_text_matched_substrings: [{ offset: 0, length: 5 }],
+ secondary_text: 'TX, USA',
+ },
+ },
+ {
+ description: "Paris Beauvais Airport, Route de l'Aéroport, Tillé, France",
+ structured_formatting: {
+ main_text: 'Paris Beauvais Airport',
+ main_text_matched_substrings: [{ offset: 0, length: 5 }],
+ secondary_text: "Route de l'Aéroport, Tillé, France",
+ },
+ },
+ {
+ description: 'Paris Las Vegas, South Las Vegas Boulevard, Las Vegas, NV, USA',
+ structured_formatting: {
+ main_text: 'Paris Las Vegas',
+ main_text_matched_substrings: [{ offset: 0, length: 5 }],
+ secondary_text: 'South Las Vegas Boulevard, Las Vegas, NV, USA',
+ },
+ },
+ {
+ description: "Paris La Défense Arena, Jardin de l'Arche, Nanterre, France",
+ structured_formatting: {
+ main_text: 'Paris La Défense Arena',
+ main_text_matched_substrings: [{ offset: 0, length: 5 }],
+ secondary_text: "Jardin de l'Arche, Nanterre, France",
+ },
+ },
+ ],
+};
diff --git a/docs/data/material/components/autocomplete/GoogleMaps.tsx b/docs/data/material/components/autocomplete/GoogleMaps.tsx
index 2d94e09bff7b0c..f0f5bd0d2e2829 100644
--- a/docs/data/material/components/autocomplete/GoogleMaps.tsx
+++ b/docs/data/material/components/autocomplete/GoogleMaps.tsx
@@ -2,11 +2,16 @@ import * as React from 'react';
import Box from '@mui/material/Box';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';
+import Paper, { PaperProps } from '@mui/material/Paper';
import LocationOnIcon from '@mui/icons-material/LocationOn';
import Grid2 from '@mui/material/Grid2';
import Typography from '@mui/material/Typography';
+import { useTheme } from '@mui/material/styles';
import parse from 'autosuggest-highlight/parse';
-import throttle from 'lodash/throttle';
+// For the sake of this demo, we have to use debounce to reduce Google Maps Places API quote use
+// But prefer to use throttle in practice
+// import throttle from 'lodash/throttle';
+import { debounce } from '@mui/material/utils';
// This key was created specifically for the demo in mui.com.
// You need to create a new one for your application.
@@ -37,39 +42,80 @@ interface PlaceType {
structured_formatting: StructuredFormatting;
}
-const fetch = throttle(
+function CustomPaper(props: PaperProps) {
+ const theme = useTheme();
+
+ return (
+
+ {props.children}
+ {/* Legal requirment https://developers.google.com/maps/documentation/javascript/policies#logo */}
+ ({
+ display: 'flex',
+ justifyContent: 'flex-end',
+ p: 1,
+ pt: '1px',
+ ...staticTheme.applyStyles('dark', {
+ opacity: 0.8,
+ }),
+ })}
+ >
+
+
+
+ );
+}
+
+const fetch = debounce(
async (
request: { input: string; sessionToken: any },
callback: (results?: readonly PlaceType[]) => void,
) => {
- const { suggestions } = await (
- window as any
- ).google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(
- request,
- );
-
- callback(
- suggestions.map((suggestion: any) => {
- const place = suggestion.placePrediction;
- // Map to the old AutocompleteService.getPlacePredictions format
- // https://developers.google.com/maps/documentation/javascript/places-migration-autocomplete
- return {
- description: place.text.text,
- structured_formatting: {
- main_text: place.mainText.text,
- main_text_matched_substrings: place.mainText.matches.map(
- (match: any) => ({
- offset: match.startOffset,
- length: match.endOffset - match.startOffset,
- }),
- ),
- secondary_text: place.secondaryText?.text,
- },
- };
- }),
- );
+ try {
+ const { suggestions } = await (
+ window as any
+ ).google.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(
+ request,
+ );
+
+ callback(
+ suggestions.map((suggestion: any) => {
+ const place = suggestion.placePrediction;
+ // Map to the old AutocompleteService.getPlacePredictions format
+ // https://developers.google.com/maps/documentation/javascript/places-migration-autocomplete
+ return {
+ description: place.text.text,
+ structured_formatting: {
+ main_text: place.mainText.text,
+ main_text_matched_substrings: place.mainText.matches.map(
+ (match: any) => ({
+ offset: match.startOffset,
+ length: match.endOffset - match.startOffset,
+ }),
+ ),
+ secondary_text: place.secondaryText?.text,
+ },
+ };
+ }),
+ );
+ } catch (err: any) {
+ if (err.message === 'Quota exceeded for quota') {
+ callback(request.input.length === 1 ? fakeAnswer.p : fakeAnswer.paris);
+ }
+
+ throw err;
+ }
},
- 300,
+ 400,
);
const emptyOptions = [] as any;
@@ -155,6 +201,9 @@ export default function GoogleMaps() {
typeof option === 'string' ? option : option.description
}
filterOptions={(x) => x}
+ slots={{
+ paper: CustomPaper,
+ }}
options={options}
autoComplete
includeInputInList
@@ -212,3 +261,87 @@ export default function GoogleMaps() {
/>
);
}
+
+// Fake data in case Google Map Places API returns a rate limit.
+const fakeAnswer = {
+ p: [
+ {
+ description: 'Portugal',
+ structured_formatting: {
+ main_text: 'Portugal',
+ main_text_matched_substrings: [{ offset: 0, length: 1 }],
+ },
+ },
+ {
+ description: 'Puerto Rico',
+ structured_formatting: {
+ main_text: 'Puerto Rico',
+ main_text_matched_substrings: [{ offset: 0, length: 1 }],
+ },
+ },
+ {
+ description: 'Pakistan',
+ structured_formatting: {
+ main_text: 'Pakistan',
+ main_text_matched_substrings: [{ offset: 0, length: 1 }],
+ },
+ },
+ {
+ description: 'Philippines',
+ structured_formatting: {
+ main_text: 'Philippines',
+ main_text_matched_substrings: [{ offset: 0, length: 1 }],
+ },
+ },
+ {
+ description: 'Paris, France',
+ structured_formatting: {
+ main_text: 'Paris',
+ main_text_matched_substrings: [{ offset: 0, length: 1 }],
+ secondary_text: 'France',
+ },
+ },
+ ],
+ paris: [
+ {
+ description: 'Paris, France',
+ structured_formatting: {
+ main_text: 'Paris',
+ main_text_matched_substrings: [{ offset: 0, length: 5 }],
+ secondary_text: 'France',
+ },
+ },
+ {
+ description: 'Paris, TX, USA',
+ structured_formatting: {
+ main_text: 'Paris',
+ main_text_matched_substrings: [{ offset: 0, length: 5 }],
+ secondary_text: 'TX, USA',
+ },
+ },
+ {
+ description: "Paris Beauvais Airport, Route de l'Aéroport, Tillé, France",
+ structured_formatting: {
+ main_text: 'Paris Beauvais Airport',
+ main_text_matched_substrings: [{ offset: 0, length: 5 }],
+ secondary_text: "Route de l'Aéroport, Tillé, France",
+ },
+ },
+ {
+ description: 'Paris Las Vegas, South Las Vegas Boulevard, Las Vegas, NV, USA',
+ structured_formatting: {
+ main_text: 'Paris Las Vegas',
+ main_text_matched_substrings: [{ offset: 0, length: 5 }],
+ secondary_text: 'South Las Vegas Boulevard, Las Vegas, NV, USA',
+ },
+ },
+ {
+ description: "Paris La Défense Arena, Jardin de l'Arche, Nanterre, France",
+ structured_formatting: {
+ main_text: 'Paris La Défense Arena',
+ main_text_matched_substrings: [{ offset: 0, length: 5 }],
+ secondary_text: "Jardin de l'Arche, Nanterre, France",
+ },
+ },
+ ],
+};
diff --git a/docs/data/material/components/autocomplete/autocomplete.md b/docs/data/material/components/autocomplete/autocomplete.md
index 09ec3ffbf059bc..553ba3c910d09d 100644
--- a/docs/data/material/components/autocomplete/autocomplete.md
+++ b/docs/data/material/components/autocomplete/autocomplete.md
@@ -221,6 +221,8 @@ The demo relies on [autosuggest-highlight](https://github.com/moroshko/autosugge
:::error
Before you can start using the Google Maps JavaScript API and Places API, you need to get your own [API key](https://developers.google.com/maps/documentation/javascript/get-api-key).
+
+This demo has limited quotas to make API requests. When your quota exceeds, you will see the response for "Paris".
:::
## Multiple values