Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions packages/apollo-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -175,16 +175,16 @@
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@floating-ui/react": "^0.27.15",
"@lexical/code": "0.16.0",
"@lexical/html": "0.16.0",
"@lexical/link": "0.16.0",
"@lexical/list": "0.16.0",
"@lexical/markdown": "0.16.0",
"@lexical/react": "0.16.0",
"@lexical/rich-text": "0.16.0",
"@lexical/selection": "0.16.0",
"@lexical/table": "0.16.0",
"@lexical/utils": "0.16.0",
"@lexical/code": "0.42.0",
"@lexical/html": "0.42.0",
"@lexical/link": "0.42.0",
"@lexical/list": "0.42.0",
"@lexical/markdown": "0.42.0",
"@lexical/react": "0.42.0",
"@lexical/rich-text": "0.42.0",
"@lexical/selection": "0.42.0",
"@lexical/table": "0.42.0",
"@lexical/utils": "0.42.0",
"@lingui/core": "^5.6.1",
"@lingui/react": "^5.6.1",
"@mui/icons-material": "^5.18.0",
Expand Down Expand Up @@ -216,7 +216,7 @@
"debounce": "^3.0.0",
"html-to-image": "^1.11.11",
"katex": "^0.16.27",
"lexical": "0.16.0",
"lexical": "0.42.0",
"lodash": "^4.18.1",
"lucide-react": "^0.577.0",
"luxon": "^3.7.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ListItemNode, ListNode } from '@lexical/list';
import { $convertFromMarkdownString, $convertToMarkdownString } from '@lexical/markdown';
import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
import { ListPlugin } from '@lexical/react/LexicalListPlugin';
Expand Down
6 changes: 6 additions & 0 deletions packages/apollo-wind/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@hookform/resolvers": "^5.2.2",
"@lexical/clipboard": "0.42.0",
"@lexical/react": "0.42.0",
"@lexical/utils": "0.42.0",
"@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-aspect-ratio": "^1.1.8",
Expand Down Expand Up @@ -112,9 +115,12 @@
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"date-fns": "^4.1.0",
"dompurify": "^3.4.0",
"framer-motion": "^12.26.2",
"jsep": "^1.4.0",
"lexical": "0.42.0",
"lucide-react": "^0.577.0",
"marked": "^17.0.6",
"next-themes": "^0.4.6",
"react-day-picker": "^9.13.0",
"react-hook-form": "^7.66.1",
Expand Down
1 change: 1 addition & 0 deletions packages/apollo-wind/src/components/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export * from './multi-select';
export * from './pagination';
export * from './popover';
export * from './progress';
export * from './prompt-editor';
export * from './radio-group';
export * from './resizable';
export * from './scroll-area';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { Bold, Italic, List, ListOrdered, Maximize2, Strikethrough } from 'lucide-react';
import { cn } from '@/lib';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import type { PromptEditorMode, PromptEditorToolbarActionsRef } from '../types';
Comment thread
fikewa-olatunji marked this conversation as resolved.

export interface EditorToolbarProps {
mode: PromptEditorMode;
onModeChange: (mode: PromptEditorMode) => void;
disabled?: boolean;
actionsRef?: React.RefObject<PromptEditorToolbarActionsRef | null>;
onFullscreen?: () => void;
}

/**
* Toolbar formatting button: 28×28 px tap target, 4 px border-radius, 14 px lucide icon.
*/
const ToolbarButton = ({
icon: Icon,
label,
disabled,
onClick,
}: {
icon: React.ComponentType<{ className?: string }>;
label: string;
disabled?: boolean;
onClick?: () => void;
}) => (
<Tooltip>
<TooltipTrigger asChild>
<button
type="button"
aria-label={label}
disabled={disabled}
onClick={onClick}
className={cn(
'inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground',
'hover:bg-accent hover:text-accent-foreground',
'disabled:opacity-50 disabled:pointer-events-none'
)}
>
<Icon className="h-3.5 w-3.5" />
</button>
</TooltipTrigger>
<TooltipContent side="bottom">
<span className="text-xs">{label}</span>
</TooltipContent>
</Tooltip>
);

const ToolbarSeparator = () => <span aria-hidden className="mx-1 h-4 w-px bg-border/60" />;

export const EditorToolbar = ({
mode,
onModeChange,
disabled,
actionsRef,
onFullscreen,
}: EditorToolbarProps) => {
const isEditMode = mode === 'edit';

const handleFormat = (actionName: keyof PromptEditorToolbarActionsRef) => () => {
if (!disabled && isEditMode) {
const fn = actionsRef?.current?.[actionName];
if (typeof fn === 'function') fn();
}
};

return (
<div
// No bottom border on the toolbar itself — the separator is drawn by the absolute hairline
// `<span>` below at full width so the L/R outlines stay continuous with the editor body's
// `border-t-0` border underneath.
className="relative flex items-center justify-between gap-1 overflow-hidden rounded-t-md border border-b-0 bg-background px-2 py-1"
data-testid="editor-toolbar"
>
<span
aria-hidden
data-testid="editor-toolbar-separator"
className="pointer-events-none absolute bottom-0 left-0 h-px w-full bg-border/40"
/>
{/* Left: Edit/Preview mode switcher */}
<div className="flex items-center gap-1 shrink-0">
<div className="flex items-center rounded-md bg-muted p-0.5">
<button
type="button"
className={cn(
'rounded px-2 py-0.5 text-[11px] font-semibold transition-colors',
mode === 'edit' ? 'bg-primary/20 text-primary' : 'text-foreground hover:bg-accent'
)}
disabled={disabled}
onClick={() => onModeChange('edit')}
>
Edit
</button>
<button
type="button"
className={cn(
'rounded px-2 py-0.5 text-[11px] font-semibold transition-colors',
mode === 'preview' ? 'bg-primary/20 text-primary' : 'text-foreground hover:bg-accent'
)}
disabled={disabled}
onClick={() => onModeChange('preview')}
>
Preview
</button>
</div>
</div>

{/* Right: formatting cluster (Bold/Italic/Strike) → list cluster (Numbered/Bullet) → Expand. */}
<div className="flex items-center gap-0.5 overflow-hidden">
<ToolbarButton
icon={Bold}
label="Bold"
disabled={disabled || !isEditMode}
onClick={handleFormat('formatBold')}
/>
<ToolbarButton
icon={Italic}
label="Italic"
disabled={disabled || !isEditMode}
onClick={handleFormat('formatItalic')}
/>
<ToolbarButton
icon={Strikethrough}
label="Strikethrough"
disabled={disabled || !isEditMode}
onClick={handleFormat('formatStrikethrough')}
/>

<ToolbarSeparator />

<ToolbarButton
icon={ListOrdered}
label="Numbered List"
disabled={disabled || !isEditMode}
onClick={handleFormat('formatNumberedList')}
/>
<ToolbarButton
icon={List}
label="Bulleted List"
disabled={disabled || !isEditMode}
onClick={handleFormat('formatBulletedList')}
/>

{onFullscreen && (
<>
<ToolbarSeparator />
<ToolbarButton
icon={Maximize2}
label="Expand"
disabled={disabled}
onClick={onFullscreen}
/>
</>
)}
</div>
</div>
);
};
Loading
Loading