[WEB-638] feat: add tabIndex prop support to navigate using Tab key in all the editors (#3902)

* feat: added tab index support to navigate using Tab key in all the editors

* chore: changed the name of Table of Contents in Pages

* chore: file formatting

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
This commit is contained in:
M. Palanikannan 2024-03-11 20:58:23 +05:30 committed by GitHub
parent 899771a678
commit 4b30339a59
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 57 additions and 14 deletions

View File

@ -1,17 +1,28 @@
import { Editor, EditorContent } from "@tiptap/react"; import { Editor, EditorContent } from "@tiptap/react";
import { ReactNode } from "react"; import { FC, ReactNode } from "react";
import { ImageResizer } from "src/ui/extensions/image/image-resize"; import { ImageResizer } from "src/ui/extensions/image/image-resize";
interface EditorContentProps { interface EditorContentProps {
editor: Editor | null; editor: Editor | null;
editorContentCustomClassNames: string | undefined; editorContentCustomClassNames: string | undefined;
children?: ReactNode; children?: ReactNode;
tabIndex?: number;
} }
export const EditorContentWrapper = ({ editor, editorContentCustomClassNames = "", children }: EditorContentProps) => ( export const EditorContentWrapper: FC<EditorContentProps> = (props) => {
<div className={`contentEditor ${editorContentCustomClassNames}`}> const { editor, editorContentCustomClassNames = "", tabIndex, children } = props;
<EditorContent editor={editor} />
{editor?.isActive("image") && editor?.isEditable && <ImageResizer editor={editor} />} return (
{children} <div
</div> className={`contentEditor ${editorContentCustomClassNames}`}
); tabIndex={tabIndex}
onFocus={() => {
editor?.chain().focus(undefined, { scrollIntoView: false }).run();
}}
>
<EditorContent editor={editor} />
{editor?.isActive("image") && editor?.isEditable && <ImageResizer editor={editor} />}
{children}
</div>
);
};

View File

@ -19,7 +19,7 @@ export const ContentBrowser = (props: ContentBrowserProps) => {
return ( return (
<div className="flex h-full flex-col overflow-hidden"> <div className="flex h-full flex-col overflow-hidden">
<h2 className="font-medium">Table of Contents</h2> <h2 className="font-medium">Outline</h2>
<div className="h-full overflow-y-auto"> <div className="h-full overflow-y-auto">
{markings.length !== 0 ? ( {markings.length !== 0 ? (
markings.map((marking) => markings.map((marking) =>

View File

@ -29,11 +29,13 @@ type IPageRenderer = {
editorContentCustomClassNames?: string; editorContentCustomClassNames?: string;
hideDragHandle?: () => void; hideDragHandle?: () => void;
readonly: boolean; readonly: boolean;
tabIndex?: number;
}; };
export const PageRenderer = (props: IPageRenderer) => { export const PageRenderer = (props: IPageRenderer) => {
const { const {
documentDetails, documentDetails,
tabIndex,
editor, editor,
editorClassNames, editorClassNames,
editorContentCustomClassNames, editorContentCustomClassNames,
@ -169,7 +171,11 @@ export const PageRenderer = (props: IPageRenderer) => {
)} )}
<div className="flex relative h-full w-full flex-col pr-5 editor-renderer" onMouseOver={handleLinkHover}> <div className="flex relative h-full w-full flex-col pr-5 editor-renderer" onMouseOver={handleLinkHover}>
<EditorContainer hideDragHandle={hideDragHandle} editor={editor} editorClassNames={editorClassNames}> <EditorContainer hideDragHandle={hideDragHandle} editor={editor} editorClassNames={editorClassNames}>
<EditorContentWrapper editor={editor} editorContentCustomClassNames={editorContentCustomClassNames} /> <EditorContentWrapper
tabIndex={tabIndex}
editor={editor}
editorContentCustomClassNames={editorContentCustomClassNames}
/>
</EditorContainer> </EditorContainer>
</div> </div>
{isOpen && linkViewProps && coordinates && ( {isOpen && linkViewProps && coordinates && (

View File

@ -47,6 +47,8 @@ interface IDocumentEditor {
duplicationConfig?: IDuplicationConfig; duplicationConfig?: IDuplicationConfig;
pageLockConfig?: IPageLockConfig; pageLockConfig?: IPageLockConfig;
pageArchiveConfig?: IPageArchiveConfig; pageArchiveConfig?: IPageArchiveConfig;
tabIndex?: number;
} }
interface DocumentEditorProps extends IDocumentEditor { interface DocumentEditorProps extends IDocumentEditor {
forwardedRef?: React.Ref<EditorHandle>; forwardedRef?: React.Ref<EditorHandle>;
@ -79,6 +81,7 @@ const DocumentEditor = ({
cancelUploadImage, cancelUploadImage,
onActionCompleteHandler, onActionCompleteHandler,
rerenderOnPropsChange, rerenderOnPropsChange,
tabIndex,
}: IDocumentEditor) => { }: IDocumentEditor) => {
const { markings, updateMarkings } = useEditorMarkings(); const { markings, updateMarkings } = useEditorMarkings();
const [sidePeekVisible, setSidePeekVisible] = useState(true); const [sidePeekVisible, setSidePeekVisible] = useState(true);
@ -160,6 +163,7 @@ const DocumentEditor = ({
</div> </div>
<div className="h-full w-full md:w-[calc(100%-14rem)] lg:w-[calc(100%-18rem-18rem)] page-renderer"> <div className="h-full w-full md:w-[calc(100%-14rem)] lg:w-[calc(100%-18rem-18rem)] page-renderer">
<PageRenderer <PageRenderer
tabIndex={tabIndex}
onActionCompleteHandler={onActionCompleteHandler} onActionCompleteHandler={onActionCompleteHandler}
hideDragHandle={hideDragHandleOnMouseLeave} hideDragHandle={hideDragHandleOnMouseLeave}
readonly={false} readonly={false}

View File

@ -28,6 +28,7 @@ interface IDocumentReadOnlyEditor {
message: string; message: string;
type: "success" | "error" | "warning" | "info"; type: "success" | "error" | "warning" | "info";
}) => void; }) => void;
tabIndex?: number;
} }
interface DocumentReadOnlyEditorProps extends IDocumentReadOnlyEditor { interface DocumentReadOnlyEditorProps extends IDocumentReadOnlyEditor {
@ -51,6 +52,7 @@ const DocumentReadOnlyEditor = ({
pageArchiveConfig, pageArchiveConfig,
rerenderOnPropsChange, rerenderOnPropsChange,
onActionCompleteHandler, onActionCompleteHandler,
tabIndex,
}: DocumentReadOnlyEditorProps) => { }: DocumentReadOnlyEditorProps) => {
const router = useRouter(); const router = useRouter();
const [sidePeekVisible, setSidePeekVisible] = useState(true); const [sidePeekVisible, setSidePeekVisible] = useState(true);
@ -108,6 +110,7 @@ const DocumentReadOnlyEditor = ({
</div> </div>
<div className="h-full w-[calc(100%-14rem)] lg:w-[calc(100%-18rem-18rem)] page-renderer"> <div className="h-full w-[calc(100%-14rem)] lg:w-[calc(100%-18rem-18rem)] page-renderer">
<PageRenderer <PageRenderer
tabIndex={tabIndex}
onActionCompleteHandler={onActionCompleteHandler} onActionCompleteHandler={onActionCompleteHandler}
updatePageTitle={() => Promise.resolve()} updatePageTitle={() => Promise.resolve()}
readonly={true} readonly={true}

View File

@ -42,6 +42,7 @@ interface ILiteTextEditor {
mentionHighlights?: string[]; mentionHighlights?: string[];
mentionSuggestions?: IMentionSuggestion[]; mentionSuggestions?: IMentionSuggestion[];
submitButton?: React.ReactNode; submitButton?: React.ReactNode;
tabIndex?: number;
} }
interface LiteTextEditorProps extends ILiteTextEditor { interface LiteTextEditorProps extends ILiteTextEditor {
@ -74,6 +75,7 @@ const LiteTextEditor = (props: LiteTextEditorProps) => {
mentionHighlights, mentionHighlights,
mentionSuggestions, mentionSuggestions,
submitButton, submitButton,
tabIndex,
} = props; } = props;
const editor = useEditor({ const editor = useEditor({
@ -103,7 +105,11 @@ const LiteTextEditor = (props: LiteTextEditorProps) => {
return ( return (
<EditorContainer editor={editor} editorClassNames={editorClassNames}> <EditorContainer editor={editor} editorClassNames={editorClassNames}>
<div className="flex flex-col"> <div className="flex flex-col">
<EditorContentWrapper editor={editor} editorContentCustomClassNames={editorContentCustomClassNames} /> <EditorContentWrapper
tabIndex={tabIndex}
editor={editor}
editorContentCustomClassNames={editorContentCustomClassNames}
/>
<div className="mt-4 w-full"> <div className="mt-4 w-full">
<FixedMenu <FixedMenu
editor={editor} editor={editor}

View File

@ -8,6 +8,7 @@ interface ICoreReadOnlyEditor {
borderOnFocus?: boolean; borderOnFocus?: boolean;
customClassName?: string; customClassName?: string;
mentionHighlights: string[]; mentionHighlights: string[];
tabIndex?: number;
} }
interface EditorCoreProps extends ICoreReadOnlyEditor { interface EditorCoreProps extends ICoreReadOnlyEditor {
@ -27,6 +28,7 @@ const LiteReadOnlyEditor = ({
value, value,
forwardedRef, forwardedRef,
mentionHighlights, mentionHighlights,
tabIndex,
}: EditorCoreProps) => { }: EditorCoreProps) => {
const editor = useReadOnlyEditor({ const editor = useReadOnlyEditor({
value, value,
@ -45,7 +47,11 @@ const LiteReadOnlyEditor = ({
return ( return (
<EditorContainer editor={editor} editorClassNames={editorClassNames}> <EditorContainer editor={editor} editorClassNames={editorClassNames}>
<div className="flex flex-col"> <div className="flex flex-col">
<EditorContentWrapper editor={editor} editorContentCustomClassNames={editorContentCustomClassNames} /> <EditorContentWrapper
tabIndex={tabIndex}
editor={editor}
editorContentCustomClassNames={editorContentCustomClassNames}
/>
</div> </div>
</EditorContainer> </EditorContainer>
); );

View File

@ -36,6 +36,7 @@ export type IRichTextEditor = {
debouncedUpdatesEnabled?: boolean; debouncedUpdatesEnabled?: boolean;
mentionHighlights?: string[]; mentionHighlights?: string[];
mentionSuggestions?: IMentionSuggestion[]; mentionSuggestions?: IMentionSuggestion[];
tabIndex?: number;
}; };
export interface RichTextEditorProps extends IRichTextEditor { export interface RichTextEditorProps extends IRichTextEditor {
@ -68,6 +69,7 @@ const RichTextEditor = ({
mentionHighlights, mentionHighlights,
rerenderOnPropsChange, rerenderOnPropsChange,
mentionSuggestions, mentionSuggestions,
tabIndex,
}: RichTextEditorProps) => { }: RichTextEditorProps) => {
const [hideDragHandleOnMouseLeave, setHideDragHandleOnMouseLeave] = React.useState<() => void>(() => {}); const [hideDragHandleOnMouseLeave, setHideDragHandleOnMouseLeave] = React.useState<() => void>(() => {});
@ -110,7 +112,11 @@ const RichTextEditor = ({
<EditorContainer hideDragHandle={hideDragHandleOnMouseLeave} editor={editor} editorClassNames={editorClassNames}> <EditorContainer hideDragHandle={hideDragHandleOnMouseLeave} editor={editor} editorClassNames={editorClassNames}>
{editor && <EditorBubbleMenu editor={editor} />} {editor && <EditorBubbleMenu editor={editor} />}
<div className="flex flex-col"> <div className="flex flex-col">
<EditorContentWrapper editor={editor} editorContentCustomClassNames={editorContentCustomClassNames} /> <EditorContentWrapper
tabIndex={tabIndex}
editor={editor}
editorContentCustomClassNames={editorContentCustomClassNames}
/>
</div> </div>
</EditorContainer> </EditorContainer>
); );

View File

@ -9,6 +9,7 @@ interface IRichTextReadOnlyEditor {
borderOnFocus?: boolean; borderOnFocus?: boolean;
customClassName?: string; customClassName?: string;
mentionHighlights?: string[]; mentionHighlights?: string[];
tabIndex?: number;
} }
interface RichTextReadOnlyEditorProps extends IRichTextReadOnlyEditor { interface RichTextReadOnlyEditorProps extends IRichTextReadOnlyEditor {

View File

@ -467,7 +467,7 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
}} }}
mentionHighlights={mentionHighlights} mentionHighlights={mentionHighlights}
mentionSuggestions={mentionSuggestions} mentionSuggestions={mentionSuggestions}
// tabIndex={2} tabIndex={getTabIndex("description_html")}
/> />
)} )}
/> />