Editable.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. "use client";
  2. import * as React from 'react';
  3. import EnterOutlined from "@ant-design/icons/es/icons/EnterOutlined";
  4. import classNames from 'classnames';
  5. import KeyCode from "rc-util/es/KeyCode";
  6. import { cloneElement } from '../_util/reactNode';
  7. import TextArea from '../input/TextArea';
  8. import useStyle from './style';
  9. const Editable = props => {
  10. const {
  11. prefixCls,
  12. 'aria-label': ariaLabel,
  13. className,
  14. style,
  15. direction,
  16. maxLength,
  17. autoSize = true,
  18. value,
  19. onSave,
  20. onCancel,
  21. onEnd,
  22. component,
  23. enterIcon = /*#__PURE__*/React.createElement(EnterOutlined, null)
  24. } = props;
  25. const ref = React.useRef(null);
  26. const inComposition = React.useRef(false);
  27. const lastKeyCode = React.useRef(null);
  28. const [current, setCurrent] = React.useState(value);
  29. React.useEffect(() => {
  30. setCurrent(value);
  31. }, [value]);
  32. React.useEffect(() => {
  33. var _a;
  34. if ((_a = ref.current) === null || _a === void 0 ? void 0 : _a.resizableTextArea) {
  35. const {
  36. textArea
  37. } = ref.current.resizableTextArea;
  38. textArea.focus();
  39. const {
  40. length
  41. } = textArea.value;
  42. textArea.setSelectionRange(length, length);
  43. }
  44. }, []);
  45. const onChange = ({
  46. target
  47. }) => {
  48. setCurrent(target.value.replace(/[\n\r]/g, ''));
  49. };
  50. const onCompositionStart = () => {
  51. inComposition.current = true;
  52. };
  53. const onCompositionEnd = () => {
  54. inComposition.current = false;
  55. };
  56. const onKeyDown = ({
  57. keyCode
  58. }) => {
  59. // We don't record keyCode when IME is using
  60. if (inComposition.current) return;
  61. lastKeyCode.current = keyCode;
  62. };
  63. const confirmChange = () => {
  64. onSave(current.trim());
  65. };
  66. const onKeyUp = ({
  67. keyCode,
  68. ctrlKey,
  69. altKey,
  70. metaKey,
  71. shiftKey
  72. }) => {
  73. // Check if it's a real key
  74. if (lastKeyCode.current !== keyCode || inComposition.current || ctrlKey || altKey || metaKey || shiftKey) {
  75. return;
  76. }
  77. if (keyCode === KeyCode.ENTER) {
  78. confirmChange();
  79. onEnd === null || onEnd === void 0 ? void 0 : onEnd();
  80. } else if (keyCode === KeyCode.ESC) {
  81. onCancel();
  82. }
  83. };
  84. const onBlur = () => {
  85. confirmChange();
  86. };
  87. const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
  88. const textAreaClassName = classNames(prefixCls, `${prefixCls}-edit-content`, {
  89. [`${prefixCls}-rtl`]: direction === 'rtl',
  90. [`${prefixCls}-${component}`]: !!component
  91. }, className, hashId, cssVarCls);
  92. return wrapCSSVar(/*#__PURE__*/React.createElement("div", {
  93. className: textAreaClassName,
  94. style: style
  95. }, /*#__PURE__*/React.createElement(TextArea, {
  96. ref: ref,
  97. maxLength: maxLength,
  98. value: current,
  99. onChange: onChange,
  100. onKeyDown: onKeyDown,
  101. onKeyUp: onKeyUp,
  102. onCompositionStart: onCompositionStart,
  103. onCompositionEnd: onCompositionEnd,
  104. onBlur: onBlur,
  105. "aria-label": ariaLabel,
  106. rows: 1,
  107. autoSize: autoSize
  108. }), enterIcon !== null ? cloneElement(enterIcon, {
  109. className: `${prefixCls}-edit-content-confirm`
  110. }) : null));
  111. };
  112. export default Editable;