col-browser 2.2.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/chunks/index-BmhRLlZh.js +100 -0
- package/es/chunks/index-BmhRLlZh.js.map +1 -0
- package/es/index.js +1 -1
- package/es/routing.js +1 -1
- package/package.json +1 -1
- package/types/index.d.ts +7 -0
- package/umd/col-browser.js +29 -20
- package/umd/col-browser.js.map +1 -1
- package/umd/col-browser.min.js +5 -5
- package/umd/col-browser.min.js.map +1 -1
- package/es/chunks/index-CNK3JADR.js +0 -95
- package/es/chunks/index-CNK3JADR.js.map +0 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { j as N } from "./jsx-runtime-BzflLqGi.js";
|
|
2
|
+
import { useState as O, useEffect as q, useMemo as B, useCallback as v } from "react";
|
|
3
|
+
import l from "query-string";
|
|
4
|
+
const b = (n) => n === "hash", g = (n) => {
|
|
5
|
+
if (b(n)) {
|
|
6
|
+
const o = typeof window < "u" && window.location.hash || "", t = o.startsWith("#") ? o.slice(1) : o, e = t.indexOf("?");
|
|
7
|
+
return {
|
|
8
|
+
path: e >= 0 ? t.slice(0, e) : t,
|
|
9
|
+
search: e >= 0 ? t.slice(e) : ""
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
path: typeof window < "u" && window.location.pathname || "",
|
|
14
|
+
search: typeof window < "u" && window.location.search || ""
|
|
15
|
+
};
|
|
16
|
+
}, j = (n, o, t) => {
|
|
17
|
+
const e = t && Object.keys(t).length > 0 ? `?${l.stringify(t, { arrayFormat: "none" })}` : "";
|
|
18
|
+
if (b(n)) {
|
|
19
|
+
const s = `${o}${e}`;
|
|
20
|
+
window.location.hash = s;
|
|
21
|
+
} else {
|
|
22
|
+
const s = `${o}${e}`;
|
|
23
|
+
window.history.pushState(null, "", s), window.dispatchEvent(new PopStateEvent("popstate"));
|
|
24
|
+
}
|
|
25
|
+
}, D = (n, o) => {
|
|
26
|
+
const t = b(n) ? "hashchange" : "popstate";
|
|
27
|
+
return window.addEventListener(t, o), () => window.removeEventListener(t, o);
|
|
28
|
+
}, d = (n, o, t, e = {}) => {
|
|
29
|
+
if (!o) return null;
|
|
30
|
+
const s = t == null || typeof t == "object" ? "" : String(t), i = typeof t == "object" && t ? { ...t, ...e } : { ...e }, c = Object.keys(i).length > 0 ? `?${l.stringify(i, { arrayFormat: "none" })}` : "", r = `${o}${s}${c}`;
|
|
31
|
+
return b(n) ? `#${r}` : r;
|
|
32
|
+
}, x = (n, o, t, e, s = {}) => {
|
|
33
|
+
if (!t) return;
|
|
34
|
+
if (o === "reload") {
|
|
35
|
+
const r = d(n, t, e, s);
|
|
36
|
+
r != null && typeof window < "u" && window.location.assign(r);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
let i = t, c = Object.keys(s).length > 0 ? { ...s } : null;
|
|
40
|
+
typeof e == "string" || typeof e == "number" ? i = `${t}${e}` : e && typeof e == "object" && (c = { ...c || {}, ...e }), j(n, i, c);
|
|
41
|
+
}, L = (n, o, t, e = {}) => ({
|
|
42
|
+
hrefForTaxon: (s) => d(n, t.taxon, s, e),
|
|
43
|
+
hrefForTree: (s) => d(n, t.tree, s, e),
|
|
44
|
+
hrefForSearch: (s) => d(n, t.search, s, e),
|
|
45
|
+
hrefForSource: (s) => d(n, t.source, s, e),
|
|
46
|
+
onNavigateToTaxon: (s) => x(n, o, t.taxon, s, e),
|
|
47
|
+
onNavigateToTree: (s) => x(n, o, t.tree, s, e),
|
|
48
|
+
onNavigateToSearch: (s) => x(n, o, t.search, s, e),
|
|
49
|
+
onNavigateToSource: (s) => x(n, o, t.source, s, e)
|
|
50
|
+
}), h = (n, o) => {
|
|
51
|
+
if (o) {
|
|
52
|
+
if (!n.startsWith(o)) {
|
|
53
|
+
const t = n.indexOf(o);
|
|
54
|
+
return t < 0 ? void 0 : n.slice(t + o.length).split("/").filter(Boolean).pop();
|
|
55
|
+
}
|
|
56
|
+
return n.slice(o.length).split("/").filter(Boolean).pop();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
function W(n, o) {
|
|
60
|
+
const { kind: t, mode: e = "path", navigation: s = "spa", paths: i = {}, query: c = "" } = o, r = c ? l.parse(c) : {}, m = Object.keys(r), K = (w) => {
|
|
61
|
+
if (m.length === 0) return w;
|
|
62
|
+
const $ = { ...w };
|
|
63
|
+
for (const k of m) delete $[k];
|
|
64
|
+
return $;
|
|
65
|
+
}, S = (w) => {
|
|
66
|
+
const [$, k] = O(0);
|
|
67
|
+
q(() => D(e, () => k((f) => f + 1)), []);
|
|
68
|
+
const { path: u, search: F } = g(e), E = B(() => L(e, s, i, r), []);
|
|
69
|
+
let a = {};
|
|
70
|
+
if (t === "taxon")
|
|
71
|
+
a.taxonKey = h(u, i.taxon);
|
|
72
|
+
else if (t === "source")
|
|
73
|
+
a.sourceDatasetKey = h(u, i.source);
|
|
74
|
+
else if (t === "taxonBreakdown")
|
|
75
|
+
a.taxonId = h(u, i.taxonBreakdown);
|
|
76
|
+
else if (t === "taxonDistribution")
|
|
77
|
+
a.taxonId = h(u, i.taxonDistribution);
|
|
78
|
+
else if (t === "bibtex")
|
|
79
|
+
a.sourceDatasetKey = h(u, i.bibtex);
|
|
80
|
+
else if (t === "tree") {
|
|
81
|
+
const f = K(l.parse(F));
|
|
82
|
+
a.expandedTaxonKey = f.taxonKey || void 0, a.onExpandedTaxonKeyChange = v((p) => {
|
|
83
|
+
const y = g(e), T = l.parse(y.search);
|
|
84
|
+
p ? T.taxonKey = p : delete T.taxonKey, j(e, y.path || i.tree || "/", T);
|
|
85
|
+
}, []);
|
|
86
|
+
} else if (t === "search") {
|
|
87
|
+
const f = K(l.parse(F, { arrayFormat: "none" }));
|
|
88
|
+
a.filters = f, a.onFiltersChange = v((p) => {
|
|
89
|
+
const y = g(e);
|
|
90
|
+
j(e, y.path || i.search || "/", { ...r, ...p });
|
|
91
|
+
}, []);
|
|
92
|
+
}
|
|
93
|
+
return /* @__PURE__ */ N.jsx(n, { ...E, ...a, ...w });
|
|
94
|
+
};
|
|
95
|
+
return S.displayName = `withRouting(${n.displayName || n.name || "Component"})`, S;
|
|
96
|
+
}
|
|
97
|
+
export {
|
|
98
|
+
W as w
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=index-BmhRLlZh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BmhRLlZh.js","sources":["../../src/url/index.js"],"sourcesContent":["import React, { useState, useEffect, useMemo, useCallback } from \"react\";\nimport qs from \"query-string\";\n\n// withRouting(Component, options): adapts a controlled col-browser\n// component to read/write the host page's URL.\n//\n// options.kind — one of \"taxon\" | \"tree\" | \"source\" | \"sourceList\" |\n// \"search\" | \"taxonBreakdown\" | \"taxonDistribution\" |\n// \"bibtex\"\n// options.mode — \"path\" (recommended for the COL portal) or \"hash\"\n// (used by the GitHub Pages demo)\n// options.navigation — \"spa\" (default) or \"reload\". Controls what the four\n// onNavigateToX callbacks do when an in-component\n// action triggers cross-page navigation (e.g. a\n// Highcharts pie segment click with no <a href>\n// fallback). \"spa\" uses history.pushState — right\n// for SPA hosts (react-router, Next.js, TanStack\n// Router). \"reload\" calls window.location.assign,\n// forcing the browser to load the target page —\n// right for static / multi-page hosts (a Jekyll\n// portal, the GitHub Pages demo, any plain HTML).\n// The in-component state callbacks\n// (onExpandedTaxonKeyChange, onFiltersChange) always\n// use pushState so they don't reload the page while\n// the user is interacting with a single component.\n// options.paths — prefix strings for the four navigation targets, e.g.\n// { taxon: \"/taxon/\", tree: \"/tree\", search: \"/search\",\n// source: \"/source/\" }. For hash mode, the prefixes\n// are applied to window.location.hash (without the\n// leading #). Both modes use plain pathnames; query\n// strings are only used for `expandedTaxonKey` (Tree)\n// and `filters` (Search).\n// options.query — optional reserved query string (e.g. \"?v=br\") that\n// is APPENDED to every generated cross-link and\n// PRESERVED across the component's own state writes,\n// but EXCLUDED from the component's parsed state — so a\n// host can pin a release/variant on the URL without the\n// marker leaking into Search filters (which would be\n// sent to the API) or Tree state. Used by the COL\n// portal to scope a page to the Base release (?v=br).\n//\n// All wrappers provide the four hrefForX + onNavigateToX pairs, derived\n// from `paths` and the active routing mode. Kind-specific wrappers also\n// inject the controlled identifier and the appropriate change handler\n// (e.g. `filters` + `onFiltersChange` for Search).\n\nconst isHash = (mode) => mode === \"hash\";\n\nconst readLocationKind = (mode) => {\n if (isHash(mode)) {\n const raw = (typeof window !== \"undefined\" && window.location.hash) || \"\";\n const hash = raw.startsWith(\"#\") ? raw.slice(1) : raw;\n const qIdx = hash.indexOf(\"?\");\n return {\n path: qIdx >= 0 ? hash.slice(0, qIdx) : hash,\n search: qIdx >= 0 ? hash.slice(qIdx) : \"\",\n };\n }\n return {\n path: (typeof window !== \"undefined\" && window.location.pathname) || \"\",\n search: (typeof window !== \"undefined\" && window.location.search) || \"\",\n };\n};\n\nconst writeLocation = (mode, path, search) => {\n const searchStr = search && Object.keys(search).length > 0\n ? `?${qs.stringify(search, { arrayFormat: \"none\" })}`\n : \"\";\n if (isHash(mode)) {\n const next = `${path}${searchStr}`;\n window.location.hash = next;\n } else {\n const url = `${path}${searchStr}`;\n window.history.pushState(null, \"\", url);\n // notify any listeners (the adapter subscribes via popstate / hashchange)\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }\n};\n\nconst subscribe = (mode, cb) => {\n const evt = isHash(mode) ? \"hashchange\" : \"popstate\";\n window.addEventListener(evt, cb);\n return () => window.removeEventListener(evt, cb);\n};\n\n// Build href: the URL the host would land on for each target. `reserved` is a\n// param object (e.g. { v: \"br\" }) merged into the query of every link.\nconst hrefFor = (mode, prefix, args, reserved = {}) => {\n if (!prefix) return null;\n const arg = args == null ? \"\" : typeof args === \"object\" ? \"\" : String(args);\n const queryObj = typeof args === \"object\" && args ? { ...args, ...reserved } : { ...reserved };\n const tail = Object.keys(queryObj).length > 0\n ? `?${qs.stringify(queryObj, { arrayFormat: \"none\" })}`\n : \"\";\n const url = `${prefix}${arg}${tail}`;\n return isHash(mode) ? `#${url}` : url;\n};\n\nconst navigate = (mode, navigation, prefix, args, reserved = {}) => {\n if (!prefix) return;\n if (navigation === \"reload\") {\n // Force a real browser navigation. hrefFor builds the same URL the\n // adapter would render in href= attributes, so the imperative and\n // anchor paths land on identical URLs.\n const url = hrefFor(mode, prefix, args, reserved);\n if (url != null && typeof window !== \"undefined\") {\n window.location.assign(url);\n }\n return;\n }\n // Default \"spa\" behaviour: pushState + popstate so an SPA host re-renders.\n let path = prefix;\n let search = Object.keys(reserved).length > 0 ? { ...reserved } : null;\n if (typeof args === \"string\" || typeof args === \"number\") {\n path = `${prefix}${args}`;\n } else if (args && typeof args === \"object\") {\n search = { ...(search || {}), ...args };\n }\n writeLocation(mode, path, search);\n};\n\nconst buildNavProps = (mode, navigation, paths, reserved = {}) => ({\n hrefForTaxon: (id) => hrefFor(mode, paths.taxon, id, reserved),\n hrefForTree: (a) => hrefFor(mode, paths.tree, a, reserved),\n hrefForSearch: (a) => hrefFor(mode, paths.search, a, reserved),\n hrefForSource: (id) => hrefFor(mode, paths.source, id, reserved),\n\n onNavigateToTaxon: (id) => navigate(mode, navigation, paths.taxon, id, reserved),\n onNavigateToTree: (a) => navigate(mode, navigation, paths.tree, a, reserved),\n onNavigateToSearch: (a) => navigate(mode, navigation, paths.search, a, reserved),\n onNavigateToSource: (id) => navigate(mode, navigation, paths.source, id, reserved),\n});\n\n// Extract the last path segment after a prefix, ignoring trailing slash.\nconst lastSegmentAfter = (path, prefix) => {\n if (!prefix) return undefined;\n if (!path.startsWith(prefix)) {\n // Allow matching when the host wraps in a base path; fall back to\n // \"anything after the prefix substring\".\n const i = path.indexOf(prefix);\n if (i < 0) return undefined;\n return path.slice(i + prefix.length).split(\"/\").filter(Boolean).pop();\n }\n return path.slice(prefix.length).split(\"/\").filter(Boolean).pop();\n};\n\nexport function withRouting(Component, options) {\n const { kind, mode = \"path\", navigation = \"spa\", paths = {}, query = \"\" } = options;\n\n // Reserved query params (e.g. a release marker \"?v=br\"). Round-tripped onto\n // every link + state write, but kept out of the component's parsed state so\n // it never reaches the API (Search filters) or the Tree's expanded key.\n const reserved = query ? qs.parse(query) : {};\n const reservedKeys = Object.keys(reserved);\n const stripReserved = (obj) => {\n if (reservedKeys.length === 0) return obj;\n const out = { ...obj };\n for (const k of reservedKeys) delete out[k];\n return out;\n };\n\n const Wrapped = (props) => {\n const [tick, setTick] = useState(0);\n useEffect(() => subscribe(mode, () => setTick((t) => t + 1)), []);\n\n const { path, search } = readLocationKind(mode);\n\n const navProps = useMemo(() => buildNavProps(mode, navigation, paths, reserved), []);\n\n // Controlled identifier per kind.\n let extra = {};\n if (kind === \"taxon\") {\n extra.taxonKey = lastSegmentAfter(path, paths.taxon);\n } else if (kind === \"source\") {\n extra.sourceDatasetKey = lastSegmentAfter(path, paths.source);\n } else if (kind === \"taxonBreakdown\") {\n extra.taxonId = lastSegmentAfter(path, paths.taxonBreakdown);\n } else if (kind === \"taxonDistribution\") {\n extra.taxonId = lastSegmentAfter(path, paths.taxonDistribution);\n } else if (kind === \"bibtex\") {\n extra.sourceDatasetKey = lastSegmentAfter(path, paths.bibtex);\n } else if (kind === \"tree\") {\n const parsed = stripReserved(qs.parse(search));\n extra.expandedTaxonKey = parsed.taxonKey || undefined;\n extra.onExpandedTaxonKeyChange = useCallback((id) => {\n const cur = readLocationKind(mode);\n const next = qs.parse(cur.search);\n if (id) next.taxonKey = id;\n else delete next.taxonKey;\n writeLocation(mode, cur.path || paths.tree || \"/\", next);\n }, []);\n } else if (kind === \"search\") {\n // Drop reserved params (e.g. v=br) so they aren't sent to the search API.\n const parsed = stripReserved(qs.parse(search, { arrayFormat: \"none\" }));\n extra.filters = parsed;\n extra.onFiltersChange = useCallback((filters) => {\n const cur = readLocationKind(mode);\n // Re-attach reserved params so the release marker survives filter edits.\n writeLocation(mode, cur.path || paths.search || \"/\", { ...reserved, ...filters });\n }, []);\n }\n // sourceList: no controlled identifier; only nav callbacks.\n\n return <Component {...navProps} {...extra} {...props} />;\n };\n Wrapped.displayName = `withRouting(${\n Component.displayName || Component.name || \"Component\"\n })`;\n return Wrapped;\n}\n\nexport default withRouting;\n"],"names":["isHash","mode","readLocationKind","raw","hash","qIdx","writeLocation","path","search","searchStr","qs","next","url","subscribe","cb","evt","hrefFor","prefix","args","reserved","arg","queryObj","tail","navigate","navigation","buildNavProps","paths","id","a","lastSegmentAfter","i","withRouting","Component","options","kind","query","reservedKeys","stripReserved","obj","out","Wrapped","props","tick","setTick","useState","useEffect","t","navProps","useMemo","extra","parsed","useCallback","cur","filters"],"mappings":"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"}
|
package/es/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { SourceDatasetList as n } from "./sourceDatasetList.js";
|
|
|
6
6
|
import { BibTex as T } from "./bibtex.js";
|
|
7
7
|
import { TaxonBreakdown as c } from "./taxonBreakdown.js";
|
|
8
8
|
import { TaxonDistribution as D } from "./taxonDistribution.js";
|
|
9
|
-
import { w as b } from "./chunks/index-
|
|
9
|
+
import { w as b } from "./chunks/index-BmhRLlZh.js";
|
|
10
10
|
export {
|
|
11
11
|
T as BibTex,
|
|
12
12
|
x as Search,
|
package/es/routing.js
CHANGED
package/package.json
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -150,6 +150,13 @@ export interface WithRoutingOptions {
|
|
|
150
150
|
navigation?: "spa" | "reload";
|
|
151
151
|
/** Per-kind URL prefixes used to read/write the controlled identifier. */
|
|
152
152
|
paths?: Partial<Record<WithRoutingOptions["kind"], string>>;
|
|
153
|
+
/**
|
|
154
|
+
* Reserved query string (e.g. "?v=br") appended to every generated link and
|
|
155
|
+
* preserved across the component's own state writes, but excluded from its
|
|
156
|
+
* parsed state — so a release/variant marker never leaks into Search filters
|
|
157
|
+
* or Tree state.
|
|
158
|
+
*/
|
|
159
|
+
query?: string;
|
|
153
160
|
}
|
|
154
161
|
|
|
155
162
|
/**
|
package/umd/col-browser.js
CHANGED
|
@@ -89887,40 +89887,41 @@ Please report this to https://github.com/markedjs/marked.`, e2) {
|
|
|
89887
89887
|
window.addEventListener(evt, cb);
|
|
89888
89888
|
return () => window.removeEventListener(evt, cb);
|
|
89889
89889
|
};
|
|
89890
|
-
const hrefFor = (mode, prefix2, args) => {
|
|
89890
|
+
const hrefFor = (mode, prefix2, args, reserved = {}) => {
|
|
89891
89891
|
if (!prefix2) return null;
|
|
89892
89892
|
const arg = args == null ? "" : typeof args === "object" ? "" : String(args);
|
|
89893
|
-
const
|
|
89893
|
+
const queryObj = typeof args === "object" && args ? { ...args, ...reserved } : { ...reserved };
|
|
89894
|
+
const tail = Object.keys(queryObj).length > 0 ? `?${queryString.stringify(queryObj, { arrayFormat: "none" })}` : "";
|
|
89894
89895
|
const url = `${prefix2}${arg}${tail}`;
|
|
89895
89896
|
return isHash(mode) ? `#${url}` : url;
|
|
89896
89897
|
};
|
|
89897
|
-
const navigate = (mode, navigation2, prefix2, args) => {
|
|
89898
|
+
const navigate = (mode, navigation2, prefix2, args, reserved = {}) => {
|
|
89898
89899
|
if (!prefix2) return;
|
|
89899
89900
|
if (navigation2 === "reload") {
|
|
89900
|
-
const url = hrefFor(mode, prefix2, args);
|
|
89901
|
+
const url = hrefFor(mode, prefix2, args, reserved);
|
|
89901
89902
|
if (url != null && typeof window !== "undefined") {
|
|
89902
89903
|
window.location.assign(url);
|
|
89903
89904
|
}
|
|
89904
89905
|
return;
|
|
89905
89906
|
}
|
|
89906
89907
|
let path = prefix2;
|
|
89907
|
-
let search = null;
|
|
89908
|
+
let search = Object.keys(reserved).length > 0 ? { ...reserved } : null;
|
|
89908
89909
|
if (typeof args === "string" || typeof args === "number") {
|
|
89909
89910
|
path = `${prefix2}${args}`;
|
|
89910
89911
|
} else if (args && typeof args === "object") {
|
|
89911
|
-
search = args;
|
|
89912
|
+
search = { ...search || {}, ...args };
|
|
89912
89913
|
}
|
|
89913
89914
|
writeLocation(mode, path, search);
|
|
89914
89915
|
};
|
|
89915
|
-
const buildNavProps = (mode, navigation2, paths) => ({
|
|
89916
|
-
hrefForTaxon: (id) => hrefFor(mode, paths.taxon, id),
|
|
89917
|
-
hrefForTree: (a) => hrefFor(mode, paths.tree, a),
|
|
89918
|
-
hrefForSearch: (a) => hrefFor(mode, paths.search, a),
|
|
89919
|
-
hrefForSource: (id) => hrefFor(mode, paths.source, id),
|
|
89920
|
-
onNavigateToTaxon: (id) => navigate(mode, navigation2, paths.taxon, id),
|
|
89921
|
-
onNavigateToTree: (a) => navigate(mode, navigation2, paths.tree, a),
|
|
89922
|
-
onNavigateToSearch: (a) => navigate(mode, navigation2, paths.search, a),
|
|
89923
|
-
onNavigateToSource: (id) => navigate(mode, navigation2, paths.source, id)
|
|
89916
|
+
const buildNavProps = (mode, navigation2, paths, reserved = {}) => ({
|
|
89917
|
+
hrefForTaxon: (id) => hrefFor(mode, paths.taxon, id, reserved),
|
|
89918
|
+
hrefForTree: (a) => hrefFor(mode, paths.tree, a, reserved),
|
|
89919
|
+
hrefForSearch: (a) => hrefFor(mode, paths.search, a, reserved),
|
|
89920
|
+
hrefForSource: (id) => hrefFor(mode, paths.source, id, reserved),
|
|
89921
|
+
onNavigateToTaxon: (id) => navigate(mode, navigation2, paths.taxon, id, reserved),
|
|
89922
|
+
onNavigateToTree: (a) => navigate(mode, navigation2, paths.tree, a, reserved),
|
|
89923
|
+
onNavigateToSearch: (a) => navigate(mode, navigation2, paths.search, a, reserved),
|
|
89924
|
+
onNavigateToSource: (id) => navigate(mode, navigation2, paths.source, id, reserved)
|
|
89924
89925
|
});
|
|
89925
89926
|
const lastSegmentAfter = (path, prefix2) => {
|
|
89926
89927
|
if (!prefix2) return void 0;
|
|
@@ -89932,12 +89933,20 @@ Please report this to https://github.com/markedjs/marked.`, e2) {
|
|
|
89932
89933
|
return path.slice(prefix2.length).split("/").filter(Boolean).pop();
|
|
89933
89934
|
};
|
|
89934
89935
|
function withRouting(Component, options) {
|
|
89935
|
-
const { kind, mode = "path", navigation: navigation2 = "spa", paths = {} } = options;
|
|
89936
|
+
const { kind, mode = "path", navigation: navigation2 = "spa", paths = {}, query = "" } = options;
|
|
89937
|
+
const reserved = query ? queryString.parse(query) : {};
|
|
89938
|
+
const reservedKeys = Object.keys(reserved);
|
|
89939
|
+
const stripReserved = (obj) => {
|
|
89940
|
+
if (reservedKeys.length === 0) return obj;
|
|
89941
|
+
const out = { ...obj };
|
|
89942
|
+
for (const k of reservedKeys) delete out[k];
|
|
89943
|
+
return out;
|
|
89944
|
+
};
|
|
89936
89945
|
const Wrapped = (props) => {
|
|
89937
89946
|
const [tick, setTick] = reactExports.useState(0);
|
|
89938
89947
|
reactExports.useEffect(() => subscribe(mode, () => setTick((t2) => t2 + 1)), []);
|
|
89939
89948
|
const { path, search } = readLocationKind(mode);
|
|
89940
|
-
const navProps = reactExports.useMemo(() => buildNavProps(mode, navigation2, paths), []);
|
|
89949
|
+
const navProps = reactExports.useMemo(() => buildNavProps(mode, navigation2, paths, reserved), []);
|
|
89941
89950
|
let extra = {};
|
|
89942
89951
|
if (kind === "taxon") {
|
|
89943
89952
|
extra.taxonKey = lastSegmentAfter(path, paths.taxon);
|
|
@@ -89950,7 +89959,7 @@ Please report this to https://github.com/markedjs/marked.`, e2) {
|
|
|
89950
89959
|
} else if (kind === "bibtex") {
|
|
89951
89960
|
extra.sourceDatasetKey = lastSegmentAfter(path, paths.bibtex);
|
|
89952
89961
|
} else if (kind === "tree") {
|
|
89953
|
-
const parsed = queryString.parse(search);
|
|
89962
|
+
const parsed = stripReserved(queryString.parse(search));
|
|
89954
89963
|
extra.expandedTaxonKey = parsed.taxonKey || void 0;
|
|
89955
89964
|
extra.onExpandedTaxonKeyChange = reactExports.useCallback((id) => {
|
|
89956
89965
|
const cur = readLocationKind(mode);
|
|
@@ -89960,11 +89969,11 @@ Please report this to https://github.com/markedjs/marked.`, e2) {
|
|
|
89960
89969
|
writeLocation(mode, cur.path || paths.tree || "/", next2);
|
|
89961
89970
|
}, []);
|
|
89962
89971
|
} else if (kind === "search") {
|
|
89963
|
-
const parsed = queryString.parse(search, { arrayFormat: "none" });
|
|
89972
|
+
const parsed = stripReserved(queryString.parse(search, { arrayFormat: "none" }));
|
|
89964
89973
|
extra.filters = parsed;
|
|
89965
89974
|
extra.onFiltersChange = reactExports.useCallback((filters) => {
|
|
89966
89975
|
const cur = readLocationKind(mode);
|
|
89967
|
-
writeLocation(mode, cur.path || paths.search || "/", filters);
|
|
89976
|
+
writeLocation(mode, cur.path || paths.search || "/", { ...reserved, ...filters });
|
|
89968
89977
|
}, []);
|
|
89969
89978
|
}
|
|
89970
89979
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(Component, { ...navProps, ...extra, ...props });
|