@koordinates/xstate-tree 4.1.6 → 4.3.0-beta.1
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/README.md
CHANGED
|
@@ -185,6 +185,14 @@ These events can be added anywhere, either next to a component for component spe
|
|
|
185
185
|
2. If they are tied to a component they need to be in the index.ts file that imports the view/selectors/actions etc and calls `createXStateTreeMachine`. If they are in the file containing those functions the index.d.ts file will not end up importing them.
|
|
186
186
|
|
|
187
187
|
|
|
188
|
+
### Type helpers
|
|
189
|
+
|
|
190
|
+
There are some exported type helpers for use with xstate-tree
|
|
191
|
+
|
|
192
|
+
* `SelectorsFrom<TMachine>`: Takes a machine and returns the type of the selectors object
|
|
193
|
+
* `ActionsFrom<TMachine>`: Takes a machine and returns the type of the actions object
|
|
194
|
+
|
|
195
|
+
|
|
188
196
|
### [Storybook](https://storybook.js.org)
|
|
189
197
|
|
|
190
198
|
It is relatively simple to display xstate-tree views directly in Storybook. Since the views are plain React components that accept selectors/actions/slots/inState as props you can just import the view and render it in a Story
|
package/lib/routing/Link.js
CHANGED
|
@@ -8,13 +8,37 @@ import { useHref } from "./useHref";
|
|
|
8
8
|
* The query/params/meta props are conditionally required based on the
|
|
9
9
|
* route passed as the To parameter
|
|
10
10
|
*/
|
|
11
|
-
export function Link({ to, children, testId, ...rest }) {
|
|
11
|
+
export function Link({ to, children, testId, preloadOnHoverMs, preloadOnInteraction, onMouseDown: _onMouseDown, onMouseEnter: _onMouseEnter, onMouseLeave: _onMouseLeave, ...rest }) {
|
|
12
12
|
// @ts-ignore, these fields _might_ exist, so typechecking doesn't believe they exist
|
|
13
13
|
// and everything that consumes params/query already checks for undefined
|
|
14
14
|
const { params, query, meta, ...props } = rest;
|
|
15
|
+
let timeout;
|
|
15
16
|
const href = useHref(to, params, query);
|
|
16
|
-
|
|
17
|
+
const onMouseDown = preloadOnInteraction
|
|
18
|
+
? (e) => {
|
|
19
|
+
_onMouseDown === null || _onMouseDown === void 0 ? void 0 : _onMouseDown(e);
|
|
20
|
+
to.preload({ params, query, meta });
|
|
21
|
+
}
|
|
22
|
+
: undefined;
|
|
23
|
+
const onMouseEnter = preloadOnHoverMs !== undefined
|
|
24
|
+
? (e) => {
|
|
25
|
+
_onMouseEnter === null || _onMouseEnter === void 0 ? void 0 : _onMouseEnter(e);
|
|
26
|
+
timeout = setTimeout(() => {
|
|
27
|
+
to.preload({ params, query, meta });
|
|
28
|
+
}, preloadOnHoverMs);
|
|
29
|
+
}
|
|
30
|
+
: undefined;
|
|
31
|
+
const onMouseLeave = preloadOnHoverMs !== undefined
|
|
32
|
+
? (e) => {
|
|
33
|
+
_onMouseLeave === null || _onMouseLeave === void 0 ? void 0 : _onMouseLeave(e);
|
|
34
|
+
if (timeout !== undefined) {
|
|
35
|
+
clearTimeout(timeout);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
: undefined;
|
|
39
|
+
return (React.createElement("a", { ...props, href: href, "data-testid": testId, onMouseDown: onMouseDown !== null && onMouseDown !== void 0 ? onMouseDown : _onMouseDown, onMouseEnter: onMouseEnter !== null && onMouseEnter !== void 0 ? onMouseEnter : _onMouseEnter, onMouseLeave: onMouseLeave !== null && onMouseLeave !== void 0 ? onMouseLeave : _onMouseLeave, onClick: (e) => {
|
|
17
40
|
var _a;
|
|
41
|
+
e.preventDefault();
|
|
18
42
|
if (((_a = props.onClick) === null || _a === void 0 ? void 0 : _a.call(props, e)) === false) {
|
|
19
43
|
return;
|
|
20
44
|
}
|
|
@@ -23,7 +47,6 @@ export function Link({ to, children, testId, ...rest }) {
|
|
|
23
47
|
if (e.metaKey || e.ctrlKey) {
|
|
24
48
|
return;
|
|
25
49
|
}
|
|
26
|
-
e.preventDefault();
|
|
27
50
|
to.navigate({ params, query, meta });
|
|
28
51
|
} }, children));
|
|
29
52
|
}
|
|
@@ -66,7 +66,7 @@ export function buildCreateRoute(history, basePath) {
|
|
|
66
66
|
}
|
|
67
67
|
return parentRoutes;
|
|
68
68
|
}
|
|
69
|
-
return ({ event, matcher, reverser, paramsSchema, querySchema, redirect, }) => {
|
|
69
|
+
return ({ event, matcher, reverser, paramsSchema, querySchema, redirect, preload, }) => {
|
|
70
70
|
let fullParamsSchema = paramsSchema;
|
|
71
71
|
let parentRoute = baseRoute;
|
|
72
72
|
while (fullParamsSchema && parentRoute) {
|
|
@@ -156,6 +156,14 @@ export function buildCreateRoute(history, basePath) {
|
|
|
156
156
|
history: this.history(),
|
|
157
157
|
});
|
|
158
158
|
},
|
|
159
|
+
// @ts-ignore :cry:
|
|
160
|
+
preload(args) {
|
|
161
|
+
const parentRoutes = getParentArray();
|
|
162
|
+
parentRoutes.forEach((route) => {
|
|
163
|
+
route === null || route === void 0 ? void 0 : route.preload(args);
|
|
164
|
+
});
|
|
165
|
+
preload === null || preload === void 0 ? void 0 : preload(args);
|
|
166
|
+
},
|
|
159
167
|
};
|
|
160
168
|
};
|
|
161
169
|
},
|
|
@@ -24,9 +24,10 @@ export function handleLocationChange(routes, basePath, path, search, meta) {
|
|
|
24
24
|
const matchedEvent = match.event;
|
|
25
25
|
matchedEvent.meta = { ...(meta !== null && meta !== void 0 ? meta : {}) };
|
|
26
26
|
matchedEvent.meta.indexEvent = true;
|
|
27
|
-
const { params } = match.event;
|
|
27
|
+
const { params, query } = match.event;
|
|
28
28
|
const routingEvents = [];
|
|
29
29
|
let route = match.route;
|
|
30
|
+
route.preload({ params, query, meta: matchedEvent.meta });
|
|
30
31
|
while (route.parent) {
|
|
31
32
|
routingEvents.push(route.parent.getEvent({ params, query: {}, meta: { ...(meta !== null && meta !== void 0 ? meta : {}) } }));
|
|
32
33
|
route = route.parent;
|
package/lib/xstate-tree.d.ts
CHANGED
|
@@ -26,6 +26,17 @@ export declare type Actions<TMachine extends AnyStateMachine, TSelectorsOutput,
|
|
|
26
26
|
selectors: TSelectorsOutput;
|
|
27
27
|
}) => TOut;
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* @public
|
|
31
|
+
*
|
|
32
|
+
* Retrieves the actions return type from the xstate-tree machine
|
|
33
|
+
*/
|
|
34
|
+
export declare type ActionsFrom<TMachine extends AnyXstateTreeMachine> = TMachine extends StateMachine<any, infer TMeta, any> ? TMeta extends {
|
|
35
|
+
meta: {
|
|
36
|
+
actions: infer TOut;
|
|
37
|
+
};
|
|
38
|
+
} ? TOut extends (...args: any) => any ? ReturnType<TOut> : never : never : never;
|
|
39
|
+
|
|
29
40
|
/**
|
|
30
41
|
* @public
|
|
31
42
|
*/
|
|
@@ -40,6 +51,7 @@ export declare type AnyRoute = {
|
|
|
40
51
|
navigate: any;
|
|
41
52
|
getEvent: any;
|
|
42
53
|
event: string;
|
|
54
|
+
preload: any;
|
|
43
55
|
basePath: string;
|
|
44
56
|
history: () => XstateTreeHistory;
|
|
45
57
|
parent?: AnyRoute;
|
|
@@ -116,6 +128,7 @@ export declare function buildCreateRoute(history: () => XstateTreeHistory, baseP
|
|
|
116
128
|
querySchema?: TQuerySchema | undefined;
|
|
117
129
|
meta?: TMeta | undefined;
|
|
118
130
|
redirect?: RouteRedirect<MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta> & SharedMeta> | undefined;
|
|
131
|
+
preload?: RouteArgumentFunctions<void, MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta>, RouteArguments<MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta>>> | undefined;
|
|
119
132
|
}) => Route<MergeRouteTypes<RouteParams<TBaseRoute>, ResolveZodType<TParamsSchema>>, ResolveZodType<TQuerySchema>, TEvent, MergeRouteTypes<RouteMeta<TBaseRoute>, TMeta> & SharedMeta>;
|
|
120
133
|
route<TBaseRoute_1 extends AnyRoute>(baseRoute?: TBaseRoute_1 | undefined): <TEvent_1 extends string, TParamsSchema_1 extends Z.ZodObject<any, "strip", Z.ZodTypeAny, {
|
|
121
134
|
[x: string]: any;
|
|
@@ -125,7 +138,7 @@ export declare function buildCreateRoute(history: () => XstateTreeHistory, baseP
|
|
|
125
138
|
[x: string]: any;
|
|
126
139
|
}, {
|
|
127
140
|
[x: string]: any;
|
|
128
|
-
}> | undefined, TMeta_1 extends Record<string, unknown>>({ event, matcher, reverser, paramsSchema, querySchema, redirect, }: {
|
|
141
|
+
}> | undefined, TMeta_1 extends Record<string, unknown>>({ event, matcher, reverser, paramsSchema, querySchema, redirect, preload, }: {
|
|
129
142
|
event: TEvent_1;
|
|
130
143
|
paramsSchema?: TParamsSchema_1 | undefined;
|
|
131
144
|
querySchema?: TQuerySchema_1 | undefined;
|
|
@@ -146,6 +159,7 @@ export declare function buildCreateRoute(history: () => XstateTreeHistory, baseP
|
|
|
146
159
|
* Supplied with params/query objects and constructs the correct URL based on them
|
|
147
160
|
*/
|
|
148
161
|
reverser: RouteArgumentFunctions<string, MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>, RouteArguments<MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>>>;
|
|
162
|
+
preload?: RouteArgumentFunctions<void, MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>, RouteArguments<MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1>>> | undefined;
|
|
149
163
|
}) => Route<MergeRouteTypes<RouteParams<TBaseRoute_1>, ResolveZodType<TParamsSchema_1>>, ResolveZodType<TQuerySchema_1>, TEvent_1, MergeRouteTypes<RouteMeta<TBaseRoute_1>, TMeta_1> & SharedMeta>;
|
|
150
164
|
};
|
|
151
165
|
|
|
@@ -341,7 +355,7 @@ export declare function lazy<TMachine extends AnyStateMachine>(factory: () => Pr
|
|
|
341
355
|
* The query/params/meta props are conditionally required based on the
|
|
342
356
|
* route passed as the To parameter
|
|
343
357
|
*/
|
|
344
|
-
export declare function Link<TRoute extends AnyRoute>({ to, children, testId, ...rest }: LinkProps<TRoute>): JSX.Element;
|
|
358
|
+
export declare function Link<TRoute extends AnyRoute>({ to, children, testId, preloadOnHoverMs, preloadOnInteraction, onMouseDown: _onMouseDown, onMouseEnter: _onMouseEnter, onMouseLeave: _onMouseLeave, ...rest }: LinkProps<TRoute>): JSX.Element;
|
|
345
359
|
|
|
346
360
|
/**
|
|
347
361
|
* @public
|
|
@@ -354,6 +368,8 @@ export declare type LinkProps<TRoute extends AnyRoute, TRouteParams = TRoute ext
|
|
|
354
368
|
* onClick works as normal, but if you return false from it the navigation will not happen
|
|
355
369
|
*/
|
|
356
370
|
onClick?: (e: React_2.MouseEvent<HTMLAnchorElement>) => boolean | void;
|
|
371
|
+
preloadOnInteraction?: boolean;
|
|
372
|
+
preloadOnHoverMs?: number;
|
|
357
373
|
} & RouteArguments<TRouteParams, TRouteQuery, TRouteMeta> & Omit<React_2.AnchorHTMLAttributes<HTMLAnchorElement>, "href" | "onClick">;
|
|
358
374
|
|
|
359
375
|
/**
|
|
@@ -513,6 +529,17 @@ export declare type Route<TParams, TQuery, TEvent, TMeta> = {
|
|
|
513
529
|
* url via History.push
|
|
514
530
|
*/
|
|
515
531
|
navigate: RouteArgumentFunctions<void, TParams, TQuery, TMeta>;
|
|
532
|
+
/**
|
|
533
|
+
* Preloads data required by the route. Passed in query/params/meta objects as required by the route
|
|
534
|
+
*
|
|
535
|
+
* Must be idempotent as it may be called multiple times
|
|
536
|
+
*
|
|
537
|
+
* Can be called on
|
|
538
|
+
* * Mouse down on a Link
|
|
539
|
+
* * Hovering on a Link
|
|
540
|
+
* * When a route is matched
|
|
541
|
+
*/
|
|
542
|
+
preload: RouteArgumentFunctions<void, TParams, TQuery, TMeta>;
|
|
516
543
|
/**
|
|
517
544
|
* Returns an event object for this route based on the supplied params/query/meta
|
|
518
545
|
*
|
|
@@ -619,6 +646,17 @@ export declare type Selectors<TMachine extends AnyStateMachine, TOut> = (args: {
|
|
|
619
646
|
inState: MatchesFrom<TMachine>;
|
|
620
647
|
}) => TOut;
|
|
621
648
|
|
|
649
|
+
/**
|
|
650
|
+
* @public
|
|
651
|
+
*
|
|
652
|
+
* Retrieves the selector return type from the xstate-tree machine
|
|
653
|
+
*/
|
|
654
|
+
export declare type SelectorsFrom<TMachine extends AnyXstateTreeMachine> = TMachine extends StateMachine<any, infer TMeta, any> ? TMeta extends {
|
|
655
|
+
meta: {
|
|
656
|
+
selectors: infer TOut;
|
|
657
|
+
};
|
|
658
|
+
} ? TOut extends (...args: any) => any ? ReturnType<TOut> : never : never : never;
|
|
659
|
+
|
|
622
660
|
/**
|
|
623
661
|
* @public
|
|
624
662
|
*/
|
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": "4.1
|
|
5
|
+
"version": "4.3.0-beta.1",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"description": "Build UIs with Actors using xstate and React",
|
|
8
8
|
"keywords": [
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@testing-library/dom": "^8.14.0",
|
|
35
35
|
"@testing-library/jest-dom": "^5.16.1",
|
|
36
36
|
"@testing-library/react": "^13.4.0",
|
|
37
|
-
"@testing-library/user-event": "^
|
|
37
|
+
"@testing-library/user-event": "^14.4.3",
|
|
38
38
|
"@types/history": "^4.7.7",
|
|
39
39
|
"@types/jest": "^28.1.4",
|
|
40
40
|
"@types/react": "^17.0.29",
|