Core API

Builder Ref

Builder ref API
export interface IBuilderRef {
cloneNode: (nodeId: string) => boolean;
deleteNode: (nodeId: string) => boolean;
replaceNode: (nodeId: string, node: NormalizedNode) => boolean;
updateNode: (
nodeId: string,
updater: (node: NormalizedNode) => NormalizedNode
) => boolean;
insertNodes: (
nodes: NormalizedQuery,
index: number,
parentId?: string
) => boolean;
addNode: (node: NormalizedNode, parentId?: string, index?: number) => boolean;
addGroup: (
groupType?: QueryGroupType,
parentId?: string,
index?: number
) => boolean;
addRule: (
rule?: Partial<INormalizedRuleNode>,
parentId?: string,
index?: number
) => boolean;
moveNode: (nodeId: string, index: number, parentId?: string) => boolean;
setNodeLock: (
nodeId: string,
state: 'unlocked' | 'self' | 'all'
) => boolean;
lockNode: (nodeId: string, state?: 'self' | 'all') => boolean;
unlockNode: (nodeId: string) => boolean;
getNodeById: (nodeId: string) => NormalizedNode | undefined;
getNearestField: (
currentNodeId: string,
targetFieldName: string
) => INearestFieldMatch | undefined;
isFieldInUse: (field: string) => boolean;
getFieldOptionState: (field: string) => IBuilderFieldOptionState;
getRuleOptionState: (ruleId: string) => IBuilderFieldOptionState;
subscribeToFieldOptionState: (
field: string,
listener: BuilderFieldOptionStateListener
) => () => void;
subscribeToRuleOptionState: (
ruleId: string,
listener: BuilderFieldOptionStateListener
) => () => void;
setFieldOptions: (
field: string,
options:
| BuilderFieldOption[]
| ((current: BuilderFieldOption[]) => BuilderFieldOption[])
) => void;
setRuleOptions: (
ruleId: string,
options:
| BuilderFieldOption[]
| ((current: BuilderFieldOption[]) => BuilderFieldOption[])
) => void;
setFieldOptionsStatus: (
field: string,
status: BuilderFieldOptionsStatus
) => void;
setRuleOptionsStatus: (
ruleId: string,
status: BuilderFieldOptionsStatus
) => void;
invalidateFieldOptions: (field: string) => void;
reloadFieldOptions: (field: string) => void;
clearFieldOptions: (field: string) => void;
invalidateRuleOptions: (ruleId: string) => void;
reloadRuleOptions: (ruleId: string) => void;
clearRuleOptions: (ruleId: string) => void;
reconcileRuleValueWithOptions: (
ruleId: string,
config: IBuilderRuleValueReconciliationConfig
) => boolean;
getNodes: () => NormalizedQuery;
getData: () => DenormalizedQuery;
getHistory: () => IBuilderHistoryState;
setHistory: (history: IBuilderHistoryState) => void;
undo: () => void;
redo: () => void;
}
export type BuilderRefListener = (builder: IBuilderRef | null) => void;
export type BuilderRuleDependenciesListener = (
entries: IBuilderRuleDependencyEntry[]
) => void;
export type BuilderFieldDependenciesListener = BuilderRuleDependenciesListener;
export type BuilderFieldOptionStateListener = (
state: IBuilderFieldOptionState
) => void;
export type BuilderRef = React.MutableRefObject<IBuilderRef | null> & {
subscribe: (listener: BuilderRefListener) => () => void;
bindRuleOptions: (
field: string,
config: IBuilderRuleOptionsBindingConfig
) => () => void;
subscribeToRuleDependencies: (
field: string,
dependencyFields: string[],
listener: BuilderRuleDependenciesListener
) => () => void;
subscribeToFieldDependencies: (
field: string,
dependencyFields: string[],
listener: BuilderFieldDependenciesListener
) => () => void;
subscribeToFieldOptionState: (
field: string,
listener: BuilderFieldOptionStateListener
) => () => void;
subscribeToRuleOptionState: (
ruleId: string,
listener: BuilderFieldOptionStateListener
) => () => void;
reconcileRuleValueWithOptions: (
ruleId: string,
config: IBuilderRuleValueReconciliationConfig
) => boolean;
};
export const useBuilderRef = (): BuilderRef;
Rule dependencies hook
export const useBuilderRuleDependencies = (
builderRef: BuilderRef,
field: string,
dependencyFields: string[]
): IBuilderRuleDependencyEntry[];
Rule options binding
export interface IBuilderRuleOptionsResolverContext {
ruleId: string;
field: string;
dependencies: Record<string, INearestFieldMatch | undefined>;
signal: AbortSignal;
}
export interface IBuilderRuleOptionsBindingConfig {
dependencies: string[];
resolve: (
context: IBuilderRuleOptionsResolverContext
) => Promise<BuilderFieldOption[]>;
onError?: (
error: unknown,
context: Omit<IBuilderRuleOptionsResolverContext, 'signal'>
) => void;
onOptionsResolved?: (
context: {
ruleId: string;
field: string;
dependencies: Record<string, INearestFieldMatch | undefined>;
options: BuilderFieldOption[];
}
) => void;
clearOnMissingDependencies?: boolean;
}

How to attach it

  • useBuilderRef() Returns a typed React ref controller for the builder instance.
  • useBuilderRuleDependencies(builderRef, field, dependencyFields) Returns one dependency snapshot per matching rule and is the recommended React-first integration for React Query or similar hook-based data layers.
  • <Builder ref={builderRef} /> Attaches the ref to the builder so builderRef.current exposes the imperative methods.
  • builderRef.subscribe(listener) Subscribes to builder handle updates. The listener fires immediately with the current handle and then again whenever committed builder state replaces that handle.
  • builderRef.bindRuleOptions(field, config) Automatically hydrates and refreshes rule-scoped options for dependency-aware fields. This is the recommended entrypoint when you do not need an external query library to own the orchestration, and onOptionsResolved is the clean place for follow-up work such as explicit value reconciliation.
  • builderRef.subscribeToRuleDependencies(field, dependencyFields, listener) Subscribes to dependency snapshots for one field. The listener receives one entry per matching rule and only re-runs when that rule's dependency context changes.
  • builderRef.subscribeToFieldOptionState(field, listener) and builderRef.subscribeToRuleOptionState(ruleId, listener) Subscribe to reactive loading and option snapshots for external UI such as badges, spinners, or helper text.
Reactive option state
getFieldOptionState() and getRuleOptionState() return snapshots. Use subscribeToFieldOptionState() or subscribeToRuleOptionState() when surrounding React UI should rerender as the state changes.

Read methods

  • getNodeById(nodeId) Returns one normalized node by id, or undefined when it does not exist.
  • getNodes() Returns the current normalized query array.
  • getData() Returns the current denormalized query tree in the same shape emitted by onChange.
  • getHistory() Returns the current history object with past and future stacks.
  • getNearestField(currentNodeId, targetFieldName) Returns the nearest matching rule in the current ancestor chain. This is especially useful for dependency-aware rule options.
  • isFieldInUse(field) Returns true when at least one rule currently targets the given field.
  • getFieldOptionState(field) Returns the shared runtime option list and loading status for a field.
  • getRuleOptionState(ruleId) Returns the rule-scoped runtime option list and loading status for one rule instance.
  • bindRuleOptions(field, config) Resolves dependency-aware options, sets loading, success, and error states, aborts stale requests, and clears removed rules automatically. Use onOptionsResolved when you want to run post-load logic such as reconcileRuleValueWithOptions(...).
  • subscribeToRuleDependencies(field, dependencyFields, listener) Emits dependency entries such as the nearest country for every city rule, which is ideal for dependency-aware dynamic options.
  • subscribeToFieldOptionState(field, listener) and subscribeToRuleOptionState(ruleId, listener) Emit reactive option-state snapshots so external UI can reflect idle, loading, success, or error without waiting for unrelated renders.
  • reconcileRuleValueWithOptions(ruleId, { strategy } ) Reconciles the current rule value against the effective option list. The built-in clear-if-missing strategy is useful when a value should be cleared once it is no longer available after a dependency-driven reload.

Mutation methods

  • cloneNode(nodeId) Clones a rule or group subtree directly below the original node and preserves its read-only configuration.
  • deleteNode(nodeId) Removes a node subtree unless the node itself or one of its descendants is protected by effective read-only state.
  • replaceNode(nodeId, node) Replaces a normalized node directly.
  • updateNode(nodeId, updater) Reads the current normalized node, passes it to an updater, and replaces it with the updater result.
  • insertNodes(nodes, index, parentId?) Inserts one or more normalized nodes at the target index, either at the root or inside a group.
  • addNode(node, parentId?, index?) Inserts one normalized node and appends it when index is omitted.
  • addGroup(groupType?, parentId?, index?) Creates and inserts a new group node.
  • addRule(rule?, parentId?, index?) Creates and inserts a new rule node with optional initial values.
  • moveNode(nodeId, index, parentId?) Moves a node to a new index and optional parent group.

Field Option Methods

  • setFieldOptions(field, options) Replaces the shared runtime option set for a field without changing the original fields prop.
  • setFieldOptionsStatus(field, status) Stores a shared option loading state of 'idle', 'loading', 'success', or 'error'.
  • invalidateFieldOptions(field) Clears the shared runtime cache and falls back to the static options defined in field.value.
  • reloadFieldOptions(field) Invalidates the shared runtime cache and then calls onFieldOptionsReload(field) so the surrounding app can trigger a refetch.
  • clearFieldOptions(field) Removes the shared runtime option state entirely.

Rule Option Methods

  • setRuleOptions(ruleId, options) Replaces the runtime option set for one specific rule instance.
  • setRuleOptionsStatus(ruleId, status) Stores a loading state for one specific rule instance.
  • invalidateRuleOptions(ruleId) Clears the rule-scoped runtime cache and falls back to field-scoped or static options.
  • reloadRuleOptions(ruleId) Invalidates the rule-scoped runtime cache and then calls onRuleOptionsReload(ruleId).
  • clearRuleOptions(ruleId) Removes the rule-scoped runtime option state entirely.
  • reconcileRuleValueWithOptions(ruleId, { strategy: 'clear-if-missing' }) Compares the current rule value against the effective option list for that rule and clears missing selections explicitly instead of doing it automatically on every reload.

Lock and history methods

  • setNodeLock(nodeId, state) Sets the explicit lock state for a rule or group. Groups additionally support 'all' for descendant inheritance.
  • lockNode(nodeId, state?) Convenience wrapper for locking a node. For rules, the effective lock state is always 'self'.
  • unlockNode(nodeId) Clears the node's lock state while preserving object-based readOnly.targets metadata so it can be restored by later lock toggles.
  • undo() and redo() Replay history steps when history is enabled.
  • setHistory(history) Replaces the current history state. This is useful for clearing or restoring custom history snapshots.
© Vojtěch Václav Porteš 2026 - All library contents are available under the MIT license.
Loading privacy preferences...