@stoplight/elements 7.15.0 → 7.15.2

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.
@@ -2,6 +2,13 @@ import { ExportButtonProps } from '@stoplight/elements-core';
2
2
  import * as React from 'react';
3
3
  import { ServiceNode } from '../../utils/oas/types';
4
4
  declare type TryItCredentialsPolicy = 'omit' | 'include' | 'same-origin';
5
+ interface Location {
6
+ pathname: string;
7
+ search: string;
8
+ hash: string;
9
+ state: unknown;
10
+ key: string;
11
+ }
5
12
  declare type StackedLayoutProps = {
6
13
  serviceNode: ServiceNode;
7
14
  hideTryIt?: boolean;
@@ -9,6 +16,8 @@ declare type StackedLayoutProps = {
9
16
  exportProps?: ExportButtonProps;
10
17
  tryItCredentialsPolicy?: TryItCredentialsPolicy;
11
18
  tryItCorsProxy?: string;
19
+ showPoweredByLink?: boolean;
20
+ location: Location;
12
21
  };
13
22
  export declare const APIWithStackedLayout: React.FC<StackedLayoutProps>;
14
23
  export {};
package/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { APIWithStackedLayout } from './components/API/APIWithStackedLayout';
1
2
  export type { APIProps } from './containers/API';
2
3
  export { API } from './containers/API';
3
4
  export { useExportDocumentProps } from './hooks/useExportDocumentProps';
package/index.esm.js CHANGED
@@ -1,12 +1,12 @@
1
- import { isHttpOperation, isHttpService, Logo, TableOfContents, PoweredByLink, SidebarLayout, ParsedDocs, HttpMethodColors, DeprecatedBadge, TryItWithRequestSamples, Docs, slugify, withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider, useParsedValue, useBundleRefsIntoDocument, NonIdealState, InlineRefResolverProvider } from '@stoplight/elements-core';
2
- import { Flex, Heading, Box, Icon, Tabs, TabList, Tab, TabPanels, TabPanel } from '@stoplight/mosaic';
3
- import flow from 'lodash/flow.js';
1
+ import { isHttpOperation, isHttpService, HttpMethodColors, DeprecatedBadge, ParsedDocs, TryItWithRequestSamples, Docs, Logo, TableOfContents, PoweredByLink, SidebarLayout, slugify, withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider, useParsedValue, useBundleRefsIntoDocument, NonIdealState, InlineRefResolverProvider } from '@stoplight/elements-core';
2
+ import { Box, Flex, Icon, Tabs, TabList, Tab, TabPanels, TabPanel, Heading } from '@stoplight/mosaic';
3
+ import { NodeType } from '@stoplight/types';
4
+ import cn from 'classnames';
4
5
  import * as React from 'react';
6
+ import defaults from 'lodash/defaults.js';
7
+ import flow from 'lodash/flow.js';
5
8
  import { useQuery } from 'react-query';
6
- import { NodeType } from '@stoplight/types';
7
9
  import { useLocation, Redirect, Link } from 'react-router-dom';
8
- import defaults from 'lodash/defaults.js';
9
- import cn from 'classnames';
10
10
  import { safeStringify } from '@stoplight/yaml';
11
11
  import saver from 'file-saver';
12
12
  import { transformOas2Service, transformOas2Operation } from '@stoplight/http-spec/oas2';
@@ -157,59 +157,37 @@ 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, }) => {
161
- const container = React.useRef(null);
162
- const tree = React.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
163
- const location = useLocation();
164
- const { pathname } = location;
165
- const isRootPath = !pathname || pathname === '/';
166
- const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
167
- const layoutOptions = React.useMemo(() => ({ hideTryIt: hideTryIt, hideExport: hideExport || (node === null || node === void 0 ? void 0 : node.type) !== NodeType.HttpService }), [hideTryIt, hideExport, node]);
168
- if (!node) {
169
- const firstSlug = findFirstNodeSlug(tree);
170
- if (firstSlug) {
171
- return React.createElement(Redirect, { to: firstSlug });
172
- }
173
- }
174
- if (hideInternal && node && isInternal(node)) {
175
- return React.createElement(Redirect, { to: "/" });
176
- }
177
- const handleTocClick = () => {
178
- if (container.current) {
179
- container.current.scrollIntoView();
180
- }
181
- };
182
- const sidebar = (React.createElement(React.Fragment, null,
183
- React.createElement(Flex, { ml: 4, mb: 5, alignItems: "center" },
184
- logo ? (React.createElement(Logo, { logo: { url: logo, altText: 'logo' } })) : (serviceNode.data.logo && React.createElement(Logo, { logo: serviceNode.data.logo })),
185
- React.createElement(Heading, { size: 4 }, serviceNode.name)),
186
- React.createElement(Flex, { flexGrow: true, flexShrink: true, overflowY: "auto", direction: "col" },
187
- React.createElement(TableOfContents, { tree: tree, activeId: pathname, Link: Link, onLinkClick: handleTocClick })),
188
- 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 }))));
190
- };
191
-
192
160
  const itemMatchesHash = (hash, item) => {
193
- return hash.substr(1) === `${item.name}-${item.data.method}`;
161
+ return hash.substr(1) === `${item.data.path}-${item.data.method}`;
194
162
  };
195
163
  const TryItContext = React.createContext({
196
164
  hideTryIt: false,
197
165
  tryItCredentialsPolicy: 'omit',
198
166
  });
199
167
  TryItContext.displayName = 'TryItContext';
200
- const APIWithStackedLayout = ({ serviceNode, hideTryIt, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, }) => {
201
- const location = useLocation();
168
+ const LocationContext = React.createContext({
169
+ location: {
170
+ hash: '',
171
+ key: '',
172
+ pathname: '',
173
+ search: '',
174
+ state: '',
175
+ },
176
+ });
177
+ LocationContext.displayName = 'LocationContext';
178
+ const APIWithStackedLayout = ({ serviceNode, hideTryIt, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, showPoweredByLink = true, location, }) => {
202
179
  const { groups } = computeTagGroups(serviceNode);
203
- return (React.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy } },
204
- React.createElement(Flex, { w: "full", flexDirection: "col", m: "auto", className: "sl-max-w-4xl" },
205
- React.createElement(Box, { w: "full", borderB: true },
206
- 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 })),
207
- groups.map(group => (React.createElement(Group, { key: group.title, group: group }))))));
180
+ return (React.createElement(LocationContext.Provider, { value: { location } },
181
+ React.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy } },
182
+ React.createElement(Flex, { w: "full", flexDirection: "col", m: "auto", className: "sl-max-w-4xl" },
183
+ React.createElement(Box, { w: "full", borderB: true },
184
+ React.createElement(Docs, { className: "sl-mx-auto", nodeData: serviceNode.data, nodeTitle: serviceNode.name, nodeType: NodeType.HttpService, location: location, layoutOptions: { showPoweredByLink, hideExport }, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy })),
185
+ groups.map(group => (React.createElement(Group, { key: group.title, group: group })))))));
208
186
  };
209
187
  const Group = React.memo(({ group }) => {
210
188
  const [isExpanded, setIsExpanded] = React.useState(false);
211
- const { hash } = useLocation();
212
189
  const scrollRef = React.useRef(null);
190
+ const { location: { hash }, } = React.useContext(LocationContext);
213
191
  const urlHashMatches = hash.substr(1) === group.title;
214
192
  const onClick = React.useCallback(() => setIsExpanded(!isExpanded), [isExpanded]);
215
193
  const shouldExpand = React.useMemo(() => {
@@ -233,7 +211,7 @@ const Group = React.memo(({ group }) => {
233
211
  }))));
234
212
  });
235
213
  const Item = React.memo(({ item }) => {
236
- const location = useLocation();
214
+ const { location } = React.useContext(LocationContext);
237
215
  const { hash } = location;
238
216
  const [isExpanded, setIsExpanded] = React.useState(false);
239
217
  const scrollRef = React.useRef(null);
@@ -273,6 +251,38 @@ const Collapse = ({ isOpen, children }) => {
273
251
  return React.createElement(Box, null, children);
274
252
  };
275
253
 
254
+ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, }) => {
255
+ const container = React.useRef(null);
256
+ const tree = React.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
257
+ const location = useLocation();
258
+ const { pathname } = location;
259
+ const isRootPath = !pathname || pathname === '/';
260
+ const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
261
+ const layoutOptions = React.useMemo(() => ({ hideTryIt: hideTryIt, hideExport: hideExport || (node === null || node === void 0 ? void 0 : node.type) !== NodeType.HttpService }), [hideTryIt, hideExport, node]);
262
+ if (!node) {
263
+ const firstSlug = findFirstNodeSlug(tree);
264
+ if (firstSlug) {
265
+ return React.createElement(Redirect, { to: firstSlug });
266
+ }
267
+ }
268
+ if (hideInternal && node && isInternal(node)) {
269
+ return React.createElement(Redirect, { to: "/" });
270
+ }
271
+ const handleTocClick = () => {
272
+ if (container.current) {
273
+ container.current.scrollIntoView();
274
+ }
275
+ };
276
+ const sidebar = (React.createElement(React.Fragment, null,
277
+ React.createElement(Flex, { ml: 4, mb: 5, alignItems: "center" },
278
+ logo ? (React.createElement(Logo, { logo: { url: logo, altText: 'logo' } })) : (serviceNode.data.logo && React.createElement(Logo, { logo: serviceNode.data.logo })),
279
+ React.createElement(Heading, { size: 4 }, serviceNode.name)),
280
+ React.createElement(Flex, { flexGrow: true, flexShrink: true, overflowY: "auto", direction: "col" },
281
+ React.createElement(TableOfContents, { tree: tree, activeId: pathname, Link: Link, onLinkClick: handleTocClick })),
282
+ React.createElement(PoweredByLink, { source: serviceNode.name, pathname: pathname, packageType: "elements" })));
283
+ 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 }))));
284
+ };
285
+
276
286
  var NodeTypes;
277
287
  (function (NodeTypes) {
278
288
  NodeTypes["Paths"] = "paths";
@@ -486,6 +496,7 @@ const propsAreWithDocument = (props) => {
486
496
  };
487
497
  const APIImpl = props => {
488
498
  const { layout, apiDescriptionUrl = '', logo, hideTryIt, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, maxRefDepth, } = props;
499
+ const location = useLocation();
489
500
  const apiDescriptionDocument = propsAreWithDocument(props) ? props.apiDescriptionDocument : undefined;
490
501
  const { data: fetchedDocument, error } = useQuery([apiDescriptionUrl], () => fetch(apiDescriptionUrl).then(res => {
491
502
  if (res.ok) {
@@ -512,8 +523,8 @@ const APIImpl = props => {
512
523
  return (React.createElement(Flex, { justify: "center", alignItems: "center", w: "full", minH: "screen" },
513
524
  React.createElement(NonIdealState, { title: "Failed to parse OpenAPI file", description: "Please make sure your OpenAPI file is valid and try again" })));
514
525
  }
515
- return (React.createElement(InlineRefResolverProvider, { document: parsedDocument, maxRefDepth: maxRefDepth }, layout === 'stacked' ? (React.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy })) : (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }))));
526
+ return (React.createElement(InlineRefResolverProvider, { document: parsedDocument, maxRefDepth: maxRefDepth }, layout === 'stacked' ? (React.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, location: location })) : (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }))));
516
527
  };
517
528
  const API = flow(withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider)(APIImpl);
518
529
 
519
- export { API, transformOasToServiceNode, useExportDocumentProps };
530
+ export { API, APIWithStackedLayout, transformOasToServiceNode, useExportDocumentProps };
package/index.js CHANGED
@@ -4,13 +4,13 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var elementsCore = require('@stoplight/elements-core');
6
6
  var mosaic = require('@stoplight/mosaic');
7
- var flow = require('lodash/flow.js');
7
+ var types = require('@stoplight/types');
8
+ var cn = require('classnames');
8
9
  var React = require('react');
10
+ var defaults = require('lodash/defaults.js');
11
+ var flow = require('lodash/flow.js');
9
12
  var reactQuery = require('react-query');
10
- var types = require('@stoplight/types');
11
13
  var reactRouterDom = require('react-router-dom');
12
- var defaults = require('lodash/defaults.js');
13
- var cn = require('classnames');
14
14
  var yaml = require('@stoplight/yaml');
15
15
  var saver = require('file-saver');
16
16
  var oas2 = require('@stoplight/http-spec/oas2');
@@ -40,10 +40,10 @@ function _interopNamespace(e) {
40
40
  return Object.freeze(n);
41
41
  }
42
42
 
43
- var flow__default = /*#__PURE__*/_interopDefaultLegacy(flow);
43
+ var cn__default = /*#__PURE__*/_interopDefaultLegacy(cn);
44
44
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
45
45
  var defaults__default = /*#__PURE__*/_interopDefaultLegacy(defaults);
46
- var cn__default = /*#__PURE__*/_interopDefaultLegacy(cn);
46
+ var flow__default = /*#__PURE__*/_interopDefaultLegacy(flow);
47
47
  var saver__default = /*#__PURE__*/_interopDefaultLegacy(saver);
48
48
  var get__default = /*#__PURE__*/_interopDefaultLegacy(get);
49
49
  var isObject__default = /*#__PURE__*/_interopDefaultLegacy(isObject);
@@ -190,59 +190,37 @@ 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, }) => {
194
- const container = React__namespace.useRef(null);
195
- const tree = React__namespace.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
196
- const location = reactRouterDom.useLocation();
197
- const { pathname } = location;
198
- const isRootPath = !pathname || pathname === '/';
199
- const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
200
- 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
- if (!node) {
202
- const firstSlug = findFirstNodeSlug(tree);
203
- if (firstSlug) {
204
- return React__namespace.createElement(reactRouterDom.Redirect, { to: firstSlug });
205
- }
206
- }
207
- if (hideInternal && node && isInternal(node)) {
208
- return React__namespace.createElement(reactRouterDom.Redirect, { to: "/" });
209
- }
210
- const handleTocClick = () => {
211
- if (container.current) {
212
- container.current.scrollIntoView();
213
- }
214
- };
215
- const sidebar = (React__namespace.createElement(React__namespace.Fragment, null,
216
- React__namespace.createElement(mosaic.Flex, { ml: 4, mb: 5, alignItems: "center" },
217
- logo ? (React__namespace.createElement(elementsCore.Logo, { logo: { url: logo, altText: 'logo' } })) : (serviceNode.data.logo && React__namespace.createElement(elementsCore.Logo, { logo: serviceNode.data.logo })),
218
- React__namespace.createElement(mosaic.Heading, { size: 4 }, serviceNode.name)),
219
- React__namespace.createElement(mosaic.Flex, { flexGrow: true, flexShrink: true, overflowY: "auto", direction: "col" },
220
- React__namespace.createElement(elementsCore.TableOfContents, { tree: tree, activeId: pathname, Link: reactRouterDom.Link, onLinkClick: handleTocClick })),
221
- React__namespace.createElement(elementsCore.PoweredByLink, { source: serviceNode.name, pathname: pathname, packageType: "elements" })));
222
- return (React__namespace.createElement(elementsCore.SidebarLayout, { ref: container, sidebar: sidebar }, node && (React__namespace.createElement(elementsCore.ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }))));
223
- };
224
-
225
193
  const itemMatchesHash = (hash, item) => {
226
- return hash.substr(1) === `${item.name}-${item.data.method}`;
194
+ return hash.substr(1) === `${item.data.path}-${item.data.method}`;
227
195
  };
228
196
  const TryItContext = React__namespace.createContext({
229
197
  hideTryIt: false,
230
198
  tryItCredentialsPolicy: 'omit',
231
199
  });
232
200
  TryItContext.displayName = 'TryItContext';
233
- const APIWithStackedLayout = ({ serviceNode, hideTryIt, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, }) => {
234
- const location = reactRouterDom.useLocation();
201
+ const LocationContext = React__namespace.createContext({
202
+ location: {
203
+ hash: '',
204
+ key: '',
205
+ pathname: '',
206
+ search: '',
207
+ state: '',
208
+ },
209
+ });
210
+ LocationContext.displayName = 'LocationContext';
211
+ const APIWithStackedLayout = ({ serviceNode, hideTryIt, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, showPoweredByLink = true, location, }) => {
235
212
  const { groups } = computeTagGroups(serviceNode);
236
- return (React__namespace.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy } },
237
- React__namespace.createElement(mosaic.Flex, { w: "full", flexDirection: "col", m: "auto", className: "sl-max-w-4xl" },
238
- React__namespace.createElement(mosaic.Box, { w: "full", borderB: true },
239
- React__namespace.createElement(elementsCore.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 })),
240
- groups.map(group => (React__namespace.createElement(Group, { key: group.title, group: group }))))));
213
+ return (React__namespace.createElement(LocationContext.Provider, { value: { location } },
214
+ React__namespace.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy } },
215
+ React__namespace.createElement(mosaic.Flex, { w: "full", flexDirection: "col", m: "auto", className: "sl-max-w-4xl" },
216
+ React__namespace.createElement(mosaic.Box, { w: "full", borderB: true },
217
+ React__namespace.createElement(elementsCore.Docs, { className: "sl-mx-auto", nodeData: serviceNode.data, nodeTitle: serviceNode.name, nodeType: types.NodeType.HttpService, location: location, layoutOptions: { showPoweredByLink, hideExport }, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy })),
218
+ groups.map(group => (React__namespace.createElement(Group, { key: group.title, group: group })))))));
241
219
  };
242
220
  const Group = React__namespace.memo(({ group }) => {
243
221
  const [isExpanded, setIsExpanded] = React__namespace.useState(false);
244
- const { hash } = reactRouterDom.useLocation();
245
222
  const scrollRef = React__namespace.useRef(null);
223
+ const { location: { hash }, } = React__namespace.useContext(LocationContext);
246
224
  const urlHashMatches = hash.substr(1) === group.title;
247
225
  const onClick = React__namespace.useCallback(() => setIsExpanded(!isExpanded), [isExpanded]);
248
226
  const shouldExpand = React__namespace.useMemo(() => {
@@ -266,7 +244,7 @@ const Group = React__namespace.memo(({ group }) => {
266
244
  }))));
267
245
  });
268
246
  const Item = React__namespace.memo(({ item }) => {
269
- const location = reactRouterDom.useLocation();
247
+ const { location } = React__namespace.useContext(LocationContext);
270
248
  const { hash } = location;
271
249
  const [isExpanded, setIsExpanded] = React__namespace.useState(false);
272
250
  const scrollRef = React__namespace.useRef(null);
@@ -306,6 +284,38 @@ const Collapse = ({ isOpen, children }) => {
306
284
  return React__namespace.createElement(mosaic.Box, null, children);
307
285
  };
308
286
 
287
+ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, }) => {
288
+ const container = React__namespace.useRef(null);
289
+ const tree = React__namespace.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
290
+ const location = reactRouterDom.useLocation();
291
+ const { pathname } = location;
292
+ const isRootPath = !pathname || pathname === '/';
293
+ const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
294
+ const layoutOptions = React__namespace.useMemo(() => ({ hideTryIt: hideTryIt, hideExport: hideExport || (node === null || node === void 0 ? void 0 : node.type) !== types.NodeType.HttpService }), [hideTryIt, hideExport, node]);
295
+ if (!node) {
296
+ const firstSlug = findFirstNodeSlug(tree);
297
+ if (firstSlug) {
298
+ return React__namespace.createElement(reactRouterDom.Redirect, { to: firstSlug });
299
+ }
300
+ }
301
+ if (hideInternal && node && isInternal(node)) {
302
+ return React__namespace.createElement(reactRouterDom.Redirect, { to: "/" });
303
+ }
304
+ const handleTocClick = () => {
305
+ if (container.current) {
306
+ container.current.scrollIntoView();
307
+ }
308
+ };
309
+ const sidebar = (React__namespace.createElement(React__namespace.Fragment, null,
310
+ React__namespace.createElement(mosaic.Flex, { ml: 4, mb: 5, alignItems: "center" },
311
+ logo ? (React__namespace.createElement(elementsCore.Logo, { logo: { url: logo, altText: 'logo' } })) : (serviceNode.data.logo && React__namespace.createElement(elementsCore.Logo, { logo: serviceNode.data.logo })),
312
+ React__namespace.createElement(mosaic.Heading, { size: 4 }, serviceNode.name)),
313
+ React__namespace.createElement(mosaic.Flex, { flexGrow: true, flexShrink: true, overflowY: "auto", direction: "col" },
314
+ React__namespace.createElement(elementsCore.TableOfContents, { tree: tree, activeId: pathname, Link: reactRouterDom.Link, onLinkClick: handleTocClick })),
315
+ React__namespace.createElement(elementsCore.PoweredByLink, { source: serviceNode.name, pathname: pathname, packageType: "elements" })));
316
+ return (React__namespace.createElement(elementsCore.SidebarLayout, { ref: container, sidebar: sidebar }, node && (React__namespace.createElement(elementsCore.ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }))));
317
+ };
318
+
309
319
  var NodeTypes;
310
320
  (function (NodeTypes) {
311
321
  NodeTypes["Paths"] = "paths";
@@ -519,6 +529,7 @@ const propsAreWithDocument = (props) => {
519
529
  };
520
530
  const APIImpl = props => {
521
531
  const { layout, apiDescriptionUrl = '', logo, hideTryIt, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, maxRefDepth, } = props;
532
+ const location = reactRouterDom.useLocation();
522
533
  const apiDescriptionDocument = propsAreWithDocument(props) ? props.apiDescriptionDocument : undefined;
523
534
  const { data: fetchedDocument, error } = reactQuery.useQuery([apiDescriptionUrl], () => fetch(apiDescriptionUrl).then(res => {
524
535
  if (res.ok) {
@@ -545,10 +556,11 @@ const APIImpl = props => {
545
556
  return (React__namespace.createElement(mosaic.Flex, { justify: "center", alignItems: "center", w: "full", minH: "screen" },
546
557
  React__namespace.createElement(elementsCore.NonIdealState, { title: "Failed to parse OpenAPI file", description: "Please make sure your OpenAPI file is valid and try again" })));
547
558
  }
548
- return (React__namespace.createElement(elementsCore.InlineRefResolverProvider, { document: parsedDocument, maxRefDepth: maxRefDepth }, layout === 'stacked' ? (React__namespace.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy })) : (React__namespace.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }))));
559
+ return (React__namespace.createElement(elementsCore.InlineRefResolverProvider, { document: parsedDocument, maxRefDepth: maxRefDepth }, layout === 'stacked' ? (React__namespace.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, location: location })) : (React__namespace.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }))));
549
560
  };
550
561
  const API = flow__default["default"](elementsCore.withRouter, elementsCore.withStyles, elementsCore.withPersistenceBoundary, elementsCore.withMosaicProvider, elementsCore.withQueryClientProvider)(APIImpl);
551
562
 
552
563
  exports.API = API;
564
+ exports.APIWithStackedLayout = APIWithStackedLayout;
553
565
  exports.transformOasToServiceNode = transformOasToServiceNode;
554
566
  exports.useExportDocumentProps = useExportDocumentProps;
package/index.mjs CHANGED
@@ -1,12 +1,12 @@
1
- import { isHttpOperation, isHttpService, Logo, TableOfContents, PoweredByLink, SidebarLayout, ParsedDocs, HttpMethodColors, DeprecatedBadge, TryItWithRequestSamples, Docs, slugify, withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider, useParsedValue, useBundleRefsIntoDocument, NonIdealState, InlineRefResolverProvider } from '@stoplight/elements-core';
2
- import { Flex, Heading, Box, Icon, Tabs, TabList, Tab, TabPanels, TabPanel } from '@stoplight/mosaic';
3
- import flow from 'lodash/flow.js';
1
+ import { isHttpOperation, isHttpService, HttpMethodColors, DeprecatedBadge, ParsedDocs, TryItWithRequestSamples, Docs, Logo, TableOfContents, PoweredByLink, SidebarLayout, slugify, withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider, useParsedValue, useBundleRefsIntoDocument, NonIdealState, InlineRefResolverProvider } from '@stoplight/elements-core';
2
+ import { Box, Flex, Icon, Tabs, TabList, Tab, TabPanels, TabPanel, Heading } from '@stoplight/mosaic';
3
+ import { NodeType } from '@stoplight/types';
4
+ import cn from 'classnames';
4
5
  import * as React from 'react';
6
+ import defaults from 'lodash/defaults.js';
7
+ import flow from 'lodash/flow.js';
5
8
  import { useQuery } from 'react-query';
6
- import { NodeType } from '@stoplight/types';
7
9
  import { useLocation, Redirect, Link } from 'react-router-dom';
8
- import defaults from 'lodash/defaults.js';
9
- import cn from 'classnames';
10
10
  import { safeStringify } from '@stoplight/yaml';
11
11
  import saver from 'file-saver';
12
12
  import { transformOas2Service, transformOas2Operation } from '@stoplight/http-spec/oas2';
@@ -157,59 +157,37 @@ 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, }) => {
161
- const container = React.useRef(null);
162
- const tree = React.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
163
- const location = useLocation();
164
- const { pathname } = location;
165
- const isRootPath = !pathname || pathname === '/';
166
- const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
167
- const layoutOptions = React.useMemo(() => ({ hideTryIt: hideTryIt, hideExport: hideExport || (node === null || node === void 0 ? void 0 : node.type) !== NodeType.HttpService }), [hideTryIt, hideExport, node]);
168
- if (!node) {
169
- const firstSlug = findFirstNodeSlug(tree);
170
- if (firstSlug) {
171
- return React.createElement(Redirect, { to: firstSlug });
172
- }
173
- }
174
- if (hideInternal && node && isInternal(node)) {
175
- return React.createElement(Redirect, { to: "/" });
176
- }
177
- const handleTocClick = () => {
178
- if (container.current) {
179
- container.current.scrollIntoView();
180
- }
181
- };
182
- const sidebar = (React.createElement(React.Fragment, null,
183
- React.createElement(Flex, { ml: 4, mb: 5, alignItems: "center" },
184
- logo ? (React.createElement(Logo, { logo: { url: logo, altText: 'logo' } })) : (serviceNode.data.logo && React.createElement(Logo, { logo: serviceNode.data.logo })),
185
- React.createElement(Heading, { size: 4 }, serviceNode.name)),
186
- React.createElement(Flex, { flexGrow: true, flexShrink: true, overflowY: "auto", direction: "col" },
187
- React.createElement(TableOfContents, { tree: tree, activeId: pathname, Link: Link, onLinkClick: handleTocClick })),
188
- 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 }))));
190
- };
191
-
192
160
  const itemMatchesHash = (hash, item) => {
193
- return hash.substr(1) === `${item.name}-${item.data.method}`;
161
+ return hash.substr(1) === `${item.data.path}-${item.data.method}`;
194
162
  };
195
163
  const TryItContext = React.createContext({
196
164
  hideTryIt: false,
197
165
  tryItCredentialsPolicy: 'omit',
198
166
  });
199
167
  TryItContext.displayName = 'TryItContext';
200
- const APIWithStackedLayout = ({ serviceNode, hideTryIt, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, }) => {
201
- const location = useLocation();
168
+ const LocationContext = React.createContext({
169
+ location: {
170
+ hash: '',
171
+ key: '',
172
+ pathname: '',
173
+ search: '',
174
+ state: '',
175
+ },
176
+ });
177
+ LocationContext.displayName = 'LocationContext';
178
+ const APIWithStackedLayout = ({ serviceNode, hideTryIt, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, showPoweredByLink = true, location, }) => {
202
179
  const { groups } = computeTagGroups(serviceNode);
203
- return (React.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy } },
204
- React.createElement(Flex, { w: "full", flexDirection: "col", m: "auto", className: "sl-max-w-4xl" },
205
- React.createElement(Box, { w: "full", borderB: true },
206
- 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 })),
207
- groups.map(group => (React.createElement(Group, { key: group.title, group: group }))))));
180
+ return (React.createElement(LocationContext.Provider, { value: { location } },
181
+ React.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy } },
182
+ React.createElement(Flex, { w: "full", flexDirection: "col", m: "auto", className: "sl-max-w-4xl" },
183
+ React.createElement(Box, { w: "full", borderB: true },
184
+ React.createElement(Docs, { className: "sl-mx-auto", nodeData: serviceNode.data, nodeTitle: serviceNode.name, nodeType: NodeType.HttpService, location: location, layoutOptions: { showPoweredByLink, hideExport }, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy })),
185
+ groups.map(group => (React.createElement(Group, { key: group.title, group: group })))))));
208
186
  };
209
187
  const Group = React.memo(({ group }) => {
210
188
  const [isExpanded, setIsExpanded] = React.useState(false);
211
- const { hash } = useLocation();
212
189
  const scrollRef = React.useRef(null);
190
+ const { location: { hash }, } = React.useContext(LocationContext);
213
191
  const urlHashMatches = hash.substr(1) === group.title;
214
192
  const onClick = React.useCallback(() => setIsExpanded(!isExpanded), [isExpanded]);
215
193
  const shouldExpand = React.useMemo(() => {
@@ -233,7 +211,7 @@ const Group = React.memo(({ group }) => {
233
211
  }))));
234
212
  });
235
213
  const Item = React.memo(({ item }) => {
236
- const location = useLocation();
214
+ const { location } = React.useContext(LocationContext);
237
215
  const { hash } = location;
238
216
  const [isExpanded, setIsExpanded] = React.useState(false);
239
217
  const scrollRef = React.useRef(null);
@@ -273,6 +251,38 @@ const Collapse = ({ isOpen, children }) => {
273
251
  return React.createElement(Box, null, children);
274
252
  };
275
253
 
254
+ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, }) => {
255
+ const container = React.useRef(null);
256
+ const tree = React.useMemo(() => computeAPITree(serviceNode, { hideSchemas, hideInternal }), [serviceNode, hideSchemas, hideInternal]);
257
+ const location = useLocation();
258
+ const { pathname } = location;
259
+ const isRootPath = !pathname || pathname === '/';
260
+ const node = isRootPath ? serviceNode : serviceNode.children.find(child => child.uri === pathname);
261
+ const layoutOptions = React.useMemo(() => ({ hideTryIt: hideTryIt, hideExport: hideExport || (node === null || node === void 0 ? void 0 : node.type) !== NodeType.HttpService }), [hideTryIt, hideExport, node]);
262
+ if (!node) {
263
+ const firstSlug = findFirstNodeSlug(tree);
264
+ if (firstSlug) {
265
+ return React.createElement(Redirect, { to: firstSlug });
266
+ }
267
+ }
268
+ if (hideInternal && node && isInternal(node)) {
269
+ return React.createElement(Redirect, { to: "/" });
270
+ }
271
+ const handleTocClick = () => {
272
+ if (container.current) {
273
+ container.current.scrollIntoView();
274
+ }
275
+ };
276
+ const sidebar = (React.createElement(React.Fragment, null,
277
+ React.createElement(Flex, { ml: 4, mb: 5, alignItems: "center" },
278
+ logo ? (React.createElement(Logo, { logo: { url: logo, altText: 'logo' } })) : (serviceNode.data.logo && React.createElement(Logo, { logo: serviceNode.data.logo })),
279
+ React.createElement(Heading, { size: 4 }, serviceNode.name)),
280
+ React.createElement(Flex, { flexGrow: true, flexShrink: true, overflowY: "auto", direction: "col" },
281
+ React.createElement(TableOfContents, { tree: tree, activeId: pathname, Link: Link, onLinkClick: handleTocClick })),
282
+ React.createElement(PoweredByLink, { source: serviceNode.name, pathname: pathname, packageType: "elements" })));
283
+ 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 }))));
284
+ };
285
+
276
286
  var NodeTypes;
277
287
  (function (NodeTypes) {
278
288
  NodeTypes["Paths"] = "paths";
@@ -486,6 +496,7 @@ const propsAreWithDocument = (props) => {
486
496
  };
487
497
  const APIImpl = props => {
488
498
  const { layout, apiDescriptionUrl = '', logo, hideTryIt, hideSchemas, hideInternal, hideExport, tryItCredentialsPolicy, tryItCorsProxy, maxRefDepth, } = props;
499
+ const location = useLocation();
489
500
  const apiDescriptionDocument = propsAreWithDocument(props) ? props.apiDescriptionDocument : undefined;
490
501
  const { data: fetchedDocument, error } = useQuery([apiDescriptionUrl], () => fetch(apiDescriptionUrl).then(res => {
491
502
  if (res.ok) {
@@ -512,8 +523,8 @@ const APIImpl = props => {
512
523
  return (React.createElement(Flex, { justify: "center", alignItems: "center", w: "full", minH: "screen" },
513
524
  React.createElement(NonIdealState, { title: "Failed to parse OpenAPI file", description: "Please make sure your OpenAPI file is valid and try again" })));
514
525
  }
515
- return (React.createElement(InlineRefResolverProvider, { document: parsedDocument, maxRefDepth: maxRefDepth }, layout === 'stacked' ? (React.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy })) : (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }))));
526
+ return (React.createElement(InlineRefResolverProvider, { document: parsedDocument, maxRefDepth: maxRefDepth }, layout === 'stacked' ? (React.createElement(APIWithStackedLayout, { serviceNode: serviceNode, hideTryIt: hideTryIt, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy, location: location })) : (React.createElement(APIWithSidebarLayout, { logo: logo, serviceNode: serviceNode, hideTryIt: hideTryIt, hideSchemas: hideSchemas, hideInternal: hideInternal, hideExport: hideExport, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }))));
516
527
  };
517
528
  const API = flow(withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider)(APIImpl);
518
529
 
519
- export { API, transformOasToServiceNode, useExportDocumentProps };
530
+ export { API, APIWithStackedLayout, transformOasToServiceNode, useExportDocumentProps };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoplight/elements",
3
- "version": "7.15.0",
3
+ "version": "7.15.2",
4
4
  "description": "UI components for composing beautiful developer documentation.",
5
5
  "keywords": [],
6
6
  "main": "./index.js",