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,52 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import React from "react";
import type { ISvgIcons } from "@plane/propel/icons";
import { DropdownIcon } from "@plane/propel/icons";
import { cn } from "../utils";
type Props = {
isOpen: boolean;
title: React.ReactNode;
hideChevron?: boolean;
indicatorElement?: React.ReactNode;
actionItemElement?: React.ReactNode;
className?: string;
titleClassName?: string;
ChevronIcon?: React.FC<ISvgIcons>;
};
export function CollapsibleButton(props: Props) {
const {
isOpen,
title,
hideChevron = false,
indicatorElement,
actionItemElement,
className = "",
titleClassName = "",
ChevronIcon = DropdownIcon,
} = props;
return (
<div className={cn("flex h-12 items-center justify-between gap-3 border-b border-subtle px-2.5 py-3", className)}>
<div className="flex items-center gap-3.5">
<div className="flex items-center gap-3">
{!hideChevron && (
<ChevronIcon
className={cn("size-2 text-tertiary duration-300 hover:text-secondary", {
"-rotate-90": !isOpen,
})}
/>
)}
<span className={cn("text-14 font-medium text-primary", titleClassName)}>{title}</span>
</div>
{indicatorElement && indicatorElement}
</div>
{actionItemElement && isOpen && actionItemElement}
</div>
);
}
@@ -0,0 +1,62 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { Disclosure, Transition } from "@headlessui/react";
import React, { useState, useEffect, useCallback } from "react";
export type TCollapsibleProps = {
title: string | React.ReactNode;
children: React.ReactNode;
buttonRef?: React.RefObject<HTMLButtonElement>;
className?: string;
buttonClassName?: string;
isOpen?: boolean;
onToggle?: () => void;
defaultOpen?: boolean;
};
export function Collapsible(props: TCollapsibleProps) {
const { title, children, buttonRef, className, buttonClassName, isOpen, onToggle, defaultOpen } = props;
// state
const [localIsOpen, setLocalIsOpen] = useState<boolean>(isOpen || defaultOpen ? true : false);
useEffect(() => {
if (isOpen !== undefined) {
setLocalIsOpen(isOpen);
}
}, [isOpen]);
// handlers
const handleOnClick = useCallback(() => {
if (isOpen !== undefined) {
if (onToggle) onToggle();
} else {
setLocalIsOpen((prev) => !prev);
}
}, [isOpen, onToggle]);
return (
<Disclosure as="div" className={className}>
<Disclosure.Button ref={buttonRef} className={buttonClassName} onClick={handleOnClick}>
{title}
</Disclosure.Button>
<Transition
show={localIsOpen}
enter="transition-all duration-300 ease-in-out"
enterFrom="grid-rows-[0fr] opacity-0"
enterTo="grid-rows-[1fr] opacity-100"
leave="transition-all duration-300 ease-in-out"
leaveFrom="grid-rows-[1fr] opacity-100"
leaveTo="grid-rows-[0fr] opacity-0"
className="grid overflow-hidden"
>
<Disclosure.Panel static className="min-h-0">
{children}
</Disclosure.Panel>
</Transition>
</Disclosure>
);
}
@@ -0,0 +1,8 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
export * from "./collapsible";
export * from "./collapsible-button";