From fa7fad6375ddc0296811229b75a3969772c00388 Mon Sep 17 00:00:00 2001 From: Rohan Chakraborty Date: Thu, 12 Mar 2026 16:41:27 +0530 Subject: [PATCH 1/5] feat: add Toolbar component based on Base UI primitive Co-Authored-By: Claude Opus 4.6 --- apps/www/src/components/playground/index.ts | 1 + .../playground/toolbar-examples.tsx | 95 +++++++++ .../content/docs/components/toolbar/demo.ts | 61 ++++++ .../content/docs/components/toolbar/index.mdx | 95 +++++++++ .../content/docs/components/toolbar/props.ts | 95 +++++++++ .../toolbar/__tests__/toolbar.test.tsx | 196 ++++++++++++++++++ .../raystack/components/toolbar/index.tsx | 1 + .../components/toolbar/toolbar.module.css | 50 +++++ .../raystack/components/toolbar/toolbar.tsx | 79 +++++++ packages/raystack/index.tsx | 1 + 10 files changed, 674 insertions(+) create mode 100644 apps/www/src/components/playground/toolbar-examples.tsx create mode 100644 apps/www/src/content/docs/components/toolbar/demo.ts create mode 100644 apps/www/src/content/docs/components/toolbar/index.mdx create mode 100644 apps/www/src/content/docs/components/toolbar/props.ts create mode 100644 packages/raystack/components/toolbar/__tests__/toolbar.test.tsx create mode 100644 packages/raystack/components/toolbar/index.tsx create mode 100644 packages/raystack/components/toolbar/toolbar.module.css create mode 100644 packages/raystack/components/toolbar/toolbar.tsx diff --git a/apps/www/src/components/playground/index.ts b/apps/www/src/components/playground/index.ts index 62ec07833..5d32811a0 100644 --- a/apps/www/src/components/playground/index.ts +++ b/apps/www/src/components/playground/index.ts @@ -44,4 +44,5 @@ export * from './tabs-examples'; export * from './text-area-examples'; export * from './text-examples'; export * from './toast-examples'; +export * from './toolbar-examples'; export * from './tooltip-examples'; diff --git a/apps/www/src/components/playground/toolbar-examples.tsx b/apps/www/src/components/playground/toolbar-examples.tsx new file mode 100644 index 000000000..bbe0eb77a --- /dev/null +++ b/apps/www/src/components/playground/toolbar-examples.tsx @@ -0,0 +1,95 @@ +'use client'; + +import { + FontBoldIcon, + FontItalicIcon, + TextAlignCenterIcon, + TextAlignLeftIcon, + TextAlignRightIcon, + UnderlineIcon +} from '@radix-ui/react-icons'; +import { Button, Flex, IconButton, Text, Toolbar } from '@raystack/apsara'; +import PlaygroundLayout from './playground-layout'; + +export function ToolbarExamples() { + return ( + + + Default: + + Bold + Italic + + Left + Center + Right + + + Grouped with composition: + + } + > + 32px + + + + + } + > + + + + } + > + + + + } + > + + + + + + + } + > + + + + } + > + + + + } + > + + + + + + Disabled: + + Bold + Italic + + Left + + + + ); +} diff --git a/apps/www/src/content/docs/components/toolbar/demo.ts b/apps/www/src/content/docs/components/toolbar/demo.ts new file mode 100644 index 000000000..86db53cba --- /dev/null +++ b/apps/www/src/content/docs/components/toolbar/demo.ts @@ -0,0 +1,61 @@ +'use client'; + +export const preview = { + type: 'code', + code: ` + Bold + Italic + Underline + + Left + Center + Right +` +}; + +export const groupDemo = { + type: 'code', + code: ` + + Bold + Italic + Underline + + + + Left + Center + Right + +` +}; + +export const compositionDemo = { + type: 'code', + code: ` + }> + 32px + + + + }> + + + }> + + + + + Help +` +}; + +export const disabledDemo = { + type: 'code', + code: ` + Bold + Italic + + Left +` +}; diff --git a/apps/www/src/content/docs/components/toolbar/index.mdx b/apps/www/src/content/docs/components/toolbar/index.mdx new file mode 100644 index 000000000..256b86207 --- /dev/null +++ b/apps/www/src/content/docs/components/toolbar/index.mdx @@ -0,0 +1,95 @@ +--- +title: Toolbar +description: A container for grouping interactive controls with accessible keyboard navigation. +source: packages/raystack/components/toolbar +tag: new +--- + +import { preview, groupDemo, compositionDemo, disabledDemo } from "./demo.ts"; + + + +## Anatomy + +Import and assemble the component: + +```tsx +import { Toolbar } from '@raystack/apsara' + + + + + + + + + + + +``` + +## API Reference + +### Root + +Groups all toolbar controls. Manages keyboard navigation between items. + + + +### Button + +An interactive button within the toolbar. Supports the `render` prop to compose with other components like `Button` or `IconButton`. + + + +### Group + +Groups related toolbar items together. + + + +### Separator + +A visual divider between toolbar sections. + + + +### Link + +An anchor element for navigation within the toolbar. + + + +### Input + +A native input element with integrated keyboard navigation. + + + +## Examples + +### Grouped + +Use `Toolbar.Group` to group related buttons. + + + +### Composition + +Use the `render` prop on `Toolbar.Button` to compose with Apsara components like `Button` and `IconButton`. + + + +### Disabled + +Disable all toolbar items by setting `disabled` on the root. + + + +## Accessibility + +- Uses `role="toolbar"` for proper semantic grouping +- Arrow keys navigate between focusable items +- `Home` and `End` keys jump to first and last items +- Focus loops by default (configurable via `loopFocus`) +- Disabled items remain focusable for screen reader discoverability diff --git a/apps/www/src/content/docs/components/toolbar/props.ts b/apps/www/src/content/docs/components/toolbar/props.ts new file mode 100644 index 000000000..744642267 --- /dev/null +++ b/apps/www/src/content/docs/components/toolbar/props.ts @@ -0,0 +1,95 @@ +export interface ToolbarProps { + /** + * Whether keyboard navigation loops from the last item back to the first. + * @defaultValue true + */ + loopFocus?: boolean; + + /** + * The orientation of the toolbar layout. + * @defaultValue "horizontal" + */ + orientation?: 'horizontal' | 'vertical'; + + /** + * Whether the toolbar and all its items are disabled. + * @defaultValue false + */ + disabled?: boolean; + + /** Additional CSS class names. */ + className?: string; +} + +export interface ToolbarButtonProps { + /** + * Whether the button remains focusable when disabled. + * @defaultValue true + */ + focusableWhenDisabled?: boolean; + + /** + * Whether the button is disabled. + * @defaultValue false + */ + disabled?: boolean; + + /** + * Allows you to replace the component's HTML element with a different tag, or compose it with another component. + * + * @remarks `ReactElement | function` + */ + render?: + | React.ReactElement + | ((props: React.HTMLAttributes) => React.ReactElement); + + /** Additional CSS class names. */ + className?: string; +} + +export interface ToolbarGroupProps { + /** + * Whether the group and all its items are disabled. + * @defaultValue false + */ + disabled?: boolean; + + /** Additional CSS class names. */ + className?: string; +} + +export interface ToolbarSeparatorProps { + /** Additional CSS class names. */ + className?: string; +} + +export interface ToolbarLinkProps { + /** + * Allows you to replace the component's HTML element with a different tag, or compose it with another component. + * + * @remarks `ReactElement | function` + */ + render?: + | React.ReactElement + | ((props: React.HTMLAttributes) => React.ReactElement); + + /** Additional CSS class names. */ + className?: string; +} + +export interface ToolbarInputProps { + /** + * Whether the input remains focusable when disabled. + * @defaultValue true + */ + focusableWhenDisabled?: boolean; + + /** + * Whether the input is disabled. + * @defaultValue false + */ + disabled?: boolean; + + /** Additional CSS class names. */ + className?: string; +} diff --git a/packages/raystack/components/toolbar/__tests__/toolbar.test.tsx b/packages/raystack/components/toolbar/__tests__/toolbar.test.tsx new file mode 100644 index 000000000..67b48e807 --- /dev/null +++ b/packages/raystack/components/toolbar/__tests__/toolbar.test.tsx @@ -0,0 +1,196 @@ +import { fireEvent, render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { createRef } from 'react'; +import { describe, expect, it, vi } from 'vitest'; +import { Toolbar } from '../toolbar'; +import styles from '../toolbar.module.css'; + +describe('Toolbar', () => { + it('renders with children', () => { + render( + + Bold + + ); + expect(screen.getByRole('toolbar')).toBeInTheDocument(); + expect(screen.getByText('Bold')).toBeInTheDocument(); + }); + + it('applies custom className to root', () => { + render(content); + const toolbar = screen.getByRole('toolbar'); + expect(toolbar.className).toContain(styles.root); + expect(toolbar.className).toContain('custom'); + }); + + it('forwards ref to root', () => { + const ref = createRef(); + render(content); + expect(ref.current).toBeInstanceOf(HTMLDivElement); + expect(ref.current).toBe(screen.getByRole('toolbar')); + }); + + describe('Button', () => { + it('renders as a button', () => { + render( + + Click + + ); + expect(screen.getByRole('button', { name: 'Click' })).toBeInTheDocument(); + }); + + it('handles click events', async () => { + const onClick = vi.fn(); + render( + + Click + + ); + fireEvent.click(screen.getByRole('button')); + expect(onClick).toHaveBeenCalledTimes(1); + }); + + it('applies custom className', () => { + render( + + Click + + ); + const button = screen.getByRole('button'); + expect(button.className).toContain(styles.button); + expect(button.className).toContain('custom'); + }); + + it('forwards ref', () => { + const ref = createRef(); + render( + + Click + + ); + expect(ref.current).toBeInstanceOf(HTMLButtonElement); + }); + }); + + describe('Group', () => { + it('renders children in a group', () => { + render( + + + A + B + + + ); + const group = screen.getByTestId('group'); + expect(group.className).toContain(styles.group); + expect(screen.getByText('A')).toBeInTheDocument(); + expect(screen.getByText('B')).toBeInTheDocument(); + }); + + it('forwards ref', () => { + const ref = createRef(); + render( + + + A + + + ); + expect(ref.current).toBeInstanceOf(HTMLDivElement); + }); + }); + + describe('Separator', () => { + it('renders a separator', () => { + render( + + + + ); + const sep = screen.getByTestId('sep'); + expect(sep).toBeInTheDocument(); + expect(sep.className).toContain(styles.separator); + }); + + it('forwards ref', () => { + const ref = createRef(); + render( + + + + ); + expect(ref.current).toBeInstanceOf(HTMLDivElement); + }); + }); + + describe('Link', () => { + it('renders a link', () => { + render( + + Example + + ); + const link = screen.getByRole('link', { name: 'Example' }); + expect(link).toBeInTheDocument(); + expect(link).toHaveAttribute('href', 'https://example.com'); + }); + + it('forwards ref', () => { + const ref = createRef(); + render( + + + Link + + + ); + expect(ref.current).toBeInstanceOf(HTMLAnchorElement); + }); + }); + + describe('Input', () => { + it('renders an input', () => { + render( + + + + ); + expect(screen.getByTestId('input')).toBeInTheDocument(); + }); + + it('forwards ref', () => { + const ref = createRef(); + render( + + + + ); + expect(ref.current).toBeInstanceOf(HTMLInputElement); + }); + }); + + describe('Keyboard navigation', () => { + it('navigates between buttons with arrow keys', async () => { + const user = userEvent.setup(); + render( + + First + Second + Third + + ); + + const first = screen.getByText('First'); + first.focus(); + expect(first).toHaveFocus(); + + await user.keyboard('{ArrowRight}'); + expect(screen.getByText('Second')).toHaveFocus(); + + await user.keyboard('{ArrowRight}'); + expect(screen.getByText('Third')).toHaveFocus(); + }); + }); +}); diff --git a/packages/raystack/components/toolbar/index.tsx b/packages/raystack/components/toolbar/index.tsx new file mode 100644 index 000000000..dc5abb129 --- /dev/null +++ b/packages/raystack/components/toolbar/index.tsx @@ -0,0 +1 @@ +export { Toolbar } from './toolbar'; diff --git a/packages/raystack/components/toolbar/toolbar.module.css b/packages/raystack/components/toolbar/toolbar.module.css new file mode 100644 index 000000000..f9c52d459 --- /dev/null +++ b/packages/raystack/components/toolbar/toolbar.module.css @@ -0,0 +1,50 @@ +.root { + display: flex; + align-items: center; + gap: var(--rs-space-1); + padding: var(--rs-space-1); + border: 0.5px solid var(--rs-color-border-base-primary); + border-radius: var(--rs-radius-2); + overflow: clip; +} + +.button { + cursor: pointer; + background: none; + border: none; + outline: none; + padding: var(--rs-space-1) var(--rs-space-2); + border-radius: var(--rs-radius-2); + font-family: var(--rs-font-body); + font-size: var(--rs-font-size-mini); + font-weight: var(--rs-font-weight-medium); + line-height: var(--rs-line-height-mini); + letter-spacing: var(--rs-letter-spacing-mini); + color: var(--rs-color-foreground-base-primary); +} + +.button:hover, +.button:focus-visible { + background-color: var(--rs-color-background-base-primary-hover); +} + +.button[data-disabled] { + pointer-events: none; + opacity: 0.5; +} + +.group { + display: flex; + align-items: center; +} + +.group > * { + border: none; +} + +.separator { + flex-shrink: 0; + width: 0.5px; + height: 16px; + background-color: var(--rs-color-border-base-primary); +} diff --git a/packages/raystack/components/toolbar/toolbar.tsx b/packages/raystack/components/toolbar/toolbar.tsx new file mode 100644 index 000000000..54be0e3fd --- /dev/null +++ b/packages/raystack/components/toolbar/toolbar.tsx @@ -0,0 +1,79 @@ +'use client'; + +import { Toolbar as ToolbarPrimitive } from '@base-ui/react/toolbar'; +import { cx } from 'class-variance-authority'; +import { ElementRef, forwardRef } from 'react'; + +import styles from './toolbar.module.css'; + +const ToolbarRoot = forwardRef< + ElementRef, + ToolbarPrimitive.Root.Props +>(({ className, ...props }, ref) => ( + +)); +ToolbarRoot.displayName = 'Toolbar'; + +const ToolbarButton = forwardRef< + ElementRef, + ToolbarPrimitive.Button.Props +>(({ className, ...props }, ref) => ( + +)); +ToolbarButton.displayName = 'Toolbar.Button'; + +const ToolbarGroup = forwardRef< + ElementRef, + ToolbarPrimitive.Group.Props +>(({ className, ...props }, ref) => ( + +)); +ToolbarGroup.displayName = 'Toolbar.Group'; + +const ToolbarSeparator = forwardRef< + ElementRef, + ToolbarPrimitive.Separator.Props +>(({ className, ...props }, ref) => ( + +)); +ToolbarSeparator.displayName = 'Toolbar.Separator'; + +const ToolbarLink = forwardRef< + ElementRef, + ToolbarPrimitive.Link.Props +>(({ className, ...props }, ref) => ( + +)); +ToolbarLink.displayName = 'Toolbar.Link'; + +const ToolbarInput = forwardRef< + ElementRef, + ToolbarPrimitive.Input.Props +>(({ className, ...props }, ref) => ( + +)); +ToolbarInput.displayName = 'Toolbar.Input'; + +export const Toolbar = Object.assign(ToolbarRoot, { + Button: ToolbarButton, + Group: ToolbarGroup, + Separator: ToolbarSeparator, + Link: ToolbarLink, + Input: ToolbarInput +}); diff --git a/packages/raystack/index.tsx b/packages/raystack/index.tsx index 37885b603..edf337c04 100644 --- a/packages/raystack/index.tsx +++ b/packages/raystack/index.tsx @@ -68,4 +68,5 @@ export { useTheme } from './components/theme-provider'; export { Toast, toastManager } from './components/toast'; +export { Toolbar } from './components/toolbar'; export { Tooltip } from './components/tooltip'; From 0384539d6833160bc61a8666d5a27222e7e77002 Mon Sep 17 00:00:00 2001 From: Rohan Chakraborty Date: Tue, 17 Mar 2026 15:35:36 +0530 Subject: [PATCH 2/5] fix: toolbar styles and composition --- .../content/docs/components/toolbar/demo.ts | 26 +++++++------ .../components/toolbar/toolbar.module.css | 38 ++++--------------- .../raystack/components/toolbar/toolbar.tsx | 26 ++----------- 3 files changed, 27 insertions(+), 63 deletions(-) diff --git a/apps/www/src/content/docs/components/toolbar/demo.ts b/apps/www/src/content/docs/components/toolbar/demo.ts index 86db53cba..e752133df 100644 --- a/apps/www/src/content/docs/components/toolbar/demo.ts +++ b/apps/www/src/content/docs/components/toolbar/demo.ts @@ -33,20 +33,24 @@ export const groupDemo = { export const compositionDemo = { type: 'code', code: ` - }> - 32px - + }> + } > + }> + - - }> - - - }> - - + + Format - Help + ` }; diff --git a/packages/raystack/components/toolbar/toolbar.module.css b/packages/raystack/components/toolbar/toolbar.module.css index f9c52d459..01c730cab 100644 --- a/packages/raystack/components/toolbar/toolbar.module.css +++ b/packages/raystack/components/toolbar/toolbar.module.css @@ -1,50 +1,28 @@ .root { - display: flex; - align-items: center; - gap: var(--rs-space-1); padding: var(--rs-space-1); border: 0.5px solid var(--rs-color-border-base-primary); border-radius: var(--rs-radius-2); overflow: clip; } - -.button { - cursor: pointer; - background: none; - border: none; - outline: none; - padding: var(--rs-space-1) var(--rs-space-2); - border-radius: var(--rs-radius-2); - font-family: var(--rs-font-body); - font-size: var(--rs-font-size-mini); - font-weight: var(--rs-font-weight-medium); - line-height: var(--rs-line-height-mini); - letter-spacing: var(--rs-letter-spacing-mini); - color: var(--rs-color-foreground-base-primary); -} - -.button:hover, -.button:focus-visible { - background-color: var(--rs-color-background-base-primary-hover); -} - -.button[data-disabled] { - pointer-events: none; - opacity: 0.5; -} - +.root, .group { display: flex; align-items: center; + gap: var(--rs-space-1); } +.root > *, .group > * { border: none; } .separator { flex-shrink: 0; - width: 0.5px; + width: 1px; height: 16px; background-color: var(--rs-color-border-base-primary); } +.group { + padding: 0; + background-color: none; +} diff --git a/packages/raystack/components/toolbar/toolbar.tsx b/packages/raystack/components/toolbar/toolbar.tsx index 54be0e3fd..e38aa9dab 100644 --- a/packages/raystack/components/toolbar/toolbar.tsx +++ b/packages/raystack/components/toolbar/toolbar.tsx @@ -3,7 +3,7 @@ import { Toolbar as ToolbarPrimitive } from '@base-ui/react/toolbar'; import { cx } from 'class-variance-authority'; import { ElementRef, forwardRef } from 'react'; - +import { Button } from '../button'; import styles from './toolbar.module.css'; const ToolbarRoot = forwardRef< @@ -21,10 +21,10 @@ ToolbarRoot.displayName = 'Toolbar'; const ToolbarButton = forwardRef< ElementRef, ToolbarPrimitive.Button.Props ->(({ className, ...props }, ref) => ( +>((props, ref) => ( } {...props} /> )); @@ -54,26 +54,8 @@ const ToolbarSeparator = forwardRef< )); ToolbarSeparator.displayName = 'Toolbar.Separator'; -const ToolbarLink = forwardRef< - ElementRef, - ToolbarPrimitive.Link.Props ->(({ className, ...props }, ref) => ( - -)); -ToolbarLink.displayName = 'Toolbar.Link'; - -const ToolbarInput = forwardRef< - ElementRef, - ToolbarPrimitive.Input.Props ->(({ className, ...props }, ref) => ( - -)); -ToolbarInput.displayName = 'Toolbar.Input'; - export const Toolbar = Object.assign(ToolbarRoot, { Button: ToolbarButton, Group: ToolbarGroup, - Separator: ToolbarSeparator, - Link: ToolbarLink, - Input: ToolbarInput + Separator: ToolbarSeparator }); From 650af12554ddf005e6c8b67bc0d4bcb0ab927b94 Mon Sep 17 00:00:00 2001 From: Rohan Chakraborty Date: Tue, 17 Mar 2026 15:52:25 +0530 Subject: [PATCH 3/5] fix: breaking toolbar tests --- .../toolbar/__tests__/toolbar.test.tsx | 53 ++----------------- 1 file changed, 3 insertions(+), 50 deletions(-) diff --git a/packages/raystack/components/toolbar/__tests__/toolbar.test.tsx b/packages/raystack/components/toolbar/__tests__/toolbar.test.tsx index 67b48e807..b45d19c00 100644 --- a/packages/raystack/components/toolbar/__tests__/toolbar.test.tsx +++ b/packages/raystack/components/toolbar/__tests__/toolbar.test.tsx @@ -58,7 +58,6 @@ describe('Toolbar', () => { ); const button = screen.getByRole('button'); - expect(button.className).toContain(styles.button); expect(button.className).toContain('custom'); }); @@ -125,52 +124,6 @@ describe('Toolbar', () => { }); }); - describe('Link', () => { - it('renders a link', () => { - render( - - Example - - ); - const link = screen.getByRole('link', { name: 'Example' }); - expect(link).toBeInTheDocument(); - expect(link).toHaveAttribute('href', 'https://example.com'); - }); - - it('forwards ref', () => { - const ref = createRef(); - render( - - - Link - - - ); - expect(ref.current).toBeInstanceOf(HTMLAnchorElement); - }); - }); - - describe('Input', () => { - it('renders an input', () => { - render( - - - - ); - expect(screen.getByTestId('input')).toBeInTheDocument(); - }); - - it('forwards ref', () => { - const ref = createRef(); - render( - - - - ); - expect(ref.current).toBeInstanceOf(HTMLInputElement); - }); - }); - describe('Keyboard navigation', () => { it('navigates between buttons with arrow keys', async () => { const user = userEvent.setup(); @@ -182,15 +135,15 @@ describe('Toolbar', () => { ); - const first = screen.getByText('First'); + const first = screen.getByRole('button', { name: 'First' }); first.focus(); expect(first).toHaveFocus(); await user.keyboard('{ArrowRight}'); - expect(screen.getByText('Second')).toHaveFocus(); + expect(screen.getByRole('button', { name: 'Second' })).toHaveFocus(); await user.keyboard('{ArrowRight}'); - expect(screen.getByText('Third')).toHaveFocus(); + expect(screen.getByRole('button', { name: 'Third' })).toHaveFocus(); }); }); }); From f7b94dc65263fccc37cd71bbe116b28bbdc59e39 Mon Sep 17 00:00:00 2001 From: Rohan Chakraborty Date: Tue, 17 Mar 2026 16:31:46 +0530 Subject: [PATCH 4/5] feat: add toolbar vertical support --- .../src/content/docs/components/toolbar/demo.ts | 17 +++++++++++++++++ .../content/docs/components/toolbar/index.mdx | 10 ++++++++-- .../components/toolbar/toolbar.module.css | 14 ++++++++++++-- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/apps/www/src/content/docs/components/toolbar/demo.ts b/apps/www/src/content/docs/components/toolbar/demo.ts index e752133df..2c4338094 100644 --- a/apps/www/src/content/docs/components/toolbar/demo.ts +++ b/apps/www/src/content/docs/components/toolbar/demo.ts @@ -30,6 +30,23 @@ export const groupDemo = { ` }; +export const verticalDemo = { + type: 'code', + code: ` + + Bold + Italic + Underline + + + + Left + Center + Right + +` +}; + export const compositionDemo = { type: 'code', code: ` diff --git a/apps/www/src/content/docs/components/toolbar/index.mdx b/apps/www/src/content/docs/components/toolbar/index.mdx index 256b86207..db8bd1d90 100644 --- a/apps/www/src/content/docs/components/toolbar/index.mdx +++ b/apps/www/src/content/docs/components/toolbar/index.mdx @@ -5,7 +5,7 @@ source: packages/raystack/components/toolbar tag: new --- -import { preview, groupDemo, compositionDemo, disabledDemo } from "./demo.ts"; +import { preview, groupDemo, verticalDemo, compositionDemo, disabledDemo } from "./demo.ts"; @@ -74,9 +74,15 @@ Use `Toolbar.Group` to group related buttons. +### Vertical + +Use the `orientation` prop to render the toolbar vertically. + + + ### Composition -Use the `render` prop on `Toolbar.Button` to compose with Apsara components like `Button` and `IconButton`. +Use the `render` prop to compose with other components. diff --git a/packages/raystack/components/toolbar/toolbar.module.css b/packages/raystack/components/toolbar/toolbar.module.css index 01c730cab..c371a4e9f 100644 --- a/packages/raystack/components/toolbar/toolbar.module.css +++ b/packages/raystack/components/toolbar/toolbar.module.css @@ -10,6 +10,10 @@ align-items: center; gap: var(--rs-space-1); } +.root[data-orientation="vertical"], +.root[data-orientation="vertical"] .group { + flex-direction: column; +} .root > *, .group > * { @@ -18,10 +22,16 @@ .separator { flex-shrink: 0; - width: 1px; - height: 16px; background-color: var(--rs-color-border-base-primary); } +.separator[data-orientation="vertical"] { + width: 1px; + height: var(--rs-space-5); +} +.separator[data-orientation="horizontal"] { + width: calc(100% - var(--rs-space-3)); + height: 1px; +} .group { padding: 0; background-color: none; From 2a37f41d96b1325edc351706696127a457f8c3da Mon Sep 17 00:00:00 2001 From: Rohan Chakraborty Date: Tue, 17 Mar 2026 16:33:00 +0530 Subject: [PATCH 5/5] fix: vertical orientation button size --- packages/raystack/components/toolbar/toolbar.module.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/raystack/components/toolbar/toolbar.module.css b/packages/raystack/components/toolbar/toolbar.module.css index c371a4e9f..e9b76ca5f 100644 --- a/packages/raystack/components/toolbar/toolbar.module.css +++ b/packages/raystack/components/toolbar/toolbar.module.css @@ -15,6 +15,9 @@ flex-direction: column; } +.root[data-orientation="vertical"] button { + width: 100%; +} .root > *, .group > * { border: none;