Skip to content

Commit

Permalink
feat(UI): improve Sections component
Browse files Browse the repository at this point in the history
1- Allow multiple sections to be opened simultaneously.
2- `Add matchContentHeight` property (default: false), enabling sections to automatically adjust their height based on the content instead of the parent's available height.
3- Introduce `leftElement`, similar to `rightElement`, for rendering custom elements on the left side of the section header.
  • Loading branch information
hamed-musallam committed Oct 23, 2024
1 parent c807446 commit 8656ef1
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 25 deletions.
61 changes: 37 additions & 24 deletions src/component/elements/Sections.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ const Container = styled.div<{ overflow: boolean }>(
`,
);

const SectionWrapper = styled.div<ActiveProps>(
({ isOpen, overflow }) => `
const SectionWrapper = styled.div<
ActiveProps & { matchContentHeight: boolean }
>(
({ isOpen, overflow, matchContentHeight }) => `
display: flex;
flex-direction: column;
flex: ${isOpen ? (overflow ? '1' : overflow ? '1' : '1 1 1px') : 'none'};
flex:none;
flex: ${isOpen && !matchContentHeight ? (overflow ? '1' : overflow ? '1' : '1 1 1px') : 'none'};
`,
);

Expand Down Expand Up @@ -88,12 +91,10 @@ const OpenIcon = styled(Icon)<ActiveProps>`
const ContentWrapper = styled.div<ActiveProps>(
({ isOpen, overflow }) => `
background-color: white;
// overflow: hidden;
display: ${isOpen ? 'flex' : 'none'};
flex: ${isOpen ? (overflow ? '1' : '1 1 1px') : 'none'};
max-height: 100%;
flex-direction:column;
`,
);
const Content = styled.div`
Expand All @@ -104,7 +105,7 @@ const Content = styled.div`
flex-direction: column;
padding: 10px;
`;
const RightElementsContainer = styled.div`
const ElementsContainer = styled.div`
display: flex;
align-items: center;
`;
Expand Down Expand Up @@ -136,15 +137,17 @@ interface BaseSectionProps {
title: string;
serial?: number;
rightElement?: ReactNode | ((isOpen) => ReactNode);
leftElement?: ReactNode | ((isOpen) => ReactNode);
headerStyle?: CSSProperties;
}

interface SectionItemProps extends BaseSectionProps {
id?: string;
onClick?: (id, event?: MouseEvent<HTMLDivElement>) => void;
children?: ReactNode | ((options: { isOpen?: boolean }) => ReactNode);
selectedSectionId?: string;
isOpen: boolean;
sticky?: boolean;
matchContentHeight?: boolean;
}

interface SectionProps {
Expand Down Expand Up @@ -188,46 +191,48 @@ function SectionItem(props: SectionItemProps) {
onClick,
serial,
rightElement,
leftElement,
children,
selectedSectionId,
headerStyle,
isOpen,
sticky = false,
matchContentHeight = false,
} = props;

const isOpen = selectedSectionId === id;
const { overflow } = useSections();

return (
<SectionWrapper isOpen={isOpen} overflow={overflow}>
<SectionWrapper
isOpen={isOpen}
overflow={overflow}
matchContentHeight={matchContentHeight}
>
<MainSectionHeader
title={title}
isOpen={isOpen}
onClick={(event) => onClick?.(id, event)}
serial={serial}
rightElement={rightElement}
leftElement={leftElement}
headerStyle={headerStyle}
sticky={sticky}
/>
<Wrapper isOpen={isOpen} id={id} selectedSectionId={selectedSectionId}>
{children}
</Wrapper>
<Wrapper isOpen={isOpen}>{children}</Wrapper>
</SectionWrapper>
);
}

interface WrapperProps {
children: ReactNode | ((options: { isOpen?: boolean }) => ReactNode);
isOpen: boolean;
id: string;
selectedSectionId?: string;
}

function Wrapper(props: WrapperProps) {
const { overflow, renderActiveSectionContentOnly } = useSections();

const { children, isOpen, selectedSectionId, id } = props;
const { children, isOpen } = props;

if (renderActiveSectionContentOnly && id !== selectedSectionId) {
if (renderActiveSectionContentOnly && !isOpen) {
return null;
}

Expand All @@ -252,6 +257,7 @@ function MainSectionHeader(props: MainSectionHeaderProps) {
onClick,
serial,
rightElement,
leftElement,
headerStyle = {},
sticky,
} = props;
Expand All @@ -268,19 +274,26 @@ function MainSectionHeader(props: MainSectionHeaderProps) {
}}
>
<TitleContainer>
<Active round isOpen={isOpen}>
{serial}
</Active>
{typeof serial === 'number' && (
<Active round isOpen={isOpen}>
{serial}
</Active>
)}
<ElementsContainer onClick={(event) => event.stopPropagation()}>
{typeof leftElement === 'function'
? leftElement(isOpen)
: leftElement}
</ElementsContainer>
<Title>{title}</Title>
</TitleContainer>
<RightElementsContainer>
<RightElementsContainer onClick={(event) => event.stopPropagation()}>
<ElementsContainer>
<ElementsContainer onClick={(event) => event.stopPropagation()}>
{typeof rightElement === 'function'
? rightElement(isOpen)
: rightElement}
</RightElementsContainer>
</ElementsContainer>
<OpenIcon icon="chevron-right" isOpen={isOpen} />
</RightElementsContainer>
</ElementsContainer>
</Header>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ function FiltersInner(props: FiltersInnerProps) {
onClick={(id) => {
toggleSection(id);
}}
selectedSectionId={selectedSection}
isOpen={name === selectedSection}
rightElement={
<FilterElements
filter={filter}
Expand Down

0 comments on commit 8656ef1

Please sign in to comment.