Skip to content

Commit

Permalink
feat: add Expander component
Browse files Browse the repository at this point in the history
  • Loading branch information
jamiehenson committed Apr 19, 2024
1 parent 9273a09 commit 64a4085
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 0 deletions.
46 changes: 46 additions & 0 deletions src/core/Expander.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React, { PropsWithChildren, useEffect, useRef, useState } from "react";

type ExpanderProps = {
height?: number;
};

const Expander = ({
height = 200,
children,
}: PropsWithChildren<ExpanderProps>) => {
const innerRef = useRef<HTMLDivElement>(null);
const [contentHeight, setContentHeight] = useState(height);
const [expanded, setExpanded] = useState(false);

useEffect(() => {
setContentHeight(innerRef.current?.clientHeight ?? height);
}, [height, expanded]);

const showControls = contentHeight > height;

return (
<>
<div
style={{ height: expanded ? contentHeight : height }}
className="overflow-hidden transition-all relative"
>
{showControls && !expanded && (
<div className="h-64 w-full bg-gradient-to-t from-white to-transparent absolute bottom-0"></div>
)}
<div ref={innerRef}>{children}</div>
</div>
{showControls && (
<div
onClick={() => setExpanded(!expanded)}
onKeyDown={(e) => e.key === "Enter" && setExpanded(!expanded)}
tabIndex={0}
className="mt-16 cursor-pointer font-bold text-gui-blue-default-light hover:text-gui-blue-hover-light active:text-gui-blue-active-light focus:text-gui-blue-focus"
>
{expanded ? "View less -" : "View all +"}
</div>
)}
</>
);
};

export default Expander;
118 changes: 118 additions & 0 deletions src/core/Expander/Expander.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React from "react";
import Expander from "../Expander";

export default {
title: "Components/Expander",
component: Expander,
tags: ["autodocs"],
args: {
height: 200,
},
argTypes: {
height: {
control: {
type: "number",
},
},
},
};

export const LongContent = {
render: () => (
<Expander>
<div>
<p>Ipsum</p>
<ul className="mb-16 list-inside list-disc">
<li>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</li>
<li>
Sed convallis ex pharetra, tristique tellus vel, rhoncus velit.
</li>
<li>Mauris molestie felis et scelerisque ullamcorper.</li>
<li>Maecenas congue ligula ut commodo tristique.</li>
<li>
Pellentesque venenatis elit vitae urna condimentum, in mollis arcu
venenatis.
</li>
<li>Donec nec turpis vel urna egestas fringilla.</li>
</ul>
<p>Ipsum</p>
<ul className="mb-16 list-inside list-disc">
<li>Mauris ut nibh vel metus cursus semper.</li>
<li>Ut mattis tortor eu urna accumsan gravida.</li>
<li>Nunc pellentesque neque at elit pretium tempor.</li>
<li>Curabitur finibus magna vitae nunc varius fermentum.</li>
</ul>
<ul className="mb-16 list-inside list-disc">
<li>
Curabitur vehicula mi iaculis, luctus augue eu, venenatis quam.
</li>
<li>Praesent in eros efficitur, consequat ante eu, faucibus arcu.</li>
<li>Nulla laoreet nibh a odio interdum, non molestie diam auctor.</li>
</ul>
<p>Ipsum</p>
<ul className="mb-16 list-inside list-disc">
<li>
Praesent aliquam diam tincidunt, sollicitudin tortor eget, vulputate
lacus.
</li>
<li>Quisque in mi sed ex vulputate varius in a leo.</li>
<li>Etiam posuere dolor at tortor aliquam imperdiet.</li>
<li>
Maecenas quis neque consequat, ultricies est sit amet, congue est.
</li>
<li>Aenean a elit sed nibh pretium lacinia sed convallis sapien.</li>
</ul>
<p>Ipsum</p>
<ul className="mb-16 list-inside list-disc">
<li>
Nulla malesuada libero id dolor aliquam, non sagittis mi
scelerisque.
</li>
<li>
Etiam tincidunt lacus eu diam laoreet consectetur sit amet non est.
</li>
<li>In porta arcu nec purus tincidunt vulputate.</li>
</ul>
</div>
</Expander>
),
parameters: {
docs: {
description: {
story:
"A larger amount of content that exceeds the height cut-off, controls shown.",
},
},
},
};

export const ShortContent = {
render: () => (
<Expander>
<div>
<p>Ipsum</p>
<ul className="mb-16 list-inside list-disc">
<li>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</li>
<li>
Sed convallis ex pharetra, tristique tellus vel, rhoncus velit.
</li>
<li>Mauris molestie felis et scelerisque ullamcorper.</li>
<li>Maecenas congue ligula ut commodo tristique.</li>
<li>
Pellentesque venenatis elit vitae urna condimentum, in mollis arcu
venenatis.
</li>
<li>Donec nec turpis vel urna egestas fringilla.</li>
</ul>
</div>
</Expander>
),
parameters: {
docs: {
description: {
story:
"A smaller amount of content that doesn't exceed the height cut-off, therefore no controls shown.",
},
},
},
};

0 comments on commit 64a4085

Please sign in to comment.