jig-ui 0.26.1 → 0.26.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.26.2 (2026-10-13)
4
+
5
+ A button in a table row keeps the row's height, and the render probe reports
6
+ rows it stretches.
7
+
8
+ ### Fixed
9
+
10
+ - **A button in a table row takes the row's height.** 0.26.0 said so in the
11
+ tokens chapter, but the Button pattern, which an agent reads to build a
12
+ button, still gave its hit area a 48px floor with no exception, and an
13
+ invoices table on 0.26.1 had its "Mark as paid" rows at 65px among 41px ones.
14
+ The Button and Data table patterns now say it where buttons are built: a
15
+ button in a row is sized to the control height with no minimum of its own,
16
+ and on a touch screen the whole row rises to the touch target instead. On a
17
+ run of this release, every row stood 36px with a mouse and 48px on touch.
18
+
19
+ ### Added
20
+
21
+ - **The render probe reports a table whose rows are not one height because of
22
+ a control.** When the rows holding a button or link stand taller than the
23
+ rest, and the control is taller than the short rows, it is a measured
24
+ failure (`P-02`, `P-06`). Rows that differ only because text wraps are left
25
+ alone.
26
+
3
27
  ## 0.26.1 (2026-10-13)
4
28
 
5
29
  The colour and typeface you decide in `/jig decide` now reach the pages, and
package/dist/index.js CHANGED
@@ -6633,6 +6633,25 @@ var PROBE_SCRIPT = `(async () => {
6633
6633
  if (!table || getComputedStyle(table).display !== 'table' || display === 'table-cell' || display === 'none' || !vis(cell)) continue;
6634
6634
  brokenCells.push({ cell: cell.tagName.toLowerCase() + (cell.classList[0] ? '.' + cell.classList[0] : ''), text: (cell.innerText || '').trim().replace(/\\s+/g, ' ').slice(0, 40), display });
6635
6635
  }
6636
+ // Rows of one table at different heights, where the taller rows are the
6637
+ // ones holding a control taller than the short rows: a button given the
6638
+ // touch-target floor as its own minimum height. An invoices table had its
6639
+ // "Mark as paid" rows at 65px among 41px ones. Rows that differ because a
6640
+ // cell's text wraps are left alone: only a control can be the cause here.
6641
+ const unevenRows = [];
6642
+ for (const table of [...document.querySelectorAll('table')].slice(0, 20)) {
6643
+ if (unevenRows.length >= 3 || getComputedStyle(table).display !== 'table' || !vis(table)) continue;
6644
+ const rows = [...table.querySelectorAll('tbody tr')].filter((r) => vis(r));
6645
+ if (rows.length < 2) continue;
6646
+ const heights = rows.map((r) => Math.round(r.getBoundingClientRect().height));
6647
+ const short = Math.min(...heights);
6648
+ const control = rows
6649
+ .filter((r, i) => heights[i] > short + 2)
6650
+ .map((r) => [...r.querySelectorAll('button, a[href], input, select')].find((c) => vis(c) && c.getBoundingClientRect().height > short))
6651
+ .find(Boolean);
6652
+ if (!control) continue;
6653
+ unevenRows.push({ table: 'table' + (table.classList[0] ? '.' + table.classList[0] : ''), short, tall: Math.max(...heights), control: control.tagName.toLowerCase() + (control.classList[0] ? '.' + control.classList[0] : ''), controlHeight: Math.round(control.getBoundingClientRect().height) });
6654
+ }
6636
6655
  return JSON.stringify({
6637
6656
  jigProbe: ${PROBE_VERSION},
6638
6657
  url: location.href,
@@ -6642,6 +6661,7 @@ var PROBE_SCRIPT = `(async () => {
6642
6661
  sidewaysScroll: doc.scrollWidth > doc.clientWidth,
6643
6662
  sidewaysBoxes,
6644
6663
  brokenCells,
6664
+ unevenRows,
6645
6665
  bodyFont: getComputedStyle(document.body).fontFamily,
6646
6666
  defaultFont: getComputedStyle(document.body).fontFamily === defaultFont,
6647
6667
  unresolvedTokens: [...unresolved],
@@ -7128,6 +7148,9 @@ function probeCheck(probes, verdictOf, indexable = true, mode) {
7128
7148
  const shown = p.brokenCells.map((c) => `${c.cell}${c.text ? ` ("${c.text}")` : ""} is display: ${c.display}`).join("; ");
7129
7149
  failures.push(`${at(p)}: ${p.brokenCells.length === 1 ? "a table cell has" : `${p.brokenCells.length} table cells have`} left the table: ${shown}. A cell given its own display stops taking its row's height, so its border and its text drift from the row's. Keep the cell a cell and put the flex on a wrapper inside it (P-06).`);
7130
7150
  }
7151
+ for (const u of p.unevenRows ?? []) {
7152
+ failures.push(`${at(p)}: ${u.table}'s rows are not one height: those holding ${u.control} (${u.controlHeight}px tall) stand ${u.tall}px, the rest ${u.short}px. A button in a row takes the row's height and has no minimum height of its own; on a touch screen the row rises to the touch target instead (P-02, P-06).`);
7153
+ }
7131
7154
  if (p.defaultFont) {
7132
7155
  failures.push(`${at(p)}: the page renders in the browser's default font (${p.bodyFont ?? "unknown"}) \u2014 its styles are not applying. No review of this page can pass until they do.`);
7133
7156
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jig-ui",
3
- "version": "0.26.1",
3
+ "version": "0.26.2",
4
4
  "description": "A design system for coding agents. 160 numbered UI rules, brand x mode design tokens, and an installer for Claude Code, Codex, Cursor and opencode.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -53,7 +53,16 @@ Four numbers, and most button designs in the wild fail at least one:
53
53
  | Button **shape** — fill or border — against its background | **3:1** |
54
54
  | Button **text** against the button | **4.5:1** |
55
55
  | Two buttons sharing a style, distinguished only by contrast | **3:1 between them** |
56
- | Hit area | `--size-touch-target` — **48×48px** floor |
56
+ | Hit area | `--size-touch-target` — **48×48px** floor, except inside a table row (below) |
57
+
58
+ **Inside a table row, a button takes the row's height.** A dense row is shorter
59
+ than the floor, and a button given `min-height: var(--size-touch-target)` there
60
+ stretches the rows that hold it and not the rest: an invoices table had its
61
+ "Mark as paid" rows at 65px among 41px ones, twice. Size it to `--size-control`
62
+ and never give it a minimum height of its own. On a touch screen the row itself
63
+ rises to `--size-touch-target` (the mode files do it under a coarse pointer), so
64
+ a finger still gets the floor. The render probe reports rows made uneven this
65
+ way.
57
66
 
58
67
  A secondary button's fill or border is **not decorative**. It is the only thing identifying the element as a button, so it carries the 3:1 non-text requirement (`02-tokens.md`). Strip it and you have coloured text.
59
68
 
@@ -285,6 +294,7 @@ Primarily an `operator` pattern; the rules apply wherever a table appears.
285
294
  **Rules**
286
295
  - Row identity is stable across refresh, sort and filter. A row that moves under a click causes the wrong record to be acted on — the most damaging bug this pattern has.
287
296
  - Numeric columns are right-aligned and use tabular figures (`--font-numeric`). Text columns are start-aligned. Never centre either.
297
+ - Every row is one height. A button or link in a row takes the row's height and has no minimum height of its own (see the Button pattern, Hit area).
288
298
  - A cell stays a table cell. To line up what is inside it (a name and a tag, an icon and a label), put `display: flex` on a wrapper inside the cell, never on the `<td>` or `<th>` itself: a cell given its own display stops taking its row's height, so its text and its border drift from the rest of the row. A table stacked on a phone, the whole table set to `block`, is the exception (`L-01`, step 6). The render probe reports a cell that has left its table.
289
299
  - Column headers state units. "Weight" is ambiguous; "Weight (kg)" is not.
290
300
  - Truncation is resolvable by click or expand, never by hover alone (`E-31`, `01-modes.md`).