diff options
Diffstat (limited to 'packages/renderer/src/components/locationBar/LocationTextField.tsx')
-rw-r--r-- | packages/renderer/src/components/locationBar/LocationTextField.tsx | 85 |
1 files changed, 70 insertions, 15 deletions
diff --git a/packages/renderer/src/components/locationBar/LocationTextField.tsx b/packages/renderer/src/components/locationBar/LocationTextField.tsx index a618bf6..f436bf0 100644 --- a/packages/renderer/src/components/locationBar/LocationTextField.tsx +++ b/packages/renderer/src/components/locationBar/LocationTextField.tsx | |||
@@ -18,40 +18,95 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import IconGlobe from '@mui/icons-material/Public'; | ||
22 | import FilledInput from '@mui/material/FilledInput'; | 21 | import FilledInput from '@mui/material/FilledInput'; |
23 | import InputAdornment from '@mui/material/InputAdornment'; | 22 | import { styled } from '@mui/material/styles'; |
24 | import { Service } from '@sophie/shared'; | 23 | import { Service } from '@sophie/shared'; |
24 | import { autorun } from 'mobx'; | ||
25 | import { observer } from 'mobx-react-lite'; | 25 | import { observer } from 'mobx-react-lite'; |
26 | import React from 'react'; | 26 | import React, { useCallback, useEffect, useState } from 'react'; |
27 | |||
28 | import GoAdornment from './GoAdornment'; | ||
29 | import LocationOverlayInput from './LocationOverlayInput'; | ||
30 | import UrlAdornment from './UrlAdornment'; | ||
31 | import UrlOverlay from './UrlOverlay'; | ||
32 | import splitUrl from './splitUrl'; | ||
33 | |||
34 | const LocationTextFieldRoot = styled(FilledInput, { | ||
35 | name: 'LocationTextField', | ||
36 | slot: 'Root', | ||
37 | })(({ theme }) => ({ | ||
38 | paddingLeft: 12, | ||
39 | paddingRight: 12, | ||
40 | borderRadius: 20, | ||
41 | '&.Mui-focused': { | ||
42 | outline: `2px solid ${theme.palette.primary.main}`, | ||
43 | }, | ||
44 | })); | ||
27 | 45 | ||
28 | function LocationTextField({ | 46 | function LocationTextField({ |
29 | service, | 47 | service, |
30 | }: { | 48 | }: { |
31 | service: Service | undefined; | 49 | service: Service | undefined; |
32 | }): JSX.Element { | 50 | }): JSX.Element { |
51 | const [inputFocused, setInputFocused] = useState(false); | ||
52 | const [changed, setChanged] = useState(false); | ||
53 | const [value, setValue] = useState(''); | ||
54 | |||
55 | const resetValue = useCallback(() => { | ||
56 | setValue(service?.currentUrl ?? ''); | ||
57 | setChanged(false); | ||
58 | }, [service, setChanged, setValue]); | ||
59 | |||
60 | useEffect( | ||
61 | () => | ||
62 | autorun(() => { | ||
63 | resetValue(); | ||
64 | }), | ||
65 | [resetValue], | ||
66 | ); | ||
67 | |||
68 | const inputRefCallback = useCallback( | ||
69 | (input: HTMLInputElement) => { | ||
70 | setInputFocused( | ||
71 | document.activeElement !== null && document.activeElement === input, | ||
72 | ); | ||
73 | }, | ||
74 | [setInputFocused], | ||
75 | ); | ||
76 | |||
77 | const splitResult = splitUrl(service?.currentUrl); | ||
78 | |||
33 | return ( | 79 | return ( |
34 | <FilledInput | 80 | <LocationTextFieldRoot |
35 | aria-label="Location" | 81 | inputComponent={LocationOverlayInput} |
36 | inputProps={{ | 82 | inputProps={{ |
83 | 'aria-label': 'Location', | ||
37 | spellCheck: false, | 84 | spellCheck: false, |
85 | overlayVisible: !inputFocused && !changed, | ||
86 | overlay: <UrlOverlay splitResult={splitResult} />, | ||
87 | }} | ||
88 | inputRef={inputRefCallback} | ||
89 | onFocus={() => setInputFocused(true)} | ||
90 | onBlur={() => setInputFocused(false)} | ||
91 | onChange={({ target: { value: newValue } }) => { | ||
92 | setValue(newValue); | ||
93 | setChanged(true); | ||
94 | }} | ||
95 | onKeyUp={(event) => { | ||
96 | if (event.key === 'Escape') { | ||
97 | resetValue(); | ||
98 | event.preventDefault(); | ||
99 | } | ||
38 | }} | 100 | }} |
39 | size="small" | 101 | size="small" |
40 | fullWidth | 102 | fullWidth |
41 | hiddenLabel | 103 | hiddenLabel |
42 | disableUnderline | 104 | disableUnderline |
43 | sx={(theme) => ({ | ||
44 | borderRadius: 1, | ||
45 | '&.Mui-focused': { | ||
46 | outline: `2px solid ${theme.palette.primary.main}`, | ||
47 | }, | ||
48 | })} | ||
49 | startAdornment={ | 105 | startAdornment={ |
50 | <InputAdornment position="start"> | 106 | <UrlAdornment changed={changed} splitResult={splitResult} /> |
51 | <IconGlobe fontSize="small" /> | ||
52 | </InputAdornment> | ||
53 | } | 107 | } |
54 | value={service?.currentUrl ?? ''} | 108 | endAdornment={changed ? <GoAdornment /> : undefined} |
109 | value={value} | ||
55 | /> | 110 | /> |
56 | ); | 111 | ); |
57 | } | 112 | } |