// SelectionBubble floats above a text selection and offers to rewrite it: a // prominent "✨ 更自然 Say it naturally" action plus the tone vocabulary (学术, // 轻松, …) mirrored from the document-tone picker. Picking one hands the style up // to EditorCore, which calls the LLM and shows a preview. Buttons use // onMouseDown→preventDefault so clicking them doesn't collapse the selection // before the handler captures its range. export interface RewriteStyle { value: string emoji: string zh: string en: string } // 'natural' is the default "say it more naturally" rewrite; the rest mirror the // llm styleGuidance keys (and the ToneSelect labels) so the two stay in step. export const REWRITE_STYLES: RewriteStyle[] = [ { value: 'natural', emoji: '✨', zh: '更自然', en: 'Natural' }, { value: 'academic', emoji: '🎓', zh: '学术', en: 'Academic' }, { value: 'professional', emoji: '💼', zh: '专业', en: 'Professional' }, { value: 'casual', emoji: '☕', zh: '轻松', en: 'Casual' }, { value: 'humorous', emoji: '😄', zh: '幽默', en: 'Humorous' }, { value: 'creative', emoji: '🎨', zh: '创意', en: 'Creative' }, { value: 'persuasive', emoji: '📣', zh: '说服', en: 'Persuasive' }, ] interface Props { style: React.CSSProperties onRewrite: (style: string) => void // Read the selected text aloud (null when speech isn't available — the button // is then hidden). onSpeak: (() => void) | null } const CJK = "'Nunito','PingFang SC','Microsoft YaHei','Noto Sans CJK SC',sans-serif" export function SelectionBubble({ style, onRewrite, onSpeak }: Props) { const [natural, ...tones] = REWRITE_STYLES return (