@stoplight/elements 8.5.1 → 9.0.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.
@@ -18,6 +18,8 @@ declare type SidebarLayoutProps = {
18
18
  tryItCorsProxy?: string;
19
19
  compact?: number | boolean;
20
20
  renderExtensionAddon?: ExtensionAddonRenderer;
21
+ basePath?: string;
22
+ outerRouter?: boolean;
21
23
  };
22
24
  export declare const APIWithResponsiveSidebarLayout: React.FC<SidebarLayoutProps>;
23
25
  export {};
@@ -17,6 +17,8 @@ declare type SidebarLayoutProps = {
17
17
  tryItCredentialsPolicy?: 'omit' | 'include' | 'same-origin';
18
18
  tryItCorsProxy?: string;
19
19
  renderExtensionAddon?: ExtensionAddonRenderer;
20
+ basePath?: string;
21
+ outerRouter?: boolean;
20
22
  };
21
23
  export declare const APIWithSidebarLayout: React.FC<SidebarLayoutProps>;
22
24
  declare type SidebarProps = {
@@ -16,4 +16,5 @@ interface ComputeAPITreeConfig {
16
16
  export declare const computeAPITree: (serviceNode: ServiceNode, config?: ComputeAPITreeConfig) => TableOfContentsItem[];
17
17
  export declare const findFirstNodeSlug: (tree: TableOfContentsItem[]) => string | void;
18
18
  export declare const isInternal: (node: ServiceChildNode | ServiceNode) => boolean;
19
+ export declare const resolveRelativePath: (currentPath: string, basePath: string, outerRouter: boolean) => string;
19
20
  export {};
@@ -24,6 +24,7 @@ export interface CommonAPIProps extends RoutingProps {
24
24
  tryItCorsProxy?: string;
25
25
  maxRefDepth?: number;
26
26
  renderExtensionAddon?: ExtensionAddonRenderer;
27
+ outerRouter?: boolean;
27
28
  }
28
29
  export declare const APIImpl: React.FC<APIProps>;
29
30
  export declare const API: React.FC<APIProps>;
@@ -1,3 +1 @@
1
1
  import '@testing-library/jest-dom';
2
- import * as React from 'react';
3
- export declare const APIWithoutRouter: React.FC<import("./API").APIProps>;
package/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { isHttpOperation, isHttpWebhookOperation, isHttpService, HttpMethodColors, DeprecatedBadge, ParsedDocs, TryItWithRequestSamples, Docs, ResponsiveSidebarLayout, ElementsOptionsProvider, SidebarLayout, Logo, TableOfContents, PoweredByLink, slugify, withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider, useResponsiveLayout, useParsedValue, useBundleRefsIntoDocument, NonIdealState, InlineRefResolverProvider } from '@stoplight/elements-core';
1
+ import { isHttpOperation, isHttpWebhookOperation, isHttpService, resolveUrl, HttpMethodColors, DeprecatedBadge, ParsedDocs, TryItWithRequestSamples, Docs, resolveRelativeLink, ResponsiveSidebarLayout, ElementsOptionsProvider, SidebarLayout, Logo, TableOfContents, PoweredByLink, slugify, withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider, useResponsiveLayout, useParsedValue, useBundleRefsIntoDocument, NonIdealState, InlineRefResolverProvider } from '@stoplight/elements-core';
2
2
  import { Box, Flex, Icon, Tabs, TabList, Tab, TabPanels, TabPanel, Heading } from '@stoplight/mosaic';
3
3
  import { NodeType } from '@stoplight/types';
4
4
  import cn from 'classnames';
@@ -6,7 +6,7 @@ import * as React from 'react';
6
6
  import defaults from 'lodash/defaults.js';
7
7
  import flow from 'lodash/flow.js';
8
8
  import { useQuery } from 'react-query';
9
- import { useLocation, Redirect, Link } from 'react-router-dom';
9
+ import { useLocation, Navigate, Link } from 'react-router-dom';
10
10
  import { safeStringify } from '@stoplight/yaml';
11
11
  import saver from 'file-saver';
12
12
  import { OPERATION_CONFIG, WEBHOOK_CONFIG } from '@stoplight/http-spec/oas';
@@ -160,6 +160,14 @@ const addTagGroupsToTree = (groups, ungrouped, tree, itemsType, hideInternal) =>
160
160
  }
161
161
  });
162
162
  };
163
+ const resolveRelativePath = (currentPath, basePath, outerRouter) => {
164
+ if (!outerRouter || !basePath || basePath === '/') {
165
+ return currentPath;
166
+ }
167
+ const baseUrl = resolveUrl(basePath);
168
+ const currentUrl = resolveUrl(currentPath);
169
+ return baseUrl && currentUrl && baseUrl !== currentUrl ? currentUrl.replace(baseUrl, '') : '/';
170
+ };
163
171
 
164
172
  const itemMatchesHash = (hash, item) => {
165
173
  if (item.type === NodeType.HttpOperation) {
@@ -270,13 +278,14 @@ const Collapse = ({ isOpen, children }) => {
270
278
  };
271
279
  Collapse.displayName = 'Collapse';
272
280
 
273
- const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, compact, hideSchemas, hideInternal, hideExport, hideServerInfo, hideSecurityInfo, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, }) => {
281
+ const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, compact, hideSchemas, hideInternal, hideExport, hideServerInfo, hideSecurityInfo, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, basePath = '/', outerRouter = false, }) => {
274
282
  const container = React.useRef(null);
275
283
  const tree = React.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
276
284
  const location = useLocation();
277
- const { pathname } = location;
278
- const isRootPath = !pathname || pathname === '/';
279
- const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
285
+ const { pathname: currentPath } = location;
286
+ const relativePath = resolveRelativePath(currentPath, basePath, outerRouter);
287
+ const isRootPath = relativePath === '/';
288
+ const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === relativePath);
280
289
  const layoutOptions = React.useMemo(() => ({
281
290
  hideTryIt: hideTryIt,
282
291
  hideTryItPanel,
@@ -289,11 +298,11 @@ const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hid
289
298
  if (!node) {
290
299
  const firstSlug = findFirstNodeSlug(tree);
291
300
  if (firstSlug) {
292
- return React.createElement(Redirect, { to: firstSlug });
301
+ return React.createElement(Navigate, { to: resolveRelativeLink(firstSlug), replace: true });
293
302
  }
294
303
  }
295
304
  if (hideInternal && node && isInternal(node)) {
296
- return React.createElement(Redirect, { to: "/" });
305
+ return React.createElement(Navigate, { to: ".", replace: true });
297
306
  }
298
307
  const handleTocClick = () => {
299
308
  if (container.current) {
@@ -301,16 +310,17 @@ const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hid
301
310
  }
302
311
  };
303
312
  return (React.createElement(ResponsiveSidebarLayout, { onTocClick: handleTocClick, tree: tree, logo: logo !== null && logo !== void 0 ? logo : serviceNode.data.logo, ref: container, name: serviceNode.name }, node && (React.createElement(ElementsOptionsProvider, { renderExtensionAddon: renderExtensionAddon },
304
- React.createElement(ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
313
+ React.createElement(ParsedDocs, { key: relativePath, uri: relativePath, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
305
314
  };
306
315
 
307
- const APIWithSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, hideSchemas, hideSecurityInfo, hideServerInfo, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, }) => {
316
+ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, hideSchemas, hideSecurityInfo, hideServerInfo, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, basePath = '/', outerRouter = false, }) => {
308
317
  const container = React.useRef(null);
309
318
  const tree = React.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
310
319
  const location = useLocation();
311
- const { pathname } = location;
312
- const isRootPath = !pathname || pathname === '/';
313
- const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
320
+ const { pathname: currentPath } = location;
321
+ const relativePath = resolveRelativePath(currentPath, basePath, outerRouter);
322
+ const isRootPath = relativePath === '/';
323
+ const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === relativePath);
314
324
  const layoutOptions = React.useMemo(() => ({
315
325
  hideTryIt: hideTryIt,
316
326
  hideTryItPanel,
@@ -322,15 +332,15 @@ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hi
322
332
  if (!node) {
323
333
  const firstSlug = findFirstNodeSlug(tree);
324
334
  if (firstSlug) {
325
- return React.createElement(Redirect, { to: firstSlug });
335
+ return React.createElement(Navigate, { to: resolveRelativeLink(firstSlug), replace: true });
326
336
  }
327
337
  }
328
338
  if (hideInternal && node && isInternal(node)) {
329
- return React.createElement(Redirect, { to: "/" });
339
+ return React.createElement(Navigate, { to: ".", replace: true });
330
340
  }
331
- const sidebar = (React.createElement(Sidebar, { serviceNode: serviceNode, logo: logo, container: container, pathname: pathname, tree: tree }));
341
+ const sidebar = (React.createElement(Sidebar, { serviceNode: serviceNode, logo: logo, container: container, pathname: relativePath, tree: tree }));
332
342
  return (React.createElement(SidebarLayout, { ref: container, sidebar: sidebar }, node && (React.createElement(ElementsOptionsProvider, { renderExtensionAddon: renderExtensionAddon },
333
- React.createElement(ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
343
+ React.createElement(ParsedDocs, { key: relativePath, uri: relativePath, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
334
344
  };
335
345
  const Sidebar = ({ serviceNode, logo, container, pathname, tree }) => {
336
346
  const handleTocClick = () => {
@@ -608,7 +618,7 @@ const propsAreWithDocument = (props) => {
608
618
  return props.hasOwnProperty('apiDescriptionDocument');
609
619
  };
610
620
  const APIImpl = props => {
611
- const { layout = 'sidebar', apiDescriptionUrl = '', logo, hideTryItPanel, hideTryIt, hideSamples, hideSecurityInfo, hideServerInfo, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, maxRefDepth, renderExtensionAddon, } = props;
621
+ const { layout = 'sidebar', apiDescriptionUrl = '', logo, hideTryItPanel, hideTryIt, hideSamples, hideSecurityInfo, hideServerInfo, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, maxRefDepth, renderExtensionAddon, basePath, outerRouter = false, } = props;
612
622
  const location = useLocation();
613
623
  const apiDescriptionDocument = propsAreWithDocument(props) ? props.apiDescriptionDocument : undefined;
614
624
  const { isResponsiveLayoutEnabled } = useResponsiveLayout();
@@ -639,8 +649,8 @@ const APIImpl = props => {
639
649
  }
640
650
  return (React.createElement(InlineRefResolverProvider, { document: parsedDocument, maxRefDepth: maxRefDepth },
641
651
  layout === 'stacked' && (React.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideSamples: hideSamples, hideTryItPanel: hideTryItPanel, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, location: location })),
642
- layout === 'sidebar' && (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })),
643
- layout === 'responsive' && (React.createElement(APIWithResponsiveSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, compact: isResponsiveLayoutEnabled }))));
652
+ layout === 'sidebar' && (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, basePath: basePath, outerRouter: outerRouter })),
653
+ layout === 'responsive' && (React.createElement(APIWithResponsiveSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, compact: isResponsiveLayoutEnabled, basePath: basePath, outerRouter: outerRouter }))));
644
654
  };
645
655
  const API = flow(withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider)(APIImpl);
646
656
 
package/index.js CHANGED
@@ -181,6 +181,14 @@ const addTagGroupsToTree = (groups, ungrouped, tree, itemsType, hideInternal) =>
181
181
  }
182
182
  });
183
183
  };
184
+ const resolveRelativePath = (currentPath, basePath, outerRouter) => {
185
+ if (!outerRouter || !basePath || basePath === '/') {
186
+ return currentPath;
187
+ }
188
+ const baseUrl = elementsCore.resolveUrl(basePath);
189
+ const currentUrl = elementsCore.resolveUrl(currentPath);
190
+ return baseUrl && currentUrl && baseUrl !== currentUrl ? currentUrl.replace(baseUrl, '') : '/';
191
+ };
184
192
 
185
193
  const itemMatchesHash = (hash, item) => {
186
194
  if (item.type === types.NodeType.HttpOperation) {
@@ -291,13 +299,14 @@ const Collapse = ({ isOpen, children }) => {
291
299
  };
292
300
  Collapse.displayName = 'Collapse';
293
301
 
294
- const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, compact, hideSchemas, hideInternal, hideExport, hideServerInfo, hideSecurityInfo, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, }) => {
302
+ const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, compact, hideSchemas, hideInternal, hideExport, hideServerInfo, hideSecurityInfo, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, basePath = '/', outerRouter = false, }) => {
295
303
  const container = React__namespace.useRef(null);
296
304
  const tree = React__namespace.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
297
305
  const location = reactRouterDom.useLocation();
298
- const { pathname } = location;
299
- const isRootPath = !pathname || pathname === '/';
300
- const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
306
+ const { pathname: currentPath } = location;
307
+ const relativePath = resolveRelativePath(currentPath, basePath, outerRouter);
308
+ const isRootPath = relativePath === '/';
309
+ const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === relativePath);
301
310
  const layoutOptions = React__namespace.useMemo(() => ({
302
311
  hideTryIt: hideTryIt,
303
312
  hideTryItPanel,
@@ -310,11 +319,11 @@ const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hid
310
319
  if (!node) {
311
320
  const firstSlug = findFirstNodeSlug(tree);
312
321
  if (firstSlug) {
313
- return React__namespace.createElement(reactRouterDom.Redirect, { to: firstSlug });
322
+ return React__namespace.createElement(reactRouterDom.Navigate, { to: elementsCore.resolveRelativeLink(firstSlug), replace: true });
314
323
  }
315
324
  }
316
325
  if (hideInternal && node && isInternal(node)) {
317
- return React__namespace.createElement(reactRouterDom.Redirect, { to: "/" });
326
+ return React__namespace.createElement(reactRouterDom.Navigate, { to: ".", replace: true });
318
327
  }
319
328
  const handleTocClick = () => {
320
329
  if (container.current) {
@@ -322,16 +331,17 @@ const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hid
322
331
  }
323
332
  };
324
333
  return (React__namespace.createElement(elementsCore.ResponsiveSidebarLayout, { onTocClick: handleTocClick, tree: tree, logo: logo !== null && logo !== void 0 ? logo : serviceNode.data.logo, ref: container, name: serviceNode.name }, node && (React__namespace.createElement(elementsCore.ElementsOptionsProvider, { renderExtensionAddon: renderExtensionAddon },
325
- React__namespace.createElement(elementsCore.ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
334
+ React__namespace.createElement(elementsCore.ParsedDocs, { key: relativePath, uri: relativePath, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
326
335
  };
327
336
 
328
- const APIWithSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, hideSchemas, hideSecurityInfo, hideServerInfo, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, }) => {
337
+ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, hideSchemas, hideSecurityInfo, hideServerInfo, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, basePath = '/', outerRouter = false, }) => {
329
338
  const container = React__namespace.useRef(null);
330
339
  const tree = React__namespace.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
331
340
  const location = reactRouterDom.useLocation();
332
- const { pathname } = location;
333
- const isRootPath = !pathname || pathname === '/';
334
- const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
341
+ const { pathname: currentPath } = location;
342
+ const relativePath = resolveRelativePath(currentPath, basePath, outerRouter);
343
+ const isRootPath = relativePath === '/';
344
+ const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === relativePath);
335
345
  const layoutOptions = React__namespace.useMemo(() => ({
336
346
  hideTryIt: hideTryIt,
337
347
  hideTryItPanel,
@@ -343,15 +353,15 @@ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hi
343
353
  if (!node) {
344
354
  const firstSlug = findFirstNodeSlug(tree);
345
355
  if (firstSlug) {
346
- return React__namespace.createElement(reactRouterDom.Redirect, { to: firstSlug });
356
+ return React__namespace.createElement(reactRouterDom.Navigate, { to: elementsCore.resolveRelativeLink(firstSlug), replace: true });
347
357
  }
348
358
  }
349
359
  if (hideInternal && node && isInternal(node)) {
350
- return React__namespace.createElement(reactRouterDom.Redirect, { to: "/" });
360
+ return React__namespace.createElement(reactRouterDom.Navigate, { to: ".", replace: true });
351
361
  }
352
- const sidebar = (React__namespace.createElement(Sidebar, { serviceNode: serviceNode, logo: logo, container: container, pathname: pathname, tree: tree }));
362
+ const sidebar = (React__namespace.createElement(Sidebar, { serviceNode: serviceNode, logo: logo, container: container, pathname: relativePath, tree: tree }));
353
363
  return (React__namespace.createElement(elementsCore.SidebarLayout, { ref: container, sidebar: sidebar }, node && (React__namespace.createElement(elementsCore.ElementsOptionsProvider, { renderExtensionAddon: renderExtensionAddon },
354
- React__namespace.createElement(elementsCore.ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
364
+ React__namespace.createElement(elementsCore.ParsedDocs, { key: relativePath, uri: relativePath, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
355
365
  };
356
366
  const Sidebar = ({ serviceNode, logo, container, pathname, tree }) => {
357
367
  const handleTocClick = () => {
@@ -629,7 +639,7 @@ const propsAreWithDocument = (props) => {
629
639
  return props.hasOwnProperty('apiDescriptionDocument');
630
640
  };
631
641
  const APIImpl = props => {
632
- const { layout = 'sidebar', apiDescriptionUrl = '', logo, hideTryItPanel, hideTryIt, hideSamples, hideSecurityInfo, hideServerInfo, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, maxRefDepth, renderExtensionAddon, } = props;
642
+ const { layout = 'sidebar', apiDescriptionUrl = '', logo, hideTryItPanel, hideTryIt, hideSamples, hideSecurityInfo, hideServerInfo, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, maxRefDepth, renderExtensionAddon, basePath, outerRouter = false, } = props;
633
643
  const location = reactRouterDom.useLocation();
634
644
  const apiDescriptionDocument = propsAreWithDocument(props) ? props.apiDescriptionDocument : undefined;
635
645
  const { isResponsiveLayoutEnabled } = elementsCore.useResponsiveLayout();
@@ -660,8 +670,8 @@ const APIImpl = props => {
660
670
  }
661
671
  return (React__namespace.createElement(elementsCore.InlineRefResolverProvider, { document: parsedDocument, maxRefDepth: maxRefDepth },
662
672
  layout === 'stacked' && (React__namespace.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideSamples: hideSamples, hideTryItPanel: hideTryItPanel, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, location: location })),
663
- layout === 'sidebar' && (React__namespace.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })),
664
- layout === 'responsive' && (React__namespace.createElement(APIWithResponsiveSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, compact: isResponsiveLayoutEnabled }))));
673
+ layout === 'sidebar' && (React__namespace.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, basePath: basePath, outerRouter: outerRouter })),
674
+ layout === 'responsive' && (React__namespace.createElement(APIWithResponsiveSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, compact: isResponsiveLayoutEnabled, basePath: basePath, outerRouter: outerRouter }))));
665
675
  };
666
676
  const API = flow(elementsCore.withRouter, elementsCore.withStyles, elementsCore.withPersistenceBoundary, elementsCore.withMosaicProvider, elementsCore.withQueryClientProvider)(APIImpl);
667
677
 
package/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { isHttpOperation, isHttpWebhookOperation, isHttpService, HttpMethodColors, DeprecatedBadge, ParsedDocs, TryItWithRequestSamples, Docs, ResponsiveSidebarLayout, ElementsOptionsProvider, SidebarLayout, Logo, TableOfContents, PoweredByLink, slugify, withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider, useResponsiveLayout, useParsedValue, useBundleRefsIntoDocument, NonIdealState, InlineRefResolverProvider } from '@stoplight/elements-core';
1
+ import { isHttpOperation, isHttpWebhookOperation, isHttpService, resolveUrl, HttpMethodColors, DeprecatedBadge, ParsedDocs, TryItWithRequestSamples, Docs, resolveRelativeLink, ResponsiveSidebarLayout, ElementsOptionsProvider, SidebarLayout, Logo, TableOfContents, PoweredByLink, slugify, withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider, useResponsiveLayout, useParsedValue, useBundleRefsIntoDocument, NonIdealState, InlineRefResolverProvider } from '@stoplight/elements-core';
2
2
  import { Box, Flex, Icon, Tabs, TabList, Tab, TabPanels, TabPanel, Heading } from '@stoplight/mosaic';
3
3
  import { NodeType } from '@stoplight/types';
4
4
  import cn from 'classnames';
@@ -6,7 +6,7 @@ import * as React from 'react';
6
6
  import defaults from 'lodash/defaults.js';
7
7
  import flow from 'lodash/flow.js';
8
8
  import { useQuery } from 'react-query';
9
- import { useLocation, Redirect, Link } from 'react-router-dom';
9
+ import { useLocation, Navigate, Link } from 'react-router-dom';
10
10
  import { safeStringify } from '@stoplight/yaml';
11
11
  import saver from 'file-saver';
12
12
  import { OPERATION_CONFIG, WEBHOOK_CONFIG } from '@stoplight/http-spec/oas';
@@ -160,6 +160,14 @@ const addTagGroupsToTree = (groups, ungrouped, tree, itemsType, hideInternal) =>
160
160
  }
161
161
  });
162
162
  };
163
+ const resolveRelativePath = (currentPath, basePath, outerRouter) => {
164
+ if (!outerRouter || !basePath || basePath === '/') {
165
+ return currentPath;
166
+ }
167
+ const baseUrl = resolveUrl(basePath);
168
+ const currentUrl = resolveUrl(currentPath);
169
+ return baseUrl && currentUrl && baseUrl !== currentUrl ? currentUrl.replace(baseUrl, '') : '/';
170
+ };
163
171
 
164
172
  const itemMatchesHash = (hash, item) => {
165
173
  if (item.type === NodeType.HttpOperation) {
@@ -270,13 +278,14 @@ const Collapse = ({ isOpen, children }) => {
270
278
  };
271
279
  Collapse.displayName = 'Collapse';
272
280
 
273
- const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, compact, hideSchemas, hideInternal, hideExport, hideServerInfo, hideSecurityInfo, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, }) => {
281
+ const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, compact, hideSchemas, hideInternal, hideExport, hideServerInfo, hideSecurityInfo, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, basePath = '/', outerRouter = false, }) => {
274
282
  const container = React.useRef(null);
275
283
  const tree = React.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
276
284
  const location = useLocation();
277
- const { pathname } = location;
278
- const isRootPath = !pathname || pathname === '/';
279
- const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
285
+ const { pathname: currentPath } = location;
286
+ const relativePath = resolveRelativePath(currentPath, basePath, outerRouter);
287
+ const isRootPath = relativePath === '/';
288
+ const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === relativePath);
280
289
  const layoutOptions = React.useMemo(() => ({
281
290
  hideTryIt: hideTryIt,
282
291
  hideTryItPanel,
@@ -289,11 +298,11 @@ const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hid
289
298
  if (!node) {
290
299
  const firstSlug = findFirstNodeSlug(tree);
291
300
  if (firstSlug) {
292
- return React.createElement(Redirect, { to: firstSlug });
301
+ return React.createElement(Navigate, { to: resolveRelativeLink(firstSlug), replace: true });
293
302
  }
294
303
  }
295
304
  if (hideInternal && node && isInternal(node)) {
296
- return React.createElement(Redirect, { to: "/" });
305
+ return React.createElement(Navigate, { to: ".", replace: true });
297
306
  }
298
307
  const handleTocClick = () => {
299
308
  if (container.current) {
@@ -301,16 +310,17 @@ const APIWithResponsiveSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hid
301
310
  }
302
311
  };
303
312
  return (React.createElement(ResponsiveSidebarLayout, { onTocClick: handleTocClick, tree: tree, logo: logo !== null && logo !== void 0 ? logo : serviceNode.data.logo, ref: container, name: serviceNode.name }, node && (React.createElement(ElementsOptionsProvider, { renderExtensionAddon: renderExtensionAddon },
304
- React.createElement(ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
313
+ React.createElement(ParsedDocs, { key: relativePath, uri: relativePath, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
305
314
  };
306
315
 
307
- const APIWithSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, hideSchemas, hideSecurityInfo, hideServerInfo, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, }) => {
316
+ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hideSamples, hideSchemas, hideSecurityInfo, hideServerInfo, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, renderExtensionAddon, basePath = '/', outerRouter = false, }) => {
308
317
  const container = React.useRef(null);
309
318
  const tree = React.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
310
319
  const location = useLocation();
311
- const { pathname } = location;
312
- const isRootPath = !pathname || pathname === '/';
313
- const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
320
+ const { pathname: currentPath } = location;
321
+ const relativePath = resolveRelativePath(currentPath, basePath, outerRouter);
322
+ const isRootPath = relativePath === '/';
323
+ const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === relativePath);
314
324
  const layoutOptions = React.useMemo(() => ({
315
325
  hideTryIt: hideTryIt,
316
326
  hideTryItPanel,
@@ -322,15 +332,15 @@ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryItPanel, hideTryIt, hi
322
332
  if (!node) {
323
333
  const firstSlug = findFirstNodeSlug(tree);
324
334
  if (firstSlug) {
325
- return React.createElement(Redirect, { to: firstSlug });
335
+ return React.createElement(Navigate, { to: resolveRelativeLink(firstSlug), replace: true });
326
336
  }
327
337
  }
328
338
  if (hideInternal && node && isInternal(node)) {
329
- return React.createElement(Redirect, { to: "/" });
339
+ return React.createElement(Navigate, { to: ".", replace: true });
330
340
  }
331
- const sidebar = (React.createElement(Sidebar, { serviceNode: serviceNode, logo: logo, container: container, pathname: pathname, tree: tree }));
341
+ const sidebar = (React.createElement(Sidebar, { serviceNode: serviceNode, logo: logo, container: container, pathname: relativePath, tree: tree }));
332
342
  return (React.createElement(SidebarLayout, { ref: container, sidebar: sidebar }, node && (React.createElement(ElementsOptionsProvider, { renderExtensionAddon: renderExtensionAddon },
333
- React.createElement(ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
343
+ React.createElement(ParsedDocs, { key: relativePath, uri: relativePath, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })))));
334
344
  };
335
345
  const Sidebar = ({ serviceNode, logo, container, pathname, tree }) => {
336
346
  const handleTocClick = () => {
@@ -608,7 +618,7 @@ const propsAreWithDocument = (props) => {
608
618
  return props.hasOwnProperty('apiDescriptionDocument');
609
619
  };
610
620
  const APIImpl = props => {
611
- const { layout = 'sidebar', apiDescriptionUrl = '', logo, hideTryItPanel, hideTryIt, hideSamples, hideSecurityInfo, hideServerInfo, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, maxRefDepth, renderExtensionAddon, } = props;
621
+ const { layout = 'sidebar', apiDescriptionUrl = '', logo, hideTryItPanel, hideTryIt, hideSamples, hideSecurityInfo, hideServerInfo, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, maxRefDepth, renderExtensionAddon, basePath, outerRouter = false, } = props;
612
622
  const location = useLocation();
613
623
  const apiDescriptionDocument = propsAreWithDocument(props) ? props.apiDescriptionDocument : undefined;
614
624
  const { isResponsiveLayoutEnabled } = useResponsiveLayout();
@@ -639,8 +649,8 @@ const APIImpl = props => {
639
649
  }
640
650
  return (React.createElement(InlineRefResolverProvider, { document: parsedDocument, maxRefDepth: maxRefDepth },
641
651
  layout === 'stacked' && (React.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideSamples: hideSamples, hideTryItPanel: hideTryItPanel, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, location: location })),
642
- layout === 'sidebar' && (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon })),
643
- layout === 'responsive' && (React.createElement(APIWithResponsiveSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, compact: isResponsiveLayoutEnabled }))));
652
+ layout === 'sidebar' && (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, basePath: basePath, outerRouter: outerRouter })),
653
+ layout === 'responsive' && (React.createElement(APIWithResponsiveSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryItPanel: hideTryItPanel, hideTryIt: hideTryIt, hideSamples: hideSamples, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, renderExtensionAddon: renderExtensionAddon, compact: isResponsiveLayoutEnabled, basePath: basePath, outerRouter: outerRouter }))));
644
654
  };
645
655
  const API = flow(withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider)(APIImpl);
646
656
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoplight/elements",
3
- "version": "8.5.1",
3
+ "version": "9.0.0",
4
4
  "description": "UI components for composing beautiful developer documentation.",
5
5
  "keywords": [],
6
6
  "main": "./index.js",
@@ -26,7 +26,7 @@
26
26
  "react-dom": ">=16.8"
27
27
  },
28
28
  "dependencies": {
29
- "@stoplight/elements-core": "^8.5.1",
29
+ "@stoplight/elements-core": "~9.0.0",
30
30
  "@stoplight/http-spec": "^7.1.0",
31
31
  "@stoplight/json": "^3.18.1",
32
32
  "@stoplight/mosaic": "^1.53.4",
@@ -36,7 +36,7 @@
36
36
  "file-saver": "^2.0.5",
37
37
  "lodash": "^4.17.21",
38
38
  "react-query": "^3.34.19",
39
- "react-router-dom": "^5.2.0"
39
+ "react-router-dom": "^6.28.0"
40
40
  },
41
41
  "type": "commonjs",
42
42
  "exports": {