When fields are not displayed in show page, title should be editable https://github.com/user-attachments/assets/049c2998-6944-46c7-9e9e-f6d29da06c6c
141 lines
3.8 KiB
TypeScript
141 lines
3.8 KiB
TypeScript
import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper';
|
|
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
|
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
|
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
|
import { useTheme } from '@emotion/react';
|
|
import styled from '@emotion/styled';
|
|
import { ChangeEvent, FocusEvent, useRef } from 'react';
|
|
import { useRecoilState } from 'recoil';
|
|
import { Key } from 'ts-key-enum';
|
|
import {
|
|
IconComponent,
|
|
isDefined,
|
|
TablerIconsProps,
|
|
TEXT_INPUT_STYLE,
|
|
} from 'twenty-ui';
|
|
import { useHotkeyScopeOnMount } from '~/hooks/useHotkeyScopeOnMount';
|
|
|
|
type NavigationDrawerInputProps = {
|
|
className?: string;
|
|
Icon?: IconComponent | ((props: TablerIconsProps) => JSX.Element);
|
|
value: string;
|
|
onChange: (value: string) => void;
|
|
onSubmit: (value: string) => void;
|
|
onCancel: (value: string) => void;
|
|
onClickOutside: (event: MouseEvent | TouchEvent, value: string) => void;
|
|
hotkeyScope: string;
|
|
};
|
|
|
|
const StyledItem = styled.div<{ isNavigationDrawerExpanded: boolean }>`
|
|
align-items: center;
|
|
background-color: ${({ theme }) => theme.background.primary};
|
|
border: 1px solid ${({ theme }) => theme.color.blue};
|
|
border-radius: ${({ theme }) => theme.border.radius.sm};
|
|
box-sizing: content-box;
|
|
color: ${({ theme }) => theme.font.color.primary};
|
|
display: flex;
|
|
font-family: ${({ theme }) => theme.font.family};
|
|
font-size: ${({ theme }) => theme.font.size.md};
|
|
height: calc(${({ theme }) => theme.spacing(5)} - 2px);
|
|
padding: ${({ theme }) => theme.spacing(1)};
|
|
text-decoration: none;
|
|
user-select: none;
|
|
`;
|
|
|
|
const StyledItemElementsContainer = styled.span`
|
|
align-items: center;
|
|
gap: ${({ theme }) => theme.spacing(2)};
|
|
display: flex;
|
|
width: 100%;
|
|
`;
|
|
|
|
const StyledTextInput = styled.input`
|
|
${TEXT_INPUT_STYLE}
|
|
margin: 0;
|
|
width: 100%;
|
|
padding: 0;
|
|
`;
|
|
|
|
export const NavigationDrawerInput = ({
|
|
className,
|
|
Icon,
|
|
value,
|
|
onChange,
|
|
onSubmit,
|
|
onCancel,
|
|
onClickOutside,
|
|
hotkeyScope,
|
|
}: NavigationDrawerInputProps) => {
|
|
const theme = useTheme();
|
|
const [isNavigationDrawerExpanded] = useRecoilState(
|
|
isNavigationDrawerExpandedState,
|
|
);
|
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
|
|
useHotkeyScopeOnMount(hotkeyScope);
|
|
|
|
useScopedHotkeys(
|
|
[Key.Escape],
|
|
() => {
|
|
onCancel(value);
|
|
},
|
|
hotkeyScope,
|
|
);
|
|
|
|
useScopedHotkeys(
|
|
[Key.Enter],
|
|
() => {
|
|
onSubmit(value);
|
|
},
|
|
hotkeyScope,
|
|
);
|
|
|
|
useListenClickOutside({
|
|
refs: [inputRef],
|
|
callback: (event) => {
|
|
event.stopImmediatePropagation();
|
|
onClickOutside(event, value);
|
|
},
|
|
listenerId: 'navigation-drawer-input',
|
|
});
|
|
|
|
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
onChange(event.target.value);
|
|
};
|
|
|
|
const handleFocus = (event: FocusEvent<HTMLInputElement>) => {
|
|
if (isDefined(value)) {
|
|
event.target.select();
|
|
}
|
|
};
|
|
|
|
return (
|
|
<StyledItem
|
|
className={className}
|
|
isNavigationDrawerExpanded={isNavigationDrawerExpanded}
|
|
>
|
|
<StyledItemElementsContainer>
|
|
{Icon && (
|
|
<Icon
|
|
style={{
|
|
minWidth: theme.icon.size.md,
|
|
}}
|
|
size={theme.icon.size.md}
|
|
stroke={theme.icon.stroke.md}
|
|
color="currentColor"
|
|
/>
|
|
)}
|
|
<NavigationDrawerAnimatedCollapseWrapper>
|
|
<StyledTextInput
|
|
ref={inputRef}
|
|
value={value}
|
|
onChange={handleChange}
|
|
onFocus={handleFocus}
|
|
autoFocus
|
|
/>
|
|
</NavigationDrawerAnimatedCollapseWrapper>
|
|
</StyledItemElementsContainer>
|
|
</StyledItem>
|
|
);
|
|
};
|