Skip to content

Commit

Permalink
chore: Accordion
Browse files Browse the repository at this point in the history
  • Loading branch information
Seedy authored Jan 18, 2022
1 parent 7b9288b commit e245717
Show file tree
Hide file tree
Showing 8 changed files with 425 additions and 1 deletion.
91 changes: 91 additions & 0 deletions components/Accordion/Accordion.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { ComponentMeta, ComponentStory } from '@storybook/react';
import React from 'react';
import { AccordionRoot, AccordionItem, AccordionTrigger, AccordionContent } from '.';
import { modifyVariantsForStory } from '../../utils/modifyVariantsForStory';
import { VariantProps } from '../../stitches.config';

import { Badge } from '../Badge';
import { Text } from '../Text';
import { Card } from '../Card';
import { Flex } from '../Flex';
import { MagnifyingGlassIcon } from '@radix-ui/react-icons'

type AccordionVariants = VariantProps<typeof AccordionRoot>

const BaseAccordion = (props: any): JSX.Element => <AccordionRoot {...props} />;
const AccordionForStory = modifyVariantsForStory<AccordionVariants, any>(BaseAccordion);

export default {
title: 'Components/Accordion',
component: AccordionForStory,
} as ComponentMeta<typeof AccordionForStory>;

const Template: ComponentStory<typeof AccordionForStory> = (args) => (
<Card css={{ width: 300 }}>
<AccordionForStory {...args}>
<AccordionItem value="item-1">
<AccordionTrigger>Item1 Trigger</AccordionTrigger>
<AccordionContent>Item1 Content</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>Item2 Trigger</AccordionTrigger>
<AccordionContent>Item2 Content</AccordionContent>
</AccordionItem>
</AccordionForStory>
</Card>
)

export const Single = Template.bind({});
Single.args = {
type: 'single',
};

export const Collapsible = Template.bind({});
Collapsible.args = {
type: 'single',
collapsible: true,
}

export const MultipleCollapsible = Template.bind({});
MultipleCollapsible.args = {
type: 'multiple',
collapsible: true,
};


export const Complex
: ComponentStory<typeof AccordionForStory> = (args) => (
<Card css={{ width: 300 }}>
<AccordionForStory {...args}>
<AccordionItem value="item-1">
<AccordionTrigger>
<Flex
css={{ flexGrow: 1 }}
align="center"
justify="space-between"
>
<Text>Title</Text>
<Badge>Status</Badge>
<Text>Metadata</Text>
</Flex>
</AccordionTrigger>
<AccordionContent>
<Flex gap="2">
<MagnifyingGlassIcon />
<Text>More information</Text>
<Text>Version</Text>
</Flex>
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>Item2 Trigger</AccordionTrigger>
<AccordionContent>Item2 Content</AccordionContent>
</AccordionItem>
</AccordionForStory>
</Card>
)

Complex.args = {
type: 'multiple',
collapsible: true,
};
25 changes: 25 additions & 0 deletions components/Accordion/Accordion.themes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Property } from '@stitches/react/types/css';
import { ColorInfo } from '../../utils/getPrimaryColorInfo';
import tinycolor from 'tinycolor2';

export namespace Theme {
type Colors = {
accordionBackground: Property.Color;
accordionHoverShadow: Property.Color;
accordionActiveShadow: Property.Color;
};

type Factory = (primaryColor: ColorInfo) => Colors;

export const getLight: Factory = () => ({
accordionBackground: 'white',
accordionHoverShadow: tinycolor('black').setAlpha(0.05).toHslString(),
accordionActiveShadow: tinycolor('black').setAlpha(0.2).toHslString(),
});

export const getDark: Factory = () => ({
accordionBackground: '$deepBlue2',
accordionHoverShadow: tinycolor('white').setAlpha(0.05).toHslString(),
accordionActiveShadow: tinycolor('white').setAlpha(0.2).toHslString(),
});
}
114 changes: 114 additions & 0 deletions components/Accordion/Accordion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React from 'react';
import * as AccordionPrimitive from '@radix-ui/react-accordion';
import { keyframes, styled } from '../../stitches.config';
import { elevationVariants } from '../Elevation';
import { ChevronRightIcon } from '@radix-ui/react-icons';

const open = keyframes({
from: { height: 0 },
to: { height: 'var(--radix-accordion-content-height)' },
});

const close = keyframes({
from: { height: 'var(--radix-accordion-content-height)' },
to: { height: 0 },
});

const StyledAccordionRoot = styled(AccordionPrimitive.Root, {
borderRadius: '$3',
bc: 'transparent',
variants: {
elevation: elevationVariants,
},
defaultVariants: {
elevation: 0,
},
});

const StyledAccordionItem = styled(AccordionPrimitive.Item, {
mt: '$1',
borderRadius: '$3',
'&:first-child': {
mt: 0,
},
})

const StyledAccordionHeader = styled(AccordionPrimitive.Header, {
all: 'unset',
display: 'flex',
borderRadius: 'inherit'
});

const StyledAccordionTrigger = styled(AccordionPrimitive.Trigger, {
all: 'unset',
borderRadius: 'inherit',
fontFamily: 'inherit',
bc: '$accordionBackground',
c: '$textDefault',
p: '$2',
lineHeight: 1,
fontSize: '$3',
display: 'flex',
flex: 1,
alignItems: 'center',
justifyContent: 'space-between',
position: 'relative',
'&::before': {
borderRadius: 'inherit',
boxSizing: 'border-box',
content: '""',
position: 'absolute',
inset: 0,
},
'&:focus': {
boxShadow: 'inset 0 0 0 1px $colors$accordionActiveShadow',
},
'@hover': {
'&:hover': {
cursor: 'pointer',
'&::before': {
backgroundColor: '$accordionHoverShadow',
}
},
},
});

const StyledAccordionChevron = styled(ChevronRightIcon, {
transition: 'transform 200ms ease-out',
'[data-state=open] &': { transform: 'rotateZ(90deg)' },
});

const StyledAccordionContent = styled(AccordionPrimitive.Content, {
overflow: 'hidden',
fontSize: '$3',
c: '$textDefault',
'&[data-state="open"]': {
animation: `${open} 200ms ease-out`,
},
'&[data-state="closed"]': {
animation: `${close} 200ms ease-out`
},
});

const StyledAccordionContentWrapper = styled('div', {
p: '$2',
});

// EXPORTS
export const AccordionRoot = StyledAccordionRoot;
export const AccordionItem = StyledAccordionItem;
export const AccordionTrigger = React.forwardRef<
React.ElementRef<typeof StyledAccordionTrigger>, any>(({ children, ...props }, forwardedRef) => (
<StyledAccordionHeader>
<StyledAccordionTrigger ref={forwardedRef} {...props}>
<StyledAccordionChevron aria-hidden />
{children}
</StyledAccordionTrigger>
</StyledAccordionHeader>
));
export const AccordionContent = React.forwardRef<React.ElementRef<typeof StyledAccordionContent>, any>(({ children, ...props }, forwardedRef) => (
<StyledAccordionContent {...props} ref={forwardedRef}>
<StyledAccordionContentWrapper>{children}</StyledAccordionContentWrapper>
</StyledAccordionContent>
));;

1 change: 1 addition & 0 deletions components/Accordion/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Accordion';
1 change: 1 addition & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { AccordionRoot, AccordionItem, AccordionTrigger, AccordionContent } from './components/Accordion';
export { Alert } from './components/Alert';
export { AspectRatio } from '@radix-ui/react-aspect-ratio';
export { Badge } from './components/Badge';
Expand Down
Loading

0 comments on commit e245717

Please sign in to comment.