node-registry.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import {
  2. DataEvent,
  3. EffectFuncProps,
  4. Field,
  5. FieldRenderProps,
  6. FormMeta,
  7. ValidateTrigger,
  8. WorkflowNodeRegistry,
  9. FieldArray,
  10. FieldArrayRenderProps,
  11. } from '@flowgram.ai/free-layout-editor';
  12. import { FieldWrapper } from '@flowgram.ai/demo-node-form';
  13. import { Input, Button, Popover } from '@douyinfe/semi-ui';
  14. import { IconPlus, IconCrossCircleStroked, IconArrowDown } from '@douyinfe/semi-icons';
  15. import './index.css';
  16. import '../index.css';
  17. export const render = () => (
  18. <div className="demo-node-content">
  19. <div className="demo-node-title">Array Examples</div>
  20. <FieldArray name="array">
  21. {({ field, fieldState }: FieldArrayRenderProps<string>) => (
  22. <FieldWrapper title={'My Array'}>
  23. {field.map((child, index) => (
  24. <Field name={child.name} key={child.key}>
  25. {({ field: childField, fieldState: childState }: FieldRenderProps<string>) => (
  26. <FieldWrapper error={childState.errors?.[0]?.message}>
  27. <div className="array-item-wrapper">
  28. <Input {...childField} size={'small'} />
  29. {index < field.value!.length - 1 ? (
  30. <Popover
  31. content={'swap with next element'}
  32. className={'icon-button-popover'}
  33. showArrow
  34. position={'topLeft'}
  35. >
  36. <Button
  37. theme="borderless"
  38. size={'small'}
  39. icon={<IconArrowDown />}
  40. onClick={() => field.swap(index, index + 1)}
  41. />
  42. </Popover>
  43. ) : null}
  44. <Popover
  45. content={'delete current element'}
  46. className={'icon-button-popover'}
  47. showArrow
  48. position={'topLeft'}
  49. >
  50. <Button
  51. theme="borderless"
  52. size={'small'}
  53. icon={<IconCrossCircleStroked />}
  54. onClick={() => field.delete(index)}
  55. />
  56. </Popover>
  57. </div>
  58. </FieldWrapper>
  59. )}
  60. </Field>
  61. ))}
  62. <div>
  63. <Button
  64. size={'small'}
  65. theme="borderless"
  66. icon={<IconPlus />}
  67. onClick={() => field.append('default')}
  68. >
  69. Add
  70. </Button>
  71. </div>
  72. </FieldWrapper>
  73. )}
  74. </FieldArray>
  75. </div>
  76. );
  77. interface FormData {
  78. array: string[];
  79. }
  80. const formMeta: FormMeta<FormData> = {
  81. render,
  82. validateTrigger: ValidateTrigger.onChange,
  83. defaultValues: {
  84. array: ['default'],
  85. },
  86. validate: {
  87. 'array.*': ({ value }) =>
  88. value.length > 8 ? 'max length exceeded: current length is ' + value.length : undefined,
  89. },
  90. effect: {
  91. 'array.*': [
  92. {
  93. event: DataEvent.onValueInit,
  94. effect: ({ value, name }: EffectFuncProps<string, FormData>) => {
  95. console.log(name + ' value init to ', value);
  96. },
  97. },
  98. {
  99. event: DataEvent.onValueChange,
  100. effect: ({ value, name }: EffectFuncProps<string, FormData>) => {
  101. console.log(name + ' value changed to ', value);
  102. },
  103. },
  104. ],
  105. },
  106. };
  107. export const nodeRegistry: WorkflowNodeRegistry = {
  108. type: 'custom',
  109. meta: {},
  110. defaultPorts: [{ type: 'output' }, { type: 'input' }],
  111. formMeta,
  112. };