dynamic-categorize.tsx
Overview
dynamic-categorize.tsx is a React functional component file that provides a dynamic, user-interactive form UI for managing a list of categories. Each category can be named, described, provided with examples, and linked to a next step. The form supports adding, editing, and removing categories dynamically with real-time validation for unique category names.
This component is designed for use within a larger workflow or flowchart editor where nodes represent discrete steps, and categorization helps route or organize process logic dynamically. The file leverages Ant Design's form and UI components, custom hooks for translation and form option building, and integrates with the XYFlow library to update node internals when categories change.
Detailed Explanation
Interfaces
IProps
interface IProps {
nodeId?: string;
}
Purpose: Props for the main
DynamicCategorizecomponent.Properties:
nodeId(optional): Identifier of the node this categorization belongs to, used to notify and update node internals when changes occur.
INameInputProps
interface INameInputProps {
value?: string;
onChange?: (value: string) => void;
otherNames?: string[];
validate(errors: string[]): void;
}
Purpose: Props for the
NameInputcomponent, which provides controlled input for category names with validation.Properties:
value: The current input value.onChange: Callback fired when the input value is validated and changed.otherNames: Array of other existing names to check for duplicates.validate: Function to report validation errors to the parent form.
Utility Function
getOtherFieldValues
const getOtherFieldValues = (
form: FormInstance,
formListName: string = 'items',
field: FormListFieldData,
latestField: string,
) => string[]
Purpose: Extracts values of a specific field (
latestField) from all form list items, excluding the current field to avoid self-comparison.Parameters:
form: Ant Design form instance.formListName: Name of the form list field (defaults to'items').field: The current form list field data to exclude.latestField: The specific sub-field name to extract (e.g.,'name').
Returns: Array of string values from other items for the specified field.
Usage: Used to check for duplicate category names or references in the form list.
Components
NameInput
const NameInput: React.FC<INameInputProps>
Purpose: Controlled input component for category names with live validation.
Behavior:
Validates that the input is not empty and does not duplicate any names in
otherNames.Updates validation errors via
validatecallback.Calls
onChangeonly when the input loses focus and passes validation.
State:
name: Local state to manage input value.
Hooks:
useTranslate('flow')for localization strings.
Example Usage:
<NameInput value={categoryName} onChange={(val) => setCategoryName(val)} otherNames={existingCategoryNames} validate={(errors) => form.setFields([{name: 'categoryName', errors}])} />Important: Uses
trimto ignore whitespace-only names.
FormSet
const FormSet: React.FC<IProps & { field: FormListFieldData }>
Purpose: Renders the form inputs for a single category item inside the form list.
Fields Rendered:
Category Name (
name): UsesNameInputwith validation.Description (
description): TextArea input.Examples (
examples): TextArea input.Next Step (
to): Select input populated dynamically with options viauseBuildFormSelectOptions.Index (
index): Hidden input to track order.
Parameters:
nodeId: Passed down for option building context.field: The FormListFieldData representing this item.
Implementation Details:
Uses Ant Design
Form.Itemwith appropriate validation.Leverages
getOtherFieldValuesto prevent duplicate category names and next step selections.
Example Usage:
<FormSet nodeId="abc123" field={field} />
DynamicCategorize
const DynamicCategorize: React.FC<IProps>
Purpose: Main component that manages the dynamic list of categories in a form.
Features:
Displays a list of collapsible category panels.
Allows adding new categories with auto-generated unique names (
humanId).Allows removing categories.
Updates node internals on category list changes if
nodeIdis provided.
Hooks:
useUpdateNodeInternalsto notify XYFlow system of node changes.useTranslate('flow')for localized UI text.
UI Elements:
Ant Design
Form.Listfor dynamic form item management.Collapsepanels for each category with a close icon for removal.Buttonto add new categories.
Key Logic:
On add: increments index based on last item's index, assigns a human-readable unique name.
On remove: removes the category and updates the UI.
Example usage:
<Form form={formInstance}> <DynamicCategorize nodeId="node123" /> </Form>Interaction with System:
Calls
updateNodeInternals(nodeId)to sync changes with XYFlow when categories change.
Important Implementation Details
Validation Logic:
NameInputenforces uniqueness and non-empty names using localized error messages. Validation occurs on input change and blur events.Dynamic Form Management: Utilizes Ant Design's
Form.ListAPI to handle an array of form items with add/remove capabilities and dynamic field names.Node Update Integration: Uses XYFlow's
useUpdateNodeInternalshook to notify the parent flow system about changes to the node's category data, ensuring the overall flow state remains consistent.Human-readable IDs: Uses
human-idto generate readable and unique default names for new categories.Localization: All user-facing text is translated via a custom
useTranslatehook scoped to'flow'namespace.Styling: Uses CSS module styles imported from
index.lessfor layout and visual styling of category cards and buttons.
Interaction with Other Parts of the System
XYFlow React Library: The component integrates with XYFlow's
useUpdateNodeInternalsto update node metadata when categories change.Common Hooks: Uses
useTranslatefor i18n support anduseBuildFormSelectOptionsto dynamically generate options for the "Next Step" select field based on the current node and flow configuration.Ant Design UI Framework: The file heavily depends on Ant Design components (
Form,Input,Select,Collapse,Button) for form management and UI.Constants: Uses an
Operator.Categorizeconstant to specify the type of operation for building form select options.Styles: CSS modules provide scoped styling, ensuring consistent look and feel within the flow editor UI.
Visual Diagram
componentDiagram
component DynamicCategorize {
+nodeId?: string
+Form.List "items"
+addCategory()
+removeCategory()
+updateNodeInternals(nodeId)
}
component FormSet {
+nodeId?: string
+field: FormListFieldData
+NameInput
+Input.TextArea (description, examples)
+Select (nextStep)
}
component NameInput {
+value?: string
+onChange(value: string)
+otherNames?: string[]
+validate(errors: string[])
+handleNameChange()
+handleNameBlur()
}
component getOtherFieldValues {
+form: FormInstance
+formListName: string
+field: FormListFieldData
+latestField: string
+returns string[]
}
DynamicCategorize --> FormSet : renders multiple
FormSet --> NameInput : includes
FormSet --> getOtherFieldValues : validates name uniqueness
DynamicCategorize --> getOtherFieldValues : validates nextStep uniqueness
DynamicCategorize --> useUpdateNodeInternals : updates node state
DynamicCategorize --> useTranslate : for i18n
FormSet --> useBuildFormSelectOptions : builds nextStep options
Summary
dynamic-categorize.tsx is a well-structured React component file that provides a dynamic UI for managing categories within a flow node. It ensures data integrity via validation, supports localization, and integrates smoothly with the XYFlow system to keep node data synchronized. Its modular design, clear separation of concerns, and reliance on popular libraries like Ant Design make it both maintainable and extendable.
Usage Example
import { Form } from 'antd';
import DynamicCategorize from './dynamic-categorize';
const MyFlowNodeEditor = ({ nodeId }: { nodeId: string }) => {
const [form] = Form.useForm();
return (
<Form form={form} initialValues={{ items: [] }}>
<DynamicCategorize nodeId={nodeId} />
</Form>
);
};
This example shows how to embed the DynamicCategorize component inside an Ant Design Form and provide the node identifier for proper integration with the flow system.