@stoplight/elements-dev-portal 2.5.2 → 3.0.1

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.
package/index.esm.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { Menu, FieldButton, Modal, Input, Box, Icon, ListBox, ListBoxItem, Flex, VStack, Heading } from '@stoplight/mosaic';
2
2
  import * as React from 'react';
3
3
  import React__default, { useRef, useEffect, useMemo, useCallback, useState } from 'react';
4
- import { withPersistenceBoundary, withQueryClientProvider, withMosaicProvider, MarkdownComponentsProvider, LinkHeading, MockingProvider, Docs, withStyles, NodeTypeIconDefs, NodeTypeColors, TableOfContents as TableOfContents$1, PoweredByLink, useRouter, RouterTypeContext, findFirstNode, ReactRouterMarkdownLink, SidebarLayout } from '@stoplight/elements-core';
4
+ import { withPersistenceBoundary, withQueryClientProvider, withMosaicProvider, MarkdownComponentsProvider, LinkHeading, MockingProvider, Docs, RouterTypeContext, withStyles, NodeTypeIconDefs, NodeTypeColors, TableOfContents as TableOfContents$1, PoweredByLink, useRouter, findFirstNode, SidebarLayout, ScrollToHashElement, ReactRouterMarkdownLink } from '@stoplight/elements-core';
5
5
  import { resolve, dirname } from '@stoplight/path';
6
6
  import { NodeType } from '@stoplight/types';
7
+ import { useLocation, useInRouterContext, Routes, Route, useParams, useNavigate, Navigate, Link, Outlet, useOutletContext } from 'react-router-dom';
7
8
  import flow from 'lodash/flow.js';
8
- import { Switch, Route, useParams, useHistory, Redirect, Link } from 'react-router-dom';
9
9
  import { useQuery } from 'react-query';
10
10
 
11
11
  const BranchSelector = ({ branchSlug, branches, onChange }) => {
@@ -125,6 +125,9 @@ const NodeLinkContext = React.createContext(undefined);
125
125
  const externalRegex = new RegExp('^(?:[a-z]+:)?//', 'i');
126
126
  const LinkComponent = ({ children, href, title }) => {
127
127
  const ctx = React.useContext(NodeLinkContext);
128
+ const routerKind = React.useContext(RouterTypeContext);
129
+ const { pathname } = useLocation();
130
+ const route = pathname.split('#')[0];
128
131
  try {
129
132
  if (href && externalRegex.test(href)) {
130
133
  const baseURL = window.location.host;
@@ -152,15 +155,18 @@ const LinkComponent = ({ children, href, title }) => {
152
155
  const [resolvedUriWithoutAnchor, hash] = resolvedUri.split('#');
153
156
  const decodedUrl = decodeURIComponent(href);
154
157
  const decodedResolvedUriWithoutAnchor = decodeURIComponent(resolvedUriWithoutAnchor);
155
- const [pagePathWithoutHash] = window.location.pathname.split('#');
156
- const edge = node.outbound_edges.find(edge => edge.uri === decodedUrl ||
157
- edge.uri === decodedResolvedUriWithoutAnchor ||
158
- pagePathWithoutHash === `/${edge.slug}`);
158
+ const [pagePathWithoutHash] = pathname.split('#');
159
+ let edge = node.outbound_edges.find(edge => edge.uri === decodedUrl || edge.uri === decodedResolvedUriWithoutAnchor);
160
+ if (!edge) {
161
+ edge = node.outbound_edges.find(edge => pagePathWithoutHash === `/${edge.slug}`);
162
+ }
159
163
  if (edge) {
160
- return React.createElement(Link, { to: `${edge.slug}${hash ? `#${hash}` : ''}` }, children);
164
+ const slug = routerKind === 'hash' ? `#${route.replace(node.slug, edge.slug)}` : edge.slug;
165
+ return React.createElement(Link, { to: `${slug}${hash ? `#${hash}` : ''}` }, children);
161
166
  }
162
167
  }
163
- return React.createElement("a", { href: href }, children);
168
+ const fullHref = routerKind === 'hash' ? `#${route}${href}` : href;
169
+ return React.createElement("a", { href: fullHref }, children);
164
170
  };
165
171
  function getBundledUrl(url) {
166
172
  if (url === undefined)
@@ -286,7 +292,7 @@ const UpgradeToStarter = () => (React__default.createElement(Flex, { as: "a", hr
286
292
  React__default.createElement(Icon, { icon: ['fas', 'exclamation-triangle'], size: "4x" }),
287
293
  React__default.createElement(Box, { pt: 3 }, "Please upgrade your Stoplight Workspace to the Starter Plan to use Elements Dev Portal in production.")));
288
294
 
289
- const appVersion = '2.5.2';
295
+ const appVersion = '3.0.1';
290
296
 
291
297
  class ResponseError extends Error {
292
298
  constructor(message, responseCode) {
@@ -361,10 +367,10 @@ function useGetTableOfContents({ projectId, branchSlug }) {
361
367
  return useQuery([...devPortalCacheKeys.branchTOC(projectId, branchSlug !== null && branchSlug !== void 0 ? branchSlug : ''), platformUrl, isLoggedIn], () => getTableOfContents({ projectId, branchSlug, platformUrl, platformAuthToken }), { enabled: projectId ? true : false });
362
368
  }
363
369
 
364
- const StoplightProjectImpl = ({ projectId, hideTryIt, hideSecurityInfo, hideServerInfo, hideMocking, hideExport, collapseTableOfContents = false, tryItCredentialsPolicy, tryItCorsProxy, }) => {
370
+ const StoplightProjectImpl = ({ projectId, collapseTableOfContents = false }) => {
365
371
  const { branchSlug: encodedBranchSlug = '', nodeSlug = '' } = useParams();
366
372
  const branchSlug = decodeURIComponent(encodedBranchSlug);
367
- const history = useHistory();
373
+ const navigate = useNavigate();
368
374
  const { data: tableOfContents, isFetched: isTocFetched } = useGetTableOfContents({ projectId, branchSlug });
369
375
  const { data: branches } = useGetBranches({ projectId });
370
376
  const { data: node, isLoading: isLoadingNode, isError, error: nodeError, } = useGetNodeContent({
@@ -376,63 +382,73 @@ const StoplightProjectImpl = ({ projectId, hideTryIt, hideSecurityInfo, hideServ
376
382
  if (!nodeSlug && isTocFetched && (tableOfContents === null || tableOfContents === void 0 ? void 0 : tableOfContents.items)) {
377
383
  const firstNode = findFirstNode(tableOfContents.items);
378
384
  if (firstNode) {
379
- return React.createElement(Redirect, { to: branchSlug ? `/branches/${branchSlug}/${firstNode.slug}` : `/${firstNode.slug}` });
385
+ return React.createElement(Navigate, { to: branchSlug ? `branches/${branchSlug}/${firstNode.slug}` : `${firstNode.slug}`, replace: true });
380
386
  }
381
387
  }
382
- let elem;
388
+ const handleTocClick = () => {
389
+ if (container.current) {
390
+ container.current.scrollIntoView();
391
+ }
392
+ };
393
+ return (React.createElement(SidebarLayout, { ref: container, sidebar: React.createElement(React.Fragment, null,
394
+ branches && branches.items.length > 1 ? (React.createElement(BranchSelector, { branchSlug: branchSlug, branches: branches.items, onChange: branch => {
395
+ const encodedBranchSlug = encodeURIComponent(branch.slug);
396
+ navigate(branch.is_default ? `${nodeSlug}` : `branches/${encodedBranchSlug}/${nodeSlug}`);
397
+ } })) : null,
398
+ tableOfContents ? (React.createElement(TableOfContents, { activeId: (node === null || node === void 0 ? void 0 : node.id) || (nodeSlug === null || nodeSlug === void 0 ? void 0 : nodeSlug.split('-')[0]) || '', tableOfContents: tableOfContents, Link: Link, collapseTableOfContents: collapseTableOfContents, onLinkClick: handleTocClick })) : null) },
399
+ React.createElement(Outlet, { context: [isLoadingNode, isTocFetched, isError, nodeError, node] })));
400
+ };
401
+ const ProjectNode = ({ hideTryIt, hideSecurityInfo, hideServerInfo, hideMocking, hideExport, tryItCredentialsPolicy, tryItCorsProxy, }) => {
402
+ const { branchSlug: encodedBranchSlug = '', nodeSlug = '' } = useParams();
403
+ const branchSlug = decodeURIComponent(encodedBranchSlug);
404
+ const [isLoadingNode, isTocFetched, isError, nodeError, node] = useOutletContext();
383
405
  if (isLoadingNode || !isTocFetched) {
384
- elem = React.createElement(Loading, null);
406
+ return React.createElement(Loading, null);
385
407
  }
386
- else if (isError) {
408
+ if (isError) {
387
409
  if (nodeError instanceof ResponseError) {
388
410
  if (nodeError.code === 402) {
389
- elem = React.createElement(UpgradeToStarter, null);
411
+ return React.createElement(UpgradeToStarter, null);
390
412
  }
391
413
  else if (nodeError.code === 403) {
392
- elem = React.createElement(Forbidden, null);
414
+ return React.createElement(Forbidden, null);
393
415
  }
394
416
  else {
395
- elem = React.createElement(NotFound, null);
417
+ return React.createElement(NotFound, null);
396
418
  }
397
419
  }
398
420
  else {
399
- elem = React.createElement(NotFound, null);
421
+ return React.createElement(NotFound, null);
400
422
  }
401
423
  }
402
- else if (!node) {
403
- elem = React.createElement(NotFound, null);
404
- }
405
- else if ((node === null || node === void 0 ? void 0 : node.slug) && nodeSlug !== node.slug) {
406
- return React.createElement(Redirect, { to: branchSlug ? `/branches/${branchSlug}/${node.slug}` : `/${node.slug}` });
424
+ if (!node) {
425
+ return React.createElement(NotFound, null);
407
426
  }
408
- else {
409
- elem = (React.createElement(NodeContent, { node: node, Link: ReactRouterMarkdownLink, hideTryIt: hideTryIt, hideMocking: hideMocking, hideExport: hideExport, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }));
427
+ if ((node === null || node === void 0 ? void 0 : node.slug) && nodeSlug !== node.slug) {
428
+ return React.createElement(Navigate, { to: branchSlug ? `/branches/${branchSlug}/${node.slug}` : `/${node.slug}`, replace: true });
410
429
  }
411
- const handleTocClick = () => {
412
- if (container.current) {
413
- container.current.scrollIntoView();
414
- }
415
- };
416
- return (React.createElement(SidebarLayout, { ref: container, sidebar: React.createElement(React.Fragment, null,
417
- branches && branches.items.length > 1 ? (React.createElement(BranchSelector, { branchSlug: branchSlug, branches: branches.items, onChange: branch => {
418
- const encodedBranchSlug = encodeURIComponent(branch.slug);
419
- history.push(branch.is_default ? `/${nodeSlug}` : `/branches/${encodedBranchSlug}/${nodeSlug}`);
420
- } })) : null,
421
- tableOfContents ? (React.createElement(TableOfContents, { activeId: (node === null || node === void 0 ? void 0 : node.id) || (nodeSlug === null || nodeSlug === void 0 ? void 0 : nodeSlug.split('-')[0]) || '', tableOfContents: tableOfContents, Link: Link, collapseTableOfContents: collapseTableOfContents, onLinkClick: handleTocClick })) : null) }, elem));
430
+ return (React.createElement(React.Fragment, null,
431
+ React.createElement(ScrollToHashElement, null),
432
+ React.createElement(NodeContent, { node: node, Link: ReactRouterMarkdownLink, hideTryIt: hideTryIt, hideMocking: hideMocking, hideExport: hideExport, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy })));
422
433
  };
423
434
  const StoplightProjectRouter = (_a) => {
424
- var { platformUrl, basePath = '/', staticRouterPath = '', router = 'history' } = _a, props = __rest(_a, ["platformUrl", "basePath", "staticRouterPath", "router"]);
435
+ var { platformUrl, basePath = '/', staticRouterPath = '', router = 'hash' } = _a, props = __rest(_a, ["platformUrl", "basePath", "staticRouterPath", "router"]);
425
436
  const { Router, routerProps } = useRouter(router, basePath, staticRouterPath);
437
+ const outerRouter = useInRouterContext();
438
+ const InternalRoutes = () => (React.createElement(Routes, null,
439
+ React.createElement(Route, { path: "/", element: React.createElement(StoplightProjectImpl, Object.assign({}, props)) },
440
+ React.createElement(Route, { path: "/branches/:branchSlug/:nodeSlug/*", element: React.createElement(ProjectNode, Object.assign({}, props)) }),
441
+ React.createElement(Route, { path: "/:nodeSlug/*", element: React.createElement(ProjectNode, Object.assign({}, props)) }),
442
+ React.createElement(Route, { element: React.createElement(ProjectNode, Object.assign({}, props)) }))));
443
+ if (!outerRouter) {
444
+ return (React.createElement(DevPortalProvider, { platformUrl: platformUrl },
445
+ React.createElement(RouterTypeContext.Provider, { value: router },
446
+ React.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
447
+ React.createElement(InternalRoutes, null)))));
448
+ }
426
449
  return (React.createElement(DevPortalProvider, { platformUrl: platformUrl },
427
450
  React.createElement(RouterTypeContext.Provider, { value: router },
428
- React.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
429
- React.createElement(Switch, null,
430
- React.createElement(Route, { path: "/branches/:branchSlug/:nodeSlug+", exact: true },
431
- React.createElement(StoplightProjectImpl, Object.assign({}, props))),
432
- React.createElement(Route, { path: "/:nodeSlug+", exact: true },
433
- React.createElement(StoplightProjectImpl, Object.assign({}, props))),
434
- React.createElement(Route, { path: "/", exact: true },
435
- React.createElement(StoplightProjectImpl, Object.assign({}, props))))))));
451
+ React.createElement(InternalRoutes, null))));
436
452
  };
437
453
  const StoplightProject = withStyles(StoplightProjectRouter);
438
454
 
package/index.js CHANGED
@@ -5,8 +5,8 @@ var React = require('react');
5
5
  var elementsCore = require('@stoplight/elements-core');
6
6
  var path = require('@stoplight/path');
7
7
  var types = require('@stoplight/types');
8
- var flow = require('lodash/flow.js');
9
8
  var reactRouterDom = require('react-router-dom');
9
+ var flow = require('lodash/flow.js');
10
10
  var reactQuery = require('react-query');
11
11
 
12
12
  function _interopNamespaceDefault(e) {
@@ -145,6 +145,9 @@ const NodeLinkContext = React__namespace.createContext(undefined);
145
145
  const externalRegex = new RegExp('^(?:[a-z]+:)?//', 'i');
146
146
  const LinkComponent = ({ children, href, title }) => {
147
147
  const ctx = React__namespace.useContext(NodeLinkContext);
148
+ const routerKind = React__namespace.useContext(elementsCore.RouterTypeContext);
149
+ const { pathname } = reactRouterDom.useLocation();
150
+ const route = pathname.split('#')[0];
148
151
  try {
149
152
  if (href && externalRegex.test(href)) {
150
153
  const baseURL = window.location.host;
@@ -172,15 +175,18 @@ const LinkComponent = ({ children, href, title }) => {
172
175
  const [resolvedUriWithoutAnchor, hash] = resolvedUri.split('#');
173
176
  const decodedUrl = decodeURIComponent(href);
174
177
  const decodedResolvedUriWithoutAnchor = decodeURIComponent(resolvedUriWithoutAnchor);
175
- const [pagePathWithoutHash] = window.location.pathname.split('#');
176
- const edge = node.outbound_edges.find(edge => edge.uri === decodedUrl ||
177
- edge.uri === decodedResolvedUriWithoutAnchor ||
178
- pagePathWithoutHash === `/${edge.slug}`);
178
+ const [pagePathWithoutHash] = pathname.split('#');
179
+ let edge = node.outbound_edges.find(edge => edge.uri === decodedUrl || edge.uri === decodedResolvedUriWithoutAnchor);
180
+ if (!edge) {
181
+ edge = node.outbound_edges.find(edge => pagePathWithoutHash === `/${edge.slug}`);
182
+ }
179
183
  if (edge) {
180
- return React__namespace.createElement(Link, { to: `${edge.slug}${hash ? `#${hash}` : ''}` }, children);
184
+ const slug = routerKind === 'hash' ? `#${route.replace(node.slug, edge.slug)}` : edge.slug;
185
+ return React__namespace.createElement(Link, { to: `${slug}${hash ? `#${hash}` : ''}` }, children);
181
186
  }
182
187
  }
183
- return React__namespace.createElement("a", { href: href }, children);
188
+ const fullHref = routerKind === 'hash' ? `#${route}${href}` : href;
189
+ return React__namespace.createElement("a", { href: fullHref }, children);
184
190
  };
185
191
  function getBundledUrl(url) {
186
192
  if (url === undefined)
@@ -306,7 +312,7 @@ const UpgradeToStarter = () => (React.createElement(mosaic.Flex, { as: "a", href
306
312
  React.createElement(mosaic.Icon, { icon: ['fas', 'exclamation-triangle'], size: "4x" }),
307
313
  React.createElement(mosaic.Box, { pt: 3 }, "Please upgrade your Stoplight Workspace to the Starter Plan to use Elements Dev Portal in production.")));
308
314
 
309
- const appVersion = '2.5.2';
315
+ const appVersion = '3.0.1';
310
316
 
311
317
  class ResponseError extends Error {
312
318
  constructor(message, responseCode) {
@@ -381,10 +387,10 @@ function useGetTableOfContents({ projectId, branchSlug }) {
381
387
  return reactQuery.useQuery([...devPortalCacheKeys.branchTOC(projectId, branchSlug !== null && branchSlug !== void 0 ? branchSlug : ''), platformUrl, isLoggedIn], () => getTableOfContents({ projectId, branchSlug, platformUrl, platformAuthToken }), { enabled: projectId ? true : false });
382
388
  }
383
389
 
384
- const StoplightProjectImpl = ({ projectId, hideTryIt, hideSecurityInfo, hideServerInfo, hideMocking, hideExport, collapseTableOfContents = false, tryItCredentialsPolicy, tryItCorsProxy, }) => {
390
+ const StoplightProjectImpl = ({ projectId, collapseTableOfContents = false }) => {
385
391
  const { branchSlug: encodedBranchSlug = '', nodeSlug = '' } = reactRouterDom.useParams();
386
392
  const branchSlug = decodeURIComponent(encodedBranchSlug);
387
- const history = reactRouterDom.useHistory();
393
+ const navigate = reactRouterDom.useNavigate();
388
394
  const { data: tableOfContents, isFetched: isTocFetched } = useGetTableOfContents({ projectId, branchSlug });
389
395
  const { data: branches } = useGetBranches({ projectId });
390
396
  const { data: node, isLoading: isLoadingNode, isError, error: nodeError, } = useGetNodeContent({
@@ -396,63 +402,73 @@ const StoplightProjectImpl = ({ projectId, hideTryIt, hideSecurityInfo, hideServ
396
402
  if (!nodeSlug && isTocFetched && (tableOfContents === null || tableOfContents === void 0 ? void 0 : tableOfContents.items)) {
397
403
  const firstNode = elementsCore.findFirstNode(tableOfContents.items);
398
404
  if (firstNode) {
399
- return React__namespace.createElement(reactRouterDom.Redirect, { to: branchSlug ? `/branches/${branchSlug}/${firstNode.slug}` : `/${firstNode.slug}` });
405
+ return React__namespace.createElement(reactRouterDom.Navigate, { to: branchSlug ? `branches/${branchSlug}/${firstNode.slug}` : `${firstNode.slug}`, replace: true });
400
406
  }
401
407
  }
402
- let elem;
408
+ const handleTocClick = () => {
409
+ if (container.current) {
410
+ container.current.scrollIntoView();
411
+ }
412
+ };
413
+ return (React__namespace.createElement(elementsCore.SidebarLayout, { ref: container, sidebar: React__namespace.createElement(React__namespace.Fragment, null,
414
+ branches && branches.items.length > 1 ? (React__namespace.createElement(BranchSelector, { branchSlug: branchSlug, branches: branches.items, onChange: branch => {
415
+ const encodedBranchSlug = encodeURIComponent(branch.slug);
416
+ navigate(branch.is_default ? `${nodeSlug}` : `branches/${encodedBranchSlug}/${nodeSlug}`);
417
+ } })) : null,
418
+ tableOfContents ? (React__namespace.createElement(TableOfContents, { activeId: (node === null || node === void 0 ? void 0 : node.id) || (nodeSlug === null || nodeSlug === void 0 ? void 0 : nodeSlug.split('-')[0]) || '', tableOfContents: tableOfContents, Link: reactRouterDom.Link, collapseTableOfContents: collapseTableOfContents, onLinkClick: handleTocClick })) : null) },
419
+ React__namespace.createElement(reactRouterDom.Outlet, { context: [isLoadingNode, isTocFetched, isError, nodeError, node] })));
420
+ };
421
+ const ProjectNode = ({ hideTryIt, hideSecurityInfo, hideServerInfo, hideMocking, hideExport, tryItCredentialsPolicy, tryItCorsProxy, }) => {
422
+ const { branchSlug: encodedBranchSlug = '', nodeSlug = '' } = reactRouterDom.useParams();
423
+ const branchSlug = decodeURIComponent(encodedBranchSlug);
424
+ const [isLoadingNode, isTocFetched, isError, nodeError, node] = reactRouterDom.useOutletContext();
403
425
  if (isLoadingNode || !isTocFetched) {
404
- elem = React__namespace.createElement(Loading, null);
426
+ return React__namespace.createElement(Loading, null);
405
427
  }
406
- else if (isError) {
428
+ if (isError) {
407
429
  if (nodeError instanceof ResponseError) {
408
430
  if (nodeError.code === 402) {
409
- elem = React__namespace.createElement(UpgradeToStarter, null);
431
+ return React__namespace.createElement(UpgradeToStarter, null);
410
432
  }
411
433
  else if (nodeError.code === 403) {
412
- elem = React__namespace.createElement(Forbidden, null);
434
+ return React__namespace.createElement(Forbidden, null);
413
435
  }
414
436
  else {
415
- elem = React__namespace.createElement(NotFound, null);
437
+ return React__namespace.createElement(NotFound, null);
416
438
  }
417
439
  }
418
440
  else {
419
- elem = React__namespace.createElement(NotFound, null);
441
+ return React__namespace.createElement(NotFound, null);
420
442
  }
421
443
  }
422
- else if (!node) {
423
- elem = React__namespace.createElement(NotFound, null);
444
+ if (!node) {
445
+ return React__namespace.createElement(NotFound, null);
424
446
  }
425
- else if ((node === null || node === void 0 ? void 0 : node.slug) && nodeSlug !== node.slug) {
426
- return React__namespace.createElement(reactRouterDom.Redirect, { to: branchSlug ? `/branches/${branchSlug}/${node.slug}` : `/${node.slug}` });
447
+ if ((node === null || node === void 0 ? void 0 : node.slug) && nodeSlug !== node.slug) {
448
+ return React__namespace.createElement(reactRouterDom.Navigate, { to: branchSlug ? `/branches/${branchSlug}/${node.slug}` : `/${node.slug}`, replace: true });
427
449
  }
428
- else {
429
- elem = (React__namespace.createElement(NodeContent, { node: node, Link: elementsCore.ReactRouterMarkdownLink, hideTryIt: hideTryIt, hideMocking: hideMocking, hideExport: hideExport, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }));
430
- }
431
- const handleTocClick = () => {
432
- if (container.current) {
433
- container.current.scrollIntoView();
434
- }
435
- };
436
- return (React__namespace.createElement(elementsCore.SidebarLayout, { ref: container, sidebar: React__namespace.createElement(React__namespace.Fragment, null,
437
- branches && branches.items.length > 1 ? (React__namespace.createElement(BranchSelector, { branchSlug: branchSlug, branches: branches.items, onChange: branch => {
438
- const encodedBranchSlug = encodeURIComponent(branch.slug);
439
- history.push(branch.is_default ? `/${nodeSlug}` : `/branches/${encodedBranchSlug}/${nodeSlug}`);
440
- } })) : null,
441
- tableOfContents ? (React__namespace.createElement(TableOfContents, { activeId: (node === null || node === void 0 ? void 0 : node.id) || (nodeSlug === null || nodeSlug === void 0 ? void 0 : nodeSlug.split('-')[0]) || '', tableOfContents: tableOfContents, Link: reactRouterDom.Link, collapseTableOfContents: collapseTableOfContents, onLinkClick: handleTocClick })) : null) }, elem));
450
+ return (React__namespace.createElement(React__namespace.Fragment, null,
451
+ React__namespace.createElement(elementsCore.ScrollToHashElement, null),
452
+ React__namespace.createElement(NodeContent, { node: node, Link: elementsCore.ReactRouterMarkdownLink, hideTryIt: hideTryIt, hideMocking: hideMocking, hideExport: hideExport, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy })));
442
453
  };
443
454
  const StoplightProjectRouter = (_a) => {
444
- var { platformUrl, basePath = '/', staticRouterPath = '', router = 'history' } = _a, props = __rest(_a, ["platformUrl", "basePath", "staticRouterPath", "router"]);
455
+ var { platformUrl, basePath = '/', staticRouterPath = '', router = 'hash' } = _a, props = __rest(_a, ["platformUrl", "basePath", "staticRouterPath", "router"]);
445
456
  const { Router, routerProps } = elementsCore.useRouter(router, basePath, staticRouterPath);
457
+ const outerRouter = reactRouterDom.useInRouterContext();
458
+ const InternalRoutes = () => (React__namespace.createElement(reactRouterDom.Routes, null,
459
+ React__namespace.createElement(reactRouterDom.Route, { path: "/", element: React__namespace.createElement(StoplightProjectImpl, Object.assign({}, props)) },
460
+ React__namespace.createElement(reactRouterDom.Route, { path: "/branches/:branchSlug/:nodeSlug/*", element: React__namespace.createElement(ProjectNode, Object.assign({}, props)) }),
461
+ React__namespace.createElement(reactRouterDom.Route, { path: "/:nodeSlug/*", element: React__namespace.createElement(ProjectNode, Object.assign({}, props)) }),
462
+ React__namespace.createElement(reactRouterDom.Route, { element: React__namespace.createElement(ProjectNode, Object.assign({}, props)) }))));
463
+ if (!outerRouter) {
464
+ return (React__namespace.createElement(DevPortalProvider, { platformUrl: platformUrl },
465
+ React__namespace.createElement(elementsCore.RouterTypeContext.Provider, { value: router },
466
+ React__namespace.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
467
+ React__namespace.createElement(InternalRoutes, null)))));
468
+ }
446
469
  return (React__namespace.createElement(DevPortalProvider, { platformUrl: platformUrl },
447
470
  React__namespace.createElement(elementsCore.RouterTypeContext.Provider, { value: router },
448
- React__namespace.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
449
- React__namespace.createElement(reactRouterDom.Switch, null,
450
- React__namespace.createElement(reactRouterDom.Route, { path: "/branches/:branchSlug/:nodeSlug+", exact: true },
451
- React__namespace.createElement(StoplightProjectImpl, Object.assign({}, props))),
452
- React__namespace.createElement(reactRouterDom.Route, { path: "/:nodeSlug+", exact: true },
453
- React__namespace.createElement(StoplightProjectImpl, Object.assign({}, props))),
454
- React__namespace.createElement(reactRouterDom.Route, { path: "/", exact: true },
455
- React__namespace.createElement(StoplightProjectImpl, Object.assign({}, props))))))));
471
+ React__namespace.createElement(InternalRoutes, null))));
456
472
  };
457
473
  const StoplightProject = elementsCore.withStyles(StoplightProjectRouter);
458
474
 
package/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
1
  import { Menu, FieldButton, Modal, Input, Box, Icon, ListBox, ListBoxItem, Flex, VStack, Heading } from '@stoplight/mosaic';
2
2
  import * as React from 'react';
3
3
  import React__default, { useRef, useEffect, useMemo, useCallback, useState } from 'react';
4
- import { withPersistenceBoundary, withQueryClientProvider, withMosaicProvider, MarkdownComponentsProvider, LinkHeading, MockingProvider, Docs, withStyles, NodeTypeIconDefs, NodeTypeColors, TableOfContents as TableOfContents$1, PoweredByLink, useRouter, RouterTypeContext, findFirstNode, ReactRouterMarkdownLink, SidebarLayout } from '@stoplight/elements-core';
4
+ import { withPersistenceBoundary, withQueryClientProvider, withMosaicProvider, MarkdownComponentsProvider, LinkHeading, MockingProvider, Docs, RouterTypeContext, withStyles, NodeTypeIconDefs, NodeTypeColors, TableOfContents as TableOfContents$1, PoweredByLink, useRouter, findFirstNode, SidebarLayout, ScrollToHashElement, ReactRouterMarkdownLink } from '@stoplight/elements-core';
5
5
  import { resolve, dirname } from '@stoplight/path';
6
6
  import { NodeType } from '@stoplight/types';
7
+ import { useLocation, useInRouterContext, Routes, Route, useParams, useNavigate, Navigate, Link, Outlet, useOutletContext } from 'react-router-dom';
7
8
  import flow from 'lodash/flow.js';
8
- import { Switch, Route, useParams, useHistory, Redirect, Link } from 'react-router-dom';
9
9
  import { useQuery } from 'react-query';
10
10
 
11
11
  const BranchSelector = ({ branchSlug, branches, onChange }) => {
@@ -125,6 +125,9 @@ const NodeLinkContext = React.createContext(undefined);
125
125
  const externalRegex = new RegExp('^(?:[a-z]+:)?//', 'i');
126
126
  const LinkComponent = ({ children, href, title }) => {
127
127
  const ctx = React.useContext(NodeLinkContext);
128
+ const routerKind = React.useContext(RouterTypeContext);
129
+ const { pathname } = useLocation();
130
+ const route = pathname.split('#')[0];
128
131
  try {
129
132
  if (href && externalRegex.test(href)) {
130
133
  const baseURL = window.location.host;
@@ -152,15 +155,18 @@ const LinkComponent = ({ children, href, title }) => {
152
155
  const [resolvedUriWithoutAnchor, hash] = resolvedUri.split('#');
153
156
  const decodedUrl = decodeURIComponent(href);
154
157
  const decodedResolvedUriWithoutAnchor = decodeURIComponent(resolvedUriWithoutAnchor);
155
- const [pagePathWithoutHash] = window.location.pathname.split('#');
156
- const edge = node.outbound_edges.find(edge => edge.uri === decodedUrl ||
157
- edge.uri === decodedResolvedUriWithoutAnchor ||
158
- pagePathWithoutHash === `/${edge.slug}`);
158
+ const [pagePathWithoutHash] = pathname.split('#');
159
+ let edge = node.outbound_edges.find(edge => edge.uri === decodedUrl || edge.uri === decodedResolvedUriWithoutAnchor);
160
+ if (!edge) {
161
+ edge = node.outbound_edges.find(edge => pagePathWithoutHash === `/${edge.slug}`);
162
+ }
159
163
  if (edge) {
160
- return React.createElement(Link, { to: `${edge.slug}${hash ? `#${hash}` : ''}` }, children);
164
+ const slug = routerKind === 'hash' ? `#${route.replace(node.slug, edge.slug)}` : edge.slug;
165
+ return React.createElement(Link, { to: `${slug}${hash ? `#${hash}` : ''}` }, children);
161
166
  }
162
167
  }
163
- return React.createElement("a", { href: href }, children);
168
+ const fullHref = routerKind === 'hash' ? `#${route}${href}` : href;
169
+ return React.createElement("a", { href: fullHref }, children);
164
170
  };
165
171
  function getBundledUrl(url) {
166
172
  if (url === undefined)
@@ -286,7 +292,7 @@ const UpgradeToStarter = () => (React__default.createElement(Flex, { as: "a", hr
286
292
  React__default.createElement(Icon, { icon: ['fas', 'exclamation-triangle'], size: "4x" }),
287
293
  React__default.createElement(Box, { pt: 3 }, "Please upgrade your Stoplight Workspace to the Starter Plan to use Elements Dev Portal in production.")));
288
294
 
289
- const appVersion = '2.5.2';
295
+ const appVersion = '3.0.1';
290
296
 
291
297
  class ResponseError extends Error {
292
298
  constructor(message, responseCode) {
@@ -361,10 +367,10 @@ function useGetTableOfContents({ projectId, branchSlug }) {
361
367
  return useQuery([...devPortalCacheKeys.branchTOC(projectId, branchSlug !== null && branchSlug !== void 0 ? branchSlug : ''), platformUrl, isLoggedIn], () => getTableOfContents({ projectId, branchSlug, platformUrl, platformAuthToken }), { enabled: projectId ? true : false });
362
368
  }
363
369
 
364
- const StoplightProjectImpl = ({ projectId, hideTryIt, hideSecurityInfo, hideServerInfo, hideMocking, hideExport, collapseTableOfContents = false, tryItCredentialsPolicy, tryItCorsProxy, }) => {
370
+ const StoplightProjectImpl = ({ projectId, collapseTableOfContents = false }) => {
365
371
  const { branchSlug: encodedBranchSlug = '', nodeSlug = '' } = useParams();
366
372
  const branchSlug = decodeURIComponent(encodedBranchSlug);
367
- const history = useHistory();
373
+ const navigate = useNavigate();
368
374
  const { data: tableOfContents, isFetched: isTocFetched } = useGetTableOfContents({ projectId, branchSlug });
369
375
  const { data: branches } = useGetBranches({ projectId });
370
376
  const { data: node, isLoading: isLoadingNode, isError, error: nodeError, } = useGetNodeContent({
@@ -376,63 +382,73 @@ const StoplightProjectImpl = ({ projectId, hideTryIt, hideSecurityInfo, hideServ
376
382
  if (!nodeSlug && isTocFetched && (tableOfContents === null || tableOfContents === void 0 ? void 0 : tableOfContents.items)) {
377
383
  const firstNode = findFirstNode(tableOfContents.items);
378
384
  if (firstNode) {
379
- return React.createElement(Redirect, { to: branchSlug ? `/branches/${branchSlug}/${firstNode.slug}` : `/${firstNode.slug}` });
385
+ return React.createElement(Navigate, { to: branchSlug ? `branches/${branchSlug}/${firstNode.slug}` : `${firstNode.slug}`, replace: true });
380
386
  }
381
387
  }
382
- let elem;
388
+ const handleTocClick = () => {
389
+ if (container.current) {
390
+ container.current.scrollIntoView();
391
+ }
392
+ };
393
+ return (React.createElement(SidebarLayout, { ref: container, sidebar: React.createElement(React.Fragment, null,
394
+ branches && branches.items.length > 1 ? (React.createElement(BranchSelector, { branchSlug: branchSlug, branches: branches.items, onChange: branch => {
395
+ const encodedBranchSlug = encodeURIComponent(branch.slug);
396
+ navigate(branch.is_default ? `${nodeSlug}` : `branches/${encodedBranchSlug}/${nodeSlug}`);
397
+ } })) : null,
398
+ tableOfContents ? (React.createElement(TableOfContents, { activeId: (node === null || node === void 0 ? void 0 : node.id) || (nodeSlug === null || nodeSlug === void 0 ? void 0 : nodeSlug.split('-')[0]) || '', tableOfContents: tableOfContents, Link: Link, collapseTableOfContents: collapseTableOfContents, onLinkClick: handleTocClick })) : null) },
399
+ React.createElement(Outlet, { context: [isLoadingNode, isTocFetched, isError, nodeError, node] })));
400
+ };
401
+ const ProjectNode = ({ hideTryIt, hideSecurityInfo, hideServerInfo, hideMocking, hideExport, tryItCredentialsPolicy, tryItCorsProxy, }) => {
402
+ const { branchSlug: encodedBranchSlug = '', nodeSlug = '' } = useParams();
403
+ const branchSlug = decodeURIComponent(encodedBranchSlug);
404
+ const [isLoadingNode, isTocFetched, isError, nodeError, node] = useOutletContext();
383
405
  if (isLoadingNode || !isTocFetched) {
384
- elem = React.createElement(Loading, null);
406
+ return React.createElement(Loading, null);
385
407
  }
386
- else if (isError) {
408
+ if (isError) {
387
409
  if (nodeError instanceof ResponseError) {
388
410
  if (nodeError.code === 402) {
389
- elem = React.createElement(UpgradeToStarter, null);
411
+ return React.createElement(UpgradeToStarter, null);
390
412
  }
391
413
  else if (nodeError.code === 403) {
392
- elem = React.createElement(Forbidden, null);
414
+ return React.createElement(Forbidden, null);
393
415
  }
394
416
  else {
395
- elem = React.createElement(NotFound, null);
417
+ return React.createElement(NotFound, null);
396
418
  }
397
419
  }
398
420
  else {
399
- elem = React.createElement(NotFound, null);
421
+ return React.createElement(NotFound, null);
400
422
  }
401
423
  }
402
- else if (!node) {
403
- elem = React.createElement(NotFound, null);
404
- }
405
- else if ((node === null || node === void 0 ? void 0 : node.slug) && nodeSlug !== node.slug) {
406
- return React.createElement(Redirect, { to: branchSlug ? `/branches/${branchSlug}/${node.slug}` : `/${node.slug}` });
424
+ if (!node) {
425
+ return React.createElement(NotFound, null);
407
426
  }
408
- else {
409
- elem = (React.createElement(NodeContent, { node: node, Link: ReactRouterMarkdownLink, hideTryIt: hideTryIt, hideMocking: hideMocking, hideExport: hideExport, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }));
427
+ if ((node === null || node === void 0 ? void 0 : node.slug) && nodeSlug !== node.slug) {
428
+ return React.createElement(Navigate, { to: branchSlug ? `/branches/${branchSlug}/${node.slug}` : `/${node.slug}`, replace: true });
410
429
  }
411
- const handleTocClick = () => {
412
- if (container.current) {
413
- container.current.scrollIntoView();
414
- }
415
- };
416
- return (React.createElement(SidebarLayout, { ref: container, sidebar: React.createElement(React.Fragment, null,
417
- branches && branches.items.length > 1 ? (React.createElement(BranchSelector, { branchSlug: branchSlug, branches: branches.items, onChange: branch => {
418
- const encodedBranchSlug = encodeURIComponent(branch.slug);
419
- history.push(branch.is_default ? `/${nodeSlug}` : `/branches/${encodedBranchSlug}/${nodeSlug}`);
420
- } })) : null,
421
- tableOfContents ? (React.createElement(TableOfContents, { activeId: (node === null || node === void 0 ? void 0 : node.id) || (nodeSlug === null || nodeSlug === void 0 ? void 0 : nodeSlug.split('-')[0]) || '', tableOfContents: tableOfContents, Link: Link, collapseTableOfContents: collapseTableOfContents, onLinkClick: handleTocClick })) : null) }, elem));
430
+ return (React.createElement(React.Fragment, null,
431
+ React.createElement(ScrollToHashElement, null),
432
+ React.createElement(NodeContent, { node: node, Link: ReactRouterMarkdownLink, hideTryIt: hideTryIt, hideMocking: hideMocking, hideExport: hideExport, hideSecurityInfo: hideSecurityInfo, hideServerInfo: hideServerInfo, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy })));
422
433
  };
423
434
  const StoplightProjectRouter = (_a) => {
424
- var { platformUrl, basePath = '/', staticRouterPath = '', router = 'history' } = _a, props = __rest(_a, ["platformUrl", "basePath", "staticRouterPath", "router"]);
435
+ var { platformUrl, basePath = '/', staticRouterPath = '', router = 'hash' } = _a, props = __rest(_a, ["platformUrl", "basePath", "staticRouterPath", "router"]);
425
436
  const { Router, routerProps } = useRouter(router, basePath, staticRouterPath);
437
+ const outerRouter = useInRouterContext();
438
+ const InternalRoutes = () => (React.createElement(Routes, null,
439
+ React.createElement(Route, { path: "/", element: React.createElement(StoplightProjectImpl, Object.assign({}, props)) },
440
+ React.createElement(Route, { path: "/branches/:branchSlug/:nodeSlug/*", element: React.createElement(ProjectNode, Object.assign({}, props)) }),
441
+ React.createElement(Route, { path: "/:nodeSlug/*", element: React.createElement(ProjectNode, Object.assign({}, props)) }),
442
+ React.createElement(Route, { element: React.createElement(ProjectNode, Object.assign({}, props)) }))));
443
+ if (!outerRouter) {
444
+ return (React.createElement(DevPortalProvider, { platformUrl: platformUrl },
445
+ React.createElement(RouterTypeContext.Provider, { value: router },
446
+ React.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
447
+ React.createElement(InternalRoutes, null)))));
448
+ }
426
449
  return (React.createElement(DevPortalProvider, { platformUrl: platformUrl },
427
450
  React.createElement(RouterTypeContext.Provider, { value: router },
428
- React.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
429
- React.createElement(Switch, null,
430
- React.createElement(Route, { path: "/branches/:branchSlug/:nodeSlug+", exact: true },
431
- React.createElement(StoplightProjectImpl, Object.assign({}, props))),
432
- React.createElement(Route, { path: "/:nodeSlug+", exact: true },
433
- React.createElement(StoplightProjectImpl, Object.assign({}, props))),
434
- React.createElement(Route, { path: "/", exact: true },
435
- React.createElement(StoplightProjectImpl, Object.assign({}, props))))))));
451
+ React.createElement(InternalRoutes, null))));
436
452
  };
437
453
  const StoplightProject = withStyles(StoplightProjectRouter);
438
454
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoplight/elements-dev-portal",
3
- "version": "2.5.2",
3
+ "version": "3.0.1",
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.2",
29
+ "@stoplight/elements-core": "~9.0.1",
30
30
  "@stoplight/markdown-viewer": "^5.7.1",
31
31
  "@stoplight/mosaic": "^1.53.4",
32
32
  "@stoplight/path": "^1.3.2",
@@ -34,7 +34,7 @@
34
34
  "classnames": "^2.2.6",
35
35
  "lodash": "^4.17.21",
36
36
  "react-query": "^3.34.19",
37
- "react-router-dom": "^5.2.0",
37
+ "react-router-dom": "^6.28.0",
38
38
  "use-debounce": "^6.0.1"
39
39
  },
40
40
  "type": "commonjs",
package/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const appVersion = "2.5.2";
1
+ export declare const appVersion = "3.0.1";