Remove all styled(Component) patterns in favor of parent wrappers and props (#18430)

## Summary

Eliminates all ~350 `styled(Component)` usages across `twenty-front` and
`twenty-ui` (212 files changed). Each was replaced following these
rules:

- **Margin/layout CSS** (margin, padding, flex, align-self, width) →
wrapped in a `styled.div`/`styled.span` parent container
- **Third-party components** (Link, TextareaAutosize,
ReactPhoneNumberInput, Handle, etc.) → parent container with child CSS
selectors (`> a`, `> textarea`, `> input`, etc.)
- **Intrinsic behavior via existing props** (TableRow
`gridTemplateColumns`, TableCell `color`/`align`) → replaced
`styled(TableRow)` / `styled(TableCell)` with direct prop usage
- **Other visual overrides on twenty-ui components** (Card, Section,
TabList, Button, MenuItem, ScrollWrapper, etc.) → parent wrappers with
`> div` / `> *` child selectors
- **Extending styled.div/span** → merged all CSS into a single
`styled.div`/`styled.span`

Also adds `overflow: hidden` to parent containers wrapping
`ScrollWrapper` so scroll activates correctly with the new wrapper
structure.

### Migration patterns

| Before | After |
|--------|-------|
| `styled(Avatar)` with `margin-right` | `<StyledAvatarContainer><Avatar
/></StyledAvatarContainer>` |
| `styled(Link)` with `text-decoration: none` |
`<StyledLinkContainer><Link /></StyledLinkContainer>` with `> a { ... }`
|
| `styled(TableRow)` with `grid-template-columns` | `<TableRow
gridTemplateColumns="..." />` |
| `styled(TableCell)` with `color` / `align` | `<TableCell color={...}
align="right" />` |
| `styled(Card)` with `margin-top` | `<StyledCardContainer><Card
/></StyledCardContainer>` |
| `styled(TabList)` with `background` |
`<StyledTabListContainer><TabList /></StyledTabListContainer>` with `>
div { ... }` |
| `styled(StyledBase)` extending a `styled.div` | Single merged
`styled.div` with all styles inlined |
This commit is contained in:
Charles Bochet
2026-03-05 18:16:25 +01:00
committed by GitHub
parent e5e3132ddd
commit c53a13417e
224 changed files with 4765 additions and 3837 deletions
@@ -19,12 +19,15 @@ const StyledMainContainerLayoutForDesktop = styled.div`
padding-right: ${themeCssVariables.spacing[3]};
`;
const StyledPageBodyForDesktop = styled(PageBody)`
const StyledPageBodyForDesktopContainer = styled.div`
flex: 1 1 0;
min-width: 0;
width: 0;
padding-bottom: 0;
padding-right: 0;
> * {
padding-bottom: 0;
padding-right: 0;
}
`;
const StyledMainContainerLayoutForMobile = styled.div`
@@ -34,11 +37,12 @@ const StyledMainContainerLayoutForMobile = styled.div`
padding: 0;
`;
const StyledPageBodyForMobile = styled(PageBody)`
padding-bottom: 0;
padding-left: ${themeCssVariables.spacing[1]};
padding-right: ${themeCssVariables.spacing['1.5']};
const StyledPageBodyForMobileContainer = styled.div`
> * {
padding-bottom: 0;
padding-left: ${themeCssVariables.spacing[1]};
padding-right: ${themeCssVariables.spacing['1.5']};
}
`;
export const MainContainerLayoutWithSidePanel = ({
@@ -51,7 +55,9 @@ export const MainContainerLayoutWithSidePanel = ({
if (isMobile) {
return (
<StyledMainContainerLayoutForMobile>
<StyledPageBodyForMobile>{children}</StyledPageBodyForMobile>
<StyledPageBodyForMobileContainer>
<PageBody>{children}</PageBody>
</StyledPageBodyForMobileContainer>
<CommandMenuForMobile />
</StyledMainContainerLayoutForMobile>
);
@@ -59,7 +65,9 @@ export const MainContainerLayoutWithSidePanel = ({
return (
<StyledMainContainerLayoutForDesktop>
<StyledPageBodyForDesktop>{children}</StyledPageBodyForDesktop>
<StyledPageBodyForDesktopContainer>
<PageBody>{children}</PageBody>
</StyledPageBodyForDesktopContainer>
<SidePanelForDesktop />
</StyledMainContainerLayoutForDesktop>
);
@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`generateDepthRecordGqlFieldsFromRecord should generate depth one record gql fields from empty record 1`] = `
{
@@ -3,7 +3,7 @@ import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/use
import { styled } from '@linaria/react';
import { NotificationCounter } from 'twenty-ui/navigation';
const StyledNotificationCounter = styled(NotificationCounter)`
const StyledNotificationCounterContainer = styled.div`
position: absolute;
top: -7px;
right: -7px;
@@ -23,5 +23,9 @@ export const RecordBoardCardMultiDragCounterChip = () => {
return null;
}
return <StyledNotificationCounter count={selectedCount} />;
return (
<StyledNotificationCounterContainer>
<NotificationCounter count={selectedCount} />
</StyledNotificationCounterContainer>
);
};
@@ -68,7 +68,7 @@ const StyledColumn = styled.div`
position: relative;
`;
const StyledTag = styled(Tag)`
const StyledTagContainer = styled.div`
max-width: 100%;
min-width: 0;
overflow: hidden;
@@ -139,24 +139,29 @@ export const RecordBoardColumnHeader = () => {
y: 10,
}}
clickableComponent={
<StyledTag
variant={
columnDefinition.type === RecordGroupDefinitionType.Value
? 'solid'
: 'outline'
}
color={
columnDefinition.type === RecordGroupDefinitionType.Value
? columnDefinition.color
: 'transparent'
}
text={columnDefinition.title}
weight={
columnDefinition.type === RecordGroupDefinitionType.Value
? 'regular'
: 'medium'
}
/>
<StyledTagContainer>
<Tag
variant={
columnDefinition.type ===
RecordGroupDefinitionType.Value
? 'solid'
: 'outline'
}
color={
columnDefinition.type ===
RecordGroupDefinitionType.Value
? columnDefinition.color
: 'transparent'
}
text={columnDefinition.title}
weight={
columnDefinition.type ===
RecordGroupDefinitionType.Value
? 'regular'
: 'medium'
}
/>
</StyledTagContainer>
}
dropdownComponents={<RecordBoardColumnDropdownMenu />}
/>
@@ -6,12 +6,14 @@ import { type Nullable } from 'twenty-shared/types';
import { Tag } from 'twenty-ui/components';
import { AppTooltip, TooltipDelay } from 'twenty-ui/display';
const StyledTag = styled(Tag)`
const StyledTagContainer = styled.div`
width: 100%;
`;
const StyledHeader = styled(StyledHeaderDropdownButton)`
padding: 0;
const StyledHeaderContainer = styled.div`
> * {
padding: 0;
}
`;
export const RecordBoardColumnHeaderAggregateDropdownButton = ({
@@ -29,24 +31,28 @@ export const RecordBoardColumnHeaderAggregateDropdownButton = ({
);
return (
<StyledHeader id={dropdownId} isUnfolded={isDropdownOpen}>
<>
<StyledTag
text={value ? value.toString() : '-'}
color="transparent"
weight="regular"
/>
{!isDropdownOpen && (
<AppTooltip
anchorSelect={`#${dropdownId}`}
content={tooltip ?? ''}
noArrow
place="right"
positionStrategy="fixed"
delay={TooltipDelay.mediumDelay}
/>
)}
</>
</StyledHeader>
<StyledHeaderContainer>
<StyledHeaderDropdownButton id={dropdownId} isUnfolded={isDropdownOpen}>
<>
<StyledTagContainer>
<Tag
text={value ? value.toString() : '-'}
color="transparent"
weight="regular"
/>
</StyledTagContainer>
{!isDropdownOpen && (
<AppTooltip
anchorSelect={`#${dropdownId}`}
content={tooltip ?? ''}
noArrow
place="right"
positionStrategy="fixed"
delay={TooltipDelay.mediumDelay}
/>
)}
</>
</StyledHeaderDropdownButton>
</StyledHeaderContainer>
);
};
@@ -14,7 +14,7 @@ import { IconPlus } from 'twenty-ui/display';
import { Button } from 'twenty-ui/input';
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
const StyledButton = styled(Button)`
const StyledButtonContainer = styled.div`
padding: ${themeCssVariables.spacing['0.5']};
min-width: unset;
height: auto;
@@ -69,17 +69,19 @@ export const RecordCalendarAddNew = ({
}
return (
<StyledButton
onClick={async () => {
await createNewIndexRecord({
[calendarFieldMetadataItem.name]: cardDate
.toZonedDateTime(userTimezone)
.toInstant()
.toString(),
});
}}
variant="tertiary"
Icon={() => <IconPlus size={theme.icon.size.sm} />}
/>
<StyledButtonContainer>
<Button
onClick={async () => {
await createNewIndexRecord({
[calendarFieldMetadataItem.name]: cardDate
.toZonedDateTime(userTimezone)
.toInstant()
.toString(),
});
}}
variant="tertiary"
Icon={() => <IconPlus size={theme.icon.size.sm} />}
/>
</StyledButtonContainer>
);
};
@@ -30,7 +30,7 @@ const StyledContainer = styled.div`
width: 100%;
`;
const StyledNavigationButton = styled(Button)`
const StyledNavigationButtonContainer = styled.div`
padding: ${themeCssVariables.spacing[1]};
`;
@@ -120,24 +120,28 @@ export const RecordCalendarTopBar = () => {
</StyledLeftSection>
<StyledNavigationSection>
<StyledNavigationButton
size="small"
variant="tertiary"
Icon={IconChevronLeft}
onClick={handlePreviousMonth}
/>
<StyledNavigationButtonContainer>
<Button
size="small"
variant="tertiary"
Icon={IconChevronLeft}
onClick={handlePreviousMonth}
/>
</StyledNavigationButtonContainer>
<Button
size="small"
variant="tertiary"
title={t`Today`}
onClick={handleTodayClick}
/>
<StyledNavigationButton
size="small"
variant="tertiary"
Icon={IconChevronRight}
onClick={handleNextMonth}
/>
<StyledNavigationButtonContainer>
<Button
size="small"
variant="tertiary"
Icon={IconChevronRight}
onClick={handleNextMonth}
/>
</StyledNavigationButtonContainer>
</StyledNavigationSection>
</StyledContainer>
);
@@ -24,7 +24,7 @@ const StyledContainer = styled.div`
display: flex;
`;
const StyledRecordCard = styled(RecordCard)`
const StyledRecordCardContainer = styled.div`
width: calc(100% - 2px);
`;
@@ -84,18 +84,20 @@ export const RecordCalendarCard = ({ recordId }: RecordCalendarCardProps) => {
value={{ scopeInstanceId: RECORD_CALENDAR_CARD_INPUT_ID_PREFIX }}
>
<StyledContainer onContextMenu={handleContextMenuOpen}>
<StyledRecordCard
data-selected={isRecordCalendarCardSelected}
data-click-outside-id={RECORD_CALENDAR_CARD_CLICK_OUTSIDE_ID}
>
<RecordCalendarCardHeader recordId={recordId} />
<AnimatedEaseInOut isOpen={!isCompactModeActive} initial={false}>
<RecordCalendarCardBody
recordId={recordId}
isRecordReadOnly={false}
/>
</AnimatedEaseInOut>
</StyledRecordCard>
<StyledRecordCardContainer>
<RecordCard
data-selected={isRecordCalendarCardSelected}
data-click-outside-id={RECORD_CALENDAR_CARD_CLICK_OUTSIDE_ID}
>
<RecordCalendarCardHeader recordId={recordId} />
<AnimatedEaseInOut isOpen={!isCompactModeActive} initial={false}>
<RecordCalendarCardBody
recordId={recordId}
isRecordReadOnly={false}
/>
</AnimatedEaseInOut>
</RecordCard>
</StyledRecordCardContainer>
<RecordCalendarCardCellHoveredPortal recordId={recordId} />
<RecordCalendarCardCellEditModePortal recordId={recordId} />
</StyledContainer>
@@ -4,7 +4,7 @@ import { Link } from 'react-router-dom';
import { Section } from 'twenty-ui/layout';
import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledRecordDetailSectionContainer = styled(Section)`
const StyledRecordDetailSectionWrapper = styled.div`
border-top: 1px solid ${themeCssVariables.border.color.light};
padding-top: ${themeCssVariables.spacing[3]};
padding-bottom: ${themeCssVariables.spacing[3]};
@@ -36,13 +36,15 @@ const StyledTitleLabel = styled.div`
font-weight: ${themeCssVariables.font.weight.medium};
`;
const StyledLink = styled(Link)`
color: ${themeCssVariables.font.color.light};
text-decoration: none;
font-size: ${themeCssVariables.font.size.sm};
const StyledLinkContainer = styled.span`
& > a {
color: ${themeCssVariables.font.color.light};
font-size: ${themeCssVariables.font.size.sm};
text-decoration: none;
:hover {
color: ${themeCssVariables.font.color.secondary};
&:hover {
color: ${themeCssVariables.font.color.secondary};
}
}
`;
@@ -67,22 +69,28 @@ export const RecordDetailSectionContainer = ({
}: RecordDetailSectionContainerProps) => {
const [isHovered, setIsHovered] = useState(false);
return (
<StyledRecordDetailSectionContainer>
<StyledHeader
areRecordsAvailable={areRecordsAvailable}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
data-testid={dataTestId}
>
<StyledTitle>
<StyledTitleLabel>{title}</StyledTitleLabel>
{link && <StyledLink to={link.to}>{link.label}</StyledLink>}
</StyledTitle>
{hideRightAdornmentOnMouseLeave && !isHovered && areRecordsAvailable
? null
: rightAdornment}
</StyledHeader>
{children}
</StyledRecordDetailSectionContainer>
<StyledRecordDetailSectionWrapper>
<Section>
<StyledHeader
areRecordsAvailable={areRecordsAvailable}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
data-testid={dataTestId}
>
<StyledTitle>
<StyledTitleLabel>{title}</StyledTitleLabel>
{link && (
<StyledLinkContainer>
<Link to={link.to}>{link.label}</Link>
</StyledLinkContainer>
)}
</StyledTitle>
{hideRightAdornmentOnMouseLeave && !isHovered && areRecordsAvailable
? null
: rightAdornment}
</StyledHeader>
{children}
</Section>
</StyledRecordDetailSectionWrapper>
);
};
@@ -22,7 +22,7 @@ import { IconMaximize } from 'twenty-ui/display';
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
import { useIsMobile } from 'twenty-ui/utilities';
const StyledAdvancedTextFieldContainer = styled(FormFieldInputContainer)`
const StyledAdvancedTextFieldContainerWrapper = styled.div`
flex-grow: 1;
`;
@@ -63,14 +63,16 @@ const StyledFullScreenEditorContainer = styled.div`
overflow-y: auto;
`;
const StyledFullScreenButtonContainer = styled(StyledDropdownButtonContainer)`
background-color: transparent;
const StyledFullScreenButtonContainerWrapper = styled.div`
> * {
background-color: transparent;
color: ${themeCssVariables.font.color.tertiary};
padding: ${themeCssVariables.spacing[2]};
color: ${themeCssVariables.font.color.tertiary};
padding: ${themeCssVariables.spacing[2]};
:hover {
cursor: pointer;
background-color: ${themeCssVariables.background.transparent.light};
:hover {
cursor: pointer;
background-color: ${themeCssVariables.background.transparent.light};
}
}
`;
@@ -209,46 +211,50 @@ export const FormAdvancedTextFieldInput = ({
return (
<>
<StyledAdvancedTextFieldContainer>
{label ? <InputLabel>{label}</InputLabel> : null}
<StyledAdvancedTextFieldContainerWrapper>
<FormFieldInputContainer>
{label ? <InputLabel>{label}</InputLabel> : null}
<StyledAdvancedTextFieldFieldContainer>
<StyledAdvancedTextFieldInnerContainer>
{!isFullScreen && (
<AdvancedTextEditor
editor={editor}
readonly={readonly}
minHeight={minHeight}
maxWidth={maxWidth}
/>
)}
<StyledAdvancedTextFieldFieldContainer>
<StyledAdvancedTextFieldInnerContainer>
{!isFullScreen && (
<AdvancedTextEditor
editor={editor}
readonly={readonly}
minHeight={minHeight}
maxWidth={maxWidth}
/>
)}
{enableFullScreen && (
<StyledEditorActionButtonContainer>
{!readonly && !isFullScreen && (
<StyledFullScreenButtonContainer
isUnfolded={false}
transparentBackground
onClick={handleEnterFullScreen}
>
<IconMaximize size={theme.icon.size.md} />
</StyledFullScreenButtonContainer>
)}
</StyledEditorActionButtonContainer>
)}
{enableFullScreen && (
<StyledEditorActionButtonContainer>
{!readonly && !isFullScreen && (
<StyledFullScreenButtonContainerWrapper>
<StyledDropdownButtonContainer
isUnfolded={false}
transparentBackground
onClick={handleEnterFullScreen}
>
<IconMaximize size={theme.icon.size.md} />
</StyledDropdownButtonContainer>
</StyledFullScreenButtonContainerWrapper>
)}
</StyledEditorActionButtonContainer>
)}
{VariablePicker && !readonly ? (
<VariablePicker
instanceId={instanceId}
multiline={true}
onVariableSelect={handleVariableTagInsert}
/>
) : null}
</StyledAdvancedTextFieldInnerContainer>
</StyledAdvancedTextFieldFieldContainer>
{hint && <InputHint>{hint}</InputHint>}
{error && <InputErrorHelper>{error}</InputErrorHelper>}
</StyledAdvancedTextFieldContainer>
{VariablePicker && !readonly ? (
<VariablePicker
instanceId={instanceId}
multiline={true}
onVariableSelect={handleVariableTagInsert}
/>
) : null}
</StyledAdvancedTextFieldInnerContainer>
</StyledAdvancedTextFieldFieldContainer>
{hint && <InputHint>{hint}</InputHint>}
{error && <InputErrorHelper>{error}</InputErrorHelper>}
</FormFieldInputContainer>
</StyledAdvancedTextFieldContainerWrapper>
{fullScreenOverlay}
</>
@@ -52,7 +52,14 @@ const StyledDisplayModeReadonlyContainer = styled.div`
width: 100%;
`;
const StyledDisplayModeContainer = styled(StyledDisplayModeReadonlyContainer)`
const StyledDisplayModeContainer = styled.div`
align-items: center;
background: transparent;
border: none;
display: flex;
font-family: inherit;
padding-inline: ${themeCssVariables.spacing[2]};
width: 100%;
height: 30px;
cursor: pointer;
box-sizing: border-box;
@@ -63,11 +70,11 @@ const StyledDisplayModeContainer = styled(StyledDisplayModeReadonlyContainer)`
}
`;
const StyledInput = styled(TextInput)`
const StyledInputContainer = styled.div`
padding: ${themeCssVariables.spacing[1]} ${themeCssVariables.spacing[2]};
`;
const StyledPlaceholder = styled(FormFieldPlaceholder)`
const StyledPlaceholderContainer = styled.div`
width: 100%;
`;
@@ -303,19 +310,23 @@ export const FormArrayFieldInput = ({
{draftValue.value.length > 0 ? (
<ArrayDisplay value={draftValue.value} />
) : (
<StyledPlaceholder />
<StyledPlaceholderContainer>
<FormFieldPlaceholder />
</StyledPlaceholderContainer>
)}
</StyledDisplayModeReadonlyContainer>
) : draftValue.value.length === 0 ? (
<StyledInput
instanceId={formFieldInputInstanceId}
placeholder={t`Enter an item`}
value={newItemDraftValue}
copyButton={false}
onChange={handleFirstItemInputChange}
onEnter={handleFirstItemInputEnter}
shouldTrim={false}
/>
<StyledInputContainer>
<TextInput
instanceId={formFieldInputInstanceId}
placeholder={t`Enter an item`}
value={newItemDraftValue}
copyButton={false}
onChange={handleFirstItemInputChange}
onEnter={handleFirstItemInputEnter}
shouldTrim={false}
/>
</StyledInputContainer>
) : (
<Dropdown
dropdownId={dropdownId}
@@ -33,7 +33,7 @@ import { themeCssVariables } from 'twenty-ui/theme-constants';
import { type Nullable } from 'twenty-ui/utilities';
import { getDateFormatStringForDatePickerInputMask } from '~/utils/date-utils';
const StyledInputContainer = styled(FormFieldInputInnerContainer)`
const StyledInputContainerWrapper = styled.div`
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr 0;
@@ -327,49 +327,50 @@ export const FormDateFieldInput = ({
{label ? <InputLabel>{label}</InputLabel> : null}
<FormFieldInputRowContainer>
<StyledInputContainer
formFieldInputInstanceId={instanceId}
ref={datePickerWrapperRef}
hasRightElement={isDefined(VariablePicker) && !readonly}
>
{draftValue.type === 'static' ? (
<>
<StyledDateInput
type="text"
placeholder={placeholderToDisplay}
value={inputDate}
onFocus={handleInputFocus}
onChange={handleInputChange}
onKeyDown={handleInputKeydown}
disabled={readonly}
/>
<StyledInputContainerWrapper ref={datePickerWrapperRef}>
<FormFieldInputInnerContainer
formFieldInputInstanceId={instanceId}
hasRightElement={isDefined(VariablePicker) && !readonly}
>
{draftValue.type === 'static' ? (
<>
<StyledDateInput
type="text"
placeholder={placeholderToDisplay}
value={inputDate}
onFocus={handleInputFocus}
onChange={handleInputChange}
onKeyDown={handleInputKeydown}
disabled={readonly}
/>
{draftValue.mode === 'edit' ? (
<StyledDateInputContainer>
<StyledDateInputAbsoluteContainer>
<OverlayContainer>
<DatePicker
instanceId={instanceId}
plainDateString={pickerDate}
onChange={handlePickerChange}
onClose={handlePickerMouseSelect}
onEnter={handlePickerEnter}
onEscape={handlePickerEscape}
onClear={handlePickerClear}
hideHeaderInput
/>
</OverlayContainer>
</StyledDateInputAbsoluteContainer>
</StyledDateInputContainer>
) : null}
</>
) : (
<VariableChipStandalone
rawVariableName={draftValue.value}
onRemove={readonly ? undefined : handleUnlinkVariable}
/>
)}
</StyledInputContainer>
{draftValue.mode === 'edit' ? (
<StyledDateInputContainer>
<StyledDateInputAbsoluteContainer>
<OverlayContainer>
<DatePicker
instanceId={instanceId}
plainDateString={pickerDate}
onChange={handlePickerChange}
onClose={handlePickerMouseSelect}
onEnter={handlePickerEnter}
onEscape={handlePickerEscape}
onClear={handlePickerClear}
hideHeaderInput
/>
</OverlayContainer>
</StyledDateInputAbsoluteContainer>
</StyledDateInputContainer>
) : null}
</>
) : (
<VariableChipStandalone
rawVariableName={draftValue.value}
onRemove={readonly ? undefined : handleUnlinkVariable}
/>
)}
</FormFieldInputInnerContainer>
</StyledInputContainerWrapper>
{VariablePicker && !readonly ? (
<VariablePicker
@@ -26,7 +26,7 @@ import { isDefined } from 'twenty-shared/utils';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { type Nullable } from 'twenty-ui/utilities';
const StyledInputContainer = styled(FormFieldInputInnerContainer)`
const StyledInputContainerWrapper = styled.div`
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr 0;
@@ -243,49 +243,50 @@ export const FormDateTimeFieldInput = ({
{label ? <InputLabel>{label}</InputLabel> : null}
<FormFieldInputRowContainer>
<StyledInputContainer
formFieldInputInstanceId={instanceId}
ref={datePickerWrapperRef}
hasRightElement={isDefined(VariablePicker) && !readonly}
>
{draftValue.type === 'static' ? (
<>
<StyledDateInputTextContainer>
<DateTimePickerInput
date={dateValue}
onChange={handleInputChange}
onFocus={handleInputFocus}
readonly={readonly}
timeZone={timeZone}
/>
</StyledDateInputTextContainer>
{draftValue.mode === 'edit' ? (
<StyledDateInputContainer>
<StyledDateInputAbsoluteContainer>
<OverlayContainer>
<DateTimePicker
instanceId={instanceId}
date={dateValue}
onChange={handlePickerChange}
onClose={handlePickerMouseSelect}
onEnter={handlePickerEnter}
onEscape={handlePickerEscape}
onClear={handlePickerClear}
hideHeaderInput
timeZone={timeZone}
/>
</OverlayContainer>
</StyledDateInputAbsoluteContainer>
</StyledDateInputContainer>
) : null}
</>
) : (
<VariableChipStandalone
rawVariableName={draftValue.value}
onRemove={readonly ? undefined : handleUnlinkVariable}
/>
)}
</StyledInputContainer>
<StyledInputContainerWrapper ref={datePickerWrapperRef}>
<FormFieldInputInnerContainer
formFieldInputInstanceId={instanceId}
hasRightElement={isDefined(VariablePicker) && !readonly}
>
{draftValue.type === 'static' ? (
<>
<StyledDateInputTextContainer>
<DateTimePickerInput
date={dateValue}
onChange={handleInputChange}
onFocus={handleInputFocus}
readonly={readonly}
timeZone={timeZone}
/>
</StyledDateInputTextContainer>
{draftValue.mode === 'edit' ? (
<StyledDateInputContainer>
<StyledDateInputAbsoluteContainer>
<OverlayContainer>
<DateTimePicker
instanceId={instanceId}
date={dateValue}
onChange={handlePickerChange}
onClose={handlePickerMouseSelect}
onEnter={handlePickerEnter}
onEscape={handlePickerEscape}
onClear={handlePickerClear}
hideHeaderInput
timeZone={timeZone}
/>
</OverlayContainer>
</StyledDateInputAbsoluteContainer>
</StyledDateInputContainer>
) : null}
</>
) : (
<VariableChipStandalone
rawVariableName={draftValue.value}
onRemove={readonly ? undefined : handleUnlinkVariable}
/>
)}
</FormFieldInputInnerContainer>
</StyledInputContainerWrapper>
{VariablePicker && !readonly ? (
<VariablePicker
instanceId={instanceId}
@@ -50,7 +50,14 @@ const StyledDisplayModeReadonlyContainer = styled.div`
width: 100%;
`;
const StyledDisplayModeContainer = styled(StyledDisplayModeReadonlyContainer)`
const StyledDisplayModeContainer = styled.div`
align-items: center;
background: transparent;
border: none;
display: flex;
font-family: inherit;
padding-inline: ${themeCssVariables.spacing[2]};
width: 100%;
cursor: pointer;
&:hover,
@@ -65,7 +72,7 @@ const StyledSelectInputContainer = styled.div`
top: ${themeCssVariables.spacing[9]};
`;
const StyledPlaceholder = styled(FormFieldPlaceholder)`
const StyledPlaceholderContainer = styled.div`
width: 100%;
`;
@@ -223,7 +230,9 @@ export const FormMultiSelectFieldInput = ({
options={selectedOptions}
/>
) : (
<StyledPlaceholder />
<StyledPlaceholderContainer>
<FormFieldPlaceholder />
</StyledPlaceholderContainer>
)}
<IconChevronDown
size={theme.icon.size.md}
@@ -243,7 +252,11 @@ export const FormMultiSelectFieldInput = ({
options={selectedOptions}
/>
) : (
<StyledPlaceholder>{placeholderText}</StyledPlaceholder>
<StyledPlaceholderContainer>
<FormFieldPlaceholder>
{placeholderText}
</FormFieldPlaceholder>
</StyledPlaceholderContainer>
)}
<IconChevronDown
size={theme.icon.size.md}
@@ -22,9 +22,7 @@ import { CustomError, isDefined, isValidUuid } from 'twenty-shared/utils';
import { IconChevronDown, IconForbid } from 'twenty-ui/display';
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
const StyledFormSelectContainer = styled(FormFieldInputInnerContainer)<{
readonly?: boolean;
}>`
const StyledFormSelectContainerWrapper = styled.div<{ readonly?: boolean }>`
align-items: center;
height: 32px;
justify-content: space-between;
@@ -166,19 +164,20 @@ export const FormSingleRecordPicker = ({
{label ? <InputLabel>{label}</InputLabel> : null}
<FormFieldInputRowContainer>
{disabled ? (
<StyledFormSelectContainer
formFieldInputInstanceId={componentId}
hasRightElement={false}
readonly
>
<FormSingleRecordFieldChip
draftValue={draftValue}
selectedRecord={selectedRecord}
objectNameSingular={objectNameSingulars[0]}
onRemove={handleUnlinkVariable}
disabled={disabled}
/>
</StyledFormSelectContainer>
<StyledFormSelectContainerWrapper readonly>
<FormFieldInputInnerContainer
formFieldInputInstanceId={componentId}
hasRightElement={false}
>
<FormSingleRecordFieldChip
draftValue={draftValue}
selectedRecord={selectedRecord}
objectNameSingular={objectNameSingulars[0]}
onRemove={handleUnlinkVariable}
disabled={disabled}
/>
</FormFieldInputInnerContainer>
</StyledFormSelectContainerWrapper>
) : (
<Dropdown
dropdownId={dropdownId}
@@ -190,25 +189,27 @@ export const FormSingleRecordPicker = ({
y: parseInt(theme.spacing[1], 10),
}}
clickableComponent={
<StyledFormSelectContainer
formFieldInputInstanceId={componentId}
hasRightElement={isDefined(VariablePicker) && !disabled}
preventFocusStackUpdate={true}
>
<FormSingleRecordFieldChip
draftValue={draftValue}
selectedRecord={selectedRecord}
objectNameSingular={objectNameSingulars[0]}
onRemove={handleUnlinkVariable}
disabled={disabled}
/>
<StyledIconButton>
<IconChevronDown
size={theme.icon.size.md}
color={theme.font.color.light}
<StyledFormSelectContainerWrapper>
<FormFieldInputInnerContainer
formFieldInputInstanceId={componentId}
hasRightElement={isDefined(VariablePicker) && !disabled}
preventFocusStackUpdate={true}
>
<FormSingleRecordFieldChip
draftValue={draftValue}
selectedRecord={selectedRecord}
objectNameSingular={objectNameSingulars[0]}
onRemove={handleUnlinkVariable}
disabled={disabled}
/>
</StyledIconButton>
</StyledFormSelectContainer>
<StyledIconButton>
<IconChevronDown
size={theme.icon.size.md}
color={theme.font.color.light}
/>
</StyledIconButton>
</FormFieldInputInnerContainer>
</StyledFormSelectContainerWrapper>
}
dropdownComponents={
<SingleRecordPicker
@@ -43,23 +43,15 @@ const StyledCustomPhoneInputContainer = styled.div<{
height: ${({ hasItem }) => (hasItem ? '30px' : 'auto')};
`;
const StyledCustomPhoneInput = styled(ReactPhoneNumberInput)`
const StyledCustomPhoneInputWrapper = styled.div`
background-color: transparent;
border: none;
color: ${themeCssVariables.font.color.primary};
font-family: ${themeCssVariables.font.family};
font-size: inherit;
font-weight: inherit;
outline: none;
padding: 0;
&::placeholder,
&::-webkit-input-placeholder {
color: ${themeCssVariables.font.color.light};
font-family: ${themeCssVariables.font.family};
font-weight: ${themeCssVariables.font.weight.medium};
}
height: 100%;
width: calc(100% - ${themeCssVariables.spacing[8]});
.PhoneInputInput {
background: none;
@@ -83,7 +75,6 @@ const StyledCustomPhoneInput = styled(ReactPhoneNumberInput)`
border-radius: ${themeCssVariables.border.radius.xs};
height: 12px;
}
width: calc(100% - ${themeCssVariables.spacing[8]});
`;
export const PhonesFieldInput = () => {
@@ -219,16 +210,18 @@ export const PhonesFieldInput = () => {
hasItem={!!phones.length}
hasError={hasError}
>
<StyledCustomPhoneInput
autoFocus={autoFocus}
placeholder={placeholder}
value={value as E164Number}
onChange={onChange as unknown as (newValue: E164Number) => void}
international={true}
withCountryCallingCode={true}
countrySelectComponent={PhoneCountryPickerDropdownButton}
defaultCountry={defaultCountry}
/>
<StyledCustomPhoneInputWrapper>
<ReactPhoneNumberInput
autoFocus={autoFocus}
placeholder={placeholder}
value={value as E164Number}
onChange={onChange as unknown as (newValue: E164Number) => void}
international={true}
withCountryCallingCode={true}
countrySelectComponent={PhoneCountryPickerDropdownButton}
defaultCountry={defaultCountry}
/>
</StyledCustomPhoneInputWrapper>
</StyledCustomPhoneInputContainer>
);
}}
@@ -6,7 +6,7 @@ import { isDefined } from 'twenty-shared/utils';
import { MenuItem } from 'twenty-ui/navigation';
import { Tag } from 'twenty-ui/components';
const StyledMenuItem = styled(MenuItem)`
const StyledMenuItemContainer = styled.div`
width: calc(100% - 2 * var(--horizontal-padding));
`;
@@ -29,28 +29,30 @@ export const RecordIndexPageKanbanAddMenuItem = ({
}
return (
<StyledMenuItem
text={
<Tag
variant={
recordGroupDefinition.type === RecordGroupDefinitionType.Value
? 'solid'
: 'outline'
}
color={
recordGroupDefinition.type === RecordGroupDefinitionType.Value
? recordGroupDefinition.color
: 'transparent'
}
text={recordGroupDefinition.title}
weight={
recordGroupDefinition.type === RecordGroupDefinitionType.Value
? 'regular'
: 'medium'
}
/>
}
onClick={() => onItemClick(recordGroupDefinition)}
/>
<StyledMenuItemContainer>
<MenuItem
text={
<Tag
variant={
recordGroupDefinition.type === RecordGroupDefinitionType.Value
? 'solid'
: 'outline'
}
color={
recordGroupDefinition.type === RecordGroupDefinitionType.Value
? recordGroupDefinition.color
: 'transparent'
}
text={recordGroupDefinition.title}
weight={
recordGroupDefinition.type === RecordGroupDefinitionType.Value
? 'regular'
: 'medium'
}
/>
}
onClick={() => onItemClick(recordGroupDefinition)}
/>
</StyledMenuItemContainer>
);
};
@@ -27,7 +27,7 @@ const StyledShowPageRightContainer = styled.div`
overflow: auto;
`;
const StyledTabList = styled(TabList)`
const StyledTabListContainer = styled.div`
background-color: ${themeCssVariables.background.secondary};
padding-left: ${themeCssVariables.spacing[2]};
`;
@@ -65,11 +65,13 @@ export const MergeRecordsContainer = ({
<TabListComponentInstanceContext.Provider
value={{ instanceId: instanceId }}
>
<StyledTabList
tabs={tabs}
behaveAsLinks={false}
componentInstanceId={instanceId}
/>
<StyledTabListContainer>
<TabList
tabs={tabs}
behaveAsLinks={false}
componentInstanceId={instanceId}
/>
</StyledTabListContainer>
</TabListComponentInstanceContext.Provider>
<StyledContentContainer>
{activeTabId === MergeRecordsTabId.MERGE_PREVIEW && (
@@ -8,7 +8,7 @@ import { getPositionNumberIcon } from '@/object-record/record-merge/utils/getPos
import { getPositionWordLabel } from '@/object-record/record-merge/utils/getPositionWordLabel';
import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledSection = styled(Section)`
const StyledSectionContainer = styled.div`
margin: ${themeCssVariables.spacing[4]};
width: auto;
`;
@@ -37,14 +37,16 @@ export const MergeSettingsTab = () => {
}
return (
<StyledSection>
<Select
dropdownId="merge-settings-priority-select"
options={priorityOptions}
value={mergeSettings.conflictPriorityIndex}
onChange={handleSelectionChange}
label={t`Fields conflicts`}
/>
</StyledSection>
<StyledSectionContainer>
<Section>
<Select
dropdownId="merge-settings-priority-select"
options={priorityOptions}
value={mergeSettings.conflictPriorityIndex}
onChange={handleSelectionChange}
label={t`Fields conflicts`}
/>
</Section>
</StyledSectionContainer>
);
};
@@ -16,10 +16,10 @@ import {
type AnimatedPlaceholderType,
} from 'twenty-ui/layout';
const StyledEmptyPlaceholderOuterContainer = styled(
AnimatedPlaceholderEmptyContainer,
)`
align-items: flex-start;
const StyledEmptyPlaceholderOuterContainer = styled.div`
> * {
align-items: flex-start;
}
`;
type RecordTableEmptyStateDisplayButtonComponentProps = {
@@ -22,8 +22,7 @@ const StyledContainer = styled.div`
padding-right: ${themeCssVariables.spacing[1]};
`;
// TODO: refactor
const StyledRecordTableTd = styled(RecordTableCellStyleWrapper)`
const StyledRecordTableTdContainer = styled.div`
border-left: 1px solid transparent;
`;
@@ -43,14 +42,16 @@ export const RecordTableCellCheckbox = () => {
);
return (
<StyledRecordTableTd
isSelected={isSelected}
hasRightBorder={false}
widthClassName={RECORD_TABLE_COLUMN_CHECKBOX_WIDTH_CLASS_NAME}
>
<StyledContainer onClick={handleClick} data-select-disable>
<Checkbox hoverable checked={isSelected} />
</StyledContainer>
</StyledRecordTableTd>
<StyledRecordTableTdContainer>
<RecordTableCellStyleWrapper
isSelected={isSelected}
hasRightBorder={false}
widthClassName={RECORD_TABLE_COLUMN_CHECKBOX_WIDTH_CLASS_NAME}
>
<StyledContainer onClick={handleClick} data-select-disable>
<Checkbox hoverable checked={isSelected} />
</StyledContainer>
</RecordTableCellStyleWrapper>
</StyledRecordTableTdContainer>
);
};
@@ -19,8 +19,7 @@ const StyledContainer = styled.div`
padding-right: ${themeCssVariables.spacing[1]};
`;
// TODO: refactor
const StyledRecordTableTd = styled(RecordTableCellStyleWrapper)`
const StyledRecordTableTdContainer = styled.div`
border-left: 1px solid transparent;
`;
@@ -28,14 +27,16 @@ export const RecordTableCellCheckboxPlaceholder = () => {
const { hasUserSelectedAllRows } = useRecordTableBodyContextOrThrow();
return (
<StyledRecordTableTd
isSelected={hasUserSelectedAllRows}
hasRightBorder={false}
widthClassName={RECORD_TABLE_COLUMN_CHECKBOX_WIDTH_CLASS_NAME}
>
<StyledContainer data-select-disable>
<Checkbox hoverable checked={hasUserSelectedAllRows === true} />
</StyledContainer>
</StyledRecordTableTd>
<StyledRecordTableTdContainer>
<RecordTableCellStyleWrapper
isSelected={hasUserSelectedAllRows}
hasRightBorder={false}
widthClassName={RECORD_TABLE_COLUMN_CHECKBOX_WIDTH_CLASS_NAME}
>
<StyledContainer data-select-disable>
<Checkbox hoverable checked={hasUserSelectedAllRows === true} />
</StyledContainer>
</RecordTableCellStyleWrapper>
</StyledRecordTableTdContainer>
);
};
@@ -1,5 +1,4 @@
import { TABLE_Z_INDEX } from '@/object-record/record-table/constants/TableZIndex';
import { StyledCell } from '@/object-record/record-table/record-table-cell/components/RecordTableCellStyleWrapper';
import { isRecordTableScrolledVerticallyComponentState } from '@/object-record/record-table/states/isRecordTableScrolledVerticallyComponentState';
import { recordTableFocusPositionComponentState } from '@/object-record/record-table/states/recordTableFocusPositionComponentState';
import { recordTableHoverPositionComponentState } from '@/object-record/record-table/states/recordTableHoverPositionComponentState';
@@ -12,7 +11,30 @@ import { cx } from '@linaria/core';
import { useContext, type ReactNode } from 'react';
import { ThemeContext } from 'twenty-ui/theme-constants';
const StyledRecordTableTd = styled(StyledCell)<{ zIndex: number }>`
const StyledRecordTableTd = styled.div<{
backgroundColor: string;
borderColor: string;
isDragging?: boolean;
fontColor: string;
hasRightBorder?: boolean;
hasBottomBorder?: boolean;
zIndex: number;
}>`
border-bottom: 1px solid
${({ borderColor, hasBottomBorder, isDragging }) =>
hasBottomBorder && !isDragging ? borderColor : 'transparent'};
color: ${({ fontColor }) => fontColor};
border-right: ${({ borderColor, hasRightBorder }) =>
hasRightBorder ? `1px solid ${borderColor}` : 'none'};
padding: 0;
text-align: left;
background: ${({ backgroundColor, isDragging }) =>
isDragging ? 'transparent' : backgroundColor};
z-index: ${({ zIndex }) => zIndex};
`;
@@ -20,7 +20,7 @@ const StyledText = styled.span`
z-index: 1;
`;
const StyledScrollableContainer = styled.div`
const StyledValueContainer = styled.div`
overflow-x: auto;
white-space: nowrap;
scrollbar-width: none;
@@ -29,9 +29,7 @@ const StyledScrollableContainer = styled.div`
&::-webkit-scrollbar {
display: none;
}
`;
const StyledValueContainer = styled(StyledScrollableContainer)`
align-items: center;
display: flex;
gap: 4px;
@@ -38,7 +38,7 @@ const StyledCell = styled.div<{ isUnfolded: boolean; isFirstCell: boolean }>`
: '0'};
`;
const StyledIcon = styled(IconChevronDown)`
const StyledIconContainer = styled.div`
align-items: center;
display: flex;
height: 20px;
@@ -94,7 +94,9 @@ export const RecordTableColumnAggregateFooterValueCell = ({
dropdownId={dropdownId}
/>
{!hasAggregateOperationForViewField && (
<StyledIcon fontWeight="light" size={theme.icon.size.sm} />
<StyledIconContainer>
<IconChevronDown fontWeight="light" size={theme.icon.size.sm} />
</StyledIconContainer>
)}
</>
) : (
@@ -30,7 +30,7 @@ export type RecordTableColumnHeadDropdownMenuProps = {
objectMetadataId: string;
};
const StyledDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
const StyledDropdownMenuItemsContainerWrapper = styled.div`
z-index: ${themeCssVariables.lastLayerZIndex};
`;
@@ -136,44 +136,46 @@ export const RecordTableColumnHeadDropdownMenu = ({
return (
<DropdownContent>
<StyledDropdownMenuItemsContainer>
{isFilterable && (
<MenuItem
LeftIcon={IconFilter}
onClick={handleFilterClick}
text={t`Filter`}
/>
)}
{isSortable && (
<MenuItem
LeftIcon={IconSortDescending}
onClick={handleSortClick}
text={t`Sort`}
/>
)}
{showSeparator && <DropdownMenuSeparator />}
{canMoveLeft && (
<MenuItem
LeftIcon={IconArrowLeft}
onClick={handleColumnMoveLeft}
text={t`Move left`}
/>
)}
{canMoveRight && (
<MenuItem
LeftIcon={IconArrowRight}
onClick={handleColumnMoveRight}
text={t`Move right`}
/>
)}
{canHide && (
<MenuItem
LeftIcon={IconEyeOff}
onClick={async () => await handleColumnVisibility()}
text={t`Hide`}
/>
)}
</StyledDropdownMenuItemsContainer>
<StyledDropdownMenuItemsContainerWrapper>
<DropdownMenuItemsContainer>
{isFilterable && (
<MenuItem
LeftIcon={IconFilter}
onClick={handleFilterClick}
text={t`Filter`}
/>
)}
{isSortable && (
<MenuItem
LeftIcon={IconSortDescending}
onClick={handleSortClick}
text={t`Sort`}
/>
)}
{showSeparator && <DropdownMenuSeparator />}
{canMoveLeft && (
<MenuItem
LeftIcon={IconArrowLeft}
onClick={handleColumnMoveLeft}
text={t`Move left`}
/>
)}
{canMoveRight && (
<MenuItem
LeftIcon={IconArrowRight}
onClick={handleColumnMoveRight}
text={t`Move right`}
/>
)}
{canHide && (
<MenuItem
LeftIcon={IconEyeOff}
onClick={async () => await handleColumnVisibility()}
text={t`Hide`}
/>
)}
</DropdownMenuItemsContainer>
</StyledDropdownMenuItemsContainerWrapper>
</DropdownContent>
);
};
@@ -20,13 +20,6 @@ import {
import { type IconComponent } from 'twenty-ui/display';
import { useIsMobile } from 'twenty-ui/utilities';
const StyledDragDropPlaceholderCell = styled(
RecordTableDragAndDropPlaceholderCell,
)`
left: 0;
position: sticky;
`;
const StyledFieldPlaceholderCell = styled.div<{ widthOfFields: number }>`
height: ${RECORD_TABLE_ROW_HEIGHT}px;
min-width: ${({ widthOfFields }) => widthOfFields}px;
@@ -137,7 +130,7 @@ export const RecordTableActionRow = ({
return (
<StyledRecordTableDraggableTr onClick={onClick}>
<StyledDragDropPlaceholderCell />
<RecordTableDragAndDropPlaceholderCell />
<StyledIconContainer>
<LeftIcon
stroke={theme.icon.stroke.sm}
@@ -3,7 +3,7 @@ import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/use
import { styled } from '@linaria/react';
import { NotificationCounter } from 'twenty-ui/navigation';
const StyledNotificationCounter = styled(NotificationCounter)`
const StyledNotificationCounterContainer = styled.div`
position: absolute;
top: -7px;
left: -7px;
@@ -23,5 +23,9 @@ export const RecordTableRowMultiDragCounterChip = () => {
return null;
}
return <StyledNotificationCounter count={selectedCount} />;
return (
<StyledNotificationCounterContainer>
<NotificationCounter count={selectedCount} />
</StyledNotificationCounterContainer>
);
};
@@ -64,7 +64,7 @@ const StyledChevronContainer = styled.div`
z-index: ${TABLE_Z_INDEX.groupSection.stickyCell};
`;
const StyledAnimatedLightIconButton = styled(AnimatedLightIconButton)`
const StyledAnimatedLightIconButtonContainer = styled.div`
display: block;
margin: auto;
@@ -88,7 +88,7 @@ const StyledRecordGroupSection = styled.div<{ width: number }>`
z-index: ${TABLE_Z_INDEX.groupSection.stickyCell};
`;
const StyledTag = styled(Tag)`
const StyledTagContainer = styled.div`
flex-shrink: 0;
`;
@@ -195,32 +195,36 @@ export const RecordTableRecordGroupSection = () => {
<StyledTrContainer onClick={handleDropdownToggle}>
<StyledRecordTableDragAndDropPlaceholderCell />
<StyledChevronContainer>
<StyledAnimatedLightIconButton
Icon={IconChevronDown}
size="small"
accent="secondary"
animate={{ rotate: !isRecordGroupTableSectionToggled ? -90 : 0 }}
transition={{ duration: theme.animation.duration.normal }}
/>
<StyledAnimatedLightIconButtonContainer>
<AnimatedLightIconButton
Icon={IconChevronDown}
size="small"
accent="secondary"
animate={{ rotate: !isRecordGroupTableSectionToggled ? -90 : 0 }}
transition={{ duration: theme.animation.duration.normal }}
/>
</StyledAnimatedLightIconButtonContainer>
</StyledChevronContainer>
<StyledRecordGroupSection
className="disable-shadow"
width={widthOfLabelIdentifierRecordField}
>
<StyledTag
variant={
recordGroupDefinition.type !== RecordGroupDefinitionType.NoValue
? 'solid'
: 'outline'
}
color={
recordGroupDefinition.type !== RecordGroupDefinitionType.NoValue
? recordGroupDefinition.color
: 'transparent'
}
text={recordGroupDefinition.title}
weight="medium"
/>
<StyledTagContainer>
<Tag
variant={
recordGroupDefinition.type !== RecordGroupDefinitionType.NoValue
? 'solid'
: 'outline'
}
color={
recordGroupDefinition.type !== RecordGroupDefinitionType.NoValue
? recordGroupDefinition.color
: 'transparent'
}
text={recordGroupDefinition.title}
weight="medium"
/>
</StyledTagContainer>
<RecordBoardColumnHeaderAggregateDropdown
aggregateValue={recordIndexAggregateDisplayValueForGroupValue}
dropdownId={`record-group-section-aggregate-dropdown-${currentRecordGroupId}`}
@@ -10,12 +10,14 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { Section } from 'twenty-ui/layout';
import { themeCssVariables } from 'twenty-ui/theme-constants';
const StyledSection = styled(Section)`
display: flex;
flex-direction: column;
gap: ${themeCssVariables.spacing[6]};
padding: ${themeCssVariables.spacing[4]} ${themeCssVariables.spacing[3]};
width: auto;
const StyledSectionContainer = styled.div`
> * {
display: flex;
flex-direction: column;
gap: ${themeCssVariables.spacing[6]};
padding: ${themeCssVariables.spacing[4]} ${themeCssVariables.spacing[3]};
width: auto;
}
`;
export type UpdateMultipleRecordsFormProps = {
@@ -50,35 +52,37 @@ export const UpdateMultipleRecordsForm = ({
}));
return (
<StyledSection>
{fieldsWithDefinitions.map(({ fieldMetadataItem, fieldDefinition }) => {
const fieldName = fieldDefinition.metadata.fieldName;
const isRelation = isFieldRelation(fieldDefinition);
const fieldNameOrRelationIdName =
isRelation && fieldMetadataItem.type === FieldMetadataType.RELATION
? (fieldMetadataItem.settings?.joinColumnName as string)
: fieldName;
<StyledSectionContainer>
<Section>
{fieldsWithDefinitions.map(({ fieldMetadataItem, fieldDefinition }) => {
const fieldName = fieldDefinition.metadata.fieldName;
const isRelation = isFieldRelation(fieldDefinition);
const fieldNameOrRelationIdName =
isRelation && fieldMetadataItem.type === FieldMetadataType.RELATION
? (fieldMetadataItem.settings?.joinColumnName as string)
: fieldName;
const value = values[fieldNameOrRelationIdName];
const value = values[fieldNameOrRelationIdName];
const handleValueChange = (newValue: any) => {
if (isUpdateRecordValueEmpty(newValue)) {
onChange(fieldNameOrRelationIdName, undefined);
} else {
onChange(fieldNameOrRelationIdName, newValue);
}
};
const handleValueChange = (newValue: any) => {
if (isUpdateRecordValueEmpty(newValue)) {
onChange(fieldNameOrRelationIdName, undefined);
} else {
onChange(fieldNameOrRelationIdName, newValue);
}
};
return (
<FormFieldInput
key={fieldDefinition.metadata.fieldName}
readonly={disabled}
field={fieldDefinition}
defaultValue={value}
onChange={handleValueChange}
/>
);
})}
</StyledSection>
return (
<FormFieldInput
key={fieldDefinition.metadata.fieldName}
readonly={disabled}
field={fieldDefinition}
defaultValue={value}
onChange={handleValueChange}
/>
);
})}
</Section>
</StyledSectionContainer>
);
};