WbwMeaning.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. import { useState } from "react";
  2. import { useIntl } from "react-intl";
  3. import { Input, Popover, Typography } from "antd";
  4. import { IWbw, TWbwDisplayMode } from "./WbwWord";
  5. import WbwMeaningSelect from "./WbwMeaningSelect";
  6. import { ArticleMode } from "../../article/Article";
  7. import CaseFormula from "./CaseFormula";
  8. const { Text } = Typography;
  9. interface IWidget {
  10. data: IWbw;
  11. display?: TWbwDisplayMode;
  12. mode?: ArticleMode;
  13. onChange?: Function;
  14. }
  15. const WbwMeaningWidget = ({
  16. data,
  17. display = "block",
  18. mode = "edit",
  19. onChange,
  20. }: IWidget) => {
  21. const intl = useIntl();
  22. const [open, setOpen] = useState(false);
  23. const [input, setInput] = useState<string>();
  24. const [editable, setEditable] = useState(false);
  25. let meaning = <></>;
  26. if (
  27. typeof data.meaning?.value === "string" &&
  28. data.meaning.value.trim().length > 0
  29. ) {
  30. const eMeaning = data.meaning.value
  31. .replaceAll("[", "@[")
  32. .replaceAll("]", "]@")
  33. .replaceAll("{", "@{")
  34. .replaceAll("}", "}@")
  35. .split("@")
  36. .map((item, index) => {
  37. if (item.includes("[")) {
  38. return (
  39. <span key={index} style={{ color: "rosybrown" }}>
  40. {item.replaceAll("[", "").replaceAll("]", "")}
  41. </span>
  42. );
  43. } else if (item.includes("{")) {
  44. return (
  45. <span key={index} style={{ color: "lightskyblue" }}>
  46. {item.replaceAll("{", "").replaceAll("}", "")}
  47. </span>
  48. );
  49. } else {
  50. return <Text key={index}>{item}</Text>;
  51. }
  52. });
  53. meaning = <Text>{eMeaning}</Text>;
  54. } else if (mode === "wbw" || display === "inline") {
  55. //空白的意思在逐词解析模式显示占位字符串
  56. meaning = (
  57. <Text type="secondary">
  58. {intl.formatMessage({ id: "dict.fields.meaning.label" })}
  59. </Text>
  60. );
  61. }
  62. const meaningInner = editable ? (
  63. <Input
  64. defaultValue={data.meaning?.value ? data.meaning?.value : ""}
  65. placeholder="meaning"
  66. style={{ width: "100%" }}
  67. onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
  68. setInput(event.target.value);
  69. }}
  70. onPressEnter={(event: React.KeyboardEvent<HTMLInputElement>) => {
  71. inputOk();
  72. }}
  73. onKeyDown={(event: React.KeyboardEvent<HTMLInputElement>) => {
  74. if (event.key === "Escape") {
  75. setEditable(false);
  76. }
  77. }}
  78. />
  79. ) : (
  80. <span
  81. onClick={(event: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
  82. if (event.ctrlKey) {
  83. setEditable(true);
  84. }
  85. }}
  86. >
  87. {meaning}
  88. </span>
  89. );
  90. const inputOk = () => {
  91. setEditable(false);
  92. if (typeof onChange !== "undefined") {
  93. onChange(input);
  94. }
  95. };
  96. const hide = () => {
  97. setOpen(false);
  98. };
  99. const handleOpenChange = (newOpen: boolean) => {
  100. setOpen(newOpen);
  101. };
  102. if (
  103. typeof data.real?.value === "string" &&
  104. data.real.value.trim().length > 0
  105. ) {
  106. //非标点符号
  107. return (
  108. <div className="wbw_word_item">
  109. {editable ? (
  110. meaningInner
  111. ) : (
  112. <div style={{ display: "flex", justifyContent: "space-between" }}>
  113. <Popover
  114. open={open}
  115. onOpenChange={handleOpenChange}
  116. content={
  117. <div style={{ width: 500, height: "450px", overflow: "auto" }}>
  118. <WbwMeaningSelect
  119. data={data}
  120. onSelect={(e: string) => {
  121. hide();
  122. if (typeof onChange !== "undefined") {
  123. onChange(e);
  124. }
  125. }}
  126. />
  127. </div>
  128. }
  129. placement="bottomLeft"
  130. trigger="hover"
  131. >
  132. {meaningInner}
  133. </Popover>
  134. {mode === "wbw" ? (
  135. <CaseFormula
  136. data={data}
  137. onCaseChange={(formula: string) => {
  138. if (
  139. data.meaning?.value &&
  140. data.meaning?.value.indexOf("[") >= 0
  141. ) {
  142. return;
  143. }
  144. }}
  145. onChange={(formula: string) => {
  146. /**
  147. * 有 [ ] 不自动替换
  148. * 有{ } 祛除 { }
  149. * 把 格位公式中的 ~ 替换为 data.meaning.value
  150. */
  151. let meaning: string = data.meaning?.value
  152. ? data.meaning?.value
  153. : "";
  154. meaning = meaning.replace(/\{(.+?)\}/g, "");
  155. meaning = meaning.replace(/\[(.+?)\]/g, "");
  156. meaning = formula
  157. .replaceAll("{", "[")
  158. .replaceAll("}", "]")
  159. .replace("~", meaning);
  160. if (typeof onChange !== "undefined") {
  161. onChange(meaning);
  162. }
  163. }}
  164. />
  165. ) : undefined}
  166. </div>
  167. )}
  168. </div>
  169. );
  170. } else {
  171. //标点符号
  172. return <></>;
  173. }
  174. };
  175. export default WbwMeaningWidget;