Flatten a tree in DFS order. Each emitted FlatTreeNode carries
aria-level (depth + 1), aria-posinset, and aria-setsize data so the
rendering layer can bind them directly.
Derives a stable id from (value, path). Defaults to
path.join('.') — adequate for static trees; supply a key-based idFn
for data that may be re-ordered without changing identity.