Skip to content

Commit 7751fe2

Browse files
authored
Merge pull request #251 from beNative/codex/implement-lexical-rich-document-support
Add rich editor toolbar and context menu
2 parents 2a7fc0c + aa64194 commit 7751fe2

17 files changed

Lines changed: 2148 additions & 258 deletions

App.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ const PREVIEW_ZOOM_STEP = 0.05;
5555

5656
const isElectron = !!window.electronAPI;
5757

58+
const TREE_SELECTION_COMMAND_IDS = new Set(['delete-item', 'duplicate-item', 'rename-item']);
59+
5860
const resolveClipboardHelpUrl = (): string | null => {
5961
if (typeof navigator === 'undefined') {
6062
return null;
@@ -1791,7 +1793,7 @@ export const MainApp: React.FC = () => {
17911793
const handleNewDocument = useCallback(async (parentId?: string | null) => {
17921794
addLog('INFO', 'User action: Create New Document.');
17931795
const effectiveParentId = parentId !== undefined ? parentId : getParentIdForNewItem();
1794-
const newDoc = await addDocument({ parentId: effectiveParentId });
1796+
const newDoc = await addDocument({ parentId: effectiveParentId, doc_type: 'rich_text', language_hint: 'html' });
17951797
ensureNodeVisible(newDoc);
17961798
activateDocumentTab(newDoc.id);
17971799
setSelectedIds(new Set([newDoc.id]));
@@ -2128,12 +2130,9 @@ export const MainApp: React.FC = () => {
21282130
}
21292131
}, [activeNodeId, activeNode, updateItem, addLog]);
21302132

2131-
const handleCommitVersion = useCallback((content: string) => {
2132-
if (activeNodeId) {
2133-
return commitVersion(activeNodeId, content);
2134-
}
2135-
return Promise.resolve();
2136-
}, [activeNodeId, commitVersion]);
2133+
const handleCommitVersion = useCallback((documentId: string, content: string) => {
2134+
return commitVersion(documentId, content);
2135+
}, [commitVersion]);
21372136

21382137
const handleSaveTemplate = (updatedTemplate: Partial<Omit<DocumentTemplate, 'template_id'>>) => {
21392138
if (activeTemplateId) {
@@ -2861,22 +2860,28 @@ export const MainApp: React.FC = () => {
28612860
};
28622861
}, [handleGlobalMouseMove, handleGlobalMouseUp]);
28632862

2864-
useEffect(() => {
2863+
useEffect(() => {
28652864
const shortcutMap = getShortcutMap(commands, settings.customShortcuts);
2866-
2865+
28672866
const handleKeyDown = (e: KeyboardEvent) => {
28682867
const shortcut = formatShortcut(e);
28692868
const command = shortcutMap.get(shortcut);
28702869

28712870
const activeEl = document.activeElement;
28722871
const isFormElement = activeEl && ['INPUT', 'TEXTAREA', 'SELECT'].includes(activeEl.tagName);
2872+
const isRichTextElement =
2873+
activeEl instanceof HTMLElement && Boolean(activeEl.closest('[data-component="rich-text-editor"]'));
28732874
const isPaletteInput = activeEl === commandPaletteInputRef.current;
28742875
const isCommandPaletteToggle = command?.id === 'toggle-command-palette';
28752876

28762877
if (isFormElement && !isPaletteInput && !isCommandPaletteToggle) {
28772878
return;
28782879
}
28792880

2881+
if (isRichTextElement && command && TREE_SELECTION_COMMAND_IDS.has(command.id)) {
2882+
return;
2883+
}
2884+
28802885
if (command?.category === 'Document Tree' && command.id !== 'document-tree-focus-search') {
28812886
const target = e.target as HTMLElement | null;
28822887
const isWithinSidebar = target?.closest('[data-component="document-tree-sidebar"]');

components/FolderOverview.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const DOC_TYPE_LABELS: Record<DocType, string> = {
9292
source_code: 'Source code',
9393
pdf: 'PDFs',
9494
image: 'Images',
95+
rich_text: 'Rich documents',
9596
};
9697

9798
const formatDocTypeLabel = (docType: DocType) => DOC_TYPE_LABELS[docType] ?? docType.replace(/_/g, ' ');

components/IconButton.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>
1212
const IconButton: React.FC<IconButtonProps> = ({ children, tooltip, className, variant = 'primary', size='md', tooltipPosition = 'top', ...props }) => {
1313
const [isHovered, setIsHovered] = useState(false);
1414
const wrapperRef = useRef<HTMLSpanElement>(null);
15+
const { ['aria-label']: ariaLabel, ...buttonProps } = props;
16+
const computedAriaLabel = ariaLabel ?? tooltip;
1517

1618
const handleMouseEnter = useCallback(() => {
1719
if (tooltip) setIsHovered(true);
@@ -47,7 +49,8 @@ const IconButton: React.FC<IconButtonProps> = ({ children, tooltip, className, v
4749
>
4850
<button
4951
className={`${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${className}`}
50-
{...props}
52+
aria-label={computedAriaLabel}
53+
{...buttonProps}
5154
>
5255
{children}
5356
</button>

0 commit comments

Comments
 (0)