From 50ab5a4b65d7429271bf3698aeea90d826330ea8 Mon Sep 17 00:00:00 2001 From: Arthurk12 Date: Wed, 16 Sep 2026 20:07:32 -0300 Subject: [PATCH 1/7] feat(BBBToast): add notification card component Add BBBToast, the presentational card for transient notifications: an icon badge matched to `variant`, a title row it shares with the close button, and a content area below, both aligned to the same edge. The card never hides itself. The close button and the `autoClose` timer both call `onRequestClose`, leaving removal to whoever owns the toast stack, so the card can sit inside an external engine without leaving an empty slot behind. `maxHeight` caps it and scrolls its body past that point, since those engines clip their own containers with no scrollbar. The card fills the width of the slot it is given, since engines wrap each toast in a flex container that would otherwise shrink it to its content and leave a stack of mismatched widths, and its body keeps room for the close button's focus ring, which the scroll container would otherwise clip. The `autoClose` countdown pauses while the card is hovered or has focus inside it, and resumes with the time left, so the toast does not vanish under someone reading it or about to press one of its buttons (WCAG 2.2.1, Timing Adjustable). A bar along the bottom of the card counts the delay down and pauses with it, showing how long the toast has left; `hideProgressBar` drops it. `paused` holds both from outside, for engines that pause a whole stack while it is hovered, since the card only sees the pointer over itself. Every badge carries a white glyph. White fails the 3:1 non-text contrast (WCAG 1.4.11) on the palette's success and warning fills (1.97:1 and 2.32:1), so those badges use new darker shades, `colorSuccessDark` and `colorWarningDark` (about 3.6:1), exposed as `--color-success-dark` and `--color-warning-dark` so themes can override them. A dark glyph passes too, but it set those two variants apart from the rest. The card is a live region, which rules out `role="button"` on it, and it holds buttons of its own, so a clickable container would nest interactive elements and swallow their Enter/Space presses. With `onClick`, the click is exposed through a real button wrapping `message` instead: it is announced as a button, reachable with Tab and activated natively, and its focus ring outlines the whole card. `clickAriaLabel` names it when the message does not describe the action, and clicks on interactive elements passed in `message` or `content` stay with those elements. The pointer cursor follows `onClick` by default, with `disablePointer` as an override. The close button takes `closeButtonAriaLabel`, since a hardcoded English name is what screen readers announce in every locale. The live-region attributes stay overridable through the rest props, for engines whose wrapper is already a live region, while the card's own handlers and test id are applied after them. Prop names follow the library rather than react-toastify or BBB's notify(): `variant` as in BBButton and BBBTypography, and `hideCloseButton` as in BBBHint, so opting out of the close button reads the same across components. DOM-driven handlers (`onClick`, `onActionClick`) receive the event, as in BBButton; `onRequestClose` does not, as in BBBHint, since the timer fires it too. `small` keeps its name to match the field already in BBB's notify() and in the plugin SDK. `message` is optional, for cards whose content reads on its own, and typed as a node rather than a string because four call sites pass a `` that cannot be flattened without losing inline markup. --- README.md | 1 + package.json | 10 + src/components/Toast/README.md | 276 +++++++++++++++++++ src/components/Toast/assets/example.png | Bin 0 -> 125502 bytes src/components/Toast/component.stories.tsx | 305 +++++++++++++++++++++ src/components/Toast/component.tsx | 266 ++++++++++++++++++ src/components/Toast/constants.ts | 45 +++ src/components/Toast/index.ts | 1 + src/components/Toast/styles.ts | 211 ++++++++++++++ src/components/Toast/types.ts | 96 +++++++ src/components/index.ts | 1 + src/stylesheets/palette.ts | 4 + webpack.config.babel.js | 1 + 13 files changed, 1217 insertions(+) create mode 100644 src/components/Toast/README.md create mode 100644 src/components/Toast/assets/example.png create mode 100644 src/components/Toast/component.stories.tsx create mode 100644 src/components/Toast/component.tsx create mode 100644 src/components/Toast/constants.ts create mode 100644 src/components/Toast/index.ts create mode 100644 src/components/Toast/styles.ts create mode 100644 src/components/Toast/types.ts diff --git a/README.md b/README.md index 223b759..c1dd7e5 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Below is a list of the components available in this library. Each component has - [BBBSpinner](./src/components/Spinner//README.md) - [BBBTextAreaInput](./src/components/TextAreaInput/README.md) - [BBBTextInput](./src/components/TextInput/README.md) +- [BBBToast](./src/components/Toast/README.md) - [BBBToggle](./src/components/Toggle/README.md) - [BBBTypography](./src/components/Typography/README.md) diff --git a/package.json b/package.json index bea56d7..02178ba 100644 --- a/package.json +++ b/package.json @@ -113,6 +113,13 @@ "require": "./dist/components/TextInput.js", "default": "./dist/components/TextInput.js" }, + "./Toast": { + "types": "./dist/types/components/Toast/index.d.ts", + "node": "./dist/components/Toast.js", + "import": "./dist/esm/components/Toast/index.js", + "require": "./dist/components/Toast.js", + "default": "./dist/components/Toast.js" + }, "./Toggle": { "types": "./dist/types/components/Toggle/index.d.ts", "node": "./dist/components/Toggle.js", @@ -220,6 +227,9 @@ "TextInput": [ "dist/types/components/TextInput/index.d.ts" ], + "Toast": [ + "dist/types/components/Toast/index.d.ts" + ], "Toggle": [ "dist/types/components/Toggle/index.d.ts" ], diff --git a/src/components/Toast/README.md b/src/components/Toast/README.md new file mode 100644 index 0000000..4d87cb4 --- /dev/null +++ b/src/components/Toast/README.md @@ -0,0 +1,276 @@ +# BBBToast + +The `BBBToast` component is the presentational card for transient notifications. It is laid out in two columns: the icon badge owns a full-height section on the left, and to its right sit the title (`message`, on a row it shares with the close button) and the `content` area for the description, links or action buttons. + +![Demo](assets/example.png) + +`BBBToast` never hides itself. Both the close button and the `autoClose` timer call `onRequestClose`, and removing the card is up to whoever owns the toast stack. That keeps the card usable inside an external toast engine (such as `react-toastify`), which would otherwise be left rendering an empty slot. + +## Usage Example + +### Basic Toast + +```jsx +import { BBBToast } from 'bbb-ui-components-react'; + + +``` + +### Toast With Content + +Pass `content` for the description below the title. It shares the title's left edge, so the two read as one block. A divider separates them unless `showSeparator` is `false`. + +```jsx +import { BBBToast } from 'bbb-ui-components-react'; + + +``` + +### Dismissing the Toast + +Wire `onRequestClose` to remove the card. It fires both when the close button is clicked and when `autoClose` elapses. + +```jsx +import { useState } from 'react'; +import { BBBToast } from 'bbb-ui-components-react'; + +const [visible, setVisible] = useState(true); + +{visible && ( + setVisible(false)} + /> +)} +``` + +The countdown pauses while the pointer is over the card or focus is inside it, and resumes with the time that was left, so the toast never disappears under someone reading it or reaching for one of its buttons. A bar along the bottom of the card shows the time left and pauses with the countdown; pass `hideProgressBar` to drop it. Set `paused` to hold the countdown from outside as well, for example while the toast engine's stack is hovered. + +Pass `autoClose={false}` for a toast that persists until it is dismissed manually, and `hideCloseButton` to drop the close button as well. + +### Clickable Toast + +`onClick` covers the whole card, and the cursor turns into a pointer to show it. Pass `disablePointer` to keep the default cursor anyway, or `disablePointer={false}` to show the pointer on a card without `onClick` — for example when the toast engine closes it on click. + +```jsx +import { BBBToast } from 'bbb-ui-components-react'; + + openChatPanel()} +/> +``` + +The card stays a live region, so the click is exposed through a real button wrapping `message`: screen readers announce it as a button named after the message, it is reachable with Tab and activates with Enter or Space, and its focus ring outlines the whole card. Pass `clickAriaLabel` when the message alone doesn't describe what the click does: + +```jsx + openChatPanel()} +/> +``` + +Without a `message`, the button is visually hidden and takes its name from `clickAriaLabel`, falling back to the `content` text. + +Clicks on interactive elements passed in `message` or `content` (links, buttons, inputs) stay with those elements and don't fire `onClick`. + +### Toast With an Action + +```jsx +import { BBBToast } from 'bbb-ui-components-react'; + + window.open(helpLink)} +/> +``` + +### Rich Content + +`content` takes an arbitrary node, so links, buttons and inline media all render. Use it when a notification needs more than one action — for example a confirmation toast with both a cancel and a confirm button, which `actionLabel` alone does not cover. + +```jsx +import { BBBToast, BBButton } from 'bbb-ui-components-react'; + + +

Participants will be notified.

+ + + + )} +/> +``` + +### Custom or Hidden Icon + +Pass `icon` to replace the icon matched to `variant`, or `icon={false}` to drop the badge entirely. + +```jsx +import { MdCampaign } from 'react-icons/md'; +import { BBBToast } from 'bbb-ui-components-react'; + +} /> + +``` + +## Props + +| Property | Type | Default | Description | +| ---------------- | ----------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------- | +| `message` | `React.ReactNode` | | The title of the notification, rendered on its own line. Optional — omit it for cards whose `content` carries the whole notification. Usually plain text; takes a node for inline i18n markup (e.g. a ``). | +| `variant` | `'default' \| 'info' \| 'success' \| 'warning' \| 'error'` | `'default'` | Visual variant driving the default icon and the icon badge color. | +| `icon` | `React.ReactNode \| false` | icon matched to `variant` | A custom icon replacing the one matched to `variant`, or `false` to hide the icon badge entirely. | +| `content` | `React.ReactNode` | | The description or secondary content (text, links, action buttons), rendered below the title and sharing its left edge. | +| `showSeparator` | `boolean` | `true` | Shows the divider between the title and `content`; only rendered when both are present. | +| `small` | `boolean` | `false` | Compact variant for space-constrained placements. | +| `disablePointer` | `boolean` | `!onClick` | Keeps the default cursor instead of showing a pointer one, so the toast doesn't read as clickable; defaults to `false` when `onClick` is set and `true` otherwise. | +| `onClick` | `React.MouseEventHandler` | | A click handler for the whole toast (e.g. open a related chat or panel); exposed to assistive technology as a button wrapping `message`. | +| `clickAriaLabel` | `string` | | The accessible name for the `onClick` action, overriding the `message` text; needed when `onClick` is set without a `message`, else the `content` text is used. | +| `actionLabel` | `string` | | The label for an optional action button rendered below the content. | +| `onActionClick` | `React.MouseEventHandler` | | A handler for the action button; only used when `actionLabel` is set. | +| `autoClose` | `number \| false` | `5000` | The auto-dismiss delay in milliseconds, paused while the toast is hovered or focused, or `false` to persist until dismissed manually. | +| `paused` | `boolean` | `false` | Pauses the `autoClose` countdown from outside, on top of the card's own pause on hover and focus (e.g. while a toast engine's stack is hovered). | +| `hideProgressBar` | `boolean` | `false` | Hides the bar at the bottom of the card that counts down `autoClose`; never shown when `autoClose` is `false`. | +| `hideCloseButton` | `boolean` | `false` | Hides the close (X) button, for toasts that shouldn't be manually dismissed. | +| `closeButtonAriaLabel` | `string` | `'Close'` | The accessible name for the close button; pass a translated string in localized apps. | +| `onRequestClose` | `() => void` | | A callback fired when the toast is dismissed, by the close button or by `autoClose`. | +| `maxHeight` | `string` | `'70vh'` | Caps the card's height, scrolling its body past that point. Any CSS length. | +| `dataTest` | `string` | | The value for the `data-test` attribute on the container; also the base for the three derived ids below. | +| `messageDataTest` | `string` | `${dataTest}-message` | A test identifier applied to the message. | +| `closeButtonDataTest` | `string` | `${dataTest}-close-button` | A test identifier applied to the close button. | +| `actionButtonDataTest` | `string` | `${dataTest}-action-button` | A test identifier applied to the action button. | +| `...props` | `HTMLAttributes` | | Any other props will be passed down to the underlying container div. They can override the live-region attributes (`role`, `aria-live`, `aria-atomic`), but not the card's own handlers or `data-test`. | + +## Layout + +The icon badge sits in a section that spans the card's full height, and the title and `content` share the column to its right, aligned to the same left edge. The close button shares a row with the title only, so it stays on the title's line instead of drifting down past the description. + +When `icon` is `false` the icon section is not rendered at all, and the title and content take the whole card width. + +In right-to-left documents the layout mirrors: the icon badge moves to the right and the close button to the left. + +## Height and Scrolling + +`maxHeight` caps the card and its body scrolls past that point, so tall content is never clipped without a scrollbar. This matters because toast engines cap their own containers — `react-toastify`'s is `max-height: 75vh; overflow: hidden` — and would otherwise cut the card off in silence. + +The default of `70vh` sits just under that, so the card scrolls before the engine clips it. Lower it for a card that should stay small: + +```jsx + +``` + +When only one region should scroll and the rest of the card should stay put, cap that region instead with `BBBScrollArea`, and raise `maxHeight` so the card itself is not the limit: + +```jsx +import { BBBToast, BBBScrollArea } from 'bbb-ui-components-react'; + +{fileRows}} +/> +``` + +## Cards Without a Title + +`message` is optional. Omit it when the notification is a single line or a row that reads on its own — a file with its status, say — and `content` carries it: + +```jsx +} /> +``` + +The title row is still rendered for the close button, which keeps its place at the end of the row; drop it too with `hideCloseButton` and the row goes away entirely. + +## Test Identifiers + +Set `dataTest` and the toast derives stable identifiers for its inner parts: + +```jsx + +``` + +```html +
+
Recording started
+ + +
+``` + +Override any of them individually when a selector has to keep an existing name: + +```jsx + +``` + +Setting `dataTest` matters for more than convenience. With no value of its own, the underlying `BBButton` derives one from its label — and since `actionLabel` is usually a translated string, the resulting selector changes with the interface language. The derived ids above are what keep it stable. + +`actionLabel` renders a button the toast owns, so arbitrary props cannot be forwarded to it; the identifiers above are the supported hook. When the action needs more than that — extra ARIA attributes, a different variant, or more than one button — render your own `BBButton` inside `content` instead, which is also how BBB builds its two-button confirmation toasts. + +## Using It With a Toast Engine + +`BBBToast` is the card, not the stack. Pair it with whatever engine positions, stacks and dismisses toasts — in `bigbluebutton-html5` that is `react-toastify`. + +The engine wraps every toast in its own element, and `react-toastify`'s default wrapper styles a card of its own. Left alone, the two cards stack up: two backgrounds, two paddings, two shadows, mismatched corners and two close buttons. Turn the wrapper into a plain box and let `BBBToast` do the styling: + +```css +.Toastify__toast.bbbToast { + background: none; /* the theme class paints #fff behind the card */ + padding: 0; /* wrapper adds 14px on top of the card's own */ + border-radius: 0; /* wrapper rounds to 6px, the card to 8px */ + box-shadow: none; /* wrapper adds its own 0 4px 12px shadow */ + min-height: 0; /* wrapper floors the height at 64px */ + font-family: inherit; /* wrapper forces sans-serif over the app font */ +} +``` + +```jsx +toast( + toast.dismiss(id)} />, + { className: 'bbbToast', closeButton: false, toastId: id }, +); +``` + +`closeButton: false` is what drops the engine's own X, since `BBBToast` already renders one. Keep the engine's `autoClose` and the card's `autoClose` from both running — pass the delay to whichever one owns dismissal and set the other to `false`. The card's own timer already pauses on hover and focus, so letting it own dismissal doesn't depend on the engine's `pauseOnHover`. + +If the engine's wrapper is already a live region — `bigbluebutton-html5` wraps every toast in a `role="alert"` element — pass `role="none"` and `aria-live="off"` to the card so the notification isn't announced twice. + +`react-toastify`'s container defaults to a 320px width, which is the width the Storybook stories render at (`20rem`). + +## Accessibility + +The card renders as a live region so screen readers announce it as it appears: `role="status"` with `aria-live="polite"` for the `default`, `info` and `success` variants, and `role="alert"` with `aria-live="assertive"` for `warning` and `error`. + +These live-region attributes can be overridden through the rest props, for when the surrounding toast engine already provides the live region (see [Using It With a Toast Engine](#using-it-with-a-toast-engine)). + +With `onClick`, the click is exposed as a real button wrapping `message` (or a visually hidden one named by `clickAriaLabel` when there is no message), so it is announced as a button, reachable with Tab and activated with Enter or Space. See [Clickable Toast](#clickable-toast). + +The `autoClose` countdown pauses while the card is hovered or has focus inside it, so it never disappears under someone reading it or reaching for one of its buttons. + +The close button's accessible name defaults to the English `'Close'`; pass `closeButtonAriaLabel` with a translated string in localized apps. + +Every icon glyph is white, and each badge fill keeps at least the 3:1 non-text contrast ratio against it, which is why `success` and `warning` use the darker shades of their colors (`--color-success-dark`, `--color-warning-dark`). diff --git a/src/components/Toast/assets/example.png b/src/components/Toast/assets/example.png new file mode 100644 index 0000000000000000000000000000000000000000..7f903c31fb518e222371e4786a62fc8bbc75184e GIT binary patch literal 125502 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 ( +
+ +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +/** + * Wrapper component so hooks can be used inside Storybook's render function, + * showing that the card leaves removal to its owner: both the close button and the + * `autoClose` timer only call `onRequestClose`. + */ +const DismissibleToastStory: React.FC> = (args) => { + const [visible, setVisible] = useState(true); + + return ( +
+ {!visible && setVisible(true)} />} + {visible && setVisible(false)} />} +
+ ); +}; + +/** Basic toast with only a message, the default variant and its matching icon. */ +export const Default: Story = { + args: { + message: 'You are muted', + }, +}; + +/** Toast with secondary `content` below the message, separated by the default divider. */ +export const WithContent: Story = { + args: { + message: 'Recording started', + content: 'This session is being recorded and will be available after the meeting ends.', + }, +}; + +/** Every `variant`, showing the icon and badge color each one applies. */ +export const Variants: Story = { + args: { + message: 'Notification', + }, + render: (args) => ( +
+ {TOAST_VARIANT_VALUES.map((variant) => ( + + ))} +
+ ), +}; + +/** The compact `small` variant, for space-constrained placements like chat push alerts. */ +export const Small: Story = { + args: { + message: 'New message from Arthur', + content: 'Are we still on for the 3pm call?', + small: true, + }, +}; + +/** Toast with `icon={false}`, dropping the badge for messages that carry their own visual. */ +export const WithoutIcon: Story = { + args: { + message: 'Start recording?', + content: 'Participants will be notified that the session is being recorded.', + icon: false, + }, +}; + +/** Toast with a custom `icon` node replacing the one matched to `variant`. */ +export const CustomIcon: Story = { + args: { + message: 'Presenter changed', + content: 'Arthur is now presenting.', + icon: , + }, +}; + +/** Toast with `showSeparator={false}`, for content that reads as one block with the message. */ +export const WithoutSeparator: Story = { + args: { + message: 'Connection unstable', + content: 'Your audio may be affected.', + variant: 'warning', + showSeparator: false, + }, +}; + +/** Toast with an action button, rendered from `actionLabel` and wired to `onActionClick`. */ +export const WithAction: Story = { + args: { + message: 'Screenshare failed', + content: 'Your browser blocked the screen sharing request.', + variant: 'error', + actionLabel: 'Learn more', + onActionClick: () => window.alert('Action clicked'), + }, +}; + +/** Test identifiers: `dataTest` seeds the container and derives the message, close and action ids. */ +export const WithDataTest: Story = { + args: { + message: 'Reload required', + content: 'Inspect the DOM to see the derived data-test attributes.', + actionLabel: 'Reload', + onActionClick: () => {}, + dataTest: 'notificationBanner', + actionButtonDataTest: 'notificationBannerReloadButton', + }, +}; + +/** Titleless card: with no `message`, the content carries the notification on its own. */ +export const WithoutMessage: Story = { + args: { + content: 'presentation.pdf — upload complete', + }, +}; + +/** Tall content scrolls inside the card instead of being clipped, capped by `maxHeight`. */ +export const ScrollingContent: Story = { + args: { + message: 'Uploading presentations', + maxHeight: '12rem', + autoClose: false, + content: ( + <> + {Array.from({ length: 12 }, (_, i) => ( +

{`slide-deck-${i + 1}.pdf — processing`}

+ ))} + + ), + }, +}; + +/** Clickable toast: `onClick` on the whole card, announced as a button and shown with a pointer cursor. */ +export const Clickable: Story = { + args: { + message: 'New message in Public Chat', + content: 'Click to open the chat panel.', + variant: 'info', + small: true, + onClick: () => window.alert('Toast clicked'), + }, +}; + +/** Toast with `autoClose={false}` and `hideCloseButton`, persisting until its owner removes it. */ +export const Persistent: Story = { + args: { + message: 'You are listening to a breakout room', + variant: 'info', + autoClose: false, + hideCloseButton: true, + }, +}; + +/** Rich `content` (links, buttons, inline media), as in BBB's two-button confirmation toasts. */ +export const RichContent: Story = { + args: { + message: 'Start recording?', + icon: false, + autoClose: false, + showSeparator: false, + content: ( + <> +
+
+ {}} /> + {}} /> +
+ + ), + }, +}; + +/** Dismissal in practice: the close button and the `autoClose` timer (paused on hover) both ask the owner to remove the card. */ +export const Dismissible: Story = { + args: { + message: 'This toast asks to be closed after 4 seconds', + content: 'Its owner is what actually removes it.', + autoClose: 4000, + }, + render: (args) => , +}; diff --git a/src/components/Toast/component.tsx b/src/components/Toast/component.tsx new file mode 100644 index 0000000..09291a1 --- /dev/null +++ b/src/components/Toast/component.tsx @@ -0,0 +1,266 @@ +import React, { + JSX, useEffect, useId, useRef, useState, +} from 'react'; +import { MdClose } from 'react-icons/md'; +import * as Styled from './styles'; +import { BBBDivider } from '../Divider'; +import { BBButton } from '../Button'; +import { ToastProps } from './types'; +import { + DEFAULT_AUTO_CLOSE, DEFAULT_CLOSE_BUTTON_ARIA_LABEL, DEFAULT_ICONS, + DEFAULT_MAX_HEIGHT, DEFAULT_TOAST_VARIANT, INTERACTIVE_SELECTOR, TOAST_VARIANTS, +} from './constants'; + +/** + * A notification card for transient messages. + * + * This component renders the presentational part of a toast notification: an icon badge + * matched to `variant`, the message, optional secondary content and an optional action button. + * + * It never hides itself. Both the close button and the `autoClose` timer call `onRequestClose`, + * leaving removal to whoever owns the toast stack, so the card can live inside an external + * toast engine without leaving an empty slot behind. + */ +function Toast({ + message, + variant = DEFAULT_TOAST_VARIANT, + icon, + content, + showSeparator = true, + small = false, + disablePointer, + onClick, + clickAriaLabel, + actionLabel, + onActionClick, + autoClose = DEFAULT_AUTO_CLOSE, + paused = false, + hideProgressBar = false, + hideCloseButton = false, + closeButtonAriaLabel = DEFAULT_CLOSE_BUTTON_ARIA_LABEL, + onRequestClose, + maxHeight = DEFAULT_MAX_HEIGHT, + dataTest, + messageDataTest, + closeButtonDataTest, + actionButtonDataTest, + onMouseEnter, + onMouseLeave, + onFocus, + onBlur, + ...rest +}: ToastProps): JSX.Element { + // Without an explicit value BBButton derives its own from the label, which is + // translated at every call site — so the derived ids below are what keep test + // selectors stable across locales. + const derive = (explicit: string | undefined, suffix: string): string | undefined => + explicit ?? (dataTest ? `${dataTest}-${suffix}` : undefined); + + const testIds = { + message: derive(messageDataTest, 'message'), + closeButton: derive(closeButtonDataTest, 'close-button'), + actionButton: derive(actionButtonDataTest, 'action-button'), + }; + + // Held in a ref so an inline `onRequestClose` doesn't restart the timer on every + // render, which would keep the toast alive forever. + const onRequestCloseRef = useRef(onRequestClose); + + useEffect(() => { + onRequestCloseRef.current = onRequestClose; + }, [onRequestClose]); + + // Paused while hovered or focused so the toast doesn't vanish under a user who is + // reading it or about to press one of its buttons (WCAG 2.2.1, Timing Adjustable). + const [isHovered, setIsHovered] = useState(false); + const [isFocused, setIsFocused] = useState(false); + const isPaused = paused || isHovered || isFocused; + const remainingRef = useRef(autoClose === false ? 0 : autoClose); + + useEffect(() => { + if (autoClose !== false) remainingRef.current = autoClose; + }, [autoClose]); + + useEffect(() => { + if (autoClose === false || isPaused) return undefined; + + const startedAt = Date.now(); + const delay = remainingRef.current; + const timeout = setTimeout(() => onRequestCloseRef.current?.(), delay); + return () => { + clearTimeout(timeout); + remainingRef.current = Math.max(0, delay - (Date.now() - startedAt)); + }; + }, [autoClose, isPaused]); + + const handleMouseEnter: React.MouseEventHandler = (event) => { + setIsHovered(true); + onMouseEnter?.(event); + }; + + const handleMouseLeave: React.MouseEventHandler = (event) => { + setIsHovered(false); + onMouseLeave?.(event); + }; + + const handleFocus: React.FocusEventHandler = (event) => { + setIsFocused(true); + onFocus?.(event); + }; + + const handleBlur: React.FocusEventHandler = (event) => { + if (!event.currentTarget.contains(event.relatedTarget)) setIsFocused(false); + onBlur?.(event); + }; + + const isAssertive = variant === TOAST_VARIANTS.WARNING || variant === TOAST_VARIANTS.ERROR; + + const contentId = useId(); + const cardActionRef = useRef(null); + + // Every click on the card lands here, including the card action's own (keyboard + // activation of a button dispatches a click too). Clicks on other interactive + // elements passed through `message` or `content` belong to those elements. + const handleCardClick: React.MouseEventHandler = (event) => { + if (!onClick) return; + + const interactive = (event.target as Element).closest(INTERACTIVE_SELECTOR); + const isOwnedElsewhere = interactive + && interactive !== cardActionRef.current + && event.currentTarget.contains(interactive); + if (isOwnedElsewhere) return; + + onClick(event); + }; + + const handleCloseClick: React.MouseEventHandler = (event) => { + event.stopPropagation(); + onRequestClose?.(); + }; + + const handleActionClick: React.MouseEventHandler = (event) => { + event.stopPropagation(); + onActionClick?.(event); + }; + + const renderIconSection = (): JSX.Element | null => { + if (icon === false) return null; + + const DefaultIcon = DEFAULT_ICONS[variant]; + return ( + + + + + + ); + }; + + return ( + + {renderIconSection()} + + {onClick && !message && ( + + )} + + + {(message || !hideCloseButton) && ( + + {message && ( + + {onClick ? ( + + {message} + + ) : message} + + )} + + {!hideCloseButton && ( + + } + ariaLabel={closeButtonAriaLabel} + onClick={handleCloseClick} + {...(testIds.closeButton ? { dataTest: testIds.closeButton } : {})} + /> + + )} + + )} + + {content && ( + <> + {showSeparator && message && } + {content} + + )} + + {actionLabel && ( + + + + )} + + + {autoClose !== false && !hideProgressBar && ( + + )} + + ); +} + +export default Toast; diff --git a/src/components/Toast/constants.ts b/src/components/Toast/constants.ts new file mode 100644 index 0000000..c2a401c --- /dev/null +++ b/src/components/Toast/constants.ts @@ -0,0 +1,45 @@ +import { MdCheck, MdError, MdHelp, MdInfo, MdWarning } from 'react-icons/md'; +import { + colorBrand1, colorSuccessDark, colorWarningDark, colorError, colorWhite, +} from '../../stylesheets/palette'; + +export const TOAST_VARIANTS = { + DEFAULT: 'default', + INFO: 'info', + SUCCESS: 'success', + WARNING: 'warning', + ERROR: 'error', +} as const; +export const TOAST_VARIANT_VALUES = Object.values(TOAST_VARIANTS); +export const DEFAULT_TOAST_VARIANT = TOAST_VARIANTS.DEFAULT; + +export const DEFAULT_AUTO_CLOSE = 5000; + +export const DEFAULT_CLOSE_BUTTON_ARIA_LABEL = 'Close'; + +export const INTERACTIVE_SELECTOR = [ + 'a[href]', 'button', 'input', 'select', 'textarea', 'summary', 'label', + '[role="button"]', '[role="link"]', '[tabindex]:not([tabindex="-1"])', +].join(', '); + +// Caps the card so tall content scrolls inside it instead of being clipped in silence by +// the toast engine's own container (react-toastify's is `max-height: 75vh; overflow: hidden`). +export const DEFAULT_MAX_HEIGHT = '70vh'; + +export const DEFAULT_ICONS = { + default: MdInfo, + info: MdHelp, + success: MdCheck, + warning: MdWarning, + error: MdError, +} as const; + +// The success and warning badges take the dark shades of their colors so the white glyph +// keeps at least the 3:1 non-text contrast WCAG asks for; it fails on the lighter fills. +export const VARIANT_COLORS = { + default: { background: colorBrand1, glyph: colorWhite }, + info: { background: colorBrand1, glyph: colorWhite }, + success: { background: colorSuccessDark, glyph: colorWhite }, + warning: { background: colorWarningDark, glyph: colorWhite }, + error: { background: colorError, glyph: colorWhite }, +} as const; diff --git a/src/components/Toast/index.ts b/src/components/Toast/index.ts new file mode 100644 index 0000000..0f44552 --- /dev/null +++ b/src/components/Toast/index.ts @@ -0,0 +1 @@ +export { default as BBBToast } from './component'; diff --git a/src/components/Toast/styles.ts b/src/components/Toast/styles.ts new file mode 100644 index 0000000..990f746 --- /dev/null +++ b/src/components/Toast/styles.ts @@ -0,0 +1,211 @@ +import styled, { css, keyframes } from 'styled-components'; +import { + colorBackgroundWhite, colorBrand1, colorShadowDefault, + colorTextDefault, colorTextLight, +} from '../../stylesheets/palette'; +import { + borderRadiusSmall, spacingMediumLarge, + spacingSmall, spacingSmallMedium, +} from '../../stylesheets/sizing'; +import { + fontSizeBig, fontSizeDefault, fontSizeSmall, fontSizeXSmall, + fontWeightLight, +} from '../../stylesheets/typography'; +import { + StyledCardActionProps, StyledIconBadgeProps, StyledProgressBarProps, StyledTextProps, + StyledToastProps, +} from './types'; +import { VARIANT_COLORS } from './constants'; + +// `message` and `content` take arbitrary nodes, so any media a consumer passes is +// capped to the card instead of forcing it wider than its container. +const richContent = css` + img, + svg, + video { + max-width: 100%; + } +`; + +const visuallyHidden = css` + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip-path: inset(50%); + white-space: nowrap; +`; + +// Unstyled so the message reads as plain text; its focus ring is drawn on the whole card. +export const CardAction = styled.button` + margin: 0; + padding: 0; + border: 0; + background: none; + color: inherit; + font: inherit; + line-height: inherit; + text-align: start; + cursor: inherit; + + &:focus { + outline: none; + } + + ${({ $visuallyHidden }) => $visuallyHidden && visuallyHidden} +`; + +export const Container = styled.div` + position: relative; + display: flex; + /* Fills the slot it is given even when that slot is a flex container, as toast engines' + wrappers usually are, so every toast in a stack has the same width. */ + width: 100%; + flex-direction: row; + align-items: stretch; + gap: ${spacingSmallMedium}; + padding: ${spacingMediumLarge}; + background-color: ${colorBackgroundWhite}; + border-radius: ${borderRadiusSmall}; + box-shadow: 0 2px 8px ${colorShadowDefault}; + overflow-wrap: break-word; + /* So maxHeight caps the whole card, padding included, rather than just its content box. */ + box-sizing: border-box; + max-height: ${({ $maxHeight }) => $maxHeight}; + cursor: ${({ $disablePointer }) => ($disablePointer ? 'auto' : 'pointer')}; + + &:has(${CardAction}:focus-visible) { + outline: 2px solid ${colorBrand1}; + } +`; + +// Mirrors the close button's box. The title row is sized by that button rather than by +// the text, so pinning the badge to the top left it riding high by half the difference — +// worse the smaller the badge, which is why it showed up first in the `small` variant. +// Giving the badge and the title row the same band centers them on one line at any size. +const titleRowHeight = '2.375rem'; + +// The width of BBButton's focus outline, which is drawn outside its box. +const focusRingWidth = '2px'; + +// The icon owns a full-height section of its own on the left; inside it, the badge is +// centered on the title row so it stays on the title's line as content grows. +export const IconSection = styled.div` + display: flex; + align-items: flex-start; + flex-shrink: 0; +`; + +export const IconBand = styled.div` + display: flex; + align-items: center; + min-height: ${titleRowHeight}; +`; + +export const Body = styled.div` + display: flex; + flex-direction: column; + flex: 1; + min-width: 0; + gap: ${spacingSmall}; + + /* min-height lets this flex child shrink below its content so the overflow can scroll. */ + min-height: 0; + overflow-y: auto; + overflow-x: hidden; + + /* As a scroll container this clips whatever overflows it, including the focus ring of + the close button, which spans the full height of the title row. The padding leaves + room for the ring and the negative margin cancels it out of the layout. */ + padding: ${focusRingWidth}; + margin: -${focusRingWidth}; +`; + +// The close button shares this row with the title only, so it stays on the title's line +// instead of centering against the content below it. +export const Header = styled.div` + display: flex; + flex-direction: row; + align-items: center; + min-height: ${titleRowHeight}; + gap: ${spacingSmall}; +`; + +export const IconBadge = styled.div` + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + border-radius: 50%; + aspect-ratio: 1; + width: ${({ $small }) => ($small ? '1.5rem' : '2rem')}; + font-size: ${({ $small }) => ($small ? fontSizeXSmall : fontSizeBig)}; + background-color: ${({ $variant }) => VARIANT_COLORS[$variant].background}; + color: ${({ $variant }) => VARIANT_COLORS[$variant].glyph}; +`; + +export const Message = styled.div` + flex: 1; + min-width: 0; + color: ${colorTextDefault}; + font-size: ${({ $small }) => ($small ? fontSizeSmall : fontSizeDefault)}; + font-weight: ${fontWeightLight}; + line-height: normal; + + ${richContent} +`; + +export const Content = styled.div` + color: ${colorTextLight}; + font-size: ${({ $small }) => ($small ? fontSizeXSmall : fontSizeSmall)}; + font-weight: ${fontWeightLight}; + line-height: normal; + + ${richContent} +`; + +export const ActionWrapper = styled.div` + display: flex; + justify-content: flex-end; +`; + +export const CloseButtonWrapper = styled.div` + display: flex; + flex-shrink: 0; + margin-inline-start: auto; +`; + +const countdown = keyframes` + from { + transform: scaleX(1); + } + + to { + transform: scaleX(0); + } +`; + +// Clips the bar to the card's rounded bottom corners without clipping the card's content. +export const ProgressTrack = styled.div` + position: absolute; + inset-inline: 0; + bottom: 0; + height: 0.25rem; + overflow: hidden; + border-end-start-radius: ${borderRadiusSmall}; + border-end-end-radius: ${borderRadiusSmall}; +`; + +// Pausing the animation together with the timer keeps the two in step: both resume from +// where they stopped instead of restarting. +export const ProgressBar = styled.div` + height: 100%; + background-color: ${({ $variant }) => VARIANT_COLORS[$variant].background}; + transform-origin: left; + animation: ${countdown} ${({ $duration }) => $duration}ms linear forwards; + animation-play-state: ${({ $paused }) => ($paused ? 'paused' : 'running')}; + + [dir='rtl'] & { + transform-origin: right; + } +`; diff --git a/src/components/Toast/types.ts b/src/components/Toast/types.ts new file mode 100644 index 0000000..e9c1d1f --- /dev/null +++ b/src/components/Toast/types.ts @@ -0,0 +1,96 @@ +import React from 'react'; +import { TOAST_VARIANT_VALUES } from './constants'; + +export type ToastVariant = (typeof TOAST_VARIANT_VALUES)[number]; + +export interface StyledToastProps { + $disablePointer: boolean; + $maxHeight: string; +} + +export interface StyledProgressBarProps { + $variant: ToastVariant; + $duration: number; + $paused: boolean; +} + +export interface StyledIconBadgeProps { + $variant: ToastVariant; + $small: boolean; +} + +export interface StyledCardActionProps { + $visuallyHidden: boolean; +} + +export interface StyledTextProps { + $small: boolean; +} + +export interface ToastProps extends Omit, 'content'> { + /** Title of the notification, rendered on its own line; usually plain text, but takes a node for inline i18n markup. */ + message?: React.ReactNode; + + /** Visual variant driving the default icon and the icon badge color. @default 'default' */ + variant?: ToastVariant; + + /** Custom icon replacing the one matched to `variant`, or `false` to hide the icon badge entirely. */ + icon?: React.ReactNode | false; + + /** Description or secondary content (text, links, action buttons) rendered below the title, sharing its left edge. */ + content?: React.ReactNode; + + /** Shows the divider between the title and `content`; only rendered when both are present. @default true */ + showSeparator?: boolean; + + /** Compact variant for space-constrained placements. @default false */ + small?: boolean; + + /** Keeps the default cursor instead of showing a pointer one, so the toast doesn't read as clickable; defaults to `false` when `onClick` is set and `true` otherwise. */ + disablePointer?: boolean; + + /** Click handler for the whole toast (e.g. open a related chat or panel); exposed to assistive technology as a button wrapping `message`. */ + onClick?: React.MouseEventHandler; + + /** Accessible name for the `onClick` action, overriding the `message` text; needed when `onClick` is set without a `message`, else the `content` text is used. */ + clickAriaLabel?: string; + + /** Label for an optional action button rendered below the content. */ + actionLabel?: string; + + /** Handler for the action button; only used when `actionLabel` is set. */ + onActionClick?: React.MouseEventHandler; + + /** Auto-dismiss delay in milliseconds, paused while the toast is hovered or focused, or `false` to persist until dismissed manually. @default 5000 */ + autoClose?: number | false; + + /** Pauses the `autoClose` countdown from outside, on top of the card's own pause on hover and focus (e.g. while a toast engine's stack is hovered). @default false */ + paused?: boolean; + + /** Hides the bar at the bottom of the card that counts down `autoClose`; never shown when `autoClose` is `false`. @default false */ + hideProgressBar?: boolean; + + /** Hides the close (X) button, for toasts that shouldn't be manually dismissed. @default false */ + hideCloseButton?: boolean; + + /** Accessible name for the close button; pass a translated string in localized apps. @default 'Close' */ + closeButtonAriaLabel?: string; + + /** Callback fired when the toast is dismissed, by the close button or by `autoClose`. */ + onRequestClose?: () => void; + + /** Caps the card's height, scrolling its body past that point; any CSS length. @default '70vh' */ + maxHeight?: string; + + /** Value for the `data-test` attribute on the container; also the base for the derived test ids below. */ + dataTest?: string; + + /** Test identifier applied to the message. Defaults to `${dataTest}-message` when `dataTest` is set. */ + messageDataTest?: string; + + /** Test identifier applied to the close button. Defaults to `${dataTest}-close-button` when `dataTest` is set. */ + closeButtonDataTest?: string; + + /** Test identifier applied to the action button. Defaults to `${dataTest}-action-button` when `dataTest` is set. */ + actionButtonDataTest?: string; +} diff --git a/src/components/index.ts b/src/components/index.ts index 230d706..2af8389 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -12,5 +12,6 @@ export { BBBSelect } from './Select'; export { BBBSpinner } from './Spinner'; export { BBBTextAreaInput } from './TextAreaInput'; export { BBBTextInput } from './TextInput'; +export { BBBToast } from './Toast'; export { BBBToggle } from './Toggle'; export { BBBTypography } from './Typography'; diff --git a/src/stylesheets/palette.ts b/src/stylesheets/palette.ts index 1867278..f2b325b 100644 --- a/src/stylesheets/palette.ts +++ b/src/stylesheets/palette.ts @@ -26,6 +26,10 @@ const colorError_base = 'var(--color-error, #DF2721)'; const colorErrorDark_base = 'var(--color-error-dark, #AE1010)'; export const colorSuccess = 'var(--color-success, #2DD36F)'; export const colorWarning = 'var(--color-warning, #F59240)'; +// Darker shades of the two above, for fills that carry white text or icons - motivation: BBBToast +// warning and success which lack of contrast for displaying white icons +export const colorSuccessDark = 'var(--color-success-dark, #209B51)'; +export const colorWarningDark = 'var(--color-warning-dark, #D8680B)'; // Mapped to core css vars export const colorError = `var(--color-danger, ${colorError_base})`; export const colorErrorDark = `var(--color-danger-dark, ${colorErrorDark_base})`; diff --git a/webpack.config.babel.js b/webpack.config.babel.js index 461ae7f..927d002 100644 --- a/webpack.config.babel.js +++ b/webpack.config.babel.js @@ -16,6 +16,7 @@ export default { Spinner: './src/components/Spinner/index.ts', TextAreaInput: './src/components/TextAreaInput/index.ts', TextInput: './src/components/TextInput/index.ts', + Toast: './src/components/Toast/index.ts', Toggle: './src/components/Toggle/index.ts', Typography: './src/components/Typography/index.ts', colors: './src/stylesheets/colors.ts', From e22fd5c1162f494fe3878fd945ee8585f2e5c9e3 Mon Sep 17 00:00:00 2001 From: Arthurk12 Date: Tue, 6 Oct 2026 20:25:36 -0300 Subject: [PATCH 2/7] fix(BBBSpinner): clip the rotating svg to its box The spinner rotates its whole svg, and the corners of that square sweep past the wrapper as it turns: a 16px spinner reaches about 22.6px across its diagonal. Browsers count the transformed box as scrollable overflow, so a spinner at the edge of a scroll container makes that container show a scrollbar, as in the last row of a BBBToast, whose body scrolls past `maxHeight`. Clip the wrapper to its box. The drawn circle (radius 20 in a 50x50 viewBox, plus half the stroke) stays inside the box at any angle, so only the empty corners of the svg are clipped; a stroke wider than 10 would start to be cut. --- src/components/Spinner/styles.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Spinner/styles.ts b/src/components/Spinner/styles.ts index 90b86aa..9a03022 100644 --- a/src/components/Spinner/styles.ts +++ b/src/components/Spinner/styles.ts @@ -18,6 +18,7 @@ export const Wrapper = styled.div` height: ${({ $size }) => typeof $size === 'number' ? `${$size}px` : $size}; display: inline-grid; place-items: center; + overflow: hidden; `; export const StyledSvg = styled.svg` From 71c390bde12aacb5ca9cdaa43d4e2b63c9e9f7ff Mon Sep 17 00:00:00 2001 From: Arthurk12 Date: Thu, 15 Oct 2026 13:45:49 -0300 Subject: [PATCH 3/7] ci: prepend new releases to CHANGELOG.md instead of regenerating it The release workflow lets conventional-changelog-action regenerate CHANGELOG.md from git history on every release. With its default release-count of 5, releases older than the last five are dropped from the file, and any entry edited by hand is overwritten. Raising release-count only trades this for regenerating an ever-growing history on each release, and still discards manual edits, such as a hand-written changelog for the 0.x initial development phase. Pass the changelog as input-file. The action then generates only the new release and prepends it to the existing content, leaving older entries untouched. Create an empty file when it is missing, since the action reads input-file unconditionally; it is left without a title because anything already in the file ends up below the prepended release. --- .github/workflows/tag_and_release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/tag_and_release.yml b/.github/workflows/tag_and_release.yml index fb4a636..2d464d3 100644 --- a/.github/workflows/tag_and_release.yml +++ b/.github/workflows/tag_and_release.yml @@ -25,6 +25,9 @@ jobs: with: node-version-file: '.nvmrc' + - name: Ensure CHANGELOG.md exists + run: touch CHANGELOG.md + - name: Generate Changelog and Tag id: changelog uses: TriPSs/conventional-changelog-action@v5 @@ -37,6 +40,8 @@ jobs: preset: 'conventionalcommits' skip-ci: 'false' tag-prefix: 'v' + input-file: './CHANGELOG.md' + output-file: './CHANGELOG.md' version-file: './package.json, ./package-lock.json' pre-commit: './.github/scripts/pre-commit.js' From 019f4e3cdbb54252ff4c9db88f5403397dfd68fb Mon Sep 17 00:00:00 2001 From: Arthurk12 Date: Thu, 15 Oct 2026 13:45:55 -0300 Subject: [PATCH 4/7] ci: allow tagging without a changelog and forcing the bump type The release workflow always writes CHANGELOG.md and always infers the version bump from the commits. During initial development (0.x) no changelog is wanted, yet tags and releases should still go through the workflow instead of being made by hand. Inference is also unsafe there: the conventionalcommits preset bumps breaking changes to major even on 0.x, so a single `!` commit in the range would ship 1.0.0. Add a generate_changelog input, off by default, that sets the action's output-file to 'false' when disabled; the action still bumps, commits, tags and runs the lockfile pre-commit hook, it just writes no file. Add a release_type input that forces patch, minor or major through `npm version` plus skip-bump, and reject 'auto' while the version is 0.x. Once 1.0.0 is out, 'auto' works without further changes. Also bump softprops/action-gh-release from v1 to v3, since the v1 runtime is too old for GitHub Actions to run and the "Create GitHub Release" step can't work as is. v3 only moves the runtime to Node 24; the tag_name, body and generate_release_notes inputs used here are unchanged. A separate tag-and-push path built on `npm version` alone was considered and discarded: it would skip the lockfile pre-commit hook and duplicate what the action already does. --- .github/workflows/tag_and_release.yml | 41 +++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tag_and_release.yml b/.github/workflows/tag_and_release.yml index 2d464d3..19bd989 100644 --- a/.github/workflows/tag_and_release.yml +++ b/.github/workflows/tag_and_release.yml @@ -1,4 +1,4 @@ -name: Manual Tag & Release +name: Tag & Release (Manual Trigger) on: workflow_dispatch: @@ -8,6 +8,21 @@ on: required: true type: boolean default: false + release_type: + description: 'Version bump: auto (infer from commits) or force patch/minor/major' + required: true + type: choice + default: 'auto' + options: + - auto + - patch + - minor + - major + generate_changelog: + description: 'Generate/update CHANGELOG.md for this release?' + required: true + type: boolean + default: false jobs: release: @@ -25,9 +40,24 @@ jobs: with: node-version-file: '.nvmrc' + # The conventionalcommits preset bumps breaking changes to major even on + # 0.x, so an inferred bump could ship 1.0.0 by accident. + - name: Require an explicit bump during initial development + if: ${{ inputs.release_type == 'auto' }} + run: | + if node -p "require('./package.json').version" | grep -q '^0\.'; then + echo "::error::release_type must be patch, minor or major while the version is 0.x." + exit 1 + fi + - name: Ensure CHANGELOG.md exists + if: ${{ inputs.generate_changelog }} run: touch CHANGELOG.md + - name: Force version bump + if: ${{ inputs.release_type != 'auto' }} + run: npm version ${{ inputs.release_type }} --no-git-tag-version + - name: Generate Changelog and Tag id: changelog uses: TriPSs/conventional-changelog-action@v5 @@ -37,17 +67,18 @@ jobs: git-user-email: 'github-actions[bot]@users.noreply.github.com' git-message: 'chore(release): {version}' skip-on-empty: 'false' + skip-bump: ${{ inputs.release_type != 'auto' }} preset: 'conventionalcommits' skip-ci: 'false' tag-prefix: 'v' - input-file: './CHANGELOG.md' - output-file: './CHANGELOG.md' + input-file: ${{ inputs.generate_changelog && './CHANGELOG.md' || '' }} + output-file: ${{ inputs.generate_changelog && './CHANGELOG.md' || 'false' }} version-file: './package.json, ./package-lock.json' pre-commit: './.github/scripts/pre-commit.js' - name: Create GitHub Release - if: ${{ github.event.inputs.create_github_release == 'true' && steps.changelog.outputs.skipped == 'false' }} - uses: softprops/action-gh-release@v1 + if: ${{ inputs.create_github_release && steps.changelog.outputs.skipped == 'false' }} + uses: softprops/action-gh-release@v3 with: tag_name: ${{ steps.changelog.outputs.tag }} body: ${{ steps.changelog.outputs.clean_changelog }} From 78a48830c03fa278ba0360d63f3fce00d0a72853 Mon Sep 17 00:00:00 2001 From: Arthurk12 Date: Thu, 15 Oct 2026 13:46:00 -0300 Subject: [PATCH 5/7] ci: make npm publishing manual-only The publish workflow runs on every pushed v* tag, so pushing a tag publishes to npm right away, without a deliberate decision to release that version. Tagging and publishing should be independent steps, each triggered by hand. Drop the tag push trigger and keep workflow_dispatch only. Since a manual run can now be started from any ref, fail unless it runs from a tag matching the version in package.json, so a branch or a mismatched tag is never published. --- .github/workflows/publish.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 19f8df4..b3cae4b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,9 +2,6 @@ name: Publish to NPM on: workflow_dispatch: - push: - tags: - - 'v*' permissions: contents: read @@ -17,6 +14,14 @@ jobs: - name: Checkout uses: actions/checkout@v5 + - name: Require a release tag matching package.json + run: | + VERSION="v$(node -p "require('./package.json').version")" + if [ "${{ github.ref_type }}" != "tag" ] || [ "${{ github.ref_name }}" != "$VERSION" ]; then + echo "::error::Run this workflow from the release tag (expected $VERSION, got ${{ github.ref_type }} ${{ github.ref_name }})." + exit 1 + fi + - name: Setup Node.js uses: actions/setup-node@v5 with: From 276290df8eb5355e24b6e28284218645673cce5b Mon Sep 17 00:00:00 2001 From: Arthurk12 Date: Thu, 15 Oct 2026 13:46:04 -0300 Subject: [PATCH 6/7] ci(storybook): deploy develop to a /develop subpath alongside main Only main is published to GitHub Pages, so changes merged into develop can't be browsed or reviewed in Storybook until they are released. Trigger the deploy on pushes to develop as well, publishing it into a develop/ subdirectory of gh-pages while main stays at the root: - Before the main deploy, copy the current develop/ from gh-pages into the build output. The main deploy uses keep_files: false, which cleans the whole branch root, so without this copy it would remove develop/. If gh-pages doesn't exist yet (new repository or fork), skip the copy and let the deploy create the branch. - Run the job in a shared concurrency group with queue: max, so main and develop runs, which both push to gh-pages, wait in line instead of rejecting each other's push. With the default single pending slot, a newer pending run would cancel an older one. - Skip the job when it is dispatched manually from any branch other than main or develop, so a feature branch can never overwrite the published root. Deploying develop to a separate branch was considered and discarded: GitHub Pages serves a single site per repository, so another branch would not be published. --- .github/workflows/storybook-deploy.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/storybook-deploy.yml b/.github/workflows/storybook-deploy.yml index 9d9af42..c41fdbe 100644 --- a/.github/workflows/storybook-deploy.yml +++ b/.github/workflows/storybook-deploy.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - develop workflow_dispatch: {} permissions: @@ -13,6 +14,13 @@ permissions: jobs: build-and-deploy: + if: ${{ github.ref_name == 'main' || github.ref_name == 'develop' }} + # Both branches push to gh-pages; overlapping runs would reject each other's + # push, and the default single pending slot would drop a queued deploy. + concurrency: + group: gh-pages-deploy + cancel-in-progress: false + queue: max runs-on: ubuntu-latest steps: @@ -44,10 +52,20 @@ jobs: echo "storybook-static does not exist at ./storybook-static" fi + # The main deploy cleans the whole gh-pages root, develop/ included. + - name: Preserve the develop Storybook + if: ${{ github.ref_name == 'main' }} + run: | + git fetch --depth=1 origin gh-pages || exit 0 + if git ls-tree -d --name-only FETCH_HEAD develop | grep -q .; then + git archive FETCH_HEAD develop | tar -x -C ./storybook-static + fi + - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v4 with: publish_dir: ./storybook-static + destination_dir: ${{ github.ref_name == 'develop' && 'develop' || '' }} github_token: ${{ secrets.GITHUB_TOKEN }} publish_branch: gh-pages keep_files: false From 72e73458785c3093a72a675ec19c7159875126bc Mon Sep 17 00:00:00 2001 From: guiiBecker Date: Mon, 26 Oct 2026 09:05:16 -0300 Subject: [PATCH 7/7] feat(BBBToggle): add fullWidth prop to spread left/right-labelled rows --- src/components/Toggle/README.md | 8 +++++++ src/components/Toggle/component.stories.tsx | 25 +++++++++++++++++++++ src/components/Toggle/component.tsx | 7 ++++-- src/components/Toggle/styles.ts | 15 +++++++++++-- src/components/Toggle/types.ts | 4 ++++ 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/components/Toggle/README.md b/src/components/Toggle/README.md index 9cffe0a..3d59e07 100644 --- a/src/components/Toggle/README.md +++ b/src/components/Toggle/README.md @@ -27,6 +27,13 @@ import { BBBToggle } from 'bbb-ui-components-react'; ``` +### Full-width toggle with the label at the start and the switch at the end +```jsx +import { BBBToggle } from 'bbb-ui-components-react'; + + +``` + ### Toggle with label and helper text on the top ```jsx import { BBBToggle } from 'bbb-ui-components-react'; @@ -41,6 +48,7 @@ import { BBBToggle } from 'bbb-ui-components-react'; | `label` | `string` | | The main label text displayed next to the toggle. | | `helperText` | `string` | | The helper text displayed below the label. | | `textPosition` | `keyof typeof TEXT_POSITIONS` | `'right'` | The position of the text labels relative to the toggle switch. | +| `fullWidth` | `boolean` | `false` | If `true`, the toggle stretches to its container, putting the text and the switch at opposite ends. Only used with `textPosition` `'left'` (text at the start) or `'right'` (text at the end). | | `disabled` | `boolean` | `false` | If `true`, the toggle will be disabled and unresponsive. | | `onChange` | `(event: React.ChangeEvent, checked: boolean) => void` | | Callback function that is fired when the toggle state changes. | | `ariaLabel` | `string` | | The accessible name for the toggle. | diff --git a/src/components/Toggle/component.stories.tsx b/src/components/Toggle/component.stories.tsx index aecdce5..2f32c4e 100644 --- a/src/components/Toggle/component.stories.tsx +++ b/src/components/Toggle/component.stories.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import type { Meta, StoryObj } from '@storybook/react'; import BBBToggle from './component'; import { TEXT_POSITIONS_VALUES, DEFAULT_TEXT_POSITION } from './constants'; @@ -13,6 +14,11 @@ const meta = { description: 'Position of label/helper relative to the toggle.', table: { defaultValue: { summary: `${DEFAULT_TEXT_POSITION}` } }, }, + fullWidth: { + control: 'boolean', + description: `Stretches the row to its container, putting the text and the switch at opposite ends. Only used with textPosition 'left' or 'right'.`, + table: { defaultValue: { summary: 'false' } }, + }, label: { control: 'text', description: 'Main label text displayed next to the toggle.', @@ -43,3 +49,22 @@ type Story = StoryObj; export const Default: Story = { args: { label: 'Enable feature' } }; /** Adds helper text below the label, with the label/helper positioned to the right of the toggle. */ export const WithHelper: Story = { args: { label: 'Enable', helperText: 'Recommended', textPosition: 'right' } }; +/** Shows a `fullWidth` toggle in a settings row: label and helper text at the start, switch at the end. */ +export const FullWidth: Story = { + args: { + label: 'Join muted', + helperText: 'Joining users are muted by default', + textPosition: 'left', + fullWidth: true, + }, + render: (args) => ( +
+ +
+ ), +}; +/** Shows a `fullWidth` toggle with the text on the right: switch at the start, label and helper text at the end. */ +export const FullWidthTextRight: Story = { + ...FullWidth, + args: { ...FullWidth.args, textPosition: 'right' }, +}; diff --git a/src/components/Toggle/component.tsx b/src/components/Toggle/component.tsx index ae7afb7..21f7899 100644 --- a/src/components/Toggle/component.tsx +++ b/src/components/Toggle/component.tsx @@ -2,7 +2,7 @@ import React, { JSX, useId } from 'react'; import { SwitchOwnerState } from '@mui/material'; import { ToggleProps } from './types'; import * as Styled from './styles'; -import { DEFAULT_TEXT_POSITION } from './constants'; +import { DEFAULT_TEXT_POSITION, TEXT_POSITIONS } from './constants'; /** * A customizable Toggle switch component. @@ -15,6 +15,7 @@ function Toggle ({ label, helperText, textPosition = DEFAULT_TEXT_POSITION, + fullWidth = false, onChange, ariaLabel, ariaLabelledBy, @@ -27,6 +28,7 @@ function Toggle ({ const id = providedId ?? generatedUniqueId; const labelId = label ? `${id}-label` : undefined; const helperTextId = helperText ? `${id}-helper` : undefined; + const isFullWidth = fullWidth && (textPosition === TEXT_POSITIONS.LEFT || textPosition === TEXT_POSITIONS.RIGHT); const ariaLabelledByValue = ariaLabel ? undefined : ariaLabelledBy || labelId; // Without a name source, the

+ Participants will be notified. See the{' '} + + recording docs + {' '} + for details. +