Add styled component rule (#1261)

* Add StyledComponent rule

* update doc

* update doc

* update doc
This commit is contained in:
Weiko
2023-08-17 20:58:02 -07:00
committed by GitHub
parent 390e70a196
commit 9b34a0ff3d
70 changed files with 433 additions and 354 deletions

View File

@ -100,3 +100,36 @@ type MyType = {
}; };
``` ```
## Styling
### Use StyledComponents
Components should be styled with StyledComponents.
```tsx
// ❌ Bad
<div className="my-class">Hello World</div>
```
```tsx
// ✅ Good
const StyledTitle = styled.div`
color: red;
`;
```
Styled components should be prefixed with "Styled" to differentiate them from "real" components.
```tsx
// ❌ Bad
const Title = styled.div`
color: red;
`;
```
```tsx
// ✅ Good
const StyledTitle = styled.div`
color: red;
`;
```

View File

@ -48,6 +48,7 @@ module.exports = {
'simple-import-sort/exports': 'error', 'simple-import-sort/exports': 'error',
'twenty/sort-css-properties-alphabetically': 'error', 'twenty/sort-css-properties-alphabetically': 'error',
'twenty/no-hardcoded-colors': 'error', 'twenty/no-hardcoded-colors': 'error',
'twenty/styled-components-prefixed-with-styled': 'error',
'func-style':['error', 'declaration', { 'allowArrowFunctions': true }], 'func-style':['error', 'declaration', { 'allowArrowFunctions': true }],
"@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/no-unused-vars": "off",
"no-unused-vars": "off", "no-unused-vars": "off",

View File

@ -10,7 +10,7 @@ import { Activity, useUpdateActivityMutation } from '~/generated/graphql';
import { ACTIVITY_UPDATE_FRAGMENT } from '../graphql/fragments/activityUpdateFragment'; import { ACTIVITY_UPDATE_FRAGMENT } from '../graphql/fragments/activityUpdateFragment';
const BlockNoteStyledContainer = styled.div` const StyledBlockNoteStyledContainer = styled.div`
width: 100%; width: 100%;
`; `;
@ -70,8 +70,8 @@ export function ActivityBodyEditor({ activity, onChange }: OwnProps) {
}); });
return ( return (
<BlockNoteStyledContainer> <StyledBlockNoteStyledContainer>
<BlockEditor editor={editor} /> <BlockEditor editor={editor} />
</BlockNoteStyledContainer> </StyledBlockNoteStyledContainer>
); );
} }

View File

@ -15,7 +15,7 @@ const meta: Meta<typeof CommentChip> = {
export default meta; export default meta;
type Story = StoryObj<typeof CommentChip>; type Story = StoryObj<typeof CommentChip>;
const TestCellContainer = styled.div` const StyledTestCellContainer = styled.div`
align-items: center; align-items: center;
background: ${({ theme }) => theme.background.primary}; background: ${({ theme }) => theme.background.primary};
display: flex; display: flex;
@ -51,10 +51,10 @@ export const InCellDefault: Story = {
args: { count: 12 }, args: { count: 12 },
decorators: [ decorators: [
(Story) => ( (Story) => (
<TestCellContainer> <StyledTestCellContainer>
<StyledFakeCellText>Fake short text</StyledFakeCellText> <StyledFakeCellText>Fake short text</StyledFakeCellText>
<Story /> <Story />
</TestCellContainer> </StyledTestCellContainer>
), ),
], ],
}; };
@ -63,12 +63,12 @@ export const InCellOverlappingBlur: Story = {
...InCellDefault, ...InCellDefault,
decorators: [ decorators: [
(Story) => ( (Story) => (
<TestCellContainer> <StyledTestCellContainer>
<StyledFakeCellText> <StyledFakeCellText>
Fake long text to demonstrate ellipsis Fake long text to demonstrate ellipsis
</StyledFakeCellText> </StyledFakeCellText>
<Story /> <Story />
</TestCellContainer> </StyledTestCellContainer>
), ),
], ],
}; };

View File

@ -1,6 +1,6 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
const Separator = styled.div` const StyledSeparator = styled.div`
background-color: ${({ theme }) => theme.border.color.medium}; background-color: ${({ theme }) => theme.border.color.medium};
height: 1px; height: 1px;
margin-bottom: ${({ theme }) => theme.spacing(3)}; margin-bottom: ${({ theme }) => theme.spacing(3)};
@ -9,5 +9,5 @@ const Separator = styled.div`
`; `;
export function HorizontalSeparator(): JSX.Element { export function HorizontalSeparator(): JSX.Element {
return <Separator />; return <StyledSeparator />;
} }

View File

@ -11,11 +11,11 @@ const meta: Meta<typeof CompanyChip> = {
component: CompanyChip, component: CompanyChip,
decorators: [ decorators: [
(Story) => ( (Story) => (
<TestCellContainer> <StyledTestCellContainer>
<BrowserRouter> <BrowserRouter>
<Story /> <Story />
</BrowserRouter> </BrowserRouter>
</TestCellContainer> </StyledTestCellContainer>
), ),
ComponentDecorator, ComponentDecorator,
], ],
@ -24,7 +24,7 @@ const meta: Meta<typeof CompanyChip> = {
export default meta; export default meta;
type Story = StoryObj<typeof CompanyChip>; type Story = StoryObj<typeof CompanyChip>;
const TestCellContainer = styled.div` const StyledTestCellContainer = styled.div`
align-items: center; align-items: center;
background: ${({ theme }) => theme.background.primary}; background: ${({ theme }) => theme.background.primary};
display: flex; display: flex;

View File

@ -6,7 +6,7 @@ import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { PersonChip } from '../PersonChip'; import { PersonChip } from '../PersonChip';
const TestCellContainer = styled.div` const StyledTestCellContainer = styled.div`
align-items: center; align-items: center;
background: ${({ theme }) => theme.background.primary}; background: ${({ theme }) => theme.background.primary};
display: flex; display: flex;
@ -22,11 +22,11 @@ const meta: Meta<typeof PersonChip> = {
component: PersonChip, component: PersonChip,
decorators: [ decorators: [
(Story) => ( (Story) => (
<TestCellContainer> <StyledTestCellContainer>
<BrowserRouter> <BrowserRouter>
<Story /> <Story />
</BrowserRouter> </BrowserRouter>
</TestCellContainer> </StyledTestCellContainer>
), ),
ComponentDecorator, ComponentDecorator,
], ],

View File

@ -4,7 +4,7 @@ import { MainButton } from '@/ui/button/components/MainButton';
import { Modal } from '@/ui/modal/components/Modal'; import { Modal } from '@/ui/modal/components/Modal';
import { CircularProgressBar } from '@/ui/progress-bar/components/CircularProgressBar'; import { CircularProgressBar } from '@/ui/progress-bar/components/CircularProgressBar';
const Footer = styled(Modal.Footer)` const StyledFooter = styled(Modal.Footer)`
height: 60px; height: 60px;
justify-content: center; justify-content: center;
padding: 0px; padding: 0px;
@ -12,7 +12,7 @@ const Footer = styled(Modal.Footer)`
padding-right: ${({ theme }) => theme.spacing(30)}; padding-right: ${({ theme }) => theme.spacing(30)};
`; `;
const Button = styled(MainButton)` const StyledButton = styled(MainButton)`
width: 200px; width: 200px;
`; `;
@ -27,11 +27,11 @@ export const ContinueButton = ({
title, title,
isLoading, isLoading,
}: ContinueButtonProps) => ( }: ContinueButtonProps) => (
<Footer> <StyledFooter>
<Button <StyledButton
icon={isLoading && <CircularProgressBar size={16} barWidth={2} />} icon={isLoading && <CircularProgressBar size={16} barWidth={2} />}
title={title} title={title}
onClick={!isLoading ? onContinue : undefined} onClick={!isLoading ? onContinue : undefined}
/> />
</Footer> </StyledFooter>
); );

View File

@ -6,20 +6,20 @@ export type Props = React.ComponentProps<'div'> & {
description?: string; description?: string;
}; };
const Container = styled.div` const StyledContainer = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
`; `;
const Title = styled.span` const StyledTitle = styled.span`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.lg}; font-size: ${({ theme }) => theme.font.size.lg};
font-weight: ${({ theme }) => theme.font.weight.semiBold}; font-weight: ${({ theme }) => theme.font.weight.semiBold};
text-align: center; text-align: center;
`; `;
const Description = styled.span` const StyledDescription = styled.span`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.sm}; font-size: ${({ theme }) => theme.font.size.sm};
font-weight: ${({ theme }) => theme.font.weight.regular}; font-weight: ${({ theme }) => theme.font.weight.regular};
@ -29,9 +29,9 @@ const Description = styled.span`
export function Heading({ title, description, ...props }: Props) { export function Heading({ title, description, ...props }: Props) {
return ( return (
<Container {...props}> <StyledContainer {...props}>
<Title>{title}</Title> <StyledTitle>{title}</StyledTitle>
{description && <Description>{description}</Description>} {description && <StyledDescription>{description}</StyledDescription>}
</Container> </StyledContainer>
); );
} }

View File

@ -25,7 +25,7 @@ import { AppTooltip } from '@/ui/tooltip/AppTooltip';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useUpdateEffect } from '~/hooks/useUpdateEffect'; import { useUpdateEffect } from '~/hooks/useUpdateEffect';
const DropdownItem = styled.div` const StyledDropdownItem = styled.div`
align-items: center; align-items: center;
background-color: ${({ theme }) => theme.background.tertiary}; background-color: ${({ theme }) => theme.background.tertiary};
border-radius: ${({ theme }) => theme.border.radius.sm}; border-radius: ${({ theme }) => theme.border.radius.sm};
@ -42,7 +42,7 @@ const DropdownItem = styled.div`
} }
`; `;
const DropdownLabel = styled.span<{ isPlaceholder: boolean }>` const StyledDropdownLabel = styled.span<{ isPlaceholder: boolean }>`
color: ${({ theme, isPlaceholder }) => color: ${({ theme, isPlaceholder }) =>
isPlaceholder ? theme.font.color.tertiary : theme.font.color.primary}; isPlaceholder ? theme.font.color.tertiary : theme.font.color.primary};
display: flex; display: flex;
@ -53,7 +53,7 @@ const DropdownLabel = styled.span<{ isPlaceholder: boolean }>`
padding-right: ${({ theme }) => theme.spacing(1)}; padding-right: ${({ theme }) => theme.spacing(1)};
`; `;
const FloatingDropdown = styled.div` const StyledFloatingDropdown = styled.div`
z-index: ${({ theme }) => theme.lastLayerZIndex}; z-index: ${({ theme }) => theme.lastLayerZIndex};
`; `;
@ -147,7 +147,7 @@ export const MatchColumnSelect = ({
return ( return (
<> <>
<DropdownItem <StyledDropdownItem
id={name} id={name}
ref={(node) => { ref={(node) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@ -158,14 +158,14 @@ export const MatchColumnSelect = ({
onClick={handleDropdownItemClick} onClick={handleDropdownItemClick}
> >
{renderIcon(value?.icon)} {renderIcon(value?.icon)}
<DropdownLabel isPlaceholder={!value?.label}> <StyledDropdownLabel isPlaceholder={!value?.label}>
{value?.label ?? placeholder} {value?.label ?? placeholder}
</DropdownLabel> </StyledDropdownLabel>
<IconChevronDown size={16} color={theme.font.color.tertiary} /> <IconChevronDown size={16} color={theme.font.color.tertiary} />
</DropdownItem> </StyledDropdownItem>
{isOpen && {isOpen &&
createPortal( createPortal(
<FloatingDropdown ref={refs.setFloating} style={floatingStyles}> <StyledFloatingDropdown ref={refs.setFloating} style={floatingStyles}>
<DropdownMenu <DropdownMenu
ref={dropdownContainerRef} ref={dropdownContainerRef}
width={dropdownItemRef.current?.clientWidth} width={dropdownItemRef.current?.clientWidth}
@ -210,7 +210,7 @@ export const MatchColumnSelect = ({
)} )}
</DropdownMenuItemsContainer> </DropdownMenuItemsContainer>
</DropdownMenu> </DropdownMenu>
</FloatingDropdown>, </StyledFloatingDropdown>,
document.body, document.body,
)} )}
</> </>

View File

@ -6,7 +6,7 @@ import { IconButton } from '@/ui/button/components/IconButton';
import { useDialog } from '@/ui/dialog/hooks/useDialog'; import { useDialog } from '@/ui/dialog/hooks/useDialog';
import { IconX } from '@/ui/icon/index'; import { IconX } from '@/ui/icon/index';
const CloseButtonContainer = styled.div` const StyledCloseButtonContainer = styled.div`
align-items: center; align-items: center;
aspect-ratio: 1; aspect-ratio: 1;
display: flex; display: flex;
@ -39,12 +39,12 @@ export const ModalCloseButton = ({ onClose }: ModalCloseButtonProps) => {
return ( return (
<> <>
<CloseButtonContainer> <StyledCloseButtonContainer>
<IconButton <IconButton
icon={<IconX size={16} color={theme.font.color.tertiary} />} icon={<IconX size={16} color={theme.font.color.tertiary} />}
onClick={handleClose} onClick={handleClose}
/> />
</CloseButtonContainer> </StyledCloseButtonContainer>
</> </>
); );
}; };

View File

@ -3,7 +3,7 @@ import styled from '@emotion/styled';
import type { Columns } from '../MatchColumnsStep'; import type { Columns } from '../MatchColumnsStep';
const GridContainer = styled.div` const StyledGridContainer = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -12,7 +12,7 @@ const GridContainer = styled.div`
width: 100%; width: 100%;
`; `;
const Grid = styled.div` const StyledGrid = styled.div`
border: 1px solid ${({ theme }) => theme.border.color.medium}; border: 1px solid ${({ theme }) => theme.border.color.medium};
border-radius: ${({ theme }) => theme.border.radius.md}; border-radius: ${({ theme }) => theme.border.radius.md};
box-sizing: border-box; box-sizing: border-box;
@ -26,7 +26,7 @@ type HeightProps = {
height?: `${number}px`; height?: `${number}px`;
}; };
const GridRow = styled.div<HeightProps>` const StyledGridRow = styled.div<HeightProps>`
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -37,7 +37,7 @@ type PositionProps = {
position: 'left' | 'right'; position: 'left' | 'right';
}; };
const GridCell = styled.div<PositionProps>` const StyledGridCell = styled.div<PositionProps>`
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
@ -59,7 +59,7 @@ const GridCell = styled.div<PositionProps>`
}}; }};
`; `;
const GridHeader = styled.div<PositionProps>` const StyledGridHeader = styled.div<PositionProps>`
align-items: center; align-items: center;
background-color: ${({ theme }) => theme.background.tertiary}; background-color: ${({ theme }) => theme.background.tertiary};
box-sizing: border-box; box-sizing: border-box;
@ -98,29 +98,31 @@ export const ColumnGrid = <T extends string>({
}: ColumnGridProps<T>) => { }: ColumnGridProps<T>) => {
return ( return (
<> <>
<GridContainer> <StyledGridContainer>
<Grid> <StyledGrid>
<GridRow height="29px"> <StyledGridRow height="29px">
<GridHeader position="left">Imported data</GridHeader> <StyledGridHeader position="left">Imported data</StyledGridHeader>
<GridHeader position="right">Twenty fields</GridHeader> <StyledGridHeader position="right">Twenty fields</StyledGridHeader>
</GridRow> </StyledGridRow>
{columns.map((column, index) => { {columns.map((column, index) => {
const userColumn = renderUserColumn(columns, index); const userColumn = renderUserColumn(columns, index);
const templateColumn = renderTemplateColumn(columns, index); const templateColumn = renderTemplateColumn(columns, index);
if (React.isValidElement(userColumn)) { if (React.isValidElement(userColumn)) {
return ( return (
<GridRow key={index}> <StyledGridRow key={index}>
<GridCell position="left">{userColumn}</GridCell> <StyledGridCell position="left">{userColumn}</StyledGridCell>
<GridCell position="right">{templateColumn}</GridCell> <StyledGridCell position="right">
</GridRow> {templateColumn}
</StyledGridCell>
</StyledGridRow>
); );
} }
return null; return null;
})} })}
</Grid> </StyledGrid>
</GridContainer> </StyledGridContainer>
</> </>
); );
}; };

View File

@ -11,12 +11,12 @@ import type {
MatchedSelectOptionsColumn, MatchedSelectOptionsColumn,
} from '../MatchColumnsStep'; } from '../MatchColumnsStep';
const Container = styled.div` const StyledContainer = styled.div`
padding-bottom: ${({ theme }) => theme.spacing(1)}; padding-bottom: ${({ theme }) => theme.spacing(1)};
padding-left: ${({ theme }) => theme.spacing(2)}; padding-left: ${({ theme }) => theme.spacing(2)};
`; `;
const SelectLabel = styled.span` const StyledSelectLabel = styled.span`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.sm}; font-size: ${({ theme }) => theme.font.size.sm};
font-weight: ${({ theme }) => theme.font.weight.medium}; font-weight: ${({ theme }) => theme.font.weight.medium};
@ -40,8 +40,8 @@ export const SubMatchingSelect = <T extends string>({
const value = options.find((opt) => opt.value === option.value); const value = options.find((opt) => opt.value === option.value);
return ( return (
<Container> <StyledContainer>
<SelectLabel>{option.entry}</SelectLabel> <StyledSelectLabel>{option.entry}</StyledSelectLabel>
<MatchColumnSelect <MatchColumnSelect
value={value} value={value}
placeholder="Select..." placeholder="Select..."
@ -51,6 +51,6 @@ export const SubMatchingSelect = <T extends string>({
options={options} options={options}
name={option.entry} name={option.entry}
/> />
</Container> </StyledContainer>
); );
}; };

View File

@ -18,14 +18,14 @@ import { ColumnType } from '../MatchColumnsStep';
import { SubMatchingSelect } from './SubMatchingSelect'; import { SubMatchingSelect } from './SubMatchingSelect';
const Container = styled.div` const StyledContainer = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-height: 10px; min-height: 10px;
width: 100%; width: 100%;
`; `;
const AccordionButton = styled(ChakraAccordionButton)` const StyledAccordionButton = styled(ChakraAccordionButton)`
align-items: center; align-items: center;
background-color: ${({ theme }) => theme.accent.secondary}; background-color: ${({ theme }) => theme.accent.secondary};
border: none; border: none;
@ -46,12 +46,12 @@ const AccordionButton = styled(ChakraAccordionButton)`
} }
`; `;
const AccordionContainer = styled.div` const StyledAccordionContainer = styled.div`
display: flex; display: flex;
width: 100%; width: 100%;
`; `;
const AccordionLabel = styled.span` const StyledAccordionLabel = styled.span`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
display: flex; display: flex;
flex: 1; flex: 1;
@ -123,7 +123,7 @@ export const TemplateColumn = <T extends string>({
); );
return ( return (
<Container> <StyledContainer>
<MatchColumnSelect <MatchColumnSelect
placeholder="Select column..." placeholder="Select column..."
value={isIgnored ? ignoreValue : selectValue} value={isIgnored ? ignoreValue : selectValue}
@ -132,15 +132,15 @@ export const TemplateColumn = <T extends string>({
name={column.header} name={column.header}
/> />
{isSelect && ( {isSelect && (
<AccordionContainer> <StyledAccordionContainer>
<Accordion allowMultiple width="100%"> <Accordion allowMultiple width="100%">
<AccordionItem border="none" py={1}> <AccordionItem border="none" py={1}>
<AccordionButton data-testid="accordion-button"> <StyledAccordionButton data-testid="accordion-button">
<AccordionLabel> <StyledAccordionLabel>
{getAccordionTitle<T>(fields, column)} {getAccordionTitle<T>(fields, column)}
</AccordionLabel> </StyledAccordionLabel>
<AccordionIcon as={IconChevronDown} /> <AccordionIcon as={IconChevronDown} />
</AccordionButton> </StyledAccordionButton>
<AccordionPanel pb={4} pr={3} display="flex" flexDir="column"> <AccordionPanel pb={4} pr={3} display="flex" flexDir="column">
{column.matchedOptions.map((option) => ( {column.matchedOptions.map((option) => (
<SubMatchingSelect <SubMatchingSelect
@ -153,8 +153,8 @@ export const TemplateColumn = <T extends string>({
</AccordionPanel> </AccordionPanel>
</AccordionItem> </AccordionItem>
</Accordion> </Accordion>
</AccordionContainer> </StyledAccordionContainer>
)} )}
</Container> </StyledContainer>
); );
}; };

View File

@ -5,13 +5,13 @@ import { assertNotNull } from '~/utils/assert';
import type { Column } from '../MatchColumnsStep'; import type { Column } from '../MatchColumnsStep';
const Container = styled.div` const StyledContainer = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
`; `;
const Value = styled.span` const StyledValue = styled.span`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.sm}; font-size: ${({ theme }) => theme.font.size.sm};
font-weight: ${({ theme }) => theme.font.weight.medium}; font-weight: ${({ theme }) => theme.font.weight.medium};
@ -20,7 +20,7 @@ const Value = styled.span`
white-space: nowrap; white-space: nowrap;
`; `;
const Example = styled.span` const StyledExample = styled.span`
color: ${({ theme }) => theme.font.color.tertiary}; color: ${({ theme }) => theme.font.color.tertiary};
font-size: ${({ theme }) => theme.font.size.sm}; font-size: ${({ theme }) => theme.font.size.sm};
font-weight: ${({ theme }) => theme.font.weight.medium}; font-weight: ${({ theme }) => theme.font.weight.medium};
@ -42,9 +42,9 @@ export const UserTableColumn = <T extends string>({
const entry = entries.find(assertNotNull); const entry = entries.find(assertNotNull);
return ( return (
<Container> <StyledContainer>
<Value>{header}</Value> <StyledValue>{header}</StyledValue>
{entry && <Example>{`ex: ${entry}`}</Example>} {entry && <StyledExample>{`ex: ${entry}`}</StyledExample>}
</Container> </StyledContainer>
); );
}; };

View File

@ -12,7 +12,7 @@ const StyledHeading = styled(Heading)`
margin-bottom: ${({ theme }) => theme.spacing(8)}; margin-bottom: ${({ theme }) => theme.spacing(8)};
`; `;
const TableContainer = styled.div` const StyledTableContainer = styled.div`
display: flex; display: flex;
flex-grow: 1; flex-grow: 1;
height: 0px; height: 0px;
@ -42,13 +42,13 @@ export const SelectHeaderStep = ({ data, onContinue }: SelectHeaderProps) => {
<> <>
<Modal.Content> <Modal.Content>
<StyledHeading title="Select header row" /> <StyledHeading title="Select header row" />
<TableContainer> <StyledTableContainer>
<SelectHeaderTable <SelectHeaderTable
data={data} data={data}
selectedRows={selectedRows} selectedRows={selectedRows}
setSelectedRows={setSelectedRows} setSelectedRows={setSelectedRows}
/> />
</TableContainer> </StyledTableContainer>
</Modal.Content> </Modal.Content>
<ContinueButton <ContinueButton
onContinue={handleContinue} onContinue={handleContinue}

View File

@ -7,7 +7,7 @@ import { Radio } from '@/ui/input/radio/components/Radio';
import { RadioGroup } from '@/ui/input/radio/components/RadioGroup'; import { RadioGroup } from '@/ui/input/radio/components/RadioGroup';
import { Modal } from '@/ui/modal/components/Modal'; import { Modal } from '@/ui/modal/components/Modal';
const Content = styled(Modal.Content)` const StyledContent = styled(Modal.Content)`
align-items: center; align-items: center;
`; `;
@ -15,7 +15,7 @@ const StyledHeading = styled(Heading)`
margin-bottom: ${({ theme }) => theme.spacing(8)}; margin-bottom: ${({ theme }) => theme.spacing(8)};
`; `;
const RadioContainer = styled.div` const StyledRadioContainer = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-grow: 1; flex-grow: 1;
@ -46,16 +46,16 @@ export const SelectSheetStep = ({
return ( return (
<> <>
<Content> <StyledContent>
<StyledHeading title="Select the sheet to use" /> <StyledHeading title="Select the sheet to use" />
<RadioContainer> <StyledRadioContainer>
<RadioGroup onValueChange={(value) => setValue(value)} value={value}> <RadioGroup onValueChange={(value) => setValue(value)} value={value}>
{sheetNames.map((sheetName) => ( {sheetNames.map((sheetName) => (
<Radio value={sheetName} key={sheetName} /> <Radio value={sheetName} key={sheetName} />
))} ))}
</RadioGroup> </RadioGroup>
</RadioContainer> </StyledRadioContainer>
</Content> </StyledContent>
<ContinueButton <ContinueButton
isLoading={isLoading} isLoading={isLoading}
onContinue={() => handleOnContinue(value)} onContinue={() => handleOnContinue(value)}

View File

@ -8,7 +8,7 @@ import { useStepBar } from '@/ui/step-bar/hooks/useStepBar';
import { UploadFlow } from './UploadFlow'; import { UploadFlow } from './UploadFlow';
const Header = styled(Modal.Header)` const StyledHeader = styled(Modal.Header)`
background-color: ${({ theme }) => theme.background.secondary}; background-color: ${({ theme }) => theme.background.secondary};
border-bottom: 1px solid ${({ theme }) => theme.border.color.medium}; border-bottom: 1px solid ${({ theme }) => theme.border.color.medium};
height: 60px; height: 60px;
@ -36,13 +36,13 @@ export const Steps = () => {
return ( return (
<> <>
<Header> <StyledHeader>
<StepBar activeStep={activeStep}> <StepBar activeStep={activeStep}>
{steps.map((key) => ( {steps.map((key) => (
<StepBar.Step label={stepTitles[key]} key={key} /> <StepBar.Step label={stepTitles[key]} key={key} />
))} ))}
</StepBar> </StepBar>
</Header> </StyledHeader>
<UploadFlow nextStep={nextStep} /> <UploadFlow nextStep={nextStep} />
</> </>
); );

View File

@ -17,7 +17,7 @@ import { SelectSheetStep } from './SelectSheetStep/SelectSheetStep';
import { UploadStep } from './UploadStep/UploadStep'; import { UploadStep } from './UploadStep/UploadStep';
import { ValidationStep } from './ValidationStep/ValidationStep'; import { ValidationStep } from './ValidationStep/ValidationStep';
const ProgressBarContainer = styled(Modal.Content)` const StyledProgressBarContainer = styled(Modal.Content)`
align-items: center; align-items: center;
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -209,13 +209,13 @@ export const UploadFlow = ({ nextStep }: Props) => {
case StepType.loading: case StepType.loading:
default: default:
return ( return (
<ProgressBarContainer> <StyledProgressBarContainer>
<CircularProgressBar <CircularProgressBar
size={80} size={80}
barWidth={8} barWidth={8}
barColor={theme.font.color.primary} barColor={theme.font.color.primary}
/> />
</ProgressBarContainer> </StyledProgressBarContainer>
); );
} }
}; };

View File

@ -6,7 +6,7 @@ import { Modal } from '@/ui/modal/components/Modal';
import { DropZone } from './components/DropZone'; import { DropZone } from './components/DropZone';
const Content = styled(Modal.Content)` const StyledContent = styled(Modal.Content)`
padding: ${({ theme }) => theme.spacing(6)}; padding: ${({ theme }) => theme.spacing(6)};
`; `;
@ -27,8 +27,8 @@ export const UploadStep = ({ onContinue }: UploadProps) => {
); );
return ( return (
<Content> <StyledContent>
<DropZone onContinue={handleOnContinue} isLoading={isLoading} /> <DropZone onContinue={handleOnContinue} isLoading={isLoading} />
</Content> </StyledContent>
); );
}; };

View File

@ -8,7 +8,7 @@ import { readFileAsync } from '@/spreadsheet-import/utils/readFilesAsync';
import { MainButton } from '@/ui/button/components/MainButton'; import { MainButton } from '@/ui/button/components/MainButton';
import { useSnackBar } from '@/ui/snack-bar/hooks/useSnackBar'; import { useSnackBar } from '@/ui/snack-bar/hooks/useSnackBar';
const Container = styled.div` const StyledContainer = styled.div`
align-items: center; align-items: center;
background: ${({ theme }) => ` background: ${({ theme }) => `
repeating-linear-gradient( repeating-linear-gradient(
@ -55,7 +55,7 @@ const Container = styled.div`
position: relative; position: relative;
`; `;
const Overlay = styled.div` const StyledOverlay = styled.div`
background: ${({ theme }) => theme.background.transparent.medium}; background: ${({ theme }) => theme.background.transparent.medium};
border-radius: ${({ theme }) => theme.border.radius.sm}; border-radius: ${({ theme }) => theme.border.radius.sm};
bottom: 0px; bottom: 0px;
@ -65,14 +65,14 @@ const Overlay = styled.div`
top: 0px; top: 0px;
`; `;
const Text = styled.span` const StyledText = styled.span`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.sm}; font-size: ${({ theme }) => theme.font.size.sm};
font-weight: ${({ theme }) => theme.font.weight.medium}; font-weight: ${({ theme }) => theme.font.weight.medium};
text-align: center; text-align: center;
`; `;
const Button = styled(MainButton)` const StyledButton = styled(MainButton)`
margin-top: ${({ theme }) => theme.spacing(2)}; margin-top: ${({ theme }) => theme.spacing(2)};
width: 200px; width: 200px;
`; `;
@ -125,19 +125,19 @@ export const DropZone = ({ onContinue, isLoading }: DropZoneProps) => {
}); });
return ( return (
<Container {...getRootProps()}> <StyledContainer {...getRootProps()}>
{isDragActive && <Overlay />} {isDragActive && <StyledOverlay />}
<input {...getInputProps()} /> <input {...getInputProps()} />
{isDragActive ? ( {isDragActive ? (
<Text>Drop file here...</Text> <StyledText>Drop file here...</StyledText>
) : loading || isLoading ? ( ) : loading || isLoading ? (
<Text>Processing...</Text> <StyledText>Processing...</StyledText>
) : ( ) : (
<> <>
<Text>Upload .xlsx, .xls or .csv file</Text> <StyledText>Upload .xlsx, .xls or .csv file</StyledText>
<Button onClick={open} title="Select file" /> <StyledButton onClick={open} title="Select file" />
</> </>
)} )}
</Container> </StyledContainer>
); );
}; };

View File

@ -5,21 +5,21 @@ import styled from '@emotion/styled';
import type { Fields } from '@/spreadsheet-import/types'; import type { Fields } from '@/spreadsheet-import/types';
import { AppTooltip } from '@/ui/tooltip/AppTooltip'; import { AppTooltip } from '@/ui/tooltip/AppTooltip';
const HeaderContainer = styled.div` const StyledHeaderContainer = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
gap: ${({ theme }) => theme.spacing(1)}; gap: ${({ theme }) => theme.spacing(1)};
position: relative; position: relative;
`; `;
const HeaderLabel = styled.span` const StyledHeaderLabel = styled.span`
display: flex; display: flex;
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
`; `;
const DefaultContainer = styled.div` const StyledDefaultContainer = styled.div`
min-height: 100%; min-height: 100%;
min-width: 100%; min-width: 100%;
overflow: hidden; overflow: hidden;
@ -33,8 +33,10 @@ export const generateColumns = <T extends string>(fields: Fields<T>) =>
name: column.label, name: column.label,
minWidth: 150, minWidth: 150,
headerRenderer: () => ( headerRenderer: () => (
<HeaderContainer> <StyledHeaderContainer>
<HeaderLabel id={`${column.key}`}>{column.label}</HeaderLabel> <StyledHeaderLabel id={`${column.key}`}>
{column.label}
</StyledHeaderLabel>
{column.description && {column.description &&
createPortal( createPortal(
<AppTooltip <AppTooltip
@ -44,10 +46,10 @@ export const generateColumns = <T extends string>(fields: Fields<T>) =>
/>, />,
document.body, document.body,
)} )}
</HeaderContainer> </StyledHeaderContainer>
), ),
formatter: ({ row }) => ( formatter: ({ row }) => (
<DefaultContainer>{row[column.key]}</DefaultContainer> <StyledDefaultContainer>{row[column.key]}</StyledDefaultContainer>
), ),
}), }),
); );

View File

@ -17,7 +17,7 @@ import { Modal } from '@/ui/modal/components/Modal';
import { generateColumns } from './components/columns'; import { generateColumns } from './components/columns';
import type { Meta } from './types'; import type { Meta } from './types';
const Toolbar = styled.div` const StyledToolbar = styled.div`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
@ -25,20 +25,20 @@ const Toolbar = styled.div`
margin-top: ${({ theme }) => theme.spacing(8)}; margin-top: ${({ theme }) => theme.spacing(8)};
`; `;
const ErrorToggle = styled.div` const StyledErrorToggle = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
`; `;
const ErrorToggleDescription = styled.span` const StyledErrorToggleDescription = styled.span`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.sm}; font-size: ${({ theme }) => theme.font.size.sm};
font-weight: ${({ theme }) => theme.font.weight.regular}; font-weight: ${({ theme }) => theme.font.weight.regular};
margin-left: ${({ theme }) => theme.spacing(2)}; margin-left: ${({ theme }) => theme.spacing(2)};
`; `;
const ScrollContainer = styled.div` const StyledScrollContainer = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex-grow: 1; flex-grow: 1;
@ -46,7 +46,7 @@ const ScrollContainer = styled.div`
width: 100%; width: 100%;
`; `;
const NoRowsContainer = styled.div` const StyledNoRowsContainer = styled.div`
display: flex; display: flex;
grid-column: 1/-1; grid-column: 1/-1;
justify-content: center; justify-content: center;
@ -188,16 +188,16 @@ export const ValidationStep = <T extends string>({
title="Review your import" title="Review your import"
description="Correct the issues and fill the missing data." description="Correct the issues and fill the missing data."
/> />
<Toolbar> <StyledToolbar>
<ErrorToggle> <StyledErrorToggle>
<Toggle <Toggle
value={filterByErrors} value={filterByErrors}
onChange={() => setFilterByErrors(!filterByErrors)} onChange={() => setFilterByErrors(!filterByErrors)}
/> />
<ErrorToggleDescription> <StyledErrorToggleDescription>
Show only rows with errors Show only rows with errors
</ErrorToggleDescription> </StyledErrorToggleDescription>
</ErrorToggle> </StyledErrorToggle>
<Button <Button
icon={<IconTrash />} icon={<IconTrash />}
title="Remove" title="Remove"
@ -205,8 +205,8 @@ export const ValidationStep = <T extends string>({
onClick={deleteSelectedRows} onClick={deleteSelectedRows}
disabled={selectedRows.size === 0} disabled={selectedRows.size === 0}
/> />
</Toolbar> </StyledToolbar>
<ScrollContainer> <StyledScrollContainer>
<Table <Table
rowKeyGetter={rowKeyGetter} rowKeyGetter={rowKeyGetter}
rows={tableData} rows={tableData}
@ -216,15 +216,15 @@ export const ValidationStep = <T extends string>({
onSelectedRowsChange={setSelectedRows} onSelectedRowsChange={setSelectedRows}
components={{ components={{
noRowsFallback: ( noRowsFallback: (
<NoRowsContainer> <StyledNoRowsContainer>
{filterByErrors {filterByErrors
? 'No data containing errors' ? 'No data containing errors'
: 'No data found'} : 'No data found'}
</NoRowsContainer> </StyledNoRowsContainer>
), ),
}} }}
/> />
</ScrollContainer> </StyledScrollContainer>
</Modal.Content> </Modal.Content>
<ContinueButton onContinue={onContinue} title="Confirm" /> <ContinueButton onContinue={onContinue} title="Confirm" />
</> </>

View File

@ -14,21 +14,21 @@ import { AppTooltip } from '@/ui/tooltip/AppTooltip';
import type { Meta } from '../types'; import type { Meta } from '../types';
const HeaderContainer = styled.div` const StyledHeaderContainer = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
gap: ${({ theme }) => theme.spacing(1)}; gap: ${({ theme }) => theme.spacing(1)};
position: relative; position: relative;
`; `;
const HeaderLabel = styled.span` const StyledHeaderLabel = styled.span`
display: flex; display: flex;
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
`; `;
const CheckboxContainer = styled.div` const StyledCheckboxContainer = styled.div`
align-items: center; align-items: center;
box-sizing: content-box; box-sizing: content-box;
display: flex; display: flex;
@ -39,13 +39,13 @@ const CheckboxContainer = styled.div`
width: 100%; width: 100%;
`; `;
const ToggleContainer = styled.div` const StyledToggleContainer = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
height: 100%; height: 100%;
`; `;
const InputContainer = styled.div` const StyledInputContainer = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
min-height: 100%; min-height: 100%;
@ -53,7 +53,7 @@ const InputContainer = styled.div`
padding-right: ${({ theme }) => theme.spacing(2)}; padding-right: ${({ theme }) => theme.spacing(2)};
`; `;
const DefaultContainer = styled.div` const StyledDefaultContainer = styled.div`
min-height: 100%; min-height: 100%;
min-width: 100%; min-width: 100%;
overflow: hidden; overflow: hidden;
@ -79,7 +79,7 @@ export const generateColumns = <T extends string>(
const [isRowSelected, onRowSelectionChange] = useRowSelection(); const [isRowSelected, onRowSelectionChange] = useRowSelection();
return ( return (
<CheckboxContainer> <StyledCheckboxContainer>
<Checkbox <Checkbox
aria-label="Select" aria-label="Select"
checked={isRowSelected} checked={isRowSelected}
@ -92,7 +92,7 @@ export const generateColumns = <T extends string>(
}); });
}} }}
/> />
</CheckboxContainer> </StyledCheckboxContainer>
); );
}, },
}, },
@ -103,8 +103,10 @@ export const generateColumns = <T extends string>(
minWidth: 150, minWidth: 150,
resizable: true, resizable: true,
headerRenderer: () => ( headerRenderer: () => (
<HeaderContainer> <StyledHeaderContainer>
<HeaderLabel id={`${column.key}`}>{column.label}</HeaderLabel> <StyledHeaderLabel id={`${column.key}`}>
{column.label}
</StyledHeaderLabel>
{column.description && {column.description &&
createPortal( createPortal(
<AppTooltip <AppTooltip
@ -114,7 +116,7 @@ export const generateColumns = <T extends string>(
/>, />,
document.body, document.body,
)} )}
</HeaderContainer> </StyledHeaderContainer>
), ),
editable: column.fieldType.type !== 'checkbox', editable: column.fieldType.type !== 'checkbox',
editor: ({ row, onRowChange, onClose }) => { editor: ({ row, onRowChange, onClose }) => {
@ -158,7 +160,7 @@ export const generateColumns = <T extends string>(
); );
} }
return <InputContainer>{component}</InputContainer>; return <StyledInputContainer>{component}</StyledInputContainer>;
}, },
editorOptions: { editorOptions: {
editOnClick: true, editOnClick: true,
@ -170,7 +172,7 @@ export const generateColumns = <T extends string>(
switch (column.fieldType.type) { switch (column.fieldType.type) {
case 'checkbox': case 'checkbox':
component = ( component = (
<ToggleContainer <StyledToggleContainer
id={`${columnKey}-${row.__index}`} id={`${columnKey}-${row.__index}`}
onClick={(event) => { onClick={(event) => {
event.stopPropagation(); event.stopPropagation();
@ -185,23 +187,23 @@ export const generateColumns = <T extends string>(
}); });
}} }}
/> />
</ToggleContainer> </StyledToggleContainer>
); );
break; break;
case 'select': case 'select':
component = ( component = (
<DefaultContainer id={`${columnKey}-${row.__index}`}> <StyledDefaultContainer id={`${columnKey}-${row.__index}`}>
{column.fieldType.options.find( {column.fieldType.options.find(
(option) => option.value === row[columnKey as T], (option) => option.value === row[columnKey as T],
)?.label || null} )?.label || null}
</DefaultContainer> </StyledDefaultContainer>
); );
break; break;
default: default:
component = ( component = (
<DefaultContainer id={`${columnKey}-${row.__index}`}> <StyledDefaultContainer id={`${columnKey}-${row.__index}`}>
{row[columnKey]} {row[columnKey]}
</DefaultContainer> </StyledDefaultContainer>
); );
} }

View File

@ -65,11 +65,11 @@ const StyledDropdownItem = styled.button<ButtonProps>`
} }
`; `;
const DropdownContainer = styled.div` const StyledDropdownContainer = styled.div`
position: relative; position: relative;
`; `;
const DropdownMenu = styled.div` const StyledDropdownMenu = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: absolute; position: absolute;
@ -112,7 +112,7 @@ export function DropdownButton({
return ( return (
<> <>
{selectedOption && ( {selectedOption && (
<DropdownContainer> <StyledDropdownContainer>
<StyledButton <StyledButton
onClick={() => setIsOpen(!isOpen)} onClick={() => setIsOpen(!isOpen)}
{...buttonProps} {...buttonProps}
@ -123,7 +123,7 @@ export function DropdownButton({
{options.length > 1 && <IconChevronDown />} {options.length > 1 && <IconChevronDown />}
</StyledButton> </StyledButton>
{isOpen && ( {isOpen && (
<DropdownMenu> <StyledDropdownMenu>
{options {options
.filter((option) => option.label !== selectedOption.label) .filter((option) => option.label !== selectedOption.label)
.map((option, index) => ( .map((option, index) => (
@ -135,9 +135,9 @@ export function DropdownButton({
{option.label} {option.label}
</StyledDropdownItem> </StyledDropdownItem>
))} ))}
</DropdownMenu> </StyledDropdownMenu>
)} )}
</DropdownContainer> </StyledDropdownContainer>
)} )}
</> </>
); );

View File

@ -13,12 +13,12 @@ const StyledContainer = styled.div`
} }
`; `;
const CardContainer = styled.div` const StyledCardContainer = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
`; `;
const Label = styled.span` const StyledLabel = styled.span`
color: ${({ theme }) => theme.font.color.secondary}; color: ${({ theme }) => theme.font.color.secondary};
font-size: ${({ theme }) => theme.font.size.xs}; font-size: ${({ theme }) => theme.font.size.xs};
font-weight: ${({ theme }) => theme.font.weight.medium}; font-weight: ${({ theme }) => theme.font.weight.medium};
@ -33,30 +33,30 @@ export type ColorSchemePickerProps = {
export function ColorSchemePicker({ value, onChange }: ColorSchemePickerProps) { export function ColorSchemePicker({ value, onChange }: ColorSchemePickerProps) {
return ( return (
<StyledContainer> <StyledContainer>
<CardContainer> <StyledCardContainer>
<ColorSchemeCard <ColorSchemeCard
onClick={() => onChange(ColorScheme.Light)} onClick={() => onChange(ColorScheme.Light)}
variant="light" variant="light"
selected={value === ColorScheme.Light} selected={value === ColorScheme.Light}
/> />
<Label>Light</Label> <StyledLabel>Light</StyledLabel>
</CardContainer> </StyledCardContainer>
<CardContainer> <StyledCardContainer>
<ColorSchemeCard <ColorSchemeCard
onClick={() => onChange(ColorScheme.Dark)} onClick={() => onChange(ColorScheme.Dark)}
variant="dark" variant="dark"
selected={value === ColorScheme.Dark} selected={value === ColorScheme.Dark}
/> />
<Label>Dark</Label> <StyledLabel>Dark</StyledLabel>
</CardContainer> </StyledCardContainer>
<CardContainer> <StyledCardContainer>
<ColorSchemeCard <ColorSchemeCard
onClick={() => onChange(ColorScheme.System)} onClick={() => onChange(ColorScheme.System)}
variant="system" variant="system"
selected={value === ColorScheme.System} selected={value === ColorScheme.System}
/> />
<Label>System settings</Label> <StyledLabel>System settings</StyledLabel>
</CardContainer> </StyledCardContainer>
</StyledContainer> </StyledContainer>
); );
} }

View File

@ -5,7 +5,7 @@ import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { ColorSchemeCard } from '../ColorSchemeCard'; import { ColorSchemeCard } from '../ColorSchemeCard';
const Container = styled.div` const StyledContainer = styled.div`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
> * + * { > * + * {
@ -18,9 +18,9 @@ const meta: Meta<typeof ColorSchemeCard> = {
component: ColorSchemeCard, component: ColorSchemeCard,
decorators: [ decorators: [
(Story) => ( (Story) => (
<Container> <StyledContainer>
<Story /> <Story />
</Container> </StyledContainer>
), ),
ComponentDecorator, ComponentDecorator,
], ],

View File

@ -4,7 +4,7 @@ import { motion } from 'framer-motion';
import { Button, ButtonVariant } from '@/ui/button/components/Button'; import { Button, ButtonVariant } from '@/ui/button/components/Button';
const DialogOverlay = styled(motion.div)` const StyledDialogOverlay = styled(motion.div)`
align-items: center; align-items: center;
background: ${({ theme }) => theme.background.overlay}; background: ${({ theme }) => theme.background.overlay};
display: flex; display: flex;
@ -17,7 +17,7 @@ const DialogOverlay = styled(motion.div)`
z-index: 9999; z-index: 9999;
`; `;
const DialogContainer = styled(motion.div)` const StyledDialogContainer = styled(motion.div)`
background: ${({ theme }) => theme.background.primary}; background: ${({ theme }) => theme.background.primary};
border-radius: 8px; border-radius: 8px;
display: flex; display: flex;
@ -28,7 +28,7 @@ const DialogContainer = styled(motion.div)`
width: 100%; width: 100%;
`; `;
const DialogTitle = styled.span` const StyledDialogTitle = styled.span`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.md}; font-size: ${({ theme }) => theme.font.size.md};
font-weight: ${({ theme }) => theme.font.weight.semiBold}; font-weight: ${({ theme }) => theme.font.weight.semiBold};
@ -36,7 +36,7 @@ const DialogTitle = styled.span`
text-align: center; text-align: center;
`; `;
const DialogMessage = styled.span` const StyledDialogMessage = styled.span`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.sm}; font-size: ${({ theme }) => theme.font.size.sm};
font-weight: ${({ theme }) => theme.font.weight.regular}; font-weight: ${({ theme }) => theme.font.weight.regular};
@ -44,7 +44,7 @@ const DialogMessage = styled.span`
text-align: center; text-align: center;
`; `;
const DialogButton = styled(Button)` const StyledDialogButton = styled(Button)`
justify-content: center; justify-content: center;
margin-bottom: ${({ theme }) => theme.spacing(2)}; margin-bottom: ${({ theme }) => theme.spacing(2)};
`; `;
@ -87,7 +87,7 @@ export function Dialog({
}; };
return ( return (
<DialogOverlay <StyledDialogOverlay
variants={dialogVariants} variants={dialogVariants}
initial="closed" initial="closed"
animate="open" animate="open"
@ -99,16 +99,16 @@ export function Dialog({
} }
}} }}
> >
<DialogContainer <StyledDialogContainer
variants={containerVariants} variants={containerVariants}
transition={{ damping: 15, stiffness: 100 }} transition={{ damping: 15, stiffness: 100 }}
{...rootProps} {...rootProps}
> >
{title && <DialogTitle>{title}</DialogTitle>} {title && <StyledDialogTitle>{title}</StyledDialogTitle>}
{message && <DialogMessage>{message}</DialogMessage>} {message && <StyledDialogMessage>{message}</StyledDialogMessage>}
{children} {children}
{buttons.map((button) => ( {buttons.map((button) => (
<DialogButton <StyledDialogButton
key={button.title} key={button.title}
onClick={(e) => { onClick={(e) => {
button?.onClick?.(e); button?.onClick?.(e);
@ -119,7 +119,7 @@ export function Dialog({
{...button} {...button}
/> />
))} ))}
</DialogContainer> </StyledDialogContainer>
</DialogOverlay> </StyledDialogOverlay>
); );
} }

View File

@ -1,3 +1,4 @@
/* eslint-disable twenty/styled-components-prefixed-with-styled */
import styled from '@emotion/styled'; import styled from '@emotion/styled';
export const DropdownMenu = styled.div<{ export const DropdownMenu = styled.div<{

View File

@ -11,7 +11,7 @@ type Props = {
id?: string; id?: string;
}; };
const DropdownMenuCheckableItemContainer = styled(DropdownMenuItem)` const StyledDropdownMenuCheckableItemContainer = styled(DropdownMenuItem)`
align-items: center; align-items: center;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -42,11 +42,11 @@ export function DropdownMenuCheckableItem({
} }
return ( return (
<DropdownMenuCheckableItemContainer onClick={handleClick}> <StyledDropdownMenuCheckableItemContainer onClick={handleClick}>
<StyledLeftContainer> <StyledLeftContainer>
<Checkbox checked={checked} /> <Checkbox checked={checked} />
<StyledChildrenContainer>{children}</StyledChildrenContainer> <StyledChildrenContainer>{children}</StyledChildrenContainer>
</StyledLeftContainer> </StyledLeftContainer>
</DropdownMenuCheckableItemContainer> </StyledDropdownMenuCheckableItemContainer>
); );
} }

View File

@ -3,7 +3,7 @@ import styled from '@emotion/styled';
import { textInputStyle } from '@/ui/theme/constants/effects'; import { textInputStyle } from '@/ui/theme/constants/effects';
export const DropdownMenuInputContainer = styled.div` const StyledDropdownMenuInputContainer = styled.div`
--vertical-padding: ${({ theme }) => theme.spacing(1)}; --vertical-padding: ${({ theme }) => theme.spacing(1)};
align-items: center; align-items: center;
@ -28,7 +28,7 @@ export const DropdownMenuInput = forwardRef<
HTMLInputElement, HTMLInputElement,
InputHTMLAttributes<HTMLInputElement> InputHTMLAttributes<HTMLInputElement>
>((props, ref) => ( >((props, ref) => (
<DropdownMenuInputContainer> <StyledDropdownMenuInputContainer>
<StyledInput autoComplete="off" placeholder="Search" {...props} ref={ref} /> <StyledInput autoComplete="off" placeholder="Search" {...props} ref={ref} />
</DropdownMenuInputContainer> </StyledDropdownMenuInputContainer>
)); ));

View File

@ -1,3 +1,4 @@
/* eslint-disable twenty/styled-components-prefixed-with-styled */
import styled from '@emotion/styled'; import styled from '@emotion/styled';
export const DropdownMenuItemsContainer = styled.div<{ export const DropdownMenuItemsContainer = styled.div<{

View File

@ -13,7 +13,7 @@ type Props = React.ComponentProps<'li'> & {
disabled?: boolean; disabled?: boolean;
}; };
const DropdownMenuSelectableItemContainer = styled(DropdownMenuItem)< const StyledDropdownMenuSelectableItemContainer = styled(DropdownMenuItem)<
Pick<Props, 'hovered'> Pick<Props, 'hovered'>
>` >`
${hoverBackground}; ${hoverBackground};
@ -72,7 +72,7 @@ export function DropdownMenuSelectableItem({
}, [hovered]); }, [hovered]);
return ( return (
<DropdownMenuSelectableItemContainer <StyledDropdownMenuSelectableItemContainer
{...restProps} {...restProps}
onClick={handleClick} onClick={handleClick}
hovered={hovered} hovered={hovered}
@ -82,6 +82,6 @@ export function DropdownMenuSelectableItem({
<StyledRightIcon> <StyledRightIcon>
{selected && <IconCheck size={theme.icon.size.md} />} {selected && <IconCheck size={theme.icon.size.md} />}
</StyledRightIcon> </StyledRightIcon>
</DropdownMenuSelectableItemContainer> </StyledDropdownMenuSelectableItemContainer>
); );
} }

View File

@ -1,3 +1,4 @@
/* eslint-disable twenty/styled-components-prefixed-with-styled */
import styled from '@emotion/styled'; import styled from '@emotion/styled';
export const DropdownMenuSeparator = styled.div` export const DropdownMenuSeparator = styled.div`

View File

@ -1,3 +1,4 @@
/* eslint-disable twenty/styled-components-prefixed-with-styled */
import styled from '@emotion/styled'; import styled from '@emotion/styled';
export const DropdownMenuSubheader = styled.div` export const DropdownMenuSubheader = styled.div`

View File

@ -43,19 +43,19 @@ const FakeContentBelow = () => (
const avatarUrl = const avatarUrl =
'https://s3-alpha-sig.figma.com/img/bbb5/4905/f0a52cc2b9aaeb0a82a360d478dae8bf?Expires=1687132800&Signature=iVBr0BADa3LHoFVGbwqO-wxC51n1o~ZyFD-w7nyTyFP4yB-Y6zFawL-igewaFf6PrlumCyMJThDLAAc-s-Cu35SBL8BjzLQ6HymzCXbrblUADMB208PnMAvc1EEUDq8TyryFjRO~GggLBk5yR0EXzZ3zenqnDEGEoQZR~TRqS~uDF-GwQB3eX~VdnuiU2iittWJkajIDmZtpN3yWtl4H630A3opQvBnVHZjXAL5YPkdh87-a-H~6FusWvvfJxfNC2ZzbrARzXofo8dUFtH7zUXGCC~eUk~hIuLbLuz024lFQOjiWq2VKyB7dQQuGFpM-OZQEV8tSfkViP8uzDLTaCg__&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4'; 'https://s3-alpha-sig.figma.com/img/bbb5/4905/f0a52cc2b9aaeb0a82a360d478dae8bf?Expires=1687132800&Signature=iVBr0BADa3LHoFVGbwqO-wxC51n1o~ZyFD-w7nyTyFP4yB-Y6zFawL-igewaFf6PrlumCyMJThDLAAc-s-Cu35SBL8BjzLQ6HymzCXbrblUADMB208PnMAvc1EEUDq8TyryFjRO~GggLBk5yR0EXzZ3zenqnDEGEoQZR~TRqS~uDF-GwQB3eX~VdnuiU2iittWJkajIDmZtpN3yWtl4H630A3opQvBnVHZjXAL5YPkdh87-a-H~6FusWvvfJxfNC2ZzbrARzXofo8dUFtH7zUXGCC~eUk~hIuLbLuz024lFQOjiWq2VKyB7dQQuGFpM-OZQEV8tSfkViP8uzDLTaCg__&Key-Pair-Id=APKAQ4GOSFWCVNEHN3O4';
const FakeMenuContent = styled.div` const StyledFakeMenuContent = styled.div`
height: 400px; height: 400px;
width: 100%; width: 100%;
`; `;
const FakeBelowContainer = styled.div` const StyledFakeBelowContainer = styled.div`
height: 600px; height: 600px;
position: relative; position: relative;
width: 300px; width: 300px;
`; `;
const MenuAbsolutePositionWrapper = styled.div` const StyledMenuAbsolutePositionWrapper = styled.div`
height: fit-content; height: fit-content;
position: absolute; position: absolute;
@ -157,7 +157,7 @@ const FakeCheckableMenuItemList = ({ hasAvatar }: { hasAvatar?: boolean }) => {
export const Empty: Story = { export const Empty: Story = {
render: (args) => ( render: (args) => (
<DropdownMenu {...args}> <DropdownMenu {...args}>
<FakeMenuContent /> <StyledFakeMenuContent />
</DropdownMenu> </DropdownMenu>
), ),
}; };
@ -166,12 +166,12 @@ export const WithContentBelow: Story = {
...Empty, ...Empty,
decorators: [ decorators: [
(Story) => ( (Story) => (
<FakeBelowContainer> <StyledFakeBelowContainer>
<FakeContentBelow /> <FakeContentBelow />
<MenuAbsolutePositionWrapper> <StyledMenuAbsolutePositionWrapper>
<Story /> <Story />
</MenuAbsolutePositionWrapper> </StyledMenuAbsolutePositionWrapper>
</FakeBelowContainer> </StyledFakeBelowContainer>
), ),
], ],
}; };

View File

@ -50,7 +50,7 @@ const StyledEditButtonContainer = styled(motion.div)`
right: 0; right: 0;
`; `;
export const EditableFieldBaseContainer = styled.div` export const StyledEditableFieldBaseContainer = styled.div`
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
@ -114,7 +114,7 @@ export function EditableField({
const showEditButton = !isFieldInEditMode && isHovered && useEditButton; const showEditButton = !isFieldInEditMode && isHovered && useEditButton;
return ( return (
<EditableFieldBaseContainer <StyledEditableFieldBaseContainer
onMouseEnter={handleContainerMouseEnter} onMouseEnter={handleContainerMouseEnter}
onMouseLeave={handleContainerMouseLeave} onMouseLeave={handleContainerMouseLeave}
> >
@ -151,6 +151,6 @@ export function EditableField({
<EditableFieldEditButton /> <EditableFieldEditButton />
</StyledEditButtonContainer> </StyledEditButtonContainer>
)} )}
</EditableFieldBaseContainer> </StyledEditableFieldBaseContainer>
); );
} }

View File

@ -1,7 +1,7 @@
import { css } from '@emotion/react'; import { css } from '@emotion/react';
import styled from '@emotion/styled'; import styled from '@emotion/styled';
export const EditableFieldNormalModeOuterContainer = styled.div< const StyledEditableFieldNormalModeOuterContainer = styled.div<
Pick< Pick<
OwnProps, OwnProps,
| 'disableClick' | 'disableClick'
@ -51,7 +51,7 @@ export const EditableFieldNormalModeOuterContainer = styled.div<
}} }}
`; `;
export const EditableFieldNormalModeInnerContainer = styled.div` const StyledEditableFieldNormalModeInnerContainer = styled.div`
align-items: center; align-items: center;
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
font-size: 'inherit'; font-size: 'inherit';
@ -82,16 +82,16 @@ export function EditableFieldDisplayMode({
isDisplayModeFixHeight, isDisplayModeFixHeight,
}: React.PropsWithChildren<OwnProps>) { }: React.PropsWithChildren<OwnProps>) {
return ( return (
<EditableFieldNormalModeOuterContainer <StyledEditableFieldNormalModeOuterContainer
onClick={disableClick ? undefined : onClick} onClick={disableClick ? undefined : onClick}
disableClick={disableClick} disableClick={disableClick}
isDisplayModeContentEmpty={isDisplayModeContentEmpty} isDisplayModeContentEmpty={isDisplayModeContentEmpty}
disableHoverEffect={disableHoverEffect} disableHoverEffect={disableHoverEffect}
isDisplayModeFixHeight={isDisplayModeFixHeight} isDisplayModeFixHeight={isDisplayModeFixHeight}
> >
<EditableFieldNormalModeInnerContainer> <StyledEditableFieldNormalModeInnerContainer>
{children} {children}
</EditableFieldNormalModeInnerContainer> </StyledEditableFieldNormalModeInnerContainer>
</EditableFieldNormalModeOuterContainer> </StyledEditableFieldNormalModeOuterContainer>
); );
} }

View File

@ -3,7 +3,7 @@ import styled from '@emotion/styled';
import { useRegisterCloseFieldHandlers } from '../hooks/useRegisterCloseFieldHandlers'; import { useRegisterCloseFieldHandlers } from '../hooks/useRegisterCloseFieldHandlers';
export const EditableFieldEditModeContainer = styled.div<OwnProps>` const StyledEditableFieldEditModeContainer = styled.div<OwnProps>`
align-items: center; align-items: center;
display: flex; display: flex;
@ -33,11 +33,11 @@ export function EditableFieldEditMode({
useRegisterCloseFieldHandlers(wrapperRef, onSubmit, onCancel); useRegisterCloseFieldHandlers(wrapperRef, onSubmit, onCancel);
return ( return (
<EditableFieldEditModeContainer <StyledEditableFieldEditModeContainer
data-testid="editable-field-edit-mode-container" data-testid="editable-field-edit-mode-container"
ref={wrapperRef} ref={wrapperRef}
> >
{children} {children}
</EditableFieldEditModeContainer> </StyledEditableFieldEditModeContainer>
); );
} }

View File

@ -19,7 +19,7 @@ import {
FieldRelationValue, FieldRelationValue,
} from '../types/FieldMetadata'; } from '../types/FieldMetadata';
const RelationPickerContainer = styled.div` const StyledRelationPickerContainer = styled.div`
left: 0px; left: 0px;
position: absolute; position: absolute;
top: -8px; top: -8px;
@ -116,13 +116,13 @@ export function GenericEditableRelationFieldEditMode() {
} }
return ( return (
<RelationPickerContainer> <StyledRelationPickerContainer>
<RelationPicker <RelationPicker
fieldDefinition={currentEditableFieldDefinition} fieldDefinition={currentEditableFieldDefinition}
fieldValue={fieldValue} fieldValue={fieldValue}
handleEntitySubmit={handleSubmit} handleEntitySubmit={handleSubmit}
handleCancel={handleCancel} handleCancel={handleCancel}
/> />
</RelationPickerContainer> </StyledRelationPickerContainer>
); );
} }

View File

@ -5,12 +5,12 @@ import styled from '@emotion/styled';
import { Button, ButtonVariant } from '@/ui/button/components/Button'; import { Button, ButtonVariant } from '@/ui/button/components/Button';
import { IconFileUpload, IconTrash, IconUpload } from '@/ui/icon'; import { IconFileUpload, IconTrash, IconUpload } from '@/ui/icon';
const Container = styled.div` const StyledContainer = styled.div`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
`; `;
const Picture = styled.button<{ withPicture: boolean }>` const StyledPicture = styled.button<{ withPicture: boolean }>`
align-items: center; align-items: center;
background: ${({ theme, disabled }) => background: ${({ theme, disabled }) =>
disabled ? theme.background.secondary : theme.background.tertiary}; disabled ? theme.background.secondary : theme.background.tertiary};
@ -46,7 +46,7 @@ const Picture = styled.button<{ withPicture: boolean }>`
}}; }};
`; `;
const Content = styled.div` const StyledContent = styled.div`
display: flex; display: flex;
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
@ -54,7 +54,7 @@ const Content = styled.div`
margin-left: ${({ theme }) => theme.spacing(4)}; margin-left: ${({ theme }) => theme.spacing(4)};
`; `;
const ButtonContainer = styled.div` const StyledButtonContainer = styled.div`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
> * + * { > * + * {
@ -62,7 +62,7 @@ const ButtonContainer = styled.div`
} }
`; `;
const Text = styled.span` const StyledText = styled.span`
color: ${({ theme }) => theme.font.color.light}; color: ${({ theme }) => theme.font.color.light};
font-size: ${({ theme }) => theme.font.size.xs}; font-size: ${({ theme }) => theme.font.size.xs};
`; `;
@ -92,8 +92,8 @@ export function ImageInput({
}; };
return ( return (
<Container {...restProps}> <StyledContainer {...restProps}>
<Picture <StyledPicture
withPicture={!!picture} withPicture={!!picture}
disabled={disabled} disabled={disabled}
onClick={onUploadButtonClick} onClick={onUploadButtonClick}
@ -106,9 +106,9 @@ export function ImageInput({
) : ( ) : (
<IconFileUpload size={theme.icon.size.md} /> <IconFileUpload size={theme.icon.size.md} />
)} )}
</Picture> </StyledPicture>
<Content> <StyledContent>
<ButtonContainer> <StyledButtonContainer>
<StyledHiddenFileInput <StyledHiddenFileInput
type="file" type="file"
ref={hiddenFileInput} ref={hiddenFileInput}
@ -136,11 +136,11 @@ export function ImageInput({
disabled={!picture || disabled} disabled={!picture || disabled}
fullWidth fullWidth
/> />
</ButtonContainer> </StyledButtonContainer>
<Text> <StyledText>
We support your best PNGs, JPEGs and GIFs portraits under 10MB We support your best PNGs, JPEGs and GIFs portraits under 10MB
</Text> </StyledText>
</Content> </StyledContent>
</Container> </StyledContainer>
); );
} }

View File

@ -16,7 +16,7 @@ export enum LabelPosition {
Right = 'right', Right = 'right',
} }
const Container = styled.div<{ labelPosition?: LabelPosition }>` const StyledContainer = styled.div<{ labelPosition?: LabelPosition }>`
${({ labelPosition }) => ${({ labelPosition }) =>
labelPosition === LabelPosition.Left labelPosition === LabelPosition.Left
? ` ? `
@ -33,7 +33,7 @@ type RadioInputProps = {
'radio-size'?: RadioSize; 'radio-size'?: RadioSize;
}; };
const RadioInput = styled(motion.input)<RadioInputProps>` const StyledRadioInput = styled(motion.input)<RadioInputProps>`
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
background-color: transparent; background-color: transparent;
@ -86,7 +86,7 @@ type LabelProps = {
labelPosition?: LabelPosition; labelPosition?: LabelPosition;
}; };
const Label = styled.label<LabelProps>` const StyledLabel = styled.label<LabelProps>`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
cursor: pointer; cursor: pointer;
font-size: ${({ theme }) => theme.font.size.sm}; font-size: ${({ theme }) => theme.font.size.sm};
@ -126,8 +126,8 @@ export function Radio({
} }
return ( return (
<Container {...restProps} labelPosition={labelPosition}> <StyledContainer {...restProps} labelPosition={labelPosition}>
<RadioInput <StyledRadioInput
type="radio" type="radio"
id="input-radio" id="input-radio"
name="input-radio" name="input-radio"
@ -142,15 +142,15 @@ export function Radio({
transition={{ type: 'spring', stiffness: 300, damping: 20 }} transition={{ type: 'spring', stiffness: 300, damping: 20 }}
/> />
{value && ( {value && (
<Label <StyledLabel
htmlFor="input-radio" htmlFor="input-radio"
labelPosition={labelPosition} labelPosition={labelPosition}
disabled={disabled} disabled={disabled}
> >
{value} {value}
</Label> </StyledLabel>
)} )}
</Container> </StyledContainer>
); );
} }

View File

@ -1,17 +0,0 @@
import styled from '@emotion/styled';
import { overlayBackground } from '@/ui/theme/constants/effects';
export const TextInputContainer = styled.div`
align-items: center;
border: 1px solid ${({ theme }) => theme.border.color.medium};
border-radius: ${({ theme }) => theme.border.radius.sm};
display: flex;
margin-left: -1px;
min-height: 32px;
width: inherit;
${overlayBackground}
z-index: 10;
`;

View File

@ -1,3 +1,4 @@
/* eslint-disable twenty/styled-components-prefixed-with-styled */
import styled from '@emotion/styled'; import styled from '@emotion/styled';
export const TextInputDisplay = styled.div` export const TextInputDisplay = styled.div`

View File

@ -1,15 +1,28 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { textInputStyle } from '@/ui/theme/constants/effects'; import { textInputStyle } from '@/ui/theme/constants/effects';
import { overlayBackground } from '@/ui/theme/constants/effects';
import { TextInputContainer } from './TextInputContainer'; const StyledInplaceInputTextInput = styled.input`
const InplaceInputTextInput = styled.input`
margin: 0; margin: 0;
width: 100%; width: 100%;
${textInputStyle} ${textInputStyle}
`; `;
const StyledTextInputContainer = styled.div`
align-items: center;
border: 1px solid ${({ theme }) => theme.border.color.medium};
border-radius: ${({ theme }) => theme.border.radius.sm};
display: flex;
margin-left: -1px;
min-height: 32px;
width: inherit;
${overlayBackground}
z-index: 10;
`;
export type TextInputEditProps = { export type TextInputEditProps = {
placeholder?: string; placeholder?: string;
value?: string; value?: string;
@ -24,14 +37,14 @@ export function TextInputEdit({
autoFocus, autoFocus,
}: TextInputEditProps) { }: TextInputEditProps) {
return ( return (
<TextInputContainer> <StyledTextInputContainer>
<InplaceInputTextInput <StyledInplaceInputTextInput
autoComplete="off" autoComplete="off"
autoFocus={autoFocus} autoFocus={autoFocus}
placeholder={placeholder} placeholder={placeholder}
value={value} value={value}
onChange={(e) => onChange?.(e.target.value)} onChange={(e) => onChange?.(e.target.value)}
/> />
</TextInputContainer> </StyledTextInputContainer>
); );
} }

View File

@ -7,7 +7,7 @@ type ContainerProps = {
color?: string; color?: string;
}; };
const Container = styled.div<ContainerProps>` const StyledContainer = styled.div<ContainerProps>`
align-items: center; align-items: center;
background-color: ${({ theme, isOn, color }) => background-color: ${({ theme, isOn, color }) =>
isOn ? color ?? theme.color.blue : theme.background.quaternary}; isOn ? color ?? theme.color.blue : theme.background.quaternary};
@ -19,7 +19,7 @@ const Container = styled.div<ContainerProps>`
width: 32px; width: 32px;
`; `;
const Circle = styled(motion.div)` const StyledCircle = styled(motion.div)`
background-color: #fff; background-color: #fff;
border-radius: 50%; border-radius: 50%;
height: 16px; height: 16px;
@ -56,8 +56,8 @@ export function Toggle({ value, onChange, color }: ToggleProps) {
}, [value]); }, [value]);
return ( return (
<Container onClick={handleChange} isOn={isOn} color={color}> <StyledContainer onClick={handleChange} isOn={isOn} color={color}>
<Circle animate={isOn ? 'on' : 'off'} variants={circleVariants} /> <StyledCircle animate={isOn ? 'on' : 'off'} variants={circleVariants} />
</Container> </StyledContainer>
); );
} }

View File

@ -37,7 +37,7 @@ const StyledLayout = styled.div`
const NAVBAR_WIDTH = '236px'; const NAVBAR_WIDTH = '236px';
const MainContainer = styled.div` const StyledMainContainer = styled.div`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
overflow: hidden; overflow: hidden;
@ -63,7 +63,7 @@ export function DefaultLayout({ children }: OwnProps) {
<NavbarAnimatedContainer> <NavbarAnimatedContainer>
<AppNavbar /> <AppNavbar />
</NavbarAnimatedContainer> </NavbarAnimatedContainer>
<MainContainer> <StyledMainContainer>
{onboardingStatus && onboardingStatus !== OnboardingStatus.Completed ? ( {onboardingStatus && onboardingStatus !== OnboardingStatus.Completed ? (
<> <>
<CompaniesMockMode /> <CompaniesMockMode />
@ -76,7 +76,7 @@ export function DefaultLayout({ children }: OwnProps) {
) : ( ) : (
<>{children}</> <>{children}</>
)} )}
</MainContainer> </StyledMainContainer>
</StyledLayout> </StyledLayout>
); );
} }

View File

@ -1,3 +1,4 @@
/* eslint-disable twenty/styled-components-prefixed-with-styled */
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';

View File

@ -14,7 +14,7 @@ import { isNavbarOpenedState } from '../../states/isNavbarOpenedState';
export const PAGE_BAR_MIN_HEIGHT = 40; export const PAGE_BAR_MIN_HEIGHT = 40;
const TopBarContainer = styled.div` const StyledTopBarContainer = styled.div`
align-items: center; align-items: center;
background: ${({ theme }) => theme.background.noisy}; background: ${({ theme }) => theme.background.noisy};
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
@ -35,18 +35,18 @@ const StyledLeftContainer = styled.div`
width: 100%; width: 100%;
`; `;
const TitleContainer = styled.div` const StyledTitleContainer = styled.div`
display: flex; display: flex;
font-size: ${({ theme }) => theme.font.size.md}; font-size: ${({ theme }) => theme.font.size.md};
margin-left: ${({ theme }) => theme.spacing(1)}; margin-left: ${({ theme }) => theme.spacing(1)};
max-width: 50%; max-width: 50%;
`; `;
const TopBarButtonContainer = styled.div` const StyledTopBarButtonContainer = styled.div`
margin-right: ${({ theme }) => theme.spacing(1)}; margin-right: ${({ theme }) => theme.spacing(1)};
`; `;
const BackIconButton = styled(IconButton)` const StyledBackIconButton = styled(IconButton)`
margin-right: ${({ theme }) => theme.spacing(1)}; margin-right: ${({ theme }) => theme.spacing(1)};
`; `;
@ -58,7 +58,7 @@ const StyledTopBarIconTitleContainer = styled.div`
width: 100%; width: 100%;
`; `;
const ActionButtonsContainer = styled.div` const StyledActionButtonsContainer = styled.div`
display: inline-flex; display: inline-flex;
gap: ${({ theme }) => theme.spacing(2)}; gap: ${({ theme }) => theme.spacing(2)};
`; `;
@ -91,29 +91,29 @@ export function PageBar({
return ( return (
<> <>
<TopBarContainer> <StyledTopBarContainer>
<StyledLeftContainer> <StyledLeftContainer>
{!isNavbarOpened && ( {!isNavbarOpened && (
<TopBarButtonContainer> <StyledTopBarButtonContainer>
<NavCollapseButton direction="right" /> <NavCollapseButton direction="right" />
</TopBarButtonContainer> </StyledTopBarButtonContainer>
)} )}
{hasBackButton && ( {hasBackButton && (
<TopBarButtonContainer> <StyledTopBarButtonContainer>
<BackIconButton <StyledBackIconButton
icon={<IconChevronLeft size={iconSize} />} icon={<IconChevronLeft size={iconSize} />}
onClick={navigateBack} onClick={navigateBack}
/> />
</TopBarButtonContainer> </StyledTopBarButtonContainer>
)} )}
<StyledTopBarIconTitleContainer> <StyledTopBarIconTitleContainer>
{icon} {icon}
<TitleContainer data-testid="top-bar-title"> <StyledTitleContainer data-testid="top-bar-title">
<OverflowingTextWithTooltip text={title} /> <OverflowingTextWithTooltip text={title} />
</TitleContainer> </StyledTitleContainer>
</StyledTopBarIconTitleContainer> </StyledTopBarIconTitleContainer>
</StyledLeftContainer> </StyledLeftContainer>
<ActionButtonsContainer> <StyledActionButtonsContainer>
{onFavoriteButtonClick && ( {onFavoriteButtonClick && (
<IconButton <IconButton
icon={<IconHeart size={16} />} icon={<IconHeart size={16} />}
@ -134,8 +134,8 @@ export function PageBar({
variant="border" variant="border"
/> />
)} )}
</ActionButtonsContainer> </StyledActionButtonsContainer>
</TopBarContainer> </StyledTopBarContainer>
</> </>
); );
} }

View File

@ -1,3 +1,4 @@
/* eslint-disable twenty/styled-components-prefixed-with-styled */
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';

View File

@ -1,3 +1,4 @@
/* eslint-disable twenty/styled-components-prefixed-with-styled */
import styled from '@emotion/styled'; import styled from '@emotion/styled';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile'; import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';

View File

@ -7,7 +7,7 @@ import {
useListenClickOutside, useListenClickOutside,
} from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
const ModalDiv = styled(motion.div)` const StyledModalDiv = styled(motion.div)`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: ${({ theme }) => theme.background.primary}; background: ${({ theme }) => theme.background.primary};
@ -43,7 +43,7 @@ const StyledFooter = styled.div`
padding: ${({ theme }) => theme.spacing(5)}; padding: ${({ theme }) => theme.spacing(5)};
`; `;
const BackDrop = styled(motion.div)` const StyledBackDrop = styled(motion.div)`
align-items: center; align-items: center;
background: ${({ theme }) => theme.background.overlay}; background: ${({ theme }) => theme.background.overlay};
display: flex; display: flex;
@ -111,8 +111,8 @@ export function Modal({
} }
return ( return (
<BackDrop> <StyledBackDrop>
<ModalDiv <StyledModalDiv
// framer-motion seems to have typing problems with refs // framer-motion seems to have typing problems with refs
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore // @ts-ignore
@ -125,8 +125,8 @@ export function Modal({
{...restProps} {...restProps}
> >
{children} {children}
</ModalDiv> </StyledModalDiv>
</BackDrop> </StyledBackDrop>
); );
} }

View File

@ -9,7 +9,7 @@ type OwnProps = {
title: string; title: string;
}; };
const IconAndButtonContainer = styled.button` const StyledIconAndButtonContainer = styled.button`
align-items: center; align-items: center;
background: inherit; background: inherit;
border: none; border: none;
@ -39,7 +39,7 @@ export default function NavBackButton({ title }: OwnProps) {
return ( return (
<> <>
<StyledContainer> <StyledContainer>
<IconAndButtonContainer <StyledIconAndButtonContainer
onClick={() => { onClick={() => {
setIsNavbarSwitchingSize(true); setIsNavbarSwitchingSize(true);
navigate('/', { replace: true }); navigate('/', { replace: true });
@ -47,7 +47,7 @@ export default function NavBackButton({ title }: OwnProps) {
> >
<IconChevronLeft /> <IconChevronLeft />
<span>{title}</span> <span>{title}</span>
</IconAndButtonContainer> </StyledIconAndButtonContainer>
</StyledContainer> </StyledContainer>
</> </>
); );

View File

@ -10,7 +10,7 @@ import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { navbarIconSize } from '../constants'; import { navbarIconSize } from '../constants';
const CollapseButton = styled.button` const StyledCollapseButton = styled.button`
align-items: center; align-items: center;
background: inherit; background: inherit;
border: 0; border: 0;
@ -48,13 +48,13 @@ export default function NavCollapseButton({
return ( return (
<> <>
{direction === 'left' ? ( {direction === 'left' ? (
<CollapseButton onClick={() => setIsNavOpen(!isNavOpen)}> <StyledCollapseButton onClick={() => setIsNavOpen(!isNavOpen)}>
<IconLayoutSidebarLeftCollapse size={iconSize} /> <IconLayoutSidebarLeftCollapse size={iconSize} />
</CollapseButton> </StyledCollapseButton>
) : ( ) : (
<CollapseButton onClick={() => setIsNavOpen(!isNavOpen)}> <StyledCollapseButton onClick={() => setIsNavOpen(!isNavOpen)}>
<IconLayoutSidebarRightCollapse size={iconSize} /> <IconLayoutSidebarRightCollapse size={iconSize} />
</CollapseButton> </StyledCollapseButton>
)} )}
</> </>
); );

View File

@ -21,7 +21,7 @@ const StyledContainer = styled.div`
user-select: none; user-select: none;
`; `;
const LogoAndNameContainer = styled.div` const StyledLogoAndNameContainer = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
`; `;
@ -56,7 +56,7 @@ function NavWorkspaceButton() {
return ( return (
<StyledContainer> <StyledContainer>
<LogoAndNameContainer> <StyledLogoAndNameContainer>
<StyledLogo <StyledLogo
logo={ logo={
currentWorkspace?.logo currentWorkspace?.logo
@ -65,7 +65,7 @@ function NavWorkspaceButton() {
} }
></StyledLogo> ></StyledLogo>
<StyledName>{currentWorkspace?.displayName ?? 'Twenty'}</StyledName> <StyledName>{currentWorkspace?.displayName ?? 'Twenty'}</StyledName>
</LogoAndNameContainer> </StyledLogoAndNameContainer>
<NavCollapseButton direction="left" /> <NavCollapseButton direction="left" />
</StyledContainer> </StyledContainer>
); );

View File

@ -10,14 +10,14 @@ import { RightDrawerPages } from '../types/RightDrawerPages';
import { RightDrawerTopBar } from './RightDrawerTopBar'; import { RightDrawerTopBar } from './RightDrawerTopBar';
const RightDrawerPage = styled.div` const StyledRightDrawerPage = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
width: 100%; width: 100%;
`; `;
const RightDrawerBody = styled.div` const StyledRightDrawerBody = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: calc( height: calc(
@ -47,9 +47,9 @@ export function RightDrawerRouter() {
} }
return ( return (
<RightDrawerPage> <StyledRightDrawerPage>
<RightDrawerTopBar /> <RightDrawerTopBar />
<RightDrawerBody>{page}</RightDrawerBody> <StyledRightDrawerBody>{page}</StyledRightDrawerBody>
</RightDrawerPage> </StyledRightDrawerPage>
); );
} }

View File

@ -24,7 +24,7 @@ const StyledRightDrawerTopBar = styled.div`
padding-right: ${({ theme }) => theme.spacing(2)}; padding-right: ${({ theme }) => theme.spacing(2)};
`; `;
const TopBarWrapper = styled.div` const StyledTopBarWrapper = styled.div`
display: flex; display: flex;
`; `;
@ -34,10 +34,10 @@ export function RightDrawerTopBar() {
return ( return (
<StyledRightDrawerTopBar> <StyledRightDrawerTopBar>
<TopBarWrapper> <StyledTopBarWrapper>
<RightDrawerTopBarCloseButton /> <RightDrawerTopBarCloseButton />
{!isMobile && <RightDrawerTopBarExpandButton />} {!isMobile && <RightDrawerTopBarExpandButton />}
</TopBarWrapper> </StyledTopBarWrapper>
<ActivityActionBar activityId={activityId ?? ''} /> <ActivityActionBar activityId={activityId ?? ''} />
</StyledRightDrawerTopBar> </StyledRightDrawerTopBar>
); );

View File

@ -51,7 +51,7 @@ const StyledIconContainer = styled.div`
margin-right: ${({ theme }) => theme.spacing(2)}; margin-right: ${({ theme }) => theme.spacing(2)};
`; `;
const ProgressBarContainer = styled.div` const StyledProgressBarContainer = styled.div`
height: 5px; height: 5px;
left: 0; left: 0;
position: absolute; position: absolute;
@ -59,7 +59,7 @@ const ProgressBarContainer = styled.div`
top: 0; top: 0;
`; `;
const CloseButton = styled.button<Pick<SnackbarProps, 'variant'>>` const StyledCloseButton = styled.button<Pick<SnackbarProps, 'variant'>>`
align-items: center; align-items: center;
background-color: transparent; background-color: transparent;
border: none; border: none;
@ -162,20 +162,20 @@ export function SnackBar({
variant={variant} variant={variant}
{...rootProps} {...rootProps}
> >
<ProgressBarContainer> <StyledProgressBarContainer>
<ProgressBar <ProgressBar
ref={progressBarRef} ref={progressBarRef}
barHeight={5} barHeight={5}
barColor={rgba(theme.grayScale.gray0, 0.3)} barColor={rgba(theme.grayScale.gray0, 0.3)}
duration={duration} duration={duration}
/> />
</ProgressBarContainer> </StyledProgressBarContainer>
{icon && <StyledIconContainer>{icon}</StyledIconContainer>} {icon && <StyledIconContainer>{icon}</StyledIconContainer>}
{children ? children : message} {children ? children : message}
{allowDismiss && ( {allowDismiss && (
<CloseButton variant={variant} onClick={closeSnackbar}> <StyledCloseButton variant={variant} onClick={closeSnackbar}>
<IconX aria-label="Close" size={theme.icon.size.md} /> <IconX aria-label="Close" size={theme.icon.size.md} />
</CloseButton> </StyledCloseButton>
)} )}
</StyledMotionContainer> </StyledMotionContainer>
); );

View File

@ -6,7 +6,7 @@ import { snackBarInternalState } from '../states/snackBarState';
import { SnackBar } from './SnackBar'; import { SnackBar } from './SnackBar';
const SnackBarContainer = styled.div` const StyledSnackBarContainer = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: fixed; position: fixed;
@ -15,7 +15,7 @@ const SnackBarContainer = styled.div`
z-index: 99999999; z-index: 99999999;
`; `;
const SnackBarMotionContainer = styled(motion.div)` const StyledSnackBarMotionContainer = styled(motion.div)`
margin-right: ${({ theme }) => theme.spacing(3)}; margin-right: ${({ theme }) => theme.spacing(3)};
margin-top: ${({ theme }) => theme.spacing(3)}; margin-top: ${({ theme }) => theme.spacing(3)};
`; `;
@ -68,9 +68,9 @@ export function SnackBarProvider({ children }: React.PropsWithChildren) {
return ( return (
<> <>
{children} {children}
<SnackBarContainer> <StyledSnackBarContainer>
{snackBarState.queue.map((snackBar) => ( {snackBarState.queue.map((snackBar) => (
<SnackBarMotionContainer <StyledSnackBarMotionContainer
key={snackBar.id} key={snackBar.id}
variants={reducedMotion ? reducedVariants : variants} variants={reducedMotion ? reducedVariants : variants}
initial="initial" initial="initial"
@ -83,9 +83,9 @@ export function SnackBarProvider({ children }: React.PropsWithChildren) {
{...snackBar} {...snackBar}
onClose={() => handleSnackBarClose(snackBar.id)} onClose={() => handleSnackBarClose(snackBar.id)}
/> />
</SnackBarMotionContainer> </StyledSnackBarMotionContainer>
))} ))}
</SnackBarContainer> </StyledSnackBarContainer>
</> </>
); );
} }

View File

@ -4,13 +4,13 @@ import { motion } from 'framer-motion';
import { AnimatedCheckmark } from '@/ui/checkmark/components/AnimatedCheckmark'; import { AnimatedCheckmark } from '@/ui/checkmark/components/AnimatedCheckmark';
const Container = styled.div<{ isLast: boolean }>` const StyledContainer = styled.div<{ isLast: boolean }>`
align-items: center; align-items: center;
display: flex; display: flex;
flex-grow: ${({ isLast }) => (isLast ? '0' : '1')}; flex-grow: ${({ isLast }) => (isLast ? '0' : '1')};
`; `;
const StepCircle = styled(motion.div)` const StyledStepCircle = styled(motion.div)`
align-items: center; align-items: center;
border-radius: 50%; border-radius: 50%;
border-style: solid; border-style: solid;
@ -25,13 +25,13 @@ const StepCircle = styled(motion.div)`
width: 20px; width: 20px;
`; `;
const StepIndex = styled.span` const StyledStepIndex = styled.span`
color: ${({ theme }) => theme.font.color.tertiary}; color: ${({ theme }) => theme.font.color.tertiary};
font-size: ${({ theme }) => theme.font.size.md}; font-size: ${({ theme }) => theme.font.size.md};
font-weight: ${({ theme }) => theme.font.weight.medium}; font-weight: ${({ theme }) => theme.font.weight.medium};
`; `;
const StepLabel = styled.span<{ isActive: boolean }>` const StyledStepLabel = styled.span<{ isActive: boolean }>`
color: ${({ theme, isActive }) => color: ${({ theme, isActive }) =>
isActive ? theme.font.color.primary : theme.font.color.tertiary}; isActive ? theme.font.color.primary : theme.font.color.tertiary};
font-size: ${({ theme }) => theme.font.size.md}; font-size: ${({ theme }) => theme.font.size.md};
@ -40,7 +40,7 @@ const StepLabel = styled.span<{ isActive: boolean }>`
white-space: nowrap; white-space: nowrap;
`; `;
const StepLine = styled(motion.div)` const StyledStepLine = styled(motion.div)`
height: 2px; height: 2px;
margin-left: ${({ theme }) => theme.spacing(2)}; margin-left: ${({ theme }) => theme.spacing(2)};
margin-right: ${({ theme }) => theme.spacing(2)}; margin-right: ${({ theme }) => theme.spacing(2)};
@ -90,8 +90,8 @@ export const Step = ({
}; };
return ( return (
<Container isLast={isLast}> <StyledContainer isLast={isLast}>
<StepCircle <StyledStepCircle
variants={variantsCircle} variants={variantsCircle}
animate={isActive ? 'active' : 'inactive'} animate={isActive ? 'active' : 'inactive'}
> >
@ -101,17 +101,17 @@ export const Step = ({
color={theme.grayScale.gray0} color={theme.grayScale.gray0}
/> />
)} )}
{!isActive && <StepIndex>{index + 1}</StepIndex>} {!isActive && <StyledStepIndex>{index + 1}</StyledStepIndex>}
</StepCircle> </StyledStepCircle>
<StepLabel isActive={isActive}>{label}</StepLabel> <StyledStepLabel isActive={isActive}>{label}</StyledStepLabel>
{!isLast && ( {!isLast && (
<StepLine <StyledStepLine
variants={variantsLine} variants={variantsLine}
animate={isActive ? 'active' : 'inactive'} animate={isActive ? 'active' : 'inactive'}
/> />
)} )}
{isActive && children} {isActive && children}
</Container> </StyledContainer>
); );
}; };

View File

@ -3,7 +3,7 @@ import styled from '@emotion/styled';
import { Step, StepProps } from './Step'; import { Step, StepProps } from './Step';
const Container = styled.div` const StyledContainer = styled.div`
display: flex; display: flex;
flex: 1; flex: 1;
justify-content: space-between; justify-content: space-between;
@ -16,7 +16,7 @@ export type StepsProps = React.PropsWithChildren &
export const StepBar = ({ children, activeStep, ...restProps }: StepsProps) => { export const StepBar = ({ children, activeStep, ...restProps }: StepsProps) => {
return ( return (
<Container {...restProps}> <StyledContainer {...restProps}>
{React.Children.map(children, (child, index) => { {React.Children.map(children, (child, index) => {
if (!React.isValidElement(child)) { if (!React.isValidElement(child)) {
return null; return null;
@ -35,7 +35,7 @@ export const StepBar = ({ children, activeStep, ...restProps }: StepsProps) => {
isLast: index === React.Children.count(children) - 1, isLast: index === React.Children.count(children) - 1,
}); });
})} })}
</Container> </StyledContainer>
); );
}; };

View File

@ -27,7 +27,7 @@ const StyledEditableCellDisplayModeOuterContainer = styled.div<
: ''} : ''}
`; `;
const EditableCellDisplayModeInnerContainer = styled.div` const StyledEditableCellDisplayModeInnerContainer = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
height: 100%; height: 100%;
@ -52,9 +52,9 @@ export function EditableCellDisplayContainer({
softFocus={softFocus} softFocus={softFocus}
ref={scrollRef} ref={scrollRef}
> >
<EditableCellDisplayModeInnerContainer> <StyledEditableCellDisplayModeInnerContainer>
{children} {children}
</EditableCellDisplayModeInnerContainer> </StyledEditableCellDisplayModeInnerContainer>
</StyledEditableCellDisplayModeOuterContainer> </StyledEditableCellDisplayModeOuterContainer>
); );
} }

View File

@ -1,3 +1,4 @@
/* eslint-disable twenty/styled-components-prefixed-with-styled */
import { Tooltip } from 'react-tooltip'; import { Tooltip } from 'react-tooltip';
import styled from '@emotion/styled'; import styled from '@emotion/styled';

View File

@ -7,7 +7,7 @@ const StyledContainer = styled(motion.div)`
overflow: hidden; overflow: hidden;
`; `;
const Word = styled(motion.span)` const StyledWord = styled(motion.span)`
white-space: pre; white-space: pre;
`; `;
@ -61,9 +61,9 @@ export function AnimatedTextWord({ text = '', ...restProps }: Props) {
{...restProps} {...restProps}
> >
{words.map((word, index) => ( {words.map((word, index) => (
<Word variants={childAnimation} key={index}> <StyledWord variants={childAnimation} key={index}>
{word} {word}
</Word> </StyledWord>
))} ))}
</StyledContainer> </StyledContainer>
); );

View File

@ -14,7 +14,7 @@ const StyledContainer = styled.div`
padding: ${({ theme }) => theme.spacing(3)}; padding: ${({ theme }) => theme.spacing(3)};
`; `;
const Content = styled.div` const StyledContent = styled.div`
display: flex; display: flex;
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
@ -22,11 +22,11 @@ const Content = styled.div`
margin-left: ${({ theme }) => theme.spacing(3)}; margin-left: ${({ theme }) => theme.spacing(3)};
`; `;
const NameText = styled.span` const StyledNameText = styled.span`
color: ${({ theme }) => theme.font.color.primary}; color: ${({ theme }) => theme.font.color.primary};
`; `;
const EmailText = styled.span` const StyledEmailText = styled.span`
color: ${({ theme }) => theme.font.color.tertiary}; color: ${({ theme }) => theme.font.color.tertiary};
`; `;
@ -50,10 +50,10 @@ export function WorkspaceMemberCard({ workspaceMember, accessory }: OwnProps) {
type="squared" type="squared"
size="xl" size="xl"
/> />
<Content> <StyledContent>
<NameText>{workspaceMember.user.displayName}</NameText> <StyledNameText>{workspaceMember.user.displayName}</StyledNameText>
<EmailText>{workspaceMember.user.email}</EmailText> <StyledEmailText>{workspaceMember.user.email}</StyledEmailText>
</Content> </StyledContent>
{accessory} {accessory}
</StyledContainer> </StyledContainer>

View File

@ -30,7 +30,7 @@ const StyledContainer = styled.div`
width: 350px; width: 350px;
`; `;
const ButtonContainer = styled.div` const StyledButtonContainer = styled.div`
align-items: center; align-items: center;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -109,7 +109,7 @@ export function SettingsWorkspaceMembers() {
workspaceMember={{ user: member.user }} workspaceMember={{ user: member.user }}
accessory={ accessory={
currentUser?.id !== member.user.id && ( currentUser?.id !== member.user.id && (
<ButtonContainer> <StyledButtonContainer>
<Button <Button
onClick={() => { onClick={() => {
setIsConfirmationModalOpen(true); setIsConfirmationModalOpen(true);
@ -119,7 +119,7 @@ export function SettingsWorkspaceMembers() {
size={ButtonSize.Small} size={ButtonSize.Small}
icon={<IconTrash size={theme.icon.size.md} />} icon={<IconTrash size={theme.icon.size.md} />}
/> />
</ButtonContainer> </StyledButtonContainer>
) )
} }
/> />

View File

@ -9722,7 +9722,7 @@ eslint-plugin-testing-library@^5.0.1:
"@typescript-eslint/utils" "^5.58.0" "@typescript-eslint/utils" "^5.58.0"
"eslint-plugin-twenty@file:../packages/eslint-plugin-twenty": "eslint-plugin-twenty@file:../packages/eslint-plugin-twenty":
version "0.0.1" version "0.0.2"
dependencies: dependencies:
postcss "^8.4.24" postcss "^8.4.24"

View File

@ -1,10 +1,12 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const noHardcodedColors = require('./rules/no-hardcoded-colors'); const noHardcodedColors = require('./rules/no-hardcoded-colors');
const cssAlphabetically = require('./rules/sort-css-properties-alphabetically'); const cssAlphabetically = require('./rules/sort-css-properties-alphabetically');
const styledComponentsPrefixedWithStyled = require('./rules/styled-components-prefixed-with-styled');
module.exports = { module.exports = {
rules: { rules: {
'no-hardcoded-colors': noHardcodedColors, 'no-hardcoded-colors': noHardcodedColors,
'sort-css-properties-alphabetically': cssAlphabetically, 'sort-css-properties-alphabetically': cssAlphabetically,
'styled-components-prefixed-with-styled': styledComponentsPrefixedWithStyled,
}, },
}; };

View File

@ -1,6 +1,6 @@
{ {
"name": "eslint-plugin-twenty", "name": "eslint-plugin-twenty",
"version": "0.0.1", "version": "0.0.2",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"postcss": "^8.4.24" "postcss": "^8.4.24"

View File

@ -0,0 +1,32 @@
module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'Warn when StyledComponents are not prefixed with Styled',
},
recommended: true,
fixable: 'code',
schema: [],
},
create: function(context) {
return {
VariableDeclarator: node => {
const templateExpr = node.init
if (templateExpr?.type !== 'TaggedTemplateExpression') {
return;
}
const tag = templateExpr.tag
const tagged = tag.type === 'MemberExpression' ? tag.object
: tag.type === 'CallExpression' ? tag.callee
: null
if (tagged?.name === 'styled') {
const variable = node.id;
if (variable?.name.startsWith('Styled')) {
return;
}
context.report({ node, message: `'${variable.name}' is a StyledComponent and is not prefixed with Styled.` });
}
},
}
}
};