218 lines
6.1 KiB
TypeScript
218 lines
6.1 KiB
TypeScript
/*
|
|
* Copyright 2025 coze-dev Authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import {
|
|
useCallback,
|
|
type ReactNode,
|
|
type CSSProperties,
|
|
useState,
|
|
} from 'react';
|
|
|
|
import classNames from 'classnames';
|
|
import {
|
|
ValueExpression,
|
|
ValueExpressionType,
|
|
type RefExpression,
|
|
type ViewVariableType,
|
|
} from '@coze-workflow/base';
|
|
import { type TreeNodeData } from '@coze-arch/bot-semi/Tree';
|
|
import { IconCozApply } from '@coze-arch/coze-design/icons';
|
|
import { IconButton, type TreeSelectProps } from '@coze-arch/coze-design';
|
|
|
|
import {
|
|
RefValueDisplay,
|
|
type RefTagColor,
|
|
type RefValueDisplayProps,
|
|
} from '@/form-extensions/components/value-expression-input/ref-value-display';
|
|
import {
|
|
type CustomFilterVar,
|
|
type VariableTreeDataNode,
|
|
type RenderDisplayVarName,
|
|
} from '@/form-extensions/components/tree-variable-selector/types';
|
|
import {
|
|
VariableSelector,
|
|
type VariableSelectorProps,
|
|
} from '@/form-extensions/components/tree-variable-selector';
|
|
export const useRefInputNode = ({
|
|
value,
|
|
onChange,
|
|
onBlur,
|
|
disabled,
|
|
variablesDataSource,
|
|
validateStatus,
|
|
readonly,
|
|
invalidContent,
|
|
renderDisplayVarName,
|
|
testId,
|
|
disabledTypes,
|
|
showClear = false,
|
|
customFilterVar,
|
|
setFocused,
|
|
style,
|
|
refTagColor,
|
|
hideDeleteIcon,
|
|
variableTagStyle,
|
|
optionFilter,
|
|
renderExtraOption,
|
|
enableSelectNode,
|
|
popoverStyle,
|
|
handleDataSource,
|
|
variableTypeConstraints,
|
|
}: {
|
|
value?: ValueExpression;
|
|
onChange: (v: ValueExpression | undefined) => void;
|
|
onBlur?: () => void;
|
|
disabled?: boolean;
|
|
variablesDataSource?: VariableTreeDataNode[];
|
|
validateStatus?: TreeSelectProps['validateStatus'];
|
|
readonly?: boolean;
|
|
testId?: string;
|
|
disabledTypes?: ViewVariableType[];
|
|
showClear?: boolean;
|
|
invalidContent?: string;
|
|
renderDisplayVarName?: RenderDisplayVarName;
|
|
customFilterVar?: CustomFilterVar;
|
|
setFocused?: (focused: boolean) => void;
|
|
style?: CSSProperties;
|
|
refTagColor?: RefTagColor;
|
|
hideDeleteIcon?: boolean;
|
|
variableTagStyle?: CSSProperties;
|
|
optionFilter?: VariableSelectorProps['optionFilter'];
|
|
handleDataSource?: VariableSelectorProps['handleDataSource'];
|
|
renderExtraOption?: (
|
|
data?: TreeNodeData[],
|
|
action?: {
|
|
hiddenPopover: () => void;
|
|
},
|
|
) => ReactNode;
|
|
enableSelectNode?: boolean;
|
|
popoverStyle?: CSSProperties;
|
|
/* 类型限制,引用类型不满足限制时,显示警告信息 */
|
|
variableTypeConstraints?: RefValueDisplayProps['variableTypeConstraints'];
|
|
}) => {
|
|
const onRefChange = useCallback(
|
|
(v: string[] | undefined): void => {
|
|
if (v === undefined) {
|
|
onChange(undefined);
|
|
} else {
|
|
onChange({
|
|
type: ValueExpressionType.REF,
|
|
content: { keyPath: v as string[] },
|
|
});
|
|
}
|
|
},
|
|
[onChange],
|
|
);
|
|
|
|
const handleRefRemove = () => {
|
|
onChange?.(undefined);
|
|
onBlur?.();
|
|
};
|
|
|
|
const [focused, setStateFocused] = useState(false);
|
|
const _setFocused = useCallback(
|
|
(v: boolean) => {
|
|
setStateFocused(v);
|
|
setFocused?.(v);
|
|
},
|
|
[setFocused],
|
|
);
|
|
|
|
const renderVariableSelect = (trigger: ReactNode) =>
|
|
readonly && trigger ? (
|
|
trigger
|
|
) : (
|
|
<VariableSelector
|
|
testId={testId}
|
|
disabled={disabled}
|
|
disabledTypes={disabledTypes}
|
|
dataSource={variablesDataSource}
|
|
value={
|
|
value && ValueExpression.isRef(value)
|
|
? (value.content?.keyPath as VariableSelectorProps['value'])
|
|
: undefined
|
|
}
|
|
onChange={onRefChange}
|
|
onBlur={onBlur}
|
|
validateStatus={validateStatus}
|
|
readonly={readonly}
|
|
showClear={showClear}
|
|
customFilterVar={customFilterVar}
|
|
onPopoverVisibleChange={_setFocused}
|
|
trigger={trigger}
|
|
style={style}
|
|
invalidContent={invalidContent}
|
|
renderDisplayVarName={renderDisplayVarName}
|
|
optionFilter={optionFilter}
|
|
renderExtraOption={renderExtraOption}
|
|
enableSelectNode={enableSelectNode}
|
|
popoverStyle={popoverStyle}
|
|
handleDataSource={handleDataSource}
|
|
/>
|
|
);
|
|
|
|
const renderVariableDisplay = (props?: { needWrapper?: boolean }) =>
|
|
props?.needWrapper ? (
|
|
<div
|
|
className={classNames(
|
|
'w-full max-w-[100%] h-[24px] pr-[4px]',
|
|
'flex flex-row items-center justify-between',
|
|
'bg-transparent hover:bg-background-5 active:bg-background-6',
|
|
'rounded-lg border border-solid coz-stroke-plus hover:coz-mg-secondary-hovered active:coz-mg-secondary-pressed',
|
|
{
|
|
'semi-input-wrapper-error': validateStatus === 'error',
|
|
'coz-stroke-primary': validateStatus !== 'error',
|
|
'!coz-stroke-hglt': focused,
|
|
'pointer-events-none': readonly,
|
|
},
|
|
)}
|
|
>
|
|
{renderVariableDisplay()}
|
|
<div>
|
|
{renderVariableSelect(
|
|
<IconButton
|
|
size="mini"
|
|
color="secondary"
|
|
icon={<IconCozApply className="text-[16px]" />}
|
|
/>,
|
|
)}
|
|
</div>
|
|
</div>
|
|
) : (
|
|
renderVariableSelect(
|
|
<div
|
|
className={classNames(
|
|
'cursor-pointer w-full overflow-hidden flex items-center pl-0.5',
|
|
)}
|
|
>
|
|
<RefValueDisplay
|
|
value={value as RefExpression}
|
|
onClose={handleRefRemove}
|
|
tagColor={refTagColor}
|
|
closable={!hideDeleteIcon}
|
|
style={variableTagStyle}
|
|
variableTypeConstraints={variableTypeConstraints}
|
|
readonly={readonly}
|
|
/>
|
|
</div>,
|
|
)
|
|
);
|
|
return {
|
|
renderVariableSelect,
|
|
renderVariableDisplay,
|
|
};
|
|
};
|