@alchemy.run/sigil 0.0.0-alpha.4 → 0.0.0-alpha.6
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 +21 -9
- package/THIRD_PARTY_NOTICES.md +39 -1
- package/dist/Text-BobFKi74.d.ts +452 -0
- package/dist/ansi.d.ts +122 -131
- package/dist/ansi.js +86 -6
- package/dist/capabilities.d.ts +5 -0
- package/dist/capabilities.js +3 -0
- package/dist/cell-_ZVhbfl0.js +44 -0
- package/dist/color-CkbalRqK.js +2 -0
- package/dist/color-policy-BMzMwV7Q.d.ts +22 -0
- package/dist/color-policy-SVj1pYTA.js +560 -0
- package/dist/color-profile-DHhQHY55.js +36 -0
- package/dist/color-profile-u0Nhe9Nv.d.ts +97 -0
- package/dist/color.d.ts +21 -0
- package/dist/color.js +3 -0
- package/dist/cursor-position-D2LAkRG0.d.ts +7 -0
- package/dist/detect-Bh4yGP6w.d.ts +186 -0
- package/dist/detect-BuTXtY6e.js +373 -0
- package/dist/env-YVw64yZS.js +9 -0
- package/dist/escapes-CB_6CWOE.d.ts +72 -0
- package/dist/geometry-BxXOzJgo.d.ts +11 -0
- package/dist/index-DZ88EXJv.d.ts +21 -0
- package/dist/index.d.ts +143 -498
- package/dist/index.js +1026 -2244
- package/dist/osc-CCH7xDoS.js +71 -0
- package/dist/osc-Cn0fw77g.d.ts +23 -0
- package/dist/paint-C19minOS.d.ts +81 -0
- package/dist/query-vaIeGOkH.d.ts +152 -0
- package/dist/router.d.ts +392 -0
- package/dist/router.js +709 -0
- package/dist/sample-Cqw1bjUL.js +445 -0
- package/dist/screen-BOSLQ8fF.d.ts +49 -0
- package/dist/screen-CiPytswf.js +342 -0
- package/dist/screen.d.ts +5 -0
- package/dist/screen.js +5 -0
- package/dist/semantic-text-style-DIMzC7xt.js +91 -0
- package/dist/serialize-BTkAZgw1.js +79 -0
- package/dist/session-aZr9O8h3.js +665 -0
- package/dist/sgr-BhwaWAJB.js +246 -0
- package/dist/store-CgrG9K4y.d.ts +72 -0
- package/dist/string-width-CijQwpIk.js +69 -0
- package/dist/strip-BvU4toXG.js +6 -0
- package/dist/terminal.d.ts +118 -0
- package/dist/terminal.js +2 -0
- package/dist/tokenize-AjqbvtiT.js +1242 -0
- package/dist/tokenize-Dx1y_l5H.d.ts +57 -0
- package/dist/truncate-D31fhU6i.js +562 -0
- package/dist/use-focus-BzqAJi0n.js +1337 -0
- package/package.json +41 -9
- package/src/ansi/chalk.ts +5 -3
- package/src/ansi/escapes.ts +14 -0
- package/src/ansi/graphemes.ts +8 -0
- package/src/ansi/hyperlink.ts +44 -0
- package/src/ansi/index.ts +3 -1
- package/src/ansi/osc.ts +77 -0
- package/src/ansi/tokenize.ts +3 -4
- package/src/capabilities/color-policy.ts +34 -0
- package/src/capabilities/detect.ts +594 -0
- package/src/capabilities/index.ts +37 -0
- package/src/capabilities/query.ts +657 -0
- package/src/capabilities/store.ts +379 -0
- package/src/color/index.ts +3 -0
- package/src/color/paint.ts +169 -0
- package/src/color/palette.ts +48 -0
- package/src/color/sample.ts +323 -0
- package/src/color.ts +1 -0
- package/src/components/AnsiText.tsx +42 -0
- package/src/components/App.tsx +98 -10
- package/src/components/BackgroundContext.ts +2 -3
- package/src/components/Box.tsx +0 -8
- package/src/components/CursorContext.ts +1 -1
- package/src/components/Hyperlink.tsx +56 -0
- package/src/components/TerminalOscContext.ts +25 -0
- package/src/components/Text.tsx +22 -45
- package/src/components/Transform.tsx +1 -1
- package/src/dom.ts +11 -2
- package/src/global.d.ts +3 -0
- package/src/hooks/use-capabilities.ts +73 -0
- package/src/hooks/use-cursor.ts +2 -2
- package/src/hooks/use-terminal-osc.ts +59 -0
- package/src/index.ts +45 -1
- package/src/ink.tsx +213 -153
- package/src/{render-node-to-output.ts → paint-tree.ts} +75 -48
- package/src/reconciler.ts +24 -3
- package/src/render-background.ts +36 -15
- package/src/render-border.ts +94 -61
- package/src/render-frame.ts +83 -0
- package/src/render-to-string.ts +21 -6
- package/src/render.ts +15 -6
- package/src/router/components.tsx +343 -0
- package/src/router/context.ts +41 -0
- package/src/router/history.ts +194 -0
- package/src/router/hooks.tsx +391 -0
- package/src/router/index.ts +34 -0
- package/src/router/matcher.ts +571 -0
- package/src/screen/ansi.ts +184 -0
- package/src/screen/canvas.ts +160 -0
- package/src/screen/cell.ts +138 -0
- package/src/screen/color-profile.ts +47 -0
- package/src/screen/geometry.ts +9 -0
- package/src/screen/index.ts +6 -0
- package/src/screen/screen.ts +305 -0
- package/src/screen/serialize.ts +129 -0
- package/src/screen.ts +1 -0
- package/src/semantic-text-style.ts +118 -0
- package/src/squash-text-nodes.ts +2 -5
- package/src/structured-text.ts +325 -0
- package/src/styles.ts +19 -14
- package/src/terminal/index.ts +2 -0
- package/src/terminal/inline-presenter.ts +120 -0
- package/src/terminal/input.ts +86 -0
- package/src/terminal/render-scheduler.ts +37 -0
- package/src/terminal/screen-presenter.ts +188 -0
- package/src/terminal/session.ts +407 -0
- package/src/terminal.ts +1 -0
- package/src/testing/browser.ts +588 -0
- package/src/testing/emulators.ts +205 -0
- package/src/testing/explorer-app/index.html +12 -0
- package/src/testing/explorer-app/main.ts +381 -0
- package/src/testing/explorer-app/style.css +194 -0
- package/src/testing/explorer-app/tsconfig.json +15 -0
- package/src/testing/explorer-app/vite-env.d.ts +1 -0
- package/src/testing/index.ts +26 -0
- package/src/testing/keys.ts +56 -0
- package/src/testing/live.ts +85 -0
- package/src/testing/matchers.ts +70 -0
- package/src/testing/public.ts +94 -0
- package/src/testing/terminal.ts +349 -0
- package/src/testing/vitest.ts +157 -0
- package/src/transform-adapter.ts +14 -0
- package/src/wrap-text.ts +4 -0
- package/dist/sgr-CMfEpjSk.d.ts +0 -91
- package/dist/truncate-Cr6xVFMa.js +0 -2330
- package/src/ansi/supports-color.ts +0 -207
- package/src/colorize.ts +0 -60
- package/src/log-update.ts +0 -370
- package/src/output.ts +0 -308
- package/src/renderer.ts +0 -73
package/dist/router.js
ADDED
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
import { f as Text, n as useInput, t as useFocus } from "./use-focus-BzqAJi0n.js";
|
|
2
|
+
import { Children, Fragment, createContext, isValidElement, startTransition, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/router/history.ts
|
|
5
|
+
/**
|
|
6
|
+
Splits a path string into its pathname and search parts.
|
|
7
|
+
*/
|
|
8
|
+
const parsePath = (path) => {
|
|
9
|
+
const parsedPath = {};
|
|
10
|
+
if (path) {
|
|
11
|
+
const searchIndex = path.indexOf("?");
|
|
12
|
+
if (searchIndex >= 0) {
|
|
13
|
+
parsedPath.search = path.slice(searchIndex);
|
|
14
|
+
path = path.slice(0, searchIndex);
|
|
15
|
+
}
|
|
16
|
+
if (path) parsedPath.pathname = path;
|
|
17
|
+
}
|
|
18
|
+
return parsedPath;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
Joins a `Path` back into a single string.
|
|
22
|
+
*/
|
|
23
|
+
const createPath = ({ pathname = "/", search = "" }) => pathname + (search && search !== "?" ? search.startsWith("?") ? search : `?${search}` : "");
|
|
24
|
+
const createMemoryHistory = ({ initialEntries = ["/"], initialIndex } = {}) => {
|
|
25
|
+
let keyCounter = 0;
|
|
26
|
+
const createKey = () => `k${keyCounter++}`;
|
|
27
|
+
const createLocation = (to, state = null) => {
|
|
28
|
+
const path = typeof to === "string" ? parsePath(to) : to;
|
|
29
|
+
const location = {
|
|
30
|
+
pathname: path.pathname ?? "/",
|
|
31
|
+
search: path.search ?? "",
|
|
32
|
+
state,
|
|
33
|
+
key: createKey()
|
|
34
|
+
};
|
|
35
|
+
if (!location.pathname.startsWith("/")) throw new Error(`Route pathnames must be absolute, but "${location.pathname}" was used to initialize the navigation stack.`);
|
|
36
|
+
return location;
|
|
37
|
+
};
|
|
38
|
+
const entries = initialEntries.map((entry) => createLocation(entry, typeof entry === "string" ? null : entry.state ?? null));
|
|
39
|
+
let index = Math.min(Math.max(initialIndex ?? entries.length - 1, 0), entries.length - 1);
|
|
40
|
+
let action = "POP";
|
|
41
|
+
let listener = null;
|
|
42
|
+
return {
|
|
43
|
+
get index() {
|
|
44
|
+
return index;
|
|
45
|
+
},
|
|
46
|
+
get action() {
|
|
47
|
+
return action;
|
|
48
|
+
},
|
|
49
|
+
get location() {
|
|
50
|
+
return entries[index];
|
|
51
|
+
},
|
|
52
|
+
get canGoBack() {
|
|
53
|
+
return index > 0;
|
|
54
|
+
},
|
|
55
|
+
get canGoForward() {
|
|
56
|
+
return index < entries.length - 1;
|
|
57
|
+
},
|
|
58
|
+
push(to, state) {
|
|
59
|
+
action = "PUSH";
|
|
60
|
+
const nextLocation = createLocation(to, state);
|
|
61
|
+
index += 1;
|
|
62
|
+
entries.splice(index, entries.length, nextLocation);
|
|
63
|
+
listener?.({
|
|
64
|
+
action,
|
|
65
|
+
location: nextLocation,
|
|
66
|
+
delta: 1
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
replace(to, state) {
|
|
70
|
+
action = "REPLACE";
|
|
71
|
+
const nextLocation = createLocation(to, state);
|
|
72
|
+
entries[index] = nextLocation;
|
|
73
|
+
listener?.({
|
|
74
|
+
action,
|
|
75
|
+
location: nextLocation,
|
|
76
|
+
delta: 0
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
go(delta) {
|
|
80
|
+
action = "POP";
|
|
81
|
+
const nextIndex = Math.min(Math.max(index + delta, 0), entries.length - 1);
|
|
82
|
+
const actualDelta = nextIndex - index;
|
|
83
|
+
index = nextIndex;
|
|
84
|
+
listener?.({
|
|
85
|
+
action,
|
|
86
|
+
location: entries[index],
|
|
87
|
+
delta: actualDelta
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
listen(newListener) {
|
|
91
|
+
if (listener) throw new Error("A memory history only supports one listener at a time.");
|
|
92
|
+
listener = newListener;
|
|
93
|
+
return () => {
|
|
94
|
+
listener = null;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/router/matcher.ts
|
|
101
|
+
const joinPaths = (paths) => paths.join("/").replace(/\/\/+/g, "/");
|
|
102
|
+
const normalizePathname = (pathname) => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
|
|
103
|
+
const normalizeSearch = (search) => !search || search === "?" ? "" : search.startsWith("?") ? search : `?${search}`;
|
|
104
|
+
/**
|
|
105
|
+
Matches a set of (possibly nested) routes against a location and returns the
|
|
106
|
+
chain of matches from the root route down to the leaf, or `null` if nothing
|
|
107
|
+
matches.
|
|
108
|
+
*/
|
|
109
|
+
function matchRoutes(routes, locationArg) {
|
|
110
|
+
const pathname = (typeof locationArg === "string" ? parsePath(locationArg) : locationArg).pathname ?? "/";
|
|
111
|
+
const branches = flattenRoutes(routes);
|
|
112
|
+
rankRouteBranches(branches);
|
|
113
|
+
let matches = null;
|
|
114
|
+
for (let index = 0; matches == null && index < branches.length; index++) matches = matchRouteBranch(branches[index], pathname);
|
|
115
|
+
return matches;
|
|
116
|
+
}
|
|
117
|
+
function flattenRoutes(routes, branches = [], parentsMeta = [], parentPath = "", hasParentOptionalSegments = false) {
|
|
118
|
+
const flattenRoute = (route, index, insideOptional, relativePath = route.path ?? "") => {
|
|
119
|
+
const meta = {
|
|
120
|
+
relativePath,
|
|
121
|
+
childrenIndex: index,
|
|
122
|
+
route
|
|
123
|
+
};
|
|
124
|
+
if (meta.relativePath.startsWith("/")) {
|
|
125
|
+
if (!meta.relativePath.startsWith(parentPath)) {
|
|
126
|
+
if (insideOptional) return;
|
|
127
|
+
throw new Error(`Absolute route path "${meta.relativePath}" nested under path "${parentPath}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`);
|
|
128
|
+
}
|
|
129
|
+
meta.relativePath = meta.relativePath.slice(parentPath.length);
|
|
130
|
+
}
|
|
131
|
+
const path = joinPaths([parentPath, meta.relativePath]);
|
|
132
|
+
const routesMeta = parentsMeta.concat(meta);
|
|
133
|
+
if (route.children && route.children.length > 0) {
|
|
134
|
+
if (route.index) throw new Error(`Index routes must not have child routes. Please remove all child routes from route path "${path}".`);
|
|
135
|
+
flattenRoutes(route.children, branches, routesMeta, path, insideOptional);
|
|
136
|
+
}
|
|
137
|
+
if (route.path == null && !route.index) return;
|
|
138
|
+
branches.push({
|
|
139
|
+
path,
|
|
140
|
+
score: computeScore(path, route.index),
|
|
141
|
+
routesMeta
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
routes.forEach((route, index) => {
|
|
145
|
+
if (route.path === "" || !route.path?.includes("?")) flattenRoute(route, index, hasParentOptionalSegments);
|
|
146
|
+
else for (const exploded of explodeOptionalSegments(route.path)) flattenRoute(route, index, true, exploded);
|
|
147
|
+
});
|
|
148
|
+
return branches;
|
|
149
|
+
}
|
|
150
|
+
function explodeOptionalSegments(path) {
|
|
151
|
+
const segments = path.split("/");
|
|
152
|
+
if (segments.length === 0) return [];
|
|
153
|
+
const [first = "", ...rest] = segments;
|
|
154
|
+
const isOptional = first.endsWith("?");
|
|
155
|
+
const required = first.replace(/\?$/, "");
|
|
156
|
+
if (rest.length === 0) return isOptional ? [required, ""] : [required];
|
|
157
|
+
const restExploded = explodeOptionalSegments(rest.join("/"));
|
|
158
|
+
const result = [];
|
|
159
|
+
result.push(...restExploded.map((subpath) => subpath === "" ? required : [required, subpath].join("/")));
|
|
160
|
+
if (isOptional) result.push(...restExploded);
|
|
161
|
+
return result.map((exploded) => path.startsWith("/") && exploded === "" ? "/" : exploded);
|
|
162
|
+
}
|
|
163
|
+
const paramRe = /^:[\w-]+$/;
|
|
164
|
+
const dynamicSegmentValue = 3;
|
|
165
|
+
const indexRouteValue = 2;
|
|
166
|
+
const emptySegmentValue = 1;
|
|
167
|
+
const staticSegmentValue = 10;
|
|
168
|
+
const splatPenalty = -2;
|
|
169
|
+
const isSplat = (segment) => segment === "*";
|
|
170
|
+
function computeScore(path, index) {
|
|
171
|
+
const segments = path.split("/");
|
|
172
|
+
let initialScore = segments.length;
|
|
173
|
+
if (segments.some(isSplat)) initialScore += splatPenalty;
|
|
174
|
+
if (index) initialScore += indexRouteValue;
|
|
175
|
+
return segments.filter((segment) => !isSplat(segment)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
|
|
176
|
+
}
|
|
177
|
+
function rankRouteBranches(branches) {
|
|
178
|
+
branches.sort((a, b) => a.score !== b.score ? b.score - a.score : compareIndexes(a.routesMeta.map((meta) => meta.childrenIndex), b.routesMeta.map((meta) => meta.childrenIndex)));
|
|
179
|
+
}
|
|
180
|
+
function compareIndexes(a, b) {
|
|
181
|
+
return a.length === b.length && a.slice(0, -1).every((n, index) => n === b[index]) ? a[a.length - 1] - b[b.length - 1] : 0;
|
|
182
|
+
}
|
|
183
|
+
function matchRouteBranch(branch, pathname) {
|
|
184
|
+
const { routesMeta } = branch;
|
|
185
|
+
const matchedParams = {};
|
|
186
|
+
let matchedPathname = "/";
|
|
187
|
+
const matches = [];
|
|
188
|
+
for (let index = 0; index < routesMeta.length; index++) {
|
|
189
|
+
const meta = routesMeta[index];
|
|
190
|
+
const end = index === routesMeta.length - 1;
|
|
191
|
+
const remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
|
|
192
|
+
const match = matchPath({
|
|
193
|
+
path: meta.relativePath,
|
|
194
|
+
end
|
|
195
|
+
}, remainingPathname);
|
|
196
|
+
if (!match) return null;
|
|
197
|
+
Object.assign(matchedParams, match.params);
|
|
198
|
+
matches.push({
|
|
199
|
+
params: matchedParams,
|
|
200
|
+
pathname: joinPaths([matchedPathname, match.pathname]),
|
|
201
|
+
pathnameBase: normalizePathname(joinPaths([matchedPathname, match.pathnameBase])),
|
|
202
|
+
route: meta.route
|
|
203
|
+
});
|
|
204
|
+
if (match.pathnameBase !== "/") matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
|
|
205
|
+
}
|
|
206
|
+
return matches;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
Matches a single path pattern against a pathname. Returns the match with
|
|
210
|
+
extracted params, or `null` if the pattern does not match.
|
|
211
|
+
*/
|
|
212
|
+
function matchPath(pattern, pathname) {
|
|
213
|
+
if (typeof pattern === "string") pattern = {
|
|
214
|
+
path: pattern,
|
|
215
|
+
end: true
|
|
216
|
+
};
|
|
217
|
+
const [matcher, compiledParams] = compilePath(pattern.path, pattern.end);
|
|
218
|
+
const match = pathname.match(matcher);
|
|
219
|
+
if (!match) return null;
|
|
220
|
+
const matchedPathname = match[0];
|
|
221
|
+
let pathnameBase = matchedPathname.replace(/(.)\/+$/, "$1");
|
|
222
|
+
const captureGroups = match.slice(1);
|
|
223
|
+
return {
|
|
224
|
+
params: compiledParams.reduce((memo, { paramName, isOptional }, index) => {
|
|
225
|
+
const value = captureGroups[index];
|
|
226
|
+
if (paramName === "*") {
|
|
227
|
+
const splatValue = value || "";
|
|
228
|
+
pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
|
|
229
|
+
}
|
|
230
|
+
memo[paramName] = isOptional && !value ? void 0 : value || "";
|
|
231
|
+
return memo;
|
|
232
|
+
}, {}),
|
|
233
|
+
pathname: matchedPathname,
|
|
234
|
+
pathnameBase,
|
|
235
|
+
pattern
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function compilePath(path, end = true) {
|
|
239
|
+
if (path !== "*" && path.endsWith("*") && !path.endsWith("/*")) throw new Error(`Route path "${path}" is invalid because the \`*\` character must always follow a \`/\` in the pattern. Please change the route path to "${path.replace(/\*$/, "/*")}".`);
|
|
240
|
+
const params = [];
|
|
241
|
+
let regexpSource = "^" + path.replace(/\/*\*?$/, "").replace(/^\/*/, "/").replace(/[\\.*+^${}|()[\]]/g, "\\$&").replace(/\/:([\w-]+)(\?)?/g, (_, paramName, isOptional) => {
|
|
242
|
+
params.push({
|
|
243
|
+
paramName,
|
|
244
|
+
isOptional: isOptional != null
|
|
245
|
+
});
|
|
246
|
+
return isOptional ? "/?([^\\/]+)?" : "/([^\\/]+)";
|
|
247
|
+
}).replace(/\/([\w-]+)\?(\/|$)/g, "(/$1)?$2");
|
|
248
|
+
if (path.endsWith("*")) {
|
|
249
|
+
params.push({ paramName: "*" });
|
|
250
|
+
regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
|
|
251
|
+
} else if (end) regexpSource += "\\/*$";
|
|
252
|
+
else if (path !== "" && path !== "/") regexpSource += "(?:(?=\\/|$))";
|
|
253
|
+
return [new RegExp(regexpSource), params];
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
Interpolates params into a route path pattern.
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
generatePath("/users/:id", { id: "42" }); // "/users/42"
|
|
260
|
+
```
|
|
261
|
+
*/
|
|
262
|
+
function generatePath(originalPath, params = {}) {
|
|
263
|
+
const path = originalPath;
|
|
264
|
+
if (path.endsWith("*") && path !== "*" && !path.endsWith("/*")) throw new Error(`Route path "${path}" is invalid because the \`*\` character must always follow a \`/\` in the pattern. Please change the route path to "${path.replace(/\*$/, "/*")}".`);
|
|
265
|
+
return (path.startsWith("/") ? "/" : "") + path.split(/\/+/).map((segment, index, array) => {
|
|
266
|
+
if (index === array.length - 1 && segment === "*") return params["*"] ?? "";
|
|
267
|
+
const keyMatch = segment.match(/^:([\w-]+)(\??)$/);
|
|
268
|
+
if (keyMatch) {
|
|
269
|
+
const key = keyMatch[1];
|
|
270
|
+
const optional = keyMatch[2];
|
|
271
|
+
const param = params[key];
|
|
272
|
+
if (optional !== "?" && param == null) throw new Error(`Missing ":${key}" param`);
|
|
273
|
+
return param ?? "";
|
|
274
|
+
}
|
|
275
|
+
return segment.replace(/\?$/g, "");
|
|
276
|
+
}).filter((segment) => !!segment).join("/");
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
Resolves a `To` value against a starting pathname, handling `.` and `..`
|
|
280
|
+
segments.
|
|
281
|
+
*/
|
|
282
|
+
function resolvePath(to, fromPathname = "/") {
|
|
283
|
+
const { pathname: toPathname, search = "" } = typeof to === "string" ? parsePath(to) : to;
|
|
284
|
+
return {
|
|
285
|
+
pathname: toPathname ? toPathname.startsWith("/") ? toPathname : resolvePathname(toPathname, fromPathname) : fromPathname,
|
|
286
|
+
search: normalizeSearch(search)
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function resolvePathname(relativePath, fromPathname) {
|
|
290
|
+
const segments = fromPathname.replace(/\/+$/, "").split("/");
|
|
291
|
+
for (const segment of relativePath.split("/")) if (segment === "..") {
|
|
292
|
+
if (segments.length > 1) segments.pop();
|
|
293
|
+
} else if (segment !== ".") segments.push(segment);
|
|
294
|
+
return segments.length > 1 ? segments.join("/") : "/";
|
|
295
|
+
}
|
|
296
|
+
function getPathContributingMatches(matches) {
|
|
297
|
+
return matches.filter((match, index) => index === 0 || match.route.path && match.route.path.length > 0);
|
|
298
|
+
}
|
|
299
|
+
function getResolveToMatches(matches) {
|
|
300
|
+
const pathMatches = getPathContributingMatches(matches);
|
|
301
|
+
return pathMatches.map((match, index) => index === pathMatches.length - 1 ? match.pathname : match.pathnameBase);
|
|
302
|
+
}
|
|
303
|
+
function resolveTo(toArg, routePathnames, locationPathname) {
|
|
304
|
+
const to = typeof toArg === "string" ? parsePath(toArg) : { ...toArg };
|
|
305
|
+
if (to.pathname?.includes("?")) throw new Error(`Cannot include a '?' character in a manually specified \`to.pathname\` field [${JSON.stringify(to)}]. Please separate it out to the \`to.search\` field.`);
|
|
306
|
+
const isEmptyPath = toArg === "" || to.pathname === "";
|
|
307
|
+
const toPathname = isEmptyPath ? "/" : to.pathname;
|
|
308
|
+
let from;
|
|
309
|
+
if (toPathname == null) from = locationPathname;
|
|
310
|
+
else {
|
|
311
|
+
let routePathnameIndex = routePathnames.length - 1;
|
|
312
|
+
if (toPathname.startsWith("..")) {
|
|
313
|
+
const toSegments = toPathname.split("/");
|
|
314
|
+
while (toSegments[0] === "..") {
|
|
315
|
+
toSegments.shift();
|
|
316
|
+
routePathnameIndex -= 1;
|
|
317
|
+
}
|
|
318
|
+
to.pathname = toSegments.join("/");
|
|
319
|
+
}
|
|
320
|
+
from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
|
|
321
|
+
}
|
|
322
|
+
const path = resolvePath(to, from);
|
|
323
|
+
const hasExplicitTrailingSlash = toPathname && toPathname !== "/" && toPathname.endsWith("/");
|
|
324
|
+
const hasCurrentTrailingSlash = (isEmptyPath || toPathname === ".") && locationPathname.endsWith("/");
|
|
325
|
+
if (!path.pathname.endsWith("/") && (hasExplicitTrailingSlash || hasCurrentTrailingSlash)) path.pathname += "/";
|
|
326
|
+
return path;
|
|
327
|
+
}
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region src/router/context.ts
|
|
330
|
+
const NavigationContext = createContext(null);
|
|
331
|
+
const LocationContext = createContext(null);
|
|
332
|
+
const RouteContext = createContext({
|
|
333
|
+
outlet: null,
|
|
334
|
+
matches: []
|
|
335
|
+
});
|
|
336
|
+
const OutletContext = createContext(null);
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/router/hooks.tsx
|
|
339
|
+
/** @jsxImportSource react */
|
|
340
|
+
const warned = /* @__PURE__ */ new Set();
|
|
341
|
+
const warnOnce = (key, message) => {
|
|
342
|
+
if (!warned.has(key)) {
|
|
343
|
+
warned.add(key);
|
|
344
|
+
console.warn(message);
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
/**
|
|
348
|
+
Returns `true` when rendered inside a `<MemoryRouter>`. Useful for components
|
|
349
|
+
that optionally integrate with routing.
|
|
350
|
+
*/
|
|
351
|
+
const useInRouterContext = () => useContext(LocationContext) != null;
|
|
352
|
+
/**
|
|
353
|
+
Returns the current `Location`.
|
|
354
|
+
*/
|
|
355
|
+
const useLocation = () => {
|
|
356
|
+
const locationContext = useContext(LocationContext);
|
|
357
|
+
if (!locationContext) throw new Error("useLocation() may be used only in the context of a <MemoryRouter> component.");
|
|
358
|
+
return locationContext.location;
|
|
359
|
+
};
|
|
360
|
+
/**
|
|
361
|
+
Returns the type of navigation that produced the current location: `"POP"`,
|
|
362
|
+
`"PUSH"`, or `"REPLACE"`.
|
|
363
|
+
*/
|
|
364
|
+
const useNavigationType = () => {
|
|
365
|
+
const locationContext = useContext(LocationContext);
|
|
366
|
+
if (!locationContext) throw new Error("useNavigationType() may be used only in the context of a <MemoryRouter> component.");
|
|
367
|
+
return locationContext.navigationType;
|
|
368
|
+
};
|
|
369
|
+
const useNavigationContext = (hookName) => {
|
|
370
|
+
const navigationContext = useContext(NavigationContext);
|
|
371
|
+
if (!navigationContext) throw new Error(`${hookName} may be used only in the context of a <MemoryRouter> component.`);
|
|
372
|
+
return navigationContext;
|
|
373
|
+
};
|
|
374
|
+
/**
|
|
375
|
+
Returns a stable function for imperative navigation.
|
|
376
|
+
*/
|
|
377
|
+
const useNavigate = () => {
|
|
378
|
+
const { navigator } = useNavigationContext("useNavigate()");
|
|
379
|
+
const { matches } = useContext(RouteContext);
|
|
380
|
+
const { pathname: locationPathname } = useLocation();
|
|
381
|
+
const routePathnamesJson = JSON.stringify(getResolveToMatches(matches));
|
|
382
|
+
const activeRef = useRef(false);
|
|
383
|
+
useLayoutEffect(() => {
|
|
384
|
+
activeRef.current = true;
|
|
385
|
+
});
|
|
386
|
+
return useCallback((to, options = {}) => {
|
|
387
|
+
if (!activeRef.current) return;
|
|
388
|
+
if (typeof to === "number") {
|
|
389
|
+
navigator.go(to);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const path = resolveTo(to, JSON.parse(routePathnamesJson), locationPathname);
|
|
393
|
+
(options.replace ? navigator.replace : navigator.push)(path, options.state);
|
|
394
|
+
}, [
|
|
395
|
+
navigator,
|
|
396
|
+
routePathnamesJson,
|
|
397
|
+
locationPathname
|
|
398
|
+
]);
|
|
399
|
+
};
|
|
400
|
+
/**
|
|
401
|
+
Returns whether the navigation stack has entries behind/ahead of the current
|
|
402
|
+
one — i.e. whether `navigate(-1)` / `navigate(1)` will move anywhere. Handy
|
|
403
|
+
for "Esc goes back, unless at root" bindings.
|
|
404
|
+
*/
|
|
405
|
+
const useNavigationStack = () => {
|
|
406
|
+
const { navigator } = useNavigationContext("useNavigationStack()");
|
|
407
|
+
useLocation();
|
|
408
|
+
return {
|
|
409
|
+
canGoBack: navigator.canGoBack(),
|
|
410
|
+
canGoForward: navigator.canGoForward()
|
|
411
|
+
};
|
|
412
|
+
};
|
|
413
|
+
/**
|
|
414
|
+
Returns the params from all dynamic segments matched by the current route and
|
|
415
|
+
its ancestors.
|
|
416
|
+
*/
|
|
417
|
+
const useParams = () => {
|
|
418
|
+
const { matches } = useContext(RouteContext);
|
|
419
|
+
const routeMatch = matches[matches.length - 1];
|
|
420
|
+
return routeMatch ? routeMatch.params : {};
|
|
421
|
+
};
|
|
422
|
+
/**
|
|
423
|
+
Matches a path pattern against the current location's pathname. Returns the
|
|
424
|
+
match (with params) or `null`.
|
|
425
|
+
*/
|
|
426
|
+
const useMatch = (pattern) => {
|
|
427
|
+
const { pathname } = useLocation();
|
|
428
|
+
return matchPath(pattern, pathname);
|
|
429
|
+
};
|
|
430
|
+
/**
|
|
431
|
+
Resolves a `To` value against the current route, exactly as `useNavigate`
|
|
432
|
+
would. Useful for building navigation UI.
|
|
433
|
+
*/
|
|
434
|
+
const useResolvedPath = (to) => {
|
|
435
|
+
const { matches } = useContext(RouteContext);
|
|
436
|
+
const { pathname: locationPathname } = useLocation();
|
|
437
|
+
return resolveTo(to, getResolveToMatches(matches), locationPathname);
|
|
438
|
+
};
|
|
439
|
+
/**
|
|
440
|
+
Returns the element for the child route at this level of the route hierarchy,
|
|
441
|
+
or `null` if there is none. Used internally by `<Outlet>`.
|
|
442
|
+
*/
|
|
443
|
+
const useOutlet = (context) => {
|
|
444
|
+
const { outlet } = useContext(RouteContext);
|
|
445
|
+
if (outlet) return /* @__PURE__ */ jsx(OutletContext.Provider, {
|
|
446
|
+
value: context,
|
|
447
|
+
children: outlet
|
|
448
|
+
});
|
|
449
|
+
return outlet;
|
|
450
|
+
};
|
|
451
|
+
/**
|
|
452
|
+
Returns the value passed to the nearest parent `<Outlet context={...}>`.
|
|
453
|
+
*/
|
|
454
|
+
const useOutletContext = () => useContext(OutletContext);
|
|
455
|
+
/**
|
|
456
|
+
Creates a `URLSearchParams` from common initializer shapes, including
|
|
457
|
+
`{ key: ["a", "b"] }` for repeated keys.
|
|
458
|
+
*/
|
|
459
|
+
const createSearchParams = (init = "") => new URLSearchParams(typeof init === "string" || Array.isArray(init) || init instanceof URLSearchParams ? init : Object.keys(init).flatMap((key) => {
|
|
460
|
+
const value = init[key];
|
|
461
|
+
return Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]];
|
|
462
|
+
}));
|
|
463
|
+
/**
|
|
464
|
+
Returns the current location's search params and a setter that navigates to
|
|
465
|
+
the same pathname with the new params.
|
|
466
|
+
*/
|
|
467
|
+
const useSearchParams = (defaultInit) => {
|
|
468
|
+
const defaultSearchParamsRef = useRef(createSearchParams(defaultInit));
|
|
469
|
+
const hasSetSearchParamsRef = useRef(false);
|
|
470
|
+
const location = useLocation();
|
|
471
|
+
const searchParams = useMemo(() => {
|
|
472
|
+
const params = createSearchParams(location.search);
|
|
473
|
+
if (!hasSetSearchParamsRef.current) {
|
|
474
|
+
for (const key of defaultSearchParamsRef.current.keys()) if (!params.has(key)) for (const value of defaultSearchParamsRef.current.getAll(key)) params.append(key, value);
|
|
475
|
+
}
|
|
476
|
+
return params;
|
|
477
|
+
}, [location.search]);
|
|
478
|
+
const navigate = useNavigate();
|
|
479
|
+
return [searchParams, useCallback((nextInit, navigateOptions) => {
|
|
480
|
+
const newSearchParams = createSearchParams(typeof nextInit === "function" ? nextInit(new URLSearchParams(searchParams)) : nextInit);
|
|
481
|
+
hasSetSearchParamsRef.current = true;
|
|
482
|
+
navigate(`?${newSearchParams.toString()}`, navigateOptions);
|
|
483
|
+
}, [navigate, searchParams])];
|
|
484
|
+
};
|
|
485
|
+
/**
|
|
486
|
+
Matches a set of route objects against the current location (or an override)
|
|
487
|
+
and returns the rendered element tree. The plain-object alternative to
|
|
488
|
+
`<Routes>`.
|
|
489
|
+
*/
|
|
490
|
+
const useRoutes = (routes, locationArg) => {
|
|
491
|
+
if (!useInRouterContext()) throw new Error("useRoutes() may be used only in the context of a <MemoryRouter> component.");
|
|
492
|
+
const { matches: parentMatches } = useContext(RouteContext);
|
|
493
|
+
const routeMatch = parentMatches[parentMatches.length - 1];
|
|
494
|
+
const parentParams = routeMatch ? routeMatch.params : {};
|
|
495
|
+
const parentPathnameBase = routeMatch ? routeMatch.pathnameBase : "/";
|
|
496
|
+
const parentRoute = routeMatch?.route;
|
|
497
|
+
const locationFromContext = useLocation();
|
|
498
|
+
let location;
|
|
499
|
+
if (locationArg) {
|
|
500
|
+
const parsedLocationArg = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
|
|
501
|
+
if (parentPathnameBase !== "/" && !parsedLocationArg.pathname?.startsWith(parentPathnameBase)) throw new Error(`When overriding the location using \`<Routes location>\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the pathname that was matched by all parent routes. The current pathname base is "${parentPathnameBase}" but pathname "${parsedLocationArg.pathname}" was given in the \`location\` prop.`);
|
|
502
|
+
location = parsedLocationArg;
|
|
503
|
+
} else location = locationFromContext;
|
|
504
|
+
const pathname = location.pathname ?? "/";
|
|
505
|
+
let remainingPathname = pathname;
|
|
506
|
+
if (parentPathnameBase !== "/") {
|
|
507
|
+
const parentSegments = parentPathnameBase.replace(/^\//, "").split("/");
|
|
508
|
+
remainingPathname = `/${pathname.replace(/^\//, "").split("/").slice(parentSegments.length).join("/")}`;
|
|
509
|
+
}
|
|
510
|
+
const matches = matchRoutes(routes, { pathname: remainingPathname });
|
|
511
|
+
const parentPath = parentRoute?.path ?? "";
|
|
512
|
+
if (parentRoute && !parentPath.endsWith("*")) warnOnce(`descendant-routes:${routeMatch.pathname}`, `You rendered descendant <Routes> (or called useRoutes()) at "${routeMatch.pathname}" (under <Route path="${parentPath}">) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. Please change the parent to <Route path="${parentPath === "/" ? "*" : `${parentPath}/*`}">.`);
|
|
513
|
+
if (matches == null && !parentRoute) warnOnce(`no-match:${pathname}${location.search ?? ""}`, `No routes matched location "${pathname}${location.search ?? ""}".`);
|
|
514
|
+
return renderMatches(matches && matches.map((match) => ({
|
|
515
|
+
...match,
|
|
516
|
+
params: {
|
|
517
|
+
...parentParams,
|
|
518
|
+
...match.params
|
|
519
|
+
},
|
|
520
|
+
pathname: joinPaths([parentPathnameBase, match.pathname]),
|
|
521
|
+
pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([parentPathnameBase, match.pathnameBase])
|
|
522
|
+
})), parentMatches);
|
|
523
|
+
};
|
|
524
|
+
function renderMatches(matches, parentMatches) {
|
|
525
|
+
if (matches == null) return null;
|
|
526
|
+
return matches.reduceRight((outlet, match, index) => {
|
|
527
|
+
const matchesUpToHere = parentMatches.concat(matches.slice(0, index + 1));
|
|
528
|
+
return /* @__PURE__ */ jsx(RouteContext.Provider, {
|
|
529
|
+
value: {
|
|
530
|
+
outlet,
|
|
531
|
+
matches: matchesUpToHere
|
|
532
|
+
},
|
|
533
|
+
children: match.route.element ?? outlet
|
|
534
|
+
});
|
|
535
|
+
}, null);
|
|
536
|
+
}
|
|
537
|
+
//#endregion
|
|
538
|
+
//#region src/router/components.tsx
|
|
539
|
+
/** @jsxImportSource react */
|
|
540
|
+
/**
|
|
541
|
+
The routing container for a Sigil app. Stores the navigation stack in memory —
|
|
542
|
+
routes aren't URLs, they're screen states.
|
|
543
|
+
|
|
544
|
+
```tsx
|
|
545
|
+
<MemoryRouter>
|
|
546
|
+
<Routes>
|
|
547
|
+
<Route path="/" element={<Home />} />
|
|
548
|
+
<Route path="/settings" element={<Settings />} />
|
|
549
|
+
</Routes>
|
|
550
|
+
</MemoryRouter>
|
|
551
|
+
```
|
|
552
|
+
*/
|
|
553
|
+
function MemoryRouter({ initialEntries, initialIndex, children }) {
|
|
554
|
+
const historyRef = useRef(null);
|
|
555
|
+
historyRef.current ??= createMemoryHistory({
|
|
556
|
+
initialEntries,
|
|
557
|
+
initialIndex
|
|
558
|
+
});
|
|
559
|
+
const history = historyRef.current;
|
|
560
|
+
const [state, setState] = useState({
|
|
561
|
+
action: history.action,
|
|
562
|
+
location: history.location
|
|
563
|
+
});
|
|
564
|
+
useLayoutEffect(() => history.listen(({ action, location }) => {
|
|
565
|
+
startTransition(() => {
|
|
566
|
+
setState({
|
|
567
|
+
action,
|
|
568
|
+
location
|
|
569
|
+
});
|
|
570
|
+
});
|
|
571
|
+
}), [history]);
|
|
572
|
+
const navigator = useMemo(() => ({
|
|
573
|
+
push: (to, historyState) => history.push(to, historyState),
|
|
574
|
+
replace: (to, historyState) => history.replace(to, historyState),
|
|
575
|
+
go: (delta) => history.go(delta),
|
|
576
|
+
canGoBack: () => history.canGoBack,
|
|
577
|
+
canGoForward: () => history.canGoForward
|
|
578
|
+
}), [history]);
|
|
579
|
+
const navigationContext = useMemo(() => ({ navigator }), [navigator]);
|
|
580
|
+
const locationContext = useMemo(() => ({
|
|
581
|
+
location: state.location,
|
|
582
|
+
navigationType: state.action
|
|
583
|
+
}), [state]);
|
|
584
|
+
return /* @__PURE__ */ jsx(NavigationContext.Provider, {
|
|
585
|
+
value: navigationContext,
|
|
586
|
+
children: /* @__PURE__ */ jsx(LocationContext.Provider, {
|
|
587
|
+
value: locationContext,
|
|
588
|
+
children
|
|
589
|
+
})
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
Declares a route. Only valid as a child of `<Routes>` or another `<Route>`.
|
|
594
|
+
*/
|
|
595
|
+
function Route(_props) {
|
|
596
|
+
throw new Error("A <Route> is only ever to be used as the child of a <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.");
|
|
597
|
+
}
|
|
598
|
+
function createRoutesFromChildren(children) {
|
|
599
|
+
const routes = [];
|
|
600
|
+
Children.forEach(children, (element) => {
|
|
601
|
+
if (!isValidElement(element)) return;
|
|
602
|
+
if (element.type === Fragment) {
|
|
603
|
+
routes.push(...createRoutesFromChildren(element.props.children));
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
if (element.type !== Route) throw new Error(`[${typeof element.type === "string" ? element.type : element.type.name ?? "unknown"}] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>.`);
|
|
607
|
+
const props = element.props;
|
|
608
|
+
const route = {
|
|
609
|
+
path: props.path,
|
|
610
|
+
index: props.index,
|
|
611
|
+
element: props.element
|
|
612
|
+
};
|
|
613
|
+
if (props.children) route.children = createRoutesFromChildren(props.children);
|
|
614
|
+
routes.push(route);
|
|
615
|
+
});
|
|
616
|
+
return routes;
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
Renders the branch of child `<Route>` elements that best matches the current
|
|
620
|
+
location.
|
|
621
|
+
*/
|
|
622
|
+
function Routes({ children, location }) {
|
|
623
|
+
return useRoutes(createRoutesFromChildren(children), location);
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
Renders the matching child route of a parent route, or nothing if no child
|
|
627
|
+
matches.
|
|
628
|
+
*/
|
|
629
|
+
function Outlet(props) {
|
|
630
|
+
return useOutlet(props.context);
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
Navigates as soon as it renders. The component form of `useNavigate`, for
|
|
634
|
+
declarative redirects:
|
|
635
|
+
|
|
636
|
+
```tsx
|
|
637
|
+
<Route path="/" element={<Navigate to="/home" replace />} />
|
|
638
|
+
```
|
|
639
|
+
*/
|
|
640
|
+
function Navigate({ to, replace, state }) {
|
|
641
|
+
const navigate = useNavigate();
|
|
642
|
+
const { pathname, search } = useResolvedPath(to);
|
|
643
|
+
useEffect(() => {
|
|
644
|
+
navigate({
|
|
645
|
+
pathname,
|
|
646
|
+
search
|
|
647
|
+
}, {
|
|
648
|
+
replace,
|
|
649
|
+
state
|
|
650
|
+
});
|
|
651
|
+
}, [
|
|
652
|
+
navigate,
|
|
653
|
+
pathname,
|
|
654
|
+
search,
|
|
655
|
+
replace,
|
|
656
|
+
state
|
|
657
|
+
]);
|
|
658
|
+
return null;
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
A focusable navigation element — the terminal's `<a>` tag. Focus it with
|
|
662
|
+
<kbd>Tab</kbd> and activate it with <kbd>Enter</kbd>. By default the focused
|
|
663
|
+
link renders inverse; pass a function as `children` (or any `Text` props) to
|
|
664
|
+
customize.
|
|
665
|
+
|
|
666
|
+
```tsx
|
|
667
|
+
<Link to="/settings">Settings</Link>
|
|
668
|
+
```
|
|
669
|
+
*/
|
|
670
|
+
function Link({ to, replace = false, state, autoFocus = false, id, children, ...textProps }) {
|
|
671
|
+
const navigate = useNavigate();
|
|
672
|
+
const path = useResolvedPath(to);
|
|
673
|
+
const { pathname: locationPathname } = useLocation();
|
|
674
|
+
const { isFocused } = useFocus({
|
|
675
|
+
autoFocus,
|
|
676
|
+
id
|
|
677
|
+
});
|
|
678
|
+
const toPathname = normalizePathname(path.pathname);
|
|
679
|
+
const isActive = locationPathname === toPathname || locationPathname.startsWith(toPathname) && locationPathname.charAt(toPathname.length) === "/";
|
|
680
|
+
const activate = useCallback(() => {
|
|
681
|
+
navigate({
|
|
682
|
+
pathname: path.pathname,
|
|
683
|
+
search: path.search
|
|
684
|
+
}, {
|
|
685
|
+
replace,
|
|
686
|
+
state
|
|
687
|
+
});
|
|
688
|
+
}, [
|
|
689
|
+
navigate,
|
|
690
|
+
path.pathname,
|
|
691
|
+
path.search,
|
|
692
|
+
replace,
|
|
693
|
+
state
|
|
694
|
+
]);
|
|
695
|
+
useInput((_input, key) => {
|
|
696
|
+
if (key.return) activate();
|
|
697
|
+
}, { isActive: isFocused });
|
|
698
|
+
if (typeof children === "function") return /* @__PURE__ */ jsx(Fragment$1, { children: children({
|
|
699
|
+
isFocused,
|
|
700
|
+
isActive
|
|
701
|
+
}) });
|
|
702
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
703
|
+
inverse: isFocused,
|
|
704
|
+
...textProps,
|
|
705
|
+
children
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
//#endregion
|
|
709
|
+
export { Link, MemoryRouter, Navigate, Outlet, Route, Routes, createPath, createSearchParams, generatePath, matchPath, matchRoutes, parsePath, resolvePath, useInRouterContext, useLocation, useMatch, useNavigate, useNavigationStack, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRoutes, useSearchParams };
|