@webmcpui/core 0.1.1 → 0.2.0

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.js CHANGED
@@ -4,12 +4,11 @@ import {
4
4
 
5
5
  // src/elements/form-control.ts
6
6
  import {
7
- LitElement,
8
7
  html,
9
8
  css,
10
9
  nothing
11
10
  } from "lit";
12
- import { property, state } from "lit/decorators.js";
11
+ import { property as property2, state } from "lit/decorators.js";
13
12
 
14
13
  // src/standard-schema.ts
15
14
  async function validateStandard(schema, value) {
@@ -23,6 +22,10 @@ function isStandardSchema(value) {
23
22
  return typeof value === "object" && value !== null && "~standard" in value && typeof value["~standard"]?.validate === "function";
24
23
  }
25
24
 
25
+ // src/elements/exposable.ts
26
+ import { LitElement } from "lit";
27
+ import { property } from "lit/decorators.js";
28
+
26
29
  // src/webmcp.ts
27
30
  function getModelContext() {
28
31
  const fromDocument = typeof document !== "undefined" ? document.modelContext : void 0;
@@ -73,6 +76,67 @@ function exposeTool(definition) {
73
76
  };
74
77
  }
75
78
 
79
+ // src/elements/exposable.ts
80
+ var WmcpExposable = class extends LitElement {
81
+ constructor() {
82
+ super(...arguments);
83
+ this.expose = false;
84
+ this.toolName = "";
85
+ this.toolDescription = "";
86
+ this.toolDisposer = () => {
87
+ };
88
+ }
89
+ /** JSON Schema for the tool's args. Defaults to a no-argument tool. */
90
+ toolInputSchema() {
91
+ return { type: "object", properties: {} };
92
+ }
93
+ /**
94
+ * Property changes that alter the tool's *identity* (name/description) and so
95
+ * require re-registration. State read live inside {@link executeTool} does
96
+ * not belong here. Subclasses extend this with their own naming inputs.
97
+ */
98
+ get toolReactiveProps() {
99
+ return ["expose", "toolName", "toolDescription"];
100
+ }
101
+ connectedCallback() {
102
+ super.connectedCallback();
103
+ if (this.expose) this.registerTool();
104
+ }
105
+ disconnectedCallback() {
106
+ super.disconnectedCallback();
107
+ this.toolDisposer();
108
+ this.toolDisposer = () => {
109
+ };
110
+ }
111
+ updated(changed) {
112
+ if (this.expose && this.toolReactiveProps.some((p) => changed.has(p))) {
113
+ this.registerTool();
114
+ } else if (!this.expose && changed.has("expose")) {
115
+ this.toolDisposer();
116
+ this.toolDisposer = () => {
117
+ };
118
+ }
119
+ }
120
+ registerTool() {
121
+ this.toolDisposer();
122
+ this.toolDisposer = exposeTool({
123
+ name: this.resolvedToolName,
124
+ description: this.toolDescription || this.defaultToolDescription,
125
+ inputSchema: this.toolInputSchema(),
126
+ execute: (args) => this.executeTool(args)
127
+ });
128
+ }
129
+ };
130
+ __decorateClass([
131
+ property({ type: Boolean })
132
+ ], WmcpExposable.prototype, "expose", 2);
133
+ __decorateClass([
134
+ property({ attribute: "tool-name" })
135
+ ], WmcpExposable.prototype, "toolName", 2);
136
+ __decorateClass([
137
+ property({ attribute: "tool-description" })
138
+ ], WmcpExposable.prototype, "toolDescription", 2);
139
+
76
140
  // src/elements/form-control.ts
77
141
  var textFieldStyles = css`
78
142
  .control {
@@ -116,7 +180,7 @@ var textFieldStyles = css`
116
180
  );
117
181
  }
118
182
  `;
119
- var WmcpFormControl = class extends LitElement {
183
+ var WmcpFormControl = class extends WmcpExposable {
120
184
  constructor() {
121
185
  super(...arguments);
122
186
  this.label = "";
@@ -127,13 +191,8 @@ var WmcpFormControl = class extends LitElement {
127
191
  this.disabled = false;
128
192
  this.helperText = "";
129
193
  this.requiredMessage = "";
130
- this.expose = false;
131
- this.toolName = "";
132
- this.toolDescription = "";
133
194
  this.error = "";
134
195
  this.internals = this.attachInternals();
135
- this.toolDisposer = () => {
136
- };
137
196
  /** Reveal the validation message when the form reports validity (submit). */
138
197
  this.onInvalid = () => {
139
198
  this.error = this.internals.validationMessage;
@@ -198,7 +257,6 @@ var WmcpFormControl = class extends LitElement {
198
257
  this.syncFormValue();
199
258
  this.addEventListener("invalid", this.onInvalid);
200
259
  void this.validate(false);
201
- if (this.expose) this.registerTool();
202
260
  }
203
261
  /**
204
262
  * The value contributed to the containing form. Defaults to the string
@@ -233,40 +291,32 @@ var WmcpFormControl = class extends LitElement {
233
291
  disconnectedCallback() {
234
292
  super.disconnectedCallback();
235
293
  this.removeEventListener("invalid", this.onInvalid);
236
- this.toolDisposer();
237
- this.toolDisposer = () => {
238
- };
239
294
  }
240
295
  updated(changed) {
296
+ super.updated(changed);
241
297
  this.syncFormValue();
242
- if (this.expose && (changed.has("expose") || changed.has("name") || changed.has("toolName") || changed.has("toolDescription"))) {
243
- this.registerTool();
244
- }
245
298
  }
246
- /** The resolved WebMCP tool name. */
247
299
  get resolvedToolName() {
248
300
  return this.toolName || `fill_${this.name || this.controlNoun}`;
249
301
  }
250
- registerTool() {
251
- this.toolDisposer();
302
+ get defaultToolDescription() {
303
+ return `Set the value of the "${this.label || this.name || this.controlNoun}" field.`;
304
+ }
305
+ get toolReactiveProps() {
306
+ return [...super.toolReactiveProps, "name"];
307
+ }
308
+ async executeTool(args) {
252
309
  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
- });
310
+ await this.applyAgentValue(args);
311
+ return {
312
+ content: [
313
+ {
314
+ type: "text",
315
+ text: this.error ? `Set "${noun}" but validation failed: ${this.error}` : `Set "${noun}" to "${this.stateDescription()}".`
316
+ }
317
+ ],
318
+ isError: Boolean(this.error)
319
+ };
270
320
  }
271
321
  /**
272
322
  * Apply the agent's tool arguments to component state. Defaults to treating
@@ -370,48 +420,43 @@ var WmcpFormControl = class extends LitElement {
370
420
  }
371
421
  };
372
422
  __decorateClass([
373
- property()
423
+ property2()
374
424
  ], WmcpFormControl.prototype, "label", 2);
375
425
  __decorateClass([
376
- property()
426
+ property2()
377
427
  ], WmcpFormControl.prototype, "name", 2);
378
428
  __decorateClass([
379
- property()
429
+ property2()
380
430
  ], WmcpFormControl.prototype, "value", 2);
381
431
  __decorateClass([
382
- property()
432
+ property2()
383
433
  ], WmcpFormControl.prototype, "placeholder", 2);
384
434
  __decorateClass([
385
- property({ type: Boolean, reflect: true })
435
+ property2({ type: Boolean, reflect: true })
386
436
  ], WmcpFormControl.prototype, "required", 2);
387
437
  __decorateClass([
388
- property({ type: Boolean, reflect: true })
438
+ property2({ type: Boolean, reflect: true })
389
439
  ], WmcpFormControl.prototype, "disabled", 2);
390
440
  __decorateClass([
391
- property({ attribute: "helper-text" })
441
+ property2({ attribute: "helper-text" })
392
442
  ], WmcpFormControl.prototype, "helperText", 2);
393
443
  __decorateClass([
394
- property({ attribute: "required-message" })
444
+ property2({ attribute: "required-message" })
395
445
  ], WmcpFormControl.prototype, "requiredMessage", 2);
396
446
  __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 })
447
+ property2({ attribute: false })
407
448
  ], WmcpFormControl.prototype, "schema", 2);
408
449
  __decorateClass([
409
450
  state()
410
451
  ], WmcpFormControl.prototype, "error", 2);
411
452
 
412
453
  // 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";
454
+ import {
455
+ html as html2,
456
+ css as css2,
457
+ nothing as nothing2
458
+ } from "lit";
459
+ import { property as property3 } from "lit/decorators.js";
415
460
  var WmcpInput = class extends WmcpFormControl {
416
461
  constructor() {
417
462
  super(...arguments);
@@ -466,12 +511,16 @@ var WmcpInput = class extends WmcpFormControl {
466
511
  }
467
512
  };
468
513
  __decorateClass([
469
- property2()
514
+ property3()
470
515
  ], WmcpInput.prototype, "type", 2);
471
516
 
472
517
  // 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";
518
+ import {
519
+ html as html3,
520
+ css as css3,
521
+ nothing as nothing3
522
+ } from "lit";
523
+ import { property as property4 } from "lit/decorators.js";
475
524
  var WmcpTextarea = class extends WmcpFormControl {
476
525
  constructor() {
477
526
  super(...arguments);
@@ -514,12 +563,16 @@ var WmcpTextarea = class extends WmcpFormControl {
514
563
  }
515
564
  };
516
565
  __decorateClass([
517
- property3({ type: Number })
566
+ property4({ type: Number })
518
567
  ], WmcpTextarea.prototype, "rows", 2);
519
568
 
520
569
  // 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";
570
+ import {
571
+ html as html4,
572
+ css as css4,
573
+ nothing as nothing4
574
+ } from "lit";
575
+ import { property as property5, state as state2 } from "lit/decorators.js";
523
576
  import { repeat } from "lit/directives/repeat.js";
524
577
  function isGroup(item) {
525
578
  return Array.isArray(item.options);
@@ -650,15 +703,19 @@ var WmcpSelect = class extends WmcpFormControl {
650
703
  }
651
704
  };
652
705
  __decorateClass([
653
- property4({ attribute: false })
706
+ property5({ attribute: false })
654
707
  ], WmcpSelect.prototype, "options", 2);
655
708
  __decorateClass([
656
709
  state2()
657
710
  ], WmcpSelect.prototype, "resolvedOptions", 2);
658
711
 
659
712
  // 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";
713
+ import {
714
+ html as html5,
715
+ css as css5,
716
+ nothing as nothing5
717
+ } from "lit";
718
+ import { property as property6 } from "lit/decorators.js";
662
719
  var WmcpCheckbox = class extends WmcpFormControl {
663
720
  constructor() {
664
721
  super();
@@ -785,12 +842,16 @@ var WmcpCheckbox = class extends WmcpFormControl {
785
842
  }
786
843
  };
787
844
  __decorateClass([
788
- property5({ type: Boolean, reflect: true })
845
+ property6({ type: Boolean, reflect: true })
789
846
  ], WmcpCheckbox.prototype, "checked", 2);
790
847
 
791
848
  // 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";
849
+ import {
850
+ html as html6,
851
+ css as css6,
852
+ nothing as nothing6
853
+ } from "lit";
854
+ import { property as property7, state as state3 } from "lit/decorators.js";
794
855
  import { repeat as repeat2 } from "lit/directives/repeat.js";
795
856
  var groupCounter = 0;
796
857
  var WmcpRadio = class extends HTMLElement {
@@ -962,20 +1023,1553 @@ var WmcpRadioGroup = class extends WmcpFormControl {
962
1023
  }
963
1024
  };
964
1025
  __decorateClass([
965
- property6({ attribute: false })
1026
+ property7({ attribute: false })
966
1027
  ], WmcpRadioGroup.prototype, "options", 2);
967
1028
  __decorateClass([
968
1029
  state3()
969
1030
  ], WmcpRadioGroup.prototype, "resolvedOptions", 2);
970
1031
 
971
- // src/register.ts
972
- var elements = [
973
- WmcpInput,
974
- WmcpTextarea,
975
- WmcpSelect,
976
- WmcpCheckbox,
977
- WmcpRadio,
978
- WmcpRadioGroup
1032
+ // src/elements/action.ts
1033
+ import { property as property8 } from "lit/decorators.js";
1034
+ var WmcpAction = class extends WmcpExposable {
1035
+ constructor() {
1036
+ super(...arguments);
1037
+ this.name = "";
1038
+ this.label = "";
1039
+ }
1040
+ /** Suffix for the default tool name when `name` is empty. */
1041
+ get defaultNameSuffix() {
1042
+ return "element";
1043
+ }
1044
+ /** Human-readable noun for the thing being acted on. */
1045
+ get actionNoun() {
1046
+ return this.label || this.name || this.defaultNameSuffix;
1047
+ }
1048
+ get resolvedToolName() {
1049
+ return this.toolName || `${this.actionVerb}_${this.name || this.defaultNameSuffix}`;
1050
+ }
1051
+ get defaultToolDescription() {
1052
+ return `Activate the "${this.actionNoun}".`;
1053
+ }
1054
+ get toolReactiveProps() {
1055
+ return [...super.toolReactiveProps, "name", "label"];
1056
+ }
1057
+ };
1058
+ __decorateClass([
1059
+ property8()
1060
+ ], WmcpAction.prototype, "name", 2);
1061
+ __decorateClass([
1062
+ property8()
1063
+ ], WmcpAction.prototype, "label", 2);
1064
+
1065
+ // src/elements/button.ts
1066
+ import {
1067
+ LitElement as LitElement2,
1068
+ html as html7,
1069
+ css as css7,
1070
+ nothing as nothing7
1071
+ } from "lit";
1072
+ import { property as property9 } from "lit/decorators.js";
1073
+ var WmcpButton = class extends WmcpAction {
1074
+ constructor() {
1075
+ super(...arguments);
1076
+ this.variant = "primary";
1077
+ this.size = "md";
1078
+ this.type = "button";
1079
+ this.disabled = false;
1080
+ this.internals = this.attachInternals();
1081
+ }
1082
+ static {
1083
+ this.tagName = "wmcp-button";
1084
+ }
1085
+ static {
1086
+ this.formAssociated = true;
1087
+ }
1088
+ static {
1089
+ // Delegate focus to the inner native button so the host is keyboard- and
1090
+ // agent-focusable and `:focus-visible` lands on the real control.
1091
+ this.shadowRootOptions = {
1092
+ ...LitElement2.shadowRootOptions,
1093
+ delegatesFocus: true
1094
+ };
1095
+ }
1096
+ static {
1097
+ this.styles = css7`
1098
+ :host {
1099
+ display: inline-block;
1100
+ font-family: var(
1101
+ --button-font-family,
1102
+ var(--input-font-family, ui-sans-serif, system-ui, sans-serif)
1103
+ );
1104
+ }
1105
+ :host([hidden]) {
1106
+ display: none;
1107
+ }
1108
+ .control {
1109
+ box-sizing: border-box;
1110
+ display: inline-flex;
1111
+ align-items: center;
1112
+ justify-content: center;
1113
+ gap: var(--button-gap, 0.5rem);
1114
+ width: 100%;
1115
+ font-family: inherit;
1116
+ font-size: var(--button-font-size, 0.875rem);
1117
+ font-weight: var(--button-font-weight, 500);
1118
+ line-height: 1;
1119
+ white-space: nowrap;
1120
+ cursor: pointer;
1121
+ user-select: none;
1122
+ border: var(--button-border-width, 1px) solid transparent;
1123
+ border-radius: var(--button-radius, var(--radius, 0.625rem));
1124
+ transition: background-color var(--button-transition-duration, 150ms)
1125
+ var(--button-transition-easing, cubic-bezier(0.4, 0, 0.2, 1)),
1126
+ color var(--button-transition-duration, 150ms)
1127
+ var(--button-transition-easing, cubic-bezier(0.4, 0, 0.2, 1)),
1128
+ border-color var(--button-transition-duration, 150ms)
1129
+ var(--button-transition-easing, cubic-bezier(0.4, 0, 0.2, 1)),
1130
+ box-shadow var(--button-transition-duration, 150ms)
1131
+ var(--button-transition-easing, cubic-bezier(0.4, 0, 0.2, 1));
1132
+ }
1133
+ /* Sizes */
1134
+ :host([size='sm']) .control {
1135
+ height: var(--button-height-sm, 2rem);
1136
+ padding-inline: var(--button-padding-x-sm, 0.75rem);
1137
+ }
1138
+ .control {
1139
+ height: var(--button-height-md, 2.25rem);
1140
+ padding-inline: var(--button-padding-x-md, 1rem);
1141
+ }
1142
+ :host([size='lg']) .control {
1143
+ height: var(--button-height-lg, 2.5rem);
1144
+ padding-inline: var(--button-padding-x-lg, 1.5rem);
1145
+ }
1146
+ /* Primary (default) */
1147
+ .control {
1148
+ color: var(--button-primary-text, var(--primary-foreground, oklch(0.985 0 0)));
1149
+ background: var(--button-primary-bg, var(--primary, oklch(0.205 0 0)));
1150
+ }
1151
+ .control:hover:not(:disabled) {
1152
+ background: var(
1153
+ --button-primary-bg-hover,
1154
+ color-mix(in oklch, var(--primary, oklch(0.205 0 0)) 90%, transparent)
1155
+ );
1156
+ }
1157
+ /* Secondary */
1158
+ :host([variant='secondary']) .control {
1159
+ color: var(--button-secondary-text, var(--secondary-foreground, oklch(0.205 0 0)));
1160
+ background: var(--button-secondary-bg, var(--secondary, oklch(0.97 0 0)));
1161
+ }
1162
+ :host([variant='secondary']) .control:hover:not(:disabled) {
1163
+ background: var(
1164
+ --button-secondary-bg-hover,
1165
+ color-mix(in oklch, var(--secondary, oklch(0.97 0 0)) 80%, var(--foreground, oklch(0.145 0 0)))
1166
+ );
1167
+ }
1168
+ /* Destructive */
1169
+ :host([variant='destructive']) .control {
1170
+ color: var(--button-destructive-text, var(--destructive-foreground, oklch(0.985 0 0)));
1171
+ background: var(--button-destructive-bg, var(--destructive, oklch(0.577 0.245 27.325)));
1172
+ }
1173
+ :host([variant='destructive']) .control:hover:not(:disabled) {
1174
+ background: var(
1175
+ --button-destructive-bg-hover,
1176
+ color-mix(in oklch, var(--destructive, oklch(0.577 0.245 27.325)) 90%, transparent)
1177
+ );
1178
+ }
1179
+ /* Outline */
1180
+ :host([variant='outline']) .control {
1181
+ color: var(--button-outline-text, var(--foreground, oklch(0.145 0 0)));
1182
+ background: var(--button-outline-bg, var(--background, oklch(1 0 0)));
1183
+ border-color: var(--button-outline-border, var(--border, oklch(0.922 0 0)));
1184
+ }
1185
+ :host([variant='outline']) .control:hover:not(:disabled) {
1186
+ background: var(--button-outline-bg-hover, var(--accent, oklch(0.97 0 0)));
1187
+ color: var(--button-outline-text-hover, var(--accent-foreground, oklch(0.205 0 0)));
1188
+ }
1189
+ /* Ghost */
1190
+ :host([variant='ghost']) .control {
1191
+ color: var(--button-ghost-text, var(--foreground, oklch(0.145 0 0)));
1192
+ background: transparent;
1193
+ }
1194
+ :host([variant='ghost']) .control:hover:not(:disabled) {
1195
+ background: var(--button-ghost-bg-hover, var(--accent, oklch(0.97 0 0)));
1196
+ color: var(--button-ghost-text-hover, var(--accent-foreground, oklch(0.205 0 0)));
1197
+ }
1198
+ /* Focus + disabled (shared across variants) */
1199
+ .control:focus-visible {
1200
+ outline: none;
1201
+ box-shadow: 0 0 0 var(--ring-width, 3px)
1202
+ color-mix(in oklch, var(--ring, oklch(0.708 0 0)) 40%, transparent);
1203
+ }
1204
+ .control:disabled {
1205
+ opacity: var(--button-disabled-opacity, 0.5);
1206
+ cursor: not-allowed;
1207
+ }
1208
+ `;
1209
+ }
1210
+ /** The inner native `<button>` that owns activation, focus, and a11y. */
1211
+ get button() {
1212
+ return this.renderRoot?.querySelector("button") ?? null;
1213
+ }
1214
+ // --- WmcpAction hooks ---------------------------------------------------
1215
+ get actionVerb() {
1216
+ return "click";
1217
+ }
1218
+ get defaultNameSuffix() {
1219
+ return "button";
1220
+ }
1221
+ // A button's visible name is its slotted text, so fall back to that.
1222
+ get actionNoun() {
1223
+ return this.label || this.textContent?.trim() || this.name || "button";
1224
+ }
1225
+ get defaultToolDescription() {
1226
+ return `Click the "${this.actionNoun}" button.`;
1227
+ }
1228
+ executeTool() {
1229
+ const noun = this.actionNoun;
1230
+ if (this.disabled) {
1231
+ return {
1232
+ content: [
1233
+ {
1234
+ type: "text",
1235
+ text: `The "${noun}" button is disabled and can't be activated.`
1236
+ }
1237
+ ],
1238
+ isError: true
1239
+ };
1240
+ }
1241
+ this.activate();
1242
+ const effect = this.type === "submit" ? " (submitted the form)" : this.type === "reset" ? " (reset the form)" : "";
1243
+ return {
1244
+ content: [
1245
+ { type: "text", text: `Clicked the "${noun}" button${effect}.` }
1246
+ ]
1247
+ };
1248
+ }
1249
+ // --- Activation ---------------------------------------------------------
1250
+ /**
1251
+ * Activate the button as if a human clicked it: routes through the inner
1252
+ * native button so light-DOM `click` handlers fire and `type`-driven form
1253
+ * submission/reset happens. A no-op when disabled.
1254
+ */
1255
+ activate() {
1256
+ this.button?.click();
1257
+ }
1258
+ /**
1259
+ * Inner-button click handler. The native click already bubbles (composed) to
1260
+ * the host, so light-DOM listeners fire without help; this only adds the
1261
+ * cross-shadow form behavior a native submit/reset button can't do from here.
1262
+ */
1263
+ onInnerClick() {
1264
+ if (this.disabled) return;
1265
+ if (this.type === "submit") {
1266
+ this.internals.form?.requestSubmit();
1267
+ } else if (this.type === "reset") {
1268
+ this.internals.form?.reset();
1269
+ }
1270
+ }
1271
+ render() {
1272
+ return html7`
1273
+ <button
1274
+ class="control"
1275
+ part="control"
1276
+ type="button"
1277
+ ?disabled=${this.disabled}
1278
+ aria-label=${this.label || nothing7}
1279
+ @click=${this.onInnerClick}
1280
+ >
1281
+ <slot></slot>
1282
+ </button>
1283
+ `;
1284
+ }
1285
+ };
1286
+ __decorateClass([
1287
+ property9({ reflect: true })
1288
+ ], WmcpButton.prototype, "variant", 2);
1289
+ __decorateClass([
1290
+ property9({ reflect: true })
1291
+ ], WmcpButton.prototype, "size", 2);
1292
+ __decorateClass([
1293
+ property9()
1294
+ ], WmcpButton.prototype, "type", 2);
1295
+ __decorateClass([
1296
+ property9({ type: Boolean, reflect: true })
1297
+ ], WmcpButton.prototype, "disabled", 2);
1298
+
1299
+ // src/elements/dialog.ts
1300
+ import {
1301
+ html as html8,
1302
+ css as css8
1303
+ } from "lit";
1304
+ import { property as property10 } from "lit/decorators.js";
1305
+ var WmcpDialog = class extends WmcpAction {
1306
+ constructor() {
1307
+ super(...arguments);
1308
+ this.open = false;
1309
+ this.modal = true;
1310
+ this.staticBackdrop = false;
1311
+ /** Last `returnValue` the dialog closed with (mirrors native `<dialog>`). */
1312
+ this.returnValue = "";
1313
+ }
1314
+ static {
1315
+ this.tagName = "wmcp-dialog";
1316
+ }
1317
+ static {
1318
+ this.styles = css8`
1319
+ :host {
1320
+ display: contents;
1321
+ }
1322
+ dialog {
1323
+ box-sizing: border-box;
1324
+ width: var(--dialog-width, min(92vw, 32rem));
1325
+ max-width: var(--dialog-max-width, 32rem);
1326
+ max-height: var(--dialog-max-height, 85dvh);
1327
+ color: var(--dialog-text, var(--popover-foreground, oklch(0.145 0 0)));
1328
+ background: var(--dialog-bg, var(--popover, oklch(1 0 0)));
1329
+ border: var(--dialog-border-width, 1px) solid
1330
+ var(--dialog-border, var(--border, oklch(0.922 0 0)));
1331
+ border-radius: var(--dialog-radius, var(--radius, 0.625rem));
1332
+ box-shadow: var(
1333
+ --dialog-shadow,
1334
+ 0 10px 38px -10px color-mix(in oklch, oklch(0 0 0) 35%, transparent),
1335
+ 0 10px 20px -15px color-mix(in oklch, oklch(0 0 0) 20%, transparent)
1336
+ );
1337
+ font-family: var(
1338
+ --dialog-font-family,
1339
+ ui-sans-serif,
1340
+ system-ui,
1341
+ sans-serif
1342
+ );
1343
+ overflow: auto;
1344
+ }
1345
+ dialog::backdrop {
1346
+ background: var(
1347
+ --dialog-backdrop,
1348
+ color-mix(in oklch, oklch(0 0 0) 50%, transparent)
1349
+ );
1350
+ }
1351
+ /* Padding lives on the panel, not the dialog, so the dialog's box is the
1352
+ panel's box — a click whose target is the <dialog> is unambiguously the
1353
+ backdrop, never the dialog's own visible frame. */
1354
+ .panel {
1355
+ padding: var(--dialog-padding, 1.5rem);
1356
+ }
1357
+ /* Modern-CSS entrance: fade + lift, honoring reduced-motion. */
1358
+ @media (prefers-reduced-motion: no-preference) {
1359
+ dialog,
1360
+ dialog::backdrop {
1361
+ transition: opacity var(--dialog-transition-duration, 180ms)
1362
+ var(--dialog-transition-easing, cubic-bezier(0.4, 0, 0.2, 1)),
1363
+ translate var(--dialog-transition-duration, 180ms)
1364
+ var(--dialog-transition-easing, cubic-bezier(0.4, 0, 0.2, 1)),
1365
+ overlay var(--dialog-transition-duration, 180ms) allow-discrete,
1366
+ display var(--dialog-transition-duration, 180ms) allow-discrete;
1367
+ }
1368
+ dialog:not([open]),
1369
+ dialog:not([open])::backdrop {
1370
+ opacity: 0;
1371
+ }
1372
+ dialog:not([open]) {
1373
+ translate: 0 0.5rem;
1374
+ }
1375
+ @starting-style {
1376
+ dialog[open],
1377
+ dialog[open]::backdrop {
1378
+ opacity: 0;
1379
+ }
1380
+ dialog[open] {
1381
+ translate: 0 0.5rem;
1382
+ }
1383
+ }
1384
+ }
1385
+ `;
1386
+ }
1387
+ get dialogEl() {
1388
+ return this.renderRoot?.querySelector("dialog") ?? null;
1389
+ }
1390
+ // --- WmcpAction hooks ---------------------------------------------------
1391
+ get actionVerb() {
1392
+ return "open";
1393
+ }
1394
+ get defaultNameSuffix() {
1395
+ return "dialog";
1396
+ }
1397
+ get defaultToolDescription() {
1398
+ return `Open the "${this.actionNoun}" dialog for the user to review.`;
1399
+ }
1400
+ executeTool() {
1401
+ const noun = this.actionNoun;
1402
+ if (this.open) {
1403
+ return {
1404
+ content: [
1405
+ { type: "text", text: `The "${noun}" dialog is already open.` }
1406
+ ]
1407
+ };
1408
+ }
1409
+ this.show();
1410
+ return {
1411
+ content: [
1412
+ {
1413
+ type: "text",
1414
+ text: `Opened the "${noun}" dialog for the user to review.`
1415
+ }
1416
+ ]
1417
+ };
1418
+ }
1419
+ // --- Open / close -------------------------------------------------------
1420
+ updated(changed) {
1421
+ super.updated(changed);
1422
+ if (changed.has("open")) this.syncNativeOpen();
1423
+ }
1424
+ /** Open the dialog (modal unless `modal` is false). */
1425
+ show() {
1426
+ this.open = true;
1427
+ }
1428
+ /** Close the dialog, optionally recording a `returnValue`. */
1429
+ close(returnValue) {
1430
+ if (returnValue !== void 0) this.returnValue = returnValue;
1431
+ this.open = false;
1432
+ }
1433
+ /** Reconcile our `open` state with the native dialog's imperative API. */
1434
+ syncNativeOpen() {
1435
+ const d = this.dialogEl;
1436
+ if (!d) return;
1437
+ if (this.open && !d.open) {
1438
+ if (this.modal) d.showModal();
1439
+ else d.show();
1440
+ this.dispatchEvent(new Event("open", { bubbles: true, composed: true }));
1441
+ } else if (!this.open && d.open) {
1442
+ d.close(this.returnValue);
1443
+ }
1444
+ }
1445
+ /** Native `close` fires for Escape, backdrop, or our own `close()`. */
1446
+ onNativeClose() {
1447
+ this.returnValue = this.dialogEl?.returnValue ?? this.returnValue;
1448
+ if (this.open) this.open = false;
1449
+ this.dispatchEvent(new Event("close", { bubbles: true, composed: true }));
1450
+ }
1451
+ /**
1452
+ * Close on a backdrop click. A click whose target is the `<dialog>` itself
1453
+ * is the backdrop — content clicks retarget to `.panel` or its children — so
1454
+ * this never fires on the dialog's own frame or a text drag-select.
1455
+ */
1456
+ onDialogClick(event) {
1457
+ if (this.staticBackdrop) return;
1458
+ if (event.target === this.dialogEl) this.close();
1459
+ }
1460
+ render() {
1461
+ return html8`
1462
+ <dialog
1463
+ part="dialog"
1464
+ aria-label=${this.label || this.actionNoun}
1465
+ @close=${this.onNativeClose}
1466
+ @click=${this.onDialogClick}
1467
+ >
1468
+ <div class="panel" part="panel">
1469
+ <slot></slot>
1470
+ </div>
1471
+ </dialog>
1472
+ `;
1473
+ }
1474
+ };
1475
+ __decorateClass([
1476
+ property10({ type: Boolean, reflect: true })
1477
+ ], WmcpDialog.prototype, "open", 2);
1478
+ __decorateClass([
1479
+ property10({ type: Boolean })
1480
+ ], WmcpDialog.prototype, "modal", 2);
1481
+ __decorateClass([
1482
+ property10({ type: Boolean, attribute: "static-backdrop" })
1483
+ ], WmcpDialog.prototype, "staticBackdrop", 2);
1484
+
1485
+ // src/elements/menu.ts
1486
+ import {
1487
+ html as html9,
1488
+ css as css9,
1489
+ nothing as nothing8
1490
+ } from "lit";
1491
+ import { property as property11, state as state4 } from "lit/decorators.js";
1492
+ import { repeat as repeat3 } from "lit/directives/repeat.js";
1493
+ var WmcpMenu = class extends WmcpAction {
1494
+ constructor() {
1495
+ super(...arguments);
1496
+ this.label = "";
1497
+ this.items = [];
1498
+ this.open = false;
1499
+ this.resolvedItems = [];
1500
+ }
1501
+ static {
1502
+ this.tagName = "wmcp-menu";
1503
+ }
1504
+ static {
1505
+ this.styles = css9`
1506
+ :host {
1507
+ display: inline-block;
1508
+ font-family: var(
1509
+ --menu-font-family,
1510
+ var(--input-font-family, ui-sans-serif, system-ui, sans-serif)
1511
+ );
1512
+ }
1513
+ :host([hidden]) {
1514
+ display: none;
1515
+ }
1516
+ .trigger {
1517
+ box-sizing: border-box;
1518
+ display: inline-flex;
1519
+ align-items: center;
1520
+ gap: var(--menu-trigger-gap, 0.375rem);
1521
+ height: var(--menu-trigger-height, 2.25rem);
1522
+ padding-inline: var(--menu-trigger-padding-x, 1rem);
1523
+ font: inherit;
1524
+ font-size: var(--menu-font-size, 0.875rem);
1525
+ font-weight: var(--menu-trigger-font-weight, 500);
1526
+ color: var(--menu-trigger-text, var(--foreground, oklch(0.145 0 0)));
1527
+ background: var(--menu-trigger-bg, var(--background, oklch(1 0 0)));
1528
+ border: 1px solid var(--menu-trigger-border, var(--border, oklch(0.922 0 0)));
1529
+ border-radius: var(--menu-radius, var(--radius, 0.625rem));
1530
+ cursor: pointer;
1531
+ anchor-name: --wmcp-menu-anchor;
1532
+ }
1533
+ .trigger:hover {
1534
+ background: var(--menu-trigger-bg-hover, var(--accent, oklch(0.97 0 0)));
1535
+ }
1536
+ .trigger:focus-visible {
1537
+ outline: none;
1538
+ box-shadow: 0 0 0 var(--ring-width, 3px)
1539
+ color-mix(in oklch, var(--ring, oklch(0.708 0 0)) 40%, transparent);
1540
+ }
1541
+ .caret {
1542
+ width: 0.75rem;
1543
+ height: 0.75rem;
1544
+ transition: rotate 150ms cubic-bezier(0.4, 0, 0.2, 1);
1545
+ }
1546
+ .trigger[aria-expanded='true'] .caret {
1547
+ rotate: 180deg;
1548
+ }
1549
+ .menu {
1550
+ box-sizing: border-box;
1551
+ min-width: var(--menu-min-width, 11rem);
1552
+ margin: 0;
1553
+ padding: var(--menu-padding, 0.25rem);
1554
+ color: var(--menu-text, var(--popover-foreground, oklch(0.145 0 0)));
1555
+ background: var(--menu-bg, var(--popover, oklch(1 0 0)));
1556
+ border: 1px solid var(--menu-border, var(--border, oklch(0.922 0 0)));
1557
+ border-radius: var(--menu-radius, var(--radius, 0.625rem));
1558
+ box-shadow: var(
1559
+ --menu-shadow,
1560
+ 0 10px 38px -10px color-mix(in oklch, oklch(0 0 0) 35%, transparent)
1561
+ );
1562
+ /* Anchor the popover under the trigger; margin is the no-anchor fallback. */
1563
+ position-anchor: --wmcp-menu-anchor;
1564
+ inset: auto;
1565
+ top: anchor(bottom);
1566
+ left: anchor(left);
1567
+ margin-top: var(--menu-offset, 0.25rem);
1568
+ }
1569
+ @media (prefers-reduced-motion: no-preference) {
1570
+ .menu {
1571
+ transition: opacity 130ms ease, translate 130ms ease,
1572
+ overlay 130ms allow-discrete, display 130ms allow-discrete;
1573
+ }
1574
+ .menu:not(:popover-open) {
1575
+ opacity: 0;
1576
+ translate: 0 -0.25rem;
1577
+ }
1578
+ @starting-style {
1579
+ .menu:popover-open {
1580
+ opacity: 0;
1581
+ translate: 0 -0.25rem;
1582
+ }
1583
+ }
1584
+ }
1585
+ .item {
1586
+ display: flex;
1587
+ width: 100%;
1588
+ align-items: center;
1589
+ gap: var(--menu-item-gap, 0.5rem);
1590
+ padding: var(--menu-item-padding, 0.4rem 0.6rem);
1591
+ font: inherit;
1592
+ font-size: var(--menu-font-size, 0.875rem);
1593
+ color: inherit;
1594
+ text-align: start;
1595
+ background: transparent;
1596
+ border: 0;
1597
+ border-radius: var(--menu-item-radius, 0.4rem);
1598
+ cursor: pointer;
1599
+ }
1600
+ .item:hover:not(:disabled),
1601
+ .item:focus-visible {
1602
+ outline: none;
1603
+ background: var(--menu-item-bg-hover, var(--accent, oklch(0.97 0 0)));
1604
+ color: var(--menu-item-text-hover, var(--accent-foreground, oklch(0.205 0 0)));
1605
+ }
1606
+ .item:disabled {
1607
+ opacity: var(--menu-item-disabled-opacity, 0.5);
1608
+ cursor: not-allowed;
1609
+ }
1610
+ `;
1611
+ }
1612
+ get menuEl() {
1613
+ return this.renderRoot?.querySelector(".menu") ?? null;
1614
+ }
1615
+ get itemButtons() {
1616
+ return Array.from(
1617
+ this.renderRoot?.querySelectorAll(".item") ?? []
1618
+ );
1619
+ }
1620
+ // --- WmcpAction hooks ---------------------------------------------------
1621
+ get actionVerb() {
1622
+ return "select";
1623
+ }
1624
+ get defaultNameSuffix() {
1625
+ return "menu";
1626
+ }
1627
+ get actionNoun() {
1628
+ return this.label || this.name || "menu";
1629
+ }
1630
+ get defaultToolDescription() {
1631
+ return `Select an item from the "${this.actionNoun}" menu.`;
1632
+ }
1633
+ // Re-register the tool when the item set changes so its enum stays in sync.
1634
+ get toolReactiveProps() {
1635
+ return [...super.toolReactiveProps, "resolvedItems"];
1636
+ }
1637
+ toolInputSchema() {
1638
+ return {
1639
+ type: "object",
1640
+ properties: {
1641
+ item: {
1642
+ type: "string",
1643
+ enum: this.resolvedItems.filter((i) => !i.disabled).map((i) => i.value),
1644
+ description: `Which item to select from the "${this.actionNoun}" menu.`
1645
+ }
1646
+ },
1647
+ required: ["item"]
1648
+ };
1649
+ }
1650
+ executeTool(args) {
1651
+ const value = args.item == null ? "" : String(args.item);
1652
+ const item = this.resolvedItems.find((i) => i.value === value);
1653
+ if (!item) {
1654
+ return {
1655
+ content: [
1656
+ {
1657
+ type: "text",
1658
+ text: `No item "${value}" in the "${this.actionNoun}" menu.`
1659
+ }
1660
+ ],
1661
+ isError: true
1662
+ };
1663
+ }
1664
+ if (item.disabled) {
1665
+ return {
1666
+ content: [
1667
+ { type: "text", text: `The "${item.label}" item is disabled.` }
1668
+ ],
1669
+ isError: true
1670
+ };
1671
+ }
1672
+ this.selectItem(item);
1673
+ return {
1674
+ content: [
1675
+ {
1676
+ type: "text",
1677
+ text: `Selected "${item.label}" from the "${this.actionNoun}" menu.`
1678
+ }
1679
+ ]
1680
+ };
1681
+ }
1682
+ // --- Item model ---------------------------------------------------------
1683
+ connectedCallback() {
1684
+ this.syncItems();
1685
+ super.connectedCallback();
1686
+ this.itemObserver = new MutationObserver(() => this.syncItems());
1687
+ this.itemObserver.observe(this, { childList: true });
1688
+ }
1689
+ disconnectedCallback() {
1690
+ super.disconnectedCallback();
1691
+ this.itemObserver?.disconnect();
1692
+ this.itemObserver = void 0;
1693
+ }
1694
+ willUpdate(changed) {
1695
+ if (changed.has("items")) this.syncItems();
1696
+ }
1697
+ syncItems() {
1698
+ this.resolvedItems = this.items.length > 0 ? this.items : this.readDeclarativeItems();
1699
+ }
1700
+ readDeclarativeItems() {
1701
+ return Array.from(this.querySelectorAll("option")).map((o) => ({
1702
+ value: o.value,
1703
+ label: o.textContent?.trim() || o.value,
1704
+ disabled: o.disabled
1705
+ }));
1706
+ }
1707
+ // --- Selection + keyboard ----------------------------------------------
1708
+ /** Dispatch the selection and close the menu. */
1709
+ selectItem(item) {
1710
+ this.dispatchEvent(
1711
+ new CustomEvent("select", {
1712
+ detail: { value: item.value, label: item.label },
1713
+ bubbles: true,
1714
+ composed: true
1715
+ })
1716
+ );
1717
+ this.menuEl?.hidePopover();
1718
+ }
1719
+ onItemClick(item) {
1720
+ if (item.disabled) return;
1721
+ this.selectItem(item);
1722
+ }
1723
+ /** Sync `open`/`aria-expanded` and move focus into the menu when it opens. */
1724
+ onToggle(event) {
1725
+ this.open = event.newState === "open";
1726
+ if (this.open) {
1727
+ this.itemButtons.find((b) => !b.disabled)?.focus();
1728
+ }
1729
+ }
1730
+ /** Roving focus among items with the arrow / Home / End keys. */
1731
+ onMenuKeydown(event) {
1732
+ const buttons = this.itemButtons.filter((b) => !b.disabled);
1733
+ if (buttons.length === 0) return;
1734
+ const current = buttons.indexOf(
1735
+ this.shadowRoot?.activeElement
1736
+ );
1737
+ let next = -1;
1738
+ switch (event.key) {
1739
+ case "ArrowDown":
1740
+ next = current < 0 ? 0 : (current + 1) % buttons.length;
1741
+ break;
1742
+ case "ArrowUp":
1743
+ next = current <= 0 ? buttons.length - 1 : current - 1;
1744
+ break;
1745
+ case "Home":
1746
+ next = 0;
1747
+ break;
1748
+ case "End":
1749
+ next = buttons.length - 1;
1750
+ break;
1751
+ default:
1752
+ return;
1753
+ }
1754
+ event.preventDefault();
1755
+ buttons[next]?.focus();
1756
+ }
1757
+ render() {
1758
+ return html9`
1759
+ <button
1760
+ type="button"
1761
+ class="trigger"
1762
+ part="trigger"
1763
+ popovertarget="menu-pop"
1764
+ aria-haspopup="menu"
1765
+ aria-expanded=${this.open ? "true" : "false"}
1766
+ >
1767
+ <span>${this.label || "Menu"}</span>
1768
+ <svg class="caret" viewBox="0 0 16 16" aria-hidden="true">
1769
+ <path
1770
+ d="M4 6l4 4 4-4"
1771
+ fill="none"
1772
+ stroke="currentColor"
1773
+ stroke-width="1.5"
1774
+ stroke-linecap="round"
1775
+ stroke-linejoin="round"
1776
+ />
1777
+ </svg>
1778
+ </button>
1779
+ <div
1780
+ id="menu-pop"
1781
+ class="menu"
1782
+ part="menu"
1783
+ popover="auto"
1784
+ role="menu"
1785
+ aria-label=${this.label || "Menu"}
1786
+ @toggle=${this.onToggle}
1787
+ @keydown=${this.onMenuKeydown}
1788
+ >
1789
+ ${this.resolvedItems.length === 0 ? nothing8 : repeat3(
1790
+ this.resolvedItems,
1791
+ (item) => item.value,
1792
+ (item) => html9`
1793
+ <button
1794
+ type="button"
1795
+ class="item"
1796
+ role="menuitem"
1797
+ part="item"
1798
+ ?disabled=${item.disabled ?? false}
1799
+ @click=${() => this.onItemClick(item)}
1800
+ >
1801
+ ${item.label}
1802
+ </button>
1803
+ `
1804
+ )}
1805
+ </div>
1806
+ `;
1807
+ }
1808
+ };
1809
+ __decorateClass([
1810
+ property11()
1811
+ ], WmcpMenu.prototype, "label", 2);
1812
+ __decorateClass([
1813
+ property11({ attribute: false })
1814
+ ], WmcpMenu.prototype, "items", 2);
1815
+ __decorateClass([
1816
+ property11({ type: Boolean, reflect: true })
1817
+ ], WmcpMenu.prototype, "open", 2);
1818
+ __decorateClass([
1819
+ state4()
1820
+ ], WmcpMenu.prototype, "resolvedItems", 2);
1821
+
1822
+ // src/elements/tabs.ts
1823
+ import {
1824
+ html as html10,
1825
+ css as css10,
1826
+ nothing as nothing9
1827
+ } from "lit";
1828
+ import { property as property12, state as state5 } from "lit/decorators.js";
1829
+ import { repeat as repeat4 } from "lit/directives/repeat.js";
1830
+ var WmcpTabs = class extends WmcpAction {
1831
+ constructor() {
1832
+ super(...arguments);
1833
+ this.active = "";
1834
+ this.label = "";
1835
+ this.tabs = [];
1836
+ }
1837
+ static {
1838
+ this.tagName = "wmcp-tabs";
1839
+ }
1840
+ static {
1841
+ this.styles = css10`
1842
+ :host {
1843
+ display: block;
1844
+ font-family: var(
1845
+ --tabs-font-family,
1846
+ var(--input-font-family, ui-sans-serif, system-ui, sans-serif)
1847
+ );
1848
+ }
1849
+ :host([hidden]) {
1850
+ display: none;
1851
+ }
1852
+ [role='tablist'] {
1853
+ display: flex;
1854
+ gap: var(--tabs-gap, 0.25rem);
1855
+ border-bottom: 1px solid var(--tabs-border, var(--border, oklch(0.922 0 0)));
1856
+ }
1857
+ .tab {
1858
+ position: relative;
1859
+ appearance: none;
1860
+ border: 0;
1861
+ background: transparent;
1862
+ padding: var(--tabs-tab-padding, 0.5rem 0.875rem);
1863
+ margin-bottom: -1px;
1864
+ font: inherit;
1865
+ font-size: var(--tabs-font-size, 0.875rem);
1866
+ font-weight: var(--tabs-font-weight, 500);
1867
+ color: var(--tabs-tab-text, var(--muted-foreground, oklch(0.556 0 0)));
1868
+ cursor: pointer;
1869
+ border-bottom: 2px solid transparent;
1870
+ transition: color 150ms ease, border-color 150ms ease;
1871
+ }
1872
+ .tab:hover:not(:disabled) {
1873
+ color: var(--tabs-tab-text-hover, var(--foreground, oklch(0.145 0 0)));
1874
+ }
1875
+ .tab[aria-selected='true'] {
1876
+ color: var(--tabs-tab-text-active, var(--foreground, oklch(0.145 0 0)));
1877
+ border-bottom-color: var(--tabs-indicator, var(--primary, oklch(0.205 0 0)));
1878
+ }
1879
+ .tab:focus-visible {
1880
+ outline: none;
1881
+ border-radius: 0.375rem;
1882
+ box-shadow: 0 0 0 var(--ring-width, 3px)
1883
+ color-mix(in oklch, var(--ring, oklch(0.708 0 0)) 40%, transparent);
1884
+ }
1885
+ .tab:disabled {
1886
+ opacity: var(--tabs-tab-disabled-opacity, 0.5);
1887
+ cursor: not-allowed;
1888
+ }
1889
+ .panels {
1890
+ padding-top: var(--tabs-panel-padding-top, 1rem);
1891
+ }
1892
+ `;
1893
+ }
1894
+ // --- WmcpAction hooks ---------------------------------------------------
1895
+ get actionVerb() {
1896
+ return "switch";
1897
+ }
1898
+ get defaultNameSuffix() {
1899
+ return "tabs";
1900
+ }
1901
+ get actionNoun() {
1902
+ return this.label || this.name || "tabs";
1903
+ }
1904
+ get defaultToolDescription() {
1905
+ return `Switch the active tab in the "${this.actionNoun}" tabs.`;
1906
+ }
1907
+ // The enum tracks the live tab set; the description need not track `active`.
1908
+ get toolReactiveProps() {
1909
+ return [...super.toolReactiveProps, "tabs"];
1910
+ }
1911
+ toolInputSchema() {
1912
+ return {
1913
+ type: "object",
1914
+ properties: {
1915
+ tab: {
1916
+ type: "string",
1917
+ enum: this.tabs.filter((t) => !t.disabled).map((t) => t.value),
1918
+ description: `Which tab to switch to in the "${this.actionNoun}" tabs.`
1919
+ }
1920
+ },
1921
+ required: ["tab"]
1922
+ };
1923
+ }
1924
+ executeTool(args) {
1925
+ const value = args.tab == null ? "" : String(args.tab);
1926
+ const tab = this.tabs.find((t) => t.value === value);
1927
+ if (!tab) {
1928
+ return {
1929
+ content: [
1930
+ { type: "text", text: `No tab "${value}" in the "${this.actionNoun}" tabs.` }
1931
+ ],
1932
+ isError: true
1933
+ };
1934
+ }
1935
+ if (tab.disabled) {
1936
+ return {
1937
+ content: [{ type: "text", text: `The "${tab.label}" tab is disabled.` }],
1938
+ isError: true
1939
+ };
1940
+ }
1941
+ this.switchTo(tab.value);
1942
+ return {
1943
+ content: [
1944
+ {
1945
+ type: "text",
1946
+ text: `Switched to the "${tab.label}" tab in the "${this.actionNoun}" tabs.`
1947
+ }
1948
+ ]
1949
+ };
1950
+ }
1951
+ // --- Tab model + state --------------------------------------------------
1952
+ connectedCallback() {
1953
+ this.syncTabs();
1954
+ this.ensureActive();
1955
+ super.connectedCallback();
1956
+ this.panelObserver = new MutationObserver(() => {
1957
+ this.syncTabs();
1958
+ this.ensureActive();
1959
+ });
1960
+ this.panelObserver.observe(this, { childList: true });
1961
+ }
1962
+ disconnectedCallback() {
1963
+ super.disconnectedCallback();
1964
+ this.panelObserver?.disconnect();
1965
+ this.panelObserver = void 0;
1966
+ }
1967
+ updated(changed) {
1968
+ super.updated(changed);
1969
+ if (changed.has("active") || changed.has("tabs")) this.applyPanels();
1970
+ }
1971
+ /** Light-DOM children that declare a tab via the `tab` attribute. */
1972
+ get panelEls() {
1973
+ return Array.from(this.querySelectorAll("[tab]"));
1974
+ }
1975
+ syncTabs() {
1976
+ this.tabs = this.panelEls.map((el) => ({
1977
+ value: el.getAttribute("tab") ?? "",
1978
+ label: el.getAttribute("tab-label") || el.getAttribute("tab") || "",
1979
+ disabled: el.hasAttribute("tab-disabled")
1980
+ }));
1981
+ }
1982
+ /** Fall back to the first enabled tab when `active` is unset or invalid. */
1983
+ ensureActive() {
1984
+ const valid = this.tabs.some((t) => t.value === this.active && !t.disabled);
1985
+ if (!valid) this.active = this.tabs.find((t) => !t.disabled)?.value ?? "";
1986
+ }
1987
+ /** Reflect the active tab onto the slotted panels (roles, labels, hidden). */
1988
+ applyPanels() {
1989
+ for (const el of this.panelEls) {
1990
+ const value = el.getAttribute("tab") ?? "";
1991
+ const tab = this.tabs.find((t) => t.value === value);
1992
+ el.setAttribute("role", "tabpanel");
1993
+ el.setAttribute("tabindex", "0");
1994
+ if (tab?.label) el.setAttribute("aria-label", tab.label);
1995
+ el.toggleAttribute("hidden", value !== this.active);
1996
+ }
1997
+ }
1998
+ /** Switch the active tab, firing `change` when it actually moves. */
1999
+ switchTo(value) {
2000
+ if (value === this.active) return;
2001
+ this.active = value;
2002
+ this.dispatchEvent(
2003
+ new CustomEvent("change", {
2004
+ detail: { value },
2005
+ bubbles: true,
2006
+ composed: true
2007
+ })
2008
+ );
2009
+ }
2010
+ get tabButtons() {
2011
+ return Array.from(this.renderRoot?.querySelectorAll(".tab") ?? []);
2012
+ }
2013
+ /** Arrow / Home / End roving with automatic activation (ARIA tabs pattern). */
2014
+ onKeydown(event) {
2015
+ const enabled = this.tabs.filter((t) => !t.disabled);
2016
+ if (enabled.length === 0) return;
2017
+ const order = enabled.map((t) => t.value);
2018
+ const current = order.indexOf(this.active);
2019
+ let next = -1;
2020
+ switch (event.key) {
2021
+ case "ArrowRight":
2022
+ case "ArrowDown":
2023
+ next = (current + 1) % order.length;
2024
+ break;
2025
+ case "ArrowLeft":
2026
+ case "ArrowUp":
2027
+ next = current <= 0 ? order.length - 1 : current - 1;
2028
+ break;
2029
+ case "Home":
2030
+ next = 0;
2031
+ break;
2032
+ case "End":
2033
+ next = order.length - 1;
2034
+ break;
2035
+ default:
2036
+ return;
2037
+ }
2038
+ event.preventDefault();
2039
+ const value = order[next];
2040
+ this.switchTo(value);
2041
+ void this.updateComplete.then(() => {
2042
+ this.tabButtons.find((b) => b.dataset.value === value)?.focus();
2043
+ });
2044
+ }
2045
+ render() {
2046
+ return html10`
2047
+ <div role="tablist" aria-label=${this.label || nothing9} @keydown=${this.onKeydown}>
2048
+ ${repeat4(
2049
+ this.tabs,
2050
+ (tab) => tab.value,
2051
+ (tab) => {
2052
+ const selected = tab.value === this.active;
2053
+ return html10`<button
2054
+ type="button"
2055
+ class="tab"
2056
+ part="tab"
2057
+ role="tab"
2058
+ data-value=${tab.value}
2059
+ aria-selected=${selected ? "true" : "false"}
2060
+ tabindex=${selected ? "0" : "-1"}
2061
+ ?disabled=${tab.disabled ?? false}
2062
+ @click=${() => this.switchTo(tab.value)}
2063
+ >
2064
+ ${tab.label}
2065
+ </button>`;
2066
+ }
2067
+ )}
2068
+ </div>
2069
+ <div class="panels" part="panels"><slot></slot></div>
2070
+ `;
2071
+ }
2072
+ };
2073
+ __decorateClass([
2074
+ property12({ reflect: true })
2075
+ ], WmcpTabs.prototype, "active", 2);
2076
+ __decorateClass([
2077
+ property12()
2078
+ ], WmcpTabs.prototype, "label", 2);
2079
+ __decorateClass([
2080
+ state5()
2081
+ ], WmcpTabs.prototype, "tabs", 2);
2082
+
2083
+ // src/elements/popover.ts
2084
+ import {
2085
+ html as html11,
2086
+ css as css11,
2087
+ nothing as nothing10
2088
+ } from "lit";
2089
+ import { property as property13 } from "lit/decorators.js";
2090
+ var WmcpPopover = class extends WmcpAction {
2091
+ constructor() {
2092
+ super(...arguments);
2093
+ this.open = false;
2094
+ this.label = "";
2095
+ this.placement = "bottom";
2096
+ this.trigger = "click";
2097
+ }
2098
+ static {
2099
+ this.tagName = "wmcp-popover";
2100
+ }
2101
+ static {
2102
+ this.styles = css11`
2103
+ :host {
2104
+ display: inline-block;
2105
+ font-family: var(
2106
+ --popover-font-family,
2107
+ var(--input-font-family, ui-sans-serif, system-ui, sans-serif)
2108
+ );
2109
+ }
2110
+ :host([hidden]) {
2111
+ display: none;
2112
+ }
2113
+ .trigger {
2114
+ appearance: none;
2115
+ font: inherit;
2116
+ cursor: pointer;
2117
+ anchor-name: --wmcp-pop-anchor;
2118
+ /* Unstyled by default so any trigger content (text, a button, an icon)
2119
+ sits flush; consumers theme via ::part(trigger). */
2120
+ border: 0;
2121
+ background: none;
2122
+ padding: 0;
2123
+ color: inherit;
2124
+ }
2125
+ .panel {
2126
+ box-sizing: border-box;
2127
+ width: max-content;
2128
+ max-width: var(--popover-max-width, 18rem);
2129
+ margin: 0;
2130
+ padding: var(--popover-padding, 0.75rem 0.875rem);
2131
+ color: var(--popover-text, var(--popover-foreground, oklch(0.145 0 0)));
2132
+ background: var(--popover-bg, var(--popover, oklch(1 0 0)));
2133
+ border: 1px solid var(--popover-border, var(--border, oklch(0.922 0 0)));
2134
+ border-radius: var(--popover-radius, var(--radius, 0.625rem));
2135
+ box-shadow: var(
2136
+ --popover-shadow,
2137
+ 0 10px 38px -10px color-mix(in oklch, oklch(0 0 0) 35%, transparent)
2138
+ );
2139
+ font-size: var(--popover-font-size, 0.875rem);
2140
+ position-anchor: --wmcp-pop-anchor;
2141
+ inset: auto;
2142
+ }
2143
+ :host([placement='bottom']) .panel {
2144
+ top: anchor(bottom);
2145
+ left: anchor(left);
2146
+ margin-top: var(--popover-offset, 0.4rem);
2147
+ }
2148
+ :host([placement='top']) .panel {
2149
+ bottom: anchor(top);
2150
+ left: anchor(left);
2151
+ margin-bottom: var(--popover-offset, 0.4rem);
2152
+ }
2153
+ :host([placement='right']) .panel {
2154
+ left: anchor(right);
2155
+ top: anchor(top);
2156
+ margin-left: var(--popover-offset, 0.4rem);
2157
+ }
2158
+ :host([placement='left']) .panel {
2159
+ right: anchor(left);
2160
+ top: anchor(top);
2161
+ margin-right: var(--popover-offset, 0.4rem);
2162
+ }
2163
+ @media (prefers-reduced-motion: no-preference) {
2164
+ .panel {
2165
+ transition: opacity 130ms ease, translate 130ms ease,
2166
+ overlay 130ms allow-discrete, display 130ms allow-discrete;
2167
+ }
2168
+ .panel:not(:popover-open) {
2169
+ opacity: 0;
2170
+ translate: 0 -0.25rem;
2171
+ }
2172
+ @starting-style {
2173
+ .panel:popover-open {
2174
+ opacity: 0;
2175
+ translate: 0 -0.25rem;
2176
+ }
2177
+ }
2178
+ }
2179
+ `;
2180
+ }
2181
+ get panelEl() {
2182
+ return this.renderRoot?.querySelector(".panel") ?? null;
2183
+ }
2184
+ // --- WmcpAction hooks ---------------------------------------------------
2185
+ get actionVerb() {
2186
+ return "open";
2187
+ }
2188
+ get defaultNameSuffix() {
2189
+ return "popover";
2190
+ }
2191
+ get defaultToolDescription() {
2192
+ return `Open the "${this.actionNoun}" popover.`;
2193
+ }
2194
+ executeTool() {
2195
+ const noun = this.actionNoun;
2196
+ if (this.open) {
2197
+ return { content: [{ type: "text", text: `The "${noun}" popover is already open.` }] };
2198
+ }
2199
+ this.show();
2200
+ return { content: [{ type: "text", text: `Opened the "${noun}" popover.` }] };
2201
+ }
2202
+ // --- Open / close -------------------------------------------------------
2203
+ updated(changed) {
2204
+ super.updated(changed);
2205
+ if (changed.has("open")) this.syncNativeOpen();
2206
+ }
2207
+ /** Open the popover. */
2208
+ show() {
2209
+ this.open = true;
2210
+ }
2211
+ /** Close the popover. */
2212
+ close() {
2213
+ this.open = false;
2214
+ }
2215
+ syncNativeOpen() {
2216
+ const p = this.panelEl;
2217
+ if (!p) return;
2218
+ const isOpen = p.matches(":popover-open");
2219
+ if (this.open && !isOpen) p.showPopover();
2220
+ else if (!this.open && isOpen) p.hidePopover();
2221
+ }
2222
+ /** Native toggle fires for clicks, light-dismiss, Escape, and our own calls. */
2223
+ onToggle(event) {
2224
+ const opened = event.newState === "open";
2225
+ this.open = opened;
2226
+ this.dispatchEvent(
2227
+ new Event(opened ? "open" : "close", { bubbles: true, composed: true })
2228
+ );
2229
+ }
2230
+ disconnectedCallback() {
2231
+ super.disconnectedCallback();
2232
+ this.cancelScheduledClose();
2233
+ }
2234
+ /** Open on hover/focus of the trigger *or* the panel. */
2235
+ openOnHover() {
2236
+ if (this.trigger !== "hover") return;
2237
+ this.cancelScheduledClose();
2238
+ this.show();
2239
+ }
2240
+ /**
2241
+ * Close on leave/blur — but on a short delay, so the pointer can cross the
2242
+ * gap from the trigger to the panel (and reach interactive content inside it)
2243
+ * without the popover vanishing. Re-entering either cancels the close.
2244
+ */
2245
+ scheduleHoverClose() {
2246
+ if (this.trigger !== "hover") return;
2247
+ this.cancelScheduledClose();
2248
+ this.closeTimer = setTimeout(() => this.close(), 120);
2249
+ }
2250
+ cancelScheduledClose() {
2251
+ if (this.closeTimer) {
2252
+ clearTimeout(this.closeTimer);
2253
+ this.closeTimer = void 0;
2254
+ }
2255
+ }
2256
+ render() {
2257
+ const isTooltip = this.trigger === "hover";
2258
+ return html11`
2259
+ <button
2260
+ type="button"
2261
+ class="trigger"
2262
+ part="trigger"
2263
+ popovertarget=${this.trigger === "click" ? "wmcp-pop" : nothing10}
2264
+ aria-haspopup=${isTooltip ? nothing10 : "dialog"}
2265
+ aria-expanded=${isTooltip ? nothing10 : this.open ? "true" : "false"}
2266
+ aria-describedby=${isTooltip ? "wmcp-pop" : nothing10}
2267
+ @pointerenter=${this.openOnHover}
2268
+ @pointerleave=${this.scheduleHoverClose}
2269
+ @focusin=${this.openOnHover}
2270
+ @focusout=${this.scheduleHoverClose}
2271
+ >
2272
+ <slot name="trigger">${this.label}</slot>
2273
+ </button>
2274
+ <div
2275
+ id="wmcp-pop"
2276
+ class="panel"
2277
+ part="panel"
2278
+ popover=${isTooltip ? "manual" : "auto"}
2279
+ role=${isTooltip ? "tooltip" : "dialog"}
2280
+ aria-label=${this.label || this.actionNoun}
2281
+ @toggle=${this.onToggle}
2282
+ @pointerenter=${this.openOnHover}
2283
+ @pointerleave=${this.scheduleHoverClose}
2284
+ @focusin=${this.openOnHover}
2285
+ @focusout=${this.scheduleHoverClose}
2286
+ >
2287
+ <slot></slot>
2288
+ </div>
2289
+ `;
2290
+ }
2291
+ };
2292
+ __decorateClass([
2293
+ property13({ type: Boolean, reflect: true })
2294
+ ], WmcpPopover.prototype, "open", 2);
2295
+ __decorateClass([
2296
+ property13()
2297
+ ], WmcpPopover.prototype, "label", 2);
2298
+ __decorateClass([
2299
+ property13({ reflect: true })
2300
+ ], WmcpPopover.prototype, "placement", 2);
2301
+ __decorateClass([
2302
+ property13()
2303
+ ], WmcpPopover.prototype, "trigger", 2);
2304
+
2305
+ // src/elements/toast.ts
2306
+ import {
2307
+ html as html12,
2308
+ css as css12,
2309
+ nothing as nothing11
2310
+ } from "lit";
2311
+ import { property as property14, state as state6 } from "lit/decorators.js";
2312
+ import { repeat as repeat5 } from "lit/directives/repeat.js";
2313
+ var RECENT_WINDOW_MS = 3e4;
2314
+ var WmcpToast = class extends WmcpExposable {
2315
+ constructor() {
2316
+ super(...arguments);
2317
+ this.name = "";
2318
+ this.label = "";
2319
+ this.placement = "bottom-right";
2320
+ this.duration = 5e3;
2321
+ this.toasts = [];
2322
+ // A short history so an agent that reads *after* a toast auto-dismisses still
2323
+ // learns what happened (async outcomes vanish before the agent polls).
2324
+ this.recent = [];
2325
+ this.nextId = 0;
2326
+ this.timers = /* @__PURE__ */ new Map();
2327
+ }
2328
+ static {
2329
+ this.tagName = "wmcp-toast";
2330
+ }
2331
+ static {
2332
+ this.styles = css12`
2333
+ :host {
2334
+ position: fixed;
2335
+ z-index: var(--toast-z, 1000);
2336
+ display: flex;
2337
+ flex-direction: column;
2338
+ gap: var(--toast-gap, 0.5rem);
2339
+ width: max-content;
2340
+ max-width: var(--toast-max-width, min(92vw, 22rem));
2341
+ pointer-events: none;
2342
+ font-family: var(
2343
+ --toast-font-family,
2344
+ var(--input-font-family, ui-sans-serif, system-ui, sans-serif)
2345
+ );
2346
+ }
2347
+ :host([placement='bottom-right']) {
2348
+ right: var(--toast-inset, 1rem);
2349
+ bottom: var(--toast-inset, 1rem);
2350
+ }
2351
+ :host([placement='bottom-left']) {
2352
+ left: var(--toast-inset, 1rem);
2353
+ bottom: var(--toast-inset, 1rem);
2354
+ }
2355
+ :host([placement='top-right']) {
2356
+ right: var(--toast-inset, 1rem);
2357
+ top: var(--toast-inset, 1rem);
2358
+ }
2359
+ :host([placement='top-left']) {
2360
+ left: var(--toast-inset, 1rem);
2361
+ top: var(--toast-inset, 1rem);
2362
+ }
2363
+ .toast {
2364
+ pointer-events: auto;
2365
+ display: flex;
2366
+ align-items: start;
2367
+ gap: var(--toast-item-gap, 0.625rem);
2368
+ padding: var(--toast-padding, 0.75rem 0.875rem);
2369
+ color: var(--toast-text, var(--popover-foreground, oklch(0.145 0 0)));
2370
+ background: var(--toast-bg, var(--popover, oklch(1 0 0)));
2371
+ border: 1px solid var(--toast-border, var(--border, oklch(0.922 0 0)));
2372
+ border-left: 3px solid var(--toast-accent, var(--border, oklch(0.922 0 0)));
2373
+ border-radius: var(--toast-radius, var(--radius, 0.625rem));
2374
+ box-shadow: var(
2375
+ --toast-shadow,
2376
+ 0 10px 38px -10px color-mix(in oklch, oklch(0 0 0) 35%, transparent)
2377
+ );
2378
+ font-size: var(--toast-font-size, 0.875rem);
2379
+ }
2380
+ .toast[data-variant='success'] {
2381
+ --toast-accent: var(--toast-accent-success, oklch(0.627 0.13 160));
2382
+ }
2383
+ .toast[data-variant='warning'] {
2384
+ --toast-accent: var(--toast-accent-warning, oklch(0.7 0.16 75));
2385
+ }
2386
+ .toast[data-variant='error'] {
2387
+ --toast-accent: var(--toast-accent-error, var(--destructive, oklch(0.577 0.245 27.325)));
2388
+ }
2389
+ .toast[data-variant='info'] {
2390
+ --toast-accent: var(--toast-accent-info, var(--primary, oklch(0.205 0 0)));
2391
+ }
2392
+ .body {
2393
+ flex: 1;
2394
+ min-width: 0;
2395
+ }
2396
+ .title {
2397
+ font-weight: 600;
2398
+ }
2399
+ .message {
2400
+ color: var(--toast-message, var(--muted-foreground, oklch(0.556 0 0)));
2401
+ }
2402
+ .title + .message {
2403
+ margin-top: 0.125rem;
2404
+ }
2405
+ .close {
2406
+ appearance: none;
2407
+ flex-shrink: 0;
2408
+ width: 1.25rem;
2409
+ height: 1.25rem;
2410
+ padding: 0;
2411
+ border: 0;
2412
+ border-radius: 0.25rem;
2413
+ background: transparent;
2414
+ color: var(--toast-message, var(--muted-foreground, oklch(0.556 0 0)));
2415
+ cursor: pointer;
2416
+ line-height: 1;
2417
+ }
2418
+ .close:hover {
2419
+ color: var(--toast-text, var(--foreground, oklch(0.145 0 0)));
2420
+ }
2421
+ @media (prefers-reduced-motion: no-preference) {
2422
+ .toast {
2423
+ animation: toast-in 180ms cubic-bezier(0.34, 1.56, 0.64, 1);
2424
+ }
2425
+ @keyframes toast-in {
2426
+ from {
2427
+ opacity: 0;
2428
+ translate: 0 0.5rem;
2429
+ }
2430
+ }
2431
+ }
2432
+ `;
2433
+ }
2434
+ // --- Imperative API (what page code calls) ------------------------------
2435
+ /** Show a toast. Returns its id (pass to {@link dismiss}). */
2436
+ show(options) {
2437
+ const record = {
2438
+ ...options,
2439
+ id: this.nextId++,
2440
+ variant: options.variant ?? "info",
2441
+ shownAt: Date.now()
2442
+ };
2443
+ this.toasts = [...this.toasts, record];
2444
+ this.recent = [record, ...this.recent].slice(0, 10);
2445
+ const ms = options.duration ?? this.duration;
2446
+ if (ms > 0) {
2447
+ this.timers.set(
2448
+ record.id,
2449
+ setTimeout(() => this.dismiss(record.id), ms)
2450
+ );
2451
+ }
2452
+ return record.id;
2453
+ }
2454
+ /** Dismiss a toast by id. */
2455
+ dismiss(id) {
2456
+ this.toasts = this.toasts.filter((t) => t.id !== id);
2457
+ const timer = this.timers.get(id);
2458
+ if (timer) {
2459
+ clearTimeout(timer);
2460
+ this.timers.delete(id);
2461
+ }
2462
+ }
2463
+ /** Dismiss all visible toasts. */
2464
+ clear() {
2465
+ for (const t of [...this.toasts]) this.dismiss(t.id);
2466
+ }
2467
+ disconnectedCallback() {
2468
+ super.disconnectedCallback();
2469
+ for (const timer of this.timers.values()) clearTimeout(timer);
2470
+ this.timers.clear();
2471
+ }
2472
+ // --- WmcpExposable hooks (the agent's *read* surface) -------------------
2473
+ get resolvedToolName() {
2474
+ return this.toolName || `read_${this.name || "notifications"}`;
2475
+ }
2476
+ get defaultToolDescription() {
2477
+ return "Read the notifications currently shown to the user (with any that appeared in the last few seconds), so you can tell what just happened on the page.";
2478
+ }
2479
+ get toolReactiveProps() {
2480
+ return [...super.toolReactiveProps, "name"];
2481
+ }
2482
+ executeTool() {
2483
+ const describe = (t) => `[${t.variant}] ${t.title ? `${t.title}: ` : ""}${t.message}`;
2484
+ if (this.toasts.length > 0) {
2485
+ return {
2486
+ content: [
2487
+ {
2488
+ type: "text",
2489
+ text: `${this.toasts.length} notification(s) showing:
2490
+ ` + this.toasts.map(describe).join("\n")
2491
+ }
2492
+ ]
2493
+ };
2494
+ }
2495
+ const cutoff = Date.now() - RECENT_WINDOW_MS;
2496
+ const recent = this.recent.filter((t) => t.shownAt >= cutoff);
2497
+ if (recent.length > 0) {
2498
+ return {
2499
+ content: [
2500
+ {
2501
+ type: "text",
2502
+ text: "No notifications are showing now. Recently shown:\n" + recent.map(describe).join("\n")
2503
+ }
2504
+ ]
2505
+ };
2506
+ }
2507
+ return { content: [{ type: "text", text: "No notifications." }] };
2508
+ }
2509
+ // --- Render -------------------------------------------------------------
2510
+ render() {
2511
+ return html12`
2512
+ <div role="region" aria-label=${this.label || "Notifications"} aria-live="polite">
2513
+ ${repeat5(
2514
+ this.toasts,
2515
+ (t) => t.id,
2516
+ (t) => html12`
2517
+ <div
2518
+ class="toast"
2519
+ part="toast"
2520
+ data-variant=${t.variant}
2521
+ role=${t.variant === "error" ? "alert" : "status"}
2522
+ >
2523
+ <div class="body">
2524
+ ${t.title ? html12`<div class="title">${t.title}</div>` : nothing11}
2525
+ <div class="message">${t.message}</div>
2526
+ </div>
2527
+ <button
2528
+ class="close"
2529
+ part="close"
2530
+ type="button"
2531
+ aria-label="Dismiss notification"
2532
+ @click=${() => this.dismiss(t.id)}
2533
+ >
2534
+
2535
+ </button>
2536
+ </div>
2537
+ `
2538
+ )}
2539
+ </div>
2540
+ `;
2541
+ }
2542
+ };
2543
+ __decorateClass([
2544
+ property14()
2545
+ ], WmcpToast.prototype, "name", 2);
2546
+ __decorateClass([
2547
+ property14()
2548
+ ], WmcpToast.prototype, "label", 2);
2549
+ __decorateClass([
2550
+ property14({ reflect: true })
2551
+ ], WmcpToast.prototype, "placement", 2);
2552
+ __decorateClass([
2553
+ property14({ type: Number })
2554
+ ], WmcpToast.prototype, "duration", 2);
2555
+ __decorateClass([
2556
+ state6()
2557
+ ], WmcpToast.prototype, "toasts", 2);
2558
+
2559
+ // src/register.ts
2560
+ var elements = [
2561
+ WmcpInput,
2562
+ WmcpTextarea,
2563
+ WmcpSelect,
2564
+ WmcpCheckbox,
2565
+ WmcpRadio,
2566
+ WmcpRadioGroup,
2567
+ WmcpButton,
2568
+ WmcpDialog,
2569
+ WmcpMenu,
2570
+ WmcpTabs,
2571
+ WmcpPopover,
2572
+ WmcpToast
979
2573
  ];
980
2574
  function defineComponents() {
981
2575
  if (typeof customElements === "undefined") return;
@@ -986,13 +2580,21 @@ function defineComponents() {
986
2580
  }
987
2581
  }
988
2582
  export {
2583
+ WmcpAction,
2584
+ WmcpButton,
989
2585
  WmcpCheckbox,
2586
+ WmcpDialog,
2587
+ WmcpExposable,
990
2588
  WmcpFormControl,
991
2589
  WmcpInput,
2590
+ WmcpMenu,
2591
+ WmcpPopover,
992
2592
  WmcpRadio,
993
2593
  WmcpRadioGroup,
994
2594
  WmcpSelect,
2595
+ WmcpTabs,
995
2596
  WmcpTextarea,
2597
+ WmcpToast,
996
2598
  defineComponents,
997
2599
  exposeTool,
998
2600
  isStandardSchema,