Thank you @Roko C. Buljan for your help (I wanted to reply as a comment on your post, but my example was too long).
Your approach using :scope
and :not()
works well for the initial example, but I encountered an issue when applying it to a specific parent element.
If I call getDirectChildren(document.querySelector("#layout-3"))
on the initial example, it does not return #layout-4
as expected. I think this happens because the selector :scope .layout:not(.layout .layout)
only considers direct .layout
elements relative to the original parent (.parent
in the example), but it does not properly update when parent
itself is a .layout
.
Here is an extended example demonstrating the issue:
const getDirectChildren = (parent, sel = ".layout") =>
[...parent.querySelectorAll(`:scope ${sel}:not(${sel} ${sel})`)];
// Example 1 : Should print [#layout-1, #layout-2, #layout-7]
let app = document.querySelector(".app");
console.log("App descendant children", getDirectChildren(app)); // Result: Correct!
// Example 2 : Should print [#layout-3, #layout-4, #layout-6]
let layout2 = document.querySelector("#layout-2");
console.log("Layout 2 descendant children", getDirectChildren(layout2)); // Current result: []
// Example 3 : Should print [#layout-5]
let layout4 = document.querySelector("#layout-4");
console.log("Layout 4 descendant children", getDirectChildren(layout4)); // Current result: []
<div class="app">
<div>
<div class="layout" id="layout-1"></div>
</div>
<div>
<div class="layout" id="layout-2">
<div class="layout" id="layout-3"></div>
<div>
<div class="layout" id="layout-4">
<div>
<div class="layout" id="layout-5"></div>
</div>
</div>
<div class="layout" id="layout-6"></div>
</div>
<div></div>
</div>
</div>
<div class="layout" id="layout-7"></div>
</div>
This shows that while the function works at the top level, it fails to return children when applied to .layout
elements deeper in the hierarchy.