This commit is contained in:
DCCONSTRUCTIONS
2026-04-18 18:39:25 +03:00
commit 3ba092b60c
4944 changed files with 497564 additions and 0 deletions
@@ -0,0 +1,204 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import type { Meta, StoryObj } from "@storybook/react-vite";
import { Accordion } from "./accordion";
const meta = {
title: "Components/Accordion",
component: Accordion.Root,
parameters: {
layout: "centered",
controls: { disable: true },
},
tags: ["autodocs"],
subcomponents: {
Item: Accordion.Item,
Trigger: Accordion.Trigger,
Content: Accordion.Content,
},
args: {
children: null,
},
} satisfies Meta<typeof Accordion.Root>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render() {
return (
<Accordion.Root className="w-96">
<Accordion.Item value="item-1">
<Accordion.Trigger>What is Plane?</Accordion.Trigger>
<Accordion.Content>
Plane is an open-source project management tool designed for developers and teams to plan, track, and manage
their work efficiently.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-2">
<Accordion.Trigger>How do I get started?</Accordion.Trigger>
<Accordion.Content>
You can get started by signing up for an account, creating your first workspace, and inviting your team
members to collaborate.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-3">
<Accordion.Trigger>Is it free to use?</Accordion.Trigger>
<Accordion.Content>
Plane offers both free and paid plans. The free plan includes essential features for small teams, while paid
plans unlock advanced functionality.
</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
);
},
};
export const SingleOpen: Story = {
render() {
return (
<Accordion.Root defaultValue={["item-1"]} className="w-96">
<Accordion.Item value="item-1">
<Accordion.Trigger>Section 1</Accordion.Trigger>
<Accordion.Content>Content for section 1. Only one section can be open at a time.</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-2">
<Accordion.Trigger>Section 2</Accordion.Trigger>
<Accordion.Content>Content for section 2.</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-3">
<Accordion.Trigger>Section 3</Accordion.Trigger>
<Accordion.Content>Content for section 3.</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
);
},
};
export const AllowMultiple: Story = {
render() {
return (
<Accordion.Root allowMultiple defaultValue={["item-1", "item-2"]} className="w-96">
<Accordion.Item value="item-1">
<Accordion.Trigger>First Section</Accordion.Trigger>
<Accordion.Content>Multiple sections can be open at the same time.</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-2">
<Accordion.Trigger>Second Section</Accordion.Trigger>
<Accordion.Content>This section is also open by default.</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-3">
<Accordion.Trigger>Third Section</Accordion.Trigger>
<Accordion.Content>You can open this section while keeping the others open.</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
);
},
};
export const WithDisabledItem: Story = {
render() {
return (
<Accordion.Root className="w-96">
<Accordion.Item value="item-1">
<Accordion.Trigger>Enabled Section</Accordion.Trigger>
<Accordion.Content>This section can be toggled.</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-2" disabled>
<Accordion.Trigger>Disabled Section</Accordion.Trigger>
<Accordion.Content>This content cannot be accessed.</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-3">
<Accordion.Trigger>Another Enabled Section</Accordion.Trigger>
<Accordion.Content>This section can also be toggled.</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
);
},
};
export const CustomIcon: Story = {
render() {
return (
<Accordion.Root className="w-96">
<Accordion.Item value="item-1">
<Accordion.Trigger
icon={
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="transition-transform group-data-[panel-open]:rotate-180"
>
<path d="m6 9 6 6 6-6" />
</svg>
}
>
Custom Chevron Icon
</Accordion.Trigger>
<Accordion.Content>
This accordion uses a custom chevron icon instead of the default plus icon.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-2">
<Accordion.Trigger
icon={
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="transition-transform group-data-[panel-open]:rotate-180"
>
<path d="m6 9 6 6 6-6" />
</svg>
}
>
Another Section
</Accordion.Trigger>
<Accordion.Content>All items in this accordion use the custom icon.</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
);
},
};
export const AsChildTrigger: Story = {
render() {
return (
<Accordion.Root className="w-96">
<Accordion.Item value="item-1">
<Accordion.Trigger asChild>
<button className="bg-blue-500 hover:bg-blue-600 w-full rounded-md px-4 py-2 text-left text-on-color">
Custom Button Trigger
</button>
</Accordion.Trigger>
<Accordion.Content>
When using asChild, you can completely customize the trigger element without the default icon wrapper.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="item-2">
<Accordion.Trigger asChild>
<button className="bg-green-500 hover:bg-green-600 w-full rounded-md px-4 py-2 text-left text-on-color">
Another Custom Trigger
</button>
</Accordion.Trigger>
<Accordion.Content>This gives you full control over the trigger styling and behavior.</Accordion.Content>
</Accordion.Item>
</Accordion.Root>
);
},
};
@@ -0,0 +1,94 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import * as React from "react";
import { Accordion as BaseAccordion } from "@base-ui-components/react";
import { PlusIcon } from "../icons";
export interface AccordionRootProps {
defaultValue?: string[];
allowMultiple?: boolean;
className?: string;
children: React.ReactNode;
}
export interface AccordionItemProps {
value: string;
disabled?: boolean;
className?: string;
children: React.ReactNode;
}
export interface AccordionTriggerProps {
className?: string;
icon?: React.ReactNode;
children: React.ReactNode;
asChild?: boolean;
iconClassName?: string;
}
export interface AccordionContentProps {
className?: string;
contentWrapperClassName?: string;
children: React.ReactNode;
}
function AccordionRoot({ defaultValue = [], allowMultiple = false, className = "", children }: AccordionRootProps) {
return (
<BaseAccordion.Root defaultValue={defaultValue} openMultiple={allowMultiple} className={`text-14 ${className}`}>
{children}
</BaseAccordion.Root>
);
}
function AccordionItem({ value, disabled, className = "", children }: AccordionItemProps) {
return (
<BaseAccordion.Item value={value} disabled={disabled} className={`relative ${className}`}>
{children}
</BaseAccordion.Item>
);
}
function AccordionTrigger({
className = "",
icon = <PlusIcon aria-hidden="true" className="transition-all ease-out group-data-[panel-open]:rotate-45" />,
iconClassName = "",
children,
asChild = false,
}: AccordionTriggerProps) {
return (
<BaseAccordion.Header>
{asChild ? (
<BaseAccordion.Trigger className={`w-full py-2 ${className}`}>{children}</BaseAccordion.Trigger>
) : (
<BaseAccordion.Trigger className={`flex w-full items-center justify-between gap-2 py-2 ${className}`}>
{children}
<span aria-hidden="true" className={`flex-shrink-0 ${iconClassName}`}>
{icon}
</span>
</BaseAccordion.Trigger>
)}
</BaseAccordion.Header>
);
}
function AccordionContent({ className = "", contentWrapperClassName = "", children }: AccordionContentProps) {
return (
<BaseAccordion.Panel
className={`h-[var(--accordion-panel-height)] overflow-hidden transition-[height] ease-out data-[ending-style]:h-0 data-[starting-style]:h-0 ${className}`}
>
<div className={`py-2 ${contentWrapperClassName}`}>{children}</div>
</BaseAccordion.Panel>
);
}
export const Accordion = {
Root: AccordionRoot,
Item: AccordionItem,
Trigger: AccordionTrigger,
Content: AccordionContent,
};
@@ -0,0 +1,7 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
export * from "./accordion";