docusaurus-theme-openapi-docs 5.0.2 → 5.1.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 (137) hide show
  1. package/lib/markdown/schema.js +38 -15
  2. package/lib/markdown/schema.test.d.ts +1 -0
  3. package/lib/markdown/schema.test.js +86 -0
  4. package/lib/theme/ApiExplorer/ApiCodeBlock/Container/index.js +4 -2
  5. package/lib/theme/ApiExplorer/ApiCodeBlock/Content/String.js +9 -6
  6. package/lib/theme/ApiExplorer/ApiCodeBlock/Line/index.d.ts +1 -1
  7. package/lib/theme/ApiExplorer/ApiCodeBlock/index.d.ts +1 -1
  8. package/lib/theme/ApiExplorer/Authorization/index.js +9 -10
  9. package/lib/theme/ApiExplorer/Body/index.js +4 -5
  10. package/lib/theme/ApiExplorer/CodeSnippets/index.js +96 -61
  11. package/lib/theme/ApiExplorer/CodeSnippets/languages.js +12 -1
  12. package/lib/theme/ApiExplorer/CodeSnippets/languages.test.d.ts +1 -0
  13. package/lib/theme/ApiExplorer/CodeSnippets/languages.test.js +102 -0
  14. package/lib/theme/ApiExplorer/CodeTabs/index.d.ts +1 -1
  15. package/lib/theme/ApiExplorer/CodeTabs/index.js +6 -5
  16. package/lib/theme/ApiExplorer/Export/index.js +9 -2
  17. package/lib/theme/ApiExplorer/FormFileUpload/index.js +1 -2
  18. package/lib/theme/ApiExplorer/FormLabel/index.js +1 -2
  19. package/lib/theme/ApiExplorer/FormTextInput/index.js +1 -2
  20. package/lib/theme/ApiExplorer/LiveEditor/index.js +1 -2
  21. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.js +5 -3
  22. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.js +75 -4
  23. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.js +1 -2
  24. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.js +67 -4
  25. package/lib/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.js +65 -1
  26. package/lib/theme/ApiExplorer/ParamOptions/index.js +2 -3
  27. package/lib/theme/ApiExplorer/Request/index.js +17 -18
  28. package/lib/theme/ApiExplorer/Response/index.js +54 -12
  29. package/lib/theme/ApiExplorer/SecuritySchemes/index.js +57 -50
  30. package/lib/theme/ApiExplorer/Server/index.js +2 -3
  31. package/lib/theme/ApiItem/index.js +59 -33
  32. package/lib/theme/ApiTabs/index.d.ts +1 -1
  33. package/lib/theme/ApiTabs/index.js +7 -7
  34. package/lib/theme/DiscriminatorTabs/index.d.ts +1 -1
  35. package/lib/theme/DiscriminatorTabs/index.js +6 -5
  36. package/lib/theme/Example/index.js +3 -4
  37. package/lib/theme/MimeTabs/index.d.ts +1 -1
  38. package/lib/theme/MimeTabs/index.js +6 -5
  39. package/lib/theme/OperationTabs/index.d.ts +1 -1
  40. package/lib/theme/OperationTabs/index.js +6 -5
  41. package/lib/theme/ParamsDetails/index.js +1 -2
  42. package/lib/theme/ParamsItem/index.js +7 -8
  43. package/lib/theme/RequestSchema/index.js +57 -57
  44. package/lib/theme/ResponseExamples/index.js +3 -4
  45. package/lib/theme/ResponseSchema/index.js +26 -24
  46. package/lib/theme/Schema/index.js +148 -27
  47. package/lib/theme/SchemaExpansion/_SchemaExpansion.scss +113 -0
  48. package/lib/theme/SchemaExpansion/context.d.ts +24 -0
  49. package/lib/theme/SchemaExpansion/context.js +187 -0
  50. package/lib/theme/SchemaExpansion/index.d.ts +4 -0
  51. package/lib/theme/SchemaExpansion/index.js +314 -0
  52. package/lib/theme/SchemaItem/index.js +9 -10
  53. package/lib/theme/SchemaTabs/index.d.ts +1 -1
  54. package/lib/theme/SchemaTabs/index.js +6 -5
  55. package/lib/theme/StatusCodes/index.js +2 -4
  56. package/lib/theme/TabItem/index.d.ts +5 -0
  57. package/lib/theme/TabItem/index.js +51 -0
  58. package/lib/theme/TabItem/styles.module.css +3 -0
  59. package/lib/theme/Tabs/index.d.ts +5 -0
  60. package/lib/theme/Tabs/index.js +148 -0
  61. package/lib/theme/Tabs/styles.module.css +7 -0
  62. package/lib/theme/styles.scss +1 -0
  63. package/lib/theme/translationIds.d.ts +1 -93
  64. package/lib/theme/translationIds.js +0 -109
  65. package/lib/theme/utils/codeBlockUtils.d.ts +28 -0
  66. package/lib/theme/utils/codeBlockUtils.js +223 -0
  67. package/lib/theme/utils/reactUtils.d.ts +1 -0
  68. package/lib/theme/utils/reactUtils.js +23 -0
  69. package/lib/theme/utils/scrollUtils.d.ts +7 -0
  70. package/lib/theme/utils/scrollUtils.js +175 -0
  71. package/lib/theme/utils/tabsUtils.d.ts +47 -0
  72. package/lib/theme/utils/tabsUtils.js +299 -0
  73. package/lib/theme/utils/useCodeWordWrap.d.ts +8 -0
  74. package/lib/theme/utils/useCodeWordWrap.js +84 -0
  75. package/lib/theme/utils/useMutationObserver.d.ts +3 -0
  76. package/lib/theme/utils/useMutationObserver.js +34 -0
  77. package/package.json +4 -4
  78. package/src/markdown/schema.test.ts +102 -0
  79. package/src/markdown/schema.ts +42 -15
  80. package/src/theme/ApiExplorer/ApiCodeBlock/Container/index.tsx +2 -1
  81. package/src/theme/ApiExplorer/ApiCodeBlock/Content/String.tsx +8 -7
  82. package/src/theme/ApiExplorer/ApiCodeBlock/Line/index.tsx +1 -1
  83. package/src/theme/ApiExplorer/ApiCodeBlock/index.tsx +1 -1
  84. package/src/theme/ApiExplorer/Authorization/index.tsx +9 -10
  85. package/src/theme/ApiExplorer/Body/index.tsx +7 -5
  86. package/src/theme/ApiExplorer/CodeSnippets/index.tsx +103 -59
  87. package/src/theme/ApiExplorer/CodeSnippets/languages.test.ts +109 -0
  88. package/src/theme/ApiExplorer/CodeSnippets/languages.ts +13 -1
  89. package/src/theme/ApiExplorer/CodeTabs/index.tsx +5 -5
  90. package/src/theme/ApiExplorer/Export/index.tsx +6 -2
  91. package/src/theme/ApiExplorer/FormFileUpload/index.tsx +1 -2
  92. package/src/theme/ApiExplorer/FormLabel/index.tsx +1 -2
  93. package/src/theme/ApiExplorer/FormTextInput/index.tsx +1 -2
  94. package/src/theme/ApiExplorer/LiveEditor/index.tsx +1 -2
  95. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamArrayFormItem.tsx +5 -3
  96. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamBooleanFormItem.tsx +20 -4
  97. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamMultiSelectFormItem.tsx +1 -2
  98. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamSelectFormItem.tsx +15 -4
  99. package/src/theme/ApiExplorer/ParamOptions/ParamFormItems/ParamTextFormItem.tsx +11 -1
  100. package/src/theme/ApiExplorer/ParamOptions/index.tsx +2 -3
  101. package/src/theme/ApiExplorer/Request/index.tsx +23 -18
  102. package/src/theme/ApiExplorer/Response/index.tsx +63 -9
  103. package/src/theme/ApiExplorer/SecuritySchemes/index.tsx +60 -52
  104. package/src/theme/ApiExplorer/Server/index.tsx +8 -3
  105. package/src/theme/ApiItem/index.tsx +43 -21
  106. package/src/theme/ApiTabs/index.tsx +8 -8
  107. package/src/theme/DiscriminatorTabs/index.tsx +6 -5
  108. package/src/theme/Example/index.tsx +3 -4
  109. package/src/theme/MimeTabs/index.tsx +9 -8
  110. package/src/theme/OperationTabs/index.tsx +5 -4
  111. package/src/theme/ParamsDetails/index.tsx +1 -2
  112. package/src/theme/ParamsItem/index.tsx +13 -8
  113. package/src/theme/RequestSchema/index.tsx +38 -40
  114. package/src/theme/ResponseExamples/index.tsx +3 -4
  115. package/src/theme/ResponseSchema/index.tsx +16 -17
  116. package/src/theme/Schema/index.tsx +156 -27
  117. package/src/theme/SchemaExpansion/_SchemaExpansion.scss +113 -0
  118. package/src/theme/SchemaExpansion/context.tsx +154 -0
  119. package/src/theme/SchemaExpansion/index.tsx +236 -0
  120. package/src/theme/SchemaItem/index.tsx +18 -10
  121. package/src/theme/SchemaTabs/index.tsx +6 -5
  122. package/src/theme/StatusCodes/index.tsx +2 -3
  123. package/src/theme/TabItem/index.tsx +61 -0
  124. package/src/theme/TabItem/styles.module.css +3 -0
  125. package/src/theme/Tabs/index.tsx +164 -0
  126. package/src/theme/Tabs/styles.module.css +7 -0
  127. package/src/theme/styles.scss +1 -0
  128. package/src/theme/translationIds.ts +37 -106
  129. package/src/theme/utils/codeBlockUtils.ts +296 -0
  130. package/src/theme/utils/reactUtils.ts +22 -0
  131. package/src/theme/utils/scrollUtils.tsx +153 -0
  132. package/src/theme/utils/tabsUtils.tsx +329 -0
  133. package/src/theme/utils/useCodeWordWrap.ts +110 -0
  134. package/src/theme/utils/useMutationObserver.ts +43 -0
  135. package/src/theme-classic.d.ts +0 -96
  136. package/src/types.d.ts +27 -0
  137. package/tsconfig.tsbuildinfo +1 -1
@@ -19,10 +19,10 @@ const Markdown_1 = __importDefault(require("@theme/Markdown"));
19
19
  const MimeTabs_1 = __importDefault(require("@theme/MimeTabs")); // Assume these components exist
20
20
  const ResponseExamples_1 = require("@theme/ResponseExamples");
21
21
  const Schema_1 = __importDefault(require("@theme/Schema"));
22
+ const SchemaExpansion_1 = __importDefault(require("@theme/SchemaExpansion"));
22
23
  const SchemaTabs_1 = __importDefault(require("@theme/SchemaTabs"));
23
24
  const SkeletonLoader_1 = __importDefault(require("@theme/SkeletonLoader"));
24
25
  const TabItem_1 = __importDefault(require("@theme/TabItem"));
25
- const translationIds_1 = require("@theme/translationIds");
26
26
  const ResponseSchemaComponent = ({ title, body, style }) => {
27
27
  if (
28
28
  body === undefined ||
@@ -57,7 +57,7 @@ const ResponseSchemaComponent = ({ title, body, style }) => {
57
57
  "div",
58
58
  null,
59
59
  (0, Translate_1.translate)({
60
- id: translationIds_1.OPENAPI_SCHEMA.NO_SCHEMA,
60
+ id: "theme.openapi.schema.noSchema",
61
61
  message: "No schema",
62
62
  })
63
63
  )
@@ -83,29 +83,31 @@ const ResponseSchemaComponent = ({ title, body, style }) => {
83
83
  open: true,
84
84
  style: style,
85
85
  summary: react_1.default.createElement(
86
- react_1.default.Fragment,
87
- null,
86
+ "summary",
87
+ {
88
+ className:
89
+ "openapi-markdown__details-summary--with-control",
90
+ },
88
91
  react_1.default.createElement(
89
- "summary",
90
- null,
91
- react_1.default.createElement(
92
- "strong",
93
- {
94
- className:
95
- "openapi-markdown__details-summary-response",
96
- },
97
- title,
98
- body.required === true &&
99
- react_1.default.createElement(
100
- "span",
101
- { className: "openapi-schema__required" },
102
- (0, Translate_1.translate)({
103
- id: translationIds_1.OPENAPI_SCHEMA_ITEM
104
- .REQUIRED,
105
- message: "required",
106
- })
107
- )
108
- )
92
+ "strong",
93
+ {
94
+ className:
95
+ "openapi-markdown__details-summary-response",
96
+ },
97
+ title,
98
+ body.required === true &&
99
+ react_1.default.createElement(
100
+ "span",
101
+ { className: "openapi-schema__required" },
102
+ (0, Translate_1.translate)({
103
+ id: "theme.openapi.schemaItem.required",
104
+ message: "required",
105
+ })
106
+ )
107
+ ),
108
+ react_1.default.createElement(
109
+ SchemaExpansion_1.default,
110
+ null
109
111
  )
110
112
  ),
111
113
  },
@@ -77,10 +77,10 @@ const DiscriminatorTabs_1 = __importDefault(
77
77
  require("@theme/DiscriminatorTabs")
78
78
  );
79
79
  const Markdown_1 = __importDefault(require("@theme/Markdown"));
80
+ const SchemaExpansion_1 = require("@theme/SchemaExpansion");
80
81
  const SchemaItem_1 = __importDefault(require("@theme/SchemaItem"));
81
82
  const SchemaTabs_1 = __importDefault(require("@theme/SchemaTabs"));
82
83
  const TabItem_1 = __importDefault(require("@theme/TabItem"));
83
- const translationIds_1 = require("@theme/translationIds");
84
84
  // eslint-disable-next-line import/no-extraneous-dependencies
85
85
  const allof_merge_1 = require("allof-merge");
86
86
  const clsx_1 = __importDefault(require("clsx"));
@@ -88,13 +88,99 @@ const isEmpty_1 = __importDefault(require("lodash/isEmpty"));
88
88
  const schema_1 = require("../../markdown/schema");
89
89
  // eslint-disable-next-line import/no-extraneous-dependencies
90
90
  // const jsonSchemaMergeAllOf = require("json-schema-merge-allof");
91
+ /**
92
+ * Strip `additionalProperties: false` from sibling allOf members so the
93
+ * strict-AND semantics of `allof-merge` don't collapse the result to an
94
+ * unsatisfiable empty schema.
95
+ *
96
+ * Per JSON Schema, two allOf members that each set `additionalProperties: false`
97
+ * with disjoint `properties` sets define an unsatisfiable schema (no value can
98
+ * satisfy both — each member rejects the other's properties). `allof-merge` is
99
+ * technically correct to drop all properties in that case, but it leaves the
100
+ * rendered schema blank.
101
+ *
102
+ * NSwag and Swashbuckle emit this pattern by default whenever a model uses
103
+ * inheritance/composition, so it's the dominant style for .NET-generated specs.
104
+ * Redoc, Swagger UI, and Stoplight all union the properties and ignore the
105
+ * conflicting flag — the approach this helper emulates by stripping the flag
106
+ * before delegating to `allof-merge`. The flag is render-irrelevant anyway:
107
+ * `additionalProperties: false` is treated identically to `undefined` by the
108
+ * AdditionalProperties component below (line ~641).
109
+ *
110
+ * Strips from every allOf member whenever the parent has ≥2 members. The
111
+ * collapse triggers symmetrically (both siblings strict) or asymmetrically
112
+ * (one strict member rejects another's properties as "additional"), so the
113
+ * presence of multiple members is the right gate. Single-member allOf is left
114
+ * alone — it can't conflict with anything.
115
+ *
116
+ * See https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/issues/1119
117
+ * Mirrored in plugin: docusaurus-plugin-openapi-docs/src/markdown/createSchema.ts
118
+ */
119
+ const stripConflictingAdditionalProps = (node) => {
120
+ if (Array.isArray(node)) return node.map(stripConflictingAdditionalProps);
121
+ if (!node || typeof node !== "object") return node;
122
+ let working = node;
123
+ if (Array.isArray(node.allOf) && node.allOf.length > 1) {
124
+ const hasStrictMember = node.allOf.some(
125
+ (m) => m && m.additionalProperties === false
126
+ );
127
+ if (hasStrictMember) {
128
+ working = {
129
+ ...node,
130
+ allOf: node.allOf.map((m) => {
131
+ if (m && m.additionalProperties === false) {
132
+ const { additionalProperties: _drop, ...rest } = m;
133
+ return rest;
134
+ }
135
+ return m;
136
+ }),
137
+ };
138
+ }
139
+ }
140
+ const result = {};
141
+ for (const [k, v] of Object.entries(working)) {
142
+ result[k] = stripConflictingAdditionalProps(v);
143
+ }
144
+ return result;
145
+ };
91
146
  const mergeAllOf = (allOf) => {
92
147
  const onMergeError = (msg) => {
93
148
  console.warn(msg);
94
149
  };
95
- const mergedSchemas = (0, allof_merge_1.merge)(allOf, { onMergeError });
150
+ const mergedSchemas = (0, allof_merge_1.merge)(
151
+ stripConflictingAdditionalProps(allOf),
152
+ {
153
+ onMergeError,
154
+ }
155
+ );
96
156
  return mergedSchemas ?? {};
97
157
  };
158
+ /**
159
+ * Fold sibling fields into each `oneOf`/`anyOf` branch via allOf-merge, so each
160
+ * branch is self-contained. Mirrors Redoc's `SchemaModel.initOneOf` behavior.
161
+ * Without this, when an `allOf` override redefines a nested property with
162
+ * `oneOf`, the merged schema ends up with both `properties` and `oneOf` as
163
+ * siblings — and the renderer prints the shared properties twice.
164
+ *
165
+ * See https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/issues/1218
166
+ */
167
+ const foldSiblingsIntoBranches = (schema) => {
168
+ const branchKey = schema?.oneOf
169
+ ? "oneOf"
170
+ : schema?.anyOf
171
+ ? "anyOf"
172
+ : undefined;
173
+ if (!branchKey) return schema;
174
+ const branches = schema[branchKey];
175
+ if (!Array.isArray(branches) || branches.length === 0) return schema;
176
+ const siblings = { ...schema };
177
+ delete siblings[branchKey];
178
+ if (Object.keys(siblings).length === 0) return schema;
179
+ const folded = branches.map((branch) =>
180
+ mergeAllOf({ allOf: [siblings, branch] })
181
+ );
182
+ return { [branchKey]: folded };
183
+ };
98
184
  /**
99
185
  * Recursively searches for a property in a schema, including nested
100
186
  * oneOf, anyOf, and allOf structures. This is needed for discriminators
@@ -199,7 +285,7 @@ const Summary = ({ name, schemaName, schema, required }) => {
199
285
  "span",
200
286
  { className: "openapi-schema__nullable" },
201
287
  (0, Translate_1.translate)({
202
- id: translationIds_1.OPENAPI_SCHEMA_ITEM.NULLABLE,
288
+ id: "theme.openapi.schemaItem.nullable",
203
289
  message: "nullable",
204
290
  })
205
291
  ),
@@ -208,7 +294,7 @@ const Summary = ({ name, schemaName, schema, required }) => {
208
294
  "span",
209
295
  { className: "openapi-schema__required" },
210
296
  (0, Translate_1.translate)({
211
- id: translationIds_1.OPENAPI_SCHEMA_ITEM.REQUIRED,
297
+ id: "theme.openapi.schemaItem.required",
212
298
  message: "required",
213
299
  })
214
300
  ),
@@ -217,7 +303,7 @@ const Summary = ({ name, schemaName, schema, required }) => {
217
303
  "span",
218
304
  { className: "openapi-schema__deprecated" },
219
305
  (0, Translate_1.translate)({
220
- id: translationIds_1.OPENAPI_SCHEMA_ITEM.DEPRECATED,
306
+ id: "theme.openapi.schemaItem.deprecated",
221
307
  message: "deprecated",
222
308
  })
223
309
  )
@@ -234,11 +320,11 @@ const AnyOneOf = ({ schema, schemaType, schemaPath }) => {
234
320
  }
235
321
  const type = schema.oneOf
236
322
  ? (0, Translate_1.translate)({
237
- id: translationIds_1.OPENAPI_SCHEMA_ITEM.ONE_OF,
323
+ id: "theme.openapi.schemaItem.oneOf",
238
324
  message: "oneOf",
239
325
  })
240
326
  : (0, Translate_1.translate)({
241
- id: translationIds_1.OPENAPI_SCHEMA_ITEM.ANY_OF,
327
+ id: "theme.openapi.schemaItem.anyOf",
242
328
  message: "anyOf",
243
329
  });
244
330
  // Generate a unique ID for this anyOf/oneOf to prevent tab value collisions
@@ -285,12 +371,12 @@ const AnyOneOf = ({ schema, schemaType, schemaPath }) => {
285
371
  if (!label) {
286
372
  if (anyOneSchema.oneOf) {
287
373
  label = (0, Translate_1.translate)({
288
- id: translationIds_1.OPENAPI_SCHEMA_ITEM.ONE_OF,
374
+ id: "theme.openapi.schemaItem.oneOf",
289
375
  message: "oneOf",
290
376
  });
291
377
  } else if (anyOneSchema.anyOf) {
292
378
  label = (0, Translate_1.translate)({
293
- id: translationIds_1.OPENAPI_SCHEMA_ITEM.ANY_OF,
379
+ id: "theme.openapi.schemaItem.anyOf",
294
380
  message: "anyOf",
295
381
  });
296
382
  } else {
@@ -459,7 +545,7 @@ const PropertyDiscriminator = ({
459
545
  "span",
460
546
  { className: "openapi-schema__required" },
461
547
  (0, Translate_1.translate)({
462
- id: translationIds_1.OPENAPI_SCHEMA_ITEM.REQUIRED,
548
+ id: "theme.openapi.schemaItem.required",
463
549
  message: "required",
464
550
  })
465
551
  )
@@ -644,13 +730,18 @@ const SchemaNodeDetails = ({
644
730
  schemaType,
645
731
  schemaPath,
646
732
  }) => {
733
+ const depth = (0, SchemaExpansion_1.useSchemaDepth)();
734
+ const { level } = (0, SchemaExpansion_1.useSchemaExpansion)();
735
+ const defaultOpen = depth < level;
647
736
  return react_1.default.createElement(
648
737
  SchemaItem_1.default,
649
738
  { collapsible: true },
650
739
  react_1.default.createElement(
651
740
  Details_1.default,
652
741
  {
742
+ key: `level-${level}`,
653
743
  className: "openapi-markdown__details",
744
+ open: defaultOpen,
654
745
  summary: react_1.default.createElement(Summary, {
655
746
  name: name,
656
747
  schemaName: schemaName,
@@ -669,11 +760,15 @@ const SchemaNodeDetails = ({
669
760
  react_1.default.createElement(MarkdownWrapper, {
670
761
  text: (0, schema_1.getQualifierMessage)(schema),
671
762
  }),
672
- react_1.default.createElement(SchemaNode, {
673
- schema: schema,
674
- schemaType: schemaType,
675
- schemaPath: schemaPath,
676
- })
763
+ react_1.default.createElement(
764
+ SchemaExpansion_1.SchemaDepthProvider,
765
+ { depth: depth + 1 },
766
+ react_1.default.createElement(SchemaNode, {
767
+ schema: schema,
768
+ schemaType: schemaType,
769
+ schemaPath: schemaPath,
770
+ })
771
+ )
677
772
  )
678
773
  )
679
774
  );
@@ -691,17 +786,25 @@ const Items = ({ schema, schemaType, schemaPath }) => {
691
786
  // Build the items schema path
692
787
  const itemsSchemaPath = schemaPath ? `${schemaPath}.items` : undefined;
693
788
  if (hasOneOfAnyOf || hasProperties || hasAdditionalProperties) {
789
+ // Fold sibling properties into each oneOf/anyOf branch to avoid duplicate
790
+ // property rendering. See issue #1218.
791
+ const renderSchema =
792
+ hasOneOfAnyOf && hasProperties
793
+ ? foldSiblingsIntoBranches(itemsSchema)
794
+ : itemsSchema;
795
+ const renderHasProperties =
796
+ hasOneOfAnyOf && hasProperties ? false : hasProperties;
694
797
  return react_1.default.createElement(
695
798
  react_1.default.Fragment,
696
799
  null,
697
800
  react_1.default.createElement(ArrayBrackets_1.OpeningArrayBracket, null),
698
801
  hasOneOfAnyOf &&
699
802
  react_1.default.createElement(AnyOneOf, {
700
- schema: itemsSchema,
803
+ schema: renderSchema,
701
804
  schemaType: schemaType,
702
805
  schemaPath: itemsSchemaPath,
703
806
  }),
704
- hasProperties &&
807
+ renderHasProperties &&
705
808
  react_1.default.createElement(Properties, {
706
809
  schema: itemsSchema,
707
810
  schemaType: schemaType,
@@ -918,22 +1021,30 @@ const SchemaEdge = ({
918
1021
  });
919
1022
  };
920
1023
  function renderChildren(schema, schemaType, schemaPath) {
1024
+ // Fold sibling properties into each oneOf/anyOf branch to avoid duplicate
1025
+ // property rendering. See issue #1218.
1026
+ const hasOneOfAnyOf = !!(schema.oneOf || schema.anyOf);
1027
+ const hasProperties = !!schema.properties;
1028
+ const folded =
1029
+ hasOneOfAnyOf && hasProperties ? foldSiblingsIntoBranches(schema) : schema;
1030
+ const renderProperties =
1031
+ hasOneOfAnyOf && hasProperties ? false : hasProperties;
921
1032
  return react_1.default.createElement(
922
1033
  react_1.default.Fragment,
923
1034
  null,
924
- schema.oneOf &&
1035
+ folded.oneOf &&
925
1036
  react_1.default.createElement(AnyOneOf, {
926
- schema: schema,
1037
+ schema: folded,
927
1038
  schemaType: schemaType,
928
1039
  schemaPath: schemaPath,
929
1040
  }),
930
- schema.anyOf &&
1041
+ folded.anyOf &&
931
1042
  react_1.default.createElement(AnyOneOf, {
932
- schema: schema,
1043
+ schema: folded,
933
1044
  schemaType: schemaType,
934
1045
  schemaPath: schemaPath,
935
1046
  }),
936
- schema.properties &&
1047
+ renderProperties &&
937
1048
  react_1.default.createElement(Properties, {
938
1049
  schema: schema,
939
1050
  schemaType: schemaType,
@@ -1034,22 +1145,32 @@ const SchemaNode = ({ schema, schemaType, schemaPath }) => {
1034
1145
  ) {
1035
1146
  return null;
1036
1147
  }
1148
+ // Fold sibling properties into each oneOf/anyOf branch to avoid duplicate
1149
+ // property rendering. See issue #1218.
1150
+ const hasOneOfAnyOf = !!(mergedSchemas.oneOf || mergedSchemas.anyOf);
1151
+ const hasProperties = !!mergedSchemas.properties;
1152
+ const folded =
1153
+ hasOneOfAnyOf && hasProperties
1154
+ ? foldSiblingsIntoBranches(mergedSchemas)
1155
+ : mergedSchemas;
1156
+ const renderProperties =
1157
+ hasOneOfAnyOf && hasProperties ? false : hasProperties;
1037
1158
  return react_1.default.createElement(
1038
1159
  "div",
1039
1160
  null,
1040
- mergedSchemas.oneOf &&
1161
+ folded.oneOf &&
1041
1162
  react_1.default.createElement(AnyOneOf, {
1042
- schema: mergedSchemas,
1163
+ schema: folded,
1043
1164
  schemaType: schemaType,
1044
1165
  schemaPath: schemaPath,
1045
1166
  }),
1046
- mergedSchemas.anyOf &&
1167
+ folded.anyOf &&
1047
1168
  react_1.default.createElement(AnyOneOf, {
1048
- schema: mergedSchemas,
1169
+ schema: folded,
1049
1170
  schemaType: schemaType,
1050
1171
  schemaPath: schemaPath,
1051
1172
  }),
1052
- mergedSchemas.properties &&
1173
+ renderProperties &&
1053
1174
  react_1.default.createElement(Properties, {
1054
1175
  schema: mergedSchemas,
1055
1176
  schemaType: schemaType,
@@ -0,0 +1,113 @@
1
+ /* ============================================================================
2
+ * Copyright (c) Palo Alto Networks
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ * ========================================================================== */
7
+
8
+ .openapi-schema-expansion {
9
+ position: relative;
10
+ display: inline-flex;
11
+ align-items: center;
12
+ margin-left: auto;
13
+ }
14
+
15
+ .openapi-schema-expansion__trigger {
16
+ appearance: none;
17
+ background: transparent;
18
+ border: none;
19
+ border-radius: var(--ifm-global-radius);
20
+ padding: 0;
21
+ width: 22px;
22
+ height: 22px;
23
+ flex: 0 0 22px;
24
+ display: inline-flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ color: var(--ifm-color-emphasis-600);
28
+ line-height: 0;
29
+ opacity: 0.7;
30
+ transition:
31
+ opacity 0.12s ease,
32
+ background-color 0.12s ease,
33
+ color 0.12s ease;
34
+
35
+ &:hover {
36
+ opacity: 1;
37
+ background-color: var(--ifm-color-emphasis-200);
38
+ color: var(--ifm-color-emphasis-900);
39
+ }
40
+
41
+ &:focus-visible {
42
+ outline: 2px solid var(--ifm-color-primary);
43
+ outline-offset: 2px;
44
+ opacity: 1;
45
+ }
46
+
47
+ &[aria-expanded="true"] {
48
+ opacity: 1;
49
+ background-color: var(--ifm-color-emphasis-200);
50
+ color: var(--ifm-color-emphasis-900);
51
+ }
52
+ }
53
+
54
+ .openapi-schema-expansion__popover {
55
+ position: fixed;
56
+ z-index: 1000;
57
+ display: inline-flex;
58
+ align-items: center;
59
+ gap: 2px;
60
+ padding: 3px;
61
+ background-color: var(--ifm-background-surface-color);
62
+ border: 1px solid var(--ifm-color-emphasis-300);
63
+ border-radius: var(--ifm-global-radius);
64
+ box-shadow: var(--ifm-global-shadow-md);
65
+ white-space: nowrap;
66
+ }
67
+
68
+ .openapi-schema-expansion__option {
69
+ appearance: none;
70
+ background: transparent;
71
+ border: none;
72
+ border-radius: calc(var(--ifm-global-radius) - 2px);
73
+ padding: 2px 8px;
74
+ font-size: 0.8rem;
75
+ line-height: 1.4;
76
+ color: var(--ifm-color-emphasis-800);
77
+ transition:
78
+ background-color 0.12s ease,
79
+ color 0.12s ease;
80
+
81
+ &:hover {
82
+ background-color: var(--ifm-color-emphasis-200);
83
+ }
84
+
85
+ &:focus-visible {
86
+ outline: 2px solid var(--ifm-color-primary);
87
+ outline-offset: 1px;
88
+ }
89
+ }
90
+
91
+ .openapi-schema-expansion__option--active {
92
+ background-color: var(--ifm-color-primary);
93
+ color: var(--ifm-color-white);
94
+
95
+ &:hover {
96
+ background-color: var(--ifm-color-primary-dark);
97
+ }
98
+ }
99
+
100
+ .openapi-markdown__details-summary--with-control {
101
+ display: flex !important;
102
+ align-items: center;
103
+ gap: 0.5rem;
104
+
105
+ > h3,
106
+ > strong {
107
+ margin-bottom: 0;
108
+ display: inline-flex;
109
+ align-items: center;
110
+ flex-wrap: wrap;
111
+ gap: 0.4rem;
112
+ }
113
+ }
@@ -0,0 +1,24 @@
1
+ import React from "react";
2
+ export declare const SCHEMA_EXPANSION_STORAGE_KEY = "docusaurus-openapi-schema-expansion-level";
3
+ export interface SchemaExpansionConfig {
4
+ enabled: boolean;
5
+ defaultLevel: number;
6
+ max: number;
7
+ persist: boolean;
8
+ }
9
+ interface SchemaExpansionContextValue {
10
+ config: SchemaExpansionConfig;
11
+ level: number;
12
+ setLevel: (next: number) => void;
13
+ }
14
+ export declare function normalizeLevel(value: number | "all" | undefined): number;
15
+ export declare const SchemaExpansionProvider: React.FC<{
16
+ children: React.ReactNode;
17
+ }>;
18
+ export declare const SchemaDepthProvider: React.FC<{
19
+ depth: number;
20
+ children: React.ReactNode;
21
+ }>;
22
+ export declare function useSchemaExpansion(): SchemaExpansionContextValue;
23
+ export declare function useSchemaDepth(): number;
24
+ export {};