Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Props & API Reference

Complete reference for the DataLogicEditor component and related exports.

DataLogicEditor Props

Required Props

value

The JSONLogic expression to render.

value: JsonLogicValue | null

Accepts any valid JSONLogic expression or null for an empty state. An expression nested deeper than 100 levels renders an error instead of a diagram.

The editor compares value by reference. When you pass back the value onChange handed you (or an equal copy), the canvas keeps its selection, open properties panel, pan and zoom. Any other new object counts as a new rule: the canvas remounts and fits the view to it. In a parent that re-renders often, keep value in state or useMemo rather than writing a fresh literal on each render.

// Simple expression
<DataLogicEditor value={{ "==": [1, 1] }} />

// Complex expression
<DataLogicEditor value={{
  "and": [
    { ">=": [{ "var": "age" }, 18] },
    { "var": "active" }
  ]
}} />

// Null for empty state
<DataLogicEditor value={null} />

Optional Props

data

Data context for evaluation. When provided, the editor evaluates the expression through the WASM trace API and the debugger controls become available. Any JSON value is a valid root context: object, array or scalar. Values appear on nodes as you step, not at rest (see Modes). The editor re-runs the trace when the content of data changes, so an inline object is fine. If the WASM engine fails to load, a banner above the diagram gives the load error.

data?: unknown
<DataLogicEditor
  value={{ "var": "user.name" }}
  data={{ user: { name: "Alice" } }}
/>

onChange

Callback fired when the expression changes. It is active whenever editable is set: the editor debounces canvas edits (about 300ms) and passes back the rebuilt JSONLogic expression. Passing that value back as value keeps the selection, the open properties panel, and the pan and zoom.

onChange?: (expr: JsonLogicValue | null) => void
<DataLogicEditor
  value={expression}
  onChange={setExpression}
  editable
/>

editable

Enable editing: node selection, properties panel, context menus, the Insert menu (Cmd/Ctrl+K), keyboard shortcuts, and undo/redo. Keyboard shortcuts apply only while focus is inside this editor, so two editors on one page, or a page with its own shortcuts, do not take each other’s keys.

editable?: boolean

Default: false

<DataLogicEditor value={expr} onChange={setExpr} editable />

templating

Enable templating mode: multi-key objects and arrays in compiled rules become output-shaping templates with embedded JSONLogic expressions, rather than being rejected as invalid JSONLogic. Matches the v5 core API (Engine::builder().with_templating(true)).

templating?: boolean

Default: false

<DataLogicEditor value={expr} templating />

onTemplatingChange

Callback fired when templating mode changes from the toolbar checkbox. The checkbox renders only when this prop is provided; with templating alone the mode is fixed.

onTemplatingChange?: (value: boolean) => void
<DataLogicEditor
  value={expr}
  templating={templating}
  onTemplatingChange={setTemplating}
/>

exampleSuggestions

Optional list of example names to surface as quick-action chips in the empty state. Each chip, when clicked, calls onSelectExample with the corresponding name. Chips render only when you provide both exampleSuggestions and onSelectExample and the editor is empty.

exampleSuggestions?: string[]
<DataLogicEditor
  value={null}
  exampleSuggestions={['Age check', 'Discount rule']}
  onSelectExample={loadExample}
/>

onSelectExample

Callback invoked when a user clicks an empty-state example chip. Receives the example name from exampleSuggestions.

onSelectExample?: (name: string) => void

config

Engine evaluation settings, applied to both the plain result and the traced run. Mirrors the core EvaluationConfig; every key is optional and omitted keys keep the engine default (or the selected preset’s value).

config?: DataLogicEvaluationConfig

interface DataLogicEvaluationConfig {
  preset?: 'default' | 'safe_arithmetic' | 'strict';
  arithmetic_nan_handling?: 'throw_error' | 'ignore_value' | 'coerce_to_zero' | 'return_null';
  division_by_zero?: 'return_saturated' | 'throw_error' | 'return_null' | 'return_infinity';
  loose_equality_errors?: boolean;
  truthy_evaluator?: 'javascript' | 'python' | 'strict_boolean';
  numeric_coercion?: {
    empty_string_to_zero?: boolean;
    null_to_zero?: boolean;
    bool_to_number?: boolean;
    reject_non_numeric?: boolean;
  };
  max_recursion_depth?: number;
  ops_budget?: number;
}
<DataLogicEditor
  value={expr}
  data={data}
  config={{ preset: 'strict', division_by_zero: 'return_null' }}
/>

The toolbar shows a compact summary whenever the settings differ from the engine defaults. The editor keys the engine on the settings, not on the object: an inline literal is fine, and only a change of setting rebuilds the engine, which resets selection, undo history and the debugger position. The engine rejects an unknown key or value with a ConfigurationError. See Configuration for what each setting does.

ops_budget caps the operations one evaluation may charge (see Operation Budget). Crossing it raises a BudgetExceeded error that try cannot catch.

customOperators

Custom operators registered on the evaluation engine, keyed by operator name.

customOperators?: Record<string, (args: unknown[]) => unknown>
<DataLogicEditor
  value={{ discounted: [{ var: 'price' }] }}
  data={{ price: 100 }}
  customOperators={{ discounted: (args) => Number(args[0]) * 0.9 }}
/>

Arguments arrive already evaluated; the return value may be any JSON-serializable value (undefined becomes null), and a thrown exception becomes a runtime evaluation error. Rules using them evaluate and trace like any other, but the palette and help panel only know built-in operators, so custom nodes render with the generic “utility” styling. Built-ins win a name collision: registering "+" has no effect. Adding or removing a name rebuilds the engine; passing new implementations under the same names (an inline object on every render, say) does not, because the engine calls the latest function for each name.

theme

Theme override.

theme?: 'light' | 'dark'

Default: System preference

<DataLogicEditor value={expr} theme="dark" />

The component writes data-theme onto its own .logic-editor root; it does not read a data-theme set on an ancestor.

className

Additional CSS class for the container.

className?: string
<DataLogicEditor value={expr} className="my-editor" />

Type Definitions

JsonLogicValue

The type for JSONLogic expressions:

type JsonLogicPrimitive = string | number | boolean | null;

type JsonLogicExpression = {
  [operator: string]: JsonLogicValue | JsonLogicValue[];
};

type JsonLogicValue =
  | JsonLogicPrimitive
  | JsonLogicPrimitive[]
  | JsonLogicExpression
  | JsonLogicValue[];

Only JsonLogicValue is exported.

Annotate expression literals whose arrays hold more than one operator key. Without the annotation TypeScript widens the array into a union of per-key object types, which the index signature does not accept:

const expression: JsonLogicValue = {
  and: [
    { '>': [{ var: 'age' }, 18] },
    { '==': [{ var: 'status' }, 'active'] },
  ],
};

DataLogicEditorProps

interface DataLogicEditorProps {
  value: JsonLogicValue | null;
  onChange?: (expr: JsonLogicValue | null) => void;
  data?: unknown;
  theme?: 'light' | 'dark';
  className?: string;
  templating?: boolean;
  onTemplatingChange?: (value: boolean) => void;
  config?: DataLogicEvaluationConfig;
  customOperators?: Record<string, DataLogicCustomOperator>;
  editable?: boolean;
  exampleSuggestions?: string[];
  onSelectExample?: (name: string) => void;
}

LogicNode

A React Flow node carrying the package’s custom node data (for advanced customization):

import type { Node } from '@xyflow/react';

type LogicNode = Node<LogicNodeData>;

type LogicNodeData = OperatorNodeData | LiteralNodeData | StructureNodeData;

The data payload is one of three shapes, discriminated by its type field:

interface OperatorNodeData {
  type: 'operator';
  operator: string;
  category: OperatorCategory;
  label: string;
  icon: IconName;
  cells: CellData[];        // all arguments as rows
  collapsed?: boolean;
  expressionText?: string;  // single-line text when collapsed
}

interface LiteralNodeData {
  type: 'literal';
  value: JsonLogicValue;
  valueType: 'string' | 'number' | 'boolean' | 'null' | 'array';
}

interface StructureNodeData {
  type: 'structure';
  isArray: boolean;
  formattedJson: string;
  elements: StructureElement[];
  collapsed?: boolean;
  expressionText?: string;
}

LogicEdge

An alias for the React Flow Edge type:

import type { Edge } from '@xyflow/react';

type LogicEdge = Edge;

OperatorCategory

type OperatorCategory =
  | 'variable'
  | 'comparison'
  | 'logical'
  | 'arithmetic'
  | 'control'
  | 'string'
  | 'array'
  | 'object'
  | 'datetime'
  | 'validation'
  | 'error'
  | 'utility'
  | 'flagd'
  | 'tensor';

CATEGORY_COLORS is keyed by NodeCategory, which is OperatorCategory plus 'literal' for literal nodes.


Exports

Component

import { DataLogicEditor } from '@goplasmatic/datalogic-ui';

Types

import type {
  DataLogicEditorProps,
  DataLogicEvaluationConfig,
  DataLogicCustomOperator,
  JsonLogicValue,
  JsonLogicToNodesOptions,
  LogicNode,
  LogicEdge,
  LogicNodeData,
  OperatorNodeData,
  VariableNodeData,
  LiteralNodeData,
  StructureNodeData,
  StructureElement,
  CellData,
  ConversionResult,
  StructuredError,
  TracedResult,
  OperatorCategory,
  FlowDirection,
  IconName,
} from '@goplasmatic/datalogic-ui';

Constants

import { OPERATORS, CATEGORY_COLORS } from '@goplasmatic/datalogic-ui';

OPERATORS: the operator registry, keyed by name. Each entry carries its label, category, arity, properties-panel configuration, and help (summary, return type, notes, and examples). The registry covers every operator the bundled engine accepts, and the package’s test suite evaluates every help example against the engine, so an example that disagrees with the engine fails the tests.

CATEGORY_COLORS: a per-category palette for consumer-side legends, pickers and custom node renderers. The shipped nodes are not coloured by category: they are coloured by the type of value they produce, through the --sig-* tokens described in Customization.

Utilities and hooks

import {
  jsonLogicToNodes,
  applyTreeLayout,
  useWasmEvaluator,
  DataLogicEvaluationError,
  summarizeEvaluationConfig,
  isDefaultEvaluationConfig,
} from '@goplasmatic/datalogic-ui';

jsonLogicToNodes and applyTreeLayout are described under Utility Functions.

useWasmEvaluator: the engine hook the component itself uses. It loads the bundled WASM engine and builds one Engine per combination of the templating flag, the config settings and the set of customOperators names:

const { ready, loading, error, evaluate, evaluateMetered, evaluateWithTrace } = useWasmEvaluator({
  templating: false,
  config: { preset: 'strict' },
  customOperators: { double: (args) => Number(args[0]) * 2 },
});

if (ready) {
  const result = evaluate({ '+': [1, 2] }, {});           // 3
  const trace = evaluateWithTrace({ '+': [1, 2] }, {});   // { result, steps, expression_tree, pointers, ... }
  const { value, ops } = evaluateMetered({ '+': [1, 2] }, {}); // 3, plus the operations charged
}

error holds the message when the engine fails to load. The component shows the same message in a banner when data asks for evaluation.

The traced result (TracedResult) carries result, expression_tree and steps; error and structured_error when evaluation fails; and pointers: for each node id, the RFC 6901 JSON Pointer into the rule of the value that node was compiled from (absent when the rule does not compile).

DataLogicEvaluationError: thrown by evaluate, evaluateMetered and evaluateWithTrace when the engine fails, and when the engine rejects config. Its .structured field is a StructuredError carrying type and message, plus operator, node_ids, thrown, variable, level, index, length, stage, budget or spent where the engine provides them.

summarizeEvaluationConfig / isDefaultEvaluationConfig: format a DataLogicEvaluationConfig as the one-line summary the toolbar shows, and test whether it matches the engine defaults.


Utility Functions

jsonLogicToNodes

Convert a JSONLogic expression to React Flow nodes and edges.

function jsonLogicToNodes(
  expr: JsonLogicValue | null,
  options?: { templating?: boolean }
): ConversionResult

interface ConversionResult {
  nodes: LogicNode[];
  edges: LogicEdge[];
  rootId: string | null;
}

Parameters:

  • expr: JSONLogic expression to convert (null yields an empty result)
  • options.templating: when true, multi-key objects compile to output-shaping templates with embedded JSONLogic

Returns: A ConversionResult with nodes, edges, and rootId (the id of the root node, or null for an empty expression)

Example:

import { jsonLogicToNodes } from '@goplasmatic/datalogic-ui';

const expr = { "==": [{ "var": "x" }, 1] };
const { nodes, edges, rootId } = jsonLogicToNodes(expr);

// nodes: LogicNode[], React Flow nodes whose `data` is
//   OperatorNodeData | LiteralNodeData | StructureNodeData (node `type` is
//   'operator' | 'literal' | 'structure'). The `==` and `var` expressions
//   become operator nodes (categories 'comparison' and 'variable'); the
//   `1` becomes a literal node.
// edges: LogicEdge[], React Flow edges linking each operator to its arguments
// rootId: string, id of the root `==` node

applyTreeLayout

Apply dagre-based tree layout to nodes.

function applyTreeLayout(
  nodes: LogicNode[],
  edges?: LogicEdge[],
  direction?: FlowDirection   // 'flow' | 'hierarchy', default 'flow'
): LogicNode[]

Parameters:

  • nodes: array of nodes
  • edges: optional array of edges. When omitted, the function derives edges from the node relationships
  • direction: 'flow' (default) lays the graph out left-to-right in data-flow order: leaf operands on the left, the root’s result on the right. 'hierarchy' also runs left-to-right but ranks the root first, matching JSON nesting order. The component’s toolbar toggles between the two and reflects the choice as data-direction on the .logic-editor root.

Returns: Nodes with updated positions and dimensions.


Advanced Usage

Custom Node Rendering

For advanced customization, use the utilities to render with your own React Flow setup. The editor’s bundled React Flow styles apply only inside .logic-editor, so import @xyflow/react/dist/style.css for your own canvas (see Customization):

import { ReactFlow } from '@xyflow/react';
import { jsonLogicToNodes, applyTreeLayout } from '@goplasmatic/datalogic-ui';

function CustomEditor({ expression }) {
  const { nodes: rawNodes, edges } = jsonLogicToNodes(expression);
  const nodes = applyTreeLayout(rawNodes, edges);

  return (
    <ReactFlow
      nodes={nodes}
      edges={edges}
      nodeTypes={customNodeTypes}
      // Custom configuration...
    />
  );
}

Accessing Category Colors

import { CATEGORY_COLORS } from '@goplasmatic/datalogic-ui';

// Use in your own legends, pickers or custom node renderers
const logicalColor = CATEGORY_COLORS.logical;  // '#8b5cf6'

To re-theme the shipped nodes, override the --sig-* tokens instead: see Customization.

Next Steps