diff --git a/client/packages/lowcoder-design/src/components/iconSelect/index.tsx b/client/packages/lowcoder-design/src/components/iconSelect/index.tsx
index eaae8bfe5..ac3264aa2 100644
--- a/client/packages/lowcoder-design/src/components/iconSelect/index.tsx
+++ b/client/packages/lowcoder-design/src/components/iconSelect/index.tsx
@@ -1,16 +1,24 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import type { IconDefinition } from "@fortawesome/free-regular-svg-icons";
-import { default as Popover } from "antd/es/popover";
-import { ActionType } from '@rc-component/trigger/lib/interface';
+import { Popover } from "antd";
+import { ActionType } from "@rc-component/trigger/lib/interface";
import { TacoInput } from "components/tacoInput";
import { Tooltip } from "components/toolTip";
import { trans } from "i18n/design";
import _ from "lodash";
-import { ReactNode, useEffect, useCallback, useMemo, useRef, useState } from "react";
+import {
+ ReactNode,
+ useEffect,
+ useCallback,
+ useMemo,
+ useRef,
+ useState,
+} from "react";
import Draggable from "react-draggable";
import { default as List, ListRowProps } from "react-virtualized/dist/es/List";
import styled from "styled-components";
import { CloseIcon, SearchIcon } from "icons";
+import { ANTDICON } from "../../../../lowcoder/src/comps/comps/timelineComp/antIcon";
const PopupContainer = styled.div`
width: 408px;
@@ -110,11 +118,23 @@ const IconItemContainer = styled.div`
class Icon {
readonly title: string;
- constructor(readonly def: IconDefinition, readonly names: string[]) {
- this.title = def.iconName.split("-").map(_.upperFirst).join(" ");
+ constructor(readonly def: IconDefinition | any, readonly names: string[]) {
+ if (def?.iconName) {
+ this.title = def.iconName.split("-").map(_.upperFirst).join(" ");
+ } else {
+ this.title = names[0].slice(5);
+ this.def = def;
+ }
}
getView() {
- return ;
+ if (this.names[0]?.startsWith("antd/")) return this.def;
+ else
+ return (
+
+ );
}
}
@@ -144,6 +164,13 @@ async function getAllIcons() {
}
}
}
+ //append ant icon
+ for (let key of Object.keys(ANTDICON)) {
+ ret["antd/" + key] = new Icon(
+ ANTDICON[key.toLowerCase() as keyof typeof ANTDICON],
+ ["antd/" + key]
+ );
+ }
allIcons = ret;
return ret;
}
@@ -151,7 +178,11 @@ async function getAllIcons() {
export const iconPrefix = "/icon:";
export function removeQuote(value?: string) {
- return value ? (value.startsWith('"') && value.endsWith('"') ? value.slice(1, -1) : value) : "";
+ return value
+ ? value.startsWith('"') && value.endsWith('"')
+ ? value.slice(1, -1)
+ : value
+ : "";
}
function getIconKey(value?: string) {
@@ -171,7 +202,8 @@ export function useIcon(value?: string) {
function search(
allIcons: Record,
searchText: string,
- searchKeywords?: Record
+ searchKeywords?: Record,
+ IconType?: "OnlyAntd" | "All" | "default" | undefined
) {
const tokens = searchText
.toLowerCase()
@@ -182,6 +214,8 @@ function search(
if (icon.names.length === 0) {
return false;
}
+ if (IconType === "OnlyAntd" && !key.startsWith("antd/")) return false;
+ if (IconType === "default" && key.startsWith("antd/")) return false;
let text = icon.names
.flatMap((name) => [name, searchKeywords?.[name]])
.filter((t) => t)
@@ -198,16 +232,20 @@ const IconPopup = (props: {
label?: ReactNode;
onClose: () => void;
searchKeywords?: Record;
+ IconType?: "OnlyAntd" | "All" | "default" | undefined;
}) => {
const [searchText, setSearchText] = useState("");
const [allIcons, setAllIcons] = useState>({});
const searchResults = useMemo(
- () => search(allIcons, searchText, props.searchKeywords),
+ () => search(allIcons, searchText, props.searchKeywords, props.IconType),
[searchText, allIcons]
);
const onChangeRef = useRef(props.onChange);
onChangeRef.current = props.onChange;
- const onChangeIcon = useCallback((key: string) => onChangeRef.current(iconPrefix + key), []);
+ const onChangeIcon = useCallback(
+ (key: string) => onChangeRef.current(iconPrefix + key),
+ []
+ );
const columnNum = 8;
useEffect(() => {
@@ -217,24 +255,26 @@ const IconPopup = (props: {
const rowRenderer = useCallback(
(p: ListRowProps) => (
- {searchResults.slice(p.index * columnNum, (p.index + 1) * columnNum).map(([key, icon]) => (
-
- {
- onChangeIcon(key);
- }}
+ {searchResults
+ .slice(p.index * columnNum, (p.index + 1) * columnNum)
+ .map(([key, icon]) => (
+
- {icon.getView()}
-
-
- ))}
+ {
+ onChangeIcon(key);
+ }}
+ >
+ {icon.getView()}
+
+
+ ))}
),
[searchResults, allIcons, onChangeIcon]
@@ -279,6 +319,7 @@ export const IconSelectBase = (props: {
leftOffset?: number;
parent?: HTMLElement | null;
searchKeywords?: Record;
+ IconType?: "OnlyAntd" | "All" | "default" | undefined;
}) => {
const { setVisible, parent } = props;
return (
@@ -290,7 +331,11 @@ export const IconSelectBase = (props: {
onOpenChange={setVisible}
getPopupContainer={parent ? () => parent : undefined}
// hide the original background when dragging the popover is allowed
- overlayInnerStyle={{ border: "none", boxShadow: "none", background: "transparent" }}
+ overlayInnerStyle={{
+ border: "none",
+ boxShadow: "none",
+ background: "transparent",
+ }}
// when dragging is allowed, always re-location to avoid the popover exceeds the screen
destroyTooltipOnHide
content={
@@ -299,6 +344,7 @@ export const IconSelectBase = (props: {
label={props.label}
onClose={() => setVisible?.(false)}
searchKeywords={props.searchKeywords}
+ IconType={props.IconType}
/>
}
>
@@ -312,6 +358,7 @@ export const IconSelect = (props: {
label?: ReactNode;
children?: ReactNode;
searchKeywords?: Record;
+ IconType?: "OnlyAntd" | "All" | "default" | undefined;
}) => {
const [visible, setVisible] = useState(false);
return (
diff --git a/client/packages/lowcoder-design/src/icons/IconCompIcon.svg b/client/packages/lowcoder-design/src/icons/IconCompIcon.svg
new file mode 100644
index 000000000..ce549b56c
--- /dev/null
+++ b/client/packages/lowcoder-design/src/icons/IconCompIcon.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 938cd1fc4..662c4b0ed 100644
--- a/client/packages/lowcoder-design/src/icons/index.ts
+++ b/client/packages/lowcoder-design/src/icons/index.ts
@@ -278,6 +278,28 @@ export { ReactComponent as SignatureIcon } from "./icon-signature.svg";
export { ReactComponent as ManualIcon } from "./icon-manual.svg";
export { ReactComponent as WarnIcon } from "./icon-warn.svg";
export { ReactComponent as SyncManualIcon } from "./icon-sync-manual.svg";
+
+export { ReactComponent as DangerIcon } from "icons/icon-danger.svg";
+export { ReactComponent as TableMinusIcon } from "icons/icon-table-minus.svg";
+export { ReactComponent as TablePlusIcon } from "icons/icon-table-plus.svg";
+export { ReactComponent as MobileAppIcon } from "icons/icon-mobile-app.svg";
+export { ReactComponent as MobileNavIcon } from "icons/icon-navigation-mobile.svg";
+export { ReactComponent as PcNavIcon } from "icons/icon-navigation-pc.svg";
+export { ReactComponent as UnLockIcon } from "icons/icon-unlock.svg";
+export { ReactComponent as CalendarDeleteIcon } from "icons/icon-calendar-delete.svg";
+export { ReactComponent as TableCheckedIcon } from "icons/icon-table-checked.svg";
+export { ReactComponent as TableUnCheckedIcon } from "icons/icon-table-boolean-false.svg";
+export { ReactComponent as FileFolderIcon } from "icons/icon-editor-folder.svg";
+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";
+export { ReactComponent as MentionIcon } from "icons/icon-mention-comp.svg";
+export { ReactComponent as AutoCompleteCompIcon } from "icons/icon-autocomplete-comp.svg";
+
+export { ReactComponent as IconCompIcon } from "icons/IconCompIcon.svg";
+
export { ReactComponent as DangerIcon } from "./icon-danger.svg";
export { ReactComponent as TableMinusIcon } from "./icon-table-minus.svg";
export { ReactComponent as TablePlusIcon } from "./icon-table-plus.svg";
@@ -612,4 +634,5 @@ export { ReactComponent as MentionIcon } from "./icon-mention-comp.svg";
export { ReactComponent as AutoCompleteCompIcon } from "./icon-autocomplete-comp.svg";
export { ReactComponent as WidthIcon } from "./icon-width.svg";
export { ReactComponent as ResponsiveLayoutCompIcon } from "./remix/layout-column-line.svg"; // Closest match for responsive layout component
-export { ReactComponent as TextSizeIcon } from "./icon-text-size.svg"; */
\ No newline at end of file
+export { ReactComponent as TextSizeIcon } from "./icon-text-size.svg"; */
+
diff --git a/client/packages/lowcoder/src/comps/comps/iconComp.tsx b/client/packages/lowcoder/src/comps/comps/iconComp.tsx
new file mode 100644
index 000000000..41b73da71
--- /dev/null
+++ b/client/packages/lowcoder/src/comps/comps/iconComp.tsx
@@ -0,0 +1,142 @@
+import { useEffect, useRef, useState } from "react";
+import styled, { css } from "styled-components";
+import { RecordConstructorToView } from "lowcoder-core";
+import { styleControl } from "comps/controls/styleControl";
+import _ from "lodash";
+import {
+ IconStyle,
+ IconStyleType,
+ heightCalculator,
+ widthCalculator,
+} from "comps/controls/styleControlConstants";
+import { UICompBuilder } from "comps/generators/uiCompBuilder";
+import { withDefault } from "../generators";
+import {
+ NameConfigHidden,
+ withExposingConfigs,
+} from "comps/generators/withExposing";
+import { Section, sectionNames } from "lowcoder-design";
+import { hiddenPropertyView } from "comps/utils/propertyUtils";
+import { trans } from "i18n";
+import { NumberControl } from "comps/controls/codeControl";
+import { IconControl } from "comps/controls/iconControl";
+import ReactResizeDetector from "react-resize-detector";
+import { AutoHeightControl } from "../controls/autoHeightControl";
+import {
+ clickEvent,
+ eventHandlerControl,
+} from "../controls/eventHandlerControl";
+
+const Container = styled.div<{ $style: IconStyleType | undefined }>`
+ height: 100%;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ svg {
+ object-fit: contain;
+ pointer-events: auto;
+ }
+ ${(props) => props.$style && getStyle(props.$style)}
+`;
+
+const getStyle = (style: IconStyleType) => {
+ return css`
+ svg {
+ color: ${style.fill};
+ }
+ padding: ${style.padding};
+ border: 1px solid ${style.border};
+ border-radius: ${style.radius};
+ margin: ${style.margin};
+ max-width: ${widthCalculator(style.margin)};
+ max-height: ${heightCalculator(style.margin)};
+ `;
+};
+
+const EventOptions = [clickEvent] as const;
+
+const childrenMap = {
+ style: styleControl(IconStyle),
+ icon: withDefault(IconControl, "/icon:antd/homefilled"),
+ autoHeight: withDefault(AutoHeightControl, "auto"),
+ iconSize: withDefault(NumberControl, 20),
+ onEvent: eventHandlerControl(EventOptions),
+};
+
+const IconView = (props: RecordConstructorToView) => {
+ const conRef = useRef(null);
+ const [width, setWidth] = useState(0);
+ const [height, setHeight] = useState(0);
+
+ useEffect(() => {
+ if (height && width) {
+ onResize();
+ }
+ }, [height, width]);
+
+ const onResize = () => {
+ const container = conRef.current;
+ setWidth(container?.clientWidth ?? 0);
+ setHeight(container?.clientHeight ?? 0);
+ };
+
+ return (
+
+ props.onEvent("click")}
+ >
+ {props.icon}
+
+
+ );
+};
+
+let IconBasicComp = (function () {
+ return new UICompBuilder(childrenMap, (props) => )
+ .setPropertyViewFn((children) => (
+ <>
+
+ {children.icon.propertyView({
+ label: trans("iconComp.icon"),
+ IconType: "All",
+ })}
+ {children.autoHeight.propertyView({
+ label: trans("iconComp.autoSize"),
+ })}
+ {!children.autoHeight.getView() &&
+ children.iconSize.propertyView({
+ label: trans("iconComp.iconSize"),
+ })}
+
+
+ {children.onEvent.getPropertyView()}
+
+
+ {hiddenPropertyView(children)}
+
+
+ {children.style.getPropertyView()}
+
+ >
+ ))
+ .build();
+})();
+
+IconBasicComp = class extends IconBasicComp {
+ override autoHeight(): boolean {
+ return false;
+ }
+};
+
+export const IconComp = withExposingConfigs(IconBasicComp, [
+ NameConfigHidden,
+]);
diff --git a/client/packages/lowcoder/src/comps/controls/controlParams.tsx b/client/packages/lowcoder/src/comps/controls/controlParams.tsx
index 0ee9de8e6..7b84c439d 100644
--- a/client/packages/lowcoder/src/comps/controls/controlParams.tsx
+++ b/client/packages/lowcoder/src/comps/controls/controlParams.tsx
@@ -18,6 +18,7 @@ export interface ControlParams extends CodeEditorControlParams {
preInputNode?: ReactNode;
childrenWrapperStyle?: CSSProperties;
extraChildren?: ReactNode;
+ IconType?: "OnlyAntd" | "All" | "default" | undefined;
}
export interface ControlType {
diff --git a/client/packages/lowcoder/src/comps/controls/dropdownControl.tsx b/client/packages/lowcoder/src/comps/controls/dropdownControl.tsx
index 01b7b832c..ea8e6f006 100644
--- a/client/packages/lowcoder/src/comps/controls/dropdownControl.tsx
+++ b/client/packages/lowcoder/src/comps/controls/dropdownControl.tsx
@@ -28,6 +28,7 @@ interface DropdownControlParams extends ControlParams {
showSearch?: boolean;
dropdownStyle?: React.CSSProperties;
labelStyle?: React.CSSProperties;
+ IconType?: "OnlyAntd" | "All" | "default" | undefined;
}
interface DropdownPropertyViewProps
diff --git a/client/packages/lowcoder/src/comps/controls/iconControl.tsx b/client/packages/lowcoder/src/comps/controls/iconControl.tsx
index 26a768b4e..ca954b47d 100644
--- a/client/packages/lowcoder/src/comps/controls/iconControl.tsx
+++ b/client/packages/lowcoder/src/comps/controls/iconControl.tsx
@@ -75,6 +75,7 @@ const IconPicker = (props: {
value: string;
onChange: (value: string) => void;
label?: ReactNode;
+ IconType?: "OnlyAntd" | "All" | "default" | undefined;
}) => {
const icon = useIcon(props.value);
return (
@@ -82,6 +83,7 @@ const IconPicker = (props: {
onChange={props.onChange}
label={props.label}
searchKeywords={i18nObjs.iconSearchKeywords}
+ IconType={props.IconType}
>
{icon ? (
@@ -251,7 +253,7 @@ export class IconControl extends AbstractComp
- {this.useCodeEditor && }
+ {this.useCodeEditor && }
);
}
@@ -262,6 +264,7 @@ export class IconControl extends AbstractComp this.dispatchChangeValueAction(x)}
label={params.label}
+ IconType={params.IconType}
/>
)}
diff --git a/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx b/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx
index a9749121f..9626e4fbf 100644
--- a/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx
+++ b/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx
@@ -1078,6 +1078,10 @@ export const NavigationStyle = [
export const ImageStyle = [getStaticBorder("#00000000"), RADIUS, BORDER_WIDTH, MARGIN, PADDING] as const;
+export const IconStyle = [getStaticBackground("#00000000"),
+ getStaticBorder("#00000000"), FILL, RADIUS, MARGIN, PADDING] as const;
+
+
export const ListViewStyle = BG_STATIC_BORDER_RADIUS;
export const JsonSchemaFormStyle = BG_STATIC_BORDER_RADIUS;
@@ -1331,6 +1335,7 @@ export type DividerStyleType = StyleConfigType;
export type ProgressStyleType = StyleConfigType;
export type NavigationStyleType = StyleConfigType;
export type ImageStyleType = StyleConfigType;
+export type IconStyleType = StyleConfigType;
export type ListViewStyleType = StyleConfigType;
export type JsonSchemaFormStyleType = StyleConfigType;
export type TreeSelectStyleType = StyleConfigType;
diff --git a/client/packages/lowcoder/src/comps/index.tsx b/client/packages/lowcoder/src/comps/index.tsx
index 0de77fadc..072eec5e9 100644
--- a/client/packages/lowcoder/src/comps/index.tsx
+++ b/client/packages/lowcoder/src/comps/index.tsx
@@ -130,6 +130,41 @@ import {
CommentIcon,
MentionIcon,
AutoCompleteCompIcon,
+
+ IconCompIcon,
+} from "lowcoder-design";
+// from Mousheng
+import { defaultFormData, FormComp } from "./comps/formComp/formComp";
+import { IFrameComp } from "./comps/iframeComp";
+import { defaultGridData, defaultListViewData, GridComp, ListViewComp } from "./comps/listViewComp";
+import { ModuleComp } from "./comps/moduleComp/moduleComp";
+import { NavComp } from "./comps/navComp/navComp";
+import { TableComp } from "./comps/tableComp";
+import { registerComp, UICompManifest, UICompType } from "./uiCompRegistry";
+import { QRCodeComp } from "./comps/qrCodeComp";
+import { JsonExplorerComp } from "./comps/jsonComp/jsonExplorerComp";
+import { JsonEditorComp } from "./comps/jsonComp/jsonEditorComp";
+import { TreeComp } from "./comps/treeComp/treeComp";
+import { TreeSelectComp } from "./comps/treeComp/treeSelectComp";
+import { trans } from "i18n";
+import { remoteComp } from "./comps/remoteComp/remoteComp";
+import { AudioComp } from "./comps/mediaComp/audioComp";
+import { VideoComp } from "./comps/mediaComp/videoComp";
+import { DrawerComp } from "./hooks/drawerComp";
+import { CarouselComp } from "./comps/carouselComp";
+import { ToggleButtonComp } from "./comps/buttonComp/toggleButtonComp";
+import { defaultCollapsibleContainerData } from "./comps/containerComp/collapsibleContainerComp";
+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";
+import { AutoCompleteComp } from "./comps/autoCompleteComp/autoCompleteComp"
+import { IconComp } from "./comps/iconComp";
+// from Mousheng
+
+//Added by Aqib Mirza
+import { JsonLottieComp } from "./comps/jsonComp/jsonLottieComp";
ResponsiveLayoutCompIcon,
MermaidIcon,
} from "lowcoder-design";
@@ -1023,6 +1058,23 @@ var uiCompMap: Registry = {
},
},
+// from Mousheng
+ icon: {
+ name: trans("uiComp.iconCompName"),
+ enName: "icon",
+ description: trans("uiComp.iconCompDesc"),
+ categories: ["dataDisplay"],
+ icon: IconCompIcon,
+ keywords: trans("uiComp.iconCompKeywords"),
+ comp: IconComp,
+ layoutInfo: {
+ w: 2,
+ h: 10,
+ },
+ },
+
+// from Mousheng
+
// Integration
iframe: {
diff --git a/client/packages/lowcoder/src/comps/uiCompRegistry.ts b/client/packages/lowcoder/src/comps/uiCompRegistry.ts
index f015a46db..c74893811 100644
--- a/client/packages/lowcoder/src/comps/uiCompRegistry.ts
+++ b/client/packages/lowcoder/src/comps/uiCompRegistry.ts
@@ -119,12 +119,14 @@ export type UICompType =
| "calendar"
| "signature"
| "jsonLottie" //Added By Aqib Mirza
+ | "icon" //Added By Mousheng
| "timeline" //Added By Mousheng
| "comment" //Added By Mousheng
| "mention" //Added By Mousheng
| "autocomplete" //Added By Mousheng
| "responsiveLayout";
+
export const uiCompRegistry = {} as Record;
export function registerComp(
diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts
index 74b2296b9..bd41b118a 100644
--- a/client/packages/lowcoder/src/i18n/locales/en.ts
+++ b/client/packages/lowcoder/src/i18n/locales/en.ts
@@ -1068,7 +1068,11 @@ export const en = {
// ninth part
-
+ "iconComp": {
+ "icon": "Icon",
+ "autoSize": "Icon AutoSize",
+ "iconSize": "Icon Size",
+ },
"numberInput": {
"formatter": "Format",
"precision": "Precision",
diff --git a/client/packages/lowcoder/src/i18n/locales/zh.ts b/client/packages/lowcoder/src/i18n/locales/zh.ts
index 28194e00f..e0634a234 100644
--- a/client/packages/lowcoder/src/i18n/locales/zh.ts
+++ b/client/packages/lowcoder/src/i18n/locales/zh.ts
@@ -879,6 +879,9 @@ uiComp: {
responsiveLayoutCompName: "响应式布局",
responsiveLayoutCompDesc: "响应式布局",
responsiveLayoutCompKeywords: "",
+ iconCompName: "图标",
+ iconCompDesc: "图标",
+ iconCompKeywords: "tb",
},
comp: {
menuViewDocs: "查看文档",
@@ -2630,6 +2633,11 @@ timeLine: {
helpvalue: "评论内容",
helpcreatedAt: "创建时间",
},
+ iconComp: {
+ icon: "图标",
+ autoSize: "图标自动大小",
+ iconSize: "图标大小",
+ },
mention:{
mentionList: "提及列表",
},
diff --git a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx
index 2820e14c9..5d69824e3 100644
--- a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx
+++ b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx
@@ -41,7 +41,9 @@ import {
CommentIcon,
MentionIcon,
AutoCompleteCompIcon,
+ IconCompIcon,
ResponsiveLayoutCompIcon,
+
} from "lowcoder-design";
export const CompStateIcon: {
@@ -116,5 +118,7 @@ export const CompStateIcon: {
comment: ,
mention: ,
autocomplete: ,
+ icon: ,
responsiveLayout: ,
+
};