Selection Actions

Select text and a bar of agent actions appears under it.

Washed Huila opens with red apple and panela, then settles into a finish that stays long and sweet well after the cup cools. Select any words to ask about them.

'use client';

import { useState } from 'react';
import { SelectionActions, StreamingText } from '@brand-studio/ui';

const replies: Record<string, (text: string) => string> = {
  explain: text => `“${text}” means the flavour the coffee leaves after you swallow, and how long it lasts.`,
  shorten: () => 'A long, sweet finish.',
  translate: () => 'Un final largo y dulce.',
};

export default function SelectionActionsDemo() {
  const [reply, setReply] = useState<string>();
  return (
    <div style={{ width: '100%', maxWidth: 560, display: 'grid', gap: 20 }}>
      <SelectionActions
        actions={[{ id: 'explain', label: 'Explain' }, { id: 'shorten', label: 'Shorten' }, { id: 'translate', label: 'Translate' }]}
        onAction={(id, text) => setReply(replies[id](text))}
      >
        <p style={{ margin: 0, fontSize: 18, lineHeight: 1.6 }}>
          Washed Huila opens with red apple and panela, then settles into a finish that stays long and sweet well after the cup cools. Select any words to ask about them.
        </p>
      </SelectionActions>
      <div style={{ minHeight: 48, color: 'var(--bs-muted)' }}>{reply ? <StreamingText key={reply} text={reply} /> : null}</div>
    </div>
  );
}

Installation

pnpm add @brand-studio/ui

Usage

import { SelectionActions } from '@brand-studio/ui';
<SelectionActions actions={[{ id: 'explain', label: 'Explain' }, { id: 'shorten', label: 'Shorten' }]} onAction={(id, text) => ask(id, text)}>
  <p>Washed Huila opens with red apple and panela…</p>
</SelectionActions>

Select part of the wrapped text with the mouse, touch or Shift and the arrow keys, and a bar appears under the selection. Choosing an action calls onAction with its id and the selected text, then clears the selection. What happens next is up to you: answer beside it, or replace the text.

Accessibility

  • The bar is a toolbar that comes after the text in reading order, so Tab reaches it after a keyboard selection. Arrow keys move along it.
  • Escape dismisses the bar and clears the selection.

API Reference

PropTypeDefault
actionsSelectionAction[]
onAction?((id: string, text: string) => void)
childrenReact.ReactNode
label?string'Selection actions'
className?string''

Still, Deskhand and Hollis are fictional brands. The coffee photographs are original generated artwork. @brand-studio/ui is MIT licensed.