diff --git a/README.md b/README.md
index 8f6d7b0..6fbee16 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@ Below is a list of the components available in this library. Each component has
- [BBBCheckbox](./src/components/Checkbox/README.md)
- [BBBDivider](./src/components/Divider/README.md)
- [BBBHint](./src/components/Hint/README.md)
+- [BBBInput](./src/components/Input/README.md)
- [BBBModal](./src/components/Modal//README.md)
- [BBBNavigation](./src/components/Navigation/README.md)
- [BBBSearch](./src/components/Search/README.md)
diff --git a/package.json b/package.json
index 9f3e200..c867055 100644
--- a/package.json
+++ b/package.json
@@ -50,6 +50,13 @@
"require": "./dist/components/Hint.js",
"default": "./dist/components/Hint.js"
},
+ "./Input": {
+ "types": "./dist/types/components/Input/index.d.ts",
+ "node": "./dist/components/Input.js",
+ "import": "./dist/esm/components/Input/index.js",
+ "require": "./dist/components/Input.js",
+ "default": "./dist/components/Input.js"
+ },
"./Modal": {
"types": "./dist/types/components/Modal/index.d.ts",
"node": "./dist/components/Modal.js",
@@ -172,6 +179,9 @@
"Hint": [
"dist/types/components/Hint/index.d.ts"
],
+ "Input": [
+ "dist/types/components/Input/index.d.ts"
+ ],
"Modal": [
"dist/types/components/Modal/index.d.ts"
],
diff --git a/src/components/Button/README.md b/src/components/Button/README.md
index 9438bcd..50b6299 100644
--- a/src/components/Button/README.md
+++ b/src/components/Button/README.md
@@ -1,6 +1,6 @@
# BBButton
-The `BBButton` component is a versatile button that supports multiple layouts and styles. It can be rendered as a standard inline button, a circular icon button, or a stacked button with an icon and a label.
+The `BBButton` component is a versatile button that supports multiple layouts and styles. It can be rendered as a standard inline button, a circular icon button, a compact squared icon button, or a stacked button with an icon and a label.

@@ -33,6 +33,15 @@ import { MdFavorite } from 'react-icons/md';
} tooltipLabel="Favorite" onClick={() => (console.log('clicked'))}/>
```
+### Squared Button
+
+```jsx
+import { BBButton } from 'bbb-ui-components-react';
+import { MdSend } from 'react-icons/md';
+
+} ariaLabel="Send" onClick={() => (console.log('clicked'))}/>
+```
+
### Stacked Button
```jsx
@@ -62,7 +71,7 @@ import { MdPlayArrow } from 'react-icons/md';
| `layout` | `keyof typeof LAYOUTS` | `'default'` | The layout of the button. |
| `disabled` | `boolean` | `false` | If `true`, the button will be disabled. |
| `children` | `React.ReactNode` | | The content of the button, typically used for the 'default' layout. |
-| `icon` | `React.ReactNode` | | The icon to be displayed. Used for 'circle' and 'stacked' layouts. |
+| `icon` | `React.ReactNode` | | The icon to be displayed. Used for 'circle', 'squared' and 'stacked' layouts. |
| `iconStart` | `React.ReactNode` | | The icon to be displayed at the start of the button. Used for 'default' layout.|
| `iconEnd` | `React.ReactNode` | | The icon to be displayed at the end of the button. Used for 'default' layout. |
| `helperIcon` | `React.ReactNode` | | The auxiliary icon to be displayed. Used for 'stacked' layout. |
diff --git a/src/components/Button/component.stories.tsx b/src/components/Button/component.stories.tsx
index 12a4806..d393508 100644
--- a/src/components/Button/component.stories.tsx
+++ b/src/components/Button/component.stories.tsx
@@ -69,7 +69,7 @@ const meta = {
},
icon: {
control: false,
- description: `Main icon for the button. Commonly used for icon-only buttons (layout 'circle') or in 'stacked' layout. When using a label, prefer \`iconStart\` or \`iconEnd\` in the 'default' layout.`,
+ description: `Main icon for the button. Commonly used for icon-only buttons (layouts 'circle' and 'squared') or in 'stacked' layout. When using a label, prefer \`iconStart\` or \`iconEnd\` in the 'default' layout.`,
table: { defaultValue: { summary: 'null' } },
},
iconStart: {
@@ -247,6 +247,28 @@ export const Circle: Story = {
),
};
+export const Squared: Story = {
+ name: 'Squared',
+ args: {
+ tooltipPlacement: 'top',
+ variant: 'primary',
+ layout: 'squared',
+ icon: ,
+ },
+ render: (args) => (
+
+ {COLOR_VALUES.map((color) => (
+
+ ))}
+
+ ),
+};
+
export const WithIcon: Story = {
args: {
label: 'Like',
diff --git a/src/components/Button/component.tsx b/src/components/Button/component.tsx
index bb96125..1869686 100644
--- a/src/components/Button/component.tsx
+++ b/src/components/Button/component.tsx
@@ -53,7 +53,7 @@ function Button(props: ButtonProps): JSX.Element {
if (ariaDescribedBy) accessibilityProps['aria-describedby'] = ariaDescribedBy;
const buttonElement = (() => {
- if (props.layout === LAYOUTS.CIRCLE) {
+ if (props.layout === LAYOUTS.CIRCLE || props.layout === LAYOUTS.SQUARED) {
const { icon } = props;
const testId = dataTest || `button-${id || 'default'}`;
diff --git a/src/components/Button/constants.ts b/src/components/Button/constants.ts
index 7deb88f..f0fe7ea 100644
--- a/src/components/Button/constants.ts
+++ b/src/components/Button/constants.ts
@@ -46,6 +46,7 @@ const LAYOUTS = {
DEFAULT: 'default',
STACKED: 'stacked',
CIRCLE: 'circle',
+ SQUARED: 'squared',
} as const;
const LAYOUT_VALUES = Object.values(LAYOUTS);
const DEFAULT_LAYOUT = LAYOUT_VALUES[0];
diff --git a/src/components/Button/styles.ts b/src/components/Button/styles.ts
index 25256a8..5683fba 100644
--- a/src/components/Button/styles.ts
+++ b/src/components/Button/styles.ts
@@ -15,6 +15,7 @@ import {
} from './type';
import {
borderRadiusDefault,
+ borderRadiusSmall,
spacingSmall,
} from '../../stylesheets/sizing';
import { colorBorderDefault, colorTextDefault } from '../../stylesheets/pallete';
@@ -129,6 +130,18 @@ const circleLayoutStyles = css`
align-items: center;
`;
+// Icon-only, sized by its own (equal, non-text) padding rather than a fixed
+// box — stays compact next to a single line of text instead of forcing a
+// fixed height like circle/stacked do.
+const squaredLayoutStyles = css`
+ border-radius: ${borderRadiusSmall};
+ aspect-ratio: 1;
+ padding: ${spacingSmall};
+ display: flex;
+ justify-content: center;
+ align-items: center;
+`;
+
const defaultLayoutStyles = css`
display: inline-flex;
justify-content: center;
@@ -156,6 +169,8 @@ export const Button = styled.button`
return stackedLayoutStyles;
case LAYOUTS.CIRCLE:
return circleLayoutStyles;
+ case LAYOUTS.SQUARED:
+ return squaredLayoutStyles;
default:
return defaultLayoutStyles;
}
diff --git a/src/components/Button/type.ts b/src/components/Button/type.ts
index a48b355..29857ef 100644
--- a/src/components/Button/type.ts
+++ b/src/components/Button/type.ts
@@ -97,4 +97,9 @@ type CircleLayoutProps = BaseButtonProps & {
icon?: React.ReactNode;
};
-export type ButtonProps = DefaultLayoutProps | StackedLayoutProps | CircleLayoutProps;
+type SquaredLayoutProps = BaseButtonProps & {
+ layout: typeof LAYOUTS.SQUARED;
+ icon?: React.ReactNode;
+};
+
+export type ButtonProps = DefaultLayoutProps | StackedLayoutProps | CircleLayoutProps | SquaredLayoutProps;
diff --git a/src/components/Input/README.md b/src/components/Input/README.md
new file mode 100644
index 0000000..f8ac888
--- /dev/null
+++ b/src/components/Input/README.md
@@ -0,0 +1,118 @@
+# BBBInput
+
+The `BBBInput` component provides a labeled, auto-growing text field with an inline action button. It unifies the recurring "text field + submit button" pattern used across chat, guest messages, breakouts and similar areas, modeled after the core chat text input.
+
+`BBBTextInput` and `BBBTextAreaInput` remain the right choice for standalone fields with no inline action button.
+
+## Usage Example
+
+### Basic usage — text field with a submit icon button
+```jsx
+import { BBBInput } from 'bbb-ui-components-react';
+import { MdSend } from 'react-icons/md';
+
+}
+ buttonAriaLabel="Send message"
+ onSubmit={(value) => handleSend(value)}
+/>
+```
+
+### With a text button label instead of an icon
+```jsx
+ sendGuestMessage(value)}
+/>
+```
+
+### Controlled
+```jsx
+const [value, setValue] = useState('');
+
+}
+ buttonAriaLabel="Send message"
+ onSubmit={(submittedValue) => {
+ submitMessage(submittedValue);
+ setValue('');
+ }}
+/>
+```
+
+### With sent feedback
+```jsx
+}
+ buttonAriaLabel="Send message"
+ showSentFeedback
+ onSubmit={(value) => handleSend(value)}
+/>
+```
+
+### With extra actions around the submit button
+```jsx
+import { MdEmojiEmotions } from 'react-icons/md';
+
+}
+ buttonAriaLabel="Send message"
+ beforeButton={(
+
+ )}
+ onSubmit={(value) => handleSend(value)}
+/>
+```
+
+## Props
+
+| Property | Type | Default | Description |
+| ----------------------- | --------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------ |
+| `label` | `string` | | Label displayed above the field. |
+| `placeholder` | `string` | | Placeholder text displayed when the field is empty. |
+| `value` | `string` | | Controlled value. Enables controlled mode when provided together with `onChange`. |
+| `onChange` | `(value: string) => void` | | Called on every keystroke. Required in controlled mode. |
+| `onSubmit` | `(value: string) => void` | | Called with the trimmed, non-empty value when the field is submitted. **Required.** |
+| `buttonIcon` | `React.ReactNode` | | Icon rendered inside the action button. |
+| `buttonLabel` | `string` | | Text label rendered by the action button, instead of (or alongside) `buttonIcon`. |
+| `buttonAriaLabel` | `string` | | Accessible name for the action button. **Required** when only `buttonIcon` is set (no `buttonLabel`). |
+| `buttonVariant` | `'primary' \| 'secondary' \| 'tertiary' \| 'subtle'` | `'primary'` | Visual variant of the action button (same variants as the shared `Button`). |
+| `dataTest` | `string` | | `data-test` attribute on the underlying `