@webmcpui/core 0.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/LICENSE +21 -0
- package/README.md +111 -0
- package/dist/chunk-ADS4GRIL.js +14 -0
- package/dist/index.d.ts +378 -0
- package/dist/index.js +1002 -0
- package/dist/testing.d.ts +34 -0
- package/dist/testing.js +47 -0
- package/dist/webmcp-DEspBoqq.d.ts +47 -0
- package/dist/webmcpui.global.js +343 -0
- package/package.json +65 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1002 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__decorateClass
|
|
3
|
+
} from "./chunk-ADS4GRIL.js";
|
|
4
|
+
|
|
5
|
+
// src/elements/form-control.ts
|
|
6
|
+
import {
|
|
7
|
+
LitElement,
|
|
8
|
+
html,
|
|
9
|
+
css,
|
|
10
|
+
nothing
|
|
11
|
+
} from "lit";
|
|
12
|
+
import { property, state } from "lit/decorators.js";
|
|
13
|
+
|
|
14
|
+
// src/standard-schema.ts
|
|
15
|
+
async function validateStandard(schema, value) {
|
|
16
|
+
const result = await schema["~standard"].validate(value);
|
|
17
|
+
if (result.issues) {
|
|
18
|
+
return { valid: false, errors: result.issues.map((i) => i.message) };
|
|
19
|
+
}
|
|
20
|
+
return { valid: true, value: result.value, errors: [] };
|
|
21
|
+
}
|
|
22
|
+
function isStandardSchema(value) {
|
|
23
|
+
return typeof value === "object" && value !== null && "~standard" in value && typeof value["~standard"]?.validate === "function";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/webmcp.ts
|
|
27
|
+
function getModelContext() {
|
|
28
|
+
const fromDocument = typeof document !== "undefined" ? document.modelContext : void 0;
|
|
29
|
+
const fromNavigator = typeof navigator !== "undefined" ? navigator.modelContext : void 0;
|
|
30
|
+
const mc = fromDocument ?? fromNavigator;
|
|
31
|
+
return mc && typeof mc.registerTool === "function" ? mc : void 0;
|
|
32
|
+
}
|
|
33
|
+
function isWebMCPAvailable() {
|
|
34
|
+
return getModelContext() !== void 0;
|
|
35
|
+
}
|
|
36
|
+
var isDevEnv = globalThis.process?.env?.NODE_ENV !== "production";
|
|
37
|
+
var registeredToolNames = /* @__PURE__ */ new Set();
|
|
38
|
+
function exposeTool(definition) {
|
|
39
|
+
const mc = getModelContext();
|
|
40
|
+
if (!mc?.registerTool) return () => {
|
|
41
|
+
};
|
|
42
|
+
const descriptor = {
|
|
43
|
+
name: definition.name,
|
|
44
|
+
description: definition.description,
|
|
45
|
+
inputSchema: definition.inputSchema ?? { type: "object", properties: {} },
|
|
46
|
+
execute: definition.execute
|
|
47
|
+
};
|
|
48
|
+
if (isDevEnv && registeredToolNames.has(descriptor.name)) {
|
|
49
|
+
console.warn(
|
|
50
|
+
`[webmcpui] A WebMCP tool named "${descriptor.name}" is already registered on this page. Tool names are page-global, so the host rejects the duplicate and this control won't be agent-callable. Give one control a unique \`name\`, or override it with \`tool-name\`.`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
registeredToolNames.add(descriptor.name);
|
|
54
|
+
const controller = typeof AbortController === "function" ? new AbortController() : void 0;
|
|
55
|
+
const handle = mc.registerTool(
|
|
56
|
+
descriptor,
|
|
57
|
+
controller ? { signal: controller.signal } : void 0
|
|
58
|
+
);
|
|
59
|
+
let disposed = false;
|
|
60
|
+
return () => {
|
|
61
|
+
if (disposed) return;
|
|
62
|
+
disposed = true;
|
|
63
|
+
registeredToolNames.delete(descriptor.name);
|
|
64
|
+
try {
|
|
65
|
+
controller?.abort();
|
|
66
|
+
if (handle && typeof handle.unregister === "function") {
|
|
67
|
+
handle.unregister();
|
|
68
|
+
} else if (typeof mc.unregisterTool === "function") {
|
|
69
|
+
mc.unregisterTool(definition.name);
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// src/elements/form-control.ts
|
|
77
|
+
var textFieldStyles = css`
|
|
78
|
+
.control {
|
|
79
|
+
box-sizing: border-box;
|
|
80
|
+
width: 100%;
|
|
81
|
+
padding: var(--input-padding-y, 0.5rem) var(--input-padding-x, 0.75rem);
|
|
82
|
+
font-family: inherit;
|
|
83
|
+
font-size: var(--input-font-size, 0.875rem);
|
|
84
|
+
line-height: var(--input-line-height, 1.25rem);
|
|
85
|
+
color: var(--input-text, var(--foreground, oklch(0.145 0 0)));
|
|
86
|
+
background: var(--input-bg, var(--background, oklch(1 0 0)));
|
|
87
|
+
border: var(--input-border-width, 1px) solid
|
|
88
|
+
var(--input-border, var(--input, oklch(0.922 0 0)));
|
|
89
|
+
border-radius: var(--input-radius, var(--radius, 0.625rem));
|
|
90
|
+
transition: border-color var(--input-transition-duration, 150ms)
|
|
91
|
+
var(--input-transition-easing, cubic-bezier(0.4, 0, 0.2, 1)),
|
|
92
|
+
box-shadow var(--input-transition-duration, 150ms)
|
|
93
|
+
var(--input-transition-easing, cubic-bezier(0.4, 0, 0.2, 1));
|
|
94
|
+
}
|
|
95
|
+
.control::placeholder {
|
|
96
|
+
color: var(--input-placeholder, var(--muted-foreground, oklch(0.556 0 0)));
|
|
97
|
+
}
|
|
98
|
+
.control:hover:not(:disabled) {
|
|
99
|
+
border-color: var(--input-border-hover, var(--border, oklch(0.922 0 0)));
|
|
100
|
+
}
|
|
101
|
+
.control:focus-visible {
|
|
102
|
+
outline: none;
|
|
103
|
+
border-color: var(--input-border-focus, var(--ring, oklch(0.708 0 0)));
|
|
104
|
+
box-shadow: 0 0 0 var(--ring-width, 3px)
|
|
105
|
+
color-mix(in oklch, var(--ring, oklch(0.708 0 0)) 40%, transparent);
|
|
106
|
+
}
|
|
107
|
+
.control:disabled {
|
|
108
|
+
color: var(--input-text-disabled, var(--muted-foreground, oklch(0.556 0 0)));
|
|
109
|
+
background: var(--input-bg-disabled, var(--muted, oklch(0.97 0 0)));
|
|
110
|
+
cursor: not-allowed;
|
|
111
|
+
}
|
|
112
|
+
:host([invalid]) .control {
|
|
113
|
+
border-color: var(
|
|
114
|
+
--input-border-error,
|
|
115
|
+
var(--destructive, oklch(0.577 0.245 27.325))
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
`;
|
|
119
|
+
var WmcpFormControl = class extends LitElement {
|
|
120
|
+
constructor() {
|
|
121
|
+
super(...arguments);
|
|
122
|
+
this.label = "";
|
|
123
|
+
this.name = "";
|
|
124
|
+
this.value = "";
|
|
125
|
+
this.placeholder = "";
|
|
126
|
+
this.required = false;
|
|
127
|
+
this.disabled = false;
|
|
128
|
+
this.helperText = "";
|
|
129
|
+
this.requiredMessage = "";
|
|
130
|
+
this.expose = false;
|
|
131
|
+
this.toolName = "";
|
|
132
|
+
this.toolDescription = "";
|
|
133
|
+
this.error = "";
|
|
134
|
+
this.internals = this.attachInternals();
|
|
135
|
+
this.toolDisposer = () => {
|
|
136
|
+
};
|
|
137
|
+
/** Reveal the validation message when the form reports validity (submit). */
|
|
138
|
+
this.onInvalid = () => {
|
|
139
|
+
this.error = this.internals.validationMessage;
|
|
140
|
+
this.toggleAttribute("invalid", true);
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
static {
|
|
144
|
+
this.formAssociated = true;
|
|
145
|
+
}
|
|
146
|
+
static {
|
|
147
|
+
// Shared by every control: host layout, label, and the message/error text.
|
|
148
|
+
// Text-field box styling lives in `textFieldStyles` (opted into by input /
|
|
149
|
+
// textarea / select) so non-text controls like checkbox don't inherit it.
|
|
150
|
+
this.styles = css`
|
|
151
|
+
:host {
|
|
152
|
+
display: inline-flex;
|
|
153
|
+
flex-direction: column;
|
|
154
|
+
gap: var(--input-gap-label, 0.375rem);
|
|
155
|
+
font-family: var(
|
|
156
|
+
--input-font-family,
|
|
157
|
+
ui-sans-serif,
|
|
158
|
+
system-ui,
|
|
159
|
+
sans-serif
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
:host([hidden]) {
|
|
163
|
+
display: none;
|
|
164
|
+
}
|
|
165
|
+
label {
|
|
166
|
+
font-size: var(--input-font-size-label, 0.875rem);
|
|
167
|
+
font-weight: var(--input-font-weight-label, 500);
|
|
168
|
+
color: var(--input-label, var(--foreground, oklch(0.145 0 0)));
|
|
169
|
+
}
|
|
170
|
+
.message {
|
|
171
|
+
font-size: var(--input-font-size-helper, 0.8125rem);
|
|
172
|
+
}
|
|
173
|
+
.helper {
|
|
174
|
+
color: var(--input-helper, var(--muted-foreground, oklch(0.556 0 0)));
|
|
175
|
+
}
|
|
176
|
+
.error {
|
|
177
|
+
color: var(
|
|
178
|
+
--input-error-text,
|
|
179
|
+
var(--destructive, oklch(0.577 0.245 27.325))
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
`;
|
|
183
|
+
}
|
|
184
|
+
/** Noun used in default tool names/descriptions when `name` is empty. */
|
|
185
|
+
get controlNoun() {
|
|
186
|
+
return "field";
|
|
187
|
+
}
|
|
188
|
+
/** The rendered control element (`<input>` / `<textarea>` / `<select>`). */
|
|
189
|
+
get control() {
|
|
190
|
+
return this.renderRoot?.querySelector("input, textarea, select") ?? null;
|
|
191
|
+
}
|
|
192
|
+
/** Id to point the control's `aria-describedby` at, if any. */
|
|
193
|
+
get describedBy() {
|
|
194
|
+
return this.error ? "wmcp-error" : this.helperText ? "wmcp-helper" : void 0;
|
|
195
|
+
}
|
|
196
|
+
connectedCallback() {
|
|
197
|
+
super.connectedCallback();
|
|
198
|
+
this.syncFormValue();
|
|
199
|
+
this.addEventListener("invalid", this.onInvalid);
|
|
200
|
+
void this.validate(false);
|
|
201
|
+
if (this.expose) this.registerTool();
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* The value contributed to the containing form. Defaults to the string
|
|
205
|
+
* `value`; controls with a conditional contribution (e.g. an unchecked
|
|
206
|
+
* checkbox) override this and may return `null` to contribute nothing.
|
|
207
|
+
*/
|
|
208
|
+
getFormValue() {
|
|
209
|
+
return this.value;
|
|
210
|
+
}
|
|
211
|
+
/** Push the current form value into ElementInternals. */
|
|
212
|
+
syncFormValue() {
|
|
213
|
+
this.internals.setFormValue(this.getFormValue());
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* The value passed to the schema validator. Defaults to the string `value`;
|
|
217
|
+
* boolean controls (checkbox) override to validate their checked state.
|
|
218
|
+
*/
|
|
219
|
+
get validationValue() {
|
|
220
|
+
return this.value;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Whether the control counts as empty for the `required` constraint.
|
|
224
|
+
* Defaults to an empty string value; boolean controls (checkbox) override.
|
|
225
|
+
*/
|
|
226
|
+
get isEmpty() {
|
|
227
|
+
return this.value === "";
|
|
228
|
+
}
|
|
229
|
+
/** Default message for the `required` constraint when none is provided. */
|
|
230
|
+
get requiredMessageDefault() {
|
|
231
|
+
return "This field is required.";
|
|
232
|
+
}
|
|
233
|
+
disconnectedCallback() {
|
|
234
|
+
super.disconnectedCallback();
|
|
235
|
+
this.removeEventListener("invalid", this.onInvalid);
|
|
236
|
+
this.toolDisposer();
|
|
237
|
+
this.toolDisposer = () => {
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
updated(changed) {
|
|
241
|
+
this.syncFormValue();
|
|
242
|
+
if (this.expose && (changed.has("expose") || changed.has("name") || changed.has("toolName") || changed.has("toolDescription"))) {
|
|
243
|
+
this.registerTool();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/** The resolved WebMCP tool name. */
|
|
247
|
+
get resolvedToolName() {
|
|
248
|
+
return this.toolName || `fill_${this.name || this.controlNoun}`;
|
|
249
|
+
}
|
|
250
|
+
registerTool() {
|
|
251
|
+
this.toolDisposer();
|
|
252
|
+
const noun = this.label || this.name || this.controlNoun;
|
|
253
|
+
this.toolDisposer = exposeTool({
|
|
254
|
+
name: this.resolvedToolName,
|
|
255
|
+
description: this.toolDescription || `Set the value of the "${noun}" field.`,
|
|
256
|
+
inputSchema: this.toolInputSchema(),
|
|
257
|
+
execute: async (args) => {
|
|
258
|
+
await this.applyAgentValue(args);
|
|
259
|
+
return {
|
|
260
|
+
content: [
|
|
261
|
+
{
|
|
262
|
+
type: "text",
|
|
263
|
+
text: this.error ? `Set "${noun}" but validation failed: ${this.error}` : `Set "${noun}" to "${this.stateDescription()}".`
|
|
264
|
+
}
|
|
265
|
+
],
|
|
266
|
+
isError: Boolean(this.error)
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Apply the agent's tool arguments to component state. Defaults to treating
|
|
273
|
+
* `args.value` as the new string value; controls with a different shape
|
|
274
|
+
* (e.g. checkbox's `args.checked`) override this.
|
|
275
|
+
*/
|
|
276
|
+
async applyAgentValue(args) {
|
|
277
|
+
const next = args.value;
|
|
278
|
+
await this.setValueFromAgent(next == null ? "" : String(next));
|
|
279
|
+
}
|
|
280
|
+
/** Human-readable current state, used in the tool's result message. */
|
|
281
|
+
stateDescription() {
|
|
282
|
+
return this.value;
|
|
283
|
+
}
|
|
284
|
+
/** JSON Schema for the WebMCP tool's args. Defaults to a single string. */
|
|
285
|
+
toolInputSchema() {
|
|
286
|
+
return {
|
|
287
|
+
type: "object",
|
|
288
|
+
properties: {
|
|
289
|
+
value: {
|
|
290
|
+
type: "string",
|
|
291
|
+
description: this.label || this.name || "The value to set."
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
required: ["value"]
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
/** Apply a value as if a user typed it: update, validate, announce. */
|
|
298
|
+
async setValueFromAgent(value) {
|
|
299
|
+
this.value = value;
|
|
300
|
+
await this.validate();
|
|
301
|
+
this.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
|
|
302
|
+
this.dispatchEvent(new Event("change", { bubbles: true, composed: true }));
|
|
303
|
+
}
|
|
304
|
+
async onInput(event) {
|
|
305
|
+
this.value = event.target.value;
|
|
306
|
+
await this.validate();
|
|
307
|
+
}
|
|
308
|
+
/** Compute validity: the `required` constraint first, then the schema. */
|
|
309
|
+
async computeValidity() {
|
|
310
|
+
if (this.required && this.isEmpty) {
|
|
311
|
+
return {
|
|
312
|
+
valid: false,
|
|
313
|
+
message: this.requiredMessage || this.requiredMessageDefault,
|
|
314
|
+
flags: { valueMissing: true }
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
if (isStandardSchema(this.schema)) {
|
|
318
|
+
const outcome = await validateStandard(this.schema, this.validationValue);
|
|
319
|
+
if (!outcome.valid) {
|
|
320
|
+
return {
|
|
321
|
+
valid: false,
|
|
322
|
+
message: outcome.errors[0] ?? "Invalid value",
|
|
323
|
+
flags: { customError: true }
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return { valid: true, message: "", flags: {} };
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Validate and reflect the result to the form via ElementInternals.
|
|
331
|
+
*
|
|
332
|
+
* @param show When true (default, on interaction) the error is also made
|
|
333
|
+
* visible. When false (on connect/reset) validity is set for
|
|
334
|
+
* `form.checkValidity()` but the message stays hidden until the form is
|
|
335
|
+
* actually reported (native-style — the `invalid` event reveals it).
|
|
336
|
+
*/
|
|
337
|
+
async validate(show = true) {
|
|
338
|
+
const { valid, message, flags } = await this.computeValidity();
|
|
339
|
+
if (valid) {
|
|
340
|
+
this.internals.setValidity({});
|
|
341
|
+
} else {
|
|
342
|
+
this.internals.setValidity(flags, message, this.control ?? void 0);
|
|
343
|
+
}
|
|
344
|
+
if (show) {
|
|
345
|
+
this.error = valid ? "" : message;
|
|
346
|
+
this.toggleAttribute("invalid", !valid);
|
|
347
|
+
}
|
|
348
|
+
return valid;
|
|
349
|
+
}
|
|
350
|
+
/** Called by the form when it resets. */
|
|
351
|
+
formResetCallback() {
|
|
352
|
+
this.value = "";
|
|
353
|
+
this.error = "";
|
|
354
|
+
this.toggleAttribute("invalid", false);
|
|
355
|
+
void this.validate(false);
|
|
356
|
+
}
|
|
357
|
+
renderMessage() {
|
|
358
|
+
return this.error ? html`<span id="wmcp-error" class="message error" role="alert"
|
|
359
|
+
>${this.error}</span
|
|
360
|
+
>` : this.helperText ? html`<span id="wmcp-helper" class="message helper"
|
|
361
|
+
>${this.helperText}</span
|
|
362
|
+
>` : nothing;
|
|
363
|
+
}
|
|
364
|
+
render() {
|
|
365
|
+
return html`
|
|
366
|
+
${this.label ? html`<label for="control">${this.label}</label>` : nothing}
|
|
367
|
+
${this.renderControl()}
|
|
368
|
+
${this.renderMessage()}
|
|
369
|
+
`;
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
__decorateClass([
|
|
373
|
+
property()
|
|
374
|
+
], WmcpFormControl.prototype, "label", 2);
|
|
375
|
+
__decorateClass([
|
|
376
|
+
property()
|
|
377
|
+
], WmcpFormControl.prototype, "name", 2);
|
|
378
|
+
__decorateClass([
|
|
379
|
+
property()
|
|
380
|
+
], WmcpFormControl.prototype, "value", 2);
|
|
381
|
+
__decorateClass([
|
|
382
|
+
property()
|
|
383
|
+
], WmcpFormControl.prototype, "placeholder", 2);
|
|
384
|
+
__decorateClass([
|
|
385
|
+
property({ type: Boolean, reflect: true })
|
|
386
|
+
], WmcpFormControl.prototype, "required", 2);
|
|
387
|
+
__decorateClass([
|
|
388
|
+
property({ type: Boolean, reflect: true })
|
|
389
|
+
], WmcpFormControl.prototype, "disabled", 2);
|
|
390
|
+
__decorateClass([
|
|
391
|
+
property({ attribute: "helper-text" })
|
|
392
|
+
], WmcpFormControl.prototype, "helperText", 2);
|
|
393
|
+
__decorateClass([
|
|
394
|
+
property({ attribute: "required-message" })
|
|
395
|
+
], WmcpFormControl.prototype, "requiredMessage", 2);
|
|
396
|
+
__decorateClass([
|
|
397
|
+
property({ type: Boolean })
|
|
398
|
+
], WmcpFormControl.prototype, "expose", 2);
|
|
399
|
+
__decorateClass([
|
|
400
|
+
property({ attribute: "tool-name" })
|
|
401
|
+
], WmcpFormControl.prototype, "toolName", 2);
|
|
402
|
+
__decorateClass([
|
|
403
|
+
property({ attribute: "tool-description" })
|
|
404
|
+
], WmcpFormControl.prototype, "toolDescription", 2);
|
|
405
|
+
__decorateClass([
|
|
406
|
+
property({ attribute: false })
|
|
407
|
+
], WmcpFormControl.prototype, "schema", 2);
|
|
408
|
+
__decorateClass([
|
|
409
|
+
state()
|
|
410
|
+
], WmcpFormControl.prototype, "error", 2);
|
|
411
|
+
|
|
412
|
+
// src/elements/input.ts
|
|
413
|
+
import { html as html2, css as css2, nothing as nothing2 } from "lit";
|
|
414
|
+
import { property as property2 } from "lit/decorators.js";
|
|
415
|
+
var WmcpInput = class extends WmcpFormControl {
|
|
416
|
+
constructor() {
|
|
417
|
+
super(...arguments);
|
|
418
|
+
this.type = "text";
|
|
419
|
+
}
|
|
420
|
+
static {
|
|
421
|
+
this.tagName = "wmcp-input";
|
|
422
|
+
}
|
|
423
|
+
static {
|
|
424
|
+
this.styles = [
|
|
425
|
+
WmcpFormControl.styles,
|
|
426
|
+
textFieldStyles,
|
|
427
|
+
css2`
|
|
428
|
+
.control {
|
|
429
|
+
height: var(--input-height-md, 2.25rem);
|
|
430
|
+
}
|
|
431
|
+
`
|
|
432
|
+
];
|
|
433
|
+
}
|
|
434
|
+
get controlNoun() {
|
|
435
|
+
return "input";
|
|
436
|
+
}
|
|
437
|
+
toolInputSchema() {
|
|
438
|
+
const valueType = this.type === "number" ? "number" : "string";
|
|
439
|
+
return {
|
|
440
|
+
type: "object",
|
|
441
|
+
properties: {
|
|
442
|
+
value: {
|
|
443
|
+
type: valueType,
|
|
444
|
+
description: this.label || this.name || "The value to set."
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
required: ["value"]
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
renderControl() {
|
|
451
|
+
return html2`
|
|
452
|
+
<input
|
|
453
|
+
id="control"
|
|
454
|
+
class="control"
|
|
455
|
+
part="control"
|
|
456
|
+
.type=${this.type}
|
|
457
|
+
.value=${this.value}
|
|
458
|
+
placeholder=${this.placeholder || nothing2}
|
|
459
|
+
?required=${this.required}
|
|
460
|
+
?disabled=${this.disabled}
|
|
461
|
+
aria-invalid=${this.error ? "true" : "false"}
|
|
462
|
+
aria-describedby=${this.describedBy ?? nothing2}
|
|
463
|
+
@input=${this.onInput}
|
|
464
|
+
/>
|
|
465
|
+
`;
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
__decorateClass([
|
|
469
|
+
property2()
|
|
470
|
+
], WmcpInput.prototype, "type", 2);
|
|
471
|
+
|
|
472
|
+
// src/elements/textarea.ts
|
|
473
|
+
import { html as html3, css as css3, nothing as nothing3 } from "lit";
|
|
474
|
+
import { property as property3 } from "lit/decorators.js";
|
|
475
|
+
var WmcpTextarea = class extends WmcpFormControl {
|
|
476
|
+
constructor() {
|
|
477
|
+
super(...arguments);
|
|
478
|
+
this.rows = 3;
|
|
479
|
+
}
|
|
480
|
+
static {
|
|
481
|
+
this.tagName = "wmcp-textarea";
|
|
482
|
+
}
|
|
483
|
+
static {
|
|
484
|
+
this.styles = [
|
|
485
|
+
WmcpFormControl.styles,
|
|
486
|
+
textFieldStyles,
|
|
487
|
+
css3`
|
|
488
|
+
.control {
|
|
489
|
+
min-height: var(--textarea-min-height, 4.5rem);
|
|
490
|
+
resize: vertical;
|
|
491
|
+
}
|
|
492
|
+
`
|
|
493
|
+
];
|
|
494
|
+
}
|
|
495
|
+
get controlNoun() {
|
|
496
|
+
return "textarea";
|
|
497
|
+
}
|
|
498
|
+
renderControl() {
|
|
499
|
+
return html3`
|
|
500
|
+
<textarea
|
|
501
|
+
id="control"
|
|
502
|
+
class="control"
|
|
503
|
+
part="control"
|
|
504
|
+
rows=${this.rows}
|
|
505
|
+
.value=${this.value}
|
|
506
|
+
placeholder=${this.placeholder || nothing3}
|
|
507
|
+
?required=${this.required}
|
|
508
|
+
?disabled=${this.disabled}
|
|
509
|
+
aria-invalid=${this.error ? "true" : "false"}
|
|
510
|
+
aria-describedby=${this.describedBy ?? nothing3}
|
|
511
|
+
@input=${this.onInput}
|
|
512
|
+
></textarea>
|
|
513
|
+
`;
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
__decorateClass([
|
|
517
|
+
property3({ type: Number })
|
|
518
|
+
], WmcpTextarea.prototype, "rows", 2);
|
|
519
|
+
|
|
520
|
+
// src/elements/select.ts
|
|
521
|
+
import { html as html4, css as css4, nothing as nothing4 } from "lit";
|
|
522
|
+
import { property as property4, state as state2 } from "lit/decorators.js";
|
|
523
|
+
import { repeat } from "lit/directives/repeat.js";
|
|
524
|
+
function isGroup(item) {
|
|
525
|
+
return Array.isArray(item.options);
|
|
526
|
+
}
|
|
527
|
+
var WmcpSelect = class extends WmcpFormControl {
|
|
528
|
+
constructor() {
|
|
529
|
+
super(...arguments);
|
|
530
|
+
this.options = [];
|
|
531
|
+
this.resolvedOptions = [];
|
|
532
|
+
}
|
|
533
|
+
static {
|
|
534
|
+
this.tagName = "wmcp-select";
|
|
535
|
+
}
|
|
536
|
+
static {
|
|
537
|
+
this.styles = [
|
|
538
|
+
WmcpFormControl.styles,
|
|
539
|
+
textFieldStyles,
|
|
540
|
+
css4`
|
|
541
|
+
.control {
|
|
542
|
+
height: var(--input-height-md, 2.25rem);
|
|
543
|
+
cursor: pointer;
|
|
544
|
+
}
|
|
545
|
+
.control:disabled {
|
|
546
|
+
cursor: not-allowed;
|
|
547
|
+
}
|
|
548
|
+
`
|
|
549
|
+
];
|
|
550
|
+
}
|
|
551
|
+
get controlNoun() {
|
|
552
|
+
return "select";
|
|
553
|
+
}
|
|
554
|
+
connectedCallback() {
|
|
555
|
+
this.syncOptions();
|
|
556
|
+
super.connectedCallback();
|
|
557
|
+
this.optionObserver = new MutationObserver(() => this.syncOptions());
|
|
558
|
+
this.optionObserver.observe(this, { childList: true, subtree: true });
|
|
559
|
+
}
|
|
560
|
+
disconnectedCallback() {
|
|
561
|
+
super.disconnectedCallback();
|
|
562
|
+
this.optionObserver?.disconnect();
|
|
563
|
+
this.optionObserver = void 0;
|
|
564
|
+
}
|
|
565
|
+
willUpdate(changed) {
|
|
566
|
+
if (changed.has("options")) this.syncOptions();
|
|
567
|
+
}
|
|
568
|
+
updated(changed) {
|
|
569
|
+
super.updated(changed);
|
|
570
|
+
if (this.expose && changed.has("resolvedOptions")) {
|
|
571
|
+
this.registerTool();
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
syncOptions() {
|
|
575
|
+
this.resolvedOptions = this.options.length > 0 ? this.options : this.readDeclarativeOptions();
|
|
576
|
+
}
|
|
577
|
+
readDeclarativeOptions() {
|
|
578
|
+
const toOption = (o) => ({
|
|
579
|
+
value: o.value,
|
|
580
|
+
label: o.textContent?.trim() || o.value,
|
|
581
|
+
disabled: o.disabled
|
|
582
|
+
});
|
|
583
|
+
const items = [];
|
|
584
|
+
for (const child of Array.from(this.children)) {
|
|
585
|
+
if (child instanceof HTMLOptGroupElement) {
|
|
586
|
+
items.push({
|
|
587
|
+
label: child.label,
|
|
588
|
+
options: Array.from(
|
|
589
|
+
child.querySelectorAll("option")
|
|
590
|
+
).map(toOption)
|
|
591
|
+
});
|
|
592
|
+
} else if (child instanceof HTMLOptionElement) {
|
|
593
|
+
items.push(toOption(child));
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return items;
|
|
597
|
+
}
|
|
598
|
+
/** All selectable options, flattened across groups. */
|
|
599
|
+
flatOptions() {
|
|
600
|
+
return this.resolvedOptions.flatMap(
|
|
601
|
+
(item) => isGroup(item) ? item.options : [item]
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
toolInputSchema() {
|
|
605
|
+
return {
|
|
606
|
+
type: "object",
|
|
607
|
+
properties: {
|
|
608
|
+
value: {
|
|
609
|
+
type: "string",
|
|
610
|
+
enum: this.flatOptions().map((o) => o.value),
|
|
611
|
+
description: this.label || this.name || "The option value to select."
|
|
612
|
+
}
|
|
613
|
+
},
|
|
614
|
+
required: ["value"]
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
renderOption(option) {
|
|
618
|
+
return html4`<option
|
|
619
|
+
value=${option.value}
|
|
620
|
+
?disabled=${option.disabled ?? false}
|
|
621
|
+
?selected=${option.value === this.value}
|
|
622
|
+
>
|
|
623
|
+
${option.label}
|
|
624
|
+
</option>`;
|
|
625
|
+
}
|
|
626
|
+
renderControl() {
|
|
627
|
+
return html4`
|
|
628
|
+
<select
|
|
629
|
+
id="control"
|
|
630
|
+
class="control"
|
|
631
|
+
part="control"
|
|
632
|
+
?required=${this.required}
|
|
633
|
+
?disabled=${this.disabled}
|
|
634
|
+
aria-invalid=${this.error ? "true" : "false"}
|
|
635
|
+
aria-describedby=${this.describedBy ?? nothing4}
|
|
636
|
+
@change=${this.onInput}
|
|
637
|
+
>
|
|
638
|
+
${this.placeholder ? html4`<option value="" disabled ?selected=${!this.value}>
|
|
639
|
+
${this.placeholder}
|
|
640
|
+
</option>` : nothing4}
|
|
641
|
+
${repeat(
|
|
642
|
+
this.resolvedOptions,
|
|
643
|
+
(item, i) => isGroup(item) ? `g:${item.label}:${i}` : `o:${item.value}`,
|
|
644
|
+
(item) => isGroup(item) ? html4`<optgroup label=${item.label}>
|
|
645
|
+
${item.options.map((o) => this.renderOption(o))}
|
|
646
|
+
</optgroup>` : this.renderOption(item)
|
|
647
|
+
)}
|
|
648
|
+
</select>
|
|
649
|
+
`;
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
__decorateClass([
|
|
653
|
+
property4({ attribute: false })
|
|
654
|
+
], WmcpSelect.prototype, "options", 2);
|
|
655
|
+
__decorateClass([
|
|
656
|
+
state2()
|
|
657
|
+
], WmcpSelect.prototype, "resolvedOptions", 2);
|
|
658
|
+
|
|
659
|
+
// src/elements/checkbox.ts
|
|
660
|
+
import { html as html5, css as css5, nothing as nothing5 } from "lit";
|
|
661
|
+
import { property as property5 } from "lit/decorators.js";
|
|
662
|
+
var WmcpCheckbox = class extends WmcpFormControl {
|
|
663
|
+
constructor() {
|
|
664
|
+
super();
|
|
665
|
+
this.checked = false;
|
|
666
|
+
this.defaultChecked = false;
|
|
667
|
+
this.value = "on";
|
|
668
|
+
}
|
|
669
|
+
static {
|
|
670
|
+
this.tagName = "wmcp-checkbox";
|
|
671
|
+
}
|
|
672
|
+
static {
|
|
673
|
+
this.styles = [
|
|
674
|
+
WmcpFormControl.styles,
|
|
675
|
+
css5`
|
|
676
|
+
.row {
|
|
677
|
+
display: inline-flex;
|
|
678
|
+
align-items: center;
|
|
679
|
+
gap: var(--input-gap-icon, 0.5rem);
|
|
680
|
+
cursor: pointer;
|
|
681
|
+
font-weight: 400;
|
|
682
|
+
}
|
|
683
|
+
.row:has(.control:disabled) {
|
|
684
|
+
cursor: not-allowed;
|
|
685
|
+
color: var(
|
|
686
|
+
--input-text-disabled,
|
|
687
|
+
var(--muted-foreground, oklch(0.556 0 0))
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
.control {
|
|
691
|
+
box-sizing: border-box;
|
|
692
|
+
width: var(--checkbox-size, 1.05rem);
|
|
693
|
+
height: var(--checkbox-size, 1.05rem);
|
|
694
|
+
margin: 0;
|
|
695
|
+
accent-color: var(--checkbox-accent, var(--primary, oklch(0.205 0 0)));
|
|
696
|
+
cursor: inherit;
|
|
697
|
+
}
|
|
698
|
+
.control:focus-visible {
|
|
699
|
+
outline: none;
|
|
700
|
+
border-radius: 0.25rem;
|
|
701
|
+
box-shadow: 0 0 0 var(--ring-width, 3px)
|
|
702
|
+
color-mix(in oklch, var(--ring, oklch(0.708 0 0)) 40%, transparent);
|
|
703
|
+
}
|
|
704
|
+
.label-text {
|
|
705
|
+
font-size: var(--input-font-size, 0.875rem);
|
|
706
|
+
color: var(--input-text, var(--foreground, oklch(0.145 0 0)));
|
|
707
|
+
}
|
|
708
|
+
`
|
|
709
|
+
];
|
|
710
|
+
}
|
|
711
|
+
get controlNoun() {
|
|
712
|
+
return "checkbox";
|
|
713
|
+
}
|
|
714
|
+
connectedCallback() {
|
|
715
|
+
this.defaultChecked = this.checked;
|
|
716
|
+
super.connectedCallback();
|
|
717
|
+
}
|
|
718
|
+
getFormValue() {
|
|
719
|
+
return this.checked ? this.value : null;
|
|
720
|
+
}
|
|
721
|
+
get validationValue() {
|
|
722
|
+
return this.checked;
|
|
723
|
+
}
|
|
724
|
+
get isEmpty() {
|
|
725
|
+
return !this.checked;
|
|
726
|
+
}
|
|
727
|
+
get requiredMessageDefault() {
|
|
728
|
+
return "Please check this box.";
|
|
729
|
+
}
|
|
730
|
+
toolInputSchema() {
|
|
731
|
+
return {
|
|
732
|
+
type: "object",
|
|
733
|
+
properties: {
|
|
734
|
+
checked: {
|
|
735
|
+
type: "boolean",
|
|
736
|
+
description: this.label || this.name || "Whether the box is checked."
|
|
737
|
+
}
|
|
738
|
+
},
|
|
739
|
+
required: ["checked"]
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
async applyAgentValue(args) {
|
|
743
|
+
this.checked = Boolean(args.checked);
|
|
744
|
+
await this.validate();
|
|
745
|
+
this.dispatchEvent(new Event("input", { bubbles: true, composed: true }));
|
|
746
|
+
this.dispatchEvent(new Event("change", { bubbles: true, composed: true }));
|
|
747
|
+
}
|
|
748
|
+
stateDescription() {
|
|
749
|
+
return this.checked ? "checked" : "unchecked";
|
|
750
|
+
}
|
|
751
|
+
formResetCallback() {
|
|
752
|
+
this.checked = this.defaultChecked;
|
|
753
|
+
this.error = "";
|
|
754
|
+
this.toggleAttribute("invalid", false);
|
|
755
|
+
void this.validate(false);
|
|
756
|
+
}
|
|
757
|
+
async onToggle(event) {
|
|
758
|
+
this.checked = event.target.checked;
|
|
759
|
+
await this.validate();
|
|
760
|
+
}
|
|
761
|
+
renderControl() {
|
|
762
|
+
return html5`
|
|
763
|
+
<input
|
|
764
|
+
id="control"
|
|
765
|
+
class="control"
|
|
766
|
+
part="control"
|
|
767
|
+
type="checkbox"
|
|
768
|
+
.checked=${this.checked}
|
|
769
|
+
?required=${this.required}
|
|
770
|
+
?disabled=${this.disabled}
|
|
771
|
+
aria-invalid=${this.error ? "true" : "false"}
|
|
772
|
+
aria-describedby=${this.describedBy ?? nothing5}
|
|
773
|
+
@change=${this.onToggle}
|
|
774
|
+
/>
|
|
775
|
+
`;
|
|
776
|
+
}
|
|
777
|
+
render() {
|
|
778
|
+
return html5`
|
|
779
|
+
<label class="row">
|
|
780
|
+
${this.renderControl()}
|
|
781
|
+
${this.label ? html5`<span class="label-text">${this.label}</span>` : nothing5}
|
|
782
|
+
</label>
|
|
783
|
+
${this.renderMessage()}
|
|
784
|
+
`;
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
__decorateClass([
|
|
788
|
+
property5({ type: Boolean, reflect: true })
|
|
789
|
+
], WmcpCheckbox.prototype, "checked", 2);
|
|
790
|
+
|
|
791
|
+
// src/elements/radio.ts
|
|
792
|
+
import { html as html6, css as css6, nothing as nothing6 } from "lit";
|
|
793
|
+
import { property as property6, state as state3 } from "lit/decorators.js";
|
|
794
|
+
import { repeat as repeat2 } from "lit/directives/repeat.js";
|
|
795
|
+
var groupCounter = 0;
|
|
796
|
+
var WmcpRadio = class extends HTMLElement {
|
|
797
|
+
static {
|
|
798
|
+
this.tagName = "wmcp-radio";
|
|
799
|
+
}
|
|
800
|
+
get value() {
|
|
801
|
+
return this.getAttribute("value") ?? "";
|
|
802
|
+
}
|
|
803
|
+
get label() {
|
|
804
|
+
return this.getAttribute("label") ?? this.textContent?.trim() ?? "";
|
|
805
|
+
}
|
|
806
|
+
get disabled() {
|
|
807
|
+
return this.hasAttribute("disabled");
|
|
808
|
+
}
|
|
809
|
+
connectedCallback() {
|
|
810
|
+
this.style.display = "none";
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
var WmcpRadioGroup = class extends WmcpFormControl {
|
|
814
|
+
constructor() {
|
|
815
|
+
super(...arguments);
|
|
816
|
+
this.options = [];
|
|
817
|
+
this.resolvedOptions = [];
|
|
818
|
+
/** Internal name shared by the rendered inputs (groups them natively). */
|
|
819
|
+
this.groupName = `wmcp-radio-${++groupCounter}`;
|
|
820
|
+
}
|
|
821
|
+
static {
|
|
822
|
+
this.tagName = "wmcp-radio-group";
|
|
823
|
+
}
|
|
824
|
+
static {
|
|
825
|
+
this.styles = [
|
|
826
|
+
WmcpFormControl.styles,
|
|
827
|
+
css6`
|
|
828
|
+
.group-label {
|
|
829
|
+
font-size: var(--input-font-size-label, 0.875rem);
|
|
830
|
+
font-weight: var(--input-font-weight-label, 500);
|
|
831
|
+
color: var(--input-label, var(--foreground, oklch(0.145 0 0)));
|
|
832
|
+
}
|
|
833
|
+
.group {
|
|
834
|
+
display: flex;
|
|
835
|
+
flex-direction: column;
|
|
836
|
+
gap: var(--input-gap-label, 0.375rem);
|
|
837
|
+
}
|
|
838
|
+
.row {
|
|
839
|
+
display: inline-flex;
|
|
840
|
+
align-items: center;
|
|
841
|
+
gap: var(--input-gap-icon, 0.5rem);
|
|
842
|
+
cursor: pointer;
|
|
843
|
+
font-weight: 400;
|
|
844
|
+
}
|
|
845
|
+
.row:has(.control:disabled) {
|
|
846
|
+
cursor: not-allowed;
|
|
847
|
+
color: var(
|
|
848
|
+
--input-text-disabled,
|
|
849
|
+
var(--muted-foreground, oklch(0.556 0 0))
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
.control {
|
|
853
|
+
box-sizing: border-box;
|
|
854
|
+
width: var(--radio-size, 1.05rem);
|
|
855
|
+
height: var(--radio-size, 1.05rem);
|
|
856
|
+
margin: 0;
|
|
857
|
+
accent-color: var(--radio-accent, var(--primary, oklch(0.205 0 0)));
|
|
858
|
+
cursor: inherit;
|
|
859
|
+
}
|
|
860
|
+
.control:focus-visible {
|
|
861
|
+
outline: none;
|
|
862
|
+
border-radius: 50%;
|
|
863
|
+
box-shadow: 0 0 0 var(--ring-width, 3px)
|
|
864
|
+
color-mix(in oklch, var(--ring, oklch(0.708 0 0)) 40%, transparent);
|
|
865
|
+
}
|
|
866
|
+
.label-text {
|
|
867
|
+
font-size: var(--input-font-size, 0.875rem);
|
|
868
|
+
color: var(--input-text, var(--foreground, oklch(0.145 0 0)));
|
|
869
|
+
}
|
|
870
|
+
`
|
|
871
|
+
];
|
|
872
|
+
}
|
|
873
|
+
get controlNoun() {
|
|
874
|
+
return "radio";
|
|
875
|
+
}
|
|
876
|
+
connectedCallback() {
|
|
877
|
+
this.syncOptions();
|
|
878
|
+
super.connectedCallback();
|
|
879
|
+
this.optionObserver = new MutationObserver(() => this.syncOptions());
|
|
880
|
+
this.optionObserver.observe(this, { childList: true, subtree: true });
|
|
881
|
+
}
|
|
882
|
+
disconnectedCallback() {
|
|
883
|
+
super.disconnectedCallback();
|
|
884
|
+
this.optionObserver?.disconnect();
|
|
885
|
+
this.optionObserver = void 0;
|
|
886
|
+
}
|
|
887
|
+
willUpdate(changed) {
|
|
888
|
+
if (changed.has("options")) this.syncOptions();
|
|
889
|
+
}
|
|
890
|
+
updated(changed) {
|
|
891
|
+
super.updated(changed);
|
|
892
|
+
if (this.expose && changed.has("resolvedOptions")) {
|
|
893
|
+
this.registerTool();
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
syncOptions() {
|
|
897
|
+
this.resolvedOptions = this.options.length > 0 ? this.options : this.readDeclarativeOptions();
|
|
898
|
+
}
|
|
899
|
+
readDeclarativeOptions() {
|
|
900
|
+
return Array.from(this.querySelectorAll(":scope > wmcp-radio")).map(
|
|
901
|
+
(el) => ({
|
|
902
|
+
value: el.getAttribute("value") ?? "",
|
|
903
|
+
label: el.getAttribute("label") ?? el.textContent?.trim() ?? "",
|
|
904
|
+
disabled: el.hasAttribute("disabled")
|
|
905
|
+
})
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
toolInputSchema() {
|
|
909
|
+
return {
|
|
910
|
+
type: "object",
|
|
911
|
+
properties: {
|
|
912
|
+
value: {
|
|
913
|
+
type: "string",
|
|
914
|
+
enum: this.resolvedOptions.map((o) => o.value),
|
|
915
|
+
description: this.label || this.name || "The option value to select."
|
|
916
|
+
}
|
|
917
|
+
},
|
|
918
|
+
required: ["value"]
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
async onSelect(event) {
|
|
922
|
+
this.value = event.target.value;
|
|
923
|
+
await this.validate();
|
|
924
|
+
}
|
|
925
|
+
renderControl() {
|
|
926
|
+
return html6`
|
|
927
|
+
<div
|
|
928
|
+
class="group"
|
|
929
|
+
role="radiogroup"
|
|
930
|
+
aria-labelledby=${this.label ? "group-label" : nothing6}
|
|
931
|
+
aria-describedby=${this.describedBy ?? nothing6}
|
|
932
|
+
aria-invalid=${this.error ? "true" : "false"}
|
|
933
|
+
>
|
|
934
|
+
${repeat2(
|
|
935
|
+
this.resolvedOptions,
|
|
936
|
+
(o) => o.value,
|
|
937
|
+
(o) => html6`
|
|
938
|
+
<label class="row">
|
|
939
|
+
<input
|
|
940
|
+
type="radio"
|
|
941
|
+
class="control"
|
|
942
|
+
part="control"
|
|
943
|
+
name=${this.groupName}
|
|
944
|
+
value=${o.value}
|
|
945
|
+
?disabled=${o.disabled ?? this.disabled}
|
|
946
|
+
.checked=${o.value === this.value}
|
|
947
|
+
@change=${this.onSelect}
|
|
948
|
+
/>
|
|
949
|
+
<span class="label-text">${o.label}</span>
|
|
950
|
+
</label>
|
|
951
|
+
`
|
|
952
|
+
)}
|
|
953
|
+
</div>
|
|
954
|
+
`;
|
|
955
|
+
}
|
|
956
|
+
render() {
|
|
957
|
+
return html6`
|
|
958
|
+
${this.label ? html6`<span id="group-label" class="group-label">${this.label}</span>` : nothing6}
|
|
959
|
+
${this.renderControl()}
|
|
960
|
+
${this.renderMessage()}
|
|
961
|
+
`;
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
__decorateClass([
|
|
965
|
+
property6({ attribute: false })
|
|
966
|
+
], WmcpRadioGroup.prototype, "options", 2);
|
|
967
|
+
__decorateClass([
|
|
968
|
+
state3()
|
|
969
|
+
], WmcpRadioGroup.prototype, "resolvedOptions", 2);
|
|
970
|
+
|
|
971
|
+
// src/register.ts
|
|
972
|
+
var elements = [
|
|
973
|
+
WmcpInput,
|
|
974
|
+
WmcpTextarea,
|
|
975
|
+
WmcpSelect,
|
|
976
|
+
WmcpCheckbox,
|
|
977
|
+
WmcpRadio,
|
|
978
|
+
WmcpRadioGroup
|
|
979
|
+
];
|
|
980
|
+
function defineComponents() {
|
|
981
|
+
if (typeof customElements === "undefined") return;
|
|
982
|
+
for (const ctor of elements) {
|
|
983
|
+
if (!customElements.get(ctor.tagName)) {
|
|
984
|
+
customElements.define(ctor.tagName, ctor);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
export {
|
|
989
|
+
WmcpCheckbox,
|
|
990
|
+
WmcpFormControl,
|
|
991
|
+
WmcpInput,
|
|
992
|
+
WmcpRadio,
|
|
993
|
+
WmcpRadioGroup,
|
|
994
|
+
WmcpSelect,
|
|
995
|
+
WmcpTextarea,
|
|
996
|
+
defineComponents,
|
|
997
|
+
exposeTool,
|
|
998
|
+
isStandardSchema,
|
|
999
|
+
isWebMCPAvailable,
|
|
1000
|
+
textFieldStyles,
|
|
1001
|
+
validateStandard
|
|
1002
|
+
};
|