Merge pull request #3324 from github/koesie10/access-path-suggest-box
Extract `AccessPathSuggestBox` component
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import type { AccessPathOption } from "../../model-editor/suggestions";
|
||||
import { SuggestBox } from "../common/SuggestBox";
|
||||
import { useDebounceCallback } from "../common/useDebounceCallback";
|
||||
import type { AccessPathDiagnostic } from "../../model-editor/shared/access-paths";
|
||||
import {
|
||||
parseAccessPathTokens,
|
||||
validateAccessPath,
|
||||
} from "../../model-editor/shared/access-paths";
|
||||
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
|
||||
|
||||
type Props = {
|
||||
value: string | undefined;
|
||||
onChange: (value: string) => void;
|
||||
suggestions: AccessPathOption[];
|
||||
disabled?: boolean;
|
||||
|
||||
"aria-label": string;
|
||||
};
|
||||
|
||||
const parseValueToTokens = (value: string) =>
|
||||
parseAccessPathTokens(value).map((t) => t.text);
|
||||
|
||||
const getIcon = (option: AccessPathOption) => (
|
||||
<ModelSuggestionIcon name={option.icon} />
|
||||
);
|
||||
|
||||
const getDetails = (option: AccessPathOption) => option.details;
|
||||
|
||||
export const AccessPathSuggestBox = ({
|
||||
value: givenValue,
|
||||
suggestions,
|
||||
onChange,
|
||||
disabled,
|
||||
"aria-label": ariaLabel,
|
||||
}: Props) => {
|
||||
const [value, setValue] = useState<string | undefined>(givenValue);
|
||||
|
||||
useEffect(() => {
|
||||
setValue(givenValue);
|
||||
}, [givenValue]);
|
||||
|
||||
// Debounce the callback to avoid updating the model too often.
|
||||
// Not doing this results in a lot of lag when typing.
|
||||
useDebounceCallback(
|
||||
value,
|
||||
(newValue: string | undefined) => {
|
||||
if (newValue === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
onChange(newValue);
|
||||
},
|
||||
500,
|
||||
);
|
||||
|
||||
return (
|
||||
<SuggestBox<AccessPathOption, AccessPathDiagnostic>
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
options={suggestions}
|
||||
parseValueToTokens={parseValueToTokens}
|
||||
validateValue={validateAccessPath}
|
||||
getIcon={getIcon}
|
||||
getDetails={getDetails}
|
||||
disabled={disabled}
|
||||
aria-label={ariaLabel}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1,19 +1,12 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import type { ModeledMethod } from "../../model-editor/modeled-method";
|
||||
import {
|
||||
calculateNewProvenance,
|
||||
modeledMethodSupportsInput,
|
||||
} from "../../model-editor/modeled-method";
|
||||
import type { AccessPathOption } from "../../model-editor/suggestions";
|
||||
import { SuggestBox } from "../common/SuggestBox";
|
||||
import { useDebounceCallback } from "../common/useDebounceCallback";
|
||||
import type { AccessPathDiagnostic } from "../../model-editor/shared/access-paths";
|
||||
import {
|
||||
parseAccessPathTokens,
|
||||
validateAccessPath,
|
||||
} from "../../model-editor/shared/access-paths";
|
||||
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
|
||||
import { ModelTypePathSuggestBox } from "./ModelTypePathSuggestBox";
|
||||
import { AccessPathSuggestBox } from "./AccessPathSuggestBox";
|
||||
|
||||
type Props = {
|
||||
modeledMethod: ModeledMethod | undefined;
|
||||
@@ -22,37 +15,13 @@ type Props = {
|
||||
onChange: (modeledMethod: ModeledMethod) => void;
|
||||
};
|
||||
|
||||
const parseValueToTokens = (value: string) =>
|
||||
parseAccessPathTokens(value).map((t) => t.text);
|
||||
|
||||
const getIcon = (option: AccessPathOption) => (
|
||||
<ModelSuggestionIcon name={option.icon} />
|
||||
);
|
||||
|
||||
const getDetails = (option: AccessPathOption) => option.details;
|
||||
|
||||
export const ModelInputSuggestBox = ({
|
||||
modeledMethod,
|
||||
suggestions,
|
||||
typePathSuggestions,
|
||||
onChange,
|
||||
}: Props) => {
|
||||
const [value, setValue] = useState<string | undefined>(
|
||||
modeledMethod && modeledMethodSupportsInput(modeledMethod)
|
||||
? modeledMethod.input
|
||||
: undefined,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (modeledMethod && modeledMethodSupportsInput(modeledMethod)) {
|
||||
setValue(modeledMethod.input);
|
||||
}
|
||||
}, [modeledMethod]);
|
||||
|
||||
// Debounce the callback to avoid updating the model too often.
|
||||
// Not doing this results in a lot of lag when typing.
|
||||
useDebounceCallback(
|
||||
value,
|
||||
const handleChange = useCallback(
|
||||
(input: string | undefined) => {
|
||||
if (
|
||||
!modeledMethod ||
|
||||
@@ -68,7 +37,7 @@ export const ModelInputSuggestBox = ({
|
||||
input,
|
||||
});
|
||||
},
|
||||
500,
|
||||
[onChange, modeledMethod],
|
||||
);
|
||||
|
||||
const enabled = useMemo(
|
||||
@@ -87,14 +56,14 @@ export const ModelInputSuggestBox = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<SuggestBox<AccessPathOption, AccessPathDiagnostic>
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
options={suggestions}
|
||||
parseValueToTokens={parseValueToTokens}
|
||||
validateValue={validateAccessPath}
|
||||
getIcon={getIcon}
|
||||
getDetails={getDetails}
|
||||
<AccessPathSuggestBox
|
||||
value={
|
||||
modeledMethod && modeledMethodSupportsInput(modeledMethod)
|
||||
? modeledMethod.input
|
||||
: undefined
|
||||
}
|
||||
onChange={handleChange}
|
||||
suggestions={suggestions}
|
||||
disabled={!enabled}
|
||||
aria-label="Input"
|
||||
/>
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useCallback, useMemo } from "react";
|
||||
import type { ModeledMethod } from "../../model-editor/modeled-method";
|
||||
import {
|
||||
calculateNewProvenance,
|
||||
modeledMethodSupportsOutput,
|
||||
} from "../../model-editor/modeled-method";
|
||||
import type { AccessPathOption } from "../../model-editor/suggestions";
|
||||
import { SuggestBox } from "../common/SuggestBox";
|
||||
import { useDebounceCallback } from "../common/useDebounceCallback";
|
||||
import type { AccessPathDiagnostic } from "../../model-editor/shared/access-paths";
|
||||
import {
|
||||
parseAccessPathTokens,
|
||||
validateAccessPath,
|
||||
} from "../../model-editor/shared/access-paths";
|
||||
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
|
||||
import { ModelTypeTextbox } from "./ModelTypeTextbox";
|
||||
import { AccessPathSuggestBox } from "./AccessPathSuggestBox";
|
||||
|
||||
type Props = {
|
||||
modeledMethod: ModeledMethod | undefined;
|
||||
@@ -21,36 +14,12 @@ type Props = {
|
||||
onChange: (modeledMethod: ModeledMethod) => void;
|
||||
};
|
||||
|
||||
const parseValueToTokens = (value: string) =>
|
||||
parseAccessPathTokens(value).map((t) => t.text);
|
||||
|
||||
const getIcon = (option: AccessPathOption) => (
|
||||
<ModelSuggestionIcon name={option.icon} />
|
||||
);
|
||||
|
||||
const getDetails = (option: AccessPathOption) => option.details;
|
||||
|
||||
export const ModelOutputSuggestBox = ({
|
||||
modeledMethod,
|
||||
suggestions,
|
||||
onChange,
|
||||
}: Props) => {
|
||||
const [value, setValue] = useState<string | undefined>(
|
||||
modeledMethod && modeledMethodSupportsOutput(modeledMethod)
|
||||
? modeledMethod.output
|
||||
: undefined,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (modeledMethod && modeledMethodSupportsOutput(modeledMethod)) {
|
||||
setValue(modeledMethod.output);
|
||||
}
|
||||
}, [modeledMethod]);
|
||||
|
||||
// Debounce the callback to avoid updating the model too often.
|
||||
// Not doing this results in a lot of lag when typing.
|
||||
useDebounceCallback(
|
||||
value,
|
||||
const handleChange = useCallback(
|
||||
(output: string | undefined) => {
|
||||
if (
|
||||
!modeledMethod ||
|
||||
@@ -66,7 +35,7 @@ export const ModelOutputSuggestBox = ({
|
||||
output,
|
||||
});
|
||||
},
|
||||
500,
|
||||
[modeledMethod, onChange],
|
||||
);
|
||||
|
||||
const enabled = useMemo(
|
||||
@@ -86,15 +55,15 @@ export const ModelOutputSuggestBox = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<SuggestBox<AccessPathOption, AccessPathDiagnostic>
|
||||
value={value}
|
||||
options={suggestions}
|
||||
<AccessPathSuggestBox
|
||||
value={
|
||||
modeledMethod && modeledMethodSupportsOutput(modeledMethod)
|
||||
? modeledMethod.output
|
||||
: undefined
|
||||
}
|
||||
suggestions={suggestions}
|
||||
disabled={!enabled}
|
||||
onChange={setValue}
|
||||
parseValueToTokens={parseValueToTokens}
|
||||
validateValue={validateAccessPath}
|
||||
getIcon={getIcon}
|
||||
getDetails={getDetails}
|
||||
onChange={handleChange}
|
||||
aria-label="Output"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useCallback } from "react";
|
||||
import type { TypeModeledMethod } from "../../model-editor/modeled-method";
|
||||
import type { AccessPathOption } from "../../model-editor/suggestions";
|
||||
import { SuggestBox } from "../common/SuggestBox";
|
||||
import { useDebounceCallback } from "../common/useDebounceCallback";
|
||||
import type { AccessPathDiagnostic } from "../../model-editor/shared/access-paths";
|
||||
import {
|
||||
parseAccessPathTokens,
|
||||
validateAccessPath,
|
||||
} from "../../model-editor/shared/access-paths";
|
||||
import { ModelSuggestionIcon } from "./ModelSuggestionIcon";
|
||||
import { AccessPathSuggestBox } from "./AccessPathSuggestBox";
|
||||
|
||||
type Props = {
|
||||
modeledMethod: TypeModeledMethod;
|
||||
@@ -16,30 +9,12 @@ type Props = {
|
||||
onChange: (modeledMethod: TypeModeledMethod) => void;
|
||||
};
|
||||
|
||||
const parseValueToTokens = (value: string) =>
|
||||
parseAccessPathTokens(value).map((t) => t.text);
|
||||
|
||||
const getIcon = (option: AccessPathOption) => (
|
||||
<ModelSuggestionIcon name={option.icon} />
|
||||
);
|
||||
|
||||
const getDetails = (option: AccessPathOption) => option.details;
|
||||
|
||||
export const ModelTypePathSuggestBox = ({
|
||||
modeledMethod,
|
||||
suggestions,
|
||||
onChange,
|
||||
}: Props) => {
|
||||
const [value, setValue] = useState<string | undefined>(modeledMethod.path);
|
||||
|
||||
useEffect(() => {
|
||||
setValue(modeledMethod.path);
|
||||
}, [modeledMethod]);
|
||||
|
||||
// Debounce the callback to avoid updating the model too often.
|
||||
// Not doing this results in a lot of lag when typing.
|
||||
useDebounceCallback(
|
||||
value,
|
||||
const handleChange = useCallback(
|
||||
(path: string | undefined) => {
|
||||
if (path === undefined) {
|
||||
return;
|
||||
@@ -50,18 +25,14 @@ export const ModelTypePathSuggestBox = ({
|
||||
path,
|
||||
});
|
||||
},
|
||||
500,
|
||||
[modeledMethod, onChange],
|
||||
);
|
||||
|
||||
return (
|
||||
<SuggestBox<AccessPathOption, AccessPathDiagnostic>
|
||||
value={value}
|
||||
options={suggestions}
|
||||
onChange={setValue}
|
||||
parseValueToTokens={parseValueToTokens}
|
||||
validateValue={validateAccessPath}
|
||||
getIcon={getIcon}
|
||||
getDetails={getDetails}
|
||||
<AccessPathSuggestBox
|
||||
value={modeledMethod.path}
|
||||
suggestions={suggestions}
|
||||
onChange={handleChange}
|
||||
aria-label="Path"
|
||||
/>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user