Browse Source

feat(group): add form value persistence for group notes (#1011)

Louis Young 1 tháng trước cách đây
mục cha
commit
8304478057

+ 1 - 0
apps/demo-fixed-layout/src/hooks/index.ts

@@ -6,3 +6,4 @@
 export { useEditorProps } from './use-editor-props';
 export { useNodeRenderContext } from './use-node-render-context';
 export { useIsSidebar } from './use-is-sidebar';
+export { useFormValue } from './use-form-value';

+ 58 - 0
apps/demo-fixed-layout/src/hooks/use-form-value.ts

@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import { useEffect, useState } from 'react';
+
+import { FlowNodeEntity, FlowNodeFormData, FormModelV2 } from '@flowgram.ai/fixed-layout-editor';
+
+export const useFormValue = <T = unknown>(params: {
+  node?: FlowNodeEntity;
+  fieldName: string;
+  defaultValue?: T;
+}): [T, (v: T) => void] => {
+  const { node, fieldName, defaultValue } = params;
+  const formModel = node?.getData(FlowNodeFormData).getFormModel<FormModelV2>();
+
+  const [innerValue, setInnerValue] = useState<T | undefined>(() =>
+    formModel?.getValueIn<T>(fieldName)
+  );
+
+  // 初始化表单值
+  useEffect(() => {
+    if (!formModel) {
+      return;
+    }
+    const initValue = formModel.getValueIn<{ width: number; height: number }>(fieldName);
+    if (!initValue) {
+      formModel.setValueIn(fieldName, defaultValue);
+    }
+  }, [defaultValue, formModel, fieldName]);
+
+  // 同步表单外部值变化:初始化/undo/redo/协同
+  useEffect(() => {
+    if (!formModel) {
+      return;
+    }
+    const disposer = formModel.onFormValueChangeIn(fieldName, () => {
+      const newValue = formModel.getValueIn<T>(fieldName);
+      if (!newValue) {
+        return;
+      }
+      setInnerValue(newValue);
+    });
+    return () => disposer.dispose();
+  }, [formModel, fieldName]);
+
+  const setValue = (newValue: T) => {
+    if (!formModel) {
+      return;
+    }
+    formModel.setValueIn(fieldName, newValue);
+    setInnerValue(newValue);
+  };
+
+  const value = (innerValue ?? defaultValue) as T;
+  return [value, setValue];
+};

+ 7 - 1
apps/demo-fixed-layout/src/plugins/group-plugin/group-note.tsx

@@ -13,6 +13,7 @@ import {
 import type { AutosizeRow } from '@douyinfe/semi-ui/lib/es/input/textarea';
 import { Tooltip } from '@douyinfe/semi-ui';
 
+import { useFormValue } from '../../hooks';
 import MultiLineEditor from './multilang-textarea-editor';
 
 interface GroupNoteProps {
@@ -26,6 +27,7 @@ interface GroupNoteProps {
 
 export const GroupNote: FC<GroupNoteProps> = (props) => {
   const {
+    groupNode,
     groupController,
     containerStyle = {},
     textStyle = {},
@@ -33,7 +35,11 @@ export const GroupNote: FC<GroupNoteProps> = (props) => {
     enableTooltip = false,
   } = props;
 
-  const [editingValue, setEditingValue] = useState<string>('');
+  const [editingValue, setEditingValue] = useFormValue<string>({
+    node: groupNode,
+    fieldName: 'note',
+    defaultValue: '',
+  });
 
   const ref = useRef<HTMLDivElement>(null);
   const [tooltipVisible, setTooltipVisible] = useState<boolean>(false);

+ 3 - 3
packages/plugins/group-plugin/src/components/group-box.tsx

@@ -7,13 +7,13 @@
 import { useEffect, type CSSProperties } from 'react';
 import React from 'react';
 
-import { FlowGroupController } from '@flowgram.ai/document';
 import type { Rectangle } from '@flowgram.ai/utils';
+import { FlowGroupController } from '@flowgram.ai/document';
 
 import { IGroupBox } from '../type';
 import { useHover } from './hooks';
 
-export const GroupBox: IGroupBox = props => {
+export const GroupBox: IGroupBox = (props) => {
   const { groupNode } = props;
   const groupController = FlowGroupController.create(groupNode)!;
   const bounds: Rectangle = groupController.bounds;
@@ -30,7 +30,7 @@ export const GroupBox: IGroupBox = props => {
   const defaultBackgroundStyle: CSSProperties = {
     borderRadius: 10,
     zIndex: -1,
-    outline: `${hover ? 3 : 1}px solid rgb(97, 69, 211)`,
+    outline: `${hover ? 2 : 1}px solid rgb(97, 69, 211)`,
     backgroundColor: 'rgb(236 233 247)',
   };
 

+ 5 - 0
packages/plugins/group-plugin/src/group-node-register.tsx

@@ -3,6 +3,8 @@
  * SPDX-License-Identifier: MIT
  */
 
+import React from 'react';
+
 import { IPoint, PaddingSchema, Point } from '@flowgram.ai/utils';
 import {
   FlowGroupController,
@@ -48,6 +50,9 @@ export const GroupRegister: FlowNodeRegistry = {
       };
     },
   },
+  formMeta: {
+    render: () => React.createElement('div'),
+  },
   getLines(transition) {
     const { transform } = transition;
     const lines: FlowTransitionLine[] = [];