@flowgram.ai/form-materials 0.4.4 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/esm/chunk-6OZSB6PD.js +10 -0
  2. package/dist/esm/chunk-6OZSB6PD.js.map +1 -0
  3. package/dist/esm/chunk-G4HQ7OSI.js +440 -0
  4. package/dist/esm/chunk-G4HQ7OSI.js.map +1 -0
  5. package/dist/esm/chunk-QIJ4QVB2.js +271 -0
  6. package/dist/esm/chunk-QIJ4QVB2.js.map +1 -0
  7. package/dist/esm/editor-6UMULJYB.js +180 -0
  8. package/dist/esm/editor-6UMULJYB.js.map +1 -0
  9. package/dist/esm/editor-E2BQTPCD.js +388 -0
  10. package/dist/esm/editor-E2BQTPCD.js.map +1 -0
  11. package/dist/esm/editor-H2R7JJLO.js +282 -0
  12. package/dist/esm/editor-H2R7JJLO.js.map +1 -0
  13. package/dist/esm/editor-JX42GFAZ.js +249 -0
  14. package/dist/esm/editor-JX42GFAZ.js.map +1 -0
  15. package/dist/esm/editor-YMNCDGUR.js +167 -0
  16. package/dist/esm/editor-YMNCDGUR.js.map +1 -0
  17. package/dist/esm/index.js +1388 -3029
  18. package/dist/esm/index.js.map +1 -1
  19. package/dist/index.d.mts +144 -51
  20. package/dist/index.d.ts +144 -51
  21. package/dist/index.js +3511 -2759
  22. package/dist/index.js.map +1 -1
  23. package/package.json +6 -6
  24. package/src/components/code-editor/editor.tsx +96 -0
  25. package/src/components/code-editor/index.tsx +5 -89
  26. package/src/components/code-editor/theme/dark.ts +49 -30
  27. package/src/components/code-editor/theme/light.ts +56 -32
  28. package/src/components/code-editor-mini/index.tsx +2 -2
  29. package/src/components/condition-row/index.tsx +4 -0
  30. package/src/components/db-condition-row/hooks/use-left.tsx +66 -0
  31. package/src/components/db-condition-row/hooks/use-op.tsx +59 -0
  32. package/src/components/db-condition-row/index.tsx +93 -0
  33. package/src/components/db-condition-row/styles.tsx +43 -0
  34. package/src/components/db-condition-row/types.ts +34 -0
  35. package/src/components/index.ts +1 -0
  36. package/src/components/json-editor-with-variables/editor.tsx +69 -0
  37. package/src/components/json-editor-with-variables/extensions/variable-tag.tsx +4 -3
  38. package/src/components/json-editor-with-variables/index.tsx +5 -60
  39. package/src/components/prompt-editor/editor.tsx +81 -0
  40. package/src/components/prompt-editor/index.tsx +5 -69
  41. package/src/components/prompt-editor-with-inputs/editor.tsx +25 -0
  42. package/src/components/prompt-editor-with-inputs/index.tsx +5 -15
  43. package/src/components/prompt-editor-with-variables/editor.tsx +22 -0
  44. package/src/components/prompt-editor-with-variables/extensions/variable-tag.tsx +10 -18
  45. package/src/components/prompt-editor-with-variables/index.tsx +5 -13
  46. package/src/shared/index.ts +1 -0
  47. package/src/shared/polyfill-create-root/index.tsx +33 -0
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import React, { useMemo } from 'react';
7
+
8
+ import { I18n } from '@flowgram.ai/editor';
9
+ import { Input } from '@douyinfe/semi-ui';
10
+
11
+ import { InjectDynamicValueInput } from '@/components/dynamic-value-input';
12
+
13
+ import { DBConditionOptionType, DBConditionRowValueType, IRules, OpConfigs } from './types';
14
+ import { UIContainer, UILeft, UIOperator, UIRight, UIValues } from './styles';
15
+ import { useOp } from './hooks/use-op';
16
+ import { useLeft } from './hooks/use-left';
17
+
18
+ interface PropTypes {
19
+ value?: DBConditionRowValueType;
20
+ onChange: (value?: DBConditionRowValueType) => void;
21
+ style?: React.CSSProperties;
22
+ options?: DBConditionOptionType[];
23
+ readonly?: boolean;
24
+ ruleConfig?: {
25
+ ops?: OpConfigs;
26
+ rules?: IRules;
27
+ };
28
+ }
29
+
30
+ const defaultRuleConfig = {
31
+ ops: {},
32
+ rules: {},
33
+ };
34
+
35
+ export function DBConditionRow({
36
+ style,
37
+ value,
38
+ onChange,
39
+ readonly,
40
+ options,
41
+ ruleConfig = defaultRuleConfig,
42
+ }: PropTypes) {
43
+ const { left, operator, right } = value || {};
44
+
45
+ const { rule, renderDBOptionSelect } = useLeft({
46
+ left,
47
+ options,
48
+ onChange: (leftKey) => onChange({ ...value, left: leftKey }),
49
+ readonly,
50
+ userRules: ruleConfig.rules,
51
+ });
52
+
53
+ const { renderOpSelect, opConfig } = useOp({
54
+ rule,
55
+ op: operator,
56
+ onChange: (v) => onChange({ ...value, operator: v }),
57
+ readonly,
58
+ userOps: ruleConfig.ops,
59
+ });
60
+
61
+ const targetSchema = useMemo(() => {
62
+ const targetType: string | null = rule?.[operator || ''] || null;
63
+ return targetType ? { type: targetType, extra: { weak: true } } : null;
64
+ }, [rule, opConfig]);
65
+
66
+ return (
67
+ <UIContainer style={style}>
68
+ <UIOperator>{renderOpSelect()}</UIOperator>
69
+ <UIValues>
70
+ <UILeft>{renderDBOptionSelect()}</UILeft>
71
+ <UIRight>
72
+ {targetSchema ? (
73
+ <InjectDynamicValueInput
74
+ readonly={readonly || !rule}
75
+ value={right}
76
+ schema={targetSchema}
77
+ onChange={(v) => onChange({ ...value, right: v })}
78
+ />
79
+ ) : (
80
+ <Input
81
+ size="small"
82
+ disabled
83
+ style={{ pointerEvents: 'none' }}
84
+ value={opConfig?.rightDisplay || I18n.t('Empty')}
85
+ />
86
+ )}
87
+ </UIRight>
88
+ </UIValues>
89
+ </UIContainer>
90
+ );
91
+ }
92
+
93
+ export { type DBConditionRowValueType, type DBConditionOptionType };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import styled from 'styled-components';
7
+ import { Select } from '@douyinfe/semi-ui';
8
+
9
+ export const UIContainer = styled.div`
10
+ display: flex;
11
+ align-items: center;
12
+ gap: 4px;
13
+ `;
14
+
15
+ export const UIOperator = styled.div``;
16
+
17
+ export const UILeft = styled.div`
18
+ width: 100%;
19
+ `;
20
+
21
+ export const UIRight = styled.div`
22
+ width: 100%;
23
+ `;
24
+
25
+ export const UIValues = styled.div`
26
+ flex-grow: 1;
27
+ display: flex;
28
+ flex-direction: column;
29
+ align-items: center;
30
+ gap: 4px;
31
+ `;
32
+
33
+ export const UIOptionLabel = styled.div`
34
+ display: flex;
35
+ align-items: center;
36
+ gap: 10px;
37
+ `;
38
+
39
+ export const UISelect = styled(Select)`
40
+ & .semi-select-selection {
41
+ margin-left: 5px;
42
+ }
43
+ `;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { IJsonSchema } from '@flowgram.ai/json-schema';
7
+
8
+ import { IFlowConstantRefValue } from '@/typings';
9
+
10
+ export interface OpConfig {
11
+ label: string;
12
+ abbreviation: string;
13
+ // When right is not a value, display this text
14
+ rightDisplay?: string;
15
+ }
16
+
17
+ export type OpConfigs = Record<string, OpConfig>;
18
+
19
+ export type IRule = Partial<Record<string, string | null>>;
20
+
21
+ export type IRules = Record<string, IRule>;
22
+
23
+ export interface DBConditionRowValueType {
24
+ left?: string;
25
+ schema?: IJsonSchema;
26
+ operator?: string;
27
+ right?: IFlowConstantRefValue;
28
+ }
29
+
30
+ export interface DBConditionOptionType {
31
+ label: string | JSX.Element;
32
+ value: string;
33
+ schema: IJsonSchema;
34
+ }
@@ -10,6 +10,7 @@ export * from './batch-variable-selector';
10
10
  export * from './constant-input';
11
11
  export * from './dynamic-value-input';
12
12
  export * from './condition-row';
13
+ export * from './db-condition-row';
13
14
  export * from './batch-outputs';
14
15
  export * from './prompt-editor';
15
16
  export * from './prompt-editor-with-variables';
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import React from 'react';
7
+
8
+ import { I18n } from '@flowgram.ai/editor';
9
+ import { transformerCreator } from '@coze-editor/editor/preset-code';
10
+ import { Text } from '@coze-editor/editor/language-json';
11
+
12
+ import { CodeEditor, type CodeEditorPropsType } from '@/components/code-editor';
13
+
14
+ import { VariableTree } from './extensions/variable-tree';
15
+ import { VariableTagInject } from './extensions/variable-tag';
16
+
17
+ type Match = { match: string; range: [number, number] };
18
+ function findAllMatches(inputString: string, regex: RegExp): Match[] {
19
+ const globalRegex = new RegExp(
20
+ regex,
21
+ regex.flags.includes('g') ? regex.flags : regex.flags + 'g'
22
+ );
23
+ let match;
24
+ const matches: Match[] = [];
25
+
26
+ while ((match = globalRegex.exec(inputString)) !== null) {
27
+ if (match.index === globalRegex.lastIndex) {
28
+ globalRegex.lastIndex++;
29
+ }
30
+ matches.push({
31
+ match: match[0],
32
+ range: [match.index, match.index + match[0].length],
33
+ });
34
+ }
35
+
36
+ return matches;
37
+ }
38
+
39
+ const transformer = transformerCreator((text: Text) => {
40
+ const originalSource = text.toString();
41
+ const matches = findAllMatches(originalSource, /\{\{([^\}]*)\}\}/g);
42
+
43
+ if (matches.length > 0) {
44
+ matches.forEach(({ range }) => {
45
+ text.replaceRange(range[0], range[1], 'null');
46
+ });
47
+ }
48
+
49
+ return text;
50
+ });
51
+
52
+ export interface JsonEditorWithVariablesProps extends Omit<CodeEditorPropsType, 'languageId'> {}
53
+
54
+ export function JsonEditorWithVariables(props: JsonEditorWithVariablesProps) {
55
+ return (
56
+ <CodeEditor
57
+ languageId="json"
58
+ activeLinePlaceholder={I18n.t("Press '@' to Select variable")}
59
+ {...props}
60
+ options={{
61
+ transformer,
62
+ ...(props.options || {}),
63
+ }}
64
+ >
65
+ <VariableTree />
66
+ <VariableTagInject />
67
+ </CodeEditor>
68
+ );
69
+ }
@@ -5,7 +5,6 @@
5
5
 
6
6
  import React, { useLayoutEffect } from 'react';
7
7
 
8
- import { createRoot, Root } from 'react-dom/client';
9
8
  import { isEqual, last } from 'lodash';
10
9
  import {
11
10
  BaseVariableField,
@@ -26,6 +25,8 @@ import {
26
25
  WidgetType,
27
26
  } from '@codemirror/view';
28
27
 
28
+ import { IPolyfillRoot, polyfillCreateRoot } from '@/shared';
29
+
29
30
  import { UIPopoverContent, UIRootTitle, UITag, UIVarName } from '../styles';
30
31
 
31
32
  class VariableTagWidget extends WidgetType {
@@ -35,7 +36,7 @@ class VariableTagWidget extends WidgetType {
35
36
 
36
37
  scope: Scope;
37
38
 
38
- root: Root;
39
+ root: IPolyfillRoot;
39
40
 
40
41
  constructor({ keyPath, scope }: { keyPath?: string[]; scope: Scope }) {
41
42
  super();
@@ -90,7 +91,7 @@ class VariableTagWidget extends WidgetType {
90
91
  toDOM(view: EditorView): HTMLElement {
91
92
  const dom = document.createElement('span');
92
93
 
93
- this.root = createRoot(dom);
94
+ this.root = polyfillCreateRoot(dom);
94
95
 
95
96
  this.toDispose.push(
96
97
  Disposable.create(() => {
@@ -3,65 +3,10 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- import React from 'react';
6
+ import { lazy } from 'react';
7
7
 
8
- import { transformerCreator } from '@coze-editor/editor/preset-code';
9
- import { Text } from '@coze-editor/editor/language-json';
8
+ export const JsonEditorWithVariables = lazy(() =>
9
+ import('./editor').then((module) => ({ default: module.JsonEditorWithVariables }))
10
+ );
10
11
 
11
- import { CodeEditor, type CodeEditorPropsType } from '@/components/code-editor';
12
-
13
- import { VariableTree } from './extensions/variable-tree';
14
- import { VariableTagInject } from './extensions/variable-tag';
15
- import { I18n } from '@flowgram.ai/editor';
16
-
17
- type Match = { match: string; range: [number, number] };
18
- function findAllMatches(inputString: string, regex: RegExp): Match[] {
19
- const globalRegex = new RegExp(
20
- regex,
21
- regex.flags.includes('g') ? regex.flags : regex.flags + 'g'
22
- );
23
- let match;
24
- const matches: Match[] = [];
25
-
26
- while ((match = globalRegex.exec(inputString)) !== null) {
27
- if (match.index === globalRegex.lastIndex) {
28
- globalRegex.lastIndex++;
29
- }
30
- matches.push({
31
- match: match[0],
32
- range: [match.index, match.index + match[0].length],
33
- });
34
- }
35
-
36
- return matches;
37
- }
38
-
39
- const transformer = transformerCreator((text: Text) => {
40
- const originalSource = text.toString();
41
- const matches = findAllMatches(originalSource, /\{\{([^\}]*)\}\}/g);
42
-
43
- if (matches.length > 0) {
44
- matches.forEach(({ range }) => {
45
- text.replaceRange(range[0], range[1], 'null');
46
- });
47
- }
48
-
49
- return text;
50
- });
51
-
52
- export function JsonEditorWithVariables(props: Omit<CodeEditorPropsType, 'languageId'>) {
53
- return (
54
- <CodeEditor
55
- languageId="json"
56
- activeLinePlaceholder={I18n.t("Press '@' to Select variable")}
57
- {...props}
58
- options={{
59
- transformer,
60
- ...(props.options || {}),
61
- }}
62
- >
63
- <VariableTree />
64
- <VariableTagInject />
65
- </CodeEditor>
66
- );
67
- }
12
+ export type { JsonEditorWithVariablesProps } from './editor';
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import React, { useEffect, useRef } from 'react';
7
+
8
+ import {
9
+ Renderer,
10
+ EditorProvider,
11
+ ActiveLinePlaceholder,
12
+ InferValues,
13
+ } from '@coze-editor/editor/react';
14
+ import preset, { EditorAPI } from '@coze-editor/editor/preset-prompt';
15
+
16
+ import { PropsType } from './types';
17
+ import { UIContainer } from './styles';
18
+ import MarkdownHighlight from './extensions/markdown';
19
+ import LanguageSupport from './extensions/language-support';
20
+ import JinjaHighlight from './extensions/jinja';
21
+
22
+ type Preset = typeof preset;
23
+ type Options = Partial<InferValues<Preset[number]>>;
24
+
25
+ export interface PromptEditorPropsType extends PropsType {
26
+ options?: Options;
27
+ }
28
+
29
+ export function PromptEditor(props: PromptEditorPropsType) {
30
+ const {
31
+ value,
32
+ onChange,
33
+ readonly,
34
+ placeholder,
35
+ activeLinePlaceholder,
36
+ style,
37
+ hasError,
38
+ children,
39
+ disableMarkdownHighlight,
40
+ options,
41
+ } = props || {};
42
+
43
+ const editorRef = useRef<EditorAPI | null>(null);
44
+
45
+ useEffect(() => {
46
+ // listen to value change
47
+ if (editorRef.current?.getValue() !== value?.content) {
48
+ editorRef.current?.setValue(String(value?.content || ''));
49
+ }
50
+ }, [value]);
51
+
52
+ return (
53
+ <UIContainer $hasError={hasError} style={style}>
54
+ <EditorProvider>
55
+ <Renderer
56
+ didMount={(editor: EditorAPI) => {
57
+ editorRef.current = editor;
58
+ }}
59
+ plugins={preset}
60
+ defaultValue={String(value?.content)}
61
+ options={{
62
+ readOnly: readonly,
63
+ editable: !readonly,
64
+ placeholder,
65
+ ...options,
66
+ }}
67
+ onChange={(e) => {
68
+ onChange({ type: 'template', content: e.value });
69
+ }}
70
+ />
71
+ {activeLinePlaceholder && (
72
+ <ActiveLinePlaceholder>{activeLinePlaceholder}</ActiveLinePlaceholder>
73
+ )}
74
+ {!disableMarkdownHighlight && <MarkdownHighlight />}
75
+ <LanguageSupport />
76
+ <JinjaHighlight />
77
+ {children}
78
+ </EditorProvider>
79
+ </UIContainer>
80
+ );
81
+ }
@@ -3,74 +3,10 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- import React, { useEffect, useRef } from 'react';
6
+ import { lazy } from 'react';
7
7
 
8
- import { Renderer, EditorProvider, ActiveLinePlaceholder, InferValues } from '@coze-editor/editor/react';
9
- import preset, { EditorAPI } from '@coze-editor/editor/preset-prompt';
8
+ export const PromptEditor = lazy(() =>
9
+ import('./editor').then((module) => ({ default: module.PromptEditor }))
10
+ );
10
11
 
11
- import { PropsType } from './types';
12
- import { UIContainer } from './styles';
13
- import MarkdownHighlight from './extensions/markdown';
14
- import LanguageSupport from './extensions/language-support';
15
- import JinjaHighlight from './extensions/jinja';
16
-
17
- type Preset = typeof preset;
18
- type Options = Partial<InferValues<Preset[number]>>;
19
-
20
- export interface PromptEditorPropsType extends PropsType {
21
- options?: Options;
22
- }
23
-
24
- export function PromptEditor(props: PromptEditorPropsType) {
25
- const {
26
- value,
27
- onChange,
28
- readonly,
29
- placeholder,
30
- activeLinePlaceholder,
31
- style,
32
- hasError,
33
- children,
34
- disableMarkdownHighlight,
35
- options,
36
- } = props || {};
37
-
38
- const editorRef = useRef<EditorAPI | null>(null);
39
-
40
- useEffect(() => {
41
- // listen to value change
42
- if (editorRef.current?.getValue() !== value?.content) {
43
- editorRef.current?.setValue(String(value?.content || ''));
44
- }
45
- }, [value]);
46
-
47
- return (
48
- <UIContainer $hasError={hasError} style={style}>
49
- <EditorProvider>
50
- <Renderer
51
- didMount={(editor: EditorAPI) => {
52
- editorRef.current = editor;
53
- }}
54
- plugins={preset}
55
- defaultValue={String(value?.content)}
56
- options={{
57
- readOnly: readonly,
58
- editable: !readonly,
59
- placeholder,
60
- ...options
61
- }}
62
- onChange={(e) => {
63
- onChange({ type: 'template', content: e.value });
64
- }}
65
- />
66
- {activeLinePlaceholder && (
67
- <ActiveLinePlaceholder>{activeLinePlaceholder}</ActiveLinePlaceholder>
68
- )}
69
- {!disableMarkdownHighlight && <MarkdownHighlight />}
70
- <LanguageSupport />
71
- <JinjaHighlight />
72
- {children}
73
- </EditorProvider>
74
- </UIContainer>
75
- );
76
- }
12
+ export type { PromptEditorPropsType } from './editor';
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import React from 'react';
7
+
8
+ import { PromptEditor, PromptEditorPropsType } from '@/components/prompt-editor';
9
+
10
+ import { InputsTree } from './extensions/inputs-tree';
11
+
12
+ export interface PromptEditorWithInputsProps extends PromptEditorPropsType {
13
+ inputsValues: any;
14
+ }
15
+
16
+ export function PromptEditorWithInputs({
17
+ inputsValues,
18
+ ...restProps
19
+ }: PromptEditorWithInputsProps) {
20
+ return (
21
+ <PromptEditor {...restProps}>
22
+ <InputsTree inputsValues={inputsValues} />
23
+ </PromptEditor>
24
+ );
25
+ }
@@ -3,20 +3,10 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- import React from 'react';
6
+ import { lazy } from 'react';
7
7
 
8
- import { PromptEditor, PromptEditorPropsType } from '@/components/prompt-editor';
8
+ export const PromptEditorWithInputs = lazy(() =>
9
+ import('./editor').then((module) => ({ default: module.PromptEditorWithInputs }))
10
+ );
9
11
 
10
- import { InputsTree } from './extensions/inputs-tree';
11
-
12
- interface PropsType extends PromptEditorPropsType {
13
- inputsValues: any;
14
- }
15
-
16
- export function PromptEditorWithInputs({ inputsValues, ...restProps }: PropsType) {
17
- return (
18
- <PromptEditor {...restProps}>
19
- <InputsTree inputsValues={inputsValues} />
20
- </PromptEditor>
21
- );
22
- }
12
+ export type { PromptEditorWithInputsProps } from './editor';
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import React from 'react';
7
+
8
+ import { PromptEditor, PromptEditorPropsType } from '@/components/prompt-editor';
9
+
10
+ import { VariableTree } from './extensions/variable-tree';
11
+ import { VariableTagInject } from './extensions/variable-tag';
12
+
13
+ export interface PromptEditorWithVariablesProps extends PromptEditorPropsType {}
14
+
15
+ export function PromptEditorWithVariables(props: PromptEditorWithVariablesProps) {
16
+ return (
17
+ <PromptEditor {...props}>
18
+ <VariableTree />
19
+ <VariableTagInject />
20
+ </PromptEditor>
21
+ );
22
+ }
@@ -3,7 +3,6 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- import ReactDOM from 'react-dom';
7
6
  import React, { useLayoutEffect } from 'react';
8
7
 
9
8
  import { isEqual, last } from 'lodash';
@@ -26,6 +25,8 @@ import {
26
25
  WidgetType,
27
26
  } from '@codemirror/view';
28
27
 
28
+ import { IPolyfillRoot, polyfillCreateRoot } from '@/shared';
29
+
29
30
  import { UIPopoverContent, UIRootTitle, UITag, UIVarName } from '../styles';
30
31
 
31
32
  class VariableTagWidget extends WidgetType {
@@ -35,7 +36,7 @@ class VariableTagWidget extends WidgetType {
35
36
 
36
37
  scope: Scope;
37
38
 
38
- rootDOM?: HTMLSpanElement;
39
+ root: IPolyfillRoot;
39
40
 
40
41
  constructor({ keyPath, scope }: { keyPath?: string[]; scope: Scope }) {
41
42
  super();
@@ -52,14 +53,9 @@ class VariableTagWidget extends WidgetType {
52
53
  return icon;
53
54
  };
54
55
 
55
- renderReact(jsx: React.ReactElement) {
56
- // NOTICE: For React 19, upgrade to 'react-dom/client'
57
- ReactDOM.render(jsx, this.rootDOM!);
58
- }
59
-
60
56
  renderVariable(v?: BaseVariableField) {
61
57
  if (!v) {
62
- this.renderReact(
58
+ this.root.render(
63
59
  <UITag prefixIcon={<IconIssueStroked />} color="amber">
64
60
  Unknown
65
61
  </UITag>
@@ -67,17 +63,14 @@ class VariableTagWidget extends WidgetType {
67
63
  return;
68
64
  }
69
65
 
70
- const rootField = last(v.parentFields) || v;
71
- const isRoot = v.parentFields.length === 0;
66
+ const rootField = last(v.parentFields);
72
67
 
73
68
  const rootTitle = (
74
- <UIRootTitle>
75
- {rootField?.meta.title ? `${rootField.meta.title} ${isRoot ? '' : '-'} ` : ''}
76
- </UIRootTitle>
69
+ <UIRootTitle>{rootField?.meta.title ? `${rootField.meta.title} -` : ''}</UIRootTitle>
77
70
  );
78
71
  const rootIcon = this.renderIcon(rootField?.meta.icon);
79
72
 
80
- this.renderReact(
73
+ this.root.render(
81
74
  <Popover
82
75
  content={
83
76
  <UIPopoverContent>
@@ -89,7 +82,7 @@ class VariableTagWidget extends WidgetType {
89
82
  >
90
83
  <UITag prefixIcon={rootIcon}>
91
84
  {rootTitle}
92
- {!isRoot && <UIVarName>{v?.key}</UIVarName>}
85
+ <UIVarName>{v?.key}</UIVarName>
93
86
  </UITag>
94
87
  </Popover>
95
88
  );
@@ -98,12 +91,11 @@ class VariableTagWidget extends WidgetType {
98
91
  toDOM(view: EditorView): HTMLElement {
99
92
  const dom = document.createElement('span');
100
93
 
101
- this.rootDOM = dom;
94
+ this.root = polyfillCreateRoot(dom);
102
95
 
103
96
  this.toDispose.push(
104
97
  Disposable.create(() => {
105
- // NOTICE: For React 19, upgrade to 'react-dom/client'
106
- ReactDOM.unmountComponentAtNode(this.rootDOM!);
98
+ this.root.unmount();
107
99
  })
108
100
  );
109
101