2282 Rename components to use the new naming convention part 1 (#2293)

renaming in progress
This commit is contained in:
bosiraphael
2023-10-31 12:12:52 +01:00
committed by GitHub
parent 7fe569ec6a
commit ec8389cecf
403 changed files with 458 additions and 455 deletions

View File

@ -0,0 +1,89 @@
import { useContext } from 'react';
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
import { FieldDisplay } from '../../field/components/FieldDisplay';
import { FieldInput } from '../../field/components/FieldInput';
import { FieldContext } from '../../field/contexts/FieldContext';
import { useGetButtonIcon } from '../../field/hooks/useGetButtonIcon';
import { useIsFieldEmpty } from '../../field/hooks/useIsFieldEmpty';
import { useIsFieldInputOnly } from '../../field/hooks/useIsFieldInputOnly';
import { FieldInputEvent } from '../../field/types/FieldInputEvent';
import { isFieldRelation } from '../../field/types/guards/isFieldRelation';
import { useInlineCell } from '../hooks/useInlineCell';
import { InlineCellContainer } from './InlineCellContainer';
export const InlineCell = () => {
const { fieldDefinition } = useContext(FieldContext);
const buttonIcon = useGetButtonIcon();
const isFieldEmpty = useIsFieldEmpty();
const isFieldInputOnly = useIsFieldInputOnly();
const { closeInlineCell } = useInlineCell();
const handleEnter: FieldInputEvent = (persistField) => {
persistField();
closeInlineCell();
};
const handleSubmit: FieldInputEvent = (persistField) => {
persistField();
closeInlineCell();
};
const handleCancel = () => {
closeInlineCell();
};
const handleEscape = () => {
closeInlineCell();
};
const handleTab: FieldInputEvent = (persistField) => {
persistField();
closeInlineCell();
};
const handleShiftTab: FieldInputEvent = (persistField) => {
persistField();
closeInlineCell();
};
const handleClickOutside: FieldInputEvent = (persistField) => {
persistField();
closeInlineCell();
};
return (
<InlineCellContainer
buttonIcon={buttonIcon}
customEditHotkeyScope={
isFieldRelation(fieldDefinition)
? {
scope: RelationPickerHotkeyScope.RelationPicker,
}
: undefined
}
IconLabel={fieldDefinition.Icon}
editModeContent={
<FieldInput
onEnter={handleEnter}
onCancel={handleCancel}
onEscape={handleEscape}
onSubmit={handleSubmit}
onTab={handleTab}
onShiftTab={handleShiftTab}
onClickOutside={handleClickOutside}
/>
}
displayModeContent={<FieldDisplay />}
isDisplayModeContentEmpty={isFieldEmpty}
isDisplayModeFixHeight
editModeContentOnly={isFieldInputOnly}
/>
);
};

View File

@ -0,0 +1,181 @@
import { useState } from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useInlineCell } from '../hooks/useInlineCell';
import { InlineCellDisplayMode } from './InlineCellDisplayMode';
import { InlineCellButton } from './InlineCellEditButton';
import { InlineCellEditMode } from './InlineCellEditMode';
const StyledIconContainer = styled.div`
align-items: center;
color: ${({ theme }) => theme.font.color.tertiary};
display: flex;
width: 16px;
svg {
align-items: center;
display: flex;
height: 16px;
justify-content: center;
width: 16px;
}
`;
const StyledLabelAndIconContainer = styled.div`
align-items: center;
color: ${({ theme }) => theme.font.color.tertiary};
display: flex;
gap: ${({ theme }) => theme.spacing(1)};
`;
const StyledValueContainer = styled.div`
display: flex;
max-width: calc(100% - ${({ theme }) => theme.spacing(4)});
`;
const StyledLabel = styled.div<
Pick<InlineCellContainerProps, 'labelFixedWidth'>
>`
align-items: center;
width: ${({ labelFixedWidth }) =>
labelFixedWidth ? `${labelFixedWidth}px` : 'fit-content'};
`;
const StyledEditButtonContainer = styled(motion.div)`
align-items: center;
display: flex;
`;
const StyledClickableContainer = styled.div`
cursor: pointer;
display: flex;
gap: ${({ theme }) => theme.spacing(1)};
width: 100%;
`;
const StyledInlineCellBaseContainer = styled.div`
align-items: center;
box-sizing: border-box;
display: flex;
gap: ${({ theme }) => theme.spacing(1)};
position: relative;
user-select: none;
width: 100%;
`;
type InlineCellContainerProps = {
IconLabel?: IconComponent;
label?: string;
labelFixedWidth?: number;
buttonIcon?: IconComponent;
editModeContent?: React.ReactNode;
editModeContentOnly?: boolean;
displayModeContent: React.ReactNode;
customEditHotkeyScope?: HotkeyScope;
isDisplayModeContentEmpty?: boolean;
isDisplayModeFixHeight?: boolean;
disableHoverEffect?: boolean;
};
export const InlineCellContainer = ({
IconLabel,
label,
labelFixedWidth,
buttonIcon,
editModeContent,
displayModeContent,
customEditHotkeyScope,
isDisplayModeContentEmpty,
editModeContentOnly,
isDisplayModeFixHeight,
disableHoverEffect,
}: InlineCellContainerProps) => {
const [isHovered, setIsHovered] = useState(false);
const handleContainerMouseEnter = () => {
setIsHovered(true);
};
const handleContainerMouseLeave = () => {
setIsHovered(false);
};
const { isInlineCellInEditMode, openInlineCell } = useInlineCell();
const handleDisplayModeClick = () => {
if (!editModeContentOnly) {
openInlineCell(customEditHotkeyScope);
}
};
const showEditButton =
buttonIcon && !isInlineCellInEditMode && isHovered && !editModeContentOnly;
const theme = useTheme();
return (
<StyledInlineCellBaseContainer
onMouseEnter={handleContainerMouseEnter}
onMouseLeave={handleContainerMouseLeave}
>
<StyledLabelAndIconContainer>
{IconLabel && (
<StyledIconContainer>
<IconLabel stroke={theme.icon.stroke.sm} />
</StyledIconContainer>
)}
{label && (
<StyledLabel labelFixedWidth={labelFixedWidth}>{label}</StyledLabel>
)}
</StyledLabelAndIconContainer>
<StyledValueContainer>
{isInlineCellInEditMode ? (
<InlineCellEditMode>{editModeContent}</InlineCellEditMode>
) : editModeContentOnly ? (
<StyledClickableContainer>
<InlineCellDisplayMode
disableHoverEffect={disableHoverEffect}
isDisplayModeContentEmpty={isDisplayModeContentEmpty}
isDisplayModeFixHeight={isDisplayModeFixHeight}
isHovered={isHovered}
>
{editModeContent}
</InlineCellDisplayMode>
</StyledClickableContainer>
) : (
<StyledClickableContainer onClick={handleDisplayModeClick}>
<InlineCellDisplayMode
disableHoverEffect={disableHoverEffect}
isDisplayModeContentEmpty={isDisplayModeContentEmpty}
isDisplayModeFixHeight={isDisplayModeFixHeight}
isHovered={isHovered}
>
{displayModeContent}
</InlineCellDisplayMode>
{showEditButton && (
<StyledEditButtonContainer
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.1 }}
whileHover={{ scale: 1.04 }}
>
<InlineCellButton Icon={buttonIcon} />
</StyledEditButtonContainer>
)}
</StyledClickableContainer>
)}
</StyledValueContainer>
</StyledInlineCellBaseContainer>
);
};

View File

@ -0,0 +1,81 @@
import { css } from '@emotion/react';
import styled from '@emotion/styled';
const StyledInlineCellNormalModeOuterContainer = styled.div<
Pick<
InlineCellDisplayModeProps,
| 'isDisplayModeContentEmpty'
| 'disableHoverEffect'
| 'isDisplayModeFixHeight'
| 'isHovered'
>
>`
align-items: center;
border-radius: ${({ theme }) => theme.border.radius.sm};
display: flex;
height: ${({ isDisplayModeFixHeight }) =>
isDisplayModeFixHeight ? '16px' : 'auto'};
min-height: 16px;
overflow: hidden;
padding: ${({ theme }) => theme.spacing(1)};
${(props) => {
if (props.isHovered) {
return css`
background-color: ${!props.disableHoverEffect
? props.theme.background.transparent.light
: 'transparent'};
cursor: pointer;
`;
}
}}
`;
const StyledInlineCellNormalModeInnerContainer = styled.div`
align-items: center;
color: ${({ theme }) => theme.font.color.primary};
font-size: 'inherit';
font-weight: 'inherit';
height: fit-content;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
const StyledEmptyField = styled.div`
color: ${({ theme }) => theme.font.color.light};
`;
type InlineCellDisplayModeProps = {
isDisplayModeContentEmpty?: boolean;
disableHoverEffect?: boolean;
isDisplayModeFixHeight?: boolean;
isHovered?: boolean;
};
export const InlineCellDisplayMode = ({
children,
isDisplayModeContentEmpty,
disableHoverEffect,
isDisplayModeFixHeight,
isHovered,
}: React.PropsWithChildren<InlineCellDisplayModeProps>) => (
<StyledInlineCellNormalModeOuterContainer
isDisplayModeContentEmpty={isDisplayModeContentEmpty}
disableHoverEffect={disableHoverEffect}
isDisplayModeFixHeight={isDisplayModeFixHeight}
isHovered={isHovered}
>
<StyledInlineCellNormalModeInnerContainer>
{isDisplayModeContentEmpty || !children ? (
<StyledEmptyField>{'Empty'}</StyledEmptyField>
) : (
children
)}
</StyledInlineCellNormalModeInnerContainer>
</StyledInlineCellNormalModeOuterContainer>
);

View File

@ -0,0 +1,21 @@
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { FloatingIconButton } from '@/ui/input/button/components/FloatingIconButton';
import { useInlineCell } from '../hooks/useInlineCell';
export const InlineCellButton = ({ Icon }: { Icon: IconComponent }) => {
const { openInlineCell } = useInlineCell();
const handleClick = () => {
openInlineCell();
};
return (
<FloatingIconButton
size="small"
onClick={handleClick}
Icon={Icon}
data-testid="inline-cell-edit-mode-container"
/>
);
};

View File

@ -0,0 +1,34 @@
import styled from '@emotion/styled';
const StyledInlineCellEditModeContainer = styled.div<InlineCellEditModeProps>`
align-items: center;
display: flex;
height: 24px;
margin-left: -${({ theme }) => theme.spacing(1)};
position: relative;
z-index: 10;
`;
const StyledInlineCellInput = styled.div`
align-items: center;
display: flex;
margin-left: -1px;
min-height: 32px;
min-width: 200px;
width: inherit;
z-index: 10;
`;
type InlineCellEditModeProps = {
children: React.ReactNode;
};
export const InlineCellEditMode = ({ children }: InlineCellEditModeProps) => (
<StyledInlineCellEditModeContainer data-testid="inline-cell-edit-mode-container">
<StyledInlineCellInput>{children}</StyledInlineCellInput>
</StyledInlineCellEditModeContainer>
);

View File

@ -0,0 +1,3 @@
import { createContext } from 'react';
export const InlineCellMutationContext = createContext<any>(undefined);

View File

@ -0,0 +1,47 @@
import { useContext } from 'react';
import { useRecoilState } from 'recoil';
import { FieldContext } from '@/ui/object/field/contexts/FieldContext';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { isInlineCellInEditModeScopedState } from '../states/isInlineCellInEditModeScopedState';
import { InlineCellHotkeyScope } from '../types/InlineCellHotkeyScope';
export const useInlineCell = () => {
const { recoilScopeId } = useContext(FieldContext);
const [isInlineCellInEditMode, setIsInlineCellInEditMode] = useRecoilState(
isInlineCellInEditModeScopedState(recoilScopeId),
);
const {
setHotkeyScopeAndMemorizePreviousScope,
goBackToPreviousHotkeyScope,
} = usePreviousHotkeyScope();
const closeInlineCell = () => {
setIsInlineCellInEditMode(false);
goBackToPreviousHotkeyScope();
};
const openInlineCell = (customEditHotkeyScopeForField?: HotkeyScope) => {
setIsInlineCellInEditMode(true);
if (customEditHotkeyScopeForField) {
setHotkeyScopeAndMemorizePreviousScope(
customEditHotkeyScopeForField.scope,
customEditHotkeyScopeForField.customScopes,
);
} else {
setHotkeyScopeAndMemorizePreviousScope(InlineCellHotkeyScope.InlineCell);
}
};
return {
isInlineCellInEditMode,
closeInlineCell,
openInlineCell,
};
};

View File

@ -0,0 +1,21 @@
import styled from '@emotion/styled';
const StyledPropertyBoxContainer = styled.div`
align-self: stretch;
background: ${({ theme }) => theme.background.secondary};
border: 1px solid ${({ theme }) => theme.border.color.medium};
border-radius: ${({ theme }) => theme.border.radius.sm};
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(2)};
padding: ${({ theme }) => theme.spacing(3)};
`;
interface PropertyBoxProps {
children: React.ReactNode;
extraPadding?: boolean;
}
export const PropertyBox = ({ children }: PropertyBoxProps) => (
<StyledPropertyBoxContainer>{children}</StyledPropertyBoxContainer>
);

View File

@ -0,0 +1,11 @@
import { atomFamily } from 'recoil';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
export const customEditHotkeyScopeForFieldScopedState = atomFamily<
HotkeyScope | null,
string
>({
key: 'customEditHotkeyScopeForFieldScopedState',
default: null,
});

View File

@ -0,0 +1,6 @@
import { atomFamily } from 'recoil';
export const isInlineCellInEditModeScopedState = atomFamily<boolean, string>({
key: 'isInlineCellInEditModeScopedState',
default: false,
});

View File

@ -0,0 +1,11 @@
import { atomFamily } from 'recoil';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
export const parentHotkeyScopeForFieldScopedState = atomFamily<
HotkeyScope | null,
string
>({
key: 'parentHotkeyScopeForFieldScopedState',
default: null,
});

View File

@ -0,0 +1,3 @@
import { createContext } from 'react';
export const FieldRecoilScopeContext = createContext<string | null>(null);

View File

@ -0,0 +1,3 @@
export enum InlineCellHotkeyScope {
InlineCell = 'inline-cell',
}