@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.
- package/dist/control/{action-executor.d.ts → index.d.mts} +14 -6
- package/dist/control/index.d.ts +95 -5
- package/dist/control/index.js +74 -11
- package/dist/control/index.js.map +1 -1
- package/dist/control/index.mjs +74 -11
- package/dist/control/index.mjs.map +1 -1
- package/dist/core/index.d.mts +46 -0
- package/dist/core/index.d.ts +43 -6
- package/dist/core/index.js +69 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +69 -1
- package/dist/core/index.mjs.map +1 -1
- package/dist/debug/{inspector.d.ts → index.d.mts} +6 -3
- package/dist/debug/index.d.ts +44 -4
- package/dist/debug/index.js.map +1 -1
- package/dist/debug/index.mjs.map +1 -1
- package/dist/design/{design-inspector-native.d.ts → index.d.mts} +11 -7
- package/dist/design/index.d.ts +60 -5
- package/dist/{design/design-types.d.ts → design-types-BHr6Q1FX.d.mts} +11 -10
- package/dist/design-types-BHr6Q1FX.d.ts +205 -0
- package/dist/http-server-DCdR8WlL.d.mts +622 -0
- package/dist/http-server-Dj3grQW4.d.ts +622 -0
- package/dist/index.d.mts +89 -0
- package/dist/index.d.ts +86 -28
- package/dist/index.js +391 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +386 -13
- package/dist/index.mjs.map +1 -1
- package/dist/react/{useAutoRegister.d.ts → index.d.mts} +15 -7
- package/dist/react/index.d.ts +69 -8
- package/dist/react/index.js +388 -12
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +386 -13
- package/dist/react/index.mjs.map +1 -1
- package/dist/registry-Cahd8Gn2.d.mts +230 -0
- package/dist/{core/registry.d.ts → registry-z-3WJsxp.d.ts} +28 -10
- package/dist/server/index.d.mts +119 -0
- package/dist/server/index.d.ts +117 -13
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs.map +1 -1
- package/dist/types-DAfCeWXc.d.mts +197 -0
- package/dist/{core/types.d.ts → types-Oz13YLZq.d.mts} +124 -30
- package/dist/types-Oz13YLZq.d.ts +477 -0
- package/dist/{control/types.d.ts → types-ajakyp-l.d.ts} +36 -15
- package/dist/useUIBridgeToast-D32KXyL1.d.ts +720 -0
- package/dist/useUIBridgeToast-GmT1TzUe.d.mts +720 -0
- package/package.json +1 -1
- package/dist/control/action-executor.d.ts.map +0 -1
- package/dist/control/index.d.ts.map +0 -1
- package/dist/control/types.d.ts.map +0 -1
- package/dist/core/element-identifier.d.ts +0 -41
- package/dist/core/element-identifier.d.ts.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/registry.d.ts.map +0 -1
- package/dist/core/types.d.ts.map +0 -1
- package/dist/debug/index.d.ts.map +0 -1
- package/dist/debug/inspector.d.ts.map +0 -1
- package/dist/design/design-inspector-native.d.ts.map +0 -1
- package/dist/design/design-types.d.ts.map +0 -1
- package/dist/design/index.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/react/UIBridgeNativeProvider.d.ts +0 -147
- package/dist/react/UIBridgeNativeProvider.d.ts.map +0 -1
- package/dist/react/index.d.ts.map +0 -1
- package/dist/react/useAutoRegister.d.ts.map +0 -1
- package/dist/react/useUIBridge.d.ts +0 -103
- package/dist/react/useUIBridge.d.ts.map +0 -1
- package/dist/react/useUIComponent.d.ts +0 -112
- package/dist/react/useUIComponent.d.ts.map +0 -1
- package/dist/react/useUIElement.d.ts +0 -162
- package/dist/react/useUIElement.d.ts.map +0 -1
- package/dist/server/design-handlers.d.ts +0 -47
- package/dist/server/design-handlers.d.ts.map +0 -1
- package/dist/server/handlers.d.ts +0 -20
- package/dist/server/handlers.d.ts.map +0 -1
- package/dist/server/http-server.d.ts +0 -247
- package/dist/server/http-server.d.ts.map +0 -1
- package/dist/server/index.d.ts.map +0 -1
- package/dist/server/types.d.ts +0 -200
- package/dist/server/types.d.ts.map +0 -1
- package/dist/server/ws-connection.d.ts +0 -48
- package/dist/server/ws-connection.d.ts.map +0 -1
- package/dist/server/ws-event-bridge.d.ts +0 -113
- package/dist/server/ws-event-bridge.d.ts.map +0 -1
- package/dist/server/ws-protocol.d.ts +0 -48
- package/dist/server/ws-protocol.d.ts.map +0 -1
- package/dist/server/ws-types.d.ts +0 -65
- package/dist/server/ws-types.d.ts.map +0 -1
- package/dist/transport/CloudRelayClient.d.ts +0 -51
- package/dist/transport/CloudRelayClient.d.ts.map +0 -1
- package/dist/transport/DeviceAnnouncer.d.ts +0 -75
- package/dist/transport/DeviceAnnouncer.d.ts.map +0 -1
- package/dist/transport/index.d.ts +0 -3
- package/dist/transport/index.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -55,9 +55,34 @@ var NativeUIBridgeRegistry = class {
|
|
|
55
55
|
this.components = /* @__PURE__ */ new Map();
|
|
56
56
|
this.workflows = /* @__PURE__ */ new Map();
|
|
57
57
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
58
|
+
this.enrichers = {};
|
|
59
|
+
this.snapshotExtras = /* @__PURE__ */ new Map();
|
|
58
60
|
this.config = config;
|
|
59
61
|
}
|
|
60
62
|
// ============================================================================
|
|
63
|
+
// Snapshot Enricher Slots
|
|
64
|
+
// ============================================================================
|
|
65
|
+
/**
|
|
66
|
+
* Register/replace canonical enrichers (modal/toast/undo). HMR-safe — calling
|
|
67
|
+
* with a partial set merges into existing slots instead of clobbering them.
|
|
68
|
+
*/
|
|
69
|
+
setEnrichers(e) {
|
|
70
|
+
this.enrichers = { ...this.enrichers, ...e };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Register a custom snapshot enricher. The returned object will be
|
|
74
|
+
* `Object.assign`ed onto the snapshot, so use unique top-level keys to avoid
|
|
75
|
+
* clobbering canonical fields. Returns a disposer.
|
|
76
|
+
*/
|
|
77
|
+
registerSnapshotEnricher(name, fn) {
|
|
78
|
+
this.snapshotExtras.set(name, fn);
|
|
79
|
+
return () => this.unregisterSnapshotEnricher(name);
|
|
80
|
+
}
|
|
81
|
+
/** Remove a custom snapshot enricher by name */
|
|
82
|
+
unregisterSnapshotEnricher(name) {
|
|
83
|
+
this.snapshotExtras.delete(name);
|
|
84
|
+
}
|
|
85
|
+
// ============================================================================
|
|
61
86
|
// Element Management
|
|
62
87
|
// ============================================================================
|
|
63
88
|
/**
|
|
@@ -420,7 +445,7 @@ var NativeUIBridgeRegistry = class {
|
|
|
420
445
|
const currentRoute = routeInfo.currentRoute;
|
|
421
446
|
elements = elements.filter((e) => e.registrationRoute === currentRoute);
|
|
422
447
|
}
|
|
423
|
-
|
|
448
|
+
const snapshot = {
|
|
424
449
|
timestamp: Date.now(),
|
|
425
450
|
elements: elements.map((e) => {
|
|
426
451
|
const handlers = extractHandlerNames(e.props);
|
|
@@ -452,6 +477,49 @@ var NativeUIBridgeRegistry = class {
|
|
|
452
477
|
currentRoute: routeInfo?.currentRoute ?? null,
|
|
453
478
|
segments: routeInfo?.segments
|
|
454
479
|
};
|
|
480
|
+
if (this.enrichers.modalDetector) {
|
|
481
|
+
try {
|
|
482
|
+
snapshot.modalStack = this.enrichers.modalDetector.getSnapshotModalContext();
|
|
483
|
+
} catch (error3) {
|
|
484
|
+
if (this.config.verbose) {
|
|
485
|
+
console.warn(`[ui-bridge-native] modalDetector enricher threw:`, error3);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (this.enrichers.toastCapture) {
|
|
490
|
+
try {
|
|
491
|
+
snapshot.toasts = this.enrichers.toastCapture.getSnapshotToastContext();
|
|
492
|
+
} catch (error3) {
|
|
493
|
+
if (this.config.verbose) {
|
|
494
|
+
console.warn(`[ui-bridge-native] toastCapture enricher threw:`, error3);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
if (this.enrichers.undoTracker) {
|
|
499
|
+
try {
|
|
500
|
+
snapshot.undoRedo = this.enrichers.undoTracker.getSnapshotUndoContext();
|
|
501
|
+
} catch (error3) {
|
|
502
|
+
if (this.config.verbose) {
|
|
503
|
+
console.warn(`[ui-bridge-native] undoTracker enricher threw:`, error3);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (this.snapshotExtras.size > 0) {
|
|
508
|
+
const ctx = { elements, currentRoute: routeInfo?.currentRoute ?? null };
|
|
509
|
+
for (const [name, fn] of this.snapshotExtras) {
|
|
510
|
+
try {
|
|
511
|
+
const extra = fn(ctx);
|
|
512
|
+
if (extra && typeof extra === "object") {
|
|
513
|
+
Object.assign(snapshot, extra);
|
|
514
|
+
}
|
|
515
|
+
} catch (error3) {
|
|
516
|
+
if (this.config.verbose) {
|
|
517
|
+
console.warn(`[ui-bridge-native] snapshot enricher "${name}" threw:`, error3);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return snapshot;
|
|
455
523
|
}
|
|
456
524
|
/**
|
|
457
525
|
* Get registry statistics
|
|
@@ -597,6 +665,23 @@ function sleep(ms) {
|
|
|
597
665
|
var DefaultNativeActionExecutor = class {
|
|
598
666
|
constructor(registry) {
|
|
599
667
|
this.registry = registry;
|
|
668
|
+
this.actionListeners = /* @__PURE__ */ new Set();
|
|
669
|
+
}
|
|
670
|
+
onActionExecuted(listener) {
|
|
671
|
+
this.actionListeners.add(listener);
|
|
672
|
+
return () => {
|
|
673
|
+
this.actionListeners.delete(listener);
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
/** Notify listeners out-of-band; isolate each invocation so one bad listener can't poison the rest. */
|
|
677
|
+
emitActionEvent(event) {
|
|
678
|
+
for (const listener of this.actionListeners) {
|
|
679
|
+
try {
|
|
680
|
+
listener(event);
|
|
681
|
+
} catch (error3) {
|
|
682
|
+
console.warn(`[ui-bridge-native] Action listener error:`, error3);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
600
685
|
}
|
|
601
686
|
/**
|
|
602
687
|
* Execute an action on an element
|
|
@@ -610,11 +695,23 @@ var DefaultNativeActionExecutor = class {
|
|
|
610
695
|
registered = findElementByIdentifier(elementId) ?? void 0;
|
|
611
696
|
}
|
|
612
697
|
if (!registered) {
|
|
698
|
+
const failTime = Date.now();
|
|
699
|
+
const errorMsg = `Element not found: ${elementId}`;
|
|
700
|
+
this.emitActionEvent({
|
|
701
|
+
elementId,
|
|
702
|
+
action: request.action,
|
|
703
|
+
params: request.params,
|
|
704
|
+
success: false,
|
|
705
|
+
error: errorMsg,
|
|
706
|
+
timestamp: failTime,
|
|
707
|
+
requestId: request.requestId,
|
|
708
|
+
durationMs: failTime - startTime
|
|
709
|
+
});
|
|
613
710
|
return {
|
|
614
711
|
success: false,
|
|
615
|
-
error:
|
|
616
|
-
durationMs:
|
|
617
|
-
timestamp:
|
|
712
|
+
error: errorMsg,
|
|
713
|
+
durationMs: failTime - startTime,
|
|
714
|
+
timestamp: failTime,
|
|
618
715
|
requestId: request.requestId
|
|
619
716
|
};
|
|
620
717
|
}
|
|
@@ -622,33 +719,67 @@ var DefaultNativeActionExecutor = class {
|
|
|
622
719
|
const waitResult = await this.waitForElementInternal(registered.id, request.waitOptions);
|
|
623
720
|
waitDurationMs = waitResult.waitedMs;
|
|
624
721
|
if (!waitResult.met) {
|
|
722
|
+
const failTime = Date.now();
|
|
723
|
+
const errorMsg = waitResult.error || "Wait condition not met";
|
|
724
|
+
this.emitActionEvent({
|
|
725
|
+
elementId,
|
|
726
|
+
action: request.action,
|
|
727
|
+
params: request.params,
|
|
728
|
+
success: false,
|
|
729
|
+
error: errorMsg,
|
|
730
|
+
timestamp: failTime,
|
|
731
|
+
requestId: request.requestId,
|
|
732
|
+
durationMs: failTime - startTime
|
|
733
|
+
});
|
|
625
734
|
return {
|
|
626
735
|
success: false,
|
|
627
|
-
error:
|
|
628
|
-
durationMs:
|
|
629
|
-
timestamp:
|
|
736
|
+
error: errorMsg,
|
|
737
|
+
durationMs: failTime - startTime,
|
|
738
|
+
timestamp: failTime,
|
|
630
739
|
requestId: request.requestId,
|
|
631
740
|
waitDurationMs
|
|
632
741
|
};
|
|
633
742
|
}
|
|
634
743
|
}
|
|
635
744
|
const result = await this.performAction(registered, request.action, request.params);
|
|
745
|
+
const successTime = Date.now();
|
|
746
|
+
this.emitActionEvent({
|
|
747
|
+
elementId,
|
|
748
|
+
action: request.action,
|
|
749
|
+
params: request.params,
|
|
750
|
+
success: true,
|
|
751
|
+
timestamp: successTime,
|
|
752
|
+
requestId: request.requestId,
|
|
753
|
+
durationMs: successTime - startTime
|
|
754
|
+
});
|
|
636
755
|
return {
|
|
637
756
|
success: true,
|
|
638
757
|
elementState: registered.getState(),
|
|
639
758
|
result,
|
|
640
|
-
durationMs:
|
|
641
|
-
timestamp:
|
|
759
|
+
durationMs: successTime - startTime,
|
|
760
|
+
timestamp: successTime,
|
|
642
761
|
requestId: request.requestId,
|
|
643
762
|
waitDurationMs
|
|
644
763
|
};
|
|
645
764
|
} catch (error3) {
|
|
765
|
+
const failTime = Date.now();
|
|
766
|
+
const errorMsg = error3 instanceof Error ? error3.message : String(error3);
|
|
767
|
+
this.emitActionEvent({
|
|
768
|
+
elementId,
|
|
769
|
+
action: request.action,
|
|
770
|
+
params: request.params,
|
|
771
|
+
success: false,
|
|
772
|
+
error: errorMsg,
|
|
773
|
+
timestamp: failTime,
|
|
774
|
+
requestId: request.requestId,
|
|
775
|
+
durationMs: failTime - startTime
|
|
776
|
+
});
|
|
646
777
|
return {
|
|
647
778
|
success: false,
|
|
648
|
-
error:
|
|
779
|
+
error: errorMsg,
|
|
649
780
|
stack: error3 instanceof Error ? error3.stack : void 0,
|
|
650
|
-
durationMs:
|
|
651
|
-
timestamp:
|
|
781
|
+
durationMs: failTime - startTime,
|
|
782
|
+
timestamp: failTime,
|
|
652
783
|
requestId: request.requestId,
|
|
653
784
|
waitDurationMs
|
|
654
785
|
};
|
|
@@ -3566,6 +3697,186 @@ function parseQueryParams(path) {
|
|
|
3566
3697
|
}
|
|
3567
3698
|
return result;
|
|
3568
3699
|
}
|
|
3700
|
+
|
|
3701
|
+
// src/modal/modal-detector.ts
|
|
3702
|
+
var ModalDetector = class {
|
|
3703
|
+
constructor() {
|
|
3704
|
+
/** Map preserves O(1) idempotent replace by id; ordering comes from detectedAt. */
|
|
3705
|
+
this.modals = /* @__PURE__ */ new Map();
|
|
3706
|
+
}
|
|
3707
|
+
pushModal(modal) {
|
|
3708
|
+
const existing = this.modals.get(modal.id);
|
|
3709
|
+
const detectedAt = existing ? existing.detectedAt : Date.now();
|
|
3710
|
+
const next = {
|
|
3711
|
+
id: modal.id,
|
|
3712
|
+
title: modal.title,
|
|
3713
|
+
type: modal.type ?? "modal",
|
|
3714
|
+
blocking: modal.blocking ?? true,
|
|
3715
|
+
dismissible: modal.dismissible ?? true,
|
|
3716
|
+
detectedAt
|
|
3717
|
+
};
|
|
3718
|
+
this.modals.set(modal.id, next);
|
|
3719
|
+
}
|
|
3720
|
+
dismissModal(id) {
|
|
3721
|
+
this.modals.delete(id);
|
|
3722
|
+
}
|
|
3723
|
+
getSnapshotModalContext() {
|
|
3724
|
+
const active = this.getActive();
|
|
3725
|
+
const ctx = {
|
|
3726
|
+
modals: active,
|
|
3727
|
+
hasBlockingModal: active.some((m) => m.blocking),
|
|
3728
|
+
count: active.length
|
|
3729
|
+
};
|
|
3730
|
+
if (active.length > 0) {
|
|
3731
|
+
ctx.topModal = active[active.length - 1];
|
|
3732
|
+
}
|
|
3733
|
+
return ctx;
|
|
3734
|
+
}
|
|
3735
|
+
getActive() {
|
|
3736
|
+
return Array.from(this.modals.values()).sort((a, b) => a.detectedAt - b.detectedAt);
|
|
3737
|
+
}
|
|
3738
|
+
clear() {
|
|
3739
|
+
this.modals.clear();
|
|
3740
|
+
}
|
|
3741
|
+
};
|
|
3742
|
+
|
|
3743
|
+
// src/toast/toast-capture.ts
|
|
3744
|
+
var DEFAULT_MAX_RECENT = 50;
|
|
3745
|
+
var ToastCapture = class {
|
|
3746
|
+
constructor(config = {}) {
|
|
3747
|
+
this.active = /* @__PURE__ */ new Map();
|
|
3748
|
+
this.recent = [];
|
|
3749
|
+
this.totalCaptured = 0;
|
|
3750
|
+
this.maxRecent = config.maxRecent ?? DEFAULT_MAX_RECENT;
|
|
3751
|
+
}
|
|
3752
|
+
recordToast(toast) {
|
|
3753
|
+
if (this.active.has(toast.id)) {
|
|
3754
|
+
return;
|
|
3755
|
+
}
|
|
3756
|
+
const appearedAt = toast.appearedAt ?? Date.now();
|
|
3757
|
+
const entry = {
|
|
3758
|
+
id: toast.id,
|
|
3759
|
+
message: toast.message,
|
|
3760
|
+
level: toast.level ?? "info",
|
|
3761
|
+
appearedAt,
|
|
3762
|
+
visible: true,
|
|
3763
|
+
durationMs: 0
|
|
3764
|
+
};
|
|
3765
|
+
this.active.set(toast.id, entry);
|
|
3766
|
+
this.totalCaptured += 1;
|
|
3767
|
+
}
|
|
3768
|
+
dismissToast(id) {
|
|
3769
|
+
const entry = this.active.get(id);
|
|
3770
|
+
if (!entry) {
|
|
3771
|
+
return;
|
|
3772
|
+
}
|
|
3773
|
+
this.active.delete(id);
|
|
3774
|
+
const dismissedAt = Date.now();
|
|
3775
|
+
const dismissed = {
|
|
3776
|
+
...entry,
|
|
3777
|
+
dismissedAt,
|
|
3778
|
+
visible: false,
|
|
3779
|
+
durationMs: dismissedAt - entry.appearedAt
|
|
3780
|
+
};
|
|
3781
|
+
this.recent.push(dismissed);
|
|
3782
|
+
if (this.recent.length > this.maxRecent) {
|
|
3783
|
+
this.recent.shift();
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
getSnapshotToastContext() {
|
|
3787
|
+
const now = Date.now();
|
|
3788
|
+
const active = Array.from(this.active.values()).map((entry) => ({
|
|
3789
|
+
...entry,
|
|
3790
|
+
durationMs: now - entry.appearedAt
|
|
3791
|
+
}));
|
|
3792
|
+
return {
|
|
3793
|
+
active,
|
|
3794
|
+
recent: [...this.recent],
|
|
3795
|
+
totalCaptured: this.totalCaptured
|
|
3796
|
+
};
|
|
3797
|
+
}
|
|
3798
|
+
clear() {
|
|
3799
|
+
this.active.clear();
|
|
3800
|
+
this.recent = [];
|
|
3801
|
+
this.totalCaptured = 0;
|
|
3802
|
+
}
|
|
3803
|
+
};
|
|
3804
|
+
|
|
3805
|
+
// src/undo/undo-tracker.ts
|
|
3806
|
+
var DEFAULT_MAX_HISTORY = 50;
|
|
3807
|
+
function buildSummary(ctx) {
|
|
3808
|
+
if (!ctx.canUndo && !ctx.canRedo) {
|
|
3809
|
+
return "no undo available";
|
|
3810
|
+
}
|
|
3811
|
+
const parts = [];
|
|
3812
|
+
if (ctx.canUndo) {
|
|
3813
|
+
parts.push(`undo: '${ctx.undoDescription ?? "available"}'`);
|
|
3814
|
+
}
|
|
3815
|
+
if (ctx.canRedo) {
|
|
3816
|
+
parts.push(`redo: '${ctx.redoDescription ?? "available"}'`);
|
|
3817
|
+
}
|
|
3818
|
+
return parts.join(" / ");
|
|
3819
|
+
}
|
|
3820
|
+
var UndoTracker = class {
|
|
3821
|
+
constructor(config = {}) {
|
|
3822
|
+
this.actions = [];
|
|
3823
|
+
this.declaredState = null;
|
|
3824
|
+
this.maxHistory = config.maxHistory ?? DEFAULT_MAX_HISTORY;
|
|
3825
|
+
}
|
|
3826
|
+
recordAction(record) {
|
|
3827
|
+
this.actions.push(record);
|
|
3828
|
+
if (this.actions.length > this.maxHistory) {
|
|
3829
|
+
this.actions = this.actions.slice(-this.maxHistory);
|
|
3830
|
+
}
|
|
3831
|
+
}
|
|
3832
|
+
setDeclaredState(state) {
|
|
3833
|
+
this.declaredState = state;
|
|
3834
|
+
}
|
|
3835
|
+
getActionHistory() {
|
|
3836
|
+
return this.actions.slice();
|
|
3837
|
+
}
|
|
3838
|
+
getSnapshotUndoContext() {
|
|
3839
|
+
const declared = this.declaredState;
|
|
3840
|
+
if (declared) {
|
|
3841
|
+
const summary2 = buildSummary({
|
|
3842
|
+
canUndo: declared.canUndo,
|
|
3843
|
+
canRedo: declared.canRedo,
|
|
3844
|
+
undoDescription: declared.undoDescription,
|
|
3845
|
+
redoDescription: declared.redoDescription
|
|
3846
|
+
});
|
|
3847
|
+
return {
|
|
3848
|
+
canUndo: declared.canUndo,
|
|
3849
|
+
canRedo: declared.canRedo,
|
|
3850
|
+
undoDescription: declared.undoDescription,
|
|
3851
|
+
redoDescription: declared.redoDescription,
|
|
3852
|
+
undoDepth: declared.undoDepth,
|
|
3853
|
+
redoDepth: declared.redoDepth,
|
|
3854
|
+
summary: summary2
|
|
3855
|
+
};
|
|
3856
|
+
}
|
|
3857
|
+
const canUndo = this.actions.some((a) => a.reversible !== false);
|
|
3858
|
+
const canRedo = false;
|
|
3859
|
+
const lastReversible = [...this.actions].reverse().find((a) => a.reversible !== false);
|
|
3860
|
+
const undoDescription = lastReversible?.description;
|
|
3861
|
+
const summary = buildSummary({ canUndo, canRedo, undoDescription });
|
|
3862
|
+
return {
|
|
3863
|
+
canUndo,
|
|
3864
|
+
canRedo,
|
|
3865
|
+
undoDescription,
|
|
3866
|
+
summary
|
|
3867
|
+
};
|
|
3868
|
+
}
|
|
3869
|
+
executeUndo() {
|
|
3870
|
+
return { ok: false, reason: "Not implemented in native" };
|
|
3871
|
+
}
|
|
3872
|
+
executeRedo() {
|
|
3873
|
+
return { ok: false, reason: "Not implemented in native" };
|
|
3874
|
+
}
|
|
3875
|
+
clear() {
|
|
3876
|
+
this.actions = [];
|
|
3877
|
+
this.declaredState = null;
|
|
3878
|
+
}
|
|
3879
|
+
};
|
|
3569
3880
|
var UIBridgeNativeContext = react.createContext(null);
|
|
3570
3881
|
function UIBridgeNativeProvider({
|
|
3571
3882
|
children,
|
|
@@ -3582,6 +3893,9 @@ function UIBridgeNativeProvider({
|
|
|
3582
3893
|
}) {
|
|
3583
3894
|
const registryRef = react.useRef(null);
|
|
3584
3895
|
const executorRef = react.useRef(null);
|
|
3896
|
+
const modalDetectorRef = react.useRef(null);
|
|
3897
|
+
const toastCaptureRef = react.useRef(null);
|
|
3898
|
+
const undoTrackerRef = react.useRef(null);
|
|
3585
3899
|
const [serverRunning, setServerRunning] = react.useState(false);
|
|
3586
3900
|
if (!registryRef.current) {
|
|
3587
3901
|
registryRef.current = new NativeUIBridgeRegistry({
|
|
@@ -3595,6 +3909,12 @@ function UIBridgeNativeProvider({
|
|
|
3595
3909
|
executorRef.current = createNativeActionExecutor(registry);
|
|
3596
3910
|
}
|
|
3597
3911
|
const executor = executorRef.current;
|
|
3912
|
+
if (!modalDetectorRef.current) modalDetectorRef.current = new ModalDetector();
|
|
3913
|
+
if (!toastCaptureRef.current) toastCaptureRef.current = new ToastCapture();
|
|
3914
|
+
if (!undoTrackerRef.current) undoTrackerRef.current = new UndoTracker();
|
|
3915
|
+
const modalDetector = modalDetectorRef.current;
|
|
3916
|
+
const toastCapture = toastCaptureRef.current;
|
|
3917
|
+
const undoTracker = undoTrackerRef.current;
|
|
3598
3918
|
const serverRef = react.useRef(null);
|
|
3599
3919
|
const eventBridgeRef = react.useRef(null);
|
|
3600
3920
|
const announcerRef = react.useRef(null);
|
|
@@ -3783,6 +4103,22 @@ function UIBridgeNativeProvider({
|
|
|
3783
4103
|
lastRoute = current;
|
|
3784
4104
|
});
|
|
3785
4105
|
}, [routeProvider, registry]);
|
|
4106
|
+
react.useEffect(() => {
|
|
4107
|
+
registry.setEnrichers({ modalDetector, toastCapture, undoTracker });
|
|
4108
|
+
}, [registry, modalDetector, toastCapture, undoTracker]);
|
|
4109
|
+
react.useEffect(() => {
|
|
4110
|
+
const unsubscribe = executor.onActionExecuted((event) => {
|
|
4111
|
+
if (!event.success) return;
|
|
4112
|
+
undoTracker.recordAction({
|
|
4113
|
+
id: event.requestId ?? `action-${event.timestamp}`,
|
|
4114
|
+
type: event.action,
|
|
4115
|
+
targetId: event.elementId,
|
|
4116
|
+
timestamp: event.timestamp,
|
|
4117
|
+
reversible: true
|
|
4118
|
+
});
|
|
4119
|
+
});
|
|
4120
|
+
return unsubscribe;
|
|
4121
|
+
}, [executor, undoTracker]);
|
|
3786
4122
|
const on = react.useCallback(
|
|
3787
4123
|
(type, listener) => registry.on(type, listener),
|
|
3788
4124
|
[registry]
|
|
@@ -3797,6 +4133,9 @@ function UIBridgeNativeProvider({
|
|
|
3797
4133
|
config,
|
|
3798
4134
|
registry,
|
|
3799
4135
|
executor,
|
|
4136
|
+
modalDetector,
|
|
4137
|
+
toastCapture,
|
|
4138
|
+
undoTracker,
|
|
3800
4139
|
getElements,
|
|
3801
4140
|
getComponents,
|
|
3802
4141
|
createSnapshot,
|
|
@@ -3813,6 +4152,9 @@ function UIBridgeNativeProvider({
|
|
|
3813
4152
|
config,
|
|
3814
4153
|
registry,
|
|
3815
4154
|
executor,
|
|
4155
|
+
modalDetector,
|
|
4156
|
+
toastCapture,
|
|
4157
|
+
undoTracker,
|
|
3816
4158
|
getElements,
|
|
3817
4159
|
getComponents,
|
|
3818
4160
|
createSnapshot,
|
|
@@ -4293,6 +4635,37 @@ function useUIBridgeRequired() {
|
|
|
4293
4635
|
}
|
|
4294
4636
|
return result;
|
|
4295
4637
|
}
|
|
4638
|
+
function useUIBridgeModal(opts) {
|
|
4639
|
+
const { modalDetector } = useUIBridgeNative();
|
|
4640
|
+
const { id, title, type, blocking, dismissible } = opts;
|
|
4641
|
+
react.useEffect(() => {
|
|
4642
|
+
modalDetector.pushModal({ id, title, type, blocking, dismissible });
|
|
4643
|
+
return () => {
|
|
4644
|
+
modalDetector.dismissModal(id);
|
|
4645
|
+
};
|
|
4646
|
+
}, [modalDetector, id, title, type, blocking, dismissible]);
|
|
4647
|
+
}
|
|
4648
|
+
function useUIBridgeToast(opts) {
|
|
4649
|
+
const { toastCapture } = useUIBridgeNative();
|
|
4650
|
+
const { id, message, level } = opts;
|
|
4651
|
+
react.useEffect(() => {
|
|
4652
|
+
toastCapture.recordToast({ id, message, level });
|
|
4653
|
+
return () => {
|
|
4654
|
+
toastCapture.dismissToast(id);
|
|
4655
|
+
};
|
|
4656
|
+
}, [toastCapture, id, message, level]);
|
|
4657
|
+
}
|
|
4658
|
+
function useToastRecorder() {
|
|
4659
|
+
const { toastCapture } = useUIBridgeNative();
|
|
4660
|
+
const recordToast = react.useCallback(
|
|
4661
|
+
(toast) => {
|
|
4662
|
+
toastCapture.recordToast(toast);
|
|
4663
|
+
},
|
|
4664
|
+
[toastCapture]
|
|
4665
|
+
);
|
|
4666
|
+
const dismissToast = react.useCallback((id) => toastCapture.dismissToast(id), [toastCapture]);
|
|
4667
|
+
return { recordToast, dismissToast };
|
|
4668
|
+
}
|
|
4296
4669
|
|
|
4297
4670
|
// src/server/types.ts
|
|
4298
4671
|
var UI_BRIDGE_NATIVE_ROUTES = {
|
|
@@ -5197,11 +5570,14 @@ var styles = reactNative.StyleSheet.create({
|
|
|
5197
5570
|
exports.CloudRelayClient = CloudRelayClient;
|
|
5198
5571
|
exports.DefaultNativeActionExecutor = DefaultNativeActionExecutor;
|
|
5199
5572
|
exports.DeviceAnnouncer = DeviceAnnouncer;
|
|
5573
|
+
exports.ModalDetector = ModalDetector;
|
|
5200
5574
|
exports.NativeUIBridgeRegistry = NativeUIBridgeRegistry;
|
|
5201
5575
|
exports.NativeUIBridgeServer = NativeUIBridgeServer;
|
|
5576
|
+
exports.ToastCapture = ToastCapture;
|
|
5202
5577
|
exports.UIBridgeInspector = UIBridgeInspector;
|
|
5203
5578
|
exports.UIBridgeNativeProvider = UIBridgeNativeProvider;
|
|
5204
5579
|
exports.UI_BRIDGE_NATIVE_ROUTES = UI_BRIDGE_NATIVE_ROUTES;
|
|
5580
|
+
exports.UndoTracker = UndoTracker;
|
|
5205
5581
|
exports.WebSocketConnection = WebSocketConnection;
|
|
5206
5582
|
exports.WebSocketEventBridge = WebSocketEventBridge;
|
|
5207
5583
|
exports.buildTreePath = buildTreePath;
|
|
@@ -5224,11 +5600,14 @@ exports.matchesIdentifier = matchesIdentifier;
|
|
|
5224
5600
|
exports.parseTreePath = parseTreePath;
|
|
5225
5601
|
exports.resetGlobalRegistry = resetGlobalRegistry;
|
|
5226
5602
|
exports.setGlobalRegistry = setGlobalRegistry;
|
|
5603
|
+
exports.useToastRecorder = useToastRecorder;
|
|
5227
5604
|
exports.useUIBridge = useUIBridge;
|
|
5605
|
+
exports.useUIBridgeModal = useUIBridgeModal;
|
|
5228
5606
|
exports.useUIBridgeNative = useUIBridgeNative;
|
|
5229
5607
|
exports.useUIBridgeNativeOptional = useUIBridgeNativeOptional;
|
|
5230
5608
|
exports.useUIBridgeNativeRequired = useUIBridgeNativeRequired;
|
|
5231
5609
|
exports.useUIBridgeRequired = useUIBridgeRequired;
|
|
5610
|
+
exports.useUIBridgeToast = useUIBridgeToast;
|
|
5232
5611
|
exports.useUIComponent = useUIComponent;
|
|
5233
5612
|
exports.useUIComponentAction = useUIComponentAction;
|
|
5234
5613
|
exports.useUIElement = useUIElement;
|