Skip to content

Commit 3f71caa

Browse files
Merge pull request #1683 from iamfaran/feat/LCS-51-tab-index
[FEAT]: Tab Index for Inputs
2 parents f2b7d10 + 41cb384 commit 3f71caa

File tree

20 files changed

+100
-11
lines changed

20 files changed

+100
-11
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
import styled, { css } from "styled-components";
2121
import { UICompBuilder } from "../../generators";
2222
import { FormDataPropertyView } from "../formComp/formDataConstants";
23-
import { jsonControl } from "comps/controls/codeControl";
23+
import { jsonControl, NumberControl } from "comps/controls/codeControl";
2424
import { dropdownControl } from "comps/controls/dropdownControl";
2525
import {
2626
getStyle,
@@ -92,6 +92,7 @@ const childrenMap = {
9292
inputFieldStyle: styleControl(InputLikeStyle , 'inputFieldStyle'),
9393
childrenInputFieldStyle: styleControl(ChildrenMultiSelectStyle, 'childrenInputFieldStyle'),
9494
animationStyle: styleControl(AnimationStyle , 'animationStyle'),
95+
tabIndex: NumberControl,
9596
};
9697

9798
const getValidate = (value: any): "" | "warning" | "error" | undefined => {
@@ -271,6 +272,7 @@ let AutoCompleteCompBase = (function () {
271272
suffix={hasIcon(props.suffixIcon) && props.suffixIcon}
272273
status={getValidate(validateState)}
273274
onPressEnter={undefined}
275+
tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined}
274276
/>
275277
</AutoComplete>
276278
</>
@@ -354,6 +356,9 @@ let AutoCompleteCompBase = (function () {
354356
>
355357
{children.animationStyle.getPropertyView()}
356358
</Section>
359+
<Section name={sectionNames.advanced}>
360+
{children.tabIndex.propertyView({ label: trans("prop.tabIndex") })}
361+
</Section>
357362
</>
358363
);
359364
})

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { RecordConstructorToComp, RecordConstructorToView } from "lowcoder-core"
44
import {
55
BoolCodeControl,
66
CustomRuleControl,
7+
NumberControl,
78
RangeControl,
89
StringControl,
910
} from "../../controls/codeControl";
@@ -99,6 +100,7 @@ const commonChildren = {
99100
childrenInputFieldStyle: styleControl(ChildrenMultiSelectStyle, 'childrenInputFieldStyle'),
100101
timeZone: dropdownControl(timeZoneOptions, Intl.DateTimeFormat().resolvedOptions().timeZone),
101102
pickerMode: dropdownControl(PickerModeOptions, 'date'),
103+
tabIndex: NumberControl,
102104
};
103105
type CommonChildrenType = RecordConstructorToComp<typeof commonChildren>;
104106

@@ -185,6 +187,7 @@ export type DateCompViewProps = Pick<
185187
disabledTime: () => ReturnType<typeof disabledTime>;
186188
suffixIcon: ReactNode;
187189
placeholder?: string | [string, string];
190+
tabIndex?: number;
188191
};
189192

190193
const getFormattedDate = (
@@ -281,6 +284,7 @@ const DatePickerTmpCmp = new UICompBuilder(childrenMap, (props) => {
281284
onFocus={() => props.onEvent("focus")}
282285
onBlur={() => props.onEvent("blur")}
283286
suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon}
287+
tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined}
284288
/>
285289
),
286290
showValidationWhenEmpty: props.showValidationWhenEmpty,
@@ -340,6 +344,7 @@ const DatePickerTmpCmp = new UICompBuilder(childrenMap, (props) => {
340344
<><Section name={sectionNames.advanced}>
341345
{timeFields(children, isMobile)}
342346
{children.suffixIcon.propertyView({ label: trans("button.suffixIcon") })}
347+
{children.tabIndex.propertyView({ label: trans("prop.tabIndex") })}
343348
</Section></>
344349
)}
345350
{(useContext(EditorContext).editorModeStatus === "logic" || useContext(EditorContext).editorModeStatus === "both") && !isMobile && commonAdvanceSection(children)}
@@ -475,7 +480,9 @@ let DateRangeTmpCmp = (function () {
475480
}}
476481
onFocus={() => props.onEvent("focus")}
477482
onBlur={() => props.onEvent("blur")}
478-
suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon} />
483+
suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon}
484+
tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined}
485+
/>
479486
);
480487

481488
const startResult = validate({ ...props, value: props.start });
@@ -553,6 +560,7 @@ let DateRangeTmpCmp = (function () {
553560
<><Section name={sectionNames.advanced}>
554561
{timeFields(children, isMobile)}
555562
{children.suffixIcon.propertyView({ label: trans("button.suffixIcon") })}
563+
{children.tabIndex.propertyView({ label: trans("prop.tabIndex") })}
556564
</Section></>
557565
)}
558566
{(useContext(EditorContext).editorModeStatus === "logic" || useContext(EditorContext).editorModeStatus === "both") && commonAdvanceSection(children)}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ export interface DateRangeUIViewProps extends DateCompViewProps {
4444
placeholder?: string | [string, string];
4545
onChange: (start?: dayjs.Dayjs | null, end?: dayjs.Dayjs | null) => void;
4646
onPanelChange: (value: any, mode: [string, string]) => void;
47-
onClickDateRangeTimeZone:(value:any)=>void
47+
onClickDateRangeTimeZone:(value:any)=>void;
48+
tabIndex?: number;
4849
}
4950

5051
export const DateRangeUIView = (props: DateRangeUIViewProps) => {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export interface DataUIViewProps extends DateCompViewProps {
3939
onChange: DatePickerProps<Dayjs>['onChange'];
4040
onPanelChange: () => void;
4141
onClickDateTimeZone:(value:any)=>void;
42-
42+
tabIndex?: number;
4343
}
4444

4545
const DateMobileUIView = React.lazy(() =>

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { RecordConstructorToComp, RecordConstructorToView } from "lowcoder-core"
44
import {
55
BoolCodeControl,
66
CustomRuleControl,
7+
NumberControl,
78
RangeControl,
89
StringControl,
910
} from "../../controls/codeControl";
@@ -92,6 +93,7 @@ const commonChildren = {
9293
suffixIcon: withDefault(IconControl, "/icon:regular/clock"),
9394
timeZone: dropdownControl(timeZoneOptions, Intl.DateTimeFormat().resolvedOptions().timeZone),
9495
viewRef: RefControl<CommonPickerMethods>,
96+
tabIndex: NumberControl,
9597
...validationChildren,
9698
};
9799

@@ -212,6 +214,7 @@ const TimePickerTmpCmp = new UICompBuilder(childrenMap, (props) => {
212214
onFocus={() => props.onEvent("focus")}
213215
onBlur={() => props.onEvent("blur")}
214216
suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon}
217+
tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined}
215218
/>
216219
),
217220
showValidationWhenEmpty: props.showValidationWhenEmpty,
@@ -263,6 +266,7 @@ const TimePickerTmpCmp = new UICompBuilder(childrenMap, (props) => {
263266
{commonAdvanceSection(children)}
264267
{children.use12Hours.propertyView({ label: trans("prop.use12Hours") })}
265268
{children.suffixIcon.propertyView({ label: trans("button.suffixIcon") })}
269+
{children.tabIndex.propertyView({ label: trans("prop.tabIndex") })}
266270
</Section>
267271
)}
268272

@@ -368,6 +372,7 @@ const TimeRangeTmpCmp = (function () {
368372
onFocus={() => props.onEvent("focus")}
369373
onBlur={() => props.onEvent("blur")}
370374
suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon}
375+
tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined}
371376
/>
372377
);
373378

@@ -439,6 +444,7 @@ const TimeRangeTmpCmp = (function () {
439444
{commonAdvanceSection(children)}
440445
{children.use12Hours.propertyView({ label: trans("prop.use12Hours") })}
441446
{children.suffixIcon.propertyView({ label: trans("button.suffixIcon") })}
447+
{children.tabIndex.propertyView({ label: trans("prop.tabIndex") })}
442448
</Section>
443449
)}
444450

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface TimeRangeUIViewProps extends TimeCompViewProps {
3939
placeholder?: string | [string, string];
4040
onChange: (start?: dayjs.Dayjs | null, end?: dayjs.Dayjs | null) => void;
4141
handleTimeRangeZoneChange: (value:any) => void;
42+
tabIndex?: number;
4243
}
4344

4445
export const TimeRangeUIView = (props: TimeRangeUIViewProps) => {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export interface TimeUIViewProps extends TimeCompViewProps {
3434
value: dayjs.Dayjs | null;
3535
onChange: (value: dayjs.Dayjs | null) => void;
3636
handleTimeZoneChange: (value:any) => void;
37+
tabIndex?: number;
3738
}
3839

3940
export const TimeUIView = (props: TimeUIViewProps) => {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ const childrenMap = {
272272
min: UndefinedNumberControl,
273273
max: UndefinedNumberControl,
274274
customRule: CustomRuleControl,
275+
tabIndex: NumberControl,
275276

276277
...formDataChildren,
277278
};
@@ -330,6 +331,7 @@ const CustomInputNumber = (props: RecordConstructorToView<typeof childrenMap>) =
330331
precision={props.precision}
331332
$style={props.inputFieldStyle}
332333
prefix={hasIcon(props.prefixIcon) ? props.prefixIcon : props.prefixText.value}
334+
tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined}
333335
onPressEnter={() => {
334336
handleFinish();
335337
props.onEvent("submit");
@@ -436,6 +438,7 @@ let NumberInputTmpComp = (function () {
436438
})}
437439
{children.controls.propertyView({ label: trans("numberInput.controls") })}
438440
{readOnlyPropertyView(children)}
441+
{children.tabIndex.propertyView({ label: trans("prop.tabIndex") })}
439442
</Section>
440443
)}
441444

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import { CommonNameConfig, NameConfig, withExposingConfigs } from "../../generat
66
import { SliderChildren, SliderPropertyView, SliderStyled, SliderWrapper } from "./sliderCompConstants";
77
import { hasIcon } from "comps/utils";
88
import { BoolControl } from "comps/controls/boolControl";
9+
import { NumberControl } from "comps/controls/codeControl";
910

1011
const RangeSliderBasicComp = (function () {
1112
const childrenMap = {
1213
...SliderChildren,
1314
start: numberExposingStateControl("start", 10),
1415
end: numberExposingStateControl("end", 60),
1516
vertical: BoolControl,
17+
tabIndex: NumberControl,
1618
};
1719
return new UICompBuilder(childrenMap, (props, dispatch) => {
1820
return props.label({
@@ -36,6 +38,7 @@ const RangeSliderBasicComp = (function () {
3638
$style={props.inputFieldStyle}
3739
style={{ margin: 0 }}
3840
$vertical={Boolean(props.vertical) || false}
41+
tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined}
3942
onChange={([start, end]) => {
4043
props.start.onChange(start);
4144
props.end.onChange(end);
@@ -60,6 +63,7 @@ const RangeSliderBasicComp = (function () {
6063
tooltip: trans("rangeSlider.stepTooltip"),
6164
})}
6265
{children.vertical.propertyView({ label: trans("slider.vertical") })}
66+
{children.tabIndex.propertyView({ label: trans("prop.tabIndex") })}
6367
</Section>
6468

6569
<SliderPropertyView {...children} />

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { formDataChildren, FormDataPropertyView } from "../formComp/formDataCons
77
import { SliderChildren, SliderPropertyView, SliderStyled, SliderWrapper } from "./sliderCompConstants";
88
import { hasIcon } from "comps/utils";
99
import { BoolControl } from "comps/controls/boolControl";
10+
import { NumberControl } from "comps/controls/codeControl";
1011

1112
const SliderBasicComp = (function () {
1213
/**
@@ -16,6 +17,7 @@ const SliderBasicComp = (function () {
1617
...SliderChildren,
1718
value: numberExposingStateControl("value", 60),
1819
vertical: BoolControl,
20+
tabIndex: NumberControl,
1921
...formDataChildren,
2022
};
2123
return new UICompBuilder(childrenMap, (props) => {
@@ -39,6 +41,7 @@ const SliderBasicComp = (function () {
3941
$style={props.inputFieldStyle}
4042
style={{margin: 0}}
4143
$vertical={Boolean(props.vertical) || false}
44+
tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined}
4245
onChange={(e) => {
4346
props.value.onChange(e);
4447
props.onEvent("change");
@@ -61,6 +64,7 @@ const SliderBasicComp = (function () {
6164
tooltip: trans("slider.stepTooltip"),
6265
})}
6366
{children.vertical.propertyView({ label: trans("slider.vertical") })}
67+
{children.tabIndex.propertyView({ label: trans("prop.tabIndex") })}
6468
</Section>
6569
<FormDataPropertyView {...children} />
6670
<SliderPropertyView {...children} />

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { StringControl } from "comps/controls/codeControl";
1+
import { StringControl, NumberControl } from "comps/controls/codeControl";
22
import { BoolControl } from "comps/controls/boolControl";
33
import { BoolCodeControl } from "../controls/codeControl";
44
import { stringExposingStateControl } from "comps/controls/codeStateControl";
@@ -180,6 +180,7 @@ const childrenMap = {
180180
toolbar: withDefault(StringControl, JSON.stringify(toolbarOptions)),
181181
onEvent: ChangeEventHandlerControl,
182182
style: styleControl(RichTextEditorStyle , 'style'),
183+
tabIndex: NumberControl,
183184

184185
...formDataChildren,
185186
};
@@ -196,6 +197,7 @@ interface IProps {
196197
onChange: (value: string) => void;
197198
$style: RichTextEditorStyleType;
198199
contentScrollBar: boolean;
200+
tabIndex?: number;
199201
}
200202

201203
const ReactQuillEditor = React.lazy(() => import("react-quill"));
@@ -226,6 +228,15 @@ function RichTextEditor(props: IProps) {
226228
[props.placeholder]
227229
);
228230

231+
useEffect(() => {
232+
if (editorRef.current && props.tabIndex !== undefined) {
233+
const editor = editorRef.current.getEditor();
234+
if (editor && editor.scroll && editor.scroll.domNode) {
235+
(editor.scroll.domNode as HTMLElement).tabIndex = props.tabIndex;
236+
}
237+
}
238+
}, [props.tabIndex, key]); // Also re-run when key changes due to placeholder update
239+
229240
const contains = (parent: HTMLElement, descendant: HTMLElement) => {
230241
try {
231242
// Firefox inserts inaccessible nodes around video elements
@@ -316,6 +327,7 @@ const RichTextEditorCompBase = new UICompBuilder(childrenMap, (props) => {
316327
onChange={handleChange}
317328
$style={props.style}
318329
contentScrollBar={props.contentScrollBar}
330+
tabIndex={props.tabIndex}
319331
/>
320332
);
321333
})
@@ -334,6 +346,7 @@ const RichTextEditorCompBase = new UICompBuilder(childrenMap, (props) => {
334346
{children.onEvent.getPropertyView()}
335347
{hiddenPropertyView(children)}
336348
{readOnlyPropertyView(children)}
349+
{children.tabIndex.propertyView({ label: trans("prop.tabIndex") })}
337350
{showDataLoadingIndicatorsPropertyView(children)}
338351
</Section>
339352
)}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { default as AntdCheckboxGroup } from "antd/es/checkbox/Group";
22
import { SelectInputOptionControl } from "comps/controls/optionsControl";
3-
import { BoolCodeControl } from "../../controls/codeControl";
3+
import { BoolCodeControl, NumberControl } from "../../controls/codeControl";
44
import { arrayStringExposingStateControl } from "../../controls/codeStateControl";
55
import { LabelControl } from "../../controls/labelControl";
66
import { ChangeEventHandlerControl } from "../../controls/eventHandlerControl";
@@ -115,6 +115,7 @@ export const getStyle = (style: CheckboxStyleType) => {
115115
const CheckboxGroup = styled(AntdCheckboxGroup) <{
116116
$style: CheckboxStyleType;
117117
$layout: ValueFromOption<typeof RadioLayoutOptions>;
118+
tabIndex?: number;
118119
}>`
119120
min-height: 32px;
120121
${(props) => props.$style && getStyle(props.$style)}
@@ -156,6 +157,7 @@ let CheckboxBasicComp = (function () {
156157
viewRef: RefControl<HTMLDivElement>,
157158
inputFieldStyle: styleControl(CheckboxStyle , 'inputFieldStyle'),
158159
animationStyle: styleControl(AnimationStyle , 'animationStyle'),
160+
tabIndex: NumberControl,
159161
...SelectInputValidationChildren,
160162
...formDataChildren,
161163
};
@@ -184,6 +186,7 @@ let CheckboxBasicComp = (function () {
184186
value: option.value,
185187
disabled: option.disabled,
186188
}))}
189+
tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined}
187190
onChange={(values) => {
188191
handleChange(values as string[]);
189192
}}

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { EllipsisTextCss, ValueFromOption } from "lowcoder-design";
1313
import { trans } from "i18n";
1414
import { fixOldInputCompData } from "../textInputComp/textInputConstants";
1515
import { migrateOldData } from "comps/generators/simpleGenerators";
16+
import { useEffect, useRef } from "react";
1617

1718
const getStyle = (style: RadioStyleType, inputFieldStyle?:RadioStyleType ) => {
1819
return css`
@@ -102,6 +103,18 @@ let RadioBasicComp = (function () {
102103
validateState,
103104
handleChange,
104105
] = useSelectInputValidate(props);
106+
107+
const radioRef = useRef<HTMLDivElement | null>(null);
108+
109+
useEffect(() => {
110+
if (radioRef.current && typeof props.tabIndex === 'number') {
111+
const firstRadioInput = radioRef.current.querySelector('input[type="radio"]');
112+
if (firstRadioInput) {
113+
firstRadioInput.setAttribute('tabindex', props.tabIndex.toString());
114+
}
115+
}
116+
}, [props.tabIndex, props.options]);
117+
105118
return props.label({
106119
required: props.required,
107120
style: props.style,
@@ -110,7 +123,12 @@ let RadioBasicComp = (function () {
110123
animationStyle:props.animationStyle,
111124
children: (
112125
<Radio
113-
ref={props.viewRef}
126+
ref={(el) => {
127+
if (el) {
128+
props.viewRef(el);
129+
radioRef.current = el;
130+
}
131+
}}
114132
disabled={props.disabled}
115133
value={props.value.value}
116134
$style={props.style}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy