diff --git a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx b/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx index e71310d36..25daccb38 100644 --- a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx +++ b/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx @@ -22,6 +22,7 @@ import { createPortal } from 'react-dom'; import { useLocation } from 'react-router-dom'; import { useRecoilState } from 'recoil'; import { + AnimatedExpandableContainer, IconFolder, IconFolderOpen, IconHeartOff, @@ -158,7 +159,12 @@ export const CurrentWorkspaceMemberFavorites = ({ )} - {isOpen && ( + {(provided) => (
)} - )} + {createPortal( diff --git a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx index 94581966a..8ebd71f36 100644 --- a/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx +++ b/packages/twenty-front/src/modules/object-metadata/components/NavigationDrawerItemForObjectMetadataItem.tsx @@ -9,7 +9,7 @@ import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-dr import { View } from '@/views/types/View'; import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews'; import { useLocation } from 'react-router-dom'; -import { useIcons } from 'twenty-ui'; +import { AnimatedExpandableContainer, useIcons } from 'twenty-ui'; export type NavigationDrawerItemForObjectMetadataItemProps = { objectMetadataItem: ObjectMetadataItem; @@ -66,8 +66,14 @@ export const NavigationDrawerItemForObjectMetadataItem = ({ Icon={getIcon(objectMetadataItem.icon)} active={isActive} /> - {shouldSubItemsBeDisplayed && - sortedObjectMetadataViews.map((view, index) => ( + + + {sortedObjectMetadataViews.map((view, index) => ( ))} + ); }; diff --git a/packages/twenty-front/src/modules/settings/components/AdvancedSettingsWrapper.tsx b/packages/twenty-front/src/modules/settings/components/AdvancedSettingsWrapper.tsx index ad3f07184..d8ec22bf8 100644 --- a/packages/twenty-front/src/modules/settings/components/AdvancedSettingsWrapper.tsx +++ b/packages/twenty-front/src/modules/settings/components/AdvancedSettingsWrapper.tsx @@ -1,26 +1,37 @@ -import { useExpandedAnimation } from '@/settings/hooks/useExpandedAnimation'; +import { ADVANCED_SETTINGS_ANIMATION_DURATION } from '@/settings/constants/AdvancedSettingsAnimationDurations'; import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; import styled from '@emotion/styled'; -import { AnimatePresence, motion } from 'framer-motion'; import { useRecoilValue } from 'recoil'; -import { IconPoint, MAIN_COLORS } from 'twenty-ui'; +import { AnimatedExpandableContainer, IconPoint, MAIN_COLORS } from 'twenty-ui'; const StyledAdvancedWrapper = styled.div` position: relative; width: 100%; `; -const StyledIconContainer = styled.div` +const StyledIconContainer = styled.div<{ navigationDrawerItem: boolean }>` display: flex; - height: 100%; - left: ${({ theme }) => theme.spacing(-4)}; position: absolute; - top: 0; + + ${({ navigationDrawerItem, theme }) => { + if (navigationDrawerItem) { + return ` + height: 100%; + left: ${theme.spacing(-5)}; + align-items: center; + `; + } + return ` + left: ${theme.spacing(-4)}; + top: ${theme.spacing(1)}; + `; + }} `; const StyledContent = styled.div` width: 100%; `; + const StyledIconPoint = styled(IconPoint)` margin-right: 0; `; @@ -29,43 +40,37 @@ type AdvancedSettingsWrapperProps = { children: React.ReactNode; dimension?: 'width' | 'height'; hideIcon?: boolean; + navigationDrawerItem?: boolean; }; export const AdvancedSettingsWrapper = ({ children, dimension = 'height', hideIcon = false, + navigationDrawerItem = false, }: AdvancedSettingsWrapperProps) => { const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState); - const { contentRef, motionAnimationVariants } = useExpandedAnimation( - isAdvancedModeEnabled, - dimension, - ); return ( - - {isAdvancedModeEnabled && ( - - - {!hideIcon && ( - - - - )} - {children} - - - )} - + + + {!hideIcon && ( + + + + )} + {children} + + ); }; diff --git a/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx b/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx index 6f4409b54..ddc3dfdec 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx @@ -12,20 +12,18 @@ import { IconHierarchy2, IconKey, IconMail, - IconPoint, IconRocket, IconServer, IconSettings, IconUserCircle, IconUsers, - MAIN_COLORS, } from 'twenty-ui'; import { useAuth } from '@/auth/hooks/useAuth'; import { currentUserState } from '@/auth/states/currentUserState'; import { billingState } from '@/client-config/states/billingState'; +import { AdvancedSettingsWrapper } from '@/settings/components/AdvancedSettingsWrapper'; import { SettingsNavigationDrawerItem } from '@/settings/components/SettingsNavigationDrawerItem'; -import { useExpandedAnimation } from '@/settings/hooks/useExpandedAnimation'; import { getSettingsPagePath } from '@/settings/utils/getSettingsPagePath'; import { SettingsPath } from '@/types/SettingsPath'; import { @@ -35,11 +33,8 @@ import { import { NavigationDrawerItemGroup } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItemGroup'; import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSection'; import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle'; -import { isAdvancedModeEnabledState } from '@/ui/navigation/navigation-drawer/states/isAdvancedModeEnabledState'; import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; -import styled from '@emotion/styled'; -import { AnimatePresence, motion } from 'framer-motion'; import { matchPath, resolvePath, useLocation } from 'react-router-dom'; import { FeatureFlagKey } from '~/generated/graphql'; @@ -51,32 +46,7 @@ type SettingsNavigationItem = { matchSubPages?: boolean; }; -const StyledIconContainer = styled.div` - position: absolute; - left: ${({ theme }) => theme.spacing(-5)}; - height: 100%; - display: flex; - align-items: center; -`; - -const StyledContainer = styled.div` - position: relative; -`; - -const StyledIconPoint = styled(IconPoint)` - margin-right: 0; -`; - export const SettingsNavigationDrawerItems = () => { - const isAdvancedModeEnabled = useRecoilValue(isAdvancedModeEnabledState); - const { - contentRef: securityRef, - motionAnimationVariants: securityAnimationVariants, - } = useExpandedAnimation(isAdvancedModeEnabled); - const { - contentRef: developersRef, - motionAnimationVariants: developersAnimationVariants, - } = useExpandedAnimation(isAdvancedModeEnabled); const { signOut } = useAuth(); const billing = useRecoilValue(billingState); @@ -198,81 +168,36 @@ export const SettingsNavigationDrawerItems = () => { Icon={IconCode} /> )} - - {isAdvancedModeEnabled && ( - - - - - - - - - )} - + + + - - {isAdvancedModeEnabled && ( - - - - - - - - - - - {isFunctionSettingsEnabled && ( - - - - - - - - )} - - + + + + + + + + {isFunctionSettingsEnabled && ( + + + )} - + {isAdminPageEnabled && ( diff --git a/packages/twenty-front/src/modules/settings/hooks/useExpandedAnimation.ts b/packages/twenty-front/src/modules/settings/hooks/useExpandedAnimation.ts deleted file mode 100644 index e87da3739..000000000 --- a/packages/twenty-front/src/modules/settings/hooks/useExpandedAnimation.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { ADVANCED_SETTINGS_ANIMATION_DURATION } from '@/settings/constants/AdvancedSettingsAnimationDurations'; -import { useEffect, useRef, useState } from 'react'; -import { isDefined } from 'twenty-ui'; - -type AnimationDimension = 'width' | 'height'; - -const getTransitionValues = (dimension: AnimationDimension) => ({ - transition: { - opacity: { duration: ADVANCED_SETTINGS_ANIMATION_DURATION.opacity }, - [dimension]: { duration: ADVANCED_SETTINGS_ANIMATION_DURATION.size }, - }, -}); - -const commonStyles = (dimension: AnimationDimension) => ({ - opacity: 0, - [dimension]: 0, - ...getTransitionValues(dimension), -}); - -const advancedSectionAnimationConfig = ( - isExpanded: boolean, - dimension: AnimationDimension, - measuredValue?: number, -) => ({ - initial: { - ...commonStyles(dimension), - }, - animate: { - opacity: 1, - [dimension]: isExpanded - ? dimension === 'width' - ? '100%' - : measuredValue - : 0, - ...getTransitionValues(dimension), - }, - exit: { - ...commonStyles(dimension), - }, -}); - -export const useExpandedAnimation = ( - isExpanded: boolean, - dimension: AnimationDimension = 'height', -) => { - const contentRef = useRef(null); - const [measuredValue, setMeasuredValue] = useState(0); - - useEffect(() => { - if (dimension === 'height' && isDefined(contentRef.current)) { - setMeasuredValue(contentRef.current.scrollHeight); - } - }, [isExpanded, dimension]); - - return { - contentRef, - motionAnimationVariants: advancedSectionAnimationConfig( - isExpanded, - dimension, - dimension === 'height' ? measuredValue : undefined, - ), - }; -}; diff --git a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/UnmatchColumn.tsx b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/UnmatchColumn.tsx index ee5eb779e..1edfc63ce 100644 --- a/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/UnmatchColumn.tsx +++ b/packages/twenty-front/src/modules/spreadsheet-import/steps/components/MatchColumnsStep/components/UnmatchColumn.tsx @@ -5,7 +5,7 @@ import { Column } from '@/spreadsheet-import/steps/components/MatchColumnsStep/M import { Fields } from '@/spreadsheet-import/types'; import styled from '@emotion/styled'; import { useState } from 'react'; -import { ExpandableContainer, isDefined } from 'twenty-ui'; +import { AnimatedExpandableContainer, isDefined } from 'twenty-ui'; const getExpandableContainerTitle = ( fields: Fields, @@ -59,7 +59,12 @@ export const UnmatchColumn = ({ buttonOnClick={() => setIsExpanded(!isExpanded)} isExpanded={isExpanded} /> - + {column.matchedOptions.map((option) => ( ({ /> ))} - + ); }; diff --git a/packages/twenty-ui/src/layout/animated-expandable-container/__stories__/AnimatedExpandableContainer.stories.tsx b/packages/twenty-ui/src/layout/animated-expandable-container/__stories__/AnimatedExpandableContainer.stories.tsx new file mode 100644 index 000000000..4bcb38976 --- /dev/null +++ b/packages/twenty-ui/src/layout/animated-expandable-container/__stories__/AnimatedExpandableContainer.stories.tsx @@ -0,0 +1,164 @@ +import styled from '@emotion/styled'; +import { Meta, StoryObj } from '@storybook/react'; +import { ComponentDecorator } from '@ui/testing'; +import { useState } from 'react'; +import { AnimatedExpandableContainer } from '../components/AnimatedExpandableContainer'; + +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 StyledButtonWrapper = styled.div<{ dimension: 'width' | 'height' }>` + ${({ dimension }) => dimension === 'height' && `width: 600px;`} + ${({ dimension }) => dimension === 'width' && `height: 300px;`} +`; + +const StyledExpandableWrapper = styled.div` + background-color: ${({ theme }) => theme.background.primary}; + height: 100%; + width: 100%; +`; + +const StyledContent = styled.div<{ + dimension: 'width' | 'height'; + mode: 'scroll-height' | 'fit-content'; +}>` + padding: ${({ theme }) => theme.spacing(3)}; + ${({ dimension, mode }) => + dimension === 'height' && mode === 'scroll-height' && `height: 200px;`} + ${({ dimension }) => dimension === 'width' && `width: 400px;`} + + p { + color: ${({ theme }) => theme.font.color.primary}; + margin-bottom: ${({ theme }) => theme.spacing(2)}; + font-size: ${({ theme }) => theme.font.size.md}; + } +`; + +type AnimatedExpandableContainerWithButtonProps = { + isExpanded: boolean; + dimension: 'width' | 'height'; + mode: 'scroll-height' | 'fit-content'; + animationDurations: + | { + opacity: number; + size: number; + } + | 'default'; +}; + +const AnimatedExpandableContainerWithButton = ({ + isExpanded: initialIsExpanded, + ...args +}: AnimatedExpandableContainerWithButtonProps) => { + const [isExpanded, setIsExpanded] = useState(initialIsExpanded); + + return ( + + setIsExpanded(!isExpanded)}> + {isExpanded ? 'Collapse' : 'Expand'} + + + + +

+ This is some content inside the AnimatedExpandableContainer. It + will animate smoothly when expanding or collapsing. +

+

+ You can control the animation duration, dimension, and mode + through the Storybook controls. +

+

+ Try different combinations to see how the container behaves with + different settings! +

+
+
+
+
+ ); +}; + +const meta: Meta = { + title: 'UI/Layout/AnimatedExpandableContainer', + component: AnimatedExpandableContainerWithButton, + decorators: [ComponentDecorator], + argTypes: { + isExpanded: { + control: 'boolean', + description: 'Controls whether the container is expanded or collapsed', + defaultValue: false, + }, + dimension: { + control: 'radio', + options: ['width', 'height'], + description: 'The dimension along which the container expands', + defaultValue: 'height', + }, + mode: { + control: 'radio', + options: ['scroll-height', 'fit-content'], + description: 'How the container should calculate its expanded size', + defaultValue: 'scroll-height', + }, + animationDurations: { + control: 'radio', + options: ['default', 'custom'], + mapping: { + default: 'default', + custom: { opacity: 0.3, size: 0.3 }, + }, + description: + 'Animation durations - either default theme values or custom values', + }, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + isExpanded: false, + dimension: 'height', + mode: 'scroll-height', + animationDurations: 'default', + }, +}; + +export const FitContent: Story = { + args: { + ...Default.args, + mode: 'fit-content', + }, +}; + +export const CustomDurations: Story = { + args: { + ...Default.args, + animationDurations: { opacity: 0.8, size: 1.2 }, + }, +}; + +export const WidthAnimation: Story = { + args: { + ...Default.args, + dimension: 'width', + }, +}; diff --git a/packages/twenty-ui/src/layout/animated-expandable-container/components/AnimatedExpandableContainer.tsx b/packages/twenty-ui/src/layout/animated-expandable-container/components/AnimatedExpandableContainer.tsx new file mode 100644 index 000000000..e0d73d323 --- /dev/null +++ b/packages/twenty-ui/src/layout/animated-expandable-container/components/AnimatedExpandableContainer.tsx @@ -0,0 +1,90 @@ +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; +import { AnimationDimension } from '@ui/layout/animated-expandable-container/types/AnimationDimension'; +import { AnimationDurationObject } from '@ui/layout/animated-expandable-container/types/AnimationDurationObject'; +import { AnimationDurations } from '@ui/layout/animated-expandable-container/types/AnimationDurations'; +import { AnimationMode } from '@ui/layout/animated-expandable-container/types/AnimationMode'; +import { AnimationSize } from '@ui/layout/animated-expandable-container/types/AnimationSize'; +import { getExpandableAnimationConfig } from '@ui/layout/animated-expandable-container/utils/getExpandableAnimationConfig'; +import { isDefined } from '@ui/utilities'; +import { AnimatePresence, motion } from 'framer-motion'; +import { ReactNode, useRef, useState } from 'react'; + +const StyledMotionContainer = styled(motion.div)<{ + containAnimation: boolean; +}>` + ${({ containAnimation }) => + containAnimation && + ` + display: flex; + flex-direction: column; + overflow: hidden; + width: 100%; + `} +`; + +type AnimatedExpandableContainerProps = { + children: ReactNode; + isExpanded: boolean; + dimension?: AnimationDimension; + animationDurations?: AnimationDurations; + mode?: AnimationMode; + containAnimation?: boolean; +}; + +export const AnimatedExpandableContainer = ({ + children, + isExpanded, + dimension = 'height', + animationDurations = 'default', + mode = 'scroll-height', + containAnimation = true, +}: AnimatedExpandableContainerProps) => { + const theme = useTheme(); + const contentRef = useRef(null); + const [size, setSize] = useState(0); + + const actualDurations: AnimationDurationObject = + animationDurations === 'default' + ? { + opacity: theme.animation.duration.normal, + size: theme.animation.duration.normal, + } + : animationDurations; + + const updateSize = () => { + if ( + mode === 'scroll-height' && + dimension === 'height' && + isDefined(contentRef.current) + ) { + setSize(contentRef.current.scrollHeight); + } + }; + + const motionAnimationVariants = getExpandableAnimationConfig( + isExpanded, + dimension, + actualDurations.opacity, + actualDurations.size, + mode === 'fit-content' ? 'fit-content' : size, + ); + + return ( + + {isExpanded && ( + + {children} + + )} + + ); +}; diff --git a/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationDimension.ts b/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationDimension.ts new file mode 100644 index 000000000..4cec5d0c7 --- /dev/null +++ b/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationDimension.ts @@ -0,0 +1 @@ +export type AnimationDimension = 'width' | 'height'; diff --git a/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationDurationObject.ts b/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationDurationObject.ts new file mode 100644 index 000000000..3867129f1 --- /dev/null +++ b/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationDurationObject.ts @@ -0,0 +1,4 @@ +export type AnimationDurationObject = { + opacity: number; + size: number; +}; diff --git a/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationDurations.ts b/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationDurations.ts new file mode 100644 index 000000000..8c85746d5 --- /dev/null +++ b/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationDurations.ts @@ -0,0 +1,3 @@ +import { AnimationDurationObject } from '@ui/layout/animated-expandable-container/types/AnimationDurationObject'; + +export type AnimationDurations = AnimationDurationObject | 'default'; diff --git a/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationMode.ts b/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationMode.ts new file mode 100644 index 000000000..e7acddfee --- /dev/null +++ b/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationMode.ts @@ -0,0 +1 @@ +export type AnimationMode = 'scroll-height' | 'fit-content'; diff --git a/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationSize.ts b/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationSize.ts new file mode 100644 index 000000000..c1824a054 --- /dev/null +++ b/packages/twenty-ui/src/layout/animated-expandable-container/types/AnimationSize.ts @@ -0,0 +1 @@ +export type AnimationSize = number | 'fit-content'; diff --git a/packages/twenty-ui/src/layout/animated-expandable-container/utils/getCommonStyles.ts b/packages/twenty-ui/src/layout/animated-expandable-container/utils/getCommonStyles.ts new file mode 100644 index 000000000..4299e7163 --- /dev/null +++ b/packages/twenty-ui/src/layout/animated-expandable-container/utils/getCommonStyles.ts @@ -0,0 +1,12 @@ +import { AnimationDimension } from '@ui/layout/animated-expandable-container/types/AnimationDimension'; +import { getTransitionValues } from '@ui/layout/animated-expandable-container/utils/getTransitionValues'; + +export const getCommonStyles = ( + dimension: AnimationDimension, + opacityDuration: number, + sizeDuration: number, +) => ({ + opacity: 0, + [dimension]: 0, + ...getTransitionValues(dimension, opacityDuration, sizeDuration), +}); diff --git a/packages/twenty-ui/src/layout/animated-expandable-container/utils/getExpandableAnimationConfig.ts b/packages/twenty-ui/src/layout/animated-expandable-container/utils/getExpandableAnimationConfig.ts new file mode 100644 index 000000000..5a0003bdc --- /dev/null +++ b/packages/twenty-ui/src/layout/animated-expandable-container/utils/getExpandableAnimationConfig.ts @@ -0,0 +1,30 @@ +import { AnimationDimension } from '@ui/layout/animated-expandable-container/types/AnimationDimension'; +import { AnimationSize } from '@ui/layout/animated-expandable-container/types/AnimationSize'; +import { getCommonStyles } from '@ui/layout/animated-expandable-container/utils/getCommonStyles'; +import { getTransitionValues } from '@ui/layout/animated-expandable-container/utils/getTransitionValues'; + +export const getExpandableAnimationConfig = ( + isExpanded: boolean, + dimension: AnimationDimension, + opacityDuration: number, + sizeDuration: number, + size: AnimationSize, +) => ({ + initial: { + ...getCommonStyles(dimension, opacityDuration, sizeDuration), + }, + animate: { + opacity: 1, + [dimension]: isExpanded + ? size === 'fit-content' + ? 'fit-content' + : dimension === 'width' + ? '100%' + : size + : 0, + ...getTransitionValues(dimension, opacityDuration, sizeDuration), + }, + exit: { + ...getCommonStyles(dimension, opacityDuration, sizeDuration), + }, +}); diff --git a/packages/twenty-ui/src/layout/animated-expandable-container/utils/getTransitionValues.ts b/packages/twenty-ui/src/layout/animated-expandable-container/utils/getTransitionValues.ts new file mode 100644 index 000000000..053c1f08c --- /dev/null +++ b/packages/twenty-ui/src/layout/animated-expandable-container/utils/getTransitionValues.ts @@ -0,0 +1,18 @@ +import { AnimationDimension } from '@ui/layout/animated-expandable-container/types/AnimationDimension'; + +export const getTransitionValues = ( + dimension: AnimationDimension, + opacityDuration: number, + sizeDuration: number, +) => ({ + transition: { + opacity: { + duration: opacityDuration, + ease: 'easeInOut', + }, + [dimension]: { + duration: sizeDuration, + ease: 'easeInOut', + }, + }, +}); diff --git a/packages/twenty-ui/src/layout/expandableContainer/components/ExpandableContainer.tsx b/packages/twenty-ui/src/layout/expandableContainer/components/ExpandableContainer.tsx deleted file mode 100644 index aff789f57..000000000 --- a/packages/twenty-ui/src/layout/expandableContainer/components/ExpandableContainer.tsx +++ /dev/null @@ -1,42 +0,0 @@ -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(null); - - useLayoutEffect(() => { - if (isDefined(contentRef.current)) { - setContentHeight(contentRef.current.scrollHeight); - } - }, [isExpanded]); - - return ( - -
{children}
-
- ); -}; - -export default ExpandableContainer; diff --git a/packages/twenty-ui/src/layout/expandableContainer/components/__stories__/ExpandableContainer.stories.tsx b/packages/twenty-ui/src/layout/expandableContainer/components/__stories__/ExpandableContainer.stories.tsx deleted file mode 100644 index 66c0915b4..000000000 --- a/packages/twenty-ui/src/layout/expandableContainer/components/__stories__/ExpandableContainer.stories.tsx +++ /dev/null @@ -1,81 +0,0 @@ -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 ( -
- setIsExpanded(!isExpanded)}> - {isExpanded ? 'Collapse' : 'Expand'} - - - -

- This is some content inside the ExpandableContainer. It will grow - and shrink depending on the expand/collapse state. -

-

- Add more text or even other components here to test how the - container handles more content. -

-

- Feel free to adjust the height and content to see how it affects the - expand/collapse behavior. -

-
-
-
- ); -}; - -const meta: Meta = { - 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; - -export const Default: Story = { - args: { - isExpanded: false, - }, -}; diff --git a/packages/twenty-ui/src/layout/index.ts b/packages/twenty-ui/src/layout/index.ts index a2f333052..1f88712f8 100644 --- a/packages/twenty-ui/src/layout/index.ts +++ b/packages/twenty-ui/src/layout/index.ts @@ -1,3 +1,4 @@ +export * from './animated-expandable-container/components/AnimatedExpandableContainer'; export * from './animated-placeholder/components/AnimatedPlaceholder'; export * from './animated-placeholder/components/EmptyPlaceholderStyled'; export * from './animated-placeholder/components/ErrorPlaceholderStyled'; @@ -9,5 +10,4 @@ export * from './card/components/Card'; export * from './card/components/CardContent'; export * from './card/components/CardFooter'; export * from './card/components/CardHeader'; -export * from './expandableContainer/components/ExpandableContainer'; export * from './section/components/Section';