Skip to content

Commit

Permalink
removed @chakra-ui dependencies (twentyhq#7004)
Browse files Browse the repository at this point in the history
Issue twentyhq#6976 
@FelixMalfait 

I could not do
```
import { Banner } from 'twenty-ui';

const StyledBanner = styled(Banner)
  display: flex;
  align-items: center;
  padding: ${({ theme }) => theme.spacing(8)};
  position: absolute;
  border-radius: 8px;
  &:hover {
    background-color: ${({ theme }) => theme.accent.primary};
  }
;
```
The styles wont get overridden for Banner, so for now I styled a new
banner in `UnmatchColumnBanner` which is inconsistent.
I couldnt figure out why css properties are not being overridden, need
help!

@Bonapara 
Question - 
Should the click work on entire banner or just cheveron? For now it just
on cheveron click.


https://github.com/user-attachments/assets/0f409e78-a341-4f26-af74-117e4b2775a9

---------

Co-authored-by: Charles Bochet <[email protected]>
  • Loading branch information
ehconitin and charlesBochet authored Sep 14, 2024
1 parent 4544114 commit 0dbd4a7
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 350 deletions.
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
"@aws-sdk/credential-providers": "^3.363.0",
"@blocknote/mantine": "^0.15.3",
"@blocknote/react": "^0.15.3",
"@chakra-ui/accordion": "^2.3.0",
"@chakra-ui/system": "^2.6.0",
"@codesandbox/sandpack-react": "^2.13.5",
"@dagrejs/dagre": "^1.1.2",
"@docusaurus/core": "^3.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,56 +1,13 @@
import { useSpreadsheetImportInternal } from '@/spreadsheet-import/hooks/useSpreadsheetImportInternal';
import { SubMatchingSelect } from '@/spreadsheet-import/steps/components/MatchColumnsStep/components/SubMatchingSelect';
import { UnmatchColumnBanner } from '@/spreadsheet-import/steps/components/MatchColumnsStep/components/UnmatchColumnBanner';
import { Column } from '@/spreadsheet-import/steps/components/MatchColumnsStep/MatchColumnsStep';
import { Fields } from '@/spreadsheet-import/types';
import {
Accordion,
AccordionIcon,
AccordionItem,
AccordionPanel,
AccordionButton as ChakraAccordionButton,
} from '@chakra-ui/accordion';
import styled from '@emotion/styled';
import { IconChevronDown, IconInfoCircle, isDefined } from 'twenty-ui';
import { useState } from 'react';
import { ExpandableContainer, isDefined } from 'twenty-ui';

const StyledAccordionButton = styled(ChakraAccordionButton)`
align-items: center;
background-color: ${({ theme }) => theme.accent.secondary};
border: none;
border-radius: ${({ theme }) => theme.border.radius.md};
box-sizing: border-box;
color: ${({ theme }) => theme.font.color.primary};
display: flex;
flex-direction: row;
padding: ${({ theme }) => theme.spacing(2)};
width: 100%;
height: 40px;
&:hover {
background-color: ${({ theme }) => theme.accent.primary};
}
`;

const StyledAccordionContainer = styled.div`
display: flex;
width: 100%;
height: auto;
`;

const StyledAccordionLabel = styled.span`
color: ${({ theme }) => theme.color.blue};
display: flex;
flex: 1;
font-size: ${({ theme }) => theme.font.size.sm};
align-items: center;
gap: ${({ theme }) => theme.spacing(2)};
text-align: left;
`;

const StyledIconChevronDown = styled(IconChevronDown)`
color: ${({ theme }) => theme.color.blue} !important;
`;

const getAccordionTitle = <T extends string>(
const getExpandableContainerTitle = <T extends string>(
fields: Fields<T>,
column: Column<T>,
) => {
Expand All @@ -70,42 +27,51 @@ type UnmatchColumnProps<T extends string> = {
onSubChange: (val: T, index: number, option: string) => void;
};

const StyledContainer = styled.div`
position: relative;
width: 100%;
`;

const StyledContentWrapper = styled.div`
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(3)};
margin-top: ${({ theme }) => theme.spacing(4)};
padding-bottom: ${({ theme }) => theme.spacing(4)};
`;

export const UnmatchColumn = <T extends string>({
columns,
columnIndex,
onSubChange,
}: UnmatchColumnProps<T>) => {
const { fields } = useSpreadsheetImportInternal<T>();

const [isExpanded, setIsExpanded] = useState(false);
const column = columns[columnIndex];
const isSelect = 'matchedOptions' in column;

if (!isSelect) return null;

return (
isSelect && (
<StyledAccordionContainer>
<Accordion allowMultiple width="100%" height="100%">
<AccordionItem border="none" py={1} height="100%">
<StyledAccordionButton data-testid="accordion-button">
<StyledAccordionLabel>
<IconInfoCircle />
{getAccordionTitle(fields, column)}
</StyledAccordionLabel>
<AccordionIcon as={StyledIconChevronDown} />
</StyledAccordionButton>
<AccordionPanel mt={16} gap={12} display="flex" flexDir="column">
{column.matchedOptions.map((option) => (
<SubMatchingSelect
option={option}
column={column}
onSubChange={onSubChange}
key={option.entry}
placeholder="Select an option"
/>
))}
</AccordionPanel>
</AccordionItem>
</Accordion>
</StyledAccordionContainer>
)
<StyledContainer>
<UnmatchColumnBanner
message={getExpandableContainerTitle(fields, column)}
buttonOnClick={() => setIsExpanded(!isExpanded)}
isExpanded={isExpanded}
/>
<ExpandableContainer isExpanded={isExpanded}>
<StyledContentWrapper>
{column.matchedOptions.map((option) => (
<SubMatchingSelect
option={option}
column={column}
onSubChange={onSubChange}
key={option.entry}
placeholder="Select an option"
/>
))}
</StyledContentWrapper>
</ExpandableContainer>
</StyledContainer>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { Banner, IconChevronDown, IconInfoCircle } from 'twenty-ui';

const StyledBanner = styled(Banner)`
background: ${({ theme }) => theme.accent.secondary};
border-radius: ${({ theme }) => theme.spacing(2)};
padding: ${({ theme }) => theme.spacing(2) + ' ' + theme.spacing(2.5)};
`;

const StyledText = styled.div`
color: ${({ theme }) => theme.color.blue};
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;

const StyledTransitionedIconChevronDown = styled(IconChevronDown)<{
isExpanded: boolean;
}>`
color: ${({ theme }) => theme.color.blue};
transform: ${({ isExpanded }) =>
isExpanded ? 'rotate(180deg)' : 'rotate(0deg)'};
transition: ${({ theme }) =>
`transform ${theme.animation.duration.normal}s ease`};
cursor: pointer;
`;

export const UnmatchColumnBanner = ({
message,
isExpanded,
buttonOnClick,
}: {
message: string;
isExpanded: boolean;
buttonOnClick?: () => void;
}) => {
const theme = useTheme();
return (
<StyledBanner>
<IconInfoCircle color={theme.color.blue} size={theme.icon.size.md} />
<StyledText>{message}</StyledText>
{buttonOnClick && (
<StyledTransitionedIconChevronDown
isExpanded={isExpanded}
onClick={buttonOnClick}
size={theme.icon.size.md}
/>
)}
</StyledBanner>
);
};
1 change: 0 additions & 1 deletion packages/twenty-front/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ export default defineConfig(({ command, mode }) => {
localsConvention: 'camelCaseOnly',
},
},

resolve: {
alias: {
path: 'rollup-plugin-node-polyfills/polyfills/path',
Expand Down
16 changes: 11 additions & 5 deletions packages/twenty-ui/src/display/banner/components/Banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@ const StyledBanner = styled.div<{ variant?: BannerVariant }>`

export type BannerVariant = 'danger' | 'default';

type BannerProps = {
variant?: BannerVariant;
className?: string;
children: React.ReactNode;
} & React.HTMLAttributes<HTMLDivElement>;

export const Banner = ({
variant = 'default',
className,
children,
}: {
variant?: BannerVariant;
children: React.ReactNode;
} & React.HTMLAttributes<HTMLDivElement>) => (
<StyledBanner variant={variant}>{children}</StyledBanner>
}: BannerProps) => (
<StyledBanner variant={variant} className={className}>
{children}
</StyledBanner>
);
1 change: 1 addition & 0 deletions packages/twenty-ui/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './components';
export * from './display';
export * from './layout';
export * from './testing';
export * from './theme';
export * from './utilities';
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import styled from '@emotion/styled';
import { isDefined } from '@ui/utilities';
import React, { useLayoutEffect, useRef, useState } from 'react';

const StyledTransitionContainer = styled.div<{
isExpanded: boolean;
height: number;
}>`
max-height: ${({ isExpanded, height }) => (isExpanded ? `${height}px` : '0')};
overflow: hidden;
position: relative;
transition: max-height
${({ theme, isExpanded }) =>
`${theme.animation.duration.normal}s ${isExpanded ? 'ease-in' : 'ease-out'}`};
`;

type ExpandableContainerProps = {
isExpanded: boolean;
children: React.ReactNode;
};

export const ExpandableContainer = ({
isExpanded,
children,
}: ExpandableContainerProps) => {
const [contentHeight, setContentHeight] = useState(0);
const contentRef = useRef<HTMLDivElement>(null);

useLayoutEffect(() => {
if (isDefined(contentRef.current)) {
setContentHeight(contentRef.current.scrollHeight);
}
}, [isExpanded]);

return (
<StyledTransitionContainer isExpanded={isExpanded} height={contentHeight}>
<div ref={contentRef}>{children}</div>
</StyledTransitionContainer>
);
};

export default ExpandableContainer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import styled from '@emotion/styled';
import { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '@ui/testing';
import { useState } from 'react';
import ExpandableContainer from '../ExpandableContainer';

const StyledButton = styled.button`
padding: ${({ theme }) => theme.spacing(2)} ${({ theme }) => theme.spacing(4)};
background-color: ${({ theme }) => theme.color.blue50};
color: ${({ theme }) => theme.font.color.primary};
border: none;
border-radius: ${({ theme }) => theme.spacing(1)};
cursor: pointer;
margin-bottom: ${({ theme }) => theme.spacing(3)};
&:hover {
background-color: ${({ theme }) => theme.color.blue40};
}
`;

const StyledContent = styled.div`
background-color: ${({ theme }) => theme.background.primary};
height: 200px;
padding: ${({ theme }) => theme.spacing(3)};
p {
color: ${({ theme }) => theme.font.color.primary};
margin-bottom: ${({ theme }) => theme.spacing(2)};
font-size: ${({ theme }) => theme.font.size.md};
}
`;

const ExpandableContainerWithButton = (args: any) => {
const [isExpanded, setIsExpanded] = useState(args.isExpanded);

return (
<div>
<StyledButton onClick={() => setIsExpanded(!isExpanded)}>
{isExpanded ? 'Collapse' : 'Expand'}
</StyledButton>
<ExpandableContainer isExpanded={isExpanded}>
<StyledContent>
<p>
This is some content inside the ExpandableContainer. It will grow
and shrink depending on the expand/collapse state.
</p>
<p>
Add more text or even other components here to test how the
container handles more content.
</p>
<p>
Feel free to adjust the height and content to see how it affects the
expand/collapse behavior.
</p>
</StyledContent>
</ExpandableContainer>
</div>
);
};

const meta: Meta<typeof ExpandableContainer> = {
title: 'UI/Layout/ExpandableContainer',
component: ExpandableContainerWithButton,
decorators: [ComponentDecorator],
argTypes: {
isExpanded: {
control: 'boolean',
description: 'Controls whether the container is expanded or collapsed',
defaultValue: false,
},
},
};

export default meta;
type Story = StoryObj<typeof ExpandableContainerWithButton>;

export const Default: Story = {
args: {
isExpanded: false,
},
};
1 change: 1 addition & 0 deletions packages/twenty-ui/src/layout/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './expandableContainer/components/ExpandableContainer';
Loading

0 comments on commit 0dbd4a7

Please sign in to comment.