diff --git a/packages/propel/src/combobox/combobox.stories.tsx b/packages/propel/src/combobox/combobox.stories.tsx
index 5789514249b..42bfc32a75a 100644
--- a/packages/propel/src/combobox/combobox.stories.tsx
+++ b/packages/propel/src/combobox/combobox.stories.tsx
@@ -2,7 +2,7 @@ import { useState } from "react";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { Check, ChevronsUpDown } from "lucide-react";
import { useArgs } from "storybook/preview-api";
-import { Combobox } from "./combobox";
+import { Combobox, ComboboxButton, ComboboxOptions, ComboboxOption } from "./combobox";
const frameworks = [
{ value: "react", label: "React" },
@@ -19,9 +19,9 @@ const meta = {
title: "Components/Combobox",
component: Combobox,
subcomponents: {
- ComboboxButton: Combobox.Button,
- ComboboxOptions: Combobox.Options,
- ComboboxOption: Combobox.Option,
+ ComboboxButton,
+ ComboboxOptions,
+ ComboboxOption,
},
parameters: {
layout: "centered",
@@ -37,22 +37,22 @@ const meta = {
const setValue = (newValue: string | string[]) => updateArgs({ value: newValue });
return (
setValue(v as string)}>
-
+
{value ? frameworks.find((f) => f.value === value)?.label : "Select framework..."}
-
-
+
+
{frameworks.map((framework) => (
-
{value === framework.value && }
{framework.label}
-
+
))}
-
+
);
},
@@ -68,22 +68,22 @@ export const WithoutSearch: Story = {
const [value, setValue] = useState("");
return (
setValue(v as string)}>
-
+
{value ? frameworks.find((f) => f.value === value)?.label : "Select framework..."}
-
-
+
+
{frameworks.map((framework) => (
-
{value === framework.value && }
{framework.label}
-
+
))}
-
+
);
},
@@ -95,22 +95,22 @@ export const MultiSelect: Story = {
return (
setValue(v as string[])}>
-
+
{value.length > 0 ? `${value.length} selected` : "Select frameworks..."}
-
-
+
+
{frameworks.map((framework) => (
-
{value.includes(framework.value) && }
{framework.label}
-
+
))}
-
+
);
},
@@ -123,24 +123,24 @@ export const MultiSelectWithLimit: Story = {
return (
setValue(v as string[])}>
-
+
{value.length > 0 ? `${value.length}/3 selected` : "Select up to 3 frameworks..."}
-
-
+
+
{frameworks.map((framework) => (
-
{value.includes(framework.value) && }
{framework.label}
-
+
))}
-
+
Maximum 3 selections allowed
@@ -154,22 +154,22 @@ export const Disabled: Story = {
const [value, setValue] = useState("");
return (
setValue(v as string)}>
-
+
{value ? frameworks.find((f) => f.value === value)?.label : "Select framework..."}
-
-
+
+
{frameworks.map((framework) => (
-
{value === framework.value && }
{framework.label}
-
+
))}
-
+
);
},
@@ -180,13 +180,13 @@ export const DisabledOptions: Story = {
const [value, setValue] = useState("");
return (
setValue(v as string)}>
-
+
{value ? frameworks.find((f) => f.value === value)?.label : "Select framework..."}
-
-
+
+
{frameworks.map((framework) => (
-
{value === framework.value && }
{framework.label}
-
+
))}
-
+
);
},
@@ -207,22 +207,22 @@ export const CustomMaxHeight: Story = {
const [value, setValue] = useState("");
return (
setValue(v as string)}>
-
+
{value ? frameworks.find((f) => f.value === value)?.label : "Select framework..."}
-
-
+
+
{frameworks.map((framework) => (
-
{value === framework.value && }
{framework.label}
-
+
))}
-
+
);
},
@@ -233,27 +233,27 @@ export const CustomEmptyMessage: Story = {
const [value, setValue] = useState("");
return (
setValue(v as string)}>
-
+
{value ? frameworks.find((f) => f.value === value)?.label : "Select framework..."}
-
-
+
{frameworks.map((framework) => (
-
{value === framework.value && }
{framework.label}
-
+
))}
-
+
);
},
diff --git a/packages/propel/src/combobox/combobox.tsx b/packages/propel/src/combobox/combobox.tsx
index 94b307533c8..65567041459 100644
--- a/packages/propel/src/combobox/combobox.tsx
+++ b/packages/propel/src/combobox/combobox.tsx
@@ -220,11 +220,10 @@ function ComboboxOption({ value, children, disabled, className }: ComboboxOption
);
}
-// Compound component export
-const Combobox = Object.assign(ComboboxRoot, {
- Button: ComboboxButton,
- Options: ComboboxOptions,
- Option: ComboboxOption,
-});
+ComboboxRoot.displayName = "Combobox";
+ComboboxButton.displayName = "ComboboxButton";
+ComboboxOptions.displayName = "ComboboxOptions";
+ComboboxOption.displayName = "ComboboxOption";
+
-export { Combobox };
+export { ComboboxRoot as Combobox, ComboboxButton, ComboboxOptions, ComboboxOption };
diff --git a/packages/propel/src/command/command.stories.tsx b/packages/propel/src/command/command.stories.tsx
index 9f41c9b4b93..86378ca59c8 100644
--- a/packages/propel/src/command/command.stories.tsx
+++ b/packages/propel/src/command/command.stories.tsx
@@ -1,15 +1,15 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { File, Folder, Settings, User } from "lucide-react";
-import { Command } from "./command";
+import { Command, CommandInput, CommandList, CommandItem, CommandEmpty } from "./command";
const meta = {
title: "Components/Command",
component: Command,
subcomponents: {
- CommandInput: Command.Input,
- CommandList: Command.List,
- CommandItem: Command.Item,
- CommandEmpty: Command.Empty,
+ CommandInput,
+ CommandList,
+ CommandItem,
+ CommandEmpty,
},
parameters: {
layout: "centered",
@@ -24,13 +24,13 @@ export const Default: Story = {
render() {
return (
-
-
- Item 1
- Item 2
- Item 3
-
- No results found.
+
+
+ Item 1
+ Item 2
+ Item 3
+
+ No results found.
);
},
@@ -40,29 +40,29 @@ export const WithIcons: Story = {
render() {
return (
-
-
-
+
+
Documents
-
-
+
+
Downloads
-
-
+
+
README.md
-
-
+
+
package.json
-
-
- No files or folders found.
+
+
+ No files or folders found.
);
},
@@ -72,32 +72,32 @@ export const WithCategories: Story = {
render() {
return (
-
-
+
User
-
+
Profile
-
-
+
+
Settings
-
+
Files
-
+
Open Folder
-
-
+
+
New File
-
-
- No commands found.
+
+
+ No commands found.
);
},
@@ -107,12 +107,12 @@ export const EmptyState: Story = {
render() {
return (
-
- {/* No items - will show empty state */}
-
+
+ {/* No items - will show empty state */}
+
No results found
Try searching for something else
-
+
);
},
@@ -122,15 +122,15 @@ export const LongList: Story = {
render() {
return (
-
-
+
+
{Array.from({ length: 20 }, (_, i) => (
-
+
Item {i + 1}
-
+
))}
-
- No results found.
+
+ No results found.
);
},
@@ -140,20 +140,20 @@ export const WithoutSearch: Story = {
render() {
return (
-
-
+
+
Profile
-
-
+
+
Settings
-
-
+
+
Files
-
-
+
+
);
},
@@ -163,22 +163,22 @@ export const CustomStyling: Story = {
render() {
return (
-
-
-
+
+
Custom Item 1
-
-
+
+
Custom Item 2
-
-
+
+
Custom Item 3
-
-
- No matching items found.
+
+
+ No matching items found.
);
},
@@ -188,15 +188,15 @@ export const DisabledItems: Story = {
render() {
return (
-
-
- Active Item 1
-
+
+
+ Active Item 1
+
Disabled Item
-
- Active Item 2
-
- No results found.
+
+ Active Item 2
+
+ No results found.
);
},
diff --git a/packages/propel/src/command/command.tsx b/packages/propel/src/command/command.tsx
index e462a7f2d79..4c46d9babd3 100644
--- a/packages/propel/src/command/command.tsx
+++ b/packages/propel/src/command/command.tsx
@@ -31,11 +31,11 @@ function CommandItem({ ...props }: React.ComponentProps ;
}
-const Command = Object.assign(CommandComponent, {
- Input: CommandInput,
- List: CommandList,
- Empty: CommandEmpty,
- Item: CommandItem,
-});
+// Display names for debugging
+CommandComponent.displayName = "Command";
+CommandInput.displayName = "CommandInput";
+CommandList.displayName = "CommandList";
+CommandEmpty.displayName = "CommandEmpty";
+CommandItem.displayName = "CommandItem";
-export { Command };
+export { CommandComponent as Command, CommandInput, CommandList, CommandEmpty, CommandItem };
diff --git a/packages/propel/src/context-menu/context-menu.stories.tsx b/packages/propel/src/context-menu/context-menu.stories.tsx
index a378dbd196f..08576aa0df8 100644
--- a/packages/propel/src/context-menu/context-menu.stories.tsx
+++ b/packages/propel/src/context-menu/context-menu.stories.tsx
@@ -1,20 +1,20 @@
import type { Meta, StoryObj } from "@storybook/react-vite";
import { Copy, Download, Edit, Share, Trash, Star, Archive } from "lucide-react";
import { ChevronRightIcon } from "../icons/arrows/chevron-right";
-import { ContextMenu } from "./context-menu";
+import { ContextMenu, ContextMenuTrigger, ContextMenuPortal, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuSubmenu, ContextMenuSubmenuTrigger } from "./context-menu";
// cannot use satisfies here because base-ui does not have portable types.
const meta: Meta = {
title: "Components/ContextMenu",
component: ContextMenu,
subcomponents: {
- ContextMenuTrigger: ContextMenu.Trigger,
- ContextMenuPortal: ContextMenu.Portal,
- ContextMenuContent: ContextMenu.Content,
- ContextMenuItem: ContextMenu.Item,
- ContextMenuSeparator: ContextMenu.Separator,
- ContextMenuSubmenu: ContextMenu.Submenu,
- ContextMenuSubmenuTrigger: ContextMenu.SubmenuTrigger,
+ ContextMenuTrigger,
+ ContextMenuPortal,
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuSeparator,
+ ContextMenuSubmenu,
+ ContextMenuSubmenuTrigger,
},
args: {
children: null,
@@ -32,20 +32,20 @@ export const Default: Story = {
render() {
return (
-
+
Right click here
-
-
-
- Back
- Forward
- Reload
-
- More Tools
-
-
+
+
+
+ Back
+ Forward
+ Reload
+
+ More Tools
+
+
);
},
@@ -55,36 +55,36 @@ export const WithIcons: Story = {
render() {
return (
-
+
Right click here
-
-
-
-
+
+
+
+
Copy
-
-
+
+
Edit
-
-
+
+
Download
-
-
-
+
+
+
Share
-
-
+
+
Delete
-
-
-
+
+
+
);
},
@@ -94,43 +94,43 @@ export const WithSubmenus: Story = {
render() {
return (
-
+
Right click here
-
-
-
-
+
+
+
+
Copy
-
-
+
+
Edit
-
-
-
-
+
+
+
+
Share
-
-
-
- Email
- Message
- Copy Link
-
-
-
-
-
+
+
+
+ Email
+ Message
+ Copy Link
+
+
+
+
+
Delete
-
-
-
+
+
+
);
},
@@ -140,36 +140,36 @@ export const DisabledItems: Story = {
render() {
return (
-
+
Right click here
-
-
-
-
+
+
+
+
Copy
-
-
+
+
Edit (Disabled)
-
-
+
+
Download
-
-
-
+
+
+
Share (Disabled)
-
-
+
+
Delete
-
-
-
+
+
+
);
},
@@ -179,7 +179,7 @@ export const OnFileCard: Story = {
render() {
return (
-
+
@@ -191,32 +191,32 @@ export const OnFileCard: Story = {
-
-
-
-
+
+
+
+
Download
-
-
+
+
Copy Link
-
-
+
+
Add to Favorites
-
-
-
+
+
+
Archive
-
-
+
+
Delete
-
-
-
+
+
+
);
},
@@ -226,31 +226,31 @@ export const OnImage: Story = {
render() {
return (
-
+
-
-
-
-
+
+
+
+
Save Image
-
-
+
+
Copy Image
-
-
+
+
Copy Image URL
-
-
- Open Image in New Tab
-
-
+
+
+ Open Image in New Tab
+
+
);
},
@@ -260,7 +260,7 @@ export const OnText: Story = {
render() {
return (
-
+
Context Menu on Text
@@ -268,21 +268,21 @@ export const OnText: Story = {
applied to text content areas.
-
-
-
-
+
+
+
+
Copy
-
-
+
+
Edit
-
-
- Select All
-
-
+
+
+ Select All
+
+
);
},
@@ -292,48 +292,48 @@ export const NestedSubmenus: Story = {
render() {
return (
-
+
Right click here
-
-
-
- New File
- New Folder
-
-
-
+
+
+
+ New File
+ New Folder
+
+
+
Import
-
-
-
- From File
- From URL
-
-
+
+
+
+ From File
+ From URL
+
+
From Cloud
-
-
-
- Google Drive
- Dropbox
- OneDrive
-
-
-
-
-
-
-
-
+
+
+
+ Google Drive
+ Dropbox
+ OneDrive
+
+
+
+
+
+
+
+
Delete
-
-
-
+
+
+
);
},
@@ -343,36 +343,36 @@ export const WithKeyboardShortcuts: Story = {
render() {
return (
-
+
Right click here
-
-
-
-
+
+
+
+
Copy
⌘C
-
-
+
+
Edit
⌘E
-
-
+
+
Download
⌘D
-
-
-
+
+
+
Delete
⌘⌫
-
-
-
+
+
+
);
},
diff --git a/packages/propel/src/context-menu/context-menu.tsx b/packages/propel/src/context-menu/context-menu.tsx
index 494cceb6706..5e916a1eaa9 100644
--- a/packages/propel/src/context-menu/context-menu.tsx
+++ b/packages/propel/src/context-menu/context-menu.tsx
@@ -128,15 +128,13 @@ 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,
-});
-
-export { ContextMenu };
+export {
+ ContextMenuRoot as ContextMenu,
+ ContextMenuTrigger,
+ ContextMenuPortal,
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuSeparator,
+ ContextMenuSubmenu,
+ ContextMenuSubmenuTrigger,
+};
diff --git a/packages/propel/src/context-menu/index.ts b/packages/propel/src/context-menu/index.ts
index 7a0cbc670c9..5cc8201c916 100644
--- a/packages/propel/src/context-menu/index.ts
+++ b/packages/propel/src/context-menu/index.ts
@@ -1,4 +1,13 @@
-export { ContextMenu } from "./context-menu";
+export {
+ ContextMenu,
+ ContextMenuTrigger,
+ ContextMenuPortal,
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuSeparator,
+ ContextMenuSubmenu,
+ ContextMenuSubmenuTrigger,
+} from "./context-menu";
export type {
ContextMenuProps,
ContextMenuTriggerProps,
diff --git a/packages/propel/src/dialog/dialog.stories.tsx b/packages/propel/src/dialog/dialog.stories.tsx
index cf9ccff56d8..2ba3a54804a 100644
--- a/packages/propel/src/dialog/dialog.stories.tsx
+++ b/packages/propel/src/dialog/dialog.stories.tsx
@@ -2,14 +2,14 @@ import { useState } from "react";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { useArgs } from "storybook/preview-api";
import { CloseIcon } from "../icons/actions/close-icon";
-import { Dialog, EDialogWidth } from "./root";
+import { Dialog, DialogPanel, DialogTitle, EDialogWidth } from "./root";
const meta = {
title: "Components/Dialog",
component: Dialog,
subcomponents: {
- DialogPanel: Dialog.Panel,
- DialogTitle: Dialog.Title,
+ DialogPanel,
+ DialogTitle,
},
args: {
children: null,
@@ -31,9 +31,9 @@ const meta = {
{open && (
-
+
-
Dialog Title
+
Dialog Title
This is the dialog content. You can put any content here.
@@ -52,7 +52,7 @@ const meta = {
-
+
)}
>
@@ -79,9 +79,9 @@ export const TopPosition: Story = {
{open && (
-
+
-
Top Positioned Dialog
+
Top Positioned Dialog
This dialog appears at the top of the screen instead of centered.
@@ -96,7 +96,7 @@ export const TopPosition: Story = {
-
+
)}
>
@@ -114,9 +114,9 @@ export const SmallWidth: Story = {
{open && (
-
+
-
Small Dialog
+
Small Dialog
@@ -129,7 +129,7 @@ export const SmallWidth: Story = {
-
+
)}
>
@@ -147,9 +147,9 @@ export const LargeWidth: Story = {
{open && (
-
+
-
Large Dialog
+
Large Dialog
This is a large dialog with more horizontal space for content.
@@ -164,7 +164,7 @@ export const LargeWidth: Story = {
-
+
)}
>
@@ -182,10 +182,10 @@ export const WithCloseButton: Story = {
{open && (
-
+
-
Dialog with Close Button
+
Dialog with Close Button
setOpen(false)} className="rounded-full p-1 hover:bg-gray-100">
@@ -194,7 +194,7 @@ export const WithCloseButton: Story = {
This dialog has a close button in the header.
-
+
)}
>
@@ -216,9 +216,9 @@ export const ConfirmationDialog: Story = {
{open && (
-
+
-
Confirm Deletion
+
Confirm Deletion
Are you sure you want to delete this item? This action cannot be undone.
@@ -239,7 +239,7 @@ export const ConfirmationDialog: Story = {
-
+
)}
>
@@ -262,9 +262,9 @@ export const FormDialog: Story = {
{open && (
-
+
+
))}
diff --git a/packages/propel/src/dialog/root.tsx b/packages/propel/src/dialog/root.tsx
index e0a518b228f..6ccfd8db474 100644
--- a/packages/propel/src/dialog/root.tsx
+++ b/packages/propel/src/dialog/root.tsx
@@ -34,6 +34,18 @@ export interface DialogTitleProps extends React.ComponentProps {
+ children: React.ReactNode;
+}
+
+export interface DialogOverlayProps extends React.ComponentProps {
+ className?: string;
+}
+
+export interface DialogTriggerProps extends React.ComponentProps {
+ 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";
@@ -122,14 +134,6 @@ const DialogTitle = memo(function DialogTitle({ className, children, ...props }:
});
DialogTitle.displayName = "DialogTitle";
+DialogComponent.displayName = "Dialog";
-// Create the compound Dialog component with proper typing
-const Dialog = Object.assign(DialogComponent, {
- Panel: DialogPanel,
- Title: DialogTitle,
-}) as typeof DialogComponent & {
- Panel: typeof DialogPanel;
- Title: typeof DialogTitle;
-};
-
-export { Dialog, DialogTitle, DialogPanel };
+export { DialogComponent as Dialog, DialogTitle, DialogPanel, DialogTrigger };
diff --git a/packages/propel/src/emoji-icon-picker/emoji-picker.tsx b/packages/propel/src/emoji-icon-picker/emoji-picker.tsx
index fcb22d310c7..58b9b6cdb6a 100644
--- a/packages/propel/src/emoji-icon-picker/emoji-picker.tsx
+++ b/packages/propel/src/emoji-icon-picker/emoji-picker.tsx
@@ -1,6 +1,6 @@
import { useMemo, useCallback } from "react";
import { Tabs } from "@base-ui-components/react";
-import { Popover } from "../popover";
+import { Popover, PopoverTrigger, PopoverContent } from "../popover";
import { cn } from "../utils/classname";
import { convertPlacementToSideAndAlign } from "../utils/placement";
import { EmojiRoot } from "./emoji/emoji";
@@ -95,10 +95,10 @@ export function EmojiPicker(props: TCustomEmojiPicker) {
return (
-
+
{label}
-
-
+
))}
-
+
);
}
diff --git a/packages/propel/src/emoji-reaction/emoji-reaction-picker.tsx b/packages/propel/src/emoji-reaction/emoji-reaction-picker.tsx
index e1cb4740b39..cfe49a07577 100644
--- a/packages/propel/src/emoji-reaction/emoji-reaction-picker.tsx
+++ b/packages/propel/src/emoji-reaction/emoji-reaction-picker.tsx
@@ -1,7 +1,7 @@
import React, { useMemo, useCallback } from "react";
import { EmojiRoot } from "../emoji-icon-picker/emoji/emoji";
import { emojiToString } from "../emoji-icon-picker/helper";
-import { Popover } from "../popover";
+import { Popover, PopoverTrigger, PopoverContent } from "../popover";
import { cn } from "../utils/classname";
import { convertPlacementToSideAndAlign } from "../utils/placement";
import type { TPlacement, TSide, TAlign } from "../utils/placement";
@@ -59,10 +59,10 @@ export function EmojiReactionPicker(props: EmojiReactionPickerProps) {
return (
-
+
{label}
-
-
+
-
+
);
}
diff --git a/packages/propel/src/popover/popover.stories.tsx b/packages/propel/src/popover/popover.stories.tsx
index 2a0d60c0a6c..ed52309b8cc 100644
--- a/packages/propel/src/popover/popover.stories.tsx
+++ b/packages/propel/src/popover/popover.stories.tsx
@@ -2,15 +2,15 @@ import { useState } from "react";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { useArgs } from "storybook/preview-api";
import { CloseIcon } from "../icons/actions/close-icon";
-import { Popover } from "./root";
+import { Popover, PopoverTrigger, PopoverContent } from "./root";
// cannot use satifies here because base-ui does not have portable types.
const meta: Meta = {
title: "Components/Popover",
component: Popover,
subcomponents: {
- PopoverButton: Popover.Button,
- PopoverPanel: Popover.Panel,
+ PopoverTrigger,
+ PopoverContent,
},
parameters: {
layout: "centered",
@@ -27,13 +27,13 @@ const meta: Meta = {
return (
-
+
Open Popover
-
-
+
+
Popover Title
This is the popover content. You can put any content here.
-
+
);
},
@@ -63,10 +63,10 @@ export const Controlled: Story = {
-
+
Controlled Popover
-
-
+
+
Controlled State
setOpen(false)} className="rounded-full p-1 hover:bg-gray-100">
@@ -74,7 +74,7 @@ export const Controlled: Story = {
Current state: {open ? "Open" : "Closed"}
-
+
);
@@ -86,13 +86,13 @@ export const SideTop: Story = {
const [open, setOpen] = useState(args.open);
return (
-
+
Open Above
-
-
+
+
Top Positioned
This popover appears above the button.
-
+
);
},
@@ -103,13 +103,13 @@ export const SideBottom: Story = {
const [open, setOpen] = useState(args.open);
return (
-
+
Open Below
-
-
+
+
Bottom Positioned
This popover appears below the button.
-
+
);
},
@@ -120,13 +120,13 @@ export const SideLeft: Story = {
const [open, setOpen] = useState(args.open);
return (
-
+
Open Left
-
-
+
+
Left Positioned
This popover appears to the left of the button.
-
+
);
},
@@ -137,13 +137,13 @@ export const SideRight: Story = {
const [open, setOpen] = useState(args.open);
return (
-
+
Open Right
-
-
+
+
Right Positioned
This popover appears to the right of the button.
-
+
);
},
@@ -154,13 +154,13 @@ export const AlignStart: Story = {
const [open, setOpen] = useState(args.open);
return (
-
+
Align Start
-
-
+
+
Start Aligned
This popover is aligned to the start.
-
+
);
},
@@ -171,13 +171,13 @@ export const AlignEnd: Story = {
const [open, setOpen] = useState(args.open);
return (
-
+
Align End
-
-
+
+
End Aligned
This popover is aligned to the end.
-
+
);
},
@@ -188,13 +188,13 @@ export const CustomOffset: Story = {
const [open, setOpen] = useState(args.open);
return (
-
+
Custom Offset
-
-
+
+
Custom Side Offset
This popover has a custom side offset of 20px.
-
+
);
},
@@ -210,10 +210,10 @@ export const WithForm: Story = {
};
return (
-
+
Open Form
-
-
+
+
Quick Form
-
+
);
},
@@ -262,17 +262,17 @@ export const WithList: Story = {
const [open, setOpen] = useState(args.open);
return (
-
+
Show Options
-
-
+
+
Options
Option 1
Option 2
Option 3
-
+
);
},
@@ -285,11 +285,11 @@ export const ColorPicker: Story = {
return (
-
+
Pick Color
-
-
+
+
Select Color
{colors.map((color) => (
@@ -304,7 +304,7 @@ export const ColorPicker: Story = {
/>
))}
-
+
);
},
diff --git a/packages/propel/src/popover/root.tsx b/packages/propel/src/popover/root.tsx
index d7d9ac40b85..6b2b6e7c9bf 100644
--- a/packages/propel/src/popover/root.tsx
+++ b/packages/propel/src/popover/root.tsx
@@ -45,6 +45,15 @@ const PopoverContent = memo(function PopoverContent({
});
// wrapper components
+const PopoverTrigger = React.memo(function PopoverTrigger(props: React.ComponentProps) {
+ return ;
+});
+
+const PopoverPortal = React.memo(function PopoverPortal(props: React.ComponentProps) {
+ return ;
+});
+
+const PopoverPositioner = React.memo(function PopoverPositioner(props: React.ComponentProps) {
const PopoverTrigger = memo(function PopoverTrigger(props: React.ComponentProps) {
return ;
});
@@ -58,6 +67,9 @@ const PopoverPositioner = memo(function PopoverPositioner(props: React.Component
});
// compound components
+const PopoverRoot = React.memo>(function Popover(props) {
+ return ;
+});
const Popover = Object.assign(
memo(function Popover(props: React.ComponentProps) {
return ;
@@ -70,9 +82,9 @@ const Popover = Object.assign(
// display names
PopoverContent.displayName = "PopoverContent";
-Popover.displayName = "Popover";
+PopoverRoot.displayName = "Popover";
PopoverPortal.displayName = "PopoverPortal";
PopoverTrigger.displayName = "PopoverTrigger";
PopoverPositioner.displayName = "PopoverPositioner";
-export { Popover };
+export { PopoverRoot as Popover, PopoverTrigger, PopoverContent };
diff --git a/packages/propel/src/skeleton/root.tsx b/packages/propel/src/skeleton/root.tsx
index 03bb61bd35b..5eeeec97a9d 100644
--- a/packages/propel/src/skeleton/root.tsx
+++ b/packages/propel/src/skeleton/root.tsx
@@ -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 (
@@ -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 (
-
+
);
},
@@ -29,10 +29,10 @@ export const Card: Story = {
render() {
return (
-
+
-
-
+
+
);
@@ -45,10 +45,10 @@ export const List: Story = {
{[...Array(5)].map((_, i) => (
))}
@@ -62,15 +62,15 @@ export const Table: Story = {
return (
-
-
-
+
+
+
{[...Array(5)].map((_, i) => (
-
-
-
+
+
+
))}
@@ -83,16 +83,16 @@ export const Profile: Story = {
return (
-
-
-
+
+
+
);
@@ -103,7 +103,7 @@ export const Avatar: Story = {
render() {
return (
-
+
);
},
@@ -114,7 +114,7 @@ export const AvatarGroup: Story = {
return (
{[...Array(4)].map((_, i) => (
-
+
))}
);
@@ -125,10 +125,10 @@ export const Text: Story = {
render() {
return (
-
-
-
-
+
+
+
+
);
},
@@ -138,7 +138,7 @@ export const Button: Story = {
render() {
return (
-
+
);
},
@@ -148,8 +148,8 @@ export const Input: Story = {
render() {
return (
-
-
+
+
);
},
@@ -160,18 +160,18 @@ export const Form: Story = {
return (
-
-
+
+
-
-
+
+
-
-
+
+
-
+
);
},
@@ -181,13 +181,13 @@ export const ProductCard: Story = {
render() {
return (
-
+
-
-
-
+
+
+
-
+
);
},
diff --git a/packages/propel/src/tabs/tabs.stories.tsx b/packages/propel/src/tabs/tabs.stories.tsx
index a0a5614fbd1..83e0716568e 100644
--- a/packages/propel/src/tabs/tabs.stories.tsx
+++ b/packages/propel/src/tabs/tabs.stories.tsx
@@ -2,7 +2,7 @@ import { useState } from "react";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { Settings, User, Bell } from "lucide-react";
import { HomeIcon } from "../icons/workspace/home-icon";
-import { Tabs } from "./tabs";
+import { Tabs, TabsList, TabsTrigger, TabsContent, TabsIndicator } from "./tabs";
type TabOption = {
label: string;
@@ -20,10 +20,10 @@ const meta: Meta = {
title: "Components/Tabs",
component: Tabs,
subcomponents: {
- TabsList: Tabs.List,
- TabsTrigger: Tabs.Trigger,
- TabsContent: Tabs.Content,
- TabsIndicator: Tabs.Indicator,
+ TabsList,
+ TabsTrigger,
+ TabsContent,
+ TabsIndicator,
},
parameters: {
layout: "centered",
@@ -41,21 +41,21 @@ export const Basic: Story = {
return (
-
+
{tabOptions.map((option) => (
-
+
{option.label}
-
+
))}
-
-
+
+
{tabOptions.map((option) => (
-
+
{option.label}
Content for the {option.label.toLowerCase()} tab.
-
+
))}
@@ -77,14 +77,14 @@ export const Sizes: Story = {
{sizeLabels[size]}
-
+
{tabOptions.map((option) => (
-
+
{option.label}
-
+
))}
-
-
+
+
))}
@@ -103,18 +103,18 @@ export const Controlled: Story = {
Active tab: {activeTab}
value && setActiveTab(value)}>
-
+
{tabOptions.map((option) => (
-
+
{option.label}
-
+
))}
-
-
+
+
{tabOptions.map((option) => (
-
+
Content for {option.label}
-
+
))}
@@ -127,23 +127,23 @@ export const DisabledTab: Story = {
return (
-
- Account
-
+
+ Account
+
Password
-
- Notifications
-
-
-
+
+ Notifications
+
+
+
Account content
-
-
+
+
Password content (disabled)
-
-
+
+
Notifications content
-
+
);
@@ -162,19 +162,19 @@ export const WithIcons: Story = {
return (
-
+
{tabsWithIcons.map((tab) => (
-
+
{tab.label}
-
+
))}
-
-
+
+
{tabsWithIcons.map((tab) => (
-
+
Content for {tab.label}
-
+
))}
@@ -194,18 +194,18 @@ export const IconsOnly: Story = {
return (
-
+
{iconTabs.map((tab) => (
-
+
-
+
))}
-
-
+
+
{iconTabs.map((tab) => (
-
+
Content for {tab.value}
-
+
))}
@@ -245,9 +245,9 @@ export const DynamicTabs: Story = {
value && setActiveTab(value)}>
-
+
{tabs.map((tab) => (
-
+
{tab.label}
{tabs.length > 1 && (
)}
-
+
))}
-
-
+
+
{tabs.map((tab) => (
-
+
Content for {tab.label}
-
+
))}
@@ -280,22 +280,22 @@ export const FullWidth: Story = {
return (
-
-
+
+
Account
-
-
+
+
Password
-
-
+
+
Notifications
-
-
-
+
+
+
{tabOptions.map((option) => (
-
+
Content for {option.label}
-
+
))}
@@ -308,15 +308,15 @@ export const WithComplexContent: Story = {
return (
-
+
{tabOptions.map((option) => (
-
+
{option.label}
-
+
))}
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
+
);
diff --git a/packages/propel/src/tabs/tabs.tsx b/packages/propel/src/tabs/tabs.tsx
index 08cec2d9544..33e1c540357 100644
--- a/packages/propel/src/tabs/tabs.tsx
+++ b/packages/propel/src/tabs/tabs.tsx
@@ -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 & React.RefAttributes>
-> & {
- List: React.ForwardRefExoticComponent<
- React.ComponentProps & React.RefAttributes>
- >;
- Trigger: React.ForwardRefExoticComponent<
- React.ComponentProps & { size?: "sm" | "md" | "lg" } & React.RefAttributes<
- React.ElementRef
- >
- >;
- Content: React.ForwardRefExoticComponent<
- React.ComponentProps & React.RefAttributes>
- >;
- Indicator: React.ForwardRefExoticComponent & React.RefAttributes>;
-};
-
const TabsRoot = React.forwardRef(function TabsRoot(
{ className, ...props }: React.ComponentProps,
ref: React.ForwardedRef>
@@ -104,11 +87,10 @@ const TabsIndicator = React.forwardRef(function TabsIndicator(
);
});
-export const Tabs = Object.assign(TabsRoot, {
- List: TabsList,
- Trigger: TabsTrigger,
- Content: TabsContent,
- Indicator: TabsIndicator,
-}) satisfies TabsCompound;
+TabsRoot.displayName = "Tabs";
+TabsList.displayName = "TabsList";
+TabsTrigger.displayName = "TabsTrigger";
+TabsContent.displayName = "TabsContent";
+TabsIndicator.displayName = "TabsIndicator";
-export { TabsList, TabsTrigger, TabsContent, TabsIndicator };
+export { TabsRoot as Tabs, TabsList, TabsTrigger, TabsContent, TabsIndicator };
diff --git a/packages/propel/src/toolbar/index.ts b/packages/propel/src/toolbar/index.ts
index da2a48965eb..fbd1121e9c3 100644
--- a/packages/propel/src/toolbar/index.ts
+++ b/packages/propel/src/toolbar/index.ts
@@ -1,4 +1,4 @@
-export { Toolbar } from "./toolbar";
+export { Toolbar, ToolbarGroup, ToolbarItem, ToolbarSeparator, ToolbarSubmitButton } from "./toolbar";
export type {
ToolbarProps,
ToolbarGroupProps,
diff --git a/packages/propel/src/toolbar/toolbar.stories.tsx b/packages/propel/src/toolbar/toolbar.stories.tsx
index b663710633e..eeb7783f8a1 100644
--- a/packages/propel/src/toolbar/toolbar.stories.tsx
+++ b/packages/propel/src/toolbar/toolbar.stories.tsx
@@ -17,7 +17,7 @@ import {
Lock,
} from "lucide-react";
import { ListLayoutIcon } from "../icons/layouts/list-icon";
-import { Toolbar } from "./toolbar";
+import { Toolbar, ToolbarGroup, ToolbarItem, ToolbarSeparator, ToolbarSubmitButton } from "./toolbar";
const meta = {
title: "Components/Toolbar",
@@ -40,30 +40,30 @@ export const Default: Story = {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -76,21 +76,21 @@ export const WithActiveStates: Story = {
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
@@ -106,23 +106,23 @@ export const CommentToolbar: Story = {
{/* Access Specifier */}
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
Comment
+
Comment
diff --git a/packages/propel/src/toolbar/toolbar.tsx b/packages/propel/src/toolbar/toolbar.tsx
index b939ad1cafe..dc657f5fd77 100644
--- a/packages/propel/src/toolbar/toolbar.tsx
+++ b/packages/propel/src/toolbar/toolbar.tsx
@@ -164,12 +164,5 @@ ToolbarItem.displayName = "ToolbarItem";
ToolbarSeparator.displayName = "ToolbarSeparator";
ToolbarSubmitButton.displayName = "ToolbarSubmitButton";
-// compound components
-const Toolbar = Object.assign(ToolbarRoot, {
- Group: ToolbarGroup,
- Item: ToolbarItem,
- Separator: ToolbarSeparator,
- SubmitButton: ToolbarSubmitButton,
-});
-export { Toolbar };
+export { ToolbarRoot as Toolbar, ToolbarGroup, ToolbarItem, ToolbarSeparator, ToolbarSubmitButton };