zustand-iten 0.0.2 → 0.4.2

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
@@ -1,5 +1,89 @@
1
1
  # zustand-iten
2
2
 
3
- Reserved package for the upcoming Zustand adapter for `iten`.
3
+ Zustand bindings for `iten`, an ultralight typed in-memory router for embedded JavaScript apps.
4
4
 
5
- Use `iten-core` today for framework-agnostic routing.
5
+ This package exposes a scoped vanilla Zustand store backed by `iten-core`. Use it when routing should live in a Zustand store, or when you want a framework-light adapter surface that can be consumed by Zustand selectors.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install zustand-iten zustand
11
+ ```
12
+
13
+ `zustand-iten` depends on `iten-core`. Install `@tanstack/react-query` only when route loaders call `queryClient.ensureQueryData`.
14
+
15
+ ## Quick Start
16
+
17
+ ```ts
18
+ import {
19
+ createRoute,
20
+ createRouter,
21
+ defineRoutes,
22
+ type InferRoutes,
23
+ route,
24
+ } from 'zustand-iten'
25
+
26
+ const routes = defineRoutes({
27
+ home: route(),
28
+ project: route<{ id: string }>(),
29
+ settings: route(),
30
+ })
31
+
32
+ type Routes = InferRoutes<typeof routes>
33
+
34
+ const toRoute = createRoute(routes)
35
+
36
+ const router = createRouter<Routes>({
37
+ initial: toRoute({ name: 'home' }),
38
+ })
39
+
40
+ await router.navigate({ target: toRoute({ name: 'project', params: { id: 'alpha' } }) })
41
+
42
+ router.store.getState().route
43
+ router.store.getState().canGoBack
44
+ ```
45
+
46
+ ## Store Shape
47
+
48
+ The Zustand store state is the core router state plus router actions:
49
+
50
+ - `route`
51
+ - `pendingRoute`
52
+ - `history`
53
+ - `error`
54
+ - `isNavigating`
55
+ - `canGoBack`
56
+ - `navigate(input)`
57
+ - `goBack()`
58
+ - `dispose()`
59
+
60
+ ```ts
61
+ const unsub = router.store.subscribe((state) => {
62
+ console.log(state.route)
63
+ })
64
+
65
+ unsub()
66
+ ```
67
+
68
+ ## URL Sync
69
+
70
+ `zustand-iten/url` keeps URL support explicit and optional.
71
+
72
+ ```ts
73
+ import { createUrlSync } from 'zustand-iten/url'
74
+
75
+ const sync = createUrlSync({
76
+ router,
77
+ parse: ({ url }) => parseRoute(url),
78
+ format: ({ route, url }) => formatRoute({ route, url }),
79
+ })
80
+
81
+ await sync.hydrate()
82
+ sync.start()
83
+ ```
84
+
85
+ ## Entry Points
86
+
87
+ - `zustand-iten`: scoped Zustand store, route utilities, and types
88
+ - `zustand-iten/url`: optional URL sync adapter
89
+ - `zustand-iten/utils`: route factories, guards, matching, and type utilities
@@ -0,0 +1,63 @@
1
+ let iten_core = require("iten-core");
2
+ let zustand_vanilla = require("zustand/vanilla");
3
+ //#region src/create-router.ts
4
+ function createRouter(config) {
5
+ const getCtx = () => {
6
+ if (typeof config.context === "function") return config.context();
7
+ return config.context ?? {};
8
+ };
9
+ const core = (0, iten_core.createItenCore)({
10
+ initial: config.initial,
11
+ routeConfig: config.routeConfig,
12
+ maxHistoryLength: config.maxHistoryLength,
13
+ queryClient: config.queryClient,
14
+ getCtx
15
+ });
16
+ let stopCoreSubscription;
17
+ function makeState({ state, actions }) {
18
+ return {
19
+ ...state,
20
+ ...actions
21
+ };
22
+ }
23
+ const actions = {
24
+ navigate: async (input) => {
25
+ await core.navigate(input);
26
+ store.setState(makeState({
27
+ state: core.getState(),
28
+ actions
29
+ }), true);
30
+ },
31
+ goBack: () => {
32
+ core.goBack();
33
+ store.setState(makeState({
34
+ state: core.getState(),
35
+ actions
36
+ }), true);
37
+ },
38
+ dispose: () => {
39
+ stopCoreSubscription?.();
40
+ stopCoreSubscription = void 0;
41
+ core.dispose();
42
+ }
43
+ };
44
+ const store = (0, zustand_vanilla.createStore)(() => makeState({
45
+ state: core.getState(),
46
+ actions
47
+ }));
48
+ stopCoreSubscription = core.subscribe({ listener: (state) => {
49
+ store.setState(makeState({
50
+ state,
51
+ actions
52
+ }), true);
53
+ } });
54
+ return {
55
+ store,
56
+ core,
57
+ navigate: actions.navigate,
58
+ goBack: actions.goBack,
59
+ dispose: actions.dispose
60
+ };
61
+ }
62
+ //#endregion
63
+ exports.createRouter = createRouter;
@@ -0,0 +1,14 @@
1
+ import { ZustandRouterActions, ZustandRouterConfig, ZustandRouterStore } from "./types.cjs";
2
+ import { ItenCore, RouteMapDef } from "iten-core";
3
+
4
+ //#region src/create-router.d.ts
5
+ type ZustandRouter<M extends RouteMapDef, _Ctx = unknown> = {
6
+ store: ZustandRouterStore<M>;
7
+ core: ItenCore<M>;
8
+ navigate: ZustandRouterActions<M>["navigate"];
9
+ goBack: ZustandRouterActions<M>["goBack"];
10
+ dispose: ZustandRouterActions<M>["dispose"];
11
+ };
12
+ declare function createRouter<M extends RouteMapDef, Ctx = unknown>(config: ZustandRouterConfig<M, Ctx>): ZustandRouter<M, Ctx>;
13
+ //#endregion
14
+ export { ZustandRouter, createRouter };
@@ -0,0 +1,14 @@
1
+ import { ZustandRouterActions, ZustandRouterConfig, ZustandRouterStore } from "./types.js";
2
+ import { ItenCore, RouteMapDef } from "iten-core";
3
+
4
+ //#region src/create-router.d.ts
5
+ type ZustandRouter<M extends RouteMapDef, _Ctx = unknown> = {
6
+ store: ZustandRouterStore<M>;
7
+ core: ItenCore<M>;
8
+ navigate: ZustandRouterActions<M>["navigate"];
9
+ goBack: ZustandRouterActions<M>["goBack"];
10
+ dispose: ZustandRouterActions<M>["dispose"];
11
+ };
12
+ declare function createRouter<M extends RouteMapDef, Ctx = unknown>(config: ZustandRouterConfig<M, Ctx>): ZustandRouter<M, Ctx>;
13
+ //#endregion
14
+ export { ZustandRouter, createRouter };
@@ -0,0 +1,63 @@
1
+ import { createItenCore } from "iten-core";
2
+ import { createStore } from "zustand/vanilla";
3
+ //#region src/create-router.ts
4
+ function createRouter(config) {
5
+ const getCtx = () => {
6
+ if (typeof config.context === "function") return config.context();
7
+ return config.context ?? {};
8
+ };
9
+ const core = createItenCore({
10
+ initial: config.initial,
11
+ routeConfig: config.routeConfig,
12
+ maxHistoryLength: config.maxHistoryLength,
13
+ queryClient: config.queryClient,
14
+ getCtx
15
+ });
16
+ let stopCoreSubscription;
17
+ function makeState({ state, actions }) {
18
+ return {
19
+ ...state,
20
+ ...actions
21
+ };
22
+ }
23
+ const actions = {
24
+ navigate: async (input) => {
25
+ await core.navigate(input);
26
+ store.setState(makeState({
27
+ state: core.getState(),
28
+ actions
29
+ }), true);
30
+ },
31
+ goBack: () => {
32
+ core.goBack();
33
+ store.setState(makeState({
34
+ state: core.getState(),
35
+ actions
36
+ }), true);
37
+ },
38
+ dispose: () => {
39
+ stopCoreSubscription?.();
40
+ stopCoreSubscription = void 0;
41
+ core.dispose();
42
+ }
43
+ };
44
+ const store = createStore(() => makeState({
45
+ state: core.getState(),
46
+ actions
47
+ }));
48
+ stopCoreSubscription = core.subscribe({ listener: (state) => {
49
+ store.setState(makeState({
50
+ state,
51
+ actions
52
+ }), true);
53
+ } });
54
+ return {
55
+ store,
56
+ core,
57
+ navigate: actions.navigate,
58
+ goBack: actions.goBack,
59
+ dispose: actions.dispose
60
+ };
61
+ }
62
+ //#endregion
63
+ export { createRouter };
package/dist/index.cjs ADDED
@@ -0,0 +1,46 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_create_router = require("./create-router.cjs");
3
+ let iten_core = require("iten-core");
4
+ Object.defineProperty(exports, "createRoute", {
5
+ enumerable: true,
6
+ get: function() {
7
+ return iten_core.createRoute;
8
+ }
9
+ });
10
+ exports.createRouter = require_create_router.createRouter;
11
+ Object.defineProperty(exports, "defineRouteConfig", {
12
+ enumerable: true,
13
+ get: function() {
14
+ return iten_core.defineRouteConfig;
15
+ }
16
+ });
17
+ Object.defineProperty(exports, "defineRoutes", {
18
+ enumerable: true,
19
+ get: function() {
20
+ return iten_core.defineRoutes;
21
+ }
22
+ });
23
+ Object.defineProperty(exports, "isRoute", {
24
+ enumerable: true,
25
+ get: function() {
26
+ return iten_core.isRoute;
27
+ }
28
+ });
29
+ Object.defineProperty(exports, "isRouteName", {
30
+ enumerable: true,
31
+ get: function() {
32
+ return iten_core.isRouteName;
33
+ }
34
+ });
35
+ Object.defineProperty(exports, "matchRoute", {
36
+ enumerable: true,
37
+ get: function() {
38
+ return iten_core.matchRoute;
39
+ }
40
+ });
41
+ Object.defineProperty(exports, "route", {
42
+ enumerable: true,
43
+ get: function() {
44
+ return iten_core.route;
45
+ }
46
+ });
@@ -0,0 +1,4 @@
1
+ import { InferRoutes, NoParams, QueryClientLike, RouteConfigMap, RouteDefinition, RouteDefinitions, RouteMap, RouteMapDef, RouteMatcher, RouteName, RouteOf, RouteParams, RouteUnion, RouterError, RouterState, ZustandRouterActions, ZustandRouterConfig, ZustandRouterState, ZustandRouterStore } from "./types.cjs";
2
+ import { ZustandRouter, createRouter } from "./create-router.cjs";
3
+ import { createRoute, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route } from "iten-core";
4
+ export { type InferRoutes, type NoParams, type QueryClientLike, type RouteConfigMap, type RouteDefinition, type RouteDefinitions, type RouteMap, type RouteMapDef, type RouteMatcher, type RouteName, type RouteOf, type RouteParams, type RouteUnion, type RouterError, type RouterState, type ZustandRouter, type ZustandRouterActions, type ZustandRouterConfig, type ZustandRouterState, type ZustandRouterStore, createRoute, createRouter, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route };
@@ -0,0 +1,4 @@
1
+ import { InferRoutes, NoParams, QueryClientLike, RouteConfigMap, RouteDefinition, RouteDefinitions, RouteMap, RouteMapDef, RouteMatcher, RouteName, RouteOf, RouteParams, RouteUnion, RouterError, RouterState, ZustandRouterActions, ZustandRouterConfig, ZustandRouterState, ZustandRouterStore } from "./types.js";
2
+ import { ZustandRouter, createRouter } from "./create-router.js";
3
+ import { createRoute, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route } from "iten-core";
4
+ export { type InferRoutes, type NoParams, type QueryClientLike, type RouteConfigMap, type RouteDefinition, type RouteDefinitions, type RouteMap, type RouteMapDef, type RouteMatcher, type RouteName, type RouteOf, type RouteParams, type RouteUnion, type RouterError, type RouterState, type ZustandRouter, type ZustandRouterActions, type ZustandRouterConfig, type ZustandRouterState, type ZustandRouterStore, createRoute, createRouter, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route };
package/dist/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { createRouter } from "./create-router.mjs";
2
+ import { createRoute, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route } from "iten-core";
3
+ export { createRoute, createRouter, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route };
@@ -0,0 +1,20 @@
1
+ import { InferRoutes, NavigateInput, NoParams, QueryClientLike, RouteConfigMap, RouteDefinition, RouteDefinitions, RouteMap, RouteMapDef as RouteMapDef$1, RouteMatcher, RouteName, RouteOf, RouteParams, RouteUnion, RouterError, RouterState } from "iten-core";
2
+ import { StoreApi } from "zustand/vanilla";
3
+
4
+ //#region src/types.d.ts
5
+ type ZustandRouterConfig<M extends RouteMapDef$1, Ctx = unknown> = {
6
+ initial: RouteUnion<M> | null;
7
+ routeConfig?: RouteConfigMap<M, Ctx> | undefined;
8
+ maxHistoryLength?: number | undefined;
9
+ context?: Ctx | (() => Ctx) | undefined;
10
+ queryClient?: QueryClientLike | null | undefined;
11
+ };
12
+ type ZustandRouterActions<M extends RouteMapDef$1> = {
13
+ navigate: (input: NavigateInput<M>) => Promise<void>;
14
+ goBack: () => void;
15
+ dispose: () => void;
16
+ };
17
+ type ZustandRouterState<M extends RouteMapDef$1> = RouterState<M> & ZustandRouterActions<M>;
18
+ type ZustandRouterStore<M extends RouteMapDef$1> = StoreApi<ZustandRouterState<M>>;
19
+ //#endregion
20
+ export { type InferRoutes, type NoParams, type QueryClientLike, type RouteConfigMap, type RouteDefinition, type RouteDefinitions, type RouteMap, type RouteMapDef$1 as RouteMapDef, type RouteMatcher, type RouteName, type RouteOf, type RouteParams, type RouteUnion, type RouterError, type RouterState, ZustandRouterActions, ZustandRouterConfig, ZustandRouterState, ZustandRouterStore };
@@ -0,0 +1,20 @@
1
+ import { InferRoutes, NavigateInput, NoParams, QueryClientLike, RouteConfigMap, RouteDefinition, RouteDefinitions, RouteMap, RouteMapDef as RouteMapDef$1, RouteMatcher, RouteName, RouteOf, RouteParams, RouteUnion, RouterError, RouterState } from "iten-core";
2
+ import { StoreApi } from "zustand/vanilla";
3
+
4
+ //#region src/types.d.ts
5
+ type ZustandRouterConfig<M extends RouteMapDef$1, Ctx = unknown> = {
6
+ initial: RouteUnion<M> | null;
7
+ routeConfig?: RouteConfigMap<M, Ctx> | undefined;
8
+ maxHistoryLength?: number | undefined;
9
+ context?: Ctx | (() => Ctx) | undefined;
10
+ queryClient?: QueryClientLike | null | undefined;
11
+ };
12
+ type ZustandRouterActions<M extends RouteMapDef$1> = {
13
+ navigate: (input: NavigateInput<M>) => Promise<void>;
14
+ goBack: () => void;
15
+ dispose: () => void;
16
+ };
17
+ type ZustandRouterState<M extends RouteMapDef$1> = RouterState<M> & ZustandRouterActions<M>;
18
+ type ZustandRouterStore<M extends RouteMapDef$1> = StoreApi<ZustandRouterState<M>>;
19
+ //#endregion
20
+ export { type InferRoutes, type NoParams, type QueryClientLike, type RouteConfigMap, type RouteDefinition, type RouteDefinitions, type RouteMap, type RouteMapDef$1 as RouteMapDef, type RouteMatcher, type RouteName, type RouteOf, type RouteParams, type RouteUnion, type RouterError, type RouterState, ZustandRouterActions, ZustandRouterConfig, ZustandRouterState, ZustandRouterStore };
package/dist/url.cjs ADDED
@@ -0,0 +1,20 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let iten_core_url = require("iten-core/url");
3
+ //#region src/url.ts
4
+ function createUrlSync({ router, ...input }) {
5
+ const coreLike = {
6
+ getState: () => router.store.getState(),
7
+ navigate: (navigateInput) => router.navigate(navigateInput),
8
+ goBack: () => router.goBack(),
9
+ subscribe: ({ listener }) => router.store.subscribe((state) => {
10
+ listener(state);
11
+ }),
12
+ dispose: () => {}
13
+ };
14
+ return (0, iten_core_url.createUrlSync)({
15
+ ...input,
16
+ router: coreLike
17
+ });
18
+ }
19
+ //#endregion
20
+ exports.createUrlSync = createUrlSync;
package/dist/url.d.cts ADDED
@@ -0,0 +1,14 @@
1
+ import { ZustandRouter } from "./create-router.cjs";
2
+ import { RouteMapDef } from "iten-core";
3
+ import { CreateUrlSyncInput as CreateUrlSyncInput$1, FormatUrlInput, ParseUrlInput, UrlHydrateInput, UrlParseErrorInput, UrlStartInput, UrlSubscribeInput, UrlSync, UrlSync as UrlSync$1, UrlWriteInput, UrlWriteMode } from "iten-core/url";
4
+
5
+ //#region src/url.d.ts
6
+ type CreateUrlSyncInput<M extends RouteMapDef> = Omit<CreateUrlSyncInput$1<M>, "router"> & {
7
+ router: ZustandRouter<M>;
8
+ };
9
+ declare function createUrlSync<M extends RouteMapDef>({
10
+ router,
11
+ ...input
12
+ }: CreateUrlSyncInput<M>): UrlSync$1<M>;
13
+ //#endregion
14
+ export { CreateUrlSyncInput, type FormatUrlInput, type ParseUrlInput, type UrlHydrateInput, type UrlParseErrorInput, type UrlStartInput, type UrlSubscribeInput, type UrlSync, type UrlWriteInput, type UrlWriteMode, createUrlSync };
package/dist/url.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import { ZustandRouter } from "./create-router.js";
2
+ import { RouteMapDef } from "iten-core";
3
+ import { CreateUrlSyncInput as CreateUrlSyncInput$1, FormatUrlInput, ParseUrlInput, UrlHydrateInput, UrlParseErrorInput, UrlStartInput, UrlSubscribeInput, UrlSync, UrlSync as UrlSync$1, UrlWriteInput, UrlWriteMode } from "iten-core/url";
4
+
5
+ //#region src/url.d.ts
6
+ type CreateUrlSyncInput<M extends RouteMapDef> = Omit<CreateUrlSyncInput$1<M>, "router"> & {
7
+ router: ZustandRouter<M>;
8
+ };
9
+ declare function createUrlSync<M extends RouteMapDef>({
10
+ router,
11
+ ...input
12
+ }: CreateUrlSyncInput<M>): UrlSync$1<M>;
13
+ //#endregion
14
+ export { CreateUrlSyncInput, type FormatUrlInput, type ParseUrlInput, type UrlHydrateInput, type UrlParseErrorInput, type UrlStartInput, type UrlSubscribeInput, type UrlSync, type UrlWriteInput, type UrlWriteMode, createUrlSync };
package/dist/url.mjs ADDED
@@ -0,0 +1,19 @@
1
+ import { createUrlSync as createUrlSync$1 } from "iten-core/url";
2
+ //#region src/url.ts
3
+ function createUrlSync({ router, ...input }) {
4
+ const coreLike = {
5
+ getState: () => router.store.getState(),
6
+ navigate: (navigateInput) => router.navigate(navigateInput),
7
+ goBack: () => router.goBack(),
8
+ subscribe: ({ listener }) => router.store.subscribe((state) => {
9
+ listener(state);
10
+ }),
11
+ dispose: () => {}
12
+ };
13
+ return createUrlSync$1({
14
+ ...input,
15
+ router: coreLike
16
+ });
17
+ }
18
+ //#endregion
19
+ export { createUrlSync };
package/dist/utils.cjs ADDED
@@ -0,0 +1,44 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let iten_core_utils = require("iten-core/utils");
3
+ Object.defineProperty(exports, "createRoute", {
4
+ enumerable: true,
5
+ get: function() {
6
+ return iten_core_utils.createRoute;
7
+ }
8
+ });
9
+ Object.defineProperty(exports, "defineRouteConfig", {
10
+ enumerable: true,
11
+ get: function() {
12
+ return iten_core_utils.defineRouteConfig;
13
+ }
14
+ });
15
+ Object.defineProperty(exports, "defineRoutes", {
16
+ enumerable: true,
17
+ get: function() {
18
+ return iten_core_utils.defineRoutes;
19
+ }
20
+ });
21
+ Object.defineProperty(exports, "isRoute", {
22
+ enumerable: true,
23
+ get: function() {
24
+ return iten_core_utils.isRoute;
25
+ }
26
+ });
27
+ Object.defineProperty(exports, "isRouteName", {
28
+ enumerable: true,
29
+ get: function() {
30
+ return iten_core_utils.isRouteName;
31
+ }
32
+ });
33
+ Object.defineProperty(exports, "matchRoute", {
34
+ enumerable: true,
35
+ get: function() {
36
+ return iten_core_utils.matchRoute;
37
+ }
38
+ });
39
+ Object.defineProperty(exports, "route", {
40
+ enumerable: true,
41
+ get: function() {
42
+ return iten_core_utils.route;
43
+ }
44
+ });
@@ -0,0 +1,3 @@
1
+ import { InferRoutes, NoParams, RouteConfigMap, RouteMap, RouteMapDef, RouteUnion } from "iten-core";
2
+ import { RouteMatcher, RouteName, RouteOf, RouteParams, createRoute, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route } from "iten-core/utils";
3
+ export { type InferRoutes, type NoParams, type RouteConfigMap, type RouteMap, type RouteMapDef, type RouteMatcher, type RouteName, type RouteOf, type RouteParams, type RouteUnion, createRoute, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route };
@@ -0,0 +1,3 @@
1
+ import { InferRoutes, NoParams, RouteConfigMap, RouteMap, RouteMapDef, RouteUnion } from "iten-core";
2
+ import { RouteMatcher, RouteName, RouteOf, RouteParams, createRoute, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route } from "iten-core/utils";
3
+ export { type InferRoutes, type NoParams, type RouteConfigMap, type RouteMap, type RouteMapDef, type RouteMatcher, type RouteName, type RouteOf, type RouteParams, type RouteUnion, createRoute, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route };
package/dist/utils.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { createRoute, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route } from "iten-core/utils";
2
+ export { createRoute, defineRouteConfig, defineRoutes, isRoute, isRouteName, matchRoute, route };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zustand-iten",
3
- "version": "0.0.2",
4
- "description": "Zustand adapter for iten — ultralight in-memory router for embedded JS apps. Coming soon.",
3
+ "version": "0.4.2",
4
+ "description": "Zustand adapter for iten — ultralight in-memory router for embedded JS apps",
5
5
  "keywords": [
6
6
  "zustand",
7
7
  "router",
@@ -18,13 +18,69 @@
18
18
  "url": "https://github.com/andrew-bierman/iten/issues"
19
19
  },
20
20
  "homepage": "https://github.com/andrew-bierman/iten#readme",
21
- "main": "index.js",
21
+ "type": "module",
22
+ "sideEffects": false,
23
+ "exports": {
24
+ ".": {
25
+ "bun": "./src/index.ts",
26
+ "import": {
27
+ "types": "./dist/index.d.ts",
28
+ "default": "./dist/index.mjs"
29
+ },
30
+ "require": {
31
+ "types": "./dist/index.d.cts",
32
+ "default": "./dist/index.cjs"
33
+ }
34
+ },
35
+ "./utils": {
36
+ "bun": "./src/utils.ts",
37
+ "import": {
38
+ "types": "./dist/utils.d.ts",
39
+ "default": "./dist/utils.mjs"
40
+ },
41
+ "require": {
42
+ "types": "./dist/utils.d.cts",
43
+ "default": "./dist/utils.cjs"
44
+ }
45
+ },
46
+ "./url": {
47
+ "bun": "./src/url.ts",
48
+ "import": {
49
+ "types": "./dist/url.d.ts",
50
+ "default": "./dist/url.mjs"
51
+ },
52
+ "require": {
53
+ "types": "./dist/url.d.cts",
54
+ "default": "./dist/url.cjs"
55
+ }
56
+ }
57
+ },
58
+ "main": "./dist/index.cjs",
59
+ "module": "./dist/index.mjs",
60
+ "types": "./dist/index.d.ts",
22
61
  "files": [
23
- "index.js",
24
- "README.md"
62
+ "dist",
63
+ "src"
25
64
  ],
65
+ "scripts": {
66
+ "build": "tsdown",
67
+ "typecheck": "tsc --noEmit",
68
+ "typecheck:types": "bun run build && tsc -p tsconfig.type-tests.json",
69
+ "test": "bun test ./test"
70
+ },
71
+ "peerDependencies": {
72
+ "zustand": "^5.0.0"
73
+ },
74
+ "dependencies": {
75
+ "iten-core": "^0.4.2"
76
+ },
26
77
  "publishConfig": {
27
78
  "access": "public",
28
79
  "registry": "https://registry.npmjs.org/"
80
+ },
81
+ "devDependencies": {
82
+ "tsdown": "0.21.9",
83
+ "typescript": "^5.7.0",
84
+ "zustand": "^5.0.0"
29
85
  }
30
86
  }
@@ -0,0 +1,85 @@
1
+ import type { ItenCore, RouteMapDef, RouterState } from 'iten-core'
2
+ import { createItenCore } from 'iten-core'
3
+ import { createStore } from 'zustand/vanilla'
4
+ import type {
5
+ ZustandRouterActions,
6
+ ZustandRouterConfig,
7
+ ZustandRouterState,
8
+ ZustandRouterStore,
9
+ } from './types.ts'
10
+
11
+ export type ZustandRouter<M extends RouteMapDef, _Ctx = unknown> = {
12
+ store: ZustandRouterStore<M>
13
+ core: ItenCore<M>
14
+ navigate: ZustandRouterActions<M>['navigate']
15
+ goBack: ZustandRouterActions<M>['goBack']
16
+ dispose: ZustandRouterActions<M>['dispose']
17
+ }
18
+
19
+ export function createRouter<M extends RouteMapDef, Ctx = unknown>(
20
+ config: ZustandRouterConfig<M, Ctx>,
21
+ ): ZustandRouter<M, Ctx> {
22
+ const getCtx = (): Ctx => {
23
+ if (typeof config.context === 'function') {
24
+ return (config.context as () => Ctx)()
25
+ }
26
+ return (config.context ?? {}) as Ctx
27
+ }
28
+
29
+ const core = createItenCore<M, Ctx>({
30
+ initial: config.initial,
31
+ routeConfig: config.routeConfig,
32
+ maxHistoryLength: config.maxHistoryLength,
33
+ queryClient: config.queryClient,
34
+ getCtx,
35
+ })
36
+
37
+ let stopCoreSubscription: (() => void) | undefined
38
+
39
+ function makeState({
40
+ state,
41
+ actions,
42
+ }: {
43
+ state: RouterState<M>
44
+ actions: ZustandRouterActions<M>
45
+ }): ZustandRouterState<M> {
46
+ return {
47
+ ...state,
48
+ ...actions,
49
+ }
50
+ }
51
+
52
+ const actions: ZustandRouterActions<M> = {
53
+ navigate: async (input) => {
54
+ await core.navigate(input)
55
+ store.setState(makeState({ state: core.getState(), actions }), true)
56
+ },
57
+ goBack: () => {
58
+ core.goBack()
59
+ store.setState(makeState({ state: core.getState(), actions }), true)
60
+ },
61
+ dispose: () => {
62
+ stopCoreSubscription?.()
63
+ stopCoreSubscription = undefined
64
+ core.dispose()
65
+ },
66
+ }
67
+
68
+ const store = createStore<ZustandRouterState<M>>(() =>
69
+ makeState({ state: core.getState(), actions }),
70
+ )
71
+
72
+ stopCoreSubscription = core.subscribe({
73
+ listener: (state) => {
74
+ store.setState(makeState({ state, actions }), true)
75
+ },
76
+ })
77
+
78
+ return {
79
+ store,
80
+ core,
81
+ navigate: actions.navigate,
82
+ goBack: actions.goBack,
83
+ dispose: actions.dispose,
84
+ }
85
+ }
package/src/index.ts ADDED
@@ -0,0 +1,32 @@
1
+ export {
2
+ createRoute,
3
+ defineRouteConfig,
4
+ defineRoutes,
5
+ isRoute,
6
+ isRouteName,
7
+ matchRoute,
8
+ route,
9
+ } from 'iten-core'
10
+ export type { ZustandRouter } from './create-router.ts'
11
+ export { createRouter } from './create-router.ts'
12
+ export type {
13
+ InferRoutes,
14
+ NoParams,
15
+ QueryClientLike,
16
+ RouteConfigMap,
17
+ RouteDefinition,
18
+ RouteDefinitions,
19
+ RouteMap,
20
+ RouteMapDef,
21
+ RouteMatcher,
22
+ RouteName,
23
+ RouteOf,
24
+ RouteParams,
25
+ RouterError,
26
+ RouterState,
27
+ RouteUnion,
28
+ ZustandRouterActions,
29
+ ZustandRouterConfig,
30
+ ZustandRouterState,
31
+ ZustandRouterStore,
32
+ } from './types.ts'
package/src/types.ts ADDED
@@ -0,0 +1,55 @@
1
+ import type {
2
+ InferRoutes,
3
+ NavigateInput,
4
+ NoParams,
5
+ QueryClientLike,
6
+ RouteConfigMap,
7
+ RouteDefinition,
8
+ RouteDefinitions,
9
+ RouteMap,
10
+ RouteMapDef,
11
+ RouteMatcher,
12
+ RouteName,
13
+ RouteOf,
14
+ RouteParams,
15
+ RouterError,
16
+ RouterState,
17
+ RouteUnion,
18
+ } from 'iten-core'
19
+ import type { StoreApi } from 'zustand/vanilla'
20
+
21
+ export type {
22
+ InferRoutes,
23
+ NoParams,
24
+ QueryClientLike,
25
+ RouteConfigMap,
26
+ RouteDefinition,
27
+ RouteDefinitions,
28
+ RouteMap,
29
+ RouteMapDef,
30
+ RouteMatcher,
31
+ RouteName,
32
+ RouteOf,
33
+ RouteParams,
34
+ RouterError,
35
+ RouterState,
36
+ RouteUnion,
37
+ }
38
+
39
+ export type ZustandRouterConfig<M extends RouteMapDef, Ctx = unknown> = {
40
+ initial: RouteUnion<M> | null
41
+ routeConfig?: RouteConfigMap<M, Ctx> | undefined
42
+ maxHistoryLength?: number | undefined
43
+ context?: Ctx | (() => Ctx) | undefined
44
+ queryClient?: QueryClientLike | null | undefined
45
+ }
46
+
47
+ export type ZustandRouterActions<M extends RouteMapDef> = {
48
+ navigate: (input: NavigateInput<M>) => Promise<void>
49
+ goBack: () => void
50
+ dispose: () => void
51
+ }
52
+
53
+ export type ZustandRouterState<M extends RouteMapDef> = RouterState<M> & ZustandRouterActions<M>
54
+
55
+ export type ZustandRouterStore<M extends RouteMapDef> = StoreApi<ZustandRouterState<M>>
package/src/url.ts ADDED
@@ -0,0 +1,47 @@
1
+ import type { ItenCore, NavigateInput, RouteMapDef, RouterState } from 'iten-core'
2
+ import {
3
+ type CreateUrlSyncInput as CoreCreateUrlSyncInput,
4
+ createUrlSync as createCoreUrlSync,
5
+ type UrlSync,
6
+ } from 'iten-core/url'
7
+ import type { ZustandRouter } from './create-router.ts'
8
+
9
+ export type {
10
+ FormatUrlInput,
11
+ ParseUrlInput,
12
+ UrlHydrateInput,
13
+ UrlParseErrorInput,
14
+ UrlStartInput,
15
+ UrlSubscribeInput,
16
+ UrlSync,
17
+ UrlWriteInput,
18
+ UrlWriteMode,
19
+ } from 'iten-core/url'
20
+
21
+ export type CreateUrlSyncInput<M extends RouteMapDef> = Omit<
22
+ CoreCreateUrlSyncInput<M>,
23
+ 'router'
24
+ > & {
25
+ router: ZustandRouter<M>
26
+ }
27
+
28
+ export function createUrlSync<M extends RouteMapDef>({
29
+ router,
30
+ ...input
31
+ }: CreateUrlSyncInput<M>): UrlSync<M> {
32
+ const coreLike: ItenCore<M> = {
33
+ getState: () => router.store.getState() as RouterState<M>,
34
+ navigate: (navigateInput: NavigateInput<M>) => router.navigate(navigateInput),
35
+ goBack: () => router.goBack(),
36
+ subscribe: ({ listener }) =>
37
+ router.store.subscribe((state) => {
38
+ listener(state as RouterState<M>)
39
+ }),
40
+ dispose: () => {},
41
+ }
42
+
43
+ return createCoreUrlSync<M>({
44
+ ...input,
45
+ router: coreLike,
46
+ })
47
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,23 @@
1
+ export type {
2
+ InferRoutes,
3
+ NoParams,
4
+ RouteConfigMap,
5
+ RouteMap,
6
+ RouteMapDef,
7
+ RouteUnion,
8
+ } from 'iten-core'
9
+ export type {
10
+ RouteMatcher,
11
+ RouteName,
12
+ RouteOf,
13
+ RouteParams,
14
+ } from 'iten-core/utils'
15
+ export {
16
+ createRoute,
17
+ defineRouteConfig,
18
+ defineRoutes,
19
+ isRoute,
20
+ isRouteName,
21
+ matchRoute,
22
+ route,
23
+ } from 'iten-core/utils'
package/index.js DELETED
@@ -1 +0,0 @@
1
- throw new Error('zustand-iten is reserved for the upcoming Zustand adapter. Use iten-core today.')