@qontinui/ui-bridge 0.3.0 → 0.3.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.
Files changed (127) hide show
  1. package/dist/ai/index.d.mts +312 -155
  2. package/dist/ai/index.d.ts +312 -155
  3. package/dist/ai/index.js +2363 -67
  4. package/dist/ai/index.js.map +1 -1
  5. package/dist/ai/index.mjs +2328 -68
  6. package/dist/ai/index.mjs.map +1 -1
  7. package/dist/annotations/index.d.mts +218 -0
  8. package/dist/annotations/index.d.ts +218 -0
  9. package/dist/annotations/index.js +246 -0
  10. package/dist/annotations/index.js.map +1 -0
  11. package/dist/annotations/index.mjs +241 -0
  12. package/dist/annotations/index.mjs.map +1 -0
  13. package/dist/assertions-BSR3afVr.d.ts +161 -0
  14. package/dist/assertions-CTw1hfOx.d.mts +161 -0
  15. package/dist/babel-plugin/index.js +23 -34
  16. package/dist/babel-plugin/index.js.map +1 -1
  17. package/dist/babel-plugin/index.mjs +23 -34
  18. package/dist/babel-plugin/index.mjs.map +1 -1
  19. package/dist/browser-capture-Bms60T6f.d.mts +47 -0
  20. package/dist/browser-capture-CsTU29mb.d.ts +47 -0
  21. package/dist/control/index.d.mts +26 -7
  22. package/dist/control/index.d.ts +26 -7
  23. package/dist/control/index.js +276 -48
  24. package/dist/control/index.js.map +1 -1
  25. package/dist/control/index.mjs +276 -48
  26. package/dist/control/index.mjs.map +1 -1
  27. package/dist/core/index.d.mts +2 -2
  28. package/dist/core/index.d.ts +2 -2
  29. package/dist/core/index.js.map +1 -1
  30. package/dist/core/index.mjs.map +1 -1
  31. package/dist/debug/index.d.mts +5 -3
  32. package/dist/debug/index.d.ts +5 -3
  33. package/dist/debug/index.js +925 -1
  34. package/dist/debug/index.js.map +1 -1
  35. package/dist/debug/index.mjs +924 -2
  36. package/dist/debug/index.mjs.map +1 -1
  37. package/dist/index.d.mts +12 -7
  38. package/dist/index.d.ts +12 -7
  39. package/dist/index.js +4720 -173
  40. package/dist/index.js.map +1 -1
  41. package/dist/index.mjs +4656 -174
  42. package/dist/index.mjs.map +1 -1
  43. package/dist/{metrics-DTA2bwG7.d.mts → metrics-DuA2qIIz.d.mts} +2 -2
  44. package/dist/{metrics-BfiT_rhZ.d.ts → metrics-KFAAKNEB.d.ts} +2 -2
  45. package/dist/native/control/index.js +2 -7
  46. package/dist/native/control/index.js.map +1 -1
  47. package/dist/native/control/index.mjs +2 -7
  48. package/dist/native/control/index.mjs.map +1 -1
  49. package/dist/native/core/index.js.map +1 -1
  50. package/dist/native/core/index.mjs.map +1 -1
  51. package/dist/native/debug/index.js +23 -66
  52. package/dist/native/debug/index.js.map +1 -1
  53. package/dist/native/debug/index.mjs +23 -66
  54. package/dist/native/debug/index.mjs.map +1 -1
  55. package/dist/native/index.js +89 -131
  56. package/dist/native/index.js.map +1 -1
  57. package/dist/native/index.mjs +89 -131
  58. package/dist/native/index.mjs.map +1 -1
  59. package/dist/native/react/index.js +28 -52
  60. package/dist/native/react/index.js.map +1 -1
  61. package/dist/native/react/index.mjs +28 -52
  62. package/dist/native/react/index.mjs.map +1 -1
  63. package/dist/native/server/index.js +38 -13
  64. package/dist/native/server/index.js.map +1 -1
  65. package/dist/native/server/index.mjs +38 -13
  66. package/dist/native/server/index.mjs.map +1 -1
  67. package/dist/react/index.d.mts +107 -8
  68. package/dist/react/index.d.ts +107 -8
  69. package/dist/react/index.js +2194 -84
  70. package/dist/react/index.js.map +1 -1
  71. package/dist/react/index.mjs +2194 -85
  72. package/dist/react/index.mjs.map +1 -1
  73. package/dist/{registry-BKLEm-yk.d.ts → registry-C6dDtn1v.d.ts} +27 -2
  74. package/dist/{registry-BmZgyCz8.d.mts → registry-POtcxnal.d.mts} +27 -2
  75. package/dist/render-log/index.d.mts +1 -1
  76. package/dist/render-log/index.d.ts +1 -1
  77. package/dist/server/express.d.mts +5 -4
  78. package/dist/server/express.d.ts +5 -4
  79. package/dist/server/express.js +104 -2
  80. package/dist/server/express.js.map +1 -1
  81. package/dist/server/express.mjs +104 -2
  82. package/dist/server/express.mjs.map +1 -1
  83. package/dist/server/handlers.d.mts +36 -5
  84. package/dist/server/handlers.d.ts +36 -5
  85. package/dist/server/handlers.js +3129 -224
  86. package/dist/server/handlers.js.map +1 -1
  87. package/dist/server/handlers.mjs +3129 -224
  88. package/dist/server/handlers.mjs.map +1 -1
  89. package/dist/server/index.d.mts +7 -5
  90. package/dist/server/index.d.ts +7 -5
  91. package/dist/server/index.js +3215 -183
  92. package/dist/server/index.js.map +1 -1
  93. package/dist/server/index.mjs +3215 -183
  94. package/dist/server/index.mjs.map +1 -1
  95. package/dist/server/nextjs.d.mts +6 -4
  96. package/dist/server/nextjs.d.ts +6 -4
  97. package/dist/server/nextjs.js +106 -3
  98. package/dist/server/nextjs.js.map +1 -1
  99. package/dist/server/nextjs.mjs +106 -3
  100. package/dist/server/nextjs.mjs.map +1 -1
  101. package/dist/server/standalone.d.mts +6 -5
  102. package/dist/server/standalone.d.ts +6 -5
  103. package/dist/server/standalone.js +131 -5
  104. package/dist/server/standalone.js.map +1 -1
  105. package/dist/server/standalone.mjs +131 -5
  106. package/dist/server/standalone.mjs.map +1 -1
  107. package/dist/specs/index.d.mts +365 -0
  108. package/dist/specs/index.d.ts +365 -0
  109. package/dist/specs/index.js +2809 -0
  110. package/dist/specs/index.js.map +1 -0
  111. package/dist/specs/index.mjs +2786 -0
  112. package/dist/specs/index.mjs.map +1 -0
  113. package/dist/{standalone-BURj8J3G.d.ts → standalone-B6GLIEmR.d.ts} +6 -2
  114. package/dist/{standalone-Dwmel29d.d.mts → standalone-CjdYqj3P.d.mts} +6 -2
  115. package/dist/{types-CHnlwiTK.d.ts → types-B2EfvEaq.d.ts} +83 -3
  116. package/dist/{types-B7J7noLK.d.mts → types-C7gVYRnF.d.ts} +72 -2
  117. package/dist/{types-BkNRILUa.d.ts → types-CJGrBEhC.d.mts} +72 -2
  118. package/dist/types-CebMQj76.d.ts +1275 -0
  119. package/dist/types-D_ypYl3T.d.mts +1275 -0
  120. package/dist/types-UBtp7R0u.d.mts +132 -0
  121. package/dist/types-UBtp7R0u.d.ts +132 -0
  122. package/dist/{types-CEQLnFMv.d.mts → types-gO696T_t.d.mts} +83 -3
  123. package/dist/{types-jKVgTI6_.d.mts → types-suaYwWWg.d.mts} +173 -2
  124. package/dist/{types-jKVgTI6_.d.ts → types-suaYwWWg.d.ts} +173 -2
  125. package/package.json +18 -2
  126. package/dist/types-B5Q0GVo0.d.mts +0 -646
  127. package/dist/types-DfPqwU-i.d.ts +0 -646
@@ -103,6 +103,10 @@ function getElementState(element) {
103
103
  pointerEvents: style.pointerEvents
104
104
  }
105
105
  };
106
+ const rawText = element.textContent?.trim();
107
+ if (rawText) {
108
+ state.textContent = rawText.replace(/\s+/g, " ").slice(0, 500);
109
+ }
106
110
  if (element instanceof HTMLInputElement) {
107
111
  state.value = element.value;
108
112
  if (element.type === "checkbox" || element.type === "radio") {
@@ -144,9 +148,25 @@ function createMouseEvent(type, element, options) {
144
148
  clientY: rect.top + y
145
149
  });
146
150
  }
151
+ function elementFromPointSafe(x, y) {
152
+ if (typeof document.elementFromPoint === "function") {
153
+ return document.elementFromPoint(x, y);
154
+ }
155
+ return null;
156
+ }
157
+ function createMouseEventAt(type, clientX, clientY) {
158
+ return new MouseEvent(type, {
159
+ bubbles: true,
160
+ cancelable: true,
161
+ button: 0,
162
+ clientX,
163
+ clientY
164
+ });
165
+ }
147
166
  var DefaultActionExecutor = class {
148
- constructor(registry) {
167
+ constructor(registry, consoleCapture) {
149
168
  this.registry = registry;
169
+ this.consoleCapture = consoleCapture;
150
170
  }
151
171
  /**
152
172
  * Execute an action on an element
@@ -183,11 +203,19 @@ var DefaultActionExecutor = class {
183
203
  };
184
204
  }
185
205
  }
206
+ const actionStartTime = Date.now();
186
207
  const result = await this.performAction(element, request.action, request.params);
208
+ let consoleErrors;
209
+ if (this.consoleCapture) {
210
+ await sleep(50);
211
+ const errors = this.consoleCapture.getConsoleSince(actionStartTime);
212
+ if (errors.length > 0) consoleErrors = errors;
213
+ }
187
214
  return {
188
215
  success: true,
189
216
  elementState: getElementState(element),
190
217
  result,
218
+ consoleErrors,
191
219
  durationMs: performance.now() - startTime,
192
220
  timestamp: Date.now(),
193
221
  requestId: request.requestId,
@@ -279,47 +307,76 @@ var DefaultActionExecutor = class {
279
307
  const rootEl = document.querySelector(options.root);
280
308
  if (rootEl) root = rootEl;
281
309
  }
282
- const interactiveSelectors = [
283
- "a[href]",
284
- "button",
285
- "input",
286
- "select",
287
- "textarea",
288
- "[onclick]",
289
- '[role="button"]',
290
- '[role="link"]',
291
- '[role="checkbox"]',
292
- '[role="radio"]',
293
- '[role="menuitem"]',
294
- '[role="tab"]',
295
- '[role="switch"]',
296
- '[tabindex]:not([tabindex="-1"])',
297
- '[contenteditable="true"]',
298
- "[data-ui-id]",
299
- "[data-testid]"
300
- ];
301
- const selector = options?.selector || interactiveSelectors.join(", ");
302
- const foundElements = root.querySelectorAll(selector);
303
- for (const el of foundElements) {
304
- if (options?.limit && elements.length >= options.limit) break;
305
- const state = getElementState(el);
306
- if (!options?.includeHidden && !state.visible) continue;
307
- if (options?.types) {
308
- const type = this.inferElementType(el);
309
- if (!options.types.includes(type)) continue;
310
- }
311
- const registered = this.registry.findByDOMElement(el);
312
- elements.push({
313
- id: registered?.id || this.getElementId(el),
314
- type: registered?.type || this.inferElementType(el),
315
- label: registered?.label || this.getElementLabel(el),
316
- tagName: el.tagName.toLowerCase(),
317
- role: el.getAttribute("role") || void 0,
318
- accessibleName: this.getAccessibleName(el),
319
- actions: registered?.actions || this.inferActions(el),
320
- state,
321
- registered: !!registered
322
- });
310
+ if (!options?.contentOnly) {
311
+ const interactiveSelectors = [
312
+ "a[href]",
313
+ "button",
314
+ "input",
315
+ "select",
316
+ "textarea",
317
+ "[onclick]",
318
+ '[role="button"]',
319
+ '[role="link"]',
320
+ '[role="checkbox"]',
321
+ '[role="radio"]',
322
+ '[role="menuitem"]',
323
+ '[role="tab"]',
324
+ '[role="switch"]',
325
+ '[tabindex]:not([tabindex="-1"])',
326
+ '[contenteditable="true"]',
327
+ "[data-ui-element]",
328
+ "[data-ui-id]",
329
+ "[data-testid]"
330
+ ];
331
+ const selector = options?.selector || interactiveSelectors.join(", ");
332
+ const foundElements = root.querySelectorAll(selector);
333
+ for (const el of foundElements) {
334
+ if (options?.limit && elements.length >= options.limit) break;
335
+ const state = getElementState(el);
336
+ if (!options?.includeHidden && !state.visible) continue;
337
+ if (options?.types) {
338
+ const type = this.inferElementType(el);
339
+ if (!options.types.includes(type)) continue;
340
+ }
341
+ const registered = this.registry.findByDOMElement(el);
342
+ elements.push({
343
+ id: registered?.id || this.getElementId(el),
344
+ type: registered?.type || this.inferElementType(el),
345
+ label: registered?.label || this.getElementLabel(el),
346
+ tagName: el.tagName.toLowerCase(),
347
+ role: el.getAttribute("role") || void 0,
348
+ accessibleName: this.getAccessibleName(el),
349
+ actions: registered?.actions || this.inferActions(el),
350
+ state,
351
+ registered: !!registered,
352
+ category: registered?.category || "interactive",
353
+ contentMetadata: registered?.contentMetadata
354
+ });
355
+ }
356
+ }
357
+ if (options?.includeContent || options?.contentOnly) {
358
+ const contentElements = this.registry.getAllContentElements();
359
+ for (const el of contentElements) {
360
+ if (options?.limit && elements.length >= options.limit) break;
361
+ const state = el.getState();
362
+ if (!options?.includeHidden && !state.visible) continue;
363
+ if (options?.contentRole && el.contentMetadata?.contentRole !== options.contentRole) {
364
+ continue;
365
+ }
366
+ elements.push({
367
+ id: el.id,
368
+ type: el.type,
369
+ label: el.label,
370
+ tagName: el.element.tagName.toLowerCase(),
371
+ role: el.element.getAttribute("role") || void 0,
372
+ accessibleName: el.label || state.textContent?.trim(),
373
+ actions: [],
374
+ state,
375
+ registered: true,
376
+ category: "content",
377
+ contentMetadata: el.contentMetadata
378
+ });
379
+ }
323
380
  }
324
381
  return {
325
382
  elements,
@@ -349,7 +406,9 @@ var DefaultActionExecutor = class {
349
406
  type: el.type,
350
407
  label: el.label,
351
408
  actions: [...el.actions, ...el.customActions ? Object.keys(el.customActions) : []],
352
- state: el.getState()
409
+ state: el.getState(),
410
+ category: el.category,
411
+ contentMetadata: el.contentMetadata
353
412
  })),
354
413
  components: components.map((comp) => ({
355
414
  id: comp.id,
@@ -433,6 +492,14 @@ var DefaultActionExecutor = class {
433
492
  return this.performCheck(element, false);
434
493
  case "toggle":
435
494
  return this.performToggle(element);
495
+ case "drag":
496
+ return this.performDrag(element, params);
497
+ case "setValue":
498
+ return this.performSetValue(element, params);
499
+ case "submit":
500
+ return this.performSubmit(element);
501
+ case "reset":
502
+ return this.performReset(element);
436
503
  default: {
437
504
  const registered = this.registry.findByDOMElement(element);
438
505
  if (registered?.customActions?.[action]) {
@@ -462,15 +529,26 @@ var DefaultActionExecutor = class {
462
529
  if (!(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement)) {
463
530
  throw new Error("Type action requires an input or textarea element");
464
531
  }
532
+ const proto = element instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype;
533
+ const nativeSetter = Object.getOwnPropertyDescriptor(proto, "value")?.set;
465
534
  element.focus();
466
535
  if (options?.clear) {
467
- element.value = "";
536
+ if (nativeSetter) {
537
+ nativeSetter.call(element, "");
538
+ } else {
539
+ element.value = "";
540
+ }
468
541
  element.dispatchEvent(new Event("input", { bubbles: true }));
469
542
  }
470
543
  const text = options?.text || "";
471
544
  const delay = options?.delay || 0;
472
545
  for (const char of text) {
473
- element.value += char;
546
+ const current = element.value;
547
+ if (nativeSetter) {
548
+ nativeSetter.call(element, current + char);
549
+ } else {
550
+ element.value = current + char;
551
+ }
474
552
  if (options?.triggerEvents !== false) {
475
553
  element.dispatchEvent(new Event("input", { bubbles: true }));
476
554
  }
@@ -484,7 +562,13 @@ var DefaultActionExecutor = class {
484
562
  }
485
563
  performClear(element) {
486
564
  if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
487
- element.value = "";
565
+ const proto = element instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype;
566
+ const nativeSetter = Object.getOwnPropertyDescriptor(proto, "value")?.set;
567
+ if (nativeSetter) {
568
+ nativeSetter.call(element, "");
569
+ } else {
570
+ element.value = "";
571
+ }
488
572
  element.dispatchEvent(new Event("input", { bubbles: true }));
489
573
  element.dispatchEvent(new Event("change", { bubbles: true }));
490
574
  }
@@ -566,6 +650,150 @@ var DefaultActionExecutor = class {
566
650
  element.dispatchEvent(new Event("change", { bubbles: true }));
567
651
  }
568
652
  }
653
+ performSetValue(element, params) {
654
+ const value = params?.value;
655
+ if (value === void 0) {
656
+ throw new Error('setValue requires a "value" parameter');
657
+ }
658
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
659
+ const nativeSetter = Object.getOwnPropertyDescriptor(
660
+ element instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype,
661
+ "value"
662
+ )?.set;
663
+ if (nativeSetter) {
664
+ nativeSetter.call(element, value);
665
+ } else {
666
+ element.value = value;
667
+ }
668
+ element.dispatchEvent(new Event("input", { bubbles: true }));
669
+ element.dispatchEvent(new Event("change", { bubbles: true }));
670
+ } else if (element instanceof HTMLSelectElement) {
671
+ element.value = value;
672
+ element.dispatchEvent(new Event("change", { bubbles: true }));
673
+ }
674
+ }
675
+ performSubmit(element) {
676
+ const form = element instanceof HTMLFormElement ? element : element.closest("form");
677
+ if (form) {
678
+ const submitEvent = new Event("submit", { bubbles: true, cancelable: true });
679
+ if (form.dispatchEvent(submitEvent)) {
680
+ form.requestSubmit();
681
+ }
682
+ } else {
683
+ throw new Error("No form found for submit action");
684
+ }
685
+ }
686
+ performReset(element) {
687
+ const form = element instanceof HTMLFormElement ? element : element.closest("form");
688
+ if (form) {
689
+ form.reset();
690
+ form.dispatchEvent(new Event("reset", { bubbles: true }));
691
+ } else {
692
+ throw new Error("No form found for reset action");
693
+ }
694
+ }
695
+ /**
696
+ * Perform a drag operation by dispatching a sequence of mouse events.
697
+ *
698
+ * Follows the same composite pattern as the qontinui core library:
699
+ * mousedown on source → wait → mousemove × N along path → mouseup on target.
700
+ *
701
+ * Optionally dispatches HTML5 drag events (dragstart/dragover/drop/dragend)
702
+ * for apps that use the HTML5 Drag and Drop API instead of mouse events.
703
+ */
704
+ async performDrag(sourceElement, options) {
705
+ const sourceRect = sourceElement.getBoundingClientRect();
706
+ const sourceX = sourceRect.left + (options?.sourceOffset?.x ?? sourceRect.width / 2);
707
+ const sourceY = sourceRect.top + (options?.sourceOffset?.y ?? sourceRect.height / 2);
708
+ let targetX;
709
+ let targetY;
710
+ if (options?.targetPosition) {
711
+ targetX = options.targetPosition.x;
712
+ targetY = options.targetPosition.y;
713
+ } else if (options?.target) {
714
+ const targetElement = this.resolveTargetElement(options.target);
715
+ if (!targetElement) {
716
+ throw new Error(`Drag target element not found: ${JSON.stringify(options.target)}`);
717
+ }
718
+ const targetRect = targetElement.getBoundingClientRect();
719
+ targetX = targetRect.left + (options?.targetOffset?.x ?? targetRect.width / 2);
720
+ targetY = targetRect.top + (options?.targetOffset?.y ?? targetRect.height / 2);
721
+ } else {
722
+ throw new Error("Drag requires either target or targetPosition");
723
+ }
724
+ const steps = options?.steps ?? 10;
725
+ const holdDelay = options?.holdDelay ?? 100;
726
+ const releaseDelay = options?.releaseDelay ?? 50;
727
+ sourceElement.dispatchEvent(createMouseEventAt("mousedown", sourceX, sourceY));
728
+ const canHTML5 = options?.html5 && typeof DragEvent !== "undefined";
729
+ if (canHTML5) {
730
+ sourceElement.dispatchEvent(
731
+ new DragEvent("dragstart", {
732
+ bubbles: true,
733
+ cancelable: true,
734
+ clientX: sourceX,
735
+ clientY: sourceY
736
+ })
737
+ );
738
+ }
739
+ if (holdDelay > 0) {
740
+ await sleep(holdDelay);
741
+ }
742
+ for (let i = 1; i <= steps; i++) {
743
+ const progress = i / steps;
744
+ const currentX = sourceX + (targetX - sourceX) * progress;
745
+ const currentY = sourceY + (targetY - sourceY) * progress;
746
+ const dispatchTarget = elementFromPointSafe(currentX, currentY) || sourceElement;
747
+ dispatchTarget.dispatchEvent(createMouseEventAt("mousemove", currentX, currentY));
748
+ if (canHTML5) {
749
+ dispatchTarget.dispatchEvent(
750
+ new DragEvent("dragover", {
751
+ bubbles: true,
752
+ cancelable: true,
753
+ clientX: currentX,
754
+ clientY: currentY
755
+ })
756
+ );
757
+ }
758
+ }
759
+ const dropTarget = elementFromPointSafe(targetX, targetY) || sourceElement;
760
+ dropTarget.dispatchEvent(createMouseEventAt("mouseup", targetX, targetY));
761
+ if (canHTML5) {
762
+ dropTarget.dispatchEvent(
763
+ new DragEvent("drop", {
764
+ bubbles: true,
765
+ cancelable: true,
766
+ clientX: targetX,
767
+ clientY: targetY
768
+ })
769
+ );
770
+ sourceElement.dispatchEvent(
771
+ new DragEvent("dragend", {
772
+ bubbles: true,
773
+ cancelable: true,
774
+ clientX: targetX,
775
+ clientY: targetY
776
+ })
777
+ );
778
+ }
779
+ if (releaseDelay > 0) {
780
+ await sleep(releaseDelay);
781
+ }
782
+ }
783
+ /**
784
+ * Resolve a drag target element from a target descriptor.
785
+ */
786
+ resolveTargetElement(target) {
787
+ if (target.elementId) {
788
+ const registered = this.registry.getElement(target.elementId);
789
+ if (registered?.element) return registered.element;
790
+ return findElementByIdentifier(target.elementId);
791
+ }
792
+ if (target.selector) {
793
+ return document.querySelector(target.selector);
794
+ }
795
+ return null;
796
+ }
569
797
  getElementId(element) {
570
798
  return element.getAttribute("data-ui-id") || element.getAttribute("data-testid") || element.id || `${element.tagName.toLowerCase()}-${Math.random().toString(36).substr(2, 8)}`;
571
799
  }
@@ -661,8 +889,8 @@ var DefaultActionExecutor = class {
661
889
  }
662
890
  }
663
891
  };
664
- function createActionExecutor(registry) {
665
- return new DefaultActionExecutor(registry);
892
+ function createActionExecutor(registry, consoleCapture) {
893
+ return new DefaultActionExecutor(registry, consoleCapture);
666
894
  }
667
895
 
668
896
  // src/control/workflow-engine.ts