@ai-gui/plugin-form 0.4.2 → 0.4.4

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/index.cjs CHANGED
@@ -94,7 +94,7 @@ function form(options) {
94
94
  }
95
95
  const output = {
96
96
  kind: "mount",
97
- mount: (host) => mountForm(host, parsed.data, options.actionRuntime)
97
+ mount: (host) => mountForm(host, parsed.data, options)
98
98
  };
99
99
  outputs.set(node, output);
100
100
  return output;
@@ -303,13 +303,14 @@ function parseOptions(value, path, issues) {
303
303
  }] : [];
304
304
  });
305
305
  }
306
- function mountForm(host, definition, runtime) {
306
+ function mountForm(host, definition, options) {
307
307
  const instanceId = String(++nextFormInstanceId);
308
308
  const instancePrefix = `aigui-form-${instanceId}-${definition.id}`;
309
309
  const cardType = `form:${definition.id}:${instanceId}`;
310
310
  const owner = {};
311
311
  const controller = new AbortController();
312
312
  let pending = false;
313
+ let submitted = options.submitted === true;
313
314
  let disposed = false;
314
315
  const formElement = document.createElement("form");
315
316
  formElement.noValidate = true;
@@ -333,6 +334,16 @@ function mountForm(host, definition, runtime) {
333
334
  submit.setAttribute("data-aigui-form-submit", "");
334
335
  submit.textContent = definition.submitLabel ?? "Submit";
335
336
  formElement.appendChild(submit);
337
+ const markSubmitted = () => {
338
+ if (disposed) return;
339
+ pending = false;
340
+ submitted = true;
341
+ formElement.removeAttribute("aria-busy");
342
+ formElement.setAttribute("data-aigui-form-submitted", "");
343
+ for (const element of Array.from(formElement.elements)) if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement || element instanceof HTMLButtonElement || element instanceof HTMLFieldSetElement) element.disabled = true;
344
+ submit.textContent = options.submittedLabel ?? "Submitted";
345
+ };
346
+ if (submitted) markSubmitted();
336
347
  const onInput = (event) => {
337
348
  const control = event.target;
338
349
  if (!(control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement || control instanceof HTMLSelectElement)) return;
@@ -340,7 +351,7 @@ function mountForm(host, definition, runtime) {
340
351
  actionError.hidden = true;
341
352
  };
342
353
  const onSubmit = () => {
343
- if (pending || disposed) return;
354
+ if (pending || submitted || disposed) return;
344
355
  const validation = validateFormValues(definition, readControls(definition, controls));
345
356
  renderErrors(validation.errors, controls, errorElements);
346
357
  actionError.hidden = true;
@@ -357,14 +368,14 @@ function mountForm(host, definition, runtime) {
357
368
  submit.disabled = false;
358
369
  formElement.removeAttribute("aria-busy");
359
370
  };
360
- runtime.dispatch({
371
+ options.actionRuntime.dispatch({
361
372
  type: definition.submitAction,
362
373
  params: validation.values,
363
374
  cardType
364
375
  }, {
365
376
  owner,
366
377
  signal: controller.signal
367
- }).then(settle, (error) => {
378
+ }).then(markSubmitted, (error) => {
368
379
  if (!disposed && !controller.signal.aborted) {
369
380
  actionError.textContent = actionErrorMessage(error);
370
381
  actionError.hidden = false;
package/dist/index.d.cts CHANGED
@@ -56,6 +56,10 @@ interface FormValidationResult {
56
56
  interface FormPluginOptions {
57
57
  /** Shared core runtime whose registry is the only allowlist for submitAction. */
58
58
  actionRuntime: ActionRuntime;
59
+ /** Mount forms as already submitted, useful when restoring persisted conversations. */
60
+ submitted?: boolean;
61
+ /** Label shown after a successful or restored submission. */
62
+ submittedLabel?: string;
59
63
  }
60
64
  declare function formPromptSpec(): string;
61
65
  declare function form(options: FormPluginOptions): AIGuiPlugin;
package/dist/index.d.ts CHANGED
@@ -56,6 +56,10 @@ interface FormValidationResult {
56
56
  interface FormPluginOptions {
57
57
  /** Shared core runtime whose registry is the only allowlist for submitAction. */
58
58
  actionRuntime: ActionRuntime;
59
+ /** Mount forms as already submitted, useful when restoring persisted conversations. */
60
+ submitted?: boolean;
61
+ /** Label shown after a successful or restored submission. */
62
+ submittedLabel?: string;
59
63
  }
60
64
  declare function formPromptSpec(): string;
61
65
  declare function form(options: FormPluginOptions): AIGuiPlugin;
package/dist/index.js CHANGED
@@ -70,7 +70,7 @@ function form(options) {
70
70
  }
71
71
  const output = {
72
72
  kind: "mount",
73
- mount: (host) => mountForm(host, parsed.data, options.actionRuntime)
73
+ mount: (host) => mountForm(host, parsed.data, options)
74
74
  };
75
75
  outputs.set(node, output);
76
76
  return output;
@@ -279,13 +279,14 @@ function parseOptions(value, path, issues) {
279
279
  }] : [];
280
280
  });
281
281
  }
282
- function mountForm(host, definition, runtime) {
282
+ function mountForm(host, definition, options) {
283
283
  const instanceId = String(++nextFormInstanceId);
284
284
  const instancePrefix = `aigui-form-${instanceId}-${definition.id}`;
285
285
  const cardType = `form:${definition.id}:${instanceId}`;
286
286
  const owner = {};
287
287
  const controller = new AbortController();
288
288
  let pending = false;
289
+ let submitted = options.submitted === true;
289
290
  let disposed = false;
290
291
  const formElement = document.createElement("form");
291
292
  formElement.noValidate = true;
@@ -309,6 +310,16 @@ function mountForm(host, definition, runtime) {
309
310
  submit.setAttribute("data-aigui-form-submit", "");
310
311
  submit.textContent = definition.submitLabel ?? "Submit";
311
312
  formElement.appendChild(submit);
313
+ const markSubmitted = () => {
314
+ if (disposed) return;
315
+ pending = false;
316
+ submitted = true;
317
+ formElement.removeAttribute("aria-busy");
318
+ formElement.setAttribute("data-aigui-form-submitted", "");
319
+ for (const element of Array.from(formElement.elements)) if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement || element instanceof HTMLButtonElement || element instanceof HTMLFieldSetElement) element.disabled = true;
320
+ submit.textContent = options.submittedLabel ?? "Submitted";
321
+ };
322
+ if (submitted) markSubmitted();
312
323
  const onInput = (event) => {
313
324
  const control = event.target;
314
325
  if (!(control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement || control instanceof HTMLSelectElement)) return;
@@ -316,7 +327,7 @@ function mountForm(host, definition, runtime) {
316
327
  actionError.hidden = true;
317
328
  };
318
329
  const onSubmit = () => {
319
- if (pending || disposed) return;
330
+ if (pending || submitted || disposed) return;
320
331
  const validation = validateFormValues(definition, readControls(definition, controls));
321
332
  renderErrors(validation.errors, controls, errorElements);
322
333
  actionError.hidden = true;
@@ -333,14 +344,14 @@ function mountForm(host, definition, runtime) {
333
344
  submit.disabled = false;
334
345
  formElement.removeAttribute("aria-busy");
335
346
  };
336
- runtime.dispatch({
347
+ options.actionRuntime.dispatch({
337
348
  type: definition.submitAction,
338
349
  params: validation.values,
339
350
  cardType
340
351
  }, {
341
352
  owner,
342
353
  signal: controller.signal
343
- }).then(settle, (error) => {
354
+ }).then(markSubmitted, (error) => {
344
355
  if (!disposed && !controller.signal.aborted) {
345
356
  actionError.textContent = actionErrorMessage(error);
346
357
  actionError.hidden = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-gui/plugin-form",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "Safe interactive form blocks for AIGUI, backed by the core ActionRuntime.",
5
5
  "keywords": [
6
6
  "llm",
@@ -49,7 +49,7 @@
49
49
  "access": "public"
50
50
  },
51
51
  "dependencies": {
52
- "@ai-gui/core": "0.4.2"
52
+ "@ai-gui/core": "0.4.4"
53
53
  },
54
54
  "scripts": {
55
55
  "build": "tsdown",