@jpmorganchase/elemental 3.0.1 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -12,6 +12,7 @@ declare type SidebarLayoutProps = {
12
12
  tryItCredentialsPolicy?: 'omit' | 'include' | 'same-origin';
13
13
  tryItCorsProxy?: string;
14
14
  tryItOutDefaultServer?: string;
15
+ useCustomNav?: boolean;
15
16
  };
16
17
  export declare const APIWithSidebarLayout: React.FC<SidebarLayoutProps>;
17
18
  export {};
@@ -18,6 +18,7 @@ export interface CommonAPIProps extends RoutingProps {
18
18
  tryItCredentialsPolicy?: 'omit' | 'include' | 'same-origin';
19
19
  tryItCorsProxy?: string;
20
20
  tryItOutDefaultServer?: string;
21
+ useCustomNav?: boolean;
21
22
  }
22
23
  export declare const APIImpl: React.FC<APIProps>;
23
24
  export declare const API: React.FC<APIProps>;
@@ -0,0 +1 @@
1
+ export declare const useGetOasNavTree: (apiDescriptionDocument: string | object) => any[];
@@ -0,0 +1 @@
1
+ import '@testing-library/jest-dom';
package/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export type { APIProps } from './containers/API';
2
2
  export { API } from './containers/API';
3
+ export { useGetOasNavTree } from './hooks/oas-nav-tree/useGetOasNavTree';
package/index.esm.js CHANGED
@@ -157,13 +157,20 @@ const isInternal = (node) => {
157
157
  return !!data['x-internal'];
158
158
  };
159
159
 
160
- const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, }) => {
160
+ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, useCustomNav, }) => {
161
161
  const container = React.useRef(null);
162
- const tree = React.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
162
+ const tree = React.useMemo(() => {
163
+ if (!useCustomNav)
164
+ return computeAPITree(serviceNode, { hideSchemas, hideInternal });
165
+ else
166
+ return [];
167
+ }, [serviceNode, hideSchemas, hideInternal, useCustomNav]);
163
168
  const location = useLocation();
164
169
  const { pathname } = location;
165
170
  const isRootPath = !pathname || pathname === '/';
166
171
  const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
172
+ React.useEffect(() => {
173
+ }, [pathname]);
167
174
  const layoutOptions = React.useMemo(() => ({ hideTryIt: hideTryIt, hideExport: hideExport || (node === null || node === void 0 ? void 0 : node.type) !== NodeType.HttpService }), [hideTryIt, hideExport, node]);
168
175
  if (!node) {
169
176
  const firstSlug = findFirstNodeSlug(tree);
@@ -186,7 +193,7 @@ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideI
186
193
  React.createElement(Flex, { flexGrow: true, flexShrink: true, overflowY: "auto", direction: "col" },
187
194
  React.createElement(TableOfContents, { tree: tree, activeId: pathname, Link: Link, onLinkClick: handleTocClick })),
188
195
  React.createElement(PoweredByLink, { source: serviceNode.name, pathname: pathname, packageType: "elements" })));
189
- return (React.createElement(SidebarLayout, { ref: container, sidebar: sidebar }, node && (React.createElement(ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer }))));
196
+ return (React.createElement(SidebarLayout, { ref: container, sidebar: sidebar, renderSideBar: !useCustomNav }, node && (React.createElement(ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer }))));
190
197
  };
191
198
 
192
199
  const itemMatchesHash = (hash, item) => {
@@ -200,7 +207,7 @@ TryItContext.displayName = 'TryItContext';
200
207
  const APIWithStackedLayout = ({ serviceNode, hideTryIt, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, }) => {
201
208
  const location = useLocation();
202
209
  const { groups } = computeTagGroups(serviceNode);
203
- return (React.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy } },
210
+ return (React.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy, tryItOutDefaultServer } },
204
211
  React.createElement(Flex, { w: "full", flexDirection: "col", m: "auto", className: "sl-max-w-4xl" },
205
212
  React.createElement(Box, { w: "full", borderB: true },
206
213
  React.createElement(Docs, { className: "sl-mx-auto", nodeData: serviceNode.data, nodeTitle: serviceNode.name, nodeType: NodeType.HttpService, location: location, layoutOptions: { showPoweredByLink: true, hideExport }, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItOutDefaultServer: tryItOutDefaultServer })),
@@ -239,7 +246,7 @@ const Item = React.memo(({ item }) => {
239
246
  const scrollRef = React.useRef(null);
240
247
  const color = HttpMethodColors[item.data.method] || 'gray';
241
248
  const isDeprecated = !!item.data.deprecated;
242
- const { hideTryIt, tryItCredentialsPolicy, corsProxy } = React.useContext(TryItContext);
249
+ const { hideTryIt, tryItCredentialsPolicy, corsProxy, tryItOutDefaultServer } = React.useContext(TryItContext);
243
250
  const onClick = React.useCallback(() => setIsExpanded(!isExpanded), [isExpanded]);
244
251
  React.useEffect(() => {
245
252
  var _a;
@@ -263,7 +270,7 @@ const Item = React.memo(({ item }) => {
263
270
  React.createElement(TabPanel, null,
264
271
  React.createElement(ParsedDocs, { className: "sl-px-4", node: item, location: location, layoutOptions: { noHeading: true, hideTryItPanel: true } })),
265
272
  React.createElement(TabPanel, null,
266
- React.createElement(TryItWithRequestSamples, { httpOperation: item.data, tryItCredentialsPolicy: tryItCredentialsPolicy, corsProxy: corsProxy }))))))));
273
+ React.createElement(TryItWithRequestSamples, { httpOperation: item.data, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItOutDefaultServer: tryItOutDefaultServer, corsProxy: corsProxy }))))))));
267
274
  });
268
275
  const Collapse = ({ isOpen, children }) => {
269
276
  if (!isOpen)
@@ -434,7 +441,8 @@ function findMapMatch(key, map) {
434
441
  if (typeof key === 'number')
435
442
  return;
436
443
  for (const entry of map) {
437
- if (!!((_a = entry.match) === null || _a === void 0 ? void 0 : _a.match(key)) || (entry.notMatch !== void 0 && !entry.notMatch.match(key))) {
444
+ const escapedKey = key.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
445
+ if (!!((_a = entry.match) === null || _a === void 0 ? void 0 : _a.match(escapedKey)) || (entry.notMatch !== void 0 && !entry.notMatch.match(escapedKey))) {
438
446
  return entry;
439
447
  }
440
448
  }
@@ -482,7 +490,7 @@ const propsAreWithDocument = (props) => {
482
490
  return props.hasOwnProperty('apiDescriptionDocument');
483
491
  };
484
492
  const APIImpl = props => {
485
- const { layout, apiDescriptionUrl = '', logo, hideTryIt, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, } = props;
493
+ const { layout, apiDescriptionUrl = '', logo, hideTryIt, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, useCustomNav, } = props;
486
494
  const apiDescriptionDocument = propsAreWithDocument(props) ? props.apiDescriptionDocument : undefined;
487
495
  const { data: fetchedDocument, error } = useQuery([apiDescriptionUrl], () => fetch(apiDescriptionUrl).then(res => {
488
496
  if (res.ok) {
@@ -509,8 +517,37 @@ const APIImpl = props => {
509
517
  return (React.createElement(Flex, { justify: "center", alignItems: "center", w: "full", minH: "screen" },
510
518
  React.createElement(NonIdealState, { title: "Failed to parse OpenAPI file", description: "Please make sure your OpenAPI file is valid and try again" })));
511
519
  }
512
- return (React.createElement(InlineRefResolverProvider, { document: parsedDocument }, layout === 'stacked' ? (React.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer })) : (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer }))));
520
+ return (React.createElement(InlineRefResolverProvider, { document: parsedDocument }, layout === 'stacked' ? (React.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer })) : (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer, useCustomNav: useCustomNav }))));
513
521
  };
514
522
  const API = flow(withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider)(APIImpl);
515
523
 
516
- export { API };
524
+ const useGetOasNavTree = (apiDescriptionDocument) => {
525
+ const parsedDocument = useParsedValue(apiDescriptionDocument);
526
+ const bundledDocument = useBundleRefsIntoDocument(parsedDocument);
527
+ if (!bundledDocument)
528
+ return [];
529
+ const groupSchemas = (tree) => {
530
+ const targetTitle = 'Schemas';
531
+ const newTree = tree.reduce((accumulator, currentObject) => {
532
+ var _a;
533
+ if (currentObject.title === targetTitle) {
534
+ accumulator.matchedObject = currentObject;
535
+ }
536
+ else if ((_a = currentObject.id) === null || _a === void 0 ? void 0 : _a.includes(targetTitle.toLowerCase())) {
537
+ accumulator.matchedObject.items = accumulator.matchedObject.items || [];
538
+ accumulator.matchedObject.items.push(currentObject);
539
+ }
540
+ else {
541
+ accumulator.others = accumulator.others || [];
542
+ accumulator.others.push(currentObject);
543
+ }
544
+ return accumulator;
545
+ }, {});
546
+ const navTree = [...newTree.others, newTree.matchedObject];
547
+ return navTree;
548
+ };
549
+ const apiTree = computeAPITree(transformOasToServiceNode(bundledDocument));
550
+ return groupSchemas(apiTree);
551
+ };
552
+
553
+ export { API, useGetOasNavTree };
package/index.js CHANGED
@@ -190,13 +190,20 @@ const isInternal = (node) => {
190
190
  return !!data['x-internal'];
191
191
  };
192
192
 
193
- const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, }) => {
193
+ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, useCustomNav, }) => {
194
194
  const container = React__namespace.useRef(null);
195
- const tree = React__namespace.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
195
+ const tree = React__namespace.useMemo(() => {
196
+ if (!useCustomNav)
197
+ return computeAPITree(serviceNode, { hideSchemas, hideInternal });
198
+ else
199
+ return [];
200
+ }, [serviceNode, hideSchemas, hideInternal, useCustomNav]);
196
201
  const location = reactRouterDom.useLocation();
197
202
  const { pathname } = location;
198
203
  const isRootPath = !pathname || pathname === '/';
199
204
  const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
205
+ React__namespace.useEffect(() => {
206
+ }, [pathname]);
200
207
  const layoutOptions = React__namespace.useMemo(() => ({ hideTryIt: hideTryIt, hideExport: hideExport || (node === null || node === void 0 ? void 0 : node.type) !== types.NodeType.HttpService }), [hideTryIt, hideExport, node]);
201
208
  if (!node) {
202
209
  const firstSlug = findFirstNodeSlug(tree);
@@ -219,7 +226,7 @@ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideI
219
226
  React__namespace.createElement(mosaic.Flex, { flexGrow: true, flexShrink: true, overflowY: "auto", direction: "col" },
220
227
  React__namespace.createElement(elementalCore.TableOfContents, { tree: tree, activeId: pathname, Link: reactRouterDom.Link, onLinkClick: handleTocClick })),
221
228
  React__namespace.createElement(elementalCore.PoweredByLink, { source: serviceNode.name, pathname: pathname, packageType: "elements" })));
222
- return (React__namespace.createElement(elementalCore.SidebarLayout, { ref: container, sidebar: sidebar }, node && (React__namespace.createElement(elementalCore.ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer }))));
229
+ return (React__namespace.createElement(elementalCore.SidebarLayout, { ref: container, sidebar: sidebar, renderSideBar: !useCustomNav }, node && (React__namespace.createElement(elementalCore.ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer }))));
223
230
  };
224
231
 
225
232
  const itemMatchesHash = (hash, item) => {
@@ -233,7 +240,7 @@ TryItContext.displayName = 'TryItContext';
233
240
  const APIWithStackedLayout = ({ serviceNode, hideTryIt, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, }) => {
234
241
  const location = reactRouterDom.useLocation();
235
242
  const { groups } = computeTagGroups(serviceNode);
236
- return (React__namespace.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy } },
243
+ return (React__namespace.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy, tryItOutDefaultServer } },
237
244
  React__namespace.createElement(mosaic.Flex, { w: "full", flexDirection: "col", m: "auto", className: "sl-max-w-4xl" },
238
245
  React__namespace.createElement(mosaic.Box, { w: "full", borderB: true },
239
246
  React__namespace.createElement(elementalCore.Docs, { className: "sl-mx-auto", nodeData: serviceNode.data, nodeTitle: serviceNode.name, nodeType: types.NodeType.HttpService, location: location, layoutOptions: { showPoweredByLink: true, hideExport }, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItOutDefaultServer: tryItOutDefaultServer })),
@@ -272,7 +279,7 @@ const Item = React__namespace.memo(({ item }) => {
272
279
  const scrollRef = React__namespace.useRef(null);
273
280
  const color = elementalCore.HttpMethodColors[item.data.method] || 'gray';
274
281
  const isDeprecated = !!item.data.deprecated;
275
- const { hideTryIt, tryItCredentialsPolicy, corsProxy } = React__namespace.useContext(TryItContext);
282
+ const { hideTryIt, tryItCredentialsPolicy, corsProxy, tryItOutDefaultServer } = React__namespace.useContext(TryItContext);
276
283
  const onClick = React__namespace.useCallback(() => setIsExpanded(!isExpanded), [isExpanded]);
277
284
  React__namespace.useEffect(() => {
278
285
  var _a;
@@ -296,7 +303,7 @@ const Item = React__namespace.memo(({ item }) => {
296
303
  React__namespace.createElement(mosaic.TabPanel, null,
297
304
  React__namespace.createElement(elementalCore.ParsedDocs, { className: "sl-px-4", node: item, location: location, layoutOptions: { noHeading: true, hideTryItPanel: true } })),
298
305
  React__namespace.createElement(mosaic.TabPanel, null,
299
- React__namespace.createElement(elementalCore.TryItWithRequestSamples, { httpOperation: item.data, tryItCredentialsPolicy: tryItCredentialsPolicy, corsProxy: corsProxy }))))))));
306
+ React__namespace.createElement(elementalCore.TryItWithRequestSamples, { httpOperation: item.data, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItOutDefaultServer: tryItOutDefaultServer, corsProxy: corsProxy }))))))));
300
307
  });
301
308
  const Collapse = ({ isOpen, children }) => {
302
309
  if (!isOpen)
@@ -467,7 +474,8 @@ function findMapMatch(key, map) {
467
474
  if (typeof key === 'number')
468
475
  return;
469
476
  for (const entry of map) {
470
- if (!!((_a = entry.match) === null || _a === void 0 ? void 0 : _a.match(key)) || (entry.notMatch !== void 0 && !entry.notMatch.match(key))) {
477
+ const escapedKey = key.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
478
+ if (!!((_a = entry.match) === null || _a === void 0 ? void 0 : _a.match(escapedKey)) || (entry.notMatch !== void 0 && !entry.notMatch.match(escapedKey))) {
471
479
  return entry;
472
480
  }
473
481
  }
@@ -515,7 +523,7 @@ const propsAreWithDocument = (props) => {
515
523
  return props.hasOwnProperty('apiDescriptionDocument');
516
524
  };
517
525
  const APIImpl = props => {
518
- const { layout, apiDescriptionUrl = '', logo, hideTryIt, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, } = props;
526
+ const { layout, apiDescriptionUrl = '', logo, hideTryIt, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, useCustomNav, } = props;
519
527
  const apiDescriptionDocument = propsAreWithDocument(props) ? props.apiDescriptionDocument : undefined;
520
528
  const { data: fetchedDocument, error } = reactQuery.useQuery([apiDescriptionUrl], () => fetch(apiDescriptionUrl).then(res => {
521
529
  if (res.ok) {
@@ -542,8 +550,38 @@ const APIImpl = props => {
542
550
  return (React__namespace.createElement(mosaic.Flex, { justify: "center", alignItems: "center", w: "full", minH: "screen" },
543
551
  React__namespace.createElement(elementalCore.NonIdealState, { title: "Failed to parse OpenAPI file", description: "Please make sure your OpenAPI file is valid and try again" })));
544
552
  }
545
- return (React__namespace.createElement(elementalCore.InlineRefResolverProvider, { document: parsedDocument }, layout === 'stacked' ? (React__namespace.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer })) : (React__namespace.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer }))));
553
+ return (React__namespace.createElement(elementalCore.InlineRefResolverProvider, { document: parsedDocument }, layout === 'stacked' ? (React__namespace.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer })) : (React__namespace.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer, useCustomNav: useCustomNav }))));
546
554
  };
547
555
  const API = flow__default["default"](elementalCore.withRouter, elementalCore.withStyles, elementalCore.withPersistenceBoundary, elementalCore.withMosaicProvider, elementalCore.withQueryClientProvider)(APIImpl);
548
556
 
557
+ const useGetOasNavTree = (apiDescriptionDocument) => {
558
+ const parsedDocument = elementalCore.useParsedValue(apiDescriptionDocument);
559
+ const bundledDocument = elementalCore.useBundleRefsIntoDocument(parsedDocument);
560
+ if (!bundledDocument)
561
+ return [];
562
+ const groupSchemas = (tree) => {
563
+ const targetTitle = 'Schemas';
564
+ const newTree = tree.reduce((accumulator, currentObject) => {
565
+ var _a;
566
+ if (currentObject.title === targetTitle) {
567
+ accumulator.matchedObject = currentObject;
568
+ }
569
+ else if ((_a = currentObject.id) === null || _a === void 0 ? void 0 : _a.includes(targetTitle.toLowerCase())) {
570
+ accumulator.matchedObject.items = accumulator.matchedObject.items || [];
571
+ accumulator.matchedObject.items.push(currentObject);
572
+ }
573
+ else {
574
+ accumulator.others = accumulator.others || [];
575
+ accumulator.others.push(currentObject);
576
+ }
577
+ return accumulator;
578
+ }, {});
579
+ const navTree = [...newTree.others, newTree.matchedObject];
580
+ return navTree;
581
+ };
582
+ const apiTree = computeAPITree(transformOasToServiceNode(bundledDocument));
583
+ return groupSchemas(apiTree);
584
+ };
585
+
549
586
  exports.API = API;
587
+ exports.useGetOasNavTree = useGetOasNavTree;
package/index.mjs CHANGED
@@ -157,13 +157,20 @@ const isInternal = (node) => {
157
157
  return !!data['x-internal'];
158
158
  };
159
159
 
160
- const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, }) => {
160
+ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, useCustomNav, }) => {
161
161
  const container = React.useRef(null);
162
- const tree = React.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
162
+ const tree = React.useMemo(() => {
163
+ if (!useCustomNav)
164
+ return computeAPITree(serviceNode, { hideSchemas, hideInternal });
165
+ else
166
+ return [];
167
+ }, [serviceNode, hideSchemas, hideInternal, useCustomNav]);
163
168
  const location = useLocation();
164
169
  const { pathname } = location;
165
170
  const isRootPath = !pathname || pathname === '/';
166
171
  const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
172
+ React.useEffect(() => {
173
+ }, [pathname]);
167
174
  const layoutOptions = React.useMemo(() => ({ hideTryIt: hideTryIt, hideExport: hideExport || (node === null || node === void 0 ? void 0 : node.type) !== NodeType.HttpService }), [hideTryIt, hideExport, node]);
168
175
  if (!node) {
169
176
  const firstSlug = findFirstNodeSlug(tree);
@@ -186,7 +193,7 @@ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideI
186
193
  React.createElement(Flex, { flexGrow: true, flexShrink: true, overflowY: "auto", direction: "col" },
187
194
  React.createElement(TableOfContents, { tree: tree, activeId: pathname, Link: Link, onLinkClick: handleTocClick })),
188
195
  React.createElement(PoweredByLink, { source: serviceNode.name, pathname: pathname, packageType: "elements" })));
189
- return (React.createElement(SidebarLayout, { ref: container, sidebar: sidebar }, node && (React.createElement(ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer }))));
196
+ return (React.createElement(SidebarLayout, { ref: container, sidebar: sidebar, renderSideBar: !useCustomNav }, node && (React.createElement(ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer }))));
190
197
  };
191
198
 
192
199
  const itemMatchesHash = (hash, item) => {
@@ -200,7 +207,7 @@ TryItContext.displayName = 'TryItContext';
200
207
  const APIWithStackedLayout = ({ serviceNode, hideTryIt, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, }) => {
201
208
  const location = useLocation();
202
209
  const { groups } = computeTagGroups(serviceNode);
203
- return (React.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy } },
210
+ return (React.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy, tryItOutDefaultServer } },
204
211
  React.createElement(Flex, { w: "full", flexDirection: "col", m: "auto", className: "sl-max-w-4xl" },
205
212
  React.createElement(Box, { w: "full", borderB: true },
206
213
  React.createElement(Docs, { className: "sl-mx-auto", nodeData: serviceNode.data, nodeTitle: serviceNode.name, nodeType: NodeType.HttpService, location: location, layoutOptions: { showPoweredByLink: true, hideExport }, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItOutDefaultServer: tryItOutDefaultServer })),
@@ -239,7 +246,7 @@ const Item = React.memo(({ item }) => {
239
246
  const scrollRef = React.useRef(null);
240
247
  const color = HttpMethodColors[item.data.method] || 'gray';
241
248
  const isDeprecated = !!item.data.deprecated;
242
- const { hideTryIt, tryItCredentialsPolicy, corsProxy } = React.useContext(TryItContext);
249
+ const { hideTryIt, tryItCredentialsPolicy, corsProxy, tryItOutDefaultServer } = React.useContext(TryItContext);
243
250
  const onClick = React.useCallback(() => setIsExpanded(!isExpanded), [isExpanded]);
244
251
  React.useEffect(() => {
245
252
  var _a;
@@ -263,7 +270,7 @@ const Item = React.memo(({ item }) => {
263
270
  React.createElement(TabPanel, null,
264
271
  React.createElement(ParsedDocs, { className: "sl-px-4", node: item, location: location, layoutOptions: { noHeading: true, hideTryItPanel: true } })),
265
272
  React.createElement(TabPanel, null,
266
- React.createElement(TryItWithRequestSamples, { httpOperation: item.data, tryItCredentialsPolicy: tryItCredentialsPolicy, corsProxy: corsProxy }))))))));
273
+ React.createElement(TryItWithRequestSamples, { httpOperation: item.data, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItOutDefaultServer: tryItOutDefaultServer, corsProxy: corsProxy }))))))));
267
274
  });
268
275
  const Collapse = ({ isOpen, children }) => {
269
276
  if (!isOpen)
@@ -434,7 +441,8 @@ function findMapMatch(key, map) {
434
441
  if (typeof key === 'number')
435
442
  return;
436
443
  for (const entry of map) {
437
- if (!!((_a = entry.match) === null || _a === void 0 ? void 0 : _a.match(key)) || (entry.notMatch !== void 0 && !entry.notMatch.match(key))) {
444
+ const escapedKey = key.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&');
445
+ if (!!((_a = entry.match) === null || _a === void 0 ? void 0 : _a.match(escapedKey)) || (entry.notMatch !== void 0 && !entry.notMatch.match(escapedKey))) {
438
446
  return entry;
439
447
  }
440
448
  }
@@ -482,7 +490,7 @@ const propsAreWithDocument = (props) => {
482
490
  return props.hasOwnProperty('apiDescriptionDocument');
483
491
  };
484
492
  const APIImpl = props => {
485
- const { layout, apiDescriptionUrl = '', logo, hideTryIt, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, } = props;
493
+ const { layout, apiDescriptionUrl = '', logo, hideTryIt, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, tryItOutDefaultServer, useCustomNav, } = props;
486
494
  const apiDescriptionDocument = propsAreWithDocument(props) ? props.apiDescriptionDocument : undefined;
487
495
  const { data: fetchedDocument, error } = useQuery([apiDescriptionUrl], () => fetch(apiDescriptionUrl).then(res => {
488
496
  if (res.ok) {
@@ -509,8 +517,37 @@ const APIImpl = props => {
509
517
  return (React.createElement(Flex, { justify: "center", alignItems: "center", w: "full", minH: "screen" },
510
518
  React.createElement(NonIdealState, { title: "Failed to parse OpenAPI file", description: "Please make sure your OpenAPI file is valid and try again" })));
511
519
  }
512
- return (React.createElement(InlineRefResolverProvider, { document: parsedDocument }, layout === 'stacked' ? (React.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer })) : (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer }))));
520
+ return (React.createElement(InlineRefResolverProvider, { document: parsedDocument }, layout === 'stacked' ? (React.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer })) : (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, tryItOutDefaultServer: tryItOutDefaultServer, useCustomNav: useCustomNav }))));
513
521
  };
514
522
  const API = flow(withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider)(APIImpl);
515
523
 
516
- export { API };
524
+ const useGetOasNavTree = (apiDescriptionDocument) => {
525
+ const parsedDocument = useParsedValue(apiDescriptionDocument);
526
+ const bundledDocument = useBundleRefsIntoDocument(parsedDocument);
527
+ if (!bundledDocument)
528
+ return [];
529
+ const groupSchemas = (tree) => {
530
+ const targetTitle = 'Schemas';
531
+ const newTree = tree.reduce((accumulator, currentObject) => {
532
+ var _a;
533
+ if (currentObject.title === targetTitle) {
534
+ accumulator.matchedObject = currentObject;
535
+ }
536
+ else if ((_a = currentObject.id) === null || _a === void 0 ? void 0 : _a.includes(targetTitle.toLowerCase())) {
537
+ accumulator.matchedObject.items = accumulator.matchedObject.items || [];
538
+ accumulator.matchedObject.items.push(currentObject);
539
+ }
540
+ else {
541
+ accumulator.others = accumulator.others || [];
542
+ accumulator.others.push(currentObject);
543
+ }
544
+ return accumulator;
545
+ }, {});
546
+ const navTree = [...newTree.others, newTree.matchedObject];
547
+ return navTree;
548
+ };
549
+ const apiTree = computeAPITree(transformOasToServiceNode(bundledDocument));
550
+ return groupSchemas(apiTree);
551
+ };
552
+
553
+ export { API, useGetOasNavTree };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jpmorganchase/elemental",
3
- "version": "3.0.1",
3
+ "version": "3.2.1",
4
4
  "description": "UI components for composing beautiful developer documentation.",
5
5
  "keywords": [],
6
6
  "main": "./index.js",
@@ -26,11 +26,11 @@
26
26
  "react-dom": ">=16.8"
27
27
  },
28
28
  "dependencies": {
29
- "@jpmorganchase/elemental-core": "^1.1.1",
30
- "@stoplight/http-spec": "^5.1.4",
29
+ "@jpmorganchase/elemental-core": "^1.3.1",
30
+ "@stoplight/http-spec": "^6.0.0",
31
31
  "@stoplight/json": "^3.18.1",
32
- "@stoplight/mosaic": "^1.33.0",
33
- "@stoplight/types": "^13.7.0",
32
+ "@stoplight/mosaic": "^1.44.3",
33
+ "@stoplight/types": "^14.0.0",
34
34
  "@stoplight/yaml": "^4.2.3",
35
35
  "classnames": "^2.2.6",
36
36
  "file-saver": "^2.0.5",