aboutsummaryrefslogtreecommitdiffstats
path: root/packages/renderer/src/components/locationBar/LocationTextField.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/renderer/src/components/locationBar/LocationTextField.tsx')
-rw-r--r--packages/renderer/src/components/locationBar/LocationTextField.tsx85
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
21import IconGlobe from '@mui/icons-material/Public';
22import FilledInput from '@mui/material/FilledInput'; 21import FilledInput from '@mui/material/FilledInput';
23import InputAdornment from '@mui/material/InputAdornment'; 22import { styled } from '@mui/material/styles';
24import { Service } from '@sophie/shared'; 23import { Service } from '@sophie/shared';
24import { autorun } from 'mobx';
25import { observer } from 'mobx-react-lite'; 25import { observer } from 'mobx-react-lite';
26import React from 'react'; 26import React, { useCallback, useEffect, useState } from 'react';
27
28import GoAdornment from './GoAdornment';
29import LocationOverlayInput from './LocationOverlayInput';
30import UrlAdornment from './UrlAdornment';
31import UrlOverlay from './UrlOverlay';
32import splitUrl from './splitUrl';
33
34const 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
28function LocationTextField({ 46function 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}