zudoku 0.28.1 → 0.28.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/main.js +1 -2
- package/dist/app/main.js.map +1 -1
- package/dist/lib/components/index.d.ts +4 -0
- package/dist/lib/components/index.js +2 -0
- package/dist/lib/components/index.js.map +1 -1
- package/dist/lib/components/navigation/Sidebar.js +6 -1
- package/dist/lib/components/navigation/Sidebar.js.map +1 -1
- package/dist/lib/oas/graphql/index.js +11 -10
- package/dist/lib/oas/graphql/index.js.map +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.d.ts +2 -1
- package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
- package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
- package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js +6 -2
- package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/Headers.d.ts +2 -3
- package/dist/lib/plugins/openapi/playground/Headers.js +2 -2
- package/dist/lib/plugins/openapi/playground/Headers.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/Playground.d.ts +3 -0
- package/dist/lib/plugins/openapi/playground/Playground.js +1 -1
- package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +1 -1
- package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js.map +1 -1
- package/dist/lib/util/scrollIntoViewIfNeeded.d.ts +1 -0
- package/dist/lib/util/scrollIntoViewIfNeeded.js +14 -0
- package/dist/lib/util/scrollIntoViewIfNeeded.js.map +1 -0
- package/dist/lib/util/useScrollToAnchor.js +1 -13
- package/dist/lib/util/useScrollToAnchor.js.map +1 -1
- package/dist/vite/plugin-api.js +97 -97
- package/dist/vite/plugin-api.js.map +1 -1
- package/dist/vite/plugin-theme-css.js +7 -4
- package/dist/vite/plugin-theme-css.js.map +1 -1
- package/lib/{AuthenticationPlugin-Du8cLBSr.js → AuthenticationPlugin-DeEA69mE.js} +3 -3
- package/lib/{AuthenticationPlugin-Du8cLBSr.js.map → AuthenticationPlugin-DeEA69mE.js.map} +1 -1
- package/lib/{Markdown-Cyrx_JrO.js → Markdown-LcMEZ0Sn.js} +2 -2
- package/lib/{Markdown-Cyrx_JrO.js.map → Markdown-LcMEZ0Sn.js.map} +1 -1
- package/lib/{MdxPage-BuG8Tuwc.js → MdxPage-DkH3V4hV.js} +5 -5
- package/lib/{MdxPage-BuG8Tuwc.js.map → MdxPage-DkH3V4hV.js.map} +1 -1
- package/lib/{OpenApiRoute-UrC_t0e5.js → OpenApiRoute-ULLXjfro.js} +3 -3
- package/lib/{OpenApiRoute-UrC_t0e5.js.map → OpenApiRoute-ULLXjfro.js.map} +1 -1
- package/lib/{OperationList-CDt1xdc4.js → OperationList-wzZNceUl.js} +339 -336
- package/lib/{OperationList-CDt1xdc4.js.map → OperationList-wzZNceUl.js.map} +1 -1
- package/lib/{Select-CnCZ4WhS.js → Select-DJkXPPD0.js} +3 -3
- package/lib/{Select-CnCZ4WhS.js.map → Select-DJkXPPD0.js.map} +1 -1
- package/lib/{SlotletProvider-mQiPDQIH.js → SlotletProvider-D1t2ePCI.js} +4 -4
- package/lib/{SlotletProvider-mQiPDQIH.js.map → SlotletProvider-D1t2ePCI.js.map} +1 -1
- package/lib/{ZudokuContext-BTUJPpQl.js → ZudokuContext-dUyBGMap.js} +2 -2
- package/lib/{ZudokuContext-BTUJPpQl.js.map → ZudokuContext-dUyBGMap.js.map} +1 -1
- package/lib/{chunk-SYFQ2XB5-BPvC-soB.js → chunk-SYFQ2XB5-QijJrSf0.js} +3 -3
- package/lib/{chunk-SYFQ2XB5-BPvC-soB.js.map → chunk-SYFQ2XB5-QijJrSf0.js.map} +1 -1
- package/lib/{createServer-CjNktZzL.js → createServer-DIztAu7i.js} +11 -8
- package/lib/{createServer-CjNktZzL.js.map → createServer-DIztAu7i.js.map} +1 -1
- package/lib/{hook-FT3SJLe_.js → hook-CiX69UZ6.js} +2 -2
- package/lib/{hook-FT3SJLe_.js.map → hook-CiX69UZ6.js.map} +1 -1
- package/lib/{index-Eb1oiHbM.js → index-DrR58fsJ.js} +234 -223
- package/lib/index-DrR58fsJ.js.map +1 -0
- package/lib/{useExposedProps-BLKFBylA.js → useExposedProps-Bbf99zic.js} +2 -2
- package/lib/{useExposedProps-BLKFBylA.js.map → useExposedProps-Bbf99zic.js.map} +1 -1
- package/lib/{useScrollToAnchor-BZsGmBng.js → useScrollToAnchor-DYGn1MT9.js} +11 -10
- package/lib/useScrollToAnchor-DYGn1MT9.js.map +1 -0
- package/lib/zudoku.auth-clerk.js +1 -1
- package/lib/zudoku.auth-openid.js +3 -3
- package/lib/zudoku.components.js +530 -443
- package/lib/zudoku.components.js.map +1 -1
- package/lib/zudoku.plugin-api-catalog.js +3 -3
- package/lib/zudoku.plugin-api-keys.js +5 -5
- package/lib/zudoku.plugin-custom-pages.js +2 -2
- package/lib/zudoku.plugin-markdown.js +1 -1
- package/lib/zudoku.plugin-openapi.js +3 -3
- package/lib/zudoku.plugin-redirect.js +1 -1
- package/package.json +2 -2
- package/src/app/main.tsx +7 -2
- package/src/lib/components/index.ts +2 -0
- package/src/lib/components/navigation/Sidebar.tsx +7 -1
- package/src/lib/oas/graphql/index.ts +14 -17
- package/src/lib/plugins/openapi/OperationListItem.tsx +1 -1
- package/src/lib/plugins/openapi/PlaygroundDialogWrapper.tsx +7 -2
- package/src/lib/plugins/openapi/playground/Headers.tsx +5 -9
- package/src/lib/plugins/openapi/playground/Playground.tsx +4 -1
- package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +5 -2
- package/src/lib/util/scrollIntoViewIfNeeded.ts +18 -0
- package/src/lib/util/useScrollToAnchor.ts +1 -19
- package/lib/index-Eb1oiHbM.js.map +0 -1
- package/lib/useScrollToAnchor-BZsGmBng.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { j as e } from "./jsx-runtime-Bdg6XQ1m.js";
|
|
2
2
|
import { s as j } from "./index-CjJS0l4l.js";
|
|
3
|
-
import { u as b } from "./ZudokuContext-
|
|
4
|
-
import { b as y } from "./chunk-SYFQ2XB5-
|
|
3
|
+
import { u as b } from "./ZudokuContext-dUyBGMap.js";
|
|
4
|
+
import { b as y } from "./chunk-SYFQ2XB5-QijJrSf0.js";
|
|
5
5
|
import { Head as v, Link as N } from "./zudoku.components.js";
|
|
6
6
|
import { u as w } from "./state-mM7uaXTW.js";
|
|
7
|
-
import { M as C } from "./Markdown-
|
|
7
|
+
import { M as C } from "./Markdown-LcMEZ0Sn.js";
|
|
8
8
|
import { c as h } from "./cn-qaFjX9_3.js";
|
|
9
9
|
const f = (r, n) => j(`${r}-${n}`), k = ({
|
|
10
10
|
items: r,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { j as e } from "./jsx-runtime-Bdg6XQ1m.js";
|
|
2
2
|
import { RotateCwIcon as g, TrashIcon as f, EyeOffIcon as j, EyeIcon as v, CheckIcon as w, CopyIcon as b, FileKey2Icon as K } from "lucide-react";
|
|
3
|
-
import { D as k, S as m, R as N } from "./SlotletProvider-
|
|
3
|
+
import { D as k, S as m, R as N } from "./SlotletProvider-D1t2ePCI.js";
|
|
4
4
|
import { i as c } from "./invariant-Caa8-XvF.js";
|
|
5
|
-
import { u as d, S as I, a as S, b as A, c as C, d as E, e as x } from "./Select-
|
|
5
|
+
import { u as d, S as I, a as S, b as A, c as C, d as E, e as x } from "./Select-DJkXPPD0.js";
|
|
6
6
|
import { a as P } from "./index.esm-CrSoEshU.js";
|
|
7
|
-
import { a as D, L as u, O as R } from "./chunk-SYFQ2XB5-
|
|
8
|
-
import { a as y, e as q, u as O } from "./ZudokuContext-
|
|
7
|
+
import { a as D, L as u, O as R } from "./chunk-SYFQ2XB5-QijJrSf0.js";
|
|
8
|
+
import { a as y, e as q, u as O } from "./ZudokuContext-dUyBGMap.js";
|
|
9
9
|
import { Button as l } from "./ui/Button.js";
|
|
10
10
|
import { Input as z } from "./ui/Input.js";
|
|
11
|
-
import { u as F } from "./hook-
|
|
11
|
+
import { u as F } from "./hook-CiX69UZ6.js";
|
|
12
12
|
import { useState as p } from "react";
|
|
13
13
|
import { c as T } from "./cn-qaFjX9_3.js";
|
|
14
14
|
const L = ({ service: t }) => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { j as o } from "./jsx-runtime-Bdg6XQ1m.js";
|
|
2
2
|
import a from "react";
|
|
3
|
-
import { P as n } from "./Markdown-
|
|
3
|
+
import { P as n } from "./Markdown-LcMEZ0Sn.js";
|
|
4
4
|
import { c } from "./cn-qaFjX9_3.js";
|
|
5
|
-
import { u as p } from "./useExposedProps-
|
|
5
|
+
import { u as p } from "./useExposedProps-Bbf99zic.js";
|
|
6
6
|
const u = ({
|
|
7
7
|
element: t,
|
|
8
8
|
render: s,
|
|
@@ -74,7 +74,7 @@ const C = (n) => ({
|
|
|
74
74
|
const h = {
|
|
75
75
|
path: r,
|
|
76
76
|
lazy: async () => {
|
|
77
|
-
const { MdxPage: l } = await import("./MdxPage-
|
|
77
|
+
const { MdxPage: l } = await import("./MdxPage-DkH3V4hV.js"), { default: p, ...g } = await a();
|
|
78
78
|
return {
|
|
79
79
|
element: /* @__PURE__ */ P.jsx(
|
|
80
80
|
l,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import "./jsx-runtime-Bdg6XQ1m.js";
|
|
2
2
|
import "./index-CjJS0l4l.js";
|
|
3
3
|
import "lucide-react";
|
|
4
|
-
import "./chunk-SYFQ2XB5-
|
|
5
|
-
import "./hook-
|
|
4
|
+
import "./chunk-SYFQ2XB5-QijJrSf0.js";
|
|
5
|
+
import "./hook-CiX69UZ6.js";
|
|
6
6
|
import "./ui/Button.js";
|
|
7
7
|
import "./joinUrl-nLx9pD-Z.js";
|
|
8
|
-
import { o as f } from "./index-
|
|
8
|
+
import { o as f } from "./index-DrR58fsJ.js";
|
|
9
9
|
export {
|
|
10
10
|
f as openApiPlugin
|
|
11
11
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zudoku",
|
|
3
|
-
"version": "0.28.
|
|
3
|
+
"version": "0.28.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"homepage": "https://zudoku.dev",
|
|
6
6
|
"repository": {
|
|
@@ -245,7 +245,7 @@
|
|
|
245
245
|
"react-dom": ">=19"
|
|
246
246
|
},
|
|
247
247
|
"optionalDependencies": {
|
|
248
|
-
"@clerk/clerk-js": "^5.
|
|
248
|
+
"@clerk/clerk-js": "^5.51.0",
|
|
249
249
|
"@sentry/react": "^8.50.0"
|
|
250
250
|
},
|
|
251
251
|
"scripts": {
|
package/src/app/main.tsx
CHANGED
|
@@ -11,9 +11,14 @@ import { configuredRedirectPlugin } from "virtual:zudoku-redirect-plugin";
|
|
|
11
11
|
import { configuredSearchPlugin } from "virtual:zudoku-search-plugin";
|
|
12
12
|
import { configuredSidebar } from "virtual:zudoku-sidebar";
|
|
13
13
|
import "virtual:zudoku-theme.css";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
Layout,
|
|
16
|
+
RouteGuard,
|
|
17
|
+
RouterError,
|
|
18
|
+
StatusPage,
|
|
19
|
+
Zudoku,
|
|
20
|
+
} from "zudoku/components";
|
|
15
21
|
import type { ZudokuConfig } from "../config/config.js";
|
|
16
|
-
import { StatusPage } from "../lib/components/StatusPage.js";
|
|
17
22
|
import type { ZudokuContextOptions } from "../lib/core/ZudokuContext.js";
|
|
18
23
|
import { isNavigationPlugin } from "../lib/core/plugins.js";
|
|
19
24
|
|
|
@@ -20,6 +20,7 @@ import { useZudoku as useZudokuImport } from "./context/ZudokuContext.js";
|
|
|
20
20
|
import { Layout as LayoutImport } from "./Layout.js";
|
|
21
21
|
import { Markdown as MarkdownImport } from "./Markdown.js";
|
|
22
22
|
import { Spinner as SpinnerImport } from "./Spinner.js";
|
|
23
|
+
import { StatusPage as StatusPageImport } from "./StatusPage.js";
|
|
23
24
|
import { Zudoku as ZudokuImport } from "./Zudoku.js";
|
|
24
25
|
|
|
25
26
|
export const useMDXComponents = /*@__PURE__*/ useMDXComponentsImport;
|
|
@@ -38,6 +39,7 @@ export const useCache = /*@__PURE__*/ useCacheImport;
|
|
|
38
39
|
export const CACHE_KEYS = /*@__PURE__*/ CACHE_KEYS_IMPORT;
|
|
39
40
|
export const Zudoku = /*@__PURE__*/ ZudokuImport;
|
|
40
41
|
|
|
42
|
+
export const StatusPage = /*@__PURE__*/ StatusPageImport;
|
|
41
43
|
export const Callout = /*@__PURE__*/ CalloutImport;
|
|
42
44
|
export const Markdown = /*@__PURE__*/ MarkdownImport;
|
|
43
45
|
export const Spinner = /*@__PURE__*/ SpinnerImport;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { useRef } from "react";
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
2
|
|
|
3
3
|
import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
|
|
4
4
|
import { DrawerContent, DrawerTitle } from "../../ui/Drawer.js";
|
|
5
|
+
import { scrollIntoViewIfNeeded } from "../../util/scrollIntoViewIfNeeded.js";
|
|
5
6
|
import { useCurrentNavigation } from "../context/ZudokuContext.js";
|
|
6
7
|
import { Slotlet } from "../SlotletProvider.js";
|
|
7
8
|
import { SidebarItem } from "./SidebarItem.js";
|
|
@@ -15,6 +16,11 @@ export const Sidebar = ({
|
|
|
15
16
|
const navRef = useRef<HTMLDivElement | null>(null);
|
|
16
17
|
const navigation = useCurrentNavigation();
|
|
17
18
|
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const active = navRef.current?.querySelector('[aria-current="page"]');
|
|
21
|
+
scrollIntoViewIfNeeded(active ?? null);
|
|
22
|
+
}, []);
|
|
23
|
+
|
|
18
24
|
return (
|
|
19
25
|
<>
|
|
20
26
|
<SidebarWrapper
|
|
@@ -87,27 +87,24 @@ const JSONObjectScalar = builder.addScalarType("JSONObject", GraphQLJSONObject);
|
|
|
87
87
|
const JSONSchemaScalar = builder.addScalarType("JSONSchema", GraphQLJSONSchema);
|
|
88
88
|
|
|
89
89
|
export const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
.flatMap((operation) =>
|
|
96
|
-
typeof operation === "object" && "tags" in operation
|
|
97
|
-
? (operation.tags ?? [])
|
|
98
|
-
: [],
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
// Remove duplicates and tags that appear in the schema
|
|
102
|
-
const uniqueOperationTags = [...new Set(operationTags)].filter(
|
|
103
|
-
(tag) => !tags.some((rootTag) => rootTag.name === tag),
|
|
90
|
+
const rootTags = schema.tags ?? [];
|
|
91
|
+
const operationTags = new Set(
|
|
92
|
+
Object.values(schema.paths ?? {})
|
|
93
|
+
.flatMap((path) => Object.values(path ?? {}))
|
|
94
|
+
.flatMap((op) => (op as OperationObject).tags ?? []),
|
|
104
95
|
);
|
|
105
|
-
|
|
96
|
+
|
|
97
|
+
return [
|
|
98
|
+
// Keep root tags that are actually used in operations
|
|
99
|
+
...rootTags.filter((tag) => operationTags.has(tag.name)),
|
|
100
|
+
// Add tags found in operations but not defined in root tags
|
|
101
|
+
...[...operationTags]
|
|
102
|
+
.filter((tag) => !rootTags.some((rt) => rt.name === tag))
|
|
103
|
+
.map((tag) => ({ name: tag })),
|
|
104
|
+
];
|
|
106
105
|
};
|
|
107
106
|
|
|
108
107
|
const getAllOperations = (paths?: PathsObject) => {
|
|
109
|
-
const start = performance.now();
|
|
110
|
-
|
|
111
108
|
const operations = Object.entries(paths ?? {}).flatMap(([path, value]) =>
|
|
112
109
|
HttpMethods.flatMap((method) => {
|
|
113
110
|
if (!value?.[method]) return [];
|
|
@@ -11,7 +11,7 @@ import { FragmentType, useFragment } from "./graphql/index.js";
|
|
|
11
11
|
import { SchemaView } from "./schema/SchemaView.js";
|
|
12
12
|
import { methodForColor } from "./util/methodToColor.js";
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
const PARAM_GROUPS = ["path", "query", "header", "cookie"] as const;
|
|
15
15
|
export type ParameterGroup = (typeof PARAM_GROUPS)[number];
|
|
16
16
|
|
|
17
17
|
export const OperationListItem = ({
|
|
@@ -15,10 +15,15 @@ export const PlaygroundDialogWrapper = ({
|
|
|
15
15
|
}) => {
|
|
16
16
|
const headers = operation.parameters
|
|
17
17
|
?.filter((p) => p.in === "header")
|
|
18
|
+
.sort((a, b) => (a.required && !b.required ? -1 : 1))
|
|
18
19
|
.map((p) => ({
|
|
19
20
|
name: p.name,
|
|
20
|
-
defaultValue:
|
|
21
|
-
|
|
21
|
+
defaultValue:
|
|
22
|
+
p.schema?.default ?? p.examples?.find((x) => x.value)?.value ?? "",
|
|
23
|
+
defaultActive: p.required ?? false,
|
|
24
|
+
isRequired: p.required ?? false,
|
|
25
|
+
enum: p.schema?.type == "array" ? p.schema?.items?.enum : p.schema?.enum,
|
|
26
|
+
type: p.schema?.type ?? "string",
|
|
22
27
|
}));
|
|
23
28
|
const queryParams = operation.parameters
|
|
24
29
|
?.filter((p) => p.in === "query")
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
Controller,
|
|
6
6
|
useFieldArray,
|
|
7
7
|
useFormContext,
|
|
8
|
-
UseFormRegister,
|
|
9
8
|
} from "react-hook-form";
|
|
10
9
|
import { Card } from "zudoku/ui/Card.js";
|
|
11
10
|
import { Checkbox } from "zudoku/ui/Checkbox.js";
|
|
@@ -44,13 +43,7 @@ const headerOptions = Object.freeze([
|
|
|
44
43
|
"X-Requested-With",
|
|
45
44
|
]);
|
|
46
45
|
|
|
47
|
-
export const Headers = ({
|
|
48
|
-
control,
|
|
49
|
-
register,
|
|
50
|
-
}: {
|
|
51
|
-
register: UseFormRegister<PlaygroundForm>;
|
|
52
|
-
control: Control<PlaygroundForm>;
|
|
53
|
-
}) => {
|
|
46
|
+
export const Headers = ({ control }: { control: Control<PlaygroundForm> }) => {
|
|
54
47
|
const { fields, append, remove } = useFieldArray<PlaygroundForm>({
|
|
55
48
|
control,
|
|
56
49
|
name: "headers",
|
|
@@ -81,7 +74,10 @@ export const Headers = ({
|
|
|
81
74
|
<Card className="overflow-hidden">
|
|
82
75
|
<ParamsGrid>
|
|
83
76
|
{fields.map((header, i) => (
|
|
84
|
-
<div
|
|
77
|
+
<div
|
|
78
|
+
key={header.name}
|
|
79
|
+
className="group grid col-span-full grid-cols-subgrid"
|
|
80
|
+
>
|
|
85
81
|
<div className="flex items-center gap-2 ">
|
|
86
82
|
<Controller
|
|
87
83
|
control={control}
|
|
@@ -36,6 +36,9 @@ export type Header = {
|
|
|
36
36
|
name: string;
|
|
37
37
|
defaultValue?: string;
|
|
38
38
|
defaultActive?: boolean;
|
|
39
|
+
isRequired?: boolean;
|
|
40
|
+
enum?: string[];
|
|
41
|
+
type?: string;
|
|
39
42
|
};
|
|
40
43
|
|
|
41
44
|
export type QueryParam = {
|
|
@@ -337,7 +340,7 @@ export const Playground = ({
|
|
|
337
340
|
</TabsList>
|
|
338
341
|
</div>
|
|
339
342
|
<TabsContent value="headers">
|
|
340
|
-
<Headers control={control}
|
|
343
|
+
<Headers control={control} />
|
|
341
344
|
</TabsContent>
|
|
342
345
|
<TabsContent value="parameters">
|
|
343
346
|
{pathParams.length > 0 && (
|
|
@@ -39,9 +39,12 @@ const PlaygroundDialog = (props: PlaygroundDialogProps) => {
|
|
|
39
39
|
<Dialog onOpenChange={(open) => setOpen(open)}>
|
|
40
40
|
<DialogTrigger asChild>
|
|
41
41
|
{props.children ?? (
|
|
42
|
-
<button
|
|
42
|
+
<button
|
|
43
|
+
type="button"
|
|
44
|
+
className="flex gap-1 items-center px-2 py-1 rounded-md transition text-xs bg-primary text-primary-foreground shadow-sm hover:bg-primary/80"
|
|
45
|
+
>
|
|
43
46
|
Test
|
|
44
|
-
<HeroPlayIcon
|
|
47
|
+
<HeroPlayIcon size={14} />
|
|
45
48
|
</button>
|
|
46
49
|
)}
|
|
47
50
|
</DialogTrigger>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const scrollIntoViewIfNeeded = (
|
|
2
|
+
element: Element | null,
|
|
3
|
+
options: ScrollIntoViewOptions = { block: "center" },
|
|
4
|
+
) => {
|
|
5
|
+
if (!element) return;
|
|
6
|
+
|
|
7
|
+
const rect = element.getBoundingClientRect();
|
|
8
|
+
const isInView =
|
|
9
|
+
rect.top >= 0 &&
|
|
10
|
+
rect.left >= 0 &&
|
|
11
|
+
rect.bottom <=
|
|
12
|
+
(window.innerHeight || document.documentElement.clientHeight) &&
|
|
13
|
+
rect.right <= (window.innerWidth || document.documentElement.clientWidth);
|
|
14
|
+
|
|
15
|
+
if (isInView) return;
|
|
16
|
+
|
|
17
|
+
element.scrollIntoView(options);
|
|
18
|
+
};
|
|
@@ -2,25 +2,7 @@ import { useCallback, useEffect } from "react";
|
|
|
2
2
|
import { useLocation } from "react-router";
|
|
3
3
|
import { useViewportAnchor } from "../components/context/ViewportAnchorContext.js";
|
|
4
4
|
import { DATA_ANCHOR_ATTR } from "../components/navigation/SidebarItem.js";
|
|
5
|
-
|
|
6
|
-
const scrollIntoViewIfNeeded = (
|
|
7
|
-
element: Element | null,
|
|
8
|
-
options: ScrollIntoViewOptions = { block: "center" },
|
|
9
|
-
) => {
|
|
10
|
-
if (!element) return;
|
|
11
|
-
|
|
12
|
-
const rect = element.getBoundingClientRect();
|
|
13
|
-
const isInView =
|
|
14
|
-
rect.top >= 0 &&
|
|
15
|
-
rect.left >= 0 &&
|
|
16
|
-
rect.bottom <=
|
|
17
|
-
(window.innerHeight || document.documentElement.clientHeight) &&
|
|
18
|
-
rect.right <= (window.innerWidth || document.documentElement.clientWidth);
|
|
19
|
-
|
|
20
|
-
if (isInView) return;
|
|
21
|
-
|
|
22
|
-
element.scrollIntoView(options);
|
|
23
|
-
};
|
|
5
|
+
import { scrollIntoViewIfNeeded } from "./scrollIntoViewIfNeeded.js";
|
|
24
6
|
|
|
25
7
|
export const useScrollToHash = () => {
|
|
26
8
|
const { setActiveAnchor } = useViewportAnchor();
|