zudoku 0.35.1 → 0.35.3

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.
Files changed (70) hide show
  1. package/dist/config/validators/common.d.ts +176 -0
  2. package/dist/config/validators/common.js +1 -0
  3. package/dist/config/validators/common.js.map +1 -1
  4. package/dist/config/validators/validate.d.ts +63 -0
  5. package/dist/lib/components/InlineCode.js +2 -9
  6. package/dist/lib/components/InlineCode.js.map +1 -1
  7. package/dist/lib/components/Layout.js +1 -1
  8. package/dist/lib/components/Layout.js.map +1 -1
  9. package/dist/lib/errors/ErrorAlert.js +6 -1
  10. package/dist/lib/errors/ErrorAlert.js.map +1 -1
  11. package/dist/lib/plugins/openapi/OperationList.js +5 -3
  12. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  13. package/dist/lib/plugins/openapi/OperationListItem.js +3 -11
  14. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  15. package/dist/lib/plugins/openapi/ParameterListItem.js +3 -2
  16. package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
  17. package/dist/lib/plugins/openapi/components/EnumValues.d.ts +5 -0
  18. package/dist/lib/plugins/openapi/components/EnumValues.js +15 -0
  19. package/dist/lib/plugins/openapi/components/EnumValues.js.map +1 -0
  20. package/dist/lib/plugins/openapi/components/SelectOnClick.d.ts +5 -0
  21. package/dist/lib/plugins/openapi/components/SelectOnClick.js +16 -0
  22. package/dist/lib/plugins/openapi/components/SelectOnClick.js.map +1 -0
  23. package/dist/lib/plugins/openapi/interfaces.d.ts +1 -0
  24. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js +3 -2
  25. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js.map +1 -1
  26. package/dist/lib/ui/SyntaxHighlight.js +2 -0
  27. package/dist/lib/ui/SyntaxHighlight.js.map +1 -1
  28. package/dist/vite/plugin-api.js +1 -1
  29. package/dist/vite/plugin-api.js.map +1 -1
  30. package/lib/{Markdown-D1Y3cd9l.js → Markdown-hBN9vkm5.js} +1045 -1026
  31. package/lib/Markdown-hBN9vkm5.js.map +1 -0
  32. package/lib/{MdxPage-CUL_SQzW.js → MdxPage-UCWwxhzC.js} +2 -2
  33. package/lib/{MdxPage-CUL_SQzW.js.map → MdxPage-UCWwxhzC.js.map} +1 -1
  34. package/lib/{OasProvider-vimCZXXF.js → OasProvider-7Z9UwS9y.js} +2 -2
  35. package/lib/{OasProvider-vimCZXXF.js.map → OasProvider-7Z9UwS9y.js.map} +1 -1
  36. package/lib/{OperationList-C6Tumce9.js → OperationList-a7wnHdXv.js} +1859 -1835
  37. package/lib/OperationList-a7wnHdXv.js.map +1 -0
  38. package/lib/SlotletProvider-D-XPr1Wg.js +338 -0
  39. package/lib/SlotletProvider-D-XPr1Wg.js.map +1 -0
  40. package/lib/SyntaxHighlight-BEoSoPEo.js +2890 -0
  41. package/lib/SyntaxHighlight-BEoSoPEo.js.map +1 -0
  42. package/lib/{index-OD2IZ2Nn.js → index-UmhI2mj7.js} +4 -4
  43. package/lib/{index-OD2IZ2Nn.js.map → index-UmhI2mj7.js.map} +1 -1
  44. package/lib/prism-jsstacktrace.min-BfobCF2F.js +2 -0
  45. package/lib/prism-jsstacktrace.min-BfobCF2F.js.map +1 -0
  46. package/lib/ui/SyntaxHighlight.js +8 -2883
  47. package/lib/ui/SyntaxHighlight.js.map +1 -1
  48. package/lib/zudoku.components.js +38 -38
  49. package/lib/zudoku.components.js.map +1 -1
  50. package/lib/zudoku.plugin-api-catalog.js +1 -1
  51. package/lib/zudoku.plugin-api-keys.js +1 -1
  52. package/lib/zudoku.plugin-custom-pages.js +1 -1
  53. package/lib/zudoku.plugin-markdown.js +1 -1
  54. package/lib/zudoku.plugin-openapi.js +1 -1
  55. package/package.json +1 -1
  56. package/src/lib/components/InlineCode.tsx +11 -16
  57. package/src/lib/components/Layout.tsx +1 -1
  58. package/src/lib/errors/ErrorAlert.tsx +24 -17
  59. package/src/lib/plugins/openapi/OperationList.tsx +7 -2
  60. package/src/lib/plugins/openapi/OperationListItem.tsx +4 -16
  61. package/src/lib/plugins/openapi/ParameterListItem.tsx +3 -1
  62. package/src/lib/plugins/openapi/components/EnumValues.tsx +58 -0
  63. package/src/lib/plugins/openapi/components/SelectOnClick.tsx +29 -0
  64. package/src/lib/plugins/openapi/interfaces.ts +1 -0
  65. package/src/lib/plugins/openapi/schema/SchemaPropertyItem.tsx +9 -2
  66. package/src/lib/ui/SyntaxHighlight.tsx +2 -0
  67. package/lib/Markdown-D1Y3cd9l.js.map +0 -1
  68. package/lib/OperationList-C6Tumce9.js.map +0 -1
  69. package/lib/SlotletProvider-iDmNlxD5.js +0 -221
  70. package/lib/SlotletProvider-iDmNlxD5.js.map +0 -1
@@ -5,7 +5,7 @@ import { j as d } from "./joinUrl-10po2Jdj.js";
5
5
  import { u as j, b as y } from "./hook-CfCFKZ-2.js";
6
6
  import { H as v } from "./index.esm-CltAN0Tf.js";
7
7
  import { Link as N } from "./zudoku.components.js";
8
- import { H as S, M as w } from "./Markdown-D1Y3cd9l.js";
8
+ import { H as S, M as w } from "./Markdown-hBN9vkm5.js";
9
9
  const H = ({
10
10
  items: s,
11
11
  filterCatalogItems: l = (n) => n,
@@ -1,6 +1,6 @@
1
1
  import { j as e } from "./jsx-runtime-CYK1ROHF.js";
2
2
  import { RotateCwIcon as j, TrashIcon as v, EyeOffIcon as w, EyeIcon as K, CheckIcon as b, CopyIcon as k, FileKey2Icon as N } from "lucide-react";
3
- import { D as I, S as x, R as S } from "./SlotletProvider-iDmNlxD5.js";
3
+ import { D as I, S as x, R as S } from "./SlotletProvider-D-XPr1Wg.js";
4
4
  import { i as c } from "./invariant-Caa8-XvF.js";
5
5
  import { u as h } from "./useQuery-CQUwWR9i.js";
6
6
  import { u as d, S as A, a as C, b as E, c as P, d as D, e as p } from "./Select-FAYHOYTy.js";
@@ -1,6 +1,6 @@
1
1
  import { j as o } from "./jsx-runtime-CYK1ROHF.js";
2
2
  import a from "react";
3
- import { P as n } from "./Markdown-D1Y3cd9l.js";
3
+ import { P as n } from "./Markdown-hBN9vkm5.js";
4
4
  import { c } from "./cn-qaFjX9_3.js";
5
5
  import { u as p } from "./useExposedProps-BslIn-FE.js";
6
6
  const u = ({
@@ -53,7 +53,7 @@ const P = (e) => ({
53
53
  const u = {
54
54
  path: r,
55
55
  lazy: async () => {
56
- const { MdxPage: p } = await import("./MdxPage-CUL_SQzW.js"), { default: f, ...l } = await i();
56
+ const { MdxPage: p } = await import("./MdxPage-UCWwxhzC.js"), { default: f, ...l } = await i();
57
57
  return {
58
58
  element: /* @__PURE__ */ d.jsx(
59
59
  p,
@@ -5,7 +5,7 @@ import "./chunk-HA7DTUK3-ZGg2W6yV.js";
5
5
  import "./hook-CfCFKZ-2.js";
6
6
  import "./ui/Button.js";
7
7
  import "./joinUrl-10po2Jdj.js";
8
- import { U as n, o as s } from "./index-OD2IZ2Nn.js";
8
+ import { U as n, o as s } from "./index-UmhI2mj7.js";
9
9
  export {
10
10
  n as UNTAGGED_PATH,
11
11
  s as openApiPlugin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.35.1",
3
+ "version": "0.35.3",
4
4
  "type": "module",
5
5
  "homepage": "https://zudoku.dev",
6
6
  "repository": {
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode } from "react";
2
+ import { SelectOnClick } from "../plugins/openapi/components/SelectOnClick.js";
2
3
  import { cn } from "../util/cn.js";
3
4
 
4
5
  export const InlineCode = ({
@@ -10,20 +11,14 @@ export const InlineCode = ({
10
11
  children: ReactNode;
11
12
  selectOnClick?: boolean;
12
13
  }) => (
13
- <code
14
- onClick={(e) => {
15
- if (!selectOnClick) return;
16
- const selection = window.getSelection();
17
- const range = document.createRange();
18
- range.selectNodeContents(e.currentTarget);
19
- selection?.removeAllRanges();
20
- selection?.addRange(range);
21
- }}
22
- className={cn(
23
- "font-mono border p-1 py-0.5 rounded bg-border/50 dark:bg-border/70 [overflow-wrap:anywhere]",
24
- className,
25
- )}
26
- >
27
- {children}
28
- </code>
14
+ <SelectOnClick asChild enabled={selectOnClick}>
15
+ <code
16
+ className={cn(
17
+ "font-mono border p-1 py-0.5 rounded bg-border/50 dark:bg-border/70 [overflow-wrap:anywhere]",
18
+ className,
19
+ )}
20
+ >
21
+ {children}
22
+ </code>
23
+ </SelectOnClick>
29
24
  );
@@ -62,7 +62,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
62
62
  <Header />
63
63
  <Slotlet name="layout-after-head" />
64
64
 
65
- <div className="grid lg:grid-cols-[var(--side-nav-width)_1fr] max-w-screen-2xl w-full lg:mx-auto px-4 lg:px-8 2xl:border-x">
65
+ <div className="grid grid-cols-1 grid-rows-[min-content_1fr] lg:grid-cols-[var(--side-nav-width)_1fr] max-w-screen-2xl w-full lg:mx-auto px-4 lg:px-8 2xl:border-x">
66
66
  {showSpinner ? (
67
67
  <LoadingFallback />
68
68
  ) : (
@@ -1,5 +1,9 @@
1
1
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
2
+ import { SyntaxHighlight } from "zudoku/ui/SyntaxHighlight.js";
2
3
  import { DeveloperHint } from "../components/DeveloperHint.js";
4
+ import { Heading } from "../components/Heading.js";
5
+ import { ProseClasses } from "../components/Markdown.js";
6
+ import { cn } from "../util/cn.js";
3
7
  import { ZudokuError } from "../util/invariant.js";
4
8
 
5
9
  export function ErrorAlert({ error }: { error: unknown }) {
@@ -12,24 +16,27 @@ export function ErrorAlert({ error }: { error: unknown }) {
12
16
  const stack = error instanceof Error ? error.stack : undefined;
13
17
  const cause = error instanceof Error ? error.cause : undefined;
14
18
 
19
+ const stringError = cause instanceof Error ? String(cause.stack) : stack;
20
+
15
21
  return (
16
- <div className="flex h-screen max-h-[calc(100vh-var(--header-height))] min-h-full items-center justify-center bg-primary-background px-4 py-16 lg:px-8">
17
- <div className="mx-auto max-w-[85%] sm:max-w-[50%]">
18
- <h1 className="text-4xl font-bold tracking-tight text-h1-text sm:text-5xl">
19
- {title}
20
- </h1>
21
- <p className="mt-5 text-h1-text">{message}</p>
22
- {hint && <DeveloperHint className="mb-4">{hint}</DeveloperHint>}
23
- {cause instanceof Error ? (
24
- <pre className="mt-5 max-h-[400px] w-full overflow-scroll rounded-md border border-input-border bg-input-background p-3 text-property-name-text text-red-700">
25
- {cause.stack}
26
- </pre>
27
- ) : stack ? (
28
- <pre className="mt-5 max-h-[400px] w-full overflow-scroll rounded-md border border-input-border bg-input-background p-3 text-property-name-text text-red-700">
29
- {stack}
30
- </pre>
31
- ) : null}
32
- </div>
22
+ <div
23
+ className={cn(
24
+ ProseClasses,
25
+ "grid grid-cols-1 !max-w-none pt-[--padding-content-top]",
26
+ )}
27
+ >
28
+ <Heading level={1}>{title}</Heading>
29
+ Error: {message}
30
+ {hint && <DeveloperHint className="mb-4">{hint}</DeveloperHint>}
31
+ {stringError && (
32
+ <div>
33
+ <SyntaxHighlight
34
+ className="max-h-[400px] border mt-2"
35
+ language="jsstacktrace"
36
+ code={stringError}
37
+ />
38
+ </div>
39
+ )}
33
40
  </div>
34
41
  );
35
42
  }
@@ -131,7 +131,7 @@ export const OperationList = ({
131
131
  tag?: string;
132
132
  untagged?: boolean;
133
133
  }) => {
134
- const { input, type, versions, version } = useOasConfig();
134
+ const { input, type, versions, version, options } = useOasConfig();
135
135
  const query = useCreateQuery(AllOperationsQuery, {
136
136
  input,
137
137
  type,
@@ -164,7 +164,11 @@ export const OperationList = ({
164
164
  ? sanitizeMarkdownForMetatag(description)
165
165
  : undefined;
166
166
 
167
- const showVersions = Object.entries(versions).length > 1;
167
+ const hasMultipleVersions = Object.entries(versions).length > 1;
168
+
169
+ const showVersions =
170
+ options?.showVersionSelect === "always" ||
171
+ (hasMultipleVersions && options?.showVersionSelect !== "hide");
168
172
 
169
173
  return (
170
174
  <div
@@ -203,6 +207,7 @@ export const OperationList = ({
203
207
  <Select
204
208
  onValueChange={(version) => navigate(versions[version]!)}
205
209
  defaultValue={version}
210
+ disabled={!hasMultipleVersions}
206
211
  >
207
212
  <SelectTrigger className="w-[180px]">
208
213
  <SelectValue placeholder="Select version" />
@@ -1,5 +1,5 @@
1
1
  import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
2
- import { useRef, useState } from "react";
2
+ import { useState } from "react";
3
3
  import { Badge } from "zudoku/ui/Badge.js";
4
4
  import { Heading } from "../../components/Heading.js";
5
5
  import { Markdown, ProseClasses } from "../../components/Markdown.js";
@@ -10,6 +10,7 @@ import { renderIf } from "../../util/renderIf.js";
10
10
  import { OperationsFragment } from "./OperationList.js";
11
11
  import { ParameterList } from "./ParameterList.js";
12
12
  import { Sidecar } from "./Sidecar.js";
13
+ import { SelectOnClick } from "./components/SelectOnClick.js";
13
14
  import { type FragmentType, useFragment } from "./graphql/index.js";
14
15
  import { SchemaView } from "./schema/SchemaView.js";
15
16
  import { methodForColor } from "./util/methodToColor.js";
@@ -29,7 +30,6 @@ export const OperationListItem = ({
29
30
  operation.parameters ?? [],
30
31
  (param) => param.in,
31
32
  );
32
- const parentRef = useRef<HTMLDivElement>(null);
33
33
 
34
34
  const first = operation.responses.at(0);
35
35
  const [selectedResponse, setSelectedResponse] = useState(first?.statusCode);
@@ -60,19 +60,7 @@ export const OperationListItem = ({
60
60
  <span className={methodForColor(operation.method)}>
61
61
  {operation.method.toUpperCase()}
62
62
  </span>
63
- <div
64
- ref={parentRef}
65
- className="max-w-full truncate flex cursor-pointer"
66
- onClick={() => {
67
- if (parentRef.current) {
68
- const range = document.createRange();
69
- range.selectNodeContents(parentRef.current);
70
- const selection = window.getSelection();
71
- selection?.removeAllRanges();
72
- selection?.addRange(range);
73
- }
74
- }}
75
- >
63
+ <SelectOnClick className="max-w-full truncate flex cursor-pointer">
76
64
  {serverUrl && (
77
65
  <div className="text-neutral-400 dark:text-neutral-500 truncate">
78
66
  {serverUrl}
@@ -81,7 +69,7 @@ export const OperationListItem = ({
81
69
  <div className="text-neutral-900 dark:text-neutral-200">
82
70
  {operation.path}
83
71
  </div>
84
- </div>
72
+ </SelectOnClick>
85
73
  </div>
86
74
 
87
75
  <div className="flex flex-col gap-4">
@@ -4,6 +4,7 @@ import { type SchemaObject } from "../../oas/graphql/index.js";
4
4
  import { ColorizedParam } from "./ColorizedParam.js";
5
5
  import type { OperationListItemResult } from "./OperationList.js";
6
6
  import type { ParameterGroup } from "./OperationListItem.js";
7
+ import { EnumValues } from "./components/EnumValues.js";
7
8
 
8
9
  const getParameterSchema = (
9
10
  parameter: ParameterListItemResult,
@@ -32,7 +33,7 @@ export const ParameterListItem = ({
32
33
  const paramSchema = getParameterSchema(parameter);
33
34
 
34
35
  return (
35
- <li className="p-4 bg-border/20 text-sm flex flex-col gap-1">
36
+ <li className="p-4 bg-border/20 text-sm flex flex-col gap-1.5">
36
37
  <div className="flex items-center gap-2">
37
38
  <code>
38
39
  {group === "path" ? (
@@ -62,6 +63,7 @@ export const ParameterListItem = ({
62
63
  className="text-sm prose-p:my-1 prose-code:whitespace-pre-line"
63
64
  />
64
65
  )}
66
+ {paramSchema.enum && <EnumValues values={paramSchema.enum} />}
65
67
  </li>
66
68
  );
67
69
  };
@@ -0,0 +1,58 @@
1
+ import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
2
+ import { useState } from "react";
3
+ import { Button } from "zudoku/ui/Button.js";
4
+ import { cn } from "../../../util/cn.js";
5
+ import { SelectOnClick } from "./SelectOnClick.js";
6
+
7
+ export const EnumValues = ({
8
+ values,
9
+ className,
10
+ maxVisibleValues = 8,
11
+ }: {
12
+ values: Array<string | number>;
13
+ className?: string;
14
+ maxVisibleValues?: number;
15
+ }) => {
16
+ const [isOpen, setIsOpen] = useState(false);
17
+
18
+ if (!values.length) return null;
19
+
20
+ const shouldCollapse = values.length > maxVisibleValues;
21
+ const visibleValues =
22
+ shouldCollapse && !isOpen ? values.slice(0, maxVisibleValues) : values;
23
+
24
+ return (
25
+ <div className={cn("flex flex-wrap gap-1.5 text-xs", className)}>
26
+ <span className="text-muted-foreground">Enum values: </span>
27
+ {visibleValues.map((value) => (
28
+ <div key={value}>
29
+ <SelectOnClick className="border rounded px-1 font-mono cursor-pointer">
30
+ {value}
31
+ </SelectOnClick>
32
+ </div>
33
+ ))}
34
+ {shouldCollapse && (
35
+ <Button
36
+ variant="ghost"
37
+ size="sm"
38
+ className="h-fit px-0"
39
+ onClick={() => setIsOpen(!isOpen)}
40
+ >
41
+ {isOpen ? (
42
+ <div className="flex items-center gap-1">
43
+ <ChevronUpIcon size={12} />
44
+ <span className="text-muted-foreground">show less</span>
45
+ </div>
46
+ ) : (
47
+ <div className="flex items-center gap-1">
48
+ <ChevronDownIcon size={12} />
49
+ <span className="text-muted-foreground">
50
+ show {values.length - maxVisibleValues} more
51
+ </span>
52
+ </div>
53
+ )}
54
+ </Button>
55
+ )}
56
+ </div>
57
+ );
58
+ };
@@ -0,0 +1,29 @@
1
+ import { Slot, type SlotProps } from "@radix-ui/react-slot";
2
+
3
+ export const SelectOnClick = ({
4
+ asChild,
5
+ onClick,
6
+ enabled = true,
7
+ ...props
8
+ }: {
9
+ asChild?: boolean;
10
+ enabled?: boolean;
11
+ } & SlotProps) => {
12
+ const Component = asChild ? Slot : "span";
13
+
14
+ return (
15
+ <Component
16
+ onClick={(e) => {
17
+ if (enabled) {
18
+ const range = document.createRange();
19
+ range.selectNodeContents(e.currentTarget);
20
+ const selection = window.getSelection();
21
+ selection?.removeAllRanges();
22
+ selection?.addRange(range);
23
+ }
24
+ onClick?.(e);
25
+ }}
26
+ {...props}
27
+ />
28
+ );
29
+ };
@@ -19,6 +19,7 @@ type BaseOasConfig = {
19
19
  examplesLanguage?: string;
20
20
  disablePlayground?: boolean;
21
21
  loadTags?: boolean;
22
+ showVersionSelect?: "always" | "if-available" | "hide";
22
23
  };
23
24
  };
24
25
 
@@ -7,6 +7,7 @@ import type { SchemaObject } from "../../../oas/parser/index.js";
7
7
  import { Button } from "../../../ui/Button.js";
8
8
  import { cn } from "../../../util/cn.js";
9
9
  import { objectEntries } from "../../../util/objectEntries.js";
10
+ import { EnumValues } from "../components/EnumValues.js";
10
11
  import { LogicalGroup } from "./LogicalGroup/LogicalGroup.js";
11
12
  import { SchemaView } from "./SchemaView.js";
12
13
  import {
@@ -82,7 +83,7 @@ export const SchemaPropertyItem = ({
82
83
 
83
84
  return (
84
85
  <li className="p-4 bg-border/20 hover:bg-border/30">
85
- <div className="flex flex-col gap-1 justify-between text-sm">
86
+ <div className="flex flex-col gap-1.5 justify-between text-sm">
86
87
  <div className="flex gap-2 items-center">
87
88
  <code>{name}</code>
88
89
  <Badge variant="muted">
@@ -99,13 +100,19 @@ export const SchemaPropertyItem = ({
99
100
  "items" in schema &&
100
101
  isCircularRef(schema.items) && <RecursiveIndicator />}
101
102
  </div>
102
-
103
103
  {schema.description && (
104
104
  <Markdown
105
105
  className={cn(ProseClasses, "text-sm leading-normal line-clamp-4")}
106
106
  content={schema.description}
107
107
  />
108
108
  )}
109
+ {schema.format && (
110
+ <div>
111
+ <span className="text-sm text-muted-foreground">Format: </span>
112
+ <code>{schema.format}</code>
113
+ </div>
114
+ )}
115
+ {schema.enum && <EnumValues values={schema.enum} />}
109
116
 
110
117
  {(hasLogicalGroupings(schema) || isComplexType(schema)) && (
111
118
  <Collapsible.Root
@@ -28,6 +28,8 @@ void import("prismjs/components/prism-markdown.min.js");
28
28
  void import("prismjs/components/prism-javascript.min.js");
29
29
  // @ts-expect-error This is untyped
30
30
  void import("prismjs/components/prism-typescript.min.js");
31
+ // @ts-expect-error This is untyped
32
+ void import("prismjs/components/prism-jsstacktrace.min.js");
31
33
 
32
34
  import { useTheme } from "next-themes";
33
35
  import { memo, useState } from "react";