zudoku 0.12.2 → 0.13.0

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 (54) hide show
  1. package/dist/app/main.js +3 -3
  2. package/dist/app/main.js.map +1 -1
  3. package/dist/config/validators/validate.d.ts +21 -16
  4. package/dist/config/validators/validate.js +3 -1
  5. package/dist/config/validators/validate.js.map +1 -1
  6. package/dist/index.d.ts +1 -0
  7. package/dist/lib/components/Banner.js +7 -1
  8. package/dist/lib/components/Banner.js.map +1 -1
  9. package/dist/lib/components/Header.js +1 -1
  10. package/dist/lib/components/Header.js.map +1 -1
  11. package/dist/lib/components/Layout.js +1 -1
  12. package/dist/lib/components/Layout.js.map +1 -1
  13. package/dist/lib/components/SlotletProvider.d.ts +5 -2
  14. package/dist/lib/components/SlotletProvider.js +6 -2
  15. package/dist/lib/components/SlotletProvider.js.map +1 -1
  16. package/dist/lib/core/DevPortalContext.d.ts +1 -1
  17. package/dist/lib/oas/graphql/index.js +2 -6
  18. package/dist/lib/oas/graphql/index.js.map +1 -1
  19. package/dist/lib/plugins/{custom-page → custom-pages}/index.d.ts +2 -2
  20. package/dist/lib/plugins/{custom-page → custom-pages}/index.js +1 -1
  21. package/dist/lib/plugins/custom-pages/index.js.map +1 -0
  22. package/dist/vite/config.js +2 -0
  23. package/dist/vite/config.js.map +1 -1
  24. package/dist/vite/dev-server.js +10 -2
  25. package/dist/vite/dev-server.js.map +1 -1
  26. package/dist/vite/plugin-component.js +0 -1
  27. package/dist/vite/plugin-component.js.map +1 -1
  28. package/dist/vite/plugin-custom-pages.d.ts +4 -0
  29. package/dist/vite/plugin-custom-pages.js +30 -0
  30. package/dist/vite/plugin-custom-pages.js.map +1 -0
  31. package/dist/vite/plugin.js +2 -0
  32. package/dist/vite/plugin.js.map +1 -1
  33. package/lib/{SlotletProvider-D3UD5Go3.js → SlotletProvider-BWwfPzgI.js} +28 -26
  34. package/lib/{SlotletProvider-D3UD5Go3.js.map → SlotletProvider-BWwfPzgI.js.map} +1 -1
  35. package/lib/assets/{worker-Bcj4NA2p.js → worker-BP8Uzflt.js} +1247 -1249
  36. package/lib/assets/{worker-Bcj4NA2p.js.map → worker-BP8Uzflt.js.map} +1 -1
  37. package/lib/zudoku.components.js +545 -538
  38. package/lib/zudoku.components.js.map +1 -1
  39. package/lib/zudoku.openapi-worker.js +1274 -1276
  40. package/lib/zudoku.openapi-worker.js.map +1 -1
  41. package/lib/zudoku.plugin-api-keys.js +1 -1
  42. package/lib/{zudoku.plugin-custom-page.js → zudoku.plugin-custom-pages.js} +2 -2
  43. package/lib/zudoku.plugin-custom-pages.js.map +1 -0
  44. package/package.json +4 -4
  45. package/src/app/main.tsx +3 -3
  46. package/src/lib/components/Banner.tsx +12 -2
  47. package/src/lib/components/Header.tsx +2 -0
  48. package/src/lib/components/Layout.tsx +1 -0
  49. package/src/lib/components/SlotletProvider.tsx +20 -4
  50. package/src/lib/core/DevPortalContext.ts +1 -1
  51. package/src/lib/oas/graphql/index.ts +3 -11
  52. package/src/lib/plugins/{custom-page → custom-pages}/index.tsx +3 -3
  53. package/dist/lib/plugins/custom-page/index.js.map +0 -1
  54. package/lib/zudoku.plugin-custom-page.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { j as e } from "./jsx-runtime-B6kdoens.js";
2
- import { S as x, R as f } from "./SlotletProvider-D3UD5Go3.js";
2
+ import { S as x, R as f } from "./SlotletProvider-BWwfPzgI.js";
3
3
  import { u as g, a as d, I as j, S as v, b as w, c as b, d as k, e as K, f as m } from "./Input-CtVUl3eT.js";
4
4
  import { a as N, L as u, O as I } from "./index-BG0g4WW0.js";
5
5
  import { u as h, a as E, b as S } from "./ZudokuContext-cr-pTRY1.js";
@@ -8,6 +8,6 @@ const l = (s) => ({
8
8
  }))
9
9
  });
10
10
  export {
11
- l as customPagePlugin
11
+ l as customPagesPlugin
12
12
  };
13
- //# sourceMappingURL=zudoku.plugin-custom-page.js.map
13
+ //# sourceMappingURL=zudoku.plugin-custom-pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zudoku.plugin-custom-pages.js","sources":["../src/lib/plugins/custom-pages/index.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { RouteObject } from \"react-router-dom\";\nimport { ProseClasses } from \"../../components/Markdown.js\";\nimport type { DevPortalPlugin, NavigationPlugin } from \"../../core/plugins.js\";\n\ntype CustomPagesConfig = Array<{\n path: string;\n element: ReactNode;\n}>;\n\nexport const customPagesPlugin = (\n config: CustomPagesConfig,\n): DevPortalPlugin & NavigationPlugin => {\n return {\n getRoutes: (): RouteObject[] =>\n config.map(({ path, element }) => ({\n path,\n // TODO: we should componentize prose pages\n element: <div className={ProseClasses + \" max-w-full\"}>{element}</div>,\n })),\n };\n};\n"],"names":["customPagesPlugin","config","path","element","jsx","ProseClasses"],"mappings":";;AAUa,MAAAA,IAAoB,CAC/BC,OAEO;AAAA,EACL,WAAW,MACTA,EAAO,IAAI,CAAC,EAAE,MAAAC,GAAM,SAAAC,SAAe;AAAA,IACjC,MAAAD;AAAA;AAAA,IAEA,SAAUE,gBAAAA,EAAAA,IAAA,OAAA,EAAI,WAAWC,IAAe,eAAgB,UAAQF,GAAA;AAAA,EAAA,EAChE;AAAA;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.12.2",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "homepage": "https://zudoku.dev",
6
6
  "repository": {
@@ -61,9 +61,9 @@
61
61
  "import": "./lib/zudoku.plugin-redirect.js",
62
62
  "types": "./dist/lib/plugins/redirect/index.d.ts"
63
63
  },
64
- "./plugins/custom-page": {
65
- "import": "./lib/zudoku.plugin-custom-page.js",
66
- "types": "./dist/lib/plugins/custom-page/index.d.ts"
64
+ "./plugins/custom-pages": {
65
+ "import": "./lib/zudoku.plugin-custom-pages.js",
66
+ "types": "./dist/lib/plugins/custom-pages/index.d.ts"
67
67
  },
68
68
  "./plugins/search-inkeep": {
69
69
  "import": "./lib/zudoku.plugin-search-inkeep.js",
package/src/app/main.tsx CHANGED
@@ -2,13 +2,13 @@ import { redirect, type RouteObject } from "react-router-dom";
2
2
  import { configuredApiKeysPlugin } from "virtual:zudoku-api-keys-plugin";
3
3
  import { configuredApiPlugins } from "virtual:zudoku-api-plugins";
4
4
  import { configuredAuthProvider } from "virtual:zudoku-auth";
5
+ import { configuredCustomPagesPlugin } from "virtual:zudoku-custom-pages-plugin";
5
6
  import { configuredDocsPlugins } from "virtual:zudoku-docs-plugins";
6
7
  import { configuredRedirectPlugin } from "virtual:zudoku-redirect-plugin";
7
8
  import { configuredSidebar } from "virtual:zudoku-sidebar";
8
9
  import "virtual:zudoku-theme.css";
9
10
  import { DevPortal, Layout, RouterError } from "zudoku/components";
10
11
  import { isNavigationPlugin } from "zudoku/internal";
11
- import { customPagePlugin } from "zudoku/plugins/custom-page";
12
12
  import { inkeepSearchPlugin } from "zudoku/plugins/search-inkeep";
13
13
  import type { ZudokuConfig } from "../config/config.js";
14
14
  import { traverseSidebar } from "../lib/components/navigation/utils.js";
@@ -42,7 +42,7 @@ export const convertZudokuConfigToOptions = (
42
42
  },
43
43
  },
44
44
  },
45
- slotlets: config.slotlets,
45
+ slotlets: config.UNSAFE_slotlets,
46
46
  metadata: {
47
47
  favicon: "https://cdn.zudoku.dev/logos/favicon.svg",
48
48
  title: "%s - Zudoku",
@@ -60,7 +60,7 @@ export const convertZudokuConfigToOptions = (
60
60
  ...configuredApiPlugins,
61
61
  ...(configuredRedirectPlugin ? [configuredRedirectPlugin] : []),
62
62
  ...(configuredApiKeysPlugin ? [configuredApiKeysPlugin] : []),
63
- ...(config.customPages ? [customPagePlugin(config.customPages)] : []),
63
+ ...(configuredCustomPagesPlugin ? [configuredCustomPagesPlugin] : []),
64
64
  ...(configuredAuthProvider?.getAuthenticationPlugin
65
65
  ? [configuredAuthProvider.getAuthenticationPlugin()]
66
66
  : []),
@@ -9,7 +9,7 @@ const COLOR_MAP = {
9
9
  tip: "bg-green-600",
10
10
  caution: "bg-orange-500",
11
11
  danger: "bg-rose-500",
12
- };
12
+ } as const;
13
13
 
14
14
  export const Banner = () => {
15
15
  const { page } = useZudoku();
@@ -19,12 +19,22 @@ export const Banner = () => {
19
19
  return <style>{`:root { --banner-height: 0px; }`}</style>;
20
20
  }
21
21
 
22
+ const mappedColor =
23
+ page.banner.color && page.banner.color in COLOR_MAP
24
+ ? COLOR_MAP[page.banner.color as keyof typeof COLOR_MAP]
25
+ : !page.banner.color
26
+ ? "bg-primary"
27
+ : undefined;
28
+
29
+ const style = !mappedColor ? { backgroundColor: page.banner.color } : {};
30
+
22
31
  return (
23
32
  <div
24
33
  className={cn(
25
34
  "relative text-primary-foreground text-sm font-medium px-4 py-2 flex gap-2 items-center",
26
- page.banner.color ? COLOR_MAP[page.banner.color] : "bg-primary",
35
+ mappedColor,
27
36
  )}
37
+ style={style}
28
38
  >
29
39
  <div className="w-full">{page.banner.message}</div>
30
40
  {page.banner.dismissible && (
@@ -133,7 +133,9 @@ export const Header = memo(function HeaderInner() {
133
133
  </div>
134
134
  </div>
135
135
  </div>
136
+ <Slotlet name="top-navigation-before" />
136
137
  <TopNavigation />
138
+ <Slotlet name="top-navigation-after" />
137
139
  </div>
138
140
  </header>
139
141
  );
@@ -49,6 +49,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
49
49
  </Helmet>
50
50
  <Slotlet name="layout-before-head" />
51
51
  <Header />
52
+ <Slotlet name="layout-after-head" />
52
53
 
53
54
  <div className="w-full max-w-screen-2xl mx-auto px-10 lg:px-12">
54
55
  <Suspense
@@ -1,6 +1,15 @@
1
- import React, { type ReactElement, ReactNode, useContext } from "react";
1
+ import React, {
2
+ type ComponentType,
3
+ type ReactElement,
4
+ ReactNode,
5
+ useContext,
6
+ } from "react";
2
7
  import { isValidElementType } from "react-is";
3
- export type Slotlets = Record<string, ReactNode | ReactElement>;
8
+ import { useLocation } from "react-router-dom";
9
+ export type Slotlets = Record<
10
+ string,
11
+ ReactNode | ReactElement | ComponentType<SlotletComponentProps>
12
+ >;
4
13
 
5
14
  const SlotletContext = React.createContext<Slotlets | undefined>({});
6
15
 
@@ -18,13 +27,20 @@ export const SlotletProvider = ({
18
27
  );
19
28
  };
20
29
 
30
+ export type SlotletComponentProps = {
31
+ location: Location;
32
+ };
33
+
21
34
  export const Slotlet = ({ name }: { name: string }) => {
22
35
  const context = useContext(SlotletContext);
23
36
  const componentOrElement = context?.[name];
37
+ const location = useLocation();
24
38
 
25
39
  if (isValidElementType(componentOrElement)) {
26
- return React.createElement(componentOrElement);
40
+ return React.createElement(componentOrElement, {
41
+ location,
42
+ });
27
43
  }
28
44
 
29
- return componentOrElement;
45
+ return componentOrElement as ReactNode;
30
46
  };
@@ -51,7 +51,7 @@ type Page = Partial<{
51
51
  };
52
52
  banner?: {
53
53
  message: ReactNode;
54
- color?: "note" | "tip" | "info" | "caution" | "danger";
54
+ color?: "note" | "tip" | "info" | "caution" | "danger" | (string & {});
55
55
  dismissible?: boolean;
56
56
  };
57
57
  }>;
@@ -58,9 +58,10 @@ export const createOperationSlug = (
58
58
  );
59
59
  };
60
60
 
61
- const cache = new LRUCache<string, Promise<OpenAPIDocument>>({
61
+ const cache = new LRUCache<string, OpenAPIDocument>({
62
62
  ttl: 60 * 10 * 1000,
63
63
  ttlAutopurge: true,
64
+ fetchMethod: (_key, _oldValue, { context }) => validate(context as string),
64
65
  });
65
66
 
66
67
  const builder = new SchemaBuilder<{
@@ -429,16 +430,7 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
429
430
 
430
431
  const loadOpenAPISchema = async (input: NonNullable<unknown>) => {
431
432
  const hash = hashit(input);
432
-
433
- if (cache.has(hash)) {
434
- return cache.get(hash)!;
435
- }
436
-
437
- const schema = validate(input);
438
-
439
- cache.set(hash, schema);
440
-
441
- return schema;
433
+ return await cache.forceFetch(hash, { context: input });
442
434
  };
443
435
 
444
436
  const SchemaSource = builder.enumType("SchemaType", {
@@ -3,13 +3,13 @@ import type { RouteObject } from "react-router-dom";
3
3
  import { ProseClasses } from "../../components/Markdown.js";
4
4
  import type { DevPortalPlugin, NavigationPlugin } from "../../core/plugins.js";
5
5
 
6
- type CustomPageConfig = Array<{
6
+ type CustomPagesConfig = Array<{
7
7
  path: string;
8
8
  element: ReactNode;
9
9
  }>;
10
10
 
11
- export const customPagePlugin = (
12
- config: CustomPageConfig,
11
+ export const customPagesPlugin = (
12
+ config: CustomPagesConfig,
13
13
  ): DevPortalPlugin & NavigationPlugin => {
14
14
  return {
15
15
  getRoutes: (): RouteObject[] =>
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/lib/plugins/custom-page/index.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAQ5D,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,MAAwB,EACY,EAAE;IACtC,OAAO;QACL,SAAS,EAAE,GAAkB,EAAE,CAC7B,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;YACjC,IAAI;YACJ,2CAA2C;YAC3C,OAAO,EAAE,cAAK,SAAS,EAAE,YAAY,GAAG,aAAa,YAAG,OAAO,GAAO;SACvE,CAAC,CAAC;KACN,CAAC;AACJ,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"zudoku.plugin-custom-page.js","sources":["../src/lib/plugins/custom-page/index.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport type { RouteObject } from \"react-router-dom\";\nimport { ProseClasses } from \"../../components/Markdown.js\";\nimport type { DevPortalPlugin, NavigationPlugin } from \"../../core/plugins.js\";\n\ntype CustomPageConfig = Array<{\n path: string;\n element: ReactNode;\n}>;\n\nexport const customPagePlugin = (\n config: CustomPageConfig,\n): DevPortalPlugin & NavigationPlugin => {\n return {\n getRoutes: (): RouteObject[] =>\n config.map(({ path, element }) => ({\n path,\n // TODO: we should componentize prose pages\n element: <div className={ProseClasses + \" max-w-full\"}>{element}</div>,\n })),\n };\n};\n"],"names":["customPagePlugin","config","path","element","jsx","ProseClasses"],"mappings":";;AAUa,MAAAA,IAAmB,CAC9BC,OAEO;AAAA,EACL,WAAW,MACTA,EAAO,IAAI,CAAC,EAAE,MAAAC,GAAM,SAAAC,SAAe;AAAA,IACjC,MAAAD;AAAA;AAAA,IAEA,SAAUE,gBAAAA,EAAAA,IAAA,OAAA,EAAI,WAAWC,IAAe,eAAgB,UAAQF,GAAA;AAAA,EAAA,EAChE;AAAA;"}