Expose editable limits and accessible command errors

This commit is contained in:
Meta Vens 2026-08-22 21:14:08 +02:00
commit 3a5e2057e0
3 changed files with 14 additions and 8 deletions

View file

@ -137,7 +137,7 @@ export class EveBrowserProviderHost {
await this.consumeCommandResult(intent, result);
}
catch (error) {
this.presentCommandStatus(error instanceof Error ? error.message : "Command failed.", "error");
this.presentCommandStatus(error instanceof Error ? error.message : "Command failed.", "alert");
return;
}
this.lastSurfaceVersion = "";
@ -158,7 +158,7 @@ export class EveBrowserProviderHost {
surface: this.selected,
});
}
this.presentCommandStatus(result.receipt.message || result.receipt.state, accepted ? "status" : "error", result.transientProjection);
this.presentCommandStatus(result.receipt.message || result.receipt.state, accepted ? "status" : "alert", result.transientProjection);
}
presentCommandStatus(message, role, transient) {
let region = this.host.querySelector(":scope > .eve-command-result-region");
@ -1874,6 +1874,9 @@ function renderEditableControl(node, kind, props, layout, style, options) {
else if (props.rows !== undefined) {
control.rows = positiveInt(props.rows, 3);
}
const maxLength = positiveInt(props.maxLength, 0);
if (maxLength > 0)
control.maxLength = maxLength;
control.value = String(context.value ?? "");
control.disabled = context.disabled;
control.name = context.bindingName;

View file

@ -294,7 +294,7 @@ export class EveBrowserProviderHost {
const result = parseEveCommandResult(await this.transport.submitCommand(intent));
await this.consumeCommandResult(intent, result);
} catch (error) {
this.presentCommandStatus(error instanceof Error ? error.message : "Command failed.", "error");
this.presentCommandStatus(error instanceof Error ? error.message : "Command failed.", "alert");
return;
}
this.lastSurfaceVersion = "";
@ -318,12 +318,12 @@ export class EveBrowserProviderHost {
}
this.presentCommandStatus(
result.receipt.message || result.receipt.state,
accepted ? "status" : "error",
accepted ? "status" : "alert",
result.transientProjection,
);
}
private presentCommandStatus(message: string, role: "status" | "error", transient?: unknown): void {
private presentCommandStatus(message: string, role: "status" | "alert", transient?: unknown): void {
let region = this.host.querySelector<HTMLElement>(":scope > .eve-command-result-region");
if (!region) {
region = el("section", "eve-command-result-region");
@ -2236,6 +2236,8 @@ function renderEditableControl(
} else if (props.rows !== undefined) {
control.rows = positiveInt(props.rows, 3);
}
const maxLength = positiveInt(props.maxLength, 0);
if (maxLength > 0) control.maxLength = maxLength;
control.value = String(context.value ?? "");
control.disabled = context.disabled;
control.name = context.bindingName;

View file

@ -225,7 +225,7 @@ test("editable bindings preserve local drafts across authoritative refresh and o
{
id: "composer",
kind: "control.input.textarea",
props: { label: "Message", value },
props: { label: "Message", value, maxLength: 2000 },
stateBindings: [{
targetProp: "value",
pointerId: "ghostlight.local.composer.message",
@ -245,6 +245,7 @@ test("editable bindings preserve local drafts across authoritative refresh and o
const options = { provider, draftStore: drafts, commandSink: intent => commands.push(intent) };
renderEveSurface(surface(""), host, options);
const composer = host.querySelector("textarea");
assert.equal(composer.maxLength, 2000);
composer.value = "The world should remember this.";
composer.dispatchEvent(new window.Event("input", { bubbles: true }));
@ -408,7 +409,7 @@ test("component captures extend rather than disappear behind operation descripto
}
});
test("authoritative refresh preserves the renderer-owned command result", () => {
test("authoritative refresh preserves the renderer-owned accessible command result", () => {
const restoreDom = installDom();
try {
const host = document.querySelector("#a");
@ -420,7 +421,7 @@ test("authoritative refresh preserves the renderer-owned command result", () =>
renderEveSurface(surface(7), host);
const result = document.createElement("section");
result.className = "eve-command-result-region";
result.setAttribute("role", "error");
result.setAttribute("role", "alert");
result.textContent = "The command was denied.";
host.append(result);