JS: buildNodeStyles

File: tests/js/unit/template-builder/buildNodeStyles.test.js Tests: buildNodeStyles in admin/assets/js/src/template-builder/utils/buildNodeStyles.js


What this function does

buildNodeStyles( nodes, device ) takes the node tree from the Template Builder and returns a CSS string. That string is injected as an inline <style> block into the canvas iframe so you see a live preview as you edit.

It is called every time any node property changes — background color, gap, padding, font size, visibility, etc.


How the CSS is targeted

Each node in the canvas has a data-node-id attribute on its DOM element. The generated CSS uses attribute selectors to target each node individually:

[data-node-id="node-1"] { display: flex; flex-direction: column; background-color: #ffffff; }

This means every node gets its own scoped rule. No class names are shared between nodes, so changing one node's styles cannot affect another.


The function always prepends one fixed rule regardless of the node tree:

.sanilwb-tbve-link { color: inherit; text-decoration: none; }

This resets anchor tags inside the template canvas so they do not inherit blue underline styles from the browser or theme. It is included on every call — even when the nodes array is empty — because the canvas DOM always contains the link wrapper elements.


Tests

Produces a [data-node-id] rule and display:flex for a div node

const nodes = [{
    id:        'node-1',
    type:      'div',
    direction: 'column',
    bgcolor:   '#ffffff',
    children:  [],
}];

const css = buildNodeStyles( nodes, 'desktop' );

expect( css ).toContain( '.sanilwb-tbve-link' );         // base rule always present
expect( css ).toContain( '[data-node-id="node-1"]' );    // node-specific rule emitted
expect( css ).toContain( 'display:flex' );               // div nodes are always flex

div nodes are the structural containers in the Template Builder. They always render as display: flex because they support a direction property (row or column) that controls how their children are laid out.


const css = buildNodeStyles( [], 'desktop' );

expect( css ).toBe( '.sanilwb-tbve-link{color:inherit;text-decoration:none;}' );

A new template with no nodes yet should not produce any node rules — but the link-reset rule must still be there. This test pins the exact output so regressions (extra whitespace, missing semicolons, extra rules) are caught immediately.


Relationship to the inline style block in public/hooks.php

The canvas iframe (?sanilwb_preview=1) also receives an inline <style> block from public/hooks.php. Any CSS class added to template-builder.scss that is used by canvas elements must also be added to that inline block — otherwise styles work in the editor but not in the preview iframe.

buildNodeStyles is only responsible for the node-specific dynamic CSS (the [data-node-id="..."] rules). The static class-based styles (tbve-* classes) live in the stylesheet and the hooks.php block.