antd#Mentions TypeScript Examples
The following examples show how to use
antd#Mentions.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utils.tsx From antdp with MIT License | 6 votes |
getItem = ({ attr, type, inputNode }: {
attr?: Partial<ItemChildAttr<any, any>>;
type?: ItemChildType;
inputNode?: ((...arg: any[]) => React.ReactNode) | React.ReactNode;
}) => {
let renderItem = undefined;
if (type === 'Input') {
const inputAttr = attr as InputProps;
renderItem = <Input {...inputAttr} />;
} else if (type === 'TextArea') {
const inputAttr = attr as TextAreaProps;
renderItem = <Input.TextArea {...inputAttr} />;
} else if (type === 'InputNumber') {
const inputAttr = attr as InputNumberProps;
renderItem = <InputNumber {...inputAttr} />;
} else if (type === 'AutoComplete') {
const inputAttr = attr as AutoCompleteProps;
renderItem = <AutoComplete {...inputAttr} />;
} else if (type === 'Cascader') {
const inputAttr = attr as CascaderProps;
renderItem = <Cascader {...inputAttr} />;
} else if (type === 'DatePicker') {
const inputAttr = attr as DatePickerProps;
renderItem = <DatePicker {...inputAttr} />;
} else if (type === 'Rate') {
const inputAttr = attr as RateProps;
renderItem = <Rate {...inputAttr} />;
} else if (type === 'Slider') {
const inputAttr = attr as SliderSingleProps;
renderItem = <Slider {...inputAttr} />;
} else if (type === 'TreeSelect') {
const inputAttr = attr as TreeSelectProps<any>;
renderItem = <TreeSelect {...inputAttr} />;
} else if (type === 'Select') {
const inputAttr = attr as SelectProps<any>;
renderItem = <Select {...inputAttr} />;
} else if (type === 'Checkbox') {
const inputAttr = attr as CheckboxGroupProps;
renderItem = <Checkbox.Group {...inputAttr} />;
} else if (type === 'Mentions') {
const inputAttr = attr as MentionProps;
renderItem = <Mentions {...inputAttr} />;
} else if (type === 'Radio') {
const inputAttr = attr as RadioProps;
renderItem = <Radio.Group {...inputAttr} />;
} else if (type === 'Switch') {
const inputAttr = attr as SwitchProps;
renderItem = <Switch {...inputAttr} />;
} else if (type === 'TimePicker') {
const inputAttr = attr as TimePickerProps;
renderItem = <TimePicker {...inputAttr} />;
} else if (type === 'Upload') {
const inputAttr = attr as UploadProps;
renderItem = <Upload {...inputAttr} />;
} else if (type === 'RangePicker') {
const inputAttr = attr as RangePickerProps;
renderItem = <RangePicker {...inputAttr} />;
} else if (type === 'Custom') {
renderItem = inputNode;
}
return renderItem;
}
Example #2
Source File: UploadImg.spec.tsx From next-basics with GNU General Public License v3.0 | 4 votes |
describe("UploadImg", () => {
it("should work", async () => {
const onChange = jest.fn();
const wrapper = mount(
<UploadImg
bucketName="agile"
value={{
text: "desc",
}}
listType="picture-card"
onChange={onChange}
showTextarea={true}
/>
);
expect(wrapper.find(Input.TextArea).text()).toBe("desc");
wrapper.find(Input.TextArea).invoke("onChange")({
target: {
value: "",
},
});
await Promise.resolve();
expect(onChange).toHaveBeenCalled();
message.error = jest.fn();
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "123",
size: 1234,
type: "application/json",
name: "json",
status: "done",
url: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png",
},
fileList: [...fileList],
});
const notImageResult = wrapper.find(Upload).invoke("beforeUpload")(
{
uid: "123",
size: 1234,
type: "application/json",
name: "json",
} as RcFile,
[...fileList]
);
await expect(notImageResult).rejects.toStrictEqual(
new Error("仅支持上传图片文件")
);
wrapper.setProps({
limitSize: 2,
});
const overLimitResult = wrapper.find(Upload).invoke("beforeUpload")(
{
uid: "123",
size: 1024 * 1024 * 3,
type: "image/png",
name: "png",
} as RcFile,
[...fileList]
);
await expect(overLimitResult).rejects.toStrictEqual(
new Error("上传文件体积大于限定体积")
);
const allowResult = wrapper.find(Upload).invoke("beforeUpload")(
{
uid: "123",
size: 1024 * 1024,
type: "image/png",
name: "png",
} as RcFile,
[...fileList]
);
await expect(allowResult).resolves.toMatchObject({
size: 1024 * 1024,
});
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "123",
size: 1234,
type: "image/png",
name: "image.png",
status: "done",
response: {
data: {
objectName: "image.png",
},
},
},
fileList: [...fileList],
});
expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "123",
size: 1234,
type: "image/png",
name: "image.png",
status: "removed",
response: {
data: {
objectName: "image.png",
},
},
},
fileList: [],
});
await jest.runAllTimers();
wrapper.update();
expect(wrapper.find(".ant-upload-list-item").length).toBe(0);
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "uploading",
response: {
data: {
objectName: "image.png",
},
},
},
fileList: [
...fileList,
{
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "uploading",
response: {
data: {
objectName: "image.png",
},
},
},
],
});
expect(wrapper.find(Upload).prop("disabled")).toBe(true);
wrapper.find(Input.TextArea).invoke("onPaste")({
clipboardData: {
items: [
{
getAsFile: jest.fn(
() => new File([], "xxx.json", { type: "application/json" })
),
},
],
},
});
expect(message.error).not.toBeCalledWith("还有附件正在上传,请稍候再试。");
wrapper.find(Input.TextArea).invoke("onPaste")({
clipboardData: {
items: [
{
getAsFile: jest.fn(
() => new File([], "xxx.png", { type: "image/png" })
),
},
],
},
});
expect(message.error).toBeCalledWith("还有附件正在上传,请稍候再试。");
await act(async () => {
wrapper.find(Upload).invoke("onPreview")({
size: 1024,
name: "123",
type: "image/png",
uid: "-3",
status: "done",
originFileObj: new File([], "xxx.png", { type: "image/png" }),
});
await (global as any).flushPromises();
});
wrapper.find(Upload).invoke("onPreview")({
uid: "123",
size: 1234,
type: "image/png",
name: "image",
status: "done",
url: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png",
});
expect(wrapper.find(Modal).prop("visible")).toBe(true);
wrapper.find(Modal).invoke("onCancel")({});
expect(wrapper.find(Modal).prop("visible")).toBe(false);
});
it("should work with empty value", async () => {
const onChange = jest.fn();
const wrapper = mount(
<UploadImg
listType="picture-card"
onChange={onChange}
bucketName="agile"
showTextarea={true}
/>
);
expect(wrapper.find(Input.TextArea).text()).toBe("");
await act(async () => {
message.error = jest.fn();
jest.spyOn(http, "put").mockRejectedValueOnce(new Error("http error"));
wrapper.find(Input.TextArea).invoke("onPaste")({
clipboardData: {
items: [
{
getAsFile: jest.fn(
() => new File([], "xxx.png", { type: "image/png" })
),
},
],
},
});
await (global as any).flushPromises();
});
expect(message.error).toHaveBeenCalled();
await act(async () => {
message.error = jest.fn();
jest.spyOn(http, "put").mockResolvedValueOnce({
data: {
objectName: "newImage.png",
},
});
wrapper.find(Input.TextArea).invoke("onPaste")({
clipboardData: {
items: [
{
getAsFile: jest.fn(
() => new File([], "newImage.png", { type: "image/png" })
),
},
],
},
});
await (global as any).flushPromises();
});
wrapper.update();
expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
});
it("test error", async () => {
const onChange = jest.fn();
const wrapper = mount(
<UploadImg
listType="picture-card"
onChange={onChange}
bucketName="agile"
showTextarea={true}
/>
);
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "uploading",
},
fileList: [
{
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "uploading",
},
],
});
wrapper.update();
expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "error",
},
fileList: [],
});
await act(async () => {
await jest.runAllTimers();
});
wrapper.update();
expect(wrapper.find(".ant-upload-list-item").length).toBe(0);
});
it("test set value by outside", async () => {
const onChange = jest.fn();
const wrapper = mount(
<UploadImg
listType="picture-card"
onChange={onChange}
bucketName="agile"
showTextarea={true}
/>
);
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "done",
},
fileList: [
{
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "done",
},
],
});
wrapper.update();
expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
wrapper.setProps({
value: {
images: [
{
url: "image2.png",
},
{
url: "image2.png",
},
],
},
});
await act(async () => {
await jest.runAllTimers();
});
wrapper.update();
expect(wrapper.find(".ant-upload-list-item").length).toBe(2);
});
it("test maxNumber and showTextarea", async () => {
const onChange = jest.fn();
const wrapper = mount(
<UploadImg
listType="picture-card"
onChange={onChange}
bucketName="agile"
maxNumber={1}
/>
);
await act(async () => {
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "done",
response: {
data: {
objectName: "image.png",
},
},
originFileObj: new File([], "image.png", { type: "image/png" }),
},
fileList: [
{
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "done",
response: {
data: {
objectName: "image.png",
},
},
originFileObj: new File([], "image.png", { type: "image/png" }),
},
],
});
await (global as any).flushPromises();
});
wrapper.update();
expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
expect(wrapper.find(".ant-upload-text").length).toBe(0);
wrapper.setProps({
maxNumber: 2,
value: {
images: [
{
url: "image2.png",
},
{
url: "image2.png",
},
],
},
});
await act(async () => {
await jest.runAllTimers();
});
wrapper.update();
expect(wrapper.find(".ant-upload-list-item").length).toBe(2);
expect(wrapper.find(Input.TextArea).length).toBe(0);
expect(wrapper.find(".ant-upload-text").length).toBe(0);
wrapper.setProps({
maxNumber: 3,
});
expect(wrapper.find(".ant-upload-text").length).toBe(1);
});
it("should work when listType is picture", async () => {
const onChange = jest.fn();
const wrapper = mount(
<UploadImg listType="picture" onChange={onChange} bucketName="agile" />
);
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "-img1",
size: 1024,
percent: 28,
type: "image/png",
name: "image.png",
status: "uploading",
},
fileList: [
{
uid: "-img1",
size: 1024,
percent: 28,
type: "image/png",
name: "image.png",
status: "uploading",
},
],
});
wrapper.update();
expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
expect(wrapper.find(".upload-file-main-info").length).toBe(1);
expect(wrapper.find(".upload-file-error-info").length).toBe(1);
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "done",
},
fileList: [
{
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "done",
},
],
});
await act(async () => {
await jest.runAllTimers();
});
wrapper.update();
expect(wrapper.find(".ant-upload-list-item").length).toBe(1);
expect(wrapper.find(".upload-file-main-info").length).toBe(1);
expect(wrapper.find(".upload-file-error-info").length).toBe(0);
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "error",
},
fileList: [
{
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "error",
},
],
});
await act(async () => {
await jest.runAllTimers();
});
wrapper.update();
expect(wrapper.find(".ant-upload-list-item").length).toBe(0);
expect(wrapper.find(".upload-file-main-info").length).toBe(0);
expect(wrapper.find(".upload-file-error-info").length).toBe(0);
});
it("test getPreview", async () => {
const onChange = jest.fn();
const wrapper = mount(
<UploadImg
listType="picture-card"
onChange={onChange}
bucketName="agile"
maxNumber={1}
getPreview={true}
/>
);
await act(async () => {
wrapper.find(Upload).invoke("onChange")({
file: {
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "done",
response: {
data: {
objectName: "image.png",
},
},
originFileObj: new File([], "image.png", { type: "image/png" }),
},
fileList: [
{
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "done",
response: {
data: {
objectName: "image.png",
},
},
originFileObj: new File([], "image.png", { type: "image/png" }),
},
],
});
await (global as any).flushPromises();
});
wrapper.update();
expect(onChange).toBeCalledWith({
images: [
{
name: "image.png",
preview: "data:image/png;base64,",
url: "api/gateway/object_store.object_store.GetObject/api/v1/objectStore/bucket/agile/object/image.png",
},
],
});
const wrapper2 = mount(
<UploadImg
listType="picture-card"
onChange={onChange}
bucketName="agile"
maxNumber={2}
getPreview={true}
/>
);
await act(async () => {
wrapper2.find(Upload).invoke("onChange")({
file: {
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "done",
response: {
data: {
objectName: "image.png",
},
},
originFileObj: new File([], "image.png", { type: "image/png" }),
},
fileList: [
{
uid: "-img1",
size: 1024,
type: "image/png",
name: "image.png",
status: "done",
response: {
data: {
objectName: "image.png",
},
},
originFileObj: new File([], "image.png", { type: "image/png" }),
},
],
});
await (global as any).flushPromises();
});
wrapper2.update();
expect(onChange).toBeCalledWith({
images: [
{
name: "image.png",
preview: "data:image/png;base64,",
url: "api/gateway/object_store.object_store.GetObject/api/v1/objectStore/bucket/agile/object/image.png",
},
],
});
});
it("should work when showMentions is true", async () => {
const onChange = jest.fn();
const wrapper = mount(
<UploadImg
listType="picture-card"
onChange={onChange}
bucketName="monitor"
showMentions={true}
hideUploadButton={true}
/>
);
await act(async () => {
await (global as any).flushPromises();
});
wrapper.update();
expect(wrapper.find(Mentions).length).toBe(1);
wrapper.find(Mentions).invoke("onChange")("123");
wrapper.update();
expect(onChange).toHaveBeenCalled();
wrapper.setProps({
showMentions: false,
});
expect(wrapper.find(Mentions).length).toBe(0);
});
it("should show dark icon", () => {
const spyOnUseCurrentTheme = jest
.spyOn(brickKit, "useCurrentTheme")
.mockReturnValue("dark-v2");
const wrapper = mount(
<UploadImg listType="picture" bucketName="monitor" uploadDraggable />
);
expect(wrapper.find(GeneralIcon).at(0).prop("icon")).toEqual({
category: "colored-common",
icon: "upload-dark",
lib: "easyops",
});
spyOnUseCurrentTheme.mockRestore();
});
});
Example #3
Source File: UploadImg.tsx From next-basics with GNU General Public License v3.0 | 4 votes |
export function RealUploadImg(
props: UploadImgProps,
ref: any
): React.ReactElement {
const { t } = useTranslation(NS_FORMS);
const action = `api/gateway/object_store.object_store.PutObject/api/v1/objectStore/bucket/${props.bucketName}/object`;
const [value, setValue] = React.useState(props.value);
const [imageList, setImageList] = useState(transformToImageList(props.value));
const [previewImage, setPreviewImage] = useState("");
const [previewVisible, setPreviewVisible] = useState(false);
const [disabled, setDisabled] = useState(false);
const [allUser, serAllUser] = useState<UserInfo[]>();
const theme = useCurrentTheme();
const buttonIcon: MenuIcon = {
lib: "easyops",
category: "colored-common",
icon: theme == "dark-v2" ? "upload-dark" : "upload-light",
};
React.useEffect(() => {
setValue(props.value);
const isDifferent = compareValues(props.value?.images, imageList);
if (isDifferent) {
setImageList(transformToImageList(props.value));
}
}, [props.value]);
React.useEffect(() => {
const getAllUser = async () => {
const userMap = await getRuntime().getAllUserMapAsync();
serAllUser([...userMap.values()]);
};
if (props.showMentions) {
getAllUser();
}
}, [props.showMentions]);
const transformResponseToUrl = (objectName: string) => {
const url = `api/gateway/object_store.object_store.GetObject/api/v1/objectStore/bucket/${props.bucketName}/object/${objectName}`;
return props.useFullUrlPath ? `/next/${url}` : `${url}`;
};
const handleValueChange = (v: UploadImgValue) => {
let newValue = { ...value, ...v };
if (
(newValue.text === "" || isNil(newValue.text)) &&
isEmpty(newValue.images)
) {
newValue = null;
}
setValue(newValue);
props.onChange?.(newValue);
};
const handleFilesChange = async (
newFile: ImageItem,
newFileList: ImageItem[],
isDone: boolean
): Promise<void> => {
if (isDone) {
if (props.maxNumber === 1) {
newFile.preview =
newFile.preview || (await getBase64(newFile.originFileObj));
setImageList([
{
...newFile,
},
]);
handleValueChange({
images: [
{
...(props.getPreview ? { preview: newFile.preview } : {}),
url: newFile.url,
name: newFile.name,
},
],
});
} else {
setImageList(
update(newFileList, {
[newFileList.length - 1]: { $set: newFile },
})
);
handleValueChange({
images: update(value?.images || [], {
$push: [
{
...(props.getPreview ? { preview: newFile.preview } : {}),
url: newFile.url,
name: newFile.name,
},
],
}),
});
}
} else {
if (props.maxNumber === 1) {
setImageList([{ ...newFile }]);
} else {
setImageList(newFileList);
}
}
};
const handlePreview = async (file: any): Promise<void> => {
if (!file.preview && file.originFileObj) {
file.preview = await getBase64(file.originFileObj);
}
setPreviewImage(file.preview || file.url);
setPreviewVisible(true);
};
const handleChange = ({
file,
fileList,
}: {
file: UploadFile;
fileList: UploadFile[];
}): void => {
if (some(fileList, ["status", "uploading"])) {
setDisabled(true);
} else {
setDisabled(false);
}
if (file.status === "removed") {
const index = findIndex(imageList, ["uid", file.uid]);
handleValueChange({
images: update(value.images, { $splice: [[index, 1]] }),
});
setImageList(fileList);
} else if (file.status === "error") {
setDisabled(false);
const index = findIndex(imageList, ["uid", file.uid]);
if (index !== -1) {
setImageList(update(imageList, { $splice: [[index, 1]] }));
}
message.error("上传文件失败");
} else {
if (file?.type.startsWith("image/")) {
handleFilesChange(file, [...fileList], false);
if (file.response && file.status === "done") {
file.url = transformResponseToUrl(file.response.data.objectName);
handleFilesChange(file, [...fileList], true);
}
} else {
setDisabled(false);
}
}
};
const handleCancel = (): void => {
setPreviewVisible(false);
};
const uploadButton = (): React.ReactElement => {
if (props.hideUploadButton && !props.uploadDraggable) {
return null;
}
if (props.uploadDraggable) {
return (
<>
<p className="ant-upload-drag-icon">
<GeneralIcon icon={buttonIcon} />
</p>
<p className="ant-upload-text">
{props.draggableUploadText ?? t(K.DRAGGABLE_UPLOAD_TEXT)}
</p>
<p className="ant-upload-hint">
{props.draggableUploadHint ?? t(K.DRAGGABLE_UPLOAD_HINT)}
</p>
</>
);
}
if (props.listType === "picture-card") {
return (
<div>
{props.maxNumber === 1 && disabled ? (
<LoadingOutlined />
) : theme === "dark-v2" ? (
<ImageUploadDark />
) : (
<ImageUpload />
)}
<div className="ant-upload-text" style={{ marginTop: "-8px" }}>
上传图片
</div>
</div>
);
} else {
return (
<Button>
<UploadOutlined /> Upload
</Button>
);
}
};
const uploadNode = (): React.ReactElement => {
return !props.maxNumber || imageList?.length < props.maxNumber
? uploadButton()
: null;
};
const filesPasted = (e): void => {
const items = e.clipboardData.items;
forEach(items, async (item) => {
const file = item.getAsFile();
if (file?.type.startsWith("image/")) {
if (
props.maxNumber &&
imageList?.length >= props.maxNumber &&
props.maxNumber !== 1
) {
message.error(`仅支持上传 ${props.maxNumber} 张图片`);
return;
}
if (disabled) {
message.error("还有附件正在上传,请稍候再试。");
return;
}
const fileInfo: any = {
originFileObj: file,
type: file.type,
name: file.name,
size: file.size,
lastModified: file.lastModified,
lastModifiedDate: file.lastModifiedDate,
uid: uniqueId("-img"),
status: "uploading",
percent: 0,
};
const oldList = cloneDeep(imageList);
handleFilesChange(fileInfo, [...oldList, fileInfo], false);
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
fileInfo.preview = reader.result as string;
fileInfo.percent = 100;
};
// 上传文件
setDisabled(true);
try {
const response = await ObjectStoreApi_putObject(props.bucketName, {
file: file,
});
fileInfo.status = "done";
fileInfo.url = transformResponseToUrl(response.objectName);
handleFilesChange(fileInfo, [...oldList, fileInfo], true);
setDisabled(false);
} catch (err) {
message.error("上传失败");
setImageList(oldList);
setDisabled(false);
}
}
});
};
const handleTextChange = (e: any): void => {
handleValueChange({
text: e.target.value,
});
};
const handleMentionsChange = (value: string): void => {
handleValueChange({
text: value,
});
};
const handleRemove = (e: any): void => {
props.onRemove?.(e);
};
const handleBeforeUpload = (file: RcFile): Promise<RcFile> => {
return new Promise((resolve, reject) => {
if (!file.type?.startsWith("image/")) {
message.error("仅支持上传图片文件");
reject(new Error("仅支持上传图片文件"));
}
if (FileUtils.sizeCompare(file, props.limitSize ?? 10)) {
message.error(`上传文件体积大于限定体积`);
reject(new Error("上传文件体积大于限定体积"));
}
resolve(file);
});
};
const fileInfoNode = (file: UploadFile): ReactNode => (
<>
<div className={styles["upload-file-main-info"]}>
<span className={styles["upload-file-name"]}>{file.name}</span>
<span className={styles["upload-file-size"]}>
{file.size &&
(file.status === "uploading"
? `${sizeFormat(file.size)} (${Math.floor(file.percent)}%Done)`
: sizeFormat(file.size))}
</span>
</div>
<div className={styles["upload-file-else-info"]}>
{(file.status === "error" || file.status === "uploading") && (
<span className={styles["upload-file-error-info"]}>
{file.status === "error" && "Wrong!"}
</span>
)}
</div>
</>
);
const cloneFileItemNode = (
node: ReactElement,
file: UploadFile
): ReactNode => {
const nodeChildren = React.Children.map(node?.props?.children, (child) => {
if (
child?.props?.className
?.split(" ")
?.includes("ant-upload-list-item-name")
) {
return React.cloneElement(child, null, fileInfoNode(file));
}
return cloneFileItemNode(child, file);
});
if (React.isValidElement(node)) {
// children是function额外处理
if (node?.props?.children instanceof Function)
return React.cloneElement(node, null, node.props.children);
return React.cloneElement(node, null, nodeChildren);
}
return node;
};
const textProps = {
progress: {
strokeColor: "#2FC25B",
trailColor: "var(--theme-gray-background)",
strokeWidth: "1px",
showInfo: false,
},
showUploadList: {
// eslint-disable-next-line react/display-name
removeIcon: (file: UploadFile): ReactNode =>
file.status === "error" ? (
<GeneralIcon
icon={{
lib: "antd",
theme: "outlined",
icon: "close",
}}
/>
) : (
<GeneralIcon
icon={{
lib: "easyops",
category: "default",
icon: "delete",
}}
/>
),
},
// eslint-disable-next-line react/display-name
iconRender: (file: UploadFile): ReactNode =>
file.status === "uploading" ? (
<LoadingOutlined />
) : (
<GeneralIcon
icon={{
lib: "antd",
icon: "file-text",
theme: "outlined",
}}
/>
),
};
const pictureProps = {
progress: {
strokeColor: "var(--color-brand)",
trailColor: "#FFF",
strokeWidth: "4px",
showInfo: false,
},
showUploadList: {
// eslint-disable-next-line react/display-name
removeIcon: (file: UploadFile): ReactNode =>
file.status === "error" ? (
<GeneralIcon
icon={{
lib: "antd",
theme: "outlined",
icon: "close",
}}
/>
) : (
<GeneralIcon
icon={{
lib: "easyops",
category: "default",
icon: "delete",
}}
/>
),
},
// eslint-disable-next-line react/display-name
itemRender: (originNode: ReactElement, file: UploadFile): ReactNode => {
return cloneFileItemNode(originNode, file);
},
};
let typeProps = {};
if (props.listType === "picture") {
typeProps = pictureProps;
} else if (props.listType === "text") {
typeProps = textProps;
}
const uploadProps = {
className: classNames({
[styles.uploadContainerDisplayNone]:
props.uploadDraggable &&
props.maxNumber &&
imageList?.length >= props.maxNumber,
}),
method: "put",
action,
listType: props.listType,
fileList: imageList,
onPreview: handlePreview,
onChange: handleChange,
onRemove: handleRemove,
beforeUpload: handleBeforeUpload,
supportServerRender: true,
disabled,
};
return (
<div ref={ref} className={styles.uploadContainer}>
{props.showTextarea && (
<Input.TextArea
onPaste={(e) => filesPasted(e)}
onChange={handleTextChange}
className={styles.textContainer}
value={value?.text || ""}
placeholder={props.placeholder}
autoSize={props.autoSize}
/>
)}
{props.showMentions && !props.showTextarea && (
<Mentions
rows={2}
onChange={handleMentionsChange}
value={value?.text || ""}
autoSize={props.autoSize}
className={styles.textContainer}
onPaste={(e) => filesPasted(e)}
placeholder={props.placeholder}
>
{allUser &&
allUser.map((item) => (
<Mentions.Option value={item.name} key={item.name}>
<Avatar
src={item.user_icon}
size={24}
className={classNames(styles.avatar, {
[styles.defaultIcon]: !item.user_icon,
})}
>
{!item.user_icon && item.name?.slice(0, 2)}
</Avatar>
{item.name}
</Mentions.Option>
))}
</Mentions>
)}
{props.uploadDraggable ? (
<Upload.Dragger {...uploadProps}>{uploadNode()}</Upload.Dragger>
) : (
<Upload {...uploadProps} {...typeProps}>
{uploadNode()}
</Upload>
)}
<Modal visible={previewVisible} footer={null} onCancel={handleCancel}>
<img alt="example" style={{ width: "100%" }} src={previewImage} />
</Modal>
</div>
);
}
Example #4
Source File: logic.block.tsx From ui with GNU Affero General Public License v3.0 | 4 votes |
LogicBlock: React.FC<Props> = ({
form,
field,
fields,
remove,
index,
}) => {
const { t } = useTranslation()
const evaluator = useMath()
return (
<div
style={{
borderRight: '5px solid #DDD',
paddingRight: 10,
}}
>
<Form.Item
name={[field.name as string, 'formula']}
labelCol={{ span: 6 }}
label={'Formula'}
rules={[{ required: true, message: 'combine other fields' }]}
extra={'Save form to get new @IDs and $slugs. (example: $slug < 21 or @id = 42)'}
>
<Mentions rows={1}>
{fields.map((field) => (
<Mentions.Option key={field.id} value={field.id}>
{field.title}
</Mentions.Option>
))}
</Mentions>
</Form.Item>
<Form.Item noStyle shouldUpdate>
{(form: FormInstance & { prefixName: string[] }) => {
try {
const defaults = {}
fields.forEach((field) => {
defaults[`@${field.id}`] = field.defaultValue
if (field.slug) {
defaults[`$${field.slug}`] = field.defaultValue
}
})
const result = evaluator(
form.getFieldValue([
...form.prefixName,
field.name as string,
'formula',
]),
defaults
)
return (
<Alert
type={result ? 'success' : 'warning'}
message={
result
? 'would trigger action with current default values'
: 'would NOT trigger action with current default values'
}
style={{ marginBottom: 24 }}
/>
)
} catch (e) {
return (
<Alert
message={(e as Error).message || 'Failed to process formula'}
type={'error'}
style={{ marginBottom: 24 }}
/>
)
}
}}
</Form.Item>
<Form.Item name={[field.name as string, 'action']} labelCol={{ span: 6 }} label={'Action'}>
<Select
options={[
{
value: 'jumpTo',
label: t('form:logic.action.jumpTo'),
},
{
value: 'visible',
label: t('form:logic.action.visible'),
},
{
value: 'disable',
label: t('form:logic.action.disable'),
},
{
value: 'require',
label: t('form:logic.action.require'),
},
]}
/>
</Form.Item>
<Form.Item noStyle shouldUpdate>
{(form: FormInstance & { prefixName: string[] }) => {
return (
<Form.Item
hidden={
form.getFieldValue([
...form.prefixName, field.name as string, 'action',
]) !==
'jumpTo'
}
labelCol={{ span: 6 }}
label={t('form:logic.action.jumpTo')}
rules={[{ required: true, message: 'Jump target is required' }]}
extra={'after selecting field (works best with clickable values)'}
>
<Select
options={fields
.filter((field) => !/NEW/i.test(field.id))
.map((field) => ({
value: field.id,
label: field.title,
}))}
/>
</Form.Item>
)
}}
</Form.Item>
<Form.Item noStyle shouldUpdate>
{(form: FormInstance & { prefixName: string[] }) => {
return (
<Form.Item
hidden={
form.getFieldValue([
...form.prefixName, field.name as string, 'action',
]) !==
'visible'
}
initialValue={true}
labelCol={{ span: 6 }}
label={t('form:logic.action.visible')}
valuePropName={'checked'}
getValueFromEvent={(checked: boolean) => (checked ? '1' : '')}
getValueProps={(e: string) => ({ checked: !!e })}
>
<Checkbox />
</Form.Item>
)
}}
</Form.Item>
<Form.Item noStyle shouldUpdate>
{(form: FormInstance & { prefixName: string[] }) => {
return (
<Form.Item
hidden={
form.getFieldValue([
...form.prefixName, field.name as string, 'action',
]) !==
'disable'
}
initialValue={false}
labelCol={{ span: 6 }}
label={t('form:logic.action.disable')}
valuePropName={'checked'}
getValueFromEvent={(checked: boolean) => (checked ? '1' : '')}
getValueProps={(e: string) => ({ checked: !!e })}
>
<Checkbox />
</Form.Item>
)
}}
</Form.Item>
<Form.Item noStyle shouldUpdate>
{(form: FormInstance & { prefixName: string[] }) => {
return (
<Form.Item
hidden={
form.getFieldValue([
...form.prefixName, field.name as string, 'action',
]) !==
'require'
}
initialValue={true}
labelCol={{ span: 6 }}
label={t('form:logic.action.require')}
valuePropName={'checked'}
getValueFromEvent={(checked: boolean) => (checked ? '1' : '')}
getValueProps={(e: string) => ({ checked: !!e })}
>
<Checkbox />
</Form.Item>
)
}}
</Form.Item>
<Form.Item>
<div style={{ textAlign: 'right' }}>
<Popconfirm
placement={'right'}
title={t('type:confirmDelete')}
okText={t('type:deleteNow')}
okButtonProps={{ danger: true }}
onConfirm={() => {
remove(index)
}}
>
<Button danger>
<DeleteOutlined />
</Button>
</Popconfirm>
</div>
</Form.Item>
</div>
)
}