[WEB-4688]feat: added collapsible to propel (#7643)

* chore: added collapsibl to propel

* fix: export path

* chore: made collapsible a compound component

* fix: lint and format errors

* chore: updated propel exports order and added collapsible to tsdown config
This commit is contained in:
Vamsi Krishna 2025-09-09 13:59:00 +05:30 committed by GitHub
parent 11b83cf4f2
commit a8a6536379
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 103 additions and 0 deletions

View File

@ -20,6 +20,7 @@
"./avatar": "./dist/avatar/index.js", "./avatar": "./dist/avatar/index.js",
"./card": "./dist/card/index.js", "./card": "./dist/card/index.js",
"./charts/*": "./dist/charts/*/index.js", "./charts/*": "./dist/charts/*/index.js",
"./collapsible": "./dist/collapsible/index.js",
"./combobox": "./dist/combobox/index.js", "./combobox": "./dist/combobox/index.js",
"./command": "./dist/command/index.js", "./command": "./dist/command/index.js",
"./dialog": "./dist/dialog/index.js", "./dialog": "./dist/dialog/index.js",

View File

@ -0,0 +1,100 @@
import React, { useState, useEffect, useCallback, createContext, useContext } from "react";
import { Collapsible as BaseCollapsible } from "@base-ui-components/react/collapsible";
import clsx from "clsx";
// Types
type CollapsibleContextType = {
isOpen: boolean;
onToggle: () => void;
};
type RootProps = {
children: React.ReactNode;
className?: string;
isOpen?: boolean;
onToggle?: () => void;
defaultOpen?: boolean;
};
type TriggerProps = {
children: React.ReactNode;
className?: string;
buttonRef?: React.RefObject<HTMLButtonElement>;
};
type ContentProps = {
children: React.ReactNode;
className?: string;
};
// Context
const CollapsibleContext = createContext<CollapsibleContextType | undefined>(undefined);
// Hook
const useCollapsible = () => {
const context = useContext(CollapsibleContext);
if (!context) {
throw new Error("Collapsible compound components cannot be rendered outside the Collapsible component");
}
return context;
};
// Components
const Root: React.FC<RootProps> = ({ children, className, isOpen: controlledIsOpen, onToggle, defaultOpen }) => {
const [localIsOpen, setLocalIsOpen] = useState<boolean>(controlledIsOpen || defaultOpen || false);
useEffect(() => {
if (controlledIsOpen !== undefined) {
setLocalIsOpen(controlledIsOpen);
}
}, [controlledIsOpen]);
const handleToggle = useCallback(() => {
if (controlledIsOpen !== undefined) {
onToggle?.();
} else {
setLocalIsOpen((prev) => !prev);
}
}, [controlledIsOpen, onToggle]);
return (
<CollapsibleContext.Provider value={{ isOpen: localIsOpen, onToggle: handleToggle }}>
<BaseCollapsible.Root
className={clsx(className)}
defaultOpen={defaultOpen}
open={localIsOpen}
onOpenChange={handleToggle}
>
{children}
</BaseCollapsible.Root>
</CollapsibleContext.Provider>
);
};
const Trigger: React.FC<TriggerProps> = ({ children, className, buttonRef }) => {
const { isOpen } = useCollapsible();
return (
<BaseCollapsible.Trigger data-panel-open={isOpen} ref={buttonRef} className={className}>
{children}
</BaseCollapsible.Trigger>
);
};
const Content: React.FC<ContentProps> = ({ children, className }) => (
<BaseCollapsible.Panel
className={clsx(
"flex h-[var(--collapsible-panel-height)] flex-col overflow-hidden text-sm transition-all ease-out data-[ending-style]:h-0 data-[starting-style]:h-0",
className
)}
>
{children}
</BaseCollapsible.Panel>
);
// Compound Component
export const Collapsible = {
CollapsibleRoot: Root,
CollapsibleTrigger: Trigger,
CollapsibleContent: Content,
};

View File

@ -0,0 +1 @@
export * from "./collapsible";

View File

@ -6,6 +6,7 @@ export default defineConfig({
"src/avatar/index.ts", "src/avatar/index.ts",
"src/card/index.ts", "src/card/index.ts",
"src/charts/*/index.ts", "src/charts/*/index.ts",
"src/collapsible/index.ts",
"src/combobox/index.ts", "src/combobox/index.ts",
"src/command/index.ts", "src/command/index.ts",
"src/dialog/index.ts", "src/dialog/index.ts",