Vanilla DOM

mountQueryBuilder with no framework, and DOM helpers for drag and drop.

pnpm add @qnot/core @qnot/dom
import '@qnot/core/styles.css';
import { createQueryStore } from '@qnot/core';
import { mountQueryBuilder } from '@qnot/dom';

const store = createQueryStore({ fields, initial: saved });
const dispose = mountQueryBuilder(document.getElementById('filters')!, store, { showLock: true });

store.subscribe(() => save(store.getQuery()));
// later: dispose();

Each node subscribes to its own id and patches only its own elements, with a keyed reconcile per group, so the vanilla builder keeps the same "one rule, one update" behaviour as the framework bindings.

Options

mountQueryBuilder(el, store, options) takes components, labels, className, showNot and showLock. A custom value editor is a factory returning { el, update(props), destroy? }; it's created once and patched in place as the rule changes.

Drag and drop helpers

bindDragHandle, bindDropTarget and bindGroupDropZone attach the store's drag-and-drop to your own elements, and dropPositionOf reads where a drop would land.