From 3d672ffa9e8b2d7de595420cf7012f15909474fd Mon Sep 17 00:00:00 2001
From: mou <10402885@qq.com>
Date: Tue, 1 Aug 2023 16:22:17 +0800
Subject: [PATCH 1/2] Add mention component
---
.../src/icons/icon-mention-comp.svg | 1 +
.../lowcoder-design/src/icons/index.ts | 3 +-
.../comps/comps/textInputComp/mentionComp.tsx | 268 ++++++++++++++++++
.../textInputComp/textInputConstants.tsx | 12 +
.../comps/controls/eventHandlerControl.tsx | 5 +
client/packages/lowcoder/src/comps/index.tsx | 11 +
.../lowcoder/src/comps/uiCompRegistry.ts | 1 +
.../packages/lowcoder/src/i18n/locales/en.ts | 10 +-
.../packages/lowcoder/src/i18n/locales/zh.ts | 10 +-
.../src/pages/editor/editorConstants.tsx | 2 +
10 files changed, 320 insertions(+), 3 deletions(-)
create mode 100644 client/packages/lowcoder-design/src/icons/icon-mention-comp.svg
create mode 100644 client/packages/lowcoder/src/comps/comps/textInputComp/mentionComp.tsx
diff --git a/client/packages/lowcoder-design/src/icons/icon-mention-comp.svg b/client/packages/lowcoder-design/src/icons/icon-mention-comp.svg
new file mode 100644
index 000000000..4c04c61e2
--- /dev/null
+++ b/client/packages/lowcoder-design/src/icons/icon-mention-comp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/client/packages/lowcoder-design/src/icons/index.ts b/client/packages/lowcoder-design/src/icons/index.ts
index dd55eb897..b51898abc 100644
--- a/client/packages/lowcoder-design/src/icons/index.ts
+++ b/client/packages/lowcoder-design/src/icons/index.ts
@@ -288,4 +288,5 @@ export { ReactComponent as ExpandIcon } from "icons/icon-expand.svg";
export { ReactComponent as CompressIcon } from "icons/icon-compress.svg";
export { ReactComponent as TableCellsIcon } from "icons/icon-table-cells.svg"; // Added By Aqib Mirza
export { ReactComponent as TimeLineIcon } from "icons/icon-timeline-comp.svg"
-export { ReactComponent as LottieIcon } from "icons/icon-lottie.svg";
\ No newline at end of file
+export { ReactComponent as LottieIcon } from "icons/icon-lottie.svg";
+export { ReactComponent as MentionIcon } from "icons/icon-mention-comp.svg";
\ No newline at end of file
diff --git a/client/packages/lowcoder/src/comps/comps/textInputComp/mentionComp.tsx b/client/packages/lowcoder/src/comps/comps/textInputComp/mentionComp.tsx
new file mode 100644
index 000000000..f4fe60cf5
--- /dev/null
+++ b/client/packages/lowcoder/src/comps/comps/textInputComp/mentionComp.tsx
@@ -0,0 +1,268 @@
+import { useState, useEffect } from "react";
+import {
+ NameConfig,
+ NameConfigPlaceHolder,
+ NameConfigRequired,
+ withExposingConfigs,
+} from "comps/generators/withExposing";
+import { Section, sectionNames } from "lowcoder-design";
+import { BoolControl } from "../../controls/boolControl";
+import { AutoHeightControl } from "../../controls/autoHeightControl";
+import { UICompBuilder } from "../../generators";
+import { FormDataPropertyView } from "../formComp/formDataConstants";
+import {
+ checkMentionListData,
+ textInputChildren,
+} from "./textInputConstants";
+import {
+ withMethodExposing,
+ refMethods,
+} from "../../generators/withMethodExposing";
+import { styleControl } from "comps/controls/styleControl";
+import styled from "styled-components";
+import {
+ InputLikeStyle,
+ InputLikeStyleType,
+} from "comps/controls/styleControlConstants";
+import {
+ disabledPropertyView,
+ hiddenPropertyView,
+ maxLengthPropertyView,
+ minLengthPropertyView,
+ readOnlyPropertyView,
+ requiredPropertyView,
+} from "comps/utils/propertyUtils";
+import { booleanExposingStateControl } from "comps/controls/codeStateControl";
+import { trans } from "i18n";
+import { RefControl } from "comps/controls/refControl";
+import { TextAreaRef } from "antd/lib/input/TextArea";
+import { Mentions, ConfigProvider } from "antd";
+import { blurMethod, focusWithOptions } from "comps/utils/methodUtils";
+import type { MentionsOptionProps } from "antd/es/mentions";
+import {
+ textInputValidate,
+} from "../textInputComp/textInputConstants";
+import { jsonControl } from "@lowcoder-ee/comps/controls/codeControl";
+// 事件控制
+import {
+ submitEvent,
+ eventHandlerControl,
+ mentionEvent,
+ focusEvent,
+ blurEvent,
+ changeEvent
+} from "comps/controls/eventHandlerControl";
+
+const Wrapper = styled.div<{
+ $style: InputLikeStyleType;
+}>`
+ height: 100%;
+
+ .ant-input-clear-icon {
+ opacity: 0.45;
+ color: ${(props) => props.$style.text};
+ top: 10px;
+
+ &:hover {
+ opacity: 0.65;
+ color: ${(props) => props.$style.text};
+ }
+ }
+`;
+
+const EventOptions = [
+ focusEvent,
+ blurEvent,
+ changeEvent,
+ mentionEvent,
+ submitEvent,
+] as const;
+
+let MentionTmpComp = (function () {
+ const childrenMap = {
+ ...textInputChildren,
+ viewRef: RefControl,
+ allowClear: BoolControl,
+ autoHeight: AutoHeightControl,
+ style: styleControl(InputLikeStyle),
+ mentionList: jsonControl(checkMentionListData, {
+ "@": ["Li Lei", "Han Meimei"],
+ "#": ["123", "456", "789"],
+ }),
+ onEvent: eventHandlerControl(EventOptions),
+ invalid: booleanExposingStateControl("invalid"),
+ };
+
+ return new UICompBuilder(childrenMap, (props) => {
+ const { mentionList } = props;
+ const [validateState, setvalidateState] = useState({});
+ const [activationFlag, setActivationFlag] = useState(false);
+ const [prefix, setPrefix] = useState("@");
+ type PrefixType = "@" | keyof typeof mentionList;
+
+ // 获取提及搜索关键字
+ const onSearch = (_: string, newPrefix: PrefixType) => {
+ setPrefix(newPrefix);
+ };
+ const onChange = (value: string) => {
+ props.value.onChange(value);
+ props.onEvent("change");
+ };
+
+ const onPressEnter = (e: any) => {
+ if (e.shiftKey) {
+ e.preventDefault();
+ props.onEvent("submit");
+ }
+ };
+
+ const onSelect = (option: MentionsOptionProps) => {
+ props.onEvent("mention");
+ };
+ const getValidate = (value: any): "" | "warning" | "error" | undefined => {
+ if (
+ value.hasOwnProperty("validateStatus") &&
+ value["validateStatus"] === "error"
+ )
+ return "error";
+ return "";
+ };
+
+ const getTextInputValidate = () => {
+ return {
+ value: { value: props.value.value },
+ required: props.required,
+ minLength: props?.minLength ?? 0,
+ maxLength: props?.maxLength ?? 0,
+ validationType: props.validationType,
+ regex: props.regex,
+ customRule: props.customRule,
+ };
+ };
+
+ useEffect(() => {
+ if (activationFlag) {
+ const temp = textInputValidate(getTextInputValidate());
+ setvalidateState(temp);
+ props.invalid.onChange(temp.validateStatus !== "");
+ }
+ }, [
+ props.value.value,
+ props.required,
+ props?.minLength,
+ props?.maxLength,
+ props.validationType,
+ props.regex,
+ props.customRule,
+ ]);
+ return props.label({
+ required: props.required,
+ children: (
+
+
+ {
+ setActivationFlag(true);
+ props.onEvent("focus");
+ }}
+ onBlur={() => props.onEvent("blur")}
+ onPressEnter={onPressEnter}
+ onSearch={onSearch}
+ onChange={onChange}
+ onSelect={onSelect}
+ placeholder={props.placeholder}
+ value={props.value.value}
+ disabled={props.disabled}
+ status={getValidate(validateState)}
+ options={(mentionList[prefix] || []).map((value: string) => ({
+ key: value,
+ value,
+ label: value,
+ }))}
+ autoSize={props.autoHeight}
+ style={{ height: "100%", maxHeight: "100%", resize: "none" }}
+ readOnly={props.readOnly}
+ />
+
+
+ ),
+ style: props.style,
+ ...validateState,
+ });
+ })
+ .setPropertyViewFn((children) => (
+ <>
+
+ {children.mentionList.propertyView({
+ label: trans("mention.mentionList"),
+ })}
+ {children.value.propertyView({ label: trans("prop.defaultValue") })}
+ {children.placeholder.propertyView({
+ label: trans("prop.placeholder"),
+ })}
+
+
+ {children.label.getPropertyView()}
+
+
+ {children.onEvent.getPropertyView()}
+ {disabledPropertyView(children)}
+
+
+
+ {readOnlyPropertyView(children)}
+
+
+
+ {requiredPropertyView(children)}
+ {children.validationType.propertyView({
+ label: trans("prop.textType"),
+ })}
+ {minLengthPropertyView(children)}
+ {maxLengthPropertyView(children)}
+ {children.customRule.propertyView({})}
+
+
+
+ {children.autoHeight.getPropertyView()}
+ {hiddenPropertyView(children)}
+
+
+
+ {children.style.getPropertyView()}
+
+ >
+ ))
+ .build();
+})();
+
+MentionTmpComp = class extends MentionTmpComp {
+ override autoHeight(): boolean {
+ return this.children.autoHeight.getView();
+ }
+};
+
+const TextareaTmp2Comp = withMethodExposing(
+ MentionTmpComp,
+ refMethods([focusWithOptions, blurMethod])
+);
+
+export const MentionComp = withExposingConfigs(TextareaTmp2Comp, [
+ new NameConfig("value", trans("export.inputValueDesc")),
+ NameConfigPlaceHolder,
+ NameConfigRequired,
+ new NameConfig("invalid", trans("export.invalidDesc")),
+ new NameConfig("hidden", trans("export.hiddenDesc")),
+ new NameConfig("disabled", trans("export.disabledDesc")),
+]);
diff --git a/client/packages/lowcoder/src/comps/comps/textInputComp/textInputConstants.tsx b/client/packages/lowcoder/src/comps/comps/textInputComp/textInputConstants.tsx
index f6bdabe60..9b1e76fd7 100644
--- a/client/packages/lowcoder/src/comps/comps/textInputComp/textInputConstants.tsx
+++ b/client/packages/lowcoder/src/comps/comps/textInputComp/textInputConstants.tsx
@@ -1,4 +1,5 @@
import { BoolControl } from "comps/controls/boolControl";
+import { check } from "util/convertUtils";
import {
BoolCodeControl,
CustomRuleControl,
@@ -268,3 +269,14 @@ export const inputRefMethods = [
(comp.children.viewRef.viewRef?.input?.setRangeText as any)?.(...params),
},
];
+
+export function checkMentionListData(data: any) {
+ if(data === "") return {}
+ for(const key in data) {
+ check(data[key], ["array"], key,(node)=>{
+ check(node, ["string"], );
+ return node
+ })
+ }
+ return data
+}
diff --git a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx
index f940759f9..426357c92 100644
--- a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx
+++ b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx
@@ -305,6 +305,11 @@ export const successEvent: EventConfigType = {
value: "success",
description: trans("event.successDesc"),
};
+export const mentionEvent: EventConfigType = {
+ label: trans("event.mention"),
+ value: "mention",
+ description: trans("event.mentionDesc"),
+};
export const InputEventHandlerControl = eventHandlerControl([
changeEvent,
diff --git a/client/packages/lowcoder/src/comps/index.tsx b/client/packages/lowcoder/src/comps/index.tsx
index e2bdd418c..746fde17a 100644
--- a/client/packages/lowcoder/src/comps/index.tsx
+++ b/client/packages/lowcoder/src/comps/index.tsx
@@ -93,6 +93,7 @@ import {
VideoCompIcon,
TimeLineIcon,
LottieIcon,
+ MentionIcon,
} from "lowcoder-design";
import { defaultFormData, FormComp } from "./comps/formComp/formComp";
@@ -119,6 +120,7 @@ import { RemoteCompInfo } from "types/remoteComp";
import { ScannerComp } from "./comps/buttonComp/scannerComp";
import { SignatureComp } from "./comps/signatureComp";
import { TimeLineComp } from "./comps/timelineComp/timelineComp";
+import { MentionComp } from "./comps/textInputComp/mentionComp";
//Added by Aqib Mirza
import { JsonLottieComp } from "./comps/jsonComp/jsonLottieComp";
@@ -855,6 +857,15 @@ const uiCompMap: Registry = {
h: 55,
},
},
+ mention: {
+ name: trans("uiComp.mentionCompName"),
+ enName: "mention",
+ description: trans("uiComp.mentionCompDesc"),
+ categories: ["dataInputText"],
+ icon: MentionIcon,
+ keywords: trans("uiComp.mentionCompKeywords"),
+ comp: MentionComp,
+ },
};
export function loadComps() {
diff --git a/client/packages/lowcoder/src/comps/uiCompRegistry.ts b/client/packages/lowcoder/src/comps/uiCompRegistry.ts
index bba81c125..ccdae86ac 100644
--- a/client/packages/lowcoder/src/comps/uiCompRegistry.ts
+++ b/client/packages/lowcoder/src/comps/uiCompRegistry.ts
@@ -112,6 +112,7 @@ export type UICompType =
| "signature"
| "jsonLottie" //Added By Aqib Mirza
| "timeline"
+ | "mention"
export const uiCompRegistry = {} as Record;
diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts
index 160955098..0339b7d1e 100644
--- a/client/packages/lowcoder/src/i18n/locales/en.ts
+++ b/client/packages/lowcoder/src/i18n/locales/en.ts
@@ -262,6 +262,8 @@ export const en = {
parseDesc: "Triggers on parse",
success: "Success",
successDesc: "Triggers on success",
+ mention: "mention",
+ mentionDesc: "Triggers on mention",
},
themeDetail: {
primary: "Brand color",
@@ -845,6 +847,9 @@ export const en = {
timelineCompName: "Time Line",
timelineCompDesc: "Time Line",
timelineCompKeywords: "",
+ mentionCompName: "mention",
+ mentionCompDesc: "mention",
+ mentionCompKeywords: "",
},
comp: {
menuViewDocs: "View documentation",
@@ -2467,5 +2472,8 @@ export const en = {
valueDesc: "data of timeline",
clickedObjectDesc: "clicked item data",
clickedIndexDesc: "clicked item index",
- }
+ },
+ mention:{
+ mentionList: "mention list",
+ },
};
diff --git a/client/packages/lowcoder/src/i18n/locales/zh.ts b/client/packages/lowcoder/src/i18n/locales/zh.ts
index f92dff893..708f41ccf 100644
--- a/client/packages/lowcoder/src/i18n/locales/zh.ts
+++ b/client/packages/lowcoder/src/i18n/locales/zh.ts
@@ -258,7 +258,9 @@ event: {
parse: "解析",
parseDesc: "在解析时触发",
success: "成功",
- successDesc: "在成功时触发"
+ successDesc: "在成功时触发",
+ mention: "提及",
+ mentionDesc: "在提及时触发",
},
themeDetail: {
primary: "颜色主题",
@@ -828,6 +830,9 @@ uiComp: {
timelineCompName: "时间线",
timelineCompDesc: "时间线组件",
timelineCompKeywords: "sjx",
+ mentionCompName: "提及",
+ mentionCompDesc: "提及组件",
+ mentionCompKeywords: "tj",
},
comp: {
menuViewDocs: "查看文档",
@@ -2458,5 +2463,8 @@ timeLine: {
endlessLoop: "循环播放",
keepLastFrame: "冻结最后一帧",
},
+ mention:{
+ mentionList: "提及列表",
+ },
};
diff --git a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx
index 7e23f6d99..0e5eb27ba 100644
--- a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx
+++ b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx
@@ -37,6 +37,7 @@ import {
LeftVideo,
LeftSignature,
TimeLineIcon,
+ MentionIcon,
} from "lowcoder-design";
export const CompStateIcon: {
@@ -103,4 +104,5 @@ export const CompStateIcon: {
signature: ,
jsonLottie: , //Added By Aqib Mirza
timeline: ,
+ mention: ,
};
From 13c9647f2bf7a644e7fdedf8253429e28eb1b9e3 Mon Sep 17 00:00:00 2001
From: Aqib Mirza
Date: Mon, 7 Aug 2023 15:19:48 +0530
Subject: [PATCH 2/2] fix: design fixes
---
.../lowcoder/src/comps/comps/textInputComp/mentionComp.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/client/packages/lowcoder/src/comps/comps/textInputComp/mentionComp.tsx b/client/packages/lowcoder/src/comps/comps/textInputComp/mentionComp.tsx
index f4fe60cf5..9184ce39d 100644
--- a/client/packages/lowcoder/src/comps/comps/textInputComp/mentionComp.tsx
+++ b/client/packages/lowcoder/src/comps/comps/textInputComp/mentionComp.tsx
@@ -191,7 +191,7 @@ let MentionTmpComp = (function () {
label: value,
}))}
autoSize={props.autoHeight}
- style={{ height: "100%", maxHeight: "100%", resize: "none" }}
+ style={{ height: "100%", maxHeight: "100%", resize: "none", padding: props.style.padding }}
readOnly={props.readOnly}
/>