@ -4,6 +4,7 @@ import { motion } from 'framer-motion';
|
||||
|
||||
import { HotkeyScope } from '@/ui/hotkey/types/HotkeyScope';
|
||||
|
||||
import { useBindFieldHotkeyScope } from '../hooks/useBindFieldHotkeyScope';
|
||||
import { useEditableField } from '../hooks/useEditableField';
|
||||
|
||||
import { EditableFieldDisplayMode } from './EditableFieldDisplayMode';
|
||||
@ -43,8 +44,10 @@ export const EditableFieldBaseContainer = styled.div`
|
||||
box-sizing: border-box;
|
||||
|
||||
display: flex;
|
||||
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
height: 24px;
|
||||
justify-content: flex-start;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
|
||||
@ -60,6 +63,7 @@ type OwnProps = {
|
||||
displayModeContent: React.ReactNode;
|
||||
parentHotkeyScope?: HotkeyScope;
|
||||
customEditHotkeyScope?: HotkeyScope;
|
||||
isDisplayModeContentEmpty?: boolean;
|
||||
onSubmit?: () => void;
|
||||
onCancel?: () => void;
|
||||
};
|
||||
@ -73,11 +77,17 @@ export function EditableField({
|
||||
displayModeContent,
|
||||
parentHotkeyScope,
|
||||
customEditHotkeyScope,
|
||||
isDisplayModeContentEmpty,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}: OwnProps) {
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
|
||||
useBindFieldHotkeyScope({
|
||||
customEditHotkeyScope,
|
||||
parentHotkeyScope,
|
||||
});
|
||||
|
||||
function handleContainerMouseEnter() {
|
||||
setIsHovered(true);
|
||||
}
|
||||
@ -86,11 +96,10 @@ export function EditableField({
|
||||
setIsHovered(false);
|
||||
}
|
||||
|
||||
const { isFieldInEditMode, openEditableField } =
|
||||
useEditableField(parentHotkeyScope);
|
||||
const { isFieldInEditMode, openEditableField } = useEditableField();
|
||||
|
||||
function handleDisplayModeClick() {
|
||||
openEditableField(customEditHotkeyScope);
|
||||
openEditableField();
|
||||
}
|
||||
|
||||
const showEditButton = !isFieldInEditMode && isHovered && useEditButton;
|
||||
@ -114,6 +123,7 @@ export function EditableField({
|
||||
<EditableFieldDisplayMode
|
||||
disableClick={useEditButton}
|
||||
onClick={handleDisplayModeClick}
|
||||
isDisplayModeContentEmpty={isDisplayModeContentEmpty}
|
||||
>
|
||||
{displayModeContent}
|
||||
</EditableFieldDisplayMode>
|
||||
|
||||
@ -2,7 +2,7 @@ import { css } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const EditableFieldNormalModeOuterContainer = styled.div<
|
||||
Pick<OwnProps, 'disableClick'>
|
||||
Pick<OwnProps, 'disableClick' | 'isDisplayModeContentEmpty'>
|
||||
>`
|
||||
align-items: center;
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
@ -15,7 +15,18 @@ export const EditableFieldNormalModeOuterContainer = styled.div<
|
||||
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
|
||||
width: 100%;
|
||||
${(props) => {
|
||||
console.log(props.isDisplayModeContentEmpty);
|
||||
if (props.isDisplayModeContentEmpty) {
|
||||
return css`
|
||||
min-width: 50px;
|
||||
`;
|
||||
} else {
|
||||
return css`
|
||||
width: fit-content;
|
||||
`;
|
||||
}
|
||||
}}
|
||||
|
||||
${(props) => {
|
||||
if (props.disableClick) {
|
||||
@ -51,17 +62,20 @@ export const EditableFieldNormalModeInnerContainer = styled.div`
|
||||
type OwnProps = {
|
||||
disableClick?: boolean;
|
||||
onClick?: () => void;
|
||||
isDisplayModeContentEmpty?: boolean;
|
||||
};
|
||||
|
||||
export function EditableFieldDisplayMode({
|
||||
children,
|
||||
disableClick,
|
||||
onClick,
|
||||
isDisplayModeContentEmpty,
|
||||
}: React.PropsWithChildren<OwnProps>) {
|
||||
return (
|
||||
<EditableFieldNormalModeOuterContainer
|
||||
onClick={disableClick ? undefined : onClick}
|
||||
disableClick={disableClick}
|
||||
isDisplayModeContentEmpty={isDisplayModeContentEmpty}
|
||||
>
|
||||
<EditableFieldNormalModeInnerContainer>
|
||||
{children}
|
||||
|
||||
@ -34,7 +34,7 @@ export function EditableFieldEditButton({ customHotkeyScope }: OwnProps) {
|
||||
const { openEditableField } = useEditableField();
|
||||
|
||||
function handleClick() {
|
||||
openEditableField(customHotkeyScope);
|
||||
openEditableField();
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { HotkeyScope } from '@/ui/hotkey/types/HotkeyScope';
|
||||
import { isSameHotkeyScope } from '@/ui/hotkey/utils/isSameHotkeyScope';
|
||||
import { useRecoilScopedState } from '@/ui/recoil-scope/hooks/useRecoilScopedState';
|
||||
|
||||
import { customEditHotkeyScopeForFieldScopedState } from '../states/customEditHotkeyScopeForFieldScopedState';
|
||||
import { FieldContext } from '../states/FieldContext';
|
||||
import { parentHotkeyScopeForFieldScopedState } from '../states/parentHotkeyScopeForFieldScopedState';
|
||||
|
||||
export function useBindFieldHotkeyScope({
|
||||
customEditHotkeyScope,
|
||||
parentHotkeyScope,
|
||||
}: {
|
||||
customEditHotkeyScope?: HotkeyScope;
|
||||
parentHotkeyScope?: HotkeyScope;
|
||||
}) {
|
||||
const [customEditHotkeyScopeForField, setCustomEditHotkeyScopeForField] =
|
||||
useRecoilScopedState(
|
||||
customEditHotkeyScopeForFieldScopedState,
|
||||
FieldContext,
|
||||
);
|
||||
|
||||
const [parentHotkeyScopeForField, setParentHotkeyScopeForField] =
|
||||
useRecoilScopedState(parentHotkeyScopeForFieldScopedState, FieldContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
customEditHotkeyScope &&
|
||||
!isSameHotkeyScope(customEditHotkeyScope, customEditHotkeyScopeForField)
|
||||
) {
|
||||
setCustomEditHotkeyScopeForField(customEditHotkeyScope);
|
||||
}
|
||||
}, [
|
||||
customEditHotkeyScope,
|
||||
customEditHotkeyScopeForField,
|
||||
setCustomEditHotkeyScopeForField,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
parentHotkeyScope &&
|
||||
!isSameHotkeyScope(parentHotkeyScope, parentHotkeyScopeForField)
|
||||
) {
|
||||
setParentHotkeyScopeForField(parentHotkeyScope);
|
||||
}
|
||||
}, [
|
||||
parentHotkeyScope,
|
||||
parentHotkeyScopeForField,
|
||||
setParentHotkeyScopeForField,
|
||||
]);
|
||||
}
|
||||
@ -1,33 +1,50 @@
|
||||
import { useSetHotkeyScope } from '@/ui/hotkey/hooks/useSetHotkeyScope';
|
||||
import { HotkeyScope } from '@/ui/hotkey/types/HotkeyScope';
|
||||
import { useRecoilScopedState } from '@/ui/recoil-scope/hooks/useRecoilScopedState';
|
||||
|
||||
import { customEditHotkeyScopeForFieldScopedState } from '../states/customEditHotkeyScopeForFieldScopedState';
|
||||
import { FieldContext } from '../states/FieldContext';
|
||||
import { isFieldInEditModeScopedState } from '../states/isFieldInEditModeScopedState';
|
||||
import { parentHotkeyScopeForFieldScopedState } from '../states/parentHotkeyScopeForFieldScopedState';
|
||||
import { EditableFieldHotkeyScope } from '../types/EditableFieldHotkeyScope';
|
||||
|
||||
// TODO: use atoms for hotkey scopes
|
||||
export function useEditableField(parentHotkeyScope?: HotkeyScope) {
|
||||
export function useEditableField() {
|
||||
const [isFieldInEditMode, setIsFieldInEditMode] = useRecoilScopedState(
|
||||
isFieldInEditModeScopedState,
|
||||
FieldContext,
|
||||
);
|
||||
|
||||
const [customEditHotkeyScopeForField] = useRecoilScopedState(
|
||||
customEditHotkeyScopeForFieldScopedState,
|
||||
FieldContext,
|
||||
);
|
||||
|
||||
const [parentHotkeyScopeForField] = useRecoilScopedState(
|
||||
parentHotkeyScopeForFieldScopedState,
|
||||
FieldContext,
|
||||
);
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
function closeEditableField() {
|
||||
setIsFieldInEditMode(false);
|
||||
|
||||
if (parentHotkeyScope) {
|
||||
setHotkeyScope(parentHotkeyScope.scope, parentHotkeyScope.customScopes);
|
||||
if (parentHotkeyScopeForField) {
|
||||
setHotkeyScope(
|
||||
parentHotkeyScopeForField.scope,
|
||||
parentHotkeyScopeForField.customScopes,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function openEditableField(customHotkeyScope?: HotkeyScope) {
|
||||
function openEditableField() {
|
||||
setIsFieldInEditMode(true);
|
||||
|
||||
if (customHotkeyScope) {
|
||||
setHotkeyScope(customHotkeyScope.scope, customHotkeyScope.customScopes);
|
||||
if (customEditHotkeyScopeForField) {
|
||||
setHotkeyScope(
|
||||
customEditHotkeyScopeForField.scope,
|
||||
customEditHotkeyScopeForField.customScopes,
|
||||
);
|
||||
} else {
|
||||
setHotkeyScope(EditableFieldHotkeyScope.EditableField);
|
||||
}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
import { HotkeyScope } from '@/ui/hotkey/types/HotkeyScope';
|
||||
|
||||
export const customEditHotkeyScopeForFieldScopedState = atomFamily<
|
||||
HotkeyScope | null,
|
||||
string
|
||||
>({
|
||||
key: 'customEditHotkeyScopeForFieldScopedState',
|
||||
default: null,
|
||||
});
|
||||
@ -0,0 +1,11 @@
|
||||
import { atomFamily } from 'recoil';
|
||||
|
||||
import { HotkeyScope } from '@/ui/hotkey/types/HotkeyScope';
|
||||
|
||||
export const parentHotkeyScopeForFieldScopedState = atomFamily<
|
||||
HotkeyScope | null,
|
||||
string
|
||||
>({
|
||||
key: 'parentHotkeyScopeForFieldScopedState',
|
||||
default: null,
|
||||
});
|
||||
@ -10,12 +10,8 @@ type OwnProps = {
|
||||
parentHotkeyScope?: HotkeyScope;
|
||||
};
|
||||
|
||||
export function EditableFieldEditModeDate({
|
||||
value,
|
||||
onChange,
|
||||
parentHotkeyScope,
|
||||
}: OwnProps) {
|
||||
const { closeEditableField } = useEditableField(parentHotkeyScope);
|
||||
export function EditableFieldEditModeDate({ value, onChange }: OwnProps) {
|
||||
const { closeEditableField } = useEditableField();
|
||||
|
||||
function handleChange(newValue: string) {
|
||||
onChange?.(newValue);
|
||||
|
||||
Reference in New Issue
Block a user