forked from github/plane
style: lite text editor editor toolbar (#2601)
* style: comment editor toolbar * style: updated icon styling
This commit is contained in:
parent
5b808571e5
commit
c394a4f64e
@ -7,7 +7,11 @@ interface EditorContainerProps {
|
|||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EditorContainer = ({ editor, editorClassNames, children }: EditorContainerProps) => (
|
export const EditorContainer = ({
|
||||||
|
editor,
|
||||||
|
editorClassNames,
|
||||||
|
children,
|
||||||
|
}: EditorContainerProps) => (
|
||||||
<div
|
<div
|
||||||
id="editor-container"
|
id="editor-container"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
"use client"
|
"use client";
|
||||||
import * as React from 'react';
|
import * as React from "react";
|
||||||
import { Extension } from "@tiptap/react";
|
import { Extension } from "@tiptap/react";
|
||||||
import { UploadImage } from '../types/upload-image';
|
import { UploadImage } from "../types/upload-image";
|
||||||
import { DeleteImage } from '../types/delete-image';
|
import { DeleteImage } from "../types/delete-image";
|
||||||
import { getEditorClassNames } from '../lib/utils';
|
import { getEditorClassNames } from "../lib/utils";
|
||||||
import { EditorProps } from '@tiptap/pm/view';
|
import { EditorProps } from "@tiptap/pm/view";
|
||||||
import { useEditor } from './hooks/useEditor';
|
import { useEditor } from "./hooks/useEditor";
|
||||||
import { EditorContainer } from '../ui/components/editor-container';
|
import { EditorContainer } from "../ui/components/editor-container";
|
||||||
import { EditorContentWrapper } from '../ui/components/editor-content';
|
import { EditorContentWrapper } from "../ui/components/editor-content";
|
||||||
import { IMentionSuggestion } from '../types/mention-suggestion';
|
import { IMentionSuggestion } from "../types/mention-suggestion";
|
||||||
|
|
||||||
interface ICoreEditor {
|
interface ICoreEditor {
|
||||||
value: string;
|
value: string;
|
||||||
@ -19,7 +19,9 @@ interface ICoreEditor {
|
|||||||
customClassName?: string;
|
customClassName?: string;
|
||||||
editorContentCustomClassNames?: string;
|
editorContentCustomClassNames?: string;
|
||||||
onChange?: (json: any, html: string) => void;
|
onChange?: (json: any, html: string) => void;
|
||||||
setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void;
|
setIsSubmitting?: (
|
||||||
|
isSubmitting: "submitting" | "submitted" | "saved",
|
||||||
|
) => void;
|
||||||
setShouldShowAlert?: (showAlert: boolean) => void;
|
setShouldShowAlert?: (showAlert: boolean) => void;
|
||||||
editable?: boolean;
|
editable?: boolean;
|
||||||
forwardedRef?: any;
|
forwardedRef?: any;
|
||||||
@ -72,22 +74,29 @@ const CoreEditor = ({
|
|||||||
forwardedRef,
|
forwardedRef,
|
||||||
});
|
});
|
||||||
|
|
||||||
const editorClassNames = getEditorClassNames({ noBorder, borderOnFocus, customClassName });
|
const editorClassNames = getEditorClassNames({
|
||||||
|
noBorder,
|
||||||
|
borderOnFocus,
|
||||||
|
customClassName,
|
||||||
|
});
|
||||||
|
|
||||||
if (!editor) return null;
|
if (!editor) return null;
|
||||||
|
|
||||||
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
|
||||||
|
editor={editor}
|
||||||
|
editorContentCustomClassNames={editorContentCustomClassNames}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</EditorContainer>
|
</EditorContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const CoreEditorWithRef = React.forwardRef<EditorHandle, ICoreEditor>((props, ref) => (
|
const CoreEditorWithRef = React.forwardRef<EditorHandle, ICoreEditor>(
|
||||||
<CoreEditor {...props} forwardedRef={ref} />
|
(props, ref) => <CoreEditor {...props} forwardedRef={ref} />,
|
||||||
));
|
);
|
||||||
|
|
||||||
CoreEditorWithRef.displayName = "CoreEditorWithRef";
|
CoreEditorWithRef.displayName = "CoreEditorWithRef";
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ export type IMentionSuggestion = {
|
|||||||
title: string;
|
title: string;
|
||||||
subtitle: string;
|
subtitle: string;
|
||||||
redirect_uri: string;
|
redirect_uri: string;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type IMentionHighlight = string
|
export type IMentionHighlight = string;
|
||||||
|
|
||||||
interface ILiteTextEditor {
|
interface ILiteTextEditor {
|
||||||
value: string;
|
value: string;
|
||||||
@ -32,7 +32,7 @@ interface ILiteTextEditor {
|
|||||||
editorContentCustomClassNames?: string;
|
editorContentCustomClassNames?: string;
|
||||||
onChange?: (json: any, html: string) => void;
|
onChange?: (json: any, html: string) => void;
|
||||||
setIsSubmitting?: (
|
setIsSubmitting?: (
|
||||||
isSubmitting: "submitting" | "submitted" | "saved"
|
isSubmitting: "submitting" | "submitted" | "saved",
|
||||||
) => void;
|
) => void;
|
||||||
setShouldShowAlert?: (showAlert: boolean) => void;
|
setShouldShowAlert?: (showAlert: boolean) => void;
|
||||||
forwardedRef?: any;
|
forwardedRef?: any;
|
||||||
@ -50,6 +50,7 @@ interface ILiteTextEditor {
|
|||||||
onEnterKeyPress?: (e?: any) => void;
|
onEnterKeyPress?: (e?: any) => void;
|
||||||
mentionHighlights?: string[];
|
mentionHighlights?: string[];
|
||||||
mentionSuggestions?: IMentionSuggestion[];
|
mentionSuggestions?: IMentionSuggestion[];
|
||||||
|
submitButton?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LiteTextEditorProps extends ILiteTextEditor {
|
interface LiteTextEditorProps extends ILiteTextEditor {
|
||||||
@ -61,7 +62,8 @@ interface EditorHandle {
|
|||||||
setEditorValue: (content: string) => void;
|
setEditorValue: (content: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LiteTextEditor = ({
|
const LiteTextEditor = (props: LiteTextEditorProps) => {
|
||||||
|
const {
|
||||||
onChange,
|
onChange,
|
||||||
debouncedUpdatesEnabled,
|
debouncedUpdatesEnabled,
|
||||||
setIsSubmitting,
|
setIsSubmitting,
|
||||||
@ -77,8 +79,10 @@ const LiteTextEditor = ({
|
|||||||
commentAccessSpecifier,
|
commentAccessSpecifier,
|
||||||
onEnterKeyPress,
|
onEnterKeyPress,
|
||||||
mentionHighlights,
|
mentionHighlights,
|
||||||
mentionSuggestions
|
mentionSuggestions,
|
||||||
}: LiteTextEditorProps) => {
|
submitButton,
|
||||||
|
} = props;
|
||||||
|
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
onChange,
|
onChange,
|
||||||
debouncedUpdatesEnabled,
|
debouncedUpdatesEnabled,
|
||||||
@ -90,7 +94,7 @@ const LiteTextEditor = ({
|
|||||||
forwardedRef,
|
forwardedRef,
|
||||||
extensions: LiteTextEditorExtensions(onEnterKeyPress),
|
extensions: LiteTextEditorExtensions(onEnterKeyPress),
|
||||||
mentionHighlights,
|
mentionHighlights,
|
||||||
mentionSuggestions
|
mentionSuggestions,
|
||||||
});
|
});
|
||||||
|
|
||||||
const editorClassNames = getEditorClassNames({
|
const editorClassNames = getEditorClassNames({
|
||||||
@ -114,6 +118,7 @@ const LiteTextEditor = ({
|
|||||||
uploadFile={uploadFile}
|
uploadFile={uploadFile}
|
||||||
setIsSubmitting={setIsSubmitting}
|
setIsSubmitting={setIsSubmitting}
|
||||||
commentAccessSpecifier={commentAccessSpecifier}
|
commentAccessSpecifier={commentAccessSpecifier}
|
||||||
|
submitButton={submitButton}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -122,7 +127,7 @@ const LiteTextEditor = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const LiteTextEditorWithRef = React.forwardRef<EditorHandle, ILiteTextEditor>(
|
const LiteTextEditorWithRef = React.forwardRef<EditorHandle, ILiteTextEditor>(
|
||||||
(props, ref) => <LiteTextEditor {...props} forwardedRef={ref} />
|
(props, ref) => <LiteTextEditor {...props} forwardedRef={ref} />,
|
||||||
);
|
);
|
||||||
|
|
||||||
LiteTextEditorWithRef.displayName = "LiteTextEditorWithRef";
|
LiteTextEditorWithRef.displayName = "LiteTextEditorWithRef";
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Editor } from "@tiptap/react";
|
import { Editor } from "@tiptap/react";
|
||||||
import { BoldIcon, LucideIcon } from "lucide-react";
|
import { BoldIcon } from "lucide-react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BoldItem,
|
BoldItem,
|
||||||
@ -14,7 +14,6 @@ import {
|
|||||||
TableItem,
|
TableItem,
|
||||||
UnderLineItem,
|
UnderLineItem,
|
||||||
} from "@plane/editor-core";
|
} from "@plane/editor-core";
|
||||||
import { Icon } from "./icon";
|
|
||||||
import { Tooltip } from "../../tooltip";
|
import { Tooltip } from "../../tooltip";
|
||||||
import { UploadImage } from "../..";
|
import { UploadImage } from "../..";
|
||||||
|
|
||||||
@ -41,8 +40,9 @@ type EditorBubbleMenuProps = {
|
|||||||
};
|
};
|
||||||
uploadFile: UploadImage;
|
uploadFile: UploadImage;
|
||||||
setIsSubmitting?: (
|
setIsSubmitting?: (
|
||||||
isSubmitting: "submitting" | "submitted" | "saved"
|
isSubmitting: "submitting" | "submitted" | "saved",
|
||||||
) => void;
|
) => void;
|
||||||
|
submitButton: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FixedMenu = (props: EditorBubbleMenuProps) => {
|
export const FixedMenu = (props: EditorBubbleMenuProps) => {
|
||||||
@ -72,117 +72,133 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => {
|
|||||||
props.commentAccessSpecifier?.onAccessChange(accessKey);
|
props.commentAccessSpecifier?.onAccessChange(accessKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log(complexItems);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex w-fit divide-x divide-custom-border-300 rounded border border-custom-border-300 bg-custom-background-100 shadow-xl">
|
<div className="flex items-stretch gap-1.5 w-full h-9">
|
||||||
{props.commentAccessSpecifier && (
|
{props.commentAccessSpecifier && (
|
||||||
<div className="flex border border-custom-border-300 mt-0 divide-x divide-custom-border-300 rounded overflow-hidden">
|
<div className="flex-shrink-0 flex items-stretch gap-0.5 border border-custom-border-200 rounded p-1">
|
||||||
{props?.commentAccessSpecifier.commentAccess?.map((access) => (
|
{props?.commentAccessSpecifier.commentAccess?.map((access) => (
|
||||||
<Tooltip key={access.key} tooltipContent={access.label}>
|
<Tooltip key={access.key} tooltipContent={access.label}>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleAccessChange(access.key)}
|
onClick={() => handleAccessChange(access.key)}
|
||||||
className={`grid place-basicMarkItems-center p-1 hover:bg-custom-background-80 ${
|
className={`aspect-square grid place-items-center p-1 rounded-sm hover:bg-custom-background-90 ${
|
||||||
props.commentAccessSpecifier?.accessValue === access.key
|
props.commentAccessSpecifier?.accessValue === access.key
|
||||||
? "bg-custom-background-80"
|
? "bg-custom-background-90"
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<access.icon
|
<access.icon
|
||||||
className={`w-4 h-4 ${
|
className={`w-3.5 h-3.5 ${
|
||||||
props.commentAccessSpecifier?.accessValue === access.key
|
props.commentAccessSpecifier?.accessValue === access.key
|
||||||
? "!text-custom-text-100"
|
? "text-custom-text-100"
|
||||||
: "!text-custom-text-400"
|
: "text-custom-text-400"
|
||||||
}`}
|
}`}
|
||||||
|
strokeWidth={2}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="flex">
|
<div className="flex items-stretch justify-between gap-2 w-full border border-custom-border-200 bg-custom-background-90 rounded p-1">
|
||||||
|
<div className="flex items-stretch">
|
||||||
|
<div className="flex items-stretch gap-0.5 pr-2.5 border-r border-custom-border-200">
|
||||||
{basicMarkItems.map((item, index) => (
|
{basicMarkItems.map((item, index) => (
|
||||||
<button
|
<button
|
||||||
key={index}
|
key={index}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={item.command}
|
onClick={item.command}
|
||||||
className={cn(
|
className={cn(
|
||||||
"p-2 text-custom-text-300 hover:bg-custom-primary-100/5 active:bg-custom-primary-100/5 transition-colors",
|
"p-1 aspect-square text-custom-text-400 hover:bg-custom-background-80 rounded-sm grid place-items-center",
|
||||||
{
|
{
|
||||||
"text-custom-text-100 bg-custom-primary-100/5": item.isActive(),
|
"text-custom-text-100 bg-custom-background-80":
|
||||||
}
|
item.isActive(),
|
||||||
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<item.icon
|
<item.icon
|
||||||
className={cn("h-4 w-4", {
|
className={cn("h-3.5 w-3.5", {
|
||||||
"text-custom-text-100": item.isActive(),
|
"text-custom-text-100": item.isActive(),
|
||||||
})}
|
})}
|
||||||
|
strokeWidth={2.5}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex items-stretch gap-0.5 px-2.5 border-r border-custom-border-200">
|
||||||
{listItems.map((item, index) => (
|
{listItems.map((item, index) => (
|
||||||
<button
|
<button
|
||||||
key={index}
|
key={index}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={item.command}
|
onClick={item.command}
|
||||||
className={cn(
|
className={cn(
|
||||||
"p-2 text-custom-text-300 hover:bg-custom-primary-100/5 active:bg-custom-primary-100/5 transition-colors",
|
"p-1 aspect-square text-custom-text-400 hover:bg-custom-background-80 rounded-sm grid place-items-center",
|
||||||
{
|
{
|
||||||
"text-custom-text-100 bg-custom-primary-100/5": item.isActive(),
|
"text-custom-text-100 bg-custom-background-80":
|
||||||
}
|
item.isActive(),
|
||||||
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<item.icon
|
<item.icon
|
||||||
className={cn("h-4 w-4", {
|
className={cn("h-3.5 w-3.5", {
|
||||||
"text-custom-text-100": item.isActive(),
|
"text-custom-text-100": item.isActive(),
|
||||||
})}
|
})}
|
||||||
|
strokeWidth={2.5}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex items-stretch gap-0.5 px-2.5 border-r border-custom-border-200">
|
||||||
{userActionItems.map((item, index) => (
|
{userActionItems.map((item, index) => (
|
||||||
<button
|
<button
|
||||||
key={index}
|
key={index}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={item.command}
|
onClick={item.command}
|
||||||
className={cn(
|
className={cn(
|
||||||
"p-2 text-custom-text-300 hover:bg-custom-primary-100/5 active:bg-custom-primary-100/5 transition-colors",
|
"p-1 aspect-square text-custom-text-400 hover:bg-custom-background-80 rounded-sm grid place-items-center",
|
||||||
{
|
{
|
||||||
"text-custom-text-100 bg-custom-primary-100/5": item.isActive(),
|
"text-custom-text-100 bg-custom-background-80":
|
||||||
}
|
item.isActive(),
|
||||||
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<item.icon
|
<item.icon
|
||||||
className={cn("h-4 w-4", {
|
className={cn("h-3.5 w-3.5", {
|
||||||
"text-custom-text-100": item.isActive(),
|
"text-custom-text-100": item.isActive(),
|
||||||
})}
|
})}
|
||||||
|
strokeWidth={2.5}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="flex items-stretch gap-0.5 pl-2.5">
|
||||||
{complexItems.map((item, index) => (
|
{complexItems.map((item, index) => (
|
||||||
<button
|
<button
|
||||||
key={index}
|
key={index}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={item.command}
|
onClick={item.command}
|
||||||
className={cn(
|
className={cn(
|
||||||
"p-2 text-custom-text-300 hover:bg-custom-primary-100/5 active:bg-custom-primary-100/5 transition-colors",
|
"p-1 aspect-square text-custom-text-400 hover:bg-custom-background-80 rounded-sm grid place-items-center",
|
||||||
{
|
{
|
||||||
"text-custom-text-100 bg-custom-primary-100/5": item.isActive(),
|
"text-custom-text-100 bg-custom-background-80":
|
||||||
}
|
item.isActive(),
|
||||||
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<item.icon
|
<item.icon
|
||||||
className={cn("h-4 w-4", {
|
className={cn("h-3.5 w-3.5", {
|
||||||
"text-custom-text-100": item.isActive(),
|
"text-custom-text-100": item.isActive(),
|
||||||
})}
|
})}
|
||||||
|
strokeWidth={2.5}
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{props.submitButton}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -49,7 +49,7 @@ export const IssueCommentCard: React.FC<IIssueCommentCard> = (props) => {
|
|||||||
|
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
|
|
||||||
const editorSuggestions = useEditorSuggestions(workspaceSlug, projectId)
|
const editorSuggestions = useEditorSuggestions(workspaceSlug, projectId);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
formState: { isSubmitting },
|
formState: { isSubmitting },
|
||||||
|
@ -54,7 +54,7 @@ export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
const editorSuggestions = useEditorSuggestions(workspaceSlug as string | undefined, projectId as string | undefined)
|
const editorSuggestions = useEditorSuggestions(workspaceSlug as string | undefined, projectId as string | undefined);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -75,7 +75,7 @@ export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit(handleAddComment)}>
|
<form onSubmit={handleSubmit(handleAddComment)}>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="relative">
|
<div className="relative h-full">
|
||||||
{showAccessSpecifier && (
|
{showAccessSpecifier && (
|
||||||
<div className="absolute bottom-2 left-3 z-[1]">
|
<div className="absolute bottom-2 left-3 z-[1]">
|
||||||
<Controller
|
<Controller
|
||||||
@ -119,22 +119,28 @@ export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
|
|||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.deleteImage}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
||||||
customClassName="p-3 min-h-[100px] shadow-sm"
|
customClassName="p-2 h-full"
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
mentionSuggestions={editorSuggestions.mentionSuggestions}
|
mentionSuggestions={editorSuggestions.mentionSuggestions}
|
||||||
mentionHighlights={editorSuggestions.mentionHighlights}
|
mentionHighlights={editorSuggestions.mentionHighlights}
|
||||||
onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)}
|
onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)}
|
||||||
commentAccessSpecifier={{ accessValue, onAccessChange, showAccessSpecifier, commentAccess }}
|
commentAccessSpecifier={{ accessValue, onAccessChange, showAccessSpecifier, commentAccess }}
|
||||||
|
submitButton={
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
className="!px-2.5 !py-1.5 !text-xs"
|
||||||
|
disabled={isSubmitting || disabled}
|
||||||
|
>
|
||||||
|
{isSubmitting ? "Adding..." : "Comment"}
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button variant="neutral-primary" type="submit" disabled={isSubmitting || disabled}>
|
|
||||||
{isSubmitting ? "Adding..." : "Comment"}
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user