Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions packages/propel/src/combobox/combobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,14 @@ function ComboboxOption({ value, children, disabled, className }: ComboboxOption
);
}

// Compound component export
const Combobox = Object.assign(ComboboxRoot, {
Button: ComboboxButton,
Options: ComboboxOptions,
Option: ComboboxOption,
});

const Combobox = ComboboxRoot as typeof ComboboxRoot & {
Button: typeof ComboboxButton;
Options: typeof ComboboxOptions;
Option: typeof ComboboxOption;
};
Combobox.Button = ComboboxButton;
Combobox.Options = ComboboxOptions;
Combobox.Option = ComboboxOption;

export { Combobox };
16 changes: 10 additions & 6 deletions packages/propel/src/command/command.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,15 @@ function CommandItem({ ...props }: React.ComponentProps<typeof CommandPrimitive.
return <CommandPrimitive.Item data-slot="command-item" {...props} />;
}

const Command = Object.assign(CommandComponent, {
Input: CommandInput,
List: CommandList,
Empty: CommandEmpty,
Item: CommandItem,
});
const Command = CommandComponent as typeof CommandComponent & {
Input: typeof CommandInput;
List: typeof CommandList;
Empty: typeof CommandEmpty;
Item: typeof CommandItem;
};
Command.Input = CommandInput;
Command.List = CommandList;
Command.Empty = CommandEmpty;
Command.Item = CommandItem;

export { Command };
28 changes: 18 additions & 10 deletions packages/propel/src/context-menu/context-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,23 @@ ContextMenuItem.displayName = "ContextMenuItem";
ContextMenuSeparator.displayName = "ContextMenuSeparator";
ContextMenuSubmenuTrigger.displayName = "ContextMenuSubmenuTrigger";

// compound components
const ContextMenu = Object.assign(ContextMenuRoot, {
Trigger: ContextMenuTrigger,
Portal: ContextMenuPortal,
Content: ContextMenuContent,
Item: ContextMenuItem,
Separator: ContextMenuSeparator,
Submenu: ContextMenuSubmenu,
SubmenuTrigger: ContextMenuSubmenuTrigger,
});

const ContextMenu = ContextMenuRoot as typeof ContextMenuRoot & {
Trigger: typeof ContextMenuTrigger;
Portal: typeof ContextMenuPortal;
Content: typeof ContextMenuContent;
Item: typeof ContextMenuItem;
Separator: typeof ContextMenuSeparator;
Submenu: typeof ContextMenuSubmenu;
SubmenuTrigger: typeof ContextMenuSubmenuTrigger;
};

ContextMenu.Trigger = ContextMenuTrigger;
ContextMenu.Portal = ContextMenuPortal;
ContextMenu.Content = ContextMenuContent;
ContextMenu.Item = ContextMenuItem;
ContextMenu.Separator = ContextMenuSeparator;
ContextMenu.Submenu = ContextMenuSubmenu;
ContextMenu.SubmenuTrigger = ContextMenuSubmenuTrigger;

export { ContextMenu };
33 changes: 23 additions & 10 deletions packages/propel/src/dialog/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ export interface DialogTitleProps extends React.ComponentProps<typeof BaseDialog
children: React.ReactNode;
}

export interface DialogPortalProps extends React.ComponentProps<typeof BaseDialog.Portal> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer types over interfaces for prop types, you don't need declaration merging for props

children: React.ReactNode;
}

export interface DialogOverlayProps extends React.ComponentProps<typeof BaseDialog.Backdrop> {
className?: string;
}

export interface DialogTriggerProps extends React.ComponentProps<typeof BaseDialog.Trigger> {
children: React.ReactNode;
}

// Constants
const OVERLAY_CLASSNAME = cn("fixed inset-0 z-backdrop bg-custom-backdrop");
const BASE_CLASSNAME = "relative text-left bg-custom-background-100 rounded-lg shadow-md w-full z-modal";
Expand All @@ -45,7 +57,7 @@ const getPositionClassNames = (position: DialogPosition) =>
"top-8 left-1/2 -translate-x-1/2": position === "top",
});

const DialogPortal = memo(function DialogPortal({ children, ...props }) {
const DialogPortal = memo<DialogPortalProps>(function DialogPortal({ children, ...props }: DialogPortalProps) {
return (
<BaseDialog.Portal data-slot="dialog-portal" {...props}>
{children}
Expand All @@ -54,12 +66,12 @@ const DialogPortal = memo(function DialogPortal({ children, ...props }) {
});
DialogPortal.displayName = "DialogPortal";

const DialogOverlay = memo(function DialogOverlay({ className, ...props }) {
const DialogOverlay = memo<DialogOverlayProps>(function DialogOverlay({ className, ...props }: DialogOverlayProps) {
return <BaseDialog.Backdrop data-slot="dialog-overlay" className={cn(OVERLAY_CLASSNAME, className)} {...props} />;
});
DialogOverlay.displayName = "DialogOverlay";

const DialogComponent = memo(function DialogComponent({ children, ...props }) {
const DialogComponent = memo<DialogProps>(function DialogComponent({ children, ...props }: DialogProps) {
return (
<BaseDialog.Root data-slot="dialog" {...props}>
{children}
Expand All @@ -68,7 +80,7 @@ const DialogComponent = memo(function DialogComponent({ children, ...props }) {
});
DialogComponent.displayName = "Dialog";

const DialogTrigger = memo(function DialogTrigger({ children, ...props }) {
const DialogTrigger = memo<DialogTriggerProps>(function DialogTrigger({ children, ...props }: DialogTriggerProps) {
return (
<BaseDialog.Trigger data-slot="dialog-trigger" {...props}>
{children}
Expand Down Expand Up @@ -100,7 +112,7 @@ const DialogPanel = forwardRef(function DialogPanel(
});
DialogPanel.displayName = "DialogPanel";

const DialogTitle = memo(function DialogTitle({ className, children, ...props }) {
const DialogTitle = memo<DialogTitleProps>(function DialogTitle({ className, children, ...props }: DialogTitleProps) {
return (
<BaseDialog.Title
data-slot="dialog-title"
Expand All @@ -115,12 +127,13 @@ const DialogTitle = memo(function DialogTitle({ className, children, ...props })
DialogTitle.displayName = "DialogTitle";

// Create the compound Dialog component with proper typing
const Dialog = Object.assign(DialogComponent, {
Panel: DialogPanel,
Title: DialogTitle,
}) as typeof DialogComponent & {
const Dialog = DialogComponent as typeof DialogComponent & {
Panel: typeof DialogPanel;
Title: typeof DialogTitle;
Trigger: typeof DialogTrigger;
};
Dialog.Panel = DialogPanel;
Dialog.Title = DialogTitle;
Dialog.Trigger = DialogTrigger;

export { Dialog, DialogTitle, DialogPanel };
export { Dialog, DialogTitle, DialogPanel, DialogTrigger };
29 changes: 15 additions & 14 deletions packages/propel/src/popover/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface PopoverContentProps extends React.ComponentProps<typeof BasePop
}

// PopoverContent component
const PopoverContent = React.memo(function PopoverContent({
const PopoverContent = React.memo<PopoverContentProps>(function PopoverContent({
children,
className,
placement,
Expand All @@ -23,7 +23,7 @@ const PopoverContent = React.memo(function PopoverContent({
containerRef,
positionerClassName,
...props
}) {
}: PopoverContentProps) {
// side and align calculations
const { finalSide, finalAlign } = React.useMemo(() => {
if (placement) {
Expand All @@ -45,28 +45,29 @@ const PopoverContent = React.memo(function PopoverContent({
});

// wrapper components
const PopoverTrigger = React.memo(function PopoverTrigger(props) {
const PopoverTrigger = React.memo(function PopoverTrigger(props: React.ComponentProps<typeof BasePopover.Trigger>) {
return <BasePopover.Trigger data-slot="popover-trigger" {...props} />;
});

const PopoverPortal = React.memo(function PopoverPortal(props) {
const PopoverPortal = React.memo(function PopoverPortal(props: React.ComponentProps<typeof BasePopover.Portal>) {
return <BasePopover.Portal data-slot="popover-portal" {...props} />;
});

const PopoverPositioner = React.memo(function PopoverPositioner(props) {
const PopoverPositioner = React.memo(function PopoverPositioner(props: React.ComponentProps<typeof BasePopover.Positioner>) {
return <BasePopover.Positioner data-slot="popover-positioner" {...props} />;
});

// compound components
const Popover = Object.assign(
React.memo<React.ComponentProps<typeof BasePopover.Root>>(function Popover(props) {
return <BasePopover.Root data-slot="popover" {...props} />;
}),
{
Button: PopoverTrigger,
Panel: PopoverContent,
}
);
const PopoverRoot = React.memo<React.ComponentProps<typeof BasePopover.Root>>(function Popover(props) {
return <BasePopover.Root data-slot="popover" {...props} />;
});

const Popover = PopoverRoot as typeof PopoverRoot & {
Button: typeof PopoverTrigger;
Panel: typeof PopoverContent;
};
Popover.Button = PopoverTrigger;
Popover.Panel = PopoverContent;

// display names
PopoverContent.displayName = "PopoverContent";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

Expand Down
25 changes: 14 additions & 11 deletions packages/propel/src/skeleton/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ import React from "react";
// helpers
import { cn } from "../utils/classname";

type SkeletonProps = {
export type SkeletonProps = {
children: React.ReactNode;
className?: string;
ariaLabel?: string;
};

export type SkeletonItemProps = {
height?: string;
width?: string;
className?: string;
};

function SkeletonRoot({ children, className = "", ariaLabel = "Loading content" }: SkeletonProps) {
return (
<div data-slot="skeleton" className={cn("animate-pulse", className)} role="status" aria-label={ariaLabel}>
Expand All @@ -16,13 +22,7 @@ function SkeletonRoot({ children, className = "", ariaLabel = "Loading content"
);
}

type ItemProps = {
height?: string;
width?: string;
className?: string;
};

function SkeletonItem({ height = "auto", width = "auto", className = "" }: ItemProps) {
function SkeletonItem({ height = "auto", width = "auto", className = "" }: SkeletonItemProps) {
return (
<div
data-slot="skeleton-item"
Expand All @@ -32,9 +32,12 @@ function SkeletonItem({ height = "auto", width = "auto", className = "" }: ItemP
);
}

const Skeleton = Object.assign(SkeletonRoot, { Item: SkeletonItem });

SkeletonRoot.displayName = "plane-ui-skeleton";
SkeletonItem.displayName = "plane-ui-skeleton-item";

export { Skeleton };
const Skeleton = SkeletonRoot as typeof SkeletonRoot & {
Item: typeof SkeletonItem;
};
Skeleton.Item = SkeletonItem;

export { Skeleton, SkeletonRoot, SkeletonItem };
41 changes: 17 additions & 24 deletions packages/propel/src/tabs/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,6 @@ import * as React from "react";
import { Tabs as TabsPrimitive } from "@base-ui-components/react/tabs";
import { cn } from "../utils/classname";

type TabsCompound = React.ForwardRefExoticComponent<
React.ComponentProps<typeof TabsPrimitive.Root> & React.RefAttributes<React.ElementRef<typeof TabsPrimitive.Root>>
> & {
List: React.ForwardRefExoticComponent<
React.ComponentProps<typeof TabsPrimitive.List> & React.RefAttributes<React.ElementRef<typeof TabsPrimitive.List>>
>;
Trigger: React.ForwardRefExoticComponent<
React.ComponentProps<typeof TabsPrimitive.Tab> & { size?: "sm" | "md" | "lg" } & React.RefAttributes<
React.ElementRef<typeof TabsPrimitive.Tab>
>
>;
Content: React.ForwardRefExoticComponent<
React.ComponentProps<typeof TabsPrimitive.Panel> & React.RefAttributes<React.ElementRef<typeof TabsPrimitive.Panel>>
>;
Indicator: React.ForwardRefExoticComponent<React.ComponentProps<"div"> & React.RefAttributes<HTMLDivElement>>;
};

const TabsRoot = React.forwardRef(function TabsRoot(
{ className, ...props }: React.ComponentProps<typeof TabsPrimitive.Root>,
ref: React.ForwardedRef<React.ElementRef<typeof TabsPrimitive.Root>>
Expand Down Expand Up @@ -104,11 +87,21 @@ const TabsIndicator = React.forwardRef(function TabsIndicator(
);
});

export const Tabs = Object.assign(TabsRoot, {
List: TabsList,
Trigger: TabsTrigger,
Content: TabsContent,
Indicator: TabsIndicator,
}) satisfies TabsCompound;
TabsRoot.displayName = "TabsRoot";
TabsList.displayName = "TabsList";
TabsTrigger.displayName = "TabsTrigger";
TabsContent.displayName = "TabsContent";
TabsIndicator.displayName = "TabsIndicator";

const Tabs = TabsRoot as typeof TabsRoot & {
List: typeof TabsList;
Trigger: typeof TabsTrigger;
Content: typeof TabsContent;
Indicator: typeof TabsIndicator;
};
Tabs.List = TabsList;
Tabs.Trigger = TabsTrigger;
Tabs.Content = TabsContent;
Tabs.Indicator = TabsIndicator;

export { TabsList, TabsTrigger, TabsContent, TabsIndicator };
export { Tabs, TabsList, TabsTrigger, TabsContent, TabsIndicator };
16 changes: 10 additions & 6 deletions packages/propel/src/toolbar/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,15 @@ ToolbarSeparator.displayName = "ToolbarSeparator";
ToolbarSubmitButton.displayName = "ToolbarSubmitButton";

// compound components
const Toolbar = Object.assign(ToolbarRoot, {
Group: ToolbarGroup,
Item: ToolbarItem,
Separator: ToolbarSeparator,
SubmitButton: ToolbarSubmitButton,
});
const Toolbar = ToolbarRoot as typeof ToolbarRoot & {
Group: typeof ToolbarGroup;
Item: typeof ToolbarItem;
Separator: typeof ToolbarSeparator;
SubmitButton: typeof ToolbarSubmitButton;
};
Toolbar.Group = ToolbarGroup;
Toolbar.Item = ToolbarItem;
Toolbar.Separator = ToolbarSeparator;
Toolbar.SubmitButton = ToolbarSubmitButton;

export { Toolbar };
Loading