@argon-router/core 0.11.1 → 0.12.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/index.js CHANGED
@@ -1,8 +1,12 @@
1
- import { createEffect, createStore, createEvent, attach, sample, split, scopeBind, withFactory } from "effector";
1
+ import { createEffect, attach, createStore, createEvent, sample, scopeBind, split, withFactory } from "effector";
2
+ import { createAction, createAsyncAction } from "effector-action";
3
+ import { compile } from "@argon-router/paths";
2
4
  import queryString from "query-string";
3
5
  import { or, not } from "patronum";
4
- function createRoute(config) {
6
+ function createRoute() {
7
+ let config = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
5
8
  let asyncImport;
9
+ const beforeOpen = config.beforeOpen ?? [];
6
10
  const openFx = createEffect(async (payload) => {
7
11
  await waitForAsyncBundleFx();
8
12
  await beforeOpenFx();
@@ -18,65 +22,80 @@ function createRoute(config) {
18
22
  return payload;
19
23
  }, {
20
24
  name: "openFx",
21
- sid: "awhgwd"
25
+ sid: "sf5hhk"
26
+ });
27
+ const forceOpenParentFx = createEffect(async (payload) => {
28
+ const parent = config.parent;
29
+ if (parent) {
30
+ await parent.internal.forceOpenParentFx({
31
+ ...payload ?? {
32
+ params: {}
33
+ },
34
+ navigate: false
35
+ });
36
+ }
37
+ return payload;
38
+ }, {
39
+ name: "forceOpenParentFx",
40
+ sid: "acd7wj"
41
+ });
42
+ const navigatedFx = attach({
43
+ and: {
44
+ effect: openFx
45
+ },
46
+ or: {
47
+ name: "navigatedFx",
48
+ sid: "ci6eci"
49
+ }
22
50
  });
23
51
  const $params = createStore({}, {
24
52
  name: "$params",
25
- sid: "-oahffx"
53
+ sid: "p3bnh9"
26
54
  });
27
55
  const $isOpened = createStore(false, {
28
56
  name: "$isOpened",
29
- sid: "-6l68oe"
57
+ sid: "o5kkev"
30
58
  });
31
59
  const $isPending = openFx.pending;
32
60
  const open = createEvent({
33
61
  name: "open",
34
- sid: "gjsrgc"
62
+ sid: "-bhgc3p"
35
63
  });
36
64
  const close = createEvent({
37
65
  name: "close",
38
- sid: "-yagmc8"
66
+ sid: "vypd6z"
39
67
  });
40
68
  const opened = createEvent({
41
69
  name: "opened",
42
- sid: "x0iwhi"
70
+ sid: "-uyucke"
43
71
  });
44
72
  const openedOnServer = createEvent({
45
73
  name: "openedOnServer",
46
- sid: "346r3u"
74
+ sid: "mewjoi"
47
75
  });
48
76
  const openedOnClient = createEvent({
49
77
  name: "openedOnClient",
50
- sid: "31q95t"
78
+ sid: "63cfjt"
51
79
  });
52
80
  const navigated = createEvent({
53
81
  name: "navigated",
54
- sid: "-t30l0x"
82
+ sid: "mycajg"
55
83
  });
56
84
  const closed = createEvent({
57
85
  name: "closed",
58
- sid: "uue4ce"
86
+ sid: "5idv7d"
59
87
  });
60
88
  const waitForAsyncBundleFx = createEffect(() => asyncImport == null ? void 0 : asyncImport(), {
61
89
  name: "waitForAsyncBundleFx",
62
- sid: "-nml5ho"
90
+ sid: "-6s0q41"
63
91
  });
64
92
  const beforeOpenFx = createEffect(async () => {
65
- for (const fx of config.beforeOpen ?? []) {
93
+ for (const fx of beforeOpen) {
66
94
  await fx();
67
95
  }
68
96
  }, {
69
97
  name: "beforeOpenFx",
70
- sid: "-vqlnbm"
71
- });
72
- const navigatedFx = attach({
73
- and: {
74
- effect: openFx
75
- },
76
- or: {
77
- name: "navigatedFx",
78
- sid: "a4yadj"
79
- }
98
+ sid: "7f9gfq"
80
99
  });
81
100
  const defaultParams = {};
82
101
  sample({
@@ -85,7 +104,7 @@ function createRoute(config) {
85
104
  target: openFx
86
105
  }],
87
106
  or: {
88
- sid: "ynxuww"
107
+ sid: "-yxhjaa"
89
108
  }
90
109
  });
91
110
  sample({
@@ -98,24 +117,36 @@ function createRoute(config) {
98
117
  target: navigatedFx
99
118
  }],
100
119
  or: {
101
- sid: "z28ica"
120
+ sid: "-yj6vuw"
102
121
  }
103
122
  });
104
123
  sample({
105
124
  and: [{
106
- clock: navigatedFx.doneData,
107
- fn: (payload) => {
108
- if (!payload) {
109
- return defaultParams;
110
- }
111
- return "params" in payload ? {
112
- ...payload.params
113
- } : defaultParams;
125
+ clock: navigatedFx.done,
126
+ fn: (_ref) => {
127
+ let {
128
+ params
129
+ } = _ref;
130
+ return params;
114
131
  },
115
- target: $params
132
+ target: forceOpenParentFx
116
133
  }],
117
134
  or: {
118
- sid: "z5j9wg"
135
+ sid: "-yfw4aq"
136
+ }
137
+ });
138
+ createAction({
139
+ clock: [navigatedFx.doneData, forceOpenParentFx.doneData],
140
+ target: {
141
+ $params
142
+ },
143
+ fn: (target, payload) => {
144
+ if (!payload) {
145
+ return target.$params(defaultParams);
146
+ }
147
+ return target.$params("params" in payload ? {
148
+ ...payload.params
149
+ } : defaultParams);
119
150
  }
120
151
  });
121
152
  sample({
@@ -125,20 +156,20 @@ function createRoute(config) {
125
156
  target: $params
126
157
  }],
127
158
  or: {
128
- sid: "-z1vw16"
159
+ sid: "-xhsvic"
129
160
  }
130
161
  });
131
- split({
132
- and: [{
133
- source: navigatedFx.doneData,
134
- match: () => typeof window === "undefined" ? "server" : "client",
135
- cases: {
136
- server: openedOnServer,
137
- client: openedOnClient
162
+ createAction({
163
+ clock: [navigatedFx.doneData, forceOpenParentFx.doneData],
164
+ target: {
165
+ openedOnServer,
166
+ openedOnClient
167
+ },
168
+ fn: (target, payload) => {
169
+ if (typeof window === "undefined") {
170
+ return target.openedOnServer(payload);
138
171
  }
139
- }],
140
- or: {
141
- sid: "-yyl4h0"
172
+ return target.openedOnClient(payload);
142
173
  }
143
174
  });
144
175
  sample({
@@ -147,7 +178,7 @@ function createRoute(config) {
147
178
  target: opened
148
179
  }],
149
180
  or: {
150
- sid: "-yhji2t"
181
+ sid: "-w72d2n"
151
182
  }
152
183
  });
153
184
  sample({
@@ -156,7 +187,7 @@ function createRoute(config) {
156
187
  target: closed
157
188
  }],
158
189
  or: {
159
- sid: "-y38unf"
190
+ sid: "-w4be3u"
160
191
  }
161
192
  });
162
193
  sample({
@@ -165,13 +196,14 @@ function createRoute(config) {
165
196
  target: $isOpened
166
197
  }],
167
198
  or: {
168
- sid: "-y0hvom"
199
+ sid: "-ls2oed"
169
200
  }
170
201
  });
171
202
  return {
172
203
  $params,
173
204
  $isOpened,
174
205
  $isPending,
206
+ // @ts-expect-error :((
175
207
  open,
176
208
  closed,
177
209
  opened,
@@ -182,12 +214,14 @@ function createRoute(config) {
182
214
  navigated,
183
215
  close,
184
216
  openFx,
217
+ forceOpenParentFx,
185
218
  setAsyncImport: (value) => asyncImport = value
186
219
  },
187
220
  "@@unitShape": () => ({
188
221
  params: $params,
189
222
  isPending: $isPending,
190
223
  isOpened: $isOpened,
224
+ // @ts-expect-error :((
191
225
  onOpen: open
192
226
  })
193
227
  };
@@ -208,7 +242,7 @@ function trackQueryControlsFactory(_ref) {
208
242
  return trackQueryFactory({
209
243
  $activeRoutes: createStore([], {
210
244
  name: "$activeRoutes",
211
- sid: "ni3bf8"
245
+ sid: "og6k7m"
212
246
  }),
213
247
  $query,
214
248
  navigate
@@ -227,27 +261,27 @@ function trackQueryFactory(_ref2) {
227
261
  } = config;
228
262
  const $entered = createStore(false, {
229
263
  name: "$entered",
230
- sid: "-i5493b"
264
+ sid: "-792y0u"
231
265
  });
232
266
  const entered = createEvent({
233
267
  name: "entered",
234
- sid: "9i8bun"
268
+ sid: "agbkn1"
235
269
  });
236
270
  const exited = createEvent({
237
271
  name: "exited",
238
- sid: "-p2hcsy"
272
+ sid: "-o4e40k"
239
273
  });
240
274
  const enter = createEvent({
241
275
  name: "enter",
242
- sid: "30cmky"
276
+ sid: "3yfvdc"
243
277
  });
244
278
  const exit = createEvent({
245
279
  name: "exit",
246
- sid: "-2657ec"
280
+ sid: "-181yly"
247
281
  });
248
282
  const changeEntered = createEvent({
249
283
  name: "changeEntered",
250
- sid: "-5jm7r1"
284
+ sid: "-4liyyn"
251
285
  });
252
286
  sample({
253
287
  and: [{
@@ -255,7 +289,7 @@ function trackQueryFactory(_ref2) {
255
289
  target: $entered
256
290
  }],
257
291
  or: {
258
- sid: "-j6nk9y"
292
+ sid: "-iu0amn"
259
293
  }
260
294
  });
261
295
  sample({
@@ -280,7 +314,7 @@ function trackQueryFactory(_ref2) {
280
314
  target: [entered, changeEntered.prepend(() => true)]
281
315
  }],
282
316
  or: {
283
- sid: "-iscwuk"
317
+ sid: "-ir9bnu"
284
318
  }
285
319
  });
286
320
  sample({
@@ -301,7 +335,7 @@ function trackQueryFactory(_ref2) {
301
335
  target: [exited.prepend(() => void 0), changeEntered.prepend(() => false)]
302
336
  }],
303
337
  or: {
304
- sid: "-ibv31q"
338
+ sid: "-iarhv0"
305
339
  }
306
340
  });
307
341
  sample({
@@ -319,7 +353,7 @@ function trackQueryFactory(_ref2) {
319
353
  target: navigate
320
354
  }],
321
355
  or: {
322
- sid: "-hsmaa3"
356
+ sid: "-hqywi0"
323
357
  }
324
358
  });
325
359
  sample({
@@ -345,7 +379,7 @@ function trackQueryFactory(_ref2) {
345
379
  target: navigate
346
380
  }],
347
381
  or: {
348
- sid: "-whgzm0"
382
+ sid: "-wf9t8k"
349
383
  }
350
384
  });
351
385
  return {
@@ -356,298 +390,46 @@ function trackQueryFactory(_ref2) {
356
390
  };
357
391
  };
358
392
  }
359
- function prepareParser(tokens) {
360
- return (input) => {
361
- const rawTokens = input.split("/").map((part) => part.trim()).filter((part) => part !== "");
362
- let params = null;
363
- function setKey(key, value) {
364
- if (!params) {
365
- params = {};
366
- }
367
- params[key] = value;
368
- }
369
- if (tokens.length === 0) {
370
- return rawTokens.length === 0 ? {
371
- path: input,
372
- params: null
373
- } : null;
374
- }
375
- for (let i = 0; i < tokens.length; i++) {
376
- const token = tokens[i];
377
- switch (token.type) {
378
- case "const": {
379
- if (token.name !== rawTokens.shift()) {
380
- return null;
381
- }
382
- continue;
383
- }
384
- case "parameter": {
385
- const {
386
- arrayProps,
387
- genericProps,
388
- required
389
- } = token.payload;
390
- if (arrayProps) {
391
- const array = [];
392
- let rawToken2;
393
- while (true) {
394
- rawToken2 = rawTokens.shift();
395
- if (!rawToken2) {
396
- break;
397
- }
398
- switch (genericProps == null ? void 0 : genericProps.type) {
399
- case "number": {
400
- if (isNaN(+rawToken2)) {
401
- return null;
402
- }
403
- array.push(+rawToken2);
404
- break;
405
- }
406
- case "union": {
407
- if (!genericProps.items.includes(rawToken2)) {
408
- return null;
409
- }
410
- array.push(rawToken2);
411
- break;
412
- }
413
- default: {
414
- array.push(rawToken2);
415
- break;
416
- }
417
- }
418
- if (array.length >= (arrayProps.max ?? Infinity)) {
419
- break;
420
- }
421
- }
422
- if (array.length < (arrayProps.min ?? 0)) {
423
- return null;
424
- }
425
- if (rawTokens.length > 0 && !tokens[i + 1]) {
426
- return null;
427
- }
428
- setKey(token.name, array);
429
- break;
430
- }
431
- const rawToken = rawTokens.shift();
432
- if (required && !rawToken) {
433
- return null;
434
- }
435
- if (!rawToken) {
436
- setKey(token.name, void 0);
437
- continue;
438
- }
439
- switch (genericProps == null ? void 0 : genericProps.type) {
440
- case "number": {
441
- if (isNaN(+rawToken)) {
442
- return null;
443
- }
444
- setKey(token.name, +rawToken);
445
- break;
446
- }
447
- case "union": {
448
- if (!genericProps.items.includes(rawToken)) {
449
- return null;
450
- }
451
- setKey(token.name, rawToken);
452
- break;
453
- }
454
- default: {
455
- setKey(token.name, rawToken);
456
- break;
457
- }
458
- }
459
- }
460
- }
461
- }
462
- if (rawTokens.length > 0) {
463
- return null;
464
- }
465
- return {
466
- path: input,
467
- params
468
- };
469
- };
470
- }
471
- function getTokenParameters(params) {
472
- if (!params) {
473
- return null;
474
- }
475
- const name = params[1];
476
- let genericProps;
477
- let arrayProps;
478
- let modificator;
479
- for (const parameter of params.slice(2)) {
480
- if (!parameter) {
481
- continue;
482
- }
483
- if (parameter.includes("<")) {
484
- genericProps = parameter.replaceAll(/\s/g, "").replace("<", "").replace(">", "");
485
- continue;
486
- }
487
- if (parameter.includes("{")) {
488
- arrayProps = parameter.replace("{", "").replace("}", "").split(",").map((item) => parseInt(item));
489
- }
490
- if (["*", "?", "+"].includes(parameter)) {
491
- modificator = parameter;
492
- continue;
493
- }
494
- }
495
- return {
496
- name,
497
- genericProps,
498
- arrayProps,
499
- modificator
500
- };
501
- }
502
- function prepareBuilder(tokens) {
503
- return (params) => {
504
- const result = [];
505
- if (tokens.length === 0) {
506
- return "/";
507
- }
508
- for (const token of tokens) {
509
- switch (token.type) {
510
- case "const": {
511
- result.push(token.name);
512
- break;
513
- }
514
- case "parameter": {
515
- if (!params[token.name]) {
516
- continue;
517
- }
518
- if (Array.isArray(params[token.name])) {
519
- for (const param of params[token.name]) {
520
- result.push(param.toString());
521
- }
522
- } else {
523
- result.push(params[token.name].toString());
524
- }
525
- break;
526
- }
527
- }
528
- }
529
- return `/${result.join("/")}`;
530
- };
531
- }
532
- function compile(path) {
533
- const tokens = [];
534
- const regexp = /:(\w+)(<[\s?\w|]+>)?({\d+\,\d+})?([+*?])?/;
535
- const parsedTokens = path.split("/").filter(Boolean);
536
- for (let i = 0; i < parsedTokens.length; i++) {
537
- const parsedToken = parsedTokens[i];
538
- if (!parsedToken) {
539
- continue;
540
- }
541
- const parameters = getTokenParameters(parsedToken.match(regexp));
542
- if (!parameters) {
543
- tokens.push({
544
- type: "const",
545
- name: parsedToken,
546
- payload: void 0
547
- });
548
- continue;
549
- }
550
- const {
551
- arrayProps,
552
- genericProps,
553
- modificator,
554
- name
555
- } = parameters;
556
- if (!name) {
557
- throw new Error(`Invalid path: "${path}". Name for argument must be provided`);
558
- }
559
- const token = {
560
- type: "parameter",
561
- name,
562
- payload: {
563
- required: true
564
- }
565
- };
566
- if (genericProps && genericProps === "number") {
567
- token.payload.genericProps = {
568
- type: "number"
569
- };
570
- }
571
- if (genericProps && genericProps.includes("|")) {
572
- token.payload.genericProps = {
573
- type: "union",
574
- items: genericProps.split("|")
575
- };
576
- }
577
- switch (modificator) {
578
- case "*": {
579
- token.payload.arrayProps = {};
580
- break;
581
- }
582
- case "+": {
583
- token.payload.arrayProps = {
584
- min: 1
585
- };
586
- break;
587
- }
588
- case "?": {
589
- token.payload.required = false;
590
- break;
591
- }
592
- }
593
- if (arrayProps) {
594
- token.payload.arrayProps = {
595
- ...token.payload.arrayProps,
596
- min: arrayProps[0],
597
- max: arrayProps[1]
598
- };
599
- }
600
- tokens.push(token);
601
- }
602
- return {
603
- /**
604
- * @param input Input path
605
- * @returns `{ path: string; params: Params }` | `null`
606
- */
607
- parse: prepareParser(tokens),
608
- /**
609
- * @param params Route parameters
610
- * @returns string
611
- */
612
- build: prepareBuilder(tokens)
613
- };
614
- }
615
393
  function createRouterControls() {
616
394
  const $history = createStore(null, {
617
395
  and: {
618
396
  serialize: "ignore"
619
397
  },
620
398
  name: "$history",
621
- sid: "-ld7lzl"
399
+ sid: "-kw5zle"
622
400
  });
623
401
  const $locationState = createStore({
624
402
  query: {},
625
403
  path: null
626
404
  }, {
627
405
  name: "$locationState",
628
- sid: "-4u3w85"
406
+ sid: "-2xxend"
407
+ });
408
+ const $subscription = createStore(null, {
409
+ name: "$subscription",
410
+ sid: "27a2zr"
629
411
  });
630
412
  const $query = $locationState.map((state) => state.query);
631
413
  const $path = $locationState.map((state) => state.path);
632
414
  const setHistory = createEvent({
633
415
  name: "setHistory",
634
- sid: "-ormmkk"
416
+ sid: "-lxcw7e"
635
417
  });
636
418
  const navigate = createEvent({
637
419
  name: "navigate",
638
- sid: "tawqep"
420
+ sid: "w56grv"
639
421
  });
640
422
  const back = createEvent({
641
423
  name: "back",
642
- sid: "bxy8rt"
424
+ sid: "es7z4z"
643
425
  });
644
426
  const forward = createEvent({
645
427
  name: "forward",
646
- sid: "-bpmzb1"
428
+ sid: "12ktc8"
647
429
  });
648
430
  const locationUpdated = createEvent({
649
431
  name: "locationUpdated",
650
- sid: "lkzldx"
432
+ sid: "yd7e16"
651
433
  });
652
434
  const navigateFx = attach({
653
435
  and: {
@@ -674,34 +456,70 @@ function createRouterControls() {
674
456
  },
675
457
  or: {
676
458
  name: "navigateFx",
677
- sid: "-ov1xn7"
459
+ sid: "-m0s7a1"
678
460
  }
679
461
  });
680
- const subscribeHistoryFx = createEffect((history) => {
681
- const historyLocationUpdated = scopeBind(locationUpdated);
682
- historyLocationUpdated({
683
- pathname: history.location.pathname,
684
- query: {
685
- ...queryString.parse(history.location.search)
462
+ const subscribeHistoryFx = createAsyncAction({
463
+ target: {
464
+ locationUpdated,
465
+ $subscription
466
+ },
467
+ source: {
468
+ $subscription
469
+ },
470
+ fn: async (target, getSource, history) => {
471
+ if (!history) {
472
+ throw Error("Cannot initialize router controls with empty history adapter. Please provide some provider or check your code for passing of nullable value");
686
473
  }
687
- });
688
- if (!history) {
689
- throw new Error();
690
- }
691
- history.listen((_ref2) => {
692
- let {
693
- location
694
- } = _ref2;
695
- historyLocationUpdated({
696
- pathname: location.pathname,
474
+ const source = await getSource();
475
+ if (source.subscription) {
476
+ source.subscription.unsubscribe();
477
+ }
478
+ target.locationUpdated({
479
+ pathname: history.location.pathname,
697
480
  query: {
698
- ...queryString.parse(location.search)
481
+ ...queryString.parse(history.location.search)
699
482
  }
700
483
  });
701
- });
702
- }, {
703
- name: "subscribeHistoryFx",
704
- sid: "-m60vds"
484
+ target.$subscription(history.listen((location) => {
485
+ target.locationUpdated({
486
+ pathname: location.pathname,
487
+ query: {
488
+ ...queryString.parse(location.search)
489
+ }
490
+ });
491
+ }));
492
+ }
493
+ });
494
+ const goBackFx = attach({
495
+ and: {
496
+ source: $history,
497
+ effect: (history) => {
498
+ if (!history) {
499
+ throw new Error("history not found");
500
+ }
501
+ history.goBack();
502
+ }
503
+ },
504
+ or: {
505
+ name: "goBackFx",
506
+ sid: "k3gxue"
507
+ }
508
+ });
509
+ const goForwardFx = attach({
510
+ and: {
511
+ source: $history,
512
+ effect: (history) => {
513
+ if (!history) {
514
+ throw new Error("history not found");
515
+ }
516
+ history.goForward();
517
+ }
518
+ },
519
+ or: {
520
+ name: "goForwardFx",
521
+ sid: "1m1c40"
522
+ }
705
523
  });
706
524
  sample({
707
525
  and: [{
@@ -709,7 +527,7 @@ function createRouterControls() {
709
527
  target: $history
710
528
  }],
711
529
  or: {
712
- sid: "ii4q"
530
+ sid: "1ycdhl"
713
531
  }
714
532
  });
715
533
  sample({
@@ -719,7 +537,7 @@ function createRouterControls() {
719
537
  target: subscribeHistoryFx
720
538
  }],
721
539
  or: {
722
- sid: "39h3j"
540
+ sid: "213cge"
723
541
  }
724
542
  });
725
543
  sample({
@@ -732,7 +550,7 @@ function createRouterControls() {
732
550
  target: $locationState
733
551
  }],
734
552
  or: {
735
- sid: "i3x4a"
553
+ sid: "2fxsh5"
736
554
  }
737
555
  });
738
556
  sample({
@@ -746,7 +564,25 @@ function createRouterControls() {
746
564
  target: navigateFx
747
565
  }],
748
566
  or: {
749
- sid: "ylqx4"
567
+ sid: "2wfm9z"
568
+ }
569
+ });
570
+ sample({
571
+ and: [{
572
+ clock: back,
573
+ target: goBackFx
574
+ }],
575
+ or: {
576
+ sid: "3btuw3"
577
+ }
578
+ });
579
+ sample({
580
+ and: [{
581
+ clock: forward,
582
+ target: goForwardFx
583
+ }],
584
+ or: {
585
+ sid: "3ektuw"
750
586
  }
751
587
  });
752
588
  return {
@@ -765,6 +601,31 @@ function createRouterControls() {
765
601
  })
766
602
  };
767
603
  }
604
+ const is = {
605
+ route(input) {
606
+ return is.pathRoute(input) || is.pathlessRoute(input);
607
+ },
608
+ pathRoute(input) {
609
+ return typeof input === "object" && input !== null && "@@type" in input && input["@@type"] === "path-route";
610
+ },
611
+ pathlessRoute(input) {
612
+ return typeof input === "object" && input !== null && "@@type" in input && input["@@type"] === "pathless-route";
613
+ },
614
+ router(input) {
615
+ return typeof input === "object" && input !== null && "@@type" in input && input["@@type"] === "router";
616
+ }
617
+ };
618
+ const inputIs = {
619
+ pathlessRoute(route) {
620
+ return "route" in route;
621
+ },
622
+ pathRoute(route) {
623
+ return !this.pathlessRoute(route) && !this.router(route);
624
+ },
625
+ router(route) {
626
+ return is.router(route);
627
+ }
628
+ };
768
629
  function createRouter(config) {
769
630
  const {
770
631
  base = "/",
@@ -773,34 +634,87 @@ function createRouter(config) {
773
634
  const {
774
635
  $path,
775
636
  $query,
637
+ $history,
776
638
  back,
777
639
  forward,
778
640
  navigate,
779
641
  setHistory,
780
642
  locationUpdated
781
- } = createRouterControls();
782
- const mappedRoutes = routes.map((route) => {
783
- let internalRoute = route;
643
+ } = config.controls ?? createRouterControls();
644
+ function getPathWithBase(path) {
645
+ if (base === "/") {
646
+ return path;
647
+ }
648
+ return path === "/" ? base : `${base}${path}`;
649
+ }
650
+ const connectToParentRouter = createEvent({
651
+ name: "connectToParentRouter",
652
+ sid: "t0jaae"
653
+ });
654
+ let parent = null;
655
+ const knownRoutes = [];
656
+ function mapRoute(inputRoute) {
657
+ if (inputIs.pathlessRoute(inputRoute)) {
658
+ const {
659
+ build: build2,
660
+ parse: parse2
661
+ } = compile(getPathWithBase(inputRoute.path));
662
+ const route2 = {
663
+ route: inputRoute.route,
664
+ path: inputRoute.path,
665
+ build: build2,
666
+ parse: parse2
667
+ };
668
+ return route2;
669
+ }
670
+ if (inputIs.router(inputRoute)) {
671
+ sample({
672
+ and: [{
673
+ clock: setHistory,
674
+ target: inputRoute.setHistory
675
+ }],
676
+ or: {
677
+ sid: "ez3kyw"
678
+ }
679
+ });
680
+ return null;
681
+ }
682
+ let internalRoute = inputRoute;
784
683
  const path = [];
785
684
  path.unshift(internalRoute.path);
786
685
  while (internalRoute.parent) {
686
+ if (is.pathlessRoute(internalRoute.parent)) {
687
+ break;
688
+ }
787
689
  internalRoute = internalRoute.parent;
788
690
  if (internalRoute.path !== "/") {
789
691
  path.unshift(internalRoute.path);
790
692
  }
791
693
  }
792
- const joinedPath = base === "/" ? path.join("") : [base, ...path].join("");
694
+ const joinedPath = getPathWithBase(path.join(""));
793
695
  const {
794
696
  build,
795
697
  parse
796
698
  } = compile(joinedPath);
797
- return {
798
- route,
699
+ const route = {
700
+ route: inputRoute,
799
701
  path: joinedPath,
800
702
  build,
801
703
  parse
802
704
  };
803
- });
705
+ return route;
706
+ }
707
+ const ownRoutes = routes.reduce((acc, inputRoute) => {
708
+ const mappedRoute = mapRoute(inputRoute);
709
+ if (mappedRoute) {
710
+ knownRoutes.push(mappedRoute);
711
+ acc.push(mappedRoute);
712
+ }
713
+ if (inputIs.router(inputRoute)) {
714
+ knownRoutes.push(...inputRoute.knownRoutes);
715
+ }
716
+ return acc;
717
+ }, []);
804
718
  const $activeRoutes = $path.map((path) => {
805
719
  const result = [];
806
720
  if (!path) {
@@ -809,7 +723,7 @@ function createRouter(config) {
809
723
  for (const {
810
724
  route,
811
725
  parse
812
- } of mappedRoutes) {
726
+ } of ownRoutes) {
813
727
  if (parse(path)) {
814
728
  result.push(route);
815
729
  }
@@ -830,7 +744,7 @@ function createRouter(config) {
830
744
  for (const {
831
745
  route,
832
746
  parse
833
- } of mappedRoutes) {
747
+ } of ownRoutes) {
834
748
  const matchResult = parse(path);
835
749
  const [routeClosed, routeNavigated] = [scopeBind(route.internal.close), scopeBind(route.internal.navigated)];
836
750
  if (!matchResult) {
@@ -846,31 +760,35 @@ function createRouter(config) {
846
760
  },
847
761
  or: {
848
762
  name: "openRoutesByPathFx",
849
- sid: "-3zl7vq"
763
+ sid: "-bl0nuq"
850
764
  }
851
765
  });
852
- for (const {
853
- route,
854
- build
855
- } of mappedRoutes) {
856
- sample({
857
- and: [{
858
- clock: route.internal.openFx.doneData,
859
- filter: (payload) => (payload == null ? void 0 : payload.navigate) !== false,
860
- fn: (payload) => {
861
- return {
862
- path: build(payload && "params" in payload ? payload.params : void 0),
863
- query: (payload == null ? void 0 : payload.query) ?? {},
864
- replace: payload == null ? void 0 : payload.replace
865
- };
866
- },
867
- target: navigate
868
- }],
869
- or: {
870
- sid: "exzzqg"
766
+ function registerRouteApi(_ref2) {
767
+ let {
768
+ route,
769
+ build
770
+ } = _ref2;
771
+ createAction({
772
+ clock: route.internal.openFx.doneData,
773
+ target: {
774
+ navigate
775
+ },
776
+ fn: (target, payload) => {
777
+ if ((payload == null ? void 0 : payload.navigate) === false) {
778
+ return;
779
+ }
780
+ const navigateParams = {
781
+ path: build(payload && "params" in payload ? payload.params : void 0),
782
+ query: (payload == null ? void 0 : payload.query) ?? {},
783
+ replace: payload == null ? void 0 : payload.replace
784
+ };
785
+ return target.navigate(navigateParams);
871
786
  }
872
787
  });
873
788
  }
789
+ for (const route of ownRoutes) {
790
+ registerRouteApi(route);
791
+ }
874
792
  sample({
875
793
  and: [{
876
794
  clock: locationUpdated,
@@ -881,24 +799,47 @@ function createRouter(config) {
881
799
  target: openRoutesByPathFx
882
800
  }],
883
801
  or: {
884
- sid: "ficdn3"
802
+ sid: "ukhip5"
885
803
  }
886
804
  });
887
- return {
805
+ const router = {
806
+ "@@type": "router",
888
807
  $query,
889
808
  $path,
809
+ $history,
890
810
  $activeRoutes,
891
811
  back,
892
812
  forward,
893
813
  navigate,
894
- routes,
895
814
  setHistory,
896
- mappedRoutes,
815
+ ownRoutes,
816
+ knownRoutes,
817
+ internal: {
818
+ connectToParentRouter,
819
+ get parent() {
820
+ return parent;
821
+ },
822
+ set parent(router2) {
823
+ parent = router2;
824
+ },
825
+ base
826
+ },
897
827
  trackQuery: trackQueryFactory({
898
828
  $activeRoutes,
899
829
  $query,
900
830
  navigate
901
831
  }),
832
+ registerRoute: (route) => {
833
+ const mappedRoute = mapRoute(route);
834
+ if (mappedRoute) {
835
+ knownRoutes.push(mappedRoute);
836
+ ownRoutes.push(mappedRoute);
837
+ registerRouteApi(mappedRoute);
838
+ }
839
+ if (inputIs.router(route)) {
840
+ knownRoutes.push(...route.knownRoutes);
841
+ }
842
+ },
902
843
  "@@unitShape": () => ({
903
844
  query: $query,
904
845
  path: $path,
@@ -908,6 +849,7 @@ function createRouter(config) {
908
849
  onNavigate: navigate
909
850
  })
910
851
  };
852
+ return router;
911
853
  }
912
854
  function createVirtualRoute() {
913
855
  let options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
@@ -1006,6 +948,7 @@ function createVirtualRoute() {
1006
948
  }
1007
949
  });
1008
950
  return {
951
+ "@@type": "pathless-route",
1009
952
  $params,
1010
953
  $isOpened,
1011
954
  $isPending,
@@ -1037,7 +980,7 @@ function chainRoute(props) {
1037
980
  let asyncImport;
1038
981
  const waitForAsyncBundleFx = createEffect(() => asyncImport == null ? void 0 : asyncImport(), {
1039
982
  name: "waitForAsyncBundleFx",
1040
- sid: "qdkcuo"
983
+ sid: "t7u37u"
1041
984
  });
1042
985
  const openFx = createEffect(async (payload) => {
1043
986
  await waitForAsyncBundleFx();
@@ -1046,13 +989,13 @@ function chainRoute(props) {
1046
989
  }
1047
990
  }, {
1048
991
  name: "openFx",
1049
- sid: "-fwntqy"
992
+ sid: "-34g13p"
1050
993
  });
1051
994
  const transformer = (payload) => {
1052
995
  if (!payload) {
1053
- return null;
996
+ return {};
1054
997
  }
1055
- return "params" in payload ? payload.params : null;
998
+ return "params" in payload ? payload.params : {};
1056
999
  };
1057
1000
  const virtualRoute = createVirtualRoute({
1058
1001
  transformer
@@ -1063,7 +1006,7 @@ function chainRoute(props) {
1063
1006
  target: openFx
1064
1007
  }],
1065
1008
  or: {
1066
- sid: "-s9xf6p"
1009
+ sid: "-1tngcz"
1067
1010
  }
1068
1011
  });
1069
1012
  sample({
@@ -1073,7 +1016,7 @@ function chainRoute(props) {
1073
1016
  target: virtualRoute.$params
1074
1017
  }],
1075
1018
  or: {
1076
- sid: "-1u78yc"
1019
+ sid: "-1qwhe6"
1077
1020
  }
1078
1021
  });
1079
1022
  if (openOn) {
@@ -1081,11 +1024,13 @@ function chainRoute(props) {
1081
1024
  and: [{
1082
1025
  clock: openOn,
1083
1026
  source: virtualRoute.$params,
1084
- fn: (params) => params,
1027
+ fn: (params) => ({
1028
+ params
1029
+ }),
1085
1030
  target: virtualRoute.open
1086
1031
  }],
1087
1032
  or: {
1088
- sid: "-1qcor3"
1033
+ sid: "-1bi8qc"
1089
1034
  }
1090
1035
  });
1091
1036
  }
@@ -1096,7 +1041,7 @@ function chainRoute(props) {
1096
1041
  target: virtualRoute.close
1097
1042
  }],
1098
1043
  or: {
1099
- sid: "-19uuy9"
1044
+ sid: "-v0exi"
1100
1045
  }
1101
1046
  });
1102
1047
  sample({
@@ -1105,7 +1050,7 @@ function chainRoute(props) {
1105
1050
  target: virtualRoute.cancelled
1106
1051
  }],
1107
1052
  or: {
1108
- sid: "-vk7iv"
1053
+ sid: "-s9fyp"
1109
1054
  }
1110
1055
  });
1111
1056
  }
@@ -1163,11 +1108,86 @@ function group(routes) {
1163
1108
  });
1164
1109
  return virtual;
1165
1110
  }
1111
+ function historyAdapter(history) {
1112
+ return {
1113
+ location: history.location,
1114
+ push: history.push.bind(history),
1115
+ replace: history.replace.bind(history),
1116
+ goBack: history.back.bind(history),
1117
+ goForward: history.forward.bind(history),
1118
+ listen: (callback) => {
1119
+ const unlisten = history.listen((_ref) => {
1120
+ let {
1121
+ location
1122
+ } = _ref;
1123
+ return callback(location);
1124
+ });
1125
+ return Object.assign(unlisten, {
1126
+ unsubscribe: unlisten
1127
+ });
1128
+ }
1129
+ };
1130
+ }
1131
+ function extractLocation(location) {
1132
+ const url = new URL(decodeURIComponent(location.search));
1133
+ return {
1134
+ pathname: url.pathname,
1135
+ search: url.search,
1136
+ hash: url.hash
1137
+ };
1138
+ }
1139
+ function queryAdapter(history) {
1140
+ return {
1141
+ location: extractLocation(history.location),
1142
+ push: (to) => {
1143
+ if (typeof to === "string") {
1144
+ const url = new URL(history.location.pathname);
1145
+ url.search = to;
1146
+ history.push(url.toString());
1147
+ } else {
1148
+ const url = new URL(history.location.pathname);
1149
+ url.search = `${to.pathname ?? ""}${to.search ?? ""}${to.hash ?? ""}`;
1150
+ history.push(url.toString());
1151
+ }
1152
+ },
1153
+ replace: (to) => {
1154
+ if (typeof to === "string") {
1155
+ const url = new URL(history.location.pathname);
1156
+ url.search = to;
1157
+ history.replace(url.toString());
1158
+ } else {
1159
+ const url = new URL(history.location.pathname);
1160
+ url.search = `${to.pathname ?? ""}${to.search ?? ""}${to.hash ?? ""}`;
1161
+ history.replace(url.toString());
1162
+ }
1163
+ },
1164
+ goBack: () => {
1165
+ history.back();
1166
+ },
1167
+ goForward: () => {
1168
+ history.forward();
1169
+ },
1170
+ listen: (callback) => {
1171
+ const unlisten = history.listen((_ref) => {
1172
+ let {
1173
+ location
1174
+ } = _ref;
1175
+ return callback(extractLocation(location));
1176
+ });
1177
+ return Object.assign(unlisten, {
1178
+ unsubscribe: unlisten
1179
+ });
1180
+ }
1181
+ };
1182
+ }
1166
1183
  export {
1167
1184
  chainRoute,
1168
1185
  createRoute,
1169
1186
  createRouter,
1170
1187
  createRouterControls,
1171
1188
  createVirtualRoute,
1172
- group
1189
+ group,
1190
+ historyAdapter,
1191
+ is,
1192
+ queryAdapter
1173
1193
  };