Skip to content

Commit bbfc5d8

Browse files
authored
Merge pull request #3324 from github/koesie10/access-path-suggest-box
Extract `AccessPathSuggestBox` component
2 parents b418f47 + 688aa30 commit bbfc5d8

File tree

4 files changed

+102
-123
lines changed

4 files changed

+102
-123
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { useEffect, useState } from "react";
2+
import type { AccessPathOption } from "../../model-editor/suggestions";
3+
import { SuggestBox } from "../common/SuggestBox";
4+
import { useDebounceCallback } from "../common/useDebounceCallback";
5+
import type { AccessPathDiagnostic } from "../../model-editor/shared/access-paths";
6+
import {
7+
parseAccessPathTokens,
8+
validateAccessPath,
9+
} from "../../model-editor/shared/access-paths";
10+
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
11+
12+
type Props = {
13+
value: string | undefined;
14+
onChange: (value: string) => void;
15+
suggestions: AccessPathOption[];
16+
disabled?: boolean;
17+
18+
"aria-label": string;
19+
};
20+
21+
const parseValueToTokens = (value: string) =>
22+
parseAccessPathTokens(value).map((t) => t.text);
23+
24+
const getIcon = (option: AccessPathOption) => (
25+
<ModelSuggestionIcon name={option.icon} />
26+
);
27+
28+
const getDetails = (option: AccessPathOption) => option.details;
29+
30+
export const AccessPathSuggestBox = ({
31+
value: givenValue,
32+
suggestions,
33+
onChange,
34+
disabled,
35+
"aria-label": ariaLabel,
36+
}: Props) => {
37+
const [value, setValue] = useState<string | undefined>(givenValue);
38+
39+
useEffect(() => {
40+
setValue(givenValue);
41+
}, [givenValue]);
42+
43+
// Debounce the callback to avoid updating the model too often.
44+
// Not doing this results in a lot of lag when typing.
45+
useDebounceCallback(
46+
value,
47+
(newValue: string | undefined) => {
48+
if (newValue === undefined) {
49+
return;
50+
}
51+
52+
onChange(newValue);
53+
},
54+
500,
55+
);
56+
57+
return (
58+
<SuggestBox<AccessPathOption, AccessPathDiagnostic>
59+
value={value}
60+
onChange={setValue}
61+
options={suggestions}
62+
parseValueToTokens={parseValueToTokens}
63+
validateValue={validateAccessPath}
64+
getIcon={getIcon}
65+
getDetails={getDetails}
66+
disabled={disabled}
67+
aria-label={ariaLabel}
68+
/>
69+
);
70+
};

extensions/ql-vscode/src/view/model-editor/ModelInputSuggestBox.tsx

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
1-
import { useEffect, useMemo, useState } from "react";
1+
import { useCallback, useMemo } from "react";
22
import type { ModeledMethod } from "../../model-editor/modeled-method";
33
import {
44
calculateNewProvenance,
55
modeledMethodSupportsInput,
66
} from "../../model-editor/modeled-method";
77
import type { AccessPathOption } from "../../model-editor/suggestions";
8-
import { SuggestBox } from "../common/SuggestBox";
9-
import { useDebounceCallback } from "../common/useDebounceCallback";
10-
import type { AccessPathDiagnostic } from "../../model-editor/shared/access-paths";
11-
import {
12-
parseAccessPathTokens,
13-
validateAccessPath,
14-
} from "../../model-editor/shared/access-paths";
15-
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
168
import { ModelTypePathSuggestBox } from "./ModelTypePathSuggestBox";
9+
import { AccessPathSuggestBox } from "./AccessPathSuggestBox";
1710

1811
type Props = {
1912
modeledMethod: ModeledMethod | undefined;
@@ -22,37 +15,13 @@ type Props = {
2215
onChange: (modeledMethod: ModeledMethod) => void;
2316
};
2417

25-
const parseValueToTokens = (value: string) =>
26-
parseAccessPathTokens(value).map((t) => t.text);
27-
28-
const getIcon = (option: AccessPathOption) => (
29-
<ModelSuggestionIcon name={option.icon} />
30-
);
31-
32-
const getDetails = (option: AccessPathOption) => option.details;
33-
3418
export const ModelInputSuggestBox = ({
3519
modeledMethod,
3620
suggestions,
3721
typePathSuggestions,
3822
onChange,
3923
}: Props) => {
40-
const [value, setValue] = useState<string | undefined>(
41-
modeledMethod && modeledMethodSupportsInput(modeledMethod)
42-
? modeledMethod.input
43-
: undefined,
44-
);
45-
46-
useEffect(() => {
47-
if (modeledMethod && modeledMethodSupportsInput(modeledMethod)) {
48-
setValue(modeledMethod.input);
49-
}
50-
}, [modeledMethod]);
51-
52-
// Debounce the callback to avoid updating the model too often.
53-
// Not doing this results in a lot of lag when typing.
54-
useDebounceCallback(
55-
value,
24+
const handleChange = useCallback(
5625
(input: string | undefined) => {
5726
if (
5827
!modeledMethod ||
@@ -68,7 +37,7 @@ export const ModelInputSuggestBox = ({
6837
input,
6938
});
7039
},
71-
500,
40+
[onChange, modeledMethod],
7241
);
7342

7443
const enabled = useMemo(
@@ -87,14 +56,14 @@ export const ModelInputSuggestBox = ({
8756
}
8857

8958
return (
90-
<SuggestBox<AccessPathOption, AccessPathDiagnostic>
91-
value={value}
92-
onChange={setValue}
93-
options={suggestions}
94-
parseValueToTokens={parseValueToTokens}
95-
validateValue={validateAccessPath}
96-
getIcon={getIcon}
97-
getDetails={getDetails}
59+
<AccessPathSuggestBox
60+
value={
61+
modeledMethod && modeledMethodSupportsInput(modeledMethod)
62+
? modeledMethod.input
63+
: undefined
64+
}
65+
onChange={handleChange}
66+
suggestions={suggestions}
9867
disabled={!enabled}
9968
aria-label="Input"
10069
/>

extensions/ql-vscode/src/view/model-editor/ModelOutputSuggestBox.tsx

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,25 @@
1-
import { useEffect, useMemo, useState } from "react";
1+
import { useCallback, useMemo } from "react";
22
import type { ModeledMethod } from "../../model-editor/modeled-method";
33
import {
44
calculateNewProvenance,
55
modeledMethodSupportsOutput,
66
} from "../../model-editor/modeled-method";
77
import type { AccessPathOption } from "../../model-editor/suggestions";
8-
import { SuggestBox } from "../common/SuggestBox";
9-
import { useDebounceCallback } from "../common/useDebounceCallback";
10-
import type { AccessPathDiagnostic } from "../../model-editor/shared/access-paths";
11-
import {
12-
parseAccessPathTokens,
13-
validateAccessPath,
14-
} from "../../model-editor/shared/access-paths";
15-
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
168
import { ModelTypeTextbox } from "./ModelTypeTextbox";
9+
import { AccessPathSuggestBox } from "./AccessPathSuggestBox";
1710

1811
type Props = {
1912
modeledMethod: ModeledMethod | undefined;
2013
suggestions: AccessPathOption[];
2114
onChange: (modeledMethod: ModeledMethod) => void;
2215
};
2316

24-
const parseValueToTokens = (value: string) =>
25-
parseAccessPathTokens(value).map((t) => t.text);
26-
27-
const getIcon = (option: AccessPathOption) => (
28-
<ModelSuggestionIcon name={option.icon} />
29-
);
30-
31-
const getDetails = (option: AccessPathOption) => option.details;
32-
3317
export const ModelOutputSuggestBox = ({
3418
modeledMethod,
3519
suggestions,
3620
onChange,
3721
}: Props) => {
38-
const [value, setValue] = useState<string | undefined>(
39-
modeledMethod && modeledMethodSupportsOutput(modeledMethod)
40-
? modeledMethod.output
41-
: undefined,
42-
);
43-
44-
useEffect(() => {
45-
if (modeledMethod && modeledMethodSupportsOutput(modeledMethod)) {
46-
setValue(modeledMethod.output);
47-
}
48-
}, [modeledMethod]);
49-
50-
// Debounce the callback to avoid updating the model too often.
51-
// Not doing this results in a lot of lag when typing.
52-
useDebounceCallback(
53-
value,
22+
const handleChange = useCallback(
5423
(output: string | undefined) => {
5524
if (
5625
!modeledMethod ||
@@ -66,7 +35,7 @@ export const ModelOutputSuggestBox = ({
6635
output,
6736
});
6837
},
69-
500,
38+
[modeledMethod, onChange],
7039
);
7140

7241
const enabled = useMemo(
@@ -86,15 +55,15 @@ export const ModelOutputSuggestBox = ({
8655
}
8756

8857
return (
89-
<SuggestBox<AccessPathOption, AccessPathDiagnostic>
90-
value={value}
91-
options={suggestions}
58+
<AccessPathSuggestBox
59+
value={
60+
modeledMethod && modeledMethodSupportsOutput(modeledMethod)
61+
? modeledMethod.output
62+
: undefined
63+
}
64+
suggestions={suggestions}
9265
disabled={!enabled}
93-
onChange={setValue}
94-
parseValueToTokens={parseValueToTokens}
95-
validateValue={validateAccessPath}
96-
getIcon={getIcon}
97-
getDetails={getDetails}
66+
onChange={handleChange}
9867
aria-label="Output"
9968
/>
10069
);

extensions/ql-vscode/src/view/model-editor/ModelTypePathSuggestBox.tsx

Lines changed: 8 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,20 @@
1-
import { useEffect, useState } from "react";
1+
import { useCallback } from "react";
22
import type { TypeModeledMethod } from "../../model-editor/modeled-method";
33
import type { AccessPathOption } from "../../model-editor/suggestions";
4-
import { SuggestBox } from "../common/SuggestBox";
5-
import { useDebounceCallback } from "../common/useDebounceCallback";
6-
import type { AccessPathDiagnostic } from "../../model-editor/shared/access-paths";
7-
import {
8-
parseAccessPathTokens,
9-
validateAccessPath,
10-
} from "../../model-editor/shared/access-paths";
11-
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
4+
import { AccessPathSuggestBox } from "./AccessPathSuggestBox";
125

136
type Props = {
147
modeledMethod: TypeModeledMethod;
158
suggestions: AccessPathOption[];
169
onChange: (modeledMethod: TypeModeledMethod) => void;
1710
};
1811

19-
const parseValueToTokens = (value: string) =>
20-
parseAccessPathTokens(value).map((t) => t.text);
21-
22-
const getIcon = (option: AccessPathOption) => (
23-
<ModelSuggestionIcon name={option.icon} />
24-
);
25-
26-
const getDetails = (option: AccessPathOption) => option.details;
27-
2812
export const ModelTypePathSuggestBox = ({
2913
modeledMethod,
3014
suggestions,
3115
onChange,
3216
}: Props) => {
33-
const [value, setValue] = useState<string | undefined>(modeledMethod.path);
34-
35-
useEffect(() => {
36-
setValue(modeledMethod.path);
37-
}, [modeledMethod]);
38-
39-
// Debounce the callback to avoid updating the model too often.
40-
// Not doing this results in a lot of lag when typing.
41-
useDebounceCallback(
42-
value,
17+
const handleChange = useCallback(
4318
(path: string | undefined) => {
4419
if (path === undefined) {
4520
return;
@@ -50,18 +25,14 @@ export const ModelTypePathSuggestBox = ({
5025
path,
5126
});
5227
},
53-
500,
28+
[modeledMethod, onChange],
5429
);
5530

5631
return (
57-
<SuggestBox<AccessPathOption, AccessPathDiagnostic>
58-
value={value}
59-
options={suggestions}
60-
onChange={setValue}
61-
parseValueToTokens={parseValueToTokens}
62-
validateValue={validateAccessPath}
63-
getIcon={getIcon}
64-
getDetails={getDetails}
32+
<AccessPathSuggestBox
33+
value={modeledMethod.path}
34+
suggestions={suggestions}
35+
onChange={handleChange}
6536
aria-label="Path"
6637
/>
6738
);

0 commit comments

Comments
 (0)