Skip to content

Commit f82d015

Browse files
inline row addition fixes + tab based key navigation in editable table cells
1 parent 2a08d40 commit f82d015

File tree

11 files changed

+152
-182
lines changed

11 files changed

+152
-182
lines changed

client/packages/lowcoder/src/components/table/EditableCell.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,20 +126,26 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
126126
onTableEvent?.('columnEdited');
127127
}
128128
}, [dispatch, baseValue, tmpValue]);
129+
129130
const editView = useMemo(
130131
() => editViewFn?.({ value, onChange, onChangeEnd }) ?? <></>,
131132
[editViewFn, value, onChange, onChangeEnd]
132133
);
134+
133135
const enterEditFn = useCallback(() => {
134136
if (editable) setIsEditing(true);
135137
}, [editable]);
136138

137139
if (isEditing) {
138140
return (
139141
<>
140-
<BorderDiv />
142+
<BorderDiv className="editing-border" />
141143
<TagsContext.Provider value={candidateTags ?? []}>
142-
<StatusContext.Provider value={candidateStatus ?? []}>{editView}</StatusContext.Provider>
144+
<StatusContext.Provider value={candidateStatus ?? []}>
145+
<div className="editing-wrapper">
146+
{editView}
147+
</div>
148+
</StatusContext.Provider>
143149
</TagsContext.Provider>
144150
</>
145151
);
@@ -151,7 +157,12 @@ export function EditableCell<T extends JSONValue>(props: EditableCellProps<T>) {
151157
>
152158
{status === "toSave" && !isEditing && <EditableChip />}
153159
<CellWrapper tooltipTitle={props.cellTooltip}>
154-
{normalView}
160+
<div
161+
tabIndex={editable ? 0 : -1 }
162+
onFocus={enterEditFn}
163+
>
164+
{normalView}
165+
</div>
155166
</CellWrapper>
156167
{/* overlay on normal view to handle double click for editing */}
157168
{editable && (

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,12 @@ export const SelectUIView = (
253253
inputFieldStyle: SelectStyleType;
254254
onChange: (value: any) => void;
255255
dispatch: DispatchType;
256+
autoFocus?: boolean;
256257
}
257258
) => {
258259
return <Select
259260
ref={props.viewRef}
261+
autoFocus={props.autoFocus}
260262
mode={props.mode}
261263
$inputFieldStyle={props.inputFieldStyle}
262264
$style={props.style as SelectStyleType & MultiSelectStyleType}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const InputNumberWrapper = styled.div`
1414
width: 100%;
1515
border-radius: 0;
1616
background: transparent !important;
17-
padding: 0 !important;
17+
// padding: 0 !important;
1818
box-shadow: none;
1919
2020
input {

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ const DatePickerStyled = styled(DatePicker)<{ $open: boolean }>`
4949
top: 0.5px;
5050
display: flex;
5151
align-items: center;
52-
background: #fff;
52+
// background: #fff;
5353
padding: 0 3px;
54-
border-left: 1px solid #d7d9e0;
54+
// border-left: 1px solid #d7d9e0;
5555
}
5656
`;
5757

@@ -183,7 +183,7 @@ export const DateEdit = (props: DateEditProps) => {
183183
nextIcon={<IconNext />}
184184
superNextIcon={<IconSuperNext />}
185185
superPrevIcon={<SuperPrevIcon />}
186-
allowClear={false}
186+
allowClear={true}
187187
variant="borderless"
188188
autoFocus
189189
value={tempValue}
@@ -197,7 +197,9 @@ export const DateEdit = (props: DateEditProps) => {
197197
overflow: "hidden",
198198
}}
199199
onOpenChange={(open) => setPanelOpen(open)}
200-
onChange={(value, dateString) => props.onChange(dateString as string)}
200+
onChange={(value, dateString) => {
201+
props.onChange(dateString as string)
202+
}}
201203
onBlur={() => props.onChangeEnd()}
202204
/>
203205
</Wrapper>

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

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,73 @@ import { StringControl } from "comps/controls/codeControl";
77
import { trans } from "i18n";
88
import { ColumnTypeCompBuilder, ColumnTypeViewFn } from "../columnTypeCompBuilder";
99
import { ColumnValueTooltip } from "../simpleColumnTypeComps";
10+
import { styled } from "styled-components";
11+
12+
const Wrapper = styled.div`
13+
display: inline-flex;
14+
align-items: center;
15+
width: 100%;
16+
height: 100%;
17+
position: absolute;
18+
top: 0;
19+
background: transparent !important;
20+
padding: 8px;
21+
22+
> div {
23+
width: 100%;
24+
height: 100%;
25+
}
26+
27+
.ant-select {
28+
height: 100%;
29+
.ant-select-selector {
30+
padding: 0 7px;
31+
height: 100%;
32+
overflow: hidden;
33+
.ant-select-selection-item {
34+
display: inline-flex;
35+
align-items: center;
36+
padding-right: 24px;
37+
}
38+
}
39+
.ant-select-arrow {
40+
height: calc(100% - 3px);
41+
width: fit-content;
42+
top: 1.5px;
43+
margin-top: 0;
44+
background-color: white;
45+
right: 1.5px;
46+
border-right: 1px solid #d7d9e0;
47+
cursor: pointer;
48+
pointer-events: auto;
49+
svg {
50+
min-width: 18px;
51+
min-height: 18px;
52+
}
53+
&:hover svg path {
54+
fill: #315efb;
55+
}
56+
}
57+
.ant-select-selector .ant-select-selection-search {
58+
left: 7px;
59+
input {
60+
height: 100%;
61+
}
62+
}
63+
&.ant-select-open {
64+
.ant-select-arrow {
65+
border-right: none;
66+
border-left: 1px solid #d7d9e0;
67+
svg g path {
68+
fill: #315efb;
69+
}
70+
}
71+
.ant-select-selection-item {
72+
opacity: 0.4;
73+
}
74+
}
75+
}
76+
`;
1077

1178
const childrenMap = {
1279
text: StringControl,
@@ -28,6 +95,8 @@ const SelectEdit = (props: SelectEditProps) => {
2895
const [currentValue, setCurrentValue] = useState(props.initialValue);
2996
return (
3097
<SelectUIView
98+
autoFocus
99+
allowClear
31100
{...defaultProps}
32101
value={currentValue}
33102
options={props.options}
@@ -67,12 +136,14 @@ export const ColumnSelectComp = (function () {
67136
)
68137
.setEditViewFn((props) => {
69138
return (
70-
<SelectEdit
71-
initialValue={props.value}
72-
options={options}
73-
onChange={props.onChange}
74-
onChangeEnd={props.onChangeEnd}
75-
/>
139+
<Wrapper>
140+
<SelectEdit
141+
initialValue={props.value}
142+
options={options}
143+
onChange={props.onChange}
144+
onChangeEnd={props.onChangeEnd}
145+
/>
146+
</Wrapper>
76147
)
77148
})
78149
.setPropertyViewFn((children) => {

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

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ const StatusEdit = (props: StatusEditPropsType) => {
4848
const defaultStatus = useContext(StatusContext);
4949
const [status, setStatus] = useState(defaultStatus);
5050
const [allOptions, setAllOptions] = useState(BadgeStatusOptions);
51-
const [open, setOpen] = useState(true);
51+
const [open, setOpen] = useState(false);
5252

5353
return (
5454
<Wrapper>
@@ -84,18 +84,20 @@ const StatusEdit = (props: StatusEditPropsType) => {
8484
value,
8585
status: status.find((item) => item.text === value)?.status || "none",
8686
});
87+
setOpen(false)
8788
}}
8889
dropdownRender={(originNode: ReactNode) => (
8990
<DropdownStyled>
9091
<ScrollBar style={{ maxHeight: "256px" }}>{originNode}</ScrollBar>
9192
</DropdownStyled>
9293
)}
9394
dropdownStyle={{ marginTop: "7px", padding: "8px 0 6px 0" }}
94-
onBlur={props.onChangeEnd}
95-
onKeyDown={(e) => {
96-
if (e.key === "Enter") {
97-
props.onChangeEnd();
98-
}
95+
onBlur={() => {
96+
props.onChangeEnd();
97+
setOpen(false);
98+
}}
99+
onFocus={() => {
100+
setOpen(true);
99101
}}
100102
onClick={() => setOpen(!open)}
101103
>

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

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ export const Wrapper = styled.div`
9292
position: absolute;
9393
top: 0;
9494
background: transparent !important;
95+
padding: 8px;
96+
9597
> div {
9698
width: 100%;
9799
height: 100%;
@@ -147,7 +149,7 @@ export const Wrapper = styled.div`
147149
}
148150
}
149151
.ant-tag {
150-
margin-left: 20px;
152+
margin-left: 5px;
151153
}
152154
.ant-tag svg {
153155
margin-right: 4px;
@@ -159,6 +161,10 @@ export const DropdownStyled = styled.div`
159161
padding: 3px 8px;
160162
margin: 0 0 2px 8px;
161163
border-radius: 4px;
164+
165+
&.ant-select-item-option-active {
166+
background-color: #f2f7fc;
167+
}
162168
}
163169
.ant-select-item-option-content {
164170
display: flex;
@@ -193,7 +199,7 @@ const TagEdit = (props: TagEditPropsType) => {
193199
});
194200
return result;
195201
});
196-
const [open, setOpen] = useState(true);
202+
const [open, setOpen] = useState(false);
197203
return (
198204
<Wrapper>
199205
<CustomSelect
@@ -205,6 +211,7 @@ const TagEdit = (props: TagEditPropsType) => {
205211
defaultValue={props.value}
206212
style={{ width: "100%" }}
207213
open={open}
214+
allowClear={true}
208215
suffixIcon={<PackUpIcon />}
209216
onSearch={(value: string) => {
210217
if (defaultTags.findIndex((item) => item.includes(value)) < 0) {
@@ -216,18 +223,20 @@ const TagEdit = (props: TagEditPropsType) => {
216223
}}
217224
onChange={(value: string | string[]) => {
218225
props.onChange(value);
226+
setOpen(false)
219227
}}
220228
dropdownRender={(originNode: ReactNode) => (
221229
<DropdownStyled>
222230
<ScrollBar style={{ maxHeight: "256px" }}>{originNode}</ScrollBar>
223231
</DropdownStyled>
224232
)}
225233
dropdownStyle={{ marginTop: "7px", padding: "8px 0 6px 0" }}
226-
onBlur={props.onChangeEnd}
227-
onKeyDown={(e) => {
228-
if (e.key === "Enter") {
229-
props.onChangeEnd();
230-
}
234+
onFocus={() => {
235+
setOpen(true);
236+
}}
237+
onBlur={() => {
238+
props.onChangeEnd();
239+
setOpen(false);
231240
}}
232241
onClick={() => setOpen(!open)}
233242
>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const ButtonComp = (function () {
4545
loading={props.loading}
4646
disabled={props.disabled}
4747
$buttonStyle={props.buttonType === "primary" ? style : undefined}
48+
style={{margin: 0}}
4849
>
4950
{/* prevent the button from disappearing */}
5051
{!props.text ? " " : props.text}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import { TextOverflowControl } from "comps/controls/textOverflowControl";
3030
import { default as Divider } from "antd/es/divider";
3131
import { ColumnValueTooltip } from "./simpleColumnTypeComps";
3232
import { SummaryColumnComp } from "./tableSummaryColumnComp";
33-
import Segmented from "antd/es/segmented";
3433
import { list } from "@lowcoder-ee/comps/generators/list";
3534
import { EMPTY_ROW_KEY } from "../tableCompView";
3635
export type Render = ReturnType<ConstructorToComp<typeof RenderComp>["getOriginalComp"]>;
@@ -408,7 +407,6 @@ export class ColumnComp extends ColumnInitComp {
408407
dispatchClearInsertSet() {
409408
const renderMap = this.children.render.getMap();
410409
const insertMapKeys = Object.keys(renderMap).filter(key => key.startsWith(EMPTY_ROW_KEY));
411-
const insertMap: Record<string, any> = {};
412410
insertMapKeys.forEach(key => {
413411
const render = renderMap[key];
414412
render.getComp().children.comp.children.changeValue.dispatchChangeValueAction(null);

0 commit comments

Comments
 (0)