diff --git a/.changeset/warm-ducks-notice.md b/.changeset/warm-ducks-notice.md new file mode 100644 index 0000000000..95e28b0836 --- /dev/null +++ b/.changeset/warm-ducks-notice.md @@ -0,0 +1,39 @@ +--- +'@backstage/ui': minor +--- + +**BREAKING**: Removed `Collapsible` component. Migrate to `Accordion` or use React Aria `Disclosure`. + +## Migration Path 1: Accordion (Opinionated Styled Component) + +Accordion provides preset styling with a similar component structure. + +```diff +- import { Collapsible } from '@backstage/ui'; ++ import { Accordion, AccordionTrigger, AccordionPanel } from '@backstage/ui'; + +- +- } /> +- Content +- + ++ ++ ++ Content ++ +``` + +CSS classes: `.bui-CollapsibleRoot` → `.bui-Accordion`, `.bui-CollapsibleTrigger` → `.bui-AccordionTrigger` (now on heading element), `.bui-CollapsiblePanel` → `.bui-AccordionPanel` + +## Migration Path 2: React Aria Disclosure (Full Customization) + +For custom styling without preset styles: + +```tsx +import { Disclosure, Button, DisclosurePanel } from 'react-aria-components'; + + + + Content +; +``` diff --git a/docs-ui/src/content/accordion.mdx b/docs-ui/src/content/accordion.mdx new file mode 100644 index 0000000000..2694f8d144 --- /dev/null +++ b/docs-ui/src/content/accordion.mdx @@ -0,0 +1,128 @@ +import { PropsTable } from '@/components/PropsTable'; +import { Snippet } from '@/components/Snippet'; +import { CodeBlock } from '@/components/CodeBlock'; +import { AccordionSnippet } from '@/snippets/stories-snippets'; +import { + accordionPropDefs, + accordionTriggerPropDefs, + accordionPanelPropDefs, + accordionGroupPropDefs, + accordionUsageSnippet, + accordionWithSubtitleSnippet, + accordionCustomTriggerSnippet, + accordionDefaultExpandedSnippet, + accordionGroupSingleOpenSnippet, + accordionGroupMultipleOpenSnippet, +} from './accordion.props'; +import { PageTitle } from '@/components/PageTitle'; +import { Theming } from '@/components/Theming'; +import { ChangelogComponent } from '@/components/ChangelogComponent'; + + + +} + code={accordionUsageSnippet} +/> + +## Usage + + + +## API reference + +### Accordion + +Root container for the accordion. Renders a `
` element. + + + +### AccordionTrigger + +Trigger component with built-in animated chevron icon. Renders a heading element (defaults to `

`, configurable via `level` prop) wrapping a ` - )} /> - Your content -`; - -export const collapsibleDefaultSnippet = ` - ( - - )} /> - - - It's the edge of the world and all of Western civilization - The sun may rise in the East, at least it settled in a final location - It's understood that Hollywood sells Californication - - -`; - -export const collapsibleTriggerSnippet = ` - )} /> - - - It's the edge of the world and all of Western civilization - The sun may rise in the East, at least it settled in a final location - It's understood that Hollywood sells Californication - - -`; diff --git a/docs-ui/src/snippets/stories-snippets.tsx b/docs-ui/src/snippets/stories-snippets.tsx index 5e50c03558..0cb6119ce6 100644 --- a/docs-ui/src/snippets/stories-snippets.tsx +++ b/docs-ui/src/snippets/stories-snippets.tsx @@ -15,7 +15,7 @@ import * as SelectStories from '../../../packages/ui/src/components/Select/Selec import * as MenuStories from '../../../packages/ui/src/components/Menu/Menu.stories'; import * as LinkStories from '../../../packages/ui/src/components/Link/Link.stories'; import * as AvatarStories from '../../../packages/ui/src/components/Avatar/Avatar.stories'; -import * as CollapsibleStories from '../../../packages/ui/src/components/Collapsible/Collapsible.stories'; +import * as AccordionStories from '../../../packages/ui/src/components/Accordion/Accordion.stories'; import * as DialogStories from '../../../packages/ui/src/components/Dialog/Dialog.stories'; import * as RadioGroupStories from '../../../packages/ui/src/components/RadioGroup/RadioGroup.stories'; import * as TabsStories from '../../../packages/ui/src/components/Tabs/Tabs.stories'; @@ -62,7 +62,7 @@ export const SelectSnippet = createSnippetComponent(SelectStories); export const MenuSnippet = createSnippetComponent(MenuStories); export const LinkSnippet = createSnippetComponent(LinkStories); export const AvatarSnippet = createSnippetComponent(AvatarStories); -export const CollapsibleSnippet = createSnippetComponent(CollapsibleStories); +export const AccordionSnippet = createSnippetComponent(AccordionStories); export const DialogSnippet = createSnippetComponent(DialogStories); export const RadioGroupSnippet = createSnippetComponent(RadioGroupStories); export const TabsSnippet = createSnippetComponent(TabsStories); diff --git a/docs-ui/src/utils/changelog.ts b/docs-ui/src/utils/changelog.ts index ef2e6c9fb9..05a06fdb9f 100644 --- a/docs-ui/src/utils/changelog.ts +++ b/docs-ui/src/utils/changelog.ts @@ -13,6 +13,7 @@ export type Component = | 'datatable' | 'select' | 'collapsible' + | 'accordion' | 'checkbox' | 'container' | 'link' diff --git a/docs-ui/src/utils/data.ts b/docs-ui/src/utils/data.ts index ae150b4c1e..de369043d1 100644 --- a/docs-ui/src/utils/data.ts +++ b/docs-ui/src/utils/data.ts @@ -24,6 +24,10 @@ export const layoutComponents: Page[] = [ ]; export const components: Page[] = [ + { + title: 'Accordion', + slug: 'accordion', + }, { title: 'Avatar', slug: 'avatar', @@ -48,10 +52,6 @@ export const components: Page[] = [ title: 'Checkbox', slug: 'checkbox', }, - { - title: 'Collapsible', - slug: 'collapsible', - }, { title: 'Dialog', slug: 'dialog', diff --git a/packages/ui/report.api.md b/packages/ui/report.api.md index bfb0604a36..c1e1a309cc 100644 --- a/packages/ui/report.api.md +++ b/packages/ui/report.api.md @@ -6,12 +6,14 @@ import { ButtonProps as ButtonProps_2 } from 'react-aria-components'; import { CellProps as CellProps_2 } from 'react-aria-components'; import { CheckboxProps as CheckboxProps_2 } from 'react-aria-components'; -import { Collapsible as Collapsible_2 } from '@base-ui-components/react/collapsible'; import { ColumnProps as ColumnProps_2 } from 'react-aria-components'; import { ComponentProps } from 'react'; import type { ComponentPropsWithRef } from 'react'; import { DetailedHTMLProps } from 'react'; import type { DialogTriggerProps as DialogTriggerProps_2 } from 'react-aria-components'; +import type { DisclosureGroupProps } from 'react-aria-components'; +import type { DisclosurePanelProps } from 'react-aria-components'; +import type { DisclosureProps } from 'react-aria-components'; import type { ElementType } from 'react'; import { ForwardRefExoticComponent } from 'react'; import type { HeadingProps } from 'react-aria-components'; @@ -51,6 +53,57 @@ import type { TextFieldProps as TextFieldProps_2 } from 'react-aria-components'; import { TooltipProps as TooltipProps_2 } from 'react-aria-components'; import { TooltipTriggerComponentProps } from 'react-aria-components'; +// @public (undocumented) +export const Accordion: ForwardRefExoticComponent< + AccordionProps & RefAttributes +>; + +// @public (undocumented) +export const AccordionGroup: ForwardRefExoticComponent< + AccordionGroupProps & RefAttributes +>; + +// @public +export interface AccordionGroupProps extends DisclosureGroupProps { + allowsMultiple?: boolean; + // (undocumented) + className?: string; +} + +// @public (undocumented) +export const AccordionPanel: ForwardRefExoticComponent< + AccordionPanelProps & RefAttributes +>; + +// @public +export interface AccordionPanelProps extends DisclosurePanelProps { + // (undocumented) + className?: string; +} + +// @public +export interface AccordionProps extends DisclosureProps { + // (undocumented) + className?: string; +} + +// @public (undocumented) +export const AccordionTrigger: ForwardRefExoticComponent< + AccordionTriggerProps & RefAttributes +>; + +// @public +export interface AccordionTriggerProps extends HeadingProps { + // (undocumented) + children?: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + subtitle?: string; + // (undocumented) + title?: string; +} + // @public (undocumented) export type AlignItems = 'stretch' | 'start' | 'center' | 'end'; @@ -279,25 +332,6 @@ export interface CheckboxProps extends CheckboxProps_2 { // @public export type ClassNamesMap = Record; -// @public -export const Collapsible: { - Root: ForwardRefExoticComponent< - Omit, 'ref'> & - RefAttributes - >; - Trigger: ForwardRefExoticComponent< - Omit< - Collapsible_2.Trigger.Props & RefAttributes, - 'ref' - > & - RefAttributes - >; - Panel: ForwardRefExoticComponent< - Omit, 'ref'> & - RefAttributes - >; -}; - // @public (undocumented) export const Column: (props: ColumnProps) => JSX_2.Element; @@ -417,13 +451,6 @@ export const componentDefinitions: { readonly selected: readonly [true, false]; }; }; - readonly Collapsible: { - readonly classNames: { - readonly root: 'bui-CollapsibleRoot'; - readonly trigger: 'bui-CollapsibleTrigger'; - readonly panel: 'bui-CollapsiblePanel'; - }; - }; readonly Container: { readonly classNames: { readonly root: 'bui-Container'; @@ -440,6 +467,18 @@ export const componentDefinitions: { readonly footer: 'bui-DialogFooter'; }; }; + readonly Accordion: { + readonly classNames: { + readonly root: 'bui-Accordion'; + readonly trigger: 'bui-AccordionTrigger'; + readonly triggerButton: 'bui-AccordionTriggerButton'; + readonly triggerTitle: 'bui-AccordionTriggerTitle'; + readonly triggerSubtitle: 'bui-AccordionTriggerSubtitle'; + readonly triggerIcon: 'bui-AccordionTriggerIcon'; + readonly panel: 'bui-AccordionPanel'; + readonly group: 'bui-AccordionGroup'; + }; + }; readonly FieldError: { readonly classNames: { readonly root: 'bui-FieldError'; diff --git a/packages/ui/src/components/Accordion/Accordion.module.css b/packages/ui/src/components/Accordion/Accordion.module.css new file mode 100644 index 0000000000..a86400986d --- /dev/null +++ b/packages/ui/src/components/Accordion/Accordion.module.css @@ -0,0 +1,93 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@layer tokens, base, components, utilities; + +@layer components { + .bui-Accordion { + width: 100%; + background-color: var(--bui-bg-surface-1); + border-radius: var(--bui-radius-3); + padding: var(--bui-space-3); + } + + .bui-AccordionTrigger { + all: unset; + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + } + + .bui-AccordionTriggerButton { + all: unset; + width: 100%; + color: var(--bui-fg-primary); + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + text-align: left; + + &:focus-visible { + outline: none; + transition: none; + box-shadow: inset 0 0 0 2px var(--bui-ring); + } + + &[data-disabled='true'] { + background-color: transparent; + color: var(--bui-fg-disabled); + cursor: not-allowed; + } + } + + .bui-AccordionTriggerTitle { + font-size: var(--bui-font-size-4); + font-weight: var(--bui-font-weight-bold); + line-height: 140%; + } + + .bui-AccordionTriggerSubtitle { + font-size: var(--bui-font-size-2); + line-height: 140%; + color: var(--bui-fg-secondary); + } + + .bui-AccordionTriggerIcon { + transition: transform 150ms ease-out; + flex-shrink: 0; + width: 1rem; + height: 1rem; + + [data-expanded='true'] & { + transform: rotate(180deg); + } + } + + .bui-AccordionPanel { + [data-expanded='true'] & { + padding-top: var(--bui-space-1); + } + } + + .bui-AccordionGroup { + display: flex; + flex-direction: column; + gap: var(--bui-space-3); + width: 100%; + } +} diff --git a/packages/ui/src/components/Accordion/Accordion.stories.tsx b/packages/ui/src/components/Accordion/Accordion.stories.tsx new file mode 100644 index 0000000000..6640bd5d6a --- /dev/null +++ b/packages/ui/src/components/Accordion/Accordion.stories.tsx @@ -0,0 +1,177 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { Meta, StoryObj } from '@storybook/react-vite'; +import { + Accordion, + AccordionTrigger, + AccordionPanel, + AccordionGroup, +} from './Accordion'; +import { Box } from '../Box'; +import { Text } from '../Text'; + +const Content = () => ( + + + It's the edge of the world and all of Western civilization + + + The sun may rise in the East, at least it settled in a final location + + It's understood that Hollywood sells Californication + +); + +const meta = { + title: 'Backstage UI/Accordion', + component: Accordion, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + + + + ), +}; + +export const WithSubtitle: Story = { + render: () => ( + + + + + + + ), +}; + +export const CustomTrigger: Story = { + render: () => ( + + + + + Custom Multi-line Trigger + + + Click to expand additional details and configuration options + + + + + + + + ), +}; + +export const DefaultExpanded: Story = { + render: () => ( + + + + + + + ), +}; + +export const GroupSingleOpen: Story = { + render: () => ( + + + + + + + It's the edge of the world and all of Western civilization + + + + + + + + + + The sun may rise in the East, at least it settled in a final + location + + + + + + + + + + It's understood that Hollywood sells Californication + + + + + + ), +}; + +export const GroupMultipleOpen: Story = { + render: () => ( + + + + + + + It's the edge of the world and all of Western civilization + + + + + + + + + + The sun may rise in the East, at least it settled in a final + location + + + + + + + + + + It's understood that Hollywood sells Californication + + + + + + ), +}; diff --git a/packages/ui/src/components/Accordion/Accordion.tsx b/packages/ui/src/components/Accordion/Accordion.tsx new file mode 100644 index 0000000000..3f35ab7554 --- /dev/null +++ b/packages/ui/src/components/Accordion/Accordion.tsx @@ -0,0 +1,153 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { forwardRef } from 'react'; +import { + Disclosure as RADisclosure, + Button as RAButton, + DisclosurePanel as RADisclosurePanel, + DisclosureGroup as RADisclosureGroup, + Heading as RAHeading, +} from 'react-aria-components'; +import { RiArrowDownSLine } from '@remixicon/react'; +import clsx from 'clsx'; +import type { + AccordionProps, + AccordionTriggerProps, + AccordionPanelProps, + AccordionGroupProps, +} from './types'; +import { useStyles } from '../../hooks/useStyles'; +import styles from './Accordion.module.css'; +import { Flex } from '../Flex'; + +/** @public */ +export const Accordion = forwardRef< + React.ElementRef, + AccordionProps +>(({ className, ...props }, ref) => { + const { classNames, cleanedProps } = useStyles('Accordion', props); + + return ( + + ); +}); + +Accordion.displayName = 'Accordion'; + +/** @public */ +export const AccordionTrigger = forwardRef< + React.ElementRef, + AccordionTriggerProps +>(({ className, title, subtitle, children, ...props }, ref) => { + const { classNames, cleanedProps } = useStyles('Accordion', props); + + return ( + + + {children ? ( + children + ) : ( + + + {title} + + {subtitle && ( + + {subtitle} + + )} + + )} + + + + + ); +}); + +AccordionTrigger.displayName = 'AccordionTrigger'; + +/** @public */ +export const AccordionPanel = forwardRef< + React.ElementRef, + AccordionPanelProps +>(({ className, ...props }, ref) => { + const { classNames, cleanedProps } = useStyles('Accordion', props); + + return ( + + ); +}); + +AccordionPanel.displayName = 'AccordionPanel'; + +/** @public */ +export const AccordionGroup = forwardRef< + React.ElementRef, + AccordionGroupProps +>(({ className, allowsMultiple = false, ...props }, ref) => { + const { classNames, cleanedProps } = useStyles('Accordion', props); + + return ( + + ); +}); + +AccordionGroup.displayName = 'AccordionGroup'; diff --git a/packages/ui/src/components/Collapsible/index.ts b/packages/ui/src/components/Accordion/index.ts similarity index 73% rename from packages/ui/src/components/Collapsible/index.ts rename to packages/ui/src/components/Accordion/index.ts index 6a7f8e8816..cd34b4bc87 100644 --- a/packages/ui/src/components/Collapsible/index.ts +++ b/packages/ui/src/components/Accordion/index.ts @@ -14,4 +14,15 @@ * limitations under the License. */ -export { Collapsible } from './Collapsible'; +export { + Accordion, + AccordionTrigger, + AccordionPanel, + AccordionGroup, +} from './Accordion'; +export type { + AccordionProps, + AccordionTriggerProps, + AccordionPanelProps, + AccordionGroupProps, +} from './types'; diff --git a/packages/ui/src/components/Accordion/types.ts b/packages/ui/src/components/Accordion/types.ts new file mode 100644 index 0000000000..06c8549ebd --- /dev/null +++ b/packages/ui/src/components/Accordion/types.ts @@ -0,0 +1,62 @@ +/* + * Copyright 2025 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { + DisclosureProps as RADisclosureProps, + HeadingProps as RAHeadingProps, + DisclosurePanelProps as RADisclosurePanelProps, + DisclosureGroupProps as RADisclosureGroupProps, +} from 'react-aria-components'; + +/** + * Props for the Accordion component. + * @public + */ +export interface AccordionProps extends RADisclosureProps { + className?: string; +} + +/** + * Props for the AccordionTrigger component. + * @public + */ +export interface AccordionTriggerProps extends RAHeadingProps { + className?: string; + title?: string; + subtitle?: string; + children?: React.ReactNode; +} + +/** + * Props for the AccordionPanel component. + * @public + */ +export interface AccordionPanelProps extends RADisclosurePanelProps { + className?: string; +} + +/** + * Props for the AccordionGroup component. + * @public + */ +export interface AccordionGroupProps extends RADisclosureGroupProps { + className?: string; + /** + * Whether multiple accordions can be expanded at the same time. + * @defaultValue false + */ + allowsMultiple?: boolean; +} diff --git a/packages/ui/src/components/Collapsible/Collapsible.module.css b/packages/ui/src/components/Collapsible/Collapsible.module.css deleted file mode 100644 index d3b394011c..0000000000 --- a/packages/ui/src/components/Collapsible/Collapsible.module.css +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2025 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -@layer tokens, base, components, utilities; - -@layer components { - .bui-CollapsiblePanel { - display: flex; - height: var(--collapsible-panel-height); - overflow: hidden; - transition: all 150ms ease-out; - - &[data-starting-style], - &[data-ending-style] { - height: 0; - } - } -} diff --git a/packages/ui/src/components/Collapsible/Collapsible.stories.tsx b/packages/ui/src/components/Collapsible/Collapsible.stories.tsx deleted file mode 100644 index 47b76f2f56..0000000000 --- a/packages/ui/src/components/Collapsible/Collapsible.stories.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2025 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { Meta, StoryObj } from '@storybook/react-vite'; -import { Collapsible } from './Collapsible'; -import { Button } from '../Button'; -import { Box } from '../Box'; -import { Text } from '../Text'; -import { RiArrowDownSLine, RiArrowUpSLine } from '@remixicon/react'; - -const meta = { - title: 'Backstage UI/Collapsible', - component: Collapsible.Root, -} satisfies Meta; - -export default meta; -type Story = StoryObj; - -export const Default: Story = { - args: { - style: { - display: 'flex', - flexDirection: 'column', - gap: 'var(--bui-space-2)', - alignItems: 'center', - }, - children: ( - <> - ( - - )} - /> - - - - It's the edge of the world and all of Western civilization - - - The sun may rise in the East, at least it settled in a final - location - - It's understood that Hollywood sells Californication - - - - ), - }, -}; - -export const Open: Story = { - args: { - ...Default.args, - defaultOpen: true, - }, -}; diff --git a/packages/ui/src/components/Collapsible/Collapsible.tsx b/packages/ui/src/components/Collapsible/Collapsible.tsx deleted file mode 100644 index c9417d2019..0000000000 --- a/packages/ui/src/components/Collapsible/Collapsible.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2025 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { forwardRef } from 'react'; -import { Collapsible as CollapsiblePrimitive } from '@base-ui-components/react/collapsible'; -import clsx from 'clsx'; -import { useStyles } from '../../hooks/useStyles'; -import styles from './Collapsible.module.css'; - -const CollapsibleRoot = forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => { - const { classNames, cleanedProps } = useStyles('Collapsible', props); - - return ( - - ); -}); -CollapsibleRoot.displayName = CollapsiblePrimitive.Root.displayName; - -const CollapsibleTrigger = forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => { - const { classNames, cleanedProps } = useStyles('Collapsible', props); - - return ( - - ); -}); -CollapsibleTrigger.displayName = CollapsiblePrimitive.Trigger.displayName; - -const CollapsiblePanel = forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => { - const { classNames, cleanedProps } = useStyles('Collapsible', props); - - return ( - - ); -}); -CollapsiblePanel.displayName = CollapsiblePrimitive.Panel.displayName; - -/** - * Collapsible is a component that allows you to collapse and expand content. - * It is a wrapper around the CollapsiblePrimitive component from base-ui-components. - * - * @public - */ -export const Collapsible = { - Root: CollapsibleRoot, - Trigger: CollapsibleTrigger, - Panel: CollapsiblePanel, -}; diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 1bb10cfbd1..baa4c3e5dc 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -30,7 +30,7 @@ export * from './components/Container'; export * from './components/Avatar'; export * from './components/Button'; export * from './components/Card'; -export * from './components/Collapsible'; +export * from './components/Accordion'; export * from './components/Dialog'; export * from './components/FieldLabel'; export * from './components/Header'; diff --git a/packages/ui/src/utils/componentDefinitions.ts b/packages/ui/src/utils/componentDefinitions.ts index 8f44e1e730..9b18a6feaf 100644 --- a/packages/ui/src/utils/componentDefinitions.ts +++ b/packages/ui/src/utils/componentDefinitions.ts @@ -96,13 +96,6 @@ export const componentDefinitions = { selected: [true, false] as const, }, }, - Collapsible: { - classNames: { - root: 'bui-CollapsibleRoot', - trigger: 'bui-CollapsibleTrigger', - panel: 'bui-CollapsiblePanel', - }, - }, Container: { classNames: { root: 'bui-Container', @@ -119,6 +112,18 @@ export const componentDefinitions = { footer: 'bui-DialogFooter', }, }, + Accordion: { + classNames: { + root: 'bui-Accordion', + trigger: 'bui-AccordionTrigger', + triggerButton: 'bui-AccordionTriggerButton', + triggerTitle: 'bui-AccordionTriggerTitle', + triggerSubtitle: 'bui-AccordionTriggerSubtitle', + triggerIcon: 'bui-AccordionTriggerIcon', + panel: 'bui-AccordionPanel', + group: 'bui-AccordionGroup', + }, + }, FieldError: { classNames: { root: 'bui-FieldError',