@ashley-shrok/viewmodel-shell 6.5.0 → 6.8.0

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.
Files changed (2) hide show
  1. package/dist/browser.js +23 -3
  2. package/package.json +1 -1
package/dist/browser.js CHANGED
@@ -3034,9 +3034,13 @@ export class BrowserAdapter {
3034
3034
  // filter-narrow that equals all matches; under pagination it is the current
3035
3035
  // page (selection accumulates via the round-tripped binds); over-cap /
3036
3036
  // zero-match render no rows, so the control below simply is not drawn and
3037
- // can never claim to select rows that are not on screen. This re-adds ONLY
3038
- // the DOM toggle, never the per-toggle dispatch that got the old
3039
- // TableNode.selection seam removed in 0.15.0.
3037
+ // can never claim to select rows that are not on screen. It writes the binds
3038
+ // and for checkboxes that carry an `action` replays each one's dispatch,
3039
+ // so select-all does EXACTLY what clicking each row by hand does (see the
3040
+ // change handler below). It is NOT the removed 0.15.0 selection.action seam:
3041
+ // that was the framework's own per-toggle seam racing with no coalescing loop;
3042
+ // this reuses CheckboxNode.action (a shipped, app-declared capability) and the
3043
+ // v4.2 non-blocking latest-wins loop, and never forces a dispatch semantic.
3040
3044
  const rowCheckboxes = n.rows.flatMap(r => (r.actions ?? []).filter((e) => e.type === "checkbox"));
3041
3045
  if (rowCheckboxes.length > 0) {
3042
3046
  const lbl = document.createElement("label");
@@ -3060,6 +3064,22 @@ export class BrowserAdapter {
3060
3064
  rowInp.checked = target;
3061
3065
  }
3062
3066
  inp.indeterminate = false;
3067
+ // Select-all is N per-row toggles expressed at once: after writing every
3068
+ // bind, replay each checkbox's OWN dispatch. Behaviorally identical to the
3069
+ // user clicking each row by hand — same actions, same order, same blocking/
3070
+ // coalescing — so it introduces ZERO new dispatch semantics. A checkbox with
3071
+ // no `action` dispatches nothing, so the pure client-harvest model (selection
3072
+ // stays client-side until a bulk-button harvest) is untouched. The app owns
3073
+ // what a burst means: the non-blocking latest-wins loop it opted into
3074
+ // collapses N identical dispatches to one server recompute; a blocking
3075
+ // checkbox serializes under the dispatch guard exactly as rapid manual
3076
+ // clicking would. (Consumer-driven — Poppy/PBMInvoices 2026-07-20: a
3077
+ // server-tracked SelectedMap went stale on select-all because only per-row
3078
+ // toggles dispatched, not the header box.)
3079
+ for (const cb of rowCheckboxes) {
3080
+ if (cb.action)
3081
+ on(cb.action);
3082
+ }
3063
3083
  });
3064
3084
  lbl.appendChild(inp);
3065
3085
  lbl.appendChild(mark);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ashley-shrok/viewmodel-shell",
3
- "version": "6.5.0",
3
+ "version": "6.8.0",
4
4
  "description": "A server-driven UI framework where the wire format is structured enough that agents can build full-stack apps without ever opening a browser and all UI tests are pure unit tests with no browser runtime. Server returns a JSON tree of typed nodes; a thin TypeScript adapter renders it to DOM. Backend-agnostic \u2014 a .NET reference backend ships with the repo, but any language can produce the JSON contract.",
5
5
  "type": "module",
6
6
  "license": "MIT",