feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user