Skip to content

Commit

Permalink
Merge pull request #463 from AppQuality/UN-538-new-accordion
Browse files Browse the repository at this point in the history
Un 538 new accordion
  • Loading branch information
d-beezee authored Dec 18, 2024
2 parents 840cd43 + 90ce951 commit d689caf
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { GlobalStyle } from "./stories/shared/globalStyle";

// --- Accordions ---
export * from "./stories/accordions";
export * from "./stories/accordion-new";

// --- Alerts ---
export * from "./stories/notifications/alerts";
Expand Down
68 changes: 68 additions & 0 deletions src/stories/accordion-new/AccordionHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Accordion as ZendeskAccordion } from "@zendeskgarden/react-accordions";
import { Checkbox, Field, Label } from "@zendeskgarden/react-forms";
import { forwardRef, useEffect, useState } from "react";
import styled from "styled-components";
import { theme } from "../theme";

export interface AccordionHeaderArgs extends React.HTMLAttributes<HTMLDivElement> {
hasCheckbox?: boolean;
checkboxProps?: React.ComponentProps<typeof Checkbox>;
isSelected?: boolean;
isLarge?: boolean;
icon?: React.ReactNode;
}

const StyledAccordionHeader = styled(ZendeskAccordion.Header)`
padding: ${theme.space.md};
display: flex;
gap: ${theme.space.xs};
align-items: flex-start;
[data-garden-id="accordions.rotate_icon"] {
padding: 0;
}
.accordion-header-inner-wrapper {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: ${theme.space.xs};
width: 100%;
}
`;

export const AccordionHeader = forwardRef<HTMLDivElement, AccordionHeaderArgs>(({
children,
isSelected,
hasCheckbox,
checkboxProps,
icon,
...rest
}, ref) => {
const handleCheckboxChange = (e: React.ChangeEvent<HTMLInputElement>) => {
e.stopPropagation();
if (typeof checkboxProps?.onChange === "function") {
checkboxProps.onChange(e);
}
return false;
}

return (
<StyledAccordionHeader ref={ref} {...rest}>
{hasCheckbox &&
<Field onChange={handleCheckboxChange}>
<Checkbox
{...checkboxProps}
onChange={handleCheckboxChange}
>
{checkboxProps?.["aria-label"]}
<Label hidden>
{checkboxProps?.["aria-label"]}
</Label>
</Checkbox>
</Field>}
{icon}
<div className="accordion-header-inner-wrapper">
{children}
</div>
</StyledAccordionHeader>
)
});
40 changes: 40 additions & 0 deletions src/stories/accordion-new/AccordionLabel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Accordion as ZendeskAccordion } from "@zendeskgarden/react-accordions";
import { forwardRef} from "react";
import { theme } from "../theme";
import styled from "styled-components";
import { LG, MD, SM } from "../typography/typescale";

interface AccordionLabelArgs extends React.HTMLAttributes<HTMLDivElement> {
isLarge?: boolean;
label?: string;
subtitle?: string;
supertitle?: string;
meta?: React.ReactNode;
}
const StyledAccordionLabel = styled(ZendeskAccordion.Label)<AccordionLabelArgs>`
padding: 0;
width: auto;
flex-grow: 1;
`;

export const AccordionLabel = forwardRef<HTMLButtonElement, AccordionLabelArgs>(({
label,
supertitle,
subtitle,
isLarge,
...rest
}, ref) => (
<StyledAccordionLabel ref={ref} {...rest}>
{supertitle && <SM color={theme.palette.grey[700]} style={{marginBottom: theme.space.xxs}}>{supertitle}</SM>}
{label &&
isLarge
? <LG isBold style={{marginBottom: theme.space.xxs}}>{label}</LG>
: <SM isBold style={{marginBottom: theme.space.xxs}}>{label}</SM>
}
{subtitle &&
isLarge
? <MD color={theme.palette.grey[600]} style={{marginBottom: theme.space.xs}}>{subtitle}</MD>
: <SM color={theme.palette.grey[600]} style={{marginBottom: theme.space.xs}}>{subtitle}</SM>
}
</StyledAccordionLabel>
));
16 changes: 16 additions & 0 deletions src/stories/accordion-new/AccordionMeta.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { forwardRef} from "react";
import styled from "styled-components";

interface AccordionMetaArgs extends React.HTMLAttributes<HTMLDivElement> {
}
const StyledAccordionMeta = styled.div<AccordionMetaArgs>`
`;

export const AccordionMeta = forwardRef<HTMLDivElement, AccordionMetaArgs>(({
children,
...rest
}, ref) => (
<StyledAccordionMeta ref={ref} {...rest}>
{children}
</StyledAccordionMeta>
));
19 changes: 19 additions & 0 deletions src/stories/accordion-new/AccordionSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Accordion as ZendeskAccordion } from "@zendeskgarden/react-accordions";
import { Checkbox, Field, Label } from "@zendeskgarden/react-forms";
import { forwardRef } from "react";
import styled from "styled-components";

export interface AccordionSectionArgs extends React.HTMLAttributes<HTMLDivElement> {
isSelected?: boolean;
}

export const AccordionSection = forwardRef<HTMLDivElement, AccordionSectionArgs>(({
children,
isSelected,
className,
...rest
}, ref) => (
<ZendeskAccordion.Section ref={ref} className={`${className} ${isSelected ? 'isSelected' : ''}`} {...rest}>
{children}
</ZendeskAccordion.Section>
));
66 changes: 66 additions & 0 deletions src/stories/accordion-new/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Meta, StoryObj } from "@storybook/react";
import { AccordionArgs, AccordionNew } from ".";
import { Placeholder } from "../placeholder";

const accordionContent = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

const items = [
{
accordionContent,
headerTitle: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, Equum cibum est optimum prandium est",
},
{
accordionContent,
headerTitle: "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
},
{
accordionContent,
headerTitle: "Lorem ipsum dolor sit amet",
},
];

type StoryArgs = AccordionArgs & {};

const meta = {
title: "Molecules/New Accordion",
component: AccordionNew,

render: ({ ...args }) => {
return (

<AccordionNew {...args}>
{items.map((item) => {
return (
<AccordionNew.Section>
<AccordionNew.Header>
<AccordionNew.Label label={item.headerTitle} />
</AccordionNew.Header>
<AccordionNew.Panel><Placeholder /></AccordionNew.Panel>
</AccordionNew.Section>
)
})}
</AccordionNew>
);
},
} satisfies Meta<StoryArgs>;

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

const defaultArgs: StoryArgs = {
level: 3,
isBare: false
};

export const Default: Story = {
args: {
...defaultArgs,
},
};

export const Bare: Story = {
args: {
...defaultArgs,
isBare: true,
},
};
37 changes: 37 additions & 0 deletions src/stories/accordion-new/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Accordion as ZendeskAccordion } from "@zendeskgarden/react-accordions";
import { forwardRef } from "react";
import { IAccordionProps } from "@zendeskgarden/react-accordions";
import { AccordionHeader } from "./AccordionHeader";
import { AccordionSection } from "./AccordionSection";
import { AccordionLabel } from "./AccordionLabel";
import { AccordionMeta } from "./AccordionMeta";

export interface AccordionArgs extends IAccordionProps {
}

/**
* Accordions are headers that can be expanded to reveal content or collapsed to hide it.
* <hr>
* Used for this:
- To organize related information into sections
- To surface information through progressive disclosure
*/
const AccordionComponent = forwardRef<HTMLDivElement, AccordionArgs>((props, ref) => (
<ZendeskAccordion ref={ref} {...props} />
));



export const AccordionNew = AccordionComponent as typeof AccordionComponent & {
Section: typeof AccordionSection;
Header: typeof AccordionHeader;
Label: typeof AccordionLabel;
Meta: typeof AccordionMeta;
Panel: typeof ZendeskAccordion.Panel;
};

AccordionNew.Section = AccordionSection;
AccordionNew.Header = AccordionHeader;
AccordionNew.Label = AccordionLabel;
AccordionNew.Meta = AccordionMeta;
AccordionNew.Panel = ZendeskAccordion.Panel;
112 changes: 112 additions & 0 deletions src/stories/accordion-new/section.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { Meta, StoryObj } from "@storybook/react";
import { AccordionNew } from ".";
import { Checkbox } from "../forms/checkbox";
import React from "react";
import { ReactComponent as FolderIcon } from "@zendeskgarden/svg-icons/src/16/folder-open-stroke.svg";
import { Placeholder } from "../placeholder";
import { AccordionSectionArgs } from "./AccordionSection";


type StoryArgs = AccordionSectionArgs & {
hasCheckbox?: boolean;
selected?: boolean;
checkboxProps?: React.ComponentProps<typeof Checkbox>;
icon?: React.ReactNode;
isLarge?: boolean;
hasSubtitles?: boolean;
hasSupertitles?: boolean;
hasMeta?: boolean;
isOpen?: boolean;
};

const meta = {
title: "Molecules/New Accordion/Section",
component: AccordionNew.Section,
decorators: [
(Story: React.ComponentType, context) => {
return(
<AccordionNew level={3} expandedSections={context.args.isOpen ? [0] : []}>
<Story />
</AccordionNew>
)},
],
render: ({ ...args }) => {
return (
<AccordionNew.Section isSelected={args.selected}>
<AccordionNew.Header
hasCheckbox={args.hasCheckbox}
icon={args.icon}
>
<AccordionNew.Label isLarge={args.isLarge}
label="Lorem ipsum dolor sit amet, consectetur adipiscing elit, Equum cibum est optimum prandium est"
subtitle={args.hasSubtitles ? "Some more info on the item" : ""}
supertitle={args.hasSupertitles ? "00:00:23 - 00:00:27" : ""}
meta
/>
{args.hasMeta && <AccordionNew.Meta>
<Placeholder />
</AccordionNew.Meta>}
</AccordionNew.Header>
<AccordionNew.Panel><Placeholder /></AccordionNew.Panel>
</AccordionNew.Section>

);
},
} satisfies Meta<StoryArgs>;

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

const defaultArgs: StoryArgs = {
hasCheckbox: false,
isLarge: false,
hasSubtitles: false,
hasSupertitles: false,
hasMeta: false,
isOpen: false,
};

export const Default: Story = {
args: {
...defaultArgs,
},
};

export const Large: Story = {
args: {
...defaultArgs,
isLarge: true,
},
};

export const Selectable: Story = {
args: {
...defaultArgs,
hasCheckbox: true,
},
};

export const Icon: Story = {
args: {
...defaultArgs,
icon: <FolderIcon />,
},
};

export const WithMeta: Story = {
args: {
...defaultArgs,
hasMeta: true,
},
};

export const Full: Story = {
args: {
...defaultArgs,
icon: <FolderIcon />,
hasCheckbox: true,
hasSubtitles: true,
hasSupertitles: true,
hasMeta: true,
},
};

0 comments on commit d689caf

Please sign in to comment.