@stoplight/elements-core 9.0.12 → 9.0.13-alpha.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.
@@ -21,6 +21,7 @@ export declare type TableOfContentsGroup = {
21
21
  title: string;
22
22
  items: TableOfContentsGroupItem[];
23
23
  itemsType?: 'article' | 'http_operation' | 'http_webhook' | 'model';
24
+ index: string;
24
25
  };
25
26
  export declare type TableOfContentsExternalLink = {
26
27
  title: string;
@@ -33,5 +34,11 @@ export declare type TableOfContentsNode<T = 'http_service' | 'http_operation' |
33
34
  type: T;
34
35
  meta: string;
35
36
  version?: string;
37
+ index: string;
36
38
  };
37
39
  export declare type TableOfContentsNodeGroup = TableOfContentsNode<'http_service'> & TableOfContentsGroup;
40
+ export declare type ActiveItemContextType = {
41
+ activeId: string | undefined;
42
+ lastActiveIndex: string;
43
+ setLastActiveIndex: React.Dispatch<React.SetStateAction<string>>;
44
+ };
@@ -4,12 +4,10 @@ import { JSONSchema7, JSONSchema7Definition } from 'json-schema';
4
4
  export declare type ParameterSpec = Pick<IHttpParam, 'name' | 'schema' | 'required'> & {
5
5
  examples?: (Omit<INodeExample, 'id'> | Omit<INodeExternalExample, 'id'>)[];
6
6
  };
7
- export declare function parameterOptions(parameter: ParameterSpec): ({
7
+ export declare function parameterOptions(parameter: ParameterSpec): {
8
8
  value: string | number;
9
- } | {
10
9
  label: string;
11
- value: string;
12
- })[] | null;
10
+ }[] | null;
13
11
  export declare const selectExampleOption: {
14
12
  value: string;
15
13
  label: string;
package/index.esm.js CHANGED
@@ -1341,7 +1341,11 @@ const booleanOptions = [
1341
1341
  { label: 'True', value: 'true' },
1342
1342
  ];
1343
1343
  function enumOptions(enumValues, required) {
1344
- const options = map(enumValues, v => ({ value: typeof v === 'number' ? v : String(v) }));
1344
+ const options = map(enumValues, v => {
1345
+ var _a;
1346
+ const value = typeof v === 'object' && v !== null ? (_a = safeStringify(v)) !== null && _a !== void 0 ? _a : String(v) : typeof v === 'number' ? v : String(v);
1347
+ return { value, label: String(value) };
1348
+ });
1345
1349
  return required ? options : [{ label: 'Not Set', value: '' }, ...options];
1346
1350
  }
1347
1351
  function parameterOptions(parameter) {
@@ -1371,15 +1375,16 @@ function parameterSupportsFileUpload(parameter) {
1371
1375
  ((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
1372
1376
  }
1373
1377
  function stringifyValue(value) {
1374
- return typeof value === 'object' ? JSON.stringify(value) : escapeQuotes(String(value));
1378
+ var _a;
1379
+ if (typeof value === 'object' && value !== null) {
1380
+ return (_a = safeStringify(value)) !== null && _a !== void 0 ? _a : String(value);
1381
+ }
1382
+ return String(value);
1375
1383
  }
1376
1384
  function exampleValue(example) {
1377
1385
  const value = 'value' in example ? example.value : example.externalValue;
1378
1386
  return stringifyValue(value);
1379
1387
  }
1380
- function escapeQuotes(value) {
1381
- return value.replace(/"/g, '\\"');
1382
- }
1383
1388
  function getPlaceholderForParameter(parameter) {
1384
1389
  var _a, _b;
1385
1390
  const { value: parameterValue, isDefault } = getValueForParameter(parameter);
@@ -1405,14 +1410,14 @@ const getValueForParameter = (parameter) => {
1405
1410
  if (typeof defaultValue !== 'undefined') {
1406
1411
  return { value: stringifyValue(defaultValue), isDefault: true };
1407
1412
  }
1408
- const examples = (_a = parameter.examples) !== null && _a !== void 0 ? _a : [];
1409
- if (examples.length > 0) {
1410
- return { value: exampleValue(examples[0]) };
1411
- }
1412
- const enums = (_c = (_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.enum) !== null && _c !== void 0 ? _c : [];
1413
+ const enums = (_b = (_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.enum) !== null && _b !== void 0 ? _b : [];
1413
1414
  if (enums.length > 0) {
1414
1415
  return { value: stringifyValue(enums[0]) };
1415
1416
  }
1417
+ const examples = (_c = parameter.examples) !== null && _c !== void 0 ? _c : [];
1418
+ if (examples.length > 0) {
1419
+ return { value: exampleValue(examples[0]) };
1420
+ }
1416
1421
  return { value: '' };
1417
1422
  };
1418
1423
  const getInitialValueForParameter = (parameter) => {
@@ -2330,7 +2335,7 @@ const VariableEditor = ({ variable, value, onChange }) => {
2330
2335
  return (React.createElement(React.Fragment, null,
2331
2336
  React.createElement(Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, variable.name),
2332
2337
  React.createElement(Text, { mx: 3 }, ":"),
2333
- React.createElement("div", null, variable.enum ? (React.createElement(Select, { flex: 1, "aria-label": variable.name, options: variable.enum.map(s => ({ value: s })), value: value || variable.default, onChange: onChange })) : (React.createElement(Flex, { flex: 1 },
2338
+ React.createElement("div", null, variable.enum ? (React.createElement(Select, { flex: 1, "aria-label": variable.name, options: variable.enum.map(s => ({ value: s, label: String(s) })), value: value || variable.default, onChange: onChange })) : (React.createElement(Flex, { flex: 1 },
2334
2339
  React.createElement(Input, { id: inputId, "aria-label": variable.name, appearance: 'minimal', flex: 1, placeholder: variable.default, type: "text", required: true, intent: 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }))))));
2335
2340
  };
2336
2341
 
@@ -3496,7 +3501,7 @@ function findFirstNode(items) {
3496
3501
  return;
3497
3502
  }
3498
3503
  function isDivider(item) {
3499
- return Object.keys(item).length === 1 && 'title' in item;
3504
+ return Object.keys(item).length === 2 && 'title' in item && 'index' in item;
3500
3505
  }
3501
3506
  function isGroup(item) {
3502
3507
  return Object.keys(item).length >= 2 && 'title' in item && 'items' in item;
@@ -3508,13 +3513,33 @@ function isNode(item) {
3508
3513
  return 'title' in item && 'slug' in item && 'id' in item && 'meta' in item && 'type' in item;
3509
3514
  }
3510
3515
  function isExternalLink(item) {
3511
- return Object.keys(item).length === 2 && 'title' in item && 'url' in item;
3516
+ return Object.keys(item).length === 3 && 'title' in item && 'url' in item && 'index' in item;
3512
3517
  }
3513
3518
 
3514
- const ActiveIdContext = React.createContext(undefined);
3519
+ const ActiveItemContext = React.createContext({
3520
+ activeId: undefined,
3521
+ lastActiveIndex: '',
3522
+ setLastActiveIndex: () => { },
3523
+ });
3515
3524
  const LinkContext = React.createContext(undefined);
3516
3525
  LinkContext.displayName = 'LinkContext';
3517
3526
  const TableOfContents = React.memo(({ tree, activeId, Link, maxDepthOpenByDefault, externalScrollbar = false, isInResponsiveMode = false, onLinkClick, }) => {
3527
+ const [lastActiveIndex, setLastActiveIndex] = useState('');
3528
+ const value = React.useMemo(() => ({
3529
+ lastActiveIndex,
3530
+ setLastActiveIndex,
3531
+ activeId,
3532
+ }), [lastActiveIndex, activeId]);
3533
+ const updateTocTree = React.useCallback((arr, parentId) => {
3534
+ return arr.map((item, key) => {
3535
+ let newItem = Object.assign(Object.assign({}, item), { index: parentId + key + '-' });
3536
+ if (isGroup(item) || isNodeGroup(item)) {
3537
+ newItem.items = updateTocTree(item.items, parentId + key + '-');
3538
+ }
3539
+ return newItem;
3540
+ });
3541
+ }, []);
3542
+ const updatedTree = updateTocTree(tree, '');
3518
3543
  const container = React.useRef(null);
3519
3544
  const child = React.useRef(null);
3520
3545
  const firstRender = useFirstRender();
@@ -3534,18 +3559,30 @@ const TableOfContents = React.memo(({ tree, activeId, Link, maxDepthOpenByDefaul
3534
3559
  return (React.createElement(Box, { ref: container, w: "full", bg: isInResponsiveMode ? 'canvas' : 'canvas-100', overflowY: "auto" },
3535
3560
  React.createElement(Box, { ref: child, my: 3 },
3536
3561
  React.createElement(LinkContext.Provider, { value: Link },
3537
- React.createElement(ActiveIdContext.Provider, { value: activeId }, tree.map((item, key) => {
3538
- if (isDivider(item)) {
3539
- return React.createElement(Divider, { key: key, item: item, isInResponsiveMode: isInResponsiveMode });
3540
- }
3541
- return (React.createElement(GroupItem, { key: key, item: item, depth: 0, maxDepthOpenByDefault: maxDepthOpenByDefault, onLinkClick: onLinkClick, isInResponsiveMode: isInResponsiveMode }));
3542
- }))))));
3562
+ React.createElement(ActiveItemContext.Provider, { value: value },
3563
+ React.createElement(TOCContainer, { updatedTree: updatedTree }, updatedTree.map((item, key) => {
3564
+ if (isDivider(item)) {
3565
+ return React.createElement(Divider, { key: key, item: item, isInResponsiveMode: isInResponsiveMode });
3566
+ }
3567
+ return (React.createElement(GroupItem, { key: key, item: item, depth: 0, maxDepthOpenByDefault: maxDepthOpenByDefault, onLinkClick: onLinkClick, isInResponsiveMode: isInResponsiveMode }));
3568
+ })))))));
3543
3569
  });
3544
3570
  TableOfContents.displayName = 'TableOfContents';
3545
3571
  const Divider = React.memo(({ item, isInResponsiveMode = false }) => {
3546
3572
  return (React.createElement(Box, { pl: 4, mb: 2, mt: 6, textTransform: "uppercase", fontSize: isInResponsiveMode ? 'lg' : 'sm', lineHeight: "relaxed", letterSpacing: "wide", fontWeight: "bold" }, item.title));
3547
3573
  });
3548
3574
  Divider.displayName = 'Divider';
3575
+ const TOCContainer = React.memo(({ children, updatedTree }) => {
3576
+ const { setLastActiveIndex } = React.useContext(ActiveItemContext);
3577
+ React.useEffect(() => {
3578
+ const firstNode = findFirstNode(updatedTree);
3579
+ if (firstNode) {
3580
+ setLastActiveIndex(firstNode.index);
3581
+ }
3582
+ }, []);
3583
+ return React.createElement(Box, null, children);
3584
+ });
3585
+ TOCContainer.displayName = 'TOCContainer';
3549
3586
  const GroupItem = React.memo(({ item, depth, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick }) => {
3550
3587
  if (isExternalLink(item)) {
3551
3588
  return (React.createElement(Box, { as: "a", href: item.url, target: "_blank", rel: "noopener noreferrer", display: "block" },
@@ -3563,9 +3600,24 @@ const GroupItem = React.memo(({ item, depth, maxDepthOpenByDefault, isInResponsi
3563
3600
  });
3564
3601
  GroupItem.displayName = 'GroupItem';
3565
3602
  const Group = React.memo(({ depth, item, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick = () => { } }) => {
3566
- const activeId = React.useContext(ActiveIdContext);
3603
+ const { activeId, lastActiveIndex } = React.useContext(ActiveItemContext);
3567
3604
  const [isOpen, setIsOpen] = React.useState(() => isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault));
3568
- const hasActive = !!activeId && hasActiveItem(item.items, activeId);
3605
+ const isActiveGroup = React.useCallback((items, activeId, contextIndex) => {
3606
+ return items.some(element => {
3607
+ const hasSlugOrId = 'slug' in element || 'id' in element;
3608
+ const hasItems = 'items' in element && Array.isArray(element.items);
3609
+ if (!hasSlugOrId && !hasItems)
3610
+ return false;
3611
+ if (activeId &&
3612
+ 'index' in element &&
3613
+ (element.slug === activeId || element.id === activeId) &&
3614
+ element.index === contextIndex) {
3615
+ return true;
3616
+ }
3617
+ return hasItems ? isActiveGroup(element.items, activeId, contextIndex) : false;
3618
+ });
3619
+ }, []);
3620
+ const hasActive = isActiveGroup(item.items, activeId, lastActiveIndex);
3569
3621
  React.useEffect(() => {
3570
3622
  const openByDefault = isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault);
3571
3623
  if (isOpen !== openByDefault) {
@@ -3615,8 +3667,10 @@ const Item = React.memo(({ depth, isActive, id, title, meta, icon, isInResponsiv
3615
3667
  });
3616
3668
  Item.displayName = 'Item';
3617
3669
  const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode, onClick, onLinkClick = () => { } }) => {
3618
- const activeId = React.useContext(ActiveIdContext);
3619
- const isActive = activeId === item.slug || activeId === item.id;
3670
+ const { activeId, lastActiveIndex, setLastActiveIndex } = React.useContext(ActiveItemContext);
3671
+ const { index } = item;
3672
+ const isSlugMatched = activeId === item.slug || activeId === item.id;
3673
+ const isActive = lastActiveIndex === index && isSlugMatched;
3620
3674
  const LinkComponent = React.useContext(LinkContext);
3621
3675
  const handleClick = (e) => {
3622
3676
  if (isActive) {
@@ -3624,6 +3678,7 @@ const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode,
3624
3678
  e.preventDefault();
3625
3679
  }
3626
3680
  else {
3681
+ setLastActiveIndex(index);
3627
3682
  onLinkClick();
3628
3683
  }
3629
3684
  if (onClick) {
@@ -3631,7 +3686,7 @@ const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode,
3631
3686
  }
3632
3687
  };
3633
3688
  return (React.createElement(Box, { as: LinkComponent, to: resolveRelativeLink(item.slug), display: "block", textDecoration: "no-underline", className: "ElementsTableOfContentsItem" },
3634
- React.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React.createElement(Box, { as: Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: handleClick })));
3689
+ React.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React.createElement(Box, { as: Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: e => handleClick(e) })));
3635
3690
  });
3636
3691
  Node.displayName = 'Node';
3637
3692
  const Version = ({ value }) => {
package/index.js CHANGED
@@ -1362,7 +1362,11 @@ const booleanOptions = [
1362
1362
  { label: 'True', value: 'true' },
1363
1363
  ];
1364
1364
  function enumOptions(enumValues, required) {
1365
- const options = map(enumValues, v => ({ value: typeof v === 'number' ? v : String(v) }));
1365
+ const options = map(enumValues, v => {
1366
+ var _a;
1367
+ const value = typeof v === 'object' && v !== null ? (_a = json.safeStringify(v)) !== null && _a !== void 0 ? _a : String(v) : typeof v === 'number' ? v : String(v);
1368
+ return { value, label: String(value) };
1369
+ });
1366
1370
  return required ? options : [{ label: 'Not Set', value: '' }, ...options];
1367
1371
  }
1368
1372
  function parameterOptions(parameter) {
@@ -1392,15 +1396,16 @@ function parameterSupportsFileUpload(parameter) {
1392
1396
  ((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
1393
1397
  }
1394
1398
  function stringifyValue(value) {
1395
- return typeof value === 'object' ? JSON.stringify(value) : escapeQuotes(String(value));
1399
+ var _a;
1400
+ if (typeof value === 'object' && value !== null) {
1401
+ return (_a = json.safeStringify(value)) !== null && _a !== void 0 ? _a : String(value);
1402
+ }
1403
+ return String(value);
1396
1404
  }
1397
1405
  function exampleValue(example) {
1398
1406
  const value = 'value' in example ? example.value : example.externalValue;
1399
1407
  return stringifyValue(value);
1400
1408
  }
1401
- function escapeQuotes(value) {
1402
- return value.replace(/"/g, '\\"');
1403
- }
1404
1409
  function getPlaceholderForParameter(parameter) {
1405
1410
  var _a, _b;
1406
1411
  const { value: parameterValue, isDefault } = getValueForParameter(parameter);
@@ -1426,14 +1431,14 @@ const getValueForParameter = (parameter) => {
1426
1431
  if (typeof defaultValue !== 'undefined') {
1427
1432
  return { value: stringifyValue(defaultValue), isDefault: true };
1428
1433
  }
1429
- const examples = (_a = parameter.examples) !== null && _a !== void 0 ? _a : [];
1430
- if (examples.length > 0) {
1431
- return { value: exampleValue(examples[0]) };
1432
- }
1433
- const enums = (_c = (_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.enum) !== null && _c !== void 0 ? _c : [];
1434
+ const enums = (_b = (_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.enum) !== null && _b !== void 0 ? _b : [];
1434
1435
  if (enums.length > 0) {
1435
1436
  return { value: stringifyValue(enums[0]) };
1436
1437
  }
1438
+ const examples = (_c = parameter.examples) !== null && _c !== void 0 ? _c : [];
1439
+ if (examples.length > 0) {
1440
+ return { value: exampleValue(examples[0]) };
1441
+ }
1437
1442
  return { value: '' };
1438
1443
  };
1439
1444
  const getInitialValueForParameter = (parameter) => {
@@ -2351,7 +2356,7 @@ const VariableEditor = ({ variable, value, onChange }) => {
2351
2356
  return (React__namespace.createElement(React__namespace.Fragment, null,
2352
2357
  React__namespace.createElement(mosaic.Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, variable.name),
2353
2358
  React__namespace.createElement(mosaic.Text, { mx: 3 }, ":"),
2354
- React__namespace.createElement("div", null, variable.enum ? (React__namespace.createElement(mosaic.Select, { flex: 1, "aria-label": variable.name, options: variable.enum.map(s => ({ value: s })), value: value || variable.default, onChange: onChange })) : (React__namespace.createElement(mosaic.Flex, { flex: 1 },
2359
+ React__namespace.createElement("div", null, variable.enum ? (React__namespace.createElement(mosaic.Select, { flex: 1, "aria-label": variable.name, options: variable.enum.map(s => ({ value: s, label: String(s) })), value: value || variable.default, onChange: onChange })) : (React__namespace.createElement(mosaic.Flex, { flex: 1 },
2355
2360
  React__namespace.createElement(mosaic.Input, { id: inputId, "aria-label": variable.name, appearance: 'minimal', flex: 1, placeholder: variable.default, type: "text", required: true, intent: 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }))))));
2356
2361
  };
2357
2362
 
@@ -3517,7 +3522,7 @@ function findFirstNode(items) {
3517
3522
  return;
3518
3523
  }
3519
3524
  function isDivider(item) {
3520
- return Object.keys(item).length === 1 && 'title' in item;
3525
+ return Object.keys(item).length === 2 && 'title' in item && 'index' in item;
3521
3526
  }
3522
3527
  function isGroup(item) {
3523
3528
  return Object.keys(item).length >= 2 && 'title' in item && 'items' in item;
@@ -3529,13 +3534,33 @@ function isNode(item) {
3529
3534
  return 'title' in item && 'slug' in item && 'id' in item && 'meta' in item && 'type' in item;
3530
3535
  }
3531
3536
  function isExternalLink(item) {
3532
- return Object.keys(item).length === 2 && 'title' in item && 'url' in item;
3537
+ return Object.keys(item).length === 3 && 'title' in item && 'url' in item && 'index' in item;
3533
3538
  }
3534
3539
 
3535
- const ActiveIdContext = React__namespace.createContext(undefined);
3540
+ const ActiveItemContext = React__namespace.createContext({
3541
+ activeId: undefined,
3542
+ lastActiveIndex: '',
3543
+ setLastActiveIndex: () => { },
3544
+ });
3536
3545
  const LinkContext = React__namespace.createContext(undefined);
3537
3546
  LinkContext.displayName = 'LinkContext';
3538
3547
  const TableOfContents = React__namespace.memo(({ tree, activeId, Link, maxDepthOpenByDefault, externalScrollbar = false, isInResponsiveMode = false, onLinkClick, }) => {
3548
+ const [lastActiveIndex, setLastActiveIndex] = React.useState('');
3549
+ const value = React__namespace.useMemo(() => ({
3550
+ lastActiveIndex,
3551
+ setLastActiveIndex,
3552
+ activeId,
3553
+ }), [lastActiveIndex, activeId]);
3554
+ const updateTocTree = React__namespace.useCallback((arr, parentId) => {
3555
+ return arr.map((item, key) => {
3556
+ let newItem = Object.assign(Object.assign({}, item), { index: parentId + key + '-' });
3557
+ if (isGroup(item) || isNodeGroup(item)) {
3558
+ newItem.items = updateTocTree(item.items, parentId + key + '-');
3559
+ }
3560
+ return newItem;
3561
+ });
3562
+ }, []);
3563
+ const updatedTree = updateTocTree(tree, '');
3539
3564
  const container = React__namespace.useRef(null);
3540
3565
  const child = React__namespace.useRef(null);
3541
3566
  const firstRender = useFirstRender();
@@ -3555,18 +3580,30 @@ const TableOfContents = React__namespace.memo(({ tree, activeId, Link, maxDepthO
3555
3580
  return (React__namespace.createElement(mosaic.Box, { ref: container, w: "full", bg: isInResponsiveMode ? 'canvas' : 'canvas-100', overflowY: "auto" },
3556
3581
  React__namespace.createElement(mosaic.Box, { ref: child, my: 3 },
3557
3582
  React__namespace.createElement(LinkContext.Provider, { value: Link },
3558
- React__namespace.createElement(ActiveIdContext.Provider, { value: activeId }, tree.map((item, key) => {
3559
- if (isDivider(item)) {
3560
- return React__namespace.createElement(Divider, { key: key, item: item, isInResponsiveMode: isInResponsiveMode });
3561
- }
3562
- return (React__namespace.createElement(GroupItem, { key: key, item: item, depth: 0, maxDepthOpenByDefault: maxDepthOpenByDefault, onLinkClick: onLinkClick, isInResponsiveMode: isInResponsiveMode }));
3563
- }))))));
3583
+ React__namespace.createElement(ActiveItemContext.Provider, { value: value },
3584
+ React__namespace.createElement(TOCContainer, { updatedTree: updatedTree }, updatedTree.map((item, key) => {
3585
+ if (isDivider(item)) {
3586
+ return React__namespace.createElement(Divider, { key: key, item: item, isInResponsiveMode: isInResponsiveMode });
3587
+ }
3588
+ return (React__namespace.createElement(GroupItem, { key: key, item: item, depth: 0, maxDepthOpenByDefault: maxDepthOpenByDefault, onLinkClick: onLinkClick, isInResponsiveMode: isInResponsiveMode }));
3589
+ })))))));
3564
3590
  });
3565
3591
  TableOfContents.displayName = 'TableOfContents';
3566
3592
  const Divider = React__namespace.memo(({ item, isInResponsiveMode = false }) => {
3567
3593
  return (React__namespace.createElement(mosaic.Box, { pl: 4, mb: 2, mt: 6, textTransform: "uppercase", fontSize: isInResponsiveMode ? 'lg' : 'sm', lineHeight: "relaxed", letterSpacing: "wide", fontWeight: "bold" }, item.title));
3568
3594
  });
3569
3595
  Divider.displayName = 'Divider';
3596
+ const TOCContainer = React__namespace.memo(({ children, updatedTree }) => {
3597
+ const { setLastActiveIndex } = React__namespace.useContext(ActiveItemContext);
3598
+ React__namespace.useEffect(() => {
3599
+ const firstNode = findFirstNode(updatedTree);
3600
+ if (firstNode) {
3601
+ setLastActiveIndex(firstNode.index);
3602
+ }
3603
+ }, []);
3604
+ return React__namespace.createElement(mosaic.Box, null, children);
3605
+ });
3606
+ TOCContainer.displayName = 'TOCContainer';
3570
3607
  const GroupItem = React__namespace.memo(({ item, depth, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick }) => {
3571
3608
  if (isExternalLink(item)) {
3572
3609
  return (React__namespace.createElement(mosaic.Box, { as: "a", href: item.url, target: "_blank", rel: "noopener noreferrer", display: "block" },
@@ -3584,9 +3621,24 @@ const GroupItem = React__namespace.memo(({ item, depth, maxDepthOpenByDefault, i
3584
3621
  });
3585
3622
  GroupItem.displayName = 'GroupItem';
3586
3623
  const Group = React__namespace.memo(({ depth, item, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick = () => { } }) => {
3587
- const activeId = React__namespace.useContext(ActiveIdContext);
3624
+ const { activeId, lastActiveIndex } = React__namespace.useContext(ActiveItemContext);
3588
3625
  const [isOpen, setIsOpen] = React__namespace.useState(() => isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault));
3589
- const hasActive = !!activeId && hasActiveItem(item.items, activeId);
3626
+ const isActiveGroup = React__namespace.useCallback((items, activeId, contextIndex) => {
3627
+ return items.some(element => {
3628
+ const hasSlugOrId = 'slug' in element || 'id' in element;
3629
+ const hasItems = 'items' in element && Array.isArray(element.items);
3630
+ if (!hasSlugOrId && !hasItems)
3631
+ return false;
3632
+ if (activeId &&
3633
+ 'index' in element &&
3634
+ (element.slug === activeId || element.id === activeId) &&
3635
+ element.index === contextIndex) {
3636
+ return true;
3637
+ }
3638
+ return hasItems ? isActiveGroup(element.items, activeId, contextIndex) : false;
3639
+ });
3640
+ }, []);
3641
+ const hasActive = isActiveGroup(item.items, activeId, lastActiveIndex);
3590
3642
  React__namespace.useEffect(() => {
3591
3643
  const openByDefault = isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault);
3592
3644
  if (isOpen !== openByDefault) {
@@ -3636,8 +3688,10 @@ const Item = React__namespace.memo(({ depth, isActive, id, title, meta, icon, is
3636
3688
  });
3637
3689
  Item.displayName = 'Item';
3638
3690
  const Node = React__namespace.memo(({ item, depth, meta, showAsActive, isInResponsiveMode, onClick, onLinkClick = () => { } }) => {
3639
- const activeId = React__namespace.useContext(ActiveIdContext);
3640
- const isActive = activeId === item.slug || activeId === item.id;
3691
+ const { activeId, lastActiveIndex, setLastActiveIndex } = React__namespace.useContext(ActiveItemContext);
3692
+ const { index } = item;
3693
+ const isSlugMatched = activeId === item.slug || activeId === item.id;
3694
+ const isActive = lastActiveIndex === index && isSlugMatched;
3641
3695
  const LinkComponent = React__namespace.useContext(LinkContext);
3642
3696
  const handleClick = (e) => {
3643
3697
  if (isActive) {
@@ -3645,6 +3699,7 @@ const Node = React__namespace.memo(({ item, depth, meta, showAsActive, isInRespo
3645
3699
  e.preventDefault();
3646
3700
  }
3647
3701
  else {
3702
+ setLastActiveIndex(index);
3648
3703
  onLinkClick();
3649
3704
  }
3650
3705
  if (onClick) {
@@ -3652,7 +3707,7 @@ const Node = React__namespace.memo(({ item, depth, meta, showAsActive, isInRespo
3652
3707
  }
3653
3708
  };
3654
3709
  return (React__namespace.createElement(mosaic.Box, { as: LinkComponent, to: resolveRelativeLink(item.slug), display: "block", textDecoration: "no-underline", className: "ElementsTableOfContentsItem" },
3655
- React__namespace.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React__namespace.createElement(mosaic.Box, { as: mosaic.Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: handleClick })));
3710
+ React__namespace.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React__namespace.createElement(mosaic.Box, { as: mosaic.Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: e => handleClick(e) })));
3656
3711
  });
3657
3712
  Node.displayName = 'Node';
3658
3713
  const Version = ({ value }) => {
package/index.mjs CHANGED
@@ -1341,7 +1341,11 @@ const booleanOptions = [
1341
1341
  { label: 'True', value: 'true' },
1342
1342
  ];
1343
1343
  function enumOptions(enumValues, required) {
1344
- const options = map(enumValues, v => ({ value: typeof v === 'number' ? v : String(v) }));
1344
+ const options = map(enumValues, v => {
1345
+ var _a;
1346
+ const value = typeof v === 'object' && v !== null ? (_a = safeStringify(v)) !== null && _a !== void 0 ? _a : String(v) : typeof v === 'number' ? v : String(v);
1347
+ return { value, label: String(value) };
1348
+ });
1345
1349
  return required ? options : [{ label: 'Not Set', value: '' }, ...options];
1346
1350
  }
1347
1351
  function parameterOptions(parameter) {
@@ -1371,15 +1375,16 @@ function parameterSupportsFileUpload(parameter) {
1371
1375
  ((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
1372
1376
  }
1373
1377
  function stringifyValue(value) {
1374
- return typeof value === 'object' ? JSON.stringify(value) : escapeQuotes(String(value));
1378
+ var _a;
1379
+ if (typeof value === 'object' && value !== null) {
1380
+ return (_a = safeStringify(value)) !== null && _a !== void 0 ? _a : String(value);
1381
+ }
1382
+ return String(value);
1375
1383
  }
1376
1384
  function exampleValue(example) {
1377
1385
  const value = 'value' in example ? example.value : example.externalValue;
1378
1386
  return stringifyValue(value);
1379
1387
  }
1380
- function escapeQuotes(value) {
1381
- return value.replace(/"/g, '\\"');
1382
- }
1383
1388
  function getPlaceholderForParameter(parameter) {
1384
1389
  var _a, _b;
1385
1390
  const { value: parameterValue, isDefault } = getValueForParameter(parameter);
@@ -1405,14 +1410,14 @@ const getValueForParameter = (parameter) => {
1405
1410
  if (typeof defaultValue !== 'undefined') {
1406
1411
  return { value: stringifyValue(defaultValue), isDefault: true };
1407
1412
  }
1408
- const examples = (_a = parameter.examples) !== null && _a !== void 0 ? _a : [];
1409
- if (examples.length > 0) {
1410
- return { value: exampleValue(examples[0]) };
1411
- }
1412
- const enums = (_c = (_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.enum) !== null && _c !== void 0 ? _c : [];
1413
+ const enums = (_b = (_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.enum) !== null && _b !== void 0 ? _b : [];
1413
1414
  if (enums.length > 0) {
1414
1415
  return { value: stringifyValue(enums[0]) };
1415
1416
  }
1417
+ const examples = (_c = parameter.examples) !== null && _c !== void 0 ? _c : [];
1418
+ if (examples.length > 0) {
1419
+ return { value: exampleValue(examples[0]) };
1420
+ }
1416
1421
  return { value: '' };
1417
1422
  };
1418
1423
  const getInitialValueForParameter = (parameter) => {
@@ -2330,7 +2335,7 @@ const VariableEditor = ({ variable, value, onChange }) => {
2330
2335
  return (React.createElement(React.Fragment, null,
2331
2336
  React.createElement(Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, variable.name),
2332
2337
  React.createElement(Text, { mx: 3 }, ":"),
2333
- React.createElement("div", null, variable.enum ? (React.createElement(Select, { flex: 1, "aria-label": variable.name, options: variable.enum.map(s => ({ value: s })), value: value || variable.default, onChange: onChange })) : (React.createElement(Flex, { flex: 1 },
2338
+ React.createElement("div", null, variable.enum ? (React.createElement(Select, { flex: 1, "aria-label": variable.name, options: variable.enum.map(s => ({ value: s, label: String(s) })), value: value || variable.default, onChange: onChange })) : (React.createElement(Flex, { flex: 1 },
2334
2339
  React.createElement(Input, { id: inputId, "aria-label": variable.name, appearance: 'minimal', flex: 1, placeholder: variable.default, type: "text", required: true, intent: 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }))))));
2335
2340
  };
2336
2341
 
@@ -3496,7 +3501,7 @@ function findFirstNode(items) {
3496
3501
  return;
3497
3502
  }
3498
3503
  function isDivider(item) {
3499
- return Object.keys(item).length === 1 && 'title' in item;
3504
+ return Object.keys(item).length === 2 && 'title' in item && 'index' in item;
3500
3505
  }
3501
3506
  function isGroup(item) {
3502
3507
  return Object.keys(item).length >= 2 && 'title' in item && 'items' in item;
@@ -3508,13 +3513,33 @@ function isNode(item) {
3508
3513
  return 'title' in item && 'slug' in item && 'id' in item && 'meta' in item && 'type' in item;
3509
3514
  }
3510
3515
  function isExternalLink(item) {
3511
- return Object.keys(item).length === 2 && 'title' in item && 'url' in item;
3516
+ return Object.keys(item).length === 3 && 'title' in item && 'url' in item && 'index' in item;
3512
3517
  }
3513
3518
 
3514
- const ActiveIdContext = React.createContext(undefined);
3519
+ const ActiveItemContext = React.createContext({
3520
+ activeId: undefined,
3521
+ lastActiveIndex: '',
3522
+ setLastActiveIndex: () => { },
3523
+ });
3515
3524
  const LinkContext = React.createContext(undefined);
3516
3525
  LinkContext.displayName = 'LinkContext';
3517
3526
  const TableOfContents = React.memo(({ tree, activeId, Link, maxDepthOpenByDefault, externalScrollbar = false, isInResponsiveMode = false, onLinkClick, }) => {
3527
+ const [lastActiveIndex, setLastActiveIndex] = useState('');
3528
+ const value = React.useMemo(() => ({
3529
+ lastActiveIndex,
3530
+ setLastActiveIndex,
3531
+ activeId,
3532
+ }), [lastActiveIndex, activeId]);
3533
+ const updateTocTree = React.useCallback((arr, parentId) => {
3534
+ return arr.map((item, key) => {
3535
+ let newItem = Object.assign(Object.assign({}, item), { index: parentId + key + '-' });
3536
+ if (isGroup(item) || isNodeGroup(item)) {
3537
+ newItem.items = updateTocTree(item.items, parentId + key + '-');
3538
+ }
3539
+ return newItem;
3540
+ });
3541
+ }, []);
3542
+ const updatedTree = updateTocTree(tree, '');
3518
3543
  const container = React.useRef(null);
3519
3544
  const child = React.useRef(null);
3520
3545
  const firstRender = useFirstRender();
@@ -3534,18 +3559,30 @@ const TableOfContents = React.memo(({ tree, activeId, Link, maxDepthOpenByDefaul
3534
3559
  return (React.createElement(Box, { ref: container, w: "full", bg: isInResponsiveMode ? 'canvas' : 'canvas-100', overflowY: "auto" },
3535
3560
  React.createElement(Box, { ref: child, my: 3 },
3536
3561
  React.createElement(LinkContext.Provider, { value: Link },
3537
- React.createElement(ActiveIdContext.Provider, { value: activeId }, tree.map((item, key) => {
3538
- if (isDivider(item)) {
3539
- return React.createElement(Divider, { key: key, item: item, isInResponsiveMode: isInResponsiveMode });
3540
- }
3541
- return (React.createElement(GroupItem, { key: key, item: item, depth: 0, maxDepthOpenByDefault: maxDepthOpenByDefault, onLinkClick: onLinkClick, isInResponsiveMode: isInResponsiveMode }));
3542
- }))))));
3562
+ React.createElement(ActiveItemContext.Provider, { value: value },
3563
+ React.createElement(TOCContainer, { updatedTree: updatedTree }, updatedTree.map((item, key) => {
3564
+ if (isDivider(item)) {
3565
+ return React.createElement(Divider, { key: key, item: item, isInResponsiveMode: isInResponsiveMode });
3566
+ }
3567
+ return (React.createElement(GroupItem, { key: key, item: item, depth: 0, maxDepthOpenByDefault: maxDepthOpenByDefault, onLinkClick: onLinkClick, isInResponsiveMode: isInResponsiveMode }));
3568
+ })))))));
3543
3569
  });
3544
3570
  TableOfContents.displayName = 'TableOfContents';
3545
3571
  const Divider = React.memo(({ item, isInResponsiveMode = false }) => {
3546
3572
  return (React.createElement(Box, { pl: 4, mb: 2, mt: 6, textTransform: "uppercase", fontSize: isInResponsiveMode ? 'lg' : 'sm', lineHeight: "relaxed", letterSpacing: "wide", fontWeight: "bold" }, item.title));
3547
3573
  });
3548
3574
  Divider.displayName = 'Divider';
3575
+ const TOCContainer = React.memo(({ children, updatedTree }) => {
3576
+ const { setLastActiveIndex } = React.useContext(ActiveItemContext);
3577
+ React.useEffect(() => {
3578
+ const firstNode = findFirstNode(updatedTree);
3579
+ if (firstNode) {
3580
+ setLastActiveIndex(firstNode.index);
3581
+ }
3582
+ }, []);
3583
+ return React.createElement(Box, null, children);
3584
+ });
3585
+ TOCContainer.displayName = 'TOCContainer';
3549
3586
  const GroupItem = React.memo(({ item, depth, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick }) => {
3550
3587
  if (isExternalLink(item)) {
3551
3588
  return (React.createElement(Box, { as: "a", href: item.url, target: "_blank", rel: "noopener noreferrer", display: "block" },
@@ -3563,9 +3600,24 @@ const GroupItem = React.memo(({ item, depth, maxDepthOpenByDefault, isInResponsi
3563
3600
  });
3564
3601
  GroupItem.displayName = 'GroupItem';
3565
3602
  const Group = React.memo(({ depth, item, maxDepthOpenByDefault, isInResponsiveMode, onLinkClick = () => { } }) => {
3566
- const activeId = React.useContext(ActiveIdContext);
3603
+ const { activeId, lastActiveIndex } = React.useContext(ActiveItemContext);
3567
3604
  const [isOpen, setIsOpen] = React.useState(() => isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault));
3568
- const hasActive = !!activeId && hasActiveItem(item.items, activeId);
3605
+ const isActiveGroup = React.useCallback((items, activeId, contextIndex) => {
3606
+ return items.some(element => {
3607
+ const hasSlugOrId = 'slug' in element || 'id' in element;
3608
+ const hasItems = 'items' in element && Array.isArray(element.items);
3609
+ if (!hasSlugOrId && !hasItems)
3610
+ return false;
3611
+ if (activeId &&
3612
+ 'index' in element &&
3613
+ (element.slug === activeId || element.id === activeId) &&
3614
+ element.index === contextIndex) {
3615
+ return true;
3616
+ }
3617
+ return hasItems ? isActiveGroup(element.items, activeId, contextIndex) : false;
3618
+ });
3619
+ }, []);
3620
+ const hasActive = isActiveGroup(item.items, activeId, lastActiveIndex);
3569
3621
  React.useEffect(() => {
3570
3622
  const openByDefault = isGroupOpenByDefault(depth, item, activeId, maxDepthOpenByDefault);
3571
3623
  if (isOpen !== openByDefault) {
@@ -3615,8 +3667,10 @@ const Item = React.memo(({ depth, isActive, id, title, meta, icon, isInResponsiv
3615
3667
  });
3616
3668
  Item.displayName = 'Item';
3617
3669
  const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode, onClick, onLinkClick = () => { } }) => {
3618
- const activeId = React.useContext(ActiveIdContext);
3619
- const isActive = activeId === item.slug || activeId === item.id;
3670
+ const { activeId, lastActiveIndex, setLastActiveIndex } = React.useContext(ActiveItemContext);
3671
+ const { index } = item;
3672
+ const isSlugMatched = activeId === item.slug || activeId === item.id;
3673
+ const isActive = lastActiveIndex === index && isSlugMatched;
3620
3674
  const LinkComponent = React.useContext(LinkContext);
3621
3675
  const handleClick = (e) => {
3622
3676
  if (isActive) {
@@ -3624,6 +3678,7 @@ const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode,
3624
3678
  e.preventDefault();
3625
3679
  }
3626
3680
  else {
3681
+ setLastActiveIndex(index);
3627
3682
  onLinkClick();
3628
3683
  }
3629
3684
  if (onClick) {
@@ -3631,7 +3686,7 @@ const Node = React.memo(({ item, depth, meta, showAsActive, isInResponsiveMode,
3631
3686
  }
3632
3687
  };
3633
3688
  return (React.createElement(Box, { as: LinkComponent, to: resolveRelativeLink(item.slug), display: "block", textDecoration: "no-underline", className: "ElementsTableOfContentsItem" },
3634
- React.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React.createElement(Box, { as: Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: handleClick })));
3689
+ React.createElement(Item, { id: getHtmlIdFromItemId(item.slug || item.id), isActive: isActive || showAsActive, depth: depth, title: item.title, icon: NODE_TYPE_TITLE_ICON[item.type] && (React.createElement(Box, { as: Icon, color: NODE_TYPE_ICON_COLOR[item.type], icon: NODE_TYPE_TITLE_ICON[item.type] })), meta: meta, isInResponsiveMode: isInResponsiveMode, onClick: e => handleClick(e) })));
3635
3690
  });
3636
3691
  Node.displayName = 'Node';
3637
3692
  const Version = ({ value }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoplight/elements-core",
3
- "version": "9.0.12",
3
+ "version": "9.0.13-alpha.0",
4
4
  "main": "./index.js",
5
5
  "sideEffects": [
6
6
  "web-components.min.js",