From e9ec6deb2f3f304a2e8c8881c4fe9845d6e1745f Mon Sep 17 00:00:00 2001 From: Kamal Qureshi Date: Sat, 7 Jun 2025 03:44:40 +0500 Subject: [PATCH 1/7] Added double click to almost all components --- client/packages/lowcoder/src/comps/comps/avatar.tsx | 4 +++- .../lowcoder/src/comps/comps/avatarGroup.tsx | 7 +++++-- .../src/comps/comps/commentComp/commentComp.tsx | 7 ++++++- .../packages/lowcoder/src/comps/comps/iconComp.tsx | 4 +++- .../packages/lowcoder/src/comps/comps/imageComp.tsx | 4 +++- .../column/columnTypeComps/columnAvatarsComp.tsx | 10 ++++++++-- .../column/columnTypeComps/columnDropdownComp.tsx | 10 ++++++++-- .../column/columnTypeComps/columnLinkComp.tsx | 11 +++++++++-- .../column/columnTypeComps/columnLinksComp.tsx | 10 +++++++--- .../column/columnTypeComps/columnSelectComp.tsx | 13 ++++++++----- .../tableComp/column/simpleColumnTypeComps.tsx | 9 +++++++-- .../packages/lowcoder/src/comps/comps/textComp.tsx | 9 ++++++--- .../src/comps/comps/timelineComp/timelineComp.tsx | 8 ++++++++ .../src/comps/controls/eventHandlerControl.tsx | 3 ++- 14 files changed, 83 insertions(+), 26 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/avatar.tsx b/client/packages/lowcoder/src/comps/comps/avatar.tsx index bbd39f73e8..f07de98cae 100644 --- a/client/packages/lowcoder/src/comps/comps/avatar.tsx +++ b/client/packages/lowcoder/src/comps/comps/avatar.tsx @@ -25,6 +25,7 @@ import { IconControl } from "comps/controls/iconControl"; import { clickEvent, eventHandlerControl, + doubleClickEvent, } from "../controls/eventHandlerControl"; import { Avatar, AvatarProps, Badge, Dropdown, Menu } from "antd"; import { LeftRightControl, dropdownControl } from "../controls/dropdownControl"; @@ -106,7 +107,7 @@ padding: ${props=>props.$style.padding}; background: ${props=>props.$style.background}; text-decoration: ${props => props.$style.textDecoration}; ` -const EventOptions = [clickEvent] as const; +const EventOptions = [clickEvent, doubleClickEvent] as const; const sharpOptions = [ { label: trans("avatarComp.square"), value: "square" }, { label: trans("avatarComp.circle"), value: "circle" }, @@ -183,6 +184,7 @@ const AvatarView = (props: RecordConstructorToView) => { src={src.value} // $cursorPointer={eventsCount > 0} onClick={() => props.onEvent("click")} + onDoubleClick={() => props.onEvent("doubleClick")} > {title.value} diff --git a/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx b/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx index 4cc2567c64..8f35bd4f4d 100644 --- a/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx +++ b/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx @@ -8,7 +8,7 @@ import { hiddenPropertyView } from "comps/utils/propertyUtils"; import { trans } from "i18n"; import { NumberControl, StringControl } from "comps/controls/codeControl"; import { Avatar, Tooltip } from "antd"; -import { clickEvent, eventHandlerControl, refreshEvent } from "../controls/eventHandlerControl"; +import { clickEvent, doubleClickEvent, eventHandlerControl, refreshEvent } from "../controls/eventHandlerControl"; import styled from "styled-components"; import { useContext, ReactElement, useEffect } from "react"; import { MultiCompBuilder, stateComp, withDefault } from "../generators"; @@ -77,7 +77,7 @@ const DropdownOption = new MultiCompBuilder( )) .build(); -const EventOptions = [clickEvent, refreshEvent] as const; +const EventOptions = [clickEvent, refreshEvent, doubleClickEvent] as const; export const alignOptions = [ { label: , value: "flex-start" }, @@ -128,6 +128,9 @@ const AvatarGroupView = (props: RecordConstructorToView & { props.onEvent("click") props.dispatch(changeChildAction("currentAvatar", item as JSONObject, false)); }} + onDoubleClick={() => { + props.onEvent("doubleClick") + }} > {item.label} diff --git a/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx b/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx index 4fb21b69f5..d79fa542d2 100644 --- a/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx @@ -25,6 +25,7 @@ import { eventHandlerControl, deleteEvent, mentionEvent, + doubleClickEvent, } from "comps/controls/eventHandlerControl"; import { EditorContext } from "comps/editorState"; @@ -80,6 +81,7 @@ dayjs.extend(relativeTime); const EventOptions = [ clickEvent, + doubleClickEvent, submitEvent, deleteEvent, mentionEvent, @@ -290,7 +292,10 @@ const CommentCompBase = ( props.onEvent("click")}> +
props.onEvent("click")} + onDoubleClick={() => props.onEvent("doubleClick")} + > {item?.user?.name} ) => { $animationStyle={props.animationStyle} style={style} onClick={() => props.onEvent("click")} + onDoubleClick={() => props.onEvent("doubleClick")} > { props.sourceMode === 'standard' ? (props.icon || '') diff --git a/client/packages/lowcoder/src/comps/comps/imageComp.tsx b/client/packages/lowcoder/src/comps/comps/imageComp.tsx index ec4190bc6e..b0bd4d3dd6 100644 --- a/client/packages/lowcoder/src/comps/comps/imageComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/imageComp.tsx @@ -3,6 +3,7 @@ import { Section, sectionNames } from "lowcoder-design"; import { clickEvent, eventHandlerControl, + doubleClickEvent, } from "../controls/eventHandlerControl"; import { StringStateControl } from "../controls/codeStateControl"; import { UICompBuilder, withDefault } from "../generators"; @@ -112,7 +113,7 @@ const getStyle = (style: ImageStyleType) => { `; }; -const EventOptions = [clickEvent] as const; +const EventOptions = [clickEvent, doubleClickEvent] as const; const ModeOptions = [ { label: "URL", value: "standard" }, { label: "Asset Library", value: "asset-library" }, @@ -212,6 +213,7 @@ const ContainerImg = (props: RecordConstructorToView) => { preview={props.supportPreview ? {src: props.previewSrc || props.src.value } : false} fallback={DEFAULT_IMG_URL} onClick={() => props.onEvent("click")} + onDoubleClick={() => props.onEvent("doubleClick")} />
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx index c34b6dfbb9..11141281fa 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx @@ -9,7 +9,7 @@ import { avatarGroupStyle, AvatarGroupStyleType } from "comps/controls/styleCont import { AlignCenter, AlignLeft, AlignRight } from "lowcoder-design"; import { NumberControl } from "comps/controls/codeControl"; import { Avatar, Tooltip } from "antd"; -import { clickEvent, eventHandlerControl, refreshEvent } from "comps/controls/eventHandlerControl"; +import { clickEvent, eventHandlerControl, refreshEvent, doubleClickEvent } from "comps/controls/eventHandlerControl"; import React, { ReactElement, useCallback, useEffect, useRef } from "react"; import { IconControl } from "comps/controls/iconControl"; import { ColorControl } from "comps/controls/colorControl"; @@ -68,7 +68,7 @@ const DropdownOption = new MultiCompBuilder( }) .build(); -const EventOptions = [clickEvent, refreshEvent] as const; +const EventOptions = [clickEvent, refreshEvent, doubleClickEvent] as const; export const alignOptions = [ { label: , value: "flex-start" }, @@ -106,6 +106,11 @@ const MemoizedAvatar = React.memo(({ onEvent("click"); }, [onEvent]); + const handleDoubleClick = useCallback(() => { + if (!mountedRef.current) return; + onEvent("doubleClick"); + }, [onEvent]); + return ( {item.label} diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx index 9055413de1..d7efb3afff 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx @@ -15,7 +15,7 @@ import { ButtonStyle } from "comps/controls/styleControlConstants"; import { Button100 } from "comps/comps/buttonComp/buttonCompConstants"; import styled from "styled-components"; import { ButtonType } from "antd/es/button"; -import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl"; +import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; const StyledButton = styled(Button100)` display: flex; @@ -29,7 +29,7 @@ const StyledIconWrapper = styled(IconWrapper)` margin: 0; `; -const DropdownEventOptions = [clickEvent] as const; +const DropdownEventOptions = [clickEvent, doubleClickEvent] as const; const childrenMap = { buttonType: dropdownControl(ButtonTypeOptions, "primary"), @@ -67,10 +67,16 @@ const DropdownMenu = React.memo(({ items, options, onEvent }: { items: any[]; op e.preventDefault(); }, []); + const handleDoubleClick = useCallback((e: React.MouseEvent) => { + if (!mountedRef.current) return; + onEvent?.("doubleClick"); + }, [onEvent]); + return ( ); diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx index 512329ee36..183d87889b 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx @@ -11,11 +11,11 @@ import { disabledPropertyView } from "comps/utils/propertyUtils"; import styled, { css } from "styled-components"; import { styleControl } from "comps/controls/styleControl"; import { TableColumnLinkStyle } from "comps/controls/styleControlConstants"; -import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl"; +import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; export const ColumnValueTooltip = trans("table.columnValueTooltip"); -const LinkEventOptions = [clickEvent] as const; +const LinkEventOptions = [clickEvent, doubleClickEvent] as const; const childrenMap = { text: StringControl, @@ -44,10 +44,17 @@ export const ColumnLink = React.memo(({ disabled, label, onEvent }: { disabled: } }, [disabled, onEvent]); + const handleDoubleClick = useCallback(() => { + if (!disabled && onEvent) { + onEvent("doubleClick"); + } + }, [disabled, onEvent]); + return ( {label} diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx index b36f2acfcd..89ed76672f 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx @@ -10,7 +10,7 @@ import { trans } from "i18n"; import styled from "styled-components"; import { ColumnLink } from "comps/comps/tableComp/column/columnTypeComps/columnLinkComp"; import { LightActiveTextColor, PrimaryColor } from "constants/style"; -import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl"; +import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; const MenuLinkWrapper = styled.div` > a { @@ -38,7 +38,7 @@ const MenuWrapper = styled.div` } `; -const LinksEventOptions = [clickEvent] as const; +const LinksEventOptions = [clickEvent, doubleClickEvent] as const; // Update OptionItem to include event handlers const OptionItem = new MultiCompBuilder( @@ -76,11 +76,15 @@ const MenuItem = React.memo(({ option, index }: { option: any; index: number }) if (option.onClick) { option.onClick(); } + if (option.onDoubleClick) { + option.onDoubleClick(); + } if (option.onEvent) { option.onEvent("click"); } + } - }, [option.disabled, option.onClick, option.onEvent]); + }, [option.disabled, option.onClick, option.onEvent, option.onDoubleClick]); return ( diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx index 6162abea76..a751b033ab 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx @@ -11,7 +11,7 @@ import { trans } from "i18n"; import { ColumnTypeCompBuilder, ColumnTypeViewFn } from "../columnTypeCompBuilder"; import { ColumnValueTooltip } from "../simpleColumnTypeComps"; import { styled } from "styled-components"; -import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl"; +import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; const Wrapper = styled.div` display: inline-flex; @@ -79,7 +79,7 @@ const Wrapper = styled.div` } `; -const SelectOptionEventOptions = [clickEvent] as const; +const SelectOptionEventOptions = [clickEvent, doubleClickEvent] as const; // Create a new option type with event handlers for each option const SelectOptionWithEvents = new MultiCompBuilder( @@ -144,11 +144,14 @@ const SelectEdit = React.memo((props: SelectEditProps) => { if (!mountedRef.current) return; props.onChange(val); setCurrentValue(val); - // Trigger the specific option's event handler const selectedOption = props.options.find(option => option.value === val); - if (selectedOption && selectedOption.onEvent) { - selectedOption.onEvent("click"); + if (selectedOption?.onEvent) { + if (selectedOption.onEvent.isBind("click")) { + selectedOption.onEvent("click"); + } else if (selectedOption.onEvent.isBind("doubleClick")) { + selectedOption.onEvent("doubleClick"); + } } }, [props.onChange, props.options]); diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx index ba264c5e4f..0df62e2f0b 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx @@ -13,7 +13,7 @@ import React, { useCallback, useEffect, useMemo } from "react"; import { CSSProperties } from "react"; import { RecordConstructorToComp } from "lowcoder-core"; import { ToViewReturn } from "@lowcoder-ee/comps/generators/multi"; -import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl"; +import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; export const ColumnValueTooltip = trans("table.columnValueTooltip"); @@ -32,7 +32,7 @@ export const ButtonTypeOptions = [ }, ] as const; -const ButtonEventOptions = [clickEvent] as const; +const ButtonEventOptions = [clickEvent, doubleClickEvent] as const; const childrenMap = { text: StringControl, @@ -55,6 +55,10 @@ const ButtonStyled = React.memo(({ props }: { props: ToViewReturn { + props.onEvent("doubleClick"); + }, [props.onEvent]); + const buttonStyle = useMemo(() => ({ margin: 0, width: iconOnly ? 'auto' : undefined, @@ -71,6 +75,7 @@ const ButtonStyled = React.memo(({ props }: { props: ToViewReturn {/* prevent the button from disappearing */} {hasText ? props.text : (iconOnly ? null : " ")} diff --git a/client/packages/lowcoder/src/comps/comps/textComp.tsx b/client/packages/lowcoder/src/comps/comps/textComp.tsx index 93b3d79ae0..73f776ac37 100644 --- a/client/packages/lowcoder/src/comps/comps/textComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/textComp.tsx @@ -20,13 +20,13 @@ import { PaddingControl } from "../controls/paddingControl"; import React, { useContext, useEffect, useRef, useMemo } from "react"; import { EditorContext } from "comps/editorState"; -import { clickEvent, eventHandlerControl } from "../controls/eventHandlerControl"; +import { clickEvent, doubleClickEvent, eventHandlerControl } from "../controls/eventHandlerControl"; import { NewChildren } from "../generators/uiCompBuilder"; import { RecordConstructorToComp } from "lowcoder-core"; import { ToViewReturn } from "../generators/multi"; import { BoolControl } from "../controls/boolControl"; -const EventOptions = [clickEvent] as const; +const EventOptions = [clickEvent, doubleClickEvent] as const; const getStyle = (style: TextStyleType) => { return css` @@ -227,7 +227,9 @@ const TextView = React.memo((props: ToViewReturn) => { const handleClick = React.useCallback(() => { props.onEvent("click"); }, [props.onEvent]); - + const handleDoubleClick = React.useCallback(() => { + props.onEvent("doubleClick"); + }, [props.onEvent]); const containerStyle = useMemo(() => ({ justifyContent: props.horizontalAlignment, alignItems: props.autoHeight ? "center" : props.verticalAlignment, @@ -247,6 +249,7 @@ const TextView = React.memo((props: ToViewReturn) => { $styleConfig={props.style} style={containerStyle} onClick={handleClick} + onDoubleClick={handleDoubleClick} > {content} diff --git a/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx b/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx index db45ba023b..e7743f0f8e 100644 --- a/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx @@ -30,6 +30,7 @@ import { import { clickEvent, eventHandlerControl, + doubleClickEvent, } from "comps/controls/eventHandlerControl"; import { TimeLineStyle, @@ -69,6 +70,7 @@ const TimelineWrapper = styled.div<{ const EventOptions = [ clickEvent, + doubleClickEvent, ] as const; const modeOptions = [ @@ -142,6 +144,12 @@ const TimelineComp = ( dispatch(changeChildAction("clickedIndex", index, false)); onEvent("click"); }} + onDoubleClick={(e) => { + e.preventDefault(); + dispatch(changeChildAction("clickedObject", value, false)); + dispatch(changeChildAction("clickedIndex", index, false)); + onEvent("doubleClick"); + }} // for responsiveness style={{ cursor: "pointer", diff --git a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx index d8c26d7ad8..289a212eac 100644 --- a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx @@ -378,7 +378,7 @@ export const doubleClickEvent: EventConfigType = { }; export const rightClickEvent: EventConfigType = { label: trans("event.rightClick"), - value: "doubleClick", + value: "rightClick", description: trans("event.rightClickDesc"), }; @@ -704,6 +704,7 @@ export const InputEventHandlerControl = eventHandlerControl([ export const ButtonEventHandlerControl = eventHandlerControl([ clickEvent, + doubleClickEvent, ] as const); export const ChangeEventHandlerControl = eventHandlerControl([ From a65010b3d4f7aca1e39433d4b01af2b5fb5ac4c4 Mon Sep 17 00:00:00 2001 From: Kamal Qureshi Date: Wed, 11 Jun 2025 20:31:17 +0500 Subject: [PATCH 2/7] Updated event value --- .../lowcoder/src/comps/controls/eventHandlerControl.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx index 289a212eac..f3a751eb6e 100644 --- a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx @@ -378,7 +378,7 @@ export const doubleClickEvent: EventConfigType = { }; export const rightClickEvent: EventConfigType = { label: trans("event.rightClick"), - value: "rightClick", + value: "doubleClick", description: trans("event.rightClickDesc"), }; From 4dbce10475a6c1ace48d172f5408e8884ad4c482 Mon Sep 17 00:00:00 2001 From: Kamal Qureshi Date: Thu, 12 Jun 2025 20:14:06 +0500 Subject: [PATCH 3/7] Updated Double Click event on all components --- .../lowcoder/src/comps/comps/avatar.tsx | 6 ++-- .../lowcoder/src/comps/comps/avatarGroup.tsx | 6 ++-- .../src/comps/comps/buttonComp/buttonComp.tsx | 3 +- .../comps/buttonComp/floatButtonComp.tsx | 3 +- .../comps/comps/commentComp/commentComp.tsx | 10 +++--- .../comps/comps/containerComp/cardComp.tsx | 6 ++-- .../lowcoder/src/comps/comps/iconComp.tsx | 4 +-- .../lowcoder/src/comps/comps/imageComp.tsx | 4 +-- .../comps/comps/meetingComp/controlButton.tsx | 3 +- .../columnTypeComps/ColumnNumberComp.tsx | 9 +++--- .../columnTypeComps/columnAvatarsComp.tsx | 9 ++---- .../columnTypeComps/columnDropdownComp.tsx | 9 ++---- .../column/columnTypeComps/columnLinkComp.tsx | 10 ++---- .../columnTypeComps/columnLinksComp.tsx | 23 +++++--------- .../column/columnTypeComps/simpleTextComp.tsx | 10 +++--- .../column/simpleColumnTypeComps.tsx | 8 ++--- .../lowcoder/src/comps/comps/textComp.tsx | 8 ++--- .../comps/comps/timelineComp/timelineComp.tsx | 9 ++---- .../comps/controls/eventHandlerControl.tsx | 1 + .../src/comps/utils/componentClickHandler.tsx | 31 +++++++++++++++++++ 20 files changed, 85 insertions(+), 87 deletions(-) create mode 100644 client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx diff --git a/client/packages/lowcoder/src/comps/comps/avatar.tsx b/client/packages/lowcoder/src/comps/comps/avatar.tsx index f07de98cae..c9d5b9602b 100644 --- a/client/packages/lowcoder/src/comps/comps/avatar.tsx +++ b/client/packages/lowcoder/src/comps/comps/avatar.tsx @@ -35,6 +35,8 @@ import { BadgeBasicSection, badgeChildren } from "./badgeComp/badgeConstants"; import { DropdownOptionControl } from "../controls/optionsControl"; import { ReactElement, useContext, useEffect } from "react"; import { CompNameContext, EditorContext } from "../editorState"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; + const AvatarWrapper = styled(Avatar) ` background: ${(props) => props.$style.background}; @@ -182,9 +184,7 @@ const AvatarView = (props: RecordConstructorToView) => { shape={shape} $style={props.avatarStyle} src={src.value} - // $cursorPointer={eventsCount > 0} - onClick={() => props.onEvent("click")} - onDoubleClick={() => props.onEvent("doubleClick")} + onClick={ComponentClickHandler({onEvent: props.onEvent})} > {title.value} diff --git a/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx b/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx index 8f35bd4f4d..9181c5c215 100644 --- a/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx +++ b/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx @@ -19,6 +19,7 @@ import { optionsControl } from "../controls/optionsControl"; import { BoolControl } from "../controls/boolControl"; import { dropdownControl } from "../controls/dropdownControl"; import { JSONObject } from "util/jsonTypes"; +import { ComponentClickHandler } from "../utils/componentClickHandler"; const MacaroneList = [ '#fde68a', @@ -125,12 +126,9 @@ const AvatarGroupView = (props: RecordConstructorToView & { }} size={props.avatarSize} onClick={() => { - props.onEvent("click") + ComponentClickHandler({onEvent: props.onEvent})(); props.dispatch(changeChildAction("currentAvatar", item as JSONObject, false)); }} - onDoubleClick={() => { - props.onEvent("doubleClick") - }} > {item.label} diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx index 6f657c1e84..e7218dd70d 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx @@ -29,6 +29,7 @@ import { AnimationStyle } from "@lowcoder-ee/comps/controls/styleControlConstant import { styleControl } from "@lowcoder-ee/comps/controls/styleControl"; import { RecordConstructorToComp } from "lowcoder-core"; import { ToViewReturn } from "@lowcoder-ee/comps/generators/multi"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; const FormLabel = styled(CommonBlueLabel)` font-size: 13px; @@ -193,7 +194,7 @@ const ButtonView = React.memo((props: ToViewReturn) => { try { if (isDefault(props.type)) { - props.onEvent("click"); + ComponentClickHandler({onEvent: props.onEvent})() } else { submitForm(editorState, props.form); } diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx index 223650ef48..71fbbba204 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx @@ -17,6 +17,7 @@ import styled from "styled-components"; import { ButtonEventHandlerControl } from "comps/controls/eventHandlerControl"; import { manualOptionsControl } from "comps/controls/optionsControl"; import { useContext, useEffect } from "react"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; const StyledFloatButton = styled(FloatButton)<{ $animationStyle: AnimationStyleType; @@ -105,7 +106,7 @@ const FloatButtonView = (props: RecordConstructorToView) => $animationStyle={props.animationStyle} key={button?.id} icon={button?.icon} - onClick={() => button.onEvent("click")} + onClick={ComponentClickHandler({onEvent: button.onEvent})} tooltip={button?.label} description={button?.description} badge={{ count: button?.badge, color: props.badgeStyle.badgeColor, dot: props?.dot }} diff --git a/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx b/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx index d79fa542d2..8e7ab8dfc6 100644 --- a/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx @@ -26,10 +26,10 @@ import { deleteEvent, mentionEvent, doubleClickEvent, -} from "comps/controls/eventHandlerControl"; - +} from "comps/controls/eventHandlerControl"; import { EditorContext } from "comps/editorState"; + // Introducing styles import { AnimationStyle, @@ -67,6 +67,7 @@ import dayjs from "dayjs"; // import "dayjs/locale/zh-cn"; import { getInitialsAndColorCode } from "util/stringUtils"; import { default as CloseOutlined } from "@ant-design/icons/CloseOutlined"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; dayjs.extend(relativeTime); // dayjs.locale("zh-cn"); @@ -176,7 +177,7 @@ const CommentCompBase = ( const generateCommentAvatar = (item: commentDataTYPE) => { return ( props.onEvent("click")} + onClick={ComponentClickHandler({onEvent: props.onEvent})} // If there is an avatar, no background colour is set, and if displayName is not null, displayName is called using getInitialsAndColorCode style={{ backgroundColor: item?.user?.avatar @@ -293,8 +294,7 @@ const CommentCompBase = ( avatar={generateCommentAvatar(item)} title={
props.onEvent("click")} - onDoubleClick={() => props.onEvent("doubleClick")} + onClick={ComponentClickHandler({onEvent: props.onEvent})} > {item?.user?.name} { props.container.showHeader = false; - // 注入容器参数 props.container.style = Object.assign(props.container.style, { CONTAINER_BODY_PADDING: props.style.containerBodyPadding, border: '#00000000', @@ -233,7 +233,7 @@ export const ContainerBaseComp = (function () { $cardType={props.cardType} onMouseEnter={() => props.onEvent('focus')} onMouseLeave={() => props.onEvent('blur')} - onClick={() => props.onEvent('click')} + onClick={ComponentClickHandler({onEvent: props.onEvent})} > !item.hidden).map(item => { return ( item.onEvent('click')} + onClick={ComponentClickHandler({onEvent: props.onEvent})} disabled={item.disabled} $style={props.style} > diff --git a/client/packages/lowcoder/src/comps/comps/iconComp.tsx b/client/packages/lowcoder/src/comps/comps/iconComp.tsx index e50bd002ce..12a3da1985 100644 --- a/client/packages/lowcoder/src/comps/comps/iconComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/iconComp.tsx @@ -33,6 +33,7 @@ import { useContext } from "react"; import { EditorContext } from "comps/editorState"; import { AssetType, IconscoutControl } from "@lowcoder-ee/comps/controls/iconscoutControl"; import { dropdownControl } from "../controls/dropdownControl"; +import { ComponentClickHandler } from "../utils/componentClickHandler"; const Container = styled.div<{ $sourceMode: string; @@ -135,8 +136,7 @@ const IconView = (props: RecordConstructorToView) => { $sourceMode={props.sourceMode} $animationStyle={props.animationStyle} style={style} - onClick={() => props.onEvent("click")} - onDoubleClick={() => props.onEvent("doubleClick")} + onClick={ComponentClickHandler({onEvent: props.onEvent})} > { props.sourceMode === 'standard' ? (props.icon || '') diff --git a/client/packages/lowcoder/src/comps/comps/imageComp.tsx b/client/packages/lowcoder/src/comps/comps/imageComp.tsx index b0bd4d3dd6..e82d2bab25 100644 --- a/client/packages/lowcoder/src/comps/comps/imageComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/imageComp.tsx @@ -38,6 +38,7 @@ import { StringControl } from "../controls/codeControl"; import { PositionControl } from "comps/controls/dropdownControl"; import { dropdownControl } from "../controls/dropdownControl"; import { AssetType, IconscoutControl } from "../controls/iconscoutControl"; +import { ComponentClickHandler } from "../utils/componentClickHandler"; const Container = styled.div<{ $style: ImageStyleType | undefined, @@ -212,8 +213,7 @@ const ContainerImg = (props: RecordConstructorToView) => { draggable={false} preview={props.supportPreview ? {src: props.previewSrc || props.src.value } : false} fallback={DEFAULT_IMG_URL} - onClick={() => props.onEvent("click")} - onDoubleClick={() => props.onEvent("doubleClick")} + onClick={ComponentClickHandler({onEvent: props.onEvent})} />
diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx index 313358815a..90da85e8cb 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx @@ -41,6 +41,7 @@ import { useResizeDetector } from "react-resize-detector"; import { useContext } from "react"; import { Tooltip } from "antd"; import { AssetType, IconscoutControl } from "@lowcoder-ee/comps/controls/iconscoutControl"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; const Container = styled.div<{ $style: any }>` height: 100%; @@ -285,7 +286,7 @@ let ButtonTmpComp = (function () { } onClick={() => isDefault(props.type) - ? props.onEvent("click") + ? ComponentClickHandler({onEvent: props.onEvent})() : submitForm(editorState, props.form) } > diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx index 78bba93807..af77fa4726 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx @@ -9,7 +9,8 @@ import { withDefault } from "comps/generators"; import styled from "styled-components"; import { IconControl } from "comps/controls/iconControl"; import { hasIcon } from "comps/utils"; -import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl"; +import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; const InputNumberWrapper = styled.div` .ant-input-number { @@ -33,7 +34,7 @@ const NumberViewWrapper = styled.div` gap: 4px; `; -const NumberEventOptions = [clickEvent] as const; +const NumberEventOptions = [clickEvent, doubleClickEvent] as const; const childrenMap = { text: NumberControl, @@ -79,9 +80,7 @@ const ColumnNumberView = React.memo((props: NumberViewProps) => { }, [props.value, props.float, props.precision]); const handleClick = useCallback(() => { - if (props.onEvent) { - props.onEvent("click"); - } + props.onEvent && ComponentClickHandler({onEvent: props.onEvent})() }, [props.onEvent]); return ( diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx index a33100154a..a8f864a775 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx @@ -17,6 +17,7 @@ import { optionsControl } from "comps/controls/optionsControl"; import { BoolControl } from "comps/controls/boolControl"; import { dropdownControl } from "comps/controls/dropdownControl"; import { JSONObject } from "util/jsonTypes"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; const MacaroneList = [ '#fde68a', @@ -116,14 +117,9 @@ const MemoizedAvatar = React.memo(({ } // Then trigger main component event - onEvent("click"); + ComponentClickHandler({onEvent})() }, [onEvent, onItemEvent]); - const handleDoubleClick = useCallback(() => { - if (!mountedRef.current) return; - onEvent("doubleClick"); - }, [onEvent]); - return ( {item.label} diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx index d7efb3afff..cb426e2964 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx @@ -16,6 +16,7 @@ import { Button100 } from "comps/comps/buttonComp/buttonCompConstants"; import styled from "styled-components"; import { ButtonType } from "antd/es/button"; import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; const StyledButton = styled(Button100)` display: flex; @@ -59,7 +60,7 @@ const DropdownMenu = React.memo(({ items, options, onEvent }: { items: any[]; op const itemIndex = options.findIndex(option => option.label === item?.label); item && options[itemIndex]?.onEvent("click"); // Also trigger the dropdown's main event handler - onEvent?.("click"); + onEvent && ComponentClickHandler({onEvent})(); }, [items, options, onEvent]); const handleMouseDown = useCallback((e: React.MouseEvent) => { @@ -67,16 +68,10 @@ const DropdownMenu = React.memo(({ items, options, onEvent }: { items: any[]; op e.preventDefault(); }, []); - const handleDoubleClick = useCallback((e: React.MouseEvent) => { - if (!mountedRef.current) return; - onEvent?.("doubleClick"); - }, [onEvent]); - return ( ); diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx index 183d87889b..e285898d73 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx @@ -12,6 +12,7 @@ import styled, { css } from "styled-components"; import { styleControl } from "comps/controls/styleControl"; import { TableColumnLinkStyle } from "comps/controls/styleControlConstants"; import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; export const ColumnValueTooltip = trans("table.columnValueTooltip"); @@ -40,13 +41,7 @@ const StyledLink = styled.a<{ $disabled: boolean }>` export const ColumnLink = React.memo(({ disabled, label, onEvent }: { disabled: boolean; label: string; onEvent?: (eventName: string) => void }) => { const handleClick = useCallback(() => { if (!disabled && onEvent) { - onEvent("click"); - } - }, [disabled, onEvent]); - - const handleDoubleClick = useCallback(() => { - if (!disabled && onEvent) { - onEvent("doubleClick"); + ComponentClickHandler({onEvent})(); } }, [disabled, onEvent]); @@ -54,7 +49,6 @@ export const ColumnLink = React.memo(({ disabled, label, onEvent }: { disabled: {label} diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx index e62db2c746..ed5190c544 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx @@ -11,6 +11,7 @@ import styled from "styled-components"; import { ColumnLink } from "comps/comps/tableComp/column/columnTypeComps/columnLinkComp"; import { LightActiveTextColor, PrimaryColor } from "constants/style"; import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; const MenuLinkWrapper = styled.div` > a { @@ -73,22 +74,14 @@ const OptionItem = new MultiCompBuilder( const MenuItem = React.memo(({ option, index, onMainEvent }: { option: any; index: number; onMainEvent?: (eventName: string) => void }) => { const handleClick = useCallback(() => { if (!option.disabled) { - if (option.onClick) { - option.onClick(); - } - if (option.onDoubleClick) { - option.onDoubleClick(); - } - if (option.onEvent) { - option.onEvent("click"); - } - - // Trigger the main component's event handler - if (onMainEvent) { - onMainEvent("click"); - } + // Handle both option's event and main event through ComponentClickHandler + const combinedHandler = (event: "click" | "doubleClick") => { + option.onEvent?.(event); + onMainEvent?.(event); + }; + ComponentClickHandler({onEvent: combinedHandler})(); } - }, [option.disabled, option.onClick, option.onEvent, onMainEvent, option.onDoubleClick]); + }, [option.disabled, option.onEvent, onMainEvent]); return ( diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx index aba5052526..3bb7aeb503 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx @@ -7,10 +7,11 @@ import { IconControl } from "comps/controls/iconControl"; import { hasIcon } from "comps/utils"; import React, { useCallback, useMemo } from "react"; import { RecordConstructorToComp } from "lowcoder-core"; -import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl"; +import { clickEvent, doubleClickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl"; import styled from "styled-components"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; -const TextEventOptions = [clickEvent] as const; +const TextEventOptions = [clickEvent, doubleClickEvent] as const; const TextWrapper = styled.div` cursor: pointer; @@ -50,9 +51,8 @@ interface SimpleTextEditViewProps { const SimpleTextContent = React.memo(({ value, prefixIcon, suffixIcon, onEvent }: SimpleTextContentProps) => { const handleClick = useCallback(() => { - if (onEvent) { - onEvent("click"); - } + console.log("This comp"); + onEvent && ComponentClickHandler({onEvent})() }, [onEvent]); return ( diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx index 0df62e2f0b..2a28f098cd 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx @@ -14,6 +14,7 @@ import { CSSProperties } from "react"; import { RecordConstructorToComp } from "lowcoder-core"; import { ToViewReturn } from "@lowcoder-ee/comps/generators/multi"; import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; export const ColumnValueTooltip = trans("table.columnValueTooltip"); @@ -52,11 +53,7 @@ const ButtonStyled = React.memo(({ props }: { props: ToViewReturn { - props.onEvent("click"); - }, [props.onEvent]); - - const handleDoubleClick = useCallback((e: React.MouseEvent) => { - props.onEvent("doubleClick"); + ComponentClickHandler({onEvent: props.onEvent}) }, [props.onEvent]); const buttonStyle = useMemo(() => ({ @@ -75,7 +72,6 @@ const ButtonStyled = React.memo(({ props }: { props: ToViewReturn {/* prevent the button from disappearing */} {hasText ? props.text : (iconOnly ? null : " ")} diff --git a/client/packages/lowcoder/src/comps/comps/textComp.tsx b/client/packages/lowcoder/src/comps/comps/textComp.tsx index 73f776ac37..b41ab1b61d 100644 --- a/client/packages/lowcoder/src/comps/comps/textComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/textComp.tsx @@ -25,6 +25,7 @@ import { NewChildren } from "../generators/uiCompBuilder"; import { RecordConstructorToComp } from "lowcoder-core"; import { ToViewReturn } from "../generators/multi"; import { BoolControl } from "../controls/boolControl"; +import { ComponentClickHandler } from "../utils/componentClickHandler"; const EventOptions = [clickEvent, doubleClickEvent] as const; @@ -225,11 +226,9 @@ const TextPropertyView = React.memo((props: { const TextView = React.memo((props: ToViewReturn) => { const value = props.text.value; const handleClick = React.useCallback(() => { - props.onEvent("click"); - }, [props.onEvent]); - const handleDoubleClick = React.useCallback(() => { - props.onEvent("doubleClick"); + props.onEvent && ComponentClickHandler({onEvent: props.onEvent})() }, [props.onEvent]); + const containerStyle = useMemo(() => ({ justifyContent: props.horizontalAlignment, alignItems: props.autoHeight ? "center" : props.verticalAlignment, @@ -249,7 +248,6 @@ const TextView = React.memo((props: ToViewReturn) => { $styleConfig={props.style} style={containerStyle} onClick={handleClick} - onDoubleClick={handleDoubleClick} > {content} diff --git a/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx b/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx index e7743f0f8e..ee5e162649 100644 --- a/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx @@ -50,6 +50,7 @@ import { convertTimeLineData } from "./timelineUtils"; import { default as Timeline } from "antd/es/timeline"; import { EditorContext } from "comps/editorState"; import { styled } from "styled-components"; +import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; const TimelineWrapper = styled.div<{ $style: TimeLineStyleType @@ -142,13 +143,7 @@ const TimelineComp = ( e.preventDefault(); dispatch(changeChildAction("clickedObject", value, false)); dispatch(changeChildAction("clickedIndex", index, false)); - onEvent("click"); - }} - onDoubleClick={(e) => { - e.preventDefault(); - dispatch(changeChildAction("clickedObject", value, false)); - dispatch(changeChildAction("clickedIndex", index, false)); - onEvent("doubleClick"); + ComponentClickHandler({onEvent})() }} // for responsiveness style={{ diff --git a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx index f3a751eb6e..b4b19d5228 100644 --- a/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/eventHandlerControl.tsx @@ -819,4 +819,5 @@ export const CardEventHandlerControl = eventHandlerControl([ clickExtraEvent, focusEvent, blurEvent, + doubleClickEvent ] as const); \ No newline at end of file diff --git a/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx b/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx new file mode 100644 index 0000000000..705321074d --- /dev/null +++ b/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx @@ -0,0 +1,31 @@ +import React from "react"; + +export enum ClickEventType { + CLICK = "click", + DOUBLE_CLICK = "doubleClick" +} + +interface Props { + onEvent: (event: ClickEventType) => void; +} + +const DOUBLE_CLICK_THRESHOLD = 300; // ms +let lastClickTime = 0; +let clickTimer: ReturnType; + +export const ComponentClickHandler = (props: Props) => { + return () => { + const now = Date.now() + clearTimeout(clickTimer) + + if((now - lastClickTime) < DOUBLE_CLICK_THRESHOLD){ + return props.onEvent(ClickEventType.DOUBLE_CLICK) + } else { + clickTimer = setTimeout(() => { + props.onEvent(ClickEventType.CLICK) + }, DOUBLE_CLICK_THRESHOLD) + } + + lastClickTime = now + } +} \ No newline at end of file From a27f132b40cdc5d2c7ed10568eb71957c0bb0af7 Mon Sep 17 00:00:00 2001 From: Kamal Qureshi Date: Thu, 12 Jun 2025 20:21:42 +0500 Subject: [PATCH 4/7] fix: - Added timeout - Removed Console logs --- .../comps/tableComp/column/columnTypeComps/simpleTextComp.tsx | 1 - .../lowcoder/src/comps/utils/componentClickHandler.tsx | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx index 3bb7aeb503..c346c22d90 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx @@ -51,7 +51,6 @@ interface SimpleTextEditViewProps { const SimpleTextContent = React.memo(({ value, prefixIcon, suffixIcon, onEvent }: SimpleTextContentProps) => { const handleClick = useCallback(() => { - console.log("This comp"); onEvent && ComponentClickHandler({onEvent})() }, [onEvent]); diff --git a/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx b/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx index 705321074d..47fd335da7 100644 --- a/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx +++ b/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx @@ -19,7 +19,8 @@ export const ComponentClickHandler = (props: Props) => { clearTimeout(clickTimer) if((now - lastClickTime) < DOUBLE_CLICK_THRESHOLD){ - return props.onEvent(ClickEventType.DOUBLE_CLICK) + clearTimeout(clickTimer) + props.onEvent(ClickEventType.DOUBLE_CLICK) } else { clickTimer = setTimeout(() => { props.onEvent(ClickEventType.CLICK) From c6f2d790e2bf5e5eaff7336055f6f23f9da8de0b Mon Sep 17 00:00:00 2001 From: RAHEEL Date: Fri, 13 Jun 2025 16:35:27 +0500 Subject: [PATCH 5/7] fix memory leaks and convert click event wrapper to hook --- .../src/comps/comps/buttonComp/buttonComp.tsx | 6 ++- .../src/comps/utils/componentClickHandler.tsx | 47 ++++++++++++------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx index e7218dd70d..1e44b5bbc1 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx @@ -29,7 +29,7 @@ import { AnimationStyle } from "@lowcoder-ee/comps/controls/styleControlConstant import { styleControl } from "@lowcoder-ee/comps/controls/styleControl"; import { RecordConstructorToComp } from "lowcoder-core"; import { ToViewReturn } from "@lowcoder-ee/comps/generators/multi"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; const FormLabel = styled(CommonBlueLabel)` font-size: 13px; @@ -182,6 +182,7 @@ const ButtonPropertyView = React.memo((props: { const ButtonView = React.memo((props: ToViewReturn) => { const editorState = useContext(EditorContext); const mountedRef = useRef(true); + const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent}); useEffect(() => { return () => { @@ -194,7 +195,8 @@ const ButtonView = React.memo((props: ToViewReturn) => { try { if (isDefault(props.type)) { - ComponentClickHandler({onEvent: props.onEvent})() + // ComponentClickHandler({onEvent: props.onEvent})() + handleClickEvent(); } else { submitForm(editorState, props.form); } diff --git a/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx b/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx index 47fd335da7..e8f64cc5a4 100644 --- a/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx +++ b/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useCallback, useRef } from "react"; export enum ClickEventType { CLICK = "click", @@ -10,23 +10,38 @@ interface Props { } const DOUBLE_CLICK_THRESHOLD = 300; // ms -let lastClickTime = 0; -let clickTimer: ReturnType; -export const ComponentClickHandler = (props: Props) => { - return () => { - const now = Date.now() - clearTimeout(clickTimer) +export const useCompClickEventHandler = (props: Props) => { + const lastClickTimeRef = useRef(0); + const clickTimerRef = useRef>(); - if((now - lastClickTime) < DOUBLE_CLICK_THRESHOLD){ - clearTimeout(clickTimer) - props.onEvent(ClickEventType.DOUBLE_CLICK) + const handleClick = useCallback(() => { + const now = Date.now(); + + // Clear any existing timeout + if (clickTimerRef.current) { + clearTimeout(clickTimerRef.current); + } + + if ((now - lastClickTimeRef.current) < DOUBLE_CLICK_THRESHOLD) { + props.onEvent(ClickEventType.DOUBLE_CLICK); } else { - clickTimer = setTimeout(() => { - props.onEvent(ClickEventType.CLICK) - }, DOUBLE_CLICK_THRESHOLD) + clickTimerRef.current = setTimeout(() => { + props.onEvent(ClickEventType.CLICK); + }, DOUBLE_CLICK_THRESHOLD); } - lastClickTime = now - } -} \ No newline at end of file + lastClickTimeRef.current = now; + }, [props.onEvent]); + + // Cleanup on unmount + React.useEffect(() => { + return () => { + if (clickTimerRef.current) { + clearTimeout(clickTimerRef.current); + } + }; + }, []); + + return handleClick; +}; From df38a039fba78c0bd034890e474921bb372c2437 Mon Sep 17 00:00:00 2001 From: Kamal Qureshi Date: Mon, 16 Jun 2025 11:47:55 +0500 Subject: [PATCH 6/7] Optimizations - Added hook for click event handlers --- .../lowcoder/src/comps/comps/avatar.tsx | 6 ++- .../lowcoder/src/comps/comps/avatarGroup.tsx | 6 ++- .../src/comps/comps/buttonComp/buttonComp.tsx | 3 +- .../comps/buttonComp/floatButtonComp.tsx | 54 ++++++++++++++----- .../comps/comps/commentComp/commentComp.tsx | 8 +-- .../comps/comps/containerComp/cardComp.tsx | 17 ++++-- .../lowcoder/src/comps/comps/iconComp.tsx | 5 +- .../lowcoder/src/comps/comps/imageComp.tsx | 6 ++- .../comps/comps/meetingComp/controlButton.tsx | 7 ++- .../columnTypeComps/ColumnNumberComp.tsx | 6 ++- .../columnTypeComps/columnAvatarsComp.tsx | 6 ++- .../columnTypeComps/columnDropdownComp.tsx | 13 ++--- .../column/columnTypeComps/columnLinkComp.tsx | 18 +++---- .../columnTypeComps/columnLinksComp.tsx | 10 +--- .../column/columnTypeComps/simpleTextComp.tsx | 6 ++- .../column/simpleColumnTypeComps.tsx | 12 ++--- .../lowcoder/src/comps/comps/textComp.tsx | 6 ++- .../comps/comps/timelineComp/timelineComp.tsx | 6 ++- ...ndler.tsx => useCompClickEventHandler.tsx} | 0 19 files changed, 120 insertions(+), 75 deletions(-) rename client/packages/lowcoder/src/comps/utils/{componentClickHandler.tsx => useCompClickEventHandler.tsx} (100%) diff --git a/client/packages/lowcoder/src/comps/comps/avatar.tsx b/client/packages/lowcoder/src/comps/comps/avatar.tsx index c9d5b9602b..aac9949a0a 100644 --- a/client/packages/lowcoder/src/comps/comps/avatar.tsx +++ b/client/packages/lowcoder/src/comps/comps/avatar.tsx @@ -35,7 +35,7 @@ import { BadgeBasicSection, badgeChildren } from "./badgeComp/badgeConstants"; import { DropdownOptionControl } from "../controls/optionsControl"; import { ReactElement, useContext, useEffect } from "react"; import { CompNameContext, EditorContext } from "../editorState"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; const AvatarWrapper = styled(Avatar) ` @@ -143,6 +143,8 @@ const childrenMap = { const AvatarView = (props: RecordConstructorToView) => { const { shape, title, src, iconSize } = props; const comp = useContext(EditorContext).getUICompByName(useContext(CompNameContext)); + const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent}) + // const eventsCount = comp ? Object.keys(comp?.children.comp.children.onEvent.children).length : 0; const hasIcon = props.options.findIndex((option) => (option.prefixIcon as ReactElement)?.props.value) > -1; const items = props.options @@ -184,7 +186,7 @@ const AvatarView = (props: RecordConstructorToView) => { shape={shape} $style={props.avatarStyle} src={src.value} - onClick={ComponentClickHandler({onEvent: props.onEvent})} + onClick={() => handleClickEvent()} > {title.value} diff --git a/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx b/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx index 9181c5c215..f370a4ef99 100644 --- a/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx +++ b/client/packages/lowcoder/src/comps/comps/avatarGroup.tsx @@ -19,7 +19,7 @@ import { optionsControl } from "../controls/optionsControl"; import { BoolControl } from "../controls/boolControl"; import { dropdownControl } from "../controls/dropdownControl"; import { JSONObject } from "util/jsonTypes"; -import { ComponentClickHandler } from "../utils/componentClickHandler"; +import { useCompClickEventHandler } from "../utils/useCompClickEventHandler"; const MacaroneList = [ '#fde68a', @@ -106,6 +106,8 @@ const childrenMap = { }; const AvatarGroupView = (props: RecordConstructorToView & { dispatch: (action: CompAction) => void; }) => { + const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent}) + return ( & { }} size={props.avatarSize} onClick={() => { - ComponentClickHandler({onEvent: props.onEvent})(); + handleClickEvent(); props.dispatch(changeChildAction("currentAvatar", item as JSONObject, false)); }} > diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx index 1e44b5bbc1..70a8de5d83 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx @@ -29,7 +29,7 @@ import { AnimationStyle } from "@lowcoder-ee/comps/controls/styleControlConstant import { styleControl } from "@lowcoder-ee/comps/controls/styleControl"; import { RecordConstructorToComp } from "lowcoder-core"; import { ToViewReturn } from "@lowcoder-ee/comps/generators/multi"; -import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; const FormLabel = styled(CommonBlueLabel)` font-size: 13px; @@ -195,7 +195,6 @@ const ButtonView = React.memo((props: ToViewReturn) => { try { if (isDefault(props.type)) { - // ComponentClickHandler({onEvent: props.onEvent})() handleClickEvent(); } else { submitForm(editorState, props.form); diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx index 71fbbba204..358a1e6ff2 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx @@ -1,3 +1,4 @@ +import React from "react"; import { RecordConstructorToView } from "lowcoder-core"; import { BoolControl } from "comps/controls/boolControl"; import { stringExposingStateControl } from "comps/controls/codeStateControl"; @@ -16,8 +17,7 @@ import { IconControl } from "comps/controls/iconControl"; import styled from "styled-components"; import { ButtonEventHandlerControl } from "comps/controls/eventHandlerControl"; import { manualOptionsControl } from "comps/controls/optionsControl"; -import { useContext, useEffect } from "react"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; const StyledFloatButton = styled(FloatButton)<{ $animationStyle: AnimationStyleType; @@ -99,21 +99,51 @@ const childrenMap = { dot: BoolControl, }; +const FloatButtonItem = React.memo(({ + button, + animationStyle, + badgeStyle, + buttonTheme, + shape, + dot +}: { + button: any; + animationStyle: AnimationStyleType; + badgeStyle: BadgeStyleType; + buttonTheme: 'primary' | 'default'; + shape: 'circle' | 'square'; + dot: boolean; +}) => { + const handleClickEvent = useCompClickEventHandler({ onEvent: button.onEvent }); + + return ( + + ); +}); + const FloatButtonView = (props: RecordConstructorToView) => { const renderButton = (button: any, onlyOne?: boolean) => { return !button?.hidden ? ( - ) - : '' + dot={props.dot} + /> + ) : ''; } return ( diff --git a/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx b/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx index 8e7ab8dfc6..c20cb793ba 100644 --- a/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx @@ -67,7 +67,7 @@ import dayjs from "dayjs"; // import "dayjs/locale/zh-cn"; import { getInitialsAndColorCode } from "util/stringUtils"; import { default as CloseOutlined } from "@ant-design/icons/CloseOutlined"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; dayjs.extend(relativeTime); // dayjs.locale("zh-cn"); @@ -136,6 +136,8 @@ const CommentCompBase = ( const [commentListData, setCommentListData] = useState([]); const [prefix, setPrefix] = useState("@"); const [context, setContext] = useState(""); + const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent}) + // Integrate the comment list with the names in the original mention list const mergeAllMentionList = (mentionList: any) => { setMentionList( @@ -177,7 +179,7 @@ const CommentCompBase = ( const generateCommentAvatar = (item: commentDataTYPE) => { return ( handleClickEvent()} // If there is an avatar, no background colour is set, and if displayName is not null, displayName is called using getInitialsAndColorCode style={{ backgroundColor: item?.user?.avatar @@ -294,7 +296,7 @@ const CommentCompBase = ( avatar={generateCommentAvatar(item)} title={
handleClickEvent()} > {item?.user?.name} (null); const [width, setWidth] = useState(0); const [height, setHeight] = useState(0); + const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent}) + const actionHandlers = props.actionOptions.map(item => ({ + ...item, + clickHandler: useCompClickEventHandler({onEvent: item.onEvent}) + })); + useEffect(() => { if (height && width) { onResize(); @@ -233,7 +239,7 @@ export const ContainerBaseComp = (function () { $cardType={props.cardType} onMouseEnter={() => props.onEvent('focus')} onMouseLeave={() => props.onEvent('blur')} - onClick={ComponentClickHandler({onEvent: props.onEvent})} + onClick={() => handleClickEvent()} > } actions={props.cardType == 'common' && props.showActionIcon ? - props.actionOptions.filter(item => !item.hidden).map(item => { + actionHandlers.filter(item => !item.hidden).map(item => { return ( { + e.stopPropagation() + item.clickHandler() + }} disabled={item.disabled} $style={props.style} > diff --git a/client/packages/lowcoder/src/comps/comps/iconComp.tsx b/client/packages/lowcoder/src/comps/comps/iconComp.tsx index 12a3da1985..6e49b429ae 100644 --- a/client/packages/lowcoder/src/comps/comps/iconComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/iconComp.tsx @@ -33,7 +33,7 @@ import { useContext } from "react"; import { EditorContext } from "comps/editorState"; import { AssetType, IconscoutControl } from "@lowcoder-ee/comps/controls/iconscoutControl"; import { dropdownControl } from "../controls/dropdownControl"; -import { ComponentClickHandler } from "../utils/componentClickHandler"; +import { useCompClickEventHandler } from "../utils/useCompClickEventHandler"; const Container = styled.div<{ $sourceMode: string; @@ -96,6 +96,7 @@ const IconView = (props: RecordConstructorToView) => { const conRef = useRef(null); const [width, setWidth] = useState(0); const [height, setHeight] = useState(0); + const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent}) useEffect(() => { if (height && width) { @@ -136,7 +137,7 @@ const IconView = (props: RecordConstructorToView) => { $sourceMode={props.sourceMode} $animationStyle={props.animationStyle} style={style} - onClick={ComponentClickHandler({onEvent: props.onEvent})} + onClick={() => handleClickEvent()} > { props.sourceMode === 'standard' ? (props.icon || '') diff --git a/client/packages/lowcoder/src/comps/comps/imageComp.tsx b/client/packages/lowcoder/src/comps/comps/imageComp.tsx index e82d2bab25..80d2ba77b0 100644 --- a/client/packages/lowcoder/src/comps/comps/imageComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/imageComp.tsx @@ -38,7 +38,7 @@ import { StringControl } from "../controls/codeControl"; import { PositionControl } from "comps/controls/dropdownControl"; import { dropdownControl } from "../controls/dropdownControl"; import { AssetType, IconscoutControl } from "../controls/iconscoutControl"; -import { ComponentClickHandler } from "../utils/componentClickHandler"; +import { useCompClickEventHandler } from "../utils/useCompClickEventHandler"; const Container = styled.div<{ $style: ImageStyleType | undefined, @@ -125,6 +125,8 @@ const ContainerImg = (props: RecordConstructorToView) => { const conRef = useRef(null); const [width, setWidth] = useState(0); const [height, setHeight] = useState(0); + const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent}) + const imgOnload = (img: HTMLImageElement) => { img.onload = function () { @@ -213,7 +215,7 @@ const ContainerImg = (props: RecordConstructorToView) => { draggable={false} preview={props.supportPreview ? {src: props.previewSrc || props.src.value } : false} fallback={DEFAULT_IMG_URL} - onClick={ComponentClickHandler({onEvent: props.onEvent})} + onClick={() => handleClickEvent()} />
diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx index 90da85e8cb..0445c94039 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/controlButton.tsx @@ -41,7 +41,7 @@ import { useResizeDetector } from "react-resize-detector"; import { useContext } from "react"; import { Tooltip } from "antd"; import { AssetType, IconscoutControl } from "@lowcoder-ee/comps/controls/iconscoutControl"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; const Container = styled.div<{ $style: any }>` height: 100%; @@ -213,6 +213,9 @@ let ButtonTmpComp = (function () { const imgRef = useRef(null); const conRef = useRef(null); + + const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent}) + useEffect(() => { if (height && width) { onResize(); @@ -286,7 +289,7 @@ let ButtonTmpComp = (function () { } onClick={() => isDefault(props.type) - ? ComponentClickHandler({onEvent: props.onEvent})() + ? handleClickEvent() : submitForm(editorState, props.form) } > diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx index af77fa4726..619b42674f 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/ColumnNumberComp.tsx @@ -10,7 +10,7 @@ import styled from "styled-components"; import { IconControl } from "comps/controls/iconControl"; import { hasIcon } from "comps/utils"; import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; const InputNumberWrapper = styled.div` .ant-input-number { @@ -71,6 +71,8 @@ type NumberEditProps = { }; const ColumnNumberView = React.memo((props: NumberViewProps) => { + const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent ?? (() => {})}) + const formattedValue = useMemo(() => { let result = !props.float ? Math.floor(props.value) : props.value; if (props.float) { @@ -80,7 +82,7 @@ const ColumnNumberView = React.memo((props: NumberViewProps) => { }, [props.value, props.float, props.precision]); const handleClick = useCallback(() => { - props.onEvent && ComponentClickHandler({onEvent: props.onEvent})() + handleClickEvent() }, [props.onEvent]); return ( diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx index a8f864a775..f85863e01b 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx @@ -17,7 +17,7 @@ import { optionsControl } from "comps/controls/optionsControl"; import { BoolControl } from "comps/controls/boolControl"; import { dropdownControl } from "comps/controls/dropdownControl"; import { JSONObject } from "util/jsonTypes"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; const MacaroneList = [ '#fde68a', @@ -100,6 +100,8 @@ const MemoizedAvatar = React.memo(({ onItemEvent?: (event: string) => void; }) => { const mountedRef = useRef(true); + const handleClickEvent = useCompClickEventHandler({onEvent}) + // Cleanup on unmount useEffect(() => { @@ -117,7 +119,7 @@ const MemoizedAvatar = React.memo(({ } // Then trigger main component event - ComponentClickHandler({onEvent})() + handleClickEvent() }, [onEvent, onItemEvent]); return ( diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx index cb426e2964..7dd3bf2424 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx @@ -15,8 +15,8 @@ import { ButtonStyle } from "comps/controls/styleControlConstants"; import { Button100 } from "comps/comps/buttonComp/buttonCompConstants"; import styled from "styled-components"; import { ButtonType } from "antd/es/button"; -import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; const StyledButton = styled(Button100)` display: flex; @@ -30,7 +30,7 @@ const StyledIconWrapper = styled(IconWrapper)` margin: 0; `; -const DropdownEventOptions = [clickEvent, doubleClickEvent] as const; +const DropdownEventOptions = [clickEvent] as const; const childrenMap = { buttonType: dropdownControl(ButtonTypeOptions, "primary"), @@ -44,8 +44,9 @@ const childrenMap = { const getBaseValue: ColumnTypeViewFn = (props) => props.label; // Memoized dropdown menu component -const DropdownMenu = React.memo(({ items, options, onEvent }: { items: any[]; options: any[]; onEvent?: (eventName: string) => void }) => { +const DropdownMenu = React.memo(({ items, options, onEvent }: { items: any[]; options: any[]; onEvent: (eventName: string) => void }) => { const mountedRef = useRef(true); + const handleClickEvent = useCompClickEventHandler({onEvent}) // Cleanup on unmount useEffect(() => { @@ -60,7 +61,7 @@ const DropdownMenu = React.memo(({ items, options, onEvent }: { items: any[]; op const itemIndex = options.findIndex(option => option.label === item?.label); item && options[itemIndex]?.onEvent("click"); // Also trigger the dropdown's main event handler - onEvent && ComponentClickHandler({onEvent})(); + handleClickEvent(); }, [items, options, onEvent]); const handleMouseDown = useCallback((e: React.MouseEvent) => { @@ -128,7 +129,7 @@ const DropdownView = React.memo((props: { const buttonStyle = useStyle(ButtonStyle); const menu = useMemo(() => ( - + {})} /> ), [items, props.options, props.onEvent]); return ( diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx index 3be2c5db95..e93b3082a6 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx @@ -11,7 +11,7 @@ import styled, { css } from "styled-components"; import { styleControl } from "comps/controls/styleControl"; import { TableColumnLinkStyle } from "comps/controls/styleControlConstants"; import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; import { migrateOldData } from "@lowcoder-ee/comps/generators/simpleGenerators"; import { fixOldActionData } from "comps/comps/tableComp/column/simpleColumnTypeComps"; @@ -39,19 +39,13 @@ const StyledLink = styled.a<{ $disabled: boolean }>` `; // Memoized link component -export const ColumnLink = React.memo(({ disabled, label, onClick }: { disabled: boolean; label: string; onClick?: (eventName: string) => void }) => { +export const ColumnLink = React.memo(({ disabled, label, onClick }: { disabled: boolean; label: string; onClick: (eventName: string) => void }) => { + const handleClickEvent = useCompClickEventHandler({onEvent: onClick}) const handleClick = useCallback(() => { - if (!disabled && onEvent) { - ComponentClickHandler({onEvent})(); + if (!disabled) { + handleClickEvent(); } - }, [disabled, onEvent]); - // if (disabled) return; - // onClick?.(); - // // onEvent?.("click"); - // }, [disabled, onClick, onEvent]); - // if (disabled) return; - // onClick?.("click"); - // }, [disabled, onClick]); + }, [disabled, onClick]); return ( { - const handleClick = useCallback(() => { - if (!option.disabled && option.onClick) { - option.onClick("click"); - } - }, [option.disabled, option.onClick]); - return ( ); diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx index c346c22d90..80b8e89811 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx @@ -9,7 +9,7 @@ import React, { useCallback, useMemo } from "react"; import { RecordConstructorToComp } from "lowcoder-core"; import { clickEvent, doubleClickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl"; import styled from "styled-components"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; const TextEventOptions = [clickEvent, doubleClickEvent] as const; @@ -50,8 +50,10 @@ interface SimpleTextEditViewProps { } const SimpleTextContent = React.memo(({ value, prefixIcon, suffixIcon, onEvent }: SimpleTextContentProps) => { + const handleClickEvent = useCompClickEventHandler({onEvent: onEvent ?? (() => {})}) + const handleClick = useCallback(() => { - onEvent && ComponentClickHandler({onEvent})() + handleClickEvent() }, [onEvent]); return ( diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx index 2da1fbe7e9..8ec51c6a1a 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx @@ -14,8 +14,8 @@ import { CSSProperties } from "react"; import { RecordConstructorToComp } from "lowcoder-core"; import { ToViewReturn } from "@lowcoder-ee/comps/generators/multi"; import { clickEvent, eventHandlerControl, doubleClickEvent } from "comps/controls/eventHandlerControl"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; import { migrateOldData } from "@lowcoder-ee/comps/generators/simpleGenerators"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; export const fixOldActionData = (oldData: any) => { if (!oldData) return oldData; @@ -65,15 +65,11 @@ const ButtonStyled = React.memo(({ props }: { props: ToViewReturn { - ComponentClickHandler({onEvent: props.onEvent}) - }, [props.onEvent]); - // props.onClick?.(); - // // props.onEvent?.("click"); - // }, [props.onClick, props.onEvent]); - // props.onClick?.("click"); - // }, [props.onClick]); + handleClickEvent() + }, [handleClickEvent]); const buttonStyle = useMemo(() => ({ margin: 0, diff --git a/client/packages/lowcoder/src/comps/comps/textComp.tsx b/client/packages/lowcoder/src/comps/comps/textComp.tsx index b41ab1b61d..41b8ee09e3 100644 --- a/client/packages/lowcoder/src/comps/comps/textComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/textComp.tsx @@ -25,7 +25,7 @@ import { NewChildren } from "../generators/uiCompBuilder"; import { RecordConstructorToComp } from "lowcoder-core"; import { ToViewReturn } from "../generators/multi"; import { BoolControl } from "../controls/boolControl"; -import { ComponentClickHandler } from "../utils/componentClickHandler"; +import { useCompClickEventHandler } from "../utils/useCompClickEventHandler"; const EventOptions = [clickEvent, doubleClickEvent] as const; @@ -225,8 +225,10 @@ const TextPropertyView = React.memo((props: { const TextView = React.memo((props: ToViewReturn) => { const value = props.text.value; + const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent}) + const handleClick = React.useCallback(() => { - props.onEvent && ComponentClickHandler({onEvent: props.onEvent})() + handleClickEvent() }, [props.onEvent]); const containerStyle = useMemo(() => ({ diff --git a/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx b/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx index ee5e162649..06e1ff1a4e 100644 --- a/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/timelineComp/timelineComp.tsx @@ -50,7 +50,7 @@ import { convertTimeLineData } from "./timelineUtils"; import { default as Timeline } from "antd/es/timeline"; import { EditorContext } from "comps/editorState"; import { styled } from "styled-components"; -import { ComponentClickHandler } from "@lowcoder-ee/comps/utils/componentClickHandler"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; const TimelineWrapper = styled.div<{ $style: TimeLineStyleType @@ -113,6 +113,8 @@ const TimelineComp = ( ) => { const { value, dispatch, style, mode, reverse, onEvent } = props; const [icons, setIcons] = useState([]); + const handleClickEvent = useCompClickEventHandler({onEvent}) + useEffect(() => { const loadIcons = async () => { const iconComponents = await Promise.all( @@ -143,7 +145,7 @@ const TimelineComp = ( e.preventDefault(); dispatch(changeChildAction("clickedObject", value, false)); dispatch(changeChildAction("clickedIndex", index, false)); - ComponentClickHandler({onEvent})() + handleClickEvent() }} // for responsiveness style={{ diff --git a/client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx b/client/packages/lowcoder/src/comps/utils/useCompClickEventHandler.tsx similarity index 100% rename from client/packages/lowcoder/src/comps/utils/componentClickHandler.tsx rename to client/packages/lowcoder/src/comps/utils/useCompClickEventHandler.tsx From b454a7ff53ffb5b621bfcc357649497a8e090b1b Mon Sep 17 00:00:00 2001 From: Kamal Qureshi Date: Mon, 16 Jun 2025 14:36:09 +0500 Subject: [PATCH 7/7] - Requested Changes --- client/packages/lowcoder/src/comps/comps/avatar.tsx | 2 +- .../lowcoder/src/comps/comps/commentComp/commentComp.tsx | 4 ++-- .../lowcoder/src/comps/comps/containerComp/cardComp.tsx | 2 +- client/packages/lowcoder/src/comps/comps/iconComp.tsx | 2 +- client/packages/lowcoder/src/comps/comps/imageComp.tsx | 2 +- .../column/columnTypeComps/columnAvatarsComp.tsx | 2 +- .../column/columnTypeComps/columnDropdownComp.tsx | 2 +- .../tableComp/column/columnTypeComps/columnSelectComp.tsx | 8 ++------ .../tableComp/column/columnTypeComps/simpleTextComp.tsx | 2 +- client/packages/lowcoder/src/comps/comps/textComp.tsx | 2 +- 10 files changed, 12 insertions(+), 16 deletions(-) diff --git a/client/packages/lowcoder/src/comps/comps/avatar.tsx b/client/packages/lowcoder/src/comps/comps/avatar.tsx index aac9949a0a..94e24d59a4 100644 --- a/client/packages/lowcoder/src/comps/comps/avatar.tsx +++ b/client/packages/lowcoder/src/comps/comps/avatar.tsx @@ -186,7 +186,7 @@ const AvatarView = (props: RecordConstructorToView) => { shape={shape} $style={props.avatarStyle} src={src.value} - onClick={() => handleClickEvent()} + onClick={handleClickEvent} > {title.value} diff --git a/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx b/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx index c20cb793ba..f3b14959c9 100644 --- a/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx @@ -179,7 +179,7 @@ const CommentCompBase = ( const generateCommentAvatar = (item: commentDataTYPE) => { return ( handleClickEvent()} + onClick={handleClickEvent} // If there is an avatar, no background colour is set, and if displayName is not null, displayName is called using getInitialsAndColorCode style={{ backgroundColor: item?.user?.avatar @@ -296,7 +296,7 @@ const CommentCompBase = ( avatar={generateCommentAvatar(item)} title={
handleClickEvent()} + onClick={handleClickEvent} > {item?.user?.name} props.onEvent('focus')} onMouseLeave={() => props.onEvent('blur')} - onClick={() => handleClickEvent()} + onClick={handleClickEvent} > ) => { $sourceMode={props.sourceMode} $animationStyle={props.animationStyle} style={style} - onClick={() => handleClickEvent()} + onClick={handleClickEvent} > { props.sourceMode === 'standard' ? (props.icon || '') diff --git a/client/packages/lowcoder/src/comps/comps/imageComp.tsx b/client/packages/lowcoder/src/comps/comps/imageComp.tsx index 80d2ba77b0..8bc246a2b1 100644 --- a/client/packages/lowcoder/src/comps/comps/imageComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/imageComp.tsx @@ -215,7 +215,7 @@ const ContainerImg = (props: RecordConstructorToView) => { draggable={false} preview={props.supportPreview ? {src: props.previewSrc || props.src.value } : false} fallback={DEFAULT_IMG_URL} - onClick={() => handleClickEvent()} + onClick={handleClickEvent} />
diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx index f85863e01b..f02ee19943 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnAvatarsComp.tsx @@ -120,7 +120,7 @@ const MemoizedAvatar = React.memo(({ // Then trigger main component event handleClickEvent() - }, [onEvent, onItemEvent]); + }, [onItemEvent, handleClickEvent]); return ( diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx index 7dd3bf2424..b78601a5fa 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx @@ -62,7 +62,7 @@ const DropdownMenu = React.memo(({ items, options, onEvent }: { items: any[]; op item && options[itemIndex]?.onEvent("click"); // Also trigger the dropdown's main event handler handleClickEvent(); - }, [items, options, onEvent]); + }, [items, options, handleClickEvent]); const handleMouseDown = useCallback((e: React.MouseEvent) => { e.stopPropagation(); diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx index 5c532836a7..b54be87997 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx @@ -6,7 +6,6 @@ import { IconControl } from "comps/controls/iconControl"; import { MultiCompBuilder } from "comps/generators"; import { optionsControl } from "comps/controls/optionsControl"; import { disabledPropertyView, hiddenPropertyView } from "comps/utils/propertyUtils"; - import { trans } from "i18n"; import { ColumnTypeCompBuilder, ColumnTypeViewFn } from "../columnTypeCompBuilder"; import { ColumnValueTooltip } from "../simpleColumnTypeComps"; @@ -146,14 +145,11 @@ const SelectEdit = React.memo((props: SelectEditProps) => { if (!mountedRef.current) return; props.onChange(val); setCurrentValue(val); + // Trigger the specific option's event handler const selectedOption = props.options.find(option => option.value === val); if (selectedOption?.onEvent) { - if (selectedOption.onEvent.isBind("click")) { - selectedOption.onEvent("click"); - } else if (selectedOption.onEvent.isBind("doubleClick")) { - selectedOption.onEvent("doubleClick"); - } + selectedOption.onEvent("click"); } // Also trigger the main component's event handler diff --git a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx index 80b8e89811..dcdffe3907 100644 --- a/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/simpleTextComp.tsx @@ -54,7 +54,7 @@ const SimpleTextContent = React.memo(({ value, prefixIcon, suffixIcon, onEvent } const handleClick = useCallback(() => { handleClickEvent() - }, [onEvent]); + }, [handleClickEvent]); return ( diff --git a/client/packages/lowcoder/src/comps/comps/textComp.tsx b/client/packages/lowcoder/src/comps/comps/textComp.tsx index 41b8ee09e3..dcc5ccdb2b 100644 --- a/client/packages/lowcoder/src/comps/comps/textComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/textComp.tsx @@ -229,7 +229,7 @@ const TextView = React.memo((props: ToViewReturn) => { const handleClick = React.useCallback(() => { handleClickEvent() - }, [props.onEvent]); + }, [handleClickEvent]); const containerStyle = useMemo(() => ({ justifyContent: props.horizontalAlignment,