Skip to content

Commit

Permalink
Wrap Long text fields (textarea) (#8557)
Browse files Browse the repository at this point in the history
Here we add the option for Text inputs to be wrapped, and to select on
how many lines text should be displayed.

Fix #7552

---------

Co-authored-by: guillim <[email protected]>
  • Loading branch information
guillim and guillim authored Nov 18, 2024
1 parent 83b5eb6 commit 2f3c416
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import { useTextFieldDisplay } from '@/object-record/record-field/meta-types/hoo
import { TextDisplay } from '@/ui/field/display/components/TextDisplay';

export const TextFieldDisplay = () => {
const { fieldValue } = useTextFieldDisplay();
const { fieldValue, fieldDefinition } = useTextFieldDisplay();

return <TextDisplay text={fieldValue} />;
return (
<TextDisplay
text={fieldValue}
displayedMaxRows={fieldDefinition.metadata?.settings?.displayedMaxRows}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ import { useContext } from 'react';

import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';

import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata';
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { FieldContext } from '../../contexts/FieldContext';

export const useTextFieldDisplay = () => {
const { recordId, fieldDefinition, hotkeyScope } = useContext(FieldContext);

assertFieldMetadata(FieldMetadataType.Text, isFieldText, fieldDefinition);
const fieldName = fieldDefinition.metadata.fieldName;

const fieldValue =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export type FieldTextMetadata = {
objectMetadataNameSingular?: string;
placeHolder: string;
fieldName: string;
settings?: Record<string, never>;
settings?: {
displayedMaxRows?: number;
};
};

export type FieldDateTimeMetadata = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import { RecordInlineCellValue } from '@/object-record/record-inline-cell/compon
import { getRecordFieldInputId } from '@/object-record/utils/getRecordFieldInputId';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';

import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata';
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
import { FieldMetadataType } from '~/generated-metadata/graphql';
import { useRecordInlineCellContext } from './RecordInlineCellContext';

const StyledIconContainer = styled.div`
Expand All @@ -36,6 +39,7 @@ const StyledLabelAndIconContainer = styled.div`
color: ${({ theme }) => theme.font.color.tertiary};
display: flex;
gap: ${({ theme }) => theme.spacing(1)};
height: 24px;
`;

const StyledValueContainer = styled.div`
Expand All @@ -52,11 +56,12 @@ const StyledLabelContainer = styled.div<{ width?: number }>`
`;

const StyledInlineCellBaseContainer = styled.div`
align-items: center;
align-items: flex-start;
box-sizing: border-box;
width: 100%;
display: flex;
height: 24px;
height: fit-content;
line-height: 24px;
gap: ${({ theme }) => theme.spacing(1)};
user-select: none;
justify-content: center;
Expand Down Expand Up @@ -88,6 +93,10 @@ export const RecordInlineCellContainer = () => {

const { recordId, fieldDefinition } = useContext(FieldContext);

if (isFieldText(fieldDefinition)) {
assertFieldMetadata(FieldMetadataType.Text, isFieldText, fieldDefinition);
}

const { setIsFocused } = useFieldFocus();

const handleContainerMouseEnter = () => {
Expand Down Expand Up @@ -122,7 +131,7 @@ export const RecordInlineCellContainer = () => {
)}
{showLabel && label && (
<StyledLabelContainer width={labelWidth}>
<OverflowingTextWithTooltip text={label} />
<OverflowingTextWithTooltip text={label} isLabel={true} />
</StyledLabelContainer>
)}
{/* TODO: Displaying Tooltips on the board is causing performance issues https://react-tooltip.com/docs/examples/render */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ const StyledRecordInlineCellNormalModeOuterContainer = styled.div<
isDisplayModeFixHeight ? '16px' : 'auto'};
min-height: 16px;
overflow: hidden;
padding: ${({ theme }) => theme.spacing(1)};
padding-right: ${({ theme }) => theme.spacing(1)};
padding-left: ${({ theme }) => theme.spacing(1)};
${(props) => {
if (props.isHovered === true) {
return css`
Expand All @@ -39,15 +39,17 @@ const StyledRecordInlineCellNormalModeOuterContainer = styled.div<
`;

const StyledRecordInlineCellNormalModeInnerContainer = styled.div`
align-content: center;
align-items: center;
color: ${({ theme }) => theme.font.color.primary};
font-size: 'inherit';
font-weight: 'inherit';
height: fit-content;
min-height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/componen
import { SETTINGS_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsFieldTypeConfigs';
import { settingsDataModelFieldBooleanFormSchema } from '@/settings/data-model/fields/forms/boolean/components/SettingsDataModelFieldBooleanForm';
import { SettingsDataModelFieldBooleanSettingsFormCard } from '@/settings/data-model/fields/forms/boolean/components/SettingsDataModelFieldBooleanSettingsFormCard';
import { settingsDataModelFieldtextFormSchema } from '@/settings/data-model/fields/forms/components/text/SettingsDataModelFieldTextForm';
import { SettingsDataModelFieldTextSettingsFormCard } from '@/settings/data-model/fields/forms/components/text/SettingsDataModelFieldTextSettingsFormCard';
import { settingsDataModelFieldCurrencyFormSchema } from '@/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencyForm';
import { SettingsDataModelFieldCurrencySettingsFormCard } from '@/settings/data-model/fields/forms/currency/components/SettingsDataModelFieldCurrencySettingsFormCard';
import { settingsDataModelFieldDateFormSchema } from '@/settings/data-model/fields/forms/date/components/SettingsDataModelFieldDateForm';
Expand Down Expand Up @@ -58,6 +60,10 @@ const numberFieldFormSchema = z
.object({ type: z.literal(FieldMetadataType.Number) })
.merge(settingsDataModelFieldNumberFormSchema);

const textFieldFormSchema = z
.object({ type: z.literal(FieldMetadataType.Text) })
.merge(settingsDataModelFieldtextFormSchema);

const otherFieldsFormSchema = z.object({
type: z.enum(
Object.keys(
Expand All @@ -70,6 +76,7 @@ const otherFieldsFormSchema = z.object({
FieldMetadataType.Date,
FieldMetadataType.DateTime,
FieldMetadataType.Number,
FieldMetadataType.Text,
]),
) as [FieldMetadataType, ...FieldMetadataType[]],
),
Expand All @@ -86,6 +93,7 @@ export const settingsDataModelFieldSettingsFormSchema = z.discriminatedUnion(
selectFieldFormSchema,
multiSelectFieldFormSchema,
numberFieldFormSchema,
textFieldFormSchema,
otherFieldsFormSchema,
],
);
Expand Down Expand Up @@ -183,6 +191,15 @@ export const SettingsDataModelFieldSettingsFormCard = ({
);
}

if (fieldMetadataItem.type === FieldMetadataType.Text) {
return (
<SettingsDataModelFieldTextSettingsFormCard
fieldMetadataItem={fieldMetadataItem}
objectMetadataItem={objectMetadataItem}
/>
);
}

if (
fieldMetadataItem.type === FieldMetadataType.Select ||
fieldMetadataItem.type === FieldMetadataType.MultiSelect
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Controller, useFormContext } from 'react-hook-form';

import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { Select } from '@/ui/input/components/Select';
import styled from '@emotion/styled';
import { CardContent } from 'twenty-ui';
import { z } from 'zod';

const StyledFormCardTitle = styled.div`
color: ${({ theme }) => theme.font.color.light};
font-size: ${({ theme }) => theme.font.size.xs};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin-bottom: ${({ theme }) => theme.spacing(1)};
`;

type SettingsDataModelFieldTextFormProps = {
disabled?: boolean;
fieldMetadataItem: Pick<
FieldMetadataItem,
'icon' | 'label' | 'type' | 'defaultValue' | 'settings'
>;
};

export const textFieldDefaultValueSchema = z.object({
displayedMaxRows: z.number().nullable(),
});

export const settingsDataModelFieldtextFormSchema = z.object({
settings: textFieldDefaultValueSchema,
});

export type SettingsDataModelFieldTextFormValues = z.infer<
typeof settingsDataModelFieldtextFormSchema
>;

export const SettingsDataModelFieldTextForm = ({
disabled,
fieldMetadataItem,
}: SettingsDataModelFieldTextFormProps) => {
const { control } = useFormContext<SettingsDataModelFieldTextFormValues>();
return (
<CardContent>
<Controller
name="settings"
defaultValue={{
displayedMaxRows: fieldMetadataItem?.settings?.displayedMaxRows || 0,
}}
control={control}
render={({ field: { onChange, value } }) => {
const displayedMaxRows = value?.displayedMaxRows ?? 0;

return (
<>
<StyledFormCardTitle>Wrap on record pages</StyledFormCardTitle>
<Select
disabled={disabled}
dropdownId="selectTextWrap"
options={[
{
label: 'Deactivated',
value: 0,
},
{
label: 'First 2 lines',
value: 2,
},
{
label: 'First 5 lines',
value: 5,
},
{
label: 'First 10 lines',
value: 10,
},
{
label: 'All lines',
value: 99,
},
]}
value={displayedMaxRows}
onChange={(value) => onChange({ displayedMaxRows: value })}
withSearchInput={false}
dropdownWidthAuto={true}
/>
</>
);
}}
/>
</CardContent>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import styled from '@emotion/styled';

import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import { SettingsDataModelPreviewFormCard } from '@/settings/data-model/components/SettingsDataModelPreviewFormCard';

import { SettingsDataModelFieldTextForm } from '@/settings/data-model/fields/forms/components/text/SettingsDataModelFieldTextForm';
import {
SettingsDataModelFieldPreviewCard,
SettingsDataModelFieldPreviewCardProps,
} from '@/settings/data-model/fields/preview/components/SettingsDataModelFieldPreviewCard';

type SettingsDataModelFieldTextSettingsFormCardProps = {
disabled?: boolean;
fieldMetadataItem: Pick<
FieldMetadataItem,
'icon' | 'label' | 'type' | 'defaultValue'
>;
} & Pick<SettingsDataModelFieldPreviewCardProps, 'objectMetadataItem'>;

const StyledFieldPreviewCard = styled(SettingsDataModelFieldPreviewCard)`
flex: 1 1 100%;
`;

export const SettingsDataModelFieldTextSettingsFormCard = ({
disabled,
fieldMetadataItem,
objectMetadataItem,
}: SettingsDataModelFieldTextSettingsFormCardProps) => {
return (
<SettingsDataModelPreviewFormCard
preview={
<StyledFieldPreviewCard
fieldMetadataItem={fieldMetadataItem}
objectMetadataItem={objectMetadataItem}
/>
}
form={
<SettingsDataModelFieldTextForm
disabled={disabled}
fieldMetadataItem={fieldMetadataItem}
/>
}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,21 @@ export type SettingsDataModelFieldPreviewProps = {
};

const StyledFieldPreview = styled.div<{ shrink?: boolean }>`
align-items: center;
align-items: flex-start;
background-color: ${({ theme }) => theme.background.primary};
border: 1px solid ${({ theme }) => theme.border.color.medium};
border-radius: ${({ theme }) => theme.border.radius.sm};
display: flex;
gap: ${({ theme }) => theme.spacing(2)};
height: ${({ theme }) => theme.spacing(8)};
height: fit-content;
line-height: 24px;
overflow: hidden;
padding: 0
${({ shrink, theme }) => (shrink ? theme.spacing(1) : theme.spacing(2))};
white-space: nowrap;
margin-top: ${({ theme }) => theme.spacing(2)};
padding-top: ${({ theme }) => theme.spacing(2)};
padding-bottom: ${({ theme }) => theme.spacing(2)};
`;

const StyledFieldLabel = styled.div`
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { OverflowingTextWithTooltip } from 'twenty-ui';

type TextDisplayProps = {
text: string;
displayedMaxRows?: number;
};

export const TextDisplay = ({ text }: TextDisplayProps) => (
<OverflowingTextWithTooltip text={text} />
export const TextDisplay = ({ text, displayedMaxRows }: TextDisplayProps) => (
<OverflowingTextWithTooltip text={text} displayedMaxRows={displayedMaxRows} />
);
Loading

0 comments on commit 2f3c416

Please sign in to comment.