@koordinates/xstate-tree 5.2.3 → 5.4.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.
@@ -2,22 +2,27 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useIsRouteActive = void 0;
4
4
  const providers_1 = require("./providers");
5
- /**
6
- * @public
7
- * Accepts Routes and returns true if any route is currently active. False if not.
8
- *
9
- * If used outside of a RoutingContext, an error will be thrown.
10
- * @param routes - the routes to check
11
- * @returns true if any route is active, false if not
12
- * @throws if used outside of an xstate-tree root
13
- */
14
- function useIsRouteActive(...routes) {
5
+ function useIsRouteActive(...args) {
15
6
  const activeRouteEvents = (0, providers_1.useActiveRouteEvents)();
16
7
  if (!activeRouteEvents) {
17
8
  throw new Error("useIsRouteActive must be used within a RoutingContext. Are you using it outside of an xstate-tree Root?");
18
9
  }
10
+ let routes;
11
+ let predicate;
12
+ if (args.length === 2 &&
13
+ Array.isArray(args[0]) &&
14
+ typeof args[1] === "function") {
15
+ routes = args[0];
16
+ predicate = args[1];
17
+ }
18
+ else {
19
+ routes = args;
20
+ }
19
21
  return activeRouteEvents.some((activeRouteEvent) => {
20
- return routes.some((route) => activeRouteEvent.type === route.event);
22
+ const matches = routes.some((route) => activeRouteEvent.type === route.event);
23
+ if (!matches)
24
+ return false;
25
+ return predicate ? predicate(activeRouteEvent) : true;
21
26
  });
22
27
  }
23
28
  exports.useIsRouteActive = useIsRouteActive;
@@ -218,6 +218,13 @@ declare type IsEmptyObject<Obj, ExcludeOptional extends boolean = false> = undef
218
218
  never
219
219
  ] ? true : false;
220
220
 
221
+ /**
222
+ * @public
223
+ * Predicate invoked with the matching active route event to decide whether the
224
+ * route should be considered active.
225
+ */
226
+ declare type IsRouteActivePredicate<TRoutes extends AnyRoute[]> = (event: RoutingEvent<TRoutes[number]>) => boolean;
227
+
221
228
  declare type IsUnknown<T> = unknown extends T ? true : false;
222
229
 
223
230
  /**
@@ -403,6 +410,7 @@ declare type RootOptions<TInput> = {
403
410
  basePath: string;
404
411
  getPathName?: () => string;
405
412
  getQueryString?: () => string;
413
+ shouldBlockActiveRouteUpdate?: (event: RoutingEvent<any>) => boolean;
406
414
  } | undefined;
407
415
  input: IsUnknown<TInput> extends true ? undefined : TInput;
408
416
  };
@@ -680,6 +688,20 @@ export declare function useActiveRouteEvents(): {
680
688
  */
681
689
  export declare function useIsRouteActive(...routes: AnyRoute[]): boolean;
682
690
 
691
+ /**
692
+ * @public
693
+ * Accepts an array of Routes and a predicate. Returns true if any of the
694
+ * routes is currently active AND the predicate returns true when called with
695
+ * the matching active route event.
696
+ *
697
+ * If used outside of a RoutingContext, an error will be thrown.
698
+ * @param routes - the routes to check
699
+ * @param predicate - called with the matching active route event; return true to treat the route as active
700
+ * @returns true if any route is active and the predicate returns true, false otherwise
701
+ * @throws if used outside of an xstate-tree root
702
+ */
703
+ export declare function useIsRouteActive<TRoutes extends AnyRoute[]>(routes: [...TRoutes], predicate: IsRouteActivePredicate<TRoutes>): boolean;
704
+
683
705
  /**
684
706
  * @public
685
707
  * Accepts a single Route and returns true if the route is currently active and marked as an index route.
package/lib/xstateTree.js CHANGED
@@ -331,8 +331,12 @@ function buildRootComponent(options) {
331
331
  const queryString = getQueryString();
332
332
  const result = (0, routing_1.handleLocationChange)(routing.routes, routing.basePath, getPathName(), getQueryString(), initialMeta);
333
333
  if (result) {
334
- setActiveRouteEvents(result.events);
335
- setActiveRoute({ ...result.matchedRoute });
334
+ const matchedEvent = result.events[result.events.length - 1];
335
+ const block = routing.shouldBlockActiveRouteUpdate?.(matchedEvent) === true;
336
+ if (!block) {
337
+ setActiveRouteEvents(result.events);
338
+ setActiveRoute({ ...result.matchedRoute });
339
+ }
336
340
  }
337
341
  // Hack to ensure the initial location doesn't have undefined state
338
342
  // It's not supposed to, but it does for some reason
@@ -347,8 +351,12 @@ function buildRootComponent(options) {
347
351
  const unsub = routing.history.listen((location) => {
348
352
  const result = (0, routing_1.handleLocationChange)(routing.routes, routing.basePath, location.pathname, location.search, location.state?.meta);
349
353
  if (result) {
350
- setActiveRouteEvents(result.events);
351
- setActiveRoute({ ...result.matchedRoute });
354
+ const matchedEvent = result.events[result.events.length - 1];
355
+ const block = routing.shouldBlockActiveRouteUpdate?.(matchedEvent) === true;
356
+ if (!block) {
357
+ setActiveRouteEvents(result.events);
358
+ setActiveRoute({ ...result.matchedRoute });
359
+ }
352
360
  }
353
361
  });
354
362
  return () => {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@koordinates/xstate-tree",
3
3
  "main": "lib/index.js",
4
4
  "types": "lib/xstate-tree.d.ts",
5
- "version": "5.2.3",
5
+ "version": "5.4.0",
6
6
  "license": "MIT",
7
7
  "description": "Build UIs with Actors using xstate and React",
8
8
  "keywords": [