@qontinui/ui-bridge-native 0.6.14 → 0.6.16

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.
@@ -14,4 +14,8 @@ export { useUIBridgeToast, useToastRecorder } from './useUIBridgeToast';
14
14
  export type { UseUIBridgeToastOptions, ToastRecorderInput } from './useUIBridgeToast';
15
15
  export { State, TransitionTo } from './StateAnnotation';
16
16
  export type { StateProps, TransitionToProps, StateAnnotationRequiredElement } from './StateAnnotation';
17
+ export { useRouteAwareness } from './useRouteAwareness';
18
+ export type { UseRouteAwarenessOptions } from './useRouteAwareness';
19
+ export { expoRouterPattern, expoRouterRouteStack, reactNavigationPattern, isExpoRouterUnmatched, } from './routePattern';
20
+ export type { NavigationStateLike, ReactNavigationPatternOptions } from './routePattern';
17
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACxE,YAAY,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,8BAA8B,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACxE,YAAY,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,8BAA8B,EAAE,MAAM,mBAAmB,CAAC;AACvG,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,gBAAgB,CAAC"}
@@ -313,6 +313,13 @@ function computeVisibility(state, clip) {
313
313
  const onScreen = spansOverlap(rect.left, rect.right, clip.left, clip.right) && spansOverlap(rect.top, rect.bottom, clip.top, clip.bottom);
314
314
  return onScreen ? { visibility: "visible" } : { visibility: "hidden", visibilityReason: "off-screen" };
315
315
  }
316
+ function copyRouteInfo(info) {
317
+ const copy = { ...info };
318
+ if (info.params) copy.params = { ...info.params };
319
+ if (info.queryParams) copy.queryParams = { ...info.queryParams };
320
+ if (info.routeStack) copy.routeStack = [...info.routeStack];
321
+ return copy;
322
+ }
316
323
  function inferActions(type, scrollAncestorId) {
317
324
  const baseActions = scrollAncestorId ? ["focus", "blur", "scrollIntoView"] : ["focus", "blur"];
318
325
  switch (type) {
@@ -377,6 +384,16 @@ var NativeUIBridgeRegistry = class {
377
384
  * already installs.
378
385
  */
379
386
  this.routeProvider = null;
387
+ /**
388
+ * The route TEMPLATE the app last reported through `useRouteAwareness`
389
+ * (via {@link setRouteInfo}), emitted on every snapshot as `page.route`.
390
+ *
391
+ * Deliberately NOT named `routeInfo`: `createSnapshot`'s parameter of that
392
+ * name is the CONCRETE `{currentRoute, segments, activeTab}` read from the
393
+ * route provider. The two must never be confused — the concrete path is
394
+ * user input, and this slot is the router-asserted template.
395
+ */
396
+ this.reportedRoute = void 0;
380
397
  /**
381
398
  * Device pixel ratio used to project `state.layout` (logical dp) into the
382
399
  * physical-pixel `bbox` emitted on each snapshot element. Defaults to `1`
@@ -435,6 +452,22 @@ var NativeUIBridgeRegistry = class {
435
452
  getRouteProvider() {
436
453
  return this.routeProvider;
437
454
  }
455
+ /**
456
+ * Set the route info emitted as `page.route` on every snapshot — the
457
+ * router-asserted TEMPLATE, normally reported by `useRouteAwareness`.
458
+ * Pass `undefined` to clear it (the hook does so on unmount), after which
459
+ * snapshots omit `page` again.
460
+ *
461
+ * The value is copied, so a later mutation by the caller cannot alter what
462
+ * is stored or what an already-emitted snapshot holds.
463
+ */
464
+ setRouteInfo(info) {
465
+ this.reportedRoute = info ? copyRouteInfo(info) : void 0;
466
+ }
467
+ /** Read-only accessor for the reported route info, if any (a copy). */
468
+ getRouteInfo() {
469
+ return this.reportedRoute ? copyRouteInfo(this.reportedRoute) : void 0;
470
+ }
438
471
  /**
439
472
  * Resolve the snapshot's `activeTab`: an explicit `getActiveTab()` on the
440
473
  * route provider wins, otherwise derive it from the Expo Router segments the
@@ -1275,6 +1308,12 @@ var NativeUIBridgeRegistry = class {
1275
1308
  // hosts that wire no route provider.
1276
1309
  ...resolvedRoute.currentRoute ? { route: resolvedRoute.currentRoute } : {},
1277
1310
  ...resolvedRoute.activeTab ? { activeTab: resolvedRoute.activeTab } : {},
1311
+ // The router-asserted route TEMPLATE, spelled as the web SDK's
1312
+ // `snapshot.page.route`. Emitted on the ONE assembly point both route
1313
+ // branches above share (the explicit-`routeInfo` branch the server's
1314
+ // `getSnapshot` override uses, and the provider fallback). Omitted, not
1315
+ // nulled, when unset — the same convention as the aliases above.
1316
+ ...this.reportedRoute ? { page: { route: copyRouteInfo(this.reportedRoute) } } : {},
1278
1317
  registration: this.getRegistrationCoverage()
1279
1318
  };
1280
1319
  if (this.appInfo) {
@@ -1321,6 +1360,9 @@ var NativeUIBridgeRegistry = class {
1321
1360
  }
1322
1361
  }
1323
1362
  }
1363
+ if (this.reportedRoute) {
1364
+ snapshot.page = { route: copyRouteInfo(this.reportedRoute) };
1365
+ }
1324
1366
  }
1325
1367
  return snapshot;
1326
1368
  }
@@ -4313,7 +4355,7 @@ function createServerHandlers(registry, executor, config) {
4313
4355
  };
4314
4356
  if (config?.appInfo) {
4315
4357
  response.uiBridge = {
4316
- version: "0.6.14",
4358
+ version: "0.6.16",
4317
4359
  ...config.appInfo,
4318
4360
  capabilities: ["elements", "components", "actions", "design"],
4319
4361
  elementCount: stats.elements,
@@ -6312,7 +6354,7 @@ var DeviceAnnouncer = class {
6312
6354
  this.publishInFlight = true;
6313
6355
  let result;
6314
6356
  try {
6315
- result = await zeroconf.publishService("_uibridge", "_tcp.", "local.", serviceName, port, {
6357
+ result = await zeroconf.publishService("uibridge", "tcp", "local.", serviceName, port, {
6316
6358
  device_id: this.config.deviceId,
6317
6359
  app_id: this.config.appId,
6318
6360
  version: this.config.version ?? "unknown",
@@ -7875,11 +7917,84 @@ function State(props) {
7875
7917
  function TransitionTo(props) {
7876
7918
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: props.children });
7877
7919
  }
7920
+ function effectiveInfo(info, unmatched) {
7921
+ return unmatched ? { ...info, pattern: null, params: void 0 } : info;
7922
+ }
7923
+ function useRouteAwareness(info, options = {}) {
7924
+ const bridge = useUIBridgeNativeOptional();
7925
+ const unmatched = options.unmatched === true;
7926
+ const infoRef = react.useRef(info);
7927
+ infoRef.current = info;
7928
+ const pattern = info.pattern;
7929
+ const patternSource = info.patternSource;
7930
+ const paramsKey = info.params ? JSON.stringify(info.params) : "";
7931
+ const queryParamsKey = info.queryParams ? JSON.stringify(info.queryParams) : "";
7932
+ const routeStackKey = info.routeStack?.join(",");
7933
+ react.useEffect(() => {
7934
+ if (!bridge) return;
7935
+ const registry = bridge.registry;
7936
+ registry.setRouteInfo(effectiveInfo(infoRef.current, unmatched));
7937
+ return () => {
7938
+ registry.setRouteInfo(void 0);
7939
+ };
7940
+ }, [bridge, unmatched, pattern, patternSource, paramsKey, queryParamsKey, routeStackKey]);
7941
+ }
7942
+
7943
+ // src/react/routePattern.ts
7944
+ function focusedIndex(state, routeCount) {
7945
+ if (state.index !== void 0) return state.index;
7946
+ return typeof state.type === "string" && state.type !== "stack" ? 0 : routeCount - 1;
7947
+ }
7948
+ function isRouteIdentifier(value) {
7949
+ return typeof value === "string" && value.length > 0 && !value.includes("/") && !value.includes("?") && !value.includes("#");
7950
+ }
7951
+ function isExpoRouterUnmatched(segments) {
7952
+ return segments.some((s) => typeof s === "string" && s.startsWith("+"));
7953
+ }
7954
+ function expoRouterPattern(segments) {
7955
+ if (!Array.isArray(segments)) return null;
7956
+ for (const segment of segments) {
7957
+ if (!isRouteIdentifier(segment)) return null;
7958
+ if (segment.startsWith("+")) return null;
7959
+ }
7960
+ return "/" + segments.join("/");
7961
+ }
7962
+ function expoRouterRouteStack(segments) {
7963
+ if (expoRouterPattern(segments) === null) return void 0;
7964
+ const stack = ["/"];
7965
+ for (let depth = 1; depth <= segments.length; depth++) {
7966
+ stack.push("/" + segments.slice(0, depth).join("/"));
7967
+ }
7968
+ return stack;
7969
+ }
7970
+ function reactNavigationPattern(state, options = {}) {
7971
+ const names = [];
7972
+ let level = state ?? void 0;
7973
+ while (level) {
7974
+ const routes = level.routes;
7975
+ if (!Array.isArray(routes) || routes.length === 0) return null;
7976
+ const index = focusedIndex(level, routes.length);
7977
+ if (!Number.isInteger(index) || index < 0 || index >= routes.length) return null;
7978
+ const route = routes[index];
7979
+ if (!route || !isRouteIdentifier(route.name)) return null;
7980
+ names.push(route.name);
7981
+ level = route.state;
7982
+ }
7983
+ if (names.length === 0) return null;
7984
+ const leaf = names[names.length - 1];
7985
+ if (options.notFoundRouteNames?.includes(leaf)) return null;
7986
+ return "/" + names.join("/");
7987
+ }
7878
7988
 
7879
7989
  exports.State = State;
7880
7990
  exports.TransitionTo = TransitionTo;
7881
7991
  exports.UIBridgeNativeProvider = UIBridgeNativeProvider;
7992
+ exports.expoRouterPattern = expoRouterPattern;
7993
+ exports.expoRouterRouteStack = expoRouterRouteStack;
7994
+ exports.isExpoRouterUnmatched = isExpoRouterUnmatched;
7995
+ exports.reactNavigationPattern = reactNavigationPattern;
7882
7996
  exports.useAutoRegister = useAutoRegister;
7997
+ exports.useRouteAwareness = useRouteAwareness;
7883
7998
  exports.useToastRecorder = useToastRecorder;
7884
7999
  exports.useUIBridge = useUIBridge;
7885
8000
  exports.useUIBridgeModal = useUIBridgeModal;