Skip to content

Commit f6bb40f

Browse files
author
FalkWolsky
committed
Steps Component finalized
1 parent 6987550 commit f6bb40f

File tree

5 files changed

+168
-83
lines changed

5 files changed

+168
-83
lines changed

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

+104-68
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ import { BoolCodeControl } from "comps/controls/codeControl";
33
import { BoolControl } from "comps/controls/boolControl";
44
import { stringExposingStateControl, numberExposingStateControl } from "comps/controls/codeStateControl";
55
import { ChangeEventHandlerControl } from "comps/controls/eventHandlerControl";
6-
import { LabelControl } from "comps/controls/labelControl";
76
import { StepOptionControl } from "comps/controls/optionsControl";
87
import { styleControl } from "comps/controls/styleControl";
9-
import { StepsStyle, StepsStyleType } from "comps/controls/styleControlConstants";
8+
import { StepsStyle, StepsStyleType, heightCalculator, widthCalculator, marginCalculator } from "comps/controls/styleControlConstants";
109
import styled, { css } from "styled-components";
11-
import { UICompBuilder, withDefault } from "../../generators";
10+
import { UICompBuilder } from "../../generators";
1211
import { CommonNameConfig, NameConfig, withExposingConfigs } from "../../generators/withExposing";
1312
import { selectDivRefMethods, } from "./selectInputConstants";
1413
import { Section, sectionNames } from "lowcoder-design";
@@ -17,7 +16,6 @@ import { trans } from "i18n";
1716
import { hasIcon } from "comps/utils";
1817
import { RefControl } from "comps/controls/refControl";
1918
import { dropdownControl } from "comps/controls/dropdownControl";
20-
2119
import { useContext, useState, useEffect } from "react";
2220
import { EditorContext } from "comps/editorState";
2321

@@ -79,14 +77,16 @@ const statusOptions = [
7977
]
8078

8179
const StepsChildrenMap = {
82-
initialValue: numberExposingStateControl("0"),
80+
initialValue: numberExposingStateControl("1"),
8381
value: stringExposingStateControl("value"),
84-
stepsStatus : stringExposingStateControl("process"),
82+
stepStatus : stringExposingStateControl("process"),
83+
stepPercent: numberExposingStateControl("60"),
8584
size: dropdownControl(sizeOptions, "default"),
8685
displayType : dropdownControl(typeOptions, "default"),
8786
direction: dropdownControl(directionOptions, "horizontal"),
8887
showDots : BoolControl,
8988
showIcons : BoolControl,
89+
selectable : BoolControl,
9090
labelPlacement: dropdownControl(directionOptions, "horizontal"),
9191
disabled: BoolCodeControl,
9292
onEvent: ChangeEventHandlerControl,
@@ -98,82 +98,108 @@ const StepsChildrenMap = {
9898
let StepControlBasicComp = (function () {
9999
return new UICompBuilder(StepsChildrenMap, (props) => {
100100

101-
// enabling user interaction to change the current step
102-
const [current, setCurrent] = useState(0);
101+
const StyledWrapper = styled.div<{ style: StepsStyleType }>`
102+
min-height: 24px;
103+
max-width: ${widthCalculator(props.style.margin)};
104+
max-height: ${heightCalculator(props.style.margin)};
105+
display: flex;
106+
flex-direction: column;
107+
justify-content: center;
108+
align-items: center;
109+
text-decoration: ${props.style.textDecoration};
110+
font-style: ${props.style.fontStyle};
111+
font-weight: ${props.style.textWeight};
112+
font-size: ${props.style.textSize};
113+
text-transform: ${props.style.textTransform};
114+
margin: ${props.style.margin};
115+
padding: ${props.style.padding};
116+
background-color: ${props.style.background};
117+
border: ${props.style.borderWidth} solid ${props.style.border};
118+
border-radius: ${props.style.radius};
119+
background-image: ${props.style.backgroundImage};
120+
background-repeat: ${props.style.backgroundImageRepeat};
121+
background-size: ${props.style.backgroundImageSize};
122+
background-position: ${props.style.backgroundImagePosition};
123+
background-origin: ${props.style.backgroundImageOrigin};
124+
.ant-steps-item { padding-top: 5px !important; }
125+
.ant-steps.ant-steps-label-vertical.ant-steps-small .ant-steps-item-icon { margin-top: 17px !important; }
126+
.ant-steps.ant-steps-label-vertical.ant-steps-default .ant-steps-item-icon { margin-top: 12px !important; }
127+
.ant-steps.ant-steps-dot .ant-steps-item-process .ant-steps-icon .ant-steps-icon-dot { margin-top: 4px !important; }
128+
.ant-steps.ant-steps-default .ant-steps-item-icon .ant-steps-icon-dot { margin-top: 9px !important; }
129+
.ant-steps.ant-steps-small .ant-steps-item-icon .ant-steps-icon-dot { margin-top: 4px !important; }
130+
.ant-steps.ant-steps-dot .ant-steps-item-title { margin-top: 10px !important; }
131+
.ant-steps.ant-steps-default.ant-steps-with-progress.ant-steps-label-horizontal .ant-steps-item.ant-steps-item-custom div.ant-steps-item-icon { margin-top:4px !important; }
132+
.ant-steps.ant-steps-default.ant-steps-with-progress.ant-steps-label-vertical .ant-steps-item.ant-steps-item-custom div.ant-steps-item-icon { margin-top:17px !important; }
133+
.ant-steps.ant-steps-dot.ant-steps-small.ant-steps-with-progress .ant-steps-item-icon .ant-progress { inset-block-start: -8px !important; inset-inline-start: -11px !important; }
134+
.ant-steps.ant-steps-dot.ant-steps-default.ant-steps-with-progress .ant-steps-item-icon .ant-progress { inset-block-start: -7px !important; inset-inline-start: -13px !important; }
135+
.ant-steps.ant-steps-small.ant-steps-with-progress .ant-steps-item:not(.ant-steps-item-custom) .ant-progress { inset-block-start: -5px !important; inset-inline-start: -5px !important; }
136+
.ant-steps.ant-steps-default.ant-steps-with-progress .ant-steps-item:not(.ant-steps-item-custom) .ant-progress { inset-block-start: -5px !important; inset-inline-start: -5px !important; }
137+
.ant-steps.ant-steps-small.ant-steps-with-progress .ant-steps-item.ant-steps-item-custom .ant-progress { inset-block-start: -5px !important; inset-inline-start: -10px !important; }
138+
.ant-steps.ant-steps-default.ant-steps-with-progress .ant-steps-item.ant-steps-item-custom .ant-progress { inset-block-start: -4px !important; inset-inline-start: -13px !important; }
139+
`;
140+
141+
const [current, setCurrent] = useState(props.initialValue.value - 1); // Convert 1-based index to 0-based.
103142

104-
// updating the state of current by the expose value
105143
useEffect(() => {
106-
setCurrent(Number(props.value.value));
144+
const newValue = Number(props.value.value);
145+
setCurrent(newValue - 1); // Adjust for 0-based index.
107146
}, [props.value.value]);
108147

109-
110-
const onChange = (current: number) => {
111-
setCurrent(current);
112-
if (props.options[current]?.value !== undefined) {
113-
props.value.onChange(props.options[current].value+"");
148+
const onChange = (index: number) => {
149+
if (props.selectable == false) return;
150+
const newIndex = Math.max(0, index);
151+
setCurrent(newIndex);
152+
if (props.options[newIndex]?.value !== undefined) {
153+
props.value.onChange(newIndex + 1 + ""); // Convert back to 1-based index for display.
114154
props.onEvent("change");
115155
}
116156
};
117157

118-
// margin-top: 17px; is important cause the dots where placed wrong.
119-
/*
120-
.ant-steps.ant-steps-small .ant-steps-item-icon {
121-
margin-top: 17px;
122-
}
123-
*/
124-
const StepsWrapper = styled.div`
125-
width: 100%;
126-
min-height: 24px;
127-
128-
`;
129-
130158
return (
131-
<StepsWrapper ref={props.viewRef}>
132159
<ConfigProvider
133160
theme={{
134-
components: {
135-
Steps: {
136-
colorPrimary: '#00b96b',
137-
algorithm: true,
138-
}
139-
},
161+
token: {
162+
colorPrimary: props.style.activeBackground,
163+
colorText: props.style.titleText,
164+
colorTextDescription: props.style.text,
165+
fontFamily: props.style.fontFamily,
166+
}
140167
}}
141168
>
142-
<Steps
143-
initial={Number(props.initialValue.value) - 1}
144-
current={current}
145-
onChange={(current) => {
146-
onChange(current);
147-
}}
148-
percent={60}
149-
status={props.stepsStatus.value as "error" | "finish" | "process" | "wait"}
150-
type={props.displayType}
151-
size={props.size}
152-
labelPlacement={props.labelPlacement}
153-
progressDot={props.showDots}
154-
direction={props.direction}
155-
>
156-
{props.options.map((option, index) => (
157-
<Steps.Step
158-
key={index}
159-
title={option.label}
160-
subTitle={option.subTitle}
161-
description={option.description}
162-
status={option.status as "error" | "finish" | "wait" | "process" | undefined}
163-
icon={props.showIcons && hasIcon(option.icon) && option.icon || undefined}
164-
/>
165-
))}
166-
</Steps>
169+
<StyledWrapper style={props.style}>
170+
<Steps
171+
initial={props.initialValue.value -1}
172+
current={current}
173+
onChange={onChange}
174+
percent={props.stepPercent.value}
175+
status={props.stepStatus.value as "error" | "finish" | "process" | "wait"}
176+
type={props.displayType}
177+
size={props.size}
178+
labelPlacement={props.labelPlacement}
179+
progressDot={props.showDots}
180+
direction={props.direction}
181+
>
182+
{props.options.map((option, index) => (
183+
<Steps.Step
184+
key={index}
185+
title={option.label}
186+
subTitle={option.subTitle}
187+
description={option.description}
188+
status={option.status as "error" | "finish" | "wait" | "process" | undefined}
189+
icon={props.showIcons && hasIcon(option.icon) && option.icon || undefined}
190+
/>
191+
))}
192+
</Steps>
193+
</StyledWrapper>
167194
</ConfigProvider>
168-
</StepsWrapper>
169195
);
170196

171197
})
172198
.setPropertyViewFn((children) => (
173199
<>
174200
<Section name={sectionNames.basic}>
175201
{children.options.propertyView({})}
176-
{children.initialValue.propertyView({ label: trans("step.initialValue") })}
202+
{children.initialValue.propertyView({ label: trans("step.initialValue"), tooltip : trans("step.initialValueTooltip")})}
177203
</Section>
178204

179205
{["logic", "both"].includes(useContext(EditorContext).editorModeStatus) && (
@@ -182,7 +208,9 @@ let StepControlBasicComp = (function () {
182208
{children.onEvent.getPropertyView()}
183209
{disabledPropertyView(children)}
184210
{hiddenPropertyView(children)}
185-
{children.stepsStatus.propertyView({label: trans("step.status")})}
211+
{children.stepStatus.propertyView({label: trans("step.status")})}
212+
{children.stepPercent.propertyView({label: trans("step.percent")})}
213+
{children.selectable.propertyView({label: trans("step.selectable")})}
186214
</Section></>
187215
)}
188216

@@ -200,12 +228,18 @@ let StepControlBasicComp = (function () {
200228
label: trans("step.direction"),
201229
radioButton: true,
202230
})}
203-
{children.labelPlacement.propertyView({
204-
label: trans("step.labelPlacement"),
205-
radioButton: true,
206-
})}
207-
{children.showDots.propertyView({label: trans("step.showDots")})}
208-
{children.showIcons.propertyView({label: trans("step.showIcons")})}
231+
{ children.direction.getView() == "horizontal" &&
232+
children.labelPlacement.propertyView({
233+
label: trans("step.labelPlacement"),
234+
radioButton: true,
235+
})
236+
}
237+
{ children.displayType.getView() != "inline" && !children.showIcons.getView() && (
238+
children.showDots.propertyView({label: trans("step.showDots")}
239+
))}
240+
{ children.displayType.getView() != "inline" && !children.showDots.getView() && (
241+
children.showIcons.propertyView({label: trans("step.showIcons")}
242+
))}
209243
</Section>
210244
)}
211245

@@ -222,5 +256,7 @@ let StepControlBasicComp = (function () {
222256

223257
export const StepComp = withExposingConfigs(StepControlBasicComp, [
224258
new NameConfig("value", trans("step.valueDesc")),
259+
new NameConfig("stepStatus", trans("step.status") ),
260+
new NameConfig("stepPercent", trans("step.percent")),
225261
...CommonNameConfig,
226262
]);

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ StepOption = class extends StepOption implements OptionCompProperty {
651651
propertyView(param: { autoMap?: boolean }) {
652652
return (
653653
<>
654-
{this.children.value.propertyView({ label: trans("stepOptionsControl.value") })}
654+
{this.children.value.propertyView({ label: trans("stepOptionsControl.value"), tooltip: trans("stepOptionsControl.valueTooltip") })}
655655
{this.children.label.propertyView({ label: trans("stepOptionsControl.title") })}
656656
{this.children.subTitle.propertyView({ label: trans("stepOptionsControl.subTitle") })}
657657
{this.children.description.propertyView({ label: trans("stepOptionsControl.description") })}

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

+33-13
Original file line numberDiff line numberDiff line change
@@ -964,26 +964,46 @@ export const SegmentStyle = [
964964
] as const;
965965

966966
export const StepsStyle = [
967-
LABEL,
968-
...STYLING_FIELDS_SEQUENCE.filter((style) => ['border', 'borderWidth'].includes(style.name) === false),
969-
{
970-
name: "indicatorBackground",
971-
label: trans("style.indicatorBackground"),
972-
color: SURFACE_COLOR,
973-
},
974967
{
975-
name: "background",
976-
label: trans("style.background"),
977-
depName: "indicatorBackground",
968+
name: "activeBackground",
969+
label: trans("style.accent"),
970+
depName: "activeBackground",
978971
transformer: handleToSegmentBackground,
979972
},
980973
{
981-
name: "text",
982-
label: trans("text"),
983-
depName: "indicatorBackground",
974+
name: "titleText",
975+
label: trans("title"),
976+
depName: "background",
984977
depType: DEP_TYPE.CONTRAST_TEXT,
985978
transformer: contrastText,
986979
},
980+
...STYLING_FIELDS_SEQUENCE.filter((style) => ['background', 'textSize','textDecoration'].includes(style.name) === false),
981+
getBackground(),
982+
{
983+
name: "backgroundImage",
984+
label: trans("style.backgroundImage"),
985+
backgroundImage: "backgroundImage",
986+
},
987+
{
988+
name: "backgroundImageRepeat",
989+
label: trans("style.backgroundImageRepeat"),
990+
backgroundImageRepeat: "backgroundImageRepeat",
991+
},
992+
{
993+
name: "backgroundImageSize",
994+
label: trans("style.backgroundImageSize"),
995+
backgroundImageSize: "backgroundImageSize",
996+
},
997+
{
998+
name: "backgroundImagePosition",
999+
label: trans("style.backgroundImagePosition"),
1000+
backgroundImagePosition: "backgroundImagePosition",
1001+
},
1002+
{
1003+
name: "backgroundImageOrigin",
1004+
label: trans("style.backgroundImageOrigin"),
1005+
backgroundImageOrigin: "backgroundImageOrigin",
1006+
},
9871007
] as const;
9881008

9891009
const LinkTextStyle = [

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -1260,14 +1260,16 @@ export const en = {
12601260
},
12611261
"stepOptionsControl": {
12621262
"value": "Value / Key",
1263+
"valueTooltip": "Step Value must be a number. For the first Step, it must be equal to the initial value. Numbers must be in consistent and ascending order",
12631264
"title": "Step Title",
12641265
"subTitle": "Step Subtitle",
12651266
"description": "Step Description",
12661267
"status": "Step Status",
12671268
"icon": "Step Icon",
12681269
},
12691270
"step" : {
1270-
"initialValue": "Start Numbers from",
1271+
"initialValue": "Start Numbers at",
1272+
"initialValueTooltip": "Where to start the visual Numbering. Must be 1 or higher.",
12711273
"valueDesc": "Current Value",
12721274
"size" : "Steps Size",
12731275
"sizeSmall" : "Small",
@@ -1289,6 +1291,7 @@ export const en = {
12891291
"showDots" : "Show Dots instead Symbols",
12901292
"showIcons" : "Show Icons instead Symbols",
12911293
"responsive" : "Responsive",
1294+
"selectable" : "Selectable",
12921295
},
12931296
"radio": {
12941297
"options": "Options",

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

+26
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,32 @@ optionsControl: {
11861186
"description": "描述",
11871187
"status": "状态",
11881188
},
1189+
"step" : {
1190+
"initialValue": "初始值",
1191+
"initialValueTooltip": "视觉编号的起始位置。必须是 1 或更高。",
1192+
"valueDesc": "当前价值",
1193+
"size" : "台阶大小",
1194+
"sizeSmall" : "小型",
1195+
"sizeDefault" : "默认值",
1196+
"percent" : "步骤 百分比",
1197+
"type" : "步骤类型",
1198+
"typeDefault" : "标准",
1199+
"typeNavigation" : "导航",
1200+
"typeInline" : "内联",
1201+
"direction" : "步骤 方向",
1202+
"directionVertical" : "垂直",
1203+
"directionHorizontal" : "横向",
1204+
"labelPlacement" : "步骤 标签放置",
1205+
"status" : "步骤状态",
1206+
"statusWait" : "等待",
1207+
"statusProcess" : "过程",
1208+
"statusFinish" : "完成",
1209+
"statusError" : "错误",
1210+
"showDots" : "用圆点代替数字",
1211+
"showIcons" : "显示图标而不是数字",
1212+
"responsive" : "响应式",
1213+
"selectable" : "可选择",
1214+
},
11891215
radio: {
11901216
options: "选项",
11911217
horizontal: "水平",

0 commit comments

Comments
 (0)