docusaurus-theme-openapi-docs 4.6.0 → 4.7.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 (36) hide show
  1. package/lib/markdown/schema.js +5 -0
  2. package/lib/theme/ApiExplorer/Body/index.js +263 -128
  3. package/lib/theme/ApiExplorer/Body/resolveSchemaWithSelections.d.ts +13 -0
  4. package/lib/theme/ApiExplorer/Body/resolveSchemaWithSelections.js +133 -0
  5. package/lib/theme/ApiExplorer/SchemaSelection/index.d.ts +2 -0
  6. package/lib/theme/ApiExplorer/SchemaSelection/index.js +36 -0
  7. package/lib/theme/ApiExplorer/SchemaSelection/slice.d.ts +37 -0
  8. package/lib/theme/ApiExplorer/SchemaSelection/slice.js +39 -0
  9. package/lib/theme/ApiExplorer/persistenceMiddleware.d.ts +2 -0
  10. package/lib/theme/ApiItem/hooks.d.ts +1 -0
  11. package/lib/theme/ApiItem/index.js +1 -0
  12. package/lib/theme/ApiItem/store.d.ts +6 -0
  13. package/lib/theme/ApiItem/store.js +6 -2
  14. package/lib/theme/RequestSchema/index.js +58 -52
  15. package/lib/theme/Schema/index.d.ts +6 -0
  16. package/lib/theme/Schema/index.js +135 -9
  17. package/lib/theme/SchemaTabs/index.d.ts +8 -1
  18. package/lib/theme/SchemaTabs/index.js +10 -1
  19. package/lib/theme/StatusCodes/index.d.ts +1 -1
  20. package/lib/theme/styles.scss +10 -0
  21. package/package.json +3 -3
  22. package/src/markdown/schema.ts +6 -0
  23. package/src/theme/ApiExplorer/Body/index.tsx +206 -122
  24. package/src/theme/ApiExplorer/Body/resolveSchemaWithSelections.ts +155 -0
  25. package/{lib/types.js → src/theme/ApiExplorer/SchemaSelection/index.ts} +7 -2
  26. package/src/theme/ApiExplorer/SchemaSelection/slice.ts +46 -0
  27. package/src/theme/ApiItem/index.tsx +1 -0
  28. package/src/theme/ApiItem/store.ts +2 -0
  29. package/src/theme/RequestSchema/index.tsx +49 -39
  30. package/src/theme/Schema/index.tsx +184 -27
  31. package/src/theme/SchemaTabs/index.tsx +15 -4
  32. package/src/theme/StatusCodes/index.tsx +1 -2
  33. package/src/theme/styles.scss +10 -0
  34. package/tsconfig.tsbuildinfo +1 -1
  35. package/lib/types.d.ts +0 -54
  36. /package/src/{types.ts → types.d.ts} +0 -0
@@ -45,7 +45,7 @@ const RequestSchemaComponent: React.FC<Props> = ({ title, body, style }) => {
45
45
 
46
46
  if (mimeTypes.length > 1) {
47
47
  return (
48
- <MimeTabs className="openapi-tabs__mime" schemaType="request">
48
+ <MimeTabs className="openapi-tabs__mime" schemaType="request" lazy>
49
49
  {mimeTypes.map((mimeType) => {
50
50
  const firstBody = body.content![mimeType].schema;
51
51
  if (
@@ -58,43 +58,49 @@ const RequestSchemaComponent: React.FC<Props> = ({ title, body, style }) => {
58
58
  return (
59
59
  // @ts-ignore
60
60
  <TabItem key={mimeType} label={mimeType} value={mimeType}>
61
- <Details
62
- className="openapi-markdown__details mime"
63
- data-collapsed={false}
64
- open={true}
65
- style={style}
66
- summary={
67
- <>
68
- <summary>
69
- <h3 className="openapi-markdown__details-summary-header-body">
70
- {translate({
71
- id: OPENAPI_REQUEST.BODY_TITLE,
72
- message: title,
73
- })}
74
- {body.required === true && (
75
- <span className="openapi-schema__required">
76
- {translate({
77
- id: OPENAPI_SCHEMA_ITEM.REQUIRED,
78
- message: "required",
79
- })}
80
- </span>
81
- )}
82
- </h3>
83
- </summary>
84
- </>
85
- }
86
- >
87
- <div style={{ textAlign: "left", marginLeft: "1rem" }}>
88
- {body.description && (
89
- <div style={{ marginTop: "1rem", marginBottom: "1rem" }}>
90
- <Markdown>{body.description}</Markdown>
91
- </div>
92
- )}
93
- </div>
94
- <ul style={{ marginLeft: "1rem" }}>
95
- <SchemaNode schema={firstBody} schemaType="request" />
96
- </ul>
97
- </Details>
61
+ <div style={{ marginTop: "1rem" }}>
62
+ <Details
63
+ className="openapi-markdown__details mime"
64
+ data-collapsed={false}
65
+ open={true}
66
+ style={style}
67
+ summary={
68
+ <>
69
+ <summary>
70
+ <h3 className="openapi-markdown__details-summary-header-body">
71
+ {translate({
72
+ id: OPENAPI_REQUEST.BODY_TITLE,
73
+ message: title,
74
+ })}
75
+ {body.required === true && (
76
+ <span className="openapi-schema__required">
77
+ {translate({
78
+ id: OPENAPI_SCHEMA_ITEM.REQUIRED,
79
+ message: "required",
80
+ })}
81
+ </span>
82
+ )}
83
+ </h3>
84
+ </summary>
85
+ </>
86
+ }
87
+ >
88
+ <div style={{ textAlign: "left", marginLeft: "1rem" }}>
89
+ {body.description && (
90
+ <div style={{ marginTop: "1rem", marginBottom: "1rem" }}>
91
+ <Markdown>{body.description}</Markdown>
92
+ </div>
93
+ )}
94
+ </div>
95
+ <ul style={{ marginLeft: "1rem" }}>
96
+ <SchemaNode
97
+ schema={firstBody}
98
+ schemaType="request"
99
+ schemaPath="requestBody"
100
+ />
101
+ </ul>
102
+ </Details>
103
+ </div>
98
104
  </TabItem>
99
105
  );
100
106
  })}
@@ -151,7 +157,11 @@ const RequestSchemaComponent: React.FC<Props> = ({ title, body, style }) => {
151
157
  )}
152
158
  </div>
153
159
  <ul style={{ marginLeft: "1rem" }}>
154
- <SchemaNode schema={firstBody} schemaType="request" />
160
+ <SchemaNode
161
+ schema={firstBody}
162
+ schemaType="request"
163
+ schemaPath="requestBody"
164
+ />
155
165
  </ul>
156
166
  </Details>
157
167
  </TabItem>
@@ -5,9 +5,11 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
- import React from "react";
8
+ import React, { useCallback } from "react";
9
9
 
10
10
  import { translate } from "@docusaurus/Translate";
11
+ import { setSchemaSelection } from "@theme/ApiExplorer/SchemaSelection/slice";
12
+ import { useTypedDispatch } from "@theme/ApiItem/hooks";
11
13
  import { ClosingArrayBracket, OpeningArrayBracket } from "@theme/ArrayBrackets";
12
14
  import Details from "@theme/Details";
13
15
  import DiscriminatorTabs from "@theme/DiscriminatorTabs";
@@ -124,9 +126,19 @@ const Summary: React.FC<SummaryProps> = ({
124
126
  interface SchemaProps {
125
127
  schema: SchemaObject;
126
128
  schemaType: "request" | "response";
129
+ /**
130
+ * Optional path identifier for tracking anyOf/oneOf selections.
131
+ * When provided, tab selections will be dispatched to Redux state
132
+ * to enable dynamic body example updates.
133
+ */
134
+ schemaPath?: string;
127
135
  }
128
136
 
129
- const AnyOneOf: React.FC<SchemaProps> = ({ schema, schemaType }) => {
137
+ const AnyOneOf: React.FC<SchemaProps> = ({
138
+ schema,
139
+ schemaType,
140
+ schemaPath,
141
+ }) => {
130
142
  const key = schema.oneOf ? "oneOf" : "anyOf";
131
143
  const type = schema.oneOf
132
144
  ? translate({ id: OPENAPI_SCHEMA_ITEM.ONE_OF, message: "oneOf" })
@@ -138,12 +150,36 @@ const AnyOneOf: React.FC<SchemaProps> = ({ schema, schemaType }) => {
138
150
  []
139
151
  );
140
152
 
153
+ // Try to get Redux dispatch - will be undefined if not inside a Provider
154
+ let dispatch: ReturnType<typeof useTypedDispatch> | undefined;
155
+ try {
156
+ // eslint-disable-next-line react-hooks/rules-of-hooks
157
+ dispatch = useTypedDispatch();
158
+ } catch {
159
+ // Not inside a Redux Provider, which is fine for response schemas
160
+ dispatch = undefined;
161
+ }
162
+
163
+ // Handle tab change - dispatch to Redux if schemaPath is provided
164
+ const handleTabChange = useCallback(
165
+ (index: number) => {
166
+ if (schemaPath && dispatch) {
167
+ dispatch(setSchemaSelection({ path: schemaPath, index }));
168
+ }
169
+ },
170
+ [schemaPath, dispatch]
171
+ );
172
+
141
173
  return (
142
174
  <>
143
175
  <span className="badge badge--info" style={{ marginBottom: "1rem" }}>
144
176
  {type}
145
177
  </span>
146
- <SchemaTabs groupId={`schema-${uniqueId}`} lazy>
178
+ <SchemaTabs
179
+ groupId={`schema-${uniqueId}`}
180
+ lazy
181
+ onChange={handleTabChange}
182
+ >
147
183
  {schema[key]?.map((anyOneSchema: any, index: number) => {
148
184
  // Use getSchemaName to include format info (e.g., "string<date-time>")
149
185
  const computedSchemaName = getSchemaName(anyOneSchema);
@@ -167,6 +203,12 @@ const AnyOneOf: React.FC<SchemaProps> = ({ schema, schemaType }) => {
167
203
  label = `Option ${index + 1}`;
168
204
  }
169
205
  }
206
+
207
+ // Build the nested schemaPath for child anyOf/oneOf
208
+ const childSchemaPath = schemaPath
209
+ ? `${schemaPath}.${index}`
210
+ : undefined;
211
+
170
212
  return (
171
213
  // @ts-ignore
172
214
  <TabItem
@@ -208,19 +250,39 @@ const AnyOneOf: React.FC<SchemaProps> = ({ schema, schemaType }) => {
208
250
  {/* Note: In OpenAPI, properties implies type: object even if not explicitly set */}
209
251
  {(anyOneSchema.type === "object" || !anyOneSchema.type) &&
210
252
  anyOneSchema.properties && (
211
- <Properties schema={anyOneSchema} schemaType={schemaType} />
253
+ <Properties
254
+ schema={anyOneSchema}
255
+ schemaType={schemaType}
256
+ schemaPath={childSchemaPath}
257
+ />
212
258
  )}
213
259
  {anyOneSchema.allOf && (
214
- <SchemaNode schema={anyOneSchema} schemaType={schemaType} />
260
+ <SchemaNode
261
+ schema={anyOneSchema}
262
+ schemaType={schemaType}
263
+ schemaPath={childSchemaPath}
264
+ />
215
265
  )}
216
266
  {anyOneSchema.oneOf && (
217
- <SchemaNode schema={anyOneSchema} schemaType={schemaType} />
267
+ <SchemaNode
268
+ schema={anyOneSchema}
269
+ schemaType={schemaType}
270
+ schemaPath={childSchemaPath}
271
+ />
218
272
  )}
219
273
  {anyOneSchema.anyOf && (
220
- <SchemaNode schema={anyOneSchema} schemaType={schemaType} />
274
+ <SchemaNode
275
+ schema={anyOneSchema}
276
+ schemaType={schemaType}
277
+ schemaPath={childSchemaPath}
278
+ />
221
279
  )}
222
280
  {anyOneSchema.items && (
223
- <Items schema={anyOneSchema} schemaType={schemaType} />
281
+ <Items
282
+ schema={anyOneSchema}
283
+ schemaType={schemaType}
284
+ schemaPath={childSchemaPath}
285
+ />
224
286
  )}
225
287
  </TabItem>
226
288
  );
@@ -230,7 +292,11 @@ const AnyOneOf: React.FC<SchemaProps> = ({ schema, schemaType }) => {
230
292
  );
231
293
  };
232
294
 
233
- const Properties: React.FC<SchemaProps> = ({ schema, schemaType }) => {
295
+ const Properties: React.FC<SchemaProps> = ({
296
+ schema,
297
+ schemaType,
298
+ schemaPath,
299
+ }) => {
234
300
  const discriminator = schema.discriminator;
235
301
  if (discriminator && !discriminator.mapping) {
236
302
  const anyOneOf = schema.oneOf ?? schema.anyOf ?? {};
@@ -274,6 +340,7 @@ const Properties: React.FC<SchemaProps> = ({ schema, schemaType }) => {
274
340
  }
275
341
  discriminator={discriminator}
276
342
  schemaType={schemaType}
343
+ schemaPath={schemaPath ? `${schemaPath}.${key}` : undefined}
277
344
  />
278
345
  )
279
346
  )}
@@ -531,6 +598,7 @@ const SchemaNodeDetails: React.FC<SchemaEdgeProps> = ({
531
598
  schema,
532
599
  required,
533
600
  schemaType,
601
+ schemaPath,
534
602
  }) => {
535
603
  return (
536
604
  <SchemaItem collapsible={true}>
@@ -550,7 +618,11 @@ const SchemaNodeDetails: React.FC<SchemaEdgeProps> = ({
550
618
  {getQualifierMessage(schema) && (
551
619
  <MarkdownWrapper text={getQualifierMessage(schema)} />
552
620
  )}
553
- <SchemaNode schema={schema} schemaType={schemaType} />
621
+ <SchemaNode
622
+ schema={schema}
623
+ schemaType={schemaType}
624
+ schemaPath={schemaPath}
625
+ />
554
626
  </div>
555
627
  </Details>
556
628
  </SchemaItem>
@@ -560,7 +632,8 @@ const SchemaNodeDetails: React.FC<SchemaEdgeProps> = ({
560
632
  const Items: React.FC<{
561
633
  schema: any;
562
634
  schemaType: "request" | "response";
563
- }> = ({ schema, schemaType }) => {
635
+ schemaPath?: string;
636
+ }> = ({ schema, schemaType, schemaPath }) => {
564
637
  // Process schema.items to handle allOf merging
565
638
  let itemsSchema = schema.items;
566
639
  if (schema.items?.allOf) {
@@ -572,15 +645,26 @@ const Items: React.FC<{
572
645
  const hasProperties = itemsSchema?.properties;
573
646
  const hasAdditionalProperties = itemsSchema?.additionalProperties;
574
647
 
648
+ // Build the items schema path
649
+ const itemsSchemaPath = schemaPath ? `${schemaPath}.items` : undefined;
650
+
575
651
  if (hasOneOfAnyOf || hasProperties || hasAdditionalProperties) {
576
652
  return (
577
653
  <>
578
654
  <OpeningArrayBracket />
579
655
  {hasOneOfAnyOf && (
580
- <AnyOneOf schema={itemsSchema} schemaType={schemaType} />
656
+ <AnyOneOf
657
+ schema={itemsSchema}
658
+ schemaType={schemaType}
659
+ schemaPath={itemsSchemaPath}
660
+ />
581
661
  )}
582
662
  {hasProperties && (
583
- <Properties schema={itemsSchema} schemaType={schemaType} />
663
+ <Properties
664
+ schema={itemsSchema}
665
+ schemaType={schemaType}
666
+ schemaPath={itemsSchemaPath}
667
+ />
584
668
  )}
585
669
  {hasAdditionalProperties && (
586
670
  <AdditionalProperties schema={itemsSchema} schemaType={schemaType} />
@@ -645,6 +729,7 @@ interface SchemaEdgeProps {
645
729
  nullable?: boolean | undefined;
646
730
  discriminator?: any;
647
731
  schemaType: "request" | "response";
732
+ schemaPath?: string;
648
733
  }
649
734
 
650
735
  const SchemaEdge: React.FC<SchemaEdgeProps> = ({
@@ -653,6 +738,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
653
738
  required,
654
739
  discriminator,
655
740
  schemaType,
741
+ schemaPath,
656
742
  }) => {
657
743
  if (
658
744
  (schemaType === "request" && schema.readOnly) ||
@@ -686,6 +772,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
686
772
  required={required}
687
773
  schema={schema}
688
774
  nullable={schema.nullable}
775
+ schemaPath={schemaPath}
689
776
  />
690
777
  );
691
778
  }
@@ -699,6 +786,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
699
786
  required={required}
700
787
  schema={schema}
701
788
  nullable={schema.nullable}
789
+ schemaPath={schemaPath}
702
790
  />
703
791
  );
704
792
  }
@@ -712,6 +800,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
712
800
  required={required}
713
801
  schema={schema}
714
802
  nullable={schema.nullable}
803
+ schemaPath={schemaPath}
715
804
  />
716
805
  );
717
806
  }
@@ -725,6 +814,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
725
814
  nullable={schema.nullable}
726
815
  schema={schema}
727
816
  schemaType={schemaType}
817
+ schemaPath={schemaPath}
728
818
  />
729
819
  );
730
820
  }
@@ -738,6 +828,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
738
828
  nullable={schema.nullable}
739
829
  schema={schema}
740
830
  schemaType={schemaType}
831
+ schemaPath={schemaPath}
741
832
  />
742
833
  );
743
834
  }
@@ -787,6 +878,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
787
878
  nullable={mergedSchemas.nullable}
788
879
  schema={mergedSchemas}
789
880
  schemaType={schemaType}
881
+ schemaPath={schemaPath}
790
882
  />
791
883
  );
792
884
  }
@@ -802,6 +894,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
802
894
  nullable={mergedSchemas.nullable}
803
895
  schema={mergedSchemas}
804
896
  schemaType={schemaType}
897
+ schemaPath={schemaPath}
805
898
  />
806
899
  );
807
900
  }
@@ -817,6 +910,7 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
817
910
  nullable={mergedSchemas.nullable}
818
911
  schema={mergedSchemas}
819
912
  schemaType={schemaType}
913
+ schemaPath={schemaPath}
820
914
  />
821
915
  );
822
916
  }
@@ -851,24 +945,51 @@ const SchemaEdge: React.FC<SchemaEdgeProps> = ({
851
945
 
852
946
  function renderChildren(
853
947
  schema: SchemaObject,
854
- schemaType: "request" | "response"
948
+ schemaType: "request" | "response",
949
+ schemaPath?: string
855
950
  ) {
856
951
  return (
857
952
  <>
858
- {schema.oneOf && <AnyOneOf schema={schema} schemaType={schemaType} />}
859
- {schema.anyOf && <AnyOneOf schema={schema} schemaType={schemaType} />}
953
+ {schema.oneOf && (
954
+ <AnyOneOf
955
+ schema={schema}
956
+ schemaType={schemaType}
957
+ schemaPath={schemaPath}
958
+ />
959
+ )}
960
+ {schema.anyOf && (
961
+ <AnyOneOf
962
+ schema={schema}
963
+ schemaType={schemaType}
964
+ schemaPath={schemaPath}
965
+ />
966
+ )}
860
967
  {schema.properties && (
861
- <Properties schema={schema} schemaType={schemaType} />
968
+ <Properties
969
+ schema={schema}
970
+ schemaType={schemaType}
971
+ schemaPath={schemaPath}
972
+ />
862
973
  )}
863
974
  {schema.additionalProperties && (
864
975
  <AdditionalProperties schema={schema} schemaType={schemaType} />
865
976
  )}
866
- {schema.items && <Items schema={schema} schemaType={schemaType} />}
977
+ {schema.items && (
978
+ <Items
979
+ schema={schema}
980
+ schemaType={schemaType}
981
+ schemaPath={schemaPath}
982
+ />
983
+ )}
867
984
  </>
868
985
  );
869
986
  }
870
987
 
871
- const SchemaNode: React.FC<SchemaProps> = ({ schema, schemaType }) => {
988
+ const SchemaNode: React.FC<SchemaProps> = ({
989
+ schema,
990
+ schemaType,
991
+ schemaPath,
992
+ }) => {
872
993
  if (
873
994
  (schemaType === "request" && schema.readOnly) ||
874
995
  (schemaType === "response" && schema.writeOnly)
@@ -911,9 +1032,16 @@ const SchemaNode: React.FC<SchemaProps> = ({ schema, schemaType }) => {
911
1032
  {/* Render all oneOf/anyOf constraints first */}
912
1033
  {schema.allOf.map((item: any, index: number) => {
913
1034
  if (item.oneOf || item.anyOf) {
1035
+ const itemSchemaPath = schemaPath
1036
+ ? `${schemaPath}.allOf.${index}`
1037
+ : undefined;
914
1038
  return (
915
1039
  <div key={index}>
916
- <AnyOneOf schema={item} schemaType={schemaType} />
1040
+ <AnyOneOf
1041
+ schema={item}
1042
+ schemaType={schemaType}
1043
+ schemaPath={itemSchemaPath}
1044
+ />
917
1045
  </div>
918
1046
  );
919
1047
  }
@@ -921,10 +1049,18 @@ const SchemaNode: React.FC<SchemaProps> = ({ schema, schemaType }) => {
921
1049
  })}
922
1050
  {/* Then render shared properties from the merge */}
923
1051
  {mergedSchemas.properties && (
924
- <Properties schema={mergedSchemas} schemaType={schemaType} />
1052
+ <Properties
1053
+ schema={mergedSchemas}
1054
+ schemaType={schemaType}
1055
+ schemaPath={schemaPath}
1056
+ />
925
1057
  )}
926
1058
  {mergedSchemas.items && (
927
- <Items schema={mergedSchemas} schemaType={schemaType} />
1059
+ <Items
1060
+ schema={mergedSchemas}
1061
+ schemaType={schemaType}
1062
+ schemaPath={schemaPath}
1063
+ />
928
1064
  )}
929
1065
  </div>
930
1066
  );
@@ -943,16 +1079,32 @@ const SchemaNode: React.FC<SchemaProps> = ({ schema, schemaType }) => {
943
1079
  return (
944
1080
  <div>
945
1081
  {mergedSchemas.oneOf && (
946
- <AnyOneOf schema={mergedSchemas} schemaType={schemaType} />
1082
+ <AnyOneOf
1083
+ schema={mergedSchemas}
1084
+ schemaType={schemaType}
1085
+ schemaPath={schemaPath}
1086
+ />
947
1087
  )}
948
1088
  {mergedSchemas.anyOf && (
949
- <AnyOneOf schema={mergedSchemas} schemaType={schemaType} />
1089
+ <AnyOneOf
1090
+ schema={mergedSchemas}
1091
+ schemaType={schemaType}
1092
+ schemaPath={schemaPath}
1093
+ />
950
1094
  )}
951
1095
  {mergedSchemas.properties && (
952
- <Properties schema={mergedSchemas} schemaType={schemaType} />
1096
+ <Properties
1097
+ schema={mergedSchemas}
1098
+ schemaType={schemaType}
1099
+ schemaPath={schemaPath}
1100
+ />
953
1101
  )}
954
1102
  {mergedSchemas.items && (
955
- <Items schema={mergedSchemas} schemaType={schemaType} />
1103
+ <Items
1104
+ schema={mergedSchemas}
1105
+ schemaType={schemaType}
1106
+ schemaPath={schemaPath}
1107
+ />
956
1108
  )}
957
1109
  </div>
958
1110
  );
@@ -983,7 +1135,7 @@ const SchemaNode: React.FC<SchemaProps> = ({ schema, schemaType }) => {
983
1135
  );
984
1136
  }
985
1137
 
986
- return renderChildren(schema, schemaType);
1138
+ return renderChildren(schema, schemaType, schemaPath);
987
1139
  };
988
1140
 
989
1141
  export default SchemaNode;
@@ -999,5 +1151,10 @@ const PRIMITIVE_TYPES: Record<PrimitiveSchemaType, true> = {
999
1151
  } as const;
1000
1152
 
1001
1153
  const isPrimitive = (schema: SchemaObject) => {
1154
+ // Enum-only schemas (without explicit type) should be treated as primitives
1155
+ // This is valid JSON Schema where enum values define the constraints
1156
+ if (schema.enum && !schema.type) {
1157
+ return true;
1158
+ }
1002
1159
  return PRIMITIVE_TYPES[schema.type as PrimitiveSchemaType];
1003
1160
  };
@@ -25,13 +25,22 @@ import useIsBrowser from "@docusaurus/useIsBrowser";
25
25
  import clsx from "clsx";
26
26
  import flatten from "lodash/flatten";
27
27
 
28
+ export interface SchemaTabsProps extends TabProps {
29
+ /**
30
+ * Optional callback fired when the selected tab changes.
31
+ * Receives the index of the newly selected tab.
32
+ */
33
+ onChange?: (index: number) => void;
34
+ }
35
+
28
36
  function TabList({
29
37
  className,
30
38
  block,
31
39
  selectedValue,
32
40
  selectValue,
33
41
  tabValues,
34
- }: TabProps & ReturnType<typeof useTabs>) {
42
+ onChange,
43
+ }: SchemaTabsProps & ReturnType<typeof useTabs>) {
35
44
  const tabRefs: (HTMLLIElement | null)[] = [];
36
45
  const { blockElementScrollPositionUntilNextRender } =
37
46
  useScrollPositionBlocker();
@@ -49,6 +58,8 @@ function TabList({
49
58
  if (newTabValue !== selectedValue) {
50
59
  blockElementScrollPositionUntilNextRender(newTab);
51
60
  selectValue(newTabValue);
61
+ // Notify parent component of the tab change
62
+ onChange?.(newTabIndex);
52
63
  }
53
64
  };
54
65
 
@@ -177,7 +188,7 @@ function TabContent({
177
188
  lazy,
178
189
  children,
179
190
  selectedValue,
180
- }: TabProps & ReturnType<typeof useTabs>) {
191
+ }: SchemaTabsProps & ReturnType<typeof useTabs>) {
181
192
  const childTabs = (Array.isArray(children) ? children : [children]).filter(
182
193
  Boolean
183
194
  ) as ReactElement<TabItemProps>[];
@@ -203,7 +214,7 @@ function TabContent({
203
214
  </div>
204
215
  );
205
216
  }
206
- function TabsComponent(props: TabProps): React.JSX.Element {
217
+ function TabsComponent(props: SchemaTabsProps): React.JSX.Element {
207
218
  const tabs = useTabs(props);
208
219
  return (
209
220
  <div className="openapi-tabs__schema-container">
@@ -212,7 +223,7 @@ function TabsComponent(props: TabProps): React.JSX.Element {
212
223
  </div>
213
224
  );
214
225
  }
215
- export default function SchemaTabs(props: TabProps): React.JSX.Element {
226
+ export default function SchemaTabs(props: SchemaTabsProps): React.JSX.Element {
216
227
  const isBrowser = useIsBrowser();
217
228
  return (
218
229
  <TabsComponent
@@ -8,7 +8,6 @@
8
8
  import React from "react";
9
9
 
10
10
  import { translate } from "@docusaurus/Translate";
11
-
12
11
  import ApiTabs from "@theme/ApiTabs";
13
12
  import Details from "@theme/Details";
14
13
  import Markdown from "@theme/Markdown";
@@ -16,7 +15,7 @@ import ResponseHeaders from "@theme/ResponseHeaders";
16
15
  import ResponseSchema from "@theme/ResponseSchema";
17
16
  import TabItem from "@theme/TabItem";
18
17
  import { OPENAPI_STATUS_CODES } from "@theme/translationIds";
19
- import { ApiItem } from "docusaurus-plugin-openapi-docs/lib/types";
18
+ import { ApiItem } from "docusaurus-plugin-openapi-docs/src/types";
20
19
 
21
20
  interface Props {
22
21
  id?: string;
@@ -166,6 +166,16 @@
166
166
  border-right: thin solid var(--ifm-toc-border-color);
167
167
  }
168
168
 
169
+ @media (min-width: 997px) {
170
+ .openapi-right-panel__container {
171
+ position: sticky;
172
+ top: calc(var(--ifm-navbar-height) + 1rem);
173
+ max-height: calc(100vh - var(--ifm-navbar-height) - 2rem);
174
+ overflow-y: auto;
175
+ align-self: flex-start;
176
+ }
177
+ }
178
+
169
179
  @media (max-width: 997px) {
170
180
  .schema {
171
181
  margin-bottom: 1rem;
@@ -1 +1 @@
1
- {"root":["./src/index.ts","./src/plugin-content-docs.d.ts","./src/postman-code-generators.d.ts","./src/react-magic-dropzone.d.ts","./src/theme-classic.d.ts","./src/theme-openapi.d.ts","./src/types.ts","./src/markdown/createDescription.ts","./src/markdown/schema.ts","./src/markdown/utils.test.ts","./src/markdown/utils.ts","./src/theme/translationIds.ts","./src/theme/ApiExplorer/buildPostmanRequest.ts","./src/theme/ApiExplorer/index.tsx","./src/theme/ApiExplorer/persistenceMiddleware.ts","./src/theme/ApiExplorer/storage-utils.ts","./src/theme/ApiExplorer/Accept/index.tsx","./src/theme/ApiExplorer/Accept/slice.ts","./src/theme/ApiExplorer/ApiCodeBlock/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/Container/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/Content/Element.tsx","./src/theme/ApiExplorer/ApiCodeBlock/Content/String.tsx","./src/theme/ApiExplorer/ApiCodeBlock/CopyButton/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/ExitButton/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/ExpandButton/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/Line/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/WordWrapButton/index.tsx","./src/theme/ApiExplorer/Authorization/auth-types.ts","./src/theme/ApiExplorer/Authorization/index.tsx","./src/theme/ApiExplorer/Authorization/slice.ts","./src/theme/ApiExplorer/Body/index.tsx","./src/theme/ApiExplorer/Body/json2xml.d.ts","./src/theme/ApiExplorer/Body/slice.ts","./src/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.tsx","./src/theme/ApiExplorer/Body/FormBodyItem/index.tsx","./src/theme/ApiExplorer/CodeSnippets/code-snippets-types.ts","./src/theme/ApiExplorer/CodeSnippets/index.tsx","./src/theme/ApiExplorer/CodeSnippets/languages.ts","./src/theme/ApiExplorer/CodeTabs/index.tsx","./src/theme/ApiExplorer/ContentType/index.tsx","./src/theme/ApiExplorer/ContentType/slice.ts","./src/theme/ApiExplorer/Export/index.tsx","./src/theme/ApiExplorer/FloatingButton/index.tsx","./src/theme/ApiExplorer/FormFileUpload/index.tsx","./src/theme/ApiExplorer/FormItem/index.tsx","./src/theme/ApiExplorer/FormMultiSelect/index.tsx","./src/theme/ApiExplorer/FormSelect/index.tsx","./src/theme/ApiExplorer/FormTextInput/index.tsx","./src/theme/ApiExplorer/LiveEditor/index.tsx","./src/theme/ApiExplorer/MethodEndpoint/index.tsx","./src/theme/ApiExplorer/ParamOptions/index.tsx","./src/theme/ApiExplorer/ParamOptions/slice.ts","./src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.tsx","./src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.tsx","./src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.tsx","./src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.tsx","./src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.tsx","./src/theme/ApiExplorer/Request/index.tsx","./src/theme/ApiExplorer/Request/makeRequest.ts","./src/theme/ApiExplorer/Response/index.tsx","./src/theme/ApiExplorer/Response/slice.ts","./src/theme/ApiExplorer/SecuritySchemes/index.tsx","./src/theme/ApiExplorer/Server/index.tsx","./src/theme/ApiExplorer/Server/slice.ts","./src/theme/ApiItem/hooks.ts","./src/theme/ApiItem/index.tsx","./src/theme/ApiItem/store.ts","./src/theme/ApiItem/Layout/index.tsx","./src/theme/ApiLogo/index.tsx","./src/theme/ApiTabs/index.tsx","./src/theme/ArrayBrackets/index.tsx","./src/theme/CodeSamples/index.tsx","./src/theme/DiscriminatorTabs/index.tsx","./src/theme/Example/index.tsx","./src/theme/Markdown/index.d.ts","./src/theme/MimeTabs/index.tsx","./src/theme/OperationTabs/index.tsx","./src/theme/ParamsDetails/index.tsx","./src/theme/ParamsItem/index.tsx","./src/theme/RequestSchema/index.tsx","./src/theme/ResponseExamples/index.tsx","./src/theme/ResponseHeaders/index.tsx","./src/theme/ResponseSchema/index.tsx","./src/theme/Schema/index.tsx","./src/theme/SchemaItem/index.tsx","./src/theme/SchemaTabs/index.tsx","./src/theme/SkeletonLoader/index.tsx","./src/theme/StatusCodes/index.tsx"],"version":"5.9.3"}
1
+ {"root":["./src/index.ts","./src/plugin-content-docs.d.ts","./src/postman-code-generators.d.ts","./src/react-magic-dropzone.d.ts","./src/theme-classic.d.ts","./src/theme-openapi.d.ts","./src/types.d.ts","./src/markdown/createDescription.ts","./src/markdown/schema.ts","./src/markdown/utils.test.ts","./src/markdown/utils.ts","./src/theme/translationIds.ts","./src/theme/ApiExplorer/buildPostmanRequest.ts","./src/theme/ApiExplorer/index.tsx","./src/theme/ApiExplorer/persistenceMiddleware.ts","./src/theme/ApiExplorer/storage-utils.ts","./src/theme/ApiExplorer/Accept/index.tsx","./src/theme/ApiExplorer/Accept/slice.ts","./src/theme/ApiExplorer/ApiCodeBlock/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/Container/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/Content/Element.tsx","./src/theme/ApiExplorer/ApiCodeBlock/Content/String.tsx","./src/theme/ApiExplorer/ApiCodeBlock/CopyButton/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/ExitButton/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/ExpandButton/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/Line/index.tsx","./src/theme/ApiExplorer/ApiCodeBlock/WordWrapButton/index.tsx","./src/theme/ApiExplorer/Authorization/auth-types.ts","./src/theme/ApiExplorer/Authorization/index.tsx","./src/theme/ApiExplorer/Authorization/slice.ts","./src/theme/ApiExplorer/Body/index.tsx","./src/theme/ApiExplorer/Body/json2xml.d.ts","./src/theme/ApiExplorer/Body/resolveSchemaWithSelections.ts","./src/theme/ApiExplorer/Body/slice.ts","./src/theme/ApiExplorer/Body/FileArrayFormBodyItem/index.tsx","./src/theme/ApiExplorer/Body/FormBodyItem/index.tsx","./src/theme/ApiExplorer/CodeSnippets/code-snippets-types.ts","./src/theme/ApiExplorer/CodeSnippets/index.tsx","./src/theme/ApiExplorer/CodeSnippets/languages.ts","./src/theme/ApiExplorer/CodeTabs/index.tsx","./src/theme/ApiExplorer/ContentType/index.tsx","./src/theme/ApiExplorer/ContentType/slice.ts","./src/theme/ApiExplorer/Export/index.tsx","./src/theme/ApiExplorer/FloatingButton/index.tsx","./src/theme/ApiExplorer/FormFileUpload/index.tsx","./src/theme/ApiExplorer/FormItem/index.tsx","./src/theme/ApiExplorer/FormMultiSelect/index.tsx","./src/theme/ApiExplorer/FormSelect/index.tsx","./src/theme/ApiExplorer/FormTextInput/index.tsx","./src/theme/ApiExplorer/LiveEditor/index.tsx","./src/theme/ApiExplorer/MethodEndpoint/index.tsx","./src/theme/ApiExplorer/ParamOptions/index.tsx","./src/theme/ApiExplorer/ParamOptions/slice.ts","./src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.tsx","./src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.tsx","./src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.tsx","./src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.tsx","./src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.tsx","./src/theme/ApiExplorer/Request/index.tsx","./src/theme/ApiExplorer/Request/makeRequest.ts","./src/theme/ApiExplorer/Response/index.tsx","./src/theme/ApiExplorer/Response/slice.ts","./src/theme/ApiExplorer/SchemaSelection/index.ts","./src/theme/ApiExplorer/SchemaSelection/slice.ts","./src/theme/ApiExplorer/SecuritySchemes/index.tsx","./src/theme/ApiExplorer/Server/index.tsx","./src/theme/ApiExplorer/Server/slice.ts","./src/theme/ApiItem/hooks.ts","./src/theme/ApiItem/index.tsx","./src/theme/ApiItem/store.ts","./src/theme/ApiItem/Layout/index.tsx","./src/theme/ApiLogo/index.tsx","./src/theme/ApiTabs/index.tsx","./src/theme/ArrayBrackets/index.tsx","./src/theme/CodeSamples/index.tsx","./src/theme/DiscriminatorTabs/index.tsx","./src/theme/Example/index.tsx","./src/theme/Markdown/index.d.ts","./src/theme/MimeTabs/index.tsx","./src/theme/OperationTabs/index.tsx","./src/theme/ParamsDetails/index.tsx","./src/theme/ParamsItem/index.tsx","./src/theme/RequestSchema/index.tsx","./src/theme/ResponseExamples/index.tsx","./src/theme/ResponseHeaders/index.tsx","./src/theme/ResponseSchema/index.tsx","./src/theme/Schema/index.tsx","./src/theme/SchemaItem/index.tsx","./src/theme/SchemaTabs/index.tsx","./src/theme/SkeletonLoader/index.tsx","./src/theme/StatusCodes/index.tsx"],"version":"5.9.3"}