Skip to content

Commit 60609a1

Browse files
added showValidationMessageOnEmptyInput flag in input fields
1 parent 172be23 commit 60609a1

File tree

17 files changed

+56
-10
lines changed

17 files changed

+56
-10
lines changed

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

+1
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ let AutoCompleteCompBase = (function () {
285285
labelStyle: props.labelStyle,
286286
inputFieldStyle:props.inputFieldStyle,
287287
animationStyle: props.animationStyle,
288+
showValidationWhenEmpty: props.showValidationWhenEmpty,
288289
...validateState,
289290
});
290291
})

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

+9
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import { timeZoneOptions } from "./timeZone";
5656
const EventOptions = [changeEvent, focusEvent, blurEvent] as const;
5757

5858
const validationChildren = {
59+
showValidationWhenEmpty: BoolControl,
5960
required: BoolControl,
6061
minDate: StringControl,
6162
maxDate: StringControl,
@@ -224,6 +225,7 @@ export const datePickerControl = new UICompBuilder(childrenMap, (props) => {
224225
suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon}
225226
/>
226227
),
228+
showValidationWhenEmpty: props.showValidationWhenEmpty,
227229
...validate(props),
228230
});
229231
})
@@ -247,6 +249,9 @@ export const datePickerControl = new UICompBuilder(childrenMap, (props) => {
247249
{(useContext(EditorContext).editorModeStatus === "logic" || useContext(EditorContext).editorModeStatus === "both") && (
248250
<><Section name={sectionNames.validation}>
249251
{requiredPropertyView(children)}
252+
{children.showValidationWhenEmpty.propertyView({
253+
label: trans("prop.showEmptyValidation")
254+
})}
250255
{dateValidationFields(children)}
251256
{timeValidationFields(children)}
252257
{children.customRule.propertyView({})}
@@ -381,6 +386,7 @@ export const dateRangeControl = (function () {
381386
children: children,
382387
inputFieldStyle:props.inputFieldStyle,
383388
onMouseDown: (e) => e.stopPropagation(),
389+
showValidationWhenEmpty: props.showValidationWhenEmpty,
384390
...(startResult.validateStatus !== "success"
385391
? startResult
386392
: endResult.validateStatus !== "success"
@@ -413,6 +419,9 @@ export const dateRangeControl = (function () {
413419
{(useContext(EditorContext).editorModeStatus === "logic" || useContext(EditorContext).editorModeStatus === "both") && (
414420
<><Section name={sectionNames.validation}>
415421
{requiredPropertyView(children)}
422+
{children.showValidationWhenEmpty.propertyView({
423+
label: trans("prop.showEmptyValidation")
424+
})}
416425
{dateValidationFields(children)}
417426
{timeValidationFields(children)}
418427
{children.customRule.propertyView({})}

client/packages/lowcoder/src/comps/comps/dateComp/timeComp.tsx

+10-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import { timeZoneOptions } from "./timeZone";
5959
const EventOptions = [changeEvent, focusEvent, blurEvent] as const;
6060

6161
const validationChildren = {
62+
showValidationWhenEmpty: BoolControl,
6263
required: BoolControl,
6364
minTime: StringControl,
6465
maxTime: StringControl,
@@ -116,7 +117,7 @@ function validate(
116117
}
117118

118119
const current = dayjs(props.value.value, TimeParser);
119-
if (props.required && !current.isValid()) {
120+
if (props.required && (!Boolean(props.value.value) || !current.isValid())) {
120121
return { validateStatus: "error", help: trans("prop.required") };
121122
}
122123
return { validateStatus: "success" };
@@ -197,6 +198,7 @@ export const timePickerControl = new UICompBuilder(childrenMap, (props) => {
197198
onBlur={() => props.onEvent("blur")}
198199
suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon} />
199200
),
201+
showValidationWhenEmpty: props.showValidationWhenEmpty,
200202
...validate(props),
201203
});
202204
})
@@ -217,6 +219,9 @@ export const timePickerControl = new UICompBuilder(childrenMap, (props) => {
217219
{(useContext(EditorContext).editorModeStatus === "logic" || useContext(EditorContext).editorModeStatus === "both") && (
218220
<><Section name={sectionNames.validation}>
219221
{requiredPropertyView(children)}
222+
{children.showValidationWhenEmpty.propertyView({
223+
label: trans("prop.showEmptyValidation")
224+
})}
220225
{minTimePropertyView(children)}
221226
{maxTimePropertyView(children)}
222227
{children.customRule.propertyView({})}
@@ -338,6 +343,7 @@ export const timeRangeControl = (function () {
338343
animationStyle:props.animationStyle,
339344
children: children,
340345
onMouseDown: (e) => e.stopPropagation(),
346+
showValidationWhenEmpty: props.showValidationWhenEmpty,
341347
...(startResult.validateStatus !== "success"
342348
? startResult
343349
: endResult.validateStatus !== "success"
@@ -366,6 +372,9 @@ export const timeRangeControl = (function () {
366372
{(useContext(EditorContext).editorModeStatus === "logic" || useContext(EditorContext).editorModeStatus === "both") && (
367373
<><Section name={sectionNames.validation}>
368374
{requiredPropertyView(children)}
375+
{children.showValidationWhenEmpty.propertyView({
376+
label: trans("prop.showEmptyValidation")
377+
})}
369378
{minTimePropertyView(children)}
370379
{maxTimePropertyView(children)}
371380
{children.customRule.propertyView({})}

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

+3
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ const childrenMap = {
268268
inputFieldStyle: styleControl(InputLikeStyle , 'inputFieldStyle'),
269269
// validation
270270
required: BoolControl,
271+
showValidationWhenEmpty: BoolControl,
271272
min: UndefinedNumberControl,
272273
max: UndefinedNumberControl,
273274
customRule: CustomRuleControl,
@@ -389,6 +390,7 @@ let NumberInputTmpComp = (function () {
389390
labelStyle: props.labelStyle,
390391
inputFieldStyle:props.inputFieldStyle,
391392
animationStyle:props.animationStyle,
393+
showValidationWhenEmpty: props.showValidationWhenEmpty,
392394
...validate(props),
393395
});
394396
})
@@ -405,6 +407,7 @@ let NumberInputTmpComp = (function () {
405407
{(useContext(EditorContext).editorModeStatus === "logic" || useContext(EditorContext).editorModeStatus === "both") && (
406408
<><Section name={sectionNames.validation}>
407409
{requiredPropertyView(children)}
410+
{children.showValidationWhenEmpty.propertyView({label: trans("prop.showEmptyValidation")})}
408411
{children.min.propertyView({ label: trans("prop.minimum") })}
409412
{children.max.propertyView({ label: trans("prop.maximum") })}
410413
{children.customRule.propertyView({})}

client/packages/lowcoder/src/comps/comps/numberInputComp/rangeSliderComp.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const RangeSliderBasicComp = (function () {
2222
animationStyle:props.animationStyle,
2323
children: (
2424
<SliderWrapper
25-
vertical={props.vertical}
25+
$vertical={Boolean(props.vertical)}
2626
onMouseDown={(e: any) => {
2727
e.stopPropagation();
2828
return false;
@@ -35,7 +35,7 @@ const RangeSliderBasicComp = (function () {
3535
value={[props.start.value, props.end.value]}
3636
$style={props.inputFieldStyle}
3737
style={{ margin: 0 }}
38-
vertical={props.vertical || false}
38+
$vertical={Boolean(props.vertical) || false}
3939
onChange={([start, end]) => {
4040
props.start.onChange(start);
4141
props.end.onChange(end);

client/packages/lowcoder/src/comps/comps/numberInputComp/sliderComp.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const SliderBasicComp = (function () {
2626
animationStyle:props.animationStyle,
2727
children: (
2828
<SliderWrapper
29-
vertical={props.vertical}
29+
$vertical={Boolean(props.vertical)}
3030
onMouseDown={(e: any) => {
3131
e.stopPropagation();
3232
return false;
@@ -38,7 +38,7 @@ const SliderBasicComp = (function () {
3838
value={props.value.value}
3939
$style={props.inputFieldStyle}
4040
style={{margin: 0}}
41-
vertical={props.vertical || false}
41+
$vertical={Boolean(props.vertical) || false}
4242
onChange={(e) => {
4343
props.value.onChange(e);
4444
props.onEvent("change");

client/packages/lowcoder/src/comps/comps/numberInputComp/sliderCompConstants.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,11 @@ const getStyle = (style: SliderStyleType, vertical: boolean) => {
6060
`;
6161
};
6262

63-
export const SliderStyled = styled(Slider)<{ $style: SliderStyleType, vertical: boolean }>`
64-
${(props) => props.$style && getStyle(props.$style, props.vertical)}
63+
export const SliderStyled = styled(Slider)<{ $style: SliderStyleType, $vertical: boolean }>`
64+
${(props) => props.$style && getStyle(props.$style, props.$vertical)}
6565
`;
6666

67-
export const SliderWrapper = styled.div<{ vertical: boolean }>`
67+
export const SliderWrapper = styled.div<{ $vertical: boolean }>`
6868
width: 100%;
6969
display: inline-flex;
7070
align-items: center;

client/packages/lowcoder/src/comps/comps/selectInputComp/selectComp.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ let SelectBasicComp = (function () {
5555
dispatch={dispatch}
5656
/>
5757
),
58+
showValidationWhenEmpty: props.showValidationWhenEmpty,
5859
...validateState,
5960
});
6061
})

client/packages/lowcoder/src/comps/comps/selectInputComp/selectInputConstants.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { blurMethod, focusWithOptions } from "comps/utils/methodUtils";
1818

1919
export const SelectInputValidationChildren = {
2020
required: BoolControl,
21+
showValidationWhenEmpty: BoolControl,
2122
customRule: CustomRuleControl,
2223
};
2324
type ValidationComp = RecordConstructorToComp<typeof SelectInputValidationChildren>;
@@ -122,6 +123,9 @@ export const SelectInputInvalidConfig = depsConfig<
122123
export const SelectInputValidationSection = (children: ValidationComp) => (
123124
<Section name={sectionNames.validation}>
124125
{requiredPropertyView(children)}
126+
{children.showValidationWhenEmpty.propertyView({
127+
label: trans("prop.showEmptyValidation"),
128+
})}
125129
{children.customRule.propertyView({})}
126130
</Section>
127131
);

client/packages/lowcoder/src/comps/comps/textInputComp/inputComp.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ let InputBasicComp = new UICompBuilder(childrenMap, (props) => {
7878
labelStyle: props.labelStyle,
7979
inputFieldStyle:props.inputFieldStyle,
8080
animationStyle:props.animationStyle,
81+
showValidationWhenEmpty: props.showValidationWhenEmpty,
8182
...validateState,
8283
});
8384
})

client/packages/lowcoder/src/comps/comps/textInputComp/passwordComp.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ let PasswordTmpComp = (function () {
8282
labelStyle: props.labelStyle,
8383
inputFieldStyle:props.inputFieldStyle,
8484
animationStyle:props.animationStyle,
85+
showValidationWhenEmpty: props.showValidationWhenEmpty,
8586
...validateState,
8687
});
8788
})
@@ -106,6 +107,7 @@ let PasswordTmpComp = (function () {
106107
{children.prefixIcon.propertyView({ label: trans("button.prefixIcon") })}
107108
</Section><Section name={sectionNames.validation}>
108109
{requiredPropertyView(children)}
110+
{children.showValidationWhenEmpty.propertyView({label: trans("prop.showEmptyValidation")})}
109111
{regexPropertyView(children)}
110112
{minLengthPropertyView(children)}
111113
{maxLengthPropertyView(children)}

client/packages/lowcoder/src/comps/comps/textInputComp/textAreaComp.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ let TextAreaTmpComp = (function () {
9999
style: props.style,
100100
labelStyle: props.labelStyle,
101101
animationStyle: props.animationStyle,
102+
showValidationWhenEmpty: props.showValidationWhenEmpty,
102103
...validateState,
103104
});
104105
})

client/packages/lowcoder/src/comps/comps/textInputComp/textInputConstants.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ export const textInputChildren = {
144144

145145
// validation
146146
required: BoolControl,
147+
showValidationWhenEmpty: BoolControl,
147148
minLength: NumberControl,
148149
maxLength: NumberControl,
149150
validationType: dropdownControl(TextInputValidationOptions, "Text"),
@@ -226,6 +227,7 @@ export const TextInputInteractionSection = (children: TextInputComp) => (
226227
export const TextInputValidationSection = (children: TextInputComp) => (
227228
<Section name={sectionNames.validation}>
228229
{requiredPropertyView(children)}
230+
{children.showValidationWhenEmpty.propertyView({label: trans("prop.showEmptyValidation")})}
229231
{children.validationType.propertyView({ label: trans("prop.textType") })}
230232
{valueInfoMap[children.validationType.getView()]?.extra === undefined &&
231233
regexPropertyView(children)}

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

+1
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ const TreeCompView = (props: RecordConstructorToView<typeof childrenMap>) => {
130130
</ScrollBar>
131131
</Container>
132132
),
133+
showValidationWhenEmpty: props.showValidationWhenEmpty,
133134
});
134135
};
135136

client/packages/lowcoder/src/comps/comps/treeComp/treeSelectComp.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ const TreeCompView = (
141141
onBlur={() => props.onEvent("blur")}
142142
/>
143143
),
144+
showValidationWhenEmpty: props.showValidationWhenEmpty,
144145
});
145146
};
146147

client/packages/lowcoder/src/comps/controls/labelControl.tsx

+12-2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type LabelViewProps = Pick<FormItemProps, "required" | "help" | "validateStatus"
2626
childrenInputFieldStyle?: Record<string, string>;
2727
animationStyle?: Record<string, string>;
2828
onMouseDown?: React.MouseEventHandler<HTMLDivElement>;
29+
showValidationWhenEmpty?: boolean;
2930
};
3031

3132
const StyledStarIcon = styled(StarIcon)`
@@ -77,7 +78,7 @@ const MainWrapper = styled.div<{
7778
props.$position === "column" && props.$hasLabel ? "calc(100% - 4px)" : "100%"};
7879
display: flex;
7980
align-items: ${(props) => (props.$position === "row" ? "center" : "start")};
80-
flex-shrink: 0;
81+
flex-shrink: 1;
8182
`;
8283

8384
const LabelWrapper = styled.div<{
@@ -178,6 +179,12 @@ export const LabelControl = (function () {
178179

179180
return new MultiCompBuilder(childrenMap, (props) => (args: LabelViewProps) =>
180181
{
182+
const inputValue = (
183+
((args.children as ReactElement)?.props?.children as ReactElement)?.props?.value // text area comp
184+
?? (args.children as ReactElement)?.props.value?.value // number input comp
185+
?? (args.children as ReactElement)?.props.value
186+
);
187+
181188
return (
182189
<LabelViewWrapper
183190
$style={args.style}
@@ -245,7 +252,10 @@ export const LabelControl = (function () {
245252
</ChildrenWrapper>
246253
</MainWrapper>
247254

248-
{args.help && Boolean((args.children as ReactElement)?.props.value) && (
255+
{args.help && (
256+
args.showValidationWhenEmpty
257+
|| (!args.showValidationWhenEmpty && Boolean(inputValue))
258+
) && (
249259
<HelpWrapper
250260
$marginLeft={
251261
props.position === "column" || isEmpty(props.text) || props.hidden

client/packages/lowcoder/src/i18n/locales/en.ts

+1
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ export const en = {
163163
"showSearch": "Searchable",
164164
"defaultValue": "Default Value",
165165
"required": "Required Field",
166+
"showEmptyValidation": "Show Validation On Empty/Reset",
166167
"readOnly": "Read Only",
167168
"readOnlyTooltip": "Read-only components appear normal but cannot be modified.",
168169
"minimum": "Minimum",

0 commit comments

Comments
 (0)