Clean and re-organize post table refactoring (#1000)

* Clean and re-organize post table refactoring

* Fix tests
This commit is contained in:
Charles Bochet
2023-07-30 18:26:32 -07:00
committed by GitHub
parent 86a2d67efd
commit ade5e52e55
336 changed files with 638 additions and 2757 deletions

View File

@ -1,7 +1,7 @@
import { ReactElement } from 'react';
import styled from '@emotion/styled';
import { HotkeyScope } from '@/ui/hotkey/types/HotkeyScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { CellHotkeyScopeContext } from '../../states/CellHotkeyScopeContext';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';

View File

@ -1,7 +1,7 @@
import { ReactElement } from 'react';
import styled from '@emotion/styled';
import { overlayBackground } from '@/ui/themes/effects';
import { overlayBackground } from '@/ui/theme/constants/effects';
export const EditableCellEditModeContainer = styled.div<OwnProps>`
align-items: center;

View File

@ -1,7 +1,7 @@
import { PropsWithChildren } from 'react';
import { useScopedHotkeys } from '@/ui/hotkey/hooks/useScopedHotkeys';
import { isNonTextWritingKey } from '@/ui/hotkey/utils/isNonTextWritingKey';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { isNonTextWritingKey } from '@/ui/utilities/hotkey/utils/isNonTextWritingKey';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
import { useEditableCell } from '../hooks/useEditableCell';

View File

@ -0,0 +1,54 @@
import {
ViewFieldDefinition,
ViewFieldMetadata,
} from '@/ui/table/types/ViewField';
import { isViewFieldChip } from '../../types/guards/isViewFieldChip';
import { isViewFieldDate } from '../../types/guards/isViewFieldDate';
import { isViewFieldDoubleText } from '../../types/guards/isViewFieldDoubleText';
import { isViewFieldDoubleTextChip } from '../../types/guards/isViewFieldDoubleTextChip';
import { isViewFieldNumber } from '../../types/guards/isViewFieldNumber';
import { isViewFieldPhone } from '../../types/guards/isViewFieldPhone';
import { isViewFieldRelation } from '../../types/guards/isViewFieldRelation';
import { isViewFieldText } from '../../types/guards/isViewFieldText';
import { isViewFieldURL } from '../../types/guards/isViewFieldURL';
import { GenericEditableChipCell } from '../type/components/GenericEditableChipCell';
import { GenericEditableDateCell } from '../type/components/GenericEditableDateCell';
import { GenericEditableDoubleTextCell } from '../type/components/GenericEditableDoubleTextCell';
import { GenericEditableDoubleTextChipCell } from '../type/components/GenericEditableDoubleTextChipCell';
import { GenericEditableNumberCell } from '../type/components/GenericEditableNumberCell';
import { GenericEditablePhoneCell } from '../type/components/GenericEditablePhoneCell';
import { GenericEditableRelationCell } from '../type/components/GenericEditableRelationCell';
import { GenericEditableTextCell } from '../type/components/GenericEditableTextCell';
import { GenericEditableURLCell } from '../type/components/GenericEditableURLCell';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldMetadata>;
};
export function GenericEditableCell({ viewField: fieldDefinition }: OwnProps) {
if (isViewFieldText(fieldDefinition)) {
return <GenericEditableTextCell viewField={fieldDefinition} />;
} else if (isViewFieldRelation(fieldDefinition)) {
return <GenericEditableRelationCell fieldDefinition={fieldDefinition} />;
} else if (isViewFieldDoubleTextChip(fieldDefinition)) {
return <GenericEditableDoubleTextChipCell viewField={fieldDefinition} />;
} else if (isViewFieldDoubleText(fieldDefinition)) {
return <GenericEditableDoubleTextCell viewField={fieldDefinition} />;
} else if (isViewFieldPhone(fieldDefinition)) {
return <GenericEditablePhoneCell viewField={fieldDefinition} />;
} else if (isViewFieldURL(fieldDefinition)) {
return <GenericEditableURLCell viewField={fieldDefinition} />;
} else if (isViewFieldDate(fieldDefinition)) {
return <GenericEditableDateCell viewField={fieldDefinition} />;
} else if (isViewFieldNumber(fieldDefinition)) {
return <GenericEditableNumberCell viewField={fieldDefinition} />;
} else if (isViewFieldChip(fieldDefinition)) {
return <GenericEditableChipCell viewField={fieldDefinition} />;
} else {
console.warn(
`Unknown field metadata type: ${fieldDefinition.metadata.type} in GenericEditableCell`,
);
return <></>;
}
}

View File

@ -1,60 +0,0 @@
import { expect } from '@storybook/jest';
import type { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library';
import { CellPositionDecorator } from '~/testing/decorators/CellPositionDecorator';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { sleep } from '~/testing/sleep';
import { EditableCellText } from '../../types/EditableCellText';
const meta: Meta<typeof EditableCellText> = {
title: 'UI/EditableCell/EditableCellText',
component: EditableCellText,
decorators: [ComponentDecorator, CellPositionDecorator],
args: {
value: 'Content',
},
};
export default meta;
type Story = StoryObj<typeof EditableCellText>;
export const DisplayMode: Story = {
render: EditableCellText,
};
export const SoftFocusMode: Story = {
...DisplayMode,
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
const content = await canvas.findByText('Content');
await userEvent.click(content);
await userEvent.keyboard('{esc}');
await sleep(10);
await step('Has soft focus mode', () => {
expect(canvas.getByTestId('editable-cell-soft-focus-mode')).toBeDefined();
});
},
};
export const EditMode: Story = {
...DisplayMode,
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
const click = () => userEvent.click(canvas.getByText('Content'));
await step('Click once', click);
await step('Has edit mode', () => {
expect(
canvas.getByTestId('editable-cell-edit-mode-container'),
).toBeDefined();
});
},
};

View File

@ -1,7 +1,7 @@
import { useContext } from 'react';
import { useSetHotkeyScope } from '@/ui/hotkey/hooks/useSetHotkeyScope';
import { HotkeyScope } from '@/ui/hotkey/types/HotkeyScope';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { useCloseCurrentCellInEditMode } from '../../hooks/useClearCellInEditMode';
import { CellHotkeyScopeContext } from '../../states/CellHotkeyScopeContext';

View File

@ -1,5 +1,5 @@
import { useListenClickOutside } from '@/ui/hooks/useListenClickOutside';
import { useScopedHotkeys } from '@/ui/hotkey/hooks/useScopedHotkeys';
import { useListenClickOutside } from '@/ui/utilities/click-outside/hooks/useListenClickOutside';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useMoveSoftFocus } from '../../hooks/useMoveSoftFocus';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';

View File

@ -1,6 +1,6 @@
import { useRecoilCallback } from 'recoil';
import { useSetHotkeyScope } from '@/ui/hotkey/hooks/useSetHotkeyScope';
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
import { useSetSoftFocusPosition } from '../../hooks/useSetSoftFocusPosition';
import { isSoftFocusActiveState } from '../../states/isSoftFocusActiveState';

View File

@ -2,12 +2,12 @@ import { useRef } from 'react';
import styled from '@emotion/styled';
import { Key } from 'ts-key-enum';
import { useScopedHotkeys } from '@/ui/hotkey/hooks/useScopedHotkeys';
import { InplaceInputDate } from '@/ui/inplace-input/components/InplaceInputDate';
import { DateInputEdit } from '@/ui/input/date/components/DateInputEdit';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import { useListenClickOutside } from '@/ui/utilities/click-outside/hooks/useListenClickOutside';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useListenClickOutside } from '../../../hooks/useListenClickOutside';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
import { useEditableCell } from '../hooks/useEditableCell';
import { useEditableCell } from '../../hooks/useEditableCell';
const EditableCellDateEditModeContainer = styled.div`
margin-top: -1px;
@ -19,10 +19,7 @@ export type EditableDateProps = {
onSubmit: (date: Date) => void;
};
export function EditableCellDateEditMode({
value,
onSubmit,
}: EditableDateProps) {
export function DateCellEdit({ value, onSubmit }: EditableDateProps) {
const { closeEditableCell } = useEditableCell();
function handleDateChange(newDate: Date) {
@ -55,7 +52,7 @@ export function EditableCellDateEditMode({
return (
<EditableCellDateEditModeContainer ref={containerRef}>
<InplaceInputDate onChange={handleDateChange} value={value} />
<DateInputEdit onChange={handleDateChange} value={value} />
</EditableCellDateEditModeContainer>
);
}

View File

@ -2,13 +2,14 @@ import { ChangeEvent, useEffect, useRef, useState } from 'react';
import styled from '@emotion/styled';
import { Key } from 'ts-key-enum';
import { useScopedHotkeys } from '@/ui/hotkey/hooks/useScopedHotkeys';
import { StyledInput } from '@/ui/inplace-input/components/InplaceInputTextCellEditMode';
import { useMoveSoftFocus } from '@/ui/table/hooks/useMoveSoftFocus';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import { useMoveSoftFocus } from '../../hooks/useMoveSoftFocus';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
import { useEditableCell } from '../hooks/useEditableCell';
import { useRegisterCloseCellHandlers } from '../hooks/useRegisterCloseCellHandlers';
import { useEditableCell } from '../../hooks/useEditableCell';
import { useRegisterCloseCellHandlers } from '../../hooks/useRegisterCloseCellHandlers';
import { StyledInput } from './TextCellEdit';
type OwnProps = {
firstValue: string;
@ -35,7 +36,7 @@ const StyledContainer = styled.div`
}
`;
export function EditableCellDoubleTextEditMode({
export function DoubleTextCellEdit({
firstValue,
secondValue,
firstValuePlaceholder,

View File

@ -0,0 +1,31 @@
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import {
ViewFieldChipMetadata,
ViewFieldDefinition,
} from '@/ui/table/types/ViewField';
import { GenericEditableChipCellDisplayMode } from './GenericEditableChipCellDisplayMode';
import { GenericEditableChipCellEditMode } from './GenericEditableChipCellEditMode';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldChipMetadata>;
editModeHorizontalAlign?: 'left' | 'right';
placeholder?: string;
};
export function GenericEditableChipCell({
viewField,
editModeHorizontalAlign,
}: OwnProps) {
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<GenericEditableChipCellEditMode viewField={viewField} />
}
nonEditModeContent={
<GenericEditableChipCellDisplayMode fieldDefinition={viewField} />
}
></EditableCell>
);
}

View File

@ -0,0 +1,52 @@
import { useRecoilValue } from 'recoil';
import { CompanyChip } from '@/companies/components/CompanyChip';
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldChipMetadata,
ViewFieldDefinition,
} from '@/ui/table/types/ViewField';
import { getLogoUrlFromDomainName } from '~/utils';
type OwnProps = {
fieldDefinition: ViewFieldDefinition<ViewFieldChipMetadata>;
};
export function GenericEditableChipCellDisplayMode({
fieldDefinition,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const content = useRecoilValue<any | null>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: fieldDefinition.metadata.contentFieldName,
}),
);
const chipUrl = useRecoilValue<any | null>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: fieldDefinition.metadata.urlFieldName,
}),
);
switch (fieldDefinition.metadata.relationType) {
case Entity.Company: {
return (
<CompanyChip
id={currentRowEntityId ?? ''}
name={content ?? ''}
pictureUrl={getLogoUrlFromDomainName(chipUrl)}
/>
);
}
default:
console.warn(
`Unknown relation type: "${fieldDefinition.metadata.relationType}" in GenericEditableChipCellEditMode`,
);
return <> </>;
}
}

View File

@ -0,0 +1,48 @@
import { useRecoilState } from 'recoil';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldChipMetadata,
ViewFieldDefinition,
} from '@/ui/table/types/ViewField';
import { TextCellEdit } from './TextCellEdit';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldChipMetadata>;
};
export function GenericEditableChipCellEditMode({ viewField }: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
// TODO: we could use a hook that would return the field value with the right type
const [fieldValue, setFieldValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.contentFieldName,
}),
);
const updateField = useUpdateEntityField();
function handleSubmit(newText: string) {
if (newText === fieldValue) return;
setFieldValue(newText);
if (currentRowEntityId && updateField) {
updateField(currentRowEntityId, viewField, newText);
}
}
return (
<TextCellEdit
placeholder={viewField.metadata.placeHolder ?? ''}
autoFocus
value={fieldValue ?? ''}
onSubmit={handleSubmit}
/>
);
}

View File

@ -0,0 +1,41 @@
import { useRecoilValue } from 'recoil';
import { DateInputDisplay } from '@/ui/input/date/components/DateInputDisplay';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDateMetadata,
ViewFieldDefinition,
} from '@/ui/table/types/ViewField';
import { GenericEditableDateCellEditMode } from './GenericEditableDateCellEditMode';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldDateMetadata>;
editModeHorizontalAlign?: 'left' | 'right';
};
export function GenericEditableDateCell({
viewField,
editModeHorizontalAlign,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const fieldValue = useRecoilValue<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName,
}),
);
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<GenericEditableDateCellEditMode viewField={viewField} />
}
nonEditModeContent={<DateInputDisplay value={fieldValue} />}
></EditableCell>
);
}

View File

@ -0,0 +1,53 @@
import { DateTime } from 'luxon';
import { useRecoilState } from 'recoil';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDateMetadata,
ViewFieldDefinition,
} from '@/ui/table/types/ViewField';
import { DateCellEdit } from './DateCellEdit';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldDateMetadata>;
};
export function GenericEditableDateCellEditMode({ viewField }: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
// TODO: we could use a hook that would return the field value with the right type
const [fieldValue, setFieldValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName,
}),
);
const updateField = useUpdateEntityField();
function handleSubmit(newDate: Date) {
const fieldValueDate = fieldValue
? DateTime.fromISO(fieldValue).toJSDate()
: null;
const newDateISO = DateTime.fromJSDate(newDate).toISO();
if (newDate === fieldValueDate || !newDateISO) return;
setFieldValue(newDateISO);
if (currentRowEntityId && updateField && newDateISO) {
updateField(currentRowEntityId, viewField, newDateISO);
}
}
return (
<DateCellEdit
value={DateTime.fromISO(fieldValue).toJSDate()}
onSubmit={handleSubmit}
/>
);
}

View File

@ -0,0 +1,45 @@
import { useRecoilValue } from 'recoil';
import { TextInputDisplay } from '@/ui/input/text/components/TextInputDisplay';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldDoubleTextMetadata,
} from '@/ui/table/types/ViewField';
import { GenericEditableDoubleTextCellEditMode } from './GenericEditableDoubleTextCellEditMode';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldDoubleTextMetadata>;
};
export function GenericEditableDoubleTextCell({ viewField }: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const firstValue = useRecoilValue<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.firstValueFieldName,
}),
);
const secondValue = useRecoilValue<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.secondValueFieldName,
}),
);
const displayName = `${firstValue ?? ''} ${secondValue ?? ''}`;
return (
<EditableCell
editModeContent={
<GenericEditableDoubleTextCellEditMode viewField={viewField} />
}
nonEditModeContent={<TextInputDisplay>{displayName}</TextInputDisplay>}
></EditableCell>
);
}

View File

@ -0,0 +1,60 @@
import { useRecoilState } from 'recoil';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldDoubleTextMetadata,
} from '@/ui/table/types/ViewField';
import { DoubleTextCellEdit } from './DoubleTextCellEdit';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldDoubleTextMetadata>;
};
export function GenericEditableDoubleTextCellEditMode({ viewField }: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
// TODO: we could use a hook that would return the field value with the right type
const [firstValue, setFirstValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.firstValueFieldName,
}),
);
const [secondValue, setSecondValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.firstValueFieldName,
}),
);
const updateField = useUpdateEntityField();
function handleSubmit(newFirstValue: string, newSecondValue: string) {
if (newFirstValue === firstValue && newSecondValue === secondValue) return;
setFirstValue(newFirstValue);
setSecondValue(newSecondValue);
if (currentRowEntityId && updateField) {
updateField(currentRowEntityId, viewField, {
firstValue: newFirstValue,
secondValue: newSecondValue,
});
}
}
return (
<DoubleTextCellEdit
firstValuePlaceholder={viewField.metadata.firstValuePlaceholder}
secondValuePlaceholder={viewField.metadata.secondValuePlaceholder}
firstValue={firstValue ?? ''}
secondValue={secondValue ?? ''}
onSubmit={handleSubmit}
/>
);
}

View File

@ -0,0 +1,27 @@
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { TableHotkeyScope } from '@/ui/table/types/TableHotkeyScope';
import {
ViewFieldDefinition,
ViewFieldDoubleTextChipMetadata,
} from '@/ui/table/types/ViewField';
import { GenericEditableDoubleTextChipCellDisplayMode } from './GenericEditableDoubleTextChipCellDisplayMode';
import { GenericEditableDoubleTextChipCellEditMode } from './GenericEditableDoubleTextChipCellEditMode';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldDoubleTextChipMetadata>;
};
export function GenericEditableDoubleTextChipCell({ viewField }: OwnProps) {
return (
<EditableCell
editHotkeyScope={{ scope: TableHotkeyScope.CellDoubleTextInput }}
editModeContent={
<GenericEditableDoubleTextChipCellEditMode viewField={viewField} />
}
nonEditModeContent={
<GenericEditableDoubleTextChipCellDisplayMode viewField={viewField} />
}
></EditableCell>
);
}

View File

@ -0,0 +1,64 @@
import { useRecoilState } from 'recoil';
import { CompanyChip } from '@/companies/components/CompanyChip';
import { PersonChip } from '@/people/components/PersonChip';
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldDoubleTextChipMetadata,
} from '@/ui/table/types/ViewField';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldDoubleTextChipMetadata>;
};
export function GenericEditableDoubleTextChipCellDisplayMode({
viewField,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const [firstValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.firstValueFieldName,
}),
);
const [secondValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.secondValueFieldName,
}),
);
const [avatarUrlValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.avatarUrlFieldName,
}),
);
const displayName = `${firstValue} ${secondValue}`;
switch (viewField.metadata.entityType) {
case Entity.Company: {
return <CompanyChip id={currentRowEntityId ?? ''} name={displayName} />;
}
case Entity.Person: {
return (
<PersonChip
id={currentRowEntityId ?? ''}
name={displayName}
pictureUrl={avatarUrlValue}
/>
);
}
default:
console.warn(
`Unknown relation type: "${viewField.metadata.entityType}" in GenericEditableDoubleTextChipCellDisplayMode`,
);
return <> </>;
}
}

View File

@ -0,0 +1,72 @@
import { useRecoilState } from 'recoil';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldDoubleTextChipMetadata,
} from '@/ui/table/types/ViewField';
import { DoubleTextCellEdit } from './DoubleTextCellEdit';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldDoubleTextChipMetadata>;
};
export function GenericEditableDoubleTextChipCellEditMode({
viewField,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
// TODO: we could use a hook that would return the field value with the right type
const [firstValue, setFirstValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.firstValueFieldName,
}),
);
const [secondValue, setSecondValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.secondValueFieldName,
}),
);
const updateField = useUpdateEntityField();
function handleSubmit(newFirstValue: string, newSecondValue: string) {
const firstValueChanged = newFirstValue !== firstValue;
const secondValueChanged = newSecondValue !== secondValue;
if (firstValueChanged) {
setFirstValue(newFirstValue);
}
if (secondValueChanged) {
setSecondValue(newSecondValue);
}
if (
currentRowEntityId &&
updateField &&
(firstValueChanged || secondValueChanged)
) {
updateField(currentRowEntityId, viewField, {
firstValue: firstValueChanged ? newFirstValue : firstValue,
secondValue: secondValueChanged ? newSecondValue : secondValue,
});
}
}
return (
<DoubleTextCellEdit
firstValuePlaceholder={viewField.metadata.firstValuePlaceholder}
secondValuePlaceholder={viewField.metadata.secondValuePlaceholder}
firstValue={firstValue ?? ''}
secondValue={secondValue ?? ''}
onSubmit={handleSubmit}
/>
);
}

View File

@ -0,0 +1,40 @@
import { useRecoilValue } from 'recoil';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldNumberMetadata,
} from '@/ui/table/types/ViewField';
import { GenericEditableNumberCellEditMode } from './GenericEditableNumberCellEditMode';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldNumberMetadata>;
editModeHorizontalAlign?: 'left' | 'right';
};
export function GenericEditableNumberCell({
viewField,
editModeHorizontalAlign,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const fieldValue = useRecoilValue<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName,
}),
);
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<GenericEditableNumberCellEditMode viewField={viewField} />
}
nonEditModeContent={<>{fieldValue}</>}
></EditableCell>
);
}

View File

@ -0,0 +1,62 @@
import { useRecoilState } from 'recoil';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldNumberMetadata,
} from '@/ui/table/types/ViewField';
import { TextCellEdit } from './TextCellEdit';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldNumberMetadata>;
};
export function GenericEditableNumberCellEditMode({ viewField }: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
// TODO: we could use a hook that would return the field value with the right type
const [fieldValue, setFieldValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName,
}),
);
const updateField = useUpdateEntityField();
function handleSubmit(newText: string) {
if (newText === fieldValue) return;
try {
const numberValue = parseInt(newText);
if (isNaN(numberValue)) {
throw new Error('Not a number');
}
// TODO: find a way to store this better in DB
if (numberValue > 2000000000) {
throw new Error('Number too big');
}
console.log({ numberValue });
setFieldValue(numberValue.toString());
if (currentRowEntityId && updateField) {
updateField(currentRowEntityId, viewField, numberValue);
}
} catch (error) {
console.warn(
`In GenericEditableNumberCellEditMode, Invalid number: ${newText}, ${error}`,
);
}
}
return (
<TextCellEdit autoFocus value={fieldValue ?? ''} onSubmit={handleSubmit} />
);
}

View File

@ -0,0 +1,41 @@
import { useRecoilValue } from 'recoil';
import { PhoneInputDisplay } from '@/ui/input/phone/components/PhoneInputDisplay';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldPhoneMetadata,
} from '@/ui/table/types/ViewField';
import { GenericEditablePhoneCellEditMode } from './GenericEditablePhoneCellEditMode';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldPhoneMetadata>;
editModeHorizontalAlign?: 'left' | 'right';
};
export function GenericEditablePhoneCell({
viewField,
editModeHorizontalAlign,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const fieldValue = useRecoilValue<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName,
}),
);
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<GenericEditablePhoneCellEditMode viewField={viewField} />
}
nonEditModeContent={<PhoneInputDisplay value={fieldValue} />}
></EditableCell>
);
}

View File

@ -0,0 +1,48 @@
import { useRecoilState } from 'recoil';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldPhoneMetadata,
} from '@/ui/table/types/ViewField';
import { TextCellEdit } from './TextCellEdit';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldPhoneMetadata>;
};
export function GenericEditablePhoneCellEditMode({ viewField }: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
// TODO: we could use a hook that would return the field value with the right type
const [fieldValue, setFieldValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName,
}),
);
const updateField = useUpdateEntityField();
function handleSubmit(newText: string) {
if (newText === fieldValue) return;
setFieldValue(newText);
if (currentRowEntityId && updateField) {
updateField(currentRowEntityId, viewField, newText);
}
}
return (
<TextCellEdit
placeholder={viewField.metadata.placeHolder ?? ''}
autoFocus
value={fieldValue ?? ''}
onSubmit={handleSubmit}
/>
);
}

View File

@ -0,0 +1,38 @@
import { RelationPickerHotkeyScope } from '@/ui/input/relation-picker/types/RelationPickerHotkeyScope';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import {
ViewFieldDefinition,
ViewFieldRelationMetadata,
} from '@/ui/table/types/ViewField';
import { GenericEditableRelationCellDisplayMode } from './GenericEditableRelationCellDisplayMode';
import { GenericEditableRelationCellEditMode } from './GenericEditableRelationCellEditMode';
type OwnProps = {
fieldDefinition: ViewFieldDefinition<ViewFieldRelationMetadata>;
editModeHorizontalAlign?: 'left' | 'right';
placeholder?: string;
};
export function GenericEditableRelationCell({
fieldDefinition,
editModeHorizontalAlign,
placeholder,
}: OwnProps) {
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editHotkeyScope={{ scope: RelationPickerHotkeyScope.RelationPicker }}
editModeContent={
<GenericEditableRelationCellEditMode viewField={fieldDefinition} />
}
nonEditModeContent={
<GenericEditableRelationCellDisplayMode
fieldDefinition={fieldDefinition}
editModeHorizontalAlign={editModeHorizontalAlign}
placeholder={placeholder}
/>
}
></EditableCell>
);
}

View File

@ -0,0 +1,58 @@
import { useRecoilValue } from 'recoil';
import { CompanyChip } from '@/companies/components/CompanyChip';
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldRelationMetadata,
} from '@/ui/table/types/ViewField';
import { UserChip } from '@/users/components/UserChip';
import { getLogoUrlFromDomainName } from '~/utils';
type OwnProps = {
fieldDefinition: ViewFieldDefinition<ViewFieldRelationMetadata>;
editModeHorizontalAlign?: 'left' | 'right';
placeholder?: string;
};
export function GenericEditableRelationCellDisplayMode({
fieldDefinition,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
// TODO: type value with generic getter
const fieldValue = useRecoilValue<any | null>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: fieldDefinition.metadata.fieldName,
}),
);
switch (fieldDefinition.metadata.relationType) {
case Entity.Company: {
return (
<CompanyChip
id={fieldValue?.id ?? ''}
name={fieldValue?.name ?? ''}
pictureUrl={getLogoUrlFromDomainName(fieldValue?.domainName)}
/>
);
}
case Entity.User: {
return (
<UserChip
id={fieldValue?.id ?? ''}
name={fieldValue?.displayName ?? ''}
pictureUrl={fieldValue?.avatarUrl ?? ''}
/>
);
}
default:
console.warn(
`Unknown relation type: "${fieldDefinition.metadata.relationType}" in GenericEditableRelationCellEditMode`,
);
return <> </>;
}
}

View File

@ -0,0 +1,75 @@
import { useRecoilState } from 'recoil';
import { CompanyPickerCell } from '@/companies/components/CompanyPickerCell';
import { EntityForSelect } from '@/ui/input/relation-picker/types/EntityForSelect';
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
import { useEditableCell } from '@/ui/table/editable-cell/hooks/useEditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldRelationMetadata,
} from '@/ui/table/types/ViewField';
import { UserPicker } from '@/users/components/UserPicker';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldRelationMetadata>;
};
export function GenericEditableRelationCellEditMode({ viewField }: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const { closeEditableCell } = useEditableCell();
const [fieldValueEntity] = useRecoilState<any | null>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName,
}),
);
const updateEntityField = useUpdateEntityField();
function handleEntitySubmit(newFieldEntity: EntityForSelect | null) {
if (
newFieldEntity?.id !== fieldValueEntity?.id &&
currentRowEntityId &&
updateEntityField
) {
updateEntityField(currentRowEntityId, viewField, newFieldEntity);
}
closeEditableCell();
}
function handleCancel() {
closeEditableCell();
}
switch (viewField.metadata.relationType) {
case Entity.Company: {
return (
<CompanyPickerCell
companyId={fieldValueEntity?.id ?? null}
onSubmit={handleEntitySubmit}
onCancel={handleCancel}
/>
);
}
case Entity.User: {
return (
<UserPicker
userId={fieldValueEntity?.id ?? null}
onSubmit={handleEntitySubmit}
onCancel={handleCancel}
/>
);
}
default:
console.warn(
`Unknown relation type: "${viewField.metadata.relationType}" in GenericEditableRelationCellEditMode`,
);
return <></>;
}
}

View File

@ -0,0 +1,41 @@
import { useRecoilValue } from 'recoil';
import { TextInputDisplay } from '@/ui/input/text/components/TextInputDisplay';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldTextMetadata,
} from '@/ui/table/types/ViewField';
import { GenericEditableTextCellEditMode } from './GenericEditableTextCellEditMode';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldTextMetadata>;
editModeHorizontalAlign?: 'left' | 'right';
};
export function GenericEditableTextCell({
viewField,
editModeHorizontalAlign,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const fieldValue = useRecoilValue<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName,
}),
);
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<GenericEditableTextCellEditMode viewField={viewField} />
}
nonEditModeContent={<TextInputDisplay>{fieldValue}</TextInputDisplay>}
></EditableCell>
);
}

View File

@ -0,0 +1,48 @@
import { useRecoilState } from 'recoil';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldTextMetadata,
} from '@/ui/table/types/ViewField';
import { TextCellEdit } from './TextCellEdit';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldTextMetadata>;
};
export function GenericEditableTextCellEditMode({ viewField }: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
// TODO: we could use a hook that would return the field value with the right type
const [fieldValue, setFieldValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName,
}),
);
const updateField = useUpdateEntityField();
function handleSubmit(newText: string) {
if (newText === fieldValue) return;
setFieldValue(newText);
if (currentRowEntityId && updateField) {
updateField(currentRowEntityId, viewField, newText);
}
}
return (
<TextCellEdit
placeholder={viewField.metadata.placeHolder ?? ''}
autoFocus
value={fieldValue ?? ''}
onSubmit={handleSubmit}
/>
);
}

View File

@ -0,0 +1,39 @@
import { useRecoilValue } from 'recoil';
import { InplaceInputURLDisplayMode } from '@/ui/input/url/components/URLTextInputDisplay';
import { EditableCell } from '@/ui/table/editable-cell/components/EditableCell';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldURLMetadata,
} from '@/ui/table/types/ViewField';
import { GenericEditableURLCellEditMode } from './GenericEditableURLCellEditMode';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldURLMetadata>;
editModeHorizontalAlign?: 'left' | 'right';
};
export function GenericEditableURLCell({
viewField,
editModeHorizontalAlign,
}: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
const fieldValue = useRecoilValue<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName,
}),
);
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={<GenericEditableURLCellEditMode viewField={viewField} />}
nonEditModeContent={<InplaceInputURLDisplayMode value={fieldValue} />}
></EditableCell>
);
}

View File

@ -0,0 +1,48 @@
import { useRecoilState } from 'recoil';
import { useCurrentRowEntityId } from '@/ui/table/hooks/useCurrentEntityId';
import { useUpdateEntityField } from '@/ui/table/hooks/useUpdateEntityField';
import { tableEntityFieldFamilySelector } from '@/ui/table/states/tableEntityFieldFamilySelector';
import {
ViewFieldDefinition,
ViewFieldURLMetadata,
} from '@/ui/table/types/ViewField';
import { TextCellEdit } from './TextCellEdit';
type OwnProps = {
viewField: ViewFieldDefinition<ViewFieldURLMetadata>;
};
export function GenericEditableURLCellEditMode({ viewField }: OwnProps) {
const currentRowEntityId = useCurrentRowEntityId();
// TODO: we could use a hook that would return the field value with the right type
const [fieldValue, setFieldValue] = useRecoilState<string>(
tableEntityFieldFamilySelector({
entityId: currentRowEntityId ?? '',
fieldName: viewField.metadata.fieldName,
}),
);
const updateField = useUpdateEntityField();
function handleSubmit(newText: string) {
if (newText === fieldValue) return;
setFieldValue(newText);
if (currentRowEntityId && updateField) {
updateField(currentRowEntityId, viewField, newText);
}
}
return (
<TextCellEdit
placeholder={viewField.metadata.placeHolder ?? ''}
autoFocus
value={fieldValue ?? ''}
onSubmit={handleSubmit}
/>
);
}

View File

@ -0,0 +1,59 @@
import { ChangeEvent, useEffect, useRef, useState } from 'react';
import styled from '@emotion/styled';
import { textInputStyle } from '@/ui/theme/constants/effects';
import { useRegisterCloseCellHandlers } from '../../hooks/useRegisterCloseCellHandlers';
export const StyledInput = styled.input`
margin: 0;
width: 100%;
${textInputStyle}
`;
type OwnProps = {
placeholder?: string;
autoFocus?: boolean;
value: string;
onSubmit: (newText: string) => void;
};
export function TextCellEdit({
placeholder,
autoFocus,
value,
onSubmit,
}: OwnProps) {
const [internalText, setInternalText] = useState(value);
const wrapperRef = useRef(null);
function handleSubmit() {
onSubmit(internalText);
}
function handleCancel() {
setInternalText(value);
}
function handleChange(event: ChangeEvent<HTMLInputElement>) {
setInternalText(event.target.value);
}
useEffect(() => {
setInternalText(value);
}, [value]);
useRegisterCloseCellHandlers(wrapperRef, handleSubmit, handleCancel);
return (
<StyledInput
autoComplete="off"
ref={wrapperRef}
placeholder={placeholder}
onChange={handleChange}
autoFocus={autoFocus}
value={internalText}
/>
);
}

View File

@ -1,29 +0,0 @@
import { InplaceInputDateDisplayMode } from '@/ui/display/component/InplaceInputDateDisplayMode';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
import { EditableCell } from '../components/EditableCell';
import { EditableCellDateEditMode } from './EditableCellDateEditMode';
export type EditableDateProps = {
value: Date;
onChange: (date: Date) => void;
editModeHorizontalAlign?: 'left' | 'right';
};
export function EditableCellDate({
value,
onChange,
editModeHorizontalAlign,
}: EditableDateProps) {
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<EditableCellDateEditMode onSubmit={onChange} value={value} />
}
nonEditModeContent={<InplaceInputDateDisplayMode value={value} />}
editHotkeyScope={{ scope: TableHotkeyScope.CellDateEditMode }}
></EditableCell>
);
}

View File

@ -1,47 +0,0 @@
import { ReactElement } from 'react';
import { TableHotkeyScope } from '../../types/TableHotkeyScope';
import { CellSkeleton } from '../components/CellSkeleton';
import { EditableCell } from '../components/EditableCell';
import { EditableCellDoubleTextEditMode } from './EditableCellDoubleTextEditMode';
type OwnProps = {
firstValue: string;
secondValue: string;
firstValuePlaceholder: string;
secondValuePlaceholder: string;
nonEditModeContent: ReactElement;
onSubmit?: (firstValue: string, secondValue: string) => void;
onCancel?: () => void;
loading?: boolean;
};
export function EditableCellDoubleText({
firstValue,
secondValue,
firstValuePlaceholder,
secondValuePlaceholder,
onSubmit,
onCancel,
nonEditModeContent,
loading,
}: OwnProps) {
return (
<EditableCell
editHotkeyScope={{ scope: TableHotkeyScope.CellDoubleTextInput }}
editModeContent={
<EditableCellDoubleTextEditMode
firstValue={firstValue}
secondValue={secondValue}
firstValuePlaceholder={firstValuePlaceholder}
secondValuePlaceholder={secondValuePlaceholder}
onSubmit={onSubmit}
onCancel={onCancel}
/>
}
nonEditModeContent={loading ? <CellSkeleton /> : nonEditModeContent}
></EditableCell>
);
}

View File

@ -1,26 +0,0 @@
import { InplaceInputPhoneDisplayMode } from '@/ui/display/component/InplaceInputPhoneDisplayMode';
import { InplaceInputTextCellEditMode } from '@/ui/inplace-input/components/InplaceInputTextCellEditMode';
import { EditableCell } from '../components/EditableCell';
type OwnProps = {
placeholder?: string;
value: string;
onSubmit?: (newText: string) => void;
};
export function EditableCellPhone({ value, placeholder, onSubmit }: OwnProps) {
return (
<EditableCell
editModeContent={
<InplaceInputTextCellEditMode
autoFocus
placeholder={placeholder || ''}
value={value}
onSubmit={(newText) => onSubmit?.(newText)}
/>
}
nonEditModeContent={<InplaceInputPhoneDisplayMode value={value} />}
/>
);
}

View File

@ -1,19 +0,0 @@
import styled from '@emotion/styled';
export const EditableCellRelationCreateButton = styled.button`
align-items: center;
background: none;
border: none;
border-radius: ${({ theme }) => theme.border.radius.sm};
cursor: pointer;
display: flex;
font-family: 'Inter';
font-size: ${({ theme }) => theme.font.size.md};
gap: ${({ theme }) => theme.spacing(2)};
height: 31px;
padding-bottom: ${({ theme }) => theme.spacing(1)};
padding-left: ${({ theme }) => theme.spacing(1)};
padding-top: ${({ theme }) => theme.spacing(1)};
user-select: none;
width: 100%;
`;

View File

@ -1,42 +0,0 @@
import { InplaceInputTextDisplayMode } from '@/ui/display/component/InplaceInputTextDisplayMode';
import { InplaceInputTextCellEditMode } from '@/ui/inplace-input/components/InplaceInputTextCellEditMode';
import { CellSkeleton } from '../components/CellSkeleton';
import { EditableCell } from '../components/EditableCell';
type OwnProps = {
placeholder?: string;
value: string;
editModeHorizontalAlign?: 'left' | 'right';
loading?: boolean;
onSubmit?: (newText: string) => void;
};
export function EditableCellText({
value,
placeholder,
editModeHorizontalAlign,
loading,
onSubmit,
}: OwnProps) {
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<InplaceInputTextCellEditMode
placeholder={placeholder || ''}
autoFocus
value={value}
onSubmit={(newText) => onSubmit?.(newText)}
/>
}
nonEditModeContent={
loading ? (
<CellSkeleton />
) : (
<InplaceInputTextDisplayMode>{value}</InplaceInputTextDisplayMode>
)
}
></EditableCell>
);
}

View File

@ -1,46 +0,0 @@
import { InplaceInputTextCellEditMode } from '@/ui/inplace-input/components/InplaceInputTextCellEditMode';
import { RawLink } from '../../../link/components/RawLink';
import { CellSkeleton } from '../components/CellSkeleton';
import { EditableCell } from '../components/EditableCell';
type OwnProps = {
placeholder?: string;
url: string;
onChange?: (newURL: string) => void;
editModeHorizontalAlign?: 'left' | 'right';
loading?: boolean;
onSubmit?: (newURL: string) => void;
onCancel?: () => void;
};
export function EditableCellURL({
url,
placeholder,
editModeHorizontalAlign,
loading,
onSubmit,
}: OwnProps) {
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<InplaceInputTextCellEditMode
placeholder={placeholder}
autoFocus
value={url}
onSubmit={(newURL) => onSubmit?.(newURL)}
/>
}
nonEditModeContent={
loading ? (
<CellSkeleton />
) : (
<RawLink onClick={(e) => e.stopPropagation()} href={url ?? ''}>
{url}
</RawLink>
)
}
></EditableCell>
);
}

View File

@ -1,78 +0,0 @@
import { ReactNode, useEffect, useState } from 'react';
import styled from '@emotion/styled';
import { InplaceInputTextCellEditMode } from '../../../inplace-input/components/InplaceInputTextCellEditMode';
import { EditableCell } from '../components/EditableCell';
export type EditableChipProps = {
placeholder?: string;
value: string;
editModeHorizontalAlign?: 'left' | 'right';
ChipComponent: React.ReactNode;
activityCount?: number;
onCommentClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
rightEndContents?: ReactNode[];
onSubmit?: (newValue: string) => void;
onCancel?: () => void;
};
const NoEditModeContainer = styled.div`
align-items: center;
display: flex;
justify-content: space-between;
width: 100%;
`;
const RightContainer = styled.div`
margin-left: ${(props) => props.theme.spacing(1)};
`;
// TODO: move right end content in EditableCell
export function EditableCellChip({
value,
placeholder,
editModeHorizontalAlign,
ChipComponent,
rightEndContents,
onSubmit,
}: EditableChipProps) {
const [inputValue, setInputValue] = useState(value);
useEffect(() => {
setInputValue(value);
}, [value]);
const handleRightEndContentClick = (
event: React.MouseEvent<HTMLDivElement>,
) => {
event.stopPropagation();
};
return (
<EditableCell
editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={
<InplaceInputTextCellEditMode
placeholder={placeholder || ''}
autoFocus
value={inputValue}
onSubmit={(newValue) => onSubmit?.(newValue)}
/>
}
nonEditModeContent={
<NoEditModeContainer>
{ChipComponent}
<RightContainer>
{rightEndContents &&
rightEndContents.length > 0 &&
rightEndContents.map((content, index) => (
<div key={index} onClick={handleRightEndContentClick}>
{content}
</div>
))}
</RightContainer>
</NoEditModeContainer>
}
/>
);
}