tosijs-ui 1.12.0 → 1.12.1

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,57 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.12.1
4
+
5
+ ### The Playwright lane no longer fights itself
6
+
7
+ Local workers are pinned to **6** rather than Playwright's default (~half the cores, 9 here).
8
+ Every engine had taken a turn producing a `page.goto` timeout or a `docs.json` load failure —
9
+ roughly one full run in five, always passing in isolation — because 9 browsers were hitting one
10
+ dev server. 1.11.0 fixed the client half (`fetchCorpus` retries); this reduces the contention
11
+ instead of surviving it.
12
+
13
+ Measured, not guessed: 9 workers ran the suite in 82s and 6 in 81s, so the lane is not
14
+ CPU-bound at 9 and a third of the load is free; 4 workers costs 106s and buys nothing further.
15
+ 6/6 clean afterwards. Contributor-facing only — CI already runs at 1 worker.
16
+
17
+ ### `<tosi-schema-form>`: all three perf guards, and they cover different things
18
+
19
+ The keystroke perf guard counts DOM lookups, and provably could not see `syncValues` — which
20
+ runs on add/remove-item, not on keystrokes. A root-scoped per-field scan reintroduced there
21
+ passed the existing test. There is now a sibling test on that path; mutation-testing takes it
22
+ from 1 lookup per add to 41 → 161 as field count grows, while the keystroke test stays green
23
+ under the same mutation.
24
+
25
+ Wall-clock is back alongside them, too. It was removed in 1.11.0 for flaking; with the lane
26
+ quiet the isolated and loaded distributions now overlap (3.20-4.57 vs 2.64-4.14 across all
27
+ three engines, against 4.0 for linear and 16 for quadratic), so a threshold of 8 separates
28
+ them. It earns its place by catching what counting cannot: an O(N) scan per field that uses no
29
+ selector at all fails it at 9.63x while both count guards pass.
30
+
31
+ ### `<tosi-table>`: the header and body can no longer describe different columns (#102)
32
+
33
+ Reported from a host app that changes column visibility when the page size changes. `set
34
+ columns` updates the column list **synchronously** but defers the rebuild to the next frame,
35
+ so between the assignment and that frame anything recomputing widths — a resize drag, a scroll
36
+ handler, or the host's own page-size code — wrote a grid template for the NEW columns over the
37
+ cells the OLD ones had built.
38
+
39
+ Why that reads as _disagreement_ rather than a missing column, which is what made it confusing
40
+ to report: with fewer tracks than cells, CSS Grid auto-places the surplus into **implicit**
41
+ tracks, and implicit tracks size to content. Header text and body text differ, so the two rows
42
+ resolve them to different widths and the columns visibly step apart.
43
+
44
+ `setColumnWidths()` now describes the column set the DOM was actually built from, refreshed by
45
+ `render()` on the frame that installs those cells. A column change is therefore **deferred, not
46
+ dropped** — and because column objects are shared by reference, a resize drag still moves
47
+ widths immediately: it is the shape that is pinned to the DOM, not the widths. All three
48
+ properties have tests, and the fix is mutation-verified (reverting it fails with
49
+ `tracks: 3, headerCells: 4`).
50
+
51
+ The caller arguably should not reassign columns mid-render. It does not matter — a table that
52
+ can show a header and a body describing different columns is our defect whenever the
53
+ assignment lands.
54
+
3
55
  ## 1.12.0
4
56
 
5
57
  ### tosijs-ui is Apache-2.0 as of this release (MIT through 1.11.1)
@@ -202,6 +202,7 @@ export declare class TosiTable extends WebComponent {
202
202
  private rowData;
203
203
  private _array;
204
204
  private _columns;
205
+ private _renderedCols;
205
206
  private _filter;
206
207
  private _sort?;
207
208
  private _rowGroupId;
@@ -1311,6 +1311,11 @@ export class TosiTable extends WebComponent {
1311
1311
  };
1312
1312
  _array = [];
1313
1313
  _columns = null;
1314
+ /*
1315
+ The columns the CURRENT DOM was built from — see `setColumnWidths`. Not `_columns`: that one
1316
+ changes the instant a caller assigns it, which is exactly the window this exists to cover.
1317
+ */
1318
+ _renderedCols = [];
1314
1319
  _filter = passThru;
1315
1320
  _sort;
1316
1321
  _rowGroupId = null;
@@ -2611,7 +2616,30 @@ export class TosiTable extends WebComponent {
2611
2616
  this.addEventListener('keydown', this.handleKeyNav);
2612
2617
  }
2613
2618
  setColumnWidths() {
2614
- const cols = this.visibleColumns;
2619
+ /*
2620
+ The widths describe the columns the DOM ACTUALLY HAS, not the ones it is about to get.
2621
+
2622
+ `set columns` updates `_columns` synchronously but defers the rebuild to `queueRender()`,
2623
+ so between the assignment and the frame, `visibleColumns` already answers for a column set
2624
+ no cell in the document belongs to. Anything that recomputes widths in that window — a
2625
+ resize drag, a scroll handler, a host reacting to a page-size change — used to write a
2626
+ template for the NEW columns over the OLD cells.
2627
+
2628
+ That reads as the header disagreeing with the body (#102), and the reason it looks like
2629
+ disagreement rather than simple breakage is worth knowing: with fewer tracks than cells,
2630
+ CSS Grid auto-places the surplus into IMPLICIT tracks, which size to content. Header text
2631
+ and body text differ, so the two rows resolve those tracks to different widths and the
2632
+ columns visibly step apart.
2633
+
2634
+ `_renderedCols` is the set the last render built the cells from; `render()` refreshes it
2635
+ immediately before calling here, so a legitimate column change still takes effect on the
2636
+ very frame that installs its cells. Column objects are shared by reference, so a resize
2637
+ drag that mutates `column.width` is still reflected — it is the SHAPE that is pinned to
2638
+ the DOM, not the widths.
2639
+ */
2640
+ const cols = this._renderedCols.length
2641
+ ? this._renderedCols
2642
+ : this.visibleColumns;
2615
2643
  const total = cols.reduce((w, c) => w + c.width, 0);
2616
2644
  /*
2617
2645
  `fullWidthHeader` lets ONE column absorb whatever width is left over, so a table narrower
@@ -2886,6 +2914,8 @@ export class TosiTable extends WebComponent {
2886
2914
  if (cols.length === 0)
2887
2915
  return;
2888
2916
  const stickyInfo = this.computeStickyInfo(cols);
2917
+ // Before setColumnWidths, so the widths describe the cells this render is about to build.
2918
+ this._renderedCols = cols;
2889
2919
  this.style.setProperty('--tosi-table-row-height', this.rowHeight > 0 ? `${this.rowHeight}px` : 'auto');
2890
2920
  this.setColumnWidths();
2891
2921
  // Build the regions. Header + optional pinned tbodies are siblings