fix: textarea with password visual bug (#3739)
* Fix textarea with password visual bug * Changed password field to default to none * updated sanitizedHTMLWrapper to receive ref * fixed sanitizedhtmlwrapper type * Added back to scroll position and cursor position on Chrome * [autofix.ci] apply automated fixes * Fix position of password * Fixed tests * Fixed examples * Fixed test schema --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: anovazzi1 <otavio2204@gmail.com>
This commit is contained in:
parent
0b1198efc4
commit
5bb266cbc1
8 changed files with 69 additions and 36 deletions
|
|
@ -1,23 +1,24 @@
|
|||
import DOMPurify from "dompurify";
|
||||
import { forwardRef } from "react";
|
||||
import { SanitizedHTMLWrapperType } from "../../types/components";
|
||||
|
||||
const SanitizedHTMLWrapper = ({
|
||||
className,
|
||||
content,
|
||||
onClick,
|
||||
suppressWarning = false,
|
||||
}: SanitizedHTMLWrapperType): JSX.Element => {
|
||||
const SanitizedHTMLWrapper = forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLHeadingElement> & SanitizedHTMLWrapperType
|
||||
>(({ content, suppressWarning = false, ...props }, ref) => {
|
||||
const sanitizedHTML = DOMPurify.sanitize(content);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
data-testid="edit-prompt-sanitized"
|
||||
className={className}
|
||||
dangerouslySetInnerHTML={{ __html: sanitizedHTML }}
|
||||
suppressContentEditableWarning={suppressWarning}
|
||||
onClick={onClick}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
SanitizedHTMLWrapper.displayName = "SanitizedHTMLWrapper";
|
||||
|
||||
export default SanitizedHTMLWrapper;
|
||||
|
|
|
|||
|
|
@ -50,12 +50,7 @@ export default function TextAreaComponent({
|
|||
disabled={disabled}
|
||||
password={password}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
"flex items-center",
|
||||
password ? "relative left-6" : "",
|
||||
)}
|
||||
>
|
||||
<div className={classNames("flex items-center")}>
|
||||
<Button unstyled>
|
||||
<IconComponent
|
||||
strokeWidth={1.5}
|
||||
|
|
@ -79,10 +74,7 @@ export default function TextAreaComponent({
|
|||
unstyled
|
||||
tabIndex={-1}
|
||||
className={classNames(
|
||||
"side-bar-button-size absolute mb-px text-muted-foreground hover:text-current",
|
||||
editNode
|
||||
? "bottom-[1.3rem] right-[4.2rem]"
|
||||
: "bottom-4 right-[4.2rem]",
|
||||
"side-bar-button-size absolute right-3 top-1/2 mb-px -translate-y-1/2 text-muted-foreground hover:text-current",
|
||||
)}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
|
|
@ -128,12 +120,12 @@ export default function TextAreaComponent({
|
|||
};
|
||||
|
||||
return (
|
||||
<div className={classNames("flex w-full items-center", disabled ? "" : "")}>
|
||||
<div className="flex w-full items-center gap-3" data-testid={`div-${id}`}>
|
||||
<div className={classNames("flex w-full items-center gap-3")}>
|
||||
<div className="relative w-full" data-testid={`div-${id}`}>
|
||||
{renderTextarea()}
|
||||
{renderExternalLinkButton()}
|
||||
{renderPasswordToggle()}
|
||||
</div>
|
||||
{renderExternalLinkButton()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { usePostValidatePrompt } from "@/controllers/API/queries/nodes/use-post-validate-prompt";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import SanitizedHTMLWrapper from "../../components/sanitizedHTMLWrapper";
|
||||
import ShadTooltip from "../../components/shadTooltipComponent";
|
||||
|
|
@ -47,6 +47,10 @@ export default function PromptModal({
|
|||
const divRef = useRef(null);
|
||||
const divRefPrompt = useRef(null);
|
||||
const { mutate: postValidatePrompt } = usePostValidatePrompt();
|
||||
const [clickPosition, setClickPosition] = useState({ x: 0, y: 0 });
|
||||
const [scrollPosition, setScrollPosition] = useState(0);
|
||||
const previewRef = useRef<HTMLDivElement>(null);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
function checkVariables(valueToCheck: string): void {
|
||||
const regex = /\{([^{}]+)\}/g;
|
||||
|
|
@ -172,6 +176,37 @@ export default function PromptModal({
|
|||
);
|
||||
}
|
||||
|
||||
const handlePreviewClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (!isEdit && !readonly) {
|
||||
const clickX = e.clientX;
|
||||
const clickY = e.clientY;
|
||||
setClickPosition({ x: clickX, y: clickY });
|
||||
setScrollPosition(e.currentTarget.scrollTop);
|
||||
setIsEdit(true);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isEdit && textareaRef.current) {
|
||||
textareaRef.current.focus();
|
||||
textareaRef.current.scrollTop = scrollPosition;
|
||||
|
||||
const textArea = textareaRef.current;
|
||||
const { x, y } = clickPosition;
|
||||
|
||||
// Use caretPositionFromPoint to get the closest text position. Does not work on Safari.
|
||||
if ("caretPositionFromPoint" in document) {
|
||||
let range = (document as any).caretPositionFromPoint(x, y)?.offset ?? 0;
|
||||
if (range) {
|
||||
const position = range;
|
||||
textArea.setSelectionRange(position, position);
|
||||
}
|
||||
}
|
||||
} else if (!isEdit && previewRef.current) {
|
||||
previewRef.current.scrollTop = scrollPosition;
|
||||
}
|
||||
}, [isEdit, clickPosition, scrollPosition]);
|
||||
|
||||
return (
|
||||
<BaseModal
|
||||
onChangeOpenModal={(open) => {}}
|
||||
|
|
@ -202,10 +237,11 @@ export default function PromptModal({
|
|||
<Textarea
|
||||
id={"modal-" + id}
|
||||
data-testid={"modal-" + id}
|
||||
ref={divRefPrompt}
|
||||
className="form-input h-full w-full resize-none rounded-lg custom-scroll focus-visible:ring-1"
|
||||
ref={textareaRef}
|
||||
className="form-input h-full w-full resize-none rounded-lg border-0 custom-scroll focus-visible:ring-1"
|
||||
value={inputValue}
|
||||
onBlur={() => {
|
||||
setScrollPosition(textareaRef.current?.scrollTop || 0);
|
||||
setIsEdit(false);
|
||||
}}
|
||||
autoFocus
|
||||
|
|
@ -220,11 +256,10 @@ export default function PromptModal({
|
|||
/>
|
||||
) : (
|
||||
<SanitizedHTMLWrapper
|
||||
ref={previewRef}
|
||||
className={getClassByNumberLength() + " bg-muted"}
|
||||
onClick={handlePreviewClick}
|
||||
content={coloredContent}
|
||||
onClick={() => {
|
||||
if (!readonly) setIsEdit(true);
|
||||
}}
|
||||
suppressWarning={true}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -644,9 +644,7 @@ export type parsedDataType = {
|
|||
};
|
||||
|
||||
export type SanitizedHTMLWrapperType = {
|
||||
className: string;
|
||||
content: string;
|
||||
onClick: () => void;
|
||||
suppressWarning?: boolean;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue