Painting Borders

The border resolvers read the framework border rails as BorderFill objects. Apply them to custom rails, or convert them for Highcharts axes and grid lines.

#

Borders and dividers

Every resolver takes an optional { el }: the id or element whose nearest .screen ancestor supplies the paint. The probe technique is documented on Paint API .

  • border(spec, { dir, el }): a border rail as a BorderFill. The spec is a shade step from 10 to 75 or the literal 'black' / 'white' rails; dir is 'h' (default) or 'v'. Framework borders paint as a background on a pseudo-element, so the resolved paint is read there.
  • divider({ dir, el }): the level-6 .divider rail as a BorderFill, probed on the element itself.

Dither-mode lines are multi-layer and list-valued, so BorderFill keeps size, position and repeat as verbatim computed strings. It also carries the renderer-ready SVG program declared by the same CSS rule; JavaScript never parses gradients or derives their geometry.

BorderFill = {
  color:    string | null,  // resolved background-color (solid/black-white modes)
  image:    string | null,  // resolved background-image gradient(s); null when "none"
  url:      string | null,  // first url(...) ink tile (black/white rails); null otherwise
  size:     string | null,  // VERBATIM background-size string (dither lines are list-valued)
  position: string | null,  // VERBATIM background-position string
  repeat:   string | null,  // VERBATIM background-repeat string
  render: {                  // CSS-declared; copied verbatim by renderer adapters
    stroke:  string | null,
    width:   string | null,
    height:  string | null,
    viewBox: string | null,
    path1:   string | null,
    color1:  string | null,
    path2:   string | null,
    color2:  string | null,
  } | null,
  dir:      "h" | "v",      // which pseudo/orientation was probed
}

border() is the guaranteed-hairline path: it probes the fill-backed .border--* utilities, which carry real ink in every mode and pick up theme tinting for free. semantic('border-strong') and semantic('border-muted') describe the semantic role's token tile, not the directional rail art. Draw rails with border(); reach for semantic('border-*') only when you need the role as a Fill.

// Framework rail utilities, resolved for the current mode/theme.
var gridRail = TRMNLPaint.border(65, { el: "my-chart" });     // -> BorderFill
var axisRail = TRMNLPaint.border("black", { dir: "v", el: "my-chart" });
var step40 = TRMNLPaint.border(40, { el: "my-chart" });
#

Painting rails

A resolved rail is written back verbatim, so it paints exactly as the CSS .border--* utilities do. Wrap paints in watch() so rails re-resolve on mode, dark and theme changes; see Paint API .

  • applyBorder(node, borderFill): writes a BorderFill onto a node as its five background longhands, verbatim, so a solid, a flat gradient and a multi-layer dither line all round-trip unchanged.
#

Highcharts axes

The axis adapters copy a resolved rail into Highcharts' native options; the fill adapter and the adapter ground rules live on Painting Charts .

  • toHighchartsAxis(borderFill): turns a BorderFill into a { gridLineColor, gridLineWidth, gridLineDashStyle, lineColor, tickColor } block.
  • applyHighchartsAxisPaint(): carries the resolved BorderFill into Highcharts' render cycle and copies its CSS-declared SVG program onto the rendered grid, axis and tick paths. Flat modes declare a stroke; patterned modes declare their complete tile, paths and colors.
// Rails into Highcharts axis/grid options.
var grid = TRMNLPaint.toHighchartsAxis(
  TRMNLPaint.border(65, { el: "my-chart" }));
// TRMNLCharts.options() applies the BorderFill pattern to rendered SVG paths.
#

Live example

The separator under each schedule row is painted with TRMNLPaint.border() and TRMNLPaint.applyBorder(), wrapped in TRMNLPaint.watch(). Each row uses a different spec (shade steps 65 and 40, the literal black and white rails), labelled on the right. Change the device mode or Style in the picker and the rails re-resolve, picking up dither art and theme tinting.

TRMNL Logo Paint API TRMNLPaint.applyBorder
<div id="border-strip" class="flex flex--col w--full"></div>

<script type="text/javascript">
  // plugins.js bundles TRMNLPaint; wait for it before painting.
  function whenReady(cb) {
    if (window.TRMNLPaint) return cb();
    window.addEventListener("load", function () {
      if (window.TRMNLPaint) cb();
    }, { once: true });
  }

  whenReady(function () {
    var el = "border-strip";
    var SPECS = [65, 40, "black", "white"];
    // watch() re-resolves each rail whenever the screen device/scale/mode/dark/theme changes.
    TRMNLPaint.watch(el, function () {
      var box = document.getElementById(el);
      if (!box) return;
      box.innerHTML = "";
      SPECS.forEach(function (spec) {
        var row = document.createElement("div");
        row.style.cssText = "padding:12px 0;";
        row.textContent = "border(" + JSON.stringify(spec) + ")";
        var rail = document.createElement("div");
        rail.style.cssText = "height:2px;width:100%;";
        // applyBorder writes the five background longhands verbatim, so the
        // rail paints exactly as the CSS .border--* utilities do.
        TRMNLPaint.applyBorder(rail, TRMNLPaint.border(spec, { el: el }));
        box.appendChild(row);
        box.appendChild(rail);
      });
    });
  });
</script>