Skip to content

Commit 4aa6d92

Browse files
committed
Merge branch 'dev' of github.com:lowcoder-org/lowcoder into feat/1289-customize-drawer-close
2 parents 99ce13d + ba30103 commit 4aa6d92

27 files changed

+403
-78
lines changed

client/packages/lowcoder/src/comps/comps/buttonComp/scannerComp.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import React, {
3030
useState,
3131
useContext,
3232
} from "react";
33-
import { arrayStringExposingStateControl } from "comps/controls/codeStateControl";
33+
import { arrayStringExposingStateControl, stringExposingStateControl } from "comps/controls/codeStateControl";
3434
import { BoolControl } from "comps/controls/boolControl";
3535
import { RefControl } from "comps/controls/refControl";
3636
import { EditorContext } from "comps/editorState";
@@ -120,6 +120,7 @@ const BarcodeScannerComponent = React.lazy(
120120
const ScannerTmpComp = (function () {
121121
const childrenMap = {
122122
data: arrayStringExposingStateControl("data"),
123+
value: stringExposingStateControl("value"),
123124
text: withDefault(StringControl, trans("scanner.text")),
124125
continuous: BoolControl,
125126
uniqueData: withDefault(BoolControl, true),
@@ -150,17 +151,27 @@ const ScannerTmpComp = (function () {
150151
}, [success, showModal]);
151152

152153
const continuousValue = useRef<string[]>([]);
154+
const seenSetRef = useRef<Set<string>>(new Set());
153155

154156
const handleUpdate = (err: any, result: any) => {
155157
if (result) {
156158
if (props.continuous) {
157-
continuousValue.current = [...continuousValue.current, result.text];
159+
const scannedText: string = result.text;
160+
if (props.uniqueData && seenSetRef.current.has(scannedText)) {
161+
return;
162+
}
163+
continuousValue.current = [...continuousValue.current, scannedText];
164+
if (props.uniqueData) {
165+
seenSetRef.current.add(scannedText);
166+
}
158167
const val = props.uniqueData
159168
? [...new Set(continuousValue.current)]
160169
: continuousValue.current;
170+
props.value.onChange(scannedText);
161171
props.data.onChange(val);
162172
props.onEvent("success");
163173
} else {
174+
props.value.onChange(result.text);
164175
props.data.onChange([result.text]);
165176
setShowModal(false);
166177
setSuccess(true);
@@ -205,6 +216,7 @@ const ScannerTmpComp = (function () {
205216
props.onEvent("click");
206217
setShowModal(true);
207218
continuousValue.current = [];
219+
seenSetRef.current = new Set();
208220
}}
209221
>
210222
<span>{props.text}</span>
@@ -317,6 +329,7 @@ const ScannerTmpComp = (function () {
317329

318330
export const ScannerComp = withExposingConfigs(ScannerTmpComp, [
319331
new NameConfig("data", trans("data")),
332+
new NameConfig("value", trans("value")),
320333
new NameConfig("text", trans("button.textDesc")),
321334
...CommonNameConfig,
322335
]);

client/packages/lowcoder/src/comps/comps/formComp/formComp.tsx

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -390,15 +390,24 @@ let FormTmpComp = class extends FormBaseComp implements IForm {
390390
if (ret.children.initialData !== this.children.initialData) {
391391
// FIXME: kill setTimeout ?
392392
setTimeout(() => {
393-
this.dispatch(
394-
customAction<SetDataAction>(
395-
{
396-
type: "setData",
397-
initialData: (action.value["initialData"] as ValueAndMsg<JSONObject>).value || {},
398-
},
399-
false
400-
)
401-
);
393+
const newInitialData = (action.value["initialData"] as ValueAndMsg<JSONObject>)
394+
.value;
395+
// only setData when initialData has explicit keys.
396+
if (
397+
newInitialData &&
398+
typeof newInitialData === "object" &&
399+
Object.keys(newInitialData).length > 0
400+
) {
401+
this.dispatch(
402+
customAction<SetDataAction>(
403+
{
404+
type: "setData",
405+
initialData: newInitialData,
406+
},
407+
false
408+
)
409+
);
410+
}
402411
}, 1000);
403412
}
404413
return ret;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import { BoolCodeControl, StringControl } from "comps/controls/codeControl";
2+
import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl";
3+
import { MultiCompBuilder } from "comps/generators/multi";
4+
import { dropdownControl } from "comps/controls/dropdownControl";
5+
import { mapOptionsControl } from "comps/controls/optionsControl";
6+
import { trans } from "i18n";
7+
import { navListComp } from "../navItemComp";
8+
import { controlItem } from "lowcoder-design";
9+
import { menuPropertyView } from "./MenuItemList";
10+
11+
export function createNavItemsControl() {
12+
const OptionTypes = [
13+
{ label: trans("prop.manual"), value: "manual" },
14+
{ label: trans("prop.map"), value: "map" },
15+
] as const;
16+
17+
const NavMapOption = new MultiCompBuilder(
18+
{
19+
label: StringControl,
20+
hidden: BoolCodeControl,
21+
disabled: BoolCodeControl,
22+
active: BoolCodeControl,
23+
onEvent: eventHandlerControl([clickEvent]),
24+
},
25+
(props) => props
26+
)
27+
.setPropertyViewFn((children) => (
28+
<>
29+
{children.label.propertyView({ label: trans("label"), placeholder: "{{item}}" })}
30+
{children.active.propertyView({ label: trans("navItemComp.active") })}
31+
{children.hidden.propertyView({ label: trans("hidden") })}
32+
{children.disabled.propertyView({ label: trans("disabled") })}
33+
{children.onEvent.getPropertyView()}
34+
</>
35+
))
36+
.build();
37+
38+
const TmpNavItemsControl = new MultiCompBuilder(
39+
{
40+
optionType: dropdownControl(OptionTypes, "manual"),
41+
manual: navListComp(),
42+
mapData: mapOptionsControl(NavMapOption),
43+
},
44+
(props) => {
45+
return props.optionType === "manual" ? props.manual : props.mapData;
46+
}
47+
)
48+
.setPropertyViewFn(() => {
49+
throw new Error("Method not implemented.");
50+
})
51+
.build();
52+
53+
return class NavItemsControl extends TmpNavItemsControl {
54+
exposingNode() {
55+
return this.children.optionType.getView() === "manual"
56+
? (this.children.manual as any).exposingNode()
57+
: (this.children.mapData as any).exposingNode();
58+
}
59+
60+
propertyView() {
61+
const isManual = this.children.optionType.getView() === "manual";
62+
const content = isManual
63+
? menuPropertyView(this.children.manual as any)
64+
: this.children.mapData.getPropertyView();
65+
66+
return controlItem(
67+
{ searchChild: true },
68+
<>
69+
{this.children.optionType.propertyView({ radioButton: true, type: "oneline" })}
70+
{content}
71+
</>
72+
);
73+
}
74+
};
75+
}
76+
77+

client/packages/lowcoder/src/comps/comps/navComp/navComp.tsx

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { NameConfig, NameConfigHidden, withExposingConfigs } from "comps/generators/withExposing";
2+
import { MultiCompBuilder } from "comps/generators/multi";
23
import { UICompBuilder, withDefault } from "comps/generators";
34
import { Section, sectionNames } from "lowcoder-design";
45
import styled from "styled-components";
56
import { clickEvent, eventHandlerControl } from "comps/controls/eventHandlerControl";
6-
import { StringControl } from "comps/controls/codeControl";
7+
import { BoolCodeControl, StringControl } from "comps/controls/codeControl";
78
import { alignWithJustifyControl } from "comps/controls/alignControl";
89
import { navListComp } from "./navItemComp";
910
import { menuPropertyView } from "./components/MenuItemList";
@@ -22,6 +23,8 @@ import { trans } from "i18n";
2223

2324
import { useContext } from "react";
2425
import { EditorContext } from "comps/editorState";
26+
import { controlItem } from "lowcoder-design";
27+
import { createNavItemsControl } from "./components/NavItemsControl";
2528

2629
type IProps = {
2730
$justify: boolean;
@@ -63,11 +66,12 @@ const Item = styled.div<{
6366
$padding: string;
6467
$textTransform:string;
6568
$textDecoration:string;
69+
$disabled?: boolean;
6670
}>`
6771
height: 30px;
6872
line-height: 30px;
6973
padding: ${(props) => props.$padding ? props.$padding : '0 16px'};
70-
color: ${(props) => (props.$active ? props.$activeColor : props.$color)};
74+
color: ${(props) => props.$disabled ? `${props.$color}80` : (props.$active ? props.$activeColor : props.$color)};
7175
font-weight: ${(props) => (props.$textWeight ? props.$textWeight : 500)};
7276
font-family:${(props) => (props.$fontFamily ? props.$fontFamily : 'sans-serif')};
7377
font-style:${(props) => (props.$fontStyle ? props.$fontStyle : 'normal')};
@@ -77,8 +81,8 @@ const Item = styled.div<{
7781
margin:${(props) => props.$margin ? props.$margin : '0px'};
7882
7983
&:hover {
80-
color: ${(props) => props.$activeColor};
81-
cursor: pointer;
84+
color: ${(props) => props.$disabled ? (props.$active ? props.$activeColor : props.$color) : props.$activeColor};
85+
cursor: ${(props) => props.$disabled ? 'not-allowed' : 'pointer'};
8286
}
8387
8488
.anticon {
@@ -131,41 +135,74 @@ function fixOldStyleData(oldData: any) {
131135
return oldData;
132136
}
133137

138+
function fixOldItemsData(oldData: any) {
139+
if (Array.isArray(oldData)) {
140+
return {
141+
optionType: "manual",
142+
manual: oldData,
143+
};
144+
}
145+
if (oldData && !oldData.optionType && Array.isArray(oldData.manual)) {
146+
return {
147+
optionType: "manual",
148+
manual: oldData.manual,
149+
};
150+
}
151+
return oldData;
152+
}
153+
134154
const childrenMap = {
135155
logoUrl: StringControl,
136156
logoEvent: withDefault(eventHandlerControl(logoEventHandlers), [{ name: "click" }]),
137157
horizontalAlignment: alignWithJustifyControl(),
138158
style: migrateOldData(styleControl(NavigationStyle, 'style'), fixOldStyleData),
139159
animationStyle: styleControl(AnimationStyle, 'animationStyle'),
140-
items: withDefault(navListComp(), [
141-
{
142-
label: trans("menuItem") + " 1",
143-
},
144-
]),
160+
items: withDefault(migrateOldData(createNavItemsControl(), fixOldItemsData), {
161+
optionType: "manual",
162+
manual: [
163+
{
164+
label: trans("menuItem") + " 1",
165+
},
166+
],
167+
}),
145168
};
146169

147170
const NavCompBase = new UICompBuilder(childrenMap, (props) => {
148171
const data = props.items;
149172
const items = (
150173
<>
151-
{data.map((menuItem, idx) => {
152-
const { hidden, label, items, active, onEvent } = menuItem.getView();
174+
{data.map((menuItem: any, idx: number) => {
175+
const isCompItem = typeof menuItem?.getView === "function";
176+
const view = isCompItem ? menuItem.getView() : menuItem;
177+
const hidden = !!view?.hidden;
153178
if (hidden) {
154179
return null;
155180
}
156-
const subMenuItems: Array<{ key: string; label: string }> = [];
181+
182+
const label = view?.label;
183+
const active = !!view?.active;
184+
const onEvent = view?.onEvent;
185+
const disabled = !!view?.disabled;
186+
const subItems = isCompItem ? view?.items : [];
187+
188+
const subMenuItems: Array<{ key: string; label: any; disabled?: boolean }> = [];
157189
const subMenuSelectedKeys: Array<string> = [];
158-
items.forEach((subItem, originalIndex) => {
159-
if (subItem.children.hidden.getView()) {
160-
return;
161-
}
162-
const key = originalIndex + "";
163-
subItem.children.active.getView() && subMenuSelectedKeys.push(key);
164-
subMenuItems.push({
165-
key: key,
166-
label: subItem.children.label.getView(),
190+
191+
if (Array.isArray(subItems)) {
192+
subItems.forEach((subItem: any, originalIndex: number) => {
193+
if (subItem.children.hidden.getView()) {
194+
return;
195+
}
196+
const key = originalIndex + "";
197+
subItem.children.active.getView() && subMenuSelectedKeys.push(key);
198+
subMenuItems.push({
199+
key: key,
200+
label: subItem.children.label.getView(),
201+
disabled: !!subItem.children.disabled.getView(),
202+
});
167203
});
168-
});
204+
}
205+
169206
const item = (
170207
<Item
171208
key={idx}
@@ -180,18 +217,23 @@ const NavCompBase = new UICompBuilder(childrenMap, (props) => {
180217
$textTransform={props.style.textTransform}
181218
$textDecoration={props.style.textDecoration}
182219
$margin={props.style.margin}
183-
onClick={() => onEvent("click")}
220+
$disabled={disabled}
221+
onClick={() => { if (!disabled && onEvent) onEvent("click"); }}
184222
>
185223
{label}
186-
{items.length > 0 && <DownOutlined />}
224+
{Array.isArray(subItems) && subItems.length > 0 && <DownOutlined />}
187225
</Item>
188226
);
189227
if (subMenuItems.length > 0) {
190228
const subMenu = (
191229
<StyledMenu
192230
onClick={(e) => {
193-
const { onEvent: onSubEvent } = items[Number(e.key)]?.getView();
194-
onSubEvent("click");
231+
if (disabled) return;
232+
const subItem = subItems[Number(e.key)];
233+
const isSubDisabled = !!subItem?.children?.disabled?.getView?.();
234+
if (isSubDisabled) return;
235+
const onSubEvent = subItem?.getView()?.onEvent;
236+
onSubEvent && onSubEvent("click");
195237
}}
196238
selectedKeys={subMenuSelectedKeys}
197239
items={subMenuItems}
@@ -201,6 +243,7 @@ const NavCompBase = new UICompBuilder(childrenMap, (props) => {
201243
<Dropdown
202244
key={idx}
203245
popupRender={() => subMenu}
246+
disabled={disabled}
204247
>
205248
{item}
206249
</Dropdown>
@@ -237,7 +280,7 @@ const NavCompBase = new UICompBuilder(childrenMap, (props) => {
237280
return (
238281
<>
239282
<Section name={sectionNames.basic}>
240-
{menuPropertyView(children.items)}
283+
{children.items.propertyView()}
241284
</Section>
242285

243286
{(useContext(EditorContext).editorModeStatus === "logic" || useContext(EditorContext).editorModeStatus === "both") && (

0 commit comments

Comments
 (0)