CustomInput.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import React, { useEffect, useMemo, useRef, useState } from "react";
  2. import { Input, InputRef } from "antd";
  3. import { Node } from "@antv/x6";
  4. import { useSafeState } from "ahooks";
  5. import FlowExtra from "./FlowExtra";
  6. export default function CustomInput(props: {
  7. value: string;
  8. styles: React.CSSProperties & {
  9. textVAlign: "top" | "middle" | "bottom";
  10. bold: boolean;
  11. italic: boolean;
  12. };
  13. node: Node;
  14. placeholder?: string;
  15. txtStyle?: React.CSSProperties;
  16. onChange?: (value: string) => void;
  17. }) {
  18. const { value, styles, node, placeholder, txtStyle } = props;
  19. const [isEditing, setIsEditing] = useSafeState(false);
  20. const inputRef = useRef<InputRef>(null);
  21. const style = useMemo(() => {
  22. const top =
  23. styles.textVAlign === "top"
  24. ? 0
  25. : styles.textVAlign === "middle"
  26. ? "50%"
  27. : undefined;
  28. const bottom = styles.textVAlign === "bottom" ? 0 : undefined;
  29. return {
  30. ...styles,
  31. fontWeight: styles.bold ? "bold" : undefined,
  32. fontStyle: styles.italic ? "italic" : undefined,
  33. transform:
  34. styles.textVAlign === "middle" ? "translateY(-50%)" : undefined,
  35. minHeight: "12px",
  36. top,
  37. bottom,
  38. };
  39. }, [styles]);
  40. const handleChange = (val: string) => {
  41. node.setData({ label: val });
  42. props.onChange?.(val);
  43. };
  44. const [findObj, setFindObj] = useState<{
  45. findStr: string;
  46. currentCellId?: string;
  47. currentIndex: number;
  48. }>();
  49. // 查找
  50. const handleFind = (args: any) => {
  51. setFindObj(args?.current || {});
  52. };
  53. const label = useMemo(() => {
  54. if (!findObj) return value;
  55. const list = (value || "").split(findObj.findStr || "");
  56. return list.map((str: string, index) => {
  57. // 当前的节点展示
  58. const style =
  59. findObj.currentCellId === node.id
  60. ? {
  61. background:
  62. index + 1 === findObj.currentIndex
  63. ? "#FF9933"
  64. : "rgba(255, 153, 51, 0.25)",
  65. }
  66. : {
  67. background: "#ffff00",
  68. };
  69. return (
  70. <span key={index}>
  71. {str}
  72. {index < list.length - 1 && (
  73. <span style={style}>{findObj.findStr}</span>
  74. )}
  75. </span>
  76. );
  77. });
  78. }, [value, findObj]);
  79. const handleReplace = (args: any) => {
  80. console.log("替换:", args);
  81. const { type, searchText, replaceText, currentIndex, currentCellId } = args?.current || {};
  82. if(args.current?.type === 'replaceAll') {
  83. handleChange(value.replaceAll(searchText, replaceText));
  84. }
  85. if(type === 'replace' && currentCellId === node.id) {
  86. const list = value.split(searchText);
  87. const text = list.map((str, index) => {
  88. const result = index + 1 === currentIndex ? replaceText : searchText;
  89. return str + (index < list.length - 1 ? result : '');
  90. }).join("");
  91. console.log(text);
  92. handleChange(text);
  93. }
  94. };
  95. const handleClear = () => {
  96. setFindObj(undefined);
  97. };
  98. useEffect(() => {
  99. node.off("change:find", handleFind);
  100. node.off("change:replace", handleReplace);
  101. node.off("change:clearFind", handleClear);
  102. node.on("change:find", handleFind);
  103. node.on("change:replace", handleReplace);
  104. node.on("change:clearFind", handleClear);
  105. return () => {
  106. node.off("change:find", handleFind);
  107. node.off("change:replace", handleReplace);
  108. node.off("change:clearFind", handleClear);
  109. };
  110. }, [value]);
  111. const handleSetEditing = (edit: boolean) => {
  112. if (node.data?.lock) {
  113. return;
  114. }
  115. node.setData({
  116. ignoreDrag: edit,
  117. });
  118. if (edit) {
  119. setTimeout(() => {
  120. inputRef.current?.focus({ cursor: "all" });
  121. }, 100);
  122. }
  123. setIsEditing(edit);
  124. };
  125. // useEffect(() => {
  126. // // 处理字体加载
  127. // // @ts-ignore
  128. // // WebFont.load({
  129. // // google: {
  130. // // families: [styles.fontFamily]
  131. // // }
  132. // // })
  133. // }, [styles.fontFamily]);
  134. return (
  135. <div className="absolute w-full h-full w-full" style={txtStyle}>
  136. <FlowExtra node={node} />
  137. {isEditing ? (
  138. <Input.TextArea
  139. ref={inputRef}
  140. placeholder={placeholder}
  141. value={value}
  142. variant="borderless"
  143. className="absolute"
  144. style={style}
  145. onChange={(e) => handleChange(e.target.value)}
  146. onBlur={() => handleSetEditing(false)}
  147. autoSize
  148. />
  149. ) : (
  150. <div
  151. className="absolute w-full"
  152. style={style}
  153. onDoubleClick={() => handleSetEditing(true)}
  154. >
  155. {label}
  156. </div>
  157. )}
  158. </div>
  159. );
  160. }