diff options
Diffstat (limited to 'packages/renderer/src/components/locationBar/LocationOverlayInput.tsx')
-rw-r--r-- | packages/renderer/src/components/locationBar/LocationOverlayInput.tsx | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/packages/renderer/src/components/locationBar/LocationOverlayInput.tsx b/packages/renderer/src/components/locationBar/LocationOverlayInput.tsx new file mode 100644 index 0000000..cbb5b06 --- /dev/null +++ b/packages/renderer/src/components/locationBar/LocationOverlayInput.tsx | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com> | ||
3 | * | ||
4 | * This file is part of Sophie. | ||
5 | * | ||
6 | * Sophie is free software: you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU Affero General Public License as | ||
8 | * published by the Free Software Foundation, version 3. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Affero General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Affero General Public License | ||
16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * SPDX-License-Identifier: AGPL-3.0-only | ||
19 | */ | ||
20 | |||
21 | import { styled } from '@mui/material/styles'; | ||
22 | import React, { forwardRef, ForwardedRef } from 'react'; | ||
23 | |||
24 | const inputClassName = 'LocationOverlayInput-Input'; | ||
25 | |||
26 | const overlayClassName = 'LocationOverlayInput-Overlay'; | ||
27 | |||
28 | const clipClassName = 'LocationOverlayInput-Clip'; | ||
29 | |||
30 | const LocationOverlayInputRoot = styled('div', { | ||
31 | name: 'LocationOverlayInput', | ||
32 | slot: 'Root', | ||
33 | shouldForwardProp: (prop) => prop !== 'overlayVisible', | ||
34 | })<{ overlayVisible: boolean }>(({ theme, overlayVisible }) => { | ||
35 | const itemStyle = { | ||
36 | padding: '6px 0 7px 0', | ||
37 | // Set text alignment explicitly so it can be flipped by `stylis-plugin-rtl`. | ||
38 | textAlign: 'left', | ||
39 | }; | ||
40 | return { | ||
41 | display: 'flex', | ||
42 | position: 'relative', | ||
43 | flex: 1, | ||
44 | [`.${inputClassName}`]: { | ||
45 | ...itemStyle, | ||
46 | color: overlayVisible ? 'transparent' : 'inherit', | ||
47 | }, | ||
48 | [`.${overlayClassName}`]: { | ||
49 | ...itemStyle, | ||
50 | display: 'flex', | ||
51 | position: 'absolute', | ||
52 | left: 0, | ||
53 | right: 0, | ||
54 | top: 0, | ||
55 | bottom: 0, | ||
56 | // Text rendering with selected transparent text works better on the bottom in light mode. | ||
57 | zIndex: theme.palette.mode === 'dark' ? 999 : -999, | ||
58 | pointerEvents: 'none', | ||
59 | width: 'auto', | ||
60 | }, | ||
61 | [`.${clipClassName}`]: { | ||
62 | flex: 1, | ||
63 | overflow: 'hidden', | ||
64 | whiteSpace: 'nowrap', | ||
65 | textOverflow: 'clip', | ||
66 | }, | ||
67 | }; | ||
68 | }); | ||
69 | |||
70 | export interface LocationOverlayInputProps | ||
71 | extends React.HTMLProps<HTMLInputElement> { | ||
72 | className?: string | undefined; | ||
73 | |||
74 | overlayVisible?: boolean; | ||
75 | |||
76 | overlay?: JSX.Element | undefined; | ||
77 | } | ||
78 | |||
79 | const LocationOverlayInput = forwardRef( | ||
80 | ( | ||
81 | { overlayVisible, overlay, className, ...props }: LocationOverlayInputProps, | ||
82 | ref: ForwardedRef<HTMLInputElement>, | ||
83 | ) => ( | ||
84 | <LocationOverlayInputRoot overlayVisible={overlayVisible ?? false}> | ||
85 | {/* eslint-disable react/jsx-props-no-spreading -- | ||
86 | Deliberately passing props through to the actual input element. | ||
87 | */} | ||
88 | <input | ||
89 | ref={ref} | ||
90 | className={`${className ?? ''} ${inputClassName}`} | ||
91 | dir="ltr" | ||
92 | {...props} | ||
93 | /> | ||
94 | {/* eslint-enable react/jsx-props-no-spreading */} | ||
95 | {overlayVisible && ( | ||
96 | <div aria-hidden className={`${className ?? ''} ${overlayClassName}`}> | ||
97 | <div className={clipClassName} dir="ltr"> | ||
98 | {overlay} | ||
99 | </div> | ||
100 | </div> | ||
101 | )} | ||
102 | </LocationOverlayInputRoot> | ||
103 | ), | ||
104 | ); | ||
105 | |||
106 | LocationOverlayInput.displayName = 'LocationOverlayInput'; | ||
107 | |||
108 | LocationOverlayInput.defaultProps = { | ||
109 | className: undefined, | ||
110 | overlayVisible: false, | ||
111 | overlay: undefined, | ||
112 | }; | ||
113 | |||
114 | export default LocationOverlayInput; | ||