From 5919277935c49790e51a4f1756d762aa216f8ba6 Mon Sep 17 00:00:00 2001 From: mou <10402885@qq.com> Date: Fri, 4 Aug 2023 16:29:41 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=9B=BE=E6=A0=87=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E6=B7=BB=E5=8A=A0antD=E5=9B=BE=E6=A0=87=20ic?= =?UTF-8?q?onControl=20add=20antd=20icon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/iconSelect/index.tsx | 101 +++++++++++++----- .../src/comps/controls/controlParams.tsx | 1 + .../src/comps/controls/dropdownControl.tsx | 1 + .../src/comps/controls/iconControl.tsx | 5 +- 4 files changed, 80 insertions(+), 28 deletions(-) diff --git a/client/packages/lowcoder-design/src/components/iconSelect/index.tsx b/client/packages/lowcoder-design/src/components/iconSelect/index.tsx index 41f0bcf61..425b19185 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 { Popover } from "antd"; -import { ActionType } from '@rc-component/trigger/lib/interface'; +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 { List, ListRowProps } from "react-virtualized"; 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/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 211dd0910..838b98a34 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} /> )} From f3cb6746830fb915b42e184bf7ed30922875f8c5 Mon Sep 17 00:00:00 2001 From: mou <10402885@qq.com> Date: Wed, 9 Aug 2023 09:55:58 +0800 Subject: [PATCH 2/3] add_icon_component --- .../src/icons/IconCompIcon.svg | 1 + .../lowcoder-design/src/icons/index.ts | 2 + .../lowcoder/src/comps/comps/iconComp.tsx | 142 ++++++++++++++++++ .../comps/controls/styleControlConstants.tsx | 5 + client/packages/lowcoder/src/comps/index.tsx | 16 ++ .../lowcoder/src/comps/uiCompRegistry.ts | 1 + .../packages/lowcoder/src/i18n/locales/en.ts | 8 + .../packages/lowcoder/src/i18n/locales/zh.ts | 33 ++++ .../src/pages/editor/editorConstants.tsx | 2 + 9 files changed, 210 insertions(+) create mode 100644 client/packages/lowcoder-design/src/icons/IconCompIcon.svg create mode 100644 client/packages/lowcoder/src/comps/comps/iconComp.tsx 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 4ac1b051e..6d620cf46 100644 --- a/client/packages/lowcoder-design/src/icons/index.ts +++ b/client/packages/lowcoder-design/src/icons/index.ts @@ -291,3 +291,5 @@ 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"; \ No newline at end of file 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/styleControlConstants.tsx b/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx index 5d650faea..ca58c2836 100644 --- a/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx +++ b/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx @@ -775,6 +775,10 @@ export const NavigationStyle = [ export const ImageStyle = [getStaticBorder("#00000000"), RADIUS, 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; @@ -934,6 +938,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 5dc0f2923..b70906d20 100644 --- a/client/packages/lowcoder/src/comps/index.tsx +++ b/client/packages/lowcoder/src/comps/index.tsx @@ -96,6 +96,7 @@ import { LottieIcon, MentionIcon, AutoCompleteCompIcon, + IconCompIcon, } from "lowcoder-design"; import { defaultFormData, FormComp } from "./comps/formComp/formComp"; @@ -124,6 +125,8 @@ 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"; + //Added by Aqib Mirza import { JsonLottieComp } from "./comps/jsonComp/jsonLottieComp"; @@ -881,6 +884,19 @@ const uiCompMap: Registry = { h: 5, }, }, + 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, + }, + }, }; export function loadComps() { diff --git a/client/packages/lowcoder/src/comps/uiCompRegistry.ts b/client/packages/lowcoder/src/comps/uiCompRegistry.ts index 6cd63e920..9ba13b930 100644 --- a/client/packages/lowcoder/src/comps/uiCompRegistry.ts +++ b/client/packages/lowcoder/src/comps/uiCompRegistry.ts @@ -114,6 +114,7 @@ export type UICompType = | "timeline" | "mention" | "autocomplete" + | "icon" 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 941a77767..304651c62 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -853,6 +853,9 @@ export const en = { autoCompleteCompName: "autoComplete", autoCompleteCompDesc: "autoComplete", autoCompleteCompKeywords: "", + iconCompName: "icon", + iconCompDesc: "icon", + iconCompKeywords: "", }, comp: { menuViewDocs: "View documentation", @@ -2505,4 +2508,9 @@ export const en = { helpLabel: "label", helpValue: "value", }, + iconComp: { + icon: "icon", + autoSize: "icon AutoSize", + iconSize: "icon size", + } }; diff --git a/client/packages/lowcoder/src/i18n/locales/zh.ts b/client/packages/lowcoder/src/i18n/locales/zh.ts index 7fb2416d5..0539f15ca 100644 --- a/client/packages/lowcoder/src/i18n/locales/zh.ts +++ b/client/packages/lowcoder/src/i18n/locales/zh.ts @@ -836,6 +836,9 @@ uiComp: { autoCompleteCompName: "自动完成", autoCompleteCompDesc: "自动完成", autoCompleteCompKeywords: "zdwc", + iconCompName: "图标", + iconCompDesc: "图标", + iconCompKeywords: "tb", }, comp: { menuViewDocs: "查看文档", @@ -2495,5 +2498,35 @@ timeLine: { helpLabel: "标签", helpValue: "值", }, + comment: { + value: "评论列表数据", + showSendButton: "允许评论", + title: "标题", + titledDefaultValue: "共有%d条评论", + placeholder: "shift + enter 快捷发送评论;输入@或#可快速输入", + placeholderDec: "占位符", + buttonTextDec: "按钮文本", + buttonText: "发表", + mentionList: "提及列表数据", + mentionListDec: "key-提及关键字;value-提及列表", + userInfo: "用户信息", + dateErr: "日期错误", + commentList: "评论列表数据", + deletedItem: "已删除的数据", + submitedItem: "已提交的数据", + deleteAble: "显示删除按钮", + Introduction: "属性介绍", + helpUser: "用户信息(必填)", + helpname: "用户名(必填)", + helpavatar: "头像地址(高优先)", + helpdisplayName: "头像文字(低优先)", + helpvalue: "评论内容", + helpcreatedAt: "创建时间", + }, + iconComp: { + icon: "图标", + autoSize: "图标自动大小", + iconSize: "图标大小", + } }; diff --git a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx index a09a9a56e..cd3c81c3a 100644 --- a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx +++ b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx @@ -39,6 +39,7 @@ import { TimeLineIcon, MentionIcon, AutoCompleteCompIcon, + IconCompIcon, } from "lowcoder-design"; export const CompStateIcon: { @@ -107,4 +108,5 @@ export const CompStateIcon: { timeline: , mention: , autocomplete: , + icon: , }; From fd9c3ccfe95ff3de8f2d4f46f43fb86fbdb0e6b6 Mon Sep 17 00:00:00 2001 From: mou <10402885@qq.com> Date: Wed, 9 Aug 2023 10:26:48 +0800 Subject: [PATCH 3/3] fix_toggle_button_icon_bug --- .../lowcoder-design/src/components/iconSelect/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/packages/lowcoder-design/src/components/iconSelect/index.tsx b/client/packages/lowcoder-design/src/components/iconSelect/index.tsx index 425b19185..da47c2dab 100644 --- a/client/packages/lowcoder-design/src/components/iconSelect/index.tsx +++ b/client/packages/lowcoder-design/src/components/iconSelect/index.tsx @@ -127,7 +127,7 @@ class Icon { } } getView() { - if (this.names[0].startsWith("antd/")) return this.def; + if (this.names[0]?.startsWith("antd/")) return this.def; else return (