Skip to content

Commit a8ffe8c

Browse files
authored
Merge pull request #1742 from iamfaran/feat/1585-table-events
[Feat]: #1585 Add Event Handlers for more Table Column Types
2 parents 248262a + 6a3ce06 commit a8ffe8c

File tree

5 files changed

+108
-45
lines changed

5 files changed

+108
-45
lines changed

client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnDropdownComp.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { ButtonStyle } from "comps/controls/styleControlConstants";
1515
import { Button100 } from "comps/comps/buttonComp/buttonCompConstants";
1616
import styled from "styled-components";
1717
import { ButtonType } from "antd/es/button";
18+
import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl";
1819

1920
const StyledButton = styled(Button100)`
2021
display: flex;
@@ -28,18 +29,21 @@ const StyledIconWrapper = styled(IconWrapper)`
2829
margin: 0;
2930
`;
3031

32+
const DropdownEventOptions = [clickEvent] as const;
33+
3134
const childrenMap = {
3235
buttonType: dropdownControl(ButtonTypeOptions, "primary"),
3336
label: withDefault(StringControl, 'Menu'),
3437
prefixIcon: IconControl,
3538
suffixIcon: IconControl,
3639
options: DropdownOptionControl,
40+
onEvent: eventHandlerControl(DropdownEventOptions),
3741
};
3842

3943
const getBaseValue: ColumnTypeViewFn<typeof childrenMap, string, string> = (props) => props.label;
4044

4145
// Memoized dropdown menu component
42-
const DropdownMenu = React.memo(({ items, options }: { items: any[]; options: any[] }) => {
46+
const DropdownMenu = React.memo(({ items, options, onEvent }: { items: any[]; options: any[]; onEvent?: (eventName: string) => void }) => {
4347
const mountedRef = useRef(true);
4448

4549
// Cleanup on unmount
@@ -54,7 +58,9 @@ const DropdownMenu = React.memo(({ items, options }: { items: any[]; options: an
5458
const item = items.find((o) => o.key === key);
5559
const itemIndex = options.findIndex(option => option.label === item?.label);
5660
item && options[itemIndex]?.onEvent("click");
57-
}, [items, options]);
61+
// Also trigger the dropdown's main event handler
62+
onEvent?.("click");
63+
}, [items, options, onEvent]);
5864

5965
const handleMouseDown = useCallback((e: React.MouseEvent) => {
6066
e.stopPropagation();
@@ -78,6 +84,7 @@ const DropdownView = React.memo((props: {
7884
prefixIcon: ReactNode;
7985
suffixIcon: ReactNode;
8086
options: any[];
87+
onEvent?: (eventName: string) => void;
8188
}) => {
8289
const mountedRef = useRef(true);
8390

@@ -120,8 +127,8 @@ const DropdownView = React.memo((props: {
120127
const buttonStyle = useStyle(ButtonStyle);
121128

122129
const menu = useMemo(() => (
123-
<DropdownMenu items={items} options={props.options} />
124-
), [items, props.options]);
130+
<DropdownMenu items={items} options={props.options} onEvent={props.onEvent} />
131+
), [items, props.options, props.onEvent]);
125132

126133
return (
127134
<Dropdown
@@ -183,6 +190,7 @@ export const ColumnDropdownComp = (function () {
183190
{children.options.propertyView({
184191
title: trans("optionsControl.optionList"),
185192
})}
193+
{children.onEvent.propertyView()}
186194
</>
187195
);
188196
})

client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinkComp.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@ import { disabledPropertyView } from "comps/utils/propertyUtils";
1111
import styled, { css } from "styled-components";
1212
import { styleControl } from "comps/controls/styleControl";
1313
import { TableColumnLinkStyle } from "comps/controls/styleControlConstants";
14+
import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl";
1415

1516
export const ColumnValueTooltip = trans("table.columnValueTooltip");
1617

18+
const LinkEventOptions = [clickEvent] as const;
19+
1720
const childrenMap = {
1821
text: StringControl,
19-
onClick: ActionSelectorControlInContext,
22+
onEvent: eventHandlerControl(LinkEventOptions),
2023
disabled: BoolCodeControl,
2124
style: styleControl(TableColumnLinkStyle),
2225
};
@@ -34,12 +37,12 @@ const StyledLink = styled.a<{ $disabled: boolean }>`
3437
`;
3538

3639
// Memoized link component
37-
export const ColumnLink = React.memo(({ disabled, label, onClick }: { disabled: boolean; label: string; onClick?: () => void }) => {
40+
export const ColumnLink = React.memo(({ disabled, label, onEvent }: { disabled: boolean; label: string; onEvent?: (eventName: string) => void }) => {
3841
const handleClick = useCallback(() => {
39-
if (!disabled && onClick) {
40-
onClick();
42+
if (!disabled && onEvent) {
43+
onEvent("click");
4144
}
42-
}, [disabled, onClick]);
45+
}, [disabled, onEvent]);
4346

4447
return (
4548
<StyledLink
@@ -106,7 +109,7 @@ export const LinkComp = (function () {
106109
childrenMap,
107110
(props, dispatch) => {
108111
const value = props.changeValue ?? getBaseValue(props, dispatch);
109-
return <ColumnLink disabled={props.disabled} label={value} onClick={props.onClick} />;
112+
return <ColumnLink disabled={props.disabled} label={value} onEvent={props.onEvent} />;
110113
},
111114
(nodeValue) => nodeValue.text.value,
112115
getBaseValue
@@ -125,10 +128,7 @@ export const LinkComp = (function () {
125128
tooltip: ColumnValueTooltip,
126129
})}
127130
{disabledPropertyView(children)}
128-
{children.onClick.propertyView({
129-
label: trans("table.action"),
130-
placement: "table",
131-
})}
131+
{children.onEvent.propertyView()}
132132
</>
133133
))
134134
.setStylePropertyViewFn((children) => (

client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnLinksComp.tsx

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { trans } from "i18n";
1010
import styled from "styled-components";
1111
import { ColumnLink } from "comps/comps/tableComp/column/columnTypeComps/columnLinkComp";
1212
import { LightActiveTextColor, PrimaryColor } from "constants/style";
13+
import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl";
1314

1415
const MenuLinkWrapper = styled.div`
1516
> a {
@@ -37,33 +38,16 @@ const MenuWrapper = styled.div`
3738
}
3839
`;
3940

40-
// Memoized menu item component
41-
const MenuItem = React.memo(({ option, index }: { option: any; index: number }) => {
42-
const handleClick = useCallback(() => {
43-
if (!option.disabled && option.onClick) {
44-
option.onClick();
45-
}
46-
}, [option.disabled, option.onClick]);
47-
48-
return (
49-
<MenuLinkWrapper>
50-
<ColumnLink
51-
disabled={option.disabled}
52-
label={option.label}
53-
onClick={handleClick}
54-
/>
55-
</MenuLinkWrapper>
56-
);
57-
});
58-
59-
MenuItem.displayName = 'MenuItem';
41+
const LinksEventOptions = [clickEvent] as const;
6042

43+
// Update OptionItem to include event handlers
6144
const OptionItem = new MultiCompBuilder(
6245
{
6346
label: StringControl,
6447
onClick: ActionSelectorControlInContext,
6548
hidden: BoolCodeControl,
6649
disabled: BoolCodeControl,
50+
onEvent: eventHandlerControl(LinksEventOptions),
6751
},
6852
(props) => {
6953
return props;
@@ -79,11 +63,38 @@ const OptionItem = new MultiCompBuilder(
7963
})}
8064
{hiddenPropertyView(children)}
8165
{disabledPropertyView(children)}
66+
{children.onEvent.propertyView()}
8267
</>
8368
);
8469
})
8570
.build();
8671

72+
// Memoized menu item component
73+
const MenuItem = React.memo(({ option, index }: { option: any; index: number }) => {
74+
const handleClick = useCallback(() => {
75+
if (!option.disabled) {
76+
if (option.onClick) {
77+
option.onClick();
78+
}
79+
if (option.onEvent) {
80+
option.onEvent("click");
81+
}
82+
}
83+
}, [option.disabled, option.onClick, option.onEvent]);
84+
85+
return (
86+
<MenuLinkWrapper>
87+
<ColumnLink
88+
disabled={option.disabled}
89+
label={option.label}
90+
onEvent={handleClick}
91+
/>
92+
</MenuLinkWrapper>
93+
);
94+
});
95+
96+
MenuItem.displayName = 'MenuItem';
97+
8798
// Memoized menu component
8899
const LinksMenu = React.memo(({ options }: { options: any[] }) => {
89100
const mountedRef = useRef(true);

client/packages/lowcoder/src/comps/comps/tableComp/column/columnTypeComps/columnSelectComp.tsx

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import React, { useState, useRef, useEffect, useCallback, useMemo } from "react";
22

33
import { SelectUIView } from "comps/comps/selectInputComp/selectCompConstants";
4-
import { SelectOptionControl } from "comps/controls/optionsControl";
5-
import { StringControl } from "comps/controls/codeControl";
4+
import { StringControl, BoolCodeControl } from "comps/controls/codeControl";
5+
import { IconControl } from "comps/controls/iconControl";
6+
import { MultiCompBuilder } from "comps/generators";
7+
import { optionsControl } from "comps/controls/optionsControl";
8+
import { disabledPropertyView, hiddenPropertyView } from "comps/utils/propertyUtils";
69

710
import { trans } from "i18n";
811
import { ColumnTypeCompBuilder, ColumnTypeViewFn } from "../columnTypeCompBuilder";
912
import { ColumnValueTooltip } from "../simpleColumnTypeComps";
1013
import { styled } from "styled-components";
14+
import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl";
1115

1216
const Wrapper = styled.div`
1317
display: inline-flex;
@@ -75,9 +79,43 @@ const Wrapper = styled.div`
7579
}
7680
`;
7781

82+
const SelectOptionEventOptions = [clickEvent] as const;
83+
84+
// Create a new option type with event handlers for each option
85+
const SelectOptionWithEvents = new MultiCompBuilder(
86+
{
87+
value: StringControl,
88+
label: StringControl,
89+
prefixIcon: IconControl,
90+
disabled: BoolCodeControl,
91+
hidden: BoolCodeControl,
92+
onEvent: eventHandlerControl(SelectOptionEventOptions),
93+
},
94+
(props) => props
95+
)
96+
.setPropertyViewFn((children) => (
97+
<>
98+
{children.label.propertyView({ label: trans("label") })}
99+
{children.value.propertyView({ label: trans("value") })}
100+
{children.prefixIcon.propertyView({ label: trans("button.prefixIcon") })}
101+
{disabledPropertyView(children)}
102+
{hiddenPropertyView(children)}
103+
{children.onEvent.propertyView()}
104+
</>
105+
))
106+
.build();
107+
108+
const SelectOptionWithEventsControl = optionsControl(SelectOptionWithEvents, {
109+
initOptions: [
110+
{ label: trans("optionsControl.optionI", { i: 1 }), value: "1" },
111+
{ label: trans("optionsControl.optionI", { i: 2 }), value: "2" },
112+
],
113+
uniqField: "value",
114+
});
115+
78116
const childrenMap = {
79117
text: StringControl,
80-
options: SelectOptionControl,
118+
options: SelectOptionWithEventsControl,
81119
};
82120

83121
const getBaseValue: ColumnTypeViewFn<typeof childrenMap, string, string> = (props) => props.text;
@@ -106,7 +144,13 @@ const SelectEdit = React.memo((props: SelectEditProps) => {
106144
if (!mountedRef.current) return;
107145
props.onChange(val);
108146
setCurrentValue(val);
109-
}, [props.onChange]);
147+
148+
// Trigger the specific option's event handler
149+
const selectedOption = props.options.find(option => option.value === val);
150+
if (selectedOption && selectedOption.onEvent) {
151+
selectedOption.onEvent("click");
152+
}
153+
}, [props.onChange, props.options]);
110154

111155
const handleEvent = useCallback(async (eventName: string) => {
112156
if (!mountedRef.current) return [] as unknown[];

client/packages/lowcoder/src/comps/comps/tableComp/column/simpleColumnTypeComps.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import React, { useCallback, useEffect, useMemo } from "react";
1313
import { CSSProperties } from "react";
1414
import { RecordConstructorToComp } from "lowcoder-core";
1515
import { ToViewReturn } from "@lowcoder-ee/comps/generators/multi";
16+
import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl";
1617

1718
export const ColumnValueTooltip = trans("table.columnValueTooltip");
1819

@@ -31,10 +32,12 @@ export const ButtonTypeOptions = [
3132
},
3233
] as const;
3334

35+
const ButtonEventOptions = [clickEvent] as const;
36+
3437
const childrenMap = {
3538
text: StringControl,
3639
buttonType: dropdownControl(ButtonTypeOptions, "primary"),
37-
onClick: ActionSelectorControlInContext,
40+
onEvent: eventHandlerControl(ButtonEventOptions),
3841
loading: BoolCodeControl,
3942
disabled: BoolCodeControl,
4043
prefixIcon: IconControl,
@@ -49,8 +52,8 @@ const ButtonStyled = React.memo(({ props }: { props: ToViewReturn<RecordConstruc
4952
const iconOnly = !hasText && (hasPrefixIcon || hasSuffixIcon);
5053

5154
const handleClick = useCallback((e: React.MouseEvent) => {
52-
props.onClick?.();
53-
}, [props.onClick]);
55+
props.onEvent("click");
56+
}, [props.onEvent]);
5457

5558
const buttonStyle = useMemo(() => ({
5659
margin: 0,
@@ -100,10 +103,7 @@ export const ButtonComp = (function () {
100103
})}
101104
{loadingPropertyView(children)}
102105
{disabledPropertyView(children)}
103-
{children.onClick.propertyView({
104-
label: trans("table.action"),
105-
placement: "table",
106-
})}
106+
{children.onEvent.propertyView()}
107107
</>
108108
))
109109
.build();

0 commit comments

Comments
 (0)