mirror of
https://github.com/gosticks/plane.git
synced 2025-10-16 12:45:33 +00:00
[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:
parent
11b83cf4f2
commit
a8a6536379
@ -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",
|
||||||
|
|||||||
100
packages/propel/src/collapsible/collapsible.tsx
Normal file
100
packages/propel/src/collapsible/collapsible.tsx
Normal 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,
|
||||||
|
};
|
||||||
1
packages/propel/src/collapsible/index.ts
Normal file
1
packages/propel/src/collapsible/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from "./collapsible";
|
||||||
@ -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",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user