Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Below is a list of the components available in this library. Each component has
- [BBBInput](./src/components/Input/README.md)
- [BBBModal](./src/components/Modal//README.md)
- [BBBNavigation](./src/components/Navigation/README.md)
- [BBBScrollArea](./src/components/ScrollArea/README.md)
- [BBBSearch](./src/components/Search/README.md)
- [BBBSelect](./src/components/Select/README.md)
- [BBBSpinner](./src/components/Spinner//README.md)
Expand Down Expand Up @@ -96,6 +97,10 @@ The following table lists the supported CSS variables for color overriding, extr
| `--color-hover-dark` | No | #0C57A7 |
| `--color-hover-light` | No | #D4E5FA |
| `--color-hover-neutral` | No | #DCE4EC |
| `--color-border-focus-ring`| No | rgba(29, 101, 212, 0.15) |
| `--color-icon-default-dark`| No | rgba(255, 255, 255, 0.35) |
| `--color-overlay` | No | rgba(0, 0, 0, 0.75) |
| `--color-shadow-default` | No | rgb(0 35 11 / 20%) |

**Example Usage**:
```css
Expand All @@ -107,6 +112,28 @@ The following table lists the supported CSS variables for color overriding, extr

If you need to override colors for specific components or add new variables, refer to the component's `styles.ts` file for implementation details.

### Importing Color Tokens in JS

In addition to CSS variables, the same color tokens used internally by every component are also
exported as a nested `colors` object, for use directly in JS/TS (e.g. in your own
styled-components):

```jsx
// From the package root
import { colors } from '@bigbluebutton/bbb-ui-components-react';

// Or from the dedicated, tree-shakeable subpath
import { colors } from '@bigbluebutton/bbb-ui-components-react/colors';

const StyledDiv = styled.div`
color: ${colors.text.default};
background: ${colors.background.white};
`;
```

`colors` is grouped the same way as the table above: `neutral`, `brand`, `semantic`, `background`,
`border`, `text`, `icon`, `hover`.

## Installation

You can install the library directly from npm:
Expand Down
20 changes: 20 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@
"require": "./dist/components/Navigation.js",
"default": "./dist/components/Navigation.js"
},
"./ScrollArea": {
"types": "./dist/types/components/ScrollArea/index.d.ts",
"node": "./dist/components/ScrollArea.js",
"import": "./dist/esm/components/ScrollArea/index.js",
"require": "./dist/components/ScrollArea.js",
"default": "./dist/components/ScrollArea.js"
},
"./Search": {
"types": "./dist/types/components/Search/index.d.ts",
"node": "./dist/components/Search.js",
Expand Down Expand Up @@ -120,6 +127,13 @@
"require": "./dist/components/Typography.js",
"default": "./dist/components/Typography.js"
},
"./colors": {
"types": "./dist/types/stylesheets/colors.d.ts",
"node": "./dist/components/colors.js",
"import": "./dist/esm/stylesheets/colors.js",
"require": "./dist/components/colors.js",
"default": "./dist/components/colors.js"
},
"./dist/components": {
"types": "./dist/types/index.d.ts",
"require": "./dist/components/index.js",
Expand Down Expand Up @@ -188,6 +202,9 @@
"Navigation": [
"dist/types/components/Navigation/index.d.ts"
],
"ScrollArea": [
"dist/types/components/ScrollArea/index.d.ts"
],
"Search": [
"dist/types/components/Search/index.d.ts"
],
Expand All @@ -208,6 +225,9 @@
],
"Typography": [
"dist/types/components/Typography/index.d.ts"
],
"colors": [
"dist/types/stylesheets/colors.d.ts"
]
}
},
Expand Down
32 changes: 22 additions & 10 deletions src/components/Accordion/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,27 @@ import { MdFavorite } from 'react-icons/md';
</BBBAccordion>
```

### Accordion with a right-aligned button header

```jsx
import { BBBAccordion } from 'bbb-ui-components-react';
import { MdEdit } from 'react-icons/md';

<BBBAccordion title="Right-aligned" buttonHeader={<MdEdit />} buttonHeaderPosition="right">
<p>Content for the accordion.</p>
</BBBAccordion>
```

## 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. |
31 changes: 30 additions & 1 deletion src/components/Accordion/component.stories.tsx
Original file line number Diff line number Diff line change
@@ -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 = {
Expand Down Expand Up @@ -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.',
Expand Down Expand Up @@ -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: <MdEdit aria-label="Edit" />,
buttonHeaderPosition: BUTTON_HEADER_POSITIONS.RIGHT,
children: (
<div style={{ padding: '1rem' }}>
<Typography>Accordion content goes here.</Typography>
</div>
),
},
};
7 changes: 5 additions & 2 deletions src/components/Accordion/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -21,6 +21,7 @@ function Accordion({
ariaLabelledBy,
ariaDescribedBy,
buttonHeader = null,
buttonHeaderPosition = DEFAULT_BUTTON_HEADER_POSITION,
children,
}: AccordionProps): JSX.Element {
const [isExpanded, setIsExpanded] = useState(false);
Expand All @@ -38,7 +39,9 @@ function Accordion({
<MdExpandMore />
</Styled.ExpandIcon>
<Styled.TitleText>{title}</Styled.TitleText>
{buttonHeader}
<Styled.ButtonHeaderWrapper $position={buttonHeaderPosition}>
{buttonHeader}
</Styled.ButtonHeaderWrapper>
</Styled.ButtonContent>
</Styled.ExpandButton>
);
Expand Down
10 changes: 10 additions & 0 deletions src/components/Accordion/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
8 changes: 7 additions & 1 deletion src/components/Accordion/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -51,6 +51,12 @@ export const ExpandIcon = styled.div<StyledExpandIcon>`
}
`;

export const ButtonHeaderWrapper = styled.span<StyledButtonHeaderWrapper>`
display: flex;
align-items: center;
margin-left: ${({ $position }) => ($position === 'right' ? 'auto' : '0')};
`;

export const TitleText = styled.span`
font-size: ${fontSizeDefault};
font-weight: 400;
Expand Down
10 changes: 9 additions & 1 deletion src/components/Accordion/types.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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. */
Expand All @@ -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;
};
55 changes: 47 additions & 8 deletions src/components/Hint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,52 @@ import { BBBHint } from 'bbb-ui-components-react';
/>
```

### Uncontrolled Hint (default)

Without an `open` prop, the hint manages its own visibility and closes itself when the close button is clicked — no external state required.

```jsx
import { BBBHint } from 'bbb-ui-components-react';

<BBBHint label="This is a simple hint." />
```

### Controlled Hint

Pass `open` to drive visibility externally; the hint calls `onRequestClose` instead of hiding itself, leaving the parent in charge of updating `open`.

```jsx
import { useState } from 'react';
import { BBBHint } from 'bbb-ui-components-react';

const [open, setOpen] = useState(true);

<BBBHint
open={open}
onRequestClose={() => setOpen(false)}
label="This hint's visibility is controlled externally."
/>
```

### Hint Without a Close Button

Pass `hideCloseButton` for hints that shouldn't be manually dismissed — e.g. ones dismissed by interacting with another UI element, or tooltip-style hints with no explicit dismiss action.

```jsx
import { BBBHint } from 'bbb-ui-components-react';

<BBBHint hideCloseButton label="This hint cannot be manually dismissed." />
```

## Props

| Property | Type | Default | Description |
| ---------------- | -------------------------------- | ------- | ------------------------------------------------------------------------------------ |
| `label` | `string` | | The main text content of the hint. |
| `title` | `string` | | An optional title for the hint. If provided, a close button will be displayed. |
| `icon` | `React.ReactNode` | | An optional icon to be displayed next to the title or label. |
| `onRequestClose` | `() => void` | | A callback function to be called when the close button is clicked. |
| `children` | `React.ReactNode` | | Optional additional content to be displayed below the label. |
| `...props` | `HTMLAttributes<HTMLDivElement>` | | Any other props will be passed down to the underlying container div. |
| Property | Type | Default | Description |
| ----------------- | -------------------------------- | ------- | ------------------------------------------------------------------------------------ |
| `label` | `string` | | The main text content of the hint. |
| `title` | `string` | | An optional title shown in the header; when set, `label` renders as a separate line below instead of inline. |
| `icon` | `React.ReactNode` | | An optional icon to be displayed next to the title or label. |
| `open` | `boolean` | | Whether the hint is visible. Omit to let the hint manage its own visibility, closing itself when the close button is clicked; pass a boolean to control visibility externally. |
| `onRequestClose` | `() => void` | | A callback function to be called when the close button is clicked, in both controlled and uncontrolled mode. |
| `hideCloseButton` | `boolean` | `false` | Hides the close (X) button, for hints that shouldn't be manually dismissed. |
| `children` | `React.ReactNode` | | Optional additional content to be displayed below the label. |
| `...props` | `HTMLAttributes<HTMLDivElement>` | | Any other props will be passed down to the underlying container div. |
Loading
Loading