@ashley-shrok/viewmodel-shell 5.0.0 → 5.0.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/dist/browser.d.ts +9 -0
- package/dist/browser.js +27 -13
- package/package.json +1 -1
package/dist/browser.d.ts
CHANGED
|
@@ -136,6 +136,15 @@ export declare class BrowserAdapter implements Adapter {
|
|
|
136
136
|
/** CheckboxNode (standalone, immediate-dispatch) — bound boolean; on toggle,
|
|
137
137
|
* write to state then dispatch the action name (if any). */
|
|
138
138
|
private checkbox;
|
|
139
|
+
/** Shared button appearance + activation behavior, applied to a <button> element
|
|
140
|
+
* (a standalone ButtonNode's button, OR a form's submitButton). Sets the full
|
|
141
|
+
* className (emphasis/tone/size/width/disabled), label, and the `disabled` attr,
|
|
142
|
+
* and returns a guarded `activate()` that runs disabled -> confirm -> pendingLabel
|
|
143
|
+
* swap -> dispatch. Both the standalone button() renderer and the FormNode
|
|
144
|
+
* submitButton branch use this so the two can NEVER diverge — the divergence WAS
|
|
145
|
+
* the bug (a form-level submit button silently dropped pendingLabel/disabled/
|
|
146
|
+
* confirm because it re-implemented rendering without the click behavior). */
|
|
147
|
+
private applyButtonBehavior;
|
|
139
148
|
private button;
|
|
140
149
|
private text;
|
|
141
150
|
private link;
|
package/dist/browser.js
CHANGED
|
@@ -865,15 +865,17 @@ export class BrowserAdapter {
|
|
|
865
865
|
const sb = n.submitButton;
|
|
866
866
|
const effectiveSubmit = sb ? sb.action : n.submitAction;
|
|
867
867
|
if (sb) {
|
|
868
|
-
const submitAction = sb.action;
|
|
869
868
|
const submit = document.createElement("button");
|
|
870
869
|
submit.type = "submit";
|
|
871
|
-
|
|
872
|
-
|
|
870
|
+
// Same appearance + activation as a standalone button — disabled/confirm/
|
|
871
|
+
// pendingLabel included. The form's submit event is the single dispatch
|
|
872
|
+
// point (keeps native Enter-to-submit for text fields working); activate()
|
|
873
|
+
// carries the disabled guard, confirm guard, and pendingLabel swap.
|
|
874
|
+
const activate = this.applyButtonBehavior(submit, sb, dispatchWithFiles);
|
|
873
875
|
form.appendChild(submit);
|
|
874
876
|
form.addEventListener("submit", (e) => {
|
|
875
877
|
e.preventDefault();
|
|
876
|
-
|
|
878
|
+
activate();
|
|
877
879
|
});
|
|
878
880
|
}
|
|
879
881
|
else if (n.submitAction) {
|
|
@@ -1269,24 +1271,30 @@ export class BrowserAdapter {
|
|
|
1269
1271
|
});
|
|
1270
1272
|
parent.appendChild(lbl);
|
|
1271
1273
|
}
|
|
1272
|
-
button
|
|
1273
|
-
|
|
1274
|
-
|
|
1274
|
+
/** Shared button appearance + activation behavior, applied to a <button> element
|
|
1275
|
+
* (a standalone ButtonNode's button, OR a form's submitButton). Sets the full
|
|
1276
|
+
* className (emphasis/tone/size/width/disabled), label, and the `disabled` attr,
|
|
1277
|
+
* and returns a guarded `activate()` that runs disabled -> confirm -> pendingLabel
|
|
1278
|
+
* swap -> dispatch. Both the standalone button() renderer and the FormNode
|
|
1279
|
+
* submitButton branch use this so the two can NEVER diverge — the divergence WAS
|
|
1280
|
+
* the bug (a form-level submit button silently dropped pendingLabel/disabled/
|
|
1281
|
+
* confirm because it re-implemented rendering without the click behavior). */
|
|
1282
|
+
applyButtonBehavior(btn, n, dispatch) {
|
|
1275
1283
|
btn.className = `vms-button${n.emphasis ? ` vms-button--${n.emphasis}` : ""}${n.tone ? ` vms-button--${n.tone}` : ""}${n.size ? ` vms-button--${n.size}` : ""}${n.width === "full" ? " vms-button--full" : ""}${n.disabled ? " vms-button--disabled" : ""}`;
|
|
1276
1284
|
btn.textContent = n.label;
|
|
1277
1285
|
if (n.disabled)
|
|
1278
1286
|
btn.disabled = true;
|
|
1279
|
-
|
|
1287
|
+
return () => {
|
|
1280
1288
|
// Forms-completeness (3.4.0): a disabled button never dispatches. (Native
|
|
1281
|
-
// `disabled` already suppresses
|
|
1282
|
-
// attribute
|
|
1289
|
+
// `disabled` already suppresses a click, but guard anyway — a form submit
|
|
1290
|
+
// isn't a native button click, and the attribute could be cleared out-of-band.)
|
|
1283
1291
|
if (n.disabled)
|
|
1284
1292
|
return;
|
|
1285
1293
|
// confirm: a destructive-action guard. Show the NATIVE browser confirm
|
|
1286
1294
|
// BEFORE any pendingLabel swap or dispatch; Cancel suppresses everything
|
|
1287
1295
|
// (no dispatch, no visual change). Native by design — zero app/framework
|
|
1288
1296
|
// state, and it's a client-only human affordance (an agent never reaches
|
|
1289
|
-
// this
|
|
1297
|
+
// this handler; it dispatches the action directly over the wire).
|
|
1290
1298
|
if (n.confirm && !window.confirm(n.confirm))
|
|
1291
1299
|
return;
|
|
1292
1300
|
// pendingLabel: instant client-side feedback. Swap text + add
|
|
@@ -1297,8 +1305,14 @@ export class BrowserAdapter {
|
|
|
1297
1305
|
btn.textContent = n.pendingLabel;
|
|
1298
1306
|
btn.classList.add("vms-button--pending");
|
|
1299
1307
|
}
|
|
1300
|
-
|
|
1301
|
-
}
|
|
1308
|
+
dispatch(n.action);
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
button(n, parent, on) {
|
|
1312
|
+
const btn = document.createElement("button");
|
|
1313
|
+
btn.type = "button";
|
|
1314
|
+
const activate = this.applyButtonBehavior(btn, n, on);
|
|
1315
|
+
btn.addEventListener("click", activate);
|
|
1302
1316
|
parent.appendChild(btn);
|
|
1303
1317
|
}
|
|
1304
1318
|
text(n, parent) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ashley-shrok/viewmodel-shell",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.1",
|
|
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",
|