@webmcpui/core 0.1.2 → 0.2.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/README.md +46 -24
- package/dist/index.d.ts +446 -13
- package/dist/index.js +1653 -71
- package/dist/testing.d.ts +1 -1
- package/dist/{webmcp-JAn7I2xj.d.ts → webmcp-DbmbtX6x.d.ts} +1 -1
- package/dist/webmcpui.global.js +701 -47
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
# @webmcpui/core
|
|
2
2
|
|
|
3
|
-
Framework-agnostic, WebMCP-native custom elements.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
subclass that supplies its control and specifics.
|
|
3
|
+
Framework-agnostic, WebMCP-native custom elements. Every `<wmcp-*>` element is a
|
|
4
|
+
proper, accessible HTML control first and, when you opt in, also registers an
|
|
5
|
+
imperative [WebMCP](https://webmcpui.com/docs/webmcp) tool an agent can call.
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
**Two families of primitives:**
|
|
8
|
+
|
|
9
|
+
- **Form controls** expose a _value_ an agent can set — `<wmcp-input>`,
|
|
10
|
+
`<wmcp-textarea>`, `<wmcp-select>`, `<wmcp-checkbox>`, `<wmcp-radio>` /
|
|
11
|
+
`<wmcp-radio-group>`. Shared behavior (form association via `ElementInternals`,
|
|
12
|
+
Standard Schema validation, a11y, theming) lives in a `WmcpFormControl` base.
|
|
13
|
+
- **Interaction primitives** expose an _action_ an agent can trigger —
|
|
14
|
+
`<wmcp-button>`, `<wmcp-dialog>`, `<wmcp-menu>`, `<wmcp-tabs>`,
|
|
15
|
+
`<wmcp-popover>` — or, for `<wmcp-toast>`, a _reading_ an agent can perceive.
|
|
16
|
+
They share a `WmcpAction` / `WmcpExposable` base.
|
|
9
17
|
|
|
10
18
|
One source of truth (vanilla custom elements built with [Lit](https://lit.dev)),
|
|
11
19
|
two distribution channels: an ESM package for build tools, and a single-file
|
|
@@ -21,11 +29,12 @@ pnpm add @webmcpui/core @webmcpui/tokens
|
|
|
21
29
|
import { defineComponents } from '@webmcpui/core';
|
|
22
30
|
import '@webmcpui/tokens/css'; // the theme tokens (CSS custom properties)
|
|
23
31
|
|
|
24
|
-
defineComponents(); // registers
|
|
32
|
+
defineComponents(); // registers every <wmcp-*> element
|
|
25
33
|
```
|
|
26
34
|
|
|
27
35
|
```html
|
|
28
36
|
<wmcp-input label="Email" name="email" type="email"></wmcp-input>
|
|
37
|
+
<wmcp-button variant="primary">Save</wmcp-button>
|
|
29
38
|
```
|
|
30
39
|
|
|
31
40
|
Importing the package does **not** register elements — you call
|
|
@@ -45,7 +54,7 @@ For Webflow / WordPress / hand-written HTML — one tag, elements auto-register:
|
|
|
45
54
|
|
|
46
55
|
See `examples/plain-html.html` for a working local version.
|
|
47
56
|
|
|
48
|
-
## Standard Schema validation
|
|
57
|
+
## Standard Schema validation (form controls)
|
|
49
58
|
|
|
50
59
|
Bring any [Standard Schema](https://standardschema.dev) validator — Zod,
|
|
51
60
|
Valibot, ArkType — set it as the `schema` property. No bespoke schema language.
|
|
@@ -59,51 +68,64 @@ input.schema = z.string().email('Enter a valid email');
|
|
|
59
68
|
|
|
60
69
|
Validation runs on input and during native form validation; failures set
|
|
61
70
|
`aria-invalid`, render an error message in a live region, and propagate to the
|
|
62
|
-
containing `<form>` via ElementInternals
|
|
63
|
-
|
|
64
|
-
> **Note:** Standard Schema validates values but does not emit JSON Schema, so
|
|
65
|
-
> the WebMCP tool's parameter schema is derived from the input `type`, not from
|
|
66
|
-
> the validator. Richer tool schemas are a future enhancement.
|
|
71
|
+
containing `<form>` via `ElementInternals`.
|
|
67
72
|
|
|
68
73
|
## WebMCP exposure
|
|
69
74
|
|
|
70
|
-
Opt in with `expose`. The element registers an imperative WebMCP tool
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
first.
|
|
75
|
+
Opt in with `expose`. The element registers an imperative WebMCP tool on connect
|
|
76
|
+
and unregisters on disconnect. It is feature-detected — preferring
|
|
77
|
+
`document.modelContext` (canonical as of the Chrome 149+ origin trial) and
|
|
78
|
+
falling back to the deprecated `navigator.modelContext` — and a complete no-op
|
|
79
|
+
when no host is present, so the element is always a good control first.
|
|
75
80
|
|
|
76
81
|
```html
|
|
82
|
+
<!-- form control → a "fill" tool that sets a value -->
|
|
77
83
|
<wmcp-input label="Email" name="email" expose></wmcp-input>
|
|
78
|
-
|
|
84
|
+
|
|
85
|
+
<!-- interaction primitive → an "action" tool the agent can trigger -->
|
|
86
|
+
<wmcp-button tool-name="book_appointment" expose>Book</wmcp-button>
|
|
87
|
+
|
|
88
|
+
<!-- a menu → a parameterized action (the agent picks which item) -->
|
|
89
|
+
<wmcp-menu name="row_action" label="Actions" expose>
|
|
90
|
+
<option value="edit">Edit</option>
|
|
91
|
+
<option value="delete">Delete</option>
|
|
92
|
+
</wmcp-menu>
|
|
79
93
|
```
|
|
80
94
|
|
|
95
|
+
Consequential steps stay a deliberate human action: an agent can _set_ a value
|
|
96
|
+
or _open_ a dialog, but submitting/confirming is the person's to make.
|
|
97
|
+
|
|
81
98
|
## Testing without a real agent
|
|
82
99
|
|
|
83
|
-
No mainstream agent calls WebMCP yet, so `@webmcpui/core/testing` ships a
|
|
84
|
-
host to exercise exposure end to end
|
|
100
|
+
No mainstream agent calls WebMCP broadly yet, so `@webmcpui/core/testing` ships a
|
|
101
|
+
fake host to exercise exposure end to end:
|
|
85
102
|
|
|
86
103
|
```ts
|
|
87
104
|
import { installFakeAgent } from '@webmcpui/core/testing';
|
|
88
105
|
|
|
89
106
|
const agent = installFakeAgent();
|
|
90
|
-
// ... connect a <wmcp-input expose> ...
|
|
107
|
+
// ... connect a <wmcp-input expose> / <wmcp-button expose> ...
|
|
91
108
|
await agent.call('fill_email', { value: 'agent@webmcpui.com' });
|
|
109
|
+
await agent.call('click_button');
|
|
92
110
|
agent.restore();
|
|
93
111
|
```
|
|
94
112
|
|
|
113
|
+
## Documentation
|
|
114
|
+
|
|
115
|
+
Full docs, live demos for every element, and `llms.txt` at
|
|
116
|
+
**[webmcpui.com](https://webmcpui.com)**.
|
|
117
|
+
|
|
95
118
|
## Build & test
|
|
96
119
|
|
|
97
120
|
```bash
|
|
98
121
|
pnpm build # tsup → dist/ (ESM + IIFE + d.ts)
|
|
99
122
|
pnpm typecheck # tsc --noEmit
|
|
100
|
-
pnpm test # @web/test-runner in real Chromium
|
|
101
|
-
# validation a11y, WebMCP exposure)
|
|
123
|
+
pnpm test # @web/test-runner in real Chromium
|
|
102
124
|
pnpm test:smoke # node smoke check against the built dist
|
|
103
125
|
```
|
|
104
126
|
|
|
105
127
|
Tests run in a genuine browser via the Playwright launcher — form-associated
|
|
106
|
-
custom elements and ElementInternals don't work under jsdom. First run needs
|
|
128
|
+
custom elements and `ElementInternals` don't work under jsdom. First run needs
|
|
107
129
|
the browser binary:
|
|
108
130
|
|
|
109
131
|
```bash
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LitElement, CSSResultGroup, TemplateResult, nothing, CSSResult } from 'lit';
|
|
2
|
-
import { J as JSONSchema } from './webmcp-
|
|
3
|
-
export { T as ToolDisposer,
|
|
2
|
+
import { J as JSONSchema, W as WebMCPToolResult } from './webmcp-DbmbtX6x.js';
|
|
3
|
+
export { T as ToolDisposer, a as WebMCPToolDefinition, b as WebMCPToolResultContent, e as exposeTool, i as isWebMCPAvailable } from './webmcp-DbmbtX6x.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Minimal Standard Schema v1 types + a validation helper.
|
|
@@ -61,6 +61,51 @@ declare function validateStandard<Output>(schema: StandardSchemaV1<unknown, Outp
|
|
|
61
61
|
/** Duck-type check that an unknown value is a Standard Schema. */
|
|
62
62
|
declare function isStandardSchema(value: unknown): value is StandardSchemaV1;
|
|
63
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Base for every element that can register itself as a WebMCP tool — both the
|
|
66
|
+
* *value* controls ({@link WmcpFormControl}) and the *action* elements
|
|
67
|
+
* ({@link WmcpAction}).
|
|
68
|
+
*
|
|
69
|
+
* It owns only the exposure *mechanism*: the `expose` / `tool-name` /
|
|
70
|
+
* `tool-description` opt-in surface, the tool's lifecycle (register on connect,
|
|
71
|
+
* dispose on disconnect, re-register when its identity changes, drop when
|
|
72
|
+
* `expose` is turned off), and the single `exposeTool` call. The spec-sensitive
|
|
73
|
+
* registration/disposal itself lives one layer down in `exposeTool`, so this is
|
|
74
|
+
* thin wiring over a single source of truth.
|
|
75
|
+
*
|
|
76
|
+
* Each subtree supplies the *policy* via four hooks — {@link resolvedToolName},
|
|
77
|
+
* {@link defaultToolDescription}, {@link toolInputSchema}, {@link executeTool} —
|
|
78
|
+
* plus {@link toolReactiveProps} when extra properties feed the tool's name or
|
|
79
|
+
* description. Abstract — not registered on its own.
|
|
80
|
+
*/
|
|
81
|
+
declare abstract class WmcpExposable extends LitElement {
|
|
82
|
+
/** Whether to expose this element as a WebMCP tool. */
|
|
83
|
+
expose: boolean;
|
|
84
|
+
/** Override the generated WebMCP tool name. */
|
|
85
|
+
toolName: string;
|
|
86
|
+
/** Override the generated WebMCP tool description. */
|
|
87
|
+
toolDescription: string;
|
|
88
|
+
private toolDisposer;
|
|
89
|
+
/** The resolved WebMCP tool name. */
|
|
90
|
+
abstract get resolvedToolName(): string;
|
|
91
|
+
/** Description used when `tool-description` is not set. */
|
|
92
|
+
protected abstract get defaultToolDescription(): string;
|
|
93
|
+
/** JSON Schema for the tool's args. Defaults to a no-argument tool. */
|
|
94
|
+
protected toolInputSchema(): JSONSchema;
|
|
95
|
+
/** Invoked when the agent calls the tool; returns the agent-facing result. */
|
|
96
|
+
protected abstract executeTool(args: Record<string, unknown>): WebMCPToolResult | Promise<WebMCPToolResult>;
|
|
97
|
+
/**
|
|
98
|
+
* Property changes that alter the tool's *identity* (name/description) and so
|
|
99
|
+
* require re-registration. State read live inside {@link executeTool} does
|
|
100
|
+
* not belong here. Subclasses extend this with their own naming inputs.
|
|
101
|
+
*/
|
|
102
|
+
protected get toolReactiveProps(): readonly string[];
|
|
103
|
+
connectedCallback(): void;
|
|
104
|
+
disconnectedCallback(): void;
|
|
105
|
+
updated(changed: Map<string, unknown>): void;
|
|
106
|
+
protected registerTool(): void;
|
|
107
|
+
}
|
|
108
|
+
|
|
64
109
|
/**
|
|
65
110
|
* Base class for form-associated, agent-operable controls.
|
|
66
111
|
*
|
|
@@ -86,7 +131,7 @@ declare const textFieldStyles: CSSResult;
|
|
|
86
131
|
* that supplies its control markup and tool schema. Abstract — not registered
|
|
87
132
|
* on its own.
|
|
88
133
|
*/
|
|
89
|
-
declare abstract class WmcpFormControl extends
|
|
134
|
+
declare abstract class WmcpFormControl extends WmcpExposable {
|
|
90
135
|
static formAssociated: boolean;
|
|
91
136
|
static styles: CSSResultGroup;
|
|
92
137
|
/** Visible label text. */
|
|
@@ -102,12 +147,6 @@ declare abstract class WmcpFormControl extends LitElement {
|
|
|
102
147
|
helperText: string;
|
|
103
148
|
/** Message shown when a `required` control is empty. */
|
|
104
149
|
requiredMessage: string;
|
|
105
|
-
/** Whether to expose this control as a WebMCP tool. */
|
|
106
|
-
expose: boolean;
|
|
107
|
-
/** Override the generated WebMCP tool name. */
|
|
108
|
-
toolName: string;
|
|
109
|
-
/** Override the generated WebMCP tool description. */
|
|
110
|
-
toolDescription: string;
|
|
111
150
|
/**
|
|
112
151
|
* Standard Schema validator (Zod, Valibot, ArkType, …). Set as a property,
|
|
113
152
|
* not an attribute. Validation runs on input and on form validation.
|
|
@@ -115,7 +154,6 @@ declare abstract class WmcpFormControl extends LitElement {
|
|
|
115
154
|
schema?: StandardSchemaV1<unknown, unknown>;
|
|
116
155
|
protected error: string;
|
|
117
156
|
protected readonly internals: ElementInternals;
|
|
118
|
-
private toolDisposer;
|
|
119
157
|
/** Noun used in default tool names/descriptions when `name` is empty. */
|
|
120
158
|
protected get controlNoun(): string;
|
|
121
159
|
/** The rendered control element (`<input>` / `<textarea>` / `<select>`). */
|
|
@@ -145,9 +183,10 @@ declare abstract class WmcpFormControl extends LitElement {
|
|
|
145
183
|
protected get requiredMessageDefault(): string;
|
|
146
184
|
disconnectedCallback(): void;
|
|
147
185
|
updated(changed: Map<string, unknown>): void;
|
|
148
|
-
/** The resolved WebMCP tool name. */
|
|
149
186
|
get resolvedToolName(): string;
|
|
150
|
-
protected
|
|
187
|
+
protected get defaultToolDescription(): string;
|
|
188
|
+
protected get toolReactiveProps(): readonly string[];
|
|
189
|
+
protected executeTool(args: Record<string, unknown>): Promise<WebMCPToolResult>;
|
|
151
190
|
/**
|
|
152
191
|
* Apply the agent's tool arguments to component state. Defaults to treating
|
|
153
192
|
* `args.value` as the new string value; controls with a different shape
|
|
@@ -359,13 +398,401 @@ declare class WmcpRadioGroup extends WmcpFormControl {
|
|
|
359
398
|
render(): TemplateResult;
|
|
360
399
|
}
|
|
361
400
|
|
|
401
|
+
/**
|
|
402
|
+
* Base class for agent-operable *action* elements.
|
|
403
|
+
*
|
|
404
|
+
* Where {@link WmcpFormControl} exposes a *value* an agent can set, an action
|
|
405
|
+
* element exposes an *action* an agent can trigger — a click, an open, a
|
|
406
|
+
* dismissal. The WebMCP exposure mechanism (the `expose` surface, the tool
|
|
407
|
+
* lifecycle, the `exposeTool` call) lives in the shared {@link WmcpExposable}
|
|
408
|
+
* base; this layer adds the action-flavored *policy*: a verb-prefixed tool name
|
|
409
|
+
* (`click_save`, `open_booking`), an action-shaped default description, and a
|
|
410
|
+
* no-argument tool by default.
|
|
411
|
+
*
|
|
412
|
+
* A subclass supplies {@link actionVerb} and {@link executeTool}, and may
|
|
413
|
+
* override {@link actionNoun}, {@link defaultNameSuffix}, or
|
|
414
|
+
* {@link toolInputSchema} (e.g. a menu whose action takes which-item). Abstract
|
|
415
|
+
* — not registered on its own.
|
|
416
|
+
*
|
|
417
|
+
* Extracted when the second action element (dialog) landed alongside the first
|
|
418
|
+
* (button) — two data points reveal what's genuinely shared, the same rule
|
|
419
|
+
* that produced `WmcpFormControl`.
|
|
420
|
+
*/
|
|
421
|
+
declare abstract class WmcpAction extends WmcpExposable {
|
|
422
|
+
/** Identifier used to build the default tool name. */
|
|
423
|
+
name: string;
|
|
424
|
+
/** Accessible name and the noun used in the default tool description. */
|
|
425
|
+
label: string;
|
|
426
|
+
/** Verb that prefixes the default tool name, e.g. `click` → `click_save`. */
|
|
427
|
+
protected abstract get actionVerb(): string;
|
|
428
|
+
/** Suffix for the default tool name when `name` is empty. */
|
|
429
|
+
protected get defaultNameSuffix(): string;
|
|
430
|
+
/** Human-readable noun for the thing being acted on. */
|
|
431
|
+
protected get actionNoun(): string;
|
|
432
|
+
get resolvedToolName(): string;
|
|
433
|
+
protected get defaultToolDescription(): string;
|
|
434
|
+
protected get toolReactiveProps(): readonly string[];
|
|
435
|
+
/**
|
|
436
|
+
* Perform the action and return the agent-facing result. Called when the
|
|
437
|
+
* agent invokes the tool; subclasses implement the actual effect.
|
|
438
|
+
*/
|
|
439
|
+
protected abstract executeTool(args: Record<string, unknown>): WebMCPToolResult | Promise<WebMCPToolResult>;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/** Visual variants `<wmcp-button>` supports (shadcn-aligned). */
|
|
443
|
+
type WmcpButtonVariant = 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost';
|
|
444
|
+
/** Size variants `<wmcp-button>` supports. */
|
|
445
|
+
type WmcpButtonSize = 'sm' | 'md' | 'lg';
|
|
446
|
+
/** Native button behaviors `<wmcp-button>` mirrors. */
|
|
447
|
+
type WmcpButtonType = 'button' | 'submit' | 'reset';
|
|
448
|
+
/**
|
|
449
|
+
* `<wmcp-button>` — a themeable, agent-operable button. The first Phase 2
|
|
450
|
+
* interaction primitive.
|
|
451
|
+
*
|
|
452
|
+
* Where the form controls expose a *value* an agent can set, a button exposes
|
|
453
|
+
* an *action* an agent can trigger. When a WebMCP host is present and the
|
|
454
|
+
* button opts in (`expose`), it registers a tool that activates the button
|
|
455
|
+
* exactly as a human click would — running light-DOM `click` handlers and, for
|
|
456
|
+
* `type="submit"`/`"reset"`, driving the associated form. With no agent
|
|
457
|
+
* present (the common case today) it is simply a good, accessible button.
|
|
458
|
+
*
|
|
459
|
+
* Activation has a single path: both a real click and an agent tool call route
|
|
460
|
+
* through the inner native `<button>`, so behavior, focus, and form
|
|
461
|
+
* participation are identical for human and agent. A `disabled` button can be
|
|
462
|
+
* activated by neither.
|
|
463
|
+
*
|
|
464
|
+
* Form-associated, so `type="submit"` and `type="reset"` work from inside the
|
|
465
|
+
* shadow boundary (a native submit button there would not reach the outer
|
|
466
|
+
* form). Visible content is slotted; an explicit `label` is used for the
|
|
467
|
+
* accessible name and the default tool description when set.
|
|
468
|
+
*
|
|
469
|
+
* Not auto-registered — call `defineComponents()` (or load the CDN bundle).
|
|
470
|
+
*/
|
|
471
|
+
declare class WmcpButton extends WmcpAction {
|
|
472
|
+
static readonly tagName = "wmcp-button";
|
|
473
|
+
static formAssociated: boolean;
|
|
474
|
+
static shadowRootOptions: ShadowRootInit;
|
|
475
|
+
static styles: CSSResultGroup;
|
|
476
|
+
/** Visual variant. */
|
|
477
|
+
variant: WmcpButtonVariant;
|
|
478
|
+
/** Size. */
|
|
479
|
+
size: WmcpButtonSize;
|
|
480
|
+
/** Native button behavior: a plain button, a form submit, or a form reset. */
|
|
481
|
+
type: WmcpButtonType;
|
|
482
|
+
/** Disables the button for both humans and agents. */
|
|
483
|
+
disabled: boolean;
|
|
484
|
+
private readonly internals;
|
|
485
|
+
/** The inner native `<button>` that owns activation, focus, and a11y. */
|
|
486
|
+
private get button();
|
|
487
|
+
protected get actionVerb(): string;
|
|
488
|
+
protected get defaultNameSuffix(): string;
|
|
489
|
+
protected get actionNoun(): string;
|
|
490
|
+
protected get defaultToolDescription(): string;
|
|
491
|
+
protected executeTool(): WebMCPToolResult;
|
|
492
|
+
/**
|
|
493
|
+
* Activate the button as if a human clicked it: routes through the inner
|
|
494
|
+
* native button so light-DOM `click` handlers fire and `type`-driven form
|
|
495
|
+
* submission/reset happens. A no-op when disabled.
|
|
496
|
+
*/
|
|
497
|
+
activate(): void;
|
|
498
|
+
/**
|
|
499
|
+
* Inner-button click handler. The native click already bubbles (composed) to
|
|
500
|
+
* the host, so light-DOM listeners fire without help; this only adds the
|
|
501
|
+
* cross-shadow form behavior a native submit/reset button can't do from here.
|
|
502
|
+
*/
|
|
503
|
+
private onInnerClick;
|
|
504
|
+
render(): TemplateResult;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* `<wmcp-dialog>` — a modal dialog whose *action* is being opened. The second
|
|
509
|
+
* Phase 2 interaction primitive, and the one that motivated the shared
|
|
510
|
+
* {@link WmcpAction} base.
|
|
511
|
+
*
|
|
512
|
+
* It wraps the native `<dialog>` element, so it inherits the platform's focus
|
|
513
|
+
* trap, top-layer stacking, backdrop, and Escape-to-close for free. The
|
|
514
|
+
* exposed WebMCP action is **open** — the agent surfaces the dialog for the
|
|
515
|
+
* user to review; closing/confirming stays a deliberate human (or
|
|
516
|
+
* programmatic) step. That asymmetry is the consent gate: an agent can ask for
|
|
517
|
+
* attention, but the irreversible confirm is the person's to make.
|
|
518
|
+
*
|
|
519
|
+
* Drive it declaratively with the reflected `open` attribute or imperatively
|
|
520
|
+
* with {@link show} / {@link close}; either way it emits composed `open` and
|
|
521
|
+
* `close` events. With no agent present it is simply an accessible modal.
|
|
522
|
+
*
|
|
523
|
+
* Not auto-registered — call `defineComponents()` (or load the CDN bundle).
|
|
524
|
+
*/
|
|
525
|
+
declare class WmcpDialog extends WmcpAction {
|
|
526
|
+
static readonly tagName = "wmcp-dialog";
|
|
527
|
+
static styles: CSSResultGroup;
|
|
528
|
+
/** Whether the dialog is open (reflected, so `[open]` styling works). */
|
|
529
|
+
open: boolean;
|
|
530
|
+
/** Open as a modal (focus-trapping, with backdrop). Set false for non-modal. */
|
|
531
|
+
modal: boolean;
|
|
532
|
+
/** Keep the dialog open when the backdrop is clicked (modal "static" mode). */
|
|
533
|
+
staticBackdrop: boolean;
|
|
534
|
+
/** Last `returnValue` the dialog closed with (mirrors native `<dialog>`). */
|
|
535
|
+
returnValue: string;
|
|
536
|
+
private get dialogEl();
|
|
537
|
+
protected get actionVerb(): string;
|
|
538
|
+
protected get defaultNameSuffix(): string;
|
|
539
|
+
protected get defaultToolDescription(): string;
|
|
540
|
+
protected executeTool(): WebMCPToolResult;
|
|
541
|
+
updated(changed: Map<string, unknown>): void;
|
|
542
|
+
/** Open the dialog (modal unless `modal` is false). */
|
|
543
|
+
show(): void;
|
|
544
|
+
/** Close the dialog, optionally recording a `returnValue`. */
|
|
545
|
+
close(returnValue?: string): void;
|
|
546
|
+
/** Reconcile our `open` state with the native dialog's imperative API. */
|
|
547
|
+
private syncNativeOpen;
|
|
548
|
+
/** Native `close` fires for Escape, backdrop, or our own `close()`. */
|
|
549
|
+
private onNativeClose;
|
|
550
|
+
/**
|
|
551
|
+
* Close on a backdrop click. A click whose target is the `<dialog>` itself
|
|
552
|
+
* is the backdrop — content clicks retarget to `.panel` or its children — so
|
|
553
|
+
* this never fires on the dialog's own frame or a text drag-select.
|
|
554
|
+
*/
|
|
555
|
+
private onDialogClick;
|
|
556
|
+
render(): TemplateResult;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/** A single selectable item in a `<wmcp-menu>`. */
|
|
560
|
+
interface WmcpMenuItem {
|
|
561
|
+
value: string;
|
|
562
|
+
label: string;
|
|
563
|
+
disabled?: boolean;
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* `<wmcp-menu>` — a menu-button whose exposed action is *selecting an item*.
|
|
567
|
+
* The first **parameterized** interaction primitive: where button and dialog
|
|
568
|
+
* expose no-argument actions, the menu's tool takes *which item* — an `enum`
|
|
569
|
+
* of the item values — so it pressure-tests the {@link WmcpAction} base the
|
|
570
|
+
* way `<wmcp-select>` did for `WmcpFormControl`.
|
|
571
|
+
*
|
|
572
|
+
* The popup uses the native Popover API (top layer, light-dismiss, and Escape
|
|
573
|
+
* for free); items come from declarative `<option>` children (no build) or the
|
|
574
|
+
* `items` property. Selecting an item — by human click, keyboard, or agent
|
|
575
|
+
* tool call — fires a composed `select` event (`detail: { value, label }`) and
|
|
576
|
+
* closes the menu. A menu dispatches actions; it does not hold a value.
|
|
577
|
+
*
|
|
578
|
+
* Not auto-registered — call `defineComponents()` (or load the CDN bundle).
|
|
579
|
+
*/
|
|
580
|
+
declare class WmcpMenu extends WmcpAction {
|
|
581
|
+
static readonly tagName = "wmcp-menu";
|
|
582
|
+
static styles: CSSResultGroup;
|
|
583
|
+
/** Trigger label. */
|
|
584
|
+
label: string;
|
|
585
|
+
/**
|
|
586
|
+
* Items as data. When non-empty, takes precedence over declarative
|
|
587
|
+
* `<option>` children. Set as a property, not an attribute.
|
|
588
|
+
*/
|
|
589
|
+
items: WmcpMenuItem[];
|
|
590
|
+
/** Whether the popup is open (reflected). */
|
|
591
|
+
open: boolean;
|
|
592
|
+
/** The normalized item model actually rendered (property or declarative). */
|
|
593
|
+
private resolvedItems;
|
|
594
|
+
private itemObserver?;
|
|
595
|
+
private get menuEl();
|
|
596
|
+
private get itemButtons();
|
|
597
|
+
protected get actionVerb(): string;
|
|
598
|
+
protected get defaultNameSuffix(): string;
|
|
599
|
+
protected get actionNoun(): string;
|
|
600
|
+
protected get defaultToolDescription(): string;
|
|
601
|
+
protected get toolReactiveProps(): readonly string[];
|
|
602
|
+
protected toolInputSchema(): JSONSchema;
|
|
603
|
+
protected executeTool(args: Record<string, unknown>): WebMCPToolResult;
|
|
604
|
+
connectedCallback(): void;
|
|
605
|
+
disconnectedCallback(): void;
|
|
606
|
+
willUpdate(changed: Map<string, unknown>): void;
|
|
607
|
+
private syncItems;
|
|
608
|
+
private readDeclarativeItems;
|
|
609
|
+
/** Dispatch the selection and close the menu. */
|
|
610
|
+
private selectItem;
|
|
611
|
+
private onItemClick;
|
|
612
|
+
/** Sync `open`/`aria-expanded` and move focus into the menu when it opens. */
|
|
613
|
+
private onToggle;
|
|
614
|
+
/** Roving focus among items with the arrow / Home / End keys. */
|
|
615
|
+
private onMenuKeydown;
|
|
616
|
+
render(): TemplateResult;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/** A single tab derived from a `[tab]` panel child of `<wmcp-tabs>`. */
|
|
620
|
+
interface WmcpTabInfo {
|
|
621
|
+
value: string;
|
|
622
|
+
label: string;
|
|
623
|
+
disabled?: boolean;
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* `<wmcp-tabs>` — a tab set whose exposed action is *switching the active tab*.
|
|
627
|
+
* The first **stateful** interaction primitive: where button/dialog/menu are
|
|
628
|
+
* fire-and-forget dispatchers, a tab set holds a persistent `active` selection
|
|
629
|
+
* (reflected), and the agent's tool both reads and changes it.
|
|
630
|
+
*
|
|
631
|
+
* It confirms the {@link WmcpAction} base needs no "current value" concept — a
|
|
632
|
+
* stateful action element simply owns its own state (here `active`, like the
|
|
633
|
+
* dialog owns `open`) and its `executeTool` mutates it.
|
|
634
|
+
*
|
|
635
|
+
* Panels are declarative light-DOM children carrying a `tab` attribute (and an
|
|
636
|
+
* optional `tab-label`); the tablist is derived from them. Switching — by
|
|
637
|
+
* click, arrow keys, or agent — updates `active`, reveals the matching panel,
|
|
638
|
+
* and fires a composed `change` event (`detail: { value }`).
|
|
639
|
+
*
|
|
640
|
+
* Not auto-registered — call `defineComponents()` (or load the CDN bundle).
|
|
641
|
+
*/
|
|
642
|
+
declare class WmcpTabs extends WmcpAction {
|
|
643
|
+
static readonly tagName = "wmcp-tabs";
|
|
644
|
+
static styles: CSSResultGroup;
|
|
645
|
+
/** The value of the active tab (reflected — this is the persistent state). */
|
|
646
|
+
active: string;
|
|
647
|
+
/** Accessible name for the tablist. */
|
|
648
|
+
label: string;
|
|
649
|
+
/** The tab model derived from the `[tab]` panel children. */
|
|
650
|
+
private tabs;
|
|
651
|
+
private panelObserver?;
|
|
652
|
+
protected get actionVerb(): string;
|
|
653
|
+
protected get defaultNameSuffix(): string;
|
|
654
|
+
protected get actionNoun(): string;
|
|
655
|
+
protected get defaultToolDescription(): string;
|
|
656
|
+
protected get toolReactiveProps(): readonly string[];
|
|
657
|
+
protected toolInputSchema(): JSONSchema;
|
|
658
|
+
protected executeTool(args: Record<string, unknown>): WebMCPToolResult;
|
|
659
|
+
connectedCallback(): void;
|
|
660
|
+
disconnectedCallback(): void;
|
|
661
|
+
updated(changed: Map<string, unknown>): void;
|
|
662
|
+
/** Light-DOM children that declare a tab via the `tab` attribute. */
|
|
663
|
+
private get panelEls();
|
|
664
|
+
private syncTabs;
|
|
665
|
+
/** Fall back to the first enabled tab when `active` is unset or invalid. */
|
|
666
|
+
private ensureActive;
|
|
667
|
+
/** Reflect the active tab onto the slotted panels (roles, labels, hidden). */
|
|
668
|
+
private applyPanels;
|
|
669
|
+
/** Switch the active tab, firing `change` when it actually moves. */
|
|
670
|
+
switchTo(value: string): void;
|
|
671
|
+
private get tabButtons();
|
|
672
|
+
/** Arrow / Home / End roving with automatic activation (ARIA tabs pattern). */
|
|
673
|
+
private onKeydown;
|
|
674
|
+
render(): TemplateResult;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/** Where the panel sits relative to its trigger. */
|
|
678
|
+
type WmcpPopoverPlacement = 'top' | 'bottom' | 'left' | 'right';
|
|
679
|
+
/** How the popover is opened: clicked (interactive) or hovered (tooltip). */
|
|
680
|
+
type WmcpPopoverTrigger = 'click' | 'hover';
|
|
681
|
+
/**
|
|
682
|
+
* `<wmcp-popover>` — a non-modal, anchored floating panel whose exposed action
|
|
683
|
+
* is being opened. The sibling of [dialog](./dialog.ts) (modal) and
|
|
684
|
+
* [menu](./menu.ts) (action list): same native-Popover-API + CSS-anchor
|
|
685
|
+
* machinery as the menu, but the content is arbitrary.
|
|
686
|
+
*
|
|
687
|
+
* `trigger="click"` (default) gives an interactive popover — click to toggle,
|
|
688
|
+
* with light-dismiss and Escape for free. `trigger="hover"` gives a tooltip —
|
|
689
|
+
* it opens on hover/focus, closes on leave/blur, and labels its trigger via
|
|
690
|
+
* `aria-describedby`. Either way the agent can `open` it; closing stays a
|
|
691
|
+
* human/light-dismiss step, the same consent posture as the dialog.
|
|
692
|
+
*
|
|
693
|
+
* Not auto-registered — call `defineComponents()` (or load the CDN bundle).
|
|
694
|
+
*/
|
|
695
|
+
declare class WmcpPopover extends WmcpAction {
|
|
696
|
+
static readonly tagName = "wmcp-popover";
|
|
697
|
+
static styles: CSSResultGroup;
|
|
698
|
+
/** Whether the panel is open (reflected). */
|
|
699
|
+
open: boolean;
|
|
700
|
+
/** Trigger text, used when no `trigger` slot content is provided. */
|
|
701
|
+
label: string;
|
|
702
|
+
/** Panel placement relative to the trigger. */
|
|
703
|
+
placement: WmcpPopoverPlacement;
|
|
704
|
+
/** Open on click (interactive popover) or on hover/focus (tooltip). */
|
|
705
|
+
trigger: WmcpPopoverTrigger;
|
|
706
|
+
private get panelEl();
|
|
707
|
+
protected get actionVerb(): string;
|
|
708
|
+
protected get defaultNameSuffix(): string;
|
|
709
|
+
protected get defaultToolDescription(): string;
|
|
710
|
+
protected executeTool(): WebMCPToolResult;
|
|
711
|
+
updated(changed: Map<string, unknown>): void;
|
|
712
|
+
/** Open the popover. */
|
|
713
|
+
show(): void;
|
|
714
|
+
/** Close the popover. */
|
|
715
|
+
close(): void;
|
|
716
|
+
private syncNativeOpen;
|
|
717
|
+
/** Native toggle fires for clicks, light-dismiss, Escape, and our own calls. */
|
|
718
|
+
private onToggle;
|
|
719
|
+
private closeTimer?;
|
|
720
|
+
disconnectedCallback(): void;
|
|
721
|
+
/** Open on hover/focus of the trigger *or* the panel. */
|
|
722
|
+
private openOnHover;
|
|
723
|
+
/**
|
|
724
|
+
* Close on leave/blur — but on a short delay, so the pointer can cross the
|
|
725
|
+
* gap from the trigger to the panel (and reach interactive content inside it)
|
|
726
|
+
* without the popover vanishing. Re-entering either cancels the close.
|
|
727
|
+
*/
|
|
728
|
+
private scheduleHoverClose;
|
|
729
|
+
private cancelScheduledClose;
|
|
730
|
+
render(): TemplateResult;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/** A toast's severity, used for styling and the agent-readable summary. */
|
|
734
|
+
type WmcpToastVariant = 'info' | 'success' | 'warning' | 'error';
|
|
735
|
+
/** Options accepted by {@link WmcpToast.show}. */
|
|
736
|
+
interface WmcpToastOptions {
|
|
737
|
+
title?: string;
|
|
738
|
+
message: string;
|
|
739
|
+
variant?: WmcpToastVariant;
|
|
740
|
+
/** Auto-dismiss after this many ms; `0` keeps it until dismissed. */
|
|
741
|
+
duration?: number;
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* `<wmcp-toast>` — a notification region, and the one component whose agent
|
|
745
|
+
* surface is *perceiving* rather than *actuating*.
|
|
746
|
+
*
|
|
747
|
+
* Page code throws toasts the way it always has — `el.show({ message })` — and
|
|
748
|
+
* they announce to screen readers via an `aria-live` region. When `expose` is
|
|
749
|
+
* set, the very same notifications become readable by an agent through a
|
|
750
|
+
* `read_<name>` tool: the machine-readable twin of the `aria-live`
|
|
751
|
+
* announcement. An agent acting on the user's behalf often has no other way to
|
|
752
|
+
* learn an outcome ("Payment declined", an async "Export ready"), so it reads
|
|
753
|
+
* the toasts rather than posting them.
|
|
754
|
+
*
|
|
755
|
+
* Extends {@link WmcpExposable} directly — not {@link WmcpAction} — because the
|
|
756
|
+
* tool reports state instead of triggering an action.
|
|
757
|
+
*
|
|
758
|
+
* Not auto-registered — call `defineComponents()` (or load the CDN bundle).
|
|
759
|
+
*/
|
|
760
|
+
declare class WmcpToast extends WmcpExposable {
|
|
761
|
+
static readonly tagName = "wmcp-toast";
|
|
762
|
+
static styles: CSSResultGroup;
|
|
763
|
+
/** Identifier used for the default tool name (`read_<name>`). */
|
|
764
|
+
name: string;
|
|
765
|
+
/** Accessible name for the live region. */
|
|
766
|
+
label: string;
|
|
767
|
+
/** Corner the toasts stack in. */
|
|
768
|
+
placement: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
769
|
+
/** Default auto-dismiss in ms; `0` keeps toasts until dismissed. */
|
|
770
|
+
duration: number;
|
|
771
|
+
private toasts;
|
|
772
|
+
private recent;
|
|
773
|
+
private nextId;
|
|
774
|
+
private timers;
|
|
775
|
+
/** Show a toast. Returns its id (pass to {@link dismiss}). */
|
|
776
|
+
show(options: WmcpToastOptions): number;
|
|
777
|
+
/** Dismiss a toast by id. */
|
|
778
|
+
dismiss(id: number): void;
|
|
779
|
+
/** Dismiss all visible toasts. */
|
|
780
|
+
clear(): void;
|
|
781
|
+
disconnectedCallback(): void;
|
|
782
|
+
get resolvedToolName(): string;
|
|
783
|
+
protected get defaultToolDescription(): string;
|
|
784
|
+
protected get toolReactiveProps(): readonly string[];
|
|
785
|
+
protected executeTool(): WebMCPToolResult;
|
|
786
|
+
render(): TemplateResult;
|
|
787
|
+
}
|
|
788
|
+
|
|
362
789
|
/**
|
|
363
790
|
* Register all webmcpui custom elements. Idempotent — safe to call more than
|
|
364
791
|
* once and safe alongside the CDN bundle (already-defined tags are skipped).
|
|
365
792
|
*/
|
|
366
793
|
declare function defineComponents(): void;
|
|
367
794
|
|
|
368
|
-
export { JSONSchema, StandardSchemaV1, type ValidationOutcome, WmcpCheckbox, WmcpFormControl, WmcpInput, type WmcpInputType, WmcpRadio, WmcpRadioGroup, type WmcpRadioOption, WmcpSelect, type WmcpSelectItem, type WmcpSelectOption, type WmcpSelectOptionGroup, WmcpTextarea, defineComponents, isStandardSchema, textFieldStyles, validateStandard };
|
|
795
|
+
export { JSONSchema, StandardSchemaV1, type ValidationOutcome, WebMCPToolResult, WmcpAction, WmcpButton, type WmcpButtonSize, type WmcpButtonType, type WmcpButtonVariant, WmcpCheckbox, WmcpDialog, WmcpExposable, WmcpFormControl, WmcpInput, type WmcpInputType, WmcpMenu, type WmcpMenuItem, WmcpPopover, type WmcpPopoverPlacement, type WmcpPopoverTrigger, WmcpRadio, WmcpRadioGroup, type WmcpRadioOption, WmcpSelect, type WmcpSelectItem, type WmcpSelectOption, type WmcpSelectOptionGroup, type WmcpTabInfo, WmcpTabs, WmcpTextarea, WmcpToast, type WmcpToastOptions, type WmcpToastVariant, defineComponents, isStandardSchema, textFieldStyles, validateStandard };
|
|
369
796
|
|
|
370
797
|
declare global {
|
|
371
798
|
interface HTMLElementTagNameMap {
|
|
@@ -375,5 +802,11 @@ declare global {
|
|
|
375
802
|
'wmcp-checkbox': import('./index.js').WmcpCheckbox;
|
|
376
803
|
'wmcp-radio': import('./index.js').WmcpRadio;
|
|
377
804
|
'wmcp-radio-group': import('./index.js').WmcpRadioGroup;
|
|
805
|
+
'wmcp-button': import('./index.js').WmcpButton;
|
|
806
|
+
'wmcp-dialog': import('./index.js').WmcpDialog;
|
|
807
|
+
'wmcp-menu': import('./index.js').WmcpMenu;
|
|
808
|
+
'wmcp-tabs': import('./index.js').WmcpTabs;
|
|
809
|
+
'wmcp-popover': import('./index.js').WmcpPopover;
|
|
810
|
+
'wmcp-toast': import('./index.js').WmcpToast;
|
|
378
811
|
}
|
|
379
812
|
}
|