diff --git a/src/components/Accordion/README.md b/src/components/Accordion/README.md index 3711f94..d110204 100644 --- a/src/components/Accordion/README.md +++ b/src/components/Accordion/README.md @@ -38,15 +38,27 @@ import { MdFavorite } from 'react-icons/md'; ``` +### Accordion with a right-aligned button header + +```jsx +import { BBBAccordion } from 'bbb-ui-components-react'; +import { MdEdit } from 'react-icons/md'; + +} buttonHeaderPosition="right"> +

Content for the accordion.

+
+``` + ## Props -| Property | Type | Default | Description | -| ------------------ | -------------------------------------- | ----------- | ------------------------------------------------------------------------------ | -| `title` | `string` | | The text to be displayed in the accordion header. | -| `tooltipLabel` | `string` | `null` | An optional label for the tooltip that appears on hover. | -| `tooltipPlacement` | `import('@tippyjs/react').Placement` | `'bottom'` | The placement of the tooltip. | -| `ariaLabel` | `string` | | The accessible name for the expand button. | -| `ariaLabelledBy` | `string` | | The ID of the element that labels the expand button. | -| `ariaDescribedBy` | `string` | | The ID of the element that describes the expand button. | -| `buttonHeader` | `React.ReactNode` | `null` | Optional content to be rendered inside the button header. | -| `children` | `React.ReactNode` | | The content to be displayed when the accordion is expanded. | +| Property | Type | Default | Description | +| ----------------------- | -------------------------------------- | ----------- | ------------------------------------------------------------------------------ | +| `title` | `string` | | The text to be displayed in the accordion header. | +| `tooltipLabel` | `string` | `null` | An optional label for the tooltip that appears on hover. | +| `tooltipPlacement` | `import('@tippyjs/react').Placement` | `'bottom'` | The placement of the tooltip. | +| `ariaLabel` | `string` | | The accessible name for the expand button. | +| `ariaLabelledBy` | `string` | | The ID of the element that labels the expand button. | +| `ariaDescribedBy` | `string` | | The ID of the element that describes the expand button. | +| `buttonHeader` | `React.ReactNode` | `null` | Optional content to be rendered inside the button header. | +| `buttonHeaderPosition` | `'left' \| 'right'` | `'left'` | Position of `buttonHeader` within the header row. | +| `children` | `React.ReactNode` | | The content to be displayed when the accordion is expanded. | diff --git a/src/components/Accordion/component.stories.tsx b/src/components/Accordion/component.stories.tsx index 7b54464..7a05344 100644 --- a/src/components/Accordion/component.stories.tsx +++ b/src/components/Accordion/component.stories.tsx @@ -1,7 +1,14 @@ import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import BBBAccordion from './component'; -import { TOOLTIP_PLACEMENT_VALUES, DEFAULT_TOOLTIP_PLACEMENT } from './constants'; +import { + TOOLTIP_PLACEMENT_VALUES, + DEFAULT_TOOLTIP_PLACEMENT, + BUTTON_HEADER_POSITIONS, + BUTTON_HEADER_POSITION_VALUES, + DEFAULT_BUTTON_HEADER_POSITION, +} from './constants'; +import { MdEdit } from 'react-icons/md'; import Typography from '../Typography/component'; const meta = { @@ -44,6 +51,14 @@ const meta = { control: false, description: 'Optional React node rendered inside the button header.', }, + buttonHeaderPosition: { + control: 'select', + options: BUTTON_HEADER_POSITION_VALUES, + description: 'Position of `buttonHeader` within the header row.', + table: { + defaultValue: { summary: `${DEFAULT_BUTTON_HEADER_POSITION}` }, + }, + }, children: { control: false, description: 'Content shown when the accordion is expanded.', @@ -79,3 +94,17 @@ export const WithTooltip: Story = { ), }, }; + +/** Shows `buttonHeaderPosition="right"` pushing the button header to the far edge of the header row. */ +export const WithRightAlignedButtonHeader: Story = { + args: { + title: 'Right-aligned Button Header', + buttonHeader: , + buttonHeaderPosition: BUTTON_HEADER_POSITIONS.RIGHT, + children: ( +
+ Accordion content goes here. +
+ ), + }, +}; diff --git a/src/components/Accordion/component.tsx b/src/components/Accordion/component.tsx index 5fc0753..9524240 100644 --- a/src/components/Accordion/component.tsx +++ b/src/components/Accordion/component.tsx @@ -4,7 +4,7 @@ import * as Styled from './styles'; import { MdExpandMore } from 'react-icons/md'; import Tippy from '@tippyjs/react'; import 'tippy.js/dist/tippy.css'; -import { DEFAULT_TOOLTIP_PLACEMENT } from './constants'; +import { DEFAULT_TOOLTIP_PLACEMENT, DEFAULT_BUTTON_HEADER_POSITION } from './constants'; /** * A customizable Accordion component that allows expanding and collapsing content. @@ -21,6 +21,7 @@ function Accordion({ ariaLabelledBy, ariaDescribedBy, buttonHeader = null, + buttonHeaderPosition = DEFAULT_BUTTON_HEADER_POSITION, children, }: AccordionProps): JSX.Element { const [isExpanded, setIsExpanded] = useState(false); @@ -38,7 +39,9 @@ function Accordion({ {title} - {buttonHeader} + + {buttonHeader} + ); diff --git a/src/components/Accordion/constants.ts b/src/components/Accordion/constants.ts index 79011e3..6dff066 100644 --- a/src/components/Accordion/constants.ts +++ b/src/components/Accordion/constants.ts @@ -7,8 +7,18 @@ const TOOLTIP_PLACEMENTS = { const TOOLTIP_PLACEMENT_VALUES = Object.values(TOOLTIP_PLACEMENTS); const DEFAULT_TOOLTIP_PLACEMENT = TOOLTIP_PLACEMENTS.TOP; +const BUTTON_HEADER_POSITIONS = { + LEFT: 'left', + RIGHT: 'right', +} as const; +const BUTTON_HEADER_POSITION_VALUES = Object.values(BUTTON_HEADER_POSITIONS); +const DEFAULT_BUTTON_HEADER_POSITION = BUTTON_HEADER_POSITIONS.LEFT; + export { TOOLTIP_PLACEMENTS, TOOLTIP_PLACEMENT_VALUES, DEFAULT_TOOLTIP_PLACEMENT, + BUTTON_HEADER_POSITIONS, + BUTTON_HEADER_POSITION_VALUES, + DEFAULT_BUTTON_HEADER_POSITION, } \ No newline at end of file diff --git a/src/components/Accordion/styles.ts b/src/components/Accordion/styles.ts index 721cbb7..0850835 100644 --- a/src/components/Accordion/styles.ts +++ b/src/components/Accordion/styles.ts @@ -2,7 +2,7 @@ import styled from 'styled-components'; import { colorBackgroundLight, colorBrand1, colorTextDefault, colorWhite } from '../../stylesheets/palette'; import { fontSizeDefault } from '../../stylesheets/typography'; import { borderRadiusDefault, spacingMedium, spacingSmall } from '../../stylesheets/sizing'; -import { StyledAccordionContent, StyledExpandIcon } from './types'; +import { StyledAccordionContent, StyledExpandIcon, StyledButtonHeaderWrapper } from './types'; export const ExpandButton = styled.button` display: flex; @@ -51,6 +51,12 @@ export const ExpandIcon = styled.div` } `; +export const ButtonHeaderWrapper = styled.span` + display: flex; + align-items: center; + margin-left: ${({ $position }) => ($position === 'right' ? 'auto' : '0')}; +`; + export const TitleText = styled.span` font-size: ${fontSizeDefault}; font-weight: 400; diff --git a/src/components/Accordion/types.ts b/src/components/Accordion/types.ts index 87b09e4..2e61837 100644 --- a/src/components/Accordion/types.ts +++ b/src/components/Accordion/types.ts @@ -1,4 +1,4 @@ -import { TOOLTIP_PLACEMENT_VALUES } from './constants'; +import { TOOLTIP_PLACEMENT_VALUES, BUTTON_HEADER_POSITION_VALUES } from './constants'; import * as React from 'react'; export interface StyledExpandIcon { @@ -10,7 +10,12 @@ export interface StyledAccordionContent { $scrollHeight: number; } +export interface StyledButtonHeaderWrapper { + $position: ButtonHeaderPositionType; +} + type TooltipPlacementType = typeof TOOLTIP_PLACEMENT_VALUES[number]; +type ButtonHeaderPositionType = typeof BUTTON_HEADER_POSITION_VALUES[number]; export interface AccordionProps { /** The text to be displayed in the accordion header. */ @@ -34,6 +39,9 @@ export interface AccordionProps { /** Optional React node rendered inside the button header, alongside the title. @default null */ buttonHeader?: React.ReactNode; + /** Position of `buttonHeader` within the header row. @default 'left' */ + buttonHeaderPosition?: ButtonHeaderPositionType; + /** Content shown when the accordion is expanded. */ children?: React.ReactNode; };