Parcourir la source

feat(material): enhance inputsValues (#592)

Yiwei Mao il y a 5 mois
Parent
commit
3d57f5c088

+ 27 - 0
packages/materials/form-materials/src/components/inputs-values/components/blur-input.tsx

@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import React, { useEffect, useState } from 'react';
+
+import Input, { InputProps } from '@douyinfe/semi-ui/lib/es/input';
+
+export function BlurInput(props: InputProps) {
+  const [value, setValue] = useState('');
+
+  useEffect(() => {
+    setValue(props.value as string);
+  }, [props.value]);
+
+  return (
+    <Input
+      {...props}
+      value={value}
+      onChange={(value) => {
+        setValue(value);
+      }}
+      onBlur={(e) => props.onChange?.(value, e)}
+    />
+  );
+}

+ 14 - 3
packages/materials/form-materials/src/components/inputs-values/index.tsx

@@ -5,7 +5,7 @@
 
 import React from 'react';
 
-import { Button, IconButton, Input } from '@douyinfe/semi-ui';
+import { Button, IconButton } from '@douyinfe/semi-ui';
 import { IconDelete, IconPlus } from '@douyinfe/semi-icons';
 
 import { PropsType } from './types';
@@ -13,11 +13,20 @@ import { DynamicValueInput } from '../dynamic-value-input';
 import { IFlowConstantRefValue, IFlowValue } from '../../typings';
 import { useObjectList } from '../../hooks';
 import { UIRow, UIRows } from './styles';
+import { BlurInput } from './components/blur-input';
 
-export function InputsValues({ value, onChange, style, readonly, constantProps }: PropsType) {
+export function InputsValues({
+  value,
+  onChange,
+  style,
+  readonly,
+  constantProps,
+  schema,
+}: PropsType) {
   const { list, updateKey, updateValue, remove, add } = useObjectList<IFlowValue | undefined>({
     value,
     onChange,
+    sortIndexKey: 'extra.index',
   });
 
   return (
@@ -25,18 +34,20 @@ export function InputsValues({ value, onChange, style, readonly, constantProps }
       <UIRows style={style}>
         {list.map((item) => (
           <UIRow key={item.id}>
-            <Input
+            <BlurInput
               style={{ width: 100, minWidth: 100, maxWidth: 100 }}
               disabled={readonly}
               size="small"
               value={item.key}
               onChange={(v) => updateKey(item.id, v)}
+              placeholder="Input Key"
             />
             <DynamicValueInput
               style={{ flexGrow: 1 }}
               readonly={readonly}
               value={item.value as IFlowConstantRefValue}
               onChange={(v) => updateValue(item.id, v)}
+              schema={schema}
               constantProps={{
                 ...constantProps,
                 strategies: [...(constantProps?.strategies || [])],

+ 2 - 1
packages/materials/form-materials/src/components/inputs-values/types.ts

@@ -4,13 +4,14 @@
  */
 
 import { Strategy } from '../constant-input/types';
-import { IFlowValue } from '../../typings';
+import { IFlowValue, IJsonSchema } from '../../typings';
 
 export interface PropsType {
   value?: Record<string, IFlowValue | undefined>;
   onChange: (value?: Record<string, IFlowValue | undefined>) => void;
   readonly?: boolean;
   hasError?: boolean;
+  schema?: IJsonSchema;
   style?: React.CSSProperties;
   constantProps?: {
     strategies?: Strategy[];

+ 6 - 3
packages/materials/form-materials/src/components/prompt-editor-with-variables/extensions/variable-tag.tsx

@@ -67,10 +67,13 @@ class VariableTagWidget extends WidgetType {
       return;
     }
 
-    const rootField = last(v.parentFields);
+    const rootField = last(v.parentFields) || v;
+    const isRoot = v.parentFields.length === 0;
 
     const rootTitle = (
-      <UIRootTitle>{rootField?.meta.title ? `${rootField.meta.title} -` : ''}</UIRootTitle>
+      <UIRootTitle>
+        {rootField?.meta.title ? `${rootField.meta.title} ${isRoot ? '' : '-'} ` : ''}
+      </UIRootTitle>
     );
     const rootIcon = this.renderIcon(rootField?.meta.icon);
 
@@ -86,7 +89,7 @@ class VariableTagWidget extends WidgetType {
       >
         <UITag prefixIcon={rootIcon}>
           {rootTitle}
-          <UIVarName>{v?.key}</UIVarName>
+          {!isRoot && <UIVarName>{v?.key}</UIVarName>}
         </UITag>
       </Popover>
     );

+ 4 - 2
packages/materials/form-materials/src/components/variable-selector/index.tsx

@@ -98,7 +98,9 @@ export const VariableSelector = ({
 
           const rootTitle = (
             <UIRootTitle>
-              {_option.rootMeta?.title ? `${_option.rootMeta?.title} -` : null}
+              {_option.rootMeta?.title
+                ? `${_option.rootMeta?.title} ${_option.isRoot ? '' : '-'} `
+                : null}
             </UIRootTitle>
           );
 
@@ -119,7 +121,7 @@ export const VariableSelector = ({
                   onClose={() => onChange(undefined)}
                 >
                   {rootTitle}
-                  <UIVarName $inSelector>{_option.label}</UIVarName>
+                  {!_option.isRoot && <UIVarName $inSelector>{_option.label}</UIVarName>}
                 </UITag>
               </Popover>
             </div>

+ 2 - 1
packages/materials/form-materials/src/components/variable-selector/use-variable-tree.tsx

@@ -93,7 +93,8 @@ export function useVariableTree(params: {
       icon: getVariableTypeIcon(variable),
       children,
       disabled: !isSchemaMatch,
-      rootMeta: parentFields[0]?.meta,
+      rootMeta: parentFields[0]?.meta || variable.meta,
+      isRoot: !parentFields?.length,
     };
   };
 

+ 16 - 3
packages/materials/form-materials/src/hooks/use-object-list/index.tsx

@@ -6,7 +6,7 @@
 import { useEffect, useState } from 'react';
 
 import { nanoid } from 'nanoid';
-import { difference } from 'lodash';
+import { difference, get, isObject, set } from 'lodash';
 
 function genId() {
   return nanoid();
@@ -23,15 +23,20 @@ type ObjectType<ValueType> = Record<string, ValueType | undefined>;
 export function useObjectList<ValueType>({
   value,
   onChange,
+  sortIndexKey,
 }: {
   value?: ObjectType<ValueType>;
   onChange: (value?: ObjectType<ValueType>) => void;
+  sortIndexKey?: string;
 }) {
   const [list, setList] = useState<ListItem<ValueType>[]>([]);
 
   useEffect(() => {
     setList((_prevList) => {
-      const newKeys = Object.keys(value || {});
+      const newKeys = Object.entries(value || {})
+        .sort((a, b) => get(a[1], sortIndexKey || 0) - get(b[1], sortIndexKey || 0))
+        .map(([key]) => key);
+
       const oldKeys = _prevList.map((item) => item.key).filter(Boolean) as string[];
       const addKeys = difference(newKeys, oldKeys);
 
@@ -75,7 +80,15 @@ export function useObjectList<ValueType>({
 
       onChange(
         Object.fromEntries(
-          nextList.filter((item) => item.key).map((item) => [item.key!, item.value])
+          nextList
+            .filter((item) => item.key)
+            .map((item) => [item.key!, item.value])
+            .map((_res, idx) => {
+              if (isObject(_res[1]) && sortIndexKey) {
+                set(_res[1], sortIndexKey, idx);
+              }
+              return _res;
+            })
         )
       );
 

+ 8 - 0
packages/materials/form-materials/src/typings/flow-value/index.ts

@@ -5,25 +5,33 @@
 
 import { IJsonSchema } from '../json-schema';
 
+export interface IFlowValueExtra {
+  index?: number;
+}
+
 export interface IFlowConstantValue {
   type: 'constant';
   content?: string | number | boolean;
   schema?: IJsonSchema;
+  extra?: IFlowValueExtra;
 }
 
 export interface IFlowRefValue {
   type: 'ref';
   content?: string[];
+  extra?: IFlowValueExtra;
 }
 
 export interface IFlowExpressionValue {
   type: 'expression';
   content?: string;
+  extra?: IFlowValueExtra;
 }
 
 export interface IFlowTemplateValue {
   type: 'template';
   content?: string;
+  extra?: IFlowValueExtra;
 }
 
 export type IFlowValue =