@tanstack/react-router 0.0.1-beta.18 → 0.0.1-beta.180

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.
@@ -0,0 +1,644 @@
1
+ /**
2
+ * @tanstack/react-router/src/index.tsx
3
+ *
4
+ * Copyright (c) TanStack
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE.md file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+ 'use strict';
12
+
13
+ Object.defineProperty(exports, '__esModule', { value: true });
14
+
15
+ var _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
16
+ var React = require('react');
17
+ var reactStore = require('@tanstack/react-store');
18
+ var invariant = require('tiny-invariant');
19
+ var warning = require('tiny-warning');
20
+ var routerCore = require('@tanstack/router-core');
21
+
22
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
23
+
24
+ function _interopNamespace(e) {
25
+ if (e && e.__esModule) return e;
26
+ var n = Object.create(null);
27
+ if (e) {
28
+ Object.keys(e).forEach(function (k) {
29
+ if (k !== 'default') {
30
+ var d = Object.getOwnPropertyDescriptor(e, k);
31
+ Object.defineProperty(n, k, d.get ? d : {
32
+ enumerable: true,
33
+ get: function () { return e[k]; }
34
+ });
35
+ }
36
+ });
37
+ }
38
+ n["default"] = e;
39
+ return Object.freeze(n);
40
+ }
41
+
42
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
43
+ var invariant__default = /*#__PURE__*/_interopDefaultLegacy(invariant);
44
+ var warning__default = /*#__PURE__*/_interopDefaultLegacy(warning);
45
+
46
+ routerCore.Route.__onInit = route => {
47
+ Object.assign(route, {
48
+ useMatch: (opts = {}) => {
49
+ return useMatch({
50
+ ...opts,
51
+ from: route.id
52
+ });
53
+ },
54
+ useLoader: (opts = {}) => {
55
+ return useLoader({
56
+ ...opts,
57
+ from: route.id
58
+ });
59
+ },
60
+ useContext: (opts = {}) => {
61
+ return useMatch({
62
+ ...opts,
63
+ from: route.id,
64
+ select: d => opts?.select ? opts.select(d.context) : d.context
65
+ });
66
+ },
67
+ useRouteContext: (opts = {}) => {
68
+ return useMatch({
69
+ ...opts,
70
+ from: route.id,
71
+ select: d => opts?.select ? opts.select(d.routeContext) : d.routeContext
72
+ });
73
+ },
74
+ useSearch: (opts = {}) => {
75
+ return useSearch({
76
+ ...opts,
77
+ from: route.id
78
+ });
79
+ },
80
+ useParams: (opts = {}) => {
81
+ return useParams({
82
+ ...opts,
83
+ from: route.id
84
+ });
85
+ }
86
+ });
87
+ };
88
+
89
+ //
90
+
91
+ function lazyRouteComponent(importer, exportName) {
92
+ let loadPromise;
93
+ const load = () => {
94
+ if (!loadPromise) {
95
+ loadPromise = importer();
96
+ }
97
+ return loadPromise;
98
+ };
99
+ const lazyComp = /*#__PURE__*/React__namespace.lazy(async () => {
100
+ const moduleExports = await load();
101
+ const comp = moduleExports[exportName ?? 'default'];
102
+ return {
103
+ default: comp
104
+ };
105
+ });
106
+ lazyComp.preload = load;
107
+ return lazyComp;
108
+ }
109
+ //
110
+
111
+ function useLinkProps(options) {
112
+ const router = useRouter();
113
+ const {
114
+ // custom props
115
+ type,
116
+ children,
117
+ target,
118
+ activeProps = () => ({
119
+ className: 'active'
120
+ }),
121
+ inactiveProps = () => ({}),
122
+ activeOptions,
123
+ disabled,
124
+ // fromCurrent,
125
+ hash,
126
+ search,
127
+ params,
128
+ to = '.',
129
+ preload,
130
+ preloadDelay,
131
+ replace,
132
+ // element props
133
+ style,
134
+ className,
135
+ onClick,
136
+ onFocus,
137
+ onMouseEnter,
138
+ onMouseLeave,
139
+ onTouchStart,
140
+ ...rest
141
+ } = options;
142
+ const linkInfo = router.buildLink(options);
143
+ if (linkInfo.type === 'external') {
144
+ const {
145
+ href
146
+ } = linkInfo;
147
+ return {
148
+ href
149
+ };
150
+ }
151
+ const {
152
+ handleClick,
153
+ handleFocus,
154
+ handleEnter,
155
+ handleLeave,
156
+ handleTouchStart,
157
+ isActive,
158
+ next
159
+ } = linkInfo;
160
+ const handleReactClick = e => {
161
+ if (options.startTransition ?? true) {
162
+ (React__namespace.startTransition || (d => d))(() => {
163
+ handleClick(e);
164
+ });
165
+ }
166
+ };
167
+ const composeHandlers = handlers => e => {
168
+ if (e.persist) e.persist();
169
+ handlers.filter(Boolean).forEach(handler => {
170
+ if (e.defaultPrevented) return;
171
+ handler(e);
172
+ });
173
+ };
174
+
175
+ // Get the active props
176
+ const resolvedActiveProps = isActive ? routerCore.functionalUpdate(activeProps, {}) ?? {} : {};
177
+
178
+ // Get the inactive props
179
+ const resolvedInactiveProps = isActive ? {} : routerCore.functionalUpdate(inactiveProps, {}) ?? {};
180
+ return {
181
+ ...resolvedActiveProps,
182
+ ...resolvedInactiveProps,
183
+ ...rest,
184
+ href: disabled ? undefined : next.href,
185
+ onClick: composeHandlers([onClick, handleReactClick]),
186
+ onFocus: composeHandlers([onFocus, handleFocus]),
187
+ onMouseEnter: composeHandlers([onMouseEnter, handleEnter]),
188
+ onMouseLeave: composeHandlers([onMouseLeave, handleLeave]),
189
+ onTouchStart: composeHandlers([onTouchStart, handleTouchStart]),
190
+ target,
191
+ style: {
192
+ ...style,
193
+ ...resolvedActiveProps.style,
194
+ ...resolvedInactiveProps.style
195
+ },
196
+ className: [className, resolvedActiveProps.className, resolvedInactiveProps.className].filter(Boolean).join(' ') || undefined,
197
+ ...(disabled ? {
198
+ role: 'link',
199
+ 'aria-disabled': true
200
+ } : undefined),
201
+ ['data-status']: isActive ? 'active' : undefined
202
+ };
203
+ }
204
+ const Link = /*#__PURE__*/React__namespace.forwardRef((props, ref) => {
205
+ const linkProps = useLinkProps(props);
206
+ return /*#__PURE__*/React__namespace.createElement("a", _rollupPluginBabelHelpers["extends"]({
207
+ ref: ref
208
+ }, linkProps, {
209
+ children: typeof props.children === 'function' ? props.children({
210
+ isActive: linkProps['data-status'] === 'active'
211
+ }) : props.children
212
+ }));
213
+ });
214
+ function Navigate(props) {
215
+ const router = useRouter();
216
+ React__namespace.useLayoutEffect(() => {
217
+ router.navigate(props);
218
+ }, []);
219
+ return null;
220
+ }
221
+ const matchIdsContext = /*#__PURE__*/React__namespace.createContext(null);
222
+ const routerContext = /*#__PURE__*/React__namespace.createContext(null);
223
+ function useRouterState(opts) {
224
+ const router = useRouter();
225
+ return reactStore.useStore(router.__store, opts?.select);
226
+ }
227
+ function RouterProvider({
228
+ router,
229
+ ...rest
230
+ }) {
231
+ router.update(rest);
232
+ React__namespace.useEffect(() => {
233
+ let unsub;
234
+ React__namespace.startTransition(() => {
235
+ unsub = router.mount();
236
+ });
237
+ return unsub;
238
+ }, [router]);
239
+ const Wrap = router.options.Wrap || React__namespace.Fragment;
240
+ return /*#__PURE__*/React__namespace.createElement(Wrap, null, /*#__PURE__*/React__namespace.createElement(routerContext.Provider, {
241
+ value: router
242
+ }, /*#__PURE__*/React__namespace.createElement(Matches, null)));
243
+ }
244
+ function Matches() {
245
+ const router = useRouter();
246
+ const matchIds = useRouterState({
247
+ select: state => {
248
+ const hasPendingComponent = state.pendingMatches.some(d => {
249
+ const route = router.getRoute(d.routeId);
250
+ return !!route?.options.pendingComponent;
251
+ });
252
+ if (hasPendingComponent) {
253
+ return state.pendingMatchIds;
254
+ }
255
+ return state.matchIds;
256
+ }
257
+ });
258
+ return /*#__PURE__*/React__namespace.createElement(matchIdsContext.Provider, {
259
+ value: [undefined, ...matchIds]
260
+ }, /*#__PURE__*/React__namespace.createElement(CatchBoundary, {
261
+ errorComponent: ErrorComponent,
262
+ route: router.getRoute(routerCore.rootRouteId),
263
+ onCatch: () => {
264
+ warning__default["default"](false, `Error in router! Consider setting an 'errorComponent' in your RootRoute! 👍`);
265
+ }
266
+ }, /*#__PURE__*/React__namespace.createElement(Outlet, null)));
267
+ }
268
+ function useRouter() {
269
+ const value = React__namespace.useContext(routerContext);
270
+ warning__default["default"](value, 'useRouter must be used inside a <Router> component!');
271
+ return value;
272
+ }
273
+ function useMatches(opts) {
274
+ const matchIds = React__namespace.useContext(matchIdsContext);
275
+ return useRouterState({
276
+ select: state => {
277
+ const matches = state.matches.slice(state.matches.findIndex(d => d.id === matchIds[0]));
278
+ return opts?.select ? opts.select(matches) : matches;
279
+ }
280
+ });
281
+ }
282
+ function useMatch(opts) {
283
+ const router = useRouter();
284
+ const nearestMatchId = React__namespace.useContext(matchIdsContext)[0];
285
+ const nearestMatchRouteId = router.getRouteMatch(nearestMatchId)?.routeId;
286
+ const matchRouteId = useRouterState({
287
+ select: state => {
288
+ const matches = state.matches;
289
+ const match = opts?.from ? matches.find(d => d.routeId === opts?.from) : matches.find(d => d.id === nearestMatchId);
290
+ return match.routeId;
291
+ }
292
+ });
293
+ if (opts?.strict ?? true) {
294
+ invariant__default["default"](nearestMatchRouteId == matchRouteId, `useMatch("${matchRouteId}") is being called in a component that is meant to render the '${nearestMatchRouteId}' route. Did you mean to 'useMatch("${matchRouteId}", { strict: false })' or 'useRoute("${matchRouteId}")' instead?`);
295
+ }
296
+ const matchSelection = useRouterState({
297
+ select: state => {
298
+ const matches = state.matches;
299
+ const match = opts?.from ? matches.find(d => d.routeId === opts?.from) : matches.find(d => d.id === nearestMatchId);
300
+ invariant__default["default"](match, `Could not find ${opts?.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`);
301
+ return opts?.select ? opts.select(match) : match;
302
+ }
303
+ });
304
+ return matchSelection;
305
+ }
306
+ function useLoader(opts) {
307
+ return useMatch({
308
+ ...opts,
309
+ select: match => opts?.select ? opts?.select(match.loaderData) : match.loaderData
310
+ });
311
+ }
312
+ function useRouterContext(opts) {
313
+ return useMatch({
314
+ ...opts,
315
+ select: match => opts?.select ? opts.select(match.context) : match.context
316
+ });
317
+ }
318
+ function useRouteContext(opts) {
319
+ return useMatch({
320
+ ...opts,
321
+ select: match => opts?.select ? opts.select(match.routeContext) : match.routeContext
322
+ });
323
+ }
324
+ function useSearch(opts) {
325
+ return useMatch({
326
+ ...opts,
327
+ select: match => {
328
+ return opts?.select ? opts.select(match.search) : match.search;
329
+ }
330
+ });
331
+ }
332
+ function useParams(opts) {
333
+ return useRouterState({
334
+ select: state => {
335
+ const params = routerCore.last(state.matches)?.params;
336
+ return opts?.select ? opts.select(params) : params;
337
+ }
338
+ });
339
+ }
340
+ function useNavigate(defaultOpts) {
341
+ const router = useRouter();
342
+ return React__namespace.useCallback(opts => {
343
+ return router.navigate({
344
+ ...defaultOpts,
345
+ ...opts
346
+ });
347
+ }, []);
348
+ }
349
+ function useMatchRoute() {
350
+ const router = useRouter();
351
+ return React__namespace.useCallback(opts => {
352
+ const {
353
+ pending,
354
+ caseSensitive,
355
+ ...rest
356
+ } = opts;
357
+ return router.matchRoute(rest, {
358
+ pending,
359
+ caseSensitive
360
+ });
361
+ }, []);
362
+ }
363
+ function MatchRoute(props) {
364
+ const matchRoute = useMatchRoute();
365
+ const params = matchRoute(props);
366
+ if (typeof props.children === 'function') {
367
+ return props.children(params);
368
+ }
369
+ return !!params ? props.children : null;
370
+ }
371
+ function Outlet() {
372
+ const matchIds = React__namespace.useContext(matchIdsContext).slice(1);
373
+ if (!matchIds[0]) {
374
+ return null;
375
+ }
376
+ return /*#__PURE__*/React__namespace.createElement(Match, {
377
+ matchIds: matchIds
378
+ });
379
+ }
380
+ const defaultPending = () => null;
381
+ function Match({
382
+ matchIds
383
+ }) {
384
+ const router = useRouter();
385
+ const matchId = matchIds[0];
386
+ const routeId = router.getRouteMatch(matchId).routeId;
387
+ const route = router.getRoute(routeId);
388
+ const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent ?? defaultPending;
389
+ const errorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent ?? ErrorComponent;
390
+ const ResolvedSuspenseBoundary = route.options.wrapInSuspense ?? !route.isRoot ? React__namespace.Suspense : SafeFragment;
391
+ const ResolvedCatchBoundary = !!errorComponent ? CatchBoundary : SafeFragment;
392
+ return /*#__PURE__*/React__namespace.createElement(matchIdsContext.Provider, {
393
+ value: matchIds
394
+ }, /*#__PURE__*/React__namespace.createElement(ResolvedSuspenseBoundary, {
395
+ fallback: /*#__PURE__*/React__namespace.createElement(PendingComponent, {
396
+ useMatch: route.useMatch,
397
+ useContext: route.useContext,
398
+ useRouteContext: route.useRouteContext,
399
+ useSearch: route.useSearch,
400
+ useParams: route.useParams
401
+ })
402
+ }, /*#__PURE__*/React__namespace.createElement(ResolvedCatchBoundary, {
403
+ key: route.id,
404
+ errorComponent: errorComponent,
405
+ route: route,
406
+ onCatch: () => {
407
+ warning__default["default"](false, `Error in route match: ${matchId}`);
408
+ }
409
+ }, /*#__PURE__*/React__namespace.createElement(MatchInner, {
410
+ matchId: matchId,
411
+ PendingComponent: PendingComponent
412
+ }))));
413
+ }
414
+ function MatchInner({
415
+ matchId,
416
+ PendingComponent
417
+ }) {
418
+ const router = useRouter();
419
+ const match = useRouterState({
420
+ select: d => {
421
+ const match = d.matchesById[matchId];
422
+ return routerCore.pick(match, ['status', 'loadPromise', 'routeId', 'error']);
423
+ }
424
+ });
425
+ const route = router.getRoute(match.routeId);
426
+ if (match.status === 'error') {
427
+ throw match.error;
428
+ }
429
+ if (match.status === 'pending') {
430
+ return /*#__PURE__*/React__namespace.createElement(PendingComponent, {
431
+ useLoader: route.useLoader,
432
+ useMatch: route.useMatch,
433
+ useContext: route.useContext,
434
+ useRouteContext: route.useRouteContext,
435
+ useSearch: route.useSearch,
436
+ useParams: route.useParams
437
+ });
438
+ }
439
+ if (match.status === 'success') {
440
+ let comp = route.options.component ?? router.options.defaultComponent;
441
+ if (comp) {
442
+ return /*#__PURE__*/React__namespace.createElement(comp, {
443
+ useLoader: route.useLoader,
444
+ useMatch: route.useMatch,
445
+ useContext: route.useContext,
446
+ useRouteContext: route.useRouteContext,
447
+ useSearch: route.useSearch,
448
+ useParams: route.useParams
449
+ });
450
+ }
451
+ return /*#__PURE__*/React__namespace.createElement(Outlet, null);
452
+ }
453
+ invariant__default["default"](false, 'Idle routeMatch status encountered during rendering! You should never see this. File an issue!');
454
+ }
455
+ function SafeFragment(props) {
456
+ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, props.children);
457
+ }
458
+ function useInjectHtml() {
459
+ const router = useRouter();
460
+ return React__namespace.useCallback(html => {
461
+ router.injectHtml(html);
462
+ }, []);
463
+ }
464
+ function useDehydrate() {
465
+ const router = useRouter();
466
+ return React__namespace.useCallback(function dehydrate(key, data) {
467
+ return router.dehydrateData(key, data);
468
+ }, []);
469
+ }
470
+ function useHydrate() {
471
+ const router = useRouter();
472
+ return function hydrate(key) {
473
+ return router.hydrateData(key);
474
+ };
475
+ }
476
+
477
+ // This is the messiest thing ever... I'm either seriously tired (likely) or
478
+ // there has to be a better way to reset error boundaries when the
479
+ // router's location key changes.
480
+
481
+ class CatchBoundary extends React__namespace.Component {
482
+ state = {
483
+ error: false,
484
+ info: undefined
485
+ };
486
+ componentDidCatch(error, info) {
487
+ this.props.onCatch(error, info);
488
+ this.setState({
489
+ error,
490
+ info
491
+ });
492
+ }
493
+ render() {
494
+ return /*#__PURE__*/React__namespace.createElement(CatchBoundaryInner, _rollupPluginBabelHelpers["extends"]({}, this.props, {
495
+ errorState: this.state,
496
+ reset: () => this.setState({})
497
+ }));
498
+ }
499
+ }
500
+ function CatchBoundaryInner(props) {
501
+ const locationKey = useRouterState({
502
+ select: d => d.resolvedLocation.key
503
+ });
504
+ const [activeErrorState, setActiveErrorState] = React__namespace.useState(props.errorState);
505
+ const errorComponent = props.errorComponent ?? ErrorComponent;
506
+ const prevKeyRef = React__namespace.useRef('');
507
+ React__namespace.useEffect(() => {
508
+ if (activeErrorState) {
509
+ if (locationKey !== prevKeyRef.current) {
510
+ setActiveErrorState({});
511
+ }
512
+ }
513
+ prevKeyRef.current = locationKey;
514
+ }, [activeErrorState, locationKey]);
515
+ React__namespace.useEffect(() => {
516
+ if (props.errorState.error) {
517
+ setActiveErrorState(props.errorState);
518
+ }
519
+ // props.reset()
520
+ }, [props.errorState.error]);
521
+ if (props.errorState.error && activeErrorState.error) {
522
+ return /*#__PURE__*/React__namespace.createElement(errorComponent, {
523
+ ...activeErrorState,
524
+ useMatch: props.route.useMatch,
525
+ useContext: props.route.useContext,
526
+ useRouteContext: props.route.useRouteContext,
527
+ useSearch: props.route.useSearch,
528
+ useParams: props.route.useParams
529
+ });
530
+ }
531
+ return props.children;
532
+ }
533
+ function ErrorComponent({
534
+ error
535
+ }) {
536
+ const [show, setShow] = React__namespace.useState(process.env.NODE_ENV !== 'production');
537
+ return /*#__PURE__*/React__namespace.createElement("div", {
538
+ style: {
539
+ padding: '.5rem',
540
+ maxWidth: '100%'
541
+ }
542
+ }, /*#__PURE__*/React__namespace.createElement("div", {
543
+ style: {
544
+ display: 'flex',
545
+ alignItems: 'center',
546
+ gap: '.5rem'
547
+ }
548
+ }, /*#__PURE__*/React__namespace.createElement("strong", {
549
+ style: {
550
+ fontSize: '1rem'
551
+ }
552
+ }, "Something went wrong!"), /*#__PURE__*/React__namespace.createElement("button", {
553
+ style: {
554
+ appearance: 'none',
555
+ fontSize: '.6em',
556
+ border: '1px solid currentColor',
557
+ padding: '.1rem .2rem',
558
+ fontWeight: 'bold',
559
+ borderRadius: '.25rem'
560
+ },
561
+ onClick: () => setShow(d => !d)
562
+ }, show ? 'Hide Error' : 'Show Error')), /*#__PURE__*/React__namespace.createElement("div", {
563
+ style: {
564
+ height: '.25rem'
565
+ }
566
+ }), show ? /*#__PURE__*/React__namespace.createElement("div", null, /*#__PURE__*/React__namespace.createElement("pre", {
567
+ style: {
568
+ fontSize: '.7em',
569
+ border: '1px solid red',
570
+ borderRadius: '.25rem',
571
+ padding: '.3rem',
572
+ color: 'red',
573
+ overflow: 'auto'
574
+ }
575
+ }, error.message ? /*#__PURE__*/React__namespace.createElement("code", null, error.message) : null)) : null);
576
+ }
577
+ function useBlocker(message, condition = true) {
578
+ const router = useRouter();
579
+ React__namespace.useEffect(() => {
580
+ if (!condition) return;
581
+ let unblock = router.history.block((retry, cancel) => {
582
+ if (window.confirm(message)) {
583
+ unblock();
584
+ retry();
585
+ }
586
+ });
587
+ return unblock;
588
+ });
589
+ }
590
+ function Block({
591
+ message,
592
+ condition,
593
+ children
594
+ }) {
595
+ useBlocker(message, condition);
596
+ return children ?? null;
597
+ }
598
+ function shallow(objA, objB) {
599
+ if (Object.is(objA, objB)) {
600
+ return true;
601
+ }
602
+ if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
603
+ return false;
604
+ }
605
+ const keysA = Object.keys(objA);
606
+ if (keysA.length !== Object.keys(objB).length) {
607
+ return false;
608
+ }
609
+ for (let i = 0; i < keysA.length; i++) {
610
+ if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) {
611
+ return false;
612
+ }
613
+ }
614
+ return true;
615
+ }
616
+
617
+ exports.Block = Block;
618
+ exports.ErrorComponent = ErrorComponent;
619
+ exports.Link = Link;
620
+ exports.MatchRoute = MatchRoute;
621
+ exports.Navigate = Navigate;
622
+ exports.Outlet = Outlet;
623
+ exports.RouterProvider = RouterProvider;
624
+ exports.lazyRouteComponent = lazyRouteComponent;
625
+ exports.matchIdsContext = matchIdsContext;
626
+ exports.routerContext = routerContext;
627
+ exports.shallow = shallow;
628
+ exports.useBlocker = useBlocker;
629
+ exports.useDehydrate = useDehydrate;
630
+ exports.useHydrate = useHydrate;
631
+ exports.useInjectHtml = useInjectHtml;
632
+ exports.useLinkProps = useLinkProps;
633
+ exports.useLoader = useLoader;
634
+ exports.useMatch = useMatch;
635
+ exports.useMatchRoute = useMatchRoute;
636
+ exports.useMatches = useMatches;
637
+ exports.useNavigate = useNavigate;
638
+ exports.useParams = useParams;
639
+ exports.useRouteContext = useRouteContext;
640
+ exports.useRouter = useRouter;
641
+ exports.useRouterContext = useRouterContext;
642
+ exports.useRouterState = useRouterState;
643
+ exports.useSearch = useSearch;
644
+ //# sourceMappingURL=react.js.map