mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
[WEB-1067] chore: enter key entension added to editor package and issue modal description improvement (#4617)
* chore: enter key extension added to RichTextEditorWithRef editor package * chore: enter to submit functionality added to issue and inbox issue modal description
This commit is contained in:
parent
a8fcaf1f48
commit
05807fe123
@ -0,0 +1,25 @@
|
|||||||
|
import { Extension } from "@tiptap/core";
|
||||||
|
|
||||||
|
export const EnterKeyExtension = (onEnterKeyPress?: () => void) =>
|
||||||
|
Extension.create({
|
||||||
|
name: "enterKey",
|
||||||
|
|
||||||
|
addKeyboardShortcuts(this) {
|
||||||
|
return {
|
||||||
|
Enter: () => {
|
||||||
|
if (onEnterKeyPress) {
|
||||||
|
onEnterKeyPress();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
"Shift-Enter": ({ editor }) =>
|
||||||
|
editor.commands.first(({ commands }) => [
|
||||||
|
() => commands.newlineInCode(),
|
||||||
|
() => commands.splitListItem("listItem"),
|
||||||
|
() => commands.createParagraphNear(),
|
||||||
|
() => commands.liftEmptyBlock(),
|
||||||
|
() => commands.splitBlock(),
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
@ -1,13 +1,21 @@
|
|||||||
import { UploadImage } from "@plane/editor-core";
|
import { UploadImage } from "@plane/editor-core";
|
||||||
import { DragAndDrop, SlashCommand } from "@plane/editor-extensions";
|
import { DragAndDrop, SlashCommand } from "@plane/editor-extensions";
|
||||||
|
import { EnterKeyExtension } from "./enter-key-extension";
|
||||||
|
|
||||||
type TArguments = {
|
type TArguments = {
|
||||||
uploadFile: UploadImage;
|
uploadFile: UploadImage;
|
||||||
dragDropEnabled?: boolean;
|
dragDropEnabled?: boolean;
|
||||||
setHideDragHandle?: (hideDragHandlerFromDragDrop: () => void) => void;
|
setHideDragHandle?: (hideDragHandlerFromDragDrop: () => void) => void;
|
||||||
|
onEnterKeyPress?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const RichTextEditorExtensions = ({ uploadFile, dragDropEnabled, setHideDragHandle }: TArguments) => [
|
export const RichTextEditorExtensions = ({
|
||||||
|
uploadFile,
|
||||||
|
dragDropEnabled,
|
||||||
|
setHideDragHandle,
|
||||||
|
onEnterKeyPress,
|
||||||
|
}: TArguments) => [
|
||||||
SlashCommand(uploadFile),
|
SlashCommand(uploadFile),
|
||||||
dragDropEnabled === true && DragAndDrop(setHideDragHandle),
|
dragDropEnabled === true && DragAndDrop(setHideDragHandle),
|
||||||
|
EnterKeyExtension(onEnterKeyPress),
|
||||||
];
|
];
|
||||||
|
@ -37,6 +37,7 @@ export type IRichTextEditor = {
|
|||||||
};
|
};
|
||||||
placeholder?: string | ((isFocused: boolean, value: string) => string);
|
placeholder?: string | ((isFocused: boolean, value: string) => string);
|
||||||
tabIndex?: number;
|
tabIndex?: number;
|
||||||
|
onEnterKeyPress?: (e?: any) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const RichTextEditor = (props: IRichTextEditor) => {
|
const RichTextEditor = (props: IRichTextEditor) => {
|
||||||
@ -54,6 +55,7 @@ const RichTextEditor = (props: IRichTextEditor) => {
|
|||||||
placeholder,
|
placeholder,
|
||||||
tabIndex,
|
tabIndex,
|
||||||
mentionHandler,
|
mentionHandler,
|
||||||
|
onEnterKeyPress,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [hideDragHandleOnMouseLeave, setHideDragHandleOnMouseLeave] = React.useState<() => void>(() => {});
|
const [hideDragHandleOnMouseLeave, setHideDragHandleOnMouseLeave] = React.useState<() => void>(() => {});
|
||||||
@ -80,6 +82,7 @@ const RichTextEditor = (props: IRichTextEditor) => {
|
|||||||
uploadFile: fileHandler.upload,
|
uploadFile: fileHandler.upload,
|
||||||
dragDropEnabled,
|
dragDropEnabled,
|
||||||
setHideDragHandle: setHideDragHandleFunction,
|
setHideDragHandle: setHideDragHandleFunction,
|
||||||
|
onEnterKeyPress,
|
||||||
}),
|
}),
|
||||||
tabIndex,
|
tabIndex,
|
||||||
mentionHandler,
|
mentionHandler,
|
||||||
|
@ -42,6 +42,7 @@ export const InboxIssueCreateRoot: FC<TInboxIssueCreateRoot> = observer((props)
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
// refs
|
// refs
|
||||||
const descriptionEditorRef = useRef<EditorRefApi>(null);
|
const descriptionEditorRef = useRef<EditorRefApi>(null);
|
||||||
|
const submitBtnRef = useRef<HTMLButtonElement | null>(null);
|
||||||
// hooks
|
// hooks
|
||||||
const { captureIssueEvent } = useEventTracker();
|
const { captureIssueEvent } = useEventTracker();
|
||||||
const { createInboxIssue } = useProjectInbox();
|
const { createInboxIssue } = useProjectInbox();
|
||||||
@ -139,6 +140,7 @@ export const InboxIssueCreateRoot: FC<TInboxIssueCreateRoot> = observer((props)
|
|||||||
handleData={handleFormData}
|
handleData={handleFormData}
|
||||||
editorRef={descriptionEditorRef}
|
editorRef={descriptionEditorRef}
|
||||||
containerClassName="border-[0.5px] border-custom-border-200 py-3 min-h-[150px]"
|
containerClassName="border-[0.5px] border-custom-border-200 py-3 min-h-[150px]"
|
||||||
|
onEnterKeyPress={() => submitBtnRef?.current?.click()}
|
||||||
/>
|
/>
|
||||||
<InboxIssueProperties projectId={projectId} data={formData} handleData={handleFormData} />
|
<InboxIssueProperties projectId={projectId} data={formData} handleData={handleFormData} />
|
||||||
</div>
|
</div>
|
||||||
@ -158,6 +160,7 @@ export const InboxIssueCreateRoot: FC<TInboxIssueCreateRoot> = observer((props)
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
|
ref={submitBtnRef}
|
||||||
size="sm"
|
size="sm"
|
||||||
type="submit"
|
type="submit"
|
||||||
loading={formSubmitting}
|
loading={formSubmitting}
|
||||||
|
@ -34,6 +34,7 @@ export const InboxIssueEditRoot: FC<TInboxIssueEditRoot> = observer((props) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
// refs
|
// refs
|
||||||
const descriptionEditorRef = useRef<EditorRefApi>(null);
|
const descriptionEditorRef = useRef<EditorRefApi>(null);
|
||||||
|
const submitBtnRef = useRef<HTMLButtonElement | null>(null);
|
||||||
// store hooks
|
// store hooks
|
||||||
const { captureIssueEvent } = useEventTracker();
|
const { captureIssueEvent } = useEventTracker();
|
||||||
const { currentProjectDetails } = useProject();
|
const { currentProjectDetails } = useProject();
|
||||||
@ -148,6 +149,7 @@ export const InboxIssueEditRoot: FC<TInboxIssueEditRoot> = observer((props) => {
|
|||||||
handleData={handleFormData}
|
handleData={handleFormData}
|
||||||
editorRef={descriptionEditorRef}
|
editorRef={descriptionEditorRef}
|
||||||
containerClassName="border-[0.5px] border-custom-border-200 py-3 min-h-[150px]"
|
containerClassName="border-[0.5px] border-custom-border-200 py-3 min-h-[150px]"
|
||||||
|
onEnterKeyPress={() => submitBtnRef?.current?.click()}
|
||||||
/>
|
/>
|
||||||
<InboxIssueProperties projectId={projectId} data={formData} handleData={handleFormData} isVisible />
|
<InboxIssueProperties projectId={projectId} data={formData} handleData={handleFormData} isVisible />
|
||||||
</div>
|
</div>
|
||||||
@ -160,6 +162,7 @@ export const InboxIssueEditRoot: FC<TInboxIssueEditRoot> = observer((props) => {
|
|||||||
variant="primary"
|
variant="primary"
|
||||||
size="sm"
|
size="sm"
|
||||||
type="button"
|
type="button"
|
||||||
|
ref={submitBtnRef}
|
||||||
loading={formSubmitting}
|
loading={formSubmitting}
|
||||||
disabled={isTitleLengthMoreThan255Character}
|
disabled={isTitleLengthMoreThan255Character}
|
||||||
onClick={handleFormSubmit}
|
onClick={handleFormSubmit}
|
||||||
|
@ -18,11 +18,13 @@ type TInboxIssueDescription = {
|
|||||||
data: Partial<TIssue>;
|
data: Partial<TIssue>;
|
||||||
handleData: (issueKey: keyof Partial<TIssue>, issueValue: Partial<TIssue>[keyof Partial<TIssue>]) => void;
|
handleData: (issueKey: keyof Partial<TIssue>, issueValue: Partial<TIssue>[keyof Partial<TIssue>]) => void;
|
||||||
editorRef: RefObject<EditorRefApi>;
|
editorRef: RefObject<EditorRefApi>;
|
||||||
|
onEnterKeyPress?: (e?: any) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: have to implement GPT Assistance
|
// TODO: have to implement GPT Assistance
|
||||||
export const InboxIssueDescription: FC<TInboxIssueDescription> = observer((props) => {
|
export const InboxIssueDescription: FC<TInboxIssueDescription> = observer((props) => {
|
||||||
const { containerClassName, workspaceSlug, projectId, workspaceId, data, handleData, editorRef } = props;
|
const { containerClassName, workspaceSlug, projectId, workspaceId, data, handleData, editorRef, onEnterKeyPress } =
|
||||||
|
props;
|
||||||
// hooks
|
// hooks
|
||||||
const { loader } = useProjectInbox();
|
const { loader } = useProjectInbox();
|
||||||
|
|
||||||
@ -44,6 +46,7 @@ export const InboxIssueDescription: FC<TInboxIssueDescription> = observer((props
|
|||||||
onChange={(_description: object, description_html: string) => handleData("description_html", description_html)}
|
onChange={(_description: object, description_html: string) => handleData("description_html", description_html)}
|
||||||
placeholder={getDescriptionPlaceholder}
|
placeholder={getDescriptionPlaceholder}
|
||||||
containerClassName={containerClassName}
|
containerClassName={containerClassName}
|
||||||
|
onEnterKeyPress={onEnterKeyPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -109,6 +109,7 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||||||
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
||||||
// refs
|
// refs
|
||||||
const editorRef = useRef<EditorRefApi>(null);
|
const editorRef = useRef<EditorRefApi>(null);
|
||||||
|
const submitBtnRef = useRef<HTMLButtonElement | null>(null);
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
@ -470,6 +471,7 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||||||
onChange(description_html);
|
onChange(description_html);
|
||||||
handleFormChange();
|
handleFormChange();
|
||||||
}}
|
}}
|
||||||
|
onEnterKeyPress={() => submitBtnRef?.current?.click()}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
tabIndex={getTabIndex("description_html")}
|
tabIndex={getTabIndex("description_html")}
|
||||||
placeholder={getDescriptionPlaceholder}
|
placeholder={getDescriptionPlaceholder}
|
||||||
@ -770,6 +772,7 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||||||
variant="primary"
|
variant="primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
ref={submitBtnRef}
|
||||||
loading={isSubmitting}
|
loading={isSubmitting}
|
||||||
tabIndex={isDraft ? getTabIndex("submit_button") : getTabIndex("draft_button")}
|
tabIndex={isDraft ? getTabIndex("submit_button") : getTabIndex("draft_button")}
|
||||||
>
|
>
|
||||||
|
Loading…
Reference in New Issue
Block a user