@stoplight/elements-core 9.0.13 → 9.0.15-beta-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.
@@ -4,19 +4,19 @@ 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 encodeSafeSelectorValue(value: string | number): string | number;
8
+ export declare function decodeSafeSelectorValue(value: string | number): string | number;
9
+ export declare function parameterOptions(parameter: ParameterSpec): {
8
10
  value: string | number;
9
- } | {
10
11
  label: string;
11
- value: string;
12
- })[] | null;
12
+ }[] | null;
13
13
  export declare const selectExampleOption: {
14
14
  value: string;
15
15
  label: string;
16
16
  };
17
17
  export declare function exampleOptions(parameter: ParameterSpec): {
18
- value: string;
19
18
  label: string;
19
+ value: string | number;
20
20
  }[] | null;
21
21
  export declare function parameterSupportsFileUpload(parameter?: Pick<ParameterSpec, 'schema'>): boolean | undefined;
22
22
  export declare function getPlaceholderForParameter(parameter: ParameterSpec): string;
package/index.esm.js CHANGED
@@ -1340,8 +1340,50 @@ const booleanOptions = [
1340
1340
  { label: 'False', value: 'false' },
1341
1341
  { label: 'True', value: 'true' },
1342
1342
  ];
1343
+ function encodeSafeSelectorValue(value) {
1344
+ if (typeof value === 'number') {
1345
+ return value;
1346
+ }
1347
+ const hasSpecialChars = /["'\[\]\\(){}]/.test(value);
1348
+ if (!hasSpecialChars) {
1349
+ return value;
1350
+ }
1351
+ try {
1352
+ return 'b64:' + btoa(value);
1353
+ }
1354
+ catch (e) {
1355
+ return 'enc:' + encodeURIComponent(value);
1356
+ }
1357
+ }
1358
+ function decodeSafeSelectorValue(value) {
1359
+ if (typeof value === 'number') {
1360
+ return value;
1361
+ }
1362
+ if (value.startsWith('b64:')) {
1363
+ try {
1364
+ return atob(value.substring(4));
1365
+ }
1366
+ catch (e) {
1367
+ return value;
1368
+ }
1369
+ }
1370
+ if (value.startsWith('enc:')) {
1371
+ try {
1372
+ return decodeURIComponent(value.substring(4));
1373
+ }
1374
+ catch (e) {
1375
+ return value;
1376
+ }
1377
+ }
1378
+ return value;
1379
+ }
1343
1380
  function enumOptions(enumValues, required) {
1344
- const options = map(enumValues, v => ({ value: typeof v === 'number' ? v : String(v) }));
1381
+ const options = map(enumValues, v => {
1382
+ var _a;
1383
+ const stringValue = typeof v === 'object' && v !== null ? (_a = safeStringify(v)) !== null && _a !== void 0 ? _a : String(v) : typeof v === 'number' ? v : String(v);
1384
+ const safeValue = encodeSafeSelectorValue(stringValue);
1385
+ return { value: safeValue, label: String(stringValue) };
1386
+ });
1345
1387
  return required ? options : [{ label: 'Not Set', value: '' }, ...options];
1346
1388
  }
1347
1389
  function parameterOptions(parameter) {
@@ -1358,7 +1400,10 @@ function exampleOptions(parameter) {
1358
1400
  return ((_a = parameter.examples) === null || _a === void 0 ? void 0 : _a.length) && parameter.examples.length > 1
1359
1401
  ? [
1360
1402
  selectExampleOption,
1361
- ...parameter.examples.map(example => ({ label: example.key, value: exampleValue(example) })),
1403
+ ...parameter.examples.map(example => ({
1404
+ label: example.key,
1405
+ value: encodeSafeSelectorValue(exampleValue(example)),
1406
+ })),
1362
1407
  ]
1363
1408
  : null;
1364
1409
  }
@@ -1371,15 +1416,19 @@ function parameterSupportsFileUpload(parameter) {
1371
1416
  ((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
1372
1417
  }
1373
1418
  function stringifyValue(value) {
1374
- return typeof value === 'object' ? JSON.stringify(value) : escapeQuotes(String(value));
1375
- }
1376
- function exampleValue(example) {
1377
- const value = 'value' in example ? example.value : example.externalValue;
1378
- return stringifyValue(value);
1419
+ var _a;
1420
+ if (typeof value === 'object' && value !== null) {
1421
+ return (_a = safeStringify(value)) !== null && _a !== void 0 ? _a : String(value);
1422
+ }
1423
+ return String(value);
1379
1424
  }
1380
1425
  function escapeQuotes(value) {
1381
1426
  return value.replace(/"/g, '\\"');
1382
1427
  }
1428
+ function exampleValue(example) {
1429
+ const value = 'value' in example ? example.value : example.externalValue;
1430
+ return escapeQuotes(stringifyValue(value));
1431
+ }
1383
1432
  function getPlaceholderForParameter(parameter) {
1384
1433
  var _a, _b;
1385
1434
  const { value: parameterValue, isDefault } = getValueForParameter(parameter);
@@ -1405,14 +1454,14 @@ const getValueForParameter = (parameter) => {
1405
1454
  if (typeof defaultValue !== 'undefined') {
1406
1455
  return { value: stringifyValue(defaultValue), isDefault: true };
1407
1456
  }
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 : [];
1457
+ const enums = (_b = (_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.enum) !== null && _b !== void 0 ? _b : [];
1413
1458
  if (enums.length > 0) {
1414
1459
  return { value: stringifyValue(enums[0]) };
1415
1460
  }
1461
+ const examples = (_c = parameter.examples) !== null && _c !== void 0 ? _c : [];
1462
+ if (examples.length > 0) {
1463
+ return { value: exampleValue(examples[0]) };
1464
+ }
1416
1465
  return { value: '' };
1417
1466
  };
1418
1467
  const getInitialValueForParameter = (parameter) => {
@@ -1461,20 +1510,35 @@ function isRequired(n) {
1461
1510
  }
1462
1511
 
1463
1512
  const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
1464
- var _a, _b;
1513
+ var _a;
1465
1514
  const inputId = useUniqueId(`id_${parameter.name}_`);
1466
1515
  const inputCheckId = useUniqueId(`id_${parameter.name}_checked`);
1467
1516
  const parameterValueOptions = parameterOptions(parameter);
1468
1517
  const examples = exampleOptions(parameter);
1469
- const selectedExample = (_a = examples === null || examples === void 0 ? void 0 : examples.find(e => e.value === value)) !== null && _a !== void 0 ? _a : selectExampleOption;
1518
+ const selectedExample = React.useMemo(() => {
1519
+ if (!examples)
1520
+ return selectExampleOption;
1521
+ const matchingExample = examples.find(e => {
1522
+ return String(decodeSafeSelectorValue(e.value)) === value;
1523
+ });
1524
+ return matchingExample !== null && matchingExample !== void 0 ? matchingExample : selectExampleOption;
1525
+ }, [examples, value]);
1470
1526
  const parameterDisplayName = `${parameter.name}${parameter.required ? '*' : ''}`;
1527
+ const encodedValue = React.useMemo(() => {
1528
+ if (!value || !parameterValueOptions)
1529
+ return value || '';
1530
+ const matchingOption = parameterValueOptions.find(opt => {
1531
+ return String(decodeSafeSelectorValue(opt.value)) === value;
1532
+ });
1533
+ return matchingOption ? String(matchingOption.value) : value;
1534
+ }, [value, parameterValueOptions]);
1471
1535
  const requiredButEmpty = validate && parameter.required && !value;
1472
1536
  return (React.createElement(React.Fragment, null,
1473
1537
  React.createElement(Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, parameterDisplayName),
1474
1538
  React.createElement(Text, { mx: 3 }, ":"),
1475
- React.createElement("div", null, parameterValueOptions ? (React.createElement(Select, { flex: 1, "aria-label": parameter.name, options: parameterValueOptions, value: value || '', onChange: onChange, placeholder: getPlaceholderForSelectedParameter(parameter) })) : (React.createElement(Flex, { flex: 1 },
1476
- React.createElement(Input, { id: inputId, "aria-label": parameter.name, appearance: requiredButEmpty ? 'default' : 'minimal', flex: 1, placeholder: getPlaceholderForParameter(parameter), type: ((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.type) === 'number' ? 'number' : 'text', required: true, intent: requiredButEmpty ? 'danger' : 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }),
1477
- examples && (React.createElement(Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: onChange }))))),
1539
+ React.createElement("div", null, parameterValueOptions ? (React.createElement(Select, { flex: 1, "aria-label": parameter.name, options: parameterValueOptions, value: encodedValue, onChange: val => onChange && onChange(String(decodeSafeSelectorValue(val))), placeholder: getPlaceholderForSelectedParameter(parameter) })) : (React.createElement(Flex, { flex: 1 },
1540
+ React.createElement(Input, { id: inputId, "aria-label": parameter.name, appearance: requiredButEmpty ? 'default' : 'minimal', flex: 1, placeholder: getPlaceholderForParameter(parameter), type: ((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'number' ? 'number' : 'text', required: true, intent: requiredButEmpty ? 'danger' : 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }),
1541
+ examples && (React.createElement(Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: val => onChange && onChange(String(decodeSafeSelectorValue(val))) }))))),
1478
1542
  canChangeOptional && !parameter.required && (React.createElement(React.Fragment, null,
1479
1543
  React.createElement("div", null),
1480
1544
  React.createElement("div", null),
@@ -2327,10 +2391,17 @@ ServersDropdown.displayName = 'ServersDropdown';
2327
2391
 
2328
2392
  const VariableEditor = ({ variable, value, onChange }) => {
2329
2393
  const inputId = useUniqueId(`id_${variable.name}_`);
2394
+ const encodedOptions = React.useMemo(() => (variable.enum ? variable.enum.map(s => ({ value: encodeSafeSelectorValue(s), label: String(s) })) : []), [variable.enum]);
2395
+ const encodedValue = React.useMemo(() => {
2396
+ if (!value || !variable.enum)
2397
+ return value || variable.default;
2398
+ const matchingOption = encodedOptions.find(opt => decodeSafeSelectorValue(String(opt.value)) === value);
2399
+ return matchingOption ? String(matchingOption.value) : value;
2400
+ }, [value, variable.enum, variable.default, encodedOptions]);
2330
2401
  return (React.createElement(React.Fragment, null,
2331
2402
  React.createElement(Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, variable.name),
2332
2403
  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 },
2404
+ React.createElement("div", null, variable.enum ? (React.createElement(Select, { flex: 1, "aria-label": variable.name, options: encodedOptions, value: encodedValue, onChange: val => onChange && onChange(decodeSafeSelectorValue(String(val))) })) : (React.createElement(Flex, { flex: 1 },
2334
2405
  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
2406
  };
2336
2407
 
@@ -3255,7 +3326,7 @@ const HttpServiceComponent = React.memo(({ data: unresolvedData, location = {},
3255
3326
  var _a, _b, _c, _d;
3256
3327
  const { nodeHasChanged } = useOptionsCtx();
3257
3328
  const data = useResolvedObject(unresolvedData);
3258
- const { ref: layoutRef, isCompact } = useIsCompact(layoutOptions);
3329
+ const { ref: layoutRef } = useIsCompact(layoutOptions);
3259
3330
  const { search, pathname } = location;
3260
3331
  const mocking = React.useContext(MockingContext);
3261
3332
  const query = new URLSearchParams(search);
@@ -3267,7 +3338,7 @@ const HttpServiceComponent = React.memo(({ data: unresolvedData, location = {},
3267
3338
  React.createElement(Box, { pos: "relative" },
3268
3339
  React.createElement(Heading, { size: 1, mb: 4, fontWeight: "semibold" }, data.name),
3269
3340
  React.createElement(NodeAnnotation, { change: nameChanged })),
3270
- exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && !isCompact && React.createElement(ExportButton, Object.assign({}, exportProps)))),
3341
+ exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && React.createElement(ExportButton, Object.assign({}, exportProps)))),
3271
3342
  data.version && (React.createElement(Box, { mb: 5, pos: "relative" },
3272
3343
  React.createElement(VersionBadge, { value: data.version }),
3273
3344
  React.createElement(NodeAnnotation, { change: versionChanged }))),
@@ -3303,7 +3374,7 @@ const ModelComponent = ({ data: unresolvedData, className, nodeTitle, layoutOpti
3303
3374
  isDeprecated && React.createElement(DeprecatedBadge, null),
3304
3375
  isInternal && React.createElement(InternalBadge, null))),
3305
3376
  React.createElement(NodeAnnotation, { change: titleChanged })),
3306
- exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && !isCompact && React.createElement(ExportButton, Object.assign({}, exportProps))));
3377
+ exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && React.createElement(ExportButton, Object.assign({}, exportProps))));
3307
3378
  const modelExamples = !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideModelExamples) && React.createElement(ModelExamples, { data: data, isCollapsible: isCompact });
3308
3379
  const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId, attr: 'description' });
3309
3380
  const description = (React.createElement(VStack, { spacing: 10 },
@@ -3535,6 +3606,38 @@ const TableOfContents = React.memo(({ tree, activeId, Link, maxDepthOpenByDefaul
3535
3606
  });
3536
3607
  }, []);
3537
3608
  const updatedTree = updateTocTree(tree, '');
3609
+ const findFirstMatchAndIndexMatch = React.useCallback((items, id) => {
3610
+ let firstMatch;
3611
+ let hasAnyLastIndexMatch = false;
3612
+ if (!id)
3613
+ return [firstMatch, hasAnyLastIndexMatch];
3614
+ const walk = (arr, stack) => {
3615
+ for (const itm of arr) {
3616
+ const newStack = stack.concat(itm);
3617
+ const matches = ('slug' in itm && itm.slug === id) || ('id' in itm && itm.id === id);
3618
+ if (matches) {
3619
+ if (!firstMatch)
3620
+ firstMatch = itm;
3621
+ const hasLastIndexMatch = newStack.some(el => 'index' in el && el.index === lastActiveIndex);
3622
+ if (hasLastIndexMatch)
3623
+ hasAnyLastIndexMatch = true;
3624
+ }
3625
+ if ('items' in itm && Array.isArray(itm.items)) {
3626
+ if (walk(itm.items, newStack))
3627
+ return true;
3628
+ }
3629
+ }
3630
+ return false;
3631
+ };
3632
+ walk(items, []);
3633
+ return [firstMatch, hasAnyLastIndexMatch];
3634
+ }, [lastActiveIndex]);
3635
+ const [firstMatchItem, hasAnyLastIndexMatch] = React.useMemo(() => findFirstMatchAndIndexMatch(updatedTree, activeId), [updatedTree, activeId, findFirstMatchAndIndexMatch]);
3636
+ React.useEffect(() => {
3637
+ if (!hasAnyLastIndexMatch && firstMatchItem && 'index' in firstMatchItem && firstMatchItem.index) {
3638
+ setLastActiveIndex(firstMatchItem.index);
3639
+ }
3640
+ }, [firstMatchItem, hasAnyLastIndexMatch]);
3538
3641
  const container = React.useRef(null);
3539
3642
  const child = React.useRef(null);
3540
3643
  const firstRender = useFirstRender();
package/index.js CHANGED
@@ -1361,8 +1361,50 @@ const booleanOptions = [
1361
1361
  { label: 'False', value: 'false' },
1362
1362
  { label: 'True', value: 'true' },
1363
1363
  ];
1364
+ function encodeSafeSelectorValue(value) {
1365
+ if (typeof value === 'number') {
1366
+ return value;
1367
+ }
1368
+ const hasSpecialChars = /["'\[\]\\(){}]/.test(value);
1369
+ if (!hasSpecialChars) {
1370
+ return value;
1371
+ }
1372
+ try {
1373
+ return 'b64:' + btoa(value);
1374
+ }
1375
+ catch (e) {
1376
+ return 'enc:' + encodeURIComponent(value);
1377
+ }
1378
+ }
1379
+ function decodeSafeSelectorValue(value) {
1380
+ if (typeof value === 'number') {
1381
+ return value;
1382
+ }
1383
+ if (value.startsWith('b64:')) {
1384
+ try {
1385
+ return atob(value.substring(4));
1386
+ }
1387
+ catch (e) {
1388
+ return value;
1389
+ }
1390
+ }
1391
+ if (value.startsWith('enc:')) {
1392
+ try {
1393
+ return decodeURIComponent(value.substring(4));
1394
+ }
1395
+ catch (e) {
1396
+ return value;
1397
+ }
1398
+ }
1399
+ return value;
1400
+ }
1364
1401
  function enumOptions(enumValues, required) {
1365
- const options = map(enumValues, v => ({ value: typeof v === 'number' ? v : String(v) }));
1402
+ const options = map(enumValues, v => {
1403
+ var _a;
1404
+ const stringValue = typeof v === 'object' && v !== null ? (_a = json.safeStringify(v)) !== null && _a !== void 0 ? _a : String(v) : typeof v === 'number' ? v : String(v);
1405
+ const safeValue = encodeSafeSelectorValue(stringValue);
1406
+ return { value: safeValue, label: String(stringValue) };
1407
+ });
1366
1408
  return required ? options : [{ label: 'Not Set', value: '' }, ...options];
1367
1409
  }
1368
1410
  function parameterOptions(parameter) {
@@ -1379,7 +1421,10 @@ function exampleOptions(parameter) {
1379
1421
  return ((_a = parameter.examples) === null || _a === void 0 ? void 0 : _a.length) && parameter.examples.length > 1
1380
1422
  ? [
1381
1423
  selectExampleOption,
1382
- ...parameter.examples.map(example => ({ label: example.key, value: exampleValue(example) })),
1424
+ ...parameter.examples.map(example => ({
1425
+ label: example.key,
1426
+ value: encodeSafeSelectorValue(exampleValue(example)),
1427
+ })),
1383
1428
  ]
1384
1429
  : null;
1385
1430
  }
@@ -1392,15 +1437,19 @@ function parameterSupportsFileUpload(parameter) {
1392
1437
  ((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
1393
1438
  }
1394
1439
  function stringifyValue(value) {
1395
- return typeof value === 'object' ? JSON.stringify(value) : escapeQuotes(String(value));
1396
- }
1397
- function exampleValue(example) {
1398
- const value = 'value' in example ? example.value : example.externalValue;
1399
- return stringifyValue(value);
1440
+ var _a;
1441
+ if (typeof value === 'object' && value !== null) {
1442
+ return (_a = json.safeStringify(value)) !== null && _a !== void 0 ? _a : String(value);
1443
+ }
1444
+ return String(value);
1400
1445
  }
1401
1446
  function escapeQuotes(value) {
1402
1447
  return value.replace(/"/g, '\\"');
1403
1448
  }
1449
+ function exampleValue(example) {
1450
+ const value = 'value' in example ? example.value : example.externalValue;
1451
+ return escapeQuotes(stringifyValue(value));
1452
+ }
1404
1453
  function getPlaceholderForParameter(parameter) {
1405
1454
  var _a, _b;
1406
1455
  const { value: parameterValue, isDefault } = getValueForParameter(parameter);
@@ -1426,14 +1475,14 @@ const getValueForParameter = (parameter) => {
1426
1475
  if (typeof defaultValue !== 'undefined') {
1427
1476
  return { value: stringifyValue(defaultValue), isDefault: true };
1428
1477
  }
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 : [];
1478
+ const enums = (_b = (_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.enum) !== null && _b !== void 0 ? _b : [];
1434
1479
  if (enums.length > 0) {
1435
1480
  return { value: stringifyValue(enums[0]) };
1436
1481
  }
1482
+ const examples = (_c = parameter.examples) !== null && _c !== void 0 ? _c : [];
1483
+ if (examples.length > 0) {
1484
+ return { value: exampleValue(examples[0]) };
1485
+ }
1437
1486
  return { value: '' };
1438
1487
  };
1439
1488
  const getInitialValueForParameter = (parameter) => {
@@ -1482,20 +1531,35 @@ function isRequired(n) {
1482
1531
  }
1483
1532
 
1484
1533
  const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
1485
- var _a, _b;
1534
+ var _a;
1486
1535
  const inputId = useUniqueId(`id_${parameter.name}_`);
1487
1536
  const inputCheckId = useUniqueId(`id_${parameter.name}_checked`);
1488
1537
  const parameterValueOptions = parameterOptions(parameter);
1489
1538
  const examples = exampleOptions(parameter);
1490
- const selectedExample = (_a = examples === null || examples === void 0 ? void 0 : examples.find(e => e.value === value)) !== null && _a !== void 0 ? _a : selectExampleOption;
1539
+ const selectedExample = React__namespace.useMemo(() => {
1540
+ if (!examples)
1541
+ return selectExampleOption;
1542
+ const matchingExample = examples.find(e => {
1543
+ return String(decodeSafeSelectorValue(e.value)) === value;
1544
+ });
1545
+ return matchingExample !== null && matchingExample !== void 0 ? matchingExample : selectExampleOption;
1546
+ }, [examples, value]);
1491
1547
  const parameterDisplayName = `${parameter.name}${parameter.required ? '*' : ''}`;
1548
+ const encodedValue = React__namespace.useMemo(() => {
1549
+ if (!value || !parameterValueOptions)
1550
+ return value || '';
1551
+ const matchingOption = parameterValueOptions.find(opt => {
1552
+ return String(decodeSafeSelectorValue(opt.value)) === value;
1553
+ });
1554
+ return matchingOption ? String(matchingOption.value) : value;
1555
+ }, [value, parameterValueOptions]);
1492
1556
  const requiredButEmpty = validate && parameter.required && !value;
1493
1557
  return (React__namespace.createElement(React__namespace.Fragment, null,
1494
1558
  React__namespace.createElement(mosaic.Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, parameterDisplayName),
1495
1559
  React__namespace.createElement(mosaic.Text, { mx: 3 }, ":"),
1496
- React__namespace.createElement("div", null, parameterValueOptions ? (React__namespace.createElement(mosaic.Select, { flex: 1, "aria-label": parameter.name, options: parameterValueOptions, value: value || '', onChange: onChange, placeholder: getPlaceholderForSelectedParameter(parameter) })) : (React__namespace.createElement(mosaic.Flex, { flex: 1 },
1497
- React__namespace.createElement(mosaic.Input, { id: inputId, "aria-label": parameter.name, appearance: requiredButEmpty ? 'default' : 'minimal', flex: 1, placeholder: getPlaceholderForParameter(parameter), type: ((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.type) === 'number' ? 'number' : 'text', required: true, intent: requiredButEmpty ? 'danger' : 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }),
1498
- examples && (React__namespace.createElement(mosaic.Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: onChange }))))),
1560
+ React__namespace.createElement("div", null, parameterValueOptions ? (React__namespace.createElement(mosaic.Select, { flex: 1, "aria-label": parameter.name, options: parameterValueOptions, value: encodedValue, onChange: val => onChange && onChange(String(decodeSafeSelectorValue(val))), placeholder: getPlaceholderForSelectedParameter(parameter) })) : (React__namespace.createElement(mosaic.Flex, { flex: 1 },
1561
+ React__namespace.createElement(mosaic.Input, { id: inputId, "aria-label": parameter.name, appearance: requiredButEmpty ? 'default' : 'minimal', flex: 1, placeholder: getPlaceholderForParameter(parameter), type: ((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'number' ? 'number' : 'text', required: true, intent: requiredButEmpty ? 'danger' : 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }),
1562
+ examples && (React__namespace.createElement(mosaic.Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: val => onChange && onChange(String(decodeSafeSelectorValue(val))) }))))),
1499
1563
  canChangeOptional && !parameter.required && (React__namespace.createElement(React__namespace.Fragment, null,
1500
1564
  React__namespace.createElement("div", null),
1501
1565
  React__namespace.createElement("div", null),
@@ -2348,10 +2412,17 @@ ServersDropdown.displayName = 'ServersDropdown';
2348
2412
 
2349
2413
  const VariableEditor = ({ variable, value, onChange }) => {
2350
2414
  const inputId = useUniqueId(`id_${variable.name}_`);
2415
+ const encodedOptions = React__namespace.useMemo(() => (variable.enum ? variable.enum.map(s => ({ value: encodeSafeSelectorValue(s), label: String(s) })) : []), [variable.enum]);
2416
+ const encodedValue = React__namespace.useMemo(() => {
2417
+ if (!value || !variable.enum)
2418
+ return value || variable.default;
2419
+ const matchingOption = encodedOptions.find(opt => decodeSafeSelectorValue(String(opt.value)) === value);
2420
+ return matchingOption ? String(matchingOption.value) : value;
2421
+ }, [value, variable.enum, variable.default, encodedOptions]);
2351
2422
  return (React__namespace.createElement(React__namespace.Fragment, null,
2352
2423
  React__namespace.createElement(mosaic.Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, variable.name),
2353
2424
  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 },
2425
+ React__namespace.createElement("div", null, variable.enum ? (React__namespace.createElement(mosaic.Select, { flex: 1, "aria-label": variable.name, options: encodedOptions, value: encodedValue, onChange: val => onChange && onChange(decodeSafeSelectorValue(String(val))) })) : (React__namespace.createElement(mosaic.Flex, { flex: 1 },
2355
2426
  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
2427
  };
2357
2428
 
@@ -3276,7 +3347,7 @@ const HttpServiceComponent = React__namespace.memo(({ data: unresolvedData, loca
3276
3347
  var _a, _b, _c, _d;
3277
3348
  const { nodeHasChanged } = useOptionsCtx();
3278
3349
  const data = useResolvedObject(unresolvedData);
3279
- const { ref: layoutRef, isCompact } = useIsCompact(layoutOptions);
3350
+ const { ref: layoutRef } = useIsCompact(layoutOptions);
3280
3351
  const { search, pathname } = location;
3281
3352
  const mocking = React__namespace.useContext(MockingContext);
3282
3353
  const query = new URLSearchParams(search);
@@ -3288,7 +3359,7 @@ const HttpServiceComponent = React__namespace.memo(({ data: unresolvedData, loca
3288
3359
  React__namespace.createElement(mosaic.Box, { pos: "relative" },
3289
3360
  React__namespace.createElement(mosaic.Heading, { size: 1, mb: 4, fontWeight: "semibold" }, data.name),
3290
3361
  React__namespace.createElement(mosaic.NodeAnnotation, { change: nameChanged })),
3291
- exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && !isCompact && React__namespace.createElement(ExportButton, Object.assign({}, exportProps)))),
3362
+ exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && React__namespace.createElement(ExportButton, Object.assign({}, exportProps)))),
3292
3363
  data.version && (React__namespace.createElement(mosaic.Box, { mb: 5, pos: "relative" },
3293
3364
  React__namespace.createElement(VersionBadge, { value: data.version }),
3294
3365
  React__namespace.createElement(mosaic.NodeAnnotation, { change: versionChanged }))),
@@ -3324,7 +3395,7 @@ const ModelComponent = ({ data: unresolvedData, className, nodeTitle, layoutOpti
3324
3395
  isDeprecated && React__namespace.createElement(DeprecatedBadge, null),
3325
3396
  isInternal && React__namespace.createElement(InternalBadge, null))),
3326
3397
  React__namespace.createElement(mosaic.NodeAnnotation, { change: titleChanged })),
3327
- exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && !isCompact && React__namespace.createElement(ExportButton, Object.assign({}, exportProps))));
3398
+ exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && React__namespace.createElement(ExportButton, Object.assign({}, exportProps))));
3328
3399
  const modelExamples = !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideModelExamples) && React__namespace.createElement(ModelExamples, { data: data, isCollapsible: isCompact });
3329
3400
  const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId, attr: 'description' });
3330
3401
  const description = (React__namespace.createElement(mosaic.VStack, { spacing: 10 },
@@ -3556,6 +3627,38 @@ const TableOfContents = React__namespace.memo(({ tree, activeId, Link, maxDepthO
3556
3627
  });
3557
3628
  }, []);
3558
3629
  const updatedTree = updateTocTree(tree, '');
3630
+ const findFirstMatchAndIndexMatch = React__namespace.useCallback((items, id) => {
3631
+ let firstMatch;
3632
+ let hasAnyLastIndexMatch = false;
3633
+ if (!id)
3634
+ return [firstMatch, hasAnyLastIndexMatch];
3635
+ const walk = (arr, stack) => {
3636
+ for (const itm of arr) {
3637
+ const newStack = stack.concat(itm);
3638
+ const matches = ('slug' in itm && itm.slug === id) || ('id' in itm && itm.id === id);
3639
+ if (matches) {
3640
+ if (!firstMatch)
3641
+ firstMatch = itm;
3642
+ const hasLastIndexMatch = newStack.some(el => 'index' in el && el.index === lastActiveIndex);
3643
+ if (hasLastIndexMatch)
3644
+ hasAnyLastIndexMatch = true;
3645
+ }
3646
+ if ('items' in itm && Array.isArray(itm.items)) {
3647
+ if (walk(itm.items, newStack))
3648
+ return true;
3649
+ }
3650
+ }
3651
+ return false;
3652
+ };
3653
+ walk(items, []);
3654
+ return [firstMatch, hasAnyLastIndexMatch];
3655
+ }, [lastActiveIndex]);
3656
+ const [firstMatchItem, hasAnyLastIndexMatch] = React__namespace.useMemo(() => findFirstMatchAndIndexMatch(updatedTree, activeId), [updatedTree, activeId, findFirstMatchAndIndexMatch]);
3657
+ React__namespace.useEffect(() => {
3658
+ if (!hasAnyLastIndexMatch && firstMatchItem && 'index' in firstMatchItem && firstMatchItem.index) {
3659
+ setLastActiveIndex(firstMatchItem.index);
3660
+ }
3661
+ }, [firstMatchItem, hasAnyLastIndexMatch]);
3559
3662
  const container = React__namespace.useRef(null);
3560
3663
  const child = React__namespace.useRef(null);
3561
3664
  const firstRender = useFirstRender();
package/index.mjs CHANGED
@@ -1340,8 +1340,50 @@ const booleanOptions = [
1340
1340
  { label: 'False', value: 'false' },
1341
1341
  { label: 'True', value: 'true' },
1342
1342
  ];
1343
+ function encodeSafeSelectorValue(value) {
1344
+ if (typeof value === 'number') {
1345
+ return value;
1346
+ }
1347
+ const hasSpecialChars = /["'\[\]\\(){}]/.test(value);
1348
+ if (!hasSpecialChars) {
1349
+ return value;
1350
+ }
1351
+ try {
1352
+ return 'b64:' + btoa(value);
1353
+ }
1354
+ catch (e) {
1355
+ return 'enc:' + encodeURIComponent(value);
1356
+ }
1357
+ }
1358
+ function decodeSafeSelectorValue(value) {
1359
+ if (typeof value === 'number') {
1360
+ return value;
1361
+ }
1362
+ if (value.startsWith('b64:')) {
1363
+ try {
1364
+ return atob(value.substring(4));
1365
+ }
1366
+ catch (e) {
1367
+ return value;
1368
+ }
1369
+ }
1370
+ if (value.startsWith('enc:')) {
1371
+ try {
1372
+ return decodeURIComponent(value.substring(4));
1373
+ }
1374
+ catch (e) {
1375
+ return value;
1376
+ }
1377
+ }
1378
+ return value;
1379
+ }
1343
1380
  function enumOptions(enumValues, required) {
1344
- const options = map(enumValues, v => ({ value: typeof v === 'number' ? v : String(v) }));
1381
+ const options = map(enumValues, v => {
1382
+ var _a;
1383
+ const stringValue = typeof v === 'object' && v !== null ? (_a = safeStringify(v)) !== null && _a !== void 0 ? _a : String(v) : typeof v === 'number' ? v : String(v);
1384
+ const safeValue = encodeSafeSelectorValue(stringValue);
1385
+ return { value: safeValue, label: String(stringValue) };
1386
+ });
1345
1387
  return required ? options : [{ label: 'Not Set', value: '' }, ...options];
1346
1388
  }
1347
1389
  function parameterOptions(parameter) {
@@ -1358,7 +1400,10 @@ function exampleOptions(parameter) {
1358
1400
  return ((_a = parameter.examples) === null || _a === void 0 ? void 0 : _a.length) && parameter.examples.length > 1
1359
1401
  ? [
1360
1402
  selectExampleOption,
1361
- ...parameter.examples.map(example => ({ label: example.key, value: exampleValue(example) })),
1403
+ ...parameter.examples.map(example => ({
1404
+ label: example.key,
1405
+ value: encodeSafeSelectorValue(exampleValue(example)),
1406
+ })),
1362
1407
  ]
1363
1408
  : null;
1364
1409
  }
@@ -1371,15 +1416,19 @@ function parameterSupportsFileUpload(parameter) {
1371
1416
  ((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
1372
1417
  }
1373
1418
  function stringifyValue(value) {
1374
- return typeof value === 'object' ? JSON.stringify(value) : escapeQuotes(String(value));
1375
- }
1376
- function exampleValue(example) {
1377
- const value = 'value' in example ? example.value : example.externalValue;
1378
- return stringifyValue(value);
1419
+ var _a;
1420
+ if (typeof value === 'object' && value !== null) {
1421
+ return (_a = safeStringify(value)) !== null && _a !== void 0 ? _a : String(value);
1422
+ }
1423
+ return String(value);
1379
1424
  }
1380
1425
  function escapeQuotes(value) {
1381
1426
  return value.replace(/"/g, '\\"');
1382
1427
  }
1428
+ function exampleValue(example) {
1429
+ const value = 'value' in example ? example.value : example.externalValue;
1430
+ return escapeQuotes(stringifyValue(value));
1431
+ }
1383
1432
  function getPlaceholderForParameter(parameter) {
1384
1433
  var _a, _b;
1385
1434
  const { value: parameterValue, isDefault } = getValueForParameter(parameter);
@@ -1405,14 +1454,14 @@ const getValueForParameter = (parameter) => {
1405
1454
  if (typeof defaultValue !== 'undefined') {
1406
1455
  return { value: stringifyValue(defaultValue), isDefault: true };
1407
1456
  }
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 : [];
1457
+ const enums = (_b = (_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.enum) !== null && _b !== void 0 ? _b : [];
1413
1458
  if (enums.length > 0) {
1414
1459
  return { value: stringifyValue(enums[0]) };
1415
1460
  }
1461
+ const examples = (_c = parameter.examples) !== null && _c !== void 0 ? _c : [];
1462
+ if (examples.length > 0) {
1463
+ return { value: exampleValue(examples[0]) };
1464
+ }
1416
1465
  return { value: '' };
1417
1466
  };
1418
1467
  const getInitialValueForParameter = (parameter) => {
@@ -1461,20 +1510,35 @@ function isRequired(n) {
1461
1510
  }
1462
1511
 
1463
1512
  const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
1464
- var _a, _b;
1513
+ var _a;
1465
1514
  const inputId = useUniqueId(`id_${parameter.name}_`);
1466
1515
  const inputCheckId = useUniqueId(`id_${parameter.name}_checked`);
1467
1516
  const parameterValueOptions = parameterOptions(parameter);
1468
1517
  const examples = exampleOptions(parameter);
1469
- const selectedExample = (_a = examples === null || examples === void 0 ? void 0 : examples.find(e => e.value === value)) !== null && _a !== void 0 ? _a : selectExampleOption;
1518
+ const selectedExample = React.useMemo(() => {
1519
+ if (!examples)
1520
+ return selectExampleOption;
1521
+ const matchingExample = examples.find(e => {
1522
+ return String(decodeSafeSelectorValue(e.value)) === value;
1523
+ });
1524
+ return matchingExample !== null && matchingExample !== void 0 ? matchingExample : selectExampleOption;
1525
+ }, [examples, value]);
1470
1526
  const parameterDisplayName = `${parameter.name}${parameter.required ? '*' : ''}`;
1527
+ const encodedValue = React.useMemo(() => {
1528
+ if (!value || !parameterValueOptions)
1529
+ return value || '';
1530
+ const matchingOption = parameterValueOptions.find(opt => {
1531
+ return String(decodeSafeSelectorValue(opt.value)) === value;
1532
+ });
1533
+ return matchingOption ? String(matchingOption.value) : value;
1534
+ }, [value, parameterValueOptions]);
1471
1535
  const requiredButEmpty = validate && parameter.required && !value;
1472
1536
  return (React.createElement(React.Fragment, null,
1473
1537
  React.createElement(Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, parameterDisplayName),
1474
1538
  React.createElement(Text, { mx: 3 }, ":"),
1475
- React.createElement("div", null, parameterValueOptions ? (React.createElement(Select, { flex: 1, "aria-label": parameter.name, options: parameterValueOptions, value: value || '', onChange: onChange, placeholder: getPlaceholderForSelectedParameter(parameter) })) : (React.createElement(Flex, { flex: 1 },
1476
- React.createElement(Input, { id: inputId, "aria-label": parameter.name, appearance: requiredButEmpty ? 'default' : 'minimal', flex: 1, placeholder: getPlaceholderForParameter(parameter), type: ((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.type) === 'number' ? 'number' : 'text', required: true, intent: requiredButEmpty ? 'danger' : 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }),
1477
- examples && (React.createElement(Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: onChange }))))),
1539
+ React.createElement("div", null, parameterValueOptions ? (React.createElement(Select, { flex: 1, "aria-label": parameter.name, options: parameterValueOptions, value: encodedValue, onChange: val => onChange && onChange(String(decodeSafeSelectorValue(val))), placeholder: getPlaceholderForSelectedParameter(parameter) })) : (React.createElement(Flex, { flex: 1 },
1540
+ React.createElement(Input, { id: inputId, "aria-label": parameter.name, appearance: requiredButEmpty ? 'default' : 'minimal', flex: 1, placeholder: getPlaceholderForParameter(parameter), type: ((_a = parameter.schema) === null || _a === void 0 ? void 0 : _a.type) === 'number' ? 'number' : 'text', required: true, intent: requiredButEmpty ? 'danger' : 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }),
1541
+ examples && (React.createElement(Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: val => onChange && onChange(String(decodeSafeSelectorValue(val))) }))))),
1478
1542
  canChangeOptional && !parameter.required && (React.createElement(React.Fragment, null,
1479
1543
  React.createElement("div", null),
1480
1544
  React.createElement("div", null),
@@ -2327,10 +2391,17 @@ ServersDropdown.displayName = 'ServersDropdown';
2327
2391
 
2328
2392
  const VariableEditor = ({ variable, value, onChange }) => {
2329
2393
  const inputId = useUniqueId(`id_${variable.name}_`);
2394
+ const encodedOptions = React.useMemo(() => (variable.enum ? variable.enum.map(s => ({ value: encodeSafeSelectorValue(s), label: String(s) })) : []), [variable.enum]);
2395
+ const encodedValue = React.useMemo(() => {
2396
+ if (!value || !variable.enum)
2397
+ return value || variable.default;
2398
+ const matchingOption = encodedOptions.find(opt => decodeSafeSelectorValue(String(opt.value)) === value);
2399
+ return matchingOption ? String(matchingOption.value) : value;
2400
+ }, [value, variable.enum, variable.default, encodedOptions]);
2330
2401
  return (React.createElement(React.Fragment, null,
2331
2402
  React.createElement(Text, { as: "label", "aria-hidden": "true", "data-testid": "param-label", htmlFor: inputId, fontSize: "base" }, variable.name),
2332
2403
  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 },
2404
+ React.createElement("div", null, variable.enum ? (React.createElement(Select, { flex: 1, "aria-label": variable.name, options: encodedOptions, value: encodedValue, onChange: val => onChange && onChange(decodeSafeSelectorValue(String(val))) })) : (React.createElement(Flex, { flex: 1 },
2334
2405
  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
2406
  };
2336
2407
 
@@ -3255,7 +3326,7 @@ const HttpServiceComponent = React.memo(({ data: unresolvedData, location = {},
3255
3326
  var _a, _b, _c, _d;
3256
3327
  const { nodeHasChanged } = useOptionsCtx();
3257
3328
  const data = useResolvedObject(unresolvedData);
3258
- const { ref: layoutRef, isCompact } = useIsCompact(layoutOptions);
3329
+ const { ref: layoutRef } = useIsCompact(layoutOptions);
3259
3330
  const { search, pathname } = location;
3260
3331
  const mocking = React.useContext(MockingContext);
3261
3332
  const query = new URLSearchParams(search);
@@ -3267,7 +3338,7 @@ const HttpServiceComponent = React.memo(({ data: unresolvedData, location = {},
3267
3338
  React.createElement(Box, { pos: "relative" },
3268
3339
  React.createElement(Heading, { size: 1, mb: 4, fontWeight: "semibold" }, data.name),
3269
3340
  React.createElement(NodeAnnotation, { change: nameChanged })),
3270
- exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && !isCompact && React.createElement(ExportButton, Object.assign({}, exportProps)))),
3341
+ exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && React.createElement(ExportButton, Object.assign({}, exportProps)))),
3271
3342
  data.version && (React.createElement(Box, { mb: 5, pos: "relative" },
3272
3343
  React.createElement(VersionBadge, { value: data.version }),
3273
3344
  React.createElement(NodeAnnotation, { change: versionChanged }))),
@@ -3303,7 +3374,7 @@ const ModelComponent = ({ data: unresolvedData, className, nodeTitle, layoutOpti
3303
3374
  isDeprecated && React.createElement(DeprecatedBadge, null),
3304
3375
  isInternal && React.createElement(InternalBadge, null))),
3305
3376
  React.createElement(NodeAnnotation, { change: titleChanged })),
3306
- exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && !isCompact && React.createElement(ExportButton, Object.assign({}, exportProps))));
3377
+ exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && React.createElement(ExportButton, Object.assign({}, exportProps))));
3307
3378
  const modelExamples = !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideModelExamples) && React.createElement(ModelExamples, { data: data, isCollapsible: isCompact });
3308
3379
  const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId, attr: 'description' });
3309
3380
  const description = (React.createElement(VStack, { spacing: 10 },
@@ -3535,6 +3606,38 @@ const TableOfContents = React.memo(({ tree, activeId, Link, maxDepthOpenByDefaul
3535
3606
  });
3536
3607
  }, []);
3537
3608
  const updatedTree = updateTocTree(tree, '');
3609
+ const findFirstMatchAndIndexMatch = React.useCallback((items, id) => {
3610
+ let firstMatch;
3611
+ let hasAnyLastIndexMatch = false;
3612
+ if (!id)
3613
+ return [firstMatch, hasAnyLastIndexMatch];
3614
+ const walk = (arr, stack) => {
3615
+ for (const itm of arr) {
3616
+ const newStack = stack.concat(itm);
3617
+ const matches = ('slug' in itm && itm.slug === id) || ('id' in itm && itm.id === id);
3618
+ if (matches) {
3619
+ if (!firstMatch)
3620
+ firstMatch = itm;
3621
+ const hasLastIndexMatch = newStack.some(el => 'index' in el && el.index === lastActiveIndex);
3622
+ if (hasLastIndexMatch)
3623
+ hasAnyLastIndexMatch = true;
3624
+ }
3625
+ if ('items' in itm && Array.isArray(itm.items)) {
3626
+ if (walk(itm.items, newStack))
3627
+ return true;
3628
+ }
3629
+ }
3630
+ return false;
3631
+ };
3632
+ walk(items, []);
3633
+ return [firstMatch, hasAnyLastIndexMatch];
3634
+ }, [lastActiveIndex]);
3635
+ const [firstMatchItem, hasAnyLastIndexMatch] = React.useMemo(() => findFirstMatchAndIndexMatch(updatedTree, activeId), [updatedTree, activeId, findFirstMatchAndIndexMatch]);
3636
+ React.useEffect(() => {
3637
+ if (!hasAnyLastIndexMatch && firstMatchItem && 'index' in firstMatchItem && firstMatchItem.index) {
3638
+ setLastActiveIndex(firstMatchItem.index);
3639
+ }
3640
+ }, [firstMatchItem, hasAnyLastIndexMatch]);
3538
3641
  const container = React.useRef(null);
3539
3642
  const child = React.useRef(null);
3540
3643
  const firstRender = useFirstRender();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoplight/elements-core",
3
- "version": "9.0.13",
3
+ "version": "9.0.15-beta-0.1",
4
4
  "main": "./index.js",
5
5
  "sideEffects": [
6
6
  "web-components.min.js",