@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
package/dist/index.mjs CHANGED
@@ -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
@@ -595,6 +663,23 @@ function sleep(ms) {
595
663
  var DefaultNativeActionExecutor = class {
596
664
  constructor(registry) {
597
665
  this.registry = registry;
666
+ this.actionListeners = /* @__PURE__ */ new Set();
667
+ }
668
+ onActionExecuted(listener) {
669
+ this.actionListeners.add(listener);
670
+ return () => {
671
+ this.actionListeners.delete(listener);
672
+ };
673
+ }
674
+ /** Notify listeners out-of-band; isolate each invocation so one bad listener can't poison the rest. */
675
+ emitActionEvent(event) {
676
+ for (const listener of this.actionListeners) {
677
+ try {
678
+ listener(event);
679
+ } catch (error3) {
680
+ console.warn(`[ui-bridge-native] Action listener error:`, error3);
681
+ }
682
+ }
598
683
  }
599
684
  /**
600
685
  * Execute an action on an element
@@ -608,11 +693,23 @@ var DefaultNativeActionExecutor = class {
608
693
  registered = findElementByIdentifier(elementId) ?? void 0;
609
694
  }
610
695
  if (!registered) {
696
+ const failTime = Date.now();
697
+ const errorMsg = `Element not found: ${elementId}`;
698
+ this.emitActionEvent({
699
+ elementId,
700
+ action: request.action,
701
+ params: request.params,
702
+ success: false,
703
+ error: errorMsg,
704
+ timestamp: failTime,
705
+ requestId: request.requestId,
706
+ durationMs: failTime - startTime
707
+ });
611
708
  return {
612
709
  success: false,
613
- error: `Element not found: ${elementId}`,
614
- durationMs: Date.now() - startTime,
615
- timestamp: Date.now(),
710
+ error: errorMsg,
711
+ durationMs: failTime - startTime,
712
+ timestamp: failTime,
616
713
  requestId: request.requestId
617
714
  };
618
715
  }
@@ -620,33 +717,67 @@ var DefaultNativeActionExecutor = class {
620
717
  const waitResult = await this.waitForElementInternal(registered.id, request.waitOptions);
621
718
  waitDurationMs = waitResult.waitedMs;
622
719
  if (!waitResult.met) {
720
+ const failTime = Date.now();
721
+ const errorMsg = waitResult.error || "Wait condition not met";
722
+ this.emitActionEvent({
723
+ elementId,
724
+ action: request.action,
725
+ params: request.params,
726
+ success: false,
727
+ error: errorMsg,
728
+ timestamp: failTime,
729
+ requestId: request.requestId,
730
+ durationMs: failTime - startTime
731
+ });
623
732
  return {
624
733
  success: false,
625
- error: waitResult.error || "Wait condition not met",
626
- durationMs: Date.now() - startTime,
627
- timestamp: Date.now(),
734
+ error: errorMsg,
735
+ durationMs: failTime - startTime,
736
+ timestamp: failTime,
628
737
  requestId: request.requestId,
629
738
  waitDurationMs
630
739
  };
631
740
  }
632
741
  }
633
742
  const result = await this.performAction(registered, request.action, request.params);
743
+ const successTime = Date.now();
744
+ this.emitActionEvent({
745
+ elementId,
746
+ action: request.action,
747
+ params: request.params,
748
+ success: true,
749
+ timestamp: successTime,
750
+ requestId: request.requestId,
751
+ durationMs: successTime - startTime
752
+ });
634
753
  return {
635
754
  success: true,
636
755
  elementState: registered.getState(),
637
756
  result,
638
- durationMs: Date.now() - startTime,
639
- timestamp: Date.now(),
757
+ durationMs: successTime - startTime,
758
+ timestamp: successTime,
640
759
  requestId: request.requestId,
641
760
  waitDurationMs
642
761
  };
643
762
  } catch (error3) {
763
+ const failTime = Date.now();
764
+ const errorMsg = error3 instanceof Error ? error3.message : String(error3);
765
+ this.emitActionEvent({
766
+ elementId,
767
+ action: request.action,
768
+ params: request.params,
769
+ success: false,
770
+ error: errorMsg,
771
+ timestamp: failTime,
772
+ requestId: request.requestId,
773
+ durationMs: failTime - startTime
774
+ });
644
775
  return {
645
776
  success: false,
646
- error: error3 instanceof Error ? error3.message : String(error3),
777
+ error: errorMsg,
647
778
  stack: error3 instanceof Error ? error3.stack : void 0,
648
- durationMs: Date.now() - startTime,
649
- timestamp: Date.now(),
779
+ durationMs: failTime - startTime,
780
+ timestamp: failTime,
650
781
  requestId: request.requestId,
651
782
  waitDurationMs
652
783
  };
@@ -3564,6 +3695,186 @@ function parseQueryParams(path) {
3564
3695
  }
3565
3696
  return result;
3566
3697
  }
3698
+
3699
+ // src/modal/modal-detector.ts
3700
+ var ModalDetector = class {
3701
+ constructor() {
3702
+ /** Map preserves O(1) idempotent replace by id; ordering comes from detectedAt. */
3703
+ this.modals = /* @__PURE__ */ new Map();
3704
+ }
3705
+ pushModal(modal) {
3706
+ const existing = this.modals.get(modal.id);
3707
+ const detectedAt = existing ? existing.detectedAt : Date.now();
3708
+ const next = {
3709
+ id: modal.id,
3710
+ title: modal.title,
3711
+ type: modal.type ?? "modal",
3712
+ blocking: modal.blocking ?? true,
3713
+ dismissible: modal.dismissible ?? true,
3714
+ detectedAt
3715
+ };
3716
+ this.modals.set(modal.id, next);
3717
+ }
3718
+ dismissModal(id) {
3719
+ this.modals.delete(id);
3720
+ }
3721
+ getSnapshotModalContext() {
3722
+ const active = this.getActive();
3723
+ const ctx = {
3724
+ modals: active,
3725
+ hasBlockingModal: active.some((m) => m.blocking),
3726
+ count: active.length
3727
+ };
3728
+ if (active.length > 0) {
3729
+ ctx.topModal = active[active.length - 1];
3730
+ }
3731
+ return ctx;
3732
+ }
3733
+ getActive() {
3734
+ return Array.from(this.modals.values()).sort((a, b) => a.detectedAt - b.detectedAt);
3735
+ }
3736
+ clear() {
3737
+ this.modals.clear();
3738
+ }
3739
+ };
3740
+
3741
+ // src/toast/toast-capture.ts
3742
+ var DEFAULT_MAX_RECENT = 50;
3743
+ var ToastCapture = class {
3744
+ constructor(config = {}) {
3745
+ this.active = /* @__PURE__ */ new Map();
3746
+ this.recent = [];
3747
+ this.totalCaptured = 0;
3748
+ this.maxRecent = config.maxRecent ?? DEFAULT_MAX_RECENT;
3749
+ }
3750
+ recordToast(toast) {
3751
+ if (this.active.has(toast.id)) {
3752
+ return;
3753
+ }
3754
+ const appearedAt = toast.appearedAt ?? Date.now();
3755
+ const entry = {
3756
+ id: toast.id,
3757
+ message: toast.message,
3758
+ level: toast.level ?? "info",
3759
+ appearedAt,
3760
+ visible: true,
3761
+ durationMs: 0
3762
+ };
3763
+ this.active.set(toast.id, entry);
3764
+ this.totalCaptured += 1;
3765
+ }
3766
+ dismissToast(id) {
3767
+ const entry = this.active.get(id);
3768
+ if (!entry) {
3769
+ return;
3770
+ }
3771
+ this.active.delete(id);
3772
+ const dismissedAt = Date.now();
3773
+ const dismissed = {
3774
+ ...entry,
3775
+ dismissedAt,
3776
+ visible: false,
3777
+ durationMs: dismissedAt - entry.appearedAt
3778
+ };
3779
+ this.recent.push(dismissed);
3780
+ if (this.recent.length > this.maxRecent) {
3781
+ this.recent.shift();
3782
+ }
3783
+ }
3784
+ getSnapshotToastContext() {
3785
+ const now = Date.now();
3786
+ const active = Array.from(this.active.values()).map((entry) => ({
3787
+ ...entry,
3788
+ durationMs: now - entry.appearedAt
3789
+ }));
3790
+ return {
3791
+ active,
3792
+ recent: [...this.recent],
3793
+ totalCaptured: this.totalCaptured
3794
+ };
3795
+ }
3796
+ clear() {
3797
+ this.active.clear();
3798
+ this.recent = [];
3799
+ this.totalCaptured = 0;
3800
+ }
3801
+ };
3802
+
3803
+ // src/undo/undo-tracker.ts
3804
+ var DEFAULT_MAX_HISTORY = 50;
3805
+ function buildSummary(ctx) {
3806
+ if (!ctx.canUndo && !ctx.canRedo) {
3807
+ return "no undo available";
3808
+ }
3809
+ const parts = [];
3810
+ if (ctx.canUndo) {
3811
+ parts.push(`undo: '${ctx.undoDescription ?? "available"}'`);
3812
+ }
3813
+ if (ctx.canRedo) {
3814
+ parts.push(`redo: '${ctx.redoDescription ?? "available"}'`);
3815
+ }
3816
+ return parts.join(" / ");
3817
+ }
3818
+ var UndoTracker = class {
3819
+ constructor(config = {}) {
3820
+ this.actions = [];
3821
+ this.declaredState = null;
3822
+ this.maxHistory = config.maxHistory ?? DEFAULT_MAX_HISTORY;
3823
+ }
3824
+ recordAction(record) {
3825
+ this.actions.push(record);
3826
+ if (this.actions.length > this.maxHistory) {
3827
+ this.actions = this.actions.slice(-this.maxHistory);
3828
+ }
3829
+ }
3830
+ setDeclaredState(state) {
3831
+ this.declaredState = state;
3832
+ }
3833
+ getActionHistory() {
3834
+ return this.actions.slice();
3835
+ }
3836
+ getSnapshotUndoContext() {
3837
+ const declared = this.declaredState;
3838
+ if (declared) {
3839
+ const summary2 = buildSummary({
3840
+ canUndo: declared.canUndo,
3841
+ canRedo: declared.canRedo,
3842
+ undoDescription: declared.undoDescription,
3843
+ redoDescription: declared.redoDescription
3844
+ });
3845
+ return {
3846
+ canUndo: declared.canUndo,
3847
+ canRedo: declared.canRedo,
3848
+ undoDescription: declared.undoDescription,
3849
+ redoDescription: declared.redoDescription,
3850
+ undoDepth: declared.undoDepth,
3851
+ redoDepth: declared.redoDepth,
3852
+ summary: summary2
3853
+ };
3854
+ }
3855
+ const canUndo = this.actions.some((a) => a.reversible !== false);
3856
+ const canRedo = false;
3857
+ const lastReversible = [...this.actions].reverse().find((a) => a.reversible !== false);
3858
+ const undoDescription = lastReversible?.description;
3859
+ const summary = buildSummary({ canUndo, canRedo, undoDescription });
3860
+ return {
3861
+ canUndo,
3862
+ canRedo,
3863
+ undoDescription,
3864
+ summary
3865
+ };
3866
+ }
3867
+ executeUndo() {
3868
+ return { ok: false, reason: "Not implemented in native" };
3869
+ }
3870
+ executeRedo() {
3871
+ return { ok: false, reason: "Not implemented in native" };
3872
+ }
3873
+ clear() {
3874
+ this.actions = [];
3875
+ this.declaredState = null;
3876
+ }
3877
+ };
3567
3878
  var UIBridgeNativeContext = createContext(null);
3568
3879
  function UIBridgeNativeProvider({
3569
3880
  children,
@@ -3580,6 +3891,9 @@ function UIBridgeNativeProvider({
3580
3891
  }) {
3581
3892
  const registryRef = useRef(null);
3582
3893
  const executorRef = useRef(null);
3894
+ const modalDetectorRef = useRef(null);
3895
+ const toastCaptureRef = useRef(null);
3896
+ const undoTrackerRef = useRef(null);
3583
3897
  const [serverRunning, setServerRunning] = useState(false);
3584
3898
  if (!registryRef.current) {
3585
3899
  registryRef.current = new NativeUIBridgeRegistry({
@@ -3593,6 +3907,12 @@ function UIBridgeNativeProvider({
3593
3907
  executorRef.current = createNativeActionExecutor(registry);
3594
3908
  }
3595
3909
  const executor = executorRef.current;
3910
+ if (!modalDetectorRef.current) modalDetectorRef.current = new ModalDetector();
3911
+ if (!toastCaptureRef.current) toastCaptureRef.current = new ToastCapture();
3912
+ if (!undoTrackerRef.current) undoTrackerRef.current = new UndoTracker();
3913
+ const modalDetector = modalDetectorRef.current;
3914
+ const toastCapture = toastCaptureRef.current;
3915
+ const undoTracker = undoTrackerRef.current;
3596
3916
  const serverRef = useRef(null);
3597
3917
  const eventBridgeRef = useRef(null);
3598
3918
  const announcerRef = useRef(null);
@@ -3781,6 +4101,22 @@ function UIBridgeNativeProvider({
3781
4101
  lastRoute = current;
3782
4102
  });
3783
4103
  }, [routeProvider, registry]);
4104
+ useEffect(() => {
4105
+ registry.setEnrichers({ modalDetector, toastCapture, undoTracker });
4106
+ }, [registry, modalDetector, toastCapture, undoTracker]);
4107
+ useEffect(() => {
4108
+ const unsubscribe = executor.onActionExecuted((event) => {
4109
+ if (!event.success) return;
4110
+ undoTracker.recordAction({
4111
+ id: event.requestId ?? `action-${event.timestamp}`,
4112
+ type: event.action,
4113
+ targetId: event.elementId,
4114
+ timestamp: event.timestamp,
4115
+ reversible: true
4116
+ });
4117
+ });
4118
+ return unsubscribe;
4119
+ }, [executor, undoTracker]);
3784
4120
  const on = useCallback(
3785
4121
  (type, listener) => registry.on(type, listener),
3786
4122
  [registry]
@@ -3795,6 +4131,9 @@ function UIBridgeNativeProvider({
3795
4131
  config,
3796
4132
  registry,
3797
4133
  executor,
4134
+ modalDetector,
4135
+ toastCapture,
4136
+ undoTracker,
3798
4137
  getElements,
3799
4138
  getComponents,
3800
4139
  createSnapshot,
@@ -3811,6 +4150,9 @@ function UIBridgeNativeProvider({
3811
4150
  config,
3812
4151
  registry,
3813
4152
  executor,
4153
+ modalDetector,
4154
+ toastCapture,
4155
+ undoTracker,
3814
4156
  getElements,
3815
4157
  getComponents,
3816
4158
  createSnapshot,
@@ -4291,6 +4633,37 @@ function useUIBridgeRequired() {
4291
4633
  }
4292
4634
  return result;
4293
4635
  }
4636
+ function useUIBridgeModal(opts) {
4637
+ const { modalDetector } = useUIBridgeNative();
4638
+ const { id, title, type, blocking, dismissible } = opts;
4639
+ useEffect(() => {
4640
+ modalDetector.pushModal({ id, title, type, blocking, dismissible });
4641
+ return () => {
4642
+ modalDetector.dismissModal(id);
4643
+ };
4644
+ }, [modalDetector, id, title, type, blocking, dismissible]);
4645
+ }
4646
+ function useUIBridgeToast(opts) {
4647
+ const { toastCapture } = useUIBridgeNative();
4648
+ const { id, message, level } = opts;
4649
+ useEffect(() => {
4650
+ toastCapture.recordToast({ id, message, level });
4651
+ return () => {
4652
+ toastCapture.dismissToast(id);
4653
+ };
4654
+ }, [toastCapture, id, message, level]);
4655
+ }
4656
+ function useToastRecorder() {
4657
+ const { toastCapture } = useUIBridgeNative();
4658
+ const recordToast = useCallback(
4659
+ (toast) => {
4660
+ toastCapture.recordToast(toast);
4661
+ },
4662
+ [toastCapture]
4663
+ );
4664
+ const dismissToast = useCallback((id) => toastCapture.dismissToast(id), [toastCapture]);
4665
+ return { recordToast, dismissToast };
4666
+ }
4294
4667
 
4295
4668
  // src/server/types.ts
4296
4669
  var UI_BRIDGE_NATIVE_ROUTES = {
@@ -5192,6 +5565,6 @@ var styles = StyleSheet.create({
5192
5565
  }
5193
5566
  });
5194
5567
 
5195
- export { CloudRelayClient, DefaultNativeActionExecutor, DeviceAnnouncer, NativeUIBridgeRegistry, NativeUIBridgeServer, UIBridgeInspector, UIBridgeNativeProvider, UI_BRIDGE_NATIVE_ROUTES, WebSocketConnection, WebSocketEventBridge, buildTreePath, buildUpgradeResponse, captureNativeResponsiveSnapshot, captureNativeStateVariations, computeAcceptKey, createDesignHandlers, createNativeActionExecutor, createNativeElementIdentifier, createNativeServer, createServerHandlers, extractHandlerNames, findAllByPattern, findElementByIdentifier, getGlobalRegistry, getNativeElementDesignData, mapNativeStyleToExtended, matchesIdentifier, parseTreePath, resetGlobalRegistry, setGlobalRegistry, useUIBridge, useUIBridgeNative, useUIBridgeNativeOptional, useUIBridgeNativeRequired, useUIBridgeRequired, useUIComponent, useUIComponentAction, useUIElement, useUIElementWithProps };
5568
+ export { CloudRelayClient, DefaultNativeActionExecutor, DeviceAnnouncer, ModalDetector, NativeUIBridgeRegistry, NativeUIBridgeServer, ToastCapture, UIBridgeInspector, UIBridgeNativeProvider, UI_BRIDGE_NATIVE_ROUTES, UndoTracker, WebSocketConnection, WebSocketEventBridge, buildTreePath, buildUpgradeResponse, captureNativeResponsiveSnapshot, captureNativeStateVariations, computeAcceptKey, createDesignHandlers, createNativeActionExecutor, createNativeElementIdentifier, createNativeServer, createServerHandlers, extractHandlerNames, findAllByPattern, findElementByIdentifier, getGlobalRegistry, getNativeElementDesignData, mapNativeStyleToExtended, matchesIdentifier, parseTreePath, resetGlobalRegistry, setGlobalRegistry, useToastRecorder, useUIBridge, useUIBridgeModal, useUIBridgeNative, useUIBridgeNativeOptional, useUIBridgeNativeRequired, useUIBridgeRequired, useUIBridgeToast, useUIComponent, useUIComponentAction, useUIElement, useUIElementWithProps };
5196
5569
  //# sourceMappingURL=index.mjs.map
5197
5570
  //# sourceMappingURL=index.mjs.map