mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 11:26:55 +00:00
fix(client/formula): set cursor focus on input (#959)
* fix(client/formula): set cursor focus on input * fix(client/formula): when formula field name has contains the other one will case FormulaError refactor partial implementation
This commit is contained in:
parent
7cb5ff554e
commit
9a81b1b8ee
@ -1,7 +1,7 @@
|
|||||||
import { Field, onFormSubmitValidateStart } from '@formily/core';
|
import { Field, onFormSubmitValidateStart } from '@formily/core';
|
||||||
import { connect, mapProps, mapReadPretty, useField, useFieldSchema, useFormEffects } from '@formily/react';
|
import { connect, mapProps, useField, useFormEffects } from '@formily/react';
|
||||||
import { Button, Input, Popover, Tag, Menu, Dropdown } from 'antd';
|
import { Menu, Dropdown } from 'antd';
|
||||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import ContentEditable from 'react-contenteditable';
|
import ContentEditable from 'react-contenteditable';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import * as math from 'mathjs';
|
import * as math from 'mathjs';
|
||||||
@ -14,62 +14,65 @@ const AntdFormulaInput = (props) => {
|
|||||||
|
|
||||||
const inputRef = useRef();
|
const inputRef = useRef();
|
||||||
const [dropdownVisible, setDropdownVisible] = useState(false);
|
const [dropdownVisible, setDropdownVisible] = useState(false);
|
||||||
const [formula, setFormula] = useState(null);
|
|
||||||
const [html, setHtml] = useState(null);
|
const [html, setHtml] = useState(null);
|
||||||
|
|
||||||
const numColumns = new Map<string, string>();
|
const numColumns = new Map<string, string>();
|
||||||
const scope = {};
|
const scope = {};
|
||||||
fields.filter(field => supports.includes(field.interface)).forEach(field => {
|
fields
|
||||||
|
.filter((field) => supports.includes(field.interface))
|
||||||
|
.forEach((field) => {
|
||||||
numColumns.set(field.name, field.uiSchema.title);
|
numColumns.set(field.name, field.uiSchema.title);
|
||||||
scope[field.name] = 1;
|
scope[field.name] = 1;
|
||||||
})
|
});
|
||||||
const keys = Array.from(numColumns.keys());
|
const keys = Array.from(numColumns.keys());
|
||||||
|
|
||||||
let initHtml;
|
|
||||||
if (value) {
|
|
||||||
initHtml = value;
|
|
||||||
numColumns.forEach((value, key) => {
|
|
||||||
initHtml = initHtml.replaceAll(key, `<span contentEditable="false" style="border: 1px solid #aaa; padding: 2px 5px;">${value}</span>`)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onChange && formula) {
|
if (value) {
|
||||||
let v = formula || '';
|
let newHtml = value;
|
||||||
numColumns.forEach((value, key) => {
|
numColumns.forEach((value, key) => {
|
||||||
v = v.replaceAll(value, key);
|
newHtml = newHtml.replaceAll(
|
||||||
})
|
key,
|
||||||
if (v != value) {
|
`<span contentEditable="false" ><input disabled="disabled" style="width:${
|
||||||
onChange(v);
|
18 * value.length
|
||||||
|
}px;max-width: 120px" value="${value}"/><span hidden>${key}</span></span>`,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
newHtml = `${newHtml}<span style="padding-left: 5px"></span>`; // set extra span for cursor focus on last position
|
||||||
|
setHtml(newHtml);
|
||||||
|
} else {
|
||||||
|
setHtml('');
|
||||||
}
|
}
|
||||||
}
|
}, [value]);
|
||||||
}, [formula])
|
|
||||||
|
|
||||||
const menu = (
|
const menu = (
|
||||||
<Menu onClick={async (args) => {
|
<Menu
|
||||||
const replaceFormula = formula.replace('@', numColumns.get(args.key));
|
onClick={async (args) => {
|
||||||
const replaceHtml = html.replace('@', `<span contentEditable="false" style="border: 1px solid #aaa; padding: 2px 5px;">${numColumns.get(args.key)}</span>`);
|
const replaceFormula = field.value.replace('@', args.key);
|
||||||
setFormula(replaceFormula);
|
if (onChange && replaceFormula != field.value) {
|
||||||
setHtml(replaceHtml);
|
onChange(replaceFormula);
|
||||||
setDropdownVisible(false);
|
|
||||||
}}>
|
|
||||||
{
|
|
||||||
keys.map(key => (<Menu.Item key={key}>{numColumns.get(key)}</Menu.Item>))
|
|
||||||
}
|
}
|
||||||
|
setDropdownVisible(false);
|
||||||
|
(inputRef.current as any).focus();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{keys.map((key) => (
|
||||||
|
<Menu.Item key={key}>{numColumns.get(key)}</Menu.Item>
|
||||||
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
const current = inputRef.current as any;
|
if (onChange) {
|
||||||
setFormula(e.currentTarget.textContent);
|
if (e.currentTarget.textContent == '') {
|
||||||
setHtml(current.innerHTML);
|
|
||||||
if (e.currentTarget.textContent == '' && onChange) {
|
|
||||||
onChange(null);
|
onChange(null);
|
||||||
|
} else {
|
||||||
|
onChange(e.currentTarget.textContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleKeyDown = (e) => {
|
const handleKeyDown = (e) => {
|
||||||
const {key} = e;
|
const { key } = e;
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -82,22 +85,23 @@ const AntdFormulaInput = (props) => {
|
|||||||
setDropdownVisible(false);
|
setDropdownVisible(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
useFormEffects(() => {
|
useFormEffects(() => {
|
||||||
onFormSubmitValidateStart(() => {
|
onFormSubmitValidateStart(() => {
|
||||||
try {
|
try {
|
||||||
math.evaluate(field.value, scope);
|
math.evaluate(field.value, scope);
|
||||||
field.feedbacks = [];
|
field.feedbacks = [];
|
||||||
} catch {
|
} catch (e) {
|
||||||
|
console.error(field.value, scope, (e as Error).message);
|
||||||
field.setFeedback({
|
field.setFeedback({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
code: 'FormulaError',
|
code: 'FormulaError',
|
||||||
messages: [t('Formula error.')],
|
messages: [t('Formula error.')],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown overlay={menu} visible={dropdownVisible}>
|
<Dropdown overlay={menu} visible={dropdownVisible}>
|
||||||
@ -106,16 +110,12 @@ const AntdFormulaInput = (props) => {
|
|||||||
className="ant-input"
|
className="ant-input"
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
html={html || initHtml || ''}
|
html={html || ''}
|
||||||
/>
|
/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
)
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const FormulaInput = connect(
|
export const FormulaInput = connect(AntdFormulaInput, mapProps({}));
|
||||||
AntdFormulaInput,
|
|
||||||
mapProps({
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export default FormulaInput;
|
export default FormulaInput;
|
Loading…
Reference in New Issue
Block a user