Skip to content

Primitives

The parts every element is built from, in @contraagent/elements/primitives. Most are template functions that a Lit element calls in its render(); their look comes from the element’s styles, which start from base (@contraagent/elements/styles: the tokens, the status rules, chips, layout and motion).

A tone is the status colour a value takes: failed, attention, done, running, muted, or neutral (the text colour). The names are the token names (--ca-status-<tone>, Theming). An element shows a tone as data-tone, and neutral as no attribute (toneAttr).

src/core/tone.ts
/** A status colour, or `neutral` for the text colour. */
export type Tone = 'failed' | 'attention' | 'done' | 'running' | 'muted' | 'neutral';
/** Every tone with a status colour (a `data-tone` value): each but `neutral`. */

pill draws a status as a pill, statusWord as a word in a row, and statusChip in a class the element styles. Each sets data-tone and, where a mark belongs, data-mark (✓ done, ✕ failed, ◌ pending): the mark is drawn by CSS and hidden from screen readers, which read the word. A pill also has the parts pill and tone-<tone>.

legend draws a list of entries, each a swatch (a colour, a tone and a shape, a class, or an icon of its own) and its word; add legendStyles to the element’s styles. factLine draws a row of facts separated by | that breaks between facts, never inside one; a fact with a tone is in its status colour.

docs/examples/status.ts
// Statuses, a legend and a row of facts, drawn by the primitives into an element
// of your own: its styles start from `base` (the tokens and the status rules),
// plus `legendStyles` for the legend.
import { base, factLine, legend, legendStyles, pill, statusWord } from '@contraagent/elements';
import { LitElement, html } from 'lit';
class BuildSummary extends LitElement {
static override styles = [base, legendStyles];
override render() {
return html`<p>
${pill({ text: 'passed', tone: 'done' })} ${pill({ text: 'failed', tone: 'failed', title: 'exit code 2' })}
${pill({ text: 'running', tone: 'running' })} ${statusWord({ text: 'queued', tone: 'attention' })}
</p>
<p class="meta words">${factLine(['12 jobs', { text: '1 failed', tone: 'failed' }, '4m 05s'])}</p>
${legend(
[
{ label: 'passed', tone: 'done', shape: 'round' },
{ label: 'failed', tone: 'failed', shape: 'square' },
{ label: 'queued', tone: 'attention', shape: 'ring' },
],
{ label: 'Job states' },
)}`;
}
}
export function mount(host: HTMLElement): void {
if (!customElements.get('build-summary')) customElements.define('build-summary', BuildSummary);
host.replaceChildren(document.createElement('build-summary'));
}

icon(name, label) draws a glyph, or a template registered under name with registerIcon. Without a label it is hidden from screen readers; with one, the label is its tooltip and what a screen reader reads.

<cae-segmented> is one choice among a few: a radio group, one tab stop, the arrow keys, Home and End to choose. It sends cae-change with the chosen value; the host keeps value.

docs/examples/segmented.ts
// A segmented control: one choice among a few. The host holds the value and
// answers `cae-change`; the words are the host's.
import '@contraagent/elements/segmented/define';
export function mount(host: HTMLElement): void {
const control = document.createElement('cae-segmented');
control.label = 'Period';
control.options = [
{ value: 'day', label: 'Day' },
{ value: 'week', label: 'Week' },
{ value: 'month', label: 'Month', title: 'The last 30 days' },
];
control.value = 'week';
const shown = document.createElement('p');
shown.textContent = `Showing: ${control.value}`;
control.addEventListener('cae-change', (e) => (shown.textContent = `Showing: ${e.detail.value}`));
host.replaceChildren(control, shown);
}

RovingFocusController gives a group of items one tab stop and moves the focus with the arrow keys, in a row, a column or a grid (rovingStep is the rule). windowRows is the arithmetic for drawing only the rows of a long list that are on screen.

src/primitives/window.ts
/** The first row drawn. */
from: number;
/** The row after the last drawn. */
to: number;
/** The height that stands for the rows above `from`. */
padTop: number;
/** The height that stands for the rows from `to` on. */
padBottom: number;
}
/**
* The rows of `total` rows of `rowHeight` px that a viewport of `viewport` px,
* scrolled to `scrollTop`, shows, with `overscan` more rows on each side.
*/