@stoplight/elements-core 9.0.13 → 9.0.15

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
 
@@ -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
 
@@ -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
 
@@ -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",
4
4
  "main": "./index.js",
5
5
  "sideEffects": [
6
6
  "web-components.min.js",