@qontinui/ui-bridge-native 0.1.6 → 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.
Files changed (94) hide show
  1. package/dist/control/{action-executor.d.ts → index.d.mts} +14 -6
  2. package/dist/control/index.d.ts +95 -5
  3. package/dist/control/index.js +74 -11
  4. package/dist/control/index.js.map +1 -1
  5. package/dist/control/index.mjs +74 -11
  6. package/dist/control/index.mjs.map +1 -1
  7. package/dist/core/index.d.mts +46 -0
  8. package/dist/core/index.d.ts +43 -6
  9. package/dist/core/index.js +69 -1
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/core/index.mjs +69 -1
  12. package/dist/core/index.mjs.map +1 -1
  13. package/dist/debug/{inspector.d.ts → index.d.mts} +6 -3
  14. package/dist/debug/index.d.ts +44 -4
  15. package/dist/debug/index.js.map +1 -1
  16. package/dist/debug/index.mjs.map +1 -1
  17. package/dist/design/{design-inspector-native.d.ts → index.d.mts} +11 -7
  18. package/dist/design/index.d.ts +60 -5
  19. package/dist/{design/design-types.d.ts → design-types-BHr6Q1FX.d.mts} +11 -10
  20. package/dist/design-types-BHr6Q1FX.d.ts +205 -0
  21. package/dist/http-server-DCdR8WlL.d.mts +622 -0
  22. package/dist/http-server-Dj3grQW4.d.ts +622 -0
  23. package/dist/index.d.mts +89 -0
  24. package/dist/index.d.ts +86 -28
  25. package/dist/index.js +391 -12
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +386 -13
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/react/{useAutoRegister.d.ts → index.d.mts} +15 -7
  30. package/dist/react/index.d.ts +69 -8
  31. package/dist/react/index.js +388 -12
  32. package/dist/react/index.js.map +1 -1
  33. package/dist/react/index.mjs +386 -13
  34. package/dist/react/index.mjs.map +1 -1
  35. package/dist/registry-Cahd8Gn2.d.mts +230 -0
  36. package/dist/{core/registry.d.ts → registry-z-3WJsxp.d.ts} +28 -10
  37. package/dist/server/index.d.mts +119 -0
  38. package/dist/server/index.d.ts +117 -13
  39. package/dist/server/index.js.map +1 -1
  40. package/dist/server/index.mjs.map +1 -1
  41. package/dist/types-DAfCeWXc.d.mts +197 -0
  42. package/dist/{core/types.d.ts → types-Oz13YLZq.d.mts} +124 -30
  43. package/dist/types-Oz13YLZq.d.ts +477 -0
  44. package/dist/{control/types.d.ts → types-ajakyp-l.d.ts} +36 -15
  45. package/dist/useUIBridgeToast-D32KXyL1.d.ts +720 -0
  46. package/dist/useUIBridgeToast-GmT1TzUe.d.mts +720 -0
  47. package/package.json +1 -1
  48. package/dist/control/action-executor.d.ts.map +0 -1
  49. package/dist/control/index.d.ts.map +0 -1
  50. package/dist/control/types.d.ts.map +0 -1
  51. package/dist/core/element-identifier.d.ts +0 -41
  52. package/dist/core/element-identifier.d.ts.map +0 -1
  53. package/dist/core/index.d.ts.map +0 -1
  54. package/dist/core/registry.d.ts.map +0 -1
  55. package/dist/core/types.d.ts.map +0 -1
  56. package/dist/debug/index.d.ts.map +0 -1
  57. package/dist/debug/inspector.d.ts.map +0 -1
  58. package/dist/design/design-inspector-native.d.ts.map +0 -1
  59. package/dist/design/design-types.d.ts.map +0 -1
  60. package/dist/design/index.d.ts.map +0 -1
  61. package/dist/index.d.ts.map +0 -1
  62. package/dist/react/UIBridgeNativeProvider.d.ts +0 -147
  63. package/dist/react/UIBridgeNativeProvider.d.ts.map +0 -1
  64. package/dist/react/index.d.ts.map +0 -1
  65. package/dist/react/useAutoRegister.d.ts.map +0 -1
  66. package/dist/react/useUIBridge.d.ts +0 -103
  67. package/dist/react/useUIBridge.d.ts.map +0 -1
  68. package/dist/react/useUIComponent.d.ts +0 -112
  69. package/dist/react/useUIComponent.d.ts.map +0 -1
  70. package/dist/react/useUIElement.d.ts +0 -162
  71. package/dist/react/useUIElement.d.ts.map +0 -1
  72. package/dist/server/design-handlers.d.ts +0 -47
  73. package/dist/server/design-handlers.d.ts.map +0 -1
  74. package/dist/server/handlers.d.ts +0 -20
  75. package/dist/server/handlers.d.ts.map +0 -1
  76. package/dist/server/http-server.d.ts +0 -247
  77. package/dist/server/http-server.d.ts.map +0 -1
  78. package/dist/server/index.d.ts.map +0 -1
  79. package/dist/server/types.d.ts +0 -200
  80. package/dist/server/types.d.ts.map +0 -1
  81. package/dist/server/ws-connection.d.ts +0 -48
  82. package/dist/server/ws-connection.d.ts.map +0 -1
  83. package/dist/server/ws-event-bridge.d.ts +0 -113
  84. package/dist/server/ws-event-bridge.d.ts.map +0 -1
  85. package/dist/server/ws-protocol.d.ts +0 -48
  86. package/dist/server/ws-protocol.d.ts.map +0 -1
  87. package/dist/server/ws-types.d.ts +0 -65
  88. package/dist/server/ws-types.d.ts.map +0 -1
  89. package/dist/transport/CloudRelayClient.d.ts +0 -51
  90. package/dist/transport/CloudRelayClient.d.ts.map +0 -1
  91. package/dist/transport/DeviceAnnouncer.d.ts +0 -75
  92. package/dist/transport/DeviceAnnouncer.d.ts.map +0 -1
  93. package/dist/transport/index.d.ts +0 -3
  94. package/dist/transport/index.d.ts.map +0 -1
@@ -53,9 +53,34 @@ var NativeUIBridgeRegistry = class {
53
53
  this.components = /* @__PURE__ */ new Map();
54
54
  this.workflows = /* @__PURE__ */ new Map();
55
55
  this.eventListeners = /* @__PURE__ */ new Map();
56
+ this.enrichers = {};
57
+ this.snapshotExtras = /* @__PURE__ */ new Map();
56
58
  this.config = config;
57
59
  }
58
60
  // ============================================================================
61
+ // Snapshot Enricher Slots
62
+ // ============================================================================
63
+ /**
64
+ * Register/replace canonical enrichers (modal/toast/undo). HMR-safe — calling
65
+ * with a partial set merges into existing slots instead of clobbering them.
66
+ */
67
+ setEnrichers(e) {
68
+ this.enrichers = { ...this.enrichers, ...e };
69
+ }
70
+ /**
71
+ * Register a custom snapshot enricher. The returned object will be
72
+ * `Object.assign`ed onto the snapshot, so use unique top-level keys to avoid
73
+ * clobbering canonical fields. Returns a disposer.
74
+ */
75
+ registerSnapshotEnricher(name, fn) {
76
+ this.snapshotExtras.set(name, fn);
77
+ return () => this.unregisterSnapshotEnricher(name);
78
+ }
79
+ /** Remove a custom snapshot enricher by name */
80
+ unregisterSnapshotEnricher(name) {
81
+ this.snapshotExtras.delete(name);
82
+ }
83
+ // ============================================================================
59
84
  // Element Management
60
85
  // ============================================================================
61
86
  /**
@@ -418,7 +443,7 @@ var NativeUIBridgeRegistry = class {
418
443
  const currentRoute = routeInfo.currentRoute;
419
444
  elements = elements.filter((e) => e.registrationRoute === currentRoute);
420
445
  }
421
- return {
446
+ const snapshot = {
422
447
  timestamp: Date.now(),
423
448
  elements: elements.map((e) => {
424
449
  const handlers = extractHandlerNames(e.props);
@@ -450,6 +475,49 @@ var NativeUIBridgeRegistry = class {
450
475
  currentRoute: routeInfo?.currentRoute ?? null,
451
476
  segments: routeInfo?.segments
452
477
  };
478
+ if (this.enrichers.modalDetector) {
479
+ try {
480
+ snapshot.modalStack = this.enrichers.modalDetector.getSnapshotModalContext();
481
+ } catch (error3) {
482
+ if (this.config.verbose) {
483
+ console.warn(`[ui-bridge-native] modalDetector enricher threw:`, error3);
484
+ }
485
+ }
486
+ }
487
+ if (this.enrichers.toastCapture) {
488
+ try {
489
+ snapshot.toasts = this.enrichers.toastCapture.getSnapshotToastContext();
490
+ } catch (error3) {
491
+ if (this.config.verbose) {
492
+ console.warn(`[ui-bridge-native] toastCapture enricher threw:`, error3);
493
+ }
494
+ }
495
+ }
496
+ if (this.enrichers.undoTracker) {
497
+ try {
498
+ snapshot.undoRedo = this.enrichers.undoTracker.getSnapshotUndoContext();
499
+ } catch (error3) {
500
+ if (this.config.verbose) {
501
+ console.warn(`[ui-bridge-native] undoTracker enricher threw:`, error3);
502
+ }
503
+ }
504
+ }
505
+ if (this.snapshotExtras.size > 0) {
506
+ const ctx = { elements, currentRoute: routeInfo?.currentRoute ?? null };
507
+ for (const [name, fn] of this.snapshotExtras) {
508
+ try {
509
+ const extra = fn(ctx);
510
+ if (extra && typeof extra === "object") {
511
+ Object.assign(snapshot, extra);
512
+ }
513
+ } catch (error3) {
514
+ if (this.config.verbose) {
515
+ console.warn(`[ui-bridge-native] snapshot enricher "${name}" threw:`, error3);
516
+ }
517
+ }
518
+ }
519
+ }
520
+ return snapshot;
453
521
  }
454
522
  /**
455
523
  * Get registry statistics
@@ -543,6 +611,23 @@ function sleep(ms) {
543
611
  var DefaultNativeActionExecutor = class {
544
612
  constructor(registry) {
545
613
  this.registry = registry;
614
+ this.actionListeners = /* @__PURE__ */ new Set();
615
+ }
616
+ onActionExecuted(listener) {
617
+ this.actionListeners.add(listener);
618
+ return () => {
619
+ this.actionListeners.delete(listener);
620
+ };
621
+ }
622
+ /** Notify listeners out-of-band; isolate each invocation so one bad listener can't poison the rest. */
623
+ emitActionEvent(event) {
624
+ for (const listener of this.actionListeners) {
625
+ try {
626
+ listener(event);
627
+ } catch (error3) {
628
+ console.warn(`[ui-bridge-native] Action listener error:`, error3);
629
+ }
630
+ }
546
631
  }
547
632
  /**
548
633
  * Execute an action on an element
@@ -556,11 +641,23 @@ var DefaultNativeActionExecutor = class {
556
641
  registered = findElementByIdentifier(elementId) ?? void 0;
557
642
  }
558
643
  if (!registered) {
644
+ const failTime = Date.now();
645
+ const errorMsg = `Element not found: ${elementId}`;
646
+ this.emitActionEvent({
647
+ elementId,
648
+ action: request.action,
649
+ params: request.params,
650
+ success: false,
651
+ error: errorMsg,
652
+ timestamp: failTime,
653
+ requestId: request.requestId,
654
+ durationMs: failTime - startTime
655
+ });
559
656
  return {
560
657
  success: false,
561
- error: `Element not found: ${elementId}`,
562
- durationMs: Date.now() - startTime,
563
- timestamp: Date.now(),
658
+ error: errorMsg,
659
+ durationMs: failTime - startTime,
660
+ timestamp: failTime,
564
661
  requestId: request.requestId
565
662
  };
566
663
  }
@@ -568,33 +665,67 @@ var DefaultNativeActionExecutor = class {
568
665
  const waitResult = await this.waitForElementInternal(registered.id, request.waitOptions);
569
666
  waitDurationMs = waitResult.waitedMs;
570
667
  if (!waitResult.met) {
668
+ const failTime = Date.now();
669
+ const errorMsg = waitResult.error || "Wait condition not met";
670
+ this.emitActionEvent({
671
+ elementId,
672
+ action: request.action,
673
+ params: request.params,
674
+ success: false,
675
+ error: errorMsg,
676
+ timestamp: failTime,
677
+ requestId: request.requestId,
678
+ durationMs: failTime - startTime
679
+ });
571
680
  return {
572
681
  success: false,
573
- error: waitResult.error || "Wait condition not met",
574
- durationMs: Date.now() - startTime,
575
- timestamp: Date.now(),
682
+ error: errorMsg,
683
+ durationMs: failTime - startTime,
684
+ timestamp: failTime,
576
685
  requestId: request.requestId,
577
686
  waitDurationMs
578
687
  };
579
688
  }
580
689
  }
581
690
  const result = await this.performAction(registered, request.action, request.params);
691
+ const successTime = Date.now();
692
+ this.emitActionEvent({
693
+ elementId,
694
+ action: request.action,
695
+ params: request.params,
696
+ success: true,
697
+ timestamp: successTime,
698
+ requestId: request.requestId,
699
+ durationMs: successTime - startTime
700
+ });
582
701
  return {
583
702
  success: true,
584
703
  elementState: registered.getState(),
585
704
  result,
586
- durationMs: Date.now() - startTime,
587
- timestamp: Date.now(),
705
+ durationMs: successTime - startTime,
706
+ timestamp: successTime,
588
707
  requestId: request.requestId,
589
708
  waitDurationMs
590
709
  };
591
710
  } catch (error3) {
711
+ const failTime = Date.now();
712
+ const errorMsg = error3 instanceof Error ? error3.message : String(error3);
713
+ this.emitActionEvent({
714
+ elementId,
715
+ action: request.action,
716
+ params: request.params,
717
+ success: false,
718
+ error: errorMsg,
719
+ timestamp: failTime,
720
+ requestId: request.requestId,
721
+ durationMs: failTime - startTime
722
+ });
592
723
  return {
593
724
  success: false,
594
- error: error3 instanceof Error ? error3.message : String(error3),
725
+ error: errorMsg,
595
726
  stack: error3 instanceof Error ? error3.stack : void 0,
596
- durationMs: Date.now() - startTime,
597
- timestamp: Date.now(),
727
+ durationMs: failTime - startTime,
728
+ timestamp: failTime,
598
729
  requestId: request.requestId,
599
730
  waitDurationMs
600
731
  };
@@ -3512,6 +3643,186 @@ function parseQueryParams(path) {
3512
3643
  }
3513
3644
  return result;
3514
3645
  }
3646
+
3647
+ // src/modal/modal-detector.ts
3648
+ var ModalDetector = class {
3649
+ constructor() {
3650
+ /** Map preserves O(1) idempotent replace by id; ordering comes from detectedAt. */
3651
+ this.modals = /* @__PURE__ */ new Map();
3652
+ }
3653
+ pushModal(modal) {
3654
+ const existing = this.modals.get(modal.id);
3655
+ const detectedAt = existing ? existing.detectedAt : Date.now();
3656
+ const next = {
3657
+ id: modal.id,
3658
+ title: modal.title,
3659
+ type: modal.type ?? "modal",
3660
+ blocking: modal.blocking ?? true,
3661
+ dismissible: modal.dismissible ?? true,
3662
+ detectedAt
3663
+ };
3664
+ this.modals.set(modal.id, next);
3665
+ }
3666
+ dismissModal(id) {
3667
+ this.modals.delete(id);
3668
+ }
3669
+ getSnapshotModalContext() {
3670
+ const active = this.getActive();
3671
+ const ctx = {
3672
+ modals: active,
3673
+ hasBlockingModal: active.some((m) => m.blocking),
3674
+ count: active.length
3675
+ };
3676
+ if (active.length > 0) {
3677
+ ctx.topModal = active[active.length - 1];
3678
+ }
3679
+ return ctx;
3680
+ }
3681
+ getActive() {
3682
+ return Array.from(this.modals.values()).sort((a, b) => a.detectedAt - b.detectedAt);
3683
+ }
3684
+ clear() {
3685
+ this.modals.clear();
3686
+ }
3687
+ };
3688
+
3689
+ // src/toast/toast-capture.ts
3690
+ var DEFAULT_MAX_RECENT = 50;
3691
+ var ToastCapture = class {
3692
+ constructor(config = {}) {
3693
+ this.active = /* @__PURE__ */ new Map();
3694
+ this.recent = [];
3695
+ this.totalCaptured = 0;
3696
+ this.maxRecent = config.maxRecent ?? DEFAULT_MAX_RECENT;
3697
+ }
3698
+ recordToast(toast) {
3699
+ if (this.active.has(toast.id)) {
3700
+ return;
3701
+ }
3702
+ const appearedAt = toast.appearedAt ?? Date.now();
3703
+ const entry = {
3704
+ id: toast.id,
3705
+ message: toast.message,
3706
+ level: toast.level ?? "info",
3707
+ appearedAt,
3708
+ visible: true,
3709
+ durationMs: 0
3710
+ };
3711
+ this.active.set(toast.id, entry);
3712
+ this.totalCaptured += 1;
3713
+ }
3714
+ dismissToast(id) {
3715
+ const entry = this.active.get(id);
3716
+ if (!entry) {
3717
+ return;
3718
+ }
3719
+ this.active.delete(id);
3720
+ const dismissedAt = Date.now();
3721
+ const dismissed = {
3722
+ ...entry,
3723
+ dismissedAt,
3724
+ visible: false,
3725
+ durationMs: dismissedAt - entry.appearedAt
3726
+ };
3727
+ this.recent.push(dismissed);
3728
+ if (this.recent.length > this.maxRecent) {
3729
+ this.recent.shift();
3730
+ }
3731
+ }
3732
+ getSnapshotToastContext() {
3733
+ const now = Date.now();
3734
+ const active = Array.from(this.active.values()).map((entry) => ({
3735
+ ...entry,
3736
+ durationMs: now - entry.appearedAt
3737
+ }));
3738
+ return {
3739
+ active,
3740
+ recent: [...this.recent],
3741
+ totalCaptured: this.totalCaptured
3742
+ };
3743
+ }
3744
+ clear() {
3745
+ this.active.clear();
3746
+ this.recent = [];
3747
+ this.totalCaptured = 0;
3748
+ }
3749
+ };
3750
+
3751
+ // src/undo/undo-tracker.ts
3752
+ var DEFAULT_MAX_HISTORY = 50;
3753
+ function buildSummary(ctx) {
3754
+ if (!ctx.canUndo && !ctx.canRedo) {
3755
+ return "no undo available";
3756
+ }
3757
+ const parts = [];
3758
+ if (ctx.canUndo) {
3759
+ parts.push(`undo: '${ctx.undoDescription ?? "available"}'`);
3760
+ }
3761
+ if (ctx.canRedo) {
3762
+ parts.push(`redo: '${ctx.redoDescription ?? "available"}'`);
3763
+ }
3764
+ return parts.join(" / ");
3765
+ }
3766
+ var UndoTracker = class {
3767
+ constructor(config = {}) {
3768
+ this.actions = [];
3769
+ this.declaredState = null;
3770
+ this.maxHistory = config.maxHistory ?? DEFAULT_MAX_HISTORY;
3771
+ }
3772
+ recordAction(record) {
3773
+ this.actions.push(record);
3774
+ if (this.actions.length > this.maxHistory) {
3775
+ this.actions = this.actions.slice(-this.maxHistory);
3776
+ }
3777
+ }
3778
+ setDeclaredState(state) {
3779
+ this.declaredState = state;
3780
+ }
3781
+ getActionHistory() {
3782
+ return this.actions.slice();
3783
+ }
3784
+ getSnapshotUndoContext() {
3785
+ const declared = this.declaredState;
3786
+ if (declared) {
3787
+ const summary2 = buildSummary({
3788
+ canUndo: declared.canUndo,
3789
+ canRedo: declared.canRedo,
3790
+ undoDescription: declared.undoDescription,
3791
+ redoDescription: declared.redoDescription
3792
+ });
3793
+ return {
3794
+ canUndo: declared.canUndo,
3795
+ canRedo: declared.canRedo,
3796
+ undoDescription: declared.undoDescription,
3797
+ redoDescription: declared.redoDescription,
3798
+ undoDepth: declared.undoDepth,
3799
+ redoDepth: declared.redoDepth,
3800
+ summary: summary2
3801
+ };
3802
+ }
3803
+ const canUndo = this.actions.some((a) => a.reversible !== false);
3804
+ const canRedo = false;
3805
+ const lastReversible = [...this.actions].reverse().find((a) => a.reversible !== false);
3806
+ const undoDescription = lastReversible?.description;
3807
+ const summary = buildSummary({ canUndo, canRedo, undoDescription });
3808
+ return {
3809
+ canUndo,
3810
+ canRedo,
3811
+ undoDescription,
3812
+ summary
3813
+ };
3814
+ }
3815
+ executeUndo() {
3816
+ return { ok: false, reason: "Not implemented in native" };
3817
+ }
3818
+ executeRedo() {
3819
+ return { ok: false, reason: "Not implemented in native" };
3820
+ }
3821
+ clear() {
3822
+ this.actions = [];
3823
+ this.declaredState = null;
3824
+ }
3825
+ };
3515
3826
  var UIBridgeNativeContext = createContext(null);
3516
3827
  function UIBridgeNativeProvider({
3517
3828
  children,
@@ -3528,6 +3839,9 @@ function UIBridgeNativeProvider({
3528
3839
  }) {
3529
3840
  const registryRef = useRef(null);
3530
3841
  const executorRef = useRef(null);
3842
+ const modalDetectorRef = useRef(null);
3843
+ const toastCaptureRef = useRef(null);
3844
+ const undoTrackerRef = useRef(null);
3531
3845
  const [serverRunning, setServerRunning] = useState(false);
3532
3846
  if (!registryRef.current) {
3533
3847
  registryRef.current = new NativeUIBridgeRegistry({
@@ -3541,6 +3855,12 @@ function UIBridgeNativeProvider({
3541
3855
  executorRef.current = createNativeActionExecutor(registry);
3542
3856
  }
3543
3857
  const executor = executorRef.current;
3858
+ if (!modalDetectorRef.current) modalDetectorRef.current = new ModalDetector();
3859
+ if (!toastCaptureRef.current) toastCaptureRef.current = new ToastCapture();
3860
+ if (!undoTrackerRef.current) undoTrackerRef.current = new UndoTracker();
3861
+ const modalDetector = modalDetectorRef.current;
3862
+ const toastCapture = toastCaptureRef.current;
3863
+ const undoTracker = undoTrackerRef.current;
3544
3864
  const serverRef = useRef(null);
3545
3865
  const eventBridgeRef = useRef(null);
3546
3866
  const announcerRef = useRef(null);
@@ -3729,6 +4049,22 @@ function UIBridgeNativeProvider({
3729
4049
  lastRoute = current;
3730
4050
  });
3731
4051
  }, [routeProvider, registry]);
4052
+ useEffect(() => {
4053
+ registry.setEnrichers({ modalDetector, toastCapture, undoTracker });
4054
+ }, [registry, modalDetector, toastCapture, undoTracker]);
4055
+ useEffect(() => {
4056
+ const unsubscribe = executor.onActionExecuted((event) => {
4057
+ if (!event.success) return;
4058
+ undoTracker.recordAction({
4059
+ id: event.requestId ?? `action-${event.timestamp}`,
4060
+ type: event.action,
4061
+ targetId: event.elementId,
4062
+ timestamp: event.timestamp,
4063
+ reversible: true
4064
+ });
4065
+ });
4066
+ return unsubscribe;
4067
+ }, [executor, undoTracker]);
3732
4068
  const on = useCallback(
3733
4069
  (type, listener) => registry.on(type, listener),
3734
4070
  [registry]
@@ -3743,6 +4079,9 @@ function UIBridgeNativeProvider({
3743
4079
  config,
3744
4080
  registry,
3745
4081
  executor,
4082
+ modalDetector,
4083
+ toastCapture,
4084
+ undoTracker,
3746
4085
  getElements,
3747
4086
  getComponents,
3748
4087
  createSnapshot,
@@ -3759,6 +4098,9 @@ function UIBridgeNativeProvider({
3759
4098
  config,
3760
4099
  registry,
3761
4100
  executor,
4101
+ modalDetector,
4102
+ toastCapture,
4103
+ undoTracker,
3762
4104
  getElements,
3763
4105
  getComponents,
3764
4106
  createSnapshot,
@@ -4276,7 +4618,38 @@ function useAutoRegister(options = {}) {
4276
4618
  isEnabled: enabled && !!bridge?.registry
4277
4619
  };
4278
4620
  }
4621
+ function useUIBridgeModal(opts) {
4622
+ const { modalDetector } = useUIBridgeNative();
4623
+ const { id, title, type, blocking, dismissible } = opts;
4624
+ useEffect(() => {
4625
+ modalDetector.pushModal({ id, title, type, blocking, dismissible });
4626
+ return () => {
4627
+ modalDetector.dismissModal(id);
4628
+ };
4629
+ }, [modalDetector, id, title, type, blocking, dismissible]);
4630
+ }
4631
+ function useUIBridgeToast(opts) {
4632
+ const { toastCapture } = useUIBridgeNative();
4633
+ const { id, message, level } = opts;
4634
+ useEffect(() => {
4635
+ toastCapture.recordToast({ id, message, level });
4636
+ return () => {
4637
+ toastCapture.dismissToast(id);
4638
+ };
4639
+ }, [toastCapture, id, message, level]);
4640
+ }
4641
+ function useToastRecorder() {
4642
+ const { toastCapture } = useUIBridgeNative();
4643
+ const recordToast = useCallback(
4644
+ (toast) => {
4645
+ toastCapture.recordToast(toast);
4646
+ },
4647
+ [toastCapture]
4648
+ );
4649
+ const dismissToast = useCallback((id) => toastCapture.dismissToast(id), [toastCapture]);
4650
+ return { recordToast, dismissToast };
4651
+ }
4279
4652
 
4280
- export { UIBridgeNativeProvider, useAutoRegister, useUIBridge, useUIBridgeNative, useUIBridgeNativeOptional, useUIBridgeNativeRequired, useUIBridgeRequired, useUIComponent, useUIComponentAction, useUIElement, useUIElementWithProps };
4653
+ export { UIBridgeNativeProvider, useAutoRegister, useToastRecorder, useUIBridge, useUIBridgeModal, useUIBridgeNative, useUIBridgeNativeOptional, useUIBridgeNativeRequired, useUIBridgeRequired, useUIBridgeToast, useUIComponent, useUIComponentAction, useUIElement, useUIElementWithProps };
4281
4654
  //# sourceMappingURL=index.mjs.map
4282
4655
  //# sourceMappingURL=index.mjs.map