mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 08:26:21 +00:00
refactor(client): abstract RawTextArea for variable input (#2204)
This commit is contained in:
parent
6496c65fc4
commit
6646007dd7
@ -25,7 +25,7 @@ export const Json = React.forwardRef<typeof Input.TextArea, JSONTextAreaProps>(
|
|||||||
{...props}
|
{...props}
|
||||||
className={cx(
|
className={cx(
|
||||||
css`
|
css`
|
||||||
font-size: 90%;
|
font-size: 80%;
|
||||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||||
`,
|
`,
|
||||||
props.className,
|
props.className,
|
||||||
|
@ -1,64 +1,8 @@
|
|||||||
import React, { useRef, useState } from 'react';
|
import React from 'react';
|
||||||
import { Button } from 'antd';
|
|
||||||
import { css } from '@emotion/css';
|
|
||||||
import { cloneDeep } from 'lodash';
|
|
||||||
|
|
||||||
import { Input } from '../input';
|
import { Input } from '../input';
|
||||||
import { VariableSelect } from './VariableSelect';
|
import { RawTextArea } from './RawTextArea';
|
||||||
|
|
||||||
// NOTE: https://stackoverflow.com/questions/23892547/what-is-the-best-way-to-trigger-onchange-event-in-react-js/46012210#46012210
|
|
||||||
function setNativeInputValue(input, value) {
|
|
||||||
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(input.constructor.prototype, 'value')?.set;
|
|
||||||
nativeInputValueSetter?.call(input, value);
|
|
||||||
input.dispatchEvent(
|
|
||||||
new Event('input', {
|
|
||||||
bubbles: true,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function JSONInput(props) {
|
export function JSONInput(props) {
|
||||||
const inputRef = useRef<any>(null);
|
return <RawTextArea {...props} component={Input.JSON} />;
|
||||||
const { scope, changeOnSelect, ...others } = props;
|
|
||||||
const [options, setOptions] = useState(scope ? cloneDeep(scope) : []);
|
|
||||||
|
|
||||||
function onInsert(selected) {
|
|
||||||
if (!inputRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const variable = `{{${selected.join('.')}}}`;
|
|
||||||
|
|
||||||
const { textArea } = inputRef.current.resizableTextArea;
|
|
||||||
const nextValue =
|
|
||||||
textArea.value.slice(0, textArea.selectionStart) + variable + textArea.value.slice(textArea.selectionEnd);
|
|
||||||
const nextPos = [textArea.selectionStart, textArea.selectionStart + variable.length];
|
|
||||||
setNativeInputValue(textArea, nextValue);
|
|
||||||
textArea.setSelectionRange(...nextPos);
|
|
||||||
textArea.focus();
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={css`
|
|
||||||
position: relative;
|
|
||||||
.ant-input {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Input.JSON {...others} ref={inputRef} />
|
|
||||||
<Button.Group
|
|
||||||
className={css`
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
.ant-btn-sm {
|
|
||||||
font-size: 85%;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<VariableSelect options={options} setOptions={setOptions} onInsert={onInsert} changeOnSelect={changeOnSelect} />
|
|
||||||
</Button.Group>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
import React, { useRef, useState } from 'react';
|
||||||
|
import { css } from '@emotion/css';
|
||||||
|
import { Button, Input } from 'antd';
|
||||||
|
import { cloneDeep } from 'lodash';
|
||||||
|
|
||||||
|
import { VariableSelect } from './VariableSelect';
|
||||||
|
|
||||||
|
// NOTE: https://stackoverflow.com/questions/23892547/what-is-the-best-way-to-trigger-onchange-event-in-react-js/46012210#46012210
|
||||||
|
function setNativeInputValue(input, value) {
|
||||||
|
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(input.constructor.prototype, 'value')?.set;
|
||||||
|
nativeInputValueSetter?.call(input, value);
|
||||||
|
input.dispatchEvent(
|
||||||
|
new Event('input', {
|
||||||
|
bubbles: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function RawTextArea(props): JSX.Element {
|
||||||
|
const inputRef = useRef<any>(null);
|
||||||
|
const { scope, changeOnSelect, component: Component = Input.TextArea, ...others } = props;
|
||||||
|
const [options, setOptions] = useState(scope ? cloneDeep(scope) : []);
|
||||||
|
|
||||||
|
function onInsert(selected) {
|
||||||
|
if (!inputRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const variable = `{{${selected.join('.')}}}`;
|
||||||
|
|
||||||
|
const { textArea } = inputRef.current.resizableTextArea;
|
||||||
|
const nextValue =
|
||||||
|
textArea.value.slice(0, textArea.selectionStart) + variable + textArea.value.slice(textArea.selectionEnd);
|
||||||
|
const nextPos = [textArea.selectionStart, textArea.selectionStart + variable.length];
|
||||||
|
setNativeInputValue(textArea, nextValue);
|
||||||
|
textArea.setSelectionRange(...nextPos);
|
||||||
|
textArea.focus();
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
position: relative;
|
||||||
|
.ant-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<Component {...others} ref={inputRef} />
|
||||||
|
<Button.Group
|
||||||
|
className={css`
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
.ant-btn-sm {
|
||||||
|
font-size: 85%;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<VariableSelect options={options} setOptions={setOptions} onInsert={onInsert} changeOnSelect={changeOnSelect} />
|
||||||
|
</Button.Group>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -3,6 +3,7 @@ import { connect, mapReadPretty } from '@formily/react';
|
|||||||
import { IField } from '../../../collection-manager';
|
import { IField } from '../../../collection-manager';
|
||||||
import { Input } from './Input';
|
import { Input } from './Input';
|
||||||
import { JSONInput } from './JSONInput';
|
import { JSONInput } from './JSONInput';
|
||||||
|
import { RawTextArea } from './RawTextArea';
|
||||||
import { TextArea } from './TextArea';
|
import { TextArea } from './TextArea';
|
||||||
|
|
||||||
export function Variable() {
|
export function Variable() {
|
||||||
@ -13,6 +14,8 @@ Variable.Input = connect(Input);
|
|||||||
|
|
||||||
Variable.TextArea = connect(TextArea, mapReadPretty(TextArea.ReadPretty));
|
Variable.TextArea = connect(TextArea, mapReadPretty(TextArea.ReadPretty));
|
||||||
|
|
||||||
|
Variable.RawTextArea = connect(RawTextArea);
|
||||||
|
|
||||||
Variable.JSON = connect(JSONInput);
|
Variable.JSON = connect(JSONInput);
|
||||||
|
|
||||||
export default Variable;
|
export default Variable;
|
||||||
|
Loading…
Reference in New Issue
Block a user